Annotation of embedaddon/php/ext/standard/scanf.c, revision 1.1

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-2012 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: scanf.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            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: static char * BuildCharSet(CharSet *cset, char *format)
        !           142: {
        !           143:        char *ch, start;
        !           144:        int  nranges;
        !           145:        char *end;
        !           146: 
        !           147:        memset(cset, 0, sizeof(CharSet));
        !           148: 
        !           149:        ch = format;
        !           150:        if (*ch == '^') {
        !           151:                cset->exclude = 1;
        !           152:                ch = ++format;
        !           153:        }
        !           154:        end = format + 1;       /* verify this - cc */
        !           155: 
        !           156:        /*
        !           157:         * Find the close bracket so we can overallocate the set.
        !           158:         */
        !           159:        if (*ch == ']') {
        !           160:                ch = end++;
        !           161:        }
        !           162:        nranges = 0;
        !           163:        while (*ch != ']') {
        !           164:                if (*ch == '-') {
        !           165:                        nranges++;
        !           166:                }
        !           167:                ch = end++;
        !           168:        }
        !           169: 
        !           170:        cset->chars = (char *) safe_emalloc(sizeof(char), (end - format - 1), 0);
        !           171:        if (nranges > 0) {
        !           172:                cset->ranges = (struct Range *) safe_emalloc(sizeof(struct Range), nranges, 0);
        !           173:        } else {
        !           174:                cset->ranges = NULL;
        !           175:        }
        !           176: 
        !           177:        /*
        !           178:         * Now build the character set.
        !           179:         */
        !           180:        cset->nchars = cset->nranges = 0;
        !           181:        ch    = format++;
        !           182:        start = *ch;
        !           183:        if (*ch == ']' || *ch == '-') {
        !           184:                cset->chars[cset->nchars++] = *ch;
        !           185:                ch = format++;
        !           186:        }
        !           187:        while (*ch != ']') {
        !           188:                if (*format == '-') {
        !           189:                        /*
        !           190:                         * This may be the first character of a range, so don't add
        !           191:                         * it yet.
        !           192:                         */
        !           193:                        start = *ch;
        !           194:                } 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:                        if (*format == ']') {
        !           201:                                cset->chars[cset->nchars++] = start;
        !           202:                                cset->chars[cset->nchars++] = *ch;
        !           203:                        } else {
        !           204:                                ch = format++;
        !           205: 
        !           206:                                /*
        !           207:                                 * Check to see if the range is in reverse order.
        !           208:                                 */
        !           209:                                if (start < *ch) {
        !           210:                                        cset->ranges[cset->nranges].start = start;
        !           211:                                        cset->ranges[cset->nranges].end = *ch;
        !           212:                                } else {
        !           213:                                        cset->ranges[cset->nranges].start = *ch;
        !           214:                                        cset->ranges[cset->nranges].end = start;
        !           215:                                }
        !           216:                                cset->nranges++;
        !           217:                        }
        !           218:                } else {
        !           219:                        cset->chars[cset->nchars++] = *ch;
        !           220:                }
        !           221:                ch = format++;
        !           222:        }
        !           223:        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: static int CharInSet(CharSet *cset, int c)
        !           243: {
        !           244:        char ch = (char) c;
        !           245:        int i, match = 0;
        !           246: 
        !           247:        for (i = 0; i < cset->nchars; i++) {
        !           248:                if (cset->chars[i] == ch) {
        !           249:                        match = 1;
        !           250:                        break;
        !           251:                }
        !           252:        }
        !           253:        if (!match) {
        !           254:                for (i = 0; i < cset->nranges; i++) {
        !           255:                        if ((cset->ranges[i].start <= ch)
        !           256:                                && (ch <= cset->ranges[i].end)) {
        !           257:                                match = 1;
        !           258:                                break;
        !           259:                        }
        !           260:                }
        !           261:        }
        !           262:        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: static void ReleaseCharSet(CharSet *cset)
        !           282: {
        !           283:        efree((char *)cset->chars);
        !           284:        if (cset->ranges) {
        !           285:                efree((char *)cset->ranges);
        !           286:        }
        !           287: }
        !           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: PHPAPI int ValidateFormat(char *format, int numVars, int *totalSubs)
        !           312: {
        !           313: #define STATIC_LIST_SIZE 16
        !           314:        int gotXpg, gotSequential, value, i, flags;
        !           315:        char *end, *ch = NULL;
        !           316:        int staticAssign[STATIC_LIST_SIZE];
        !           317:        int *nassign = staticAssign;
        !           318:        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:        if (numVars > nspace) {
        !           327:                nassign = (int*)safe_emalloc(sizeof(int), numVars, 0);
        !           328:                nspace = numVars;
        !           329:        }
        !           330:        for (i = 0; i < nspace; i++) {
        !           331:                nassign[i] = 0;
        !           332:        }
        !           333: 
        !           334:        xpgSize = objIndex = gotXpg = gotSequential = 0;
        !           335: 
        !           336:        while (*format != '\0') {
        !           337:                ch = format++;
        !           338:                flags = 0;
        !           339: 
        !           340:                if (*ch != '%') {
        !           341:                        continue;
        !           342:                }
        !           343:                ch = format++;
        !           344:                if (*ch == '%') {
        !           345:                        continue;
        !           346:                }
        !           347:                if (*ch == '*') {
        !           348:                        flags |= SCAN_SUPPRESS;
        !           349:                        ch = format++;
        !           350:                        goto xpgCheckDone;
        !           351:                }
        !           352: 
        !           353:                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:                        value = strtoul(format-1, &end, 10);
        !           360:                        if (*end != '$') {
        !           361:                                goto notXpg;
        !           362:                        }
        !           363:                        format = end+1;
        !           364:                        ch     = format++;
        !           365:                        gotXpg = 1;
        !           366:                        if (gotSequential) {
        !           367:                                goto mixedXPG;
        !           368:                        }
        !           369:                        objIndex = value - 1;
        !           370:                        if ((objIndex < 0) || (numVars && (objIndex >= numVars))) {
        !           371:                                goto badIndex;
        !           372:                        } 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:                                if (value > SCAN_MAX_ARGS) {
        !           385:                                        goto badIndex;
        !           386:                                }
        !           387: 
        !           388:                                xpgSize = (xpgSize > value) ? xpgSize : value;
        !           389:                        }
        !           390:                        goto xpgCheckDone;
        !           391:                }
        !           392: 
        !           393: notXpg:
        !           394:                gotSequential = 1;
        !           395:                if (gotXpg) {
        !           396: mixedXPG:
        !           397:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", "cannot mix \"%\" and \"%n$\" conversion specifiers");
        !           398:                        goto error;
        !           399:                }
        !           400: 
        !           401: xpgCheckDone:
        !           402:                /*
        !           403:                 * Parse any width specifier.
        !           404:                 */
        !           405:                if (isdigit(UCHAR(*ch))) {
        !           406:                        value = strtoul(format-1, &format, 10);
        !           407:                        flags |= SCAN_WIDTH;
        !           408:                        ch = format++;
        !           409:                }
        !           410: 
        !           411:                /*
        !           412:                 * Ignore size specifier.
        !           413:                 */
        !           414:                if ((*ch == 'l') || (*ch == 'L') || (*ch == 'h')) {
        !           415:                        ch = format++;
        !           416:                }
        !           417: 
        !           418:                if (!(flags & SCAN_SUPPRESS) && numVars && (objIndex >= numVars)) {
        !           419:                        goto badIndex;
        !           420:                }
        !           421: 
        !           422:                /*
        !           423:                 * Handle the various field types.
        !           424:                 */
        !           425:                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:                                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:                                break;
        !           453: 
        !           454:                        case '[':
        !           455:                                if (*format == '\0') {
        !           456:                                        goto badSet;
        !           457:                                }
        !           458:                                ch = format++;
        !           459:                                if (*ch == '^') {
        !           460:                                        if (*format == '\0') {
        !           461:                                                goto badSet;
        !           462:                                        }
        !           463:                                        ch = format++;
        !           464:                                }
        !           465:                                if (*ch == ']') {
        !           466:                                        if (*format == '\0') {
        !           467:                                                goto badSet;
        !           468:                                        }
        !           469:                                        ch = format++;
        !           470:                                }
        !           471:                                while (*ch != ']') {
        !           472:                                        if (*format == '\0') {
        !           473:                                                goto badSet;
        !           474:                                        }
        !           475:                                        ch = format++;
        !           476:                                }
        !           477:                                break;
        !           478: badSet:
        !           479:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unmatched [ in format string");
        !           480:                                goto error;
        !           481: 
        !           482:                        default: {
        !           483:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad scan conversion character \"%c\"", *ch);
        !           484:                                goto error;
        !           485:                        }
        !           486:                }
        !           487: 
        !           488:                if (!(flags & SCAN_SUPPRESS)) {
        !           489:                        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:                                value = nspace;
        !           496:                                if (xpgSize) {
        !           497:                                        nspace = xpgSize;
        !           498:                                } else {
        !           499:                                        nspace += STATIC_LIST_SIZE;
        !           500:                                }
        !           501:                                if (nassign == staticAssign) {
        !           502:                                        nassign = (void *)safe_emalloc(nspace, sizeof(int), 0);
        !           503:                                        for (i = 0; i < STATIC_LIST_SIZE; ++i) {
        !           504:                                                nassign[i] = staticAssign[i];
        !           505:                                        }
        !           506:                                } else {
        !           507:                                        nassign = (void *)erealloc((void *)nassign, nspace * sizeof(int));
        !           508:                                }
        !           509:                                for (i = value; i < nspace; i++) {
        !           510:                                        nassign[i] = 0;
        !           511:                                }
        !           512:                        }
        !           513:                        nassign[objIndex]++;
        !           514:                        objIndex++;
        !           515:                }
        !           516:        } /* while (*format != '\0') */
        !           517: 
        !           518:        /*
        !           519:         * Verify that all of the variable were assigned exactly once.
        !           520:         */
        !           521:        if (numVars == 0) {
        !           522:                if (xpgSize) {
        !           523:                        numVars = xpgSize;
        !           524:                } else {
        !           525:                        numVars = objIndex;
        !           526:                }
        !           527:        }
        !           528:        if (totalSubs) {
        !           529:                *totalSubs = numVars;
        !           530:        }
        !           531:        for (i = 0; i < numVars; i++) {
        !           532:                if (nassign[i] > 1) {
        !           533:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", "Variable is assigned by multiple \"%n$\" conversion specifiers");
        !           534:                        goto error;
        !           535:                } 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:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Variable is not assigned by any conversion specifiers");
        !           541:                        goto error;
        !           542:                }
        !           543:        }
        !           544: 
        !           545:        if (nassign != staticAssign) {
        !           546:                efree((char *)nassign);
        !           547:        }
        !           548:        return SCAN_SUCCESS;
        !           549: 
        !           550: badIndex:
        !           551:        if (gotXpg) {
        !           552:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", "\"%n$\" argument index out of range");
        !           553:        } else {
        !           554:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Different numbers of variable names and field specifiers");
        !           555:        }
        !           556: 
        !           557: error:
        !           558:        if (nassign != staticAssign) {
        !           559:                efree((char *)nassign);
        !           560:        }
        !           561:        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: PHPAPI int php_sscanf_internal( char *string, char *format,
        !           580:                                int argCount, zval ***args,
        !           581:                                int varStart, zval **return_value TSRMLS_DC)
        !           582: {
        !           583:        int  numVars, nconversions, totalVars = -1;
        !           584:        int  i, result;
        !           585:        long value;
        !           586:        int  objIndex;
        !           587:        char *end, *baseString;
        !           588:        zval **current;
        !           589:        char op   = 0;
        !           590:        int  base = 0;
        !           591:        int  underflow = 0;
        !           592:        size_t width;
        !           593:        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:        if ((varStart > argCount) || (varStart < 0)){
        !           601:                varStart = SCAN_MAX_ARGS + 1;
        !           602:        }
        !           603:        numVars = argCount - varStart;
        !           604:        if (numVars < 0) {
        !           605:                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:        if (ValidateFormat(format, numVars, &totalVars) != SCAN_SUCCESS) {
        !           616:                scan_set_error_return( numVars, return_value );
        !           617:                return SCAN_ERROR_INVALID_FORMAT;
        !           618:        }
        !           619: 
        !           620:        objIndex = numVars ? varStart : 0;
        !           621: 
        !           622:        /*
        !           623:         * If any variables are passed, make sure they are all passed by reference
        !           624:         */
        !           625:        if (numVars) {
        !           626:                for (i = varStart;i < argCount;i++){
        !           627:                        if ( ! PZVAL_IS_REF( *args[ i ] ) ) {
        !           628:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Parameter %d must be passed by reference", i);
        !           629:                                scan_set_error_return(numVars, return_value);
        !           630:                                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:        if (!numVars) {
        !           640:                zval *tmp;
        !           641: 
        !           642:                /* allocate an array for return */
        !           643:                array_init(*return_value);
        !           644: 
        !           645:                for (i = 0; i < totalVars; i++) {
        !           646:                        MAKE_STD_ZVAL(tmp);
        !           647:                        ZVAL_NULL(tmp);
        !           648:                        if (add_next_index_zval(*return_value, tmp) == FAILURE) {
        !           649:                                scan_set_error_return(0, return_value);
        !           650:                                return FAILURE;
        !           651:                        }
        !           652:                }
        !           653:                varStart = 0; /* Array index starts from 0 */
        !           654:        }
        !           655: 
        !           656:        baseString = string;
        !           657: 
        !           658:        /*
        !           659:         * Iterate over the format string filling in the result objects until
        !           660:         * we reach the end of input, the end of the format string, or there
        !           661:         * is a mismatch.
        !           662:         */
        !           663:        nconversions = 0;
        !           664:        /* note ! - we need to limit the loop for objIndex to keep it in bounds */
        !           665: 
        !           666:        while (*format != '\0') {
        !           667:                ch    = format++;
        !           668:                flags = 0;
        !           669: 
        !           670:                /*
        !           671:                 * If we see whitespace in the format, skip whitespace in the string.
        !           672:                 */
        !           673:                if ( isspace( (int)*ch ) ) {
        !           674:                        sch = *string;
        !           675:                        while ( isspace( (int)sch ) ) {
        !           676:                                if (*string == '\0') {
        !           677:                                        goto done;
        !           678:                                }
        !           679:                                string++;
        !           680:                                sch = *string;
        !           681:                        }
        !           682:                        continue;
        !           683:                }
        !           684: 
        !           685:                if (*ch != '%') {
        !           686: literal:
        !           687:                        if (*string == '\0') {
        !           688:                                underflow = 1;
        !           689:                                goto done;
        !           690:                        }
        !           691:                        sch = *string;
        !           692:                        string++;
        !           693:                        if (*ch != sch) {
        !           694:                                goto done;
        !           695:                        }
        !           696:                        continue;
        !           697:                }
        !           698: 
        !           699:                ch = format++;
        !           700:                if (*ch == '%') {
        !           701:                        goto literal;
        !           702:                }
        !           703: 
        !           704:                /*
        !           705:                 * Check for assignment suppression ('*') or an XPG3-style
        !           706:                 * assignment ('%n$').
        !           707:                 */
        !           708:                if (*ch == '*') {
        !           709:                        flags |= SCAN_SUPPRESS;
        !           710:                        ch = format++;
        !           711:                } else if ( isdigit(UCHAR(*ch))) {
        !           712:                        value = strtoul(format-1, &end, 10);
        !           713:                        if (*end == '$') {
        !           714:                                format = end+1;
        !           715:                                ch = format++;
        !           716:                                objIndex = varStart + value - 1;
        !           717:                        }
        !           718:                }
        !           719: 
        !           720:                /*
        !           721:                 * Parse any width specifier.
        !           722:                 */
        !           723:                if ( isdigit(UCHAR(*ch))) {
        !           724:                        width = strtoul(format-1, &format, 10);
        !           725:                        ch = format++;
        !           726:                } else {
        !           727:                        width = 0;
        !           728:                }
        !           729: 
        !           730:                /*
        !           731:                 * Ignore size specifier.
        !           732:                 */
        !           733:                if ((*ch == 'l') || (*ch == 'L') || (*ch == 'h')) {
        !           734:                        ch = format++;
        !           735:                }
        !           736: 
        !           737:                /*
        !           738:                 * Handle the various field types.
        !           739:                 */
        !           740:                switch (*ch) {
        !           741:                        case 'n':
        !           742:                                if (!(flags & SCAN_SUPPRESS)) {
        !           743:                                        if (numVars && objIndex >= argCount) {
        !           744:                                                break;
        !           745:                                        } else if (numVars) {
        !           746:                                                zend_uint refcount;
        !           747: 
        !           748:                                                current = args[objIndex++];
        !           749:                                                refcount = Z_REFCOUNT_PP(current);
        !           750:                                                zval_dtor( *current );
        !           751:                                                ZVAL_LONG( *current, (long)(string - baseString) );
        !           752:                                                Z_SET_REFCOUNT_PP(current, refcount);
        !           753:                                                Z_SET_ISREF_PP(current);
        !           754:                                        } else {
        !           755:                                                add_index_long(*return_value, objIndex++, string - baseString);
        !           756:                                        }
        !           757:                                }
        !           758:                                nconversions++;
        !           759:                                continue;
        !           760: 
        !           761:                        case 'd':
        !           762:                        case 'D':
        !           763:                                op = 'i';
        !           764:                                base = 10;
        !           765:                                fn = (long (*)())strtol;
        !           766:                                break;
        !           767:                        case 'i':
        !           768:                                op = 'i';
        !           769:                                base = 0;
        !           770:                                fn = (long (*)())strtol;
        !           771:                                break;
        !           772:                        case 'o':
        !           773:                                op = 'i';
        !           774:                                base = 8;
        !           775:                                fn = (long (*)())strtol;
        !           776:                                break;
        !           777:                        case 'x':
        !           778:                        case 'X':
        !           779:                                op = 'i';
        !           780:                                base = 16;
        !           781:                                fn = (long (*)())strtol;
        !           782:                                break;
        !           783:                        case 'u':
        !           784:                                op = 'i';
        !           785:                                base = 10;
        !           786:                                flags |= SCAN_UNSIGNED;
        !           787:                                fn = (long (*)())strtoul;
        !           788:                                break;
        !           789: 
        !           790:                        case 'f':
        !           791:                        case 'e':
        !           792:                        case 'E':
        !           793:                        case 'g':
        !           794:                                op = 'f';
        !           795:                                break;
        !           796: 
        !           797:                        case 's':
        !           798:                                op = 's';
        !           799:                                break;
        !           800: 
        !           801:                        case 'c':
        !           802:                                op = 's';
        !           803:                                flags |= SCAN_NOSKIP;
        !           804:                                /*-cc-*/
        !           805:                                if (0 == width) {
        !           806:                                        width = 1;
        !           807:                                }
        !           808:                                /*-cc-*/
        !           809:                                break;
        !           810:                        case '[':
        !           811:                                op = '[';
        !           812:                                flags |= SCAN_NOSKIP;
        !           813:                                break;
        !           814:                }   /* switch */
        !           815: 
        !           816:                /*
        !           817:                 * At this point, we will need additional characters from the
        !           818:                 * string to proceed.
        !           819:                 */
        !           820:                if (*string == '\0') {
        !           821:                        underflow = 1;
        !           822:                        goto done;
        !           823:                }
        !           824: 
        !           825:                /*
        !           826:                 * Skip any leading whitespace at the beginning of a field unless
        !           827:                 * the format suppresses this behavior.
        !           828:                 */
        !           829:                if (!(flags & SCAN_NOSKIP)) {
        !           830:                        while (*string != '\0') {
        !           831:                                sch = *string;
        !           832:                                if (! isspace((int)sch) ) {
        !           833:                                        break;
        !           834:                                }
        !           835:                                string++;
        !           836:                        }
        !           837:                        if (*string == '\0') {
        !           838:                                underflow = 1;
        !           839:                                goto done;
        !           840:                        }
        !           841:                }
        !           842: 
        !           843:                /*
        !           844:                 * Perform the requested scanning operation.
        !           845:                 */
        !           846:                switch (op) {
        !           847:                        case 'c':
        !           848:                        case 's':
        !           849:                                /*
        !           850:                                 * Scan a string up to width characters or whitespace.
        !           851:                                 */
        !           852:                                if (width == 0) {
        !           853:                                        width = (size_t) ~0;
        !           854:                                }
        !           855:                                end = string;
        !           856:                                while (*end != '\0') {
        !           857:                                        sch = *end;
        !           858:                                        if ( isspace( (int)sch ) ) {
        !           859:                                                break;
        !           860:                                        }
        !           861:                                        end++;
        !           862:                                        if (--width == 0) {
        !           863:                                           break;
        !           864:                                        }
        !           865:                                }
        !           866:                                if (!(flags & SCAN_SUPPRESS)) {
        !           867:                                        if (numVars && objIndex >= argCount) {
        !           868:                                                break;
        !           869:                                        } else if (numVars) {
        !           870:                                                zend_uint refcount;
        !           871: 
        !           872:                                                current = args[objIndex++];
        !           873:                                                refcount = Z_REFCOUNT_PP(current);
        !           874:                                                zval_dtor( *current );
        !           875:                                                ZVAL_STRINGL( *current, string, end-string, 1);
        !           876:                                                Z_SET_REFCOUNT_PP(current, refcount);
        !           877:                                                Z_SET_ISREF_PP(current);
        !           878:                                        } else {
        !           879:                                                add_index_stringl( *return_value, objIndex++, string, end-string, 1);
        !           880:                                        }
        !           881:                                }
        !           882:                                string = end;
        !           883:                                break;
        !           884: 
        !           885:                        case '[': {
        !           886:                                CharSet cset;
        !           887: 
        !           888:                                if (width == 0) {
        !           889:                                        width = (size_t) ~0;
        !           890:                                }
        !           891:                                end = string;
        !           892: 
        !           893:                                format = BuildCharSet(&cset, format);
        !           894:                                while (*end != '\0') {
        !           895:                                        sch = *end;
        !           896:                                        if (!CharInSet(&cset, (int)sch)) {
        !           897:                                                break;
        !           898:                                        }
        !           899:                                        end++;
        !           900:                                        if (--width == 0) {
        !           901:                                                break;
        !           902:                                        }
        !           903:                                }
        !           904:                                ReleaseCharSet(&cset);
        !           905: 
        !           906:                                if (string == end) {
        !           907:                                        /*
        !           908:                                         * Nothing matched the range, stop processing
        !           909:                                         */
        !           910:                                        goto done;
        !           911:                                }
        !           912:                                if (!(flags & SCAN_SUPPRESS)) {
        !           913:                                        if (numVars && objIndex >= argCount) {
        !           914:                                                break;
        !           915:                                        } else if (numVars) {
        !           916:                                                current = args[objIndex++];
        !           917:                                                zval_dtor( *current );
        !           918:                                                ZVAL_STRINGL( *current, string, end-string, 1);
        !           919:                                        } else {
        !           920:                                                add_index_stringl(*return_value, objIndex++, string, end-string, 1);
        !           921:                                        }
        !           922:                                }
        !           923:                                string = end;
        !           924:                                break;
        !           925:                        }
        !           926: /*
        !           927:                        case 'c':
        !           928:                           / Scan a single character./
        !           929: 
        !           930:                                sch = *string;
        !           931:                                string++;
        !           932:                                if (!(flags & SCAN_SUPPRESS)) {
        !           933:                                        if (numVars) {
        !           934:                                                char __buf[2];
        !           935:                                                __buf[0] = sch;
        !           936:                                                __buf[1] = '\0';;
        !           937:                                                current = args[objIndex++];
        !           938:                                                zval_dtor(*current);
        !           939:                                                ZVAL_STRINGL( *current, __buf, 1, 1);
        !           940:                                        } else {
        !           941:                                                add_index_stringl(*return_value, objIndex++, &sch, 1, 1);
        !           942:                                        }
        !           943:                                }
        !           944:                                break;
        !           945: */
        !           946:                        case 'i':
        !           947:                                /*
        !           948:                                 * Scan an unsigned or signed integer.
        !           949:                                 */
        !           950:                                /*-cc-*/
        !           951:                                buf[0] = '\0';
        !           952:                                /*-cc-*/
        !           953:                                if ((width == 0) || (width > sizeof(buf) - 1)) {
        !           954:                                        width = sizeof(buf) - 1;
        !           955:                                }
        !           956: 
        !           957:                                flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO;
        !           958:                                for (end = buf; width > 0; width--) {
        !           959:                                        switch (*string) {
        !           960:                                                /*
        !           961:                                                 * The 0 digit has special meaning at the beginning of
        !           962:                                                 * a number.  If we are unsure of the base, it
        !           963:                                                 * indicates that we are in base 8 or base 16 (if it is
        !           964:                                                 * followed by an 'x').
        !           965:                                                 */
        !           966:                                                case '0':
        !           967:                                                        /*-cc-*/
        !           968:                                                        if (base == 16) {
        !           969:                                                                flags |= SCAN_XOK;
        !           970:                                                        }
        !           971:                                                        /*-cc-*/
        !           972:                                                        if (base == 0) {
        !           973:                                                                base = 8;
        !           974:                                                                flags |= SCAN_XOK;
        !           975:                                                        }
        !           976:                                                        if (flags & SCAN_NOZERO) {
        !           977:                                                                flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO);
        !           978:                                                        } else {
        !           979:                                                                flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
        !           980:                                                        }
        !           981:                                                        goto addToInt;
        !           982: 
        !           983:                                                case '1': case '2': case '3': case '4':
        !           984:                                                case '5': case '6': case '7':
        !           985:                                                        if (base == 0) {
        !           986:                                                                base = 10;
        !           987:                                                        }
        !           988:                                                        flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
        !           989:                                                        goto addToInt;
        !           990: 
        !           991:                                                case '8': case '9':
        !           992:                                                        if (base == 0) {
        !           993:                                                                base = 10;
        !           994:                                                        }
        !           995:                                                        if (base <= 8) {
        !           996:                                                           break;
        !           997:                                                        }
        !           998:                                                        flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
        !           999:                                                        goto addToInt;
        !          1000: 
        !          1001:                                                case 'A': case 'B': case 'C':
        !          1002:                                                case 'D': case 'E': case 'F':
        !          1003:                                                case 'a': case 'b': case 'c':
        !          1004:                                                case 'd': case 'e': case 'f':
        !          1005:                                                        if (base <= 10) {
        !          1006:                                                                break;
        !          1007:                                                        }
        !          1008:                                                        flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
        !          1009:                                                        goto addToInt;
        !          1010: 
        !          1011:                                                case '+': case '-':
        !          1012:                                                        if (flags & SCAN_SIGNOK) {
        !          1013:                                                                flags &= ~SCAN_SIGNOK;
        !          1014:                                                                goto addToInt;
        !          1015:                                                        }
        !          1016:                                                        break;
        !          1017: 
        !          1018:                                                case 'x': case 'X':
        !          1019:                                                        if ((flags & SCAN_XOK) && (end == buf+1)) {
        !          1020:                                                                base = 16;
        !          1021:                                                                flags &= ~SCAN_XOK;
        !          1022:                                                                goto addToInt;
        !          1023:                                                        }
        !          1024:                                                        break;
        !          1025:                                        }
        !          1026: 
        !          1027:                                        /*
        !          1028:                                         * We got an illegal character so we are done accumulating.
        !          1029:                                         */
        !          1030:                                        break;
        !          1031: 
        !          1032: addToInt:
        !          1033:                                        /*
        !          1034:                                         * Add the character to the temporary buffer.
        !          1035:                                         */
        !          1036:                                        *end++ = *string++;
        !          1037:                                        if (*string == '\0') {
        !          1038:                                                break;
        !          1039:                                        }
        !          1040:                                }
        !          1041: 
        !          1042:                                /*
        !          1043:                                 * Check to see if we need to back up because we only got a
        !          1044:                                 * sign or a trailing x after a 0.
        !          1045:                                 */
        !          1046:                                if (flags & SCAN_NODIGITS) {
        !          1047:                                        if (*string == '\0') {
        !          1048:                                                underflow = 1;
        !          1049:                                        }
        !          1050:                                        goto done;
        !          1051:                                } else if (end[-1] == 'x' || end[-1] == 'X') {
        !          1052:                                        end--;
        !          1053:                                        string--;
        !          1054:                                }
        !          1055: 
        !          1056:                                /*
        !          1057:                                 * Scan the value from the temporary buffer.  If we are
        !          1058:                                 * returning a large unsigned value, we have to convert it back
        !          1059:                                 * to a string since PHP only supports signed values.
        !          1060:                                 */
        !          1061:                                if (!(flags & SCAN_SUPPRESS)) {
        !          1062:                                        *end = '\0';
        !          1063:                                        value = (long) (*fn)(buf, NULL, base);
        !          1064:                                        if ((flags & SCAN_UNSIGNED) && (value < 0)) {
        !          1065:                                                snprintf(buf, sizeof(buf), "%lu", value); /* INTL: ISO digit */
        !          1066:                                                if (numVars && objIndex >= argCount) {
        !          1067:                                                        break;
        !          1068:                                                } else if (numVars) {
        !          1069:                                                  /* change passed value type to string */
        !          1070:                                                        current = args[objIndex++];
        !          1071:                                                        zval_dtor(*current);
        !          1072:                                                        ZVAL_STRING( *current, buf, 1 );
        !          1073:                                                } else {
        !          1074:                                                        add_index_string(*return_value, objIndex++, buf, 1);
        !          1075:                                                }
        !          1076:                                        } else {
        !          1077:                                                if (numVars && objIndex >= argCount) {
        !          1078:                                                        break;
        !          1079:                                                } else if (numVars) {
        !          1080:                                                        current = args[objIndex++];
        !          1081:                                                        zval_dtor(*current);
        !          1082:                                                        ZVAL_LONG(*current, value);
        !          1083:                                                } else {
        !          1084:                                                        add_index_long(*return_value, objIndex++, value);
        !          1085:                                                }
        !          1086:                                        }
        !          1087:                                }
        !          1088:                                break;
        !          1089: 
        !          1090:                        case 'f':
        !          1091:                                /*
        !          1092:                                 * Scan a floating point number
        !          1093:                                 */
        !          1094:                                buf[0] = '\0';     /* call me pedantic */
        !          1095:                                if ((width == 0) || (width > sizeof(buf) - 1)) {
        !          1096:                                        width = sizeof(buf) - 1;
        !          1097:                                }
        !          1098:                                flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_PTOK | SCAN_EXPOK;
        !          1099:                                for (end = buf; width > 0; width--) {
        !          1100:                                        switch (*string) {
        !          1101:                                                case '0': case '1': case '2': case '3':
        !          1102:                                                case '4': case '5': case '6': case '7':
        !          1103:                                                case '8': case '9':
        !          1104:                                                        flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS);
        !          1105:                                                        goto addToFloat;
        !          1106:                                                case '+':
        !          1107:                                                case '-':
        !          1108:                                                        if (flags & SCAN_SIGNOK) {
        !          1109:                                                                flags &= ~SCAN_SIGNOK;
        !          1110:                                                                goto addToFloat;
        !          1111:                                                        }
        !          1112:                                                        break;
        !          1113:                                                case '.':
        !          1114:                                                        if (flags & SCAN_PTOK) {
        !          1115:                                                                flags &= ~(SCAN_SIGNOK | SCAN_PTOK);
        !          1116:                                                                goto addToFloat;
        !          1117:                                                        }
        !          1118:                                                        break;
        !          1119:                                                case 'e':
        !          1120:                                                case 'E':
        !          1121:                                                        /*
        !          1122:                                                         * An exponent is not allowed until there has
        !          1123:                                                         * been at least one digit.
        !          1124:                                                         */
        !          1125:                                                        if ((flags & (SCAN_NODIGITS | SCAN_EXPOK)) == SCAN_EXPOK) {
        !          1126:                                                                flags = (flags & ~(SCAN_EXPOK|SCAN_PTOK))
        !          1127:                                                                        | SCAN_SIGNOK | SCAN_NODIGITS;
        !          1128:                                                                goto addToFloat;
        !          1129:                                                        }
        !          1130:                                                        break;
        !          1131:                                        }
        !          1132: 
        !          1133:                                        /*
        !          1134:                                         * We got an illegal character so we are done accumulating.
        !          1135:                                         */
        !          1136:                                        break;
        !          1137: 
        !          1138: addToFloat:
        !          1139:                                        /*
        !          1140:                                         * Add the character to the temporary buffer.
        !          1141:                                         */
        !          1142:                                        *end++ = *string++;
        !          1143:                                        if (*string == '\0') {
        !          1144:                                                break;
        !          1145:                                        }
        !          1146:                                }
        !          1147: 
        !          1148:                                /*
        !          1149:                                 * Check to see if we need to back up because we saw a
        !          1150:                                 * trailing 'e' or sign.
        !          1151:                                 */
        !          1152:                                if (flags & SCAN_NODIGITS) {
        !          1153:                                        if (flags & SCAN_EXPOK) {
        !          1154:                                                /*
        !          1155:                                                 * There were no digits at all so scanning has
        !          1156:                                                 * failed and we are done.
        !          1157:                                                 */
        !          1158:                                                if (*string == '\0') {
        !          1159:                                                        underflow = 1;
        !          1160:                                                }
        !          1161:                                                goto done;
        !          1162:                                        }
        !          1163: 
        !          1164:                                        /*
        !          1165:                                         * We got a bad exponent ('e' and maybe a sign).
        !          1166:                                         */
        !          1167:                                        end--;
        !          1168:                                        string--;
        !          1169:                                        if (*end != 'e' && *end != 'E') {
        !          1170:                                                end--;
        !          1171:                                                string--;
        !          1172:                                        }
        !          1173:                                }
        !          1174: 
        !          1175:                                /*
        !          1176:                                 * Scan the value from the temporary buffer.
        !          1177:                                 */
        !          1178:                                if (!(flags & SCAN_SUPPRESS)) {
        !          1179:                                        double dvalue;
        !          1180:                                        *end = '\0';
        !          1181:                                        dvalue = zend_strtod(buf, NULL);
        !          1182:                                        if (numVars && objIndex >= argCount) {
        !          1183:                                                break;
        !          1184:                                        } else if (numVars) {
        !          1185:                                                current = args[objIndex++];
        !          1186:                                                zval_dtor(*current);
        !          1187:                                                ZVAL_DOUBLE(*current, dvalue);
        !          1188:                                        } else {
        !          1189:                                                add_index_double( *return_value, objIndex++, dvalue );
        !          1190:                                        }
        !          1191:                                }
        !          1192:                                break;
        !          1193:                } /* switch (op) */
        !          1194:                nconversions++;
        !          1195:        } /*  while (*format != '\0') */
        !          1196: 
        !          1197: done:
        !          1198:        result = SCAN_SUCCESS;
        !          1199: 
        !          1200:        if (underflow && (0==nconversions)) {
        !          1201:                scan_set_error_return( numVars, return_value );
        !          1202:                result = SCAN_ERROR_EOF;
        !          1203:        } else if (numVars) {
        !          1204:                convert_to_long( *return_value );
        !          1205:                Z_LVAL_PP(return_value) = nconversions;
        !          1206:        } else if (nconversions < totalVars) {
        !          1207:                /* TODO: not all elements converted. we need to prune the list - cc */
        !          1208:        }
        !          1209:        return result;
        !          1210: }
        !          1211: /* }}} */
        !          1212: 
        !          1213: /* the compiler choked when i tried to make this a macro    */
        !          1214: static inline void scan_set_error_return(int numVars, zval **return_value) /* {{{ */
        !          1215: {
        !          1216:        if (numVars) {
        !          1217:                Z_TYPE_PP(return_value) = IS_LONG;
        !          1218:                Z_LVAL_PP(return_value) = SCAN_ERROR_EOF;  /* EOF marker */
        !          1219:        } else {
        !          1220:                /* convert_to_null calls destructor */
        !          1221:                convert_to_null( *return_value );
        !          1222:        }
        !          1223: }
        !          1224: /* }}} */
        !          1225: 
        !          1226: /*
        !          1227:  * Local variables:
        !          1228:  * tab-width: 4
        !          1229:  * c-basic-offset: 4
        !          1230:  * End:
        !          1231:  * vim600: sw=4 ts=4 fdm=marker
        !          1232:  * vim<600: sw=4 ts=4
        !          1233:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>