---
printf.c | 37 ++++++++++++++++++++-----------------
tests/0002-printf.sh | 44 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+), 17 deletions(-)
create mode 100644 tests/0002-printf.sh
diff --git a/printf.c b/printf.c
index 039dac7..4d0399b 100644
--- a/printf.c
+++ b/printf.c
_AT_@ -19,11 +19,11 @@ int
main(int argc, char *argv[])
{
Rune *rarg;
- size_t i, j, argi, lastargi, formatlen, blen;
+ size_t i, j, f, argi, lastargi, formatlen, blen, nflags;
long long num;
double dou;
int cooldown = 0, width, precision, ret = 0;
- char *format, *tmp, *arg, *fmt, flag;
+ char *format, *tmp, *arg, *fmt;
argv0 = argv[0];
if (argc < 2)
_AT_@ -44,14 +44,20 @@ main(int argc, char *argv[])
break;
lastargi = argi;
}
+
if (format[i] != '%') {
putchar(format[i]);
continue;
}
/* flag */
- for (flag = '\0', i++; strchr("#-+ 0", format[i]); i++) {
- flag = format[i];
+ f = ++i;
+ nflags = strspn(&format[f], "#-+ 0");
+ i += nflags;
+
+ if (nflags > INT_MAX) {
+ f += nflags - INT_MAX;
+ nflags = INT_MAX;
}
/* field width */
_AT_@ -64,7 +70,7 @@ main(int argc, char *argv[])
i++;
} else {
j = i;
- for (; strchr("+-0123456789", format[i]); i++);
+ i += strspn(&format[i], "+-0123456789");
if (j != i) {
tmp = estrndup(format + j, i - j);
width = estrtonum(tmp, 0, INT_MAX);
_AT_@ -85,7 +91,7 @@ main(int argc, char *argv[])
i++;
} else {
j = i;
- for (; strchr("+-0123456789", format[i]); i++);
+ i += strspn(&format[i], "+-0123456789");
if (j != i) {
tmp = estrndup(format + j, i - j);
precision = estrtonum(tmp, 0, INT_MAX);
_AT_@ -127,9 +133,8 @@ main(int argc, char *argv[])
free(rarg);
break;
case 's':
- fmt = estrdup(flag ? "%#*.*s" : "%*.*s");
- if (flag)
- fmt[1] = flag;
+ fmt = emalloc(sizeof("%*.*s" + nflags));
+ sprintf(fmt, "%%%.*s*.*s", (int)nflags, &format[f]);
printf(fmt, width, precision, arg);
free(fmt);
break;
_AT_@ -161,22 +166,20 @@ main(int argc, char *argv[])
} else {
num = 0;
}
- fmt = estrdup(flag ? "%#*.*ll#" : "%*.*ll#");
- if (flag)
- fmt[1] = flag;
- fmt[flag ? 7 : 6] = format[i];
+ fmt = emalloc(sizeof("%*.*ll#") + nflags);
+ sprintf(fmt, "%%%.*s*.*ll%c", (int)nflags, &format[f], format[i]);
printf(fmt, width, precision, num);
free(fmt);
break;
case 'a': case 'A': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
- fmt = estrdup(flag ? "%#*.*#" : "%*.*#");
- if (flag)
- fmt[1] = flag;
- fmt[flag ? 5 : 4] = format[i];
+ fmt = emalloc(sizeof("%*.*#") + nflags);
+ sprintf(fmt, "%%%.*s*.*%c", (int)nflags, &format[f], format[i]);
dou = (strlen(arg) > 0) ? estrtod(arg) : 0;
printf(fmt, width, precision, dou);
free(fmt);
break;
+ case '\0':
+ eprintf("Missing format specifier.\n");
default:
eprintf("Invalid format specifier '%c'.\n", format[i]);
}
diff --git a/tests/0002-printf.sh b/tests/0002-printf.sh
new file mode 100644
index 0000000..6384fe2
--- /dev/null
+++ b/tests/0002-printf.sh
_AT_@ -0,0 +1,44 @@
+#!/bin/sh
+
+set -e
+
+exp1=exp1.$$
+exp2=exp2.$$
+res1=res1.$$
+res2=res2.$$
+
+cleanup()
+{
+ st=$?
+ rm -f $exp1 $exp2 $res1 $res2
+ exit $st
+}
+
+trap cleanup EXIT HUP INT TERM
+
+cat <<'EOF' > $exp1
+123
+0
+foo
+bar
++001 +2 +003 -400
+Expected failure
+EOF
+
+cat <<'EOF' > $exp2
+../printf: Missing format specifier.
+EOF
+
+(
+ ../printf '123\n'
+ ../printf '%d\n'
+ ../printf '%b' 'foo\nbar\n'
+
+ # Two flags used simulatenously, + and 0
+ ../printf '%+04d %+4d ' 1 2 3 -400; ../printf "\n"
+ # Missing format specifier; should have sane error message
+ ../printf '%000' FOO || echo "Expected failure"
+) > $res1 2> $res2
+
+diff -u $exp1 $res1
+diff -u $exp2 $res2
--
2.42.0
Received on Tue Nov 11 2025 - 13:10:53 CET
This archive was generated by hypermail 2.3.0 : Tue Nov 11 2025 - 13:12:36 CET