FreeCalypso > hg > freecalypso-sw
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 } |