Bulgarian keymap
[AROS.git] / tools / genmodule / config.c
blob7c9a92a657755f3f46fb8cefd4241f05d8635d77
1 /*
2 Copyright © 1995-2010, 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>
16 #include "functionhead.h"
17 #include "config.h"
19 const static char bannertemplate[] =
20 "/*\n"
21 " *** Automatically generated from '%s'. Edits will be lost. ***\n"
22 " Copyright © 1995-2010, The AROS Development Team. All rights reserved.\n"
23 "*/\n";
25 char*
26 getBanner(struct config* config)
28 int bannerlength = strlen(config->conffile) + strlen(bannertemplate) -1;
29 char * banner = malloc(bannerlength);
31 snprintf (banner, bannerlength, bannertemplate, config->conffile);
33 return(banner);
36 void
37 freeBanner(char *banner)
39 free((void *)banner);
42 const static char usage[] =
43 "\n"
44 "Usage: genmodule [-c conffile] [-s suffix] [-d gendir] [-r reffile] [-n]\n"
45 " {writefiles|writemakefile|writeincludes|writedummy|writelibdefs|writefunclist} modname modtype\n"
48 static void readconfig(struct config *);
49 static struct classinfo *newclass(struct config *);
51 /* the method prefices for the supported classes */
52 static const char *muimprefix[] =
54 "__OM_",
55 "__MUIM_",
56 NULL
58 static const char *gadgetmprefix[] =
60 "__OM_",
61 "__GM_",
62 "__AROSM_",
63 NULL
65 static const char *dtmprefix[] =
67 "__OM_",
68 "__GM_",
69 "__DTM_",
70 "__PDTM_",
71 NULL
74 /* Create a config struct. Initialize with the values from the programs command
75 * line arguments and the contents of the modules .conf file
77 struct config *initconfig(int argc, char **argv)
79 struct config *cfg;
80 char *s, **argvit = argv + 1;
81 int hassuffix = 0, c;
83 cfg = malloc(sizeof(struct config));
84 if (cfg == NULL)
86 fprintf(stderr, "Out of memory\n");
87 exit(20);
90 memset(cfg, 0, sizeof(struct config));
92 while ((c = getopt(argc, argv, ":c:s:d:r:")) != -1)
94 if (c == ':')
96 fprintf(stderr, "Option -%c needs an argument\n",optopt);
97 exit(20);
100 switch (c)
102 case 'c':
103 cfg->conffile = optarg;
104 break;
105 case 's':
106 cfg->suffix = optarg;
107 hassuffix = 1;
108 break;
109 case 'd':
110 /* Remove / at end if present */
111 if ((optarg)[strlen(*argvit)-1]=='/') (optarg)[strlen(optarg)-1]='\0';
112 cfg->gendir = optarg;
113 break;
114 case 'r':
115 cfg->reffile = optarg;
116 break;
117 default:
118 fprintf(stderr, "Internal error: Unhandled option\n");
119 exit(20);
123 if (optind + 3 != argc)
125 fprintf(stderr, "Wrong number of arguments.\n%s", usage);
126 exit(20);
129 if (strcmp(argv[optind], "writefiles") == 0)
131 cfg->command = FILES;
133 else if (strcmp(argv[optind], "writemakefile") == 0)
135 cfg->command = MAKEFILE;
137 else if (strcmp(argv[optind], "writeincludes") == 0)
139 cfg->command = INCLUDES;
141 else if (strcmp(argv[optind], "writelibdefs") == 0)
143 cfg->command = LIBDEFS;
145 else if (strcmp(argv[optind], "writedummy") == 0)
147 cfg->command = DUMMY;
149 else if (strcmp(argv[optind], "writefunclist") == 0)
151 cfg->command = WRITEFUNCLIST;
153 else
155 fprintf(stderr, "Unrecognized argument \"%s\"\n%s", argv[optind], usage);
156 exit(20);
159 cfg->modulename = argv[optind+1];
160 cfg->modulenameupper = strdup(cfg->modulename);
161 for (s=cfg->modulenameupper; *s!='\0'; *s = toupper(*s), s++)
164 if (strcmp(argv[optind+2],"library")==0)
166 cfg->modtype = LIBRARY;
167 cfg->moddir = "Libs";
169 else if (strcmp(argv[optind+2],"mcc")==0)
171 cfg->modtype = MCC;
172 cfg->moddir = "Classes/Zune";
174 else if (strcmp(argv[optind+2],"mui")==0)
176 cfg->modtype = MUI;
177 cfg->moddir = "Classes/Zune";
179 else if (strcmp(argv[optind+2],"mcp")==0)
181 cfg->modtype = MCP;
182 cfg->moddir = "Classes/Zune";
184 else if (strcmp(argv[optind+2], "device")==0)
186 cfg->modtype = DEVICE;
187 cfg->moddir = "Devs";
189 else if (strcmp(argv[optind+2], "resource")==0)
191 cfg->modtype = RESOURCE;
192 cfg->moddir = "Devs";
194 else if (strcmp(argv[optind+2], "gadget")==0)
196 cfg->modtype = GADGET;
197 cfg->moddir = "Classes/Gadgets";
199 else if (strcmp(argv[optind+2], "datatype")==0)
201 cfg->modtype = DATATYPE;
202 cfg->moddir = "Classes/Datatypes";
204 else if (strcmp(argv[optind+2], "usbclass")==0)
206 cfg->modtype = USBCLASS;
207 cfg->moddir = "Classes/USB";
208 if(!hassuffix)
210 cfg->suffix = "class";
211 hassuffix = 1;
214 else if (strcmp(argv[optind+2], "hidd")==0)
216 cfg->modtype = HIDD;
217 cfg->moddir = "Devs/Drivers";
219 else
221 fprintf(stderr, "Unknown modtype \"%s\" specified for second argument\n", argv[2]);
222 exit(20);
225 if (!hassuffix)
226 cfg->suffix = argv[optind+2];
228 /* Fill fields with default value if not specified on the command line */
230 char tmpbuf[256];
232 if (cfg->conffile == NULL)
234 snprintf(tmpbuf, sizeof(tmpbuf), "%s.conf", cfg->modulename);
235 cfg->conffile = strdup(tmpbuf);
238 if (cfg->gendir == NULL)
239 cfg->gendir = ".";
241 if (cfg->command != FILES && cfg->command != INCLUDES && cfg->command != WRITEFUNCLIST)
243 if (cfg->reffile != NULL)
244 fprintf(stderr, "WARNING ! Option -r ingored for %s\n", argv[optind]);
246 else if (cfg->command == FILES && cfg->reffile == NULL)
248 snprintf(tmpbuf, sizeof(tmpbuf), "%s.ref", cfg->modulename);
249 cfg->reffile = strdup(tmpbuf);
253 readconfig(cfg);
255 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
256 * if they are provided
258 if (cfg->beginiofunc != NULL)
260 struct functionhead *funchead;
262 cfg->intcfg |= CFG_NOREADREF;
264 /* Add beginio_func to the list of functions */
265 funchead = newfunctionhead(cfg->beginiofunc, REGISTERMACRO);
266 funchead->type = strdup("void");
267 funchead->lvo = 5;
268 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
270 funchead->next = cfg->funclist;
271 cfg->funclist = funchead;
273 /* Add abortio_func to the list of functions */
274 funchead = newfunctionhead(cfg->abortiofunc, REGISTERMACRO);
275 funchead->type = strdup("LONG");
276 funchead->lvo = 6;
277 funcaddarg(funchead, "struct IORequest *ioreq", "A1");
279 funchead->next = cfg->funclist->next;
280 cfg->funclist->next = funchead;
282 else if (cfg->modtype == DEVICE && cfg->intcfg & CFG_NOREADREF)
284 fprintf
286 stderr,
287 "beginio_func and abortio_func missing for a device with a non empty function list\n"
289 exit(20);
292 return cfg;
295 /* Functions to read configuration from the configuration file */
297 #include "fileread.h"
299 static char *readsections(struct config *, struct classinfo *, int);
300 static void readsectionconfig(struct config *, struct classinfo *, int);
301 static void readsectioncdef(struct config *);
302 static void readsectioncdefprivate(struct config *);
303 static void readsectionstartup(struct config *);
304 static void readsectionfunctionlist(struct config *);
305 static void readsectionmethodlist(struct classinfo *);
306 static void readsectionclass(struct config *);
308 static void readconfig(struct config *cfg)
310 struct classinfo *mainclass = NULL;
312 /* Create a classinfo structure if this module is a class */
313 switch (cfg->modtype)
315 case LIBRARY:
316 case DEVICE:
317 case RESOURCE:
318 case USBCLASS:
319 break;
321 case MCC:
322 case MUI:
323 case MCP:
324 case GADGET:
325 case DATATYPE:
326 case HIDD:
327 mainclass = newclass(cfg);
328 mainclass->classtype = cfg->modtype;
329 break;
331 default:
332 fprintf(stderr, "Internal error: unsupported modtype for classinfo creation\n");
333 exit(20);
336 switch (cfg->modtype)
338 case LIBRARY:
339 case USBCLASS:
340 cfg->firstlvo = 5;
341 break;
342 case DEVICE:
343 cfg->firstlvo = 7;
344 break;
345 case MCC:
346 case MUI:
347 case MCP:
348 cfg->firstlvo = 6;
349 mainclass->boopsimprefix = muimprefix;
350 break;
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"
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_NOREADREF;
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_NOREADREF;
472 break;
474 case 7: /* class */
475 if (inclass)
476 exitfileerror(20, "class section may not be nested\n");
477 readsectionclass(cfg);
478 break;
481 else if (strlen(line)!=0)
482 filewarning("warning line outside section ignored\n");
485 if(!inclass)
487 if (!hasconfig)
488 exitfileerror(20, "No config section in conffile\n");
490 /* If no indication was given for generating includes or not
491 decide on module type and if there are functions
493 if(!((cfg->options & OPTION_INCLUDES) || (cfg->options & OPTION_NOINCLUDES)))
495 switch (cfg->modtype)
497 case LIBRARY:
498 case RESOURCE:
499 case USBCLASS:
500 cfg->options |= OPTION_INCLUDES;
501 break;
503 case DEVICE:
504 cfg->options |= (
505 (cfg->funclist != NULL)
506 || (cfg->cdeflines != NULL)
507 || strcmp(cfg->libbasetypeptrextern, "struct Device *") != 0
508 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
509 break;
511 case GADGET:
512 case DATATYPE:
513 case MCC:
514 case MUI:
515 case MCP:
516 case HIDD:
517 cfg->options |= (
518 (cfg->funclist != NULL)
519 || (cfg->cdeflines != NULL)
520 ) ? OPTION_INCLUDES : OPTION_NOINCLUDES;
521 break;
523 default:
524 fprintf(stderr, "Internal error writemakefile: unhandled modtype for includes\n");
525 exit(20);
526 break;
530 /* If no indication was given for not generating stubs only generate them if
531 * the module has functions
533 if(!((cfg->options & OPTION_STUBS) || (cfg->options & OPTION_NOSTUBS)))
535 cfg->options |= (cfg->funclist != NULL) ?
536 OPTION_STUBS : OPTION_NOSTUBS;
539 /* If no indication was given for generating autoinit code or not
540 decide on module type
542 if(!((cfg->options & OPTION_AUTOINIT) || (cfg->options & OPTION_NOAUTOINIT)))
544 switch (cfg->modtype)
546 case LIBRARY:
547 case USBCLASS:
548 cfg->options |= OPTION_AUTOINIT;
549 break;
551 case RESOURCE:
552 case GADGET:
553 case DEVICE:
554 case DATATYPE:
555 case MCC:
556 case MUI:
557 case MCP:
558 case HIDD:
559 cfg->options |= OPTION_NOAUTOINIT;
560 break;
562 default:
563 fprintf(stderr, "Internal error writemakefile: unhandled modtype for autoinit\n");
564 exit(20);
565 break;
569 if (cfg->modtype == RESOURCE)
570 /* Enforce noopenclose for resources */
571 cfg->options |= OPTION_NOOPENCLOSE;
572 else
573 /* Enforce using RTF_AUTOINIT for everything except resources */
574 cfg->options |= OPTION_RESAUTOINIT;
576 return NULL;
579 static void readsectionconfig(struct config *cfg, struct classinfo *cl, int inclass)
581 int atend = 0, i;
582 char *line, *s, *s2, *libbasetypeextern = NULL;
583 struct tm date;
585 while (!atend)
587 line = readline();
588 if (line==NULL)
589 exitfileerror(20, "unexpected end of file in section config\n");
591 if (strncmp(line, "##", 2)!=0)
593 const char *names[] =
595 "basename", "libbase", "libbasetype", "libbasetypeextern",
596 "version", "date", "copyright", "libcall", "forcebase", "superclass",
597 "superclass_field", "residentpri", "options", "sysbase_field",
598 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
599 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
600 "initpri", "type", "getidfunc"
602 const unsigned int namenums = sizeof(names)/sizeof(char *);
603 unsigned int namenum;
605 for (i = 0, namenum = 0; namenum==0 && i<namenums; i++)
609 strncmp(line, names[i], strlen(names[i]))==0
610 && isspace(*(line+strlen(names[i])))
612 namenum = i+1;
614 if (namenum==0)
615 exitfileerror(20, "unrecognized configuration option\n");
617 s = line + strlen(names[namenum-1]);
618 if (!isspace(*s))
619 exitfileerror(20, "space character expected after \"%s\"\n", names[namenum-1]);
621 while (isspace(*s)) s++;
622 if (*s=='\0')
623 exitfileerror(20, "unexpected end of line\n");
625 s2 = s + strlen(s);
626 while (isspace(*(s2-1))) s2--;
627 *s2 = '\0';
629 switch (namenum)
631 case 1: /* basename */
632 if (!inclass)
633 cfg->basename = strdup(s);
634 if (cl != NULL)
635 cl->basename = strdup(s);
636 break;
638 case 2: /* libbase */
639 if (inclass)
640 exitfileerror(20, "libbase not valid config option when in a class section\n");
641 cfg->libbase = strdup(s);
642 break;
644 case 3: /* libbasetype */
645 if (inclass)
646 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
647 cfg->libbasetype = strdup(s);
648 break;
650 case 4: /* libbasetypeextern */
651 if (inclass)
652 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
653 libbasetypeextern = strdup(s);
654 break;
656 case 5: /* version */
657 if (inclass)
658 exitfileerror(20, "version not valid config option when in a class section\n");
659 if (sscanf(s, "%u.%u", &cfg->majorversion, &cfg->minorversion)!=2)
660 exitfileerror(20, "wrong version string \"%s\"\n", s);
661 break;
663 case 6: /* date */
664 if (inclass)
665 exitfileerror(20, "date not valid config option when in a class section\n");
666 #ifndef _WIN32
667 if (strptime(s, "%e.%m.%Y", &date) == NULL)
669 exitfileerror(20, "date string has to have d.m.yyyy format\n");
671 #endif
672 cfg->datestring = strdup(s);
673 break;
675 case 7: /* copyright */
676 if (inclass)
677 exitfileerror(20, "copyright not valid config option when in a class section\n");
678 cfg->copyright = strdup(s);
679 break;
681 case 8: /* libcall */
682 fprintf(stderr, "libcall specification is deprecated and ignored\n");
683 break;
685 case 9: /* forcebase */
686 if (inclass)
687 exitfileerror(20, "forcebase not valid config option when in a class section\n");
688 slist_append(&cfg->forcelist, s);
689 break;
691 case 10: /* superclass */
692 if (cl == NULL)
693 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
694 cl->superclass = strdup(s);
695 break;
697 case 11: /* superclass_field */
698 if (cl == NULL)
699 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
700 cl->superclass_field = strdup(s);
701 break;
703 case 12: /* residentpri */
704 if (!inclass)
706 int count;
707 char dummy;
709 count = sscanf(s, "%d%c", &cfg->residentpri, &dummy);
710 if (count != 1 ||
711 cfg->residentpri < -128 || cfg->residentpri > 127
714 exitfileerror(20, "residentpri number format error\n");
717 else
718 exitfileerror(20, "residentpri not valid config option when in a class section\n");
719 break;
721 case 13: /* options */
722 if (!inclass)
724 static const char *optionnames[] =
726 "noautolib", "noexpunge", "noresident", "peropenerbase",
727 "peridbase", "includes", "noincludes", "nostubs",
728 "autoinit", "noautoinit", "resautoinit", "noopenclose"
730 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
731 int optionnum;
735 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
737 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
739 optionnum = i + 1;
740 s += strlen(optionnames[i]);
741 while (isspace(*s)) s++;
742 if (*s == ',')
743 s++;
744 else if (*s != '\0')
745 exitfileerror(20, "Unrecognized option\n");
748 if (optionnum == 0)
749 exitfileerror(20, "Unrecognized option\n");
750 switch (optionnum)
752 case 1: /* noautolib */
753 cfg->options |= OPTION_NOAUTOLIB;
754 break;
755 case 2: /* noexpunge */
756 cfg->options |= OPTION_NOEXPUNGE;
757 break;
758 case 3: /* noresident */
759 cfg->options |= OPTION_NORESIDENT;
760 cfg->firstlvo = 1;
761 break;
762 case 5: /* peridbase */
763 cfg->options |= OPTION_DUPPERID;
764 /* Fall through */
765 case 4: /* peropenerbase */
766 if (cfg->options & OPTION_DUPBASE)
767 exitfileerror(20, "Only one option peropenerbase or peridbase allowed\n");
768 cfg->options |= OPTION_DUPBASE;
769 break;
770 case 6: /* includes */
771 if (cfg->options & OPTION_NOINCLUDES)
772 exitfileerror(20, "option includes and noincludes are incompatible\n");
773 cfg->options |= OPTION_INCLUDES;
774 break;
775 case 7: /* noincludes */
776 if (cfg->options & OPTION_INCLUDES)
777 exitfileerror(20, "option includes and noincludes are incompatible\n");
778 cfg->options |= OPTION_NOINCLUDES;
779 break;
780 case 8: /* nostubs */
781 cfg->options |= OPTION_NOSTUBS;
782 break;
783 case 9: /* autoinit */
784 if (cfg->options & OPTION_NOAUTOINIT)
785 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
786 cfg->options |= OPTION_AUTOINIT;
787 break;
788 case 10: /* noautoinit */
789 if (cfg->options & OPTION_AUTOINIT)
790 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
791 cfg->options |= OPTION_NOAUTOINIT;
792 break;
793 case 11: /* resautoinit */
794 cfg->options |= OPTION_RESAUTOINIT;
795 break;
796 case 12:
797 cfg->options |= OPTION_NOOPENCLOSE;
798 break;
800 while (isspace(*s)) s++;
801 } while(*s !='\0');
803 else
805 static const char *optionnames[] =
807 "private"
809 const unsigned int optionnums = sizeof(optionnames)/sizeof(char *);
810 int optionnum;
814 for (i = 0, optionnum = 0; optionnum==0 && i<optionnums; i++)
816 if (strncmp(s, optionnames[i], strlen(optionnames[i]))==0)
818 optionnum = i + 1;
819 s += strlen(optionnames[i]);
820 while (isspace(*s)) s++;
821 if (*s == ',')
822 s++;
823 else if (*s != '\0')
824 exitfileerror(20, "Unrecognized option\n");
827 if (optionnum == 0)
828 exitfileerror(20, "Unrecognized option\n");
829 switch (optionnum)
831 case 1: /* private */
832 cl->options |= COPTION_PRIVATE;
833 break;
835 while (isspace(*s)) s++;
836 } while(*s !='\0');
838 break;
840 case 14: /* sysbase_field */
841 if (inclass)
842 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
843 cfg->sysbase_field = strdup(s);
844 break;
846 case 15: /* seglist_field */
847 if (inclass)
848 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
849 cfg->seglist_field = strdup(s);
850 break;
852 case 16: /* rootbase_field */
853 if (inclass)
854 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
855 cfg->rootbase_field = strdup(s);
856 break;
858 case 17: /* classptr_field */
859 if (cl == NULL)
861 exitfileerror
864 "classptr_field specified when not a BOOPSI class\n"
867 cl->classptr_field = strdup(s);
868 break;
870 case 18: /* classptr_var */
871 if (cl == NULL)
873 exitfileerror
876 "classptr_var specified when not a BOOPSI class\n"
879 cl->classptr_var = strdup(s);
880 break;
882 case 19: /* classid */
883 if (cl == NULL)
884 exitfileerror(20, "classid specified when not a BOOPSI class\n");
885 if (cl->classid != NULL)
886 exitfileerror(20, "classid specified twice\n");
887 cl->classid = strdup(s);
888 if (strcmp(cl->classid, "NULL") == 0)
889 cl->options |= COPTION_PRIVATE;
890 break;
892 case 20: /* classdatatype */
893 if (cl == NULL)
894 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
895 cl->classdatatype = strdup(s);
896 break;
898 case 21: /* beginio_func */
899 if (inclass)
900 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
901 if (cfg->modtype != DEVICE)
902 exitfileerror(20, "beginio_func specified when not a device\n");
903 cfg->beginiofunc = strdup(s);
904 break;
906 case 22: /* abortio_func */
907 if (inclass)
908 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
909 if (cfg->modtype != DEVICE)
910 exitfileerror(20, "abortio_func specified when not a device\n");
911 cfg->abortiofunc = strdup(s);
912 break;
914 case 23: /* dispatcher */
915 if (cl == NULL)
916 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
917 cl->dispatcher = strdup(s);
918 /* function references are not needed when dispatcher is specified */
919 cfg->intcfg |= CFG_NOREADREF;
920 break;
922 case 24: /* initpri */
923 if (cl != NULL)
925 int count;
926 char dummy;
928 count = sscanf(s, "%d%c", &cl->initpri, &dummy);
929 if (count != 1 ||
930 cl->initpri < -128 || cl->initpri > 127
933 exitfileerror(20, "initpri number format error\n");
936 else
937 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
938 break;
940 case 25: /* type */
941 if (!inclass)
942 exitfileerror(20, "type only valid config option in a class section\n");
943 if (strcmp(s,"mcc")==0)
944 cl->classtype = MCC;
945 else if (strcmp(s,"mui")==0)
946 cl->classtype = MUI;
947 else if (strcmp(s,"mcp")==0)
948 cl->classtype = MCP;
949 else if (strcmp(s, "image")==0)
950 cl->classtype = IMAGE;
951 else if (strcmp(s, "gadget")==0)
952 cl->classtype = GADGET;
953 else if (strcmp(s, "datatype")==0)
954 cl->classtype = DATATYPE;
955 else if (strcmp(s, "usbclass")==0)
956 cl->classtype = USBCLASS;
957 else if (strcmp(s, "class")==0)
958 cl->classtype = CLASS;
959 else if (strcmp(s, "hidd")==0)
960 cl->classtype = HIDD;
961 else
963 fprintf(stderr, "Unknown type \"%s\" specified\n", s);
964 exit(20);
966 break;
967 case 26: /* getidfunc */
968 cfg->getidfunc = strdup(s);
969 break;
972 else /* Line starts with ## */
974 s = line+2;
975 while (isspace(*s)) s++;
976 if (strncmp(s, "end", 3)!=0)
977 exitfileerror(20, "\"##end config\" expected\n");
979 s += 3;
980 if (!isspace(*s))
981 exitfileerror(20, "\"##end config\" expected\n");
983 while (isspace(*s)) s++;
984 if (strncmp(s, "config", 6)!=0)
985 exitfileerror(20, "\"##end config\" expected\n");
987 s += 6;
988 while (isspace(*s)) s++;
989 if (*s!='\0')
990 exitfileerror(20, "\"##end config\" expected\n");
992 atend = 1;
996 /* When not in a class section fill in default values for fields in cfg */
997 if (!inclass)
999 if (cfg->basename==NULL)
1001 cfg->basename = strdup(cfg->modulename);
1002 *cfg->basename = toupper(*cfg->basename);
1004 if (cfg->libbase==NULL)
1006 unsigned int len = strlen(cfg->basename)+5;
1007 cfg->libbase = malloc(len);
1008 snprintf(cfg->libbase, len, "%sBase", cfg->basename);
1010 if (cfg->libbasetype == NULL && libbasetypeextern != NULL)
1011 cfg->libbasetype = strdup(libbasetypeextern);
1012 if (cfg->sysbase_field != NULL && cfg->libbasetype == NULL)
1013 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1014 if (cfg->seglist_field != NULL && cfg->libbasetype == NULL)
1015 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1016 /* rootbase_field only allowed when duplicating base */
1017 if (cfg->rootbase_field != NULL && !(cfg->options & OPTION_DUPBASE))
1018 exitfileerror(20, "rootbasefield only valid for option peropenerbase or peridbase\n");
1019 if (cfg->getidfunc != NULL && !(cfg->options & OPTION_DUPPERID))
1020 exitfileerror(20, "getidfunc only valid for option peridbase\n");
1022 /* Set default date to current date */
1023 if (cfg->datestring == NULL)
1025 char tmpbuf[256];
1026 time_t now = time(NULL);
1027 struct tm *ltime = localtime(&now);
1029 snprintf(tmpbuf, sizeof(tmpbuf), "%u.%u.%u",
1030 ltime->tm_mday, 1 + ltime->tm_mon, 1900 + ltime->tm_year);
1032 cfg->datestring = strdup(tmpbuf);
1035 if (cfg->copyright == NULL)
1036 cfg->copyright = "";
1038 if ( (cfg->beginiofunc != NULL && cfg->abortiofunc == NULL)
1039 || (cfg->beginiofunc == NULL && cfg->abortiofunc != NULL)
1041 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1043 if (libbasetypeextern==NULL)
1045 switch (cfg->modtype)
1047 case DEVICE:
1048 cfg->libbasetypeptrextern = "struct Device *";
1049 break;
1050 case RESOURCE:
1051 cfg->libbasetypeptrextern = "APTR ";
1052 break;
1053 case LIBRARY:
1054 case MUI:
1055 case MCP:
1056 case MCC:
1057 case GADGET:
1058 case DATATYPE:
1059 case USBCLASS:
1060 case HIDD:
1061 cfg->libbasetypeptrextern = "struct Library *";
1062 break;
1063 default:
1064 fprintf(stderr, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1065 exit(20);
1068 else
1070 cfg->libbasetypeptrextern = malloc(strlen(libbasetypeextern)+3);
1071 strcpy(cfg->libbasetypeptrextern, libbasetypeextern);
1072 strcat(cfg->libbasetypeptrextern, " *");
1073 free(libbasetypeextern);
1077 /* When class was given too fill in some defaults when not specified */
1078 if (cl != NULL)
1080 if (cl->classtype == UNSPECIFIED)
1081 cl->classtype = CLASS;
1083 if (cl->basename == NULL)
1085 if (!inclass)
1086 cl->basename = cfg->basename;
1087 else
1088 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1091 /* MUI classes are always private */
1092 if (cl->classtype == MUI || cl->classtype == MCC || cl->classtype == MCP)
1093 cl->options |= COPTION_PRIVATE;
1095 if (cl->classid == NULL
1096 && (cl->classtype != MUI && cl->classtype != MCC && cl->classtype != MCP)
1099 if (cl->classtype == HIDD)
1101 cl->options &= !COPTION_PRIVATE;
1103 else if (cl->options & COPTION_PRIVATE)
1105 cl->classid = "NULL";
1107 else
1109 char s[256] = "";
1111 if (cl->classtype == GADGET || cl->classtype == IMAGE || cl->classtype == CLASS || cl->classtype == USBCLASS)
1113 sprintf(s, "\"%sclass\"", inclass ? cl->basename : cfg->modulename);
1115 else if (cl->classtype == DATATYPE)
1117 sprintf(s, "\"%s.datatype\"", inclass ? cl->basename : cfg->modulename);
1119 cl->classid = strdup(s);
1123 /* Only specify superclass or superclass_field */
1124 if (cl->superclass != NULL && cl->superclass_field != NULL)
1125 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1127 /* Give default value to superclass if it is not specified */
1128 if (cl->superclass == NULL && cl->superclass == NULL)
1130 switch (cl->classtype)
1132 case MUI:
1133 case MCC:
1134 cl->superclass = "MUIC_Area";
1135 break;
1136 case MCP:
1137 cl->superclass = "MUIC_Mccprefs";
1138 break;
1139 case IMAGE:
1140 cl->superclass = "IMAGECLASS";
1141 break;
1142 case GADGET:
1143 cl->superclass = "GADGETCLASS";
1144 break;
1145 case DATATYPE:
1146 cl->superclass = "DATATYPESCLASS";
1147 break;
1148 case CLASS:
1149 cl->superclass = "ROOTCLASS";
1150 break;
1151 case HIDD:
1152 cl->superclass = "CLID_Root";
1153 break;
1154 default:
1155 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1156 break;
1162 static void readsectioncdef(struct config *cfg)
1164 int atend = 0;
1165 char *line, *s;
1167 while (!atend)
1169 line = readline();
1170 if (line==NULL)
1171 exitfileerror(20, "unexptected end of file in section cdef\n");
1173 if (strncmp(line, "##", 2)!=0)
1175 slist_append(&cfg->cdeflines, line);
1177 else
1179 s = line+2;
1180 while (isspace(*s)) s++;
1181 if (strncmp(s, "end", 3)!=0)
1182 exitfileerror(20, "\"##end cdef\" expected\n");
1184 s += 3;
1185 while (isspace(*s)) s++;
1186 if (strncmp(s, "cdef", 4)!=0)
1187 exitfileerror(20, "\"##end cdef\" expected\n");
1189 s += 5;
1190 while (isspace(*s)) s++;
1191 if (*s!='\0')
1192 exitfileerror(20, "unexpected character at position %d\n");
1194 atend = 1;
1199 static void readsectioncdefprivate(struct config *cfg)
1201 int atend = 0;
1202 char *line, *s;
1204 while (!atend)
1206 line = readline();
1207 if (line==NULL)
1208 exitfileerror(20, "unexptected end of file in section cdef\n");
1210 if (strncmp(line, "##", 2)!=0)
1212 slist_append(&cfg->cdefprivatelines, line);
1214 else
1216 s = line+2;
1217 while (isspace(*s)) s++;
1218 if (strncmp(s, "end", 3)!=0)
1219 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1221 s += 3;
1222 while (isspace(*s)) s++;
1223 if (strncmp(s, "cdefprivate", 11)!=0)
1224 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1226 s += 11;
1227 while (isspace(*s)) s++;
1228 if (*s!='\0')
1229 exitfileerror(20, "unexpected character at position %d\n");
1231 atend = 1;
1236 static void readsectionstartup(struct config *cfg)
1238 int atend = 0;
1239 char *line, *s;
1241 while (!atend)
1243 line = readline();
1244 if (line==NULL)
1245 exitfileerror(20, "unexptected end of file in section startup\n");
1247 if (strncmp(line, "##", 2)!=0)
1249 slist_append(&cfg->startuplines, line);
1251 else
1253 s = line+2;
1254 while (isspace(*s)) s++;
1255 if (strncmp(s, "end", 3)!=0)
1256 exitfileerror(20, "\"##end startup\" expected\n");
1258 s += 3;
1259 while (isspace(*s)) s++;
1260 if (strncmp(s, "startup", 7)!=0)
1261 exitfileerror(20, "\"##end startup\" expected\n");
1263 s += 7;
1264 while (isspace(*s)) s++;
1265 if (*s!='\0')
1266 exitfileerror(20, "unexpected character at position %d\n");
1268 atend = 1;
1273 static void readsectionfunctionlist(struct config *cfg)
1275 int atend = 0, i;
1276 char *line, *s, *s2;
1277 unsigned int lvo = cfg->firstlvo;
1278 struct functionhead **funclistptr = &cfg->funclist;
1280 if (cfg->basename==NULL)
1281 exitfileerror(20, "section functionlist has to come after section config\n");
1283 while (!atend)
1285 line = readline();
1286 if (line==NULL)
1287 exitfileerror(20, "unexptected EOF in functionlist section\n");
1288 if (strlen(line)==0)
1290 if (*funclistptr != NULL)
1291 funclistptr = &((*funclistptr)->next);
1292 lvo++;
1294 else if (isspace(*line))
1296 s = line;
1297 while (isspace(*s)) s++;
1298 if (*s=='\0')
1300 if (*funclistptr != NULL)
1301 funclistptr = &((*funclistptr)->next);
1302 lvo++;
1304 else
1305 exitfileerror(20, "no space allowed before functionname\n");
1307 else if (strncmp(line, "##", 2)==0)
1309 s = line+2;
1310 while (isspace(*s)) s++;
1311 if (strncmp(s, "end", 3)!=0)
1312 exitfileerror(20, "\"##end functionlist\" expected\n");
1314 s += 3;
1315 while (isspace(*s)) s++;
1316 if (strncmp(s, "functionlist", 12)!=0)
1317 exitfileerror(20, "\"##end functionlist\" expected\n");
1319 s += 12;
1320 while (isspace(*s)) s++;
1321 if (*s!='\0')
1322 exitfileerror(20, "unexpected character on position %d\n", s-line);
1324 atend = 1;
1326 else if (*line=='.')
1328 s = line+1;
1329 if (strncmp(s, "skip", 4)==0)
1331 int n;
1333 s += 4;
1334 if (!isspace(*s))
1335 exitfileerror(20, "syntax is '.skip n'\n");
1337 n=strtol(s, &s2, 10);
1338 if (s2==NULL)
1339 exitfileerror(20, "positive number expected\n");
1341 while (isspace(*s2)) s2++;
1342 if (*s2!='\0')
1343 exitfileerror(20, "syntax is '.skip n'\n");
1344 if (*funclistptr != NULL)
1345 funclistptr = &((*funclistptr)->next);
1346 lvo += n;
1348 else if (strncmp(s, "alias", 5)==0)
1350 s += 5;
1352 if (!isspace(*s))
1353 exitfileerror(20, "syntax is '.alias name'\n");
1355 while (isspace(*s)) s++;
1356 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1357 exitfileerror(20, "syntax is '.alias name'\n");
1359 s2 = s;
1360 s++;
1361 while (isalnum(*s) || *s == '_') s++;
1363 if (isspace(*s))
1365 *s = '\0';
1366 do {
1367 s++;
1368 } while (isspace(*s));
1371 if (*s != '\0')
1372 exitfileerror(20, "syntax is '.alias name'\n");
1374 if (*funclistptr == NULL)
1375 exitfileerror(20, ".alias has to come after a function declaration\n");
1377 slist_append(&(*funclistptr)->aliases, s2);
1378 cfg->intcfg |= CFG_GENASTUBS;
1380 else if (strncmp(s, "function", 8) == 0)
1382 s += 8;
1384 if (!isspace(*s))
1385 exitfileerror(20, "Syntax error\n");
1387 while (isspace(*s)) s++;
1388 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1389 exitfileerror(20, "syntax is '.function name'\n");
1391 s2 = s;
1392 s++;
1393 while (isalnum(*s) || *s == '_') s++;
1395 if (isspace(*s))
1397 *s = '\0';
1398 do {
1399 s++;
1400 } while (isspace(*s));
1403 if (*s != '\0')
1404 exitfileerror(20, "syntax is '.function name'\n");
1406 if (*funclistptr == NULL)
1407 exitfileerror(20, ".function has to come after a function declaration\n");
1409 funcsetinternalname(*funclistptr, s2);
1411 else if (strncmp(s, "cfunction", 9)==0)
1413 if (*funclistptr == NULL)
1414 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1416 (*funclistptr)->libcall = REGISTER;
1418 else if (strncmp(s, "private", 7)==0)
1420 if (*funclistptr == NULL)
1421 exitfileerror(20, ".private has to come after a function declaration\n");
1423 (*funclistptr)->priv = 1;
1425 else if (strncmp(s, "novararg", 8)==0)
1427 if (*funclistptr == NULL)
1428 exitfileerror(20, ".novararg has to come after a function declaration\n");
1430 (*funclistptr)->novararg = 1;
1432 else
1433 exitfileerror(20, "Syntax error");
1435 else if (*line!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1437 /* The line is a function prototype. It can have two syntax
1438 * type funcname(argproto1, argproto2, ...)
1439 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1440 * The former is for C type function argument passing, the latter for
1441 * register argument passing.
1443 char c, *args[64], *regs[64], *funcname;
1444 int len, argcount = 0, regcount = 0, brcount = 0;
1446 /* Parse 'type functionname' at the beginning of the line */
1447 s = strchr(line, '(');
1448 if (s == NULL)
1449 exitfileerror(20, "( expected at position %d\n", strlen(line) + 1);
1451 s2 = s;
1452 while (isspace(*(s2-1)))
1453 s2--;
1454 *s2 = '\0';
1456 while (s2 > line && !isspace(*(s2-1)) && !(*(s2-1) == '*'))
1457 s2--;
1459 if (s2 == line)
1460 exitfileerror(20, "No type specifier before function name\n");
1462 if (*funclistptr != NULL)
1463 funclistptr = &((*funclistptr)->next);
1464 *funclistptr = newfunctionhead(s2, STACK);
1466 while (isspace(*(s2-1)))
1467 s2--;
1468 *s2 = '\0';
1469 (*funclistptr)->type = strdup(line);
1470 (*funclistptr)->lvo = lvo;
1471 lvo++;
1473 /* Parse function prototype */
1474 s++;
1475 while (isspace(*s))
1476 s++;
1477 c = *s;
1479 while (c != ')')
1481 while (isspace(*s))
1482 s++;
1484 args[argcount] = s;
1485 argcount++;
1487 while
1489 *s != '\0'
1490 && !(brcount == 0 && (*s == ',' || *s == ')'))
1493 if (*s == '(')
1494 brcount++;
1495 if (*s == ')')
1497 if (brcount > 0)
1498 brcount--;
1499 else
1500 exitfileerror(20, "Unexected ')' at position %d\n", s-line+1);
1502 s++;
1505 c = *s;
1506 if (c == '\0')
1507 exitfileerror(20, "'(' without ')'");
1509 s2 = s;
1510 while (isspace(*(s2-1)))
1511 s2--;
1512 *s2 = '\0';
1514 if (!(s2 > args[argcount - 1]))
1515 exitfileerror(20, "Syntax error in function prototype\n");
1517 s++;
1520 s++;
1521 while (*s != '\0' && isspace(*s))
1522 s++;
1524 if (*s == '(')
1526 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1528 /* There may be no register specified with () so be sure then c is == ')' */
1529 s++;
1530 while(isspace(*s))
1531 s++;
1533 c = *s;
1535 while (c != ')')
1537 while (isspace(*s))
1538 s++;
1540 regs[regcount] = s;
1541 regcount++;
1543 if (memchr("AD",s[0],2)!=NULL && memchr("01234567",s[1],8)!=NULL)
1545 s += 2;
1546 c = *s;
1547 if (c == '/')
1549 if (regcount > 1)
1551 if (strchr(regs[0], '/') == NULL)
1552 exitfileerror(20, "Either all arguments has to in two registers or none\n");
1555 s++;
1556 if (s[0] == s[-3] && s[1] == s[-2] + 1)
1558 s += 2;
1559 c = *s;
1561 else
1562 exitfileerror(20,
1563 "wrong register specification \"%s\" for argument %u\n",
1564 regs[regcount-1], regcount
1567 if (regcount > 2)
1568 exitfileerror(20, "maximum two arguments passed in two registers allowed\n");
1570 *s = '\0';
1572 else
1573 exitfileerror(20,
1574 "wrong register \"%s\" for argument %u\n",
1575 regs[regcount-1], regcount
1578 while (isspace(c))
1580 s++;
1581 c = *s;
1583 if (c == '\0')
1584 exitfileerror(20, "'(' without ')'\n");
1585 if (c != ',' && c != ')')
1586 exitfileerror(20, "',' or ')' expected at position %d\n", s-line+1);
1588 s++;
1591 s++;
1592 while (isspace(*s)) s++;
1593 if (*s!='\0')
1594 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1596 if (argcount != regcount)
1597 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1598 argcount, regcount
1601 (*funclistptr)->libcall = REGISTERMACRO;
1602 for (i = 0; i < argcount; i++)
1603 funcaddarg(*funclistptr, args[i], regs[i]);
1605 else if (*s == '\0')
1606 { /* No registers specified */
1607 for (i = 0; i < argcount; i++)
1608 funcaddarg(*funclistptr, args[i], NULL);
1609 cfg->intcfg |= CFG_GENASTUBS;
1611 else
1612 exitfileerror(20, "wrong char '%c' at position %d\n", *s, (int)(s-line) + 1);
1617 static void readsectionmethodlist(struct classinfo *cl)
1619 int atend = 0, i;
1620 char *line, *s, *s2;
1621 struct functionhead **methlistptr = &cl->methlist;
1622 struct stringlist *interface = NULL;
1624 if (cl->basename==NULL)
1625 exitfileerror(20, "section methodlist has to come after section config\n");
1627 while (!atend)
1629 line = readline();
1630 if (line==NULL)
1631 exitfileerror(20, "unexptected EOF in methodlist section\n");
1633 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1634 if (strlen(line)==0 || (line[0] == '#' && line[1] != '#'))
1635 continue;
1637 if (isspace(*line))
1638 exitfileerror(20, "No space allowed at start of the line\n");
1640 if (strncmp(line, "##", 2)==0) /* Is this the end ? */
1642 s = line+2;
1643 while (isspace(*s)) s++;
1644 if (strncmp(s, "end", 3)!=0)
1645 exitfileerror(20, "\"##end methodlist\" expected\n");
1647 s += 3;
1648 while (isspace(*s)) s++;
1649 if (strncmp(s, "methodlist", 10)!=0)
1650 exitfileerror(20, "\"##end methodlist\" expected\n");
1652 s += 10;
1653 while (isspace(*s)) s++;
1654 if (*s!='\0')
1655 exitfileerror(20, "unexpected character on position %d\n", s-line);
1657 atend = 1;
1659 continue;
1662 if (*line=='.')
1664 s = line+1;
1665 if (strncmp(s, "alias", 5)==0)
1667 s += 5;
1669 if (!isspace(*s))
1670 exitfileerror(20, "syntax is '.alias name'\n");
1672 while (isspace(*s)) s++;
1673 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1674 exitfileerror(20, "syntax is '.alias name'\n");
1676 s2 = s;
1677 s++;
1678 while (isalnum(*s) || *s == '_') s++;
1680 if (isspace(*s))
1682 *s = '\0';
1683 do {
1684 s++;
1685 } while (isspace(*s));
1688 if (*s != '\0')
1689 exitfileerror(20, "syntax is '.alias name'\n");
1691 if (*methlistptr == NULL)
1692 exitfileerror(20, ".alias has to come after a function declaration\n");
1694 slist_append(&(*methlistptr)->aliases, s2);
1696 else if (strncmp(s, "function", 8) == 0)
1698 s += 8;
1700 if (!isspace(*s))
1701 exitfileerror(20, "Syntax error\n");
1703 while (isspace(*s)) s++;
1704 if (*s == '\0' || !(isalpha(*s) || *s == '_'))
1705 exitfileerror(20, "syntax is '.function name'\n");
1707 s2 = s;
1708 s++;
1709 while (isalnum(*s) || *s == '_') s++;
1711 if (isspace(*s))
1713 *s = '\0';
1714 do {
1715 s++;
1716 } while (isspace(*s));
1719 if (*s != '\0')
1720 exitfileerror(20, "syntax is '.function name'\n");
1722 if (*methlistptr == NULL)
1723 exitfileerror(20, ".function has to come after a function declaration\n");
1725 funcsetinternalname(*methlistptr, s2);
1727 else if (strncmp(s, "interface", 9) == 0)
1729 if (cl->classtype != HIDD)
1730 exitfileerror(20, "interface only valid for a HIDD\n");
1732 s += 9;
1734 if (!isspace(*s))
1735 exitfileerror(20, "Syntax error\n");
1737 while (isspace(*s)) s++;
1738 if (*s == '\0' || !isalpha(*s))
1739 exitfileerror(20, "syntax is '.interface name'\n");
1741 s2 = s;
1742 s++;
1743 while (isalnum(*s) || *s == '_') s++;
1745 if (isspace(*s))
1747 *s = '\0';
1748 do {
1749 s++;
1750 } while (isspace(*s));
1753 if (*s != '\0')
1754 exitfileerror(20, "syntax is '.interface name'\n");
1756 interface = slist_append(&cl->interfaces, s2);
1758 else
1759 exitfileerror(20, "Syntax error");
1761 else if (isalpha(*line))
1763 char stmp[256];
1765 for (s = line + 1; isalnum(*s) || *s == '_'; s++)
1768 if (cl->classtype == HIDD && interface == NULL)
1769 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
1771 if (*s != '\0')
1772 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
1774 if (*methlistptr != NULL)
1775 methlistptr = &((*methlistptr)->next);
1776 if (cl->classtype != HIDD)
1778 if (snprintf(stmp, 256, "%s__%s", cl->basename, line) >= 256)
1779 exitfileerror(20, "Method name too large\n");
1781 *methlistptr = newfunctionhead(stmp, STACK);
1782 (*methlistptr)->type = "IPTR";
1783 funcaddarg(*methlistptr, "Class *cl", NULL);
1784 funcaddarg(*methlistptr, "Object *o", NULL);
1785 funcaddarg(*methlistptr, "Msg msg", NULL);
1787 else
1789 if (snprintf(stmp, 256, "%s__%s__%s", cl->basename, interface->s, line) >= 256)
1790 exitfileerror(20, "Method name too large\n");
1792 *methlistptr = newfunctionhead(stmp, STACK);
1793 (*methlistptr)->type = "IPTR";
1794 funcaddarg(*methlistptr, "OOP_Class *cl", NULL);
1795 funcaddarg(*methlistptr, "OOP_Object *o", NULL);
1796 funcaddarg(*methlistptr, "OOP_Msg msg", NULL);
1797 (*methlistptr)->interface = interface;
1798 if (snprintf(stmp, 256, "mo%s_%s", interface->s, line) >= 256)
1799 exitfileerror(20, "Method name too large\n");
1800 (*methlistptr)->method = strdup(stmp);
1802 slist_append(&(*methlistptr)->aliases, line);
1804 else
1805 exitfileerror(20, "Methodname has to begin with a letter\n");
1809 static void
1810 readsectionclass(struct config *cfg)
1812 char *s;
1813 struct classinfo *cl;
1815 cl = newclass(cfg);
1816 s = readsections(cfg, cl, 1);
1817 if (s == NULL)
1818 exitfileerror(20, "Unexpected end of file\n");
1820 if (strncmp(s, "##", 2) != 0)
1821 exitfileerror(20, "'##end class' expected\n");
1822 s += 2;
1824 while (isspace(*s)) s++;
1826 if (strncmp(s, "end", 3) != 0)
1827 exitfileerror(20, "'##end class' expected\n");
1828 s += 3;
1830 if (!isspace(*s))
1831 exitfileerror(20, "'##end class' expected\n");
1832 while (isspace(*s)) s++;
1834 if (strncmp(s, "class", 5) != 0)
1835 exitfileerror(20, "'##end class' expected\n");
1836 s += 5;
1838 while (isspace(*s)) s++;
1839 if (*s != '\0')
1840 exitfileerror(20, "'##end class' expected\n");
1843 static struct classinfo *newclass(struct config *cfg)
1845 struct classinfo *cl, *classlistit;
1847 cl = malloc(sizeof(struct classinfo));
1848 if (cl == NULL)
1850 fprintf(stderr, "Out of memory\n");
1851 exit(20);
1853 memset(cl, 0, sizeof(struct classinfo));
1855 /* By default the classes are initialized with a priority of 1 so they
1856 * are initialized before any user added initialization with priority 1
1858 cl->initpri = 1;
1860 if (cfg->classlist == NULL)
1861 cfg->classlist = cl;
1862 else
1866 classlistit = cfg->classlist;
1867 classlistit->next != NULL;
1868 classlistit = classlistit->next
1871 classlistit->next = cl;
1874 return cl;