1 /*-
2 * Copyright (c) 2011-2021 Hans Petter Selasky <hselasky@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <ctype.h>
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <sysexits.h>
32 #include <err.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36
37 #include <sys/queue.h>
38 #include <sys/stat.h>
39 #include <errno.h>
40
41 struct node;
42 typedef TAILQ_HEAD(, node) node_head_t;
43 typedef TAILQ_ENTRY(node) node_entry_t;
44
45 struct config;
46 typedef TAILQ_HEAD(, config) config_head_t;
47 typedef TAILQ_ENTRY(config) config_entry_t;
48
49 struct directory;
50 typedef TAILQ_HEAD(, directory) directory_head_t;
51 typedef TAILQ_ENTRY(directory) directory_entry_t;
52
53 struct makefile;
54 typedef TAILQ_HEAD(, makefile) makefile_head_t;
55 typedef TAILQ_ENTRY(makefile) makefile_entry_t;
56
57 struct exclude;
58 typedef TAILQ_HEAD(, exclude) exclude_head_t;
59 typedef TAILQ_ENTRY(exclude) exclude_entry_t;
60
61 #if 0
62 void
63 style_fix(void)
64 {
65 }
66
67 #endif
68
69 struct node {
70 node_entry_t entry;
71 node_head_t children;
72 char *name; /* obj-y/obj-m/obj-n/xxx.o */
73 char *path; /* relative path to file */
74 char *objprefix; /* object prefix */
75 uint8_t has_children; /* set if object has children */
76 };
77
78 struct directory {
79 directory_entry_t entry;
80 char *name;
81 };
82
83 struct makefile {
84 makefile_entry_t entry;
85 char *name;
86 };
87
88 struct exclude {
89 exclude_entry_t entry;
90 char *name;
91 };
92
93 struct config {
94 config_entry_t entry;
95 char *name;
96 char *orig;
97 char value; /* m/y/n */
98 };
99
100 static node_head_t rootNode = TAILQ_HEAD_INITIALIZER(rootNode);
101 static config_head_t rootConfig = TAILQ_HEAD_INITIALIZER(rootConfig);
102 static directory_head_t rootDirectory = TAILQ_HEAD_INITIALIZER(rootDirectory);
103 static makefile_head_t rootMakefile = TAILQ_HEAD_INITIALIZER(rootMakefile);
104 static exclude_head_t rootExclude = TAILQ_HEAD_INITIALIZER(rootExclude);
105 static int opt_verbose;
106
107 static char *opt_config = "config";
108 static char *opt_input;
109 static char *opt_output;
110
111 static char *
strcatdup(const char * a,const char * b)112 strcatdup(const char *a, const char *b)
113 {
114 int al = strlen(a);
115 int bl = strlen(b);
116 char *ptr;
117
118 ptr = malloc(al + bl + 1);
119 if (ptr == NULL)
120 errx(EX_SOFTWARE, "Out of memory.");
121
122 memcpy(ptr, a, al);
123 memcpy(ptr + al, b, bl + 1);
124 return (ptr);
125 }
126
127 static struct node *
new_node(void)128 new_node(void)
129 {
130 struct node *temp;
131
132 temp = malloc(sizeof(*temp));
133 if (temp == NULL)
134 errx(EX_SOFTWARE, "Out of memory.");
135 memset(temp, 0, sizeof(*temp));
136 TAILQ_INIT(&temp->children);
137 return (temp);
138 }
139
140 static struct directory *
new_directory(void)141 new_directory(void)
142 {
143 struct directory *temp;
144
145 temp = malloc(sizeof(*temp));
146 if (temp == NULL)
147 errx(EX_SOFTWARE, "Out of memory.");
148 memset(temp, 0, sizeof(*temp));
149 return (temp);
150 }
151
152 static void
new_makefile(char * name)153 new_makefile(char *name)
154 {
155 struct makefile *temp;
156
157 temp = malloc(sizeof(*temp));
158 if (temp == NULL)
159 errx(EX_SOFTWARE, "Out of memory.");
160 memset(temp, 0, sizeof(*temp));
161 temp->name = name;
162 TAILQ_INSERT_TAIL(&rootMakefile, temp, entry);
163 }
164
165 static void
new_exclude(char * name)166 new_exclude(char *name)
167 {
168 struct exclude *temp;
169
170 temp = malloc(sizeof(*temp));
171 if (temp == NULL)
172 errx(EX_SOFTWARE, "Out of memory.");
173 memset(temp, 0, sizeof(*temp));
174 temp->name = name;
175 TAILQ_INSERT_TAIL(&rootExclude, temp, entry);
176 }
177
178 static uint8_t
match_exclude(const char * name)179 match_exclude(const char *name)
180 {
181 struct exclude *temp;
182
183 TAILQ_FOREACH(temp, &rootExclude, entry) {
184 if (strcmp(temp->name, name) == 0)
185 return (1);
186 }
187 return (0);
188 }
189
190 static int
sort_config_compare(const void * pa,const void * pb)191 sort_config_compare(const void *pa, const void *pb)
192 {
193 const struct config *ca = *(const void **)pa;
194 const struct config *cb = *(const void **)pb;
195
196 return (strcmp(ca->name, cb->name));
197 }
198
199 static void
sort_config(void)200 sort_config(void)
201 {
202 uint32_t x;
203 uint32_t count = 0;
204 struct config *c0;
205 struct config **ppc;
206
207 TAILQ_FOREACH(c0, &rootConfig, entry)
208 count++;
209
210 ppc = malloc(sizeof(void *) * count);
211 if (ppc == NULL)
212 return;
213
214 count = 0;
215 TAILQ_FOREACH(c0, &rootConfig, entry)
216 ppc[count++] = c0;
217
218 mergesort(ppc, count, sizeof(void *), sort_config_compare);
219
220 TAILQ_INIT(&rootConfig);
221
222 for (x = 0; x != count; x++)
223 TAILQ_INSERT_TAIL(&rootConfig, ppc[x], entry);
224
225 free(ppc);
226 }
227
228 static void
new_config(char * name,char * orig,char what)229 new_config(char *name, char *orig, char what)
230 {
231 struct config *c0;
232
233 TAILQ_FOREACH(c0, &rootConfig, entry) {
234 if (strcmp(c0->name, name) == 0) {
235 free(c0->orig);
236 free(name);
237 c0->value = what;
238 c0->orig = orig;
239 return;
240 }
241 }
242
243 c0 = malloc(sizeof(*c0));
244 if (c0 == NULL)
245 errx(EX_SOFTWARE, "Out of memory.");
246 memset(c0, 0, sizeof(*c0));
247 c0->name = name;
248 c0->value = what;
249 c0->orig = orig;
250
251 TAILQ_INSERT_TAIL(&rootConfig, c0, entry);
252 }
253
254 static void
free_node(struct node * node)255 free_node(struct node *node)
256 {
257 free(node->name);
258 free(node->objprefix);
259 free(node);
260 }
261
262 static char *
load_file(char * path)263 load_file(char *path)
264 {
265 int f;
266 long off;
267 char *ptr;
268
269 if (opt_verbose > 0)
270 fprintf(stderr, "Loading %s\n", path);
271
272 f = open(path, O_RDONLY);
273
274 free(path);
275
276 if (f < 0)
277 return (NULL);
278
279 off = lseek(f, 0, SEEK_END);
280 lseek(f, 0, SEEK_SET);
281
282 if (off < 0) {
283 close(f);
284 return (NULL);
285 }
286 ptr = malloc(off + 1);
287 if (ptr == NULL) {
288 close(f);
289 return (NULL);
290 }
291 if (read(f, ptr, off) != off) {
292 close(f);
293 return (NULL);
294 }
295 ptr[off] = 0;
296
297 while (off--) {
298 if (ptr[off] == 0)
299 ptr[off] = ' ';
300 }
301 return (ptr);
302 }
303
304 static char *
read_line(char ** ptr,int * line)305 read_line(char **ptr, int *line)
306 {
307 int c;
308 char *old = *ptr;
309 int ignore_nl = 0;
310
311 if (*old == 0)
312 return (NULL);
313
314 (*line)++;
315
316 while (1) {
317 c = **ptr;
318 if (c == 0)
319 break;
320
321 (*ptr)++;
322
323 switch (c) {
324 case ' ':
325 case '\t':
326 case '\r':
327 *((*ptr) - 1) = ' ';
328 break;
329 case '\\':
330 *((*ptr) - 1) = ' ';
331 ignore_nl = 1;
332 break;
333 case '\n':
334 if (ignore_nl) {
335 *((*ptr) - 1) = ' ';
336 (*line)++;
337 ignore_nl = 0;
338 break;
339 }
340 *((*ptr) - 1) = 0;
341 goto done;
342 default:
343 ignore_nl = 0;
344 break;
345 }
346 }
347 done:
348 return (old);
349 }
350
351 static void
skip_while(char ** ptr,char * what)352 skip_while(char **ptr, char *what)
353 {
354 int c;
355
356 while (1) {
357 c = **ptr;
358 if ((c != 0) && (strchr(what, c) != NULL)) {
359 (*ptr)++;
360 continue;
361 }
362 break;
363 }
364 }
365
366 static void
skip_until(char ** ptr,char * what)367 skip_until(char **ptr, char *what)
368 {
369 int c;
370
371 while (1) {
372 c = **ptr;
373 if ((c != 0) && (strchr(what, c) == NULL)) {
374 (*ptr)++;
375 continue;
376 }
377 break;
378 }
379 }
380
381 static void
skip_until_tp(char ** ptr,char * what)382 skip_until_tp(char **ptr, char *what)
383 {
384 int c;
385 int tp = 0;
386
387 while (1) {
388 c = **ptr;
389 if (c == '(')
390 tp++;
391 if (c == ')')
392 tp--;
393 if (c != 0) {
394 if (tp > 0) {
395 (*ptr)++;
396 continue;
397 }
398 if (strchr(what, c) == NULL) {
399 (*ptr)++;
400 continue;
401 }
402 }
403 break;
404 }
405 }
406
407 static struct node *
add_node(node_head_t * head,char * name)408 add_node(node_head_t *head, char *name)
409 {
410 struct node *node;
411
412 TAILQ_FOREACH(node, head, entry) {
413 if (strcmp(node->name, name) == 0) {
414 free(name);
415 return (node);
416 }
417 }
418 node = new_node();
419 node->name = name;
420 TAILQ_INSERT_TAIL(head, node, entry);
421 return (node);
422 }
423
424 static void
add_child(struct node * parent,char * path,char * name)425 add_child(struct node *parent, char *path, char *name)
426 {
427 struct node *node;
428
429 node = new_node();
430 node->name = name;
431 node->path = path;
432
433 TAILQ_INSERT_TAIL(&parent->children, node, entry);
434 }
435
436 static void
remove_duplicate(node_head_t * head)437 remove_duplicate(node_head_t *head)
438 {
439 struct node *n0;
440 struct node *n1;
441 struct node *n2;
442
443 TAILQ_FOREACH(n0, head, entry) {
444
445 n1 = TAILQ_NEXT(n0, entry);
446 if (n1 == NULL)
447 continue;
448 TAILQ_FOREACH_FROM_SAFE(n1, head, entry, n2) {
449 if (strcmp(n0->name, n1->name) == 0) {
450 TAILQ_REMOVE(head, n1, entry);
451 free_node(n1);
452 }
453 }
454 }
455 }
456
457 static void
resolve_nodes(void)458 resolve_nodes(void)
459 {
460 struct node *n0;
461 struct node *n1;
462 struct node *n2;
463 struct node *n3;
464
465 TAILQ_FOREACH(n0, &rootNode, entry) {
466
467 TAILQ_FOREACH_SAFE(n1, &n0->children, entry, n2) {
468
469 if (n1->name[0] == '$') {
470 char *ptr = n1->name;
471 int len = strlen(n1->name);
472
473 if (ptr[1] == '(') {
474 ptr += 2;
475 len -= 2;
476 }
477 if ((len != 0) && (ptr[len - 1] == ')')) {
478 ptr[len - 1] = 0;
479 len--;
480 }
481 TAILQ_REMOVE(&n0->children, n1, entry);
482
483 TAILQ_FOREACH(n3, &rootNode, entry) {
484
485 if (n3 == n0)
486 continue;
487
488 if (strcmp(n3->name, ptr) == 0) {
489 TAILQ_REMOVE(&rootNode, n3, entry);
490 TAILQ_CONCAT(&n0->children, &n3->children, entry);
491 free_node(n3);
492 break;
493 }
494 }
495 free_node(n1);
496 }
497 }
498 }
499
500 TAILQ_FOREACH(n0, &rootNode, entry)
501 remove_duplicate(&n0->children);
502 }
503
504 static uint8_t
obj_has_children(const node_head_t * parent,const char * name,int len)505 obj_has_children(const node_head_t *parent, const char *name, int len)
506 {
507 struct node *n0;
508
509 TAILQ_FOREACH(n0, parent, entry) {
510 if (TAILQ_FIRST(&n0->children) == NULL)
511 continue;
512 if (strstr(n0->name, name) == n0->name &&
513 (strcmp(n0->name + len, "-n") == 0 ||
514 strcmp(n0->name + len, "-y") == 0 ||
515 strcmp(n0->name + len, "-objs") == 0 ||
516 strcmp(n0->name + len, "-m") == 0)) {
517 return (1);
518 } else {
519 obj_has_children(&n0->children, name, len);
520 }
521 }
522 return (0);
523 }
524
525 static void
objs_exec(struct node * parent,void (* fn)(struct node *,const char *))526 objs_exec(struct node *parent, void (*fn) (struct node *, const char *))
527 {
528 static int recurse;
529
530 struct node *n0;
531 struct node *n1;
532 char *temp;
533 int len;
534
535 if (recurse > 64) {
536 errx(EX_SOFTWARE, "Recursive object "
537 "execute limit of 64 exceeded for '%s'.", parent->name);
538 }
539 recurse++;
540
541 temp = strcatdup(parent->name, "");
542 len = strlen(temp);
543
544 if ((len >= 2) && (temp[len - 2] == '.' && temp[len - 1] == 'o')) {
545 temp[len - 2] = 0;
546 len -= 2;
547 }
548 TAILQ_FOREACH(n0, &rootNode, entry) {
549 if (strstr(n0->name, temp) == n0->name) {
550
551 if (opt_verbose > 1) {
552 fprintf(stderr, "matching %s "
553 "= %s\n", temp, n0->name);
554 }
555 /* Expecting: <match>-<y/objs><null> */
556 if (strcmp(n0->name + len, "-y") == 0 ||
557 strcmp(n0->name + len, "-objs") == 0) {
558
559 TAILQ_FOREACH(n1, &n0->children, entry)
560 objs_exec(n1, fn);
561 }
562 }
563 }
564
565 fn(parent, temp);
566
567 free(temp);
568
569 recurse--;
570 }
571
572 static void
dump_nodes(node_head_t * head)573 dump_nodes(node_head_t *head)
574 {
575 static int level;
576 struct node *n0;
577 int x;
578
579 TAILQ_FOREACH(n0, head, entry) {
580
581 for (x = 0; x != level; x++)
582 fprintf(stderr, "\t");
583
584 fprintf(stderr, "%s%s\n", n0->name,
585 TAILQ_FIRST(&n0->children) ? " =" : "");
586
587 level++;
588
589 dump_nodes(&n0->children);
590
591 level--;
592 }
593 }
594
595 static char
get_config_entry(const char * what)596 get_config_entry(const char *what)
597 {
598 struct config *c0;
599
600 TAILQ_FOREACH(c0, &rootConfig, entry) {
601 if (c0->value == 'd')
602 continue;
603 if (strcmp(c0->name, what) == 0)
604 return (c0->value);
605 }
606
607 new_config(strcatdup(what, ""), NULL, 'n');
608
609 return ('n');
610 }
611
612 static void
variable_substitute(char * operator)613 variable_substitute(char *operator)
614 {
615 char *pt;
616 int len;
617
618 if (operator == NULL)
619 return;
620
621 pt = operator;
622 len = strlen(pt);
623
624 if (operator[1] == '(') {
625 operator += 2;
626 len -= 2;
627 }
628 if ((len != 0) && (operator[len - 1] == ')')) {
629 len--;
630 operator[len] = 0;
631 }
632 pt[0] = get_config_entry(operator);
633 pt[1] = 0;
634 }
635
636 static void
parse_config(char * path)637 parse_config(char *path)
638 {
639 char *file;
640 char *old_file;
641 char *ptr;
642 char *temp;
643 char *keyword;
644 int line;
645 int c;
646
647 line = 0;
648 old_file = file = load_file(strcatdup(path, ""));
649 if (file == NULL)
650 errx(EX_NOINPUT, "File '%sconfig' does not exist.", path);
651
652 while ((ptr = read_line(&file, &line))) {
653
654 skip_while(&ptr, "\t\r ");
655
656 /* discard comments */
657 if (*ptr == '#')
658 continue;
659
660 /* get next word */
661 temp = ptr;
662 skip_until(&temp, "\t\r =#");
663 if (temp == ptr)
664 continue;
665
666 /* duplicate word */
667 c = *temp;
668 *temp = 0;
669 keyword = strcatdup(ptr, "");
670 *temp = c;
671
672 /* skip operator */
673 ptr = temp;
674 skip_while(&temp, "\t\r =");
675 if (temp == ptr) {
676 free(keyword);
677 continue;
678 }
679 /* figure out value */
680 switch (temp[0]) {
681 case 'y':
682 new_config(keyword, NULL, 'y');
683 break;
684 case 'm':
685 new_config(keyword, NULL, 'm');
686 break;
687 case 'n':
688 new_config(keyword, NULL, 'n');
689 break;
690 case '\"':
691 case '0':
692 case '1':
693 case '2':
694 case '3':
695 case '4':
696 case '5':
697 case '6':
698 case '7':
699 case '8':
700 case '9':
701 new_config(keyword, strcatdup(temp, ""), 'd');
702 break;
703 default:
704 errx(EX_NOINPUT, "Invalid configuration "
705 "value '%c' at line %d.", temp[0], line);
706 break;
707 }
708 }
709 free(old_file);
710 }
711
712 static void
parse_makefile(char * path)713 parse_makefile(char *path)
714 {
715 static int recurse;
716
717 struct node *node;
718 char *file;
719 char *old_file;
720 char *ptr;
721 char *temp;
722 char *parent;
723 char *child;
724 struct directory *dir;
725 int line;
726 int skip = 0;
727 char c;
728
729 if (recurse > 64) {
730 errx(EX_SOFTWARE, "Recursive parse Makefile "
731 "limit of 64 exceeded in '%s'.", path);
732 }
733 recurse++;
734
735 dir = new_directory();
736 dir->name = strcatdup(path, "");
737
738 TAILQ_INSERT_TAIL(&rootDirectory, dir, entry);
739
740 line = 0;
741 old_file = file = load_file(strcatdup(path, "Makefile"));
742 if (file == NULL)
743 errx(EX_NOINPUT, "File '%sMakefile' does not exist.", path);
744
745 while ((ptr = read_line(&file, &line))) {
746
747 if (opt_verbose > 1)
748 fprintf(stderr, "line %d = %s\n", line, ptr);
749
750 skip_while(&ptr, "\t\r ");
751
752 /* discard comments */
753 if (*ptr == '#')
754 continue;
755
756 /* get next word */
757 temp = ptr;
758 skip_until(&temp, "\t\r :+=#");
759 if (temp == ptr)
760 continue;
761
762 /* duplicate word */
763 c = *temp;
764 *temp = 0;
765 parent = strcatdup(ptr, "");
766 *temp = c;
767
768 /* test for ifdef */
769 if (strcmp(parent, "ifdef") == 0 ||
770 strcmp(parent, "ifndef") == 0) {
771
772 char *a;
773 char b;
774
775 if (opt_verbose > 2) {
776 fprintf(stderr, "Found %s at line "
777 "%d level %d\n", parent, line, skip);
778 }
779 if (skip) {
780 skip++;
781 free(parent);
782 continue;
783 }
784 /* pass all ifdefs */
785
786 /* very simple expression matcher */
787
788 ptr = temp;
789 skip_while(&ptr, "\t\r ");
790
791 a = ptr;
792
793 skip_until(&ptr, "\t\r #");
794
795 c = *ptr;
796 *ptr = 0;
797 a = strcatdup(a, "");
798 *ptr = c;
799
800 b = get_config_entry(a);
801
802 if (opt_verbose > 2) {
803 fprintf(stderr, "Testing %s %c\n",
804 parent, b);
805 }
806 if (strcmp(parent, "ifdef") == 0) {
807 if (b == 'n')
808 skip++;
809 } else {
810 if (b != 'n')
811 skip++;
812 }
813
814 free(a);
815 free(parent);
816 continue;
817 }
818 /* test for ifeq and ifneq */
819 if (strcmp(parent, "ifeq") == 0 ||
820 strcmp(parent, "ifneq") == 0) {
821
822 char *a;
823 char *b;
824
825 if (opt_verbose > 2) {
826 fprintf(stderr, "Found %s at line "
827 "%d level %d\n", parent, line, skip);
828 }
829 if (skip) {
830 skip++;
831 free(parent);
832 continue;
833 }
834 /* very simple expression matcher */
835
836 ptr = temp;
837 skip_while(&ptr, "\t\r ");
838 if (ptr[0] != '(') {
839 if (opt_verbose > 2) {
840 fprintf(stderr, "Syntax error %s "
841 "at line %d level %d\n",
842 parent, line, skip);
843 }
844 skip++;
845 free(parent);
846 continue;
847 }
848 ptr++;
849
850 a = ptr;
851 skip_until_tp(&ptr, "\t\r ,");
852
853 c = *ptr;
854 *ptr = 0;
855 a = strcatdup(a, "");
856 *ptr = c;
857
858 skip_while(&ptr, "\t\r ,");
859 b = ptr;
860
861 skip_until_tp(&ptr, "\t\r )");
862
863 c = *ptr;
864 *ptr = 0;
865 b = strcatdup(b, "");
866 *ptr = c;
867
868 variable_substitute(strchr(a, '$'));
869 variable_substitute(strchr(b, '$'));
870
871 if (opt_verbose > 2) {
872 fprintf(stderr, "Comparing %s(%s,%s)\n",
873 parent, a, b);
874 }
875 if (strcmp(parent, "ifeq") == 0) {
876 if (strcmp(a, b) != 0)
877 skip++;
878 } else {
879 if (strcmp(a, b) == 0)
880 skip++;
881 }
882 free(parent);
883 free(a);
884 free(b);
885 continue;
886 }
887 /* test for ifeq and ifneq */
888 if (strcmp(parent, "endif") == 0) {
889
890 if (opt_verbose > 2) {
891 fprintf(stderr, "Found endif at line "
892 "%d level %d\n", line, skip);
893 }
894 if (skip)
895 skip--;
896
897 free(parent);
898 continue;
899 }
900 /* check if inside conditional */
901 if (skip) {
902 free(parent);
903 continue;
904 }
905 /* perform any variable substitution */
906 variable_substitute(strchr(parent, '$'));
907
908 /* get next operator, if any */
909 ptr = temp;
910 skip_while(&ptr, "\t\r ");
911 temp = ptr;
912 skip_while(&temp, ":+=");
913 if (temp == ptr) {
914 free(parent);
915 continue;
916 }
917 node = add_node(&rootNode, parent);
918
919 while (1) {
920
921 int len;
922
923 ptr = temp;
924 skip_while(&ptr, "\t\r ");
925 temp = ptr;
926 skip_until(&temp, "\t\r #");
927 if (temp == ptr)
928 break;
929
930 c = *temp;
931 *temp = 0;
932 child = strcatdup(ptr, "");
933 *temp = c;
934
935 len = strlen(child);
936 if (child[len - 1] == '/') {
937 if (strcmp(node->name, "obj-y") == 0 ||
938 strcmp(node->name, "obj-m") == 0)
939 parse_makefile(strcatdup(path, child));
940
941 } else if (match_exclude(child) == 0) {
942 add_child(node, strcatdup(path, ""), child);
943 }
944 }
945 }
946
947 free(old_file);
948
949 free(path);
950
951 recurse--;
952 }
953
954 static void
filter_objname(char * pch)955 filter_objname(char *pch)
956 {
957 while (*pch) {
958 if (*pch == '.' || *pch == '/' || *pch == '\\' || !isprint(*pch))
959 *pch = '-';
960 pch++;
961 }
962 }
963
964 static void
build_id(struct node * ptr,const char * name)965 build_id(struct node *ptr, const char *name)
966 {
967 ptr->objprefix = strdup(ptr->path);
968 if (ptr->objprefix == NULL)
969 errx(EX_SOFTWARE, "Out of memory.");
970
971 filter_objname(ptr->objprefix);
972
973 if (obj_has_children(&rootNode, name, strlen(name))) {
974 if (opt_verbose > 1) {
975 fprintf(stderr, "object %s has children\n", name);
976 }
977 ptr->has_children = 1;
978 } else {
979 ptr->has_children = 0;
980 }
981 }
982
983 static void
build_source(struct node * ptr,const char * name)984 build_source(struct node *ptr, const char *name)
985 {
986 char *objname;
987
988 if (ptr->has_children)
989 return;
990
991 objname = strdup(name);
992 filter_objname(objname);
993
994 printf("obj-%s%s.o: %s%s.c\n", ptr->objprefix, objname, ptr->path, name);
995 printf("\t" "${CC} -c -DCURR_FILE_NAME=\\\"%s\\\" ${CFLAGS} -o obj-%s%s.o %s%s.c\n",
996 name, ptr->objprefix, objname, ptr->path, name);
997
998 free(objname);
999 }
1000
1001 static void
build_objects(struct node * ptr,const char * name)1002 build_objects(struct node *ptr, const char *name)
1003 {
1004 char *objname;
1005
1006 if (ptr->has_children)
1007 return;
1008
1009 objname = strdup(name);
1010 filter_objname(objname);
1011
1012 printf("\t" "obj-%s%s.o \\\n", ptr->objprefix, objname);
1013
1014 free(objname);
1015 }
1016
1017 static void
output_makefile(char * name)1018 output_makefile(char *name)
1019 {
1020 struct node *n0;
1021 struct node *n1;
1022 struct directory *dir;
1023
1024 printf("#\n"
1025 "# This makefile was automatically generated. Do not edit!\n"
1026 "#\n"
1027 "\n");
1028
1029 printf("PKGPATHS+= \\\n");
1030
1031 TAILQ_FOREACH(dir, &rootDirectory, entry) {
1032 int c;
1033 int len;
1034
1035 len = strlen(dir->name);
1036 if (len > 0)
1037 c = dir->name[len - 1];
1038 else
1039 c = 0;
1040
1041 if (c == '/')
1042 dir->name[len - 1] = 0;
1043
1044 printf("%s \\\n", dir->name);
1045
1046 if (c == '/')
1047 dir->name[len - 1] = c;
1048 }
1049
1050 n0 = add_node(&rootNode, strcatdup(name, ""));
1051
1052 TAILQ_FOREACH(n1, &n0->children, entry) {
1053 objs_exec(n1, &build_id);
1054 }
1055
1056 printf("\n"
1057 "OBJS+= \\\n");
1058
1059 TAILQ_FOREACH(n1, &n0->children, entry) {
1060 objs_exec(n1, &build_objects);
1061 }
1062
1063 printf("\n");
1064
1065 TAILQ_FOREACH(n1, &n0->children, entry) {
1066 objs_exec(n1, &build_source);
1067 }
1068
1069 printf("\n");
1070
1071 printf(".if defined(LIB)\n"
1072 ".include \"${.CURDIR}/../../Makefile.lib\"\n"
1073 ".endif\n");
1074 }
1075
1076 static void
set_stdout(char * name)1077 set_stdout(char *name)
1078 {
1079 static int f = -1;
1080
1081 fflush(stdout);
1082
1083 if (f > -1)
1084 close(f);
1085
1086 f = open(name, O_WRONLY | O_TRUNC | O_CREAT, 0660);
1087
1088 free(name);
1089
1090 if (f < 0)
1091 err(EX_NOINPUT, "Could not set standard out");
1092
1093 if (dup2(f, STDOUT_FILENO) < 0)
1094 err(EX_NOINPUT, "Could not duplicate file descriptor");
1095 }
1096
1097 static char *
add_slashdup(char * ptr)1098 add_slashdup(char *ptr)
1099 {
1100 int len = strlen(ptr);
1101
1102 if (len && (ptr[len - 1] != '/'))
1103 return (strcatdup(ptr, "/"));
1104 return (strcatdup(ptr, ""));
1105 }
1106
1107 static char *
fname(char * ptr)1108 fname(char *ptr)
1109 {
1110 char *old = ptr;
1111
1112 while (*ptr) {
1113 if (*ptr == '/')
1114 old = ptr + 1;
1115 ptr++;
1116 }
1117 return (old);
1118 }
1119
1120 static void
usage(void)1121 usage(void)
1122 {
1123 fprintf(stderr,
1124 "usage: linux_make -c config -o . -i linuxA/ -i linuxB/\n"
1125 " -c <config-file>\n"
1126 " -i <input-directory>\n"
1127 " -o <output-directory>\n"
1128 " -x <exclude-object>\n"
1129 " -h show help message\n"
1130 " -v increase verbosity\n"
1131 );
1132 exit(EX_USAGE);
1133 }
1134
1135 static const char *targets[] = {
1136 "all",
1137 "clean",
1138 "cleandepend",
1139 "depend",
1140 NULL
1141 };
1142
1143 int
main(int argc,char ** argv)1144 main(int argc, char **argv)
1145 {
1146 const char *params = "c:i:o:hvx:";
1147 struct node *n0;
1148 struct node *n1;
1149 struct makefile *m0;
1150 struct config *c0;
1151 int c;
1152
1153 while ((c = getopt(argc, argv, params)) != -1) {
1154 switch (c) {
1155 case 'c':
1156 opt_config = optarg;
1157 break;
1158 case 'i':
1159 opt_input = optarg;
1160 break;
1161 case 'o':
1162 opt_output = optarg;
1163 break;
1164 case 'v':
1165 opt_verbose++;
1166 break;
1167 case 'x':
1168 new_exclude(optarg);
1169 break;
1170 default:
1171 usage();
1172 break;
1173 }
1174 }
1175
1176 if (opt_input == NULL || opt_output == NULL)
1177 usage();
1178
1179 opt_output = add_slashdup(opt_output);
1180
1181 parse_config(opt_config);
1182
1183 optreset = 1;
1184 optind = 1;
1185
1186 while ((c = getopt(argc, argv, params)) != -1) {
1187 switch (c) {
1188 case 'i':
1189 opt_input = add_slashdup(optarg);
1190 parse_makefile(opt_input);
1191 opt_input = NULL;
1192 break;
1193 default:
1194 break;
1195 }
1196 }
1197
1198 resolve_nodes();
1199
1200 if (opt_verbose > 1)
1201 dump_nodes(&rootNode);
1202
1203 if (mkdir(strcatdup(opt_output, "obj-y"), 0755) != 0 &&
1204 errno != EEXIST)
1205 err(EX_NOINPUT, "Could not create output directory.");
1206
1207 set_stdout(strcatdup(opt_output, "obj-y/Makefile"));
1208
1209 new_makefile(strcatdup(opt_output, "obj-y"));
1210
1211 output_makefile("obj-y");
1212
1213 n0 = add_node(&rootNode, strcatdup("obj-m", ""));
1214
1215 TAILQ_FOREACH(n1, &n0->children, entry) {
1216 char *temp;
1217 char *name;
1218 int len;
1219
1220 temp = strcatdup(n1->name, "");
1221 len = strlen(temp);
1222
1223 if ((len >= 2) && (temp[len - 2] == '.' &&
1224 temp[len - 1] == 'o')) {
1225 temp[len - 2] = 0;
1226 len -= 2;
1227 }
1228 name = strcatdup(temp, "-objs");
1229 free(temp);
1230
1231 temp = strcatdup(opt_output, name);
1232 free(name);
1233
1234 if (mkdir(temp, 0755) != 0 && errno != EEXIST)
1235 err(EX_NOINPUT, "Could not create output directory.");
1236
1237 set_stdout(strcatdup(temp, "/Makefile"));
1238
1239 new_makefile(strcatdup(temp, ""));
1240
1241 output_makefile(temp + strlen(opt_output));
1242
1243 free(temp);
1244 }
1245
1246 set_stdout(strcatdup(opt_output, "Makefile.top"));
1247
1248 printf("#\n"
1249 "# This makefile was automatically generated. Do not edit!\n"
1250 "#\n");
1251
1252 printf("\nMAKE?=make\n");
1253 printf("\nMAKE_ARGS?=\n");
1254
1255 for (c = 0; targets[c]; c++) {
1256 printf("\n%s:\n", targets[c]);
1257 TAILQ_FOREACH(m0, &rootMakefile, entry) {
1258 char *ptr;
1259
1260 ptr = fname(m0->name);
1261 printf("\tcd %s; ${MAKE} LIB=%s%s ${MAKE_ARGS} %s\n",
1262 ptr, ptr, strcmp(ptr, "obj-y") ?
1263 " MODULE=YES" : "", targets[c]);
1264 }
1265 }
1266
1267 printf("\ninstall:\n");
1268 printf("\t[ -d modules] || mkdir modules\n");
1269 TAILQ_FOREACH(m0, &rootMakefile, entry) {
1270 printf("\tcp -v %s/%s{.a,.so} modules/\n",
1271 m0->name, fname(m0->name));
1272 }
1273
1274 set_stdout(strcatdup(opt_output, "config.h"));
1275
1276 sort_config();
1277
1278 printf("/*\n"
1279 " * This file was autogenerated. Please do not edit.\n"
1280 " */\n\n");
1281
1282 printf("#ifndef _ROOT_CONFIG_H_\n"
1283 "#define\t_ROOT_CONFIG_H_\n\n");
1284
1285 TAILQ_FOREACH(c0, &rootConfig, entry) {
1286 switch (c0->value) {
1287 case 'm':
1288 printf("#define\t%s /* m */\n", c0->name);
1289 printf("#define\t%s_IS_ENABLED 1\n", c0->name);
1290 printf("#define\t%s_IS_MODULE 1\n", c0->name);
1291 break;
1292 case 'y':
1293 printf("#define\t%s /* y */\n", c0->name);
1294 printf("#define\t%s_IS_MODULE 0\n", c0->name);
1295 printf("#define\t%s_IS_ENABLED 1\n", c0->name);
1296 break;
1297 case 'd':
1298 printf("#define\t%s %s /* d */\n", c0->name, c0->orig);
1299 break;
1300 default:
1301 printf("#undef\t%s /* %c */\n", c0->name, c0->value);
1302 printf("#define\t%s_IS_MODULE 0\n", c0->name);
1303 printf("#define\t%s_IS_ENABLED 0\n", c0->name);
1304 break;
1305 }
1306 }
1307
1308 printf("\n#endif\t\t\t/* _ROOT_CONFIG_H_ */\n");
1309
1310 return (0);
1311 }
1312