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: 2015-04-14 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-2015 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             : 
     320             :         /*
     321             :          * Initialize an array that records the number of times a variable
     322             :          * is assigned to by the format string.  We use this to detect if
     323             :          * a variable is multiply assigned or left unassigned.
     324             :          */
     325        6322 :         if (numVars > nspace) {
     326           0 :                 nassign = (int*)safe_emalloc(sizeof(int), numVars, 0);
     327           0 :                 nspace = numVars;
     328             :         }
     329      107474 :         for (i = 0; i < nspace; i++) {
     330      101152 :                 nassign[i] = 0;
     331             :         }
     332             : 
     333        6322 :         xpgSize = objIndex = gotXpg = gotSequential = 0;
     334             : 
     335       20828 :         while (*format != '\0') {
     336        8670 :                 ch = format++;
     337        8670 :                 flags = 0;
     338             : 
     339        8670 :                 if (*ch != '%') {
     340        2284 :                         continue;
     341             :                 }
     342        6386 :                 ch = format++;
     343        6386 :                 if (*ch == '%') {
     344           0 :                         continue;
     345             :                 }
     346        6386 :                 if (*ch == '*') {
     347         479 :                         flags |= SCAN_SUPPRESS;
     348         479 :                         ch = format++;
     349         479 :                         goto xpgCheckDone;
     350             :                 }
     351             : 
     352        5907 :                 if ( isdigit( (int)*ch ) ) {
     353             :                         /*
     354             :                          * Check for an XPG3-style %n$ specification.  Note: there
     355             :                          * must not be a mixture of XPG3 specs and non-XPG3 specs
     356             :                          * in the same format string.
     357             :                          */
     358         970 :                         value = ZEND_STRTOUL(format-1, &end, 10);
     359         970 :                         if (*end != '$') {
     360         958 :                                 goto notXpg;
     361             :                         }
     362          12 :                         format = end+1;
     363          12 :                         ch     = format++;
     364          12 :                         gotXpg = 1;
     365          12 :                         if (gotSequential) {
     366           0 :                                 goto mixedXPG;
     367             :                         }
     368          12 :                         objIndex = value - 1;
     369          12 :                         if ((objIndex < 0) || (numVars && (objIndex >= numVars))) {
     370             :                                 goto badIndex;
     371          12 :                         } else if (numVars == 0) {
     372             :                                 /*
     373             :                                  * In the case where no vars are specified, the user can
     374             :                                  * specify %9999$ legally, so we have to consider special
     375             :                                  * rules for growing the assign array.  'value' is
     376             :                                  * guaranteed to be > 0.
     377             :                                  */
     378             : 
     379             :                                 /* set a lower artificial limit on this
     380             :                                  * in the interest of security and resource friendliness
     381             :                                  * 255 arguments should be more than enough. - cc
     382             :                                  */
     383           7 :                                 if (value > SCAN_MAX_ARGS) {
     384           0 :                                         goto badIndex;
     385             :                                 }
     386             : 
     387           7 :                                 xpgSize = (xpgSize > value) ? xpgSize : value;
     388             :                         }
     389          12 :                         goto xpgCheckDone;
     390             :                 }
     391             : 
     392             : notXpg:
     393        5895 :                 gotSequential = 1;
     394        5895 :                 if (gotXpg) {
     395             : mixedXPG:
     396           0 :                         php_error_docref(NULL, E_WARNING, "%s", "cannot mix \"%\" and \"%n$\" conversion specifiers");
     397           0 :                         goto error;
     398             :                 }
     399             : 
     400             : xpgCheckDone:
     401             :                 /*
     402             :                  * Parse any width specifier.
     403             :                  */
     404        6386 :                 if (isdigit(UCHAR(*ch))) {
     405         958 :                         value = ZEND_STRTOUL(format-1, &format, 10);
     406         958 :                         flags |= SCAN_WIDTH;
     407         958 :                         ch = format++;
     408             :                 }
     409             : 
     410             :                 /*
     411             :                  * Ignore size specifier.
     412             :                  */
     413        6386 :                 if ((*ch == 'l') || (*ch == 'L') || (*ch == 'h')) {
     414        1438 :                         ch = format++;
     415             :                 }
     416             : 
     417        6386 :                 if (!(flags & SCAN_SUPPRESS) && numVars && (objIndex >= numVars)) {
     418           2 :                         goto badIndex;
     419             :                 }
     420             : 
     421             :                 /*
     422             :                  * Handle the various field types.
     423             :                  */
     424        6384 :                 switch (*ch) {
     425             :                         case 'n':
     426             :                         case 'd':
     427             :                         case 'D':
     428             :                         case 'i':
     429             :                         case 'o':
     430             :                         case 'x':
     431             :                         case 'X':
     432             :                         case 'u':
     433             :                         case 'f':
     434             :                         case 'e':
     435             :                         case 'E':
     436             :                         case 'g':
     437             :                         case 's':
     438        4597 :                                 break;
     439             : 
     440             :                         case 'c':
     441             :                                 /* we differ here with the TCL implementation in allowing for */
     442             :                                 /* a character width specification, to be more consistent with */
     443             :                                 /* ANSI. since Zend auto allocates space for vars, this is no */
     444             :                                 /* problem - cc                                               */
     445             :                                 /*
     446             :                                 if (flags & SCAN_WIDTH) {
     447             :                                         php_error_docref(NULL, E_WARNING, "Field width may not be specified in %c conversion");
     448             :                                         goto error;
     449             :                                 }
     450             :                                 */
     451         822 :                                 break;
     452             : 
     453             :                         case '[':
     454         481 :                                 if (*format == '\0') {
     455           0 :                                         goto badSet;
     456             :                                 }
     457         481 :                                 ch = format++;
     458         481 :                                 if (*ch == '^') {
     459           2 :                                         if (*format == '\0') {
     460           0 :                                                 goto badSet;
     461             :                                         }
     462           2 :                                         ch = format++;
     463             :                                 }
     464         481 :                                 if (*ch == ']') {
     465           0 :                                         if (*format == '\0') {
     466           0 :                                                 goto badSet;
     467             :                                         }
     468           0 :                                         ch = format++;
     469             :                                 }
     470        3537 :                                 while (*ch != ']') {
     471        2575 :                                         if (*format == '\0') {
     472           0 :                                                 goto badSet;
     473             :                                         }
     474        2575 :                                         ch = format++;
     475             :                                 }
     476         481 :                                 break;
     477             : badSet:
     478           0 :                                 php_error_docref(NULL, E_WARNING, "Unmatched [ in format string");
     479           0 :                                 goto error;
     480             : 
     481             :                         default: {
     482         484 :                                 php_error_docref(NULL, E_WARNING, "Bad scan conversion character \"%c\"", *ch);
     483         484 :                                 goto error;
     484             :                         }
     485             :                 }
     486             : 
     487        5900 :                 if (!(flags & SCAN_SUPPRESS)) {
     488        5421 :                         if (objIndex >= nspace) {
     489             :                                 /*
     490             :                                  * Expand the nassign buffer.  If we are using XPG specifiers,
     491             :                                  * make sure that we grow to a large enough size.  xpgSize is
     492             :                                  * guaranteed to be at least one larger than objIndex.
     493             :                                  */
     494           0 :                                 value = nspace;
     495           0 :                                 if (xpgSize) {
     496           0 :                                         nspace = xpgSize;
     497             :                                 } else {
     498           0 :                                         nspace += STATIC_LIST_SIZE;
     499             :                                 }
     500           0 :                                 if (nassign == staticAssign) {
     501           0 :                                         nassign = (void *)safe_emalloc(nspace, sizeof(int), 0);
     502           0 :                                         for (i = 0; i < STATIC_LIST_SIZE; ++i) {
     503           0 :                                                 nassign[i] = staticAssign[i];
     504             :                                         }
     505             :                                 } else {
     506           0 :                                         nassign = (void *)erealloc((void *)nassign, nspace * sizeof(int));
     507             :                                 }
     508           0 :                                 for (i = value; i < nspace; i++) {
     509           0 :                                         nassign[i] = 0;
     510             :                                 }
     511             :                         }
     512        5421 :                         nassign[objIndex]++;
     513        5421 :                         objIndex++;
     514             :                 }
     515             :         } /* while (*format != '\0') */
     516             : 
     517             :         /*
     518             :          * Verify that all of the variable were assigned exactly once.
     519             :          */
     520        5836 :         if (numVars == 0) {
     521        5808 :                 if (xpgSize) {
     522           4 :                         numVars = xpgSize;
     523             :                 } else {
     524        5804 :                         numVars = objIndex;
     525             :                 }
     526             :         }
     527        5836 :         if (totalSubs) {
     528        5836 :                 *totalSubs = numVars;
     529             :         }
     530       11253 :         for (i = 0; i < numVars; i++) {
     531        5420 :                 if (nassign[i] > 1) {
     532           0 :                         php_error_docref(NULL, E_WARNING, "%s", "Variable is assigned by multiple \"%n$\" conversion specifiers");
     533           0 :                         goto error;
     534        5420 :                 } else if (!xpgSize && (nassign[i] == 0)) {
     535             :                         /*
     536             :                          * If the space is empty, and xpgSize is 0 (means XPG wasn't
     537             :                          * used, and/or numVars != 0), then too many vars were given
     538             :                          */
     539           3 :                         php_error_docref(NULL, E_WARNING, "Variable is not assigned by any conversion specifiers");
     540           3 :                         goto error;
     541             :                 }
     542             :         }
     543             : 
     544        5833 :         if (nassign != staticAssign) {
     545           0 :                 efree((char *)nassign);
     546             :         }
     547        5833 :         return SCAN_SUCCESS;
     548             : 
     549             : badIndex:
     550           2 :         if (gotXpg) {
     551           0 :                 php_error_docref(NULL, E_WARNING, "%s", "\"%n$\" argument index out of range");
     552             :         } else {
     553           2 :                 php_error_docref(NULL, E_WARNING, "Different numbers of variable names and field specifiers");
     554             :         }
     555             : 
     556             : error:
     557         489 :         if (nassign != staticAssign) {
     558           0 :                 efree((char *)nassign);
     559             :         }
     560         489 :         return SCAN_ERROR_INVALID_FORMAT;
     561             : #undef STATIC_LIST_SIZE
     562             : }
     563             : /* }}} */
     564             : 
     565             : /* {{{ php_sscanf_internal
     566             :  * This is the internal function which does processing on behalf of
     567             :  * both sscanf() and fscanf()
     568             :  *
     569             :  * parameters :
     570             :  *              string          literal string to be processed
     571             :  *              format          format string
     572             :  *              argCount        total number of elements in the args array
     573             :  *              args            arguments passed in from user function (f|s)scanf
     574             :  *              varStart        offset (in args) of 1st variable passed in to (f|s)scanf
     575             :  *              return_value set with the results of the scan
     576             :  */
     577             : 
     578        6322 : PHPAPI int php_sscanf_internal( char *string, char *format,
     579             :                                 int argCount, zval *args,
     580             :                                 int varStart, zval *return_value)
     581             : {
     582        6322 :         int  numVars, nconversions, totalVars = -1;
     583             :         int  i, result;
     584             :         zend_long value;
     585             :         int  objIndex;
     586             :         char *end, *baseString;
     587             :         zval *current;
     588        6322 :         char op   = 0;
     589        6322 :         int  base = 0;
     590        6322 :         int  underflow = 0;
     591             :         size_t width;
     592        6322 :         zend_long (*fn)() = NULL;
     593             :         char *ch, sch;
     594             :         int  flags;
     595             :         char buf[64];   /* Temporary buffer to hold scanned number
     596             :                                          * strings before they are passed to strtoul() */
     597             : 
     598             :         /* do some sanity checking */
     599        6322 :         if ((varStart > argCount) || (varStart < 0)){
     600           0 :                 varStart = SCAN_MAX_ARGS + 1;
     601             :         }
     602        6322 :         numVars = argCount - varStart;
     603        6322 :         if (numVars < 0) {
     604           0 :                 numVars = 0;
     605             :         }
     606             : 
     607             : #if 0
     608             :         zend_printf("<br>in sscanf_internal : <br> string is \"%s\", format = \"%s\"<br> NumVars = %d. VarStart = %d<br>-------------------------<br>",
     609             :                                         string, format, numVars, varStart);
     610             : #endif
     611             :         /*
     612             :          * Check for errors in the format string.
     613             :          */
     614        6322 :         if (ValidateFormat(format, numVars, &totalVars) != SCAN_SUCCESS) {
     615         489 :                 scan_set_error_return( numVars, return_value );
     616         489 :                 return SCAN_ERROR_INVALID_FORMAT;
     617             :         }
     618             : 
     619        5833 :         objIndex = numVars ? varStart : 0;
     620             : 
     621             :         /*
     622             :          * If any variables are passed, make sure they are all passed by reference
     623             :          */
     624        5833 :         if (numVars) {
     625          93 :                 for (i = varStart;i < argCount;i++){
     626         136 :                         if ( ! Z_ISREF(args[ i ] ) ) {
     627           0 :                                 php_error_docref(NULL, E_WARNING, "Parameter %d must be passed by reference", i);
     628           0 :                                 scan_set_error_return(numVars, return_value);
     629           0 :                                 return SCAN_ERROR_VAR_PASSED_BYVAL;
     630             :                         }
     631             :                 }
     632             :         }
     633             : 
     634             :         /*
     635             :          * Allocate space for the result objects. Only happens when no variables
     636             :          * are specified
     637             :          */
     638        5833 :         if (!numVars) {
     639             :                 zval tmp;
     640             : 
     641             :                 /* allocate an array for return */
     642        5808 :                 array_init(return_value);
     643             : 
     644       11154 :                 for (i = 0; i < totalVars; i++) {
     645        5346 :                         ZVAL_NULL(&tmp);
     646        5346 :                         if (add_next_index_zval(return_value, &tmp) == FAILURE) {
     647           0 :                                 scan_set_error_return(0, return_value);
     648           0 :                                 return FAILURE;
     649             :                         }
     650             :                 }
     651        5808 :                 varStart = 0; /* Array index starts from 0 */
     652             :         }
     653             : 
     654        5833 :         baseString = string;
     655             : 
     656             :         /*
     657             :          * Iterate over the format string filling in the result objects until
     658             :          * we reach the end of input, the end of the format string, or there
     659             :          * is a mismatch.
     660             :          */
     661        5833 :         nconversions = 0;
     662             :         /* note ! - we need to limit the loop for objIndex to keep it in bounds */
     663             : 
     664       17297 :         while (*format != '\0') {
     665        7912 :                 ch    = format++;
     666        7912 :                 flags = 0;
     667             : 
     668             :                 /*
     669             :                  * If we see whitespace in the format, skip whitespace in the string.
     670             :                  */
     671        7912 :                 if ( isspace( (int)*ch ) ) {
     672        1846 :                         sch = *string;
     673        4129 :                         while ( isspace( (int)sch ) ) {
     674         437 :                                 if (*string == '\0') {
     675           0 :                                         goto done;
     676             :                                 }
     677         437 :                                 string++;
     678         437 :                                 sch = *string;
     679             :                         }
     680        1846 :                         continue;
     681             :                 }
     682             : 
     683        6066 :                 if (*ch != '%') {
     684             : literal:
     685         180 :                         if (*string == '\0') {
     686           3 :                                 underflow = 1;
     687           3 :                                 goto done;
     688             :                         }
     689         177 :                         sch = *string;
     690         177 :                         string++;
     691         177 :                         if (*ch != sch) {
     692          13 :                                 goto done;
     693             :                         }
     694         164 :                         continue;
     695             :                 }
     696             : 
     697        5886 :                 ch = format++;
     698        5886 :                 if (*ch == '%') {
     699           0 :                         goto literal;
     700             :                 }
     701             : 
     702             :                 /*
     703             :                  * Check for assignment suppression ('*') or an XPG3-style
     704             :                  * assignment ('%n$').
     705             :                  */
     706        5886 :                 if (*ch == '*') {
     707         479 :                         flags |= SCAN_SUPPRESS;
     708         479 :                         ch = format++;
     709        5407 :                 } else if ( isdigit(UCHAR(*ch))) {
     710         969 :                         value = ZEND_STRTOUL(format-1, &end, 10);
     711         969 :                         if (*end == '$') {
     712          11 :                                 format = end+1;
     713          11 :                                 ch = format++;
     714          11 :                                 objIndex = varStart + value - 1;
     715             :                         }
     716             :                 }
     717             : 
     718             :                 /*
     719             :                  * Parse any width specifier.
     720             :                  */
     721        5886 :                 if ( isdigit(UCHAR(*ch))) {
     722         958 :                         width = ZEND_STRTOUL(format-1, &format, 10);
     723         958 :                         ch = format++;
     724             :                 } else {
     725        4928 :                         width = 0;
     726             :                 }
     727             : 
     728             :                 /*
     729             :                  * Ignore size specifier.
     730             :                  */
     731        5886 :                 if ((*ch == 'l') || (*ch == 'L') || (*ch == 'h')) {
     732        1437 :                         ch = format++;
     733             :                 }
     734             : 
     735             :                 /*
     736             :                  * Handle the various field types.
     737             :                  */
     738        5886 :                 switch (*ch) {
     739             :                         case 'n':
     740           2 :                                 if (!(flags & SCAN_SUPPRESS)) {
     741           2 :                                         if (numVars && objIndex >= argCount) {
     742             :                                                 break;
     743           2 :                                         } else if (numVars) {
     744           1 :                                                 current = Z_REFVAL(args[objIndex++]);
     745           1 :                                                 zval_ptr_dtor(current);
     746           1 :                                                 ZVAL_LONG(current, (zend_long)(string - baseString) );
     747             :                                         } else {
     748           1 :                                                 add_index_long(return_value, objIndex++, string - baseString);
     749             :                                         }
     750             :                                 }
     751           2 :                                 nconversions++;
     752           2 :                                 continue;
     753             : 
     754             :                         case 'd':
     755             :                         case 'D':
     756         606 :                                 op = 'i';
     757         606 :                                 base = 10;
     758         606 :                                 fn = (zend_long (*)())ZEND_STRTOL_PTR;
     759         606 :                                 break;
     760             :                         case 'i':
     761           0 :                                 op = 'i';
     762           0 :                                 base = 0;
     763           0 :                                 fn = (zend_long (*)())ZEND_STRTOL_PTR;
     764           0 :                                 break;
     765             :                         case 'o':
     766         770 :                                 op = 'i';
     767         770 :                                 base = 8;
     768         770 :                                 fn = (zend_long (*)())ZEND_STRTOL_PTR;
     769         770 :                                 break;
     770             :                         case 'x':
     771             :                         case 'X':
     772         421 :                                 op = 'i';
     773         421 :                                 base = 16;
     774         421 :                                 fn = (zend_long (*)())ZEND_STRTOL_PTR;
     775         421 :                                 break;
     776             :                         case 'u':
     777         399 :                                 op = 'i';
     778         399 :                                 base = 10;
     779         399 :                                 flags |= SCAN_UNSIGNED;
     780         399 :                                 fn = (zend_long (*)())ZEND_STRTOUL_PTR;
     781         399 :                                 break;
     782             : 
     783             :                         case 'f':
     784             :                         case 'e':
     785             :                         case 'E':
     786             :                         case 'g':
     787        1512 :                                 op = 'f';
     788        1512 :                                 break;
     789             : 
     790             :                         case 's':
     791         873 :                                 op = 's';
     792         873 :                                 break;
     793             : 
     794             :                         case 'c':
     795         822 :                                 op = 's';
     796         822 :                                 flags |= SCAN_NOSKIP;
     797             :                                 /*-cc-*/
     798         822 :                                 if (0 == width) {
     799         674 :                                         width = 1;
     800             :                                 }
     801             :                                 /*-cc-*/
     802         822 :                                 break;
     803             :                         case '[':
     804         481 :                                 op = '[';
     805         481 :                                 flags |= SCAN_NOSKIP;
     806             :                                 break;
     807             :                 }   /* switch */
     808             : 
     809             :                 /*
     810             :                  * At this point, we will need additional characters from the
     811             :                  * string to proceed.
     812             :                  */
     813        5884 :                 if (*string == '\0') {
     814         129 :                         underflow = 1;
     815         129 :                         goto done;
     816             :                 }
     817             : 
     818             :                 /*
     819             :                  * Skip any leading whitespace at the beginning of a field unless
     820             :                  * the format suppresses this behavior.
     821             :                  */
     822        5755 :                 if (!(flags & SCAN_NOSKIP)) {
     823        9218 :                         while (*string != '\0') {
     824        4489 :                                 sch = *string;
     825        4489 :                                 if (! isspace((int)sch) ) {
     826        4201 :                                         break;
     827             :                                 }
     828         288 :                                 string++;
     829             :                         }
     830        4465 :                         if (*string == '\0') {
     831         264 :                                 underflow = 1;
     832         264 :                                 goto done;
     833             :                         }
     834             :                 }
     835             : 
     836             :                 /*
     837             :                  * Perform the requested scanning operation.
     838             :                  */
     839        5491 :                 switch (op) {
     840             :                         case 'c':
     841             :                         case 's':
     842             :                                 /*
     843             :                                  * Scan a string up to width characters or whitespace.
     844             :                                  */
     845        1567 :                                 if (width == 0) {
     846         627 :                                         width = (size_t) ~0;
     847             :                                 }
     848        1567 :                                 end = string;
     849        7791 :                                 while (*end != '\0') {
     850        6203 :                                         sch = *end;
     851        6203 :                                         if ( isspace( (int)sch ) ) {
     852         810 :                                                 break;
     853             :                                         }
     854        5393 :                                         end++;
     855        5393 :                                         if (--width == 0) {
     856         736 :                                            break;
     857             :                                         }
     858             :                                 }
     859        1567 :                                 if (!(flags & SCAN_SUPPRESS)) {
     860        1428 :                                         if (numVars && objIndex >= argCount) {
     861             :                                                 break;
     862        1428 :                                         } else if (numVars) {
     863          21 :                                                 current = Z_REFVAL(args[objIndex++]);
     864          21 :                                                 zval_ptr_dtor(current);
     865          42 :                                                 ZVAL_STRINGL(current, string, end-string);
     866             :                                         } else {
     867        1407 :                                                 add_index_stringl(return_value, objIndex++, string, end-string);
     868             :                                         }
     869             :                                 }
     870        1567 :                                 string = end;
     871        1567 :                                 break;
     872             : 
     873             :                         case '[': {
     874             :                                 CharSet cset;
     875             : 
     876         480 :                                 if (width == 0) {
     877         480 :                                         width = (size_t) ~0;
     878             :                                 }
     879         480 :                                 end = string;
     880             : 
     881         480 :                                 format = BuildCharSet(&cset, format);
     882        1738 :                                 while (*end != '\0') {
     883        1256 :                                         sch = *end;
     884        1256 :                                         if (!CharInSet(&cset, (int)sch)) {
     885         478 :                                                 break;
     886             :                                         }
     887         778 :                                         end++;
     888         778 :                                         if (--width == 0) {
     889           0 :                                                 break;
     890             :                                         }
     891             :                                 }
     892         480 :                                 ReleaseCharSet(&cset);
     893             : 
     894         480 :                                 if (string == end) {
     895             :                                         /*
     896             :                                          * Nothing matched the range, stop processing
     897             :                                          */
     898         287 :                                         goto done;
     899             :                                 }
     900         193 :                                 if (!(flags & SCAN_SUPPRESS)) {
     901         193 :                                         if (numVars && objIndex >= argCount) {
     902             :                                                 break;
     903         193 :                                         } else if (numVars) {
     904           2 :                                                 current = Z_REFVAL(args[objIndex++]);
     905           2 :                                                 zval_ptr_dtor(current);
     906           4 :                                                 ZVAL_STRINGL(current, string, end-string);
     907             :                                         } else {
     908         191 :                                                 add_index_stringl(return_value, objIndex++, string, end-string);
     909             :                                         }
     910             :                                 }
     911         193 :                                 string = end;
     912         193 :                                 break;
     913             :                         }
     914             : /*
     915             :                         case 'c':
     916             :                            / Scan a single character./
     917             : 
     918             :                                 sch = *string;
     919             :                                 string++;
     920             :                                 if (!(flags & SCAN_SUPPRESS)) {
     921             :                                         if (numVars) {
     922             :                                                 char __buf[2];
     923             :                                                 __buf[0] = sch;
     924             :                                                 __buf[1] = '\0';;
     925             :                                                 current = args[objIndex++];
     926             :                                                 zval_dtor(*current);
     927             :                                                 ZVAL_STRINGL( *current, __buf, 1);
     928             :                                         } else {
     929             :                                                 add_index_stringl(return_value, objIndex++, &sch, 1);
     930             :                                         }
     931             :                                 }
     932             :                                 break;
     933             : */
     934             :                         case 'i':
     935             :                                 /*
     936             :                                  * Scan an unsigned or signed integer.
     937             :                                  */
     938             :                                 /*-cc-*/
     939        2020 :                                 buf[0] = '\0';
     940             :                                 /*-cc-*/
     941        2020 :                                 if ((width == 0) || (width > sizeof(buf) - 1)) {
     942        1662 :                                         width = sizeof(buf) - 1;
     943             :                                 }
     944             : 
     945        2020 :                                 flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO;
     946        5422 :                                 for (end = buf; width > 0; width--) {
     947        5389 :                                         switch (*string) {
     948             :                                                 /*
     949             :                                                  * The 0 digit has special meaning at the beginning of
     950             :                                                  * a number.  If we are unsure of the base, it
     951             :                                                  * indicates that we are in base 8 or base 16 (if it is
     952             :                                                  * followed by an 'x').
     953             :                                                  */
     954             :                                                 case '0':
     955             :                                                         /*-cc-*/
     956         555 :                                                         if (base == 16) {
     957          26 :                                                                 flags |= SCAN_XOK;
     958             :                                                         }
     959             :                                                         /*-cc-*/
     960         555 :                                                         if (base == 0) {
     961           0 :                                                                 base = 8;
     962           0 :                                                                 flags |= SCAN_XOK;
     963             :                                                         }
     964         555 :                                                         if (flags & SCAN_NOZERO) {
     965         266 :                                                                 flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO);
     966             :                                                         } else {
     967         289 :                                                                 flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
     968             :                                                         }
     969         555 :                                                         goto addToInt;
     970             : 
     971             :                                                 case '1': case '2': case '3': case '4':
     972             :                                                 case '5': case '6': case '7':
     973        2299 :                                                         if (base == 0) {
     974           0 :                                                                 base = 10;
     975             :                                                         }
     976        2299 :                                                         flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
     977        2299 :                                                         goto addToInt;
     978             : 
     979             :                                                 case '8': case '9':
     980         357 :                                                         if (base == 0) {
     981           0 :                                                                 base = 10;
     982             :                                                         }
     983         357 :                                                         if (base <= 8) {
     984         187 :                                                            break;
     985             :                                                         }
     986         170 :                                                         flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
     987         170 :                                                         goto addToInt;
     988             : 
     989             :                                                 case 'A': case 'B': case 'C':
     990             :                                                 case 'D': case 'E': case 'F':
     991             :                                                 case 'a': case 'b': case 'c':
     992             :                                                 case 'd': case 'e': case 'f':
     993         663 :                                                         if (base <= 10) {
     994         463 :                                                                 break;
     995             :                                                         }
     996         200 :                                                         flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
     997         200 :                                                         goto addToInt;
     998             : 
     999             :                                                 case '+': case '-':
    1000         184 :                                                         if (flags & SCAN_SIGNOK) {
    1001         184 :                                                                 flags &= ~SCAN_SIGNOK;
    1002         184 :                                                                 goto addToInt;
    1003             :                                                         }
    1004           0 :                                                         break;
    1005             : 
    1006             :                                                 case 'x': case 'X':
    1007           0 :                                                         if ((flags & SCAN_XOK) && (end == buf+1)) {
    1008           0 :                                                                 base = 16;
    1009           0 :                                                                 flags &= ~SCAN_XOK;
    1010           0 :                                                                 goto addToInt;
    1011             :                                                         }
    1012             :                                                         break;
    1013             :                                         }
    1014             : 
    1015             :                                         /*
    1016             :                                          * We got an illegal character so we are done accumulating.
    1017             :                                          */
    1018        1981 :                                         break;
    1019             : 
    1020             : addToInt:
    1021             :                                         /*
    1022             :                                          * Add the character to the temporary buffer.
    1023             :                                          */
    1024        3408 :                                         *end++ = *string++;
    1025        3408 :                                         if (*string == '\0') {
    1026           6 :                                                 break;
    1027             :                                         }
    1028             :                                 }
    1029             : 
    1030             :                                 /*
    1031             :                                  * Check to see if we need to back up because we only got a
    1032             :                                  * sign or a trailing x after a 0.
    1033             :                                  */
    1034        2020 :                                 if (flags & SCAN_NODIGITS) {
    1035        1011 :                                         if (*string == '\0') {
    1036           0 :                                                 underflow = 1;
    1037             :                                         }
    1038        1011 :                                         goto done;
    1039        1009 :                                 } else if (end[-1] == 'x' || end[-1] == 'X') {
    1040           0 :                                         end--;
    1041           0 :                                         string--;
    1042             :                                 }
    1043             : 
    1044             :                                 /*
    1045             :                                  * Scan the value from the temporary buffer.  If we are
    1046             :                                  * returning a large unsigned value, we have to convert it back
    1047             :                                  * to a string since PHP only supports signed values.
    1048             :                                  */
    1049        1009 :                                 if (!(flags & SCAN_SUPPRESS)) {
    1050         921 :                                         *end = '\0';
    1051         921 :                                         value = (zend_long) (*fn)(buf, NULL, base);
    1052         922 :                                         if ((flags & SCAN_UNSIGNED) && (value < 0)) {
    1053           1 :                                                 snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, value); /* INTL: ISO digit */
    1054           1 :                                                 if (numVars && objIndex >= argCount) {
    1055             :                                                         break;
    1056           1 :                                                 } else if (numVars) {
    1057             :                                                   /* change passed value type to string */
    1058           1 :                                                         current = Z_REFVAL(args[objIndex++]);
    1059           1 :                                                         zval_ptr_dtor(current);
    1060           2 :                                                         ZVAL_STRING(current, buf);
    1061             :                                                 } else {
    1062           0 :                                                         add_index_string(return_value, objIndex++, buf);
    1063             :                                                 }
    1064             :                                         } else {
    1065         920 :                                                 if (numVars && objIndex >= argCount) {
    1066             :                                                         break;
    1067         920 :                                                 } else if (numVars) {
    1068          22 :                                                         current = Z_REFVAL(args[objIndex++]);
    1069          22 :                                                         zval_ptr_dtor(current);
    1070          22 :                                                         ZVAL_LONG(current, value);
    1071             :                                                 } else {
    1072         898 :                                                         add_index_long(return_value, objIndex++, value);
    1073             :                                                 }
    1074             :                                         }
    1075             :                                 }
    1076        1009 :                                 break;
    1077             : 
    1078             :                         case 'f':
    1079             :                                 /*
    1080             :                                  * Scan a floating point number
    1081             :                                  */
    1082        1424 :                                 buf[0] = '\0';     /* call me pedantic */
    1083        1424 :                                 if ((width == 0) || (width > sizeof(buf) - 1)) {
    1084        1170 :                                         width = sizeof(buf) - 1;
    1085             :                                 }
    1086        1424 :                                 flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_PTOK | SCAN_EXPOK;
    1087        6425 :                                 for (end = buf; width > 0; width--) {
    1088        6373 :                                         switch (*string) {
    1089             :                                                 case '0': case '1': case '2': case '3':
    1090             :                                                 case '4': case '5': case '6': case '7':
    1091             :                                                 case '8': case '9':
    1092        4356 :                                                         flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS);
    1093        4356 :                                                         goto addToFloat;
    1094             :                                                 case '+':
    1095             :                                                 case '-':
    1096         379 :                                                         if (flags & SCAN_SIGNOK) {
    1097         379 :                                                                 flags &= ~SCAN_SIGNOK;
    1098         379 :                                                                 goto addToFloat;
    1099             :                                                         }
    1100           0 :                                                         break;
    1101             :                                                 case '.':
    1102         156 :                                                         if (flags & SCAN_PTOK) {
    1103         156 :                                                                 flags &= ~(SCAN_SIGNOK | SCAN_PTOK);
    1104         156 :                                                                 goto addToFloat;
    1105             :                                                         }
    1106           0 :                                                         break;
    1107             :                                                 case 'e':
    1108             :                                                 case 'E':
    1109             :                                                         /*
    1110             :                                                          * An exponent is not allowed until there has
    1111             :                                                          * been at least one digit.
    1112             :                                                          */
    1113         117 :                                                         if ((flags & (SCAN_NODIGITS | SCAN_EXPOK)) == SCAN_EXPOK) {
    1114         117 :                                                                 flags = (flags & ~(SCAN_EXPOK|SCAN_PTOK))
    1115             :                                                                         | SCAN_SIGNOK | SCAN_NODIGITS;
    1116         117 :                                                                 goto addToFloat;
    1117             :                                                         }
    1118             :                                                         break;
    1119             :                                         }
    1120             : 
    1121             :                                         /*
    1122             :                                          * We got an illegal character so we are done accumulating.
    1123             :                                          */
    1124        1365 :                                         break;
    1125             : 
    1126             : addToFloat:
    1127             :                                         /*
    1128             :                                          * Add the character to the temporary buffer.
    1129             :                                          */
    1130        5008 :                                         *end++ = *string++;
    1131        5008 :                                         if (*string == '\0') {
    1132           7 :                                                 break;
    1133             :                                         }
    1134             :                                 }
    1135             : 
    1136             :                                 /*
    1137             :                                  * Check to see if we need to back up because we saw a
    1138             :                                  * trailing 'e' or sign.
    1139             :                                  */
    1140        1424 :                                 if (flags & SCAN_NODIGITS) {
    1141         579 :                                         if (flags & SCAN_EXPOK) {
    1142             :                                                 /*
    1143             :                                                  * There were no digits at all so scanning has
    1144             :                                                  * failed and we are done.
    1145             :                                                  */
    1146         574 :                                                 if (*string == '\0') {
    1147           0 :                                                         underflow = 1;
    1148             :                                                 }
    1149         574 :                                                 goto done;
    1150             :                                         }
    1151             : 
    1152             :                                         /*
    1153             :                                          * We got a bad exponent ('e' and maybe a sign).
    1154             :                                          */
    1155           5 :                                         end--;
    1156           5 :                                         string--;
    1157           5 :                                         if (*end != 'e' && *end != 'E') {
    1158           0 :                                                 end--;
    1159           0 :                                                 string--;
    1160             :                                         }
    1161             :                                 }
    1162             : 
    1163             :                                 /*
    1164             :                                  * Scan the value from the temporary buffer.
    1165             :                                  */
    1166         850 :                                 if (!(flags & SCAN_SUPPRESS)) {
    1167             :                                         double dvalue;
    1168         775 :                                         *end = '\0';
    1169         775 :                                         dvalue = zend_strtod(buf, NULL);
    1170         775 :                                         if (numVars && objIndex >= argCount) {
    1171             :                                                 break;
    1172         775 :                                         } else if (numVars) {
    1173          14 :                                                 current = Z_REFVAL(args[objIndex++]);
    1174          14 :                                                 zval_ptr_dtor(current);
    1175          14 :                                                 ZVAL_DOUBLE(current, dvalue);
    1176             :                                         } else {
    1177         761 :                                                 add_index_double(return_value, objIndex++, dvalue );
    1178             :                                         }
    1179             :                                 }
    1180             :                                 break;
    1181             :                 } /* switch (op) */
    1182        3619 :                 nconversions++;
    1183             :         } /*  while (*format != '\0') */
    1184             : 
    1185             : done:
    1186        5833 :         result = SCAN_SUCCESS;
    1187             : 
    1188        6226 :         if (underflow && (0==nconversions)) {
    1189         393 :                 scan_set_error_return( numVars, return_value );
    1190         393 :                 result = SCAN_ERROR_EOF;
    1191        5440 :         } else if (numVars) {
    1192          25 :                 convert_to_long(return_value );
    1193          25 :                 Z_LVAL_P(return_value) = nconversions;
    1194        5415 :         } else if (nconversions < totalVars) {
    1195             :                 /* TODO: not all elements converted. we need to prune the list - cc */
    1196             :         }
    1197        5833 :         return result;
    1198             : }
    1199             : /* }}} */
    1200             : 
    1201             : /* the compiler choked when i tried to make this a macro    */
    1202         882 : static inline void scan_set_error_return(int numVars, zval *return_value) /* {{{ */
    1203             : {
    1204         882 :         if (numVars) {
    1205           6 :                 ZVAL_LONG(return_value, SCAN_ERROR_EOF);  /* EOF marker */
    1206             :         } else {
    1207             :                 /* convert_to_null calls destructor */
    1208         876 :                 convert_to_null(return_value);
    1209             :         }
    1210         882 : }
    1211             : /* }}} */
    1212             : 
    1213             : /*
    1214             :  * Local variables:
    1215             :  * tab-width: 4
    1216             :  * c-basic-offset: 4
    1217             :  * End:
    1218             :  * vim600: sw=4 ts=4 fdm=marker
    1219             :  * vim<600: sw=4 ts=4
    1220             :  */

Generated by: LCOV version 1.10

Generated at Tue, 14 Apr 2015 11:48:52 +0000 (5 days ago)

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