From: Samuel Thibault <samuel.thibault@ens-lyon.org>
To: Juergen Gross <jgross@suse.com>, wei.liu2@citrix.com
Cc: minios-devel@lists.xenproject.org,
xen-devel@lists.xenproject.org, andrew.cooper3@citrix.com
Subject: Re: [PATCH v2] mini-os: replace lib/printf.c with a version not under GPL
Date: Tue, 12 Jul 2016 10:48:50 +0200 [thread overview]
Message-ID: <20160712084850.GF3654@var.bordeaux.inria.fr> (raw)
In-Reply-To: <1467623819-31378-1-git-send-email-jgross@suse.com>
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
next prev parent reply other threads:[~2016-07-12 8:48 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
2016-07-12 9:19 ` [Minios-devel] " Wei Liu
2016-07-12 9:44 ` Wei Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160712084850.GF3654@var.bordeaux.inria.fr \
--to=samuel.thibault@ens-lyon.org \
--cc=andrew.cooper3@citrix.com \
--cc=jgross@suse.com \
--cc=minios-devel@lists.xenproject.org \
--cc=wei.liu2@citrix.com \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).