diff options
Diffstat (limited to 'scripts/bb_mkdep.c')
-rw-r--r-- | scripts/bb_mkdep.c | 855 |
1 files changed, 855 insertions, 0 deletions
diff --git a/scripts/bb_mkdep.c b/scripts/bb_mkdep.c new file mode 100644 index 000000000..408397332 --- /dev/null +++ b/scripts/bb_mkdep.c | |||
@@ -0,0 +1,855 @@ | |||
1 | /* | ||
2 | * Another dependences for Makefile mashine generator | ||
3 | * | ||
4 | * Copyright (C) 2005 by Vladimir Oleynik <dzo@simtreas.ru> | ||
5 | * | ||
6 | * This programm do | ||
7 | * 1) find #define KEY VALUE or #undef KEY from include/config.h | ||
8 | * 2) save include/config/key*.h if changed after previous usage | ||
9 | * 3) recursive scan from "./" *.[ch] files, but skip scan include/config/... | ||
10 | * 4) find #include "*.h" and KEYs using, if not as #define and #undef | ||
11 | * 5) generate depend to stdout | ||
12 | * path/file.o: include/config/key*.h found_include_*.h | ||
13 | * path/inc.h: include/config/key*.h found_included_include_*.h | ||
14 | * This programm do not generate dependences for #include <...> | ||
15 | * | ||
16 | * Options: | ||
17 | * -I local_include_path (include`s paths, default: LOCAL_INCLUDE_PATH) | ||
18 | * -d (don`t generate depend) | ||
19 | * -w (show warning if include files not found) | ||
20 | * -k include/config (default: INCLUDE_CONFIG_PATH) | ||
21 | * -c include/config.h (configs, default: INCLUDE_CONFIG_KEYS_PATH) | ||
22 | */ | ||
23 | |||
24 | #define LOCAL_INCLUDE_PATH "include" | ||
25 | #define INCLUDE_CONFIG_PATH LOCAL_INCLUDE_PATH"/config" | ||
26 | #define INCLUDE_CONFIG_KEYS_PATH LOCAL_INCLUDE_PATH"/config.h" | ||
27 | |||
28 | #define _GNU_SOURCE | ||
29 | #include <sys/types.h> | ||
30 | #include <sys/stat.h> | ||
31 | #include <sys/mman.h> | ||
32 | #include <getopt.h> | ||
33 | #include <dirent.h> | ||
34 | #include <stdio.h> | ||
35 | #include <stdlib.h> | ||
36 | #include <string.h> | ||
37 | #include <stdarg.h> | ||
38 | #include <unistd.h> | ||
39 | #include <errno.h> | ||
40 | #include <fcntl.h> | ||
41 | |||
42 | typedef struct BB_KEYS { | ||
43 | char *keyname; | ||
44 | const char *value; | ||
45 | char *stored_path; | ||
46 | int checked; | ||
47 | struct BB_KEYS *next; | ||
48 | } bb_key_t; | ||
49 | |||
50 | |||
51 | /* partial and simplify libbb routine */ | ||
52 | |||
53 | void bb_error_d(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))); | ||
54 | char * bb_asprint(const char *format, ...) __attribute__ ((format (printf, 1, 2))); | ||
55 | |||
56 | /* stolen from libbb as is */ | ||
57 | typedef struct llist_s { | ||
58 | char *data; | ||
59 | struct llist_s *link; | ||
60 | } llist_t; | ||
61 | llist_t *llist_add_to(llist_t *old_head, char *new_item); | ||
62 | void *xrealloc(void *p, size_t size); | ||
63 | void *xmalloc(size_t size); | ||
64 | char *bb_xstrdup(const char *s); | ||
65 | char *bb_simplify_path(const char *path); | ||
66 | |||
67 | /* for lexical analyzier */ | ||
68 | static bb_key_t *key_top; | ||
69 | |||
70 | static void parse_inc(const char *include, const char *fname); | ||
71 | static void parse_conf_opt(char *opt, const char *val, size_t rsz); | ||
72 | |||
73 | #define CHECK_ONLY 0 | ||
74 | #define MAKE_NEW 1 | ||
75 | static bb_key_t *find_already(bb_key_t *k, const char *nk, int flg_save_new); | ||
76 | |||
77 | #define yy_error_d(s) bb_error_d("%s:%d hmm, %s", fname, line, s) | ||
78 | |||
79 | /* state */ | ||
80 | #define S 0 /* start state */ | ||
81 | #define STR '"' /* string */ | ||
82 | #define CHR '\'' /* char */ | ||
83 | #define REM '*' /* block comment */ | ||
84 | #define POUND '#' /* # */ | ||
85 | #define I 'i' /* #include preprocessor`s directive */ | ||
86 | #define D 'd' /* #define preprocessor`s directive */ | ||
87 | #define U 'u' /* #undef preprocessor`s directive */ | ||
88 | #define LI 'I' /* #include "... */ | ||
89 | #define DK 'K' /* #define KEY... (config mode) */ | ||
90 | #define DV 'V' /* #define KEY "... or #define KEY '... */ | ||
91 | #define NLC 'n' /* \+\n */ | ||
92 | #define ANY '?' /* skip unparsed . */ | ||
93 | |||
94 | /* [A-Z_a-z] */ | ||
95 | #define ID(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') | ||
96 | /* [A-Z_a-z0-9] */ | ||
97 | #define ISALNUM(c) (ID(c) || (c >= '0' && c <= '9')) | ||
98 | |||
99 | #define getc1() do { c = (optr >= oend) ? EOF : *optr++; } while(0) | ||
100 | #define ungetc1() optr-- | ||
101 | |||
102 | #define put_id(c) do { if(id_len == mema_id) \ | ||
103 | id = xrealloc(id, mema_id += 16); \ | ||
104 | id[id_len++] = c; } while(0) | ||
105 | |||
106 | /* stupid C lexical analizator */ | ||
107 | static void c_lex(const char *fname, int flg_config_include) | ||
108 | { | ||
109 | int c = EOF; /* stupid initialize */ | ||
110 | int prev_state = EOF; | ||
111 | int called; | ||
112 | int state; | ||
113 | int line; | ||
114 | static size_t mema_id; | ||
115 | char *id = xmalloc(mema_id=128); /* fist allocate */ | ||
116 | size_t id_len = 0; /* stupid initialize */ | ||
117 | char *val = NULL; | ||
118 | unsigned char *optr, *oend; | ||
119 | unsigned char *start = NULL; /* stupid initialize */ | ||
120 | |||
121 | int fd; | ||
122 | char *map; | ||
123 | int mapsize; | ||
124 | { | ||
125 | /* stolen from mkdep by Linus Torvalds */ | ||
126 | int pagesizem1 = getpagesize() - 1; | ||
127 | struct stat st; | ||
128 | |||
129 | fd = open(fname, O_RDONLY); | ||
130 | if(fd < 0) { | ||
131 | perror(fname); | ||
132 | return; | ||
133 | } | ||
134 | fstat(fd, &st); | ||
135 | if (st.st_size == 0) | ||
136 | bb_error_d("%s is empty", fname); | ||
137 | mapsize = st.st_size; | ||
138 | mapsize = (mapsize+pagesizem1) & ~pagesizem1; | ||
139 | map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0); | ||
140 | if ((long) map == -1) | ||
141 | bb_error_d("%s: mmap: %m", fname); | ||
142 | |||
143 | /* hereinafter is my */ | ||
144 | optr = (unsigned char *)map; | ||
145 | oend = optr + st.st_size; | ||
146 | } | ||
147 | |||
148 | line = 1; | ||
149 | called = state = S; | ||
150 | |||
151 | for(;;) { | ||
152 | if(state == LI || state == DV) { | ||
153 | /* store "include.h" or config mode #define KEY "|'..."|' */ | ||
154 | put_id(0); | ||
155 | if(state == LI) { | ||
156 | parse_inc(id, fname); | ||
157 | } else { | ||
158 | /* | ||
159 | if(val[0] == '\0') | ||
160 | yy_error_d("expected value"); | ||
161 | */ | ||
162 | parse_conf_opt(id, val, (optr - start)); | ||
163 | } | ||
164 | state = S; | ||
165 | } | ||
166 | if(prev_state != state) { | ||
167 | prev_state = state; | ||
168 | getc1(); | ||
169 | } | ||
170 | |||
171 | /* [ \t]+ eat first space */ | ||
172 | while(c == ' ' || c == '\t') | ||
173 | getc1(); | ||
174 | |||
175 | if(c == '\\') { | ||
176 | getc1(); | ||
177 | if(c == '\n') { | ||
178 | /* \\\n eat continued */ | ||
179 | line++; | ||
180 | prev_state = NLC; | ||
181 | continue; | ||
182 | } | ||
183 | ungetc1(); | ||
184 | c = '\\'; | ||
185 | } | ||
186 | |||
187 | if(state == S) { | ||
188 | while(c <= ' ' && c != EOF) { | ||
189 | /* <S>[\000- ]+ */ | ||
190 | if(c == '\n') | ||
191 | line++; | ||
192 | getc1(); | ||
193 | } | ||
194 | if(c == EOF) { | ||
195 | /* <S><<EOF>> */ | ||
196 | munmap(map, mapsize); | ||
197 | close(fd); | ||
198 | return; | ||
199 | } | ||
200 | if(c == '/') { | ||
201 | /* <S>/ */ | ||
202 | getc1(); | ||
203 | if(c == '/') { | ||
204 | /* <S>"//"[^\n]* */ | ||
205 | do getc1(); while(c != '\n' && c != EOF); | ||
206 | } else if(c == '*') { | ||
207 | /* <S>[/][*] */ | ||
208 | called = S; | ||
209 | state = REM; | ||
210 | } | ||
211 | /* eat <S>/ */ | ||
212 | } else if(c == '#') { | ||
213 | /* <S>\"|\'|# */ | ||
214 | start = optr - 1; | ||
215 | state = c; | ||
216 | } else if(c == STR || c == CHR) { | ||
217 | /* <S>\"|\'|# */ | ||
218 | val = NULL; | ||
219 | called = S; | ||
220 | state = c; | ||
221 | } else if(ISALNUM(c)) { | ||
222 | /* <S>[A-Z_a-z0-9] */ | ||
223 | id_len = 0; | ||
224 | do { | ||
225 | /* <S>[A-Z_a-z0-9]+ */ | ||
226 | put_id(c); | ||
227 | getc1(); | ||
228 | } while(ISALNUM(c)); | ||
229 | put_id(0); | ||
230 | find_already(key_top, id, CHECK_ONLY); | ||
231 | } else { | ||
232 | /* <S>. */ | ||
233 | prev_state = ANY; | ||
234 | } | ||
235 | continue; | ||
236 | } | ||
237 | if(state == REM) { | ||
238 | for(;;) { | ||
239 | /* <REM>[^*]+ */ | ||
240 | while(c != '*') { | ||
241 | if(c == '\n') { | ||
242 | /* <REM>\n */ | ||
243 | if(called != S) | ||
244 | yy_error_d("unexpected newline"); | ||
245 | line++; | ||
246 | } else if(c == EOF) | ||
247 | yy_error_d("unexpected EOF"); | ||
248 | getc1(); | ||
249 | } | ||
250 | /* <REM>[*] */ | ||
251 | getc1(); | ||
252 | if(c == '/') { | ||
253 | /* <REM>[*][/] */ | ||
254 | state = called; | ||
255 | break; | ||
256 | } | ||
257 | } | ||
258 | continue; | ||
259 | } | ||
260 | if(state == STR || state == CHR) { | ||
261 | for(;;) { | ||
262 | /* <STR,CHR>\n|<<EOF>> */ | ||
263 | if(c == '\n' || c == EOF) | ||
264 | yy_error_d("unterminating"); | ||
265 | if(c == '\\') { | ||
266 | /* <STR,CHR>\\ */ | ||
267 | getc1(); | ||
268 | if(c != '\\' && c != '\n' && c != state) { | ||
269 | /* another usage \ in str or char */ | ||
270 | if(c == EOF) | ||
271 | yy_error_d("unexpected EOF"); | ||
272 | if(val) | ||
273 | put_id(c); | ||
274 | continue; | ||
275 | } | ||
276 | /* <STR,CHR>\\[\\\n] or <STR>\\\" or <CHR>\\\' */ | ||
277 | /* eat 2 char */ | ||
278 | if(c == '\n') | ||
279 | line++; | ||
280 | else if(val) | ||
281 | put_id(c); | ||
282 | } else if(c == state) { | ||
283 | /* <STR>\" or <CHR>\' */ | ||
284 | if(called == DV) | ||
285 | put_id(c); | ||
286 | state = called; | ||
287 | break; | ||
288 | } else if(val) | ||
289 | put_id(c); | ||
290 | /* <STR,CHR>. */ | ||
291 | getc1(); | ||
292 | } | ||
293 | continue; | ||
294 | } | ||
295 | |||
296 | /* begin preprocessor states */ | ||
297 | if(c == EOF) | ||
298 | yy_error_d("unexpected EOF"); | ||
299 | if(c == '/') { | ||
300 | /* <#.*>/ */ | ||
301 | getc1(); | ||
302 | if(c == '/') | ||
303 | yy_error_d("detect // in preprocessor line"); | ||
304 | if(c == '*') { | ||
305 | /* <#.*>[/][*] */ | ||
306 | called = state; | ||
307 | state = REM; | ||
308 | continue; | ||
309 | } | ||
310 | /* hmm, #.*[/] */ | ||
311 | yy_error_d("strange preprocessor line"); | ||
312 | } | ||
313 | if(state == '#') { | ||
314 | static const char * const preproc[] = { | ||
315 | "define", "undef", "include", "" | ||
316 | }; | ||
317 | const char * const *str_type; | ||
318 | |||
319 | id_len = 0; | ||
320 | while(ISALNUM(c)) { | ||
321 | put_id(c); | ||
322 | getc1(); | ||
323 | } | ||
324 | put_id(0); | ||
325 | for(str_type = preproc; (state = **str_type); str_type++) { | ||
326 | if(*id == state && strcmp(id, *str_type) == 0) | ||
327 | break; | ||
328 | } | ||
329 | /* to S if another #directive */ | ||
330 | ungetc1(); | ||
331 | id_len = 0; /* common for save */ | ||
332 | continue; | ||
333 | } | ||
334 | if(state == I) { | ||
335 | if(c == STR) { | ||
336 | /* <I>\" */ | ||
337 | val = id; | ||
338 | state = STR; | ||
339 | called = LI; | ||
340 | continue; | ||
341 | } | ||
342 | /* another (may be wrong) #include ... */ | ||
343 | ungetc1(); | ||
344 | state = S; | ||
345 | continue; | ||
346 | } | ||
347 | if(state == D || state == U) { | ||
348 | while(ISALNUM(c)) { | ||
349 | if(flg_config_include) { | ||
350 | /* save KEY from #"define"|"undef" ... */ | ||
351 | put_id(c); | ||
352 | } | ||
353 | getc1(); | ||
354 | } | ||
355 | if(!flg_config_include) { | ||
356 | state = S; | ||
357 | } else { | ||
358 | if(!id_len) | ||
359 | yy_error_d("expected identificator"); | ||
360 | put_id(0); | ||
361 | if(state == U) { | ||
362 | parse_conf_opt(id, NULL, (optr - start)); | ||
363 | state = S; | ||
364 | } else { | ||
365 | /* D -> DK */ | ||
366 | state = DK; | ||
367 | } | ||
368 | } | ||
369 | ungetc1(); | ||
370 | continue; | ||
371 | } | ||
372 | if(state == DK) { | ||
373 | /* #define (config mode) */ | ||
374 | val = id + id_len; | ||
375 | if(c == STR || c == CHR) { | ||
376 | /* define KEY "... or define KEY '... */ | ||
377 | put_id(c); | ||
378 | called = DV; | ||
379 | state = c; | ||
380 | continue; | ||
381 | } | ||
382 | while(ISALNUM(c)) { | ||
383 | put_id(c); | ||
384 | getc1(); | ||
385 | } | ||
386 | ungetc1(); | ||
387 | state = DV; | ||
388 | continue; | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | |||
393 | |||
394 | static void show_usage(void) __attribute__ ((noreturn)); | ||
395 | static void show_usage(void) | ||
396 | { | ||
397 | bb_error_d("Usage: [-I local_include_path] [-dw] " | ||
398 | "[-k path_for_store_keys] [-s skip_file]"); | ||
399 | } | ||
400 | |||
401 | static const char *kp; | ||
402 | static llist_t *Iop; | ||
403 | static bb_key_t *Ifound; | ||
404 | static int noiwarning; | ||
405 | static llist_t *configs; | ||
406 | |||
407 | static bb_key_t *find_already(bb_key_t *k, const char *nk, int flg_save_new) | ||
408 | { | ||
409 | bb_key_t *cur; | ||
410 | |||
411 | for(cur = k; cur; cur = cur->next) { | ||
412 | if(strcmp(cur->keyname, nk) == 0) { | ||
413 | cur->checked = 1; | ||
414 | return NULL; | ||
415 | } | ||
416 | } | ||
417 | if(flg_save_new == CHECK_ONLY) | ||
418 | return NULL; | ||
419 | cur = xmalloc(sizeof(bb_key_t)); | ||
420 | cur->keyname = bb_xstrdup(nk); | ||
421 | cur->checked = 1; | ||
422 | cur->next = k; | ||
423 | return cur; | ||
424 | } | ||
425 | |||
426 | static int store_include_fullpath(char *p_i, bb_key_t *li) | ||
427 | { | ||
428 | struct stat st; | ||
429 | int ok = 0; | ||
430 | |||
431 | if(stat(p_i, &st) == 0) { | ||
432 | li->stored_path = bb_simplify_path(p_i); | ||
433 | ok = 1; | ||
434 | } | ||
435 | free(p_i); | ||
436 | return ok; | ||
437 | } | ||
438 | |||
439 | static void parse_inc(const char *include, const char *fname) | ||
440 | { | ||
441 | bb_key_t *li; | ||
442 | char *p_i; | ||
443 | llist_t *lo; | ||
444 | |||
445 | if((li = find_already(Ifound, include, MAKE_NEW)) == NULL) | ||
446 | return; | ||
447 | Ifound = li; | ||
448 | if(include[0] != '/') { | ||
449 | /* relative */ | ||
450 | int w; | ||
451 | const char *p; | ||
452 | |||
453 | p_i = strrchr(fname, '/'); | ||
454 | if(p_i == NULL) { | ||
455 | p = "."; | ||
456 | w = 1; | ||
457 | } else { | ||
458 | w = (p_i-fname); | ||
459 | p = fname; | ||
460 | } | ||
461 | p_i = bb_asprint("%.*s/%s", w, p, include); | ||
462 | if(store_include_fullpath(p_i, li)) | ||
463 | return; | ||
464 | } | ||
465 | for(lo = Iop; lo; lo = lo->link) { | ||
466 | p_i = bb_asprint("%s/%s", lo->data, include); | ||
467 | if(store_include_fullpath(p_i, li)) | ||
468 | return; | ||
469 | } | ||
470 | li->stored_path = NULL; | ||
471 | if(noiwarning) | ||
472 | fprintf(stderr, "%s: Warning: #include \"%s\" not found in specified paths\n", fname, include); | ||
473 | } | ||
474 | |||
475 | static void parse_conf_opt(char *opt, const char *val, size_t recordsz) | ||
476 | { | ||
477 | bb_key_t *cur = find_already(key_top, opt, MAKE_NEW); | ||
478 | |||
479 | if(cur != NULL) { | ||
480 | /* new key, check old key if present after previous usage */ | ||
481 | char *s, *p; | ||
482 | struct stat st; | ||
483 | int fd; | ||
484 | int cmp_ok = 0; | ||
485 | static char *record_buf; | ||
486 | static char *r_cmp; | ||
487 | static size_t r_sz; | ||
488 | |||
489 | recordsz += 2; /* \n\0 */ | ||
490 | if(recordsz > r_sz) { | ||
491 | record_buf = xrealloc(record_buf, r_sz=recordsz); | ||
492 | r_cmp = xrealloc(r_cmp, recordsz); | ||
493 | } | ||
494 | s = record_buf; | ||
495 | if(val) | ||
496 | sprintf(s, "#define %s%s%s\n", opt, (*val ? " " : ""), val); | ||
497 | else | ||
498 | sprintf(s, "#undef %s\n", opt); | ||
499 | /* may be short count " " */ | ||
500 | recordsz = strlen(s); | ||
501 | /* key converting [A-Z] -> [a-z] */ | ||
502 | for(p = opt; *p; p++) { | ||
503 | if(*p >= 'A' && *p <= 'Z') | ||
504 | *p = *p - 'A' + 'a'; | ||
505 | if(*p == '_') | ||
506 | *p = '/'; | ||
507 | } | ||
508 | p = bb_asprint("%s/%s.h", kp, opt); | ||
509 | cur->stored_path = opt = p; | ||
510 | while(*++p) { | ||
511 | /* Auto-create directories. */ | ||
512 | if (*p == '/') { | ||
513 | *p = '\0'; | ||
514 | if (stat(opt, &st) != 0 && mkdir(opt, 0755) != 0) | ||
515 | bb_error_d("mkdir(%s): %m", opt); | ||
516 | *p = '/'; | ||
517 | } | ||
518 | } | ||
519 | if(stat(opt, &st) == 0) { | ||
520 | /* found */ | ||
521 | if(st.st_size == recordsz) { | ||
522 | fd = open(opt, O_RDONLY); | ||
523 | if(fd < 0 || read(fd, r_cmp, recordsz) != recordsz) | ||
524 | bb_error_d("%s: %m", opt); | ||
525 | close(fd); | ||
526 | cmp_ok = memcmp(s, r_cmp, recordsz) == 0; | ||
527 | } | ||
528 | } | ||
529 | if(!cmp_ok) { | ||
530 | fd = open(opt, O_WRONLY|O_CREAT|O_TRUNC, 0644); | ||
531 | if(fd < 0 || write(fd, s, recordsz) != recordsz) | ||
532 | bb_error_d("%s: %m", opt); | ||
533 | close(fd); | ||
534 | } | ||
535 | /* store only */ | ||
536 | cur->checked = 0; | ||
537 | if(val) { | ||
538 | if(*val == '\0') { | ||
539 | cur->value = ""; | ||
540 | } else { | ||
541 | cur->value = bb_xstrdup(val); | ||
542 | } | ||
543 | } else { | ||
544 | cur->value = NULL; | ||
545 | } | ||
546 | key_top = cur; | ||
547 | } else { | ||
548 | /* present already */ | ||
549 | for(cur = key_top; cur; cur = cur->next) { | ||
550 | if(strcmp(cur->keyname, opt) == 0) { | ||
551 | cur->checked = 0; | ||
552 | if(cur->value == NULL && val == NULL) | ||
553 | return; | ||
554 | if((cur->value == NULL && val != NULL) || | ||
555 | (cur->value != NULL && val == NULL) || | ||
556 | strcmp(cur->value, val)) | ||
557 | fprintf(stderr, "Warning: redefined %s\n", opt); | ||
558 | return; | ||
559 | } | ||
560 | } | ||
561 | } | ||
562 | } | ||
563 | |||
564 | static int show_dep(int first, bb_key_t *k, const char *a) | ||
565 | { | ||
566 | bb_key_t *cur; | ||
567 | |||
568 | for(cur = k; cur; cur = cur->next) { | ||
569 | if(cur->checked && cur->stored_path) { | ||
570 | if(first) { | ||
571 | const char *ext; | ||
572 | |||
573 | if(*a == '.' && a[1] == '/') | ||
574 | a += 2; | ||
575 | ext = strrchr(a, '.'); | ||
576 | if(ext && ext[1] == 'c' && ext[2] == '\0') { | ||
577 | /* *.c -> *.o */ | ||
578 | printf("\n%.*s.o:", (ext - a), a); | ||
579 | } else { | ||
580 | printf("\n%s:", a); | ||
581 | } | ||
582 | first = 0; | ||
583 | } else { | ||
584 | printf(" \\\n "); | ||
585 | } | ||
586 | printf(" %s", cur->stored_path); | ||
587 | } | ||
588 | cur->checked = 0; | ||
589 | } | ||
590 | return first; | ||
591 | } | ||
592 | |||
593 | static llist_t *files; | ||
594 | |||
595 | static llist_t *filter_chd(const char *fe, const char *p, llist_t *pdirs) | ||
596 | { | ||
597 | const char *e; | ||
598 | struct stat st; | ||
599 | char *fp; | ||
600 | char *afp; | ||
601 | llist_t *cfl; | ||
602 | |||
603 | if (*fe == '.') | ||
604 | return NULL; | ||
605 | fp = bb_asprint("%s/%s", p, fe); | ||
606 | if(stat(fp, &st)) { | ||
607 | fprintf(stderr, "Warning: stat(%s): %m", fp); | ||
608 | free(fp); | ||
609 | return NULL; | ||
610 | } | ||
611 | afp = bb_simplify_path(fp); | ||
612 | if(S_ISDIR(st.st_mode)) { | ||
613 | if(strcmp(kp, afp) == 0) { | ||
614 | /* is autogenerated to kp/key* by previous usage */ | ||
615 | free(afp); | ||
616 | free(fp); | ||
617 | /* drop scan kp/ directory */ | ||
618 | return NULL; | ||
619 | } | ||
620 | free(afp); | ||
621 | return llist_add_to(pdirs, fp); | ||
622 | } | ||
623 | if(!S_ISREG(st.st_mode)) { | ||
624 | /* hmm, is device! */ | ||
625 | free(afp); | ||
626 | free(fp); | ||
627 | return NULL; | ||
628 | } | ||
629 | e = strrchr(fe, '.'); | ||
630 | if(e == NULL || !((e[1]=='c' || e[1]=='h') && e[2]=='\0')) { | ||
631 | /* direntry is not directory or *.[ch] */ | ||
632 | free(afp); | ||
633 | free(fp); | ||
634 | return NULL; | ||
635 | } | ||
636 | for(cfl = configs; cfl; cfl = cfl->link) { | ||
637 | if(cfl->data && strcmp(cfl->data, afp) == 0) { | ||
638 | /* parse configs.h */ | ||
639 | free(afp); | ||
640 | c_lex(fp, 1); | ||
641 | free(fp); | ||
642 | free(cfl->data); | ||
643 | cfl->data = NULL; | ||
644 | return NULL; | ||
645 | } | ||
646 | } | ||
647 | free(fp); | ||
648 | /* direntry is *.[ch] regular file */ | ||
649 | files = llist_add_to(files, afp); | ||
650 | return NULL; | ||
651 | } | ||
652 | |||
653 | static void scan_dir_find_ch_files(char *p) | ||
654 | { | ||
655 | llist_t *dirs; | ||
656 | llist_t *d_add; | ||
657 | llist_t *d; | ||
658 | struct dirent *de; | ||
659 | DIR *dir; | ||
660 | |||
661 | dirs = llist_add_to(NULL, p); | ||
662 | /* emulate recursive */ | ||
663 | while(dirs) { | ||
664 | d_add = NULL; | ||
665 | while(dirs) { | ||
666 | dir = opendir(dirs->data); | ||
667 | if (dir == NULL) | ||
668 | fprintf(stderr, "Warning: opendir(%s): %m", dirs->data); | ||
669 | while ((de = readdir(dir)) != NULL) { | ||
670 | d = filter_chd(de->d_name, dirs->data, d_add); | ||
671 | if(d) | ||
672 | d_add = d; | ||
673 | } | ||
674 | closedir(dir); | ||
675 | if(dirs->data != p) | ||
676 | free(dirs->data); | ||
677 | d = dirs; | ||
678 | dirs = dirs->link; | ||
679 | free(d); | ||
680 | } | ||
681 | dirs = d_add; | ||
682 | } | ||
683 | } | ||
684 | |||
685 | int main(int argc, char **argv) | ||
686 | { | ||
687 | int generate_dep = 1; | ||
688 | char *s; | ||
689 | int i; | ||
690 | llist_t *fl; | ||
691 | |||
692 | while ((i = getopt(argc, argv, "I:c:dk:w")) > 0) { | ||
693 | switch(i) { | ||
694 | case 'I': | ||
695 | Iop = llist_add_to(Iop, optarg); | ||
696 | break; | ||
697 | case 'c': | ||
698 | s = bb_simplify_path(optarg); | ||
699 | configs = llist_add_to(configs, s); | ||
700 | break; | ||
701 | case 'd': | ||
702 | generate_dep = 0; | ||
703 | break; | ||
704 | case 'k': | ||
705 | if(kp) | ||
706 | bb_error_d("Hmm, why multiple -k?"); | ||
707 | kp = bb_simplify_path(optarg); | ||
708 | break; | ||
709 | case 'w': | ||
710 | noiwarning = 1; | ||
711 | break; | ||
712 | default: | ||
713 | show_usage(); | ||
714 | } | ||
715 | } | ||
716 | if(argc > optind) | ||
717 | show_usage(); | ||
718 | |||
719 | /* defaults */ | ||
720 | if(kp == NULL) | ||
721 | kp = bb_simplify_path(INCLUDE_CONFIG_PATH); | ||
722 | if(Iop == NULL) | ||
723 | Iop = llist_add_to(Iop, LOCAL_INCLUDE_PATH); | ||
724 | if(configs == NULL) { | ||
725 | s = bb_simplify_path(INCLUDE_CONFIG_KEYS_PATH); | ||
726 | configs = llist_add_to(configs, s); | ||
727 | } | ||
728 | scan_dir_find_ch_files("."); | ||
729 | |||
730 | for(fl = files; fl; fl = fl->link) { | ||
731 | c_lex(fl->data, 0); | ||
732 | if(generate_dep) { | ||
733 | i = show_dep(1, Ifound, fl->data); | ||
734 | i = show_dep(i, key_top, fl->data); | ||
735 | if(i == 0) | ||
736 | putchar('\n'); | ||
737 | } | ||
738 | } | ||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | void bb_error_d(const char *s, ...) | ||
743 | { | ||
744 | va_list p; | ||
745 | |||
746 | va_start(p, s); | ||
747 | vfprintf(stderr, s, p); | ||
748 | va_end(p); | ||
749 | putc('\n', stderr); | ||
750 | exit(1); | ||
751 | } | ||
752 | |||
753 | |||
754 | void *xmalloc(size_t size) | ||
755 | { | ||
756 | void *p = malloc(size); | ||
757 | |||
758 | if(p == NULL) | ||
759 | bb_error_d("memory exhausted"); | ||
760 | return p; | ||
761 | } | ||
762 | |||
763 | void *xrealloc(void *p, size_t size) { | ||
764 | p = realloc(p, size); | ||
765 | if(p == NULL) | ||
766 | bb_error_d("memory exhausted"); | ||
767 | return p; | ||
768 | } | ||
769 | |||
770 | char *bb_asprint(const char *format, ...) | ||
771 | { | ||
772 | va_list p; | ||
773 | int r; | ||
774 | char *out; | ||
775 | |||
776 | va_start(p, format); | ||
777 | r = vasprintf(&out, format, p); | ||
778 | va_end(p); | ||
779 | |||
780 | if (r < 0) | ||
781 | bb_error_d("bb_asprint: %m"); | ||
782 | return out; | ||
783 | } | ||
784 | |||
785 | llist_t *llist_add_to(llist_t *old_head, char *new_item) | ||
786 | { | ||
787 | llist_t *new_head; | ||
788 | |||
789 | new_head = xmalloc(sizeof(llist_t)); | ||
790 | new_head->data = new_item; | ||
791 | new_head->link = old_head; | ||
792 | |||
793 | return(new_head); | ||
794 | } | ||
795 | |||
796 | char *bb_xstrdup(const char *s) | ||
797 | { | ||
798 | char *r = strdup(s); | ||
799 | if(r == NULL) | ||
800 | bb_error_d("memory exhausted"); | ||
801 | return r; | ||
802 | } | ||
803 | |||
804 | char *bb_simplify_path(const char *path) | ||
805 | { | ||
806 | char *s, *start, *p; | ||
807 | |||
808 | if (path[0] == '/') | ||
809 | start = bb_xstrdup(path); | ||
810 | else { | ||
811 | static char *pwd; | ||
812 | |||
813 | if(pwd == NULL) { | ||
814 | /* is not libbb, but this program have not chdir() */ | ||
815 | unsigned path_max = 512; | ||
816 | char *cwd = xmalloc (path_max); | ||
817 | #define PATH_INCR 32 | ||
818 | while (getcwd (cwd, path_max) == NULL) { | ||
819 | if(errno != ERANGE) | ||
820 | bb_error_d("getcwd: %m"); | ||
821 | path_max += PATH_INCR; | ||
822 | cwd = xrealloc (cwd, path_max); | ||
823 | } | ||
824 | pwd = cwd; | ||
825 | } | ||
826 | start = bb_asprint("%s/%s", pwd, path); | ||
827 | } | ||
828 | p = s = start; | ||
829 | |||
830 | do { | ||
831 | if (*p == '/') { | ||
832 | if (*s == '/') { /* skip duplicate (or initial) slash */ | ||
833 | continue; | ||
834 | } else if (*s == '.') { | ||
835 | if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */ | ||
836 | continue; | ||
837 | } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) { | ||
838 | ++s; | ||
839 | if (p > start) { | ||
840 | while (*--p != '/'); /* omit previous dir */ | ||
841 | } | ||
842 | continue; | ||
843 | } | ||
844 | } | ||
845 | } | ||
846 | *++p = *s; | ||
847 | } while (*++s); | ||
848 | |||
849 | if ((p == start) || (*p != '/')) { /* not a trailing slash */ | ||
850 | ++p; /* so keep last character */ | ||
851 | } | ||
852 | *p = 0; | ||
853 | |||
854 | return start; | ||
855 | } | ||