summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authordas <das@FreeBSD.org>2008-08-02 06:02:42 +0000
committerdas <das@FreeBSD.org>2008-08-02 06:02:42 +0000
commit70fb465112f35080b4e32bb86725c9aa26ca1a96 (patch)
tree9bc7f0da28dd06dfb99fbea365f049c421739e33 /lib
parent6781fcee0fd409a644e5fc8f8fe7edcd82c1819f (diff)
downloadFreeBSD-src-70fb465112f35080b4e32bb86725c9aa26ca1a96.zip
FreeBSD-src-70fb465112f35080b4e32bb86725c9aa26ca1a96.tar.gz
Teach fmtcheck() about wint_t, intmax_t, char *, intmax_t *, and
wide string arguments. Also simplify the code that handles length modifiers and make it more conservative. For instance, be explicit about the modifiers allowed for %d, rather than assuming that anything other than L, q, t, or z implies an int argument.
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/gen/fmtcheck.34
-rw-r--r--lib/libc/gen/fmtcheck.c132
2 files changed, 99 insertions, 37 deletions
diff --git a/lib/libc/gen/fmtcheck.3 b/lib/libc/gen/fmtcheck.3
index 3663558..782526d 100644
--- a/lib/libc/gen/fmtcheck.3
+++ b/lib/libc/gen/fmtcheck.3
@@ -112,6 +112,4 @@ the first requires an integer and the second requires a long.
.Sh BUGS
The
.Fn fmtcheck
-function does not understand all of the conversions that
-.Xr printf 3
-does.
+function does not recognize positional parameters.
diff --git a/lib/libc/gen/fmtcheck.c b/lib/libc/gen/fmtcheck.c
index ca93983..6082913 100644
--- a/lib/libc/gen/fmtcheck.c
+++ b/lib/libc/gen/fmtcheck.c
@@ -47,14 +47,18 @@ enum __e_fmtcheck_types {
FMTCHECK_START,
FMTCHECK_SHORT,
FMTCHECK_INT,
+ FMTCHECK_WINTT,
FMTCHECK_LONG,
FMTCHECK_QUAD,
+ FMTCHECK_INTMAXT,
FMTCHECK_PTRDIFFT,
FMTCHECK_SIZET,
+ FMTCHECK_CHARPOINTER,
FMTCHECK_SHORTPOINTER,
FMTCHECK_INTPOINTER,
FMTCHECK_LONGPOINTER,
FMTCHECK_QUADPOINTER,
+ FMTCHECK_INTMAXTPOINTER,
FMTCHECK_PTRDIFFTPOINTER,
FMTCHECK_SIZETPOINTER,
#ifndef NO_FLOATING_POINT
@@ -62,6 +66,7 @@ enum __e_fmtcheck_types {
FMTCHECK_LONGDOUBLE,
#endif
FMTCHECK_STRING,
+ FMTCHECK_WSTRING,
FMTCHECK_WIDTH,
FMTCHECK_PRECISION,
FMTCHECK_DONE,
@@ -69,6 +74,18 @@ enum __e_fmtcheck_types {
};
typedef enum __e_fmtcheck_types EFT;
+enum e_modifier {
+ MOD_NONE,
+ MOD_CHAR,
+ MOD_SHORT,
+ MOD_LONG,
+ MOD_QUAD,
+ MOD_INTMAXT,
+ MOD_LONGDOUBLE,
+ MOD_PTRDIFFT,
+ MOD_SIZET,
+};
+
#define RETURN(pf,f,r) do { \
*(pf) = (f); \
return r; \
@@ -77,101 +94,148 @@ typedef enum __e_fmtcheck_types EFT;
static EFT
get_next_format_from_precision(const char **pf)
{
- int sh, lg, quad, longdouble, ptrdifft, sizet;
+ enum e_modifier modifier;
const char *f;
- sh = lg = quad = longdouble = ptrdifft = sizet = 0;
-
f = *pf;
switch (*f) {
case 'h':
f++;
- sh = 1;
+ if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (*f == 'h') {
+ f++;
+ modifier = MOD_CHAR;
+ } else {
+ modifier = MOD_SHORT;
+ }
+ break;
+ case 'j':
+ f++;
+ modifier = MOD_INTMAXT;
break;
case 'l':
f++;
if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
if (*f == 'l') {
f++;
- quad = 1;
+ modifier = MOD_QUAD;
} else {
- lg = 1;
+ modifier = MOD_LONG;
}
break;
case 'q':
f++;
- quad = 1;
+ modifier = MOD_QUAD;
break;
case 't':
f++;
- ptrdifft = 1;
+ modifier = MOD_PTRDIFFT;
break;
case 'z':
f++;
- sizet = 1;
+ modifier = MOD_SIZET;
break;
case 'L':
f++;
- longdouble = 1;
+ modifier = MOD_LONGDOUBLE;
break;
default:
+ modifier = MOD_NONE;
break;
}
if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
if (strchr("diouxX", *f)) {
- if (longdouble)
- RETURN(pf,f,FMTCHECK_UNKNOWN);
- if (lg)
+ switch (modifier) {
+ case MOD_LONG:
RETURN(pf,f,FMTCHECK_LONG);
- if (quad)
+ case MOD_QUAD:
RETURN(pf,f,FMTCHECK_QUAD);
- if (ptrdifft)
+ case MOD_INTMAXT:
+ RETURN(pf,f,FMTCHECK_INTMAXT);
+ case MOD_PTRDIFFT:
RETURN(pf,f,FMTCHECK_PTRDIFFT);
- if (sizet)
+ case MOD_SIZET:
RETURN(pf,f,FMTCHECK_SIZET);
- RETURN(pf,f,FMTCHECK_INT);
+ case MOD_CHAR:
+ case MOD_SHORT:
+ case MOD_NONE:
+ RETURN(pf,f,FMTCHECK_INT);
+ default:
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
}
if (*f == 'n') {
- if (longdouble)
- RETURN(pf,f,FMTCHECK_UNKNOWN);
- if (sh)
+ switch (modifier) {
+ case MOD_CHAR:
+ RETURN(pf,f,FMTCHECK_CHARPOINTER);
+ case MOD_SHORT:
RETURN(pf,f,FMTCHECK_SHORTPOINTER);
- if (lg)
+ case MOD_LONG:
RETURN(pf,f,FMTCHECK_LONGPOINTER);
- if (quad)
+ case MOD_QUAD:
RETURN(pf,f,FMTCHECK_QUADPOINTER);
- if (ptrdifft)
+ case MOD_INTMAXT:
+ RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
+ case MOD_PTRDIFFT:
RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
- if (sizet)
+ case MOD_SIZET:
RETURN(pf,f,FMTCHECK_SIZETPOINTER);
- RETURN(pf,f,FMTCHECK_INTPOINTER);
+ case MOD_NONE:
+ RETURN(pf,f,FMTCHECK_INTPOINTER);
+ default:
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
}
if (strchr("DOU", *f)) {
- if (sh + lg + quad + longdouble + ptrdifft + sizet)
+ if (modifier != MOD_NONE)
RETURN(pf,f,FMTCHECK_UNKNOWN);
RETURN(pf,f,FMTCHECK_LONG);
}
#ifndef NO_FLOATING_POINT
if (strchr("aAeEfFgG", *f)) {
- if (longdouble)
+ switch (modifier) {
+ case MOD_LONGDOUBLE:
RETURN(pf,f,FMTCHECK_LONGDOUBLE);
- if (sh + lg + quad + ptrdifft + sizet)
+ case MOD_LONG:
+ case MOD_NONE:
+ RETURN(pf,f,FMTCHECK_DOUBLE);
+ default:
RETURN(pf,f,FMTCHECK_UNKNOWN);
- RETURN(pf,f,FMTCHECK_DOUBLE);
+ }
}
#endif
if (*f == 'c') {
- if (sh + lg + quad + longdouble + ptrdifft + sizet)
+ switch (modifier) {
+ case MOD_LONG:
+ RETURN(pf,f,FMTCHECK_WINTT);
+ case MOD_NONE:
+ RETURN(pf,f,FMTCHECK_INT);
+ default:
RETURN(pf,f,FMTCHECK_UNKNOWN);
- RETURN(pf,f,FMTCHECK_INT);
+ }
+ }
+ if (*f == 'C') {
+ if (modifier != MOD_NONE)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_WINTT);
}
if (*f == 's') {
- if (sh + lg + quad + longdouble + ptrdifft + sizet)
+ switch (modifier) {
+ case MOD_LONG:
+ RETURN(pf,f,FMTCHECK_WSTRING);
+ case MOD_NONE:
+ RETURN(pf,f,FMTCHECK_STRING);
+ default:
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
+ }
+ if (*f == 'S') {
+ if (modifier != MOD_NONE)
RETURN(pf,f,FMTCHECK_UNKNOWN);
- RETURN(pf,f,FMTCHECK_STRING);
+ RETURN(pf,f,FMTCHECK_WSTRING);
}
if (*f == 'p') {
- if (sh + lg + quad + longdouble + ptrdifft + sizet)
+ if (modifier != MOD_NONE)
RETURN(pf,f,FMTCHECK_UNKNOWN);
RETURN(pf,f,FMTCHECK_LONG);
}
OpenPOWER on IntegriCloud