Detabbed
[AROS.git] / tools / genmodule / config.c
blob12ff6371290b36f12395debbe08970c2332b1725
1 /*
2 Copyright © 1995-2012, 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 #define __USE_XOPEN
13 #include <time.h>
14 #include <unistd.h>
15 #include <limits.h>
17 #include "functionhead.h"
18 #include "config.h"
20 const static char bannertemplate[] =
21 "/*\n"
22 " *** Automatically generated from '%s'. Edits will be lost. ***\n"
23 " Copyright © 1995-2012, The AROS Development Team. All rights reserved.\n"
24 "*/\n";
26 char*
27 getBanner(struct config* config)
29 int bannerlength = strlen(config->conffile) + strlen(bannertemplate) -1;
30 char * banner = malloc(bannerlength);
32 snprintf (banner, bannerlength, bannertemplate, config->conffile);
34 return(banner);
37 void
38 freeBanner(char *banner)
40 free((void *)banner);
43 const static char usage[] =
44 "\n"
45 "Usage: genmodule [-c conffile] [-s suffix] [-d gendir] [-n]\n"
46 " {writefiles|writemakefile|writeincludes|writelibdefs|writefunclist|writefd|writeskel} modname modtype\n"
49 static void readconfig(struct config *);
50 static struct classinfo *newclass(struct config *);
51 static struct handlerinfo *newhandler(struct config *);
52 static struct interfaceinfo *newinterface(struct config *);
54 /* the method prefices for the supported classes */
55 static const char *muimprefix[] =
57 "__OM_",
58 "__MUIM_",
59 NULL
61 static const char *gadgetmprefix[] =
63 "__OM_",
64 "__GM_",
65 "__AROSM_",
66 NULL
68 static const char *dtmprefix[] =
70 "__OM_",
71 "__GM_",
72 "__DTM_",
73 "__PDTM_",
74 NULL
77 /* Create a config struct. Initialize with the values from the programs command
78 * line arguments and the contents of the modules .conf file
80 struct config *initconfig(int argc, char **argv)
82 struct config *cfg;
83 char *s, **argvit = argv + 1;
84 int hassuffix = 0, c;
86 cfg = malloc(sizeof(struct config));
87 if (cfg == NULL)
89 fprintf(stderr, "Out of memory\n");
90 exit(20);
93 memset(cfg, 0, sizeof(struct config));
95 while ((c = getopt(argc, argv, ":c:s:d:v:")) != -1)
97 if (c == ':')
99 fprintf(stderr, "Option -%c needs an argument\n",optopt);
100 exit(20);
103 switch (c)
105 case 'c':
106 cfg->conffile = optarg;
107 break;
109 case 's':
110 cfg->suffix = optarg;
111 hassuffix = 1;
112 break;
114 case 'd':
115 /* Remove / at end if present */
116 if ((optarg)[strlen(*argvit)-1]=='/') (optarg)[strlen(optarg)-1]='\0';
117 cfg->gendir = optarg;
118 break;
120 case 'v':
121 cfg->versionextra = optarg;
122 break;
124 default:
125 fprintf(stderr, "Internal error: Unhandled option\n");
126 exit(20);
130 if (optind + 3 != argc)
132 fprintf(stderr, "Wrong number of arguments.\n%s", usage);
133 exit(20);
136 if (strcmp(argv[optind], "writefiles") == 0)
138 cfg->command = FILES;
140 else if (strcmp(argv[optind], "writemakefile") == 0)
142 cfg->command = MAKEFILE;
144 else if (strcmp(argv[optind], "writeincludes") == 0)
146 cfg->command = INCLUDES;
148 else if (strcmp(argv[optind], "writelibdefs") == 0)
150 cfg->command = LIBDEFS;
152 else if (strcmp(argv[optind], "writefunclist") == 0)
154 cfg->command = WRITEFUNCLIST;
156 else if (strcmp(argv[optind], "writefd") == 0)
158 cfg->command = WRITEFD;
160 else if (strcmp(argv[optind], "writeskel") == 0)
162 cfg->command = WRITESKEL;
164 else
166 fprintf(stderr, "Unrecognized argument \"%s\"\n%s", argv[optind], usage);
167 exit(20);
170 cfg->modulename = argv[optind+1];
171 cfg->modulenameupper = strdup(cfg->modulename);
172 for (s=cfg->modulenameupper; *s!='\0'; *s = toupper(*s), s++) {
173 if (!isalnum(*s)) *s = '_';
176 if (strcmp(argv[optind+2],"library")==0)
178 cfg->modtype = LIBRARY;
179 cfg->moddir = "Libs";
181 else if (strcmp(argv[optind+2],"mcc")==0)
183 cfg->modtype = MCC;
184 cfg->moddir = "Classes/Zune";
186 else if (strcmp(argv[optind+2],"mui")==0)
188 cfg->modtype = MUI;
189 cfg->moddir = "Classes/Zune";
191 else if (strcmp(argv[optind+2],"mcp")==0)
193 cfg->modtype = MCP;
194 cfg->moddir = "Classes/Zune";
196 else if (strcmp(argv[optind+2], "device")==0)
198 cfg->modtype = DEVICE;
199 cfg->moddir = "Devs";
201 else if (strcmp(argv[optind+2], "resource")==0)
203 cfg->modtype = RESOURCE;
204 cfg->moddir = "Devs";
206 else if (strcmp(argv[optind+2], "gadget")==0)
208 cfg->modtype = GADGET;
209 cfg->moddir = "Classes/Gadgets";
211 else if (strcmp(argv[optind+2], "datatype")==0)
213 cfg->modtype = DATATYPE;
214 cfg->moddir = "Classes/DataTypes";
216 else if (strcmp(argv[optind+2], "usbclass")==0)
218 cfg->modtype = USBCLASS;
219 cfg->moddir = "Classes/USB";
220 if(!hassuffix)
222 cfg->suffix = "class";
223 hassuffix = 1;
226 else if (strcmp(argv[optind+2], "hidd")==0)
228 cfg->modtype = HIDD;
229 cfg->moddir = "Devs/Drivers";
231 else if (strcmp(argv[optind+2], "handler")==0)
233 cfg->modtype = HANDLER;
234 cfg->moddir = "$(AROS_DIR_FS)";
236 else if (strcmp(argv[optind+2], "hook")==0)
238 cfg->modtype = HANDLER;
239 cfg->moddir = "Devs";
241 else
243 fprintf(stderr, "Unknown modtype \"%s\" specified for second argument\n", argv[optind+2]);
244 exit(20);
247 if (!hassuffix)
248 cfg->suffix = argv[optind+2];
250 /* Fill fields with default value if not specified on the command line */
252 char tmpbuf[256];
254 if (cfg->conffile == NULL)
256 snprintf(tmpbuf, sizeof(tmpbuf), "%s.conf", cfg->modulename);
257 cfg->conffile = strdup(tmpbuf);
260 if (cfg->gendir == NULL)
261 cfg->gendir = ".";
264 readconfig(cfg);
266 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
267 * if they are provided
269 if (cfg->beginiofunc != NULL)
271 struct functionhead *funchead;
273 cfg->intcfg |= CFG_NOREADFUNCS;
275 /* Add beginio_func to the list of functions */
276 funchead = newfunctionhead(cfg->beginiofunc, REGISTERMACRO);
277 funchead->type = strdup("void");
278 funchead->lvo = 5;
279 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
281 funchead->next = cfg->funclist;
282 cfg->funclist = funchead;
284 /* Add abortio_func to the list of functions */
285 funchead = newfunctionhead(cfg->abortiofunc, REGISTERMACRO);
286 funchead->type = strdup("LONG");
287 funchead->lvo = 6;
288 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
290 funchead->next = cfg->funclist->next;
291 cfg->funclist->next = funchead;
293 else if (cfg->modtype == DEVICE && cfg->intcfg & CFG_NOREADFUNCS)
295 fprintf
297 stderr,
298 "beginio_func and abortio_func missing for a device with a non empty function list\n"
300 exit(20);
303 /* See if we have any stackcall options */
304 if (cfg->funclist) {
305 struct functionhead *funchead;
307 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
308 if (funchead->libcall == STACK) {
309 cfg->options |= OPTION_STACKCALL;
310 break;
315 /* Verify that a handler has a handler */
316 if (cfg->modtype == HANDLER) {
317 if (cfg->handlerfunc == NULL) {
318 fprintf(stderr, "handler modules require a 'handler_func' ##config option\n");
319 exit(20);
321 cfg->options |= OPTION_NOAUTOLIB | OPTION_NOEXPUNGE | OPTION_NOOPENCLOSE;
324 return cfg;
327 /* Functions to read configuration from the configuration file */
329 #include "fileread.h"
331 static char *readsections(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
332 static void readsectionconfig(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
333 static void readsectioncdef(struct config *);
334 static void readsectioncdefprivate(struct config *);
335 static void readsectionstartup(struct config *);
336 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute);
337 static void readsectionclass_methodlist(struct classinfo *);
338 static void readsectionclass(struct config *);
339 static void readsectionhandler(struct config *);
340 static void readsectioninterface(struct config *);
342 static void readconfig(struct config *cfg)
344 struct classinfo *mainclass = NULL;
346 /* Create a classinfo structure if this module is a class */
347 switch (cfg->modtype)
349 case LIBRARY:
350 case DEVICE:
351 case RESOURCE:
352 case USBCLASS:
353 case HANDLER:
354 break;
356 case MCC:
357 case MUI:
358 case MCP:
359 case GADGET:
360 case DATATYPE:
361 case HIDD:
362 mainclass = newclass(cfg);
363 mainclass->classtype = cfg->modtype;
364 break;
366 default:
367 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
368 exit(20);
371 switch (cfg->modtype)
373 case LIBRARY:
374 case USBCLASS:
375 cfg->firstlvo = 5;
376 break;
377 case DEVICE:
378 cfg->firstlvo = 7;
379 break;
380 case MCC:
381 case MUI:
382 case MCP:
383 cfg->firstlvo = 6;
384 mainclass->boopsimprefix = muimprefix;
385 break;
386 case HANDLER:
387 case RESOURCE:
388 cfg->firstlvo = 1;
389 break;
390 case GADGET:
391 cfg->firstlvo = 5;
392 mainclass->boopsimprefix = gadgetmprefix;
393 break;
394 case DATATYPE:
395 cfg->firstlvo = 6;
396 mainclass->boopsimprefix = dtmprefix;
397 break;
398 case HIDD:
399 cfg->firstlvo = 5;
400 /* FIXME: need boopsimprefix ? */
401 break;
402 default:
403 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
404 exit(20);
407 if (!fileopen(cfg->conffile))
409 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
410 exit(20);
413 /* Read all sections and see that we are at the end of the file */
414 if (readsections(cfg, mainclass, NULL, 0) != NULL)
415 exitfileerror(20, "Syntax error");
417 fileclose();
420 /* readsections will scan through all the sections in the config file.
421 * arguments:
422 * struct config *cfg: The module config data which may be updated by
423 * the information in the sections
424 * struct classinfo *cl: The classdata to be filled with data from the sections.
425 * This may be NULL if this is the main part of the configuration file and the
426 * type of the module is not a class
427 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
428 * part of the config file.
430 static char *readsections(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
432 char *line, *s, *s2;
433 int hasconfig = 0;
435 while ((line=readline())!=NULL)
437 if (strncmp(line, "##", 2)==0)
439 static char *parts[] =
441 "config", "cdefprivate", "cdef", "startup", "functionlist", "methodlist", "class", "handler", "interface", "attributelist"
443 const unsigned int nums = sizeof(parts)/sizeof(char *);
444 unsigned int partnum;
445 int i, atend = 0;
447 s = line+2;
448 while (isspace(*s)) s++;
450 if (strncmp(s, "begin", 5)!=0)
451 return line;
453 s += 5;
454 if (!isspace(*s))
455 exitfileerror(20, "space after begin expected\n");
456 while (isspace(*s)) s++;
458 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
460 if (strncmp(s, parts[i], strlen(parts[i]))==0)
462 partnum = i+1;
463 s += strlen(parts[i]);
464 while (isspace(*s)) s++;
465 if (*s!='\0')
466 exitfileerror(20, "unexpected character on position %d\n", s-line);
469 if (partnum==0)
470 exitfileerror(20, "unknown start of section\n");
471 switch (partnum)
473 case 1: /* config */
474 readsectionconfig(cfg, cl, in, inclass);
475 hasconfig = 1;
476 break;
478 case 2: /* cdefprivate */
479 if (inclass)
480 exitfileerror(20, "cdefprivate section not allowed in class section\n");
481 readsectioncdefprivate(cfg);
482 break;
484 case 3: /* cdef */
485 if (inclass)
486 exitfileerror(20, "cdef section not allowed in class section\n");
487 readsectioncdef(cfg);
488 break;
490 case 4: /* startup */
491 if (inclass)
492 exitfileerror(20, "startup section not allowed in class section\n");
493 readsectionstartup(cfg);
494 break;
496 case 5: /* functionlist */
497 if (inclass)
498 exitfileerror(20, "functionlist section not allow in class section\n");
499 if (cfg->basename==NULL)
500 exitfileerror(20, "section functionlist has to come after section config\n");
502 readsectionfunctionlist("functionlist", &cfg->funclist, cfg->firstlvo, 0);
503 cfg->intcfg |= CFG_NOREADFUNCS;
504 break;
506 case 6: /* methodlist */
507 if (cl == NULL && in == NULL)
508 exitfileerror(20, "methodlist section when not in a class or interface\n");
509 if (cl)
510 readsectionclass_methodlist(cl);
511 else
512 readsectionfunctionlist("methodlist", &in->methodlist, 0, 0);
513 cfg->intcfg |= CFG_NOREADFUNCS;
514 break;
516 case 7: /* class */
517 if (inclass)
518 exitfileerror(20, "class section may not be in nested\n");
519 readsectionclass(cfg);
520 break;
521 case 8: /* handler */
522 readsectionhandler(cfg);
523 break;
524 case 9: /* interface */
525 if (inclass)
526 exitfileerror(20, "interface section may not be nested\n");
527 readsectioninterface(cfg);
528 break;
529 case 10: /* attributelist */
530 if (!in)
531 exitfileerror(20, "attributelist only valid in interface sections\n");
532 readsectionfunctionlist("attributelist", &in->attributelist, 0, 1);
533 break;
536 else if (strlen(line)!=0)
537 filewarning("warning line outside section ignored\n");
540 if(!inclass)
542 if (!hasconfig)
543 exitfileerror(20, "No config section in conffile\n");
545 /* If no indication was given for generating includes or not
546 decide on module type and if there are functions
548 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
550 switch (cfg->modtype)
552 case LIBRARY:
553 case RESOURCE:
554 cfg->options |= OPTION_INCLUDES;
555 break;
557 case HANDLER:
558 case MCC:
559 case MUI:
560 case MCP:
561 case USBCLASS:
562 cfg->options |= OPTION_NOINCLUDES;
563 break;
565 case DEVICE:
566 cfg->options |= (
567 (cfg->funclist != NULL)
568 || (cfg->cdeflines != NULL)
569 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
570 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
571 break;
573 case GADGET:
574 case DATATYPE:
575 case HIDD:
576 cfg->options |= (
577 (cfg->funclist != NULL)
578 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
579 break;
581 default:
582 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
583 exit(20);
584 break;
588 /* If no indication was given for not generating stubs only generate them if
589 * the module has functions
591 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
593 switch (cfg->modtype)
595 case LIBRARY:
596 cfg->options |= (cfg->funclist != NULL) ? OPTION_STUBS : OPTION_NOSTUBS;
597 break;
599 case USBCLASS:
600 case RESOURCE:
601 case GADGET:
602 case DEVICE:
603 case DATATYPE:
604 case MCC:
605 case MUI:
606 case MCP:
607 case HIDD:
608 case HANDLER:
609 cfg->options |= OPTION_NOSTUBS;
610 break;
612 default:
613 fprintf(stderr, "Internal error writemakefile: unhandled modtype for stubs\n");
614 exit(20);
615 break;
619 /* If no indication was given for generating autoinit code or not
620 decide on module type
622 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
624 switch (cfg->modtype)
626 case LIBRARY:
627 cfg->options |= OPTION_AUTOINIT;
628 break;
630 case USBCLASS:
631 case RESOURCE:
632 case GADGET:
633 case DEVICE:
634 case DATATYPE:
635 case MCC:
636 case MUI:
637 case MCP:
638 case HIDD:
639 case HANDLER:
640 cfg->options |= OPTION_NOAUTOINIT;
641 break;
643 default:
644 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
645 exit(20);
646 break;
650 if ((cfg->modtype == RESOURCE) || (cfg->modtype == HANDLER))
651 /* Enforce noopenclose for resources and handlers */
652 cfg->options |= OPTION_NOOPENCLOSE;
653 else if (!(cfg->options & OPTION_SELFINIT))
654 /* Enforce using RTF_AUTOINIT for everything except resources */
655 cfg->options |= OPTION_RESAUTOINIT;
658 return NULL;
661 static void readsectionconfig(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
663 int atend = 0, i;
664 char *line, *s, *s2, *libbasetypeextern = NULL;
665 struct tm date;
667 while (!atend)
669 line = readline();
670 if (line==NULL)
671 exitfileerror(20, "unexpected end of file in section config\n");
673 if (strncmp(line, "##", 2)!=0)
675 const char *names[] =
677 "basename", "libbase", "libbasetype", "libbasetypeextern",
678 "version", "date", "copyright", "libcall", "forcebase", "superclass",
679 "superclass_field", "residentpri", "options", "sysbase_field",
680 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
681 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
682 "initpri", "type", "addromtag", "oopbase_field",
683 "rellib", "interfaceid", "interfacename",
684 "methodstub", "methodbase", "attributebase", "handler_func"
686 const unsigned int namenums = sizeof(names)/sizeof(char *);
687 unsigned int namenum;
689 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
693 strncmp(line, names[i], strlen(names[i]))==0
694 && isspace(*(line+strlen(names[i])))
696 namenum = i+1;
698 if (namenum==0)
699 exitfileerror(20, "unrecognized configuration option\n");
701 s = line + strlen(names[namenum-1]);
702 if (!isspace(*s))
703 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
705 while (isspace(*s)) s++;
706 if (*s=='\0')
707 exitfileerror(20, "unexpected end of line\n");
709 s2 = s + strlen(s);
710 while (isspace(*(s2-1))) s2--;
711 *s2 = '\0';
713 switch (namenum)
715 case 1: /* basename */
716 if (!inclass)
717 cfg->basename = strdup(s);
718 if (cl != NULL)
719 cl->basename = strdup(s);
720 if (in != NULL)
721 exitfileerror(20, "basename not valid config option when in a interface section\n");
722 break;
724 case 2: /* libbase */
725 if (inclass)
726 exitfileerror(20, "libbase not valid config option when in a class section\n");
727 cfg->libbase = strdup(s);
728 break;
730 case 3: /* libbasetype */
731 if (inclass)
732 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
733 cfg->libbasetype = strdup(s);
734 break;
736 case 4: /* libbasetypeextern */
737 if (inclass)
738 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
739 libbasetypeextern = strdup(s);
740 break;
742 case 5: /* version */
743 if (inclass)
744 exitfileerror(20, "version not valid config option when in a class section\n");
745 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
746 exitfileerror(20, "wrong version string \"%s\"\n", s);
747 break;
749 case 6: /* date */
750 if (inclass)
751 exitfileerror(20, "date not valid config option when in a class section\n");
752 #ifndef _WIN32
753 if (strptime(s, "%e.%m.%Y", &date) == NULL)
755 exitfileerror(20, "date string has to have d.m.yyyy format\n");
757 #endif
758 cfg->datestring = strdup(s);
759 break;
761 case 7: /* copyright */
762 if (inclass)
763 exitfileerror(20, "copyright not valid config option when in a class section\n");
764 cfg->copyright = strdup(s);
765 break;
767 case 8: /* libcall */
768 fprintf(stderr, "libcall specification is deprecated and ignored\n");
769 break;
771 case 9: /* forcebase */
772 if (inclass)
773 exitfileerror(20, "forcebase not valid config option when in a class section\n");
774 slist_append(&cfg->forcelist, s);
775 break;
777 case 10: /* superclass */
778 if (cl == NULL)
779 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
780 cl->superclass = strdup(s);
781 break;
783 case 11: /* superclass_field */
784 if (cl == NULL)
785 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
786 cl->superclass_field = strdup(s);
787 break;
789 case 12: /* residentpri */
790 if (!inclass)
792 int count;
793 char dummy;
795 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
796 if (count != 1 ||
797 cfg->residentpri < -128 || cfg->residentpri > 127
800 exitfileerror(20, "residentpri number format error\n");
803 else
804 exitfileerror(20, "residentpri not valid config option when in a class section\n");
805 break;
807 case 13: /* options */
808 if (!inclass)
810 static const char *optionnames[] =
812 "noautolib", "noexpunge", "noresident", "peropenerbase",
813 "pertaskbase", "includes", "noincludes", "nostubs",
814 "autoinit", "noautoinit", "resautoinit", "noopenclose",
815 "selfinit"
817 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
818 int optionnum;
822 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
824 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
826 optionnum = i + 1;
827 s += strlen(optionnames[i]);
828 while (isspace(*s)) s++;
829 if (*s == ',')
830 s++;
831 else if (*s != '\0')
832 exitfileerror(20, "Unrecognized option\n");
835 if (optionnum == 0)
836 exitfileerror(20, "Unrecognized option\n");
837 switch (optionnum)
839 case 1: /* noautolib */
840 cfg->options |= OPTION_NOAUTOLIB;
841 break;
842 case 2: /* noexpunge */
843 cfg->options |= OPTION_NOEXPUNGE;
844 break;
845 case 3: /* noresident */
846 cfg->options |= OPTION_NORESIDENT;
847 cfg->firstlvo = 1;
848 break;
849 case 5: /* pertaskbase */
850 cfg->options |= OPTION_PERTASKBASE;
851 /* Fall through */
852 case 4: /* peropenerbase */
853 if (cfg->options & OPTION_DUPBASE)
854 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
855 cfg->options |= OPTION_DUPBASE;
856 break;
857 case 6: /* includes */
858 if (cfg->options & OPTION_NOINCLUDES)
859 exitfileerror(20, "option includes and noincludes are incompatible\n");
860 cfg->options |= OPTION_INCLUDES;
861 break;
862 case 7: /* noincludes */
863 if (cfg->options & OPTION_INCLUDES)
864 exitfileerror(20, "option includes and noincludes are incompatible\n");
865 cfg->options |= OPTION_NOINCLUDES;
866 break;
867 case 8: /* nostubs */
868 cfg->options |= OPTION_NOSTUBS;
869 break;
870 case 9: /* autoinit */
871 if (cfg->options & OPTION_NOAUTOINIT)
872 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
873 cfg->options |= OPTION_AUTOINIT;
874 break;
875 case 10: /* noautoinit */
876 if (cfg->options & OPTION_AUTOINIT)
877 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
878 cfg->options |= OPTION_NOAUTOINIT;
879 break;
880 case 11: /* resautoinit */
881 if (cfg->options & OPTION_SELFINIT)
882 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
883 cfg->options |= OPTION_RESAUTOINIT;
884 break;
885 case 12:
886 cfg->options |= OPTION_NOOPENCLOSE;
887 break;
888 case 13: /* noresautoinit */
889 if (cfg->options & OPTION_RESAUTOINIT)
890 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
891 cfg->options |= OPTION_SELFINIT;
892 break;
894 while (isspace(*s)) s++;
895 } while(*s !='\0');
897 else
899 static const char *optionnames[] =
901 "private"
903 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
904 int optionnum;
908 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
910 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
912 optionnum = i + 1;
913 s += strlen(optionnames[i]);
914 while (isspace(*s)) s++;
915 if (*s == ',')
916 s++;
917 else if (*s != '\0')
918 exitfileerror(20, "Unrecognized option\n");
921 if (optionnum == 0)
922 exitfileerror(20, "Unrecognized option\n");
923 switch (optionnum)
925 case 1: /* private */
926 cl->options |= COPTION_PRIVATE;
927 break;
929 while (isspace(*s)) s++;
930 } while(*s !='\0');
932 break;
934 case 14: /* sysbase_field */
935 if (inclass)
936 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
937 cfg->sysbase_field = strdup(s);
938 break;
940 case 15: /* seglist_field */
941 if (inclass)
942 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
943 cfg->seglist_field = strdup(s);
944 break;
946 case 16: /* rootbase_field */
947 if (inclass)
948 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
949 cfg->rootbase_field = strdup(s);
950 break;
952 case 17: /* classptr_field */
953 if (cl == NULL)
955 exitfileerror
958 "classptr_field specified when not a BOOPSI class\n"
961 cl->classptr_field = strdup(s);
962 break;
964 case 18: /* classptr_var */
965 if (cl == NULL)
967 exitfileerror
970 "classptr_var specified when not a BOOPSI class\n"
973 cl->classptr_var = strdup(s);
974 break;
976 case 19: /* classid */
977 if (cl == NULL)
978 exitfileerror(20, "classid specified when not a BOOPSI class\n");
979 if (cl->classid != NULL)
980 exitfileerror(20, "classid specified twice\n");
981 cl->classid = strdup(s);
982 if (strcmp(cl->classid, "NULL") == 0)
983 cl->options |= COPTION_PRIVATE;
984 break;
986 case 20: /* classdatatype */
987 if (cl == NULL)
988 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
989 cl->classdatatype = strdup(s);
990 break;
992 case 21: /* beginio_func */
993 if (inclass)
994 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
995 if (cfg->modtype != DEVICE)
996 exitfileerror(20, "beginio_func specified when not a device\n");
997 cfg->beginiofunc = strdup(s);
998 break;
1000 case 22: /* abortio_func */
1001 if (inclass)
1002 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
1003 if (cfg->modtype != DEVICE)
1004 exitfileerror(20, "abortio_func specified when not a device\n");
1005 cfg->abortiofunc = strdup(s);
1006 break;
1008 case 23: /* dispatcher */
1009 if (cl == NULL)
1010 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
1011 cl->dispatcher = strdup(s);
1012 /* function references are not needed when dispatcher is specified */
1013 cfg->intcfg |= CFG_NOREADFUNCS;
1014 break;
1016 case 24: /* initpri */
1017 if (cl != NULL)
1019 int count;
1020 char dummy;
1022 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
1023 if (count != 1 ||
1024 cl->initpri < -128 || cl->initpri > 127
1027 exitfileerror(20, "initpri number format error\n");
1030 else
1031 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
1032 break;
1034 case 25: /* type */
1035 if (!inclass)
1036 exitfileerror(20, "type only valid config option in a class section\n");
1037 if (strcmp(s,"mcc")==0)
1038 cl->classtype = MCC;
1039 else if (strcmp(s,"mui")==0)
1040 cl->classtype = MUI;
1041 else if (strcmp(s,"mcp")==0)
1042 cl->classtype = MCP;
1043 else if (strcmp(s, "image")==0)
1044 cl->classtype = IMAGE;
1045 else if (strcmp(s, "gadget")==0)
1046 cl->classtype = GADGET;
1047 else if (strcmp(s, "datatype")==0)
1048 cl->classtype = DATATYPE;
1049 else if (strcmp(s, "usbclass")==0)
1050 cl->classtype = USBCLASS;
1051 else if (strcmp(s, "class")==0)
1052 cl->classtype = CLASS;
1053 else if (strcmp(s, "hidd")==0)
1054 cl->classtype = HIDD;
1055 else
1057 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
1058 exit(20);
1060 break;
1062 case 26: /* addromtag */
1063 cfg->addromtag = strdup(s);
1064 break;
1066 case 27: /* oopbase_field */
1067 cfg->oopbase_field = strdup(s);
1068 break;
1069 case 28: /* rellib */
1070 slist_append(&cfg->rellibs, s);
1071 break;
1072 case 29: /* interfaceid */
1073 if (!in)
1074 exitfileerror(20, "interfaceid only valid config option for an interface\n");
1075 in->interfaceid = strdup(s);
1076 break;
1077 case 30: /* interfacename */
1078 if (!in)
1079 exitfileerror(20, "interfacename only valid config option for an interface\n");
1080 in->interfacename = strdup(s);
1081 break;
1082 case 31: /* methodstub */
1083 if (!in)
1084 exitfileerror(20, "methodstub only valid config option for an interface\n");
1085 in->methodstub = strdup(s);
1086 break;
1087 case 32: /* methodbase */
1088 if (!in)
1089 exitfileerror(20, "methodbase only valid config option for an interface\n");
1090 in->methodbase = strdup(s);
1091 break;
1092 case 33: /* attributebase */
1093 if (!in)
1094 exitfileerror(20, "attributebase only valid config option for an interface\n");
1095 in->attributebase = strdup(s);
1096 break;
1097 case 34: /* handler_func */
1098 if (cfg->modtype != HANDLER)
1099 exitfileerror(20, "handler specified when not a handler\n");
1100 cfg->handlerfunc = strdup(s);
1101 break;
1104 else /* Line starts with ## */
1106 s = line+2;
1107 while (isspace(*s)) s++;
1108 if (strncmp(s, "end", 3)!=0)
1109 exitfileerror(20, "\"##end config\" expected\n");
1111 s += 3;
1112 if (!isspace(*s))
1113 exitfileerror(20, "\"##end config\" expected\n");
1115 while (isspace(*s)) s++;
1116 if (strncmp(s, "config", 6)!=0)
1117 exitfileerror(20, "\"##end config\" expected\n");
1119 s += 6;
1120 while (isspace(*s)) s++;
1121 if (*s!='\0')
1122 exitfileerror(20, "\"##end config\" expected\n");
1124 atend = 1;
1128 /* When not in a class section fill in default values for fields in cfg */
1129 if (!inclass)
1131 if (cfg->basename==NULL)
1133 cfg->basename = strdup(cfg->modulename);
1134 *cfg->basename = toupper(*cfg->basename);
1136 if (cfg->libbase==NULL)
1138 unsigned int len = strlen(cfg->basename)+5;
1139 cfg->libbase = malloc(len);
1140 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1142 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1143 cfg->libbasetype = strdup(libbasetypeextern);
1144 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1145 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1146 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1147 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1148 if (cfg->oopbase_field != NULL && cfg->libbasetype == NULL)
1149 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1150 /* rootbase_field only allowed when duplicating base */
1151 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1152 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1154 /* Set default date to current date */
1155 if (cfg->datestring == NULL)
1157 char tmpbuf[256];
1158 time_t now = time(NULL);
1159 struct tm *ltime = localtime(&now);
1161 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1162 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1164 cfg->datestring = strdup(tmpbuf);
1167 if (cfg->copyright == NULL)
1168 cfg->copyright = "";
1170 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1171 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1173 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1175 if (libbasetypeextern==NULL)
1177 switch (cfg->modtype)
1179 case DEVICE:
1180 cfg->libbasetypeptrextern = "struct Device *";
1181 break;
1182 case HANDLER:
1183 case RESOURCE:
1184 cfg->libbasetypeptrextern = "APTR ";
1185 break;
1186 case LIBRARY:
1187 case MUI:
1188 case MCP:
1189 case MCC:
1190 case GADGET:
1191 case DATATYPE:
1192 case USBCLASS:
1193 case HIDD:
1194 cfg->libbasetypeptrextern = "struct Library *";
1195 break;
1196 default:
1197 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1198 exit(20);
1201 else
1203 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1204 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1205 strcat(cfg->libbasetypeptrextern, " *");
1206 free(libbasetypeextern);
1210 /* When class was given too fill in some defaults when not specified */
1211 if (cl != NULL)
1213 if (cl->classtype == UNSPECIFIED)
1214 cl->classtype = CLASS;
1216 if (cl->basename == NULL)
1218 if (!inclass)
1219 cl->basename = cfg->basename;
1220 else
1221 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1224 /* MUI classes are always private */
1225 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1226 cl->options |= COPTION_PRIVATE;
1228 if (cl->classid == NULL
1229 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1232 if (cl->classtype == HIDD)
1234 cl->options &= !COPTION_PRIVATE;
1236 else if (cl->options & COPTION_PRIVATE)
1238 cl->classid = "NULL";
1240 else
1242 char s[256] = "";
1244 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1246 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1248 else if (cl->classtype == DATATYPE)
1250 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1252 cl->classid = strdup(s);
1256 /* Only specify superclass or superclass_field */
1257 if (cl->superclass != NULL && cl->superclass_field != NULL)
1258 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1260 /* Give default value to superclass if it is not specified */
1261 if (cl->superclass == NULL && cl->superclass == NULL)
1263 switch (cl->classtype)
1265 case MUI:
1266 case MCC:
1267 cl->superclass = "MUIC_Area";
1268 break;
1269 case MCP:
1270 cl->superclass = "MUIC_Mccprefs";
1271 break;
1272 case IMAGE:
1273 cl->superclass = "IMAGECLASS";
1274 break;
1275 case GADGET:
1276 cl->superclass = "GADGETCLASS";
1277 break;
1278 case DATATYPE:
1279 cl->superclass = "DATATYPESCLASS";
1280 break;
1281 case CLASS:
1282 cl->superclass = "ROOTCLASS";
1283 break;
1284 case HIDD:
1285 cl->superclass = "CLID_Root";
1286 break;
1287 default:
1288 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1289 break;
1295 static void readsectioncdef(struct config *cfg)
1297 int atend = 0;
1298 char *line, *s;
1300 while (!atend)
1302 line = readline();
1303 if (line==NULL)
1304 exitfileerror(20, "unexptected end of file in section cdef\n");
1306 if (strncmp(line, "##", 2)!=0)
1308 slist_append(&cfg->cdeflines, line);
1310 else
1312 s = line+2;
1313 while (isspace(*s)) s++;
1314 if (strncmp(s, "end", 3)!=0)
1315 exitfileerror(20, "\"##end cdef\" expected\n");
1317 s += 3;
1318 while (isspace(*s)) s++;
1319 if (strncmp(s, "cdef", 4)!=0)
1320 exitfileerror(20, "\"##end cdef\" expected\n");
1322 s += 5;
1323 while (isspace(*s)) s++;
1324 if (*s!='\0')
1325 exitfileerror(20, "unexpected character at position %d\n");
1327 atend = 1;
1332 static void readsectioncdefprivate(struct config *cfg)
1334 int atend = 0;
1335 char *line, *s;
1337 while (!atend)
1339 line = readline();
1340 if (line==NULL)
1341 exitfileerror(20, "unexptected end of file in section cdef\n");
1343 if (strncmp(line, "##", 2)!=0)
1345 slist_append(&cfg->cdefprivatelines, line);
1347 else
1349 s = line+2;
1350 while (isspace(*s)) s++;
1351 if (strncmp(s, "end", 3)!=0)
1352 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1354 s += 3;
1355 while (isspace(*s)) s++;
1356 if (strncmp(s, "cdefprivate", 11)!=0)
1357 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1359 s += 11;
1360 while (isspace(*s)) s++;
1361 if (*s!='\0')
1362 exitfileerror(20, "unexpected character at position %d\n");
1364 atend = 1;
1369 static void readsectionstartup(struct config *cfg)
1371 int atend = 0;
1372 char *line, *s;
1374 while (!atend)
1376 line = readline();
1377 if (line==NULL)
1378 exitfileerror(20, "unexptected end of file in section startup\n");
1380 if (strncmp(line, "##", 2)!=0)
1382 slist_append(&cfg->startuplines, line);
1384 else
1386 s = line+2;
1387 while (isspace(*s)) s++;
1388 if (strncmp(s, "end", 3)!=0)
1389 exitfileerror(20, "\"##end startup\" expected\n");
1391 s += 3;
1392 while (isspace(*s)) s++;
1393 if (strncmp(s, "startup", 7)!=0)
1394 exitfileerror(20, "\"##end startup\" expected\n");
1396 s += 7;
1397 while (isspace(*s)) s++;
1398 if (*s!='\0')
1399 exitfileerror(20, "unexpected character at position %d\n");
1401 atend = 1;
1406 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute)
1408 int atend = 0, i;
1409 char *line, *s, *s2;
1410 unsigned int lvo = firstlvo;
1411 int minversion = 0;
1413 while (!atend)
1415 line = readline();
1416 if (line==NULL)
1417 exitfileerror(20, "unexpected EOF in functionlist section\n");
1418 if (strlen(line)==0)
1420 if (*funclistptr != NULL)
1421 funclistptr = &((*funclistptr)->next);
1422 lvo++;
1424 else if (isspace(*line))
1426 s = line;
1427 while (isspace(*s)) s++;
1428 if (*s=='\0')
1430 if (*funclistptr != NULL)
1431 funclistptr = &((*funclistptr)->next);
1432 lvo++;
1434 else
1435 exitfileerror(20, "no space allowed before functionname\n");
1437 else if (strncmp(line, "##", 2)==0)
1439 s = line+2;
1440 while (isspace(*s)) s++;
1441 if (strncmp(s, "end", 3)!=0)
1442 exitfileerror(20, "\"##end %s\" expected\n", type);
1444 s += 3;
1445 while (isspace(*s)) s++;
1446 if (strncmp(s, type, strlen(type))!=0)
1447 exitfileerror(20, "\"##end %s\" expected\n", type);
1449 s += strlen(type);
1450 while (isspace(*s)) s++;
1451 if (*s!='\0')
1452 exitfileerror(20, "unexpected character on position %d\n", s-line);
1454 atend = 1;
1456 else if (*line=='.')
1458 s = line+1;
1459 if (strncmp(s, "skip", 4)==0)
1461 int n;
1463 s += 4;
1464 if (!isspace(*s))
1465 exitfileerror(20, "syntax is '.skip n'\n");
1467 n=strtol(s, &s2, 10);
1468 if (s2==NULL)
1469 exitfileerror(20, "positive number expected\n");
1471 while (isspace(*s2)) s2++;
1472 if ((*s2 != '\0') && (*s2 != '#'))
1473 exitfileerror(20, "syntax is '.skip n'\n");
1474 if (*funclistptr != NULL)
1475 funclistptr = &((*funclistptr)->next);
1476 lvo += n;
1478 else if (strncmp(s, "alias", 5)==0)
1480 s += 5;
1482 if (!isspace(*s))
1483 exitfileerror(20, "syntax is '.alias name'\n");
1485 while (isspace(*s)) s++;
1486 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1487 exitfileerror(20, "syntax is '.alias name'\n");
1489 s2 = s;
1490 s++;
1491 while (isalnum(*s) || *s == '_') s++;
1493 if (isspace(*s))
1495 *s = '\0';
1496 do {
1497 s++;
1498 } while (isspace(*s));
1501 if (*s != '\0')
1502 exitfileerror(20, "syntax is '.alias name'\n");
1504 if (*funclistptr == NULL)
1505 exitfileerror(20, ".alias has to come after a function declaration\n");
1507 slist_append(&(*funclistptr)->aliases, s2);
1509 else if (strncmp(s, "function", 8) == 0)
1511 s += 8;
1513 if (!isspace(*s))
1514 exitfileerror(20, "Syntax error\n");
1516 while (isspace(*s)) s++;
1517 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1518 exitfileerror(20, "syntax is '.function name'\n");
1520 s2 = s;
1521 s++;
1522 while (isalnum(*s) || *s == '_') s++;
1524 if (isspace(*s))
1526 *s = '\0';
1527 do {
1528 s++;
1529 } while (isspace(*s));
1532 if (*s != '\0')
1533 exitfileerror(20, "syntax is '.function name'\n");
1535 if (*funclistptr == NULL)
1536 exitfileerror(20, ".function has to come after a function declaration\n");
1538 funcsetinternalname(*funclistptr, s2);
1540 else if (strncmp(s, "cfunction", 9)==0)
1542 if (*funclistptr == NULL)
1543 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1545 (*funclistptr)->libcall = REGISTER;
1547 else if (strncmp(s, "private", 7)==0)
1549 if (*funclistptr == NULL)
1550 exitfileerror(20, ".private has to come after a function declaration\n");
1552 (*funclistptr)->priv = 1;
1554 else if (strncmp(s, "novararg", 8)==0)
1556 if (*funclistptr == NULL)
1557 exitfileerror(20, ".novararg has to come after a function declaration\n");
1559 (*funclistptr)->novararg = 1;
1561 else if (strncmp(s, "version", 7) == 0)
1563 /* Mark version number for the following
1564 * functions, so that the automatic OpenLibrary()
1565 * will know what version to use.
1567 char *tmp;
1568 int ver;
1570 s += 7;
1572 while (isspace(*s)) s++;
1573 ver = (int)strtol(s, &tmp, 0);
1575 if (s == tmp)
1576 exitfileerror(20, ".version expects an integer\n");
1578 s = tmp;
1579 while (isspace(*s)) s++;
1581 if (*s && *s != '#')
1582 exitfileerror(20, ".version has junk after the version number\n");
1584 minversion = ver;
1586 else if (strncmp(s, "unusedlibbase", 13) == 0)
1588 if (*funclistptr == NULL)
1589 exitfileerror(20, ".unusedlibbase has to come after a function declaration\n");
1590 (*funclistptr)->unusedlibbase = 1;
1592 else
1593 exitfileerror(20, "Syntax error");
1595 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1597 /* The line is a function or attribute prototype.
1598 * A function can have one of two syntaxes:
1599 * type funcname(argproto1, argproto2, ...)
1600 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1601 * The former is for C type function argument passing, the latter for
1602 * register argument passing.
1603 * An attribute has the following syntax:
1604 * type attribute
1606 char c, *args[64], *regs[64], *funcname, *cp;
1607 int len, argcount = 0, regcount = 0, brcount = 0;
1609 cp = strchr(line,'#');
1610 if (cp)
1611 *(cp++) = 0;
1613 /* Parse 'type functionname' at the beginning of the line */
1614 if (isattribute) {
1615 s = line + strlen(line);
1616 } else {
1617 s = strchr(line, '(');
1618 if (s == NULL)
1619 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1622 s2 = s;
1623 while (isspace(*(s2-1)))
1624 s2--;
1625 *s2 = '\0';
1627 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1628 s2--;
1630 if (s2 == line)
1631 exitfileerror(20, "No type specifier before %s name\n", isattribute ? "attribute" : "function");
1633 if (*funclistptr != NULL)
1634 funclistptr = &((*funclistptr)->next);
1635 *funclistptr = newfunctionhead(s2, STACK);
1637 if (cp)
1638 (*funclistptr)->comment = strdup(cp);
1639 else
1640 (*funclistptr)->comment = NULL;
1642 while (isspace(*(s2-1)))
1643 s2--;
1644 *s2 = '\0';
1645 (*funclistptr)->type = strdup(line);
1646 (*funclistptr)->lvo = lvo;
1647 (*funclistptr)->version = minversion;
1648 lvo++;
1650 if (isattribute)
1651 continue;
1653 /* Parse function prototype */
1654 s++;
1655 while (isspace(*s))
1656 s++;
1657 c = *s;
1659 while (c != ')')
1661 while (isspace(*s))
1662 s++;
1664 args[argcount] = s;
1665 argcount++;
1667 while
1669 *s != '\0'
1670 && !(brcount == 0 && (*s == ',' || *s == ')'))
1673 if (*s == '(')
1674 brcount++;
1675 if (*s == ')')
1677 if (brcount > 0)
1678 brcount--;
1679 else
1680 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1682 s++;
1685 c = *s;
1686 if (c == '\0')
1687 exitfileerror(20, "'(' without ')'");
1689 s2 = s;
1690 while (isspace(*(s2-1)))
1691 s2--;
1692 *s2 = '\0';
1694 if (!(s2 > args[argcount - 1]))
1695 exitfileerror(20, "Syntax error in function prototype\n");
1697 s++;
1700 s++;
1701 while (*s != '\0' && isspace(*s))
1702 s++;
1704 if (*s == '(')
1706 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1708 /* There may be no register specified with () so be sure then c is == ')' */
1709 s++;
1710 while(isspace(*s))
1711 s++;
1713 c = *s;
1715 while (c != ')')
1717 while (isspace(*s))
1718 s++;
1720 regs[regcount] = s;
1721 regcount++;
1723 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1725 s += 2;
1726 c = *s;
1727 if (c == '/')
1729 s++;
1730 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1732 s += 2;
1733 c = *s;
1735 else
1736 exitfileerror(20,
1737 "wrong register specification \"%s\" for argument %u\n",
1738 regs[regcount-1], regcount
1741 if (regcount > 4)
1742 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount, regs[regcount-1]);
1744 *s = '\0';
1746 else
1747 exitfileerror(20,
1748 "wrong register \"%s\" for argument %u\n",
1749 regs[regcount-1], regcount
1752 while (isspace(c))
1754 s++;
1755 c = *s;
1757 if (c == '\0')
1758 exitfileerror(20, "'(' without ')'\n");
1759 if (c != ',' && c != ')')
1760 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1762 s++;
1765 s++;
1766 while (isspace(*s)) s++;
1767 if (*s!='\0')
1768 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1770 if (argcount != regcount)
1771 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1772 argcount, regcount
1775 (*funclistptr)->libcall = REGISTERMACRO;
1776 for (i = 0; i < argcount; i++)
1777 funcaddarg(*funclistptr, args[i], regs[i]);
1779 else if (*s == '\0')
1780 { /* No registers specified */
1781 for (i = 0; i < argcount; i++)
1782 funcaddarg(*funclistptr, args[i], NULL);
1784 else
1785 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1790 static void readsectionclass_methodlist(struct classinfo *cl)
1792 int atend = 0, i;
1793 char *line, *s, *s2;
1794 struct functionhead **methlistptr = &cl->methlist;
1795 struct stringlist *interface = NULL;
1797 if (cl->basename==NULL)
1798 exitfileerror(20, "section methodlist has to come after section config\n");
1800 while (!atend)
1802 line = readline();
1803 if (line==NULL)
1804 exitfileerror(20, "unexptected EOF in methodlist section\n");
1806 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1807 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1808 continue;
1810 if (isspace(*line))
1811 exitfileerror(20, "No space allowed at start of the line\n");
1813 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1815 s = line+2;
1816 while (isspace(*s)) s++;
1817 if (strncmp(s, "end", 3)!=0)
1818 exitfileerror(20, "\"##end methodlist\" expected\n");
1820 s += 3;
1821 while (isspace(*s)) s++;
1822 if (strncmp(s, "methodlist", 10)!=0)
1823 exitfileerror(20, "\"##end methodlist\" expected\n");
1825 s += 10;
1826 while (isspace(*s)) s++;
1827 if (*s!='\0')
1828 exitfileerror(20, "unexpected character on position %d\n", s-line);
1830 atend = 1;
1832 continue;
1835 if (*line=='.')
1837 s = line+1;
1838 if (strncmp(s, "alias", 5)==0)
1840 s += 5;
1842 if (!isspace(*s))
1843 exitfileerror(20, "syntax is '.alias name'\n");
1845 while (isspace(*s)) s++;
1846 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1847 exitfileerror(20, "syntax is '.alias name'\n");
1849 s2 = s;
1850 s++;
1851 while (isalnum(*s) || *s == '_') s++;
1853 if (isspace(*s))
1855 *s = '\0';
1856 do {
1857 s++;
1858 } while (isspace(*s));
1861 if (*s != '\0')
1862 exitfileerror(20, "syntax is '.alias name'\n");
1864 if (*methlistptr == NULL)
1865 exitfileerror(20, ".alias has to come after a function declaration\n");
1867 slist_append(&(*methlistptr)->aliases, s2);
1869 else if (strncmp(s, "function", 8) == 0)
1871 s += 8;
1873 if (!isspace(*s))
1874 exitfileerror(20, "Syntax error\n");
1876 while (isspace(*s)) s++;
1877 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1878 exitfileerror(20, "syntax is '.function name'\n");
1880 s2 = s;
1881 s++;
1882 while (isalnum(*s) || *s == '_') s++;
1884 if (isspace(*s))
1886 *s = '\0';
1887 do {
1888 s++;
1889 } while (isspace(*s));
1892 if (*s != '\0')
1893 exitfileerror(20, "syntax is '.function name'\n");
1895 if (*methlistptr == NULL)
1896 exitfileerror(20, ".function has to come after a function declaration\n");
1898 funcsetinternalname(*methlistptr, s2);
1900 else if (strncmp(s, "interface", 9) == 0)
1902 if (cl->classtype != HIDD)
1903 exitfileerror(20, "interface only valid for a HIDD\n");
1905 s += 9;
1907 if (!isspace(*s))
1908 exitfileerror(20, "Syntax error\n");
1910 while (isspace(*s)) s++;
1911 if (*s == '\0' || !isalpha(*s))
1912 exitfileerror(20, "syntax is '.interface name'\n");
1914 s2 = s;
1915 s++;
1916 while (isalnum(*s) || *s == '_') s++;
1918 if (isspace(*s))
1920 *s = '\0';
1921 do {
1922 s++;
1923 } while (isspace(*s));
1926 if (*s != '\0')
1927 exitfileerror(20, "syntax is '.interface name'\n");
1929 interface = slist_append(&cl->interfaces, s2);
1931 else
1932 exitfileerror(20, "Syntax error");
1934 else if (isalpha(*line))
1936 char stmp[256];
1938 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
1941 if (cl->classtype == HIDD && interface == NULL)
1942 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
1944 if (*s != '\0')
1945 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
1947 if (*methlistptr != NULL)
1948 methlistptr = &((*methlistptr)->next);
1949 if (cl->classtype != HIDD)
1951 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
1952 exitfileerror(20, "Method name too large\n");
1954 *methlistptr = newfunctionhead(stmp, STACK);
1955 (*methlistptr)->type = "IPTR";
1956 funcaddarg(*methlistptr, "Class *cl", NULL);
1957 funcaddarg(*methlistptr, "Object *o", NULL);
1958 funcaddarg(*methlistptr, "Msg msg", NULL);
1960 else
1962 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
1963 exitfileerror(20, "Method name too large\n");
1965 *methlistptr = newfunctionhead(stmp, STACK);
1966 (*methlistptr)->type = "IPTR";
1967 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
1968 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
1969 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
1970 (*methlistptr)->interface = interface;
1971 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
1972 exitfileerror(20, "Method name too large\n");
1973 (*methlistptr)->method = strdup(stmp);
1975 slist_append(&(*methlistptr)->aliases, line);
1977 else
1978 exitfileerror(20, "Methodname has to begin with a letter\n");
1982 static void
1983 readsectioninterface(struct config *cfg)
1985 char *s;
1986 struct interfaceinfo *in;
1988 in = newinterface(cfg);
1989 s = readsections(cfg, NULL, in, 1);
1990 if (s == NULL)
1991 exitfileerror(20, "Unexpected end of file\n");
1993 if (strncmp(s, "##", 2) != 0)
1994 exitfileerror(20, "'##end interface' expected\n");
1995 s += 2;
1997 while (isspace(*s)) s++;
1999 if (strncmp(s, "end", 3) != 0)
2000 exitfileerror(20, "'##end interface' expected\n");
2001 s += 3;
2003 if (!isspace(*s))
2004 exitfileerror(20, "'##end interface' expected\n");
2005 while (isspace(*s)) s++;
2007 if (strncmp(s, "interface", 9) != 0)
2008 exitfileerror(20, "'##end interface' expected\n");
2009 s += 9;
2011 while (isspace(*s)) s++;
2012 if (*s != '\0')
2013 exitfileerror(20, "'##end interface' expected\n");
2015 if (!in->interfaceid)
2016 exitfileerror(20, "interface has no 'interfaceid' defined!\n");
2018 if (!in->interfacename)
2019 exitfileerror(20, "interface has no 'interfacename' defined!\n");
2021 if (!in->methodstub)
2022 in->methodstub = strdup(in->interfacename);
2024 if (!in->methodbase) {
2025 int len = strlen(in->interfacename);
2026 in->methodbase = malloc(len + 4 + 1);
2027 strcpy(in->methodbase, in->interfacename);
2028 strcat(in->methodbase, "Base");
2031 if (!in->attributebase) {
2032 int len = strlen(in->interfacename);
2033 in->attributebase = malloc(len + 4 + 4 + 1);
2034 strcpy(in->attributebase, in->interfacename);
2035 strcat(in->attributebase, "AttrBase");
2039 static void
2040 readsectionclass(struct config *cfg)
2042 char *s;
2043 struct classinfo *cl;
2045 cl = newclass(cfg);
2046 s = readsections(cfg, cl, NULL, 1);
2047 if (s == NULL)
2048 exitfileerror(20, "Unexpected end of file\n");
2050 if (strncmp(s, "##", 2) != 0)
2051 exitfileerror(20, "'##end class' expected\n");
2052 s += 2;
2054 while (isspace(*s)) s++;
2056 if (strncmp(s, "end", 3) != 0)
2057 exitfileerror(20, "'##end class' expected\n");
2058 s += 3;
2060 if (!isspace(*s))
2061 exitfileerror(20, "'##end class' expected\n");
2062 while (isspace(*s)) s++;
2064 if (strncmp(s, "class", 5) != 0)
2065 exitfileerror(20, "'##end class' expected\n");
2066 s += 5;
2068 while (isspace(*s)) s++;
2069 if (*s != '\0')
2070 exitfileerror(20, "'##end class' expected\n");
2073 static struct classinfo *newclass(struct config *cfg)
2075 struct classinfo *cl, *classlistit;
2077 cl = malloc(sizeof(struct classinfo));
2078 if (cl == NULL)
2080 fprintf(stderr, "Out of memory\n");
2081 exit(20);
2083 memset(cl, 0, sizeof(struct classinfo));
2085 /* By default the classes are initialized with a priority of 1 so they
2086 * are initialized before any user added initialization with priority 1
2088 cl->initpri = 1;
2090 if (cfg->classlist == NULL)
2091 cfg->classlist = cl;
2092 else
2096 classlistit = cfg->classlist;
2097 classlistit->next != NULL;
2098 classlistit = classlistit->next
2101 classlistit->next = cl;
2104 return cl;
2107 static struct handlerinfo *newhandler(struct config *cfg)
2109 struct handlerinfo *hl;
2111 hl = calloc(1,sizeof(*hl));
2112 hl->next = cfg->handlerlist;
2113 cfg->handlerlist = hl;
2114 return hl;
2117 static struct interfaceinfo *newinterface(struct config *cfg)
2119 struct interfaceinfo *in, *interfacelistit;
2121 in = malloc(sizeof(struct interfaceinfo));
2122 if (in == NULL)
2124 fprintf(stderr, "Out of memory\n");
2125 exit(20);
2127 memset(in, 0, sizeof(struct interfaceinfo));
2129 if (cfg->interfacelist == NULL)
2130 cfg->interfacelist = in;
2131 else
2135 interfacelistit = cfg->interfacelist;
2136 interfacelistit->next != NULL;
2137 interfacelistit = interfacelistit->next
2140 interfacelistit->next = in;
2143 return in;
2147 static int getdirective(char *s, const char *directive, int range_min, int range_max, int *val)
2149 char *tmp;
2150 int newval;
2152 if (strncmp(s, directive, strlen(directive)) != 0)
2153 return 0;
2155 s += strlen(directive);
2156 if (*s && !isspace(*s))
2157 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive);
2159 while (isspace(*s)) s++;
2160 if (!*s)
2161 exitfileerror(20, "No .%s value specified\n", directive);
2163 newval = strtol(s, &tmp, 0);
2164 if (s == tmp || !(newval >= range_min && newval <= range_max)) {
2165 tmp = s;
2166 while (*tmp && !isspace(*tmp)) tmp++;
2167 exitfileerror(20, "Invalid .%s value of %.*s\n", directive, tmp - s, s);
2170 *val = newval;
2171 return 1;
2174 static void
2175 readsectionhandler(struct config *cfg)
2177 char *line = NULL, *s;
2178 struct handlerinfo *hl;
2179 unsigned char autolevel = 0;
2180 unsigned int stacksize = 0;
2181 int startup = 0;
2182 char priority = 10;
2183 int bootpri = -128;
2184 int has_filesystem = 0;
2186 for (;;)
2188 char *function;
2189 int function_len;
2190 char *tmp;
2192 s = line = readline();
2194 if (s==NULL)
2195 exitfileerror(20, "unexpected end of file in section hanlder\n");
2197 if (strncmp(s, "##", 2)==0)
2198 break;
2200 /* Ignore comments */
2201 if (strncmp(s, "#", 1)==0)
2202 continue;
2204 /* Skip ahead to function name */
2205 while (*s && isspace(*s)) s++;
2207 /* Permit blank lines */
2208 if (!*s)
2209 continue;
2211 if (*s == '.') {
2212 int val;
2213 s++;
2215 if (getdirective(s, "autodetect", 0, 127, &val)) {
2216 autolevel = val;
2217 } else if (getdirective(s, "stacksize", 0, INT_MAX, &val)) {
2218 stacksize = val;
2219 } else if (getdirective(s, "priority", -128, 127, &val)) {
2220 priority = val;
2221 } else if (getdirective(s, "bootpri", -128, 127, &val)) {
2222 bootpri = val;
2223 } else if (getdirective(s, "startup", INT_MIN, INT_MAX, &val)) {
2224 startup = val;
2225 } else {
2226 exitfileerror(20, "Unrecognized directive \"%s\"\n", line);
2228 continue;
2231 do {
2232 unsigned int id = 0;
2234 if (strncasecmp(s,"resident=",9)==0) {
2235 char *res;
2237 s = strchr(s, '=') + 1;
2238 res = s;
2239 while (*s && !isspace(*s)) s++;
2240 if (res == s)
2241 exitfileerror(20, "Empty resident= is not permitted\n");
2243 if (*s)
2244 *(s++) = 0;
2246 hl = newhandler(cfg);
2247 hl->type = HANDLER_RESIDENT;
2248 hl->id = 0;
2249 hl->name = strdup(res);
2250 hl->autodetect = autolevel--;
2251 hl->stacksize = stacksize;
2252 hl->priority = priority;
2253 hl->startup = startup;
2254 } else if (strncasecmp(s,"dosnode=",8)==0) {
2255 char *dev;
2257 s = strchr(s, '=') + 1;
2258 dev = s;
2259 while (*s && !isspace(*s)) s++;
2260 if (dev == s)
2261 exitfileerror(20, "Empty dosnode= is not permitted\n");
2263 if (*s)
2264 *(s++) = 0;
2266 hl = newhandler(cfg);
2267 hl->type = HANDLER_DOSNODE;
2268 hl->id = 0;
2269 hl->name = strdup(dev);
2270 hl->autodetect = autolevel ? autolevel-- : 0;
2271 hl->stacksize = stacksize;
2272 hl->priority = priority;
2273 hl->startup = startup;
2274 hl->bootpri = bootpri;
2275 } else if (strncasecmp(s,"dostype=",8) == 0) {
2276 s = strchr(s, '=') + 1;
2278 id = (unsigned int)strtoul(s, &tmp, 0);
2280 if (s == tmp) {
2281 while (*tmp && !isspace(*tmp))
2282 tmp++;
2283 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp -s), s);
2285 s = tmp;
2287 if (id == 0 || id == ~0) {
2288 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id);
2291 hl = newhandler(cfg);
2292 hl->type = HANDLER_DOSTYPE;
2293 hl->id = id;
2294 hl->name = NULL;
2295 hl->autodetect = autolevel ? autolevel-- : 0;
2296 hl->stacksize = stacksize;
2297 hl->priority = priority;
2298 hl->startup = startup;
2299 } else {
2300 for (tmp = s; !isspace(*tmp); tmp++);
2301 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp - s, s);
2304 /* Advance to next ID */
2305 while (*s && isspace(*s)) s++;
2307 } while (*s);
2310 if (s == NULL)
2311 exitfileerror(20, "Unexpected end of file\n");
2313 if (strncmp(s, "##", 2) != 0)
2314 exitfileerror(20, "'##end handler' expected\n");
2315 s += 2;
2317 while (isspace(*s)) s++;
2319 if (strncmp(s, "end", 3) != 0)
2320 exitfileerror(20, "'##end handler' expected\n");
2321 s += 3;
2323 while (isspace(*s)) s++;
2325 if (strncmp(s, "handler", 7) != 0)
2326 exitfileerror(20, "'##end handler' expected\n");
2327 s += 7;
2329 while (isspace(*s)) s++;
2330 if (*s != '\0')
2331 exitfileerror(20, "'##end handler' expected\n");