changeset 1643:54c092c3ee38

Cleanup pass on printf.
author Rob Landley <rob@landley.net>
date Fri, 02 Jan 2015 21:28:39 -0600
parents 5f8fe22a33b8
children 492bd41f8b9a
files toys/pending/printf.c
diffstat 1 files changed, 66 insertions(+), 102 deletions(-) [+]
line wrap: on
line diff
--- a/toys/pending/printf.c	Fri Jan 02 00:44:27 2015 -0600
+++ b/toys/pending/printf.c	Fri Jan 02 21:28:39 2015 -0600
@@ -8,14 +8,16 @@
 USE_PRINTF(NEWTOY(printf, "<1", TOYFLAG_USR|TOYFLAG_BIN))
 
 config PRINTF 
-    bool "printf"
-    default n
-    help
-    usage: printf Format [Arguments..]
+  bool "printf"
+  default n
+  help
+    usage: printf FORMAT [ARGUMENT...]
     
-    Format and print ARGUMENT(s) according to FORMAT.
-    Format is 'C' control output as 'C' printf.
+    Format and print ARGUMENT(s) according to FORMAT, using C printf syntax
+    (percent escapes for cdeEfgGiosuxX, slash escapes for \abefnrtv0 or
+    \0OCT or 0xHEX).
 */
+
 #define FOR_printf
 #include "toys.h"
 
@@ -29,13 +31,14 @@
 static int get_w_p()
 {
   char *ptr, *str = *toys.optargs;
-  
+
   errno = 0;
   if (*str == '-') str++;
   long value = strtol(str, &ptr, 10);
   if (errno || (ptr && (*ptr != '\0' || ptr == str)))
     perror_msg("Invalid num %s", *toys.optargs);
   if (*--str == '-') return (int)(-1 * value);
+
   return value;
 }
 
@@ -45,70 +48,56 @@
   int len = strlen(f);
   char last = f[--len], *post = "";
 
-  f[len] = '\0';
+  f[len] = 0;
   if (strchr("diouxX", last)) post = "ll";  // add ll to integer modifier.
   else if (strchr("feEgG", last)) post = "L"; // add L to float modifier.
   return xmprintf("%s%s%c", f, post, last);
 }
 
 // Print arguments with corresponding conversion and width and precision.
-static void print(char *fmt, int w, int p, int l)
+static void print(char *fmt, int w, int p)
 {
-  char *ptr = (fmt+l-1), *ep = NULL, *format = NULL;
-  long long val;
-  long double dval;
-  
+  char *ptr = fmt, *ep = 0, *format = 0, *arg = *toys.optargs;
+
   errno = 0;
-  switch (*ptr) {
-    case 'd': /*FALL_THROUGH*/
-    case 'i': /*FALL_THROUGH*/
-    case 'o': /*FALL_THROUGH*/
-    case 'u': /*FALL_THROUGH*/
-    case 'x': /*FALL_THROUGH*/
-    case 'X':
-      if (!*toys.optargs) val = 0;
+  if (strchr("diouxX", *ptr)) {
+    long long val = 0;
+
+    if (arg) {
+      if (*arg == '\'' || *arg == '"') val = arg[1];
       else {
-        if (**toys.optargs == '\'' || **toys.optargs == '"')
-          val = *((*toys.optargs) + 1);
-        else {
-          val = strtoll(*toys.optargs, &ep, 0);
-          if (errno || (ep && (*ep != '\0' || ep == *toys.optargs))) {
-            perror_msg("Invalid num %s", *toys.optargs);
-            val = 0;
-          }
+        val = strtoll(arg, &ep, 0);
+        if (errno || (ep && (*ep || ep == arg))) {
+          perror_msg("Invalid num %s", arg);
+          val = 0;
         }
       }
-      format = get_format(fmt);
-      TT.hv_w ? (TT.hv_p ? printf(format, w, p, val) : printf(format, w, val))
-        : (TT.hv_p ? printf(format, p, val) : printf(format, val));
-      break;
-    case 'g': /*FALL_THROUGH*/
-    case 'e': /*FALL_THROUGH*/
-    case 'E': /*FALL_THROUGH*/
-    case 'G': /*FALL_THROUGH*/
-    case 'f':
-      if (*toys.optargs) {
-        dval = strtold(*toys.optargs, &ep);
-        if (errno || (ep && (*ep != '\0' || ep == *toys.optargs))) {
-          perror_msg("Invalid num %s", *toys.optargs);
-          dval = 0;
-        }
-      } else dval = 0;
-      format = get_format(fmt);
-      TT.hv_w ? (TT.hv_p ? printf(format, w, p, dval):printf(format, w, dval))
-        : (TT.hv_p ? printf(format, p, dval) :  printf(format, dval));
-      break;
-    case 's':
-      {
-        char *str = (*toys.optargs ? *toys.optargs : "");
-        TT.hv_w ? (TT.hv_p ? printf(fmt,w,p,str): printf(fmt, w, str))
-          : (TT.hv_p ? printf(fmt, p, str) : printf(fmt, str));
+    }
+    format = get_format(fmt);
+    TT.hv_w ? (TT.hv_p ? printf(format, w, p, val) : printf(format, w, val))
+      : (TT.hv_p ? printf(format, p, val) : printf(format, val));
+  } else if (strchr("gGeEf", *ptr)) {
+    long double dval = 0;
+
+    if (arg) {
+      dval = strtold(arg, &ep);
+      if (errno || (ep && (*ep || ep == arg))) {
+        perror_msg("Invalid num %s", arg);
+        dval = 0;
       }
-      break;
-    case 'c':
-      printf(fmt, (*toys.optargs ? **toys.optargs : '\0'));
-      break;
-  }
+    }
+    format = get_format(fmt);
+    TT.hv_w ? (TT.hv_p ? printf(format, w, p, dval) : printf(format, w, dval))
+      : (TT.hv_p ? printf(format, p, dval) :  printf(format, dval));
+  } else if (*ptr == 's') {
+    char *str = arg;
+
+    if (!str) str = "";
+
+    TT.hv_w ? (TT.hv_p ? printf(fmt,w,p,str): printf(fmt, w, str))
+      : (TT.hv_p ? printf(fmt, p, str) : printf(fmt, str));
+  } else if (*ptr == 'c') printf(fmt, arg ? *arg : 0);
+
   if (format) free(format);
 }
 
@@ -118,7 +107,7 @@
   char *ptr = *esc_val;
   int esc_length = 0;
   unsigned  base = 0, num = 0, result = 0, count = 0;
-  
+
   /*
    * Hex escape sequence have only 1 or 2 digits, xHH. Oct escape sequence 
    * have 1,2 or 3 digits, xHHH. Leading "0" (\0HHH) we are ignoring.
@@ -146,26 +135,10 @@
     count = result = (count * base) + num;
     ptr++;
   }
-  if (base) {
-    ptr--;
-    *esc_val = ptr;
-    return (char)result;
-  } else {
-    switch (*ptr) {
-      case 'n':  result = '\n'; break;
-      case 't':  result = '\t'; break;
-      case 'e':  result = (char)27; break;
-      case 'b':  result = '\b'; break;
-      case 'a':  result = '\a'; break;
-      case 'f':  result = '\f'; break;
-      case 'v':  result = '\v'; break;
-      case 'r':  result = '\r'; break;
-      case '\\': result = '\\'; break;
-      default :
-        result = '\\';
-        ptr--; // Let pointer pointing to / we will increment after returning.
-        break;
-    }
+  if (base) ptr--;
+  else if (!(result = unescape(*ptr))) {
+    result = '\\';
+    ptr--; // Let pointer pointing to / we will increment after returning.
   }
   *esc_val = ptr;
   return (char)result;
@@ -182,15 +155,14 @@
   }
 }
 
-// Prase the format string and print.
-static void parse_print(char *f)
+// Parse the format string and print.
+static void parse_print(char *format)
 {
-  char *start, *p, format_specifiers[] = "diouxXfeEgGcs";
+  char *start, *p, *f = format;
   int len = 0, width = 0, prec = 0;
 
   while (*f) {
-    switch (*f) {
-      case '%':
+    if (*f == '%') {
         start = f++;
         len++;
         if (*f == '%') {
@@ -211,9 +183,8 @@
             width = get_w_p();
             toys.optargs++;
           }
-        } else {
-          while (isdigit(*f)) f++, len++;
-        }
+        } else while (isdigit(*f)) f++, len++;
+
         if (*f == '.') {
           f++, len++;
           if (*f == '*') {
@@ -226,8 +197,8 @@
             while (isdigit(*f)) f++, len++;
           }
         }
-        if (!(p = strchr(format_specifiers, *f)))
-          perror_exit("Missing OR Invalid format specifier");
+        if (!(p = strchr("diouxXfeEgGcs", *f)))
+          perror_exit("bad format@%ld", f-format);
         else {
           len++;
           TT.hv_p = strstr(start, ".*");
@@ -235,23 +206,16 @@
           //pitfall: handle diff b/w * and .*
           if ((TT.hv_w-1) == TT.hv_p) TT.hv_w = NULL;
           memcpy((p = xzalloc(len+1)), start, len);
-          print(p, width, prec, len);
+          print(p+len-1, width, prec);
           if (*toys.optargs) toys.optargs++;
           free(p);
           p = NULL;
         } 
         TT.encountered = 1;
-        break;
-      case '\\':
-        if (f[1]) {
-          if (*++f == 'c') exit(0); //Got '\c', so no further output  
-          xputc(handle_slash(&f));
-        } else xputc(*f);
-        break;
-      default:
-        xputc(*f);
-        break;
-    }
+    } else if (*f == '\\' && f[1]) {
+      if (*++f == 'c') exit(0); //Got '\c', so no further output  
+      xputc(handle_slash(&f));
+    } else xputc(*f);
     f++;
     len = 0;
   }