From d26461a3c61b311bdbd58334ee5f8a5113dcdbf2 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 9 Jan 2014 10:05:13 +0000 Subject: users/18298 (tidied up): add {..} expansion --- ChangeLog | 5 +++ Doc/Zsh/expn.yo | 10 ++++++ Src/glob.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++-- Test/D09brace.ztst | 15 ++++++++ 4 files changed, 128 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 93c5e514b..954c63b44 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2014-01-09 Peter Stephenson + + * users/18298 (tidied up): Doc/Zsh/expn.yo, Src/glob.c, + Test/D09brace.ztst: add {..} expansion. + 2014-01-07 Peter Stephenson * Mark Oteiza: 32238: suppress error output completing after ip. diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 5ba3e21af..8bbe7800b 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -1539,6 +1539,16 @@ specified in any of the three numbers, specifying it in the third can be useful to pad for example `tt({-99..100..01})' which is not possible to specify by putting a 0 on either of the first two numbers (i.e. pad to two characters). +An expression of the form `tt({)var(c1)tt(..)var(c2)tt(})', where +var(c1) and var(c2) are single characters (which may be multibyte +characters), is expanded to every character in the range from var(c1) to +var(c2) in whatever character sequence is used internally. For +characters with code points below 128 this is US ASCII (this is the only +case most users will need). If any intervening character is not +printable, appropriate quotation is used to render it printable. +If the character sequence is reversed, the output is in reverse +order, e.g. `tt({d..a})' is substituted as `tt(d c b a)'. + If a brace expression matches none of the above forms, it is left unchanged, unless the option tt(BRACE_CCL) (an abbreviation for `brace character class') is set. diff --git a/Src/glob.c b/Src/glob.c index e0d0cf68e..9a34a7f30 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -1895,6 +1895,8 @@ hasbraces(char *str) switch (*str++) { case Inbrace: if (!lbr) { + if (bracechardots(str-1, NULL, NULL)) + return 1; lbr = str - 1; if (*str == '-') str++; @@ -2027,6 +2029,52 @@ xpandredir(struct redir *fn, LinkList redirtab) return ret; } +/* + * Check for a brace expansion of the form {..}. + * On input str must be positioned at an Inbrace, but the sequence + * of characters beyond that has not necessarily been checked. + * Return 1 if found else 0. + * + * The other parameters are optionaland if the function returns 1 are + * used to return: + * - *c1p: the first character in the expansion. + * - *c2p: the final character in the expansion. + */ + +/**/ +static int +bracechardots(char *str, convchar_t *c1p, convchar_t *c2p) +{ + convchar_t cstart, cend; + char *pnext = str + 1, *pconv, convstr[2]; + if (itok(*pnext)) { + convstr[0] = ztokens[*pnext - Pound]; + convstr[1] = '\0'; + pconv = convstr; + } else + pconv = pnext; + MB_METACHARINIT(); + pnext += MB_METACHARLENCONV(pconv, &cstart); + if (cstart == WEOF || pnext[0] != '.' || pnext[1] != '.') + return 0; + pnext += 2; + if (itok(*pnext)) { + convstr[0] = ztokens[*pnext - Pound]; + convstr[1] = '\0'; + pconv = convstr; + } else + pconv = pnext; + MB_METACHARINIT(); + pnext += MB_METACHARLENCONV(pconv, &cend); + if (cend == WEOF || *pnext != Outbrace) + return 0; + if (c1p) + *c1p = cstart; + if (c2p) + *c2p = cend; + return 1; +} + /* brace expansion */ /**/ @@ -2060,10 +2108,57 @@ xpandbraces(LinkList list, LinkNode *np) char *dots, *p, *dots2 = NULL; LinkNode olast = last; /* Get the first number of the range */ - zlong rstart = zstrtol(str+1,&dots,10), rend = 0; + zlong rstart, rend; int err = 0, rev = 0, rincr = 1; - int wid1 = (dots - str) - 1, wid2 = (str2 - dots) - 2, wid3 = 0; - int strp = str - str3; + int wid1, wid2, wid3, strp; + convchar_t cstart, cend; + + if (bracechardots(str, &cstart, &cend)) { + int lenalloc; + /* + * This is a character range. + */ + if (cend < cstart) { + convchar_t ctmp = cend; + cend = cstart; + cstart = ctmp; + rev = 1; + } + uremnode(list, node); + strp = str - str3; + lenalloc = strp + strlen(str2+1) + 1; + for (; cend >= cstart; cend--) { +#ifdef MULTIBYTE_SUPPORT + char *ncptr; + int nclen; + mb_metacharinit(); + ncptr = wcs_nicechar(cend, NULL, NULL); + nclen = strlen(ncptr); + p = zhalloc(lenalloc + nclen); + memcpy(p, str3, strp); + memcpy(p + strp, ncptr, nclen); + strcpy(p + strp + nclen, str2 + 1); +#else + p = zhalloc(lenalloc + 1); + memcpy(p, str3, strp); + sprintf(p + strp, "%c", cend); + strcat(p + strp, str2 + 1); +#endif + insertlinknode(list, last, p); + if (rev) /* decreasing: add in reverse order. */ + last = nextnode(last); + } + *np = nextnode(olast); + return; + } + + /* Get the first number of the range */ + rstart = zstrtol(str+1,&dots,10); + rend = 0; + wid1 = (dots - str) - 1; + wid2 = (str2 - dots) - 2; + wid3 = 0; + strp = str - str3; if (dots == str + 1 || *dots != '.' || dots[1] != '.') err++; diff --git a/Test/D09brace.ztst b/Test/D09brace.ztst index d0ec93cd3..3e667a8d1 100644 --- a/Test/D09brace.ztst +++ b/Test/D09brace.ztst @@ -97,3 +97,18 @@ 0:BRACE_CCL off >X{za-q521}Y + print -r hey{a..j}there +0:{char..char} ranges, simple case +>heyathere heybthere heycthere heydthere heyethere heyfthere heygthere heyhthere heyithere heyjthere + + print -r gosh{1,{Z..a},2}cripes +0:{char..char} ranges, ASCII ordering +>gosh1cripes goshZcripes gosh[cripes gosh\cripes gosh]cripes gosh^cripes gosh_cripes gosh`cripes goshacripes gosh2cripes + + print -r crumbs{y..p}ooh +0:{char..char} ranges, reverse +>crumbsyooh crumbsxooh crumbswooh crumbsvooh crumbsuooh crumbstooh crumbssooh crumbsrooh crumbsqooh crumbspooh + + print -r left{[..]}right +0:{char..char} ranges with tokenized characters +>left[right left\right left]right -- cgit 1.4.1