LCOV - app.info - nsprpub/pr/src/io/prscanf.c

LCOV - code coverage report
| Current view: | directory - nsprpub/pr/src/io - prscanf.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 312 | 148 | 47.4 %
| Date: | 2012-04-21 | Functions: | 8 | 7 | 87.5 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is the Netscape Portable Runtime (NSPR).
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Netscape Communications Corporation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 1998-2000
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *
          24                 :  * Alternatively, the contents of this file may be used under the terms of
          25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          28                 :  * of those above. If you wish to allow use of your version of this file only
          29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          30                 :  * use your version of this file under the terms of the MPL, indicate your
          31                 :  * decision by deleting the provisions above and replace them with the notice
          32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          33                 :  * the provisions above, a recipient may use your version of this file under
          34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          35                 :  *
          36                 :  * ***** END LICENSE BLOCK ***** */
          37                 :
          38                 : /*
          39                 :  * Scan functions for NSPR types
          40                 :  *
          41                 :  * Author: Wan-Teh Chang
          42                 :  *
          43                 :  * Acknowledgment: The implementation is inspired by the source code
          44                 :  * in P.J. Plauger's "The Standard C Library," Prentice-Hall, 1992.
          45                 :  */
          46                 :
          47                 : #include <limits.h>
          48                 : #include <ctype.h>
          49                 : #include <string.h>
          50                 : #include <stdlib.h>
          51                 : #ifdef SUNOS4
          52                 : #include "md/sunos4.h"  /* for strtoul */
          53                 : #endif
          54                 : #include "prprf.h"
          55                 : #include "prdtoa.h"
          56                 : #include "prlog.h"
          57                 : #include "prerror.h"
          58                 :
          59                 : /*
          60                 :  * A function that reads a character from 'stream'.
          61                 :  * Returns the character read, or EOF if end of stream is reached.
          62                 :  */
          63                 : typedef int (*_PRGetCharFN)(void *stream);
          64                 :
          65                 : /*
          66                 :  * A function that pushes the character 'ch' back to 'stream'.
          67                 :  */
          68                 : typedef void (*_PRUngetCharFN)(void *stream, int ch);
          69                 :
          70                 : /*
          71                 :  * The size specifier for the integer and floating point number
          72                 :  * conversions in format control strings.
          73                 :  */
          74                 : typedef enum {
          75                 :     _PR_size_none,  /* No size specifier is given */
          76                 :     _PR_size_h,     /* The 'h' specifier, suggesting "short" */
          77                 :     _PR_size_l,     /* The 'l' specifier, suggesting "long" */
          78                 :     _PR_size_L,     /* The 'L' specifier, meaning a 'long double' */
          79                 :     _PR_size_ll     /* The 'll' specifier, suggesting "long long" */
          80                 : } _PRSizeSpec;
          81                 :
          82                 : /*
          83                 :  * The collection of data that is passed between the scan function
          84                 :  * and its subordinate functions.  The fields of this structure
          85                 :  * serve as the input or output arguments for these functions.
          86                 :  */
          87                 : typedef struct {
          88                 :     _PRGetCharFN get;        /* get a character from input stream */
          89                 :     _PRUngetCharFN unget;    /* unget (push back) a character */
          90                 :     void *stream;            /* argument for get and unget */
          91                 :     va_list ap;              /* the variable argument list */
          92                 :     int nChar;               /* number of characters read from 'stream' */
          93                 :
          94                 :     PRBool assign;           /* assign, or suppress assignment? */
          95                 :     int width;               /* field width */
          96                 :     _PRSizeSpec sizeSpec;    /* 'h', 'l', 'L', or 'll' */
          97                 :
          98                 :     PRBool converted;        /* is the value actually converted? */
          99                 : } ScanfState;
         100                 :
         101                 : #define GET(state) ((state)->nChar++, (state)->get((state)->stream))
         102                 : #define UNGET(state, ch) \
         103                 :         ((state)->nChar--, (state)->unget((state)->stream, ch))
         104                 :
         105                 : /*
         106                 :  * The following two macros, GET_IF_WITHIN_WIDTH and WITHIN_WIDTH,
         107                 :  * are always used together.
         108                 :  *
         109                 :  * GET_IF_WITHIN_WIDTH calls the GET macro and assigns its return
         110                 :  * value to 'ch' only if we have not exceeded the field width of
         111                 :  * 'state'.  Therefore, after GET_IF_WITHIN_WIDTH, the value of
         112                 :  * 'ch' is valid only if the macro WITHIN_WIDTH evaluates to true.
         113                 :  */
         114                 :
         115                 : #define GET_IF_WITHIN_WIDTH(state, ch) \
         116                 :         if (--(state)->width >= 0) { \
         117                 :             (ch) = GET(state); \
         118                 :         }
         119                 : #define WITHIN_WIDTH(state) ((state)->width >= 0)
         120                 :
         121                 : /*
         122                 :  * _pr_strtoull:
         123                 :  *     Convert a string to an unsigned 64-bit integer.  The string
         124                 :  *     'str' is assumed to be a representation of the integer in
         125                 :  *     base 'base'.
         126                 :  *
         127                 :  * Warning:
         128                 :  *     - Only handle base 8, 10, and 16.
         129                 :  *     - No overflow checking.
         130                 :  */
         131                 :
         132                 : static PRUint64
         133           16844 : _pr_strtoull(const char *str, char **endptr, int base)
         134                 : {
         135                 :     static const int BASE_MAX = 16;
         136                 :     static const char digits[] = "0123456789abcdef";
         137                 :     char *digitPtr;
         138                 :     PRUint64 x;    /* return value */
         139                 :     PRInt64 base64;
         140                 :     const char *cPtr;
         141                 :     PRBool negative;
         142                 :     const char *digitStart;
         143                 :
         144           16844 :     PR_ASSERT(base == 0 || base == 8 || base == 10 || base == 16);
         145           16844 :     if (base < 0 || base == 1 || base > BASE_MAX) {
         146               0 :         if (endptr) {
         147               0 :             *endptr = (char *) str;
         148               0 :             return LL_ZERO;
         149                 :         }
         150                 :     }
         151                 :
         152           16844 :     cPtr = str;
         153           33688 :     while (isspace(*cPtr)) {
         154               0 :         ++cPtr;
         155                 :     }
         156                 :
         157           16844 :     negative = PR_FALSE;
         158           16844 :     if (*cPtr == '-') {
         159               2 :         negative = PR_TRUE;
         160               2 :         cPtr++;
         161           16842 :     } else if (*cPtr == '+') {
         162               0 :         cPtr++;
         163                 :     }
         164                 :
         165           16844 :     if (base == 16) {
         166               0 :         if (*cPtr == '0' && (cPtr[1] == 'x' || cPtr[1] == 'X')) {
         167               0 :             cPtr += 2;
         168                 :         }
         169           16844 :     } else if (base == 0) {
         170               0 :         if (*cPtr != '0') {
         171               0 :             base = 10;
         172               0 :         } else if (cPtr[1] == 'x' || cPtr[1] == 'X') {
         173               0 :             base = 16;
         174               0 :             cPtr += 2;
         175                 :         } else {
         176               0 :             base = 8;
         177                 :         }
         178                 :     }
         179           16844 :     PR_ASSERT(base != 0);
         180           16844 :     LL_I2L(base64, base);
         181           16844 :     digitStart = cPtr;
         182                 :
         183                 :     /* Skip leading zeros */
         184           33688 :     while (*cPtr == '0') {
         185               0 :         cPtr++;
         186                 :     }
         187                 :
         188           16844 :     LL_I2L(x, 0);
         189          120277 :     while ((digitPtr = (char*)memchr(digits, tolower(*cPtr), base)) != NULL) {
         190                 :         PRUint64 d;
         191                 :
         192           86589 :         LL_I2L(d, (digitPtr - digits));
         193           86589 :         LL_MUL(x, x, base64);
         194           86589 :         LL_ADD(x, x, d);
         195           86589 :         cPtr++;
         196                 :     }
         197                 :
         198           16844 :     if (cPtr == digitStart) {
         199               0 :         if (endptr) {
         200               0 :             *endptr = (char *) str;
         201                 :         }
         202               0 :         return LL_ZERO;
         203                 :     }
         204                 :
         205           16844 :     if (negative) {
         206                 : #ifdef HAVE_LONG_LONG
         207                 :         /* The cast to a signed type is to avoid a compiler warning */
         208               2 :         x = -(PRInt64)x;
         209                 : #else
         210                 :         LL_NEG(x, x);
         211                 : #endif
         212                 :     }
         213                 :
         214           16844 :     if (endptr) {
         215               0 :         *endptr = (char *) cPtr;
         216                 :     }
         217           16844 :     return x;
         218                 : }
         219                 :
         220                 : /*
         221                 :  * The maximum field width (in number of characters) that is enough
         222                 :  * (may be more than necessary) to represent a 64-bit integer or
         223                 :  * floating point number.
         224                 :  */
         225                 : #define FMAX 31
         226                 : #define DECIMAL_POINT '.'
         227                 :
         228                 : static PRStatus
         229           18470 : GetInt(ScanfState *state, int code)
         230                 : {
         231                 :     char buf[FMAX + 1], *p;
         232                 :     int ch;
         233                 :     static const char digits[] = "0123456789abcdefABCDEF";
         234           18470 :     PRBool seenDigit = PR_FALSE;
         235                 :     int base;
         236                 :     int dlen;
         237                 :
         238           18470 :     switch (code) {
         239                 :         case 'd': case 'u':
         240           18470 :             base = 10;
         241           18470 :             break;
         242                 :         case 'i':
         243               0 :             base = 0;
         244               0 :             break;
         245                 :         case 'x': case 'X': case 'p':
         246               0 :             base = 16;
         247               0 :             break;
         248                 :         case 'o':
         249               0 :             base = 8;
         250               0 :             break;
         251                 :         default:
         252               0 :             return PR_FAILURE;
         253                 :     }
         254           18470 :     if (state->width == 0 || state->width > FMAX) {
         255           18470 :         state->width = FMAX;
         256                 :     }
         257           18470 :     p = buf;
         258           18470 :     GET_IF_WITHIN_WIDTH(state, ch);
         259           18470 :     if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
         260               2 :         *p++ = ch;
         261               2 :         GET_IF_WITHIN_WIDTH(state, ch);
         262                 :     }
         263           18470 :     if (WITHIN_WIDTH(state) && ch == '0') {
         264              12 :         seenDigit = PR_TRUE;
         265              12 :         *p++ = ch;
         266              12 :         GET_IF_WITHIN_WIDTH(state, ch);
         267              12 :         if (WITHIN_WIDTH(state)
         268              12 :                 && (ch == 'x' || ch == 'X')
         269               0 :                 && (base == 0 || base == 16)) {
         270               0 :             base = 16;
         271               0 :             *p++ = ch;
         272               0 :             GET_IF_WITHIN_WIDTH(state, ch);
         273              12 :         } else if (base == 0) {
         274               0 :             base = 8;
         275                 :         }
         276                 :     }
         277           18470 :     if (base == 0 || base == 10) {
         278           18470 :         dlen = 10;
         279               0 :     } else if (base == 8) {
         280               0 :         dlen = 8;
         281                 :     } else {
         282               0 :         PR_ASSERT(base == 16);
         283               0 :         dlen = 16 + 6; /* 16 digits, plus 6 in uppercase */
         284                 :     }
         285          124418 :     while (WITHIN_WIDTH(state) && memchr(digits, ch, dlen)) {
         286           87478 :         *p++ = ch;
         287           87478 :         GET_IF_WITHIN_WIDTH(state, ch);
         288           87478 :         seenDigit = PR_TRUE;
         289                 :     }
         290           18470 :     if (WITHIN_WIDTH(state)) {
         291           18470 :         UNGET(state, ch);
         292                 :     }
         293           18470 :     if (!seenDigit) {
         294            1184 :         return PR_FAILURE;
         295                 :     }
         296           17286 :     *p = '\0';
         297           17286 :     if (state->assign) {
         298           17286 :         if (code == 'd' || code == 'i') {
         299           34430 :             if (state->sizeSpec == _PR_size_ll) {
         300           16844 :                 PRInt64 llval = _pr_strtoull(buf, NULL, base);
         301           16844 :                 *va_arg(state->ap, PRInt64 *) = llval;
         302                 :             } else {
         303             371 :                 long lval = strtol(buf, NULL, base);
         304                 :
         305             371 :                 if (state->sizeSpec == _PR_size_none) {
         306             371 :                     *va_arg(state->ap, PRIntn *) = lval;
         307               0 :                 } else if (state->sizeSpec == _PR_size_h) {
         308               0 :                     *va_arg(state->ap, PRInt16 *) = (PRInt16)lval;
         309               0 :                 } else if (state->sizeSpec == _PR_size_l) {
         310               0 :                     *va_arg(state->ap, PRInt32 *) = lval;
         311                 :                 } else {
         312               0 :                     return PR_FAILURE;
         313                 :                 }
         314                 :             }
         315                 :         } else {
         316              71 :             if (state->sizeSpec == _PR_size_ll) {
         317               0 :                 PRUint64 llval = _pr_strtoull(buf, NULL, base);
         318               0 :                 *va_arg(state->ap, PRUint64 *) = llval;
         319                 :             } else {
         320              71 :                 unsigned long lval = strtoul(buf, NULL, base);
         321                 :
         322              71 :                 if (state->sizeSpec == _PR_size_none) {
         323              71 :                     *va_arg(state->ap, PRUintn *) = lval;
         324               0 :                 } else if (state->sizeSpec == _PR_size_h) {
         325               0 :                     *va_arg(state->ap, PRUint16 *) = (PRUint16)lval;
         326               0 :                 } else if (state->sizeSpec == _PR_size_l) {
         327               0 :                     *va_arg(state->ap, PRUint32 *) = lval;
         328                 :                 } else {
         329               0 :                     return PR_FAILURE;
         330                 :                 }
         331                 :             }
         332                 :         }
         333           17286 :         state->converted = PR_TRUE;
         334                 :     }
         335           17286 :     return PR_SUCCESS;
         336                 : }
         337                 :
         338                 : static PRStatus
         339               0 : GetFloat(ScanfState *state)
         340                 : {
         341                 :     char buf[FMAX + 1], *p;
         342                 :     int ch;
         343               0 :     PRBool seenDigit = PR_FALSE;
         344                 :
         345               0 :     if (state->width == 0 || state->width > FMAX) {
         346               0 :         state->width = FMAX;
         347                 :     }
         348               0 :     p = buf;
         349               0 :     GET_IF_WITHIN_WIDTH(state, ch);
         350               0 :     if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
         351               0 :         *p++ = ch;
         352               0 :         GET_IF_WITHIN_WIDTH(state, ch);
         353                 :     }
         354               0 :     while (WITHIN_WIDTH(state) && isdigit(ch)) {
         355               0 :         *p++ = ch;
         356               0 :         GET_IF_WITHIN_WIDTH(state, ch);
         357               0 :         seenDigit = PR_TRUE;
         358                 :     }
         359               0 :     if (WITHIN_WIDTH(state) && ch == DECIMAL_POINT) {
         360               0 :         *p++ = ch;
         361               0 :         GET_IF_WITHIN_WIDTH(state, ch);
         362               0 :         while (WITHIN_WIDTH(state) && isdigit(ch)) {
         363               0 :             *p++ = ch;
         364               0 :             GET_IF_WITHIN_WIDTH(state, ch);
         365               0 :             seenDigit = PR_TRUE;
         366                 :         }
         367                 :     }
         368                 :
         369                 :     /*
         370                 :      * This is not robust.  For example, "1.2e+" would confuse
         371                 :      * the code below to read 'e' and '+', only to realize that
         372                 :      * it should have stopped at "1.2".  But we can't push back
         373                 :      * more than one character, so there is nothing I can do.
         374                 :      */
         375                 :
         376                 :     /* Parse exponent */
         377               0 :     if (WITHIN_WIDTH(state) && (ch == 'e' || ch == 'E') && seenDigit) {
         378               0 :         *p++ = ch;
         379               0 :         GET_IF_WITHIN_WIDTH(state, ch);
         380               0 :         if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) {
         381               0 :             *p++ = ch;
         382               0 :             GET_IF_WITHIN_WIDTH(state, ch);
         383                 :         }
         384               0 :         while (WITHIN_WIDTH(state) && isdigit(ch)) {
         385               0 :             *p++ = ch;
         386               0 :             GET_IF_WITHIN_WIDTH(state, ch);
         387                 :         }
         388                 :     }
         389               0 :     if (WITHIN_WIDTH(state)) {
         390               0 :         UNGET(state, ch);
         391                 :     }
         392               0 :     if (!seenDigit) {
         393               0 :         return PR_FAILURE;
         394                 :     }
         395               0 :     *p = '\0';
         396               0 :     if (state->assign) {
         397               0 :         PRFloat64 dval = PR_strtod(buf, NULL);
         398                 :
         399               0 :         state->converted = PR_TRUE;
         400               0 :         if (state->sizeSpec == _PR_size_l) {
         401               0 :             *va_arg(state->ap, PRFloat64 *) = dval;
         402               0 :         } else if (state->sizeSpec == _PR_size_L) {
         403                 : #if defined(OSF1) || defined(IRIX)
         404                 :             *va_arg(state->ap, double *) = dval;
         405                 : #else
         406               0 :             *va_arg(state->ap, long double *) = dval;
         407                 : #endif
         408                 :         } else {
         409               0 :             *va_arg(state->ap, float *) = (float) dval;
         410                 :         }
         411                 :     }
         412               0 :     return PR_SUCCESS;
         413                 : }
         414                 :
         415                 : /*
         416                 :  * Convert, and return the end of the conversion spec.
         417                 :  * Return NULL on error.
         418                 :  */
         419                 :
         420                 : static const char *
         421           18561 : Convert(ScanfState *state, const char *fmt)
         422                 : {
         423                 :     const char *cPtr;
         424                 :     int ch;
         425           18561 :     char *cArg = NULL;
         426                 :
         427           18561 :     state->converted = PR_FALSE;
         428           18561 :     cPtr = fmt;
         429           18561 :     if (*cPtr != 'c' && *cPtr != 'n' && *cPtr != '[') {
         430                 :         do {
         431           18470 :             ch = GET(state);
         432           18470 :         } while (isspace(ch));
         433           18470 :         UNGET(state, ch);
         434                 :     }
         435           18561 :     switch (*cPtr) {
         436                 :         case 'c':
         437              91 :             if (state->assign) {
         438              91 :                 cArg = va_arg(state->ap, char *);
         439                 :             }
         440              91 :             if (state->width == 0) {
         441              91 :                 state->width = 1;
         442                 :             }
         443             178 :             for (; state->width > 0; state->width--) {
         444              91 :                 ch = GET(state);
         445              91 :                 if (ch == EOF) {
         446               4 :                     return NULL;
         447              87 :                 } else if (state->assign) {
         448              87 :                     *cArg++ = ch;
         449                 :                 }
         450                 :             }
         451              87 :             if (state->assign) {
         452              87 :                 state->converted = PR_TRUE;
         453                 :             }
         454              87 :             break;
         455                 :         case 'p':
         456                 :         case 'd': case 'i': case 'o':
         457                 :         case 'u': case 'x': case 'X':
         458           18470 :             if (GetInt(state, *cPtr) == PR_FAILURE) {
         459            1184 :                 return NULL;
         460                 :             }
         461           17286 :             break;
         462                 :         case 'e': case 'E': case 'f':
         463                 :         case 'g': case 'G':
         464               0 :             if (GetFloat(state) == PR_FAILURE) {
         465               0 :                 return NULL;
         466                 :             }
         467               0 :             break;
         468                 :         case 'n':
         469                 :             /* do not consume any input */
         470               0 :             if (state->assign) {
         471               0 :                 switch (state->sizeSpec) {
         472                 :                     case _PR_size_none:
         473               0 :                         *va_arg(state->ap, PRIntn *) = state->nChar;
         474               0 :                         break;
         475                 :                     case _PR_size_h:
         476               0 :                         *va_arg(state->ap, PRInt16 *) = state->nChar;
         477               0 :                         break;
         478                 :                     case _PR_size_l:
         479               0 :                         *va_arg(state->ap, PRInt32 *) = state->nChar;
         480               0 :                         break;
         481                 :                     case _PR_size_ll:
         482               0 :                         LL_I2L(*va_arg(state->ap, PRInt64 *), state->nChar);
         483               0 :                         break;
         484                 :                     default:
         485               0 :                         PR_ASSERT(0);
         486                 :                 }
         487                 :             }
         488               0 :             break;
         489                 :         case 's':
         490               0 :             if (state->width == 0) {
         491               0 :                 state->width = INT_MAX;
         492                 :             }
         493               0 :             if (state->assign) {
         494               0 :                 cArg = va_arg(state->ap, char *);
         495                 :             }
         496               0 :             for (; state->width > 0; state->width--) {
         497               0 :                 ch = GET(state);
         498               0 :                 if ((ch == EOF) || isspace(ch)) {
         499               0 :                     UNGET(state, ch);
         500               0 :                     break;
         501                 :                 }
         502               0 :                 if (state->assign) {
         503               0 :                     *cArg++ = ch;
         504                 :                 }
         505                 :             }
         506               0 :             if (state->assign) {
         507               0 :                 *cArg = '\0';
         508               0 :                 state->converted = PR_TRUE;
         509                 :             }
         510               0 :             break;
         511                 :         case '%':
         512               0 :             ch = GET(state);
         513               0 :             if (ch != '%') {
         514               0 :                 UNGET(state, ch);
         515               0 :                 return NULL;
         516                 :             }
         517               0 :             break;
         518                 :         case '[':
         519                 :             {
         520               0 :                 PRBool complement = PR_FALSE;
         521                 :                 const char *closeBracket;
         522                 :                 size_t n;
         523                 :
         524               0 :                 if (*++cPtr == '^') {
         525               0 :                     complement = PR_TRUE;
         526               0 :                     cPtr++;
         527                 :                 }
         528               0 :                 closeBracket = strchr(*cPtr == ']' ? cPtr + 1 : cPtr, ']');
         529               0 :                 if (closeBracket == NULL) {
         530               0 :                     return NULL;
         531                 :                 }
         532               0 :                 n = closeBracket - cPtr;
         533               0 :                 if (state->width == 0) {
         534               0 :                     state->width = INT_MAX;
         535                 :                 }
         536               0 :                 if (state->assign) {
         537               0 :                     cArg = va_arg(state->ap, char *);
         538                 :                 }
         539               0 :                 for (; state->width > 0; state->width--) {
         540               0 :                     ch = GET(state);
         541               0 :                     if ((ch == EOF)
         542               0 :                             || (!complement && !memchr(cPtr, ch, n))
         543               0 :                             || (complement && memchr(cPtr, ch, n))) {
         544               0 :                         UNGET(state, ch);
         545               0 :                         break;
         546                 :                     }
         547               0 :                     if (state->assign) {
         548               0 :                         *cArg++ = ch;
         549                 :                     }
         550                 :                 }
         551               0 :                 if (state->assign) {
         552               0 :                     *cArg = '\0';
         553               0 :                     state->converted = PR_TRUE;
         554                 :                 }
         555               0 :                 cPtr = closeBracket;
         556                 :             }
         557               0 :             break;
         558                 :         default:
         559               0 :             return NULL;
         560                 :     }
         561           17373 :     return cPtr;
         562                 : }
         563                 :
         564                 : static PRInt32
         565           18282 : DoScanf(ScanfState *state, const char *fmt)
         566                 : {
         567           18282 :     PRInt32 nConverted = 0;
         568                 :     const char *cPtr;
         569                 :     int ch;
         570                 :
         571           18282 :     state->nChar = 0;
         572           18282 :     cPtr = fmt;
         573                 :     while (1) {
         574           36127 :         if (isspace(*cPtr)) {
         575                 :             /* white space: skip */
         576                 :             do {
         577               0 :                 cPtr++;
         578               0 :             } while (isspace(*cPtr));
         579                 :             do {
         580               0 :                 ch = GET(state);
         581               0 :             } while (isspace(ch));
         582               0 :             UNGET(state, ch);
         583           36127 :         } else if (*cPtr == '%') {
         584                 :             /* format spec: convert */
         585           18561 :             cPtr++;
         586           18561 :             state->assign = PR_TRUE;
         587           18561 :             if (*cPtr == '*') {
         588               0 :                 cPtr++;
         589               0 :                 state->assign = PR_FALSE;
         590                 :             }
         591           18561 :             for (state->width = 0; isdigit(*cPtr); cPtr++) {
         592               0 :                 state->width = state->width * 10 + *cPtr - '0';
         593                 :             }
         594           18561 :             state->sizeSpec = _PR_size_none;
         595           18561 :             if (*cPtr == 'h') {
         596               0 :                 cPtr++;
         597               0 :                 state->sizeSpec = _PR_size_h;
         598           18561 :             } else if (*cPtr == 'l') {
         599           17533 :                 cPtr++;
         600           17533 :                 if (*cPtr == 'l') {
         601           17533 :                     cPtr++;
         602           17533 :                     state->sizeSpec = _PR_size_ll;
         603                 :                 } else {
         604               0 :                     state->sizeSpec = _PR_size_l;
         605                 :                 }
         606            1028 :             } else if (*cPtr == 'L') {
         607               0 :                 cPtr++;
         608               0 :                 state->sizeSpec = _PR_size_L;
         609                 :             }
         610           18561 :             cPtr = Convert(state, cPtr);
         611           18561 :             if (cPtr == NULL) {
         612            1188 :                 return (nConverted > 0 ? nConverted : EOF);
         613                 :             }
         614           17373 :             if (state->converted) {
         615           17373 :                 nConverted++;
         616                 :             }
         617           17373 :             cPtr++;
         618                 :         } else {
         619                 :             /* others: must match */
         620           17566 :             if (*cPtr == '\0') {
         621           17087 :                 return nConverted;
         622                 :             }
         623             479 :             ch = GET(state);
         624             479 :             if (ch != *cPtr) {
         625               7 :                 UNGET(state, ch);
         626               7 :                 return nConverted;
         627                 :             }
         628             472 :             cPtr++;
         629                 :         }
         630           17845 :     }
         631                 : }
         632                 :
         633                 : static int
         634          125002 : StringGetChar(void *stream)
         635                 : {
         636          125002 :     char *cPtr = *((char **) stream);
         637                 :
         638          125002 :     if (*cPtr == '\0') {
         639           17078 :         return EOF;
         640                 :     } else {
         641          107924 :         *((char **) stream) = cPtr + 1;
         642          107924 :         return (unsigned char) *cPtr;
         643                 :     }
         644                 : }
         645                 :
         646                 : static void
         647           36947 : StringUngetChar(void *stream, int ch)
         648                 : {
         649           36947 :     char *cPtr = *((char **) stream);
         650                 :
         651           36947 :     if (ch != EOF) {
         652           19873 :         *((char **) stream) = cPtr - 1;
         653                 :     }
         654           36947 : }
         655                 :
         656                 : PR_IMPLEMENT(PRInt32)
         657           18282 : PR_sscanf(const char *buf, const char *fmt, ...)
         658                 : {
         659                 :     PRInt32 rv;
         660                 :     ScanfState state;
         661                 :
         662           18282 :     state.get = &StringGetChar;
         663           18282 :     state.unget = &StringUngetChar;
         664           18282 :     state.stream = (void *) &buf;
         665           18282 :     va_start(state.ap, fmt);
         666           18282 :     rv = DoScanf(&state, fmt);
         667           18282 :     va_end(state.ap);
         668           18282 :     return rv;
         669                 : }

Generated by: LCOV version 1.7