chiark / gitweb /
@@@ all the mess ever
[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 static struct bench_state benchstate;
60
61 const struct tvec_info tvec_adhocinfo =
62   { 0, 1, 1, sizeof(struct tvec_reg) };
63
64 static const struct outform *find_outform(const char *p)
65 {
66   const struct outform *best = 0, *of;
67   size_t n = strlen(p);
68
69   for (of = outtab; of->name; of++)
70     if (!STRNCMP(p, ==, of->name, n))
71       ;
72     else if (!of->name[n])
73       return (of);
74     else if (best)
75       die(2, "ambiguous output format name (`%s' or `%s'?)",
76           best->name, of->name);
77     else
78       best = of;
79   if (best) return (best);
80   else die(2, "unknown output format `%s'", optarg);
81 }
82
83 static void version(FILE *fp)
84   { pquis(fp, "$, mLib test-vector framework version " VERSION "\n"); }
85
86 static void usage(FILE *fp)
87 {
88   pquis(fp, "\
89 usage: $ [-f FORMAT] [-o OUTPUT] [-t SECS] [TEST-FILE ...]\n\
90 ");
91 }
92
93 static void help(FILE *fp)
94 {
95   version(fp); fputc('\n', fp);
96   usage(fp); fputs("\
97 Options:\n\
98   -h, --help            show this help text.\n\
99   -v, --version         show version number.\n\
100   -u, --usage           show usage synopsis.\n\
101 \n\
102   -f, --format=FORMAT   produce output in FORMAT.\n\
103   -o, --output=OUTPUT   write output to OUTPUT file.\n\
104   -t, --target=SECS     aim to run benchmarks for SECS.\n\
105 ", fp);
106 }
107
108 void tvec_parseargs(int argc, char *argv[], struct tvec_state *tv_out,
109                     int *argpos_out, const struct tvec_info *info)
110 {
111   FILE *ofp = 0;
112   const struct outform *of = 0;
113   struct tvec_output *o;
114   struct bench_timer *tm;
115   const char *p; char *q;
116   int opt;
117   double t;
118   unsigned f = 0;
119 #define f_bogus 1u
120
121   static const struct option options[] = {
122     { "help",           0,              0,      'h' },
123     { "version",        0,              0,      'v' },
124     { "usage",          0,              0,      'u' },
125
126     { "format",         OPTF_ARGREQ,    0,      'f' },
127     { "output",         OPTF_ARGREQ,    0,      'o' },
128     { "target",         OPTF_ARGREQ,    0,      't' },
129     { 0,                0,              0,      0 }
130   };
131
132   tvec_benchstate = &benchstate;
133   tm = bench_createtimer(); bench_init(&benchstate, tm);
134   ego(argv[0]);
135   for (;;) {
136     opt = mdwopt(argc, argv, "hvu" "f:o:t:", options, 0, 0, 0);
137     if (opt < 0) break;
138     switch (opt) {
139       case 'h': help(stdout); exit(0);
140       case 'v': version(stdout); exit(0);
141       case 'u': usage(stdout); exit(0);
142
143       case 'f': of = find_outform(optarg); break;
144       case 'o':
145         if (ofp) fclose(ofp);
146         ofp = fopen(optarg, "w");
147         if (!ofp)
148           die(2, "failed to open `%s' for writing: %s",
149               optarg, strerror(errno));
150         break;
151       case 't':
152         errno = 0; t = strtod(optarg, &q);
153         while (ISSPACE(*q)) q++;
154         if (errno || *q || t < 0) die(2, "invalid time `%s'", optarg);
155         benchstate.target_s = t;
156         break;
157
158       default:
159         f |= f_bogus;
160         break;
161     }
162   }
163   if (f&f_bogus) { usage(stderr); exit(2); }
164   if (!ofp) ofp = stdout;
165   if (!of) {
166     p = getenv("TVEC_FORMAT");
167     if (p) of = find_outform(p);
168   }
169   if (of) o = of->makefn(ofp);
170   else o = tvec_dfltout(ofp);
171
172   tvec_begin(tv_out, info, o); *argpos_out = optind;
173 }
174
175 void tvec_readstdin(struct tvec_state *tv)
176   { tvec_read(tv, "<stdin>", stdin); }
177
178 void tvec_readfile(struct tvec_state *tv, const char *file)
179 {
180   FILE *fp;
181
182   fp = fopen(file, "r");
183   if (!fp)
184     tvec_error(tv, "failed to open `%s' for reading: %s",
185                file, strerror(errno));
186   tvec_read(tv, file, fp);
187   fclose(fp);
188 }
189
190 void tvec_readdflt(struct tvec_state *tv, const char *file)
191 {
192   dstr d = DSTR_INIT;
193   const char *p;
194
195   if (file) {
196     p = getenv("srcdir");
197     if (p)
198       { dstr_putf(&d, "%s/%s", p, file); file = d.buf; }
199     tvec_readfile(tv, file);
200   } else if (isatty(0))
201     tvec_error(tv, "use `-' to force reading from interactive stdin");
202   else
203     tvec_readstdin(tv);
204 }
205
206 void tvec_readarg(struct tvec_state *tv, const char *arg)
207 {
208   if (STRCMP(arg, ==, "-")) tvec_readstdin(tv);
209   else tvec_readfile(tv, arg);
210 }
211
212 void tvec_readargs(int argc, char *argv[], struct tvec_state *tv,
213                    int *argpos_inout, const char *dflt)
214 {
215   int i = *argpos_inout;
216
217
218   if (i == argc) tvec_readdflt(tv, dflt);
219   else while (i < argc) tvec_readarg(tv, argv[i++]);
220   *argpos_inout = i;
221 }
222
223 int tvec_main(int argc, char *argv[],
224               const struct tvec_info *info, const char *dflt)
225 {
226   struct tvec_state tv;
227   int argpos;
228
229   tvec_parseargs(argc, argv, &tv, &argpos, info);
230   tvec_readargs(argc, argv, &tv, &argpos, dflt);
231   return (tvec_end(&tv));
232 }
233
234 /*----- That's all, folks -------------------------------------------------*/