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

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

Point of no return.

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