Added support for a new config option, "includename". This value defaults
[AROS.git] / tools / genmodule / config.c
blobddf82c7dc92794ef46b8eb0284797b7732e79e71
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} 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
179 fprintf(stderr, "Unrecognized argument \"%s\"\n%s", argv[optind], usage);
180 exit(20);
183 cfg->modulename = argv[optind+1];
184 cfg->modulenameupper = strdup(cfg->modulename);
185 for (s=cfg->modulenameupper; *s!='\0'; *s = toupper(*s), s++) {
186 if (!isalnum(*s)) *s = '_';
189 if (strcmp(argv[optind+2],"library")==0)
191 cfg->modtype = LIBRARY;
192 cfg->moddir = "Libs";
194 else if (strcmp(argv[optind+2],"mcc")==0)
196 cfg->modtype = MCC;
197 cfg->moddir = "Classes/Zune";
199 else if (strcmp(argv[optind+2],"mui")==0)
201 cfg->modtype = MUI;
202 cfg->moddir = "Classes/Zune";
204 else if (strcmp(argv[optind+2],"mcp")==0)
206 cfg->modtype = MCP;
207 cfg->moddir = "Classes/Zune";
209 else if (strcmp(argv[optind+2], "device")==0)
211 cfg->modtype = DEVICE;
212 cfg->moddir = "Devs";
214 else if (strcmp(argv[optind+2], "resource")==0)
216 cfg->modtype = RESOURCE;
217 cfg->moddir = "Devs";
219 else if (strcmp(argv[optind+2], "gadget")==0)
221 cfg->modtype = GADGET;
222 cfg->moddir = "Classes/Gadgets";
224 else if (strcmp(argv[optind+2], "datatype")==0)
226 cfg->modtype = DATATYPE;
227 cfg->moddir = "Classes/DataTypes";
229 else if (strcmp(argv[optind+2], "usbclass")==0)
231 cfg->modtype = USBCLASS;
232 cfg->moddir = "Classes/USB";
233 if(!hassuffix)
235 cfg->suffix = "class";
236 hassuffix = 1;
239 else if (strcmp(argv[optind+2], "hidd")==0)
241 cfg->modtype = HIDD;
242 cfg->moddir = "Devs/Drivers";
244 else if (strcmp(argv[optind+2], "handler")==0)
246 cfg->modtype = HANDLER;
247 cfg->moddir = "$(AROS_DIR_FS)";
249 else if (strcmp(argv[optind+2], "hook")==0)
251 cfg->modtype = HANDLER;
252 cfg->moddir = "Devs";
254 else
256 fprintf(stderr, "Unknown modtype \"%s\" specified for second argument\n", argv[optind+2]);
257 exit(20);
259 cfg->modtypestr = argv[optind+2];
261 if (!hassuffix)
262 cfg->suffix = argv[optind+2];
264 /* Fill fields with default value if not specified on the command line */
266 char tmpbuf[256];
268 if (cfg->conffile == NULL)
270 snprintf(tmpbuf, sizeof(tmpbuf), "%s.conf", cfg->modulename);
271 cfg->conffile = strdup(tmpbuf);
274 if (cfg->gendir == NULL)
275 cfg->gendir = ".";
278 readconfig(cfg);
280 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
281 * if they are provided
283 if (cfg->beginiofunc != NULL)
285 struct functionhead *funchead;
287 cfg->intcfg |= CFG_NOREADFUNCS;
289 /* Add beginio_func to the list of functions */
290 funchead = newfunctionhead(cfg->beginiofunc, REGISTERMACRO);
291 funchead->type = strdup("void");
292 funchead->lvo = 5;
293 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
295 funchead->next = cfg->funclist;
296 cfg->funclist = funchead;
298 /* Add abortio_func to the list of functions */
299 funchead = newfunctionhead(cfg->abortiofunc, REGISTERMACRO);
300 funchead->type = strdup("LONG");
301 funchead->lvo = 6;
302 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
304 funchead->next = cfg->funclist->next;
305 cfg->funclist->next = funchead;
307 else if (cfg->modtype == DEVICE && cfg->intcfg & CFG_NOREADFUNCS)
309 fprintf
311 stderr,
312 "beginio_func and abortio_func missing for a device with a non empty function list\n"
314 exit(20);
317 /* See if we have any stackcall options */
318 if (cfg->funclist) {
319 struct functionhead *funchead;
321 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
322 if (funchead->libcall == STACK) {
323 cfg->options |= OPTION_STACKCALL;
324 break;
329 /* Provide default version for functions that didnt have it */
330 if (cfg->funclist) {
331 struct functionhead *funchead;
332 int defversion = cfg->majorversion; /* Assume library version is default */
334 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
335 if (funchead->version > -1) {
336 /* There was at least one .version tag. Assume 0 is default */
337 defversion = 0;
338 break;
342 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
343 if (funchead->version == -1) {
344 funchead->version = defversion;
349 /* Verify that a handler has a handler */
350 if (cfg->modtype == HANDLER) {
351 if (cfg->handlerfunc == NULL) {
352 fprintf(stderr, "handler modules require a 'handler_func' ##config option\n");
353 exit(20);
355 cfg->options |= OPTION_NOAUTOLIB | OPTION_NOEXPUNGE | OPTION_NOOPENCLOSE;
358 return cfg;
361 /* Functions to read configuration from the configuration file */
363 #include "fileread.h"
365 static char *readsections(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
366 static void readsectionconfig(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
367 static void readsectioncdef(struct config *);
368 static void readsectioncdefprivate(struct config *);
369 static void readsectionstartup(struct config *);
370 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall);
371 static void readsectionclass_methodlist(struct classinfo *);
372 static void readsectionclass(struct config *);
373 static void readsectionhandler(struct config *);
374 static void readsectioninterface(struct config *);
376 static void readconfig(struct config *cfg)
378 struct classinfo *mainclass = NULL;
380 /* Create a classinfo structure if this module is a class */
381 switch (cfg->modtype)
383 case LIBRARY:
384 case DEVICE:
385 case RESOURCE:
386 case USBCLASS:
387 case HANDLER:
388 break;
390 case MCC:
391 case MUI:
392 case MCP:
393 case GADGET:
394 case DATATYPE:
395 case HIDD:
396 mainclass = newclass(cfg);
397 mainclass->classtype = cfg->modtype;
398 break;
400 default:
401 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
402 exit(20);
405 switch (cfg->modtype)
407 case LIBRARY:
408 case USBCLASS:
409 cfg->firstlvo = 5;
410 break;
411 case DEVICE:
412 cfg->firstlvo = 7;
413 break;
414 case MCC:
415 case MUI:
416 case MCP:
417 cfg->firstlvo = 6;
418 mainclass->boopsimprefix = muimprefix;
419 break;
420 case HANDLER:
421 case RESOURCE:
422 cfg->firstlvo = 1;
423 break;
424 case GADGET:
425 cfg->firstlvo = 5;
426 mainclass->boopsimprefix = gadgetmprefix;
427 break;
428 case DATATYPE:
429 cfg->firstlvo = 6;
430 mainclass->boopsimprefix = dtmprefix;
431 break;
432 case HIDD:
433 cfg->firstlvo = 5;
434 /* FIXME: need boopsimprefix ? */
435 break;
436 default:
437 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
438 exit(20);
441 if (!fileopen(cfg->conffile))
443 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
444 exit(20);
447 /* Read all sections and see that we are at the end of the file */
448 if (readsections(cfg, mainclass, NULL, 0) != NULL)
449 exitfileerror(20, "Syntax error");
451 fileclose();
454 /* readsections will scan through all the sections in the config file.
455 * arguments:
456 * struct config *cfg: The module config data which may be updated by
457 * the information in the sections
458 * struct classinfo *cl: The classdata to be filled with data from the sections.
459 * This may be NULL if this is the main part of the configuration file and the
460 * type of the module is not a class
461 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
462 * part of the config file.
464 static char *readsections(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
466 char *line, *s, *s2;
467 int hasconfig = 0;
469 while ((line=readline())!=NULL)
471 if (strncmp(line, "##", 2)==0)
473 static char *parts[] =
475 "config", "cdefprivate", "cdef", "startup", "functionlist", "methodlist", "class", "handler", "interface", "attributelist", "cfunctionlist"
477 const unsigned int nums = sizeof(parts)/sizeof(char *);
478 unsigned int partnum;
479 int i, atend = 0;
481 s = line+2;
482 while (isspace(*s)) s++;
484 if (strncmp(s, "begin", 5)!=0)
485 return line;
487 s += 5;
488 if (!isspace(*s))
489 exitfileerror(20, "space after begin expected\n");
490 while (isspace(*s)) s++;
492 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
494 if (strncmp(s, parts[i], strlen(parts[i]))==0)
496 partnum = i+1;
497 s += strlen(parts[i]);
498 while (isspace(*s)) s++;
499 if (*s!='\0')
500 exitfileerror(20, "unexpected character on position %d\n", s-line);
503 if (partnum==0)
504 exitfileerror(20, "unknown start of section\n");
505 switch (partnum)
507 case 1: /* config */
508 readsectionconfig(cfg, cl, in, inclass);
509 hasconfig = 1;
510 break;
512 case 2: /* cdefprivate */
513 if (inclass)
514 exitfileerror(20, "cdefprivate section not allowed in class section\n");
515 readsectioncdefprivate(cfg);
516 break;
518 case 3: /* cdef */
519 if (inclass)
520 exitfileerror(20, "cdef section not allowed in class section\n");
521 readsectioncdef(cfg);
522 break;
524 case 4: /* startup */
525 if (inclass)
526 exitfileerror(20, "startup section not allowed in class section\n");
527 readsectionstartup(cfg);
528 break;
530 case 5: /* functionlist */
531 if (inclass)
532 exitfileerror(20, "functionlist section not allow in class section\n");
533 if (cfg->basename==NULL)
534 exitfileerror(20, "section functionlist has to come after section config\n");
536 readsectionfunctionlist("functionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTERMACRO);
537 cfg->intcfg |= CFG_NOREADFUNCS;
538 break;
540 case 6: /* methodlist */
541 if (cl == NULL && in == NULL)
542 exitfileerror(20, "methodlist section when not in a class or interface\n");
543 if (cl)
544 readsectionclass_methodlist(cl);
545 else
546 readsectionfunctionlist("methodlist", &in->methodlist, 0, 0, REGISTERMACRO);
547 cfg->intcfg |= CFG_NOREADFUNCS;
548 break;
550 case 7: /* class */
551 if (inclass)
552 exitfileerror(20, "class section may not be in nested\n");
553 readsectionclass(cfg);
554 break;
555 case 8: /* handler */
556 readsectionhandler(cfg);
557 break;
558 case 9: /* interface */
559 if (inclass)
560 exitfileerror(20, "interface section may not be nested\n");
561 readsectioninterface(cfg);
562 break;
563 case 10: /* attributelist */
564 if (!in)
565 exitfileerror(20, "attributelist only valid in interface sections\n");
566 readsectionfunctionlist("attributelist", &in->attributelist, 0, 1, INVALID);
567 break;
568 case 11: /* cfunctionlist */
569 if (inclass)
570 exitfileerror(20, "cfunctionlist section not allow in class section\n");
571 if (cfg->basename==NULL)
572 exitfileerror(20, "section cfunctionlist has to come after section config\n");
574 readsectionfunctionlist("cfunctionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTER);
575 cfg->intcfg |= CFG_NOREADFUNCS;
576 break;
579 else if (strlen(line)!=0)
580 filewarning("warning line outside section ignored\n");
583 if(!inclass)
585 if (!hasconfig)
586 exitfileerror(20, "No config section in conffile\n");
588 /* If no indication was given for generating includes or not
589 decide on module type and if there are functions
591 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
593 switch (cfg->modtype)
595 case LIBRARY:
596 case RESOURCE:
597 cfg->options |= OPTION_INCLUDES;
598 break;
600 case HANDLER:
601 case MCC:
602 case MUI:
603 case MCP:
604 case USBCLASS:
605 cfg->options |= OPTION_NOINCLUDES;
606 break;
608 case DEVICE:
609 cfg->options |= (
610 (cfg->funclist != NULL)
611 || (cfg->cdeflines != NULL)
612 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
613 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
614 break;
616 case GADGET:
617 case DATATYPE:
618 case HIDD:
619 cfg->options |= (
620 (cfg->funclist != NULL)
621 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
622 break;
624 default:
625 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
626 exit(20);
627 break;
631 /* If no indication was given for not generating stubs only generate them if
632 * the module has functions
634 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
636 switch (cfg->modtype)
638 case LIBRARY:
639 cfg->options |= (cfg->funclist != NULL) ? OPTION_STUBS : OPTION_NOSTUBS;
640 break;
642 case USBCLASS:
643 case RESOURCE:
644 case GADGET:
645 case DEVICE:
646 case DATATYPE:
647 case MCC:
648 case MUI:
649 case MCP:
650 case HIDD:
651 case HANDLER:
652 cfg->options |= OPTION_NOSTUBS;
653 break;
655 default:
656 fprintf(stderr, "Internal error writemakefile: unhandled modtype for stubs\n");
657 exit(20);
658 break;
662 /* If no indication was given for generating autoinit code or not
663 decide on module type
665 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
667 switch (cfg->modtype)
669 case LIBRARY:
670 cfg->options |= OPTION_AUTOINIT;
671 break;
673 case USBCLASS:
674 case RESOURCE:
675 case GADGET:
676 case DEVICE:
677 case DATATYPE:
678 case MCC:
679 case MUI:
680 case MCP:
681 case HIDD:
682 case HANDLER:
683 cfg->options |= OPTION_NOAUTOINIT;
684 break;
686 default:
687 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
688 exit(20);
689 break;
693 if ((cfg->modtype == RESOURCE) || (cfg->modtype == HANDLER))
694 /* Enforce noopenclose for resources and handlers */
695 cfg->options |= OPTION_NOOPENCLOSE;
696 else if (!(cfg->options & OPTION_SELFINIT))
697 /* Enforce using RTF_AUTOINIT for everything except resources */
698 cfg->options |= OPTION_RESAUTOINIT;
701 return NULL;
704 static void readsectionconfig(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
706 int atend = 0, i;
707 char *line, *s, *s2, *libbasetypeextern = NULL;
708 struct tm date;
710 while (!atend)
712 line = readline();
713 if (line==NULL)
714 exitfileerror(20, "unexpected end of file in section config\n");
716 if (strncmp(line, "##", 2)!=0)
718 const char *names[] =
720 "basename", "libbase", "libbasetype", "libbasetypeextern",
721 "version", "date", "copyright", "libcall", "forcebase", "superclass",
722 "superclass_field", "residentpri", "options", "sysbase_field",
723 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
724 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
725 "initpri", "type", "addromtag", "oopbase_field",
726 "rellib", "interfaceid", "interfacename",
727 "methodstub", "methodbase", "attributebase", "handler_func",
728 "includename"
730 const unsigned int namenums = sizeof(names)/sizeof(char *);
731 unsigned int namenum;
733 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
737 strncmp(line, names[i], strlen(names[i]))==0
738 && isspace(*(line+strlen(names[i])))
740 namenum = i+1;
742 if (namenum==0)
743 exitfileerror(20, "unrecognized configuration option\n");
745 s = line + strlen(names[namenum-1]);
746 if (!isspace(*s))
747 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
749 while (isspace(*s)) s++;
750 if (*s=='\0')
751 exitfileerror(20, "unexpected end of line\n");
753 s2 = s + strlen(s);
754 while (isspace(*(s2-1))) s2--;
755 *s2 = '\0';
757 switch (namenum)
759 case 1: /* basename */
760 if (!inclass)
761 cfg->basename = strdup(s);
762 if (cl != NULL)
763 cl->basename = strdup(s);
764 if (in != NULL)
765 exitfileerror(20, "basename not valid config option when in an interface section\n");
766 break;
768 case 2: /* libbase */
769 if (inclass)
770 exitfileerror(20, "libbase not valid config option when in a class section\n");
771 cfg->libbase = strdup(s);
772 break;
774 case 3: /* libbasetype */
775 if (inclass)
776 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
777 cfg->libbasetype = strdup(s);
778 break;
780 case 4: /* libbasetypeextern */
781 if (inclass)
782 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
783 libbasetypeextern = strdup(s);
784 break;
786 case 5: /* version */
787 if (inclass)
788 exitfileerror(20, "version not valid config option when in a class section\n");
789 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
790 exitfileerror(20, "wrong version string \"%s\"\n", s);
791 break;
793 case 6: /* date */
794 if (inclass)
795 exitfileerror(20, "date not valid config option when in a class section\n");
796 #ifndef _WIN32
797 if (strptime(s, "%e.%m.%Y", &date) == NULL)
799 exitfileerror(20, "date string has to have d.m.yyyy format\n");
801 #endif
802 cfg->datestring = strdup(s);
803 break;
805 case 7: /* copyright */
806 if (inclass)
807 exitfileerror(20, "copyright not valid config option when in a class section\n");
808 cfg->copyright = strdup(s);
809 break;
811 case 8: /* libcall */
812 fprintf(stderr, "libcall specification is deprecated and ignored\n");
813 break;
815 case 9: /* forcebase */
816 if (inclass)
817 exitfileerror(20, "forcebase not valid config option when in a class section\n");
818 slist_append(&cfg->forcelist, s);
819 break;
821 case 10: /* superclass */
822 if (cl == NULL)
823 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
824 cl->superclass = strdup(s);
825 break;
827 case 11: /* superclass_field */
828 if (cl == NULL)
829 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
830 cl->superclass_field = strdup(s);
831 break;
833 case 12: /* residentpri */
834 if (!inclass)
836 int count;
837 char dummy;
839 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
840 if (count != 1 ||
841 cfg->residentpri < -128 || cfg->residentpri > 127
844 exitfileerror(20, "residentpri number format error\n");
847 else
848 exitfileerror(20, "residentpri not valid config option when in a class section\n");
849 break;
851 case 13: /* options */
852 if (!inclass)
854 static const char *optionnames[] =
856 "noautolib", "noexpunge", "noresident", "peropenerbase",
857 "pertaskbase", "includes", "noincludes", "nostubs",
858 "autoinit", "noautoinit", "resautoinit", "noopenclose",
859 "selfinit"
861 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
862 int optionnum;
866 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
868 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
870 optionnum = i + 1;
871 s += strlen(optionnames[i]);
872 while (isspace(*s)) s++;
873 if (*s == ',')
874 s++;
875 else if (*s != '\0')
876 exitfileerror(20, "Unrecognized option\n");
879 if (optionnum == 0)
880 exitfileerror(20, "Unrecognized option\n");
881 switch (optionnum)
883 case 1: /* noautolib */
884 cfg->options |= OPTION_NOAUTOLIB;
885 break;
886 case 2: /* noexpunge */
887 cfg->options |= OPTION_NOEXPUNGE;
888 break;
889 case 3: /* noresident */
890 cfg->options |= OPTION_NORESIDENT;
891 cfg->firstlvo = 1;
892 break;
893 case 5: /* pertaskbase */
894 cfg->options |= OPTION_PERTASKBASE;
895 /* Fall through */
896 case 4: /* peropenerbase */
897 if (cfg->options & OPTION_DUPBASE)
898 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
899 cfg->options |= OPTION_DUPBASE;
900 break;
901 case 6: /* includes */
902 if (cfg->options & OPTION_NOINCLUDES)
903 exitfileerror(20, "option includes and noincludes are incompatible\n");
904 cfg->options |= OPTION_INCLUDES;
905 break;
906 case 7: /* noincludes */
907 if (cfg->options & OPTION_INCLUDES)
908 exitfileerror(20, "option includes and noincludes are incompatible\n");
909 cfg->options |= OPTION_NOINCLUDES;
910 break;
911 case 8: /* nostubs */
912 cfg->options |= OPTION_NOSTUBS;
913 break;
914 case 9: /* autoinit */
915 if (cfg->options & OPTION_NOAUTOINIT)
916 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
917 cfg->options |= OPTION_AUTOINIT;
918 break;
919 case 10: /* noautoinit */
920 if (cfg->options & OPTION_AUTOINIT)
921 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
922 cfg->options |= OPTION_NOAUTOINIT;
923 break;
924 case 11: /* resautoinit */
925 if (cfg->options & OPTION_SELFINIT)
926 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
927 cfg->options |= OPTION_RESAUTOINIT;
928 break;
929 case 12:
930 cfg->options |= OPTION_NOOPENCLOSE;
931 break;
932 case 13: /* noresautoinit */
933 if (cfg->options & OPTION_RESAUTOINIT)
934 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
935 cfg->options |= OPTION_SELFINIT;
936 break;
938 while (isspace(*s)) s++;
939 } while(*s !='\0');
941 else
943 static const char *optionnames[] =
945 "private"
947 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
948 int optionnum;
952 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
954 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
956 optionnum = i + 1;
957 s += strlen(optionnames[i]);
958 while (isspace(*s)) s++;
959 if (*s == ',')
960 s++;
961 else if (*s != '\0')
962 exitfileerror(20, "Unrecognized option\n");
965 if (optionnum == 0)
966 exitfileerror(20, "Unrecognized option\n");
967 switch (optionnum)
969 case 1: /* private */
970 cl->options |= COPTION_PRIVATE;
971 break;
973 while (isspace(*s)) s++;
974 } while(*s !='\0');
976 break;
978 case 14: /* sysbase_field */
979 if (inclass)
980 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
981 cfg->sysbase_field = strdup(s);
982 break;
984 case 15: /* seglist_field */
985 if (inclass)
986 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
987 cfg->seglist_field = strdup(s);
988 break;
990 case 16: /* rootbase_field */
991 if (inclass)
992 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
993 cfg->rootbase_field = strdup(s);
994 break;
996 case 17: /* classptr_field */
997 if (cl == NULL)
999 exitfileerror
1002 "classptr_field specified when not a BOOPSI class\n"
1005 cl->classptr_field = strdup(s);
1006 break;
1008 case 18: /* classptr_var */
1009 if (cl == NULL)
1011 exitfileerror
1014 "classptr_var specified when not a BOOPSI class\n"
1017 cl->classptr_var = strdup(s);
1018 break;
1020 case 19: /* classid */
1021 if (cl == NULL)
1022 exitfileerror(20, "classid specified when not a BOOPSI class\n");
1023 if (cl->classid != NULL)
1024 exitfileerror(20, "classid specified twice\n");
1025 cl->classid = strdup(s);
1026 if (strcmp(cl->classid, "NULL") == 0)
1027 cl->options |= COPTION_PRIVATE;
1028 break;
1030 case 20: /* classdatatype */
1031 if (cl == NULL)
1032 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
1033 cl->classdatatype = strdup(s);
1034 break;
1036 case 21: /* beginio_func */
1037 if (inclass)
1038 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
1039 if (cfg->modtype != DEVICE)
1040 exitfileerror(20, "beginio_func specified when not a device\n");
1041 cfg->beginiofunc = strdup(s);
1042 break;
1044 case 22: /* abortio_func */
1045 if (inclass)
1046 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
1047 if (cfg->modtype != DEVICE)
1048 exitfileerror(20, "abortio_func specified when not a device\n");
1049 cfg->abortiofunc = strdup(s);
1050 break;
1052 case 23: /* dispatcher */
1053 if (cl == NULL)
1054 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
1055 cl->dispatcher = strdup(s);
1056 /* function references are not needed when dispatcher is specified */
1057 cfg->intcfg |= CFG_NOREADFUNCS;
1058 break;
1060 case 24: /* initpri */
1061 if (cl != NULL)
1063 int count;
1064 char dummy;
1066 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
1067 if (count != 1 ||
1068 cl->initpri < -128 || cl->initpri > 127
1071 exitfileerror(20, "initpri number format error\n");
1074 else
1075 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
1076 break;
1078 case 25: /* type */
1079 if (!inclass)
1080 exitfileerror(20, "type only valid config option in a class section\n");
1081 if (strcmp(s,"mcc")==0)
1082 cl->classtype = MCC;
1083 else if (strcmp(s,"mui")==0)
1084 cl->classtype = MUI;
1085 else if (strcmp(s,"mcp")==0)
1086 cl->classtype = MCP;
1087 else if (strcmp(s, "image")==0)
1088 cl->classtype = IMAGE;
1089 else if (strcmp(s, "gadget")==0)
1090 cl->classtype = GADGET;
1091 else if (strcmp(s, "datatype")==0)
1092 cl->classtype = DATATYPE;
1093 else if (strcmp(s, "usbclass")==0)
1094 cl->classtype = USBCLASS;
1095 else if (strcmp(s, "class")==0)
1096 cl->classtype = CLASS;
1097 else if (strcmp(s, "hidd")==0)
1098 cl->classtype = HIDD;
1099 else
1101 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
1102 exit(20);
1104 break;
1106 case 26: /* addromtag */
1107 cfg->addromtag = strdup(s);
1108 break;
1110 case 27: /* oopbase_field */
1111 cfg->oopbase_field = strdup(s);
1112 break;
1113 case 28: /* rellib */
1114 slist_append(&cfg->rellibs, s);
1115 break;
1116 case 29: /* interfaceid */
1117 if (!in)
1118 exitfileerror(20, "interfaceid only valid config option for an interface\n");
1119 in->interfaceid = strdup(s);
1120 break;
1121 case 30: /* interfacename */
1122 if (!in)
1123 exitfileerror(20, "interfacename only valid config option for an interface\n");
1124 in->interfacename = strdup(s);
1125 break;
1126 case 31: /* methodstub */
1127 if (!in)
1128 exitfileerror(20, "methodstub only valid config option for an interface\n");
1129 in->methodstub = strdup(s);
1130 break;
1131 case 32: /* methodbase */
1132 if (!in)
1133 exitfileerror(20, "methodbase only valid config option for an interface\n");
1134 in->methodbase = strdup(s);
1135 break;
1136 case 33: /* attributebase */
1137 if (!in)
1138 exitfileerror(20, "attributebase only valid config option for an interface\n");
1139 in->attributebase = strdup(s);
1140 break;
1141 case 34: /* handler_func */
1142 if (cfg->modtype != HANDLER)
1143 exitfileerror(20, "handler specified when not a handler\n");
1144 cfg->handlerfunc = strdup(s);
1145 break;
1146 case 35: /* includename */
1147 if (inclass)
1148 exitfileerror(20, "includename not valid config option"
1149 " when in a class section\n");
1150 cfg->includename = strdup(s);
1151 break;
1154 else /* Line starts with ## */
1156 s = line+2;
1157 while (isspace(*s)) s++;
1158 if (strncmp(s, "end", 3)!=0)
1159 exitfileerror(20, "\"##end config\" expected\n");
1161 s += 3;
1162 if (!isspace(*s))
1163 exitfileerror(20, "\"##end config\" expected\n");
1165 while (isspace(*s)) s++;
1166 if (strncmp(s, "config", 6)!=0)
1167 exitfileerror(20, "\"##end config\" expected\n");
1169 s += 6;
1170 while (isspace(*s)) s++;
1171 if (*s!='\0')
1172 exitfileerror(20, "\"##end config\" expected\n");
1174 atend = 1;
1178 /* When not in a class section fill in default values for fields in cfg */
1179 if (!inclass)
1181 if (cfg->basename==NULL)
1183 cfg->basename = strdup(cfg->modulename);
1184 *cfg->basename = toupper(*cfg->basename);
1186 if (cfg->libbase==NULL)
1188 unsigned int len = strlen(cfg->basename)+5;
1189 cfg->libbase = malloc(len);
1190 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1192 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1193 cfg->libbasetype = strdup(libbasetypeextern);
1194 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1195 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1196 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1197 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1198 if (cfg->oopbase_field != NULL && cfg->libbasetype == NULL)
1199 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1200 /* rootbase_field only allowed when duplicating base */
1201 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1202 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1204 /* Set default date to current date */
1205 if (cfg->datestring == NULL)
1207 char tmpbuf[256];
1208 time_t now = time(NULL);
1209 struct tm *ltime = localtime(&now);
1211 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1212 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1214 cfg->datestring = strdup(tmpbuf);
1217 if (cfg->copyright == NULL)
1218 cfg->copyright = "";
1220 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1221 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1223 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1225 if (libbasetypeextern==NULL)
1227 switch (cfg->modtype)
1229 case DEVICE:
1230 cfg->libbasetypeptrextern = "struct Device *";
1231 break;
1232 case HANDLER:
1233 case RESOURCE:
1234 cfg->libbasetypeptrextern = "APTR ";
1235 break;
1236 case LIBRARY:
1237 case MUI:
1238 case MCP:
1239 case MCC:
1240 case GADGET:
1241 case DATATYPE:
1242 case USBCLASS:
1243 case HIDD:
1244 cfg->libbasetypeptrextern = "struct Library *";
1245 break;
1246 default:
1247 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1248 exit(20);
1251 else
1253 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1254 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1255 strcat(cfg->libbasetypeptrextern, " *");
1256 free(libbasetypeextern);
1259 if (cfg->includename == NULL)
1260 cfg->includename = cfg->modulename;
1261 cfg->includenameupper = strdup(cfg->includename);
1262 for (s=cfg->includenameupper; *s!='\0'; *s = toupper(*s), s++)
1263 if (!isalnum(*s)) *s = '_';
1266 /* When class was given too fill in some defaults when not specified */
1267 if (cl != NULL)
1269 if (cl->classtype == UNSPECIFIED)
1270 cl->classtype = CLASS;
1272 if (cl->basename == NULL)
1274 if (!inclass)
1275 cl->basename = cfg->basename;
1276 else
1277 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1280 /* MUI classes are always private */
1281 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1282 cl->options |= COPTION_PRIVATE;
1284 if (cl->classid == NULL
1285 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1288 if (cl->classtype == HIDD)
1290 cl->options &= !COPTION_PRIVATE;
1292 else if (cl->options & COPTION_PRIVATE)
1294 cl->classid = "NULL";
1296 else
1298 char s[256] = "";
1300 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1302 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1304 else if (cl->classtype == DATATYPE)
1306 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1308 cl->classid = strdup(s);
1312 /* Only specify superclass or superclass_field */
1313 if (cl->superclass != NULL && cl->superclass_field != NULL)
1314 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1316 /* Give default value to superclass if it is not specified */
1317 if (cl->superclass == NULL && cl->superclass == NULL)
1319 switch (cl->classtype)
1321 case MUI:
1322 case MCC:
1323 cl->superclass = "MUIC_Area";
1324 break;
1325 case MCP:
1326 cl->superclass = "MUIC_Mccprefs";
1327 break;
1328 case IMAGE:
1329 cl->superclass = "IMAGECLASS";
1330 break;
1331 case GADGET:
1332 cl->superclass = "GADGETCLASS";
1333 break;
1334 case DATATYPE:
1335 cl->superclass = "DATATYPESCLASS";
1336 break;
1337 case CLASS:
1338 cl->superclass = "ROOTCLASS";
1339 break;
1340 case HIDD:
1341 cl->superclass = "CLID_Root";
1342 break;
1343 default:
1344 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1345 break;
1351 static void readsectioncdef(struct config *cfg)
1353 int atend = 0;
1354 char *line, *s;
1356 while (!atend)
1358 line = readline();
1359 if (line==NULL)
1360 exitfileerror(20, "unexptected end of file in section cdef\n");
1362 if (strncmp(line, "##", 2)!=0)
1364 slist_append(&cfg->cdeflines, line);
1366 else
1368 s = line+2;
1369 while (isspace(*s)) s++;
1370 if (strncmp(s, "end", 3)!=0)
1371 exitfileerror(20, "\"##end cdef\" expected\n");
1373 s += 3;
1374 while (isspace(*s)) s++;
1375 if (strncmp(s, "cdef", 4)!=0)
1376 exitfileerror(20, "\"##end cdef\" expected\n");
1378 s += 5;
1379 while (isspace(*s)) s++;
1380 if (*s!='\0')
1381 exitfileerror(20, "unexpected character at position %d\n");
1383 atend = 1;
1388 static void readsectioncdefprivate(struct config *cfg)
1390 int atend = 0;
1391 char *line, *s;
1393 while (!atend)
1395 line = readline();
1396 if (line==NULL)
1397 exitfileerror(20, "unexptected end of file in section cdef\n");
1399 if (strncmp(line, "##", 2)!=0)
1401 slist_append(&cfg->cdefprivatelines, line);
1403 else
1405 s = line+2;
1406 while (isspace(*s)) s++;
1407 if (strncmp(s, "end", 3)!=0)
1408 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1410 s += 3;
1411 while (isspace(*s)) s++;
1412 if (strncmp(s, "cdefprivate", 11)!=0)
1413 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1415 s += 11;
1416 while (isspace(*s)) s++;
1417 if (*s!='\0')
1418 exitfileerror(20, "unexpected character at position %d\n");
1420 atend = 1;
1425 static void readsectionstartup(struct config *cfg)
1427 int atend = 0;
1428 char *line, *s;
1430 while (!atend)
1432 line = readline();
1433 if (line==NULL)
1434 exitfileerror(20, "unexptected end of file in section startup\n");
1436 if (strncmp(line, "##", 2)!=0)
1438 slist_append(&cfg->startuplines, line);
1440 else
1442 s = line+2;
1443 while (isspace(*s)) s++;
1444 if (strncmp(s, "end", 3)!=0)
1445 exitfileerror(20, "\"##end startup\" expected\n");
1447 s += 3;
1448 while (isspace(*s)) s++;
1449 if (strncmp(s, "startup", 7)!=0)
1450 exitfileerror(20, "\"##end startup\" expected\n");
1452 s += 7;
1453 while (isspace(*s)) s++;
1454 if (*s!='\0')
1455 exitfileerror(20, "unexpected character at position %d\n");
1457 atend = 1;
1462 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall)
1464 int atend = 0, i;
1465 char *line, *s, *s2;
1466 unsigned int lvo = firstlvo;
1467 int minversion = -1;
1469 while (!atend)
1471 line = readline();
1472 if (line==NULL)
1473 exitfileerror(20, "unexpected EOF in functionlist section\n");
1474 if (strlen(line)==0)
1476 if (*funclistptr != NULL)
1477 funclistptr = &((*funclistptr)->next);
1478 lvo++;
1480 else if (isspace(*line))
1482 s = line;
1483 while (isspace(*s)) s++;
1484 if (*s=='\0')
1486 if (*funclistptr != NULL)
1487 funclistptr = &((*funclistptr)->next);
1488 lvo++;
1490 else
1491 exitfileerror(20, "no space allowed before functionname\n");
1493 else if (strncmp(line, "##", 2)==0)
1495 s = line+2;
1496 while (isspace(*s)) s++;
1497 if (strncmp(s, "end", 3)!=0)
1498 exitfileerror(20, "\"##end %s\" expected\n", type);
1500 s += 3;
1501 while (isspace(*s)) s++;
1502 if (strncmp(s, type, strlen(type))!=0)
1503 exitfileerror(20, "\"##end %s\" expected\n", type);
1505 s += strlen(type);
1506 while (isspace(*s)) s++;
1507 if (*s!='\0')
1508 exitfileerror(20, "unexpected character on position %d\n", s-line);
1510 atend = 1;
1512 else if (*line=='.')
1514 s = line+1;
1515 if (strncmp(s, "skip", 4)==0)
1517 int n;
1519 s += 4;
1520 if (!isspace(*s))
1521 exitfileerror(20, "syntax is '.skip n'\n");
1523 n=strtol(s, &s2, 10);
1524 if (s2==NULL)
1525 exitfileerror(20, "positive number expected\n");
1527 while (isspace(*s2)) s2++;
1528 if ((*s2 != '\0') && (*s2 != '#'))
1529 exitfileerror(20, "syntax is '.skip n'\n");
1530 if (*funclistptr != NULL)
1531 funclistptr = &((*funclistptr)->next);
1532 lvo += n;
1534 else if (strncmp(s, "alias", 5)==0)
1536 s += 5;
1538 if (!isspace(*s))
1539 exitfileerror(20, "syntax is '.alias name'\n");
1541 while (isspace(*s)) s++;
1542 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1543 exitfileerror(20, "syntax is '.alias name'\n");
1545 s2 = s;
1546 s++;
1547 while (isalnum(*s) || *s == '_') s++;
1549 if (isspace(*s))
1551 *s = '\0';
1552 do {
1553 s++;
1554 } while (isspace(*s));
1557 if (*s != '\0')
1558 exitfileerror(20, "syntax is '.alias name'\n");
1560 if (*funclistptr == NULL)
1561 exitfileerror(20, ".alias has to come after a function declaration\n");
1563 slist_append(&(*funclistptr)->aliases, s2);
1565 else if (strncmp(s, "function", 8) == 0)
1567 s += 8;
1569 if (!isspace(*s))
1570 exitfileerror(20, "Syntax error\n");
1572 while (isspace(*s)) s++;
1573 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1574 exitfileerror(20, "syntax is '.function name'\n");
1576 s2 = s;
1577 s++;
1578 while (isalnum(*s) || *s == '_') s++;
1580 if (isspace(*s))
1582 *s = '\0';
1583 do {
1584 s++;
1585 } while (isspace(*s));
1588 if (*s != '\0')
1589 exitfileerror(20, "syntax is '.function name'\n");
1591 if (*funclistptr == NULL)
1592 exitfileerror(20, ".function has to come after a function declaration\n");
1594 funcsetinternalname(*funclistptr, s2);
1596 else if (strncmp(s, "cfunction", 9)==0)
1598 if (*funclistptr == NULL)
1599 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1601 (*funclistptr)->libcall = REGISTER;
1603 else if (strncmp(s, "private", 7)==0)
1605 if (*funclistptr == NULL)
1606 exitfileerror(20, ".private has to come after a function declaration\n");
1608 (*funclistptr)->priv = 1;
1610 else if (strncmp(s, "novararg", 8)==0)
1612 if (*funclistptr == NULL)
1613 exitfileerror(20, ".novararg has to come after a function declaration\n");
1615 (*funclistptr)->novararg = 1;
1617 else if (strncmp(s, "version", 7) == 0)
1619 /* Mark version number for the following
1620 * functions, so that the automatic OpenLibrary()
1621 * will know what version to use.
1623 char *tmp;
1624 int ver;
1626 s += 7;
1628 while (isspace(*s)) s++;
1629 ver = (int)strtol(s, &tmp, 0);
1631 if (s == tmp)
1632 exitfileerror(20, ".version expects an integer\n");
1634 s = tmp;
1635 while (isspace(*s)) s++;
1637 if (*s && *s != '#')
1638 exitfileerror(20, ".version has junk after the version number\n");
1640 minversion = ver;
1642 else if (strncmp(s, "unusedlibbase", 13) == 0)
1644 if (*funclistptr == NULL)
1645 exitfileerror(20, ".unusedlibbase has to come after a function declaration\n");
1646 (*funclistptr)->unusedlibbase = 1;
1648 else
1649 exitfileerror(20, "Syntax error");
1651 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1653 /* The line is a function or attribute prototype.
1654 * A function can have one of two syntaxes:
1655 * type funcname(argproto1, argproto2, ...)
1656 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1657 * The former is for C type function argument passing, the latter for
1658 * register argument passing.
1659 * An attribute has the following syntax:
1660 * type attribute
1662 char c, *args[64], *regs[64], *funcname, *cp;
1663 int len, argcount = 0, regcount = 0, brcount = 0;
1665 cp = strchr(line,'#');
1666 if (cp)
1667 *(cp++) = 0;
1669 /* Parse 'type functionname' at the beginning of the line */
1670 if (isattribute) {
1671 s = line + strlen(line);
1672 } else {
1673 s = strchr(line, '(');
1674 if (s == NULL)
1675 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1678 s2 = s;
1679 while (isspace(*(s2-1)))
1680 s2--;
1681 *s2 = '\0';
1683 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1684 s2--;
1686 if (s2 == line)
1687 exitfileerror(20, "No type specifier before %s name\n", isattribute ? "attribute" : "function");
1689 if (*funclistptr != NULL)
1690 funclistptr = &((*funclistptr)->next);
1691 *funclistptr = newfunctionhead(s2, STACK);
1693 if (cp)
1694 (*funclistptr)->comment = strdup(cp);
1695 else
1696 (*funclistptr)->comment = NULL;
1698 while (isspace(*(s2-1)))
1699 s2--;
1700 *s2 = '\0';
1701 (*funclistptr)->type = strdup(line);
1702 (*funclistptr)->lvo = lvo;
1703 (*funclistptr)->version = minversion;
1704 lvo++;
1706 if (isattribute)
1707 continue;
1709 /* Parse function prototype */
1710 s++;
1711 while (isspace(*s))
1712 s++;
1713 c = *s;
1715 while (c != ')')
1717 while (isspace(*s))
1718 s++;
1720 args[argcount] = s;
1721 argcount++;
1723 while
1725 *s != '\0'
1726 && !(brcount == 0 && (*s == ',' || *s == ')'))
1729 if (*s == '(')
1730 brcount++;
1731 if (*s == ')')
1733 if (brcount > 0)
1734 brcount--;
1735 else
1736 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1738 s++;
1741 c = *s;
1742 if (c == '\0')
1743 exitfileerror(20, "'(' without ')'");
1745 s2 = s;
1746 while (isspace(*(s2-1)))
1747 s2--;
1748 *s2 = '\0';
1750 if (!(s2 > args[argcount - 1]))
1751 exitfileerror(20, "Syntax error in function prototype\n");
1753 s++;
1756 s++;
1757 while (*s != '\0' && isspace(*s))
1758 s++;
1760 if (*s == '(')
1762 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1764 /* There may be no register specified with () so be sure then c is == ')' */
1765 s++;
1766 while(isspace(*s))
1767 s++;
1769 c = *s;
1771 while (c != ')')
1773 while (isspace(*s))
1774 s++;
1776 regs[regcount] = s;
1777 regcount++;
1779 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1781 s += 2;
1782 c = *s;
1783 if (c == '/')
1785 s++;
1786 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1788 s += 2;
1789 c = *s;
1791 else
1792 exitfileerror(20,
1793 "wrong register specification \"%s\" for argument %u\n",
1794 regs[regcount-1], regcount
1797 if (regcount > 4)
1798 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount, regs[regcount-1]);
1800 *s = '\0';
1802 else
1803 exitfileerror(20,
1804 "wrong register \"%s\" for argument %u\n",
1805 regs[regcount-1], regcount
1808 while (isspace(c))
1810 s++;
1811 c = *s;
1813 if (c == '\0')
1814 exitfileerror(20, "'(' without ')'\n");
1815 if (c != ',' && c != ')')
1816 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1818 s++;
1821 s++;
1822 while (isspace(*s)) s++;
1823 if (*s!='\0')
1824 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1826 if (argcount != regcount)
1827 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1828 argcount, regcount
1831 (*funclistptr)->libcall = def_libcall;
1832 for (i = 0; i < argcount; i++)
1833 funcaddarg(*funclistptr, args[i], regs[i]);
1835 else if (*s == '\0')
1836 { /* No registers specified */
1837 for (i = 0; i < argcount; i++)
1838 funcaddarg(*funclistptr, args[i], NULL);
1840 else
1841 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1846 static void readsectionclass_methodlist(struct classinfo *cl)
1848 int atend = 0, i;
1849 char *line, *s, *s2;
1850 struct functionhead **methlistptr = &cl->methlist;
1851 struct stringlist *interface = NULL;
1853 if (cl->basename==NULL)
1854 exitfileerror(20, "section methodlist has to come after section config\n");
1856 while (!atend)
1858 line = readline();
1859 if (line==NULL)
1860 exitfileerror(20, "unexptected EOF in methodlist section\n");
1862 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1863 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1864 continue;
1866 if (isspace(*line))
1867 exitfileerror(20, "No space allowed at start of the line\n");
1869 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1871 s = line+2;
1872 while (isspace(*s)) s++;
1873 if (strncmp(s, "end", 3)!=0)
1874 exitfileerror(20, "\"##end methodlist\" expected\n");
1876 s += 3;
1877 while (isspace(*s)) s++;
1878 if (strncmp(s, "methodlist", 10)!=0)
1879 exitfileerror(20, "\"##end methodlist\" expected\n");
1881 s += 10;
1882 while (isspace(*s)) s++;
1883 if (*s!='\0')
1884 exitfileerror(20, "unexpected character on position %d\n", s-line);
1886 atend = 1;
1888 continue;
1891 if (*line=='.')
1893 s = line+1;
1894 if (strncmp(s, "alias", 5)==0)
1896 s += 5;
1898 if (!isspace(*s))
1899 exitfileerror(20, "syntax is '.alias name'\n");
1901 while (isspace(*s)) s++;
1902 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1903 exitfileerror(20, "syntax is '.alias name'\n");
1905 s2 = s;
1906 s++;
1907 while (isalnum(*s) || *s == '_') s++;
1909 if (isspace(*s))
1911 *s = '\0';
1912 do {
1913 s++;
1914 } while (isspace(*s));
1917 if (*s != '\0')
1918 exitfileerror(20, "syntax is '.alias name'\n");
1920 if (*methlistptr == NULL)
1921 exitfileerror(20, ".alias has to come after a function declaration\n");
1923 slist_append(&(*methlistptr)->aliases, s2);
1925 else if (strncmp(s, "function", 8) == 0)
1927 s += 8;
1929 if (!isspace(*s))
1930 exitfileerror(20, "Syntax error\n");
1932 while (isspace(*s)) s++;
1933 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1934 exitfileerror(20, "syntax is '.function name'\n");
1936 s2 = s;
1937 s++;
1938 while (isalnum(*s) || *s == '_') s++;
1940 if (isspace(*s))
1942 *s = '\0';
1943 do {
1944 s++;
1945 } while (isspace(*s));
1948 if (*s != '\0')
1949 exitfileerror(20, "syntax is '.function name'\n");
1951 if (*methlistptr == NULL)
1952 exitfileerror(20, ".function has to come after a function declaration\n");
1954 funcsetinternalname(*methlistptr, s2);
1956 else if (strncmp(s, "interface", 9) == 0)
1958 if (cl->classtype != HIDD)
1959 exitfileerror(20, "interface only valid for a HIDD\n");
1961 s += 9;
1963 if (!isspace(*s))
1964 exitfileerror(20, "Syntax error\n");
1966 while (isspace(*s)) s++;
1967 if (*s == '\0' || !isalpha(*s))
1968 exitfileerror(20, "syntax is '.interface name'\n");
1970 s2 = s;
1971 s++;
1972 while (isalnum(*s) || *s == '_') s++;
1974 if (isspace(*s))
1976 *s = '\0';
1977 do {
1978 s++;
1979 } while (isspace(*s));
1982 if (*s != '\0')
1983 exitfileerror(20, "syntax is '.interface name'\n");
1985 interface = slist_append(&cl->interfaces, s2);
1987 else
1988 exitfileerror(20, "Syntax error");
1990 else if (isalpha(*line))
1992 char stmp[256];
1994 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
1997 if (cl->classtype == HIDD && interface == NULL)
1998 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
2000 if (*s != '\0')
2001 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
2003 if (*methlistptr != NULL)
2004 methlistptr = &((*methlistptr)->next);
2005 if (cl->classtype != HIDD)
2007 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
2008 exitfileerror(20, "Method name too large\n");
2010 *methlistptr = newfunctionhead(stmp, STACK);
2011 (*methlistptr)->type = "IPTR";
2012 funcaddarg(*methlistptr, "Class *cl", NULL);
2013 funcaddarg(*methlistptr, "Object *o", NULL);
2014 funcaddarg(*methlistptr, "Msg msg", NULL);
2016 else
2018 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
2019 exitfileerror(20, "Method name too large\n");
2021 *methlistptr = newfunctionhead(stmp, STACK);
2022 (*methlistptr)->type = "IPTR";
2023 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
2024 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
2025 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
2026 (*methlistptr)->interface = interface;
2027 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
2028 exitfileerror(20, "Method name too large\n");
2029 (*methlistptr)->method = strdup(stmp);
2031 slist_append(&(*methlistptr)->aliases, line);
2033 else
2034 exitfileerror(20, "Methodname has to begin with a letter\n");
2038 static void
2039 readsectioninterface(struct config *cfg)
2041 char *s;
2042 struct interfaceinfo *in;
2044 in = newinterface(cfg);
2045 s = readsections(cfg, NULL, in, 1);
2046 if (s == NULL)
2047 exitfileerror(20, "Unexpected end of file\n");
2049 if (strncmp(s, "##", 2) != 0)
2050 exitfileerror(20, "'##end interface' expected\n");
2051 s += 2;
2053 while (isspace(*s)) s++;
2055 if (strncmp(s, "end", 3) != 0)
2056 exitfileerror(20, "'##end interface' expected\n");
2057 s += 3;
2059 if (!isspace(*s))
2060 exitfileerror(20, "'##end interface' expected\n");
2061 while (isspace(*s)) s++;
2063 if (strncmp(s, "interface", 9) != 0)
2064 exitfileerror(20, "'##end interface' expected\n");
2065 s += 9;
2067 while (isspace(*s)) s++;
2068 if (*s != '\0')
2069 exitfileerror(20, "'##end interface' expected\n");
2071 if (!in->interfaceid)
2072 exitfileerror(20, "interface has no 'interfaceid' defined!\n");
2074 if (!in->interfacename)
2075 exitfileerror(20, "interface has no 'interfacename' defined!\n");
2077 if (!in->methodstub)
2078 in->methodstub = strdup(in->interfacename);
2080 if (!in->methodbase) {
2081 int len = strlen(in->interfacename);
2082 in->methodbase = malloc(len + 4 + 1);
2083 strcpy(in->methodbase, in->interfacename);
2084 strcat(in->methodbase, "Base");
2087 if (!in->attributebase) {
2088 int len = strlen(in->interfacename);
2089 in->attributebase = malloc(len + 4 + 4 + 1);
2090 strcpy(in->attributebase, in->interfacename);
2091 strcat(in->attributebase, "AttrBase");
2095 static void
2096 readsectionclass(struct config *cfg)
2098 char *s;
2099 struct classinfo *cl;
2101 cl = newclass(cfg);
2102 s = readsections(cfg, cl, NULL, 1);
2103 if (s == NULL)
2104 exitfileerror(20, "Unexpected end of file\n");
2106 if (strncmp(s, "##", 2) != 0)
2107 exitfileerror(20, "'##end class' expected\n");
2108 s += 2;
2110 while (isspace(*s)) s++;
2112 if (strncmp(s, "end", 3) != 0)
2113 exitfileerror(20, "'##end class' expected\n");
2114 s += 3;
2116 if (!isspace(*s))
2117 exitfileerror(20, "'##end class' expected\n");
2118 while (isspace(*s)) s++;
2120 if (strncmp(s, "class", 5) != 0)
2121 exitfileerror(20, "'##end class' expected\n");
2122 s += 5;
2124 while (isspace(*s)) s++;
2125 if (*s != '\0')
2126 exitfileerror(20, "'##end class' expected\n");
2129 static struct classinfo *newclass(struct config *cfg)
2131 struct classinfo *cl, *classlistit;
2133 cl = malloc(sizeof(struct classinfo));
2134 if (cl == NULL)
2136 fprintf(stderr, "Out of memory\n");
2137 exit(20);
2139 memset(cl, 0, sizeof(struct classinfo));
2141 /* By default the classes are initialized with a priority of 1 so they
2142 * are initialized before any user added initialization with priority 1
2144 cl->initpri = 1;
2146 if (cfg->classlist == NULL)
2147 cfg->classlist = cl;
2148 else
2152 classlistit = cfg->classlist;
2153 classlistit->next != NULL;
2154 classlistit = classlistit->next
2157 classlistit->next = cl;
2160 return cl;
2163 static struct handlerinfo *newhandler(struct config *cfg)
2165 struct handlerinfo *hl;
2167 hl = calloc(1,sizeof(*hl));
2168 hl->next = cfg->handlerlist;
2169 cfg->handlerlist = hl;
2170 return hl;
2173 static struct interfaceinfo *newinterface(struct config *cfg)
2175 struct interfaceinfo *in, *interfacelistit;
2177 in = malloc(sizeof(struct interfaceinfo));
2178 if (in == NULL)
2180 fprintf(stderr, "Out of memory\n");
2181 exit(20);
2183 memset(in, 0, sizeof(struct interfaceinfo));
2185 if (cfg->interfacelist == NULL)
2186 cfg->interfacelist = in;
2187 else
2191 interfacelistit = cfg->interfacelist;
2192 interfacelistit->next != NULL;
2193 interfacelistit = interfacelistit->next
2196 interfacelistit->next = in;
2199 return in;
2203 static int getdirective(char *s, const char *directive, int range_min, int range_max, int *val)
2205 char *tmp;
2206 int newval;
2208 if (strncmp(s, directive, strlen(directive)) != 0)
2209 return 0;
2211 s += strlen(directive);
2212 if (*s && !isspace(*s))
2213 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive);
2215 while (isspace(*s)) s++;
2216 if (!*s)
2217 exitfileerror(20, "No .%s value specified\n", directive);
2219 newval = strtol(s, &tmp, 0);
2220 if (s == tmp || !(newval >= range_min && newval <= range_max)) {
2221 tmp = s;
2222 while (*tmp && !isspace(*tmp)) tmp++;
2223 exitfileerror(20, "Invalid .%s value of %.*s\n", directive, tmp - s, s);
2226 *val = newval;
2227 return 1;
2230 static void
2231 readsectionhandler(struct config *cfg)
2233 char *line = NULL, *s;
2234 struct handlerinfo *hl;
2235 unsigned char autolevel = 0;
2236 unsigned int stacksize = 0;
2237 int startup = 0;
2238 char priority = 10;
2239 int bootpri = -128;
2240 int has_filesystem = 0;
2242 for (;;)
2244 char *function;
2245 int function_len;
2246 char *tmp;
2248 s = line = readline();
2250 if (s==NULL)
2251 exitfileerror(20, "unexpected end of file in section hanlder\n");
2253 if (strncmp(s, "##", 2)==0)
2254 break;
2256 /* Ignore comments */
2257 if (strncmp(s, "#", 1)==0)
2258 continue;
2260 /* Skip ahead to function name */
2261 while (*s && isspace(*s)) s++;
2263 /* Permit blank lines */
2264 if (!*s)
2265 continue;
2267 if (*s == '.') {
2268 int val;
2269 s++;
2271 if (getdirective(s, "autodetect", 0, 127, &val)) {
2272 autolevel = val;
2273 } else if (getdirective(s, "stacksize", 0, INT_MAX, &val)) {
2274 stacksize = val;
2275 } else if (getdirective(s, "priority", -128, 127, &val)) {
2276 priority = val;
2277 } else if (getdirective(s, "bootpri", -128, 127, &val)) {
2278 bootpri = val;
2279 } else if (getdirective(s, "startup", INT_MIN, INT_MAX, &val)) {
2280 startup = val;
2281 } else {
2282 exitfileerror(20, "Unrecognized directive \"%s\"\n", line);
2284 continue;
2287 do {
2288 unsigned int id = 0;
2290 if (strncasecmp(s,"resident=",9)==0) {
2291 char *res;
2293 s = strchr(s, '=') + 1;
2294 res = s;
2295 while (*s && !isspace(*s)) s++;
2296 if (res == s)
2297 exitfileerror(20, "Empty resident= is not permitted\n");
2299 if (*s)
2300 *(s++) = 0;
2302 hl = newhandler(cfg);
2303 hl->type = HANDLER_RESIDENT;
2304 hl->id = 0;
2305 hl->name = strdup(res);
2306 hl->autodetect = autolevel--;
2307 hl->stacksize = stacksize;
2308 hl->priority = priority;
2309 hl->startup = startup;
2310 } else if (strncasecmp(s,"dosnode=",8)==0) {
2311 char *dev;
2313 s = strchr(s, '=') + 1;
2314 dev = s;
2315 while (*s && !isspace(*s)) s++;
2316 if (dev == s)
2317 exitfileerror(20, "Empty dosnode= is not permitted\n");
2319 if (*s)
2320 *(s++) = 0;
2322 hl = newhandler(cfg);
2323 hl->type = HANDLER_DOSNODE;
2324 hl->id = 0;
2325 hl->name = strdup(dev);
2326 hl->autodetect = autolevel ? autolevel-- : 0;
2327 hl->stacksize = stacksize;
2328 hl->priority = priority;
2329 hl->startup = startup;
2330 hl->bootpri = bootpri;
2331 } else if (strncasecmp(s,"dostype=",8) == 0) {
2332 s = strchr(s, '=') + 1;
2334 id = (unsigned int)strtoul(s, &tmp, 0);
2336 if (s == tmp) {
2337 while (*tmp && !isspace(*tmp))
2338 tmp++;
2339 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp -s), s);
2341 s = tmp;
2343 if (id == 0 || id == ~0) {
2344 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id);
2347 hl = newhandler(cfg);
2348 hl->type = HANDLER_DOSTYPE;
2349 hl->id = id;
2350 hl->name = NULL;
2351 hl->autodetect = autolevel ? autolevel-- : 0;
2352 hl->stacksize = stacksize;
2353 hl->priority = priority;
2354 hl->startup = startup;
2355 } else {
2356 for (tmp = s; !isspace(*tmp); tmp++);
2357 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp - s, s);
2360 /* Advance to next ID */
2361 while (*s && isspace(*s)) s++;
2363 } while (*s);
2366 if (s == NULL)
2367 exitfileerror(20, "Unexpected end of file\n");
2369 if (strncmp(s, "##", 2) != 0)
2370 exitfileerror(20, "'##end handler' expected\n");
2371 s += 2;
2373 while (isspace(*s)) s++;
2375 if (strncmp(s, "end", 3) != 0)
2376 exitfileerror(20, "'##end handler' expected\n");
2377 s += 3;
2379 while (isspace(*s)) s++;
2381 if (strncmp(s, "handler", 7) != 0)
2382 exitfileerror(20, "'##end handler' expected\n");
2383 s += 7;
2385 while (isspace(*s)) s++;
2386 if (*s != '\0')
2387 exitfileerror(20, "'##end handler' expected\n");