enable the new framebuffer resizing code.
[AROS.git] / tools / genmodule / config.c
blob512a1fb16f91e2887463fb69bd136fda612f5064
1 /*
2 Copyright © 1995-2019, 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 \xA9 1995-%4u, The AROS Development Team. All rights reserved.\n"
24 "*/\n";
26 char*
27 getBanner(struct config* config)
29 static unsigned currentyear = 0;
31 int bannerlength = strlen(config->conffile) + strlen(bannertemplate);
32 // No additional bytes needed because
33 // + 1 (NUL) + 4 (4 digit year) - strlen("%s") - strlen("%4u) = 0
35 char * banner = malloc(bannerlength);
37 if (currentyear == 0)
39 time_t rawtime;
40 time(&rawtime);
41 struct tm *utctm = gmtime(&rawtime);
42 currentyear = utctm->tm_year + 1900;
45 snprintf (banner, bannerlength, bannertemplate, config->conffile, currentyear);
47 return(banner);
50 void
51 freeBanner(char *banner)
53 free((void *)banner);
56 const static char usage[] =
57 "\n"
58 "Usage: genmodule [-c conffile] [-o configoverridefile] [-s suffix] [-d gendir] [-l library-stub gendir] [-f flavour] [-v versionextra]\n"
59 " {writefiles|writemakefile|writeincludes|writelibdefs|writefunclist|writefd|writeskel|writethunk} modname modtype\n"
62 static void readconfig(struct config *);
63 static struct classinfo *newclass(struct config *);
64 static struct handlerinfo *newhandler(struct config *);
65 static struct interfaceinfo *newinterface(struct config *);
67 /* the method prefices for the supported classes */
68 static const char *muimprefix[] =
70 "__OM_",
71 "__MUIM_",
72 NULL
74 static const char *gadgetmprefix[] =
76 "__OM_",
77 "__GM_",
78 "__AROSM_",
79 NULL
81 static const char *dtmprefix[] =
83 "__OM_",
84 "__GM_",
85 "__DTM_",
86 "__PDTM_",
87 NULL
90 /* Create a config struct. Initialize with the values from the programs command
91 * line arguments and the contents of the modules .conf file
93 struct config *initconfig(int argc, char **argv)
95 struct config *cfg;
96 char *s, **argvit = argv + 1;
97 int hassuffix = 0, c;
99 cfg = malloc(sizeof(struct config));
100 if (cfg == NULL)
102 fprintf(stderr, "Out of memory\n");
103 exit(20);
106 memset(cfg, 0, sizeof(struct config));
108 while ((c = getopt(argc, argv, ":c:o:s:d:l:f:v:")) != -1)
110 if (c == ':')
112 fprintf(stderr, "Option -%c needs an argument\n",optopt);
113 exit(20);
116 switch (c)
118 case 'c':
119 cfg->conffile = optarg;
120 break;
122 case 'o':
123 cfg->confoverridefile = optarg;
124 break;
126 case 's':
127 cfg->suffix = optarg;
128 hassuffix = 1;
129 break;
131 case 'd':
132 /* Remove / at end if present */
133 if ((optarg)[strlen(*argvit)-1]=='/') (optarg)[strlen(optarg)-1]='\0';
134 cfg->gendir = optarg;
135 break;
137 case 'l':
138 /* Remove / at end if present */
139 if ((optarg)[strlen(*argvit)-1]=='/') (optarg)[strlen(optarg)-1]='\0';
140 cfg->libgendir = optarg;
141 break;
143 case 'f':
144 cfg->flavour = optarg;
145 break;
147 case 'v':
148 cfg->versionextra = optarg;
149 break;
151 default:
152 fprintf(stderr, "Internal error: Unhandled option\n");
153 exit(20);
157 if (optind + 3 != argc)
159 fprintf(stderr, "Wrong number of arguments.\n%s", usage);
160 exit(20);
163 if (strcmp(argv[optind], "writefiles") == 0)
165 cfg->command = FILES;
167 else if (strcmp(argv[optind], "writemakefile") == 0)
169 cfg->command = MAKEFILE;
171 else if (strcmp(argv[optind], "writeincludes") == 0)
173 cfg->command = INCLUDES;
175 else if (strcmp(argv[optind], "writelibdefs") == 0)
177 cfg->command = LIBDEFS;
179 else if (strcmp(argv[optind], "writefunclist") == 0)
181 cfg->command = WRITEFUNCLIST;
183 else if (strcmp(argv[optind], "writefd") == 0)
185 cfg->command = WRITEFD;
187 else if (strcmp(argv[optind], "writeskel") == 0)
189 cfg->command = WRITESKEL;
191 else if (strcmp(argv[optind], "writethunk") == 0)
193 cfg->command = WRITETHUNK;
195 else
197 fprintf(stderr, "Unrecognized argument \"%s\"\n%s", argv[optind], usage);
198 exit(20);
202 cfg->modulename = argv[optind+1];
203 cfg->modulenameupper = strdup(cfg->modulename);
204 for (s=cfg->modulenameupper; *s!='\0'; *s = toupper(*s), s++) {
205 if (!isalnum(*s)) *s = '_';
208 if (strcmp(argv[optind+2],"library")==0)
210 cfg->modtype = LIBRARY;
211 cfg->moddir = "Libs";
213 else if (strcmp(argv[optind+2],"mcc")==0)
215 cfg->modtype = MCC;
216 cfg->moddir = "Classes/Zune";
218 else if (strcmp(argv[optind+2],"mui")==0)
220 cfg->modtype = MUI;
221 cfg->moddir = "Classes/Zune";
223 else if (strcmp(argv[optind+2],"mcp")==0)
225 cfg->modtype = MCP;
226 cfg->moddir = "Classes/Zune";
228 else if (strcmp(argv[optind+2], "device")==0)
230 cfg->modtype = DEVICE;
231 cfg->moddir = "Devs";
233 else if (strcmp(argv[optind+2], "resource")==0)
235 cfg->modtype = RESOURCE;
236 cfg->moddir = "Devs";
238 else if (strcmp(argv[optind+2], "gadget")==0)
240 cfg->modtype = GADGET;
241 cfg->moddir = "Classes/Gadgets";
243 else if (strcmp(argv[optind+2], "datatype")==0)
245 cfg->modtype = DATATYPE;
246 cfg->moddir = "Classes/DataTypes";
248 else if (strcmp(argv[optind+2], "usbclass")==0)
250 cfg->modtype = USBCLASS;
251 cfg->moddir = "Classes/USB";
252 if(!hassuffix)
254 cfg->suffix = "class";
255 hassuffix = 1;
258 else if (strcmp(argv[optind+2], "hidd")==0)
260 cfg->modtype = HIDD;
261 cfg->moddir = "Devs/Drivers";
263 else if (strcmp(argv[optind+2], "handler")==0)
265 cfg->modtype = HANDLER;
266 cfg->moddir = "$(AROS_DIR_FS)";
268 else if (strcmp(argv[optind+2], "hook")==0)
270 cfg->modtype = HANDLER;
271 cfg->moddir = "Devs";
273 else
275 fprintf(stderr, "Unknown modtype \"%s\" specified for second argument\n", argv[optind+2]);
276 exit(20);
278 cfg->modtypestr = argv[optind+2];
280 if (!hassuffix)
281 cfg->suffix = argv[optind+2];
283 /* Fill fields with default value if not specified on the command line */
285 char tmpbuf[256];
287 if (cfg->conffile == NULL)
289 snprintf(tmpbuf, sizeof(tmpbuf), "%s.conf", cfg->modulename);
290 cfg->conffile = strdup(tmpbuf);
293 if (cfg->gendir == NULL)
294 cfg->gendir = ".";
296 if (cfg->libgendir == NULL)
297 cfg->libgendir = cfg->gendir;
300 readconfig(cfg);
302 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
303 * if they are provided
305 if (cfg->beginiofunc != NULL)
307 struct functionhead *funchead;
309 cfg->intcfg |= CFG_NOREADFUNCS;
311 /* Add beginio_func to the list of functions */
312 funchead = newfunctionhead(cfg->beginiofunc, REGISTERMACRO);
313 funchead->type = strdup("void");
314 funchead->lvo = 5;
315 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
317 funchead->next = cfg->funclist;
318 cfg->funclist = funchead;
320 /* Add abortio_func to the list of functions */
321 funchead = newfunctionhead(cfg->abortiofunc, REGISTERMACRO);
322 funchead->type = strdup("LONG");
323 funchead->lvo = 6;
324 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
326 funchead->next = cfg->funclist->next;
327 cfg->funclist->next = funchead;
329 else if (cfg->modtype == DEVICE && cfg->intcfg & CFG_NOREADFUNCS)
331 fprintf
333 stderr,
334 "beginio_func and abortio_func missing for a device with a non empty function list\n"
336 exit(20);
339 /* See if we have any stackcall options */
340 if (cfg->funclist) {
341 struct functionhead *funchead;
343 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
344 if (funchead->libcall == STACK) {
345 cfg->options |= OPTION_STACKCALL;
346 break;
351 /* Provide default version for functions that didnt have it */
352 if (cfg->funclist) {
353 struct functionhead *funchead;
354 int defversion = cfg->majorversion; /* Assume library version is default */
356 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
357 if (funchead->version > -1) {
358 /* There was at least one .version tag. Assume 0 is default */
359 defversion = 0;
360 break;
364 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
365 if (funchead->version == -1) {
366 funchead->version = defversion;
371 /* Verify that a handler has a handler */
372 if (cfg->modtype == HANDLER) {
373 if (cfg->handlerfunc == NULL) {
374 fprintf(stderr, "handler modules require a 'handler_func' ##config option\n");
375 exit(20);
377 cfg->options |= OPTION_NOAUTOLIB | OPTION_NOEXPUNGE | OPTION_NOOPENCLOSE;
380 return cfg;
383 /* Functions to read configuration from the configuration file */
385 #include "fileread.h"
387 static char *readsections(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass, int inoverride);
388 static void readsectionconfig(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass, int inoverride);
389 static void readsectioncdef(struct config *);
390 static void readsectioncdefprivate(struct config *);
391 static void readsectionstubprivate(struct config *);
392 static void readsectionstartup(struct config *);
393 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall);
394 static void readsectionclass_methodlist(struct classinfo *);
395 static void readsectionclass(struct config *);
396 static void readsectionhandler(struct config *);
397 static void readsectioninterface(struct config *);
399 static void readconfig(struct config *cfg)
401 struct classinfo *mainclass = NULL;
403 /* Create a classinfo structure if this module is a class */
404 switch (cfg->modtype)
406 case LIBRARY:
407 case DEVICE:
408 case RESOURCE:
409 case USBCLASS:
410 case HANDLER:
411 break;
413 case MCC:
414 case MUI:
415 case MCP:
416 case GADGET:
417 case DATATYPE:
418 case HIDD:
419 mainclass = newclass(cfg);
420 mainclass->classtype = cfg->modtype;
421 break;
423 default:
424 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
425 exit(20);
428 switch (cfg->modtype)
430 case LIBRARY:
431 case USBCLASS:
432 cfg->firstlvo = 5;
433 break;
434 case DEVICE:
435 cfg->firstlvo = 7;
436 break;
437 case MCC:
438 case MUI:
439 case MCP:
440 cfg->firstlvo = 6;
441 mainclass->boopsimprefix = muimprefix;
442 break;
443 case HANDLER:
444 case RESOURCE:
445 cfg->firstlvo = 1;
446 break;
447 case GADGET:
448 cfg->firstlvo = 5;
449 mainclass->boopsimprefix = gadgetmprefix;
450 break;
451 case DATATYPE:
452 cfg->firstlvo = 6;
453 mainclass->boopsimprefix = dtmprefix;
454 break;
455 case HIDD:
456 cfg->firstlvo = 5;
457 /* FIXME: need boopsimprefix ? */
458 break;
459 default:
460 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
461 exit(20);
464 if (!fileopen(cfg->conffile))
466 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
467 exit(20);
470 /* Read all sections and see that we are at the end of the file */
471 if (readsections(cfg, mainclass, NULL, 0, 0) != NULL)
472 exitfileerror(20, "Syntax error");
474 fileclose();
477 /* readsections will scan through all the sections in the config file.
478 * arguments:
479 * struct config *cfg: The module config data which may be updated by
480 * the information in the sections
481 * struct classinfo *cl: The classdata to be filled with data from the sections.
482 * This may be NULL if this is the main part of the configuration file and the
483 * type of the module is not a class
484 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
485 * part of the config file.
487 static char *readsections(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass, int inoverride)
489 char *line, *s, *s2;
490 int hasconfig = 0;
492 while ((line=readline())!=NULL)
494 if (strncmp(line, "##", 2)==0)
496 static char *parts[] =
498 "config", "cdefprivate", "cdef", "stubprivate", "startup", "functionlist", "methodlist", "class", "handler", "interface", "attributelist", "cfunctionlist"
500 const unsigned int nums = sizeof(parts)/sizeof(char *);
501 unsigned int partnum;
502 int i, atend = 0;
504 s = line+2;
505 while (isspace(*s)) s++;
507 if (strncmp(s, "begin", 5)!=0)
508 return line;
510 s += 5;
511 if (!isspace(*s))
512 exitfileerror(20, "space after begin expected\n");
513 while (isspace(*s)) s++;
515 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
517 if (strncmp(s, parts[i], strlen(parts[i]))==0)
519 partnum = i+1;
520 s += strlen(parts[i]);
521 while (isspace(*s)) s++;
522 if (*s!='\0')
523 exitfileerror(20, "unexpected character on position %d\n", s-line);
526 if (partnum==0)
527 exitfileerror(20, "unknown start of section\n");
528 switch (partnum)
530 case 1: /* config */
531 readsectionconfig(cfg, cl, in, inclass, inoverride);
532 hasconfig = 1;
533 break;
535 case 2: /* cdefprivate */
536 if (inclass)
537 exitfileerror(20, "cdefprivate section not allowed in class section\n");
538 readsectioncdefprivate(cfg);
539 break;
541 case 3: /* cdef */
542 if (inclass)
543 exitfileerror(20, "cdef section not allowed in class section\n");
544 readsectioncdef(cfg);
545 break;
547 case 4: /* stubprivate */
548 if (inclass)
549 exitfileerror(20, "stubprivate section not allowed in class section\n");
550 readsectionstubprivate(cfg);
551 break;
553 case 5: /* startup */
554 if (inclass)
555 exitfileerror(20, "startup section not allowed in class section\n");
556 readsectionstartup(cfg);
557 break;
559 case 6: /* functionlist */
560 if (inclass)
561 exitfileerror(20, "functionlist section not allow in class section\n");
562 if (cfg->basename==NULL)
563 exitfileerror(20, "section functionlist has to come after section config\n");
565 readsectionfunctionlist("functionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTERMACRO);
566 cfg->intcfg |= CFG_NOREADFUNCS;
567 break;
569 case 7: /* methodlist */
570 if (cl == NULL && in == NULL)
571 exitfileerror(20, "methodlist section when not in a class or interface\n");
572 if (cl)
573 readsectionclass_methodlist(cl);
574 else
575 readsectionfunctionlist("methodlist", &in->methodlist, 0, 0, REGISTERMACRO);
576 cfg->intcfg |= CFG_NOREADFUNCS;
577 break;
579 case 8: /* class */
580 if (inclass)
581 exitfileerror(20, "class section may not be in nested\n");
582 readsectionclass(cfg);
583 break;
585 case 9: /* handler */
586 readsectionhandler(cfg);
587 break;
589 case 10: /* interface */
590 if (inclass)
591 exitfileerror(20, "interface section may not be nested\n");
592 readsectioninterface(cfg);
593 break;
595 case 11: /* attributelist */
596 if (!in)
597 exitfileerror(20, "attributelist only valid in interface sections\n");
598 readsectionfunctionlist("attributelist", &in->attributelist, 0, 1, INVALID);
599 break;
601 case 12: /* cfunctionlist */
602 if (inclass)
603 exitfileerror(20, "cfunctionlist section not allow in class section\n");
604 if (cfg->basename==NULL)
605 exitfileerror(20, "section cfunctionlist has to come after section config\n");
607 readsectionfunctionlist("cfunctionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTER);
608 cfg->intcfg |= CFG_NOREADFUNCS;
609 break;
612 else if (strlen(line)!=0)
613 filewarning("warning line outside section ignored\n");
616 if(!inclass)
618 if (!hasconfig)
619 exitfileerror(20, "No config section in conffile\n");
621 /* If no indication was given for generating includes or not
622 decide on module type and if there are functions
624 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
626 switch (cfg->modtype)
628 case LIBRARY:
629 case RESOURCE:
630 cfg->options |= OPTION_INCLUDES;
631 break;
633 case HANDLER:
634 case MCC:
635 case MUI:
636 case MCP:
637 case USBCLASS:
638 cfg->options |= OPTION_NOINCLUDES;
639 break;
641 case DEVICE:
642 cfg->options |= (
643 (cfg->funclist != NULL)
644 || (cfg->cdeflines != NULL)
645 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
646 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
647 break;
649 case GADGET:
650 case DATATYPE:
651 case HIDD:
652 cfg->options |= (
653 (cfg->funclist != NULL)
654 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
655 break;
657 default:
658 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
659 exit(20);
660 break;
664 /* If no indication was given for not generating stubs only generate them if
665 * the module has functions
667 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
669 switch (cfg->modtype)
671 case LIBRARY:
672 cfg->options |= (cfg->funclist != NULL) ? OPTION_STUBS : OPTION_NOSTUBS;
673 break;
675 case USBCLASS:
676 case RESOURCE:
677 case GADGET:
678 case DEVICE:
679 case DATATYPE:
680 case MCC:
681 case MUI:
682 case MCP:
683 case HIDD:
684 case HANDLER:
685 cfg->options |= OPTION_NOSTUBS;
686 break;
688 default:
689 fprintf(stderr, "Internal error writemakefile: unhandled modtype for stubs\n");
690 exit(20);
691 break;
695 /* If no indication was given for generating autoinit code or not
696 decide on module type
698 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
700 switch (cfg->modtype)
702 case LIBRARY:
703 cfg->options |= OPTION_AUTOINIT;
704 break;
706 case USBCLASS:
707 case RESOURCE:
708 case GADGET:
709 case DEVICE:
710 case DATATYPE:
711 case MCC:
712 case MUI:
713 case MCP:
714 case HIDD:
715 case HANDLER:
716 cfg->options |= OPTION_NOAUTOINIT;
717 break;
719 default:
720 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
721 exit(20);
722 break;
726 if ((cfg->modtype == RESOURCE) || (cfg->modtype == HANDLER))
727 /* Enforce noopenclose for resources and handlers */
728 cfg->options |= OPTION_NOOPENCLOSE;
729 else if (!(cfg->options & OPTION_SELFINIT))
730 /* Enforce using RTF_AUTOINIT for everything except resources */
731 cfg->options |= OPTION_RESAUTOINIT;
734 return NULL;
737 static void readsectionconfig(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass, int inoverride)
739 int atend = 0, i;
740 char *line, *s, *s2, *libbasetypeextern = NULL;
741 struct tm date;
743 while (!atend)
745 line = readline();
746 if (line==NULL)
747 exitfileerror(20, "unexpected end of file in section config\n");
749 if (strncmp(line, "##", 2)!=0)
751 const char *names[] =
753 "basename", "libbase", "libbasetype", "libbasetypeextern",
754 "version", "date", "copyright", "libcall", "forcebase", "superclass",
755 "superclass_field", "residentpri", "options", "sysbase_field",
756 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
757 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
758 "initpri", "type", "addromtag", "oopbase_field",
759 "rellib", "interfaceid", "interfacename",
760 "methodstub", "methodbase", "attributebase", "handler_func",
761 "includename"
763 const unsigned int namenums = sizeof(names)/sizeof(char *);
764 unsigned int namenum;
766 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
770 strncmp(line, names[i], strlen(names[i]))==0
771 && isspace(*(line+strlen(names[i])))
773 namenum = i+1;
775 if (namenum==0)
776 exitfileerror(20, "unrecognized configuration option\n");
778 s = line + strlen(names[namenum-1]);
779 if (!isspace(*s))
780 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
782 while (isspace(*s)) s++;
783 if (*s=='\0')
784 exitfileerror(20, "unexpected end of line\n");
786 s2 = s + strlen(s);
787 while (isspace(*(s2-1))) s2--;
788 *s2 = '\0';
790 switch (namenum)
792 case 1: /* basename */
793 if (!inclass)
794 cfg->basename = strdup(s);
795 if (cl != NULL)
796 cl->basename = strdup(s);
797 if (in != NULL)
798 exitfileerror(20, "basename not valid config option when in an interface section\n");
799 break;
801 case 2: /* libbase */
802 if (inclass)
803 exitfileerror(20, "libbase not valid config option when in a class section\n");
804 cfg->libbase = strdup(s);
805 break;
807 case 3: /* libbasetype */
808 if (inclass)
809 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
810 cfg->libbasetype = strdup(s);
811 break;
813 case 4: /* libbasetypeextern */
814 if (inclass)
815 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
816 libbasetypeextern = strdup(s);
817 break;
819 case 5: /* version */
820 if (inclass)
821 exitfileerror(20, "version not valid config option when in a class section\n");
822 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
823 exitfileerror(20, "wrong version string \"%s\"\n", s);
824 break;
826 case 6: /* date */
827 if (inclass)
828 exitfileerror(20, "date not valid config option when in a class section\n");
829 #ifndef _WIN32
830 if (strptime(s, "%e.%m.%Y", &date) == NULL)
832 exitfileerror(20, "date string has to have d.m.yyyy format\n");
834 #endif
835 cfg->datestring = strdup(s);
836 break;
838 case 7: /* copyright */
839 if (inclass)
840 exitfileerror(20, "copyright not valid config option when in a class section\n");
841 cfg->copyright = strdup(s);
842 break;
844 case 8: /* libcall */
845 fprintf(stderr, "libcall specification is deprecated and ignored\n");
846 break;
848 case 9: /* forcebase */
849 if (inclass)
850 exitfileerror(20, "forcebase not valid config option when in a class section\n");
851 slist_append(&cfg->forcelist, s);
852 break;
854 case 10: /* superclass */
855 if (cl == NULL)
856 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
857 cl->superclass = strdup(s);
858 break;
860 case 11: /* superclass_field */
861 if (cl == NULL)
862 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
863 cl->superclass_field = strdup(s);
864 break;
866 case 12: /* residentpri */
867 if (!inclass)
869 int count;
870 char dummy;
872 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
873 if (count != 1 ||
874 cfg->residentpri < -128 || cfg->residentpri > 127
877 exitfileerror(20, "residentpri number format error\n");
880 else
881 exitfileerror(20, "residentpri not valid config option when in a class section\n");
882 break;
884 case 13: /* options */
885 if (!inclass)
887 static const char *optionnames[] =
889 "noautolib", "noexpunge", "noresident", "peropenerbase",
890 "pertaskbase", "includes", "noincludes", "nostubs",
891 "autoinit", "noautoinit", "resautoinit", "noopenclose",
892 "selfinit", "rellinklib"
894 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
895 int optionnum;
899 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
901 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
903 optionnum = i + 1;
904 s += strlen(optionnames[i]);
905 while (isspace(*s)) s++;
906 if (*s == ',')
907 s++;
908 else if (*s != '\0')
909 exitfileerror(20, "Unrecognized option\n");
912 if (optionnum == 0)
913 exitfileerror(20, "Unrecognized option\n");
914 switch (optionnum)
916 case 1: /* noautolib */
917 cfg->options |= OPTION_NOAUTOLIB;
918 break;
919 case 2: /* noexpunge */
920 cfg->options |= OPTION_NOEXPUNGE;
921 break;
922 case 3: /* noresident */
923 cfg->options |= OPTION_NORESIDENT;
924 cfg->firstlvo = 1;
925 break;
926 case 5: /* pertaskbase */
927 cfg->options |= OPTION_PERTASKBASE;
928 /* Fall through */
929 case 4: /* peropenerbase */
930 if (cfg->options & OPTION_DUPBASE)
931 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
932 cfg->options |= OPTION_DUPBASE;
933 break;
934 case 6: /* includes */
935 if (cfg->options & OPTION_NOINCLUDES)
936 exitfileerror(20, "option includes and noincludes are incompatible\n");
937 cfg->options |= OPTION_INCLUDES;
938 break;
939 case 7: /* noincludes */
940 if (cfg->options & OPTION_INCLUDES)
941 exitfileerror(20, "option includes and noincludes are incompatible\n");
942 cfg->options |= OPTION_NOINCLUDES;
943 break;
944 case 8: /* nostubs */
945 cfg->options |= OPTION_NOSTUBS;
946 break;
947 case 9: /* autoinit */
948 if (cfg->options & OPTION_NOAUTOINIT)
949 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
950 cfg->options |= OPTION_AUTOINIT;
951 break;
952 case 10: /* noautoinit */
953 if (cfg->options & OPTION_AUTOINIT)
954 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
955 cfg->options |= OPTION_NOAUTOINIT;
956 break;
957 case 11: /* resautoinit */
958 if (cfg->options & OPTION_SELFINIT)
959 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
960 cfg->options |= OPTION_RESAUTOINIT;
961 break;
962 case 12:
963 cfg->options |= OPTION_NOOPENCLOSE;
964 break;
965 case 13: /* noresautoinit */
966 if (cfg->options & OPTION_RESAUTOINIT)
967 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
968 cfg->options |= OPTION_SELFINIT;
969 break;
970 case 14: /* rellinklib */
971 cfg->options |= OPTION_RELLINKLIB;
972 break;
974 while (isspace(*s)) s++;
975 } while(*s !='\0');
977 else
979 static const char *optionnames[] =
981 "private"
983 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
984 int optionnum;
988 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
990 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
992 optionnum = i + 1;
993 s += strlen(optionnames[i]);
994 while (isspace(*s)) s++;
995 if (*s == ',')
996 s++;
997 else if (*s != '\0')
998 exitfileerror(20, "Unrecognized option\n");
1001 if (optionnum == 0)
1002 exitfileerror(20, "Unrecognized option\n");
1003 switch (optionnum)
1005 case 1: /* private */
1006 cl->options |= COPTION_PRIVATE;
1007 break;
1009 while (isspace(*s)) s++;
1010 } while(*s !='\0');
1012 break;
1014 case 14: /* sysbase_field */
1015 if (inclass)
1016 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
1017 cfg->sysbase_field = strdup(s);
1018 break;
1020 case 15: /* seglist_field */
1021 if (inclass)
1022 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
1023 cfg->seglist_field = strdup(s);
1024 break;
1026 case 16: /* rootbase_field */
1027 if (inclass)
1028 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
1029 cfg->rootbase_field = strdup(s);
1030 break;
1032 case 17: /* classptr_field */
1033 if (cl == NULL)
1035 exitfileerror
1038 "classptr_field specified when not a BOOPSI class\n"
1041 cl->classptr_field = strdup(s);
1042 break;
1044 case 18: /* classptr_var */
1045 if (cl == NULL)
1047 exitfileerror
1050 "classptr_var specified when not a BOOPSI class\n"
1053 cl->classptr_var = strdup(s);
1054 break;
1056 case 19: /* classid */
1057 if (cl == NULL)
1058 exitfileerror(20, "classid specified when not a BOOPSI class\n");
1059 if (cl->classid != NULL)
1060 exitfileerror(20, "classid specified twice\n");
1061 cl->classid = strdup(s);
1062 if (strcmp(cl->classid, "NULL") == 0)
1063 cl->options |= COPTION_PRIVATE;
1064 break;
1066 case 20: /* classdatatype */
1067 if (cl == NULL)
1068 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
1069 cl->classdatatype = strdup(s);
1070 break;
1072 case 21: /* beginio_func */
1073 if (inclass)
1074 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
1075 if (cfg->modtype != DEVICE)
1076 exitfileerror(20, "beginio_func specified when not a device\n");
1077 cfg->beginiofunc = strdup(s);
1078 break;
1080 case 22: /* abortio_func */
1081 if (inclass)
1082 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
1083 if (cfg->modtype != DEVICE)
1084 exitfileerror(20, "abortio_func specified when not a device\n");
1085 cfg->abortiofunc = strdup(s);
1086 break;
1088 case 23: /* dispatcher */
1089 if (cl == NULL)
1090 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
1091 cl->dispatcher = strdup(s);
1092 /* function references are not needed when dispatcher is specified */
1093 cfg->intcfg |= CFG_NOREADFUNCS;
1094 break;
1096 case 24: /* initpri */
1097 if (cl != NULL)
1099 int count;
1100 char dummy;
1102 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
1103 if (count != 1 ||
1104 cl->initpri < -128 || cl->initpri > 127
1107 exitfileerror(20, "initpri number format error\n");
1110 else
1111 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
1112 break;
1114 case 25: /* type */
1115 if (!inclass)
1116 exitfileerror(20, "type only valid config option in a class section\n");
1117 if (strcmp(s,"mcc")==0)
1118 cl->classtype = MCC;
1119 else if (strcmp(s,"mui")==0)
1120 cl->classtype = MUI;
1121 else if (strcmp(s,"mcp")==0)
1122 cl->classtype = MCP;
1123 else if (strcmp(s, "image")==0)
1124 cl->classtype = IMAGE;
1125 else if (strcmp(s, "gadget")==0)
1126 cl->classtype = GADGET;
1127 else if (strcmp(s, "datatype")==0)
1128 cl->classtype = DATATYPE;
1129 else if (strcmp(s, "usbclass")==0)
1130 cl->classtype = USBCLASS;
1131 else if (strcmp(s, "class")==0)
1132 cl->classtype = CLASS;
1133 else if (strcmp(s, "hidd")==0)
1134 cl->classtype = HIDD;
1135 else
1137 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
1138 exit(20);
1140 break;
1142 case 26: /* addromtag */
1143 cfg->addromtag = strdup(s);
1144 break;
1146 case 27: /* oopbase_field */
1147 cfg->oopbase_field = strdup(s);
1148 break;
1149 case 28: /* rellib */
1150 slist_append(&cfg->rellibs, s);
1151 break;
1152 case 29: /* interfaceid */
1153 if (!in)
1154 exitfileerror(20, "interfaceid only valid config option for an interface\n");
1155 in->interfaceid = strdup(s);
1156 break;
1157 case 30: /* interfacename */
1158 if (!in)
1159 exitfileerror(20, "interfacename only valid config option for an interface\n");
1160 in->interfacename = strdup(s);
1161 break;
1162 case 31: /* methodstub */
1163 if (!in)
1164 exitfileerror(20, "methodstub only valid config option for an interface\n");
1165 in->methodstub = strdup(s);
1166 break;
1167 case 32: /* methodbase */
1168 if (!in)
1169 exitfileerror(20, "methodbase only valid config option for an interface\n");
1170 in->methodbase = strdup(s);
1171 break;
1172 case 33: /* attributebase */
1173 if (!in)
1174 exitfileerror(20, "attributebase only valid config option for an interface\n");
1175 in->attributebase = strdup(s);
1176 break;
1177 case 34: /* handler_func */
1178 if (cfg->modtype != HANDLER)
1179 exitfileerror(20, "handler specified when not a handler\n");
1180 cfg->handlerfunc = strdup(s);
1181 break;
1182 case 35: /* includename */
1183 if (inclass)
1184 exitfileerror(20, "includename not valid config option"
1185 " when in a class section\n");
1186 cfg->includename = strdup(s);
1187 break;
1190 else /* Line starts with ## */
1192 s = line+2;
1193 while (isspace(*s)) s++;
1194 if (strncmp(s, "end", 3)!=0)
1195 exitfileerror(20, "\"##end config\" expected\n");
1197 s += 3;
1198 if (!isspace(*s))
1199 exitfileerror(20, "\"##end config\" expected\n");
1201 while (isspace(*s)) s++;
1202 if (strncmp(s, "config", 6)!=0)
1203 exitfileerror(20, "\"##end config\" expected\n");
1205 s += 6;
1206 while (isspace(*s)) s++;
1207 if (*s!='\0')
1208 exitfileerror(20, "\"##end config\" expected\n");
1210 atend = 1;
1214 /* When not in a class section fill in default values for fields in cfg */
1215 if (!inclass)
1217 if (cfg->basename==NULL)
1219 cfg->basename = strdup(cfg->modulename);
1220 *cfg->basename = toupper(*cfg->basename);
1222 if (cfg->libbase==NULL)
1224 unsigned int len = strlen(cfg->basename)+5;
1225 cfg->libbase = malloc(len);
1226 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1228 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1229 cfg->libbasetype = strdup(libbasetypeextern);
1230 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1231 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1232 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1233 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1234 if (cfg->oopbase_field != NULL && cfg->libbasetype == NULL)
1235 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1236 /* rootbase_field only allowed when duplicating base */
1237 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1238 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1240 /* Set default date to current date */
1241 if (cfg->datestring == NULL)
1243 char tmpbuf[256];
1244 time_t now = time(NULL);
1245 struct tm *ltime = localtime(&now);
1247 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1248 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1250 cfg->datestring = strdup(tmpbuf);
1253 if (cfg->copyright == NULL)
1254 cfg->copyright = "";
1256 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1257 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1259 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1261 if (libbasetypeextern==NULL)
1263 switch (cfg->modtype)
1265 case DEVICE:
1266 cfg->libbasetypeptrextern = "struct Device *";
1267 break;
1268 case HANDLER:
1269 case RESOURCE:
1270 cfg->libbasetypeptrextern = "APTR ";
1271 break;
1272 case LIBRARY:
1273 case MUI:
1274 case MCP:
1275 case MCC:
1276 case GADGET:
1277 case DATATYPE:
1278 case USBCLASS:
1279 case HIDD:
1280 cfg->libbasetypeptrextern = "struct Library *";
1281 break;
1282 default:
1283 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1284 exit(20);
1287 else
1289 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1290 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1291 strcat(cfg->libbasetypeptrextern, " *");
1292 free(libbasetypeextern);
1295 if (cfg->includename == NULL)
1296 cfg->includename = cfg->modulename;
1297 cfg->includenameupper = strdup(cfg->includename);
1298 for (s=cfg->includenameupper; *s!='\0'; *s = toupper(*s), s++)
1299 if (!isalnum(*s)) *s = '_';
1302 /* When class was given too fill in some defaults when not specified */
1303 if (cl != NULL)
1305 if (cl->classtype == UNSPECIFIED)
1306 cl->classtype = CLASS;
1308 if (cl->basename == NULL)
1310 if (!inclass)
1311 cl->basename = cfg->basename;
1312 else
1313 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1316 /* MUI classes are always private */
1317 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1318 cl->options |= COPTION_PRIVATE;
1320 if (cl->classid == NULL
1321 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1324 if (cl->classtype == HIDD)
1326 cl->options &= !COPTION_PRIVATE;
1328 else if (cl->options & COPTION_PRIVATE)
1330 cl->classid = "NULL";
1332 else
1334 char s[256] = "";
1336 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1338 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1340 else if (cl->classtype == DATATYPE)
1342 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1344 cl->classid = strdup(s);
1348 /* Only specify superclass or superclass_field */
1349 if (cl->superclass != NULL && cl->superclass_field != NULL)
1350 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1352 /* Give default value to superclass if it is not specified */
1353 if (cl->superclass == NULL && cl->superclass == NULL)
1355 switch (cl->classtype)
1357 case MUI:
1358 case MCC:
1359 cl->superclass = "MUIC_Area";
1360 break;
1361 case MCP:
1362 cl->superclass = "MUIC_Mccprefs";
1363 break;
1364 case IMAGE:
1365 cl->superclass = "IMAGECLASS";
1366 break;
1367 case GADGET:
1368 cl->superclass = "GADGETCLASS";
1369 break;
1370 case DATATYPE:
1371 cl->superclass = "DATATYPESCLASS";
1372 break;
1373 case CLASS:
1374 cl->superclass = "ROOTCLASS";
1375 break;
1376 case HIDD:
1377 cl->superclass = "CLID_Root";
1378 break;
1379 default:
1380 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1381 break;
1387 static void readsectioncdef(struct config *cfg)
1389 int atend = 0;
1390 char *line, *s;
1392 while (!atend)
1394 line = readline();
1395 if (line==NULL)
1396 exitfileerror(20, "unexptected end of file in section cdef\n");
1398 if (strncmp(line, "##", 2)!=0)
1400 slist_append(&cfg->cdeflines, line);
1402 else
1404 s = line+2;
1405 while (isspace(*s)) s++;
1406 if (strncmp(s, "end", 3)!=0)
1407 exitfileerror(20, "\"##end cdef\" expected\n");
1409 s += 3;
1410 while (isspace(*s)) s++;
1411 if (strncmp(s, "cdef", 4)!=0)
1412 exitfileerror(20, "\"##end cdef\" expected\n");
1414 s += 5;
1415 while (isspace(*s)) s++;
1416 if (*s!='\0')
1417 exitfileerror(20, "unexpected character at position %d\n");
1419 atend = 1;
1425 static void readsectionstubprivate(struct config *cfg)
1427 int atend = 0;
1428 char *line, *s;
1430 while (!atend)
1432 line = readline();
1433 if (line==NULL)
1434 exitfileerror(20, "unexptected end of file in section stubprivate\n");
1436 if (strncmp(line, "##", 2)!=0)
1438 slist_append(&cfg->stubprivatelines, line);
1440 else
1442 s = line+2;
1443 while (isspace(*s)) s++;
1444 if (strncmp(s, "end", 3)!=0)
1445 exitfileerror(20, "\"##end stubprivate\" expected\n");
1447 s += 3;
1448 while (isspace(*s)) s++;
1449 if (strncmp(s, "stubprivate", 11)!=0)
1450 exitfileerror(20, "\"##end stubprivate\" expected\n");
1452 s += 11;
1453 while (isspace(*s)) s++;
1454 if (*s!='\0')
1455 exitfileerror(20, "unexpected character at position %d\n");
1457 atend = 1;
1462 static void readsectioncdefprivate(struct config *cfg)
1464 int atend = 0;
1465 char *line, *s;
1467 while (!atend)
1469 line = readline();
1470 if (line==NULL)
1471 exitfileerror(20, "unexptected end of file in section cdefprivate\n");
1473 if (strncmp(line, "##", 2)!=0)
1475 slist_append(&cfg->cdefprivatelines, line);
1477 else
1479 s = line+2;
1480 while (isspace(*s)) s++;
1481 if (strncmp(s, "end", 3)!=0)
1482 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1484 s += 3;
1485 while (isspace(*s)) s++;
1486 if (strncmp(s, "cdefprivate", 11)!=0)
1487 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1489 s += 11;
1490 while (isspace(*s)) s++;
1491 if (*s!='\0')
1492 exitfileerror(20, "unexpected character at position %d\n");
1494 atend = 1;
1499 static void readsectionstartup(struct config *cfg)
1501 int atend = 0;
1502 char *line, *s;
1504 while (!atend)
1506 line = readline();
1507 if (line==NULL)
1508 exitfileerror(20, "unexptected end of file in section startup\n");
1510 if (strncmp(line, "##", 2)!=0)
1512 slist_append(&cfg->startuplines, line);
1514 else
1516 s = line+2;
1517 while (isspace(*s)) s++;
1518 if (strncmp(s, "end", 3)!=0)
1519 exitfileerror(20, "\"##end startup\" expected\n");
1521 s += 3;
1522 while (isspace(*s)) s++;
1523 if (strncmp(s, "startup", 7)!=0)
1524 exitfileerror(20, "\"##end startup\" expected\n");
1526 s += 7;
1527 while (isspace(*s)) s++;
1528 if (*s!='\0')
1529 exitfileerror(20, "unexpected character at position %d\n");
1531 atend = 1;
1536 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall)
1538 int atend = 0, i;
1539 char *line, *s, *s2;
1540 unsigned int lvo = firstlvo;
1541 int minversion = -1;
1543 while (!atend)
1545 line = readline();
1546 if (line==NULL)
1547 exitfileerror(20, "unexpected EOF in functionlist section\n");
1548 if (strlen(line)==0)
1550 if (*funclistptr != NULL)
1551 funclistptr = &((*funclistptr)->next);
1552 lvo++;
1554 else if (isspace(*line))
1556 s = line;
1557 while (isspace(*s)) s++;
1558 if (*s=='\0')
1560 if (*funclistptr != NULL)
1561 funclistptr = &((*funclistptr)->next);
1562 lvo++;
1564 else
1565 exitfileerror(20, "no space allowed before functionname\n");
1567 else if (strncmp(line, "##", 2)==0)
1569 s = line+2;
1570 while (isspace(*s)) s++;
1571 if (strncmp(s, "end", 3)!=0)
1572 exitfileerror(20, "\"##end %s\" expected\n", type);
1574 s += 3;
1575 while (isspace(*s)) s++;
1576 if (strncmp(s, type, strlen(type))!=0)
1577 exitfileerror(20, "\"##end %s\" expected\n", type);
1579 s += strlen(type);
1580 while (isspace(*s)) s++;
1581 if (*s!='\0')
1582 exitfileerror(20, "unexpected character on position %d\n", s-line);
1584 atend = 1;
1586 else if (*line=='.')
1588 s = line+1;
1589 if (strncmp(s, "skip", 4)==0)
1591 int n;
1593 s += 4;
1594 if (!isspace(*s))
1595 exitfileerror(20, "syntax is '.skip n'\n");
1597 n=strtol(s, &s2, 10);
1598 if (s2==NULL)
1599 exitfileerror(20, "positive number expected\n");
1601 while (isspace(*s2)) s2++;
1602 if ((*s2 != '\0') && (*s2 != '#'))
1603 exitfileerror(20, "syntax is '.skip n'\n");
1604 if (*funclistptr != NULL)
1605 funclistptr = &((*funclistptr)->next);
1606 lvo += n;
1608 else if (strncmp(s, "alias", 5)==0)
1610 s += 5;
1612 if (!isspace(*s))
1613 exitfileerror(20, "syntax is '.alias name'\n");
1615 while (isspace(*s)) s++;
1616 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1617 exitfileerror(20, "syntax is '.alias name'\n");
1619 s2 = s;
1620 s++;
1621 while (isalnum(*s) || *s == '_') s++;
1623 if (isspace(*s))
1625 *s = '\0';
1626 do {
1627 s++;
1628 } while (isspace(*s));
1631 if (*s != '\0')
1632 exitfileerror(20, "syntax is '.alias name'\n");
1634 if (*funclistptr == NULL)
1635 exitfileerror(20, ".alias has to come after a function declaration\n");
1637 slist_append(&(*funclistptr)->aliases, s2);
1639 else if (strncmp(s, "function", 8) == 0)
1641 s += 8;
1643 if (!isspace(*s))
1644 exitfileerror(20, "Syntax error\n");
1646 while (isspace(*s)) s++;
1647 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1648 exitfileerror(20, "syntax is '.function name'\n");
1650 s2 = s;
1651 s++;
1652 while (isalnum(*s) || *s == '_') s++;
1654 if (isspace(*s))
1656 *s = '\0';
1657 do {
1658 s++;
1659 } while (isspace(*s));
1662 if (*s != '\0')
1663 exitfileerror(20, "syntax is '.function name'\n");
1665 if (*funclistptr == NULL)
1666 exitfileerror(20, ".function has to come after a function declaration\n");
1668 funcsetinternalname(*funclistptr, s2);
1670 else if (strncmp(s, "cfunction", 9)==0)
1672 if (*funclistptr == NULL)
1673 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1675 (*funclistptr)->libcall = REGISTER;
1677 else if (strncmp(s, "private", 7)==0)
1679 if (*funclistptr == NULL)
1680 exitfileerror(20, ".private has to come after a function declaration\n");
1682 (*funclistptr)->priv = 1;
1684 else if (strncmp(s, "novararg", 8)==0)
1686 if (*funclistptr == NULL)
1687 exitfileerror(20, ".novararg has to come after a function declaration\n");
1689 (*funclistptr)->novararg = 1;
1691 else if (strncmp(s, "version", 7) == 0)
1693 /* Mark version number for the following
1694 * functions, so that the automatic OpenLibrary()
1695 * will know what version to use.
1697 char *tmp;
1698 int ver;
1700 s += 7;
1702 while (isspace(*s)) s++;
1703 ver = (int)strtol(s, &tmp, 0);
1705 if (s == tmp)
1706 exitfileerror(20, ".version expects an integer\n");
1708 s = tmp;
1709 while (isspace(*s)) s++;
1711 if (*s && *s != '#')
1712 exitfileerror(20, ".version has junk after the version number\n");
1714 minversion = ver;
1716 else if (strncmp(s, "unusedlibbase", 13) == 0)
1718 if (*funclistptr == NULL)
1719 exitfileerror(20, ".unusedlibbase has to come after a function declaration\n");
1720 (*funclistptr)->unusedlibbase = 1;
1722 else
1723 exitfileerror(20, "Syntax error");
1725 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1727 /* The line is a function or attribute prototype.
1728 * A function can have one of two syntaxes:
1729 * type funcname(argproto1, argproto2, ...)
1730 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1731 * The former is for C type function argument passing, the latter for
1732 * register argument passing.
1733 * An attribute has the following syntax:
1734 * type attribute
1736 char c, *args[64], *regs[64], *funcname, *cp;
1737 int len, argcount = 0, regcount = 0, brcount = 0;
1739 cp = strchr(line,'#');
1740 if (cp)
1741 *(cp++) = 0;
1743 /* Parse 'type functionname' at the beginning of the line */
1744 if (isattribute) {
1745 s = line + strlen(line);
1746 } else {
1747 s = strchr(line, '(');
1748 if (s == NULL)
1749 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1752 s2 = s;
1753 while (isspace(*(s2-1)))
1754 s2--;
1755 *s2 = '\0';
1757 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1758 s2--;
1760 if (s2 == line)
1761 exitfileerror(20, "No type specifier before %s name\n", isattribute ? "attribute" : "function");
1763 if (*funclistptr != NULL)
1764 funclistptr = &((*funclistptr)->next);
1765 *funclistptr = newfunctionhead(s2, STACK);
1767 if (cp)
1768 (*funclistptr)->comment = strdup(cp);
1769 else
1770 (*funclistptr)->comment = NULL;
1772 while (isspace(*(s2-1)))
1773 s2--;
1774 *s2 = '\0';
1775 (*funclistptr)->type = strdup(line);
1776 (*funclistptr)->lvo = lvo;
1777 (*funclistptr)->version = minversion;
1778 lvo++;
1780 if (isattribute)
1781 continue;
1783 /* Parse function prototype */
1784 s++;
1785 while (isspace(*s))
1786 s++;
1787 c = *s;
1789 while (c != ')')
1791 while (isspace(*s))
1792 s++;
1794 args[argcount] = s;
1795 argcount++;
1797 while
1799 *s != '\0'
1800 && !(brcount == 0 && (*s == ',' || *s == ')'))
1803 if (*s == '(')
1804 brcount++;
1805 if (*s == ')')
1807 if (brcount > 0)
1808 brcount--;
1809 else
1810 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1812 s++;
1815 c = *s;
1816 if (c == '\0')
1817 exitfileerror(20, "'(' without ')'");
1819 s2 = s;
1820 while (isspace(*(s2-1)))
1821 s2--;
1822 *s2 = '\0';
1824 if (!(s2 > args[argcount - 1]))
1825 exitfileerror(20, "Syntax error in function prototype\n");
1827 s++;
1830 s++;
1831 while (*s != '\0' && isspace(*s))
1832 s++;
1834 if (*s == '(')
1836 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1838 /* There may be no register specified with () so be sure then c is == ')' */
1839 s++;
1840 while(isspace(*s))
1841 s++;
1843 c = *s;
1845 while (c != ')')
1847 while (isspace(*s))
1848 s++;
1850 regs[regcount] = s;
1851 regcount++;
1853 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1855 s += 2;
1856 c = *s;
1857 if (c == '/')
1859 s++;
1860 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1862 s += 2;
1863 c = *s;
1865 else
1866 exitfileerror(20,
1867 "wrong register specification \"%s\" for argument %u\n",
1868 regs[regcount-1], regcount
1871 if (regcount > 4)
1872 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount, regs[regcount-1]);
1874 *s = '\0';
1876 else
1877 exitfileerror(20,
1878 "wrong register \"%s\" for argument %u\n",
1879 regs[regcount-1], regcount
1882 while (isspace(c))
1884 s++;
1885 c = *s;
1887 if (c == '\0')
1888 exitfileerror(20, "'(' without ')'\n");
1889 if (c != ',' && c != ')')
1890 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1892 s++;
1895 s++;
1896 while (isspace(*s)) s++;
1897 if (*s!='\0')
1898 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1900 if (argcount != regcount)
1901 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1902 argcount, regcount
1905 (*funclistptr)->libcall = def_libcall;
1906 for (i = 0; i < argcount; i++)
1907 funcaddarg(*funclistptr, args[i], regs[i]);
1909 else if (*s == '\0')
1910 { /* No registers specified */
1911 for (i = 0; i < argcount; i++)
1912 funcaddarg(*funclistptr, args[i], NULL);
1914 else
1915 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1920 static void readsectionclass_methodlist(struct classinfo *cl)
1922 int atend = 0, i;
1923 char *line, *s, *s2;
1924 struct functionhead **methlistptr = &cl->methlist;
1925 struct stringlist *interface = NULL;
1927 if (cl->basename==NULL)
1928 exitfileerror(20, "section methodlist has to come after section config\n");
1930 while (!atend)
1932 line = readline();
1933 if (line==NULL)
1934 exitfileerror(20, "unexptected EOF in methodlist section\n");
1936 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1937 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1938 continue;
1940 if (isspace(*line))
1941 exitfileerror(20, "No space allowed at start of the line\n");
1943 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1945 s = line+2;
1946 while (isspace(*s)) s++;
1947 if (strncmp(s, "end", 3)!=0)
1948 exitfileerror(20, "\"##end methodlist\" expected\n");
1950 s += 3;
1951 while (isspace(*s)) s++;
1952 if (strncmp(s, "methodlist", 10)!=0)
1953 exitfileerror(20, "\"##end methodlist\" expected\n");
1955 s += 10;
1956 while (isspace(*s)) s++;
1957 if (*s!='\0')
1958 exitfileerror(20, "unexpected character on position %d\n", s-line);
1960 atend = 1;
1962 continue;
1965 if (*line=='.')
1967 s = line+1;
1968 if (strncmp(s, "alias", 5)==0)
1970 s += 5;
1972 if (!isspace(*s))
1973 exitfileerror(20, "syntax is '.alias name'\n");
1975 while (isspace(*s)) s++;
1976 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1977 exitfileerror(20, "syntax is '.alias name'\n");
1979 s2 = s;
1980 s++;
1981 while (isalnum(*s) || *s == '_') s++;
1983 if (isspace(*s))
1985 *s = '\0';
1986 do {
1987 s++;
1988 } while (isspace(*s));
1991 if (*s != '\0')
1992 exitfileerror(20, "syntax is '.alias name'\n");
1994 if (*methlistptr == NULL)
1995 exitfileerror(20, ".alias has to come after a function declaration\n");
1997 slist_append(&(*methlistptr)->aliases, s2);
1999 else if (strncmp(s, "function", 8) == 0)
2001 s += 8;
2003 if (!isspace(*s))
2004 exitfileerror(20, "Syntax error\n");
2006 while (isspace(*s)) s++;
2007 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
2008 exitfileerror(20, "syntax is '.function name'\n");
2010 s2 = s;
2011 s++;
2012 while (isalnum(*s) || *s == '_') s++;
2014 if (isspace(*s))
2016 *s = '\0';
2017 do {
2018 s++;
2019 } while (isspace(*s));
2022 if (*s != '\0')
2023 exitfileerror(20, "syntax is '.function name'\n");
2025 if (*methlistptr == NULL)
2026 exitfileerror(20, ".function has to come after a function declaration\n");
2028 funcsetinternalname(*methlistptr, s2);
2030 else if (strncmp(s, "interface", 9) == 0)
2032 if (cl->classtype != HIDD)
2033 exitfileerror(20, "interface only valid for a HIDD\n");
2035 s += 9;
2037 if (!isspace(*s))
2038 exitfileerror(20, "Syntax error\n");
2040 while (isspace(*s)) s++;
2041 if (*s == '\0' || !isalpha(*s))
2042 exitfileerror(20, "syntax is '.interface name'\n");
2044 s2 = s;
2045 s++;
2046 while (isalnum(*s) || *s == '_') s++;
2048 if (isspace(*s))
2050 *s = '\0';
2051 do {
2052 s++;
2053 } while (isspace(*s));
2056 if (*s != '\0')
2057 exitfileerror(20, "syntax is '.interface name'\n");
2059 interface = slist_append(&cl->interfaces, s2);
2061 else
2062 exitfileerror(20, "Syntax error");
2064 else if (isalpha(*line))
2066 char stmp[256];
2068 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
2071 if (cl->classtype == HIDD && interface == NULL)
2072 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
2074 if (*s != '\0')
2075 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
2077 if (*methlistptr != NULL)
2078 methlistptr = &((*methlistptr)->next);
2079 if (cl->classtype != HIDD)
2081 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
2082 exitfileerror(20, "Method name too large\n");
2084 *methlistptr = newfunctionhead(stmp, STACK);
2085 (*methlistptr)->type = "IPTR";
2086 funcaddarg(*methlistptr, "Class *cl", NULL);
2087 funcaddarg(*methlistptr, "Object *o", NULL);
2088 funcaddarg(*methlistptr, "Msg msg", NULL);
2090 else
2092 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
2093 exitfileerror(20, "Method name too large\n");
2095 *methlistptr = newfunctionhead(stmp, STACK);
2096 (*methlistptr)->type = "IPTR";
2097 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
2098 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
2099 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
2100 (*methlistptr)->interface = interface;
2101 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
2102 exitfileerror(20, "Method name too large\n");
2103 (*methlistptr)->method = strdup(stmp);
2105 slist_append(&(*methlistptr)->aliases, line);
2107 else
2108 exitfileerror(20, "Methodname has to begin with a letter\n");
2112 static void
2113 readsectioninterface(struct config *cfg)
2115 char *s;
2116 struct interfaceinfo *in;
2118 in = newinterface(cfg);
2119 s = readsections(cfg, NULL, in, 1, 0);
2120 if (s == NULL)
2121 exitfileerror(20, "Unexpected end of file\n");
2123 if (strncmp(s, "##", 2) != 0)
2124 exitfileerror(20, "'##end interface' expected\n");
2125 s += 2;
2127 while (isspace(*s)) s++;
2129 if (strncmp(s, "end", 3) != 0)
2130 exitfileerror(20, "'##end interface' expected\n");
2131 s += 3;
2133 if (!isspace(*s))
2134 exitfileerror(20, "'##end interface' expected\n");
2135 while (isspace(*s)) s++;
2137 if (strncmp(s, "interface", 9) != 0)
2138 exitfileerror(20, "'##end interface' expected\n");
2139 s += 9;
2141 while (isspace(*s)) s++;
2142 if (*s != '\0')
2143 exitfileerror(20, "'##end interface' expected\n");
2145 if (!in->interfaceid)
2146 exitfileerror(20, "interface has no 'interfaceid' defined!\n");
2148 if (!in->interfacename)
2149 exitfileerror(20, "interface has no 'interfacename' defined!\n");
2151 if (!in->methodstub)
2152 in->methodstub = strdup(in->interfacename);
2154 if (!in->methodbase) {
2155 int len = strlen(in->interfacename);
2156 in->methodbase = malloc(len + 4 + 1);
2157 strcpy(in->methodbase, in->interfacename);
2158 strcat(in->methodbase, "Base");
2161 if (!in->attributebase) {
2162 int len = strlen(in->interfacename);
2163 in->attributebase = malloc(len + 4 + 4 + 1);
2164 strcpy(in->attributebase, in->interfacename);
2165 strcat(in->attributebase, "AttrBase");
2169 static void
2170 readsectionclass(struct config *cfg)
2172 char *s;
2173 struct classinfo *cl;
2175 cl = newclass(cfg);
2176 s = readsections(cfg, cl, NULL, 1, 0);
2177 if (s == NULL)
2178 exitfileerror(20, "Unexpected end of file\n");
2180 if (strncmp(s, "##", 2) != 0)
2181 exitfileerror(20, "'##end class' expected\n");
2182 s += 2;
2184 while (isspace(*s)) s++;
2186 if (strncmp(s, "end", 3) != 0)
2187 exitfileerror(20, "'##end class' expected\n");
2188 s += 3;
2190 if (!isspace(*s))
2191 exitfileerror(20, "'##end class' expected\n");
2192 while (isspace(*s)) s++;
2194 if (strncmp(s, "class", 5) != 0)
2195 exitfileerror(20, "'##end class' expected\n");
2196 s += 5;
2198 while (isspace(*s)) s++;
2199 if (*s != '\0')
2200 exitfileerror(20, "'##end class' expected\n");
2203 static struct classinfo *newclass(struct config *cfg)
2205 struct classinfo *cl, *classlistit;
2207 cl = malloc(sizeof(struct classinfo));
2208 if (cl == NULL)
2210 fprintf(stderr, "Out of memory\n");
2211 exit(20);
2213 memset(cl, 0, sizeof(struct classinfo));
2215 /* By default the classes are initialized with a priority of 1 so they
2216 * are initialized before any user added initialization with priority 1
2218 cl->initpri = 1;
2220 if (cfg->classlist == NULL)
2221 cfg->classlist = cl;
2222 else
2226 classlistit = cfg->classlist;
2227 classlistit->next != NULL;
2228 classlistit = classlistit->next
2231 classlistit->next = cl;
2234 return cl;
2237 static struct handlerinfo *newhandler(struct config *cfg)
2239 struct handlerinfo *hl;
2241 hl = calloc(1,sizeof(*hl));
2242 hl->next = cfg->handlerlist;
2243 cfg->handlerlist = hl;
2244 return hl;
2247 static struct interfaceinfo *newinterface(struct config *cfg)
2249 struct interfaceinfo *in, *interfacelistit;
2251 in = malloc(sizeof(struct interfaceinfo));
2252 if (in == NULL)
2254 fprintf(stderr, "Out of memory\n");
2255 exit(20);
2257 memset(in, 0, sizeof(struct interfaceinfo));
2259 if (cfg->interfacelist == NULL)
2260 cfg->interfacelist = in;
2261 else
2265 interfacelistit = cfg->interfacelist;
2266 interfacelistit->next != NULL;
2267 interfacelistit = interfacelistit->next
2270 interfacelistit->next = in;
2273 return in;
2277 static int getdirective(char *s, const char *directive, int range_min, int range_max, int *val)
2279 char *tmp;
2280 int newval;
2282 if (strncmp(s, directive, strlen(directive)) != 0)
2283 return 0;
2285 s += strlen(directive);
2286 if (*s && !isspace(*s))
2287 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive);
2289 while (isspace(*s)) s++;
2290 if (!*s)
2291 exitfileerror(20, "No .%s value specified\n", directive);
2293 newval = strtol(s, &tmp, 0);
2294 if (s == tmp || !(newval >= range_min && newval <= range_max)) {
2295 tmp = s;
2296 while (*tmp && !isspace(*tmp)) tmp++;
2297 exitfileerror(20, "Invalid .%s value of %.*s\n", directive, tmp - s, s);
2300 *val = newval;
2301 return 1;
2304 static void
2305 readsectionhandler(struct config *cfg)
2307 char *line = NULL, *s;
2308 struct handlerinfo *hl;
2309 unsigned char autolevel = 0;
2310 unsigned int stacksize = 0;
2311 int startup = 0;
2312 char priority = 10;
2313 int bootpri = -128;
2314 int has_filesystem = 0;
2316 for (;;)
2318 char *function;
2319 int function_len;
2320 char *tmp;
2322 s = line = readline();
2324 if (s==NULL)
2325 exitfileerror(20, "unexpected end of file in section hanlder\n");
2327 if (strncmp(s, "##", 2)==0)
2328 break;
2330 /* Ignore comments */
2331 if (strncmp(s, "#", 1)==0)
2332 continue;
2334 /* Skip ahead to function name */
2335 while (*s && isspace(*s)) s++;
2337 /* Permit blank lines */
2338 if (!*s)
2339 continue;
2341 if (*s == '.') {
2342 int val;
2343 s++;
2345 if (getdirective(s, "autodetect", 0, 127, &val)) {
2346 autolevel = val;
2347 } else if (getdirective(s, "stacksize", 0, INT_MAX, &val)) {
2348 stacksize = val;
2349 } else if (getdirective(s, "priority", -128, 127, &val)) {
2350 priority = val;
2351 } else if (getdirective(s, "bootpri", -128, 127, &val)) {
2352 bootpri = val;
2353 } else if (getdirective(s, "startup", INT_MIN, INT_MAX, &val)) {
2354 startup = val;
2355 } else {
2356 exitfileerror(20, "Unrecognized directive \"%s\"\n", line);
2358 continue;
2361 do {
2362 unsigned int id = 0;
2364 if (strncasecmp(s,"resident=",9)==0) {
2365 char *res;
2367 s = strchr(s, '=') + 1;
2368 res = s;
2369 while (*s && !isspace(*s)) s++;
2370 if (res == s)
2371 exitfileerror(20, "Empty resident= is not permitted\n");
2373 if (*s)
2374 *(s++) = 0;
2376 hl = newhandler(cfg);
2377 hl->type = HANDLER_RESIDENT;
2378 hl->id = 0;
2379 hl->name = strdup(res);
2380 hl->autodetect = autolevel--;
2381 hl->stacksize = stacksize;
2382 hl->priority = priority;
2383 hl->startup = startup;
2384 } else if (strncasecmp(s,"dosnode=",8)==0) {
2385 char *dev;
2387 s = strchr(s, '=') + 1;
2388 dev = s;
2389 while (*s && !isspace(*s)) s++;
2390 if (dev == s)
2391 exitfileerror(20, "Empty dosnode= is not permitted\n");
2393 if (*s)
2394 *(s++) = 0;
2396 hl = newhandler(cfg);
2397 hl->type = HANDLER_DOSNODE;
2398 hl->id = 0;
2399 hl->name = strdup(dev);
2400 hl->autodetect = autolevel ? autolevel-- : 0;
2401 hl->stacksize = stacksize;
2402 hl->priority = priority;
2403 hl->startup = startup;
2404 hl->bootpri = bootpri;
2405 } else if (strncasecmp(s,"dostype=",8) == 0) {
2406 s = strchr(s, '=') + 1;
2408 id = (unsigned int)strtoul(s, &tmp, 0);
2410 if (s == tmp) {
2411 while (*tmp && !isspace(*tmp))
2412 tmp++;
2413 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp -s), s);
2415 s = tmp;
2417 if (id == 0 || id == ~0) {
2418 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id);
2421 hl = newhandler(cfg);
2422 hl->type = HANDLER_DOSTYPE;
2423 hl->id = id;
2424 hl->name = NULL;
2425 hl->autodetect = autolevel ? autolevel-- : 0;
2426 hl->stacksize = stacksize;
2427 hl->priority = priority;
2428 hl->startup = startup;
2429 } else {
2430 for (tmp = s; !isspace(*tmp); tmp++);
2431 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp - s, s);
2434 /* Advance to next ID */
2435 while (*s && isspace(*s)) s++;
2437 } while (*s);
2440 if (s == NULL)
2441 exitfileerror(20, "Unexpected end of file\n");
2443 if (strncmp(s, "##", 2) != 0)
2444 exitfileerror(20, "'##end handler' expected\n");
2445 s += 2;
2447 while (isspace(*s)) s++;
2449 if (strncmp(s, "end", 3) != 0)
2450 exitfileerror(20, "'##end handler' expected\n");
2451 s += 3;
2453 while (isspace(*s)) s++;
2455 if (strncmp(s, "handler", 7) != 0)
2456 exitfileerror(20, "'##end handler' expected\n");
2457 s += 7;
2459 while (isspace(*s)) s++;
2460 if (*s != '\0')
2461 exitfileerror(20, "'##end handler' expected\n");