diff --git a/walk/walk.c b/walk/walk.c index 3abfbe9..af3f3e1 100644 --- a/walk/walk.c +++ b/walk/walk.c @@ -12,34 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include /* errno */ #include -#include +#include /* fprintf(3), stderr, stdout */ #include -#include +#include /* strerror(3) */ +#include /* EX_USAGE */ #include #include -static const char SHORT_USAGE[] = "Usage: walk [OPTION...] [DIRECTORY...]\n"; +static char *dot = "."; /* current directory */ -static const char HELP[] = - "Recursively walk the specified directories (or current directory, if none is\n" - "specified.\n\n" - " -0, --null separate filenames by a null character\n" - " --help display this help and exit\n"; +static char *nul_terminator = "\0"; +static char *newl_terminator = "\n"; +static char *asv_terminator = "\037"; /* ASCII UNIT_SEPARATOR */ -static const char ASK_FOR_HELP[] = "Try 'walk --help' for more information.\n"; - -static const char *const JUST_CURRENT_DIRECTORY[] = {".", NULL}; - -// Like readdir(3), but resets errno(3) before the call to make it easy to -// check. -static struct dirent *readdir2(DIR *const dirp) -{ - errno = 0; - return readdir(dirp); -} +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) @@ -69,19 +58,22 @@ static void put_filename(const char *filename, bool null_terminate) // 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(const char dirname[], bool null_terminate) -{ - DIR *const dir = opendir(dirname); - if (!dir) { - if (errno != ENOTDIR) { - perror(dirname); - return 1; - } - return 2; +static int +walk(char *dirname, bool null_terminate){ + DIR dir; + struct dirent *f; + char *filename; + int retval; + + if((dir = opendir(dirname)) == NULL){ + fprintf(stdout, "%s: %s: %s\n", + argv0, dirname, strerror(errno)); + return 1 + (errno == ENOTDIR); } - int r = 0; - char *filename = NULL; - for (const struct dirent *f = readdir2(dir); f; f = readdir2(dir)) { + + errno = 0; + retval = 0; + while((f = readdir(dir)) != NULL){ if (strcmp(f->d_name, ".") == 0 || strcmp(f->d_name, "..") == 0) continue; filename = xrealloc( @@ -93,55 +85,54 @@ static int walk(const char dirname[], bool null_terminate) // 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) - r = 1; + retval = 1; } if (errno) { // from readdir perror(dirname); - r = 1; + retval = 1; } free(filename); if (closedir(dir)) { perror(dirname); - r = 1; + retval = 1; } - return r; + return retval; } -int main(const int argc, char *const argv[]) -{ - static const struct option long_options[] = { - {"help", no_argument, NULL, 'h'}, - {"null", no_argument, NULL, '0'}, - {NULL, 0, NULL, 0}, - }; - bool null_terminate = false; - while (true) { - const int c = getopt_long(argc, argv, "0", long_options, NULL); - if (c == -1) break; - switch (c) { - case 'h': - fputs(SHORT_USAGE, stdout); - fputs(HELP, stdout); - return 0; - case '0': - null_terminate = true; - break; - case '?': - fputs(ASK_FOR_HELP, stderr); - return 1; - default: - fputs("Internal error; please report.\n", stderr); - return 1; +int usage(char *argv0){ + fprintf(stderr, "Usage: %s (-0n) (-d [delimiter]) (-l [max levels])" + " (directories...)\n", argv0); + return EX_USAGE; +} + +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){ + case '0': terminator = nul_terminator; break; + case 'd': terminator = optarg; break; + case 'l': /* TODO */ break; + case 'n': terminator = newl_terminator; break; + default: return usage(argv[0]); + } + 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); } - } - int r = 0; - const char *const *const dirs = argc == optind - ? JUST_CURRENT_DIRECTORY - : (const char *const *)argv + optind; - for (int i = 0; dirs[i]; ++i) { - put_filename(dirs[i], null_terminate); - r |= walk(dirs[i], null_terminate); - } - return r; + return retval; }