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 }