Annotation of Gnu-Mach/kern/printf.c, revision 1.1.1.3

1.1       root        1: /* 
                      2:  * Mach Operating System
                      3:  * Copyright (c) 1993 Carnegie Mellon University
                      4:  * All Rights Reserved.
                      5:  * 
                      6:  * Permission to use, copy, modify and distribute this software and its
                      7:  * documentation is hereby granted, provided that both the copyright
                      8:  * notice and this permission notice appear in all copies of the
                      9:  * software, derivative works or modified versions, and any portions
                     10:  * thereof, and that both notices appear in supporting documentation.
                     11:  * 
                     12:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     13:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     14:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     15:  * 
                     16:  * Carnegie Mellon requests users of this software to return to
                     17:  * 
                     18:  *  Software Distribution Coordinator  or  [email protected]
                     19:  *  School of Computer Science
                     20:  *  Carnegie Mellon University
                     21:  *  Pittsburgh PA 15213-3890
                     22:  * 
                     23:  * any improvements or extensions that they make and grant Carnegie Mellon
                     24:  * the rights to redistribute these changes.
                     25:  */
                     26: /*
                     27:  *  Common code for printf et al.
                     28:  *
                     29:  *  The calling routine typically takes a variable number of arguments,
                     30:  *  and passes the address of the first one.  This implementation
                     31:  *  assumes a straightforward, stack implementation, aligned to the
                     32:  *  machine's wordsize.  Increasing addresses are assumed to point to
                     33:  *  successive arguments (left-to-right), as is the case for a machine
                     34:  *  with a downward-growing stack with arguments pushed right-to-left.
                     35:  *
                     36:  *  To write, for example, fprintf() using this routine, the code
                     37:  *
                     38:  *     fprintf(fd, format, args)
                     39:  *     FILE *fd;
                     40:  *     char *format;
                     41:  *     {
1.1.1.3 ! root       42:  *     va_list listp;
        !            43:  *     va_start(listp, fmt);
1.1       root       44:  *     _doprnt(format, &args, fd);
1.1.1.3 ! root       45:  *     va_end(listp);
1.1       root       46:  *     }
                     47:  *
                     48:  *  would suffice.  (This example does not handle the fprintf's "return
                     49:  *  value" correctly, but who looks at the return value of fprintf
                     50:  *  anyway?)
                     51:  *
                     52:  *  This version implements the following printf features:
                     53:  *
                     54:  *     %d      decimal conversion
                     55:  *     %u      unsigned conversion
1.1.1.3 ! root       56:  *     %p      pointer address
1.1       root       57:  *     %x      hexadecimal conversion
                     58:  *     %X      hexadecimal conversion with capital letters
                     59:  *     %o      octal conversion
                     60:  *     %c      character
                     61:  *     %s      string
                     62:  *     %m.n    field width, precision
                     63:  *     %-m.n   left adjustment
                     64:  *     %0m.n   zero-padding
                     65:  *     %*.*    width and precision taken from arguments
                     66:  *
                     67:  *  This version does not implement %f, %e, or %g.  It accepts, but
                     68:  *  ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
                     69:  *  work correctly on machines for which sizeof(long) != sizeof(int).
                     70:  *  It does not even parse %D, %O, or %U; you should be using %ld, %o and
                     71:  *  %lu if you mean long conversion.
                     72:  *
                     73:  *  As mentioned, this version does not return any reasonable value.
                     74:  *
                     75:  *  Permission is granted to use, modify, or propagate this code as
                     76:  *  long as this notice is incorporated.
                     77:  *
                     78:  *  Steve Summit 3/25/87
                     79:  */
                     80: 
                     81: /*
                     82:  * Added formats for decoding device registers:
                     83:  *
                     84:  * printf("reg = %b", regval, "<base><arg>*")
                     85:  *
                     86:  * where <base> is the output base expressed as a control character:
                     87:  * i.e. '\10' gives octal, '\20' gives hex.  Each <arg> is a sequence of
                     88:  * characters, the first of which gives the bit number to be inspected
                     89:  * (origin 1), and the rest (up to a control character (<= 32)) give the
                     90:  * name of the register.  Thus
                     91:  *     printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE")
                     92:  * would produce
                     93:  *     reg = 3<BITTWO,BITONE>
                     94:  *
                     95:  * If the second character in <arg> is also a control character, it
                     96:  * indicates the last bit of a bit field.  In this case, printf will extract
                     97:  * bits <1> to <2> and print it.  Characters following the second control
                     98:  * character are printed before the bit field.
                     99:  *     printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE")
                    100:  * would produce
                    101:  *     reg = b<FIELD1=2,BITONE>
                    102:  */
                    103: /*
                    104:  * Added for general use:
                    105:  *     #       prefix for alternate format:
                    106:  *             0x (0X) for hex
                    107:  *             leading 0 for octal
                    108:  *     +       print '+' if positive
                    109:  *     blank   print ' ' if positive
                    110:  *
                    111:  *     z       signed hexadecimal
                    112:  *     r       signed, 'radix'
                    113:  *     n       unsigned, 'radix'
                    114:  *
                    115:  *     D,U,O,Z same as corresponding lower-case versions
                    116:  *             (compatibility)
                    117:  */
                    118: 
1.1.1.3 ! root      119: #include <string.h>
        !           120: #include <device/cons.h>
        !           121: #include <kern/printf.h>
1.1       root      122: #include <mach/boolean.h>
                    123: #include <kern/lock.h>
1.1.1.2   root      124: #include <stdarg.h>
1.1       root      125: 
                    126: #define isdigit(d) ((d) >= '0' && (d) <= '9')
                    127: #define Ctod(c) ((c) - '0')
                    128: 
                    129: #define MAXBUF (sizeof(long int) * 8)           /* enough for binary */
                    130: 
                    131: 
                    132: void printnum(
                    133:        register unsigned long  u,
                    134:        register int            base,
                    135:        void                    (*putc)( char, vm_offset_t ),
                    136:        vm_offset_t             putc_arg)
                    137: {
                    138:        char    buf[MAXBUF];    /* build number here */
                    139:        register char * p = &buf[MAXBUF-1];
                    140:        static char digs[] = "0123456789abcdef";
                    141: 
                    142:        do {
                    143:            *p-- = digs[u % base];
                    144:            u /= base;
                    145:        } while (u != 0);
                    146: 
                    147:        while (++p != &buf[MAXBUF])
                    148:            (*putc)(*p, putc_arg);
                    149: 
                    150: }
                    151: 
                    152: boolean_t      _doprnt_truncates = FALSE;
                    153: 
                    154: /* printf could be called at _any_ point during system initialization,
                    155:    including before printf_init() gets called from the "normal" place
                    156:    in kern/startup.c.  */
                    157: boolean_t      _doprnt_lock_initialized = FALSE;
                    158: decl_simple_lock_data(,_doprnt_lock)
                    159: 
1.1.1.3 ! root      160: void printf_init(void)
1.1       root      161: {
                    162:        if (!_doprnt_lock_initialized)
                    163:        {
                    164:                _doprnt_lock_initialized = TRUE;
                    165:                simple_lock_init(&_doprnt_lock);
                    166:        }
                    167: }
                    168: 
                    169: void _doprnt(
1.1.1.2   root      170:        register const char *fmt,
1.1.1.3 ! root      171:        va_list         argp,
1.1       root      172:                                        /* character output routine */
                    173:        void            (*putc)( char, vm_offset_t),
                    174:        int             radix,          /* default radix - for '%r' */
                    175:        vm_offset_t     putc_arg)
                    176: {
                    177:        int             length;
                    178:        int             prec;
                    179:        boolean_t       ladjust;
                    180:        char            padc;
                    181:        long            n;
                    182:        unsigned long   u;
                    183:        int             plus_sign;
                    184:        int             sign_char;
                    185:        boolean_t       altfmt, truncate;
                    186:        int             base;
                    187:        register char   c;
                    188: 
                    189:        printf_init();
                    190: 
                    191: #if 0
                    192:        /* Make sure that we get *some* printout, no matter what */
                    193:        simple_lock(&_doprnt_lock);
                    194: #else
                    195:        {
                    196:                register int i = 0;
                    197:                while (i < 1*1024*1024) {
                    198:                        if (simple_lock_try(&_doprnt_lock))
                    199:                                break;
                    200:                        i++;
                    201:                }
                    202:        }
                    203: #endif
                    204: 
                    205:        while ((c = *fmt) != '\0') {
                    206:            if (c != '%') {
                    207:                (*putc)(c, putc_arg);
                    208:                fmt++;
                    209:                continue;
                    210:            }
                    211: 
                    212:            fmt++;
                    213: 
                    214:            length = 0;
                    215:            prec = -1;
                    216:            ladjust = FALSE;
                    217:            padc = ' ';
                    218:            plus_sign = 0;
                    219:            sign_char = 0;
                    220:            altfmt = FALSE;
                    221: 
                    222:            while (TRUE) {
                    223:                c = *fmt;
                    224:                if (c == '#') {
                    225:                    altfmt = TRUE;
                    226:                }
                    227:                else if (c == '-') {
                    228:                    ladjust = TRUE;
                    229:                }
                    230:                else if (c == '+') {
                    231:                    plus_sign = '+';
                    232:                }
                    233:                else if (c == ' ') {
                    234:                    if (plus_sign == 0)
                    235:                        plus_sign = ' ';
                    236:                }
                    237:                else
                    238:                    break;
                    239:                fmt++;
                    240:            }
                    241: 
                    242:            if (c == '0') {
                    243:                padc = '0';
                    244:                c = *++fmt;
                    245:            }
                    246: 
                    247:            if (isdigit(c)) {
                    248:                while(isdigit(c)) {
                    249:                    length = 10 * length + Ctod(c);
                    250:                    c = *++fmt;
                    251:                }
                    252:            }
                    253:            else if (c == '*') {
1.1.1.3 ! root      254:                length = va_arg(argp, int);
1.1       root      255:                c = *++fmt;
                    256:                if (length < 0) {
                    257:                    ladjust = !ladjust;
                    258:                    length = -length;
                    259:                }
                    260:            }
                    261: 
                    262:            if (c == '.') {
                    263:                c = *++fmt;
                    264:                if (isdigit(c)) {
                    265:                    prec = 0;
                    266:                    while(isdigit(c)) {
                    267:                        prec = 10 * prec + Ctod(c);
                    268:                        c = *++fmt;
                    269:                    }
                    270:                }
                    271:                else if (c == '*') {
1.1.1.3 ! root      272:                    prec = va_arg(argp, int);
1.1       root      273:                    c = *++fmt;
                    274:                }
                    275:            }
                    276: 
                    277:            if (c == 'l')
                    278:                c = *++fmt;     /* need it if sizeof(int) < sizeof(long) */
                    279: 
                    280:            truncate = FALSE;
                    281: 
                    282:            switch(c) {
                    283:                case 'b':
                    284:                case 'B':
                    285:                {
                    286:                    register char *p;
                    287:                    boolean_t     any;
                    288:                    register int  i;
                    289: 
1.1.1.3 ! root      290:                    u = va_arg(argp, unsigned long);
        !           291:                    p = va_arg(argp, char *);
1.1       root      292:                    base = *p++;
                    293:                    printnum(u, base, putc, putc_arg);
                    294: 
                    295:                    if (u == 0)
                    296:                        break;
                    297: 
                    298:                    any = FALSE;
1.1.1.3 ! root      299:                    while ((i = *p++)) {
1.1       root      300:                        /* NOTE: The '32' here is because ascii space */
                    301:                        if (*p <= 32) {
                    302:                            /*
                    303:                             * Bit field
                    304:                             */
                    305:                            register int j;
                    306:                            if (any)
                    307:                                (*putc)(',', putc_arg);
                    308:                            else {
                    309:                                (*putc)('<', putc_arg);
                    310:                                any = TRUE;
                    311:                            }
                    312:                            j = *p++;
                    313:                            for (; (c = *p) > 32; p++)
                    314:                                (*putc)(c, putc_arg);
                    315:                            printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
                    316:                                        base, putc, putc_arg);
                    317:                        }
                    318:                        else if (u & (1<<(i-1))) {
                    319:                            if (any)
                    320:                                (*putc)(',', putc_arg);
                    321:                            else {
                    322:                                (*putc)('<', putc_arg);
                    323:                                any = TRUE;
                    324:                            }
                    325:                            for (; (c = *p) > 32; p++)
                    326:                                (*putc)(c, putc_arg);
                    327:                        }
                    328:                        else {
                    329:                            for (; *p > 32; p++)
                    330:                                continue;
                    331:                        }
                    332:                    }
                    333:                    if (any)
                    334:                        (*putc)('>', putc_arg);
                    335:                    break;
                    336:                }
                    337: 
                    338:                case 'c':
1.1.1.3 ! root      339:                    c = va_arg(argp, int);
1.1       root      340:                    (*putc)(c, putc_arg);
                    341:                    break;
                    342: 
                    343:                case 's':
                    344:                {
                    345:                    register char *p;
                    346:                    register char *p2;
                    347: 
                    348:                    if (prec == -1)
                    349:                        prec = 0x7fffffff;      /* MAXINT */
                    350: 
1.1.1.3 ! root      351:                    p = va_arg(argp, char *);
1.1       root      352: 
                    353:                    if (p == (char *)0)
                    354:                        p = "";
                    355: 
                    356:                    if (length > 0 && !ladjust) {
                    357:                        n = 0;
                    358:                        p2 = p;
                    359: 
                    360:                        for (; *p != '\0' && n < prec; p++)
                    361:                            n++;
                    362: 
                    363:                        p = p2;
                    364: 
                    365:                        while (n < length) {
                    366:                            (*putc)(' ', putc_arg);
                    367:                            n++;
                    368:                        }
                    369:                    }
                    370: 
                    371:                    n = 0;
                    372: 
                    373:                    while (*p != '\0') {
                    374:                        if (++n > prec)
                    375:                            break;
                    376: 
                    377:                        (*putc)(*p++, putc_arg);
                    378:                    }
                    379: 
                    380:                    if (n < length && ladjust) {
                    381:                        while (n < length) {
                    382:                            (*putc)(' ', putc_arg);
                    383:                            n++;
                    384:                        }
                    385:                    }
                    386: 
                    387:                    break;
                    388:                }
                    389: 
                    390:                case 'o':
                    391:                    truncate = _doprnt_truncates;
                    392:                case 'O':
                    393:                    base = 8;
                    394:                    goto print_unsigned;
                    395: 
                    396:                case 'd':
                    397:                    truncate = _doprnt_truncates;
                    398:                case 'D':
                    399:                    base = 10;
                    400:                    goto print_signed;
                    401: 
                    402:                case 'u':
                    403:                    truncate = _doprnt_truncates;
                    404:                case 'U':
                    405:                    base = 10;
                    406:                    goto print_unsigned;
                    407: 
1.1.1.3 ! root      408:                case 'p':
1.1       root      409:                case 'x':
                    410:                    truncate = _doprnt_truncates;
                    411:                case 'X':
                    412:                    base = 16;
                    413:                    goto print_unsigned;
                    414: 
                    415:                case 'z':
                    416:                    truncate = _doprnt_truncates;
                    417:                case 'Z':
                    418:                    base = 16;
                    419:                    goto print_signed;
                    420: 
                    421:                case 'r':
                    422:                    truncate = _doprnt_truncates;
                    423:                case 'R':
                    424:                    base = radix;
                    425:                    goto print_signed;
                    426: 
                    427:                case 'n':
                    428:                    truncate = _doprnt_truncates;
                    429:                case 'N':
                    430:                    base = radix;
                    431:                    goto print_unsigned;
                    432: 
                    433:                print_signed:
1.1.1.3 ! root      434:                    n = va_arg(argp, long);
1.1       root      435:                    if (n >= 0) {
                    436:                        u = n;
                    437:                        sign_char = plus_sign;
                    438:                    }
                    439:                    else {
                    440:                        u = -n;
                    441:                        sign_char = '-';
                    442:                    }
                    443:                    goto print_num;
                    444: 
                    445:                print_unsigned:
1.1.1.3 ! root      446:                    u = va_arg(argp, unsigned long);
1.1       root      447:                    goto print_num;
                    448: 
                    449:                print_num:
                    450:                {
                    451:                    char        buf[MAXBUF];    /* build number here */
                    452:                    register char *     p = &buf[MAXBUF-1];
                    453:                    static char digits[] = "0123456789abcdef";
                    454:                    char *prefix = 0;
                    455: 
                    456:                    if (truncate) u = (long)((int)(u));
                    457: 
                    458:                    if (u != 0 && altfmt) {
                    459:                        if (base == 8)
                    460:                            prefix = "0";
                    461:                        else if (base == 16)
                    462:                            prefix = "0x";
                    463:                    }
                    464: 
                    465:                    do {
                    466:                        *p-- = digits[u % base];
                    467:                        u /= base;
                    468:                    } while (u != 0);
                    469: 
                    470:                    length -= (&buf[MAXBUF-1] - p);
                    471:                    if (sign_char)
                    472:                        length--;
                    473:                    if (prefix)
                    474:                        length -= strlen(prefix);
                    475: 
                    476:                    if (padc == ' ' && !ladjust) {
                    477:                        /* blank padding goes before prefix */
                    478:                        while (--length >= 0)
                    479:                            (*putc)(' ', putc_arg);
                    480:                    }
                    481:                    if (sign_char)
                    482:                        (*putc)(sign_char, putc_arg);
                    483:                    if (prefix)
                    484:                        while (*prefix)
                    485:                            (*putc)(*prefix++, putc_arg);
                    486:                    if (padc == '0') {
                    487:                        /* zero padding goes after sign and prefix */
                    488:                        while (--length >= 0)
                    489:                            (*putc)('0', putc_arg);
                    490:                    }
                    491:                    while (++p != &buf[MAXBUF])
                    492:                        (*putc)(*p, putc_arg);
                    493: 
                    494:                    if (ladjust) {
                    495:                        while (--length >= 0)
                    496:                            (*putc)(' ', putc_arg);
                    497:                    }
                    498:                    break;
                    499:                }
                    500: 
                    501:                case '\0':
                    502:                    fmt--;
                    503:                    break;
                    504: 
                    505:                default:
                    506:                    (*putc)(c, putc_arg);
                    507:            }
                    508:        fmt++;
                    509:        }
                    510: 
                    511:        simple_unlock(&_doprnt_lock);
                    512: }
                    513: 
                    514: /*
                    515:  * Printing (to console)
                    516:  */
                    517: 
1.1.1.3 ! root      518: int vprintf(const char *fmt, va_list listp)
1.1       root      519: {
1.1.1.3 ! root      520:        _doprnt(fmt, listp, (void (*)( char, vm_offset_t)) cnputc, 16, 0);
        !           521:        return 0;
1.1       root      522: }
                    523: 
                    524: /*VARARGS1*/
1.1.1.3 ! root      525: int printf(const char *fmt, ...)
1.1       root      526: {
                    527:        va_list listp;
1.1.1.2   root      528:        va_start(listp, fmt);
1.1       root      529:        vprintf(fmt, listp);
                    530:        va_end(listp);
1.1.1.3 ! root      531:        return 0;
1.1       root      532: }
                    533: 
                    534: int    indent = 0;
                    535: 
                    536: /*
                    537:  * Printing (to console) with indentation.
                    538:  */
                    539: /*VARARGS1*/
1.1.1.2   root      540: void iprintf(const char *fmt, ...)
1.1       root      541: {
                    542:        va_list listp;
                    543:        register int i;
                    544: 
                    545:        for (i = indent; i > 0; ){
                    546:            if (i >= 8) {
                    547:                printf("\t");
                    548:                i -= 8;
                    549:            }
                    550:            else {
                    551:                printf(" ");
                    552:                i--;
                    553:            }
                    554:        }
1.1.1.2   root      555:        va_start(listp, fmt);
1.1.1.3 ! root      556:        _doprnt(fmt, listp, (void (*)( char, vm_offset_t)) cnputc, 16, 0);
1.1       root      557:        va_end(listp);
                    558: }
                    559: 
                    560: /*
                    561:  * Printing to generic buffer
                    562:  * Returns #bytes printed.
                    563:  * Strings are zero-terminated.
                    564:  */
                    565: static void
                    566: sputc(
                    567:        char            c,
                    568:        vm_offset_t     arg)
                    569: {
                    570:        register char   **bufp = (char **) arg;
                    571:        register char   *p = *bufp;
                    572:        *p++ = c;
                    573:        *bufp = p;
                    574: }
                    575: 
                    576: int
1.1.1.2   root      577: sprintf(char *buf, const char *fmt, ...)
1.1       root      578: {
                    579:        va_list listp;
                    580:        char    *start = buf;
                    581: 
1.1.1.2   root      582:        va_start(listp, fmt);
1.1.1.3 ! root      583:        _doprnt(fmt, listp, sputc, 16, (vm_offset_t)&buf);
1.1       root      584:        va_end(listp);
                    585: 
                    586:        *buf = 0;
                    587:        return (buf - start);
                    588: }
                    589: 
1.1.1.3 ! root      590: struct vsnprintf_cookie
        !           591: {
        !           592:   char *buf;
        !           593:   int index;
        !           594:   int max_len;
        !           595: };
        !           596: 
        !           597: static void
        !           598: snputc(char c, vm_offset_t arg)
        !           599: {
        !           600:   struct vsnprintf_cookie *cookie = (void *) arg;
        !           601: 
        !           602:   if (cookie->index < cookie->max_len)
        !           603:     cookie->buf[cookie->index ++] = c;
        !           604: }
        !           605: 
        !           606: int
        !           607: vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
        !           608: {
        !           609:   struct vsnprintf_cookie cookie
        !           610:     = { .buf = buf, .index = 0, .max_len = size };
        !           611: 
        !           612:   _doprnt (fmt, args, snputc, 16, (vm_offset_t)&cookie);
        !           613:   cookie.buf[cookie.index] = '\0';
        !           614: 
        !           615:   return cookie.index;
        !           616: }
        !           617: 
1.1       root      618: 
                    619: void safe_gets(str, maxlen)
                    620:        char *str;
                    621:        int  maxlen;
                    622: {
                    623:        register char *lp;
                    624:        register int c;
                    625:        char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
                    626: 
                    627:        lp = str;
                    628:        for (;;) {
                    629:                c = cngetc();
                    630:                switch (c) {
                    631:                case '\n':
                    632:                case '\r':
                    633:                        printf("\n");
                    634:                        *lp++ = 0;
                    635:                        return;
                    636:                        
                    637:                case '\b':
                    638:                case '#':
                    639:                case '\177':
                    640:                        if (lp > str) {
                    641:                                printf("\b \b");
                    642:                                lp--;
                    643:                        }
                    644:                        continue;
                    645: 
                    646:                case '@':
                    647:                case 'u'&037:
                    648:                        lp = str;
                    649:                        printf("\n\r");
                    650:                        continue;
                    651: 
                    652:                default:
                    653:                        if (c >= ' ' && c < '\177') {
                    654:                                if (lp < strmax) {
                    655:                                        *lp++ = c;
                    656:                                        printf("%c", c);
                    657:                                }
                    658:                                else {
                    659:                                        printf("%c", '\007'); /* beep */
                    660:                                }
                    661:                        }
                    662:                }
                    663:        }
                    664: }

unix.superglobalmegacorp.com

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