xref: /csrg-svn/lib/libc/stdio/vfprintf.c (revision 34325)
134226Sbostic /*
234233Sbostic  * Copyright (c) 1988 Regents of the University of California.
334233Sbostic  * All rights reserved.
434226Sbostic  *
534233Sbostic  * Redistribution and use in source and binary forms are permitted
634233Sbostic  * provided that this notice is preserved and that due credit is given
734233Sbostic  * to the University of California at Berkeley. The name of the University
834233Sbostic  * may not be used to endorse or promote products derived from this
934233Sbostic  * software without specific prior written permission. This software
1034233Sbostic  * is provided ``as is'' without express or implied warranty.
1134226Sbostic  */
1234226Sbostic 
1334233Sbostic #if defined(LIBC_SCCS) && !defined(lint)
14*34325Sbostic static char sccsid[] = "@(#)vfprintf.c	5.21 (Berkeley) 05/18/88";
1534233Sbostic #endif /* LIBC_SCCS and not lint */
1634233Sbostic 
1734261Sbostic #include <sys/types.h>
1834233Sbostic #include <varargs.h>
1934226Sbostic #include <stdio.h>
2034233Sbostic #include <ctype.h>
2134226Sbostic 
2234323Sbostic #define	MAXBUF		512
2334226Sbostic 
2434323Sbostic #define	PUTC(ch)	{++cnt; putc((char)ch, fp);}
2534236Sbostic 
2634318Sbostic #define	ARG() \
2734318Sbostic 	_ulong = flags&LONGINT ? va_arg(argp, long) : \
2834318Sbostic 	    flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int);
2934235Sbostic 
3034318Sbostic /* have to deal with the negative buffer count kludge */
3134318Sbostic #define	NEGATIVE_COUNT_KLUDGE
3234318Sbostic 
3334318Sbostic #define	LONGINT		0x01		/* long integer */
3434318Sbostic #define	LONGDBL		0x02		/* long double; unimplemented */
3534318Sbostic #define	SHORTINT	0x04		/* short integer */
3634318Sbostic #define	ALT		0x08		/* alternate form */
3734318Sbostic #define	LADJUST		0x10		/* left adjustment */
3834318Sbostic 
3934323Sbostic _doprnt(fmt0, argp, fp)
4034323Sbostic 	u_char *fmt0;
4134233Sbostic 	va_list argp;
4234235Sbostic 	register FILE *fp;
4334226Sbostic {
4434323Sbostic 	register u_char *fmt;
4534323Sbostic 	register int ch, cnt, n;
4634323Sbostic 	register char *t;
4734235Sbostic 	double _double;
4834314Sbostic 	u_long _ulong;
4934323Sbostic 	int base, flags, prec, size, width;
5034323Sbostic 	char padc, sign, *digs, buf[MAXBUF], *_cvt();
5134226Sbostic 
5234323Sbostic 	fmt = fmt0;
5334243Sbostic 	digs = "0123456789abcdef";
5434322Sbostic 	for (cnt = 0;; ++fmt) {
5534318Sbostic 		n = fp->_cnt;
5634318Sbostic 		for (t = fp->_ptr; (ch = *fmt) && ch != '%'; ++cnt, ++fmt)
5734318Sbostic 			if (--n < 0
5834318Sbostic #ifdef NEGATIVE_COUNT_KLUDGE
5934318Sbostic 			    && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz)
6034318Sbostic #endif
6134318Sbostic 			    || ch == '\n' && fp->_flag&_IOLBF) {
6234318Sbostic 				fp->_cnt = n;
6334318Sbostic 				fp->_ptr = t;
6434318Sbostic 				(void)_flsbuf(ch, fp);
6534318Sbostic 				n = fp->_cnt;
6634318Sbostic 				t = fp->_ptr;
6734318Sbostic 			}
6834318Sbostic 			else
6934314Sbostic 				*t++ = ch;
7034318Sbostic 		fp->_cnt = n;
7134318Sbostic 		fp->_ptr = t;
7234318Sbostic 		if (!ch)
7334314Sbostic 			return(cnt);
7434314Sbostic 
7534318Sbostic 		flags = width = 0;
7634233Sbostic 		prec = -1;
7734233Sbostic 		padc = ' ';
7834318Sbostic 		sign = '\0';
7934226Sbostic 
8034318Sbostic rflag:		switch (*++fmt) {
8134318Sbostic 		case ' ':
8234318Sbostic 			sign = ' ';
8334318Sbostic 			goto rflag;
8434233Sbostic 		case '#':
8534318Sbostic 			flags |= ALT;
8634318Sbostic 			goto rflag;
8734233Sbostic 		case '*':
8834235Sbostic 			/*
8934235Sbostic 			 * ``A negative field width argument is taken as a
9034235Sbostic 			 * - flag followed by a  positive field width.''
9134235Sbostic 			 *	-- ANSI X3J11
9234235Sbostic 			 * They don't exclude field widths read from args.
9334235Sbostic 			 */
9434235Sbostic 			if ((width = va_arg(argp, int)) >= 0)
9534318Sbostic 				goto rflag;
9634235Sbostic 			width = -width;
9734235Sbostic 			/*FALLTHROUGH*/
9834235Sbostic 		case '-':
9934318Sbostic 			flags |= LADJUST;
10034318Sbostic 			goto rflag;
10134233Sbostic 		case '+':
10234314Sbostic 			sign = '+';
10334318Sbostic 			goto rflag;
10434233Sbostic 		case '.':
10534235Sbostic 			if (*++fmt == '*')
10634318Sbostic 				n = va_arg(argp, int);
10734318Sbostic 			else if (isascii(*fmt) && isdigit(*fmt)) {
10834318Sbostic 				n = 0;
10934233Sbostic 				do {
11034318Sbostic 					n = 10 * n + *fmt - '0';
11134318Sbostic 				} while (isascii(*++fmt) && isdigit(*fmt));
11234233Sbostic 				--fmt;
11334226Sbostic 			}
11434235Sbostic 			else {
11534318Sbostic 				--fmt;
11634235Sbostic 				prec = 0;
11734318Sbostic 				goto rflag;
11834235Sbostic 			}
11934318Sbostic 			prec = n < 0 ? -1 : n;
12034318Sbostic 			goto rflag;
12134233Sbostic 		case '0':
12234233Sbostic 			padc = '0';
12334235Sbostic 			/*FALLTHROUGH*/
12434233Sbostic 		case '1': case '2': case '3': case '4':
12534233Sbostic 		case '5': case '6': case '7': case '8': case '9':
12634318Sbostic 			n = 0;
12734233Sbostic 			do {
12834318Sbostic 				n = 10 * n + *fmt - '0';
12934318Sbostic 			} while (isascii(*++fmt) && isdigit(*fmt));
13034318Sbostic 			width = n;
13134233Sbostic 			--fmt;
13234319Sbostic 			goto rflag;
13334235Sbostic 		case 'L':
13434318Sbostic 			/*
13534318Sbostic 			 * C doesn't have a long double; use long for now.
13634318Sbostic 			 * flags |= LONGDBL;
13734318Sbostic 			 */
13834318Sbostic 			flags |= LONGINT;
13934318Sbostic 			goto rflag;
14034235Sbostic 		case 'h':
14134318Sbostic 			flags |= SHORTINT;
14234318Sbostic 			goto rflag;
14334233Sbostic 		case 'l':
14434318Sbostic 			flags |= LONGINT;
14534318Sbostic 			goto rflag;
14634314Sbostic 		case 'c':
14734319Sbostic 			buf[0] = va_arg(argp, int);
14834314Sbostic 			size = 1;
14934319Sbostic 			t = buf;
15034314Sbostic 			goto pforw;
15134314Sbostic 		case 'd':
15234318Sbostic 		case 'i':
15334318Sbostic 			ARG();
15434318Sbostic 			if ((long)_ulong < 0) {
15534318Sbostic 				_ulong = -_ulong;
15634314Sbostic 				sign = '-';
15734241Sbostic 			}
15834314Sbostic 			if (sign)
15934314Sbostic 				PUTC(sign);
16034241Sbostic 			base = 10;
16134314Sbostic 			goto num;
16234261Sbostic 		case 'e':
16334236Sbostic 		case 'E':
16434235Sbostic 		case 'f':
16534261Sbostic 		case 'g':
16634243Sbostic 		case 'G':
16734243Sbostic 			_double = va_arg(argp, double);
16834323Sbostic 			size = _cvt(_double, prec, flags, *fmt, sign,
16934323Sbostic 			    buf, buf + sizeof(buf)) - buf;
17034319Sbostic 			t = buf;
17134314Sbostic 			goto pforw;
17234235Sbostic 		case 'n':
17334318Sbostic 			if (flags&LONGDBL || flags&LONGINT)
17434318Sbostic 				*va_arg(argp, long *) = cnt;
17534318Sbostic 			else if (flags&SHORTINT)
17634318Sbostic 				*va_arg(argp, short *) = cnt;
17734318Sbostic 			else
17834318Sbostic 				*va_arg(argp, int *) = cnt;
17934235Sbostic 			break;
18034226Sbostic 		case 'o':
18134318Sbostic 			ARG();
18234226Sbostic 			base = 8;
18334314Sbostic 			goto num;
18434235Sbostic 		case 'p':
18534320Sbostic 			/*
18634321Sbostic 			 * ``The argument shall be a pointer to void.  The
18734321Sbostic 			 * value of the pointer is converted to a sequence
18834321Sbostic 			 * of printable characters, in an implementation-
18934321Sbostic 			 * defined manner.''
19034321Sbostic 			 *	-- ANSI X3J11
19134320Sbostic 			 */
19234320Sbostic 			_ulong = (u_long)va_arg(argp, void *);
19334320Sbostic 			base = 16;
19434320Sbostic 			goto num;
19534226Sbostic 		case 's':
19634314Sbostic 			if (!(t = va_arg(argp, char *)))
19734314Sbostic 				t = "(null)";
19834321Sbostic 			if (prec >= 0) {
19934321Sbostic 				/*
20034321Sbostic 				 * can't use strlen; can only look for the
20134321Sbostic 				 * NUL in the first `prec' characters, and
20234321Sbostic 				 * strlen() will go further.
20334321Sbostic 				 */
20434321Sbostic 				char *p, *memchr();
20534321Sbostic 
20634321Sbostic 				if (p = memchr(t, 0, prec)) {
20734321Sbostic 					size = p - t;
20834321Sbostic 					if (size > prec)
20934321Sbostic 						size = prec;
21034321Sbostic 				}
21134321Sbostic 				else
21234321Sbostic 					size = prec;
21334321Sbostic 			}
21434321Sbostic 			else
21534321Sbostic 				size = strlen(t);
21634318Sbostic pforw:			if (!(flags&LADJUST) && width)
21734314Sbostic 				for (n = size; n++ < width;)
21834314Sbostic 					PUTC(padc);
21934314Sbostic 			if (fp->_cnt - (n = size) >= 0) {
22034314Sbostic 				cnt += n;
22134314Sbostic 				fp->_cnt -= n;
22234314Sbostic 				bcopy(t, fp->_ptr, n);
22334314Sbostic 				fp->_ptr += n;
22434233Sbostic 			}
22534314Sbostic 			else for (; n--; ++t)
22634314Sbostic 				PUTC(*t);
22734318Sbostic 			if (flags&LADJUST)
22834314Sbostic 				while (width-- > size)
229*34325Sbostic 					PUTC(' ');
23034226Sbostic 			break;
23134226Sbostic 		case 'u':
23234318Sbostic 			ARG();
23334226Sbostic 			base = 10;
23434314Sbostic 			goto num;
23534226Sbostic 		case 'X':
23634226Sbostic 			digs = "0123456789ABCDEF";
23734233Sbostic 			/*FALLTHROUGH*/
23834226Sbostic 		case 'x':
23934318Sbostic 			ARG();
24034314Sbostic 			base = 16;
24134324Sbostic 			if (!_ulong)	/* leading 0x/X only if non-zero */
24234324Sbostic 				flags &= ~ALT;
24334323Sbostic num:			t = buf + MAXBUF - 1;
24434233Sbostic 			do {
24534314Sbostic 				*t-- = digs[_ulong % base];
24634314Sbostic 				_ulong /= base;
24734314Sbostic 			} while(_ulong);
24834314Sbostic 			digs = "0123456789abcdef";
24934324Sbostic 			for (size = buf + MAXBUF - 1 - t; size < prec; ++size)
25034324Sbostic 				*t-- = '0';
25134324Sbostic 			if (flags&ALT)
25234324Sbostic 				switch (base) {
25334324Sbostic 				case 16:
25434324Sbostic 					/* avoid "00000x35" */
25534324Sbostic 					if (padc == '0') {
25634324Sbostic 						PUTC('0');
25734324Sbostic 						PUTC(*fmt);
25834324Sbostic 					}
25934324Sbostic 					else {
26034324Sbostic 						*t-- = *fmt;
26134324Sbostic 						*t-- = '0';
26234324Sbostic 					}
26334324Sbostic 					width -= 2;
26434324Sbostic 					break;
26534324Sbostic 				case 8:
26634324Sbostic 					if (t[1] != '0') {
26734324Sbostic 						*t-- = '0';
26834324Sbostic 						--width;
26934324Sbostic 					}
27034324Sbostic 					break;
27134314Sbostic 				}
27234318Sbostic 			if (!(flags&LADJUST))
27334314Sbostic 				while (size++ < width)
27434263Sbostic 					PUTC(padc);
27534323Sbostic 			while (++t < buf + MAXBUF)
27634314Sbostic 				PUTC(*t);
277*34325Sbostic 			while (width-- > size)
278*34325Sbostic 				PUTC(' ');
27934226Sbostic 			break;
28034233Sbostic 		case '\0':		/* "%?" prints ?, unless ? is NULL */
28134314Sbostic 			return(cnt);
28234226Sbostic 		default:
28334263Sbostic 			PUTC(*fmt);
28434226Sbostic 		}
28534226Sbostic 	}
28634314Sbostic 	/*NOTREACHED*/
28734226Sbostic }
28834242Sbostic 
28934261Sbostic #define	EFORMAT	0x01
29034261Sbostic #define	FFORMAT	0x02
29134261Sbostic #define	GFORMAT	0x04
29234314Sbostic #define	DEFPREC	6
29334261Sbostic 
29434323Sbostic static char *
29534323Sbostic _cvt(number, prec, flags, fmtch, sign, startp, endp)
29634242Sbostic 	double number;
29734261Sbostic 	register int prec;
29834323Sbostic 	int flags;
29934323Sbostic 	u_char fmtch;
30034323Sbostic 	char sign, *startp, *endp;
30134242Sbostic {
30234248Sbostic 	register char *p;
30334261Sbostic 	register int expcnt, format;
30434248Sbostic 	double fract, integer, tmp, modf();
30534261Sbostic 	int decpt;
30634323Sbostic 	char *savep;
30734242Sbostic 
30834314Sbostic 	if (prec == -1)
30934242Sbostic 		prec = DEFPREC;
31034242Sbostic 
31134314Sbostic 	if (number < 0) {
31234248Sbostic 		*startp++ = '-';
31334248Sbostic 		number = -number;
31434248Sbostic 	}
31534314Sbostic 	else if (sign)
31634318Sbostic 		*startp++ = sign;
31734242Sbostic 
31834261Sbostic 	switch(fmtch) {
31934261Sbostic 	case 'e':
32034261Sbostic 	case 'E':
32134261Sbostic 		format = EFORMAT;
32234261Sbostic 		break;
32334261Sbostic 	case 'f':
32434261Sbostic 		format = FFORMAT;
32534261Sbostic 		break;
32634261Sbostic 	case 'g':
32734261Sbostic 	case 'G':
32834261Sbostic 		format = GFORMAT;
32934261Sbostic 		fmtch -= 2;
33034261Sbostic 	}
33134261Sbostic 
33234248Sbostic 	/*
33334248Sbostic 	 * if the alternate flag is set, or, at least one digit of precision
33434248Sbostic 	 * was requested, add a decimal point, unless it's the g/G format
33534314Sbostic 	 * in which case we require two digits of precision, as it counts
33634248Sbostic 	 * precision differently.
33734248Sbostic 	 */
33834318Sbostic 	decpt = flags&ALT || prec > (format&GFORMAT ? 1 : 0);
33934248Sbostic 
34034248Sbostic 	expcnt = 0;
34134323Sbostic 	p = endp - 1;
34234248Sbostic 	fract = modf(number, &integer);
34334248Sbostic 	if (integer) {
34434248Sbostic 		register char *p2;
34534248Sbostic 
34634248Sbostic 		/* get integer part of number; count decimal places */
34734248Sbostic 		for (; integer; ++expcnt) {
34834248Sbostic 			tmp = modf(integer / 10, &integer);
34934248Sbostic 			*p-- = (int)((tmp + .03) * 10) + '0';
35034242Sbostic 		}
35134248Sbostic 
35234248Sbostic 		/* copy, in reverse order, to start of buffer */
35334248Sbostic 		p2 = startp;
35434248Sbostic 		*p2++ = *++p;
35534248Sbostic 
35634248Sbostic 		/*
35734248Sbostic 		 * if the format is g/G, and the resulting exponent will be
35834248Sbostic 		 * greater than the precision, use e/E format.  If e/E format,
35934248Sbostic 		 * put in a decimal point as needed, and decrement precision
36034248Sbostic 		 * count for each digit after the decimal point.
36134248Sbostic 		 */
36234248Sbostic 		if (format&GFORMAT && expcnt - 1 > prec || format&EFORMAT) {
36334248Sbostic 			if (format&GFORMAT) {
36434248Sbostic 				format |= EFORMAT;
36534248Sbostic 
36634248Sbostic 				/* first digit is precision for g/G format */
36734248Sbostic 				if (prec)
36834248Sbostic 					--prec;
36934248Sbostic 			}
37034248Sbostic 			if (decpt)
37134248Sbostic 				*p2++ = '.';
37234248Sbostic 			for (; ++p < endp && prec; --prec, *p2++ = *p);
37334248Sbostic 
37434318Sbostic 			/* precision ran out, round */
37534248Sbostic 			if (p < endp) {
37634248Sbostic 				if (*p > '4') {
37734248Sbostic 					for (savep = p2--;; *p2-- = '0') {
37834248Sbostic 						if (*p2 == '.')
37934248Sbostic 							--p2;
38034248Sbostic 						if (++*p2 <= '9')
38134248Sbostic 							break;
38234248Sbostic 					}
38334248Sbostic 					p2 = savep;
38434248Sbostic 				}
38534248Sbostic 				fract = 0;
38634248Sbostic 			}
38734242Sbostic 		}
38834248Sbostic 		/*
38934314Sbostic 		 * g/G in f format; if out of precision, replace digits with
39034314Sbostic 		 * zeroes, note, have to round first.
39134248Sbostic 		 */
39234248Sbostic 		else if (format&GFORMAT) {
39334248Sbostic 			for (; ++p < endp && prec; --prec, *p2++ = *p);
39434248Sbostic 			/* precision ran out; round and then add zeroes */
39534248Sbostic 			if (p < endp) {
39634248Sbostic 				if (*p > '4') {
39734248Sbostic 					for (savep = p2--; ++*p2 > '9';
39834248Sbostic 					    *p2-- = '0');
39934248Sbostic 					p2 = savep;
40034248Sbostic 				}
40134248Sbostic 				do {
40234248Sbostic 					*p2++ = '0';
40334248Sbostic 				} while (++p < endp);
40434248Sbostic 				fract = 0;
40534248Sbostic 			}
40634248Sbostic 			if (decpt)
40734248Sbostic 				*p2++ = '.';
40834242Sbostic 		}
40934248Sbostic 		/* f format */
41034248Sbostic 		else {
41134248Sbostic 			for (; ++p < endp; *p2++ = *p);
41234248Sbostic 			if (decpt)
41334248Sbostic 				*p2++ = '.';
41434248Sbostic 		}
41534248Sbostic 		p = p2;
41634248Sbostic 	}
41734248Sbostic 	/*
41834318Sbostic 	 * if no fraction, the number was zero, and if no precision, can't
41934318Sbostic 	 * show anything after the decimal point.
42034248Sbostic 	 */
42134248Sbostic 	else if (!fract || !prec) {
42234248Sbostic 		*startp++ = '0';
42334318Sbostic 		if (decpt && !(format&GFORMAT))
42434248Sbostic 			*startp++ = '.';
42534318Sbostic 		*startp = '\0';
42634323Sbostic 		return(startp);
42734248Sbostic 	}
42834248Sbostic 	/*
42934248Sbostic 	 * if the format is g/G, and the resulting exponent will be less than
43034248Sbostic 	 * -4 use e/E format.  If e/E format, compute exponent value.
43134248Sbostic 	 */
43234248Sbostic 	else if (format&GFORMAT && fract < .0001 || format&EFORMAT) {
43334248Sbostic 		format |= EFORMAT;
43434248Sbostic 		if (fract)
43534248Sbostic 			for (p = startp; fract;) {
43634248Sbostic 				fract = modf(fract * 10, &tmp);
43734248Sbostic 				if (!tmp) {
43834248Sbostic 					--expcnt;
43934248Sbostic 					continue;
44034248Sbostic 				}
44134248Sbostic 				*p++ = (int)tmp + '0';
44234248Sbostic 				break;
44334248Sbostic 			}
44434242Sbostic 		else
44534248Sbostic 			*p++ = '0';
44634248Sbostic 
44734248Sbostic 		/* g/G format, decrement precision for first digit */
44834248Sbostic 		if (format&GFORMAT && prec)
44934248Sbostic 			--prec;
45034248Sbostic 
45134248Sbostic 		/* add decimal after first non-zero digit */
45234248Sbostic 		if (decpt)
45334248Sbostic 			*p++ = '.';
45434242Sbostic 	}
45534248Sbostic 	/*
45634248Sbostic 	 * f format or g/G printed as f format; don't worry about decimal
45734248Sbostic 	 * point, if g/G format doesn't need it, will get stripped later.
45834248Sbostic 	 */
45934242Sbostic 	else {
46034248Sbostic 		p = startp;
46134248Sbostic 		*p++ = '0';
46234248Sbostic 		*p++ = '.';
46334248Sbostic 	}
46434248Sbostic 
46534319Sbostic 	/* finish out requested precision */
46634319Sbostic 	while (fract && prec-- > 0) {
46734319Sbostic 		fract = modf(fract * 10, &tmp);
46834319Sbostic 		*p++ = (int)tmp + '0';
46934319Sbostic 	}
47034319Sbostic 	while (prec-- > 0)
47134319Sbostic 		*p++ = '0';
47234248Sbostic 
47334248Sbostic 	/*
47434248Sbostic 	 * if any fractional value left, "round" it back up to the beginning
47534248Sbostic 	 * of the number, fixing the exponent as necessary, and avoiding the
47634248Sbostic 	 * decimal point.
47734248Sbostic 	 */
47834248Sbostic 	if (fract) {
47934248Sbostic 		(void)modf(fract * 10, &tmp);
48034248Sbostic 		if (tmp > 4) {
48134248Sbostic 			for (savep = p--;; *p-- = '0') {
48234248Sbostic 				if (*p == '.')
48334248Sbostic 					--p;
48434248Sbostic 				if (p == startp) {
48534248Sbostic 					*p = '1';
48634248Sbostic 					++expcnt;
48734248Sbostic 					break;
48834248Sbostic 				}
48934248Sbostic 				if (++*p <= '9')
49034248Sbostic 					break;
49134242Sbostic 			}
49234248Sbostic 			p = savep;
49334242Sbostic 		}
49434248Sbostic 	}
49534248Sbostic 
49634248Sbostic 	/*
49734248Sbostic 	 * if a g/G format and not alternate flag, lose trailing zeroes,
49834248Sbostic 	 * if e/E or g/G format, and last char is decimal point, lose it.
49934248Sbostic 	 */
50034318Sbostic 	if (!(flags&ALT)) {
50134248Sbostic 		if (format&GFORMAT)
50234248Sbostic 			for (; p[-1] == '0'; --p);
50334248Sbostic 		if (format&(GFORMAT|EFORMAT) && p[-1] == '.')
50434248Sbostic 			--p;
50534248Sbostic 	}
50634248Sbostic 
50734248Sbostic 	/* if an e/E format, add exponent */
50834248Sbostic 	if (format&EFORMAT) {
50934248Sbostic 		*p++ = fmtch;
51034248Sbostic 		if (--expcnt < 0) {
51134248Sbostic 			expcnt = -expcnt;
51234248Sbostic 			*p++ = '-';
51334242Sbostic 		}
51434248Sbostic 		else
51534248Sbostic 			*p++ = '+';
51634248Sbostic 		*p++ = expcnt / 10 + '0';
51734248Sbostic 		*p++ = expcnt % 10 + '0';
51834242Sbostic 	}
51934323Sbostic 	return(p);
52034242Sbostic }
521