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