blob: e1e4c6348fe6d244f82b4a8bf06d6ce6c4e4762c [file] [log] [blame]
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00001/*
"Vladimir N. Oleynik"4cbe4592005-09-19 10:26:45 +00002 * Another fast dependencies generator for Makefiles, Version 2.2
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +00003 *
4 * Copyright (C) 2005 by Vladimir Oleynik <dzo@simtreas.ru>
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +00005 * mmaping file may be originally by Linus Torvalds.
6 *
7 * (c) 2005 Bernhard Fischer:
8 * - commentary typos,
9 * - move "memory exhausted" into msg_enomem,
10 * - more verbose --help output.
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000011 *
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000012 * This program does:
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000013 * 1) find #define KEY VALUE or #undef KEY from include/config.h
14 * 2) save include/config/key*.h if changed after previous usage
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000015 * 3) recursive scan from "./" *.[ch] files, but skips scan of include/config/
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000016 * 4) find #include "*.h" and KEYs using, if not as #define and #undef
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000017 * 5) generate dependencies to stdout
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000018 * path/file.o: include/config/key*.h found_include_*.h
19 * path/inc.h: include/config/key*.h found_included_include_*.h
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +000020 * This program does not generate dependencies for #include <...>
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000021 */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000022
23#define LOCAL_INCLUDE_PATH "include"
24#define INCLUDE_CONFIG_PATH LOCAL_INCLUDE_PATH"/config"
25#define INCLUDE_CONFIG_KEYS_PATH LOCAL_INCLUDE_PATH"/config.h"
26
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000027#define bb_mkdep_full_options \
28"\nOptions:" \
29"\n\t-I local_include_path include paths, default: \"" LOCAL_INCLUDE_PATH "\"" \
30"\n\t-d don't generate depend" \
31"\n\t-w show warning if include files not found" \
32"\n\t-k include/config default: \"" INCLUDE_CONFIG_PATH "\"" \
33"\n\t-c include/config.h configs, default: \"" INCLUDE_CONFIG_KEYS_PATH "\"" \
34"\n\tdirs_to_scan default \".\""
35
36#define bb_mkdep_terse_options "Usage: [-I local_include_paths] [-dw] " \
37 "[-k path_for_stored_keys] [dirs]"
38
39
40
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000041#define _GNU_SOURCE
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <sys/mman.h>
45#include <getopt.h>
46#include <dirent.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <stdarg.h>
51#include <unistd.h>
52#include <errno.h>
53#include <fcntl.h>
54
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000055
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000056typedef struct BB_KEYS {
57 char *keyname;
58 const char *value;
59 char *stored_path;
60 int checked;
61 struct BB_KEYS *next;
62} bb_key_t;
63
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000064static bb_key_t *check_key(bb_key_t *k, const char *nk);
65static bb_key_t *make_new_key(bb_key_t *k, const char *nk);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000066
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000067/* partial and simplified libbb routine */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +000068static void bb_error_d(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
69static char * bb_asprint(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000070
71/* stolen from libbb as is */
72typedef struct llist_s {
73 char *data;
74 struct llist_s *link;
75} llist_t;
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +000076static void *xrealloc(void *p, size_t size);
77static void *xmalloc(size_t size);
78static char *bb_xstrdup(const char *s);
79static char *bb_simplify_path(const char *path);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000080/* error messages */
81static const char msg_enomem[] = "memory exhausted";
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000082
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000083/* for lexical analyser */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000084static bb_key_t *key_top;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +000085static llist_t *configs;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000086
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000087static int mode;
88#define CONFIG_MODE 0
89#define SOURCES_MODE 1
90
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +000091static void parse_inc(const char *include, const char *fname);
92static void parse_conf_opt(char *opt, const char *val, size_t rsz);
93
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000094/* for speed tricks */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +000095static char first_chars[257]; /* + L_EOF */
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +000096static char isalnums[257]; /* + L_EOF */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +000097/* trick for fast find "define", "include", "undef" */
98static char first_chars_diu[256];
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +000099
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000100static int pagesizem1;
101static size_t mema_id = 128; /* first allocated for id */
102static char *id_s;
103
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000104
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000105
106#define yy_error_d(s) bb_error_d("%s:%d hmm, %s", fname, line, s)
107
108/* state */
109#define S 0 /* start state */
110#define STR '"' /* string */
111#define CHR '\'' /* char */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000112#define REM '/' /* block comment */
113#define BS '\\' /* back slash */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000114#define POUND '#' /* # */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000115#define I 'i' /* #include preprocessor's directive */
116#define D 'd' /* #define preprocessor's directive */
117#define U 'u' /* #undef preprocessor's directive */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000118#define LI 'I' /* #include "... */
119#define DK 'K' /* #define KEY... (config mode) */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000120#define DV 'V' /* #define KEY "VALUE or #define KEY 'VALUE */
121#define NLC 'n' /* \ and \n */
122#define ANY '*' /* any unparsed chars */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000123
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000124#define L_EOF 256
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000125/* [A-Z_a-z] */
126#define ID(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
127/* [A-Z_a-z0-9] */
128#define ISALNUM(c) (ID(c) || (c >= '0' && c <= '9'))
129
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000130#define getc1() do { c = (optr >= oend) ? L_EOF : *optr++; } while(0)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000131#define ungetc1() optr--
132
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000133#define put_id(c) do { if(id_len == local_mema_id) \
134 id = xrealloc(id, local_mema_id += 16); \
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000135 id[id_len++] = c; } while(0)
136
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000137
138
139/* stupid C lexical analyser */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000140static void c_lex(const char *fname, long fsize)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000141{
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000142 int c = L_EOF; /* stupid initialize */
143 int prev_state = L_EOF;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000144 int called;
145 int state;
146 int line;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000147 char *id = id_s;
148 size_t local_mema_id = mema_id;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000149 size_t id_len = 0; /* stupid initialize */
150 char *val = NULL;
151 unsigned char *optr, *oend;
152 unsigned char *start = NULL; /* stupid initialize */
153
154 int fd;
155 char *map;
156 int mapsize;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000157
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000158 if(fsize == 0) {
159 fprintf(stderr, "Warning: %s is empty\n", fname);
160 return;
161 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000162 fd = open(fname, O_RDONLY);
163 if(fd < 0) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000164 perror(fname);
165 return;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000166 }
167 mapsize = (fsize+pagesizem1) & ~pagesizem1;
168 map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
169 if ((long) map == -1)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000170 bb_error_d("%s: mmap: %m", fname);
171
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000172 optr = (unsigned char *)map;
173 oend = optr + fsize;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000174
175 line = 1;
176 called = state = S;
177
178 for(;;) {
179 if(state == LI || state == DV) {
180 /* store "include.h" or config mode #define KEY "|'..."|' */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000181 if(state == LI) {
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000182 put_id(0);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000183 parse_inc(id, fname);
184 } else {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000185 /* #define KEY "[VAL]" */
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000186 put_id(c); /* #define KEY "VALUE"<- */
187 put_id(0);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000188 parse_conf_opt(id, val, (optr - start));
189 }
190 state = S;
191 }
192 if(prev_state != state) {
193 prev_state = state;
194 getc1();
195 }
196
197 /* [ \t]+ eat first space */
198 while(c == ' ' || c == '\t')
199 getc1();
200
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000201 if(c == BS) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000202 getc1();
203 if(c == '\n') {
204 /* \\\n eat continued */
205 line++;
206 prev_state = NLC;
207 continue;
208 }
209 ungetc1();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000210 c = BS;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000211 }
212
213 if(state == S) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000214 while(first_chars[c] == ANY) {
215 /* <S>unparsed */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000216 if(c == '\n')
217 line++;
218 getc1();
219 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000220 if(c == L_EOF) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000221 /* <S><<EOF>> */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000222 id_s = id;
223 mema_id = local_mema_id;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000224 munmap(map, mapsize);
225 close(fd);
226 return;
227 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000228 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000229 /* <S>/ */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000230 getc1(); /* eat <S>/ */
231 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000232 /* <S>"//"[^\n]* */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000233 do getc1(); while(c != '\n' && c != L_EOF);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000234 } else if(c == '*') {
235 /* <S>[/][*] */
236 called = S;
237 state = REM;
238 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000239 } else if(c == POUND) {
240 /* <S># */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000241 start = optr - 1;
242 state = c;
243 } else if(c == STR || c == CHR) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000244 /* <S>\"|\' */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000245 val = NULL;
246 called = S;
247 state = c;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000248 } else if(c != BS) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000249 /* <S>[A-Z_a-z0-9] */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000250
251 /* trick for fast drop id
252 if key with this first char undefined */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000253 if(first_chars[c] == 0) {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000254 /* skip <S>[A-Z_a-z0-9]+ */
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000255 do getc1(); while(isalnums[c]);
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000256 } else {
257 id_len = 0;
258 do {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000259 /* <S>[A-Z_a-z0-9]+ */
260 put_id(c);
261 getc1();
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000262 } while(isalnums[c]);
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000263 put_id(0);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000264 check_key(key_top, id);
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000265 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000266 } else {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000267 /* <S>\\ */
268 prev_state = c;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000269 }
270 continue;
271 }
272 if(state == REM) {
273 for(;;) {
274 /* <REM>[^*]+ */
275 while(c != '*') {
276 if(c == '\n') {
277 /* <REM>\n */
278 if(called != S)
279 yy_error_d("unexpected newline");
280 line++;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000281 } else if(c == L_EOF)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000282 yy_error_d("unexpected EOF");
283 getc1();
284 }
285 /* <REM>[*] */
286 getc1();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000287 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000288 /* <REM>[*][/] */
289 state = called;
290 break;
291 }
292 }
293 continue;
294 }
295 if(state == STR || state == CHR) {
296 for(;;) {
297 /* <STR,CHR>\n|<<EOF>> */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000298 if(c == '\n' || c == L_EOF)
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000299 yy_error_d("unterminated");
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000300 if(c == BS) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000301 /* <STR,CHR>\\ */
302 getc1();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000303 if(c != BS && c != '\n' && c != state) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000304 /* another usage \ in str or char */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000305 if(c == L_EOF)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000306 yy_error_d("unexpected EOF");
307 if(val)
308 put_id(c);
309 continue;
310 }
311 /* <STR,CHR>\\[\\\n] or <STR>\\\" or <CHR>\\\' */
312 /* eat 2 char */
313 if(c == '\n')
314 line++;
315 else if(val)
316 put_id(c);
317 } else if(c == state) {
318 /* <STR>\" or <CHR>\' */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000319 state = called;
320 break;
321 } else if(val)
322 put_id(c);
323 /* <STR,CHR>. */
324 getc1();
325 }
326 continue;
327 }
328
329 /* begin preprocessor states */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000330 if(c == L_EOF)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000331 yy_error_d("unexpected EOF");
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000332 if(c == REM) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000333 /* <#.*>/ */
334 getc1();
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000335 if(c == REM)
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000336 yy_error_d("detected // in preprocessor line");
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000337 if(c == '*') {
338 /* <#.*>[/][*] */
339 called = state;
340 state = REM;
341 continue;
342 }
343 /* hmm, #.*[/] */
344 yy_error_d("strange preprocessor line");
345 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000346 if(state == POUND) {
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000347 /* tricks */
348 static const char * const preproc[] = {
349 /* 0-4 */
350 "", "", "", "", "",
351 /* 5 */ /* 6 */ /* 7 */
352 "undef", "define", "include",
353 };
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000354 size_t diu = first_chars_diu[c]; /* strlen and preproc ptr */
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000355 const unsigned char *p = optr - 1;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000356
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000357 while(isalnums[c]) getc1();
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000358 /* have str begined with c, readed == strlen key and compared */
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000359 if(diu != S && diu == (optr-p-1) && !memcmp(p, preproc[diu], diu)) {
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000360 state = *p;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000361 id_len = 0; /* common for save */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000362 } else {
363 state = S;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000364 }
365 ungetc1();
366 continue;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000367 }
368 if(state == I) {
369 if(c == STR) {
370 /* <I>\" */
371 val = id;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000372 called = LI;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000373 state = STR;
374 } else {
375 /* another (may be wrong) #include ... */
376 ungetc1();
377 state = S;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000378 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000379 continue;
380 }
381 if(state == D || state == U) {
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000382 if(mode == SOURCES_MODE) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000383 /* ignore depend with #define or #undef KEY */
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000384 while(isalnums[c])
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000385 getc1();
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000386 state = S;
387 } else {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000388 /* save KEY from #"define"|"undef" ... */
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000389 while(isalnums[c]) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000390 put_id(c);
391 getc1();
392 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000393 if(!id_len)
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000394 yy_error_d("expected identifier");
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000395 put_id(0);
396 if(state == U) {
397 parse_conf_opt(id, NULL, (optr - start));
398 state = S;
399 } else {
400 /* D -> DK */
401 state = DK;
402 }
403 }
404 ungetc1();
405 continue;
406 }
407 if(state == DK) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000408 /* #define KEY[ ] (config mode) */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000409 val = id + id_len;
410 if(c == STR || c == CHR) {
411 /* define KEY "... or define KEY '... */
412 put_id(c);
413 called = DV;
414 state = c;
415 continue;
416 }
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000417 while(isalnums[c]) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000418 /* VALUE */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000419 put_id(c);
420 getc1();
421 }
"Vladimir N. Oleynik"4cbe4592005-09-19 10:26:45 +0000422 c = 0;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000423 ungetc1();
424 state = DV;
425 continue;
426 }
427 }
428}
429
430
431static void show_usage(void) __attribute__ ((noreturn));
432static void show_usage(void)
433{
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000434 bb_error_d("%s\n%s\n", bb_mkdep_terse_options, bb_mkdep_full_options);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000435}
436
437static const char *kp;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000438static size_t kp_len;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000439static llist_t *Iop;
440static bb_key_t *Ifound;
441static int noiwarning;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000442
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000443static bb_key_t *check_key(bb_key_t *k, const char *nk)
444{
445 bb_key_t *cur;
446
447 for(cur = k; cur; cur = cur->next) {
448 if(strcmp(cur->keyname, nk) == 0) {
449 cur->checked = 1;
450 return cur;
451 }
452 }
453 return NULL;
454}
455
456static bb_key_t *make_new_key(bb_key_t *k, const char *nk)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000457{
458 bb_key_t *cur;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000459 size_t nk_size;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000460
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000461 nk_size = strlen(nk) + 1;
462 cur = xmalloc(sizeof(bb_key_t) + nk_size);
463 cur->keyname = memcpy(cur + 1, nk, nk_size);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000464 cur->checked = 0;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000465 cur->next = k;
466 return cur;
467}
468
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000469static inline char *store_include_fullpath(char *p_i, bb_key_t *li)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000470{
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000471 char *ok;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000472
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000473 if(access(p_i, F_OK) == 0) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000474 ok = li->stored_path = bb_simplify_path(p_i);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000475 li->checked = 1;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000476 } else {
477 ok = NULL;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000478 }
479 free(p_i);
480 return ok;
481}
482
483static void parse_inc(const char *include, const char *fname)
484{
485 bb_key_t *li;
486 char *p_i;
487 llist_t *lo;
488
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000489 li = check_key(Ifound, include);
490 if(li)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000491 return;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000492 Ifound = li = make_new_key(Ifound, include);
493
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000494 if(include[0] != '/') {
495 /* relative */
496 int w;
497 const char *p;
498
499 p_i = strrchr(fname, '/');
500 if(p_i == NULL) {
501 p = ".";
502 w = 1;
503 } else {
504 w = (p_i-fname);
505 p = fname;
506 }
507 p_i = bb_asprint("%.*s/%s", w, p, include);
508 if(store_include_fullpath(p_i, li))
509 return;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000510 for(lo = Iop; lo; lo = lo->link) {
511 p_i = bb_asprint("%s/%s", lo->data, include);
512 if(store_include_fullpath(p_i, li))
513 return;
514 }
515 } else {
516 /* absolute include pathname */
517 if(access(include, F_OK) == 0) {
518 li->stored_path = bb_xstrdup(include);
519 li->checked = 1;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000520 return;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000521 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000522 }
523 li->stored_path = NULL;
524 if(noiwarning)
525 fprintf(stderr, "%s: Warning: #include \"%s\" not found in specified paths\n", fname, include);
526}
527
528static void parse_conf_opt(char *opt, const char *val, size_t recordsz)
529{
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000530 bb_key_t *cur;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000531 char *s, *p;
532 struct stat st;
533 int fd;
534 int cmp_ok = 0;
535 static char *record_buf;
536 static char *r_cmp;
537 static size_t r_sz;
538 ssize_t rw_ret;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000539
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000540 cur = check_key(key_top, opt);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000541 if(cur != NULL) {
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000542 /* present already */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000543 cur->checked = 0; /* store only */
544 if(cur->value == NULL && val == NULL)
545 return;
546 if(cur->value != NULL && val != NULL && strcmp(cur->value, val) == 0)
547 return;
548 fprintf(stderr, "Warning: redefined %s\n", opt);
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000549 } else {
550 key_top = cur = make_new_key(key_top, opt);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000551 }
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000552 /* do generate record */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000553 recordsz += 2; /* \n\0 */
554 if(recordsz > r_sz) {
555 record_buf = xrealloc(record_buf, r_sz=recordsz);
556 r_cmp = xrealloc(r_cmp, recordsz);
557 }
558 s = record_buf;
559 /* may be short count " " */
560 if(val) {
561 if(*val == '\0') {
562 cur->value = "";
563 recordsz = sprintf(s, "#define %s\n", opt);
564 } else {
565 cur->value = bb_xstrdup(val);
566 recordsz = sprintf(s, "#define %s %s\n", opt, val);
567 }
568 } else {
569 cur->value = NULL;
570 recordsz = sprintf(s, "#undef %s\n", opt);
571 }
572 /* size_t -> ssize_t :( */
573 rw_ret = (ssize_t)recordsz;
574 /* trick, save first char KEY for do fast identify id */
575 first_chars[(int)*opt] = *opt;
576
577 /* key converting [A-Z_] -> [a-z/] */
578 for(p = opt; *p; p++) {
579 if(*p >= 'A' && *p <= 'Z')
580 *p = *p - 'A' + 'a';
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000581 else if(*p == '_' && p[1] > '9') /* do not change A_1 to A/1 */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000582 *p = '/';
583 }
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000584 /* check kp/key.h if present after previous usage */
585 cur->stored_path = opt = bb_asprint("%s/%s.h", kp, opt);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000586 if(stat(opt, &st)) {
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000587 p = opt + kp_len;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000588 while(*++p) {
589 /* Auto-create directories. */
590 if (*p == '/') {
591 *p = '\0';
592 if (access(opt, F_OK) != 0 && mkdir(opt, 0755) != 0)
593 bb_error_d("mkdir(%s): %m", opt);
594 *p = '/';
595 }
596 }
597 } else {
598 /* found */
599 if(st.st_size == (off_t)recordsz) {
600 fd = open(opt, O_RDONLY);
601 if(fd < 0 || read(fd, r_cmp, recordsz) < rw_ret)
602 bb_error_d("%s: %m", opt);
603 close(fd);
604 cmp_ok = memcmp(s, r_cmp, recordsz) == 0;
605 }
606 }
607 if(!cmp_ok) {
608 fd = open(opt, O_WRONLY|O_CREAT|O_TRUNC, 0644);
609 if(fd < 0 || write(fd, s, recordsz) < rw_ret)
610 bb_error_d("%s: %m", opt);
611 close(fd);
612 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000613}
614
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000615static int show_dep(int first, bb_key_t *k, const char *name)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000616{
617 bb_key_t *cur;
618
619 for(cur = k; cur; cur = cur->next) {
620 if(cur->checked && cur->stored_path) {
621 if(first) {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000622 printf("\n%s:", name);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000623 first = 0;
624 } else {
625 printf(" \\\n ");
626 }
627 printf(" %s", cur->stored_path);
628 }
629 cur->checked = 0;
630 }
631 return first;
632}
633
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000634static struct stat st_kp;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000635static int dontgenerate_dep;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000636
637static char *
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000638parse_chd(const char *fe, const char *p, size_t dirlen)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000639{
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000640 struct stat st;
641 char *fp;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000642 size_t df_sz;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000643 static char *dir_and_entry;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000644 static size_t dir_and_entry_sz;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000645
646 if (*fe == '.')
647 return NULL;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000648
649 df_sz = dirlen + strlen(fe) + 2; /* dir/file\0 */
650 if(df_sz > dir_and_entry_sz)
651 dir_and_entry = xrealloc(dir_and_entry, dir_and_entry_sz = df_sz);
652 fp = dir_and_entry;
653 sprintf(fp, "%s/%s", p, fe);
654
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000655 if(stat(fp, &st)) {
656 fprintf(stderr, "Warning: stat(%s): %m", fp);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000657 return NULL;
658 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000659 if(S_ISREG(st.st_mode)) {
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000660 llist_t *cfl;
661 char *e = fp + df_sz - 3;
662
663 if(*e++ != '.' || (*e != 'c' && *e != 'h')) {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000664 /* direntry is regular file, but is not *.[ch] */
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000665 return NULL;
666 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000667 for(cfl = configs; cfl; cfl = cfl->link) {
668 struct stat *config = (struct stat *)cfl->data;
669
670 if (st.st_dev == config->st_dev && st.st_ino == config->st_ino) {
671 /* skip already parsed configs.h */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000672 return NULL;
673 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000674 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000675 /* direntry is *.[ch] regular file and is not configs */
676 if(!dontgenerate_dep) {
677 int first;
678
679 c_lex(fp, st.st_size);
680 fp = bb_simplify_path(fp);
681 if(*e == 'c') {
682 /* *.c -> *.o */
683 e = strrchr(fp, '.') + 1;
684 *e = 'o';
685 }
686 first = show_dep(1, Ifound, fp);
687 first = show_dep(first, key_top, fp);
688 if(first == 0)
689 putchar('\n');
690 free(fp);
691 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000692 return NULL;
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000693 } else if(S_ISDIR(st.st_mode)) {
694 if (st.st_dev == st_kp.st_dev && st.st_ino == st_kp.st_ino)
695 return NULL; /* drop scan kp/ directory */
696 /* direntry is directory. buff is returned, begin of zero allocate */
697 dir_and_entry = NULL;
698 dir_and_entry_sz = 0;
699 return fp;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000700 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000701 /* hmm, direntry is device! */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000702 return NULL;
703}
704
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000705/* from libbb but inline for fast */
706static inline llist_t *llist_add_to(llist_t *old_head, char *new_item)
707{
708 llist_t *new_head;
709
710 new_head = xmalloc(sizeof(llist_t));
711 new_head->data = new_item;
712 new_head->link = old_head;
713
714 return(new_head);
715}
716
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000717static void scan_dir_find_ch_files(char *p)
718{
719 llist_t *dirs;
720 llist_t *d_add;
721 llist_t *d;
722 struct dirent *de;
723 DIR *dir;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000724 size_t dirlen;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000725
726 dirs = llist_add_to(NULL, p);
727 /* emulate recursive */
728 while(dirs) {
729 d_add = NULL;
730 while(dirs) {
731 dir = opendir(dirs->data);
732 if (dir == NULL)
733 fprintf(stderr, "Warning: opendir(%s): %m", dirs->data);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000734 dirlen = strlen(dirs->data);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000735 while ((de = readdir(dir)) != NULL) {
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000736 char *found_dir = parse_chd(de->d_name, dirs->data, dirlen);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000737
738 if(found_dir)
739 d_add = llist_add_to(d_add, found_dir);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000740 }
741 closedir(dir);
742 if(dirs->data != p)
743 free(dirs->data);
744 d = dirs;
745 dirs = dirs->link;
746 free(d);
747 }
748 dirs = d_add;
749 }
750}
751
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000752static char *pwd;
753
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000754int main(int argc, char **argv)
755{
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000756 char *s;
757 int i;
758 llist_t *fl;
759
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000760 {
761 /* for bb_simplify_path */
762 /* libbb xgetcwd(), this program have not chdir() */
763 unsigned path_max = 512;
764
765 s = xmalloc (path_max);
766#define PATH_INCR 32
767 while (getcwd (s, path_max) == NULL) {
768 if(errno != ERANGE)
769 bb_error_d("getcwd: %m");
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000770 s = xrealloc (s, path_max += PATH_INCR);
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000771 }
772 pwd = s;
773 }
774
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000775 while ((i = getopt(argc, argv, "I:c:dk:w")) > 0) {
776 switch(i) {
777 case 'I':
778 Iop = llist_add_to(Iop, optarg);
779 break;
780 case 'c':
781 s = bb_simplify_path(optarg);
782 configs = llist_add_to(configs, s);
783 break;
784 case 'd':
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000785 dontgenerate_dep = 1;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000786 break;
787 case 'k':
788 if(kp)
789 bb_error_d("Hmm, why multiple -k?");
790 kp = bb_simplify_path(optarg);
791 break;
792 case 'w':
793 noiwarning = 1;
794 break;
795 default:
796 show_usage();
797 }
798 }
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000799 /* default kp */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000800 if(kp == NULL)
801 kp = bb_simplify_path(INCLUDE_CONFIG_PATH);
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000802 /* globals initialize */
803 kp_len = strlen(kp);
804 if(stat(kp, &st_kp))
805 bb_error_d("stat(%s): %m", kp);
806 if(!S_ISDIR(st_kp.st_mode))
807 bb_error_d("%s is not directory", kp);
808 /* defaults */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000809 if(Iop == NULL)
810 Iop = llist_add_to(Iop, LOCAL_INCLUDE_PATH);
811 if(configs == NULL) {
812 s = bb_simplify_path(INCLUDE_CONFIG_KEYS_PATH);
813 configs = llist_add_to(configs, s);
814 }
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000815 /* for c_lex */
816 pagesizem1 = getpagesize() - 1;
817 id_s = xmalloc(mema_id);
818 for(i = 0; i < 256; i++) {
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000819 if(ISALNUM(i))
820 isalnums[i] = i;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000821 /* set unparsed chars for speed up of parser */
"Vladimir N. Oleynik"af0dd592005-09-16 13:57:33 +0000822 else if(i != CHR && i != STR && i != POUND && i != REM && i != BS)
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000823 first_chars[i] = ANY;
824 }
825 first_chars[i] = '-'; /* L_EOF */
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000826 /* trick for fast find "define", "include", "undef" */
827 first_chars_diu[(int)'d'] = (char)6; /* strlen("define"); */
828 first_chars_diu[(int)'i'] = (char)7; /* strlen("include"); */
829 first_chars_diu[(int)'u'] = (char)5; /* strlen("undef"); */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000830
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000831 /* parse configs */
832 for(fl = configs; fl; fl = fl->link) {
833 struct stat st;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000834
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000835 if(stat(fl->data, &st))
836 bb_error_d("stat(%s): %m", fl->data);
837 c_lex(fl->data, st.st_size);
838 /* trick for fast comparing found files with configs */
839 fl->data = xrealloc(fl->data, sizeof(struct stat));
840 memcpy(fl->data, &st, sizeof(struct stat));
841 }
842
843 /* main loop */
844 mode = SOURCES_MODE;
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000845 argv += optind;
846 if(*argv) {
847 while(*argv)
848 scan_dir_find_ch_files(*argv++);
849 } else {
850 scan_dir_find_ch_files(".");
851 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000852 return 0;
853}
854
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000855/* partial and simplified libbb routine */
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000856static void bb_error_d(const char *s, ...)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000857{
858 va_list p;
859
860 va_start(p, s);
861 vfprintf(stderr, s, p);
862 va_end(p);
863 putc('\n', stderr);
864 exit(1);
865}
866
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000867static char *bb_asprint(const char *format, ...)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000868{
869 va_list p;
870 int r;
871 char *out;
872
873 va_start(p, format);
874 r = vasprintf(&out, format, p);
875 va_end(p);
876
877 if (r < 0)
878 bb_error_d("bb_asprint: %m");
879 return out;
880}
881
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000882/* partial libbb routine as is */
883static void *xmalloc(size_t size)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000884{
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000885 void *p = malloc(size);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000886
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000887 if(p == NULL)
888 bb_error_d(msg_enomem);
889 return p;
890}
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000891
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000892static void *xrealloc(void *p, size_t size) {
893 p = realloc(p, size);
894 if(p == NULL)
895 bb_error_d(msg_enomem);
896 return p;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000897}
898
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000899static char *bb_xstrdup(const char *s)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000900{
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000901 char *r = strdup(s);
902
903 if(r == NULL)
"Vladimir N. Oleynik"7573ac62005-09-14 15:09:06 +0000904 bb_error_d(msg_enomem);
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000905 return r;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000906}
907
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000908static char *bb_simplify_path(const char *path)
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000909{
910 char *s, *start, *p;
911
912 if (path[0] == '/')
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000913 start = bb_xstrdup(path);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000914 else {
"Vladimir N. Oleynik"676e95e2005-09-13 16:50:53 +0000915 /* is not libbb, but this program have not chdir() */
916 start = bb_asprint("%s/%s", pwd, path);
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000917 }
918 p = s = start;
919
920 do {
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000921 if (*p == '/') {
922 if (*s == '/') { /* skip duplicate (or initial) slash */
923 continue;
924 } else if (*s == '.') {
925 if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */
926 continue;
927 } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) {
928 ++s;
929 if (p > start) {
930 while (*--p != '/'); /* omit previous dir */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000931 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000932 continue;
933 }
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000934 }
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000935 }
936 *++p = *s;
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000937 } while (*++s);
938
"Vladimir N. Oleynik"b1fe4622005-09-12 16:39:47 +0000939 if ((p == start) || (*p != '/')) { /* not a trailing slash */
940 ++p; /* so keep last character */
"Vladimir N. Oleynik"5e60dc42005-09-12 12:33:27 +0000941 }
942 *p = 0;
943
944 return start;
945}