1:
2:
3:
4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
35: #define FLOATING_POINT
36: #include <ctype.h>
37: #include <inttypes.h>
38: #include <stdarg.h>
39: #include <stddef.h>
40: #include <stdio.h>
41: #include <stdlib.h>
42: #include <string.h>
43: #include "local.h"
44:
45: #ifdef FLOATING_POINT
46: #include "floatio.h"
47: #endif
48:
49: #define BUF 513
50:
51: 52: 53:
54: #define LONG 0x00001
55: #define LONGDBL 0x00002
56: #define SHORT 0x00004
57: #define SHORTSHORT 0x00008
58: #define LLONG 0x00010
59: #define POINTER 0x00020
60: #define SIZEINT 0x00040
61: #define MAXINT 0x00080
62: #define PTRINT 0x00100
63: #define NOSKIP 0x00200
64: #define SUPPRESS 0x00400
65: #define UNSIGNED 0x00800
66:
67: 68: 69: 70: 71:
72: #define SIGNOK 0x01000
73: #define HAVESIGN 0x02000
74: #define NDIGITS 0x04000
75:
76: #define DPTOK 0x08000
77: #define EXPOK 0x10000
78:
79: #define PFXOK 0x08000
80: #define NZDIGITS 0x10000
81:
82: 83: 84:
85: #define CT_CHAR 0
86: #define CT_CCL 1
87: #define CT_STRING 2
88: #define CT_INT 3
89: #define CT_FLOAT 4
90:
91: #define u_char unsigned char
92: #define u_long unsigned long
93:
94: static u_char *__sccl(char *, u_char *);
95:
96: 97: 98:
99: int
100: __svfscanf(FILE *fp, const char *fmt0, __va_list ap)
101: {
102: u_char *fmt = (u_char *)fmt0;
103: int c;
104: size_t width;
105: char *p;
106: int n;
107: int flags;
108: char *p0;
109: int nassigned;
110: int nread;
111: int base;
112: char ccltab[256];
113: char buf[BUF];
114: #ifdef SCANF_WIDE_CHAR
115: wchar_t *wcp;
116: size_t nconv;
117: mbstate_t mbs;
118: #endif
119:
120:
121: static short basefix[17] =
122: { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
123:
124: _SET_ORIENTATION(fp, -1);
125:
126: nassigned = 0;
127: nread = 0;
128: base = 0;
129: for (;;) {
130: c = *fmt++;
131: if (c == 0)
132: return (nassigned);
133: if (isspace(c)) {
134: while ((fp->_r > 0 || __srefill(fp) == 0) &&
135: isspace(*fp->_p))
136: nread++, fp->_r--, fp->_p++;
137: continue;
138: }
139: if (c != '%')
140: goto literal;
141: width = 0;
142: flags = 0;
143: 144: 145: 146:
147: again: c = *fmt++;
148: switch (c) {
149: case '%':
150: literal:
151: if (fp->_r <= 0 && __srefill(fp))
152: goto input_failure;
153: if (*fp->_p != c)
154: goto match_failure;
155: fp->_r--, fp->_p++;
156: nread++;
157: continue;
158:
159: case '*':
160: flags |= SUPPRESS;
161: goto again;
162: case 'j':
163: flags |= MAXINT;
164: goto again;
165: case 'L':
166: flags |= LONGDBL;
167: goto again;
168: case 'h':
169: if (*fmt == 'h') {
170: fmt++;
171: flags |= SHORTSHORT;
172: } else {
173: flags |= SHORT;
174: }
175: goto again;
176: case 'l':
177: if (*fmt == 'l') {
178: fmt++;
179: flags |= LLONG;
180: } else {
181: flags |= LONG;
182: }
183: goto again;
184: case 'q':
185: flags |= LLONG;
186: goto again;
187: case 't':
188: flags |= PTRINT;
189: goto again;
190: case 'z':
191: flags |= SIZEINT;
192: goto again;
193:
194: case '0': case '1': case '2': case '3': case '4':
195: case '5': case '6': case '7': case '8': case '9':
196: width = width * 10 + c - '0';
197: goto again;
198:
199: 200: 201: 202: 203: 204: 205:
206: case 'D':
207: flags |= LONG;
208:
209: case 'd':
210: c = CT_INT;
211: base = 10;
212: break;
213:
214: case 'i':
215: c = CT_INT;
216: base = 0;
217: break;
218:
219: case 'O':
220: flags |= LONG;
221:
222: case 'o':
223: c = CT_INT;
224: flags |= UNSIGNED;
225: base = 8;
226: break;
227:
228: case 'u':
229: c = CT_INT;
230: flags |= UNSIGNED;
231: base = 10;
232: break;
233:
234: case 'X':
235: case 'x':
236: flags |= PFXOK;
237: c = CT_INT;
238: flags |= UNSIGNED;
239: base = 16;
240: break;
241:
242: #ifdef FLOATING_POINT
243: case 'e': case 'E':
244: case 'f': case 'F':
245: case 'g': case 'G':
246: case 'a': case 'A':
247: c = CT_FLOAT;
248: break;
249: #endif
250:
251: case 's':
252: c = CT_STRING;
253: break;
254:
255: case '[':
256: fmt = __sccl(ccltab, fmt);
257: flags |= NOSKIP;
258: c = CT_CCL;
259: break;
260:
261: case 'c':
262: flags |= NOSKIP;
263: c = CT_CHAR;
264: break;
265:
266: case 'p':
267: flags |= POINTER | PFXOK;
268: c = CT_INT;
269: flags |= UNSIGNED;
270: base = 16;
271: break;
272:
273: case 'n':
274: if (flags & SUPPRESS)
275: continue;
276: if (flags & SHORTSHORT)
277: *va_arg(ap, __signed char *) = nread;
278: else if (flags & SHORT)
279: *va_arg(ap, short *) = nread;
280: else if (flags & LONG)
281: *va_arg(ap, long *) = nread;
282: else if (flags & SIZEINT)
283: *va_arg(ap, ssize_t *) = nread;
284: else if (flags & PTRINT)
285: *va_arg(ap, ptrdiff_t *) = nread;
286: else if (flags & LLONG)
287: *va_arg(ap, long long *) = nread;
288: else if (flags & MAXINT)
289: *va_arg(ap, intmax_t *) = nread;
290: else
291: *va_arg(ap, int *) = nread;
292: continue;
293:
294: 295: 296:
297: case '\0':
298: return (EOF);
299:
300: default:
301: if (isupper(c))
302: flags |= LONG;
303: c = CT_INT;
304: base = 10;
305: break;
306: }
307:
308: 309: 310:
311: if (fp->_r <= 0 && __srefill(fp))
312: goto input_failure;
313:
314: 315: 316: 317:
318: if ((flags & NOSKIP) == 0) {
319: while (isspace(*fp->_p)) {
320: nread++;
321: if (--fp->_r > 0)
322: fp->_p++;
323: else if (__srefill(fp))
324: goto input_failure;
325: }
326: 327: 328: 329: 330:
331: }
332:
333: 334: 335:
336: switch (c) {
337:
338: case CT_CHAR:
339:
340: if (width == 0)
341: width = 1;
342: #ifdef SCANF_WIDE_CHAR
343: if (flags & LONG) {
344: if ((flags & SUPPRESS) == 0)
345: wcp = va_arg(ap, wchar_t *);
346: else
347: wcp = NULL;
348: n = 0;
349: while (width != 0) {
350: if (n == MB_CUR_MAX) {
351: fp->_flags |= __SERR;
352: goto input_failure;
353: }
354: buf[n++] = *fp->_p;
355: fp->_p++;
356: fp->_r--;
357: bzero(&mbs, sizeof(mbs));
358: nconv = mbrtowc(wcp, buf, n, &mbs);
359: if (nconv == (size_t)-1) {
360: fp->_flags |= __SERR;
361: goto input_failure;
362: }
363: if (nconv == 0 && !(flags & SUPPRESS))
364: *wcp = L'\0';
365: if (nconv != (size_t)-2) {
366: nread += n;
367: width--;
368: if (!(flags & SUPPRESS))
369: wcp++;
370: n = 0;
371: }
372: if (fp->_r <= 0 && __srefill(fp)) {
373: if (n != 0) {
374: fp->_flags |= __SERR;
375: goto input_failure;
376: }
377: break;
378: }
379: }
380: if (!(flags & SUPPRESS))
381: nassigned++;
382: } else
383: #endif
384: if (flags & SUPPRESS) {
385: size_t sum = 0;
386: for (;;) {
387: if ((n = fp->_r) < width) {
388: sum += n;
389: width -= n;
390: fp->_p += n;
391: if (__srefill(fp)) {
392: if (sum == 0)
393: goto input_failure;
394: break;
395: }
396: } else {
397: sum += width;
398: fp->_r -= width;
399: fp->_p += width;
400: break;
401: }
402: }
403: nread += sum;
404: } else {
405: size_t r = __sfread((void *)va_arg(ap, char *), 1,
406: width, fp);
407:
408: if (r == 0)
409: goto input_failure;
410: nread += r;
411: nassigned++;
412: }
413: break;
414:
415: case CT_CCL:
416:
417: if (width == 0)
418: width = (size_t)~0;
419: #ifdef SCANF_WIDE_CHAR
420:
421: if (flags & LONG) {
422: wchar_t twc;
423: int nchars;
424:
425: if ((flags & SUPPRESS) == 0)
426: wcp = va_arg(ap, wchar_t *);
427: else
428: wcp = &twc;
429: n = 0;
430: nchars = 0;
431: while (width != 0) {
432: if (n == MB_CUR_MAX) {
433: fp->_flags |= __SERR;
434: goto input_failure;
435: }
436: buf[n++] = *fp->_p;
437: fp->_p++;
438: fp->_r--;
439: bzero(&mbs, sizeof(mbs));
440: nconv = mbrtowc(wcp, buf, n, &mbs);
441: if (nconv == (size_t)-1) {
442: fp->_flags |= __SERR;
443: goto input_failure;
444: }
445: if (nconv == 0)
446: *wcp = L'\0';
447: if (nconv != (size_t)-2) {
448: if (wctob(*wcp) != EOF &&
449: !ccltab[wctob(*wcp)]) {
450: while (n != 0) {
451: n--;
452: __sungetc(buf[n],
453: fp);
454: }
455: break;
456: }
457: nread += n;
458: width--;
459: if (!(flags & SUPPRESS))
460: wcp++;
461: nchars++;
462: n = 0;
463: }
464: if (fp->_r <= 0 && __srefill(fp)) {
465: if (n != 0) {
466: fp->_flags |= __SERR;
467: goto input_failure;
468: }
469: break;
470: }
471: }
472: if (n != 0) {
473: fp->_flags |= __SERR;
474: goto input_failure;
475: }
476: n = nchars;
477: if (n == 0)
478: goto match_failure;
479: if (!(flags & SUPPRESS)) {
480: *wcp = L'\0';
481: nassigned++;
482: }
483: } else
484: #endif
485:
486: if (flags & SUPPRESS) {
487: n = 0;
488: while (ccltab[*fp->_p]) {
489: n++, fp->_r--, fp->_p++;
490: if (--width == 0)
491: break;
492: if (fp->_r <= 0 && __srefill(fp)) {
493: if (n == 0)
494: goto input_failure;
495: break;
496: }
497: }
498: if (n == 0)
499: goto match_failure;
500: } else {
501: p0 = p = va_arg(ap, char *);
502: while (ccltab[*fp->_p]) {
503: fp->_r--;
504: *p++ = *fp->_p++;
505: if (--width == 0)
506: break;
507: if (fp->_r <= 0 && __srefill(fp)) {
508: if (p == p0)
509: goto input_failure;
510: break;
511: }
512: }
513: n = p - p0;
514: if (n == 0)
515: goto match_failure;
516: *p = '\0';
517: nassigned++;
518: }
519: nread += n;
520: break;
521:
522: case CT_STRING:
523:
524: if (width == 0)
525: width = (size_t)~0;
526: #ifdef SCANF_WIDE_CHAR
527: if (flags & LONG) {
528: wchar_t twc;
529:
530: if ((flags & SUPPRESS) == 0)
531: wcp = va_arg(ap, wchar_t *);
532: else
533: wcp = &twc;
534: n = 0;
535: while (!isspace(*fp->_p) && width != 0) {
536: if (n == MB_CUR_MAX) {
537: fp->_flags |= __SERR;
538: goto input_failure;
539: }
540: buf[n++] = *fp->_p;
541: fp->_p++;
542: fp->_r--;
543: bzero(&mbs, sizeof(mbs));
544: nconv = mbrtowc(wcp, buf, n, &mbs);
545: if (nconv == (size_t)-1) {
546: fp->_flags |= __SERR;
547: goto input_failure;
548: }
549: if (nconv == 0)
550: *wcp = L'\0';
551: if (nconv != (size_t)-2) {
552: if (iswspace(*wcp)) {
553: while (n != 0) {
554: n--;
555: __sungetc(buf[n],
556: fp);
557: }
558: break;
559: }
560: nread += n;
561: width--;
562: if (!(flags & SUPPRESS))
563: wcp++;
564: n = 0;
565: }
566: if (fp->_r <= 0 && __srefill(fp)) {
567: if (n != 0) {
568: fp->_flags |= __SERR;
569: goto input_failure;
570: }
571: break;
572: }
573: }
574: if (!(flags & SUPPRESS)) {
575: *wcp = L'\0';
576: nassigned++;
577: }
578: } else
579: #endif
580: if (flags & SUPPRESS) {
581: n = 0;
582: while (!isspace(*fp->_p)) {
583: n++, fp->_r--, fp->_p++;
584: if (--width == 0)
585: break;
586: if (fp->_r <= 0 && __srefill(fp))
587: break;
588: }
589: nread += n;
590: } else {
591: p0 = p = va_arg(ap, char *);
592: while (!isspace(*fp->_p)) {
593: fp->_r--;
594: *p++ = *fp->_p++;
595: if (--width == 0)
596: break;
597: if (fp->_r <= 0 && __srefill(fp))
598: break;
599: }
600: *p = '\0';
601: nread += p - p0;
602: nassigned++;
603: }
604: continue;
605:
606: case CT_INT:
607:
608: #ifdef hardway
609: if (width == 0 || width > sizeof(buf) - 1)
610: width = sizeof(buf) - 1;
611: #else
612:
613: if (--width > sizeof(buf) - 2)
614: width = sizeof(buf) - 2;
615: width++;
616: #endif
617: flags |= SIGNOK | NDIGITS | NZDIGITS;
618: for (p = buf; width; width--) {
619: c = *fp->_p;
620: 621: 622: 623:
624: switch (c) {
625:
626: 627: 628: 629: 630: 631: 632: 633: 634: 635: 636: 637:
638: case '0':
639: if (base == 0) {
640: base = 8;
641: flags |= PFXOK;
642: }
643: if (flags & NZDIGITS)
644: flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
645: else
646: flags &= ~(SIGNOK|PFXOK|NDIGITS);
647: goto ok;
648:
649:
650: case '1': case '2': case '3':
651: case '4': case '5': case '6': case '7':
652: base = basefix[base];
653: flags &= ~(SIGNOK | PFXOK | NDIGITS);
654: goto ok;
655:
656:
657: case '8': case '9':
658: base = basefix[base];
659: if (base <= 8)
660: break;
661: flags &= ~(SIGNOK | PFXOK | NDIGITS);
662: goto ok;
663:
664:
665: case 'A': case 'B': case 'C':
666: case 'D': case 'E': case 'F':
667: case 'a': case 'b': case 'c':
668: case 'd': case 'e': case 'f':
669:
670: if (base <= 10)
671: break;
672: flags &= ~(SIGNOK | PFXOK | NDIGITS);
673: goto ok;
674:
675:
676: case '+': case '-':
677: if (flags & SIGNOK) {
678: flags &= ~SIGNOK;
679: flags |= HAVESIGN;
680: goto ok;
681: }
682: break;
683:
684: 685: 686: 687:
688: case 'x': case 'X':
689: if ((flags & PFXOK) && p ==
690: buf + 1 + !!(flags & HAVESIGN)) {
691: base = 16;
692: flags &= ~PFXOK;
693: goto ok;
694: }
695: break;
696: }
697:
698: 699: 700: 701:
702: break;
703: ok:
704: 705: 706:
707: *p++ = c;
708: if (--fp->_r > 0)
709: fp->_p++;
710: else if (__srefill(fp))
711: break;
712: }
713: 714: 715: 716: 717: 718:
719: if (flags & NDIGITS) {
720: if (p > buf)
721: (void) __sungetc(*(u_char *)--p, fp);
722: goto match_failure;
723: }
724: c = ((u_char *)p)[-1];
725: if (c == 'x' || c == 'X') {
726: --p;
727: (void) __sungetc(c, fp);
728: }
729: if ((flags & SUPPRESS) == 0) {
730: uintmax_t res;
731:
732: *p = '\0';
733: if (flags & UNSIGNED)
734: res = strtoumax(buf, NULL, base);
735: else
736: res = strtoimax(buf, NULL, base);
737: if (flags & POINTER)
738: *va_arg(ap, void **) =
739: (void *)(uintptr_t)res;
740: else if (flags & MAXINT)
741: *va_arg(ap, intmax_t *) = res;
742: else if (flags & LLONG)
743: *va_arg(ap, long long *) = res;
744: else if (flags & SIZEINT)
745: *va_arg(ap, ssize_t *) = res;
746: else if (flags & PTRINT)
747: *va_arg(ap, ptrdiff_t *) = res;
748: else if (flags & LONG)
749: *va_arg(ap, long *) = res;
750: else if (flags & SHORT)
751: *va_arg(ap, short *) = res;
752: else if (flags & SHORTSHORT)
753: *va_arg(ap, __signed char *) = res;
754: else
755: *va_arg(ap, int *) = res;
756: nassigned++;
757: }
758: nread += p - buf;
759: break;
760:
761: #ifdef FLOATING_POINT
762: case CT_FLOAT:
763:
764: #ifdef hardway
765: if (width == 0 || width > sizeof(buf) - 1)
766: width = sizeof(buf) - 1;
767: #else
768:
769: if (--width > sizeof(buf) - 2)
770: width = sizeof(buf) - 2;
771: width++;
772: #endif
773: flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
774: for (p = buf; width; width--) {
775: c = *fp->_p;
776: 777: 778: 779:
780: switch (c) {
781:
782: case '0': case '1': case '2': case '3':
783: case '4': case '5': case '6': case '7':
784: case '8': case '9':
785: flags &= ~(SIGNOK | NDIGITS);
786: goto fok;
787:
788: case '+': case '-':
789: if (flags & SIGNOK) {
790: flags &= ~SIGNOK;
791: goto fok;
792: }
793: break;
794: case '.':
795: if (flags & DPTOK) {
796: flags &= ~(SIGNOK | DPTOK);
797: goto fok;
798: }
799: break;
800: case 'e': case 'E':
801:
802: if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
803: flags =
804: (flags & ~(EXPOK|DPTOK)) |
805: SIGNOK | NDIGITS;
806: goto fok;
807: }
808: break;
809: }
810: break;
811: fok:
812: *p++ = c;
813: if (--fp->_r > 0)
814: fp->_p++;
815: else if (__srefill(fp))
816: break;
817: }
818: 819: 820: 821: 822:
823: if (flags & NDIGITS) {
824: if (flags & EXPOK) {
825:
826: while (p > buf)
827: __sungetc(*(u_char *)--p, fp);
828: goto match_failure;
829: }
830:
831: c = *(u_char *)--p;
832: if (c != 'e' && c != 'E') {
833: (void) __sungetc(c, fp);
834: c = *(u_char *)--p;
835: }
836: (void) __sungetc(c, fp);
837: }
838: if ((flags & SUPPRESS) == 0) {
839: *p = '\0';
840: if (flags & LONGDBL) {
841: long double res = strtold(buf,
842: (char **)NULL);
843: *va_arg(ap, long double *) = res;
844: } else if (flags & LONG) {
845: double res = strtod(buf, (char **)NULL);
846: *va_arg(ap, double *) = res;
847: } else {
848: float res = strtof(buf, (char **)NULL);
849: *va_arg(ap, float *) = res;
850: }
851: nassigned++;
852: }
853: nread += p - buf;
854: break;
855: #endif
856: }
857: }
858: input_failure:
859: if (nassigned == 0)
860: nassigned = -1;
861: match_failure:
862: return (nassigned);
863: }
864:
865: 866: 867: 868: 869: 870:
871: static u_char *
872: __sccl(char *tab, u_char *fmt)
873: {
874: int c, n, v;
875:
876:
877: c = *fmt++;
878: if (c == '^') {
879: v = 1;
880: c = *fmt++;
881: } else
882: v = 0;
883:
884: for (n = 0; n < 256; n++)
885: tab[n] = v;
886: if (c == 0)
887: return (fmt - 1);
888:
889: 890: 891: 892: 893: 894: 895:
896: v = 1 - v;
897: for (;;) {
898: tab[c] = v;
899: doswitch:
900: n = *fmt++;
901: switch (n) {
902:
903: case 0:
904: return (fmt - 1);
905:
906: case '-':
907: 908: 909: 910: 911: 912: 913: 914: 915: 916: 917: 918: 919: 920: 921: 922: 923: 924:
925: n = *fmt;
926: if (n == ']' || n < c) {
927: c = '-';
928: break;
929: }
930: fmt++;
931: do {
932: tab[++c] = v;
933: } while (c < n);
934: #if 1
935: 936: 937: 938: 939:
940: goto doswitch;
941: #else
942: c = *fmt++;
943: if (c == 0)
944: return (fmt - 1);
945: if (c == ']')
946: return (fmt);
947: #endif
948: break;
949:
950: case ']':
951: return (fmt);
952:
953: default:
954: c = n;
955: break;
956: }
957: }
958:
959: }
960:
961: int
962: vfscanf(FILE *fp, const char *fmt0, __va_list ap)
963: {
964: int r;
965:
966: FLOCKFILE(fp);
967: r = __svfscanf(fp, fmt0, ap);
968: FUNLOCKFILE(fp);
969: return (r);
970: }