source: buchla-68k/iolib/dofmt.c@ 109c83b

Last change on this file since 109c83b was 109c83b, checked in by Thomas Lopatic <thomas@…>, 7 years ago

Compiled full ROM in Hatari.

  • Property mode set to 100644
File size: 5.2 KB
Line 
1/*
2 =============================================================================
3 dofmt.c -- integer and string formatted output function
4 Version 4 -- 1987-06-12 -- D.N. Lynx Crowe
5
6 Supports most of the BSD & SysV Unix(tm) [f|s]printf conversion codes -
7 No floating point support in this implementation.
8
9 Returns a long instead of the int returned by the Unix(tm) functions.
10
11 WARNING - "Crufty code":
12
13 This code contains hacks to work around a bug in
14 the Alcyon C compiler, which, among other things,
15 doesn't handle % properly for longs. Conversions for
16 o and x are hacked to use shifts instead of modulus.
17
18 Alcyon 'cruft' is enabled by defining CRUFTY non-zero.
19 =============================================================================
20*/
21
22#define CRUFTY 1
23
24#include "stddefs.h"
25#include "ctype.h"
26#include "varargs.h"
27
28#define MAXDIGS 11
29#define HIBITL (1L << ( (8 * sizeof(long)) - 1))
30
31#define LONGHMSK 0x0FFFFFFFL
32#define LONGOMSK 0x1FFFFFFFL
33
34#define tonum(x) ((x)-'0')
35#define todigit(x) ((x)+'0')
36#define max(a,b) ((a)>(b)?(a):(b))
37#define min(a,b) ((a)<(b)?(a):(b))
38
39#if CRUFTY
40extern long uldiv(), uldivr;
41#endif
42
43long
44dofmt_(putsub, format, args)
45register int (*putsub)();
46register char *format;
47va_list args;
48{
49 register int fcode;
50
51 long k,
52 n,
53 lzero,
54 count;
55
56 int hradix,
57 lowbit,
58 length,
59 fplus,
60 fminus,
61 fblank,
62 fsharp,
63 flzero,
64 width,
65 prec;
66
67 register char *bp, *p;
68
69 char *prefix,
70 *tab,
71 buf[MAXDIGS];
72
73 long val;
74
75/*
76
77*/
78
79 count = 0;
80
81 for ( ; ; ) {
82
83 for (bp = format;
84 (fcode = *format) NE '\0' AND fcode NE '%';
85 format++)
86 ;
87
88 if (n = (long)format - (long)bp) {
89
90 count += n;
91
92 while (n--)
93 (*putsub)(*bp++);
94 }
95
96 if (fcode EQ '\0')
97 return(count);
98
99 fplus = fminus = fblank = fsharp = flzero = 0;
100
101 for ( ; ; ) {
102
103 switch (fcode = *++format) {
104
105 case '+':
106 fplus++;
107 continue;
108
109 case '-':
110 fminus++;
111 continue;
112
113 case ' ':
114 fblank++;
115 continue;
116
117 case '#':
118 fsharp++;
119 continue;
120 }
121
122 break;
123 }
124
125/*
126
127*/
128
129 if (fcode EQ '*') {
130
131 width = va_arg(args, int);
132
133 if (width < 0) {
134
135 width = -width;
136 fminus++;
137 }
138
139 format++;
140
141 } else {
142
143 if (fcode EQ '0')
144 flzero++;
145
146 for (width = 0; isdigit(fcode = *format); format++)
147 width = width * 10 + tonum(fcode);
148 }
149
150 if (*format NE '.')
151 prec = -1;
152 else if (*++format EQ '*') {
153
154 prec = va_arg(args, int);
155 format++;
156 } else
157 for (prec = 0; isdigit(fcode = *format); format++)
158 prec = prec * 10 + tonum(fcode);
159
160 length = 0;
161
162 if (*format EQ 'l') {
163
164 length++;
165 format++;
166 }
167
168 prefix = "";
169 lzero = 0;
170
171/*
172
173*/
174 switch (fcode = *format++) {
175
176 case 'd':
177 case 'u':
178 hradix = 10/2;
179 goto fixed;
180
181 case 'o':
182 hradix = 8/2;
183 goto fixed;
184
185 case 'X':
186 case 'x':
187 hradix = 16/2;
188
189 fixed:
190
191 if (prec < 0)
192 if (flzero AND width > 0)
193 prec = width;
194 else
195 prec = 1;
196
197 if (length)
198 val = va_arg(args, long);
199 else if (fcode EQ 'd')
200 val = va_arg(args, int);
201 else
202 val = va_arg(args, unsigned);
203
204 if (fcode EQ 'd') {
205
206 if (val < 0) {
207
208 prefix = "-";
209
210 if (val NE HIBITL)
211 val = -val;
212
213 } else if (fplus)
214 prefix = "+";
215 else if (fblank)
216 prefix = " ";
217 }
218
219 tab = (fcode EQ 'X') ?
220 "0123456789ABCDEF" : "0123456789abcdef";
221
222 p = bp = buf + MAXDIGS;
223
224/*
225
226*/
227 switch (hradix) {
228
229 case 4:
230
231 while (val NE 0) {
232
233 *--bp = tab[val & 0x07L];
234 val = (val >> 3) & LONGOMSK;
235 }
236
237 break;
238
239 case 5:
240
241 while (val NE 0) {
242
243#if CRUFTY
244 /* uldiv does a long divide */
245 /* ... with remainder in uldivr */
246
247 val = uldiv(val, 10L);
248 *--bp = tab[uldivr];
249#else
250 /* on most compilers, this works */
251
252 lowbit = val & 1;
253 val = (val >> 1) & ~HIBITL;
254 *--bp = tab[val % hradix * 2 + lowbit];
255 val /= hradix;
256#endif
257 }
258
259 break;
260
261 case 8:
262
263 while (val NE 0) {
264
265 *--bp = tab[val & 0x0FL];
266 val = (val >> 4) & LONGHMSK;
267 }
268 }
269
270 lzero = (long)bp - (long)p + (long)prec;
271
272 if (fsharp AND bp NE p)
273 switch (fcode) {
274
275 case 'o':
276 if (lzero < 1)
277 lzero = 1;
278 break;
279
280 case 'x':
281 case 'X':
282 prefix = "0x";
283 break;
284 }
285
286 break;
287
288/*
289
290*/
291 default:
292 buf[0] = fcode;
293 goto c_merge;
294
295 case 'c':
296 buf[0] = va_arg(args, int);
297
298 c_merge:
299
300 p = (bp = &buf[0]) + 1;
301 break;
302
303 case 's':
304 p = bp = va_arg(args, char *);
305
306 if (prec < 0)
307 p += strlen(bp);
308 else {
309 while (*p++ NE '\0' AND --prec GE 0)
310 ;
311 --p;
312 }
313
314 break;
315
316 case '\0':
317 return(-1);
318
319 }
320
321/*
322
323*/
324 if (lzero < 0)
325 lzero = 0;
326
327 k = (n = (long)p - (long)bp) + (long)(lzero +
328 (prefix[0] EQ '\0' ? 0 : (prefix[1] EQ '\0' ? 1 : 2)));
329
330 count += (width >k) ? width : k;
331
332 if (!fminus)
333 while (--width GE k)
334 (*putsub)(' ');
335
336 while (*prefix NE '\0')
337 (*putsub)(*prefix++);
338
339 while (--lzero GE 0)
340 (*putsub)('0');
341
342 if (n > 0)
343 while (n--)
344 (*putsub)(*bp++);
345
346 while (--width GE k)
347 (*putsub)(' ');
348 }
349}
Note: See TracBrowser for help on using the repository browser.