📄 prscanf.c
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//* * 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>#ifdef SUNOS4#include "md/sunos4.h" /* for strtoul */#endif#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 PRStatusGetInt(ScanfState *state, int code){ char buf[FMAX + 1], *p; int ch; 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -