[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [mini-os master] mini-os: replace lib/printf.c with a version not under GPL



commit fbe3767c03cab5de8566a4d9978dfc76320f4a4e
Author:     Juergen Gross <jgross@xxxxxxxx>
AuthorDate: Mon Jul 4 11:16:59 2016 +0200
Commit:     Wei Liu <wei.liu2@xxxxxxxxxx>
CommitDate: Tue Jul 12 12:19:51 2016 +0100

    mini-os: replace lib/printf.c with a version not under GPL
    
    Instead of a Linux kernel based implementation use one from FreeBSD.
    
    As a result some of the printings will change due to more posix like
    behavior of %p format (omitting leading zeroes, prepending "0x").
    
    Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
    Acked-by: Samuel Thibault <samuel.thibault@xxxxxxxxxxxx>
    [ wei: s/freeBSD/FreeBSD/ in commit message and code comment ]
---
 blkfront.c        |    4 -
 include/lib-gpl.h |   59 --
 include/lib.h     |   27 +-
 lib/printf.c      | 1742 +++++++++++++++++++++++++++++++++--------------------
 tpmback.c         |    4 -
 5 files changed, 1118 insertions(+), 718 deletions(-)

diff --git a/blkfront.c b/blkfront.c
index bdb7765..f747216 100644
--- a/blkfront.c
+++ b/blkfront.c
@@ -17,10 +17,6 @@
 #include <mini-os/lib.h>
 #include <fcntl.h>
 
-#ifndef HAVE_LIBC
-#define strtoul simple_strtoul
-#endif
-
 /* Note: we generally don't need to disable IRQs since we hardly do anything in
  * the interrupt handler.  */
 
diff --git a/include/lib-gpl.h b/include/lib-gpl.h
deleted file mode 100644
index d5602b2..0000000
--- a/include/lib-gpl.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*-  Mode:C; c-basic-offset:4; tab-width:4 -*-
- ****************************************************************************
- * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
- ****************************************************************************
- *
- *        File: lib.h
- *      Author: Rolf Neugebauer (neugebar@xxxxxxxxxxxxx)
- *     Changes: 
- *              
- *        Date: Aug 2003
- * 
- * Environment: Xen Minimal OS
- * Description: Random useful library functions, from Linux'
- * include/linux/kernel.h
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#ifndef _LIB_GPL_H_
-#define _LIB_GPL_H_
-
-#ifndef HAVE_LIBC
-/* printing */
-extern unsigned long simple_strtoul(const char *,char **,unsigned int);
-extern long simple_strtol(const char *,char **,unsigned int);
-extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
-extern long long simple_strtoll(const char *,char **,unsigned int);
-
-extern int sprintf(char * buf, const char * fmt, ...)
-       __attribute__ ((format (printf, 2, 3)));
-extern int vsprintf(char *buf, const char *, va_list)
-       __attribute__ ((format (printf, 2, 0)));
-extern int snprintf(char * buf, size_t size, const char * fmt, ...)
-       __attribute__ ((format (printf, 3, 4)));
-extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
-       __attribute__ ((format (printf, 3, 0)));
-extern int scnprintf(char * buf, size_t size, const char * fmt, ...)
-       __attribute__ ((format (printf, 3, 4)));
-extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
-       __attribute__ ((format (printf, 3, 0)));
-extern int sscanf(const char *, const char *, ...)
-       __attribute__ ((format (scanf, 2, 3)));
-extern int vsscanf(const char *, const char *, va_list)
-       __attribute__ ((format (scanf, 2, 0)));
-#endif
-
-#endif /* _LIB_GPL_H_ */
diff --git a/include/lib.h b/include/lib.h
index 62836c7..39d6a18 100644
--- a/include/lib.h
+++ b/include/lib.h
@@ -66,11 +66,6 @@
 #ifdef HAVE_LIBC
 #include <sys/queue.h>
 #include <stdio.h>
-#else
-#include <lib-gpl.h>
-#endif
-
-#ifdef HAVE_LIBC
 #include <string.h>
 #else
 /* string and memory manipulation */
@@ -107,6 +102,28 @@ char *strrchr(const char *p, int ch);
 void   *memcpy(void *to, const void *from, size_t len);
 
 size_t strnlen(const char *, size_t);
+
+unsigned long strtoul(const char *nptr, char **endptr, int base);
+int64_t strtoq(const char *nptr, char **endptr, int base);
+uint64_t strtouq(const char *nptr, char **endptr, int base);
+
+extern int sprintf(char * buf, const char * fmt, ...)
+        __attribute__ ((format (printf, 2, 3)));
+extern int vsprintf(char *buf, const char *, va_list)
+        __attribute__ ((format (printf, 2, 0)));
+extern int snprintf(char * buf, size_t size, const char * fmt, ...)
+        __attribute__ ((format (printf, 3, 4)));
+extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+        __attribute__ ((format (printf, 3, 0)));
+extern int scnprintf(char * buf, size_t size, const char * fmt, ...)
+        __attribute__ ((format (printf, 3, 4)));
+extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+        __attribute__ ((format (printf, 3, 0)));
+extern int sscanf(const char *, const char *, ...)
+        __attribute__ ((format (scanf, 2, 3)));
+extern int vsscanf(const char *, const char *, va_list)
+        __attribute__ ((format (scanf, 2, 0)));
+
 #endif
 
 #include <mini-os/console.h>
diff --git a/lib/printf.c b/lib/printf.c
index 40f92fc..ad6a304 100644
--- a/lib/printf.c
+++ b/lib/printf.c
@@ -1,50 +1,53 @@
 /*
  ****************************************************************************
- * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
- ****************************************************************************
  *
  *        File: printf.c
- *      Author: Rolf Neugebauer (neugebar@xxxxxxxxxxxxx)
- *     Changes: Grzegorz Milos (gm281@xxxxxxxxx) 
+ *      Author: Juergen Gross <jgross@xxxxxxxx>
  *
- *        Date: Aug 2003, Aug 2005
+ *        Date: Jun 2016
  *
  * Environment: Xen Minimal OS
  * Description: Library functions for printing
- *              (Linux port, mainly lib/vsprintf.c)
+ *              (FreeBSD port)
  *
  ****************************************************************************
  */
 
-/*
- * Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
-/*
- * Wirzenius wrote this portably, Torvalds fucked it up :-)
- */
-
-/*
- * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@xxxxxxxxxxxxxx>
- * - changed to provide snprintf and vsnprintf functions
- * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@xxxxxxx>
- * - scnprintf and vscnprintf
+/*-
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #if !defined HAVE_LIBC
@@ -57,449 +60,529 @@
 #include <mini-os/ctype.h>
 #include <mini-os/posix/limits.h>
 
-/**
- * simple_strtoul - convert a string to an unsigned long
- * @cp: The start of the string
- * @endp: A pointer to the end of the parsed string will be placed here
- * @base: The number base to use
- */
-unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
-{
-    unsigned long result = 0,value;
-
-    if (!base) {
-        base = 10;
-        if (*cp == '0') {
-            base = 8;
-            cp++;
-            if ((*cp == 'x') && isxdigit(cp[1])) {
-                cp++;
-                base = 16;
-            }
-        }
-    }
-    while (isxdigit(*cp) &&
-           (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
-        result = result*base + value;
-        cp++;
-    }
-    if (endp)
-        *endp = (char *)cp;
-    return result;
-}
+#define __DECONST(type, var)    ((type)(uintptr_t)(const void *)(var))
+/* 64 bits + 0-Byte at end */
+#define MAXNBUF        65
 
-/**
- * simple_strtol - convert a string to a signed long
- * @cp: The start of the string
- * @endp: A pointer to the end of the parsed string will be placed here
- * @base: The number base to use
+static char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+/*
+ * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
+ * order; return an optional length and a pointer to the last character
+ * written in the buffer (i.e., the first character of the string).
+ * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
  */
-long simple_strtol(const char *cp,char **endp,unsigned int base)
+static char *
+ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
 {
-    if(*cp=='-')
-        return -simple_strtoul(cp+1,endp,base);
-    return simple_strtoul(cp,endp,base);
+       char *p, c;
+
+       p = nbuf;
+       *p = '\0';
+       do {
+               c = hex2ascii_data[num % base];
+               *++p = upper ? toupper(c) : c;
+       } while (num /= base);
+       if (lenp)
+               *lenp = p - nbuf;
+       return (p);
 }
 
-/**
- * simple_strtoull - convert a string to an unsigned long long
- * @cp: The start of the string
- * @endp: A pointer to the end of the parsed string will be placed here
- * @base: The number base to use
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
  */
-unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int 
base)
+unsigned long
+strtoul(const char *nptr, char **endptr, int base)
 {
-    unsigned long long result = 0,value;
-
-    if (!base) {
-        base = 10;
-        if (*cp == '0') {
-            base = 8;
-            cp++;
-            if ((*cp == 'x') && isxdigit(cp[1])) {
-                cp++;
+        const char *s = nptr;
+        unsigned long acc;
+        unsigned char c;
+        unsigned long cutoff;
+        int neg = 0, any, cutlim;
+
+        /*
+         * See strtol for comments as to the logic used.
+         */
+        do {
+                c = *s++;
+        } while (isspace(c));
+        if (c == '-') {
+                neg = 1;
+                c = *s++;
+        } else if (c == '+')
+                c = *s++;
+        if ((base == 0 || base == 16) &&
+            c == '0' && (*s == 'x' || *s == 'X')) {
+                c = s[1];
+                s += 2;
                 base = 16;
-            }
         }
-    }
-    while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
-                                                               ? toupper(*cp) 
: *cp)-'A'+10) < base) {
-        result = result*base + value;
-        cp++;
-    }
-    if (endp)
-        *endp = (char *)cp;
-    return result;
+        if (base == 0)
+                base = c == '0' ? 8 : 10;
+        cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
+        cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
+        for (acc = 0, any = 0;; c = *s++) {
+                if (!isascii(c))
+                        break;
+                if (isdigit(c))
+                        c -= '0';
+                else if (isalpha(c))
+                        c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+                else
+                        break;
+                if (c >= base)
+                        break;
+                if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+                        any = -1;
+                else {
+                        any = 1;
+                        acc *= base;
+                        acc += c;
+                }
+        }
+        if (any < 0) {
+                acc = ULONG_MAX;
+        } else if (neg)
+                acc = -acc;
+        if (endptr != 0)
+                *endptr = __DECONST(char *, any ? s - 1 : nptr);
+        return (acc);
 }
 
-/**
- * simple_strtoll - convert a string to a signed long long
- * @cp: The start of the string
- * @endp: A pointer to the end of the parsed string will be placed here
- * @base: The number base to use
+/*
+ * Convert a string to a quad integer.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
  */
-long long simple_strtoll(const char *cp,char **endp,unsigned int base)
+int64_t
+strtoq(const char *nptr, char **endptr, int base)
 {
-    if(*cp=='-')
-        return -simple_strtoull(cp+1,endp,base);
-    return simple_strtoull(cp,endp,base);
-}
+        const char *s;
+        uint64_t acc;
+        unsigned char c;
+        uint64_t qbase, cutoff;
+        int neg, any, cutlim;
 
-static int skip_atoi(const char **s)
-{
-    int i=0;
+        /*
+         * Skip white space and pick up leading +/- sign if any.
+         * If base is 0, allow 0x for hex and 0 for octal, else
+         * assume decimal; if base is already 16, allow 0x.
+         */
+        s = nptr;
+        do {
+                c = *s++;
+        } while (isspace(c));
+        if (c == '-') {
+                neg = 1;
+                c = *s++;
+        } else {
+                neg = 0;
+                if (c == '+')
+                        c = *s++;
+        }
+        if ((base == 0 || base == 16) &&
+            c == '0' && (*s == 'x' || *s == 'X')) {
+                c = s[1];
+                s += 2;
+                base = 16;
+        }
+        if (base == 0)
+                base = c == '0' ? 8 : 10;
 
-    while (isdigit(**s))
-        i = i*10 + *((*s)++) - '0';
-    return i;
+        /*
+         * Compute the cutoff value between legal numbers and illegal
+         * numbers.  That is the largest legal value, divided by the
+         * base.  An input number that is greater than this value, if
+         * followed by a legal input character, is too big.  One that
+         * is equal to this value may be valid or not; the limit
+         * between valid and invalid numbers is then based on the last
+         * digit.  For instance, if the range for quads is
+         * [-9223372036854775808..9223372036854775807] and the input base
+         * is 10, cutoff will be set to 922337203685477580 and cutlim to
+         * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+         * accumulated a value > 922337203685477580, or equal but the
+         * next digit is > 7 (or 8), the number is too big, and we will
+         * return a range error.
+         *
+         * Set any if any `digits' consumed; make it negative to indicate
+         * overflow.
+         */
+        qbase = (unsigned)base;
+        cutoff = neg ? (uint64_t)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX : 
LLONG_MAX;
+        cutlim = cutoff % qbase;
+        cutoff /= qbase;
+        for (acc = 0, any = 0;; c = *s++) {
+                if (!isascii(c))
+                        break;
+                if (isdigit(c))
+                        c -= '0';
+                else if (isalpha(c))
+                        c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+                else
+                        break;
+                if (c >= base)
+                        break;
+                if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+                        any = -1;
+                else {
+                        any = 1;
+                        acc *= qbase;
+                        acc += c;
+                }
+        }
+        if (any < 0) {
+                acc = neg ? LLONG_MIN : LLONG_MAX;
+        } else if (neg)
+                acc = -acc;
+        if (endptr != 0)
+                *endptr = __DECONST(char *, any ? s - 1 : nptr);
+        return (acc);
 }
 
-#define ZEROPAD 1               /* pad with zero */
-#define SIGN    2               /* unsigned/signed long */
-#define PLUS    4               /* show plus */
-#define SPACE   8               /* space if plus */
-#define LEFT    16              /* left justified */
-#define SPECIAL 32              /* 0x */
-#define LARGE   64              /* use 'ABCDEF' instead of 'abcdef' */
-
-static char * number(char * buf, char * end, long long num, int base, int 
size, int precision, int type)
+/*
+ * Convert a string to an unsigned quad integer.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+uint64_t
+strtouq(const char *nptr, char **endptr, int base)
 {
-    char c,sign,tmp[66];
-    const char *digits;
-    const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-    const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-    int i;
+        const char *s = nptr;
+        uint64_t acc;
+        unsigned char c;
+        uint64_t qbase, cutoff;
+        int neg, any, cutlim;
 
-    digits = (type & LARGE) ? large_digits : small_digits;
-    if (type & LEFT)
-        type &= ~ZEROPAD;
-    if (base < 2 || base > 36)
-        return buf;
-    c = (type & ZEROPAD) ? '0' : ' ';
-    sign = 0;
-    if (type & SIGN) {
-        if (num < 0) {
-            sign = '-';
-            num = -num;
-            size--;
-        } else if (type & PLUS) {
-            sign = '+';
-            size--;
-        } else if (type & SPACE) {
-            sign = ' ';
-            size--;
-        }
-    }
-    if (type & SPECIAL) {
-        if (base == 16)
-            size -= 2;
-        else if (base == 8)
-            size--;
-    }
-    i = 0;
-    if (num == 0)
-        tmp[i++]='0';
-    else 
-    {
-        /* XXX KAF: force unsigned mod and div. */
-        unsigned long long num2=(unsigned long long)num;
-        unsigned int base2=(unsigned int)base;
-        while (num2 != 0) { tmp[i++] = digits[num2%base2]; num2 /= base2; }
-    }
-    if (i > precision)
-        precision = i;
-    size -= precision;
-    if (!(type&(ZEROPAD+LEFT))) {
-        while(size-->0) {
-            if (buf <= end)
-                *buf = ' ';
-            ++buf;
+        /*
+         * See strtoq for comments as to the logic used.
+         */
+        do {
+                c = *s++;
+        } while (isspace(c));
+        if (c == '-') {
+                neg = 1;
+                c = *s++;
+        } else {
+                neg = 0;
+                if (c == '+')
+                        c = *s++;
         }
-    }
-    if (sign) {
-        if (buf <= end)
-            *buf = sign;
-        ++buf;
-    }
-    if (type & SPECIAL) {
-        if (base==8) {
-            if (buf <= end)
-                *buf = '0';
-            ++buf;
-        } else if (base==16) {
-            if (buf <= end)
-                *buf = '0';
-            ++buf;
-            if (buf <= end)
-                *buf = digits[33];
-            ++buf;
+        if ((base == 0 || base == 16) &&
+            c == '0' && (*s == 'x' || *s == 'X')) {
+                c = s[1];
+                s += 2;
+                base = 16;
         }
-    }
-    if (!(type & LEFT)) {
-        while (size-- > 0) {
-            if (buf <= end)
-                *buf = c;
-            ++buf;
+        if (base == 0)
+                base = c == '0' ? 8 : 10;
+        qbase = (unsigned)base;
+        cutoff = (uint64_t)ULLONG_MAX / qbase;
+        cutlim = (uint64_t)ULLONG_MAX % qbase;
+        for (acc = 0, any = 0;; c = *s++) {
+                if (!isascii(c))
+                        break;
+                if (isdigit(c))
+                        c -= '0';
+                else if (isalpha(c))
+                        c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+                else
+                        break;
+                if (c >= base)
+                        break;
+                if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+                        any = -1;
+                else {
+                        any = 1;
+                        acc *= qbase;
+                        acc += c;
+                }
         }
-    }
-    while (i < precision--) {
-        if (buf <= end)
-            *buf = '0';
-        ++buf;
-    }
-    while (i-- > 0) {
-        if (buf <= end)
-            *buf = tmp[i];
-        ++buf;
-    }
-    while (size-- > 0) {
-        if (buf <= end)
-            *buf = ' ';
-        ++buf;
-    }
-    return buf;
+        if (any < 0) {
+                acc = ULLONG_MAX;
+        } else if (neg)
+                acc = -acc;
+        if (endptr != 0)
+                *endptr = __DECONST(char *, any ? s - 1 : nptr);
+        return (acc);
 }
 
-/**
-* vsnprintf - Format a string and place it in a buffer
-* @buf: The buffer to place the result into
-* @size: The size of the buffer, including the trailing null space
-* @fmt: The format string to use
-* @args: Arguments for the format string
-*
-* Call this function if you are already dealing with a va_list.
-* You probably want snprintf instead.
+/*
+ * Scaled down version of printf(3).
  */
-int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+int
+vsnprintf(char *str, size_t size, char const *fmt, va_list ap)
 {
-    int len;
-    unsigned long long num;
-    int i, base;
-    char *str, *end, c;
-    const char *s;
-
-    int flags;          /* flags to number() */
-
-    int field_width;    /* width of output field */
-    int precision;              /* min. # of digits for integers; max
-                                   number of chars for from string */
-    int qualifier;              /* 'h', 'l', or 'L' for integer fields */
-                                /* 'z' support added 23/7/1999 S.H.    */
-                                /* 'z' changed to 'Z' --davidm 1/25/99 */
-
-    str = buf;
-    end = buf + size - 1;
-
-    if (end < buf - 1) {
-        end = ((void *) -1);
-        size = end - buf + 1;
-    }
-
-    for (; *fmt ; ++fmt) {
-        if (*fmt != '%') {
-            if (str <= end)
-                *str = *fmt;
-            ++str;
-            continue;
-        }
+#define PCHAR(c) { if (size >= 2) { *str++ = c; size--; } retval++; }
+        char nbuf[MAXNBUF];
+        const char *p, *percent;
+        int ch, n;
+        uintmax_t num;
+        int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
+        int cflag, hflag, jflag, tflag, zflag;
+        int dwidth, upper;
+        char padc;
+        int stop = 0, retval = 0;
 
-        /* process flags */
-        flags = 0;
-    repeat:
-        ++fmt;          /* this also skips first '%' */
-        switch (*fmt) {
-        case '-': flags |= LEFT; goto repeat;
-        case '+': flags |= PLUS; goto repeat;
-        case ' ': flags |= SPACE; goto repeat;
-        case '#': flags |= SPECIAL; goto repeat;
-        case '0': flags |= ZEROPAD; goto repeat;
-        }
+        num = 0;
 
-        /* get field width */
-        field_width = -1;
-        if (isdigit(*fmt))
-            field_width = skip_atoi(&fmt);
-        else if (*fmt == '*') {
-            ++fmt;
-            /* it's the next argument */
-            field_width = va_arg(args, int);
-            if (field_width < 0) {
-                field_width = -field_width;
-                flags |= LEFT;
-            }
-        }
+        if (fmt == NULL)
+                fmt = "(fmt null)\n";
 
-        /* get the precision */
-        precision = -1;
-        if (*fmt == '.') {
-            ++fmt;
-            if (isdigit(*fmt))
-                precision = skip_atoi(&fmt);
-            else if (*fmt == '*') {
-                ++fmt;
-                          /* it's the next argument */
-                precision = va_arg(args, int);
-            }
-            if (precision < 0)
-                precision = 0;
-        }
+        for (;;) {
+                padc = ' ';
+                width = 0;
+                while ((ch = (u_char)*fmt++) != '%' || stop) {
+                        if (ch == '\0') {
+                                if (size >= 1)
+                                        *str++ = '\0';
+                                return (retval);
+                        }
+                        PCHAR(ch);
+                }
+                percent = fmt - 1;
+                qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
+                sign = 0; dot = 0; dwidth = 0; upper = 0;
+                cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
+reswitch:       switch (ch = (u_char)*fmt++) {
+                case '.':
+                        dot = 1;
+                        goto reswitch;
+                case '#':
+                        sharpflag = 1;
+                        goto reswitch;
+                case '+':
+                        sign = 1;
+                        goto reswitch;
+                case '-':
+                        ladjust = 1;
+                        goto reswitch;
+                case '%':
+                        PCHAR(ch);
+                        break;
+                case '*':
+                        if (!dot) {
+                                width = va_arg(ap, int);
+                                if (width < 0) {
+                                        ladjust = !ladjust;
+                                        width = -width;
+                                }
+                        } else {
+                                dwidth = va_arg(ap, int);
+                        }
+                        goto reswitch;
+                case '0':
+                        if (!dot) {
+                                padc = '0';
+                                goto reswitch;
+                        }
+                case '1': case '2': case '3': case '4':
+                case '5': case '6': case '7': case '8': case '9':
+                                for (n = 0;; ++fmt) {
+                                        n = n * 10 + ch - '0';
+                                        ch = *fmt;
+                                        if (ch < '0' || ch > '9')
+                                                break;
+                                }
+                        if (dot)
+                                dwidth = n;
+                        else
+                                width = n;
+                        goto reswitch;
+                case 'c':
+                        PCHAR(va_arg(ap, int));
+                        break;
+                case 'd':
+                case 'i':
+                        base = 10;
+                        sign = 1;
+                        goto handle_sign;
+                case 'h':
+                        if (hflag) {
+                                hflag = 0;
+                                cflag = 1;
+                        } else
+                                hflag = 1;
+                        goto reswitch;
+                case 'j':
+                        jflag = 1;
+                        goto reswitch;
+                case 'l':
+                        if (lflag) {
+                                lflag = 0;
+                                qflag = 1;
+                        } else
+                                lflag = 1;
+                        goto reswitch;
+                case 'n':
+                        if (jflag)
+                                *(va_arg(ap, intmax_t *)) = retval;
+                        else if (qflag)
+                                *(va_arg(ap, int64_t *)) = retval;
+                        else if (lflag)
+                                *(va_arg(ap, long *)) = retval;
+                        else if (zflag)
+                                *(va_arg(ap, size_t *)) = retval;
+                        else if (hflag)
+                                *(va_arg(ap, short *)) = retval;
+                        else if (cflag)
+                                *(va_arg(ap, char *)) = retval;
+                        else
+                                *(va_arg(ap, int *)) = retval;
+                        break;
+                case 'o':
+                        base = 8;
+                        goto handle_nosign;
+                case 'p':
+                        base = 16;
+                        sharpflag = (width == 0);
+                        sign = 0;
+                        num = (uintptr_t)va_arg(ap, void *);
+                        goto number;
+                case 'q':
+                        qflag = 1;
+                        goto reswitch;
+                case 'r':
+                        base = 10;
+                        if (sign)
+                                goto handle_sign;
+                        goto handle_nosign;
+                case 's':
+                        p = va_arg(ap, char *);
+                        if (p == NULL)
+                                p = "(null)";
+                        if (!dot)
+                                n = strlen (p);
+                        else
+                                for (n = 0; n < dwidth && p[n]; n++)
+                                        continue;
 
-        /* get the conversion qualifier */
-        qualifier = -1;
-        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z' || *fmt == 
'z') {
-            qualifier = *fmt;
-            ++fmt;
-            if (qualifier == 'l' && *fmt == 'l') {
-                qualifier = 'L';
-                ++fmt;
-            } else if (qualifier == 'z') {
-                qualifier = 'Z';
-            }
-        }
-        if (*fmt == 'q') {
-            qualifier = 'L';
-            ++fmt;
-        }
+                        width -= n;
 
-        /* default base */
-        base = 10;
+                        if (!ladjust && width > 0)
+                                while (width--)
+                                        PCHAR(padc);
+                        while (n--)
+                                PCHAR(*p++);
+                        if (ladjust && width > 0)
+                                while (width--)
+                                        PCHAR(padc);
+                        break;
+                case 't':
+                        tflag = 1;
+                        goto reswitch;
+                case 'u':
+                        base = 10;
+                        goto handle_nosign;
+                case 'X':
+                        upper = 1;
+                case 'x':
+                        base = 16;
+                        goto handle_nosign;
+                case 'y':
+                        base = 16;
+                        sign = 1;
+                        goto handle_sign;
+                case 'z':
+                        zflag = 1;
+                        goto reswitch;
+handle_nosign:
+                        sign = 0;
+                        if (jflag)
+                                num = va_arg(ap, uintmax_t);
+                        else if (qflag)
+                                num = va_arg(ap, uint64_t);
+                        else if (tflag)
+                                num = va_arg(ap, ptrdiff_t);
+                        else if (lflag)
+                                num = va_arg(ap, u_long);
+                        else if (zflag)
+                                num = va_arg(ap, size_t);
+                        else if (hflag)
+                                num = (unsigned short)va_arg(ap, int);
+                        else if (cflag)
+                                num = (u_char)va_arg(ap, int);
+                        else
+                                num = va_arg(ap, u_int);
+                        goto number;
+handle_sign:
+                        if (jflag)
+                                num = va_arg(ap, intmax_t);
+                        else if (qflag)
+                                num = va_arg(ap, int64_t);
+                        else if (tflag)
+                                num = va_arg(ap, ptrdiff_t);
+                        else if (lflag)
+                                num = va_arg(ap, long);
+                        else if (zflag)
+                                num = va_arg(ap, ssize_t);
+                        else if (hflag)
+                                num = (short)va_arg(ap, int);
+                        else if (cflag)
+                                num = (char)va_arg(ap, int);
+                        else
+                                num = va_arg(ap, int);
+number:
+                        if (sign && (intmax_t)num < 0) {
+                                neg = 1;
+                                num = -(intmax_t)num;
+                        }
+                        p = ksprintn(nbuf, num, base, &n, upper);
+                        tmp = 0;
+                        if (sharpflag && num != 0) {
+                                if (base == 8)
+                                        tmp++;
+                                else if (base == 16)
+                                        tmp += 2;
+                        }
+                        if (neg)
+                                tmp++;
 
-        switch (*fmt) {
-        case 'c':
-            if (!(flags & LEFT)) {
-                while (--field_width > 0) {
-                    if (str <= end)
-                        *str = ' ';
-                    ++str;
-                }
-            }
-            c = (unsigned char) va_arg(args, int);
-            if (str <= end)
-                *str = c;
-            ++str;
-            while (--field_width > 0) {
-                if (str <= end)
-                    *str = ' ';
-                ++str;
-            }
-            continue;
-
-        case 's':
-            s = va_arg(args, char *);
-            if (!s)
-                s = "<NULL>";
-
-            len = strnlen(s, precision);
-
-            if (!(flags & LEFT)) {
-                while (len < field_width--) {
-                    if (str <= end)
-                        *str = ' ';
-                    ++str;
+                        if (!ladjust && padc == '0')
+                                dwidth = width - tmp;
+                        width -= tmp + (dwidth > n ? dwidth : n);
+                        dwidth -= n;
+                        if (!ladjust)
+                                while (width-- > 0)
+                                        PCHAR(' ');
+                        if (neg)
+                                PCHAR('-');
+                        if (sharpflag && num != 0) {
+                                if (base == 8) {
+                                        PCHAR('0');
+                                } else if (base == 16) {
+                                        PCHAR('0');
+                                        PCHAR('x');
+                                }
+                        }
+                        while (dwidth-- > 0)
+                                PCHAR('0');
+
+                        while (*p)
+                                PCHAR(*p--);
+
+                        if (ladjust)
+                                while (width-- > 0)
+                                        PCHAR(' ');
+
+                        break;
+                default:
+                        while (percent < fmt)
+                                PCHAR(*percent++);
+                        /*
+                         * Since we ignore a formatting argument it is no
+                         * longer safe to obey the remaining formatting
+                         * arguments as the arguments will no longer match
+                         * the format specs.
+                         */
+                        stop = 1;
+                        break;
                 }
-            }
-            for (i = 0; i < len; ++i) {
-                if (str <= end)
-                    *str = *s;
-                ++str; ++s;
-            }
-            while (len < field_width--) {
-                if (str <= end)
-                    *str = ' ';
-                ++str;
-            }
-            continue;
-
-        case 'p':
-            if (field_width == -1) {
-                field_width = 2*sizeof(void *);
-                flags |= ZEROPAD;
-            }
-            str = number(str, end,
-                         (unsigned long) va_arg(args, void *),
-                         16, field_width, precision, flags);
-            continue;
-
-
-        case 'n':
-            if (qualifier == 'l') {
-                long * ip = va_arg(args, long *);
-                *ip = (str - buf);
-            } else if (qualifier == 'Z') {
-                size_t * ip = va_arg(args, size_t *);
-                *ip = (str - buf);
-            } else {
-                int * ip = va_arg(args, int *);
-                *ip = (str - buf);
-            }
-            continue;
-
-        case '%':
-            if (str <= end)
-                *str = '%';
-            ++str;
-            continue;
-
-            /* integer number formats - set up the flags and "break" */
-        case 'o':
-            base = 8;
-            break;
-
-        case 'X':
-            flags |= LARGE;
-        case 'x':
-            base = 16;
-            break;
-
-        case 'd':
-        case 'i':
-            flags |= SIGN;
-        case 'u':
-            break;
-
-        default:
-            if (str <= end)
-                *str = '%';
-            ++str;
-            if (*fmt) {
-                if (str <= end)
-                    *str = *fmt;
-                ++str;
-            } else {
-                --fmt;
-            }
-            continue;
-        }
-        if (qualifier == 'L')
-            num = va_arg(args, long long);
-        else if (qualifier == 'l') {
-            num = va_arg(args, unsigned long);
-            if (flags & SIGN)
-                num = (signed long) num;
-        } else if (qualifier == 'Z') {
-            num = va_arg(args, size_t);
-        } else if (qualifier == 'h') {
-            num = (unsigned short) va_arg(args, int);
-            if (flags & SIGN)
-                num = (signed short) num;
-        } else {
-            num = va_arg(args, unsigned int);
-            if (flags & SIGN)
-                num = (signed int) num;
         }
-
-        str = number(str, end, num, base,
-                     field_width, precision, flags);
-    }
-    if (str <= end)
-        *str = '\0';
-    else if (size > 0)
-        /* don't write out a null byte if the buf size is zero */
-        *end = '\0';
-    /* the trailing null byte doesn't count towards the total
-     * ++str;
-     */
-    return str-buf;
+#undef PCHAR
 }
 
 /**
@@ -552,220 +635,587 @@ int sprintf(char * buf, const char *fmt, ...)
     return i;
 }
 
+/*
+ * Fill in the given table from the scanset at the given format
+ * (just after `[').  Return a pointer to the character past the
+ * closing `]'.  The table has a 1 wherever characters should be
+ * considered part of the scanset.
+ */
+static const u_char *
+__sccl(char *tab, const u_char *fmt)
+{
+        int c, n, v;
+
+        /* first `clear' the whole table */
+        c = *fmt++;             /* first char hat => negated scanset */
+        if (c == '^') {
+                v = 1;          /* default => accept */
+                c = *fmt++;     /* get new first char */
+        } else
+                v = 0;          /* default => reject */
+
+        /* XXX: Will not work if sizeof(tab*) > sizeof(char) */
+        for (n = 0; n < 256; n++)
+                     tab[n] = v;        /* memset(tab, v, 256) */
+
+        if (c == 0)
+                return (fmt - 1);/* format ended before closing ] */
+
+        /*
+         * Now set the entries corresponding to the actual scanset
+         * to the opposite of the above.
+         *
+         * The first character may be ']' (or '-') without being special;
+         * the last character may be '-'.
+         */
+        v = 1 - v;
+        for (;;) {
+                tab[c] = v;             /* take character c */
+doswitch:
+                n = *fmt++;             /* and examine the next */
+                switch (n) {
+
+                case 0:                 /* format ended too soon */
+                        return (fmt - 1);
+
+                case '-':
+                        /*
+                         * A scanset of the form
+                         *      [01+-]
+                         * is defined as `the digit 0, the digit 1,
+                         * the character +, the character -', but
+                         * the effect of a scanset such as
+                         *      [a-zA-Z0-9]
+                         * is implementation defined.  The V7 Unix
+                         * scanf treats `a-z' as `the letters a through
+                         * z', but treats `a-a' as `the letter a, the
+                         * character -, and the letter a'.
+                         *
+                         * For compatibility, the `-' is not considerd
+                         * to define a range if the character following
+                         * it is either a close bracket (required by ANSI)
+                         * or is not numerically greater than the character
+                         * we just stored in the table (c).
+                         */
+                        n = *fmt;
+                        if (n == ']' || n < c) {
+                                c = '-';
+                                break;  /* resume the for(;;) */
+                        }
+                        fmt++;
+                        /* fill in the range */
+                        do {
+                            tab[++c] = v;
+                        } while (c < n);
+                        c = n;
+                        /*
+                         * Alas, the V7 Unix scanf also treats formats
+                         * such as [a-c-e] as `the letters a through e'.
+                         * This too is permitted by the standard....
+                         */
+                        goto doswitch;
+                        break;
+
+                case ']':               /* end of scanset */
+                        return (fmt);
+
+                default:                /* just another character */
+                        c = n;
+                        break;
+                }
+        }
+        /* NOTREACHED */
+}
+
 /**
  * vsscanf - Unformat a buffer into a list of arguments
  * @buf:       input buffer
  * @fmt:       format of buffer
  * @args:      arguments
  */
-int vsscanf(const char * buf, const char * fmt, va_list args)
+#define BUF             32      /* Maximum length of numeric string. */
+
+/*
+ * Flags used during conversion.
+ */
+#define LONG            0x01    /* l: long or double */
+#define SHORT           0x04    /* h: short */
+#define SUPPRESS        0x08    /* suppress assignment */
+#define POINTER         0x10    /* weird %p pointer (`fake hex') */
+#define NOSKIP          0x20    /* do not skip blanks */
+#define QUAD            0x400
+#define SHORTSHORT      0x4000  /** hh: char */
+
+/*
+ * The following are used in numeric conversions only:
+ * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
+ * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
+ */
+#define SIGNOK          0x40    /* +/- is (still) legal */
+#define NDIGITS         0x80    /* no digits detected */
+
+#define DPTOK           0x100   /* (float) decimal point is still legal */
+#define EXPOK           0x200   /* (float) exponent (e+3, etc) still legal */
+
+#define PFXOK           0x100   /* 0x prefix is (still) legal */
+#define NZDIGITS        0x200   /* no zero digits detected */
+
+/*
+ * Conversion types.
+ */
+#define CT_CHAR         0       /* %c conversion */
+#define CT_CCL          1       /* %[...] conversion */
+#define CT_STRING       2       /* %s conversion */
+#define CT_INT          3       /* integer, i.e., strtoq or strtouq */
+typedef uint64_t (*ccfntype)(const char *, char **, int);
+
+int
+vsscanf(const char *inp, char const *fmt0, va_list ap)
 {
-       const char *str = buf;
-       char *next;
-       char digit;
-       int num = 0;
-       int qualifier;
-       int base;
-       int field_width;
-       int is_sign = 0;
-
-       while(*fmt && *str) {
-               /* skip any white space in format */
-               /* white space in format matchs any amount of
-                * white space, including none, in the input.
-                */
-               if (isspace(*fmt)) {
-                       while (isspace(*fmt))
-                               ++fmt;
-                       while (isspace(*str))
-                               ++str;
-               }
-
-               /* anything that is not a conversion must match exactly */
-               if (*fmt != '%' && *fmt) {
-                       if (*fmt++ != *str++)
-                               break;
-                       continue;
-               }
-
-               if (!*fmt)
-                       break;
-               ++fmt;
-               
-               /* skip this conversion.
-                * advance both strings to next white space
-                */
-               if (*fmt == '*') {
-                       while (!isspace(*fmt) && *fmt)
-                               fmt++;
-                       while (!isspace(*str) && *str)
-                               str++;
-                       continue;
-               }
-
-               /* get field width */
-               field_width = -1;
-               if (isdigit(*fmt))
-                       field_width = skip_atoi(&fmt);
-
-               /* get conversion qualifier */
-               qualifier = -1;
-               if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
-                   *fmt == 'Z' || *fmt == 'z') {
-                       qualifier = *fmt++;
-                       if (unlikely(qualifier == *fmt)) {
-                               if (qualifier == 'h') {
-                                       qualifier = 'H';
-                                       fmt++;
-                               } else if (qualifier == 'l') {
-                                       qualifier = 'L';
-                                       fmt++;
-                               }
-                       }
-               }
-               base = 10;
-               is_sign = 0;
-
-               if (!*fmt || !*str)
-                       break;
-
-               switch(*fmt++) {
-               case 'c':
-               {
-                       char *s = (char *) va_arg(args,char*);
-                       if (field_width == -1)
-                               field_width = 1;
-                       do {
-                               *s++ = *str++;
-                       } while (--field_width > 0 && *str);
-                       num++;
-               }
-               continue;
-               case 's':
-               {
-                       char *s = (char *) va_arg(args, char *);
-                       if(field_width == -1)
-                               field_width = INT_MAX;
-                       /* first, skip leading white space in buffer */
-                       while (isspace(*str))
-                               str++;
-
-                       /* now copy until next white space */
-                       while (*str && !isspace(*str) && field_width--) {
-                               *s++ = *str++;
-                       }
-                       *s = '\0';
-                       num++;
-               }
-               continue;
-               case 'n':
-                       /* return number of characters read so far */
-               {
-                       int *i = (int *)va_arg(args,int*);
-                       *i = str - buf;
-               }
-               continue;
-               case 'o':
-                       base = 8;
-                       break;
-               case 'x':
-               case 'X':
-                       base = 16;
-                       break;
-               case 'i':
+        int inr;
+        const u_char *fmt = (const u_char *)fmt0;
+        int c;                  /* character from format, or conversion */
+        size_t width;           /* field width, or 0 */
+        char *p;                /* points into all kinds of strings */
+        int n;                  /* handy integer */
+        int flags;              /* flags as defined above */
+        char *p0;               /* saves original value of p when necessary */
+        int nassigned;          /* number of fields assigned */
+        int nconversions;       /* number of conversions */
+        int nread;              /* number of characters consumed from fp */
+        int base;               /* base argument to strtoq/strtouq */
+        ccfntype ccfn;          /* conversion function (strtoq/strtouq) */
+        char ccltab[256];       /* character class table for %[...] */
+        char buf[BUF];          /* buffer for numeric conversions */
+
+        /* `basefix' is used to avoid `if' tests in the integer scanner */
+        static short basefix[17] =
+                { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+        inr = strlen(inp);
+
+        nassigned = 0;
+        nconversions = 0;
+        nread = 0;
+        base = 0;               /* XXX just to keep gcc happy */
+        ccfn = NULL;            /* XXX just to keep gcc happy */
+        for (;;) {
+                c = *fmt++;
+                if (c == 0)
+                        return (nassigned);
+                if (isspace(c)) {
+                        while (inr > 0 && isspace(*inp))
+                                nread++, inr--, inp++;
+                        continue;
+                }
+                if (c != '%')
+                        goto literal;
+                width = 0;
+                flags = 0;
+                /*
+                 * switch on the format.  continue if done;
+                 * break once format type is derived.
+                 */
+again:          c = *fmt++;
+                switch (c) {
+                case '%':
+literal:
+                        if (inr <= 0)
+                                goto input_failure;
+                        if (*inp != c)
+                                goto match_failure;
+                        inr--, inp++;
+                        nread++;
+                        continue;
+
+                case '*':
+                        flags |= SUPPRESS;
+                        goto again;
+                case 'l':
+                        if (flags & LONG){
+                                flags &= ~LONG;
+                                flags |= QUAD;
+                        } else {
+                                flags |= LONG;
+                        }
+                        goto again;
+                case 'q':
+                        flags |= QUAD;
+                        goto again;
+                case 'h':
+                        if (flags & SHORT){
+                                flags &= ~SHORT;
+                                flags |= SHORTSHORT;
+                        } else {
+                                flags |= SHORT;
+                        }
+                        goto again;
+
+                case '0': case '1': case '2': case '3': case '4':
+                case '5': case '6': case '7': case '8': case '9':
+                        width = width * 10 + c - '0';
+                        goto again;
+
+                /*
+                 * Conversions.
+                 *
+                 */
+                case 'd':
+                        c = CT_INT;
+                        ccfn = (ccfntype)strtoq;
+                        base = 10;
+                        break;
+
+                case 'i':
+                        c = CT_INT;
+                        ccfn = (ccfntype)strtoq;
                         base = 0;
-               case 'd':
-                       is_sign = 1;
-               case 'u':
-                       break;
-               case '%':
-                       /* looking for '%' in str */
-                       if (*str++ != '%') 
-                               return num;
-                       continue;
-               default:
-                       /* invalid format; stop here */
-                       return num;
-               }
-
-               /* have some sort of integer conversion.
-                * first, skip white space in buffer.
-                */
-               while (isspace(*str))
-                       str++;
-
-               digit = *str;
-               if (is_sign && digit == '-')
-                       digit = *(str + 1);
-
-               if (!digit
-                    || (base == 16 && !isxdigit(digit))
-                    || (base == 10 && !isdigit(digit))
-                    || (base == 8 && (!isdigit(digit) || digit > '7'))
-                    || (base == 0 && !isdigit(digit)))
-                               break;
-
-               switch(qualifier) {
-               case 'H':       /* that's 'hh' in format */
-                       if (is_sign) {
-                               signed char *s = (signed char *) 
va_arg(args,signed char *);
-                               *s = (signed char) 
simple_strtol(str,&next,base);
-                       } else {
-                               unsigned char *s = (unsigned char *) 
va_arg(args, unsigned char *);
-                               *s = (unsigned char) simple_strtoul(str, &next, 
base);
-                       }
-                       break;
-               case 'h':
-                       if (is_sign) {
-                               short *s = (short *) va_arg(args,short *);
-                               *s = (short) simple_strtol(str,&next,base);
-                       } else {
-                               unsigned short *s = (unsigned short *) 
va_arg(args, unsigned short *);
-                               *s = (unsigned short) simple_strtoul(str, 
&next, base);
-                       }
-                       break;
-               case 'l':
-                       if (is_sign) {
-                               long *l = (long *) va_arg(args,long *);
-                               *l = simple_strtol(str,&next,base);
-                       } else {
-                               unsigned long *l = (unsigned long*) 
va_arg(args,unsigned long*);
-                               *l = simple_strtoul(str,&next,base);
-                       }
-                       break;
-               case 'L':
-                       if (is_sign) {
-                               long long *l = (long long*) va_arg(args,long 
long *);
-                               *l = simple_strtoll(str,&next,base);
-                       } else {
-                               unsigned long long *l = (unsigned long long*) 
va_arg(args,unsigned long long*);
-                               *l = simple_strtoull(str,&next,base);
-                       }
-                       break;
-               case 'Z':
-               case 'z':
-               {
-                       size_t *s = (size_t*) va_arg(args,size_t*);
-                       *s = (size_t) simple_strtoul(str,&next,base);
-               }
-               break;
-               default:
-                       if (is_sign) {
-                               int *i = (int *) va_arg(args, int*);
-                               *i = (int) simple_strtol(str,&next,base);
-                       } else {
-                               unsigned int *i = (unsigned int*) va_arg(args, 
unsigned int*);
-                               *i = (unsigned int) 
simple_strtoul(str,&next,base);
-                       }
-                       break;
-               }
-               num++;
-
-               if (!next)
-                       break;
-               str = next;
-       }
-       return num;
+                        break;
+
+                case 'o':
+                        c = CT_INT;
+                        ccfn = strtouq;
+                        base = 8;
+                        break;
+
+                case 'u':
+                        c = CT_INT;
+                        ccfn = strtouq;
+                        base = 10;
+                        break;
+
+                case 'x':
+                        flags |= PFXOK; /* enable 0x prefixing */
+                        c = CT_INT;
+                        ccfn = strtouq;
+                        base = 16;
+                        break;
+
+                case 's':
+                        c = CT_STRING;
+                        break;
+
+                case '[':
+                        fmt = __sccl(ccltab, fmt);
+                        flags |= NOSKIP;
+                        c = CT_CCL;
+                        break;
+
+                case 'c':
+                        flags |= NOSKIP;
+                        c = CT_CHAR;
+                        break;
+
+                case 'p':       /* pointer format is like hex */
+                        flags |= POINTER | PFXOK;
+                        c = CT_INT;
+                        ccfn = strtouq;
+                        base = 16;
+                        break;
+
+                case 'n':
+                        nconversions++;
+                        if (flags & SUPPRESS)   /* ??? */
+                                continue;
+                        if (flags & SHORTSHORT)
+                                *va_arg(ap, char *) = nread;
+                        else if (flags & SHORT)
+                                *va_arg(ap, short *) = nread;
+                        else if (flags & LONG)
+                                *va_arg(ap, long *) = nread;
+                        else if (flags & QUAD)
+                                *va_arg(ap, int64_t *) = nread;
+                        else
+                                *va_arg(ap, int *) = nread;
+                        continue;
+                }
+
+                /*
+                 * We have a conversion that requires input.
+                 */
+                if (inr <= 0)
+                        goto input_failure;
+
+                /*
+                 * Consume leading white space, except for formats
+                 * that suppress this.
+                 */
+                if ((flags & NOSKIP) == 0) {
+                        while (isspace(*inp)) {
+                                nread++;
+                                if (--inr > 0)
+                                        inp++;
+                                else
+                                        goto input_failure;
+                        }
+                        /*
+                         * Note that there is at least one character in
+                         * the buffer, so conversions that do not set NOSKIP
+                         * can no longer result in an input failure.
+                         */
+                }
+
+                /*
+                 * Do the conversion.
+                 */
+                switch (c) {
+
+                case CT_CHAR:
+                        /* scan arbitrary characters (sets NOSKIP) */
+                        if (width == 0)
+                                width = 1;
+                        if (flags & SUPPRESS) {
+                                size_t sum = 0;
+                                for (;;) {
+                                        if ((n = inr) < width) {
+                                                sum += n;
+                                                width -= n;
+                                                inp += n;
+                                                if (sum == 0)
+                                                        goto input_failure;
+                                                break;
+                                        } else {
+                                                sum += width;
+                                                inr -= width;
+                                                inp += width;
+                                                break;
+                                        }
+                                }
+                                nread += sum;
+                        } else {
+                                memcpy(va_arg(ap, char *), inp, width);
+                                inr -= width;
+                                inp += width;
+                                nread += width;
+                                nassigned++;
+                        }
+                        nconversions++;
+                        break;
+
+                case CT_CCL:
+                        /* scan a (nonempty) character class (sets NOSKIP) */
+                        if (width == 0)
+                                width = (size_t)~0;     /* `infinity' */
+                        /* take only those things in the class */
+                        if (flags & SUPPRESS) {
+                                n = 0;
+                                while (ccltab[(unsigned char)*inp]) {
+                                        n++, inr--, inp++;
+                                        if (--width == 0)
+                                                break;
+                                        if (inr <= 0) {
+                                                if (n == 0)
+                                                        goto input_failure;
+                                                break;
+                                        }
+                                }
+                                if (n == 0)
+                                        goto match_failure;
+                        } else {
+                                p0 = p = va_arg(ap, char *);
+                                while (ccltab[(unsigned char)*inp]) {
+                                        inr--;
+                                        *p++ = *inp++;
+                                        if (--width == 0)
+                                                break;
+                                        if (inr <= 0) {
+                                                if (p == p0)
+                                                        goto input_failure;
+                                                break;
+                                        }
+                                }
+                                n = p - p0;
+                                if (n == 0)
+                                        goto match_failure;
+                                *p = 0;
+                                nassigned++;
+                        }
+                        nread += n;
+                        nconversions++;
+                        break;
+
+                case CT_STRING:
+                        /* like CCL, but zero-length string OK, & no NOSKIP */
+                        if (width == 0)
+                                width = (size_t)~0;
+                        if (flags & SUPPRESS) {
+                                n = 0;
+                                while (!isspace(*inp)) {
+                                        n++, inr--, inp++;
+                                        if (--width == 0)
+                                                break;
+                                        if (inr <= 0)
+                                                break;
+                                }
+                                nread += n;
+                        } else {
+                                p0 = p = va_arg(ap, char *);
+                                while (!isspace(*inp)) {
+                                        inr--;
+                                        *p++ = *inp++;
+                                        if (--width == 0)
+                                                break;
+                                        if (inr <= 0)
+                                                break;
+                                }
+                                *p = 0;
+                                nread += p - p0;
+                                nassigned++;
+                        }
+                        nconversions++;
+                        continue;
+
+                case CT_INT:
+                        /* scan an integer as if by strtoq/strtouq */
+#ifdef hardway
+                        if (width == 0 || width > sizeof(buf) - 1)
+                                width = sizeof(buf) - 1;
+#else
+                        /* size_t is unsigned, hence this optimisation */
+                        if (--width > sizeof(buf) - 2)
+                                width = sizeof(buf) - 2;
+                        width++;
+#endif
+                        flags |= SIGNOK | NDIGITS | NZDIGITS;
+                        for (p = buf; width; width--) {
+                                c = *inp;
+                                /*
+                                 * Switch on the character; `goto ok'
+                                 * if we accept it as a part of number.
+                                 */
+                                switch (c) {
+
+                                /*
+                                 * The digit 0 is always legal, but is
+                                 * special.  For %i conversions, if no
+                                 * digits (zero or nonzero) have been
+                                 * scanned (only signs), we will have
+                                 * base==0.  In that case, we should set
+                                 * it to 8 and enable 0x prefixing.
+                                 * Also, if we have not scanned zero digits
+                                 * before this, do not turn off prefixing
+                                 * (someone else will turn it off if we
+                                 * have scanned any nonzero digits).
+                                 */
+                                case '0':
+                                        if (base == 0) {
+                                                base = 8;
+                                                flags |= PFXOK;
+                                        }
+                                        if (flags & NZDIGITS)
+                                            flags &= 
~(SIGNOK|NZDIGITS|NDIGITS);
+                                        else
+                                            flags &= ~(SIGNOK|PFXOK|NDIGITS);
+                                        goto ok;
+
+                                /* 1 through 7 always legal */
+                                case '1': case '2': case '3':
+                                case '4': case '5': case '6': case '7':
+                                        base = basefix[base];
+                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
+                                        goto ok;
+
+                                /* digits 8 and 9 ok iff decimal or hex */
+                                case '8': case '9':
+                                        base = basefix[base];
+                                        if (base <= 8)
+                                                break;  /* not legal here */
+                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
+                                        goto ok;
+
+                                /* letters ok iff hex */
+                                case 'A': case 'B': case 'C':
+                                case 'D': case 'E': case 'F':
+                                case 'a': case 'b': case 'c':
+                                case 'd': case 'e': case 'f':
+                                        /* no need to fix base here */
+                                        if (base <= 10)
+                                                break;  /* not legal here */
+                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
+                                        goto ok;
+
+                                /* sign ok only as first character */
+                                case '+': case '-':
+                                        if (flags & SIGNOK) {
+                                                flags &= ~SIGNOK;
+                                                goto ok;
+                                        }
+                                        break;
+
+                                /* x ok iff flag still set & 2nd char */
+                                case 'x': case 'X':
+                                        if (flags & PFXOK && p == buf + 1) {
+                                                base = 16;      /* if %i */
+                                                flags &= ~PFXOK;
+                                                goto ok;
+                                        }
+                                        break;
+                                }
+
+                                /*
+                                 * If we got here, c is not a legal character
+                                 * for a number.  Stop accumulating digits.
+                                 */
+                                break;
+                ok:
+                                /*
+                                 * c is legal: store it and look at the next.
+                                 */
+                                *p++ = c;
+                                if (--inr > 0)
+                                        inp++;
+                                else 
+                                        break;          /* end of input */
+                        }
+                        /*
+                         * If we had only a sign, it is no good; push
+                         * back the sign.  If the number ends in `x',
+                         * it was [sign] '' 'x', so push back the x
+                         * and treat it as [sign] ''.
+                         */
+                        if (flags & NDIGITS) {
+                                if (p > buf) {
+                                        inp--;
+                                        inr++;
+                                }
+                                goto match_failure;
+                        }
+                        c = ((u_char *)p)[-1];
+                        if (c == 'x' || c == 'X') {
+                                --p;
+                                inp--;
+                                inr++;
+                        }
+                        if ((flags & SUPPRESS) == 0) {
+                                uint64_t res;
+
+                                *p = 0;
+                                res = (*ccfn)(buf, (char **)NULL, base);
+                                if (flags & POINTER)
+                                        *va_arg(ap, void **) =
+                                                (void *)(uintptr_t)res;
+                                else if (flags & SHORTSHORT)
+                                        *va_arg(ap, char *) = res;
+                                else if (flags & SHORT)
+                                        *va_arg(ap, short *) = res;
+                                else if (flags & LONG)
+                                        *va_arg(ap, long *) = res;
+                                else if (flags & QUAD)
+                                        *va_arg(ap, int64_t *) = res;
+                                else
+                                        *va_arg(ap, int *) = res;
+                                nassigned++;
+                        }
+                        nread += p - buf;
+                        nconversions++;
+                        break;
+
+                }
+        }
+input_failure:
+        return (nconversions != 0 ? nassigned : -1);
+match_failure:
+        return (nassigned);
 }
 
 /**
diff --git a/tpmback.c b/tpmback.c
index 00b66e8..22adbd3 100644
--- a/tpmback.c
+++ b/tpmback.c
@@ -52,10 +52,6 @@
 #include <mini-os/wait.h>
 
 
-#ifndef HAVE_LIBC
-#define strtoul simple_strtoul
-#endif
-
 //#define TPMBACK_PRINT_DEBUG
 #ifdef TPMBACK_PRINT_DEBUG
 #define TPMBACK_DEBUG(fmt,...) printk("Tpmback:Debug("__FILE__":%d) " fmt, 
__LINE__, ##__VA_ARGS__)
--
generated by git-patchbot for /home/xen/git/mini-os.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.