diff --git a/ChangeLog b/ChangeLog index a167a5d47..c8fbe8365 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,17 @@ * Alexey: 30322: Completion/Unix/Command/_xmlsoft: accept more file types. +2012-03-06 Barton E. Schaefer + + * 30320: Doc/Zsh/builtins.yo, Src/builtin.c, Src/init.c, + Src/options.c: "emulate" accepts invocation-time setopt flags + after the shell name, in addition to "-c command". + + * 30320 (bonus): Doc/Zsh/params.yo: document interaction of + sun_keyboard_hack with the KEYBOARD_HACK paramter. + + * 30320 (misc.): Etc/FAQ.yo: rectify a minor omission. + 2012-03-05 Clint Adams * 30314: Completion/Unix/Command/_ssh: add completion for @@ -16077,5 +16088,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5605 $ +* $Revision: 1.5606 $ ***************************************************** diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 706c2803f..98c470a54 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -348,7 +348,7 @@ cindex(compatibility, csh) cindex(sh, compatibility) cindex(ksh, compatibility) cindex(csh, compatibility) -item(tt(emulate) [ tt(-LR) ] [ {tt(zsh)|tt(sh)|tt(ksh)|tt(csh)} [ tt(-c) tt(arg) ] ])( +item(tt(emulate) [ tt(-LR) ] [ {tt(zsh)|tt(sh)|tt(ksh)|tt(csh)} [ var(flags) ... ] ])( Without any argument print current emulation mode. With single argument set up zsh options to emulate the specified shell @@ -359,7 +359,7 @@ will be used as a default; more precisely, the tests performed on the argument are the same as those used to determine the emulation at startup based on the shell name, see ifzman(\ -the section `Compatibility' in zmanref(zshmisc) +the section COMPATIBILITY in zmanref(zsh) )\ ifnzman(\ noderef(Compatibility) @@ -373,26 +373,34 @@ Note that code executed inside the function by the tt(.), tt(source), or tt(eval) commands is not considered to be running directly from the function, hence does not provoke this behaviour. -If the tt(-R) option is given, all options +If the tt(-R) switch is given, all settable options are reset to their default value corresponding to the specified emulation mode, except for certain options describing the interactive environment; otherwise, only those options likely to cause portability -problems in scripts and functions are altered. If the tt(-L) option is given, +problems in scripts and functions are altered. If the tt(-L) switch is given, the options tt(LOCAL_OPTIONS) and tt(LOCAL_TRAPS) will be set as well, causing the effects of the tt(emulate) command and any tt(setopt) and tt(trap) commands to be local to the immediately surrounding shell function, if any; normally these options are turned off in all emulation -modes except tt(ksh). The tt(-L) and tt(-c) are mutually exclusive. +modes except tt(ksh). The tt(-L) switch is mutually exclusive with the +use of tt(-c) in var(flags). -If tt(-c) tt(arg) is given, evaluate tt(arg) while the requested -emulation is temporarily in effect. The emulation and all options will -be restored to their original values before tt(emulate) returns. The -tt(-R) flag may be used. +The var(flags) may be any of the invocation-time flags described in +ifnzman(noderef(Invocation))\ +ifzman(the section INVOCATION in zmanref(zsh)), +except that `tt(-o EMACS)' and `tt(-o VI)' may not be used. Flags such +as `tt(+r)'/`tt(+o RESTRICTED)' may be prohibited in some circumstances. +If tt(-c) var(arg) appears in var(flags), var(arg) is evaluated while the +requested emulation is temporarily in effect. In this case the emulation +mode and all options are restored to their previous values before +tt(emulate) returns. The tt(-R) switch may precede the name of the shell +to emulate; note this has a meaning distinct from including tt(-R) in +var(flags). Use of tt(-c) enables `sticky' emulation mode for functions defined within the evaluated expression: the emulation mode is associated thereafter with the function so that whenever the function is executed -the emulation (respecting the tt(-R) flag, if present) and all +the emulation (respecting the tt(-R) switch, if present) and all options are set before entry to the function, and restored after exit. If the function is called when the sticky emulation is already in effect, either within an `tt(emulate) var(shell) tt(-c)' expression or @@ -434,7 +442,7 @@ within sticky emulation.) sitem(3.)(No special handling is provided for functions marked for tt(autoload) nor for functions present in wordcode created by the tt(zcompile) command.) -sitem(4.)(The presence or absence of the tt(-R) flag to tt(emulate) +sitem(4.)(The presence or absence of the tt(-R) switch to tt(emulate) corresponds to different sticky emulation modes, so for example `tt(emulate sh -c)', `tt(emulate -R sh -c)' and `tt(emulate csh -c)' are treated as three distinct sticky emulations.) diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index e9a3c722d..82768983d 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -1003,6 +1003,10 @@ and replaces the tt(SUNKEYBOARDHACK) option which did this for backquotes only. Should the chosen character be one of singlequote, doublequote or backquote, there must also be an odd number of them on the command line for the last one to be removed. + +For backward compabitility, if the tt(SUNKEYBOARDHACK) option is +explicitly set, the value of tt(KEYBOARD_HACK) reverts to backquote. +If the option is explicitly unset, this variable is set to empty. ) vindex(KEYTIMEOUT) item(tt(KEYTIMEOUT))( diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo index ee79a6ac4..ddbf42885 100644 --- a/Etc/FAQ.yo +++ b/Etc/FAQ.yo @@ -722,7 +722,7 @@ label(23) appear inside the tt({ }) the way they get appended to an alias. myeit() If the csh alias references its own name (tt(alias rm "rm -i")), - then in a zsh function you need the "command" keyword + then in a zsh function you need the "command" or "builtin" keyword (function tt(rm() { command rm -i "$@" })), but in a zsh alias you don't (tt(alias rm="rm -i")). diff --git a/Src/builtin.c b/Src/builtin.c index b43c08235..c32b1c023 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -58,7 +58,7 @@ static struct builtin builtins[] = BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmrs", NULL), BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL), BUILTIN("echo", BINF_SKIPINVALID, bin_print, 0, -1, BIN_ECHO, "neE", "-"), - BUILTIN("emulate", 0, bin_emulate, 0, 3, 0, "LR", NULL), + BUILTIN("emulate", 0, bin_emulate, 0, -1, 0, "LR", NULL), BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmrs", NULL), BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL), BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL), @@ -4958,14 +4958,14 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) { int opt_L = OPT_ISSET(ops, 'L'); int opt_R = OPT_ISSET(ops, 'R'); - int saveemulation, savesticky_emulation; - int ret; + int saveemulation, savesticky_emulation, savehackchar; + int ret = 1; char saveopts[OPT_SIZE]; + char *cmd = 0; + const char *shname = *argv; /* without arguments just print current emulation */ - if (!*argv) { - const char *shname; - + if (!shname) { if (opt_L || opt_R) { zwarnnam("emulate", "not enough arguments"); return 1; @@ -4995,39 +4995,46 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) /* with single argument set current emulation */ if (!argv[1]) { - emulate(*argv, OPT_ISSET(ops,'R')); + emulate(shname, OPT_ISSET(ops,'R')); if (OPT_ISSET(ops,'L')) opts[LOCALOPTIONS] = opts[LOCALTRAPS] = 1; return 0; } + argv++; + memcpy(saveopts, opts, sizeof(opts)); + savehackchar = keyboardhackchar; + cmd = parseopts("emulate", &argv); + + /* parseopts() has consumed anything that looks like an option */ + if (*argv) { + zwarnnam("emulate", "unknown argument %s", *argv); + goto restore; + } + /* If "-c command" is given, evaluate command using specified * emulation mode. */ - if (strcmp(argv[1], "-c")) { - zwarnnam("emulate", "unknown argument %s", argv[1]); - return 1; - } + if (cmd) { + if (opt_L) { + zwarnnam("emulate", "option -L incompatible with -c"); + goto restore; + } + *--argv = cmd; /* on stack, never free()d, see execbuiltin() */ + } else + return 0; - if (!argv[2]) { - zwarnnam("emulate", "not enough arguments"); - return 1; - } - - if (opt_L) { - zwarnnam("emulate", "option -L incompatible with -c"); - return 1; - } - - memcpy(saveopts, opts, sizeof(opts)); saveemulation = emulation; savesticky_emulation = sticky_emulation; - emulate(*argv, OPT_ISSET(ops,'R')); + emulate(shname, OPT_ISSET(ops,'R')); sticky_emulation = emulation; - ret = eval(argv+2); - memcpy(opts, saveopts, sizeof(opts)); + ret = eval(argv); sticky_emulation = savesticky_emulation; emulation = saveemulation; + restore: + memcpy(opts, saveopts, sizeof(opts)); + keyboardhackchar = savehackchar; + inittyptab(); /* restore banghist */ return ret; } diff --git a/Src/init.c b/Src/init.c index 9820070fb..1212a48d9 100644 --- a/Src/init.c +++ b/Src/init.c @@ -215,6 +215,7 @@ loop(int toplevel, int justonce) return LOOP_OK; } +/* Shared among parseargs(), parseopts(), init_io(), and init_misc() */ static char *cmd; static int restricted; @@ -222,9 +223,7 @@ static int restricted; static void parseargs(char **argv, char **runscript) { - int optionbreak = 0; char **x; - int action, optno; LinkList paramlist; argzero = *argv++; @@ -247,93 +246,9 @@ parseargs(char **argv, char **runscript) opts[SHINSTDIN] = 0; opts[SINGLECOMMAND] = 0; - /* loop through command line options (begins with "-" or "+") */ - while (!optionbreak && *argv && (**argv == '-' || **argv == '+')) { - char *args = *argv; - action = (**argv == '-'); - if (!argv[0][1]) - *argv = "--"; - while (*++*argv) { - if (**argv == '-') { - if(!argv[0][1]) { - /* The pseudo-option `--' signifies the end of options. */ - argv++; - goto doneoptions; - } - if(*argv != args+1 || **argv != '-') - goto badoptionstring; - /* GNU-style long options */ - ++*argv; - if (!strcmp(*argv, "version")) { - printf("zsh %s (%s-%s-%s)\n", - ZSH_VERSION, MACHTYPE, VENDOR, OSTYPE); - exit(0); - } - if (!strcmp(*argv, "help")) { - printhelp(); - exit(0); - } - /* `-' characters are allowed in long options */ - for(args = *argv; *args; args++) - if(*args == '-') - *args = '_'; - goto longoptions; - } + cmd = parseopts(NULL, &argv); - if (unset(SHOPTIONLETTERS) && **argv == 'b') { - /* -b ends options at the end of this argument */ - optionbreak = 1; - } else if (**argv == 'c') { - /* -c command */ - cmd = *argv; - opts[INTERACTIVE] &= 1; - scriptname = scriptfilename = ztrdup("zsh"); - } else if (**argv == 'o') { - if (!*++*argv) - argv++; - if (!*argv) { - zerr("string expected after -o"); - exit(1); - } - longoptions: - if (!(optno = optlookup(*argv))) { - zerr("no such option: %s", *argv); - exit(1); - } else if (optno == RESTRICTED) - restricted = action; - else - dosetopt(optno, action, 1); - break; - } else if (isspace(STOUC(**argv))) { - /* zsh's typtab not yet set, have to use ctype */ - while (*++*argv) - if (!isspace(STOUC(**argv))) { - badoptionstring: - zerr("bad option string: `%s'", args); - exit(1); - } - break; - } else { - if (!(optno = optlookupc(**argv))) { - zerr("bad option: -%c", **argv); - exit(1); - } else if (optno == RESTRICTED) - restricted = action; - else - dosetopt(optno, action, 1); - } - } - argv++; - } - doneoptions: paramlist = znewlinklist(); - if (cmd) { - if (!*argv) { - zerr("string expected after -%s", cmd); - exit(1); - } - cmd = *argv++; - } if (*argv) { if (unset(SHINSTDIN)) { if (cmd) @@ -361,6 +276,114 @@ parseargs(char **argv, char **runscript) argzero = ztrdup(argzero); } +/**/ +mod_export char * +parseopts(char *nam, char ***argvp) +{ + int optionbreak = 0; + int action, optno; + char *cmd = 0; /* deliberately hides static */ + char **argv = *argvp; + +#define WARN_OPTION(F, S) if (nam) zwarnnam(nam, F, S); else zerr(F, S) +#define LAST_OPTION(N) \ + if (nam) { if (*argv) argv++; goto doneargv; } else exit(N) + + /* loop through command line options (begins with "-" or "+") */ + while (!optionbreak && *argv && (**argv == '-' || **argv == '+')) { + char *args = *argv; + action = (**argv == '-'); + if (!argv[0][1]) + *argv = "--"; + while (*++*argv) { + if (**argv == '-') { + if(!argv[0][1]) { + /* The pseudo-option `--' signifies the end of options. */ + argv++; + goto doneoptions; + } + if(*argv != args+1 || **argv != '-') + goto badoptionstring; + /* GNU-style long options */ + ++*argv; + if (!strcmp(*argv, "version")) { + printf("zsh %s (%s-%s-%s)\n", + ZSH_VERSION, MACHTYPE, VENDOR, OSTYPE); + LAST_OPTION(0); + } + if (!strcmp(*argv, "help")) { + printhelp(); + LAST_OPTION(0); + } + /* `-' characters are allowed in long options */ + for(args = *argv; *args; args++) + if(*args == '-') + *args = '_'; + goto longoptions; + } + + if (unset(SHOPTIONLETTERS) && **argv == 'b') { + /* -b ends options at the end of this argument */ + optionbreak = 1; + } else if (**argv == 'c') { + /* -c command */ + cmd = *argv; + opts[INTERACTIVE] &= 1; + scriptname = scriptfilename = ztrdup("zsh"); + } else if (**argv == 'o') { + if (!*++*argv) + argv++; + if (!*argv) { + WARN_OPTION("string expected after -o", NULL); + LAST_OPTION(1); + } + longoptions: + if (!(optno = optlookup(*argv))) { + WARN_OPTION("no such option: %s", *argv); + LAST_OPTION(1); + } else if (optno == RESTRICTED && !nam) + restricted = action; + else if ((optno == EMACSMODE || optno == VIMODE) && nam) + WARN_OPTION("can't change option: %s", *argv); + else if (dosetopt(optno, action, !nam) && nam) + WARN_OPTION("can't change option: %s", *argv); + break; + } else if (isspace(STOUC(**argv))) { + /* zsh's typtab not yet set, have to use ctype */ + while (*++*argv) + if (!isspace(STOUC(**argv))) { + badoptionstring: + WARN_OPTION("bad option string: '%s'", args); + LAST_OPTION(1); + } + break; + } else { + if (!(optno = optlookupc(**argv))) { + WARN_OPTION("bad option: -%c", **argv); + LAST_OPTION(1); + } else if (optno == RESTRICTED && !nam) + restricted = action; + else if ((optno == EMACSMODE || optno == VIMODE) && nam) + WARN_OPTION("can't change option: %s", *argv); + else if (dosetopt(optno, action, !nam) && nam) + WARN_OPTION("can't change option: -%c", **argv); + } + } + argv++; + } + doneoptions: + if (cmd) { + if (!*argv) { + WARN_OPTION("string expected after -%s", cmd); + LAST_OPTION(1); + } + cmd = *argv++; + } + doneargv: + *argvp = argv; + return cmd; +} + /**/ static void printhelp(void) diff --git a/Src/options.c b/Src/options.c index 48df16045..c6db75372 100644 --- a/Src/options.c +++ b/Src/options.c @@ -767,6 +767,8 @@ dosetopt(int optno, int value, int force) return -1; #endif /* GETPWNAM_FAKED */ } else if ((optno == EMACSMODE || optno == VIMODE) && value) { + if (sticky_emulation) + return -1; zleentry(ZLE_CMD_SET_KEYMAP, optno); opts[(optno == EMACSMODE) ? VIMODE : EMACSMODE] = 0; } else if (optno == SUNKEYBOARDHACK) {