4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
37 #include <floatingpoint.h>
41 #define NCHARS (1 << BITSPERBYTE)
42 #define locgetc() (chcount+=1,getc(iop))
43 #define locungetc(x) (chcount-=1,ungetc(x,iop))
45 static int chcount
,flag_eof
;
47 static int number(int, int, int, int, FILE *, va_list *);
48 static int string(int, int, int, char *, FILE *, va_list *);
49 static unsigned char *setup(unsigned char *, char *);
52 #define isws(c) isspace(c)
55 * _sptab[c+1] is 1 iff 'c' is a white space character according to the
56 * 4.2BSD "scanf" definition - namely, SP, TAB, and NL are the only
57 * whitespace characters.
59 static char _sptab
[1+256] = {
60 0, /* EOF - not a whitespace char */
79 #define isws(c) ((_sptab + 1)[c] != 0)
83 _doscan(FILE *iop
, unsigned char *fmt
, va_list va_alist
)
87 int nmatch
= 0, len
, inchar
, stow
, size
;
88 chcount
=0; flag_eof
=0;
90 /*******************************************************
91 * Main loop: reads format to determine a pattern,
92 * and then goes to read input stream
93 * in attempt to match the pattern.
94 *******************************************************/
97 if ( (ch
= *fmt
++) == '\0')
98 return(nmatch
); /* end of format */
103 while (isws(inchar
= locgetc()))
109 else if (locungetc(inchar
) == EOF
)
114 if (ch
!= '%' || (ch
= *fmt
++) == '%')
116 if ( (inchar
= locgetc()) == ch
)
119 if (locungetc(inchar
) != EOF
)
120 return(nmatch
); /* failed to match input */
134 for (len
= 0; isdigit(ch
); ch
= *fmt
++)
135 len
= len
* 10 + ch
- '0';
138 if ( (size
= ch
) == 'l' || (size
== 'h') || (size
== 'L') )
141 ch
== '[' && (fmt
= setup(fmt
, tab
)) == NULL
)
142 return(EOF
); /* unexpected end of format */
143 if (isupper(ch
)) /* no longer documented */
146 * The rationale behind excluding the size
147 * of 'L' is that the 'L' size specifier was
148 * introduced in ANSI/ISO-C. If the user
149 * specifies a format of %LG, it can mean
150 * nothing other than "long double", be the
151 * code ANSI or not. Mapping it to "double"
167 if ((size
= string(stow
,ch
,len
,tab
,iop
,&va_alist
)) < 0)
168 goto out
; /* EOF seen, nothing converted */
174 *va_arg(va_alist
, short *) = (short) chcount
;
175 else if (size
== 'l')
176 *va_arg(va_alist
, long *) = (long) chcount
;
178 *va_arg(va_alist
, int *) = (int) chcount
;
181 if ((size
= number(stow
, ch
, len
, size
, iop
, &va_alist
)) < 0)
182 goto out
; /* EOF seen, nothing converted */
188 return((flag_eof
&& !nmatch
) ? EOF
: nmatch
);
192 return (nmatch
!= 0 ? nmatch
: EOF
); /* end of input */
196 **************************************************************
197 * Functions to read the input stream in an attempt to match incoming
198 * data to the current pattern from the main loop of _doscan().
199 **************************************************************
202 number(int stow
, int type
, int len
, int size
, FILE *iop
, va_list *listp
)
204 char numbuf
[64], inchar
, lookahead
;
207 int digitseen
= 0, floater
= 0, negflg
= 0;
227 return(0); /* unrecognized conversion character */
231 while (isws(c
= locgetc()))
238 return(-1); /* EOF before match */
240 if (floater
!= 0) { /* Handle floating point with
241 * file_to_decimal. */
244 fp_exception_field_type efs
;
245 enum decimal_string_form form
;
254 file_to_decimal(&nb
, len
, 0, &dr
, &form
, &echar
, iop
, &nread
);
255 if (stow
&& (form
!= invalid_form
)) {
256 dm
.rd
= fp_direction
;
257 if (size
== 'l') { /* double */
258 decimal_to_double((double *) va_arg(*listp
, double *), &dm
, &dr
, &efs
);
259 } else if (size
== 'L') { /* quad */
260 decimal_to_quadruple((quadruple
*)va_arg(*listp
, double *), &dm
, &dr
, &efs
);
262 decimal_to_single((float *) va_arg(*listp
, float *), &dm
, &dr
, &efs
);
264 if ((efs
& (1 << fp_overflow
)) != 0) {
267 if ((efs
& (1 << fp_underflow
)) != 0) {
271 chcount
+= nread
; /* Count characters read. */
272 c
= *nb
; /* Get first unused character. */
278 * If null, first unused may have been put back
285 } else if (locungetc(c
) == EOF
)
287 return ((form
== invalid_form
) ? 0 : 1); /* successful match if
295 case '+': /* fall-through */
298 if ( (c
= locgetc()) != '0')
301 if ( (type
!= 'i') || (len
<= 1) )
303 if ( ((inchar
= locgetc()) == 'x') || (inchar
== 'X') )
305 /* If not using sscanf and *
306 * at the buffer's end *
309 if ( (iop
->_flag
& _IOSTRG
) || (iop
->_cnt
!= 0) )
310 lookahead
= locgetc();
313 if ( read(fileno(iop
),np
,1) == 1)
319 if ( isxdigit(lookahead
) )
325 locungetc(lookahead
);
326 len
-= 1; /* Take into account the 'x'*/
331 len
-= 2; /* Take into account '0x'*/
336 locungetc(lookahead
);
346 if (!negflg
|| type
!= 'u')
347 for (; --len
>= 0 ; *np
++ = c
, c
= locgetc())
349 if (np
> numbuf
+ 62)
363 lcval
= (lcval
<<3) + digit
;
370 lcval
= (((lcval
<<2) + lcval
)<<1) + digit
;
371 else /* base == 16 */
372 lcval
= (lcval
<<4) + digit
;
380 else if (base
== 16 && isxdigit(c
))
383 digit
= c
- (isupper(c
) ? 'A' - 10 : 'a' - 10);
385 lcval
= (lcval
<<4) + digit
;
393 if (stow
&& digitseen
)
395 /* suppress possible overflow on 2's-comp negation */
396 if (negflg
&& lcval
!= HIBITL
)
399 *va_arg(*listp
, long *) = lcval
;
400 else if (size
== 'h')
401 *va_arg(*listp
, short *) = (short)lcval
;
403 *va_arg(*listp
, int *) = (int)lcval
;
408 } else if (locungetc(c
) == EOF
)
410 return (digitseen
); /* successful match if non-zero */
414 string(int stow
, int type
, int len
, char *tab
, FILE *iop
, va_list *listp
)
420 start
= ptr
= stow
? va_arg(*listp
, char *) : NULL
;
425 while (isws(ch
= locgetc()))
431 return(-1); /* EOF before match */
432 while (ch
!= EOF
&& !isws(ch
))
441 } else if (type
== 'c') {
444 while ( (ch
= locgetc()) != EOF
)
452 } else { /* type == '[' */
453 while ( (ch
= locgetc()) != EOF
&& !tab
[ch
])
467 else if (len
> 0 && locungetc(ch
) == EOF
)
470 return(0); /* no match */
471 if (stow
&& type
!= 'c')
473 return (1); /* successful match */
476 static unsigned char *
477 setup(unsigned char *fmt
, char *tab
)
486 (void) memset(tab
, !t
, NCHARS
);
487 if ( (c
= *fmt
) == ']' || c
== '-') /* first char is special */
492 while ( (c
= *fmt
++) != ']')
495 return(NULL
); /* unexpected end of format */
496 if (c
== '-' && (d
= *fmt
) != ']' && (b
= fmt
[-2]) < d
)
498 (void) memset(&tab
[b
], t
, d
- b
+ 1);