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