nsprpub/pr/src/io/prscanf.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial