add NOWARN_SIZEOF_POINTER_MEMACCESS
[AROS.git] / tools / genmodule / config.c
blob6d4297d4149fa855dc132a8a36c72796420ab11a
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 readsectionstubprivate(struct config *);
374 static void readsectionstartup(struct config *);
375 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall);
376 static void readsectionclass_methodlist(struct classinfo *);
377 static void readsectionclass(struct config *);
378 static void readsectionhandler(struct config *);
379 static void readsectioninterface(struct config *);
381 static void readconfig(struct config *cfg)
383 struct classinfo *mainclass = NULL;
385 /* Create a classinfo structure if this module is a class */
386 switch (cfg->modtype)
388 case LIBRARY:
389 case DEVICE:
390 case RESOURCE:
391 case USBCLASS:
392 case HANDLER:
393 break;
395 case MCC:
396 case MUI:
397 case MCP:
398 case GADGET:
399 case DATATYPE:
400 case HIDD:
401 mainclass = newclass(cfg);
402 mainclass->classtype = cfg->modtype;
403 break;
405 default:
406 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
407 exit(20);
410 switch (cfg->modtype)
412 case LIBRARY:
413 case USBCLASS:
414 cfg->firstlvo = 5;
415 break;
416 case DEVICE:
417 cfg->firstlvo = 7;
418 break;
419 case MCC:
420 case MUI:
421 case MCP:
422 cfg->firstlvo = 6;
423 mainclass->boopsimprefix = muimprefix;
424 break;
425 case HANDLER:
426 case RESOURCE:
427 cfg->firstlvo = 1;
428 break;
429 case GADGET:
430 cfg->firstlvo = 5;
431 mainclass->boopsimprefix = gadgetmprefix;
432 break;
433 case DATATYPE:
434 cfg->firstlvo = 6;
435 mainclass->boopsimprefix = dtmprefix;
436 break;
437 case HIDD:
438 cfg->firstlvo = 5;
439 /* FIXME: need boopsimprefix ? */
440 break;
441 default:
442 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
443 exit(20);
446 if (!fileopen(cfg->conffile))
448 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
449 exit(20);
452 /* Read all sections and see that we are at the end of the file */
453 if (readsections(cfg, mainclass, NULL, 0) != NULL)
454 exitfileerror(20, "Syntax error");
456 fileclose();
459 /* readsections will scan through all the sections in the config file.
460 * arguments:
461 * struct config *cfg: The module config data which may be updated by
462 * the information in the sections
463 * struct classinfo *cl: The classdata to be filled with data from the sections.
464 * This may be NULL if this is the main part of the configuration file and the
465 * type of the module is not a class
466 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
467 * part of the config file.
469 static char *readsections(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
471 char *line, *s, *s2;
472 int hasconfig = 0;
474 while ((line=readline())!=NULL)
476 if (strncmp(line, "##", 2)==0)
478 static char *parts[] =
480 "config", "cdefprivate", "cdef", "stubprivate", "startup", "functionlist", "methodlist", "class", "handler", "interface", "attributelist", "cfunctionlist"
482 const unsigned int nums = sizeof(parts)/sizeof(char *);
483 unsigned int partnum;
484 int i, atend = 0;
486 s = line+2;
487 while (isspace(*s)) s++;
489 if (strncmp(s, "begin", 5)!=0)
490 return line;
492 s += 5;
493 if (!isspace(*s))
494 exitfileerror(20, "space after begin expected\n");
495 while (isspace(*s)) s++;
497 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
499 if (strncmp(s, parts[i], strlen(parts[i]))==0)
501 partnum = i+1;
502 s += strlen(parts[i]);
503 while (isspace(*s)) s++;
504 if (*s!='\0')
505 exitfileerror(20, "unexpected character on position %d\n", s-line);
508 if (partnum==0)
509 exitfileerror(20, "unknown start of section\n");
510 switch (partnum)
512 case 1: /* config */
513 readsectionconfig(cfg, cl, in, inclass);
514 hasconfig = 1;
515 break;
517 case 2: /* cdefprivate */
518 if (inclass)
519 exitfileerror(20, "cdefprivate section not allowed in class section\n");
520 readsectioncdefprivate(cfg);
521 break;
523 case 3: /* cdef */
524 if (inclass)
525 exitfileerror(20, "cdef section not allowed in class section\n");
526 readsectioncdef(cfg);
527 break;
529 case 4: /* stubprivate */
530 if (inclass)
531 exitfileerror(20, "stubprivate section not allowed in class section\n");
532 readsectionstubprivate(cfg);
533 break;
535 case 5: /* startup */
536 if (inclass)
537 exitfileerror(20, "startup section not allowed in class section\n");
538 readsectionstartup(cfg);
539 break;
541 case 6: /* functionlist */
542 if (inclass)
543 exitfileerror(20, "functionlist section not allow in class section\n");
544 if (cfg->basename==NULL)
545 exitfileerror(20, "section functionlist has to come after section config\n");
547 readsectionfunctionlist("functionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTERMACRO);
548 cfg->intcfg |= CFG_NOREADFUNCS;
549 break;
551 case 7: /* methodlist */
552 if (cl == NULL && in == NULL)
553 exitfileerror(20, "methodlist section when not in a class or interface\n");
554 if (cl)
555 readsectionclass_methodlist(cl);
556 else
557 readsectionfunctionlist("methodlist", &in->methodlist, 0, 0, REGISTERMACRO);
558 cfg->intcfg |= CFG_NOREADFUNCS;
559 break;
561 case 8: /* class */
562 if (inclass)
563 exitfileerror(20, "class section may not be in nested\n");
564 readsectionclass(cfg);
565 break;
567 case 9: /* handler */
568 readsectionhandler(cfg);
569 break;
571 case 10: /* interface */
572 if (inclass)
573 exitfileerror(20, "interface section may not be nested\n");
574 readsectioninterface(cfg);
575 break;
577 case 11: /* attributelist */
578 if (!in)
579 exitfileerror(20, "attributelist only valid in interface sections\n");
580 readsectionfunctionlist("attributelist", &in->attributelist, 0, 1, INVALID);
581 break;
583 case 12: /* cfunctionlist */
584 if (inclass)
585 exitfileerror(20, "cfunctionlist section not allow in class section\n");
586 if (cfg->basename==NULL)
587 exitfileerror(20, "section cfunctionlist has to come after section config\n");
589 readsectionfunctionlist("cfunctionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTER);
590 cfg->intcfg |= CFG_NOREADFUNCS;
591 break;
594 else if (strlen(line)!=0)
595 filewarning("warning line outside section ignored\n");
598 if(!inclass)
600 if (!hasconfig)
601 exitfileerror(20, "No config section in conffile\n");
603 /* If no indication was given for generating includes or not
604 decide on module type and if there are functions
606 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
608 switch (cfg->modtype)
610 case LIBRARY:
611 case RESOURCE:
612 cfg->options |= OPTION_INCLUDES;
613 break;
615 case HANDLER:
616 case MCC:
617 case MUI:
618 case MCP:
619 case USBCLASS:
620 cfg->options |= OPTION_NOINCLUDES;
621 break;
623 case DEVICE:
624 cfg->options |= (
625 (cfg->funclist != NULL)
626 || (cfg->cdeflines != NULL)
627 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
628 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
629 break;
631 case GADGET:
632 case DATATYPE:
633 case HIDD:
634 cfg->options |= (
635 (cfg->funclist != NULL)
636 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
637 break;
639 default:
640 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
641 exit(20);
642 break;
646 /* If no indication was given for not generating stubs only generate them if
647 * the module has functions
649 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
651 switch (cfg->modtype)
653 case LIBRARY:
654 cfg->options |= (cfg->funclist != NULL) ? OPTION_STUBS : OPTION_NOSTUBS;
655 break;
657 case USBCLASS:
658 case RESOURCE:
659 case GADGET:
660 case DEVICE:
661 case DATATYPE:
662 case MCC:
663 case MUI:
664 case MCP:
665 case HIDD:
666 case HANDLER:
667 cfg->options |= OPTION_NOSTUBS;
668 break;
670 default:
671 fprintf(stderr, "Internal error writemakefile: unhandled modtype for stubs\n");
672 exit(20);
673 break;
677 /* If no indication was given for generating autoinit code or not
678 decide on module type
680 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
682 switch (cfg->modtype)
684 case LIBRARY:
685 cfg->options |= OPTION_AUTOINIT;
686 break;
688 case USBCLASS:
689 case RESOURCE:
690 case GADGET:
691 case DEVICE:
692 case DATATYPE:
693 case MCC:
694 case MUI:
695 case MCP:
696 case HIDD:
697 case HANDLER:
698 cfg->options |= OPTION_NOAUTOINIT;
699 break;
701 default:
702 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
703 exit(20);
704 break;
708 if ((cfg->modtype == RESOURCE) || (cfg->modtype == HANDLER))
709 /* Enforce noopenclose for resources and handlers */
710 cfg->options |= OPTION_NOOPENCLOSE;
711 else if (!(cfg->options & OPTION_SELFINIT))
712 /* Enforce using RTF_AUTOINIT for everything except resources */
713 cfg->options |= OPTION_RESAUTOINIT;
716 return NULL;
719 static void readsectionconfig(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
721 int atend = 0, i;
722 char *line, *s, *s2, *libbasetypeextern = NULL;
723 struct tm date;
725 while (!atend)
727 line = readline();
728 if (line==NULL)
729 exitfileerror(20, "unexpected end of file in section config\n");
731 if (strncmp(line, "##", 2)!=0)
733 const char *names[] =
735 "basename", "libbase", "libbasetype", "libbasetypeextern",
736 "version", "date", "copyright", "libcall", "forcebase", "superclass",
737 "superclass_field", "residentpri", "options", "sysbase_field",
738 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
739 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
740 "initpri", "type", "addromtag", "oopbase_field",
741 "rellib", "interfaceid", "interfacename",
742 "methodstub", "methodbase", "attributebase", "handler_func",
743 "includename"
745 const unsigned int namenums = sizeof(names)/sizeof(char *);
746 unsigned int namenum;
748 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
752 strncmp(line, names[i], strlen(names[i]))==0
753 && isspace(*(line+strlen(names[i])))
755 namenum = i+1;
757 if (namenum==0)
758 exitfileerror(20, "unrecognized configuration option\n");
760 s = line + strlen(names[namenum-1]);
761 if (!isspace(*s))
762 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
764 while (isspace(*s)) s++;
765 if (*s=='\0')
766 exitfileerror(20, "unexpected end of line\n");
768 s2 = s + strlen(s);
769 while (isspace(*(s2-1))) s2--;
770 *s2 = '\0';
772 switch (namenum)
774 case 1: /* basename */
775 if (!inclass)
776 cfg->basename = strdup(s);
777 if (cl != NULL)
778 cl->basename = strdup(s);
779 if (in != NULL)
780 exitfileerror(20, "basename not valid config option when in an interface section\n");
781 break;
783 case 2: /* libbase */
784 if (inclass)
785 exitfileerror(20, "libbase not valid config option when in a class section\n");
786 cfg->libbase = strdup(s);
787 break;
789 case 3: /* libbasetype */
790 if (inclass)
791 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
792 cfg->libbasetype = strdup(s);
793 break;
795 case 4: /* libbasetypeextern */
796 if (inclass)
797 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
798 libbasetypeextern = strdup(s);
799 break;
801 case 5: /* version */
802 if (inclass)
803 exitfileerror(20, "version not valid config option when in a class section\n");
804 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
805 exitfileerror(20, "wrong version string \"%s\"\n", s);
806 break;
808 case 6: /* date */
809 if (inclass)
810 exitfileerror(20, "date not valid config option when in a class section\n");
811 #ifndef _WIN32
812 if (strptime(s, "%e.%m.%Y", &date) == NULL)
814 exitfileerror(20, "date string has to have d.m.yyyy format\n");
816 #endif
817 cfg->datestring = strdup(s);
818 break;
820 case 7: /* copyright */
821 if (inclass)
822 exitfileerror(20, "copyright not valid config option when in a class section\n");
823 cfg->copyright = strdup(s);
824 break;
826 case 8: /* libcall */
827 fprintf(stderr, "libcall specification is deprecated and ignored\n");
828 break;
830 case 9: /* forcebase */
831 if (inclass)
832 exitfileerror(20, "forcebase not valid config option when in a class section\n");
833 slist_append(&cfg->forcelist, s);
834 break;
836 case 10: /* superclass */
837 if (cl == NULL)
838 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
839 cl->superclass = strdup(s);
840 break;
842 case 11: /* superclass_field */
843 if (cl == NULL)
844 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
845 cl->superclass_field = strdup(s);
846 break;
848 case 12: /* residentpri */
849 if (!inclass)
851 int count;
852 char dummy;
854 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
855 if (count != 1 ||
856 cfg->residentpri < -128 || cfg->residentpri > 127
859 exitfileerror(20, "residentpri number format error\n");
862 else
863 exitfileerror(20, "residentpri not valid config option when in a class section\n");
864 break;
866 case 13: /* options */
867 if (!inclass)
869 static const char *optionnames[] =
871 "noautolib", "noexpunge", "noresident", "peropenerbase",
872 "pertaskbase", "includes", "noincludes", "nostubs",
873 "autoinit", "noautoinit", "resautoinit", "noopenclose",
874 "selfinit"
876 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
877 int optionnum;
881 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
883 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
885 optionnum = i + 1;
886 s += strlen(optionnames[i]);
887 while (isspace(*s)) s++;
888 if (*s == ',')
889 s++;
890 else if (*s != '\0')
891 exitfileerror(20, "Unrecognized option\n");
894 if (optionnum == 0)
895 exitfileerror(20, "Unrecognized option\n");
896 switch (optionnum)
898 case 1: /* noautolib */
899 cfg->options |= OPTION_NOAUTOLIB;
900 break;
901 case 2: /* noexpunge */
902 cfg->options |= OPTION_NOEXPUNGE;
903 break;
904 case 3: /* noresident */
905 cfg->options |= OPTION_NORESIDENT;
906 cfg->firstlvo = 1;
907 break;
908 case 5: /* pertaskbase */
909 cfg->options |= OPTION_PERTASKBASE;
910 /* Fall through */
911 case 4: /* peropenerbase */
912 if (cfg->options & OPTION_DUPBASE)
913 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
914 cfg->options |= OPTION_DUPBASE;
915 break;
916 case 6: /* includes */
917 if (cfg->options & OPTION_NOINCLUDES)
918 exitfileerror(20, "option includes and noincludes are incompatible\n");
919 cfg->options |= OPTION_INCLUDES;
920 break;
921 case 7: /* noincludes */
922 if (cfg->options & OPTION_INCLUDES)
923 exitfileerror(20, "option includes and noincludes are incompatible\n");
924 cfg->options |= OPTION_NOINCLUDES;
925 break;
926 case 8: /* nostubs */
927 cfg->options |= OPTION_NOSTUBS;
928 break;
929 case 9: /* autoinit */
930 if (cfg->options & OPTION_NOAUTOINIT)
931 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
932 cfg->options |= OPTION_AUTOINIT;
933 break;
934 case 10: /* noautoinit */
935 if (cfg->options & OPTION_AUTOINIT)
936 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
937 cfg->options |= OPTION_NOAUTOINIT;
938 break;
939 case 11: /* resautoinit */
940 if (cfg->options & OPTION_SELFINIT)
941 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
942 cfg->options |= OPTION_RESAUTOINIT;
943 break;
944 case 12:
945 cfg->options |= OPTION_NOOPENCLOSE;
946 break;
947 case 13: /* noresautoinit */
948 if (cfg->options & OPTION_RESAUTOINIT)
949 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
950 cfg->options |= OPTION_SELFINIT;
951 break;
953 while (isspace(*s)) s++;
954 } while(*s !='\0');
956 else
958 static const char *optionnames[] =
960 "private"
962 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
963 int optionnum;
967 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
969 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
971 optionnum = i + 1;
972 s += strlen(optionnames[i]);
973 while (isspace(*s)) s++;
974 if (*s == ',')
975 s++;
976 else if (*s != '\0')
977 exitfileerror(20, "Unrecognized option\n");
980 if (optionnum == 0)
981 exitfileerror(20, "Unrecognized option\n");
982 switch (optionnum)
984 case 1: /* private */
985 cl->options |= COPTION_PRIVATE;
986 break;
988 while (isspace(*s)) s++;
989 } while(*s !='\0');
991 break;
993 case 14: /* sysbase_field */
994 if (inclass)
995 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
996 cfg->sysbase_field = strdup(s);
997 break;
999 case 15: /* seglist_field */
1000 if (inclass)
1001 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
1002 cfg->seglist_field = strdup(s);
1003 break;
1005 case 16: /* rootbase_field */
1006 if (inclass)
1007 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
1008 cfg->rootbase_field = strdup(s);
1009 break;
1011 case 17: /* classptr_field */
1012 if (cl == NULL)
1014 exitfileerror
1017 "classptr_field specified when not a BOOPSI class\n"
1020 cl->classptr_field = strdup(s);
1021 break;
1023 case 18: /* classptr_var */
1024 if (cl == NULL)
1026 exitfileerror
1029 "classptr_var specified when not a BOOPSI class\n"
1032 cl->classptr_var = strdup(s);
1033 break;
1035 case 19: /* classid */
1036 if (cl == NULL)
1037 exitfileerror(20, "classid specified when not a BOOPSI class\n");
1038 if (cl->classid != NULL)
1039 exitfileerror(20, "classid specified twice\n");
1040 cl->classid = strdup(s);
1041 if (strcmp(cl->classid, "NULL") == 0)
1042 cl->options |= COPTION_PRIVATE;
1043 break;
1045 case 20: /* classdatatype */
1046 if (cl == NULL)
1047 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
1048 cl->classdatatype = strdup(s);
1049 break;
1051 case 21: /* beginio_func */
1052 if (inclass)
1053 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
1054 if (cfg->modtype != DEVICE)
1055 exitfileerror(20, "beginio_func specified when not a device\n");
1056 cfg->beginiofunc = strdup(s);
1057 break;
1059 case 22: /* abortio_func */
1060 if (inclass)
1061 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
1062 if (cfg->modtype != DEVICE)
1063 exitfileerror(20, "abortio_func specified when not a device\n");
1064 cfg->abortiofunc = strdup(s);
1065 break;
1067 case 23: /* dispatcher */
1068 if (cl == NULL)
1069 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
1070 cl->dispatcher = strdup(s);
1071 /* function references are not needed when dispatcher is specified */
1072 cfg->intcfg |= CFG_NOREADFUNCS;
1073 break;
1075 case 24: /* initpri */
1076 if (cl != NULL)
1078 int count;
1079 char dummy;
1081 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
1082 if (count != 1 ||
1083 cl->initpri < -128 || cl->initpri > 127
1086 exitfileerror(20, "initpri number format error\n");
1089 else
1090 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
1091 break;
1093 case 25: /* type */
1094 if (!inclass)
1095 exitfileerror(20, "type only valid config option in a class section\n");
1096 if (strcmp(s,"mcc")==0)
1097 cl->classtype = MCC;
1098 else if (strcmp(s,"mui")==0)
1099 cl->classtype = MUI;
1100 else if (strcmp(s,"mcp")==0)
1101 cl->classtype = MCP;
1102 else if (strcmp(s, "image")==0)
1103 cl->classtype = IMAGE;
1104 else if (strcmp(s, "gadget")==0)
1105 cl->classtype = GADGET;
1106 else if (strcmp(s, "datatype")==0)
1107 cl->classtype = DATATYPE;
1108 else if (strcmp(s, "usbclass")==0)
1109 cl->classtype = USBCLASS;
1110 else if (strcmp(s, "class")==0)
1111 cl->classtype = CLASS;
1112 else if (strcmp(s, "hidd")==0)
1113 cl->classtype = HIDD;
1114 else
1116 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
1117 exit(20);
1119 break;
1121 case 26: /* addromtag */
1122 cfg->addromtag = strdup(s);
1123 break;
1125 case 27: /* oopbase_field */
1126 cfg->oopbase_field = strdup(s);
1127 break;
1128 case 28: /* rellib */
1129 slist_append(&cfg->rellibs, s);
1130 break;
1131 case 29: /* interfaceid */
1132 if (!in)
1133 exitfileerror(20, "interfaceid only valid config option for an interface\n");
1134 in->interfaceid = strdup(s);
1135 break;
1136 case 30: /* interfacename */
1137 if (!in)
1138 exitfileerror(20, "interfacename only valid config option for an interface\n");
1139 in->interfacename = strdup(s);
1140 break;
1141 case 31: /* methodstub */
1142 if (!in)
1143 exitfileerror(20, "methodstub only valid config option for an interface\n");
1144 in->methodstub = strdup(s);
1145 break;
1146 case 32: /* methodbase */
1147 if (!in)
1148 exitfileerror(20, "methodbase only valid config option for an interface\n");
1149 in->methodbase = strdup(s);
1150 break;
1151 case 33: /* attributebase */
1152 if (!in)
1153 exitfileerror(20, "attributebase only valid config option for an interface\n");
1154 in->attributebase = strdup(s);
1155 break;
1156 case 34: /* handler_func */
1157 if (cfg->modtype != HANDLER)
1158 exitfileerror(20, "handler specified when not a handler\n");
1159 cfg->handlerfunc = strdup(s);
1160 break;
1161 case 35: /* includename */
1162 if (inclass)
1163 exitfileerror(20, "includename not valid config option"
1164 " when in a class section\n");
1165 cfg->includename = strdup(s);
1166 break;
1169 else /* Line starts with ## */
1171 s = line+2;
1172 while (isspace(*s)) s++;
1173 if (strncmp(s, "end", 3)!=0)
1174 exitfileerror(20, "\"##end config\" expected\n");
1176 s += 3;
1177 if (!isspace(*s))
1178 exitfileerror(20, "\"##end config\" expected\n");
1180 while (isspace(*s)) s++;
1181 if (strncmp(s, "config", 6)!=0)
1182 exitfileerror(20, "\"##end config\" expected\n");
1184 s += 6;
1185 while (isspace(*s)) s++;
1186 if (*s!='\0')
1187 exitfileerror(20, "\"##end config\" expected\n");
1189 atend = 1;
1193 /* When not in a class section fill in default values for fields in cfg */
1194 if (!inclass)
1196 if (cfg->basename==NULL)
1198 cfg->basename = strdup(cfg->modulename);
1199 *cfg->basename = toupper(*cfg->basename);
1201 if (cfg->libbase==NULL)
1203 unsigned int len = strlen(cfg->basename)+5;
1204 cfg->libbase = malloc(len);
1205 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1207 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1208 cfg->libbasetype = strdup(libbasetypeextern);
1209 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1210 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1211 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1212 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1213 if (cfg->oopbase_field != NULL && cfg->libbasetype == NULL)
1214 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1215 /* rootbase_field only allowed when duplicating base */
1216 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1217 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1219 /* Set default date to current date */
1220 if (cfg->datestring == NULL)
1222 char tmpbuf[256];
1223 time_t now = time(NULL);
1224 struct tm *ltime = localtime(&now);
1226 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1227 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1229 cfg->datestring = strdup(tmpbuf);
1232 if (cfg->copyright == NULL)
1233 cfg->copyright = "";
1235 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1236 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1238 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1240 if (libbasetypeextern==NULL)
1242 switch (cfg->modtype)
1244 case DEVICE:
1245 cfg->libbasetypeptrextern = "struct Device *";
1246 break;
1247 case HANDLER:
1248 case RESOURCE:
1249 cfg->libbasetypeptrextern = "APTR ";
1250 break;
1251 case LIBRARY:
1252 case MUI:
1253 case MCP:
1254 case MCC:
1255 case GADGET:
1256 case DATATYPE:
1257 case USBCLASS:
1258 case HIDD:
1259 cfg->libbasetypeptrextern = "struct Library *";
1260 break;
1261 default:
1262 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1263 exit(20);
1266 else
1268 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1269 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1270 strcat(cfg->libbasetypeptrextern, " *");
1271 free(libbasetypeextern);
1274 if (cfg->includename == NULL)
1275 cfg->includename = cfg->modulename;
1276 cfg->includenameupper = strdup(cfg->includename);
1277 for (s=cfg->includenameupper; *s!='\0'; *s = toupper(*s), s++)
1278 if (!isalnum(*s)) *s = '_';
1281 /* When class was given too fill in some defaults when not specified */
1282 if (cl != NULL)
1284 if (cl->classtype == UNSPECIFIED)
1285 cl->classtype = CLASS;
1287 if (cl->basename == NULL)
1289 if (!inclass)
1290 cl->basename = cfg->basename;
1291 else
1292 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1295 /* MUI classes are always private */
1296 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1297 cl->options |= COPTION_PRIVATE;
1299 if (cl->classid == NULL
1300 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1303 if (cl->classtype == HIDD)
1305 cl->options &= !COPTION_PRIVATE;
1307 else if (cl->options & COPTION_PRIVATE)
1309 cl->classid = "NULL";
1311 else
1313 char s[256] = "";
1315 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1317 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1319 else if (cl->classtype == DATATYPE)
1321 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1323 cl->classid = strdup(s);
1327 /* Only specify superclass or superclass_field */
1328 if (cl->superclass != NULL && cl->superclass_field != NULL)
1329 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1331 /* Give default value to superclass if it is not specified */
1332 if (cl->superclass == NULL && cl->superclass == NULL)
1334 switch (cl->classtype)
1336 case MUI:
1337 case MCC:
1338 cl->superclass = "MUIC_Area";
1339 break;
1340 case MCP:
1341 cl->superclass = "MUIC_Mccprefs";
1342 break;
1343 case IMAGE:
1344 cl->superclass = "IMAGECLASS";
1345 break;
1346 case GADGET:
1347 cl->superclass = "GADGETCLASS";
1348 break;
1349 case DATATYPE:
1350 cl->superclass = "DATATYPESCLASS";
1351 break;
1352 case CLASS:
1353 cl->superclass = "ROOTCLASS";
1354 break;
1355 case HIDD:
1356 cl->superclass = "CLID_Root";
1357 break;
1358 default:
1359 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1360 break;
1366 static void readsectioncdef(struct config *cfg)
1368 int atend = 0;
1369 char *line, *s;
1371 while (!atend)
1373 line = readline();
1374 if (line==NULL)
1375 exitfileerror(20, "unexptected end of file in section cdef\n");
1377 if (strncmp(line, "##", 2)!=0)
1379 slist_append(&cfg->cdeflines, line);
1381 else
1383 s = line+2;
1384 while (isspace(*s)) s++;
1385 if (strncmp(s, "end", 3)!=0)
1386 exitfileerror(20, "\"##end cdef\" expected\n");
1388 s += 3;
1389 while (isspace(*s)) s++;
1390 if (strncmp(s, "cdef", 4)!=0)
1391 exitfileerror(20, "\"##end cdef\" expected\n");
1393 s += 5;
1394 while (isspace(*s)) s++;
1395 if (*s!='\0')
1396 exitfileerror(20, "unexpected character at position %d\n");
1398 atend = 1;
1404 static void readsectionstubprivate(struct config *cfg)
1406 int atend = 0;
1407 char *line, *s;
1409 while (!atend)
1411 line = readline();
1412 if (line==NULL)
1413 exitfileerror(20, "unexptected end of file in section stubprivate\n");
1415 if (strncmp(line, "##", 2)!=0)
1417 slist_append(&cfg->stubprivatelines, line);
1419 else
1421 s = line+2;
1422 while (isspace(*s)) s++;
1423 if (strncmp(s, "end", 3)!=0)
1424 exitfileerror(20, "\"##end stubprivate\" expected\n");
1426 s += 3;
1427 while (isspace(*s)) s++;
1428 if (strncmp(s, "stubprivate", 11)!=0)
1429 exitfileerror(20, "\"##end stubprivate\" expected\n");
1431 s += 11;
1432 while (isspace(*s)) s++;
1433 if (*s!='\0')
1434 exitfileerror(20, "unexpected character at position %d\n");
1436 atend = 1;
1441 static void readsectioncdefprivate(struct config *cfg)
1443 int atend = 0;
1444 char *line, *s;
1446 while (!atend)
1448 line = readline();
1449 if (line==NULL)
1450 exitfileerror(20, "unexptected end of file in section cdefprivate\n");
1452 if (strncmp(line, "##", 2)!=0)
1454 slist_append(&cfg->cdefprivatelines, line);
1456 else
1458 s = line+2;
1459 while (isspace(*s)) s++;
1460 if (strncmp(s, "end", 3)!=0)
1461 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1463 s += 3;
1464 while (isspace(*s)) s++;
1465 if (strncmp(s, "cdefprivate", 11)!=0)
1466 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1468 s += 11;
1469 while (isspace(*s)) s++;
1470 if (*s!='\0')
1471 exitfileerror(20, "unexpected character at position %d\n");
1473 atend = 1;
1478 static void readsectionstartup(struct config *cfg)
1480 int atend = 0;
1481 char *line, *s;
1483 while (!atend)
1485 line = readline();
1486 if (line==NULL)
1487 exitfileerror(20, "unexptected end of file in section startup\n");
1489 if (strncmp(line, "##", 2)!=0)
1491 slist_append(&cfg->startuplines, line);
1493 else
1495 s = line+2;
1496 while (isspace(*s)) s++;
1497 if (strncmp(s, "end", 3)!=0)
1498 exitfileerror(20, "\"##end startup\" expected\n");
1500 s += 3;
1501 while (isspace(*s)) s++;
1502 if (strncmp(s, "startup", 7)!=0)
1503 exitfileerror(20, "\"##end startup\" expected\n");
1505 s += 7;
1506 while (isspace(*s)) s++;
1507 if (*s!='\0')
1508 exitfileerror(20, "unexpected character at position %d\n");
1510 atend = 1;
1515 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall)
1517 int atend = 0, i;
1518 char *line, *s, *s2;
1519 unsigned int lvo = firstlvo;
1520 int minversion = -1;
1522 while (!atend)
1524 line = readline();
1525 if (line==NULL)
1526 exitfileerror(20, "unexpected EOF in functionlist section\n");
1527 if (strlen(line)==0)
1529 if (*funclistptr != NULL)
1530 funclistptr = &((*funclistptr)->next);
1531 lvo++;
1533 else if (isspace(*line))
1535 s = line;
1536 while (isspace(*s)) s++;
1537 if (*s=='\0')
1539 if (*funclistptr != NULL)
1540 funclistptr = &((*funclistptr)->next);
1541 lvo++;
1543 else
1544 exitfileerror(20, "no space allowed before functionname\n");
1546 else if (strncmp(line, "##", 2)==0)
1548 s = line+2;
1549 while (isspace(*s)) s++;
1550 if (strncmp(s, "end", 3)!=0)
1551 exitfileerror(20, "\"##end %s\" expected\n", type);
1553 s += 3;
1554 while (isspace(*s)) s++;
1555 if (strncmp(s, type, strlen(type))!=0)
1556 exitfileerror(20, "\"##end %s\" expected\n", type);
1558 s += strlen(type);
1559 while (isspace(*s)) s++;
1560 if (*s!='\0')
1561 exitfileerror(20, "unexpected character on position %d\n", s-line);
1563 atend = 1;
1565 else if (*line=='.')
1567 s = line+1;
1568 if (strncmp(s, "skip", 4)==0)
1570 int n;
1572 s += 4;
1573 if (!isspace(*s))
1574 exitfileerror(20, "syntax is '.skip n'\n");
1576 n=strtol(s, &s2, 10);
1577 if (s2==NULL)
1578 exitfileerror(20, "positive number expected\n");
1580 while (isspace(*s2)) s2++;
1581 if ((*s2 != '\0') && (*s2 != '#'))
1582 exitfileerror(20, "syntax is '.skip n'\n");
1583 if (*funclistptr != NULL)
1584 funclistptr = &((*funclistptr)->next);
1585 lvo += n;
1587 else if (strncmp(s, "alias", 5)==0)
1589 s += 5;
1591 if (!isspace(*s))
1592 exitfileerror(20, "syntax is '.alias name'\n");
1594 while (isspace(*s)) s++;
1595 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1596 exitfileerror(20, "syntax is '.alias name'\n");
1598 s2 = s;
1599 s++;
1600 while (isalnum(*s) || *s == '_') s++;
1602 if (isspace(*s))
1604 *s = '\0';
1605 do {
1606 s++;
1607 } while (isspace(*s));
1610 if (*s != '\0')
1611 exitfileerror(20, "syntax is '.alias name'\n");
1613 if (*funclistptr == NULL)
1614 exitfileerror(20, ".alias has to come after a function declaration\n");
1616 slist_append(&(*funclistptr)->aliases, s2);
1618 else if (strncmp(s, "function", 8) == 0)
1620 s += 8;
1622 if (!isspace(*s))
1623 exitfileerror(20, "Syntax error\n");
1625 while (isspace(*s)) s++;
1626 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1627 exitfileerror(20, "syntax is '.function name'\n");
1629 s2 = s;
1630 s++;
1631 while (isalnum(*s) || *s == '_') s++;
1633 if (isspace(*s))
1635 *s = '\0';
1636 do {
1637 s++;
1638 } while (isspace(*s));
1641 if (*s != '\0')
1642 exitfileerror(20, "syntax is '.function name'\n");
1644 if (*funclistptr == NULL)
1645 exitfileerror(20, ".function has to come after a function declaration\n");
1647 funcsetinternalname(*funclistptr, s2);
1649 else if (strncmp(s, "cfunction", 9)==0)
1651 if (*funclistptr == NULL)
1652 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1654 (*funclistptr)->libcall = REGISTER;
1656 else if (strncmp(s, "private", 7)==0)
1658 if (*funclistptr == NULL)
1659 exitfileerror(20, ".private has to come after a function declaration\n");
1661 (*funclistptr)->priv = 1;
1663 else if (strncmp(s, "novararg", 8)==0)
1665 if (*funclistptr == NULL)
1666 exitfileerror(20, ".novararg has to come after a function declaration\n");
1668 (*funclistptr)->novararg = 1;
1670 else if (strncmp(s, "version", 7) == 0)
1672 /* Mark version number for the following
1673 * functions, so that the automatic OpenLibrary()
1674 * will know what version to use.
1676 char *tmp;
1677 int ver;
1679 s += 7;
1681 while (isspace(*s)) s++;
1682 ver = (int)strtol(s, &tmp, 0);
1684 if (s == tmp)
1685 exitfileerror(20, ".version expects an integer\n");
1687 s = tmp;
1688 while (isspace(*s)) s++;
1690 if (*s && *s != '#')
1691 exitfileerror(20, ".version has junk after the version number\n");
1693 minversion = ver;
1695 else if (strncmp(s, "unusedlibbase", 13) == 0)
1697 if (*funclistptr == NULL)
1698 exitfileerror(20, ".unusedlibbase has to come after a function declaration\n");
1699 (*funclistptr)->unusedlibbase = 1;
1701 else
1702 exitfileerror(20, "Syntax error");
1704 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1706 /* The line is a function or attribute prototype.
1707 * A function can have one of two syntaxes:
1708 * type funcname(argproto1, argproto2, ...)
1709 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1710 * The former is for C type function argument passing, the latter for
1711 * register argument passing.
1712 * An attribute has the following syntax:
1713 * type attribute
1715 char c, *args[64], *regs[64], *funcname, *cp;
1716 int len, argcount = 0, regcount = 0, brcount = 0;
1718 cp = strchr(line,'#');
1719 if (cp)
1720 *(cp++) = 0;
1722 /* Parse 'type functionname' at the beginning of the line */
1723 if (isattribute) {
1724 s = line + strlen(line);
1725 } else {
1726 s = strchr(line, '(');
1727 if (s == NULL)
1728 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1731 s2 = s;
1732 while (isspace(*(s2-1)))
1733 s2--;
1734 *s2 = '\0';
1736 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1737 s2--;
1739 if (s2 == line)
1740 exitfileerror(20, "No type specifier before %s name\n", isattribute ? "attribute" : "function");
1742 if (*funclistptr != NULL)
1743 funclistptr = &((*funclistptr)->next);
1744 *funclistptr = newfunctionhead(s2, STACK);
1746 if (cp)
1747 (*funclistptr)->comment = strdup(cp);
1748 else
1749 (*funclistptr)->comment = NULL;
1751 while (isspace(*(s2-1)))
1752 s2--;
1753 *s2 = '\0';
1754 (*funclistptr)->type = strdup(line);
1755 (*funclistptr)->lvo = lvo;
1756 (*funclistptr)->version = minversion;
1757 lvo++;
1759 if (isattribute)
1760 continue;
1762 /* Parse function prototype */
1763 s++;
1764 while (isspace(*s))
1765 s++;
1766 c = *s;
1768 while (c != ')')
1770 while (isspace(*s))
1771 s++;
1773 args[argcount] = s;
1774 argcount++;
1776 while
1778 *s != '\0'
1779 && !(brcount == 0 && (*s == ',' || *s == ')'))
1782 if (*s == '(')
1783 brcount++;
1784 if (*s == ')')
1786 if (brcount > 0)
1787 brcount--;
1788 else
1789 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1791 s++;
1794 c = *s;
1795 if (c == '\0')
1796 exitfileerror(20, "'(' without ')'");
1798 s2 = s;
1799 while (isspace(*(s2-1)))
1800 s2--;
1801 *s2 = '\0';
1803 if (!(s2 > args[argcount - 1]))
1804 exitfileerror(20, "Syntax error in function prototype\n");
1806 s++;
1809 s++;
1810 while (*s != '\0' && isspace(*s))
1811 s++;
1813 if (*s == '(')
1815 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1817 /* There may be no register specified with () so be sure then c is == ')' */
1818 s++;
1819 while(isspace(*s))
1820 s++;
1822 c = *s;
1824 while (c != ')')
1826 while (isspace(*s))
1827 s++;
1829 regs[regcount] = s;
1830 regcount++;
1832 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1834 s += 2;
1835 c = *s;
1836 if (c == '/')
1838 s++;
1839 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1841 s += 2;
1842 c = *s;
1844 else
1845 exitfileerror(20,
1846 "wrong register specification \"%s\" for argument %u\n",
1847 regs[regcount-1], regcount
1850 if (regcount > 4)
1851 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount, regs[regcount-1]);
1853 *s = '\0';
1855 else
1856 exitfileerror(20,
1857 "wrong register \"%s\" for argument %u\n",
1858 regs[regcount-1], regcount
1861 while (isspace(c))
1863 s++;
1864 c = *s;
1866 if (c == '\0')
1867 exitfileerror(20, "'(' without ')'\n");
1868 if (c != ',' && c != ')')
1869 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1871 s++;
1874 s++;
1875 while (isspace(*s)) s++;
1876 if (*s!='\0')
1877 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1879 if (argcount != regcount)
1880 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1881 argcount, regcount
1884 (*funclistptr)->libcall = def_libcall;
1885 for (i = 0; i < argcount; i++)
1886 funcaddarg(*funclistptr, args[i], regs[i]);
1888 else if (*s == '\0')
1889 { /* No registers specified */
1890 for (i = 0; i < argcount; i++)
1891 funcaddarg(*funclistptr, args[i], NULL);
1893 else
1894 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1899 static void readsectionclass_methodlist(struct classinfo *cl)
1901 int atend = 0, i;
1902 char *line, *s, *s2;
1903 struct functionhead **methlistptr = &cl->methlist;
1904 struct stringlist *interface = NULL;
1906 if (cl->basename==NULL)
1907 exitfileerror(20, "section methodlist has to come after section config\n");
1909 while (!atend)
1911 line = readline();
1912 if (line==NULL)
1913 exitfileerror(20, "unexptected EOF in methodlist section\n");
1915 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1916 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1917 continue;
1919 if (isspace(*line))
1920 exitfileerror(20, "No space allowed at start of the line\n");
1922 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1924 s = line+2;
1925 while (isspace(*s)) s++;
1926 if (strncmp(s, "end", 3)!=0)
1927 exitfileerror(20, "\"##end methodlist\" expected\n");
1929 s += 3;
1930 while (isspace(*s)) s++;
1931 if (strncmp(s, "methodlist", 10)!=0)
1932 exitfileerror(20, "\"##end methodlist\" expected\n");
1934 s += 10;
1935 while (isspace(*s)) s++;
1936 if (*s!='\0')
1937 exitfileerror(20, "unexpected character on position %d\n", s-line);
1939 atend = 1;
1941 continue;
1944 if (*line=='.')
1946 s = line+1;
1947 if (strncmp(s, "alias", 5)==0)
1949 s += 5;
1951 if (!isspace(*s))
1952 exitfileerror(20, "syntax is '.alias name'\n");
1954 while (isspace(*s)) s++;
1955 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1956 exitfileerror(20, "syntax is '.alias name'\n");
1958 s2 = s;
1959 s++;
1960 while (isalnum(*s) || *s == '_') s++;
1962 if (isspace(*s))
1964 *s = '\0';
1965 do {
1966 s++;
1967 } while (isspace(*s));
1970 if (*s != '\0')
1971 exitfileerror(20, "syntax is '.alias name'\n");
1973 if (*methlistptr == NULL)
1974 exitfileerror(20, ".alias has to come after a function declaration\n");
1976 slist_append(&(*methlistptr)->aliases, s2);
1978 else if (strncmp(s, "function", 8) == 0)
1980 s += 8;
1982 if (!isspace(*s))
1983 exitfileerror(20, "Syntax error\n");
1985 while (isspace(*s)) s++;
1986 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1987 exitfileerror(20, "syntax is '.function name'\n");
1989 s2 = s;
1990 s++;
1991 while (isalnum(*s) || *s == '_') s++;
1993 if (isspace(*s))
1995 *s = '\0';
1996 do {
1997 s++;
1998 } while (isspace(*s));
2001 if (*s != '\0')
2002 exitfileerror(20, "syntax is '.function name'\n");
2004 if (*methlistptr == NULL)
2005 exitfileerror(20, ".function has to come after a function declaration\n");
2007 funcsetinternalname(*methlistptr, s2);
2009 else if (strncmp(s, "interface", 9) == 0)
2011 if (cl->classtype != HIDD)
2012 exitfileerror(20, "interface only valid for a HIDD\n");
2014 s += 9;
2016 if (!isspace(*s))
2017 exitfileerror(20, "Syntax error\n");
2019 while (isspace(*s)) s++;
2020 if (*s == '\0' || !isalpha(*s))
2021 exitfileerror(20, "syntax is '.interface name'\n");
2023 s2 = s;
2024 s++;
2025 while (isalnum(*s) || *s == '_') s++;
2027 if (isspace(*s))
2029 *s = '\0';
2030 do {
2031 s++;
2032 } while (isspace(*s));
2035 if (*s != '\0')
2036 exitfileerror(20, "syntax is '.interface name'\n");
2038 interface = slist_append(&cl->interfaces, s2);
2040 else
2041 exitfileerror(20, "Syntax error");
2043 else if (isalpha(*line))
2045 char stmp[256];
2047 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
2050 if (cl->classtype == HIDD && interface == NULL)
2051 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
2053 if (*s != '\0')
2054 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
2056 if (*methlistptr != NULL)
2057 methlistptr = &((*methlistptr)->next);
2058 if (cl->classtype != HIDD)
2060 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
2061 exitfileerror(20, "Method name too large\n");
2063 *methlistptr = newfunctionhead(stmp, STACK);
2064 (*methlistptr)->type = "IPTR";
2065 funcaddarg(*methlistptr, "Class *cl", NULL);
2066 funcaddarg(*methlistptr, "Object *o", NULL);
2067 funcaddarg(*methlistptr, "Msg msg", NULL);
2069 else
2071 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
2072 exitfileerror(20, "Method name too large\n");
2074 *methlistptr = newfunctionhead(stmp, STACK);
2075 (*methlistptr)->type = "IPTR";
2076 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
2077 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
2078 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
2079 (*methlistptr)->interface = interface;
2080 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
2081 exitfileerror(20, "Method name too large\n");
2082 (*methlistptr)->method = strdup(stmp);
2084 slist_append(&(*methlistptr)->aliases, line);
2086 else
2087 exitfileerror(20, "Methodname has to begin with a letter\n");
2091 static void
2092 readsectioninterface(struct config *cfg)
2094 char *s;
2095 struct interfaceinfo *in;
2097 in = newinterface(cfg);
2098 s = readsections(cfg, NULL, in, 1);
2099 if (s == NULL)
2100 exitfileerror(20, "Unexpected end of file\n");
2102 if (strncmp(s, "##", 2) != 0)
2103 exitfileerror(20, "'##end interface' expected\n");
2104 s += 2;
2106 while (isspace(*s)) s++;
2108 if (strncmp(s, "end", 3) != 0)
2109 exitfileerror(20, "'##end interface' expected\n");
2110 s += 3;
2112 if (!isspace(*s))
2113 exitfileerror(20, "'##end interface' expected\n");
2114 while (isspace(*s)) s++;
2116 if (strncmp(s, "interface", 9) != 0)
2117 exitfileerror(20, "'##end interface' expected\n");
2118 s += 9;
2120 while (isspace(*s)) s++;
2121 if (*s != '\0')
2122 exitfileerror(20, "'##end interface' expected\n");
2124 if (!in->interfaceid)
2125 exitfileerror(20, "interface has no 'interfaceid' defined!\n");
2127 if (!in->interfacename)
2128 exitfileerror(20, "interface has no 'interfacename' defined!\n");
2130 if (!in->methodstub)
2131 in->methodstub = strdup(in->interfacename);
2133 if (!in->methodbase) {
2134 int len = strlen(in->interfacename);
2135 in->methodbase = malloc(len + 4 + 1);
2136 strcpy(in->methodbase, in->interfacename);
2137 strcat(in->methodbase, "Base");
2140 if (!in->attributebase) {
2141 int len = strlen(in->interfacename);
2142 in->attributebase = malloc(len + 4 + 4 + 1);
2143 strcpy(in->attributebase, in->interfacename);
2144 strcat(in->attributebase, "AttrBase");
2148 static void
2149 readsectionclass(struct config *cfg)
2151 char *s;
2152 struct classinfo *cl;
2154 cl = newclass(cfg);
2155 s = readsections(cfg, cl, NULL, 1);
2156 if (s == NULL)
2157 exitfileerror(20, "Unexpected end of file\n");
2159 if (strncmp(s, "##", 2) != 0)
2160 exitfileerror(20, "'##end class' expected\n");
2161 s += 2;
2163 while (isspace(*s)) s++;
2165 if (strncmp(s, "end", 3) != 0)
2166 exitfileerror(20, "'##end class' expected\n");
2167 s += 3;
2169 if (!isspace(*s))
2170 exitfileerror(20, "'##end class' expected\n");
2171 while (isspace(*s)) s++;
2173 if (strncmp(s, "class", 5) != 0)
2174 exitfileerror(20, "'##end class' expected\n");
2175 s += 5;
2177 while (isspace(*s)) s++;
2178 if (*s != '\0')
2179 exitfileerror(20, "'##end class' expected\n");
2182 static struct classinfo *newclass(struct config *cfg)
2184 struct classinfo *cl, *classlistit;
2186 cl = malloc(sizeof(struct classinfo));
2187 if (cl == NULL)
2189 fprintf(stderr, "Out of memory\n");
2190 exit(20);
2192 memset(cl, 0, sizeof(struct classinfo));
2194 /* By default the classes are initialized with a priority of 1 so they
2195 * are initialized before any user added initialization with priority 1
2197 cl->initpri = 1;
2199 if (cfg->classlist == NULL)
2200 cfg->classlist = cl;
2201 else
2205 classlistit = cfg->classlist;
2206 classlistit->next != NULL;
2207 classlistit = classlistit->next
2210 classlistit->next = cl;
2213 return cl;
2216 static struct handlerinfo *newhandler(struct config *cfg)
2218 struct handlerinfo *hl;
2220 hl = calloc(1,sizeof(*hl));
2221 hl->next = cfg->handlerlist;
2222 cfg->handlerlist = hl;
2223 return hl;
2226 static struct interfaceinfo *newinterface(struct config *cfg)
2228 struct interfaceinfo *in, *interfacelistit;
2230 in = malloc(sizeof(struct interfaceinfo));
2231 if (in == NULL)
2233 fprintf(stderr, "Out of memory\n");
2234 exit(20);
2236 memset(in, 0, sizeof(struct interfaceinfo));
2238 if (cfg->interfacelist == NULL)
2239 cfg->interfacelist = in;
2240 else
2244 interfacelistit = cfg->interfacelist;
2245 interfacelistit->next != NULL;
2246 interfacelistit = interfacelistit->next
2249 interfacelistit->next = in;
2252 return in;
2256 static int getdirective(char *s, const char *directive, int range_min, int range_max, int *val)
2258 char *tmp;
2259 int newval;
2261 if (strncmp(s, directive, strlen(directive)) != 0)
2262 return 0;
2264 s += strlen(directive);
2265 if (*s && !isspace(*s))
2266 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive);
2268 while (isspace(*s)) s++;
2269 if (!*s)
2270 exitfileerror(20, "No .%s value specified\n", directive);
2272 newval = strtol(s, &tmp, 0);
2273 if (s == tmp || !(newval >= range_min && newval <= range_max)) {
2274 tmp = s;
2275 while (*tmp && !isspace(*tmp)) tmp++;
2276 exitfileerror(20, "Invalid .%s value of %.*s\n", directive, tmp - s, s);
2279 *val = newval;
2280 return 1;
2283 static void
2284 readsectionhandler(struct config *cfg)
2286 char *line = NULL, *s;
2287 struct handlerinfo *hl;
2288 unsigned char autolevel = 0;
2289 unsigned int stacksize = 0;
2290 int startup = 0;
2291 char priority = 10;
2292 int bootpri = -128;
2293 int has_filesystem = 0;
2295 for (;;)
2297 char *function;
2298 int function_len;
2299 char *tmp;
2301 s = line = readline();
2303 if (s==NULL)
2304 exitfileerror(20, "unexpected end of file in section hanlder\n");
2306 if (strncmp(s, "##", 2)==0)
2307 break;
2309 /* Ignore comments */
2310 if (strncmp(s, "#", 1)==0)
2311 continue;
2313 /* Skip ahead to function name */
2314 while (*s && isspace(*s)) s++;
2316 /* Permit blank lines */
2317 if (!*s)
2318 continue;
2320 if (*s == '.') {
2321 int val;
2322 s++;
2324 if (getdirective(s, "autodetect", 0, 127, &val)) {
2325 autolevel = val;
2326 } else if (getdirective(s, "stacksize", 0, INT_MAX, &val)) {
2327 stacksize = val;
2328 } else if (getdirective(s, "priority", -128, 127, &val)) {
2329 priority = val;
2330 } else if (getdirective(s, "bootpri", -128, 127, &val)) {
2331 bootpri = val;
2332 } else if (getdirective(s, "startup", INT_MIN, INT_MAX, &val)) {
2333 startup = val;
2334 } else {
2335 exitfileerror(20, "Unrecognized directive \"%s\"\n", line);
2337 continue;
2340 do {
2341 unsigned int id = 0;
2343 if (strncasecmp(s,"resident=",9)==0) {
2344 char *res;
2346 s = strchr(s, '=') + 1;
2347 res = s;
2348 while (*s && !isspace(*s)) s++;
2349 if (res == s)
2350 exitfileerror(20, "Empty resident= is not permitted\n");
2352 if (*s)
2353 *(s++) = 0;
2355 hl = newhandler(cfg);
2356 hl->type = HANDLER_RESIDENT;
2357 hl->id = 0;
2358 hl->name = strdup(res);
2359 hl->autodetect = autolevel--;
2360 hl->stacksize = stacksize;
2361 hl->priority = priority;
2362 hl->startup = startup;
2363 } else if (strncasecmp(s,"dosnode=",8)==0) {
2364 char *dev;
2366 s = strchr(s, '=') + 1;
2367 dev = s;
2368 while (*s && !isspace(*s)) s++;
2369 if (dev == s)
2370 exitfileerror(20, "Empty dosnode= is not permitted\n");
2372 if (*s)
2373 *(s++) = 0;
2375 hl = newhandler(cfg);
2376 hl->type = HANDLER_DOSNODE;
2377 hl->id = 0;
2378 hl->name = strdup(dev);
2379 hl->autodetect = autolevel ? autolevel-- : 0;
2380 hl->stacksize = stacksize;
2381 hl->priority = priority;
2382 hl->startup = startup;
2383 hl->bootpri = bootpri;
2384 } else if (strncasecmp(s,"dostype=",8) == 0) {
2385 s = strchr(s, '=') + 1;
2387 id = (unsigned int)strtoul(s, &tmp, 0);
2389 if (s == tmp) {
2390 while (*tmp && !isspace(*tmp))
2391 tmp++;
2392 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp -s), s);
2394 s = tmp;
2396 if (id == 0 || id == ~0) {
2397 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id);
2400 hl = newhandler(cfg);
2401 hl->type = HANDLER_DOSTYPE;
2402 hl->id = id;
2403 hl->name = NULL;
2404 hl->autodetect = autolevel ? autolevel-- : 0;
2405 hl->stacksize = stacksize;
2406 hl->priority = priority;
2407 hl->startup = startup;
2408 } else {
2409 for (tmp = s; !isspace(*tmp); tmp++);
2410 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp - s, s);
2413 /* Advance to next ID */
2414 while (*s && isspace(*s)) s++;
2416 } while (*s);
2419 if (s == NULL)
2420 exitfileerror(20, "Unexpected end of file\n");
2422 if (strncmp(s, "##", 2) != 0)
2423 exitfileerror(20, "'##end handler' expected\n");
2424 s += 2;
2426 while (isspace(*s)) s++;
2428 if (strncmp(s, "end", 3) != 0)
2429 exitfileerror(20, "'##end handler' expected\n");
2430 s += 3;
2432 while (isspace(*s)) s++;
2434 if (strncmp(s, "handler", 7) != 0)
2435 exitfileerror(20, "'##end handler' expected\n");
2436 s += 7;
2438 while (isspace(*s)) s++;
2439 if (*s != '\0')
2440 exitfileerror(20, "'##end handler' expected\n");