Renamed include file aros/_timeval.h to aros/types/timeval_s.h.
[AROS.git] / tools / genmf / genmf.c
blob9f3f9ef9fc65387f7f3881191dfe2d56ff95703c
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define PROTOTYPES
7 #define HAVE_STDARG_H
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <assert.h>
13 #include <ctype.h>
14 #include <errno.h>
16 #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
17 # include <stdarg.h>
18 # define VA_START(args, lastarg) va_start(args, lastarg)
19 #else
20 # include <varargs.h>
21 # define VA_START(args, lastarg) va_start(args)
22 #endif
24 #ifdef PROTOTYPES
25 # define PARAMS(x) x
26 #else
27 # define PARAMS(x) ()
28 #endif /* PROTOTYPES */
31 /* Types */
32 typedef struct _Node Node;
34 struct _Node
36 Node * next,
37 * prev;
38 char * name;
41 typedef struct
43 Node * first,
44 * last,
45 * prelast;
47 List;
49 typedef struct
51 int len;
52 int max;
53 char * value;
55 String;
57 typedef struct
59 Node node;
60 int argcount;
61 List args;
62 String * body;
64 Template;
66 typedef struct
68 Node node;
69 char * defval;
70 /* char * value; */
71 int flags;
72 int pos;
73 #define ARGF_MULTI 1
74 #define ARGF_ALWAYS 2
75 #define ARGF_GOTIT 4
77 Arg;
79 /* Globals */
80 List templates;
81 char * curdir = NULL;
83 /* Macros */
84 # define NewList(l) (((List *)l)->prelast = (Node *)(l), \
85 ((List *)l)->last = 0, \
86 ((List *)l)->first = (Node *)&(((List *)l)->last))
88 # define AddHead(l,n) ((void)(\
89 ((Node *)n)->next = ((List *)l)->first, \
90 ((Node *)n)->prev = (Node *)&((List *)l)->first, \
91 ((List *)l)->first->prev = ((Node *)n), \
92 ((List *)l)->first = ((Node *)n)))
94 # define AddTail(l,n) ((void)(\
95 ((Node *)n)->next = (Node *)&((List *)l)->last, \
96 ((Node *)n)->prev = ((List *)l)->prelast, \
97 ((List *)l)->prelast->next = ((Node *)n), \
98 ((List *)l)->prelast = ((Node *)n) ))
100 # define Remove(n) ((void)(\
101 ((Node *)n)->prev->next = ((Node *)n)->next,\
102 ((Node *)n)->next->prev = ((Node *)n)->prev ))
104 # define GetHead(l) (void *)(((List *)l)->first->next \
105 ? ((List *)l)->first \
106 : (Node *)0)
107 # define GetTail(l) (void *)(((List *)l)->prelast->prev \
108 ? ((List *)l)->prelast \
109 : (Node *)0)
110 # define GetNext(n) (void *)(((Node *)n)->next->next \
111 ? ((Node *)n)->next \
112 : (Node *)0)
113 # define GetPrev(n) (void *)(((Node *)n)->prev->prev \
114 ? ((Node *)n)->prev \
115 : (Node *)0)
116 # define ForeachNode(l,n) \
117 for (n=(void *)(((List *)(l))->first); \
118 ((Node *)(n))->next; \
119 n=(void *)(((Node *)(n))->next))
120 # define ForeachNodeSafe(l,node,nextnode) \
121 for (node=(void *)(((List *)(l))->first); \
122 ((nextnode)=(void*)((Node *)(node))->next); \
123 (node)=(void *)(nextnode))
125 #define cfree(x) if (x) free (x)
126 #define SETSTR(str,val) \
127 cfree (str); \
128 str = val ? xstrdup (val) : NULL
130 #define xstrdup(str) _xstrdup(str,__FILE__,__LINE__)
131 #define xmalloc(size) _xmalloc(size,__FILE__,__LINE__)
132 #define xfree(ptr) _xfree(ptr,__FILE__,__LINE__)
134 #define new(type) xmalloc(sizeof(type))
136 /* Prototypes */
137 extern void cleanup PARAMS ((int exitcode));
138 extern void error PARAMS ((const char * fmt, ...));
140 /* Functions */
141 char *
142 _xstrdup (const char * str, const char * file, int line)
144 char * nstr;
146 if (!str)
148 fprintf (stderr, "NULL string passed to strdup from %s:%d\n", file, line);
149 cleanup (20);
152 nstr = strdup (str);
154 if (!nstr)
156 fprintf (stderr, "Out of memory in %s:%d\n", file, line);
157 cleanup (20);
160 return nstr;
163 void *
164 _xmalloc (size_t size, const char * file, int line)
166 void * ptr;
168 ptr = malloc (size);
170 if (size && !ptr)
172 fprintf (stderr, "Out of memory in %s:%d", file, line);
173 cleanup (20);
176 return ptr;
179 void
180 _xfree (void * ptr, const char * file, int line)
182 if (ptr)
184 #if 0
185 ((int *)ptr)[0] = 0xDEADBEEF;
186 #endif
187 free (ptr);
189 else
190 fprintf (stderr, "Illegal free(NULL) in %s:%d", file, line);
193 Node * FindNode (const List * l, const char * name)
195 Node * n;
197 ForeachNode (l, n)
199 if (!strcmp (n->name, name))
200 return n;
203 return NULL;
206 void error (const char * fmt, ...)
208 va_list args;
209 VA_START (args, fmt);
210 fprintf (stderr, "Error: ");
211 vfprintf (stderr, fmt, args);
212 fprintf (stderr, ": %s\n", strerror (errno));
213 va_end (args);
214 exit (1);
217 void cleanup (int exitcode)
219 #if 0
220 if (startdir)
222 chdir (startdir);
223 free (startdir);
225 #endif
227 exit (exitcode);
230 String * new_string (const char * init)
232 String * s = new (String);
234 if (init && *init)
236 s->len = strlen (init);
237 s->max = (s->len+31)&-32;
238 s->value = xmalloc (s->max+1);
239 strcpy (s->value, init);
241 else
243 s->len = 0;
244 s->max = 32;
245 s->value = xmalloc (s->max+1);
246 s->value[0] = 0;
249 return s;
252 void free_string (String * s)
254 cfree (s->value);
255 xfree (s);
258 void append_string (String * s, const char * app)
260 int len;
262 if (!app || !*app)
263 return;
265 len = strlen (app);
267 if (len < s->max - s->len - 1)
269 strcpy (s->value+s->len, app);
270 s->len += len;
272 else
274 char * ns;
276 s->max = (s->len+len+31) & -32;
278 ns = xmalloc (s->max+1);
280 strcpy (ns, s->value);
281 strcpy (ns+s->len, app);
283 s->len += len;
285 xfree (s->value);
286 s->value = ns;
290 String * getline (FILE * fh)
292 String * s = NULL;
293 char line[256], * ptr;
294 int len;
296 for (;;)
298 ptr = fgets (line, sizeof (line), fh);
300 if (!ptr)
301 break;
303 len = strlen (line);
305 if (line[len - 1] == '\n')
307 line[len - 1] = 0;
309 if (s)
310 append_string (s, line);
311 else
312 s = new_string (line);
314 break;
317 if (s)
318 append_string (s, line);
319 else
320 s = new_string (line);
323 return s;
326 void add_continuation(String *s, FILE *fh)
328 String *s2;
330 while (s->value[s->len-1]=='\\')
332 s2 = getline(fh);
333 s->value[s->len-1]='\0';
334 s->len--;
335 append_string(s, s2->value);
336 free_string(s2);
341 void output (const char * line, FILE * outfile)
343 const char * ptr = line;
345 while (*ptr)
347 if (*ptr == '$' && ptr[1] == '(' && curdir &&
348 !strncmp ("CURDIR)", ptr+2, 7)
351 ptr += 9;
352 fputs (curdir, outfile);
354 else
356 fputc (*ptr, outfile);
357 ptr ++;
362 char ** getargs (const char * line, int * argc)
364 static char * argv[64];
365 static char * buffer = NULL;
366 char * src;
367 int arg;
369 cfree (buffer);
371 assert (line);
373 buffer = xstrdup (line);
375 assert (buffer);
377 src = buffer;
378 arg = 0;
380 while (*src)
382 while (isspace (*src))
383 src ++;
385 if (!*src)
386 break;
388 assert (arg < 63);
389 argv[arg++] = src;
391 while (*src && !isspace (*src))
393 if (*src == '"')
395 src ++;
397 while (*src && *src != '"')
398 src ++;
400 src ++;
402 else
403 src ++;
406 if (*src)
407 *src++ = 0;
410 argv[arg] = NULL;
412 if (argc)
413 *argc = arg;
415 return argv;
418 void print_template (Template * tmpl)
420 Arg * arg;
422 printf ("Template %s:\n", tmpl->node.name);
423 ForeachNode (&tmpl->args, arg)
425 printf (" %s (%s) %d\n", arg->node.name,
426 arg->defval ? arg->defval : "--none--",
427 arg->flags
430 printf (" body=%s---\n", tmpl->body->value);
433 void read_templates (const char * fn)
435 FILE * fh;
436 String * line;
437 Template * tmpl = NULL;
438 char * ptr;
439 char ** argv;
440 int argc;
442 if (!(fh = fopen (fn, "r")) )
444 error ("Can't open %s for reading", fn);
445 cleanup (10);
448 while ((line = getline (fh)))
450 ptr = line->value;
451 while (isspace (*ptr)) ptr++;
453 if (!strncmp (ptr, "%define", 7))
455 int t;
456 char * defval, * flags;
457 Arg * arg;
459 add_continuation(line, fh);
461 tmpl = new (Template);
463 NewList (&tmpl->args);
464 tmpl->body = NULL;
466 argv = getargs (line->value, &argc);
468 tmpl->node.name = xstrdup (argv[1]);
469 tmpl->argcount = argc-2;
471 for (t=2; t<argc; t++)
473 defval = argv[t];
475 while (*defval && *defval != '=') defval ++;
477 if (*defval)
478 *defval ++ = 0;
480 flags = defval;
482 if (*flags)
484 flags += strlen (flags);
486 while (flags-2 >= defval && flags[-2] == '/' && isalpha (flags[-1]))
487 flags -= 2;
489 if (*flags)
490 *flags++ = 0;
493 #if 0
494 printf ("arg=\"%s\" defval=\"%s\" flags=\"%s\"\n",
495 argv[t], defval, flags);
496 #endif
498 arg = new (Arg);
500 arg->node.name = xstrdup (argv[t]);
501 arg->pos = t-2;
503 if (*defval)
505 if (*defval == '"')
507 defval ++;
508 defval[strlen (defval) -1] = 0;
511 arg->defval = xstrdup (defval);
513 else
514 arg->defval = NULL;
516 arg->flags = 0;
518 while (*flags)
520 if (*flags == 'M')
521 arg->flags |= ARGF_MULTI;
522 else if(*flags == 'A')
523 arg->flags |= ARGF_ALWAYS;
524 else
525 error ("Unknown flag %s in argument %s of template %s",
526 flags, arg->node.name, tmpl->node.name);
528 flags ++;
529 if (*flags)
530 flags ++;
533 AddTail (&tmpl->args, arg);
536 free_string (line);
538 while ((line = getline (fh)))
540 if (!strcmp (line->value, "%end"))
541 break;
543 ptr = line->value;
544 while (isspace(*ptr)) ptr++;
545 if (*ptr=='%' && ptr[1]!='(' && ptr[1]!='\0')
546 add_continuation(line, fh);
548 if (tmpl->body)
549 append_string (tmpl->body, line->value);
550 else
551 tmpl->body = new_string (line->value);
553 append_string (tmpl->body, "\n");
556 #if 0
557 print_template (tmpl);
558 #endif
559 AddTail (&templates, tmpl);
562 free_string (line);
565 fclose (fh);
568 Arg * findArg (Template * tmpl, char ** argstr)
570 char argname[64];
571 char * ptr = *argstr;
572 int len;
573 Arg * arg;
575 ptr += 2;
576 len = 0;
578 while (*ptr && *ptr != ')')
579 argname[len++] = *ptr++;
581 argname[len] = 0;
582 if (*ptr) ptr++;
584 arg = (Arg *)FindNode (&tmpl->args, argname);
586 if (!arg)
587 error ("Unknown argument %s for template %s",
588 argname, tmpl->node.name);
590 *argstr = ptr;
592 return arg;
595 void replace_template (const char * string, FILE * outfile)
597 char ** argv;
598 int argc, t;
599 Template * tmpl;
600 Arg * arg;
601 char * argnptr, * value, * ptr;
602 char ** values, * freeflags;
604 argv = getargs (string, &argc);
606 tmpl = (Template *) FindNode (&templates, argv[0]+1);
608 if (!tmpl)
610 /* Print no error for GNU Make patterns */
611 /* error ("Can't find template %s\n", argv[0]); */
612 fputs (string, outfile);
614 else
616 values = xmalloc (sizeof (values[0]) * tmpl->argcount);
617 freeflags = xmalloc (sizeof (freeflags[0]) * tmpl->argcount);
619 t = 0;
620 ForeachNode (&tmpl->args, arg)
622 freeflags[t] = 0;
623 values[t] = arg->defval ? arg->defval : "";
624 t ++;
626 assert (t == tmpl->argcount);
628 arg = GetHead (&tmpl->args);
630 for (t=1; t<argc; t++)
632 value = argv[t];
633 while (*value && *value != '=') value++;
635 if (*value)
637 argnptr = argv[t];
638 *value ++ = 0;
640 else
642 argnptr = "";
643 value = argv[t];
646 if (*value == '"')
648 value ++;
649 value[strlen (value) - 1] = 0;
652 if (*argnptr)
654 arg = (Arg *) FindNode (&tmpl->args, argnptr);
655 if (!arg)
656 error ("Unknown argument %s to template %s", argnptr, tmpl->node.name);
659 if (arg->flags & ARGF_MULTI)
661 String * vals = new_string (value);
663 for (t++; t<argc; t++)
665 append_string (vals, " ");
666 append_string (vals, argv[t]);
669 values[arg->pos] = vals->value;
670 freeflags[arg->pos] = 1;
671 vals->value = NULL;
672 free_string (vals);
673 arg->flags |= ARGF_GOTIT;
675 else
677 arg->flags |= ARGF_GOTIT;
678 values[arg->pos] = xstrdup (value);
679 freeflags[arg->pos] = 1;
680 arg = GetNext (arg);
684 ForeachNode (&tmpl->args, arg)
686 if( arg->flags & ARGF_ALWAYS
687 && (arg->flags & ARGF_GOTIT) == 0 )
689 error("No value supplied for argument %s for template %s",
690 arg->node.name, tmpl->node.name
695 for (ptr=tmpl->body->value; *ptr; )
697 if (*ptr == '%' && ptr[1] == '(' /*)*/)
699 arg = findArg (tmpl, &ptr);
700 if (arg)
701 output (values[arg->pos], outfile);
703 else if (*ptr == '%')
705 /* nested template */
706 String * str = new_string ("");
707 char app[2];
708 app[1] = 0;
710 while (*ptr)
712 if (*ptr == '%' && ptr[1] == '(' /*)*/)
714 arg = findArg (tmpl, &ptr);
715 if (arg)
716 append_string (str, values[arg->pos]);
718 else
720 app[0] = *ptr++;
721 append_string (str, app);
724 if (*ptr == '\n')
725 break;
728 replace_template (str->value, outfile);
729 free_string (str);
731 else if (*ptr == '$' && ptr[1] == '(' && curdir &&
732 !strncmp ("CURDIR)", ptr+2, 7)
735 ptr += 9;
736 fputs (curdir, outfile);
738 else
740 fputc (*ptr, outfile);
741 ptr ++;
745 for (t=0; t<tmpl->argcount; t++)
747 if (freeflags[t])
748 xfree (values[t]);
751 xfree (values);
752 xfree (freeflags);
756 void process_file(FILE * infile, FILE *outfile)
758 char * ptr;
759 String * line;
760 int common = 0;
762 fputs (
763 "####################################################################\n"
764 "####################################################################\n"
765 "############# THIS IS A GENERATED FILE ! DO NOT EDIT ###############\n"
766 "####################################################################\n"
767 "####################################################################\n"
768 , outfile
771 while ((line = getline (infile)))
773 ptr = line->value;
774 while (isspace (*ptr)) ptr++;
776 if (*ptr == '%')
778 int pos = ptr - line->value;
780 if (!strncmp (ptr+1, "common", 6))
781 common = 1;
783 add_continuation (line, infile);
784 ptr = line->value + pos;
786 replace_template (ptr, outfile);
788 else
790 output (line->value, outfile);
791 fputc ('\n', outfile);
794 free_string (line);
797 if (!common)
799 replace_template ("%common", outfile);
804 int main (int argc, char ** argv)
806 int t;
807 FILE * infile = NULL, * outfile = NULL;
808 FILE * listfile = NULL;
809 char * infilename, *outfilename;
810 String * line;
812 NewList (&templates);
814 for (t=1; t<argc; t++)
816 if (!strncmp ("--curdir=", argv[t], 9))
817 curdir = argv[t] + 9;
818 else if(!strncmp ("--listfile", argv[t], 10))
820 // next parameter is the list file name
821 if (t+1 <= argc)
823 if (!(listfile = fopen (argv[t+1], "r" )))
825 error ( "Can't open list file %s\n", argv[t+1] );
826 t++;
829 else
830 error ( "No list file name given\n" );
832 else
833 read_templates (argv[t]);
835 if (listfile)
837 for (t = 0; line = getline (listfile); t++)
839 infilename = strtok (line->value, " \t");
840 if (!infilename)
841 error("Syntax error in list file at line %d\n", t);
842 outfilename = strtok (NULL, " \t");
843 if (!outfilename)
844 error("Syntax error in list file at line %d\n", t);
845 if (!(infile = fopen (infilename, "r")))
846 error("Can't open input file %s\n", infilename);
847 if (!(outfile = fopen (outfilename, "w")))
848 error("Can't open output file %s\n", outfilename);
849 process_file (infile, outfile);
850 fclose (infile);
851 fclose (outfile);
852 free_string (line);
854 fclose (listfile);
856 else process_file (stdin, stdout);
858 return 0;