]> git.draconx.ca Git - cdecl99.git/blob - src/declare.c
Consolidate header files.
[cdecl99.git] / src / declare.c
1 /*
2  *  Render C declarations.
3  *  Copyright © 2011, 2021 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
19 #include <config.h>
20 #include <stdio.h>
21 #include <stdbool.h>
22 #include <assert.h>
23
24 #include "cdecl.h"
25 #include "cdecl-internal.h"
26
27 static size_t declare_specs(char *buf, size_t n, struct cdecl_declspec *s)
28 {
29         size_t ret = 0, rc;
30
31         if (!s)
32                 return 0;
33
34         rc = cdecl__explain_pre_specs(buf, n, s);
35         ret += cdecl__advance(&buf, &n, rc);
36
37         rc = cdecl__explain_post_specs(buf, n, s);
38         return ret + rc;
39 }
40
41 static size_t
42 declare_declarator(char *buf, size_t n, struct cdecl_declarator *d);
43
44 static size_t declare_decl(char *buf, size_t n, struct cdecl *decl)
45 {
46         size_t ret = 0, rc;
47
48         rc = declare_specs(buf, n, decl->specifiers);
49         if (decl->declarators->type != CDECL_DECL_NULL)
50                 ret += cdecl__advance(&buf, &n, rc);
51         else
52                 ret += cdecl__advance_(&buf, &n, rc);
53
54         return ret + declare_declarator(buf, n, decl->declarators);
55 }
56
57 static size_t
58 declare_postfix_child(char *buf, size_t n, struct cdecl_declarator *d)
59 {
60         size_t ret = 0, rc;
61
62         if (d->type == CDECL_DECL_POINTER) {
63                 rc = snprintf(buf, n, "(");
64                 ret += cdecl__advance_(&buf, &n, rc);
65         }
66
67         rc = declare_declarator(buf, n, d);
68         ret += cdecl__advance_(&buf, &n, rc);
69
70         if (d->type == CDECL_DECL_POINTER) {
71                 rc = snprintf(buf, n, ")");
72                 ret += cdecl__advance_(&buf, &n, rc);
73         }
74
75         return ret;
76 }
77
78 static size_t declare_pointer(char *buf, size_t n, struct cdecl_pointer *p)
79 {
80         size_t ret = 0, rc;
81
82         rc = snprintf(buf, n, "*");
83         if (p->qualifiers)
84                 ret += cdecl__advance(&buf, &n, rc);
85         else
86                 ret += cdecl__advance_(&buf, &n, rc);
87
88         rc = cdecl__explain_specs(buf, n, p->qualifiers, CDECL_SPEC_QUAL);
89         return ret + rc;
90 }
91
92 static bool pointer_needs_space(struct cdecl_declarator *d)
93 {
94         assert(d->type == CDECL_DECL_POINTER);
95
96         if (d->u.pointer.qualifiers)
97                 return d->child->type != CDECL_DECL_NULL;
98
99         return false;
100 }
101
102 static size_t declare_array(char *buf, size_t n, struct cdecl_array *a)
103 {
104         size_t ret = 0, rc;
105
106         rc = snprintf(buf, n, "[");
107         ret += cdecl__advance_(&buf, &n, rc);
108
109         if (a->vla)
110                 rc = snprintf(buf, n, "%s", a->vla[0] ? a->vla : "*");
111         else
112                 rc = snprintf(buf, n, "%.0ju", a->length);
113         ret += cdecl__advance_(&buf, &n, rc);
114
115         return ret + snprintf(buf, n, "]");
116 }
117
118 static size_t declare_function(char *buf, size_t n, struct cdecl_function *f)
119 {
120         size_t ret = 0, rc;
121
122         rc = snprintf(buf, n, "(");
123         ret += cdecl__advance_(&buf, &n, rc);
124
125         for (struct cdecl *p = f->parameters; p; p = p->next) {
126                 rc = declare_decl(buf, n, p);
127                 ret += cdecl__advance_(&buf, &n, rc);
128
129                 rc = 0;
130                 if (p->next)
131                         rc = snprintf(buf, n, ", ");
132                 else if (f->variadic)
133                         rc = snprintf(buf, n, ", ...");
134                 ret += cdecl__advance_(&buf, &n, rc);
135         }
136
137         return ret + snprintf(buf, n, ")");
138 }
139
140 static size_t
141 declare_declarator(char *buf, size_t n, struct cdecl_declarator *d)
142 {
143         size_t ret = 0, rc;
144
145         for (; d; d = d->child) {
146                 switch (d->type) {
147                 case CDECL_DECL_NULL:
148                         break;
149                 case CDECL_DECL_IDENT:
150                         rc = snprintf(buf, n, "%s", d->u.ident);
151                         ret += cdecl__advance_(&buf, &n, rc);
152                         break;
153                 case CDECL_DECL_POINTER:
154                         rc = declare_pointer(buf, n, &d->u.pointer);
155                         if (pointer_needs_space(d))
156                                 ret += cdecl__advance(&buf, &n, rc);
157                         else
158                                 ret += cdecl__advance_(&buf, &n, rc);
159                         break;
160                 /*
161                  * Arrays and functions are special: since they are postfix,
162                  * we need to render the children before rendering their
163                  * "bodies".
164                  */
165                 case CDECL_DECL_ARRAY:
166                         rc = declare_postfix_child(buf, n, d->child);
167                         ret += cdecl__advance_(&buf, &n, rc);
168                         return ret + declare_array(buf, n, &d->u.array);
169                 case CDECL_DECL_FUNCTION:
170                         rc = declare_postfix_child(buf, n, d->child);
171                         ret += cdecl__advance_(&buf, &n, rc);
172                         return ret + declare_function(buf, n, &d->u.function);
173                 default:
174                         assert(0);
175                 }
176         }
177
178         return ret;
179 }
180
181 size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl)
182 {
183         return declare_decl(buf, n, decl);
184 }