]> git.draconx.ca Git - cdecl99.git/blob - src/output.c
Add support for outputting declarations as C code.
[cdecl99.git] / src / output.c
1 #include <stdio.h>
2 #include <assert.h>
3
4 #include "typemap.h"
5 #include "output.h"
6 #include "cdecl.h"
7
8 size_t cdecl__advance_(char **buf, size_t *n, size_t amount)
9 {
10         if (amount >= *n) {
11                 *n   = 0;
12                 *buf = 0;
13         } else {
14                 *buf += amount;
15                 *n   -= amount;
16         }
17
18         return amount;
19 }
20
21 size_t cdecl__advance(char **buf, size_t *n, size_t amount)
22 {
23         size_t ret, rc;
24
25         if (!amount)
26                 return 0;
27
28         ret = cdecl__advance_(buf, n, amount);
29         rc = snprintf(*buf, *n, " ");
30         return ret + cdecl__advance_(buf, n, rc);
31 }
32
33 static size_t explain_storage(char *buf, size_t n, unsigned spec)
34 {
35         switch (spec) {
36         case CDECL_STOR_TYPEDEF:
37                 return snprintf(buf, n, "typedef");
38         case CDECL_STOR_EXTERN:
39                 return snprintf(buf, n, "extern");
40         case CDECL_STOR_STATIC:
41                 return snprintf(buf, n, "static");
42         case CDECL_STOR_AUTO:
43                 return snprintf(buf, n, "auto");
44         case CDECL_STOR_REGISTER:
45                 return snprintf(buf, n, "register");
46         default:
47                 assert(0);
48         }
49 }
50
51 /* Renders the storage-class and function specifiers in canonical form. */
52 size_t cdecl__explain_pre_specs(char *buf, size_t n, struct cdecl_declspec *s)
53 {
54         unsigned long funcmap = 0;
55         size_t ret = 0, rc = 0;
56
57         for (struct cdecl_declspec *c = s; c; c = c->next) {
58                 switch (cdecl_spec_kind(c)) {
59                 case CDECL_SPEC_FUNC:
60                         funcmap |= 1ul << (c->type & 0xff);
61                         break;
62                 case CDECL_SPEC_STOR:
63                         /* Valid C declarations have at most one
64                          * storage-class specifier. */
65                         rc = explain_storage(buf, n, c->type);
66                         break;
67                 }
68         }
69
70         if (funcmap & (1ul << (CDECL_FUNC_INLINE & 0xff))) {
71                 ret += cdecl__advance(&buf, &n, rc);
72                 rc = snprintf(buf, n, "inline");
73         }
74
75         return ret + rc;
76 }
77
78 size_t cdecl__explain_qualifiers(char *buf, size_t n, struct cdecl_declspec *s)
79 {
80         unsigned long qualmap = 0;
81         size_t ret = 0, rc = 0;
82
83         for (struct cdecl_declspec *c = s; c; c = c->next) {
84                 if (cdecl_spec_kind(c) != CDECL_SPEC_QUAL)
85                         continue;
86                 qualmap |= 1ul << (c->type & 0xff);
87         }
88
89         if (qualmap & (1ul << (CDECL_QUAL_RESTRICT & 0xff))) {
90                 ret += cdecl__advance(&buf, &n, rc);
91                 rc = snprintf(buf, n, "restrict");
92         }
93         if (qualmap & (1ul << (CDECL_QUAL_VOLATILE & 0xff))) {
94                 ret += cdecl__advance(&buf, &n, rc);
95                 rc = snprintf(buf, n, "volatile");
96         }
97         if (qualmap & (1ul << (CDECL_QUAL_CONST & 0xff))) {
98                 ret += cdecl__advance(&buf, &n, rc);
99                 rc = snprintf(buf, n, "const");
100         }
101
102         return ret + rc;
103 }
104
105 /* Renders the type qualifiers and type specifiers in canonical form. */
106 size_t cdecl__explain_post_specs(char *buf, size_t n, struct cdecl_declspec *s)
107 {
108         const char *tag = NULL;
109         unsigned long typemap;
110         size_t ret = 0, rc;
111
112         typemap = cdecl__build_typemap(s);
113         if (typemap == -1)
114                 return 0;
115
116         for (struct cdecl_declspec *c = s; c; c = c->next) {
117                 if (cdecl_spec_kind(c) != CDECL_SPEC_TYPE)
118                         continue;
119
120                 /* Valid C types have at most one identifier. */
121                 if (c->ident)
122                         tag = c->ident;
123         }
124
125         rc = cdecl__explain_qualifiers(buf, n, s);
126         ret += cdecl__advance(&buf, &n, rc);
127
128         rc = snprintf(buf, n, "%s", cdecl__explain_typemap(typemap));
129         if (tag) {
130                 ret += cdecl__advance(&buf, &n, rc);
131                 rc = snprintf(buf, n, "%s", tag);
132         }
133
134         return ret + rc;
135 }