Home | History | Annotate | Line # | Download | only in sl
slc-gram.y revision 1.1
      1 /*	$NetBSD: slc-gram.y,v 1.1 2011/04/13 18:15:44 elric 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 = \"%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 
    498     name = find(as, "name");
    499     n = strdup(name->u.value);
    500     gen_name(n);
    501     arg = find(as, "argument");
    502     opt1 = find(as, "option");
    503     function = find(as, "function");
    504     if(function)
    505 	f = function->u.value;
    506     else
    507 	f = n;
    508 
    509 
    510     if(opt1 != NULL) {
    511 	gen_options(opt1, n);
    512 	hprint(0, "int %s(struct %s_options*, int, char **);\n", f, n);
    513     } else {
    514 	hprint(0, "int %s(void*, int, char **);\n", f);
    515     }
    516 
    517     fprintf(cfile, "static int\n");
    518     fprintf(cfile, "%s_wrap(int argc, char **argv)\n", n);
    519     fprintf(cfile, "{\n");
    520     if(opt1 != NULL)
    521 	cprint(1, "struct %s_options opt;\n", n);
    522     cprint(1, "int ret;\n");
    523     cprint(1, "int optidx = 0;\n");
    524     cprint(1, "struct getargs args[] = {\n");
    525     for(tmp = find(as, "option");
    526 	tmp != NULL;
    527 	tmp = find_next(tmp, "option")) {
    528 	struct assignment *type = find(tmp->u.assignment, "type");
    529 	struct assignment *lopt = find(tmp->u.assignment, "long");
    530 	struct assignment *sopt = find(tmp->u.assignment, "short");
    531 	struct assignment *aarg = find(tmp->u.assignment, "argument");
    532 	struct assignment *help = find(tmp->u.assignment, "help");
    533 
    534 	struct type_handler *th;
    535 
    536 	cprint(2, "{ ");
    537 	if(lopt)
    538 	    fprintf(cfile, "\"%s\", ", lopt->u.value);
    539 	else
    540 	    fprintf(cfile, "NULL, ");
    541 	if(sopt)
    542 	    fprintf(cfile, "'%c', ", *sopt->u.value);
    543 	else
    544 	    fprintf(cfile, "0, ");
    545 	th = find_handler(type);
    546 	fprintf(cfile, "%s, ", th->getarg_type);
    547 	fprintf(cfile, "NULL, ");
    548 	if(help)
    549 	    fprintf(cfile, "\"%s\", ", help->u.value);
    550 	else
    551 	    fprintf(cfile, "NULL, ");
    552 	if(aarg)
    553 	    fprintf(cfile, "\"%s\"", aarg->u.value);
    554 	else
    555 	    fprintf(cfile, "NULL");
    556 	fprintf(cfile, " },\n");
    557     }
    558     cprint(2, "{ \"help\", 'h', arg_flag, NULL, NULL, NULL }\n");
    559     cprint(1, "};\n");
    560     cprint(1, "int help_flag = 0;\n");
    561 
    562     for(tmp = find(as, "option");
    563 	tmp != NULL;
    564 	tmp = find_next(tmp, "option")) {
    565 	char *s;
    566 	struct assignment *type = find(tmp->u.assignment, "type");
    567 
    568 	struct assignment *defval = find(tmp->u.assignment, "default");
    569 
    570 	struct type_handler *th;
    571 
    572 	s = make_name(tmp->u.assignment);
    573 	th = find_handler(type);
    574 	(*th->defval)(s, defval);
    575 	free(s);
    576     }
    577 
    578     for(tmp = find(as, "option");
    579 	tmp != NULL;
    580 	tmp = find_next(tmp, "option")) {
    581 	char *s;
    582 	s = make_name(tmp->u.assignment);
    583 	cprint(1, "args[%d].value = &opt.%s;\n", nargs++, s);
    584 	free(s);
    585     }
    586     cprint(1, "args[%d].value = &help_flag;\n", nargs++);
    587     cprint(1, "if(getarg(args, %d, argc, argv, &optidx))\n", nargs);
    588     cprint(2, "goto usage;\n");
    589 
    590     {
    591 	int min_args = -1;
    592 	int max_args = -1;
    593 	char *end;
    594 	if(arg == NULL) {
    595 	    max_args = 0;
    596 	} else {
    597 	    if((tmp = find(as, "min_args")) != NULL) {
    598 		min_args = strtol(tmp->u.value, &end, 0);
    599 		if(*end != '\0') {
    600 		    ex(tmp, "min_args is not numeric");
    601 		    exit(1);
    602 		}
    603 		if(min_args < 0) {
    604 		    ex(tmp, "min_args must be non-negative");
    605 		    exit(1);
    606 		}
    607 	    }
    608 	    if((tmp = find(as, "max_args")) != NULL) {
    609 		max_args = strtol(tmp->u.value, &end, 0);
    610 		if(*end != '\0') {
    611 		    ex(tmp, "max_args is not numeric");
    612 		    exit(1);
    613 		}
    614 		if(max_args < 0) {
    615 		    ex(tmp, "max_args must be non-negative");
    616 		    exit(1);
    617 		}
    618 	    }
    619 	}
    620 	if(min_args != -1 || max_args != -1) {
    621 	    if(min_args == max_args) {
    622 		cprint(1, "if(argc - optidx != %d) {\n",
    623 		       min_args);
    624 		cprint(2, "fprintf(stderr, \"Need exactly %u parameters (%%u given).\\n\\n\", argc - optidx);\n", min_args);
    625 		cprint(2, "goto usage;\n");
    626 		cprint(1, "}\n");
    627 	    } else {
    628 		if(max_args != -1) {
    629 		    cprint(1, "if(argc - optidx > %d) {\n", max_args);
    630 		    cprint(2, "fprintf(stderr, \"Arguments given (%%u) are more than expected (%u).\\n\\n\", argc - optidx);\n", max_args);
    631 		    cprint(2, "goto usage;\n");
    632 		    cprint(1, "}\n");
    633 		}
    634 		if(min_args != -1) {
    635 		    cprint(1, "if(argc - optidx < %d) {\n", min_args);
    636 		    cprint(2, "fprintf(stderr, \"Arguments given (%%u) are less than expected (%u).\\n\\n\", argc - optidx);\n", min_args);
    637 		    cprint(2, "goto usage;\n");
    638 		    cprint(1, "}\n");
    639 		}
    640 	    }
    641 	}
    642     }
    643 
    644     cprint(1, "if(help_flag)\n");
    645     cprint(2, "goto usage;\n");
    646 
    647     cprint(1, "ret = %s(%s, argc - optidx, argv + optidx);\n",
    648 	   f, opt1 ? "&opt": "NULL");
    649 
    650     /* free allocated data */
    651     for(tmp = find(as, "option");
    652 	tmp != NULL;
    653 	tmp = find_next(tmp, "option")) {
    654 	char *s;
    655 	struct assignment *type = find(tmp->u.assignment, "type");
    656 	struct type_handler *th;
    657 	th = find_handler(type);
    658 	if(th->free == NULL)
    659 	    continue;
    660 	s = make_name(tmp->u.assignment);
    661 	(*th->free)(s);
    662 	free(s);
    663     }
    664     cprint(1, "return ret;\n");
    665 
    666     cprint(0, "usage:\n");
    667     cprint(1, "arg_printusage (args, %d, \"%s\", \"%s\");\n", nargs,
    668 	   name->u.value, arg ? arg->u.value : "");
    669     /* free allocated data */
    670     for(tmp = find(as, "option");
    671 	tmp != NULL;
    672 	tmp = find_next(tmp, "option")) {
    673 	char *s;
    674 	struct assignment *type = find(tmp->u.assignment, "type");
    675 	struct type_handler *th;
    676 	th = find_handler(type);
    677 	if(th->free == NULL)
    678 	    continue;
    679 	s = make_name(tmp->u.assignment);
    680 	(*th->free)(s);
    681 	free(s);
    682     }
    683     cprint(1, "return 0;\n");
    684     cprint(0, "}\n");
    685     cprint(0, "\n");
    686 }
    687 
    688 char cname[PATH_MAX];
    689 char hname[PATH_MAX];
    690 
    691 static void
    692 gen(struct assignment *as)
    693 {
    694     struct assignment *a;
    695     cprint(0, "#include <stdio.h>\n");
    696     cprint(0, "#include <krb5/getarg.h>\n");
    697     cprint(0, "#include <krb5/sl.h>\n");
    698     cprint(0, "#include \"%s\"\n\n", hname);
    699 
    700     hprint(0, "#include <stdio.h>\n");
    701     hprint(0, "#include <krb5/sl.h>\n");
    702     hprint(0, "\n");
    703 
    704 
    705     for(a = as; a != NULL; a = a->next)
    706 	gen_wrapper(a->u.assignment);
    707 
    708     cprint(0, "SL_cmd commands[] = {\n");
    709     for(a = as; a != NULL; a = a->next)
    710 	gen_command(a->u.assignment);
    711     cprint(1, "{ NULL }\n");
    712     cprint(0, "};\n");
    713 
    714     hprint(0, "extern SL_cmd commands[];\n");
    715 }
    716 
    717 int version_flag;
    718 int help_flag;
    719 struct getargs args[] = {
    720     { "version", 0, arg_flag, &version_flag },
    721     { "help", 0, arg_flag, &help_flag }
    722 };
    723 int num_args = sizeof(args) / sizeof(args[0]);
    724 
    725 static void
    726 usage(int code)
    727 {
    728     arg_printusage(args, num_args, NULL, "command-table");
    729     exit(code);
    730 }
    731 
    732 int
    733 main(int argc, char **argv)
    734 {
    735     char *p;
    736 
    737     int optidx = 0;
    738 
    739     setprogname(argv[0]);
    740     if(getarg(args, num_args, argc, argv, &optidx))
    741 	usage(1);
    742     if(help_flag)
    743 	usage(0);
    744     if(version_flag) {
    745 	print_version(NULL);
    746 	exit(0);
    747     }
    748 
    749     if(argc == optidx)
    750 	usage(1);
    751 
    752     filename = argv[optidx];
    753     yyin = fopen(filename, "r");
    754     if(yyin == NULL)
    755 	err(1, "%s", filename);
    756     p = strrchr(filename, '/');
    757     if(p)
    758 	strlcpy(cname, p + 1, sizeof(cname));
    759     else
    760 	strlcpy(cname, filename, sizeof(cname));
    761     p = strrchr(cname, '.');
    762     if(p)
    763 	*p = '\0';
    764     strlcpy(hname, cname, sizeof(hname));
    765     strlcat(cname, ".c", sizeof(cname));
    766     strlcat(hname, ".h", sizeof(hname));
    767     yyparse();
    768     if(error_flag)
    769 	exit(1);
    770     if(check(assignment) == 0) {
    771 	cfile = fopen(cname, "w");
    772 	if(cfile == NULL)
    773 	  err(1, "%s", cname);
    774 	hfile = fopen(hname, "w");
    775 	if(hfile == NULL)
    776 	  err(1, "%s", hname);
    777 	gen(assignment);
    778 	fclose(cfile);
    779 	fclose(hfile);
    780     }
    781     fclose(yyin);
    782     return 0;
    783 }
    784