FreeCalypso > hg > freecalypso-sw
comparison loadagent/libprintf/doprnt.c @ 3:45bf8af5f061
libprintf brought in from older PPC/m68k code, but fucking GCC
refuses to compile <varargs.h> - need to convert to Anshit C <stdarg.h>
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Mon, 29 Apr 2013 07:00:22 +0000 |
parents | |
children | 5c7b3d5d5702 |
comparison
equal
deleted
inserted
replaced
2:ddda170fa6f4 | 3:45bf8af5f061 |
---|---|
1 /* the guts of printf - this implementation came from 4.3BSD-Tahoe */ | |
2 | |
3 #include <sys/types.h> | |
4 #include <ctype.h> | |
5 #include <varargs.h> | |
6 | |
7 #define PUTC(ch) ((*outfunc)((ch), outfunc_param)) | |
8 | |
9 #define ARG() \ | |
10 _ulong = flags&LONGINT ? va_arg(argp, long) : \ | |
11 flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); | |
12 | |
13 #define BUF 256 | |
14 | |
15 #define todigit(c) ((c) - '0') | |
16 #define tochar(n) ((n) + '0') | |
17 | |
18 /* have to deal with the negative buffer count kludge */ | |
19 #define NEGATIVE_COUNT_KLUDGE | |
20 | |
21 #define LONGINT 0x01 /* long integer */ | |
22 #define LONGDBL 0x02 /* long double; unimplemented */ | |
23 #define SHORTINT 0x04 /* short integer */ | |
24 #define ALT 0x08 /* alternate form */ | |
25 #define LADJUST 0x10 /* left adjustment */ | |
26 #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ | |
27 #define HEXPREFIX 0x40 /* add 0x or 0X prefix */ | |
28 | |
29 _doprnt(fmt0, argp, outfunc, outfunc_param) | |
30 u_char *fmt0; | |
31 va_list argp; | |
32 void (*outfunc)(); | |
33 void *outfunc_param; | |
34 { | |
35 register u_char *fmt; /* format string */ | |
36 register int ch; /* character from fmt */ | |
37 register int cnt; /* return value accumulator */ | |
38 register int n; /* random handy integer */ | |
39 register char *t; /* buffer pointer */ | |
40 u_long _ulong; /* integer arguments %[diouxX] */ | |
41 int base; /* base for [diouxX] conversion */ | |
42 int dprec; /* decimal precision in [diouxX] */ | |
43 int fieldsz; /* field size expanded by sign, etc */ | |
44 int flags; /* flags as above */ | |
45 int prec; /* precision from format (%.3d), or -1 */ | |
46 int realsz; /* field size expanded by decimal precision */ | |
47 int size; /* size of converted field or string */ | |
48 int width; /* width from format (%8d), or 0 */ | |
49 char sign; /* sign prefix (' ', '+', '-', or \0) */ | |
50 char softsign; /* temporary negative sign for floats */ | |
51 char *digs; /* digits for [diouxX] conversion */ | |
52 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ | |
53 | |
54 fmt = fmt0; | |
55 digs = "0123456789abcdef"; | |
56 for (cnt = 0;; ++fmt) { | |
57 for (; (ch = *fmt) && ch != '%'; ++cnt, ++fmt) | |
58 PUTC(ch); | |
59 if (!ch) | |
60 return (cnt); | |
61 | |
62 flags = 0; dprec = 0; width = 0; | |
63 prec = -1; | |
64 sign = '\0'; | |
65 | |
66 rflag: switch (*++fmt) { | |
67 case ' ': | |
68 /* | |
69 * ``If the space and + flags both appear, the space | |
70 * flag will be ignored.'' | |
71 * -- ANSI X3J11 | |
72 */ | |
73 if (!sign) | |
74 sign = ' '; | |
75 goto rflag; | |
76 case '#': | |
77 flags |= ALT; | |
78 goto rflag; | |
79 case '*': | |
80 /* | |
81 * ``A negative field width argument is taken as a | |
82 * - flag followed by a positive field width.'' | |
83 * -- ANSI X3J11 | |
84 * They don't exclude field widths read from args. | |
85 */ | |
86 if ((width = va_arg(argp, int)) >= 0) | |
87 goto rflag; | |
88 width = -width; | |
89 /* FALLTHROUGH */ | |
90 case '-': | |
91 flags |= LADJUST; | |
92 goto rflag; | |
93 case '+': | |
94 sign = '+'; | |
95 goto rflag; | |
96 case '.': | |
97 if (*++fmt == '*') | |
98 n = va_arg(argp, int); | |
99 else { | |
100 n = 0; | |
101 while (isascii(*fmt) && isdigit(*fmt)) | |
102 n = 10 * n + todigit(*fmt++); | |
103 --fmt; | |
104 } | |
105 prec = n < 0 ? -1 : n; | |
106 goto rflag; | |
107 case '0': | |
108 /* | |
109 * ``Note that 0 is taken as a flag, not as the | |
110 * beginning of a field width.'' | |
111 * -- ANSI X3J11 | |
112 */ | |
113 flags |= ZEROPAD; | |
114 goto rflag; | |
115 case '1': case '2': case '3': case '4': | |
116 case '5': case '6': case '7': case '8': case '9': | |
117 n = 0; | |
118 do { | |
119 n = 10 * n + todigit(*fmt); | |
120 } while (isascii(*++fmt) && isdigit(*fmt)); | |
121 width = n; | |
122 --fmt; | |
123 goto rflag; | |
124 case 'L': | |
125 flags |= LONGDBL; | |
126 goto rflag; | |
127 case 'h': | |
128 flags |= SHORTINT; | |
129 goto rflag; | |
130 case 'l': | |
131 flags |= LONGINT; | |
132 goto rflag; | |
133 case 'c': | |
134 *(t = buf) = va_arg(argp, int); | |
135 size = 1; | |
136 sign = '\0'; | |
137 goto pforw; | |
138 case 'D': | |
139 flags |= LONGINT; | |
140 /*FALLTHROUGH*/ | |
141 case 'd': | |
142 case 'i': | |
143 ARG(); | |
144 if ((long)_ulong < 0) { | |
145 _ulong = -_ulong; | |
146 sign = '-'; | |
147 } | |
148 base = 10; | |
149 goto number; | |
150 case 'n': | |
151 if (flags & LONGINT) | |
152 *va_arg(argp, long *) = cnt; | |
153 else if (flags & SHORTINT) | |
154 *va_arg(argp, short *) = cnt; | |
155 else | |
156 *va_arg(argp, int *) = cnt; | |
157 break; | |
158 case 'O': | |
159 flags |= LONGINT; | |
160 /*FALLTHROUGH*/ | |
161 case 'o': | |
162 ARG(); | |
163 base = 8; | |
164 goto nosign; | |
165 case 'p': | |
166 /* | |
167 * ``The argument shall be a pointer to void. The | |
168 * value of the pointer is converted to a sequence | |
169 * of printable characters, in an implementation- | |
170 * defined manner.'' | |
171 * -- ANSI X3J11 | |
172 */ | |
173 /* NOSTRICT */ | |
174 _ulong = (u_long)va_arg(argp, void *); | |
175 base = 16; | |
176 goto nosign; | |
177 case 's': | |
178 if (!(t = va_arg(argp, char *))) | |
179 t = "(null)"; | |
180 if (prec >= 0) { | |
181 /* | |
182 * can't use strlen; can only look for the | |
183 * NUL in the first `prec' characters, and | |
184 * strlen() will go further. | |
185 */ | |
186 char *p; | |
187 | |
188 for (p = t, size = 0; size < prec; p++, size++) | |
189 if (*p == '\0') | |
190 break; | |
191 } else | |
192 size = strlen(t); | |
193 sign = '\0'; | |
194 goto pforw; | |
195 case 'U': | |
196 flags |= LONGINT; | |
197 /*FALLTHROUGH*/ | |
198 case 'u': | |
199 ARG(); | |
200 base = 10; | |
201 goto nosign; | |
202 case 'X': | |
203 digs = "0123456789ABCDEF"; | |
204 /* FALLTHROUGH */ | |
205 case 'x': | |
206 ARG(); | |
207 base = 16; | |
208 /* leading 0x/X only if non-zero */ | |
209 if (flags & ALT && _ulong != 0) | |
210 flags |= HEXPREFIX; | |
211 | |
212 /* unsigned conversions */ | |
213 nosign: sign = '\0'; | |
214 /* | |
215 * ``... diouXx conversions ... if a precision is | |
216 * specified, the 0 flag will be ignored.'' | |
217 * -- ANSI X3J11 | |
218 */ | |
219 number: if ((dprec = prec) >= 0) | |
220 flags &= ~ZEROPAD; | |
221 | |
222 /* | |
223 * ``The result of converting a zero value with an | |
224 * explicit precision of zero is no characters.'' | |
225 * -- ANSI X3J11 | |
226 */ | |
227 t = buf + BUF; | |
228 if (_ulong != 0 || prec != 0) { | |
229 do { | |
230 *--t = digs[_ulong % base]; | |
231 _ulong /= base; | |
232 } while (_ulong); | |
233 digs = "0123456789abcdef"; | |
234 if (flags & ALT && base == 8 && *t != '0') | |
235 *--t = '0'; /* octal leading 0 */ | |
236 } | |
237 size = buf + BUF - t; | |
238 | |
239 pforw: | |
240 /* | |
241 * All reasonable formats wind up here. At this point, | |
242 * `t' points to a string which (if not flags&LADJUST) | |
243 * should be padded out to `width' places. If | |
244 * flags&ZEROPAD, it should first be prefixed by any | |
245 * sign or other prefix; otherwise, it should be blank | |
246 * padded before the prefix is emitted. After any | |
247 * left-hand padding and prefixing, emit zeroes | |
248 * required by a decimal [diouxX] precision, then print | |
249 * the string proper, then emit zeroes required by any | |
250 * leftover floating precision; finally, if LADJUST, | |
251 * pad with blanks. | |
252 */ | |
253 | |
254 /* | |
255 * compute actual size, so we know how much to pad | |
256 * fieldsz excludes decimal prec; realsz includes it | |
257 */ | |
258 fieldsz = size; | |
259 if (sign) | |
260 fieldsz++; | |
261 if (flags & HEXPREFIX) | |
262 fieldsz += 2; | |
263 realsz = dprec > fieldsz ? dprec : fieldsz; | |
264 | |
265 /* right-adjusting blank padding */ | |
266 if ((flags & (LADJUST|ZEROPAD)) == 0 && width) | |
267 for (n = realsz; n < width; n++) | |
268 PUTC(' '); | |
269 /* prefix */ | |
270 if (sign) | |
271 PUTC(sign); | |
272 if (flags & HEXPREFIX) { | |
273 PUTC('0'); | |
274 PUTC((char)*fmt); | |
275 } | |
276 /* right-adjusting zero padding */ | |
277 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) | |
278 for (n = realsz; n < width; n++) | |
279 PUTC('0'); | |
280 /* leading zeroes from decimal precision */ | |
281 for (n = fieldsz; n < dprec; n++) | |
282 PUTC('0'); | |
283 | |
284 for (n = size; --n >= 0; ) | |
285 PUTC(*t++); | |
286 /* left-adjusting padding (always blank) */ | |
287 if (flags & LADJUST) | |
288 for (n = realsz; n < width; n++) | |
289 PUTC(' '); | |
290 /* finally, adjust cnt */ | |
291 cnt += width > realsz ? width : realsz; | |
292 break; | |
293 case '\0': /* "%?" prints ?, unless ? is NULL */ | |
294 return (cnt); | |
295 default: | |
296 PUTC((char)*fmt); | |
297 cnt++; | |
298 } | |
299 } | |
300 /* NOTREACHED */ | |
301 } |