import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / stdio / doscan.c
blob60913d6ee828cbf99a0d457ff4368f9ba74c85d1
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
30 #include "lint.h"
31 #include <sys/types.h>
32 #include "mtlib.h"
33 #include "file64.h"
34 #include <stdio.h>
35 #include <ctype.h>
36 #include <stdarg.h>
37 #include <values.h>
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <math.h>
42 #include <thread.h>
43 #include <synch.h>
44 #include <stdlib.h>
45 #include <fnmatch.h>
46 #include <limits.h>
47 #include <wchar.h>
48 #include <unistd.h>
49 #include "libc.h"
50 #include "stdiom.h"
51 #include "xpg6.h"
53 #define NCHARS (1 << BITSPERBYTE)
55 /* if the _IOWRT flag is set, this must be a call from sscanf */
56 #define locgetc(cnt) (cnt += 1, (iop->_flag & _IOWRT) ? \
57 ((*iop->_ptr == '\0') ? EOF : *iop->_ptr++) : \
58 GETC(iop))
59 #define locungetc(cnt, x) (cnt -= 1, (x == EOF) ? EOF : \
60 ((iop->_flag & _IOWRT) ? *(--iop->_ptr) : \
61 (++iop->_cnt, *(--iop->_ptr))))
63 #define wlocgetc() ((iop->_flag & _IOWRT) ? \
64 ((*iop->_ptr == '\0') ? EOF : *iop->_ptr++) : \
65 GETC(iop))
66 #define wlocungetc(x) ((x == EOF) ? EOF : \
67 ((iop->_flag & _IOWRT) ? *(--iop->_ptr) : \
68 UNGETC(x, iop)))
70 #define MAXARGS 30 /* max. number of args for fast positional paramters */
73 * stva_list is used to subvert C's restriction that a variable with an
74 * array type can not appear on the left hand side of an assignment operator.
75 * By putting the array inside a structure, the functionality of assigning to
76 * the whole array through a simple assignment is achieved..
78 typedef struct stva_list {
79 va_list ap;
80 } stva_list;
82 static int number(int *, int *, int, int, int, int, FILE *, va_list *);
83 static int readchar(FILE *, int *);
84 static int string(int *, int *, int, int, int, char *, FILE *, va_list *);
85 static int wstring(int *, int *, int, int, int, FILE *, va_list *);
86 static int wbrstring(int *, int *, int, int, int, FILE *,
87 unsigned char *, va_list *);
88 #ifdef _WIDE
89 static int brstring(int *, int *, int, int, int, FILE *,
90 unsigned char *, va_list *);
91 #endif
92 static int _bi_getwc(FILE *);
93 static int _bi_ungetwc(wint_t, FILE *);
95 #ifdef _WIDE
96 static int _mkarglst(const wchar_t *, stva_list, stva_list[]);
97 static wint_t _wd_getwc(int *, FILE *);
98 static wint_t _wd_ungetwc(int *, wchar_t, FILE *);
99 static int _watoi(wchar_t *);
100 #else /* _WIDE */
101 static int _mkarglst(const char *, stva_list, stva_list[]);
102 #endif /* _WIDE */
104 #ifndef _WIDE
106 _doscan(FILE *iop, const char *fmt, va_list va_Alist)
108 int ret;
109 rmutex_t *lk;
111 if (iop->_flag & _IOWRT)
112 ret = __doscan_u(iop, fmt, va_Alist, 0);
113 else {
114 FLOCKFILE(lk, iop);
115 ret = __doscan_u(iop, fmt, va_Alist, 0);
116 FUNLOCKFILE(lk);
118 return (ret);
120 #endif /* _WIDE */
122 /* ARGSUSED3 */
123 #ifdef _WIDE
125 __wdoscan_u(FILE *iop, const wchar_t *fmt, va_list va_Alist, int scflag)
126 #else /* _WIDE */
128 __doscan_u(FILE *iop, const char *sfmt, va_list va_Alist, int scflag)
129 #endif /* _WIDE */
131 #ifdef _WIDE
132 wchar_t ch;
133 wchar_t inchar, size;
134 int nmatch = 0, len, stow;
135 #else /* _WIDE */
136 int ch;
137 int nmatch = 0, len, inchar, stow, size;
138 #endif /* _WIDE */
140 unsigned char *bracket_str = NULL;
141 int chcount, flag_eof;
142 char tab[NCHARS];
144 /* variables for postional parameters */
145 #ifdef _WIDE
146 const wchar_t *sformat = fmt; /* save the beginning of the format */
147 #else /* _WIDE */
148 const unsigned char *fmt = (const unsigned char *)sfmt;
149 const char *sformat = sfmt; /* save the beginning of the format */
150 #endif /* _WIDE */
151 int fpos = 1; /* 1 if first postional parameter */
152 stva_list args; /* used to step through the argument list */
153 stva_list sargs; /* used to save start of the argument list */
154 stva_list arglst[MAXARGS];
156 * array giving the appropriate values
157 * for va_arg() to retrieve the
158 * corresponding argument:
159 * arglst[0] is the first argument
160 * arglst[1] is the second argument,etc.
162 /* Check if readable stream */
163 if (!(iop->_flag & (_IOREAD | _IORW))) {
164 errno = EBADF;
165 return (EOF);
169 * Initialize args and sargs to the start of the argument list.
170 * We don't know any portable way to copy an arbitrary C object
171 * so we use a system-specific routine(probably a macro) from
172 * stdarg.h. (Remember that if va_list is an array, in_args will
173 * be a pointer and &in_args won't be what we would want for
174 * memcpy.)
176 va_copy(args.ap, va_Alist);
178 sargs = args;
180 chcount = 0; flag_eof = 0;
183 * ****************************************************
184 * Main loop: reads format to determine a pattern,
185 * and then goes to read input stream
186 * in attempt to match the pattern.
187 * ****************************************************
189 for (; ; ) {
190 if ((ch = *fmt++) == '\0') {
191 return (nmatch); /* end of format */
193 #ifdef _WIDE
194 if (iswspace(ch)) {
195 if (!flag_eof) {
196 while (iswspace(inchar =
197 _wd_getwc(&chcount, iop)))
199 if (_wd_ungetwc(&chcount, inchar, iop) == WEOF)
200 flag_eof = 1;
202 continue;
204 if (ch != '%' || (ch = *fmt++) == '%') {
205 if (ch == '%') {
206 if (!flag_eof) {
207 while (iswspace(inchar =
208 _wd_getwc(&chcount, iop)))
210 if (_wd_ungetwc(&chcount, inchar, iop)
211 == WEOF)
212 flag_eof = 1;
215 if ((inchar = _wd_getwc(&chcount, iop)) == ch)
216 continue;
217 if (_wd_ungetwc(&chcount, inchar, iop) != WEOF) {
218 return (nmatch); /* failed to match input */
220 break;
222 #else /* _WIDE */
223 if (isspace(ch)) {
224 if (!flag_eof) {
225 while (isspace(inchar = locgetc(chcount)))
227 if (locungetc(chcount, inchar) == EOF)
228 flag_eof = 1;
231 continue;
233 if (ch != '%' || (ch = *fmt++) == '%') {
234 if (ch == '%') {
235 if (!flag_eof) {
236 while (isspace(inchar =
237 locgetc(chcount)))
239 if (locungetc(chcount, inchar) == EOF)
240 flag_eof = 1;
243 if ((inchar = locgetc(chcount)) == ch)
244 continue;
245 if (locungetc(chcount, inchar) != EOF) {
246 return (nmatch); /* failed to match input */
248 break;
250 #endif /* _WIDE */
252 charswitch: /* target of a goto 8-( */
254 if (ch == '*') {
255 stow = 0;
256 ch = *fmt++;
257 } else
258 stow = 1;
260 #ifdef _WIDE
261 for (len = 0; ((ch >= 0) && (ch < 256) && isdigit(ch));
262 ch = *fmt++)
263 len = len * 10 + ch - '0';
264 #else /* _WIDE */
265 for (len = 0; isdigit(ch); ch = *fmt++)
266 len = len * 10 + ch - '0';
267 #endif /* _WIDE */
269 if (ch == '$') {
271 * positional parameter handling - the number
272 * specified in len gives the argument to which
273 * the next conversion should be applied.
274 * WARNING: This implementation of positional
275 * parameters assumes that the sizes of all pointer
276 * types are the same. (Code similar to that
277 * in the portable doprnt.c should be used if this
278 * assumption does not hold for a particular
279 * port.)
281 if (fpos) {
282 if (_mkarglst(sformat, sargs, arglst) != 0) {
283 return (EOF);
284 } else {
285 fpos = 0;
288 if (len <= MAXARGS) {
289 args = arglst[len - 1];
290 } else {
291 args = arglst[MAXARGS - 1];
292 for (len -= MAXARGS; len > 0; len--)
293 (void) va_arg(args.ap, void *);
295 len = 0;
296 ch = *fmt++;
297 goto charswitch;
300 if (len == 0)
301 len = MAXINT;
302 #ifdef _WIDE
303 if ((size = ch) == 'l' || (size == 'h') || (size == 'L') ||
304 (size == 'j') || (size == 't') || (size == 'z'))
305 ch = *fmt++;
306 #else /* _WIDE */
307 if ((size = ch) == 'l' || (size == 'h') || (size == 'L') ||
308 (size == 'w') || (size == 'j') || (size == 't') ||
309 (size == 'z'))
310 ch = *fmt++;
311 #endif /* _WIDE */
312 if (size == 'l' && ch == 'l') {
313 size = 'm'; /* size = 'm' if long long */
314 ch = *fmt++;
315 } else if (size == 'h' && ch == 'h') {
316 size = 'b'; /* use size = 'b' if char */
317 ch = *fmt++;
318 } else if ((size == 't') || (size == 'z')) {
319 size = 'l';
320 } else if (size == 'j') {
321 #ifndef _LP64
322 /* check scflag for size of u/intmax_t (32-bit libc) */
323 if (!(scflag & _F_INTMAX32)) {
324 #endif
325 size = 'm';
326 #ifndef _LP64
328 #endif
330 if (ch == '\0') {
331 return (EOF); /* unexpected end of format */
333 #ifdef _WIDE
334 if (ch == '[') {
335 wchar_t c;
336 size_t len;
337 int negflg = 0;
338 wchar_t *p;
339 wchar_t *wbracket_str;
340 size_t wlen, clen;
342 /* p points to the address of '[' */
343 p = (wchar_t *)fmt - 1;
344 len = 0;
345 if (*fmt == '^') {
346 len++;
347 fmt++;
348 negflg = 1;
350 if (((c = *fmt) == ']') || (c == '-')) {
351 len++;
352 fmt++;
354 while ((c = *fmt) != ']') {
355 if (c == '\0') {
356 return (EOF); /* unexpected EOF */
357 } else {
358 len++;
359 fmt++;
362 fmt++;
363 len += 2;
364 wbracket_str = (wchar_t *)
365 malloc(sizeof (wchar_t) * (len + 1));
366 if (wbracket_str == NULL) {
367 errno = ENOMEM;
368 return (EOF);
369 } else {
370 (void) wmemcpy(wbracket_str,
371 (const wchar_t *)p, len);
372 *(wbracket_str + len) = L'\0';
373 if (negflg && *(wbracket_str + 1) == '^') {
374 *(wbracket_str + 1) = L'!';
377 wlen = wcslen(wbracket_str);
378 clen = wcstombs(NULL, wbracket_str, 0);
379 if (clen == (size_t)-1) {
380 free(wbracket_str);
381 return (EOF);
383 bracket_str = (unsigned char *)
384 malloc(sizeof (unsigned char) * (clen + 1));
385 if (bracket_str == NULL) {
386 free(wbracket_str);
387 errno = ENOMEM;
388 return (EOF);
390 clen = wcstombs((char *)bracket_str, wbracket_str,
391 wlen + 1);
392 free(wbracket_str);
393 if (clen == (size_t)-1) {
394 free(bracket_str);
395 return (EOF);
398 #else /* _WIDE */
399 if (ch == '[') {
400 if (size == 'l') {
401 int c, len, i;
402 int negflg = 0;
403 unsigned char *p;
405 p = (unsigned char *)(fmt - 1);
406 len = 0;
407 if (*fmt == '^') {
408 len++;
409 fmt++;
410 negflg = 1;
412 if (((c = *fmt) == ']') || (c == '-')) {
413 len++;
414 fmt++;
416 while ((c = *fmt) != ']') {
417 if (c == '\0') {
418 return (EOF);
419 } else if (isascii(c)) {
420 len++;
421 fmt++;
422 } else {
423 i = mblen((const char *)fmt,
424 MB_CUR_MAX);
425 if (i <= 0) {
426 return (EOF);
427 } else {
428 len += i;
429 fmt += i;
433 fmt++;
434 len += 2;
435 bracket_str = (unsigned char *)
436 malloc(sizeof (unsigned char) * (len + 1));
437 if (bracket_str == NULL) {
438 errno = ENOMEM;
439 return (EOF);
440 } else {
441 (void) strncpy((char *)bracket_str,
442 (const char *)p, len);
443 *(bracket_str + len) = '\0';
444 if (negflg &&
445 *(bracket_str + 1) == '^') {
446 *(bracket_str + 1) = '!';
449 } else {
450 int t = 0;
451 int b, c, d;
453 if (*fmt == '^') {
454 t++;
455 fmt++;
457 (void) memset(tab, !t, NCHARS);
458 if ((c = *fmt) == ']' || c == '-') {
459 tab[c] = t;
460 fmt++;
463 while ((c = *fmt) != ']') {
464 if (c == '\0') {
465 return (EOF);
467 b = *(fmt - 1);
468 d = *(fmt + 1);
469 if ((c == '-') && (d != ']') &&
470 (b < d)) {
471 (void) memset(&tab[b], t,
472 d - b + 1);
473 fmt += 2;
474 } else {
475 tab[c] = t;
476 fmt++;
479 fmt++;
482 #endif /* _WIDE */
484 #ifdef _WIDE
485 if ((ch >= 0) && (ch < 256) &&
486 isupper((int)ch)) { /* no longer documented */
487 if (_lib_version == c_issue_4) {
488 if (size != 'm' && size != 'L')
489 size = 'l';
491 ch = _tolower((int)ch);
493 if (ch != 'n' && !flag_eof) {
494 if (ch != 'c' && ch != 'C' && ch != '[') {
495 while (iswspace(inchar =
496 _wd_getwc(&chcount, iop)))
498 if (_wd_ungetwc(&chcount, inchar, iop) == WEOF)
499 break;
503 #else /* _WIDE */
504 if (isupper(ch)) { /* no longer documented */
505 if (_lib_version == c_issue_4) {
506 if (size != 'm' && size != 'L')
507 size = 'l';
509 ch = _tolower(ch);
511 if (ch != 'n' && !flag_eof) {
512 if (ch != 'c' && ch != 'C' && ch != '[') {
513 while (isspace(inchar = locgetc(chcount)))
515 if (locungetc(chcount, inchar) == EOF)
516 break;
519 #endif /* _WIDE */
521 switch (ch) {
522 case 'C':
523 case 'S':
524 case 'c':
525 case 's':
526 #ifdef _WIDE
527 if ((size == 'l') || (size == 'C') || (size == 'S'))
528 #else /* _WIDE */
529 if ((size == 'w') || (size == 'l') || (size == 'C') ||
530 (size == 'S'))
531 #endif /* _WIDE */
533 size = wstring(&chcount, &flag_eof, stow,
534 (int)ch, len, iop, &args.ap);
535 } else {
536 size = string(&chcount, &flag_eof, stow,
537 (int)ch, len, tab, iop, &args.ap);
539 break;
540 case '[':
541 if (size == 'l') {
542 size = wbrstring(&chcount, &flag_eof, stow,
543 (int)ch, len, iop, bracket_str, &args.ap);
544 free(bracket_str);
545 bracket_str = NULL;
546 } else {
547 #ifdef _WIDE
548 size = brstring(&chcount, &flag_eof, stow,
549 (int)ch, len, iop, bracket_str, &args.ap);
550 free(bracket_str);
551 bracket_str = NULL;
552 #else /* _WIDE */
553 size = string(&chcount, &flag_eof, stow,
554 ch, len, tab, iop, &args.ap);
555 #endif /* _WIDE */
557 break;
559 case 'n':
560 if (stow == 0)
561 continue;
562 if (size == 'b') /* char */
563 *va_arg(args.ap, char *) = (char)chcount;
564 else if (size == 'h')
565 *va_arg(args.ap, short *) = (short)chcount;
566 else if (size == 'l')
567 *va_arg(args.ap, long *) = (long)chcount;
568 else if (size == 'm') /* long long */
569 *va_arg(args.ap, long long *) =
570 (long long) chcount;
571 else
572 *va_arg(args.ap, int *) = (int)chcount;
573 continue;
575 case 'i':
576 default:
577 size = number(&chcount, &flag_eof, stow, (int)ch,
578 len, (int)size, iop, &args.ap);
579 break;
581 if (size)
582 nmatch += stow;
583 else {
584 return ((flag_eof && !nmatch) ? EOF : nmatch);
586 continue;
588 free(bracket_str);
589 return (nmatch != 0 ? nmatch : EOF); /* end of input */
592 /* ****************************************************************** */
593 /* Functions to read the input stream in an attempt to match incoming */
594 /* data to the current pattern from the main loop of _doscan(). */
595 /* ****************************************************************** */
596 static int
597 number(int *chcount, int *flag_eof, int stow, int type, int len, int size,
598 FILE *iop, va_list *listp)
600 char numbuf[64];
601 char *np = numbuf;
602 int c, base, inchar, lookahead;
603 int digitseen = 0, floater = 0, negflg = 0;
604 int lc;
605 long long lcval = 0LL;
607 switch (type) {
608 case 'e':
609 case 'f':
610 case 'g':
612 * lc = 0 corresponds to c90 mode: do not recognize
613 * hexadecimal fp strings; attempt to push back
614 * all unused characters read
616 * lc = -1 corresponds to c99 mode: recognize hexa-
617 * decimal fp strings; push back at most one
618 * unused character
620 lc = (__xpg6 & _C99SUSv3_recognize_hexfp)? -1 : 0;
621 floater = 1;
622 break;
624 case 'a':
625 lc = -1;
626 floater = 1;
627 break;
629 case 'd':
630 case 'u':
631 case 'i':
632 base = 10;
633 break;
634 case 'o':
635 base = 8;
636 break;
637 case 'p':
638 #ifdef _LP64
639 size = 'l'; /* pointers are long in LP64 */
640 #endif /* _LP64 */
641 /* FALLTHROUGH */
642 case 'x':
643 base = 16;
644 break;
645 default:
646 return (0); /* unrecognized conversion character */
649 if (floater != 0) {
651 * Handle floating point with
652 * file_to_decimal.
654 decimal_mode dm;
655 decimal_record dr;
656 fp_exception_field_type efs;
657 enum decimal_string_form form;
658 char *echar;
659 int nread;
660 char buffer[1024+1];
661 char *nb = buffer;
663 if (len > 1024)
664 len = 1024;
665 file_to_decimal(&nb, len, lc, &dr, &form, &echar, iop, &nread);
666 if (lc == -1) {
668 * In C99 mode, the entire string read has to be
669 * accepted in order to qualify as a match
671 if (nb != buffer + nread)
672 form = invalid_form;
674 if (stow && (form != invalid_form)) {
675 #if defined(__sparc)
676 dm.rd = _QgetRD();
677 if (size == 'L') { /* long double */
678 if ((int)form < 0)
679 __hex_to_quadruple(&dr, dm.rd,
680 va_arg(*listp, quadruple *), &efs);
681 else
682 decimal_to_quadruple(
683 va_arg(*listp, quadruple *),
684 &dm, &dr, &efs);
686 #elif defined(__i386) || defined(__amd64)
687 dm.rd = __xgetRD();
688 if (size == 'L') { /* long double */
689 if ((int)form < 0)
690 __hex_to_extended(&dr, dm.rd,
691 va_arg(*listp, extended *), &efs);
692 else
693 decimal_to_extended(
694 va_arg(*listp, extended *),
695 &dm, &dr, &efs);
697 #else
698 #error Unknown architecture
699 #endif
700 else if (size == 'l') { /* double */
701 if ((int)form < 0)
702 __hex_to_double(&dr, dm.rd,
703 va_arg(*listp, double *), &efs);
704 else
705 decimal_to_double(
706 va_arg(*listp, double *),
707 &dm, &dr, &efs);
708 } else { /* float */
709 if ((int)form < 0)
710 __hex_to_single(&dr, dm.rd,
711 va_arg(*listp, single *), &efs);
712 else
713 decimal_to_single((single *)
714 va_arg(*listp, single *),
715 &dm, &dr, &efs);
717 if ((efs & (1 << fp_overflow)) != 0) {
718 errno = ERANGE;
720 if ((efs & (1 << fp_underflow)) != 0) {
721 errno = ERANGE;
724 (*chcount) += nread; /* Count characters read. */
725 c = locgetc((*chcount));
726 if (locungetc((*chcount), c) == EOF)
727 *flag_eof = 1;
728 return ((form == invalid_form) ? 0 : 1);
729 /* successful match if non-zero */
732 switch (c = locgetc((*chcount))) {
733 case '-':
734 negflg++;
735 /* FALLTHROUGH */
736 case '+':
737 if (--len <= 0)
738 break;
739 if ((c = locgetc((*chcount))) != '0')
740 break;
741 /* FALLTHROUGH */
742 case '0':
744 * If %i or %x, the characters 0x or 0X may optionally precede
745 * the sequence of letters and digits (base 16).
747 if ((type != 'i' && type != 'x') || (len <= 1))
748 break;
749 if (((inchar = locgetc((*chcount))) == 'x') ||
750 (inchar == 'X')) {
751 lookahead = readchar(iop, chcount);
752 if (isxdigit(lookahead)) {
753 base = 16;
755 if (len <= 2) {
756 (void) locungetc((*chcount), lookahead);
757 /* Take into account the 'x' */
758 len -= 1;
759 } else {
760 c = lookahead;
761 /* Take into account '0x' */
762 len -= 2;
764 } else {
765 (void) locungetc((*chcount), lookahead);
766 (void) locungetc((*chcount), inchar);
768 } else {
769 /* inchar wans't 'x'. */
770 (void) locungetc((*chcount), inchar); /* Put it back. */
771 if (type == 'i') /* Only %i accepts an octal. */
772 base = 8;
775 for (; --len >= 0; *np++ = (char)c, c = locgetc((*chcount))) {
776 if (np > numbuf + 62) {
777 errno = ERANGE;
778 return (0);
780 if (isdigit(c) || base == 16 && isxdigit(c)) {
781 int digit = c - (isdigit(c) ? '0' :
782 isupper(c) ? 'A' - 10 : 'a' - 10);
783 if (digit >= base)
784 break;
785 if (stow)
786 lcval = base * lcval + digit;
787 digitseen++;
788 continue;
790 break;
793 if (stow && digitseen) {
794 /* suppress possible overflow on 2's-comp negation */
795 if (negflg && lcval != (1ULL << 63))
796 lcval = -lcval;
797 switch (size) {
798 case 'm':
799 *va_arg(*listp, long long *) = lcval;
800 break;
801 case 'l':
802 *va_arg(*listp, long *) = (long)lcval;
803 break;
804 case 'h':
805 *va_arg(*listp, short *) = (short)lcval;
806 break;
807 case 'b':
808 *va_arg(*listp, char *) = (char)lcval;
809 break;
810 default:
811 *va_arg(*listp, int *) = (int)lcval;
812 break;
815 if (locungetc((*chcount), c) == EOF)
816 *flag_eof = 1;
817 return (digitseen); /* successful match if non-zero */
820 /* Get a character. If not using sscanf and at the buffer's end */
821 /* then do a direct read(). Characters read via readchar() */
822 /* can be pushed back on the input stream by locungetc((*chcount),) */
823 /* since there is padding allocated at the end of the stream buffer. */
824 static int
825 readchar(FILE *iop, int *chcount)
827 int inchar;
828 char buf[1];
830 if ((iop->_flag & _IOWRT) || (iop->_cnt != 0))
831 inchar = locgetc((*chcount));
832 else {
833 if (read(FILENO(iop), buf, 1) != 1)
834 return (EOF);
835 inchar = (int)buf[0];
836 (*chcount) += 1;
838 return (inchar);
841 static int
842 string(int *chcount, int *flag_eof, int stow, int type, int len, char *tab,
843 FILE *iop, va_list *listp)
845 int ch;
846 char *ptr;
847 char *start;
849 start = ptr = stow ? va_arg(*listp, char *) : NULL;
850 if (((type == 'c') || (type == 'C')) && len == MAXINT)
851 len = 1;
852 #ifdef _WIDE
853 while ((ch = locgetc((*chcount))) != EOF &&
854 !(((type == 's') || (type == 'S')) && isspace(ch))) {
855 #else /* _WIDE */
856 while ((ch = locgetc((*chcount))) != EOF &&
857 !(((type == 's') || (type == 'S')) &&
858 isspace(ch) || type == '[' && tab[ch])) {
859 #endif /* _WIDE */
860 if (stow)
861 *ptr = (char)ch;
862 ptr++;
863 if (--len <= 0)
864 break;
866 if (ch == EOF) {
867 (*flag_eof) = 1;
868 (*chcount) -= 1;
869 } else if (len > 0 && locungetc((*chcount), ch) == EOF)
870 (*flag_eof) = 1;
871 if (ptr == start)
872 return (0); /* no match */
873 if (stow && ((type != 'c') && (type != 'C')))
874 *ptr = '\0';
875 return (1); /* successful match */
878 /* This function initializes arglst, to contain the appropriate */
879 /* va_list values for the first MAXARGS arguments. */
880 /* WARNING: this code assumes that the sizes of all pointer types */
881 /* are the same. (Code similar to that in the portable doprnt.c */
882 /* should be used if this assumption is not true for a */
883 /* particular port.) */
885 #ifdef _WIDE
886 static int
887 _mkarglst(const wchar_t *fmt, stva_list args, stva_list arglst[])
888 #else /* _WIDE */
889 static int
890 _mkarglst(const char *fmt, stva_list args, stva_list arglst[])
891 #endif /* _WIDE */
893 #ifdef _WIDE
894 #define STRCHR wcschr
895 #define STRSPN wcsspn
896 #define ATOI(x) _watoi((wchar_t *)x)
897 #define SPNSTR1 L"01234567890"
898 #define SPNSTR2 L"# +-.0123456789hL$"
899 #else /* _WIDE */
900 #define STRCHR strchr
901 #define STRSPN strspn
902 #define ATOI(x) atoi(x)
903 #define SPNSTR1 "01234567890"
904 #define SPNSTR2 "# +-.0123456789hL$"
905 #endif /* _WIDE */
907 int maxnum, curargno;
908 size_t n;
910 maxnum = -1;
911 curargno = 0;
913 while ((fmt = STRCHR(fmt, '%')) != NULL) {
914 fmt++; /* skip % */
915 if (*fmt == '*' || *fmt == '%')
916 continue;
917 if (fmt[n = STRSPN(fmt, SPNSTR1)] == L'$') {
918 /* convert to zero base */
919 curargno = ATOI(fmt) - 1;
920 fmt += n + 1;
923 if (maxnum < curargno)
924 maxnum = curargno;
925 curargno++; /* default to next in list */
927 fmt += STRSPN(fmt, SPNSTR2);
928 if (*fmt == '[') {
929 int i;
930 fmt++; /* has to be at least on item in scan list */
931 if (*fmt == ']') {
932 fmt++;
934 while (*fmt != ']') {
935 if (*fmt == L'\0') {
936 return (-1); /* bad format */
937 #ifdef _WIDE
938 } else {
939 fmt++;
941 #else /* _WIDE */
942 } else if (isascii(*fmt)) {
943 fmt++;
944 } else {
945 i = mblen((const char *)
946 fmt, MB_CUR_MAX);
947 if (i <= 0) {
948 return (-1);
949 } else {
950 fmt += i;
953 #endif /* _WIDE */
957 if (maxnum > MAXARGS)
958 maxnum = MAXARGS;
959 for (n = 0; n <= maxnum; n++) {
960 arglst[n] = args;
961 (void) va_arg(args.ap, void *);
963 return (0);
968 * For wide character handling
971 #ifdef _WIDE
972 static int
973 wstring(int *chcount, int *flag_eof, int stow, int type,
974 int len, FILE *iop, va_list *listp)
976 wint_t wch;
977 wchar_t *ptr;
978 wchar_t *wstart;
979 int dummy;
981 wstart = ptr = stow ? va_arg(*listp, wchar_t *) : NULL;
983 if ((type == 'c') && len == MAXINT)
984 len = 1;
985 while (((wch = _wd_getwc(chcount, iop)) != WEOF) &&
986 !(type == 's' && iswspace(wch))) {
987 if (stow)
988 *ptr = wch;
989 ptr++;
990 if (--len <= 0)
991 break;
993 if (wch == WEOF) {
994 *flag_eof = 1;
995 (*chcount) -= 1;
996 } else {
997 if (len > 0 && _wd_ungetwc(chcount, wch, iop) == WEOF)
998 *flag_eof = 1;
1000 if (ptr == wstart)
1001 return (0); /* no match */
1002 if (stow && (type != 'c'))
1003 *ptr = '\0';
1004 return (1); /* successful match */
1007 #else /* _WIDE */
1008 static int
1009 wstring(int *chcount, int *flag_eof, int stow, int type, int len, FILE *iop,
1010 va_list *listp)
1012 int wch;
1013 wchar_t *ptr;
1014 wchar_t *wstart;
1016 wstart = ptr = stow ? va_arg(*listp, wchar_t *) : NULL;
1018 if ((type == 'c') && len == MAXINT)
1019 len = 1;
1020 while (((wch = _bi_getwc(iop)) != EOF) &&
1021 !(type == 's' && (isascii(wch) ? isspace(wch) : 0))) {
1022 (*chcount) += _scrwidth((wchar_t)wch);
1023 if (stow)
1024 *ptr = wch;
1025 ptr++;
1026 if (--len <= 0)
1027 break;
1029 if (wch == EOF) {
1030 (*flag_eof) = 1;
1031 (*chcount) -= 1;
1032 } else {
1033 if (len > 0 && _bi_ungetwc(wch, iop) == EOF)
1034 (*flag_eof) = 1;
1036 if (ptr == wstart)
1037 return (0); /* no match */
1038 if (stow && (type != 'c'))
1039 *ptr = '\0';
1040 return (1); /* successful match */
1042 #endif /* _WIDE */
1044 #ifdef _WIDE
1045 static wint_t
1046 _wd_getwc(int *chcount, FILE *iop)
1048 wint_t wc;
1049 int len;
1051 if (!(iop->_flag & _IOWRT)) {
1052 /* call from fwscanf, wscanf */
1053 wc = __fgetwc_xpg5(iop);
1054 (*chcount)++;
1055 return (wc);
1056 } else {
1057 /* call from swscanf */
1058 if (*iop->_ptr == '\0')
1059 return (WEOF);
1060 len = mbtowc((wchar_t *)&wc, (const char *)iop->_ptr,
1061 MB_CUR_MAX);
1062 if (len == -1)
1063 return (WEOF);
1064 iop->_ptr += len;
1065 (*chcount)++;
1066 return (wc);
1070 static wint_t
1071 _wd_ungetwc(int *chcount, wchar_t wc, FILE *iop)
1073 wint_t ret;
1074 int len;
1075 char mbs[MB_LEN_MAX];
1077 if (wc == WEOF)
1078 return (WEOF);
1080 if (!(iop->_flag & _IOWRT)) {
1081 /* call from fwscanf, wscanf */
1082 ret = __ungetwc_xpg5((wint_t)wc, iop);
1083 if (ret != (wint_t)wc)
1084 return (WEOF);
1085 (*chcount)--;
1086 return (ret);
1087 } else {
1088 /* call from swscanf */
1089 len = wctomb(mbs, wc);
1090 if (len == -1)
1091 return (WEOF);
1092 iop->_ptr -= len;
1093 (*chcount)--;
1094 return ((wint_t)wc);
1098 static int
1099 _watoi(wchar_t *fmt)
1101 int n = 0;
1102 wchar_t ch;
1104 ch = *fmt;
1105 if ((ch >= 0) && (ch < 256) && isdigit((int)ch)) {
1106 n = ch - '0';
1107 while (((ch = *++fmt) >= 0) && (ch < 256) &&
1108 isdigit((int)ch)) {
1109 n *= 10;
1110 n += ch - '0';
1113 return (n);
1115 #endif /* _WIDE */
1117 /* ARGSUSED3 */
1118 static int
1119 wbrstring(int *chcount, int *flag_eof, int stow, int type,
1120 int len, FILE *iop, unsigned char *brstr, va_list *listp)
1122 wint_t wch;
1123 int i;
1124 char str[MB_LEN_MAX + 1]; /* include null termination */
1125 wchar_t *ptr, *start;
1126 #ifdef _WIDE
1127 int dummy;
1128 #endif /* _WIDE */
1130 start = ptr = stow ? va_arg(*listp, wchar_t *) : NULL;
1132 #ifdef _WIDE
1133 while ((wch = _wd_getwc(&dummy, iop)) != WEOF) {
1134 #else /* _WIDE */
1135 while ((wch = _bi_getwc(iop)) != WEOF) {
1136 #endif /* _WIDE */
1137 i = wctomb(str, (wchar_t)wch);
1138 if (i == -1) {
1139 return (0);
1141 str[i] = '\0';
1142 if (fnmatch((const char *)brstr, (const char *)str,
1143 FNM_NOESCAPE)) {
1144 break;
1145 } else {
1146 if (len > 0) {
1147 #ifdef _WIDE
1148 (*chcount)++;
1149 #else /* _WIDE */
1150 (*chcount) += _scrwidth(wch);
1151 #endif /* _WIDE */
1152 len--;
1153 if (stow) {
1154 *ptr = wch;
1156 ptr++;
1157 if (len <= 0)
1158 break;
1159 } else {
1160 break;
1164 if (wch == WEOF) {
1165 *flag_eof = 1;
1166 } else {
1167 #ifdef _WIDE
1168 if (len > 0 && _wd_ungetwc(&dummy, wch, iop) == WEOF)
1169 #else /* _WIDE */
1170 if (len > 0 && _bi_ungetwc(wch, iop) == WEOF)
1171 #endif /* _WIDE */
1172 *flag_eof = 1;
1174 if (ptr == start)
1175 return (0); /* no match */
1176 if (stow)
1177 *ptr = L'\0';
1178 return (1); /* successful match */
1181 #ifdef _WIDE
1182 static int
1183 brstring(int *chcount, int *flag_eof, int stow, int type,
1184 int len, FILE *iop, unsigned char *brstr, va_list *listp)
1186 wint_t wch;
1187 int i;
1188 char str[MB_LEN_MAX + 1]; /* include null termination */
1189 char *ptr, *start, *p;
1190 int dummy;
1192 start = ptr = stow ? va_arg(*listp, char *) : NULL;
1194 while ((wch = _wd_getwc(&dummy, iop)) != WEOF) {
1195 p = str;
1196 i = wctomb(str, (wchar_t)wch);
1197 if (i == -1) {
1198 return (0);
1200 str[i] = '\0';
1201 if (fnmatch((const char *)brstr, (const char *)str,
1202 FNM_NOESCAPE)) {
1203 break;
1204 } else {
1205 if (len >= i) {
1206 (*chcount)++;
1207 len -= i;
1208 if (stow) {
1209 while (i-- > 0) {
1210 *ptr++ = *p++;
1212 } else {
1213 while (i-- > 0) {
1214 ptr++;
1217 if (len <= 0)
1218 break;
1219 } else {
1220 break;
1224 if (wch == WEOF) {
1225 *flag_eof = 1;
1226 } else {
1227 if (len > 0 && _wd_ungetwc(&dummy, wch, iop) == WEOF)
1228 *flag_eof = 1;
1230 if (ptr == start)
1231 return (0); /* no match */
1232 if (stow)
1233 *ptr = '\0';
1234 return (1); /* successful match */
1236 #endif /* _WIDE */
1239 * Locally define getwc and ungetwc
1241 static int
1242 _bi_getwc(FILE *iop)
1244 int c;
1245 wchar_t intcode;
1246 int i, nbytes, cur_max;
1247 char buff[MB_LEN_MAX];
1249 if ((c = wlocgetc()) == EOF)
1250 return (WEOF);
1252 if (isascii(c)) /* ASCII code */
1253 return ((wint_t)c);
1255 buff[0] = (char)c;
1257 cur_max = (int)MB_CUR_MAX;
1258 /* MB_CUR_MAX doen't exeed the value of MB_LEN_MAX */
1259 /* So we use MB_CUR_MAX instead of MB_LEN_MAX for */
1260 /* improving the performance. */
1261 for (i = 1; i < cur_max; i++) {
1262 c = wlocgetc();
1263 if (c == '\n') {
1264 (void) wlocungetc(c);
1265 break;
1267 if (c == EOF) {
1268 /* this still may be a valid multibyte character */
1269 break;
1271 buff[i] = (char)c;
1274 if ((nbytes = mbtowc(&intcode, buff, i)) == -1) {
1276 * If mbtowc fails, the input was not a legal character.
1277 * ungetc all but one character.
1279 * Note: the number of pushback characters that
1280 * ungetc() can handle must be >= (MB_LEN_MAX - 1).
1281 * In Solaris 2.x, the number of pushback
1282 * characters is 4.
1284 while (i-- > 1) {
1285 (void) wlocungetc((signed char)buff[i]);
1287 errno = EILSEQ;
1288 return (WEOF); /* Illegal EUC sequence. */
1291 while (i-- > nbytes) {
1293 * Note: the number of pushback characters that
1294 * ungetc() can handle must be >= (MB_LEN_MAX - 1).
1295 * In Solaris 2.x, the number of pushback
1296 * characters is 4.
1298 (void) wlocungetc((signed char)buff[i]);
1300 return ((int)intcode);
1303 static int
1304 _bi_ungetwc(wint_t wc, FILE *iop)
1306 char mbs[MB_LEN_MAX];
1307 unsigned char *p;
1308 int n;
1310 if ((wc == WEOF) || ((iop->_flag & _IOREAD) == 0))
1311 return (WEOF);
1313 n = wctomb(mbs, (wchar_t)wc);
1314 if (n <= 0)
1315 return (WEOF);
1317 if (iop->_ptr <= iop->_base) {
1318 if (iop->_base == NULL) {
1319 return (WEOF);
1321 if ((iop->_ptr == iop->_base) && (iop->_cnt == 0)) {
1322 ++iop->_ptr;
1323 } else if ((iop->_ptr - n) < (iop->_base - PUSHBACK)) {
1324 return (WEOF);
1328 p = (unsigned char *)(mbs+n-1); /* p points the last byte */
1329 /* if _IOWRT is set to iop->_flag, it means this is */
1330 /* an invocation from sscanf(), and in that time we */
1331 /* don't touch iop->_cnt. Otherwise, which means an */
1332 /* invocation from fscanf() or scanf(), we touch iop->_cnt */
1333 if ((iop->_flag & _IOWRT) == 0) {
1334 /* scanf() and fscanf() */
1335 iop->_cnt += n;
1336 while (n--) {
1337 *--iop->_ptr = *(p--);
1339 } else {
1340 /* sscanf() */
1341 iop->_ptr -= n;
1343 return (wc);