Fix for compile with enabled debug support. return value of function is not in variab...
[AROS.git] / tools / genmodule / config.c
blob252c473a3e6b0d2217d13bbf04d4731948874067
1 /*
2 Copyright © 1995-2014, 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] [-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: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 'v':
134 cfg->versionextra = optarg;
135 break;
137 default:
138 fprintf(stderr, "Internal error: Unhandled option\n");
139 exit(20);
143 if (optind + 3 != argc)
145 fprintf(stderr, "Wrong number of arguments.\n%s", usage);
146 exit(20);
149 if (strcmp(argv[optind], "writefiles") == 0)
151 cfg->command = FILES;
153 else if (strcmp(argv[optind], "writemakefile") == 0)
155 cfg->command = MAKEFILE;
157 else if (strcmp(argv[optind], "writeincludes") == 0)
159 cfg->command = INCLUDES;
161 else if (strcmp(argv[optind], "writelibdefs") == 0)
163 cfg->command = LIBDEFS;
165 else if (strcmp(argv[optind], "writefunclist") == 0)
167 cfg->command = WRITEFUNCLIST;
169 else if (strcmp(argv[optind], "writefd") == 0)
171 cfg->command = WRITEFD;
173 else if (strcmp(argv[optind], "writeskel") == 0)
175 cfg->command = WRITESKEL;
177 else if (strcmp(argv[optind], "writethunk") == 0)
179 cfg->command = WRITETHUNK;
181 else
183 fprintf(stderr, "Unrecognized argument \"%s\"\n%s", argv[optind], usage);
184 exit(20);
187 cfg->modulename = argv[optind+1];
188 cfg->modulenameupper = strdup(cfg->modulename);
189 for (s=cfg->modulenameupper; *s!='\0'; *s = toupper(*s), s++) {
190 if (!isalnum(*s)) *s = '_';
193 if (strcmp(argv[optind+2],"library")==0)
195 cfg->modtype = LIBRARY;
196 cfg->moddir = "Libs";
198 else if (strcmp(argv[optind+2],"mcc")==0)
200 cfg->modtype = MCC;
201 cfg->moddir = "Classes/Zune";
203 else if (strcmp(argv[optind+2],"mui")==0)
205 cfg->modtype = MUI;
206 cfg->moddir = "Classes/Zune";
208 else if (strcmp(argv[optind+2],"mcp")==0)
210 cfg->modtype = MCP;
211 cfg->moddir = "Classes/Zune";
213 else if (strcmp(argv[optind+2], "device")==0)
215 cfg->modtype = DEVICE;
216 cfg->moddir = "Devs";
218 else if (strcmp(argv[optind+2], "resource")==0)
220 cfg->modtype = RESOURCE;
221 cfg->moddir = "Devs";
223 else if (strcmp(argv[optind+2], "gadget")==0)
225 cfg->modtype = GADGET;
226 cfg->moddir = "Classes/Gadgets";
228 else if (strcmp(argv[optind+2], "datatype")==0)
230 cfg->modtype = DATATYPE;
231 cfg->moddir = "Classes/DataTypes";
233 else if (strcmp(argv[optind+2], "usbclass")==0)
235 cfg->modtype = USBCLASS;
236 cfg->moddir = "Classes/USB";
237 if(!hassuffix)
239 cfg->suffix = "class";
240 hassuffix = 1;
243 else if (strcmp(argv[optind+2], "hidd")==0)
245 cfg->modtype = HIDD;
246 cfg->moddir = "Devs/Drivers";
248 else if (strcmp(argv[optind+2], "handler")==0)
250 cfg->modtype = HANDLER;
251 cfg->moddir = "$(AROS_DIR_FS)";
253 else if (strcmp(argv[optind+2], "hook")==0)
255 cfg->modtype = HANDLER;
256 cfg->moddir = "Devs";
258 else
260 fprintf(stderr, "Unknown modtype \"%s\" specified for second argument\n", argv[optind+2]);
261 exit(20);
263 cfg->modtypestr = argv[optind+2];
265 if (!hassuffix)
266 cfg->suffix = argv[optind+2];
268 /* Fill fields with default value if not specified on the command line */
270 char tmpbuf[256];
272 if (cfg->conffile == NULL)
274 snprintf(tmpbuf, sizeof(tmpbuf), "%s.conf", cfg->modulename);
275 cfg->conffile = strdup(tmpbuf);
278 if (cfg->gendir == NULL)
279 cfg->gendir = ".";
282 readconfig(cfg);
284 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
285 * if they are provided
287 if (cfg->beginiofunc != NULL)
289 struct functionhead *funchead;
291 cfg->intcfg |= CFG_NOREADFUNCS;
293 /* Add beginio_func to the list of functions */
294 funchead = newfunctionhead(cfg->beginiofunc, REGISTERMACRO);
295 funchead->type = strdup("void");
296 funchead->lvo = 5;
297 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
299 funchead->next = cfg->funclist;
300 cfg->funclist = funchead;
302 /* Add abortio_func to the list of functions */
303 funchead = newfunctionhead(cfg->abortiofunc, REGISTERMACRO);
304 funchead->type = strdup("LONG");
305 funchead->lvo = 6;
306 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
308 funchead->next = cfg->funclist->next;
309 cfg->funclist->next = funchead;
311 else if (cfg->modtype == DEVICE && cfg->intcfg & CFG_NOREADFUNCS)
313 fprintf
315 stderr,
316 "beginio_func and abortio_func missing for a device with a non empty function list\n"
318 exit(20);
321 /* See if we have any stackcall options */
322 if (cfg->funclist) {
323 struct functionhead *funchead;
325 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
326 if (funchead->libcall == STACK) {
327 cfg->options |= OPTION_STACKCALL;
328 break;
333 /* Provide default version for functions that didnt have it */
334 if (cfg->funclist) {
335 struct functionhead *funchead;
336 int defversion = cfg->majorversion; /* Assume library version is default */
338 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
339 if (funchead->version > -1) {
340 /* There was at least one .version tag. Assume 0 is default */
341 defversion = 0;
342 break;
346 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
347 if (funchead->version == -1) {
348 funchead->version = defversion;
353 /* Verify that a handler has a handler */
354 if (cfg->modtype == HANDLER) {
355 if (cfg->handlerfunc == NULL) {
356 fprintf(stderr, "handler modules require a 'handler_func' ##config option\n");
357 exit(20);
359 cfg->options |= OPTION_NOAUTOLIB | OPTION_NOEXPUNGE | OPTION_NOOPENCLOSE;
362 return cfg;
365 /* Functions to read configuration from the configuration file */
367 #include "fileread.h"
369 static char *readsections(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
370 static void readsectionconfig(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
371 static void readsectioncdef(struct config *);
372 static void readsectioncdefprivate(struct config *);
373 static void readsectionstartup(struct config *);
374 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall);
375 static void readsectionclass_methodlist(struct classinfo *);
376 static void readsectionclass(struct config *);
377 static void readsectionhandler(struct config *);
378 static void readsectioninterface(struct config *);
380 static void readconfig(struct config *cfg)
382 struct classinfo *mainclass = NULL;
384 /* Create a classinfo structure if this module is a class */
385 switch (cfg->modtype)
387 case LIBRARY:
388 case DEVICE:
389 case RESOURCE:
390 case USBCLASS:
391 case HANDLER:
392 break;
394 case MCC:
395 case MUI:
396 case MCP:
397 case GADGET:
398 case DATATYPE:
399 case HIDD:
400 mainclass = newclass(cfg);
401 mainclass->classtype = cfg->modtype;
402 break;
404 default:
405 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
406 exit(20);
409 switch (cfg->modtype)
411 case LIBRARY:
412 case USBCLASS:
413 cfg->firstlvo = 5;
414 break;
415 case DEVICE:
416 cfg->firstlvo = 7;
417 break;
418 case MCC:
419 case MUI:
420 case MCP:
421 cfg->firstlvo = 6;
422 mainclass->boopsimprefix = muimprefix;
423 break;
424 case HANDLER:
425 case RESOURCE:
426 cfg->firstlvo = 1;
427 break;
428 case GADGET:
429 cfg->firstlvo = 5;
430 mainclass->boopsimprefix = gadgetmprefix;
431 break;
432 case DATATYPE:
433 cfg->firstlvo = 6;
434 mainclass->boopsimprefix = dtmprefix;
435 break;
436 case HIDD:
437 cfg->firstlvo = 5;
438 /* FIXME: need boopsimprefix ? */
439 break;
440 default:
441 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
442 exit(20);
445 if (!fileopen(cfg->conffile))
447 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
448 exit(20);
451 /* Read all sections and see that we are at the end of the file */
452 if (readsections(cfg, mainclass, NULL, 0) != NULL)
453 exitfileerror(20, "Syntax error");
455 fileclose();
458 /* readsections will scan through all the sections in the config file.
459 * arguments:
460 * struct config *cfg: The module config data which may be updated by
461 * the information in the sections
462 * struct classinfo *cl: The classdata to be filled with data from the sections.
463 * This may be NULL if this is the main part of the configuration file and the
464 * type of the module is not a class
465 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
466 * part of the config file.
468 static char *readsections(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
470 char *line, *s, *s2;
471 int hasconfig = 0;
473 while ((line=readline())!=NULL)
475 if (strncmp(line, "##", 2)==0)
477 static char *parts[] =
479 "config", "cdefprivate", "cdef", "startup", "functionlist", "methodlist", "class", "handler", "interface", "attributelist", "cfunctionlist"
481 const unsigned int nums = sizeof(parts)/sizeof(char *);
482 unsigned int partnum;
483 int i, atend = 0;
485 s = line+2;
486 while (isspace(*s)) s++;
488 if (strncmp(s, "begin", 5)!=0)
489 return line;
491 s += 5;
492 if (!isspace(*s))
493 exitfileerror(20, "space after begin expected\n");
494 while (isspace(*s)) s++;
496 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
498 if (strncmp(s, parts[i], strlen(parts[i]))==0)
500 partnum = i+1;
501 s += strlen(parts[i]);
502 while (isspace(*s)) s++;
503 if (*s!='\0')
504 exitfileerror(20, "unexpected character on position %d\n", s-line);
507 if (partnum==0)
508 exitfileerror(20, "unknown start of section\n");
509 switch (partnum)
511 case 1: /* config */
512 readsectionconfig(cfg, cl, in, inclass);
513 hasconfig = 1;
514 break;
516 case 2: /* cdefprivate */
517 if (inclass)
518 exitfileerror(20, "cdefprivate section not allowed in class section\n");
519 readsectioncdefprivate(cfg);
520 break;
522 case 3: /* cdef */
523 if (inclass)
524 exitfileerror(20, "cdef section not allowed in class section\n");
525 readsectioncdef(cfg);
526 break;
528 case 4: /* startup */
529 if (inclass)
530 exitfileerror(20, "startup section not allowed in class section\n");
531 readsectionstartup(cfg);
532 break;
534 case 5: /* functionlist */
535 if (inclass)
536 exitfileerror(20, "functionlist section not allow in class section\n");
537 if (cfg->basename==NULL)
538 exitfileerror(20, "section functionlist has to come after section config\n");
540 readsectionfunctionlist("functionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTERMACRO);
541 cfg->intcfg |= CFG_NOREADFUNCS;
542 break;
544 case 6: /* methodlist */
545 if (cl == NULL && in == NULL)
546 exitfileerror(20, "methodlist section when not in a class or interface\n");
547 if (cl)
548 readsectionclass_methodlist(cl);
549 else
550 readsectionfunctionlist("methodlist", &in->methodlist, 0, 0, REGISTERMACRO);
551 cfg->intcfg |= CFG_NOREADFUNCS;
552 break;
554 case 7: /* class */
555 if (inclass)
556 exitfileerror(20, "class section may not be in nested\n");
557 readsectionclass(cfg);
558 break;
559 case 8: /* handler */
560 readsectionhandler(cfg);
561 break;
562 case 9: /* interface */
563 if (inclass)
564 exitfileerror(20, "interface section may not be nested\n");
565 readsectioninterface(cfg);
566 break;
567 case 10: /* attributelist */
568 if (!in)
569 exitfileerror(20, "attributelist only valid in interface sections\n");
570 readsectionfunctionlist("attributelist", &in->attributelist, 0, 1, INVALID);
571 break;
572 case 11: /* cfunctionlist */
573 if (inclass)
574 exitfileerror(20, "cfunctionlist section not allow in class section\n");
575 if (cfg->basename==NULL)
576 exitfileerror(20, "section cfunctionlist has to come after section config\n");
578 readsectionfunctionlist("cfunctionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTER);
579 cfg->intcfg |= CFG_NOREADFUNCS;
580 break;
583 else if (strlen(line)!=0)
584 filewarning("warning line outside section ignored\n");
587 if(!inclass)
589 if (!hasconfig)
590 exitfileerror(20, "No config section in conffile\n");
592 /* If no indication was given for generating includes or not
593 decide on module type and if there are functions
595 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
597 switch (cfg->modtype)
599 case LIBRARY:
600 case RESOURCE:
601 cfg->options |= OPTION_INCLUDES;
602 break;
604 case HANDLER:
605 case MCC:
606 case MUI:
607 case MCP:
608 case USBCLASS:
609 cfg->options |= OPTION_NOINCLUDES;
610 break;
612 case DEVICE:
613 cfg->options |= (
614 (cfg->funclist != NULL)
615 || (cfg->cdeflines != NULL)
616 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
617 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
618 break;
620 case GADGET:
621 case DATATYPE:
622 case HIDD:
623 cfg->options |= (
624 (cfg->funclist != NULL)
625 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
626 break;
628 default:
629 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
630 exit(20);
631 break;
635 /* If no indication was given for not generating stubs only generate them if
636 * the module has functions
638 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
640 switch (cfg->modtype)
642 case LIBRARY:
643 cfg->options |= (cfg->funclist != NULL) ? OPTION_STUBS : OPTION_NOSTUBS;
644 break;
646 case USBCLASS:
647 case RESOURCE:
648 case GADGET:
649 case DEVICE:
650 case DATATYPE:
651 case MCC:
652 case MUI:
653 case MCP:
654 case HIDD:
655 case HANDLER:
656 cfg->options |= OPTION_NOSTUBS;
657 break;
659 default:
660 fprintf(stderr, "Internal error writemakefile: unhandled modtype for stubs\n");
661 exit(20);
662 break;
666 /* If no indication was given for generating autoinit code or not
667 decide on module type
669 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
671 switch (cfg->modtype)
673 case LIBRARY:
674 cfg->options |= OPTION_AUTOINIT;
675 break;
677 case USBCLASS:
678 case RESOURCE:
679 case GADGET:
680 case DEVICE:
681 case DATATYPE:
682 case MCC:
683 case MUI:
684 case MCP:
685 case HIDD:
686 case HANDLER:
687 cfg->options |= OPTION_NOAUTOINIT;
688 break;
690 default:
691 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
692 exit(20);
693 break;
697 if ((cfg->modtype == RESOURCE) || (cfg->modtype == HANDLER))
698 /* Enforce noopenclose for resources and handlers */
699 cfg->options |= OPTION_NOOPENCLOSE;
700 else if (!(cfg->options & OPTION_SELFINIT))
701 /* Enforce using RTF_AUTOINIT for everything except resources */
702 cfg->options |= OPTION_RESAUTOINIT;
705 return NULL;
708 static void readsectionconfig(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
710 int atend = 0, i;
711 char *line, *s, *s2, *libbasetypeextern = NULL;
712 struct tm date;
714 while (!atend)
716 line = readline();
717 if (line==NULL)
718 exitfileerror(20, "unexpected end of file in section config\n");
720 if (strncmp(line, "##", 2)!=0)
722 const char *names[] =
724 "basename", "libbase", "libbasetype", "libbasetypeextern",
725 "version", "date", "copyright", "libcall", "forcebase", "superclass",
726 "superclass_field", "residentpri", "options", "sysbase_field",
727 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
728 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
729 "initpri", "type", "addromtag", "oopbase_field",
730 "rellib", "interfaceid", "interfacename",
731 "methodstub", "methodbase", "attributebase", "handler_func",
732 "includename"
734 const unsigned int namenums = sizeof(names)/sizeof(char *);
735 unsigned int namenum;
737 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
741 strncmp(line, names[i], strlen(names[i]))==0
742 && isspace(*(line+strlen(names[i])))
744 namenum = i+1;
746 if (namenum==0)
747 exitfileerror(20, "unrecognized configuration option\n");
749 s = line + strlen(names[namenum-1]);
750 if (!isspace(*s))
751 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
753 while (isspace(*s)) s++;
754 if (*s=='\0')
755 exitfileerror(20, "unexpected end of line\n");
757 s2 = s + strlen(s);
758 while (isspace(*(s2-1))) s2--;
759 *s2 = '\0';
761 switch (namenum)
763 case 1: /* basename */
764 if (!inclass)
765 cfg->basename = strdup(s);
766 if (cl != NULL)
767 cl->basename = strdup(s);
768 if (in != NULL)
769 exitfileerror(20, "basename not valid config option when in an interface section\n");
770 break;
772 case 2: /* libbase */
773 if (inclass)
774 exitfileerror(20, "libbase not valid config option when in a class section\n");
775 cfg->libbase = strdup(s);
776 break;
778 case 3: /* libbasetype */
779 if (inclass)
780 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
781 cfg->libbasetype = strdup(s);
782 break;
784 case 4: /* libbasetypeextern */
785 if (inclass)
786 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
787 libbasetypeextern = strdup(s);
788 break;
790 case 5: /* version */
791 if (inclass)
792 exitfileerror(20, "version not valid config option when in a class section\n");
793 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
794 exitfileerror(20, "wrong version string \"%s\"\n", s);
795 break;
797 case 6: /* date */
798 if (inclass)
799 exitfileerror(20, "date not valid config option when in a class section\n");
800 #ifndef _WIN32
801 if (strptime(s, "%e.%m.%Y", &date) == NULL)
803 exitfileerror(20, "date string has to have d.m.yyyy format\n");
805 #endif
806 cfg->datestring = strdup(s);
807 break;
809 case 7: /* copyright */
810 if (inclass)
811 exitfileerror(20, "copyright not valid config option when in a class section\n");
812 cfg->copyright = strdup(s);
813 break;
815 case 8: /* libcall */
816 fprintf(stderr, "libcall specification is deprecated and ignored\n");
817 break;
819 case 9: /* forcebase */
820 if (inclass)
821 exitfileerror(20, "forcebase not valid config option when in a class section\n");
822 slist_append(&cfg->forcelist, s);
823 break;
825 case 10: /* superclass */
826 if (cl == NULL)
827 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
828 cl->superclass = strdup(s);
829 break;
831 case 11: /* superclass_field */
832 if (cl == NULL)
833 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
834 cl->superclass_field = strdup(s);
835 break;
837 case 12: /* residentpri */
838 if (!inclass)
840 int count;
841 char dummy;
843 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
844 if (count != 1 ||
845 cfg->residentpri < -128 || cfg->residentpri > 127
848 exitfileerror(20, "residentpri number format error\n");
851 else
852 exitfileerror(20, "residentpri not valid config option when in a class section\n");
853 break;
855 case 13: /* options */
856 if (!inclass)
858 static const char *optionnames[] =
860 "noautolib", "noexpunge", "noresident", "peropenerbase",
861 "pertaskbase", "includes", "noincludes", "nostubs",
862 "autoinit", "noautoinit", "resautoinit", "noopenclose",
863 "selfinit"
865 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
866 int optionnum;
870 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
872 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
874 optionnum = i + 1;
875 s += strlen(optionnames[i]);
876 while (isspace(*s)) s++;
877 if (*s == ',')
878 s++;
879 else if (*s != '\0')
880 exitfileerror(20, "Unrecognized option\n");
883 if (optionnum == 0)
884 exitfileerror(20, "Unrecognized option\n");
885 switch (optionnum)
887 case 1: /* noautolib */
888 cfg->options |= OPTION_NOAUTOLIB;
889 break;
890 case 2: /* noexpunge */
891 cfg->options |= OPTION_NOEXPUNGE;
892 break;
893 case 3: /* noresident */
894 cfg->options |= OPTION_NORESIDENT;
895 cfg->firstlvo = 1;
896 break;
897 case 5: /* pertaskbase */
898 cfg->options |= OPTION_PERTASKBASE;
899 /* Fall through */
900 case 4: /* peropenerbase */
901 if (cfg->options & OPTION_DUPBASE)
902 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
903 cfg->options |= OPTION_DUPBASE;
904 break;
905 case 6: /* includes */
906 if (cfg->options & OPTION_NOINCLUDES)
907 exitfileerror(20, "option includes and noincludes are incompatible\n");
908 cfg->options |= OPTION_INCLUDES;
909 break;
910 case 7: /* noincludes */
911 if (cfg->options & OPTION_INCLUDES)
912 exitfileerror(20, "option includes and noincludes are incompatible\n");
913 cfg->options |= OPTION_NOINCLUDES;
914 break;
915 case 8: /* nostubs */
916 cfg->options |= OPTION_NOSTUBS;
917 break;
918 case 9: /* autoinit */
919 if (cfg->options & OPTION_NOAUTOINIT)
920 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
921 cfg->options |= OPTION_AUTOINIT;
922 break;
923 case 10: /* noautoinit */
924 if (cfg->options & OPTION_AUTOINIT)
925 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
926 cfg->options |= OPTION_NOAUTOINIT;
927 break;
928 case 11: /* resautoinit */
929 if (cfg->options & OPTION_SELFINIT)
930 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
931 cfg->options |= OPTION_RESAUTOINIT;
932 break;
933 case 12:
934 cfg->options |= OPTION_NOOPENCLOSE;
935 break;
936 case 13: /* noresautoinit */
937 if (cfg->options & OPTION_RESAUTOINIT)
938 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
939 cfg->options |= OPTION_SELFINIT;
940 break;
942 while (isspace(*s)) s++;
943 } while(*s !='\0');
945 else
947 static const char *optionnames[] =
949 "private"
951 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
952 int optionnum;
956 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
958 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
960 optionnum = i + 1;
961 s += strlen(optionnames[i]);
962 while (isspace(*s)) s++;
963 if (*s == ',')
964 s++;
965 else if (*s != '\0')
966 exitfileerror(20, "Unrecognized option\n");
969 if (optionnum == 0)
970 exitfileerror(20, "Unrecognized option\n");
971 switch (optionnum)
973 case 1: /* private */
974 cl->options |= COPTION_PRIVATE;
975 break;
977 while (isspace(*s)) s++;
978 } while(*s !='\0');
980 break;
982 case 14: /* sysbase_field */
983 if (inclass)
984 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
985 cfg->sysbase_field = strdup(s);
986 break;
988 case 15: /* seglist_field */
989 if (inclass)
990 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
991 cfg->seglist_field = strdup(s);
992 break;
994 case 16: /* rootbase_field */
995 if (inclass)
996 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
997 cfg->rootbase_field = strdup(s);
998 break;
1000 case 17: /* classptr_field */
1001 if (cl == NULL)
1003 exitfileerror
1006 "classptr_field specified when not a BOOPSI class\n"
1009 cl->classptr_field = strdup(s);
1010 break;
1012 case 18: /* classptr_var */
1013 if (cl == NULL)
1015 exitfileerror
1018 "classptr_var specified when not a BOOPSI class\n"
1021 cl->classptr_var = strdup(s);
1022 break;
1024 case 19: /* classid */
1025 if (cl == NULL)
1026 exitfileerror(20, "classid specified when not a BOOPSI class\n");
1027 if (cl->classid != NULL)
1028 exitfileerror(20, "classid specified twice\n");
1029 cl->classid = strdup(s);
1030 if (strcmp(cl->classid, "NULL") == 0)
1031 cl->options |= COPTION_PRIVATE;
1032 break;
1034 case 20: /* classdatatype */
1035 if (cl == NULL)
1036 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
1037 cl->classdatatype = strdup(s);
1038 break;
1040 case 21: /* beginio_func */
1041 if (inclass)
1042 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
1043 if (cfg->modtype != DEVICE)
1044 exitfileerror(20, "beginio_func specified when not a device\n");
1045 cfg->beginiofunc = strdup(s);
1046 break;
1048 case 22: /* abortio_func */
1049 if (inclass)
1050 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
1051 if (cfg->modtype != DEVICE)
1052 exitfileerror(20, "abortio_func specified when not a device\n");
1053 cfg->abortiofunc = strdup(s);
1054 break;
1056 case 23: /* dispatcher */
1057 if (cl == NULL)
1058 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
1059 cl->dispatcher = strdup(s);
1060 /* function references are not needed when dispatcher is specified */
1061 cfg->intcfg |= CFG_NOREADFUNCS;
1062 break;
1064 case 24: /* initpri */
1065 if (cl != NULL)
1067 int count;
1068 char dummy;
1070 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
1071 if (count != 1 ||
1072 cl->initpri < -128 || cl->initpri > 127
1075 exitfileerror(20, "initpri number format error\n");
1078 else
1079 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
1080 break;
1082 case 25: /* type */
1083 if (!inclass)
1084 exitfileerror(20, "type only valid config option in a class section\n");
1085 if (strcmp(s,"mcc")==0)
1086 cl->classtype = MCC;
1087 else if (strcmp(s,"mui")==0)
1088 cl->classtype = MUI;
1089 else if (strcmp(s,"mcp")==0)
1090 cl->classtype = MCP;
1091 else if (strcmp(s, "image")==0)
1092 cl->classtype = IMAGE;
1093 else if (strcmp(s, "gadget")==0)
1094 cl->classtype = GADGET;
1095 else if (strcmp(s, "datatype")==0)
1096 cl->classtype = DATATYPE;
1097 else if (strcmp(s, "usbclass")==0)
1098 cl->classtype = USBCLASS;
1099 else if (strcmp(s, "class")==0)
1100 cl->classtype = CLASS;
1101 else if (strcmp(s, "hidd")==0)
1102 cl->classtype = HIDD;
1103 else
1105 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
1106 exit(20);
1108 break;
1110 case 26: /* addromtag */
1111 cfg->addromtag = strdup(s);
1112 break;
1114 case 27: /* oopbase_field */
1115 cfg->oopbase_field = strdup(s);
1116 break;
1117 case 28: /* rellib */
1118 slist_append(&cfg->rellibs, s);
1119 break;
1120 case 29: /* interfaceid */
1121 if (!in)
1122 exitfileerror(20, "interfaceid only valid config option for an interface\n");
1123 in->interfaceid = strdup(s);
1124 break;
1125 case 30: /* interfacename */
1126 if (!in)
1127 exitfileerror(20, "interfacename only valid config option for an interface\n");
1128 in->interfacename = strdup(s);
1129 break;
1130 case 31: /* methodstub */
1131 if (!in)
1132 exitfileerror(20, "methodstub only valid config option for an interface\n");
1133 in->methodstub = strdup(s);
1134 break;
1135 case 32: /* methodbase */
1136 if (!in)
1137 exitfileerror(20, "methodbase only valid config option for an interface\n");
1138 in->methodbase = strdup(s);
1139 break;
1140 case 33: /* attributebase */
1141 if (!in)
1142 exitfileerror(20, "attributebase only valid config option for an interface\n");
1143 in->attributebase = strdup(s);
1144 break;
1145 case 34: /* handler_func */
1146 if (cfg->modtype != HANDLER)
1147 exitfileerror(20, "handler specified when not a handler\n");
1148 cfg->handlerfunc = strdup(s);
1149 break;
1150 case 35: /* includename */
1151 if (inclass)
1152 exitfileerror(20, "includename not valid config option"
1153 " when in a class section\n");
1154 cfg->includename = strdup(s);
1155 break;
1158 else /* Line starts with ## */
1160 s = line+2;
1161 while (isspace(*s)) s++;
1162 if (strncmp(s, "end", 3)!=0)
1163 exitfileerror(20, "\"##end config\" expected\n");
1165 s += 3;
1166 if (!isspace(*s))
1167 exitfileerror(20, "\"##end config\" expected\n");
1169 while (isspace(*s)) s++;
1170 if (strncmp(s, "config", 6)!=0)
1171 exitfileerror(20, "\"##end config\" expected\n");
1173 s += 6;
1174 while (isspace(*s)) s++;
1175 if (*s!='\0')
1176 exitfileerror(20, "\"##end config\" expected\n");
1178 atend = 1;
1182 /* When not in a class section fill in default values for fields in cfg */
1183 if (!inclass)
1185 if (cfg->basename==NULL)
1187 cfg->basename = strdup(cfg->modulename);
1188 *cfg->basename = toupper(*cfg->basename);
1190 if (cfg->libbase==NULL)
1192 unsigned int len = strlen(cfg->basename)+5;
1193 cfg->libbase = malloc(len);
1194 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1196 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1197 cfg->libbasetype = strdup(libbasetypeextern);
1198 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1199 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1200 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1201 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1202 if (cfg->oopbase_field != NULL && cfg->libbasetype == NULL)
1203 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1204 /* rootbase_field only allowed when duplicating base */
1205 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1206 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1208 /* Set default date to current date */
1209 if (cfg->datestring == NULL)
1211 char tmpbuf[256];
1212 time_t now = time(NULL);
1213 struct tm *ltime = localtime(&now);
1215 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1216 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1218 cfg->datestring = strdup(tmpbuf);
1221 if (cfg->copyright == NULL)
1222 cfg->copyright = "";
1224 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1225 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1227 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1229 if (libbasetypeextern==NULL)
1231 switch (cfg->modtype)
1233 case DEVICE:
1234 cfg->libbasetypeptrextern = "struct Device *";
1235 break;
1236 case HANDLER:
1237 case RESOURCE:
1238 cfg->libbasetypeptrextern = "APTR ";
1239 break;
1240 case LIBRARY:
1241 case MUI:
1242 case MCP:
1243 case MCC:
1244 case GADGET:
1245 case DATATYPE:
1246 case USBCLASS:
1247 case HIDD:
1248 cfg->libbasetypeptrextern = "struct Library *";
1249 break;
1250 default:
1251 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1252 exit(20);
1255 else
1257 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1258 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1259 strcat(cfg->libbasetypeptrextern, " *");
1260 free(libbasetypeextern);
1263 if (cfg->includename == NULL)
1264 cfg->includename = cfg->modulename;
1265 cfg->includenameupper = strdup(cfg->includename);
1266 for (s=cfg->includenameupper; *s!='\0'; *s = toupper(*s), s++)
1267 if (!isalnum(*s)) *s = '_';
1270 /* When class was given too fill in some defaults when not specified */
1271 if (cl != NULL)
1273 if (cl->classtype == UNSPECIFIED)
1274 cl->classtype = CLASS;
1276 if (cl->basename == NULL)
1278 if (!inclass)
1279 cl->basename = cfg->basename;
1280 else
1281 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1284 /* MUI classes are always private */
1285 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1286 cl->options |= COPTION_PRIVATE;
1288 if (cl->classid == NULL
1289 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1292 if (cl->classtype == HIDD)
1294 cl->options &= !COPTION_PRIVATE;
1296 else if (cl->options & COPTION_PRIVATE)
1298 cl->classid = "NULL";
1300 else
1302 char s[256] = "";
1304 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1306 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1308 else if (cl->classtype == DATATYPE)
1310 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1312 cl->classid = strdup(s);
1316 /* Only specify superclass or superclass_field */
1317 if (cl->superclass != NULL && cl->superclass_field != NULL)
1318 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1320 /* Give default value to superclass if it is not specified */
1321 if (cl->superclass == NULL && cl->superclass == NULL)
1323 switch (cl->classtype)
1325 case MUI:
1326 case MCC:
1327 cl->superclass = "MUIC_Area";
1328 break;
1329 case MCP:
1330 cl->superclass = "MUIC_Mccprefs";
1331 break;
1332 case IMAGE:
1333 cl->superclass = "IMAGECLASS";
1334 break;
1335 case GADGET:
1336 cl->superclass = "GADGETCLASS";
1337 break;
1338 case DATATYPE:
1339 cl->superclass = "DATATYPESCLASS";
1340 break;
1341 case CLASS:
1342 cl->superclass = "ROOTCLASS";
1343 break;
1344 case HIDD:
1345 cl->superclass = "CLID_Root";
1346 break;
1347 default:
1348 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1349 break;
1355 static void readsectioncdef(struct config *cfg)
1357 int atend = 0;
1358 char *line, *s;
1360 while (!atend)
1362 line = readline();
1363 if (line==NULL)
1364 exitfileerror(20, "unexptected end of file in section cdef\n");
1366 if (strncmp(line, "##", 2)!=0)
1368 slist_append(&cfg->cdeflines, line);
1370 else
1372 s = line+2;
1373 while (isspace(*s)) s++;
1374 if (strncmp(s, "end", 3)!=0)
1375 exitfileerror(20, "\"##end cdef\" expected\n");
1377 s += 3;
1378 while (isspace(*s)) s++;
1379 if (strncmp(s, "cdef", 4)!=0)
1380 exitfileerror(20, "\"##end cdef\" expected\n");
1382 s += 5;
1383 while (isspace(*s)) s++;
1384 if (*s!='\0')
1385 exitfileerror(20, "unexpected character at position %d\n");
1387 atend = 1;
1392 static void readsectioncdefprivate(struct config *cfg)
1394 int atend = 0;
1395 char *line, *s;
1397 while (!atend)
1399 line = readline();
1400 if (line==NULL)
1401 exitfileerror(20, "unexptected end of file in section cdef\n");
1403 if (strncmp(line, "##", 2)!=0)
1405 slist_append(&cfg->cdefprivatelines, line);
1407 else
1409 s = line+2;
1410 while (isspace(*s)) s++;
1411 if (strncmp(s, "end", 3)!=0)
1412 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1414 s += 3;
1415 while (isspace(*s)) s++;
1416 if (strncmp(s, "cdefprivate", 11)!=0)
1417 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1419 s += 11;
1420 while (isspace(*s)) s++;
1421 if (*s!='\0')
1422 exitfileerror(20, "unexpected character at position %d\n");
1424 atend = 1;
1429 static void readsectionstartup(struct config *cfg)
1431 int atend = 0;
1432 char *line, *s;
1434 while (!atend)
1436 line = readline();
1437 if (line==NULL)
1438 exitfileerror(20, "unexptected end of file in section startup\n");
1440 if (strncmp(line, "##", 2)!=0)
1442 slist_append(&cfg->startuplines, line);
1444 else
1446 s = line+2;
1447 while (isspace(*s)) s++;
1448 if (strncmp(s, "end", 3)!=0)
1449 exitfileerror(20, "\"##end startup\" expected\n");
1451 s += 3;
1452 while (isspace(*s)) s++;
1453 if (strncmp(s, "startup", 7)!=0)
1454 exitfileerror(20, "\"##end startup\" expected\n");
1456 s += 7;
1457 while (isspace(*s)) s++;
1458 if (*s!='\0')
1459 exitfileerror(20, "unexpected character at position %d\n");
1461 atend = 1;
1466 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall)
1468 int atend = 0, i;
1469 char *line, *s, *s2;
1470 unsigned int lvo = firstlvo;
1471 int minversion = -1;
1473 while (!atend)
1475 line = readline();
1476 if (line==NULL)
1477 exitfileerror(20, "unexpected EOF in functionlist section\n");
1478 if (strlen(line)==0)
1480 if (*funclistptr != NULL)
1481 funclistptr = &((*funclistptr)->next);
1482 lvo++;
1484 else if (isspace(*line))
1486 s = line;
1487 while (isspace(*s)) s++;
1488 if (*s=='\0')
1490 if (*funclistptr != NULL)
1491 funclistptr = &((*funclistptr)->next);
1492 lvo++;
1494 else
1495 exitfileerror(20, "no space allowed before functionname\n");
1497 else if (strncmp(line, "##", 2)==0)
1499 s = line+2;
1500 while (isspace(*s)) s++;
1501 if (strncmp(s, "end", 3)!=0)
1502 exitfileerror(20, "\"##end %s\" expected\n", type);
1504 s += 3;
1505 while (isspace(*s)) s++;
1506 if (strncmp(s, type, strlen(type))!=0)
1507 exitfileerror(20, "\"##end %s\" expected\n", type);
1509 s += strlen(type);
1510 while (isspace(*s)) s++;
1511 if (*s!='\0')
1512 exitfileerror(20, "unexpected character on position %d\n", s-line);
1514 atend = 1;
1516 else if (*line=='.')
1518 s = line+1;
1519 if (strncmp(s, "skip", 4)==0)
1521 int n;
1523 s += 4;
1524 if (!isspace(*s))
1525 exitfileerror(20, "syntax is '.skip n'\n");
1527 n=strtol(s, &s2, 10);
1528 if (s2==NULL)
1529 exitfileerror(20, "positive number expected\n");
1531 while (isspace(*s2)) s2++;
1532 if ((*s2 != '\0') && (*s2 != '#'))
1533 exitfileerror(20, "syntax is '.skip n'\n");
1534 if (*funclistptr != NULL)
1535 funclistptr = &((*funclistptr)->next);
1536 lvo += n;
1538 else if (strncmp(s, "alias", 5)==0)
1540 s += 5;
1542 if (!isspace(*s))
1543 exitfileerror(20, "syntax is '.alias name'\n");
1545 while (isspace(*s)) s++;
1546 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1547 exitfileerror(20, "syntax is '.alias name'\n");
1549 s2 = s;
1550 s++;
1551 while (isalnum(*s) || *s == '_') s++;
1553 if (isspace(*s))
1555 *s = '\0';
1556 do {
1557 s++;
1558 } while (isspace(*s));
1561 if (*s != '\0')
1562 exitfileerror(20, "syntax is '.alias name'\n");
1564 if (*funclistptr == NULL)
1565 exitfileerror(20, ".alias has to come after a function declaration\n");
1567 slist_append(&(*funclistptr)->aliases, s2);
1569 else if (strncmp(s, "function", 8) == 0)
1571 s += 8;
1573 if (!isspace(*s))
1574 exitfileerror(20, "Syntax error\n");
1576 while (isspace(*s)) s++;
1577 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1578 exitfileerror(20, "syntax is '.function name'\n");
1580 s2 = s;
1581 s++;
1582 while (isalnum(*s) || *s == '_') s++;
1584 if (isspace(*s))
1586 *s = '\0';
1587 do {
1588 s++;
1589 } while (isspace(*s));
1592 if (*s != '\0')
1593 exitfileerror(20, "syntax is '.function name'\n");
1595 if (*funclistptr == NULL)
1596 exitfileerror(20, ".function has to come after a function declaration\n");
1598 funcsetinternalname(*funclistptr, s2);
1600 else if (strncmp(s, "cfunction", 9)==0)
1602 if (*funclistptr == NULL)
1603 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1605 (*funclistptr)->libcall = REGISTER;
1607 else if (strncmp(s, "private", 7)==0)
1609 if (*funclistptr == NULL)
1610 exitfileerror(20, ".private has to come after a function declaration\n");
1612 (*funclistptr)->priv = 1;
1614 else if (strncmp(s, "novararg", 8)==0)
1616 if (*funclistptr == NULL)
1617 exitfileerror(20, ".novararg has to come after a function declaration\n");
1619 (*funclistptr)->novararg = 1;
1621 else if (strncmp(s, "version", 7) == 0)
1623 /* Mark version number for the following
1624 * functions, so that the automatic OpenLibrary()
1625 * will know what version to use.
1627 char *tmp;
1628 int ver;
1630 s += 7;
1632 while (isspace(*s)) s++;
1633 ver = (int)strtol(s, &tmp, 0);
1635 if (s == tmp)
1636 exitfileerror(20, ".version expects an integer\n");
1638 s = tmp;
1639 while (isspace(*s)) s++;
1641 if (*s && *s != '#')
1642 exitfileerror(20, ".version has junk after the version number\n");
1644 minversion = ver;
1646 else if (strncmp(s, "unusedlibbase", 13) == 0)
1648 if (*funclistptr == NULL)
1649 exitfileerror(20, ".unusedlibbase has to come after a function declaration\n");
1650 (*funclistptr)->unusedlibbase = 1;
1652 else
1653 exitfileerror(20, "Syntax error");
1655 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1657 /* The line is a function or attribute prototype.
1658 * A function can have one of two syntaxes:
1659 * type funcname(argproto1, argproto2, ...)
1660 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1661 * The former is for C type function argument passing, the latter for
1662 * register argument passing.
1663 * An attribute has the following syntax:
1664 * type attribute
1666 char c, *args[64], *regs[64], *funcname, *cp;
1667 int len, argcount = 0, regcount = 0, brcount = 0;
1669 cp = strchr(line,'#');
1670 if (cp)
1671 *(cp++) = 0;
1673 /* Parse 'type functionname' at the beginning of the line */
1674 if (isattribute) {
1675 s = line + strlen(line);
1676 } else {
1677 s = strchr(line, '(');
1678 if (s == NULL)
1679 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1682 s2 = s;
1683 while (isspace(*(s2-1)))
1684 s2--;
1685 *s2 = '\0';
1687 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1688 s2--;
1690 if (s2 == line)
1691 exitfileerror(20, "No type specifier before %s name\n", isattribute ? "attribute" : "function");
1693 if (*funclistptr != NULL)
1694 funclistptr = &((*funclistptr)->next);
1695 *funclistptr = newfunctionhead(s2, STACK);
1697 if (cp)
1698 (*funclistptr)->comment = strdup(cp);
1699 else
1700 (*funclistptr)->comment = NULL;
1702 while (isspace(*(s2-1)))
1703 s2--;
1704 *s2 = '\0';
1705 (*funclistptr)->type = strdup(line);
1706 (*funclistptr)->lvo = lvo;
1707 (*funclistptr)->version = minversion;
1708 lvo++;
1710 if (isattribute)
1711 continue;
1713 /* Parse function prototype */
1714 s++;
1715 while (isspace(*s))
1716 s++;
1717 c = *s;
1719 while (c != ')')
1721 while (isspace(*s))
1722 s++;
1724 args[argcount] = s;
1725 argcount++;
1727 while
1729 *s != '\0'
1730 && !(brcount == 0 && (*s == ',' || *s == ')'))
1733 if (*s == '(')
1734 brcount++;
1735 if (*s == ')')
1737 if (brcount > 0)
1738 brcount--;
1739 else
1740 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1742 s++;
1745 c = *s;
1746 if (c == '\0')
1747 exitfileerror(20, "'(' without ')'");
1749 s2 = s;
1750 while (isspace(*(s2-1)))
1751 s2--;
1752 *s2 = '\0';
1754 if (!(s2 > args[argcount - 1]))
1755 exitfileerror(20, "Syntax error in function prototype\n");
1757 s++;
1760 s++;
1761 while (*s != '\0' && isspace(*s))
1762 s++;
1764 if (*s == '(')
1766 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1768 /* There may be no register specified with () so be sure then c is == ')' */
1769 s++;
1770 while(isspace(*s))
1771 s++;
1773 c = *s;
1775 while (c != ')')
1777 while (isspace(*s))
1778 s++;
1780 regs[regcount] = s;
1781 regcount++;
1783 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1785 s += 2;
1786 c = *s;
1787 if (c == '/')
1789 s++;
1790 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1792 s += 2;
1793 c = *s;
1795 else
1796 exitfileerror(20,
1797 "wrong register specification \"%s\" for argument %u\n",
1798 regs[regcount-1], regcount
1801 if (regcount > 4)
1802 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount, regs[regcount-1]);
1804 *s = '\0';
1806 else
1807 exitfileerror(20,
1808 "wrong register \"%s\" for argument %u\n",
1809 regs[regcount-1], regcount
1812 while (isspace(c))
1814 s++;
1815 c = *s;
1817 if (c == '\0')
1818 exitfileerror(20, "'(' without ')'\n");
1819 if (c != ',' && c != ')')
1820 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1822 s++;
1825 s++;
1826 while (isspace(*s)) s++;
1827 if (*s!='\0')
1828 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1830 if (argcount != regcount)
1831 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1832 argcount, regcount
1835 (*funclistptr)->libcall = def_libcall;
1836 for (i = 0; i < argcount; i++)
1837 funcaddarg(*funclistptr, args[i], regs[i]);
1839 else if (*s == '\0')
1840 { /* No registers specified */
1841 for (i = 0; i < argcount; i++)
1842 funcaddarg(*funclistptr, args[i], NULL);
1844 else
1845 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1850 static void readsectionclass_methodlist(struct classinfo *cl)
1852 int atend = 0, i;
1853 char *line, *s, *s2;
1854 struct functionhead **methlistptr = &cl->methlist;
1855 struct stringlist *interface = NULL;
1857 if (cl->basename==NULL)
1858 exitfileerror(20, "section methodlist has to come after section config\n");
1860 while (!atend)
1862 line = readline();
1863 if (line==NULL)
1864 exitfileerror(20, "unexptected EOF in methodlist section\n");
1866 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1867 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1868 continue;
1870 if (isspace(*line))
1871 exitfileerror(20, "No space allowed at start of the line\n");
1873 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1875 s = line+2;
1876 while (isspace(*s)) s++;
1877 if (strncmp(s, "end", 3)!=0)
1878 exitfileerror(20, "\"##end methodlist\" expected\n");
1880 s += 3;
1881 while (isspace(*s)) s++;
1882 if (strncmp(s, "methodlist", 10)!=0)
1883 exitfileerror(20, "\"##end methodlist\" expected\n");
1885 s += 10;
1886 while (isspace(*s)) s++;
1887 if (*s!='\0')
1888 exitfileerror(20, "unexpected character on position %d\n", s-line);
1890 atend = 1;
1892 continue;
1895 if (*line=='.')
1897 s = line+1;
1898 if (strncmp(s, "alias", 5)==0)
1900 s += 5;
1902 if (!isspace(*s))
1903 exitfileerror(20, "syntax is '.alias name'\n");
1905 while (isspace(*s)) s++;
1906 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1907 exitfileerror(20, "syntax is '.alias name'\n");
1909 s2 = s;
1910 s++;
1911 while (isalnum(*s) || *s == '_') s++;
1913 if (isspace(*s))
1915 *s = '\0';
1916 do {
1917 s++;
1918 } while (isspace(*s));
1921 if (*s != '\0')
1922 exitfileerror(20, "syntax is '.alias name'\n");
1924 if (*methlistptr == NULL)
1925 exitfileerror(20, ".alias has to come after a function declaration\n");
1927 slist_append(&(*methlistptr)->aliases, s2);
1929 else if (strncmp(s, "function", 8) == 0)
1931 s += 8;
1933 if (!isspace(*s))
1934 exitfileerror(20, "Syntax error\n");
1936 while (isspace(*s)) s++;
1937 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1938 exitfileerror(20, "syntax is '.function name'\n");
1940 s2 = s;
1941 s++;
1942 while (isalnum(*s) || *s == '_') s++;
1944 if (isspace(*s))
1946 *s = '\0';
1947 do {
1948 s++;
1949 } while (isspace(*s));
1952 if (*s != '\0')
1953 exitfileerror(20, "syntax is '.function name'\n");
1955 if (*methlistptr == NULL)
1956 exitfileerror(20, ".function has to come after a function declaration\n");
1958 funcsetinternalname(*methlistptr, s2);
1960 else if (strncmp(s, "interface", 9) == 0)
1962 if (cl->classtype != HIDD)
1963 exitfileerror(20, "interface only valid for a HIDD\n");
1965 s += 9;
1967 if (!isspace(*s))
1968 exitfileerror(20, "Syntax error\n");
1970 while (isspace(*s)) s++;
1971 if (*s == '\0' || !isalpha(*s))
1972 exitfileerror(20, "syntax is '.interface name'\n");
1974 s2 = s;
1975 s++;
1976 while (isalnum(*s) || *s == '_') s++;
1978 if (isspace(*s))
1980 *s = '\0';
1981 do {
1982 s++;
1983 } while (isspace(*s));
1986 if (*s != '\0')
1987 exitfileerror(20, "syntax is '.interface name'\n");
1989 interface = slist_append(&cl->interfaces, s2);
1991 else
1992 exitfileerror(20, "Syntax error");
1994 else if (isalpha(*line))
1996 char stmp[256];
1998 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
2001 if (cl->classtype == HIDD && interface == NULL)
2002 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
2004 if (*s != '\0')
2005 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
2007 if (*methlistptr != NULL)
2008 methlistptr = &((*methlistptr)->next);
2009 if (cl->classtype != HIDD)
2011 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
2012 exitfileerror(20, "Method name too large\n");
2014 *methlistptr = newfunctionhead(stmp, STACK);
2015 (*methlistptr)->type = "IPTR";
2016 funcaddarg(*methlistptr, "Class *cl", NULL);
2017 funcaddarg(*methlistptr, "Object *o", NULL);
2018 funcaddarg(*methlistptr, "Msg msg", NULL);
2020 else
2022 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
2023 exitfileerror(20, "Method name too large\n");
2025 *methlistptr = newfunctionhead(stmp, STACK);
2026 (*methlistptr)->type = "IPTR";
2027 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
2028 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
2029 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
2030 (*methlistptr)->interface = interface;
2031 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
2032 exitfileerror(20, "Method name too large\n");
2033 (*methlistptr)->method = strdup(stmp);
2035 slist_append(&(*methlistptr)->aliases, line);
2037 else
2038 exitfileerror(20, "Methodname has to begin with a letter\n");
2042 static void
2043 readsectioninterface(struct config *cfg)
2045 char *s;
2046 struct interfaceinfo *in;
2048 in = newinterface(cfg);
2049 s = readsections(cfg, NULL, in, 1);
2050 if (s == NULL)
2051 exitfileerror(20, "Unexpected end of file\n");
2053 if (strncmp(s, "##", 2) != 0)
2054 exitfileerror(20, "'##end interface' expected\n");
2055 s += 2;
2057 while (isspace(*s)) s++;
2059 if (strncmp(s, "end", 3) != 0)
2060 exitfileerror(20, "'##end interface' expected\n");
2061 s += 3;
2063 if (!isspace(*s))
2064 exitfileerror(20, "'##end interface' expected\n");
2065 while (isspace(*s)) s++;
2067 if (strncmp(s, "interface", 9) != 0)
2068 exitfileerror(20, "'##end interface' expected\n");
2069 s += 9;
2071 while (isspace(*s)) s++;
2072 if (*s != '\0')
2073 exitfileerror(20, "'##end interface' expected\n");
2075 if (!in->interfaceid)
2076 exitfileerror(20, "interface has no 'interfaceid' defined!\n");
2078 if (!in->interfacename)
2079 exitfileerror(20, "interface has no 'interfacename' defined!\n");
2081 if (!in->methodstub)
2082 in->methodstub = strdup(in->interfacename);
2084 if (!in->methodbase) {
2085 int len = strlen(in->interfacename);
2086 in->methodbase = malloc(len + 4 + 1);
2087 strcpy(in->methodbase, in->interfacename);
2088 strcat(in->methodbase, "Base");
2091 if (!in->attributebase) {
2092 int len = strlen(in->interfacename);
2093 in->attributebase = malloc(len + 4 + 4 + 1);
2094 strcpy(in->attributebase, in->interfacename);
2095 strcat(in->attributebase, "AttrBase");
2099 static void
2100 readsectionclass(struct config *cfg)
2102 char *s;
2103 struct classinfo *cl;
2105 cl = newclass(cfg);
2106 s = readsections(cfg, cl, NULL, 1);
2107 if (s == NULL)
2108 exitfileerror(20, "Unexpected end of file\n");
2110 if (strncmp(s, "##", 2) != 0)
2111 exitfileerror(20, "'##end class' expected\n");
2112 s += 2;
2114 while (isspace(*s)) s++;
2116 if (strncmp(s, "end", 3) != 0)
2117 exitfileerror(20, "'##end class' expected\n");
2118 s += 3;
2120 if (!isspace(*s))
2121 exitfileerror(20, "'##end class' expected\n");
2122 while (isspace(*s)) s++;
2124 if (strncmp(s, "class", 5) != 0)
2125 exitfileerror(20, "'##end class' expected\n");
2126 s += 5;
2128 while (isspace(*s)) s++;
2129 if (*s != '\0')
2130 exitfileerror(20, "'##end class' expected\n");
2133 static struct classinfo *newclass(struct config *cfg)
2135 struct classinfo *cl, *classlistit;
2137 cl = malloc(sizeof(struct classinfo));
2138 if (cl == NULL)
2140 fprintf(stderr, "Out of memory\n");
2141 exit(20);
2143 memset(cl, 0, sizeof(struct classinfo));
2145 /* By default the classes are initialized with a priority of 1 so they
2146 * are initialized before any user added initialization with priority 1
2148 cl->initpri = 1;
2150 if (cfg->classlist == NULL)
2151 cfg->classlist = cl;
2152 else
2156 classlistit = cfg->classlist;
2157 classlistit->next != NULL;
2158 classlistit = classlistit->next
2161 classlistit->next = cl;
2164 return cl;
2167 static struct handlerinfo *newhandler(struct config *cfg)
2169 struct handlerinfo *hl;
2171 hl = calloc(1,sizeof(*hl));
2172 hl->next = cfg->handlerlist;
2173 cfg->handlerlist = hl;
2174 return hl;
2177 static struct interfaceinfo *newinterface(struct config *cfg)
2179 struct interfaceinfo *in, *interfacelistit;
2181 in = malloc(sizeof(struct interfaceinfo));
2182 if (in == NULL)
2184 fprintf(stderr, "Out of memory\n");
2185 exit(20);
2187 memset(in, 0, sizeof(struct interfaceinfo));
2189 if (cfg->interfacelist == NULL)
2190 cfg->interfacelist = in;
2191 else
2195 interfacelistit = cfg->interfacelist;
2196 interfacelistit->next != NULL;
2197 interfacelistit = interfacelistit->next
2200 interfacelistit->next = in;
2203 return in;
2207 static int getdirective(char *s, const char *directive, int range_min, int range_max, int *val)
2209 char *tmp;
2210 int newval;
2212 if (strncmp(s, directive, strlen(directive)) != 0)
2213 return 0;
2215 s += strlen(directive);
2216 if (*s && !isspace(*s))
2217 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive);
2219 while (isspace(*s)) s++;
2220 if (!*s)
2221 exitfileerror(20, "No .%s value specified\n", directive);
2223 newval = strtol(s, &tmp, 0);
2224 if (s == tmp || !(newval >= range_min && newval <= range_max)) {
2225 tmp = s;
2226 while (*tmp && !isspace(*tmp)) tmp++;
2227 exitfileerror(20, "Invalid .%s value of %.*s\n", directive, tmp - s, s);
2230 *val = newval;
2231 return 1;
2234 static void
2235 readsectionhandler(struct config *cfg)
2237 char *line = NULL, *s;
2238 struct handlerinfo *hl;
2239 unsigned char autolevel = 0;
2240 unsigned int stacksize = 0;
2241 int startup = 0;
2242 char priority = 10;
2243 int bootpri = -128;
2244 int has_filesystem = 0;
2246 for (;;)
2248 char *function;
2249 int function_len;
2250 char *tmp;
2252 s = line = readline();
2254 if (s==NULL)
2255 exitfileerror(20, "unexpected end of file in section hanlder\n");
2257 if (strncmp(s, "##", 2)==0)
2258 break;
2260 /* Ignore comments */
2261 if (strncmp(s, "#", 1)==0)
2262 continue;
2264 /* Skip ahead to function name */
2265 while (*s && isspace(*s)) s++;
2267 /* Permit blank lines */
2268 if (!*s)
2269 continue;
2271 if (*s == '.') {
2272 int val;
2273 s++;
2275 if (getdirective(s, "autodetect", 0, 127, &val)) {
2276 autolevel = val;
2277 } else if (getdirective(s, "stacksize", 0, INT_MAX, &val)) {
2278 stacksize = val;
2279 } else if (getdirective(s, "priority", -128, 127, &val)) {
2280 priority = val;
2281 } else if (getdirective(s, "bootpri", -128, 127, &val)) {
2282 bootpri = val;
2283 } else if (getdirective(s, "startup", INT_MIN, INT_MAX, &val)) {
2284 startup = val;
2285 } else {
2286 exitfileerror(20, "Unrecognized directive \"%s\"\n", line);
2288 continue;
2291 do {
2292 unsigned int id = 0;
2294 if (strncasecmp(s,"resident=",9)==0) {
2295 char *res;
2297 s = strchr(s, '=') + 1;
2298 res = s;
2299 while (*s && !isspace(*s)) s++;
2300 if (res == s)
2301 exitfileerror(20, "Empty resident= is not permitted\n");
2303 if (*s)
2304 *(s++) = 0;
2306 hl = newhandler(cfg);
2307 hl->type = HANDLER_RESIDENT;
2308 hl->id = 0;
2309 hl->name = strdup(res);
2310 hl->autodetect = autolevel--;
2311 hl->stacksize = stacksize;
2312 hl->priority = priority;
2313 hl->startup = startup;
2314 } else if (strncasecmp(s,"dosnode=",8)==0) {
2315 char *dev;
2317 s = strchr(s, '=') + 1;
2318 dev = s;
2319 while (*s && !isspace(*s)) s++;
2320 if (dev == s)
2321 exitfileerror(20, "Empty dosnode= is not permitted\n");
2323 if (*s)
2324 *(s++) = 0;
2326 hl = newhandler(cfg);
2327 hl->type = HANDLER_DOSNODE;
2328 hl->id = 0;
2329 hl->name = strdup(dev);
2330 hl->autodetect = autolevel ? autolevel-- : 0;
2331 hl->stacksize = stacksize;
2332 hl->priority = priority;
2333 hl->startup = startup;
2334 hl->bootpri = bootpri;
2335 } else if (strncasecmp(s,"dostype=",8) == 0) {
2336 s = strchr(s, '=') + 1;
2338 id = (unsigned int)strtoul(s, &tmp, 0);
2340 if (s == tmp) {
2341 while (*tmp && !isspace(*tmp))
2342 tmp++;
2343 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp -s), s);
2345 s = tmp;
2347 if (id == 0 || id == ~0) {
2348 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id);
2351 hl = newhandler(cfg);
2352 hl->type = HANDLER_DOSTYPE;
2353 hl->id = id;
2354 hl->name = NULL;
2355 hl->autodetect = autolevel ? autolevel-- : 0;
2356 hl->stacksize = stacksize;
2357 hl->priority = priority;
2358 hl->startup = startup;
2359 } else {
2360 for (tmp = s; !isspace(*tmp); tmp++);
2361 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp - s, s);
2364 /* Advance to next ID */
2365 while (*s && isspace(*s)) s++;
2367 } while (*s);
2370 if (s == NULL)
2371 exitfileerror(20, "Unexpected end of file\n");
2373 if (strncmp(s, "##", 2) != 0)
2374 exitfileerror(20, "'##end handler' expected\n");
2375 s += 2;
2377 while (isspace(*s)) s++;
2379 if (strncmp(s, "end", 3) != 0)
2380 exitfileerror(20, "'##end handler' expected\n");
2381 s += 3;
2383 while (isspace(*s)) s++;
2385 if (strncmp(s, "handler", 7) != 0)
2386 exitfileerror(20, "'##end handler' expected\n");
2387 s += 7;
2389 while (isspace(*s)) s++;
2390 if (*s != '\0')
2391 exitfileerror(20, "'##end handler' expected\n");