aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
author"Vladimir N. Oleynik" <dzo@simtreas.ru>2005-09-12 12:33:27 +0000
committer"Vladimir N. Oleynik" <dzo@simtreas.ru>2005-09-12 12:33:27 +0000
commit5e60dc4a209b053e8fe5170bd143173941c4634c (patch)
tree43f8c3bf33914c701b2224b218d2ed21078ef2ea /scripts
parentba50217281e9265aa5935d184f698204143e765f (diff)
downloadbusybox-5e60dc4a209b053e8fe5170bd143173941c4634c.tar.gz
new my scripts/mm_mkdep, dependences work now
Diffstat (limited to 'scripts')
-rw-r--r--scripts/bb_mkdep.c855
-rw-r--r--scripts/mkdep.c628
-rw-r--r--scripts/split-include.c226
3 files changed, 855 insertions, 854 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 @@
+/*
+ * Another dependences for Makefile mashine generator
+ *
+ * Copyright (C) 2005 by Vladimir Oleynik <dzo@simtreas.ru>
+ *
+ * This programm do
+ * 1) find #define KEY VALUE or #undef KEY from include/config.h
+ * 2) save include/config/key*.h if changed after previous usage
+ * 3) recursive scan from "./" *.[ch] files, but skip scan include/config/...
+ * 4) find #include "*.h" and KEYs using, if not as #define and #undef
+ * 5) generate depend to stdout
+ * path/file.o: include/config/key*.h found_include_*.h
+ * path/inc.h: include/config/key*.h found_included_include_*.h
+ * This programm do not generate dependences for #include <...>
+ *
+ * Options:
+ * -I local_include_path (include`s paths, default: LOCAL_INCLUDE_PATH)
+ * -d (don`t generate depend)
+ * -w (show warning if include files not found)
+ * -k include/config (default: INCLUDE_CONFIG_PATH)
+ * -c include/config.h (configs, default: INCLUDE_CONFIG_KEYS_PATH)
+*/
+
+#define LOCAL_INCLUDE_PATH "include"
+#define INCLUDE_CONFIG_PATH LOCAL_INCLUDE_PATH"/config"
+#define INCLUDE_CONFIG_KEYS_PATH LOCAL_INCLUDE_PATH"/config.h"
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+typedef struct BB_KEYS {
+ char *keyname;
+ const char *value;
+ char *stored_path;
+ int checked;
+ struct BB_KEYS *next;
+} bb_key_t;
+
+
+/* partial and simplify libbb routine */
+
+void bb_error_d(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2)));
+char * bb_asprint(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+
+/* stolen from libbb as is */
+typedef struct llist_s {
+ char *data;
+ struct llist_s *link;
+} llist_t;
+llist_t *llist_add_to(llist_t *old_head, char *new_item);
+void *xrealloc(void *p, size_t size);
+void *xmalloc(size_t size);
+char *bb_xstrdup(const char *s);
+char *bb_simplify_path(const char *path);
+
+/* for lexical analyzier */
+static bb_key_t *key_top;
+
+static void parse_inc(const char *include, const char *fname);
+static void parse_conf_opt(char *opt, const char *val, size_t rsz);
+
+#define CHECK_ONLY 0
+#define MAKE_NEW 1
+static bb_key_t *find_already(bb_key_t *k, const char *nk, int flg_save_new);
+
+#define yy_error_d(s) bb_error_d("%s:%d hmm, %s", fname, line, s)
+
+/* state */
+#define S 0 /* start state */
+#define STR '"' /* string */
+#define CHR '\'' /* char */
+#define REM '*' /* block comment */
+#define POUND '#' /* # */
+#define I 'i' /* #include preprocessor`s directive */
+#define D 'd' /* #define preprocessor`s directive */
+#define U 'u' /* #undef preprocessor`s directive */
+#define LI 'I' /* #include "... */
+#define DK 'K' /* #define KEY... (config mode) */
+#define DV 'V' /* #define KEY "... or #define KEY '... */
+#define NLC 'n' /* \+\n */
+#define ANY '?' /* skip unparsed . */
+
+/* [A-Z_a-z] */
+#define ID(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
+/* [A-Z_a-z0-9] */
+#define ISALNUM(c) (ID(c) || (c >= '0' && c <= '9'))
+
+#define getc1() do { c = (optr >= oend) ? EOF : *optr++; } while(0)
+#define ungetc1() optr--
+
+#define put_id(c) do { if(id_len == mema_id) \
+ id = xrealloc(id, mema_id += 16); \
+ id[id_len++] = c; } while(0)
+
+/* stupid C lexical analizator */
+static void c_lex(const char *fname, int flg_config_include)
+{
+ int c = EOF; /* stupid initialize */
+ int prev_state = EOF;
+ int called;
+ int state;
+ int line;
+ static size_t mema_id;
+ char *id = xmalloc(mema_id=128); /* fist allocate */
+ size_t id_len = 0; /* stupid initialize */
+ char *val = NULL;
+ unsigned char *optr, *oend;
+ unsigned char *start = NULL; /* stupid initialize */
+
+ int fd;
+ char *map;
+ int mapsize;
+ {
+ /* stolen from mkdep by Linus Torvalds */
+ int pagesizem1 = getpagesize() - 1;
+ struct stat st;
+
+ fd = open(fname, O_RDONLY);
+ if(fd < 0) {
+ perror(fname);
+ return;
+ }
+ fstat(fd, &st);
+ if (st.st_size == 0)
+ bb_error_d("%s is empty", fname);
+ mapsize = st.st_size;
+ mapsize = (mapsize+pagesizem1) & ~pagesizem1;
+ map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
+ if ((long) map == -1)
+ bb_error_d("%s: mmap: %m", fname);
+
+ /* hereinafter is my */
+ optr = (unsigned char *)map;
+ oend = optr + st.st_size;
+ }
+
+ line = 1;
+ called = state = S;
+
+ for(;;) {
+ if(state == LI || state == DV) {
+ /* store "include.h" or config mode #define KEY "|'..."|' */
+ put_id(0);
+ if(state == LI) {
+ parse_inc(id, fname);
+ } else {
+ /*
+ if(val[0] == '\0')
+ yy_error_d("expected value");
+ */
+ parse_conf_opt(id, val, (optr - start));
+ }
+ state = S;
+ }
+ if(prev_state != state) {
+ prev_state = state;
+ getc1();
+ }
+
+ /* [ \t]+ eat first space */
+ while(c == ' ' || c == '\t')
+ getc1();
+
+ if(c == '\\') {
+ getc1();
+ if(c == '\n') {
+ /* \\\n eat continued */
+ line++;
+ prev_state = NLC;
+ continue;
+ }
+ ungetc1();
+ c = '\\';
+ }
+
+ if(state == S) {
+ while(c <= ' ' && c != EOF) {
+ /* <S>[\000- ]+ */
+ if(c == '\n')
+ line++;
+ getc1();
+ }
+ if(c == EOF) {
+ /* <S><<EOF>> */
+ munmap(map, mapsize);
+ close(fd);
+ return;
+ }
+ if(c == '/') {
+ /* <S>/ */
+ getc1();
+ if(c == '/') {
+ /* <S>"//"[^\n]* */
+ do getc1(); while(c != '\n' && c != EOF);
+ } else if(c == '*') {
+ /* <S>[/][*] */
+ called = S;
+ state = REM;
+ }
+ /* eat <S>/ */
+ } else if(c == '#') {
+ /* <S>\"|\'|# */
+ start = optr - 1;
+ state = c;
+ } else if(c == STR || c == CHR) {
+ /* <S>\"|\'|# */
+ val = NULL;
+ called = S;
+ state = c;
+ } else if(ISALNUM(c)) {
+ /* <S>[A-Z_a-z0-9] */
+ id_len = 0;
+ do {
+ /* <S>[A-Z_a-z0-9]+ */
+ put_id(c);
+ getc1();
+ } while(ISALNUM(c));
+ put_id(0);
+ find_already(key_top, id, CHECK_ONLY);
+ } else {
+ /* <S>. */
+ prev_state = ANY;
+ }
+ continue;
+ }
+ if(state == REM) {
+ for(;;) {
+ /* <REM>[^*]+ */
+ while(c != '*') {
+ if(c == '\n') {
+ /* <REM>\n */
+ if(called != S)
+ yy_error_d("unexpected newline");
+ line++;
+ } else if(c == EOF)
+ yy_error_d("unexpected EOF");
+ getc1();
+ }
+ /* <REM>[*] */
+ getc1();
+ if(c == '/') {
+ /* <REM>[*][/] */
+ state = called;
+ break;
+ }
+ }
+ continue;
+ }
+ if(state == STR || state == CHR) {
+ for(;;) {
+ /* <STR,CHR>\n|<<EOF>> */
+ if(c == '\n' || c == EOF)
+ yy_error_d("unterminating");
+ if(c == '\\') {
+ /* <STR,CHR>\\ */
+ getc1();
+ if(c != '\\' && c != '\n' && c != state) {
+ /* another usage \ in str or char */
+ if(c == EOF)
+ yy_error_d("unexpected EOF");
+ if(val)
+ put_id(c);
+ continue;
+ }
+ /* <STR,CHR>\\[\\\n] or <STR>\\\" or <CHR>\\\' */
+ /* eat 2 char */
+ if(c == '\n')
+ line++;
+ else if(val)
+ put_id(c);
+ } else if(c == state) {
+ /* <STR>\" or <CHR>\' */
+ if(called == DV)
+ put_id(c);
+ state = called;
+ break;
+ } else if(val)
+ put_id(c);
+ /* <STR,CHR>. */
+ getc1();
+ }
+ continue;
+ }
+
+ /* begin preprocessor states */
+ if(c == EOF)
+ yy_error_d("unexpected EOF");
+ if(c == '/') {
+ /* <#.*>/ */
+ getc1();
+ if(c == '/')
+ yy_error_d("detect // in preprocessor line");
+ if(c == '*') {
+ /* <#.*>[/][*] */
+ called = state;
+ state = REM;
+ continue;
+ }
+ /* hmm, #.*[/] */
+ yy_error_d("strange preprocessor line");
+ }
+ if(state == '#') {
+ static const char * const preproc[] = {
+ "define", "undef", "include", ""
+ };
+ const char * const *str_type;
+
+ id_len = 0;
+ while(ISALNUM(c)) {
+ put_id(c);
+ getc1();
+ }
+ put_id(0);
+ for(str_type = preproc; (state = **str_type); str_type++) {
+ if(*id == state && strcmp(id, *str_type) == 0)
+ break;
+ }
+ /* to S if another #directive */
+ ungetc1();
+ id_len = 0; /* common for save */
+ continue;
+ }
+ if(state == I) {
+ if(c == STR) {
+ /* <I>\" */
+ val = id;
+ state = STR;
+ called = LI;
+ continue;
+ }
+ /* another (may be wrong) #include ... */
+ ungetc1();
+ state = S;
+ continue;
+ }
+ if(state == D || state == U) {
+ while(ISALNUM(c)) {
+ if(flg_config_include) {
+ /* save KEY from #"define"|"undef" ... */
+ put_id(c);
+ }
+ getc1();
+ }
+ if(!flg_config_include) {
+ state = S;
+ } else {
+ if(!id_len)
+ yy_error_d("expected identificator");
+ put_id(0);
+ if(state == U) {
+ parse_conf_opt(id, NULL, (optr - start));
+ state = S;
+ } else {
+ /* D -> DK */
+ state = DK;
+ }
+ }
+ ungetc1();
+ continue;
+ }
+ if(state == DK) {
+ /* #define (config mode) */
+ val = id + id_len;
+ if(c == STR || c == CHR) {
+ /* define KEY "... or define KEY '... */
+ put_id(c);
+ called = DV;
+ state = c;
+ continue;
+ }
+ while(ISALNUM(c)) {
+ put_id(c);
+ getc1();
+ }
+ ungetc1();
+ state = DV;
+ continue;
+ }
+ }
+}
+
+
+static void show_usage(void) __attribute__ ((noreturn));
+static void show_usage(void)
+{
+ bb_error_d("Usage: [-I local_include_path] [-dw] "
+ "[-k path_for_store_keys] [-s skip_file]");
+}
+
+static const char *kp;
+static llist_t *Iop;
+static bb_key_t *Ifound;
+static int noiwarning;
+static llist_t *configs;
+
+static bb_key_t *find_already(bb_key_t *k, const char *nk, int flg_save_new)
+{
+ bb_key_t *cur;
+
+ for(cur = k; cur; cur = cur->next) {
+ if(strcmp(cur->keyname, nk) == 0) {
+ cur->checked = 1;
+ return NULL;
+ }
+ }
+ if(flg_save_new == CHECK_ONLY)
+ return NULL;
+ cur = xmalloc(sizeof(bb_key_t));
+ cur->keyname = bb_xstrdup(nk);
+ cur->checked = 1;
+ cur->next = k;
+ return cur;
+}
+
+static int store_include_fullpath(char *p_i, bb_key_t *li)
+{
+ struct stat st;
+ int ok = 0;
+
+ if(stat(p_i, &st) == 0) {
+ li->stored_path = bb_simplify_path(p_i);
+ ok = 1;
+ }
+ free(p_i);
+ return ok;
+}
+
+static void parse_inc(const char *include, const char *fname)
+{
+ bb_key_t *li;
+ char *p_i;
+ llist_t *lo;
+
+ if((li = find_already(Ifound, include, MAKE_NEW)) == NULL)
+ return;
+ Ifound = li;
+ if(include[0] != '/') {
+ /* relative */
+ int w;
+ const char *p;
+
+ p_i = strrchr(fname, '/');
+ if(p_i == NULL) {
+ p = ".";
+ w = 1;
+ } else {
+ w = (p_i-fname);
+ p = fname;
+ }
+ p_i = bb_asprint("%.*s/%s", w, p, include);
+ if(store_include_fullpath(p_i, li))
+ return;
+ }
+ for(lo = Iop; lo; lo = lo->link) {
+ p_i = bb_asprint("%s/%s", lo->data, include);
+ if(store_include_fullpath(p_i, li))
+ return;
+ }
+ li->stored_path = NULL;
+ if(noiwarning)
+ fprintf(stderr, "%s: Warning: #include \"%s\" not found in specified paths\n", fname, include);
+}
+
+static void parse_conf_opt(char *opt, const char *val, size_t recordsz)
+{
+ bb_key_t *cur = find_already(key_top, opt, MAKE_NEW);
+
+ if(cur != NULL) {
+ /* new key, check old key if present after previous usage */
+ char *s, *p;
+ struct stat st;
+ int fd;
+ int cmp_ok = 0;
+ static char *record_buf;
+ static char *r_cmp;
+ static size_t r_sz;
+
+ recordsz += 2; /* \n\0 */
+ if(recordsz > r_sz) {
+ record_buf = xrealloc(record_buf, r_sz=recordsz);
+ r_cmp = xrealloc(r_cmp, recordsz);
+ }
+ s = record_buf;
+ if(val)
+ sprintf(s, "#define %s%s%s\n", opt, (*val ? " " : ""), val);
+ else
+ sprintf(s, "#undef %s\n", opt);
+ /* may be short count " " */
+ recordsz = strlen(s);
+ /* key converting [A-Z] -> [a-z] */
+ for(p = opt; *p; p++) {
+ if(*p >= 'A' && *p <= 'Z')
+ *p = *p - 'A' + 'a';
+ if(*p == '_')
+ *p = '/';
+ }
+ p = bb_asprint("%s/%s.h", kp, opt);
+ cur->stored_path = opt = p;
+ while(*++p) {
+ /* Auto-create directories. */
+ if (*p == '/') {
+ *p = '\0';
+ if (stat(opt, &st) != 0 && mkdir(opt, 0755) != 0)
+ bb_error_d("mkdir(%s): %m", opt);
+ *p = '/';
+ }
+ }
+ if(stat(opt, &st) == 0) {
+ /* found */
+ if(st.st_size == recordsz) {
+ fd = open(opt, O_RDONLY);
+ if(fd < 0 || read(fd, r_cmp, recordsz) != recordsz)
+ bb_error_d("%s: %m", opt);
+ close(fd);
+ cmp_ok = memcmp(s, r_cmp, recordsz) == 0;
+ }
+ }
+ if(!cmp_ok) {
+ fd = open(opt, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if(fd < 0 || write(fd, s, recordsz) != recordsz)
+ bb_error_d("%s: %m", opt);
+ close(fd);
+ }
+ /* store only */
+ cur->checked = 0;
+ if(val) {
+ if(*val == '\0') {
+ cur->value = "";
+ } else {
+ cur->value = bb_xstrdup(val);
+ }
+ } else {
+ cur->value = NULL;
+ }
+ key_top = cur;
+ } else {
+ /* present already */
+ for(cur = key_top; cur; cur = cur->next) {
+ if(strcmp(cur->keyname, opt) == 0) {
+ cur->checked = 0;
+ if(cur->value == NULL && val == NULL)
+ return;
+ if((cur->value == NULL && val != NULL) ||
+ (cur->value != NULL && val == NULL) ||
+ strcmp(cur->value, val))
+ fprintf(stderr, "Warning: redefined %s\n", opt);
+ return;
+ }
+ }
+ }
+}
+
+static int show_dep(int first, bb_key_t *k, const char *a)
+{
+ bb_key_t *cur;
+
+ for(cur = k; cur; cur = cur->next) {
+ if(cur->checked && cur->stored_path) {
+ if(first) {
+ const char *ext;
+
+ if(*a == '.' && a[1] == '/')
+ a += 2;
+ ext = strrchr(a, '.');
+ if(ext && ext[1] == 'c' && ext[2] == '\0') {
+ /* *.c -> *.o */
+ printf("\n%.*s.o:", (ext - a), a);
+ } else {
+ printf("\n%s:", a);
+ }
+ first = 0;
+ } else {
+ printf(" \\\n ");
+ }
+ printf(" %s", cur->stored_path);
+ }
+ cur->checked = 0;
+ }
+ return first;
+}
+
+static llist_t *files;
+
+static llist_t *filter_chd(const char *fe, const char *p, llist_t *pdirs)
+{
+ const char *e;
+ struct stat st;
+ char *fp;
+ char *afp;
+ llist_t *cfl;
+
+ if (*fe == '.')
+ return NULL;
+ fp = bb_asprint("%s/%s", p, fe);
+ if(stat(fp, &st)) {
+ fprintf(stderr, "Warning: stat(%s): %m", fp);
+ free(fp);
+ return NULL;
+ }
+ afp = bb_simplify_path(fp);
+ if(S_ISDIR(st.st_mode)) {
+ if(strcmp(kp, afp) == 0) {
+ /* is autogenerated to kp/key* by previous usage */
+ free(afp);
+ free(fp);
+ /* drop scan kp/ directory */
+ return NULL;
+ }
+ free(afp);
+ return llist_add_to(pdirs, fp);
+ }
+ if(!S_ISREG(st.st_mode)) {
+ /* hmm, is device! */
+ free(afp);
+ free(fp);
+ return NULL;
+ }
+ e = strrchr(fe, '.');
+ if(e == NULL || !((e[1]=='c' || e[1]=='h') && e[2]=='\0')) {
+ /* direntry is not directory or *.[ch] */
+ free(afp);
+ free(fp);
+ return NULL;
+ }
+ for(cfl = configs; cfl; cfl = cfl->link) {
+ if(cfl->data && strcmp(cfl->data, afp) == 0) {
+ /* parse configs.h */
+ free(afp);
+ c_lex(fp, 1);
+ free(fp);
+ free(cfl->data);
+ cfl->data = NULL;
+ return NULL;
+ }
+ }
+ free(fp);
+ /* direntry is *.[ch] regular file */
+ files = llist_add_to(files, afp);
+ return NULL;
+}
+
+static void scan_dir_find_ch_files(char *p)
+{
+ llist_t *dirs;
+ llist_t *d_add;
+ llist_t *d;
+ struct dirent *de;
+ DIR *dir;
+
+ dirs = llist_add_to(NULL, p);
+ /* emulate recursive */
+ while(dirs) {
+ d_add = NULL;
+ while(dirs) {
+ dir = opendir(dirs->data);
+ if (dir == NULL)
+ fprintf(stderr, "Warning: opendir(%s): %m", dirs->data);
+ while ((de = readdir(dir)) != NULL) {
+ d = filter_chd(de->d_name, dirs->data, d_add);
+ if(d)
+ d_add = d;
+ }
+ closedir(dir);
+ if(dirs->data != p)
+ free(dirs->data);
+ d = dirs;
+ dirs = dirs->link;
+ free(d);
+ }
+ dirs = d_add;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int generate_dep = 1;
+ char *s;
+ int i;
+ llist_t *fl;
+
+ while ((i = getopt(argc, argv, "I:c:dk:w")) > 0) {
+ switch(i) {
+ case 'I':
+ Iop = llist_add_to(Iop, optarg);
+ break;
+ case 'c':
+ s = bb_simplify_path(optarg);
+ configs = llist_add_to(configs, s);
+ break;
+ case 'd':
+ generate_dep = 0;
+ break;
+ case 'k':
+ if(kp)
+ bb_error_d("Hmm, why multiple -k?");
+ kp = bb_simplify_path(optarg);
+ break;
+ case 'w':
+ noiwarning = 1;
+ break;
+ default:
+ show_usage();
+ }
+ }
+ if(argc > optind)
+ show_usage();
+
+ /* defaults */
+ if(kp == NULL)
+ kp = bb_simplify_path(INCLUDE_CONFIG_PATH);
+ if(Iop == NULL)
+ Iop = llist_add_to(Iop, LOCAL_INCLUDE_PATH);
+ if(configs == NULL) {
+ s = bb_simplify_path(INCLUDE_CONFIG_KEYS_PATH);
+ configs = llist_add_to(configs, s);
+ }
+ scan_dir_find_ch_files(".");
+
+ for(fl = files; fl; fl = fl->link) {
+ c_lex(fl->data, 0);
+ if(generate_dep) {
+ i = show_dep(1, Ifound, fl->data);
+ i = show_dep(i, key_top, fl->data);
+ if(i == 0)
+ putchar('\n');
+ }
+ }
+ return 0;
+}
+
+void bb_error_d(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vfprintf(stderr, s, p);
+ va_end(p);
+ putc('\n', stderr);
+ exit(1);
+}
+
+
+void *xmalloc(size_t size)
+{
+ void *p = malloc(size);
+
+ if(p == NULL)
+ bb_error_d("memory exhausted");
+ return p;
+}
+
+void *xrealloc(void *p, size_t size) {
+ p = realloc(p, size);
+ if(p == NULL)
+ bb_error_d("memory exhausted");
+ return p;
+}
+
+char *bb_asprint(const char *format, ...)
+{
+ va_list p;
+ int r;
+ char *out;
+
+ va_start(p, format);
+ r = vasprintf(&out, format, p);
+ va_end(p);
+
+ if (r < 0)
+ bb_error_d("bb_asprint: %m");
+ return out;
+}
+
+llist_t *llist_add_to(llist_t *old_head, char *new_item)
+{
+ llist_t *new_head;
+
+ new_head = xmalloc(sizeof(llist_t));
+ new_head->data = new_item;
+ new_head->link = old_head;
+
+ return(new_head);
+}
+
+char *bb_xstrdup(const char *s)
+{
+ char *r = strdup(s);
+ if(r == NULL)
+ bb_error_d("memory exhausted");
+ return r;
+}
+
+char *bb_simplify_path(const char *path)
+{
+ char *s, *start, *p;
+
+ if (path[0] == '/')
+ start = bb_xstrdup(path);
+ else {
+ static char *pwd;
+
+ if(pwd == NULL) {
+ /* is not libbb, but this program have not chdir() */
+ unsigned path_max = 512;
+ char *cwd = xmalloc (path_max);
+#define PATH_INCR 32
+ while (getcwd (cwd, path_max) == NULL) {
+ if(errno != ERANGE)
+ bb_error_d("getcwd: %m");
+ path_max += PATH_INCR;
+ cwd = xrealloc (cwd, path_max);
+ }
+ pwd = cwd;
+ }
+ start = bb_asprint("%s/%s", pwd, path);
+ }
+ p = s = start;
+
+ do {
+ if (*p == '/') {
+ if (*s == '/') { /* skip duplicate (or initial) slash */
+ continue;
+ } else if (*s == '.') {
+ if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */
+ continue;
+ } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) {
+ ++s;
+ if (p > start) {
+ while (*--p != '/'); /* omit previous dir */
+ }
+ continue;
+ }
+ }
+ }
+ *++p = *s;
+ } while (*++s);
+
+ if ((p == start) || (*p != '/')) { /* not a trailing slash */
+ ++p; /* so keep last character */
+ }
+ *p = 0;
+
+ return start;
+}
diff --git a/scripts/mkdep.c b/scripts/mkdep.c
deleted file mode 100644
index ae3cc74e0..000000000
--- a/scripts/mkdep.c
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * Originally by Linus Torvalds.
- * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
- *
- * Usage: mkdep cflags -- file ...
- *
- * Read source files and output makefile dependency lines for them.
- * I make simple dependency lines for #include <*.h> and #include "*.h".
- * I also find instances of CONFIG_FOO and generate dependencies
- * like include/config/foo.h.
- *
- * 1 August 1999, Michael Elizabeth Chastain, <mec@shout.net>
- * - Keith Owens reported a bug in smart config processing. There used
- * to be an optimization for "#define CONFIG_FOO ... #ifdef CONFIG_FOO",
- * so that the file would not depend on CONFIG_FOO because the file defines
- * this symbol itself. But this optimization is bogus! Consider this code:
- * "#if 0 \n #define CONFIG_FOO \n #endif ... #ifdef CONFIG_FOO". Here
- * the definition is inactivated, but I still used it. It turns out this
- * actually happens a few times in the kernel source. The simple way to
- * fix this problem is to remove this particular optimization.
- *
- * 2.3.99-pre1, Andrew Morton <andrewm@uow.edu.au>
- * - Changed so that 'filename.o' depends upon 'filename.[cS]'. This is so that
- * missing source files are noticed, rather than silently ignored.
- *
- * 2.4.2-pre3, Keith Owens <kaos@ocs.com.au>
- * - Accept cflags followed by '--' followed by filenames. mkdep extracts -I
- * options from cflags and looks in the specified directories as well as the
- * defaults. Only -I is supported, no attempt is made to handle -idirafter,
- * -isystem, -I- etc.
- */
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-
-
-char depname[512];
-int hasdep;
-
-struct path_struct {
- int len;
- char *buffer;
-};
-struct path_struct *path_array;
-int paths;
-
-
-/* Current input file */
-static const char *g_filename;
-
-/*
- * This records all the configuration options seen.
- * In perl this would be a hash, but here it's a long string
- * of values separated by newlines. This is simple and
- * extremely fast.
- */
-char * str_config = NULL;
-int size_config = 0;
-int len_config = 0;
-
-static void
-do_depname(void)
-{
- if (!hasdep) {
- hasdep = 1;
- if (g_filename) {
- /* Source file (*.[cS]) */
- printf("%s:", depname);
- printf(" %s", g_filename);
- } else {
- /* header file (*.h) */
- printf("dep_%s +=", depname);
- }
- }
-}
-
-/*
- * Grow the configuration string to a desired length.
- * Usually the first growth is plenty.
- */
-void grow_config(int len)
-{
- while (len_config + len > size_config) {
- if (size_config == 0)
- size_config = 2048;
- str_config = realloc(str_config, size_config *= 2);
- if (str_config == NULL)
- { perror("malloc config"); exit(1); }
- }
-}
-
-
-
-/*
- * Lookup a value in the configuration string.
- */
-int is_defined_config(const char * name, int len)
-{
- const char * pconfig;
- const char * plast = str_config + len_config - len;
- for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
- if (pconfig[ -1] == '\n'
- && pconfig[len] == '\n'
- && !memcmp(pconfig, name, len))
- return 1;
- }
- return 0;
-}
-
-
-
-/*
- * Add a new value to the configuration string.
- */
-void define_config(const char * name, int len)
-{
- grow_config(len + 1);
-
- memcpy(str_config+len_config, name, len);
- len_config += len;
- str_config[len_config++] = '\n';
-}
-
-
-
-/*
- * Clear the set of configuration strings.
- */
-void clear_config(void)
-{
- len_config = 0;
- define_config("", 0);
-}
-
-
-
-/*
- * This records all the precious .h filenames. No need for a hash,
- * it's a long string of values enclosed in tab and newline.
- */
-char * str_precious = NULL;
-int size_precious = 0;
-int len_precious = 0;
-
-
-
-/*
- * Grow the precious string to a desired length.
- * Usually the first growth is plenty.
- */
-void grow_precious(int len)
-{
- while (len_precious + len > size_precious) {
- if (size_precious == 0)
- size_precious = 2048;
- str_precious = realloc(str_precious, size_precious *= 2);
- if (str_precious == NULL)
- { perror("malloc"); exit(1); }
- }
-}
-
-
-
-/*
- * Add a new value to the precious string.
- */
-void define_precious(const char * filename)
-{
- int len = strlen(filename);
- grow_precious(len + 4);
- *(str_precious+len_precious++) = '\t';
- memcpy(str_precious+len_precious, filename, len);
- len_precious += len;
- memcpy(str_precious+len_precious, " \\\n", 3);
- len_precious += 3;
-}
-
-
-
-/*
- * Handle an #include line.
- */
-void handle_include(int start, const char * name, int len)
-{
- struct path_struct *path;
- int i;
-
- if (len == 14 && !memcmp(name, "include/config.h", len))
- return;
-
- if (len >= 7 && !memcmp(name, "config/", 7))
- define_config(name+7, len-7-2);
-
- for (i = start, path = path_array+start; i < paths; ++i, ++path) {
- memcpy(path->buffer+path->len, name, len);
- path->buffer[path->len+len] = '\0';
- if (access(path->buffer, F_OK) == 0) {
- do_depname();
- printf(" \\\n %s $(dep_%s)", path->buffer, path->buffer);
- return;
- }
- }
-
-}
-
-
-
-/*
- * Add a path to the list of include paths.
- */
-void add_path(const char * name)
-{
- struct path_struct *path;
- char resolved_path[PATH_MAX+1];
- const char *name2;
-
- if (strcmp(name, ".")) {
- name2 = realpath(name, resolved_path);
- if (!name2) {
- fprintf(stderr, "realpath(%s) failed, %m\n", name);
- exit(1);
- }
- }
- else {
- name2 = "";
- }
-
- path_array = realloc(path_array, (++paths)*sizeof(*path_array));
- if (!path_array) {
- fprintf(stderr, "cannot expand path_arry\n");
- exit(1);
- }
-
- path = path_array+paths-1;
- path->len = strlen(name2);
- path->buffer = malloc(path->len+1+256+1);
- if (!path->buffer) {
- fprintf(stderr, "cannot allocate path buffer\n");
- exit(1);
- }
- strcpy(path->buffer, name2);
- if (path->len && *(path->buffer+path->len-1) != '/') {
- *(path->buffer+path->len) = '/';
- *(path->buffer+(++(path->len))) = '\0';
- }
-}
-
-
-
-/*
- * Record the use of a CONFIG_* word.
- */
-void use_config(const char * name, int len)
-{
- char *pc;
- int i;
-
- pc = path_array[paths-1].buffer + path_array[paths-1].len;
- memcpy(pc, "config/", 7);
- pc += 7;
-
- for (i = 0; i < len; i++) {
- char c = name[i];
- if (isupper((int)c)) c = tolower((int)c);
- if (c == '_') c = '/';
- pc[i] = c;
- }
- pc[len] = '\0';
-
- if (is_defined_config(pc, len))
- return;
-
- define_config(pc, len);
-
- do_depname();
- printf(" \\\n $(wildcard %s.h)", path_array[paths-1].buffer);
-}
-
-
-
-/*
- * Macros for stunningly fast map-based character access.
- * __buf is a register which holds the current word of the input.
- * Thus, there is one memory access per sizeof(unsigned long) characters.
- */
-
-#if defined(__alpha__) || defined(__i386__) || defined(__ia64__) || defined(__x86_64__) || defined(__MIPSEL__) \
- || defined(__arm__)
-#define LE_MACHINE
-#endif
-
-#ifdef LE_MACHINE
-#define next_byte(x) (x >>= 8)
-#define current ((unsigned char) __buf)
-#else
-#define next_byte(x) (x <<= 8)
-#define current (__buf >> 8*(sizeof(unsigned long)-1))
-#endif
-
-#define GETNEXT { \
- next_byte(__buf); \
- if ((unsigned long) next % sizeof(unsigned long) == 0) { \
- if (next >= end) \
- break; \
- __buf = * (unsigned long *) next; \
- } \
- next++; \
-}
-
-/*
- * State machine macros.
- */
-#define CASE(c,label) if (current == c) goto label
-#define NOTCASE(c,label) if (current != c) goto label
-
-/*
- * Yet another state machine speedup.
- */
-#define MAX2(a,b) ((a)>(b)?(a):(b))
-#define MIN2(a,b) ((a)<(b)?(a):(b))
-#define MAX5(a,b,c,d,e) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,e)))))
-#define MIN5(a,b,c,d,e) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,e)))))
-
-
-
-/*
- * The state machine looks for (approximately) these Perl regular expressions:
- *
- * m|\/\*.*?\*\/|
- * m|\/\/.*|
- * m|'.*?'|
- * m|".*?"|
- * m|#\s*include\s*"(.*?)"|
- * m|#\s*include\s*<(.*?>"|
- * m|#\s*(?define|undef)\s*CONFIG_(\w*)|
- * m|(?!\w)CONFIG_|
- *
- * About 98% of the CPU time is spent here, and most of that is in
- * the 'start' paragraph. Because the current characters are
- * in a register, the start loop usually eats 4 or 8 characters
- * per memory read. The MAX5 and MIN5 tests dispose of most
- * input characters with 1 or 2 comparisons.
- */
-void state_machine(const char * map, const char * end)
-{
- const char * next = map;
- const char * map_dot;
- unsigned long __buf = 0;
-
- for (;;) {
-start:
- GETNEXT
-__start:
- if (current > MAX5('/','\'','"','#','C')) goto start;
- if (current < MIN5('/','\'','"','#','C')) goto start;
- CASE('/', slash);
- CASE('\'', squote);
- CASE('"', dquote);
- CASE('#', pound);
- CASE('C', cee);
- goto start;
-
-/* // */
-slash_slash:
- GETNEXT
- CASE('\n', start);
- NOTCASE('\\', slash_slash);
- GETNEXT
- goto slash_slash;
-
-/* / */
-slash:
- GETNEXT
- CASE('/', slash_slash);
- NOTCASE('*', __start);
-slash_star_dot_star:
- GETNEXT
-__slash_star_dot_star:
- NOTCASE('*', slash_star_dot_star);
- GETNEXT
- NOTCASE('/', __slash_star_dot_star);
- goto start;
-
-/* '.*?' */
-squote:
- GETNEXT
- CASE('\'', start);
- NOTCASE('\\', squote);
- GETNEXT
- goto squote;
-
-/* ".*?" */
-dquote:
- GETNEXT
- CASE('"', start);
- NOTCASE('\\', dquote);
- GETNEXT
- goto dquote;
-
-/* #\s* */
-pound:
- GETNEXT
- CASE(' ', pound);
- CASE('\t', pound);
- CASE('i', pound_i);
- CASE('d', pound_d);
- CASE('u', pound_u);
- goto __start;
-
-/* #\s*i */
-pound_i:
- GETNEXT NOTCASE('n', __start);
- GETNEXT NOTCASE('c', __start);
- GETNEXT NOTCASE('l', __start);
- GETNEXT NOTCASE('u', __start);
- GETNEXT NOTCASE('d', __start);
- GETNEXT NOTCASE('e', __start);
- goto pound_include;
-
-/* #\s*include\s* */
-pound_include:
- GETNEXT
- CASE(' ', pound_include);
- CASE('\t', pound_include);
- map_dot = next;
- CASE('"', pound_include_dquote);
- CASE('<', pound_include_langle);
- goto __start;
-
-/* #\s*include\s*"(.*)" */
-pound_include_dquote:
- GETNEXT
- CASE('\n', start);
- NOTCASE('"', pound_include_dquote);
- handle_include(0, map_dot, next - map_dot - 1);
- goto start;
-
-/* #\s*include\s*<(.*)> */
-pound_include_langle:
- GETNEXT
- CASE('\n', start);
- NOTCASE('>', pound_include_langle);
- handle_include(1, map_dot, next - map_dot - 1);
- goto start;
-
-/* #\s*d */
-pound_d:
- GETNEXT NOTCASE('e', __start);
- GETNEXT NOTCASE('f', __start);
- GETNEXT NOTCASE('i', __start);
- GETNEXT NOTCASE('n', __start);
- GETNEXT NOTCASE('e', __start);
- goto pound_define_undef;
-
-/* #\s*u */
-pound_u:
- GETNEXT NOTCASE('n', __start);
- GETNEXT NOTCASE('d', __start);
- GETNEXT NOTCASE('e', __start);
- GETNEXT NOTCASE('f', __start);
- goto pound_define_undef;
-
-/*
- * #\s*(define|undef)\s*CONFIG_(\w*)
- *
- * this does not define the word, because it could be inside another
- * conditional (#if 0). But I do parse the word so that this instance
- * does not count as a use. -- mec
- */
-pound_define_undef:
- GETNEXT
- CASE(' ', pound_define_undef);
- CASE('\t', pound_define_undef);
-
- NOTCASE('C', __start);
- GETNEXT NOTCASE('O', __start);
- GETNEXT NOTCASE('N', __start);
- GETNEXT NOTCASE('F', __start);
- GETNEXT NOTCASE('I', __start);
- GETNEXT NOTCASE('G', __start);
- GETNEXT NOTCASE('_', __start);
-
- map_dot = next;
-pound_define_undef_CONFIG_word:
- GETNEXT
- if (isalnum(current) || current == '_')
- goto pound_define_undef_CONFIG_word;
- goto __start;
-
-/* \<CONFIG_(\w*) */
-cee:
- if (next >= map+2 && (isalnum((int)next[-2]) || next[-2] == '_'))
- goto start;
- GETNEXT NOTCASE('O', __start);
- GETNEXT NOTCASE('N', __start);
- GETNEXT NOTCASE('F', __start);
- GETNEXT NOTCASE('I', __start);
- GETNEXT NOTCASE('G', __start);
- GETNEXT NOTCASE('_', __start);
-
- map_dot = next;
-cee_CONFIG_word:
- GETNEXT
- if (isalnum(current) || current == '_')
- goto cee_CONFIG_word;
- use_config(map_dot, next - map_dot - 1);
- goto __start;
- }
-}
-
-
-
-/*
- * Generate dependencies for one file.
- */
-void do_depend(const char * filename)
-{
- int mapsize;
- int pagesizem1 = getpagesize()-1;
- int fd;
- struct stat st;
- char * map;
-
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- perror(filename);
- return;
- }
-
- fstat(fd, &st);
- if (st.st_size == 0) {
- fprintf(stderr,"%s is empty\n",filename);
- close(fd);
- return;
- }
-
- mapsize = st.st_size;
- mapsize = (mapsize+pagesizem1) & ~pagesizem1;
- map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
- if ((long) map == -1) {
- perror("mkdep: mmap");
- close(fd);
- return;
- }
- if ((unsigned long) map % sizeof(unsigned long) != 0)
- {
- fprintf(stderr, "do_depend: map not aligned\n");
- exit(1);
- }
-
- hasdep = 0;
- clear_config();
- state_machine(map, map+st.st_size);
- if (hasdep) {
- puts("");
- }
-
- munmap(map, mapsize);
- close(fd);
-}
-
-
-
-/*
- * Generate dependencies for all files.
- */
-int main(int argc, char **argv)
-{
- int len;
- const char *hpath;
-
- hpath = getenv("TOPDIR");
- if (!hpath) {
- fputs("mkdep: TOPDIR not set in environment. "
- "Don't bypass the top level Makefile.\n", stderr);
- return 1;
- }
-
- add_path("."); /* for #include "..." */
-
- while (++argv, --argc > 0) {
- if (strncmp(*argv, "-I", 2) == 0) {
- if (*((*argv)+2)) {
- add_path((*argv)+2);
- }
- else {
- ++argv;
- --argc;
- add_path(*argv);
- }
- }
- else if (strcmp(*argv, "--") == 0) {
- break;
- }
- }
-
- add_path(hpath); /* must be last entry, for config files */
-
- while (--argc > 0) {
- const char * filename = *++argv;
- g_filename = 0;
- len = strlen(filename);
- memcpy(depname, filename, len+1);
- if (len > 2 && filename[len-2] == '.') {
- if (filename[len-1] == 'c' || filename[len-1] == 'S') {
- depname[len-1] = 'o';
- g_filename = filename;
- }
- }
- do_depend(filename);
- }
- if (len_precious) {
- *(str_precious+len_precious) = '\0';
- printf(".PRECIOUS:%s\n", str_precious);
- }
- return 0;
-}
diff --git a/scripts/split-include.c b/scripts/split-include.c
deleted file mode 100644
index 624a0d62b..000000000
--- a/scripts/split-include.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * split-include.c
- *
- * Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
- * This is a C version of syncdep.pl by Werner Almesberger.
- *
- * This program takes autoconf.h as input and outputs a directory full
- * of one-line include files, merging onto the old values.
- *
- * Think of the configuration options as key-value pairs. Then there
- * are five cases:
- *
- * key old value new value action
- *
- * KEY-1 VALUE-1 VALUE-1 leave file alone
- * KEY-2 VALUE-2A VALUE-2B write VALUE-2B into file
- * KEY-3 - VALUE-3 write VALUE-3 into file
- * KEY-4 VALUE-4 - write an empty file
- * KEY-5 (empty) - leave old empty file alone
- */
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#define ERROR_EXIT(strExit) \
- { \
- const int errnoSave = errno; \
- fprintf(stderr, "%s: ", str_my_name); \
- errno = errnoSave; \
- perror((strExit)); \
- exit(1); \
- }
-
-
-
-int main(int argc, const char * argv [])
-{
- const char * str_my_name;
- const char * str_file_autoconf;
- const char * str_dir_config;
-
- FILE * fp_config;
- FILE * fp_target;
- FILE * fp_find;
-
- int buffer_size;
-
- char * line;
- char * old_line;
- char * list_target;
- char * ptarget;
-
- struct stat stat_buf;
-
- /* Check arg count. */
- if (argc != 3)
- {
- fprintf(stderr, "%s: wrong number of arguments.\n", argv[0]);
- exit(1);
- }
-
- str_my_name = argv[0];
- str_file_autoconf = argv[1];
- str_dir_config = argv[2];
-
- /* Find a buffer size. */
- if (stat(str_file_autoconf, &stat_buf) != 0)
- ERROR_EXIT(str_file_autoconf);
- buffer_size = 2 * stat_buf.st_size + 4096;
-
- /* Allocate buffers. */
- if ( (line = malloc(buffer_size)) == NULL
- || (old_line = malloc(buffer_size)) == NULL
- || (list_target = malloc(buffer_size)) == NULL )
- ERROR_EXIT(str_file_autoconf);
-
- /* Open autoconfig file. */
- if ((fp_config = fopen(str_file_autoconf, "r")) == NULL)
- ERROR_EXIT(str_file_autoconf);
-
- /* Make output directory if needed. */
- if (stat(str_dir_config, &stat_buf) != 0)
- {
- if (mkdir(str_dir_config, 0755) != 0)
- ERROR_EXIT(str_dir_config);
- }
-
- /* Change to output directory. */
- if (chdir(str_dir_config) != 0)
- ERROR_EXIT(str_dir_config);
-
- /* Put initial separator into target list. */
- ptarget = list_target;
- *ptarget++ = '\n';
-
- /* Read config lines. */
- while (fgets(line, buffer_size, fp_config))
- {
- const char * str_config;
- int is_same;
- int itarget;
-
- if (line[0] != '#')
- continue;
- if ((str_config = strstr(line, "CONFIG_")) == NULL)
- continue;
-
- /* Make the output file name. */
- str_config += sizeof("CONFIG_") - 1;
- for (itarget = 0; !isspace(str_config[itarget]); itarget++)
- {
- char c = str_config[itarget];
- if (isupper(c)) c = tolower(c);
- if (c == '_') c = '/';
- ptarget[itarget] = c;
- }
- ptarget[itarget++] = '.';
- ptarget[itarget++] = 'h';
- ptarget[itarget++] = '\0';
-
- /* Check for existing file. */
- is_same = 0;
- if ((fp_target = fopen(ptarget, "r")) != NULL)
- {
- fgets(old_line, buffer_size, fp_target);
- if (fclose(fp_target) != 0)
- ERROR_EXIT(ptarget);
- if (!strcmp(line, old_line))
- is_same = 1;
- }
-
- if (!is_same)
- {
- /* Auto-create directories. */
- int islash;
- for (islash = 0; islash < itarget; islash++)
- {
- if (ptarget[islash] == '/')
- {
- ptarget[islash] = '\0';
- if (stat(ptarget, &stat_buf) != 0
- && mkdir(ptarget, 0755) != 0)
- ERROR_EXIT( ptarget );
- ptarget[islash] = '/';
- }
- }
-
- /* Write the file. */
- if ((fp_target = fopen(ptarget, "w" )) == NULL)
- ERROR_EXIT(ptarget);
- fputs(line, fp_target);
- if (ferror(fp_target) || fclose(fp_target) != 0)
- ERROR_EXIT(ptarget);
- }
-
- /* Update target list */
- ptarget += itarget;
- *(ptarget-1) = '\n';
- }
-
- /*
- * Close autoconfig file.
- * Terminate the target list.
- */
- if (fclose(fp_config) != 0)
- ERROR_EXIT(str_file_autoconf);
- *ptarget = '\0';
-
- /*
- * Fix up existing files which have no new value.
- * This is Case 4 and Case 5.
- *
- * I re-read the tree and filter it against list_target.
- * This is crude. But it avoids data copies. Also, list_target
- * is compact and contiguous, so it easily fits into cache.
- *
- * Notice that list_target contains strings separated by \n,
- * with a \n before the first string and after the last.
- * fgets gives the incoming names a terminating \n.
- * So by having an initial \n, strstr will find exact matches.
- */
-
- fp_find = popen("find * -type f -name \"*.h\" -print", "r");
- if (fp_find == 0)
- ERROR_EXIT( "find" );
-
- line[0] = '\n';
- while (fgets(line+1, buffer_size, fp_find))
- {
- if (strstr(list_target, line) == NULL)
- {
- /*
- * This is an old file with no CONFIG_* flag in autoconf.h.
- */
-
- /* First strip the \n. */
- line[strlen(line)-1] = '\0';
-
- /* Grab size. */
- if (stat(line+1, &stat_buf) != 0)
- ERROR_EXIT(line);
-
- /* If file is not empty, make it empty and give it a fresh date. */
- if (stat_buf.st_size != 0)
- {
- if ((fp_target = fopen(line+1, "w")) == NULL)
- ERROR_EXIT(line);
- if (fclose(fp_target) != 0)
- ERROR_EXIT(line);
- }
- }
- }
-
- if (pclose(fp_find) != 0)
- ERROR_EXIT("find");
-
- return 0;
-}