Home | History | Annotate | Line # | Download | only in sl
slc-gram.y revision 1.1.1.2
      1 /*	$NetBSD: slc-gram.y,v 1.1.1.2 2014/04/24 12:45:53 pettai Exp $	*/
      2 
      3 %{
      4 /*
      5  * Copyright (c) 2004-2006 Kungliga Tekniska Hgskolan
      6  * (Royal Institute of Technology, Stockholm, Sweden).
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  *
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  *
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  *
     20  * 3. Neither the name of the Institute nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #include <config.h>
     38 
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <err.h>
     42 #include <ctype.h>
     43 #include <limits.h>
     44 #include <getarg.h>
     45 #include <vers.h>
     46 #include <roken.h>
     47 
     48 #include "slc.h"
     49 extern FILE *yyin;
     50 extern struct assignment *assignment;
     51 
     52 /* Declarations for Bison:
     53  */
     54 #define YYMALLOC        malloc
     55 #define YYFREE          free
     56 
     57 %}
     58 
     59 %union {
     60 	char *string;
     61 	struct assignment *assignment;
     62 }
     63 
     64 %token <string> LITERAL
     65 %token <string> STRING
     66 %type <assignment> assignment assignments
     67 
     68 %start start
     69 
     70 %%
     71 
     72 start		: assignments
     73 		{
     74 			assignment = $1;
     75 		}
     76 		;
     77 
     78 assignments	: assignment assignments
     79 		{
     80 			$1->next = $2;
     81 			$$ = $1;
     82 		}
     83 		| assignment
     84 		;
     85 
     86 assignment	: LITERAL '=' STRING
     87 		{
     88 			$$ = malloc(sizeof(*$$));
     89 			$$->name = $1;
     90 			$$->type = a_value;
     91 			$$->lineno = lineno;
     92 			$$->u.value = $3;
     93 			$$->next = NULL;
     94 		}
     95 		| LITERAL '=' '{' assignments '}'
     96 		{
     97 			$$ = malloc(sizeof(*$$));
     98 			$$->name = $1;
     99 			$$->type = a_assignment;
    100 			$$->lineno = lineno;
    101 			$$->u.assignment = $4;
    102 			$$->next = NULL;
    103 		}
    104 		;
    105 
    106 %%
    107 char *filename;
    108 FILE *cfile, *hfile;
    109 int error_flag;
    110 struct assignment *assignment;
    111 
    112 
    113 static void
    114 ex(struct assignment *a, const char *fmt, ...)
    115 {
    116     va_list ap;
    117     fprintf(stderr, "%s:%d: ", a->name, a->lineno);
    118     va_start(ap, fmt);
    119     vfprintf(stderr, fmt, ap);
    120     va_end(ap);
    121     fprintf(stderr, "\n");
    122 }
    123 
    124 
    125 
    126 static int
    127 check_option(struct assignment *as)
    128 {
    129     struct assignment *a;
    130     int seen_long = 0;
    131     int seen_name = 0;
    132     int seen_short = 0;
    133     int seen_type = 0;
    134     int seen_argument = 0;
    135     int seen_help = 0;
    136     int seen_default = 0;
    137     int ret = 0;
    138 
    139     for(a = as; a != NULL; a = a->next) {
    140 	if(strcmp(a->name, "long") == 0)
    141 	    seen_long++;
    142 	else if(strcmp(a->name, "short") == 0)
    143 	    seen_short++;
    144 	else if(strcmp(a->name, "name") == 0)
    145 	    seen_name++;
    146 	else if(strcmp(a->name, "type") == 0)
    147 	    seen_type++;
    148 	else if(strcmp(a->name, "argument") == 0)
    149 	    seen_argument++;
    150 	else if(strcmp(a->name, "help") == 0)
    151 	    seen_help++;
    152 	else if(strcmp(a->name, "default") == 0)
    153 	    seen_default++;
    154 	else {
    155 	    ex(a, "unknown name %s", a->name);
    156 	    ret++;
    157 	}
    158     }
    159     if(seen_long == 0 && seen_short == 0) {
    160 	ex(as, "neither long nor short option");
    161 	ret++;
    162     }
    163     if (seen_long == 0 && seen_name == 0) {
    164 	ex(as, "either of long or name option must be used");
    165 	ret++;
    166     }
    167     if(seen_long > 1) {
    168 	ex(as, "multiple long options");
    169 	ret++;
    170     }
    171     if(seen_short > 1) {
    172 	ex(as, "multiple short options");
    173 	ret++;
    174     }
    175     if(seen_type > 1) {
    176 	ex(as, "multiple types");
    177 	ret++;
    178     }
    179     if(seen_argument > 1) {
    180 	ex(as, "multiple arguments");
    181 	ret++;
    182     }
    183     if(seen_help > 1) {
    184 	ex(as, "multiple help strings");
    185 	ret++;
    186     }
    187     if(seen_default > 1) {
    188 	ex(as, "multiple default values");
    189 	ret++;
    190     }
    191     return ret;
    192 }
    193 
    194 static int
    195 check_command(struct assignment *as)
    196 {
    197 	struct assignment *a;
    198 	int seen_name = 0;
    199 	int seen_function = 0;
    200 	int seen_help = 0;
    201 	int seen_argument = 0;
    202 	int seen_minargs = 0;
    203 	int seen_maxargs = 0;
    204 	int ret = 0;
    205 	for(a = as; a != NULL; a = a->next) {
    206 		if(strcmp(a->name, "name") == 0)
    207 			seen_name++;
    208 		else if(strcmp(a->name, "function") == 0) {
    209 			seen_function++;
    210 		} else if(strcmp(a->name, "option") == 0)
    211 			ret += check_option(a->u.assignment);
    212 		else if(strcmp(a->name, "help") == 0) {
    213 			seen_help++;
    214 		} else if(strcmp(a->name, "argument") == 0) {
    215 			seen_argument++;
    216 		} else if(strcmp(a->name, "min_args") == 0) {
    217 			seen_minargs++;
    218 		} else if(strcmp(a->name, "max_args") == 0) {
    219 			seen_maxargs++;
    220 		} else {
    221 			ex(a, "unknown name: %s", a->name);
    222 			ret++;
    223 		}
    224 	}
    225 	if(seen_name == 0) {
    226 		ex(as, "no command name");
    227 		ret++;
    228 	}
    229 	if(seen_function > 1) {
    230 		ex(as, "multiple function names");
    231 		ret++;
    232 	}
    233 	if(seen_help > 1) {
    234 		ex(as, "multiple help strings");
    235 		ret++;
    236 	}
    237 	if(seen_argument > 1) {
    238 		ex(as, "multiple argument strings");
    239 		ret++;
    240 	}
    241 	if(seen_minargs > 1) {
    242 		ex(as, "multiple min_args strings");
    243 		ret++;
    244 	}
    245 	if(seen_maxargs > 1) {
    246 		ex(as, "multiple max_args strings");
    247 		ret++;
    248 	}
    249 
    250 	return ret;
    251 }
    252 
    253 static int
    254 check(struct assignment *as)
    255 {
    256     struct assignment *a;
    257     int ret = 0;
    258     for(a = as; a != NULL; a = a->next) {
    259 	if(strcmp(a->name, "command")) {
    260 	    fprintf(stderr, "unknown type %s line %d\n", a->name, a->lineno);
    261 	    ret++;
    262 	    continue;
    263 	}
    264 	if(a->type != a_assignment) {
    265 	    fprintf(stderr, "bad command definition %s line %d\n", a->name, a->lineno);
    266 	    ret++;
    267 	    continue;
    268 	}
    269 	ret += check_command(a->u.assignment);
    270     }
    271     return ret;
    272 }
    273 
    274 static struct assignment *
    275 find_next(struct assignment *as, const char *name)
    276 {
    277     for(as = as->next; as != NULL; as = as->next) {
    278 	if(strcmp(as->name, name) == 0)
    279 	    return as;
    280     }
    281     return NULL;
    282 }
    283 
    284 static struct assignment *
    285 find(struct assignment *as, const char *name)
    286 {
    287     for(; as != NULL; as = as->next) {
    288 	if(strcmp(as->name, name) == 0)
    289 	    return as;
    290     }
    291     return NULL;
    292 }
    293 
    294 static void
    295 space(FILE *f, int level)
    296 {
    297     fprintf(f, "%*.*s", level * 4, level * 4, " ");
    298 }
    299 
    300 static void
    301 cprint(int level, const char *fmt, ...)
    302 {
    303     va_list ap;
    304     va_start(ap, fmt);
    305     space(cfile, level);
    306     vfprintf(cfile, fmt, ap);
    307     va_end(ap);
    308 }
    309 
    310 static void
    311 hprint(int level, const char *fmt, ...)
    312 {
    313     va_list ap;
    314     va_start(ap, fmt);
    315     space(hfile, level);
    316     vfprintf(hfile, fmt, ap);
    317     va_end(ap);
    318 }
    319 
    320 static void gen_name(char *str);
    321 
    322 static void
    323 gen_command(struct assignment *as)
    324 {
    325     struct assignment *a, *b;
    326     char *f;
    327     a = find(as, "name");
    328     f = strdup(a->u.value);
    329     gen_name(f);
    330     cprint(1, "    { ");
    331     fprintf(cfile, "\"%s\", ", a->u.value);
    332     fprintf(cfile, "%s_wrap, ", f);
    333     b = find(as, "argument");
    334     if(b)
    335 	fprintf(cfile, "\"%s %s\", ", a->u.value, b->u.value);
    336     else
    337 	fprintf(cfile, "\"%s\", ", a->u.value);
    338     b = find(as, "help");
    339     if(b)
    340 	fprintf(cfile, "\"%s\"", b->u.value);
    341     else
    342 	fprintf(cfile, "NULL");
    343     fprintf(cfile, " },\n");
    344     for(a = a->next; a != NULL; a = a->next)
    345 	if(strcmp(a->name, "name") == 0)
    346 	    cprint(1, "    { \"%s\" },\n", a->u.value);
    347     cprint(0, "\n");
    348 }
    349 
    350 static void
    351 gen_name(char *str)
    352 {
    353     char *p;
    354     for(p = str; *p != '\0'; p++)
    355 	if(!isalnum((unsigned char)*p))
    356 	    *p = '_';
    357 }
    358 
    359 static char *
    360 make_name(struct assignment *as)
    361 {
    362     struct assignment *lopt;
    363     struct assignment *type;
    364     char *s;
    365 
    366     lopt = find(as, "long");
    367     if(lopt == NULL)
    368 	lopt = find(as, "name");
    369     if(lopt == NULL)
    370 	return NULL;
    371 
    372     type = find(as, "type");
    373     if(strcmp(type->u.value, "-flag") == 0)
    374 	asprintf(&s, "%s_flag", lopt->u.value);
    375     else
    376 	asprintf(&s, "%s_%s", lopt->u.value, type->u.value);
    377     gen_name(s);
    378     return s;
    379 }
    380 
    381 
    382 static void defval_int(const char *name, struct assignment *defval)
    383 {
    384     if(defval != NULL)
    385 	cprint(1, "opt.%s = %s;\n", name, defval->u.value);
    386     else
    387 	cprint(1, "opt.%s = 0;\n", name);
    388 }
    389 static void defval_neg_flag(const char *name, struct assignment *defval)
    390 {
    391     if(defval != NULL)
    392 	cprint(1, "opt.%s = %s;\n", name, defval->u.value);
    393     else
    394 	cprint(1, "opt.%s = 1;\n", name);
    395 }
    396 static void defval_string(const char *name, struct assignment *defval)
    397 {
    398     if(defval != NULL)
    399 	cprint(1, "opt.%s = (char *)(unsigned long)\"%s\";\n", name, defval->u.value);
    400     else
    401 	cprint(1, "opt.%s = NULL;\n", name);
    402 }
    403 static void defval_strings(const char *name, struct assignment *defval)
    404 {
    405     cprint(1, "opt.%s.num_strings = 0;\n", name);
    406     cprint(1, "opt.%s.strings = NULL;\n", name);
    407 }
    408 
    409 static void free_strings(const char *name)
    410 {
    411     cprint(1, "free_getarg_strings (&opt.%s);\n", name);
    412 }
    413 
    414 struct type_handler {
    415     const char *typename;
    416     const char *c_type;
    417     const char *getarg_type;
    418     void (*defval)(const char*, struct assignment*);
    419     void (*free)(const char*);
    420 } type_handlers[] = {
    421 	{ "integer",
    422 	  "int",
    423 	  "arg_integer",
    424 	  defval_int,
    425 	  NULL
    426 	},
    427 	{ "string",
    428 	  "char*",
    429 	  "arg_string",
    430 	  defval_string,
    431 	  NULL
    432 	},
    433 	{ "strings",
    434 	  "struct getarg_strings",
    435 	  "arg_strings",
    436 	  defval_strings,
    437 	  free_strings
    438 	},
    439 	{ "flag",
    440 	  "int",
    441 	  "arg_flag",
    442 	  defval_int,
    443 	  NULL
    444 	},
    445 	{ "-flag",
    446 	  "int",
    447 	  "arg_negative_flag",
    448 	  defval_neg_flag,
    449 	  NULL
    450 	},
    451 	{ NULL }
    452 };
    453 
    454 static struct type_handler *find_handler(struct assignment *type)
    455 {
    456     struct type_handler *th;
    457     for(th = type_handlers; th->typename != NULL; th++)
    458 	if(strcmp(type->u.value, th->typename) == 0)
    459 	    return th;
    460     ex(type, "unknown type \"%s\"", type->u.value);
    461     exit(1);
    462 }
    463 
    464 static void
    465 gen_options(struct assignment *opt1, const char *name)
    466 {
    467     struct assignment *tmp;
    468 
    469     hprint(0, "struct %s_options {\n", name);
    470 
    471     for(tmp = opt1;
    472 	tmp != NULL;
    473 	tmp = find_next(tmp, "option")) {
    474 	struct assignment *type;
    475 	struct type_handler *th;
    476 	char *s;
    477 
    478 	s = make_name(tmp->u.assignment);
    479 	type = find(tmp->u.assignment, "type");
    480 	th = find_handler(type);
    481 	hprint(1, "%s %s;\n", th->c_type, s);
    482 	free(s);
    483     }
    484     hprint(0, "};\n");
    485 }
    486 
    487 static void
    488 gen_wrapper(struct assignment *as)
    489 {
    490     struct assignment *name;
    491     struct assignment *arg;
    492     struct assignment *opt1;
    493     struct assignment *function;
    494     struct assignment *tmp;
    495     char *n, *f;
    496     int nargs = 0;
    497     int narguments = 0;
    498 
    499     name = find(as, "name");
    500     n = strdup(name->u.value);
    501     gen_name(n);
    502     arg = find(as, "argument");
    503     if (arg)
    504         narguments++;
    505     opt1 = find(as, "option");
    506     function = find(as, "function");
    507     if(function)
    508 	f = function->u.value;
    509     else
    510 	f = n;
    511 
    512 
    513     if(opt1 != NULL) {
    514 	gen_options(opt1, n);
    515 	hprint(0, "int %s(struct %s_options*, int, char **);\n", f, n);
    516     } else {
    517 	hprint(0, "int %s(void*, int, char **);\n", f);
    518     }
    519 
    520     fprintf(cfile, "static int\n");
    521     fprintf(cfile, "%s_wrap(int argc, char **argv)\n", n);
    522     fprintf(cfile, "{\n");
    523     if(opt1 != NULL)
    524 	cprint(1, "struct %s_options opt;\n", n);
    525     cprint(1, "int ret;\n");
    526     cprint(1, "int optidx = 0;\n");
    527     cprint(1, "struct getargs args[] = {\n");
    528     for(tmp = find(as, "option");
    529 	tmp != NULL;
    530 	tmp = find_next(tmp, "option")) {
    531 	struct assignment *type = find(tmp->u.assignment, "type");
    532 	struct assignment *lopt = find(tmp->u.assignment, "long");
    533 	struct assignment *sopt = find(tmp->u.assignment, "short");
    534 	struct assignment *aarg = find(tmp->u.assignment, "argument");
    535 	struct assignment *help = find(tmp->u.assignment, "help");
    536 
    537 	struct type_handler *th;
    538 
    539 	cprint(2, "{ ");
    540 	if(lopt)
    541 	    fprintf(cfile, "\"%s\", ", lopt->u.value);
    542 	else
    543 	    fprintf(cfile, "NULL, ");
    544 	if(sopt)
    545 	    fprintf(cfile, "'%c', ", *sopt->u.value);
    546 	else
    547 	    fprintf(cfile, "0, ");
    548 	th = find_handler(type);
    549 	fprintf(cfile, "%s, ", th->getarg_type);
    550 	fprintf(cfile, "NULL, ");
    551 	if(help)
    552 	    fprintf(cfile, "\"%s\", ", help->u.value);
    553 	else
    554 	    fprintf(cfile, "NULL, ");
    555 	if(aarg) {
    556 	    fprintf(cfile, "\"%s\"", aarg->u.value);
    557             narguments++;
    558 	} else
    559 	    fprintf(cfile, "NULL");
    560 	fprintf(cfile, " },\n");
    561     }
    562     cprint(2, "{ \"help\", 'h', arg_flag, NULL, NULL, NULL }\n");
    563     cprint(1, "};\n");
    564     cprint(1, "int help_flag = 0;\n");
    565 
    566     for(tmp = find(as, "option");
    567 	tmp != NULL;
    568 	tmp = find_next(tmp, "option")) {
    569 	char *s;
    570 	struct assignment *type = find(tmp->u.assignment, "type");
    571 
    572 	struct assignment *defval = find(tmp->u.assignment, "default");
    573 
    574 	struct type_handler *th;
    575 
    576 	s = make_name(tmp->u.assignment);
    577 	th = find_handler(type);
    578 	(*th->defval)(s, defval);
    579 	free(s);
    580     }
    581 
    582     for(tmp = find(as, "option");
    583 	tmp != NULL;
    584 	tmp = find_next(tmp, "option")) {
    585 	char *s;
    586 	s = make_name(tmp->u.assignment);
    587 	cprint(1, "args[%d].value = &opt.%s;\n", nargs++, s);
    588 	free(s);
    589     }
    590     cprint(1, "args[%d].value = &help_flag;\n", nargs++);
    591     cprint(1, "if(getarg(args, %d, argc, argv, &optidx))\n", nargs);
    592     cprint(2, "goto usage;\n");
    593 
    594     {
    595 	int min_args = -1;
    596 	int max_args = -1;
    597 	char *end;
    598 	if(narguments == 0) {
    599 	    max_args = 0;
    600 	} else {
    601 	    if((tmp = find(as, "min_args")) != NULL) {
    602 		min_args = strtol(tmp->u.value, &end, 0);
    603 		if(*end != '\0') {
    604 		    ex(tmp, "min_args is not numeric");
    605 		    exit(1);
    606 		}
    607 		if(min_args < 0) {
    608 		    ex(tmp, "min_args must be non-negative");
    609 		    exit(1);
    610 		}
    611 	    }
    612 	    if((tmp = find(as, "max_args")) != NULL) {
    613 		max_args = strtol(tmp->u.value, &end, 0);
    614 		if(*end != '\0') {
    615 		    ex(tmp, "max_args is not numeric");
    616 		    exit(1);
    617 		}
    618 		if(max_args < 0) {
    619 		    ex(tmp, "max_args must be non-negative");
    620 		    exit(1);
    621 		}
    622 	    }
    623 	}
    624 	if(min_args != -1 || max_args != -1) {
    625 	    if(min_args == max_args) {
    626 		cprint(1, "if(argc - optidx != %d) {\n",
    627 		       min_args);
    628 		cprint(2, "fprintf(stderr, \"Need exactly %u parameters (%%u given).\\n\\n\", argc - optidx);\n", min_args);
    629 		cprint(2, "goto usage;\n");
    630 		cprint(1, "}\n");
    631 	    } else {
    632 		if(max_args != -1) {
    633 		    cprint(1, "if(argc - optidx > %d) {\n", max_args);
    634 		    cprint(2, "fprintf(stderr, \"Arguments given (%%u) are more than expected (%u).\\n\\n\", argc - optidx);\n", max_args);
    635 		    cprint(2, "goto usage;\n");
    636 		    cprint(1, "}\n");
    637 		}
    638 		if(min_args != -1) {
    639 		    cprint(1, "if(argc - optidx < %d) {\n", min_args);
    640 		    cprint(2, "fprintf(stderr, \"Arguments given (%%u) are less than expected (%u).\\n\\n\", argc - optidx);\n", min_args);
    641 		    cprint(2, "goto usage;\n");
    642 		    cprint(1, "}\n");
    643 		}
    644 	    }
    645 	}
    646     }
    647 
    648     cprint(1, "if(help_flag)\n");
    649     cprint(2, "goto usage;\n");
    650 
    651     cprint(1, "ret = %s(%s, argc - optidx, argv + optidx);\n",
    652 	   f, opt1 ? "&opt": "NULL");
    653 
    654     /* free allocated data */
    655     for(tmp = find(as, "option");
    656 	tmp != NULL;
    657 	tmp = find_next(tmp, "option")) {
    658 	char *s;
    659 	struct assignment *type = find(tmp->u.assignment, "type");
    660 	struct type_handler *th;
    661 	th = find_handler(type);
    662 	if(th->free == NULL)
    663 	    continue;
    664 	s = make_name(tmp->u.assignment);
    665 	(*th->free)(s);
    666 	free(s);
    667     }
    668     cprint(1, "return ret;\n");
    669 
    670     cprint(0, "usage:\n");
    671     cprint(1, "arg_printusage (args, %d, \"%s\", \"%s\");\n", nargs,
    672 	   name->u.value, arg ? arg->u.value : "");
    673     /* free allocated data */
    674     for(tmp = find(as, "option");
    675 	tmp != NULL;
    676 	tmp = find_next(tmp, "option")) {
    677 	char *s;
    678 	struct assignment *type = find(tmp->u.assignment, "type");
    679 	struct type_handler *th;
    680 	th = find_handler(type);
    681 	if(th->free == NULL)
    682 	    continue;
    683 	s = make_name(tmp->u.assignment);
    684 	(*th->free)(s);
    685 	free(s);
    686     }
    687     cprint(1, "return 0;\n");
    688     cprint(0, "}\n");
    689     cprint(0, "\n");
    690 }
    691 
    692 char cname[PATH_MAX];
    693 char hname[PATH_MAX];
    694 
    695 static void
    696 gen(struct assignment *as)
    697 {
    698     struct assignment *a;
    699     cprint(0, "#include <stdio.h>\n");
    700     cprint(0, "#include <krb5/getarg.h>\n");
    701     cprint(0, "#include <krb5/sl.h>\n");
    702     cprint(0, "#include \"%s\"\n\n", hname);
    703 
    704     hprint(0, "#include <stdio.h>\n");
    705     hprint(0, "#include <krb5/sl.h>\n");
    706     hprint(0, "\n");
    707 
    708 
    709     for(a = as; a != NULL; a = a->next)
    710 	gen_wrapper(a->u.assignment);
    711 
    712     cprint(0, "SL_cmd commands[] = {\n");
    713     for(a = as; a != NULL; a = a->next)
    714 	gen_command(a->u.assignment);
    715     cprint(1, "{ NULL }\n");
    716     cprint(0, "};\n");
    717 
    718     hprint(0, "extern SL_cmd commands[];\n");
    719 }
    720 
    721 int version_flag;
    722 int help_flag;
    723 struct getargs args[] = {
    724     { "version", 0, arg_flag, &version_flag },
    725     { "help", 0, arg_flag, &help_flag }
    726 };
    727 int num_args = sizeof(args) / sizeof(args[0]);
    728 
    729 static void
    730 usage(int code)
    731 {
    732     arg_printusage(args, num_args, NULL, "command-table");
    733     exit(code);
    734 }
    735 
    736 int
    737 main(int argc, char **argv)
    738 {
    739     char *p;
    740 
    741     int optidx = 0;
    742 
    743     setprogname(argv[0]);
    744     if(getarg(args, num_args, argc, argv, &optidx))
    745 	usage(1);
    746     if(help_flag)
    747 	usage(0);
    748     if(version_flag) {
    749 	print_version(NULL);
    750 	exit(0);
    751     }
    752 
    753     if(argc == optidx)
    754 	usage(1);
    755 
    756     filename = argv[optidx];
    757     yyin = fopen(filename, "r");
    758     if(yyin == NULL)
    759 	err(1, "%s", filename);
    760     p = strrchr(filename, '/');
    761     if(p)
    762 	strlcpy(cname, p + 1, sizeof(cname));
    763     else
    764 	strlcpy(cname, filename, sizeof(cname));
    765     p = strrchr(cname, '.');
    766     if(p)
    767 	*p = '\0';
    768     strlcpy(hname, cname, sizeof(hname));
    769     strlcat(cname, ".c", sizeof(cname));
    770     strlcat(hname, ".h", sizeof(hname));
    771     yyparse();
    772     if(error_flag)
    773 	exit(1);
    774     if(check(assignment) == 0) {
    775 	cfile = fopen(cname, "w");
    776 	if(cfile == NULL)
    777 	  err(1, "%s", cname);
    778 	hfile = fopen(hname, "w");
    779 	if(hfile == NULL)
    780 	  err(1, "%s", hname);
    781 	gen(assignment);
    782 	fclose(cfile);
    783 	fclose(hfile);
    784     }
    785     fclose(yyin);
    786     return 0;
    787 }
    788