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