genmf.py: print dots instead of "Regenerating n of m" as progress indicator.
[AROS.git] / tools / hiddtool / hiddtool.c
blobced2357533865fe3f3300b21e51bfb06dd213c7d
1 /* Hiddtool
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
4 This file is part of Hiddtool
6 Hiddtool is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 Hiddtool is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20 /* Includes */
21 // #include "config.h"
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <assert.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <stdlib.h>
30 #include <time.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <sys/types.h>
35 #define TRUE 1
36 #define FALSE 0
38 /* Types */
39 typedef struct _Node Node;
41 struct _Node
43 Node * next,
44 * prev;
45 char * name;
48 typedef struct
50 Node * first,
51 * last,
52 * prelast;
54 List;
56 typedef struct
58 Node node;
59 char * value;
61 Var;
63 typedef struct
65 Node node;
66 List deps;
67 int circularcheck; /* Used when checking for circular dependencies */
69 } Item;
71 typedef struct {
73 List items;
74 } DepsDB;
76 typedef struct {
77 Node node;
78 int opt;
79 } Conf;
81 enum {
82 OPT_KERNEL,
83 OPT_DISK
86 /* Macros */
87 # define NewList(l) (((List *)l)->prelast = (Node *)(l), \
88 ((List *)l)->last = 0, \
89 ((List *)l)->first = (Node *)&(((List *)l)->last))
91 # define AddHead(l,n) ((void)(\
92 ((Node *)n)->next = ((List *)l)->first, \
93 ((Node *)n)->prev = (Node *)&((List *)l)->first, \
94 ((List *)l)->first->prev = ((Node *)n), \
95 ((List *)l)->first = ((Node *)n)))
97 # define AddTail(l,n) ((void)(\
98 ((Node *)n)->next = (Node *)&((List *)l)->last, \
99 ((Node *)n)->prev = ((List *)l)->prelast, \
100 ((List *)l)->prelast->next = ((Node *)n), \
101 ((List *)l)->prelast = ((Node *)n) ))
103 # define Remove(n) ((void)(\
104 ((Node *)n)->prev->next = ((Node *)n)->next,\
105 ((Node *)n)->next->prev = ((Node *)n)->prev ))
107 # define GetHead(l) (void *)(((List *)l)->first->next \
108 ? ((List *)l)->first \
109 : (Node *)0)
110 # define GetTail(l) (void *)(((List *)l)->prelast->prev \
111 ? ((List *)l)->prelast \
112 : (Node *)0)
113 # define GetNext(n) (void *)(((Node *)n)->next->next \
114 ? ((Node *)n)->next \
115 : (Node *)0)
116 # define GetPrev(n) (void *)(((Node *)n)->prev->prev \
117 ? ((Node *)n)->prev \
118 : (Node *)0)
120 #define InsertBefore(n, before) \
121 ((Node *)before)->prev->next = n; \
122 ((Node *)n)->prev = ((Node *)before)->prev; \
123 ((Node *)before)->prev = n; \
124 ((Node *)n)->next = before;
126 # define ForeachNode(l,n) \
127 for (n=(void *)(((List *)(l))->first); \
128 ((Node *)(n))->next; \
129 n=(void *)(((Node *)(n))->next))
130 # define ForeachNodeSafe(l,node,nextnode) \
131 for (node=(void *)(((List *)(l))->first); \
132 ((nextnode)=(void*)((Node *)(node))->next); \
133 (node)=(void *)(nextnode))
135 #define cfree(x) if (x) free (x)
136 #define SETSTR(str,val) \
137 cfree (str); \
138 str = val ? xstrdup (val) : NULL
140 #define xstrdup(str) _xstrdup(str,__FILE__,__LINE__)
141 #define xmalloc(size) _xmalloc(size,__FILE__,__LINE__)
142 #define xfree(ptr) _xfree(ptr,__FILE__,__LINE__)
143 #define new(x) ((x *) xmalloc (sizeof (x)))
146 /* Functions */
147 char *
148 _xstrdup (const char * str, const char * file, int line)
150 char * nstr;
152 assert (str);
154 nstr = strdup (str);
156 if (!nstr)
158 fprintf (stderr, "Out of memory in %s:%d", file, line);
159 exit (20);
162 return nstr;
165 void *
166 _xmalloc (size_t size, const char * file, int line)
168 void * ptr;
170 ptr = malloc (size);
172 if (size && !ptr)
174 fprintf (stderr, "Out of memory in %s:%d", file, line);
175 exit (20);
178 return ptr;
181 void
182 _xfree (void * ptr, const char * file, int line)
184 if (ptr)
185 free (ptr);
186 else
187 fprintf (stderr, "Illegal free(NULL) in %s:%d", file, line);
190 Node *
191 findnode (const List * l, const char * name)
193 Node * n;
195 ForeachNode (l, n)
197 if (!strcmp (n->name, name))
198 return n;
201 return NULL;
205 void
206 printlist (List * l)
208 Node * n;
210 ForeachNode (l,n)
212 printf (" \"%s\"\n", n->name);
219 void cleanup(int exitcode)
221 exit(exitcode);
224 void usage()
226 fprintf(stderr, "Usage: hiddtool -k configfile: get list of all kernel hidds\n");
227 fprintf(stderr, " hiddtool -d configfile: get list of all disk hidds\n");
228 fprintf(stderr, " hiddtool -m configfile: generate metamake dependancies\n");
229 cleanup(1);
232 /* Returns pointer to next noblank car or NULL if end of buffer is reached */
233 char *next_not_blank(char *s)
235 while (*s && isspace(*s)) {
236 s ++;
238 if (0 == *s)
239 s = NULL;
241 return s;
244 /* Returns pointer to end of word or NULL on error */
245 char *end_of_word(char *word)
247 char *s = word;
248 while (*s && (isalpha(*s) || *s == '-')) {
249 s ++;
252 if (s == word) /* Target was of length 0 ? */
253 s = NULL;
255 return s;
258 void print_deps_db(DepsDB *db)
260 Item *item;
262 ForeachNode(&db->items, item) {
263 Node *depnode;
265 printf("%s :", item->node.name);
267 ForeachNode(&item->deps, depnode) {
268 printf(" %s", depnode->name);
271 printf("\n");
275 static inline void freenode(Node *n)
277 if (NULL != n->name) {
278 xfree(n->name);
279 n->name = NULL;
282 xfree(n);
285 void free_deps_db(DepsDB *db)
287 Item *item, *safeitem;
289 ForeachNodeSafe(&db->items, item, safeitem) {
290 Node *depnode, *safedepnode;
292 ForeachNodeSafe(&item->deps, depnode, safedepnode) {
293 freenode(depnode);
295 freenode((Node *)item);
298 xfree(db);
302 DepsDB *build_deps_db(char *filename)
304 DepsDB *db;
305 FILE *f;
306 int ok = 1;
308 db = xmalloc(sizeof (*db));
309 NewList(&db->items);
311 f = fopen(filename, "r");
312 if (NULL == f) {
313 fprintf(stderr, "Could not open dependancy db file %s\n", filename);
314 ok = FALSE;
315 } else {
316 /* Read in all the dependancies */
317 char buf[500];
318 int line;
320 line = 0;
321 while(ok) {
322 char *s;
323 char *target, *target_end;
324 Item *item;
325 int done = FALSE;
326 if (NULL == fgets(buf, sizeof (buf), f))
327 break;
328 line ++;
330 s = buf;
332 /* Parse the contents in the buffer */
333 target = s = next_not_blank(s);
334 if (NULL == target)
335 continue;
337 s = end_of_word(s);
338 if (NULL == s) {
339 fprintf(stderr, "Malformed target at line %d in %s\n", line, filename);
340 ok = FALSE;
341 break;
343 target_end = s;
345 /* Go to next not blanke */
346 s = next_not_blank(s);
347 if (NULL == s) {
348 fprintf(stderr, "Missing colon at line %d in %s\n", line, filename);
349 ok = FALSE;
350 break;
353 if (*s != ':') {
354 fprintf(stderr, "Rubbish instead of colon at line %d in %s\n", line, filename);
355 ok = FALSE;
356 break;
359 s ++;
361 *target_end = 0;
362 /* Now read all the targets dependancies */
364 /* Allocate a db item */
365 item = xmalloc(sizeof (*item));
366 item->node.name = xstrdup(target);
367 item->circularcheck = 0;
369 NewList(&item->deps);
371 /* Add it to the db */
372 AddTail(&db->items, item);
375 /* Read all the dependencies */
377 while(!done && ok) {
378 Node *depnode;
380 char *dep, *dep_end;
381 dep = s = next_not_blank(s);
382 if (NULL == dep) {
383 break;
385 dep_end = s = end_of_word(s);
386 if (NULL == dep_end) {
387 fprintf(stderr, "Malformed dependancy at line %d in %s\n", line, filename);
388 ok = 0;
389 break;
394 if (*s == 0) {
395 done = 1;
396 } else {
397 s ++;
400 *dep_end = 0;
402 depnode = xmalloc(sizeof (*depnode));
403 depnode->name = xstrdup(dep);
405 AddTail(&item->deps, depnode);
407 } /* while (parse deps) */
409 } /* while (parse lines) */
411 fclose(f);
412 } /* if (file opened) */
414 if (!ok) {
415 free_deps_db(db);
416 db = NULL;
418 return db;
422 void free_list(List *conf)
424 Conf *cnode, *safe;
426 ForeachNodeSafe(conf, cnode, safe) {
427 freenode((Node *)cnode);
429 xfree(conf);
432 void print_conf(List *conf)
434 Conf *cnode;
436 ForeachNode(conf, cnode) {
437 char *optstr;
438 switch (cnode->opt) {
439 case OPT_KERNEL:
440 optstr = "kernel";
441 break;
442 case OPT_DISK:
443 optstr = "disk";
444 break;
446 default:
447 fprintf(stderr, "print_conf: unknown option %d\n", cnode->opt);
448 cleanup(1);
449 break;
451 printf("%s => %s\n", cnode->node.name, optstr);
455 List *get_conf(char *filename)
457 FILE *f;
458 List *conf;
459 int ok = TRUE;
460 int line = 0;
462 conf = xmalloc(sizeof (*conf));
463 NewList(conf);
465 f = fopen(filename, "r");
466 if (NULL == f) {
467 fprintf(stderr, "Could not open config file %s\n", filename);
468 ok = FALSE;
469 } else {
470 while (ok) {
471 char buf[500];
472 char *s, *target, *target_end, *opt, *opt_end;
473 Conf *cnode;
475 if (NULL == fgets(buf, sizeof(buf), f))
476 break;
478 s = buf;
479 line ++;
481 target = s = next_not_blank(s);
482 if (NULL == target)
483 continue; /* Handle blank lines */
485 target_end = s = end_of_word(s);
486 if (NULL == s) {
487 fprintf(stderr, "Malformed target at line %d in %s\n", line, filename);
488 ok = FALSE;
489 break;
492 opt = s = next_not_blank(s);
493 if (NULL == opt) {
494 fprintf(stderr, "Missing option at line %d in %s\n", line, filename);
495 ok = FALSE;
496 break;
499 if (opt == target_end) {
500 fprintf(stderr, "Malformed option at line %d in %s\n", line, filename);
501 ok = FALSE;
502 break;
504 *target_end = 0;
506 opt_end = s = end_of_word(s);
507 if (NULL == opt_end) {
508 fprintf(stderr, "Malformed option at line %d in %s\n", line, filename);
509 ok = FALSE;
510 break;
513 if (NULL != next_not_blank(s)) {
514 fprintf(stderr, "Rubbish at end of line %d in %s\n", line, filename);
515 ok = FALSE;
516 break;
519 *opt_end = 0;
521 cnode = xmalloc(sizeof (*cnode));
522 AddTail(conf, cnode);
523 cnode->node.name = xstrdup(target);
525 if (0 == strcmp(opt, "kernel")) {
526 cnode->opt = OPT_KERNEL;
527 } else if (0 == strcmp(opt, "disk")) {
528 cnode->opt = OPT_DISK;
529 } else {
530 fprintf(stderr, "Unknown option %s at line %d in %s\n", opt, line, filename);
531 ok = FALSE;
532 break;
535 fclose(f);
538 if (!ok) {
539 free_list(conf);
540 conf = NULL;
542 return conf;
545 int checkcircular(Item *cur, DepsDB *ddb, Item **circ_found)
547 Item *depnode;
549 if (cur->circularcheck) {
550 fprintf(stderr, "Circular dependency detected:\n");
551 fprintf(stderr, "%s depends on ", cur->node.name);
552 *circ_found = cur;
553 return FALSE;
555 cur->circularcheck = 1;
557 ForeachNode(&cur->deps, depnode) {
558 Item *dep;
560 dep = (Item *)findnode(&ddb->items, depnode->node.name);
561 if (NULL != dep) {
562 /*fprintf(stderr, "checking cirular on dependcy of %s: %s\n", cur->node.name, dep->node.name);
563 */ if (!checkcircular(dep, ddb, circ_found)) {
564 if (NULL != *circ_found) {
565 if (0 == strcmp(cur->node.name, (*circ_found)->node.name)) {
566 fprintf(stderr, "%s\n", cur->node.name);
567 *circ_found = NULL;
568 } else {
569 fprintf(stderr, "%s depends on ", cur->node.name);
572 return FALSE;
578 cur->circularcheck = 0;
580 return TRUE;
583 int add_deps(List *l, Node *dependee, Item *item, DepsDB *ddb)
585 Node *n;
586 Item *circ_found;
587 /*fprintf(stderr, "Looking at dep %s\n", item->node.name);
589 if (!checkcircular(item, ddb, &circ_found))
590 return FALSE;
592 /* Check if this item allredy exists in the list */
593 n = findnode(l, item->node.name);
594 if (NULL != n) {
595 /*fprintf(stderr, "Allready existed in list\n");
596 */ } else{
597 Item *depnode;
599 n = xmalloc(sizeof (*n));
600 n->name = xstrdup(item->node.name);
602 if (NULL != dependee) {
604 /* Insert before the dependee */
605 /*fprintf(stderr, "Inserted before dependee %s\n", dependee->name);
606 */ InsertBefore(n, dependee);
607 } else {
609 /*fprintf(stderr, "Added at end of list\n");
610 */ AddTail(l, n);
613 /* Go through everything we depend on and add it to the list */
614 ForeachNode(&item->deps, depnode) {
615 Item *dep;
616 /*fprintf(stderr, "Looking at dep in list: %s\n", depnode->node.name);
617 */ /* Find the item in the deps DB */
618 dep = (Item *)findnode(&ddb->items, depnode->node.name);
619 if (NULL != dep) {
620 /*fprintf(stderr, "Found dep for %s: %s\n", depnode->node.name, dep->node.name);
621 */ /* This dependany has more under-dependancies. Check it out */
622 if (!add_deps(l, n, dep, ddb))
623 return FALSE;
624 } else {
625 fprintf(stderr, "Non existing dependancy: %s\n", depnode->node.name);
626 return FALSE;
631 return TRUE;
635 List *do_deps(List *conf, DepsDB *ddb, int opt)
637 Conf *cnode;
638 List *deps;
639 int ok = TRUE;
641 deps = xmalloc(sizeof (*deps));
642 NewList(deps);
644 /* Go through all entries in the conf list */
645 ForeachNode(conf, cnode) {
646 Item *item;
647 if (opt != cnode->opt)
648 continue;
650 /* Find in the deps db */
651 item = (Item *)findnode(&ddb->items, cnode->node.name);
652 if (NULL == item) {
653 fprintf(stderr, "Target %s could not be found in dependancy db\n", cnode->node.name);
654 ok = FALSE;
655 break;
658 if (!add_deps(deps, NULL, item, ddb)) {
659 ok = FALSE;
660 break;
664 if (!ok) {
665 free_list(deps);
666 deps = NULL;
669 return deps;
672 void print_deps(List *deps, const char *pre)
674 Node *dnode;
676 ForeachNode(deps, dnode) {
677 printf("%s%s ", pre, dnode->name);
681 #define get_kernel_deps(conf, ddb) \
682 do_deps(conf, ddb, OPT_KERNEL)
684 List *get_disk_deps(List *conf, DepsDB *ddb, List *supkdeps)
686 List *ddeps;
688 /* First get the disk deps */
689 ddeps = do_deps(conf, ddb, OPT_DISK);
690 if (NULL != ddeps) {
691 List *kdeps = NULL;
692 if (NULL == supkdeps) {
693 kdeps = do_deps(conf, ddb, OPT_KERNEL);
694 } else {
695 kdeps = supkdeps;
697 if (NULL != kdeps) {
698 Node *ddep, *ddepsafe;
699 /* Go through all disk deps and see if it exists among the kernel deps. If so, remove it */
700 ForeachNodeSafe(ddeps, ddep, ddepsafe) {
701 Node *kdep;
703 kdep = findnode(kdeps, ddep->name);
704 if (NULL != kdep) {
705 /* Allready in kernel. Remove from disk */
706 Remove(ddep);
707 freenode(ddep);
712 if (NULL == supkdeps)
713 free_list(kdeps); /* Dependancies were gotten incide here */
715 return ddeps;
717 free_list(ddeps);
721 return NULL;
724 void print_meta_targets(List *deps, const char *text)
726 printf("#MM hidd-%s : ", text);
727 print_deps(deps, "hidd-");
729 printf("\n");
730 printf("hidd-%s : hidd-%s-local\n",text, text);
731 printf("\t@(NOP)\n");
734 int do_metamake(List *conf, DepsDB *ddb)
736 List *kdeps;
737 int ret = FALSE;
739 kdeps = get_kernel_deps(conf, ddb);
740 if (NULL != kdeps) {
741 List *ddeps;
743 ddeps = get_disk_deps(conf, ddb, kdeps);
744 if (NULL != ddeps) {
746 print_meta_targets(kdeps, "kernel");
747 printf("\n");
748 print_meta_targets(ddeps, "disk");
750 ret = TRUE;
752 free_list(ddeps);
754 free_list(kdeps);
756 return ret;
761 #define DEPSFILE "./hidds.dep"
763 #define DO_DISK 0x01
764 #define DO_KERNEL 0x02
765 #define DO_METAMAKE 0x04
769 int main(int argc, char *argv[])
771 DepsDB *ddb;
772 int exitcode = 0;
773 int action = 0;
776 char *configfile;
778 for (;;) {
779 int c;
780 c = getopt(argc, argv, "kdm");
781 if (-1 == c)
782 break;
783 switch (c) {
784 case 'k':
785 action |= DO_KERNEL;
786 break;
788 case 'd':
789 action |= DO_DISK;
790 break;
792 case 'm':
793 action |= DO_METAMAKE;
794 break;
796 default:
797 usage();
802 if (optind + 1 != argc)
803 usage();
805 configfile = argv[optind];
809 /* We used flags to get the options. This way we easily catch the case where
810 the user has passed more than one option.
812 if (action != DO_KERNEL && action != DO_DISK && action != DO_METAMAKE)
813 usage();
816 ddb = build_deps_db(DEPSFILE);
817 if (NULL != ddb) {
818 List *conf;
820 // print_deps_db(ddb);
822 conf = get_conf(configfile);
823 if (NULL != conf) {
824 List *deps = NULL;
825 switch (action) {
826 case DO_DISK:
827 deps = get_disk_deps(conf, ddb, NULL);
828 break;
830 case DO_KERNEL: {
831 deps = get_kernel_deps(conf, ddb);
832 break;
835 case DO_METAMAKE:
836 if (!do_metamake(conf, ddb)) {
837 exitcode = 1;
839 break;
844 /* Print and free stuff from DO_DISK and DO_KERNEL */
845 if (action == DO_DISK || action == DO_KERNEL) {
846 if (NULL != deps) {
847 print_deps(deps, "");
848 free_list(deps);
849 } else {
850 exitcode = 1;
854 free_list(conf);
856 } else {
857 exitcode = 1;
860 free_deps_db(ddb);
862 } else {
863 exitcode = 1;
866 return exitcode;