2 Copyright © 1995-2012, 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 © 1995-2012, The AROS Development Team. All rights reserved.\n"
27 getBanner(struct config
* config
)
29 int bannerlength
= strlen(config
->conffile
) + strlen(bannertemplate
) -1;
30 char * banner
= malloc(bannerlength
);
32 snprintf (banner
, bannerlength
, bannertemplate
, config
->conffile
);
38 freeBanner(char *banner
)
43 const static char usage
[] =
45 "Usage: genmodule [-c conffile] [-s suffix] [-d gendir] [-n]\n"
46 " {writefiles|writemakefile|writeincludes|writelibdefs|writefunclist|writefd|writeskel} modname modtype\n"
49 static void readconfig(struct config
*);
50 static struct classinfo
*newclass(struct config
*);
51 static struct handlerinfo
*newhandler(struct config
*);
52 static struct interfaceinfo
*newinterface(struct config
*);
54 /* the method prefices for the supported classes */
55 static const char *muimprefix
[] =
61 static const char *gadgetmprefix
[] =
68 static const char *dtmprefix
[] =
77 /* Create a config struct. Initialize with the values from the programs command
78 * line arguments and the contents of the modules .conf file
80 struct config
*initconfig(int argc
, char **argv
)
83 char *s
, **argvit
= argv
+ 1;
86 cfg
= malloc(sizeof(struct config
));
89 fprintf(stderr
, "Out of memory\n");
93 memset(cfg
, 0, sizeof(struct config
));
95 while ((c
= getopt(argc
, argv
, ":c:s:d:v:")) != -1)
99 fprintf(stderr
, "Option -%c needs an argument\n",optopt
);
106 cfg
->conffile
= optarg
;
110 cfg
->suffix
= optarg
;
115 /* Remove / at end if present */
116 if ((optarg
)[strlen(*argvit
)-1]=='/') (optarg
)[strlen(optarg
)-1]='\0';
117 cfg
->gendir
= optarg
;
121 cfg
->versionextra
= optarg
;
125 fprintf(stderr
, "Internal error: Unhandled option\n");
130 if (optind
+ 3 != argc
)
132 fprintf(stderr
, "Wrong number of arguments.\n%s", usage
);
136 if (strcmp(argv
[optind
], "writefiles") == 0)
138 cfg
->command
= FILES
;
140 else if (strcmp(argv
[optind
], "writemakefile") == 0)
142 cfg
->command
= MAKEFILE
;
144 else if (strcmp(argv
[optind
], "writeincludes") == 0)
146 cfg
->command
= INCLUDES
;
148 else if (strcmp(argv
[optind
], "writelibdefs") == 0)
150 cfg
->command
= LIBDEFS
;
152 else if (strcmp(argv
[optind
], "writefunclist") == 0)
154 cfg
->command
= WRITEFUNCLIST
;
156 else if (strcmp(argv
[optind
], "writefd") == 0)
158 cfg
->command
= WRITEFD
;
160 else if (strcmp(argv
[optind
], "writeskel") == 0)
162 cfg
->command
= WRITESKEL
;
166 fprintf(stderr
, "Unrecognized argument \"%s\"\n%s", argv
[optind
], usage
);
170 cfg
->modulename
= argv
[optind
+1];
171 cfg
->modulenameupper
= strdup(cfg
->modulename
);
172 for (s
=cfg
->modulenameupper
; *s
!='\0'; *s
= toupper(*s
), s
++) {
173 if (!isalnum(*s
)) *s
= '_';
176 if (strcmp(argv
[optind
+2],"library")==0)
178 cfg
->modtype
= LIBRARY
;
179 cfg
->moddir
= "Libs";
181 else if (strcmp(argv
[optind
+2],"mcc")==0)
184 cfg
->moddir
= "Classes/Zune";
186 else if (strcmp(argv
[optind
+2],"mui")==0)
189 cfg
->moddir
= "Classes/Zune";
191 else if (strcmp(argv
[optind
+2],"mcp")==0)
194 cfg
->moddir
= "Classes/Zune";
196 else if (strcmp(argv
[optind
+2], "device")==0)
198 cfg
->modtype
= DEVICE
;
199 cfg
->moddir
= "Devs";
201 else if (strcmp(argv
[optind
+2], "resource")==0)
203 cfg
->modtype
= RESOURCE
;
204 cfg
->moddir
= "Devs";
206 else if (strcmp(argv
[optind
+2], "gadget")==0)
208 cfg
->modtype
= GADGET
;
209 cfg
->moddir
= "Classes/Gadgets";
211 else if (strcmp(argv
[optind
+2], "datatype")==0)
213 cfg
->modtype
= DATATYPE
;
214 cfg
->moddir
= "Classes/DataTypes";
216 else if (strcmp(argv
[optind
+2], "usbclass")==0)
218 cfg
->modtype
= USBCLASS
;
219 cfg
->moddir
= "Classes/USB";
222 cfg
->suffix
= "class";
226 else if (strcmp(argv
[optind
+2], "hidd")==0)
229 cfg
->moddir
= "Devs/Drivers";
231 else if (strcmp(argv
[optind
+2], "handler")==0)
233 cfg
->modtype
= HANDLER
;
234 cfg
->moddir
= "$(AROS_DIR_FS)";
236 else if (strcmp(argv
[optind
+2], "hook")==0)
238 cfg
->modtype
= HANDLER
;
239 cfg
->moddir
= "Devs";
243 fprintf(stderr
, "Unknown modtype \"%s\" specified for second argument\n", argv
[optind
+2]);
248 cfg
->suffix
= argv
[optind
+2];
250 /* Fill fields with default value if not specified on the command line */
254 if (cfg
->conffile
== NULL
)
256 snprintf(tmpbuf
, sizeof(tmpbuf
), "%s.conf", cfg
->modulename
);
257 cfg
->conffile
= strdup(tmpbuf
);
260 if (cfg
->gendir
== NULL
)
266 /* For a device add the functions given in beginiofunc and abortiofunc to the functionlist
267 * if they are provided
269 if (cfg
->beginiofunc
!= NULL
)
271 struct functionhead
*funchead
;
273 cfg
->intcfg
|= CFG_NOREADFUNCS
;
275 /* Add beginio_func to the list of functions */
276 funchead
= newfunctionhead(cfg
->beginiofunc
, REGISTERMACRO
);
277 funchead
->type
= strdup("void");
279 funcaddarg(funchead
, "struct IORequest *ioreq", "A1");
281 funchead
->next
= cfg
->funclist
;
282 cfg
->funclist
= funchead
;
284 /* Add abortio_func to the list of functions */
285 funchead
= newfunctionhead(cfg
->abortiofunc
, REGISTERMACRO
);
286 funchead
->type
= strdup("LONG");
288 funcaddarg(funchead
, "struct IORequest *ioreq", "A1");
290 funchead
->next
= cfg
->funclist
->next
;
291 cfg
->funclist
->next
= funchead
;
293 else if (cfg
->modtype
== DEVICE
&& cfg
->intcfg
& CFG_NOREADFUNCS
)
298 "beginio_func and abortio_func missing for a device with a non empty function list\n"
303 /* See if we have any stackcall options */
305 struct functionhead
*funchead
;
307 for (funchead
= cfg
->funclist
; funchead
; funchead
= funchead
->next
) {
308 if (funchead
->libcall
== STACK
) {
309 cfg
->options
|= OPTION_STACKCALL
;
315 /* Verify that a handler has a handler */
316 if (cfg
->modtype
== HANDLER
) {
317 if (cfg
->handlerfunc
== NULL
) {
318 fprintf(stderr
, "handler modules require a 'handler_func' ##config option\n");
321 cfg
->options
|= OPTION_NOAUTOLIB
| OPTION_NOEXPUNGE
| OPTION_NOOPENCLOSE
;
327 /* Functions to read configuration from the configuration file */
329 #include "fileread.h"
331 static char *readsections(struct config
*, struct classinfo
*cl
, struct interfaceinfo
*in
, int inclass
);
332 static void readsectionconfig(struct config
*, struct classinfo
*cl
, struct interfaceinfo
*in
, int inclass
);
333 static void readsectioncdef(struct config
*);
334 static void readsectioncdefprivate(struct config
*);
335 static void readsectionstartup(struct config
*);
336 static void readsectionfunctionlist(const char *type
, struct functionhead
**funclistptr
, unsigned int firstlvo
, int isattribute
);
337 static void readsectionclass_methodlist(struct classinfo
*);
338 static void readsectionclass(struct config
*);
339 static void readsectionhandler(struct config
*);
340 static void readsectioninterface(struct config
*);
342 static void readconfig(struct config
*cfg
)
344 struct classinfo
*mainclass
= NULL
;
346 /* Create a classinfo structure if this module is a class */
347 switch (cfg
->modtype
)
362 mainclass
= newclass(cfg
);
363 mainclass
->classtype
= cfg
->modtype
;
367 fprintf(stderr
, "Internal error: unsupported modtype for classinfo creation\n");
371 switch (cfg
->modtype
)
384 mainclass
->boopsimprefix
= muimprefix
;
392 mainclass
->boopsimprefix
= gadgetmprefix
;
396 mainclass
->boopsimprefix
= dtmprefix
;
400 /* FIXME: need boopsimprefix ? */
403 fprintf(stderr
, "Internal error: unsupported modtype for firstlvo\n");
407 if (!fileopen(cfg
->conffile
))
409 fprintf(stderr
, "In readconfig: Could not open %s\n", cfg
->conffile
);
413 /* Read all sections and see that we are at the end of the file */
414 if (readsections(cfg
, mainclass
, NULL
, 0) != NULL
)
415 exitfileerror(20, "Syntax error");
420 /* readsections will scan through all the sections in the config file.
422 * struct config *cfg: The module config data which may be updated by
423 * the information in the sections
424 * struct classinfo *cl: The classdata to be filled with data from the sections.
425 * This may be NULL if this is the main part of the configuration file and the
426 * type of the module is not a class
427 * int inclass: Boolean to indicate if we are in a class part. If not we are in the main
428 * part of the config file.
430 static char *readsections(struct config
*cfg
, struct classinfo
*cl
, struct interfaceinfo
*in
, int inclass
)
435 while ((line
=readline())!=NULL
)
437 if (strncmp(line
, "##", 2)==0)
439 static char *parts
[] =
441 "config", "cdefprivate", "cdef", "startup", "functionlist", "methodlist", "class", "handler", "interface", "attributelist"
443 const unsigned int nums
= sizeof(parts
)/sizeof(char *);
444 unsigned int partnum
;
448 while (isspace(*s
)) s
++;
450 if (strncmp(s
, "begin", 5)!=0)
455 exitfileerror(20, "space after begin expected\n");
456 while (isspace(*s
)) s
++;
458 for (i
= 0, partnum
= 0; partnum
==0 && i
<nums
; i
++)
460 if (strncmp(s
, parts
[i
], strlen(parts
[i
]))==0)
463 s
+= strlen(parts
[i
]);
464 while (isspace(*s
)) s
++;
466 exitfileerror(20, "unexpected character on position %d\n", s
-line
);
470 exitfileerror(20, "unknown start of section\n");
474 readsectionconfig(cfg
, cl
, in
, inclass
);
478 case 2: /* cdefprivate */
480 exitfileerror(20, "cdefprivate section not allowed in class section\n");
481 readsectioncdefprivate(cfg
);
486 exitfileerror(20, "cdef section not allowed in class section\n");
487 readsectioncdef(cfg
);
490 case 4: /* startup */
492 exitfileerror(20, "startup section not allowed in class section\n");
493 readsectionstartup(cfg
);
496 case 5: /* functionlist */
498 exitfileerror(20, "functionlist section not allow in class section\n");
499 if (cfg
->basename
==NULL
)
500 exitfileerror(20, "section functionlist has to come after section config\n");
502 readsectionfunctionlist("functionlist", &cfg
->funclist
, cfg
->firstlvo
, 0);
503 cfg
->intcfg
|= CFG_NOREADFUNCS
;
506 case 6: /* methodlist */
507 if (cl
== NULL
&& in
== NULL
)
508 exitfileerror(20, "methodlist section when not in a class or interface\n");
510 readsectionclass_methodlist(cl
);
512 readsectionfunctionlist("methodlist", &in
->methodlist
, 0, 0);
513 cfg
->intcfg
|= CFG_NOREADFUNCS
;
518 exitfileerror(20, "class section may not be in nested\n");
519 readsectionclass(cfg
);
521 case 8: /* handler */
522 readsectionhandler(cfg
);
524 case 9: /* interface */
526 exitfileerror(20, "interface section may not be nested\n");
527 readsectioninterface(cfg
);
529 case 10: /* attributelist */
531 exitfileerror(20, "attributelist only valid in interface sections\n");
532 readsectionfunctionlist("attributelist", &in
->attributelist
, 0, 1);
536 else if (strlen(line
)!=0)
537 filewarning("warning line outside section ignored\n");
543 exitfileerror(20, "No config section in conffile\n");
545 /* If no indication was given for generating includes or not
546 decide on module type and if there are functions
548 if(!((cfg
->options
& OPTION_INCLUDES
) || (cfg
->options
& OPTION_NOINCLUDES
)))
550 switch (cfg
->modtype
)
554 cfg
->options
|= OPTION_INCLUDES
;
562 cfg
->options
|= OPTION_NOINCLUDES
;
567 (cfg
->funclist
!= NULL
)
568 || (cfg
->cdeflines
!= NULL
)
569 || strcmp(cfg
->libbasetypeptrextern
, "struct Device *") != 0
570 ) ? OPTION_INCLUDES
: OPTION_NOINCLUDES
;
577 (cfg
->funclist
!= NULL
)
578 ) ? OPTION_INCLUDES
: OPTION_NOINCLUDES
;
582 fprintf(stderr
, "Internal error writemakefile: unhandled modtype for includes\n");
588 /* If no indication was given for not generating stubs only generate them if
589 * the module has functions
591 if(!((cfg
->options
& OPTION_STUBS
) || (cfg
->options
& OPTION_NOSTUBS
)))
593 switch (cfg
->modtype
)
596 cfg
->options
|= (cfg
->funclist
!= NULL
) ? OPTION_STUBS
: OPTION_NOSTUBS
;
609 cfg
->options
|= OPTION_NOSTUBS
;
613 fprintf(stderr
, "Internal error writemakefile: unhandled modtype for stubs\n");
619 /* If no indication was given for generating autoinit code or not
620 decide on module type
622 if(!((cfg
->options
& OPTION_AUTOINIT
) || (cfg
->options
& OPTION_NOAUTOINIT
)))
624 switch (cfg
->modtype
)
627 cfg
->options
|= OPTION_AUTOINIT
;
640 cfg
->options
|= OPTION_NOAUTOINIT
;
644 fprintf(stderr
, "Internal error writemakefile: unhandled modtype for autoinit\n");
650 if ((cfg
->modtype
== RESOURCE
) || (cfg
->modtype
== HANDLER
))
651 /* Enforce noopenclose for resources and handlers */
652 cfg
->options
|= OPTION_NOOPENCLOSE
;
653 else if (!(cfg
->options
& OPTION_SELFINIT
))
654 /* Enforce using RTF_AUTOINIT for everything except resources */
655 cfg
->options
|= OPTION_RESAUTOINIT
;
661 static void readsectionconfig(struct config
*cfg
, struct classinfo
*cl
, struct interfaceinfo
*in
, int inclass
)
664 char *line
, *s
, *s2
, *libbasetypeextern
= NULL
;
671 exitfileerror(20, "unexpected end of file in section config\n");
673 if (strncmp(line
, "##", 2)!=0)
675 const char *names
[] =
677 "basename", "libbase", "libbasetype", "libbasetypeextern",
678 "version", "date", "copyright", "libcall", "forcebase", "superclass",
679 "superclass_field", "residentpri", "options", "sysbase_field",
680 "seglist_field", "rootbase_field", "classptr_field", "classptr_var",
681 "classid", "classdatatype", "beginio_func", "abortio_func", "dispatcher",
682 "initpri", "type", "addromtag", "oopbase_field",
683 "rellib", "interfaceid", "interfacename",
684 "methodstub", "methodbase", "attributebase", "handler_func"
686 const unsigned int namenums
= sizeof(names
)/sizeof(char *);
687 unsigned int namenum
;
689 for (i
= 0, namenum
= 0; namenum
==0 && i
<namenums
; i
++)
693 strncmp(line
, names
[i
], strlen(names
[i
]))==0
694 && isspace(*(line
+strlen(names
[i
])))
699 exitfileerror(20, "unrecognized configuration option\n");
701 s
= line
+ strlen(names
[namenum
-1]);
703 exitfileerror(20, "space character expected after \"%s\"\n", names
[namenum
-1]);
705 while (isspace(*s
)) s
++;
707 exitfileerror(20, "unexpected end of line\n");
710 while (isspace(*(s2
-1))) s2
--;
715 case 1: /* basename */
717 cfg
->basename
= strdup(s
);
719 cl
->basename
= strdup(s
);
721 exitfileerror(20, "basename not valid config option when in a interface section\n");
724 case 2: /* libbase */
726 exitfileerror(20, "libbase not valid config option when in a class section\n");
727 cfg
->libbase
= strdup(s
);
730 case 3: /* libbasetype */
732 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
733 cfg
->libbasetype
= strdup(s
);
736 case 4: /* libbasetypeextern */
738 exitfileerror(20, "libbasetype not valid config option when in a class section\n");
739 libbasetypeextern
= strdup(s
);
742 case 5: /* version */
744 exitfileerror(20, "version not valid config option when in a class section\n");
745 if (sscanf(s
, "%u.%u", &cfg
->majorversion
, &cfg
->minorversion
)!=2)
746 exitfileerror(20, "wrong version string \"%s\"\n", s
);
751 exitfileerror(20, "date not valid config option when in a class section\n");
753 if (strptime(s
, "%e.%m.%Y", &date
) == NULL
)
755 exitfileerror(20, "date string has to have d.m.yyyy format\n");
758 cfg
->datestring
= strdup(s
);
761 case 7: /* copyright */
763 exitfileerror(20, "copyright not valid config option when in a class section\n");
764 cfg
->copyright
= strdup(s
);
767 case 8: /* libcall */
768 fprintf(stderr
, "libcall specification is deprecated and ignored\n");
771 case 9: /* forcebase */
773 exitfileerror(20, "forcebase not valid config option when in a class section\n");
774 slist_append(&cfg
->forcelist
, s
);
777 case 10: /* superclass */
779 exitfileerror(20, "superclass specified when not a BOOPSI class\n");
780 cl
->superclass
= strdup(s
);
783 case 11: /* superclass_field */
785 exitfileerror(20, "superclass_field specified when not a BOOPSI class\n");
786 cl
->superclass_field
= strdup(s
);
789 case 12: /* residentpri */
795 count
= sscanf(s
, "%d%c", &cfg
->residentpri
, &dummy
);
797 cfg
->residentpri
< -128 || cfg
->residentpri
> 127
800 exitfileerror(20, "residentpri number format error\n");
804 exitfileerror(20, "residentpri not valid config option when in a class section\n");
807 case 13: /* options */
810 static const char *optionnames
[] =
812 "noautolib", "noexpunge", "noresident", "peropenerbase",
813 "pertaskbase", "includes", "noincludes", "nostubs",
814 "autoinit", "noautoinit", "resautoinit", "noopenclose",
817 const unsigned int optionnums
= sizeof(optionnames
)/sizeof(char *);
822 for (i
= 0, optionnum
= 0; optionnum
==0 && i
<optionnums
; i
++)
824 if (strncmp(s
, optionnames
[i
], strlen(optionnames
[i
]))==0)
827 s
+= strlen(optionnames
[i
]);
828 while (isspace(*s
)) s
++;
832 exitfileerror(20, "Unrecognized option\n");
836 exitfileerror(20, "Unrecognized option\n");
839 case 1: /* noautolib */
840 cfg
->options
|= OPTION_NOAUTOLIB
;
842 case 2: /* noexpunge */
843 cfg
->options
|= OPTION_NOEXPUNGE
;
845 case 3: /* noresident */
846 cfg
->options
|= OPTION_NORESIDENT
;
849 case 5: /* pertaskbase */
850 cfg
->options
|= OPTION_PERTASKBASE
;
852 case 4: /* peropenerbase */
853 if (cfg
->options
& OPTION_DUPBASE
)
854 exitfileerror(20, "Only one option peropenerbase or pertaskbase allowed\n");
855 cfg
->options
|= OPTION_DUPBASE
;
857 case 6: /* includes */
858 if (cfg
->options
& OPTION_NOINCLUDES
)
859 exitfileerror(20, "option includes and noincludes are incompatible\n");
860 cfg
->options
|= OPTION_INCLUDES
;
862 case 7: /* noincludes */
863 if (cfg
->options
& OPTION_INCLUDES
)
864 exitfileerror(20, "option includes and noincludes are incompatible\n");
865 cfg
->options
|= OPTION_NOINCLUDES
;
867 case 8: /* nostubs */
868 cfg
->options
|= OPTION_NOSTUBS
;
870 case 9: /* autoinit */
871 if (cfg
->options
& OPTION_NOAUTOINIT
)
872 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
873 cfg
->options
|= OPTION_AUTOINIT
;
875 case 10: /* noautoinit */
876 if (cfg
->options
& OPTION_AUTOINIT
)
877 exitfileerror(20, "option autoinit and noautoinit are incompatible\n");
878 cfg
->options
|= OPTION_NOAUTOINIT
;
880 case 11: /* resautoinit */
881 if (cfg
->options
& OPTION_SELFINIT
)
882 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
883 cfg
->options
|= OPTION_RESAUTOINIT
;
886 cfg
->options
|= OPTION_NOOPENCLOSE
;
888 case 13: /* noresautoinit */
889 if (cfg
->options
& OPTION_RESAUTOINIT
)
890 exitfileerror(20, "option resautoinit and selfinit are incompatible\n");
891 cfg
->options
|= OPTION_SELFINIT
;
894 while (isspace(*s
)) s
++;
899 static const char *optionnames
[] =
903 const unsigned int optionnums
= sizeof(optionnames
)/sizeof(char *);
908 for (i
= 0, optionnum
= 0; optionnum
==0 && i
<optionnums
; i
++)
910 if (strncmp(s
, optionnames
[i
], strlen(optionnames
[i
]))==0)
913 s
+= strlen(optionnames
[i
]);
914 while (isspace(*s
)) s
++;
918 exitfileerror(20, "Unrecognized option\n");
922 exitfileerror(20, "Unrecognized option\n");
925 case 1: /* private */
926 cl
->options
|= COPTION_PRIVATE
;
929 while (isspace(*s
)) s
++;
934 case 14: /* sysbase_field */
936 exitfileerror(20, "sysbase_field not valid config option when in a class section\n");
937 cfg
->sysbase_field
= strdup(s
);
940 case 15: /* seglist_field */
942 exitfileerror(20, "seglist_field not valid config option when in a class section\n");
943 cfg
->seglist_field
= strdup(s
);
946 case 16: /* rootbase_field */
948 exitfileerror(20, "rootbase_field not valid config option when in a class section\n");
949 cfg
->rootbase_field
= strdup(s
);
952 case 17: /* classptr_field */
958 "classptr_field specified when not a BOOPSI class\n"
961 cl
->classptr_field
= strdup(s
);
964 case 18: /* classptr_var */
970 "classptr_var specified when not a BOOPSI class\n"
973 cl
->classptr_var
= strdup(s
);
976 case 19: /* classid */
978 exitfileerror(20, "classid specified when not a BOOPSI class\n");
979 if (cl
->classid
!= NULL
)
980 exitfileerror(20, "classid specified twice\n");
981 cl
->classid
= strdup(s
);
982 if (strcmp(cl
->classid
, "NULL") == 0)
983 cl
->options
|= COPTION_PRIVATE
;
986 case 20: /* classdatatype */
988 exitfileerror(20, "classdatatype specified when not a BOOPSI class\n");
989 cl
->classdatatype
= strdup(s
);
992 case 21: /* beginio_func */
994 exitfileerror(20, "beginio_func not valid config option when in a class section\n");
995 if (cfg
->modtype
!= DEVICE
)
996 exitfileerror(20, "beginio_func specified when not a device\n");
997 cfg
->beginiofunc
= strdup(s
);
1000 case 22: /* abortio_func */
1002 exitfileerror(20, "abortio_func not valid config option when in a class section\n");
1003 if (cfg
->modtype
!= DEVICE
)
1004 exitfileerror(20, "abortio_func specified when not a device\n");
1005 cfg
->abortiofunc
= strdup(s
);
1008 case 23: /* dispatcher */
1010 exitfileerror(20, "dispatcher specified when not a BOOPSI class\n");
1011 cl
->dispatcher
= strdup(s
);
1012 /* function references are not needed when dispatcher is specified */
1013 cfg
->intcfg
|= CFG_NOREADFUNCS
;
1016 case 24: /* initpri */
1022 count
= sscanf(s
, "%d%c", &cl
->initpri
, &dummy
);
1024 cl
->initpri
< -128 || cl
->initpri
> 127
1027 exitfileerror(20, "initpri number format error\n");
1031 exitfileerror(20, "initpri only valid config option for a BOOPSI class\n");
1036 exitfileerror(20, "type only valid config option in a class section\n");
1037 if (strcmp(s
,"mcc")==0)
1038 cl
->classtype
= MCC
;
1039 else if (strcmp(s
,"mui")==0)
1040 cl
->classtype
= MUI
;
1041 else if (strcmp(s
,"mcp")==0)
1042 cl
->classtype
= MCP
;
1043 else if (strcmp(s
, "image")==0)
1044 cl
->classtype
= IMAGE
;
1045 else if (strcmp(s
, "gadget")==0)
1046 cl
->classtype
= GADGET
;
1047 else if (strcmp(s
, "datatype")==0)
1048 cl
->classtype
= DATATYPE
;
1049 else if (strcmp(s
, "usbclass")==0)
1050 cl
->classtype
= USBCLASS
;
1051 else if (strcmp(s
, "class")==0)
1052 cl
->classtype
= CLASS
;
1053 else if (strcmp(s
, "hidd")==0)
1054 cl
->classtype
= HIDD
;
1057 fprintf(stderr
, "Unknown type \"%s\" specified\n", s
);
1062 case 26: /* addromtag */
1063 cfg
->addromtag
= strdup(s
);
1066 case 27: /* oopbase_field */
1067 cfg
->oopbase_field
= strdup(s
);
1069 case 28: /* rellib */
1070 slist_append(&cfg
->rellibs
, s
);
1072 case 29: /* interfaceid */
1074 exitfileerror(20, "interfaceid only valid config option for an interface\n");
1075 in
->interfaceid
= strdup(s
);
1077 case 30: /* interfacename */
1079 exitfileerror(20, "interfacename only valid config option for an interface\n");
1080 in
->interfacename
= strdup(s
);
1082 case 31: /* methodstub */
1084 exitfileerror(20, "methodstub only valid config option for an interface\n");
1085 in
->methodstub
= strdup(s
);
1087 case 32: /* methodbase */
1089 exitfileerror(20, "methodbase only valid config option for an interface\n");
1090 in
->methodbase
= strdup(s
);
1092 case 33: /* attributebase */
1094 exitfileerror(20, "attributebase only valid config option for an interface\n");
1095 in
->attributebase
= strdup(s
);
1097 case 34: /* handler_func */
1098 if (cfg
->modtype
!= HANDLER
)
1099 exitfileerror(20, "handler specified when not a handler\n");
1100 cfg
->handlerfunc
= strdup(s
);
1104 else /* Line starts with ## */
1107 while (isspace(*s
)) s
++;
1108 if (strncmp(s
, "end", 3)!=0)
1109 exitfileerror(20, "\"##end config\" expected\n");
1113 exitfileerror(20, "\"##end config\" expected\n");
1115 while (isspace(*s
)) s
++;
1116 if (strncmp(s
, "config", 6)!=0)
1117 exitfileerror(20, "\"##end config\" expected\n");
1120 while (isspace(*s
)) s
++;
1122 exitfileerror(20, "\"##end config\" expected\n");
1128 /* When not in a class section fill in default values for fields in cfg */
1131 if (cfg
->basename
==NULL
)
1133 cfg
->basename
= strdup(cfg
->modulename
);
1134 *cfg
->basename
= toupper(*cfg
->basename
);
1136 if (cfg
->libbase
==NULL
)
1138 unsigned int len
= strlen(cfg
->basename
)+5;
1139 cfg
->libbase
= malloc(len
);
1140 snprintf(cfg
->libbase
, len
, "%sBase", cfg
->basename
);
1142 if (cfg
->libbasetype
== NULL
&& libbasetypeextern
!= NULL
)
1143 cfg
->libbasetype
= strdup(libbasetypeextern
);
1144 if (cfg
->sysbase_field
!= NULL
&& cfg
->libbasetype
== NULL
)
1145 exitfileerror(20, "sysbase_field specified when no libbasetype is given\n");
1146 if (cfg
->seglist_field
!= NULL
&& cfg
->libbasetype
== NULL
)
1147 exitfileerror(20, "seglist_field specified when no libbasetype is given\n");
1148 if (cfg
->oopbase_field
!= NULL
&& cfg
->libbasetype
== NULL
)
1149 exitfileerror(20, "oopbase_field specified when no libbasetype is given\n");
1150 /* rootbase_field only allowed when duplicating base */
1151 if (cfg
->rootbase_field
!= NULL
&& !(cfg
->options
& OPTION_DUPBASE
))
1152 exitfileerror(20, "rootbasefield only valid for option peropenerbase or pertaskbase\n");
1154 /* Set default date to current date */
1155 if (cfg
->datestring
== NULL
)
1158 time_t now
= time(NULL
);
1159 struct tm
*ltime
= localtime(&now
);
1161 snprintf(tmpbuf
, sizeof(tmpbuf
), "%u.%u.%u",
1162 ltime
->tm_mday
, 1 + ltime
->tm_mon
, 1900 + ltime
->tm_year
);
1164 cfg
->datestring
= strdup(tmpbuf
);
1167 if (cfg
->copyright
== NULL
)
1168 cfg
->copyright
= "";
1170 if ( (cfg
->beginiofunc
!= NULL
&& cfg
->abortiofunc
== NULL
)
1171 || (cfg
->beginiofunc
== NULL
&& cfg
->abortiofunc
!= NULL
)
1173 exitfileerror(20, "please specify both beginio_func and abortio_func\n");
1175 if (libbasetypeextern
==NULL
)
1177 switch (cfg
->modtype
)
1180 cfg
->libbasetypeptrextern
= "struct Device *";
1184 cfg
->libbasetypeptrextern
= "APTR ";
1194 cfg
->libbasetypeptrextern
= "struct Library *";
1197 fprintf(stderr
, "Internal error: Unsupported modtype for libbasetypeptrextern\n");
1203 cfg
->libbasetypeptrextern
= malloc(strlen(libbasetypeextern
)+3);
1204 strcpy(cfg
->libbasetypeptrextern
, libbasetypeextern
);
1205 strcat(cfg
->libbasetypeptrextern
, " *");
1206 free(libbasetypeextern
);
1210 /* When class was given too fill in some defaults when not specified */
1213 if (cl
->classtype
== UNSPECIFIED
)
1214 cl
->classtype
= CLASS
;
1216 if (cl
->basename
== NULL
)
1219 cl
->basename
= cfg
->basename
;
1221 exitfileerror(20, "basename has to be specified in the config section inside of a class section\n");
1224 /* MUI classes are always private */
1225 if (cl
->classtype
== MUI
|| cl
->classtype
== MCC
|| cl
->classtype
== MCP
)
1226 cl
->options
|= COPTION_PRIVATE
;
1228 if (cl
->classid
== NULL
1229 && (cl
->classtype
!= MUI
&& cl
->classtype
!= MCC
&& cl
->classtype
!= MCP
)
1232 if (cl
->classtype
== HIDD
)
1234 cl
->options
&= !COPTION_PRIVATE
;
1236 else if (cl
->options
& COPTION_PRIVATE
)
1238 cl
->classid
= "NULL";
1244 if (cl
->classtype
== GADGET
|| cl
->classtype
== IMAGE
|| cl
->classtype
== CLASS
|| cl
->classtype
== USBCLASS
)
1246 sprintf(s
, "\"%sclass\"", inclass
? cl
->basename
: cfg
->modulename
);
1248 else if (cl
->classtype
== DATATYPE
)
1250 sprintf(s
, "\"%s.datatype\"", inclass
? cl
->basename
: cfg
->modulename
);
1252 cl
->classid
= strdup(s
);
1256 /* Only specify superclass or superclass_field */
1257 if (cl
->superclass
!= NULL
&& cl
->superclass_field
!= NULL
)
1258 exitfileerror(20, "Only specify one of superclass or superclass_field in config section\n");
1260 /* Give default value to superclass if it is not specified */
1261 if (cl
->superclass
== NULL
&& cl
->superclass
== NULL
)
1263 switch (cl
->classtype
)
1267 cl
->superclass
= "MUIC_Area";
1270 cl
->superclass
= "MUIC_Mccprefs";
1273 cl
->superclass
= "IMAGECLASS";
1276 cl
->superclass
= "GADGETCLASS";
1279 cl
->superclass
= "DATATYPESCLASS";
1282 cl
->superclass
= "ROOTCLASS";
1285 cl
->superclass
= "CLID_Root";
1288 exitfileerror(20, "Internal error: unhandled classtype in readsectionconfig\n");
1295 static void readsectioncdef(struct config
*cfg
)
1304 exitfileerror(20, "unexptected end of file in section cdef\n");
1306 if (strncmp(line
, "##", 2)!=0)
1308 slist_append(&cfg
->cdeflines
, line
);
1313 while (isspace(*s
)) s
++;
1314 if (strncmp(s
, "end", 3)!=0)
1315 exitfileerror(20, "\"##end cdef\" expected\n");
1318 while (isspace(*s
)) s
++;
1319 if (strncmp(s
, "cdef", 4)!=0)
1320 exitfileerror(20, "\"##end cdef\" expected\n");
1323 while (isspace(*s
)) s
++;
1325 exitfileerror(20, "unexpected character at position %d\n");
1332 static void readsectioncdefprivate(struct config
*cfg
)
1341 exitfileerror(20, "unexptected end of file in section cdef\n");
1343 if (strncmp(line
, "##", 2)!=0)
1345 slist_append(&cfg
->cdefprivatelines
, line
);
1350 while (isspace(*s
)) s
++;
1351 if (strncmp(s
, "end", 3)!=0)
1352 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1355 while (isspace(*s
)) s
++;
1356 if (strncmp(s
, "cdefprivate", 11)!=0)
1357 exitfileerror(20, "\"##end cdefprivate\" expected\n");
1360 while (isspace(*s
)) s
++;
1362 exitfileerror(20, "unexpected character at position %d\n");
1369 static void readsectionstartup(struct config
*cfg
)
1378 exitfileerror(20, "unexptected end of file in section startup\n");
1380 if (strncmp(line
, "##", 2)!=0)
1382 slist_append(&cfg
->startuplines
, line
);
1387 while (isspace(*s
)) s
++;
1388 if (strncmp(s
, "end", 3)!=0)
1389 exitfileerror(20, "\"##end startup\" expected\n");
1392 while (isspace(*s
)) s
++;
1393 if (strncmp(s
, "startup", 7)!=0)
1394 exitfileerror(20, "\"##end startup\" expected\n");
1397 while (isspace(*s
)) s
++;
1399 exitfileerror(20, "unexpected character at position %d\n");
1406 static void readsectionfunctionlist(const char *type
, struct functionhead
**funclistptr
, unsigned int firstlvo
, int isattribute
)
1409 char *line
, *s
, *s2
;
1410 unsigned int lvo
= firstlvo
;
1417 exitfileerror(20, "unexpected EOF in functionlist section\n");
1418 if (strlen(line
)==0)
1420 if (*funclistptr
!= NULL
)
1421 funclistptr
= &((*funclistptr
)->next
);
1424 else if (isspace(*line
))
1427 while (isspace(*s
)) s
++;
1430 if (*funclistptr
!= NULL
)
1431 funclistptr
= &((*funclistptr
)->next
);
1435 exitfileerror(20, "no space allowed before functionname\n");
1437 else if (strncmp(line
, "##", 2)==0)
1440 while (isspace(*s
)) s
++;
1441 if (strncmp(s
, "end", 3)!=0)
1442 exitfileerror(20, "\"##end %s\" expected\n", type
);
1445 while (isspace(*s
)) s
++;
1446 if (strncmp(s
, type
, strlen(type
))!=0)
1447 exitfileerror(20, "\"##end %s\" expected\n", type
);
1450 while (isspace(*s
)) s
++;
1452 exitfileerror(20, "unexpected character on position %d\n", s
-line
);
1456 else if (*line
=='.')
1459 if (strncmp(s
, "skip", 4)==0)
1465 exitfileerror(20, "syntax is '.skip n'\n");
1467 n
=strtol(s
, &s2
, 10);
1469 exitfileerror(20, "positive number expected\n");
1471 while (isspace(*s2
)) s2
++;
1472 if ((*s2
!= '\0') && (*s2
!= '#'))
1473 exitfileerror(20, "syntax is '.skip n'\n");
1474 if (*funclistptr
!= NULL
)
1475 funclistptr
= &((*funclistptr
)->next
);
1478 else if (strncmp(s
, "alias", 5)==0)
1483 exitfileerror(20, "syntax is '.alias name'\n");
1485 while (isspace(*s
)) s
++;
1486 if (*s
== '\0' || !(isalpha(*s
) || *s
== '_'))
1487 exitfileerror(20, "syntax is '.alias name'\n");
1491 while (isalnum(*s
) || *s
== '_') s
++;
1498 } while (isspace(*s
));
1502 exitfileerror(20, "syntax is '.alias name'\n");
1504 if (*funclistptr
== NULL
)
1505 exitfileerror(20, ".alias has to come after a function declaration\n");
1507 slist_append(&(*funclistptr
)->aliases
, s2
);
1509 else if (strncmp(s
, "function", 8) == 0)
1514 exitfileerror(20, "Syntax error\n");
1516 while (isspace(*s
)) s
++;
1517 if (*s
== '\0' || !(isalpha(*s
) || *s
== '_'))
1518 exitfileerror(20, "syntax is '.function name'\n");
1522 while (isalnum(*s
) || *s
== '_') s
++;
1529 } while (isspace(*s
));
1533 exitfileerror(20, "syntax is '.function name'\n");
1535 if (*funclistptr
== NULL
)
1536 exitfileerror(20, ".function has to come after a function declaration\n");
1538 funcsetinternalname(*funclistptr
, s2
);
1540 else if (strncmp(s
, "cfunction", 9)==0)
1542 if (*funclistptr
== NULL
)
1543 exitfileerror(20, ".cfunction has to come after a function declaration\n");
1545 (*funclistptr
)->libcall
= REGISTER
;
1547 else if (strncmp(s
, "private", 7)==0)
1549 if (*funclistptr
== NULL
)
1550 exitfileerror(20, ".private has to come after a function declaration\n");
1552 (*funclistptr
)->priv
= 1;
1554 else if (strncmp(s
, "novararg", 8)==0)
1556 if (*funclistptr
== NULL
)
1557 exitfileerror(20, ".novararg has to come after a function declaration\n");
1559 (*funclistptr
)->novararg
= 1;
1561 else if (strncmp(s
, "version", 7) == 0)
1563 /* Mark version number for the following
1564 * functions, so that the automatic OpenLibrary()
1565 * will know what version to use.
1572 while (isspace(*s
)) s
++;
1573 ver
= (int)strtol(s
, &tmp
, 0);
1576 exitfileerror(20, ".version expects an integer\n");
1579 while (isspace(*s
)) s
++;
1581 if (*s
&& *s
!= '#')
1582 exitfileerror(20, ".version has junk after the version number\n");
1586 else if (strncmp(s
, "unusedlibbase", 13) == 0)
1588 if (*funclistptr
== NULL
)
1589 exitfileerror(20, ".unusedlibbase has to come after a function declaration\n");
1590 (*funclistptr
)->unusedlibbase
= 1;
1593 exitfileerror(20, "Syntax error");
1595 else if (*line
!='#') /* Ignore line that is a comment, e.g. that starts with a # */
1597 /* The line is a function or attribute prototype.
1598 * A function can have one of two syntaxes:
1599 * type funcname(argproto1, argproto2, ...)
1600 * type funcname(argproto1, argproto2, ...) (reg1, reg2, ...)
1601 * The former is for C type function argument passing, the latter for
1602 * register argument passing.
1603 * An attribute has the following syntax:
1606 char c
, *args
[64], *regs
[64], *funcname
, *cp
;
1607 int len
, argcount
= 0, regcount
= 0, brcount
= 0;
1609 cp
= strchr(line
,'#');
1613 /* Parse 'type functionname' at the beginning of the line */
1615 s
= line
+ strlen(line
);
1617 s
= strchr(line
, '(');
1619 exitfileerror(20, "( expected at position %d\n", strlen(line
) + 1);
1623 while (isspace(*(s2
-1)))
1627 while (s2
> line
&& !isspace(*(s2
-1)) && !(*(s2
-1) == '*'))
1631 exitfileerror(20, "No type specifier before %s name\n", isattribute
? "attribute" : "function");
1633 if (*funclistptr
!= NULL
)
1634 funclistptr
= &((*funclistptr
)->next
);
1635 *funclistptr
= newfunctionhead(s2
, STACK
);
1638 (*funclistptr
)->comment
= strdup(cp
);
1640 (*funclistptr
)->comment
= NULL
;
1642 while (isspace(*(s2
-1)))
1645 (*funclistptr
)->type
= strdup(line
);
1646 (*funclistptr
)->lvo
= lvo
;
1647 (*funclistptr
)->version
= minversion
;
1653 /* Parse function prototype */
1670 && !(brcount
== 0 && (*s
== ',' || *s
== ')'))
1680 exitfileerror(20, "Unexected ')' at position %d\n", s
-line
+1);
1687 exitfileerror(20, "'(' without ')'");
1690 while (isspace(*(s2
-1)))
1694 if (!(s2
> args
[argcount
- 1]))
1695 exitfileerror(20, "Syntax error in function prototype\n");
1701 while (*s
!= '\0' && isspace(*s
))
1706 /* Parse registers specifications if available otherwise this prototype for C type argument passing */
1708 /* There may be no register specified with () so be sure then c is == ')' */
1723 if (memchr("AD",s
[0],2)!=NULL
&& memchr("01234567",s
[1],8)!=NULL
)
1730 if (s
[0] == s
[-3] && s
[1] == s
[-2] + 1)
1737 "wrong register specification \"%s\" for argument %u\n",
1738 regs
[regcount
-1], regcount
1742 exitfileerror(20, "maximum four arguments passed in two registers allowed (%d, %s) \n", regcount
, regs
[regcount
-1]);
1748 "wrong register \"%s\" for argument %u\n",
1749 regs
[regcount
-1], regcount
1758 exitfileerror(20, "'(' without ')'\n");
1759 if (c
!= ',' && c
!= ')')
1760 exitfileerror(20, "',' or ')' expected at position %d\n", s
-line
+1);
1766 while (isspace(*s
)) s
++;
1768 exitfileerror(20, "wrong char '%c' at position %d\n", *s
, (int)(s
-line
) + 1);
1770 if (argcount
!= regcount
)
1771 exitfileerror(20, "Number of arguments (%d) and registers (%d) mismatch\n",
1775 (*funclistptr
)->libcall
= REGISTERMACRO
;
1776 for (i
= 0; i
< argcount
; i
++)
1777 funcaddarg(*funclistptr
, args
[i
], regs
[i
]);
1779 else if (*s
== '\0')
1780 { /* No registers specified */
1781 for (i
= 0; i
< argcount
; i
++)
1782 funcaddarg(*funclistptr
, args
[i
], NULL
);
1785 exitfileerror(20, "wrong char '%c' at position %d\n", *s
, (int)(s
-line
) + 1);
1790 static void readsectionclass_methodlist(struct classinfo
*cl
)
1793 char *line
, *s
, *s2
;
1794 struct functionhead
**methlistptr
= &cl
->methlist
;
1795 struct stringlist
*interface
= NULL
;
1797 if (cl
->basename
==NULL
)
1798 exitfileerror(20, "section methodlist has to come after section config\n");
1804 exitfileerror(20, "unexptected EOF in methodlist section\n");
1806 /* Ignore empty lines or lines that qre a comment, e.g. that starts with a # */
1807 if (strlen(line
)==0 || (line
[0] == '#' && line
[1] != '#'))
1811 exitfileerror(20, "No space allowed at start of the line\n");
1813 if (strncmp(line
, "##", 2)==0) /* Is this the end ? */
1816 while (isspace(*s
)) s
++;
1817 if (strncmp(s
, "end", 3)!=0)
1818 exitfileerror(20, "\"##end methodlist\" expected\n");
1821 while (isspace(*s
)) s
++;
1822 if (strncmp(s
, "methodlist", 10)!=0)
1823 exitfileerror(20, "\"##end methodlist\" expected\n");
1826 while (isspace(*s
)) s
++;
1828 exitfileerror(20, "unexpected character on position %d\n", s
-line
);
1838 if (strncmp(s
, "alias", 5)==0)
1843 exitfileerror(20, "syntax is '.alias name'\n");
1845 while (isspace(*s
)) s
++;
1846 if (*s
== '\0' || !(isalpha(*s
) || *s
== '_'))
1847 exitfileerror(20, "syntax is '.alias name'\n");
1851 while (isalnum(*s
) || *s
== '_') s
++;
1858 } while (isspace(*s
));
1862 exitfileerror(20, "syntax is '.alias name'\n");
1864 if (*methlistptr
== NULL
)
1865 exitfileerror(20, ".alias has to come after a function declaration\n");
1867 slist_append(&(*methlistptr
)->aliases
, s2
);
1869 else if (strncmp(s
, "function", 8) == 0)
1874 exitfileerror(20, "Syntax error\n");
1876 while (isspace(*s
)) s
++;
1877 if (*s
== '\0' || !(isalpha(*s
) || *s
== '_'))
1878 exitfileerror(20, "syntax is '.function name'\n");
1882 while (isalnum(*s
) || *s
== '_') s
++;
1889 } while (isspace(*s
));
1893 exitfileerror(20, "syntax is '.function name'\n");
1895 if (*methlistptr
== NULL
)
1896 exitfileerror(20, ".function has to come after a function declaration\n");
1898 funcsetinternalname(*methlistptr
, s2
);
1900 else if (strncmp(s
, "interface", 9) == 0)
1902 if (cl
->classtype
!= HIDD
)
1903 exitfileerror(20, "interface only valid for a HIDD\n");
1908 exitfileerror(20, "Syntax error\n");
1910 while (isspace(*s
)) s
++;
1911 if (*s
== '\0' || !isalpha(*s
))
1912 exitfileerror(20, "syntax is '.interface name'\n");
1916 while (isalnum(*s
) || *s
== '_') s
++;
1923 } while (isspace(*s
));
1927 exitfileerror(20, "syntax is '.interface name'\n");
1929 interface
= slist_append(&cl
->interfaces
, s2
);
1932 exitfileerror(20, "Syntax error");
1934 else if (isalpha(*line
))
1938 for (s
= line
+ 1; isalnum(*s
) || *s
== '_'; s
++)
1941 if (cl
->classtype
== HIDD
&& interface
== NULL
)
1942 exitfileerror(20, "For a HIDD the first method has to come after an .interface line\n");
1945 exitfileerror(20, "Only letters, digits and an underscore allowed in a methodname\n");
1947 if (*methlistptr
!= NULL
)
1948 methlistptr
= &((*methlistptr
)->next
);
1949 if (cl
->classtype
!= HIDD
)
1951 if (snprintf(stmp
, 256, "%s__%s", cl
->basename
, line
) >= 256)
1952 exitfileerror(20, "Method name too large\n");
1954 *methlistptr
= newfunctionhead(stmp
, STACK
);
1955 (*methlistptr
)->type
= "IPTR";
1956 funcaddarg(*methlistptr
, "Class *cl", NULL
);
1957 funcaddarg(*methlistptr
, "Object *o", NULL
);
1958 funcaddarg(*methlistptr
, "Msg msg", NULL
);
1962 if (snprintf(stmp
, 256, "%s__%s__%s", cl
->basename
, interface
->s
, line
) >= 256)
1963 exitfileerror(20, "Method name too large\n");
1965 *methlistptr
= newfunctionhead(stmp
, STACK
);
1966 (*methlistptr
)->type
= "IPTR";
1967 funcaddarg(*methlistptr
, "OOP_Class *cl", NULL
);
1968 funcaddarg(*methlistptr
, "OOP_Object *o", NULL
);
1969 funcaddarg(*methlistptr
, "OOP_Msg msg", NULL
);
1970 (*methlistptr
)->interface
= interface
;
1971 if (snprintf(stmp
, 256, "mo%s_%s", interface
->s
, line
) >= 256)
1972 exitfileerror(20, "Method name too large\n");
1973 (*methlistptr
)->method
= strdup(stmp
);
1975 slist_append(&(*methlistptr
)->aliases
, line
);
1978 exitfileerror(20, "Methodname has to begin with a letter\n");
1983 readsectioninterface(struct config
*cfg
)
1986 struct interfaceinfo
*in
;
1988 in
= newinterface(cfg
);
1989 s
= readsections(cfg
, NULL
, in
, 1);
1991 exitfileerror(20, "Unexpected end of file\n");
1993 if (strncmp(s
, "##", 2) != 0)
1994 exitfileerror(20, "'##end interface' expected\n");
1997 while (isspace(*s
)) s
++;
1999 if (strncmp(s
, "end", 3) != 0)
2000 exitfileerror(20, "'##end interface' expected\n");
2004 exitfileerror(20, "'##end interface' expected\n");
2005 while (isspace(*s
)) s
++;
2007 if (strncmp(s
, "interface", 9) != 0)
2008 exitfileerror(20, "'##end interface' expected\n");
2011 while (isspace(*s
)) s
++;
2013 exitfileerror(20, "'##end interface' expected\n");
2015 if (!in
->interfaceid
)
2016 exitfileerror(20, "interface has no 'interfaceid' defined!\n");
2018 if (!in
->interfacename
)
2019 exitfileerror(20, "interface has no 'interfacename' defined!\n");
2021 if (!in
->methodstub
)
2022 in
->methodstub
= strdup(in
->interfacename
);
2024 if (!in
->methodbase
) {
2025 int len
= strlen(in
->interfacename
);
2026 in
->methodbase
= malloc(len
+ 4 + 1);
2027 strcpy(in
->methodbase
, in
->interfacename
);
2028 strcat(in
->methodbase
, "Base");
2031 if (!in
->attributebase
) {
2032 int len
= strlen(in
->interfacename
);
2033 in
->attributebase
= malloc(len
+ 4 + 4 + 1);
2034 strcpy(in
->attributebase
, in
->interfacename
);
2035 strcat(in
->attributebase
, "AttrBase");
2040 readsectionclass(struct config
*cfg
)
2043 struct classinfo
*cl
;
2046 s
= readsections(cfg
, cl
, NULL
, 1);
2048 exitfileerror(20, "Unexpected end of file\n");
2050 if (strncmp(s
, "##", 2) != 0)
2051 exitfileerror(20, "'##end class' expected\n");
2054 while (isspace(*s
)) s
++;
2056 if (strncmp(s
, "end", 3) != 0)
2057 exitfileerror(20, "'##end class' expected\n");
2061 exitfileerror(20, "'##end class' expected\n");
2062 while (isspace(*s
)) s
++;
2064 if (strncmp(s
, "class", 5) != 0)
2065 exitfileerror(20, "'##end class' expected\n");
2068 while (isspace(*s
)) s
++;
2070 exitfileerror(20, "'##end class' expected\n");
2073 static struct classinfo
*newclass(struct config
*cfg
)
2075 struct classinfo
*cl
, *classlistit
;
2077 cl
= malloc(sizeof(struct classinfo
));
2080 fprintf(stderr
, "Out of memory\n");
2083 memset(cl
, 0, sizeof(struct classinfo
));
2085 /* By default the classes are initialized with a priority of 1 so they
2086 * are initialized before any user added initialization with priority 1
2090 if (cfg
->classlist
== NULL
)
2091 cfg
->classlist
= cl
;
2096 classlistit
= cfg
->classlist
;
2097 classlistit
->next
!= NULL
;
2098 classlistit
= classlistit
->next
2101 classlistit
->next
= cl
;
2107 static struct handlerinfo
*newhandler(struct config
*cfg
)
2109 struct handlerinfo
*hl
;
2111 hl
= calloc(1,sizeof(*hl
));
2112 hl
->next
= cfg
->handlerlist
;
2113 cfg
->handlerlist
= hl
;
2117 static struct interfaceinfo
*newinterface(struct config
*cfg
)
2119 struct interfaceinfo
*in
, *interfacelistit
;
2121 in
= malloc(sizeof(struct interfaceinfo
));
2124 fprintf(stderr
, "Out of memory\n");
2127 memset(in
, 0, sizeof(struct interfaceinfo
));
2129 if (cfg
->interfacelist
== NULL
)
2130 cfg
->interfacelist
= in
;
2135 interfacelistit
= cfg
->interfacelist
;
2136 interfacelistit
->next
!= NULL
;
2137 interfacelistit
= interfacelistit
->next
2140 interfacelistit
->next
= in
;
2147 static int getdirective(char *s
, const char *directive
, int range_min
, int range_max
, int *val
)
2152 if (strncmp(s
, directive
, strlen(directive
)) != 0)
2155 s
+= strlen(directive
);
2156 if (*s
&& !isspace(*s
))
2157 exitfileerror(20, "Unrecognized directive \".%s\"\n", directive
);
2159 while (isspace(*s
)) s
++;
2161 exitfileerror(20, "No .%s value specified\n", directive
);
2163 newval
= strtol(s
, &tmp
, 0);
2164 if (s
== tmp
|| !(newval
>= range_min
&& newval
<= range_max
)) {
2166 while (*tmp
&& !isspace(*tmp
)) tmp
++;
2167 exitfileerror(20, "Invalid .%s value of %.*s\n", directive
, tmp
- s
, s
);
2175 readsectionhandler(struct config
*cfg
)
2177 char *line
= NULL
, *s
;
2178 struct handlerinfo
*hl
;
2179 unsigned char autolevel
= 0;
2180 unsigned int stacksize
= 0;
2184 int has_filesystem
= 0;
2192 s
= line
= readline();
2195 exitfileerror(20, "unexpected end of file in section hanlder\n");
2197 if (strncmp(s
, "##", 2)==0)
2200 /* Ignore comments */
2201 if (strncmp(s
, "#", 1)==0)
2204 /* Skip ahead to function name */
2205 while (*s
&& isspace(*s
)) s
++;
2207 /* Permit blank lines */
2215 if (getdirective(s
, "autodetect", 0, 127, &val
)) {
2217 } else if (getdirective(s
, "stacksize", 0, INT_MAX
, &val
)) {
2219 } else if (getdirective(s
, "priority", -128, 127, &val
)) {
2221 } else if (getdirective(s
, "bootpri", -128, 127, &val
)) {
2223 } else if (getdirective(s
, "startup", INT_MIN
, INT_MAX
, &val
)) {
2226 exitfileerror(20, "Unrecognized directive \"%s\"\n", line
);
2232 unsigned int id
= 0;
2234 if (strncasecmp(s
,"resident=",9)==0) {
2237 s
= strchr(s
, '=') + 1;
2239 while (*s
&& !isspace(*s
)) s
++;
2241 exitfileerror(20, "Empty resident= is not permitted\n");
2246 hl
= newhandler(cfg
);
2247 hl
->type
= HANDLER_RESIDENT
;
2249 hl
->name
= strdup(res
);
2250 hl
->autodetect
= autolevel
--;
2251 hl
->stacksize
= stacksize
;
2252 hl
->priority
= priority
;
2253 hl
->startup
= startup
;
2254 } else if (strncasecmp(s
,"dosnode=",8)==0) {
2257 s
= strchr(s
, '=') + 1;
2259 while (*s
&& !isspace(*s
)) s
++;
2261 exitfileerror(20, "Empty dosnode= is not permitted\n");
2266 hl
= newhandler(cfg
);
2267 hl
->type
= HANDLER_DOSNODE
;
2269 hl
->name
= strdup(dev
);
2270 hl
->autodetect
= autolevel
? autolevel
-- : 0;
2271 hl
->stacksize
= stacksize
;
2272 hl
->priority
= priority
;
2273 hl
->startup
= startup
;
2274 hl
->bootpri
= bootpri
;
2275 } else if (strncasecmp(s
,"dostype=",8) == 0) {
2276 s
= strchr(s
, '=') + 1;
2278 id
= (unsigned int)strtoul(s
, &tmp
, 0);
2281 while (*tmp
&& !isspace(*tmp
))
2283 exitfileerror(20, "\"%.*s\" is not a numerical DOS ID\n", (tmp
-s
), s
);
2287 if (id
== 0 || id
== ~0) {
2288 exitfileerror(20, "DOS ID 0x%08x is not permitted\n", id
);
2291 hl
= newhandler(cfg
);
2292 hl
->type
= HANDLER_DOSTYPE
;
2295 hl
->autodetect
= autolevel
? autolevel
-- : 0;
2296 hl
->stacksize
= stacksize
;
2297 hl
->priority
= priority
;
2298 hl
->startup
= startup
;
2300 for (tmp
= s
; !isspace(*tmp
); tmp
++);
2301 exitfileerror(20, "Unknown option \"%.*s\"\n", tmp
- s
, s
);
2304 /* Advance to next ID */
2305 while (*s
&& isspace(*s
)) s
++;
2311 exitfileerror(20, "Unexpected end of file\n");
2313 if (strncmp(s
, "##", 2) != 0)
2314 exitfileerror(20, "'##end handler' expected\n");
2317 while (isspace(*s
)) s
++;
2319 if (strncmp(s
, "end", 3) != 0)
2320 exitfileerror(20, "'##end handler' expected\n");
2323 while (isspace(*s
)) s
++;
2325 if (strncmp(s
, "handler", 7) != 0)
2326 exitfileerror(20, "'##end handler' expected\n");
2329 while (isspace(*s
)) s
++;
2331 exitfileerror(20, "'##end handler' expected\n");