aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2015-01-11 01:22:36 -0600
committerRob Landley <rob@landley.net>2015-01-11 01:22:36 -0600
commitcaa6b014ba15dea377e5f65fcac57afaa932fa64 (patch)
treea980afdfcc8414eaa972f4fe3f5c23887829b98a
parent70cbfe8eda34df26cc91c51cd77098612e33fd80 (diff)
downloadtoybox-caa6b014ba15dea377e5f65fcac57afaa932fa64.tar.gz
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.
-rw-r--r--toys/pending/printf.c55
1 files changed, 26 insertions, 29 deletions
diff --git a/toys/pending/printf.c b/toys/pending/printf.c
index e1c77c5b..81fcd22a 100644
--- a/toys/pending/printf.c
+++ b/toys/pending/printf.c
@@ -88,52 +88,49 @@ void printf_main(void)
// 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++;
- errno = 0;
c = *f++;
+ seen = sprintf(to, "*.*%c", c);;
+ errno = 0;
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;
- if (end && (errno || *end)) perror_msg("bad %%%c %s", c, aa);
+ sprintf(to, "*.*ll%c", c);
+ if (*aa == '\'' || *aa == '"') ll = aa[1];
+ else ll = strtoll(aa, &end, 0);
- 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));
+ 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);
}
}