Reapplied r44288:
[AROS.git] / tools / genmodule / config.c
blobdf6924d12525f797b1954e5f2d89c788a01e70f9
1 /*
2 Copyright © 1995-2012, 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-2012, The AROS Development Team. All rights reserved.\n"
24 "*/\n";
26 char*
27 getBanner(struct config* config)
29 int bannerlength = strlen(config->conffile) + strlen(bannertemplate) -1;
30 char * banner = malloc(bannerlength);
32 snprintf (banner, bannerlength, bannertemplate, config->conffile);
34 return(banner);
37 void
38 freeBanner(char *banner)
40 free((void *)banner);
43 const static char usage[] =
44 "\n"
45 "Usage: genmodule [-c conffile] [-s suffix] [-d gendir] [-n]\n"
46 " {writefiles|writemakefile|writeincludes|writelibdefs|writefunclist|writefd|writeskel} modname modtype\n"
49 static void readconfig(struct config *);
50 static struct classinfo *newclass(struct config *);
51 static struct handlerinfo *newhandler(struct config *);
53 /* the method prefices for the supported classes */
54 static const char *muimprefix[] =
56 "__OM_",
57 "__MUIM_",
58 NULL
60 static const char *gadgetmprefix[] =
62 "__OM_",
63 "__GM_",
64 "__AROSM_",
65 NULL
67 static const char *dtmprefix[] =
69 "__OM_",
70 "__GM_",
71 "__DTM_",
72 "__PDTM_",
73 NULL
76 /* Create a config struct. Initialize with the values from the programs command
77 * line arguments and the contents of the modules .conf file
79 struct config *initconfig(int argc, char **argv)
81 struct config *cfg;
82 char *s, **argvit = argv + 1;
83 int hassuffix = 0, c;
85 cfg = malloc(sizeof(struct config));
86 if (cfg == NULL)
88 fprintf(stderr, "Out of memory\n");
89 exit(20);
92 memset(cfg, 0, sizeof(struct config));
94 while ((c = getopt(argc, argv, ":c:s:d:v:")) != -1)
96 if (c == ':')
98 fprintf(stderr, "Option -%c needs an argument\n",optopt);
99 exit(20);
102 switch (c)
104 case 'c':
105 cfg->conffile = optarg;
106 break;
108 case 's':
109 cfg->suffix = optarg;
110 hassuffix = 1;
111 break;
113 case 'd':
114 /* Remove / at end if present */
115 if ((optarg)[strlen(*argvit)-1]=='/') (optarg)[strlen(optarg)-1]='\0';
116 cfg->gendir = optarg;
117 break;
119 case 'v':
120 cfg->versionextra = optarg;
121 break;
123 default:
124 fprintf(stderr, "Internal error: Unhandled option\n");
125 exit(20);
129 if (optind + 3 != argc)
131 fprintf(stderr, "Wrong number of arguments.\n%s", usage);
132 exit(20);
135 if (strcmp(argv[optind], "writefiles") == 0)
137 cfg->command = FILES;
139 else if (strcmp(argv[optind], "writemakefile") == 0)
141 cfg->command = MAKEFILE;
143 else if (strcmp(argv[optind], "writeincludes") == 0)
145 cfg->command = INCLUDES;
147 else if (strcmp(argv[optind], "writelibdefs") == 0)
149 cfg->command = LIBDEFS;
151 else if (strcmp(argv[optind], "writefunclist") == 0)
153 cfg->command = WRITEFUNCLIST;
155 else if (strcmp(argv[optind], "writefd") == 0)
157 cfg->command = WRITEFD;
159 else if (strcmp(argv[optind], "writeskel") == 0)
161 cfg->command = WRITESKEL;
163 else
165 fprintf(stderr, "Unrecognized argument \"%s\"\n%s", argv[optind], usage);
166 exit(20);
169 cfg->modulename = argv[optind+1];
170 cfg->modulenameupper = strdup(cfg->modulename);
171 for (s=cfg->modulenameupper; *s!='\0'; *s = toupper(*s), s++) {
172 if (!isalnum(*s)) *s = '_';
175 if (strcmp(argv[optind+2],"library")==0)
177 cfg->modtype = LIBRARY;
178 cfg->moddir = "Libs";
180 else if (strcmp(argv[optind+2],"mcc")==0)
182 cfg->modtype = MCC;
183 cfg->moddir = "Classes/Zune";
185 else if (strcmp(argv[optind+2],"mui")==0)
187 cfg->modtype = MUI;
188 cfg->moddir = "Classes/Zune";
190 else if (strcmp(argv[optind+2],"mcp")==0)
192 cfg->modtype = MCP;
193 cfg->moddir = "Classes/Zune";
195 else if (strcmp(argv[optind+2], "device")==0)
197 cfg->modtype = DEVICE;
198 cfg->moddir = "Devs";
200 else if (strcmp(argv[optind+2], "resource")==0)
202 cfg->modtype = RESOURCE;
203 cfg->moddir = "Devs";
205 else if (strcmp(argv[optind+2], "gadget")==0)
207 cfg->modtype = GADGET;
208 cfg->moddir = "Classes/Gadgets";
210 else if (strcmp(argv[optind+2], "datatype")==0)
212 cfg->modtype = DATATYPE;
213 cfg->moddir = "Classes/DataTypes";
215 else if (strcmp(argv[optind+2], "usbclass")==0)
217 cfg->modtype = USBCLASS;
218 cfg->moddir = "Classes/USB";
219 if(!hassuffix)
221 cfg->suffix = "class";
222 hassuffix = 1;
225 else if (strcmp(argv[optind+2], "hidd")==0)
227 cfg->modtype = HIDD;
228 cfg->moddir = "Devs/Drivers";
230 else if (strcmp(argv[optind+2], "handler")==0)
232 cfg->modtype = HANDLER;
233 cfg->moddir = "$(AROS_DIR_FS)";
235 else
237 fprintf(stderr, "Unknown modtype \"%s\" specified for second argument\n", argv[2]);
238 exit(20);
241 if (!hassuffix)
242 cfg->suffix = argv[optind+2];
244 /* Fill fields with default value if not specified on the command line */
246 char tmpbuf[256];
248 if (cfg->conffile == NULL)
250 snprintf(tmpbuf, sizeof(tmpbuf), "%s.conf", cfg->modulename);
251 cfg->conffile = strdup(tmpbuf);
254 if (cfg->gendir == NULL)
255 cfg->gendir = ".";
258 readconfig(cfg);
260 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
261 * if they are provided
263 if (cfg->beginiofunc != NULL)
265 struct functionhead *funchead;
267 cfg->intcfg |= CFG_NOREADFUNCS;
269 /* Add beginio_func to the list of functions */
270 funchead = newfunctionhead(cfg->beginiofunc, REGISTERMACRO);
271 funchead->type = strdup("void");
272 funchead->lvo = 5;
273 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
275 funchead->next = cfg->funclist;
276 cfg->funclist = funchead;
278 /* Add abortio_func to the list of functions */
279 funchead = newfunctionhead(cfg->abortiofunc, REGISTERMACRO);
280 funchead->type = strdup("LONG");
281 funchead->lvo = 6;
282 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
284 funchead->next = cfg->funclist->next;
285 cfg->funclist->next = funchead;
287 else if (cfg->modtype == DEVICE && cfg->intcfg & CFG_NOREADFUNCS)
289 fprintf
291 stderr,
292 "beginio_func and abortio_func missing for a device with a non empty function list\n"
294 exit(20);
297 return cfg;
300 /* Functions to read configuration from the configuration file */
302 #include "fileread.h"
304 static char *readsections(struct config *, struct classinfo *, int);
305 static void readsectionconfig(struct config *, struct classinfo *, int);
306 static void readsectioncdef(struct config *);
307 static void readsectioncdefprivate(struct config *);
308 static void readsectionstartup(struct config *);
309 static void readsectionfunctionlist(struct config *);
310 static void readsectionmethodlist(struct classinfo *);
311 static void readsectionclass(struct config *);
312 static void readsectionhandler(struct config *);
314 static void readconfig(struct config *cfg)
316 struct classinfo *mainclass = NULL;
318 /* Create a classinfo structure if this module is a class */
319 switch (cfg->modtype)
321 case LIBRARY:
322 case DEVICE:
323 case RESOURCE:
324 case USBCLASS:
325 case HANDLER:
326 break;
328 case MCC:
329 case MUI:
330 case MCP:
331 case GADGET:
332 case DATATYPE:
333 case HIDD:
334 mainclass = newclass(cfg);
335 mainclass->classtype = cfg->modtype;
336 break;
338 default:
339 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
340 exit(20);
343 switch (cfg->modtype)
345 case LIBRARY:
346 case USBCLASS:
347 cfg->firstlvo = 5;
348 break;
349 case DEVICE:
350 cfg->firstlvo = 7;
351 break;
352 case MCC:
353 case MUI:
354 case MCP:
355 cfg->firstlvo = 6;
356 mainclass->boopsimprefix = muimprefix;
357 break;
358 case HANDLER:
359 case RESOURCE:
360 cfg->firstlvo = 1;
361 break;
362 case GADGET:
363 cfg->firstlvo = 5;
364 mainclass->boopsimprefix = gadgetmprefix;
365 break;
366 case DATATYPE:
367 cfg->firstlvo = 6;
368 mainclass->boopsimprefix = dtmprefix;
369 break;
370 case HIDD:
371 cfg->firstlvo = 5;
372 /* FIXME: need boopsimprefix ? */
373 break;
374 default:
375 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
376 exit(20);
379 if (!fileopen(cfg->conffile))
381 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
382 exit(20);
385 /* Read all sections and see that we are at the end of the file */
386 if (readsections(cfg, mainclass, 0) != NULL)
387 exitfileerror(20, "Syntax error");
389 fileclose();
392 /* readsections will scan through all the sections in the config file.
393 * arguments:
394 * struct config *cfg: The module config data which may be updated by
395 * the information in the sections
396 * struct classinfo *cl: The classdata to be filled with data from the sections.
397 * This may be NULL if this is the main part of the configuration file and the
398 * type of the module is not a class
399 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
400 * part of the config file.
402 static char *readsections(struct config *cfg, struct classinfo *cl, int inclass)
404 char *line, *s, *s2;
405 int hasconfig = 0;
407 while ((line=readline())!=NULL)
409 if (strncmp(line, "##", 2)==0)
411 static char *parts[] =
413 "config", "cdefprivate", "cdef", "startup", "functionlist", "methodlist", "class", "handler",
415 const unsigned int nums = sizeof(parts)/sizeof(char *);
416 unsigned int partnum;
417 int i, atend = 0;
419 s = line+2;
420 while (isspace(*s)) s++;
422 if (strncmp(s, "begin", 5)!=0)
423 return line;
425 s += 5;
426 if (!isspace(*s))
427 exitfileerror(20, "space after begin expected\n");
428 while (isspace(*s)) s++;
430 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
432 if (strncmp(s, parts[i], strlen(parts[i]))==0)
434 partnum = i+1;
435 s += strlen(parts[i]);
436 while (isspace(*s)) s++;
437 if (*s!='\0')
438 exitfileerror(20, "unexpected character on position %d\n", s-line);
441 if (partnum==0)
442 exitfileerror(20, "unknown start of section\n");
443 switch (partnum)
445 case 1: /* config */
446 readsectionconfig(cfg, cl, inclass);
447 hasconfig = 1;
448 break;
450 case 2: /* cdefprivate */
451 if (inclass)
452 exitfileerror(20, "cdefprivate section not allowed in class section\n");
453 readsectioncdefprivate(cfg);
454 break;
456 case 3: /* cdef */
457 if (inclass)
458 exitfileerror(20, "cdef section not allowed in class section\n");
459 readsectioncdef(cfg);
460 break;
462 case 4: /* startup */
463 if (inclass)
464 exitfileerror(20, "startup section not allowed in class section\n");
465 readsectionstartup(cfg);
466 break;
468 case 5: /* functionlist */
469 if (inclass)
470 exitfileerror(20, "functionlist section not allow in class section\n");
471 readsectionfunctionlist(cfg);
472 cfg->intcfg |= CFG_NOREADFUNCS;
473 break;
475 case 6: /* methodlist */
476 if (cl == NULL)
477 exitfileerror(20, "methodlist section when not in a class\n");
478 readsectionmethodlist(cl);
479 cfg->intcfg |= CFG_NOREADFUNCS;
480 break;
482 case 7: /* class */
483 if (inclass)
484 exitfileerror(20, "class section may not be nested\n");
485 readsectionclass(cfg);
486 break;
487 case 8: /* handler */
488 readsectionhandler(cfg);
489 break;
492 else if (strlen(line)!=0)
493 filewarning("warning line outside section ignored\n");
496 if(!inclass)
498 if (!hasconfig)
499 exitfileerror(20, "No config section in conffile\n");
501 /* If no indication was given for generating includes or not
502 decide on module type and if there are functions
504 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
506 switch (cfg->modtype)
508 case LIBRARY:
509 case RESOURCE:
510 cfg->options |= OPTION_INCLUDES;
511 break;
513 case HANDLER:
514 case MCC:
515 case MUI:
516 case MCP:
517 case USBCLASS:
518 cfg->options |= OPTION_NOINCLUDES;
519 break;
521 case DEVICE:
522 cfg->options |= (
523 (cfg->funclist != NULL)
524 || (cfg->cdeflines != NULL)
525 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
526 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
527 break;
529 case GADGET:
530 case DATATYPE:
531 case HIDD:
532 cfg->options |= (
533 (cfg->funclist != NULL)
534 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
535 break;
537 default:
538 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
539 exit(20);
540 break;
544 /* If no indication was given for not generating stubs only generate them if
545 * the module has functions
547 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
549 switch (cfg->modtype)
551 case LIBRARY:
552 cfg->options |= (cfg->funclist != NULL) ? OPTION_STUBS : OPTION_NOSTUBS;
553 break;
555 case USBCLASS:
556 case RESOURCE:
557 case GADGET:
558 case DEVICE:
559 case DATATYPE:
560 case MCC:
561 case MUI:
562 case MCP:
563 case HIDD:
564 case HANDLER:
565 cfg->options |= OPTION_NOSTUBS;
566 break;
568 default:
569 fprintf(stderr, "Internal error writemakefile: unhandled modtype for stubs\n");
570 exit(20);
571 break;
575 /* If no indication was given for generating autoinit code or not
576 decide on module type
578 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
580 switch (cfg->modtype)
582 case LIBRARY:
583 cfg->options |= OPTION_AUTOINIT;
584 break;
586 case USBCLASS:
587 case RESOURCE:
588 case GADGET:
589 case DEVICE:
590 case DATATYPE:
591 case MCC:
592 case MUI:
593 case MCP:
594 case HIDD:
595 case HANDLER:
596 cfg->options |= OPTION_NOAUTOINIT;
597 break;
599 default:
600 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
601 exit(20);
602 break;
606 if ((cfg->modtype == RESOURCE) || (cfg->modtype == HANDLER))
607 /* Enforce noopenclose for resources and handlers */
608 cfg->options |= OPTION_NOOPENCLOSE;
609 else if (!(cfg->options & OPTION_SELFINIT))
610 /* Enforce using RTF_AUTOINIT for everything except resources */
611 cfg->options |= OPTION_RESAUTOINIT;
614 return NULL;
617 static void readsectionconfig(struct config *cfg, struct classinfo *cl, int inclass)
619 int atend = 0, i;
620 char *line, *s, *s2, *libbasetypeextern = NULL;
621 struct tm date;
623 while (!atend)
625 line = readline();
626 if (line==NULL)
627 exitfileerror(20, "unexpected end of file in section config\n");
629 if (strncmp(line, "##", 2)!=0)
631 const char *names[] =
633 "basename", "libbase", "libbasetype", "libbasetypeextern",
634 "version", "date", "copyright", "libcall", "forcebase", "superclass",
635 "superclass_field", "residentpri", "options", "sysbase_field",
636 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
637 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
638 "initpri", "type", "addromtag", "oopbase_field"
640 const unsigned int namenums = sizeof(names)/sizeof(char *);
641 unsigned int namenum;
643 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
647 strncmp(line, names[i], strlen(names[i]))==0
648 && isspace(*(line+strlen(names[i])))
650 namenum = i+1;
652 if (namenum==0)
653 exitfileerror(20, "unrecognized configuration option\n");
655 s = line + strlen(names[namenum-1]);
656 if (!isspace(*s))
657 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
659 while (isspace(*s)) s++;
660 if (*s=='\0')
661 exitfileerror(20, "unexpected end of line\n");
663 s2 = s + strlen(s);
664 while (isspace(*(s2-1))) s2--;
665 *s2 = '\0';
667 switch (namenum)
669 case 1: /* basename */
670 if (!inclass)
671 cfg->basename = strdup(s);
672 if (cl != NULL)
673 cl->basename = strdup(s);
674 break;
676 case 2: /* libbase */
677 if (inclass)
678 exitfileerror(20, "libbase not valid config option when in a class section\n");
679 cfg->libbase = strdup(s);
680 break;
682 case 3: /* libbasetype */
683 if (inclass)
684 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
685 cfg->libbasetype = strdup(s);
686 break;
688 case 4: /* libbasetypeextern */
689 if (inclass)
690 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
691 libbasetypeextern = strdup(s);
692 break;
694 case 5: /* version */
695 if (inclass)
696 exitfileerror(20, "version not valid config option when in a class section\n");
697 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
698 exitfileerror(20, "wrong version string \"%s\"\n", s);
699 break;
701 case 6: /* date */
702 if (inclass)
703 exitfileerror(20, "date not valid config option when in a class section\n");
704 #ifndef _WIN32
705 if (strptime(s, "%e.%m.%Y", &date) == NULL)
707 exitfileerror(20, "date string has to have d.m.yyyy format\n");
709 #endif
710 cfg->datestring = strdup(s);
711 break;
713 case 7: /* copyright */
714 if (inclass)
715 exitfileerror(20, "copyright not valid config option when in a class section\n");
716 cfg->copyright = strdup(s);
717 break;
719 case 8: /* libcall */
720 fprintf(stderr, "libcall specification is deprecated and ignored\n");
721 break;
723 case 9: /* forcebase */
724 if (inclass)
725 exitfileerror(20, "forcebase not valid config option when in a class section\n");
726 slist_append(&cfg->forcelist, s);
727 break;
729 case 10: /* superclass */
730 if (cl == NULL)
731 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
732 cl->superclass = strdup(s);
733 break;
735 case 11: /* superclass_field */
736 if (cl == NULL)
737 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
738 cl->superclass_field = strdup(s);
739 break;
741 case 12: /* residentpri */
742 if (!inclass)
744 int count;
745 char dummy;
747 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
748 if (count != 1 ||
749 cfg->residentpri < -128 || cfg->residentpri > 127
752 exitfileerror(20, "residentpri number format error\n");
755 else
756 exitfileerror(20, "residentpri not valid config option when in a class section\n");
757 break;
759 case 13: /* options */
760 if (!inclass)
762 static const char *optionnames[] =
764 "noautolib", "noexpunge", "noresident", "peropenerbase",
765 "pertaskbase", "includes", "noincludes", "nostubs",
766 "autoinit", "noautoinit", "resautoinit", "noopenclose",
767 "selfinit"
769 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
770 int optionnum;
774 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
776 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
778 optionnum = i + 1;
779 s += strlen(optionnames[i]);
780 while (isspace(*s)) s++;
781 if (*s == ',')
782 s++;
783 else if (*s != '\0')
784 exitfileerror(20, "Unrecognized option\n");
787 if (optionnum == 0)
788 exitfileerror(20, "Unrecognized option\n");
789 switch (optionnum)
791 case 1: /* noautolib */
792 cfg->options |= OPTION_NOAUTOLIB;
793 break;
794 case 2: /* noexpunge */
795 cfg->options |= OPTION_NOEXPUNGE;
796 break;
797 case 3: /* noresident */
798 cfg->options |= OPTION_NORESIDENT;
799 cfg->firstlvo = 1;
800 break;
801 case 5: /* pertaskbase */
802 cfg->options |= OPTION_PERTASKBASE;
803 /* Fall through */
804 case 4: /* peropenerbase */
805 if (cfg->options & OPTION_DUPBASE)
806 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
807 cfg->options |= OPTION_DUPBASE;
808 break;
809 case 6: /* includes */
810 if (cfg->options & OPTION_NOINCLUDES)
811 exitfileerror(20, "option includes and noincludes are incompatible\n");
812 cfg->options |= OPTION_INCLUDES;
813 break;
814 case 7: /* noincludes */
815 if (cfg->options & OPTION_INCLUDES)
816 exitfileerror(20, "option includes and noincludes are incompatible\n");
817 cfg->options |= OPTION_NOINCLUDES;
818 break;
819 case 8: /* nostubs */
820 cfg->options |= OPTION_NOSTUBS;
821 break;
822 case 9: /* autoinit */
823 if (cfg->options & OPTION_NOAUTOINIT)
824 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
825 cfg->options |= OPTION_AUTOINIT;
826 break;
827 case 10: /* noautoinit */
828 if (cfg->options & OPTION_AUTOINIT)
829 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
830 cfg->options |= OPTION_NOAUTOINIT;
831 break;
832 case 11: /* resautoinit */
833 if (cfg->options & OPTION_SELFINIT)
834 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
835 cfg->options |= OPTION_RESAUTOINIT;
836 break;
837 case 12:
838 cfg->options |= OPTION_NOOPENCLOSE;
839 break;
840 case 13: /* noresautoinit */
841 if (cfg->options & OPTION_RESAUTOINIT)
842 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
843 cfg->options |= OPTION_SELFINIT;
844 break;
846 while (isspace(*s)) s++;
847 } while(*s !='\0');
849 else
851 static const char *optionnames[] =
853 "private"
855 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
856 int optionnum;
860 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
862 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
864 optionnum = i + 1;
865 s += strlen(optionnames[i]);
866 while (isspace(*s)) s++;
867 if (*s == ',')
868 s++;
869 else if (*s != '\0')
870 exitfileerror(20, "Unrecognized option\n");
873 if (optionnum == 0)
874 exitfileerror(20, "Unrecognized option\n");
875 switch (optionnum)
877 case 1: /* private */
878 cl->options |= COPTION_PRIVATE;
879 break;
881 while (isspace(*s)) s++;
882 } while(*s !='\0');
884 break;
886 case 14: /* sysbase_field */
887 if (inclass)
888 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
889 cfg->sysbase_field = strdup(s);
890 break;
892 case 15: /* seglist_field */
893 if (inclass)
894 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
895 cfg->seglist_field = strdup(s);
896 break;
898 case 16: /* rootbase_field */
899 if (inclass)
900 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
901 cfg->rootbase_field = strdup(s);
902 break;
904 case 17: /* classptr_field */
905 if (cl == NULL)
907 exitfileerror
910 "classptr_field specified when not a BOOPSI class\n"
913 cl->classptr_field = strdup(s);
914 break;
916 case 18: /* classptr_var */
917 if (cl == NULL)
919 exitfileerror
922 "classptr_var specified when not a BOOPSI class\n"
925 cl->classptr_var = strdup(s);
926 break;
928 case 19: /* classid */
929 if (cl == NULL)
930 exitfileerror(20, "classid specified when not a BOOPSI class\n");
931 if (cl->classid != NULL)
932 exitfileerror(20, "classid specified twice\n");
933 cl->classid = strdup(s);
934 if (strcmp(cl->classid, "NULL") == 0)
935 cl->options |= COPTION_PRIVATE;
936 break;
938 case 20: /* classdatatype */
939 if (cl == NULL)
940 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
941 cl->classdatatype = strdup(s);
942 break;
944 case 21: /* beginio_func */
945 if (inclass)
946 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
947 if (cfg->modtype != DEVICE)
948 exitfileerror(20, "beginio_func specified when not a device\n");
949 cfg->beginiofunc = strdup(s);
950 break;
952 case 22: /* abortio_func */
953 if (inclass)
954 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
955 if (cfg->modtype != DEVICE)
956 exitfileerror(20, "abortio_func specified when not a device\n");
957 cfg->abortiofunc = strdup(s);
958 break;
960 case 23: /* dispatcher */
961 if (cl == NULL)
962 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
963 cl->dispatcher = strdup(s);
964 /* function references are not needed when dispatcher is specified */
965 cfg->intcfg |= CFG_NOREADFUNCS;
966 break;
968 case 24: /* initpri */
969 if (cl != NULL)
971 int count;
972 char dummy;
974 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
975 if (count != 1 ||
976 cl->initpri < -128 || cl->initpri > 127
979 exitfileerror(20, "initpri number format error\n");
982 else
983 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
984 break;
986 case 25: /* type */
987 if (!inclass)
988 exitfileerror(20, "type only valid config option in a class section\n");
989 if (strcmp(s,"mcc")==0)
990 cl->classtype = MCC;
991 else if (strcmp(s,"mui")==0)
992 cl->classtype = MUI;
993 else if (strcmp(s,"mcp")==0)
994 cl->classtype = MCP;
995 else if (strcmp(s, "image")==0)
996 cl->classtype = IMAGE;
997 else if (strcmp(s, "gadget")==0)
998 cl->classtype = GADGET;
999 else if (strcmp(s, "datatype")==0)
1000 cl->classtype = DATATYPE;
1001 else if (strcmp(s, "usbclass")==0)
1002 cl->classtype = USBCLASS;
1003 else if (strcmp(s, "class")==0)
1004 cl->classtype = CLASS;
1005 else if (strcmp(s, "hidd")==0)
1006 cl->classtype = HIDD;
1007 else
1009 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
1010 exit(20);
1012 break;
1014 case 26: /* addromtag */
1015 cfg->addromtag = strdup(s);
1016 break;
1018 case 27: /* oopbase_field */
1019 cfg->oopbase_field = strdup(s);
1020 break;
1023 else /* Line starts with ## */
1025 s = line+2;
1026 while (isspace(*s)) s++;
1027 if (strncmp(s, "end", 3)!=0)
1028 exitfileerror(20, "\"##end config\" expected\n");
1030 s += 3;
1031 if (!isspace(*s))
1032 exitfileerror(20, "\"##end config\" expected\n");
1034 while (isspace(*s)) s++;
1035 if (strncmp(s, "config", 6)!=0)
1036 exitfileerror(20, "\"##end config\" expected\n");
1038 s += 6;
1039 while (isspace(*s)) s++;
1040 if (*s!='\0')
1041 exitfileerror(20, "\"##end config\" expected\n");
1043 atend = 1;
1047 /* When not in a class section fill in default values for fields in cfg */
1048 if (!inclass)
1050 if (cfg->basename==NULL)
1052 cfg->basename = strdup(cfg->modulename);
1053 *cfg->basename = toupper(*cfg->basename);
1055 if (cfg->libbase==NULL)
1057 unsigned int len = strlen(cfg->basename)+5;
1058 cfg->libbase = malloc(len);
1059 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1061 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1062 cfg->libbasetype = strdup(libbasetypeextern);
1063 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1064 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1065 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1066 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1067 if (cfg->oopbase_field != NULL && cfg->libbasetype == NULL)
1068 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1069 /* rootbase_field only allowed when duplicating base */
1070 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1071 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1073 /* Set default date to current date */
1074 if (cfg->datestring == NULL)
1076 char tmpbuf[256];
1077 time_t now = time(NULL);
1078 struct tm *ltime = localtime(&now);
1080 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1081 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1083 cfg->datestring = strdup(tmpbuf);
1086 if (cfg->copyright == NULL)
1087 cfg->copyright = "";
1089 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1090 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1092 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1094 if (libbasetypeextern==NULL)
1096 switch (cfg->modtype)
1098 case DEVICE:
1099 cfg->libbasetypeptrextern = "struct Device *";
1100 break;
1101 case HANDLER:
1102 case RESOURCE:
1103 cfg->libbasetypeptrextern = "APTR ";
1104 break;
1105 case LIBRARY:
1106 case MUI:
1107 case MCP:
1108 case MCC:
1109 case GADGET:
1110 case DATATYPE:
1111 case USBCLASS:
1112 case HIDD:
1113 cfg->libbasetypeptrextern = "struct Library *";
1114 break;
1115 default:
1116 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1117 exit(20);
1120 else
1122 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1123 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1124 strcat(cfg->libbasetypeptrextern, " *");
1125 free(libbasetypeextern);
1129 /* When class was given too fill in some defaults when not specified */
1130 if (cl != NULL)
1132 if (cl->classtype == UNSPECIFIED)
1133 cl->classtype = CLASS;
1135 if (cl->basename == NULL)
1137 if (!inclass)
1138 cl->basename = cfg->basename;
1139 else
1140 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1143 /* MUI classes are always private */
1144 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1145 cl->options |= COPTION_PRIVATE;
1147 if (cl->classid == NULL
1148 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1151 if (cl->classtype == HIDD)
1153 cl->options &= !COPTION_PRIVATE;
1155 else if (cl->options & COPTION_PRIVATE)
1157 cl->classid = "NULL";
1159 else
1161 char s[256] = "";
1163 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1165 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1167 else if (cl->classtype == DATATYPE)
1169 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1171 cl->classid = strdup(s);
1175 /* Only specify superclass or superclass_field */
1176 if (cl->superclass != NULL && cl->superclass_field != NULL)
1177 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1179 /* Give default value to superclass if it is not specified */
1180 if (cl->superclass == NULL && cl->superclass == NULL)
1182 switch (cl->classtype)
1184 case MUI:
1185 case MCC:
1186 cl->superclass = "MUIC_Area";
1187 break;
1188 case MCP:
1189 cl->superclass = "MUIC_Mccprefs";
1190 break;
1191 case IMAGE:
1192 cl->superclass = "IMAGECLASS";
1193 break;
1194 case GADGET:
1195 cl->superclass = "GADGETCLASS";
1196 break;
1197 case DATATYPE:
1198 cl->superclass = "DATATYPESCLASS";
1199 break;
1200 case CLASS:
1201 cl->superclass = "ROOTCLASS";
1202 break;
1203 case HIDD:
1204 cl->superclass = "CLID_Root";
1205 break;
1206 default:
1207 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1208 break;
1214 static void readsectioncdef(struct config *cfg)
1216 int atend = 0;
1217 char *line, *s;
1219 while (!atend)
1221 line = readline();
1222 if (line==NULL)
1223 exitfileerror(20, "unexptected end of file in section cdef\n");
1225 if (strncmp(line, "##", 2)!=0)
1227 slist_append(&cfg->cdeflines, line);
1229 else
1231 s = line+2;
1232 while (isspace(*s)) s++;
1233 if (strncmp(s, "end", 3)!=0)
1234 exitfileerror(20, "\"##end cdef\" expected\n");
1236 s += 3;
1237 while (isspace(*s)) s++;
1238 if (strncmp(s, "cdef", 4)!=0)
1239 exitfileerror(20, "\"##end cdef\" expected\n");
1241 s += 5;
1242 while (isspace(*s)) s++;
1243 if (*s!='\0')
1244 exitfileerror(20, "unexpected character at position %d\n");
1246 atend = 1;
1251 static void readsectioncdefprivate(struct config *cfg)
1253 int atend = 0;
1254 char *line, *s;
1256 while (!atend)
1258 line = readline();
1259 if (line==NULL)
1260 exitfileerror(20, "unexptected end of file in section cdef\n");
1262 if (strncmp(line, "##", 2)!=0)
1264 slist_append(&cfg->cdefprivatelines, line);
1266 else
1268 s = line+2;
1269 while (isspace(*s)) s++;
1270 if (strncmp(s, "end", 3)!=0)
1271 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1273 s += 3;
1274 while (isspace(*s)) s++;
1275 if (strncmp(s, "cdefprivate", 11)!=0)
1276 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1278 s += 11;
1279 while (isspace(*s)) s++;
1280 if (*s!='\0')
1281 exitfileerror(20, "unexpected character at position %d\n");
1283 atend = 1;
1288 static void readsectionstartup(struct config *cfg)
1290 int atend = 0;
1291 char *line, *s;
1293 while (!atend)
1295 line = readline();
1296 if (line==NULL)
1297 exitfileerror(20, "unexptected end of file in section startup\n");
1299 if (strncmp(line, "##", 2)!=0)
1301 slist_append(&cfg->startuplines, line);
1303 else
1305 s = line+2;
1306 while (isspace(*s)) s++;
1307 if (strncmp(s, "end", 3)!=0)
1308 exitfileerror(20, "\"##end startup\" expected\n");
1310 s += 3;
1311 while (isspace(*s)) s++;
1312 if (strncmp(s, "startup", 7)!=0)
1313 exitfileerror(20, "\"##end startup\" expected\n");
1315 s += 7;
1316 while (isspace(*s)) s++;
1317 if (*s!='\0')
1318 exitfileerror(20, "unexpected character at position %d\n");
1320 atend = 1;
1325 static void readsectionfunctionlist(struct config *cfg)
1327 int atend = 0, i;
1328 char *line, *s, *s2;
1329 unsigned int lvo = cfg->firstlvo;
1330 int minversion = 0;
1331 struct functionhead **funclistptr = &cfg->funclist;
1333 if (cfg->basename==NULL)
1334 exitfileerror(20, "section functionlist has to come after section config\n");
1336 while (!atend)
1338 line = readline();
1339 if (line==NULL)
1340 exitfileerror(20, "unexptected EOF in functionlist section\n");
1341 if (strlen(line)==0)
1343 if (*funclistptr != NULL)
1344 funclistptr = &((*funclistptr)->next);
1345 lvo++;
1347 else if (isspace(*line))
1349 s = line;
1350 while (isspace(*s)) s++;
1351 if (*s=='\0')
1353 if (*funclistptr != NULL)
1354 funclistptr = &((*funclistptr)->next);
1355 lvo++;
1357 else
1358 exitfileerror(20, "no space allowed before functionname\n");
1360 else if (strncmp(line, "##", 2)==0)
1362 s = line+2;
1363 while (isspace(*s)) s++;
1364 if (strncmp(s, "end", 3)!=0)
1365 exitfileerror(20, "\"##end functionlist\" expected\n");
1367 s += 3;
1368 while (isspace(*s)) s++;
1369 if (strncmp(s, "functionlist", 12)!=0)
1370 exitfileerror(20, "\"##end functionlist\" expected\n");
1372 s += 12;
1373 while (isspace(*s)) s++;
1374 if (*s!='\0')
1375 exitfileerror(20, "unexpected character on position %d\n", s-line);
1377 atend = 1;
1379 else if (*line=='.')
1381 s = line+1;
1382 if (strncmp(s, "skip", 4)==0)
1384 int n;
1386 s += 4;
1387 if (!isspace(*s))
1388 exitfileerror(20, "syntax is '.skip n'\n");
1390 n=strtol(s, &s2, 10);
1391 if (s2==NULL)
1392 exitfileerror(20, "positive number expected\n");
1394 while (isspace(*s2)) s2++;
1395 if ((*s2 != '\0') && (*s2 != '#'))
1396 exitfileerror(20, "syntax is '.skip n'\n");
1397 if (*funclistptr != NULL)
1398 funclistptr = &((*funclistptr)->next);
1399 lvo += n;
1401 else if (strncmp(s, "alias", 5)==0)
1403 s += 5;
1405 if (!isspace(*s))
1406 exitfileerror(20, "syntax is '.alias name'\n");
1408 while (isspace(*s)) s++;
1409 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1410 exitfileerror(20, "syntax is '.alias name'\n");
1412 s2 = s;
1413 s++;
1414 while (isalnum(*s) || *s == '_') s++;
1416 if (isspace(*s))
1418 *s = '\0';
1419 do {
1420 s++;
1421 } while (isspace(*s));
1424 if (*s != '\0')
1425 exitfileerror(20, "syntax is '.alias name'\n");
1427 if (*funclistptr == NULL)
1428 exitfileerror(20, ".alias has to come after a function declaration\n");
1430 slist_append(&(*funclistptr)->aliases, s2);
1432 else if (strncmp(s, "function", 8) == 0)
1434 s += 8;
1436 if (!isspace(*s))
1437 exitfileerror(20, "Syntax error\n");
1439 while (isspace(*s)) s++;
1440 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1441 exitfileerror(20, "syntax is '.function name'\n");
1443 s2 = s;
1444 s++;
1445 while (isalnum(*s) || *s == '_') s++;
1447 if (isspace(*s))
1449 *s = '\0';
1450 do {
1451 s++;
1452 } while (isspace(*s));
1455 if (*s != '\0')
1456 exitfileerror(20, "syntax is '.function name'\n");
1458 if (*funclistptr == NULL)
1459 exitfileerror(20, ".function has to come after a function declaration\n");
1461 funcsetinternalname(*funclistptr, s2);
1463 else if (strncmp(s, "cfunction", 9)==0)
1465 if (*funclistptr == NULL)
1466 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1468 (*funclistptr)->libcall = REGISTER;
1470 else if (strncmp(s, "private", 7)==0)
1472 if (*funclistptr == NULL)
1473 exitfileerror(20, ".private has to come after a function declaration\n");
1475 (*funclistptr)->priv = 1;
1477 else if (strncmp(s, "novararg", 8)==0)
1479 if (*funclistptr == NULL)
1480 exitfileerror(20, ".novararg has to come after a function declaration\n");
1482 (*funclistptr)->novararg = 1;
1484 else if (strncmp(s, "version", 7) == 0)
1486 /* Mark version number for the following
1487 * functions, so that the automatic OpenLibrary()
1488 * will know what version to use.
1490 char *tmp;
1491 int ver;
1493 s += 7;
1495 while (isspace(*s)) s++;
1496 ver = (int)strtol(s, &tmp, 0);
1498 if (s == tmp)
1499 exitfileerror(20, ".version expects an integer\n");
1501 s = tmp;
1502 while (isspace(*s)) s++;
1504 if (*s && *s != '#')
1505 exitfileerror(20, ".version has junk after the version number\n");
1507 minversion = ver;
1509 else
1510 exitfileerror(20, "Syntax error");
1512 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1514 /* The line is a function prototype. It can have two syntax
1515 * type funcname(argproto1, argproto2, ...)
1516 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1517 * The former is for C type function argument passing, the latter for
1518 * register argument passing.
1520 char c, *args[64], *regs[64], *funcname;
1521 int len, argcount = 0, regcount = 0, brcount = 0;
1523 /* Parse 'type functionname' at the beginning of the line */
1524 s = strchr(line, '(');
1525 if (s == NULL)
1526 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1528 s2 = s;
1529 while (isspace(*(s2-1)))
1530 s2--;
1531 *s2 = '\0';
1533 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1534 s2--;
1536 if (s2 == line)
1537 exitfileerror(20, "No type specifier before function name\n");
1539 if (*funclistptr != NULL)
1540 funclistptr = &((*funclistptr)->next);
1541 *funclistptr = newfunctionhead(s2, STACK);
1543 while (isspace(*(s2-1)))
1544 s2--;
1545 *s2 = '\0';
1546 (*funclistptr)->type = strdup(line);
1547 (*funclistptr)->lvo = lvo;
1548 (*funclistptr)->version = minversion;
1549 lvo++;
1551 /* Parse function prototype */
1552 s++;
1553 while (isspace(*s))
1554 s++;
1555 c = *s;
1557 while (c != ')')
1559 while (isspace(*s))
1560 s++;
1562 args[argcount] = s;
1563 argcount++;
1565 while
1567 *s != '\0'
1568 && !(brcount == 0 && (*s == ',' || *s == ')'))
1571 if (*s == '(')
1572 brcount++;
1573 if (*s == ')')
1575 if (brcount > 0)
1576 brcount--;
1577 else
1578 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1580 s++;
1583 c = *s;
1584 if (c == '\0')
1585 exitfileerror(20, "'(' without ')'");
1587 s2 = s;
1588 while (isspace(*(s2-1)))
1589 s2--;
1590 *s2 = '\0';
1592 if (!(s2 > args[argcount - 1]))
1593 exitfileerror(20, "Syntax error in function prototype\n");
1595 s++;
1598 s++;
1599 while (*s != '\0' && isspace(*s))
1600 s++;
1602 if (*s == '(')
1604 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1606 /* There may be no register specified with () so be sure then c is == ')' */
1607 s++;
1608 while(isspace(*s))
1609 s++;
1611 c = *s;
1613 while (c != ')')
1615 while (isspace(*s))
1616 s++;
1618 regs[regcount] = s;
1619 regcount++;
1621 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1623 s += 2;
1624 c = *s;
1625 if (c == '/')
1627 s++;
1628 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1630 s += 2;
1631 c = *s;
1633 else
1634 exitfileerror(20,
1635 "wrong register specification \"%s\" for argument %u\n",
1636 regs[regcount-1], regcount
1639 if (regcount > 4)
1640 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount, regs[regcount-1]);
1642 *s = '\0';
1644 else
1645 exitfileerror(20,
1646 "wrong register \"%s\" for argument %u\n",
1647 regs[regcount-1], regcount
1650 while (isspace(c))
1652 s++;
1653 c = *s;
1655 if (c == '\0')
1656 exitfileerror(20, "'(' without ')'\n");
1657 if (c != ',' && c != ')')
1658 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1660 s++;
1663 s++;
1664 while (isspace(*s)) s++;
1665 if (*s!='\0')
1666 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1668 if (argcount != regcount)
1669 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1670 argcount, regcount
1673 (*funclistptr)->libcall = REGISTERMACRO;
1674 for (i = 0; i < argcount; i++)
1675 funcaddarg(*funclistptr, args[i], regs[i]);
1677 else if (*s == '\0')
1678 { /* No registers specified */
1679 for (i = 0; i < argcount; i++)
1680 funcaddarg(*funclistptr, args[i], NULL);
1682 else
1683 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1688 static void readsectionmethodlist(struct classinfo *cl)
1690 int atend = 0, i;
1691 char *line, *s, *s2;
1692 struct functionhead **methlistptr = &cl->methlist;
1693 struct stringlist *interface = NULL;
1695 if (cl->basename==NULL)
1696 exitfileerror(20, "section methodlist has to come after section config\n");
1698 while (!atend)
1700 line = readline();
1701 if (line==NULL)
1702 exitfileerror(20, "unexptected EOF in methodlist section\n");
1704 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1705 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1706 continue;
1708 if (isspace(*line))
1709 exitfileerror(20, "No space allowed at start of the line\n");
1711 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1713 s = line+2;
1714 while (isspace(*s)) s++;
1715 if (strncmp(s, "end", 3)!=0)
1716 exitfileerror(20, "\"##end methodlist\" expected\n");
1718 s += 3;
1719 while (isspace(*s)) s++;
1720 if (strncmp(s, "methodlist", 10)!=0)
1721 exitfileerror(20, "\"##end methodlist\" expected\n");
1723 s += 10;
1724 while (isspace(*s)) s++;
1725 if (*s!='\0')
1726 exitfileerror(20, "unexpected character on position %d\n", s-line);
1728 atend = 1;
1730 continue;
1733 if (*line=='.')
1735 s = line+1;
1736 if (strncmp(s, "alias", 5)==0)
1738 s += 5;
1740 if (!isspace(*s))
1741 exitfileerror(20, "syntax is '.alias name'\n");
1743 while (isspace(*s)) s++;
1744 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1745 exitfileerror(20, "syntax is '.alias name'\n");
1747 s2 = s;
1748 s++;
1749 while (isalnum(*s) || *s == '_') s++;
1751 if (isspace(*s))
1753 *s = '\0';
1754 do {
1755 s++;
1756 } while (isspace(*s));
1759 if (*s != '\0')
1760 exitfileerror(20, "syntax is '.alias name'\n");
1762 if (*methlistptr == NULL)
1763 exitfileerror(20, ".alias has to come after a function declaration\n");
1765 slist_append(&(*methlistptr)->aliases, s2);
1767 else if (strncmp(s, "function", 8) == 0)
1769 s += 8;
1771 if (!isspace(*s))
1772 exitfileerror(20, "Syntax error\n");
1774 while (isspace(*s)) s++;
1775 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1776 exitfileerror(20, "syntax is '.function name'\n");
1778 s2 = s;
1779 s++;
1780 while (isalnum(*s) || *s == '_') s++;
1782 if (isspace(*s))
1784 *s = '\0';
1785 do {
1786 s++;
1787 } while (isspace(*s));
1790 if (*s != '\0')
1791 exitfileerror(20, "syntax is '.function name'\n");
1793 if (*methlistptr == NULL)
1794 exitfileerror(20, ".function has to come after a function declaration\n");
1796 funcsetinternalname(*methlistptr, s2);
1798 else if (strncmp(s, "interface", 9) == 0)
1800 if (cl->classtype != HIDD)
1801 exitfileerror(20, "interface only valid for a HIDD\n");
1803 s += 9;
1805 if (!isspace(*s))
1806 exitfileerror(20, "Syntax error\n");
1808 while (isspace(*s)) s++;
1809 if (*s == '\0' || !isalpha(*s))
1810 exitfileerror(20, "syntax is '.interface name'\n");
1812 s2 = s;
1813 s++;
1814 while (isalnum(*s) || *s == '_') s++;
1816 if (isspace(*s))
1818 *s = '\0';
1819 do {
1820 s++;
1821 } while (isspace(*s));
1824 if (*s != '\0')
1825 exitfileerror(20, "syntax is '.interface name'\n");
1827 interface = slist_append(&cl->interfaces, s2);
1829 else
1830 exitfileerror(20, "Syntax error");
1832 else if (isalpha(*line))
1834 char stmp[256];
1836 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
1839 if (cl->classtype == HIDD && interface == NULL)
1840 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
1842 if (*s != '\0')
1843 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
1845 if (*methlistptr != NULL)
1846 methlistptr = &((*methlistptr)->next);
1847 if (cl->classtype != HIDD)
1849 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
1850 exitfileerror(20, "Method name too large\n");
1852 *methlistptr = newfunctionhead(stmp, STACK);
1853 (*methlistptr)->type = "IPTR";
1854 funcaddarg(*methlistptr, "Class *cl", NULL);
1855 funcaddarg(*methlistptr, "Object *o", NULL);
1856 funcaddarg(*methlistptr, "Msg msg", NULL);
1858 else
1860 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
1861 exitfileerror(20, "Method name too large\n");
1863 *methlistptr = newfunctionhead(stmp, STACK);
1864 (*methlistptr)->type = "IPTR";
1865 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
1866 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
1867 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
1868 (*methlistptr)->interface = interface;
1869 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
1870 exitfileerror(20, "Method name too large\n");
1871 (*methlistptr)->method = strdup(stmp);
1873 slist_append(&(*methlistptr)->aliases, line);
1875 else
1876 exitfileerror(20, "Methodname has to begin with a letter\n");
1880 static void
1881 readsectionclass(struct config *cfg)
1883 char *s;
1884 struct classinfo *cl;
1886 cl = newclass(cfg);
1887 s = readsections(cfg, cl, 1);
1888 if (s == NULL)
1889 exitfileerror(20, "Unexpected end of file\n");
1891 if (strncmp(s, "##", 2) != 0)
1892 exitfileerror(20, "'##end class' expected\n");
1893 s += 2;
1895 while (isspace(*s)) s++;
1897 if (strncmp(s, "end", 3) != 0)
1898 exitfileerror(20, "'##end class' expected\n");
1899 s += 3;
1901 if (!isspace(*s))
1902 exitfileerror(20, "'##end class' expected\n");
1903 while (isspace(*s)) s++;
1905 if (strncmp(s, "class", 5) != 0)
1906 exitfileerror(20, "'##end class' expected\n");
1907 s += 5;
1909 while (isspace(*s)) s++;
1910 if (*s != '\0')
1911 exitfileerror(20, "'##end class' expected\n");
1914 static struct classinfo *newclass(struct config *cfg)
1916 struct classinfo *cl, *classlistit;
1918 cl = malloc(sizeof(struct classinfo));
1919 if (cl == NULL)
1921 fprintf(stderr, "Out of memory\n");
1922 exit(20);
1924 memset(cl, 0, sizeof(struct classinfo));
1926 /* By default the classes are initialized with a priority of 1 so they
1927 * are initialized before any user added initialization with priority 1
1929 cl->initpri = 1;
1931 if (cfg->classlist == NULL)
1932 cfg->classlist = cl;
1933 else
1937 classlistit = cfg->classlist;
1938 classlistit->next != NULL;
1939 classlistit = classlistit->next
1942 classlistit->next = cl;
1945 return cl;
1948 static struct handlerinfo *newhandler(struct config *cfg)
1950 struct handlerinfo *hl;
1952 hl = calloc(1,sizeof(*hl));
1953 hl->next = cfg->handlerlist;
1954 cfg->handlerlist = hl;
1955 return hl;
1958 static int getdirective(char *s, const char *directive, int range_min, int range_max, int *val)
1960 char *tmp;
1961 int newval;
1963 if (strncmp(s, directive, strlen(directive)) != 0)
1964 return 0;
1966 s += strlen(directive);
1967 if (*s && !isspace(*s))
1968 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive);
1970 while (isspace(*s)) s++;
1971 if (!*s)
1972 exitfileerror(20, "No .%s value specified\n", directive);
1974 newval = strtol(s, &tmp, 0);
1975 if (s == tmp || !(newval >= range_min && newval <= range_max)) {
1976 tmp = s;
1977 while (*tmp && !isspace(*tmp)) tmp++;
1978 exitfileerror(20, "Invalid .%s value of %.*s\n", directive, tmp - s, s);
1981 *val = newval;
1982 return 1;
1985 static void
1986 readsectionhandler(struct config *cfg)
1988 char *line = NULL, *s;
1989 struct handlerinfo *hl;
1990 unsigned char autolevel = 0;
1991 unsigned int stacksize;
1992 char priority;
1994 for (;;)
1996 char *function;
1997 int function_len;
1998 char *tmp;
2000 /* Defaults */
2001 stacksize = 0;
2002 priority = 10;
2004 s = line = readline();
2006 if (s==NULL)
2007 exitfileerror(20, "unexpected end of file in section hanlder\n");
2009 if (strncmp(s, "##", 2)==0)
2010 break;
2012 /* Ignore comments */
2013 if (strncmp(s, "#", 1)==0)
2014 continue;
2016 /* Skip ahead to function name */
2017 while (*s && isspace(*s)) s++;
2019 /* Permit blank lines */
2020 if (!*s)
2021 continue;
2023 if (*s == '.') {
2024 int val;
2025 s++;
2027 if (getdirective(s, "autodetect", 0, 127, &val)) {
2028 autolevel = val;
2029 } else if (getdirective(s, "stacksize", 0, INT_MAX, &val)) {
2030 stacksize = val;
2031 } else if (getdirective(s, "priority", -128, 127, &val)) {
2032 priority = val;
2033 } else {
2034 exitfileerror(20, "Unrecognized directive \"%s\"\n", line);
2036 continue;
2039 function = s;
2040 while (*s && !isspace(*s)) s++;
2041 function_len = s - function;
2043 if (!*s)
2044 exitfileerror(20, "No identifier specified for the handler");
2046 function[function_len] = 0;
2047 s++;
2049 do {
2050 unsigned int id = 0;
2052 if (strncasecmp(s,"resident=",9)==0) {
2053 char *res;
2055 s = strchr(s, '=') + 1;
2056 res = s;
2057 while (*s && !isspace(*s)) s++;
2058 if (res == s)
2059 exitfileerror(20, "Empty resident= is not permitted\n");
2061 if (*s)
2062 *(s++) = 0;
2064 hl = newhandler(cfg);
2065 hl->type = HANDLER_RESIDENT;
2066 hl->id = 0;
2067 hl->name = strdup(res);
2068 hl->autodetect = autolevel--;
2069 hl->stacksize = stacksize;
2070 hl->priority = priority;
2071 hl->handler = strdup(function);
2072 } else if (strncasecmp(s,"dosnode=",8)==0) {
2073 char *dev;
2075 s = strchr(s, '=') + 1;
2076 dev = s;
2077 while (*s && !isspace(*s)) s++;
2078 if (dev == s)
2079 exitfileerror(20, "Empty dosnode= is not permitted\n");
2081 if (*s)
2082 *(s++) = 0;
2084 hl = newhandler(cfg);
2085 hl->type = HANDLER_DOSNODE;
2086 hl->id = 0;
2087 hl->name = strdup(dev);
2088 hl->autodetect = autolevel ? autolevel-- : 0;
2089 hl->handler = strdup(function);
2090 hl->stacksize = stacksize;
2091 hl->priority = priority;
2092 } else if (strncasecmp(s,"dostype=",8) == 0) {
2093 s = strchr(s, '=') + 1;
2095 id = (unsigned int)strtoul(s, &tmp, 0);
2097 if (s == tmp) {
2098 while (*tmp && !isspace(*tmp))
2099 tmp++;
2100 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp -s), s);
2102 s = tmp;
2104 if (id == 0 || id == ~0) {
2105 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id);
2108 hl = newhandler(cfg);
2109 hl->type = HANDLER_DOSTYPE;
2110 hl->id = id;
2111 hl->name = NULL;
2112 hl->autodetect = autolevel ? autolevel-- : 0;
2113 hl->handler = strdup(function);
2114 hl->stacksize = stacksize;
2115 hl->priority = priority;
2116 } else {
2117 for (tmp = s; !isspace(*tmp); tmp++);
2118 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp - s, s);
2121 /* Advance to next ID */
2122 while (*s && isspace(*s)) s++;
2124 } while (*s);
2127 if (s == NULL)
2128 exitfileerror(20, "Unexpected end of file\n");
2130 if (strncmp(s, "##", 2) != 0)
2131 exitfileerror(20, "'##end handler' expected\n");
2132 s += 2;
2134 while (isspace(*s)) s++;
2136 if (strncmp(s, "end", 3) != 0)
2137 exitfileerror(20, "'##end handler' expected\n");
2138 s += 3;
2140 while (isspace(*s)) s++;
2142 if (strncmp(s, "handler", 7) != 0)
2143 exitfileerror(20, "'##end handler' expected\n");
2144 s += 7;
2146 while (isspace(*s)) s++;
2147 if (*s != '\0')
2148 exitfileerror(20, "'##end handler' expected\n");