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

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

unix.superglobalmegacorp.com

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