vfscanf.c revision 92986
1/*-
2 * Copyright (c) 1990, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#if defined(LIBC_SCCS) && !defined(lint)
38static char sccsid[] = "@(#)vfscanf.c	8.1 (Berkeley) 6/4/93";
39#endif /* LIBC_SCCS and not lint */
40#include <sys/cdefs.h>
41__FBSDID("$FreeBSD: head/lib/libc/stdio/vfscanf.c 92986 2002-03-22 21:53:29Z obrien $");
42
43#include "namespace.h"
44#include <stdio.h>
45#include <stdlib.h>
46#include <ctype.h>
47#if __STDC__
48#include <stdarg.h>
49#else
50#include <varargs.h>
51#endif
52#include <string.h>
53#include "un-namespace.h"
54
55#include "collate.h"
56#include "libc_private.h"
57#include "local.h"
58
59#define FLOATING_POINT
60
61#ifdef FLOATING_POINT
62#include <locale.h>
63#include "floatio.h"
64#endif
65
66#define	BUF		513	/* Maximum length of numeric string. */
67
68/*
69 * Flags used during conversion.
70 */
71#define	LONG		0x01	/* l: long or double */
72#define	LONGDBL		0x02	/* L: long double */
73#define	SHORT		0x04	/* h: short */
74#define	SUPPRESS	0x08	/* suppress assignment */
75#define	POINTER		0x10	/* weird %p pointer (`fake hex') */
76#define	NOSKIP		0x20	/* do not skip blanks */
77#define	QUAD		0x400
78
79/*
80 * The following are used in numeric conversions only:
81 * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
82 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
83 */
84#define	SIGNOK		0x40	/* +/- is (still) legal */
85#define	NDIGITS		0x80	/* no digits detected */
86
87#define	DPTOK		0x100	/* (float) decimal point is still legal */
88#define	EXPOK		0x200	/* (float) exponent (e+3, etc) still legal */
89
90#define	PFXOK		0x100	/* 0x prefix is (still) legal */
91#define	NZDIGITS	0x200	/* no zero digits detected */
92
93/*
94 * Conversion types.
95 */
96#define	CT_CHAR		0	/* %c conversion */
97#define	CT_CCL		1	/* %[...] conversion */
98#define	CT_STRING	2	/* %s conversion */
99#define	CT_INT		3	/* integer, i.e., strtoq or strtouq */
100#define	CT_FLOAT	4	/* floating, i.e., strtod */
101
102#define u_char unsigned char
103#define u_long unsigned long
104
105static u_char *__sccl(char *, u_char *);
106
107/*
108 * __vfscanf - MT-safe version
109 */
110int
111__vfscanf(FILE *fp, char const *fmt0, va_list ap)
112{
113	int ret;
114
115	FLOCKFILE(fp);
116	ret = __svfscanf(fp, fmt0, ap);
117	FUNLOCKFILE(fp);
118	return (ret);
119}
120
121/*
122 * __svfscanf - non-MT-safe version of __vfscanf
123 */
124int
125__svfscanf(FILE *fp, char const *fmt0, va_list ap)
126{
127	u_char *fmt = (u_char *)fmt0;
128	int c;			/* character from format, or conversion */
129	size_t width;		/* field width, or 0 */
130	char *p;		/* points into all kinds of strings */
131	int n;			/* handy integer */
132	int flags;		/* flags as defined above */
133	char *p0;		/* saves original value of p when necessary */
134	int nassigned;		/* number of fields assigned */
135	int nconversions;	/* number of conversions */
136	int nread;		/* number of characters consumed from fp */
137	int base;		/* base argument to strtoq/strtouq */
138	u_quad_t(*ccfn)();	/* conversion function (strtoq/strtouq) */
139	char ccltab[256];	/* character class table for %[...] */
140	char buf[BUF];		/* buffer for numeric conversions */
141
142	/* `basefix' is used to avoid `if' tests in the integer scanner */
143	static short basefix[17] =
144		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
145#ifdef FLOATING_POINT
146	char decimal_point = localeconv()->decimal_point[0];
147#endif
148
149	nassigned = 0;
150	nconversions = 0;
151	nread = 0;
152	base = 0;		/* XXX just to keep gcc happy */
153	ccfn = NULL;		/* XXX just to keep gcc happy */
154	for (;;) {
155		c = *fmt++;
156		if (c == 0)
157			return (nassigned);
158		if (isspace(c)) {
159			while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p))
160				nread++, fp->_r--, fp->_p++;
161			continue;
162		}
163		if (c != '%')
164			goto literal;
165		width = 0;
166		flags = 0;
167		/*
168		 * switch on the format.  continue if done;
169		 * break once format type is derived.
170		 */
171again:		c = *fmt++;
172		switch (c) {
173		case '%':
174literal:
175			if (fp->_r <= 0 && __srefill(fp))
176				goto input_failure;
177			if (*fp->_p != c)
178				goto match_failure;
179			fp->_r--, fp->_p++;
180			nread++;
181			continue;
182
183		case '*':
184			flags |= SUPPRESS;
185			goto again;
186		case 'l':
187			flags |= LONG;
188			goto again;
189		case 'q':
190			flags |= QUAD;
191			goto again;
192		case 'L':
193			flags |= LONGDBL;
194			goto again;
195		case 'h':
196			flags |= SHORT;
197			goto again;
198
199		case '0': case '1': case '2': case '3': case '4':
200		case '5': case '6': case '7': case '8': case '9':
201			width = width * 10 + c - '0';
202			goto again;
203
204		/*
205		 * Conversions.
206		 * Those marked `compat' are for 4.[123]BSD compatibility.
207		 *
208		 * (According to ANSI, E and X formats are supposed
209		 * to the same as e and x.  Sorry about that.)
210		 */
211		case 'D':	/* compat */
212			flags |= LONG;
213			/* FALLTHROUGH */
214		case 'd':
215			c = CT_INT;
216			ccfn = (u_quad_t (*)())strtoq;
217			base = 10;
218			break;
219
220		case 'i':
221			c = CT_INT;
222			ccfn = (u_quad_t (*)())strtoq;
223			base = 0;
224			break;
225
226		case 'O':	/* compat */
227			flags |= LONG;
228			/* FALLTHROUGH */
229		case 'o':
230			c = CT_INT;
231			ccfn = strtouq;
232			base = 8;
233			break;
234
235		case 'u':
236			c = CT_INT;
237			ccfn = strtouq;
238			base = 10;
239			break;
240
241		case 'X':	/* compat   XXX */
242			flags |= LONG;
243			/* FALLTHROUGH */
244		case 'x':
245			flags |= PFXOK;	/* enable 0x prefixing */
246			c = CT_INT;
247			ccfn = strtouq;
248			base = 16;
249			break;
250
251#ifdef FLOATING_POINT
252		case 'E':	/* compat   XXX */
253		case 'F':	/* compat */
254			flags |= LONG;
255			/* FALLTHROUGH */
256		case 'e': case 'f': case 'g':
257			c = CT_FLOAT;
258			break;
259#endif
260
261		case 's':
262			c = CT_STRING;
263			break;
264
265		case '[':
266			fmt = __sccl(ccltab, fmt);
267			flags |= NOSKIP;
268			c = CT_CCL;
269			break;
270
271		case 'c':
272			flags |= NOSKIP;
273			c = CT_CHAR;
274			break;
275
276		case 'p':	/* pointer format is like hex */
277			flags |= POINTER | PFXOK;
278			c = CT_INT;
279			ccfn = strtouq;
280			base = 16;
281			break;
282
283		case 'n':
284			nconversions++;
285			if (flags & SUPPRESS)	/* ??? */
286				continue;
287			if (flags & SHORT)
288				*va_arg(ap, short *) = nread;
289			else if (flags & LONG)
290				*va_arg(ap, long *) = nread;
291			else if (flags & QUAD)
292				*va_arg(ap, quad_t *) = nread;
293			else
294				*va_arg(ap, int *) = nread;
295			continue;
296
297		/*
298		 * Disgusting backwards compatibility hacks.	XXX
299		 */
300		case '\0':	/* compat */
301			return (EOF);
302
303		default:	/* compat */
304			if (isupper(c))
305				flags |= LONG;
306			c = CT_INT;
307			ccfn = (u_quad_t (*)())strtoq;
308			base = 10;
309			break;
310		}
311
312		/*
313		 * We have a conversion that requires input.
314		 */
315		if (fp->_r <= 0 && __srefill(fp))
316			goto input_failure;
317
318		/*
319		 * Consume leading white space, except for formats
320		 * that suppress this.
321		 */
322		if ((flags & NOSKIP) == 0) {
323			while (isspace(*fp->_p)) {
324				nread++;
325				if (--fp->_r > 0)
326					fp->_p++;
327				else if (__srefill(fp))
328					goto input_failure;
329			}
330			/*
331			 * Note that there is at least one character in
332			 * the buffer, so conversions that do not set NOSKIP
333			 * ca no longer result in an input failure.
334			 */
335		}
336
337		/*
338		 * Do the conversion.
339		 */
340		switch (c) {
341
342		case CT_CHAR:
343			/* scan arbitrary characters (sets NOSKIP) */
344			if (width == 0)
345				width = 1;
346			if (flags & SUPPRESS) {
347				size_t sum = 0;
348				for (;;) {
349					if ((n = fp->_r) < width) {
350						sum += n;
351						width -= n;
352						fp->_p += n;
353						if (__srefill(fp)) {
354							if (sum == 0)
355							    goto input_failure;
356							break;
357						}
358					} else {
359						sum += width;
360						fp->_r -= width;
361						fp->_p += width;
362						break;
363					}
364				}
365				nread += sum;
366			} else {
367				size_t r = fread((void *)va_arg(ap, char *), 1,
368				    width, fp);
369
370				if (r == 0)
371					goto input_failure;
372				nread += r;
373				nassigned++;
374			}
375			nconversions++;
376			break;
377
378		case CT_CCL:
379			/* scan a (nonempty) character class (sets NOSKIP) */
380			if (width == 0)
381				width = (size_t)~0;	/* `infinity' */
382			/* take only those things in the class */
383			if (flags & SUPPRESS) {
384				n = 0;
385				while (ccltab[*fp->_p]) {
386					n++, fp->_r--, fp->_p++;
387					if (--width == 0)
388						break;
389					if (fp->_r <= 0 && __srefill(fp)) {
390						if (n == 0)
391							goto input_failure;
392						break;
393					}
394				}
395				if (n == 0)
396					goto match_failure;
397			} else {
398				p0 = p = va_arg(ap, char *);
399				while (ccltab[*fp->_p]) {
400					fp->_r--;
401					*p++ = *fp->_p++;
402					if (--width == 0)
403						break;
404					if (fp->_r <= 0 && __srefill(fp)) {
405						if (p == p0)
406							goto input_failure;
407						break;
408					}
409				}
410				n = p - p0;
411				if (n == 0)
412					goto match_failure;
413				*p = 0;
414				nassigned++;
415			}
416			nread += n;
417			nconversions++;
418			break;
419
420		case CT_STRING:
421			/* like CCL, but zero-length string OK, & no NOSKIP */
422			if (width == 0)
423				width = (size_t)~0;
424			if (flags & SUPPRESS) {
425				n = 0;
426				while (!isspace(*fp->_p)) {
427					n++, fp->_r--, fp->_p++;
428					if (--width == 0)
429						break;
430					if (fp->_r <= 0 && __srefill(fp))
431						break;
432				}
433				nread += n;
434			} else {
435				p0 = p = va_arg(ap, char *);
436				while (!isspace(*fp->_p)) {
437					fp->_r--;
438					*p++ = *fp->_p++;
439					if (--width == 0)
440						break;
441					if (fp->_r <= 0 && __srefill(fp))
442						break;
443				}
444				*p = 0;
445				nread += p - p0;
446				nassigned++;
447			}
448			nconversions++;
449			continue;
450
451		case CT_INT:
452			/* scan an integer as if by strtoq/strtouq */
453#ifdef hardway
454			if (width == 0 || width > sizeof(buf) - 1)
455				width = sizeof(buf) - 1;
456#else
457			/* size_t is unsigned, hence this optimisation */
458			if (--width > sizeof(buf) - 2)
459				width = sizeof(buf) - 2;
460			width++;
461#endif
462			flags |= SIGNOK | NDIGITS | NZDIGITS;
463			for (p = buf; width; width--) {
464				c = *fp->_p;
465				/*
466				 * Switch on the character; `goto ok'
467				 * if we accept it as a part of number.
468				 */
469				switch (c) {
470
471				/*
472				 * The digit 0 is always legal, but is
473				 * special.  For %i conversions, if no
474				 * digits (zero or nonzero) have been
475				 * scanned (only signs), we will have
476				 * base==0.  In that case, we should set
477				 * it to 8 and enable 0x prefixing.
478				 * Also, if we have not scanned zero digits
479				 * before this, do not turn off prefixing
480				 * (someone else will turn it off if we
481				 * have scanned any nonzero digits).
482				 */
483				case '0':
484					if (base == 0) {
485						base = 8;
486						flags |= PFXOK;
487					}
488					if (flags & NZDIGITS)
489					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
490					else
491					    flags &= ~(SIGNOK|PFXOK|NDIGITS);
492					goto ok;
493
494				/* 1 through 7 always legal */
495				case '1': case '2': case '3':
496				case '4': case '5': case '6': case '7':
497					base = basefix[base];
498					flags &= ~(SIGNOK | PFXOK | NDIGITS);
499					goto ok;
500
501				/* digits 8 and 9 ok iff decimal or hex */
502				case '8': case '9':
503					base = basefix[base];
504					if (base <= 8)
505						break;	/* not legal here */
506					flags &= ~(SIGNOK | PFXOK | NDIGITS);
507					goto ok;
508
509				/* letters ok iff hex */
510				case 'A': case 'B': case 'C':
511				case 'D': case 'E': case 'F':
512				case 'a': case 'b': case 'c':
513				case 'd': case 'e': case 'f':
514					/* no need to fix base here */
515					if (base <= 10)
516						break;	/* not legal here */
517					flags &= ~(SIGNOK | PFXOK | NDIGITS);
518					goto ok;
519
520				/* sign ok only as first character */
521				case '+': case '-':
522					if (flags & SIGNOK) {
523						flags &= ~SIGNOK;
524						goto ok;
525					}
526					break;
527
528				/* x ok iff flag still set & 2nd char */
529				case 'x': case 'X':
530					if (flags & PFXOK && p == buf + 1) {
531						base = 16;	/* if %i */
532						flags &= ~PFXOK;
533						goto ok;
534					}
535					break;
536				}
537
538				/*
539				 * If we got here, c is not a legal character
540				 * for a number.  Stop accumulating digits.
541				 */
542				break;
543		ok:
544				/*
545				 * c is legal: store it and look at the next.
546				 */
547				*p++ = c;
548				if (--fp->_r > 0)
549					fp->_p++;
550				else if (__srefill(fp))
551					break;		/* EOF */
552			}
553			/*
554			 * If we had only a sign, it is no good; push
555			 * back the sign.  If the number ends in `x',
556			 * it was [sign] '0' 'x', so push back the x
557			 * and treat it as [sign] '0'.
558			 */
559			if (flags & NDIGITS) {
560				if (p > buf)
561					(void) __ungetc(*(u_char *)--p, fp);
562				goto match_failure;
563			}
564			c = ((u_char *)p)[-1];
565			if (c == 'x' || c == 'X') {
566				--p;
567				(void) __ungetc(c, fp);
568			}
569			if ((flags & SUPPRESS) == 0) {
570				u_quad_t res;
571
572				*p = 0;
573				res = (*ccfn)(buf, (char **)NULL, base);
574				if (flags & POINTER)
575					*va_arg(ap, void **) =
576						(void *)(u_long)res;
577				else if (flags & SHORT)
578					*va_arg(ap, short *) = res;
579				else if (flags & LONG)
580					*va_arg(ap, long *) = res;
581				else if (flags & QUAD)
582					*va_arg(ap, quad_t *) = res;
583				else
584					*va_arg(ap, int *) = res;
585				nassigned++;
586			}
587			nread += p - buf;
588			nconversions++;
589			break;
590
591#ifdef FLOATING_POINT
592		case CT_FLOAT:
593			/* scan a floating point number as if by strtod */
594#ifdef hardway
595			if (width == 0 || width > sizeof(buf) - 1)
596				width = sizeof(buf) - 1;
597#else
598			/* size_t is unsigned, hence this optimisation */
599			if (--width > sizeof(buf) - 2)
600				width = sizeof(buf) - 2;
601			width++;
602#endif
603			flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
604			for (p = buf; width; width--) {
605				c = *fp->_p;
606				/*
607				 * This code mimicks the integer conversion
608				 * code, but is much simpler.
609				 */
610				switch (c) {
611
612				case '0': case '1': case '2': case '3':
613				case '4': case '5': case '6': case '7':
614				case '8': case '9':
615					flags &= ~(SIGNOK | NDIGITS);
616					goto fok;
617
618				case '+': case '-':
619					if (flags & SIGNOK) {
620						flags &= ~SIGNOK;
621						goto fok;
622					}
623					break;
624				case 'e': case 'E':
625					/* no exponent without some digits */
626					if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
627						flags =
628						    (flags & ~(EXPOK|DPTOK)) |
629						    SIGNOK | NDIGITS;
630						goto fok;
631					}
632					break;
633				default:
634					if ((char)c == decimal_point &&
635					    (flags & DPTOK)) {
636						flags &= ~(SIGNOK | DPTOK);
637						goto fok;
638					}
639					break;
640				}
641				break;
642		fok:
643				*p++ = c;
644				if (--fp->_r > 0)
645					fp->_p++;
646				else if (__srefill(fp))
647					break;	/* EOF */
648			}
649			/*
650			 * If no digits, might be missing exponent digits
651			 * (just give back the exponent) or might be missing
652			 * regular digits, but had sign and/or decimal point.
653			 */
654			if (flags & NDIGITS) {
655				if (flags & EXPOK) {
656					/* no digits at all */
657					while (p > buf)
658						__ungetc(*(u_char *)--p, fp);
659					goto match_failure;
660				}
661				/* just a bad exponent (e and maybe sign) */
662				c = *(u_char *)--p;
663				if (c != 'e' && c != 'E') {
664					(void) __ungetc(c, fp);/* sign */
665					c = *(u_char *)--p;
666				}
667				(void) __ungetc(c, fp);
668			}
669			if ((flags & SUPPRESS) == 0) {
670				double res;
671
672				*p = 0;
673				/* XXX this loses precision for long doubles. */
674				res = strtod(buf, (char **) NULL);
675				if (flags & LONGDBL)
676					*va_arg(ap, long double *) = res;
677				else if (flags & LONG)
678					*va_arg(ap, double *) = res;
679				else
680					*va_arg(ap, float *) = res;
681				nassigned++;
682			}
683			nread += p - buf;
684			nconversions++;
685			break;
686#endif /* FLOATING_POINT */
687		}
688	}
689input_failure:
690	return (nconversions != 0 ? nassigned : EOF);
691match_failure:
692	return (nassigned);
693}
694
695/*
696 * Fill in the given table from the scanset at the given format
697 * (just after `[').  Return a pointer to the character past the
698 * closing `]'.  The table has a 1 wherever characters should be
699 * considered part of the scanset.
700 */
701static u_char *
702__sccl(tab, fmt)
703	char *tab;
704	u_char *fmt;
705{
706	int c, n, v, i;
707
708	/* first `clear' the whole table */
709	c = *fmt++;		/* first char hat => negated scanset */
710	if (c == '^') {
711		v = 1;		/* default => accept */
712		c = *fmt++;	/* get new first char */
713	} else
714		v = 0;		/* default => reject */
715
716	/* XXX: Will not work if sizeof(tab*) > sizeof(char) */
717	(void) memset(tab, v, 256);
718
719	if (c == 0)
720		return (fmt - 1);/* format ended before closing ] */
721
722	/*
723	 * Now set the entries corresponding to the actual scanset
724	 * to the opposite of the above.
725	 *
726	 * The first character may be ']' (or '-') without being special;
727	 * the last character may be '-'.
728	 */
729	v = 1 - v;
730	for (;;) {
731		tab[c] = v;		/* take character c */
732doswitch:
733		n = *fmt++;		/* and examine the next */
734		switch (n) {
735
736		case 0:			/* format ended too soon */
737			return (fmt - 1);
738
739		case '-':
740			/*
741			 * A scanset of the form
742			 *	[01+-]
743			 * is defined as `the digit 0, the digit 1,
744			 * the character +, the character -', but
745			 * the effect of a scanset such as
746			 *	[a-zA-Z0-9]
747			 * is implementation defined.  The V7 Unix
748			 * scanf treats `a-z' as `the letters a through
749			 * z', but treats `a-a' as `the letter a, the
750			 * character -, and the letter a'.
751			 *
752			 * For compatibility, the `-' is not considerd
753			 * to define a range if the character following
754			 * it is either a close bracket (required by ANSI)
755			 * or is not numerically greater than the character
756			 * we just stored in the table (c).
757			 */
758			n = *fmt;
759			if (n == ']'
760			    || (__collate_load_error ? n < c :
761				__collate_range_cmp (n, c) < 0
762			       )
763			   ) {
764				c = '-';
765				break;	/* resume the for(;;) */
766			}
767			fmt++;
768			/* fill in the range */
769			if (__collate_load_error) {
770				do {
771					tab[++c] = v;
772				} while (c < n);
773			} else {
774				for (i = 0; i < 256; i ++)
775					if (   __collate_range_cmp (c, i) < 0
776					    && __collate_range_cmp (i, n) <= 0
777					   )
778						tab[i] = v;
779			}
780#if 1	/* XXX another disgusting compatibility hack */
781			c = n;
782			/*
783			 * Alas, the V7 Unix scanf also treats formats
784			 * such as [a-c-e] as `the letters a through e'.
785			 * This too is permitted by the standard....
786			 */
787			goto doswitch;
788#else
789			c = *fmt++;
790			if (c == 0)
791				return (fmt - 1);
792			if (c == ']')
793				return (fmt);
794#endif
795			break;
796
797		case ']':		/* end of scanset */
798			return (fmt);
799
800		default:		/* just another character */
801			c = n;
802			break;
803		}
804	}
805	/* NOTREACHED */
806}
807