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