Actualized documentation
[AROS.git] / tools / genmodule / config.c
bloba9c5680993bca1f14036a5cbc58f86f558e70599
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] [-n]\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);
260 if (!hassuffix)
261 cfg->suffix = argv[optind+2];
263 /* Fill fields with default value if not specified on the command line */
265 char tmpbuf[256];
267 if (cfg->conffile == NULL)
269 snprintf(tmpbuf, sizeof(tmpbuf), "%s.conf", cfg->modulename);
270 cfg->conffile = strdup(tmpbuf);
273 if (cfg->gendir == NULL)
274 cfg->gendir = ".";
277 readconfig(cfg);
279 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
280 * if they are provided
282 if (cfg->beginiofunc != NULL)
284 struct functionhead *funchead;
286 cfg->intcfg |= CFG_NOREADFUNCS;
288 /* Add beginio_func to the list of functions */
289 funchead = newfunctionhead(cfg->beginiofunc, REGISTERMACRO);
290 funchead->type = strdup("void");
291 funchead->lvo = 5;
292 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
294 funchead->next = cfg->funclist;
295 cfg->funclist = funchead;
297 /* Add abortio_func to the list of functions */
298 funchead = newfunctionhead(cfg->abortiofunc, REGISTERMACRO);
299 funchead->type = strdup("LONG");
300 funchead->lvo = 6;
301 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
303 funchead->next = cfg->funclist->next;
304 cfg->funclist->next = funchead;
306 else if (cfg->modtype == DEVICE && cfg->intcfg & CFG_NOREADFUNCS)
308 fprintf
310 stderr,
311 "beginio_func and abortio_func missing for a device with a non empty function list\n"
313 exit(20);
316 /* See if we have any stackcall options */
317 if (cfg->funclist) {
318 struct functionhead *funchead;
320 for (funchead = cfg->funclist; funchead; funchead = funchead->next) {
321 if (funchead->libcall == STACK) {
322 cfg->options |= OPTION_STACKCALL;
323 break;
328 /* Verify that a handler has a handler */
329 if (cfg->modtype == HANDLER) {
330 if (cfg->handlerfunc == NULL) {
331 fprintf(stderr, "handler modules require a 'handler_func' ##config option\n");
332 exit(20);
334 cfg->options |= OPTION_NOAUTOLIB | OPTION_NOEXPUNGE | OPTION_NOOPENCLOSE;
337 return cfg;
340 /* Functions to read configuration from the configuration file */
342 #include "fileread.h"
344 static char *readsections(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
345 static void readsectionconfig(struct config *, struct classinfo *cl, struct interfaceinfo *in, int inclass);
346 static void readsectioncdef(struct config *);
347 static void readsectioncdefprivate(struct config *);
348 static void readsectionstartup(struct config *);
349 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute);
350 static void readsectionclass_methodlist(struct classinfo *);
351 static void readsectionclass(struct config *);
352 static void readsectionhandler(struct config *);
353 static void readsectioninterface(struct config *);
355 static void readconfig(struct config *cfg)
357 struct classinfo *mainclass = NULL;
359 /* Create a classinfo structure if this module is a class */
360 switch (cfg->modtype)
362 case LIBRARY:
363 case DEVICE:
364 case RESOURCE:
365 case USBCLASS:
366 case HANDLER:
367 break;
369 case MCC:
370 case MUI:
371 case MCP:
372 case GADGET:
373 case DATATYPE:
374 case HIDD:
375 mainclass = newclass(cfg);
376 mainclass->classtype = cfg->modtype;
377 break;
379 default:
380 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
381 exit(20);
384 switch (cfg->modtype)
386 case LIBRARY:
387 case USBCLASS:
388 cfg->firstlvo = 5;
389 break;
390 case DEVICE:
391 cfg->firstlvo = 7;
392 break;
393 case MCC:
394 case MUI:
395 case MCP:
396 cfg->firstlvo = 6;
397 mainclass->boopsimprefix = muimprefix;
398 break;
399 case HANDLER:
400 case RESOURCE:
401 cfg->firstlvo = 1;
402 break;
403 case GADGET:
404 cfg->firstlvo = 5;
405 mainclass->boopsimprefix = gadgetmprefix;
406 break;
407 case DATATYPE:
408 cfg->firstlvo = 6;
409 mainclass->boopsimprefix = dtmprefix;
410 break;
411 case HIDD:
412 cfg->firstlvo = 5;
413 /* FIXME: need boopsimprefix ? */
414 break;
415 default:
416 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
417 exit(20);
420 if (!fileopen(cfg->conffile))
422 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
423 exit(20);
426 /* Read all sections and see that we are at the end of the file */
427 if (readsections(cfg, mainclass, NULL, 0) != NULL)
428 exitfileerror(20, "Syntax error");
430 fileclose();
433 /* readsections will scan through all the sections in the config file.
434 * arguments:
435 * struct config *cfg: The module config data which may be updated by
436 * the information in the sections
437 * struct classinfo *cl: The classdata to be filled with data from the sections.
438 * This may be NULL if this is the main part of the configuration file and the
439 * type of the module is not a class
440 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
441 * part of the config file.
443 static char *readsections(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
445 char *line, *s, *s2;
446 int hasconfig = 0;
448 while ((line=readline())!=NULL)
450 if (strncmp(line, "##", 2)==0)
452 static char *parts[] =
454 "config", "cdefprivate", "cdef", "startup", "functionlist", "methodlist", "class", "handler", "interface", "attributelist"
456 const unsigned int nums = sizeof(parts)/sizeof(char *);
457 unsigned int partnum;
458 int i, atend = 0;
460 s = line+2;
461 while (isspace(*s)) s++;
463 if (strncmp(s, "begin", 5)!=0)
464 return line;
466 s += 5;
467 if (!isspace(*s))
468 exitfileerror(20, "space after begin expected\n");
469 while (isspace(*s)) s++;
471 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
473 if (strncmp(s, parts[i], strlen(parts[i]))==0)
475 partnum = i+1;
476 s += strlen(parts[i]);
477 while (isspace(*s)) s++;
478 if (*s!='\0')
479 exitfileerror(20, "unexpected character on position %d\n", s-line);
482 if (partnum==0)
483 exitfileerror(20, "unknown start of section\n");
484 switch (partnum)
486 case 1: /* config */
487 readsectionconfig(cfg, cl, in, inclass);
488 hasconfig = 1;
489 break;
491 case 2: /* cdefprivate */
492 if (inclass)
493 exitfileerror(20, "cdefprivate section not allowed in class section\n");
494 readsectioncdefprivate(cfg);
495 break;
497 case 3: /* cdef */
498 if (inclass)
499 exitfileerror(20, "cdef section not allowed in class section\n");
500 readsectioncdef(cfg);
501 break;
503 case 4: /* startup */
504 if (inclass)
505 exitfileerror(20, "startup section not allowed in class section\n");
506 readsectionstartup(cfg);
507 break;
509 case 5: /* functionlist */
510 if (inclass)
511 exitfileerror(20, "functionlist section not allow in class section\n");
512 if (cfg->basename==NULL)
513 exitfileerror(20, "section functionlist has to come after section config\n");
515 readsectionfunctionlist("functionlist", &cfg->funclist, cfg->firstlvo, 0);
516 cfg->intcfg |= CFG_NOREADFUNCS;
517 break;
519 case 6: /* methodlist */
520 if (cl == NULL && in == NULL)
521 exitfileerror(20, "methodlist section when not in a class or interface\n");
522 if (cl)
523 readsectionclass_methodlist(cl);
524 else
525 readsectionfunctionlist("methodlist", &in->methodlist, 0, 0);
526 cfg->intcfg |= CFG_NOREADFUNCS;
527 break;
529 case 7: /* class */
530 if (inclass)
531 exitfileerror(20, "class section may not be in nested\n");
532 readsectionclass(cfg);
533 break;
534 case 8: /* handler */
535 readsectionhandler(cfg);
536 break;
537 case 9: /* interface */
538 if (inclass)
539 exitfileerror(20, "interface section may not be nested\n");
540 readsectioninterface(cfg);
541 break;
542 case 10: /* attributelist */
543 if (!in)
544 exitfileerror(20, "attributelist only valid in interface sections\n");
545 readsectionfunctionlist("attributelist", &in->attributelist, 0, 1);
546 break;
549 else if (strlen(line)!=0)
550 filewarning("warning line outside section ignored\n");
553 if(!inclass)
555 if (!hasconfig)
556 exitfileerror(20, "No config section in conffile\n");
558 /* If no indication was given for generating includes or not
559 decide on module type and if there are functions
561 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
563 switch (cfg->modtype)
565 case LIBRARY:
566 case RESOURCE:
567 cfg->options |= OPTION_INCLUDES;
568 break;
570 case HANDLER:
571 case MCC:
572 case MUI:
573 case MCP:
574 case USBCLASS:
575 cfg->options |= OPTION_NOINCLUDES;
576 break;
578 case DEVICE:
579 cfg->options |= (
580 (cfg->funclist != NULL)
581 || (cfg->cdeflines != NULL)
582 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
583 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
584 break;
586 case GADGET:
587 case DATATYPE:
588 case HIDD:
589 cfg->options |= (
590 (cfg->funclist != NULL)
591 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
592 break;
594 default:
595 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
596 exit(20);
597 break;
601 /* If no indication was given for not generating stubs only generate them if
602 * the module has functions
604 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
606 switch (cfg->modtype)
608 case LIBRARY:
609 cfg->options |= (cfg->funclist != NULL) ? OPTION_STUBS : OPTION_NOSTUBS;
610 break;
612 case USBCLASS:
613 case RESOURCE:
614 case GADGET:
615 case DEVICE:
616 case DATATYPE:
617 case MCC:
618 case MUI:
619 case MCP:
620 case HIDD:
621 case HANDLER:
622 cfg->options |= OPTION_NOSTUBS;
623 break;
625 default:
626 fprintf(stderr, "Internal error writemakefile: unhandled modtype for stubs\n");
627 exit(20);
628 break;
632 /* If no indication was given for generating autoinit code or not
633 decide on module type
635 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
637 switch (cfg->modtype)
639 case LIBRARY:
640 cfg->options |= OPTION_AUTOINIT;
641 break;
643 case USBCLASS:
644 case RESOURCE:
645 case GADGET:
646 case DEVICE:
647 case DATATYPE:
648 case MCC:
649 case MUI:
650 case MCP:
651 case HIDD:
652 case HANDLER:
653 cfg->options |= OPTION_NOAUTOINIT;
654 break;
656 default:
657 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
658 exit(20);
659 break;
663 if ((cfg->modtype == RESOURCE) || (cfg->modtype == HANDLER))
664 /* Enforce noopenclose for resources and handlers */
665 cfg->options |= OPTION_NOOPENCLOSE;
666 else if (!(cfg->options & OPTION_SELFINIT))
667 /* Enforce using RTF_AUTOINIT for everything except resources */
668 cfg->options |= OPTION_RESAUTOINIT;
671 return NULL;
674 static void readsectionconfig(struct config *cfg, struct classinfo *cl, struct interfaceinfo *in, int inclass)
676 int atend = 0, i;
677 char *line, *s, *s2, *libbasetypeextern = NULL;
678 struct tm date;
680 while (!atend)
682 line = readline();
683 if (line==NULL)
684 exitfileerror(20, "unexpected end of file in section config\n");
686 if (strncmp(line, "##", 2)!=0)
688 const char *names[] =
690 "basename", "libbase", "libbasetype", "libbasetypeextern",
691 "version", "date", "copyright", "libcall", "forcebase", "superclass",
692 "superclass_field", "residentpri", "options", "sysbase_field",
693 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
694 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
695 "initpri", "type", "addromtag", "oopbase_field",
696 "rellib", "interfaceid", "interfacename",
697 "methodstub", "methodbase", "attributebase", "handler_func"
699 const unsigned int namenums = sizeof(names)/sizeof(char *);
700 unsigned int namenum;
702 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
706 strncmp(line, names[i], strlen(names[i]))==0
707 && isspace(*(line+strlen(names[i])))
709 namenum = i+1;
711 if (namenum==0)
712 exitfileerror(20, "unrecognized configuration option\n");
714 s = line + strlen(names[namenum-1]);
715 if (!isspace(*s))
716 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
718 while (isspace(*s)) s++;
719 if (*s=='\0')
720 exitfileerror(20, "unexpected end of line\n");
722 s2 = s + strlen(s);
723 while (isspace(*(s2-1))) s2--;
724 *s2 = '\0';
726 switch (namenum)
728 case 1: /* basename */
729 if (!inclass)
730 cfg->basename = strdup(s);
731 if (cl != NULL)
732 cl->basename = strdup(s);
733 if (in != NULL)
734 exitfileerror(20, "basename not valid config option when in a interface section\n");
735 break;
737 case 2: /* libbase */
738 if (inclass)
739 exitfileerror(20, "libbase not valid config option when in a class section\n");
740 cfg->libbase = strdup(s);
741 break;
743 case 3: /* libbasetype */
744 if (inclass)
745 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
746 cfg->libbasetype = strdup(s);
747 break;
749 case 4: /* libbasetypeextern */
750 if (inclass)
751 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
752 libbasetypeextern = strdup(s);
753 break;
755 case 5: /* version */
756 if (inclass)
757 exitfileerror(20, "version not valid config option when in a class section\n");
758 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
759 exitfileerror(20, "wrong version string \"%s\"\n", s);
760 break;
762 case 6: /* date */
763 if (inclass)
764 exitfileerror(20, "date not valid config option when in a class section\n");
765 #ifndef _WIN32
766 if (strptime(s, "%e.%m.%Y", &date) == NULL)
768 exitfileerror(20, "date string has to have d.m.yyyy format\n");
770 #endif
771 cfg->datestring = strdup(s);
772 break;
774 case 7: /* copyright */
775 if (inclass)
776 exitfileerror(20, "copyright not valid config option when in a class section\n");
777 cfg->copyright = strdup(s);
778 break;
780 case 8: /* libcall */
781 fprintf(stderr, "libcall specification is deprecated and ignored\n");
782 break;
784 case 9: /* forcebase */
785 if (inclass)
786 exitfileerror(20, "forcebase not valid config option when in a class section\n");
787 slist_append(&cfg->forcelist, s);
788 break;
790 case 10: /* superclass */
791 if (cl == NULL)
792 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
793 cl->superclass = strdup(s);
794 break;
796 case 11: /* superclass_field */
797 if (cl == NULL)
798 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
799 cl->superclass_field = strdup(s);
800 break;
802 case 12: /* residentpri */
803 if (!inclass)
805 int count;
806 char dummy;
808 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
809 if (count != 1 ||
810 cfg->residentpri < -128 || cfg->residentpri > 127
813 exitfileerror(20, "residentpri number format error\n");
816 else
817 exitfileerror(20, "residentpri not valid config option when in a class section\n");
818 break;
820 case 13: /* options */
821 if (!inclass)
823 static const char *optionnames[] =
825 "noautolib", "noexpunge", "noresident", "peropenerbase",
826 "pertaskbase", "includes", "noincludes", "nostubs",
827 "autoinit", "noautoinit", "resautoinit", "noopenclose",
828 "selfinit"
830 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
831 int optionnum;
835 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
837 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
839 optionnum = i + 1;
840 s += strlen(optionnames[i]);
841 while (isspace(*s)) s++;
842 if (*s == ',')
843 s++;
844 else if (*s != '\0')
845 exitfileerror(20, "Unrecognized option\n");
848 if (optionnum == 0)
849 exitfileerror(20, "Unrecognized option\n");
850 switch (optionnum)
852 case 1: /* noautolib */
853 cfg->options |= OPTION_NOAUTOLIB;
854 break;
855 case 2: /* noexpunge */
856 cfg->options |= OPTION_NOEXPUNGE;
857 break;
858 case 3: /* noresident */
859 cfg->options |= OPTION_NORESIDENT;
860 cfg->firstlvo = 1;
861 break;
862 case 5: /* pertaskbase */
863 cfg->options |= OPTION_PERTASKBASE;
864 /* Fall through */
865 case 4: /* peropenerbase */
866 if (cfg->options & OPTION_DUPBASE)
867 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
868 cfg->options |= OPTION_DUPBASE;
869 break;
870 case 6: /* includes */
871 if (cfg->options & OPTION_NOINCLUDES)
872 exitfileerror(20, "option includes and noincludes are incompatible\n");
873 cfg->options |= OPTION_INCLUDES;
874 break;
875 case 7: /* noincludes */
876 if (cfg->options & OPTION_INCLUDES)
877 exitfileerror(20, "option includes and noincludes are incompatible\n");
878 cfg->options |= OPTION_NOINCLUDES;
879 break;
880 case 8: /* nostubs */
881 cfg->options |= OPTION_NOSTUBS;
882 break;
883 case 9: /* autoinit */
884 if (cfg->options & OPTION_NOAUTOINIT)
885 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
886 cfg->options |= OPTION_AUTOINIT;
887 break;
888 case 10: /* noautoinit */
889 if (cfg->options & OPTION_AUTOINIT)
890 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
891 cfg->options |= OPTION_NOAUTOINIT;
892 break;
893 case 11: /* resautoinit */
894 if (cfg->options & OPTION_SELFINIT)
895 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
896 cfg->options |= OPTION_RESAUTOINIT;
897 break;
898 case 12:
899 cfg->options |= OPTION_NOOPENCLOSE;
900 break;
901 case 13: /* noresautoinit */
902 if (cfg->options & OPTION_RESAUTOINIT)
903 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
904 cfg->options |= OPTION_SELFINIT;
905 break;
907 while (isspace(*s)) s++;
908 } while(*s !='\0');
910 else
912 static const char *optionnames[] =
914 "private"
916 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
917 int optionnum;
921 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
923 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
925 optionnum = i + 1;
926 s += strlen(optionnames[i]);
927 while (isspace(*s)) s++;
928 if (*s == ',')
929 s++;
930 else if (*s != '\0')
931 exitfileerror(20, "Unrecognized option\n");
934 if (optionnum == 0)
935 exitfileerror(20, "Unrecognized option\n");
936 switch (optionnum)
938 case 1: /* private */
939 cl->options |= COPTION_PRIVATE;
940 break;
942 while (isspace(*s)) s++;
943 } while(*s !='\0');
945 break;
947 case 14: /* sysbase_field */
948 if (inclass)
949 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
950 cfg->sysbase_field = strdup(s);
951 break;
953 case 15: /* seglist_field */
954 if (inclass)
955 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
956 cfg->seglist_field = strdup(s);
957 break;
959 case 16: /* rootbase_field */
960 if (inclass)
961 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
962 cfg->rootbase_field = strdup(s);
963 break;
965 case 17: /* classptr_field */
966 if (cl == NULL)
968 exitfileerror
971 "classptr_field specified when not a BOOPSI class\n"
974 cl->classptr_field = strdup(s);
975 break;
977 case 18: /* classptr_var */
978 if (cl == NULL)
980 exitfileerror
983 "classptr_var specified when not a BOOPSI class\n"
986 cl->classptr_var = strdup(s);
987 break;
989 case 19: /* classid */
990 if (cl == NULL)
991 exitfileerror(20, "classid specified when not a BOOPSI class\n");
992 if (cl->classid != NULL)
993 exitfileerror(20, "classid specified twice\n");
994 cl->classid = strdup(s);
995 if (strcmp(cl->classid, "NULL") == 0)
996 cl->options |= COPTION_PRIVATE;
997 break;
999 case 20: /* classdatatype */
1000 if (cl == NULL)
1001 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
1002 cl->classdatatype = strdup(s);
1003 break;
1005 case 21: /* beginio_func */
1006 if (inclass)
1007 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
1008 if (cfg->modtype != DEVICE)
1009 exitfileerror(20, "beginio_func specified when not a device\n");
1010 cfg->beginiofunc = strdup(s);
1011 break;
1013 case 22: /* abortio_func */
1014 if (inclass)
1015 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
1016 if (cfg->modtype != DEVICE)
1017 exitfileerror(20, "abortio_func specified when not a device\n");
1018 cfg->abortiofunc = strdup(s);
1019 break;
1021 case 23: /* dispatcher */
1022 if (cl == NULL)
1023 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
1024 cl->dispatcher = strdup(s);
1025 /* function references are not needed when dispatcher is specified */
1026 cfg->intcfg |= CFG_NOREADFUNCS;
1027 break;
1029 case 24: /* initpri */
1030 if (cl != NULL)
1032 int count;
1033 char dummy;
1035 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
1036 if (count != 1 ||
1037 cl->initpri < -128 || cl->initpri > 127
1040 exitfileerror(20, "initpri number format error\n");
1043 else
1044 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
1045 break;
1047 case 25: /* type */
1048 if (!inclass)
1049 exitfileerror(20, "type only valid config option in a class section\n");
1050 if (strcmp(s,"mcc")==0)
1051 cl->classtype = MCC;
1052 else if (strcmp(s,"mui")==0)
1053 cl->classtype = MUI;
1054 else if (strcmp(s,"mcp")==0)
1055 cl->classtype = MCP;
1056 else if (strcmp(s, "image")==0)
1057 cl->classtype = IMAGE;
1058 else if (strcmp(s, "gadget")==0)
1059 cl->classtype = GADGET;
1060 else if (strcmp(s, "datatype")==0)
1061 cl->classtype = DATATYPE;
1062 else if (strcmp(s, "usbclass")==0)
1063 cl->classtype = USBCLASS;
1064 else if (strcmp(s, "class")==0)
1065 cl->classtype = CLASS;
1066 else if (strcmp(s, "hidd")==0)
1067 cl->classtype = HIDD;
1068 else
1070 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
1071 exit(20);
1073 break;
1075 case 26: /* addromtag */
1076 cfg->addromtag = strdup(s);
1077 break;
1079 case 27: /* oopbase_field */
1080 cfg->oopbase_field = strdup(s);
1081 break;
1082 case 28: /* rellib */
1083 slist_append(&cfg->rellibs, s);
1084 break;
1085 case 29: /* interfaceid */
1086 if (!in)
1087 exitfileerror(20, "interfaceid only valid config option for an interface\n");
1088 in->interfaceid = strdup(s);
1089 break;
1090 case 30: /* interfacename */
1091 if (!in)
1092 exitfileerror(20, "interfacename only valid config option for an interface\n");
1093 in->interfacename = strdup(s);
1094 break;
1095 case 31: /* methodstub */
1096 if (!in)
1097 exitfileerror(20, "methodstub only valid config option for an interface\n");
1098 in->methodstub = strdup(s);
1099 break;
1100 case 32: /* methodbase */
1101 if (!in)
1102 exitfileerror(20, "methodbase only valid config option for an interface\n");
1103 in->methodbase = strdup(s);
1104 break;
1105 case 33: /* attributebase */
1106 if (!in)
1107 exitfileerror(20, "attributebase only valid config option for an interface\n");
1108 in->attributebase = strdup(s);
1109 break;
1110 case 34: /* handler_func */
1111 if (cfg->modtype != HANDLER)
1112 exitfileerror(20, "handler specified when not a handler\n");
1113 cfg->handlerfunc = strdup(s);
1114 break;
1117 else /* Line starts with ## */
1119 s = line+2;
1120 while (isspace(*s)) s++;
1121 if (strncmp(s, "end", 3)!=0)
1122 exitfileerror(20, "\"##end config\" expected\n");
1124 s += 3;
1125 if (!isspace(*s))
1126 exitfileerror(20, "\"##end config\" expected\n");
1128 while (isspace(*s)) s++;
1129 if (strncmp(s, "config", 6)!=0)
1130 exitfileerror(20, "\"##end config\" expected\n");
1132 s += 6;
1133 while (isspace(*s)) s++;
1134 if (*s!='\0')
1135 exitfileerror(20, "\"##end config\" expected\n");
1137 atend = 1;
1141 /* When not in a class section fill in default values for fields in cfg */
1142 if (!inclass)
1144 if (cfg->basename==NULL)
1146 cfg->basename = strdup(cfg->modulename);
1147 *cfg->basename = toupper(*cfg->basename);
1149 if (cfg->libbase==NULL)
1151 unsigned int len = strlen(cfg->basename)+5;
1152 cfg->libbase = malloc(len);
1153 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1155 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1156 cfg->libbasetype = strdup(libbasetypeextern);
1157 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1158 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1159 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1160 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1161 if (cfg->oopbase_field != NULL && cfg->libbasetype == NULL)
1162 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1163 /* rootbase_field only allowed when duplicating base */
1164 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1165 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1167 /* Set default date to current date */
1168 if (cfg->datestring == NULL)
1170 char tmpbuf[256];
1171 time_t now = time(NULL);
1172 struct tm *ltime = localtime(&now);
1174 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1175 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1177 cfg->datestring = strdup(tmpbuf);
1180 if (cfg->copyright == NULL)
1181 cfg->copyright = "";
1183 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1184 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1186 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1188 if (libbasetypeextern==NULL)
1190 switch (cfg->modtype)
1192 case DEVICE:
1193 cfg->libbasetypeptrextern = "struct Device *";
1194 break;
1195 case HANDLER:
1196 case RESOURCE:
1197 cfg->libbasetypeptrextern = "APTR ";
1198 break;
1199 case LIBRARY:
1200 case MUI:
1201 case MCP:
1202 case MCC:
1203 case GADGET:
1204 case DATATYPE:
1205 case USBCLASS:
1206 case HIDD:
1207 cfg->libbasetypeptrextern = "struct Library *";
1208 break;
1209 default:
1210 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1211 exit(20);
1214 else
1216 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1217 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1218 strcat(cfg->libbasetypeptrextern, " *");
1219 free(libbasetypeextern);
1223 /* When class was given too fill in some defaults when not specified */
1224 if (cl != NULL)
1226 if (cl->classtype == UNSPECIFIED)
1227 cl->classtype = CLASS;
1229 if (cl->basename == NULL)
1231 if (!inclass)
1232 cl->basename = cfg->basename;
1233 else
1234 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1237 /* MUI classes are always private */
1238 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1239 cl->options |= COPTION_PRIVATE;
1241 if (cl->classid == NULL
1242 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1245 if (cl->classtype == HIDD)
1247 cl->options &= !COPTION_PRIVATE;
1249 else if (cl->options & COPTION_PRIVATE)
1251 cl->classid = "NULL";
1253 else
1255 char s[256] = "";
1257 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1259 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1261 else if (cl->classtype == DATATYPE)
1263 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1265 cl->classid = strdup(s);
1269 /* Only specify superclass or superclass_field */
1270 if (cl->superclass != NULL && cl->superclass_field != NULL)
1271 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1273 /* Give default value to superclass if it is not specified */
1274 if (cl->superclass == NULL && cl->superclass == NULL)
1276 switch (cl->classtype)
1278 case MUI:
1279 case MCC:
1280 cl->superclass = "MUIC_Area";
1281 break;
1282 case MCP:
1283 cl->superclass = "MUIC_Mccprefs";
1284 break;
1285 case IMAGE:
1286 cl->superclass = "IMAGECLASS";
1287 break;
1288 case GADGET:
1289 cl->superclass = "GADGETCLASS";
1290 break;
1291 case DATATYPE:
1292 cl->superclass = "DATATYPESCLASS";
1293 break;
1294 case CLASS:
1295 cl->superclass = "ROOTCLASS";
1296 break;
1297 case HIDD:
1298 cl->superclass = "CLID_Root";
1299 break;
1300 default:
1301 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1302 break;
1308 static void readsectioncdef(struct config *cfg)
1310 int atend = 0;
1311 char *line, *s;
1313 while (!atend)
1315 line = readline();
1316 if (line==NULL)
1317 exitfileerror(20, "unexptected end of file in section cdef\n");
1319 if (strncmp(line, "##", 2)!=0)
1321 slist_append(&cfg->cdeflines, line);
1323 else
1325 s = line+2;
1326 while (isspace(*s)) s++;
1327 if (strncmp(s, "end", 3)!=0)
1328 exitfileerror(20, "\"##end cdef\" expected\n");
1330 s += 3;
1331 while (isspace(*s)) s++;
1332 if (strncmp(s, "cdef", 4)!=0)
1333 exitfileerror(20, "\"##end cdef\" expected\n");
1335 s += 5;
1336 while (isspace(*s)) s++;
1337 if (*s!='\0')
1338 exitfileerror(20, "unexpected character at position %d\n");
1340 atend = 1;
1345 static void readsectioncdefprivate(struct config *cfg)
1347 int atend = 0;
1348 char *line, *s;
1350 while (!atend)
1352 line = readline();
1353 if (line==NULL)
1354 exitfileerror(20, "unexptected end of file in section cdef\n");
1356 if (strncmp(line, "##", 2)!=0)
1358 slist_append(&cfg->cdefprivatelines, line);
1360 else
1362 s = line+2;
1363 while (isspace(*s)) s++;
1364 if (strncmp(s, "end", 3)!=0)
1365 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1367 s += 3;
1368 while (isspace(*s)) s++;
1369 if (strncmp(s, "cdefprivate", 11)!=0)
1370 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1372 s += 11;
1373 while (isspace(*s)) s++;
1374 if (*s!='\0')
1375 exitfileerror(20, "unexpected character at position %d\n");
1377 atend = 1;
1382 static void readsectionstartup(struct config *cfg)
1384 int atend = 0;
1385 char *line, *s;
1387 while (!atend)
1389 line = readline();
1390 if (line==NULL)
1391 exitfileerror(20, "unexptected end of file in section startup\n");
1393 if (strncmp(line, "##", 2)!=0)
1395 slist_append(&cfg->startuplines, line);
1397 else
1399 s = line+2;
1400 while (isspace(*s)) s++;
1401 if (strncmp(s, "end", 3)!=0)
1402 exitfileerror(20, "\"##end startup\" expected\n");
1404 s += 3;
1405 while (isspace(*s)) s++;
1406 if (strncmp(s, "startup", 7)!=0)
1407 exitfileerror(20, "\"##end startup\" expected\n");
1409 s += 7;
1410 while (isspace(*s)) s++;
1411 if (*s!='\0')
1412 exitfileerror(20, "unexpected character at position %d\n");
1414 atend = 1;
1419 static void readsectionfunctionlist(const char *type, struct functionhead **funclistptr, unsigned int firstlvo, int isattribute)
1421 int atend = 0, i;
1422 char *line, *s, *s2;
1423 unsigned int lvo = firstlvo;
1424 int minversion = 0;
1426 while (!atend)
1428 line = readline();
1429 if (line==NULL)
1430 exitfileerror(20, "unexpected EOF in functionlist section\n");
1431 if (strlen(line)==0)
1433 if (*funclistptr != NULL)
1434 funclistptr = &((*funclistptr)->next);
1435 lvo++;
1437 else if (isspace(*line))
1439 s = line;
1440 while (isspace(*s)) s++;
1441 if (*s=='\0')
1443 if (*funclistptr != NULL)
1444 funclistptr = &((*funclistptr)->next);
1445 lvo++;
1447 else
1448 exitfileerror(20, "no space allowed before functionname\n");
1450 else if (strncmp(line, "##", 2)==0)
1452 s = line+2;
1453 while (isspace(*s)) s++;
1454 if (strncmp(s, "end", 3)!=0)
1455 exitfileerror(20, "\"##end %s\" expected\n", type);
1457 s += 3;
1458 while (isspace(*s)) s++;
1459 if (strncmp(s, type, strlen(type))!=0)
1460 exitfileerror(20, "\"##end %s\" expected\n", type);
1462 s += strlen(type);
1463 while (isspace(*s)) s++;
1464 if (*s!='\0')
1465 exitfileerror(20, "unexpected character on position %d\n", s-line);
1467 atend = 1;
1469 else if (*line=='.')
1471 s = line+1;
1472 if (strncmp(s, "skip", 4)==0)
1474 int n;
1476 s += 4;
1477 if (!isspace(*s))
1478 exitfileerror(20, "syntax is '.skip n'\n");
1480 n=strtol(s, &s2, 10);
1481 if (s2==NULL)
1482 exitfileerror(20, "positive number expected\n");
1484 while (isspace(*s2)) s2++;
1485 if ((*s2 != '\0') && (*s2 != '#'))
1486 exitfileerror(20, "syntax is '.skip n'\n");
1487 if (*funclistptr != NULL)
1488 funclistptr = &((*funclistptr)->next);
1489 lvo += n;
1491 else if (strncmp(s, "alias", 5)==0)
1493 s += 5;
1495 if (!isspace(*s))
1496 exitfileerror(20, "syntax is '.alias name'\n");
1498 while (isspace(*s)) s++;
1499 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1500 exitfileerror(20, "syntax is '.alias name'\n");
1502 s2 = s;
1503 s++;
1504 while (isalnum(*s) || *s == '_') s++;
1506 if (isspace(*s))
1508 *s = '\0';
1509 do {
1510 s++;
1511 } while (isspace(*s));
1514 if (*s != '\0')
1515 exitfileerror(20, "syntax is '.alias name'\n");
1517 if (*funclistptr == NULL)
1518 exitfileerror(20, ".alias has to come after a function declaration\n");
1520 slist_append(&(*funclistptr)->aliases, s2);
1522 else if (strncmp(s, "function", 8) == 0)
1524 s += 8;
1526 if (!isspace(*s))
1527 exitfileerror(20, "Syntax error\n");
1529 while (isspace(*s)) s++;
1530 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1531 exitfileerror(20, "syntax is '.function name'\n");
1533 s2 = s;
1534 s++;
1535 while (isalnum(*s) || *s == '_') s++;
1537 if (isspace(*s))
1539 *s = '\0';
1540 do {
1541 s++;
1542 } while (isspace(*s));
1545 if (*s != '\0')
1546 exitfileerror(20, "syntax is '.function name'\n");
1548 if (*funclistptr == NULL)
1549 exitfileerror(20, ".function has to come after a function declaration\n");
1551 funcsetinternalname(*funclistptr, s2);
1553 else if (strncmp(s, "cfunction", 9)==0)
1555 if (*funclistptr == NULL)
1556 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1558 (*funclistptr)->libcall = REGISTER;
1560 else if (strncmp(s, "private", 7)==0)
1562 if (*funclistptr == NULL)
1563 exitfileerror(20, ".private has to come after a function declaration\n");
1565 (*funclistptr)->priv = 1;
1567 else if (strncmp(s, "novararg", 8)==0)
1569 if (*funclistptr == NULL)
1570 exitfileerror(20, ".novararg has to come after a function declaration\n");
1572 (*funclistptr)->novararg = 1;
1574 else if (strncmp(s, "version", 7) == 0)
1576 /* Mark version number for the following
1577 * functions, so that the automatic OpenLibrary()
1578 * will know what version to use.
1580 char *tmp;
1581 int ver;
1583 s += 7;
1585 while (isspace(*s)) s++;
1586 ver = (int)strtol(s, &tmp, 0);
1588 if (s == tmp)
1589 exitfileerror(20, ".version expects an integer\n");
1591 s = tmp;
1592 while (isspace(*s)) s++;
1594 if (*s && *s != '#')
1595 exitfileerror(20, ".version has junk after the version number\n");
1597 minversion = ver;
1599 else if (strncmp(s, "unusedlibbase", 13) == 0)
1601 if (*funclistptr == NULL)
1602 exitfileerror(20, ".unusedlibbase has to come after a function declaration\n");
1603 (*funclistptr)->unusedlibbase = 1;
1605 else
1606 exitfileerror(20, "Syntax error");
1608 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1610 /* The line is a function or attribute prototype.
1611 * A function can have one of two syntaxes:
1612 * type funcname(argproto1, argproto2, ...)
1613 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1614 * The former is for C type function argument passing, the latter for
1615 * register argument passing.
1616 * An attribute has the following syntax:
1617 * type attribute
1619 char c, *args[64], *regs[64], *funcname, *cp;
1620 int len, argcount = 0, regcount = 0, brcount = 0;
1622 cp = strchr(line,'#');
1623 if (cp)
1624 *(cp++) = 0;
1626 /* Parse 'type functionname' at the beginning of the line */
1627 if (isattribute) {
1628 s = line + strlen(line);
1629 } else {
1630 s = strchr(line, '(');
1631 if (s == NULL)
1632 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1635 s2 = s;
1636 while (isspace(*(s2-1)))
1637 s2--;
1638 *s2 = '\0';
1640 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1641 s2--;
1643 if (s2 == line)
1644 exitfileerror(20, "No type specifier before %s name\n", isattribute ? "attribute" : "function");
1646 if (*funclistptr != NULL)
1647 funclistptr = &((*funclistptr)->next);
1648 *funclistptr = newfunctionhead(s2, STACK);
1650 if (cp)
1651 (*funclistptr)->comment = strdup(cp);
1652 else
1653 (*funclistptr)->comment = NULL;
1655 while (isspace(*(s2-1)))
1656 s2--;
1657 *s2 = '\0';
1658 (*funclistptr)->type = strdup(line);
1659 (*funclistptr)->lvo = lvo;
1660 (*funclistptr)->version = minversion;
1661 lvo++;
1663 if (isattribute)
1664 continue;
1666 /* Parse function prototype */
1667 s++;
1668 while (isspace(*s))
1669 s++;
1670 c = *s;
1672 while (c != ')')
1674 while (isspace(*s))
1675 s++;
1677 args[argcount] = s;
1678 argcount++;
1680 while
1682 *s != '\0'
1683 && !(brcount == 0 && (*s == ',' || *s == ')'))
1686 if (*s == '(')
1687 brcount++;
1688 if (*s == ')')
1690 if (brcount > 0)
1691 brcount--;
1692 else
1693 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1695 s++;
1698 c = *s;
1699 if (c == '\0')
1700 exitfileerror(20, "'(' without ')'");
1702 s2 = s;
1703 while (isspace(*(s2-1)))
1704 s2--;
1705 *s2 = '\0';
1707 if (!(s2 > args[argcount - 1]))
1708 exitfileerror(20, "Syntax error in function prototype\n");
1710 s++;
1713 s++;
1714 while (*s != '\0' && isspace(*s))
1715 s++;
1717 if (*s == '(')
1719 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1721 /* There may be no register specified with () so be sure then c is == ')' */
1722 s++;
1723 while(isspace(*s))
1724 s++;
1726 c = *s;
1728 while (c != ')')
1730 while (isspace(*s))
1731 s++;
1733 regs[regcount] = s;
1734 regcount++;
1736 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1738 s += 2;
1739 c = *s;
1740 if (c == '/')
1742 s++;
1743 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1745 s += 2;
1746 c = *s;
1748 else
1749 exitfileerror(20,
1750 "wrong register specification \"%s\" for argument %u\n",
1751 regs[regcount-1], regcount
1754 if (regcount > 4)
1755 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount, regs[regcount-1]);
1757 *s = '\0';
1759 else
1760 exitfileerror(20,
1761 "wrong register \"%s\" for argument %u\n",
1762 regs[regcount-1], regcount
1765 while (isspace(c))
1767 s++;
1768 c = *s;
1770 if (c == '\0')
1771 exitfileerror(20, "'(' without ')'\n");
1772 if (c != ',' && c != ')')
1773 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1775 s++;
1778 s++;
1779 while (isspace(*s)) s++;
1780 if (*s!='\0')
1781 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1783 if (argcount != regcount)
1784 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1785 argcount, regcount
1788 (*funclistptr)->libcall = REGISTERMACRO;
1789 for (i = 0; i < argcount; i++)
1790 funcaddarg(*funclistptr, args[i], regs[i]);
1792 else if (*s == '\0')
1793 { /* No registers specified */
1794 for (i = 0; i < argcount; i++)
1795 funcaddarg(*funclistptr, args[i], NULL);
1797 else
1798 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1803 static void readsectionclass_methodlist(struct classinfo *cl)
1805 int atend = 0, i;
1806 char *line, *s, *s2;
1807 struct functionhead **methlistptr = &cl->methlist;
1808 struct stringlist *interface = NULL;
1810 if (cl->basename==NULL)
1811 exitfileerror(20, "section methodlist has to come after section config\n");
1813 while (!atend)
1815 line = readline();
1816 if (line==NULL)
1817 exitfileerror(20, "unexptected EOF in methodlist section\n");
1819 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1820 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1821 continue;
1823 if (isspace(*line))
1824 exitfileerror(20, "No space allowed at start of the line\n");
1826 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1828 s = line+2;
1829 while (isspace(*s)) s++;
1830 if (strncmp(s, "end", 3)!=0)
1831 exitfileerror(20, "\"##end methodlist\" expected\n");
1833 s += 3;
1834 while (isspace(*s)) s++;
1835 if (strncmp(s, "methodlist", 10)!=0)
1836 exitfileerror(20, "\"##end methodlist\" expected\n");
1838 s += 10;
1839 while (isspace(*s)) s++;
1840 if (*s!='\0')
1841 exitfileerror(20, "unexpected character on position %d\n", s-line);
1843 atend = 1;
1845 continue;
1848 if (*line=='.')
1850 s = line+1;
1851 if (strncmp(s, "alias", 5)==0)
1853 s += 5;
1855 if (!isspace(*s))
1856 exitfileerror(20, "syntax is '.alias name'\n");
1858 while (isspace(*s)) s++;
1859 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1860 exitfileerror(20, "syntax is '.alias name'\n");
1862 s2 = s;
1863 s++;
1864 while (isalnum(*s) || *s == '_') s++;
1866 if (isspace(*s))
1868 *s = '\0';
1869 do {
1870 s++;
1871 } while (isspace(*s));
1874 if (*s != '\0')
1875 exitfileerror(20, "syntax is '.alias name'\n");
1877 if (*methlistptr == NULL)
1878 exitfileerror(20, ".alias has to come after a function declaration\n");
1880 slist_append(&(*methlistptr)->aliases, s2);
1882 else if (strncmp(s, "function", 8) == 0)
1884 s += 8;
1886 if (!isspace(*s))
1887 exitfileerror(20, "Syntax error\n");
1889 while (isspace(*s)) s++;
1890 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1891 exitfileerror(20, "syntax is '.function name'\n");
1893 s2 = s;
1894 s++;
1895 while (isalnum(*s) || *s == '_') s++;
1897 if (isspace(*s))
1899 *s = '\0';
1900 do {
1901 s++;
1902 } while (isspace(*s));
1905 if (*s != '\0')
1906 exitfileerror(20, "syntax is '.function name'\n");
1908 if (*methlistptr == NULL)
1909 exitfileerror(20, ".function has to come after a function declaration\n");
1911 funcsetinternalname(*methlistptr, s2);
1913 else if (strncmp(s, "interface", 9) == 0)
1915 if (cl->classtype != HIDD)
1916 exitfileerror(20, "interface only valid for a HIDD\n");
1918 s += 9;
1920 if (!isspace(*s))
1921 exitfileerror(20, "Syntax error\n");
1923 while (isspace(*s)) s++;
1924 if (*s == '\0' || !isalpha(*s))
1925 exitfileerror(20, "syntax is '.interface name'\n");
1927 s2 = s;
1928 s++;
1929 while (isalnum(*s) || *s == '_') s++;
1931 if (isspace(*s))
1933 *s = '\0';
1934 do {
1935 s++;
1936 } while (isspace(*s));
1939 if (*s != '\0')
1940 exitfileerror(20, "syntax is '.interface name'\n");
1942 interface = slist_append(&cl->interfaces, s2);
1944 else
1945 exitfileerror(20, "Syntax error");
1947 else if (isalpha(*line))
1949 char stmp[256];
1951 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
1954 if (cl->classtype == HIDD && interface == NULL)
1955 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
1957 if (*s != '\0')
1958 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
1960 if (*methlistptr != NULL)
1961 methlistptr = &((*methlistptr)->next);
1962 if (cl->classtype != HIDD)
1964 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
1965 exitfileerror(20, "Method name too large\n");
1967 *methlistptr = newfunctionhead(stmp, STACK);
1968 (*methlistptr)->type = "IPTR";
1969 funcaddarg(*methlistptr, "Class *cl", NULL);
1970 funcaddarg(*methlistptr, "Object *o", NULL);
1971 funcaddarg(*methlistptr, "Msg msg", NULL);
1973 else
1975 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
1976 exitfileerror(20, "Method name too large\n");
1978 *methlistptr = newfunctionhead(stmp, STACK);
1979 (*methlistptr)->type = "IPTR";
1980 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
1981 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
1982 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
1983 (*methlistptr)->interface = interface;
1984 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
1985 exitfileerror(20, "Method name too large\n");
1986 (*methlistptr)->method = strdup(stmp);
1988 slist_append(&(*methlistptr)->aliases, line);
1990 else
1991 exitfileerror(20, "Methodname has to begin with a letter\n");
1995 static void
1996 readsectioninterface(struct config *cfg)
1998 char *s;
1999 struct interfaceinfo *in;
2001 in = newinterface(cfg);
2002 s = readsections(cfg, NULL, in, 1);
2003 if (s == NULL)
2004 exitfileerror(20, "Unexpected end of file\n");
2006 if (strncmp(s, "##", 2) != 0)
2007 exitfileerror(20, "'##end interface' expected\n");
2008 s += 2;
2010 while (isspace(*s)) s++;
2012 if (strncmp(s, "end", 3) != 0)
2013 exitfileerror(20, "'##end interface' expected\n");
2014 s += 3;
2016 if (!isspace(*s))
2017 exitfileerror(20, "'##end interface' expected\n");
2018 while (isspace(*s)) s++;
2020 if (strncmp(s, "interface", 9) != 0)
2021 exitfileerror(20, "'##end interface' expected\n");
2022 s += 9;
2024 while (isspace(*s)) s++;
2025 if (*s != '\0')
2026 exitfileerror(20, "'##end interface' expected\n");
2028 if (!in->interfaceid)
2029 exitfileerror(20, "interface has no 'interfaceid' defined!\n");
2031 if (!in->interfacename)
2032 exitfileerror(20, "interface has no 'interfacename' defined!\n");
2034 if (!in->methodstub)
2035 in->methodstub = strdup(in->interfacename);
2037 if (!in->methodbase) {
2038 int len = strlen(in->interfacename);
2039 in->methodbase = malloc(len + 4 + 1);
2040 strcpy(in->methodbase, in->interfacename);
2041 strcat(in->methodbase, "Base");
2044 if (!in->attributebase) {
2045 int len = strlen(in->interfacename);
2046 in->attributebase = malloc(len + 4 + 4 + 1);
2047 strcpy(in->attributebase, in->interfacename);
2048 strcat(in->attributebase, "AttrBase");
2052 static void
2053 readsectionclass(struct config *cfg)
2055 char *s;
2056 struct classinfo *cl;
2058 cl = newclass(cfg);
2059 s = readsections(cfg, cl, NULL, 1);
2060 if (s == NULL)
2061 exitfileerror(20, "Unexpected end of file\n");
2063 if (strncmp(s, "##", 2) != 0)
2064 exitfileerror(20, "'##end class' expected\n");
2065 s += 2;
2067 while (isspace(*s)) s++;
2069 if (strncmp(s, "end", 3) != 0)
2070 exitfileerror(20, "'##end class' expected\n");
2071 s += 3;
2073 if (!isspace(*s))
2074 exitfileerror(20, "'##end class' expected\n");
2075 while (isspace(*s)) s++;
2077 if (strncmp(s, "class", 5) != 0)
2078 exitfileerror(20, "'##end class' expected\n");
2079 s += 5;
2081 while (isspace(*s)) s++;
2082 if (*s != '\0')
2083 exitfileerror(20, "'##end class' expected\n");
2086 static struct classinfo *newclass(struct config *cfg)
2088 struct classinfo *cl, *classlistit;
2090 cl = malloc(sizeof(struct classinfo));
2091 if (cl == NULL)
2093 fprintf(stderr, "Out of memory\n");
2094 exit(20);
2096 memset(cl, 0, sizeof(struct classinfo));
2098 /* By default the classes are initialized with a priority of 1 so they
2099 * are initialized before any user added initialization with priority 1
2101 cl->initpri = 1;
2103 if (cfg->classlist == NULL)
2104 cfg->classlist = cl;
2105 else
2109 classlistit = cfg->classlist;
2110 classlistit->next != NULL;
2111 classlistit = classlistit->next
2114 classlistit->next = cl;
2117 return cl;
2120 static struct handlerinfo *newhandler(struct config *cfg)
2122 struct handlerinfo *hl;
2124 hl = calloc(1,sizeof(*hl));
2125 hl->next = cfg->handlerlist;
2126 cfg->handlerlist = hl;
2127 return hl;
2130 static struct interfaceinfo *newinterface(struct config *cfg)
2132 struct interfaceinfo *in, *interfacelistit;
2134 in = malloc(sizeof(struct interfaceinfo));
2135 if (in == NULL)
2137 fprintf(stderr, "Out of memory\n");
2138 exit(20);
2140 memset(in, 0, sizeof(struct interfaceinfo));
2142 if (cfg->interfacelist == NULL)
2143 cfg->interfacelist = in;
2144 else
2148 interfacelistit = cfg->interfacelist;
2149 interfacelistit->next != NULL;
2150 interfacelistit = interfacelistit->next
2153 interfacelistit->next = in;
2156 return in;
2160 static int getdirective(char *s, const char *directive, int range_min, int range_max, int *val)
2162 char *tmp;
2163 int newval;
2165 if (strncmp(s, directive, strlen(directive)) != 0)
2166 return 0;
2168 s += strlen(directive);
2169 if (*s && !isspace(*s))
2170 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive);
2172 while (isspace(*s)) s++;
2173 if (!*s)
2174 exitfileerror(20, "No .%s value specified\n", directive);
2176 newval = strtol(s, &tmp, 0);
2177 if (s == tmp || !(newval >= range_min && newval <= range_max)) {
2178 tmp = s;
2179 while (*tmp && !isspace(*tmp)) tmp++;
2180 exitfileerror(20, "Invalid .%s value of %.*s\n", directive, tmp - s, s);
2183 *val = newval;
2184 return 1;
2187 static void
2188 readsectionhandler(struct config *cfg)
2190 char *line = NULL, *s;
2191 struct handlerinfo *hl;
2192 unsigned char autolevel = 0;
2193 unsigned int stacksize = 0;
2194 int startup = 0;
2195 char priority = 10;
2196 int bootpri = -128;
2197 int has_filesystem = 0;
2199 for (;;)
2201 char *function;
2202 int function_len;
2203 char *tmp;
2205 s = line = readline();
2207 if (s==NULL)
2208 exitfileerror(20, "unexpected end of file in section hanlder\n");
2210 if (strncmp(s, "##", 2)==0)
2211 break;
2213 /* Ignore comments */
2214 if (strncmp(s, "#", 1)==0)
2215 continue;
2217 /* Skip ahead to function name */
2218 while (*s && isspace(*s)) s++;
2220 /* Permit blank lines */
2221 if (!*s)
2222 continue;
2224 if (*s == '.') {
2225 int val;
2226 s++;
2228 if (getdirective(s, "autodetect", 0, 127, &val)) {
2229 autolevel = val;
2230 } else if (getdirective(s, "stacksize", 0, INT_MAX, &val)) {
2231 stacksize = val;
2232 } else if (getdirective(s, "priority", -128, 127, &val)) {
2233 priority = val;
2234 } else if (getdirective(s, "bootpri", -128, 127, &val)) {
2235 bootpri = val;
2236 } else if (getdirective(s, "startup", INT_MIN, INT_MAX, &val)) {
2237 startup = val;
2238 } else {
2239 exitfileerror(20, "Unrecognized directive \"%s\"\n", line);
2241 continue;
2244 do {
2245 unsigned int id = 0;
2247 if (strncasecmp(s,"resident=",9)==0) {
2248 char *res;
2250 s = strchr(s, '=') + 1;
2251 res = s;
2252 while (*s && !isspace(*s)) s++;
2253 if (res == s)
2254 exitfileerror(20, "Empty resident= is not permitted\n");
2256 if (*s)
2257 *(s++) = 0;
2259 hl = newhandler(cfg);
2260 hl->type = HANDLER_RESIDENT;
2261 hl->id = 0;
2262 hl->name = strdup(res);
2263 hl->autodetect = autolevel--;
2264 hl->stacksize = stacksize;
2265 hl->priority = priority;
2266 hl->startup = startup;
2267 } else if (strncasecmp(s,"dosnode=",8)==0) {
2268 char *dev;
2270 s = strchr(s, '=') + 1;
2271 dev = s;
2272 while (*s && !isspace(*s)) s++;
2273 if (dev == s)
2274 exitfileerror(20, "Empty dosnode= is not permitted\n");
2276 if (*s)
2277 *(s++) = 0;
2279 hl = newhandler(cfg);
2280 hl->type = HANDLER_DOSNODE;
2281 hl->id = 0;
2282 hl->name = strdup(dev);
2283 hl->autodetect = autolevel ? autolevel-- : 0;
2284 hl->stacksize = stacksize;
2285 hl->priority = priority;
2286 hl->startup = startup;
2287 hl->bootpri = bootpri;
2288 } else if (strncasecmp(s,"dostype=",8) == 0) {
2289 s = strchr(s, '=') + 1;
2291 id = (unsigned int)strtoul(s, &tmp, 0);
2293 if (s == tmp) {
2294 while (*tmp && !isspace(*tmp))
2295 tmp++;
2296 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp -s), s);
2298 s = tmp;
2300 if (id == 0 || id == ~0) {
2301 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id);
2304 hl = newhandler(cfg);
2305 hl->type = HANDLER_DOSTYPE;
2306 hl->id = id;
2307 hl->name = NULL;
2308 hl->autodetect = autolevel ? autolevel-- : 0;
2309 hl->stacksize = stacksize;
2310 hl->priority = priority;
2311 hl->startup = startup;
2312 } else {
2313 for (tmp = s; !isspace(*tmp); tmp++);
2314 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp - s, s);
2317 /* Advance to next ID */
2318 while (*s && isspace(*s)) s++;
2320 } while (*s);
2323 if (s == NULL)
2324 exitfileerror(20, "Unexpected end of file\n");
2326 if (strncmp(s, "##", 2) != 0)
2327 exitfileerror(20, "'##end handler' expected\n");
2328 s += 2;
2330 while (isspace(*s)) s++;
2332 if (strncmp(s, "end", 3) != 0)
2333 exitfileerror(20, "'##end handler' expected\n");
2334 s += 3;
2336 while (isspace(*s)) s++;
2338 if (strncmp(s, "handler", 7) != 0)
2339 exitfileerror(20, "'##end handler' expected\n");
2340 s += 7;
2342 while (isspace(*s)) s++;
2343 if (*s != '\0')
2344 exitfileerror(20, "'##end handler' expected\n");