1178825Sdfr%{
2178825Sdfr/*
3233294Sstas * Copyright (c) 2004-2006 Kungliga Tekniska H��gskolan
4233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
5233294Sstas * All rights reserved.
6178825Sdfr *
7233294Sstas * Redistribution and use in source and binary forms, with or without
8233294Sstas * modification, are permitted provided that the following conditions
9233294Sstas * are met:
10178825Sdfr *
11233294Sstas * 1. Redistributions of source code must retain the above copyright
12233294Sstas *    notice, this list of conditions and the following disclaimer.
13178825Sdfr *
14233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
15233294Sstas *    notice, this list of conditions and the following disclaimer in the
16233294Sstas *    documentation and/or other materials provided with the distribution.
17178825Sdfr *
18233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
19233294Sstas *    may be used to endorse or promote products derived from this software
20233294Sstas *    without specific prior written permission.
21178825Sdfr *
22233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32233294Sstas * SUCH DAMAGE.
33178825Sdfr */
34178825Sdfr
35178825Sdfr#include <config.h>
36178825Sdfr
37178825Sdfr#include <stdio.h>
38178825Sdfr#include <stdlib.h>
39178825Sdfr#include <err.h>
40178825Sdfr#include <ctype.h>
41178825Sdfr#include <limits.h>
42178825Sdfr#include <getarg.h>
43178825Sdfr#include <vers.h>
44178825Sdfr#include <roken.h>
45178825Sdfr
46178825Sdfr#include "slc.h"
47178825Sdfrextern FILE *yyin;
48178825Sdfrextern struct assignment *assignment;
49222081Sbenlextern int yyparse(void);
50233294Sstas
51233294Sstas/* Declarations for Bison:
52233294Sstas */
53233294Sstas#define YYMALLOC        malloc
54233294Sstas#define YYFREE          free
55233294Sstas
56178825Sdfr%}
57178825Sdfr
58178825Sdfr%union {
59178825Sdfr	char *string;
60178825Sdfr	struct assignment *assignment;
61178825Sdfr}
62178825Sdfr
63178825Sdfr%token <string> LITERAL
64178825Sdfr%token <string> STRING
65178825Sdfr%type <assignment> assignment assignments
66178825Sdfr
67178825Sdfr%start start
68178825Sdfr
69178825Sdfr%%
70178825Sdfr
71178825Sdfrstart		: assignments
72178825Sdfr		{
73178825Sdfr			assignment = $1;
74178825Sdfr		}
75178825Sdfr		;
76178825Sdfr
77178825Sdfrassignments	: assignment assignments
78178825Sdfr		{
79178825Sdfr			$1->next = $2;
80178825Sdfr			$$ = $1;
81178825Sdfr		}
82178825Sdfr		| assignment
83178825Sdfr		;
84178825Sdfr
85178825Sdfrassignment	: LITERAL '=' STRING
86178825Sdfr		{
87178825Sdfr			$$ = malloc(sizeof(*$$));
88178825Sdfr			$$->name = $1;
89178825Sdfr			$$->type = a_value;
90178825Sdfr			$$->lineno = lineno;
91178825Sdfr			$$->u.value = $3;
92178825Sdfr			$$->next = NULL;
93178825Sdfr		}
94178825Sdfr		| LITERAL '=' '{' assignments '}'
95178825Sdfr		{
96178825Sdfr			$$ = malloc(sizeof(*$$));
97178825Sdfr			$$->name = $1;
98178825Sdfr			$$->type = a_assignment;
99178825Sdfr			$$->lineno = lineno;
100178825Sdfr			$$->u.assignment = $4;
101178825Sdfr			$$->next = NULL;
102178825Sdfr		}
103178825Sdfr		;
104178825Sdfr
105178825Sdfr%%
106178825Sdfrchar *filename;
107178825SdfrFILE *cfile, *hfile;
108178825Sdfrint error_flag;
109178825Sdfrstruct assignment *assignment;
110178825Sdfr
111178825Sdfr
112178825Sdfrstatic void
113178825Sdfrex(struct assignment *a, const char *fmt, ...)
114178825Sdfr{
115178825Sdfr    va_list ap;
116178825Sdfr    fprintf(stderr, "%s:%d: ", a->name, a->lineno);
117178825Sdfr    va_start(ap, fmt);
118178825Sdfr    vfprintf(stderr, fmt, ap);
119178825Sdfr    va_end(ap);
120178825Sdfr    fprintf(stderr, "\n");
121178825Sdfr}
122178825Sdfr
123178825Sdfr
124178825Sdfr
125178825Sdfrstatic int
126178825Sdfrcheck_option(struct assignment *as)
127178825Sdfr{
128178825Sdfr    struct assignment *a;
129178825Sdfr    int seen_long = 0;
130233294Sstas    int seen_name = 0;
131178825Sdfr    int seen_short = 0;
132178825Sdfr    int seen_type = 0;
133178825Sdfr    int seen_argument = 0;
134178825Sdfr    int seen_help = 0;
135178825Sdfr    int seen_default = 0;
136178825Sdfr    int ret = 0;
137178825Sdfr
138178825Sdfr    for(a = as; a != NULL; a = a->next) {
139178825Sdfr	if(strcmp(a->name, "long") == 0)
140178825Sdfr	    seen_long++;
141178825Sdfr	else if(strcmp(a->name, "short") == 0)
142178825Sdfr	    seen_short++;
143233294Sstas	else if(strcmp(a->name, "name") == 0)
144233294Sstas	    seen_name++;
145178825Sdfr	else if(strcmp(a->name, "type") == 0)
146178825Sdfr	    seen_type++;
147178825Sdfr	else if(strcmp(a->name, "argument") == 0)
148178825Sdfr	    seen_argument++;
149178825Sdfr	else if(strcmp(a->name, "help") == 0)
150178825Sdfr	    seen_help++;
151178825Sdfr	else if(strcmp(a->name, "default") == 0)
152178825Sdfr	    seen_default++;
153178825Sdfr	else {
154233294Sstas	    ex(a, "unknown name %s", a->name);
155178825Sdfr	    ret++;
156178825Sdfr	}
157178825Sdfr    }
158178825Sdfr    if(seen_long == 0 && seen_short == 0) {
159178825Sdfr	ex(as, "neither long nor short option");
160178825Sdfr	ret++;
161178825Sdfr    }
162233294Sstas    if (seen_long == 0 && seen_name == 0) {
163233294Sstas	ex(as, "either of long or name option must be used");
164233294Sstas	ret++;
165233294Sstas    }
166178825Sdfr    if(seen_long > 1) {
167178825Sdfr	ex(as, "multiple long options");
168178825Sdfr	ret++;
169178825Sdfr    }
170178825Sdfr    if(seen_short > 1) {
171178825Sdfr	ex(as, "multiple short options");
172178825Sdfr	ret++;
173178825Sdfr    }
174178825Sdfr    if(seen_type > 1) {
175178825Sdfr	ex(as, "multiple types");
176178825Sdfr	ret++;
177178825Sdfr    }
178178825Sdfr    if(seen_argument > 1) {
179178825Sdfr	ex(as, "multiple arguments");
180178825Sdfr	ret++;
181178825Sdfr    }
182178825Sdfr    if(seen_help > 1) {
183178825Sdfr	ex(as, "multiple help strings");
184178825Sdfr	ret++;
185178825Sdfr    }
186178825Sdfr    if(seen_default > 1) {
187178825Sdfr	ex(as, "multiple default values");
188178825Sdfr	ret++;
189178825Sdfr    }
190178825Sdfr    return ret;
191178825Sdfr}
192178825Sdfr
193178825Sdfrstatic int
194178825Sdfrcheck_command(struct assignment *as)
195178825Sdfr{
196178825Sdfr	struct assignment *a;
197178825Sdfr	int seen_name = 0;
198178825Sdfr	int seen_function = 0;
199178825Sdfr	int seen_help = 0;
200178825Sdfr	int seen_argument = 0;
201178825Sdfr	int seen_minargs = 0;
202178825Sdfr	int seen_maxargs = 0;
203178825Sdfr	int ret = 0;
204178825Sdfr	for(a = as; a != NULL; a = a->next) {
205178825Sdfr		if(strcmp(a->name, "name") == 0)
206178825Sdfr			seen_name++;
207178825Sdfr		else if(strcmp(a->name, "function") == 0) {
208178825Sdfr			seen_function++;
209178825Sdfr		} else if(strcmp(a->name, "option") == 0)
210178825Sdfr			ret += check_option(a->u.assignment);
211178825Sdfr		else if(strcmp(a->name, "help") == 0) {
212178825Sdfr			seen_help++;
213178825Sdfr		} else if(strcmp(a->name, "argument") == 0) {
214178825Sdfr			seen_argument++;
215178825Sdfr		} else if(strcmp(a->name, "min_args") == 0) {
216178825Sdfr			seen_minargs++;
217178825Sdfr		} else if(strcmp(a->name, "max_args") == 0) {
218178825Sdfr			seen_maxargs++;
219178825Sdfr		} else {
220233294Sstas			ex(a, "unknown name: %s", a->name);
221178825Sdfr			ret++;
222178825Sdfr		}
223178825Sdfr	}
224178825Sdfr	if(seen_name == 0) {
225178825Sdfr		ex(as, "no command name");
226178825Sdfr		ret++;
227178825Sdfr	}
228178825Sdfr	if(seen_function > 1) {
229178825Sdfr		ex(as, "multiple function names");
230178825Sdfr		ret++;
231178825Sdfr	}
232178825Sdfr	if(seen_help > 1) {
233178825Sdfr		ex(as, "multiple help strings");
234178825Sdfr		ret++;
235178825Sdfr	}
236178825Sdfr	if(seen_argument > 1) {
237178825Sdfr		ex(as, "multiple argument strings");
238178825Sdfr		ret++;
239178825Sdfr	}
240178825Sdfr	if(seen_minargs > 1) {
241178825Sdfr		ex(as, "multiple min_args strings");
242178825Sdfr		ret++;
243178825Sdfr	}
244178825Sdfr	if(seen_maxargs > 1) {
245178825Sdfr		ex(as, "multiple max_args strings");
246178825Sdfr		ret++;
247178825Sdfr	}
248233294Sstas
249178825Sdfr	return ret;
250178825Sdfr}
251178825Sdfr
252178825Sdfrstatic int
253178825Sdfrcheck(struct assignment *as)
254178825Sdfr{
255178825Sdfr    struct assignment *a;
256178825Sdfr    int ret = 0;
257178825Sdfr    for(a = as; a != NULL; a = a->next) {
258178825Sdfr	if(strcmp(a->name, "command")) {
259178825Sdfr	    fprintf(stderr, "unknown type %s line %d\n", a->name, a->lineno);
260178825Sdfr	    ret++;
261178825Sdfr	    continue;
262178825Sdfr	}
263178825Sdfr	if(a->type != a_assignment) {
264178825Sdfr	    fprintf(stderr, "bad command definition %s line %d\n", a->name, a->lineno);
265178825Sdfr	    ret++;
266178825Sdfr	    continue;
267178825Sdfr	}
268178825Sdfr	ret += check_command(a->u.assignment);
269178825Sdfr    }
270178825Sdfr    return ret;
271178825Sdfr}
272178825Sdfr
273178825Sdfrstatic struct assignment *
274178825Sdfrfind_next(struct assignment *as, const char *name)
275178825Sdfr{
276178825Sdfr    for(as = as->next; as != NULL; as = as->next) {
277178825Sdfr	if(strcmp(as->name, name) == 0)
278178825Sdfr	    return as;
279178825Sdfr    }
280178825Sdfr    return NULL;
281178825Sdfr}
282178825Sdfr
283178825Sdfrstatic struct assignment *
284178825Sdfrfind(struct assignment *as, const char *name)
285178825Sdfr{
286178825Sdfr    for(; as != NULL; as = as->next) {
287178825Sdfr	if(strcmp(as->name, name) == 0)
288178825Sdfr	    return as;
289178825Sdfr    }
290178825Sdfr    return NULL;
291178825Sdfr}
292178825Sdfr
293178825Sdfrstatic void
294178825Sdfrspace(FILE *f, int level)
295178825Sdfr{
296178825Sdfr    fprintf(f, "%*.*s", level * 4, level * 4, " ");
297178825Sdfr}
298178825Sdfr
299178825Sdfrstatic void
300178825Sdfrcprint(int level, const char *fmt, ...)
301178825Sdfr{
302178825Sdfr    va_list ap;
303178825Sdfr    va_start(ap, fmt);
304178825Sdfr    space(cfile, level);
305178825Sdfr    vfprintf(cfile, fmt, ap);
306178825Sdfr    va_end(ap);
307178825Sdfr}
308178825Sdfr
309178825Sdfrstatic void
310178825Sdfrhprint(int level, const char *fmt, ...)
311178825Sdfr{
312178825Sdfr    va_list ap;
313178825Sdfr    va_start(ap, fmt);
314178825Sdfr    space(hfile, level);
315178825Sdfr    vfprintf(hfile, fmt, ap);
316178825Sdfr    va_end(ap);
317178825Sdfr}
318178825Sdfr
319178825Sdfrstatic void gen_name(char *str);
320178825Sdfr
321178825Sdfrstatic void
322178825Sdfrgen_command(struct assignment *as)
323178825Sdfr{
324178825Sdfr    struct assignment *a, *b;
325178825Sdfr    char *f;
326178825Sdfr    a = find(as, "name");
327178825Sdfr    f = strdup(a->u.value);
328178825Sdfr    gen_name(f);
329178825Sdfr    cprint(1, "    { ");
330178825Sdfr    fprintf(cfile, "\"%s\", ", a->u.value);
331178825Sdfr    fprintf(cfile, "%s_wrap, ", f);
332178825Sdfr    b = find(as, "argument");
333178825Sdfr    if(b)
334178825Sdfr	fprintf(cfile, "\"%s %s\", ", a->u.value, b->u.value);
335178825Sdfr    else
336178825Sdfr	fprintf(cfile, "\"%s\", ", a->u.value);
337178825Sdfr    b = find(as, "help");
338178825Sdfr    if(b)
339178825Sdfr	fprintf(cfile, "\"%s\"", b->u.value);
340178825Sdfr    else
341178825Sdfr	fprintf(cfile, "NULL");
342178825Sdfr    fprintf(cfile, " },\n");
343178825Sdfr    for(a = a->next; a != NULL; a = a->next)
344178825Sdfr	if(strcmp(a->name, "name") == 0)
345178825Sdfr	    cprint(1, "    { \"%s\" },\n", a->u.value);
346178825Sdfr    cprint(0, "\n");
347178825Sdfr}
348178825Sdfr
349178825Sdfrstatic void
350178825Sdfrgen_name(char *str)
351178825Sdfr{
352178825Sdfr    char *p;
353178825Sdfr    for(p = str; *p != '\0'; p++)
354178825Sdfr	if(!isalnum((unsigned char)*p))
355178825Sdfr	    *p = '_';
356178825Sdfr}
357178825Sdfr
358178825Sdfrstatic char *
359178825Sdfrmake_name(struct assignment *as)
360178825Sdfr{
361178825Sdfr    struct assignment *lopt;
362178825Sdfr    struct assignment *type;
363178825Sdfr    char *s;
364178825Sdfr
365178825Sdfr    lopt = find(as, "long");
366178825Sdfr    if(lopt == NULL)
367178825Sdfr	lopt = find(as, "name");
368178825Sdfr    if(lopt == NULL)
369178825Sdfr	return NULL;
370233294Sstas
371178825Sdfr    type = find(as, "type");
372178825Sdfr    if(strcmp(type->u.value, "-flag") == 0)
373178825Sdfr	asprintf(&s, "%s_flag", lopt->u.value);
374178825Sdfr    else
375178825Sdfr	asprintf(&s, "%s_%s", lopt->u.value, type->u.value);
376178825Sdfr    gen_name(s);
377178825Sdfr    return s;
378178825Sdfr}
379178825Sdfr
380178825Sdfr
381178825Sdfrstatic void defval_int(const char *name, struct assignment *defval)
382178825Sdfr{
383178825Sdfr    if(defval != NULL)
384178825Sdfr	cprint(1, "opt.%s = %s;\n", name, defval->u.value);
385178825Sdfr    else
386178825Sdfr	cprint(1, "opt.%s = 0;\n", name);
387178825Sdfr}
388233294Sstasstatic void defval_neg_flag(const char *name, struct assignment *defval)
389178825Sdfr{
390178825Sdfr    if(defval != NULL)
391233294Sstas	cprint(1, "opt.%s = %s;\n", name, defval->u.value);
392178825Sdfr    else
393233294Sstas	cprint(1, "opt.%s = 1;\n", name);
394233294Sstas}
395233294Sstasstatic void defval_string(const char *name, struct assignment *defval)
396233294Sstas{
397233294Sstas    if(defval != NULL)
398233294Sstas	cprint(1, "opt.%s = (char *)(unsigned long)\"%s\";\n", name, defval->u.value);
399233294Sstas    else
400178825Sdfr	cprint(1, "opt.%s = NULL;\n", name);
401178825Sdfr}
402178825Sdfrstatic void defval_strings(const char *name, struct assignment *defval)
403178825Sdfr{
404178825Sdfr    cprint(1, "opt.%s.num_strings = 0;\n", name);
405178825Sdfr    cprint(1, "opt.%s.strings = NULL;\n", name);
406178825Sdfr}
407178825Sdfr
408178825Sdfrstatic void free_strings(const char *name)
409178825Sdfr{
410178825Sdfr    cprint(1, "free_getarg_strings (&opt.%s);\n", name);
411178825Sdfr}
412178825Sdfr
413178825Sdfrstruct type_handler {
414178825Sdfr    const char *typename;
415178825Sdfr    const char *c_type;
416178825Sdfr    const char *getarg_type;
417178825Sdfr    void (*defval)(const char*, struct assignment*);
418178825Sdfr    void (*free)(const char*);
419178825Sdfr} type_handlers[] = {
420178825Sdfr	{ "integer",
421178825Sdfr	  "int",
422178825Sdfr	  "arg_integer",
423178825Sdfr	  defval_int,
424178825Sdfr	  NULL
425178825Sdfr	},
426178825Sdfr	{ "string",
427178825Sdfr	  "char*",
428178825Sdfr	  "arg_string",
429178825Sdfr	  defval_string,
430178825Sdfr	  NULL
431178825Sdfr	},
432178825Sdfr	{ "strings",
433178825Sdfr	  "struct getarg_strings",
434178825Sdfr	  "arg_strings",
435178825Sdfr	  defval_strings,
436178825Sdfr	  free_strings
437178825Sdfr	},
438178825Sdfr	{ "flag",
439178825Sdfr	  "int",
440178825Sdfr	  "arg_flag",
441178825Sdfr	  defval_int,
442178825Sdfr	  NULL
443178825Sdfr	},
444178825Sdfr	{ "-flag",
445178825Sdfr	  "int",
446178825Sdfr	  "arg_negative_flag",
447233294Sstas	  defval_neg_flag,
448178825Sdfr	  NULL
449178825Sdfr	},
450178825Sdfr	{ NULL }
451178825Sdfr};
452178825Sdfr
453178825Sdfrstatic struct type_handler *find_handler(struct assignment *type)
454178825Sdfr{
455178825Sdfr    struct type_handler *th;
456178825Sdfr    for(th = type_handlers; th->typename != NULL; th++)
457178825Sdfr	if(strcmp(type->u.value, th->typename) == 0)
458178825Sdfr	    return th;
459178825Sdfr    ex(type, "unknown type \"%s\"", type->u.value);
460178825Sdfr    exit(1);
461178825Sdfr}
462178825Sdfr
463178825Sdfrstatic void
464178825Sdfrgen_options(struct assignment *opt1, const char *name)
465178825Sdfr{
466178825Sdfr    struct assignment *tmp;
467178825Sdfr
468178825Sdfr    hprint(0, "struct %s_options {\n", name);
469178825Sdfr
470233294Sstas    for(tmp = opt1;
471233294Sstas	tmp != NULL;
472178825Sdfr	tmp = find_next(tmp, "option")) {
473178825Sdfr	struct assignment *type;
474178825Sdfr	struct type_handler *th;
475178825Sdfr	char *s;
476233294Sstas
477178825Sdfr	s = make_name(tmp->u.assignment);
478178825Sdfr	type = find(tmp->u.assignment, "type");
479178825Sdfr	th = find_handler(type);
480178825Sdfr	hprint(1, "%s %s;\n", th->c_type, s);
481178825Sdfr	free(s);
482178825Sdfr    }
483178825Sdfr    hprint(0, "};\n");
484178825Sdfr}
485178825Sdfr
486178825Sdfrstatic void
487178825Sdfrgen_wrapper(struct assignment *as)
488178825Sdfr{
489178825Sdfr    struct assignment *name;
490178825Sdfr    struct assignment *arg;
491178825Sdfr    struct assignment *opt1;
492178825Sdfr    struct assignment *function;
493178825Sdfr    struct assignment *tmp;
494178825Sdfr    char *n, *f;
495178825Sdfr    int nargs = 0;
496233294Sstas    int narguments = 0;
497178825Sdfr
498178825Sdfr    name = find(as, "name");
499178825Sdfr    n = strdup(name->u.value);
500178825Sdfr    gen_name(n);
501178825Sdfr    arg = find(as, "argument");
502233294Sstas    if (arg)
503233294Sstas        narguments++;
504178825Sdfr    opt1 = find(as, "option");
505178825Sdfr    function = find(as, "function");
506178825Sdfr    if(function)
507178825Sdfr	f = function->u.value;
508178825Sdfr    else
509178825Sdfr	f = n;
510233294Sstas
511233294Sstas
512178825Sdfr    if(opt1 != NULL) {
513178825Sdfr	gen_options(opt1, n);
514178825Sdfr	hprint(0, "int %s(struct %s_options*, int, char **);\n", f, n);
515178825Sdfr    } else {
516178825Sdfr	hprint(0, "int %s(void*, int, char **);\n", f);
517178825Sdfr    }
518178825Sdfr
519178825Sdfr    fprintf(cfile, "static int\n");
520178825Sdfr    fprintf(cfile, "%s_wrap(int argc, char **argv)\n", n);
521178825Sdfr    fprintf(cfile, "{\n");
522178825Sdfr    if(opt1 != NULL)
523178825Sdfr	cprint(1, "struct %s_options opt;\n", n);
524178825Sdfr    cprint(1, "int ret;\n");
525178825Sdfr    cprint(1, "int optidx = 0;\n");
526178825Sdfr    cprint(1, "struct getargs args[] = {\n");
527233294Sstas    for(tmp = find(as, "option");
528233294Sstas	tmp != NULL;
529178825Sdfr	tmp = find_next(tmp, "option")) {
530178825Sdfr	struct assignment *type = find(tmp->u.assignment, "type");
531178825Sdfr	struct assignment *lopt = find(tmp->u.assignment, "long");
532178825Sdfr	struct assignment *sopt = find(tmp->u.assignment, "short");
533178825Sdfr	struct assignment *aarg = find(tmp->u.assignment, "argument");
534178825Sdfr	struct assignment *help = find(tmp->u.assignment, "help");
535178825Sdfr
536178825Sdfr	struct type_handler *th;
537233294Sstas
538178825Sdfr	cprint(2, "{ ");
539178825Sdfr	if(lopt)
540178825Sdfr	    fprintf(cfile, "\"%s\", ", lopt->u.value);
541178825Sdfr	else
542178825Sdfr	    fprintf(cfile, "NULL, ");
543178825Sdfr	if(sopt)
544178825Sdfr	    fprintf(cfile, "'%c', ", *sopt->u.value);
545178825Sdfr	else
546178825Sdfr	    fprintf(cfile, "0, ");
547178825Sdfr	th = find_handler(type);
548178825Sdfr	fprintf(cfile, "%s, ", th->getarg_type);
549178825Sdfr	fprintf(cfile, "NULL, ");
550178825Sdfr	if(help)
551178825Sdfr	    fprintf(cfile, "\"%s\", ", help->u.value);
552178825Sdfr	else
553178825Sdfr	    fprintf(cfile, "NULL, ");
554233294Sstas	if(aarg) {
555178825Sdfr	    fprintf(cfile, "\"%s\"", aarg->u.value);
556233294Sstas            narguments++;
557233294Sstas	} else
558178825Sdfr	    fprintf(cfile, "NULL");
559178825Sdfr	fprintf(cfile, " },\n");
560178825Sdfr    }
561178825Sdfr    cprint(2, "{ \"help\", 'h', arg_flag, NULL, NULL, NULL }\n");
562178825Sdfr    cprint(1, "};\n");
563178825Sdfr    cprint(1, "int help_flag = 0;\n");
564178825Sdfr
565233294Sstas    for(tmp = find(as, "option");
566233294Sstas	tmp != NULL;
567178825Sdfr	tmp = find_next(tmp, "option")) {
568178825Sdfr	char *s;
569178825Sdfr	struct assignment *type = find(tmp->u.assignment, "type");
570178825Sdfr
571178825Sdfr	struct assignment *defval = find(tmp->u.assignment, "default");
572178825Sdfr
573178825Sdfr	struct type_handler *th;
574233294Sstas
575178825Sdfr	s = make_name(tmp->u.assignment);
576178825Sdfr	th = find_handler(type);
577178825Sdfr	(*th->defval)(s, defval);
578178825Sdfr	free(s);
579178825Sdfr    }
580178825Sdfr
581233294Sstas    for(tmp = find(as, "option");
582233294Sstas	tmp != NULL;
583178825Sdfr	tmp = find_next(tmp, "option")) {
584178825Sdfr	char *s;
585178825Sdfr	s = make_name(tmp->u.assignment);
586178825Sdfr	cprint(1, "args[%d].value = &opt.%s;\n", nargs++, s);
587178825Sdfr	free(s);
588178825Sdfr    }
589178825Sdfr    cprint(1, "args[%d].value = &help_flag;\n", nargs++);
590178825Sdfr    cprint(1, "if(getarg(args, %d, argc, argv, &optidx))\n", nargs);
591178825Sdfr    cprint(2, "goto usage;\n");
592178825Sdfr
593178825Sdfr    {
594178825Sdfr	int min_args = -1;
595178825Sdfr	int max_args = -1;
596178825Sdfr	char *end;
597233294Sstas	if(narguments == 0) {
598178825Sdfr	    max_args = 0;
599178825Sdfr	} else {
600178825Sdfr	    if((tmp = find(as, "min_args")) != NULL) {
601178825Sdfr		min_args = strtol(tmp->u.value, &end, 0);
602178825Sdfr		if(*end != '\0') {
603178825Sdfr		    ex(tmp, "min_args is not numeric");
604178825Sdfr		    exit(1);
605178825Sdfr		}
606178825Sdfr		if(min_args < 0) {
607178825Sdfr		    ex(tmp, "min_args must be non-negative");
608178825Sdfr		    exit(1);
609178825Sdfr		}
610178825Sdfr	    }
611178825Sdfr	    if((tmp = find(as, "max_args")) != NULL) {
612178825Sdfr		max_args = strtol(tmp->u.value, &end, 0);
613178825Sdfr		if(*end != '\0') {
614178825Sdfr		    ex(tmp, "max_args is not numeric");
615178825Sdfr		    exit(1);
616178825Sdfr		}
617178825Sdfr		if(max_args < 0) {
618178825Sdfr		    ex(tmp, "max_args must be non-negative");
619178825Sdfr		    exit(1);
620178825Sdfr		}
621178825Sdfr	    }
622178825Sdfr	}
623178825Sdfr	if(min_args != -1 || max_args != -1) {
624178825Sdfr	    if(min_args == max_args) {
625233294Sstas		cprint(1, "if(argc - optidx != %d) {\n",
626178825Sdfr		       min_args);
627178825Sdfr		cprint(2, "fprintf(stderr, \"Need exactly %u parameters (%%u given).\\n\\n\", argc - optidx);\n", min_args);
628178825Sdfr		cprint(2, "goto usage;\n");
629178825Sdfr		cprint(1, "}\n");
630178825Sdfr	    } else {
631178825Sdfr		if(max_args != -1) {
632178825Sdfr		    cprint(1, "if(argc - optidx > %d) {\n", max_args);
633178825Sdfr		    cprint(2, "fprintf(stderr, \"Arguments given (%%u) are more than expected (%u).\\n\\n\", argc - optidx);\n", max_args);
634178825Sdfr		    cprint(2, "goto usage;\n");
635178825Sdfr		    cprint(1, "}\n");
636178825Sdfr		}
637178825Sdfr		if(min_args != -1) {
638178825Sdfr		    cprint(1, "if(argc - optidx < %d) {\n", min_args);
639178825Sdfr		    cprint(2, "fprintf(stderr, \"Arguments given (%%u) are less than expected (%u).\\n\\n\", argc - optidx);\n", min_args);
640178825Sdfr		    cprint(2, "goto usage;\n");
641178825Sdfr		    cprint(1, "}\n");
642178825Sdfr		}
643178825Sdfr	    }
644178825Sdfr	}
645178825Sdfr    }
646233294Sstas
647178825Sdfr    cprint(1, "if(help_flag)\n");
648178825Sdfr    cprint(2, "goto usage;\n");
649178825Sdfr
650233294Sstas    cprint(1, "ret = %s(%s, argc - optidx, argv + optidx);\n",
651178825Sdfr	   f, opt1 ? "&opt": "NULL");
652233294Sstas
653178825Sdfr    /* free allocated data */
654233294Sstas    for(tmp = find(as, "option");
655233294Sstas	tmp != NULL;
656178825Sdfr	tmp = find_next(tmp, "option")) {
657178825Sdfr	char *s;
658178825Sdfr	struct assignment *type = find(tmp->u.assignment, "type");
659178825Sdfr	struct type_handler *th;
660178825Sdfr	th = find_handler(type);
661178825Sdfr	if(th->free == NULL)
662178825Sdfr	    continue;
663178825Sdfr	s = make_name(tmp->u.assignment);
664178825Sdfr	(*th->free)(s);
665178825Sdfr	free(s);
666178825Sdfr    }
667178825Sdfr    cprint(1, "return ret;\n");
668178825Sdfr
669178825Sdfr    cprint(0, "usage:\n");
670233294Sstas    cprint(1, "arg_printusage (args, %d, \"%s\", \"%s\");\n", nargs,
671178825Sdfr	   name->u.value, arg ? arg->u.value : "");
672178825Sdfr    /* free allocated data */
673233294Sstas    for(tmp = find(as, "option");
674233294Sstas	tmp != NULL;
675178825Sdfr	tmp = find_next(tmp, "option")) {
676178825Sdfr	char *s;
677178825Sdfr	struct assignment *type = find(tmp->u.assignment, "type");
678178825Sdfr	struct type_handler *th;
679178825Sdfr	th = find_handler(type);
680178825Sdfr	if(th->free == NULL)
681178825Sdfr	    continue;
682178825Sdfr	s = make_name(tmp->u.assignment);
683178825Sdfr	(*th->free)(s);
684178825Sdfr	free(s);
685178825Sdfr    }
686178825Sdfr    cprint(1, "return 0;\n");
687178825Sdfr    cprint(0, "}\n");
688178825Sdfr    cprint(0, "\n");
689178825Sdfr}
690178825Sdfr
691178825Sdfrchar cname[PATH_MAX];
692178825Sdfrchar hname[PATH_MAX];
693178825Sdfr
694178825Sdfrstatic void
695178825Sdfrgen(struct assignment *as)
696178825Sdfr{
697178825Sdfr    struct assignment *a;
698178825Sdfr    cprint(0, "#include <stdio.h>\n");
699178825Sdfr    cprint(0, "#include <getarg.h>\n");
700178825Sdfr    cprint(0, "#include <sl.h>\n");
701178825Sdfr    cprint(0, "#include \"%s\"\n\n", hname);
702178825Sdfr
703178825Sdfr    hprint(0, "#include <stdio.h>\n");
704178825Sdfr    hprint(0, "#include <sl.h>\n");
705178825Sdfr    hprint(0, "\n");
706178825Sdfr
707178825Sdfr
708178825Sdfr    for(a = as; a != NULL; a = a->next)
709178825Sdfr	gen_wrapper(a->u.assignment);
710178825Sdfr
711178825Sdfr    cprint(0, "SL_cmd commands[] = {\n");
712178825Sdfr    for(a = as; a != NULL; a = a->next)
713178825Sdfr	gen_command(a->u.assignment);
714178825Sdfr    cprint(1, "{ NULL }\n");
715178825Sdfr    cprint(0, "};\n");
716178825Sdfr
717178825Sdfr    hprint(0, "extern SL_cmd commands[];\n");
718178825Sdfr}
719178825Sdfr
720178825Sdfrint version_flag;
721178825Sdfrint help_flag;
722178825Sdfrstruct getargs args[] = {
723178825Sdfr    { "version", 0, arg_flag, &version_flag },
724178825Sdfr    { "help", 0, arg_flag, &help_flag }
725178825Sdfr};
726178825Sdfrint num_args = sizeof(args) / sizeof(args[0]);
727178825Sdfr
728178825Sdfrstatic void
729178825Sdfrusage(int code)
730178825Sdfr{
731178825Sdfr    arg_printusage(args, num_args, NULL, "command-table");
732178825Sdfr    exit(code);
733178825Sdfr}
734178825Sdfr
735178825Sdfrint
736178825Sdfrmain(int argc, char **argv)
737178825Sdfr{
738178825Sdfr    char *p;
739178825Sdfr
740178825Sdfr    int optidx = 0;
741178825Sdfr
742178825Sdfr    setprogname(argv[0]);
743178825Sdfr    if(getarg(args, num_args, argc, argv, &optidx))
744178825Sdfr	usage(1);
745178825Sdfr    if(help_flag)
746178825Sdfr	usage(0);
747178825Sdfr    if(version_flag) {
748178825Sdfr	print_version(NULL);
749178825Sdfr	exit(0);
750178825Sdfr    }
751233294Sstas
752178825Sdfr    if(argc == optidx)
753178825Sdfr	usage(1);
754178825Sdfr
755178825Sdfr    filename = argv[optidx];
756178825Sdfr    yyin = fopen(filename, "r");
757178825Sdfr    if(yyin == NULL)
758178825Sdfr	err(1, "%s", filename);
759178825Sdfr    p = strrchr(filename, '/');
760178825Sdfr    if(p)
761178825Sdfr	strlcpy(cname, p + 1, sizeof(cname));
762178825Sdfr    else
763178825Sdfr	strlcpy(cname, filename, sizeof(cname));
764178825Sdfr    p = strrchr(cname, '.');
765178825Sdfr    if(p)
766178825Sdfr	*p = '\0';
767178825Sdfr    strlcpy(hname, cname, sizeof(hname));
768178825Sdfr    strlcat(cname, ".c", sizeof(cname));
769178825Sdfr    strlcat(hname, ".h", sizeof(hname));
770178825Sdfr    yyparse();
771178825Sdfr    if(error_flag)
772178825Sdfr	exit(1);
773178825Sdfr    if(check(assignment) == 0) {
774178825Sdfr	cfile = fopen(cname, "w");
775178825Sdfr	if(cfile == NULL)
776178825Sdfr	  err(1, "%s", cname);
777178825Sdfr	hfile = fopen(hname, "w");
778178825Sdfr	if(hfile == NULL)
779178825Sdfr	  err(1, "%s", hname);
780178825Sdfr	gen(assignment);
781178825Sdfr	fclose(cfile);
782178825Sdfr	fclose(hfile);
783178825Sdfr    }
784178825Sdfr    fclose(yyin);
785178825Sdfr    return 0;
786178825Sdfr}
787