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