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