1 /* printf.c - Format and Print the data.
3 * Copyright 2014 Sandeep Sharma <sandeep.jack2756@gmail.com>
4 * Copyright 2014 Kyungwan Han <asura321@gmail.com>
6 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
8 * todo: *m$ ala printf("%1$d:%2$.*3$d:%4$.*3$d\n", hour, min, precision, sec);
10 USE_PRINTF(NEWTOY(printf, "<1?^", TOYFLAG_USR|TOYFLAG_BIN))
16 usage: printf FORMAT [ARGUMENT...]
18 Format and print ARGUMENT(s) according to FORMAT, using C printf syntax
19 (% escapes for cdeEfgGiosuxX, \ escapes for abefnrtv0 or \OCTAL or \xHEX).
25 // Detect matching character (return true/false) and advance pointer if match.
26 static int eat(char **s, char c)
35 // Parse escape sequences.
36 static int handle_slash(char **esc_val)
40 unsigned result = 0, num;
42 if (*ptr == 'c') xexit();
44 // 0x12 hex escapes have 1-2 digits, \123 octal escapes have 1-3 digits.
45 if (eat(&ptr, 'x')) base = 16;
46 else if (*ptr >= '0' && *ptr <= '8') base = 8;
47 len = (char []){0,3,2}[base/8];
49 // Not a hex or octal escape? (This catches trailing \)
51 if (!(result = unescape(*ptr))) result = '\\';
58 num = tolower(*ptr) - '0';
59 if (num >= 'a'-'0') num += '0'-'a'+10;
61 // Don't parse invalid hex value ala "\xvd", print it verbatim
62 if (base == 16 && len == 2) {
68 result = (result*base)+num;
77 void printf_main(void)
79 char **arg = toys.optargs+1;
81 // Repeat format until arguments consumed
84 char *f = *toys.optargs;
86 // Loop through characters in format
88 if (eat(&f, '\\')) putchar(handle_slash(&f));
89 else if (!eat(&f, '%') || *f == '%') putchar(*f++);
93 char c, *end = 0, *aa, *to = toybuf;
94 int wp[] = {0,-1}, i = 0;
96 // Parse width.precision between % and type indicator.
98 while (strchr("-+# '0", *f) && (to-toybuf)<10) *to++ = *f++;
101 if (*arg) wp[i] = atolx(*arg++);
102 } else while (*f >= '0' && *f <= '9') wp[i] = (wp[i]*10)+(*f++)-'0';
103 if (i++ || !eat(&f, '.')) break;
107 seen = sprintf(to, "*.*%c", c);;
109 aa = *arg ? *arg++ : "";
111 // Output %esc using parsed format string
113 while (*aa) putchar(eat(&aa, '\\') ? handle_slash(&aa) : *aa++);
116 } else if (c == 'c') printf(toybuf, wp[0], wp[1], *aa);
117 else if (c == 's') printf(toybuf, wp[0], wp[1], aa);
118 else if (strchr("diouxX", c)) {
121 if (*aa == '\'' || *aa == '"') ll = aa[1];
122 else ll = strtoll(aa, &end, 0);
124 sprintf(to, "*.*ll%c", c);
125 printf(toybuf, wp[0], wp[1], ll);
126 } else if (strchr("feEgG", c)) {
127 long double ld = strtold(aa, &end);
129 sprintf(to, "*.*L%c", c);
130 printf(toybuf, wp[0], wp[1], ld);
131 } else error_exit("bad %%%c@%ld", c, (long)(f-*toys.optargs));
133 if (end && (errno || *end)) perror_msg("bad %%%c %s", c, aa);
137 // Posix says to keep looping through format until we consume all args.
138 // This only works if the format actually consumed at least one arg.
139 if (!seen || !*arg) break;