From 6e01a977cc49a19fe6b223b44e12ded7d9ef2061 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Mon, 25 Jun 2001 16:10:59 +0000 Subject: Merge a few more dev changes before 4.0.2. --- ChangeLog | 12 +- Completion/Base/Widget/_complete_debug | 24 ++ Completion/Base/Widget/_complete_help | 92 +++++ Doc/Zsh/options.yo | 14 + Src/options.c | 54 +++ Src/subst.c | 183 ++++++++-- Src/zsh.h | 135 ++++---- Test/E01options.ztst | 616 +++++++++++++++++++++++++++++++++ 8 files changed, 1033 insertions(+), 97 deletions(-) create mode 100644 Completion/Base/Widget/_complete_debug create mode 100644 Completion/Base/Widget/_complete_help create mode 100644 Test/E01options.ztst diff --git a/ChangeLog b/ChangeLog index 924a90194..51ffdec59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,7 +5,7 @@ 001-06-22 Andrej Borsenkow - * 15021: Src/prompt.c, Doc/Zsh/prompt.yo: revert to old %l + * 15021: Src/prompt.c, Doc/Zsh/prompt.yo: revert to old %l semantic; add new %y character instead as suggested by Wayne 2001-06-21 Bart Schaefer @@ -17,6 +17,10 @@ * 15018: Completion/compinit: Fix exit status of compdef. + * 15002: Completion/Base/Widget/_complete_debug, + Completion/Base/Widget/_complete_help: Use `trap' to restore state + properly in case of keyboard interrupt. + 2001-06-20 Bart Schaefer * 14880: Completion/Base/Core/_main_complete: Fix insert-tab style @@ -100,6 +104,12 @@ * 14883 (Jos Backus): Completion/Unix/Command/_mount: add code for BSDish systems +2001-06-12 Peter Stephenson + + * 14858: Doc/Zsh/options.yo, Src/options.c, Src/subst.c, + Src/zsh.h, Test/E01options.ztst: KSH_TYPESET option allows + assignments after typeset not to be split. + 2001-06-12 Bart Schaefer * 14849: README: Request "reporter" output only if a bug cannot diff --git a/Completion/Base/Widget/_complete_debug b/Completion/Base/Widget/_complete_debug new file mode 100644 index 000000000..1f12e8b9f --- /dev/null +++ b/Completion/Base/Widget/_complete_debug @@ -0,0 +1,24 @@ +#compdef -k complete-word \C-x? + +eval "$_comp_setup" + +(( $+_debug_count )) || integer -g _debug_count +local tmp=${TMPPREFIX}${$}${words[1]:t}$[++_debug_count] +local w="${(qq)words}" + +exec 3>&- # Too bad if somebody else is using it ... +[[ -t 2 ]] && { exec 3>&2 2>| $tmp ; trap 'exec 2>&3 3>&-' EXIT INT } + +setopt xtrace +_main_complete +integer ret=$? +unsetopt xtrace + +[[ -t 3 ]] && { + print -sR "${VISUAL:-${EDITOR:-${PAGER:-more}}} ${(q)tmp} ;: $w" + _message -r "Trace output left in $tmp (up-history to view)" + [[ $compstate[nmatches] -le 1 && $compstate[list] != *force* ]] && + compstate[list]='list force messages' +} + +return ret diff --git a/Completion/Base/Widget/_complete_help b/Completion/Base/Widget/_complete_help new file mode 100644 index 000000000..69930e105 --- /dev/null +++ b/Completion/Base/Widget/_complete_help @@ -0,0 +1,92 @@ +#compdef -k complete-word \C-xh + +_complete_help() { + eval "$_comp_setup" + + local _sort_tags=_help_sort_tags text i j k tmp + typeset -A help_funcs help_tags help_sfuncs help_styles + + compadd() { return 1 } + zstyle() { + local _f="${${(@)${(@)funcstack[2,(i)_(main_complete|complete|approximate|normal)]}:#_(wanted|requested|all_labels|next_label)}% *}" + + [[ -z "$_f" ]] && _f="${${(@)funcstack[2,(i)_(main_complete|complete|approximate|normal)]}:#_(wanted|requested|all_labels|next_label)}" + + if [[ "$help_sfuncs[$2]" != *${_f}* || + "$help_styles[${2}${_f}]" != *${3}* ]]; then + [[ "$help_sfuncs[$2]" != *${_f}* ]] && + help_sfuncs[$2]="${help_sfuncs[$2]}:${_f}" + local _t + + case "$1" in + -s) _t='[string] ';; + -a) _t='[array] ';; + -h) _t='[assoc] ';; + *) _t='[boolean]';; + esac + help_styles[${2}${_f}]="${help_styles[${2}${_f}]},${_t} ${3}:${_f}" + fi + + # No need to call the completers more than once with different match specs. + + if [[ "$3" = matcher-list ]]; then + set -A "$4" '' + else + builtin zstyle "$@" + fi + } + trap 'unfunction compadd zstyle' EXIT INT + + _main_complete + + unfunction compadd zstyle + trap - EXIT INT + + for i in "${(@ok)help_funcs}"; do + text="${text} +tags in context :completion:${i}:" + tmp=() + for j in "${(@s.:.)help_funcs[$i][2,-1]}"; do + tmp=( "$tmp[@]" "${(@s.,.)help_tags[${i}${j}][2,-1]}" ) + done + zformat -a tmp ' (' "$tmp[@]" + tmp=( ' + '${^tmp}')' ) + text="${text}${tmp}" + done + + if [[ ${NUMERIC:-1} -ne 1 ]]; then + text="$text +" + for i in "${(@ok)help_sfuncs}"; do + text="${text} +styles in context ${i}" + tmp=() + for j in "${(@s.:.)help_sfuncs[$i][2,-1]}"; do + tmp=( "$tmp[@]" "${(@s.,.)help_styles[${i}${j}][2,-1]}" ) + done + zformat -a tmp ' (' "$tmp[@]" + tmp=( ' + '${^tmp}')' ) + text="${text}${tmp}" + done + fi + compstate[list]='list force' + compstate[insert]='' + + compadd -UX "$text[2,-1]" -n '' +} + +_help_sort_tags() { + local f="${${(@)${(@)funcstack[3,(i)_(main_complete|complete|approximate|normal)]}:#_(wanted|requested|all_labels|next_label)}% *}" + + if [[ "$help_funcs[$curcontext]" != *${f}* || + "$help_tags[${curcontext}${f}]" != *(${(j:|:)~argv})* ]]; then + [[ "$help_funcs[$curcontext]" != *${f}* ]] && + help_funcs[$curcontext]="${help_funcs[$curcontext]}:${f}" + help_tags[${curcontext}${f}]="${help_tags[${curcontext}${f}]},${argv}:${f}" + comptry "$@" + fi +} + +_complete_help "$@" diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo index 490946cd5..564e6701b 100644 --- a/Doc/Zsh/options.yo +++ b/Doc/Zsh/options.yo @@ -668,6 +668,16 @@ Alters the way options settings are printed: instead of separate lists of set and unset options, all options are shown, marked `on' if they are in the non-default state, `off' otherwise. ) +pindex(KSH_TYPESET) +cindex(argument splitting, in typeset etc.) +cindex(ksh, argument splitting in typeset) +item(tt(KSH_TYPESET) )( +Alters the way arguments to the tt(typeset) family of commands, including +tt(declare), tt(export), tt(float), tt(integer), tt(local) and +tt(readonly), are processed. Without this option, zsh will perform normal +word splitting after command and parameter expansion in arguments of an +assignment; with it, word splitting does not take place in those cases. +) pindex(LIST_AMBIGUOUS) cindex(ambiguous completion) cindex(completion, ambiguous) @@ -757,6 +767,10 @@ not otherwise treated specially; it is passed to the command as a single argument, and not used as an actual parameter assignment. For example, in tt(echo foo=~/bar:~/rod), both occurrences of tt(~) would be replaced. Note that this happens anyway with tt(typeset) and similar statements. + +This option respects the setting of the tt(KSH_TYPESET) option. In other +words, if both options are in effect, arguments looking like +assignments will not undergo wordsplitting. ) pindex(MAIL_WARNING) cindex(mail, warning of reading) diff --git a/Src/options.c b/Src/options.c index 3e130a63e..2c63f194a 100644 --- a/Src/options.c +++ b/Src/options.c @@ -69,6 +69,7 @@ mod_export HashTable optiontab; * to avoid formatting problems. */ static struct optname optns[] = { +{NULL, "aliases", OPT_EMULATE|OPT_ALL, ALIASESOPT}, {NULL, "allexport", OPT_EMULATE, ALLEXPORT}, {NULL, "alwayslastprompt", OPT_ALL, ALWAYSLASTPROMPT}, {NULL, "alwaystoend", 0, ALWAYSTOEND}, @@ -90,6 +91,7 @@ static struct optname optns[] = { {NULL, "bgnice", OPT_EMULATE|OPT_NONBOURNE, BGNICE}, {NULL, "braceccl", OPT_EMULATE, BRACECCL}, {NULL, "bsdecho", OPT_EMULATE|OPT_SH, BSDECHO}, +{NULL, "cbases", 0, CBASES}, {NULL, "cdablevars", OPT_EMULATE, CDABLEVARS}, {NULL, "chasedots", OPT_EMULATE, CHASEDOTS}, {NULL, "chaselinks", OPT_EMULATE, CHASELINKS}, @@ -112,6 +114,7 @@ static struct optname optns[] = { {NULL, "flowcontrol", OPT_ALL, FLOWCONTROL}, {NULL, "functionargzero", OPT_EMULATE|OPT_NONBOURNE, FUNCTIONARGZERO}, {NULL, "glob", OPT_EMULATE|OPT_ALL, GLOBOPT}, +{NULL, "globalexport", OPT_EMULATE|OPT_ZSH, GLOBALEXPORT}, {NULL, "globalrcs", OPT_ALL, GLOBALRCS}, {NULL, "globassign", OPT_EMULATE|OPT_CSH, GLOBASSIGN}, {NULL, "globcomplete", 0, GLOBCOMPLETE}, @@ -142,6 +145,7 @@ static struct optname optns[] = { {NULL, "kshautoload", OPT_EMULATE|OPT_BOURNE, KSHAUTOLOAD}, {NULL, "kshglob", OPT_EMULATE|OPT_KSH, KSHGLOB}, {NULL, "kshoptionprint", OPT_EMULATE|OPT_KSH, KSHOPTIONPRINT}, +{NULL, "kshtypeset", OPT_EMULATE|OPT_KSH, KSHTYPESET}, {NULL, "listambiguous", OPT_ALL, LISTAMBIGUOUS}, {NULL, "listbeep", OPT_ALL, LISTBEEP}, {NULL, "listpacked", 0, LISTPACKED}, @@ -161,6 +165,7 @@ static struct optname optns[] = { {NULL, "notify", OPT_ZSH, NOTIFY}, {NULL, "nullglob", OPT_EMULATE, NULLGLOB}, {NULL, "numericglobsort", OPT_EMULATE, NUMERICGLOBSORT}, +{NULL, "octalzeroes", OPT_EMULATE|OPT_SH, OCTALZEROES}, {NULL, "overstrike", 0, OVERSTRIKE}, {NULL, "pathdirs", OPT_EMULATE, PATHDIRS}, {NULL, "posixbuiltins", OPT_EMULATE|OPT_BOURNE, POSIXBUILTINS}, @@ -209,6 +214,7 @@ static struct optname optns[] = { {NULL, "promptvars", OPT_ALIAS, /* bash */ PROMPTSUBST}, {NULL, "stdin", OPT_ALIAS, /* ksh */ SHINSTDIN}, {NULL, "trackall", OPT_ALIAS, /* ksh */ HASHCMDS}, +{NULL, "dvorak", 0, DVORAK}, {NULL, NULL, 0, 0} }; @@ -642,6 +648,9 @@ dosetopt(int optno, int value, int force) for (s = rparams; *s; s++) restrictparam(*s); } + } else if(!force && optno == EXECOPT && !value && interact) { + /* cannot set noexec when interactive */ + return -1; } else if(!force && (optno == INTERACTIVE || optno == SHINSTDIN || optno == SINGLECOMMAND)) { if (opts[optno] == value) @@ -691,3 +700,48 @@ dashgetfn(Param pm) *val = '\0'; return buf; } + +/* Print option list for --help */ + +/**/ +void +printoptionlist(void) +{ + short *lp; + char c; + + printf("\nNamed options:\n"); + scanhashtable(optiontab, 1, 0, OPT_ALIAS, printoptionlist_printoption, 0); + printf("\nOption aliases:\n"); + scanhashtable(optiontab, 1, OPT_ALIAS, 0, printoptionlist_printoption, 0); + printf("\nOption letters:\n"); + for(lp = optletters, c = FIRST_OPT; c <= LAST_OPT; lp++, c++) { + if(!*lp) + continue; + printf(" -%c ", c); + printoptionlist_printequiv(*lp); + } +} + +/**/ +static void +printoptionlist_printoption(HashNode hn, int ignored) +{ + Optname on = (Optname) hn; + + if(on->flags & OPT_ALIAS) { + printf(" --%-19s ", on->nam); + printoptionlist_printequiv(on->optno); + } else + printf(" --%s\n", on->nam); +} + +/**/ +static void +printoptionlist_printequiv(int optno) +{ + int isneg = optno < 0; + + optno *= (isneg ? -1 : 1); + printf(" equivalent to --%s%s\n", isneg ? "no-" : "", optns[optno-1].nam); +} diff --git a/Src/subst.c b/Src/subst.c index 408a9d406..b5480d75e 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -50,7 +50,9 @@ mod_export void prefork(LinkList list, int flags) { LinkNode node; + int asssub = (flags & PF_TYPESET) && isset(KSHTYPESET); + queue_signals(); for (node = firstnode(list); node; incnode(node)) { char *str, c; @@ -61,14 +63,18 @@ prefork(LinkList list, int flags) setdata(node, (void *) getproc(str)); /* <(...) or >(...) */ else setdata(node, (void *) getoutputfile(str)); /* =(...) */ - if (!getdata(node)) + if (!getdata(node)) { + unqueue_signals(); return; + } } else { if (isset(SHFILEEXPANSION)) filesub((char **)getaddrdata(node), flags & (PF_TYPESET|PF_ASSIGN)); - if (!(node = stringsubst(list, node, flags & PF_SINGLE))) + if (!(node = stringsubst(list, node, flags & PF_SINGLE, asssub))) { + unqueue_signals(); return; + } } } for (node = firstnode(list); node; incnode(node)) { @@ -82,14 +88,17 @@ prefork(LinkList list, int flags) flags & (PF_TYPESET|PF_ASSIGN)); } else if (!(flags & PF_SINGLE)) uremnode(list, node); - if (errflag) + if (errflag) { + unqueue_signals(); return; + } } + unqueue_signals(); } /**/ static LinkNode -stringsubst(LinkList list, LinkNode node, int ssub) +stringsubst(LinkList list, LinkNode node, int ssub, int asssub) { int qt; char *str3 = (char *)getdata(node); @@ -203,6 +212,12 @@ stringsubst(LinkList list, LinkNode node, int ssub) str3 = str2; setdata(node, str3); continue; + } else if (asssub && ((c == '=') || c == Equals) && str != str3) { + /* + * We are in a normal argument which looks like an assignment + * and is to be treated like one, with no word splitting. + */ + ssub = 1; } str++; } @@ -307,7 +322,7 @@ multsub(char **s, char ***a, int *isarr, char *sep) mod_export void filesub(char **namptr, int assign) { - char *sub = NULL, *str, *ptr; + char *eql = NULL, *sub = NULL, *str, *ptr; int len; filesubstr(namptr, assign); @@ -316,7 +331,7 @@ filesub(char **namptr, int assign) return; if (assign & PF_TYPESET) { - if ((*namptr)[1] && (sub = strchr(*namptr + 1, Equals))) { + if ((*namptr)[1] && (eql = sub = strchr(*namptr + 1, Equals))) { str = sub + 1; if ((sub[1] == Tilde || sub[1] == Equals) && filesubstr(&str, assign)) { sub[1] = '\0'; @@ -330,7 +345,9 @@ filesub(char **namptr, int assign) while ((sub = strchr(ptr, ':'))) { str = sub + 1; len = sub - *namptr; - if ((sub[1] == Tilde || sub[1] == Equals) && filesubstr(&str, assign)) { + if (sub > eql && + (sub[1] == Tilde || sub[1] == Equals) && + filesubstr(&str, assign)) { sub[1] = '\0'; *namptr = dyncat(*namptr, str); } @@ -702,17 +719,21 @@ get_intarg(char **s) /* Parsing for the (e) flag. */ static int -subst_parse_str(char **sp, int single) +subst_parse_str(char **sp, int single, int err) { char *s; *sp = s = dupstring(*sp); - if (!parsestr(s)) { + if (!(err ? parsestr(s) : parsestrnoerr(s))) { if (!single) { + int qt = 0; + for (; *s; s++) - if (*s == Qstring) + if (!qt && *s == Qstring) *s = String; + else if (*s == Dnull) + qt = !qt; } return 0; } @@ -750,6 +771,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) int casmod = 0; int quotemod = 0, quotetype = 0, quoteerr = 0; int visiblemod = 0; + int shsplit = 0; char *sep = NULL, *spsep = NULL; char *premul = NULL, *postmul = NULL, *preone = NULL, *postone = NULL; char *replstr = NULL; /* replacement string for /orig/repl */ @@ -971,6 +993,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) presc++; break; + case 'z': + shsplit = 1; + break; + default: flagerr: zerr("error in flags", NULL, 0); @@ -1000,7 +1026,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) spbreak = 0; s++; } else - spbreak = 1; + spbreak = 2; } else if ((c == '#' || c == Pound) && (iident(cc = s[1]) || cc == '*' || cc == Star || cc == '@' @@ -1053,7 +1079,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) s++; v = (Value) NULL; } else if (aspar) { - if ((v = getvalue(&vbuf, &s, 1))) { + if ((v = fetchvalue(&vbuf, &s, 1, (qt ? SCANPM_DQUOTED : 0)))) { val = idbeg = getstrvalue(v); subexp = 1; } else @@ -1065,7 +1091,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (!(v = fetchvalue(&vbuf, (subexp ? &ov : &s), (wantt ? -1 : ((unset(KSHARRAYS) || inbrace) ? 1 : -1)), - hkeys|hvals|(arrasg ? SCANPM_ASSIGNING : 0))) || + hkeys|hvals| + (arrasg ? SCANPM_ASSIGNING : 0)| + (qt ? SCANPM_DQUOTED : 0))) || (v->pm && (v->pm->flags & PM_UNSET))) vunset = 1; @@ -1104,6 +1132,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) val = dyncat(val, "-unique"); if (f & PM_HIDE) val = dyncat(val, "-hide"); + if (f & PM_HIDE) + val = dyncat(val, "-hideval"); if (f & PM_SPECIAL) val = dyncat(val, "-special"); vunset = 0; @@ -1126,6 +1156,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) isarr = 0; } pm = createparam(nulstring, isarr ? PM_ARRAY : PM_SCALAR); + DPUTS(!pm, "BUG: parameter not created"); if (isarr) pm->u.arr = aval; else @@ -1133,8 +1164,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) v = (Value) hcalloc(sizeof *v); v->isarr = isarr; v->pm = pm; - v->b = -1; - if (getindex(&s, v) || s == os) + v->end = -1; + if (getindex(&s, v, qt) || s == os) break; } if ((isarr = v->isarr)) { @@ -1149,9 +1180,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (v->pm->flags & PM_ARRAY) { int tmplen = arrlen(v->pm->gets.afn(v->pm)); - if (v->a < 0) - v->a += tmplen + v->inv; - if (!v->inv && (v->a >= tmplen || v->a < 0)) + if (v->start < 0) + v->start += tmplen + v->inv; + if (!v->inv && (v->start >= tmplen || v->start < 0)) vunset = 1; } if (!vunset) { @@ -1225,6 +1256,15 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (!inbrace) break; } + if (inbrace && + (c = *s) != '-' && c != '+' && c != ':' && c != '%' && c != '/' && + c != '=' && c != Equals && + c != '#' && c != Pound && + c != '?' && c != Quest && + c != '}' && c != Outbrace) { + zerr("bad substitution", NULL, 0); + return NULL; + } if (isarr) { if (nojoin) isarr = -1; @@ -1353,7 +1393,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) case '-': if (vunset) { val = dupstring(s); - multsub(&val, NULL, &isarr, NULL); + /* + * This is not good enough for sh emulation! Sh would + * split unquoted substrings, yet not split quoted ones + * (except according to $@ rules); but this leaves the + * unquoted substrings unsplit, and other code below + * for spbreak splits even within the quoted substrings. + */ + multsub(&val, (aspar ? NULL : &aval), &isarr, NULL); copied = 1; } break; @@ -1381,8 +1428,6 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (spsep || spbreak) { aval = sepsplit(val, spsep, 0, 1); isarr = 2; - sep = spsep = NULL; - spbreak = 0; l = arrlen(aval); if (l && !*(aval[l-1])) l--; @@ -1420,6 +1465,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) } *idend = sav; copied = 1; + if (isarr) { + if (nojoin) + isarr = -1; + if (qt && !getlen && isarr > 0 && !spsep && spbreak < 2) { + val = sepjoin(aval, sep, 1); + isarr = 0; + } + sep = spsep = NULL; + spbreak = 0; + } } break; case '?': @@ -1440,7 +1495,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) case '#': case Pound: case '/': - if (qt) { + /* This once was executed only `if (qt) ...'. But with that + * patterns in a expansion resulting from a ${(e)...} aren't + * tokenized even though this function thinks they are (it thinks + * they are because subst_parse_string() turns Qstring tokens + * into String tokens and for unquoted parameter expansions the + * lexer normally does tokenize patterns inside parameter + * expansions). */ + { int one = noerrs, oef = errflag, haserr; if (!quoteerr) @@ -1458,9 +1520,18 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) } } { +#if 0 + /* + * This allows # and % to be at the start of + * a parameter in the substitution, which is + * a bit nasty, and can be done (although + * less efficiently) with anchors. + */ + char t = s[-1]; singsub(&s); + if (t == '/' && (flags & SUB_SUBSTR)) { if ((c = *s) == '#' || c == '%') { flags &= ~SUB_SUBSTR; @@ -1471,6 +1542,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) s++; } } +#else + singsub(&s); +#endif } if (!vunset && isarr) { @@ -1635,18 +1709,24 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) aval = arrdup(aval), copied = 1; ap = aval; for (; *ap; ap++) { + char *tmps; unmetafy(*ap, &len); untokenize(*ap); - *ap = unmetafy(promptexpand(metafy(*ap, len, META_NOALLOC), - 0, NULL, NULL), &len); + tmps = unmetafy(promptexpand(metafy(*ap, len, META_NOALLOC), + 0, NULL, NULL), &len); + *ap = dupstring(tmps); + free(tmps); } } else { + char *tmps; if (!copied) val = dupstring(val), copied = 1; unmetafy(val, &len); untokenize(val); - val = unmetafy(promptexpand(metafy(val, len, META_NOALLOC), + tmps = unmetafy(promptexpand(metafy(val, len, META_NOALLOC), 0, NULL, NULL), &len); + val = dupstring(tmps); + free(tmps); } opts[PROMPTSUBST] = ops; opts[PROMPTBANG] = opb; @@ -1748,6 +1828,34 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) val = nicedupstring(val); } } + if (shsplit) { + LinkList list = NULL; + + if (isarr) { + char **ap; + for (ap = aval; *ap; ap++) + list = bufferwords(list, *ap, NULL); + isarr = 0; + } else + list = bufferwords(NULL, val, NULL); + + if (!firstnode(list)) + val = dupstring(""); + else if (!nextnode(firstnode(list))) + val = getdata(firstnode(list)); + else { + char **ap; + LinkNode node; + + aval = ap = (char **) zhalloc((countlinknodes(list) + 1) * + sizeof(char *)); + for (node = firstnode(list); node; incnode(node)) + *ap++ = (char *) getdata(node); + *ap = NULL; + mult_isarr = isarr = 2; + } + copied = 1; + } if (isarr) { char *x; char *y; @@ -1784,7 +1892,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) *--fstr = Marker; init_list1(tl, fstr); - if (!eval && !stringsubst(&tl, firstnode(&tl), ssub)) + if (!eval && !stringsubst(&tl, firstnode(&tl), ssub, 0)) return NULL; *str = aptr; tn = firstnode(&tl); @@ -1792,7 +1900,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (prenum || postnum) x = dopadding(x, prenum, postnum, preone, postone, premul, postmul); - if (eval && subst_parse_str(&x, (qt && !nojoin))) + if (eval && subst_parse_str(&x, (qt && !nojoin), quoteerr)) return NULL; xlen = strlen(x); for (tn = firstnode(&tl); @@ -1828,7 +1936,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (prenum || postnum) x = dopadding(x, prenum, postnum, preone, postone, premul, postmul); - if (eval && subst_parse_str(&x, (qt && !nojoin))) + if (eval && subst_parse_str(&x, (qt && !nojoin), quoteerr)) return NULL; xlen = strlen(x); strcatsub(&y, ostr, aptr, x, xlen, NULL, globsubst, copied); @@ -1843,7 +1951,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (prenum || postnum) x = dopadding(x, prenum, postnum, preone, postone, premul, postmul); - if (eval && subst_parse_str(&x, (qt && !nojoin))) + if (eval && subst_parse_str(&x, (qt && !nojoin), quoteerr)) return NULL; if (qt && !*x && isarr != 2) y = dupstring(nulstring); @@ -1859,7 +1967,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (prenum || postnum) x = dopadding(x, prenum, postnum, preone, postone, premul, postmul); - if (eval && subst_parse_str(&x, (qt && !nojoin))) + if (eval && subst_parse_str(&x, (qt && !nojoin), quoteerr)) return NULL; xlen = strlen(x); *str = strcatsub(&y, aptr, aptr, x, xlen, fstr, globsubst, copied); @@ -1878,7 +1986,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (prenum || postnum) x = dopadding(x, prenum, postnum, preone, postone, premul, postmul); - if (eval && subst_parse_str(&x, (qt && !nojoin))) + if (eval && subst_parse_str(&x, (qt && !nojoin), quoteerr)) return NULL; xlen = strlen(x); *str = strcatsub(&y, ostr, aptr, x, xlen, fstr, globsubst, copied); @@ -1905,15 +2013,18 @@ static char * arithsubst(char *a, char **bptr, char *rest) { char *s = *bptr, *t; - char buf[DIGBUFSIZE], *b = buf; + char buf[BDIGBUFSIZE], *b = buf; mnumber v; singsub(&a); v = matheval(a); - if (v.type & MN_FLOAT) + if ((v.type & MN_FLOAT) && !outputradix) b = convfloat(v.u.d, 0, 0, NULL); - else - convbase(buf, v.u.l, 0); + else { + if (v.type & MN_FLOAT) + v.u.l = (zlong) v.u.d; + convbase(buf, v.u.l, outputradix); + } t = *bptr = (char *) hcalloc(strlen(*bptr) + strlen(b) + strlen(rest) + 1); t--; @@ -1975,7 +2086,7 @@ modify(char **str, char **ptr) if (*ptr1) { zsfree(hsubl); hsubl = ztrdup(ptr1); - } + } if (!hsubl) { zerr("no previous substitution", NULL, 0); return; diff --git a/Src/zsh.h b/Src/zsh.h index 41add5c35..3b6c0aad4 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -30,7 +30,6 @@ #define trashzle() trashzleptr() #define zleread(X,Y,H) zlereadptr(X,Y,H) #define spaceinline(X) spaceinlineptr(X) -#define gotword() gotwordptr() #define zrefresh() refreshptr() #define compctlread(N,A,O,R) compctlreadptr(N,A,O,R) @@ -234,31 +233,31 @@ enum { * below. */ enum { - WRITE, /* > */ - WRITENOW, /* >| */ - APP, /* >> */ - APPNOW, /* >>| */ - ERRWRITE, /* &>, >& */ - ERRWRITENOW, /* >&| */ - ERRAPP, /* >>& */ - ERRAPPNOW, /* >>&| */ - READWRITE, /* <> */ - READ, /* < */ - HEREDOC, /* << */ - HEREDOCDASH, /* <<- */ - HERESTR, /* <<< */ - MERGEIN, /* <&n */ - MERGEOUT, /* >&n */ - CLOSE, /* >&-, <&- */ - INPIPE, /* < <(...) */ - OUTPIPE /* > >(...) */ + REDIR_WRITE, /* > */ + REDIR_WRITENOW, /* >| */ + REDIR_APP, /* >> */ + REDIR_APPNOW, /* >>| */ + REDIR_ERRWRITE, /* &>, >& */ + REDIR_ERRWRITENOW, /* >&| */ + REDIR_ERRAPP, /* >>& */ + REDIR_ERRAPPNOW, /* >>&| */ + REDIR_READWRITE, /* <> */ + REDIR_READ, /* < */ + REDIR_HEREDOC, /* << */ + REDIR_HEREDOCDASH, /* <<- */ + REDIR_HERESTR, /* <<< */ + REDIR_MERGEIN, /* <&n */ + REDIR_MERGEOUT, /* >&n */ + REDIR_CLOSE, /* >&-, <&- */ + REDIR_INPIPE, /* < <(...) */ + REDIR_OUTPIPE /* > >(...) */ }; -#define IS_WRITE_FILE(X) ((X)>=WRITE && (X)<=READWRITE) +#define IS_WRITE_FILE(X) ((X)>=REDIR_WRITE && (X)<=REDIR_READWRITE) #define IS_APPEND_REDIR(X) (IS_WRITE_FILE(X) && ((X) & 2)) #define IS_CLOBBER_REDIR(X) (IS_WRITE_FILE(X) && ((X) & 1)) -#define IS_ERROR_REDIR(X) ((X)>=ERRWRITE && (X)<=ERRAPPNOW) -#define IS_READFD(X) (((X)>=READWRITE && (X)<=MERGEIN) || (X)==INPIPE) +#define IS_ERROR_REDIR(X) ((X)>=REDIR_ERRWRITE && (X)<=REDIR_ERRAPPNOW) +#define IS_READFD(X) (((X)>=REDIR_READWRITE && (X)<=REDIR_MERGEIN) || (X)==REDIR_INPIPE) #define IS_REDIROP(X) ((X)>=OUTANG && (X)<=TRINANG) /* Flags for input stack */ @@ -468,8 +467,8 @@ struct value { int isarr; Param pm; /* parameter node */ int inv; /* should we return the index ? */ - int a; /* first element of array slice, or -1 */ - int b; /* last element of array slice, or -1 */ + int start; /* first element of array slice, or -1 */ + int end; /* 1-rel last element of array slice, or -1 */ char **arr; /* cache for hash turned into array */ }; @@ -487,7 +486,8 @@ typedef struct eprog *Eprog; struct funcdump { FuncDump next; /* next in list */ - char *name; /* path name */ + dev_t dev; /* device */ + ino_t ino; /* indoe number */ int fd; /* file descriptor */ Wordcode map; /* pointer to header */ Wordcode addr; /* mapped region */ @@ -496,7 +496,7 @@ struct funcdump { }; struct eprog { - int alloc; /* EA_* below */ + int flags; /* EF_* below */ int len; /* total block length */ int npats; /* Patprog cache size */ Patprog *pats; /* the memory block, the patterns */ @@ -506,9 +506,10 @@ struct eprog { FuncDump dump; /* dump file this is in */ }; -#define EA_REAL 0 -#define EA_HEAP 1 -#define EA_MAP 2 +#define EF_REAL 1 +#define EF_HEAP 2 +#define EF_MAP 4 +#define EF_RUN 8 typedef struct estate *Estate; @@ -521,9 +522,9 @@ struct estate { typedef struct eccstr *Eccstr; struct eccstr { - Eccstr next; + Eccstr left, right; char *str; - wordcode offs; + wordcode offs, aoffs; int nfunc; }; @@ -659,8 +660,9 @@ struct eccstr { /* Defintions for job table and job control */ /********************************************/ -/* size of job table */ -#define MAXJOB 50 +#ifdef NEED_LINUX_TASKS_H +#include +#endif /* entry in the job table */ @@ -751,6 +753,8 @@ struct dirsav { ino_t ino; }; +#define MAX_PIPESTATS 256 + /*******************************/ /* Definitions for Hash Tables */ /*******************************/ @@ -953,6 +957,7 @@ struct module { union { void *handle; Linkedmod linked; + char *alias; } u; LinkList deps; int wrapper; @@ -964,6 +969,7 @@ struct module { #define MOD_LINKED (1<<3) #define MOD_INIT_S (1<<4) #define MOD_INIT_B (1<<5) +#define MOD_ALIAS (1<<6) typedef int (*Module_func) _((Module)); @@ -1019,6 +1025,8 @@ struct patprog { #define PAT_STATIC 0x0040 /* Don't copy pattern to heap as per default */ #define PAT_SCAN 0x0080 /* Scanning, so don't try must-match test */ #define PAT_ZDUP 0x0100 /* Copy pattern in real memory */ +#define PAT_NOTSTART 0x0200 /* Start of string is not real start */ +#define PAT_NOTEND 0x0400 /* End of string is not real end */ /* Globbing flags: lower 8 bits gives approx count */ #define GF_LCMATCHUC 0x0100 @@ -1111,20 +1119,22 @@ struct param { #define PM_UNALIASED (1<<13) /* do not expand aliases when autoloading */ #define PM_HIDE (1<<14) /* Special behaviour hidden by local */ -#define PM_TIED (1<<15) /* array tied to colon-path or v.v. */ +#define PM_HIDEVAL (1<<15) /* Value not shown in `typeset' commands */ +#define PM_TIED (1<<16) /* array tied to colon-path or v.v. */ /* Remaining flags do not correspond directly to command line arguments */ -#define PM_LOCAL (1<<16) /* this parameter will be made local */ -#define PM_SPECIAL (1<<17) /* special builtin parameter */ -#define PM_DONTIMPORT (1<<18) /* do not import this variable */ -#define PM_RESTRICTED (1<<19) /* cannot be changed in restricted mode */ -#define PM_UNSET (1<<20) /* has null value */ -#define PM_REMOVABLE (1<<21) /* special can be removed from paramtab */ -#define PM_AUTOLOAD (1<<22) /* autoloaded from module */ -#define PM_NORESTORE (1<<23) /* do not restore value of local special */ +#define PM_LOCAL (1<<17) /* this parameter will be made local */ +#define PM_SPECIAL (1<<18) /* special builtin parameter */ +#define PM_DONTIMPORT (1<<19) /* do not import this variable */ +#define PM_RESTRICTED (1<<20) /* cannot be changed in restricted mode */ +#define PM_UNSET (1<<21) /* has null value */ +#define PM_REMOVABLE (1<<22) /* special can be removed from paramtab */ +#define PM_AUTOLOAD (1<<23) /* autoloaded from module */ +#define PM_NORESTORE (1<<24) /* do not restore value of local special */ +#define PM_HASHELEM (1<<25) /* is a hash-element */ /* The option string corresponds to the first of the variables above */ -#define TYPESET_OPTSTR "aiEFALRZlurtxUhT" +#define TYPESET_OPTSTR "aiEFALRZlurtxUhHT" /* These typeset options take an optional numeric argument */ #define TYPESET_OPTNUM "LRZiEF" @@ -1138,6 +1148,7 @@ struct param { #define SCANPM_MATCHMANY (1<<5) #define SCANPM_ASSIGNING (1<<6) #define SCANPM_KEYMATCH (1<<7) +#define SCANPM_DQUOTED (1<<8) #define SCANPM_ISVAR_AT ((-1)<<15) /* Only sign bit is significant */ /* @@ -1205,13 +1216,14 @@ struct nameddir { #define PRINT_TYPE (1<<1) #define PRINT_LIST (1<<2) #define PRINT_KV_PAIR (1<<3) +#define PRINT_INCLUDEVALUE (1<<4) /* flags for printing for the whence builtin */ -#define PRINT_WHENCE_CSH (1<<4) -#define PRINT_WHENCE_VERBOSE (1<<5) -#define PRINT_WHENCE_SIMPLE (1<<6) -#define PRINT_WHENCE_FUNCDEF (1<<7) -#define PRINT_WHENCE_WORD (1<<8) +#define PRINT_WHENCE_CSH (1<<5) +#define PRINT_WHENCE_VERBOSE (1<<6) +#define PRINT_WHENCE_SIMPLE (1<<7) +#define PRINT_WHENCE_FUNCDEF (1<<9) +#define PRINT_WHENCE_WORD (1<<10) /***********************************/ /* Definitions for history control */ @@ -1240,6 +1252,7 @@ struct histent { #define HIST_READ 0x00000004 /* Command was read back from disk*/ #define HIST_DUP 0x00000008 /* Command duplicates a later line */ #define HIST_FOREIGN 0x00000010 /* Command came from another shell */ +#define HIST_TMPSTORE 0x00000020 /* Kill when user enters another cmd */ #define GETHIST_UPWARD (-1) #define GETHIST_DOWNWARD 1 @@ -1294,6 +1307,7 @@ struct histent { enum { OPT_INVALID, + ALIASESOPT, ALLEXPORT, ALWAYSLASTPROMPT, ALWAYSTOEND, @@ -1315,6 +1329,7 @@ enum { BGNICE, BRACECCL, BSDECHO, + CBASES, CDABLEVARS, CHASEDOTS, CHASELINKS, @@ -1336,8 +1351,9 @@ enum { EXTENDEDHISTORY, FLOWCONTROL, FUNCTIONARGZERO, - GLOBALRCS, GLOBOPT, + GLOBALEXPORT, + GLOBALRCS, GLOBASSIGN, GLOBCOMPLETE, GLOBDOTS, @@ -1367,6 +1383,7 @@ enum { KSHAUTOLOAD, KSHGLOB, KSHOPTIONPRINT, + KSHTYPESET, LISTAMBIGUOUS, LISTBEEP, LISTPACKED, @@ -1386,6 +1403,7 @@ enum { NOTIFY, NULLGLOB, NUMERICGLOBSORT, + OCTALZEROES, OVERSTRIKE, PATHDIRS, POSIXBUILTINS, @@ -1422,6 +1440,7 @@ enum { VERBOSE, XTRACE, USEZLE, + DVORAK, OPT_SIZE }; @@ -1508,7 +1527,11 @@ struct ttyinfo { #define TCSTANDOUTEND 22 #define TCUNDERLINEEND 23 #define TCHORIZPOS 24 -#define TC_COUNT 25 +#define TCUPCURSOR 25 +#define TCDOWNCURSOR 26 +#define TCLEFTCURSOR 27 +#define TCRIGHTCURSOR 28 +#define TC_COUNT 29 #define tccan(X) (tclen[X]) @@ -1612,13 +1635,11 @@ struct heap { #endif ; -# define LASTALLOC_RETURN return - # define NEWHEAPS(h) do { Heap _switch_oldheaps = h = new_heaps(); do # define OLDHEAPS while (0); old_heaps(_switch_oldheaps); } while (0); -# define SWITCHHEAPS(h) do { Heap _switch_oldheaps = switch_heaps(h); do -# define SWITCHBACKHEAPS while (0); switch_heaps(_switch_oldheaps); } while (0); +# define SWITCHHEAPS(o, h) do { o = switch_heaps(h); do +# define SWITCHBACKHEAPS(o) while (0); switch_heaps(o); } while (0); /****************/ /* Debug macros */ @@ -1665,12 +1686,6 @@ typedef void (*ZleVoidFn) _((void)); typedef void (*ZleVoidIntFn) _((int)); typedef unsigned char * (*ZleReadFn) _((char *, char *, int)); -/***************************************/ -/* Pseudo-keyword to mark exportedness */ -/***************************************/ - -#define mod_export - /***************************************/ /* Hooks in core. */ /***************************************/ diff --git a/Test/E01options.ztst b/Test/E01options.ztst new file mode 100644 index 000000000..8ffba78b7 --- /dev/null +++ b/Test/E01options.ztst @@ -0,0 +1,616 @@ +# Test various shell options. +# Interactive options not tested here: +# ALWAYS_LAST_PROMPT +# ALWAYS_TO_END +# APPEND_HISTORY (history not maintained) +# AUTO_LIST +# AUTO_MENU +# AUTO_NAME_DIRS (named directory table not maintained) +# AUTO_PARAM_KEYS +# AUTO_PARAM_SLASH +# AUTO_REMOVE_SLASH +# AUTO_RESUME +# BANG_HIST +# BASH_AUTO_LIST +# BEEP (!) +# BG_NICE +# CHECK_JOBS +# COMPLETE_ALIASES +# COMPLETE_IN_WORD +# CORRECT +# CORRECT_ALL +# CSH_JUNKIE_HISTORY +# DVORAK +# EXTENDED_HISTORY +# FLOW_CONTROL +# GLOB_COMPLETE +# HIST_ALLOW_CLOBBER +# HIST_BEEP +# HIST_EXPIRE_DUPS_FIRST +# HIST_FIND_NO_DUPS +# HIST_IGNORE_ALL_DUPS +# HIST_IGNORE_DUPS (-h) +# HIST_IGNORE_SPACE (-g) +# HIST_NO_FUNCTIONS +# HIST_NO_STORE +# HIST_REDUCE_BLANKS +# HIST_SAVE_NO_DUPS +# HIST_VERIFY +# HUP +# IGNORE_EOF +# INC_APPEND_HISTORY +# INTERACTIVE +# INTERACTIVE_COMMENTS +# LIST_AMBIGUOUS +# LIST_BEEP +# LIST_PACKED +# LIST_ROWS_FIRST +# LIST_TYPES +# LOGIN +# LONG_LIST_JOBS +# MAIL_WARNING +# MENU_COMPLETE +# MONITOR +# NOTIFY +# The following require SHINSTDIN and are not (yet) tested: +# AUTO_CD +# +# Other difficult things I haven't done: +# GLOBAL_RCS (uses fixed files outside build area) +# HASH_CMDS ) +# HASH_DIRS ) fairly seriously internal, hard to test at all +# HASH_LIST_ALL ) + +%prep + mkdir options.tmp && cd options.tmp + mkdir tmpcd + touch tmpfile1 tmpfile2 + mydir=$PWD + catpath=$(which cat) + +%test + + alias echo='print foo' + unsetopt aliases + # use eval else aliases are all parsed at start + eval echo bar + setopt aliases + eval echo bar + unalias echo +0:ALIASES option +>bar +>foo bar + + setopt allexport + testpm1=exported + unsetopt allexport + testpm2=unexported + print ${(t)testpm1} + print ${(t)testpm2} +0:ALL_EXPORT option +>scalar-export +>scalar + + # Count the number of directories on the stack. Don't care what they are. + dircount() { dirs -v | tail -1 | awk '{ print $1 + 1}'; } + unsetopt autopushd + cd tmpcd + dircount + cd .. + setopt autopushd + cd tmpcd + dircount + cd .. + unsetopt autopushd +0:AUTO_PUSHD option +>1 +>2 + + unsetopt badpattern + print [a + setopt badpattern + print [b +1:BAD_PATTERN option +>[a +?ZTST_execchunk:2: bad pattern: [b + + unsetopt bareglobqual nomatch + print *(.) + setopt bareglobqual nomatch + print *(.) +0:BARE_GLOB_QUAL option +>*(.) +>tmpfile1 tmpfile2 + + setopt braceccl + print {abcd} + unsetopt braceccl + print {abcd} +0:BRACE_CCL option +>a b c d +>{abcd} + + setopt bsdecho + echo "histon\nimpington" + echo -e "girton\ncottenham" + unsetopt bsdecho + echo "newnham\ncomberton" +0:BSD_ECHO option +>histon\nimpington +>girton +>cottenham +>newnham +>comberton + + unsetopt c_bases + print $(( [#16]15 )) + print $(( [#8]9 )) + setopt c_bases + print $(( [#16]31 )) + print $(( [#8]17 )) + setopt octal_zeroes + print $(( [#8]19 )) + unsetopt c_bases octal_zeroes +0:C_BASES option +>16#F +>8#11 +>0x1F +>8#21 +>023 + + setopt cdablevars + # only absolute paths are eligible for ~-expansion + cdablevar1=tmpcd + (cd cdablevar1) + cdablevar2=$PWD/tmpcd + cd cdablevar2 + cd .. + print back in ${PWD:t} + unsetopt cdablevars + cd cdablevar2 +1q:CDABLE_VARS option +>`print -P '%~'`/tmpcd +>back in options.tmp +?ZTST_execchunk:cd:2: no such file or directory: cdablevar1 +?ZTST_execchunk:cd:2: no such file or directory: cdablevar2 + +# CHASE_DOTS should go with CHASE_LINKS in B01cd.ztst +# which saves me having to write it here. + + setopt noclobber + rm -f foo1 bar1 rod1 + echo waterbeach >foo1 + (echo landbeach >foo1) + cat foo1 + (echo lode >>bar1) + [[ -f bar1 ]] && print That shouldn\'t be there. + echo denny >rod1 + echo wicken >>rod1 + cat rod1 + unsetopt noclobber + rm -f foo2 bar2 rod2 + echo ely >foo2 + echo march >foo2 + cat foo2 + echo wimpole >>bar2 + cat bar2 + echo royston >rod2 + echo foxton >>rod2 + cat rod2 + rm -f foo* bar* rod* +0:CLOBBER option +>waterbeach +>denny +>wicken +>march +>wimpole +>royston +>foxton +?ZTST_execchunk:2: file exists: foo1 +?ZTST_execchunk:2: no such file or directory: bar1 + + setopt cshjunkieloops + eval 'for f in swaffham bulbeck; print $f; end' + print next one should fail >&2 + unsetopt cshjunkieloops + eval 'for f in chesterton arbury; print $f; end' +1:CSH_JUNKIE_LOOPS option (for loop) +>swaffham +>bulbeck +?next one should fail +?ZTST_execchunk:-1: parse error near `end' + + setopt cshjunkiequotes + print this should cause an error >&2 + eval "print 'line one + line two'" + print this should not >&2 + eval "print 'line three\\ + line four'" + unsetopt cshjunkiequotes +0:CSH_JUNKIE_QUOTES option +>line three +> line four +?this should cause an error +?ZTST_execchunk:-1: unmatched ' +?this should not + + nullcmd() { print '$NULLCMD run'; } + readnullcmd() { print 'Running $READNULLCMD'; cat; } + NULLCMD=nullcmd + READNULLCMD=readnullcmd + setopt cshnullcmd + rm -f foo + print "This should fail" >&2 + (>foo) + print "This should succeed" >&2 + print "These are the contents of foo" >foo + cat foo + print "This should also fail" >&2 + (foo + These are the contents of foo +>Running $READNULLCMD +>$NULLCMD run +?This should fail +?ZTST_execchunk:2: redirection with no command +?This should succeed +?This should also fail +?ZTST_execchunk:2: redirection with no command + +# nomatch should be overridden by cshnullglob + setopt nomatch cshnullglob + print tmp* nothing* blah + print -n 'hoping for no match: ' >&2 + (print nothing* blah) + print >&2 + unsetopt cshnullglob nomatch + print tmp* nothing* blah + print nothing* blah +0:CSH_NULL_GLOB option +>tmpcd tmpfile1 tmpfile2 blah +>tmpcd tmpfile1 tmpfile2 nothing* blah +>nothing* blah +?hoping for no match: ZTST_execchunk:2: no match +? + +# The trick is to avoid =cat being expanded in the output while $catpath is. + setopt NO_equals + print -n trick; print =cat + setopt equals + print -n trick; print =cat +0q:EQUALS option +>trick=cat +>trick$catpath + +# explanation of expected TRAPZERR output: from false and from +# testfn() with ERR_EXIT on (hmm, should we really get a second one from +# the function exiting?), then from the false only with ERR_EXIT off. + TRAPZERR() { print ZERR trapped; } + testfn() { setopt localoptions $2; print $1 before; false; print $1 after; } + (testfn on errexit) + testfn off + unfunction TRAPZERR testfn +0:ERR_EXIT option +>on before +>ZERR trapped +>ZERR trapped +>off before +>ZERR trapped +>off after + + (print before; setopt noexec; print after) +0:NO_EXEC option +>before + + # The EXTENDED_GLOB test doesn't test globbing fully --- it just tests + # that certain patterns are treated literally with the option off + # and as patterns with the option on. + testfn() { print -n "$1 $2 $3 "; if [[ $1 = ${~2} ]]; + then print yes; else print no; fi; } + tests=('a#' '?~b' '^aa') + strings=('a' 'aa' 'b' 'a#' '?~b' '^aa') + for opt in noextendedglob extendedglob; do + setopt $opt + for test in $tests; do + for string in $strings; do + testfn $string $test $opt + done + done + done +0:EXTENDED_GLOB option +>a a# noextendedglob no +>aa a# noextendedglob no +>b a# noextendedglob no +>a# a# noextendedglob yes +>?~b a# noextendedglob no +>^aa a# noextendedglob no +>a ?~b noextendedglob no +>aa ?~b noextendedglob no +>b ?~b noextendedglob no +>a# ?~b noextendedglob no +>?~b ?~b noextendedglob yes +>^aa ?~b noextendedglob no +>a ^aa noextendedglob no +>aa ^aa noextendedglob no +>b ^aa noextendedglob no +>a# ^aa noextendedglob no +>?~b ^aa noextendedglob no +>^aa ^aa noextendedglob yes +>a a# extendedglob yes +>aa a# extendedglob yes +>b a# extendedglob no +>a# a# extendedglob no +>?~b a# extendedglob no +>^aa a# extendedglob no +>a ?~b extendedglob yes +>aa ?~b extendedglob no +>b ?~b extendedglob no +>a# ?~b extendedglob no +>?~b ?~b extendedglob no +>^aa ?~b extendedglob no +>a ^aa extendedglob yes +>aa ^aa extendedglob no +>b ^aa extendedglob yes +>a# ^aa extendedglob yes +>?~b ^aa extendedglob yes +>^aa ^aa extendedglob yes + + foo() { print My name is $0; } + unsetopt functionargzero + foo + setopt functionargzero + foo + unfunction foo +0:FUNCTION_ARGZERO option +>My name is ZTST_execchunk +>My name is foo + + setopt _NO_glob_ + print tmp* + set -o glob + print tmp* +0:GLOB option +>tmp* +>tmpcd tmpfile1 tmpfile2 + + showit() { local v; + for v in first second third; do + eval print \$$v \$\{\(t\)$v\} + done; + } + setit() { typeset -x first=inside1; + typeset +g -x second=inside2; + typeset -g -x third=inside3; + showit; + } + first=outside1 second=outside2 third=outside3 + unsetopt globalexport + setit + showit + setopt globalexport + setit + showit + unfunction setit showit +0:GLOBAL_EXPORT option +>inside1 scalar-local-export +>inside2 scalar-local-export +>inside3 scalar-export +>outside1 scalar +>outside2 scalar +>inside3 scalar-export +>inside1 scalar-export +>inside2 scalar-local-export +>inside3 scalar-export +>inside1 scalar-export +>outside2 scalar +>inside3 scalar-export + + setopt globassign + foo=tmp* + print $foo + unsetopt globassign + foo=tmp* + print $foo +0:GLOB_ASSIGN option +>tmpcd tmpfile1 tmpfile2 +>tmp* + + mkdir onlysomefiles + touch onlysomefiles/.thisfile onlysomefiles/thatfile + setopt globdots + print onlysomefiles/* + unsetopt globdots + print onlysomefiles/* + rm -rf onlysomefiles +0:GLOB_DOTS option +>onlysomefiles/.thisfile onlysomefiles/thatfile +>onlysomefiles/thatfile + + # we've tested this enough times already... + # could add some stuff for other sorts of expansion + foo='tmp*' + setopt globsubst + print ${foo} + unsetopt globsubst + print ${foo} +0:GLOB_SUBST option +>tmpcd tmpfile1 tmpfile2 +>tmp* + + setopt ignorebraces + echo X{a,b}Y + unsetopt ignorebraces + echo X{a,b}Y +0:IGNORE_BRACES option +>X{a,b}Y +>XaY XbY + + setopt ksh_arrays + array=(one two three) + print $array $array[2] + print ${array[0]} ${array[1]} ${array[2]} ${array[3]} + unsetopt ksh_arrays + print $array $array[2] + print ${array[0]} ${array[1]} ${array[2]} ${array[3]} + unset array +0:KSH_ARRAYS option +>one one[2] +>one two three +>one two three two +>one one two three + + fpath=(.) + echo >foo 'echo foo loaded; foo() { echo foo run; }' + echo >bar 'bar() { echo bar run; }' + setopt kshautoload + autoload foo bar + foo + bar + unfunction foo bar + unsetopt kshautoload + autoload foo bar + foo + bar +0:KSH_AUTOLOAD option +>foo loaded +>foo run +>bar run +>foo loaded +>bar run + +# ksh_glob is tested by the glob tests. + + setopt kshoptionprint globassign + print set + setopt | grep kshoptionprint + setopt | grep globassign + unsetopt kshoptionprint + print unset + setopt | grep kshoptionprint + setopt | grep globassign + unsetopt globassign +0:KSH_OPTION_PRINT option +>set +>kshoptionprint on +>globassign on +>unset +>globassign + + setopt kshtypeset + ktvars=(ktv1 ktv2) + typeset ktfoo=`echo arg1 arg2` $ktvars + print $+ktv1 $+ktv2 $+ktv3 + print $ktfoo + unsetopt kshtypeset + typeset noktfoo=`echo noktarg1 noktarg2` + print $noktfoo + print $+noktarg1 $+noktarg2 + unset ktfoo ktv1 ktv2 noktfoo noktarg2 +0:KSH_TYPESET option +>1 1 0 +>arg1 arg2 +>noktarg1 +>0 1 + + showopt() { setopt | egrep 'localoptions|ksharrays'; } + f1() { setopt localoptions ksharrays; showopt } + f2() { setopt ksharrays; showopt } + setopt kshoptionprint + showopt + f1 + showopt + f2 + showopt + unsetopt ksh_arrays +0:LOCAL_OPTIONS option +>ksharrays off +>localoptions off +>ksharrays on +>localoptions on +>ksharrays off +>localoptions off +>ksharrays on +>localoptions off +>ksharrays on +>localoptions off + +# LOCAL_TRAPS was tested in C03traps (phew). + + fn() { + local HOME=/any/old/name + print -l var=~ 'anything goes/here'=~ split=`echo maybe not`; + } + setopt magicequalsubst + fn + setopt kshtypeset + fn + unsetopt magicequalsubst kshtypeset + fn +0:MAGIC_EQUAL_SUBST option +>var=/any/old/name +>anything goes/here=/any/old/name +>split=maybe +>not +>var=/any/old/name +>anything goes/here=/any/old/name +>split=maybe not +>var=~ +>anything goes/here=~ +>split=maybe +>not + + setopt MARK_DIRS + print tmp* + unsetopt MARK_DIRS + print tmp* +0:MARK_DIRS option +>tmpcd/ tmpfile1 tmpfile2 +>tmpcd tmpfile1 tmpfile2 + +# maybe should be in A04redirect + print "This is in1" >in1 + print "This is in2" >in2 + unsetopt multios + print Test message >foo1 >foo2 + print foo1: $(foo1 >foo2 + sleep 1 # damn, race in multios + print foo1: $(foo1: +>foo2: Test message +>This is in2 +>foo1: Test message +>foo2: Test message +>This is in1 +>This is in2 + +# tried this with other things, but not on its own, so much. + unsetopt nomatch + print with nonomatch: flooble* + setopt nomatch + print with nomatch flooble* +1:NOMATCH option +>with nonomatch: flooble* +?ZTST_execchunk:2: no matches found: flooble* + +# NULL_GLOB should override NONOMATCH... + setopt nullglob nomatch + print frooble* tmp* + unsetopt nullglob nomatch + print frooble* tmp* +0:NULL_GLOB option +>tmpcd tmpfile1 tmpfile2 +>frooble* tmpcd tmpfile1 tmpfile2 -- cgit 1.4.1