chiark / gitweb /
@@@ so much mess
[mLib] / test / tvec-main.c
1 /* -*-c-*-
2  *
3  * Main entry point for test-vector processing
4  *
5  * (c) 2023 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the mLib utilities library.
11  *
12  * mLib is free software: you can redistribute it and/or modify it under
13  * the terms of the GNU Library General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or (at
15  * your option) any later version.
16  *
17  * mLib is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
20  * License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with mLib.  If not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25  * USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include "config.h"
31
32 #include <ctype.h>
33 #include <errno.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <unistd.h>
39
40 #include "bench.h"
41 #include "dstr.h"
42 #include "macros.h"
43 #include "mdwopt.h"
44 #include "quis.h"
45 #include "report.h"
46 #include "tvec.h"
47
48 /*----- Main code ---------------------------------------------------------*/
49
50 static const struct outform {
51   const char *name;
52   struct tvec_output *(*makefn)(FILE *fp);
53 } outtab[] = {
54   { "human",            tvec_humanoutput },
55   { "tap",              tvec_tapoutput },
56   { 0,                  0 }
57 };
58
59 const struct tvec_info tvec_adhocinfo =
60   { 0, 1, 1, sizeof(struct tvec_reg) };
61
62 static const struct outform *find_outform(const char *p)
63 {
64   const struct outform *best = 0, *of;
65   size_t n = strlen(p);
66
67   for (of = outtab; of->name; of++)
68     if (!STRNCMP(p, ==, of->name, n))
69       ;
70     else if (!of->name[n])
71       return (of);
72     else if (best)
73       die(2, "ambiguous output format name (`%s' or `%s'?)",
74           best->name, of->name);
75     else
76       best = of;
77   if (best) return (best);
78   else die(2, "unknown output format `%s'", optarg);
79 }
80
81 static void version(FILE *fp)
82   { pquis(fp, "$, mLib test-vector framework version " VERSION "\n"); }
83
84 static void usage(FILE *fp)
85 {
86   pquis(fp, "\
87 usage: $ [-f FORMAT] [-o OUTPUT] [-t SECS] [TEST-FILE ...]\n\
88 ");
89 }
90
91 static void help(FILE *fp)
92 {
93   version(fp); fputc('\n', fp);
94   usage(fp); fputs("\
95 Options:\n\
96   -h, --help            show this help text.\n\
97   -v, --version         show version number.\n\
98   -u, --usage           show usage synopsis.\n\
99 \n\
100   -f, --format=FORMAT   produce output in FORMAT.\n\
101   -o, --output=OUTPUT   write output to OUTPUT file.\n\
102 ", fp);
103 }
104
105 void tvec_parseargs(int argc, char *argv[], struct tvec_state *tv_out,
106                     int *argpos_out, const struct tvec_info *info)
107 {
108   FILE *ofp = 0;
109   const struct outform *of = 0;
110   struct tvec_output *o;
111   const char *p;
112   int opt;
113   unsigned f = 0;
114 #define f_bogus 1u
115
116   static const struct option options[] = {
117     { "help",           0,              0,      'h' },
118     { "version",        0,              0,      'v' },
119     { "usage",          0,              0,      'u' },
120
121     { "format",         OPTF_ARGREQ,    0,      'f' },
122     { "output",         OPTF_ARGREQ,    0,      'o' },
123     { 0,                0,              0,      0 }
124   };
125
126   ego(argv[0]);
127   for (;;) {
128     opt = mdwopt(argc, argv, "hvu" "f:o:", options, 0, 0, 0);
129     if (opt < 0) break;
130     switch (opt) {
131       case 'h': help(stdout); exit(0);
132       case 'v': version(stdout); exit(0);
133       case 'u': usage(stdout); exit(0);
134
135       case 'f': of = find_outform(optarg); break;
136       case 'o':
137         if (ofp) fclose(ofp);
138         ofp = fopen(optarg, "w");
139         if (!ofp)
140           die(2, "failed to open `%s' for writing: %s",
141               optarg, strerror(errno));
142         break;
143
144       default:
145         f |= f_bogus;
146         break;
147     }
148   }
149   if (f&f_bogus) { usage(stderr); exit(2); }
150   if (!ofp) ofp = stdout;
151   if (!of) {
152     p = getenv("TVEC_FORMAT");
153     if (p) of = find_outform(p);
154   }
155   if (of) o = of->makefn(ofp);
156   else o = tvec_dfltout(ofp);
157
158   tvec_begin(tv_out, info, o); *argpos_out = optind;
159 }
160
161 int tvec_readstdin(struct tvec_state *tv)
162   { return (tvec_read(tv, "<stdin>", stdin)); }
163
164 int tvec_readfile(struct tvec_state *tv, const char *file)
165 {
166   FILE *fp = 0;
167   int rc;
168
169   fp = fopen(file, "r");
170   if (!fp) {
171     tvec_error(tv, "failed to open `%s' for reading: %s",
172                file, strerror(errno));
173     rc = -1; goto end;
174   }
175   if (tvec_read(tv, file, fp)) { rc = -1; goto end; }
176   rc = 0;
177 end:
178   if (fp) fclose(fp);
179   return (rc);
180 }
181
182 int tvec_readdflt(struct tvec_state *tv, const char *file)
183 {
184   dstr d = DSTR_INIT;
185   const char *p;
186   int rc;
187
188   if (file) {
189     p = getenv("srcdir");
190     if (p) { dstr_putf(&d, "%s/%s", p, file); file = d.buf; }
191     rc = tvec_readfile(tv, file);
192   } else if (isatty(0))
193     rc = tvec_error(tv, "use `-' to force reading from interactive stdin");
194   else
195     rc = tvec_readstdin(tv);
196   dstr_destroy(&d);
197   return (rc);
198 }
199
200 int tvec_readarg(struct tvec_state *tv, const char *arg)
201 {
202   int rc;
203
204   if (STRCMP(arg, ==, "-")) rc = tvec_readstdin(tv);
205   else rc = tvec_readfile(tv, arg);
206   return (rc);
207 }
208
209 int tvec_readargs(int argc, char *argv[], struct tvec_state *tv,
210                    int *argpos_inout, const char *dflt)
211 {
212   int i = *argpos_inout;
213   int rc;
214
215   if (i == argc) rc = tvec_readdflt(tv, dflt);
216   else {
217     rc = 0;
218     while (i < argc)
219       if (tvec_readarg(tv, argv[i++])) rc = -1;
220   }
221   *argpos_inout = i;
222   return (rc);
223 }
224
225 int tvec_main(int argc, char *argv[],
226               const struct tvec_info *info, const char *dflt)
227 {
228   struct tvec_state tv;
229   int argpos;
230
231   tvec_parseargs(argc, argv, &tv, &argpos, info);
232   tvec_readargs(argc, argv, &tv, &argpos, dflt);
233   return (tvec_end(&tv));
234 }
235
236 /*----- That's all, folks -------------------------------------------------*/