| Index: nspr/pr/src/io/prscanf.c
|
| diff --git a/nspr/pr/src/io/prscanf.c b/nspr/pr/src/io/prscanf.c
|
| deleted file mode 100644
|
| index 9d75d824e8e91365655793216c1e2fe27345ab7a..0000000000000000000000000000000000000000
|
| --- a/nspr/pr/src/io/prscanf.c
|
| +++ /dev/null
|
| @@ -1,634 +0,0 @@
|
| -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
| -/* This Source Code Form is subject to the terms of the Mozilla Public
|
| - * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| -
|
| -/*
|
| - * Scan functions for NSPR types
|
| - *
|
| - * Author: Wan-Teh Chang
|
| - *
|
| - * Acknowledgment: The implementation is inspired by the source code
|
| - * in P.J. Plauger's "The Standard C Library," Prentice-Hall, 1992.
|
| - */
|
| -
|
| -#include <limits.h>
|
| -#include <ctype.h>
|
| -#include <string.h>
|
| -#include <stdlib.h>
|
| -#include "prprf.h"
|
| -#include "prdtoa.h"
|
| -#include "prlog.h"
|
| -#include "prerror.h"
|
| -
|
| -/*
|
| - * A function that reads a character from 'stream'.
|
| - * Returns the character read, or EOF if end of stream is reached.
|
| - */
|
| -typedef int (*_PRGetCharFN)(void *stream);
|
| -
|
| -/*
|
| - * A function that pushes the character 'ch' back to 'stream'.
|
| - */
|
| -typedef void (*_PRUngetCharFN)(void *stream, int ch);
|
| -
|
| -/*
|
| - * The size specifier for the integer and floating point number
|
| - * conversions in format control strings.
|
| - */
|
| -typedef enum {
|
| - _PR_size_none, /* No size specifier is given */
|
| - _PR_size_h, /* The 'h' specifier, suggesting "short" */
|
| - _PR_size_l, /* The 'l' specifier, suggesting "long" */
|
| - _PR_size_L, /* The 'L' specifier, meaning a 'long double' */
|
| - _PR_size_ll /* The 'll' specifier, suggesting "long long" */
|
| -} _PRSizeSpec;
|
| -
|
| -/*
|
| - * The collection of data that is passed between the scan function
|
| - * and its subordinate functions. The fields of this structure
|
| - * serve as the input or output arguments for these functions.
|
| - */
|
| -typedef struct {
|
| - _PRGetCharFN get; /* get a character from input stream */
|
| - _PRUngetCharFN unget; /* unget (push back) a character */
|
| - void *stream; /* argument for get and unget */
|
| - va_list ap; /* the variable argument list */
|
| - int nChar; /* number of characters read from 'stream' */
|
| -
|
| - PRBool assign; /* assign, or suppress assignment? */
|
| - int width; /* field width */
|
| - _PRSizeSpec sizeSpec; /* 'h', 'l', 'L', or 'll' */
|
| -
|
| - PRBool converted; /* is the value actually converted? */
|
| -} ScanfState;
|
| -
|
| -#define GET(state) ((state)->nChar++, (state)->get((state)->stream))
|
| -#define UNGET(state, ch) \
|
| - ((state)->nChar--, (state)->unget((state)->stream, ch))
|
| -
|
| -/*
|
| - * The following two macros, GET_IF_WITHIN_WIDTH and WITHIN_WIDTH,
|
| - * are always used together.
|
| - *
|
| - * GET_IF_WITHIN_WIDTH calls the GET macro and assigns its return
|
| - * value to 'ch' only if we have not exceeded the field width of
|
| - * 'state'. Therefore, after GET_IF_WITHIN_WIDTH, the value of
|
| - * 'ch' is valid only if the macro WITHIN_WIDTH evaluates to true.
|
| - */
|
| -
|
| -#define GET_IF_WITHIN_WIDTH(state, ch) \
|
| - if (--(state)->width >= 0) { \
|
| - (ch) = GET(state); \
|
| - }
|
| -#define WITHIN_WIDTH(state) ((state)->width >= 0)
|
| -
|
| -/*
|
| - * _pr_strtoull:
|
| - * Convert a string to an unsigned 64-bit integer. The string
|
| - * 'str' is assumed to be a representation of the integer in
|
| - * base 'base'.
|
| - *
|
| - * Warning:
|
| - * - Only handle base 8, 10, and 16.
|
| - * - No overflow checking.
|
| - */
|
| -
|
| -static PRUint64
|
| -_pr_strtoull(const char *str, char **endptr, int base)
|
| -{
|
| - static const int BASE_MAX = 16;
|
| - static const char digits[] = "0123456789abcdef";
|
| - char *digitPtr;
|
| - PRUint64 x; /* return value */
|
| - PRInt64 base64;
|
| - const char *cPtr;
|
| - PRBool negative;
|
| - const char *digitStart;
|
| -
|
| - PR_ASSERT(base == 0 || base == 8 || base == 10 || base == 16);
|
| - if (base < 0 || base == 1 || base > BASE_MAX) {
|
| - if (endptr) {
|
| - *endptr = (char *) str;
|
| - return LL_ZERO;
|
| - }
|
| - }
|
| -
|
| - cPtr = str;
|
| - while (isspace(*cPtr)) {
|
| - ++cPtr;
|
| - }
|
| -
|
| - negative = PR_FALSE;
|
| - if (*cPtr == '-') {
|
| - negative = PR_TRUE;
|
| - cPtr++;
|
| - } else if (*cPtr == '+') {
|
| - cPtr++;
|
| - }
|
| -
|
| - if (base == 16) {
|
| - if (*cPtr == '0' && (cPtr[1] == 'x' || cPtr[1] == 'X')) {
|
| - cPtr += 2;
|
| - }
|
| - } else if (base == 0) {
|
| - if (*cPtr != '0') {
|
| - base = 10;
|
| - } else if (cPtr[1] == 'x' || cPtr[1] == 'X') {
|
| - base = 16;
|
| - cPtr += 2;
|
| - } else {
|
| - base = 8;
|
| - }
|
| - }
|
| - PR_ASSERT(base != 0);
|
| - LL_I2L(base64, base);
|
| - digitStart = cPtr;
|
| -
|
| - /* Skip leading zeros */
|
| - while (*cPtr == '0') {
|
| - cPtr++;
|
| - }
|
| -
|
| - LL_I2L(x, 0);
|
| - while ((digitPtr = (char*)memchr(digits, tolower(*cPtr), base)) != NULL) {
|
| - PRUint64 d;
|
| -
|
| - LL_I2L(d, (digitPtr - digits));
|
| - LL_MUL(x, x, base64);
|
| - LL_ADD(x, x, d);
|
| - cPtr++;
|
| - }
|
| -
|
| - if (cPtr == digitStart) {
|
| - if (endptr) {
|
| - *endptr = (char *) str;
|
| - }
|
| - return LL_ZERO;
|
| - }
|
| -
|
| - if (negative) {
|
| -#ifdef HAVE_LONG_LONG
|
| - /* The cast to a signed type is to avoid a compiler warning */
|
| - x = -(PRInt64)x;
|
| -#else
|
| - LL_NEG(x, x);
|
| -#endif
|
| - }
|
| -
|
| - if (endptr) {
|
| - *endptr = (char *) cPtr;
|
| - }
|
| - return x;
|
| -}
|
| -
|
| -/*
|
| - * The maximum field width (in number of characters) that is enough
|
| - * (may be more than necessary) to represent a 64-bit integer or
|
| - * floating point number.
|
| - */
|
| -#define FMAX 31
|
| -#define DECIMAL_POINT '.'
|
| -
|
| -static PRStatus
|
| -GetInt(ScanfState *state, int code)
|
| -{
|
| - char buf[FMAX + 1], *p;
|
| - int ch = 0;
|
| - static const char digits[] = "0123456789abcdefABCDEF";
|
| - PRBool seenDigit = PR_FALSE;
|
| - int base;
|
| - int dlen;
|
| -
|
| - switch (code) {
|
| - case 'd': case 'u':
|
| - base = 10;
|
| - break;
|
| - case 'i':
|
| - base = 0;
|
| - break;
|
| - case 'x': case 'X': case 'p':
|
| - base = 16;
|
| - break;
|
| - case 'o':
|
| - base = 8;
|
| - break;
|
| - default:
|
| - return PR_FAILURE;
|
| - }
|
| - if (state->width == 0 || state->width > FMAX) {
|
| - state->width = FMAX;
|
| - }
|
| - p = buf;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
|
| - *p++ = ch;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - }
|
| - if (WITHIN_WIDTH(state) && ch == '0') {
|
| - seenDigit = PR_TRUE;
|
| - *p++ = ch;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - if (WITHIN_WIDTH(state)
|
| - && (ch == 'x' || ch == 'X')
|
| - && (base == 0 || base == 16)) {
|
| - base = 16;
|
| - *p++ = ch;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - } else if (base == 0) {
|
| - base = 8;
|
| - }
|
| - }
|
| - if (base == 0 || base == 10) {
|
| - dlen = 10;
|
| - } else if (base == 8) {
|
| - dlen = 8;
|
| - } else {
|
| - PR_ASSERT(base == 16);
|
| - dlen = 16 + 6; /* 16 digits, plus 6 in uppercase */
|
| - }
|
| - while (WITHIN_WIDTH(state) && memchr(digits, ch, dlen)) {
|
| - *p++ = ch;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - seenDigit = PR_TRUE;
|
| - }
|
| - if (WITHIN_WIDTH(state)) {
|
| - UNGET(state, ch);
|
| - }
|
| - if (!seenDigit) {
|
| - return PR_FAILURE;
|
| - }
|
| - *p = '\0';
|
| - if (state->assign) {
|
| - if (code == 'd' || code == 'i') {
|
| - if (state->sizeSpec == _PR_size_ll) {
|
| - PRInt64 llval = _pr_strtoull(buf, NULL, base);
|
| - *va_arg(state->ap, PRInt64 *) = llval;
|
| - } else {
|
| - long lval = strtol(buf, NULL, base);
|
| -
|
| - if (state->sizeSpec == _PR_size_none) {
|
| - *va_arg(state->ap, PRIntn *) = lval;
|
| - } else if (state->sizeSpec == _PR_size_h) {
|
| - *va_arg(state->ap, PRInt16 *) = (PRInt16)lval;
|
| - } else if (state->sizeSpec == _PR_size_l) {
|
| - *va_arg(state->ap, PRInt32 *) = lval;
|
| - } else {
|
| - return PR_FAILURE;
|
| - }
|
| - }
|
| - } else {
|
| - if (state->sizeSpec == _PR_size_ll) {
|
| - PRUint64 llval = _pr_strtoull(buf, NULL, base);
|
| - *va_arg(state->ap, PRUint64 *) = llval;
|
| - } else {
|
| - unsigned long lval = strtoul(buf, NULL, base);
|
| -
|
| - if (state->sizeSpec == _PR_size_none) {
|
| - *va_arg(state->ap, PRUintn *) = lval;
|
| - } else if (state->sizeSpec == _PR_size_h) {
|
| - *va_arg(state->ap, PRUint16 *) = (PRUint16)lval;
|
| - } else if (state->sizeSpec == _PR_size_l) {
|
| - *va_arg(state->ap, PRUint32 *) = lval;
|
| - } else {
|
| - return PR_FAILURE;
|
| - }
|
| - }
|
| - }
|
| - state->converted = PR_TRUE;
|
| - }
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -static PRStatus
|
| -GetFloat(ScanfState *state)
|
| -{
|
| - char buf[FMAX + 1], *p;
|
| - int ch = 0;
|
| - PRBool seenDigit = PR_FALSE;
|
| -
|
| - if (state->width == 0 || state->width > FMAX) {
|
| - state->width = FMAX;
|
| - }
|
| - p = buf;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
|
| - *p++ = ch;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - }
|
| - while (WITHIN_WIDTH(state) && isdigit(ch)) {
|
| - *p++ = ch;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - seenDigit = PR_TRUE;
|
| - }
|
| - if (WITHIN_WIDTH(state) && ch == DECIMAL_POINT) {
|
| - *p++ = ch;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - while (WITHIN_WIDTH(state) && isdigit(ch)) {
|
| - *p++ = ch;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - seenDigit = PR_TRUE;
|
| - }
|
| - }
|
| -
|
| - /*
|
| - * This is not robust. For example, "1.2e+" would confuse
|
| - * the code below to read 'e' and '+', only to realize that
|
| - * it should have stopped at "1.2". But we can't push back
|
| - * more than one character, so there is nothing I can do.
|
| - */
|
| -
|
| - /* Parse exponent */
|
| - if (WITHIN_WIDTH(state) && (ch == 'e' || ch == 'E') && seenDigit) {
|
| - *p++ = ch;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
|
| - *p++ = ch;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - }
|
| - while (WITHIN_WIDTH(state) && isdigit(ch)) {
|
| - *p++ = ch;
|
| - GET_IF_WITHIN_WIDTH(state, ch);
|
| - }
|
| - }
|
| - if (WITHIN_WIDTH(state)) {
|
| - UNGET(state, ch);
|
| - }
|
| - if (!seenDigit) {
|
| - return PR_FAILURE;
|
| - }
|
| - *p = '\0';
|
| - if (state->assign) {
|
| - PRFloat64 dval = PR_strtod(buf, NULL);
|
| -
|
| - state->converted = PR_TRUE;
|
| - if (state->sizeSpec == _PR_size_l) {
|
| - *va_arg(state->ap, PRFloat64 *) = dval;
|
| - } else if (state->sizeSpec == _PR_size_L) {
|
| -#if defined(OSF1) || defined(IRIX)
|
| - *va_arg(state->ap, double *) = dval;
|
| -#else
|
| - *va_arg(state->ap, long double *) = dval;
|
| -#endif
|
| - } else {
|
| - *va_arg(state->ap, float *) = (float) dval;
|
| - }
|
| - }
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -/*
|
| - * Convert, and return the end of the conversion spec.
|
| - * Return NULL on error.
|
| - */
|
| -
|
| -static const char *
|
| -Convert(ScanfState *state, const char *fmt)
|
| -{
|
| - const char *cPtr;
|
| - int ch;
|
| - char *cArg = NULL;
|
| -
|
| - state->converted = PR_FALSE;
|
| - cPtr = fmt;
|
| - if (*cPtr != 'c' && *cPtr != 'n' && *cPtr != '[') {
|
| - do {
|
| - ch = GET(state);
|
| - } while (isspace(ch));
|
| - UNGET(state, ch);
|
| - }
|
| - switch (*cPtr) {
|
| - case 'c':
|
| - if (state->assign) {
|
| - cArg = va_arg(state->ap, char *);
|
| - }
|
| - if (state->width == 0) {
|
| - state->width = 1;
|
| - }
|
| - for (; state->width > 0; state->width--) {
|
| - ch = GET(state);
|
| - if (ch == EOF) {
|
| - return NULL;
|
| - } else if (state->assign) {
|
| - *cArg++ = ch;
|
| - }
|
| - }
|
| - if (state->assign) {
|
| - state->converted = PR_TRUE;
|
| - }
|
| - break;
|
| - case 'p':
|
| - case 'd': case 'i': case 'o':
|
| - case 'u': case 'x': case 'X':
|
| - if (GetInt(state, *cPtr) == PR_FAILURE) {
|
| - return NULL;
|
| - }
|
| - break;
|
| - case 'e': case 'E': case 'f':
|
| - case 'g': case 'G':
|
| - if (GetFloat(state) == PR_FAILURE) {
|
| - return NULL;
|
| - }
|
| - break;
|
| - case 'n':
|
| - /* do not consume any input */
|
| - if (state->assign) {
|
| - switch (state->sizeSpec) {
|
| - case _PR_size_none:
|
| - *va_arg(state->ap, PRIntn *) = state->nChar;
|
| - break;
|
| - case _PR_size_h:
|
| - *va_arg(state->ap, PRInt16 *) = state->nChar;
|
| - break;
|
| - case _PR_size_l:
|
| - *va_arg(state->ap, PRInt32 *) = state->nChar;
|
| - break;
|
| - case _PR_size_ll:
|
| - LL_I2L(*va_arg(state->ap, PRInt64 *), state->nChar);
|
| - break;
|
| - default:
|
| - PR_ASSERT(0);
|
| - }
|
| - }
|
| - break;
|
| - case 's':
|
| - if (state->width == 0) {
|
| - state->width = INT_MAX;
|
| - }
|
| - if (state->assign) {
|
| - cArg = va_arg(state->ap, char *);
|
| - }
|
| - for (; state->width > 0; state->width--) {
|
| - ch = GET(state);
|
| - if ((ch == EOF) || isspace(ch)) {
|
| - UNGET(state, ch);
|
| - break;
|
| - }
|
| - if (state->assign) {
|
| - *cArg++ = ch;
|
| - }
|
| - }
|
| - if (state->assign) {
|
| - *cArg = '\0';
|
| - state->converted = PR_TRUE;
|
| - }
|
| - break;
|
| - case '%':
|
| - ch = GET(state);
|
| - if (ch != '%') {
|
| - UNGET(state, ch);
|
| - return NULL;
|
| - }
|
| - break;
|
| - case '[':
|
| - {
|
| - PRBool complement = PR_FALSE;
|
| - const char *closeBracket;
|
| - size_t n;
|
| -
|
| - if (*++cPtr == '^') {
|
| - complement = PR_TRUE;
|
| - cPtr++;
|
| - }
|
| - closeBracket = strchr(*cPtr == ']' ? cPtr + 1 : cPtr, ']');
|
| - if (closeBracket == NULL) {
|
| - return NULL;
|
| - }
|
| - n = closeBracket - cPtr;
|
| - if (state->width == 0) {
|
| - state->width = INT_MAX;
|
| - }
|
| - if (state->assign) {
|
| - cArg = va_arg(state->ap, char *);
|
| - }
|
| - for (; state->width > 0; state->width--) {
|
| - ch = GET(state);
|
| - if ((ch == EOF)
|
| - || (!complement && !memchr(cPtr, ch, n))
|
| - || (complement && memchr(cPtr, ch, n))) {
|
| - UNGET(state, ch);
|
| - break;
|
| - }
|
| - if (state->assign) {
|
| - *cArg++ = ch;
|
| - }
|
| - }
|
| - if (state->assign) {
|
| - *cArg = '\0';
|
| - state->converted = PR_TRUE;
|
| - }
|
| - cPtr = closeBracket;
|
| - }
|
| - break;
|
| - default:
|
| - return NULL;
|
| - }
|
| - return cPtr;
|
| -}
|
| -
|
| -static PRInt32
|
| -DoScanf(ScanfState *state, const char *fmt)
|
| -{
|
| - PRInt32 nConverted = 0;
|
| - const char *cPtr;
|
| - int ch;
|
| -
|
| - state->nChar = 0;
|
| - cPtr = fmt;
|
| - while (1) {
|
| - if (isspace(*cPtr)) {
|
| - /* white space: skip */
|
| - do {
|
| - cPtr++;
|
| - } while (isspace(*cPtr));
|
| - do {
|
| - ch = GET(state);
|
| - } while (isspace(ch));
|
| - UNGET(state, ch);
|
| - } else if (*cPtr == '%') {
|
| - /* format spec: convert */
|
| - cPtr++;
|
| - state->assign = PR_TRUE;
|
| - if (*cPtr == '*') {
|
| - cPtr++;
|
| - state->assign = PR_FALSE;
|
| - }
|
| - for (state->width = 0; isdigit(*cPtr); cPtr++) {
|
| - state->width = state->width * 10 + *cPtr - '0';
|
| - }
|
| - state->sizeSpec = _PR_size_none;
|
| - if (*cPtr == 'h') {
|
| - cPtr++;
|
| - state->sizeSpec = _PR_size_h;
|
| - } else if (*cPtr == 'l') {
|
| - cPtr++;
|
| - if (*cPtr == 'l') {
|
| - cPtr++;
|
| - state->sizeSpec = _PR_size_ll;
|
| - } else {
|
| - state->sizeSpec = _PR_size_l;
|
| - }
|
| - } else if (*cPtr == 'L') {
|
| - cPtr++;
|
| - state->sizeSpec = _PR_size_L;
|
| - }
|
| - cPtr = Convert(state, cPtr);
|
| - if (cPtr == NULL) {
|
| - return (nConverted > 0 ? nConverted : EOF);
|
| - }
|
| - if (state->converted) {
|
| - nConverted++;
|
| - }
|
| - cPtr++;
|
| - } else {
|
| - /* others: must match */
|
| - if (*cPtr == '\0') {
|
| - return nConverted;
|
| - }
|
| - ch = GET(state);
|
| - if (ch != *cPtr) {
|
| - UNGET(state, ch);
|
| - return nConverted;
|
| - }
|
| - cPtr++;
|
| - }
|
| - }
|
| -}
|
| -
|
| -static int
|
| -StringGetChar(void *stream)
|
| -{
|
| - char *cPtr = *((char **) stream);
|
| -
|
| - if (*cPtr == '\0') {
|
| - return EOF;
|
| - } else {
|
| - *((char **) stream) = cPtr + 1;
|
| - return (unsigned char) *cPtr;
|
| - }
|
| -}
|
| -
|
| -static void
|
| -StringUngetChar(void *stream, int ch)
|
| -{
|
| - char *cPtr = *((char **) stream);
|
| -
|
| - if (ch != EOF) {
|
| - *((char **) stream) = cPtr - 1;
|
| - }
|
| -}
|
| -
|
| -PR_IMPLEMENT(PRInt32)
|
| -PR_sscanf(const char *buf, const char *fmt, ...)
|
| -{
|
| - PRInt32 rv;
|
| - ScanfState state;
|
| -
|
| - state.get = &StringGetChar;
|
| - state.unget = &StringUngetChar;
|
| - state.stream = (void *) &buf;
|
| - va_start(state.ap, fmt);
|
| - rv = DoScanf(&state, fmt);
|
| - va_end(state.ap);
|
| - return rv;
|
| -}
|
|
|