users/18298 (tidied up): add {<char>..<char>} expansion

This commit is contained in:
Peter Stephenson 2014-01-09 10:05:13 +00:00
parent a34754e962
commit d26461a3c6
4 changed files with 128 additions and 3 deletions

View file

@ -1,3 +1,8 @@
2014-01-09 Peter Stephenson <p.stephenson@samsung.com>
* users/18298 (tidied up): Doc/Zsh/expn.yo, Src/glob.c,
Test/D09brace.ztst: add {<char>..<char>} expansion.
2014-01-07 Peter Stephenson <p.w.stephenson@ntlworld.com>
* Mark Oteiza: 32238: suppress error output completing after ip.

View file

@ -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.

View file

@ -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 {<char>..<char>}.
* 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++;

View file

@ -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