From ffbbc86a7b8dd5a6760c3c1a43e50255e1302f27 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Wed, 15 Mar 2017 08:43:07 -0400 Subject: [PATCH] switched option parseing to OPTBEGIN macro and deleted getop.c --- Makefile | 2 +- builtins.c | 65 --------------------------- getopt.c | 51 ---------------------- glom.c | 2 +- input.c | 2 +- main.c | 64 ++++++++++----------------- rc.h | 126 +++++++++++++++++++++++++++++++++++++++++++---------- wait.c | 2 +- 8 files changed, 131 insertions(+), 183 deletions(-) delete mode 100644 getopt.c diff --git a/Makefile b/Makefile index b9d28de..f9df459 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = c99 CPPFLAGS = -I. CCCMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS) -RCOBJS = builtins.o except.o exec.o fn.o footobar.o getopt.o glob.o glom.o hash.o heredoc.o input.o lex.o list.o main.o match.o nalloc.o open.o y.tab.o print.o redir.o signal.o status.o tree.o utils.o var.o wait.o walk.o which.o sigmsgs.o system.o +RCOBJS = builtins.o except.o exec.o fn.o footobar.o glob.o glom.o hash.o heredoc.o input.o lex.o list.o main.o match.o nalloc.o open.o y.tab.o print.o redir.o signal.o status.o tree.o utils.o var.o wait.o walk.o which.o sigmsgs.o system.o all: rc diff --git a/builtins.c b/builtins.c index 5349c22..9c56e40 100644 --- a/builtins.c +++ b/builtins.c @@ -30,7 +30,6 @@ static struct { { b_shift, "shift" }, { b_umask, "umask" }, { b_wait, "wait" }, - { b_whatis, "whatis" }, { b_dot, "." }, }; @@ -261,70 +260,6 @@ static bool issig(char *s) { return FALSE; } -static void b_whatis(char **av) { - bool ess, eff, vee, pee, bee; - bool f, found; - int i, ac, c; - List *s; - Node *n; - char *e; - for (rc_optind = ac = 0; av[ac] != NULL; ac++) - ; /* count the arguments for getopt */ - ess = eff = vee = pee = bee = FALSE; - while ((c = rc_getopt(ac, av, "sfvpb")) != -1) - switch (c) { - default: set(FALSE); return; - case 's': ess = TRUE; break; - case 'f': eff = TRUE; break; - case 'v': vee = TRUE; break; - case 'p': pee = TRUE; break; - case 'b': bee = TRUE; break; - } - av += rc_optind; - if (*av == NULL) { - if (vee|eff) - whatare_all_vars(eff, vee); - if (ess) - whatare_all_signals(); - if (bee) - for (i = 0; i < arraysize(builtins); i++) - fprint(1, "builtin %s\n", builtins[i].name); - if (pee) - fprint(2, "whatis -p: must specify argument\n"); - if (show(FALSE)) /* no options? */ - whatare_all_vars(TRUE, TRUE); - set(TRUE); - return; - } - found = TRUE; - for (i = 0; av[i] != NULL; i++) { - f = FALSE; - errno = ENOENT; - if (show(vee) && (s = varlookup(av[i])) != NULL) { - f = TRUE; - prettyprint_var(1, av[i], s); - } - if (((show(ess)&&issig(av[i])) || show(eff)) && (n = fnlookup(av[i])) != NULL) { - f = TRUE; - prettyprint_fn(1, av[i], n); - } else if (show(bee) && isbuiltin(av[i]) != NULL) { - f = TRUE; - fprint(1, "builtin %s\n", av[i]); - } else if (show(pee) && (e = which(av[i], FALSE)) != NULL) { - f = TRUE; - fprint(1, "%S\n", e); - } - if (!f) { - found = FALSE; - if (errno != ENOENT) - uerror(av[i]); - else - fprint(2, "%s not found\n", av[i]); - } - } - set(found); -} - /* push a string to be eval'ed onto the input stack. evaluate it */ static void b_eval(char **av) { diff --git a/getopt.c b/getopt.c deleted file mode 100644 index 3c54f53..0000000 --- a/getopt.c +++ /dev/null @@ -1,51 +0,0 @@ -#include "rc.h" - -int rc_opterr = 1; -int rc_optind = 1; -int rc_optopt; -char *rc_optarg; - -/* getopt routine courtesy of David Sanderson */ - -extern int rc_getopt(int argc, char **argv, char *opts) { - static int sp = 1; - int c; - char *cp; - if (rc_optind == 0) /* reset rc_getopt() */ - rc_optind = sp = 1; - if (sp == 1) { - if (rc_optind >= argc || argv[rc_optind][0] != '-' || argv[rc_optind][1] == '\0') { - return -1; - } else if (strcmp(argv[rc_optind], "--") == 0) { - rc_optind++; - return -1; - } - } - rc_optopt = c = argv[rc_optind][sp]; - if (c == ':' || (cp=strchr(opts, c)) == 0) { - fprint(2, "%s: bad option: -%c\n", argv[0], c); - if (argv[rc_optind][++sp] == '\0') { - rc_optind++; - sp = 1; - } - return '?'; - } - if (*++cp == ':') { - if (argv[rc_optind][sp+1] != '\0') { - rc_optarg = &argv[rc_optind++][sp+1]; - } else if (++rc_optind >= argc) { - fprint(2, "%s: option requires an argument -- %c\n", argv[0], c); - sp = 1; - return '?'; - } else - rc_optarg = argv[rc_optind++]; - sp = 1; - } else { - if (argv[rc_optind][++sp] == '\0') { - sp = 1; - rc_optind++; - } - rc_optarg = NULL; - } - return c; -} diff --git a/glom.c b/glom.c index 86d3cf1..1d4ebe1 100644 --- a/glom.c +++ b/glom.c @@ -200,7 +200,7 @@ static List *bqinput(List *ifs, int fd) { end = &buf[m]; remain = bufsize - m; } - if ((n = rc_read(fd, end, remain)) <= 0) { + if ((n = read(fd, end, remain)) <= 0) { if (n == 0) /* break */ break; else if (errno == EINTR) diff --git a/input.c b/input.c index 697a041..ddd6c03 100644 --- a/input.c +++ b/input.c @@ -93,7 +93,7 @@ static int fdgchar() { if (chars_out >= chars_in) { /* replenish empty buffer */ ssize_t r; do { - r = rc_read(istack->fd, inbuf, BUFSIZE); + r = read(istack->fd, inbuf, BUFSIZE); sigchk(); if (r == -1) switch (errno) { diff --git a/main.c b/main.c index 72f309c..aac9ddc 100644 --- a/main.c +++ b/main.c @@ -2,6 +2,7 @@ #include "rc.h" +char* ARGV0; bool dashdee, dashee, dashvee, dashex, dasheye, dashen, dashpee, interactive; pid_t rc_pid; @@ -11,58 +12,41 @@ static bool dashEYE, dashell, dashoh, dashess; static void assigndefault(char *,...); static void checkfd(int, enum redirtype); +void usage(void) { + printf("Usage: %s [OPTION...] [FILE [ARG...]]\n", ARGV0); +} + extern int main(int argc, char *argv[], char *envp[]) { char *dashsee[2], *dollarzero, *null[1]; - int c; initprint(); dashsee[0] = dashsee[1] = NULL; dollarzero = argv[0]; rc_pid = getpid(); - dashell = (*argv[0] == '-'); /* Unix tradition */ - while ((c = rc_getopt(argc, argv, "c:deiIlnopsvx")) != -1) - switch (c) { - case 'c': - dashsee[0] = rc_optarg; - goto quitopts; - case 'd': - dashdee = TRUE; - break; - case 'e': - dashee = TRUE; + dashell = (*argv[0] == '-'); /* login shell, per unix tradition */ + + OPTBEGIN { + case 'd': dashdee = TRUE; break; + case 'e': dashee = TRUE; break; + case 'l': dashell = TRUE; break; + case 'n': dashen = TRUE; break; + case 'o': dashoh = TRUE; break; + case 'p': dashpee = TRUE; break; + case 's': dashess = TRUE; break; + case 'v': dashvee = TRUE; break; + case 'x': dashex = TRUE; break; + case 'i': + dasheye = TRUE; + interactive = TRUE; break; case 'I': dashEYE = TRUE; interactive = FALSE; break; - case 'i': - dasheye = interactive = TRUE; - break; - case 'l': - dashell = TRUE; - break; - case 'n': - dashen = TRUE; - break; - case 'o': - dashoh = TRUE; - break; - case 'p': - dashpee = TRUE; - break; - case 's': - dashess = TRUE; - break; - case 'v': - dashvee = TRUE; - break; - case 'x': - dashex = TRUE; + case 'c': + dashsee[0] = EOPTARG(usage()); break; - case '?': - exit(1); - } -quitopts: - argv += rc_optind; + } OPTEND; + /* use isatty() iff neither -i nor -I is set, and iff the input is not from a script or -c flags */ if (!dasheye && !dashEYE && dashsee[0] == NULL && (dashess || *argv == NULL)) interactive = isatty(0); diff --git a/rc.h b/rc.h index a3f3f22..29f51ae 100644 --- a/rc.h +++ b/rc.h @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -83,6 +85,8 @@ struct Limit { #ifdef __DARWIN_NSIG #define NSIG __DARWIN_NSIG +#elif _NSIG + #define NSIG _NSIG #endif typedef struct { @@ -225,10 +229,6 @@ enum { }; /* macros */ -#define EOF (-1) -#ifndef NULL -#define NULL 0 -#endif #define a2u(x) n2u(x, 10) #define o2u(x) n2u(x, 8) #define arraysize(a) ((int)(sizeof(a)/sizeof(*a))) @@ -402,7 +402,6 @@ extern struct Jbwrap rl_buf; /* redir.c */ extern void doredirs(void); - /* signal.c */ extern void initsignal(void); extern void catcher(int); @@ -411,7 +410,6 @@ extern void (*rc_signal(int, void (*)(int)))(int); extern void (*sys_signal(int, void (*)(int)))(int); extern void (*sighandlers[])(int); - /* status.c */ extern int istrue(void); extern int getstatus(void); @@ -423,23 +421,9 @@ extern void statprint(pid_t, int); extern void ssetstatus(char **); extern char *strstatus(int s); - /* system.c or system-bsd.c */ extern void writeall(int, char *, size_t); -#if HAVE_RESTARTABLE_SYSCALLS -extern int rc_read(int, char *, size_t); -extern pid_t rc_wait(int *); -extern Jbwrap slowbuf; -extern volatile sig_atomic_t slow; - -#else /* HAVE_RESTARTABLE_SYSCALLS */ - -#define rc_read read -#define rc_wait wait -#endif /* HAVE_RESTARTABLE_SYSCALLS */ - - /* tree.c */ extern Node *mk(int /*nodetype*/,...); extern Node *treecpy(Node *, void *(*)(size_t)); @@ -483,9 +467,6 @@ extern void popinput(void); extern int gchar(void); extern void ugchar(int); -/* $TERM or $TERMCAP has changed */ -extern void termchange(void); - /* parse a function from the environment */ extern Node *parseline(char *); @@ -505,3 +486,102 @@ extern void closefds(void); extern int lastchar; +/* Option Parsing + * + * This following macros implement a simple POSIX-style option parsing strategy. + * They are heavily influenced and inspired by the arg.h file from suckless.org + * (http://git.suckless.org/libsl/tree/arg.h). That file is in turn inspired by + * the corresponding macros defined in plan9. + * + * The interface assumes that the main function will have the following + * prototype: + * + * int main(int argc, char** argv); + * + * An example usage of the interface would look something like the follwoing: + * + * char* ARGV0; + * int main(int argc, char** argv) { + * OPTBEGIN { + * case 'a': printf("Simple option\n"); break; + * case 'b': printf("Option with arg: %s\n", OPTARG()); break; + * default: printf("Unknown option!\n"); + * } OPTEND; + * return 0; + * } + */ + +/* This variable contains the value of argv[0] so that it can be referenced + * again once the option parsing is done. This variable must be defined by the + * program. + * + * NOTE: Ensure that you define this variable with external linkage (i.e. not + * static) */ +extern char* ARGV0; + +/* This is a helper function used by the following macros to parse the next + * option from the command line. */ +static inline char* _getopt_(int* p_argc, char*** p_argv) { + if (!(*p_argv)[0][1] && !(*p_argv)[1]) { + return (char*)0; + } else if ((*p_argv)[0][1]) { + return &(*p_argv)[0][1]; + } else { + *p_argv = *p_argv + 1; + *p_argc = *p_argc - 1; + return (*p_argv)[0]; + } +} + +/* This macro is almost identical to the ARGBEGIN macro from suckless.org. If + * it ain't broke, don't fix it. */ +#define OPTBEGIN \ + for ( \ + ARGV0 = *argv, argc--, argv++; \ + argv[0] && argv[0][1] && argv[0][0] == '-'; \ + argc--, argv++ \ + ) { \ + int brk_; char argc_ , **argv_, *optarg_; \ + if (argv[0][1] == '-' && !argv[0][2]) { \ + argv++, argc--; break; \ + } \ + for (brk_=0, argv[0]++, argv_=argv; argv[0][0] && !brk_; argv[0]++) { \ + if (argv_ != argv) break; \ + argc_ = argv[0][0]; \ + switch (argc_) + +/* Terminate the option parsing. */ +#define OPTEND }} + +/* Get the current option character */ +#define OPTC() (argc_) + +/* Get an argument from the command line and return it as a string. If no + * argument is available, this macro returns NULL */ +#define OPTARG() \ + (optarg_ = _getopt_(&argc,&argv), brk_ = (optarg_!=0), optarg_) + +/* Get an argument from the command line and return it as a string. If no + * argument is available, this macro executes the provided code. If that code + * returns, then abort is called. */ +#define EOPTARG(code) \ + (optarg_ = _getopt_(&argc,&argv), \ + (!optarg_ ? ((code), abort(), (char*)0) : (brk_ = 1, optarg_))) + +/* Helper macro to recognize number options */ +#define OPTNUM \ + case '0': \ + case '1': \ + case '2': \ + case '3': \ + case '4': \ + case '5': \ + case '6': \ + case '7': \ + case '8': \ + case '9' + +/* Helper macro to recognize "long" options ala GNU style. */ +#define OPTLONG \ + case '-' + diff --git a/wait.c b/wait.c index 06d6271..91679b6 100644 --- a/wait.c +++ b/wait.c @@ -64,7 +64,7 @@ extern pid_t rc_wait4(pid_t pid, int *stat, bool nointr) { int ret; Pid *q; - ret = rc_wait(stat); + ret = wait(stat); if (ret < 0) { if (errno == ECHILD) -- 2.49.0