diff options
-rw-r--r-- | toys/pending/printf.c | 168 |
1 files changed, 66 insertions, 102 deletions
diff --git a/toys/pending/printf.c b/toys/pending/printf.c index 0970c8cd..3ec20813 100644 --- a/toys/pending/printf.c +++ b/toys/pending/printf.c @@ -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 @@ GLOBALS( 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 @@ static char *get_format(char *f) 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 @@ static int handle_slash(char **esc_val) 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 @@ static int handle_slash(char **esc_val) 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 @@ static void print_esc_str(char *str) } } -// 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 @@ static void parse_print(char *f) 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 @@ static void parse_print(char *f) 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 @@ static void parse_print(char *f) //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; } |