comparison target-utils/libprintf/doprnt.c @ 11:40f607bb0a2c

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