xref: /f-stack/lib/ff_subr_prf.c (revision 22ce4aff)
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  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *  @(#)subr_prf.c  8.3 (Berkeley) 1/21/94
35  */
36 
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39 
40 #include "opt_ddb.h"
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/lock.h>
45 #include <sys/kdb.h>
46 #include <sys/mutex.h>
47 #include <sys/sx.h>
48 #include <sys/kernel.h>
49 #include <sys/msgbuf.h>
50 #include <sys/malloc.h>
51 #include <sys/priv.h>
52 #include <sys/proc.h>
53 #include <sys/stddef.h>
54 #include <sys/sysctl.h>
55 #include <sys/tty.h>
56 #include <sys/syslog.h>
57 #include <sys/cons.h>
58 #include <sys/uio.h>
59 #include <sys/ctype.h>
60 #include <sys/sbuf.h>
61 
62 #ifdef DDB
63 #include <ddb/ddb.h>
64 #endif
65 
66 /*
67  * Note that stdarg.h and the ANSI style va_start macro is used for both
68  * ANSI and traditional C compilers.
69  */
70 #include <machine/stdarg.h>
71 
72 #define TOCONS    0x01
73 #define TOTTY    0x02
74 #define TOLOG    0x04
75 
76 /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
77 #define MAXNBUF    (sizeof(intmax_t) * NBBY + 1)
78 
79 struct putchar_arg {
80     int flags;
81     int pri;
82     struct tty *tty;
83     char *p_bufr;
84     size_t n_bufr;
85     char *p_next;
86     size_t remain;
87 };
88 
89 struct snprintf_arg {
90     char *str;
91     size_t remain;
92 };
93 
94 int putchar(int c);
95 int puts(const char *str);
96 
97 
98 static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
99 
100 /*
101  * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
102  * order; return an optional length and a pointer to the last character
103  * written in the buffer (i.e., the first character of the string).
104  * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
105  */
106 static char *
ksprintn(char * nbuf,uintmax_t num,int base,int * lenp,int upper)107 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
108 {
109     char *p, c;
110 
111     p = nbuf;
112     *p = '\0';
113     do {
114         c = hex2ascii(num % base);
115         *++p = upper ? toupper(c) : c;
116     } while (num /= base);
117     if (lenp)
118         *lenp = p - nbuf;
119     return (p);
120 }
121 
122 static void
putbuf(int c,struct putchar_arg * ap)123 putbuf(int c, struct putchar_arg *ap)
124 {
125     /* Check if no console output buffer was provided. */
126     if (ap->p_bufr == NULL) {
127         /* Output direct to the console. */
128         if (ap->flags & TOCONS)
129             putchar(c);
130 
131     } else {
132         /* Buffer the character: */
133         *ap->p_next++ = c;
134         ap->remain--;
135 
136         /* Always leave the buffer zero terminated. */
137         *ap->p_next = '\0';
138 
139         /* Check if the buffer needs to be flushed. */
140         if (ap->remain == 2 || c == '\n') {
141 
142             if (ap->flags & TOCONS) {
143                 puts(ap->p_bufr);
144             }
145 
146             ap->p_next = ap->p_bufr;
147             ap->remain = ap->n_bufr;
148             *ap->p_next = '\0';
149         }
150 
151         /*
152          * Since we fill the buffer up one character at a time,
153          * this should not happen.  We should always catch it when
154          * ap->remain == 2 (if not sooner due to a newline), flush
155          * the buffer and move on.  One way this could happen is
156          * if someone sets PRINTF_BUFR_SIZE to 1 or something
157          * similarly silly.
158          */
159         KASSERT(ap->remain > 2, ("Bad buffer logic, remain = %zd",
160             ap->remain));
161     }
162 }
163 
164 /*
165  * Print a character on console or users terminal.  If destination is
166  * the console then the last bunch of characters are saved in msgbuf for
167  * inspection later.
168  */
169 static void
kputchar(int c,void * arg)170 kputchar(int c, void *arg)
171 {
172     struct putchar_arg *ap = (struct putchar_arg*) arg;
173     int flags = ap->flags;
174     int putbuf_done = 0;
175 
176     if (flags & TOCONS) {
177         putbuf(c, ap);
178         putbuf_done = 1;
179     }
180 
181     if ((flags & TOLOG) && (putbuf_done == 0)) {
182         if (c != '\0')
183             putbuf(c, ap);
184     }
185 }
186 
187 /*
188  * Scaled down version of printf(3).
189  *
190  * Two additional formats:
191  *
192  * The format %b is supported to decode error registers.
193  * Its usage is:
194  *
195  *    printf("reg=%b\n", regval, "<base><arg>*");
196  *
197  * where <base> is the output base expressed as a control character, e.g.
198  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
199  * the first of which gives the bit number to be inspected (origin 1), and
200  * the next characters (up to a control character, i.e. a character <= 32),
201  * give the name of the register.  Thus:
202  *
203  *    kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
204  *
205  * would produce output:
206  *
207  *    reg=3<BITTWO,BITONE>
208  *
209  * XXX:  %D  -- Hexdump, takes pointer and separator string:
210  *        ("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
211  *        ("%*D", len, ptr, " " -> XX XX XX XX ...
212  */
213 int
kvprintf(char const * fmt,void (* func)(int,void *),void * arg,int radix,va_list ap)214 kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
215 {
216 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
217     char nbuf[MAXNBUF];
218     char *d;
219     const char *p, *percent, *q;
220     u_char *up;
221     int ch, n;
222     uintmax_t num;
223     int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
224     int cflag, hflag, jflag, tflag, zflag;
225     int dwidth, upper;
226     char padc;
227     int stop = 0, retval = 0;
228 
229     num = 0;
230     if (!func)
231         d = (char *) arg;
232     else
233         d = NULL;
234 
235     if (fmt == NULL)
236         fmt = "(fmt null)\n";
237 
238     if (radix < 2 || radix > 36)
239         radix = 10;
240 
241     for (;;) {
242         padc = ' ';
243         width = 0;
244         while ((ch = (u_char)*fmt++) != '%' || stop) {
245             if (ch == '\0')
246                 return (retval);
247             PCHAR(ch);
248         }
249         percent = fmt - 1;
250         qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
251         sign = 0; dot = 0; dwidth = 0; upper = 0;
252         cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
253 reswitch:    switch (ch = (u_char)*fmt++) {
254         case '.':
255             dot = 1;
256             goto reswitch;
257         case '#':
258             sharpflag = 1;
259             goto reswitch;
260         case '+':
261             sign = 1;
262             goto reswitch;
263         case '-':
264             ladjust = 1;
265             goto reswitch;
266         case '%':
267             PCHAR(ch);
268             break;
269         case '*':
270             if (!dot) {
271                 width = va_arg(ap, int);
272                 if (width < 0) {
273                     ladjust = !ladjust;
274                     width = -width;
275                 }
276             } else {
277                 dwidth = va_arg(ap, int);
278             }
279             goto reswitch;
280         case '0':
281             if (!dot) {
282                 padc = '0';
283                 goto reswitch;
284             }
285         case '1': case '2': case '3': case '4':
286         case '5': case '6': case '7': case '8': case '9':
287                 for (n = 0;; ++fmt) {
288                     n = n * 10 + ch - '0';
289                     ch = *fmt;
290                     if (ch < '0' || ch > '9')
291                         break;
292                 }
293             if (dot)
294                 dwidth = n;
295             else
296                 width = n;
297             goto reswitch;
298         case 'b':
299             num = (u_int)va_arg(ap, int);
300             p = va_arg(ap, char *);
301             for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
302                 PCHAR(*q--);
303 
304             if (num == 0)
305                 break;
306 
307             for (tmp = 0; *p;) {
308                 n = *p++;
309                 if (num & (1 << (n - 1))) {
310                     PCHAR(tmp ? ',' : '<');
311                     for (; (n = *p) > ' '; ++p)
312                         PCHAR(n);
313                     tmp = 1;
314                 } else
315                     for (; *p > ' '; ++p)
316                         continue;
317             }
318             if (tmp)
319                 PCHAR('>');
320             break;
321         case 'c':
322             PCHAR(va_arg(ap, int));
323             break;
324         case 'D':
325             up = va_arg(ap, u_char *);
326             p = va_arg(ap, char *);
327             if (!width)
328                 width = 16;
329             while(width--) {
330                 PCHAR(hex2ascii(*up >> 4));
331                 PCHAR(hex2ascii(*up & 0x0f));
332                 up++;
333                 if (width)
334                     for (q=p;*q;q++)
335                         PCHAR(*q);
336             }
337             break;
338         case 'd':
339         case 'i':
340             base = 10;
341             sign = 1;
342             goto handle_sign;
343         case 'h':
344             if (hflag) {
345                 hflag = 0;
346                 cflag = 1;
347             } else
348                 hflag = 1;
349             goto reswitch;
350         case 'j':
351             jflag = 1;
352             goto reswitch;
353         case 'l':
354             if (lflag) {
355                 lflag = 0;
356                 qflag = 1;
357             } else
358                 lflag = 1;
359             goto reswitch;
360         case 'n':
361             if (jflag)
362                 *(va_arg(ap, intmax_t *)) = retval;
363             else if (qflag)
364                 *(va_arg(ap, quad_t *)) = retval;
365             else if (lflag)
366                 *(va_arg(ap, long *)) = retval;
367             else if (zflag)
368                 *(va_arg(ap, size_t *)) = retval;
369             else if (hflag)
370                 *(va_arg(ap, short *)) = retval;
371             else if (cflag)
372                 *(va_arg(ap, char *)) = retval;
373             else
374                 *(va_arg(ap, int *)) = retval;
375             break;
376         case 'o':
377             base = 8;
378             goto handle_nosign;
379         case 'p':
380             base = 16;
381             sharpflag = (width == 0);
382             sign = 0;
383             num = (uintptr_t)va_arg(ap, void *);
384             goto number;
385         case 'q':
386             qflag = 1;
387             goto reswitch;
388         case 'r':
389             base = radix;
390             if (sign)
391                 goto handle_sign;
392             goto handle_nosign;
393         case 's':
394             p = va_arg(ap, char *);
395             if (p == NULL)
396                 p = "(null)";
397             if (!dot)
398                 n = strlen (p);
399             else
400                 for (n = 0; n < dwidth && p[n]; n++)
401                     continue;
402 
403             width -= n;
404 
405             if (!ladjust && width > 0)
406                 while (width--)
407                     PCHAR(padc);
408             while (n--)
409                 PCHAR(*p++);
410             if (ladjust && width > 0)
411                 while (width--)
412                     PCHAR(padc);
413             break;
414         case 't':
415             tflag = 1;
416             goto reswitch;
417         case 'u':
418             base = 10;
419             goto handle_nosign;
420         case 'X':
421             upper = 1;
422         case 'x':
423             base = 16;
424             goto handle_nosign;
425         case 'y':
426             base = 16;
427             sign = 1;
428             goto handle_sign;
429         case 'z':
430             zflag = 1;
431             goto reswitch;
432 handle_nosign:
433             sign = 0;
434             if (jflag)
435                 num = va_arg(ap, uintmax_t);
436             else if (qflag)
437                 num = va_arg(ap, u_quad_t);
438             else if (tflag)
439                 num = va_arg(ap, ptrdiff_t);
440             else if (lflag)
441                 num = va_arg(ap, u_long);
442             else if (zflag)
443                 num = va_arg(ap, size_t);
444             else if (hflag)
445                 num = (u_short)va_arg(ap, int);
446             else if (cflag)
447                 num = (u_char)va_arg(ap, int);
448             else
449                 num = va_arg(ap, u_int);
450             goto number;
451 handle_sign:
452             if (jflag)
453                 num = va_arg(ap, intmax_t);
454             else if (qflag)
455                 num = va_arg(ap, quad_t);
456             else if (tflag)
457                 num = va_arg(ap, ptrdiff_t);
458             else if (lflag)
459                 num = va_arg(ap, long);
460             else if (zflag)
461                 num = va_arg(ap, ssize_t);
462             else if (hflag)
463                 num = (short)va_arg(ap, int);
464             else if (cflag)
465                 num = (char)va_arg(ap, int);
466             else
467                 num = va_arg(ap, int);
468 number:
469             if (sign && (intmax_t)num < 0) {
470                 neg = 1;
471                 num = -(intmax_t)num;
472             }
473             p = ksprintn(nbuf, num, base, &n, upper);
474             tmp = 0;
475             if (sharpflag && num != 0) {
476                 if (base == 8)
477                     tmp++;
478                 else if (base == 16)
479                     tmp += 2;
480             }
481             if (neg)
482                 tmp++;
483 
484             if (!ladjust && padc == '0')
485                 dwidth = width - tmp;
486             width -= tmp + imax(dwidth, n);
487             dwidth -= n;
488             if (!ladjust)
489                 while (width-- > 0)
490                     PCHAR(' ');
491             if (neg)
492                 PCHAR('-');
493             if (sharpflag && num != 0) {
494                 if (base == 8) {
495                     PCHAR('0');
496                 } else if (base == 16) {
497                     PCHAR('0');
498                     PCHAR('x');
499                 }
500             }
501             while (dwidth-- > 0)
502                 PCHAR('0');
503 
504             while (*p)
505                 PCHAR(*p--);
506 
507             if (ladjust)
508                 while (width-- > 0)
509                     PCHAR(' ');
510 
511             break;
512         default:
513             while (percent < fmt)
514                 PCHAR(*percent++);
515             /*
516              * Since we ignore an formatting argument it is no
517              * longer safe to obey the remaining formatting
518              * arguments as the arguments will no longer match
519              * the format specs.
520              */
521             stop = 1;
522             break;
523         }
524     }
525 #undef PCHAR
526 }
527 
528 int
printf(const char * fmt,...)529 printf(const char *fmt, ...)
530 {
531     va_list ap;
532     int retval;
533 
534     va_start(ap, fmt);
535     retval = vprintf(fmt, ap);
536     va_end(ap);
537 
538     return (retval);
539 }
540 
541 int
vprintf(const char * fmt,va_list ap)542 vprintf(const char *fmt, va_list ap)
543 {
544     struct putchar_arg pca;
545     int retval;
546 #ifdef PRINTF_BUFR_SIZE
547     char bufr[PRINTF_BUFR_SIZE];
548 #endif
549 
550     pca.tty = NULL;
551     pca.flags = TOCONS | TOLOG;
552     pca.pri = -1;
553 #ifdef PRINTF_BUFR_SIZE
554     pca.p_bufr = bufr;
555     pca.p_next = pca.p_bufr;
556     pca.n_bufr = sizeof(bufr);
557     pca.remain = sizeof(bufr);
558     *pca.p_next = '\0';
559 #else
560     /* Don't buffer console output. */
561     pca.p_bufr = NULL;
562 #endif
563 
564     retval = kvprintf(fmt, kputchar, &pca, 10, ap);
565 
566 #ifdef PRINTF_BUFR_SIZE
567     /* Write any buffered console/log output: */
568     if (*pca.p_bufr != '\0') {
569         cnputs(pca.p_bufr);
570         msglogstr(pca.p_bufr, pca.pri, /*filter_cr*/ 1);
571     }
572 #endif
573 
574     return (retval);
575 }
576 
577 void
vlog(int level,const char * fmt,va_list ap)578 vlog(int level, const char *fmt, va_list ap)
579 {
580     (void)vprintf(fmt, ap);
581 }
582 
583 int
sbuf_printf_drain(void * arg,const char * data,int len)584 sbuf_printf_drain(void *arg, const char *data, int len)
585 {
586     return 0;
587 }
588 
589