summaryrefslogtreecommitdiff
path: root/Src/Modules/zutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Modules/zutil.c')
-rw-r--r--Src/Modules/zutil.c221
1 files changed, 146 insertions, 75 deletions
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));