summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2003-06-19 19:43:00 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2003-06-19 19:43:00 +0000
commit7b60aae9f314a2674d8512b3d85f83020148da73 (patch)
treecb0f01a3a7e5f484f8f40deff1ef89f067107edb
parent543a83f63ebcebbf6d3f189f27adc7a620d67f82 (diff)
downloadzsh-7b60aae9f314a2674d8512b3d85f83020148da73.tar.gz
zsh-7b60aae9f314a2674d8512b3d85f83020148da73.zip
18616: Add ternary expression handling to zformat
-rw-r--r--ChangeLog5
-rw-r--r--Doc/Zsh/mod_zutil.yo25
-rw-r--r--Src/Modules/zutil.c221
3 files changed, 176 insertions, 75 deletions
diff --git a/ChangeLog b/ChangeLog
index 94de17762..64c6e5329 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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,
diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo
index e22197ea2..3dc4b25a6 100644
--- a/Doc/Zsh/mod_zutil.yo
+++ b/Doc/Zsh/mod_zutil.yo
@@ -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
diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c
index 4ef237d90..57a368aab 100644
--- a/Src/Modules/zutil.c
+++ b/Src/Modules/zutil.c
@@ -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));