Annotation of XNU/bsd/kern/subr_prf.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
                     23: /*-
                     24:  * Copyright (c) 1986, 1988, 1991, 1993
                     25:  *     The Regents of the University of California.  All rights reserved.
                     26:  * (c) UNIX System Laboratories, Inc.
                     27:  * All or some portions of this file are derived from material licensed
                     28:  * to the University of California by American Telephone and Telegraph
                     29:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     30:  * the permission of UNIX System Laboratories, Inc.
                     31:  *
                     32:  * Redistribution and use in source and binary forms, with or without
                     33:  * modification, are permitted provided that the following conditions
                     34:  * are met:
                     35:  * 1. Redistributions of source code must retain the above copyright
                     36:  *    notice, this list of conditions and the following disclaimer.
                     37:  * 2. Redistributions in binary form must reproduce the above copyright
                     38:  *    notice, this list of conditions and the following disclaimer in the
                     39:  *    documentation and/or other materials provided with the distribution.
                     40:  * 3. All advertising materials mentioning features or use of this software
                     41:  *    must display the following acknowledgement:
                     42:  *     This product includes software developed by the University of
                     43:  *     California, Berkeley and its contributors.
                     44:  * 4. Neither the name of the University nor the names of its contributors
                     45:  *    may be used to endorse or promote products derived from this software
                     46:  *    without specific prior written permission.
                     47:  *
                     48:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     49:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     50:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     51:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     52:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     53:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     54:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     55:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     56:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     57:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     58:  * SUCH DAMAGE.
                     59:  *
                     60:  *     @(#)subr_prf.c  8.4 (Berkeley) 5/4/95
                     61:  */
                     62: /* HISTORY
                     63:  * 22-Sep-1997 Umesh Vaishampayan ([email protected])
                     64:  *     Cleaned up m68k crud. Fixed vlog() to do logpri() for ppc, too.
                     65:  *
                     66:  * 17-July-97  Umesh Vaishampayan ([email protected])
                     67:  *     Eliminated multiple definition of constty which is defined
                     68:  *     in bsd/dev/XXX/cons.c
                     69:  *
                     70:  * 26-MAR-1997 Umesh Vaishampayan ([email protected]
                     71:  *     Fixed tharshing format in many functions. Cleanup.
                     72:  * 
                     73:  * 17-Jun-1995 Mac Gillon (mgillon) at NeXT
                     74:  *     Purged old history
                     75:  *     New version based on 4.4 and NS3.3
                     76:  */
                     77: 
                     78: #include <sys/param.h>
                     79: #include <sys/systm.h>
                     80: #include <sys/buf.h>
                     81: #include <sys/conf.h>
                     82: #include <sys/reboot.h>
                     83: #include <sys/msgbuf.h>
                     84: #include <sys/proc.h>
                     85: #include <sys/ioctl.h>
                     86: #include <sys/tty.h>
                     87: #include <sys/file.h>
                     88: #include <sys/tprintf.h>
                     89: #include <sys/syslog.h>
                     90: #include <stdarg.h>
                     91: #include <sys/malloc.h>
                     92: #include <sys/lock.h>
                     93: #include <kern/parallel.h>
                     94: #import <sys/subr_prf.h>
                     95: 
                     96: #include <kern/cpu_number.h>   /* for cpu_number() */
                     97: #include <machine/spl.h>
                     98: #include <libkern/libkern.h>
                     99: 
                    100: struct snprintf_arg {
                    101:        char *str;
                    102:        size_t remain;
                    103: };
                    104: 
                    105: 
                    106: /*
                    107:  * In case console is off,
                    108:  * panicstr contains argument to last
                    109:  * call to panic.
                    110:  */
                    111: extern const char      *panicstr;
                    112: 
                    113: extern cnputc();                       /* standard console putc */
                    114: int    (*v_putc)() = cnputc;           /* routine to putc on virtual console */
                    115: 
                    116: extern struct tty cons;                /* standard console tty */
                    117: extern struct  tty *constty;           /* pointer to console "window" tty */
                    118: 
                    119: /*
                    120:  *     Record cpu that panic'd and lock around panic data
                    121:  */
                    122: 
                    123: static void puts(const char *s, int flags, struct tty *ttyp);
                    124: static void printn(u_long n, int b, int flags, struct tty *ttyp, int zf, int fld_size);
                    125: 
                    126: /* MP printf stuff */
                    127: decl_simple_lock_data(,printf_lock)
                    128: #if    NCPUS > 1
                    129: boolean_t new_printf_cpu_number;  /* do we need to output who we are */
                    130: #endif
                    131: 
                    132: extern void logwakeup();
                    133: extern void halt_cpu();
                    134: #if    NeXT
                    135: extern void mini_mon();
                    136: #endif /* NeXT */
                    137: extern boot();
                    138: int    putchar();
                    139: 
                    140: static void
                    141: snprintf_func(int ch, void *arg);
                    142: 
                    143: 
                    144: 
                    145: /*
                    146:  * Uprintf prints to the controlling terminal for the current process.
                    147:  * It may block if the tty queue is overfull.  No message is printed if
                    148:  * the queue does not clear in a reasonable time.
                    149:  */
                    150: void
                    151: uprintf(const char *fmt, ...)
                    152: {
                    153:        register struct proc *p = current_proc();
                    154:        va_list ap;
                    155: 
                    156:        unix_master();          /* sessions, sigh */
                    157:        if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
                    158:                va_start(ap, fmt);
                    159:                prf(fmt, ap, TOTTY, (struct tty *)p->p_session->s_ttyvp);
                    160:                va_end(ap);
                    161:        }
                    162:        unix_release();
                    163: }
                    164: 
                    165: tpr_t
                    166: tprintf_open(p)
                    167:        register struct proc *p;
                    168: {
                    169:        unix_master();          /* sessions, sigh */
                    170:        if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
                    171:                SESSHOLD(p->p_session);
                    172:                unix_release();
                    173:                return ((tpr_t) p->p_session);
                    174:        }
                    175:        unix_release();
                    176:        return ((tpr_t) NULL);
                    177: }
                    178: 
                    179: void
                    180: tprintf_close(sess)
                    181:        tpr_t sess;
                    182: {
                    183:        unix_master();          /* sessions, sigh */
                    184:        if (sess)
                    185:                SESSRELE((struct session *) sess);
                    186:        unix_release();
                    187: }
                    188: 
                    189: /*
                    190:  * tprintf prints on the controlling terminal associated
                    191:  * with the given session.
                    192:  */
                    193: void
                    194: tprintf(tpr_t tpr, const char *fmt, ...)
                    195: {
                    196:        register struct session *sess = (struct session *)tpr;
                    197:        struct tty *tp = NULL;
                    198:        int flags = TOLOG;
                    199:        va_list ap;
                    200: 
                    201:        logpri(LOG_INFO);
                    202:        unix_master();          /* sessions, sigh */
                    203:        if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
                    204:                flags |= TOTTY;
                    205:                tp = sess->s_ttyp;
                    206:        }
                    207:        if (tp != NULL) {
                    208:                va_start(ap, fmt);
                    209:                prf(fmt, ap, TOTTY, tp);
                    210:                va_end(ap);
                    211:        }
                    212:        unix_release();
                    213:        logwakeup();
                    214: }
                    215: 
                    216: /*
                    217:  * Ttyprintf displays a message on a tty; it should be used only by
                    218:  * the tty driver, or anything that knows the underlying tty will not
                    219:  * be revoke(2)'d away.  Other callers should use tprintf.
                    220:  */
                    221: void
                    222: ttyprintf(struct tty *tp, const char *fmt, ...)
                    223: {
                    224:        va_list ap;
                    225: 
                    226:        if (tp != NULL) {
                    227:                va_start(ap, fmt);
                    228:                prf(fmt, ap, TOTTY, tp);
                    229:                va_end(ap);
                    230:        }
                    231: }
                    232: 
                    233: extern int log_open;
                    234: 
                    235: 
                    236: void
                    237: logpri(level)
                    238:        int level;
                    239: {
                    240: 
                    241:        putchar('<', TOLOG, (struct tty *)0);
                    242:        printn((u_long)level, 10, TOLOG, (struct tty *)0, 0, 0);
                    243:        putchar('>', TOLOG, (struct tty *)0);
                    244: }
                    245: 
                    246: void
                    247: addlog(const char *fmt, ...)
                    248: {
                    249:        register s = splhigh();
                    250:        va_list ap;
                    251: 
                    252:        va_start(ap, fmt);
                    253:        prf(fmt, ap, TOLOG, (struct tty *)0);
                    254:        splx(s);
                    255:        if (!log_open)
                    256:                prf(fmt, ap, TOCONS, (struct tty *)0);
                    257:        va_end(ap);
                    258:        logwakeup();
                    259: }
                    260: void _printf(int flags, struct tty *ttyp, const char *format, ...)
                    261: {
                    262:        va_list ap;
                    263:        
                    264:        va_start(ap, format);
                    265:        prf(format, ap, flags, ttyp);
                    266:        va_end(ap);
                    267: }
                    268: 
                    269: int prf(const char *fmt, va_list ap, int flags, struct tty *ttyp)
                    270: {
                    271:        register int b, c, i;
                    272:        char *s;
                    273:        int any;
                    274:        int zf = 0, fld_size;
                    275:        
                    276: #if    NCPUS > 1
                    277:        int cpun = cpu_number();
                    278: 
                    279:        if(ttyp == 0) {
                    280:                simple_lock(&printf_lock);
                    281:        } else
                    282:                TTY_LOCK(ttyp);
                    283:                
                    284:        if (cpun != master_cpu)
                    285:                new_printf_cpu_number = TRUE;
                    286: 
                    287:        if (new_printf_cpu_number) {
                    288:                putchar('{', flags, ttyp);
                    289:                printn((u_long)cpun, 10, flags, ttyp, 0, 0);
                    290:                putchar('}', flags, ttyp);
                    291:        }
                    292: #endif /* NCPUS > 1 */ 
                    293: loop:
                    294:        while ((c = *fmt++) != '%') {
                    295:                if (c == '\0') {
                    296: #if    NCPUS > 1
                    297:                        if(ttyp == 0) {
                    298:                                simple_unlock(&printf_lock);
                    299:                        } else
                    300:                                TTY_UNLOCK(ttyp);
                    301: #endif
                    302:                        return 0;
                    303:                }
                    304:                putchar(c, flags, ttyp);
                    305:        }
                    306: again:
                    307:        zf = 0;
                    308:        fld_size = 0;
                    309:        c = *fmt++;
                    310:        if (c == '0')
                    311:                zf = '0';
                    312:        fld_size = 0;
                    313:        for (;c <= '9' && c >= '0'; c = *fmt++)
                    314:                fld_size = fld_size * 10 + c - '0';
                    315:        
                    316:        /* THIS CODE IS VAX DEPENDENT IN HANDLING %l? AND %c */
                    317:        switch (c) {
                    318: 
                    319:        case 'l':
                    320:                goto again;
                    321:        case 'x': case 'X':
                    322:                b = 16;
                    323:                goto number;
                    324:        case 'd': case 'D':
                    325:        case 'u':               /* what a joke */
                    326:                b = 10;
                    327:                goto number;
                    328:        case 'o': case 'O':
                    329:                b = 8;
                    330: number:
                    331:                printn(va_arg(ap, unsigned), b, flags, ttyp, zf, fld_size);
                    332:                break;
                    333:        case 'c':
                    334:                b = va_arg(ap, unsigned);
                    335: #if BYTE_ORDER == LITTLE_ENDIAN
                    336:                for (i = 24; i >= 0; i -= 8)
                    337:                        if (c = (b >> i) & 0x7f)
                    338:                                putchar(c, flags, ttyp);
                    339: #endif
                    340: #if BYTE_ORDER == BIG_ENDIAN
                    341:                if ((c = (b & 0x7f)))
                    342:                        putchar(c, flags, ttyp);
                    343: #endif
                    344:                break;
                    345:        case 'b':
                    346:                b = va_arg(ap, unsigned);
                    347:                s = va_arg(ap, char *);
                    348:                printn((u_long)b, *s++, flags, ttyp, 0, 0);
                    349:                any = 0;
                    350:                if (b) {
                    351:                        while ((i = *s++)) {
                    352:                                if (*s <= 32) {
                    353:                                        register int j;
                    354: 
                    355:                                        if (any++)
                    356:                                                putchar(',', flags, ttyp);
                    357:                                        j = *s++ ;
                    358:                                        for (; (c = *s) > 32 ; s++)
                    359:                                                putchar(c, flags, ttyp);
                    360:                                        printn( (u_long)( (b >> (j-1)) &
                    361:                                                         ( (2 << (i-j)) -1)),
                    362:                                                 8, flags, ttyp, 0, 0);
                    363:                                } else if (b & (1 << (i-1))) {
                    364:                                        putchar(any? ',' : '<', flags, ttyp);
                    365:                                        any = 1;
                    366:                                        for (; (c = *s) > 32; s++)
                    367:                                                putchar(c, flags, ttyp);
                    368:                                } else
                    369:                                        for (; *s > 32; s++)
                    370:                                                ;
                    371:                        }
                    372:                        putchar('>', flags, ttyp);
                    373:                }
                    374:                break;
                    375: 
                    376:        case 's':
                    377:                s = va_arg(ap, char *);
                    378: #ifdef DEBUG
                    379:                if (fld_size) {
                    380:                        while (fld_size-- > 0)
                    381:                                putchar((c = *s++)? c : '_', flags, ttyp);
                    382:                } else {
                    383:                        while ((c = *s++))
                    384:                                putchar(c, flags, ttyp);
                    385:                }
                    386: #else  
                    387:                while (c = *s++)
                    388:                        putchar(c, flags, ttyp);
                    389: #endif
                    390:                break;
                    391: 
                    392:        case '%':
                    393:                putchar('%', flags, ttyp);
                    394:                goto loop;
                    395:        case 'C':
                    396:                b = va_arg(ap, unsigned);
                    397: #if BYTE_ORDER == LITTLE_ENDIAN
                    398:                for (i = 24; i >= 0; i -= 8)
                    399:                        if (c = (b >> i) & 0x7f)
                    400:                                putchar(c, flags, ttyp);
                    401: #endif
                    402: #if BYTE_ORDER == BIG_ENDIAN
                    403:                if ((c = (b & 0x7f)))
                    404:                        putchar(c, flags, ttyp);
                    405: #endif
                    406: 
                    407:        case 'r':
                    408:        case 'R':
                    409:                b = va_arg(ap, unsigned);
                    410:                s = va_arg(ap, char *);
                    411:                if (c == 'R') {
                    412:                        puts("0x", flags, ttyp);
                    413:                        printn((u_long)b, 16, flags, ttyp, 0, 0);
                    414:                }
                    415:                any = 0;
                    416:                if (c == 'r' || b) {
                    417:                        register struct reg_desc *rd;
                    418:                        register struct reg_values *rv;
                    419:                        unsigned field;
                    420: 
                    421:                        putchar('<', flags, ttyp);
                    422:                        for (rd = (struct reg_desc *)s; rd->rd_mask; rd++) {
                    423:                                field = b & rd->rd_mask;
                    424:                                field = (rd->rd_shift > 0)
                    425:                                    ? field << rd->rd_shift
                    426:                                    : field >> -rd->rd_shift;
                    427:                                if (any &&
                    428:                                      (rd->rd_format || rd->rd_values
                    429:                                         || (rd->rd_name && field)
                    430:                                      )
                    431:                                )
                    432:                                        putchar(',', flags, ttyp);
                    433:                                if (rd->rd_name) {
                    434:                                        if (rd->rd_format || rd->rd_values
                    435:                                            || field) {
                    436:                                                puts(rd->rd_name, flags, ttyp);
                    437:                                                any = 1;
                    438:                                        }
                    439:                                        if (rd->rd_format || rd->rd_values) {
                    440:                                                putchar('=', flags, ttyp);
                    441:                                                any = 1;
                    442:                                        }
                    443:                                }
                    444:                                if (rd->rd_format) {
                    445:                                        _printf(flags, ttyp, rd->rd_format,
                    446:                                          field);
                    447:                                        any = 1;
                    448:                                        if (rd->rd_values)
                    449:                                                putchar(':', flags, ttyp);
                    450:                                }
                    451:                                if (rd->rd_values) {
                    452:                                        any = 1;
                    453:                                        for (rv = rd->rd_values;
                    454:                                            rv->rv_name;
                    455:                                            rv++) {
                    456:                                                if (field == rv->rv_value) {
                    457:                                                        puts(rv->rv_name, flags,
                    458:                                                            ttyp);
                    459:                                                        break;
                    460:                                                }
                    461:                                        }
                    462:                                        if (rv->rv_name == NULL)
                    463:                                                puts("???", flags, ttyp);
                    464:                                }
                    465:                        }
                    466:                        putchar('>', flags, ttyp);
                    467:                }
                    468:                break;
                    469: 
                    470:        case 'n':
                    471:        case 'N':
                    472:                {
                    473:                        register struct reg_values *rv;
                    474: 
                    475:                        b = va_arg(ap, unsigned);
                    476:                        s = va_arg(ap,char *);
                    477:                        for (rv = (struct reg_values *)s; rv->rv_name; rv++) {
                    478:                                if (b == rv->rv_value) {
                    479:                                        puts(rv->rv_name, flags, ttyp);
                    480:                                        break;
                    481:                                }
                    482:                        }
                    483:                        if (rv->rv_name == NULL)
                    484:                                puts("???", flags, ttyp);
                    485:                        if (c == 'N' || rv->rv_name == NULL) {
                    486:                                putchar(':', flags, ttyp);
                    487:                                printn((u_long)b, 10, flags, ttyp, 0, 0);
                    488:                        }
                    489:                }
                    490:                break;
                    491:        }
                    492:        goto loop;
                    493: }
                    494: 
                    495: static void puts(const char *s, int flags, struct tty *ttyp)
                    496: {
                    497:        register char c;
                    498: 
                    499:        while ((c = *s++))
                    500:                putchar(c, flags, ttyp);
                    501: }
                    502: 
                    503: /*
                    504:  * Printn prints a number n in base b.
                    505:  * We don't use recursion to avoid deep kernel stacks.
                    506:  */
                    507: static void printn(u_long n, int b, int flags, struct tty *ttyp, int zf, int fld_size)
                    508: {
                    509:        char prbuf[11];
                    510:        register char *cp;
                    511: 
                    512:        if (b == 10 && (int)n < 0) {
                    513:                putchar('-', flags, ttyp);
                    514:                n = (unsigned)(-(int)n);
                    515:        }
                    516:        cp = prbuf;
                    517:        do {
                    518:                *cp++ = "0123456789abcdef"[n%b];
                    519:                n /= b;
                    520:        } while (n);
                    521:        if (fld_size) {
                    522:                for (fld_size -= cp - prbuf; fld_size > 0; fld_size--)
                    523:                        if (zf)
                    524:                                putchar('0', flags, ttyp);
                    525:                        else
                    526:                                putchar(' ', flags, ttyp);
                    527:        }
                    528:        do
                    529:                putchar(*--cp, flags, ttyp);
                    530:        while (cp > prbuf);
                    531: }
                    532: 
                    533: 
                    534: 
                    535: /*
                    536:  * Warn that a system table is full.
                    537:  */
                    538: void tablefull(const char *tab)
                    539: {
                    540:        log(LOG_ERR, "%s: table is full\n", tab);
                    541: }
                    542: 
                    543: /*
                    544:  * Print a character on console or users terminal.
                    545:  * If destination is console then the last MSGBUFS characters
                    546:  * are saved in msgbuf for inspection later.
                    547:  */
                    548: /*ARGSUSED*/
                    549: int
                    550: putchar(c, flags, tp)
                    551:        register int c;
                    552:        struct tty *tp;
                    553: {
                    554:        register struct msgbuf *mbp;
                    555:        char **sp = (char**) tp;
                    556: 
                    557:        if (panicstr)
                    558:                constty = 0;
                    559:        if ((flags & TOCONS) && tp == NULL && constty) {
                    560:                tp = constty;
                    561:                flags |= TOTTY;
                    562:        }
                    563:        if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
                    564:            (flags & TOCONS) && tp == constty)
                    565:                constty = 0;
                    566:        if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177)
                    567:                log_putc(c);
                    568:        if ((flags & TOCONS) && constty == 0 && c != '\0')
                    569:                (*v_putc)(c);
                    570:        if (flags & TOSTR) {
                    571:                **sp = c;
                    572:                (*sp)++;
                    573:        }
                    574:        return 0;
                    575: }
                    576: 
                    577: 
                    578: 
                    579: /*
                    580:  * Scaled down version of vsprintf(3).
                    581:  */
                    582: int
                    583: vsprintf(char *buf, const char *cfmt, va_list ap)
                    584: {
                    585:        int retval;
                    586: 
                    587:        retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
                    588:        buf[retval] = '\0';
                    589:        return retval;
                    590: }
                    591: 
                    592: /*
                    593:  * Scaled down version of snprintf(3).
                    594:  */
                    595: int
                    596: snprintf(char *str, size_t size, const char *format, ...)
                    597: {
                    598:        int retval;
                    599:        va_list ap;
                    600: 
                    601:        va_start(ap, format);
                    602:        retval = vsnprintf(str, size, format, ap);
                    603:        va_end(ap);
                    604:        return(retval);
                    605: }
                    606: 
                    607: /*
                    608:  * Scaled down version of vsnprintf(3).
                    609:  */
                    610: int
                    611: vsnprintf(char *str, size_t size, const char *format, va_list ap)
                    612: {
                    613:        struct snprintf_arg info;
                    614:        int retval;
                    615: 
                    616:        info.str = str;
                    617:        info.remain = size;
                    618:        retval = kvprintf(format, snprintf_func, &info, 10, ap);
                    619:        if (info.remain >= 1)
                    620:                *info.str++ = '\0';
                    621:        return retval;
                    622: }
                    623: 
                    624: static void
                    625: snprintf_func(int ch, void *arg)
                    626: {
                    627:        struct snprintf_arg *const info = arg;
                    628: 
                    629:        if (info->remain >= 2) {
                    630:                *info->str++ = ch;
                    631:                info->remain--;
                    632:        }
                    633: }
                    634: 
                    635: /*
                    636:  * Put a number (base <= 16) in a buffer in reverse order; return an
                    637:  * optional length and a pointer to the NULL terminated (preceded?)
                    638:  * buffer.
                    639:  */
                    640: static char *
                    641: ksprintn(ul, base, lenp)
                    642:        register u_long ul;
                    643:        register int base, *lenp;
                    644: {                                      /* A long in base 8, plus NULL. */
                    645:        static char buf[sizeof(long) * NBBY / 3 + 2];
                    646:        register char *p;
                    647: 
                    648:        p = buf;
                    649:        do {
                    650:                *++p = hex2ascii(ul % base);
                    651:        } while (ul /= base);
                    652:        if (lenp)
                    653:                *lenp = p - buf;
                    654:        return (p);
                    655: }
                    656: 
                    657: /*
                    658:  * Scaled down version of printf(3).
                    659:  *
                    660:  * Two additional formats:
                    661:  *
                    662:  * The format %b is supported to decode error registers.
                    663:  * Its usage is:
                    664:  *
                    665:  *     printf("reg=%b\n", regval, "<base><arg>*");
                    666:  *
                    667:  * where <base> is the output base expressed as a control character, e.g.
                    668:  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
                    669:  * the first of which gives the bit number to be inspected (origin 1), and
                    670:  * the next characters (up to a control character, i.e. a character <= 32),
                    671:  * give the name of the register.  Thus:
                    672:  *
                    673:  *     kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
                    674:  *
                    675:  * would produce output:
                    676:  *
                    677:  *     reg=3<BITTWO,BITONE>
                    678:  *
                    679:  * XXX:  %D  -- Hexdump, takes pointer and separator string:
                    680:  *             ("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
                    681:  *             ("%*D", len, ptr, " " -> XX XX XX XX ...
                    682:  */
                    683: int
                    684: kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
                    685: {
                    686: #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
                    687:        char *p, *q, *d;
                    688:        u_char *up;
                    689:        int ch, n;
                    690:        u_long ul;
                    691:        int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
                    692:        int dwidth;
                    693:        char padc;
                    694:        int retval = 0;
                    695: 
                    696:        if (!func)
                    697:                d = (char *) arg;
                    698:        else
                    699:                d = NULL;
                    700: 
                    701:        if (fmt == NULL)
                    702:                fmt = "(fmt null)\n";
                    703: 
                    704:        if (radix < 2 || radix > 36)
                    705:                radix = 10;
                    706: 
                    707:        for (;;) {
                    708:                padc = ' ';
                    709:                width = 0;
                    710:                while ((ch = (u_char)*fmt++) != '%') {
                    711:                        if (ch == '\0') 
                    712:                                return retval;
                    713:                        PCHAR(ch);
                    714:                }
                    715:                lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
                    716:                sign = 0; dot = 0; dwidth = 0;
                    717: reswitch:      switch (ch = (u_char)*fmt++) {
                    718:                case '.':
                    719:                        dot = 1;
                    720:                        goto reswitch;
                    721:                case '#':
                    722:                        sharpflag = 1;
                    723:                        goto reswitch;
                    724:                case '+':
                    725:                        sign = 1;
                    726:                        goto reswitch;
                    727:                case '-':
                    728:                        ladjust = 1;
                    729:                        goto reswitch;
                    730:                case '%':
                    731:                        PCHAR(ch);
                    732:                        break;
                    733:                case '*':
                    734:                        if (!dot) {
                    735:                                width = va_arg(ap, int);
                    736:                                if (width < 0) {
                    737:                                        ladjust = !ladjust;
                    738:                                        width = -width;
                    739:                                }
                    740:                        } else {
                    741:                                dwidth = va_arg(ap, int);
                    742:                        }
                    743:                        goto reswitch;
                    744:                case '0':
                    745:                        if (!dot) {
                    746:                                padc = '0';
                    747:                                goto reswitch;
                    748:                        }
                    749:                case '1': case '2': case '3': case '4':
                    750:                case '5': case '6': case '7': case '8': case '9':
                    751:                                for (n = 0;; ++fmt) {
                    752:                                        n = n * 10 + ch - '0';
                    753:                                        ch = *fmt;
                    754:                                        if (ch < '0' || ch > '9')
                    755:                                                break;
                    756:                                }
                    757:                        if (dot)
                    758:                                dwidth = n;
                    759:                        else
                    760:                                width = n;
                    761:                        goto reswitch;
                    762:                case 'b':
                    763:                        ul = va_arg(ap, int);
                    764:                        p = va_arg(ap, char *);
                    765:                        for (q = ksprintn(ul, *p++, NULL); *q;)
                    766:                                PCHAR(*q--);
                    767: 
                    768:                        if (!ul)
                    769:                                break;
                    770: 
                    771:                        for (tmp = 0; *p;) {
                    772:                                n = *p++;
                    773:                                if (ul & (1 << (n - 1))) {
                    774:                                        PCHAR(tmp ? ',' : '<');
                    775:                                        for (; (n = *p) > ' '; ++p)
                    776:                                                PCHAR(n);
                    777:                                        tmp = 1;
                    778:                                } else
                    779:                                        for (; *p > ' '; ++p)
                    780:                                                continue;
                    781:                        }
                    782:                        if (tmp)
                    783:                                PCHAR('>');
                    784:                        break;
                    785:                case 'c':
                    786:                        PCHAR(va_arg(ap, int));
                    787:                        break;
                    788:                case 'D':
                    789:                        up = va_arg(ap, u_char *);
                    790:                        p = va_arg(ap, char *);
                    791:                        if (!width)
                    792:                                width = 16;
                    793:                        while(width--) {
                    794:                                PCHAR(hex2ascii(*up >> 4));
                    795:                                PCHAR(hex2ascii(*up & 0x0f));
                    796:                                up++;
                    797:                                if (width)
                    798:                                        for (q=p;*q;q++)
                    799:                                                PCHAR(*q);
                    800:                        }
                    801:                        break;
                    802:                case 'd':
                    803:                        ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
                    804:                        sign = 1;
                    805:                        base = 10;
                    806:                        goto number;
                    807:                case 'l':
                    808:                        lflag = 1;
                    809:                        goto reswitch;
                    810:                case 'o':
                    811:                        ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
                    812:                        base = 8;
                    813:                        goto nosign;
                    814:                case 'p':
                    815:                        ul = (uintptr_t)va_arg(ap, void *);
                    816:                        base = 16;
                    817:                        sharpflag = (width == 0);
                    818:                        goto nosign;
                    819:                case 'n':
                    820:                case 'r':
                    821:                        ul = lflag ? va_arg(ap, u_long) :
                    822:                            sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int);
                    823:                        base = radix;
                    824:                        goto number;
                    825:                case 's':
                    826:                        p = va_arg(ap, char *);
                    827:                        if (p == NULL)
                    828:                                p = "(null)";
                    829:                        if (!dot)
                    830:                                n = strlen (p);
                    831:                        else
                    832:                                for (n = 0; n < dwidth && p[n]; n++)
                    833:                                        continue;
                    834: 
                    835:                        width -= n;
                    836: 
                    837:                        if (!ladjust && width > 0)
                    838:                                while (width--)
                    839:                                        PCHAR(padc);
                    840:                        while (n--)
                    841:                                PCHAR(*p++);
                    842:                        if (ladjust && width > 0)
                    843:                                while (width--)
                    844:                                        PCHAR(padc);
                    845:                        break;
                    846:                case 'u':
                    847:                        ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
                    848:                        base = 10;
                    849:                        goto nosign;
                    850:                case 'x':
                    851:                        ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
                    852:                        base = 16;
                    853:                        goto nosign;
                    854:                case 'z':
                    855:                        ul = lflag ? va_arg(ap, u_long) :
                    856:                            sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int);
                    857:                        base = 16;
                    858:                        goto number;
                    859: nosign:                        sign = 0;
                    860: number:                        if (sign && (long)ul < 0L) {
                    861:                                neg = 1;
                    862:                                ul = -(long)ul;
                    863:                        }
                    864:                        p = ksprintn(ul, base, &tmp);
                    865:                        if (sharpflag && ul != 0) {
                    866:                                if (base == 8)
                    867:                                        tmp++;
                    868:                                else if (base == 16)
                    869:                                        tmp += 2;
                    870:                        }
                    871:                        if (neg)
                    872:                                tmp++;
                    873: 
                    874:                        if (!ladjust && width && (width -= tmp) > 0)
                    875:                                while (width--)
                    876:                                        PCHAR(padc);
                    877:                        if (neg)
                    878:                                PCHAR('-');
                    879:                        if (sharpflag && ul != 0) {
                    880:                                if (base == 8) {
                    881:                                        PCHAR('0');
                    882:                                } else if (base == 16) {
                    883:                                        PCHAR('0');
                    884:                                        PCHAR('x');
                    885:                                }
                    886:                        }
                    887: 
                    888:                        while (*p)
                    889:                                PCHAR(*p--);
                    890: 
                    891:                        if (ladjust && width && (width -= tmp) > 0)
                    892:                                while (width--)
                    893:                                        PCHAR(padc);
                    894: 
                    895:                        break;
                    896:                default:
                    897:                        PCHAR('%');
                    898:                        if (lflag)
                    899:                                PCHAR('l');
                    900:                        PCHAR(ch);
                    901:                        break;
                    902:                }
                    903:        }
                    904: #undef PCHAR
                    905: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.