Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
PATCH: ternary expression handling for zformat
- X-seq: zsh-workers 18616
- From: Peter Stephenson <pws@xxxxxxx>
- To: zsh-workers@xxxxxxxxxx (Zsh hackers list)
- Subject: PATCH: ternary expression handling for zformat
- Date: Thu, 19 Jun 2003 20:32:29 +0100
- Mailing-list: contact zsh-workers-help@xxxxxxxxxx; run by ezmlm
Now we've got that out of the way... This adds ternary expression
handling to the generalised %-escape mechanism of the zformat command.
I've tried to do it in a way which is as compatible as possible to the
system used by ternary expressions in prompts. It may turn up in an
extension to the TCP function system's prompts, but first things first.
The example from the manual shows the basic features:
% zformat -f REPLY "The answer is '%3(c.yes.no)'." c:3
% print $REPLY
The answer is 'yes'.
Index: Src/Modules/zutil.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/zutil.c,v
retrieving revision 1.13
diff -u -r1.13 zutil.c
--- Src/Modules/zutil.c 27 Aug 2002 21:10:34 -0000 1.13
+++ Src/Modules/zutil.c 19 Jun 2003 19:29:34 -0000
@@ -549,6 +549,148 @@
/* 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 @@
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 @@
}
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));
Index: Doc/Zsh/mod_zutil.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_zutil.yo,v
retrieving revision 1.14
diff -u -r1.14 mod_zutil.yo
--- Doc/Zsh/mod_zutil.yo 29 Aug 2000 06:35:40 -0000 1.14
+++ Doc/Zsh/mod_zutil.yo 19 Jun 2003 19:29:34 -0000
@@ -124,6 +124,31 @@
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
--
Peter Stephenson <pws@xxxxxxx> Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK Tel: +44 (0)1223 692070
**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential
and/or privileged material.
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by
persons or entities other than the intended recipient is
prohibited.
If you received this in error, please contact the sender and
delete the material from any computer.
**********************************************************************
Messages sorted by:
Reverse Date,
Date,
Thread,
Author