2 Copyright © 1995-2019, The AROS Development Team. All rights reserved.
5 Code to parse the command line options and the module config file for
17 #include "functionhead.h"
20 const static char bannertemplate
[] =
22 " *** Automatically generated from '%s'. Edits will be lost. ***\n"
23 " Copyright \xA9 1995-%4u, The AROS Development Team. All rights reserved.\n"
27 getBanner(struct config
* config
)
29 static unsigned currentyear
= 0;
31 int bannerlength
= strlen(config
->conffile
) + strlen(bannertemplate
);
32 // No additional bytes needed because
33 // + 1 (NUL) + 4 (4 digit year) - strlen("%s") - strlen("%4u) = 0
35 char * banner
= malloc(bannerlength
);
41 struct tm
*utctm
= gmtime(&rawtime
);
42 currentyear
= utctm
->tm_year
+ 1900;
45 snprintf (banner
, bannerlength
, bannertemplate
, config
->conffile
, currentyear
);
51 freeBanner(char *banner
)
56 const static char usage
[] =
58 "Usage: genmodule [-c conffile] [-o configoverridefile] [-s suffix] [-d gendir] [-l library-stub gendir] [-f flavour] [-v versionextra]\n"
59 " {writefiles|writemakefile|writeincludes|writelibdefs|writefunclist|writefd|writeskel|writethunk} modname modtype\n"
62 static void readconfig(struct config
*);
63 static struct classinfo
*newclass(struct config
*);
64 static struct handlerinfo
*newhandler(struct config
*);
65 static struct interfaceinfo
*newinterface(struct config
*);
67 /* the method prefices for the supported classes */
68 static const char *muimprefix
[] =
74 static const char *gadgetmprefix
[] =
81 static const char *dtmprefix
[] =
90 /* Create a config struct. Initialize with the values from the programs command
91 * line arguments and the contents of the modules .conf file
93 struct config
*initconfig(int argc
, char **argv
)
96 char *s
, **argvit
= argv
+ 1;
99 cfg
= malloc(sizeof(struct config
));
102 fprintf(stderr
, "Out of memory\n");
106 memset(cfg
, 0, sizeof(struct config
));
108 while ((c
= getopt(argc
, argv
, ":c:o:s:d:l:f:v:")) != -1)
112 fprintf(stderr
, "Option -%c needs an argument\n",optopt
);
119 cfg
->conffile
= optarg
;
123 cfg
->confoverridefile
= optarg
;
127 cfg
->suffix
= optarg
;
132 /* Remove / at end if present */
133 if ((optarg
)[strlen(*argvit
)-1]=='/') (optarg
)[strlen(optarg
)-1]='\0';
134 cfg
->gendir
= optarg
;
138 /* Remove / at end if present */
139 if ((optarg
)[strlen(*argvit
)-1]=='/') (optarg
)[strlen(optarg
)-1]='\0';
140 cfg
->libgendir
= optarg
;
144 cfg
->flavour
= optarg
;
148 cfg
->versionextra
= optarg
;
152 fprintf(stderr
, "Internal error: Unhandled option\n");
157 if (optind
+ 3 != argc
)
159 fprintf(stderr
, "Wrong number of arguments.\n%s", usage
);
163 if (strcmp(argv
[optind
], "writefiles") == 0)
165 cfg
->command
= FILES
;
167 else if (strcmp(argv
[optind
], "writemakefile") == 0)
169 cfg
->command
= MAKEFILE
;
171 else if (strcmp(argv
[optind
], "writeincludes") == 0)
173 cfg
->command
= INCLUDES
;
175 else if (strcmp(argv
[optind
], "writelibdefs") == 0)
177 cfg
->command
= LIBDEFS
;
179 else if (strcmp(argv
[optind
], "writefunclist") == 0)
181 cfg
->command
= WRITEFUNCLIST
;
183 else if (strcmp(argv
[optind
], "writefd") == 0)
185 cfg
->command
= WRITEFD
;
187 else if (strcmp(argv
[optind
], "writeskel") == 0)
189 cfg
->command
= WRITESKEL
;
191 else if (strcmp(argv
[optind
], "writethunk") == 0)
193 cfg
->command
= WRITETHUNK
;
197 fprintf(stderr
, "Unrecognized argument \"%s\"\n%s", argv
[optind
], usage
);
202 cfg
->modulename
= argv
[optind
+1];
203 cfg
->modulenameupper
= strdup(cfg
->modulename
);
204 for (s
=cfg
->modulenameupper
; *s
!='\0'; *s
= toupper(*s
), s
++) {
205 if (!isalnum(*s
)) *s
= '_';
208 if (strcmp(argv
[optind
+2],"library")==0)
210 cfg
->modtype
= LIBRARY
;
211 cfg
->moddir
= "Libs";
213 else if (strcmp(argv
[optind
+2],"mcc")==0)
216 cfg
->moddir
= "Classes/Zune";
218 else if (strcmp(argv
[optind
+2],"mui")==0)
221 cfg
->moddir
= "Classes/Zune";
223 else if (strcmp(argv
[optind
+2],"mcp")==0)
226 cfg
->moddir
= "Classes/Zune";
228 else if (strcmp(argv
[optind
+2], "device")==0)
230 cfg
->modtype
= DEVICE
;
231 cfg
->moddir
= "Devs";
233 else if (strcmp(argv
[optind
+2], "resource")==0)
235 cfg
->modtype
= RESOURCE
;
236 cfg
->moddir
= "Devs";
238 else if (strcmp(argv
[optind
+2], "gadget")==0)
240 cfg
->modtype
= GADGET
;
241 cfg
->moddir
= "Classes/Gadgets";
243 else if (strcmp(argv
[optind
+2], "datatype")==0)
245 cfg
->modtype
= DATATYPE
;
246 cfg
->moddir
= "Classes/DataTypes";
248 else if (strcmp(argv
[optind
+2], "usbclass")==0)
250 cfg
->modtype
= USBCLASS
;
251 cfg
->moddir
= "Classes/USB";
254 cfg
->suffix
= "class";
258 else if (strcmp(argv
[optind
+2], "hidd")==0)
261 cfg
->moddir
= "Devs/Drivers";
263 else if (strcmp(argv
[optind
+2], "handler")==0)
265 cfg
->modtype
= HANDLER
;
266 cfg
->moddir
= "$(AROS_DIR_FS)";
268 else if (strcmp(argv
[optind
+2], "hook")==0)
270 cfg
->modtype
= HANDLER
;
271 cfg
->moddir
= "Devs";
275 fprintf(stderr
, "Unknown modtype \"%s\" specified for second argument\n", argv
[optind
+2]);
278 cfg
->modtypestr
= argv
[optind
+2];
281 cfg
->suffix
= argv
[optind
+2];
283 /* Fill fields with default value if not specified on the command line */
287 if (cfg
->conffile
== NULL
)
289 snprintf(tmpbuf
, sizeof(tmpbuf
), "%s.conf", cfg
->modulename
);
290 cfg
->conffile
= strdup(tmpbuf
);
293 if (cfg
->gendir
== NULL
)
296 if (cfg
->libgendir
== NULL
)
297 cfg
->libgendir
= cfg
->gendir
;
302 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
303 * if they are provided
305 if (cfg
->beginiofunc
!= NULL
)
307 struct functionhead
*funchead
;
309 cfg
->intcfg
|= CFG_NOREADFUNCS
;
311 /* Add beginio_func to the list of functions */
312 funchead
= newfunctionhead(cfg
->beginiofunc
, REGISTERMACRO
);
313 funchead
->type
= strdup("void");
315 funcaddarg(funchead
, "struct IORequest *ioreq", "A1");
317 funchead
->next
= cfg
->funclist
;
318 cfg
->funclist
= funchead
;
320 /* Add abortio_func to the list of functions */
321 funchead
= newfunctionhead(cfg
->abortiofunc
, REGISTERMACRO
);
322 funchead
->type
= strdup("LONG");
324 funcaddarg(funchead
, "struct IORequest *ioreq", "A1");
326 funchead
->next
= cfg
->funclist
->next
;
327 cfg
->funclist
->next
= funchead
;
329 else if (cfg
->modtype
== DEVICE
&& cfg
->intcfg
& CFG_NOREADFUNCS
)
334 "beginio_func and abortio_func missing for a device with a non empty function list\n"
339 /* See if we have any stackcall options */
341 struct functionhead
*funchead
;
343 for (funchead
= cfg
->funclist
; funchead
; funchead
= funchead
->next
) {
344 if (funchead
->libcall
== STACK
) {
345 cfg
->options
|= OPTION_STACKCALL
;
351 /* Provide default version for functions that didnt have it */
353 struct functionhead
*funchead
;
354 int defversion
= cfg
->majorversion
; /* Assume library version is default */
356 for (funchead
= cfg
->funclist
; funchead
; funchead
= funchead
->next
) {
357 if (funchead
->version
> -1) {
358 /* There was at least one .version tag. Assume 0 is default */
364 for (funchead
= cfg
->funclist
; funchead
; funchead
= funchead
->next
) {
365 if (funchead
->version
== -1) {
366 funchead
->version
= defversion
;
371 /* Verify that a handler has a handler */
372 if (cfg
->modtype
== HANDLER
) {
373 if (cfg
->handlerfunc
== NULL
) {
374 fprintf(stderr
, "handler modules require a 'handler_func' ##config option\n");
377 cfg
->options
|= OPTION_NOAUTOLIB
| OPTION_NOEXPUNGE
| OPTION_NOOPENCLOSE
;
383 /* Functions to read configuration from the configuration file */
385 #include "fileread.h"
387 static char *readsections(struct config
*, struct classinfo
*cl
, struct interfaceinfo
*in
, int inclass
, int inoverride
);
388 static void readsectionconfig(struct config
*, struct classinfo
*cl
, struct interfaceinfo
*in
, int inclass
, int inoverride
);
389 static void readsectioncdef(struct config
*);
390 static void readsectioncdefprivate(struct config
*);
391 static void readsectionstubprivate(struct config
*);
392 static void readsectionstartup(struct config
*);
393 static void readsectionfunctionlist(const char *type
, struct functionhead
**funclistptr
, unsigned int firstlvo
, int isattribute
, enum libcall def_libcall
);
394 static void readsectionclass_methodlist(struct classinfo
*);
395 static void readsectionclass(struct config
*);
396 static void readsectionhandler(struct config
*);
397 static void readsectioninterface(struct config
*);
399 static void readconfig(struct config
*cfg
)
401 struct classinfo
*mainclass
= NULL
;
403 /* Create a classinfo structure if this module is a class */
404 switch (cfg
->modtype
)
419 mainclass
= newclass(cfg
);
420 mainclass
->classtype
= cfg
->modtype
;
424 fprintf(stderr
, "Internal error: unsupported modtype for classinfo creation\n");
428 switch (cfg
->modtype
)
441 mainclass
->boopsimprefix
= muimprefix
;
449 mainclass
->boopsimprefix
= gadgetmprefix
;
453 mainclass
->boopsimprefix
= dtmprefix
;
457 /* FIXME: need boopsimprefix ? */
460 fprintf(stderr
, "Internal error: unsupported modtype for firstlvo\n");
464 if (!fileopen(cfg
->conffile
))
466 fprintf(stderr
, "In readconfig: Could not open %s\n", cfg
->conffile
);
470 /* Read all sections and see that we are at the end of the file */
471 if (readsections(cfg
, mainclass
, NULL
, 0, 0) != NULL
)
472 exitfileerror(20, "Syntax error");
477 /* readsections will scan through all the sections in the config file.
479 * struct config *cfg: The module config data which may be updated by
480 * the information in the sections
481 * struct classinfo *cl: The classdata to be filled with data from the sections.
482 * This may be NULL if this is the main part of the configuration file and the
483 * type of the module is not a class
484 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
485 * part of the config file.
487 static char *readsections(struct config
*cfg
, struct classinfo
*cl
, struct interfaceinfo
*in
, int inclass
, int inoverride
)
492 while ((line
=readline())!=NULL
)
494 if (strncmp(line
, "##", 2)==0)
496 static char *parts
[] =
498 "config", "cdefprivate", "cdef", "stubprivate", "startup", "functionlist", "methodlist", "class", "handler", "interface", "attributelist", "cfunctionlist"
500 const unsigned int nums
= sizeof(parts
)/sizeof(char *);
501 unsigned int partnum
;
505 while (isspace(*s
)) s
++;
507 if (strncmp(s
, "begin", 5)!=0)
512 exitfileerror(20, "space after begin expected\n");
513 while (isspace(*s
)) s
++;
515 for (i
= 0, partnum
= 0; partnum
==0 && i
<nums
; i
++)
517 if (strncmp(s
, parts
[i
], strlen(parts
[i
]))==0)
520 s
+= strlen(parts
[i
]);
521 while (isspace(*s
)) s
++;
523 exitfileerror(20, "unexpected character on position %d\n", s
-line
);
527 exitfileerror(20, "unknown start of section\n");
531 readsectionconfig(cfg
, cl
, in
, inclass
, inoverride
);
535 case 2: /* cdefprivate */
537 exitfileerror(20, "cdefprivate section not allowed in class section\n");
538 readsectioncdefprivate(cfg
);
543 exitfileerror(20, "cdef section not allowed in class section\n");
544 readsectioncdef(cfg
);
547 case 4: /* stubprivate */
549 exitfileerror(20, "stubprivate section not allowed in class section\n");
550 readsectionstubprivate(cfg
);
553 case 5: /* startup */
555 exitfileerror(20, "startup section not allowed in class section\n");
556 readsectionstartup(cfg
);
559 case 6: /* functionlist */
561 exitfileerror(20, "functionlist section not allow in class section\n");
562 if (cfg
->basename
==NULL
)
563 exitfileerror(20, "section functionlist has to come after section config\n");
565 readsectionfunctionlist("functionlist", &cfg
->funclist
, cfg
->firstlvo
, 0, REGISTERMACRO
);
566 cfg
->intcfg
|= CFG_NOREADFUNCS
;
569 case 7: /* methodlist */
570 if (cl
== NULL
&& in
== NULL
)
571 exitfileerror(20, "methodlist section when not in a class or interface\n");
573 readsectionclass_methodlist(cl
);
575 readsectionfunctionlist("methodlist", &in
->methodlist
, 0, 0, REGISTERMACRO
);
576 cfg
->intcfg
|= CFG_NOREADFUNCS
;
581 exitfileerror(20, "class section may not be in nested\n");
582 readsectionclass(cfg
);
585 case 9: /* handler */
586 readsectionhandler(cfg
);
589 case 10: /* interface */
591 exitfileerror(20, "interface section may not be nested\n");
592 readsectioninterface(cfg
);
595 case 11: /* attributelist */
597 exitfileerror(20, "attributelist only valid in interface sections\n");
598 readsectionfunctionlist("attributelist", &in
->attributelist
, 0, 1, INVALID
);
601 case 12: /* cfunctionlist */
603 exitfileerror(20, "cfunctionlist section not allow in class section\n");
604 if (cfg
->basename
==NULL
)
605 exitfileerror(20, "section cfunctionlist has to come after section config\n");
607 readsectionfunctionlist("cfunctionlist", &cfg
->funclist
, cfg
->firstlvo
, 0, REGISTER
);
608 cfg
->intcfg
|= CFG_NOREADFUNCS
;
612 else if (strlen(line
)!=0)
613 filewarning("warning line outside section ignored\n");
619 exitfileerror(20, "No config section in conffile\n");
621 /* If no indication was given for generating includes or not
622 decide on module type and if there are functions
624 if(!((cfg
->options
& OPTION_INCLUDES
) || (cfg
->options
& OPTION_NOINCLUDES
)))
626 switch (cfg
->modtype
)
630 cfg
->options
|= OPTION_INCLUDES
;
638 cfg
->options
|= OPTION_NOINCLUDES
;
643 (cfg
->funclist
!= NULL
)
644 || (cfg
->cdeflines
!= NULL
)
645 || strcmp(cfg
->libbasetypeptrextern
, "struct Device *") != 0
646 ) ? OPTION_INCLUDES
: OPTION_NOINCLUDES
;
653 (cfg
->funclist
!= NULL
)
654 ) ? OPTION_INCLUDES
: OPTION_NOINCLUDES
;
658 fprintf(stderr
, "Internal error writemakefile: unhandled modtype for includes\n");
664 /* If no indication was given for not generating stubs only generate them if
665 * the module has functions
667 if(!((cfg
->options
& OPTION_STUBS
) || (cfg
->options
& OPTION_NOSTUBS
)))
669 switch (cfg
->modtype
)
672 cfg
->options
|= (cfg
->funclist
!= NULL
) ? OPTION_STUBS
: OPTION_NOSTUBS
;
685 cfg
->options
|= OPTION_NOSTUBS
;
689 fprintf(stderr
, "Internal error writemakefile: unhandled modtype for stubs\n");
695 /* If no indication was given for generating autoinit code or not
696 decide on module type
698 if(!((cfg
->options
& OPTION_AUTOINIT
) || (cfg
->options
& OPTION_NOAUTOINIT
)))
700 switch (cfg
->modtype
)
703 cfg
->options
|= OPTION_AUTOINIT
;
716 cfg
->options
|= OPTION_NOAUTOINIT
;
720 fprintf(stderr
, "Internal error writemakefile: unhandled modtype for autoinit\n");
726 if ((cfg
->modtype
== RESOURCE
) || (cfg
->modtype
== HANDLER
))
727 /* Enforce noopenclose for resources and handlers */
728 cfg
->options
|= OPTION_NOOPENCLOSE
;
729 else if (!(cfg
->options
& OPTION_SELFINIT
))
730 /* Enforce using RTF_AUTOINIT for everything except resources */
731 cfg
->options
|= OPTION_RESAUTOINIT
;
737 static void readsectionconfig(struct config
*cfg
, struct classinfo
*cl
, struct interfaceinfo
*in
, int inclass
, int inoverride
)
740 char *line
, *s
, *s2
, *libbasetypeextern
= NULL
;
747 exitfileerror(20, "unexpected end of file in section config\n");
749 if (strncmp(line
, "##", 2)!=0)
751 const char *names
[] =
753 "basename", "libbase", "libbasetype", "libbasetypeextern",
754 "version", "date", "copyright", "libcall", "forcebase", "superclass",
755 "superclass_field", "residentpri", "options", "sysbase_field",
756 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
757 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
758 "initpri", "type", "addromtag", "oopbase_field",
759 "rellib", "interfaceid", "interfacename",
760 "methodstub", "methodbase", "attributebase", "handler_func",
763 const unsigned int namenums
= sizeof(names
)/sizeof(char *);
764 unsigned int namenum
;
766 for (i
= 0, namenum
= 0; namenum
==0 && i
<namenums
; i
++)
770 strncmp(line
, names
[i
], strlen(names
[i
]))==0
771 && isspace(*(line
+strlen(names
[i
])))
776 exitfileerror(20, "unrecognized configuration option\n");
778 s
= line
+ strlen(names
[namenum
-1]);
780 exitfileerror(20, "space character expected after \"%s\"\n", names
[namenum
-1]);
782 while (isspace(*s
)) s
++;
784 exitfileerror(20, "unexpected end of line\n");
787 while (isspace(*(s2
-1))) s2
--;
792 case 1: /* basename */
794 cfg
->basename
= strdup(s
);
796 cl
->basename
= strdup(s
);
798 exitfileerror(20, "basename not valid config option when in an interface section\n");
801 case 2: /* libbase */
803 exitfileerror(20, "libbase not valid config option when in a class section\n");
804 cfg
->libbase
= strdup(s
);
807 case 3: /* libbasetype */
809 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
810 cfg
->libbasetype
= strdup(s
);
813 case 4: /* libbasetypeextern */
815 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
816 libbasetypeextern
= strdup(s
);
819 case 5: /* version */
821 exitfileerror(20, "version not valid config option when in a class section\n");
822 if (sscanf(s
, "%u.%u", &cfg
->majorversion
, &cfg
->minorversion
)!=2)
823 exitfileerror(20, "wrong version string \"%s\"\n", s
);
828 exitfileerror(20, "date not valid config option when in a class section\n");
830 if (strptime(s
, "%e.%m.%Y", &date
) == NULL
)
832 exitfileerror(20, "date string has to have d.m.yyyy format\n");
835 cfg
->datestring
= strdup(s
);
838 case 7: /* copyright */
840 exitfileerror(20, "copyright not valid config option when in a class section\n");
841 cfg
->copyright
= strdup(s
);
844 case 8: /* libcall */
845 fprintf(stderr
, "libcall specification is deprecated and ignored\n");
848 case 9: /* forcebase */
850 exitfileerror(20, "forcebase not valid config option when in a class section\n");
851 slist_append(&cfg
->forcelist
, s
);
854 case 10: /* superclass */
856 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
857 cl
->superclass
= strdup(s
);
860 case 11: /* superclass_field */
862 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
863 cl
->superclass_field
= strdup(s
);
866 case 12: /* residentpri */
872 count
= sscanf(s
, "%d%c", &cfg
->residentpri
, &dummy
);
874 cfg
->residentpri
< -128 || cfg
->residentpri
> 127
877 exitfileerror(20, "residentpri number format error\n");
881 exitfileerror(20, "residentpri not valid config option when in a class section\n");
884 case 13: /* options */
887 static const char *optionnames
[] =
889 "noautolib", "noexpunge", "noresident", "peropenerbase",
890 "pertaskbase", "includes", "noincludes", "nostubs",
891 "autoinit", "noautoinit", "resautoinit", "noopenclose",
892 "selfinit", "rellinklib"
894 const unsigned int optionnums
= sizeof(optionnames
)/sizeof(char *);
899 for (i
= 0, optionnum
= 0; optionnum
==0 && i
<optionnums
; i
++)
901 if (strncmp(s
, optionnames
[i
], strlen(optionnames
[i
]))==0)
904 s
+= strlen(optionnames
[i
]);
905 while (isspace(*s
)) s
++;
909 exitfileerror(20, "Unrecognized option\n");
913 exitfileerror(20, "Unrecognized option\n");
916 case 1: /* noautolib */
917 cfg
->options
|= OPTION_NOAUTOLIB
;
919 case 2: /* noexpunge */
920 cfg
->options
|= OPTION_NOEXPUNGE
;
922 case 3: /* noresident */
923 cfg
->options
|= OPTION_NORESIDENT
;
926 case 5: /* pertaskbase */
927 cfg
->options
|= OPTION_PERTASKBASE
;
929 case 4: /* peropenerbase */
930 if (cfg
->options
& OPTION_DUPBASE
)
931 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
932 cfg
->options
|= OPTION_DUPBASE
;
934 case 6: /* includes */
935 if (cfg
->options
& OPTION_NOINCLUDES
)
936 exitfileerror(20, "option includes and noincludes are incompatible\n");
937 cfg
->options
|= OPTION_INCLUDES
;
939 case 7: /* noincludes */
940 if (cfg
->options
& OPTION_INCLUDES
)
941 exitfileerror(20, "option includes and noincludes are incompatible\n");
942 cfg
->options
|= OPTION_NOINCLUDES
;
944 case 8: /* nostubs */
945 cfg
->options
|= OPTION_NOSTUBS
;
947 case 9: /* autoinit */
948 if (cfg
->options
& OPTION_NOAUTOINIT
)
949 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
950 cfg
->options
|= OPTION_AUTOINIT
;
952 case 10: /* noautoinit */
953 if (cfg
->options
& OPTION_AUTOINIT
)
954 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
955 cfg
->options
|= OPTION_NOAUTOINIT
;
957 case 11: /* resautoinit */
958 if (cfg
->options
& OPTION_SELFINIT
)
959 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
960 cfg
->options
|= OPTION_RESAUTOINIT
;
963 cfg
->options
|= OPTION_NOOPENCLOSE
;
965 case 13: /* noresautoinit */
966 if (cfg
->options
& OPTION_RESAUTOINIT
)
967 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
968 cfg
->options
|= OPTION_SELFINIT
;
970 case 14: /* rellinklib */
971 cfg
->options
|= OPTION_RELLINKLIB
;
974 while (isspace(*s
)) s
++;
979 static const char *optionnames
[] =
983 const unsigned int optionnums
= sizeof(optionnames
)/sizeof(char *);
988 for (i
= 0, optionnum
= 0; optionnum
==0 && i
<optionnums
; i
++)
990 if (strncmp(s
, optionnames
[i
], strlen(optionnames
[i
]))==0)
993 s
+= strlen(optionnames
[i
]);
994 while (isspace(*s
)) s
++;
998 exitfileerror(20, "Unrecognized option\n");
1002 exitfileerror(20, "Unrecognized option\n");
1005 case 1: /* private */
1006 cl
->options
|= COPTION_PRIVATE
;
1009 while (isspace(*s
)) s
++;
1014 case 14: /* sysbase_field */
1016 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
1017 cfg
->sysbase_field
= strdup(s
);
1020 case 15: /* seglist_field */
1022 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
1023 cfg
->seglist_field
= strdup(s
);
1026 case 16: /* rootbase_field */
1028 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
1029 cfg
->rootbase_field
= strdup(s
);
1032 case 17: /* classptr_field */
1038 "classptr_field specified when not a BOOPSI class\n"
1041 cl
->classptr_field
= strdup(s
);
1044 case 18: /* classptr_var */
1050 "classptr_var specified when not a BOOPSI class\n"
1053 cl
->classptr_var
= strdup(s
);
1056 case 19: /* classid */
1058 exitfileerror(20, "classid specified when not a BOOPSI class\n");
1059 if (cl
->classid
!= NULL
)
1060 exitfileerror(20, "classid specified twice\n");
1061 cl
->classid
= strdup(s
);
1062 if (strcmp(cl
->classid
, "NULL") == 0)
1063 cl
->options
|= COPTION_PRIVATE
;
1066 case 20: /* classdatatype */
1068 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
1069 cl
->classdatatype
= strdup(s
);
1072 case 21: /* beginio_func */
1074 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
1075 if (cfg
->modtype
!= DEVICE
)
1076 exitfileerror(20, "beginio_func specified when not a device\n");
1077 cfg
->beginiofunc
= strdup(s
);
1080 case 22: /* abortio_func */
1082 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
1083 if (cfg
->modtype
!= DEVICE
)
1084 exitfileerror(20, "abortio_func specified when not a device\n");
1085 cfg
->abortiofunc
= strdup(s
);
1088 case 23: /* dispatcher */
1090 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
1091 cl
->dispatcher
= strdup(s
);
1092 /* function references are not needed when dispatcher is specified */
1093 cfg
->intcfg
|= CFG_NOREADFUNCS
;
1096 case 24: /* initpri */
1102 count
= sscanf(s
, "%d%c", &cl
->initpri
, &dummy
);
1104 cl
->initpri
< -128 || cl
->initpri
> 127
1107 exitfileerror(20, "initpri number format error\n");
1111 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
1116 exitfileerror(20, "type only valid config option in a class section\n");
1117 if (strcmp(s
,"mcc")==0)
1118 cl
->classtype
= MCC
;
1119 else if (strcmp(s
,"mui")==0)
1120 cl
->classtype
= MUI
;
1121 else if (strcmp(s
,"mcp")==0)
1122 cl
->classtype
= MCP
;
1123 else if (strcmp(s
, "image")==0)
1124 cl
->classtype
= IMAGE
;
1125 else if (strcmp(s
, "gadget")==0)
1126 cl
->classtype
= GADGET
;
1127 else if (strcmp(s
, "datatype")==0)
1128 cl
->classtype
= DATATYPE
;
1129 else if (strcmp(s
, "usbclass")==0)
1130 cl
->classtype
= USBCLASS
;
1131 else if (strcmp(s
, "class")==0)
1132 cl
->classtype
= CLASS
;
1133 else if (strcmp(s
, "hidd")==0)
1134 cl
->classtype
= HIDD
;
1137 fprintf(stderr
, "Unknown type \"%s\" specified\n", s
);
1142 case 26: /* addromtag */
1143 cfg
->addromtag
= strdup(s
);
1146 case 27: /* oopbase_field */
1147 cfg
->oopbase_field
= strdup(s
);
1149 case 28: /* rellib */
1150 slist_append(&cfg
->rellibs
, s
);
1152 case 29: /* interfaceid */
1154 exitfileerror(20, "interfaceid only valid config option for an interface\n");
1155 in
->interfaceid
= strdup(s
);
1157 case 30: /* interfacename */
1159 exitfileerror(20, "interfacename only valid config option for an interface\n");
1160 in
->interfacename
= strdup(s
);
1162 case 31: /* methodstub */
1164 exitfileerror(20, "methodstub only valid config option for an interface\n");
1165 in
->methodstub
= strdup(s
);
1167 case 32: /* methodbase */
1169 exitfileerror(20, "methodbase only valid config option for an interface\n");
1170 in
->methodbase
= strdup(s
);
1172 case 33: /* attributebase */
1174 exitfileerror(20, "attributebase only valid config option for an interface\n");
1175 in
->attributebase
= strdup(s
);
1177 case 34: /* handler_func */
1178 if (cfg
->modtype
!= HANDLER
)
1179 exitfileerror(20, "handler specified when not a handler\n");
1180 cfg
->handlerfunc
= strdup(s
);
1182 case 35: /* includename */
1184 exitfileerror(20, "includename not valid config option"
1185 " when in a class section\n");
1186 cfg
->includename
= strdup(s
);
1190 else /* Line starts with ## */
1193 while (isspace(*s
)) s
++;
1194 if (strncmp(s
, "end", 3)!=0)
1195 exitfileerror(20, "\"##end config\" expected\n");
1199 exitfileerror(20, "\"##end config\" expected\n");
1201 while (isspace(*s
)) s
++;
1202 if (strncmp(s
, "config", 6)!=0)
1203 exitfileerror(20, "\"##end config\" expected\n");
1206 while (isspace(*s
)) s
++;
1208 exitfileerror(20, "\"##end config\" expected\n");
1214 /* When not in a class section fill in default values for fields in cfg */
1217 if (cfg
->basename
==NULL
)
1219 cfg
->basename
= strdup(cfg
->modulename
);
1220 *cfg
->basename
= toupper(*cfg
->basename
);
1222 if (cfg
->libbase
==NULL
)
1224 unsigned int len
= strlen(cfg
->basename
)+5;
1225 cfg
->libbase
= malloc(len
);
1226 snprintf(cfg
->libbase
, len
, "%sBase", cfg
->basename
);
1228 if (cfg
->libbasetype
== NULL
&& libbasetypeextern
!= NULL
)
1229 cfg
->libbasetype
= strdup(libbasetypeextern
);
1230 if (cfg
->sysbase_field
!= NULL
&& cfg
->libbasetype
== NULL
)
1231 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1232 if (cfg
->seglist_field
!= NULL
&& cfg
->libbasetype
== NULL
)
1233 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1234 if (cfg
->oopbase_field
!= NULL
&& cfg
->libbasetype
== NULL
)
1235 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1236 /* rootbase_field only allowed when duplicating base */
1237 if (cfg
->rootbase_field
!= NULL
&& !(cfg
->options
& OPTION_DUPBASE
))
1238 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1240 /* Set default date to current date */
1241 if (cfg
->datestring
== NULL
)
1244 time_t now
= time(NULL
);
1245 struct tm
*ltime
= localtime(&now
);
1247 snprintf(tmpbuf
, sizeof(tmpbuf
), "%u.%u.%u",
1248 ltime
->tm_mday
, 1 + ltime
->tm_mon
, 1900 + ltime
->tm_year
);
1250 cfg
->datestring
= strdup(tmpbuf
);
1253 if (cfg
->copyright
== NULL
)
1254 cfg
->copyright
= "";
1256 if ( (cfg
->beginiofunc
!= NULL
&& cfg
->abortiofunc
== NULL
)
1257 || (cfg
->beginiofunc
== NULL
&& cfg
->abortiofunc
!= NULL
)
1259 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1261 if (libbasetypeextern
==NULL
)
1263 switch (cfg
->modtype
)
1266 cfg
->libbasetypeptrextern
= "struct Device *";
1270 cfg
->libbasetypeptrextern
= "APTR ";
1280 cfg
->libbasetypeptrextern
= "struct Library *";
1283 fprintf(stderr
, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1289 cfg
->libbasetypeptrextern
= malloc(strlen(libbasetypeextern
)+3);
1290 strcpy(cfg
->libbasetypeptrextern
, libbasetypeextern
);
1291 strcat(cfg
->libbasetypeptrextern
, " *");
1292 free(libbasetypeextern
);
1295 if (cfg
->includename
== NULL
)
1296 cfg
->includename
= cfg
->modulename
;
1297 cfg
->includenameupper
= strdup(cfg
->includename
);
1298 for (s
=cfg
->includenameupper
; *s
!='\0'; *s
= toupper(*s
), s
++)
1299 if (!isalnum(*s
)) *s
= '_';
1302 /* When class was given too fill in some defaults when not specified */
1305 if (cl
->classtype
== UNSPECIFIED
)
1306 cl
->classtype
= CLASS
;
1308 if (cl
->basename
== NULL
)
1311 cl
->basename
= cfg
->basename
;
1313 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1316 /* MUI classes are always private */
1317 if (cl
->classtype
== MUI
|| cl
->classtype
== MCC
|| cl
->classtype
== MCP
)
1318 cl
->options
|= COPTION_PRIVATE
;
1320 if (cl
->classid
== NULL
1321 && (cl
->classtype
!= MUI
&& cl
->classtype
!= MCC
&& cl
->classtype
!= MCP
)
1324 if (cl
->classtype
== HIDD
)
1326 cl
->options
&= !COPTION_PRIVATE
;
1328 else if (cl
->options
& COPTION_PRIVATE
)
1330 cl
->classid
= "NULL";
1336 if (cl
->classtype
== GADGET
|| cl
->classtype
== IMAGE
|| cl
->classtype
== CLASS
|| cl
->classtype
== USBCLASS
)
1338 sprintf(s
, "\"%sclass\"", inclass
? cl
->basename
: cfg
->modulename
);
1340 else if (cl
->classtype
== DATATYPE
)
1342 sprintf(s
, "\"%s.datatype\"", inclass
? cl
->basename
: cfg
->modulename
);
1344 cl
->classid
= strdup(s
);
1348 /* Only specify superclass or superclass_field */
1349 if (cl
->superclass
!= NULL
&& cl
->superclass_field
!= NULL
)
1350 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1352 /* Give default value to superclass if it is not specified */
1353 if (cl
->superclass
== NULL
&& cl
->superclass
== NULL
)
1355 switch (cl
->classtype
)
1359 cl
->superclass
= "MUIC_Area";
1362 cl
->superclass
= "MUIC_Mccprefs";
1365 cl
->superclass
= "IMAGECLASS";
1368 cl
->superclass
= "GADGETCLASS";
1371 cl
->superclass
= "DATATYPESCLASS";
1374 cl
->superclass
= "ROOTCLASS";
1377 cl
->superclass
= "CLID_Root";
1380 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1387 static void readsectioncdef(struct config
*cfg
)
1396 exitfileerror(20, "unexptected end of file in section cdef\n");
1398 if (strncmp(line
, "##", 2)!=0)
1400 slist_append(&cfg
->cdeflines
, line
);
1405 while (isspace(*s
)) s
++;
1406 if (strncmp(s
, "end", 3)!=0)
1407 exitfileerror(20, "\"##end cdef\" expected\n");
1410 while (isspace(*s
)) s
++;
1411 if (strncmp(s
, "cdef", 4)!=0)
1412 exitfileerror(20, "\"##end cdef\" expected\n");
1415 while (isspace(*s
)) s
++;
1417 exitfileerror(20, "unexpected character at position %d\n");
1425 static void readsectionstubprivate(struct config
*cfg
)
1434 exitfileerror(20, "unexptected end of file in section stubprivate\n");
1436 if (strncmp(line
, "##", 2)!=0)
1438 slist_append(&cfg
->stubprivatelines
, line
);
1443 while (isspace(*s
)) s
++;
1444 if (strncmp(s
, "end", 3)!=0)
1445 exitfileerror(20, "\"##end stubprivate\" expected\n");
1448 while (isspace(*s
)) s
++;
1449 if (strncmp(s
, "stubprivate", 11)!=0)
1450 exitfileerror(20, "\"##end stubprivate\" expected\n");
1453 while (isspace(*s
)) s
++;
1455 exitfileerror(20, "unexpected character at position %d\n");
1462 static void readsectioncdefprivate(struct config
*cfg
)
1471 exitfileerror(20, "unexptected end of file in section cdefprivate\n");
1473 if (strncmp(line
, "##", 2)!=0)
1475 slist_append(&cfg
->cdefprivatelines
, line
);
1480 while (isspace(*s
)) s
++;
1481 if (strncmp(s
, "end", 3)!=0)
1482 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1485 while (isspace(*s
)) s
++;
1486 if (strncmp(s
, "cdefprivate", 11)!=0)
1487 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1490 while (isspace(*s
)) s
++;
1492 exitfileerror(20, "unexpected character at position %d\n");
1499 static void readsectionstartup(struct config
*cfg
)
1508 exitfileerror(20, "unexptected end of file in section startup\n");
1510 if (strncmp(line
, "##", 2)!=0)
1512 slist_append(&cfg
->startuplines
, line
);
1517 while (isspace(*s
)) s
++;
1518 if (strncmp(s
, "end", 3)!=0)
1519 exitfileerror(20, "\"##end startup\" expected\n");
1522 while (isspace(*s
)) s
++;
1523 if (strncmp(s
, "startup", 7)!=0)
1524 exitfileerror(20, "\"##end startup\" expected\n");
1527 while (isspace(*s
)) s
++;
1529 exitfileerror(20, "unexpected character at position %d\n");
1536 static void readsectionfunctionlist(const char *type
, struct functionhead
**funclistptr
, unsigned int firstlvo
, int isattribute
, enum libcall def_libcall
)
1539 char *line
, *s
, *s2
;
1540 unsigned int lvo
= firstlvo
;
1541 int minversion
= -1;
1547 exitfileerror(20, "unexpected EOF in functionlist section\n");
1548 if (strlen(line
)==0)
1550 if (*funclistptr
!= NULL
)
1551 funclistptr
= &((*funclistptr
)->next
);
1554 else if (isspace(*line
))
1557 while (isspace(*s
)) s
++;
1560 if (*funclistptr
!= NULL
)
1561 funclistptr
= &((*funclistptr
)->next
);
1565 exitfileerror(20, "no space allowed before functionname\n");
1567 else if (strncmp(line
, "##", 2)==0)
1570 while (isspace(*s
)) s
++;
1571 if (strncmp(s
, "end", 3)!=0)
1572 exitfileerror(20, "\"##end %s\" expected\n", type
);
1575 while (isspace(*s
)) s
++;
1576 if (strncmp(s
, type
, strlen(type
))!=0)
1577 exitfileerror(20, "\"##end %s\" expected\n", type
);
1580 while (isspace(*s
)) s
++;
1582 exitfileerror(20, "unexpected character on position %d\n", s
-line
);
1586 else if (*line
=='.')
1589 if (strncmp(s
, "skip", 4)==0)
1595 exitfileerror(20, "syntax is '.skip n'\n");
1597 n
=strtol(s
, &s2
, 10);
1599 exitfileerror(20, "positive number expected\n");
1601 while (isspace(*s2
)) s2
++;
1602 if ((*s2
!= '\0') && (*s2
!= '#'))
1603 exitfileerror(20, "syntax is '.skip n'\n");
1604 if (*funclistptr
!= NULL
)
1605 funclistptr
= &((*funclistptr
)->next
);
1608 else if (strncmp(s
, "alias", 5)==0)
1613 exitfileerror(20, "syntax is '.alias name'\n");
1615 while (isspace(*s
)) s
++;
1616 if (*s
== '\0' || !(isalpha(*s
) || *s
== '_'))
1617 exitfileerror(20, "syntax is '.alias name'\n");
1621 while (isalnum(*s
) || *s
== '_') s
++;
1628 } while (isspace(*s
));
1632 exitfileerror(20, "syntax is '.alias name'\n");
1634 if (*funclistptr
== NULL
)
1635 exitfileerror(20, ".alias has to come after a function declaration\n");
1637 slist_append(&(*funclistptr
)->aliases
, s2
);
1639 else if (strncmp(s
, "function", 8) == 0)
1644 exitfileerror(20, "Syntax error\n");
1646 while (isspace(*s
)) s
++;
1647 if (*s
== '\0' || !(isalpha(*s
) || *s
== '_'))
1648 exitfileerror(20, "syntax is '.function name'\n");
1652 while (isalnum(*s
) || *s
== '_') s
++;
1659 } while (isspace(*s
));
1663 exitfileerror(20, "syntax is '.function name'\n");
1665 if (*funclistptr
== NULL
)
1666 exitfileerror(20, ".function has to come after a function declaration\n");
1668 funcsetinternalname(*funclistptr
, s2
);
1670 else if (strncmp(s
, "cfunction", 9)==0)
1672 if (*funclistptr
== NULL
)
1673 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1675 (*funclistptr
)->libcall
= REGISTER
;
1677 else if (strncmp(s
, "private", 7)==0)
1679 if (*funclistptr
== NULL
)
1680 exitfileerror(20, ".private has to come after a function declaration\n");
1682 (*funclistptr
)->priv
= 1;
1684 else if (strncmp(s
, "novararg", 8)==0)
1686 if (*funclistptr
== NULL
)
1687 exitfileerror(20, ".novararg has to come after a function declaration\n");
1689 (*funclistptr
)->novararg
= 1;
1691 else if (strncmp(s
, "version", 7) == 0)
1693 /* Mark version number for the following
1694 * functions, so that the automatic OpenLibrary()
1695 * will know what version to use.
1702 while (isspace(*s
)) s
++;
1703 ver
= (int)strtol(s
, &tmp
, 0);
1706 exitfileerror(20, ".version expects an integer\n");
1709 while (isspace(*s
)) s
++;
1711 if (*s
&& *s
!= '#')
1712 exitfileerror(20, ".version has junk after the version number\n");
1716 else if (strncmp(s
, "unusedlibbase", 13) == 0)
1718 if (*funclistptr
== NULL
)
1719 exitfileerror(20, ".unusedlibbase has to come after a function declaration\n");
1720 (*funclistptr
)->unusedlibbase
= 1;
1723 exitfileerror(20, "Syntax error");
1725 else if (*line
!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1727 /* The line is a function or attribute prototype.
1728 * A function can have one of two syntaxes:
1729 * type funcname(argproto1, argproto2, ...)
1730 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1731 * The former is for C type function argument passing, the latter for
1732 * register argument passing.
1733 * An attribute has the following syntax:
1736 char c
, *args
[64], *regs
[64], *funcname
, *cp
;
1737 int len
, argcount
= 0, regcount
= 0, brcount
= 0;
1739 cp
= strchr(line
,'#');
1743 /* Parse 'type functionname' at the beginning of the line */
1745 s
= line
+ strlen(line
);
1747 s
= strchr(line
, '(');
1749 exitfileerror(20, "( expected at position %d\n", strlen(line
) + 1);
1753 while (isspace(*(s2
-1)))
1757 while (s2
> line
&& !isspace(*(s2
-1)) && !(*(s2
-1) == '*'))
1761 exitfileerror(20, "No type specifier before %s name\n", isattribute
? "attribute" : "function");
1763 if (*funclistptr
!= NULL
)
1764 funclistptr
= &((*funclistptr
)->next
);
1765 *funclistptr
= newfunctionhead(s2
, STACK
);
1768 (*funclistptr
)->comment
= strdup(cp
);
1770 (*funclistptr
)->comment
= NULL
;
1772 while (isspace(*(s2
-1)))
1775 (*funclistptr
)->type
= strdup(line
);
1776 (*funclistptr
)->lvo
= lvo
;
1777 (*funclistptr
)->version
= minversion
;
1783 /* Parse function prototype */
1800 && !(brcount
== 0 && (*s
== ',' || *s
== ')'))
1810 exitfileerror(20, "Unexected ')' at position %d\n", s
-line
+1);
1817 exitfileerror(20, "'(' without ')'");
1820 while (isspace(*(s2
-1)))
1824 if (!(s2
> args
[argcount
- 1]))
1825 exitfileerror(20, "Syntax error in function prototype\n");
1831 while (*s
!= '\0' && isspace(*s
))
1836 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1838 /* There may be no register specified with () so be sure then c is == ')' */
1853 if (memchr("AD",s
[0],2)!=NULL
&& memchr("01234567",s
[1],8)!=NULL
)
1860 if (s
[0] == s
[-3] && s
[1] == s
[-2] + 1)
1867 "wrong register specification \"%s\" for argument %u\n",
1868 regs
[regcount
-1], regcount
1872 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount
, regs
[regcount
-1]);
1878 "wrong register \"%s\" for argument %u\n",
1879 regs
[regcount
-1], regcount
1888 exitfileerror(20, "'(' without ')'\n");
1889 if (c
!= ',' && c
!= ')')
1890 exitfileerror(20, "',' or ')' expected at position %d\n", s
-line
+1);
1896 while (isspace(*s
)) s
++;
1898 exitfileerror(20, "wrong char '%c' at position %d\n", *s
, (int)(s
-line
) + 1);
1900 if (argcount
!= regcount
)
1901 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1905 (*funclistptr
)->libcall
= def_libcall
;
1906 for (i
= 0; i
< argcount
; i
++)
1907 funcaddarg(*funclistptr
, args
[i
], regs
[i
]);
1909 else if (*s
== '\0')
1910 { /* No registers specified */
1911 for (i
= 0; i
< argcount
; i
++)
1912 funcaddarg(*funclistptr
, args
[i
], NULL
);
1915 exitfileerror(20, "wrong char '%c' at position %d\n", *s
, (int)(s
-line
) + 1);
1920 static void readsectionclass_methodlist(struct classinfo
*cl
)
1923 char *line
, *s
, *s2
;
1924 struct functionhead
**methlistptr
= &cl
->methlist
;
1925 struct stringlist
*interface
= NULL
;
1927 if (cl
->basename
==NULL
)
1928 exitfileerror(20, "section methodlist has to come after section config\n");
1934 exitfileerror(20, "unexptected EOF in methodlist section\n");
1936 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1937 if (strlen(line
)==0 || (line
[0] == '#' && line
[1] != '#'))
1941 exitfileerror(20, "No space allowed at start of the line\n");
1943 if (strncmp(line
, "##", 2)==0) /* Is this the end ? */
1946 while (isspace(*s
)) s
++;
1947 if (strncmp(s
, "end", 3)!=0)
1948 exitfileerror(20, "\"##end methodlist\" expected\n");
1951 while (isspace(*s
)) s
++;
1952 if (strncmp(s
, "methodlist", 10)!=0)
1953 exitfileerror(20, "\"##end methodlist\" expected\n");
1956 while (isspace(*s
)) s
++;
1958 exitfileerror(20, "unexpected character on position %d\n", s
-line
);
1968 if (strncmp(s
, "alias", 5)==0)
1973 exitfileerror(20, "syntax is '.alias name'\n");
1975 while (isspace(*s
)) s
++;
1976 if (*s
== '\0' || !(isalpha(*s
) || *s
== '_'))
1977 exitfileerror(20, "syntax is '.alias name'\n");
1981 while (isalnum(*s
) || *s
== '_') s
++;
1988 } while (isspace(*s
));
1992 exitfileerror(20, "syntax is '.alias name'\n");
1994 if (*methlistptr
== NULL
)
1995 exitfileerror(20, ".alias has to come after a function declaration\n");
1997 slist_append(&(*methlistptr
)->aliases
, s2
);
1999 else if (strncmp(s
, "function", 8) == 0)
2004 exitfileerror(20, "Syntax error\n");
2006 while (isspace(*s
)) s
++;
2007 if (*s
== '\0' || !(isalpha(*s
) || *s
== '_'))
2008 exitfileerror(20, "syntax is '.function name'\n");
2012 while (isalnum(*s
) || *s
== '_') s
++;
2019 } while (isspace(*s
));
2023 exitfileerror(20, "syntax is '.function name'\n");
2025 if (*methlistptr
== NULL
)
2026 exitfileerror(20, ".function has to come after a function declaration\n");
2028 funcsetinternalname(*methlistptr
, s2
);
2030 else if (strncmp(s
, "interface", 9) == 0)
2032 if (cl
->classtype
!= HIDD
)
2033 exitfileerror(20, "interface only valid for a HIDD\n");
2038 exitfileerror(20, "Syntax error\n");
2040 while (isspace(*s
)) s
++;
2041 if (*s
== '\0' || !isalpha(*s
))
2042 exitfileerror(20, "syntax is '.interface name'\n");
2046 while (isalnum(*s
) || *s
== '_') s
++;
2053 } while (isspace(*s
));
2057 exitfileerror(20, "syntax is '.interface name'\n");
2059 interface
= slist_append(&cl
->interfaces
, s2
);
2062 exitfileerror(20, "Syntax error");
2064 else if (isalpha(*line
))
2068 for (s
= line
+ 1; isalnum(*s
) || *s
== '_'; s
++)
2071 if (cl
->classtype
== HIDD
&& interface
== NULL
)
2072 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
2075 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
2077 if (*methlistptr
!= NULL
)
2078 methlistptr
= &((*methlistptr
)->next
);
2079 if (cl
->classtype
!= HIDD
)
2081 if (snprintf(stmp
, 256, "%s__%s", cl
->basename
, line
) >= 256)
2082 exitfileerror(20, "Method name too large\n");
2084 *methlistptr
= newfunctionhead(stmp
, STACK
);
2085 (*methlistptr
)->type
= "IPTR";
2086 funcaddarg(*methlistptr
, "Class *cl", NULL
);
2087 funcaddarg(*methlistptr
, "Object *o", NULL
);
2088 funcaddarg(*methlistptr
, "Msg msg", NULL
);
2092 if (snprintf(stmp
, 256, "%s__%s__%s", cl
->basename
, interface
->s
, line
) >= 256)
2093 exitfileerror(20, "Method name too large\n");
2095 *methlistptr
= newfunctionhead(stmp
, STACK
);
2096 (*methlistptr
)->type
= "IPTR";
2097 funcaddarg(*methlistptr
, "OOP_Class *cl", NULL
);
2098 funcaddarg(*methlistptr
, "OOP_Object *o", NULL
);
2099 funcaddarg(*methlistptr
, "OOP_Msg msg", NULL
);
2100 (*methlistptr
)->interface
= interface
;
2101 if (snprintf(stmp
, 256, "mo%s_%s", interface
->s
, line
) >= 256)
2102 exitfileerror(20, "Method name too large\n");
2103 (*methlistptr
)->method
= strdup(stmp
);
2105 slist_append(&(*methlistptr
)->aliases
, line
);
2108 exitfileerror(20, "Methodname has to begin with a letter\n");
2113 readsectioninterface(struct config
*cfg
)
2116 struct interfaceinfo
*in
;
2118 in
= newinterface(cfg
);
2119 s
= readsections(cfg
, NULL
, in
, 1, 0);
2121 exitfileerror(20, "Unexpected end of file\n");
2123 if (strncmp(s
, "##", 2) != 0)
2124 exitfileerror(20, "'##end interface' expected\n");
2127 while (isspace(*s
)) s
++;
2129 if (strncmp(s
, "end", 3) != 0)
2130 exitfileerror(20, "'##end interface' expected\n");
2134 exitfileerror(20, "'##end interface' expected\n");
2135 while (isspace(*s
)) s
++;
2137 if (strncmp(s
, "interface", 9) != 0)
2138 exitfileerror(20, "'##end interface' expected\n");
2141 while (isspace(*s
)) s
++;
2143 exitfileerror(20, "'##end interface' expected\n");
2145 if (!in
->interfaceid
)
2146 exitfileerror(20, "interface has no 'interfaceid' defined!\n");
2148 if (!in
->interfacename
)
2149 exitfileerror(20, "interface has no 'interfacename' defined!\n");
2151 if (!in
->methodstub
)
2152 in
->methodstub
= strdup(in
->interfacename
);
2154 if (!in
->methodbase
) {
2155 int len
= strlen(in
->interfacename
);
2156 in
->methodbase
= malloc(len
+ 4 + 1);
2157 strcpy(in
->methodbase
, in
->interfacename
);
2158 strcat(in
->methodbase
, "Base");
2161 if (!in
->attributebase
) {
2162 int len
= strlen(in
->interfacename
);
2163 in
->attributebase
= malloc(len
+ 4 + 4 + 1);
2164 strcpy(in
->attributebase
, in
->interfacename
);
2165 strcat(in
->attributebase
, "AttrBase");
2170 readsectionclass(struct config
*cfg
)
2173 struct classinfo
*cl
;
2176 s
= readsections(cfg
, cl
, NULL
, 1, 0);
2178 exitfileerror(20, "Unexpected end of file\n");
2180 if (strncmp(s
, "##", 2) != 0)
2181 exitfileerror(20, "'##end class' expected\n");
2184 while (isspace(*s
)) s
++;
2186 if (strncmp(s
, "end", 3) != 0)
2187 exitfileerror(20, "'##end class' expected\n");
2191 exitfileerror(20, "'##end class' expected\n");
2192 while (isspace(*s
)) s
++;
2194 if (strncmp(s
, "class", 5) != 0)
2195 exitfileerror(20, "'##end class' expected\n");
2198 while (isspace(*s
)) s
++;
2200 exitfileerror(20, "'##end class' expected\n");
2203 static struct classinfo
*newclass(struct config
*cfg
)
2205 struct classinfo
*cl
, *classlistit
;
2207 cl
= malloc(sizeof(struct classinfo
));
2210 fprintf(stderr
, "Out of memory\n");
2213 memset(cl
, 0, sizeof(struct classinfo
));
2215 /* By default the classes are initialized with a priority of 1 so they
2216 * are initialized before any user added initialization with priority 1
2220 if (cfg
->classlist
== NULL
)
2221 cfg
->classlist
= cl
;
2226 classlistit
= cfg
->classlist
;
2227 classlistit
->next
!= NULL
;
2228 classlistit
= classlistit
->next
2231 classlistit
->next
= cl
;
2237 static struct handlerinfo
*newhandler(struct config
*cfg
)
2239 struct handlerinfo
*hl
;
2241 hl
= calloc(1,sizeof(*hl
));
2242 hl
->next
= cfg
->handlerlist
;
2243 cfg
->handlerlist
= hl
;
2247 static struct interfaceinfo
*newinterface(struct config
*cfg
)
2249 struct interfaceinfo
*in
, *interfacelistit
;
2251 in
= malloc(sizeof(struct interfaceinfo
));
2254 fprintf(stderr
, "Out of memory\n");
2257 memset(in
, 0, sizeof(struct interfaceinfo
));
2259 if (cfg
->interfacelist
== NULL
)
2260 cfg
->interfacelist
= in
;
2265 interfacelistit
= cfg
->interfacelist
;
2266 interfacelistit
->next
!= NULL
;
2267 interfacelistit
= interfacelistit
->next
2270 interfacelistit
->next
= in
;
2277 static int getdirective(char *s
, const char *directive
, int range_min
, int range_max
, int *val
)
2282 if (strncmp(s
, directive
, strlen(directive
)) != 0)
2285 s
+= strlen(directive
);
2286 if (*s
&& !isspace(*s
))
2287 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive
);
2289 while (isspace(*s
)) s
++;
2291 exitfileerror(20, "No .%s value specified\n", directive
);
2293 newval
= strtol(s
, &tmp
, 0);
2294 if (s
== tmp
|| !(newval
>= range_min
&& newval
<= range_max
)) {
2296 while (*tmp
&& !isspace(*tmp
)) tmp
++;
2297 exitfileerror(20, "Invalid .%s value of %.*s\n", directive
, tmp
- s
, s
);
2305 readsectionhandler(struct config
*cfg
)
2307 char *line
= NULL
, *s
;
2308 struct handlerinfo
*hl
;
2309 unsigned char autolevel
= 0;
2310 unsigned int stacksize
= 0;
2314 int has_filesystem
= 0;
2322 s
= line
= readline();
2325 exitfileerror(20, "unexpected end of file in section hanlder\n");
2327 if (strncmp(s
, "##", 2)==0)
2330 /* Ignore comments */
2331 if (strncmp(s
, "#", 1)==0)
2334 /* Skip ahead to function name */
2335 while (*s
&& isspace(*s
)) s
++;
2337 /* Permit blank lines */
2345 if (getdirective(s
, "autodetect", 0, 127, &val
)) {
2347 } else if (getdirective(s
, "stacksize", 0, INT_MAX
, &val
)) {
2349 } else if (getdirective(s
, "priority", -128, 127, &val
)) {
2351 } else if (getdirective(s
, "bootpri", -128, 127, &val
)) {
2353 } else if (getdirective(s
, "startup", INT_MIN
, INT_MAX
, &val
)) {
2356 exitfileerror(20, "Unrecognized directive \"%s\"\n", line
);
2362 unsigned int id
= 0;
2364 if (strncasecmp(s
,"resident=",9)==0) {
2367 s
= strchr(s
, '=') + 1;
2369 while (*s
&& !isspace(*s
)) s
++;
2371 exitfileerror(20, "Empty resident= is not permitted\n");
2376 hl
= newhandler(cfg
);
2377 hl
->type
= HANDLER_RESIDENT
;
2379 hl
->name
= strdup(res
);
2380 hl
->autodetect
= autolevel
--;
2381 hl
->stacksize
= stacksize
;
2382 hl
->priority
= priority
;
2383 hl
->startup
= startup
;
2384 } else if (strncasecmp(s
,"dosnode=",8)==0) {
2387 s
= strchr(s
, '=') + 1;
2389 while (*s
&& !isspace(*s
)) s
++;
2391 exitfileerror(20, "Empty dosnode= is not permitted\n");
2396 hl
= newhandler(cfg
);
2397 hl
->type
= HANDLER_DOSNODE
;
2399 hl
->name
= strdup(dev
);
2400 hl
->autodetect
= autolevel
? autolevel
-- : 0;
2401 hl
->stacksize
= stacksize
;
2402 hl
->priority
= priority
;
2403 hl
->startup
= startup
;
2404 hl
->bootpri
= bootpri
;
2405 } else if (strncasecmp(s
,"dostype=",8) == 0) {
2406 s
= strchr(s
, '=') + 1;
2408 id
= (unsigned int)strtoul(s
, &tmp
, 0);
2411 while (*tmp
&& !isspace(*tmp
))
2413 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp
-s
), s
);
2417 if (id
== 0 || id
== ~0) {
2418 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id
);
2421 hl
= newhandler(cfg
);
2422 hl
->type
= HANDLER_DOSTYPE
;
2425 hl
->autodetect
= autolevel
? autolevel
-- : 0;
2426 hl
->stacksize
= stacksize
;
2427 hl
->priority
= priority
;
2428 hl
->startup
= startup
;
2430 for (tmp
= s
; !isspace(*tmp
); tmp
++);
2431 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp
- s
, s
);
2434 /* Advance to next ID */
2435 while (*s
&& isspace(*s
)) s
++;
2441 exitfileerror(20, "Unexpected end of file\n");
2443 if (strncmp(s
, "##", 2) != 0)
2444 exitfileerror(20, "'##end handler' expected\n");
2447 while (isspace(*s
)) s
++;
2449 if (strncmp(s
, "end", 3) != 0)
2450 exitfileerror(20, "'##end handler' expected\n");
2453 while (isspace(*s
)) s
++;
2455 if (strncmp(s
, "handler", 7) != 0)
2456 exitfileerror(20, "'##end handler' expected\n");
2459 while (isspace(*s
)) s
++;
2461 exitfileerror(20, "'##end handler' expected\n");