]> git.draconx.ca Git - cdecl99.git/blob - src/explain.c
Minor portability improvements.
[cdecl99.git] / src / explain.c
1 /*
2  *  Render C declarations as English.
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 <stdlib.h>
22 #include <stdarg.h>
23 #include <inttypes.h>
24 #include <stdbool.h>
25 #include <assert.h>
26
27 #include "cdecl.h"
28 #include "cdecl-internal.h"
29
30 /*
31  * Renders the start of the thing being declared.  If top is true, print
32  * the "declare" or "type" keywords at the front, as appropriate.
33  */
34 static size_t
35 explain_prologue(char *buf, size_t n, struct cdecl_declarator *d, bool top)
36 {
37         size_t ret = 0, rc = 0;
38
39         while (d) {
40                 switch (d->type) {
41                 case CDECL_DECL_NULL:
42                         if (top)
43                                 return snprintf(buf, n, "type");
44                         return 0;
45                 case CDECL_DECL_IDENT:
46                         if (top)
47                                 rc = snprintf(buf, n, "declare");
48                         ret += cdecl__advance(&buf, &n, rc);
49                         return ret + snprintf(buf, n, "%s as", d->u.ident);
50                 }
51
52                 d = d->child;
53         }
54
55         assert(0);
56 }
57
58 static size_t
59 explain_pointer(char *buf, size_t n, struct cdecl_pointer *p)
60 {
61         size_t ret = 0, rc;
62
63         rc = cdecl__explain_specs(buf, n, p->qualifiers, CDECL_SPEC_QUAL);
64         ret += cdecl__advance(&buf, &n, rc);
65
66         return ret + snprintf(buf, n, "pointer to");
67 }
68
69 static size_t
70 explain_array(char *buf, size_t n, struct cdecl_array *a)
71 {
72         size_t ret = 0, rc = 0;
73
74         if (a->vla)
75                 rc = snprintf(buf, n, "variable-length array");
76         else
77                 rc = snprintf(buf, n, "array");
78         ret += cdecl__advance(&buf, &n, rc);
79
80         if (a->vla) {
81                 rc = snprintf(buf, n, "%s", a->vla);
82                 ret += cdecl__advance(&buf, &n, rc);
83         } else if (a->length) {
84                 rc = snprintf(buf, n, "%" PRIuMAX, a->length);
85                 ret += cdecl__advance(&buf, &n, rc);
86         }
87
88         return ret + snprintf(buf, n, "of");
89 }
90
91 static size_t
92 explain_declarators(char *buf, size_t n, struct cdecl_declarator *decl);
93
94 static size_t explain_decl(char *buf, size_t n, struct cdecl *decl, bool top)
95 {
96         size_t ret = 0, rc;
97
98         rc = explain_prologue(buf, n, decl->declarators, top);
99         ret += cdecl__advance(&buf, &n, rc);
100
101         rc = cdecl__explain_pre_specs(buf, n, decl->specifiers);
102         ret += cdecl__advance(&buf, &n, rc);
103
104         rc = explain_declarators(buf, n, decl->declarators);
105         ret += cdecl__advance(&buf, &n, rc);
106
107         return ret + cdecl__explain_post_specs(buf, n, decl->specifiers);
108 }
109
110 static size_t explain_function(char *buf, size_t n, struct cdecl_function *f)
111 {
112         size_t ret = 0, rc = 0;
113
114         rc = snprintf(buf, n, "function");
115         ret += cdecl__advance(&buf, &n, rc);
116
117         if (f->parameters) {
118                 rc = snprintf(buf, n, "(");
119                 ret += cdecl__advance_(&buf, &n, rc);
120
121                 for (struct cdecl *p = f->parameters; p; p = p->next) {
122                         rc = explain_decl(buf, n, p, false);
123                         ret += cdecl__advance_(&buf, &n, rc);
124
125                         if (p->next)
126                                 rc = snprintf(buf, n, ",");
127                         else if (f->variadic)
128                                 rc = snprintf(buf, n, ", ...)");
129                         else
130                                 rc = snprintf(buf, n, ")");
131                         ret += cdecl__advance(&buf, &n, rc);
132                 }
133         }
134
135         return ret + snprintf(buf, n, "returning");
136 }
137
138 static size_t
139 explain_declarators(char *buf, size_t n, struct cdecl_declarator *d)
140 {
141         size_t ret = 0, rc;
142
143         if (d->type == CDECL_DECL_IDENT || d->type == CDECL_DECL_NULL)
144                 return 0;
145
146         rc = explain_declarators(buf, n, d->child);
147         ret += cdecl__advance(&buf, &n, rc);
148
149         switch (d->type) {
150         case CDECL_DECL_POINTER:
151                 return ret + explain_pointer(buf, n, &d->u.pointer);
152         case CDECL_DECL_ARRAY:
153                 return ret + explain_array(buf, n, &d->u.array);
154         case CDECL_DECL_FUNCTION:
155                 return ret + explain_function(buf, n, &d->u.function);
156         default:
157                 assert(0);
158         }
159 }
160
161 size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl)
162 {
163         return explain_decl(buf, n, decl, true);
164 }