1 /*
2 * This file based on printf.c from 'Dlibs' on the atari ST (RdeBath)
3 *
4 * 19-OCT-88: Dale Schumacher
5 * > John Stanley has again been a great help in debugging, particularly
6 * > with the printf/scanf functions which are his creation.
7 *
8 * Dale Schumacher 399 Beacon Ave.
9 * (alias: Dalnefre') St. Paul, MN 55104
10 * dal@syntel.UUCP United States of America
11 * "It's not reality that's important, but how you perceive things."
12 *
13 */
14
15 /* Altered to use stdarg, made the core function vfprintf.
16 * Hooked into the stdio package using 'inside information'
17 * Altered sizeof() assumptions, now assumes all integers except chars
18 * will be either
19 * sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short)
20 *
21 * -RDB
22 */
23
24 #include <sys/types.h>
25 #include <fcntl.h>
26 #if defined(__STDC__) && !defined(__FIRST_ARG_IN_AX__)
27 #include <stdarg.h>
28 #define va_strt va_start
29 #else
30 #include <varargs.h>
31 #define va_strt(p,i) va_start(p)
32 #endif
33
34 #include "stdio.h"
35
36 #ifdef L_printf
37
38 #if defined(__STDC__) && !defined(__FIRST_ARG_IN_AX__)
printf(const char * fmt,...)39 int printf(const char * fmt, ...)
40 #else
41 int printf(fmt, va_alist)
42 __const char *fmt;
43 va_dcl
44 #endif
45 {
46 va_list ptr;
47 int rv;
48 va_strt(ptr, fmt);
49 rv = vfprintf(stdout,fmt,ptr);
50 va_end(ptr);
51 return rv;
52 }
53 #endif
54
55 #ifdef L_sprintf
56 #if defined(__STDC__) && !defined(__FIRST_ARG_IN_AX__)
sprintf(char * sp,const char * fmt,...)57 int sprintf(char * sp, const char * fmt, ...)
58 #else
59 int sprintf(sp, fmt, va_alist)
60 char * sp;
61 __const char *fmt;
62 va_dcl
63 #endif
64 {
65 static FILE string[1] =
66 {
67 {0, 0, (char*)(unsigned) -1, 0, (char*) (unsigned) -1, -1,
68 _IOFBF | __MODE_WRITE}
69 };
70
71 va_list ptr;
72 int rv;
73 va_strt(ptr, fmt);
74 string->bufpos = sp;
75 rv = vfprintf(string,fmt,ptr);
76 va_end(ptr);
77 *(string->bufpos) = 0;
78 return rv;
79 }
80 #endif
81
82 #ifdef L_fprintf
83 #if defined(__STDC__) && !defined(__FIRST_ARG_IN_AX__)
fprintf(FILE * fp,const char * fmt,...)84 int fprintf(FILE * fp, const char * fmt, ...)
85 #else
86 int fprintf(fp, fmt, va_alist)
87 FILE * fp;
88 __const char *fmt;
89 va_dcl
90 #endif
91 {
92 va_list ptr;
93 int rv;
94 va_strt(ptr, fmt);
95 rv = vfprintf(fp,fmt,ptr);
96 va_end(ptr);
97 return rv;
98 }
99 #endif
100
101 #ifdef L_vprintf
vprintf(fmt,ap)102 int vprintf(fmt, ap)
103 __const char *fmt;
104 va_list ap;
105 {
106 return vfprintf(stdout,fmt,ap);
107 }
108 #endif
109
110 #ifdef L_vsprintf
vsprintf(sp,fmt,ap)111 int vsprintf(sp, fmt, ap)
112 char * sp;
113 __const char *fmt;
114 va_list ap;
115 {
116 static FILE string[1] =
117 {
118 {0, 0, (char*)(unsigned) -1, 0, (char*) (unsigned) -1, -1,
119 _IOFBF | __MODE_WRITE}
120 };
121
122 int rv;
123 string->bufpos = sp;
124 rv = vfprintf(string,fmt,ap);
125 *(string->bufpos) = 0;
126 return rv;
127 }
128 #endif
129
130 #ifdef L_vfprintf
131
132 #ifndef __HAS_NO_FLOATS__
133 int (*__fp_print)() = 0;
134 #endif
135
136 static int
prtfld(op,buf,ljustf,sign,pad,width,preci,buffer_mode)137 prtfld(op, buf, ljustf, sign, pad, width, preci, buffer_mode)
138 register FILE *op;
139 register unsigned char *buf;
140 int ljustf;
141 register char sign;
142 char pad;
143 register int width;
144 int preci;
145 int buffer_mode;
146 /*
147 * Output the given field in the manner specified by the arguments. Return
148 * the number of characters output.
149 */
150 {
151 register int cnt = 0, len;
152 register unsigned char ch;
153
154 len = strlen(buf);
155
156 if (*buf == '-')
157 sign = *buf++;
158 else if (sign)
159 len++;
160
161 if ((preci != -1) && (len > preci)) /* limit max data width */
162 len = preci;
163
164 if (width < len) /* flexible field width or width overflow */
165 width = len;
166
167 /*
168 * at this point: width = total field width len = actual data width
169 * (including possible sign character)
170 */
171 cnt = width;
172 width -= len;
173
174 while (width || len)
175 {
176 if (!ljustf && width) /* left padding */
177 {
178 if (len && sign && (pad == '0'))
179 goto showsign;
180 ch = pad;
181 --width;
182 }
183 else if (len)
184 {
185 if (sign)
186 {
187 showsign:ch = sign; /* sign */
188 sign = '\0';
189 }
190 else
191 ch = *buf++; /* main field */
192 --len;
193 }
194 else
195 {
196 ch = pad; /* right padding */
197 --width;
198 }
199 putc(ch, op);
200 if( ch == '\n' && buffer_mode == _IOLBF ) fflush(op);
201 }
202
203 return (cnt);
204 }
205
206 int
vfprintf(op,fmt,ap)207 vfprintf(op, fmt, ap)
208 FILE *op;
209 register __const char *fmt;
210 register va_list ap;
211 {
212 register int i, cnt = 0, ljustf, lval;
213 int preci, dpoint, width;
214 char pad, sign, radix, hash;
215 register char *ptmp;
216 char tmp[64], *ltostr(), *ultostr();
217 int buffer_mode;
218
219 /* This speeds things up a bit for unbuffered */
220 buffer_mode = (op->mode&__MODE_BUF);
221 op->mode &= (~__MODE_BUF);
222
223 while (*fmt)
224 {
225 if (*fmt == '%')
226 {
227 if( buffer_mode == _IONBF ) fflush(op);
228 ljustf = 0; /* left justify flag */
229 sign = '\0'; /* sign char & status */
230 pad = ' '; /* justification padding char */
231 width = -1; /* min field width */
232 dpoint = 0; /* found decimal point */
233 preci = -1; /* max data width */
234 radix = 10; /* number base */
235 ptmp = tmp; /* pointer to area to print */
236 hash = 0;
237 lval = (sizeof(int)==sizeof(long)); /* long value flaged */
238 fmtnxt:
239 i = 0;
240 for(;;)
241 {
242 ++fmt;
243 if(*fmt < '0' || *fmt > '9' ) break;
244 i = (i * 10) + (*fmt - '0');
245 if (dpoint)
246 preci = i;
247 else if (!i && (pad == ' '))
248 {
249 pad = '0';
250 goto fmtnxt;
251 }
252 else
253 width = i;
254 }
255
256 switch (*fmt)
257 {
258 case '\0': /* early EOS */
259 --fmt;
260 goto charout;
261
262 case '-': /* left justification */
263 ljustf = 1;
264 goto fmtnxt;
265
266 case ' ':
267 case '+': /* leading sign flag */
268 sign = *fmt;
269 goto fmtnxt;
270
271 case '*': /* parameter width value */
272 i = va_arg(ap, int);
273 if (dpoint)
274 preci = i;
275 else
276 width = i;
277 goto fmtnxt;
278
279 case '.': /* secondary width field */
280 dpoint = 1;
281 goto fmtnxt;
282
283 case 'l': /* long data */
284 lval = 1;
285 goto fmtnxt;
286
287 case 'h': /* short data */
288 lval = 0;
289 goto fmtnxt;
290
291 case 'd': /* Signed decimal */
292 case 'i':
293 ptmp = ltostr((long) ((lval)
294 ? va_arg(ap, long)
295 : va_arg(ap, short)),
296 10);
297 goto printit;
298
299 case 'b': /* Unsigned binary */
300 radix = 2;
301 goto usproc;
302
303 case 'o': /* Unsigned octal */
304 radix = 8;
305 goto usproc;
306
307 case 'p': /* Pointer */
308 lval = (sizeof(char*) == sizeof(long));
309 pad = '0';
310 width = 6;
311 preci = 8;
312 /* fall thru */
313
314 case 'x': /* Unsigned hexadecimal */
315 case 'X':
316 radix = 16;
317 /* fall thru */
318
319 case 'u': /* Unsigned decimal */
320 usproc:
321 ptmp = ultostr((unsigned long) ((lval)
322 ? va_arg(ap, unsigned long)
323 : va_arg(ap, unsigned short)),
324 radix);
325 if( hash && radix == 8 ) { width = strlen(ptmp)+1; pad='0'; }
326 goto printit;
327
328 case '#':
329 hash=1;
330 goto fmtnxt;
331
332 case 'c': /* Character */
333 ptmp[0] = va_arg(ap, int);
334 ptmp[1] = '\0';
335 goto nopad;
336
337 case 's': /* String */
338 ptmp = va_arg(ap, char*);
339 nopad:
340 sign = '\0';
341 pad = ' ';
342 printit:
343 cnt += prtfld(op, ptmp, ljustf,
344 sign, pad, width, preci, buffer_mode);
345 break;
346
347 #ifndef __HAS_NO_FLOATS__
348 case 'e': /* float */
349 case 'f':
350 case 'g':
351 case 'E':
352 case 'G':
353 if ( __fp_print )
354 {
355 (*__fp_print)(&va_arg(ap, double), *fmt, preci, ptmp);
356 preci = -1;
357 goto printit;
358 }
359 /* FALLTHROUGH if no floating printf available */
360 #endif
361
362 default: /* unknown character */
363 goto charout;
364 }
365 }
366 else
367 {
368 charout:
369 putc(*fmt, op); /* normal char out */
370 ++cnt;
371 if( *fmt == '\n' && buffer_mode == _IOLBF ) fflush(op);
372 }
373 ++fmt;
374 }
375 op->mode |= buffer_mode;
376 if( buffer_mode == _IONBF ) fflush(op);
377 if( buffer_mode == _IOLBF ) op->bufwrite = op->bufstart;
378 return (cnt);
379 }
380 #endif
381
382 #ifdef L_fp_print
383 #ifndef __HAS_NO_FLOATS__
384
385 #ifdef __AS386_16__
386 #asm
387 loc 1 ! Make sure the pointer is in the correct segment
388 auto_func: ! Label for bcc -M to work.
389 .word ___xfpcvt ! Pointer to the autorun function
390 .text ! So the function after is also in the correct seg.
391 #endasm
392 #endif
393
394 #ifdef __AS386_32__
395 #asm
396 loc 1 ! Make sure the pointer is in the correct segment
397 auto_func: ! Label for bcc -M to work.
398 .long ___xfpcvt ! Pointer to the autorun function
399 .text ! So the function after is also in the correct seg.
400 #endasm
401 #endif
402
403 void
404 __fp_print_func(pval, style, preci, ptmp)
405 double * pval;
406 int style;
407 int preci;
408 char * ptmp;
409 {
410 int decpt, negative;
411 char * cvt;
412 double val = *pval;
413
414 if (preci < 0) preci = 6;
415
416 cvt = fcvt(val, preci, &decpt, &negative);
417 if(negative)
418 *ptmp++ = '-';
419
420 if (decpt<0) {
421 *ptmp++ = '0';
422 *ptmp++ = '.';
423 while(decpt<0) {
424 *ptmp++ = '0'; decpt++;
425 }
426 }
427
428 while(*cvt) {
429 *ptmp++ = *cvt++;
430 if (decpt == 1)
431 *ptmp++ = '.';
432 decpt--;
433 }
434
435 while(decpt > 0) {
436 *ptmp++ = '0';
437 decpt--;
438 }
439 }
440
441 void
__xfpcvt()442 __xfpcvt()
443 {
444 extern int (*__fp_print)();
445 __fp_print = __fp_print_func;
446 }
447
448 #endif
449 #endif
450