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