8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libbc / libc / stdio / common / doscan.c
blob08cc3ff21502c95162234441b0d7e7129739742d
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
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"
32 /*LINTLIBRARY*/
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <stdarg.h>
36 #include <values.h>
37 #include <floatingpoint.h>
38 #include <errno.h>
39 #include <memory.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 *);
51 #ifdef S5EMUL
52 #define isws(c) isspace(c)
53 #else
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 */
61 0,0,0,0,0,0,0,0,
62 0,1,1,0,0,0,0,0,
63 0,0,0,0,0,0,0,0,
64 0,0,0,0,0,0,0,0,
65 1,0,0,0,0,0,0,0,
66 0,0,0,0,0,0,0,0,
67 0,0,0,0,0,0,0,0,
68 0,0,0,0,0,0,0,0,
69 0,0,0,0,0,0,0,0,
70 0,0,0,0,0,0,0,0,
71 0,0,0,0,0,0,0,0,
72 0,0,0,0,0,0,0,0,
73 0,0,0,0,0,0,0,0,
74 0,0,0,0,0,0,0,0,
75 0,0,0,0,0,0,0,0,
76 0,0,0,0,0,0,0,0,
79 #define isws(c) ((_sptab + 1)[c] != 0)
80 #endif
82 int
83 _doscan(FILE *iop, unsigned char *fmt, va_list va_alist)
85 char tab[NCHARS];
86 int ch;
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 *******************************************************/
95 for ( ; ; )
97 if ( (ch = *fmt++) == '\0')
98 return(nmatch); /* end of format */
99 if (isws(ch))
101 if (!flag_eof)
103 while (isws(inchar = locgetc()))
105 if (inchar == EOF) {
106 chcount--;
107 flag_eof = 1;
109 else if (locungetc(inchar) == EOF)
110 flag_eof = 1;
112 continue;
114 if (ch != '%' || (ch = *fmt++) == '%')
116 if ( (inchar = locgetc()) == ch )
117 continue;
118 if (inchar != EOF) {
119 if (locungetc(inchar) != EOF)
120 return(nmatch); /* failed to match input */
121 } else {
122 chcount--;
124 break;
126 if (ch == '*')
128 stow = 0;
129 ch = *fmt++;
131 else
132 stow = 1;
134 for (len = 0; isdigit(ch); ch = *fmt++)
135 len = len * 10 + ch - '0';
136 if (len == 0)
137 len = MAXINT;
138 if ( (size = ch) == 'l' || (size == 'h') || (size == 'L') )
139 ch = *fmt++;
140 if (ch == '\0' ||
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"
152 * makes no sense.
154 if (size != 'L')
155 size = 'l';
156 #ifdef S5EMUL
157 ch = _tolower(ch);
158 #else
159 ch = tolower(ch);
160 #endif
162 switch(ch)
164 case 'c':
165 case 's':
166 case '[':
167 if ((size = string(stow,ch,len,tab,iop,&va_alist)) < 0)
168 goto out; /* EOF seen, nothing converted */
169 break;
170 case 'n':
171 if (stow == 0)
172 continue;
173 if (size == 'h')
174 *va_arg(va_alist, short *) = (short) chcount;
175 else if (size == 'l')
176 *va_arg(va_alist, long *) = (long) chcount;
177 else
178 *va_arg(va_alist, int *) = (int) chcount;
179 continue;
180 default:
181 if ((size = number(stow, ch, len, size, iop, &va_alist)) < 0)
182 goto out; /* EOF seen, nothing converted */
183 break;
185 if (size)
186 nmatch += stow;
187 else
188 return((flag_eof && !nmatch) ? EOF : nmatch);
189 continue;
191 out:
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 **************************************************************
201 static int
202 number(int stow, int type, int len, int size, FILE *iop, va_list *listp)
204 char numbuf[64], inchar, lookahead;
205 char *np = numbuf;
206 int c, base;
207 int digitseen = 0, floater = 0, negflg = 0;
208 long lcval = 0;
209 switch(type)
211 case 'e':
212 case 'f':
213 case 'g':
214 floater++;
215 case 'd':
216 case 'u':
217 case 'i':
218 base = 10;
219 break;
220 case 'o':
221 base = 8;
222 break;
223 case 'x':
224 base = 16;
225 break;
226 default:
227 return(0); /* unrecognized conversion character */
229 if (!flag_eof)
231 while (isws(c = locgetc()))
234 else
235 c = locgetc();
236 if (c == EOF) {
237 chcount--;
238 return(-1); /* EOF before match */
240 if (floater != 0) { /* Handle floating point with
241 * file_to_decimal. */
242 decimal_mode dm;
243 decimal_record dr;
244 fp_exception_field_type efs;
245 enum decimal_string_form form;
246 char *echar;
247 int nread, ic;
248 char buffer[1024];
249 char *nb = buffer;
251 locungetc(c);
252 if (len > 1024)
253 len = 1024;
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);
261 } else {/* single */
262 decimal_to_single((float *) va_arg(*listp, float *), &dm, &dr, &efs);
264 if ((efs & (1 << fp_overflow)) != 0) {
265 errno = ERANGE;
267 if ((efs & (1 << fp_underflow)) != 0) {
268 errno = ERANGE;
271 chcount += nread; /* Count characters read. */
272 c = *nb; /* Get first unused character. */
273 ic = c;
274 if (c == NULL) {
275 ic = locgetc();
276 c = ic;
278 * If null, first unused may have been put back
279 * already.
282 if (ic == EOF) {
283 chcount--;
284 flag_eof = 1;
285 } else if (locungetc(c) == EOF)
286 flag_eof = 1;
287 return ((form == invalid_form) ? 0 : 1); /* successful match if
288 * non-zero */
290 switch(c) {
291 case '-':
292 negflg++;
293 if (type == 'u')
294 break;
295 case '+': /* fall-through */
296 if (--len <= 0)
297 break;
298 if ( (c = locgetc()) != '0')
299 break;
300 case '0':
301 if ( (type != 'i') || (len <= 1) )
302 break;
303 if ( ((inchar = locgetc()) == 'x') || (inchar == 'X') )
305 /* If not using sscanf and *
306 * at the buffer's end *
307 * then LOOK ahead */
309 if ( (iop->_flag & _IOSTRG) || (iop->_cnt != 0) )
310 lookahead = locgetc();
311 else
313 if ( read(fileno(iop),np,1) == 1)
314 lookahead = *np;
315 else
316 lookahead = EOF;
317 chcount += 1;
319 if ( isxdigit(lookahead) )
321 base =16;
323 if ( len <= 2)
325 locungetc(lookahead);
326 len -= 1; /* Take into account the 'x'*/
328 else
330 c = lookahead;
331 len -= 2; /* Take into account '0x'*/
334 else
336 locungetc(lookahead);
337 locungetc(inchar);
340 else
342 locungetc(inchar);
343 base = 8;
346 if (!negflg || type != 'u')
347 for (; --len >= 0 ; *np++ = c, c = locgetc())
349 if (np > numbuf + 62)
351 errno = ERANGE;
352 return(0);
354 if (isdigit(c))
356 int digit;
357 digit = c - '0';
358 if (base == 8)
360 if (digit >= 8)
361 break;
362 if (stow)
363 lcval = (lcval<<3) + digit;
365 else
367 if (stow)
369 if (base == 10)
370 lcval = (((lcval<<2) + lcval)<<1) + digit;
371 else /* base == 16 */
372 lcval = (lcval<<4) + digit;
375 digitseen++;
378 continue;
380 else if (base == 16 && isxdigit(c))
382 int digit;
383 digit = c - (isupper(c) ? 'A' - 10 : 'a' - 10);
384 if (stow)
385 lcval = (lcval<<4) + digit;
386 digitseen++;
387 continue;
389 break;
393 if (stow && digitseen)
395 /* suppress possible overflow on 2's-comp negation */
396 if (negflg && lcval != HIBITL)
397 lcval = -lcval;
398 if (size == 'l')
399 *va_arg(*listp, long *) = lcval;
400 else if (size == 'h')
401 *va_arg(*listp, short *) = (short)lcval;
402 else
403 *va_arg(*listp, int *) = (int)lcval;
405 if (c == EOF) {
406 chcount--;
407 flag_eof=1;
408 } else if (locungetc(c) == EOF)
409 flag_eof=1;
410 return (digitseen); /* successful match if non-zero */
413 static int
414 string(int stow, int type, int len, char *tab, FILE *iop, va_list *listp)
416 int ch;
417 char *ptr;
418 char *start;
420 start = ptr = stow ? va_arg(*listp, char *) : NULL;
421 if (type == 's')
423 if (!flag_eof)
425 while (isws(ch = locgetc()))
428 else
429 ch = locgetc();
430 if (ch == EOF)
431 return(-1); /* EOF before match */
432 while (ch != EOF && !isws(ch))
434 if (stow)
435 *ptr = ch;
436 ptr++;
437 if (--len <= 0)
438 break;
439 ch = locgetc();
441 } else if (type == 'c') {
442 if (len == MAXINT)
443 len = 1;
444 while ( (ch = locgetc()) != EOF)
446 if (stow)
447 *ptr = ch;
448 ptr++;
449 if (--len <= 0)
450 break;
452 } else { /* type == '[' */
453 while ( (ch = locgetc()) != EOF && !tab[ch])
455 if (stow)
456 *ptr = ch;
457 ptr++;
458 if (--len <= 0)
459 break;
462 if (ch == EOF )
464 chcount-=1;
465 flag_eof = 1;
467 else if (len > 0 && locungetc(ch) == EOF)
468 flag_eof = 1;
469 if (ptr == start)
470 return(0); /* no match */
471 if (stow && type != 'c')
472 *ptr = '\0';
473 return (1); /* successful match */
476 static unsigned char *
477 setup(unsigned char *fmt, char *tab)
479 int b, c, d, t = 0;
481 if (*fmt == '^')
483 t++;
484 fmt++;
486 (void) memset(tab, !t, NCHARS);
487 if ( (c = *fmt) == ']' || c == '-') /* first char is special */
489 tab[c] = t;
490 fmt++;
492 while ( (c = *fmt++) != ']')
494 if (c == '\0')
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);
499 fmt++;
501 else
502 tab[c] = t;
504 return (fmt);