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

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

Prototypes for formatted I/O.

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