18616: Add ternary expression handling to zformat

This commit is contained in:
Peter Stephenson 2003-06-19 19:43:00 +00:00
parent 543a83f63e
commit 7b60aae9f3
3 changed files with 176 additions and 75 deletions

View file

@ -1,3 +1,8 @@
2003-06-19 Peter Stephenson <pws@csr.com>
* 18616: Src/Modules/zutil.c, Doc/Zsh/mod_zutil.yo: Add
ternary expression handling to zformat.
2003-06-18 Peter Stephenson <pws@csr.com>
* unposted: README, Etc/NEWS, Config/version.mk: version 4.1.1,

View file

@ -124,6 +124,31 @@ many characters. After all `tt(%)' sequences for the given var(specs)
have been processed, the resulting string is stored in the parameter
var(param).
The tt(%)-escapes also understand ternary expressions in the form used by
prompts. The tt(%) is followed by a `tt(LPAR())' and then an ordinary
format specifier character as described above. There may be a set of
digits either before or after the `tt(LPAR())'; these specify a test
number, which defaults to zero. Negative numbers are also allowed. An
arbitrary delimiter character follows the format specifier, which is
followed by a piece of `true' text, the delimiter character again, a piece
of `false' text, and a closing parenthesis. The complete expression
(without the digits) thus looks like
`tt(%LPAR())var(X)tt(.)var(text1)tt(.)var(text2)tt(RPAR())', except that
the `tt(.)' character is arbitrary. The value given for the format
specifier in the var(char)tt(:)var(string) expressions is evaluated as a
mathematical expression, and compared with the test number. If they are
the same, var(text1) is output, else var(text2) is output. A parenthesis
may be escaped in var(text2) as tt(%RPAR()). Either of var(text1) or
var(text2) may contain nested tt(%)-escapes.
For example:
example(zformat -f REPLY "The answer is '%3(c.yes.no)'." c:3)
outputs "The answer is 'yes'." to tt(REPLY) since the value for the format
specifier tt(c) is 3, agreeing with the digit argument to the ternary
expression.
The second form, using the tt(-a) option, can be used for aligning
strings. Here, the var(specs) are of the form
`var(left)tt(:)var(right)' where `var(left)' and `var(right)' are

View file

@ -549,6 +549,148 @@ bin_zstyle(char *nam, char **args, Options ops, int func)
/* Format stuff. */
/*
* One chunk of text, to allow recursive handling of ternary
* expressions in zformat -f output.
* instr The input string.
* specs The format specifiers, specs[c] is the string from c:string
* outp *outp is the start of the output string
* ousedp (*outp)[*ousedp] is where to write next
* olenp *olenp is the size allocated for *outp
* endchar Terminator character in addition to `\0' (may be '\0')
* skip If 1, don't output, just parse.
*/
static char *zformat_substring(char* instr, char **specs, char **outp,
int *ousedp, int *olenp, int endchar, int skip)
{
char *s;
for (s = instr; *s && *s != endchar; s++) {
if (*s == '%') {
int right, min = -1, max = -1, outl, testit;
char *spec, *start = s;
if ((right = (*++s == '-')))
s++;
if (*s >= '0' && *s <= '9') {
for (min = 0; *s >= '0' && *s <= '9'; s++)
min = (min * 10) + (int) STOUC(*s) - '0';
}
/* Ternary expressions */
testit = (STOUC(*s) == '(');
if (testit && s[1] == '-')
{
/* Allow %(-1... etc. */
right = 1;
s++;
}
if ((*s == '.' || testit) && s[1] >= '0' && s[1] <= '9') {
for (max = 0, s++; *s >= '0' && *s <= '9'; s++)
max = (max * 10) + (int) STOUC(*s) - '0';
}
else if (testit)
s++;
if (testit && STOUC(*s)) {
int actval, testval, endcharl;
/*
* One one number is useful for ternary expressions.
* Remember to put the sign back.
*/
testval = (min >= 0) ? min : (max >= 0) ? max : 0;
if (right)
testval *= -1;
if (specs[STOUC(*s)])
actval = (int)mathevali(specs[STOUC(*s)]);
else
actval = 0;
/* zero means values are equal, i.e. true */
actval -= testval;
/* careful about premature end of string */
if (!(endcharl = *++s))
return NULL;
/*
* Either skip true text and output false text, or
* vice versa... unless we are already skipping.
*/
if (!(s = zformat_substring(s+1, specs, outp, ousedp,
olenp, endcharl, skip || actval)))
return NULL;
if (!(s = zformat_substring(s+1, specs, outp, ousedp,
olenp, ')', skip || !actval)))
return NULL;
} else if (skip) {
continue;
} else if ((spec = specs[STOUC(*s)])) {
int len;
if ((len = strlen(spec)) > max && max >= 0)
len = max;
outl = (min >= 0 ? (min > len ? min : len) : len);
if (*ousedp + outl >= *olenp) {
int nlen = *olenp + outl + 128;
char *tmp = (char *) zhalloc(nlen);
memcpy(tmp, *outp, *olenp);
*olenp = nlen;
*outp = tmp;
}
if (len >= outl) {
memcpy(*outp + *ousedp, spec, outl);
*ousedp += outl;
} else {
int diff = outl - len;
if (right) {
while (diff--)
(*outp)[(*ousedp)++] = ' ';
memcpy(*outp + *ousedp, spec, len);
*ousedp += len;
} else {
memcpy(*outp + *ousedp, spec, len);
*ousedp += len;
while (diff--)
(*outp)[(*ousedp)++] = ' ';
}
}
} else {
int len = s - start + 1;
if (*ousedp + len >= *olenp) {
int nlen = *olenp + len + 128;
char *tmp = (char *) zhalloc(nlen);
memcpy(tmp, *outp, *olenp);
*olenp = nlen;
*outp = tmp;
}
memcpy(*outp + *ousedp, start, len);
*ousedp += len;
}
} else {
if (skip)
continue;
if (*ousedp + 1 >= *olenp) {
char *tmp = (char *) zhalloc((*olenp) << 1);
memcpy(tmp, *outp, *olenp);
*olenp <<= 1;
*outp = tmp;
}
(*outp)[(*ousedp)++] = *s;
}
}
return s;
}
static int
bin_zformat(char *nam, char **args, Options ops, int func)
{
@ -563,11 +705,13 @@ bin_zformat(char *nam, char **args, Options ops, int func)
switch (opt) {
case 'f':
{
char **ap, *specs[256], *out, *s;
char **ap, *specs[256], *out;
int olen, oused = 0;
memset(specs, 0, 256 * sizeof(char *));
specs['%'] = "%";
specs[')'] = ")";
for (ap = args + 2; *ap; ap++) {
if (!ap[0][0] || ap[0][0] == '-' || ap[0][0] == '.' ||
(ap[0][0] >= '0' && ap[0][0] <= '9') ||
@ -579,80 +723,7 @@ bin_zformat(char *nam, char **args, Options ops, int func)
}
out = (char *) zhalloc(olen = 128);
for (s = args[1]; *s; s++) {
if (*s == '%') {
int right, min = -1, max = -1, outl;
char *spec, *start = s;
if ((right = (*++s == '-')))
s++;
if (*s >= '0' && *s <= '9') {
for (min = 0; *s >= '0' && *s <= '9'; s++)
min = (min * 10) + (int) STOUC(*s) - '0';
}
if (*s == '.' && s[1] >= '0' && s[1] <= '9') {
for (max = 0, s++; *s >= '0' && *s <= '9'; s++)
max = (max * 10) + (int) STOUC(*s) - '0';
}
if ((spec = specs[STOUC(*s)])) {
int len;
if ((len = strlen(spec)) > max && max >= 0)
len = max;
outl = (min >= 0 ? (min > len ? min : len) : len);
if (oused + outl >= olen) {
int nlen = olen + outl + 128;
char *tmp = (char *) zhalloc(nlen);
memcpy(tmp, out, olen);
olen = nlen;
out = tmp;
}
if (len >= outl) {
memcpy(out + oused, spec, outl);
oused += outl;
} else {
int diff = outl - len;
if (right) {
while (diff--)
out[oused++] = ' ';
memcpy(out + oused, spec, len);
oused += len;
} else {
memcpy(out + oused, spec, len);
oused += len;
while (diff--)
out[oused++] = ' ';
}
}
} else {
int len = s - start + 1;
if (oused + len >= olen) {
int nlen = olen + len + 128;
char *tmp = (char *) zhalloc(nlen);
memcpy(tmp, out, olen);
olen = nlen;
out = tmp;
}
memcpy(out + oused, start, len);
oused += len;
}
} else {
if (oused + 1 >= olen) {
char *tmp = (char *) zhalloc(olen << 1);
memcpy(tmp, out, olen);
olen <<= 1;
out = tmp;
}
out[oused++] = *s;
}
}
zformat_substring(args[1], specs, &out, &oused, &olen, '\0', 0);
out[oused] = '\0';
setsparam(args[0], ztrdup(out));