Home | History | Annotate | Download | only in stdio
      1 /*
      2  * CDDL HEADER START
      3  *
      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.
      7  *
      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.
     12  *
     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]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1988 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     31 
     32 #include "lint.h"
     33 #include <sys/types.h>
     34 #include "mtlib.h"
     35 #include "file64.h"
     36 #include <stdio.h>
     37 #include <ctype.h>
     38 #include <stdarg.h>
     39 #include <values.h>
     40 #include <errno.h>
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include <math.h>
     44 #include <thread.h>
     45 #include <synch.h>
     46 #include <stdlib.h>
     47 #include <fnmatch.h>
     48 #include <limits.h>
     49 #include <wchar.h>
     50 #include <unistd.h>
     51 #include "libc.h"
     52 #include "stdiom.h"
     53 #include "xpg6.h"
     54 
     55 #define	NCHARS	(1 << BITSPERBYTE)
     56 
     57 /* if the _IOWRT flag is set, this must be a call from sscanf */
     58 #define	locgetc(cnt)	(cnt += 1, (iop->_flag & _IOWRT) ? \
     59 				((*iop->_ptr == '\0') ? EOF : *iop->_ptr++) : \
     60 				GETC(iop))
     61 #define	locungetc(cnt, x) (cnt -= 1, (x == EOF) ? EOF : \
     62 				((iop->_flag & _IOWRT) ? *(--iop->_ptr) : \
     63 				    (++iop->_cnt, *(--iop->_ptr))))
     64 
     65 #define	wlocgetc()	((iop->_flag & _IOWRT) ? \
     66 				((*iop->_ptr == '\0') ? EOF : *iop->_ptr++) : \
     67 				GETC(iop))
     68 #define	wlocungetc(x) ((x == EOF) ? EOF : \
     69 				((iop->_flag & _IOWRT) ? *(--iop->_ptr) : \
     70 				    UNGETC(x, iop)))
     71 
     72 #define	MAXARGS	30	/* max. number of args for fast positional paramters */
     73 
     74 /*
     75  * stva_list is used to subvert C's restriction that a variable with an
     76  * array type can not appear on the left hand side of an assignment operator.
     77  * By putting the array inside a structure, the functionality of assigning to
     78  * the whole array through a simple assignment is achieved..
     79  */
     80 typedef struct stva_list {
     81 	va_list	ap;
     82 } stva_list;
     83 
     84 static int number(int *, int *, int, int, int, int, FILE *, va_list *);
     85 static int readchar(FILE *, int *);
     86 static int string(int *, int *, int, int, int, char *, FILE *, va_list *);
     87 static int wstring(int *, int *, int, int, int, FILE *, va_list *);
     88 static int	wbrstring(int *, int *, int, int, int, FILE *,
     89 	unsigned char *, va_list *);
     90 #ifdef	_WIDE
     91 static int	brstring(int *, int *, int, int, int, FILE *,
     92 	unsigned char *, va_list *);
     93 #endif
     94 static int _bi_getwc(FILE *);
     95 static int _bi_ungetwc(wint_t, FILE *);
     96 
     97 #ifdef	_WIDE
     98 static int _mkarglst(const wchar_t *, stva_list, stva_list[]);
     99 static wint_t	_wd_getwc(int *, FILE *);
    100 static wint_t	_wd_ungetwc(int *, wchar_t, FILE *);
    101 static int	_watoi(wchar_t *);
    102 #else  /* _WIDE */
    103 static int _mkarglst(const char *, stva_list, stva_list[]);
    104 #endif /* _WIDE */
    105 
    106 #ifndef	_WIDE
    107 int
    108 _doscan(FILE *iop, const char *fmt, va_list va_Alist)
    109 {
    110 	int ret;
    111 	rmutex_t *lk;
    112 
    113 	if (iop->_flag & _IOWRT)
    114 		ret = __doscan_u(iop, fmt, va_Alist, 0);
    115 	else {
    116 		FLOCKFILE(lk, iop);
    117 		ret = __doscan_u(iop, fmt, va_Alist, 0);
    118 		FUNLOCKFILE(lk);
    119 	}
    120 	return (ret);
    121 }
    122 #endif  /* _WIDE */
    123 
    124 /* ARGSUSED3 */
    125 #ifdef	_WIDE
    126 int
    127 __wdoscan_u(FILE *iop, const wchar_t *fmt, va_list va_Alist, int scflag)
    128 #else  /* _WIDE */
    129 int
    130 __doscan_u(FILE *iop, const char *sfmt, va_list va_Alist, int scflag)
    131 #endif /* _WIDE */
    132 {
    133 #ifdef	_WIDE
    134 	wchar_t	ch;
    135 	wchar_t	inchar, size;
    136 	int	nmatch = 0, len, stow;
    137 #else  /* _WIDE */
    138 	int	ch;
    139 	int		nmatch = 0, len, inchar, stow, size;
    140 #endif /* _WIDE */
    141 
    142 	unsigned char	*bracket_str = NULL;
    143 	int		chcount, flag_eof;
    144 	char	tab[NCHARS];
    145 
    146 	/* variables for postional parameters */
    147 #ifdef	_WIDE
    148 	const wchar_t	*sformat = fmt;	/* save the beginning of the format */
    149 #else  /* _WIDE */
    150 	const unsigned char	*fmt = (const unsigned char *)sfmt;
    151 	const char	*sformat = sfmt; /* save the beginning of the format */
    152 #endif /* _WIDE */
    153 	int		fpos = 1;	/* 1 if first postional parameter */
    154 	stva_list	args;	/* used to step through the argument list */
    155 	stva_list	sargs;	/* used to save start of the argument list */
    156 	stva_list	arglst[MAXARGS];
    157 					/*
    158 					 * array giving the appropriate values
    159 					 * for va_arg() to retrieve the
    160 					 * corresponding argument:
    161 					 * arglst[0] is the first argument
    162 					 * arglst[1] is the second argument,etc.
    163 					 */
    164 	/* Check if readable stream */
    165 	if (!(iop->_flag & (_IOREAD | _IORW))) {
    166 		errno = EBADF;
    167 		return (EOF);
    168 	}
    169 
    170 	/*
    171 	 * Initialize args and sargs to the start of the argument list.
    172 	 * We don't know any portable way to copy an arbitrary C object
    173 	 * so we use a system-specific routine(probably a macro) from
    174 	 * stdarg.h.  (Remember that if va_list is an array, in_args will
    175 	 * be a pointer and &in_args won't be what we would want for
    176 	 * memcpy.)
    177 	 */
    178 	va_copy(args.ap, va_Alist);
    179 
    180 	sargs = args;
    181 
    182 	chcount = 0; flag_eof = 0;
    183 
    184 	/*
    185 	 * ****************************************************
    186 	 * Main loop: reads format to determine a pattern,
    187 	 *		and then goes to read input stream
    188 	 *		in attempt to match the pattern.
    189 	 * ****************************************************
    190 	 */
    191 	for (; ; ) {
    192 		if ((ch = *fmt++) == '\0') {
    193 			return (nmatch); /* end of format */
    194 		}
    195 #ifdef	_WIDE
    196 		if (iswspace(ch)) {
    197 			if (!flag_eof) {
    198 				while (iswspace(inchar =
    199 				    _wd_getwc(&chcount, iop)))
    200 					;
    201 				if (_wd_ungetwc(&chcount, inchar, iop) == WEOF)
    202 					flag_eof = 1;
    203 			}
    204 			continue;
    205 		}
    206 		if (ch != '%' || (ch = *fmt++) == '%') {
    207 			if (ch == '%') {
    208 				if (!flag_eof) {
    209 					while (iswspace(inchar =
    210 					    _wd_getwc(&chcount, iop)))
    211 						;
    212 					if (_wd_ungetwc(&chcount, inchar, iop)
    213 					    == WEOF)
    214 						flag_eof = 1;
    215 				}
    216 			}
    217 			if ((inchar = _wd_getwc(&chcount, iop)) == ch)
    218 				continue;
    219 			if (_wd_ungetwc(&chcount, inchar, iop) != WEOF) {
    220 				return (nmatch); /* failed to match input */
    221 			}
    222 			break;
    223 		}
    224 #else  /* _WIDE */
    225 		if (isspace(ch)) {
    226 			if (!flag_eof) {
    227 				while (isspace(inchar = locgetc(chcount)))
    228 					;
    229 				if (locungetc(chcount, inchar) == EOF)
    230 					flag_eof = 1;
    231 
    232 			}
    233 			continue;
    234 		}
    235 		if (ch != '%' || (ch = *fmt++) == '%') {
    236 			if (ch == '%') {
    237 				if (!flag_eof) {
    238 					while (isspace(inchar =
    239 					    locgetc(chcount)))
    240 						;
    241 					if (locungetc(chcount, inchar) == EOF)
    242 						flag_eof = 1;
    243 				}
    244 			}
    245 			if ((inchar = locgetc(chcount)) == ch)
    246 				continue;
    247 			if (locungetc(chcount, inchar) != EOF) {
    248 				return (nmatch); /* failed to match input */
    249 			}
    250 			break;
    251 		}
    252 #endif /* _WIDE */
    253 
    254 charswitch:	/* target of a goto 8-( */
    255 
    256 		if (ch == '*') {
    257 			stow = 0;
    258 			ch = *fmt++;
    259 		} else
    260 			stow = 1;
    261 
    262 #ifdef	_WIDE
    263 		for (len = 0; ((ch >= 0) && (ch < 256) && isdigit(ch));
    264 		    ch = *fmt++)
    265 			len = len * 10 + ch - '0';
    266 #else  /* _WIDE */
    267 		for (len = 0; isdigit(ch); ch = *fmt++)
    268 			len = len * 10 + ch - '0';
    269 #endif /* _WIDE */
    270 
    271 		if (ch == '$') {
    272 			/*
    273 			 * positional parameter handling - the number
    274 			 * specified in len gives the argument to which
    275 			 * the next conversion should be applied.
    276 			 * WARNING: This implementation of positional
    277 			 * parameters assumes that the sizes of all pointer
    278 			 * types are the same. (Code similar to that
    279 			 * in the portable doprnt.c should be used if this
    280 			 * assumption does not hold for a particular
    281 			 * port.)
    282 			 */
    283 			if (fpos) {
    284 				if (_mkarglst(sformat, sargs, arglst) != 0) {
    285 					return (EOF);
    286 				} else {
    287 					fpos = 0;
    288 				}
    289 			}
    290 			if (len <= MAXARGS) {
    291 				args = arglst[len - 1];
    292 			} else {
    293 				args = arglst[MAXARGS - 1];
    294 				for (len -= MAXARGS; len > 0; len--)
    295 					(void) va_arg(args.ap, void *);
    296 			}
    297 			len = 0;
    298 			ch = *fmt++;
    299 			goto charswitch;
    300 		}
    301 
    302 		if (len == 0)
    303 			len = MAXINT;
    304 #ifdef	_WIDE
    305 		if ((size = ch) == 'l' || (size == 'h') || (size == 'L') ||
    306 		    (size == 'j') || (size == 't') || (size == 'z'))
    307 			ch = *fmt++;
    308 #else  /* _WIDE */
    309 		if ((size = ch) == 'l' || (size == 'h') || (size == 'L') ||
    310 		    (size == 'w') || (size == 'j') || (size == 't') ||
    311 		    (size == 'z'))
    312 			ch = *fmt++;
    313 #endif /* _WIDE */
    314 		if (size == 'l' && ch == 'l') {
    315 			size = 'm';		/* size = 'm' if long long */
    316 			ch = *fmt++;
    317 		} else if (size == 'h' && ch == 'h') {
    318 			size = 'b';		/* use size = 'b' if char */
    319 			ch = *fmt++;
    320 		} else if ((size == 't') || (size == 'z')) {
    321 			size = 'l';
    322 		} else if (size == 'j') {
    323 #ifndef _LP64
    324 			/* check scflag for size of u/intmax_t (32-bit libc) */
    325 			if (!(scflag & _F_INTMAX32)) {
    326 #endif
    327 				size = 'm';
    328 #ifndef _LP64
    329 			}
    330 #endif
    331 		}
    332 		if (ch == '\0') {
    333 			return (EOF);		/* unexpected end of format */
    334 		}
    335 #ifdef	_WIDE
    336 		if (ch == '[') {
    337 			wchar_t	c;
    338 			size_t	len;
    339 			int	negflg = 0;
    340 			wchar_t	*p;
    341 			wchar_t	*wbracket_str;
    342 			size_t	wlen, clen;
    343 
    344 			/* p points to the address of '[' */
    345 			p = (wchar_t *)fmt - 1;
    346 			len = 0;
    347 			if (*fmt == '^') {
    348 				len++;
    349 				fmt++;
    350 				negflg = 1;
    351 			}
    352 			if (((c = *fmt) == ']') || (c == '-')) {
    353 				len++;
    354 				fmt++;
    355 			}
    356 			while ((c = *fmt) != ']') {
    357 				if (c == '\0') {
    358 					return (EOF); /* unexpected EOF */
    359 				} else {
    360 					len++;
    361 					fmt++;
    362 				}
    363 			}
    364 			fmt++;
    365 			len += 2;
    366 			wbracket_str = (wchar_t *)
    367 			    malloc(sizeof (wchar_t) * (len + 1));
    368 			if (wbracket_str == NULL) {
    369 				errno = ENOMEM;
    370 				return (EOF);
    371 			} else {
    372 				(void) wmemcpy(wbracket_str,
    373 				    (const wchar_t *)p, len);
    374 				*(wbracket_str + len) = L'\0';
    375 				if (negflg && *(wbracket_str + 1) == '^') {
    376 					*(wbracket_str + 1) = L'!';
    377 				}
    378 			}
    379 			wlen = wcslen(wbracket_str);
    380 			clen = wcstombs((char *)NULL, wbracket_str, 0);
    381 			if (clen == (size_t)-1) {
    382 				free(wbracket_str);
    383 				return (EOF);
    384 			}
    385 			bracket_str = (unsigned char *)
    386 			    malloc(sizeof (unsigned char) * (clen + 1));
    387 			if (bracket_str == NULL) {
    388 				free(wbracket_str);
    389 				errno = ENOMEM;
    390 				return (EOF);
    391 			}
    392 			clen = wcstombs((char *)bracket_str, wbracket_str,
    393 			    wlen + 1);
    394 			free(wbracket_str);
    395 			if (clen == (size_t)-1) {
    396 				free(bracket_str);
    397 				return (EOF);
    398 			}
    399 		}
    400 #else  /* _WIDE */
    401 		if (ch == '[') {
    402 			if (size == 'l') {
    403 				int	c, len, i;
    404 				int	negflg = 0;
    405 				unsigned char 	*p;
    406 
    407 				p = (unsigned char *)(fmt - 1);
    408 				len = 0;
    409 				if (*fmt == '^') {
    410 					len++;
    411 					fmt++;
    412 					negflg = 1;
    413 				}
    414 				if (((c = *fmt) == ']') || (c == '-')) {
    415 					len++;
    416 					fmt++;
    417 				}
    418 				while ((c = *fmt) != ']') {
    419 					if (c == '\0') {
    420 						return (EOF);
    421 					} else if (isascii(c)) {
    422 						len++;
    423 						fmt++;
    424 					} else {
    425 						i = mblen((const char *)fmt,
    426 						    MB_CUR_MAX);
    427 						if (i <= 0) {
    428 							return (EOF);
    429 						} else {
    430 							len += i;
    431 							fmt += i;
    432 						}
    433 					}
    434 				}
    435 				fmt++;
    436 				len += 2;
    437 				bracket_str = (unsigned char *)
    438 				    malloc(sizeof (unsigned char) * (len + 1));
    439 				if (bracket_str == NULL) {
    440 					errno = ENOMEM;
    441 					return (EOF);
    442 				} else {
    443 					(void) strncpy((char *)bracket_str,
    444 					    (const char *)p, len);
    445 					*(bracket_str + len) = '\0';
    446 					if (negflg &&
    447 					    *(bracket_str + 1) == '^') {
    448 						*(bracket_str + 1) = '!';
    449 					}
    450 				}
    451 			} else {
    452 				int	t = 0;
    453 				int	b, c, d;
    454 
    455 				if (*fmt == '^') {
    456 					t++;
    457 					fmt++;
    458 				}
    459 				(void) memset(tab, !t, NCHARS);
    460 				if ((c = *fmt) == ']' || c == '-') {
    461 					tab[c] = t;
    462 					fmt++;
    463 				}
    464 
    465 				while ((c = *fmt) != ']') {
    466 					if (c == '\0') {
    467 						return (EOF);
    468 					}
    469 					b = *(fmt - 1);
    470 					d = *(fmt + 1);
    471 					if ((c == '-') && (d != ']') &&
    472 					    (b < d)) {
    473 						(void) memset(&tab[b], t,
    474 						    d - b + 1);
    475 						fmt += 2;
    476 					} else {
    477 						tab[c] = t;
    478 						fmt++;
    479 					}
    480 				}
    481 				fmt++;
    482 			}
    483 		}
    484 #endif /* _WIDE */
    485 
    486 #ifdef	_WIDE
    487 		if ((ch >= 0) && (ch < 256) &&
    488 		    isupper((int)ch)) { /* no longer documented */
    489 			if (_lib_version == c_issue_4) {
    490 				if (size != 'm' && size != 'L')
    491 					size = 'l';
    492 			}
    493 			ch = _tolower((int)ch);
    494 		}
    495 		if (ch != 'n' && !flag_eof) {
    496 			if (ch != 'c' && ch != 'C' && ch != '[') {
    497 				while (iswspace(inchar =
    498 				    _wd_getwc(&chcount, iop)))
    499 					;
    500 				if (_wd_ungetwc(&chcount, inchar, iop) == WEOF)
    501 					break;
    502 
    503 			}
    504 		}
    505 #else  /* _WIDE */
    506 		if (isupper(ch)) { /* no longer documented */
    507 			if (_lib_version == c_issue_4) {
    508 				if (size != 'm' && size != 'L')
    509 					size = 'l';
    510 			}
    511 			ch = _tolower(ch);
    512 		}
    513 		if (ch != 'n' && !flag_eof) {
    514 			if (ch != 'c' && ch != 'C' && ch != '[') {
    515 				while (isspace(inchar = locgetc(chcount)))
    516 					;
    517 				if (locungetc(chcount, inchar) == EOF)
    518 					break;
    519 			}
    520 		}
    521 #endif /* _WIDE */
    522 
    523 		switch (ch) {
    524 		case 'C':
    525 		case 'S':
    526 		case 'c':
    527 		case 's':
    528 #ifdef	_WIDE
    529 			if ((size == 'l') || (size == 'C') || (size == 'S'))
    530 #else  /* _WIDE */
    531 			if ((size == 'w') || (size == 'l') || (size == 'C') ||
    532 			    (size == 'S'))
    533 #endif /* _WIDE */
    534 			{
    535 				size = wstring(&chcount, &flag_eof, stow,
    536 				    (int)ch, len, iop, &args.ap);
    537 			} else {
    538 				size = string(&chcount, &flag_eof, stow,
    539 				    (int)ch, len, tab, iop, &args.ap);
    540 			}
    541 			break;
    542 		case '[':
    543 			if (size == 'l') {
    544 				size = wbrstring(&chcount, &flag_eof, stow,
    545 				    (int)ch, len, iop, bracket_str, &args.ap);
    546 				free(bracket_str);
    547 				bracket_str = NULL;
    548 			} else {
    549 #ifdef	_WIDE
    550 				size = brstring(&chcount, &flag_eof, stow,
    551 				    (int)ch, len, iop, bracket_str, &args.ap);
    552 				free(bracket_str);
    553 				bracket_str = NULL;
    554 #else  /* _WIDE */
    555 				size = string(&chcount, &flag_eof, stow,
    556 				    ch, len, tab, iop, &args.ap);
    557 #endif /* _WIDE */
    558 			}
    559 			break;
    560 
    561 		case 'n':
    562 			if (stow == 0)
    563 				continue;
    564 			if (size == 'b')	/* char */
    565 				*va_arg(args.ap, char *) = (char)chcount;
    566 			else if (size == 'h')
    567 				*va_arg(args.ap, short *) = (short)chcount;
    568 			else if (size == 'l')
    569 				*va_arg(args.ap, long *) = (long)chcount;
    570 			else if (size == 'm') /* long long */
    571 				*va_arg(args.ap, long long *) =
    572 				    (long long) chcount;
    573 			else
    574 				*va_arg(args.ap, int *) = (int)chcount;
    575 			continue;
    576 
    577 		case 'i':
    578 		default:
    579 			size = number(&chcount, &flag_eof, stow, (int)ch,
    580 			    len, (int)size, iop, &args.ap);
    581 			break;
    582 		}
    583 		if (size)
    584 			nmatch += stow;
    585 		else {
    586 			return ((flag_eof && !nmatch) ? EOF : nmatch);
    587 		}
    588 		continue;
    589 	}
    590 	if (bracket_str)
    591 		free(bracket_str);
    592 	return (nmatch != 0 ? nmatch : EOF); /* end of input */
    593 }
    594 
    595 /* ****************************************************************** */
    596 /* Functions to read the input stream in an attempt to match incoming */
    597 /* data to the current pattern from the main loop of _doscan(). */
    598 /* ****************************************************************** */
    599 static int
    600 number(int *chcount, int *flag_eof, int stow, int type, int len, int size,
    601 	FILE *iop, va_list *listp)
    602 {
    603 	char	numbuf[64];
    604 	char	*np = numbuf;
    605 	int	c, base, inchar, lookahead;
    606 	int	digitseen = 0, floater = 0, negflg = 0;
    607 	int	lc;
    608 	long long	lcval = 0LL;
    609 
    610 	switch (type) {
    611 	case 'e':
    612 	case 'f':
    613 	case 'g':
    614 		/*
    615 		 * lc = 0 corresponds to c90 mode: do not recognize
    616 		 *	hexadecimal fp strings; attempt to push back
    617 		 *	all unused characters read
    618 		 *
    619 		 * lc = -1 corresponds to c99 mode: recognize hexa-
    620 		 *	decimal fp strings; push back at most one
    621 		 *	unused character
    622 		 */
    623 		lc = (__xpg6 & _C99SUSv3_recognize_hexfp)? -1 : 0;
    624 		floater = 1;
    625 		break;
    626 
    627 	case 'a':
    628 		lc = -1;
    629 		floater = 1;
    630 		break;
    631 
    632 	case 'd':
    633 	case 'u':
    634 	case 'i':
    635 		base = 10;
    636 		break;
    637 	case 'o':
    638 		base = 8;
    639 		break;
    640 	case 'p':
    641 #ifdef	_LP64
    642 		size = 'l'; /* pointers are long in LP64 */
    643 #endif	/*	_LP64	*/
    644 		/* FALLTHROUGH */
    645 	case 'x':
    646 		base = 16;
    647 		break;
    648 	default:
    649 		return (0); /* unrecognized conversion character */
    650 	}
    651 
    652 	if (floater != 0) {
    653 		/*
    654 		 * Handle floating point with
    655 		 * file_to_decimal.
    656 		 */
    657 		decimal_mode		dm;
    658 		decimal_record		dr;
    659 		fp_exception_field_type	efs;
    660 		enum decimal_string_form form;
    661 		char			*echar;
    662 		int			nread;
    663 		char			buffer[1024+1];
    664 		char			*nb = buffer;
    665 
    666 		if (len > 1024)
    667 			len = 1024;
    668 		file_to_decimal(&nb, len, lc, &dr, &form, &echar, iop, &nread);
    669 		if (lc == -1) {
    670 			/*
    671 			 * In C99 mode, the entire string read has to be
    672 			 * accepted in order to qualify as a match
    673 			 */
    674 			if (nb != buffer + nread)
    675 				form = invalid_form;
    676 		}
    677 		if (stow && (form != invalid_form)) {
    678 #if defined(__sparc)
    679 			dm.rd = _QgetRD();
    680 			if (size == 'L') {		/* long double */
    681 				if ((int)form < 0)
    682 					__hex_to_quadruple(&dr, dm.rd,
    683 					    va_arg(*listp, quadruple *), &efs);
    684 				else
    685 					decimal_to_quadruple(
    686 					    va_arg(*listp, quadruple *),
    687 					    &dm, &dr, &efs);
    688 			}
    689 #elif defined(__i386) || defined(__amd64)
    690 			dm.rd = __xgetRD();
    691 			if (size == 'L') {		/* long double */
    692 				if ((int)form < 0)
    693 					__hex_to_extended(&dr, dm.rd,
    694 					    va_arg(*listp, extended *), &efs);
    695 				else
    696 					decimal_to_extended(
    697 					    va_arg(*listp, extended *),
    698 					    &dm, &dr, &efs);
    699 			}
    700 #else
    701 #error Unknown architecture
    702 #endif
    703 			else if (size == 'l') {		/* double */
    704 				if ((int)form < 0)
    705 					__hex_to_double(&dr, dm.rd,
    706 					    va_arg(*listp, double *), &efs);
    707 				else
    708 					decimal_to_double(
    709 					    va_arg(*listp, double *),
    710 					    &dm, &dr, &efs);
    711 			} else {			/* float */
    712 				if ((int)form < 0)
    713 					__hex_to_single(&dr, dm.rd,
    714 					    va_arg(*listp, single *), &efs);
    715 				else
    716 					decimal_to_single((single *)
    717 					    va_arg(*listp, single *),
    718 					    &dm, &dr, &efs);
    719 			}
    720 			if ((efs & (1 << fp_overflow)) != 0) {
    721 				errno = ERANGE;
    722 			}
    723 			if ((efs & (1 << fp_underflow)) != 0) {
    724 				errno = ERANGE;
    725 			}
    726 		}
    727 		(*chcount) += nread;	/* Count characters read. */
    728 		c = locgetc((*chcount));
    729 		if (locungetc((*chcount), c) == EOF)
    730 			*flag_eof = 1;
    731 		return ((form == invalid_form) ? 0 : 1);
    732 				/* successful match if non-zero */
    733 	}
    734 
    735 	switch (c = locgetc((*chcount))) {
    736 	case '-':
    737 		negflg++;
    738 		/* FALLTHROUGH */
    739 	case '+':
    740 		if (--len <= 0)
    741 			break;
    742 		if ((c = locgetc((*chcount))) != '0')
    743 			break;
    744 		/* FALLTHROUGH */
    745 	case '0':
    746 		/*
    747 		 * If %i or %x, the characters 0x or 0X may optionally precede
    748 		 * the sequence of letters and digits (base 16).
    749 		 */
    750 		if ((type != 'i' && type != 'x') || (len <= 1))
    751 			break;
    752 		if (((inchar = locgetc((*chcount))) == 'x') ||
    753 		    (inchar == 'X')) {
    754 			lookahead = readchar(iop, chcount);
    755 			if (isxdigit(lookahead)) {
    756 				base = 16;
    757 
    758 				if (len <= 2) {
    759 					(void) locungetc((*chcount), lookahead);
    760 					/* Take into account the 'x' */
    761 					len -= 1;
    762 				} else {
    763 					c = lookahead;
    764 					/* Take into account '0x' */
    765 					len -= 2;
    766 				}
    767 			} else {
    768 				(void) locungetc((*chcount), lookahead);
    769 				(void) locungetc((*chcount), inchar);
    770 			}
    771 		} else {
    772 			/* inchar wans't 'x'. */
    773 			(void) locungetc((*chcount), inchar); /* Put it back. */
    774 			if (type == 'i') /* Only %i accepts an octal. */
    775 				base = 8;
    776 		}
    777 	}
    778 	for (; --len  >= 0; *np++ = (char)c, c = locgetc((*chcount))) {
    779 		if (np > numbuf + 62) {
    780 			errno = ERANGE;
    781 			return (0);
    782 		}
    783 		if (isdigit(c) || base == 16 && isxdigit(c)) {
    784 			int digit = c - (isdigit(c) ? '0' :
    785 			    isupper(c) ? 'A' - 10 : 'a' - 10);
    786 			if (digit >= base)
    787 				break;
    788 			if (stow)
    789 				lcval = base * lcval + digit;
    790 			digitseen++;
    791 			continue;
    792 		}
    793 		break;
    794 	}
    795 
    796 	if (stow && digitseen) {
    797 		/* suppress possible overflow on 2's-comp negation */
    798 		if (negflg && lcval != (1ULL << 63))
    799 			lcval = -lcval;
    800 		switch (size) {
    801 			case 'm':
    802 				*va_arg(*listp, long long *) = lcval;
    803 				break;
    804 			case 'l':
    805 				*va_arg(*listp, long *) = (long)lcval;
    806 				break;
    807 			case 'h':
    808 				*va_arg(*listp, short *) = (short)lcval;
    809 				break;
    810 			case 'b':
    811 				*va_arg(*listp, char *) = (char)lcval;
    812 				break;
    813 			default:
    814 				*va_arg(*listp, int *) = (int)lcval;
    815 				break;
    816 		}
    817 	}
    818 	if (locungetc((*chcount), c) == EOF)
    819 		*flag_eof = 1;
    820 	return (digitseen); /* successful match if non-zero */
    821 }
    822 
    823 /* Get a character. If not using sscanf and at the buffer's end */
    824 /* then do a direct read(). Characters read via readchar() */
    825 /* can be  pushed back on the input stream by locungetc((*chcount),) */
    826 /* since there is padding allocated at the end of the stream buffer. */
    827 static int
    828 readchar(FILE *iop, int *chcount)
    829 {
    830 	int	inchar;
    831 	char	buf[1];
    832 
    833 	if ((iop->_flag & _IOWRT) || (iop->_cnt != 0))
    834 		inchar = locgetc((*chcount));
    835 	else {
    836 		if (read(FILENO(iop), buf, 1) != 1)
    837 			return (EOF);
    838 		inchar = (int)buf[0];
    839 		(*chcount) += 1;
    840 	}
    841 	return (inchar);
    842 }
    843 
    844 static int
    845 string(int *chcount, int *flag_eof, int stow, int type, int len, char *tab,
    846 	FILE *iop, va_list *listp)
    847 {
    848 	int	ch;
    849 	char	*ptr;
    850 	char	*start;
    851 
    852 	start = ptr = stow ? va_arg(*listp, char *) : NULL;
    853 	if (((type == 'c') || (type == 'C')) && len == MAXINT)
    854 		len = 1;
    855 #ifdef	_WIDE
    856 	while ((ch = locgetc((*chcount))) != EOF &&
    857 	    !(((type == 's') || (type == 'S')) && isspace(ch))) {
    858 #else  /* _WIDE */
    859 	while ((ch = locgetc((*chcount))) != EOF &&
    860 	    !(((type == 's') || (type == 'S')) &&
    861 	    isspace(ch) || type == '[' && tab[ch])) {
    862 #endif /* _WIDE */
    863 		if (stow)
    864 			*ptr = (char)ch;
    865 		ptr++;
    866 		if (--len <= 0)
    867 			break;
    868 	}
    869 	if (ch == EOF) {
    870 		(*flag_eof) = 1;
    871 		(*chcount) -= 1;
    872 	} else if (len > 0 && locungetc((*chcount), ch) == EOF)
    873 		(*flag_eof) = 1;
    874 	if (ptr == start)
    875 		return (0);	/* no match */
    876 	if (stow && ((type != 'c') && (type != 'C')))
    877 		*ptr = '\0';
    878 	return (1);	/* successful match */
    879 }
    880 
    881 /* This function initializes arglst, to contain the appropriate */
    882 /* va_list values for the first MAXARGS arguments. */
    883 /* WARNING: this code assumes that the sizes of all pointer types */
    884 /* are the same. (Code similar to that in the portable doprnt.c */
    885 /* should be used if this assumption is not true for a */
    886 /* particular port.) */
    887 
    888 #ifdef	_WIDE
    889 static int
    890 _mkarglst(const wchar_t *fmt, stva_list args, stva_list arglst[])
    891 #else  /* _WIDE */
    892 static int
    893 _mkarglst(const char *fmt, stva_list args, stva_list arglst[])
    894 #endif /* _WIDE */
    895 {
    896 #ifdef	_WIDE
    897 #define	STRCHR	wcschr
    898 #define	STRSPN	wcsspn
    899 #define	ATOI(x)	_watoi((wchar_t *)x)
    900 #define	SPNSTR1	L"01234567890"
    901 #define	SPNSTR2	L"# +-.0123456789hL$"
    902 #else  /* _WIDE */
    903 #define	STRCHR	strchr
    904 #define	STRSPN	strspn
    905 #define	ATOI(x)	atoi(x)
    906 #define	SPNSTR1	"01234567890"
    907 #define	SPNSTR2	"# +-.0123456789hL$"
    908 #endif /* _WIDE */
    909 
    910 	int maxnum, curargno;
    911 	size_t n;
    912 
    913 	maxnum = -1;
    914 	curargno = 0;
    915 
    916 	while ((fmt = STRCHR(fmt, '%')) != NULL) {
    917 		fmt++;	/* skip % */
    918 		if (*fmt == '*' || *fmt == '%')
    919 			continue;
    920 		if (fmt[n = STRSPN(fmt, SPNSTR1)] == L'$') {
    921 			/* convert to zero base */
    922 			curargno = ATOI(fmt) - 1;
    923 			fmt += n + 1;
    924 		}
    925 
    926 		if (maxnum < curargno)
    927 			maxnum = curargno;
    928 		curargno++;	/* default to next in list */
    929 
    930 		fmt += STRSPN(fmt, SPNSTR2);
    931 		if (*fmt == '[') {
    932 			int	i;
    933 			fmt++; /* has to be at least on item in scan list */
    934 			if (*fmt == ']') {
    935 				fmt++;
    936 			}
    937 			while (*fmt != ']') {
    938 				if (*fmt == L'\0') {
    939 					return (-1); /* bad format */
    940 #ifdef	_WIDE
    941 				} else {
    942 					fmt++;
    943 				}
    944 #else  /* _WIDE */
    945 				} else if (isascii(*fmt)) {
    946 					fmt++;
    947 				} else {
    948 					i = mblen((const char *)
    949 					    fmt, MB_CUR_MAX);
    950 					if (i <= 0) {
    951 						return (-1);
    952 					} else {
    953 						fmt += i;
    954 					}
    955 				}
    956 #endif /* _WIDE */
    957 			}
    958 		}
    959 	}
    960 	if (maxnum > MAXARGS)
    961 		maxnum = MAXARGS;
    962 	for (n = 0; n <= maxnum; n++) {
    963 		arglst[n] = args;
    964 		(void) va_arg(args.ap, void *);
    965 	}
    966 	return (0);
    967 }
    968 
    969 
    970 /*
    971  * For wide character handling
    972  */
    973 
    974 #ifdef	_WIDE
    975 static int
    976 wstring(int *chcount, int *flag_eof, int stow, int type,
    977 	int len, FILE *iop, va_list *listp)
    978 {
    979 	wint_t	wch;
    980 	wchar_t	*ptr;
    981 	wchar_t	*wstart;
    982 	int	dummy;
    983 
    984 	wstart = ptr = stow ? va_arg(*listp, wchar_t *) : NULL;
    985 
    986 	if ((type == 'c') && len == MAXINT)
    987 		len = 1;
    988 	while (((wch = _wd_getwc(chcount, iop)) != WEOF) &&
    989 	    !(type == 's' && iswspace(wch))) {
    990 		if (stow)
    991 			*ptr = wch;
    992 		ptr++;
    993 		if (--len <= 0)
    994 			break;
    995 	}
    996 	if (wch == WEOF) {
    997 		*flag_eof = 1;
    998 		(*chcount) -= 1;
    999 	} else {
   1000 		if (len > 0 && _wd_ungetwc(chcount, wch, iop) == WEOF)
   1001 			*flag_eof = 1;
   1002 	}
   1003 	if (ptr == wstart)
   1004 		return (0); /* no match */
   1005 	if (stow && (type != 'c'))
   1006 		*ptr = '\0';
   1007 	return (1); /* successful match */
   1008 }
   1009 
   1010 #else  /* _WIDE */
   1011 static int
   1012 wstring(int *chcount, int *flag_eof, int stow, int type, int len, FILE *iop,
   1013 	va_list *listp)
   1014 {
   1015 	int	wch;
   1016 	wchar_t	*ptr;
   1017 	wchar_t	*wstart;
   1018 
   1019 	wstart = ptr = stow ? va_arg(*listp, wchar_t *) : NULL;
   1020 
   1021 	if ((type == 'c') && len == MAXINT)
   1022 		len = 1;
   1023 	while (((wch = _bi_getwc(iop)) != EOF) &&
   1024 	    !(type == 's' && (isascii(wch) ? isspace(wch) : 0))) {
   1025 		(*chcount) += _scrwidth((wchar_t)wch);
   1026 		if (stow)
   1027 			*ptr = wch;
   1028 		ptr++;
   1029 		if (--len <= 0)
   1030 			break;
   1031 	}
   1032 	if (wch == EOF) {
   1033 		(*flag_eof) = 1;
   1034 		(*chcount) -= 1;
   1035 	} else {
   1036 		if (len > 0 && _bi_ungetwc(wch, iop) == EOF)
   1037 			(*flag_eof) = 1;
   1038 	}
   1039 	if (ptr == wstart)
   1040 		return (0); /* no match */
   1041 	if (stow && (type != 'c'))
   1042 		*ptr = '\0';
   1043 	return (1); /* successful match */
   1044 }
   1045 #endif /* _WIDE */
   1046 
   1047 #ifdef	_WIDE
   1048 static wint_t
   1049 _wd_getwc(int *chcount, FILE *iop)
   1050 {
   1051 	wint_t	wc;
   1052 	int	len;
   1053 
   1054 	if (!(iop->_flag & _IOWRT)) {
   1055 		/* call from fwscanf, wscanf */
   1056 		wc = __fgetwc_xpg5(iop);
   1057 		(*chcount)++;
   1058 		return (wc);
   1059 	} else {
   1060 		/* call from swscanf */
   1061 		if (*iop->_ptr == '\0')
   1062 			return (WEOF);
   1063 		len = mbtowc((wchar_t *)&wc, (const char *)iop->_ptr,
   1064 		    MB_CUR_MAX);
   1065 		if (len == -1)
   1066 			return (WEOF);
   1067 		iop->_ptr += len;
   1068 		(*chcount)++;
   1069 		return (wc);
   1070 	}
   1071 }
   1072 
   1073 static wint_t
   1074 _wd_ungetwc(int *chcount, wchar_t wc, FILE *iop)
   1075 {
   1076 	wint_t	ret;
   1077 	int	len;
   1078 	char	mbs[MB_LEN_MAX];
   1079 
   1080 	if (wc == WEOF)
   1081 		return (WEOF);
   1082 
   1083 	if (!(iop->_flag & _IOWRT)) {
   1084 		/* call from fwscanf, wscanf */
   1085 		ret = __ungetwc_xpg5((wint_t)wc, iop);
   1086 		if (ret != (wint_t)wc)
   1087 			return (WEOF);
   1088 		(*chcount)--;
   1089 		return (ret);
   1090 	} else {
   1091 		/* call from swscanf */
   1092 		len = wctomb(mbs, wc);
   1093 		if (len == -1)
   1094 			return (WEOF);
   1095 		iop->_ptr -= len;
   1096 		(*chcount)--;
   1097 		return ((wint_t)wc);
   1098 	}
   1099 }
   1100 
   1101