* [PATCH v2] mini-os: replace lib/printf.c with a version not under GPL
@ 2016-07-04 9:16 Juergen Gross
2016-07-12 8:48 ` Samuel Thibault
0 siblings, 1 reply; 4+ messages in thread
From: Juergen Gross @ 2016-07-04 9:16 UTC (permalink / raw)
To: minios-devel, xen-devel; +Cc: Juergen Gross, samuel.thibault, andrew.cooper3
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@suse.com>
---
V2: remove include/lib-gpl.h as requested by Samuel Thibault
---
blkfront.c | 4 -
include/lib-gpl.h | 59 --
include/lib.h | 27 +-
lib/printf.c | 1744 +++++++++++++++++++++++++++++++++--------------------
tpmback.c | 4 -
5 files changed, 1119 insertions(+), 719 deletions(-)
delete mode 100644 include/lib-gpl.h
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@dcs.gla.ac.uk)
- * 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..e48ab61 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@dcs.gla.ac.uk)
- * Changes: Grzegorz Milos (gm281@cam.ac.uk)
+ * Author: Juergen Gross <jgross@suse.com>
*
- * 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@datastacks.com>
- * - changed to provide snprintf and vsnprintf functions
- * So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
- * - 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
+#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
+/* 64 bits + 0-Byte at end */
+#define MAXNBUF 65
+
+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.
*/
-unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+static char *
+ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
{
- 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;
-}
-
-/**
- * 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
- */
-long simple_strtol(const char *cp,char **endp,unsigned int base)
-{
- 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)
-{
- if(*cp=='-')
- return -simple_strtoull(cp+1,endp,base);
- return simple_strtoull(cp,endp,base);
-}
-
-static int skip_atoi(const char **s)
-{
- int i=0;
-
- while (isdigit(**s))
- i = i*10 + *((*s)++) - '0';
- return i;
-}
-
-#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)
+int64_t
+strtoq(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;
-
- 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;
+ const char *s;
+ uint64_t acc;
+ unsigned char c;
+ uint64_t qbase, cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * 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 (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;
+
+ /*
+ * 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;
+ }
}
- }
- 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 = neg ? LLONG_MIN : LLONG_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.
+/*
+ * Convert a string to an unsigned quad integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
*/
-int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+uint64_t
+strtouq(const char *nptr, char **endptr, int base)
{
- 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;
- }
-
- /* 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;
- }
-
- /* 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;
- }
- }
-
- /* 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;
+ const char *s = nptr;
+ uint64_t acc;
+ unsigned char c;
+ uint64_t qbase, cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * 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++;
}
-
- /* 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 ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
}
- if (*fmt == 'q') {
- qualifier = 'L';
- ++fmt;
+ 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;
+ }
}
+ if (any < 0) {
+ acc = ULLONG_MAX;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = __DECONST(char *, any ? s - 1 : nptr);
+ return (acc);
+}
- /* default base */
- base = 10;
-
- switch (*fmt) {
- case 'c':
- if (!(flags & LEFT)) {
- while (--field_width > 0) {
- if (str <= end)
- *str = ' ';
- ++str;
+/*
+ * Scaled down version of printf(3).
+ */
+int
+vsnprintf(char *str, size_t size, char const *fmt, va_list ap)
+{
+#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;
+
+ num = 0;
+
+ if (fmt == NULL)
+ fmt = "(fmt null)\n";
+
+ for (;;) {
+ padc = ' ';
+ width = 0;
+ while ((ch = (u_char)*fmt++) != '%' || stop) {
+ if (ch == '\0') {
+ if (size >= 1)
+ *str++ = '\0';
+ return (retval);
+ }
+ PCHAR(ch);
}
- }
- 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;
+ 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;
+
+ width -= n;
+
+ 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++;
+
+ 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;
+ 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 */
- 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;
- }
+ /* `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 };
- /* anything that is not a conversion must match exactly */
- if (*fmt != '%' && *fmt) {
- if (*fmt++ != *str++)
- break;
- continue;
- }
+ inr = strlen(inp);
- 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;
- }
+ 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;
- /* get field width */
- field_width = -1;
- if (isdigit(*fmt))
- field_width = skip_atoi(&fmt);
+ 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;
- /* 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;
+ 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;
- if (!*fmt || !*str)
- break;
+ /*
+ * Conversions.
+ *
+ */
+ case 'd':
+ c = CT_INT;
+ ccfn = (ccfntype)strtoq;
+ base = 10;
+ 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':
+ 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__)
--
2.6.6
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2] mini-os: replace lib/printf.c with a version not under GPL
2016-07-04 9:16 [PATCH v2] mini-os: replace lib/printf.c with a version not under GPL Juergen Gross
@ 2016-07-12 8:48 ` Samuel Thibault
2016-07-12 9:19 ` [Minios-devel] " Wei Liu
0 siblings, 1 reply; 4+ messages in thread
From: Samuel Thibault @ 2016-07-12 8:48 UTC (permalink / raw)
To: Juergen Gross, wei.liu2; +Cc: minios-devel, xen-devel, andrew.cooper3
Juergen Gross, on Mon 04 Jul 2016 11:16:59 +0200, wrote:
> 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@suse.com>
Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
> V2: remove include/lib-gpl.h as requested by Samuel Thibault
> ---
> blkfront.c | 4 -
> include/lib-gpl.h | 59 --
> include/lib.h | 27 +-
> lib/printf.c | 1744 +++++++++++++++++++++++++++++++++--------------------
> tpmback.c | 4 -
> 5 files changed, 1119 insertions(+), 719 deletions(-)
> delete mode 100644 include/lib-gpl.h
>
> 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@dcs.gla.ac.uk)
> - * 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..e48ab61 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@dcs.gla.ac.uk)
> - * Changes: Grzegorz Milos (gm281@cam.ac.uk)
> + * Author: Juergen Gross <jgross@suse.com>
> *
> - * 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@datastacks.com>
> - * - changed to provide snprintf and vsnprintf functions
> - * So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
> - * - 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
> +#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
> +/* 64 bits + 0-Byte at end */
> +#define MAXNBUF 65
> +
> +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.
> */
> -unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
> +static char *
> +ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
> {
> - 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;
> -}
> -
> -/**
> - * 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
> - */
> -long simple_strtol(const char *cp,char **endp,unsigned int base)
> -{
> - 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)
> -{
> - if(*cp=='-')
> - return -simple_strtoull(cp+1,endp,base);
> - return simple_strtoull(cp,endp,base);
> -}
> -
> -static int skip_atoi(const char **s)
> -{
> - int i=0;
> -
> - while (isdigit(**s))
> - i = i*10 + *((*s)++) - '0';
> - return i;
> -}
> -
> -#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)
> +int64_t
> +strtoq(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;
> -
> - 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;
> + const char *s;
> + uint64_t acc;
> + unsigned char c;
> + uint64_t qbase, cutoff;
> + int neg, any, cutlim;
> +
> + /*
> + * 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 (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;
> +
> + /*
> + * 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;
> + }
> }
> - }
> - 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 = neg ? LLONG_MIN : LLONG_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.
> +/*
> + * Convert a string to an unsigned quad integer.
> + *
> + * Ignores `locale' stuff. Assumes that the upper and lower case
> + * alphabets and digits are each contiguous.
> */
> -int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
> +uint64_t
> +strtouq(const char *nptr, char **endptr, int base)
> {
> - 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;
> - }
> -
> - /* 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;
> - }
> -
> - /* 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;
> - }
> - }
> -
> - /* 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;
> + const char *s = nptr;
> + uint64_t acc;
> + unsigned char c;
> + uint64_t qbase, cutoff;
> + int neg, any, cutlim;
> +
> + /*
> + * 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++;
> }
> -
> - /* 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 ((base == 0 || base == 16) &&
> + c == '0' && (*s == 'x' || *s == 'X')) {
> + c = s[1];
> + s += 2;
> + base = 16;
> }
> - if (*fmt == 'q') {
> - qualifier = 'L';
> - ++fmt;
> + 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;
> + }
> }
> + if (any < 0) {
> + acc = ULLONG_MAX;
> + } else if (neg)
> + acc = -acc;
> + if (endptr != 0)
> + *endptr = __DECONST(char *, any ? s - 1 : nptr);
> + return (acc);
> +}
>
> - /* default base */
> - base = 10;
> -
> - switch (*fmt) {
> - case 'c':
> - if (!(flags & LEFT)) {
> - while (--field_width > 0) {
> - if (str <= end)
> - *str = ' ';
> - ++str;
> +/*
> + * Scaled down version of printf(3).
> + */
> +int
> +vsnprintf(char *str, size_t size, char const *fmt, va_list ap)
> +{
> +#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;
> +
> + num = 0;
> +
> + if (fmt == NULL)
> + fmt = "(fmt null)\n";
> +
> + for (;;) {
> + padc = ' ';
> + width = 0;
> + while ((ch = (u_char)*fmt++) != '%' || stop) {
> + if (ch == '\0') {
> + if (size >= 1)
> + *str++ = '\0';
> + return (retval);
> + }
> + PCHAR(ch);
> }
> - }
> - 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;
> + 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;
> +
> + width -= n;
> +
> + 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++;
> +
> + 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;
> + 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 */
>
> - 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;
> - }
> + /* `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 };
>
> - /* anything that is not a conversion must match exactly */
> - if (*fmt != '%' && *fmt) {
> - if (*fmt++ != *str++)
> - break;
> - continue;
> - }
> + inr = strlen(inp);
>
> - 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;
> - }
> + 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;
>
> - /* get field width */
> - field_width = -1;
> - if (isdigit(*fmt))
> - field_width = skip_atoi(&fmt);
> + 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;
>
> - /* 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;
> + 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;
>
> - if (!*fmt || !*str)
> - break;
> + /*
> + * Conversions.
> + *
> + */
> + case 'd':
> + c = CT_INT;
> + ccfn = (ccfntype)strtoq;
> + base = 10;
> + 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':
> + 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__)
> --
> 2.6.6
>
--
Samuel
As usual, this being a 1.3.x release, I haven't even compiled this
kernel yet. So if it works, you should be doubly impressed.
(Linus Torvalds, announcing kernel 1.3.3 on the linux-kernel mailing list.)
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Minios-devel] [PATCH v2] mini-os: replace lib/printf.c with a version not under GPL
2016-07-12 8:48 ` Samuel Thibault
@ 2016-07-12 9:19 ` Wei Liu
2016-07-12 9:44 ` Wei Liu
0 siblings, 1 reply; 4+ messages in thread
From: Wei Liu @ 2016-07-12 9:19 UTC (permalink / raw)
To: Samuel Thibault, Juergen Gross, wei.liu2, minios-devel,
xen-devel, andrew.cooper3
On Tue, Jul 12, 2016 at 10:48:50AM +0200, Samuel Thibault wrote:
> Juergen Gross, on Mon 04 Jul 2016 11:16:59 +0200, wrote:
> > 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@suse.com>
>
> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Queued.
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Minios-devel] [PATCH v2] mini-os: replace lib/printf.c with a version not under GPL
2016-07-12 9:19 ` [Minios-devel] " Wei Liu
@ 2016-07-12 9:44 ` Wei Liu
0 siblings, 0 replies; 4+ messages in thread
From: Wei Liu @ 2016-07-12 9:44 UTC (permalink / raw)
To: Samuel Thibault, Juergen Gross, wei.liu2, minios-devel,
xen-devel, andrew.cooper3
On Tue, Jul 12, 2016 at 10:19:41AM +0100, Wei Liu wrote:
> On Tue, Jul 12, 2016 at 10:48:50AM +0200, Samuel Thibault wrote:
> > Juergen Gross, on Mon 04 Jul 2016 11:16:59 +0200, wrote:
> > > Instead of a Linux kernel based implementation use one from freeBSD.
Roger has asked me on IRC to s/freeBSD/FreeBSD/. I will do that when I
push this patch.
Wei.
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2016-07-12 9:44 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-04 9:16 [PATCH v2] mini-os: replace lib/printf.c with a version not under GPL Juergen Gross
2016-07-12 8:48 ` Samuel Thibault
2016-07-12 9:19 ` [Minios-devel] " Wei Liu
2016-07-12 9:44 ` Wei Liu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).