From d1fc7aafc77a15c150a139849536e1618f48ff94 Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Thu, 10 Feb 2000 11:56:36 +0000 Subject: zsh-workers/9648 --- Completion/Core/_files | 21 +-- Completion/Core/_multi_parts | 10 +- Completion/Core/_path_files | 26 ++- Completion/Core/_sep_parts | 8 +- Doc/Zsh/mod_zutil.yo | 53 ++++-- Src/Modules/zutil.c | 374 ++++++++++++++++++++++++++++++++++--------- 6 files changed, 366 insertions(+), 126 deletions(-) diff --git a/Completion/Core/_files b/Completion/Core/_files index f02ac7c38..ab35b7f05 100644 --- a/Completion/Core/_files +++ b/Completion/Core/_files @@ -3,10 +3,9 @@ local opts opt type=file glob group gopts dopts aopts tmp _file_pat_checked=yes local hasign ign -zparseopts \ - /tmp ftmp g+tmp \ - qopts nopts 1opts 2opts P:opts S:opts r:opts R:opts W:opts X:opts M:opts \ - F:opts J:group V:group +zparseopts -a opts \ + '/=tmp' 'f=tmp' 'g+:-=tmp' q n 1 2 P: S: r: R: W: X: M: F: \ + 'J:=group' 'V:=group' type="${(@j::M)${(@)tmp#-}#?}" [[ -n "$type" ]] || type=f @@ -15,13 +14,15 @@ if (( $tmp[(I)-g*] )); then else gopts=() fi -(( $opts[(I)-F*] )) && hasign=yes +(( $opts[(I)-F] )) && hasign=yes -if [[ "$group[1]" = -?files ]]; then +if [[ "$group[2]" = files ]]; then opts=("$opts[@]" "$group[@]") group=() fi +ign=() + if zstyle -s ":completion:${curcontext}:all-files" file-patterns tmp && [[ -n "$tmp" ]]; then aopts=(-g "$tmp") @@ -58,7 +59,7 @@ esac while _tags; do if _requested all-files; then if (( $#group )); then - group[1]="${group[1][1,2]}all-files" + group[2]=all-files _setup all-files [[ -z "$hasign" ]] && zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore && @@ -69,7 +70,7 @@ while _tags; do elif _requested directories; then if _requested globbed-files; then if (( $#group )); then - group[1]="${group[1][1,2]}globbed-files" + group[2]=globbed-files _setup globbed-files [[ -z "$hasign" ]] && zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore && @@ -78,7 +79,7 @@ while _tags; do _path_files "$opts[@]" "$ign[@]" "$dopts[@]" "$gopts[@]" && return 0 else if (( $#group )); then - group[1]="${group[1][1,2]}directories" + group[2]=directories _setup directories [[ -z "$hasign" ]] && zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore && @@ -88,7 +89,7 @@ while _tags; do fi elif _requested globbed-files; then if (( $#group )); then - group[1]="${group[1][1,2]}globbed-files" + group[2]=globbed-files _setup globbed-files [[ -z "$hasign" ]] && zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore && diff --git a/Completion/Core/_multi_parts b/Completion/Core/_multi_parts index 61bd3acaf..6aa6da064 100644 --- a/Completion/Core/_multi_parts +++ b/Completion/Core/_multi_parts @@ -13,15 +13,13 @@ typeset -U tmp2 # Get the options. -zparseopts -D \ - J:group V:group X:expl \ - P:opts F:opts \ - S:sopts r:sopts R:sopts qsopts 1sopts 2sopts nsopts \ - M:match +zparseopts -D -a sopts \ + 'J:=group' 'V:=group' 'X:=expl' 'P:=opts' 'F:=opts' \ + S: r: R: q 1 2 n 'M:=match' sopts=( "$sopts[@]" "$opts[@]" ) if (( $#match )); then - match="${match[1][3,-1]}" + match="${match[2]}" else match='' fi diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files index 2e226eaf3..0ec311c64 100644 --- a/Completion/Core/_path_files +++ b/Completion/Core/_path_files @@ -17,11 +17,10 @@ exppaths=() # Get the options. -zparseopts \ - P:pfxsfx S:pfxsfx qpfxsfx r:pfxsfx R:pfxsfx \ - W:prepaths F:ignore M+matcher \ - J:mopts V:mopts X:mopts 1:mopts 2:mopts n:mopts \ - ftmp1 /tmp1 g+tmp1 +zparseopts -a mopts \ + 'P:=pfxsfx' 'S:=pfxsfx' 'q=pfxsfx' 'r:=pfxsfx' 'R:=pfxsfx' \ + 'W:=prepaths' 'F:=ignore' 'M+=matcher' \ + J: V: X: 1: 2: n: 'f=tmp1' '/=tmp1' 'g+:-=tmp1' sopt="-${(@j::M)${(@)tmp1#-}#?}" (( $tmp1[(I)-[/g]*] )) && haspats=yes @@ -33,7 +32,7 @@ else fi if (( $#prepaths )); then - tmp1="${prepaths[1][3,-1]}" + tmp1="${prepaths[2]}" if [[ "$tmp1[1]" = '(' ]]; then prepaths=( ${^=tmp1[2,-2]%/}/ ) elif [[ "$tmp1[1]" = '/' ]]; then @@ -48,15 +47,14 @@ else fi if (( $#ignore )); then - tmp1="${ignore[1][3,-1]}" - if [[ "$tmp1[1]" = '(' ]]; then - ignore=( ${=tmp1[2,-2]} ) + if [[ "${ignore[2]}" = \(* ]]; then + ignore=( ${=ignore[2][2,-2]} ) else - ignore=( ${(P)tmp1} ) + ignore=( ${(P)ignore[2]} ) fi fi -(( $#matcher )) && mspec="${matcher[1][3,-1]}" +(( $#matcher )) && mspec="${matcher[2]}" if [[ -z "$_file_pat_checked" ]] && zstyle -s ":completion:${curcontext}:files" file-patterns tmp1 && @@ -84,7 +82,7 @@ if [[ "$sopt" = -(f|) ]]; then fi fi -if (( ! $mopts[(I)-[JVX]*] )); then +if (( ! $mopts[(I)-[JVX]] )); then local expl if [[ -z "$gopt" && "$sopt" = -/ ]]; then @@ -165,7 +163,7 @@ eorig="$orig" if (( $#ignore )); then _comp_ignore=( "$_comp_ignore[@]" "$ignore[@]" ) - (( $mopts[(I)-F*] )) || mopts=( "$mopts[@]" -F _comp_ignore ) + (( $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore ) fi # Now let's have a closer look at the string to complete. @@ -371,7 +369,7 @@ for prepath in "$prepaths[@]"; do [[ "$i" -ef "$PWD" ]] && _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" ) done fi - (( $#_comp_ignore && $mopts[(I)-F*] )) || mopts=( "$mopts[@]" -F _comp_ignore ) + (( $#_comp_ignore && $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore ) fi # Step over to the next component, if any. diff --git a/Completion/Core/_sep_parts b/Completion/Core/_sep_parts index cff34db0c..f3b73444e 100644 --- a/Completion/Core/_sep_parts +++ b/Completion/Core/_sep_parts @@ -22,13 +22,11 @@ local matchflags opt group expl nm=$compstate[nmatches] opre osuf opts match # Get the options. -zparseopts -D \ - J:group V:group \ - P:opts F:opts S:opts r:opts R:opts qopts 1opts 2opts nopts \ - X:expl M:match +zparseopts -D -a opts \ + 'J:=group' 'V=:group' P: F: S: r: R: q 1 2 n 'X:=expl' 'M:=match' if (( $#match )); then - match="${match[1][3,-1]}" + match="${match[2]}" else match='' fi diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo index c488f8b02..e72a2b712 100644 --- a/Doc/Zsh/mod_zutil.yo +++ b/Doc/Zsh/mod_zutil.yo @@ -111,28 +111,47 @@ The resulting strings are stored in the var(array). item(tt(zregexparse))( This implements the internals of the `tt(_regex_arguments)'. ) -item(tt(zparseopts) [ tt(-D) ] var(specs))( -This builtin can be used to parse the positional arguments and put -options found in them into separate arrays. Each var(spec) describes -one option which is given as its first character. If the second -character is either `tt(:)' or `tt(+)', the option takes an argument -(either directly following the option in the same word or in the next -word). After the option character or the `tt(:)' or `tt(+)' follows -the name of the array in which the option should be stored. The only -difference between the form with a `t(:)' and the one with a `tt(+)' -is that in the first case the option and its argument will be put in -the array only once (later occurrences overwriting earlier ones), -whereas with `tt(+)' all occurrences are moved to the array. +item(tt(zparseopts) [ tt(-D) ] [ tt(-a) var(array) ] [ tt(-A) var(assoc) ] var(specs))( +This builtin simplifies the parsing of options in the positional +parameters. Each var(spec) describes one option and should be of the +form `var(name)[tt(+)][tt(:)[tt(:)][tt(-)]][tt(=)var(array)]'. The var(name) +is the name of the option (without the leading `tt(-)'). If only that +is given, the option takes no argument and if it is found in the +positional parameters it will be placed in the var(array) given with +the tt(-a) option. If the optional `tt(=)var(array)' is given, it will +be put into that array instead. If one or two colons are given, the +option takes an argument. With one colon, this argument is mandatory +and with two colons it is optional. The argument will be inserted into +the var(array), too. For mandatory arguments it is added as a separate +string and for optional arguments it is put into one string together +with the option name unless the `tt(-)' option is given. In this case +the argument will be put into the same word even for mandatory +arguments (note that this makes empty strings as arguments +indistinguishable). Finally, if the `tt(+)' is given and the option +appears more than once in the positional parameters, it will be +inserted more than once in the var(array), too. Without the `tt(+)' +the option will be inserted only once in the var(array) with arguments +of later options overwriting earlier once. If any of the special +character needs to appear in the option name it must be preceded by a +backslash. + +If the tt(-A) option is given, the options and their values will also +be put into an associative array with the option names as keys and the +arguments (if any) as the values. Note that it is an error to give +var(specs) without a `tt(=)var(array)' and not use either the tt(-a) +or tt(-A) option. If the tt(-D) option is given, all options found are removed from the -positional parameters leaving only those strings that did not match -any of the var(specs). +positional parameters leaving only the strings from the first one that +was not described by any of the var(specs) to the last (note that this +is the usual rule used by tt(zparseopts) to find out when to stop +processing options). -For example, calling `tt(zparseopts afoo b:bar c+bar)' with the +For example, calling `tt(zparseopts a=foo b:=bar c+:=bar)' with the strings `tt(-a)', `tt(-bx)', `tt(-c)', `tt(y)', `tt(-cz)', `tt(baz)' and `tt(-cend)' as positional arguments will set the array tt(foo) to contain the element `tt(-a)' and the array tt(bar) to the strings -`tt(-bx)', `tt(-cy)' and `tt(-cz)'. The `tt(baz)' and any strings -after it will not be used. +`tt(-b)', `tt(x)', `tt(-c)', `tt(y)', `tt(-c)', and `tt(z)'. The +`tt(baz)' and all strings after it will not be used. ) enditem() diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 56b22b5f9..6631fc123 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -1160,27 +1160,59 @@ typedef struct zoptarr *Zoptarr; typedef struct zoptval *Zoptval; struct zoptdesc { - int arg; + Zoptdesc next; + char *name; + int flags; Zoptarr arr; + Zoptval vals, last; }; +#define ZOF_ARG 1 +#define ZOF_OPT 2 +#define ZOF_MULT 4 +#define ZOF_SAME 8 + struct zoptarr { + Zoptarr next; char *name; Zoptval vals, last; - Zoptarr next; int num; }; -#define ZOF_ARG 1 -#define ZOF_ADD 2 - struct zoptval { + Zoptval next, onext; + char *name; + char *arg; char *str; - Zoptval next; }; +static Zoptdesc opt_descs; static Zoptarr opt_arrs; +static Zoptdesc +get_opt_desc(char *name) +{ + Zoptdesc p; + + for (p = opt_descs; p; p = p->next) + if (!strcmp(name, p->name)) + return p; + + return NULL; +} + +static Zoptdesc +lookup_opt(char *str) +{ + Zoptdesc p; + + for (p = opt_descs; p; p = p->next) { + if ((p->flags & ZOF_ARG) ? strpfx(p->name, str) : !strcmp(p->name, str)) + return p; + } + return NULL; +} + static Zoptarr get_opt_arr(char *name) { @@ -1193,89 +1225,290 @@ get_opt_arr(char *name) return NULL; } +static void +add_opt_val(Zoptdesc d, char *arg) +{ + Zoptval v = NULL; + char *n = dyncat("-", d->name); + int new = 0; + + if (!(d->flags & ZOF_MULT)) + v = d->vals; + if (!v) { + v = (Zoptval) zhalloc(sizeof(*v)); + v->next = v->onext = NULL; + v->name = n; + new = 1; + } + v->arg = arg; + if ((d->flags & ZOF_ARG) && !(d->flags & (ZOF_OPT | ZOF_SAME))) { + v->str = NULL; + if (d->arr) + d->arr->num += (arg ? 2 : 1); + } else if (arg) { + char *s = (char *) zhalloc(strlen(d->name) + strlen(arg) + 2); + + *s = '-'; + strcpy(s + 1, d->name); + strcat(s, arg); + v->str = s; + if (d->arr) + d->arr->num += 1; + } else { + v->str = NULL; + if (d->arr) + d->arr->num += 1; + } + if (new) { + if (d->arr) { + if (d->arr->last) + d->arr->last->next = v; + else + d->arr->vals = v; + d->arr->last = v; + } + if (d->last) + d->last->onext = v; + else + d->vals = v; + d->last = v; + } +} + static int bin_zparseopts(char *nam, char **args, char *ops, int func) { - char *o, *n, **pp, *str, **aval; - Zoptdesc opts[256], d; - Zoptarr a; + char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL; + int del = 0, f; + Zoptdesc sopts[256], d; + Zoptarr a, defarr = NULL; Zoptval v; - memset(opts, 0, 256 * sizeof(Zoptdesc)); + opt_descs = NULL; opt_arrs = NULL; + memset(sopts, 0, 256 * sizeof(Zoptdesc)); while ((o = *args++)) { - if (opts[STOUC(*o)]) { - zerrnam(nam, "option described more than once: %s", o, 0); + if (*o == '-') { + switch (o[1]) { + case '\0': + o = NULL; + break; + case '-': + if (o[2]) + args--; + o = NULL; + break; + case 'D': + if (o[2]) { + args--; + o = NULL; + break; + } + del = 1; + break; + case 'a': + if (defarr) { + zerrnam(nam, "default array given more than once", NULL, 0); + return 1; + } + if (o[2]) + n = o + 2; + else if (*args) + n = *args++; + else { + zerrnam(nam, "missing array name", NULL, 0); + return 1; + } + defarr = (Zoptarr) zhalloc(sizeof(*defarr)); + defarr->name = n; + defarr->num = 0; + defarr->vals = defarr->last = NULL; + defarr->next = NULL; + opt_arrs = defarr; + break; + case 'A': + if (o[2]) + assoc = o + 2; + else if (*args) + assoc = *args++; + else { + zerrnam(nam, "missing array name", NULL, 0); + return 1; + } + break; + } + if (!o) + break; + } else { + args--; + break; + } + } + while ((o = dupstring(*args++))) { + if (!*o) { + zerrnam(nam, "invalid option description: %s", o, 0); return 1; } - d = (Zoptdesc) zhalloc(sizeof(*d)); - d->arg = (o[1] == ':' ? ZOF_ARG : (o[1] == '+' ? ZOF_ADD : 0)); - if (!(a = get_opt_arr((n = o + (d->arg ? 2 : 1))))) { - a = (Zoptarr) zhalloc(sizeof(*a)); - a->name = n; - a->num = 0; - a->vals = a->last = NULL; - a->next = opt_arrs; - opt_arrs = a; + f = 0; + for (p = o; *p; p++) { + if (*p == '\\' && p[1]) + p++; + else if (*p == '+') { + f |= ZOF_MULT; + *p = '\0'; + p++; + break; + } else if (*p == ':' || *p == '=') + break; + } + if (*p == ':') { + f |= ZOF_ARG; + *p = '\0'; + if (*++p == ':') { + p++; + f |= ZOF_OPT; + } + if (*p == '-') { + p++; + f |= ZOF_SAME; + } + } + a = NULL; + if (*p == '=') { + *p++ = '\0'; + if (!(a = get_opt_arr(p))) { + a = (Zoptarr) zhalloc(sizeof(*a)); + a->name = p; + a->num = 0; + a->vals = a->last = NULL; + a->next = opt_arrs; + opt_arrs = a; + } + } else if (*p) { + zerrnam(nam, "invalid option description: %s", args[-1], 0); + return 1; + } else if (!(a = defarr) && !assoc) { + zerrnam(nam, "no default array defined: %s", args[-1], 0); + return 1; + } + for (p = n = o; *p; p++) { + if (*p == '\\' && p[1]) + p++; + *n++ = *p; + } + if (get_opt_desc(o)) { + zerrnam(nam, "option defined more than once: %s", o, 0); + return 1; } + d = (Zoptdesc) zhalloc(sizeof(*d)); + d->name = o; + d->flags = f; d->arr = a; - opts[STOUC(*o)] = d; + d->next = opt_descs; + d->vals = d->last = NULL; + opt_descs = d; + if (!o[1]) + sopts[STOUC(*o)] = d; } for (pp = pparams; (o = *pp); pp++) { if (*o != '-') break; - while (*++o) { - if (!(d = opts[STOUC(*o)])) - break; - if (d->arg) { - if (o[1]) { - str = (char *) zhalloc(strlen(o) + 2); - str[0] = '-'; - strcpy(str + 1, o); - } else if (!pp[1]) { - zerrnam(nam, "missing argument for option: -%c", NULL, *o); - return 1; - } else { - str = (char *) zhalloc(strlen(pp[1]) + 3); - str[0] = '-'; - str[1] = *o; - strcpy(str + 2, pp[1]); - pp++; + if (!o[1] || (o[1] == '-' && !o[2])) { + pp++; + break; + } + if (!(d = lookup_opt(o + 1))) { + while (*++o) { + if (!(d = sopts[STOUC(*o)])) { + o = NULL; + break; } - o = "" - 1; - } else { - str = (char *) zhalloc(3); - str[0] = '-'; - str[1] = *o; - str[2] = '\0'; - } - if (d->arg != ZOF_ADD) { - for (v = d->arr->vals; v; v = v->next) { - if (str[1] == v->str[1]) { - v->str = str; - str = NULL; + if (d->flags & ZOF_ARG) { + if (o[1]) { + add_opt_val(d, o + 1); break; + } else if (!(d->flags & ZOF_OPT)) { + if (!pp[1]) { + zerrnam(nam, "missing argument for option: %s", + d->name, 0); + return 1; + } + add_opt_val(d, *++pp); + } else + add_opt_val(d, NULL); + } else + add_opt_val(d, NULL); + } + if (!o) + break; + } else { + if (d->flags & ZOF_ARG) { + char *e = o + strlen(d->name) + 1; + + if (*e) + add_opt_val(d, e); + else if (!(d->flags & ZOF_OPT)) { + if (!pp[1]) { + zerrnam(nam, "missing argument for option: %s", + d->name, 0); + return 1; } - } + add_opt_val(d, *++pp); + } else + add_opt_val(d, NULL); + } else + add_opt_val(d, NULL); + } + } + for (a = opt_arrs; a; a = a->next) { + aval = (char **) zalloc((a->num + 1) * sizeof(char *)); + for (ap = aval, v = a->vals; v; ap++, v = v->next) { + if (v->str) + *ap = ztrdup(v->str); + else { + *ap = ztrdup(v->name); + if (v->arg) + *++ap = ztrdup(v->arg); } - if (str) { - v = (Zoptval) zhalloc(sizeof(*v)); - v->str = str; - v->next = NULL; - - if (d->arr->last) - d->arr->last->next = v; - else - d->arr->vals = v; - d->arr->last = v; - d->arr->num++; + } + *ap = NULL; + setaparam(a->name, aval); + } + if (assoc) { + int num; + + for (num = 0, d = opt_descs; d; d = d->next) + if (d->vals) + num++; + + aval = (char **) zalloc(((num * 2) + 1) * sizeof(char *)); + for (ap = aval, d = opt_descs; d; d = d->next) { + if (d->vals) { + *ap++ = n = (char *) zalloc(strlen(d->name) + 2); + *n = '-'; + strcpy(n + 1, d->name); + + for (num = 1, v = d->vals; v; v = v->onext) { + num += (v->arg ? strlen(v->arg) : 0); + if (v->next) + num++; + } + *ap++ = n = (char *) zalloc(num); + for (v = d->vals; v; v = v->onext) { + if (v->arg) { + strcpy(n, v->arg); + n += strlen(v->arg); + } + *n = ' '; + } + *n = '\0'; } } - if (*o) - break; + *ap = NULL; + sethparam(assoc, aval); } - if (ops['D']) { + if (del) { PERMALLOC { pp = arrdup(pp); } LASTALLOC; @@ -1283,13 +1516,6 @@ bin_zparseopts(char *nam, char **args, char *ops, int func) freearray(pparams); pparams = pp; } - for (a = opt_arrs; a; a = a->next) { - aval = (char **) zalloc((a->num + 1) * sizeof(char *)); - for (pp = aval, v = a->vals; v; pp++, v = v->next) - *pp = ztrdup(v->str); - *pp = NULL; - setaparam(a->name, aval); - } return 0; } @@ -1297,7 +1523,7 @@ static struct builtin bintab[] = { BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL), BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL), BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL), - BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, "D", NULL), + BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, NULL, NULL), }; -- cgit 1.4.1