blob: ee8456778d761be964c419b0d4de9b2ff652505d [file] [log] [blame]
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001/*
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +00002 * Another dependences for Makefile fast mashine generator
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00003 *
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)
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +000022 * dirs_for_scan (default ".")
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000023*/
24
25#define LOCAL_INCLUDE_PATH "include"
26#define INCLUDE_CONFIG_PATH LOCAL_INCLUDE_PATH"/config"
27#define INCLUDE_CONFIG_KEYS_PATH LOCAL_INCLUDE_PATH"/config.h"
28
29#define _GNU_SOURCE
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/mman.h>
33#include <getopt.h>
34#include <dirent.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <stdarg.h>
39#include <unistd.h>
40#include <errno.h>
41#include <fcntl.h>
42
43typedef struct BB_KEYS {
44 char *keyname;
45 const char *value;
46 char *stored_path;
47 int checked;
48 struct BB_KEYS *next;
49} bb_key_t;
50
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +000051typedef struct FILE_LIST {
52 char *name;
53 char *ext; /* *.c or *.h, point to last char */
54 long size;
55} file_list_t;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000056
57/* partial and simplify libbb routine */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +000058static void bb_error_d(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
59static char * bb_asprint(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000060
61/* stolen from libbb as is */
62typedef struct llist_s {
63 char *data;
64 struct llist_s *link;
65} llist_t;
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +000066static llist_t *llist_add_to(llist_t *old_head, char *new_item);
67static void *xrealloc(void *p, size_t size);
68static void *xmalloc(size_t size);
69static char *bb_xstrdup(const char *s);
70static char *bb_simplify_path(const char *path);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000071
72/* for lexical analyzier */
73static bb_key_t *key_top;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +000074static llist_t *configs;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000075
76static void parse_inc(const char *include, const char *fname);
77static void parse_conf_opt(char *opt, const char *val, size_t rsz);
78
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +000079/* for speed triks */
80static char first_chars[257]; /* + L_EOF */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +000081
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +000082static int pagesizem1;
83static size_t mema_id = 128; /* first allocated for id */
84static char *id_s;
85
86static bb_key_t *check_key(bb_key_t *k, const char *nk);
87static bb_key_t *make_new_key(bb_key_t *k, const char *nk);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000088
89#define yy_error_d(s) bb_error_d("%s:%d hmm, %s", fname, line, s)
90
91/* state */
92#define S 0 /* start state */
93#define STR '"' /* string */
94#define CHR '\'' /* char */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +000095#define REM '/' /* block comment */
96#define BS '\\' /* back slash */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000097#define POUND '#' /* # */
98#define I 'i' /* #include preprocessor`s directive */
99#define D 'd' /* #define preprocessor`s directive */
100#define U 'u' /* #undef preprocessor`s directive */
101#define LI 'I' /* #include "... */
102#define DK 'K' /* #define KEY... (config mode) */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000103#define DV 'V' /* #define KEY "VALUE or #define KEY 'VALUE */
104#define NLC 'n' /* \ and \n */
105#define ANY '*' /* any unparsed chars */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000106
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000107#define L_EOF 256
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000108/* [A-Z_a-z] */
109#define ID(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
110/* [A-Z_a-z0-9] */
111#define ISALNUM(c) (ID(c) || (c >= '0' && c <= '9'))
112
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000113#define getc1() do { c = (optr >= oend) ? L_EOF : *optr++; } while(0)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000114#define ungetc1() optr--
115
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000116#define put_id(c) do { if(id_len == local_mema_id) \
117 id = xrealloc(id, local_mema_id += 16); \
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000118 id[id_len++] = c; } while(0)
119
120/* stupid C lexical analizator */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000121static void c_lex(const char *fname, long fsize)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000122{
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000123 int c = L_EOF; /* stupid initialize */
124 int prev_state = L_EOF;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000125 int called;
126 int state;
127 int line;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000128 char *id = id_s;
129 size_t local_mema_id = mema_id;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000130 size_t id_len = 0; /* stupid initialize */
131 char *val = NULL;
132 unsigned char *optr, *oend;
133 unsigned char *start = NULL; /* stupid initialize */
134
135 int fd;
136 char *map;
137 int mapsize;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000138
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000139 fd = open(fname, O_RDONLY);
140 if(fd < 0) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000141 perror(fname);
142 return;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000143 }
144 mapsize = (fsize+pagesizem1) & ~pagesizem1;
145 map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
146 if ((long) map == -1)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000147 bb_error_d("%s: mmap: %m", fname);
148
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000149 optr = (unsigned char *)map;
150 oend = optr + fsize;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000151
152 line = 1;
153 called = state = S;
154
155 for(;;) {
156 if(state == LI || state == DV) {
157 /* store "include.h" or config mode #define KEY "|'..."|' */
158 put_id(0);
159 if(state == LI) {
160 parse_inc(id, fname);
161 } else {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000162 /* #define KEY "[VAL]" */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000163 parse_conf_opt(id, val, (optr - start));
164 }
165 state = S;
166 }
167 if(prev_state != state) {
168 prev_state = state;
169 getc1();
170 }
171
172 /* [ \t]+ eat first space */
173 while(c == ' ' || c == '\t')
174 getc1();
175
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000176 if(c == BS) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000177 getc1();
178 if(c == '\n') {
179 /* \\\n eat continued */
180 line++;
181 prev_state = NLC;
182 continue;
183 }
184 ungetc1();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000185 c = BS;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000186 }
187
188 if(state == S) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000189 while(first_chars[c] == ANY) {
190 /* <S>unparsed */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000191 if(c == '\n')
192 line++;
193 getc1();
194 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000195 if(c == L_EOF) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000196 /* <S><<EOF>> */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000197 id_s = id;
198 mema_id = local_mema_id;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000199 munmap(map, mapsize);
200 close(fd);
201 return;
202 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000203 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000204 /* <S>/ */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000205 getc1(); /* eat <S>/ */
206 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000207 /* <S>"//"[^\n]* */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000208 do getc1(); while(c != '\n' && c != L_EOF);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000209 } else if(c == '*') {
210 /* <S>[/][*] */
211 called = S;
212 state = REM;
213 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000214 } else if(c == POUND) {
215 /* <S># */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000216 start = optr - 1;
217 state = c;
218 } else if(c == STR || c == CHR) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000219 /* <S>\"|\' */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000220 val = NULL;
221 called = S;
222 state = c;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000223 } else if(c != BS) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000224 /* <S>[A-Z_a-z0-9] */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000225
226 /* trick for fast drop id
227 if key with this first char undefined */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000228 if(first_chars[c] == 0) {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000229 /* skip <S>[A-Z_a-z0-9]+ */
230 do getc1(); while(ISALNUM(c));
231 } else {
232 id_len = 0;
233 do {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000234 /* <S>[A-Z_a-z0-9]+ */
235 put_id(c);
236 getc1();
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000237 } while(ISALNUM(c));
238 put_id(0);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000239 check_key(key_top, id);
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000240 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000241 } else {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000242 /* <S>\\ */
243 prev_state = c;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000244 }
245 continue;
246 }
247 if(state == REM) {
248 for(;;) {
249 /* <REM>[^*]+ */
250 while(c != '*') {
251 if(c == '\n') {
252 /* <REM>\n */
253 if(called != S)
254 yy_error_d("unexpected newline");
255 line++;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000256 } else if(c == L_EOF)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000257 yy_error_d("unexpected EOF");
258 getc1();
259 }
260 /* <REM>[*] */
261 getc1();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000262 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000263 /* <REM>[*][/] */
264 state = called;
265 break;
266 }
267 }
268 continue;
269 }
270 if(state == STR || state == CHR) {
271 for(;;) {
272 /* <STR,CHR>\n|<<EOF>> */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000273 if(c == '\n' || c == L_EOF)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000274 yy_error_d("unterminating");
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000275 if(c == BS) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000276 /* <STR,CHR>\\ */
277 getc1();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000278 if(c != BS && c != '\n' && c != state) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000279 /* another usage \ in str or char */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000280 if(c == L_EOF)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000281 yy_error_d("unexpected EOF");
282 if(val)
283 put_id(c);
284 continue;
285 }
286 /* <STR,CHR>\\[\\\n] or <STR>\\\" or <CHR>\\\' */
287 /* eat 2 char */
288 if(c == '\n')
289 line++;
290 else if(val)
291 put_id(c);
292 } else if(c == state) {
293 /* <STR>\" or <CHR>\' */
294 if(called == DV)
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000295 put_id(c); /* #define KEY "VALUE"<- */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000296 state = called;
297 break;
298 } else if(val)
299 put_id(c);
300 /* <STR,CHR>. */
301 getc1();
302 }
303 continue;
304 }
305
306 /* begin preprocessor states */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000307 if(c == L_EOF)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000308 yy_error_d("unexpected EOF");
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000309 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000310 /* <#.*>/ */
311 getc1();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000312 if(c == REM)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000313 yy_error_d("detect // in preprocessor line");
314 if(c == '*') {
315 /* <#.*>[/][*] */
316 called = state;
317 state = REM;
318 continue;
319 }
320 /* hmm, #.*[/] */
321 yy_error_d("strange preprocessor line");
322 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000323 if(state == POUND) {
324 if(c != 'd' && c != 'u' && c != 'i') {
325 while(ISALNUM(c))
326 getc1();
327 state = S;
328 } else {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000329 static const char * const preproc[] = {
330 "define", "undef", "include", ""
331 };
332 const char * const *str_type;
333
334 id_len = 0;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000335 do { put_id(c); getc1(); } while(ISALNUM(c));
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000336 put_id(0);
337 for(str_type = preproc; (state = **str_type); str_type++) {
338 if(*id == state && strcmp(id, *str_type) == 0)
339 break;
340 }
341 /* to S if another #directive */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000342 id_len = 0; /* common for save */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000343 }
344 ungetc1();
345 continue;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000346 }
347 if(state == I) {
348 if(c == STR) {
349 /* <I>\" */
350 val = id;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000351 called = LI;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000352 state = STR;
353 } else {
354 /* another (may be wrong) #include ... */
355 ungetc1();
356 state = S;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000357 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000358 continue;
359 }
360 if(state == D || state == U) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000361 if(configs == NULL) {
362 /* ignore depend with #define or #undef KEY */
363 while(ISALNUM(c))
364 getc1();
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000365 state = S;
366 } else {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000367 /* save KEY from #"define"|"undef" ... */
368 while(ISALNUM(c)) {
369 put_id(c);
370 getc1();
371 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000372 if(!id_len)
373 yy_error_d("expected identificator");
374 put_id(0);
375 if(state == U) {
376 parse_conf_opt(id, NULL, (optr - start));
377 state = S;
378 } else {
379 /* D -> DK */
380 state = DK;
381 }
382 }
383 ungetc1();
384 continue;
385 }
386 if(state == DK) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000387 /* #define KEY[ ] (config mode) */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000388 val = id + id_len;
389 if(c == STR || c == CHR) {
390 /* define KEY "... or define KEY '... */
391 put_id(c);
392 called = DV;
393 state = c;
394 continue;
395 }
396 while(ISALNUM(c)) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000397 /* VALUE */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000398 put_id(c);
399 getc1();
400 }
401 ungetc1();
402 state = DV;
403 continue;
404 }
405 }
406}
407
408
409static void show_usage(void) __attribute__ ((noreturn));
410static void show_usage(void)
411{
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000412 bb_error_d("Usage: [-I local_include_paths] [-dw] "
413 "[-k path_for_store_keys] [-s skip_file] [dirs]");
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000414}
415
416static const char *kp;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000417static size_t kp_len;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000418static llist_t *Iop;
419static bb_key_t *Ifound;
420static int noiwarning;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000421
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000422static bb_key_t *check_key(bb_key_t *k, const char *nk)
423{
424 bb_key_t *cur;
425
426 for(cur = k; cur; cur = cur->next) {
427 if(strcmp(cur->keyname, nk) == 0) {
428 cur->checked = 1;
429 return cur;
430 }
431 }
432 return NULL;
433}
434
435static bb_key_t *make_new_key(bb_key_t *k, const char *nk)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000436{
437 bb_key_t *cur;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000438 size_t nk_size;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000439
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000440 nk_size = strlen(nk) + 1;
441 cur = xmalloc(sizeof(bb_key_t) + nk_size);
442 cur->keyname = memcpy(cur + 1, nk, nk_size);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000443 cur->checked = 1;
444 cur->next = k;
445 return cur;
446}
447
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000448static inline char *store_include_fullpath(char *p_i, bb_key_t *li)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000449{
450 struct stat st;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000451 char *ok;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000452
453 if(stat(p_i, &st) == 0) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000454 ok = li->stored_path = bb_simplify_path(p_i);
455 } else {
456 ok = NULL;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000457 }
458 free(p_i);
459 return ok;
460}
461
462static void parse_inc(const char *include, const char *fname)
463{
464 bb_key_t *li;
465 char *p_i;
466 llist_t *lo;
467
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000468 li = check_key(Ifound, include);
469 if(li)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000470 return;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000471 Ifound = li = make_new_key(Ifound, include);
472
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000473 if(include[0] != '/') {
474 /* relative */
475 int w;
476 const char *p;
477
478 p_i = strrchr(fname, '/');
479 if(p_i == NULL) {
480 p = ".";
481 w = 1;
482 } else {
483 w = (p_i-fname);
484 p = fname;
485 }
486 p_i = bb_asprint("%.*s/%s", w, p, include);
487 if(store_include_fullpath(p_i, li))
488 return;
489 }
490 for(lo = Iop; lo; lo = lo->link) {
491 p_i = bb_asprint("%s/%s", lo->data, include);
492 if(store_include_fullpath(p_i, li))
493 return;
494 }
495 li->stored_path = NULL;
496 if(noiwarning)
497 fprintf(stderr, "%s: Warning: #include \"%s\" not found in specified paths\n", fname, include);
498}
499
500static void parse_conf_opt(char *opt, const char *val, size_t recordsz)
501{
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000502 bb_key_t *cur;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000503
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000504 cur = check_key(key_top, opt);
505 if(cur == NULL) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000506 /* new key, check old key if present after previous usage */
507 char *s, *p;
508 struct stat st;
509 int fd;
510 int cmp_ok = 0;
511 static char *record_buf;
512 static char *r_cmp;
513 static size_t r_sz;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000514 ssize_t rw_ret;
515
516 cur = make_new_key(key_top, opt);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000517
518 recordsz += 2; /* \n\0 */
519 if(recordsz > r_sz) {
520 record_buf = xrealloc(record_buf, r_sz=recordsz);
521 r_cmp = xrealloc(r_cmp, recordsz);
522 }
523 s = record_buf;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000524 /* may be short count " " */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000525 if(val) {
526 if(*val == '\0') {
527 cur->value = "";
528 recordsz = sprintf(s, "#define %s\n", opt);
529 } else {
530 cur->value = bb_xstrdup(val);
531 recordsz = sprintf(s, "#define %s %s\n", opt, val);
532 }
533 } else {
534 cur->value = NULL;
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000535 recordsz = sprintf(s, "#undef %s\n", opt);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000536 }
537 /* size_t -> ssize_t :( */
538 rw_ret = (ssize_t)recordsz;
539 /* trick, save first char KEY for do fast identify id */
540 first_chars[(int)*opt] = *opt;
541
542 /* key converting [A-Z_] -> [a-z/] */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000543 for(p = opt; *p; p++) {
544 if(*p >= 'A' && *p <= 'Z')
545 *p = *p - 'A' + 'a';
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000546 else if(*p == '_')
547 *p = '/';
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000548 }
549 p = bb_asprint("%s/%s.h", kp, opt);
550 cur->stored_path = opt = p;
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000551 if(stat(opt, &st)) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000552 p += kp_len;
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000553 while(*++p) {
554 /* Auto-create directories. */
555 if (*p == '/') {
556 *p = '\0';
557 if (stat(opt, &st) != 0 && mkdir(opt, 0755) != 0)
558 bb_error_d("mkdir(%s): %m", opt);
559 *p = '/';
560 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000561 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000562 } else {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000563 /* found */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000564 if(st.st_size == (off_t)recordsz) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000565 fd = open(opt, O_RDONLY);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000566 if(fd < 0 || read(fd, r_cmp, recordsz) < rw_ret)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000567 bb_error_d("%s: %m", opt);
568 close(fd);
569 cmp_ok = memcmp(s, r_cmp, recordsz) == 0;
570 }
571 }
572 if(!cmp_ok) {
573 fd = open(opt, O_WRONLY|O_CREAT|O_TRUNC, 0644);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000574 if(fd < 0 || write(fd, s, recordsz) < rw_ret)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000575 bb_error_d("%s: %m", opt);
576 close(fd);
577 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000578 key_top = cur;
579 } else {
580 /* present already */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000581 if((cur->value == NULL && val != NULL) ||
582 (cur->value != NULL && val == NULL) ||
583 (cur->value != NULL && val != NULL && strcmp(cur->value, val)))
584 fprintf(stderr, "Warning: redefined %s\n", opt);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000585 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000586 /* store only */
587 cur->checked = 0;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000588}
589
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000590static int show_dep(int first, bb_key_t *k, const char *name)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000591{
592 bb_key_t *cur;
593
594 for(cur = k; cur; cur = cur->next) {
595 if(cur->checked && cur->stored_path) {
596 if(first) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000597 printf("\n%s:", name);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000598 first = 0;
599 } else {
600 printf(" \\\n ");
601 }
602 printf(" %s", cur->stored_path);
603 }
604 cur->checked = 0;
605 }
606 return first;
607}
608
609static llist_t *files;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000610static struct stat st_kp;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000611
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000612static char *dir_and_entry;
613
614static char *
615filter_chd(const char *fe, const char *p, size_t dirlen)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000616{
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000617 struct stat st;
618 char *fp;
619 char *afp;
620 llist_t *cfl;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000621 file_list_t *f;
622 size_t df_sz;
623 static size_t dir_and_entry_sz;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000624
625 if (*fe == '.')
626 return NULL;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000627
628 df_sz = dirlen + strlen(fe) + 2; /* dir/file\0 */
629 if(df_sz > dir_and_entry_sz)
630 dir_and_entry = xrealloc(dir_and_entry, dir_and_entry_sz = df_sz);
631 fp = dir_and_entry;
632 sprintf(fp, "%s/%s", p, fe);
633
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000634 if(stat(fp, &st)) {
635 fprintf(stderr, "Warning: stat(%s): %m", fp);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000636 return NULL;
637 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000638 if(S_ISREG(st.st_mode)) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000639 afp = fp + df_sz - 3;
640 if(*afp++ != '.' || (*afp != 'c' && *afp != 'h')) {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000641 /* direntry is regular file, but is not *.[ch] */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000642 return NULL;
643 }
644 if (st.st_size == 0) {
645 fprintf(stderr, "Warning: %s is empty\n", fp);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000646 return NULL;
647 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000648 } else {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000649 if(S_ISDIR(st.st_mode)) {
650 if (st.st_dev == st_kp.st_dev && st.st_ino == st_kp.st_ino) {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000651 /* drop scan kp/ directory */
652 return NULL;
653 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000654 /* buff is returned, begin of zero allocate */
655 dir_and_entry = NULL;
656 dir_and_entry_sz = 0;
657 return fp;
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000658 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000659 /* hmm, is device! */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000660 return NULL;
661 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000662 afp = bb_simplify_path(fp);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000663 for(cfl = configs; cfl; cfl = cfl->link) {
664 if(cfl->data && strcmp(cfl->data, afp) == 0) {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000665 /* parse configs.h */
666 free(afp);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000667 c_lex(fp, st.st_size);
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000668 free(cfl->data);
669 cfl->data = NULL;
670 return NULL;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000671 }
672 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000673 /* direntry is *.[ch] regular file */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000674 f = xmalloc(sizeof(file_list_t));
675 f->name = afp;
676 f->ext = strrchr(afp, '.') + 1;
677 f->size = st.st_size;
678 files = llist_add_to(files, (char *)f);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000679 return NULL;
680}
681
682static void scan_dir_find_ch_files(char *p)
683{
684 llist_t *dirs;
685 llist_t *d_add;
686 llist_t *d;
687 struct dirent *de;
688 DIR *dir;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000689 size_t dirlen;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000690
691 dirs = llist_add_to(NULL, p);
692 /* emulate recursive */
693 while(dirs) {
694 d_add = NULL;
695 while(dirs) {
696 dir = opendir(dirs->data);
697 if (dir == NULL)
698 fprintf(stderr, "Warning: opendir(%s): %m", dirs->data);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000699 dirlen = strlen(dirs->data);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000700 while ((de = readdir(dir)) != NULL) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000701 char *found_dir = filter_chd(de->d_name, dirs->data, dirlen);
702
703 if(found_dir)
704 d_add = llist_add_to(d_add, found_dir);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000705 }
706 closedir(dir);
707 if(dirs->data != p)
708 free(dirs->data);
709 d = dirs;
710 dirs = dirs->link;
711 free(d);
712 }
713 dirs = d_add;
714 }
715}
716
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000717static char *pwd;
718
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000719int main(int argc, char **argv)
720{
721 int generate_dep = 1;
722 char *s;
723 int i;
724 llist_t *fl;
725
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000726 {
727 /* for bb_simplify_path */
728 /* libbb xgetcwd(), this program have not chdir() */
729 unsigned path_max = 512;
730
731 s = xmalloc (path_max);
732#define PATH_INCR 32
733 while (getcwd (s, path_max) == NULL) {
734 if(errno != ERANGE)
735 bb_error_d("getcwd: %m");
736 path_max += PATH_INCR;
737 s = xrealloc (s, path_max);
738 }
739 pwd = s;
740 }
741
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000742 while ((i = getopt(argc, argv, "I:c:dk:w")) > 0) {
743 switch(i) {
744 case 'I':
745 Iop = llist_add_to(Iop, optarg);
746 break;
747 case 'c':
748 s = bb_simplify_path(optarg);
749 configs = llist_add_to(configs, s);
750 break;
751 case 'd':
752 generate_dep = 0;
753 break;
754 case 'k':
755 if(kp)
756 bb_error_d("Hmm, why multiple -k?");
757 kp = bb_simplify_path(optarg);
758 break;
759 case 'w':
760 noiwarning = 1;
761 break;
762 default:
763 show_usage();
764 }
765 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000766 /* defaults */
767 if(kp == NULL)
768 kp = bb_simplify_path(INCLUDE_CONFIG_PATH);
769 if(Iop == NULL)
770 Iop = llist_add_to(Iop, LOCAL_INCLUDE_PATH);
771 if(configs == NULL) {
772 s = bb_simplify_path(INCLUDE_CONFIG_KEYS_PATH);
773 configs = llist_add_to(configs, s);
774 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000775 /* globals initialize */
776 /* for c_lex */
777 pagesizem1 = getpagesize() - 1;
778 id_s = xmalloc(mema_id);
779 for(i = 0; i < 256; i++) {
780 /* set unparsed chars for speed up of parser */
781 if(!ISALNUM(i) && i != CHR && i != STR &&
782 i != POUND && i != REM && i != BS)
783 first_chars[i] = ANY;
784 }
785 first_chars[i] = '-'; /* L_EOF */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000786
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000787 kp_len = strlen(kp);
788 if(stat(kp, &st_kp))
789 bb_error_d("stat(%s): %m", kp);
790 if(!S_ISDIR(st_kp.st_mode))
791 bb_error_d("%s is not directory", kp);
792
793 /* main loops */
794 argv += optind;
795 if(*argv) {
796 while(*argv)
797 scan_dir_find_ch_files(*argv++);
798 } else {
799 scan_dir_find_ch_files(".");
800 }
801
802 for(fl = configs; fl; fl = fl->link) {
803 if(fl->data) {
804 /* configs.h placed outsize of scanned dirs or not "*.ch" */
805 struct stat st;
806
807 if(stat(fl->data, &st))
808 bb_error_d("stat(%s): %m", fl->data);
809 c_lex(fl->data, st.st_size);
810 free(fl->data);
811 }
812 }
813 free(configs);
814 configs = NULL; /* flag read config --> parse sourses mode */
815
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000816 for(fl = files; fl; fl = fl->link) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000817 file_list_t *t = (file_list_t *)(fl->data);
818 c_lex(t->name, t->size);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000819 if(generate_dep) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000820 if(t->ext[0] == 'c') {
821 /* *.c -> *.o */
822 t->ext[0] = 'o';
823 }
824 i = show_dep(1, Ifound, t->name);
825 i = show_dep(i, key_top, t->name);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000826 if(i == 0)
827 putchar('\n');
828 }
829 }
830 return 0;
831}
832
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000833/* partial and simplify libbb routine */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000834static void bb_error_d(const char *s, ...)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000835{
836 va_list p;
837
838 va_start(p, s);
839 vfprintf(stderr, s, p);
840 va_end(p);
841 putc('\n', stderr);
842 exit(1);
843}
844
845
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000846static void *xmalloc(size_t size)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000847{
848 void *p = malloc(size);
849
850 if(p == NULL)
851 bb_error_d("memory exhausted");
852 return p;
853}
854
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000855static void *xrealloc(void *p, size_t size) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000856 p = realloc(p, size);
857 if(p == NULL)
858 bb_error_d("memory exhausted");
859 return p;
860}
861
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000862static char *bb_asprint(const char *format, ...)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000863{
864 va_list p;
865 int r;
866 char *out;
867
868 va_start(p, format);
869 r = vasprintf(&out, format, p);
870 va_end(p);
871
872 if (r < 0)
873 bb_error_d("bb_asprint: %m");
874 return out;
875}
876
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000877static llist_t *llist_add_to(llist_t *old_head, char *new_item)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000878{
879 llist_t *new_head;
880
881 new_head = xmalloc(sizeof(llist_t));
882 new_head->data = new_item;
883 new_head->link = old_head;
884
885 return(new_head);
886}
887
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000888static char *bb_xstrdup(const char *s)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000889{
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000890 char *r = strdup(s);
891
892 if(r == NULL)
893 bb_error_d("memory exhausted");
894 return r;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000895}
896
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000897static char *bb_simplify_path(const char *path)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000898{
899 char *s, *start, *p;
900
901 if (path[0] == '/')
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000902 start = bb_xstrdup(path);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000903 else {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000904 /* is not libbb, but this program have not chdir() */
905 start = bb_asprint("%s/%s", pwd, path);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000906 }
907 p = s = start;
908
909 do {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000910 if (*p == '/') {
911 if (*s == '/') { /* skip duplicate (or initial) slash */
912 continue;
913 } else if (*s == '.') {
914 if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */
915 continue;
916 } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) {
917 ++s;
918 if (p > start) {
919 while (*--p != '/'); /* omit previous dir */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000920 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000921 continue;
922 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000923 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000924 }
925 *++p = *s;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000926 } while (*++s);
927
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000928 if ((p == start) || (*p != '/')) { /* not a trailing slash */
929 ++p; /* so keep last character */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000930 }
931 *p = 0;
932
933 return start;
934}