From 2ffb4dcd0e788a68b9089f02838f4bba0b79dd2c Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Thu, 11 Jul 2024 16:03:13 -0400 Subject: whichbas: initial support for multiple files on the command line. --- whichbas.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/whichbas.c b/whichbas.c index aeb18f6..80ea507 100644 --- a/whichbas.c +++ b/whichbas.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "bas.h" @@ -42,17 +43,84 @@ unsigned char last_op_tok; unsigned short last_cmd_pos; void print_help(void) { - printf("Usage: %s [-v] [-k] [-s] \n", self); + printf("Usage: %s [-v] [-h] [-k] [-s] ...\n", self); +} + +int child_errs = 0; + +/* return true if the child ran and returned 0 (success) */ +int spawn_child(const char **args) { + pid_t pid, status; + int wstatus; + + pid = fork(); + if(pid == -1) { + perror("fork()"); + die("Can't spawn child process"); + } else if(pid) { + /* we are the parent */ + status = waitpid(pid, &wstatus, 0); + if(status < 0) { + perror("waitpid()"); + die("Child process went south"); + } + if(! (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) ) { + child_errs++; + return 0; + } + } else { + /* we are the child */ + if(execv(args[0], (char * const *)args) < 0) { + perror("exec()"); + exit(1); + } + } + + return 1; +} + +/* this is not the ideal way to handle multiple files. it forks a new + process for each one. however, I embedded a bunch of die() calls + in bas.c, thinking I'd never use some of the functions more than once + in the same run. what I get for trying to KISS... */ +void multiple_files(const char *argv0, char **list) { + const char *args[5]; /* 5 because eventually we include -k and/or -v */ + int kidstat; + + /* this isn't needed for things to work, but if I write buggy code, + it avoids a forkbomb. */ + setenv("WHICHBAS_MULTI_PARANOIA", "1", 1); + + args[0] = argv0; + args[2] = NULL; + + while(*list) { + args[1] = *list; + printf("%s:\t", *list); + fflush(stdout); + kidstat = spawn_child(args); + if(!kidstat) puts("(detection failed)"); + fflush(stdout); + list++; + } + + if(child_errs) { + fprintf(stderr, "%s: exiting with error status because some files failed.\n", self); + exit(1); + } else { + exit(0); + } } void parse_args(int argc, char **argv) { int opt; - while( (opt = getopt(argc, argv, "vks")) != -1) { + while( (opt = getopt(argc, argv, "vksh")) != -1) { switch(opt) { case 'v': verbose = 1; break; case 'k': keep_going = verbose = 1; break; case 's': script_mode = 1; break; + case 'h': print_help(); exit(0); default: print_help(); exit(1); @@ -61,10 +129,18 @@ void parse_args(int argc, char **argv) { if(optind >= argc) die("No input file given (and stdin not supported)."); - else + + if(optind == argc - 1) { /* got one filename only */ open_input(argv[optind]); - if(input_file == stdin) - die("Reading from standard input not supported."); + if(input_file == stdin) + die("Reading from standard input not supported."); + } else { /* got multiple filenames */ + if(keep_going || verbose || script_mode) + die("-k, -v, -s not supported with multiple filenames (yet?)"); + if(getenv("WHICHBAS_MULTI_PARANOIA")) + die("BUG: multiple_files() recursion!"); + multiple_files(argv[0], argv + optind); + } } /* don't need this. -- cgit v1.2.3