Annotation of prex/usr/lib/libc/stdio/vfprintf.c, Revision 1.1.1.1
1.1 nbrk 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. Neither the name of the University nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
34: * Actual printf innards.
35: *
36: * This code is large and complicated...
37: */
38:
39: #include <sys/types.h>
40:
41: #include <limits.h>
42: #include <stdio.h>
43: #include <stdlib.h>
44: #include <string.h>
45: #include <stdarg.h>
46:
47: #include "local.h"
48: #include "fvwrite.h"
49:
50: /*
51: * Flush out all the vectors defined by the given uio,
52: * then reset it so that it can be reused.
53: */
54: static int
55: __sprint(FILE *fp, struct __suio *uio)
56: {
57: int err;
58:
59: if (uio->uio_resid == 0) {
60: uio->uio_iovcnt = 0;
61: return (0);
62: }
63: err = __sfvwrite(fp, uio);
64: uio->uio_resid = 0;
65: uio->uio_iovcnt = 0;
66: return (err);
67: }
68:
69: /*
70: * Helper function for `fprintf to unbuffered unix file': creates a
71: * temporary buffer. We only work on write-only files; this avoids
72: * worries about ungetc buffers and so forth.
73: */
74: static int
75: __sbprintf(FILE *fp, const char *fmt, va_list ap)
76: {
77: int ret;
78: FILE fake;
79: unsigned char buf[BUFSIZ];
80:
81: /* copy the important variables */
82: fake._flags = fp->_flags & ~__SNBF;
83: fake._file = fp->_file;
84:
85: /* set up the buffer */
86: fake._bf._base = fake._p = buf;
87: fake._bf._size = fake._w = sizeof(buf);
88:
89: /* do the work, then copy any error status */
90: ret = vfprintf(&fake, fmt, ap);
91: if (ret >= 0 && fflush(&fake))
92: ret = EOF;
93: if (fake._flags & __SERR)
94: fp->_flags |= __SERR;
95: return (ret);
96: }
97:
98: /*
99: * Macros for converting digits to letters and vice versa
100: */
101: #define to_digit(c) ((c) - '0')
102: #define is_digit(c) ((unsigned)to_digit(c) <= 9)
103: #define to_char(n) ((n) + '0')
104:
105: /*
106: * Convert an unsigned long to ASCII for printf purposes, returning
107: * a pointer to the first character of the string representation.
108: * Octal numbers can be forced to have a leading zero; hex numbers
109: * use the given digits.
110: */
111: static char *
112: __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs)
113: {
114: char *cp = endp;
115: long sval;
116:
117: /*
118: * Handle the three cases separately, in the hope of getting
119: * better/faster code.
120: */
121: switch (base) {
122: case 10:
123: if (val < 10) { /* many numbers are 1 digit */
124: *--cp = to_char(val);
125: return (cp);
126: }
127: /*
128: * On many machines, unsigned arithmetic is harder than
129: * signed arithmetic, so we do at most one unsigned mod and
130: * divide; this is sufficient to reduce the range of
131: * the incoming value to where signed arithmetic works.
132: */
133: if (val > LONG_MAX) {
134: *--cp = to_char(val % 10);
135: sval = val / 10;
136: } else
137: sval = val;
138: do {
139: *--cp = to_char(sval % 10);
140: sval /= 10;
141: } while (sval != 0);
142: break;
143:
144: case 8:
145: do {
146: *--cp = to_char(val & 7);
147: val >>= 3;
148: } while (val);
149: if (octzero && *cp != '0')
150: *--cp = '0';
151: break;
152:
153: case 16:
154: do {
155: *--cp = xdigs[val & 15];
156: val >>= 4;
157: } while (val);
158: break;
159:
160: default: /* oops */
161: abort();
162: }
163: return (cp);
164: }
165:
166:
167: #define BUF 32
168:
169:
170: /*
171: * Flags used during conversion.
172: */
173: #define ALT 0x001 /* alternate form */
174: #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
175: #define LADJUST 0x004 /* left adjustment */
176: #define LONGDBL 0x008 /* long double; unimplemented */
177: #define LONGINT 0x010 /* long integer */
178: #define SHORTINT 0x040 /* short integer */
179: #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
180: int
181: vfprintf(fp, fmt0, ap)
182: FILE *fp;
183: const char *fmt0;
184: va_list ap;
185: {
186: char *fmt; /* format string */
187: int ch; /* character from fmt */
188: int n; /* handy integer (short term usage) */
189: char *cp; /* handy char pointer (short term usage) */
190: struct __siov *iovp; /* for PRINT macro */
191: int flags; /* flags as above */
192: int ret; /* return value accumulator */
193: int width; /* width from format (%8d), or 0 */
194: int prec; /* precision from format (%.3d), or -1 */
195: char sign; /* sign prefix (' ', '+', '-', or \0) */
196: u_long ulval; /* integer arguments %[diouxX] */
197: int base; /* base for [diouxX] conversion */
198: int dprec; /* a copy of prec if [diouxX], 0 otherwise */
199: int fieldsz; /* field size expanded by sign, etc */
200: int realsz; /* field size expanded by dprec */
201: int size; /* size of converted field or string */
202: char *xdigs = NULL; /* digits for [xX] conversion */
203: #define NIOV 8
204: struct __suio uio; /* output information: summary */
205: struct __siov iov[NIOV];/* ... and individual io vectors */
206: char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
207: char ox[2]; /* space for 0x hex-prefix */
208:
209: /*
210: * Choose PADSIZE to trade efficiency vs. size. If larger printf
211: * fields occur frequently, increase PADSIZE and make the initialisers
212: * below longer.
213: */
214: #define PADSIZE 16 /* pad chunk size */
215: static char blanks[PADSIZE] =
216: {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
217: static char zeroes[PADSIZE] =
218: {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
219:
220: /*
221: * BEWARE, these `goto error' on error, and PAD uses `n'.
222: */
223: #define PRINT(ptr, len) { \
224: iovp->iov_base = (ptr); \
225: iovp->iov_len = (len); \
226: uio.uio_resid += (len); \
227: iovp++; \
228: if (++uio.uio_iovcnt >= NIOV) { \
229: if (__sprint(fp, &uio)) \
230: goto error; \
231: iovp = iov; \
232: } \
233: }
234: #define PAD(howmany, with) { \
235: if ((n = (howmany)) > 0) { \
236: while (n > PADSIZE) { \
237: PRINT(with, PADSIZE); \
238: n -= PADSIZE; \
239: } \
240: PRINT(with, n); \
241: } \
242: }
243: #define FLUSH() { \
244: if (uio.uio_resid && __sprint(fp, &uio)) \
245: goto error; \
246: uio.uio_iovcnt = 0; \
247: iovp = iov; \
248: }
249:
250: /*
251: * To extend shorts properly, we need both signed and unsigned
252: * argument extraction methods.
253: */
254: #define SARG() \
255: (flags&LONGINT ? va_arg(ap, long) : \
256: flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
257: (long)va_arg(ap, int))
258: #define UARG() \
259: (flags&LONGINT ? va_arg(ap, u_long) : \
260: flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
261: (u_long)va_arg(ap, u_int))
262:
263: /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
264: if (cantwrite(fp))
265: return (EOF);
266:
267: /* optimise fprintf(stderr) (and other unbuffered Unix files) */
268: if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
269: fp->_file >= 0)
270: return (__sbprintf(fp, fmt0, ap));
271:
272: fmt = (char *)fmt0;
273: uio.uio_iov = iovp = iov;
274: uio.uio_resid = 0;
275: uio.uio_iovcnt = 0;
276: ret = 0;
277:
278: /*
279: * Scan the format for conversions (`%' character).
280: */
281: for (;;) {
282: for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
283: /* void */;
284: if ((n = fmt - cp) != 0) {
285: PRINT(cp, n);
286: ret += n;
287: }
288: if (ch == '\0')
289: goto done;
290: fmt++; /* skip over '%' */
291:
292: flags = 0;
293: dprec = 0;
294: width = 0;
295: prec = -1;
296: sign = '\0';
297:
298: rflag: ch = *fmt++;
299: reswitch: switch (ch) {
300: case ' ':
301: /*
302: * ``If the space and + flags both appear, the space
303: * flag will be ignored.''
304: * -- ANSI X3J11
305: */
306: if (!sign)
307: sign = ' ';
308: goto rflag;
309: case '#':
310: flags |= ALT;
311: goto rflag;
312: case '*':
313: /*
314: * ``A negative field width argument is taken as a
315: * - flag followed by a positive field width.''
316: * -- ANSI X3J11
317: * They don't exclude field widths read from args.
318: */
319: if ((width = va_arg(ap, int)) >= 0)
320: goto rflag;
321: width = -width;
322: /* FALLTHROUGH */
323: case '-':
324: flags |= LADJUST;
325: goto rflag;
326: case '+':
327: sign = '+';
328: goto rflag;
329: case '.':
330: if ((ch = *fmt++) == '*') {
331: n = va_arg(ap, int);
332: prec = n < 0 ? -1 : n;
333: goto rflag;
334: }
335: n = 0;
336: while (is_digit(ch)) {
337: n = 10 * n + to_digit(ch);
338: ch = *fmt++;
339: }
340: prec = n < 0 ? -1 : n;
341: goto reswitch;
342: case '0':
343: /*
344: * ``Note that 0 is taken as a flag, not as the
345: * beginning of a field width.''
346: * -- ANSI X3J11
347: */
348: flags |= ZEROPAD;
349: goto rflag;
350: case '1': case '2': case '3': case '4':
351: case '5': case '6': case '7': case '8': case '9':
352: n = 0;
353: do {
354: n = 10 * n + to_digit(ch);
355: ch = *fmt++;
356: } while (is_digit(ch));
357: width = n;
358: goto reswitch;
359: case 'h':
360: flags |= SHORTINT;
361: goto rflag;
362: case 'l':
363: flags |= LONGINT;
364: goto rflag;
365: case 'c':
366: *(cp = buf) = va_arg(ap, int);
367: size = 1;
368: sign = '\0';
369: break;
370: case 'D':
371: flags |= LONGINT;
372: /*FALLTHROUGH*/
373: case 'd':
374: case 'i':
375: ulval = SARG();
376: if ((long)ulval < 0) {
377: ulval = -ulval;
378: sign = '-';
379: }
380: base = 10;
381: goto number;
382: case 'n':
383: if (flags & LONGINT)
384: *va_arg(ap, long *) = ret;
385: else if (flags & SHORTINT)
386: *va_arg(ap, short *) = ret;
387: else
388: *va_arg(ap, int *) = ret;
389: continue; /* no output */
390: case 'O':
391: flags |= LONGINT;
392: /*FALLTHROUGH*/
393: case 'o':
394: ulval = UARG();
395: base = 8;
396: goto nosign;
397: case 'p':
398: /*
399: * ``The argument shall be a pointer to void. The
400: * value of the pointer is converted to a sequence
401: * of printable characters, in an implementation-
402: * defined manner.''
403: * -- ANSI X3J11
404: */
405: ulval = (u_long)va_arg(ap, void *);
406: base = 16;
407: xdigs = "0123456789abcdef";
408: flags |= HEXPREFIX;
409: ch = 'x';
410: goto nosign;
411: case 's':
412: if ((cp = va_arg(ap, char *)) == NULL)
413: cp = "(null)";
414: if (prec >= 0) {
415: /*
416: * can't use strlen; can only look for the
417: * NUL in the first `prec' characters, and
418: * strlen() will go further.
419: */
420: char *p = memchr(cp, 0, prec);
421:
422: if (p != NULL) {
423: size = p - cp;
424: if (size > prec)
425: size = prec;
426: } else
427: size = prec;
428: } else
429: size = strlen(cp);
430: sign = '\0';
431: break;
432: case 'U':
433: flags |= LONGINT;
434: /*FALLTHROUGH*/
435: case 'u':
436: ulval = UARG();
437: base = 10;
438: goto nosign;
439: case 'X':
440: xdigs = "0123456789ABCDEF";
441: goto hex;
442: case 'x':
443: xdigs = "0123456789abcdef";
444: hex:
445: ulval = UARG();
446: base = 16;
447: /* leading 0x/X only if non-zero */
448: if (flags & ALT && ulval != 0)
449: flags |= HEXPREFIX;
450:
451: /* unsigned conversions */
452: nosign: sign = '\0';
453: /*
454: * ``... diouXx conversions ... if a precision is
455: * specified, the 0 flag will be ignored.''
456: * -- ANSI X3J11
457: */
458: number: if ((dprec = prec) >= 0)
459: flags &= ~ZEROPAD;
460:
461: /*
462: * ``The result of converting a zero value with an
463: * explicit precision of zero is no characters.''
464: * -- ANSI X3J11
465: */
466: cp = buf + BUF;
467: if (ulval != 0 || prec != 0)
468: cp = __ultoa(ulval, cp, base,
469: flags & ALT, xdigs);
470: size = buf + BUF - cp;
471: break;
472: default: /* "%?" prints ?, unless ? is NUL */
473: if (ch == '\0')
474: goto done;
475: /* pretend it was %c with argument ch */
476: cp = buf;
477: *cp = ch;
478: size = 1;
479: sign = '\0';
480: break;
481: }
482:
483: /*
484: * All reasonable formats wind up here. At this point, `cp'
485: * points to a string which (if not flags&LADJUST) should be
486: * padded out to `width' places. If flags&ZEROPAD, it should
487: * first be prefixed by any sign or other prefix; otherwise,
488: * it should be blank padded before the prefix is emitted.
489: * After any left-hand padding and prefixing, emit zeroes
490: * required by a decimal [diouxX] precision, then print the
491: * string proper, then emit zeroes required by any leftover
492: * floating precision; finally, if LADJUST, pad with blanks.
493: *
494: * Compute actual size, so we know how much to pad.
495: * fieldsz excludes decimal prec; realsz includes it.
496: */
497: fieldsz = size;
498: if (sign)
499: fieldsz++;
500: else if (flags & HEXPREFIX)
501: fieldsz += 2;
502: realsz = dprec > fieldsz ? dprec : fieldsz;
503:
504: /* right-adjusting blank padding */
505: if ((flags & (LADJUST|ZEROPAD)) == 0)
506: PAD(width - realsz, blanks);
507:
508: /* prefix */
509: if (sign) {
510: PRINT(&sign, 1);
511: } else if (flags & HEXPREFIX) {
512: ox[0] = '0';
513: ox[1] = ch;
514: PRINT(ox, 2);
515: }
516:
517: /* right-adjusting zero padding */
518: if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
519: PAD(width - realsz, zeroes);
520:
521: /* leading zeroes from decimal precision */
522: PAD(dprec - fieldsz, zeroes);
523:
524: /* the string or number proper */
525: PRINT(cp, size);
526:
527: /* left-adjusting padding (always blank) */
528: if (flags & LADJUST)
529: PAD(width - realsz, blanks);
530:
531: /* finally, adjust ret */
532: ret += width > realsz ? width : realsz;
533:
534: FLUSH(); /* copy out the I/O vectors */
535: }
536: done:
537: FLUSH();
538: error:
539: return (__sferror(fp) ? EOF : ret);
540: /* NOTREACHED */
541: }
CVSweb