]> git.draconx.ca Git - cdecl99.git/blob - src/declare.c
Fix spacing after qualified pointers when rendering C declarations.
[cdecl99.git] / src / declare.c
1 /*
2  *  Render C declarations.
3  *  Copyright © 2011 Nick Bowler
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 #include <config.h>
19 #include <stdio.h>
20 #include <stdbool.h>
21 #include <assert.h>
22
23 #include "cdecl.h"
24 #include "output.h"
25
26 static size_t declare_specs(char *buf, size_t n, struct cdecl_declspec *s)
27 {
28         size_t ret = 0, rc;
29
30         if (!s)
31                 return 0;
32
33         rc = cdecl__explain_pre_specs(buf, n, s);
34         ret += cdecl__advance(&buf, &n, rc);
35
36         rc = cdecl__explain_post_specs(buf, n, s);
37         return ret + rc;
38 }
39
40 static size_t
41 declare_declarator(char *buf, size_t n, struct cdecl_declarator *d);
42
43 static size_t declare_decl(char *buf, size_t n, struct cdecl *decl)
44 {
45         size_t ret = 0, rc;
46
47         rc = declare_specs(buf, n, decl->specifiers);
48         if (decl->declarators->type != CDECL_DECL_NULL)
49                 ret += cdecl__advance(&buf, &n, rc);
50         else
51                 ret += cdecl__advance_(&buf, &n, rc);
52
53         return ret + declare_declarator(buf, n, decl->declarators);
54 }
55
56 static size_t
57 declare_postfix_child(char *buf, size_t n, struct cdecl_declarator *d)
58 {
59         size_t ret = 0, rc;
60
61         if (d->type == CDECL_DECL_POINTER) {
62                 rc = snprintf(buf, n, "(");
63                 ret += cdecl__advance_(&buf, &n, rc);
64         }
65
66         rc = declare_declarator(buf, n, d);
67         ret += cdecl__advance_(&buf, &n, rc);
68
69         if (d->type == CDECL_DECL_POINTER) {
70                 rc = snprintf(buf, n, ")");
71                 ret += cdecl__advance_(&buf, &n, rc);
72         }
73
74         return ret;
75 }
76
77 static size_t declare_pointer(char *buf, size_t n, struct cdecl_pointer *p)
78 {
79         size_t ret = 0, rc;
80
81         rc = snprintf(buf, n, "*");
82         if (p->qualifiers)
83                 ret += cdecl__advance(&buf, &n, rc);
84         else
85                 ret += cdecl__advance_(&buf, &n, rc);
86
87         rc = cdecl__explain_specs(buf, n, p->qualifiers, CDECL_SPEC_QUAL);
88         return ret + rc;
89 }
90
91 static bool pointer_needs_space(struct cdecl_declarator *d)
92 {
93         assert(d->type == CDECL_DECL_POINTER);
94
95         if (d->u.pointer.qualifiers)
96                 return d->child->type != CDECL_DECL_NULL;
97
98         return false;
99 }
100
101 static size_t declare_array(char *buf, size_t n, struct cdecl_array *a)
102 {
103         size_t ret = 0, rc;
104
105         rc = snprintf(buf, n, "[");
106         ret += cdecl__advance_(&buf, &n, rc);
107
108         if (a->vla)
109                 rc = snprintf(buf, n, "%s", a->vla[0] ? a->vla : "*");
110         else
111                 rc = snprintf(buf, n, "%.0ju", a->length);
112         ret += cdecl__advance_(&buf, &n, rc);
113
114         return ret + snprintf(buf, n, "]");
115 }
116
117 static size_t declare_function(char *buf, size_t n, struct cdecl_function *f)
118 {
119         size_t ret = 0, rc;
120
121         rc = snprintf(buf, n, "(");
122         ret += cdecl__advance_(&buf, &n, rc);
123
124         for (struct cdecl *p = f->parameters; p; p = p->next) {
125                 rc = declare_decl(buf, n, p);
126                 ret += cdecl__advance_(&buf, &n, rc);
127
128                 rc = 0;
129                 if (p->next)
130                         rc = snprintf(buf, n, ", ");
131                 else if (f->variadic)
132                         rc = snprintf(buf, n, ", ...");
133                 ret += cdecl__advance_(&buf, &n, rc);
134         }
135
136         return ret + snprintf(buf, n, ")");
137 }
138
139 static size_t
140 declare_declarator(char *buf, size_t n, struct cdecl_declarator *d)
141 {
142         size_t ret = 0, rc;
143
144         for (; d; d = d->child) {
145                 switch (d->type) {
146                 case CDECL_DECL_NULL:
147                         break;
148                 case CDECL_DECL_IDENT:
149                         rc = snprintf(buf, n, "%s", d->u.ident);
150                         ret += cdecl__advance_(&buf, &n, rc);
151                         break;
152                 case CDECL_DECL_POINTER:
153                         rc = declare_pointer(buf, n, &d->u.pointer);
154                         if (pointer_needs_space(d))
155                                 ret += cdecl__advance(&buf, &n, rc);
156                         else
157                                 ret += cdecl__advance_(&buf, &n, rc);
158                         break;
159                 /*
160                  * Arrays and functions are special: since they are postfix,
161                  * we need to render the children before rendering their
162                  * "bodies".
163                  */
164                 case CDECL_DECL_ARRAY:
165                         rc = declare_postfix_child(buf, n, d->child);
166                         ret += cdecl__advance_(&buf, &n, rc);
167                         return ret + declare_array(buf, n, &d->u.array);
168                 case CDECL_DECL_FUNCTION:
169                         rc = declare_postfix_child(buf, n, d->child);
170                         ret += cdecl__advance_(&buf, &n, rc);
171                         return ret + declare_function(buf, n, &d->u.function);
172                 default:
173                         assert(0);
174                 }
175         }
176
177         return ret;
178 }
179
180 size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl)
181 {
182         return declare_decl(buf, n, decl);
183 }