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