>From d4bd736da686b5927a3c655d3e25f9d0b2fc7f99 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Mon, 2 Jun 2014 19:14:10 +0000 Subject: [PATCH 1/2] Teach (Y) to take an argument --- Completion/Zsh/Type/_globquals | 1 + Doc/Zsh/expn.yo | 7 ++++--- Src/glob.c | 34 +++++++++++++++++++++++++++------- Test/D02glob.ztst | 23 ++++++++++++++--------- 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/Completion/Zsh/Type/_globquals b/Completion/Zsh/Type/_globquals index c98bd0c..37db161 100644 --- a/Completion/Zsh/Type/_globquals +++ b/Completion/Zsh/Type/_globquals @@ -251,6 +251,7 @@ case $state in "o:+ sort order, up" "O:+ sort order, down" "P:prepend word" + "Y:+ at most ARG matches" "[:+ range of files" "):end of qualifiers" "\::modifier" diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 25247f9..2f91fec 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -2564,9 +2564,10 @@ item(tt(n))( sets the tt(NUMERIC_GLOB_SORT) option for the current pattern pindex(NUMERIC_GLOB_SORT, setting in pattern) ) -item(tt(Y))( -enables short-circuit mode: the pattern will expand to just the first -matching filename, if any. +item(tt(Y)var(n))( +enables short-circuit mode: the pattern will expand to at most var(n) +filenames. If more than var(n) matches exist, only the first var(n) +matches in directory traversal order will be considered. ) item(tt(o)var(c))( specifies how the names of the files should be sorted. If var(c) is diff --git a/Src/glob.c b/Src/glob.c index 0ca63fc..33b49f1 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -473,7 +473,8 @@ scanner(Complist q, int shortcircuit) if (q->closure == 2) /* (foo/)## - match one or more dirs */ q->closure = 1; else - if (scanner(q->next, shortcircuit) == 1) + scanner(q->next, shortcircuit); + if (shortcircuit && shortcircuit == matchct) return 1; } p = q->pat; @@ -520,7 +521,8 @@ scanner(Complist q, int shortcircuit) if (add) { addpath(str, l); if (!closure || !statfullpath("", NULL, 1)) - if (scanner((q->closure) ? q : q->next, shortcircuit) == 1) + scanner((q->closure) ? q : q->next, shortcircuit); + if (shortcircuit && shortcircuit == matchct) return 1; pathbuf[pathpos = oppos] = '\0'; } @@ -528,7 +530,8 @@ scanner(Complist q, int shortcircuit) } else { if (str[l]) str = dupstrpfx(str, l); - if (insert(str, 0) == 1 && shortcircuit) + insert(str, 0); + if (shortcircuit && shortcircuit == matchct) return 1; } } else { @@ -619,7 +622,8 @@ scanner(Complist q, int shortcircuit) subdirlen += sizeof(int); } else /* if the last filename component, just add it */ - if (insert(fn, 1) == 1 && shortcircuit) + insert(fn, 1); + if (shortcircuit && shortcircuit == matchct) return 1; } } @@ -633,7 +637,9 @@ scanner(Complist q, int shortcircuit) fn += l + 1; memcpy((char *)&errsfound, fn, sizeof(int)); fn += sizeof(int); - if (scanner((q->closure) ? q : q->next, shortcircuit) == 1) /* scan next level */ + /* scan next level */ + scanner((q->closure) ? q : q->next, shortcircuit); + if (shortcircuit && shortcircuit == matchct) return 1; pathbuf[pathpos = oppos] = '\0'; } @@ -1150,7 +1156,8 @@ zglob(LinkList list, LinkNode np, int nountok) /* and index+1 of the last match */ struct globdata saved; /* saved glob state */ int nobareglob = !isset(BAREGLOBQUAL); - int shortcircuit = 0; + int shortcircuit = 0; /* How many files to match; */ + /* 0 means no limit */ if (unset(GLOBOPT) || !haswilds(ostr) || unset(EXECOPT)) { if (!nountok) @@ -1502,9 +1509,22 @@ zglob(LinkList list, LinkNode np, int nountok) gf_numsort = !(sense & 1); break; case 'Y': - /* Short circuit: just check if there are any matches */ + { + /* Short circuit: limit number of matches */ + const char *s_saved = s; shortcircuit = !(sense & 1); + if (shortcircuit) { + /* Parse the argument. */ + data = qgetnum(&s); + if ((shortcircuit = data) != data) { + /* Integer overflow */ + zerr("value too big: Y%s", s_saved); + restore_globstate(saved); + return; + } + } break; + } case 'a': /* Access time in given range */ g_amc = 0; diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst index 9e29de2..c00bbe3 100644 --- a/Test/D02glob.ztst +++ b/Test/D02glob.ztst @@ -543,17 +543,22 @@ >Multiple files matched >Normal string if nullglob not set - (){ print $#@ } glob.tmp/dir*(Y) - (){ print $#@ } glob.tmp/file*(NY) - (){ [[ $1 = glob.tmp/dir? ]] && echo "(Y) returns a matching filename" } glob.tmp/dir*(Y) - # Can be negated - (){ print $@:t } glob.tmp/dir*(Y^Y) - (){ [[ $#@ -eq 1 ]] && print Globs before last path component } glob.tmp/dir?/subdir(NY) - (){ [[ $#@ -eq 0 ]] && print Respects qualifiers } glob.tmp/dir?/subdir(NY.) + (){ print $#@ } glob.tmp/dir*(Y1) + (){ print $#@ } glob.tmp/file*(NY1) + (){ [[ "$*" == */dir?\ */dir? ]] && print Returns matching filenames } glob.tmp/dir*(Y2) + (){ print "Limit is upper bound:" $@:t } glob.tmp/dir*(Y5) + (){ print "Negated:" $@:t } glob.tmp/dir*(Y1^Y) + (){ print "Sorting:" $@:t } glob.tmp/dir*(Y4On) + (){ [[ $#@ -eq 1 ]] && print Globs before last path component } glob.tmp/dir?/subdir(NY1) + (){ [[ $#@ -eq 0 ]] && print Respects qualifiers } glob.tmp/dir*(NY1.) + (print -- *(Y)) 2>/dev/null || print "Argument required" 0:short-circuit modifier >1 >0 ->(Y) returns a matching filename ->dir1 dir2 dir3 dir4 +>Returns matching filenames +>Limit is upper bound: dir1 dir2 dir3 dir4 +>Negated: dir1 dir2 dir3 dir4 +>Sorting: dir4 dir3 dir2 dir1 >Globs before last path component >Respects qualifiers +>Argument required -- 1.7.10.4