comparison lldbg/doprnt.c @ 0:75a11d740a02

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