[BACK]Return to subr_prf.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/subr_prf.c, Revision 1.37

1.37    ! thorpej     1: /*     $NetBSD: subr_prf.c,v 1.36 1996/10/27 21:55:20 gwr Exp $        */
1.15      cgd         2:
1.12      cgd         3: /*-
                      4:  * Copyright (c) 1986, 1988, 1991, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  * (c) UNIX System Laboratories, Inc.
                      7:  * All or some portions of this file are derived from material licensed
                      8:  * to the University of California by American Telephone and Telegraph
                      9:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     10:  * the permission of UNIX System Laboratories, Inc.
                     11:  *
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 1. Redistributions of source code must retain the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer.
                     17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
                     19:  *    documentation and/or other materials provided with the distribution.
                     20:  * 3. All advertising materials mentioning features or use of this software
                     21:  *    must display the following acknowledgement:
                     22:  *     This product includes software developed by the University of
                     23:  *     California, Berkeley and its contributors.
                     24:  * 4. Neither the name of the University nor the names of its contributors
                     25:  *    may be used to endorse or promote products derived from this software
                     26:  *    without specific prior written permission.
                     27:  *
                     28:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     29:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     30:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     31:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     32:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     33:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     34:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     35:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     36:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     37:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     38:  * SUCH DAMAGE.
                     39:  *
1.15      cgd        40:  *     @(#)subr_prf.c  8.3 (Berkeley) 1/21/94
1.12      cgd        41:  */
                     42:
                     43: #include <sys/param.h>
                     44: #include <sys/systm.h>
                     45: #include <sys/buf.h>
                     46: #include <sys/conf.h>
                     47: #include <sys/reboot.h>
                     48: #include <sys/msgbuf.h>
                     49: #include <sys/proc.h>
                     50: #include <sys/ioctl.h>
                     51: #include <sys/vnode.h>
                     52: #include <sys/file.h>
                     53: #include <sys/tty.h>
                     54: #include <sys/tprintf.h>
                     55: #include <sys/syslog.h>
                     56: #include <sys/malloc.h>
                     57:
1.20      christos   58: #include <dev/cons.h>
                     59:
1.12      cgd        60: /*
                     61:  * Note that stdarg.h and the ANSI style va_start macro is used for both
                     62:  * ANSI and traditional C compilers.
1.35      gwr        63:  * XXX: This requires that stdarg.h defines: va_alist, va_dcl
1.12      cgd        64:  */
                     65: #include <machine/stdarg.h>
                     66:
1.32      ws         67: #include "ipkdb.h"
1.28      ws         68:
1.12      cgd        69: #ifdef KADB
                     70: #include <machine/kdbparam.h>
1.22      christos   71: #endif
                     72: #ifdef KGDB
                     73: #include <machine/cpu.h>
1.12      cgd        74: #endif
1.20      christos   75:
1.12      cgd        76: #define TOCONS 0x01
                     77: #define TOTTY  0x02
                     78: #define TOLOG  0x04
                     79:
1.37    ! thorpej    80: /*
        !            81:  * This is the size of the buffer that should be passed to ksnprintn().
        !            82:  * It's the length of a long in base 8, plus NULL.
        !            83:  */
        !            84: #define KSNPRINTN_BUFSIZE      (sizeof(long) * NBBY / 3 + 2)
        !            85:
1.12      cgd        86: struct tty *constty;                   /* pointer to console "window" tty */
                     87:
1.20      christos   88: void   (*v_putc) __P((int)) = cnputc;  /* routine to putc on virtual console */
1.12      cgd        89:
1.20      christos   90: static void putchar __P((int, int, struct tty *));
1.37    ! thorpej    91: static char *ksnprintn __P((u_long, int, int *, char *, size_t));
1.30      christos   92: void kprintf __P((const char *, int, struct tty *, va_list));
1.12      cgd        93:
1.14      cgd        94: int consintr = 1;                      /* Ok to handle console interrupts? */
1.12      cgd        95:
                     96: /*
1.14      cgd        97:  * Variable panicstr contains argument to first call to panic; used as flag
                     98:  * to indicate that the kernel has already called panic.
1.12      cgd        99:  */
1.14      cgd       100: const char *panicstr;
1.12      cgd       101:
                    102: /*
                    103:  * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
                    104:  * and then reboots.  If we are called twice, then we avoid trying to sync
                    105:  * the disks as this often leads to recursive panics.
                    106:  */
1.14      cgd       107: void
1.12      cgd       108: #ifdef __STDC__
                    109: panic(const char *fmt, ...)
                    110: #else
1.14      cgd       111: panic(fmt, va_alist)
1.12      cgd       112:        char *fmt;
1.20      christos  113:        va_dcl
1.12      cgd       114: #endif
                    115: {
1.14      cgd       116:        int bootopt;
1.12      cgd       117:        va_list ap;
                    118:
1.14      cgd       119:        bootopt = RB_AUTOBOOT | RB_DUMP;
1.12      cgd       120:        if (panicstr)
                    121:                bootopt |= RB_NOSYNC;
                    122:        else
                    123:                panicstr = fmt;
                    124:
                    125:        va_start(ap, fmt);
1.31      cgd       126:        printf("panic: %:\n", fmt, ap);
1.12      cgd       127:        va_end(ap);
                    128:
1.32      ws        129: #if NIPKDB > 0
                    130:        ipkdb_panic();
1.28      ws        131: #endif
1.12      cgd       132: #ifdef KGDB
                    133:        kgdb_panic();
                    134: #endif
                    135: #ifdef KADB
1.14      cgd       136:        if (boothowto & RB_KDB)
                    137:                kdbpanic();
1.12      cgd       138: #endif
                    139: #ifdef DDB
                    140:        Debugger();
                    141: #endif
1.26      mrg       142:        boot(bootopt, NULL);
1.12      cgd       143: }
                    144:
                    145: /*
                    146:  * Warn that a system table is full.
                    147:  */
                    148: void
                    149: tablefull(tab)
                    150:        const char *tab;
                    151: {
                    152:
                    153:        log(LOG_ERR, "%s: table is full\n", tab);
                    154: }
                    155:
                    156: /*
                    157:  * Uprintf prints to the controlling terminal for the current process.
                    158:  * It may block if the tty queue is overfull.  No message is printed if
                    159:  * the queue does not clear in a reasonable time.
                    160:  */
                    161: void
                    162: #ifdef __STDC__
                    163: uprintf(const char *fmt, ...)
                    164: #else
1.14      cgd       165: uprintf(fmt, va_alist)
1.12      cgd       166:        char *fmt;
1.20      christos  167:        va_dcl
1.12      cgd       168: #endif
                    169: {
                    170:        register struct proc *p = curproc;
                    171:        va_list ap;
                    172:
                    173:        if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
                    174:                va_start(ap, fmt);
1.30      christos  175:                kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
1.12      cgd       176:                va_end(ap);
                    177:        }
                    178: }
                    179:
                    180: tpr_t
                    181: tprintf_open(p)
                    182:        register struct proc *p;
                    183: {
                    184:
                    185:        if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
                    186:                SESSHOLD(p->p_session);
                    187:                return ((tpr_t) p->p_session);
                    188:        }
                    189:        return ((tpr_t) NULL);
                    190: }
                    191:
                    192: void
                    193: tprintf_close(sess)
                    194:        tpr_t sess;
                    195: {
                    196:
                    197:        if (sess)
                    198:                SESSRELE((struct session *) sess);
                    199: }
                    200:
                    201: /*
                    202:  * tprintf prints on the controlling terminal associated
                    203:  * with the given session.
                    204:  */
                    205: void
                    206: #ifdef __STDC__
                    207: tprintf(tpr_t tpr, const char *fmt, ...)
                    208: #else
1.14      cgd       209: tprintf(tpr, fmt, va_alist)
1.12      cgd       210:        tpr_t tpr;
                    211:        char *fmt;
1.20      christos  212:        va_dcl
1.12      cgd       213: #endif
                    214: {
                    215:        register struct session *sess = (struct session *)tpr;
                    216:        struct tty *tp = NULL;
                    217:        int flags = TOLOG;
                    218:        va_list ap;
                    219:
                    220:        logpri(LOG_INFO);
                    221:        if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
                    222:                flags |= TOTTY;
                    223:                tp = sess->s_ttyp;
                    224:        }
                    225:        va_start(ap, fmt);
1.30      christos  226:        kprintf(fmt, flags, tp, ap);
1.12      cgd       227:        va_end(ap);
                    228:        logwakeup();
                    229: }
                    230:
                    231: /*
                    232:  * Ttyprintf displays a message on a tty; it should be used only by
                    233:  * the tty driver, or anything that knows the underlying tty will not
                    234:  * be revoke(2)'d away.  Other callers should use tprintf.
                    235:  */
                    236: void
                    237: #ifdef __STDC__
                    238: ttyprintf(struct tty *tp, const char *fmt, ...)
                    239: #else
1.14      cgd       240: ttyprintf(tp, fmt, va_alist)
1.12      cgd       241:        struct tty *tp;
                    242:        char *fmt;
1.20      christos  243:        va_dcl
1.12      cgd       244: #endif
                    245: {
                    246:        va_list ap;
                    247:
                    248:        va_start(ap, fmt);
1.30      christos  249:        kprintf(fmt, TOTTY, tp, ap);
1.12      cgd       250:        va_end(ap);
                    251: }
                    252:
                    253: extern int log_open;
                    254:
                    255: /*
                    256:  * Log writes to the log buffer, and guarantees not to sleep (so can be
                    257:  * called by interrupt routines).  If there is no process reading the
                    258:  * log yet, it writes to the console also.
                    259:  */
                    260: void
                    261: #ifdef __STDC__
                    262: log(int level, const char *fmt, ...)
                    263: #else
1.14      cgd       264: log(level, fmt, va_alist)
1.12      cgd       265:        int level;
                    266:        char *fmt;
1.20      christos  267:        va_dcl
1.12      cgd       268: #endif
                    269: {
                    270:        register int s;
                    271:        va_list ap;
                    272:
                    273:        s = splhigh();
                    274:        logpri(level);
                    275:        va_start(ap, fmt);
1.30      christos  276:        kprintf(fmt, TOLOG, NULL, ap);
1.12      cgd       277:        splx(s);
                    278:        va_end(ap);
                    279:        if (!log_open) {
                    280:                va_start(ap, fmt);
1.30      christos  281:                kprintf(fmt, TOCONS, NULL, ap);
1.12      cgd       282:                va_end(ap);
                    283:        }
                    284:        logwakeup();
                    285: }
                    286:
1.13      mycroft   287: void
1.12      cgd       288: logpri(level)
                    289:        int level;
                    290: {
                    291:        register int ch;
                    292:        register char *p;
1.37    ! thorpej   293:        char snbuf[KSNPRINTN_BUFSIZE];
1.12      cgd       294:
                    295:        putchar('<', TOLOG, NULL);
1.37    ! thorpej   296:        for (p = ksnprintn((u_long)level, 10, NULL, snbuf, sizeof(snbuf));
        !           297:            (ch = *p--) != 0;)
1.12      cgd       298:                putchar(ch, TOLOG, NULL);
                    299:        putchar('>', TOLOG, NULL);
                    300: }
                    301:
                    302: void
                    303: #ifdef __STDC__
                    304: addlog(const char *fmt, ...)
                    305: #else
1.14      cgd       306: addlog(fmt, va_alist)
1.12      cgd       307:        char *fmt;
1.20      christos  308:        va_dcl
1.12      cgd       309: #endif
                    310: {
                    311:        register int s;
                    312:        va_list ap;
                    313:
                    314:        s = splhigh();
                    315:        va_start(ap, fmt);
1.30      christos  316:        kprintf(fmt, TOLOG, NULL, ap);
1.12      cgd       317:        splx(s);
                    318:        va_end(ap);
                    319:        if (!log_open) {
                    320:                va_start(ap, fmt);
1.30      christos  321:                kprintf(fmt, TOCONS, NULL, ap);
1.12      cgd       322:                va_end(ap);
                    323:        }
                    324:        logwakeup();
                    325: }
                    326:
                    327: void
                    328: #ifdef __STDC__
1.30      christos  329: printf(const char *fmt, ...)
1.12      cgd       330: #else
1.30      christos  331: printf(fmt, va_alist)
1.12      cgd       332:        char *fmt;
1.20      christos  333:        va_dcl
1.12      cgd       334: #endif
                    335: {
                    336:        va_list ap;
                    337:        register int savintr;
                    338:
                    339:        savintr = consintr;             /* disable interrupts */
                    340:        consintr = 0;
                    341:        va_start(ap, fmt);
1.30      christos  342:        kprintf(fmt, TOCONS | TOLOG, NULL, ap);
1.12      cgd       343:        va_end(ap);
                    344:        if (!panicstr)
                    345:                logwakeup();
                    346:        consintr = savintr;             /* reenable interrupts */
                    347: }
                    348:
                    349: /*
                    350:  * Scaled down version of printf(3).
                    351:  *
                    352:  * Two additional formats:
                    353:  *
                    354:  * The format %b is supported to decode error registers.
                    355:  * Its usage is:
                    356:  *
1.30      christos  357:  *     printf("reg=%b\n", regval, "<base><arg>*");
1.12      cgd       358:  *
                    359:  * where <base> is the output base expressed as a control character, e.g.
                    360:  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
                    361:  * the first of which gives the bit number to be inspected (origin 1), and
                    362:  * the next characters (up to a control character, i.e. a character <= 32),
                    363:  * give the name of the register.  Thus:
                    364:  *
1.30      christos  365:  *     kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
1.12      cgd       366:  *
                    367:  * would produce output:
                    368:  *
                    369:  *     reg=3<BITTWO,BITONE>
                    370:  *
1.24      christos  371:  * The format %: passes an additional format string and argument list
1.14      cgd       372:  * recursively.  Its usage is:
1.12      cgd       373:  *
1.14      cgd       374:  * fn(char *fmt, ...)
1.12      cgd       375:  * {
                    376:  *     va_list ap;
                    377:  *     va_start(ap, fmt);
1.30      christos  378:  *     printf("prefix: %: suffix\n", fmt, ap);
1.12      cgd       379:  *     va_end(ap);
1.14      cgd       380:  * }
1.12      cgd       381:  *
                    382:  * Space or zero padding and a field width are supported for the numeric
                    383:  * formats only.
                    384:  */
                    385: void
1.30      christos  386: kprintf(fmt, flags, tp, ap)
1.12      cgd       387:        register const char *fmt;
                    388:        int flags;
                    389:        struct tty *tp;
                    390:        va_list ap;
                    391: {
1.14      cgd       392:        register char *p, *q;
1.12      cgd       393:        register int ch, n;
                    394:        u_long ul;
                    395:        int base, lflag, tmp, width;
1.37    ! thorpej   396:        char padc, snbuf[KSNPRINTN_BUFSIZE];
1.12      cgd       397:
                    398:        for (;;) {
                    399:                padc = ' ';
                    400:                width = 0;
1.33      cgd       401:                while ((ch = *(const u_char *)fmt++) != '%') {
1.12      cgd       402:                        if (ch == '\0')
                    403:                                return;
                    404:                        putchar(ch, flags, tp);
                    405:                }
                    406:                lflag = 0;
1.33      cgd       407: reswitch:      switch (ch = *(const u_char *)fmt++) {
1.12      cgd       408:                case '0':
1.27      christos  409:                case '.':
1.12      cgd       410:                        padc = '0';
                    411:                        goto reswitch;
                    412:                case '1': case '2': case '3': case '4':
                    413:                case '5': case '6': case '7': case '8': case '9':
                    414:                        for (width = 0;; ++fmt) {
                    415:                                width = width * 10 + ch - '0';
                    416:                                ch = *fmt;
                    417:                                if (ch < '0' || ch > '9')
                    418:                                        break;
                    419:                        }
                    420:                        goto reswitch;
                    421:                case 'l':
                    422:                        lflag = 1;
                    423:                        goto reswitch;
                    424:                case 'b':
                    425:                        ul = va_arg(ap, int);
                    426:                        p = va_arg(ap, char *);
1.37    ! thorpej   427:                        for (q = ksnprintn(ul, *p++, NULL, snbuf,
        !           428:                            sizeof(snbuf)); (ch = *q--) != 0;)
1.12      cgd       429:                                putchar(ch, flags, tp);
                    430:
                    431:                        if (!ul)
                    432:                                break;
                    433:
1.20      christos  434:                        for (tmp = 0; (n = *p++) != 0;) {
1.12      cgd       435:                                if (ul & (1 << (n - 1))) {
                    436:                                        putchar(tmp ? ',' : '<', flags, tp);
                    437:                                        for (; (n = *p) > ' '; ++p)
                    438:                                                putchar(n, flags, tp);
                    439:                                        tmp = 1;
                    440:                                } else
1.14      cgd       441:                                        for (; *p > ' '; ++p)
                    442:                                                continue;
1.12      cgd       443:                        }
                    444:                        if (tmp)
                    445:                                putchar('>', flags, tp);
                    446:                        break;
                    447:                case 'c':
                    448:                        putchar(va_arg(ap, int), flags, tp);
                    449:                        break;
1.24      christos  450:                case ':':
1.12      cgd       451:                        p = va_arg(ap, char *);
1.30      christos  452:                        kprintf(p, flags, tp, va_arg(ap, va_list));
1.12      cgd       453:                        break;
                    454:                case 's':
1.16      mycroft   455:                        if ((p = va_arg(ap, char *)) == NULL)
                    456:                                p = "(null)";
1.20      christos  457:                        while ((ch = *p++) != 0)
1.12      cgd       458:                                putchar(ch, flags, tp);
                    459:                        break;
                    460:                case 'd':
                    461:                        ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
                    462:                        if ((long)ul < 0) {
                    463:                                putchar('-', flags, tp);
                    464:                                ul = -(long)ul;
                    465:                        }
                    466:                        base = 10;
                    467:                        goto number;
                    468:                case 'o':
                    469:                        ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
                    470:                        base = 8;
                    471:                        goto number;
                    472:                case 'u':
                    473:                        ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
                    474:                        base = 10;
                    475:                        goto number;
1.17      mycroft   476:                case 'p':
                    477:                        putchar('0', flags, tp);
                    478:                        putchar('x', flags, tp);
1.18      mycroft   479:                        ul = (u_long)va_arg(ap, void *);
                    480:                        base = 16;
                    481:                        goto number;
1.12      cgd       482:                case 'x':
                    483:                        ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
                    484:                        base = 16;
1.37    ! thorpej   485: number:                        p = ksnprintn(ul, base, &tmp, snbuf, sizeof(snbuf));
1.12      cgd       486:                        if (width && (width -= tmp) > 0)
                    487:                                while (width--)
                    488:                                        putchar(padc, flags, tp);
1.20      christos  489:                        while ((ch = *p--) != 0)
1.12      cgd       490:                                putchar(ch, flags, tp);
                    491:                        break;
                    492:                default:
                    493:                        putchar('%', flags, tp);
                    494:                        if (lflag)
                    495:                                putchar('l', flags, tp);
                    496:                        /* FALLTHROUGH */
                    497:                case '%':
                    498:                        putchar(ch, flags, tp);
                    499:                }
                    500:        }
                    501: }
                    502:
                    503: /*
                    504:  * Print a character on console or users terminal.  If destination is
                    505:  * the console then the last MSGBUFS characters are saved in msgbuf for
                    506:  * inspection later.
                    507:  */
                    508: static void
                    509: putchar(c, flags, tp)
                    510:        register int c;
                    511:        int flags;
                    512:        struct tty *tp;
                    513: {
1.14      cgd       514:        extern int msgbufmapped;
1.12      cgd       515:        register struct msgbuf *mbp;
                    516:
                    517:        if (panicstr)
                    518:                constty = NULL;
                    519:        if ((flags & TOCONS) && tp == NULL && constty) {
                    520:                tp = constty;
                    521:                flags |= TOTTY;
                    522:        }
                    523:        if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
                    524:            (flags & TOCONS) && tp == constty)
                    525:                constty = NULL;
                    526:        if ((flags & TOLOG) &&
                    527:            c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
                    528:                mbp = msgbufp;
                    529:                if (mbp->msg_magic != MSG_MAGIC) {
                    530:                        bzero((caddr_t)mbp, sizeof(*mbp));
                    531:                        mbp->msg_magic = MSG_MAGIC;
                    532:                }
                    533:                mbp->msg_bufc[mbp->msg_bufx++] = c;
                    534:                if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
                    535:                        mbp->msg_bufx = 0;
                    536:        }
                    537:        if ((flags & TOCONS) && constty == NULL && c != '\0')
                    538:                (*v_putc)(c);
                    539: }
                    540:
                    541: /*
                    542:  * Scaled down version of sprintf(3).
                    543:  */
1.20      christos  544: int
1.12      cgd       545: #ifdef __STDC__
1.30      christos  546: sprintf(char *buf, const char *cfmt, ...)
1.12      cgd       547: #else
1.30      christos  548: sprintf(buf, cfmt, va_alist)
1.34      gwr       549:        char *buf;
1.36      gwr       550:        const char *cfmt;
1.20      christos  551:        va_dcl
1.12      cgd       552: #endif
                    553: {
1.36      gwr       554:        register const char *fmt = cfmt;
1.12      cgd       555:        register char *p, *bp;
                    556:        register int ch, base;
                    557:        u_long ul;
1.19      cgd       558:        int lflag, tmp, width;
1.12      cgd       559:        va_list ap;
1.37    ! thorpej   560:        char padc, snbuf[KSNPRINTN_BUFSIZE];
1.12      cgd       561:
                    562:        va_start(ap, cfmt);
                    563:        for (bp = buf; ; ) {
1.19      cgd       564:                padc = ' ';
                    565:                width = 0;
1.33      cgd       566:                while ((ch = *(const u_char *)fmt++) != '%')
1.12      cgd       567:                        if ((*bp++ = ch) == '\0')
                    568:                                return ((bp - buf) - 1);
                    569:
                    570:                lflag = 0;
1.33      cgd       571: reswitch:      switch (ch = *(const u_char *)fmt++) {
1.19      cgd       572:                case '0':
                    573:                        padc = '0';
                    574:                        goto reswitch;
                    575:                case '1': case '2': case '3': case '4':
                    576:                case '5': case '6': case '7': case '8': case '9':
                    577:                        for (width = 0;; ++fmt) {
                    578:                                width = width * 10 + ch - '0';
                    579:                                ch = *fmt;
                    580:                                if (ch < '0' || ch > '9')
                    581:                                        break;
                    582:                        }
                    583:                        goto reswitch;
1.12      cgd       584:                case 'l':
                    585:                        lflag = 1;
                    586:                        goto reswitch;
1.19      cgd       587:                /* case 'b': ... break; XXX */
1.12      cgd       588:                case 'c':
                    589:                        *bp++ = va_arg(ap, int);
                    590:                        break;
1.19      cgd       591:                /* case 'r': ... break; XXX */
1.12      cgd       592:                case 's':
                    593:                        p = va_arg(ap, char *);
1.20      christos  594:                        while ((*bp++ = *p++) != 0)
1.14      cgd       595:                                continue;
1.12      cgd       596:                        --bp;
                    597:                        break;
                    598:                case 'd':
                    599:                        ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
                    600:                        if ((long)ul < 0) {
                    601:                                *bp++ = '-';
                    602:                                ul = -(long)ul;
                    603:                        }
                    604:                        base = 10;
                    605:                        goto number;
                    606:                        break;
                    607:                case 'o':
                    608:                        ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
                    609:                        base = 8;
                    610:                        goto number;
                    611:                        break;
                    612:                case 'u':
                    613:                        ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
                    614:                        base = 10;
                    615:                        goto number;
                    616:                        break;
1.19      cgd       617:                case 'p':
                    618:                        *bp++ = '0';
                    619:                        *bp++ = 'x';
                    620:                        ul = (u_long)va_arg(ap, void *);
                    621:                        base = 16;
                    622:                        goto number;
1.12      cgd       623:                case 'x':
                    624:                        ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
                    625:                        base = 16;
1.37    ! thorpej   626: number:                        p = ksnprintn(ul, base, &tmp, snbuf, sizeof(snbuf));
1.19      cgd       627:                        if (width && (width -= tmp) > 0)
                    628:                                while (width--)
                    629:                                        *bp++ = padc;
1.20      christos  630:                        while ((ch = *p--) != 0)
1.12      cgd       631:                                *bp++ = ch;
                    632:                        break;
                    633:                default:
                    634:                        *bp++ = '%';
                    635:                        if (lflag)
                    636:                                *bp++ = 'l';
                    637:                        /* FALLTHROUGH */
                    638:                case '%':
                    639:                        *bp++ = ch;
                    640:                }
                    641:        }
                    642:        va_end(ap);
                    643: }
                    644:
                    645: /*
                    646:  * Put a number (base <= 16) in a buffer in reverse order; return an
                    647:  * optional length and a pointer to the NULL terminated (preceded?)
                    648:  * buffer.
                    649:  */
                    650: static char *
1.37    ! thorpej   651: ksnprintn(ul, base, lenp, buf, buflen)
1.12      cgd       652:        register u_long ul;
                    653:        register int base, *lenp;
1.37    ! thorpej   654:        char *buf;
        !           655:        size_t buflen;
        !           656: {
1.12      cgd       657:        register char *p;
                    658:
                    659:        p = buf;
1.37    ! thorpej   660:        *p = '\0';                      /* ensure NULL `termination' */
        !           661:
        !           662:        /*
        !           663:         * Don't even bother of the buffer's not big enough.  No
        !           664:         * value at all is better than a wrong value, and we
        !           665:         * have a lot of control over the buffer that's passed
        !           666:         * to this function, since it's not exported.
        !           667:         */
        !           668:        if (buflen < KSNPRINTN_BUFSIZE)
        !           669:                return (p);
        !           670:
1.12      cgd       671:        do {
                    672:                *++p = "0123456789abcdef"[ul % base];
                    673:        } while (ul /= base);
                    674:        if (lenp)
                    675:                *lenp = p - buf;
                    676:        return (p);
1.37    ! thorpej   677: }
        !           678:
        !           679: /*
        !           680:  * Print a bitmask into the provided buffer, and return a pointer
        !           681:  * to that buffer.
        !           682:  */
        !           683: char *
        !           684: bitmask_snprintf(ul, p, buf, buflen)
        !           685:        u_long ul;
        !           686:        const char *p;
        !           687:        char *buf;
        !           688:        size_t buflen;
        !           689: {
        !           690:        char *bp, *q;
        !           691:        size_t left;
        !           692:        register int n;
        !           693:        int ch, tmp;
        !           694:        char snbuf[KSNPRINTN_BUFSIZE];
        !           695:
        !           696:        bp = buf;
        !           697:        bzero(buf, buflen);
        !           698:
        !           699:        /*
        !           700:         * Always leave room for the trailing NULL.
        !           701:         */
        !           702:        left = buflen - 1;
        !           703:
        !           704:        /*
        !           705:         * Print the value into the buffer.  Abort if there's not
        !           706:         * enough room.
        !           707:         */
        !           708:        if (buflen < KSNPRINTN_BUFSIZE)
        !           709:                return (buf);
        !           710:
        !           711:        for (q = ksnprintn(ul, *p++, NULL, snbuf, sizeof(snbuf));
        !           712:            (ch = *q--) != 0;) {
        !           713:                *bp++ = ch;
        !           714:                left--;
        !           715:        }
        !           716:
        !           717:        /*
        !           718:         * If the value we printed was 0, or if we don't have room for
        !           719:         * "<x>", we're done.
        !           720:         */
        !           721:        if (ul == 0 || left < 3)
        !           722:                return (buf);
        !           723:
        !           724: #define PUTBYTE(b, c, l)       \
        !           725:        *(b)++ = (c);           \
        !           726:        if (--(l) == 0)         \
        !           727:                goto out;
        !           728:
        !           729:        for (tmp = 0; (n = *p++) != 0;) {
        !           730:                if (ul & (1 << (n - 1))) {
        !           731:                        PUTBYTE(bp, tmp ? ',' : '<', left);
        !           732:                                for (; (n = *p) > ' '; ++p) {
        !           733:                                        PUTBYTE(bp, n, left);
        !           734:                                }
        !           735:                                tmp = 1;
        !           736:                } else
        !           737:                        for (; *p > ' '; ++p)
        !           738:                                continue;
        !           739:        }
        !           740:        if (tmp)
        !           741:                *bp = '>';
        !           742:
        !           743: #undef PUTBYTE
        !           744:
        !           745:  out:
        !           746:        return (buf);
1.12      cgd       747: }

CVSweb <webmaster@jp.NetBSD.org>