tabs -> spaces.
[AROS.git] / tools / genmodule / config.c
blobf92789df476c547a16dc09dec887f61478e8215b
1 /*
2 Copyright © 1995-2013, 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 /* Verify that a handler has a handler */
330 if (cfg->modtype == HANDLER) {
331 if (cfg->handlerfunc == NULL) {
332 fprintf(stderr, "handler modules require a 'handler_func' ##config option\n");
333 exit(20);
335 cfg->options |= OPTION_NOAUTOLIB | OPTION_NOEXPUNGE | OPTION_NOOPENCLOSE;
338 return cfg;
341 /* Functions to read configuration from the configuration file */
343 #include "fileread.h"
345 static char *readsections(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
346 static void readsectionconfig(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
347 static void readsectioncdef(struct config *);
348 static void readsectioncdefprivate(struct config *);
349 static void readsectionstartup(struct config *);
350 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall);
351 static void readsectionclass_methodlist(struct classinfo *);
352 static void readsectionclass(struct config *);
353 static void readsectionhandler(struct config *);
354 static void readsectioninterface(struct config *);
356 static void readconfig(struct config *cfg)
358 struct classinfo *mainclass = NULL;
360 /* Create a classinfo structure if this module is a class */
361 switch (cfg->modtype)
363 case LIBRARY:
364 case DEVICE:
365 case RESOURCE:
366 case USBCLASS:
367 case HANDLER:
368 break;
370 case MCC:
371 case MUI:
372 case MCP:
373 case GADGET:
374 case DATATYPE:
375 case HIDD:
376 mainclass = newclass(cfg);
377 mainclass->classtype = cfg->modtype;
378 break;
380 default:
381 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
382 exit(20);
385 switch (cfg->modtype)
387 case LIBRARY:
388 case USBCLASS:
389 cfg->firstlvo = 5;
390 break;
391 case DEVICE:
392 cfg->firstlvo = 7;
393 break;
394 case MCC:
395 case MUI:
396 case MCP:
397 cfg->firstlvo = 6;
398 mainclass->boopsimprefix = muimprefix;
399 break;
400 case HANDLER:
401 case RESOURCE:
402 cfg->firstlvo = 1;
403 break;
404 case GADGET:
405 cfg->firstlvo = 5;
406 mainclass->boopsimprefix = gadgetmprefix;
407 break;
408 case DATATYPE:
409 cfg->firstlvo = 6;
410 mainclass->boopsimprefix = dtmprefix;
411 break;
412 case HIDD:
413 cfg->firstlvo = 5;
414 /* FIXME: need boopsimprefix ? */
415 break;
416 default:
417 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
418 exit(20);
421 if (!fileopen(cfg->conffile))
423 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
424 exit(20);
427 /* Read all sections and see that we are at the end of the file */
428 if (readsections(cfg, mainclass, NULL, 0) != NULL)
429 exitfileerror(20, "Syntax error");
431 fileclose();
434 /* readsections will scan through all the sections in the config file.
435 * arguments:
436 * struct config *cfg: The module config data which may be updated by
437 * the information in the sections
438 * struct classinfo *cl: The classdata to be filled with data from the sections.
439 * This may be NULL if this is the main part of the configuration file and the
440 * type of the module is not a class
441 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
442 * part of the config file.
444 static char *readsections(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
446 char *line, *s, *s2;
447 int hasconfig = 0;
449 while ((line=readline())!=NULL)
451 if (strncmp(line, "##", 2)==0)
453 static char *parts[] =
455 "config", "cdefprivate", "cdef", "startup", "functionlist", "methodlist", "class", "handler", "interface", "attributelist", "cfunctionlist"
457 const unsigned int nums = sizeof(parts)/sizeof(char *);
458 unsigned int partnum;
459 int i, atend = 0;
461 s = line+2;
462 while (isspace(*s)) s++;
464 if (strncmp(s, "begin", 5)!=0)
465 return line;
467 s += 5;
468 if (!isspace(*s))
469 exitfileerror(20, "space after begin expected\n");
470 while (isspace(*s)) s++;
472 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
474 if (strncmp(s, parts[i], strlen(parts[i]))==0)
476 partnum = i+1;
477 s += strlen(parts[i]);
478 while (isspace(*s)) s++;
479 if (*s!='\0')
480 exitfileerror(20, "unexpected character on position %d\n", s-line);
483 if (partnum==0)
484 exitfileerror(20, "unknown start of section\n");
485 switch (partnum)
487 case 1: /* config */
488 readsectionconfig(cfg, cl, in, inclass);
489 hasconfig = 1;
490 break;
492 case 2: /* cdefprivate */
493 if (inclass)
494 exitfileerror(20, "cdefprivate section not allowed in class section\n");
495 readsectioncdefprivate(cfg);
496 break;
498 case 3: /* cdef */
499 if (inclass)
500 exitfileerror(20, "cdef section not allowed in class section\n");
501 readsectioncdef(cfg);
502 break;
504 case 4: /* startup */
505 if (inclass)
506 exitfileerror(20, "startup section not allowed in class section\n");
507 readsectionstartup(cfg);
508 break;
510 case 5: /* functionlist */
511 if (inclass)
512 exitfileerror(20, "functionlist section not allow in class section\n");
513 if (cfg->basename==NULL)
514 exitfileerror(20, "section functionlist has to come after section config\n");
516 readsectionfunctionlist("functionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTERMACRO);
517 cfg->intcfg |= CFG_NOREADFUNCS;
518 break;
520 case 6: /* methodlist */
521 if (cl == NULL && in == NULL)
522 exitfileerror(20, "methodlist section when not in a class or interface\n");
523 if (cl)
524 readsectionclass_methodlist(cl);
525 else
526 readsectionfunctionlist("methodlist", &in->methodlist, 0, 0, REGISTERMACRO);
527 cfg->intcfg |= CFG_NOREADFUNCS;
528 break;
530 case 7: /* class */
531 if (inclass)
532 exitfileerror(20, "class section may not be in nested\n");
533 readsectionclass(cfg);
534 break;
535 case 8: /* handler */
536 readsectionhandler(cfg);
537 break;
538 case 9: /* interface */
539 if (inclass)
540 exitfileerror(20, "interface section may not be nested\n");
541 readsectioninterface(cfg);
542 break;
543 case 10: /* attributelist */
544 if (!in)
545 exitfileerror(20, "attributelist only valid in interface sections\n");
546 readsectionfunctionlist("attributelist", &in->attributelist, 0, 1, INVALID);
547 break;
548 case 11: /* cfunctionlist */
549 if (inclass)
550 exitfileerror(20, "cfunctionlist section not allow in class section\n");
551 if (cfg->basename==NULL)
552 exitfileerror(20, "section cfunctionlist has to come after section config\n");
554 readsectionfunctionlist("cfunctionlist", &cfg->funclist, cfg->firstlvo, 0, REGISTER);
555 cfg->intcfg |= CFG_NOREADFUNCS;
556 break;
559 else if (strlen(line)!=0)
560 filewarning("warning line outside section ignored\n");
563 if(!inclass)
565 if (!hasconfig)
566 exitfileerror(20, "No config section in conffile\n");
568 /* If no indication was given for generating includes or not
569 decide on module type and if there are functions
571 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
573 switch (cfg->modtype)
575 case LIBRARY:
576 case RESOURCE:
577 cfg->options |= OPTION_INCLUDES;
578 break;
580 case HANDLER:
581 case MCC:
582 case MUI:
583 case MCP:
584 case USBCLASS:
585 cfg->options |= OPTION_NOINCLUDES;
586 break;
588 case DEVICE:
589 cfg->options |= (
590 (cfg->funclist != NULL)
591 || (cfg->cdeflines != NULL)
592 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
593 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
594 break;
596 case GADGET:
597 case DATATYPE:
598 case HIDD:
599 cfg->options |= (
600 (cfg->funclist != NULL)
601 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
602 break;
604 default:
605 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
606 exit(20);
607 break;
611 /* If no indication was given for not generating stubs only generate them if
612 * the module has functions
614 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
616 switch (cfg->modtype)
618 case LIBRARY:
619 cfg->options |= (cfg->funclist != NULL) ? OPTION_STUBS : OPTION_NOSTUBS;
620 break;
622 case USBCLASS:
623 case RESOURCE:
624 case GADGET:
625 case DEVICE:
626 case DATATYPE:
627 case MCC:
628 case MUI:
629 case MCP:
630 case HIDD:
631 case HANDLER:
632 cfg->options |= OPTION_NOSTUBS;
633 break;
635 default:
636 fprintf(stderr, "Internal error writemakefile: unhandled modtype for stubs\n");
637 exit(20);
638 break;
642 /* If no indication was given for generating autoinit code or not
643 decide on module type
645 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
647 switch (cfg->modtype)
649 case LIBRARY:
650 cfg->options |= OPTION_AUTOINIT;
651 break;
653 case USBCLASS:
654 case RESOURCE:
655 case GADGET:
656 case DEVICE:
657 case DATATYPE:
658 case MCC:
659 case MUI:
660 case MCP:
661 case HIDD:
662 case HANDLER:
663 cfg->options |= OPTION_NOAUTOINIT;
664 break;
666 default:
667 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
668 exit(20);
669 break;
673 if ((cfg->modtype == RESOURCE) || (cfg->modtype == HANDLER))
674 /* Enforce noopenclose for resources and handlers */
675 cfg->options |= OPTION_NOOPENCLOSE;
676 else if (!(cfg->options & OPTION_SELFINIT))
677 /* Enforce using RTF_AUTOINIT for everything except resources */
678 cfg->options |= OPTION_RESAUTOINIT;
681 return NULL;
684 static void readsectionconfig(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
686 int atend = 0, i;
687 char *line, *s, *s2, *libbasetypeextern = NULL;
688 struct tm date;
690 while (!atend)
692 line = readline();
693 if (line==NULL)
694 exitfileerror(20, "unexpected end of file in section config\n");
696 if (strncmp(line, "##", 2)!=0)
698 const char *names[] =
700 "basename", "libbase", "libbasetype", "libbasetypeextern",
701 "version", "date", "copyright", "libcall", "forcebase", "superclass",
702 "superclass_field", "residentpri", "options", "sysbase_field",
703 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
704 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
705 "initpri", "type", "addromtag", "oopbase_field",
706 "rellib", "interfaceid", "interfacename",
707 "methodstub", "methodbase", "attributebase", "handler_func"
709 const unsigned int namenums = sizeof(names)/sizeof(char *);
710 unsigned int namenum;
712 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
716 strncmp(line, names[i], strlen(names[i]))==0
717 && isspace(*(line+strlen(names[i])))
719 namenum = i+1;
721 if (namenum==0)
722 exitfileerror(20, "unrecognized configuration option\n");
724 s = line + strlen(names[namenum-1]);
725 if (!isspace(*s))
726 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
728 while (isspace(*s)) s++;
729 if (*s=='\0')
730 exitfileerror(20, "unexpected end of line\n");
732 s2 = s + strlen(s);
733 while (isspace(*(s2-1))) s2--;
734 *s2 = '\0';
736 switch (namenum)
738 case 1: /* basename */
739 if (!inclass)
740 cfg->basename = strdup(s);
741 if (cl != NULL)
742 cl->basename = strdup(s);
743 if (in != NULL)
744 exitfileerror(20, "basename not valid config option when in a interface section\n");
745 break;
747 case 2: /* libbase */
748 if (inclass)
749 exitfileerror(20, "libbase not valid config option when in a class section\n");
750 cfg->libbase = strdup(s);
751 break;
753 case 3: /* libbasetype */
754 if (inclass)
755 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
756 cfg->libbasetype = strdup(s);
757 break;
759 case 4: /* libbasetypeextern */
760 if (inclass)
761 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
762 libbasetypeextern = strdup(s);
763 break;
765 case 5: /* version */
766 if (inclass)
767 exitfileerror(20, "version not valid config option when in a class section\n");
768 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
769 exitfileerror(20, "wrong version string \"%s\"\n", s);
770 break;
772 case 6: /* date */
773 if (inclass)
774 exitfileerror(20, "date not valid config option when in a class section\n");
775 #ifndef _WIN32
776 if (strptime(s, "%e.%m.%Y", &date) == NULL)
778 exitfileerror(20, "date string has to have d.m.yyyy format\n");
780 #endif
781 cfg->datestring = strdup(s);
782 break;
784 case 7: /* copyright */
785 if (inclass)
786 exitfileerror(20, "copyright not valid config option when in a class section\n");
787 cfg->copyright = strdup(s);
788 break;
790 case 8: /* libcall */
791 fprintf(stderr, "libcall specification is deprecated and ignored\n");
792 break;
794 case 9: /* forcebase */
795 if (inclass)
796 exitfileerror(20, "forcebase not valid config option when in a class section\n");
797 slist_append(&cfg->forcelist, s);
798 break;
800 case 10: /* superclass */
801 if (cl == NULL)
802 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
803 cl->superclass = strdup(s);
804 break;
806 case 11: /* superclass_field */
807 if (cl == NULL)
808 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
809 cl->superclass_field = strdup(s);
810 break;
812 case 12: /* residentpri */
813 if (!inclass)
815 int count;
816 char dummy;
818 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
819 if (count != 1 ||
820 cfg->residentpri < -128 || cfg->residentpri > 127
823 exitfileerror(20, "residentpri number format error\n");
826 else
827 exitfileerror(20, "residentpri not valid config option when in a class section\n");
828 break;
830 case 13: /* options */
831 if (!inclass)
833 static const char *optionnames[] =
835 "noautolib", "noexpunge", "noresident", "peropenerbase",
836 "pertaskbase", "includes", "noincludes", "nostubs",
837 "autoinit", "noautoinit", "resautoinit", "noopenclose",
838 "selfinit"
840 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
841 int optionnum;
845 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
847 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
849 optionnum = i + 1;
850 s += strlen(optionnames[i]);
851 while (isspace(*s)) s++;
852 if (*s == ',')
853 s++;
854 else if (*s != '\0')
855 exitfileerror(20, "Unrecognized option\n");
858 if (optionnum == 0)
859 exitfileerror(20, "Unrecognized option\n");
860 switch (optionnum)
862 case 1: /* noautolib */
863 cfg->options |= OPTION_NOAUTOLIB;
864 break;
865 case 2: /* noexpunge */
866 cfg->options |= OPTION_NOEXPUNGE;
867 break;
868 case 3: /* noresident */
869 cfg->options |= OPTION_NORESIDENT;
870 cfg->firstlvo = 1;
871 break;
872 case 5: /* pertaskbase */
873 cfg->options |= OPTION_PERTASKBASE;
874 /* Fall through */
875 case 4: /* peropenerbase */
876 if (cfg->options & OPTION_DUPBASE)
877 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
878 cfg->options |= OPTION_DUPBASE;
879 break;
880 case 6: /* includes */
881 if (cfg->options & OPTION_NOINCLUDES)
882 exitfileerror(20, "option includes and noincludes are incompatible\n");
883 cfg->options |= OPTION_INCLUDES;
884 break;
885 case 7: /* noincludes */
886 if (cfg->options & OPTION_INCLUDES)
887 exitfileerror(20, "option includes and noincludes are incompatible\n");
888 cfg->options |= OPTION_NOINCLUDES;
889 break;
890 case 8: /* nostubs */
891 cfg->options |= OPTION_NOSTUBS;
892 break;
893 case 9: /* autoinit */
894 if (cfg->options & OPTION_NOAUTOINIT)
895 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
896 cfg->options |= OPTION_AUTOINIT;
897 break;
898 case 10: /* noautoinit */
899 if (cfg->options & OPTION_AUTOINIT)
900 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
901 cfg->options |= OPTION_NOAUTOINIT;
902 break;
903 case 11: /* resautoinit */
904 if (cfg->options & OPTION_SELFINIT)
905 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
906 cfg->options |= OPTION_RESAUTOINIT;
907 break;
908 case 12:
909 cfg->options |= OPTION_NOOPENCLOSE;
910 break;
911 case 13: /* noresautoinit */
912 if (cfg->options & OPTION_RESAUTOINIT)
913 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
914 cfg->options |= OPTION_SELFINIT;
915 break;
917 while (isspace(*s)) s++;
918 } while(*s !='\0');
920 else
922 static const char *optionnames[] =
924 "private"
926 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
927 int optionnum;
931 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
933 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
935 optionnum = i + 1;
936 s += strlen(optionnames[i]);
937 while (isspace(*s)) s++;
938 if (*s == ',')
939 s++;
940 else if (*s != '\0')
941 exitfileerror(20, "Unrecognized option\n");
944 if (optionnum == 0)
945 exitfileerror(20, "Unrecognized option\n");
946 switch (optionnum)
948 case 1: /* private */
949 cl->options |= COPTION_PRIVATE;
950 break;
952 while (isspace(*s)) s++;
953 } while(*s !='\0');
955 break;
957 case 14: /* sysbase_field */
958 if (inclass)
959 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
960 cfg->sysbase_field = strdup(s);
961 break;
963 case 15: /* seglist_field */
964 if (inclass)
965 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
966 cfg->seglist_field = strdup(s);
967 break;
969 case 16: /* rootbase_field */
970 if (inclass)
971 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
972 cfg->rootbase_field = strdup(s);
973 break;
975 case 17: /* classptr_field */
976 if (cl == NULL)
978 exitfileerror
981 "classptr_field specified when not a BOOPSI class\n"
984 cl->classptr_field = strdup(s);
985 break;
987 case 18: /* classptr_var */
988 if (cl == NULL)
990 exitfileerror
993 "classptr_var specified when not a BOOPSI class\n"
996 cl->classptr_var = strdup(s);
997 break;
999 case 19: /* classid */
1000 if (cl == NULL)
1001 exitfileerror(20, "classid specified when not a BOOPSI class\n");
1002 if (cl->classid != NULL)
1003 exitfileerror(20, "classid specified twice\n");
1004 cl->classid = strdup(s);
1005 if (strcmp(cl->classid, "NULL") == 0)
1006 cl->options |= COPTION_PRIVATE;
1007 break;
1009 case 20: /* classdatatype */
1010 if (cl == NULL)
1011 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
1012 cl->classdatatype = strdup(s);
1013 break;
1015 case 21: /* beginio_func */
1016 if (inclass)
1017 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
1018 if (cfg->modtype != DEVICE)
1019 exitfileerror(20, "beginio_func specified when not a device\n");
1020 cfg->beginiofunc = strdup(s);
1021 break;
1023 case 22: /* abortio_func */
1024 if (inclass)
1025 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
1026 if (cfg->modtype != DEVICE)
1027 exitfileerror(20, "abortio_func specified when not a device\n");
1028 cfg->abortiofunc = strdup(s);
1029 break;
1031 case 23: /* dispatcher */
1032 if (cl == NULL)
1033 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
1034 cl->dispatcher = strdup(s);
1035 /* function references are not needed when dispatcher is specified */
1036 cfg->intcfg |= CFG_NOREADFUNCS;
1037 break;
1039 case 24: /* initpri */
1040 if (cl != NULL)
1042 int count;
1043 char dummy;
1045 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
1046 if (count != 1 ||
1047 cl->initpri < -128 || cl->initpri > 127
1050 exitfileerror(20, "initpri number format error\n");
1053 else
1054 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
1055 break;
1057 case 25: /* type */
1058 if (!inclass)
1059 exitfileerror(20, "type only valid config option in a class section\n");
1060 if (strcmp(s,"mcc")==0)
1061 cl->classtype = MCC;
1062 else if (strcmp(s,"mui")==0)
1063 cl->classtype = MUI;
1064 else if (strcmp(s,"mcp")==0)
1065 cl->classtype = MCP;
1066 else if (strcmp(s, "image")==0)
1067 cl->classtype = IMAGE;
1068 else if (strcmp(s, "gadget")==0)
1069 cl->classtype = GADGET;
1070 else if (strcmp(s, "datatype")==0)
1071 cl->classtype = DATATYPE;
1072 else if (strcmp(s, "usbclass")==0)
1073 cl->classtype = USBCLASS;
1074 else if (strcmp(s, "class")==0)
1075 cl->classtype = CLASS;
1076 else if (strcmp(s, "hidd")==0)
1077 cl->classtype = HIDD;
1078 else
1080 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
1081 exit(20);
1083 break;
1085 case 26: /* addromtag */
1086 cfg->addromtag = strdup(s);
1087 break;
1089 case 27: /* oopbase_field */
1090 cfg->oopbase_field = strdup(s);
1091 break;
1092 case 28: /* rellib */
1093 slist_append(&cfg->rellibs, s);
1094 break;
1095 case 29: /* interfaceid */
1096 if (!in)
1097 exitfileerror(20, "interfaceid only valid config option for an interface\n");
1098 in->interfaceid = strdup(s);
1099 break;
1100 case 30: /* interfacename */
1101 if (!in)
1102 exitfileerror(20, "interfacename only valid config option for an interface\n");
1103 in->interfacename = strdup(s);
1104 break;
1105 case 31: /* methodstub */
1106 if (!in)
1107 exitfileerror(20, "methodstub only valid config option for an interface\n");
1108 in->methodstub = strdup(s);
1109 break;
1110 case 32: /* methodbase */
1111 if (!in)
1112 exitfileerror(20, "methodbase only valid config option for an interface\n");
1113 in->methodbase = strdup(s);
1114 break;
1115 case 33: /* attributebase */
1116 if (!in)
1117 exitfileerror(20, "attributebase only valid config option for an interface\n");
1118 in->attributebase = strdup(s);
1119 break;
1120 case 34: /* handler_func */
1121 if (cfg->modtype != HANDLER)
1122 exitfileerror(20, "handler specified when not a handler\n");
1123 cfg->handlerfunc = strdup(s);
1124 break;
1127 else /* Line starts with ## */
1129 s = line+2;
1130 while (isspace(*s)) s++;
1131 if (strncmp(s, "end", 3)!=0)
1132 exitfileerror(20, "\"##end config\" expected\n");
1134 s += 3;
1135 if (!isspace(*s))
1136 exitfileerror(20, "\"##end config\" expected\n");
1138 while (isspace(*s)) s++;
1139 if (strncmp(s, "config", 6)!=0)
1140 exitfileerror(20, "\"##end config\" expected\n");
1142 s += 6;
1143 while (isspace(*s)) s++;
1144 if (*s!='\0')
1145 exitfileerror(20, "\"##end config\" expected\n");
1147 atend = 1;
1151 /* When not in a class section fill in default values for fields in cfg */
1152 if (!inclass)
1154 if (cfg->basename==NULL)
1156 cfg->basename = strdup(cfg->modulename);
1157 *cfg->basename = toupper(*cfg->basename);
1159 if (cfg->libbase==NULL)
1161 unsigned int len = strlen(cfg->basename)+5;
1162 cfg->libbase = malloc(len);
1163 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1165 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1166 cfg->libbasetype = strdup(libbasetypeextern);
1167 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1168 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1169 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1170 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1171 if (cfg->oopbase_field != NULL && cfg->libbasetype == NULL)
1172 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1173 /* rootbase_field only allowed when duplicating base */
1174 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1175 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1177 /* Set default date to current date */
1178 if (cfg->datestring == NULL)
1180 char tmpbuf[256];
1181 time_t now = time(NULL);
1182 struct tm *ltime = localtime(&now);
1184 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1185 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1187 cfg->datestring = strdup(tmpbuf);
1190 if (cfg->copyright == NULL)
1191 cfg->copyright = "";
1193 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1194 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1196 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1198 if (libbasetypeextern==NULL)
1200 switch (cfg->modtype)
1202 case DEVICE:
1203 cfg->libbasetypeptrextern = "struct Device *";
1204 break;
1205 case HANDLER:
1206 case RESOURCE:
1207 cfg->libbasetypeptrextern = "APTR ";
1208 break;
1209 case LIBRARY:
1210 case MUI:
1211 case MCP:
1212 case MCC:
1213 case GADGET:
1214 case DATATYPE:
1215 case USBCLASS:
1216 case HIDD:
1217 cfg->libbasetypeptrextern = "struct Library *";
1218 break;
1219 default:
1220 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1221 exit(20);
1224 else
1226 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1227 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1228 strcat(cfg->libbasetypeptrextern, " *");
1229 free(libbasetypeextern);
1233 /* When class was given too fill in some defaults when not specified */
1234 if (cl != NULL)
1236 if (cl->classtype == UNSPECIFIED)
1237 cl->classtype = CLASS;
1239 if (cl->basename == NULL)
1241 if (!inclass)
1242 cl->basename = cfg->basename;
1243 else
1244 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1247 /* MUI classes are always private */
1248 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1249 cl->options |= COPTION_PRIVATE;
1251 if (cl->classid == NULL
1252 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1255 if (cl->classtype == HIDD)
1257 cl->options &= !COPTION_PRIVATE;
1259 else if (cl->options & COPTION_PRIVATE)
1261 cl->classid = "NULL";
1263 else
1265 char s[256] = "";
1267 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1269 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1271 else if (cl->classtype == DATATYPE)
1273 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1275 cl->classid = strdup(s);
1279 /* Only specify superclass or superclass_field */
1280 if (cl->superclass != NULL && cl->superclass_field != NULL)
1281 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1283 /* Give default value to superclass if it is not specified */
1284 if (cl->superclass == NULL && cl->superclass == NULL)
1286 switch (cl->classtype)
1288 case MUI:
1289 case MCC:
1290 cl->superclass = "MUIC_Area";
1291 break;
1292 case MCP:
1293 cl->superclass = "MUIC_Mccprefs";
1294 break;
1295 case IMAGE:
1296 cl->superclass = "IMAGECLASS";
1297 break;
1298 case GADGET:
1299 cl->superclass = "GADGETCLASS";
1300 break;
1301 case DATATYPE:
1302 cl->superclass = "DATATYPESCLASS";
1303 break;
1304 case CLASS:
1305 cl->superclass = "ROOTCLASS";
1306 break;
1307 case HIDD:
1308 cl->superclass = "CLID_Root";
1309 break;
1310 default:
1311 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1312 break;
1318 static void readsectioncdef(struct config *cfg)
1320 int atend = 0;
1321 char *line, *s;
1323 while (!atend)
1325 line = readline();
1326 if (line==NULL)
1327 exitfileerror(20, "unexptected end of file in section cdef\n");
1329 if (strncmp(line, "##", 2)!=0)
1331 slist_append(&cfg->cdeflines, line);
1333 else
1335 s = line+2;
1336 while (isspace(*s)) s++;
1337 if (strncmp(s, "end", 3)!=0)
1338 exitfileerror(20, "\"##end cdef\" expected\n");
1340 s += 3;
1341 while (isspace(*s)) s++;
1342 if (strncmp(s, "cdef", 4)!=0)
1343 exitfileerror(20, "\"##end cdef\" expected\n");
1345 s += 5;
1346 while (isspace(*s)) s++;
1347 if (*s!='\0')
1348 exitfileerror(20, "unexpected character at position %d\n");
1350 atend = 1;
1355 static void readsectioncdefprivate(struct config *cfg)
1357 int atend = 0;
1358 char *line, *s;
1360 while (!atend)
1362 line = readline();
1363 if (line==NULL)
1364 exitfileerror(20, "unexptected end of file in section cdef\n");
1366 if (strncmp(line, "##", 2)!=0)
1368 slist_append(&cfg->cdefprivatelines, line);
1370 else
1372 s = line+2;
1373 while (isspace(*s)) s++;
1374 if (strncmp(s, "end", 3)!=0)
1375 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1377 s += 3;
1378 while (isspace(*s)) s++;
1379 if (strncmp(s, "cdefprivate", 11)!=0)
1380 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1382 s += 11;
1383 while (isspace(*s)) s++;
1384 if (*s!='\0')
1385 exitfileerror(20, "unexpected character at position %d\n");
1387 atend = 1;
1392 static void readsectionstartup(struct config *cfg)
1394 int atend = 0;
1395 char *line, *s;
1397 while (!atend)
1399 line = readline();
1400 if (line==NULL)
1401 exitfileerror(20, "unexptected end of file in section startup\n");
1403 if (strncmp(line, "##", 2)!=0)
1405 slist_append(&cfg->startuplines, line);
1407 else
1409 s = line+2;
1410 while (isspace(*s)) s++;
1411 if (strncmp(s, "end", 3)!=0)
1412 exitfileerror(20, "\"##end startup\" expected\n");
1414 s += 3;
1415 while (isspace(*s)) s++;
1416 if (strncmp(s, "startup", 7)!=0)
1417 exitfileerror(20, "\"##end startup\" expected\n");
1419 s += 7;
1420 while (isspace(*s)) s++;
1421 if (*s!='\0')
1422 exitfileerror(20, "unexpected character at position %d\n");
1424 atend = 1;
1429 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute, enum libcall def_libcall)
1431 int atend = 0, i;
1432 char *line, *s, *s2;
1433 unsigned int lvo = firstlvo;
1434 int minversion = 0;
1436 while (!atend)
1438 line = readline();
1439 if (line==NULL)
1440 exitfileerror(20, "unexpected EOF in functionlist section\n");
1441 if (strlen(line)==0)
1443 if (*funclistptr != NULL)
1444 funclistptr = &((*funclistptr)->next);
1445 lvo++;
1447 else if (isspace(*line))
1449 s = line;
1450 while (isspace(*s)) s++;
1451 if (*s=='\0')
1453 if (*funclistptr != NULL)
1454 funclistptr = &((*funclistptr)->next);
1455 lvo++;
1457 else
1458 exitfileerror(20, "no space allowed before functionname\n");
1460 else if (strncmp(line, "##", 2)==0)
1462 s = line+2;
1463 while (isspace(*s)) s++;
1464 if (strncmp(s, "end", 3)!=0)
1465 exitfileerror(20, "\"##end %s\" expected\n", type);
1467 s += 3;
1468 while (isspace(*s)) s++;
1469 if (strncmp(s, type, strlen(type))!=0)
1470 exitfileerror(20, "\"##end %s\" expected\n", type);
1472 s += strlen(type);
1473 while (isspace(*s)) s++;
1474 if (*s!='\0')
1475 exitfileerror(20, "unexpected character on position %d\n", s-line);
1477 atend = 1;
1479 else if (*line=='.')
1481 s = line+1;
1482 if (strncmp(s, "skip", 4)==0)
1484 int n;
1486 s += 4;
1487 if (!isspace(*s))
1488 exitfileerror(20, "syntax is '.skip n'\n");
1490 n=strtol(s, &s2, 10);
1491 if (s2==NULL)
1492 exitfileerror(20, "positive number expected\n");
1494 while (isspace(*s2)) s2++;
1495 if ((*s2 != '\0') && (*s2 != '#'))
1496 exitfileerror(20, "syntax is '.skip n'\n");
1497 if (*funclistptr != NULL)
1498 funclistptr = &((*funclistptr)->next);
1499 lvo += n;
1501 else if (strncmp(s, "alias", 5)==0)
1503 s += 5;
1505 if (!isspace(*s))
1506 exitfileerror(20, "syntax is '.alias name'\n");
1508 while (isspace(*s)) s++;
1509 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1510 exitfileerror(20, "syntax is '.alias name'\n");
1512 s2 = s;
1513 s++;
1514 while (isalnum(*s) || *s == '_') s++;
1516 if (isspace(*s))
1518 *s = '\0';
1519 do {
1520 s++;
1521 } while (isspace(*s));
1524 if (*s != '\0')
1525 exitfileerror(20, "syntax is '.alias name'\n");
1527 if (*funclistptr == NULL)
1528 exitfileerror(20, ".alias has to come after a function declaration\n");
1530 slist_append(&(*funclistptr)->aliases, s2);
1532 else if (strncmp(s, "function", 8) == 0)
1534 s += 8;
1536 if (!isspace(*s))
1537 exitfileerror(20, "Syntax error\n");
1539 while (isspace(*s)) s++;
1540 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1541 exitfileerror(20, "syntax is '.function name'\n");
1543 s2 = s;
1544 s++;
1545 while (isalnum(*s) || *s == '_') s++;
1547 if (isspace(*s))
1549 *s = '\0';
1550 do {
1551 s++;
1552 } while (isspace(*s));
1555 if (*s != '\0')
1556 exitfileerror(20, "syntax is '.function name'\n");
1558 if (*funclistptr == NULL)
1559 exitfileerror(20, ".function has to come after a function declaration\n");
1561 funcsetinternalname(*funclistptr, s2);
1563 else if (strncmp(s, "cfunction", 9)==0)
1565 if (*funclistptr == NULL)
1566 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1568 (*funclistptr)->libcall = REGISTER;
1570 else if (strncmp(s, "private", 7)==0)
1572 if (*funclistptr == NULL)
1573 exitfileerror(20, ".private has to come after a function declaration\n");
1575 (*funclistptr)->priv = 1;
1577 else if (strncmp(s, "novararg", 8)==0)
1579 if (*funclistptr == NULL)
1580 exitfileerror(20, ".novararg has to come after a function declaration\n");
1582 (*funclistptr)->novararg = 1;
1584 else if (strncmp(s, "version", 7) == 0)
1586 /* Mark version number for the following
1587 * functions, so that the automatic OpenLibrary()
1588 * will know what version to use.
1590 char *tmp;
1591 int ver;
1593 s += 7;
1595 while (isspace(*s)) s++;
1596 ver = (int)strtol(s, &tmp, 0);
1598 if (s == tmp)
1599 exitfileerror(20, ".version expects an integer\n");
1601 s = tmp;
1602 while (isspace(*s)) s++;
1604 if (*s && *s != '#')
1605 exitfileerror(20, ".version has junk after the version number\n");
1607 minversion = ver;
1609 else if (strncmp(s, "unusedlibbase", 13) == 0)
1611 if (*funclistptr == NULL)
1612 exitfileerror(20, ".unusedlibbase has to come after a function declaration\n");
1613 (*funclistptr)->unusedlibbase = 1;
1615 else
1616 exitfileerror(20, "Syntax error");
1618 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1620 /* The line is a function or attribute prototype.
1621 * A function can have one of two syntaxes:
1622 * type funcname(argproto1, argproto2, ...)
1623 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1624 * The former is for C type function argument passing, the latter for
1625 * register argument passing.
1626 * An attribute has the following syntax:
1627 * type attribute
1629 char c, *args[64], *regs[64], *funcname, *cp;
1630 int len, argcount = 0, regcount = 0, brcount = 0;
1632 cp = strchr(line,'#');
1633 if (cp)
1634 *(cp++) = 0;
1636 /* Parse 'type functionname' at the beginning of the line */
1637 if (isattribute) {
1638 s = line + strlen(line);
1639 } else {
1640 s = strchr(line, '(');
1641 if (s == NULL)
1642 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1645 s2 = s;
1646 while (isspace(*(s2-1)))
1647 s2--;
1648 *s2 = '\0';
1650 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1651 s2--;
1653 if (s2 == line)
1654 exitfileerror(20, "No type specifier before %s name\n", isattribute ? "attribute" : "function");
1656 if (*funclistptr != NULL)
1657 funclistptr = &((*funclistptr)->next);
1658 *funclistptr = newfunctionhead(s2, STACK);
1660 if (cp)
1661 (*funclistptr)->comment = strdup(cp);
1662 else
1663 (*funclistptr)->comment = NULL;
1665 while (isspace(*(s2-1)))
1666 s2--;
1667 *s2 = '\0';
1668 (*funclistptr)->type = strdup(line);
1669 (*funclistptr)->lvo = lvo;
1670 (*funclistptr)->version = minversion;
1671 lvo++;
1673 if (isattribute)
1674 continue;
1676 /* Parse function prototype */
1677 s++;
1678 while (isspace(*s))
1679 s++;
1680 c = *s;
1682 while (c != ')')
1684 while (isspace(*s))
1685 s++;
1687 args[argcount] = s;
1688 argcount++;
1690 while
1692 *s != '\0'
1693 && !(brcount == 0 && (*s == ',' || *s == ')'))
1696 if (*s == '(')
1697 brcount++;
1698 if (*s == ')')
1700 if (brcount > 0)
1701 brcount--;
1702 else
1703 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1705 s++;
1708 c = *s;
1709 if (c == '\0')
1710 exitfileerror(20, "'(' without ')'");
1712 s2 = s;
1713 while (isspace(*(s2-1)))
1714 s2--;
1715 *s2 = '\0';
1717 if (!(s2 > args[argcount - 1]))
1718 exitfileerror(20, "Syntax error in function prototype\n");
1720 s++;
1723 s++;
1724 while (*s != '\0' && isspace(*s))
1725 s++;
1727 if (*s == '(')
1729 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1731 /* There may be no register specified with () so be sure then c is == ')' */
1732 s++;
1733 while(isspace(*s))
1734 s++;
1736 c = *s;
1738 while (c != ')')
1740 while (isspace(*s))
1741 s++;
1743 regs[regcount] = s;
1744 regcount++;
1746 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1748 s += 2;
1749 c = *s;
1750 if (c == '/')
1752 s++;
1753 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1755 s += 2;
1756 c = *s;
1758 else
1759 exitfileerror(20,
1760 "wrong register specification \"%s\" for argument %u\n",
1761 regs[regcount-1], regcount
1764 if (regcount > 4)
1765 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount, regs[regcount-1]);
1767 *s = '\0';
1769 else
1770 exitfileerror(20,
1771 "wrong register \"%s\" for argument %u\n",
1772 regs[regcount-1], regcount
1775 while (isspace(c))
1777 s++;
1778 c = *s;
1780 if (c == '\0')
1781 exitfileerror(20, "'(' without ')'\n");
1782 if (c != ',' && c != ')')
1783 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1785 s++;
1788 s++;
1789 while (isspace(*s)) s++;
1790 if (*s!='\0')
1791 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1793 if (argcount != regcount)
1794 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1795 argcount, regcount
1798 (*funclistptr)->libcall = def_libcall;
1799 for (i = 0; i < argcount; i++)
1800 funcaddarg(*funclistptr, args[i], regs[i]);
1802 else if (*s == '\0')
1803 { /* No registers specified */
1804 for (i = 0; i < argcount; i++)
1805 funcaddarg(*funclistptr, args[i], NULL);
1807 else
1808 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1813 static void readsectionclass_methodlist(struct classinfo *cl)
1815 int atend = 0, i;
1816 char *line, *s, *s2;
1817 struct functionhead **methlistptr = &cl->methlist;
1818 struct stringlist *interface = NULL;
1820 if (cl->basename==NULL)
1821 exitfileerror(20, "section methodlist has to come after section config\n");
1823 while (!atend)
1825 line = readline();
1826 if (line==NULL)
1827 exitfileerror(20, "unexptected EOF in methodlist section\n");
1829 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1830 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1831 continue;
1833 if (isspace(*line))
1834 exitfileerror(20, "No space allowed at start of the line\n");
1836 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1838 s = line+2;
1839 while (isspace(*s)) s++;
1840 if (strncmp(s, "end", 3)!=0)
1841 exitfileerror(20, "\"##end methodlist\" expected\n");
1843 s += 3;
1844 while (isspace(*s)) s++;
1845 if (strncmp(s, "methodlist", 10)!=0)
1846 exitfileerror(20, "\"##end methodlist\" expected\n");
1848 s += 10;
1849 while (isspace(*s)) s++;
1850 if (*s!='\0')
1851 exitfileerror(20, "unexpected character on position %d\n", s-line);
1853 atend = 1;
1855 continue;
1858 if (*line=='.')
1860 s = line+1;
1861 if (strncmp(s, "alias", 5)==0)
1863 s += 5;
1865 if (!isspace(*s))
1866 exitfileerror(20, "syntax is '.alias name'\n");
1868 while (isspace(*s)) s++;
1869 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1870 exitfileerror(20, "syntax is '.alias name'\n");
1872 s2 = s;
1873 s++;
1874 while (isalnum(*s) || *s == '_') s++;
1876 if (isspace(*s))
1878 *s = '\0';
1879 do {
1880 s++;
1881 } while (isspace(*s));
1884 if (*s != '\0')
1885 exitfileerror(20, "syntax is '.alias name'\n");
1887 if (*methlistptr == NULL)
1888 exitfileerror(20, ".alias has to come after a function declaration\n");
1890 slist_append(&(*methlistptr)->aliases, s2);
1892 else if (strncmp(s, "function", 8) == 0)
1894 s += 8;
1896 if (!isspace(*s))
1897 exitfileerror(20, "Syntax error\n");
1899 while (isspace(*s)) s++;
1900 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1901 exitfileerror(20, "syntax is '.function name'\n");
1903 s2 = s;
1904 s++;
1905 while (isalnum(*s) || *s == '_') s++;
1907 if (isspace(*s))
1909 *s = '\0';
1910 do {
1911 s++;
1912 } while (isspace(*s));
1915 if (*s != '\0')
1916 exitfileerror(20, "syntax is '.function name'\n");
1918 if (*methlistptr == NULL)
1919 exitfileerror(20, ".function has to come after a function declaration\n");
1921 funcsetinternalname(*methlistptr, s2);
1923 else if (strncmp(s, "interface", 9) == 0)
1925 if (cl->classtype != HIDD)
1926 exitfileerror(20, "interface only valid for a HIDD\n");
1928 s += 9;
1930 if (!isspace(*s))
1931 exitfileerror(20, "Syntax error\n");
1933 while (isspace(*s)) s++;
1934 if (*s == '\0' || !isalpha(*s))
1935 exitfileerror(20, "syntax is '.interface name'\n");
1937 s2 = s;
1938 s++;
1939 while (isalnum(*s) || *s == '_') s++;
1941 if (isspace(*s))
1943 *s = '\0';
1944 do {
1945 s++;
1946 } while (isspace(*s));
1949 if (*s != '\0')
1950 exitfileerror(20, "syntax is '.interface name'\n");
1952 interface = slist_append(&cl->interfaces, s2);
1954 else
1955 exitfileerror(20, "Syntax error");
1957 else if (isalpha(*line))
1959 char stmp[256];
1961 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
1964 if (cl->classtype == HIDD && interface == NULL)
1965 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
1967 if (*s != '\0')
1968 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
1970 if (*methlistptr != NULL)
1971 methlistptr = &((*methlistptr)->next);
1972 if (cl->classtype != HIDD)
1974 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
1975 exitfileerror(20, "Method name too large\n");
1977 *methlistptr = newfunctionhead(stmp, STACK);
1978 (*methlistptr)->type = "IPTR";
1979 funcaddarg(*methlistptr, "Class *cl", NULL);
1980 funcaddarg(*methlistptr, "Object *o", NULL);
1981 funcaddarg(*methlistptr, "Msg msg", NULL);
1983 else
1985 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
1986 exitfileerror(20, "Method name too large\n");
1988 *methlistptr = newfunctionhead(stmp, STACK);
1989 (*methlistptr)->type = "IPTR";
1990 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
1991 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
1992 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
1993 (*methlistptr)->interface = interface;
1994 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
1995 exitfileerror(20, "Method name too large\n");
1996 (*methlistptr)->method = strdup(stmp);
1998 slist_append(&(*methlistptr)->aliases, line);
2000 else
2001 exitfileerror(20, "Methodname has to begin with a letter\n");
2005 static void
2006 readsectioninterface(struct config *cfg)
2008 char *s;
2009 struct interfaceinfo *in;
2011 in = newinterface(cfg);
2012 s = readsections(cfg, NULL, in, 1);
2013 if (s == NULL)
2014 exitfileerror(20, "Unexpected end of file\n");
2016 if (strncmp(s, "##", 2) != 0)
2017 exitfileerror(20, "'##end interface' expected\n");
2018 s += 2;
2020 while (isspace(*s)) s++;
2022 if (strncmp(s, "end", 3) != 0)
2023 exitfileerror(20, "'##end interface' expected\n");
2024 s += 3;
2026 if (!isspace(*s))
2027 exitfileerror(20, "'##end interface' expected\n");
2028 while (isspace(*s)) s++;
2030 if (strncmp(s, "interface", 9) != 0)
2031 exitfileerror(20, "'##end interface' expected\n");
2032 s += 9;
2034 while (isspace(*s)) s++;
2035 if (*s != '\0')
2036 exitfileerror(20, "'##end interface' expected\n");
2038 if (!in->interfaceid)
2039 exitfileerror(20, "interface has no 'interfaceid' defined!\n");
2041 if (!in->interfacename)
2042 exitfileerror(20, "interface has no 'interfacename' defined!\n");
2044 if (!in->methodstub)
2045 in->methodstub = strdup(in->interfacename);
2047 if (!in->methodbase) {
2048 int len = strlen(in->interfacename);
2049 in->methodbase = malloc(len + 4 + 1);
2050 strcpy(in->methodbase, in->interfacename);
2051 strcat(in->methodbase, "Base");
2054 if (!in->attributebase) {
2055 int len = strlen(in->interfacename);
2056 in->attributebase = malloc(len + 4 + 4 + 1);
2057 strcpy(in->attributebase, in->interfacename);
2058 strcat(in->attributebase, "AttrBase");
2062 static void
2063 readsectionclass(struct config *cfg)
2065 char *s;
2066 struct classinfo *cl;
2068 cl = newclass(cfg);
2069 s = readsections(cfg, cl, NULL, 1);
2070 if (s == NULL)
2071 exitfileerror(20, "Unexpected end of file\n");
2073 if (strncmp(s, "##", 2) != 0)
2074 exitfileerror(20, "'##end class' expected\n");
2075 s += 2;
2077 while (isspace(*s)) s++;
2079 if (strncmp(s, "end", 3) != 0)
2080 exitfileerror(20, "'##end class' expected\n");
2081 s += 3;
2083 if (!isspace(*s))
2084 exitfileerror(20, "'##end class' expected\n");
2085 while (isspace(*s)) s++;
2087 if (strncmp(s, "class", 5) != 0)
2088 exitfileerror(20, "'##end class' expected\n");
2089 s += 5;
2091 while (isspace(*s)) s++;
2092 if (*s != '\0')
2093 exitfileerror(20, "'##end class' expected\n");
2096 static struct classinfo *newclass(struct config *cfg)
2098 struct classinfo *cl, *classlistit;
2100 cl = malloc(sizeof(struct classinfo));
2101 if (cl == NULL)
2103 fprintf(stderr, "Out of memory\n");
2104 exit(20);
2106 memset(cl, 0, sizeof(struct classinfo));
2108 /* By default the classes are initialized with a priority of 1 so they
2109 * are initialized before any user added initialization with priority 1
2111 cl->initpri = 1;
2113 if (cfg->classlist == NULL)
2114 cfg->classlist = cl;
2115 else
2119 classlistit = cfg->classlist;
2120 classlistit->next != NULL;
2121 classlistit = classlistit->next
2124 classlistit->next = cl;
2127 return cl;
2130 static struct handlerinfo *newhandler(struct config *cfg)
2132 struct handlerinfo *hl;
2134 hl = calloc(1,sizeof(*hl));
2135 hl->next = cfg->handlerlist;
2136 cfg->handlerlist = hl;
2137 return hl;
2140 static struct interfaceinfo *newinterface(struct config *cfg)
2142 struct interfaceinfo *in, *interfacelistit;
2144 in = malloc(sizeof(struct interfaceinfo));
2145 if (in == NULL)
2147 fprintf(stderr, "Out of memory\n");
2148 exit(20);
2150 memset(in, 0, sizeof(struct interfaceinfo));
2152 if (cfg->interfacelist == NULL)
2153 cfg->interfacelist = in;
2154 else
2158 interfacelistit = cfg->interfacelist;
2159 interfacelistit->next != NULL;
2160 interfacelistit = interfacelistit->next
2163 interfacelistit->next = in;
2166 return in;
2170 static int getdirective(char *s, const char *directive, int range_min, int range_max, int *val)
2172 char *tmp;
2173 int newval;
2175 if (strncmp(s, directive, strlen(directive)) != 0)
2176 return 0;
2178 s += strlen(directive);
2179 if (*s && !isspace(*s))
2180 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive);
2182 while (isspace(*s)) s++;
2183 if (!*s)
2184 exitfileerror(20, "No .%s value specified\n", directive);
2186 newval = strtol(s, &tmp, 0);
2187 if (s == tmp || !(newval >= range_min && newval <= range_max)) {
2188 tmp = s;
2189 while (*tmp && !isspace(*tmp)) tmp++;
2190 exitfileerror(20, "Invalid .%s value of %.*s\n", directive, tmp - s, s);
2193 *val = newval;
2194 return 1;
2197 static void
2198 readsectionhandler(struct config *cfg)
2200 char *line = NULL, *s;
2201 struct handlerinfo *hl;
2202 unsigned char autolevel = 0;
2203 unsigned int stacksize = 0;
2204 int startup = 0;
2205 char priority = 10;
2206 int bootpri = -128;
2207 int has_filesystem = 0;
2209 for (;;)
2211 char *function;
2212 int function_len;
2213 char *tmp;
2215 s = line = readline();
2217 if (s==NULL)
2218 exitfileerror(20, "unexpected end of file in section hanlder\n");
2220 if (strncmp(s, "##", 2)==0)
2221 break;
2223 /* Ignore comments */
2224 if (strncmp(s, "#", 1)==0)
2225 continue;
2227 /* Skip ahead to function name */
2228 while (*s && isspace(*s)) s++;
2230 /* Permit blank lines */
2231 if (!*s)
2232 continue;
2234 if (*s == '.') {
2235 int val;
2236 s++;
2238 if (getdirective(s, "autodetect", 0, 127, &val)) {
2239 autolevel = val;
2240 } else if (getdirective(s, "stacksize", 0, INT_MAX, &val)) {
2241 stacksize = val;
2242 } else if (getdirective(s, "priority", -128, 127, &val)) {
2243 priority = val;
2244 } else if (getdirective(s, "bootpri", -128, 127, &val)) {
2245 bootpri = val;
2246 } else if (getdirective(s, "startup", INT_MIN, INT_MAX, &val)) {
2247 startup = val;
2248 } else {
2249 exitfileerror(20, "Unrecognized directive \"%s\"\n", line);
2251 continue;
2254 do {
2255 unsigned int id = 0;
2257 if (strncasecmp(s,"resident=",9)==0) {
2258 char *res;
2260 s = strchr(s, '=') + 1;
2261 res = s;
2262 while (*s && !isspace(*s)) s++;
2263 if (res == s)
2264 exitfileerror(20, "Empty resident= is not permitted\n");
2266 if (*s)
2267 *(s++) = 0;
2269 hl = newhandler(cfg);
2270 hl->type = HANDLER_RESIDENT;
2271 hl->id = 0;
2272 hl->name = strdup(res);
2273 hl->autodetect = autolevel--;
2274 hl->stacksize = stacksize;
2275 hl->priority = priority;
2276 hl->startup = startup;
2277 } else if (strncasecmp(s,"dosnode=",8)==0) {
2278 char *dev;
2280 s = strchr(s, '=') + 1;
2281 dev = s;
2282 while (*s && !isspace(*s)) s++;
2283 if (dev == s)
2284 exitfileerror(20, "Empty dosnode= is not permitted\n");
2286 if (*s)
2287 *(s++) = 0;
2289 hl = newhandler(cfg);
2290 hl->type = HANDLER_DOSNODE;
2291 hl->id = 0;
2292 hl->name = strdup(dev);
2293 hl->autodetect = autolevel ? autolevel-- : 0;
2294 hl->stacksize = stacksize;
2295 hl->priority = priority;
2296 hl->startup = startup;
2297 hl->bootpri = bootpri;
2298 } else if (strncasecmp(s,"dostype=",8) == 0) {
2299 s = strchr(s, '=') + 1;
2301 id = (unsigned int)strtoul(s, &tmp, 0);
2303 if (s == tmp) {
2304 while (*tmp && !isspace(*tmp))
2305 tmp++;
2306 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp -s), s);
2308 s = tmp;
2310 if (id == 0 || id == ~0) {
2311 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id);
2314 hl = newhandler(cfg);
2315 hl->type = HANDLER_DOSTYPE;
2316 hl->id = id;
2317 hl->name = NULL;
2318 hl->autodetect = autolevel ? autolevel-- : 0;
2319 hl->stacksize = stacksize;
2320 hl->priority = priority;
2321 hl->startup = startup;
2322 } else {
2323 for (tmp = s; !isspace(*tmp); tmp++);
2324 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp - s, s);
2327 /* Advance to next ID */
2328 while (*s && isspace(*s)) s++;
2330 } while (*s);
2333 if (s == NULL)
2334 exitfileerror(20, "Unexpected end of file\n");
2336 if (strncmp(s, "##", 2) != 0)
2337 exitfileerror(20, "'##end handler' expected\n");
2338 s += 2;
2340 while (isspace(*s)) s++;
2342 if (strncmp(s, "end", 3) != 0)
2343 exitfileerror(20, "'##end handler' expected\n");
2344 s += 3;
2346 while (isspace(*s)) s++;
2348 if (strncmp(s, "handler", 7) != 0)
2349 exitfileerror(20, "'##end handler' expected\n");
2350 s += 7;
2352 while (isspace(*s)) s++;
2353 if (*s != '\0')
2354 exitfileerror(20, "'##end handler' expected\n");