From 33d44db8f48fc024999b4697e8778ed716a1d9ae Mon Sep 17 00:00:00 2001 From: Jakob Kaivo Date: Mon, 30 Mar 2020 11:59:37 -0400 Subject: use predictably resettable getopt() --- Makefile | 4 +-- builtins.c | 4 +-- getopt.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sh.h | 2 ++ 4 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 getopt.c diff --git a/Makefile b/Makefile index 12f6a23..15f5688 100644 --- a/Makefile +++ b/Makefile @@ -12,14 +12,14 @@ SOURCES=alias.c bg.c builtins.c cd.c command.c false.c fc.c fg.c getopts.c \ ulimit.c umask.c wait.c \ dot.c eval.c exec.c exit.c export.c readonly.c shift.c times.c trap.c \ unset.c \ - interactive.c parse.c init.c + interactive.c parse.c init.c getopt.c HEADERS=sh.h OBJECTS=alias.o bg.o builtins.o cd.o command.o false.o fc.o fg.o getopts.o \ hash.o jobs.o kill.o newgrp.o pwd.o read.o set.o main.o true.o type.o \ ulimit.o umask.o wait.o \ dot.o eval.o exec.o exit.o export.o readonly.o shift.o times.o trap.o \ unset.o \ - interactive.o parse.o init.o \ + interactive.o parse.o init.o getopt.o \ sh.tab.o sh.yy.o BUILTINS=alias bg cd command false fc fg getopts jobs kill newgrp pwd read \ true ulimit umask unalias wait diff --git a/builtins.c b/builtins.c index b98d16e..da39beb 100644 --- a/builtins.c +++ b/builtins.c @@ -143,9 +143,7 @@ int sh_builtin(int argc, char *argv[]) } } - optind = 1; - opterr = 1; - optarg = NULL; + optind = 0; return m(argc, argv); } diff --git a/getopt.c b/getopt.c new file mode 100644 index 0000000..5f6baaa --- /dev/null +++ b/getopt.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +int sh_getopt(int argc, char * const argv[], const char *optstring) +{ + static int optchar = 0; + char *option = NULL; + + if (optind == 0) { + optind = 1; + optchar = 0; + } + + if (argv[optind] == NULL) { + return -1; + } + + if (argv[optind][0] != '-') { + return -1; + } + + if (!strcmp(argv[optind], "-")) { + return -1; + } + + if (!strcmp(argv[optind], "--")) { + optind++; + optchar = 0; + return -1; + } + + if (optchar == 0 && argv[optind][optchar] != '-') { + return -1; + } + + optchar++; + + if (argv[optind][optchar] == '\0') { + optind++; + optchar = 0; + return getopt(argc, argv, optstring); + } + + option = strchr(optstring, argv[optind][optchar]); + + if (!option) { + optopt = argv[optind][optchar]; + if (opterr != 0 && optstring[0] != ':') { + fprintf(stderr, "%s: invalid option -%c\n", argv[0], + optopt); + } + return '?'; + } + + if (option[1] != ':') { + return *option; + } + + if (argv[optind][optchar + 1] == '\0') { + optarg = argv[++optind]; + } else { + optarg = argv[optind] + optchar + 1; + } + + optind++; + if (optarg == NULL) { + optopt = *option; + if (opterr != 0 && optstring[0] != ':') { + fprintf(stderr, "%s: missing argument to option -%c\n", + argv[0], optopt); + } + return optstring[0] == ':' ? ':' : '?'; + } + + optchar = 0; + return *option; +} + +/* +POSIX(2) +*/ diff --git a/sh.h b/sh.h index 477226d..3479baa 100644 --- a/sh.h +++ b/sh.h @@ -70,4 +70,6 @@ void sh_trap(int trapno); int yyparse(void); +#define getopt sh_getopt + #endif -- cgit v1.2.1