changeset 1650:a740a876c76c

Cleanup pass on printf. Alas, passing a union as the last argument to printf does not appear to work reliably, and there's no obvious way to manually assemble varargs in a portable manner. So I have to repeat the printf once for each data type. Oh well.
author Rob Landley <rob@landley.net>
date Sun, 11 Jan 2015 01:22:36 -0600
parents 66bb2847993d
children 114fb916e04e
files toys/pending/printf.c
diffstat 1 files changed, 26 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/toys/pending/printf.c	Sat Jan 10 20:02:21 2015 -0600
+++ b/toys/pending/printf.c	Sun Jan 11 01:22:36 2015 -0600
@@ -88,52 +88,49 @@
 
       // Handle %escape
       else {
-        char c, *start = f, *end = 0, *aa, *width = "";
-        int wp[] = {-1,-1}, i;
-        union {
-          int c; // type promotion
-          char *str;
-          long long ll;
-          double dd;
-        } mash;
+        char c, *end = 0, *aa, *to = toybuf;
+        int wp[] = {0,-1}, i;
 
         // Parse width.precision between % and type indicator.
-        // todo: we currently ignore these?
-        if (strchr("-+# ", *f)) f++;
+        *to++ = '%';
+        while (strchr("-+# '0", *f) && (to-toybuf)<10) *to = *f++;
         for (i=0; i<2; i++) {
           if (eat(&f, '*')) {
             if (*arg) wp[i] = atolx(*arg++);
-          } else while (isdigit(*f)) f++;
+          } else while (*f >= '0' && *f <= '9') {
+            if (wp[i]<0) wp[i] = 0;
+            wp[i] = (wp[i]*10)+(*f++)-'0';
+          }
           if (!eat(&f, '.')) break;
         }
-        seen++;
+        c = *f++;
+        seen = sprintf(to, "*.*%c", c);;
         errno = 0;
-        c = *f++;
         aa = *arg ? *arg++ : "";
 
-        // Handle %esc, assembling new format string into toybuf if necessary.
-        if ((f-start) > sizeof(toybuf)-4) c = 0;
+        // Output %esc using parsed format string
         if (c == 'b') {
           while (*aa) putchar(eat(&aa, '\\') ? handle_slash(&aa) : *aa++);
 
           continue;
-        } else if (c == 'c') mash.c = *aa;
-        else if (c == 's') mash.str = aa;
+        } else if (c == 'c') printf(toybuf, wp[0], wp[1], *aa);
+        else if (c == 's') printf(toybuf, wp[0], wp[1], aa);
         else if (strchr("diouxX", c)) {
-          width = "ll";
-          if (*aa == '\'' || *aa == '"') mash.ll = aa[1];
-          else mash.ll = strtoll(aa, &end, 0);
-        } else if (strchr("feEgG", c)) mash.dd = strtod(aa, &end);
-        else error_exit("bad %%%c@%ld", c, f-*toys.optargs);
+          long ll;
+
+          sprintf(to, "*.*ll%c", c);
+          if (*aa == '\'' || *aa == '"') ll = aa[1];
+          else ll = strtoll(aa, &end, 0);
+
+          printf(toybuf, wp[0], wp[1], ll);
+        } else if (strchr("feEgG", c)) {
+          long double ld = strtold(aa, &end);
+
+          sprintf(to, "*.*L%c", c);
+          printf(toybuf, wp[0], wp[1], ld);
+        } else error_exit("bad %%%c@%ld", c, f-*toys.optargs);
 
         if (end && (errno || *end)) perror_msg("bad %%%c %s", c, aa);
-
-        sprintf(toybuf, "%%%.*s%s%c", (int)(f-start)-1, start, width, c);
-        wp[0]>=0
-          ? (wp[1]>=0 ? printf(toybuf, wp[0], wp[1], mash)
-                      : printf(toybuf, wp[0], mash))
-          : (wp[1]>=0 ? printf(toybuf, wp[1], mash)
-                      : printf(toybuf, mash));
       }
     }