diff --git a/walk/walk.c b/walk/walk.c index af3f3e1..47b0aa2 100644 --- a/walk/walk.c +++ b/walk/walk.c @@ -12,57 +12,42 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include /* closedir(3), opendir(3), readdir(3), DIR */ #include /* errno */ -#include -#include /* fprintf(3), stderr, stdout */ -#include +#include /* fprintf(3), perror(3), stderr, stdout */ +#include /* realloc(3) */ #include /* strerror(3) */ -#include /* EX_USAGE */ +#include /* EX_OSERR, EX_USAGE */ -#include #include -static char *dot = "."; /* current directory */ +static char *dot[] = {".", NULL}; /* default (argc<2) */ static char *nul_terminator = "\0"; static char *newl_terminator = "\n"; static char *asv_terminator = "\037"; /* ASCII UNIT_SEPARATOR */ +static char *terminator; + +static int +fnprint(char *fn){ + if(terminator == nul_terminator) + return fprintf(stdout, "%s%c", fn, nul_terminator[0]); + else + return fprintf(stdout, "%s%s", fn, terminator); +} static char *argv0; -// Like realloc(3), but exits the binary in an out-of-memory situation. -static void *xrealloc(void *ptr, const size_t size) -{ - if (!(ptr = realloc(ptr, size))) { - perror("realloc"); - exit(EXIT_FAILURE); - } - return ptr; -} - -static void strcpy3(char *dest, const char *s1, const char *s2, const char *s3) -{ - stpcpy(stpcpy(stpcpy(dest, s1), s2), s3); -} - -static void put_filename(const char *filename, bool null_terminate) -{ - if (null_terminate) { - fputs(filename, stdout); - fputc(0, stdout); - } else { - puts(filename); - } -} - // Walks the directory named dirname, printing the names of all files it // contains (but not the name of the directory itself). Returns 2 if dirname is // not a directory and 1 if another error occurs. static int -walk(char *dirname, bool null_terminate){ +walk(char *dirname){ DIR dir; struct dirent *f; - char *filename; + static struct { size_t a; size_t s; char *p; } filename = {0, 0, NULL}; + size_t l; + char *np; int retval; if((dir = opendir(dirname)) == NULL){ @@ -74,43 +59,42 @@ walk(char *dirname, bool null_terminate){ errno = 0; retval = 0; while((f = readdir(dir)) != NULL){ - if (strcmp(f->d_name, ".") == 0 || strcmp(f->d_name, "..") == 0) + if(strcmp(f->d_name, ".") == 0 || strcmp(f->d_name, "..") == 0) continue; - filename = xrealloc( - filename, strlen(dirname) + 1 + strlen(f->d_name) + 1); - strcpy3(filename, dirname, "/", f->d_name); - // TODO(bbaren@google.com): Emulate Plan 9's cleanname(3). - put_filename(filename, null_terminate); - // Walk the file if we can successfully open it as a directory. - // Don't worry about it if it's not one (walk(filename) == 2). + if((l = strlen(dirname) + 1 + strlen(f->d_name) + 1) + > filename.a){ + if((np = realloc(filename.p, l)) == NULL){ + perror(argv0); + return EX_OSERR; + }else{ + filename.a = l; + filename.p = np; /* would you look at that */ + } + } + stpcpy(stpcpy(stpcpy(filename.p, dirname), "/"), f->d_name); + /* TODO(bbaren@google.com): Emulate Plan 9's cleanname(3). */ + fnprint(filename.p); + /* Walk the file if we can successfully open it as a directory. + * Don't worry about it if it's not one (walk(filename) == 2). */ if ((f->d_type == DT_DIR || f->d_type == DT_UNKNOWN) - && walk(filename, null_terminate) == 1) + && walk(filename.p) == 1) retval = 1; } - if (errno) { // from readdir - perror(dirname); + if(errno != 0 || closedir(dir) != NULL){ + fprintf(stderr, "%s: %s: %s\n", + argv0, dirname, strerror(errno)); retval = 1; } - free(filename); - if (closedir(dir)) { - perror(dirname); - retval = 1; - } - return retval; -} -int usage(char *argv0){ - fprintf(stderr, "Usage: %s (-0n) (-d [delimiter]) (-l [max levels])" - " (directories...)\n", argv0); - return EX_USAGE; + return retval; } int main(int argc, char *argv[]){ int c; - char *terminator; int retval; argv0 = argv[0]; + if(argc > 0){ while((c = getopt(argc, argv, "0d:l:n")) != -1) switch(c){ @@ -118,21 +102,25 @@ int main(int argc, char *argv[]){ case 'd': terminator = optarg; break; case 'l': /* TODO */ break; case 'n': terminator = newl_terminator; break; - default: return usage(argv[0]); + default: + fprintf(stderr, + "Usage: %s (-0n)" + " (-d [delimiter]) (-l [max levels])" + " (directories...)\n", argv[0]); + return EX_USAGE; } argv += optind; } retval = 0; - if(*argv == NULL){ - put_filename(dot, terminator == nul_terminator); - retval |= walk(dot, terminator == nul_terminator); - }else - for(argv += optind; *argv != NULL; ++argv){ - put_filename(*argv, terminator == nul_terminator); - retval |= walk(*argv, terminator == nul_terminator); - } + if(*argv == NULL) + argv = dot; + + while(*argv != NULL){ + fnprint(*argv); + retval |= walk(*(argv++)); + } return retval; }