diff --git a/src/cmd/ksh93/bltins/exit.c b/src/cmd/ksh93/bltins/exit.c index 9a2e75013281..60b034af5e39 100644 --- a/src/cmd/ksh93/bltins/exit.c +++ b/src/cmd/ksh93/bltins/exit.c @@ -19,72 +19,61 @@ ***********************************************************************/ #include "config_ast.h" // IWYU pragma: keep -#include #include #include -#include "ast.h" #include "builtins.h" #include "defs.h" #include "fault.h" +#include "optget_long.h" #include "shcmd.h" -static const char *short_options = "+:"; -static const struct option long_options[] = { - {"help", no_argument, NULL, 1}, // all builtins support --help +static const char *short_options = "#"; +static const struct optget_option long_options[] = { + {"help", optget_no_arg, NULL, 1}, // all builtins support --help {NULL, 0, NULL, 0}}; // // Builtin `exit` command. See also the return.c module which is similar to this module. // int b_exit(int argc, char *argv[], Shbltin_t *context) { - int n, opt; - char *arg; + int opt; Shell_t *shp = context->shp; char *cmd = argv[0]; - checkpt_t *pp = shp->jmplist; - // We use `getopt_long_only()` rather than `getopt_long()` to facilitate handling negative - // integers that might otherwise look like a flag. - optind = opterr = 0; bool done = false; - while (!done && (opt = getopt_long_only(argc, argv, short_options, long_options, NULL)) != -1) { + optget_ind = 0; + while (!done && (opt = optget_long(argc, argv, short_options, long_options)) != -1) { switch (opt) { + case -2: { + done = true; + optget_ind--; + break; + } case 1: { builtin_print_help(shp, cmd); return 0; } case ':': { - builtin_missing_argument(shp, cmd, argv[optind - 1]); + builtin_missing_argument(shp, cmd, argv[optget_ind - 1]); return 2; } case '?': { - if (!strmatch(argv[optind - 1], "[+-]+([0-9])")) { - builtin_unknown_option(shp, cmd, argv[optind - 1]); - return 2; - } - optind--; - done = true; - break; + builtin_unknown_option(shp, cmd, argv[optget_ind - 1]); + return 2; } default: { abort(); } } } + argv += optget_ind; - pp->mode = SH_JMPEXIT; - argv += optind; - arg = *argv; - n = arg ? (int)strtol(arg, NULL, 10) : shp->oldexit; - if (n < 0 || n == 256 || n > SH_EXITMASK + shp->gd->sigmax) { - n &= ((unsigned int)n) & SH_EXITMASK; - } - - // Return outside of function, dotscript and profile is exit. - if (shp->fn_depth == 0 && shp->dot_depth == 0 && !sh_isstate(shp, SH_PROFILE)) { - pp->mode = SH_JMPEXIT; + int exit_val = *argv ? strtol(*argv, NULL, 10) : shp->oldexit; + if (exit_val < 0 || exit_val == 256 || exit_val > SH_EXITMASK + shp->gd->sigmax) { + exit_val &= ((unsigned int)exit_val) & SH_EXITMASK; } - shp->savexit = n; + shp->jmplist->mode = SH_JMPEXIT; + shp->savexit = exit_val; sh_exit(shp, shp->savexit); __builtin_unreachable(); } diff --git a/src/cmd/ksh93/bltins/hist.c b/src/cmd/ksh93/bltins/hist.c index 6a63530919f3..fc4ea81065dc 100644 --- a/src/cmd/ksh93/bltins/hist.c +++ b/src/cmd/ksh93/bltins/hist.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -39,6 +38,7 @@ #include "history.h" #include "io.h" #include "name.h" +#include "optget_long.h" #include "sfio.h" #include "shcmd.h" #include "stk.h" @@ -48,9 +48,9 @@ static_fn void hist_subst(Shell_t *shp, const char *, int fd, const char *); -static const char *short_options = "+:e:lnprsN:"; -static const struct option long_options[] = { - {"help", no_argument, NULL, 1}, // all builtins support --help +static const char *short_options = "#e:lnprsN:"; +static const struct optget_option long_options[] = { + {"help", optget_no_arg, NULL, 1}, // all builtins support --help {NULL, 0, NULL, 0}}; // @@ -80,18 +80,29 @@ int b_hist(int argc, char *argv[], Shbltin_t *context) { } hp = shp->gd->hist_ptr; - // We use `getopt_long_only()` rather than `getopt_long()` to facilitate handling negative - // integers that might otherwise look like a flag. - optind = opterr = 0; + optget_ind = 0; bool done = false; - while (!done && (opt = getopt_long_only(argc, argv, short_options, long_options, NULL)) != -1) { + while (!done && (opt = optget_long(argc, argv, short_options, long_options)) != -1) { switch (opt) { + case -2: { + if (indx == -1) { + if (optget_num > INT_MAX) { + builtin_usage_error(shp, cmd, "%s: invalid -N value", argv[optget_ind - 1]); + return 2; + } + flag = hist_max(hp) - optget_num - 1; + if (flag < 0) flag = 1; + range[++indx] = flag; + } + done = true; + break; + } case 1: { builtin_print_help(shp, cmd); return 0; } case 'e': { - edit = optarg; + edit = optget_arg; break; } case 'n': { @@ -115,14 +126,13 @@ int b_hist(int argc, char *argv[], Shbltin_t *context) { break; } case 'N': { - if (indx <= 0) { + if (indx == -1) { char *cp; - int64_t n = strton64(optarg, &cp, NULL, 0); + int64_t n = strton64(optget_arg, &cp, NULL, 0); if (*cp || n < 0 || n > INT_MAX) { - builtin_usage_error(shp, cmd, "%s: invalid -N value", optarg); + builtin_usage_error(shp, cmd, "%s: invalid -N value", optget_arg); return 2; } - flag = hist_max(hp) - n - 1; if (flag < 0) flag = 1; range[++indx] = flag; @@ -130,38 +140,19 @@ int b_hist(int argc, char *argv[], Shbltin_t *context) { break; } case ':': { - builtin_missing_argument(shp, cmd, argv[optind - 1]); + builtin_missing_argument(shp, cmd, argv[optget_ind - 1]); return 2; } case '?': { - char *cp; - int64_t n = strton64(argv[optind - 1] + 1, &cp, NULL, 0); - if (*cp) { - // It's not an integer so it's an invalid flag. - builtin_unknown_option(shp, cmd, argv[optind - 1]); - return 2; - } - // Looks like a negative integer which means it's equivalent to -N followed by its - // absolute value. - if (indx <= 0) { - if (*cp || n < 0 || n > INT_MAX) { - builtin_usage_error(shp, cmd, "%s: invalid -N value", optarg); - return 2; - } - - flag = hist_max(hp) - n - 1; - if (flag < 0) flag = 1; - range[++indx] = flag; - } - done = true; - break; + builtin_unknown_option(shp, cmd, argv[optget_ind - 1]); + return 2; } default: { abort(); } } } - argv += optind; + argv += optget_ind; - // TODO: What is the usefulness of this flag ? Shall this be removed in future ? + // TODO: What is the usefulness of this flag? Shall this be removed in future? if (pflag) { hist_cancel(hp); pflag = 0; diff --git a/src/cmd/ksh93/bltins/jobs.c b/src/cmd/ksh93/bltins/jobs.c index 4aadc1f96cb2..8fb59b70e097 100644 --- a/src/cmd/ksh93/bltins/jobs.c +++ b/src/cmd/ksh93/bltins/jobs.c @@ -19,24 +19,23 @@ ***********************************************************************/ #include "config_ast.h" // IWYU pragma: keep -#include #include #include #include -#include "ast.h" #include "builtins.h" #include "defs.h" #include "error.h" #include "jobs.h" +#include "optget_long.h" #include "sfio.h" #include "shcmd.h" #ifdef JOBS -static const char *short_options = "+:lnp"; -static const struct option long_options[] = { - {"help", no_argument, NULL, 1}, // all builtins support --help +static const char *short_options = "lnp"; +static const struct optget_option long_options[] = { + {"help", optget_no_arg, NULL, 1}, // all builtins support --help {NULL, 0, NULL, 0}}; // @@ -48,11 +47,9 @@ int b_jobs(int argc, char *argv[], Shbltin_t *context) { Shell_t *shp = context->shp; char *cmd = argv[0]; - // We use `getopt_long_only()` rather than `getopt_long()` to facilitate handling negative - // integers that might otherwise look like a flag. - optind = opterr = 0; + optget_ind = 0; bool done = false; - while (!done && (opt = getopt_long_only(argc, argv, short_options, long_options, NULL)) != -1) { + while (!done && (opt = optget_long(argc, argv, short_options, long_options)) != -1) { switch (opt) { case 1: { builtin_print_help(shp, cmd); @@ -71,23 +68,18 @@ int b_jobs(int argc, char *argv[], Shbltin_t *context) { break; } case ':': { - builtin_missing_argument(shp, cmd, argv[optind - 1]); + builtin_missing_argument(shp, cmd, argv[optget_ind - 1]); return 2; } case '?': { - if (!strmatch(argv[optind - 1], "[+-]+([0-9])")) { - builtin_unknown_option(shp, cmd, argv[optind - 1]); - return 2; - } - optind--; - done = true; - break; + builtin_unknown_option(shp, cmd, argv[optget_ind - 1]); + return 2; } default: { abort(); } } } - argv += optind; + argv += optget_ind; if (!*argv) argv = NULL; if (job_walk(shp, sfstdout, job_list, flag, argv)) { errormsg(SH_DICT, ERROR_exit(1), e_no_job); diff --git a/src/cmd/ksh93/bltins/kill.c b/src/cmd/ksh93/bltins/kill.c index c7fbac5d0e43..5cd5e2134027 100644 --- a/src/cmd/ksh93/bltins/kill.c +++ b/src/cmd/ksh93/bltins/kill.c @@ -20,16 +20,21 @@ #include "config_ast.h" // IWYU pragma: keep #include -#include +#include #include +#include +#include #include #include +#include "ast.h" +#include "ast_assert.h" #include "builtins.h" #include "defs.h" #include "error.h" #include "fault.h" #include "jobs.h" +#include "optget_long.h" #include "sfio.h" #include "shcmd.h" @@ -37,9 +42,12 @@ #define S_FLAG 2 #define Q_FLAG JOB_QFLAG -static const char *short_options = "+:ln:q:s:L"; -static const struct option long_options[] = { - {"help", no_argument, NULL, 1}, // all builtins support --help +// We don't use the magic "#" short option prefix to enable recognition of numeric flags like "-9". +// That's because we use `optget_long_only()` to handle flags like `-HUP` and that also takes care +// of the "-9" case. +static const char *short_options = "ln:q:s:L"; +static const struct optget_option long_options[] = { + {"help", optget_no_arg, NULL, 1}, // all builtins support --help {NULL, 0, NULL, 0}}; // @@ -54,12 +62,9 @@ int b_kill(int argc, char *argv[], Shbltin_t *context) { Shell_t *shp = context->shp; char *cmd = argv[0]; - // We use `getopt_long_only()` rather than `getopt_long()` to facilitate handling integers that - // might otherwise look like a flag. Or signal names which we want to recognize with a single - // leading hyphen. - optind = opterr = 0; + optget_ind = 0; bool done = false; - while (!done && (opt = getopt_long_only(argc, argv, short_options, long_options, NULL)) != -1) { + while (!done && (opt = optget_long_only(argc, argv, short_options, long_options)) != -1) { switch (opt) { case 1: { builtin_print_help(shp, cmd); @@ -67,9 +72,9 @@ int b_kill(int argc, char *argv[], Shbltin_t *context) { } case 'n': { char *cp; - int64_t n = strton64(optarg, &cp, NULL, 0); - if (*cp || n < 0 || n > INT_MAX) { - errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -n", optarg); + int64_t n = strton64(optget_arg, &cp, NULL, 0); + if (*cp || n < 0 || n > MAX_SIGNUM) { + builtin_usage_error(shp, cmd, "%s: invalid signum", optget_arg); return 2; } sig = n; @@ -78,7 +83,7 @@ int b_kill(int argc, char *argv[], Shbltin_t *context) { } case 's': { flag |= S_FLAG; - signame = optarg; + signame = optget_arg; done = true; break; } @@ -93,9 +98,9 @@ int b_kill(int argc, char *argv[], Shbltin_t *context) { } case 'q': { char *cp; - int64_t n = strton64(optarg, &cp, NULL, 0); + int64_t n = strton64(optget_arg, &cp, NULL, 0); if (*cp || n < 0 || n > INT_MAX) { - errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -q", optarg); + builtin_usage_error(shp, cmd, "%s: invalid value for -q", optget_arg); return 2; } flag |= Q_FLAG; @@ -103,38 +108,32 @@ int b_kill(int argc, char *argv[], Shbltin_t *context) { break; } case ':': { - builtin_missing_argument(shp, cmd, argv[optind - 1]); + builtin_missing_argument(shp, cmd, argv[optget_ind - 1]); return 2; } case '?': { - // See if the flag is an integer that should be treated as a signal number. - char *cp; - int64_t n = strton64(argv[optind - 1] + 1, &cp, NULL, 0); - if (!*cp && n >= 0 && n <= MAX_SIGNUM) { - sig = n; - done = true; - break; - } - // See if the flag is a signal name. - sig = sig_number(shp, argv[optind - 1] + 1); - if (sig >= 0) { - done = true; - break; + // It should be impossible for this to be set to a non-zero value since we're using + // `optget_long_only()`. Which means that any unrecognized short flag is treated as + // a long flag. + assert(!optget_opt); + sig = sig_number(shp, argv[optget_ind - 1] + 1); + if (sig < 0) { // not a recognized signal name or number + builtin_unknown_option(shp, cmd, argv[optget_ind - 1]); + return 2; } - // Nope. It looks like an invalid flag. - builtin_unknown_option(shp, cmd, argv[optind - 1]); - return 2; + done = true; + break; } default: { abort(); } } } - argv += optind; + argv += optget_ind; if (*argv && strcmp(*argv, "--") == 0 && strcmp(*(argv - 1), "--") != 0) argv++; - if (error_info.errors || flag == (L_FLAG | S_FLAG) || (!(*argv) && !(flag & L_FLAG))) { + if (flag == (L_FLAG | S_FLAG) || (!(*argv) && !(flag & L_FLAG))) { shp->sigval = 0; - errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NULL)); - __builtin_unreachable(); + builtin_usage_error(shp, cmd, "illegal combination of options and arguments"); + return 2; } // Just in case we send a kill -9 $$. sfsync(sfstderr); diff --git a/src/cmd/ksh93/bltins/return.c b/src/cmd/ksh93/bltins/return.c index bfe0412578c2..04cd4adb5f23 100644 --- a/src/cmd/ksh93/bltins/return.c +++ b/src/cmd/ksh93/bltins/return.c @@ -19,19 +19,18 @@ ***********************************************************************/ #include "config_ast.h" // IWYU pragma: keep -#include #include #include -#include "ast.h" #include "builtins.h" #include "defs.h" #include "fault.h" +#include "optget_long.h" #include "shcmd.h" -static const char *short_options = "+:"; -static const struct option long_options[] = { - {"help", no_argument, NULL, 1}, // all builtins support --help +static const char *short_options = "#"; +static const struct optget_option long_options[] = { + {"help", optget_no_arg, NULL, 1}, // all builtins support --help {NULL, 0, NULL, 0}}; // @@ -43,36 +42,31 @@ int b_return(int argc, char *argv[], Shbltin_t *context) { char *cmd = argv[0]; checkpt_t *pp = shp->jmplist; - // We use `getopt_long_only()` rather than `getopt_long()` to facilitate handling negative - // integers that might otherwise look like a flag. - optind = opterr = 0; + optget_ind = 0; bool done = false; - while (!done && (opt = getopt_long_only(argc, argv, short_options, long_options, NULL)) != -1) { + while (!done && (opt = optget_long(argc, argv, short_options, long_options)) != -1) { switch (opt) { + case -2: { + done = true; + optget_ind--; + break; + } case 1: { builtin_print_help(shp, cmd); return 0; } case ':': { - builtin_missing_argument(shp, cmd, argv[optind - 1]); + builtin_missing_argument(shp, cmd, argv[optget_ind - 1]); return 2; } case '?': { - char *cp; - (void)strton64(argv[optind - 1] + 1, &cp, NULL, 0); - if (*cp) { - // It's not an integer so it's an invalid flag. - builtin_unknown_option(shp, cmd, argv[optind - 1]); - return 2; - } - optind--; - done = true; - break; + builtin_unknown_option(shp, cmd, argv[optget_ind - 1]); + return 2; } default: { abort(); } } } - argv += optind; + argv += optget_ind; pp->mode = SH_JMPFUN; int n = *argv ? (int)strtol(*argv, NULL, 10) : shp->oldexit; diff --git a/src/cmd/ksh93/cmds/head.c b/src/cmd/ksh93/cmds/head.c index 274c537a11a4..82784436e4a8 100644 --- a/src/cmd/ksh93/cmds/head.c +++ b/src/cmd/ksh93/cmds/head.c @@ -27,7 +27,6 @@ #include "config_ast.h" // IWYU pragma: keep #include -#include #include #include #include @@ -37,19 +36,20 @@ #include "builtins.h" #include "defs.h" #include "error.h" +#include "optget_long.h" #include "sfio.h" #include "shcmd.h" #include "stdlib.h" -static const char *short_options = "+:n:c:qs:v"; -static const struct option long_options[] = { - {"help", no_argument, NULL, 1}, // all builtins support --help - {"lines", required_argument, NULL, 'n'}, - {"bytes", required_argument, NULL, 'c'}, - {"skip", required_argument, NULL, 's'}, - {"quiet", no_argument, NULL, 'q'}, - {"silent", no_argument, NULL, 'q'}, - {"verbose", no_argument, NULL, 'v'}, +static const char *short_options = "#n:c:qs:v"; +static const struct optget_option long_options[] = { + {"help", optget_no_arg, NULL, 1}, // all builtins support --help + {"lines", optget_required_arg, NULL, 'n'}, + {"bytes", optget_required_arg, NULL, 'c'}, + {"skip", optget_required_arg, NULL, 's'}, + {"quiet", optget_no_arg, NULL, 'q'}, + {"silent", optget_no_arg, NULL, 'q'}, + {"verbose", optget_no_arg, NULL, 'v'}, {NULL, 0, NULL, 0}}; // @@ -72,18 +72,27 @@ int b_head(int argc, char **argv, Shbltin_t *context) { if (cmdinit(argc, argv, context, 0)) return -1; - optind = opterr = 0; - while ((opt = getopt_long_only(argc, argv, short_options, long_options, NULL)) != -1) { + optget_ind = 0; + while ((opt = optget_long(argc, argv, short_options, long_options)) != -1) { switch (opt) { + case -2: { + if (optget_num < 0 || optget_num > OFF_MAX) { + errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -n", optget_arg); + return 2; + } + keep = optget_num; + delim = '\n'; + break; + } case 1: { builtin_print_help(shp, cmd); return 0; } case 'c': { char *cp; - int64_t n = strton64(optarg, &cp, NULL, 0); + int64_t n = strton64(optget_arg, &cp, NULL, 0); if (*cp || n < 0 || n > OFF_MAX) { - errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -c", optarg); + errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -c", optget_arg); return 2; } keep = n; @@ -92,9 +101,9 @@ int b_head(int argc, char **argv, Shbltin_t *context) { } case 'n': { char *cp; - int64_t n = strton64(optarg, &cp, NULL, 0); + int64_t n = strton64(optget_arg, &cp, NULL, 0); if (*cp || n < 0 || n > OFF_MAX) { - errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -n", optarg); + errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -n", optget_arg); return 2; } keep = n; @@ -111,34 +120,27 @@ int b_head(int argc, char **argv, Shbltin_t *context) { } case 's': { char *cp; - int64_t n = strton64(optarg, &cp, NULL, 0); + int64_t n = strton64(optget_arg, &cp, NULL, 0); if (*cp || n < 0 || n > OFF_MAX) { - errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -s", optarg); + errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -s", optget_arg); return 2; } skip = n; break; } case ':': { - builtin_missing_argument(shp, cmd, argv[optind - 1]); + builtin_missing_argument(shp, cmd, argv[optget_ind - 1]); return 2; } case '?': { - char *cp; - int64_t n = strton64(argv[optind - 1] + 1, &cp, NULL, 0); - if (!*cp && n >= 0 && n <= OFF_MAX) { - keep = n; - delim = '\n'; - break; - } - builtin_unknown_option(shp, cmd, argv[optind - 1]); + builtin_unknown_option(shp, cmd, argv[optget_ind - 1]); return 2; } default: { abort(); } } } - argv += optind; - argc -= optind; + argv += optget_ind; + argc -= optget_ind; cp = *argv; if (cp) argv++; diff --git a/src/cmd/ksh93/sh/fault.c b/src/cmd/ksh93/sh/fault.c index 1b2a1d3472d1..e06496c1688f 100644 --- a/src/cmd/ksh93/sh/fault.c +++ b/src/cmd/ksh93/sh/fault.c @@ -779,7 +779,7 @@ void sh_sigcheck(Shell_t *shp) { } // -// Given the name or number of a signal return the signal number. +// Given the name or number of a signal (as a string) return the numeric signal number. // int sig_number(Shell_t *shp, const char *string) { const Shtable_t *tp;