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