aboutsummaryrefslogtreecommitdiff
path: root/toys/pending/printf.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/pending/printf.c')
-rw-r--r--toys/pending/printf.c168
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;
}