]> git.draconx.ca Git - cdecl99.git/blob - test/randomdecl.c
Add better --help text to the test programs.
[cdecl99.git] / test / randomdecl.c
1 /*
2  * Generate random C declarations for testing.
3  * Copyright © 2012, 2020 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 #include <cdecl.h>
28
29 #include "declgen.h"
30 #include "test.h"
31
32 #define PROGNAME "randomdecl"
33 static const char *progname = PROGNAME;
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
62         puts("Options:");
63         for (opt = lopts; opt->val; opt++) {
64                 int w = print_option_start(opt, NULL);
65
66                 if (w)
67                         putchar('\n');
68         }
69 }
70
71 static struct cdecl *random_decl(struct gen_rng *rng)
72 {
73         struct cdecl *decl;
74         unsigned flags = 0;
75
76         decl = malloc_nofail(sizeof *decl);
77         *decl = (struct cdecl) { 0 };
78
79         decl->declarators = gen_declarators(rng);
80         if (decl->declarators->type != CDECL_DECL_FUNCTION)
81                 flags |= GEN_NO_FUNCTION;
82         if (cdecl_is_abstract(decl->declarators))
83                 flags |= GEN_NO_STORAGE | GEN_NO_FUNCTION;
84         if (decl->declarators->type == CDECL_DECL_ARRAY
85             || decl->declarators->type == CDECL_DECL_IDENT)
86                 flags |= GEN_NO_VOID;
87
88         decl->specifiers = gen_declspecs(rng, flags);
89         return decl;
90 }
91
92 int main(int argc, char **argv)
93 {
94         const char *seed = "", *count_str = NULL;
95         struct gen_rng *rng;
96         struct cdecl *decl;
97         unsigned long count = 0;
98         int opt, mode = MODE_CDECL;
99
100         if (argc > 0)
101                 progname = argv[0];
102
103         while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
104                 switch (opt) {
105                 case 's':
106                         seed = optarg;
107                         break;
108                 case 'n':
109                         count_str = optarg;
110                         break;
111                 case 'C':
112                         mode = MODE_CDECL;
113                         break;
114                 case 'E':
115                         mode = MODE_ENGLISH;
116                         break;
117                 case 'V':
118                         test_print_version(PROGNAME);
119                         return EXIT_SUCCESS;
120                 case 'H':
121                         print_help();
122                         return EXIT_SUCCESS;
123                 default:
124                         print_usage(stderr);
125                         return EXIT_FAILURE;
126                 }
127         }
128
129         if (count_str && !strict_strtoul(&count, count_str, 0)) {
130                 fprintf(stderr, "%s: invalid count: %s\n", progname, count_str);
131                 return EXIT_FAILURE;
132         }
133
134         rng = gen_alloc_rng(seed);
135         if (!rng)
136                 return EXIT_FAILURE;
137
138         for (unsigned long i = 0; !count || i < count; i++) {
139                 decl = random_decl(rng);
140
141                 if (mode == MODE_ENGLISH) {
142                         test_explain_decl(decl);
143                 } else {
144                         test_print_decl(decl);
145                 }
146
147                 gen_free_declspecs(decl->specifiers);
148                 gen_free_declarators(decl->declarators);
149                 free(decl);
150         }
151
152         gen_free_rng(rng);
153
154         return EXIT_SUCCESS;
155 }