added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / tools / genmodule / config.c
blob82029db5388334b0be36d4872a25e76421f5a708
1 /*
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
3 $Id$
5 Code to parse the command line options and the module config file for
6 the genmodule program
7 */
9 #include <string.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <time.h>
13 #include <unistd.h>
15 #include "functionhead.h"
16 #include "config.h"
18 static char banner[256] = "\0";
21 const char*
22 getBanner(struct config* config)
24 if (banner[0] == '\0')
26 snprintf (banner, 255,
27 "/*\n"
28 " *** Automatically generated from '%s'. Edits will be lost. ***\n"
29 " Copyright © 1995-2008, The AROS Development Team. All rights reserved.\n"
30 "*/\n", config->conffile
34 return(banner);
37 const static char usage[] =
38 "\n"
39 "Usage: genmodule [-c conffile] [-s suffix] [-d gendir] [-r reffile]\n"
40 " {writefiles|writemakefile|writeincludes|writedummy|writelibdefs|writefunclist} modname modtype\n"
43 static void readconfig(struct config *);
44 static struct classinfo *newclass(struct config *);
46 /* the method prefices for the supported classes */
47 static const char *muimprefix[] =
49 "__OM_",
50 "__MUIM_",
51 NULL
53 static const char *gadgetmprefix[] =
55 "__OM_",
56 "__GM_",
57 "__AROSM_",
58 NULL
60 static const char *dtmprefix[] =
62 "__OM_",
63 "__GM_",
64 "__DTM_",
65 "__PDTM_",
66 NULL
69 /* Create a config struct. Initialize with the values from the programs command
70 * line arguments and the contents of the modules .conf file
72 struct config *initconfig(int argc, char **argv)
74 struct config *cfg;
75 char *s, **argvit = argv + 1;
76 int hassuffix = 0, c;
78 cfg = malloc(sizeof(struct config));
79 if (cfg == NULL)
81 fprintf(stderr, "Out of memory\n");
82 exit(20);
85 memset(cfg, 0, sizeof(struct config));
87 while ((c = getopt(argc, argv, ":c:s:d:r:")) != -1)
90 if (c == ':' || *optarg == '-')
92 fprintf(stderr, "Option -%c needs an argument\n",c);
93 exit(20);
96 switch (c)
98 case 'c':
99 cfg->conffile = optarg;
100 break;
101 case 's':
102 cfg->suffix = optarg;
103 hassuffix = 1;
104 break;
105 case 'd':
106 /* Remove / at end if present */
107 if ((optarg)[strlen(*argvit)-1]=='/') (optarg)[strlen(optarg)-1]='\0';
108 cfg->gendir = optarg;
109 break;
110 case 'r':
111 cfg->reffile = optarg;
112 break;
113 default:
114 fprintf(stderr, "Internal error: Unhandled option\n");
115 exit(20);
119 if (optind + 3 != argc)
121 fprintf(stderr, "Wrong number of arguments.\n%s", usage);
122 exit(20);
125 if (strcmp(argv[optind], "writefiles") == 0)
127 cfg->command = FILES;
129 else if (strcmp(argv[optind], "writemakefile") == 0)
131 cfg->command = MAKEFILE;
133 else if (strcmp(argv[optind], "writeincludes") == 0)
135 cfg->command = INCLUDES;
137 else if (strcmp(argv[optind], "writelibdefs") == 0)
139 cfg->command = LIBDEFS;
141 else if (strcmp(argv[optind], "writedummy") == 0)
143 cfg->command = DUMMY;
145 else if (strcmp(argv[optind], "writefunclist") == 0)
147 cfg->command = WRITEFUNCLIST;
149 else
151 fprintf(stderr, "Unrecognized argument \"%s\"\n%s", argv[optind], usage);
152 exit(20);
155 cfg->modulename = argv[optind+1];
156 cfg->modulenameupper = strdup(cfg->modulename);
157 for (s=cfg->modulenameupper; *s!='\0'; *s = toupper(*s), s++)
160 if (strcmp(argv[optind+2],"library")==0)
162 cfg->modtype = LIBRARY;
163 cfg->intcfg |= CFG_GENLINKLIB;
164 cfg->moddir = "Libs";
166 else if (strcmp(argv[optind+2],"mcc")==0)
168 cfg->modtype = MCC;
169 cfg->moddir = "Classes/Zune";
171 else if (strcmp(argv[optind+2],"mui")==0)
173 cfg->modtype = MUI;
174 cfg->moddir = "Classes/Zune";
176 else if (strcmp(argv[optind+2],"mcp")==0)
178 cfg->modtype = MCP;
179 cfg->moddir = "Classes/Zune";
181 else if (strcmp(argv[optind+2], "device")==0)
183 cfg->modtype = DEVICE;
184 cfg->intcfg |= CFG_GENLINKLIB;
185 cfg->moddir = "Devs";
187 else if (strcmp(argv[optind+2], "resource")==0)
189 cfg->modtype = RESOURCE;
190 cfg->intcfg |= CFG_GENLINKLIB;
191 cfg->moddir = "Devs";
193 else if (strcmp(argv[optind+2], "gadget")==0)
195 cfg->modtype = GADGET;
196 cfg->moddir = "Classes/Gadgets";
198 else if (strcmp(argv[optind+2], "datatype")==0)
200 cfg->modtype = DATATYPE;
201 cfg->moddir = "Classes/Datatypes";
203 else if (strcmp(argv[optind+2], "hidd")==0)
205 cfg->modtype = HIDD;
206 cfg->moddir = "Devs/Drivers";
208 else
210 fprintf(stderr, "Unknown modtype \"%s\" specified for second argument\n", argv[2]);
211 exit(20);
214 if (!hassuffix)
215 cfg->suffix = argv[optind+2];
219 /* Fill fields with default value if not specified on the command line */
221 char tmpbuf[256];
223 if (cfg->conffile == NULL)
225 snprintf(tmpbuf, sizeof(tmpbuf), "%s.conf", cfg->modulename);
226 cfg->conffile = strdup(tmpbuf);
229 if (cfg->gendir == NULL)
230 cfg->gendir = ".";
232 if (cfg->command != FILES && cfg->command != INCLUDES && cfg->command != WRITEFUNCLIST)
234 if (cfg->reffile != NULL)
235 fprintf(stderr, "WARNING ! Option -r ingored for %s\n", argv[optind]);
237 else if (cfg->command == FILES && cfg->reffile == NULL)
239 snprintf(tmpbuf, sizeof(tmpbuf), "%s.ref", cfg->modulename);
240 cfg->reffile = strdup(tmpbuf);
244 readconfig(cfg);
246 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
247 * if they are provided
249 if (cfg->beginiofunc != NULL)
251 struct functionhead *funchead;
253 cfg->intcfg |= CFG_NOREADREF;
255 /* Add beginio_func to the list of functions */
256 funchead = newfunctionhead(cfg->beginiofunc, REGISTERMACRO);
257 funchead->type = strdup("void");
258 funchead->lvo = 5;
259 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
261 funchead->next = cfg->funclist;
262 cfg->funclist = funchead;
264 /* Add abortio_func to the list of functions */
265 funchead = newfunctionhead(cfg->abortiofunc, REGISTERMACRO);
266 funchead->type = strdup("LONG");
267 funchead->lvo = 6;
268 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
270 funchead->next = cfg->funclist->next;
271 cfg->funclist->next = funchead;
273 else if (cfg->modtype == DEVICE && cfg->intcfg & CFG_NOREADREF)
275 fprintf
277 stderr,
278 "beginio_func and abortio_func missing for a device with a non empty function list\n"
280 exit(20);
283 return cfg;
286 /* Functions to read configuration from the configuration file */
288 #include "fileread.h"
290 static char *readsections(struct config *, struct classinfo *, int);
291 static void readsectionconfig(struct config *, struct classinfo *, int);
292 static void readsectioncdef(struct config *);
293 static void readsectioncdefprivate(struct config *);
294 static void readsectionfunctionlist(struct config *);
295 static void readsectionmethodlist(struct classinfo *);
296 static void readsectionclass(struct config *);
298 static void readconfig(struct config *cfg)
300 struct classinfo *mainclass = NULL;
302 /* Create a classinfo structure if this module is a class */
303 switch (cfg->modtype)
305 case LIBRARY:
306 case DEVICE:
307 case RESOURCE:
308 break;
310 case MCC:
311 case MUI:
312 case MCP:
313 case GADGET:
314 case DATATYPE:
315 case HIDD:
316 mainclass = newclass(cfg);
317 mainclass->classtype = cfg->modtype;
318 break;
320 default:
321 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
322 exit(20);
325 switch (cfg->modtype)
327 case LIBRARY:
328 cfg->firstlvo = 5;
329 break;
330 case DEVICE:
331 cfg->firstlvo = 7;
332 break;
333 case MCC:
334 case MUI:
335 case MCP:
336 cfg->firstlvo = 6;
337 mainclass->boopsimprefix = muimprefix;
338 break;
339 case RESOURCE:
340 cfg->firstlvo = 1;
341 break;
342 case GADGET:
343 cfg->firstlvo = 5;
344 mainclass->boopsimprefix = gadgetmprefix;
345 break;
346 case DATATYPE:
347 cfg->firstlvo = 6;
348 mainclass->boopsimprefix = dtmprefix;
349 break;
350 case HIDD:
351 cfg->firstlvo = 5;
352 /* FIXME: need boopsimprefix ? */
353 break;
354 default:
355 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
356 exit(20);
359 if (!fileopen(cfg->conffile))
361 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
362 exit(20);
365 /* Read all sections and see that we are at the end of the file */
366 if (readsections(cfg, mainclass, 0) != NULL)
367 exitfileerror(20, "Syntax error");
369 fileclose();
372 /* readsections will scan through all the sections in the config file.
373 * arguments:
374 * struct config *cfg: The module config data which may be updated by
375 * the information in the sections
376 * struct classinfo *cl: The classdata to be filled with data from the sections.
377 * This may be NULL if this is the main part of the configuration file and the
378 * type of the module is not a class
379 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
380 * part of the config file.
382 static char *readsections(struct config *cfg, struct classinfo *cl, int inclass)
384 char *line, *s, *s2;
386 while ((line=readline())!=NULL)
388 if (strncmp(line, "##", 2)==0)
390 static char *parts[] =
392 "config", "cdefprivate", "cdef", "functionlist", "methodlist", "class"
394 const unsigned int nums = sizeof(parts)/sizeof(char *);
395 unsigned int partnum;
396 int i, atend = 0;
398 s = line+2;
399 while (isspace(*s)) s++;
401 if (strncmp(s, "begin", 5)!=0)
402 return line;
404 s += 5;
405 if (!isspace(*s))
406 exitfileerror(20, "space after begin expected\n");
407 while (isspace(*s)) s++;
409 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
411 if (strncmp(s, parts[i], strlen(parts[i]))==0)
413 partnum = i+1;
414 s += strlen(parts[i]);
415 while (isspace(*s)) s++;
416 if (*s!='\0')
417 exitfileerror(20, "unexpected character on position %d\n", s-line);
420 if (partnum==0)
421 exitfileerror(20, "unknown start of section\n");
422 switch (partnum)
424 case 1: /* config */
425 readsectionconfig(cfg, cl, inclass);
426 break;
428 case 2: /* cdefprivate */
429 if (inclass)
430 exitfileerror(20, "cdefprivate section not allowed in class section\n");
431 readsectioncdefprivate(cfg);
432 break;
434 case 3: /* cdef */
435 if (inclass)
436 exitfileerror(20, "cdef section not allowed in class section\n");
437 readsectioncdef(cfg);
438 break;
440 case 4: /* functionlist */
441 if (inclass)
442 exitfileerror(20, "functionlist section not allow in class section\n");
443 readsectionfunctionlist(cfg);
444 cfg->intcfg |= CFG_NOREADREF;
445 break;
447 case 5: /* methodlist */
448 if (cl == NULL)
449 exitfileerror(20, "methodlist section when not in a class\n");
450 readsectionmethodlist(cl);
451 cfg->intcfg |= CFG_NOREADREF;
452 break;
454 case 6: /* class */
455 if (inclass)
456 exitfileerror(20, "class section may not be nested\n");
457 readsectionclass(cfg);
458 break;
461 else if (strlen(line)!=0)
462 filewarning("warning line outside section ignored\n");
465 return NULL;
468 static void readsectionconfig(struct config *cfg, struct classinfo *cl, int inclass)
470 int atend = 0, i;
471 char *line, *s, *s2, *libbasetypeextern = NULL;
473 while (!atend)
475 line = readline();
476 if (line==NULL)
477 exitfileerror(20, "unexpected end of file in section config\n");
479 if (strncmp(line, "##", 2)!=0)
481 const char *names[] =
483 "basename", "libbase", "libbasetype", "libbasetypeextern",
484 "version", "date", "copyright", "libcall", "forcebase", "superclass",
485 "superclass_field", "residentpri", "options", "sysbase_field",
486 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
487 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
488 "initpri", "type"
490 const unsigned int namenums = sizeof(names)/sizeof(char *);
491 unsigned int namenum;
493 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
497 strncmp(line, names[i], strlen(names[i]))==0
498 && isspace(*(line+strlen(names[i])))
500 namenum = i+1;
502 if (namenum==0)
503 exitfileerror(20, "unrecognized configuration option\n");
505 s = line + strlen(names[namenum-1]);
506 if (!isspace(*s))
507 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
509 while (isspace(*s)) s++;
510 if (*s=='\0')
511 exitfileerror(20, "unexpected end of line\n");
513 s2 = s + strlen(s);
514 while (isspace(*(s2-1))) s2--;
515 *s2 = '\0';
517 switch (namenum)
519 case 1: /* basename */
520 if (!inclass)
521 cfg->basename = strdup(s);
522 if (cl != NULL)
523 cl->basename = strdup(s);
524 break;
526 case 2: /* libbase */
527 if (inclass)
528 exitfileerror(20, "libbase not valid config option when in a class section\n");
529 cfg->libbase = strdup(s);
530 break;
532 case 3: /* libbasetype */
533 if (inclass)
534 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
535 cfg->libbasetype = strdup(s);
536 break;
538 case 4: /* libbasetypeextern */
539 if (inclass)
540 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
541 libbasetypeextern = strdup(s);
542 break;
544 case 5: /* version */
545 if (inclass)
546 exitfileerror(20, "version not valid config option when in a class section\n");
547 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
548 exitfileerror(20, "wrong version string \"%s\"\n", s);
549 break;
551 case 6: /* date */
552 if (inclass)
553 exitfileerror(20, "date not valid config option when in a class section\n");
554 if (!(strlen(s)==10 && isdigit(s[0]) && isdigit(s[1]) &&
555 s[2]=='.' && isdigit(s[3]) && isdigit(s[4]) &&
556 s[5]=='.' && isdigit(s[6]) && isdigit(s[7]) &&
557 isdigit(s[8]) && isdigit(s[9])
561 exitfileerror(20, "date string has have dd.mm.yyyy format\n");
563 cfg->datestring = strdup(s);
564 break;
566 case 7: /* copyright */
567 if (inclass)
568 exitfileerror(20, "copyright not valid config option when in a class section\n");
569 cfg->copyright = strdup(s);
570 break;
572 case 8: /* libcall */
573 fprintf(stderr, "libcall specification is deprecated and ignored\n");
574 break;
576 case 9: /* forcebase */
577 if (inclass)
578 exitfileerror(20, "forcebase not valid config option when in a class section\n");
579 slist_append(&cfg->forcelist, s);
580 break;
582 case 10: /* superclass */
583 if (cl == NULL)
584 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
585 cl->superclass = strdup(s);
586 break;
588 case 11: /* superclass_field */
589 if (cl == NULL)
590 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
591 cl->superclass_field = strdup(s);
592 break;
594 case 12: /* residentpri */
595 if (!inclass)
597 int count;
598 char dummy;
600 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
601 if (count != 1 ||
602 cfg->residentpri < -128 || cfg->residentpri > 127
605 exitfileerror(20, "residentpri number format error\n");
608 else
609 exitfileerror(20, "residentpri not valid config option when in a class section\n");
610 break;
612 case 13: /* options */
613 if (!inclass)
615 static const char *optionnames[] =
617 "noautolib", "noexpunge", "noresident", "peropenerbase"
619 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
620 int optionnum;
624 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
626 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
628 optionnum = i + 1;
629 s += strlen(optionnames[i]);
630 while (isspace(*s)) s++;
631 if (*s == ',')
632 s++;
633 else if (*s != '\0')
634 exitfileerror(20, "Unrecognized option\n");
637 if (optionnum == 0)
638 exitfileerror(20, "Unrecognized option\n");
639 switch (optionnum)
641 case 1: /* noautolib */
642 cfg->options |= OPTION_NOAUTOLIB;
643 break;
644 case 2: /* noexpunge */
645 cfg->options |= OPTION_NOEXPUNGE;
646 break;
647 case 3: /* noresident */
648 cfg->options |= OPTION_NORESIDENT;
649 cfg->firstlvo = 1;
650 break;
651 case 4: /* peropenerbase */
652 cfg->options |= OPTION_DUPBASE;
653 break;
655 while (isspace(*s)) s++;
656 } while(*s !='\0');
658 else
660 static const char *optionnames[] =
662 "private"
664 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
665 int optionnum;
669 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
671 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
673 optionnum = i + 1;
674 s += strlen(optionnames[i]);
675 while (isspace(*s)) s++;
676 if (*s == ',')
677 s++;
678 else if (*s != '\0')
679 exitfileerror(20, "Unrecognized option\n");
682 if (optionnum == 0)
683 exitfileerror(20, "Unrecognized option\n");
684 switch (optionnum)
686 case 1: /* private */
687 cl->options |= COPTION_PRIVATE;
688 break;
690 while (isspace(*s)) s++;
691 } while(*s !='\0');
693 break;
695 case 14: /* sysbase_field */
696 if (inclass)
697 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
698 cfg->sysbase_field = strdup(s);
699 break;
701 case 15: /* seglist_field */
702 if (inclass)
703 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
704 cfg->seglist_field = strdup(s);
705 break;
707 case 16: /* rootbase_field */
708 if (inclass)
709 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
710 cfg->rootbase_field = strdup(s);
711 break;
713 case 17: /* classptr_field */
714 if (cl == NULL)
716 exitfileerror
719 "classptr_field specified when not a BOOPSI class\n"
722 cl->classptr_field = strdup(s);
723 break;
725 case 18: /* classptr_var */
726 if (cl == NULL)
728 exitfileerror
731 "classptr_var specified when not a BOOPSI class\n"
734 cl->classptr_var = strdup(s);
735 break;
737 case 19: /* classid */
738 if (cl == NULL)
739 exitfileerror(20, "classid specified when not a BOOPSI class\n");
740 if (cl->classid != NULL)
741 exitfileerror(20, "classid specified twice\n");
742 cl->classid = strdup(s);
743 if (strcmp(cl->classid, "NULL") == 0)
744 cl->options |= COPTION_PRIVATE;
745 break;
747 case 20: /* classdatatype */
748 if (cl == NULL)
749 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
750 cl->classdatatype = strdup(s);
751 break;
753 case 21: /* beginio_func */
754 if (inclass)
755 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
756 if (cfg->modtype != DEVICE)
757 exitfileerror(20, "beginio_func specified when not a device\n");
758 cfg->beginiofunc = strdup(s);
759 break;
761 case 22: /* abortio_func */
762 if (inclass)
763 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
764 if (cfg->modtype != DEVICE)
765 exitfileerror(20, "abortio_func specified when not a device\n");
766 cfg->abortiofunc = strdup(s);
767 break;
769 case 23: /* dispatcher */
770 if (cl == NULL)
771 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
772 cl->dispatcher = strdup(s);
773 /* function references are not needed when dispatcher is specified */
774 cfg->intcfg |= CFG_NOREADREF;
775 break;
777 case 24: /* initpri */
778 if (cl != NULL)
780 int count;
781 char dummy;
783 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
784 if (count != 1 ||
785 cl->initpri < -128 || cl->initpri > 127
788 exitfileerror(20, "initpri number format error\n");
791 else
792 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
793 break;
795 case 25: /* type */
796 if (!inclass)
797 exitfileerror(20, "type only valid config option in a class section\n");
798 if (strcmp(s,"mcc")==0)
799 cl->classtype = MCC;
800 else if (strcmp(s,"mui")==0)
801 cl->classtype = MUI;
802 else if (strcmp(s,"mcp")==0)
803 cl->classtype = MCP;
804 else if (strcmp(s, "image")==0)
805 cl->classtype = IMAGE;
806 else if (strcmp(s, "gadget")==0)
807 cl->classtype = GADGET;
808 else if (strcmp(s, "datatype")==0)
809 cl->classtype = DATATYPE;
810 else if (strcmp(s, "class")==0)
811 cl->classtype = CLASS;
812 else if (strcmp(s, "hidd")==0)
813 cl->classtype = HIDD;
814 else
816 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
817 exit(20);
819 break;
822 else /* Line starts with ## */
824 s = line+2;
825 while (isspace(*s)) s++;
826 if (strncmp(s, "end", 3)!=0)
827 exitfileerror(20, "\"##end config\" expected\n");
829 s += 3;
830 if (!isspace(*s))
831 exitfileerror(20, "\"##end config\" expected\n");
833 while (isspace(*s)) s++;
834 if (strncmp(s, "config", 6)!=0)
835 exitfileerror(20, "\"##end config\" expected\n");
837 s += 6;
838 while (isspace(*s)) s++;
839 if (*s!='\0')
840 exitfileerror(20, "\"##end config\" expected\n");
842 atend = 1;
846 /* When not in a class section fill in default values for fields in cfg */
847 if (!inclass)
849 if (cfg->basename==NULL)
851 cfg->basename = strdup(cfg->modulename);
852 *cfg->basename = toupper(*cfg->basename);
854 if (cfg->libbase==NULL)
856 unsigned int len = strlen(cfg->basename)+5;
857 cfg->libbase = malloc(len);
858 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
860 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
861 cfg->libbasetype = strdup(libbasetypeextern);
862 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
863 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
864 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
865 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
867 /* Set default date to current date */
868 if (cfg->datestring == NULL)
870 char tmpbuf[256];
871 time_t now = time(NULL);
873 strftime(tmpbuf, sizeof(tmpbuf), "%d.%m.%Y", localtime(&now));
875 cfg->datestring = strdup(tmpbuf);
878 if (cfg->copyright == NULL)
879 cfg->copyright = "";
881 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
882 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
884 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
886 if (libbasetypeextern==NULL)
888 switch (cfg->modtype)
890 case DEVICE:
891 cfg->libbasetypeptrextern = "struct Device *";
892 break;
893 case RESOURCE:
894 cfg->libbasetypeptrextern = "APTR ";
895 break;
896 case LIBRARY:
897 case MUI:
898 case MCP:
899 case MCC:
900 case GADGET:
901 case DATATYPE:
902 case HIDD:
903 cfg->libbasetypeptrextern = "struct Library *";
904 break;
905 default:
906 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
907 exit(20);
910 else
912 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
913 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
914 strcat(cfg->libbasetypeptrextern, " *");
915 free(libbasetypeextern);
919 /* When class was given too fill in some defaults when not specified */
920 if (cl != NULL)
922 if (cl->classtype == UNSPECIFIED)
923 cl->classtype = CLASS;
925 if (cl->basename == NULL)
927 if (!inclass)
928 cl->basename = cfg->basename;
929 else
930 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
933 /* MUI classes are always private */
934 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
935 cl->options |= COPTION_PRIVATE;
937 if (cl->classid == NULL
938 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
941 if (cl->classtype == HIDD)
943 cl->options &= !COPTION_PRIVATE;
945 else if (cl->options & COPTION_PRIVATE)
947 cl->classid = "NULL";
949 else
951 char s[256] = "";
953 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS)
955 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
957 else if (cl->classtype == DATATYPE)
959 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
961 cl->classid = strdup(s);
965 /* Only specify superclass or superclass_field */
966 if (cl->superclass != NULL && cl->superclass_field != NULL)
967 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
969 /* Give default value to superclass if it is not specified */
970 if (cl->superclass == NULL && cl->superclass == NULL)
972 switch (cl->classtype)
974 case MUI:
975 case MCC:
976 cl->superclass = "MUIC_Area";
977 break;
978 case MCP:
979 cl->superclass = "MUIC_Mccprefs";
980 break;
981 case IMAGE:
982 cl->superclass = "IMAGECLASS";
983 break;
984 case GADGET:
985 cl->superclass = "GADGETCLASS";
986 break;
987 case DATATYPE:
988 cl->superclass = "DATATYPESCLASS";
989 break;
990 case CLASS:
991 cl->superclass = "ROOTCLASS";
992 break;
993 case HIDD:
994 cl->superclass = "CLID_Root";
995 break;
996 default:
997 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
998 break;
1004 static void readsectioncdef(struct config *cfg)
1006 int atend = 0;
1007 char *line, *s;
1009 while (!atend)
1011 line = readline();
1012 if (line==NULL)
1013 exitfileerror(20, "unexptected end of file in section cdef\n");
1015 if (strncmp(line, "##", 2)!=0)
1017 slist_append(&cfg->cdeflines, line);
1019 else
1021 s = line+2;
1022 while (isspace(*s)) s++;
1023 if (strncmp(s, "end", 3)!=0)
1024 exitfileerror(20, "\"##end cdef\" expected\n");
1026 s += 3;
1027 while (isspace(*s)) s++;
1028 if (strncmp(s, "cdef", 4)!=0)
1029 exitfileerror(20, "\"##end cdef\" expected\n");
1031 s += 5;
1032 while (isspace(*s)) s++;
1033 if (*s!='\0')
1034 exitfileerror(20, "unexpected character at position %d\n");
1036 atend = 1;
1041 static void readsectioncdefprivate(struct config *cfg)
1043 int atend = 0;
1044 char *line, *s;
1046 while (!atend)
1048 line = readline();
1049 if (line==NULL)
1050 exitfileerror(20, "unexptected end of file in section cdef\n");
1052 if (strncmp(line, "##", 2)!=0)
1054 slist_append(&cfg->cdefprivatelines, line);
1056 else
1058 s = line+2;
1059 while (isspace(*s)) s++;
1060 if (strncmp(s, "end", 3)!=0)
1061 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1063 s += 3;
1064 while (isspace(*s)) s++;
1065 if (strncmp(s, "cdefprivate", 11)!=0)
1066 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1068 s += 11;
1069 while (isspace(*s)) s++;
1070 if (*s!='\0')
1071 exitfileerror(20, "unexpected character at position %d\n");
1073 atend = 1;
1078 static void readsectionfunctionlist(struct config *cfg)
1080 int atend = 0, i;
1081 char *line, *s, *s2;
1082 unsigned int lvo = cfg->firstlvo;
1083 struct functionhead **funclistptr = &cfg->funclist;
1085 if (cfg->basename==NULL)
1086 exitfileerror(20, "section functionlist has to come after section config\n");
1088 while (!atend)
1090 line = readline();
1091 if (line==NULL)
1092 exitfileerror(20, "unexptected EOF in functionlist section\n");
1093 if (strlen(line)==0)
1095 if (*funclistptr != NULL)
1096 funclistptr = &((*funclistptr)->next);
1097 lvo++;
1099 else if (isspace(*line))
1101 s = line;
1102 while (isspace(*s)) s++;
1103 if (*s=='\0')
1105 if (*funclistptr != NULL)
1106 funclistptr = &((*funclistptr)->next);
1107 lvo++;
1109 else
1110 exitfileerror(20, "no space allowed before functionname\n");
1112 else if (strncmp(line, "##", 2)==0)
1114 s = line+2;
1115 while (isspace(*s)) s++;
1116 if (strncmp(s, "end", 3)!=0)
1117 exitfileerror(20, "\"##end functionlist\" expected\n");
1119 s += 3;
1120 while (isspace(*s)) s++;
1121 if (strncmp(s, "functionlist", 12)!=0)
1122 exitfileerror(20, "\"##end functionlist\" expected\n");
1124 s += 12;
1125 while (isspace(*s)) s++;
1126 if (*s!='\0')
1127 exitfileerror(20, "unexpected character on position %d\n", s-line);
1129 atend = 1;
1131 else if (*line=='.')
1133 s = line+1;
1134 if (strncmp(s, "skip", 4)==0)
1136 int n;
1138 s += 4;
1139 if (!isspace(*s))
1140 exitfileerror(20, "syntax is '.skip n'\n");
1142 n=strtol(s, &s2, 10);
1143 if (s2==NULL)
1144 exitfileerror(20, "positive number expected\n");
1146 while (isspace(*s2)) s2++;
1147 if (*s2!='\0')
1148 exitfileerror(20, "syntax is '.skip n'\n");
1149 if (*funclistptr != NULL)
1150 funclistptr = &((*funclistptr)->next);
1151 lvo += n;
1153 else if (strncmp(s, "alias", 5)==0)
1155 s += 5;
1157 if (!isspace(*s))
1158 exitfileerror(20, "syntax is '.alias name'\n");
1160 while (isspace(*s)) s++;
1161 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1162 exitfileerror(20, "syntax is '.alias name'\n");
1164 s2 = s;
1165 s++;
1166 while (isalnum(*s) || *s == '_') s++;
1168 if (isspace(*s))
1170 *s = '\0';
1171 do {
1172 s++;
1173 } while (isspace(*s));
1176 if (*s != '\0')
1177 exitfileerror(20, "syntax is '.alias name'\n");
1179 if (*funclistptr == NULL)
1180 exitfileerror(20, ".alias has to come after a function declaration\n");
1182 slist_append(&(*funclistptr)->aliases, s2);
1183 cfg->intcfg |= CFG_GENASTUBS;
1185 else if (strncmp(s, "cfunction", 9)==0)
1187 if (*funclistptr == NULL)
1188 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1190 (*funclistptr)->libcall = REGISTER;
1192 else if (strncmp(s, "private", 7)==0)
1194 if (*funclistptr == NULL)
1195 exitfileerror(20, ".private has to come after a function declaration\n");
1197 (*funclistptr)->priv = 1;
1199 else if (strncmp(s, "novararg", 8)==0)
1201 if (*funclistptr == NULL)
1202 exitfileerror(20, ".novararg has to come after a function declaration\n");
1204 (*funclistptr)->novararg = 1;
1206 else
1207 exitfileerror(20, "Syntax error");
1209 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1211 /* The line is a function prototype. It can have two syntax
1212 * type funcname(argproto1, argproto2, ...)
1213 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1214 * The former is for C type function argument passing, the latter for
1215 * register argument passing.
1217 char c, *args[64], *regs[64], *funcname;
1218 int len, argcount = 0, regcount = 0, brcount = 0;
1220 /* Parse 'type functionname' at the beginning of the line */
1221 s = strchr(line, '(');
1222 if (s == NULL)
1223 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1225 s2 = s;
1226 while (isspace(*(s2-1)))
1227 s2--;
1228 *s2 = '\0';
1230 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1231 s2--;
1233 if (s2 == line)
1234 exitfileerror(20, "No type specifier before function name\n");
1236 if (*funclistptr != NULL)
1237 funclistptr = &((*funclistptr)->next);
1238 *funclistptr = newfunctionhead(s2, STACK);
1240 while (isspace(*(s2-1)))
1241 s2--;
1242 *s2 = '\0';
1243 (*funclistptr)->type = strdup(line);
1244 (*funclistptr)->lvo = lvo;
1245 lvo++;
1247 /* Parse function prototype */
1248 s++;
1249 while (isspace(*s))
1250 s++;
1251 c = *s;
1253 while (c != ')')
1255 while (isspace(*s))
1256 s++;
1258 args[argcount] = s;
1259 argcount++;
1261 while
1263 *s != '\0'
1264 && !(brcount == 0 && (*s == ',' || *s == ')'))
1267 if (*s == '(')
1268 brcount++;
1269 if (*s == ')')
1271 if (brcount > 0)
1272 brcount--;
1273 else
1274 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1276 s++;
1279 c = *s;
1280 if (c == '\0')
1281 exitfileerror(20, "'(' without ')'");
1283 s2 = s;
1284 while (isspace(*(s2-1)))
1285 s2--;
1286 *s2 = '\0';
1288 if (!(s2 > args[argcount - 1]))
1289 exitfileerror(20, "Syntax error in function prototype\n");
1291 s++;
1294 s++;
1295 while (*s != '\0' && isspace(*s))
1296 s++;
1298 if (*s == '(')
1300 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1302 /* There may be no register specified with () so be sure then c is == ')' */
1303 s++;
1304 while(isspace(*s))
1305 s++;
1307 c = *s;
1309 while (c != ')')
1311 while (isspace(*s))
1312 s++;
1314 regs[regcount] = s;
1315 regcount++;
1317 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1319 s += 2;
1320 c = *s;
1321 if (c == '/')
1323 if (regcount > 1)
1325 if (strchr(regs[0], '/') == NULL)
1326 exitfileerror(20, "Either all arguments has to in two registers or none\n");
1329 s++;
1330 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1332 s += 2;
1333 c = *s;
1335 else
1336 exitfileerror(20,
1337 "wrong register specification \"%s\" for argument %u\n",
1338 regs[regcount-1], regcount
1341 if (regcount > 2)
1342 exitfileerror(20, "maximum two arguments passed in two registers allowed\n");
1344 *s = '\0';
1346 else
1347 exitfileerror(20,
1348 "wrong register \"%s\" for argument %u\n",
1349 regs[regcount-1], regcount
1352 while (isspace(c))
1354 s++;
1355 c = *s;
1357 if (c == '\0')
1358 exitfileerror(20, "'(' without ')'\n");
1359 if (c != ',' && c != ')')
1360 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1362 s++;
1365 s++;
1366 while (isspace(*s)) s++;
1367 if (*s!='\0')
1368 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1370 if (argcount != regcount)
1371 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1372 argcount, regcount
1375 (*funclistptr)->libcall = REGISTERMACRO;
1376 for (i = 0; i < argcount; i++)
1377 funcaddarg(*funclistptr, args[i], regs[i]);
1379 else if (*s == '\0')
1380 { /* No registers specified */
1381 for (i = 0; i < argcount; i++)
1382 funcaddarg(*funclistptr, args[i], NULL);
1383 cfg->intcfg |= CFG_GENASTUBS;
1385 else
1386 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1391 static void readsectionmethodlist(struct classinfo *cl)
1393 int atend = 0, i;
1394 char *line, *s, *s2;
1395 struct functionhead **methlistptr = &cl->methlist;
1396 struct stringlist *interface = NULL;
1398 if (cl->basename==NULL)
1399 exitfileerror(20, "section methodlist has to come after section config\n");
1401 while (!atend)
1403 line = readline();
1404 if (line==NULL)
1405 exitfileerror(20, "unexptected EOF in methodlist section\n");
1407 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1408 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1409 continue;
1411 if (isspace(*line))
1412 exitfileerror(20, "No space allowed at start of the line\n");
1414 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1416 s = line+2;
1417 while (isspace(*s)) s++;
1418 if (strncmp(s, "end", 3)!=0)
1419 exitfileerror(20, "\"##end methodlist\" expected\n");
1421 s += 3;
1422 while (isspace(*s)) s++;
1423 if (strncmp(s, "methodlist", 10)!=0)
1424 exitfileerror(20, "\"##end methodlist\" expected\n");
1426 s += 10;
1427 while (isspace(*s)) s++;
1428 if (*s!='\0')
1429 exitfileerror(20, "unexpected character on position %d\n", s-line);
1431 atend = 1;
1433 continue;
1436 if (*line=='.')
1438 s = line+1;
1439 if (strncmp(s, "alias", 5)==0)
1441 s += 5;
1443 if (!isspace(*s))
1444 exitfileerror(20, "syntax is '.alias name'\n");
1446 while (isspace(*s)) s++;
1447 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1448 exitfileerror(20, "syntax is '.alias name'\n");
1450 s2 = s;
1451 s++;
1452 while (isalnum(*s) || *s == '_') s++;
1454 if (isspace(*s))
1456 *s = '\0';
1457 do {
1458 s++;
1459 } while (isspace(*s));
1462 if (*s != '\0')
1463 exitfileerror(20, "syntax is '.alias name'\n");
1465 if (*methlistptr == NULL)
1466 exitfileerror(20, ".alias has to come after a function declaration\n");
1468 slist_append(&(*methlistptr)->aliases, s2);
1470 else if (strncmp(s, "function", 8) == 0)
1472 s += 8;
1474 if (!isspace(*s))
1475 exitfileerror(20, "Syntax error\n");
1477 while (isspace(*s)) s++;
1478 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1479 exitfileerror(20, "syntax is '.function name'\n");
1481 s2 = s;
1482 s++;
1483 while (isalnum(*s) || *s == '_') s++;
1485 if (isspace(*s))
1487 *s = '\0';
1488 do {
1489 s++;
1490 } while (isspace(*s));
1493 if (*s != '\0')
1494 exitfileerror(20, "syntax is '.function name'\n");
1496 if (*methlistptr == NULL)
1497 exitfileerror(20, ".function has to come after a function declaration\n");
1499 free((*methlistptr)->name);
1500 (*methlistptr)->name = strdup(s2);
1502 else if (strncmp(s, "interface", 9) == 0)
1504 if (cl->classtype != HIDD)
1505 exitfileerror(20, "interface only valid for a HIDD\n");
1507 s += 9;
1509 if (!isspace(*s))
1510 exitfileerror(20, "Syntax error\n");
1512 while (isspace(*s)) s++;
1513 if (*s == '\0' || !isalpha(*s))
1514 exitfileerror(20, "syntax is '.interface name'\n");
1516 s2 = s;
1517 s++;
1518 while (isalnum(*s) || *s == '_') s++;
1520 if (isspace(*s))
1522 *s = '\0';
1523 do {
1524 s++;
1525 } while (isspace(*s));
1528 if (*s != '\0')
1529 exitfileerror(20, "syntax is '.interface name'\n");
1531 interface = slist_append(&cl->interfaces, s2);
1533 else
1534 exitfileerror(20, "Syntax error");
1536 else if (isalpha(*line))
1538 char stmp[256];
1540 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
1543 if (cl->classtype == HIDD && interface == NULL)
1544 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
1546 if (*s != '\0')
1547 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
1549 if (*methlistptr != NULL)
1550 methlistptr = &((*methlistptr)->next);
1551 if (cl->classtype != HIDD)
1553 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
1554 exitfileerror(20, "Method name too large\n");
1556 *methlistptr = newfunctionhead(stmp, STACK);
1557 (*methlistptr)->type = "IPTR";
1558 funcaddarg(*methlistptr, "Class *cl", NULL);
1559 funcaddarg(*methlistptr, "Object *o", NULL);
1560 funcaddarg(*methlistptr, "Msg msg", NULL);
1562 else
1564 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
1565 exitfileerror(20, "Method name too large\n");
1567 *methlistptr = newfunctionhead(stmp, STACK);
1568 (*methlistptr)->type = "IPTR";
1569 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
1570 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
1571 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
1572 (*methlistptr)->interface = interface;
1573 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
1574 exitfileerror(20, "Method name too large\n");
1575 (*methlistptr)->method = strdup(stmp);
1577 slist_append(&(*methlistptr)->aliases, line);
1579 else
1580 exitfileerror(20, "Methodname has to begin with a letter\n");
1584 static void
1585 readsectionclass(struct config *cfg)
1587 char *s;
1588 struct classinfo *cl;
1590 cl = newclass(cfg);
1591 s = readsections(cfg, cl, 1);
1592 if (s == NULL)
1593 exitfileerror(20, "Unexpected end of file\n");
1595 if (strncmp(s, "##", 2) != 0)
1596 exitfileerror(20, "'##end class' expected\n");
1597 s += 2;
1599 while (isspace(*s)) s++;
1601 if (strncmp(s, "end", 3) != 0)
1602 exitfileerror(20, "'##end class' expected\n");
1603 s += 3;
1605 if (!isspace(*s))
1606 exitfileerror(20, "'##end class' expected\n");
1607 while (isspace(*s)) s++;
1609 if (strncmp(s, "class", 5) != 0)
1610 exitfileerror(20, "'##end class' expected\n");
1611 s += 5;
1613 while (isspace(*s)) s++;
1614 if (*s != '\0')
1615 exitfileerror(20, "'##end class' expected\n");
1618 static struct classinfo *newclass(struct config *cfg)
1620 struct classinfo *cl, *classlistit;
1622 cl = malloc(sizeof(struct classinfo));
1623 if (cl == NULL)
1625 fprintf(stderr, "Out of memory\n");
1626 exit(20);
1628 memset(cl, 0, sizeof(struct classinfo));
1630 /* By default the classes are initialized with a priority of 1 so they
1631 * are initialized before any user added initialization with priority 1
1633 cl->initpri = 1;
1635 if (cfg->classlist == NULL)
1636 cfg->classlist = cl;
1637 else
1641 classlistit = cfg->classlist;
1642 classlistit->next != NULL;
1643 classlistit = classlistit->next
1646 classlistit->next = cl;
1649 return cl;