1: /*-
2: * Copyright (c) 1986, 1988, 1991, 1993
3: * The Regents of the University of California. All rights reserved.
4: * (c) UNIX System Laboratories, Inc.
5: * All or some portions of this file are derived from material licensed
6: * to the University of California by American Telephone and Telegraph
7: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8: * the permission of UNIX System Laboratories, Inc.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the University of
21: * California, Berkeley and its contributors.
22: * 4. Neither the name of the University nor the names of its contributors
23: * may be used to endorse or promote products derived from this software
24: * without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36: * SUCH DAMAGE.
37: *
38: * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
39: * $FreeBSD: src/lib/libstand/printf.c,v 1.4 1999/12/27 08:45:14 peter Exp $
40: * $DragonFly: src/lib/libstand/printf.c,v 1.3 2003/11/09 02:34:03 dillon Exp $
41: */
42:
43: /*
44: * Standaloneified version of the FreeBSD kernel printf family.
45: */
46:
47: #include <sys/types.h>
48: #include <string.h>
49: #include "stand.h"
50:
51: /*
52: * Note that stdarg.h and the ANSI style va_start macro is used for both
53: * ANSI and traditional C compilers.
54: */
55: #include <stdarg.h>
56:
57: static char *ksprintn (u_long num, int base, int *len);
58: static int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap);
59:
60: int
61: printf(const char *fmt, ...)
62: {
63: va_list ap;
64: int retval;
65:
66: va_start(ap, fmt);
67: retval = kvprintf(fmt, putchar, NULL, 10, ap);
68: va_end(ap);
69: return retval;
70: }
71:
72: void
73: vprintf(const char *fmt, va_list ap)
74: {
75:
76: kvprintf(fmt, putchar, NULL, 10, ap);
77: }
78:
79: int
80: sprintf(char *buf, const char *cfmt, ...)
81: {
82: int retval;
83: va_list ap;
84:
85: va_start(ap, cfmt);
86: retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
87: buf[retval] = '\0';
88: va_end(ap);
89: return retval;
90: }
91:
92: void
93: vsprintf(char *buf, const char *cfmt, va_list ap)
94: {
95: int retval;
96:
97: retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
98: buf[retval] = '\0';
99: }
100:
101: /*
102: * Put a number (base <= 16) in a buffer in reverse order; return an
103: * optional length and a pointer to the NULL terminated (preceded?)
104: * buffer.
105: */
106: static char *
107: ksprintn(ul, base, lenp)
108: register u_long ul;
109: register int base, *lenp;
110: { /* A long in base 8, plus NULL. */
111: static char buf[sizeof(long) * NBBY / 3 + 2];
112: register char *p;
113:
114: p = buf;
115: do {
116: *++p = hex2ascii(ul % base);
117: } while (ul /= base);
118: if (lenp)
119: *lenp = p - buf;
120: return (p);
121: }
122:
123: /*
124: * Scaled down version of printf(3).
125: *
126: * Two additional formats:
127: *
128: * The format %b is supported to decode error registers.
129: * Its usage is:
130: *
131: * printf("reg=%b\n", regval, "<base><arg>*");
132: *
133: * where <base> is the output base expressed as a control character, e.g.
134: * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
135: * the first of which gives the bit number to be inspected (origin 1), and
136: * the next characters (up to a control character, i.e. a character <= 32),
137: * give the name of the register. Thus:
138: *
139: * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
140: *
141: * would produce output:
142: *
143: * reg=3<BITTWO,BITONE>
144: *
145: * XXX: %D -- Hexdump, takes pointer and separator string:
146: * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
147: * ("%*D", len, ptr, " " -> XX XX XX XX ...
148: */
149: static int
150: kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap)
151: {
152: #define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
153: char *p, *q, *d;
154: u_char *up;
155: int ch, n;
156: u_long ul;
157: int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
158: int dwidth;
159: char padc;
160: int retval = 0;
161:
162: if (!func)
163: d = (char *) arg;
164: else
165: d = NULL;
166:
167: if (fmt == NULL)
168: fmt = "(fmt null)\n";
169:
170: if (radix < 2 || radix > 36)
171: radix = 10;
172:
173: for (;;) {
174: padc = ' ';
175: width = 0;
176: while ((ch = (u_char)*fmt++) != '%') {
177: if (ch == '\0')
178: return retval;
179: PCHAR(ch);
180: }
181: lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
182: sign = 0; dot = 0; dwidth = 0;
183: reswitch: switch (ch = (u_char)*fmt++) {
184: case '.':
185: dot = 1;
186: goto reswitch;
187: case '#':
188: sharpflag = 1;
189: goto reswitch;
190: case '+':
191: sign = 1;
192: goto reswitch;
193: case '-':
194: ladjust = 1;
195: goto reswitch;
196: case '%':
197: PCHAR(ch);
198: break;
199: case '*':
200: if (!dot) {
201: width = va_arg(ap, int);
202: if (width < 0) {
203: ladjust = !ladjust;
204: width = -width;
205: }
206: } else {
207: dwidth = va_arg(ap, int);
208: }
209: goto reswitch;
210: case '0':
211: if (!dot) {
212: padc = '0';
213: goto reswitch;
214: }
215: case '1': case '2': case '3': case '4':
216: case '5': case '6': case '7': case '8': case '9':
217: for (n = 0;; ++fmt) {
218: n = n * 10 + ch - '0';
219: ch = *fmt;
220: if (ch < '0' || ch > '9')
221: break;
222: }
223: if (dot)
224: dwidth = n;
225: else
226: width = n;
227: goto reswitch;
228: case 'b':
229: ul = va_arg(ap, int);
230: p = va_arg(ap, char *);
231: for (q = ksprintn(ul, *p++, NULL); *q;)
232: PCHAR(*q--);
233:
234: if (!ul)
235: break;
236:
237: for (tmp = 0; *p;) {
238: n = *p++;
239: if (ul & (1 << (n - 1))) {
240: PCHAR(tmp ? ',' : '<');
241: for (; (n = *p) > ' '; ++p)
242: PCHAR(n);
243: tmp = 1;
244: } else
245: for (; *p > ' '; ++p)
246: continue;
247: }
248: if (tmp)
249: PCHAR('>');
250: break;
251: case 'c':
252: PCHAR(va_arg(ap, int));
253: break;
254: case 'D':
255: up = va_arg(ap, u_char *);
256: p = va_arg(ap, char *);
257: if (!width)
258: width = 16;
259: while(width--) {
260: PCHAR(hex2ascii(*up >> 4));
261: PCHAR(hex2ascii(*up & 0x0f));
262: up++;
263: if (width)
264: for (q=p;*q;q++)
265: PCHAR(*q);
266: }
267: break;
268: case 'd':
269: ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
270: sign = 1;
271: base = 10;
272: goto number;
273: case 'l':
274: lflag = 1;
275: goto reswitch;
276: case 'n':
277: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
278: base = radix;
279: goto number;
280: case 'o':
281: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
282: base = 8;
283: goto number;
284: case 'p':
285: ul = (u_long)va_arg(ap, void *);
286: base = 16;
287: sharpflag = 1;
288: goto number;
289: case 's':
290: p = va_arg(ap, char *);
291: if (p == NULL)
292: p = "(null)";
293: if (!dot)
294: n = strlen (p);
295: else
296: for (n = 0; n < dwidth && p[n]; n++)
297: continue;
298:
299: width -= n;
300:
301: if (!ladjust && width > 0)
302: while (width--)
303: PCHAR(padc);
304: while (n--)
305: PCHAR(*p++);
306: if (ladjust && width > 0)
307: while (width--)
308: PCHAR(padc);
309: break;
310: case 'u':
311: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
312: base = 10;
313: goto number;
314: case 'x':
315: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
316: base = 16;
317: number: if (sign && (long)ul < 0L) {
318: neg = 1;
319: ul = -(long)ul;
320: }
321: p = ksprintn(ul, base, &tmp);
322: if (sharpflag && ul != 0) {
323: if (base == 8)
324: tmp++;
325: else if (base == 16)
326: tmp += 2;
327: }
328: if (neg)
329: tmp++;
330:
331: if (!ladjust && width && (width -= tmp) > 0)
332: while (width--)
333: PCHAR(padc);
334: if (neg)
335: PCHAR('-');
336: if (sharpflag && ul != 0) {
337: if (base == 8) {
338: PCHAR('0');
339: } else if (base == 16) {
340: PCHAR('0');
341: PCHAR('x');
342: }
343: }
344:
345: while (*p)
346: PCHAR(*p--);
347:
348: if (ladjust && width && (width -= tmp) > 0)
349: while (width--)
350: PCHAR(padc);
351:
352: break;
353: default:
354: PCHAR('%');
355: if (lflag)
356: PCHAR('l');
357: PCHAR(ch);
358: break;
359: }
360: }
361: #undef PCHAR
362: }
363: