]> git.draconx.ca Git - cdecl99.git/blob - t/scantest.c
Port to use getline.h from dxcommon.
[cdecl99.git] / t / scantest.c
1 /*
2  * Helper to verify scanner output.
3  * Copyright © 2023-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 <getopt.h>
23
24 #include "scan.h"
25 #include "cdecl-internal.h"
26
27 #define PROGNAME "scantest"
28 #include "test.h"
29
30 /* Stubs */
31 static union { struct parse_item item; char buf[1000]; } stub_item;
32 struct parse_item *cdecl__alloc_item(size_t sz)
33 {
34         return &stub_item.item;
35 }
36
37 void cdecl__errmsg(unsigned msg)
38 {
39 }
40
41 void cdecl__err(const char *fmt, const char *arg)
42 {
43 }
44
45 size_t cdecl__strlcpy(char *dst, const char *src, size_t len)
46 {
47         abort();
48 }
49
50 static const char sopts[] = "ECVH";
51 static const struct option lopts[] = {
52         { "cdecl",   0, NULL, 'C' },
53         { "english", 0, NULL, 'E' },
54         { "version", 0, NULL, 'V' },
55         { "help",    0, NULL, 'H' },
56         { 0 }
57 };
58
59 static void print_usage(FILE *f)
60 {
61         fprintf(f, "Usage: %s [options] string [string ...]\n", progname);
62 }
63
64 static void print_help(void)
65 {
66         print_usage(stdout);
67         puts("Test the scanner by tokenizing one or more strings.\n");
68         test_print_options(lopts);
69 }
70
71 enum {
72         MODE_CDECL,
73         MODE_ENGLISH
74 };
75
76 static int print_uintmax_rec(char *buf, uintmax_t v)
77 {
78         int rc = 0;
79
80         if (v > 9) {
81                 rc = print_uintmax_rec(buf, v/10);
82                 v %= 10;
83         }
84
85         buf[rc] = '0' + v;
86         return rc + 1;
87 }
88
89 static void print_uintmax(char *buf, uintmax_t v)
90 {
91         buf[print_uintmax_rec(buf, v)] = 0;
92 }
93
94 static int do_scan(const char *s, int mode)
95 {
96         YY_BUFFER_STATE state;
97         yyscan_t scanner;
98         YYSTYPE lval;
99         YYLTYPE lloc;
100         int tok;
101
102         if (cdecl__yylex_init_extra(mode, &scanner) != 0)
103                 return -1;
104
105         state = cdecl__yy_scan_string(s, scanner);
106
107         while ((tok = cdecl__yylex(&lval, &lloc, scanner))) {
108                 const char *tname = cdecl__token_name(tok);
109
110                 switch (tok) {
111                 case T_UINT:
112                         print_uintmax(stub_item.item.s, lval.uintval);
113                         lval.item = &stub_item.item;
114                 case T_IDENT:
115                         printf("%s %s\n", tname, lval.item->s);
116                         break;
117                 default:
118                         printf("%s\n", tname);
119                 }
120         }
121         printf("eof\n");
122
123         cdecl__yy_delete_buffer(state, scanner);
124         cdecl__yylex_destroy(scanner);
125         return 0;
126 }
127
128 int main(int argc, char **argv)
129 {
130         int i, opt, mode = MODE_CDECL;
131
132         if (argc > 0)
133                 progname = argv[0];
134
135         while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
136                 switch (opt) {
137                 case 'C':
138                         mode = MODE_CDECL;
139                         break;
140                 case 'E':
141                         mode = MODE_ENGLISH;
142                         break;
143                 case 'V':
144                         test_print_version(PROGNAME);
145                         return EXIT_SUCCESS;
146                 case 'H':
147                         print_help();
148                         return EXIT_SUCCESS;
149                 default:
150                         print_usage(stderr);
151                         return EXIT_FAILURE;
152                 }
153         }
154
155         if (!argv[optind]) {
156                 print_usage(stderr);
157                 return EXIT_FAILURE;
158         }
159
160         for (i = optind; i < argc; i++) {
161                 if (do_scan(argv[i], mode) != 0)
162                         return EXIT_FAILURE;
163         }
164
165         return 0;
166 }