|
|
1.1 root 1: /*
2: * Copyright (c) 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #if defined(LIBC_SCCS) && !defined(lint)
21: static char sccsid[] = "@(#)doprnt.c 5.39 (Berkeley) 6/28/90";
22: #endif /* LIBC_SCCS and not lint */
23:
24: #include <sys/types.h>
25: #include <varargs.h>
26: #include <stdio.h>
27: #include <ctype.h>
28:
29: /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
30: #define MAXEXP 308
31: /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
32: #define MAXFRACT 39
33:
34: #define DEFPREC 6
35:
36: #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
37:
38: #define PUTC(ch) (void) putc(ch, fp)
39:
40: #define ARG(basetype) \
41: _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
42: flags&SHORTINT ? (short basetype)va_arg(argp, int) : \
43: va_arg(argp, int)
44:
45: #define todigit(c) ((c) - '0')
46: #define tochar(n) ((n) + '0')
47:
48: /* have to deal with the negative buffer count kludge */
49: #define NEGATIVE_COUNT_KLUDGE
50:
51: #define LONGINT 0x01 /* long integer */
52: #define LONGDBL 0x02 /* long double; unimplemented */
53: #define SHORTINT 0x04 /* short integer */
54: #define ALT 0x08 /* alternate form */
55: #define LADJUST 0x10 /* left adjustment */
56: #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */
57: #define HEXPREFIX 0x40 /* add 0x or 0X prefix */
58:
59: _doprnt(fmt0, argp, fp)
60: u_char *fmt0;
61: va_list argp;
62: register FILE *fp;
63: {
64: register u_char *fmt; /* format string */
65: register int ch; /* character from fmt */
66: register int cnt; /* return value accumulator */
67: register int n; /* random handy integer */
68: register char *t; /* buffer pointer */
69: double _double; /* double precision arguments %[eEfgG] */
70: u_long _ulong; /* integer arguments %[diouxX] */
71: int base; /* base for [diouxX] conversion */
72: int dprec; /* decimal precision in [diouxX] */
73: int fieldsz; /* field size expanded by sign, etc */
74: int flags; /* flags as above */
75: int fpprec; /* `extra' floating precision in [eEfgG] */
76: int prec; /* precision from format (%.3d), or -1 */
77: int realsz; /* field size expanded by decimal precision */
78: int size; /* size of converted field or string */
79: int width; /* width from format (%8d), or 0 */
80: char sign; /* sign prefix (' ', '+', '-', or \0) */
81: char softsign; /* temporary negative sign for floats */
82: char *digs; /* digits for [diouxX] conversion */
83: char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
84:
85: if (fp->_flag & _IORW) {
86: fp->_flag |= _IOWRT;
87: fp->_flag &= ~(_IOEOF|_IOREAD);
88: }
89: if ((fp->_flag & _IOWRT) == 0)
90: return (EOF);
91:
92: fmt = fmt0;
93: digs = "0123456789abcdef";
94: for (cnt = 0;; ++fmt) {
95: n = fp->_cnt;
96: for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%';
97: ++cnt, ++fmt)
98: if (--n < 0
99: #ifdef NEGATIVE_COUNT_KLUDGE
100: && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz)
101: #endif
102: || ch == '\n' && fp->_flag & _IOLBF) {
103: fp->_cnt = n;
104: fp->_ptr = t;
105: (void) _flsbuf((u_char)ch, fp);
106: n = fp->_cnt;
107: t = (char *)fp->_ptr;
108: } else
109: *t++ = ch;
110: fp->_cnt = n;
111: fp->_ptr = t;
112: if (!ch)
113: return (cnt);
114:
115: flags = 0; dprec = 0; fpprec = 0; width = 0;
116: prec = -1;
117: sign = '\0';
118:
119: rflag: switch (*++fmt) {
120: case ' ':
121: /*
122: * ``If the space and + flags both appear, the space
123: * flag will be ignored.''
124: * -- ANSI X3J11
125: */
126: if (!sign)
127: sign = ' ';
128: goto rflag;
129: case '#':
130: flags |= ALT;
131: goto rflag;
132: case '*':
133: /*
134: * ``A negative field width argument is taken as a
135: * - flag followed by a positive field width.''
136: * -- ANSI X3J11
137: * They don't exclude field widths read from args.
138: */
139: if ((width = va_arg(argp, int)) >= 0)
140: goto rflag;
141: width = -width;
142: /* FALLTHROUGH */
143: case '-':
144: flags |= LADJUST;
145: goto rflag;
146: case '+':
147: sign = '+';
148: goto rflag;
149: case '.':
150: if (*++fmt == '*')
151: n = va_arg(argp, int);
152: else {
153: n = 0;
154: while (isascii(*fmt) && isdigit(*fmt))
155: n = 10 * n + todigit(*fmt++);
156: --fmt;
157: }
158: prec = n < 0 ? -1 : n;
159: goto rflag;
160: case '0':
161: /*
162: * ``Note that 0 is taken as a flag, not as the
163: * beginning of a field width.''
164: * -- ANSI X3J11
165: */
166: flags |= ZEROPAD;
167: goto rflag;
168: case '1': case '2': case '3': case '4':
169: case '5': case '6': case '7': case '8': case '9':
170: n = 0;
171: do {
172: n = 10 * n + todigit(*fmt);
173: } while (isascii(*++fmt) && isdigit(*fmt));
174: width = n;
175: --fmt;
176: goto rflag;
177: case 'L':
178: flags |= LONGDBL;
179: goto rflag;
180: case 'h':
181: flags |= SHORTINT;
182: goto rflag;
183: case 'l':
184: flags |= LONGINT;
185: goto rflag;
186: case 'c':
187: *(t = buf) = va_arg(argp, int);
188: size = 1;
189: sign = '\0';
190: goto pforw;
191: case 'D':
192: flags |= LONGINT;
193: /*FALLTHROUGH*/
194: case 'd':
195: case 'i':
196: ARG(int);
197: if ((long)_ulong < 0) {
198: _ulong = -_ulong;
199: sign = '-';
200: }
201: base = 10;
202: goto number;
203: case 'e':
204: case 'E':
205: case 'f':
206: case 'g':
207: case 'G':
208: _double = va_arg(argp, double);
209: /*
210: * don't do unrealistic precision; just pad it with
211: * zeroes later, so buffer size stays rational.
212: */
213: if (prec > MAXFRACT) {
214: if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
215: fpprec = prec - MAXFRACT;
216: prec = MAXFRACT;
217: }
218: else if (prec == -1)
219: prec = DEFPREC;
220: /*
221: * softsign avoids negative 0 if _double is < 0 and
222: * no significant digits will be shown
223: */
224: if (_double < 0) {
225: softsign = '-';
226: _double = -_double;
227: }
228: else
229: softsign = 0;
230: /*
231: * cvt may have to round up past the "start" of the
232: * buffer, i.e. ``intf("%.2f", (double)9.999);'';
233: * if the first char isn't NULL, it did.
234: */
235: *buf = NULL;
236: size = cvt(_double, prec, flags, &softsign, *fmt, buf,
237: buf + sizeof(buf));
238: if (softsign)
239: sign = '-';
240: t = *buf ? buf : buf + 1;
241: goto pforw;
242: case 'n':
243: if (flags & LONGINT)
244: *va_arg(argp, long *) = cnt;
245: else if (flags & SHORTINT)
246: *va_arg(argp, short *) = cnt;
247: else
248: *va_arg(argp, int *) = cnt;
249: break;
250: case 'O':
251: flags |= LONGINT;
252: /*FALLTHROUGH*/
253: case 'o':
254: ARG(unsigned);
255: base = 8;
256: goto nosign;
257: case 'p':
258: /*
259: * ``The argument shall be a pointer to void. The
260: * value of the pointer is converted to a sequence
261: * of printable characters, in an implementation-
262: * defined manner.''
263: * -- ANSI X3J11
264: */
265: /* NOSTRICT */
266: _ulong = (u_long)va_arg(argp, void *);
267: base = 16;
268: goto nosign;
269: case 's':
270: if (!(t = va_arg(argp, char *)))
271: t = "(null)";
272: if (prec >= 0) {
273: /*
274: * can't use strlen; can only look for the
275: * NUL in the first `prec' characters, and
276: * strlen() will go further.
277: */
278: char *p, *memchr();
279:
280: if (p = memchr(t, 0, prec)) {
281: size = p - t;
282: if (size > prec)
283: size = prec;
284: } else
285: size = prec;
286: } else
287: size = strlen(t);
288: sign = '\0';
289: goto pforw;
290: case 'U':
291: flags |= LONGINT;
292: /*FALLTHROUGH*/
293: case 'u':
294: ARG(unsigned);
295: base = 10;
296: goto nosign;
297: case 'X':
298: digs = "0123456789ABCDEF";
299: /* FALLTHROUGH */
300: case 'x':
301: ARG(unsigned);
302: base = 16;
303: /* leading 0x/X only if non-zero */
304: if (flags & ALT && _ulong != 0)
305: flags |= HEXPREFIX;
306:
307: /* unsigned conversions */
308: nosign: sign = '\0';
309: /*
310: * ``... diouXx conversions ... if a precision is
311: * specified, the 0 flag will be ignored.''
312: * -- ANSI X3J11
313: */
314: number: if ((dprec = prec) >= 0)
315: flags &= ~ZEROPAD;
316:
317: /*
318: * ``The result of converting a zero value with an
319: * explicit precision of zero is no characters.''
320: * -- ANSI X3J11
321: */
322: t = buf + BUF;
323: if (_ulong != 0 || prec != 0) {
324: do {
325: *--t = digs[_ulong % base];
326: _ulong /= base;
327: } while (_ulong);
328: digs = "0123456789abcdef";
329: if (flags & ALT && base == 8 && *t != '0')
330: *--t = '0'; /* octal leading 0 */
331: }
332: size = buf + BUF - t;
333:
334: pforw:
335: /*
336: * All reasonable formats wind up here. At this point,
337: * `t' points to a string which (if not flags&LADJUST)
338: * should be padded out to `width' places. If
339: * flags&ZEROPAD, it should first be prefixed by any
340: * sign or other prefix; otherwise, it should be blank
341: * padded before the prefix is emitted. After any
342: * left-hand padding and prefixing, emit zeroes
343: * required by a decimal [diouxX] precision, then print
344: * the string proper, then emit zeroes required by any
345: * leftover floating precision; finally, if LADJUST,
346: * pad with blanks.
347: */
348:
349: /*
350: * compute actual size, so we know how much to pad
351: * fieldsz excludes decimal prec; realsz includes it
352: */
353: fieldsz = size + fpprec;
354: if (sign)
355: fieldsz++;
356: if (flags & HEXPREFIX)
357: fieldsz += 2;
358: realsz = dprec > fieldsz ? dprec : fieldsz;
359:
360: /* right-adjusting blank padding */
361: if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
362: for (n = realsz; n < width; n++)
363: PUTC(' ');
364: /* prefix */
365: if (sign)
366: PUTC(sign);
367: if (flags & HEXPREFIX) {
368: PUTC('0');
369: PUTC((char)*fmt);
370: }
371: /* right-adjusting zero padding */
372: if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
373: for (n = realsz; n < width; n++)
374: PUTC('0');
375: /* leading zeroes from decimal precision */
376: for (n = fieldsz; n < dprec; n++)
377: PUTC('0');
378:
379: /* the string or number proper */
380: n = size;
381: if (fp->_cnt - n >= 0 && (fp->_flag & _IOLBF) == 0) {
382: fp->_cnt -= n;
383: bcopy(t, (char *)fp->_ptr, n);
384: fp->_ptr += n;
385: } else
386: while (--n >= 0)
387: PUTC(*t++);
388: /* trailing f.p. zeroes */
389: while (--fpprec >= 0)
390: PUTC('0');
391: /* left-adjusting padding (always blank) */
392: if (flags & LADJUST)
393: for (n = realsz; n < width; n++)
394: PUTC(' ');
395: /* finally, adjust cnt */
396: cnt += width > realsz ? width : realsz;
397: break;
398: case '\0': /* "%?" prints ?, unless ? is NULL */
399: return (cnt);
400: default:
401: PUTC((char)*fmt);
402: cnt++;
403: }
404: }
405: /* NOTREACHED */
406: }
407:
408: static
409: cvt(number, prec, flags, signp, fmtch, startp, endp)
410: double number;
411: register int prec;
412: int flags;
413: u_char fmtch;
414: char *signp, *startp, *endp;
415: {
416: register char *p, *t;
417: register double fract;
418: int dotrim, expcnt, gformat;
419: double integer, tmp, modf();
420: char *exponent(), *round();
421:
422: #ifdef hp300
423: if (expcnt = isspecial(number, startp, signp))
424: return(expcnt);
425: #endif
426:
427: dotrim = expcnt = gformat = 0;
428: fract = modf(number, &integer);
429:
430: /* get an extra slot for rounding. */
431: t = ++startp;
432:
433: /*
434: * get integer portion of number; put into the end of the buffer; the
435: * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
436: */
437: for (p = endp - 1; integer; ++expcnt) {
438: tmp = modf(integer / 10, &integer);
439: *p-- = tochar((int)((tmp + .01) * 10));
440: }
441: switch(fmtch) {
442: case 'f':
443: /* reverse integer into beginning of buffer */
444: if (expcnt)
445: for (; ++p < endp; *t++ = *p);
446: else
447: *t++ = '0';
448: /*
449: * if precision required or alternate flag set, add in a
450: * decimal point.
451: */
452: if (prec || flags&ALT)
453: *t++ = '.';
454: /* if requires more precision and some fraction left */
455: if (fract) {
456: if (prec)
457: do {
458: fract = modf(fract * 10, &tmp);
459: *t++ = tochar((int)tmp);
460: } while (--prec && fract);
461: if (fract)
462: startp = round(fract, (int *)NULL, startp,
463: t - 1, (char)0, signp);
464: }
465: for (; prec--; *t++ = '0');
466: break;
467: case 'e':
468: case 'E':
469: eformat: if (expcnt) {
470: *t++ = *++p;
471: if (prec || flags&ALT)
472: *t++ = '.';
473: /* if requires more precision and some integer left */
474: for (; prec && ++p < endp; --prec)
475: *t++ = *p;
476: /*
477: * if done precision and more of the integer component,
478: * round using it; adjust fract so we don't re-round
479: * later.
480: */
481: if (!prec && ++p < endp) {
482: fract = 0;
483: startp = round((double)0, &expcnt, startp,
484: t - 1, *p, signp);
485: }
486: /* adjust expcnt for digit in front of decimal */
487: --expcnt;
488: }
489: /* until first fractional digit, decrement exponent */
490: else if (fract) {
491: /* adjust expcnt for digit in front of decimal */
492: for (expcnt = -1;; --expcnt) {
493: fract = modf(fract * 10, &tmp);
494: if (tmp)
495: break;
496: }
497: *t++ = tochar((int)tmp);
498: if (prec || flags&ALT)
499: *t++ = '.';
500: }
501: else {
502: *t++ = '0';
503: if (prec || flags&ALT)
504: *t++ = '.';
505: }
506: /* if requires more precision and some fraction left */
507: if (fract) {
508: if (prec)
509: do {
510: fract = modf(fract * 10, &tmp);
511: *t++ = tochar((int)tmp);
512: } while (--prec && fract);
513: if (fract)
514: startp = round(fract, &expcnt, startp,
515: t - 1, (char)0, signp);
516: }
517: /* if requires more precision */
518: for (; prec--; *t++ = '0');
519:
520: /* unless alternate flag, trim any g/G format trailing 0's */
521: if (gformat && !(flags&ALT)) {
522: while (t > startp && *--t == '0');
523: if (*t == '.')
524: --t;
525: ++t;
526: }
527: t = exponent(t, expcnt, fmtch);
528: break;
529: case 'g':
530: case 'G':
531: /* a precision of 0 is treated as a precision of 1. */
532: if (!prec)
533: ++prec;
534: /*
535: * ``The style used depends on the value converted; style e
536: * will be used only if the exponent resulting from the
537: * conversion is less than -4 or greater than the precision.''
538: * -- ANSI X3J11
539: */
540: if (expcnt > prec || !expcnt && fract && fract < .0001) {
541: /*
542: * g/G format counts "significant digits, not digits of
543: * precision; for the e/E format, this just causes an
544: * off-by-one problem, i.e. g/G considers the digit
545: * before the decimal point significant and e/E doesn't
546: * count it as precision.
547: */
548: --prec;
549: fmtch -= 2; /* G->E, g->e */
550: gformat = 1;
551: goto eformat;
552: }
553: /*
554: * reverse integer into beginning of buffer,
555: * note, decrement precision
556: */
557: if (expcnt)
558: for (; ++p < endp; *t++ = *p, --prec);
559: else
560: *t++ = '0';
561: /*
562: * if precision required or alternate flag set, add in a
563: * decimal point. If no digits yet, add in leading 0.
564: */
565: if (prec || flags&ALT) {
566: dotrim = 1;
567: *t++ = '.';
568: }
569: else
570: dotrim = 0;
571: /* if requires more precision and some fraction left */
572: if (fract) {
573: if (prec) {
574: do {
575: fract = modf(fract * 10, &tmp);
576: *t++ = tochar((int)tmp);
577: } while(!tmp);
578: while (--prec && fract) {
579: fract = modf(fract * 10, &tmp);
580: *t++ = tochar((int)tmp);
581: }
582: }
583: if (fract)
584: startp = round(fract, (int *)NULL, startp,
585: t - 1, (char)0, signp);
586: }
587: /* alternate format, adds 0's for precision, else trim 0's */
588: if (flags&ALT)
589: for (; prec--; *t++ = '0');
590: else if (dotrim) {
591: while (t > startp && *--t == '0');
592: if (*t != '.')
593: ++t;
594: }
595: }
596: return(t - startp);
597: }
598:
599: static char *
600: round(fract, exp, start, end, ch, signp)
601: double fract;
602: int *exp;
603: register char *start, *end;
604: char ch, *signp;
605: {
606: double tmp;
607:
608: if (fract)
609: (void)modf(fract * 10, &tmp);
610: else
611: tmp = todigit(ch);
612: if (tmp > 4)
613: for (;; --end) {
614: if (*end == '.')
615: --end;
616: if (++*end <= '9')
617: break;
618: *end = '0';
619: if (end == start) {
620: if (exp) { /* e/E; increment exponent */
621: *end = '1';
622: ++*exp;
623: }
624: else { /* f; add extra digit */
625: *--end = '1';
626: --start;
627: }
628: break;
629: }
630: }
631: /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
632: else if (*signp == '-')
633: for (;; --end) {
634: if (*end == '.')
635: --end;
636: if (*end != '0')
637: break;
638: if (end == start)
639: *signp = 0;
640: }
641: return(start);
642: }
643:
644: static char *
645: exponent(p, exp, fmtch)
646: register char *p;
647: register int exp;
648: u_char fmtch;
649: {
650: register char *t;
651: char expbuf[MAXEXP];
652:
653: *p++ = fmtch;
654: if (exp < 0) {
655: exp = -exp;
656: *p++ = '-';
657: }
658: else
659: *p++ = '+';
660: t = expbuf + MAXEXP;
661: if (exp > 9) {
662: do {
663: *--t = tochar(exp % 10);
664: } while ((exp /= 10) > 9);
665: *--t = tochar(exp);
666: for (; t < expbuf + MAXEXP; *p++ = *t++);
667: }
668: else {
669: *p++ = '0';
670: *p++ = tochar(exp);
671: }
672: return(p);
673: }
674:
675: #ifdef hp300
676: isspecial(d, bufp, signp)
677: double d;
678: char *bufp, *signp;
679: {
680: register struct IEEEdp {
681: unsigned sign:1;
682: unsigned exp:11;
683: unsigned manh:20;
684: unsigned manl:32;
685: } *ip = (struct IEEEdp *)&d;
686:
687: if (ip->exp != 0x7ff)
688: return(0);
689: if (ip->manh || ip->manl)
690: (void)strcpy(bufp, "NaN");
691: else
692: (void)strcpy(bufp, "Inf");
693: return(3);
694: }
695: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.