]> git.draconx.ca Git - cdecl99.git/blob - t/normalize.c
Port to use getline.h from dxcommon.
[cdecl99.git] / t / normalize.c
1 /*
2  * Helper application to test normalization of declaration specifiers.
3  * Copyright © 2021-2024 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 <https://www.gnu.org/licenses/>.
17  */
18
19 #include <config.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <getopt.h>
25
26 #include "cdecl.h"
27 #include "cdecl-internal.h"
28
29 #define PROGNAME "normalize"
30 #include "test.h"
31
32 static const char sopts[] = "f:VH";
33 static const struct option lopts[] = {
34         { "file", 1, NULL, 'f' },
35         { "version", 0, NULL, 'V' },
36         { "help", 0, NULL, 'H' },
37         { 0 }
38 };
39
40 static void print_usage(FILE *f)
41 {
42         fprintf(f, "Usage: %s [options]\n", progname);
43 }
44
45 static void print_help(void)
46 {
47         const struct option *opt;
48
49         print_usage(stdout);
50         puts("Test normalization of declaration specifiers.\n");
51         test_print_options(lopts);
52 }
53
54 static unsigned to_spectype(const char *tok)
55 {
56         if (!strcmp(tok, "typedef")) return CDECL_STOR_TYPEDEF;
57         if (!strcmp(tok, "extern")) return CDECL_STOR_EXTERN;
58         if (!strcmp(tok, "static")) return CDECL_STOR_STATIC;
59         if (!strcmp(tok, "auto")) return CDECL_STOR_AUTO;
60         if (!strcmp(tok, "register")) return CDECL_STOR_REGISTER;
61         if (!strcmp(tok, "inline")) return CDECL_FUNC_INLINE;
62         if (!strcmp(tok, "restrict")) return CDECL_QUAL_RESTRICT;
63         if (!strcmp(tok, "volatile")) return CDECL_QUAL_VOLATILE;
64         if (!strcmp(tok, "const")) return CDECL_QUAL_CONST;
65         if (!strcmp(tok, "void")) return CDECL_TYPE_VOID;
66         if (!strcmp(tok, "signed")) return CDECL_TYPE_SIGNED;
67         if (!strcmp(tok, "unsigned")) return CDECL_TYPE_UNSIGNED;
68         if (!strcmp(tok, "char")) return CDECL_TYPE_CHAR;
69         if (!strcmp(tok, "short")) return CDECL_TYPE_SHORT;
70         if (!strcmp(tok, "long")) return CDECL_TYPE_LONG;
71         if (!strcmp(tok, "int")) return CDECL_TYPE_INT;
72         if (!strcmp(tok, "float")) return CDECL_TYPE_FLOAT;
73         if (!strcmp(tok, "double")) return CDECL_TYPE_DOUBLE;
74         if (!strcmp(tok, "_Complex")) return CDECL_TYPE_COMPLEX;
75         if (!strcmp(tok, "_Imaginary")) return CDECL_TYPE_IMAGINARY;
76         if (!strcmp(tok, "_Bool")) return CDECL_TYPE_BOOL;
77         if (!strcmp(tok, "struct")) return CDECL_TYPE_STRUCT;
78         if (!strcmp(tok, "union")) return CDECL_TYPE_UNION;
79         if (!strcmp(tok, "enum")) return CDECL_TYPE_ENUM;
80
81         return CDECL_TYPE_IDENT;
82 }
83
84 static const char *to_specstring(unsigned type)
85 {
86         switch (type) {
87         case CDECL_STOR_TYPEDEF: return "typedef";
88         case CDECL_STOR_EXTERN: return "extern";
89         case CDECL_STOR_STATIC: return "static";
90         case CDECL_STOR_AUTO: return "auto";
91         case CDECL_STOR_REGISTER: return "register";
92         case CDECL_FUNC_INLINE: return "inline";
93         case CDECL_QUAL_RESTRICT: return "restrict";
94         case CDECL_QUAL_VOLATILE: return "volatile";
95         case CDECL_QUAL_CONST: return "const";
96         case CDECL_TYPE_VOID: return "void";
97         case CDECL_TYPE_SIGNED: return "signed";
98         case CDECL_TYPE_UNSIGNED: return "unsigned";
99         case CDECL_TYPE_CHAR: return "char";
100         case CDECL_TYPE_SHORT: return "short";
101         case CDECL_TYPE_LONG: return "long";
102         case CDECL_TYPE_INT: return "int";
103         case CDECL_TYPE_FLOAT: return "float";
104         case CDECL_TYPE_DOUBLE: return "double";
105         case CDECL_TYPE_COMPLEX: return "_Complex";
106         case CDECL_TYPE_IMAGINARY: return "_Imaginary";
107         case CDECL_TYPE_BOOL: return "_Bool";
108         case CDECL_TYPE_STRUCT: return "struct";
109         case CDECL_TYPE_UNION: return "union";
110         case CDECL_TYPE_ENUM: return "enum";
111         }
112
113         return "";
114 }
115
116 static void print_spec(struct cdecl_declspec *spec)
117 {
118         const char *s = to_specstring(spec->type);
119
120         printf("%s", s);
121         if (spec->ident) {
122                 if (s[0])
123                         putchar(' ');
124                 printf("%s", spec->ident);
125         }
126 }
127
128 int do_normalize(char *line, size_t n)
129 {
130         struct cdecl_declspec *s, *specs = NULL, **newspec = &specs;
131         char *tok = NULL;
132
133         while ((tok = strtok(tok ? NULL : line, " "))) {
134                 struct cdecl_declspec *spec = malloc_nofail(sizeof *spec);
135
136                 spec->next = NULL;
137                 spec->ident = NULL;
138                 spec->type = to_spectype(tok);
139                 switch (spec->type) {
140                 case CDECL_TYPE_STRUCT:
141                 case CDECL_TYPE_UNION:
142                 case CDECL_TYPE_ENUM:
143                         spec->ident = strtok(NULL, " ");
144                         break;
145                 case CDECL_TYPE_IDENT:
146                         spec->ident = tok;
147                 }
148
149                 *newspec = spec;
150                 newspec = &spec->next;
151         }
152
153         specs = cdecl__normalize_specs(specs);
154         for (s = specs; s; s = s->next) {
155                 print_spec(s);
156                 if (s->next)
157                         putchar(' ');
158         }
159         putchar('\n');
160
161         while (specs) {
162                 struct cdecl_declspec *c = specs;
163                 specs = specs->next;
164                 free(c);
165         }
166
167         return 0;
168 }
169
170 int main(int argc, char **argv)
171 {
172         int opt, ret = EXIT_SUCCESS;
173         char *filename = NULL, *line = NULL;
174         FILE *infile = stdin;
175         size_t n = 0;
176         ssize_t rc;
177
178         while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
179                 switch (opt) {
180                 case 'f':
181                         filename = optarg;
182                         break;
183                 case 'V':
184                         test_print_version(PROGNAME);
185                         return EXIT_SUCCESS;
186                 case 'H':
187                         print_help();
188                         return EXIT_SUCCESS;
189                 default:
190                         print_usage(stderr);
191                         return EXIT_FAILURE;
192                 }
193         }
194
195         if (filename && !freopen(filename, "r", stdin)) {
196                 print_error("%s: %s", filename, strerror(errno));
197                 return EXIT_FAILURE;
198         }
199
200         while (test_getline(&line, &n)) {
201                 if (do_normalize(line, n) < 0)
202                         ret = EXIT_FAILURE;
203         }
204
205         free(line);
206         return ret;
207 }