Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4973 right-hear 1
/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
2
/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */
3
#include 
4
#include 
5
#include 
6
#include 
7
#include 
8
#include 
9
#include 
10
#include 
11
#include 
12
#include 
13
#include 
14
#include 
15
 
16
static char decimal = '.';
17
 
18
/* 11-bit exponent (VAX G floating point) is 308 decimal digits */
19
#define	MAXEXP		308
20
#define MAXEXPLD        4952 /* this includes subnormal numbers */
21
/* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
22
#define	MAXFRACT	39
23
 
24
#define	DEFPREC		6
25
#define	DEFLPREC	6
26
 
27
#define	BUF		(MAXEXPLD+MAXFRACT+1)	/* + decimal point */
28
 
29
#define	PUTC(ch)	(void) putc(ch, fp)
30
 
31
#define ARG(basetype) \
32
	_ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
33
	    flags&SHORTINT ? (short basetype)va_arg(argp, int) : \
34
	    va_arg(argp, int)
35
 
36
static int nan2 = 0;
37
 
38
static __inline__ int todigit(char c)
39
{
40
  if (c<='0') return 0;
41
  if (c>='9') return 9;
42
  return c-'0';
43
}
44
static __inline__ char tochar(int n)
45
{
46
  if (n>=9) return '9';
47
  if (n<=0) return '0';
48
  return n+'0';
49
}
50
 
51
/* have to deal with the negative buffer count kludge */
52
 
53
#define	LONGINT		0x01		/* long integer */
54
#define	LONGDBL		0x02		/* long double */
55
#define	SHORTINT	0x04		/* short integer */
56
#define	ALT		0x08		/* alternate form */
57
#define	LADJUST		0x10		/* left adjustment */
58
#define	ZEROPAD		0x20		/* zero (as opposed to blank) pad */
59
#define	HEXPREFIX	0x40		/* add 0x or 0X prefix */
60
 
61
static cvtl(long double number, int prec, int flags, char *signp,
62
	    unsigned char fmtch, char *startp, char *endp);
63
static char *roundl(long double fract, int *expv, char *start, char *end,
64
		    char ch, char *signp);
65
static char *exponentl(char *p, int expv, unsigned char fmtch);
66
static int isspeciall(long double d, char *bufp);
67
 
68
static char NULL_REP[] = "(null)";
69
 
70
int
71
_doprnt(const char *fmt0, va_list argp, FILE *fp)
72
{
73
  const char *fmt;		/* format string */
74
  int ch;			/* character from fmt */
75
  int cnt;			/* return value accumulator */
76
  int n;			/* random handy integer */
77
  char *t;			/* buffer pointer */
78
  long double _ldouble;		/* double and long double precision arguments
79
				   %L.[eEfgG] */
80
  unsigned long _ulong;		/* integer arguments %[diouxX] */
81
  int base;			/* base for [diouxX] conversion */
82
  int dprec;			/* decimal precision in [diouxX] */
83
  int fieldsz;			/* field size expanded by sign, etc */
84
  int flags;			/* flags as above */
85
  int fpprec;			/* `extra' floating precision in [eEfgG] */
86
  int prec;			/* precision from format (%.3d), or -1 */
87
  int realsz;			/* field size expanded by decimal precision */
88
  int size;			/* size of converted field or string */
89
  int width;			/* width from format (%8d), or 0 */
90
  char sign;			/* sign prefix (' ', '+', '-', or \0) */
91
  char softsign;		/* temporary negative sign for floats */
92
  const char *digs;		/* digits for [diouxX] conversion */
93
  char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
94
 
95
  decimal = localeconv()->decimal_point[0];
96
 
97
  if (fp->_flag & _IORW)
98
  {
99
    fp->_flag |= _IOWRT;
100
    fp->_flag &= ~(_IOEOF|_IOREAD);
101
  }
102
  if ((fp->_flag & _IOWRT) == 0)
103
    return (EOF);
104
 
105
  fmt = fmt0;
106
  digs = "0123456789abcdef";
107
  for (cnt = 0;; ++fmt)
108
  {
109
    n = fp->_cnt;
110
    for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%';
111
	 ++cnt, ++fmt)
112
      if ((--n < 0
113
	   && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz))
114
	  || (ch == '\n' && fp->_flag & _IOLBF))
115
      {
116
	fp->_cnt = n;
117
	fp->_ptr = t;
118
	(void) _flsbuf((unsigned char)ch, fp);
119
	n = fp->_cnt;
120
	t = (char *)fp->_ptr;
121
      }
122
      else
123
	*t++ = ch;
124
    fp->_cnt = n;
125
    fp->_ptr = t;
126
    if (!ch)
127
      return cnt;
128
    flags = 0; dprec = 0; fpprec = 0; width = 0;
129
    prec = -1;
130
    sign = '\0';
131
  rflag:
132
    switch (*++fmt)
133
    {
134
    case ' ':
135
      /*
136
       * ``If the space and + flags both appear, the space
137
       * flag will be ignored.''
138
       *	-- ANSI X3J11
139
       */
140
      if (!sign)
141
	sign = ' ';
142
      goto rflag;
143
    case '#':
144
      flags |= ALT;
145
      goto rflag;
146
    case '*':
147
      /*
148
       * ``A negative field width argument is taken as a
149
       * - flag followed by a  positive field width.''
150
       *	-- ANSI X3J11
151
       * They don't exclude field widths read from args.
152
       */
153
      if ((width = va_arg(argp, int)) >= 0)
154
	goto rflag;
155
      width = -width;
156
      /* FALLTHROUGH */
157
    case '-':
158
      flags |= LADJUST;
159
      goto rflag;
160
    case '+':
161
      sign = '+';
162
      goto rflag;
163
    case '.':
164
      if (*++fmt == '*')
165
	n = va_arg(argp, int);
166
      else
167
      {
168
	n = 0;
169
	while (isascii(*fmt) && isdigit(*fmt))
170
	  n = 10 * n + todigit(*fmt++);
171
	--fmt;
172
      }
173
      prec = n < 0 ? -1 : n;
174
      goto rflag;
175
    case '0':
176
      /*
177
       * ``Note that 0 is taken as a flag, not as the
178
       * beginning of a field width.''
179
       *	-- ANSI X3J11
180
       */
181
      flags |= ZEROPAD;
182
      goto rflag;
183
    case '1': case '2': case '3': case '4':
184
    case '5': case '6': case '7': case '8': case '9':
185
      n = 0;
186
      do {
187
	n = 10 * n + todigit(*fmt);
188
      } while (isascii(*++fmt) && isdigit(*fmt));
189
      width = n;
190
      --fmt;
191
      goto rflag;
192
    case 'L':
193
      flags |= LONGDBL;
194
      goto rflag;
195
    case 'h':
196
      flags |= SHORTINT;
197
      goto rflag;
198
    case 'l':
199
      flags |= LONGINT;
200
      goto rflag;
201
    case 'c':
202
      *(t = buf) = va_arg(argp, int);
203
      size = 1;
204
      sign = '\0';
205
      goto pforw;
206
    case 'D':
207
      flags |= LONGINT;
208
      /*FALLTHROUGH*/
209
    case 'd':
210
    case 'i':
211
      ARG(int);
212
      if ((long)_ulong < 0)
213
      {
214
	_ulong = -_ulong;
215
	sign = '-';
216
      }
217
      base = 10;
218
      goto number;
219
    case 'e':
220
    case 'E':
221
    case 'f':
222
    case 'g':
223
    case 'G':
224
      if (flags & LONGDBL)
225
	_ldouble = va_arg(argp, long double);
226
      else
227
	_ldouble = (long double)va_arg(argp, double);
228
      /*
229
       * don't do unrealistic precision; just pad it with
230
       * zeroes later, so buffer size stays rational.
231
       */
232
      if (prec > MAXFRACT)
233
      {
234
	if (*fmt != 'g' && (*fmt != 'G' || (flags&ALT)))
235
	  fpprec = prec - MAXFRACT;
236
	prec = MAXFRACT;
237
      }
238
      else if (prec == -1)
239
      {
240
	if (flags&LONGINT)
241
	  prec = DEFLPREC;
242
	else
243
	  prec = DEFPREC;
244
      }
245
      /*
246
       * softsign avoids negative 0 if _double is < 0 and
247
       * no significant digits will be shown
248
       */
249
      if (_ldouble < 0)
250
      {
251
	softsign = '-';
252
	_ldouble = -_ldouble;
253
      }
254
      else
255
	softsign = 0;
256
      /*
257
       * cvt may have to round up past the "start" of the
258
       * buffer, i.e. ``intf("%.2f", (double)9.999);'';
259
       * if the first char isn't NULL, it did.
260
       */
261
      *buf = NULL;
262
      size = cvtl(_ldouble, prec, flags, &softsign, *fmt, buf,
263
		  buf + sizeof(buf));
264
      if (softsign && !nan2)
265
	sign = '-';
266
      nan2 = 0;
267
      t = *buf ? buf : buf + 1;
268
      goto pforw;
269
    case 'n':
270
      if (flags & LONGINT)
271
	*va_arg(argp, long *) = cnt;
272
      else if (flags & SHORTINT)
273
	*va_arg(argp, short *) = cnt;
274
      else
275
	*va_arg(argp, int *) = cnt;
276
      break;
277
    case 'O':
278
      flags |= LONGINT;
279
      /*FALLTHROUGH*/
280
    case 'o':
281
      ARG(unsigned);
282
      base = 8;
283
      goto nosign;
284
    case 'p':
285
      /*
286
       * ``The argument shall be a pointer to void.  The
287
       * value of the pointer is converted to a sequence
288
       * of printable characters, in an implementation-
289
       * defined manner.''
290
       *	-- ANSI X3J11
291
       */
292
      /* NOSTRICT */
293
      _ulong = (unsigned long)va_arg(argp, void *);
294
      base = 16;
295
      goto nosign;
296
    case 's':
297
      if (!(t = va_arg(argp, char *)))
298
	t = NULL_REP;
299
      if (prec >= 0)
300
      {
301
	/*
302
	 * can't use strlen; can only look for the
303
	 * NUL in the first `prec' characters, and
304
	 * strlen() will go further.
305
	 */
306
	char *p			/*, *memchr() */;
307
 
308
	if ((p = memchr(t, 0, prec)))
309
	{
310
	  size = p - t;
311
	  if (size > prec)
312
	    size = prec;
313
	}
314
	else
315
	  size = prec;
316
      }
317
      else
318
	size = strlen(t);
319
      sign = '\0';
320
      goto pforw;
321
    case 'U':
322
      flags |= LONGINT;
323
      /*FALLTHROUGH*/
324
    case 'u':
325
      ARG(unsigned);
326
      base = 10;
327
      goto nosign;
328
    case 'X':
329
      digs = "0123456789ABCDEF";
330
      /* FALLTHROUGH */
331
    case 'x':
332
      ARG(unsigned);
333
      base = 16;
334
      /* leading 0x/X only if non-zero */
335
      if (flags & ALT && _ulong != 0)
336
	flags |= HEXPREFIX;
337
 
338
      /* unsigned conversions */
339
    nosign:			sign = '\0';
340
      /*
341
       * ``... diouXx conversions ... if a precision is
342
       * specified, the 0 flag will be ignored.''
343
       *	-- ANSI X3J11
344
       */
345
    number:			if ((dprec = prec) >= 0)
346
      flags &= ~ZEROPAD;
347
 
348
      /*
349
       * ``The result of converting a zero value with an
350
       * explicit precision of zero is no characters.''
351
       *	-- ANSI X3J11
352
       */
353
      t = buf + BUF;
354
      if (_ulong != 0 || prec != 0)
355
      {
356
	do {
357
	  *--t = digs[_ulong % base];
358
	  _ulong /= base;
359
	} while (_ulong);
360
	digs = "0123456789abcdef";
361
	if (flags & ALT && base == 8 && *t != '0')
362
	  *--t = '0';		/* octal leading 0 */
363
      }
364
      size = buf + BUF - t;
365
 
366
    pforw:
367
      /*
368
       * All reasonable formats wind up here.  At this point,
369
       * `t' points to a string which (if not flags&LADJUST)
370
       * should be padded out to `width' places.  If
371
       * flags&ZEROPAD, it should first be prefixed by any
372
       * sign or other prefix; otherwise, it should be blank
373
       * padded before the prefix is emitted.  After any
374
       * left-hand padding and prefixing, emit zeroes
375
       * required by a decimal [diouxX] precision, then print
376
       * the string proper, then emit zeroes required by any
377
       * leftover floating precision; finally, if LADJUST,
378
       * pad with blanks.
379
       */
380
 
381
      /*
382
       * compute actual size, so we know how much to pad
383
       * fieldsz excludes decimal prec; realsz includes it
384
       */
385
      fieldsz = size + fpprec;
386
      realsz = dprec > fieldsz ? dprec : fieldsz;
387
      if (sign)
388
	realsz++;
389
      if (flags & HEXPREFIX)
390
	realsz += 2;
391
 
392
      /* right-adjusting blank padding */
393
      if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
394
	for (n = realsz; n < width; n++)
395
	  PUTC(' ');
396
      /* prefix */
397
      if (sign)
398
	PUTC(sign);
399
      if (flags & HEXPREFIX)
400
      {
401
	PUTC('0');
402
	PUTC((char)*fmt);
403
      }
404
      /* right-adjusting zero padding */
405
      if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
406
	for (n = realsz; n < width; n++)
407
	  PUTC('0');
408
      /* leading zeroes from decimal precision */
409
      for (n = fieldsz; n < dprec; n++)
410
	PUTC('0');
411
 
412
      /* the string or number proper */
413
      n = size;
414
      if (fp->_cnt - n >= 0 && (fp->_flag & _IOLBF) == 0)
415
      {
416
	fp->_cnt -= n;
417
	memcpy((char *)fp->_ptr, t, n);
418
	fp->_ptr += n;
419
      }
420
      else
421
	while (--n >= 0)
422
	  PUTC(*t++);
423
      /* trailing f.p. zeroes */
424
      while (--fpprec >= 0)
425
	PUTC('0');
426
      /* left-adjusting padding (always blank) */
427
      if (flags & LADJUST)
428
	for (n = realsz; n < width; n++)
429
	  PUTC(' ');
430
      /* finally, adjust cnt */
431
      cnt += width > realsz ? width : realsz;
432
      break;
433
    case '\0':			/* "%?" prints ?, unless ? is NULL */
434
      return cnt;
435
    default:
436
      PUTC((char)*fmt);
437
      cnt++;
438
    }
439
  }
440
  /* NOTREACHED */
441
}
442
 
443
static long double pten[] =
444
{
445
  1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L, 1e64L, 1e128L, 1e256L,
446
  1e512L, 1e1024L, 1e2048L, 1e4096L
447
};
448
 
449
static long double ptenneg[] =
450
{
451
  1e-1L, 1e-2L, 1e-4L, 1e-8L, 1e-16L, 1e-32L, 1e-64L, 1e-128L, 1e-256L,
452
  1e-512L, 1e-1024L, 1e-2048L, 1e-4096L
453
};
454
 
455
#define MAXP 4096
456
#define NP   12
457
#define P    (4294967296.0L * 4294967296.0L * 2.0L)   /* 2^65 */
458
static long double INVPREC = P;
459
static long double PREC = 1.0L/P;
460
#undef P
461
/*
462
 * Defining FAST_LDOUBLE_CONVERSION results in a little bit faster
463
 * version, which might be less accurate (about 1 bit) for long
464
 * double. For 'normal' double it doesn't matter.
465
 */
466
/* #define FAST_LDOUBLE_CONVERSION */
467
 
468
static int
469
cvtl(long double number, int prec, int flags, char *signp, unsigned char fmtch,
470
     char *startp, char *endp)
471
{
472
  char *p, *t;
473
  long double fract;
474
  int dotrim, expcnt, gformat;
475
  long double integer, tmp;
476
 
477
  if ((expcnt = isspeciall(number, startp)))
478
    return(expcnt);
479
 
480
  dotrim = expcnt = gformat = 0;
481
  /* fract = modfl(number, &integer); */
482
  integer = number;
483
 
484
  /* get an extra slot for rounding. */
485
  t = ++startp;
486
 
487
  p = endp - 1;
488
  if (integer)
489
  {
490
    int i, lp=NP, pt=MAXP;
491
#ifndef FAST_LDOUBLE_CONVERSION
492
    long double oint = integer, dd=1.0L;
493
#endif
494
    if (integer > INVPREC)
495
    {
496
      integer *= PREC;
497
      while(lp >= 0) {
498
	if (integer >= pten[lp])
499
	{
500
	  expcnt += pt;
501
	  integer *= ptenneg[lp];
502
#ifndef FAST_LDOUBLE_CONVERSION
503
	  dd *= pten[lp];
504
#endif
505
	}
506
	pt >>= 1;
507
	lp--;
508
      }
509
#ifndef FAST_LDOUBLE_CONVERSION
510
      integer = oint/dd;
511
#else
512
      integer *= INVPREC;
513
#endif
514
    }
515
    /*
516
     * Do we really need this ?
517
     */
518
    for (i = 0; i < expcnt; i++)
519
      *p-- = '0';
520
  }
521
  number = integer;
522
  fract = modfl(number, &integer);
523
  /*
524
   * get integer portion of number; put into the end of the buffer; the
525
   * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
526
   */
527
  for (; integer; ++expcnt)
528
  {
529
    tmp = modfl(integer * 0.1L , &integer);
530
    *p-- = tochar((int)((tmp + .01L) * 10));
531
  }
532
  switch(fmtch)
533
  {
534
  case 'f':
535
    /* reverse integer into beginning of buffer */
536
    if (expcnt)
537
      for (; ++p < endp; *t++ = *p);
538
    else
539
      *t++ = '0';
540
    /*
541
     * if precision required or alternate flag set, add in a
542
     * decimal point.
543
     */
544
    if (prec || flags&ALT)
545
      *t++ = decimal;
546
    /* if requires more precision and some fraction left */
547
    if (fract)
548
    {
549
      if (prec)
550
	do {
551
	  fract = modfl(fract * 10.0L, &tmp);
552
	  *t++ = tochar((int)tmp);
553
	} while (--prec && fract);
554
      if (fract)
555
	startp = roundl(fract, (int *)NULL, startp,
556
			t - 1, (char)0, signp);
557
    }
558
    for (; prec--; *t++ = '0');
559
    break;
560
  case 'e':
561
  case 'E':
562
  eformat:
563
    if (expcnt)
564
    {
565
      *t++ = *++p;
566
      if (prec || flags&ALT)
567
	*t++ = decimal;
568
      /* if requires more precision and some integer left */
569
      for (; prec && ++p < endp; --prec)
570
	*t++ = *p;
571
      /*
572
       * if done precision and more of the integer component,
573
       * round using it; adjust fract so we don't re-round
574
       * later.
575
       */
576
      if (!prec && ++p < endp)
577
      {
578
	fract = 0;
579
	startp = roundl((long double)0.0L, &expcnt,
580
			startp, t - 1, *p, signp);
581
      }
582
      /* adjust expcnt for digit in front of decimal */
583
      --expcnt;
584
    }
585
    /* until first fractional digit, decrement exponent */
586
    else if (fract)
587
    {
588
      int lp=NP, pt=MAXP;
589
#ifndef FAST_LDOUBLE_CONVERSION
590
      long double ofract = fract, dd=1.0L;
591
#endif
592
      expcnt = -1;
593
      if (fract < PREC)
594
      {
595
	fract *= INVPREC;
596
	while(lp >= 0)
597
	{
598
	  if (fract <= ptenneg[lp])
599
	  {
600
	    expcnt -= pt;
601
	    fract *= pten[lp];
602
#ifndef FAST_LDOUBLE_CONVERSION
603
	    dd *= pten[lp];
604
#endif
605
	  }
606
	  pt >>= 1;
607
	  lp--;
608
	}
609
#ifndef FAST_LDOUBLE_CONVERSION
610
	fract = ofract*dd;
611
#else
612
	fract *= PREC;
613
#endif
614
      }
615
      /* adjust expcnt for digit in front of decimal */
616
      for (			/* expcnt = -1 */ ;; --expcnt)
617
      {
618
	fract = modfl(fract * 10.0L, &tmp);
619
	if (tmp)
620
	  break;
621
      }
622
      *t++ = tochar((int)tmp);
623
      if (prec || flags&ALT)
624
	*t++ = decimal;
625
    }
626
    else
627
    {
628
      *t++ = '0';
629
      if (prec || flags&ALT)
630
	*t++ = decimal;
631
    }
632
    /* if requires more precision and some fraction left */
633
    if (fract)
634
    {
635
      if (prec)
636
	do {
637
	  fract = modfl(fract * 10.0L, &tmp);
638
	  *t++ = tochar((int)tmp);
639
	} while (--prec && fract);
640
      if (fract)
641
	startp = roundl(fract, &expcnt, startp,
642
			t - 1, (char)0, signp);
643
    }
644
    /* if requires more precision */
645
    for (; prec--; *t++ = '0');
646
 
647
    /* unless alternate flag, trim any g/G format trailing 0's */
648
    if (gformat && !(flags&ALT))
649
    {
650
      while (t > startp && *--t == '0');
651
      if (*t == decimal)
652
	--t;
653
      ++t;
654
    }
655
    t = exponentl(t, expcnt, fmtch);
656
    break;
657
  case 'g':
658
  case 'G':
659
    /* a precision of 0 is treated as a precision of 1. */
660
    if (!prec)
661
      ++prec;
662
    /*
663
     * ``The style used depends on the value converted; style e
664
     * will be used only if the exponent resulting from the
665
     * conversion is less than -4 or greater than the precision.''
666
     *	-- ANSI X3J11
667
     */
668
    if (expcnt > prec || (!expcnt && fract && fract < .0001))
669
    {
670
      /*
671
       * g/G format counts "significant digits, not digits of
672
       * precision; for the e/E format, this just causes an
673
       * off-by-one problem, i.e. g/G considers the digit
674
       * before the decimal point significant and e/E doesn't
675
       * count it as precision.
676
       */
677
      --prec;
678
      fmtch -= 2;		/* G->E, g->e */
679
      gformat = 1;
680
      goto eformat;
681
    }
682
    /*
683
     * reverse integer into beginning of buffer,
684
     * note, decrement precision
685
     */
686
    if (expcnt)
687
      for (; ++p < endp; *t++ = *p, --prec);
688
    else
689
      *t++ = '0';
690
    /*
691
     * if precision required or alternate flag set, add in a
692
     * decimal point.  If no digits yet, add in leading 0.
693
     */
694
    if (prec || flags&ALT)
695
    {
696
      dotrim = 1;
697
      *t++ = decimal;
698
    }
699
    else
700
      dotrim = 0;
701
    /* if requires more precision and some fraction left */
702
    while (prec && fract)
703
    {
704
      fract = modfl(fract * 10.0L, &tmp);
705
      *t++ = tochar((int)tmp);
706
      prec--;
707
    }
708
    if (fract)
709
      startp = roundl(fract, (int *)NULL, startp, t - 1,
710
		      (char)0, signp);
711
    /* alternate format, adds 0's for precision, else trim 0's */
712
    if (flags&ALT)
713
      for (; prec--; *t++ = '0');
714
    else if (dotrim)
715
    {
716
      while (t > startp && *--t == '0');
717
      if (*t != decimal)
718
	++t;
719
    }
720
  }
721
  return t - startp;
722
}
723
 
724
static char *
725
roundl(long double fract, int *expv, char *start, char *end, char ch,
726
       char *signp)
727
{
728
  long double tmp;
729
 
730
  if (fract)
731
  {
732
    if (fract == 0.5L)
733
    {
734
      char *e = end;
735
      if (*e == '.')
736
	e--;
737
      if (*e == '0' || *e == '2' || *e == '4'
738
	  || *e == '6' || *e == '8')
739
      {
740
	tmp = 3.0;
741
	goto start;
742
      }
743
    }
744
    (void)modfl(fract * 10.0L, &tmp);
745
  }
746
  else
747
    tmp = todigit(ch);
748
 start:
749
  if (tmp > 4)
750
    for (;; --end)
751
    {
752
      if (*end == decimal)
753
	--end;
754
      if (++*end <= '9')
755
	break;
756
      *end = '0';
757
      if (end == start)
758
      {
759
	if (expv)
760
	{		/* e/E; increment exponent */
761
	  *end = '1';
762
	  ++*expv;
763
	}
764
	else
765
	{			/* f; add extra digit */
766
	  *--end = '1';
767
	  --start;
768
	}
769
	break;
770
      }
771
    }
772
  /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
773
  else if (*signp == '-')
774
    for (;; --end)
775
    {
776
      if (*end == decimal)
777
	--end;
778
      if (*end != '0')
779
	break;
780
      if (end == start)
781
	*signp = 0;
782
    }
783
  return start;
784
}
785
 
786
static char *
787
exponentl(char *p, int expv, unsigned char fmtch)
788
{
789
  char *t;
790
  char expbuf[MAXEXPLD];
791
 
792
  *p++ = fmtch;
793
  if (expv < 0)
794
  {
795
    expv = -expv;
796
    *p++ = '-';
797
  }
798
  else
799
    *p++ = '+';
800
  t = expbuf + MAXEXPLD;
801
  if (expv > 9)
802
  {
803
    do {
804
      *--t = tochar(expv % 10);
805
    } while ((expv /= 10) > 9);
806
    *--t = tochar(expv);
807
    for (; t < expbuf + MAXEXPLD; *p++ = *t++);
808
  }
809
  else
810
  {
811
    *p++ = '0';
812
    *p++ = tochar(expv);
813
  }
814
  return p;
815
}
816
 
817
static int
818
isspeciall(long double d, char *bufp)
819
{
820
  struct IEEExp {
821
    unsigned manl:32;
822
    unsigned manh:32;
823
    unsigned exp:15;
824
    unsigned sign:1;
825
  } *ip = (struct IEEExp *)&d;
826
 
827
  nan2 = 0;  /* don't assume the static is 0 (emacs) */
828
  if (ip->exp != 0x7fff)
829
    return(0);
830
  if ((ip->manh & 0x7fffffff) || ip->manl)
831
  {
832
    strcpy(bufp, "NaN");
833
    nan2 = 1;			/* kludge: we don't need the sign,  it's not nice
834
				   but it should work */
835
  }
836
  else
837
    (void)strcpy(bufp, "Inf");
838
  return(3);
839
}
840