📄 scanf.c
字号:
/* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Clayton Collie <clcollie@mindspring.com> | +----------------------------------------------------------------------+*//* $Id: scanf.c,v 1.16.4.9.2.3 2007/01/01 09:46:48 sebastian Exp $ *//* scanf.c -- This file contains the base code which implements sscanf and by extension fscanf. Original code is from TCL8.3.0 and bears the following copyright This software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., Scriptics Corporation, and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. */ #include <stdio.h>#include <limits.h>#include <ctype.h>#include "php.h"#include "php_variables.h"#ifdef HAVE_LOCALE_H#include <locale.h> #endif#include "zend_execute.h"#include "zend_operators.h"#include "zend_strtod.h"#include "php_globals.h"#include "basic_functions.h"#include "scanf.h"/* * Flag values used internally by [f|s]canf. */#define SCAN_NOSKIP 0x1 /* Don't skip blanks. */#define SCAN_SUPPRESS 0x2 /* Suppress assignment. */#define SCAN_UNSIGNED 0x4 /* Read an unsigned value. */#define SCAN_WIDTH 0x8 /* A width value was supplied. */#define SCAN_SIGNOK 0x10 /* A +/- character is allowed. */#define SCAN_NODIGITS 0x20 /* No digits have been scanned. */#define SCAN_NOZERO 0x40 /* No zero digits have been scanned. */#define SCAN_XOK 0x80 /* An 'x' is allowed. */#define SCAN_PTOK 0x100 /* Decimal point is allowed. */#define SCAN_EXPOK 0x200 /* An exponent is allowed. */#define UCHAR(x) (zend_uchar)(x)/* * The following structure contains the information associated with * a character set. */typedef struct CharSet { int exclude; /* 1 if this is an exclusion set. */ int nchars; char *chars; int nranges; struct Range { char start; char end; } *ranges;} CharSet;/* * Declarations for functions used only in this file. */static char *BuildCharSet(CharSet *cset, char *format);static int CharInSet(CharSet *cset, int ch);static void ReleaseCharSet(CharSet *cset);static inline void scan_set_error_return(int numVars, pval **return_value);/* {{{ BuildCharSet *---------------------------------------------------------------------- * * BuildCharSet -- * * This function examines a character set format specification * and builds a CharSet containing the individual characters and * character ranges specified. * * Results: * Returns the next format position. * * Side effects: * Initializes the charset. * *---------------------------------------------------------------------- */static char * BuildCharSet(CharSet *cset, char *format){ char *ch, start; int nranges; char *end; memset(cset, 0, sizeof(CharSet)); ch = format; if (*ch == '^') { cset->exclude = 1; ch = ++format; } end = format + 1; /* verify this - cc */ /* * Find the close bracket so we can overallocate the set. */ if (*ch == ']') { ch = end++; } nranges = 0; while (*ch != ']') { if (*ch == '-') { nranges++; } ch = end++; } cset->chars = (char *) safe_emalloc(sizeof(char), (end - format - 1), 0); if (nranges > 0) { cset->ranges = (struct Range *) safe_emalloc(sizeof(struct Range), nranges, 0); } else { cset->ranges = NULL; } /* * Now build the character set. */ cset->nchars = cset->nranges = 0; ch = format++; start = *ch; if (*ch == ']' || *ch == '-') { cset->chars[cset->nchars++] = *ch; ch = format++; } while (*ch != ']') { if (*format == '-') { /* * This may be the first character of a range, so don't add * it yet. */ start = *ch; } else if (*ch == '-') { /* * Check to see if this is the last character in the set, in which * case it is not a range and we should add the previous character * as well as the dash. */ if (*format == ']') { cset->chars[cset->nchars++] = start; cset->chars[cset->nchars++] = *ch; } else { ch = format++; /* * Check to see if the range is in reverse order. */ if (start < *ch) { cset->ranges[cset->nranges].start = start; cset->ranges[cset->nranges].end = *ch; } else { cset->ranges[cset->nranges].start = *ch; cset->ranges[cset->nranges].end = start; } cset->nranges++; } } else { cset->chars[cset->nchars++] = *ch; } ch = format++; } return format;}/* }}} *//* {{{ CharInSet *---------------------------------------------------------------------- * * CharInSet -- * * Check to see if a character matches the given set. * * Results: * Returns non-zero if the character matches the given set. * * Side effects: * None. * *---------------------------------------------------------------------- */static int CharInSet(CharSet *cset, int c){ char ch = (char) c; int i, match = 0; for (i = 0; i < cset->nchars; i++) { if (cset->chars[i] == ch) { match = 1; break; } } if (!match) { for (i = 0; i < cset->nranges; i++) { if ((cset->ranges[i].start <= ch) && (ch <= cset->ranges[i].end)) { match = 1; break; } } } return (cset->exclude ? !match : match); }/* }}} *//* {{{ ReleaseCharSet *---------------------------------------------------------------------- * * ReleaseCharSet -- * * Free the storage associated with a character set. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */static void ReleaseCharSet(CharSet *cset){ efree((char *)cset->chars); if (cset->ranges) { efree((char *)cset->ranges); }}/* }}} *//* {{{ ValidateFormat *---------------------------------------------------------------------- * * ValidateFormat -- * * Parse the format string and verify that it is properly formed * and that there are exactly enough variables on the command line. * * Results: * FAILURE or SUCCESS. * * Side effects: * May set php_error based on abnormal conditions. * * Parameters : * format The format string. * numVars The number of variables passed to the scan command. * totalSubs The number of variables that will be required. * *----------------------------------------------------------------------*/PHPAPI int ValidateFormat(char *format, int numVars, int *totalSubs){#define STATIC_LIST_SIZE 16 int gotXpg, gotSequential, value, i, flags; char *end, *ch = NULL; int staticAssign[STATIC_LIST_SIZE]; int *nassign = staticAssign; int objIndex, xpgSize, nspace = STATIC_LIST_SIZE; TSRMLS_FETCH(); /* * Initialize an array that records the number of times a variable * is assigned to by the format string. We use this to detect if * a variable is multiply assigned or left unassigned. */ if (numVars > nspace) { nassign = (int*)safe_emalloc(sizeof(int), numVars, 0); nspace = numVars; } for (i = 0; i < nspace; i++) { nassign[i] = 0; } xpgSize = objIndex = gotXpg = gotSequential = 0; while (*format != '\0') { ch = format++; flags = 0; if (*ch != '%') { continue; } ch = format++; if (*ch == '%') { continue; } if (*ch == '*') { flags |= SCAN_SUPPRESS; ch = format++; goto xpgCheckDone; } if ( isdigit( (int)*ch ) ) { /* * Check for an XPG3-style %n$ specification. Note: there * must not be a mixture of XPG3 specs and non-XPG3 specs * in the same format string. */ value = strtoul(format-1, &end, 10); if (*end != '$') { goto notXpg; } format = end+1; ch = format++; gotXpg = 1; if (gotSequential) { goto mixedXPG; } objIndex = value - 1; if ((objIndex < 0) || (numVars && (objIndex >= numVars))) { goto badIndex; } else if (numVars == 0) { /* * In the case where no vars are specified, the user can * specify %9999$ legally, so we have to consider special * rules for growing the assign array. 'value' is * guaranteed to be > 0. */ /* set a lower artificial limit on this * in the interest of security and resource friendliness * 255 arguments should be more than enough. - cc */ if (value > SCAN_MAX_ARGS) { goto badIndex; } xpgSize = (xpgSize > value) ? xpgSize : value; } goto xpgCheckDone; } notXpg: gotSequential = 1; if (gotXpg) { mixedXPG: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", "cannot mix \"%\" and \"%n$\" conversion specifiers"); goto error; } xpgCheckDone: /* * Parse any width specifier. */ if (isdigit(UCHAR(*ch))) { value = strtoul(format-1, &format, 10);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -