Import SB128-v5.24 to main branch
[AROS.git] / tools / genmodule / config.c
blob92c3c8fcc46df89d6f290e7d32cf6b7bca661c9d
1 /*
2 Copyright © 1995-2011, 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-2011, 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:")) != -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;
107 case 's':
108 cfg->suffix = optarg;
109 hassuffix = 1;
110 break;
111 case 'd':
112 /* Remove / at end if present */
113 if ((optarg)[strlen(*argvit)-1]=='/') (optarg)[strlen(optarg)-1]='\0';
114 cfg->gendir = optarg;
115 break;
116 default:
117 fprintf(stderr, "Internal error: Unhandled option\n");
118 exit(20);
122 if (optind + 3 != argc)
124 fprintf(stderr, "Wrong number of arguments.\n%s", usage);
125 exit(20);
128 if (strcmp(argv[optind], "writefiles") == 0)
130 cfg->command = FILES;
132 else if (strcmp(argv[optind], "writemakefile") == 0)
134 cfg->command = MAKEFILE;
136 else if (strcmp(argv[optind], "writeincludes") == 0)
138 cfg->command = INCLUDES;
140 else if (strcmp(argv[optind], "writelibdefs") == 0)
142 cfg->command = LIBDEFS;
144 else if (strcmp(argv[optind], "writefunclist") == 0)
146 cfg->command = WRITEFUNCLIST;
148 else if (strcmp(argv[optind], "writefd") == 0)
150 cfg->command = WRITEFD;
152 else if (strcmp(argv[optind], "writeskel") == 0)
154 cfg->command = WRITESKEL;
156 else
158 fprintf(stderr, "Unrecognized argument \"%s\"\n%s", argv[optind], usage);
159 exit(20);
162 cfg->modulename = argv[optind+1];
163 cfg->modulenameupper = strdup(cfg->modulename);
164 for (s=cfg->modulenameupper; *s!='\0'; *s = toupper(*s), s++)
167 if (strcmp(argv[optind+2],"library")==0)
169 cfg->modtype = LIBRARY;
170 cfg->moddir = "Libs";
172 else if (strcmp(argv[optind+2],"mcc")==0)
174 cfg->modtype = MCC;
175 cfg->moddir = "Classes/Zune";
177 else if (strcmp(argv[optind+2],"mui")==0)
179 cfg->modtype = MUI;
180 cfg->moddir = "Classes/Zune";
182 else if (strcmp(argv[optind+2],"mcp")==0)
184 cfg->modtype = MCP;
185 cfg->moddir = "Classes/Zune";
187 else if (strcmp(argv[optind+2], "device")==0)
189 cfg->modtype = DEVICE;
190 cfg->moddir = "Devs";
192 else if (strcmp(argv[optind+2], "resource")==0)
194 cfg->modtype = RESOURCE;
195 cfg->moddir = "Devs";
197 else if (strcmp(argv[optind+2], "gadget")==0)
199 cfg->modtype = GADGET;
200 cfg->moddir = "Classes/Gadgets";
202 else if (strcmp(argv[optind+2], "datatype")==0)
204 cfg->modtype = DATATYPE;
205 cfg->moddir = "Classes/Datatypes";
207 else if (strcmp(argv[optind+2], "usbclass")==0)
209 cfg->modtype = USBCLASS;
210 cfg->moddir = "Classes/USB";
211 if(!hassuffix)
213 cfg->suffix = "class";
214 hassuffix = 1;
217 else if (strcmp(argv[optind+2], "hidd")==0)
219 cfg->modtype = HIDD;
220 cfg->moddir = "Devs/Drivers";
222 else if (strcmp(argv[optind+2], "handler")==0)
224 cfg->modtype = HANDLER;
225 cfg->moddir = "$(AROS_DIR_FS)";
227 else
229 fprintf(stderr, "Unknown modtype \"%s\" specified for second argument\n", argv[2]);
230 exit(20);
233 if (!hassuffix)
234 cfg->suffix = argv[optind+2];
236 /* Fill fields with default value if not specified on the command line */
238 char tmpbuf[256];
240 if (cfg->conffile == NULL)
242 snprintf(tmpbuf, sizeof(tmpbuf), "%s.conf", cfg->modulename);
243 cfg->conffile = strdup(tmpbuf);
246 if (cfg->gendir == NULL)
247 cfg->gendir = ".";
250 readconfig(cfg);
252 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
253 * if they are provided
255 if (cfg->beginiofunc != NULL)
257 struct functionhead *funchead;
259 cfg->intcfg |= CFG_NOREADFUNCS;
261 /* Add beginio_func to the list of functions */
262 funchead = newfunctionhead(cfg->beginiofunc, REGISTERMACRO);
263 funchead->type = strdup("void");
264 funchead->lvo = 5;
265 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
267 funchead->next = cfg->funclist;
268 cfg->funclist = funchead;
270 /* Add abortio_func to the list of functions */
271 funchead = newfunctionhead(cfg->abortiofunc, REGISTERMACRO);
272 funchead->type = strdup("LONG");
273 funchead->lvo = 6;
274 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
276 funchead->next = cfg->funclist->next;
277 cfg->funclist->next = funchead;
279 else if (cfg->modtype == DEVICE && cfg->intcfg & CFG_NOREADFUNCS)
281 fprintf
283 stderr,
284 "beginio_func and abortio_func missing for a device with a non empty function list\n"
286 exit(20);
289 return cfg;
292 /* Functions to read configuration from the configuration file */
294 #include "fileread.h"
296 static char *readsections(struct config *, struct classinfo *, int);
297 static void readsectionconfig(struct config *, struct classinfo *, int);
298 static void readsectioncdef(struct config *);
299 static void readsectioncdefprivate(struct config *);
300 static void readsectionstartup(struct config *);
301 static void readsectionfunctionlist(struct config *);
302 static void readsectionmethodlist(struct classinfo *);
303 static void readsectionclass(struct config *);
304 static void readsectionhandler(struct config *);
306 static void readconfig(struct config *cfg)
308 struct classinfo *mainclass = NULL;
310 /* Create a classinfo structure if this module is a class */
311 switch (cfg->modtype)
313 case LIBRARY:
314 case DEVICE:
315 case RESOURCE:
316 case USBCLASS:
317 case HANDLER:
318 break;
320 case MCC:
321 case MUI:
322 case MCP:
323 case GADGET:
324 case DATATYPE:
325 case HIDD:
326 mainclass = newclass(cfg);
327 mainclass->classtype = cfg->modtype;
328 break;
330 default:
331 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
332 exit(20);
335 switch (cfg->modtype)
337 case LIBRARY:
338 case USBCLASS:
339 cfg->firstlvo = 5;
340 break;
341 case DEVICE:
342 cfg->firstlvo = 7;
343 break;
344 case MCC:
345 case MUI:
346 case MCP:
347 cfg->firstlvo = 6;
348 mainclass->boopsimprefix = muimprefix;
349 break;
350 case HANDLER:
351 case RESOURCE:
352 cfg->firstlvo = 1;
353 break;
354 case GADGET:
355 cfg->firstlvo = 5;
356 mainclass->boopsimprefix = gadgetmprefix;
357 break;
358 case DATATYPE:
359 cfg->firstlvo = 6;
360 mainclass->boopsimprefix = dtmprefix;
361 break;
362 case HIDD:
363 cfg->firstlvo = 5;
364 /* FIXME: need boopsimprefix ? */
365 break;
366 default:
367 fprintf(stderr, "Internal error: unsupported modtype for firstlvo\n");
368 exit(20);
371 if (!fileopen(cfg->conffile))
373 fprintf(stderr, "In readconfig: Could not open %s\n", cfg->conffile);
374 exit(20);
377 /* Read all sections and see that we are at the end of the file */
378 if (readsections(cfg, mainclass, 0) != NULL)
379 exitfileerror(20, "Syntax error");
381 fileclose();
384 /* readsections will scan through all the sections in the config file.
385 * arguments:
386 * struct config *cfg: The module config data which may be updated by
387 * the information in the sections
388 * struct classinfo *cl: The classdata to be filled with data from the sections.
389 * This may be NULL if this is the main part of the configuration file and the
390 * type of the module is not a class
391 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
392 * part of the config file.
394 static char *readsections(struct config *cfg, struct classinfo *cl, int inclass)
396 char *line, *s, *s2;
397 int hasconfig = 0;
399 while ((line=readline())!=NULL)
401 if (strncmp(line, "##", 2)==0)
403 static char *parts[] =
405 "config", "cdefprivate", "cdef", "startup", "functionlist", "methodlist", "class", "handler",
407 const unsigned int nums = sizeof(parts)/sizeof(char *);
408 unsigned int partnum;
409 int i, atend = 0;
411 s = line+2;
412 while (isspace(*s)) s++;
414 if (strncmp(s, "begin", 5)!=0)
415 return line;
417 s += 5;
418 if (!isspace(*s))
419 exitfileerror(20, "space after begin expected\n");
420 while (isspace(*s)) s++;
422 for (i = 0, partnum = 0; partnum==0 && i<nums; i++)
424 if (strncmp(s, parts[i], strlen(parts[i]))==0)
426 partnum = i+1;
427 s += strlen(parts[i]);
428 while (isspace(*s)) s++;
429 if (*s!='\0')
430 exitfileerror(20, "unexpected character on position %d\n", s-line);
433 if (partnum==0)
434 exitfileerror(20, "unknown start of section\n");
435 switch (partnum)
437 case 1: /* config */
438 readsectionconfig(cfg, cl, inclass);
439 hasconfig = 1;
440 break;
442 case 2: /* cdefprivate */
443 if (inclass)
444 exitfileerror(20, "cdefprivate section not allowed in class section\n");
445 readsectioncdefprivate(cfg);
446 break;
448 case 3: /* cdef */
449 if (inclass)
450 exitfileerror(20, "cdef section not allowed in class section\n");
451 readsectioncdef(cfg);
452 break;
454 case 4: /* startup */
455 if (inclass)
456 exitfileerror(20, "startup section not allowed in class section\n");
457 readsectionstartup(cfg);
458 break;
460 case 5: /* functionlist */
461 if (inclass)
462 exitfileerror(20, "functionlist section not allow in class section\n");
463 readsectionfunctionlist(cfg);
464 cfg->intcfg |= CFG_NOREADFUNCS;
465 break;
467 case 6: /* methodlist */
468 if (cl == NULL)
469 exitfileerror(20, "methodlist section when not in a class\n");
470 readsectionmethodlist(cl);
471 cfg->intcfg |= CFG_NOREADFUNCS;
472 break;
474 case 7: /* class */
475 if (inclass)
476 exitfileerror(20, "class section may not be nested\n");
477 readsectionclass(cfg);
478 break;
479 case 8: /* handler */
480 readsectionhandler(cfg);
481 break;
484 else if (strlen(line)!=0)
485 filewarning("warning line outside section ignored\n");
488 if(!inclass)
490 if (!hasconfig)
491 exitfileerror(20, "No config section in conffile\n");
493 /* If no indication was given for generating includes or not
494 decide on module type and if there are functions
496 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
498 switch (cfg->modtype)
500 case LIBRARY:
501 case RESOURCE:
502 cfg->options |= OPTION_INCLUDES;
503 break;
505 case HANDLER:
506 case MCC:
507 case MUI:
508 case MCP:
509 case USBCLASS:
510 cfg->options |= OPTION_NOINCLUDES;
511 break;
513 case DEVICE:
514 cfg->options |= (
515 (cfg->funclist != NULL)
516 || (cfg->cdeflines != NULL)
517 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
518 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
519 break;
521 case GADGET:
522 case DATATYPE:
523 case HIDD:
524 cfg->options |= (
525 (cfg->funclist != NULL)
526 || (cfg->cdeflines != NULL)
527 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
528 break;
530 default:
531 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
532 exit(20);
533 break;
537 /* If no indication was given for not generating stubs only generate them if
538 * the module has functions
540 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
542 switch (cfg->modtype)
544 case LIBRARY:
545 cfg->options |= (cfg->funclist != NULL) ? OPTION_STUBS : OPTION_NOSTUBS;
546 break;
548 case USBCLASS:
549 case RESOURCE:
550 case GADGET:
551 case DEVICE:
552 case DATATYPE:
553 case MCC:
554 case MUI:
555 case MCP:
556 case HIDD:
557 case HANDLER:
558 cfg->options |= OPTION_NOSTUBS;
559 break;
561 default:
562 fprintf(stderr, "Internal error writemakefile: unhandled modtype for stubs\n");
563 exit(20);
564 break;
568 /* If no indication was given for generating autoinit code or not
569 decide on module type
571 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
573 switch (cfg->modtype)
575 case LIBRARY:
576 cfg->options |= OPTION_AUTOINIT;
577 break;
579 case USBCLASS:
580 case RESOURCE:
581 case GADGET:
582 case DEVICE:
583 case DATATYPE:
584 case MCC:
585 case MUI:
586 case MCP:
587 case HIDD:
588 case HANDLER:
589 cfg->options |= OPTION_NOAUTOINIT;
590 break;
592 default:
593 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
594 exit(20);
595 break;
599 if ((cfg->modtype == RESOURCE) || (cfg->modtype == HANDLER))
600 /* Enforce noopenclose for resources and handlers */
601 cfg->options |= OPTION_NOOPENCLOSE;
602 else if (!(cfg->options & OPTION_SELFINIT))
603 /* Enforce using RTF_AUTOINIT for everything except resources */
604 cfg->options |= OPTION_RESAUTOINIT;
607 return NULL;
610 static void readsectionconfig(struct config *cfg, struct classinfo *cl, int inclass)
612 int atend = 0, i;
613 char *line, *s, *s2, *libbasetypeextern = NULL;
614 struct tm date;
616 while (!atend)
618 line = readline();
619 if (line==NULL)
620 exitfileerror(20, "unexpected end of file in section config\n");
622 if (strncmp(line, "##", 2)!=0)
624 const char *names[] =
626 "basename", "libbase", "libbasetype", "libbasetypeextern",
627 "version", "date", "copyright", "libcall", "forcebase", "superclass",
628 "superclass_field", "residentpri", "options", "sysbase_field",
629 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
630 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
631 "initpri", "type", "getidfunc", "addromtag"
633 const unsigned int namenums = sizeof(names)/sizeof(char *);
634 unsigned int namenum;
636 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
640 strncmp(line, names[i], strlen(names[i]))==0
641 && isspace(*(line+strlen(names[i])))
643 namenum = i+1;
645 if (namenum==0)
646 exitfileerror(20, "unrecognized configuration option\n");
648 s = line + strlen(names[namenum-1]);
649 if (!isspace(*s))
650 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
652 while (isspace(*s)) s++;
653 if (*s=='\0')
654 exitfileerror(20, "unexpected end of line\n");
656 s2 = s + strlen(s);
657 while (isspace(*(s2-1))) s2--;
658 *s2 = '\0';
660 switch (namenum)
662 case 1: /* basename */
663 if (!inclass)
664 cfg->basename = strdup(s);
665 if (cl != NULL)
666 cl->basename = strdup(s);
667 break;
669 case 2: /* libbase */
670 if (inclass)
671 exitfileerror(20, "libbase not valid config option when in a class section\n");
672 cfg->libbase = strdup(s);
673 break;
675 case 3: /* libbasetype */
676 if (inclass)
677 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
678 cfg->libbasetype = strdup(s);
679 break;
681 case 4: /* libbasetypeextern */
682 if (inclass)
683 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
684 libbasetypeextern = strdup(s);
685 break;
687 case 5: /* version */
688 if (inclass)
689 exitfileerror(20, "version not valid config option when in a class section\n");
690 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
691 exitfileerror(20, "wrong version string \"%s\"\n", s);
692 break;
694 case 6: /* date */
695 if (inclass)
696 exitfileerror(20, "date not valid config option when in a class section\n");
697 #ifndef _WIN32
698 if (strptime(s, "%e.%m.%Y", &date) == NULL)
700 exitfileerror(20, "date string has to have d.m.yyyy format\n");
702 #endif
703 cfg->datestring = strdup(s);
704 break;
706 case 7: /* copyright */
707 if (inclass)
708 exitfileerror(20, "copyright not valid config option when in a class section\n");
709 cfg->copyright = strdup(s);
710 break;
712 case 8: /* libcall */
713 fprintf(stderr, "libcall specification is deprecated and ignored\n");
714 break;
716 case 9: /* forcebase */
717 if (inclass)
718 exitfileerror(20, "forcebase not valid config option when in a class section\n");
719 slist_append(&cfg->forcelist, s);
720 break;
722 case 10: /* superclass */
723 if (cl == NULL)
724 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
725 cl->superclass = strdup(s);
726 break;
728 case 11: /* superclass_field */
729 if (cl == NULL)
730 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
731 cl->superclass_field = strdup(s);
732 break;
734 case 12: /* residentpri */
735 if (!inclass)
737 int count;
738 char dummy;
740 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
741 if (count != 1 ||
742 cfg->residentpri < -128 || cfg->residentpri > 127
745 exitfileerror(20, "residentpri number format error\n");
748 else
749 exitfileerror(20, "residentpri not valid config option when in a class section\n");
750 break;
752 case 13: /* options */
753 if (!inclass)
755 static const char *optionnames[] =
757 "noautolib", "noexpunge", "noresident", "peropenerbase",
758 "peridbase", "includes", "noincludes", "nostubs",
759 "autoinit", "noautoinit", "resautoinit", "noopenclose",
760 "selfinit"
762 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
763 int optionnum;
767 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
769 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
771 optionnum = i + 1;
772 s += strlen(optionnames[i]);
773 while (isspace(*s)) s++;
774 if (*s == ',')
775 s++;
776 else if (*s != '\0')
777 exitfileerror(20, "Unrecognized option\n");
780 if (optionnum == 0)
781 exitfileerror(20, "Unrecognized option\n");
782 switch (optionnum)
784 case 1: /* noautolib */
785 cfg->options |= OPTION_NOAUTOLIB;
786 break;
787 case 2: /* noexpunge */
788 cfg->options |= OPTION_NOEXPUNGE;
789 break;
790 case 3: /* noresident */
791 cfg->options |= OPTION_NORESIDENT;
792 cfg->firstlvo = 1;
793 break;
794 case 5: /* peridbase */
795 cfg->options |= OPTION_DUPPERID;
796 /* Fall through */
797 case 4: /* peropenerbase */
798 if (cfg->options & OPTION_DUPBASE)
799 exitfileerror(20, "Only one option peropenerbase or peridbase allowed\n");
800 cfg->options |= OPTION_DUPBASE;
801 break;
802 case 6: /* includes */
803 if (cfg->options & OPTION_NOINCLUDES)
804 exitfileerror(20, "option includes and noincludes are incompatible\n");
805 cfg->options |= OPTION_INCLUDES;
806 break;
807 case 7: /* noincludes */
808 if (cfg->options & OPTION_INCLUDES)
809 exitfileerror(20, "option includes and noincludes are incompatible\n");
810 cfg->options |= OPTION_NOINCLUDES;
811 break;
812 case 8: /* nostubs */
813 cfg->options |= OPTION_NOSTUBS;
814 break;
815 case 9: /* autoinit */
816 if (cfg->options & OPTION_NOAUTOINIT)
817 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
818 cfg->options |= OPTION_AUTOINIT;
819 break;
820 case 10: /* noautoinit */
821 if (cfg->options & OPTION_AUTOINIT)
822 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
823 cfg->options |= OPTION_NOAUTOINIT;
824 break;
825 case 11: /* resautoinit */
826 if (cfg->options & OPTION_SELFINIT)
827 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
828 cfg->options |= OPTION_RESAUTOINIT;
829 break;
830 case 12:
831 cfg->options |= OPTION_NOOPENCLOSE;
832 break;
833 case 13: /* noresautoinit */
834 if (cfg->options & OPTION_RESAUTOINIT)
835 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
836 cfg->options |= OPTION_SELFINIT;
837 break;
839 while (isspace(*s)) s++;
840 } while(*s !='\0');
842 else
844 static const char *optionnames[] =
846 "private"
848 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
849 int optionnum;
853 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
855 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
857 optionnum = i + 1;
858 s += strlen(optionnames[i]);
859 while (isspace(*s)) s++;
860 if (*s == ',')
861 s++;
862 else if (*s != '\0')
863 exitfileerror(20, "Unrecognized option\n");
866 if (optionnum == 0)
867 exitfileerror(20, "Unrecognized option\n");
868 switch (optionnum)
870 case 1: /* private */
871 cl->options |= COPTION_PRIVATE;
872 break;
874 while (isspace(*s)) s++;
875 } while(*s !='\0');
877 break;
879 case 14: /* sysbase_field */
880 if (inclass)
881 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
882 cfg->sysbase_field = strdup(s);
883 break;
885 case 15: /* seglist_field */
886 if (inclass)
887 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
888 cfg->seglist_field = strdup(s);
889 break;
891 case 16: /* rootbase_field */
892 if (inclass)
893 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
894 cfg->rootbase_field = strdup(s);
895 break;
897 case 17: /* classptr_field */
898 if (cl == NULL)
900 exitfileerror
903 "classptr_field specified when not a BOOPSI class\n"
906 cl->classptr_field = strdup(s);
907 break;
909 case 18: /* classptr_var */
910 if (cl == NULL)
912 exitfileerror
915 "classptr_var specified when not a BOOPSI class\n"
918 cl->classptr_var = strdup(s);
919 break;
921 case 19: /* classid */
922 if (cl == NULL)
923 exitfileerror(20, "classid specified when not a BOOPSI class\n");
924 if (cl->classid != NULL)
925 exitfileerror(20, "classid specified twice\n");
926 cl->classid = strdup(s);
927 if (strcmp(cl->classid, "NULL") == 0)
928 cl->options |= COPTION_PRIVATE;
929 break;
931 case 20: /* classdatatype */
932 if (cl == NULL)
933 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
934 cl->classdatatype = strdup(s);
935 break;
937 case 21: /* beginio_func */
938 if (inclass)
939 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
940 if (cfg->modtype != DEVICE)
941 exitfileerror(20, "beginio_func specified when not a device\n");
942 cfg->beginiofunc = strdup(s);
943 break;
945 case 22: /* abortio_func */
946 if (inclass)
947 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
948 if (cfg->modtype != DEVICE)
949 exitfileerror(20, "abortio_func specified when not a device\n");
950 cfg->abortiofunc = strdup(s);
951 break;
953 case 23: /* dispatcher */
954 if (cl == NULL)
955 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
956 cl->dispatcher = strdup(s);
957 /* function references are not needed when dispatcher is specified */
958 cfg->intcfg |= CFG_NOREADFUNCS;
959 break;
961 case 24: /* initpri */
962 if (cl != NULL)
964 int count;
965 char dummy;
967 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
968 if (count != 1 ||
969 cl->initpri < -128 || cl->initpri > 127
972 exitfileerror(20, "initpri number format error\n");
975 else
976 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
977 break;
979 case 25: /* type */
980 if (!inclass)
981 exitfileerror(20, "type only valid config option in a class section\n");
982 if (strcmp(s,"mcc")==0)
983 cl->classtype = MCC;
984 else if (strcmp(s,"mui")==0)
985 cl->classtype = MUI;
986 else if (strcmp(s,"mcp")==0)
987 cl->classtype = MCP;
988 else if (strcmp(s, "image")==0)
989 cl->classtype = IMAGE;
990 else if (strcmp(s, "gadget")==0)
991 cl->classtype = GADGET;
992 else if (strcmp(s, "datatype")==0)
993 cl->classtype = DATATYPE;
994 else if (strcmp(s, "usbclass")==0)
995 cl->classtype = USBCLASS;
996 else if (strcmp(s, "class")==0)
997 cl->classtype = CLASS;
998 else if (strcmp(s, "hidd")==0)
999 cl->classtype = HIDD;
1000 else
1002 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
1003 exit(20);
1005 break;
1006 case 26: /* getidfunc */
1007 cfg->getidfunc = strdup(s);
1008 break;
1010 case 27: /* addromtag */
1011 cfg->addromtag = strdup(s);
1012 break;
1015 else /* Line starts with ## */
1017 s = line+2;
1018 while (isspace(*s)) s++;
1019 if (strncmp(s, "end", 3)!=0)
1020 exitfileerror(20, "\"##end config\" expected\n");
1022 s += 3;
1023 if (!isspace(*s))
1024 exitfileerror(20, "\"##end config\" expected\n");
1026 while (isspace(*s)) s++;
1027 if (strncmp(s, "config", 6)!=0)
1028 exitfileerror(20, "\"##end config\" expected\n");
1030 s += 6;
1031 while (isspace(*s)) s++;
1032 if (*s!='\0')
1033 exitfileerror(20, "\"##end config\" expected\n");
1035 atend = 1;
1039 /* When not in a class section fill in default values for fields in cfg */
1040 if (!inclass)
1042 if (cfg->basename==NULL)
1044 cfg->basename = strdup(cfg->modulename);
1045 *cfg->basename = toupper(*cfg->basename);
1047 if (cfg->libbase==NULL)
1049 unsigned int len = strlen(cfg->basename)+5;
1050 cfg->libbase = malloc(len);
1051 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1053 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1054 cfg->libbasetype = strdup(libbasetypeextern);
1055 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1056 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1057 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1058 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1059 /* rootbase_field only allowed when duplicating base */
1060 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1061 exitfileerror(20, "rootbasefield only valid for option peropenerbase or peridbase\n");
1062 if (cfg->getidfunc != NULL && !(cfg->options & OPTION_DUPPERID))
1063 exitfileerror(20, "getidfunc only valid for option peridbase\n");
1065 /* Set default date to current date */
1066 if (cfg->datestring == NULL)
1068 char tmpbuf[256];
1069 time_t now = time(NULL);
1070 struct tm *ltime = localtime(&now);
1072 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1073 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1075 cfg->datestring = strdup(tmpbuf);
1078 if (cfg->copyright == NULL)
1079 cfg->copyright = "";
1081 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1082 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1084 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1086 if (libbasetypeextern==NULL)
1088 switch (cfg->modtype)
1090 case DEVICE:
1091 cfg->libbasetypeptrextern = "struct Device *";
1092 break;
1093 case HANDLER:
1094 case RESOURCE:
1095 cfg->libbasetypeptrextern = "APTR ";
1096 break;
1097 case LIBRARY:
1098 case MUI:
1099 case MCP:
1100 case MCC:
1101 case GADGET:
1102 case DATATYPE:
1103 case USBCLASS:
1104 case HIDD:
1105 cfg->libbasetypeptrextern = "struct Library *";
1106 break;
1107 default:
1108 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1109 exit(20);
1112 else
1114 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1115 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1116 strcat(cfg->libbasetypeptrextern, " *");
1117 free(libbasetypeextern);
1121 /* When class was given too fill in some defaults when not specified */
1122 if (cl != NULL)
1124 if (cl->classtype == UNSPECIFIED)
1125 cl->classtype = CLASS;
1127 if (cl->basename == NULL)
1129 if (!inclass)
1130 cl->basename = cfg->basename;
1131 else
1132 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1135 /* MUI classes are always private */
1136 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1137 cl->options |= COPTION_PRIVATE;
1139 if (cl->classid == NULL
1140 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1143 if (cl->classtype == HIDD)
1145 cl->options &= !COPTION_PRIVATE;
1147 else if (cl->options & COPTION_PRIVATE)
1149 cl->classid = "NULL";
1151 else
1153 char s[256] = "";
1155 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1157 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1159 else if (cl->classtype == DATATYPE)
1161 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1163 cl->classid = strdup(s);
1167 /* Only specify superclass or superclass_field */
1168 if (cl->superclass != NULL && cl->superclass_field != NULL)
1169 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1171 /* Give default value to superclass if it is not specified */
1172 if (cl->superclass == NULL && cl->superclass == NULL)
1174 switch (cl->classtype)
1176 case MUI:
1177 case MCC:
1178 cl->superclass = "MUIC_Area";
1179 break;
1180 case MCP:
1181 cl->superclass = "MUIC_Mccprefs";
1182 break;
1183 case IMAGE:
1184 cl->superclass = "IMAGECLASS";
1185 break;
1186 case GADGET:
1187 cl->superclass = "GADGETCLASS";
1188 break;
1189 case DATATYPE:
1190 cl->superclass = "DATATYPESCLASS";
1191 break;
1192 case CLASS:
1193 cl->superclass = "ROOTCLASS";
1194 break;
1195 case HIDD:
1196 cl->superclass = "CLID_Root";
1197 break;
1198 default:
1199 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1200 break;
1206 static void readsectioncdef(struct config *cfg)
1208 int atend = 0;
1209 char *line, *s;
1211 while (!atend)
1213 line = readline();
1214 if (line==NULL)
1215 exitfileerror(20, "unexptected end of file in section cdef\n");
1217 if (strncmp(line, "##", 2)!=0)
1219 slist_append(&cfg->cdeflines, line);
1221 else
1223 s = line+2;
1224 while (isspace(*s)) s++;
1225 if (strncmp(s, "end", 3)!=0)
1226 exitfileerror(20, "\"##end cdef\" expected\n");
1228 s += 3;
1229 while (isspace(*s)) s++;
1230 if (strncmp(s, "cdef", 4)!=0)
1231 exitfileerror(20, "\"##end cdef\" expected\n");
1233 s += 5;
1234 while (isspace(*s)) s++;
1235 if (*s!='\0')
1236 exitfileerror(20, "unexpected character at position %d\n");
1238 atend = 1;
1243 static void readsectioncdefprivate(struct config *cfg)
1245 int atend = 0;
1246 char *line, *s;
1248 while (!atend)
1250 line = readline();
1251 if (line==NULL)
1252 exitfileerror(20, "unexptected end of file in section cdef\n");
1254 if (strncmp(line, "##", 2)!=0)
1256 slist_append(&cfg->cdefprivatelines, line);
1258 else
1260 s = line+2;
1261 while (isspace(*s)) s++;
1262 if (strncmp(s, "end", 3)!=0)
1263 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1265 s += 3;
1266 while (isspace(*s)) s++;
1267 if (strncmp(s, "cdefprivate", 11)!=0)
1268 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1270 s += 11;
1271 while (isspace(*s)) s++;
1272 if (*s!='\0')
1273 exitfileerror(20, "unexpected character at position %d\n");
1275 atend = 1;
1280 static void readsectionstartup(struct config *cfg)
1282 int atend = 0;
1283 char *line, *s;
1285 while (!atend)
1287 line = readline();
1288 if (line==NULL)
1289 exitfileerror(20, "unexptected end of file in section startup\n");
1291 if (strncmp(line, "##", 2)!=0)
1293 slist_append(&cfg->startuplines, line);
1295 else
1297 s = line+2;
1298 while (isspace(*s)) s++;
1299 if (strncmp(s, "end", 3)!=0)
1300 exitfileerror(20, "\"##end startup\" expected\n");
1302 s += 3;
1303 while (isspace(*s)) s++;
1304 if (strncmp(s, "startup", 7)!=0)
1305 exitfileerror(20, "\"##end startup\" expected\n");
1307 s += 7;
1308 while (isspace(*s)) s++;
1309 if (*s!='\0')
1310 exitfileerror(20, "unexpected character at position %d\n");
1312 atend = 1;
1317 static void readsectionfunctionlist(struct config *cfg)
1319 int atend = 0, i;
1320 char *line, *s, *s2;
1321 unsigned int lvo = cfg->firstlvo;
1322 int minversion = 0;
1323 struct functionhead **funclistptr = &cfg->funclist;
1325 if (cfg->basename==NULL)
1326 exitfileerror(20, "section functionlist has to come after section config\n");
1328 while (!atend)
1330 line = readline();
1331 if (line==NULL)
1332 exitfileerror(20, "unexptected EOF in functionlist section\n");
1333 if (strlen(line)==0)
1335 if (*funclistptr != NULL)
1336 funclistptr = &((*funclistptr)->next);
1337 lvo++;
1339 else if (isspace(*line))
1341 s = line;
1342 while (isspace(*s)) s++;
1343 if (*s=='\0')
1345 if (*funclistptr != NULL)
1346 funclistptr = &((*funclistptr)->next);
1347 lvo++;
1349 else
1350 exitfileerror(20, "no space allowed before functionname\n");
1352 else if (strncmp(line, "##", 2)==0)
1354 s = line+2;
1355 while (isspace(*s)) s++;
1356 if (strncmp(s, "end", 3)!=0)
1357 exitfileerror(20, "\"##end functionlist\" expected\n");
1359 s += 3;
1360 while (isspace(*s)) s++;
1361 if (strncmp(s, "functionlist", 12)!=0)
1362 exitfileerror(20, "\"##end functionlist\" expected\n");
1364 s += 12;
1365 while (isspace(*s)) s++;
1366 if (*s!='\0')
1367 exitfileerror(20, "unexpected character on position %d\n", s-line);
1369 atend = 1;
1371 else if (*line=='.')
1373 s = line+1;
1374 if (strncmp(s, "skip", 4)==0)
1376 int n;
1378 s += 4;
1379 if (!isspace(*s))
1380 exitfileerror(20, "syntax is '.skip n'\n");
1382 n=strtol(s, &s2, 10);
1383 if (s2==NULL)
1384 exitfileerror(20, "positive number expected\n");
1386 while (isspace(*s2)) s2++;
1387 if ((*s2 != '\0') && (*s2 != '#'))
1388 exitfileerror(20, "syntax is '.skip n'\n");
1389 if (*funclistptr != NULL)
1390 funclistptr = &((*funclistptr)->next);
1391 lvo += n;
1393 else if (strncmp(s, "alias", 5)==0)
1395 s += 5;
1397 if (!isspace(*s))
1398 exitfileerror(20, "syntax is '.alias name'\n");
1400 while (isspace(*s)) s++;
1401 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1402 exitfileerror(20, "syntax is '.alias name'\n");
1404 s2 = s;
1405 s++;
1406 while (isalnum(*s) || *s == '_') s++;
1408 if (isspace(*s))
1410 *s = '\0';
1411 do {
1412 s++;
1413 } while (isspace(*s));
1416 if (*s != '\0')
1417 exitfileerror(20, "syntax is '.alias name'\n");
1419 if (*funclistptr == NULL)
1420 exitfileerror(20, ".alias has to come after a function declaration\n");
1422 slist_append(&(*funclistptr)->aliases, s2);
1424 else if (strncmp(s, "function", 8) == 0)
1426 s += 8;
1428 if (!isspace(*s))
1429 exitfileerror(20, "Syntax error\n");
1431 while (isspace(*s)) s++;
1432 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1433 exitfileerror(20, "syntax is '.function name'\n");
1435 s2 = s;
1436 s++;
1437 while (isalnum(*s) || *s == '_') s++;
1439 if (isspace(*s))
1441 *s = '\0';
1442 do {
1443 s++;
1444 } while (isspace(*s));
1447 if (*s != '\0')
1448 exitfileerror(20, "syntax is '.function name'\n");
1450 if (*funclistptr == NULL)
1451 exitfileerror(20, ".function has to come after a function declaration\n");
1453 funcsetinternalname(*funclistptr, s2);
1455 else if (strncmp(s, "cfunction", 9)==0)
1457 if (*funclistptr == NULL)
1458 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1460 (*funclistptr)->libcall = REGISTER;
1462 else if (strncmp(s, "private", 7)==0)
1464 if (*funclistptr == NULL)
1465 exitfileerror(20, ".private has to come after a function declaration\n");
1467 (*funclistptr)->priv = 1;
1469 else if (strncmp(s, "novararg", 8)==0)
1471 if (*funclistptr == NULL)
1472 exitfileerror(20, ".novararg has to come after a function declaration\n");
1474 (*funclistptr)->novararg = 1;
1476 else if (strncmp(s, "version", 7) == 0)
1478 /* Mark version number for the following
1479 * functions, so that the automatic OpenLibrary()
1480 * will know what version to use.
1482 char *tmp;
1483 int ver;
1485 s += 7;
1487 while (isspace(*s)) s++;
1488 ver = (int)strtol(s, &tmp, 0);
1490 if (s == tmp)
1491 exitfileerror(20, ".version expects an integer\n");
1493 s = tmp;
1494 while (isspace(*s)) s++;
1496 if (*s && *s != '#')
1497 exitfileerror(20, ".version has junk after the version number\n");
1499 minversion = ver;
1501 else
1502 exitfileerror(20, "Syntax error");
1504 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1506 /* The line is a function prototype. It can have two syntax
1507 * type funcname(argproto1, argproto2, ...)
1508 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1509 * The former is for C type function argument passing, the latter for
1510 * register argument passing.
1512 char c, *args[64], *regs[64], *funcname;
1513 int len, argcount = 0, regcount = 0, brcount = 0;
1515 /* Parse 'type functionname' at the beginning of the line */
1516 s = strchr(line, '(');
1517 if (s == NULL)
1518 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1520 s2 = s;
1521 while (isspace(*(s2-1)))
1522 s2--;
1523 *s2 = '\0';
1525 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1526 s2--;
1528 if (s2 == line)
1529 exitfileerror(20, "No type specifier before function name\n");
1531 if (*funclistptr != NULL)
1532 funclistptr = &((*funclistptr)->next);
1533 *funclistptr = newfunctionhead(s2, STACK);
1535 while (isspace(*(s2-1)))
1536 s2--;
1537 *s2 = '\0';
1538 (*funclistptr)->type = strdup(line);
1539 (*funclistptr)->lvo = lvo;
1540 (*funclistptr)->version = minversion;
1541 lvo++;
1543 /* Parse function prototype */
1544 s++;
1545 while (isspace(*s))
1546 s++;
1547 c = *s;
1549 while (c != ')')
1551 while (isspace(*s))
1552 s++;
1554 args[argcount] = s;
1555 argcount++;
1557 while
1559 *s != '\0'
1560 && !(brcount == 0 && (*s == ',' || *s == ')'))
1563 if (*s == '(')
1564 brcount++;
1565 if (*s == ')')
1567 if (brcount > 0)
1568 brcount--;
1569 else
1570 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1572 s++;
1575 c = *s;
1576 if (c == '\0')
1577 exitfileerror(20, "'(' without ')'");
1579 s2 = s;
1580 while (isspace(*(s2-1)))
1581 s2--;
1582 *s2 = '\0';
1584 if (!(s2 > args[argcount - 1]))
1585 exitfileerror(20, "Syntax error in function prototype\n");
1587 s++;
1590 s++;
1591 while (*s != '\0' && isspace(*s))
1592 s++;
1594 if (*s == '(')
1596 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1598 /* There may be no register specified with () so be sure then c is == ')' */
1599 s++;
1600 while(isspace(*s))
1601 s++;
1603 c = *s;
1605 while (c != ')')
1607 while (isspace(*s))
1608 s++;
1610 regs[regcount] = s;
1611 regcount++;
1613 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1615 s += 2;
1616 c = *s;
1617 if (c == '/')
1619 s++;
1620 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1622 s += 2;
1623 c = *s;
1625 else
1626 exitfileerror(20,
1627 "wrong register specification \"%s\" for argument %u\n",
1628 regs[regcount-1], regcount
1631 if (regcount > 2)
1632 exitfileerror(20, "maximum two arguments passed in two registers allowed\n");
1634 *s = '\0';
1636 else
1637 exitfileerror(20,
1638 "wrong register \"%s\" for argument %u\n",
1639 regs[regcount-1], regcount
1642 while (isspace(c))
1644 s++;
1645 c = *s;
1647 if (c == '\0')
1648 exitfileerror(20, "'(' without ')'\n");
1649 if (c != ',' && c != ')')
1650 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1652 s++;
1655 s++;
1656 while (isspace(*s)) s++;
1657 if (*s!='\0')
1658 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1660 if (argcount != regcount)
1661 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1662 argcount, regcount
1665 (*funclistptr)->libcall = REGISTERMACRO;
1666 for (i = 0; i < argcount; i++)
1667 funcaddarg(*funclistptr, args[i], regs[i]);
1669 else if (*s == '\0')
1670 { /* No registers specified */
1671 for (i = 0; i < argcount; i++)
1672 funcaddarg(*funclistptr, args[i], NULL);
1674 else
1675 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1680 static void readsectionmethodlist(struct classinfo *cl)
1682 int atend = 0, i;
1683 char *line, *s, *s2;
1684 struct functionhead **methlistptr = &cl->methlist;
1685 struct stringlist *interface = NULL;
1687 if (cl->basename==NULL)
1688 exitfileerror(20, "section methodlist has to come after section config\n");
1690 while (!atend)
1692 line = readline();
1693 if (line==NULL)
1694 exitfileerror(20, "unexptected EOF in methodlist section\n");
1696 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1697 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1698 continue;
1700 if (isspace(*line))
1701 exitfileerror(20, "No space allowed at start of the line\n");
1703 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1705 s = line+2;
1706 while (isspace(*s)) s++;
1707 if (strncmp(s, "end", 3)!=0)
1708 exitfileerror(20, "\"##end methodlist\" expected\n");
1710 s += 3;
1711 while (isspace(*s)) s++;
1712 if (strncmp(s, "methodlist", 10)!=0)
1713 exitfileerror(20, "\"##end methodlist\" expected\n");
1715 s += 10;
1716 while (isspace(*s)) s++;
1717 if (*s!='\0')
1718 exitfileerror(20, "unexpected character on position %d\n", s-line);
1720 atend = 1;
1722 continue;
1725 if (*line=='.')
1727 s = line+1;
1728 if (strncmp(s, "alias", 5)==0)
1730 s += 5;
1732 if (!isspace(*s))
1733 exitfileerror(20, "syntax is '.alias name'\n");
1735 while (isspace(*s)) s++;
1736 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1737 exitfileerror(20, "syntax is '.alias name'\n");
1739 s2 = s;
1740 s++;
1741 while (isalnum(*s) || *s == '_') s++;
1743 if (isspace(*s))
1745 *s = '\0';
1746 do {
1747 s++;
1748 } while (isspace(*s));
1751 if (*s != '\0')
1752 exitfileerror(20, "syntax is '.alias name'\n");
1754 if (*methlistptr == NULL)
1755 exitfileerror(20, ".alias has to come after a function declaration\n");
1757 slist_append(&(*methlistptr)->aliases, s2);
1759 else if (strncmp(s, "function", 8) == 0)
1761 s += 8;
1763 if (!isspace(*s))
1764 exitfileerror(20, "Syntax error\n");
1766 while (isspace(*s)) s++;
1767 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1768 exitfileerror(20, "syntax is '.function name'\n");
1770 s2 = s;
1771 s++;
1772 while (isalnum(*s) || *s == '_') s++;
1774 if (isspace(*s))
1776 *s = '\0';
1777 do {
1778 s++;
1779 } while (isspace(*s));
1782 if (*s != '\0')
1783 exitfileerror(20, "syntax is '.function name'\n");
1785 if (*methlistptr == NULL)
1786 exitfileerror(20, ".function has to come after a function declaration\n");
1788 funcsetinternalname(*methlistptr, s2);
1790 else if (strncmp(s, "interface", 9) == 0)
1792 if (cl->classtype != HIDD)
1793 exitfileerror(20, "interface only valid for a HIDD\n");
1795 s += 9;
1797 if (!isspace(*s))
1798 exitfileerror(20, "Syntax error\n");
1800 while (isspace(*s)) s++;
1801 if (*s == '\0' || !isalpha(*s))
1802 exitfileerror(20, "syntax is '.interface name'\n");
1804 s2 = s;
1805 s++;
1806 while (isalnum(*s) || *s == '_') s++;
1808 if (isspace(*s))
1810 *s = '\0';
1811 do {
1812 s++;
1813 } while (isspace(*s));
1816 if (*s != '\0')
1817 exitfileerror(20, "syntax is '.interface name'\n");
1819 interface = slist_append(&cl->interfaces, s2);
1821 else
1822 exitfileerror(20, "Syntax error");
1824 else if (isalpha(*line))
1826 char stmp[256];
1828 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
1831 if (cl->classtype == HIDD && interface == NULL)
1832 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
1834 if (*s != '\0')
1835 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
1837 if (*methlistptr != NULL)
1838 methlistptr = &((*methlistptr)->next);
1839 if (cl->classtype != HIDD)
1841 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
1842 exitfileerror(20, "Method name too large\n");
1844 *methlistptr = newfunctionhead(stmp, STACK);
1845 (*methlistptr)->type = "IPTR";
1846 funcaddarg(*methlistptr, "Class *cl", NULL);
1847 funcaddarg(*methlistptr, "Object *o", NULL);
1848 funcaddarg(*methlistptr, "Msg msg", NULL);
1850 else
1852 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
1853 exitfileerror(20, "Method name too large\n");
1855 *methlistptr = newfunctionhead(stmp, STACK);
1856 (*methlistptr)->type = "IPTR";
1857 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
1858 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
1859 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
1860 (*methlistptr)->interface = interface;
1861 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
1862 exitfileerror(20, "Method name too large\n");
1863 (*methlistptr)->method = strdup(stmp);
1865 slist_append(&(*methlistptr)->aliases, line);
1867 else
1868 exitfileerror(20, "Methodname has to begin with a letter\n");
1872 static void
1873 readsectionclass(struct config *cfg)
1875 char *s;
1876 struct classinfo *cl;
1878 cl = newclass(cfg);
1879 s = readsections(cfg, cl, 1);
1880 if (s == NULL)
1881 exitfileerror(20, "Unexpected end of file\n");
1883 if (strncmp(s, "##", 2) != 0)
1884 exitfileerror(20, "'##end class' expected\n");
1885 s += 2;
1887 while (isspace(*s)) s++;
1889 if (strncmp(s, "end", 3) != 0)
1890 exitfileerror(20, "'##end class' expected\n");
1891 s += 3;
1893 if (!isspace(*s))
1894 exitfileerror(20, "'##end class' expected\n");
1895 while (isspace(*s)) s++;
1897 if (strncmp(s, "class", 5) != 0)
1898 exitfileerror(20, "'##end class' expected\n");
1899 s += 5;
1901 while (isspace(*s)) s++;
1902 if (*s != '\0')
1903 exitfileerror(20, "'##end class' expected\n");
1906 static struct classinfo *newclass(struct config *cfg)
1908 struct classinfo *cl, *classlistit;
1910 cl = malloc(sizeof(struct classinfo));
1911 if (cl == NULL)
1913 fprintf(stderr, "Out of memory\n");
1914 exit(20);
1916 memset(cl, 0, sizeof(struct classinfo));
1918 /* By default the classes are initialized with a priority of 1 so they
1919 * are initialized before any user added initialization with priority 1
1921 cl->initpri = 1;
1923 if (cfg->classlist == NULL)
1924 cfg->classlist = cl;
1925 else
1929 classlistit = cfg->classlist;
1930 classlistit->next != NULL;
1931 classlistit = classlistit->next
1934 classlistit->next = cl;
1937 return cl;
1940 static struct handlerinfo *newhandler(struct config *cfg)
1942 struct handlerinfo *hl;
1944 hl = calloc(1,sizeof(*hl));
1945 hl->next = cfg->handlerlist;
1946 cfg->handlerlist = hl;
1947 return hl;
1950 static int getdirective(char *s, const char *directive, int range_min, int range_max, int *val)
1952 char *tmp;
1953 int newval;
1955 if (strncmp(s, directive, strlen(directive)) != 0)
1956 return 0;
1958 s += strlen(directive);
1959 if (*s && !isspace(*s))
1960 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive);
1962 while (isspace(*s)) s++;
1963 if (!*s)
1964 exitfileerror(20, "No .%s value specified\n", directive);
1966 newval = strtol(s, &tmp, 0);
1967 if (s == tmp || !(newval >= range_min && newval <= range_max)) {
1968 tmp = s;
1969 while (*tmp && !isspace(*tmp)) tmp++;
1970 exitfileerror(20, "Invalid .%s value of %.*s\n", directive, tmp - s, s);
1973 *val = newval;
1974 return 1;
1977 static void
1978 readsectionhandler(struct config *cfg)
1980 char *line = NULL, *s;
1981 struct handlerinfo *hl;
1982 unsigned char autolevel = 0;
1983 unsigned int stacksize;
1984 char priority;
1986 for (;;)
1988 char *function;
1989 int function_len;
1990 char *tmp;
1992 /* Defaults */
1993 stacksize = 0;
1994 priority = 10;
1996 s = line = readline();
1998 if (s==NULL)
1999 exitfileerror(20, "unexpected end of file in section hanlder\n");
2001 if (strncmp(s, "##", 2)==0)
2002 break;
2004 /* Ignore comments */
2005 if (strncmp(s, "#", 1)==0)
2006 continue;
2008 /* Skip ahead to function name */
2009 while (*s && isspace(*s)) s++;
2011 /* Permit blank lines */
2012 if (!*s)
2013 continue;
2015 if (*s == '.') {
2016 int val;
2017 s++;
2019 if (getdirective(s, "autodetect", 0, 127, &val)) {
2020 autolevel = val;
2021 } else if (getdirective(s, "stacksize", 0, INT_MAX, &val)) {
2022 stacksize = val;
2023 } else if (getdirective(s, "priority", -128, 127, &val)) {
2024 priority = val;
2025 } else {
2026 exitfileerror(20, "Unrecognized directive \"%s\"\n", line);
2028 continue;
2031 function = s;
2032 while (*s && !isspace(*s)) s++;
2033 function_len = s - function;
2035 if (!*s)
2036 exitfileerror(20, "No identifier specified for the handler");
2038 function[function_len] = 0;
2039 s++;
2041 do {
2042 unsigned int id = 0;
2044 if (strncasecmp(s,"resident=",9)==0) {
2045 char *res;
2047 s = strchr(s, '=') + 1;
2048 res = s;
2049 while (*s && !isspace(*s)) s++;
2050 if (res == s)
2051 exitfileerror(20, "Empty resident= is not permitted\n");
2053 if (*s)
2054 *(s++) = 0;
2056 hl = newhandler(cfg);
2057 hl->type = HANDLER_RESIDENT;
2058 hl->id = 0;
2059 hl->name = strdup(res);
2060 hl->autodetect = autolevel--;
2061 hl->stacksize = stacksize;
2062 hl->priority = priority;
2063 hl->handler = strdup(function);
2064 } else if (strncasecmp(s,"dosnode=",8)==0) {
2065 char *dev;
2067 s = strchr(s, '=') + 1;
2068 dev = s;
2069 while (*s && !isspace(*s)) s++;
2070 if (dev == s)
2071 exitfileerror(20, "Empty dosnode= is not permitted\n");
2073 if (*s)
2074 *(s++) = 0;
2076 hl = newhandler(cfg);
2077 hl->type = HANDLER_DOSNODE;
2078 hl->id = 0;
2079 hl->name = strdup(dev);
2080 hl->autodetect = autolevel ? autolevel-- : 0;
2081 hl->handler = strdup(function);
2082 hl->stacksize = stacksize;
2083 hl->priority = priority;
2084 } else if (strncasecmp(s,"dostype=",8) == 0) {
2085 s = strchr(s, '=') + 1;
2087 id = (unsigned int)strtoul(s, &tmp, 0);
2089 if (s == tmp) {
2090 while (*tmp && !isspace(*tmp))
2091 tmp++;
2092 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp -s), s);
2094 s = tmp;
2096 if (id == 0 || id == ~0) {
2097 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id);
2100 hl = newhandler(cfg);
2101 hl->type = HANDLER_DOSTYPE;
2102 hl->id = id;
2103 hl->name = NULL;
2104 hl->autodetect = autolevel ? autolevel-- : 0;
2105 hl->handler = strdup(function);
2106 hl->stacksize = stacksize;
2107 hl->priority = priority;
2108 } else {
2109 for (tmp = s; !isspace(*tmp); tmp++);
2110 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp - s, s);
2113 /* Advance to next ID */
2114 while (*s && isspace(*s)) s++;
2116 } while (*s);
2119 if (s == NULL)
2120 exitfileerror(20, "Unexpected end of file\n");
2122 if (strncmp(s, "##", 2) != 0)
2123 exitfileerror(20, "'##end handler' expected\n");
2124 s += 2;
2126 while (isspace(*s)) s++;
2128 if (strncmp(s, "end", 3) != 0)
2129 exitfileerror(20, "'##end handler' expected\n");
2130 s += 3;
2132 while (isspace(*s)) s++;
2134 if (strncmp(s, "handler", 7) != 0)
2135 exitfileerror(20, "'##end handler' expected\n");
2136 s += 7;
2138 while (isspace(*s)) s++;
2139 if (*s != '\0')
2140 exitfileerror(20, "'##end handler' expected\n");