revert between 56095 -> 55830 in arch
[AROS.git] / tools / genmodule / config.c
blob0617dece0c8f477754c52e297e97ab9d01fd83e5
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
5 Code to parse the command line options and the module config file for
6 the genmodule program
7 */
9 #include <string.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #define __USE_XOPEN
13 #include <time.h>
14 #include <unistd.h>
15 #include <limits.h>
17 #include "functionhead.h"
18 #include "config.h"
20 const static char bannertemplate[] =
21 "/*\n"
22 " *** Automatically generated from '%s'. Edits will be lost. ***\n"
23 " Copyright \xA9 1995-%4u, The AROS Development Team. All rights reserved.\n"
24 "*/\n";
26 char*
27 getBanner(struct config* config)
29 static unsigned currentyear = 0;
31 int bannerlength = strlen(config->conffile) + strlen(bannertemplate);
32 // No additional bytes needed because
33 // + 1 (NUL) + 4 (4 digit year) - strlen("%s") - strlen("%4u) = 0
35 char * banner = malloc(bannerlength);
37 if (currentyear == 0)
39 time_t rawtime;
40 time(&rawtime);
41 struct tm *utctm = gmtime(&rawtime);
42 currentyear = utctm->tm_year + 1900;
45 snprintf (banner, bannerlength, bannertemplate, config->conffile, currentyear);
47 return(banner);
50 void
51 freeBanner(char *banner)
53 free((void *)banner);
56 const static char usage[] =
57 "\n"
58 "Usage: genmodule [-c conffile] [-s suffix] [-d gendir] [-l library-stub gendir] [-f flavour] [-v versionextra]\n"
59 " {writefiles|writemakefile|writeincludes|writelibdefs|writefunclist|writefd|writeskel|writethunk} modname modtype\n"
62 static void readconfig(struct config *);
63 static struct classinfo *newclass(struct config *);
64 static struct handlerinfo *newhandler(struct config *);
65 static struct interfaceinfo *newinterface(struct config *);
67 /* the method prefices for the supported classes */
68 static const char *muimprefix[] =
70 "__OM_",
71 "__MUIM_",
72 NULL
74 static const char *gadgetmprefix[] =
76 "__OM_",
77 "__GM_",
78 "__AROSM_",
79 NULL
81 static const char *dtmprefix[] =
83 "__OM_",
84 "__GM_",
85 "__DTM_",
86 "__PDTM_",
87 NULL
90 /* Create a config struct. Initialize with the values from the programs command
91 * line arguments and the contents of the modules .conf file
93 struct config *initconfig(int argc, char **argv)
95 struct config *cfg;
96 char *s, **argvit = argv + 1;
97 int hassuffix = 0, c;
99 cfg = malloc(sizeof(struct config));
100 if (cfg == NULL)
102 fprintf(stderr, "Out of memory\n");
103 exit(20);
106 memset(cfg, 0, sizeof(struct config));
108 while ((c = getopt(argc, argv, ":c:s:d:l:f:v:")) != -1)
110 if (c == ':')
112 fprintf(stderr, "Option -%c needs an argument\n",optopt);
113 exit(20);
116 switch (c)
118 case 'c':
119 cfg->conffile = optarg;
120 break;
122 case 's':
123 cfg->suffix = optarg;
124 hassuffix = 1;
125 break;
127 case 'd':
128 /* Remove / at end if present */
129 if ((optarg)[strlen(*argvit)-1]=='/') (optarg)[strlen(optarg)-1]='\0';
130 cfg->gendir = optarg;
131 break;
133 case 'l':
134 /* Remove / at end if present */
135 if ((optarg)[strlen(*argvit)-1]=='/') (optarg)[strlen(optarg)-1]='\0';
136 cfg->libgendir = optarg;
137 break;
139 case 'f':
140 cfg->flavour = optarg;
141 break;
143 case 'v':
144 cfg->versionextra = optarg;
145 break;
147 default:
148 fprintf(stderr, "Internal error: Unhandled option\n");
149 exit(20);
153 if (optind + 3 != argc)
155 fprintf(stderr, "Wrong number of arguments.\n%s", usage);
156 exit(20);
159 if (strcmp(argv[optind], "writefiles") == 0)
161 cfg->command = FILES;
163 else if (strcmp(argv[optind], "writemakefile") == 0)
165 cfg->command = MAKEFILE;
167 else if (strcmp(argv[optind], "writeincludes") == 0)
169 cfg->command = INCLUDES;
171 else if (strcmp(argv[optind], "writelibdefs") == 0)
173 cfg->command = LIBDEFS;
175 else if (strcmp(argv[optind], "writefunclist") == 0)
177 cfg->command = WRITEFUNCLIST;
179 else if (strcmp(argv[optind], "writefd") == 0)
181 cfg->command = WRITEFD;
183 else if (strcmp(argv[optind], "writeskel") == 0)
185 cfg->command = WRITESKEL;
187 else if (strcmp(argv[optind], "writethunk") == 0)
189 cfg->command = WRITETHUNK;
191 else
193 fprintf(stderr, "Unrecognized argument \"%s\"\n%s", argv[optind], usage);
194 exit(20);
198 cfg->modulename = argv[optind+1];
199 cfg->modulenameupper = strdup(cfg->modulename);
200 for (s=cfg->modulenameupper; *s!='\0'; *s = toupper(*s), s++) {
201 if (!isalnum(*s)) *s = '_';
204 if (strcmp(argv[optind+2],"library")==0)
206 cfg->modtype = LIBRARY;
207 cfg->moddir = "Libs";
209 else if (strcmp(argv[optind+2],"mcc")==0)
211 cfg->modtype = MCC;
212 cfg->moddir = "Classes/Zune";
214 else if (strcmp(argv[optind+2],"mui")==0)
216 cfg->modtype = MUI;
217 cfg->moddir = "Classes/Zune";
219 else if (strcmp(argv[optind+2],"mcp")==0)
221 cfg->modtype = MCP;
222 cfg->moddir = "Classes/Zune";
224 else if (strcmp(argv[optind+2], "device")==0)
226 cfg->modtype = DEVICE;
227 cfg->moddir = "Devs";
229 else if (strcmp(argv[optind+2], "resource")==0)
231 cfg->modtype = RESOURCE;
232 cfg->moddir = "Devs";
234 else if (strcmp(argv[optind+2], "gadget")==0)
236 cfg->modtype = GADGET;
237 cfg->moddir = "Classes/Gadgets";
239 else if (strcmp(argv[optind+2], "datatype")==0)
241 cfg->modtype = DATATYPE;
242 cfg->moddir = "Classes/DataTypes";
244 else if (strcmp(argv[optind+2], "usbclass")==0)
246 cfg->modtype = USBCLASS;
247 cfg->moddir = "Classes/USB";
248 if(!hassuffix)
250 cfg->suffix = "class";
251 hassuffix = 1;
254 else if (strcmp(argv[optind+2], "hidd")==0)
256 cfg->modtype = HIDD;
257 cfg->moddir = "Devs/Drivers";
259 else if (strcmp(argv[optind+2], "handler")==0)
261 cfg->modtype = HANDLER;
262 cfg->moddir = "$(AROS_DIR_FS)";
264 else if (strcmp(argv[optind+2], "hook")==0)
266 cfg->modtype = HANDLER;
267 cfg->moddir = "Devs";
269 else
271 fprintf(stderr, "Unknown modtype \"%s\" specified for second argument\n", argv[optind+2]);
272 exit(20);
274 cfg->modtypestr = argv[optind+2];
276 if (!hassuffix)
277 cfg->suffix = argv[optind+2];
279 /* Fill fields with default value if not specified on the command line */
281 char tmpbuf[256];
283 if (cfg->conffile == NULL)
285 snprintf(tmpbuf, sizeof(tmpbuf), "%s.conf", cfg->modulename);
286 cfg->conffile = strdup(tmpbuf);
289 if (cfg->gendir == NULL)
290 cfg->gendir = ".";
292 if (cfg->libgendir == NULL)
293 cfg->libgendir = cfg->gendir;
296 readconfig(cfg);
298 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
299 * if they are provided
301 if (cfg->beginiofunc != NULL)
303 struct functionhead *funchead;
305 cfg->intcfg |= CFG_NOREADFUNCS;
307 /* Add beginio_func to the list of functions */
308 funchead = newfunctionhead(cfg->beginiofunc, REGISTERMACRO);
309 funchead->type = strdup("void");
310 funchead->lvo = 5;
311 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
313 funchead->next = cfg->funclist;
314 cfg->funclist = funchead;
316 /* Add abortio_func to the list of functions */
317 funchead = newfunctionhead(cfg->abortiofunc, REGISTERMACRO);
318 funchead->type = strdup("LONG");
319 funchead->lvo = 6;
320 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
322 funchead->next = cfg->funclist->next;
323 cfg->funclist->next = funchead;
325 else if (cfg->modtype == DEVICE && cfg->intcfg & CFG_NOREADFUNCS)
327 fprintf
329 stderr,
330 "beginio_func and abortio_func missing for a device with a non empty function list\n"
332 exit(20);
335 /* See if we have any stackcall options */
336 if (cfg->funclist) {
337 struct functionhead *funchead;
339 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
340 if (funchead->libcall == STACK) {
341 cfg->options |= OPTION_STACKCALL;
342 break;
347 /* Provide default version for functions that didnt have it */
348 if (cfg->funclist) {
349 struct functionhead *funchead;
350 int defversion = cfg->majorversion; /* Assume library version is default */
352 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
353 if (funchead->version > -1) {
354 /* There was at least one .version tag. Assume 0 is default */
355 defversion = 0;
356 break;
360 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
361 if (funchead->version == -1) {
362 funchead->version = defversion;
367 /* Verify that a handler has a handler */
368 if (cfg->modtype == HANDLER) {
369 if (cfg->handlerfunc == NULL) {
370 fprintf(stderr, "handler modules require a 'handler_func' ##config option\n");
371 exit(20);
373 cfg->options |= OPTION_NOAUTOLIB | OPTION_NOEXPUNGE | OPTION_NOOPENCLOSE;
376 return cfg;
379 /* Functions to read configuration from the configuration file */
381 #include "fileread.h"
383 static char *readsections(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
384 static void readsectionconfig(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
385 static void readsectioncdef(struct config *);
386 static void readsectioncdefprivate(struct config *);
387 static void readsectionstubprivate(struct config *);
388 static void readsectionstartup(struct config *);
389 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall);
390 static void readsectionclass_methodlist(struct classinfo *);
391 static void readsectionclass(struct config *);
392 static void readsectionhandler(struct config *);
393 static void readsectioninterface(struct config *);
395 static void readconfig(struct config *cfg)
397 struct classinfo *mainclass = NULL;
399 /* Create a classinfo structure if this module is a class */
400 switch (cfg->modtype)
402 case LIBRARY:
403 case DEVICE:
404 case RESOURCE:
405 case USBCLASS:
406 case HANDLER:
407 break;
409 case MCC:
410 case MUI:
411 case MCP:
412 case GADGET:
413 case DATATYPE:
414 case HIDD:
415 mainclass = newclass(cfg);
416 mainclass->classtype = cfg->modtype;
417 break;
419 default:
420 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
421 exit(20);
424 switch (cfg->modtype)
426 case LIBRARY:
427 case USBCLASS:
428 cfg->firstlvo = 5;
429 break;
430 case DEVICE:
431 cfg->firstlvo = 7;
432 break;
433 case MCC:
434 case MUI:
435 case MCP:
436 cfg->firstlvo = 6;
437 mainclass->boopsimprefix = muimprefix;
438 break;
439 case HANDLER:
440 case RESOURCE:
441 cfg->firstlvo = 1;
442 break;
443 case GADGET:
444 cfg->firstlvo = 5;
445 mainclass->boopsimprefix = gadgetmprefix;
446 break;
447 case DATATYPE:
448 cfg->firstlvo = 6;
449 mainclass->boopsimprefix = dtmprefix;
450 break;
451 case HIDD:
452 cfg->firstlvo = 5;
453 /* FIXME: need boopsimprefix ? */
454 break;
455 default:
456 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
457 exit(20);
460 if (!fileopen(cfg->conffile))
462 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
463 exit(20);
466 /* Read all sections and see that we are at the end of the file */
467 if (readsections(cfg, mainclass, NULL, 0) != NULL)
468 exitfileerror(20, "Syntax error");
470 fileclose();
473 /* readsections will scan through all the sections in the config file.
474 * arguments:
475 * struct config *cfg: The module config data which may be updated by
476 * the information in the sections
477 * struct classinfo *cl: The classdata to be filled with data from the sections.
478 * This may be NULL if this is the main part of the configuration file and the
479 * type of the module is not a class
480 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
481 * part of the config file.
483 static char *readsections(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
485 char *line, *s, *s2;
486 int hasconfig = 0;
488 while ((line=readline())!=NULL)
490 if (strncmp(line, "##", 2)==0)
492 static char *parts[] =
494 "config", "cdefprivate", "cdef", "stubprivate", "startup", "functionlist", "methodlist", "class", "handler", "interface", "attributelist", "cfunctionlist"
496 const unsigned int nums = sizeof(parts)/sizeof(char *);
497 unsigned int partnum;
498 int i, atend = 0;
500 s = line+2;
501 while (isspace(*s)) s++;
503 if (strncmp(s, "begin", 5)!=0)
504 return line;
506 s += 5;
507 if (!isspace(*s))
508 exitfileerror(20, "space after begin expected\n");
509 while (isspace(*s)) s++;
511 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
513 if (strncmp(s, parts[i], strlen(parts[i]))==0)
515 partnum = i+1;
516 s += strlen(parts[i]);
517 while (isspace(*s)) s++;
518 if (*s!='\0')
519 exitfileerror(20, "unexpected character on position %d\n", s-line);
522 if (partnum==0)
523 exitfileerror(20, "unknown start of section\n");
524 switch (partnum)
526 case 1: /* config */
527 readsectionconfig(cfg, cl, in, inclass);
528 hasconfig = 1;
529 break;
531 case 2: /* cdefprivate */
532 if (inclass)
533 exitfileerror(20, "cdefprivate section not allowed in class section\n");
534 readsectioncdefprivate(cfg);
535 break;
537 case 3: /* cdef */
538 if (inclass)
539 exitfileerror(20, "cdef section not allowed in class section\n");
540 readsectioncdef(cfg);
541 break;
543 case 4: /* stubprivate */
544 if (inclass)
545 exitfileerror(20, "stubprivate section not allowed in class section\n");
546 readsectionstubprivate(cfg);
547 break;
549 case 5: /* startup */
550 if (inclass)
551 exitfileerror(20, "startup section not allowed in class section\n");
552 readsectionstartup(cfg);
553 break;
555 case 6: /* functionlist */
556 if (inclass)
557 exitfileerror(20, "functionlist section not allow in class section\n");
558 if (cfg->basename==NULL)
559 exitfileerror(20, "section functionlist has to come after section config\n");
561 readsectionfunctionlist("functionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTERMACRO);
562 cfg->intcfg |= CFG_NOREADFUNCS;
563 break;
565 case 7: /* methodlist */
566 if (cl == NULL && in == NULL)
567 exitfileerror(20, "methodlist section when not in a class or interface\n");
568 if (cl)
569 readsectionclass_methodlist(cl);
570 else
571 readsectionfunctionlist("methodlist", &in->methodlist, 0, 0, REGISTERMACRO);
572 cfg->intcfg |= CFG_NOREADFUNCS;
573 break;
575 case 8: /* class */
576 if (inclass)
577 exitfileerror(20, "class section may not be in nested\n");
578 readsectionclass(cfg);
579 break;
581 case 9: /* handler */
582 readsectionhandler(cfg);
583 break;
585 case 10: /* interface */
586 if (inclass)
587 exitfileerror(20, "interface section may not be nested\n");
588 readsectioninterface(cfg);
589 break;
591 case 11: /* attributelist */
592 if (!in)
593 exitfileerror(20, "attributelist only valid in interface sections\n");
594 readsectionfunctionlist("attributelist", &in->attributelist, 0, 1, INVALID);
595 break;
597 case 12: /* cfunctionlist */
598 if (inclass)
599 exitfileerror(20, "cfunctionlist section not allow in class section\n");
600 if (cfg->basename==NULL)
601 exitfileerror(20, "section cfunctionlist has to come after section config\n");
603 readsectionfunctionlist("cfunctionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTER);
604 cfg->intcfg |= CFG_NOREADFUNCS;
605 break;
608 else if (strlen(line)!=0)
609 filewarning("warning line outside section ignored\n");
612 if(!inclass)
614 if (!hasconfig)
615 exitfileerror(20, "No config section in conffile\n");
617 /* If no indication was given for generating includes or not
618 decide on module type and if there are functions
620 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
622 switch (cfg->modtype)
624 case LIBRARY:
625 case RESOURCE:
626 cfg->options |= OPTION_INCLUDES;
627 break;
629 case HANDLER:
630 case MCC:
631 case MUI:
632 case MCP:
633 case USBCLASS:
634 cfg->options |= OPTION_NOINCLUDES;
635 break;
637 case DEVICE:
638 cfg->options |= (
639 (cfg->funclist != NULL)
640 || (cfg->cdeflines != NULL)
641 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
642 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
643 break;
645 case GADGET:
646 case DATATYPE:
647 case HIDD:
648 cfg->options |= (
649 (cfg->funclist != NULL)
650 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
651 break;
653 default:
654 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
655 exit(20);
656 break;
660 /* If no indication was given for not generating stubs only generate them if
661 * the module has functions
663 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
665 switch (cfg->modtype)
667 case LIBRARY:
668 cfg->options |= (cfg->funclist != NULL) ? OPTION_STUBS : OPTION_NOSTUBS;
669 break;
671 case USBCLASS:
672 case RESOURCE:
673 case GADGET:
674 case DEVICE:
675 case DATATYPE:
676 case MCC:
677 case MUI:
678 case MCP:
679 case HIDD:
680 case HANDLER:
681 cfg->options |= OPTION_NOSTUBS;
682 break;
684 default:
685 fprintf(stderr, "Internal error writemakefile: unhandled modtype for stubs\n");
686 exit(20);
687 break;
691 /* If no indication was given for generating autoinit code or not
692 decide on module type
694 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
696 switch (cfg->modtype)
698 case LIBRARY:
699 cfg->options |= OPTION_AUTOINIT;
700 break;
702 case USBCLASS:
703 case RESOURCE:
704 case GADGET:
705 case DEVICE:
706 case DATATYPE:
707 case MCC:
708 case MUI:
709 case MCP:
710 case HIDD:
711 case HANDLER:
712 cfg->options |= OPTION_NOAUTOINIT;
713 break;
715 default:
716 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
717 exit(20);
718 break;
722 if ((cfg->modtype == RESOURCE) || (cfg->modtype == HANDLER))
723 /* Enforce noopenclose for resources and handlers */
724 cfg->options |= OPTION_NOOPENCLOSE;
725 else if (!(cfg->options & OPTION_SELFINIT))
726 /* Enforce using RTF_AUTOINIT for everything except resources */
727 cfg->options |= OPTION_RESAUTOINIT;
730 return NULL;
733 static void readsectionconfig(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
735 int atend = 0, i;
736 char *line, *s, *s2, *libbasetypeextern = NULL;
737 struct tm date;
739 while (!atend)
741 line = readline();
742 if (line==NULL)
743 exitfileerror(20, "unexpected end of file in section config\n");
745 if (strncmp(line, "##", 2)!=0)
747 const char *names[] =
749 "basename", "libbase", "libbasetype", "libbasetypeextern",
750 "version", "date", "copyright", "libcall", "forcebase", "superclass",
751 "superclass_field", "residentpri", "options", "sysbase_field",
752 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
753 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
754 "initpri", "type", "addromtag", "oopbase_field",
755 "rellib", "interfaceid", "interfacename",
756 "methodstub", "methodbase", "attributebase", "handler_func",
757 "includename"
759 const unsigned int namenums = sizeof(names)/sizeof(char *);
760 unsigned int namenum;
762 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
766 strncmp(line, names[i], strlen(names[i]))==0
767 && isspace(*(line+strlen(names[i])))
769 namenum = i+1;
771 if (namenum==0)
772 exitfileerror(20, "unrecognized configuration option\n");
774 s = line + strlen(names[namenum-1]);
775 if (!isspace(*s))
776 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
778 while (isspace(*s)) s++;
779 if (*s=='\0')
780 exitfileerror(20, "unexpected end of line\n");
782 s2 = s + strlen(s);
783 while (isspace(*(s2-1))) s2--;
784 *s2 = '\0';
786 switch (namenum)
788 case 1: /* basename */
789 if (!inclass)
790 cfg->basename = strdup(s);
791 if (cl != NULL)
792 cl->basename = strdup(s);
793 if (in != NULL)
794 exitfileerror(20, "basename not valid config option when in an interface section\n");
795 break;
797 case 2: /* libbase */
798 if (inclass)
799 exitfileerror(20, "libbase not valid config option when in a class section\n");
800 cfg->libbase = strdup(s);
801 break;
803 case 3: /* libbasetype */
804 if (inclass)
805 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
806 cfg->libbasetype = strdup(s);
807 break;
809 case 4: /* libbasetypeextern */
810 if (inclass)
811 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
812 libbasetypeextern = strdup(s);
813 break;
815 case 5: /* version */
816 if (inclass)
817 exitfileerror(20, "version not valid config option when in a class section\n");
818 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
819 exitfileerror(20, "wrong version string \"%s\"\n", s);
820 break;
822 case 6: /* date */
823 if (inclass)
824 exitfileerror(20, "date not valid config option when in a class section\n");
825 #ifndef _WIN32
826 if (strptime(s, "%e.%m.%Y", &date) == NULL)
828 exitfileerror(20, "date string has to have d.m.yyyy format\n");
830 #endif
831 cfg->datestring = strdup(s);
832 break;
834 case 7: /* copyright */
835 if (inclass)
836 exitfileerror(20, "copyright not valid config option when in a class section\n");
837 cfg->copyright = strdup(s);
838 break;
840 case 8: /* libcall */
841 fprintf(stderr, "libcall specification is deprecated and ignored\n");
842 break;
844 case 9: /* forcebase */
845 if (inclass)
846 exitfileerror(20, "forcebase not valid config option when in a class section\n");
847 slist_append(&cfg->forcelist, s);
848 break;
850 case 10: /* superclass */
851 if (cl == NULL)
852 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
853 cl->superclass = strdup(s);
854 break;
856 case 11: /* superclass_field */
857 if (cl == NULL)
858 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
859 cl->superclass_field = strdup(s);
860 break;
862 case 12: /* residentpri */
863 if (!inclass)
865 int count;
866 char dummy;
868 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
869 if (count != 1 ||
870 cfg->residentpri < -128 || cfg->residentpri > 127
873 exitfileerror(20, "residentpri number format error\n");
876 else
877 exitfileerror(20, "residentpri not valid config option when in a class section\n");
878 break;
880 case 13: /* options */
881 if (!inclass)
883 static const char *optionnames[] =
885 "noautolib", "noexpunge", "noresident", "peropenerbase",
886 "pertaskbase", "includes", "noincludes", "nostubs",
887 "autoinit", "noautoinit", "resautoinit", "noopenclose",
888 "selfinit", "rellinklib"
890 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
891 int optionnum;
895 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
897 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
899 optionnum = i + 1;
900 s += strlen(optionnames[i]);
901 while (isspace(*s)) s++;
902 if (*s == ',')
903 s++;
904 else if (*s != '\0')
905 exitfileerror(20, "Unrecognized option\n");
908 if (optionnum == 0)
909 exitfileerror(20, "Unrecognized option\n");
910 switch (optionnum)
912 case 1: /* noautolib */
913 cfg->options |= OPTION_NOAUTOLIB;
914 break;
915 case 2: /* noexpunge */
916 cfg->options |= OPTION_NOEXPUNGE;
917 break;
918 case 3: /* noresident */
919 cfg->options |= OPTION_NORESIDENT;
920 cfg->firstlvo = 1;
921 break;
922 case 5: /* pertaskbase */
923 cfg->options |= OPTION_PERTASKBASE;
924 /* Fall through */
925 case 4: /* peropenerbase */
926 if (cfg->options & OPTION_DUPBASE)
927 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
928 cfg->options |= OPTION_DUPBASE;
929 break;
930 case 6: /* includes */
931 if (cfg->options & OPTION_NOINCLUDES)
932 exitfileerror(20, "option includes and noincludes are incompatible\n");
933 cfg->options |= OPTION_INCLUDES;
934 break;
935 case 7: /* noincludes */
936 if (cfg->options & OPTION_INCLUDES)
937 exitfileerror(20, "option includes and noincludes are incompatible\n");
938 cfg->options |= OPTION_NOINCLUDES;
939 break;
940 case 8: /* nostubs */
941 cfg->options |= OPTION_NOSTUBS;
942 break;
943 case 9: /* autoinit */
944 if (cfg->options & OPTION_NOAUTOINIT)
945 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
946 cfg->options |= OPTION_AUTOINIT;
947 break;
948 case 10: /* noautoinit */
949 if (cfg->options & OPTION_AUTOINIT)
950 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
951 cfg->options |= OPTION_NOAUTOINIT;
952 break;
953 case 11: /* resautoinit */
954 if (cfg->options & OPTION_SELFINIT)
955 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
956 cfg->options |= OPTION_RESAUTOINIT;
957 break;
958 case 12:
959 cfg->options |= OPTION_NOOPENCLOSE;
960 break;
961 case 13: /* noresautoinit */
962 if (cfg->options & OPTION_RESAUTOINIT)
963 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
964 cfg->options |= OPTION_SELFINIT;
965 break;
966 case 14: /* rellinklib */
967 cfg->options |= OPTION_RELLINKLIB;
968 break;
970 while (isspace(*s)) s++;
971 } while(*s !='\0');
973 else
975 static const char *optionnames[] =
977 "private"
979 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
980 int optionnum;
984 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
986 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
988 optionnum = i + 1;
989 s += strlen(optionnames[i]);
990 while (isspace(*s)) s++;
991 if (*s == ',')
992 s++;
993 else if (*s != '\0')
994 exitfileerror(20, "Unrecognized option\n");
997 if (optionnum == 0)
998 exitfileerror(20, "Unrecognized option\n");
999 switch (optionnum)
1001 case 1: /* private */
1002 cl->options |= COPTION_PRIVATE;
1003 break;
1005 while (isspace(*s)) s++;
1006 } while(*s !='\0');
1008 break;
1010 case 14: /* sysbase_field */
1011 if (inclass)
1012 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
1013 cfg->sysbase_field = strdup(s);
1014 break;
1016 case 15: /* seglist_field */
1017 if (inclass)
1018 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
1019 cfg->seglist_field = strdup(s);
1020 break;
1022 case 16: /* rootbase_field */
1023 if (inclass)
1024 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
1025 cfg->rootbase_field = strdup(s);
1026 break;
1028 case 17: /* classptr_field */
1029 if (cl == NULL)
1031 exitfileerror
1034 "classptr_field specified when not a BOOPSI class\n"
1037 cl->classptr_field = strdup(s);
1038 break;
1040 case 18: /* classptr_var */
1041 if (cl == NULL)
1043 exitfileerror
1046 "classptr_var specified when not a BOOPSI class\n"
1049 cl->classptr_var = strdup(s);
1050 break;
1052 case 19: /* classid */
1053 if (cl == NULL)
1054 exitfileerror(20, "classid specified when not a BOOPSI class\n");
1055 if (cl->classid != NULL)
1056 exitfileerror(20, "classid specified twice\n");
1057 cl->classid = strdup(s);
1058 if (strcmp(cl->classid, "NULL") == 0)
1059 cl->options |= COPTION_PRIVATE;
1060 break;
1062 case 20: /* classdatatype */
1063 if (cl == NULL)
1064 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
1065 cl->classdatatype = strdup(s);
1066 break;
1068 case 21: /* beginio_func */
1069 if (inclass)
1070 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
1071 if (cfg->modtype != DEVICE)
1072 exitfileerror(20, "beginio_func specified when not a device\n");
1073 cfg->beginiofunc = strdup(s);
1074 break;
1076 case 22: /* abortio_func */
1077 if (inclass)
1078 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
1079 if (cfg->modtype != DEVICE)
1080 exitfileerror(20, "abortio_func specified when not a device\n");
1081 cfg->abortiofunc = strdup(s);
1082 break;
1084 case 23: /* dispatcher */
1085 if (cl == NULL)
1086 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
1087 cl->dispatcher = strdup(s);
1088 /* function references are not needed when dispatcher is specified */
1089 cfg->intcfg |= CFG_NOREADFUNCS;
1090 break;
1092 case 24: /* initpri */
1093 if (cl != NULL)
1095 int count;
1096 char dummy;
1098 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
1099 if (count != 1 ||
1100 cl->initpri < -128 || cl->initpri > 127
1103 exitfileerror(20, "initpri number format error\n");
1106 else
1107 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
1108 break;
1110 case 25: /* type */
1111 if (!inclass)
1112 exitfileerror(20, "type only valid config option in a class section\n");
1113 if (strcmp(s,"mcc")==0)
1114 cl->classtype = MCC;
1115 else if (strcmp(s,"mui")==0)
1116 cl->classtype = MUI;
1117 else if (strcmp(s,"mcp")==0)
1118 cl->classtype = MCP;
1119 else if (strcmp(s, "image")==0)
1120 cl->classtype = IMAGE;
1121 else if (strcmp(s, "gadget")==0)
1122 cl->classtype = GADGET;
1123 else if (strcmp(s, "datatype")==0)
1124 cl->classtype = DATATYPE;
1125 else if (strcmp(s, "usbclass")==0)
1126 cl->classtype = USBCLASS;
1127 else if (strcmp(s, "class")==0)
1128 cl->classtype = CLASS;
1129 else if (strcmp(s, "hidd")==0)
1130 cl->classtype = HIDD;
1131 else
1133 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
1134 exit(20);
1136 break;
1138 case 26: /* addromtag */
1139 cfg->addromtag = strdup(s);
1140 break;
1142 case 27: /* oopbase_field */
1143 cfg->oopbase_field = strdup(s);
1144 break;
1145 case 28: /* rellib */
1146 slist_append(&cfg->rellibs, s);
1147 break;
1148 case 29: /* interfaceid */
1149 if (!in)
1150 exitfileerror(20, "interfaceid only valid config option for an interface\n");
1151 in->interfaceid = strdup(s);
1152 break;
1153 case 30: /* interfacename */
1154 if (!in)
1155 exitfileerror(20, "interfacename only valid config option for an interface\n");
1156 in->interfacename = strdup(s);
1157 break;
1158 case 31: /* methodstub */
1159 if (!in)
1160 exitfileerror(20, "methodstub only valid config option for an interface\n");
1161 in->methodstub = strdup(s);
1162 break;
1163 case 32: /* methodbase */
1164 if (!in)
1165 exitfileerror(20, "methodbase only valid config option for an interface\n");
1166 in->methodbase = strdup(s);
1167 break;
1168 case 33: /* attributebase */
1169 if (!in)
1170 exitfileerror(20, "attributebase only valid config option for an interface\n");
1171 in->attributebase = strdup(s);
1172 break;
1173 case 34: /* handler_func */
1174 if (cfg->modtype != HANDLER)
1175 exitfileerror(20, "handler specified when not a handler\n");
1176 cfg->handlerfunc = strdup(s);
1177 break;
1178 case 35: /* includename */
1179 if (inclass)
1180 exitfileerror(20, "includename not valid config option"
1181 " when in a class section\n");
1182 cfg->includename = strdup(s);
1183 break;
1186 else /* Line starts with ## */
1188 s = line+2;
1189 while (isspace(*s)) s++;
1190 if (strncmp(s, "end", 3)!=0)
1191 exitfileerror(20, "\"##end config\" expected\n");
1193 s += 3;
1194 if (!isspace(*s))
1195 exitfileerror(20, "\"##end config\" expected\n");
1197 while (isspace(*s)) s++;
1198 if (strncmp(s, "config", 6)!=0)
1199 exitfileerror(20, "\"##end config\" expected\n");
1201 s += 6;
1202 while (isspace(*s)) s++;
1203 if (*s!='\0')
1204 exitfileerror(20, "\"##end config\" expected\n");
1206 atend = 1;
1210 /* When not in a class section fill in default values for fields in cfg */
1211 if (!inclass)
1213 if (cfg->basename==NULL)
1215 cfg->basename = strdup(cfg->modulename);
1216 *cfg->basename = toupper(*cfg->basename);
1218 if (cfg->libbase==NULL)
1220 unsigned int len = strlen(cfg->basename)+5;
1221 cfg->libbase = malloc(len);
1222 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1224 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1225 cfg->libbasetype = strdup(libbasetypeextern);
1226 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1227 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1228 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1229 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1230 if (cfg->oopbase_field != NULL && cfg->libbasetype == NULL)
1231 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1232 /* rootbase_field only allowed when duplicating base */
1233 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1234 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1236 /* Set default date to current date */
1237 if (cfg->datestring == NULL)
1239 char tmpbuf[256];
1240 time_t now = time(NULL);
1241 struct tm *ltime = localtime(&now);
1243 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1244 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1246 cfg->datestring = strdup(tmpbuf);
1249 if (cfg->copyright == NULL)
1250 cfg->copyright = "";
1252 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1253 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1255 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1257 if (libbasetypeextern==NULL)
1259 switch (cfg->modtype)
1261 case DEVICE:
1262 cfg->libbasetypeptrextern = "struct Device *";
1263 break;
1264 case HANDLER:
1265 case RESOURCE:
1266 cfg->libbasetypeptrextern = "APTR ";
1267 break;
1268 case LIBRARY:
1269 case MUI:
1270 case MCP:
1271 case MCC:
1272 case GADGET:
1273 case DATATYPE:
1274 case USBCLASS:
1275 case HIDD:
1276 cfg->libbasetypeptrextern = "struct Library *";
1277 break;
1278 default:
1279 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1280 exit(20);
1283 else
1285 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1286 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1287 strcat(cfg->libbasetypeptrextern, " *");
1288 free(libbasetypeextern);
1291 if (cfg->includename == NULL)
1292 cfg->includename = cfg->modulename;
1293 cfg->includenameupper = strdup(cfg->includename);
1294 for (s=cfg->includenameupper; *s!='\0'; *s = toupper(*s), s++)
1295 if (!isalnum(*s)) *s = '_';
1298 /* When class was given too fill in some defaults when not specified */
1299 if (cl != NULL)
1301 if (cl->classtype == UNSPECIFIED)
1302 cl->classtype = CLASS;
1304 if (cl->basename == NULL)
1306 if (!inclass)
1307 cl->basename = cfg->basename;
1308 else
1309 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1312 /* MUI classes are always private */
1313 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1314 cl->options |= COPTION_PRIVATE;
1316 if (cl->classid == NULL
1317 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1320 if (cl->classtype == HIDD)
1322 cl->options &= !COPTION_PRIVATE;
1324 else if (cl->options & COPTION_PRIVATE)
1326 cl->classid = "NULL";
1328 else
1330 char s[256] = "";
1332 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1334 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1336 else if (cl->classtype == DATATYPE)
1338 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1340 cl->classid = strdup(s);
1344 /* Only specify superclass or superclass_field */
1345 if (cl->superclass != NULL && cl->superclass_field != NULL)
1346 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1348 /* Give default value to superclass if it is not specified */
1349 if (cl->superclass == NULL && cl->superclass == NULL)
1351 switch (cl->classtype)
1353 case MUI:
1354 case MCC:
1355 cl->superclass = "MUIC_Area";
1356 break;
1357 case MCP:
1358 cl->superclass = "MUIC_Mccprefs";
1359 break;
1360 case IMAGE:
1361 cl->superclass = "IMAGECLASS";
1362 break;
1363 case GADGET:
1364 cl->superclass = "GADGETCLASS";
1365 break;
1366 case DATATYPE:
1367 cl->superclass = "DATATYPESCLASS";
1368 break;
1369 case CLASS:
1370 cl->superclass = "ROOTCLASS";
1371 break;
1372 case HIDD:
1373 cl->superclass = "CLID_Root";
1374 break;
1375 default:
1376 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1377 break;
1383 static void readsectioncdef(struct config *cfg)
1385 int atend = 0;
1386 char *line, *s;
1388 while (!atend)
1390 line = readline();
1391 if (line==NULL)
1392 exitfileerror(20, "unexptected end of file in section cdef\n");
1394 if (strncmp(line, "##", 2)!=0)
1396 slist_append(&cfg->cdeflines, line);
1398 else
1400 s = line+2;
1401 while (isspace(*s)) s++;
1402 if (strncmp(s, "end", 3)!=0)
1403 exitfileerror(20, "\"##end cdef\" expected\n");
1405 s += 3;
1406 while (isspace(*s)) s++;
1407 if (strncmp(s, "cdef", 4)!=0)
1408 exitfileerror(20, "\"##end cdef\" expected\n");
1410 s += 5;
1411 while (isspace(*s)) s++;
1412 if (*s!='\0')
1413 exitfileerror(20, "unexpected character at position %d\n");
1415 atend = 1;
1421 static void readsectionstubprivate(struct config *cfg)
1423 int atend = 0;
1424 char *line, *s;
1426 while (!atend)
1428 line = readline();
1429 if (line==NULL)
1430 exitfileerror(20, "unexptected end of file in section stubprivate\n");
1432 if (strncmp(line, "##", 2)!=0)
1434 slist_append(&cfg->stubprivatelines, line);
1436 else
1438 s = line+2;
1439 while (isspace(*s)) s++;
1440 if (strncmp(s, "end", 3)!=0)
1441 exitfileerror(20, "\"##end stubprivate\" expected\n");
1443 s += 3;
1444 while (isspace(*s)) s++;
1445 if (strncmp(s, "stubprivate", 11)!=0)
1446 exitfileerror(20, "\"##end stubprivate\" expected\n");
1448 s += 11;
1449 while (isspace(*s)) s++;
1450 if (*s!='\0')
1451 exitfileerror(20, "unexpected character at position %d\n");
1453 atend = 1;
1458 static void readsectioncdefprivate(struct config *cfg)
1460 int atend = 0;
1461 char *line, *s;
1463 while (!atend)
1465 line = readline();
1466 if (line==NULL)
1467 exitfileerror(20, "unexptected end of file in section cdefprivate\n");
1469 if (strncmp(line, "##", 2)!=0)
1471 slist_append(&cfg->cdefprivatelines, line);
1473 else
1475 s = line+2;
1476 while (isspace(*s)) s++;
1477 if (strncmp(s, "end", 3)!=0)
1478 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1480 s += 3;
1481 while (isspace(*s)) s++;
1482 if (strncmp(s, "cdefprivate", 11)!=0)
1483 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1485 s += 11;
1486 while (isspace(*s)) s++;
1487 if (*s!='\0')
1488 exitfileerror(20, "unexpected character at position %d\n");
1490 atend = 1;
1495 static void readsectionstartup(struct config *cfg)
1497 int atend = 0;
1498 char *line, *s;
1500 while (!atend)
1502 line = readline();
1503 if (line==NULL)
1504 exitfileerror(20, "unexptected end of file in section startup\n");
1506 if (strncmp(line, "##", 2)!=0)
1508 slist_append(&cfg->startuplines, line);
1510 else
1512 s = line+2;
1513 while (isspace(*s)) s++;
1514 if (strncmp(s, "end", 3)!=0)
1515 exitfileerror(20, "\"##end startup\" expected\n");
1517 s += 3;
1518 while (isspace(*s)) s++;
1519 if (strncmp(s, "startup", 7)!=0)
1520 exitfileerror(20, "\"##end startup\" expected\n");
1522 s += 7;
1523 while (isspace(*s)) s++;
1524 if (*s!='\0')
1525 exitfileerror(20, "unexpected character at position %d\n");
1527 atend = 1;
1532 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall)
1534 int atend = 0, i;
1535 char *line, *s, *s2;
1536 unsigned int lvo = firstlvo;
1537 int minversion = -1;
1539 while (!atend)
1541 line = readline();
1542 if (line==NULL)
1543 exitfileerror(20, "unexpected EOF in functionlist section\n");
1544 if (strlen(line)==0)
1546 if (*funclistptr != NULL)
1547 funclistptr = &((*funclistptr)->next);
1548 lvo++;
1550 else if (isspace(*line))
1552 s = line;
1553 while (isspace(*s)) s++;
1554 if (*s=='\0')
1556 if (*funclistptr != NULL)
1557 funclistptr = &((*funclistptr)->next);
1558 lvo++;
1560 else
1561 exitfileerror(20, "no space allowed before functionname\n");
1563 else if (strncmp(line, "##", 2)==0)
1565 s = line+2;
1566 while (isspace(*s)) s++;
1567 if (strncmp(s, "end", 3)!=0)
1568 exitfileerror(20, "\"##end %s\" expected\n", type);
1570 s += 3;
1571 while (isspace(*s)) s++;
1572 if (strncmp(s, type, strlen(type))!=0)
1573 exitfileerror(20, "\"##end %s\" expected\n", type);
1575 s += strlen(type);
1576 while (isspace(*s)) s++;
1577 if (*s!='\0')
1578 exitfileerror(20, "unexpected character on position %d\n", s-line);
1580 atend = 1;
1582 else if (*line=='.')
1584 s = line+1;
1585 if (strncmp(s, "skip", 4)==0)
1587 int n;
1589 s += 4;
1590 if (!isspace(*s))
1591 exitfileerror(20, "syntax is '.skip n'\n");
1593 n=strtol(s, &s2, 10);
1594 if (s2==NULL)
1595 exitfileerror(20, "positive number expected\n");
1597 while (isspace(*s2)) s2++;
1598 if ((*s2 != '\0') && (*s2 != '#'))
1599 exitfileerror(20, "syntax is '.skip n'\n");
1600 if (*funclistptr != NULL)
1601 funclistptr = &((*funclistptr)->next);
1602 lvo += n;
1604 else if (strncmp(s, "alias", 5)==0)
1606 s += 5;
1608 if (!isspace(*s))
1609 exitfileerror(20, "syntax is '.alias name'\n");
1611 while (isspace(*s)) s++;
1612 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1613 exitfileerror(20, "syntax is '.alias name'\n");
1615 s2 = s;
1616 s++;
1617 while (isalnum(*s) || *s == '_') s++;
1619 if (isspace(*s))
1621 *s = '\0';
1622 do {
1623 s++;
1624 } while (isspace(*s));
1627 if (*s != '\0')
1628 exitfileerror(20, "syntax is '.alias name'\n");
1630 if (*funclistptr == NULL)
1631 exitfileerror(20, ".alias has to come after a function declaration\n");
1633 slist_append(&(*funclistptr)->aliases, s2);
1635 else if (strncmp(s, "function", 8) == 0)
1637 s += 8;
1639 if (!isspace(*s))
1640 exitfileerror(20, "Syntax error\n");
1642 while (isspace(*s)) s++;
1643 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1644 exitfileerror(20, "syntax is '.function name'\n");
1646 s2 = s;
1647 s++;
1648 while (isalnum(*s) || *s == '_') s++;
1650 if (isspace(*s))
1652 *s = '\0';
1653 do {
1654 s++;
1655 } while (isspace(*s));
1658 if (*s != '\0')
1659 exitfileerror(20, "syntax is '.function name'\n");
1661 if (*funclistptr == NULL)
1662 exitfileerror(20, ".function has to come after a function declaration\n");
1664 funcsetinternalname(*funclistptr, s2);
1666 else if (strncmp(s, "cfunction", 9)==0)
1668 if (*funclistptr == NULL)
1669 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1671 (*funclistptr)->libcall = REGISTER;
1673 else if (strncmp(s, "private", 7)==0)
1675 if (*funclistptr == NULL)
1676 exitfileerror(20, ".private has to come after a function declaration\n");
1678 (*funclistptr)->priv = 1;
1680 else if (strncmp(s, "novararg", 8)==0)
1682 if (*funclistptr == NULL)
1683 exitfileerror(20, ".novararg has to come after a function declaration\n");
1685 (*funclistptr)->novararg = 1;
1687 else if (strncmp(s, "version", 7) == 0)
1689 /* Mark version number for the following
1690 * functions, so that the automatic OpenLibrary()
1691 * will know what version to use.
1693 char *tmp;
1694 int ver;
1696 s += 7;
1698 while (isspace(*s)) s++;
1699 ver = (int)strtol(s, &tmp, 0);
1701 if (s == tmp)
1702 exitfileerror(20, ".version expects an integer\n");
1704 s = tmp;
1705 while (isspace(*s)) s++;
1707 if (*s && *s != '#')
1708 exitfileerror(20, ".version has junk after the version number\n");
1710 minversion = ver;
1712 else if (strncmp(s, "unusedlibbase", 13) == 0)
1714 if (*funclistptr == NULL)
1715 exitfileerror(20, ".unusedlibbase has to come after a function declaration\n");
1716 (*funclistptr)->unusedlibbase = 1;
1718 else
1719 exitfileerror(20, "Syntax error");
1721 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1723 /* The line is a function or attribute prototype.
1724 * A function can have one of two syntaxes:
1725 * type funcname(argproto1, argproto2, ...)
1726 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1727 * The former is for C type function argument passing, the latter for
1728 * register argument passing.
1729 * An attribute has the following syntax:
1730 * type attribute
1732 char c, *args[64], *regs[64], *funcname, *cp;
1733 int len, argcount = 0, regcount = 0, brcount = 0;
1735 cp = strchr(line,'#');
1736 if (cp)
1737 *(cp++) = 0;
1739 /* Parse 'type functionname' at the beginning of the line */
1740 if (isattribute) {
1741 s = line + strlen(line);
1742 } else {
1743 s = strchr(line, '(');
1744 if (s == NULL)
1745 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1748 s2 = s;
1749 while (isspace(*(s2-1)))
1750 s2--;
1751 *s2 = '\0';
1753 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1754 s2--;
1756 if (s2 == line)
1757 exitfileerror(20, "No type specifier before %s name\n", isattribute ? "attribute" : "function");
1759 if (*funclistptr != NULL)
1760 funclistptr = &((*funclistptr)->next);
1761 *funclistptr = newfunctionhead(s2, STACK);
1763 if (cp)
1764 (*funclistptr)->comment = strdup(cp);
1765 else
1766 (*funclistptr)->comment = NULL;
1768 while (isspace(*(s2-1)))
1769 s2--;
1770 *s2 = '\0';
1771 (*funclistptr)->type = strdup(line);
1772 (*funclistptr)->lvo = lvo;
1773 (*funclistptr)->version = minversion;
1774 lvo++;
1776 if (isattribute)
1777 continue;
1779 /* Parse function prototype */
1780 s++;
1781 while (isspace(*s))
1782 s++;
1783 c = *s;
1785 while (c != ')')
1787 while (isspace(*s))
1788 s++;
1790 args[argcount] = s;
1791 argcount++;
1793 while
1795 *s != '\0'
1796 && !(brcount == 0 && (*s == ',' || *s == ')'))
1799 if (*s == '(')
1800 brcount++;
1801 if (*s == ')')
1803 if (brcount > 0)
1804 brcount--;
1805 else
1806 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1808 s++;
1811 c = *s;
1812 if (c == '\0')
1813 exitfileerror(20, "'(' without ')'");
1815 s2 = s;
1816 while (isspace(*(s2-1)))
1817 s2--;
1818 *s2 = '\0';
1820 if (!(s2 > args[argcount - 1]))
1821 exitfileerror(20, "Syntax error in function prototype\n");
1823 s++;
1826 s++;
1827 while (*s != '\0' && isspace(*s))
1828 s++;
1830 if (*s == '(')
1832 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1834 /* There may be no register specified with () so be sure then c is == ')' */
1835 s++;
1836 while(isspace(*s))
1837 s++;
1839 c = *s;
1841 while (c != ')')
1843 while (isspace(*s))
1844 s++;
1846 regs[regcount] = s;
1847 regcount++;
1849 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1851 s += 2;
1852 c = *s;
1853 if (c == '/')
1855 s++;
1856 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1858 s += 2;
1859 c = *s;
1861 else
1862 exitfileerror(20,
1863 "wrong register specification \"%s\" for argument %u\n",
1864 regs[regcount-1], regcount
1867 if (regcount > 4)
1868 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount, regs[regcount-1]);
1870 *s = '\0';
1872 else
1873 exitfileerror(20,
1874 "wrong register \"%s\" for argument %u\n",
1875 regs[regcount-1], regcount
1878 while (isspace(c))
1880 s++;
1881 c = *s;
1883 if (c == '\0')
1884 exitfileerror(20, "'(' without ')'\n");
1885 if (c != ',' && c != ')')
1886 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1888 s++;
1891 s++;
1892 while (isspace(*s)) s++;
1893 if (*s!='\0')
1894 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1896 if (argcount != regcount)
1897 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1898 argcount, regcount
1901 (*funclistptr)->libcall = def_libcall;
1902 for (i = 0; i < argcount; i++)
1903 funcaddarg(*funclistptr, args[i], regs[i]);
1905 else if (*s == '\0')
1906 { /* No registers specified */
1907 for (i = 0; i < argcount; i++)
1908 funcaddarg(*funclistptr, args[i], NULL);
1910 else
1911 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1916 static void readsectionclass_methodlist(struct classinfo *cl)
1918 int atend = 0, i;
1919 char *line, *s, *s2;
1920 struct functionhead **methlistptr = &cl->methlist;
1921 struct stringlist *interface = NULL;
1923 if (cl->basename==NULL)
1924 exitfileerror(20, "section methodlist has to come after section config\n");
1926 while (!atend)
1928 line = readline();
1929 if (line==NULL)
1930 exitfileerror(20, "unexptected EOF in methodlist section\n");
1932 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1933 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1934 continue;
1936 if (isspace(*line))
1937 exitfileerror(20, "No space allowed at start of the line\n");
1939 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1941 s = line+2;
1942 while (isspace(*s)) s++;
1943 if (strncmp(s, "end", 3)!=0)
1944 exitfileerror(20, "\"##end methodlist\" expected\n");
1946 s += 3;
1947 while (isspace(*s)) s++;
1948 if (strncmp(s, "methodlist", 10)!=0)
1949 exitfileerror(20, "\"##end methodlist\" expected\n");
1951 s += 10;
1952 while (isspace(*s)) s++;
1953 if (*s!='\0')
1954 exitfileerror(20, "unexpected character on position %d\n", s-line);
1956 atend = 1;
1958 continue;
1961 if (*line=='.')
1963 s = line+1;
1964 if (strncmp(s, "alias", 5)==0)
1966 s += 5;
1968 if (!isspace(*s))
1969 exitfileerror(20, "syntax is '.alias name'\n");
1971 while (isspace(*s)) s++;
1972 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1973 exitfileerror(20, "syntax is '.alias name'\n");
1975 s2 = s;
1976 s++;
1977 while (isalnum(*s) || *s == '_') s++;
1979 if (isspace(*s))
1981 *s = '\0';
1982 do {
1983 s++;
1984 } while (isspace(*s));
1987 if (*s != '\0')
1988 exitfileerror(20, "syntax is '.alias name'\n");
1990 if (*methlistptr == NULL)
1991 exitfileerror(20, ".alias has to come after a function declaration\n");
1993 slist_append(&(*methlistptr)->aliases, s2);
1995 else if (strncmp(s, "function", 8) == 0)
1997 s += 8;
1999 if (!isspace(*s))
2000 exitfileerror(20, "Syntax error\n");
2002 while (isspace(*s)) s++;
2003 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
2004 exitfileerror(20, "syntax is '.function name'\n");
2006 s2 = s;
2007 s++;
2008 while (isalnum(*s) || *s == '_') s++;
2010 if (isspace(*s))
2012 *s = '\0';
2013 do {
2014 s++;
2015 } while (isspace(*s));
2018 if (*s != '\0')
2019 exitfileerror(20, "syntax is '.function name'\n");
2021 if (*methlistptr == NULL)
2022 exitfileerror(20, ".function has to come after a function declaration\n");
2024 funcsetinternalname(*methlistptr, s2);
2026 else if (strncmp(s, "interface", 9) == 0)
2028 if (cl->classtype != HIDD)
2029 exitfileerror(20, "interface only valid for a HIDD\n");
2031 s += 9;
2033 if (!isspace(*s))
2034 exitfileerror(20, "Syntax error\n");
2036 while (isspace(*s)) s++;
2037 if (*s == '\0' || !isalpha(*s))
2038 exitfileerror(20, "syntax is '.interface name'\n");
2040 s2 = s;
2041 s++;
2042 while (isalnum(*s) || *s == '_') s++;
2044 if (isspace(*s))
2046 *s = '\0';
2047 do {
2048 s++;
2049 } while (isspace(*s));
2052 if (*s != '\0')
2053 exitfileerror(20, "syntax is '.interface name'\n");
2055 interface = slist_append(&cl->interfaces, s2);
2057 else
2058 exitfileerror(20, "Syntax error");
2060 else if (isalpha(*line))
2062 char stmp[256];
2064 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
2067 if (cl->classtype == HIDD && interface == NULL)
2068 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
2070 if (*s != '\0')
2071 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
2073 if (*methlistptr != NULL)
2074 methlistptr = &((*methlistptr)->next);
2075 if (cl->classtype != HIDD)
2077 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
2078 exitfileerror(20, "Method name too large\n");
2080 *methlistptr = newfunctionhead(stmp, STACK);
2081 (*methlistptr)->type = "IPTR";
2082 funcaddarg(*methlistptr, "Class *cl", NULL);
2083 funcaddarg(*methlistptr, "Object *o", NULL);
2084 funcaddarg(*methlistptr, "Msg msg", NULL);
2086 else
2088 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
2089 exitfileerror(20, "Method name too large\n");
2091 *methlistptr = newfunctionhead(stmp, STACK);
2092 (*methlistptr)->type = "IPTR";
2093 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
2094 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
2095 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
2096 (*methlistptr)->interface = interface;
2097 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
2098 exitfileerror(20, "Method name too large\n");
2099 (*methlistptr)->method = strdup(stmp);
2101 slist_append(&(*methlistptr)->aliases, line);
2103 else
2104 exitfileerror(20, "Methodname has to begin with a letter\n");
2108 static void
2109 readsectioninterface(struct config *cfg)
2111 char *s;
2112 struct interfaceinfo *in;
2114 in = newinterface(cfg);
2115 s = readsections(cfg, NULL, in, 1);
2116 if (s == NULL)
2117 exitfileerror(20, "Unexpected end of file\n");
2119 if (strncmp(s, "##", 2) != 0)
2120 exitfileerror(20, "'##end interface' expected\n");
2121 s += 2;
2123 while (isspace(*s)) s++;
2125 if (strncmp(s, "end", 3) != 0)
2126 exitfileerror(20, "'##end interface' expected\n");
2127 s += 3;
2129 if (!isspace(*s))
2130 exitfileerror(20, "'##end interface' expected\n");
2131 while (isspace(*s)) s++;
2133 if (strncmp(s, "interface", 9) != 0)
2134 exitfileerror(20, "'##end interface' expected\n");
2135 s += 9;
2137 while (isspace(*s)) s++;
2138 if (*s != '\0')
2139 exitfileerror(20, "'##end interface' expected\n");
2141 if (!in->interfaceid)
2142 exitfileerror(20, "interface has no 'interfaceid' defined!\n");
2144 if (!in->interfacename)
2145 exitfileerror(20, "interface has no 'interfacename' defined!\n");
2147 if (!in->methodstub)
2148 in->methodstub = strdup(in->interfacename);
2150 if (!in->methodbase) {
2151 int len = strlen(in->interfacename);
2152 in->methodbase = malloc(len + 4 + 1);
2153 strcpy(in->methodbase, in->interfacename);
2154 strcat(in->methodbase, "Base");
2157 if (!in->attributebase) {
2158 int len = strlen(in->interfacename);
2159 in->attributebase = malloc(len + 4 + 4 + 1);
2160 strcpy(in->attributebase, in->interfacename);
2161 strcat(in->attributebase, "AttrBase");
2165 static void
2166 readsectionclass(struct config *cfg)
2168 char *s;
2169 struct classinfo *cl;
2171 cl = newclass(cfg);
2172 s = readsections(cfg, cl, NULL, 1);
2173 if (s == NULL)
2174 exitfileerror(20, "Unexpected end of file\n");
2176 if (strncmp(s, "##", 2) != 0)
2177 exitfileerror(20, "'##end class' expected\n");
2178 s += 2;
2180 while (isspace(*s)) s++;
2182 if (strncmp(s, "end", 3) != 0)
2183 exitfileerror(20, "'##end class' expected\n");
2184 s += 3;
2186 if (!isspace(*s))
2187 exitfileerror(20, "'##end class' expected\n");
2188 while (isspace(*s)) s++;
2190 if (strncmp(s, "class", 5) != 0)
2191 exitfileerror(20, "'##end class' expected\n");
2192 s += 5;
2194 while (isspace(*s)) s++;
2195 if (*s != '\0')
2196 exitfileerror(20, "'##end class' expected\n");
2199 static struct classinfo *newclass(struct config *cfg)
2201 struct classinfo *cl, *classlistit;
2203 cl = malloc(sizeof(struct classinfo));
2204 if (cl == NULL)
2206 fprintf(stderr, "Out of memory\n");
2207 exit(20);
2209 memset(cl, 0, sizeof(struct classinfo));
2211 /* By default the classes are initialized with a priority of 1 so they
2212 * are initialized before any user added initialization with priority 1
2214 cl->initpri = 1;
2216 if (cfg->classlist == NULL)
2217 cfg->classlist = cl;
2218 else
2222 classlistit = cfg->classlist;
2223 classlistit->next != NULL;
2224 classlistit = classlistit->next
2227 classlistit->next = cl;
2230 return cl;
2233 static struct handlerinfo *newhandler(struct config *cfg)
2235 struct handlerinfo *hl;
2237 hl = calloc(1,sizeof(*hl));
2238 hl->next = cfg->handlerlist;
2239 cfg->handlerlist = hl;
2240 return hl;
2243 static struct interfaceinfo *newinterface(struct config *cfg)
2245 struct interfaceinfo *in, *interfacelistit;
2247 in = malloc(sizeof(struct interfaceinfo));
2248 if (in == NULL)
2250 fprintf(stderr, "Out of memory\n");
2251 exit(20);
2253 memset(in, 0, sizeof(struct interfaceinfo));
2255 if (cfg->interfacelist == NULL)
2256 cfg->interfacelist = in;
2257 else
2261 interfacelistit = cfg->interfacelist;
2262 interfacelistit->next != NULL;
2263 interfacelistit = interfacelistit->next
2266 interfacelistit->next = in;
2269 return in;
2273 static int getdirective(char *s, const char *directive, int range_min, int range_max, int *val)
2275 char *tmp;
2276 int newval;
2278 if (strncmp(s, directive, strlen(directive)) != 0)
2279 return 0;
2281 s += strlen(directive);
2282 if (*s && !isspace(*s))
2283 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive);
2285 while (isspace(*s)) s++;
2286 if (!*s)
2287 exitfileerror(20, "No .%s value specified\n", directive);
2289 newval = strtol(s, &tmp, 0);
2290 if (s == tmp || !(newval >= range_min && newval <= range_max)) {
2291 tmp = s;
2292 while (*tmp && !isspace(*tmp)) tmp++;
2293 exitfileerror(20, "Invalid .%s value of %.*s\n", directive, tmp - s, s);
2296 *val = newval;
2297 return 1;
2300 static void
2301 readsectionhandler(struct config *cfg)
2303 char *line = NULL, *s;
2304 struct handlerinfo *hl;
2305 unsigned char autolevel = 0;
2306 unsigned int stacksize = 0;
2307 int startup = 0;
2308 char priority = 10;
2309 int bootpri = -128;
2310 int has_filesystem = 0;
2312 for (;;)
2314 char *function;
2315 int function_len;
2316 char *tmp;
2318 s = line = readline();
2320 if (s==NULL)
2321 exitfileerror(20, "unexpected end of file in section hanlder\n");
2323 if (strncmp(s, "##", 2)==0)
2324 break;
2326 /* Ignore comments */
2327 if (strncmp(s, "#", 1)==0)
2328 continue;
2330 /* Skip ahead to function name */
2331 while (*s && isspace(*s)) s++;
2333 /* Permit blank lines */
2334 if (!*s)
2335 continue;
2337 if (*s == '.') {
2338 int val;
2339 s++;
2341 if (getdirective(s, "autodetect", 0, 127, &val)) {
2342 autolevel = val;
2343 } else if (getdirective(s, "stacksize", 0, INT_MAX, &val)) {
2344 stacksize = val;
2345 } else if (getdirective(s, "priority", -128, 127, &val)) {
2346 priority = val;
2347 } else if (getdirective(s, "bootpri", -128, 127, &val)) {
2348 bootpri = val;
2349 } else if (getdirective(s, "startup", INT_MIN, INT_MAX, &val)) {
2350 startup = val;
2351 } else {
2352 exitfileerror(20, "Unrecognized directive \"%s\"\n", line);
2354 continue;
2357 do {
2358 unsigned int id = 0;
2360 if (strncasecmp(s,"resident=",9)==0) {
2361 char *res;
2363 s = strchr(s, '=') + 1;
2364 res = s;
2365 while (*s && !isspace(*s)) s++;
2366 if (res == s)
2367 exitfileerror(20, "Empty resident= is not permitted\n");
2369 if (*s)
2370 *(s++) = 0;
2372 hl = newhandler(cfg);
2373 hl->type = HANDLER_RESIDENT;
2374 hl->id = 0;
2375 hl->name = strdup(res);
2376 hl->autodetect = autolevel--;
2377 hl->stacksize = stacksize;
2378 hl->priority = priority;
2379 hl->startup = startup;
2380 } else if (strncasecmp(s,"dosnode=",8)==0) {
2381 char *dev;
2383 s = strchr(s, '=') + 1;
2384 dev = s;
2385 while (*s && !isspace(*s)) s++;
2386 if (dev == s)
2387 exitfileerror(20, "Empty dosnode= is not permitted\n");
2389 if (*s)
2390 *(s++) = 0;
2392 hl = newhandler(cfg);
2393 hl->type = HANDLER_DOSNODE;
2394 hl->id = 0;
2395 hl->name = strdup(dev);
2396 hl->autodetect = autolevel ? autolevel-- : 0;
2397 hl->stacksize = stacksize;
2398 hl->priority = priority;
2399 hl->startup = startup;
2400 hl->bootpri = bootpri;
2401 } else if (strncasecmp(s,"dostype=",8) == 0) {
2402 s = strchr(s, '=') + 1;
2404 id = (unsigned int)strtoul(s, &tmp, 0);
2406 if (s == tmp) {
2407 while (*tmp && !isspace(*tmp))
2408 tmp++;
2409 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp -s), s);
2411 s = tmp;
2413 if (id == 0 || id == ~0) {
2414 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id);
2417 hl = newhandler(cfg);
2418 hl->type = HANDLER_DOSTYPE;
2419 hl->id = id;
2420 hl->name = NULL;
2421 hl->autodetect = autolevel ? autolevel-- : 0;
2422 hl->stacksize = stacksize;
2423 hl->priority = priority;
2424 hl->startup = startup;
2425 } else {
2426 for (tmp = s; !isspace(*tmp); tmp++);
2427 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp - s, s);
2430 /* Advance to next ID */
2431 while (*s && isspace(*s)) s++;
2433 } while (*s);
2436 if (s == NULL)
2437 exitfileerror(20, "Unexpected end of file\n");
2439 if (strncmp(s, "##", 2) != 0)
2440 exitfileerror(20, "'##end handler' expected\n");
2441 s += 2;
2443 while (isspace(*s)) s++;
2445 if (strncmp(s, "end", 3) != 0)
2446 exitfileerror(20, "'##end handler' expected\n");
2447 s += 3;
2449 while (isspace(*s)) s++;
2451 if (strncmp(s, "handler", 7) != 0)
2452 exitfileerror(20, "'##end handler' expected\n");
2453 s += 7;
2455 while (isspace(*s)) s++;
2456 if (*s != '\0')
2457 exitfileerror(20, "'##end handler' expected\n");