comparison rvinterf/ctracedec/doprnt.c @ 858:4c6e7ada647b

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