|
|
1.1 root 1: /*
2: * Alas, doprnt is not documented, so people feel they have license to
3: * change the parameters. The 3B implementation does not even look
4: * callable from C, and without documentation is not comprehensible.
5: * Since many systems have their own doprnt which is written in assembly
6: * language, and thus faster, but callable from C, we try to use the
7: * standard system version where possible. The ifdefs below attempt
8: * to decide where it is possible - it may need to be updated later.
9: */
10:
11: #ifdef u3b
12: #define NEEDDOPRNT
13: #endif
14:
15: #ifdef NEEDDOPRNT
16: /* @(#) doprnt.c: 1.1 10/15/83 (1.4 10/27/82) */
17: /* @(#)doprnt.c 2.4 */
18: /*LINTLIBRARY*/
19: /*
20: * _doprnt: common code for printf, fprintf, sprintf
21: */
22:
23: #include <stdio.h>
24: #include <ctype.h>
25: #include <varargs.h>
26: #include <values.h>
27:
28: /* @(#)print.h 1.3 */
29: /* Maximum number of digits in any integer representation */
30: #define MAXDIGS 11
31:
32: /* Maximum total number of digits in E format */
33: #define MAXECVT 17
34:
35: /* Maximum number of digits after decimal point in F format */
36: #define MAXFCVT 60
37:
38: /* Maximum significant figures in a floating-point number */
39: #define MAXFSIG 17
40:
41: /* Maximum number of characters in an exponent */
42: #if u3b
43: #define MAXESIZ 5
44: #else
45: #define MAXESIZ 4
46: #endif
47:
48: /* Maximum (positive) exponent */
49: #if u3b
50: #define MAXEXP 310
51: #else
52: #define MAXEXP 40
53: #endif
54:
55: /* Data type for flags */
56: typedef char bool;
57:
58: /* Convert a digit character to the corresponding number */
59: #define tonumber(x) ((x)-'0')
60:
61: /* Convert a number between 0 and 9 to the corresponding digit */
62: #define todigit(x) ((x)+'0')
63:
64: /* Max and Min macros */
65: #define max(a,b) ((a) > (b)? (a): (b))
66: #define min(a,b) ((a) < (b)? (a): (b))
67: /* end of print.h */
68:
69: static char *
70: memcpy(dest, src, n)
71: register char *dest, *src;
72: register int n;
73: {
74: register char *rv = dest;
75:
76: while (n--)
77: *dest++ = *src++;
78: return rv;
79: }
80:
81: #define PUT(p, n) if (n == 1) (void) putc(*p, iop); \
82: else if (iop->_file == _NFILE) \
83: iop->_ptr = (unsigned char *) \
84: memcpy((char *)iop->_ptr, p, n) +n; \
85: else (void) fwrite(p, 1, n, iop)
86:
87: /*
88: * C-Library routines for floating conversion
89: */
90: extern char *fcvt(), *ecvt();
91:
92: extern int strlen(), fwrite();
93:
94: int
95: _doprnt(format, args, iop)
96: register char *format;
97: va_list args;
98: register FILE *iop;
99: {
100: /* This variable counts output characters. */
101: int count = 0;
102:
103: /* Starting and ending points for value to be printed */
104: register char *bp, *p;
105:
106: /* Field width and precision */
107: int width, prec;
108:
109: /* Format code */
110: register int fcode;
111:
112: /* Number of padding zeroes required on the left and right */
113: int lzero, rzero;
114:
115: /* Flags - nonzero if corresponding character is in format */
116: int length; /* l */
117: int fplus; /* + */
118: int fminus; /* - */
119: int fblank; /* blank */
120: int fsharp; /* # */
121:
122: /* Values are developed in this buffer */
123: char buf[max(MAXDIGS, 1+max(MAXFCVT+MAXEXP, MAXECVT))];
124:
125: /* Pointer to sign, "0x", "0X", or empty */
126: char *prefix;
127:
128: /* Exponent or empty */
129: char *suffix;
130:
131: /* Buffer to create exponent */
132: char expbuf[MAXESIZ + 1];
133:
134: /* The value being converted, if integer */
135: long val;
136:
137: /* The value being converted, if real */
138: double dval;
139:
140: /* Output values from fcvt and ecvt */
141: int decpt, sign;
142:
143: /* Pointer to a translate table for digits of whatever radix */
144: char *tab;
145:
146: /* Work variables */
147: int k, n, hradix, lowbit;
148:
149: expbuf[MAXESIZ] = '\0';
150:
151: /*
152: * The main loop -- this loop goes through one iteration
153: * for each string of ordinary characters or format specification.
154: */
155: for ( ; ; ) {
156: for (bp = format;
157: (fcode = *format) != '\0' && fcode != '%'; format++)
158: ;
159: if (n = format - bp) { /* ordinary non-% characters */
160: count += n;
161: PUT(bp, n);
162: }
163: if (fcode == '\0') /* end of format; normal return */
164: return (ferror(iop) ? EOF : count);
165: /*
166: * % has been found.
167: * First, parse the format specification.
168: */
169: fplus = fminus = fblank = fsharp = lzero = 0;
170: for ( ; ; ) { /* Scan the <flags> */
171: switch (fcode = *++format) {
172: case '+':
173: fplus++;
174: continue;
175: case '-':
176: fminus++;
177: continue;
178: case ' ':
179: fblank++;
180: continue;
181: case '#':
182: fsharp++;
183: continue;
184: }
185: break;
186: }
187:
188: /* Scan the field width */
189: if (fcode == '*') {
190: width = va_arg(args, int);
191: if (width < 0) {
192: width = -width;
193: fminus++;
194: }
195: format++;
196: } else {
197: if (fcode == '0') /* obsolescent spec. */
198: lzero++; /* pad with leading zeros */
199: for (width = 0; isdigit(fcode = *format); format++)
200: width = width * 10 + tonumber(fcode);
201: }
202:
203: /* Scan the precision */
204: if (*format != '.')
205: prec = lzero ? width : -1;
206: else if (*++format == '*') { /* '*' instead of digits? */
207: prec = va_arg(args, int);
208: format++;
209: } else
210: for (prec = 0; isdigit(fcode = *format); format++)
211: prec = prec * 10 + tonumber(fcode);
212:
213: /* Scan the length modifier */
214: length = 0;
215: switch (*format) {
216: case 'l':
217: length++;
218: /* No break */
219: case 'h':
220: format++;
221: }
222:
223: /*
224: * The character addressed by format must be
225: * the format letter -- there is nothing
226: * left for it to be.
227: *
228: * The status of the +, -, #, and blank
229: * flags are reflected in the variables
230: * "fplus", "fminus", "fsharp", and
231: * "fblank". "width" and "prec" contain
232: * numbers corresponding to the digit
233: * strings before and after the decimal
234: * point, respectively. If there was no
235: * decimal point, "prec" is -1.
236: *
237: * The following switch sets things up
238: * for printing. What ultimately gets
239: * printed will be padding blanks, a
240: * prefix, left padding zeroes, a value,
241: * right padding zeroes, a suffix, and
242: * more padding blanks. Padding blanks
243: * will not appear simultaneously on both
244: * the left and the right. Each case in
245: * this switch will compute the value, and
246: * leave in several variables the informa-
247: * tion necessary to construct what is to
248: * be printed.
249: *
250: * The prefix is a sign, a blank, "0x",
251: * "0X", or null, and is addressed by
252: * "prefix".
253: *
254: * The suffix is either null or an
255: * exponent, and is addressed by "suffix".
256: *
257: * The value to be printed starts at "bp"
258: * and continues up to and not including
259: * "p".
260: *
261: * "lzero" and "rzero" will contain the
262: * number of padding zeroes required on
263: * the left and right, respectively. If
264: * either of these variables is negative,
265: * it will be treated as if it were zero.
266: *
267: * The number of padding blanks, and
268: * whether they go on the left or the
269: * right, will be computed on exit from
270: * the switch.
271: */
272:
273: prefix = "";
274: suffix = &expbuf[MAXESIZ];
275: lzero = rzero = 0;
276:
277: switch (fcode = *format++) {
278:
279: /*
280: * fixed point representations
281: *
282: * "hradix" is half the radix for the
283: * conversion. Conversion is unsigned
284: * unless fcode is 'd'. HIBITL is 100...000
285: * binary, and is equal to the maximum
286: * negative number.
287: * We assume a 2's complement machine
288: */
289:
290: case 'd':
291: case 'u':
292: hradix = 10/2;
293: goto fixed;
294:
295: case 'o':
296: hradix = 8/2;
297: goto fixed;
298:
299: case 'X':
300: case 'x':
301: hradix = 16/2;
302:
303: fixed:
304: /* Establish default precision */
305: if (prec < 0)
306: prec = 1;
307:
308: /* Fetch the argument to be printed */
309: if(length)
310: val = va_arg(args, long);
311: else if(fcode == 'd')
312: val = va_arg(args, int);
313: else
314: val = va_arg(args, unsigned);
315:
316: /* If signed conversion, make sign */
317: if(fcode == 'd') {
318: if(val < 0) {
319: prefix = "-";
320: /*
321: * Negate, checking in
322: * advance for possible
323: * overflow.
324: */
325: if(val != HIBITL)
326: val = -val;
327: } else if (fplus)
328: prefix = "+";
329: else if (fblank)
330: prefix = " ";
331: }
332:
333: /* Set translate table for digits */
334: tab = (fcode == 'X') ?
335: "0123456789ABCDEF" : "0123456789abcdef";
336:
337: /* Develop the digits of the value */
338: p = bp = buf + MAXDIGS;
339: while (val != 0) {
340: lowbit = val & 1;
341: val = (val >> 1) & ~HIBITL;
342: *--bp = tab[val % hradix * 2 + lowbit];
343: val /= hradix;
344: }
345:
346: /* Calculate padding zero requirement */
347: lzero = bp - p + prec;
348:
349: /* Handle the # flag */
350: if (fsharp && bp != p)
351: switch (fcode) {
352: case 'o':
353: if (lzero < 1)
354: lzero = 1;
355: break;
356: case 'x':
357: prefix = "0x";
358: break;
359: case 'X':
360: prefix = "0X";
361: break;
362: }
363:
364: break;
365:
366: case 'E':
367: case 'e':
368: /*
369: * E-format. The general strategy
370: * here is fairly easy: we take
371: * what ecvt gives us and re-format it.
372: */
373:
374: /* Establish default precision */
375: if (prec < 0)
376: prec = 6;
377:
378: /* Fetch the value */
379: dval = va_arg(args, double);
380:
381: /* Develop the mantissa */
382: bp = ecvt(dval, min(prec + 1, MAXECVT), &decpt, &sign);
383:
384: /* Determine the prefix */
385: e_merge:
386: if (sign)
387: prefix = "-";
388: else if (fplus)
389: prefix = "+";
390: else if (fblank)
391: prefix = " ";
392:
393: /* Place the first digit in the buffer*/
394: p = &buf[0];
395: *p++ = (*bp != '\0') ? *bp++ : '0';
396:
397: /* Put in a decimal point if needed */
398: if (prec != 0 || fsharp)
399: *p++ = '.';
400:
401: /* Create the rest of the mantissa */
402: for (rzero = prec; rzero > 0 && *bp != '\0'; --rzero)
403: *p++ = *bp++;
404:
405: bp = &buf[0];
406:
407: /* Create the exponent */
408: if (dval != 0) {
409: n = decpt - 1;
410: if (n < 0)
411: n = -n;
412: for ( ; n != 0; n /= 10)
413: *--suffix = todigit(n % 10);
414: }
415:
416: /* Prepend leading zeroes to the exponent */
417: while (suffix > &expbuf[MAXESIZ - 2])
418: *--suffix = '0';
419:
420: /* Put in the exponent sign */
421: *--suffix = (decpt > 0 || dval == 0) ? '+' : '-';
422:
423: /* Put in the e */
424: *--suffix = isupper(fcode) ? 'E' : 'e';
425:
426: break;
427:
428: case 'f':
429: /*
430: * F-format floating point. This is a
431: * good deal less simple than E-format.
432: * The overall strategy will be to call
433: * fcvt, reformat its result into buf,
434: * and calculate how many trailing
435: * zeroes will be required. There will
436: * never be any leading zeroes needed.
437: */
438:
439: /* Establish default precision */
440: if (prec < 0)
441: prec = 6;
442:
443: /* Fetch the value */
444: dval = va_arg(args, double);
445:
446: /* Do the conversion */
447: bp = fcvt(dval, min(prec, MAXFCVT), &decpt, &sign);
448:
449: /* Determine the prefix */
450: f_merge:
451: if (sign && decpt > -prec && *bp != '0')
452: prefix = "-";
453: else if (fplus)
454: prefix = "+";
455: else if (fblank)
456: prefix = " ";
457:
458: /* Initialize buffer pointer */
459: p = &buf[0];
460:
461: /* Emit the digits before the decimal point */
462: n = decpt;
463: k = 0;
464: do {
465: *p++ = (n <= 0 || *bp == '\0' || k >= MAXFSIG) ?
466: '0' : (k++, *bp++);
467: } while (--n > 0);
468:
469: /* Decide whether we need a decimal point */
470: if (fsharp || prec > 0)
471: *p++ = '.';
472:
473: /* Digits (if any) after the decimal point */
474: n = min(prec, MAXFCVT);
475: rzero = prec - n;
476: while (--n >= 0)
477: *p++ = (++decpt <= 0 || *bp == '\0' ||
478: k >= MAXFSIG) ? '0' : (k++, *bp++);
479:
480: bp = &buf[0];
481:
482: break;
483:
484: case 'G':
485: case 'g':
486: /*
487: * g-format. We play around a bit
488: * and then jump into e or f, as needed.
489: */
490:
491: /* Establish default precision */
492: if (prec < 0)
493: prec = 6;
494:
495: /* Fetch the value */
496: dval = va_arg(args, double);
497:
498: /* Do the conversion */
499: bp = ecvt(dval, min(prec, MAXECVT), &decpt, &sign);
500: if (dval == 0)
501: decpt = 1;
502:
503: k = prec;
504: if (!fsharp) {
505: n = strlen(bp);
506: if (n < k)
507: k = n;
508: while (k >= 1 && bp[k-1] == '0')
509: --k;
510: }
511:
512: if (decpt < -3 || decpt > prec) {
513: prec = k - 1;
514: goto e_merge;
515: }
516: prec = k - decpt;
517: goto f_merge;
518:
519: /* case '%': */
520: default:
521: buf[0] = fcode;
522: goto c_merge;
523:
524: case 'c':
525: buf[0] = va_arg(args, int);
526: c_merge:
527: p = (bp = &buf[0]) + 1;
528: break;
529:
530: case 's':
531: p = bp = va_arg(args, char *);
532: if (prec < 0)
533: p += strlen(bp);
534: else { /* a strnlen function would be useful here! */
535: while (*p++ != '\0' && --prec >= 0)
536: ;
537: --p;
538: }
539: break;
540:
541: case '\0': /* unexpected end of format; return error */
542: return (EOF);
543:
544: }
545:
546: /* Calculate number of padding blanks */
547: if (lzero < 0)
548: lzero = 0;
549: if (rzero < 0)
550: rzero = 0;
551: k = (n = p - bp) + lzero + rzero +
552: (prefix[0] == '\0' ? 0 : prefix[1] == '\0' ? 1 : 2) +
553: (&expbuf[MAXESIZ] - suffix);
554: count += (width > k) ? width : k;
555:
556: /* Blanks on left if required */
557: if (!fminus)
558: while (--width >= k)
559: (void) putc(' ', iop);
560:
561: /* Prefix, if any */
562: while (*prefix != '\0')
563: (void) putc(*prefix++, iop);
564:
565: /* Zeroes on the left */
566: while (--lzero >= 0)
567: (void) putc('0', iop);
568:
569: /* The value itself */
570: if (n > 0)
571: PUT(bp, n);
572:
573: /* Zeroes on the right */
574: while (--rzero >= 0)
575: (void) putc('0', iop);
576:
577: /* The suffix */
578: while (*suffix != '\0')
579: (void) putc(*suffix++, iop);
580:
581: /* Blanks on the right if required */
582: while (--width >= k)
583: (void) putc(' ', iop);
584: }
585: }
586: #else
587: /* This is just to keep from getting a diagnostic from ranlib. */
588: __dpdummy__()
589: {
590: }
591: #endif NEEDDOPRNT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.