comparison target-utils/libprintf/doprnt.c @ 0:e7502631a0f9

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