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 }