vfscanf.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:18k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * Copyright (c) 1993, 1994 Chris Provenzano. 
  4.  * All rights reserved.
  5.  *
  6.  * This code is derived from software contributed to Berkeley by
  7.  * Chris Torek.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  * This product includes software developed by the University of
  20.  * California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #if defined(LIBC_SCCS) && !defined(lint)
  38. /*static char *sccsid = "from: @(#)vfscanf.c 5.7 (Berkeley) 12/14/92";*/
  39. static char *rcsid = "$Id$";
  40. #endif /* LIBC_SCCS and not lint */
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <ctype.h>
  44. #if __STDC__
  45. #include <stdarg.h>
  46. #else
  47. #include <varargs.h>
  48. #endif
  49. #include "local.h"
  50. #define FLOATING_POINT
  51. #include "floatio.h"
  52. #define BUF 513 /* Maximum length of numeric string. */
  53. /*
  54.  * Flags used during conversion.
  55.  */
  56. #define LONG 0x01 /* l: long or double */
  57. #define LONGDBL 0x02 /* L: long double; unimplemented */
  58. #define SHORT 0x04 /* h: short */
  59. #define SUPPRESS 0x08 /* suppress assignment */
  60. #define POINTER 0x10 /* weird %p pointer (`fake hex') */
  61. #define NOSKIP 0x20 /* do not skip blanks */
  62. /*
  63.  * The following are used in numeric conversions only:
  64.  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
  65.  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
  66.  */
  67. #define SIGNOK 0x40 /* +/- is (still) legal */
  68. #define NDIGITS 0x80 /* no digits detected */
  69. #define DPTOK 0x100 /* (float) decimal point is still legal */
  70. #define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */
  71. #define PFXOK 0x100 /* 0x prefix is (still) legal */
  72. #define NZDIGITS 0x200 /* no zero digits detected */
  73. /*
  74.  * Conversion types.
  75.  */
  76. #define CT_CHAR 0 /* %c conversion */
  77. #define CT_CCL 1 /* %[...] conversion */
  78. #define CT_STRING 2 /* %s conversion */
  79. #define CT_INT 3 /* integer, i.e., strtol or strtoul */
  80. #define CT_FLOAT 4 /* floating, i.e., strtod */
  81. #define u_char unsigned char
  82. #define u_long unsigned long
  83. static u_char *__sccl();
  84. /*
  85.  * vfscanf
  86.  */
  87. __svfscanf(fp, fmt0, ap)
  88. register FILE *fp;
  89. char const *fmt0;
  90. pthread_va_list ap;
  91. {
  92. register u_char *fmt = (u_char *)fmt0;
  93. register int c; /* character from format, or conversion */
  94. register size_t width; /* field width, or 0 */
  95. register char *p; /* points into all kinds of strings */
  96. register int n; /* handy integer */
  97. register int flags; /* flags as defined above */
  98. register char *p0; /* saves original value of p when necessary */
  99. int nassigned; /* number of fields assigned */
  100. int nread; /* number of characters consumed from fp */
  101. int base; /* base argument to strtol/strtoul */
  102. u_long (*ccfn)(); /* conversion function (strtol/strtoul) */
  103. char ccltab[256]; /* character class table for %[...] */
  104. char buf[BUF]; /* buffer for numeric conversions */
  105. /* `basefix' is used to avoid `if' tests in the integer scanner */
  106. static short basefix[17] =
  107. { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
  108. nassigned = 0;
  109. nread = 0;
  110. base = 0; /* XXX just to keep gcc happy */
  111. ccfn = NULL; /* XXX just to keep gcc happy */
  112. for (;;) {
  113. c = *fmt++;
  114. if (c == 0)
  115. return (nassigned);
  116. if (isspace(c)) {
  117. for (;;) {
  118. if (fp->_r <= 0 && __srefill(fp))
  119. return (nassigned);
  120. if (!isspace(*fp->_p))
  121. break;
  122. nread++, fp->_r--, fp->_p++;
  123. }
  124. continue;
  125. }
  126. if (c != '%')
  127. goto literal;
  128. width = 0;
  129. flags = 0;
  130. /*
  131.  * switch on the format.  continue if done;
  132.  * break once format type is derived.
  133.  */
  134. again: c = *fmt++;
  135. switch (c) {
  136. case '%':
  137. literal:
  138. if (fp->_r <= 0 && __srefill(fp))
  139. goto input_failure;
  140. if (*fp->_p != c)
  141. goto match_failure;
  142. fp->_r--, fp->_p++;
  143. nread++;
  144. continue;
  145. case '*':
  146. flags |= SUPPRESS;
  147. goto again;
  148. case 'l':
  149. flags |= LONG;
  150. goto again;
  151. case 'L':
  152. flags |= LONGDBL;
  153. goto again;
  154. case 'h':
  155. flags |= SHORT;
  156. goto again;
  157. case '0': case '1': case '2': case '3': case '4':
  158. case '5': case '6': case '7': case '8': case '9':
  159. width = width * 10 + c - '0';
  160. goto again;
  161. /*
  162.  * Conversions.
  163.  * Those marked `compat' are for 4.[123]BSD compatibility.
  164.  *
  165.  * (According to ANSI, E and X formats are supposed
  166.  * to the same as e and x.  Sorry about that.)
  167.  */
  168. case 'D': /* compat */
  169. flags |= LONG;
  170. /* FALLTHROUGH */
  171. case 'd':
  172. c = CT_INT;
  173. ccfn = (u_long (*)())strtol;
  174. base = 10;
  175. break;
  176. case 'i':
  177. c = CT_INT;
  178. ccfn = (u_long (*)())strtol;
  179. base = 0;
  180. break;
  181. case 'O': /* compat */
  182. flags |= LONG;
  183. /* FALLTHROUGH */
  184. case 'o':
  185. c = CT_INT;
  186. ccfn = strtoul;
  187. base = 8;
  188. break;
  189. case 'u':
  190. c = CT_INT;
  191. ccfn = strtoul;
  192. base = 10;
  193. break;
  194. case 'X': /* compat   XXX */
  195. flags |= LONG;
  196. /* FALLTHROUGH */
  197. case 'x':
  198. flags |= PFXOK; /* enable 0x prefixing */
  199. c = CT_INT;
  200. ccfn = strtoul;
  201. base = 16;
  202. break;
  203. #ifdef FLOATING_POINT
  204. case 'E': /* compat   XXX */
  205. case 'F': /* compat */
  206. flags |= LONG;
  207. /* FALLTHROUGH */
  208. case 'e': case 'f': case 'g':
  209. c = CT_FLOAT;
  210. break;
  211. #endif
  212. case 's':
  213. c = CT_STRING;
  214. break;
  215. case '[':
  216. fmt = __sccl(ccltab, fmt);
  217. flags |= NOSKIP;
  218. c = CT_CCL;
  219. break;
  220. case 'c':
  221. flags |= NOSKIP;
  222. c = CT_CHAR;
  223. break;
  224. case 'p': /* pointer format is like hex */
  225. flags |= POINTER | PFXOK;
  226. c = CT_INT;
  227. ccfn = strtoul;
  228. base = 16;
  229. break;
  230. case 'n':
  231. if (flags & SUPPRESS) /* ??? */
  232. continue;
  233. if (flags & SHORT)
  234. *va_arg(ap, short *) = nread;
  235. else if (flags & LONG)
  236. *va_arg(ap, long *) = nread;
  237. else
  238. *va_arg(ap, int *) = nread;
  239. continue;
  240. /*
  241.  * Disgusting backwards compatibility hacks. XXX
  242.  */
  243. case '': /* compat */
  244. return (EOF);
  245. default: /* compat */
  246. if (isupper(c))
  247. flags |= LONG;
  248. c = CT_INT;
  249. ccfn = (u_long (*)())strtol;
  250. base = 10;
  251. break;
  252. }
  253. /*
  254.  * We have a conversion that requires input.
  255.  */
  256. if (fp->_r <= 0 && __srefill(fp))
  257. goto input_failure;
  258. /*
  259.  * Consume leading white space, except for formats
  260.  * that suppress this.
  261.  */
  262. if ((flags & NOSKIP) == 0) {
  263. while (isspace(*fp->_p)) {
  264. nread++;
  265. if (--fp->_r > 0)
  266. fp->_p++;
  267. else if (__srefill(fp))
  268. goto input_failure;
  269. }
  270. /*
  271.  * Note that there is at least one character in
  272.  * the buffer, so conversions that do not set NOSKIP
  273.  * ca no longer result in an input failure.
  274.  */
  275. }
  276. /*
  277.  * Do the conversion.
  278.  */
  279. switch (c) {
  280. case CT_CHAR:
  281. /* scan arbitrary characters (sets NOSKIP) */
  282. if (width == 0)
  283. width = 1;
  284. if (flags & SUPPRESS) {
  285. size_t sum = 0;
  286. for (;;) {
  287. if ((n = fp->_r) < width) {
  288. sum += n;
  289. width -= n;
  290. fp->_p += n;
  291. if (__srefill(fp)) {
  292. if (sum == 0)
  293.     goto input_failure;
  294. break;
  295. }
  296. } else {
  297. sum += width;
  298. fp->_r -= width;
  299. fp->_p += width;
  300. break;
  301. }
  302. }
  303. nread += sum;
  304. } else {
  305. size_t r = fread((void *)va_arg(ap, char *), 1,
  306.     width, fp);
  307. if (r == 0)
  308. goto input_failure;
  309. nread += r;
  310. nassigned++;
  311. }
  312. break;
  313. case CT_CCL:
  314. /* scan a (nonempty) character class (sets NOSKIP) */
  315. if (width == 0)
  316. width = ~0; /* `infinity' */
  317. /* take only those things in the class */
  318. if (flags & SUPPRESS) {
  319. n = 0;
  320. while (ccltab[*fp->_p]) {
  321. n++, fp->_r--, fp->_p++;
  322. if (--width == 0)
  323. break;
  324. if (fp->_r <= 0 && __srefill(fp)) {
  325. if (n == 0)
  326. goto input_failure;
  327. break;
  328. }
  329. }
  330. if (n == 0)
  331. goto match_failure;
  332. } else {
  333. p0 = p = va_arg(ap, char *);
  334. while (ccltab[*fp->_p]) {
  335. fp->_r--;
  336. *p++ = *fp->_p++;
  337. if (--width == 0)
  338. break;
  339. if (fp->_r <= 0 && __srefill(fp)) {
  340. if (p == p0)
  341. goto input_failure;
  342. break;
  343. }
  344. }
  345. n = p - p0;
  346. if (n == 0)
  347. goto match_failure;
  348. *p = 0;
  349. nassigned++;
  350. }
  351. nread += n;
  352. break;
  353. case CT_STRING:
  354. /* like CCL, but zero-length string OK, & no NOSKIP */
  355. if (width == 0)
  356. width = ~0;
  357. if (flags & SUPPRESS) {
  358. n = 0;
  359. while (!isspace(*fp->_p)) {
  360. n++, fp->_r--, fp->_p++;
  361. if (--width == 0)
  362. break;
  363. if (fp->_r <= 0 && __srefill(fp))
  364. break;
  365. }
  366. nread += n;
  367. } else {
  368. p0 = p = va_arg(ap, char *);
  369. while (!isspace(*fp->_p)) {
  370. fp->_r--;
  371. *p++ = *fp->_p++;
  372. if (--width == 0)
  373. break;
  374. if (fp->_r <= 0 && __srefill(fp))
  375. break;
  376. }
  377. *p = 0;
  378. nread += p - p0;
  379. nassigned++;
  380. }
  381. continue;
  382. case CT_INT:
  383. /* scan an integer as if by strtol/strtoul */
  384. #ifdef hardway
  385. if (width == 0 || width > sizeof(buf) - 1)
  386. width = sizeof(buf) - 1;
  387. #else
  388. /* size_t is unsigned, hence this optimisation */
  389. if (--width > sizeof(buf) - 2)
  390. width = sizeof(buf) - 2;
  391. width++;
  392. #endif
  393. flags |= SIGNOK | NDIGITS | NZDIGITS;
  394. for (p = buf; width; width--) {
  395. c = *fp->_p;
  396. /*
  397.  * Switch on the character; `goto ok'
  398.  * if we accept it as a part of number.
  399.  */
  400. switch (c) {
  401. /*
  402.  * The digit 0 is always legal, but is
  403.  * special.  For %i conversions, if no
  404.  * digits (zero or nonzero) have been
  405.  * scanned (only signs), we will have
  406.  * base==0.  In that case, we should set
  407.  * it to 8 and enable 0x prefixing.
  408.  * Also, if we have not scanned zero digits
  409.  * before this, do not turn off prefixing
  410.  * (someone else will turn it off if we
  411.  * have scanned any nonzero digits).
  412.  */
  413. case '0':
  414. if (base == 0) {
  415. base = 8;
  416. flags |= PFXOK;
  417. }
  418. if (flags & NZDIGITS)
  419.     flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
  420. else
  421.     flags &= ~(SIGNOK|PFXOK|NDIGITS);
  422. goto ok;
  423. /* 1 through 7 always legal */
  424. case '1': case '2': case '3':
  425. case '4': case '5': case '6': case '7':
  426. base = basefix[base];
  427. flags &= ~(SIGNOK | PFXOK | NDIGITS);
  428. goto ok;
  429. /* digits 8 and 9 ok iff decimal or hex */
  430. case '8': case '9':
  431. base = basefix[base];
  432. if (base <= 8)
  433. break; /* not legal here */
  434. flags &= ~(SIGNOK | PFXOK | NDIGITS);
  435. goto ok;
  436. /* letters ok iff hex */
  437. case 'A': case 'B': case 'C':
  438. case 'D': case 'E': case 'F':
  439. case 'a': case 'b': case 'c':
  440. case 'd': case 'e': case 'f':
  441. /* no need to fix base here */
  442. if (base <= 10)
  443. break; /* not legal here */
  444. flags &= ~(SIGNOK | PFXOK | NDIGITS);
  445. goto ok;
  446. /* sign ok only as first character */
  447. case '+': case '-':
  448. if (flags & SIGNOK) {
  449. flags &= ~SIGNOK;
  450. goto ok;
  451. }
  452. break;
  453. /* x ok iff flag still set & 2nd char */
  454. case 'x': case 'X':
  455. if (flags & PFXOK && p == buf + 1) {
  456. base = 16; /* if %i */
  457. flags &= ~PFXOK;
  458. goto ok;
  459. }
  460. break;
  461. }
  462. /*
  463.  * If we got here, c is not a legal character
  464.  * for a number.  Stop accumulating digits.
  465.  */
  466. break;
  467. ok:
  468. /*
  469.  * c is legal: store it and look at the next.
  470.  */
  471. *p++ = c;
  472. if (--fp->_r > 0)
  473. fp->_p++;
  474. else if (__srefill(fp))
  475. break; /* EOF */
  476. }
  477. /*
  478.  * If we had only a sign, it is no good; push
  479.  * back the sign.  If the number ends in `x',
  480.  * it was [sign] '0' 'x', so push back the x
  481.  * and treat it as [sign] '0'.
  482.  */
  483. if (flags & NDIGITS) {
  484. if (p > buf)
  485. (void) ungetc(*(u_char *)--p, fp);
  486. goto match_failure;
  487. }
  488. c = ((u_char *)p)[-1];
  489. if (c == 'x' || c == 'X') {
  490. --p;
  491. (void) ungetc(c, fp);
  492. }
  493. if ((flags & SUPPRESS) == 0) {
  494. u_long res;
  495. *p = 0;
  496. res = (*ccfn)(buf, (char **)NULL, base);
  497. if (flags & POINTER)
  498. *va_arg(ap, void **) = (void *)res;
  499. else if (flags & SHORT)
  500. *va_arg(ap, short *) = res;
  501. else if (flags & LONG)
  502. *va_arg(ap, long *) = res;
  503. else
  504. *va_arg(ap, int *) = res;
  505. nassigned++;
  506. }
  507. nread += p - buf;
  508. break;
  509. #ifdef FLOATING_POINT
  510. case CT_FLOAT:
  511. /* scan a floating point number as if by strtod */
  512. #ifdef hardway
  513. if (width == 0 || width > sizeof(buf) - 1)
  514. width = sizeof(buf) - 1;
  515. #else
  516. /* size_t is unsigned, hence this optimisation */
  517. if (--width > sizeof(buf) - 2)
  518. width = sizeof(buf) - 2;
  519. width++;
  520. #endif
  521. flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
  522. for (p = buf; width; width--) {
  523. c = *fp->_p;
  524. /*
  525.  * This code mimicks the integer conversion
  526.  * code, but is much simpler.
  527.  */
  528. switch (c) {
  529. case '0': case '1': case '2': case '3':
  530. case '4': case '5': case '6': case '7':
  531. case '8': case '9':
  532. flags &= ~(SIGNOK | NDIGITS);
  533. goto fok;
  534. case '+': case '-':
  535. if (flags & SIGNOK) {
  536. flags &= ~SIGNOK;
  537. goto fok;
  538. }
  539. break;
  540. case '.':
  541. if (flags & DPTOK) {
  542. flags &= ~(SIGNOK | DPTOK);
  543. goto fok;
  544. }
  545. break;
  546. case 'e': case 'E':
  547. /* no exponent without some digits */
  548. if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
  549. flags =
  550.     (flags & ~(EXPOK|DPTOK)) |
  551.     SIGNOK | NDIGITS;
  552. goto fok;
  553. }
  554. break;
  555. }
  556. break;
  557. fok:
  558. *p++ = c;
  559. if (--fp->_r > 0)
  560. fp->_p++;
  561. else if (__srefill(fp))
  562. break; /* EOF */
  563. }
  564. /*
  565.  * If no digits, might be missing exponent digits
  566.  * (just give back the exponent) or might be missing
  567.  * regular digits, but had sign and/or decimal point.
  568.  */
  569. if (flags & NDIGITS) {
  570. if (flags & EXPOK) {
  571. /* no digits at all */
  572. while (p > buf)
  573. ungetc(*(u_char *)--p, fp);
  574. goto match_failure;
  575. }
  576. /* just a bad exponent (e and maybe sign) */
  577. c = *(u_char *)--p;
  578. if (c != 'e' && c != 'E') {
  579. (void) ungetc(c, fp);/* sign */
  580. c = *(u_char *)--p;
  581. }
  582. (void) ungetc(c, fp);
  583. }
  584. if ((flags & SUPPRESS) == 0) {
  585. double res;
  586. *p = 0;
  587. res = strtod(buf, (char **) NULL);
  588. if (flags & LONG)
  589. *va_arg(ap, double *) = res;
  590. else
  591. *va_arg(ap, float *) = res;
  592. nassigned++;
  593. }
  594. nread += p - buf;
  595. break;
  596. #endif /* FLOATING_POINT */
  597. }
  598. }
  599. input_failure:
  600. return (nassigned ? nassigned : -1);
  601. match_failure:
  602. return (nassigned);
  603. }
  604. /*
  605.  * Fill in the given table from the scanset at the given format
  606.  * (just after `[').  Return a pointer to the character past the
  607.  * closing `]'.  The table has a 1 wherever characters should be
  608.  * considered part of the scanset.
  609.  */
  610. static u_char *
  611. __sccl(tab, fmt)
  612. register char *tab;
  613. register u_char *fmt;
  614. {
  615. register int c, n, v;
  616. /* first `clear' the whole table */
  617. c = *fmt++; /* first char hat => negated scanset */
  618. if (c == '^') {
  619. v = 1; /* default => accept */
  620. c = *fmt++; /* get new first char */
  621. } else
  622. v = 0; /* default => reject */
  623. /* should probably use memset here */
  624. for (n = 0; n < 256; n++)
  625. tab[n] = v;
  626. if (c == 0)
  627. return (fmt - 1);/* format ended before closing ] */
  628. /*
  629.  * Now set the entries corresponding to the actual scanset
  630.  * to the opposite of the above.
  631.  *
  632.  * The first character may be ']' (or '-') without being special;
  633.  * the last character may be '-'.
  634.  */
  635. v = 1 - v;
  636. for (;;) {
  637. tab[c] = v; /* take character c */
  638. doswitch:
  639. n = *fmt++; /* and examine the next */
  640. switch (n) {
  641. case 0: /* format ended too soon */
  642. return (fmt - 1);
  643. case '-':
  644. /*
  645.  * A scanset of the form
  646.  * [01+-]
  647.  * is defined as `the digit 0, the digit 1,
  648.  * the character +, the character -', but
  649.  * the effect of a scanset such as
  650.  * [a-zA-Z0-9]
  651.  * is implementation defined.  The V7 Unix
  652.  * scanf treats `a-z' as `the letters a through
  653.  * z', but treats `a-a' as `the letter a, the
  654.  * character -, and the letter a'.
  655.  *
  656.  * For compatibility, the `-' is not considerd
  657.  * to define a range if the character following
  658.  * it is either a close bracket (required by ANSI)
  659.  * or is not numerically greater than the character
  660.  * we just stored in the table (c).
  661.  */
  662. n = *fmt;
  663. if (n == ']' || n < c) {
  664. c = '-';
  665. break; /* resume the for(;;) */
  666. }
  667. fmt++;
  668. do { /* fill in the range */
  669. tab[++c] = v;
  670. } while (c < n);
  671. #if 1 /* XXX another disgusting compatibility hack */
  672. /*
  673.  * Alas, the V7 Unix scanf also treats formats
  674.  * such as [a-c-e] as `the letters a through e'.
  675.  * This too is permitted by the standard....
  676.  */
  677. goto doswitch;
  678. #else
  679. c = *fmt++;
  680. if (c == 0)
  681. return (fmt - 1);
  682. if (c == ']')
  683. return (fmt);
  684. #endif
  685. break;
  686. case ']': /* end of scanset */
  687. return (fmt);
  688. default: /* just another character */
  689. c = n;
  690. break;
  691. }
  692. }
  693. /* NOTREACHED */
  694. }