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

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: 
1.1.1.5 ! root      129: #define MAXBUF (sizeof(long long int) * 8)      /* enough for binary */
1.1       root      130: 
                    131: 
                    132: void printnum(
1.1.1.5 ! root      133:        unsigned long long      u,
1.1.1.4   root      134:        int                     base,
1.1       root      135:        void                    (*putc)( char, vm_offset_t ),
                    136:        vm_offset_t             putc_arg)
                    137: {
                    138:        char    buf[MAXBUF];    /* build number here */
1.1.1.4   root      139:        char *  p = &buf[MAXBUF-1];
1.1       root      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: void _doprnt(
1.1.1.4   root      155:        const char      *fmt,
1.1.1.3   root      156:        va_list         argp,
1.1       root      157:                                        /* character output routine */
                    158:        void            (*putc)( char, vm_offset_t),
                    159:        int             radix,          /* default radix - for '%r' */
                    160:        vm_offset_t     putc_arg)
                    161: {
                    162:        int             length;
                    163:        int             prec;
                    164:        boolean_t       ladjust;
                    165:        char            padc;
1.1.1.5 ! root      166:        long long       n;
        !           167:        unsigned long long      u;
        !           168:        int             have_long_long;
1.1       root      169:        int             plus_sign;
                    170:        int             sign_char;
                    171:        boolean_t       altfmt, truncate;
                    172:        int             base;
1.1.1.4   root      173:        char            c;
1.1       root      174: 
                    175:        while ((c = *fmt) != '\0') {
                    176:            if (c != '%') {
                    177:                (*putc)(c, putc_arg);
                    178:                fmt++;
                    179:                continue;
                    180:            }
                    181: 
                    182:            fmt++;
                    183: 
                    184:            length = 0;
                    185:            prec = -1;
                    186:            ladjust = FALSE;
                    187:            padc = ' ';
                    188:            plus_sign = 0;
                    189:            sign_char = 0;
                    190:            altfmt = FALSE;
1.1.1.5 ! root      191:            have_long_long = FALSE;
1.1       root      192: 
                    193:            while (TRUE) {
                    194:                c = *fmt;
                    195:                if (c == '#') {
                    196:                    altfmt = TRUE;
                    197:                }
                    198:                else if (c == '-') {
                    199:                    ladjust = TRUE;
                    200:                }
                    201:                else if (c == '+') {
                    202:                    plus_sign = '+';
                    203:                }
                    204:                else if (c == ' ') {
                    205:                    if (plus_sign == 0)
                    206:                        plus_sign = ' ';
                    207:                }
                    208:                else
                    209:                    break;
                    210:                fmt++;
                    211:            }
                    212: 
                    213:            if (c == '0') {
                    214:                padc = '0';
                    215:                c = *++fmt;
                    216:            }
                    217: 
                    218:            if (isdigit(c)) {
                    219:                while(isdigit(c)) {
                    220:                    length = 10 * length + Ctod(c);
                    221:                    c = *++fmt;
                    222:                }
                    223:            }
                    224:            else if (c == '*') {
1.1.1.3   root      225:                length = va_arg(argp, int);
1.1       root      226:                c = *++fmt;
                    227:                if (length < 0) {
                    228:                    ladjust = !ladjust;
                    229:                    length = -length;
                    230:                }
                    231:            }
                    232: 
                    233:            if (c == '.') {
                    234:                c = *++fmt;
                    235:                if (isdigit(c)) {
                    236:                    prec = 0;
                    237:                    while(isdigit(c)) {
                    238:                        prec = 10 * prec + Ctod(c);
                    239:                        c = *++fmt;
                    240:                    }
                    241:                }
                    242:                else if (c == '*') {
1.1.1.3   root      243:                    prec = va_arg(argp, int);
1.1       root      244:                    c = *++fmt;
                    245:                }
                    246:            }
                    247: 
                    248:            if (c == 'l')
                    249:                c = *++fmt;     /* need it if sizeof(int) < sizeof(long) */
1.1.1.5 ! root      250:            if (c == 'l') {
        !           251:                c = *++fmt;     /* handle `long long' */
        !           252:                have_long_long = TRUE;
        !           253:            }
1.1       root      254: 
                    255:            truncate = FALSE;
                    256: 
                    257:            switch(c) {
                    258:                case 'b':
                    259:                case 'B':
                    260:                {
1.1.1.4   root      261:                    char        *p;
                    262:                    boolean_t   any;
                    263:                    int         i;
1.1       root      264: 
1.1.1.5 ! root      265:                    if (! have_long_long)
        !           266:                      u = va_arg(argp, unsigned long);
        !           267:                    else
        !           268:                      u = va_arg(argp, unsigned long long);
1.1.1.3   root      269:                    p = va_arg(argp, char *);
1.1       root      270:                    base = *p++;
                    271:                    printnum(u, base, putc, putc_arg);
                    272: 
                    273:                    if (u == 0)
                    274:                        break;
                    275: 
                    276:                    any = FALSE;
1.1.1.3   root      277:                    while ((i = *p++)) {
1.1       root      278:                        /* NOTE: The '32' here is because ascii space */
                    279:                        if (*p <= 32) {
                    280:                            /*
                    281:                             * Bit field
                    282:                             */
1.1.1.4   root      283:                            int j;
1.1       root      284:                            if (any)
                    285:                                (*putc)(',', putc_arg);
                    286:                            else {
                    287:                                (*putc)('<', putc_arg);
                    288:                                any = TRUE;
                    289:                            }
                    290:                            j = *p++;
                    291:                            for (; (c = *p) > 32; p++)
                    292:                                (*putc)(c, putc_arg);
                    293:                            printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
                    294:                                        base, putc, putc_arg);
                    295:                        }
                    296:                        else if (u & (1<<(i-1))) {
                    297:                            if (any)
                    298:                                (*putc)(',', putc_arg);
                    299:                            else {
                    300:                                (*putc)('<', putc_arg);
                    301:                                any = TRUE;
                    302:                            }
                    303:                            for (; (c = *p) > 32; p++)
                    304:                                (*putc)(c, putc_arg);
                    305:                        }
                    306:                        else {
                    307:                            for (; *p > 32; p++)
                    308:                                continue;
                    309:                        }
                    310:                    }
                    311:                    if (any)
                    312:                        (*putc)('>', putc_arg);
                    313:                    break;
                    314:                }
                    315: 
                    316:                case 'c':
1.1.1.3   root      317:                    c = va_arg(argp, int);
1.1       root      318:                    (*putc)(c, putc_arg);
                    319:                    break;
                    320: 
                    321:                case 's':
                    322:                {
1.1.1.4   root      323:                    char *p;
                    324:                    char *p2;
1.1       root      325: 
                    326:                    if (prec == -1)
                    327:                        prec = 0x7fffffff;      /* MAXINT */
                    328: 
1.1.1.3   root      329:                    p = va_arg(argp, char *);
1.1       root      330: 
                    331:                    if (p == (char *)0)
                    332:                        p = "";
                    333: 
                    334:                    if (length > 0 && !ladjust) {
                    335:                        n = 0;
                    336:                        p2 = p;
                    337: 
                    338:                        for (; *p != '\0' && n < prec; p++)
                    339:                            n++;
                    340: 
                    341:                        p = p2;
                    342: 
                    343:                        while (n < length) {
                    344:                            (*putc)(' ', putc_arg);
                    345:                            n++;
                    346:                        }
                    347:                    }
                    348: 
                    349:                    n = 0;
                    350: 
                    351:                    while (*p != '\0') {
                    352:                        if (++n > prec)
                    353:                            break;
                    354: 
                    355:                        (*putc)(*p++, putc_arg);
                    356:                    }
                    357: 
                    358:                    if (n < length && ladjust) {
                    359:                        while (n < length) {
                    360:                            (*putc)(' ', putc_arg);
                    361:                            n++;
                    362:                        }
                    363:                    }
                    364: 
                    365:                    break;
                    366:                }
                    367: 
                    368:                case 'o':
                    369:                    truncate = _doprnt_truncates;
                    370:                case 'O':
                    371:                    base = 8;
                    372:                    goto print_unsigned;
                    373: 
                    374:                case 'd':
                    375:                    truncate = _doprnt_truncates;
                    376:                case 'D':
                    377:                    base = 10;
                    378:                    goto print_signed;
                    379: 
                    380:                case 'u':
                    381:                    truncate = _doprnt_truncates;
                    382:                case 'U':
                    383:                    base = 10;
                    384:                    goto print_unsigned;
                    385: 
1.1.1.3   root      386:                case 'p':
1.1       root      387:                case 'x':
                    388:                    truncate = _doprnt_truncates;
                    389:                case 'X':
                    390:                    base = 16;
                    391:                    goto print_unsigned;
                    392: 
                    393:                case 'z':
                    394:                    truncate = _doprnt_truncates;
                    395:                case 'Z':
                    396:                    base = 16;
                    397:                    goto print_signed;
                    398: 
                    399:                case 'r':
                    400:                    truncate = _doprnt_truncates;
                    401:                case 'R':
                    402:                    base = radix;
                    403:                    goto print_signed;
                    404: 
                    405:                case 'n':
                    406:                    truncate = _doprnt_truncates;
                    407:                case 'N':
                    408:                    base = radix;
                    409:                    goto print_unsigned;
                    410: 
                    411:                print_signed:
1.1.1.5 ! root      412:                    if (! have_long_long)
        !           413:                      n = va_arg(argp, long);
        !           414:                    else
        !           415:                      n = va_arg(argp, long long);
1.1       root      416:                    if (n >= 0) {
                    417:                        u = n;
                    418:                        sign_char = plus_sign;
                    419:                    }
                    420:                    else {
                    421:                        u = -n;
                    422:                        sign_char = '-';
                    423:                    }
                    424:                    goto print_num;
                    425: 
                    426:                print_unsigned:
1.1.1.5 ! root      427:                    if (! have_long_long)
        !           428:                      u = va_arg(argp, unsigned long);
        !           429:                    else
        !           430:                      u = va_arg(argp, unsigned long long);
1.1       root      431:                    goto print_num;
                    432: 
                    433:                print_num:
                    434:                {
                    435:                    char        buf[MAXBUF];    /* build number here */
1.1.1.4   root      436:                    char *      p = &buf[MAXBUF-1];
1.1       root      437:                    static char digits[] = "0123456789abcdef";
                    438:                    char *prefix = 0;
                    439: 
                    440:                    if (truncate) u = (long)((int)(u));
                    441: 
                    442:                    if (u != 0 && altfmt) {
                    443:                        if (base == 8)
                    444:                            prefix = "0";
                    445:                        else if (base == 16)
                    446:                            prefix = "0x";
                    447:                    }
                    448: 
                    449:                    do {
                    450:                        *p-- = digits[u % base];
                    451:                        u /= base;
                    452:                    } while (u != 0);
                    453: 
                    454:                    length -= (&buf[MAXBUF-1] - p);
                    455:                    if (sign_char)
                    456:                        length--;
                    457:                    if (prefix)
                    458:                        length -= strlen(prefix);
                    459: 
                    460:                    if (padc == ' ' && !ladjust) {
                    461:                        /* blank padding goes before prefix */
                    462:                        while (--length >= 0)
                    463:                            (*putc)(' ', putc_arg);
                    464:                    }
                    465:                    if (sign_char)
                    466:                        (*putc)(sign_char, putc_arg);
                    467:                    if (prefix)
                    468:                        while (*prefix)
                    469:                            (*putc)(*prefix++, putc_arg);
                    470:                    if (padc == '0') {
                    471:                        /* zero padding goes after sign and prefix */
                    472:                        while (--length >= 0)
                    473:                            (*putc)('0', putc_arg);
                    474:                    }
                    475:                    while (++p != &buf[MAXBUF])
                    476:                        (*putc)(*p, putc_arg);
                    477: 
                    478:                    if (ladjust) {
                    479:                        while (--length >= 0)
                    480:                            (*putc)(' ', putc_arg);
                    481:                    }
                    482:                    break;
                    483:                }
                    484: 
                    485:                case '\0':
                    486:                    fmt--;
                    487:                    break;
                    488: 
                    489:                default:
                    490:                    (*putc)(c, putc_arg);
                    491:            }
                    492:        fmt++;
                    493:        }
                    494: }
                    495: 
                    496: /*
                    497:  * Printing (to console)
                    498:  */
                    499: 
1.1.1.3   root      500: int vprintf(const char *fmt, va_list listp)
1.1       root      501: {
1.1.1.3   root      502:        _doprnt(fmt, listp, (void (*)( char, vm_offset_t)) cnputc, 16, 0);
                    503:        return 0;
1.1       root      504: }
                    505: 
                    506: /*VARARGS1*/
1.1.1.3   root      507: int printf(const char *fmt, ...)
1.1       root      508: {
                    509:        va_list listp;
1.1.1.2   root      510:        va_start(listp, fmt);
1.1       root      511:        vprintf(fmt, listp);
                    512:        va_end(listp);
1.1.1.3   root      513:        return 0;
1.1       root      514: }
                    515: 
                    516: int    indent = 0;
                    517: 
                    518: /*
                    519:  * Printing (to console) with indentation.
                    520:  */
                    521: /*VARARGS1*/
1.1.1.2   root      522: void iprintf(const char *fmt, ...)
1.1       root      523: {
                    524:        va_list listp;
1.1.1.4   root      525:        int i;
1.1       root      526: 
                    527:        for (i = indent; i > 0; ){
                    528:            if (i >= 8) {
                    529:                printf("\t");
                    530:                i -= 8;
                    531:            }
                    532:            else {
                    533:                printf(" ");
                    534:                i--;
                    535:            }
                    536:        }
1.1.1.2   root      537:        va_start(listp, fmt);
1.1.1.3   root      538:        _doprnt(fmt, listp, (void (*)( char, vm_offset_t)) cnputc, 16, 0);
1.1       root      539:        va_end(listp);
                    540: }
                    541: 
                    542: /*
                    543:  * Printing to generic buffer
                    544:  * Returns #bytes printed.
                    545:  * Strings are zero-terminated.
                    546:  */
                    547: static void
                    548: sputc(
                    549:        char            c,
                    550:        vm_offset_t     arg)
                    551: {
1.1.1.4   root      552:        char    **bufp = (char **) arg;
                    553:        char    *p = *bufp;
1.1       root      554:        *p++ = c;
                    555:        *bufp = p;
                    556: }
                    557: 
                    558: int
1.1.1.2   root      559: sprintf(char *buf, const char *fmt, ...)
1.1       root      560: {
                    561:        va_list listp;
                    562:        char    *start = buf;
                    563: 
1.1.1.2   root      564:        va_start(listp, fmt);
1.1.1.3   root      565:        _doprnt(fmt, listp, sputc, 16, (vm_offset_t)&buf);
1.1       root      566:        va_end(listp);
                    567: 
                    568:        *buf = 0;
                    569:        return (buf - start);
                    570: }
                    571: 
1.1.1.3   root      572: struct vsnprintf_cookie
                    573: {
                    574:   char *buf;
                    575:   int index;
                    576:   int max_len;
                    577: };
                    578: 
                    579: static void
                    580: snputc(char c, vm_offset_t arg)
                    581: {
                    582:   struct vsnprintf_cookie *cookie = (void *) arg;
                    583: 
                    584:   if (cookie->index < cookie->max_len)
                    585:     cookie->buf[cookie->index ++] = c;
                    586: }
                    587: 
                    588: int
                    589: vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                    590: {
                    591:   struct vsnprintf_cookie cookie
                    592:     = { .buf = buf, .index = 0, .max_len = size };
                    593: 
                    594:   _doprnt (fmt, args, snputc, 16, (vm_offset_t)&cookie);
                    595:   cookie.buf[cookie.index] = '\0';
                    596: 
                    597:   return cookie.index;
                    598: }
                    599: 
1.1.1.4   root      600: int
                    601: snprintf(char *buf, size_t size, const char *fmt, ...)
                    602: {
                    603:        int written;
                    604:        va_list listp;
                    605:        va_start(listp, fmt);
                    606:        written = vsnprintf(buf, size, fmt, listp);
                    607:        va_end(listp);
                    608:        return written;
                    609: }
1.1       root      610: 
1.1.1.4   root      611: void safe_gets(
                    612:        char *str,
                    613:        int  maxlen)
1.1       root      614: {
1.1.1.4   root      615:        char *lp;
                    616:        int c;
1.1       root      617:        char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
                    618: 
                    619:        lp = str;
                    620:        for (;;) {
                    621:                c = cngetc();
                    622:                switch (c) {
                    623:                case '\n':
                    624:                case '\r':
                    625:                        printf("\n");
                    626:                        *lp++ = 0;
                    627:                        return;
                    628:                        
                    629:                case '\b':
                    630:                case '#':
                    631:                case '\177':
                    632:                        if (lp > str) {
                    633:                                printf("\b \b");
                    634:                                lp--;
                    635:                        }
                    636:                        continue;
                    637: 
                    638:                case '@':
                    639:                case 'u'&037:
                    640:                        lp = str;
                    641:                        printf("\n\r");
                    642:                        continue;
                    643: 
                    644:                default:
                    645:                        if (c >= ' ' && c < '\177') {
                    646:                                if (lp < strmax) {
                    647:                                        *lp++ = c;
                    648:                                        printf("%c", c);
                    649:                                }
                    650:                                else {
                    651:                                        printf("%c", '\007'); /* beep */
                    652:                                }
                    653:                        }
                    654:                }
                    655:        }
                    656: }

unix.superglobalmegacorp.com

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