]> git.draconx.ca Git - cdecl99.git/blob - t/randomdecl.c
Port to use getline.h from dxcommon.
[cdecl99.git] / t / randomdecl.c
1 /*
2  * Generate random C declarations for testing.
3  * Copyright © 2012, 2020, 2022-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 <assert.h>
24 #include <stdbool.h>
25 #include <errno.h>
26 #include <getopt.h>
27
28 #include "cdecl.h"
29 #include "declgen.h"
30
31 #define PROGNAME "randomdecl"
32 #include "test.h"
33
34 static const char sopts[] = "s:n:ECVH";
35 static const struct option lopts[] = {
36         { "seed",    1, NULL, 's' },
37         { "count",   1, NULL, 'n' },
38         { "cdecl",   0, NULL, 'C' },
39         { "english", 0, NULL, 'E' },
40         { "version", 0, NULL, 'V' },
41         { "help",    0, NULL, 'H' },
42         { 0 }
43 };
44
45 enum {
46         MODE_CDECL,
47         MODE_ENGLISH
48 };
49
50 static void print_usage(FILE *f)
51 {
52         fprintf(f, "Usage: %s [options]\n", progname);
53 }
54
55 static void print_help(void)
56 {
57         const struct option *opt;
58
59         print_usage(stdout);
60         puts("Generate random C declarations for testing.\n");
61         test_print_options(lopts);
62 }
63
64 static struct cdecl *random_decl(struct test_rng *rng)
65 {
66         struct cdecl *decl;
67         unsigned flags = 0;
68
69         decl = malloc_nofail(sizeof *decl);
70         decl->next = NULL;
71
72         decl->declarators = gen_declarators(rng);
73         if (decl->declarators->type != CDECL_DECL_FUNCTION)
74                 flags |= GEN_NO_FUNCTION;
75         if (cdecl_is_abstract(decl->declarators))
76                 flags |= GEN_NO_STORAGE | GEN_NO_FUNCTION;
77         if (decl->declarators->type == CDECL_DECL_ARRAY
78             || decl->declarators->type == CDECL_DECL_IDENT)
79                 flags |= GEN_NO_VOID;
80
81         decl->specifiers = gen_declspecs(rng, flags);
82         return decl;
83 }
84
85 static void
86 print_decl(struct cdecl *decl, size_t func(char *, size_t, struct cdecl *))
87 {
88         static size_t printbuf_size;
89         static char *printbuf;
90         size_t rc;
91 retry:
92         rc = func(printbuf, printbuf_size, decl);
93         if (rc >= printbuf_size) {
94                 printbuf_size = rc + 1;
95                 printbuf = realloc_nofail(printbuf, printbuf_size);
96                 goto retry;
97         }
98
99         printf("%s\n", printbuf);
100 }
101
102 int main(int argc, char **argv)
103 {
104         const char *seed = "", *count_str = NULL;
105         unsigned long i, count = 0;
106         int opt, mode = MODE_CDECL;
107         struct test_rng *rng;
108         struct cdecl *decl;
109
110         if (argc > 0)
111                 progname = argv[0];
112
113         while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
114                 switch (opt) {
115                 case 's':
116                         seed = optarg;
117                         break;
118                 case 'n':
119                         count_str = optarg;
120                         break;
121                 case 'C':
122                         mode = MODE_CDECL;
123                         break;
124                 case 'E':
125                         mode = MODE_ENGLISH;
126                         break;
127                 case 'V':
128                         test_print_version(PROGNAME);
129                         return EXIT_SUCCESS;
130                 case 'H':
131                         print_help();
132                         return EXIT_SUCCESS;
133                 default:
134                         print_usage(stderr);
135                         return EXIT_FAILURE;
136                 }
137         }
138
139         if (count_str && !test_strtoul(&count, count_str)) {
140                 print_error("invalid count: %s", count_str);
141                 return EXIT_FAILURE;
142         }
143
144         rng = test_rng_alloc(seed);
145         if (!rng)
146                 return EXIT_FAILURE;
147
148         for (i = 0; !count || i < count; i++) {
149                 decl = random_decl(rng);
150
151                 if (mode == MODE_ENGLISH) {
152                         print_decl(decl, cdecl_explain);
153                 } else {
154                         print_decl(decl, cdecl_declare);
155                 }
156
157                 gen_free_declspecs(decl->specifiers);
158                 gen_free_declarators(decl->declarators);
159                 free(decl);
160         }
161
162         test_rng_free(rng);
163
164         return EXIT_SUCCESS;
165 }