Headers and library sources from all versions of Lightspeed C and THINK C
1
2/*
3 * printf.c
4 *
5 * Copyright (c) 1991 Symantec Corporation. All rights reserved.
6 *
7 */
8
9#include "stdio.h"
10#include "stdarg.h"
11#include "string.h"
12#include "ansi_private.h"
13#include <SANE.h>
14
15#define BUFLEN 512
16#define TRUE 1
17#define FALSE 0
18
19static struct format {
20 unsigned leftJustify : 1;
21 unsigned forceSign : 1;
22 unsigned altForm : 1;
23 unsigned zeroPad : 1;
24 unsigned havePrecision : 1;
25 unsigned hSize : 1;
26 unsigned lSize : 1;
27 unsigned LSize : 1;
28 char sign;
29 char exponent;
30 int fieldWidth;
31 int precision;
32} default_format;
33
34
35struct decrec {
36 char sgn;
37 short exp;
38 char sig[SIGDIGLEN];
39 short pad;
40 /* following fields aren't used by SANE */
41 short min;
42 short dot;
43 short max;
44};
45
46static void ftod(int, int, struct decrec *, long double);
47
48
49int
50vfprintf(FILE *fp, const char *fmt, va_list arg)
51{
52 register int c, i, j, nwritten = 0;
53 register unsigned long n;
54 long double x;
55 register char *s;
56 char buf[BUFLEN], *digits, *t;
57 struct format F;
58 struct decrec D;
59
60 for (c = *fmt; c; c = *++fmt) {
61 if (c != '%')
62 goto copy1;
63 F = default_format;
64
65 /* decode flags */
66
67 for (;;) {
68 c = *++fmt;
69 if (c == '-')
70 F.leftJustify = TRUE;
71 else if (c == '+')
72 F.forceSign = TRUE;
73 else if (c == ' ')
74 F.sign = ' ';
75 else if (c == '#')
76 F.altForm = TRUE;
77 else if (c == '0')
78 F.zeroPad = TRUE;
79 else
80 break;
81 }
82
83 /* decode field width */
84
85 if (c == '*') {
86 if ((F.fieldWidth = va_arg(arg, int)) < 0) {
87 F.leftJustify = TRUE;
88 F.fieldWidth = -F.fieldWidth;
89 }
90 c = *++fmt;
91 }
92 else {
93 for (; c >= '0' && c <= '9'; c = *++fmt)
94 F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
95 }
96
97 /* decode precision */
98
99 if (c == '.') {
100 if ((c = *++fmt) == '*') {
101 F.precision = va_arg(arg, int);
102 c = *++fmt;
103 }
104 else {
105 for (; c >= '0' && c <= '9'; c = *++fmt)
106 F.precision = (10 * F.precision) + (c - '0');
107 }
108 if (F.precision >= 0)
109 F.havePrecision = TRUE;
110 }
111
112 /* perform appropriate conversion */
113
114 s = &buf[BUFLEN];
115 if (F.leftJustify)
116 F.zeroPad = FALSE;
117conv: switch (c) {
118
119 /* 'h' size modifier */
120
121 case 'h':
122 F.hSize = TRUE;
123 c = *++fmt;
124 goto conv;
125
126 /* 'l' size modifier */
127
128 case 'l':
129 F.lSize = TRUE;
130 c = *++fmt;
131 goto conv;
132
133 /* 'L' size modifier */
134
135 case 'L':
136 F.LSize = TRUE;
137 c = *++fmt;
138 goto conv;
139
140 /* decimal (signed) */
141
142 case 'd':
143 case 'i':
144 if (F.lSize)
145 n = va_arg(arg, long);
146 else
147 n = va_arg(arg, int);
148 if (F.hSize)
149 n = (short) n;
150 if ((long) n < 0) {
151 n = -n;
152 F.sign = '-';
153 }
154 else if (F.forceSign)
155 F.sign = '+';
156 goto decimal;
157
158 /* decimal (unsigned) */
159
160 case 'u':
161 if (F.lSize)
162 n = va_arg(arg, unsigned long);
163 else
164 n = va_arg(arg, unsigned int);
165 if (F.hSize)
166 n = (unsigned short) n;
167 F.sign = 0;
168 goto decimal;
169
170 /* decimal (common code) */
171
172 decimal:
173 if (!F.havePrecision) {
174 if (F.zeroPad) {
175 F.precision = F.fieldWidth;
176 if (F.sign)
177 --F.precision;
178 }
179 if (F.precision < 1)
180 F.precision = 1;
181 }
182 for (i = 0; n; n /= 10, i++)
183 *--s = n % 10 + '0';
184 for (; i < F.precision; i++)
185 *--s = '0';
186 if (F.sign) {
187 *--s = F.sign;
188 i++;
189 }
190 break;
191
192 /* octal (unsigned) */
193
194 case 'o':
195 if (F.lSize)
196 n = va_arg(arg, unsigned long);
197 else
198 n = va_arg(arg, unsigned int);
199 if (F.hSize)
200 n = (unsigned short) n;
201 if (!F.havePrecision) {
202 if (F.zeroPad)
203 F.precision = F.fieldWidth;
204 if (F.precision < 1)
205 F.precision = 1;
206 }
207 for (i = 0; n; n /= 8, i++)
208 *--s = n % 8 + '0';
209 if (F.altForm && i && *s != '0') {
210 *--s = '0';
211 i++;
212 }
213 for (; i < F.precision; i++)
214 *--s = '0';
215 break;
216
217 /* hexadecimal (unsigned) */
218
219 case 'p':
220 F.havePrecision = F.lSize = TRUE;
221 F.precision = 8;
222 /* ... */
223 case 'X':
224 digits = "0123456789ABCDEF";
225 goto hexadecimal;
226 case 'x':
227 digits = "0123456789abcdef";
228 /* ... */
229 hexadecimal:
230 if (F.lSize)
231 n = va_arg(arg, unsigned long);
232 else
233 n = va_arg(arg, unsigned int);
234 if (F.hSize)
235 n = (unsigned short) n;
236 if (!F.havePrecision) {
237 if (F.zeroPad) {
238 F.precision = F.fieldWidth;
239 if (F.altForm)
240 F.precision -= 2;
241 }
242 if (F.precision < 1)
243 F.precision = 1;
244 }
245 for (i = 0; n; n /= 16, i++)
246 *--s = digits[n % 16];
247 for (; i < F.precision; i++)
248 *--s = '0';
249 if (F.altForm) {
250 *--s = c;
251 *--s = '0';
252 i += 2;
253 }
254 break;
255
256#ifndef _NOFLOATING_
257 /* fixed-point */
258
259 case 'f':
260 if (F.LSize)
261 x = va_arg(arg, long double);
262 else
263 x = va_arg(arg, double);
264 if (!F.havePrecision)
265 F.precision = 6;
266 ftod(1, F.precision, &D, x);
267 D.dot = D.exp + D.sig[0];
268 if ((D.min = D.dot) > 1)
269 D.min = 1;
270 D.max = D.dot + F.precision;
271 if (D.max - D.min > 508)
272 memcpy(D.sig, "\6>>>>>>", 7);
273 goto floating;
274
275 /* floating-point */
276
277 case 'e':
278 case 'E':
279 if (F.LSize)
280 x = va_arg(arg, long double);
281 else
282 x = va_arg(arg, double);
283 if (!F.havePrecision)
284 F.precision = 6;
285 F.exponent = c;
286 ftod(0, D.max = F.precision + 1, &D, x);
287 D.min = D.dot = 1;
288 D.exp += D.sig[0] - 1;
289 goto floating;
290
291 /* "general" notation */
292
293 case 'g':
294 case 'G':
295 if (F.LSize)
296 x = va_arg(arg, long double);
297 else
298 x = va_arg(arg, double);
299 if (!F.havePrecision)
300 F.precision = 6;
301 else if (F.precision == 0)
302 F.precision = 1;
303 F.exponent = c - 2;
304 ftod(0, D.max = F.precision, &D, x);
305 D.min = D.dot = 1;
306 D.exp += D.sig[0] - 1;
307 if (D.exp >= -4 && D.exp < F.precision) {
308 F.exponent = 0;
309 if ((D.dot += D.exp) < 1)
310 D.min = D.dot;
311 }
312 if (!F.altForm && D.max > D.sig[0]) {
313 if ((D.max = D.sig[0]) < D.dot)
314 D.max = D.dot;
315 }
316 goto floating;
317
318 /* floating (common code) */
319
320 floating:
321 if (D.sig[1] > '9') {
322 F.exponent = FALSE;
323 D.dot = 0;
324 D.min = 1;
325 D.max = D.sig[0];
326 }
327 i = 0;
328 if (F.exponent) {
329 n = D.exp < 0 ? -D.exp : D.exp;
330 for (; n; n /= 10, i++)
331 *--s = n % 10 + '0';
332 for (; i < 2; i++)
333 *--s = '0';
334 *--s = D.exp < 0 ? '-' : '+';
335 *--s = F.exponent;
336 i += 2;
337 }
338 j = D.max;
339 if (j == D.dot && !F.altForm)
340 ++D.dot;
341 do {
342 if (j == D.dot) {
343 *--s = '.';
344 i++;
345 }
346 *--s = j > 0 && j <= D.sig[0] ? D.sig[j] : '0';
347 } while (--j >= D.min);
348 i += D.max - j;
349 if (D.sgn)
350 F.sign = '-';
351 else if (F.forceSign)
352 F.sign = '+';
353 if (F.zeroPad) {
354 j = F.fieldWidth;
355 if (F.sign)
356 --j;
357 for (; i < j; i++)
358 *--s = '0';
359 }
360 if (F.sign) {
361 *--s = F.sign;
362 i++;
363 }
364 break;
365#endif _NOFLOATING_
366
367 /* character */
368
369 case 'c':
370 *--s = va_arg(arg, int);
371 i = 1;
372 break;
373
374 /* string */
375
376 case 's':
377 s = va_arg(arg, char *);
378 if (F.altForm) {
379 i = (unsigned char) *s++;
380 if (F.havePrecision && i > F.precision)
381 i = F.precision;
382 }
383 else {
384 if (!F.havePrecision)
385 i = strlen(s);
386 else if (t = memchr(s, '\0', F.precision))
387 i = t - s;
388 else
389 i = F.precision;
390 }
391 break;
392
393 /* store # bytes written so far */
394
395 case 'n':
396 s = va_arg(arg, void *);
397 if (F.hSize)
398 * (short *) s = nwritten;
399 else if (F.lSize)
400 * (long *) s = nwritten;
401 else
402 * (int *) s = nwritten;
403 continue;
404
405 /* oops - unknown conversion, abort */
406
407 default:
408 if (c != '%')
409 goto done;
410 copy1:
411 if (putc(c, fp) < 0)
412 return(EOF);
413 ++nwritten;
414 continue;
415 }
416
417 /* pad on the left */
418
419 if (i < F.fieldWidth && !F.leftJustify) {
420 do {
421 if (putc(' ', fp) < 0)
422 return(EOF);
423 ++nwritten;
424 } while (i < --F.fieldWidth);
425 }
426
427 /* write the converted result */
428
429 if (fwrite(s, 1, i, fp) != i)
430 return(EOF);
431 nwritten += i;
432
433 /* pad on the right */
434
435 for (; i < F.fieldWidth; i++) {
436 if (putc(' ', fp) < 0)
437 return(EOF);
438 ++nwritten;
439 }
440 }
441
442 /* all done! */
443
444done:
445 return(nwritten);
446}
447
448
449/* ---------- floating-point conversion ---------- */
450
451#ifndef _NOFLOATING_
452static void
453ftod(int fixed, int precision, struct decrec *d, long double x)
454{
455 struct { char style; short digits; } form;
456 int i;
457 register short *p = (short *) &x;
458
459 /* point to SANE extended */
460
461#if __option(mc68881) && __option(native_fp)
462 p[1] = p[0];
463#endif
464#if __option(mc68881) || !__option(native_fp)
465 p++;
466#endif
467
468 /* convert to decimal record */
469
470 if (precision >= sizeof d->sig)
471 precision = sizeof d->sig - 1;
472 form.style = fixed;
473 form.digits = precision;
474 fp68k(&form, p, d, (short)FX2DEC);
475
476 /* handle fixed-point overflow */
477
478 if (d->sig[1] == '?') {
479 form.style = 0;
480 form.digits = sizeof d->sig - 1;
481 fp68k(&form, p, d, (short)FX2DEC);
482 }
483
484 /* strip trailing zeroes */
485
486 for (i = d->sig[0]; i > 1 && d->sig[i] == '0'; --i)
487 ++d->exp;
488 d->sig[0] = i;
489
490 /* format 0, INF, NAN */
491
492 if (d->sig[1] == '0') {
493 d->sgn = 0; /* delete to allow printing "-0" */
494 d->exp = 0;
495 }
496 else if (d->sig[1] == 'I') {
497 d->sig[0] = 3;
498 d->sig[2] = 'N';
499 d->sig[3] = 'F';
500 }
501 else if (d->sig[1] == 'N') {
502 d->sig[0] = 5;
503 d->sig[2] = 'A';
504 d->sig[3] = 'N';
505 }
506}
507#endif _NOFLOATING_