PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/standard - scanf.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 387 459 84.3 %
Date: 2014-10-30 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2014 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Author: Clayton Collie <clcollie@mindspring.com>                     |
      16             :    +----------------------------------------------------------------------+
      17             : */
      18             : 
      19             : /* $Id$ */
      20             : 
      21             : /*
      22             :         scanf.c --
      23             : 
      24             :         This file contains the base code which implements sscanf and by extension
      25             :         fscanf. Original code is from TCL8.3.0 and bears the following copyright:
      26             : 
      27             :         This software is copyrighted by the Regents of the University of
      28             :         California, Sun Microsystems, Inc., Scriptics Corporation,
      29             :         and other parties.  The following terms apply to all files associated
      30             :         with the software unless explicitly disclaimed in individual files.
      31             : 
      32             :         The authors hereby grant permission to use, copy, modify, distribute,
      33             :         and license this software and its documentation for any purpose, provided
      34             :         that existing copyright notices are retained in all copies and that this
      35             :         notice is included verbatim in any distributions. No written agreement,
      36             :         license, or royalty fee is required for any of the authorized uses.
      37             :         Modifications to this software may be copyrighted by their authors
      38             :         and need not follow the licensing terms described here, provided that
      39             :         the new terms are clearly indicated on the first page of each file where
      40             :         they apply.
      41             : 
      42             :         IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
      43             :         FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
      44             :         ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
      45             :         DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
      46             :         POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             :         THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
      49             :         INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
      50             :         FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
      51             :         IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
      52             :         NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
      53             :         MODIFICATIONS.
      54             : 
      55             :         GOVERNMENT USE: If you are acquiring this software on behalf of the
      56             :         U.S. government, the Government shall have only "Restricted Rights"
      57             :         in the software and related documentation as defined in the Federal
      58             :         Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
      59             :         are acquiring the software on behalf of the Department of Defense, the
      60             :         software shall be classified as "Commercial Computer Software" and the
      61             :         Government shall have only "Restricted Rights" as defined in Clause
      62             :         252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
      63             :         authors grant the U.S. Government and others acting in its behalf
      64             :         permission to use and distribute the software in accordance with the
      65             :         terms specified in this license.
      66             : */
      67             : 
      68             : #include <stdio.h>
      69             : #include <limits.h>
      70             : #include <ctype.h>
      71             : #include "php.h"
      72             : #include "php_variables.h"
      73             : #ifdef HAVE_LOCALE_H
      74             : #include <locale.h>
      75             : #endif
      76             : #include "zend_execute.h"
      77             : #include "zend_operators.h"
      78             : #include "zend_strtod.h"
      79             : #include "php_globals.h"
      80             : #include "basic_functions.h"
      81             : #include "scanf.h"
      82             : 
      83             : /*
      84             :  * Flag values used internally by [f|s]canf.
      85             :  */
      86             : #define SCAN_NOSKIP     0x1       /* Don't skip blanks. */
      87             : #define SCAN_SUPPRESS   0x2       /* Suppress assignment. */
      88             : #define SCAN_UNSIGNED   0x4       /* Read an unsigned value. */
      89             : #define SCAN_WIDTH      0x8       /* A width value was supplied. */
      90             : 
      91             : #define SCAN_SIGNOK     0x10      /* A +/- character is allowed. */
      92             : #define SCAN_NODIGITS   0x20      /* No digits have been scanned. */
      93             : #define SCAN_NOZERO     0x40      /* No zero digits have been scanned. */
      94             : #define SCAN_XOK        0x80      /* An 'x' is allowed. */
      95             : #define SCAN_PTOK       0x100     /* Decimal point is allowed. */
      96             : #define SCAN_EXPOK      0x200     /* An exponent is allowed. */
      97             : 
      98             : #define UCHAR(x)                (zend_uchar)(x)
      99             : 
     100             : /*
     101             :  * The following structure contains the information associated with
     102             :  * a character set.
     103             :  */
     104             : typedef struct CharSet {
     105             :         int exclude;            /* 1 if this is an exclusion set. */
     106             :         int nchars;
     107             :         char *chars;
     108             :         int nranges;
     109             :         struct Range {
     110             :                 char start;
     111             :                 char end;
     112             :         } *ranges;
     113             : } CharSet;
     114             : 
     115             : /*
     116             :  * Declarations for functions used only in this file.
     117             :  */
     118             : static char *BuildCharSet(CharSet *cset, char *format);
     119             : static int      CharInSet(CharSet *cset, int ch);
     120             : static void     ReleaseCharSet(CharSet *cset);
     121             : static inline void scan_set_error_return(int numVars, zval *return_value);
     122             : 
     123             : 
     124             : /* {{{ BuildCharSet
     125             :  *----------------------------------------------------------------------
     126             :  *
     127             :  * BuildCharSet --
     128             :  *
     129             :  *      This function examines a character set format specification
     130             :  *      and builds a CharSet containing the individual characters and
     131             :  *      character ranges specified.
     132             :  *
     133             :  * Results:
     134             :  *      Returns the next format position.
     135             :  *
     136             :  * Side effects:
     137             :  *      Initializes the charset.
     138             :  *
     139             :  *----------------------------------------------------------------------
     140             :  */
     141         480 : static char * BuildCharSet(CharSet *cset, char *format)
     142             : {
     143             :         char *ch, start;
     144             :         int  nranges;
     145             :         char *end;
     146             : 
     147         480 :         memset(cset, 0, sizeof(CharSet));
     148             : 
     149         480 :         ch = format;
     150         480 :         if (*ch == '^') {
     151           2 :                 cset->exclude = 1;
     152           2 :                 ch = ++format;
     153             :         }
     154         480 :         end = format + 1;       /* verify this - cc */
     155             : 
     156             :         /*
     157             :          * Find the close bracket so we can overallocate the set.
     158             :          */
     159         480 :         if (*ch == ']') {
     160           0 :                 ch = end++;
     161             :         }
     162         480 :         nranges = 0;
     163        3526 :         while (*ch != ']') {
     164        2566 :                 if (*ch == '-') {
     165         756 :                         nranges++;
     166             :                 }
     167        2566 :                 ch = end++;
     168             :         }
     169             : 
     170         480 :         cset->chars = (char *) safe_emalloc(sizeof(char), (end - format - 1), 0);
     171         480 :         if (nranges > 0) {
     172         478 :                 cset->ranges = (struct Range *) safe_emalloc(sizeof(struct Range), nranges, 0);
     173             :         } else {
     174           2 :                 cset->ranges = NULL;
     175             :         }
     176             : 
     177             :         /*
     178             :          * Now build the character set.
     179             :          */
     180         480 :         cset->nchars = cset->nranges = 0;
     181         480 :         ch    = format++;
     182         480 :         start = *ch;
     183         480 :         if (*ch == ']' || *ch == '-') {
     184           0 :                 cset->chars[cset->nchars++] = *ch;
     185           0 :                 ch = format++;
     186             :         }
     187        2770 :         while (*ch != ']') {
     188        1810 :                 if (*format == '-') {
     189             :                         /*
     190             :                          * This may be the first character of a range, so don't add
     191             :                          * it yet.
     192             :                          */
     193         756 :                         start = *ch;
     194        1054 :                 } else if (*ch == '-') {
     195             :                         /*
     196             :                          * Check to see if this is the last character in the set, in which
     197             :                          * case it is not a range and we should add the previous character
     198             :                          * as well as the dash.
     199             :                          */
     200         756 :                         if (*format == ']') {
     201           0 :                                 cset->chars[cset->nchars++] = start;
     202           0 :                                 cset->chars[cset->nchars++] = *ch;
     203             :                         } else {
     204         756 :                                 ch = format++;
     205             : 
     206             :                                 /*
     207             :                                  * Check to see if the range is in reverse order.
     208             :                                  */
     209         756 :                                 if (start < *ch) {
     210         756 :                                         cset->ranges[cset->nranges].start = start;
     211         756 :                                         cset->ranges[cset->nranges].end = *ch;
     212             :                                 } else {
     213           0 :                                         cset->ranges[cset->nranges].start = *ch;
     214           0 :                                         cset->ranges[cset->nranges].end = start;
     215             :                                 }
     216         756 :                                 cset->nranges++;
     217             :                         }
     218             :                 } else {
     219         298 :                         cset->chars[cset->nchars++] = *ch;
     220             :                 }
     221        1810 :                 ch = format++;
     222             :         }
     223         480 :         return format;
     224             : }
     225             : /* }}} */
     226             : 
     227             : /* {{{ CharInSet
     228             :  *----------------------------------------------------------------------
     229             :  *
     230             :  * CharInSet --
     231             :  *
     232             :  *      Check to see if a character matches the given set.
     233             :  *
     234             :  * Results:
     235             :  *      Returns non-zero if the character matches the given set.
     236             :  *
     237             :  * Side effects:
     238             :  *      None.
     239             :  *
     240             :  *----------------------------------------------------------------------
     241             :  */
     242        1256 : static int CharInSet(CharSet *cset, int c)
     243             : {
     244        1256 :         char ch = (char) c;
     245        1256 :         int i, match = 0;
     246             : 
     247        2290 :         for (i = 0; i < cset->nchars; i++) {
     248        1034 :                 if (cset->chars[i] == ch) {
     249           0 :                         match = 1;
     250           0 :                         break;
     251             :                 }
     252             :         }
     253        1256 :         if (!match) {
     254        2494 :                 for (i = 0; i < cset->nranges; i++) {
     255        2955 :                         if ((cset->ranges[i].start <= ch)
     256         945 :                                 && (ch <= cset->ranges[i].end)) {
     257         772 :                                 match = 1;
     258         772 :                                 break;
     259             :                         }
     260             :                 }
     261             :         }
     262        1256 :         return (cset->exclude ? !match : match);
     263             : }
     264             : /* }}} */
     265             : 
     266             : /* {{{ ReleaseCharSet
     267             :  *----------------------------------------------------------------------
     268             :  *
     269             :  * ReleaseCharSet --
     270             :  *
     271             :  *      Free the storage associated with a character set.
     272             :  *
     273             :  * Results:
     274             :  *      None.
     275             :  *
     276             :  * Side effects:
     277             :  *      None.
     278             :  *
     279             :  *----------------------------------------------------------------------
     280             :  */
     281         480 : static void ReleaseCharSet(CharSet *cset)
     282             : {
     283         480 :         efree((char *)cset->chars);
     284         480 :         if (cset->ranges) {
     285         478 :                 efree((char *)cset->ranges);
     286             :         }
     287         480 : }
     288             : /* }}} */
     289             : 
     290             : /* {{{ ValidateFormat
     291             :  *----------------------------------------------------------------------
     292             :  *
     293             :  * ValidateFormat --
     294             :  *
     295             :  *      Parse the format string and verify that it is properly formed
     296             :  *      and that there are exactly enough variables on the command line.
     297             :  *
     298             :  * Results:
     299             :  *    FAILURE or SUCCESS.
     300             :  *
     301             :  * Side effects:
     302             :  *     May set php_error based on abnormal conditions.
     303             :  *
     304             :  * Parameters :
     305             :  *     format     The format string.
     306             :  *     numVars    The number of variables passed to the scan command.
     307             :  *     totalSubs  The number of variables that will be required.
     308             :  *
     309             :  *----------------------------------------------------------------------
     310             : */
     311        6322 : PHPAPI int ValidateFormat(char *format, int numVars, int *totalSubs)
     312             : {
     313             : #define STATIC_LIST_SIZE 16
     314             :         int gotXpg, gotSequential, value, i, flags;
     315        6322 :         char *end, *ch = NULL;
     316             :         int staticAssign[STATIC_LIST_SIZE];
     317        6322 :         int *nassign = staticAssign;
     318        6322 :         int objIndex, xpgSize, nspace = STATIC_LIST_SIZE;
     319             :         TSRMLS_FETCH();
     320             : 
     321             :         /*
     322             :          * Initialize an array that records the number of times a variable
     323             :          * is assigned to by the format string.  We use this to detect if
     324             :          * a variable is multiply assigned or left unassigned.
     325             :          */
     326        6322 :         if (numVars > nspace) {
     327           0 :                 nassign = (int*)safe_emalloc(sizeof(int), numVars, 0);
     328           0 :                 nspace = numVars;
     329             :         }
     330      107474 :         for (i = 0; i < nspace; i++) {
     331      101152 :                 nassign[i] = 0;
     332             :         }
     333             : 
     334        6322 :         xpgSize = objIndex = gotXpg = gotSequential = 0;
     335             : 
     336       20828 :         while (*format != '\0') {
     337        8670 :                 ch = format++;
     338        8670 :                 flags = 0;
     339             : 
     340        8670 :                 if (*ch != '%') {
     341        2284 :                         continue;
     342             :                 }
     343        6386 :                 ch = format++;
     344        6386 :                 if (*ch == '%') {
     345           0 :                         continue;
     346             :                 }
     347        6386 :                 if (*ch == '*') {
     348         479 :                         flags |= SCAN_SUPPRESS;
     349         479 :                         ch = format++;
     350         479 :                         goto xpgCheckDone;
     351             :                 }
     352             : 
     353        5907 :                 if ( isdigit( (int)*ch ) ) {
     354             :                         /*
     355             :                          * Check for an XPG3-style %n$ specification.  Note: there
     356             :                          * must not be a mixture of XPG3 specs and non-XPG3 specs
     357             :                          * in the same format string.
     358             :                          */
     359         970 :                         value = ZEND_STRTOUL(format-1, &end, 10);
     360         970 :                         if (*end != '$') {
     361         958 :                                 goto notXpg;
     362             :                         }
     363          12 :                         format = end+1;
     364          12 :                         ch     = format++;
     365          12 :                         gotXpg = 1;
     366          12 :                         if (gotSequential) {
     367           0 :                                 goto mixedXPG;
     368             :                         }
     369          12 :                         objIndex = value - 1;
     370          12 :                         if ((objIndex < 0) || (numVars && (objIndex >= numVars))) {
     371             :                                 goto badIndex;
     372          12 :                         } else if (numVars == 0) {
     373             :                                 /*
     374             :                                  * In the case where no vars are specified, the user can
     375             :                                  * specify %9999$ legally, so we have to consider special
     376             :                                  * rules for growing the assign array.  'value' is
     377             :                                  * guaranteed to be > 0.
     378             :                                  */
     379             : 
     380             :                                 /* set a lower artificial limit on this
     381             :                                  * in the interest of security and resource friendliness
     382             :                                  * 255 arguments should be more than enough. - cc
     383             :                                  */
     384           7 :                                 if (value > SCAN_MAX_ARGS) {
     385           0 :                                         goto badIndex;
     386             :                                 }
     387             : 
     388           7 :                                 xpgSize = (xpgSize > value) ? xpgSize : value;
     389             :                         }
     390          12 :                         goto xpgCheckDone;
     391             :                 }
     392             : 
     393             : notXpg:
     394        5895 :                 gotSequential = 1;
     395        5895 :                 if (gotXpg) {
     396             : mixedXPG:
     397           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", "cannot mix \"%\" and \"%n$\" conversion specifiers");
     398           0 :                         goto error;
     399             :                 }
     400             : 
     401             : xpgCheckDone:
     402             :                 /*
     403             :                  * Parse any width specifier.
     404             :                  */
     405        6386 :                 if (isdigit(UCHAR(*ch))) {
     406         958 :                         value = ZEND_STRTOUL(format-1, &format, 10);
     407         958 :                         flags |= SCAN_WIDTH;
     408         958 :                         ch = format++;
     409             :                 }
     410             : 
     411             :                 /*
     412             :                  * Ignore size specifier.
     413             :                  */
     414        6386 :                 if ((*ch == 'l') || (*ch == 'L') || (*ch == 'h')) {
     415        1438 :                         ch = format++;
     416             :                 }
     417             : 
     418        6386 :                 if (!(flags & SCAN_SUPPRESS) && numVars && (objIndex >= numVars)) {
     419           2 :                         goto badIndex;
     420             :                 }
     421             : 
     422             :                 /*
     423             :                  * Handle the various field types.
     424             :                  */
     425        6384 :                 switch (*ch) {
     426             :                         case 'n':
     427             :                         case 'd':
     428             :                         case 'D':
     429             :                         case 'i':
     430             :                         case 'o':
     431             :                         case 'x':
     432             :                         case 'X':
     433             :                         case 'u':
     434             :                         case 'f':
     435             :                         case 'e':
     436             :                         case 'E':
     437             :                         case 'g':
     438             :                         case 's':
     439        4597 :                                 break;
     440             : 
     441             :                         case 'c':
     442             :                                 /* we differ here with the TCL implementation in allowing for */
     443             :                                 /* a character width specification, to be more consistent with */
     444             :                                 /* ANSI. since Zend auto allocates space for vars, this is no */
     445             :                                 /* problem - cc                                               */
     446             :                                 /*
     447             :                                 if (flags & SCAN_WIDTH) {
     448             :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Field width may not be specified in %c conversion");
     449             :                                         goto error;
     450             :                                 }
     451             :                                 */
     452         822 :                                 break;
     453             : 
     454             :                         case '[':
     455         481 :                                 if (*format == '\0') {
     456           0 :                                         goto badSet;
     457             :                                 }
     458         481 :                                 ch = format++;
     459         481 :                                 if (*ch == '^') {
     460           2 :                                         if (*format == '\0') {
     461           0 :                                                 goto badSet;
     462             :                                         }
     463           2 :                                         ch = format++;
     464             :                                 }
     465         481 :                                 if (*ch == ']') {
     466           0 :                                         if (*format == '\0') {
     467           0 :                                                 goto badSet;
     468             :                                         }
     469           0 :                                         ch = format++;
     470             :                                 }
     471        3537 :                                 while (*ch != ']') {
     472        2575 :                                         if (*format == '\0') {
     473           0 :                                                 goto badSet;
     474             :                                         }
     475        2575 :                                         ch = format++;
     476             :                                 }
     477         481 :                                 break;
     478             : badSet:
     479           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unmatched [ in format string");
     480           0 :                                 goto error;
     481             : 
     482             :                         default: {
     483         484 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad scan conversion character \"%c\"", *ch);
     484         484 :                                 goto error;
     485             :                         }
     486             :                 }
     487             : 
     488        5900 :                 if (!(flags & SCAN_SUPPRESS)) {
     489        5421 :                         if (objIndex >= nspace) {
     490             :                                 /*
     491             :                                  * Expand the nassign buffer.  If we are using XPG specifiers,
     492             :                                  * make sure that we grow to a large enough size.  xpgSize is
     493             :                                  * guaranteed to be at least one larger than objIndex.
     494             :                                  */
     495           0 :                                 value = nspace;
     496           0 :                                 if (xpgSize) {
     497           0 :                                         nspace = xpgSize;
     498             :                                 } else {
     499           0 :                                         nspace += STATIC_LIST_SIZE;
     500             :                                 }
     501           0 :                                 if (nassign == staticAssign) {
     502           0 :                                         nassign = (void *)safe_emalloc(nspace, sizeof(int), 0);
     503           0 :                                         for (i = 0; i < STATIC_LIST_SIZE; ++i) {
     504           0 :                                                 nassign[i] = staticAssign[i];
     505             :                                         }
     506             :                                 } else {
     507           0 :                                         nassign = (void *)erealloc((void *)nassign, nspace * sizeof(int));
     508             :                                 }
     509           0 :                                 for (i = value; i < nspace; i++) {
     510           0 :                                         nassign[i] = 0;
     511             :                                 }
     512             :                         }
     513        5421 :                         nassign[objIndex]++;
     514        5421 :                         objIndex++;
     515             :                 }
     516             :         } /* while (*format != '\0') */
     517             : 
     518             :         /*
     519             :          * Verify that all of the variable were assigned exactly once.
     520             :          */
     521        5836 :         if (numVars == 0) {
     522        5808 :                 if (xpgSize) {
     523           4 :                         numVars = xpgSize;
     524             :                 } else {
     525        5804 :                         numVars = objIndex;
     526             :                 }
     527             :         }
     528        5836 :         if (totalSubs) {
     529        5836 :                 *totalSubs = numVars;
     530             :         }
     531       11253 :         for (i = 0; i < numVars; i++) {
     532        5420 :                 if (nassign[i] > 1) {
     533           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", "Variable is assigned by multiple \"%n$\" conversion specifiers");
     534           0 :                         goto error;
     535        5420 :                 } else if (!xpgSize && (nassign[i] == 0)) {
     536             :                         /*
     537             :                          * If the space is empty, and xpgSize is 0 (means XPG wasn't
     538             :                          * used, and/or numVars != 0), then too many vars were given
     539             :                          */
     540           3 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Variable is not assigned by any conversion specifiers");
     541           3 :                         goto error;
     542             :                 }
     543             :         }
     544             : 
     545        5833 :         if (nassign != staticAssign) {
     546           0 :                 efree((char *)nassign);
     547             :         }
     548        5833 :         return SCAN_SUCCESS;
     549             : 
     550             : badIndex:
     551           2 :         if (gotXpg) {
     552           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", "\"%n$\" argument index out of range");
     553             :         } else {
     554           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Different numbers of variable names and field specifiers");
     555             :         }
     556             : 
     557             : error:
     558         489 :         if (nassign != staticAssign) {
     559           0 :                 efree((char *)nassign);
     560             :         }
     561         489 :         return SCAN_ERROR_INVALID_FORMAT;
     562             : #undef STATIC_LIST_SIZE
     563             : }
     564             : /* }}} */
     565             : 
     566             : /* {{{ php_sscanf_internal
     567             :  * This is the internal function which does processing on behalf of
     568             :  * both sscanf() and fscanf()
     569             :  *
     570             :  * parameters :
     571             :  *              string          literal string to be processed
     572             :  *              format          format string
     573             :  *              argCount        total number of elements in the args array
     574             :  *              args            arguments passed in from user function (f|s)scanf
     575             :  *              varStart        offset (in args) of 1st variable passed in to (f|s)scanf
     576             :  *              return_value set with the results of the scan
     577             :  */
     578             : 
     579        6322 : PHPAPI int php_sscanf_internal( char *string, char *format,
     580             :                                 int argCount, zval *args,
     581             :                                 int varStart, zval *return_value TSRMLS_DC)
     582             : {
     583        6322 :         int  numVars, nconversions, totalVars = -1;
     584             :         int  i, result;
     585             :         zend_long value;
     586             :         int  objIndex;
     587             :         char *end, *baseString;
     588             :         zval *current;
     589        6322 :         char op   = 0;
     590        6322 :         int  base = 0;
     591        6322 :         int  underflow = 0;
     592             :         size_t width;
     593        6322 :         zend_long (*fn)() = NULL;
     594             :         char *ch, sch;
     595             :         int  flags;
     596             :         char buf[64];   /* Temporary buffer to hold scanned number
     597             :                                          * strings before they are passed to strtoul() */
     598             : 
     599             :         /* do some sanity checking */
     600        6322 :         if ((varStart > argCount) || (varStart < 0)){
     601           0 :                 varStart = SCAN_MAX_ARGS + 1;
     602             :         }
     603        6322 :         numVars = argCount - varStart;
     604        6322 :         if (numVars < 0) {
     605           0 :                 numVars = 0;
     606             :         }
     607             : 
     608             : #if 0
     609             :         zend_printf("<br>in sscanf_internal : <br> string is \"%s\", format = \"%s\"<br> NumVars = %d. VarStart = %d<br>-------------------------<br>",
     610             :                                         string, format, numVars, varStart);
     611             : #endif
     612             :         /*
     613             :          * Check for errors in the format string.
     614             :          */
     615        6322 :         if (ValidateFormat(format, numVars, &totalVars) != SCAN_SUCCESS) {
     616         489 :                 scan_set_error_return( numVars, return_value );
     617         489 :                 return SCAN_ERROR_INVALID_FORMAT;
     618             :         }
     619             : 
     620        5833 :         objIndex = numVars ? varStart : 0;
     621             : 
     622             :         /*
     623             :          * If any variables are passed, make sure they are all passed by reference
     624             :          */
     625        5833 :         if (numVars) {
     626          93 :                 for (i = varStart;i < argCount;i++){
     627         136 :                         if ( ! Z_ISREF(args[ i ] ) ) {
     628           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Parameter %d must be passed by reference", i);
     629           0 :                                 scan_set_error_return(numVars, return_value);
     630           0 :                                 return SCAN_ERROR_VAR_PASSED_BYVAL;
     631             :                         }
     632             :                 }
     633             :         }
     634             : 
     635             :         /*
     636             :          * Allocate space for the result objects. Only happens when no variables
     637             :          * are specified
     638             :          */
     639        5833 :         if (!numVars) {
     640             :                 zval tmp;
     641             : 
     642             :                 /* allocate an array for return */
     643        5808 :                 array_init(return_value);
     644             : 
     645       11154 :                 for (i = 0; i < totalVars; i++) {
     646        5346 :                         ZVAL_NULL(&tmp);
     647        5346 :                         if (add_next_index_zval(return_value, &tmp) == FAILURE) {
     648           0 :                                 scan_set_error_return(0, return_value);
     649           0 :                                 return FAILURE;
     650             :                         }
     651             :                 }
     652        5808 :                 varStart = 0; /* Array index starts from 0 */
     653             :         }
     654             : 
     655        5833 :         baseString = string;
     656             : 
     657             :         /*
     658             :          * Iterate over the format string filling in the result objects until
     659             :          * we reach the end of input, the end of the format string, or there
     660             :          * is a mismatch.
     661             :          */
     662        5833 :         nconversions = 0;
     663             :         /* note ! - we need to limit the loop for objIndex to keep it in bounds */
     664             : 
     665       17297 :         while (*format != '\0') {
     666        7912 :                 ch    = format++;
     667        7912 :                 flags = 0;
     668             : 
     669             :                 /*
     670             :                  * If we see whitespace in the format, skip whitespace in the string.
     671             :                  */
     672        7912 :                 if ( isspace( (int)*ch ) ) {
     673        1846 :                         sch = *string;
     674        4129 :                         while ( isspace( (int)sch ) ) {
     675         437 :                                 if (*string == '\0') {
     676           0 :                                         goto done;
     677             :                                 }
     678         437 :                                 string++;
     679         437 :                                 sch = *string;
     680             :                         }
     681        1846 :                         continue;
     682             :                 }
     683             : 
     684        6066 :                 if (*ch != '%') {
     685             : literal:
     686         180 :                         if (*string == '\0') {
     687           3 :                                 underflow = 1;
     688           3 :                                 goto done;
     689             :                         }
     690         177 :                         sch = *string;
     691         177 :                         string++;
     692         177 :                         if (*ch != sch) {
     693          13 :                                 goto done;
     694             :                         }
     695         164 :                         continue;
     696             :                 }
     697             : 
     698        5886 :                 ch = format++;
     699        5886 :                 if (*ch == '%') {
     700           0 :                         goto literal;
     701             :                 }
     702             : 
     703             :                 /*
     704             :                  * Check for assignment suppression ('*') or an XPG3-style
     705             :                  * assignment ('%n$').
     706             :                  */
     707        5886 :                 if (*ch == '*') {
     708         479 :                         flags |= SCAN_SUPPRESS;
     709         479 :                         ch = format++;
     710        5407 :                 } else if ( isdigit(UCHAR(*ch))) {
     711         969 :                         value = ZEND_STRTOUL(format-1, &end, 10);
     712         969 :                         if (*end == '$') {
     713          11 :                                 format = end+1;
     714          11 :                                 ch = format++;
     715          11 :                                 objIndex = varStart + value - 1;
     716             :                         }
     717             :                 }
     718             : 
     719             :                 /*
     720             :                  * Parse any width specifier.
     721             :                  */
     722        5886 :                 if ( isdigit(UCHAR(*ch))) {
     723         958 :                         width = ZEND_STRTOUL(format-1, &format, 10);
     724         958 :                         ch = format++;
     725             :                 } else {
     726        4928 :                         width = 0;
     727             :                 }
     728             : 
     729             :                 /*
     730             :                  * Ignore size specifier.
     731             :                  */
     732        5886 :                 if ((*ch == 'l') || (*ch == 'L') || (*ch == 'h')) {
     733        1437 :                         ch = format++;
     734             :                 }
     735             : 
     736             :                 /*
     737             :                  * Handle the various field types.
     738             :                  */
     739        5886 :                 switch (*ch) {
     740             :                         case 'n':
     741           2 :                                 if (!(flags & SCAN_SUPPRESS)) {
     742           2 :                                         if (numVars && objIndex >= argCount) {
     743             :                                                 break;
     744           2 :                                         } else if (numVars) {
     745           1 :                                                 current = Z_REFVAL(args[objIndex++]);
     746           1 :                                                 zval_ptr_dtor(current);
     747           1 :                                                 ZVAL_LONG(current, (zend_long)(string - baseString) );
     748             :                                         } else {
     749           1 :                                                 add_index_long(return_value, objIndex++, string - baseString);
     750             :                                         }
     751             :                                 }
     752           2 :                                 nconversions++;
     753           2 :                                 continue;
     754             : 
     755             :                         case 'd':
     756             :                         case 'D':
     757         606 :                                 op = 'i';
     758         606 :                                 base = 10;
     759         606 :                                 fn = (zend_long (*)())ZEND_STRTOL_PTR;
     760         606 :                                 break;
     761             :                         case 'i':
     762           0 :                                 op = 'i';
     763           0 :                                 base = 0;
     764           0 :                                 fn = (zend_long (*)())ZEND_STRTOL_PTR;
     765           0 :                                 break;
     766             :                         case 'o':
     767         770 :                                 op = 'i';
     768         770 :                                 base = 8;
     769         770 :                                 fn = (zend_long (*)())ZEND_STRTOL_PTR;
     770         770 :                                 break;
     771             :                         case 'x':
     772             :                         case 'X':
     773         421 :                                 op = 'i';
     774         421 :                                 base = 16;
     775         421 :                                 fn = (zend_long (*)())ZEND_STRTOL_PTR;
     776         421 :                                 break;
     777             :                         case 'u':
     778         399 :                                 op = 'i';
     779         399 :                                 base = 10;
     780         399 :                                 flags |= SCAN_UNSIGNED;
     781         399 :                                 fn = (zend_long (*)())ZEND_STRTOUL_PTR;
     782         399 :                                 break;
     783             : 
     784             :                         case 'f':
     785             :                         case 'e':
     786             :                         case 'E':
     787             :                         case 'g':
     788        1512 :                                 op = 'f';
     789        1512 :                                 break;
     790             : 
     791             :                         case 's':
     792         873 :                                 op = 's';
     793         873 :                                 break;
     794             : 
     795             :                         case 'c':
     796         822 :                                 op = 's';
     797         822 :                                 flags |= SCAN_NOSKIP;
     798             :                                 /*-cc-*/
     799         822 :                                 if (0 == width) {
     800         674 :                                         width = 1;
     801             :                                 }
     802             :                                 /*-cc-*/
     803         822 :                                 break;
     804             :                         case '[':
     805         481 :                                 op = '[';
     806         481 :                                 flags |= SCAN_NOSKIP;
     807             :                                 break;
     808             :                 }   /* switch */
     809             : 
     810             :                 /*
     811             :                  * At this point, we will need additional characters from the
     812             :                  * string to proceed.
     813             :                  */
     814        5884 :                 if (*string == '\0') {
     815         129 :                         underflow = 1;
     816         129 :                         goto done;
     817             :                 }
     818             : 
     819             :                 /*
     820             :                  * Skip any leading whitespace at the beginning of a field unless
     821             :                  * the format suppresses this behavior.
     822             :                  */
     823        5755 :                 if (!(flags & SCAN_NOSKIP)) {
     824        9218 :                         while (*string != '\0') {
     825        4489 :                                 sch = *string;
     826        4489 :                                 if (! isspace((int)sch) ) {
     827        4201 :                                         break;
     828             :                                 }
     829         288 :                                 string++;
     830             :                         }
     831        4465 :                         if (*string == '\0') {
     832         264 :                                 underflow = 1;
     833         264 :                                 goto done;
     834             :                         }
     835             :                 }
     836             : 
     837             :                 /*
     838             :                  * Perform the requested scanning operation.
     839             :                  */
     840        5491 :                 switch (op) {
     841             :                         case 'c':
     842             :                         case 's':
     843             :                                 /*
     844             :                                  * Scan a string up to width characters or whitespace.
     845             :                                  */
     846        1567 :                                 if (width == 0) {
     847         627 :                                         width = (size_t) ~0;
     848             :                                 }
     849        1567 :                                 end = string;
     850        7791 :                                 while (*end != '\0') {
     851        6203 :                                         sch = *end;
     852        6203 :                                         if ( isspace( (int)sch ) ) {
     853         810 :                                                 break;
     854             :                                         }
     855        5393 :                                         end++;
     856        5393 :                                         if (--width == 0) {
     857         736 :                                            break;
     858             :                                         }
     859             :                                 }
     860        1567 :                                 if (!(flags & SCAN_SUPPRESS)) {
     861        1428 :                                         if (numVars && objIndex >= argCount) {
     862             :                                                 break;
     863        1428 :                                         } else if (numVars) {
     864          21 :                                                 current = Z_REFVAL(args[objIndex++]);
     865          21 :                                                 zval_ptr_dtor(current);
     866          42 :                                                 ZVAL_STRINGL(current, string, end-string);
     867             :                                         } else {
     868        1407 :                                                 add_index_stringl(return_value, objIndex++, string, end-string);
     869             :                                         }
     870             :                                 }
     871        1567 :                                 string = end;
     872        1567 :                                 break;
     873             : 
     874             :                         case '[': {
     875             :                                 CharSet cset;
     876             : 
     877         480 :                                 if (width == 0) {
     878         480 :                                         width = (size_t) ~0;
     879             :                                 }
     880         480 :                                 end = string;
     881             : 
     882         480 :                                 format = BuildCharSet(&cset, format);
     883        1738 :                                 while (*end != '\0') {
     884        1256 :                                         sch = *end;
     885        1256 :                                         if (!CharInSet(&cset, (int)sch)) {
     886         478 :                                                 break;
     887             :                                         }
     888         778 :                                         end++;
     889         778 :                                         if (--width == 0) {
     890           0 :                                                 break;
     891             :                                         }
     892             :                                 }
     893         480 :                                 ReleaseCharSet(&cset);
     894             : 
     895         480 :                                 if (string == end) {
     896             :                                         /*
     897             :                                          * Nothing matched the range, stop processing
     898             :                                          */
     899         287 :                                         goto done;
     900             :                                 }
     901         193 :                                 if (!(flags & SCAN_SUPPRESS)) {
     902         193 :                                         if (numVars && objIndex >= argCount) {
     903             :                                                 break;
     904         193 :                                         } else if (numVars) {
     905           2 :                                                 current = Z_REFVAL(args[objIndex++]);
     906           2 :                                                 zval_ptr_dtor(current);
     907           4 :                                                 ZVAL_STRINGL(current, string, end-string);
     908             :                                         } else {
     909         191 :                                                 add_index_stringl(return_value, objIndex++, string, end-string);
     910             :                                         }
     911             :                                 }
     912         193 :                                 string = end;
     913         193 :                                 break;
     914             :                         }
     915             : /*
     916             :                         case 'c':
     917             :                            / Scan a single character./
     918             : 
     919             :                                 sch = *string;
     920             :                                 string++;
     921             :                                 if (!(flags & SCAN_SUPPRESS)) {
     922             :                                         if (numVars) {
     923             :                                                 char __buf[2];
     924             :                                                 __buf[0] = sch;
     925             :                                                 __buf[1] = '\0';;
     926             :                                                 current = args[objIndex++];
     927             :                                                 zval_dtor(*current);
     928             :                                                 ZVAL_STRINGL( *current, __buf, 1);
     929             :                                         } else {
     930             :                                                 add_index_stringl(return_value, objIndex++, &sch, 1);
     931             :                                         }
     932             :                                 }
     933             :                                 break;
     934             : */
     935             :                         case 'i':
     936             :                                 /*
     937             :                                  * Scan an unsigned or signed integer.
     938             :                                  */
     939             :                                 /*-cc-*/
     940        2020 :                                 buf[0] = '\0';
     941             :                                 /*-cc-*/
     942        2020 :                                 if ((width == 0) || (width > sizeof(buf) - 1)) {
     943        1662 :                                         width = sizeof(buf) - 1;
     944             :                                 }
     945             : 
     946        2020 :                                 flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO;
     947        5422 :                                 for (end = buf; width > 0; width--) {
     948        5389 :                                         switch (*string) {
     949             :                                                 /*
     950             :                                                  * The 0 digit has special meaning at the beginning of
     951             :                                                  * a number.  If we are unsure of the base, it
     952             :                                                  * indicates that we are in base 8 or base 16 (if it is
     953             :                                                  * followed by an 'x').
     954             :                                                  */
     955             :                                                 case '0':
     956             :                                                         /*-cc-*/
     957         555 :                                                         if (base == 16) {
     958          26 :                                                                 flags |= SCAN_XOK;
     959             :                                                         }
     960             :                                                         /*-cc-*/
     961         555 :                                                         if (base == 0) {
     962           0 :                                                                 base = 8;
     963           0 :                                                                 flags |= SCAN_XOK;
     964             :                                                         }
     965         555 :                                                         if (flags & SCAN_NOZERO) {
     966         266 :                                                                 flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO);
     967             :                                                         } else {
     968         289 :                                                                 flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
     969             :                                                         }
     970         555 :                                                         goto addToInt;
     971             : 
     972             :                                                 case '1': case '2': case '3': case '4':
     973             :                                                 case '5': case '6': case '7':
     974        2299 :                                                         if (base == 0) {
     975           0 :                                                                 base = 10;
     976             :                                                         }
     977        2299 :                                                         flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
     978        2299 :                                                         goto addToInt;
     979             : 
     980             :                                                 case '8': case '9':
     981         357 :                                                         if (base == 0) {
     982           0 :                                                                 base = 10;
     983             :                                                         }
     984         357 :                                                         if (base <= 8) {
     985         187 :                                                            break;
     986             :                                                         }
     987         170 :                                                         flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
     988         170 :                                                         goto addToInt;
     989             : 
     990             :                                                 case 'A': case 'B': case 'C':
     991             :                                                 case 'D': case 'E': case 'F':
     992             :                                                 case 'a': case 'b': case 'c':
     993             :                                                 case 'd': case 'e': case 'f':
     994         663 :                                                         if (base <= 10) {
     995         463 :                                                                 break;
     996             :                                                         }
     997         200 :                                                         flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
     998         200 :                                                         goto addToInt;
     999             : 
    1000             :                                                 case '+': case '-':
    1001         184 :                                                         if (flags & SCAN_SIGNOK) {
    1002         184 :                                                                 flags &= ~SCAN_SIGNOK;
    1003         184 :                                                                 goto addToInt;
    1004             :                                                         }
    1005           0 :                                                         break;
    1006             : 
    1007             :                                                 case 'x': case 'X':
    1008           0 :                                                         if ((flags & SCAN_XOK) && (end == buf+1)) {
    1009           0 :                                                                 base = 16;
    1010           0 :                                                                 flags &= ~SCAN_XOK;
    1011           0 :                                                                 goto addToInt;
    1012             :                                                         }
    1013             :                                                         break;
    1014             :                                         }
    1015             : 
    1016             :                                         /*
    1017             :                                          * We got an illegal character so we are done accumulating.
    1018             :                                          */
    1019        1981 :                                         break;
    1020             : 
    1021             : addToInt:
    1022             :                                         /*
    1023             :                                          * Add the character to the temporary buffer.
    1024             :                                          */
    1025        3408 :                                         *end++ = *string++;
    1026        3408 :                                         if (*string == '\0') {
    1027           6 :                                                 break;
    1028             :                                         }
    1029             :                                 }
    1030             : 
    1031             :                                 /*
    1032             :                                  * Check to see if we need to back up because we only got a
    1033             :                                  * sign or a trailing x after a 0.
    1034             :                                  */
    1035        2020 :                                 if (flags & SCAN_NODIGITS) {
    1036        1011 :                                         if (*string == '\0') {
    1037           0 :                                                 underflow = 1;
    1038             :                                         }
    1039        1011 :                                         goto done;
    1040        1009 :                                 } else if (end[-1] == 'x' || end[-1] == 'X') {
    1041           0 :                                         end--;
    1042           0 :                                         string--;
    1043             :                                 }
    1044             : 
    1045             :                                 /*
    1046             :                                  * Scan the value from the temporary buffer.  If we are
    1047             :                                  * returning a large unsigned value, we have to convert it back
    1048             :                                  * to a string since PHP only supports signed values.
    1049             :                                  */
    1050        1009 :                                 if (!(flags & SCAN_SUPPRESS)) {
    1051         921 :                                         *end = '\0';
    1052         921 :                                         value = (zend_long) (*fn)(buf, NULL, base);
    1053         922 :                                         if ((flags & SCAN_UNSIGNED) && (value < 0)) {
    1054           1 :                                                 snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, value); /* INTL: ISO digit */
    1055           1 :                                                 if (numVars && objIndex >= argCount) {
    1056             :                                                         break;
    1057           1 :                                                 } else if (numVars) {
    1058             :                                                   /* change passed value type to string */
    1059           1 :                                                         current = Z_REFVAL(args[objIndex++]);
    1060           1 :                                                         zval_ptr_dtor(current);
    1061           2 :                                                         ZVAL_STRING(current, buf);
    1062             :                                                 } else {
    1063           0 :                                                         add_index_string(return_value, objIndex++, buf);
    1064             :                                                 }
    1065             :                                         } else {
    1066         920 :                                                 if (numVars && objIndex >= argCount) {
    1067             :                                                         break;
    1068         920 :                                                 } else if (numVars) {
    1069          22 :                                                         current = Z_REFVAL(args[objIndex++]);
    1070          22 :                                                         zval_ptr_dtor(current);
    1071          22 :                                                         ZVAL_LONG(current, value);
    1072             :                                                 } else {
    1073         898 :                                                         add_index_long(return_value, objIndex++, value);
    1074             :                                                 }
    1075             :                                         }
    1076             :                                 }
    1077        1009 :                                 break;
    1078             : 
    1079             :                         case 'f':
    1080             :                                 /*
    1081             :                                  * Scan a floating point number
    1082             :                                  */
    1083        1424 :                                 buf[0] = '\0';     /* call me pedantic */
    1084        1424 :                                 if ((width == 0) || (width > sizeof(buf) - 1)) {
    1085        1170 :                                         width = sizeof(buf) - 1;
    1086             :                                 }
    1087        1424 :                                 flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_PTOK | SCAN_EXPOK;
    1088        6425 :                                 for (end = buf; width > 0; width--) {
    1089        6373 :                                         switch (*string) {
    1090             :                                                 case '0': case '1': case '2': case '3':
    1091             :                                                 case '4': case '5': case '6': case '7':
    1092             :                                                 case '8': case '9':
    1093        4356 :                                                         flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS);
    1094        4356 :                                                         goto addToFloat;
    1095             :                                                 case '+':
    1096             :                                                 case '-':
    1097         379 :                                                         if (flags & SCAN_SIGNOK) {
    1098         379 :                                                                 flags &= ~SCAN_SIGNOK;
    1099         379 :                                                                 goto addToFloat;
    1100             :                                                         }
    1101           0 :                                                         break;
    1102             :                                                 case '.':
    1103         156 :                                                         if (flags & SCAN_PTOK) {
    1104         156 :                                                                 flags &= ~(SCAN_SIGNOK | SCAN_PTOK);
    1105         156 :                                                                 goto addToFloat;
    1106             :                                                         }
    1107           0 :                                                         break;
    1108             :                                                 case 'e':
    1109             :                                                 case 'E':
    1110             :                                                         /*
    1111             :                                                          * An exponent is not allowed until there has
    1112             :                                                          * been at least one digit.
    1113             :                                                          */
    1114         117 :                                                         if ((flags & (SCAN_NODIGITS | SCAN_EXPOK)) == SCAN_EXPOK) {
    1115         117 :                                                                 flags = (flags & ~(SCAN_EXPOK|SCAN_PTOK))
    1116             :                                                                         | SCAN_SIGNOK | SCAN_NODIGITS;
    1117         117 :                                                                 goto addToFloat;
    1118             :                                                         }
    1119             :                                                         break;
    1120             :                                         }
    1121             : 
    1122             :                                         /*
    1123             :                                          * We got an illegal character so we are done accumulating.
    1124             :                                          */
    1125        1365 :                                         break;
    1126             : 
    1127             : addToFloat:
    1128             :                                         /*
    1129             :                                          * Add the character to the temporary buffer.
    1130             :                                          */
    1131        5008 :                                         *end++ = *string++;
    1132        5008 :                                         if (*string == '\0') {
    1133           7 :                                                 break;
    1134             :                                         }
    1135             :                                 }
    1136             : 
    1137             :                                 /*
    1138             :                                  * Check to see if we need to back up because we saw a
    1139             :                                  * trailing 'e' or sign.
    1140             :                                  */
    1141        1424 :                                 if (flags & SCAN_NODIGITS) {
    1142         579 :                                         if (flags & SCAN_EXPOK) {
    1143             :                                                 /*
    1144             :                                                  * There were no digits at all so scanning has
    1145             :                                                  * failed and we are done.
    1146             :                                                  */
    1147         574 :                                                 if (*string == '\0') {
    1148           0 :                                                         underflow = 1;
    1149             :                                                 }
    1150         574 :                                                 goto done;
    1151             :                                         }
    1152             : 
    1153             :                                         /*
    1154             :                                          * We got a bad exponent ('e' and maybe a sign).
    1155             :                                          */
    1156           5 :                                         end--;
    1157           5 :                                         string--;
    1158           5 :                                         if (*end != 'e' && *end != 'E') {
    1159           0 :                                                 end--;
    1160           0 :                                                 string--;
    1161             :                                         }
    1162             :                                 }
    1163             : 
    1164             :                                 /*
    1165             :                                  * Scan the value from the temporary buffer.
    1166             :                                  */
    1167         850 :                                 if (!(flags & SCAN_SUPPRESS)) {
    1168             :                                         double dvalue;
    1169         775 :                                         *end = '\0';
    1170         775 :                                         dvalue = zend_strtod(buf, NULL);
    1171         775 :                                         if (numVars && objIndex >= argCount) {
    1172             :                                                 break;
    1173         775 :                                         } else if (numVars) {
    1174          14 :                                                 current = Z_REFVAL(args[objIndex++]);
    1175          14 :                                                 zval_ptr_dtor(current);
    1176          14 :                                                 ZVAL_DOUBLE(current, dvalue);
    1177             :                                         } else {
    1178         761 :                                                 add_index_double(return_value, objIndex++, dvalue );
    1179             :                                         }
    1180             :                                 }
    1181             :                                 break;
    1182             :                 } /* switch (op) */
    1183        3619 :                 nconversions++;
    1184             :         } /*  while (*format != '\0') */
    1185             : 
    1186             : done:
    1187        5833 :         result = SCAN_SUCCESS;
    1188             : 
    1189        6226 :         if (underflow && (0==nconversions)) {
    1190         393 :                 scan_set_error_return( numVars, return_value );
    1191         393 :                 result = SCAN_ERROR_EOF;
    1192        5440 :         } else if (numVars) {
    1193          25 :                 convert_to_long(return_value );
    1194          25 :                 Z_LVAL_P(return_value) = nconversions;
    1195        5415 :         } else if (nconversions < totalVars) {
    1196             :                 /* TODO: not all elements converted. we need to prune the list - cc */
    1197             :         }
    1198        5833 :         return result;
    1199             : }
    1200             : /* }}} */
    1201             : 
    1202             : /* the compiler choked when i tried to make this a macro    */
    1203         882 : static inline void scan_set_error_return(int numVars, zval *return_value) /* {{{ */
    1204             : {
    1205         882 :         if (numVars) {
    1206           6 :                 ZVAL_LONG(return_value, SCAN_ERROR_EOF);  /* EOF marker */
    1207             :         } else {
    1208             :                 /* convert_to_null calls destructor */
    1209         876 :                 convert_to_null(return_value);
    1210             :         }
    1211         882 : }
    1212             : /* }}} */
    1213             : 
    1214             : /*
    1215             :  * Local variables:
    1216             :  * tab-width: 4
    1217             :  * c-basic-offset: 4
    1218             :  * End:
    1219             :  * vim600: sw=4 ts=4 fdm=marker
    1220             :  * vim<600: sw=4 ts=4
    1221             :  */

Generated by: LCOV version 1.10

Generated at Thu, 30 Oct 2014 07:41:41 +0000 (34 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.