Fixed to work with ABIv1.
[AROS.git] / tools / genmodule / config.c
blobd4205e2180c68fd9071113bb83d63883f9714c5b
1 /*
2 Copyright © 1995-2016, 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-%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] [-s suffix] [-d gendir] [-l library-stub gendir] [-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:s:d:l: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 's':
123 cfg->suffix = optarg;
124 hassuffix = 1;
125 break;
127 case 'd':
128 /* Remove / at end if present */
129 if ((optarg)[strlen(*argvit)-1]=='/') (optarg)[strlen(optarg)-1]='\0';
130 cfg->gendir = optarg;
131 break;
133 case 'l':
134 /* Remove / at end if present */
135 if ((optarg)[strlen(*argvit)-1]=='/') (optarg)[strlen(optarg)-1]='\0';
136 cfg->libgendir = optarg;
137 break;
139 case 'v':
140 cfg->versionextra = optarg;
141 break;
143 default:
144 fprintf(stderr, "Internal error: Unhandled option\n");
145 exit(20);
149 if (optind + 3 != argc)
151 fprintf(stderr, "Wrong number of arguments.\n%s", usage);
152 exit(20);
155 if (strcmp(argv[optind], "writefiles") == 0)
157 cfg->command = FILES;
159 else if (strcmp(argv[optind], "writemakefile") == 0)
161 cfg->command = MAKEFILE;
163 else if (strcmp(argv[optind], "writeincludes") == 0)
165 cfg->command = INCLUDES;
167 else if (strcmp(argv[optind], "writelibdefs") == 0)
169 cfg->command = LIBDEFS;
171 else if (strcmp(argv[optind], "writefunclist") == 0)
173 cfg->command = WRITEFUNCLIST;
175 else if (strcmp(argv[optind], "writefd") == 0)
177 cfg->command = WRITEFD;
179 else if (strcmp(argv[optind], "writeskel") == 0)
181 cfg->command = WRITESKEL;
183 else if (strcmp(argv[optind], "writethunk") == 0)
185 cfg->command = WRITETHUNK;
187 else
189 fprintf(stderr, "Unrecognized argument \"%s\"\n%s", argv[optind], usage);
190 exit(20);
194 cfg->modulename = argv[optind+1];
195 cfg->modulenameupper = strdup(cfg->modulename);
196 for (s=cfg->modulenameupper; *s!='\0'; *s = toupper(*s), s++) {
197 if (!isalnum(*s)) *s = '_';
200 if (strcmp(argv[optind+2],"library")==0)
202 cfg->modtype = LIBRARY;
203 cfg->moddir = "Libs";
205 else if (strcmp(argv[optind+2],"mcc")==0)
207 cfg->modtype = MCC;
208 cfg->moddir = "Classes/Zune";
210 else if (strcmp(argv[optind+2],"mui")==0)
212 cfg->modtype = MUI;
213 cfg->moddir = "Classes/Zune";
215 else if (strcmp(argv[optind+2],"mcp")==0)
217 cfg->modtype = MCP;
218 cfg->moddir = "Classes/Zune";
220 else if (strcmp(argv[optind+2], "device")==0)
222 cfg->modtype = DEVICE;
223 cfg->moddir = "Devs";
225 else if (strcmp(argv[optind+2], "resource")==0)
227 cfg->modtype = RESOURCE;
228 cfg->moddir = "Devs";
230 else if (strcmp(argv[optind+2], "gadget")==0)
232 cfg->modtype = GADGET;
233 cfg->moddir = "Classes/Gadgets";
235 else if (strcmp(argv[optind+2], "datatype")==0)
237 cfg->modtype = DATATYPE;
238 cfg->moddir = "Classes/DataTypes";
240 else if (strcmp(argv[optind+2], "usbclass")==0)
242 cfg->modtype = USBCLASS;
243 cfg->moddir = "Classes/USB";
244 if(!hassuffix)
246 cfg->suffix = "class";
247 hassuffix = 1;
250 else if (strcmp(argv[optind+2], "hidd")==0)
252 cfg->modtype = HIDD;
253 cfg->moddir = "Devs/Drivers";
255 else if (strcmp(argv[optind+2], "handler")==0)
257 cfg->modtype = HANDLER;
258 cfg->moddir = "$(AROS_DIR_FS)";
260 else if (strcmp(argv[optind+2], "hook")==0)
262 cfg->modtype = HANDLER;
263 cfg->moddir = "Devs";
265 else
267 fprintf(stderr, "Unknown modtype \"%s\" specified for second argument\n", argv[optind+2]);
268 exit(20);
270 cfg->modtypestr = argv[optind+2];
272 if (!hassuffix)
273 cfg->suffix = argv[optind+2];
275 /* Fill fields with default value if not specified on the command line */
277 char tmpbuf[256];
279 if (cfg->conffile == NULL)
281 snprintf(tmpbuf, sizeof(tmpbuf), "%s.conf", cfg->modulename);
282 cfg->conffile = strdup(tmpbuf);
285 if (cfg->gendir == NULL)
286 cfg->gendir = ".";
288 if (cfg->libgendir == NULL)
289 cfg->libgendir = cfg->gendir;
292 readconfig(cfg);
294 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
295 * if they are provided
297 if (cfg->beginiofunc != NULL)
299 struct functionhead *funchead;
301 cfg->intcfg |= CFG_NOREADFUNCS;
303 /* Add beginio_func to the list of functions */
304 funchead = newfunctionhead(cfg->beginiofunc, REGISTERMACRO);
305 funchead->type = strdup("void");
306 funchead->lvo = 5;
307 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
309 funchead->next = cfg->funclist;
310 cfg->funclist = funchead;
312 /* Add abortio_func to the list of functions */
313 funchead = newfunctionhead(cfg->abortiofunc, REGISTERMACRO);
314 funchead->type = strdup("LONG");
315 funchead->lvo = 6;
316 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
318 funchead->next = cfg->funclist->next;
319 cfg->funclist->next = funchead;
321 else if (cfg->modtype == DEVICE && cfg->intcfg & CFG_NOREADFUNCS)
323 fprintf
325 stderr,
326 "beginio_func and abortio_func missing for a device with a non empty function list\n"
328 exit(20);
331 /* See if we have any stackcall options */
332 if (cfg->funclist) {
333 struct functionhead *funchead;
335 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
336 if (funchead->libcall == STACK) {
337 cfg->options |= OPTION_STACKCALL;
338 break;
343 /* Provide default version for functions that didnt have it */
344 if (cfg->funclist) {
345 struct functionhead *funchead;
346 int defversion = cfg->majorversion; /* Assume library version is default */
348 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
349 if (funchead->version > -1) {
350 /* There was at least one .version tag. Assume 0 is default */
351 defversion = 0;
352 break;
356 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
357 if (funchead->version == -1) {
358 funchead->version = defversion;
363 /* Verify that a handler has a handler */
364 if (cfg->modtype == HANDLER) {
365 if (cfg->handlerfunc == NULL) {
366 fprintf(stderr, "handler modules require a 'handler_func' ##config option\n");
367 exit(20);
369 cfg->options |= OPTION_NOAUTOLIB | OPTION_NOEXPUNGE | OPTION_NOOPENCLOSE;
372 return cfg;
375 /* Functions to read configuration from the configuration file */
377 #include "fileread.h"
379 static char *readsections(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
380 static void readsectionconfig(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
381 static void readsectioncdef(struct config *);
382 static void readsectioncdefprivate(struct config *);
383 static void readsectionstubprivate(struct config *);
384 static void readsectionstartup(struct config *);
385 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall);
386 static void readsectionclass_methodlist(struct classinfo *);
387 static void readsectionclass(struct config *);
388 static void readsectionhandler(struct config *);
389 static void readsectioninterface(struct config *);
391 static void readconfig(struct config *cfg)
393 struct classinfo *mainclass = NULL;
395 /* Create a classinfo structure if this module is a class */
396 switch (cfg->modtype)
398 case LIBRARY:
399 case DEVICE:
400 case RESOURCE:
401 case USBCLASS:
402 case HANDLER:
403 break;
405 case MCC:
406 case MUI:
407 case MCP:
408 case GADGET:
409 case DATATYPE:
410 case HIDD:
411 mainclass = newclass(cfg);
412 mainclass->classtype = cfg->modtype;
413 break;
415 default:
416 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
417 exit(20);
420 switch (cfg->modtype)
422 case LIBRARY:
423 case USBCLASS:
424 cfg->firstlvo = 5;
425 break;
426 case DEVICE:
427 cfg->firstlvo = 7;
428 break;
429 case MCC:
430 case MUI:
431 case MCP:
432 cfg->firstlvo = 6;
433 mainclass->boopsimprefix = muimprefix;
434 break;
435 case HANDLER:
436 case RESOURCE:
437 cfg->firstlvo = 1;
438 break;
439 case GADGET:
440 cfg->firstlvo = 5;
441 mainclass->boopsimprefix = gadgetmprefix;
442 break;
443 case DATATYPE:
444 cfg->firstlvo = 6;
445 mainclass->boopsimprefix = dtmprefix;
446 break;
447 case HIDD:
448 cfg->firstlvo = 5;
449 /* FIXME: need boopsimprefix ? */
450 break;
451 default:
452 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
453 exit(20);
456 if (!fileopen(cfg->conffile))
458 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
459 exit(20);
462 /* Read all sections and see that we are at the end of the file */
463 if (readsections(cfg, mainclass, NULL, 0) != NULL)
464 exitfileerror(20, "Syntax error");
466 fileclose();
469 /* readsections will scan through all the sections in the config file.
470 * arguments:
471 * struct config *cfg: The module config data which may be updated by
472 * the information in the sections
473 * struct classinfo *cl: The classdata to be filled with data from the sections.
474 * This may be NULL if this is the main part of the configuration file and the
475 * type of the module is not a class
476 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
477 * part of the config file.
479 static char *readsections(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
481 char *line, *s, *s2;
482 int hasconfig = 0;
484 while ((line=readline())!=NULL)
486 if (strncmp(line, "##", 2)==0)
488 static char *parts[] =
490 "config", "cdefprivate", "cdef", "stubprivate", "startup", "functionlist", "methodlist", "class", "handler", "interface", "attributelist", "cfunctionlist"
492 const unsigned int nums = sizeof(parts)/sizeof(char *);
493 unsigned int partnum;
494 int i, atend = 0;
496 s = line+2;
497 while (isspace(*s)) s++;
499 if (strncmp(s, "begin", 5)!=0)
500 return line;
502 s += 5;
503 if (!isspace(*s))
504 exitfileerror(20, "space after begin expected\n");
505 while (isspace(*s)) s++;
507 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
509 if (strncmp(s, parts[i], strlen(parts[i]))==0)
511 partnum = i+1;
512 s += strlen(parts[i]);
513 while (isspace(*s)) s++;
514 if (*s!='\0')
515 exitfileerror(20, "unexpected character on position %d\n", s-line);
518 if (partnum==0)
519 exitfileerror(20, "unknown start of section\n");
520 switch (partnum)
522 case 1: /* config */
523 readsectionconfig(cfg, cl, in, inclass);
524 hasconfig = 1;
525 break;
527 case 2: /* cdefprivate */
528 if (inclass)
529 exitfileerror(20, "cdefprivate section not allowed in class section\n");
530 readsectioncdefprivate(cfg);
531 break;
533 case 3: /* cdef */
534 if (inclass)
535 exitfileerror(20, "cdef section not allowed in class section\n");
536 readsectioncdef(cfg);
537 break;
539 case 4: /* stubprivate */
540 if (inclass)
541 exitfileerror(20, "stubprivate section not allowed in class section\n");
542 readsectionstubprivate(cfg);
543 break;
545 case 5: /* startup */
546 if (inclass)
547 exitfileerror(20, "startup section not allowed in class section\n");
548 readsectionstartup(cfg);
549 break;
551 case 6: /* functionlist */
552 if (inclass)
553 exitfileerror(20, "functionlist section not allow in class section\n");
554 if (cfg->basename==NULL)
555 exitfileerror(20, "section functionlist has to come after section config\n");
557 readsectionfunctionlist("functionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTERMACRO);
558 cfg->intcfg |= CFG_NOREADFUNCS;
559 break;
561 case 7: /* methodlist */
562 if (cl == NULL && in == NULL)
563 exitfileerror(20, "methodlist section when not in a class or interface\n");
564 if (cl)
565 readsectionclass_methodlist(cl);
566 else
567 readsectionfunctionlist("methodlist", &in->methodlist, 0, 0, REGISTERMACRO);
568 cfg->intcfg |= CFG_NOREADFUNCS;
569 break;
571 case 8: /* class */
572 if (inclass)
573 exitfileerror(20, "class section may not be in nested\n");
574 readsectionclass(cfg);
575 break;
577 case 9: /* handler */
578 readsectionhandler(cfg);
579 break;
581 case 10: /* interface */
582 if (inclass)
583 exitfileerror(20, "interface section may not be nested\n");
584 readsectioninterface(cfg);
585 break;
587 case 11: /* attributelist */
588 if (!in)
589 exitfileerror(20, "attributelist only valid in interface sections\n");
590 readsectionfunctionlist("attributelist", &in->attributelist, 0, 1, INVALID);
591 break;
593 case 12: /* cfunctionlist */
594 if (inclass)
595 exitfileerror(20, "cfunctionlist section not allow in class section\n");
596 if (cfg->basename==NULL)
597 exitfileerror(20, "section cfunctionlist has to come after section config\n");
599 readsectionfunctionlist("cfunctionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTER);
600 cfg->intcfg |= CFG_NOREADFUNCS;
601 break;
604 else if (strlen(line)!=0)
605 filewarning("warning line outside section ignored\n");
608 if(!inclass)
610 if (!hasconfig)
611 exitfileerror(20, "No config section in conffile\n");
613 /* If no indication was given for generating includes or not
614 decide on module type and if there are functions
616 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
618 switch (cfg->modtype)
620 case LIBRARY:
621 case RESOURCE:
622 cfg->options |= OPTION_INCLUDES;
623 break;
625 case HANDLER:
626 case MCC:
627 case MUI:
628 case MCP:
629 case USBCLASS:
630 cfg->options |= OPTION_NOINCLUDES;
631 break;
633 case DEVICE:
634 cfg->options |= (
635 (cfg->funclist != NULL)
636 || (cfg->cdeflines != NULL)
637 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
638 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
639 break;
641 case GADGET:
642 case DATATYPE:
643 case HIDD:
644 cfg->options |= (
645 (cfg->funclist != NULL)
646 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
647 break;
649 default:
650 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
651 exit(20);
652 break;
656 /* If no indication was given for not generating stubs only generate them if
657 * the module has functions
659 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
661 switch (cfg->modtype)
663 case LIBRARY:
664 cfg->options |= (cfg->funclist != NULL) ? OPTION_STUBS : OPTION_NOSTUBS;
665 break;
667 case USBCLASS:
668 case RESOURCE:
669 case GADGET:
670 case DEVICE:
671 case DATATYPE:
672 case MCC:
673 case MUI:
674 case MCP:
675 case HIDD:
676 case HANDLER:
677 cfg->options |= OPTION_NOSTUBS;
678 break;
680 default:
681 fprintf(stderr, "Internal error writemakefile: unhandled modtype for stubs\n");
682 exit(20);
683 break;
687 /* If no indication was given for generating autoinit code or not
688 decide on module type
690 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
692 switch (cfg->modtype)
694 case LIBRARY:
695 cfg->options |= OPTION_AUTOINIT;
696 break;
698 case USBCLASS:
699 case RESOURCE:
700 case GADGET:
701 case DEVICE:
702 case DATATYPE:
703 case MCC:
704 case MUI:
705 case MCP:
706 case HIDD:
707 case HANDLER:
708 cfg->options |= OPTION_NOAUTOINIT;
709 break;
711 default:
712 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
713 exit(20);
714 break;
718 if ((cfg->modtype == RESOURCE) || (cfg->modtype == HANDLER))
719 /* Enforce noopenclose for resources and handlers */
720 cfg->options |= OPTION_NOOPENCLOSE;
721 else if (!(cfg->options & OPTION_SELFINIT))
722 /* Enforce using RTF_AUTOINIT for everything except resources */
723 cfg->options |= OPTION_RESAUTOINIT;
726 return NULL;
729 static void readsectionconfig(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
731 int atend = 0, i;
732 char *line, *s, *s2, *libbasetypeextern = NULL;
733 struct tm date;
735 while (!atend)
737 line = readline();
738 if (line==NULL)
739 exitfileerror(20, "unexpected end of file in section config\n");
741 if (strncmp(line, "##", 2)!=0)
743 const char *names[] =
745 "basename", "libbase", "libbasetype", "libbasetypeextern",
746 "version", "date", "copyright", "libcall", "forcebase", "superclass",
747 "superclass_field", "residentpri", "options", "sysbase_field",
748 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
749 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
750 "initpri", "type", "addromtag", "oopbase_field",
751 "rellib", "interfaceid", "interfacename",
752 "methodstub", "methodbase", "attributebase", "handler_func",
753 "includename"
755 const unsigned int namenums = sizeof(names)/sizeof(char *);
756 unsigned int namenum;
758 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
762 strncmp(line, names[i], strlen(names[i]))==0
763 && isspace(*(line+strlen(names[i])))
765 namenum = i+1;
767 if (namenum==0)
768 exitfileerror(20, "unrecognized configuration option\n");
770 s = line + strlen(names[namenum-1]);
771 if (!isspace(*s))
772 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
774 while (isspace(*s)) s++;
775 if (*s=='\0')
776 exitfileerror(20, "unexpected end of line\n");
778 s2 = s + strlen(s);
779 while (isspace(*(s2-1))) s2--;
780 *s2 = '\0';
782 switch (namenum)
784 case 1: /* basename */
785 if (!inclass)
786 cfg->basename = strdup(s);
787 if (cl != NULL)
788 cl->basename = strdup(s);
789 if (in != NULL)
790 exitfileerror(20, "basename not valid config option when in an interface section\n");
791 break;
793 case 2: /* libbase */
794 if (inclass)
795 exitfileerror(20, "libbase not valid config option when in a class section\n");
796 cfg->libbase = strdup(s);
797 break;
799 case 3: /* libbasetype */
800 if (inclass)
801 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
802 cfg->libbasetype = strdup(s);
803 break;
805 case 4: /* libbasetypeextern */
806 if (inclass)
807 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
808 libbasetypeextern = strdup(s);
809 break;
811 case 5: /* version */
812 if (inclass)
813 exitfileerror(20, "version not valid config option when in a class section\n");
814 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
815 exitfileerror(20, "wrong version string \"%s\"\n", s);
816 break;
818 case 6: /* date */
819 if (inclass)
820 exitfileerror(20, "date not valid config option when in a class section\n");
821 #ifndef _WIN32
822 if (strptime(s, "%e.%m.%Y", &date) == NULL)
824 exitfileerror(20, "date string has to have d.m.yyyy format\n");
826 #endif
827 cfg->datestring = strdup(s);
828 break;
830 case 7: /* copyright */
831 if (inclass)
832 exitfileerror(20, "copyright not valid config option when in a class section\n");
833 cfg->copyright = strdup(s);
834 break;
836 case 8: /* libcall */
837 fprintf(stderr, "libcall specification is deprecated and ignored\n");
838 break;
840 case 9: /* forcebase */
841 if (inclass)
842 exitfileerror(20, "forcebase not valid config option when in a class section\n");
843 slist_append(&cfg->forcelist, s);
844 break;
846 case 10: /* superclass */
847 if (cl == NULL)
848 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
849 cl->superclass = strdup(s);
850 break;
852 case 11: /* superclass_field */
853 if (cl == NULL)
854 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
855 cl->superclass_field = strdup(s);
856 break;
858 case 12: /* residentpri */
859 if (!inclass)
861 int count;
862 char dummy;
864 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
865 if (count != 1 ||
866 cfg->residentpri < -128 || cfg->residentpri > 127
869 exitfileerror(20, "residentpri number format error\n");
872 else
873 exitfileerror(20, "residentpri not valid config option when in a class section\n");
874 break;
876 case 13: /* options */
877 if (!inclass)
879 static const char *optionnames[] =
881 "noautolib", "noexpunge", "noresident", "peropenerbase",
882 "pertaskbase", "includes", "noincludes", "nostubs",
883 "autoinit", "noautoinit", "resautoinit", "noopenclose",
884 "selfinit", "rellinklib"
886 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
887 int optionnum;
891 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
893 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
895 optionnum = i + 1;
896 s += strlen(optionnames[i]);
897 while (isspace(*s)) s++;
898 if (*s == ',')
899 s++;
900 else if (*s != '\0')
901 exitfileerror(20, "Unrecognized option\n");
904 if (optionnum == 0)
905 exitfileerror(20, "Unrecognized option\n");
906 switch (optionnum)
908 case 1: /* noautolib */
909 cfg->options |= OPTION_NOAUTOLIB;
910 break;
911 case 2: /* noexpunge */
912 cfg->options |= OPTION_NOEXPUNGE;
913 break;
914 case 3: /* noresident */
915 cfg->options |= OPTION_NORESIDENT;
916 cfg->firstlvo = 1;
917 break;
918 case 5: /* pertaskbase */
919 cfg->options |= OPTION_PERTASKBASE;
920 /* Fall through */
921 case 4: /* peropenerbase */
922 if (cfg->options & OPTION_DUPBASE)
923 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
924 cfg->options |= OPTION_DUPBASE;
925 break;
926 case 6: /* includes */
927 if (cfg->options & OPTION_NOINCLUDES)
928 exitfileerror(20, "option includes and noincludes are incompatible\n");
929 cfg->options |= OPTION_INCLUDES;
930 break;
931 case 7: /* noincludes */
932 if (cfg->options & OPTION_INCLUDES)
933 exitfileerror(20, "option includes and noincludes are incompatible\n");
934 cfg->options |= OPTION_NOINCLUDES;
935 break;
936 case 8: /* nostubs */
937 cfg->options |= OPTION_NOSTUBS;
938 break;
939 case 9: /* autoinit */
940 if (cfg->options & OPTION_NOAUTOINIT)
941 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
942 cfg->options |= OPTION_AUTOINIT;
943 break;
944 case 10: /* noautoinit */
945 if (cfg->options & OPTION_AUTOINIT)
946 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
947 cfg->options |= OPTION_NOAUTOINIT;
948 break;
949 case 11: /* resautoinit */
950 if (cfg->options & OPTION_SELFINIT)
951 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
952 cfg->options |= OPTION_RESAUTOINIT;
953 break;
954 case 12:
955 cfg->options |= OPTION_NOOPENCLOSE;
956 break;
957 case 13: /* noresautoinit */
958 if (cfg->options & OPTION_RESAUTOINIT)
959 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
960 cfg->options |= OPTION_SELFINIT;
961 break;
962 case 14: /* rellinklib */
963 cfg->options |= OPTION_RELLINKLIB;
964 break;
966 while (isspace(*s)) s++;
967 } while(*s !='\0');
969 else
971 static const char *optionnames[] =
973 "private"
975 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
976 int optionnum;
980 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
982 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
984 optionnum = i + 1;
985 s += strlen(optionnames[i]);
986 while (isspace(*s)) s++;
987 if (*s == ',')
988 s++;
989 else if (*s != '\0')
990 exitfileerror(20, "Unrecognized option\n");
993 if (optionnum == 0)
994 exitfileerror(20, "Unrecognized option\n");
995 switch (optionnum)
997 case 1: /* private */
998 cl->options |= COPTION_PRIVATE;
999 break;
1001 while (isspace(*s)) s++;
1002 } while(*s !='\0');
1004 break;
1006 case 14: /* sysbase_field */
1007 if (inclass)
1008 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
1009 cfg->sysbase_field = strdup(s);
1010 break;
1012 case 15: /* seglist_field */
1013 if (inclass)
1014 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
1015 cfg->seglist_field = strdup(s);
1016 break;
1018 case 16: /* rootbase_field */
1019 if (inclass)
1020 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
1021 cfg->rootbase_field = strdup(s);
1022 break;
1024 case 17: /* classptr_field */
1025 if (cl == NULL)
1027 exitfileerror
1030 "classptr_field specified when not a BOOPSI class\n"
1033 cl->classptr_field = strdup(s);
1034 break;
1036 case 18: /* classptr_var */
1037 if (cl == NULL)
1039 exitfileerror
1042 "classptr_var specified when not a BOOPSI class\n"
1045 cl->classptr_var = strdup(s);
1046 break;
1048 case 19: /* classid */
1049 if (cl == NULL)
1050 exitfileerror(20, "classid specified when not a BOOPSI class\n");
1051 if (cl->classid != NULL)
1052 exitfileerror(20, "classid specified twice\n");
1053 cl->classid = strdup(s);
1054 if (strcmp(cl->classid, "NULL") == 0)
1055 cl->options |= COPTION_PRIVATE;
1056 break;
1058 case 20: /* classdatatype */
1059 if (cl == NULL)
1060 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
1061 cl->classdatatype = strdup(s);
1062 break;
1064 case 21: /* beginio_func */
1065 if (inclass)
1066 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
1067 if (cfg->modtype != DEVICE)
1068 exitfileerror(20, "beginio_func specified when not a device\n");
1069 cfg->beginiofunc = strdup(s);
1070 break;
1072 case 22: /* abortio_func */
1073 if (inclass)
1074 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
1075 if (cfg->modtype != DEVICE)
1076 exitfileerror(20, "abortio_func specified when not a device\n");
1077 cfg->abortiofunc = strdup(s);
1078 break;
1080 case 23: /* dispatcher */
1081 if (cl == NULL)
1082 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
1083 cl->dispatcher = strdup(s);
1084 /* function references are not needed when dispatcher is specified */
1085 cfg->intcfg |= CFG_NOREADFUNCS;
1086 break;
1088 case 24: /* initpri */
1089 if (cl != NULL)
1091 int count;
1092 char dummy;
1094 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
1095 if (count != 1 ||
1096 cl->initpri < -128 || cl->initpri > 127
1099 exitfileerror(20, "initpri number format error\n");
1102 else
1103 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
1104 break;
1106 case 25: /* type */
1107 if (!inclass)
1108 exitfileerror(20, "type only valid config option in a class section\n");
1109 if (strcmp(s,"mcc")==0)
1110 cl->classtype = MCC;
1111 else if (strcmp(s,"mui")==0)
1112 cl->classtype = MUI;
1113 else if (strcmp(s,"mcp")==0)
1114 cl->classtype = MCP;
1115 else if (strcmp(s, "image")==0)
1116 cl->classtype = IMAGE;
1117 else if (strcmp(s, "gadget")==0)
1118 cl->classtype = GADGET;
1119 else if (strcmp(s, "datatype")==0)
1120 cl->classtype = DATATYPE;
1121 else if (strcmp(s, "usbclass")==0)
1122 cl->classtype = USBCLASS;
1123 else if (strcmp(s, "class")==0)
1124 cl->classtype = CLASS;
1125 else if (strcmp(s, "hidd")==0)
1126 cl->classtype = HIDD;
1127 else
1129 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
1130 exit(20);
1132 break;
1134 case 26: /* addromtag */
1135 cfg->addromtag = strdup(s);
1136 break;
1138 case 27: /* oopbase_field */
1139 cfg->oopbase_field = strdup(s);
1140 break;
1141 case 28: /* rellib */
1142 slist_append(&cfg->rellibs, s);
1143 break;
1144 case 29: /* interfaceid */
1145 if (!in)
1146 exitfileerror(20, "interfaceid only valid config option for an interface\n");
1147 in->interfaceid = strdup(s);
1148 break;
1149 case 30: /* interfacename */
1150 if (!in)
1151 exitfileerror(20, "interfacename only valid config option for an interface\n");
1152 in->interfacename = strdup(s);
1153 break;
1154 case 31: /* methodstub */
1155 if (!in)
1156 exitfileerror(20, "methodstub only valid config option for an interface\n");
1157 in->methodstub = strdup(s);
1158 break;
1159 case 32: /* methodbase */
1160 if (!in)
1161 exitfileerror(20, "methodbase only valid config option for an interface\n");
1162 in->methodbase = strdup(s);
1163 break;
1164 case 33: /* attributebase */
1165 if (!in)
1166 exitfileerror(20, "attributebase only valid config option for an interface\n");
1167 in->attributebase = strdup(s);
1168 break;
1169 case 34: /* handler_func */
1170 if (cfg->modtype != HANDLER)
1171 exitfileerror(20, "handler specified when not a handler\n");
1172 cfg->handlerfunc = strdup(s);
1173 break;
1174 case 35: /* includename */
1175 if (inclass)
1176 exitfileerror(20, "includename not valid config option"
1177 " when in a class section\n");
1178 cfg->includename = strdup(s);
1179 break;
1182 else /* Line starts with ## */
1184 s = line+2;
1185 while (isspace(*s)) s++;
1186 if (strncmp(s, "end", 3)!=0)
1187 exitfileerror(20, "\"##end config\" expected\n");
1189 s += 3;
1190 if (!isspace(*s))
1191 exitfileerror(20, "\"##end config\" expected\n");
1193 while (isspace(*s)) s++;
1194 if (strncmp(s, "config", 6)!=0)
1195 exitfileerror(20, "\"##end config\" expected\n");
1197 s += 6;
1198 while (isspace(*s)) s++;
1199 if (*s!='\0')
1200 exitfileerror(20, "\"##end config\" expected\n");
1202 atend = 1;
1206 /* When not in a class section fill in default values for fields in cfg */
1207 if (!inclass)
1209 if (cfg->basename==NULL)
1211 cfg->basename = strdup(cfg->modulename);
1212 *cfg->basename = toupper(*cfg->basename);
1214 if (cfg->libbase==NULL)
1216 unsigned int len = strlen(cfg->basename)+5;
1217 cfg->libbase = malloc(len);
1218 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1220 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1221 cfg->libbasetype = strdup(libbasetypeextern);
1222 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1223 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1224 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1225 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1226 if (cfg->oopbase_field != NULL && cfg->libbasetype == NULL)
1227 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1228 /* rootbase_field only allowed when duplicating base */
1229 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1230 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1232 /* Set default date to current date */
1233 if (cfg->datestring == NULL)
1235 char tmpbuf[256];
1236 time_t now = time(NULL);
1237 struct tm *ltime = localtime(&now);
1239 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1240 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1242 cfg->datestring = strdup(tmpbuf);
1245 if (cfg->copyright == NULL)
1246 cfg->copyright = "";
1248 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1249 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1251 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1253 if (libbasetypeextern==NULL)
1255 switch (cfg->modtype)
1257 case DEVICE:
1258 cfg->libbasetypeptrextern = "struct Device *";
1259 break;
1260 case HANDLER:
1261 case RESOURCE:
1262 cfg->libbasetypeptrextern = "APTR ";
1263 break;
1264 case LIBRARY:
1265 case MUI:
1266 case MCP:
1267 case MCC:
1268 case GADGET:
1269 case DATATYPE:
1270 case USBCLASS:
1271 case HIDD:
1272 cfg->libbasetypeptrextern = "struct Library *";
1273 break;
1274 default:
1275 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1276 exit(20);
1279 else
1281 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1282 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1283 strcat(cfg->libbasetypeptrextern, " *");
1284 free(libbasetypeextern);
1287 if (cfg->includename == NULL)
1288 cfg->includename = cfg->modulename;
1289 cfg->includenameupper = strdup(cfg->includename);
1290 for (s=cfg->includenameupper; *s!='\0'; *s = toupper(*s), s++)
1291 if (!isalnum(*s)) *s = '_';
1294 /* When class was given too fill in some defaults when not specified */
1295 if (cl != NULL)
1297 if (cl->classtype == UNSPECIFIED)
1298 cl->classtype = CLASS;
1300 if (cl->basename == NULL)
1302 if (!inclass)
1303 cl->basename = cfg->basename;
1304 else
1305 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1308 /* MUI classes are always private */
1309 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1310 cl->options |= COPTION_PRIVATE;
1312 if (cl->classid == NULL
1313 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1316 if (cl->classtype == HIDD)
1318 cl->options &= !COPTION_PRIVATE;
1320 else if (cl->options & COPTION_PRIVATE)
1322 cl->classid = "NULL";
1324 else
1326 char s[256] = "";
1328 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1330 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1332 else if (cl->classtype == DATATYPE)
1334 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1336 cl->classid = strdup(s);
1340 /* Only specify superclass or superclass_field */
1341 if (cl->superclass != NULL && cl->superclass_field != NULL)
1342 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1344 /* Give default value to superclass if it is not specified */
1345 if (cl->superclass == NULL && cl->superclass == NULL)
1347 switch (cl->classtype)
1349 case MUI:
1350 case MCC:
1351 cl->superclass = "MUIC_Area";
1352 break;
1353 case MCP:
1354 cl->superclass = "MUIC_Mccprefs";
1355 break;
1356 case IMAGE:
1357 cl->superclass = "IMAGECLASS";
1358 break;
1359 case GADGET:
1360 cl->superclass = "GADGETCLASS";
1361 break;
1362 case DATATYPE:
1363 cl->superclass = "DATATYPESCLASS";
1364 break;
1365 case CLASS:
1366 cl->superclass = "ROOTCLASS";
1367 break;
1368 case HIDD:
1369 cl->superclass = "CLID_Root";
1370 break;
1371 default:
1372 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1373 break;
1379 static void readsectioncdef(struct config *cfg)
1381 int atend = 0;
1382 char *line, *s;
1384 while (!atend)
1386 line = readline();
1387 if (line==NULL)
1388 exitfileerror(20, "unexptected end of file in section cdef\n");
1390 if (strncmp(line, "##", 2)!=0)
1392 slist_append(&cfg->cdeflines, line);
1394 else
1396 s = line+2;
1397 while (isspace(*s)) s++;
1398 if (strncmp(s, "end", 3)!=0)
1399 exitfileerror(20, "\"##end cdef\" expected\n");
1401 s += 3;
1402 while (isspace(*s)) s++;
1403 if (strncmp(s, "cdef", 4)!=0)
1404 exitfileerror(20, "\"##end cdef\" expected\n");
1406 s += 5;
1407 while (isspace(*s)) s++;
1408 if (*s!='\0')
1409 exitfileerror(20, "unexpected character at position %d\n");
1411 atend = 1;
1417 static void readsectionstubprivate(struct config *cfg)
1419 int atend = 0;
1420 char *line, *s;
1422 while (!atend)
1424 line = readline();
1425 if (line==NULL)
1426 exitfileerror(20, "unexptected end of file in section stubprivate\n");
1428 if (strncmp(line, "##", 2)!=0)
1430 slist_append(&cfg->stubprivatelines, line);
1432 else
1434 s = line+2;
1435 while (isspace(*s)) s++;
1436 if (strncmp(s, "end", 3)!=0)
1437 exitfileerror(20, "\"##end stubprivate\" expected\n");
1439 s += 3;
1440 while (isspace(*s)) s++;
1441 if (strncmp(s, "stubprivate", 11)!=0)
1442 exitfileerror(20, "\"##end stubprivate\" expected\n");
1444 s += 11;
1445 while (isspace(*s)) s++;
1446 if (*s!='\0')
1447 exitfileerror(20, "unexpected character at position %d\n");
1449 atend = 1;
1454 static void readsectioncdefprivate(struct config *cfg)
1456 int atend = 0;
1457 char *line, *s;
1459 while (!atend)
1461 line = readline();
1462 if (line==NULL)
1463 exitfileerror(20, "unexptected end of file in section cdefprivate\n");
1465 if (strncmp(line, "##", 2)!=0)
1467 slist_append(&cfg->cdefprivatelines, line);
1469 else
1471 s = line+2;
1472 while (isspace(*s)) s++;
1473 if (strncmp(s, "end", 3)!=0)
1474 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1476 s += 3;
1477 while (isspace(*s)) s++;
1478 if (strncmp(s, "cdefprivate", 11)!=0)
1479 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1481 s += 11;
1482 while (isspace(*s)) s++;
1483 if (*s!='\0')
1484 exitfileerror(20, "unexpected character at position %d\n");
1486 atend = 1;
1491 static void readsectionstartup(struct config *cfg)
1493 int atend = 0;
1494 char *line, *s;
1496 while (!atend)
1498 line = readline();
1499 if (line==NULL)
1500 exitfileerror(20, "unexptected end of file in section startup\n");
1502 if (strncmp(line, "##", 2)!=0)
1504 slist_append(&cfg->startuplines, line);
1506 else
1508 s = line+2;
1509 while (isspace(*s)) s++;
1510 if (strncmp(s, "end", 3)!=0)
1511 exitfileerror(20, "\"##end startup\" expected\n");
1513 s += 3;
1514 while (isspace(*s)) s++;
1515 if (strncmp(s, "startup", 7)!=0)
1516 exitfileerror(20, "\"##end startup\" expected\n");
1518 s += 7;
1519 while (isspace(*s)) s++;
1520 if (*s!='\0')
1521 exitfileerror(20, "unexpected character at position %d\n");
1523 atend = 1;
1528 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall)
1530 int atend = 0, i;
1531 char *line, *s, *s2;
1532 unsigned int lvo = firstlvo;
1533 int minversion = -1;
1535 while (!atend)
1537 line = readline();
1538 if (line==NULL)
1539 exitfileerror(20, "unexpected EOF in functionlist section\n");
1540 if (strlen(line)==0)
1542 if (*funclistptr != NULL)
1543 funclistptr = &((*funclistptr)->next);
1544 lvo++;
1546 else if (isspace(*line))
1548 s = line;
1549 while (isspace(*s)) s++;
1550 if (*s=='\0')
1552 if (*funclistptr != NULL)
1553 funclistptr = &((*funclistptr)->next);
1554 lvo++;
1556 else
1557 exitfileerror(20, "no space allowed before functionname\n");
1559 else if (strncmp(line, "##", 2)==0)
1561 s = line+2;
1562 while (isspace(*s)) s++;
1563 if (strncmp(s, "end", 3)!=0)
1564 exitfileerror(20, "\"##end %s\" expected\n", type);
1566 s += 3;
1567 while (isspace(*s)) s++;
1568 if (strncmp(s, type, strlen(type))!=0)
1569 exitfileerror(20, "\"##end %s\" expected\n", type);
1571 s += strlen(type);
1572 while (isspace(*s)) s++;
1573 if (*s!='\0')
1574 exitfileerror(20, "unexpected character on position %d\n", s-line);
1576 atend = 1;
1578 else if (*line=='.')
1580 s = line+1;
1581 if (strncmp(s, "skip", 4)==0)
1583 int n;
1585 s += 4;
1586 if (!isspace(*s))
1587 exitfileerror(20, "syntax is '.skip n'\n");
1589 n=strtol(s, &s2, 10);
1590 if (s2==NULL)
1591 exitfileerror(20, "positive number expected\n");
1593 while (isspace(*s2)) s2++;
1594 if ((*s2 != '\0') && (*s2 != '#'))
1595 exitfileerror(20, "syntax is '.skip n'\n");
1596 if (*funclistptr != NULL)
1597 funclistptr = &((*funclistptr)->next);
1598 lvo += n;
1600 else if (strncmp(s, "alias", 5)==0)
1602 s += 5;
1604 if (!isspace(*s))
1605 exitfileerror(20, "syntax is '.alias name'\n");
1607 while (isspace(*s)) s++;
1608 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1609 exitfileerror(20, "syntax is '.alias name'\n");
1611 s2 = s;
1612 s++;
1613 while (isalnum(*s) || *s == '_') s++;
1615 if (isspace(*s))
1617 *s = '\0';
1618 do {
1619 s++;
1620 } while (isspace(*s));
1623 if (*s != '\0')
1624 exitfileerror(20, "syntax is '.alias name'\n");
1626 if (*funclistptr == NULL)
1627 exitfileerror(20, ".alias has to come after a function declaration\n");
1629 slist_append(&(*funclistptr)->aliases, s2);
1631 else if (strncmp(s, "function", 8) == 0)
1633 s += 8;
1635 if (!isspace(*s))
1636 exitfileerror(20, "Syntax error\n");
1638 while (isspace(*s)) s++;
1639 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1640 exitfileerror(20, "syntax is '.function name'\n");
1642 s2 = s;
1643 s++;
1644 while (isalnum(*s) || *s == '_') s++;
1646 if (isspace(*s))
1648 *s = '\0';
1649 do {
1650 s++;
1651 } while (isspace(*s));
1654 if (*s != '\0')
1655 exitfileerror(20, "syntax is '.function name'\n");
1657 if (*funclistptr == NULL)
1658 exitfileerror(20, ".function has to come after a function declaration\n");
1660 funcsetinternalname(*funclistptr, s2);
1662 else if (strncmp(s, "cfunction", 9)==0)
1664 if (*funclistptr == NULL)
1665 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1667 (*funclistptr)->libcall = REGISTER;
1669 else if (strncmp(s, "private", 7)==0)
1671 if (*funclistptr == NULL)
1672 exitfileerror(20, ".private has to come after a function declaration\n");
1674 (*funclistptr)->priv = 1;
1676 else if (strncmp(s, "novararg", 8)==0)
1678 if (*funclistptr == NULL)
1679 exitfileerror(20, ".novararg has to come after a function declaration\n");
1681 (*funclistptr)->novararg = 1;
1683 else if (strncmp(s, "version", 7) == 0)
1685 /* Mark version number for the following
1686 * functions, so that the automatic OpenLibrary()
1687 * will know what version to use.
1689 char *tmp;
1690 int ver;
1692 s += 7;
1694 while (isspace(*s)) s++;
1695 ver = (int)strtol(s, &tmp, 0);
1697 if (s == tmp)
1698 exitfileerror(20, ".version expects an integer\n");
1700 s = tmp;
1701 while (isspace(*s)) s++;
1703 if (*s && *s != '#')
1704 exitfileerror(20, ".version has junk after the version number\n");
1706 minversion = ver;
1708 else if (strncmp(s, "unusedlibbase", 13) == 0)
1710 if (*funclistptr == NULL)
1711 exitfileerror(20, ".unusedlibbase has to come after a function declaration\n");
1712 (*funclistptr)->unusedlibbase = 1;
1714 else
1715 exitfileerror(20, "Syntax error");
1717 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1719 /* The line is a function or attribute prototype.
1720 * A function can have one of two syntaxes:
1721 * type funcname(argproto1, argproto2, ...)
1722 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1723 * The former is for C type function argument passing, the latter for
1724 * register argument passing.
1725 * An attribute has the following syntax:
1726 * type attribute
1728 char c, *args[64], *regs[64], *funcname, *cp;
1729 int len, argcount = 0, regcount = 0, brcount = 0;
1731 cp = strchr(line,'#');
1732 if (cp)
1733 *(cp++) = 0;
1735 /* Parse 'type functionname' at the beginning of the line */
1736 if (isattribute) {
1737 s = line + strlen(line);
1738 } else {
1739 s = strchr(line, '(');
1740 if (s == NULL)
1741 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1744 s2 = s;
1745 while (isspace(*(s2-1)))
1746 s2--;
1747 *s2 = '\0';
1749 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1750 s2--;
1752 if (s2 == line)
1753 exitfileerror(20, "No type specifier before %s name\n", isattribute ? "attribute" : "function");
1755 if (*funclistptr != NULL)
1756 funclistptr = &((*funclistptr)->next);
1757 *funclistptr = newfunctionhead(s2, STACK);
1759 if (cp)
1760 (*funclistptr)->comment = strdup(cp);
1761 else
1762 (*funclistptr)->comment = NULL;
1764 while (isspace(*(s2-1)))
1765 s2--;
1766 *s2 = '\0';
1767 (*funclistptr)->type = strdup(line);
1768 (*funclistptr)->lvo = lvo;
1769 (*funclistptr)->version = minversion;
1770 lvo++;
1772 if (isattribute)
1773 continue;
1775 /* Parse function prototype */
1776 s++;
1777 while (isspace(*s))
1778 s++;
1779 c = *s;
1781 while (c != ')')
1783 while (isspace(*s))
1784 s++;
1786 args[argcount] = s;
1787 argcount++;
1789 while
1791 *s != '\0'
1792 && !(brcount == 0 && (*s == ',' || *s == ')'))
1795 if (*s == '(')
1796 brcount++;
1797 if (*s == ')')
1799 if (brcount > 0)
1800 brcount--;
1801 else
1802 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1804 s++;
1807 c = *s;
1808 if (c == '\0')
1809 exitfileerror(20, "'(' without ')'");
1811 s2 = s;
1812 while (isspace(*(s2-1)))
1813 s2--;
1814 *s2 = '\0';
1816 if (!(s2 > args[argcount - 1]))
1817 exitfileerror(20, "Syntax error in function prototype\n");
1819 s++;
1822 s++;
1823 while (*s != '\0' && isspace(*s))
1824 s++;
1826 if (*s == '(')
1828 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1830 /* There may be no register specified with () so be sure then c is == ')' */
1831 s++;
1832 while(isspace(*s))
1833 s++;
1835 c = *s;
1837 while (c != ')')
1839 while (isspace(*s))
1840 s++;
1842 regs[regcount] = s;
1843 regcount++;
1845 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1847 s += 2;
1848 c = *s;
1849 if (c == '/')
1851 s++;
1852 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1854 s += 2;
1855 c = *s;
1857 else
1858 exitfileerror(20,
1859 "wrong register specification \"%s\" for argument %u\n",
1860 regs[regcount-1], regcount
1863 if (regcount > 4)
1864 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount, regs[regcount-1]);
1866 *s = '\0';
1868 else
1869 exitfileerror(20,
1870 "wrong register \"%s\" for argument %u\n",
1871 regs[regcount-1], regcount
1874 while (isspace(c))
1876 s++;
1877 c = *s;
1879 if (c == '\0')
1880 exitfileerror(20, "'(' without ')'\n");
1881 if (c != ',' && c != ')')
1882 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1884 s++;
1887 s++;
1888 while (isspace(*s)) s++;
1889 if (*s!='\0')
1890 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1892 if (argcount != regcount)
1893 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1894 argcount, regcount
1897 (*funclistptr)->libcall = def_libcall;
1898 for (i = 0; i < argcount; i++)
1899 funcaddarg(*funclistptr, args[i], regs[i]);
1901 else if (*s == '\0')
1902 { /* No registers specified */
1903 for (i = 0; i < argcount; i++)
1904 funcaddarg(*funclistptr, args[i], NULL);
1906 else
1907 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1912 static void readsectionclass_methodlist(struct classinfo *cl)
1914 int atend = 0, i;
1915 char *line, *s, *s2;
1916 struct functionhead **methlistptr = &cl->methlist;
1917 struct stringlist *interface = NULL;
1919 if (cl->basename==NULL)
1920 exitfileerror(20, "section methodlist has to come after section config\n");
1922 while (!atend)
1924 line = readline();
1925 if (line==NULL)
1926 exitfileerror(20, "unexptected EOF in methodlist section\n");
1928 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1929 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1930 continue;
1932 if (isspace(*line))
1933 exitfileerror(20, "No space allowed at start of the line\n");
1935 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1937 s = line+2;
1938 while (isspace(*s)) s++;
1939 if (strncmp(s, "end", 3)!=0)
1940 exitfileerror(20, "\"##end methodlist\" expected\n");
1942 s += 3;
1943 while (isspace(*s)) s++;
1944 if (strncmp(s, "methodlist", 10)!=0)
1945 exitfileerror(20, "\"##end methodlist\" expected\n");
1947 s += 10;
1948 while (isspace(*s)) s++;
1949 if (*s!='\0')
1950 exitfileerror(20, "unexpected character on position %d\n", s-line);
1952 atend = 1;
1954 continue;
1957 if (*line=='.')
1959 s = line+1;
1960 if (strncmp(s, "alias", 5)==0)
1962 s += 5;
1964 if (!isspace(*s))
1965 exitfileerror(20, "syntax is '.alias name'\n");
1967 while (isspace(*s)) s++;
1968 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1969 exitfileerror(20, "syntax is '.alias name'\n");
1971 s2 = s;
1972 s++;
1973 while (isalnum(*s) || *s == '_') s++;
1975 if (isspace(*s))
1977 *s = '\0';
1978 do {
1979 s++;
1980 } while (isspace(*s));
1983 if (*s != '\0')
1984 exitfileerror(20, "syntax is '.alias name'\n");
1986 if (*methlistptr == NULL)
1987 exitfileerror(20, ".alias has to come after a function declaration\n");
1989 slist_append(&(*methlistptr)->aliases, s2);
1991 else if (strncmp(s, "function", 8) == 0)
1993 s += 8;
1995 if (!isspace(*s))
1996 exitfileerror(20, "Syntax error\n");
1998 while (isspace(*s)) s++;
1999 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
2000 exitfileerror(20, "syntax is '.function name'\n");
2002 s2 = s;
2003 s++;
2004 while (isalnum(*s) || *s == '_') s++;
2006 if (isspace(*s))
2008 *s = '\0';
2009 do {
2010 s++;
2011 } while (isspace(*s));
2014 if (*s != '\0')
2015 exitfileerror(20, "syntax is '.function name'\n");
2017 if (*methlistptr == NULL)
2018 exitfileerror(20, ".function has to come after a function declaration\n");
2020 funcsetinternalname(*methlistptr, s2);
2022 else if (strncmp(s, "interface", 9) == 0)
2024 if (cl->classtype != HIDD)
2025 exitfileerror(20, "interface only valid for a HIDD\n");
2027 s += 9;
2029 if (!isspace(*s))
2030 exitfileerror(20, "Syntax error\n");
2032 while (isspace(*s)) s++;
2033 if (*s == '\0' || !isalpha(*s))
2034 exitfileerror(20, "syntax is '.interface name'\n");
2036 s2 = s;
2037 s++;
2038 while (isalnum(*s) || *s == '_') s++;
2040 if (isspace(*s))
2042 *s = '\0';
2043 do {
2044 s++;
2045 } while (isspace(*s));
2048 if (*s != '\0')
2049 exitfileerror(20, "syntax is '.interface name'\n");
2051 interface = slist_append(&cl->interfaces, s2);
2053 else
2054 exitfileerror(20, "Syntax error");
2056 else if (isalpha(*line))
2058 char stmp[256];
2060 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
2063 if (cl->classtype == HIDD && interface == NULL)
2064 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
2066 if (*s != '\0')
2067 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
2069 if (*methlistptr != NULL)
2070 methlistptr = &((*methlistptr)->next);
2071 if (cl->classtype != HIDD)
2073 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
2074 exitfileerror(20, "Method name too large\n");
2076 *methlistptr = newfunctionhead(stmp, STACK);
2077 (*methlistptr)->type = "IPTR";
2078 funcaddarg(*methlistptr, "Class *cl", NULL);
2079 funcaddarg(*methlistptr, "Object *o", NULL);
2080 funcaddarg(*methlistptr, "Msg msg", NULL);
2082 else
2084 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
2085 exitfileerror(20, "Method name too large\n");
2087 *methlistptr = newfunctionhead(stmp, STACK);
2088 (*methlistptr)->type = "IPTR";
2089 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
2090 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
2091 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
2092 (*methlistptr)->interface = interface;
2093 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
2094 exitfileerror(20, "Method name too large\n");
2095 (*methlistptr)->method = strdup(stmp);
2097 slist_append(&(*methlistptr)->aliases, line);
2099 else
2100 exitfileerror(20, "Methodname has to begin with a letter\n");
2104 static void
2105 readsectioninterface(struct config *cfg)
2107 char *s;
2108 struct interfaceinfo *in;
2110 in = newinterface(cfg);
2111 s = readsections(cfg, NULL, in, 1);
2112 if (s == NULL)
2113 exitfileerror(20, "Unexpected end of file\n");
2115 if (strncmp(s, "##", 2) != 0)
2116 exitfileerror(20, "'##end interface' expected\n");
2117 s += 2;
2119 while (isspace(*s)) s++;
2121 if (strncmp(s, "end", 3) != 0)
2122 exitfileerror(20, "'##end interface' expected\n");
2123 s += 3;
2125 if (!isspace(*s))
2126 exitfileerror(20, "'##end interface' expected\n");
2127 while (isspace(*s)) s++;
2129 if (strncmp(s, "interface", 9) != 0)
2130 exitfileerror(20, "'##end interface' expected\n");
2131 s += 9;
2133 while (isspace(*s)) s++;
2134 if (*s != '\0')
2135 exitfileerror(20, "'##end interface' expected\n");
2137 if (!in->interfaceid)
2138 exitfileerror(20, "interface has no 'interfaceid' defined!\n");
2140 if (!in->interfacename)
2141 exitfileerror(20, "interface has no 'interfacename' defined!\n");
2143 if (!in->methodstub)
2144 in->methodstub = strdup(in->interfacename);
2146 if (!in->methodbase) {
2147 int len = strlen(in->interfacename);
2148 in->methodbase = malloc(len + 4 + 1);
2149 strcpy(in->methodbase, in->interfacename);
2150 strcat(in->methodbase, "Base");
2153 if (!in->attributebase) {
2154 int len = strlen(in->interfacename);
2155 in->attributebase = malloc(len + 4 + 4 + 1);
2156 strcpy(in->attributebase, in->interfacename);
2157 strcat(in->attributebase, "AttrBase");
2161 static void
2162 readsectionclass(struct config *cfg)
2164 char *s;
2165 struct classinfo *cl;
2167 cl = newclass(cfg);
2168 s = readsections(cfg, cl, NULL, 1);
2169 if (s == NULL)
2170 exitfileerror(20, "Unexpected end of file\n");
2172 if (strncmp(s, "##", 2) != 0)
2173 exitfileerror(20, "'##end class' expected\n");
2174 s += 2;
2176 while (isspace(*s)) s++;
2178 if (strncmp(s, "end", 3) != 0)
2179 exitfileerror(20, "'##end class' expected\n");
2180 s += 3;
2182 if (!isspace(*s))
2183 exitfileerror(20, "'##end class' expected\n");
2184 while (isspace(*s)) s++;
2186 if (strncmp(s, "class", 5) != 0)
2187 exitfileerror(20, "'##end class' expected\n");
2188 s += 5;
2190 while (isspace(*s)) s++;
2191 if (*s != '\0')
2192 exitfileerror(20, "'##end class' expected\n");
2195 static struct classinfo *newclass(struct config *cfg)
2197 struct classinfo *cl, *classlistit;
2199 cl = malloc(sizeof(struct classinfo));
2200 if (cl == NULL)
2202 fprintf(stderr, "Out of memory\n");
2203 exit(20);
2205 memset(cl, 0, sizeof(struct classinfo));
2207 /* By default the classes are initialized with a priority of 1 so they
2208 * are initialized before any user added initialization with priority 1
2210 cl->initpri = 1;
2212 if (cfg->classlist == NULL)
2213 cfg->classlist = cl;
2214 else
2218 classlistit = cfg->classlist;
2219 classlistit->next != NULL;
2220 classlistit = classlistit->next
2223 classlistit->next = cl;
2226 return cl;
2229 static struct handlerinfo *newhandler(struct config *cfg)
2231 struct handlerinfo *hl;
2233 hl = calloc(1,sizeof(*hl));
2234 hl->next = cfg->handlerlist;
2235 cfg->handlerlist = hl;
2236 return hl;
2239 static struct interfaceinfo *newinterface(struct config *cfg)
2241 struct interfaceinfo *in, *interfacelistit;
2243 in = malloc(sizeof(struct interfaceinfo));
2244 if (in == NULL)
2246 fprintf(stderr, "Out of memory\n");
2247 exit(20);
2249 memset(in, 0, sizeof(struct interfaceinfo));
2251 if (cfg->interfacelist == NULL)
2252 cfg->interfacelist = in;
2253 else
2257 interfacelistit = cfg->interfacelist;
2258 interfacelistit->next != NULL;
2259 interfacelistit = interfacelistit->next
2262 interfacelistit->next = in;
2265 return in;
2269 static int getdirective(char *s, const char *directive, int range_min, int range_max, int *val)
2271 char *tmp;
2272 int newval;
2274 if (strncmp(s, directive, strlen(directive)) != 0)
2275 return 0;
2277 s += strlen(directive);
2278 if (*s && !isspace(*s))
2279 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive);
2281 while (isspace(*s)) s++;
2282 if (!*s)
2283 exitfileerror(20, "No .%s value specified\n", directive);
2285 newval = strtol(s, &tmp, 0);
2286 if (s == tmp || !(newval >= range_min && newval <= range_max)) {
2287 tmp = s;
2288 while (*tmp && !isspace(*tmp)) tmp++;
2289 exitfileerror(20, "Invalid .%s value of %.*s\n", directive, tmp - s, s);
2292 *val = newval;
2293 return 1;
2296 static void
2297 readsectionhandler(struct config *cfg)
2299 char *line = NULL, *s;
2300 struct handlerinfo *hl;
2301 unsigned char autolevel = 0;
2302 unsigned int stacksize = 0;
2303 int startup = 0;
2304 char priority = 10;
2305 int bootpri = -128;
2306 int has_filesystem = 0;
2308 for (;;)
2310 char *function;
2311 int function_len;
2312 char *tmp;
2314 s = line = readline();
2316 if (s==NULL)
2317 exitfileerror(20, "unexpected end of file in section hanlder\n");
2319 if (strncmp(s, "##", 2)==0)
2320 break;
2322 /* Ignore comments */
2323 if (strncmp(s, "#", 1)==0)
2324 continue;
2326 /* Skip ahead to function name */
2327 while (*s && isspace(*s)) s++;
2329 /* Permit blank lines */
2330 if (!*s)
2331 continue;
2333 if (*s == '.') {
2334 int val;
2335 s++;
2337 if (getdirective(s, "autodetect", 0, 127, &val)) {
2338 autolevel = val;
2339 } else if (getdirective(s, "stacksize", 0, INT_MAX, &val)) {
2340 stacksize = val;
2341 } else if (getdirective(s, "priority", -128, 127, &val)) {
2342 priority = val;
2343 } else if (getdirective(s, "bootpri", -128, 127, &val)) {
2344 bootpri = val;
2345 } else if (getdirective(s, "startup", INT_MIN, INT_MAX, &val)) {
2346 startup = val;
2347 } else {
2348 exitfileerror(20, "Unrecognized directive \"%s\"\n", line);
2350 continue;
2353 do {
2354 unsigned int id = 0;
2356 if (strncasecmp(s,"resident=",9)==0) {
2357 char *res;
2359 s = strchr(s, '=') + 1;
2360 res = s;
2361 while (*s && !isspace(*s)) s++;
2362 if (res == s)
2363 exitfileerror(20, "Empty resident= is not permitted\n");
2365 if (*s)
2366 *(s++) = 0;
2368 hl = newhandler(cfg);
2369 hl->type = HANDLER_RESIDENT;
2370 hl->id = 0;
2371 hl->name = strdup(res);
2372 hl->autodetect = autolevel--;
2373 hl->stacksize = stacksize;
2374 hl->priority = priority;
2375 hl->startup = startup;
2376 } else if (strncasecmp(s,"dosnode=",8)==0) {
2377 char *dev;
2379 s = strchr(s, '=') + 1;
2380 dev = s;
2381 while (*s && !isspace(*s)) s++;
2382 if (dev == s)
2383 exitfileerror(20, "Empty dosnode= is not permitted\n");
2385 if (*s)
2386 *(s++) = 0;
2388 hl = newhandler(cfg);
2389 hl->type = HANDLER_DOSNODE;
2390 hl->id = 0;
2391 hl->name = strdup(dev);
2392 hl->autodetect = autolevel ? autolevel-- : 0;
2393 hl->stacksize = stacksize;
2394 hl->priority = priority;
2395 hl->startup = startup;
2396 hl->bootpri = bootpri;
2397 } else if (strncasecmp(s,"dostype=",8) == 0) {
2398 s = strchr(s, '=') + 1;
2400 id = (unsigned int)strtoul(s, &tmp, 0);
2402 if (s == tmp) {
2403 while (*tmp && !isspace(*tmp))
2404 tmp++;
2405 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp -s), s);
2407 s = tmp;
2409 if (id == 0 || id == ~0) {
2410 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id);
2413 hl = newhandler(cfg);
2414 hl->type = HANDLER_DOSTYPE;
2415 hl->id = id;
2416 hl->name = NULL;
2417 hl->autodetect = autolevel ? autolevel-- : 0;
2418 hl->stacksize = stacksize;
2419 hl->priority = priority;
2420 hl->startup = startup;
2421 } else {
2422 for (tmp = s; !isspace(*tmp); tmp++);
2423 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp - s, s);
2426 /* Advance to next ID */
2427 while (*s && isspace(*s)) s++;
2429 } while (*s);
2432 if (s == NULL)
2433 exitfileerror(20, "Unexpected end of file\n");
2435 if (strncmp(s, "##", 2) != 0)
2436 exitfileerror(20, "'##end handler' expected\n");
2437 s += 2;
2439 while (isspace(*s)) s++;
2441 if (strncmp(s, "end", 3) != 0)
2442 exitfileerror(20, "'##end handler' expected\n");
2443 s += 3;
2445 while (isspace(*s)) s++;
2447 if (strncmp(s, "handler", 7) != 0)
2448 exitfileerror(20, "'##end handler' expected\n");
2449 s += 7;
2451 while (isspace(*s)) s++;
2452 if (*s != '\0')
2453 exitfileerror(20, "'##end handler' expected\n");