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