]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libstand/printf.c
This commit was generated by cvs2svn to compensate for changes in r98038,
[FreeBSD/FreeBSD.git] / lib / libstand / printf.c
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  */
40
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 /*
45  * Standaloneified version of the FreeBSD kernel printf family.
46  */
47
48 #include <sys/types.h>
49 #include <string.h>
50 #include "stand.h"
51
52 /*
53  * Note that stdarg.h and the ANSI style va_start macro is used for both
54  * ANSI and traditional C compilers.
55  */
56 #include <machine/stdarg.h>
57
58 static char     *ksprintn (u_long num, int base, int *len);
59 static int      kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap);
60
61 int
62 printf(const char *fmt, ...)
63 {
64         va_list ap;
65         int retval;
66
67         va_start(ap, fmt);
68         retval = kvprintf(fmt, putchar, NULL, 10, ap);
69         va_end(ap);
70         return retval;
71 }
72
73 void
74 vprintf(const char *fmt, va_list ap)
75 {
76
77         kvprintf(fmt, putchar, NULL, 10, ap);
78 }
79
80 int
81 sprintf(char *buf, const char *cfmt, ...)
82 {
83         int retval;
84         va_list ap;
85
86         va_start(ap, cfmt);
87         retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
88         buf[retval] = '\0';
89         va_end(ap);
90         return retval;
91 }
92
93 void
94 vsprintf(char *buf, const char *cfmt, va_list ap)
95 {
96         int     retval;
97         
98         retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
99         buf[retval] = '\0';
100 }
101
102 /*
103  * Put a number (base <= 16) in a buffer in reverse order; return an
104  * optional length and a pointer to the NULL terminated (preceded?)
105  * buffer.
106  */
107 static char *
108 ksprintn(ul, base, lenp)
109         u_long ul;
110         int base, *lenp;
111 {                                       /* A long in base 8, plus NULL. */
112         static char buf[sizeof(long) * NBBY / 3 + 2];
113         char *p;
114
115         p = buf;
116         do {
117                 *++p = hex2ascii(ul % base);
118         } while (ul /= base);
119         if (lenp)
120                 *lenp = p - buf;
121         return (p);
122 }
123
124 /*
125  * Scaled down version of printf(3).
126  *
127  * Two additional formats:
128  *
129  * The format %b is supported to decode error registers.
130  * Its usage is:
131  *
132  *      printf("reg=%b\n", regval, "<base><arg>*");
133  *
134  * where <base> is the output base expressed as a control character, e.g.
135  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
136  * the first of which gives the bit number to be inspected (origin 1), and
137  * the next characters (up to a control character, i.e. a character <= 32),
138  * give the name of the register.  Thus:
139  *
140  *      kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
141  *
142  * would produce output:
143  *
144  *      reg=3<BITTWO,BITONE>
145  *
146  * XXX:  %D  -- Hexdump, takes pointer and separator string:
147  *              ("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
148  *              ("%*D", len, ptr, " " -> XX XX XX XX ...
149  */
150 static int
151 kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap)
152 {
153 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
154         char *p, *q, *d;
155         u_char *up;
156         int ch, n;
157         u_long ul;
158         int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
159         int dwidth;
160         char padc;
161         int retval = 0;
162
163         if (!func)
164                 d = (char *) arg;
165         else
166                 d = NULL;
167
168         if (fmt == NULL)
169                 fmt = "(fmt null)\n";
170
171         if (radix < 2 || radix > 36)
172                 radix = 10;
173
174         for (;;) {
175                 padc = ' ';
176                 width = 0;
177                 while ((ch = (u_char)*fmt++) != '%') {
178                         if (ch == '\0') 
179                                 return retval;
180                         PCHAR(ch);
181                 }
182                 lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
183                 sign = 0; dot = 0; dwidth = 0;
184 reswitch:       switch (ch = (u_char)*fmt++) {
185                 case '.':
186                         dot = 1;
187                         goto reswitch;
188                 case '#':
189                         sharpflag = 1;
190                         goto reswitch;
191                 case '+':
192                         sign = 1;
193                         goto reswitch;
194                 case '-':
195                         ladjust = 1;
196                         goto reswitch;
197                 case '%':
198                         PCHAR(ch);
199                         break;
200                 case '*':
201                         if (!dot) {
202                                 width = va_arg(ap, int);
203                                 if (width < 0) {
204                                         ladjust = !ladjust;
205                                         width = -width;
206                                 }
207                         } else {
208                                 dwidth = va_arg(ap, int);
209                         }
210                         goto reswitch;
211                 case '0':
212                         if (!dot) {
213                                 padc = '0';
214                                 goto reswitch;
215                         }
216                 case '1': case '2': case '3': case '4':
217                 case '5': case '6': case '7': case '8': case '9':
218                                 for (n = 0;; ++fmt) {
219                                         n = n * 10 + ch - '0';
220                                         ch = *fmt;
221                                         if (ch < '0' || ch > '9')
222                                                 break;
223                                 }
224                         if (dot)
225                                 dwidth = n;
226                         else
227                                 width = n;
228                         goto reswitch;
229                 case 'b':
230                         ul = va_arg(ap, int);
231                         p = va_arg(ap, char *);
232                         for (q = ksprintn(ul, *p++, NULL); *q;)
233                                 PCHAR(*q--);
234
235                         if (!ul)
236                                 break;
237
238                         for (tmp = 0; *p;) {
239                                 n = *p++;
240                                 if (ul & (1 << (n - 1))) {
241                                         PCHAR(tmp ? ',' : '<');
242                                         for (; (n = *p) > ' '; ++p)
243                                                 PCHAR(n);
244                                         tmp = 1;
245                                 } else
246                                         for (; *p > ' '; ++p)
247                                                 continue;
248                         }
249                         if (tmp)
250                                 PCHAR('>');
251                         break;
252                 case 'c':
253                         PCHAR(va_arg(ap, int));
254                         break;
255                 case 'D':
256                         up = va_arg(ap, u_char *);
257                         p = va_arg(ap, char *);
258                         if (!width)
259                                 width = 16;
260                         while(width--) {
261                                 PCHAR(hex2ascii(*up >> 4));
262                                 PCHAR(hex2ascii(*up & 0x0f));
263                                 up++;
264                                 if (width)
265                                         for (q=p;*q;q++)
266                                                 PCHAR(*q);
267                         }
268                         break;
269                 case 'd':
270                         ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
271                         sign = 1;
272                         base = 10;
273                         goto number;
274                 case 'l':
275                         lflag = 1;
276                         goto reswitch;
277                 case 'n':
278                         ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
279                         base = radix;
280                         goto number;
281                 case 'o':
282                         ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
283                         base = 8;
284                         goto number;
285                 case 'p':
286                         ul = (u_long)va_arg(ap, void *);
287                         base = 16;
288                         sharpflag = 1;
289                         goto number;
290                 case 's':
291                         p = va_arg(ap, char *);
292                         if (p == NULL)
293                                 p = "(null)";
294                         if (!dot)
295                                 n = strlen (p);
296                         else
297                                 for (n = 0; n < dwidth && p[n]; n++)
298                                         continue;
299
300                         width -= n;
301
302                         if (!ladjust && width > 0)
303                                 while (width--)
304                                         PCHAR(padc);
305                         while (n--)
306                                 PCHAR(*p++);
307                         if (ladjust && width > 0)
308                                 while (width--)
309                                         PCHAR(padc);
310                         break;
311                 case 'u':
312                         ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
313                         base = 10;
314                         goto number;
315                 case 'x':
316                         ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
317                         base = 16;
318 number:                 if (sign && (long)ul < 0L) {
319                                 neg = 1;
320                                 ul = -(long)ul;
321                         }
322                         p = ksprintn(ul, base, &tmp);
323                         if (sharpflag && ul != 0) {
324                                 if (base == 8)
325                                         tmp++;
326                                 else if (base == 16)
327                                         tmp += 2;
328                         }
329                         if (neg)
330                                 tmp++;
331
332                         if (!ladjust && width && (width -= tmp) > 0)
333                                 while (width--)
334                                         PCHAR(padc);
335                         if (neg)
336                                 PCHAR('-');
337                         if (sharpflag && ul != 0) {
338                                 if (base == 8) {
339                                         PCHAR('0');
340                                 } else if (base == 16) {
341                                         PCHAR('0');
342                                         PCHAR('x');
343                                 }
344                         }
345
346                         while (*p)
347                                 PCHAR(*p--);
348
349                         if (ladjust && width && (width -= tmp) > 0)
350                                 while (width--)
351                                         PCHAR(padc);
352
353                         break;
354                 default:
355                         PCHAR('%');
356                         if (lflag)
357                                 PCHAR('l');
358                         PCHAR(ch);
359                         break;
360                 }
361         }
362 #undef PCHAR
363 }
364