Sync fmtcheck(3) with FreeBSD, teaching it some new flags and args.
authorPeter Avalos <pavalos@theshell.com>
Thu, 26 Feb 2009 07:32:43 +0000 (02:32 -0500)
committerPeter Avalos <pavalos@theshell.com>
Tue, 7 Apr 2009 07:09:24 +0000 (21:09 -1000)
lib/libc/gen/fmtcheck.3
lib/libc/gen/fmtcheck.c

index 6887097..483dc47 100644 (file)
@@ -31,9 +31,9 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libc/gen/fmtcheck.3,v 1.2.2.4 2003/03/13 18:05:37 trhodes Exp $
+.\" $FreeBSD: src/lib/libc/gen/fmtcheck.3,v 1.10 2008/08/02 06:02:42 das Exp $
 .\" $DragonFly: src/lib/libc/gen/fmtcheck.3,v 1.2 2003/06/17 04:26:42 dillon Exp $
-.Dd October 17, 2000
+.Dd October 16, 2002
 .Os
 .Dt FMTCHECK 3
 .Sh NAME
@@ -65,7 +65,8 @@ is a valid format string.
 The
 .Xr printf 3
 family of functions cannot verify the types of arguments that they are
-passed at run-time.  In some cases, like
+passed at run-time.
+In some cases, like
 .Xr catgets 3 ,
 it is useful or necessary to use a user-supplied format string with no
 guarantee that the format string matches the specified arguments.
@@ -77,10 +78,11 @@ was designed to be used in these cases, as in:
 printf(fmtcheck(user_format, standard_format), arg1, arg2);
 .Ed
 .Pp
-In the check, field widths, fillers, precisions, etc. are ignored (unless
+In the check, field widths, fillers, precisions, etc.\& are ignored (unless
 the field width or precision is an asterisk
 .Ql *
-instead of a digit string).  Also, any text other than the format specifiers
+instead of a digit string).
+Also, any text other than the format specifiers
 is completely ignored.
 .Sh RETURN VALUES
 If
@@ -95,7 +97,8 @@ Otherwise, it will return
 .Fa fmt_default .
 .Sh SECURITY CONSIDERATIONS
 Note that the formats may be quite different as long as they accept the
-same arguments.  For example,
+same arguments.
+For example,
 .Qq Li "%p %o %30s %#llx %-10.*e %n"
 is compatible with
 .Qq Li "This number %lu %d%% and string %s has %qd numbers and %.*g floats (%n)" .
@@ -110,6 +113,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.
index 2140f24..b1c96f0 100644 (file)
@@ -1,7 +1,3 @@
-/*     $FreeBSD: src/lib/libc/gen/fmtcheck.c,v 1.1.2.1 2001/07/05 07:43:42 kris Exp $  */
-/*     $DragonFly: src/lib/libc/gen/fmtcheck.c,v 1.3 2003/08/22 19:31:21 asmodai Exp $ */
-/*     $NetBSD: fmtcheck.c,v 1.2 2000/11/01 01:17:20 briggs Exp $      */
-
 /*-
  * Copyright (c) 2000 The NetBSD Foundation, Inc.
  * All rights reserved.
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libc/gen/fmtcheck.c,v 1.1.2.1 2001/07/05 07:43:42 kris Exp $
+ * $NetBSD: fmtcheck.c,v 1.2 2000/11/01 01:17:20 briggs Exp $
+ * $FreeBSD: src/lib/libc/gen/fmtcheck.c,v 1.9 2008/08/02 06:02:42 das Exp $
+ * $DragonFly: src/lib/libc/gen/fmtcheck.c,v 1.3 2003/08/22 19:31:21 asmodai Exp $
  */
 
-#include <sys/cdefs.h>
-
-#include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
 
-#ifdef __weak_alias
-__weak_alias(fmtcheck,__fmtcheck)
-#endif
+__weak_reference(__fmtcheck, fmtcheck);
 
 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
        FMTCHECK_DOUBLE,
        FMTCHECK_LONGDOUBLE,
+#endif
        FMTCHECK_STRING,
+       FMTCHECK_WSTRING,
        FMTCHECK_WIDTH,
        FMTCHECK_PRECISION,
        FMTCHECK_DONE,
@@ -70,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; \
@@ -78,83 +94,148 @@ typedef enum __e_fmtcheck_types EFT;
 static EFT
 get_next_format_from_precision(const char **pf)
 {
-       int             sh, lg, quad, longdouble;
+       enum e_modifier modifier;
        const char      *f;
 
-       sh = lg = quad = longdouble = 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++;
+               modifier = MOD_PTRDIFFT;
+               break;
+       case 'z':
+               f++;
+               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);
-               RETURN(pf,f,FMTCHECK_INT);
+               case MOD_INTMAXT:
+                       RETURN(pf,f,FMTCHECK_INTMAXT);
+               case MOD_PTRDIFFT:
+                       RETURN(pf,f,FMTCHECK_PTRDIFFT);
+               case MOD_SIZET:
+                       RETURN(pf,f,FMTCHECK_SIZET);
+               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);
-               RETURN(pf,f,FMTCHECK_INTPOINTER);
+               case MOD_INTMAXT:
+                       RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
+               case MOD_PTRDIFFT:
+                       RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
+               case MOD_SIZET:
+                       RETURN(pf,f,FMTCHECK_SIZETPOINTER);
+               case MOD_NONE:
+                       RETURN(pf,f,FMTCHECK_INTPOINTER);
+               default:
+                       RETURN(pf,f,FMTCHECK_UNKNOWN);
+               }
        }
        if (strchr("DOU", *f)) {
-               if (sh + lg + quad + longdouble)
+               if (modifier != MOD_NONE)
                        RETURN(pf,f,FMTCHECK_UNKNOWN);
                RETURN(pf,f,FMTCHECK_LONG);
        }
-       if (strchr("eEfg", *f)) {
-               if (longdouble)
+#ifndef NO_FLOATING_POINT
+       if (strchr("aAeEfFgG", *f)) {
+               switch (modifier) {
+               case MOD_LONGDOUBLE:
                        RETURN(pf,f,FMTCHECK_LONGDOUBLE);
-               if (sh + lg + quad)
+               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)
+               switch (modifier) {
+               case MOD_LONG:
+                       RETURN(pf,f,FMTCHECK_WINTT);
+               case MOD_NONE:
+                       RETURN(pf,f,FMTCHECK_INT);
+               default:
+                       RETURN(pf,f,FMTCHECK_UNKNOWN);
+               }
+       }
+       if (*f == 'C') {
+               if (modifier != MOD_NONE)
                        RETURN(pf,f,FMTCHECK_UNKNOWN);
-               RETURN(pf,f,FMTCHECK_INT);
+               RETURN(pf,f,FMTCHECK_WINTT);
        }
        if (*f == 's') {
-               if (sh + lg + quad + longdouble)
+               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)
+               if (modifier != MOD_NONE)
                        RETURN(pf,f,FMTCHECK_UNKNOWN);
                RETURN(pf,f,FMTCHECK_LONG);
        }
@@ -211,7 +292,7 @@ get_next_format(const char **pf, EFT eft)
        }
 
        /* Eat any of the flags */
-       while (*f && (strchr("#0- +", *f)))
+       while (*f && (strchr("#'0- +", *f)))
                f++;
 
        if (*f == '*') {
@@ -228,7 +309,7 @@ get_next_format(const char **pf, EFT eft)
 }
 
 const char *
-fmtcheck(const char *f1, const char *f2)
+__fmtcheck(const char *f1, const char *f2)
 {
        const char      *f1p, *f2p;
        EFT             f1t, f2t;