Annotation of 43BSDTahoe/ucb/ex/printf.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1980 Regents of the University of California.
                      3:  * All rights reserved.  The Berkeley software License Agreement
                      4:  * specifies the terms and conditions for redistribution.
                      5:  */
                      6: 
                      7: #ifndef lint
                      8: static char *sccsid = "@(#)printf.c    7.4 (Berkeley) 3/9/87";
                      9: /* The pwb version this is based on */
                     10: static char *printf_id = "@(#) printf.c:2.2 6/5/79";
                     11: #endif not lint
                     12: 
                     13: #include <varargs.h>
                     14:  
                     15: /*
                     16:  * This version of printf is compatible with the Version 7 C
                     17:  * printf. The differences are only minor except that this
                     18:  * printf assumes it is to print through putchar. Version 7
                     19:  * printf is more general (and is much larger) and includes
                     20:  * provisions for floating point.
                     21:  */
                     22: 
                     23: #define MAXOCT 11      /* Maximum octal digits in a long */
                     24: #define MAXINT 32767   /* largest normal length positive integer */
                     25: #define BIG    1000000000  /* largest power of 10 less than an unsigned long */
                     26: #define MAXDIGS        10      /* number of digits in BIG */
                     27: 
                     28: static int width, sign, fill;
                     29: 
                     30: char *_p_dconv();
                     31: 
                     32: /* VARARGS */
                     33: ex_printf(va_alist)
                     34:        va_dcl
                     35: {
                     36:        va_list ap;
                     37:        register char *fmt;
                     38:        char fcode;
                     39:        int prec;
                     40:        int length,mask1,nbits,n;
                     41:        long int mask2, num;
                     42:        register char *bptr;
                     43:        char *ptr;
                     44:        char buf[134];
                     45: 
                     46:        va_start(ap);
                     47:        fmt = va_arg(ap,char *);
                     48:        for (;;) {
                     49:                /* process format string first */
                     50:                while ((fcode = *fmt++)!='%') {
                     51:                        /* ordinary (non-%) character */
                     52:                        if (fcode=='\0')
                     53:                                return;
                     54:                        ex_putchar(fcode);
                     55:                }
                     56:                /* length modifier: -1 for h, 1 for l, 0 for none */
                     57:                length = 0;
                     58:                /* check for a leading - sign */
                     59:                sign = 0;
                     60:                if (*fmt == '-') {
                     61:                        sign++;
                     62:                        fmt++;
                     63:                }
                     64:                /* a '0' may follow the - sign */
                     65:                /* this is the requested fill character */
                     66:                fill = 1;
                     67:                if (*fmt == '0') {
                     68:                        fill--;
                     69:                        fmt++;
                     70:                }
                     71:                
                     72:                /* Now comes a digit string which may be a '*' */
                     73:                if (*fmt == '*') {
                     74:                        width = va_arg(ap, int);
                     75:                        if (width < 0) {
                     76:                                width = -width;
                     77:                                sign = !sign;
                     78:                        }
                     79:                        fmt++;
                     80:                }
                     81:                else {
                     82:                        width = 0;
                     83:                        while (*fmt>='0' && *fmt<='9')
                     84:                                width = width * 10 + (*fmt++ - '0');
                     85:                }
                     86:                
                     87:                /* maybe a decimal point followed by more digits (or '*') */
                     88:                if (*fmt=='.') {
                     89:                        if (*++fmt == '*') {
                     90:                                prec = va_arg(ap, int);
                     91:                                fmt++;
                     92:                        }
                     93:                        else {
                     94:                                prec = 0;
                     95:                                while (*fmt>='0' && *fmt<='9')
                     96:                                        prec = prec * 10 + (*fmt++ - '0');
                     97:                        }
                     98:                }
                     99:                else
                    100:                        prec = -1;
                    101:                
                    102:                /*
                    103:                 * At this point, "sign" is nonzero if there was
                    104:                 * a sign, "fill" is 0 if there was a leading
                    105:                 * zero and 1 otherwise, "width" and "prec"
                    106:                 * contain numbers corresponding to the digit
                    107:                 * strings before and after the decimal point,
                    108:                 * respectively, and "fmt" addresses the next
                    109:                 * character after the whole mess. If there was
                    110:                 * no decimal point, "prec" will be -1.
                    111:                 */
                    112:                switch (*fmt) {
                    113:                        case 'L':
                    114:                        case 'l':
                    115:                                length = 2;
                    116:                                /* no break!! */
                    117:                        case 'h':
                    118:                        case 'H':
                    119:                                length--;
                    120:                                fmt++;
                    121:                                break;
                    122:                }
                    123:                
                    124:                /*
                    125:                 * At exit from the following switch, we will
                    126:                 * emit the characters starting at "bptr" and
                    127:                 * ending at "ptr"-1, unless fcode is '\0'.
                    128:                 */
                    129:                switch (fcode = *fmt++) {
                    130:                        /* process characters and strings first */
                    131:                        case 'c':
                    132:                                buf[0] = va_arg(ap, int);
                    133:                                ptr = bptr = &buf[0];
                    134:                                if (buf[0] != '\0')
                    135:                                        ptr++;
                    136:                                break;
                    137:                        case 's':
                    138:                                bptr = va_arg(ap,char *);
                    139:                                if (bptr==0)
                    140:                                        bptr = "(null pointer)";
                    141:                                if (prec < 0)
                    142:                                        prec = MAXINT;
                    143:                                for (n=0; *bptr++ && n < prec; n++) ;
                    144:                                ptr = --bptr;
                    145:                                bptr -= n;
                    146:                                break;
                    147:                        case 'O':
                    148:                                length = 1;
                    149:                                fcode = 'o';
                    150:                                /* no break */
                    151:                        case 'o':
                    152:                        case 'X':
                    153:                        case 'x':
                    154:                                if (length > 0)
                    155:                                        num = va_arg(ap,long);
                    156:                                else
                    157:                                        num = (unsigned)va_arg(ap,int);
                    158:                                if (fcode=='o') {
                    159:                                        mask1 = 0x7;
                    160:                                        mask2 = 0x1fffffffL;
                    161:                                        nbits = 3;
                    162:                                }
                    163:                                else {
                    164:                                        mask1 = 0xf;
                    165:                                        mask2 = 0x0fffffffL;
                    166:                                        nbits = 4;
                    167:                                }
                    168:                                n = (num!=0);
                    169:                                bptr = buf + MAXOCT + 3;
                    170:                                /* shift and mask for speed */
                    171:                                do
                    172:                                    if (((int) num & mask1) < 10)
                    173:                                        *--bptr = ((int) num & mask1) + 060;
                    174:                                    else
                    175:                                        *--bptr = ((int) num & mask1) + 0127;
                    176:                                while (num = (num >> nbits) & mask2);
                    177:                                
                    178:                                if (fcode=='o') {
                    179:                                        if (n)
                    180:                                                *--bptr = '0';
                    181:                                }
                    182:                                else
                    183:                                        if (!sign && fill <= 0) {
                    184:                                                ex_putchar('0');
                    185:                                                ex_putchar(fcode);
                    186:                                                width -= 2;
                    187:                                        }
                    188:                                        else {
                    189:                                                *--bptr = fcode;
                    190:                                                *--bptr = '0';
                    191:                                        }
                    192:                                ptr = buf + MAXOCT + 3;
                    193:                                break;
                    194:                        case 'D':
                    195:                        case 'U':
                    196:                        case 'I':
                    197:                                length = 1;
                    198:                                fcode = fcode + 'a' - 'A';
                    199:                                /* no break */
                    200:                        case 'd':
                    201:                        case 'i':
                    202:                        case 'u':
                    203:                                if (length > 0)
                    204:                                        num = va_arg(ap,long);
                    205:                                else {
                    206:                                        n = va_arg(ap,int);
                    207:                                        if (fcode=='u')
                    208:                                                num = (unsigned) n;
                    209:                                        else
                    210:                                                num = (long) n;
                    211:                                }
                    212:                                if (n = (fcode != 'u' && num < 0))
                    213:                                        num = -num;
                    214:                                /* now convert to digits */
                    215:                                bptr = _p_dconv(num, buf);
                    216:                                if (n)
                    217:                                        *--bptr = '-';
                    218:                                if (fill == 0)
                    219:                                        fill = -1;
                    220:                                ptr = buf + MAXDIGS + 1;
                    221:                                break;
                    222:                        default:
                    223:                                /* not a control character, 
                    224:                                 * print it.
                    225:                                 */
                    226:                                ptr = bptr = &fcode;
                    227:                                ptr++;
                    228:                                break;
                    229:                        }
                    230:                        if (fcode != '\0')
                    231:                                _p_emit(bptr,ptr);
                    232:        }
                    233:        va_end(ap);
                    234: }
                    235: 
                    236: /* _p_dconv converts the unsigned long integer "value" to
                    237:  * printable decimal and places it in "buffer", right-justified.
                    238:  * The value returned is the address of the first non-zero character,
                    239:  * or the address of the last character if all are zero.
                    240:  * The result is NOT null terminated, and is MAXDIGS characters long,
                    241:  * starting at buffer[1] (to allow for insertion of a sign).
                    242:  *
                    243:  * This program assumes it is running on 2's complement machine
                    244:  * with reasonable overflow treatment.
                    245:  */
                    246: char *
                    247: _p_dconv(value, buffer)
                    248:        long value;
                    249:        char *buffer;
                    250: {
                    251:        register char *bp;
                    252:        register int svalue;
                    253:        int n;
                    254:        long lval;
                    255:        
                    256:        bp = buffer;
                    257:        
                    258:        /* zero is a special case */
                    259:        if (value == 0) {
                    260:                bp += MAXDIGS;
                    261:                *bp = '0';
                    262:                return(bp);
                    263:        }
                    264:        
                    265:        /* develop the leading digit of the value in "n" */
                    266:        n = 0;
                    267:        while (value < 0) {
                    268:                value -= BIG;   /* will eventually underflow */
                    269:                n++;
                    270:        }
                    271:        while ((lval = value - BIG) >= 0) {
                    272:                value = lval;
                    273:                n++;
                    274:        }
                    275:        
                    276:        /* stash it in buffer[1] to allow for a sign */
                    277:        bp[1] = n + '0';
                    278:        /*
                    279:         * Now develop the rest of the digits. Since speed counts here,
                    280:         * we do it in two loops. The first gets "value" down until it
                    281:         * is no larger than MAXINT. The second one uses integer divides
                    282:         * rather than long divides to speed it up.
                    283:         */
                    284:        bp += MAXDIGS + 1;
                    285:        while (value > MAXINT) {
                    286:                *--bp = (int)(value % 10) + '0';
                    287:                value /= 10;
                    288:        }
                    289:        
                    290:        /* cannot lose precision */
                    291:        svalue = value;
                    292:        while (svalue > 0) {
                    293:                *--bp = (svalue % 10) + '0';
                    294:                svalue /= 10;
                    295:        }
                    296:        
                    297:        /* fill in intermediate zeroes if needed */
                    298:        if (buffer[1] != '0') {
                    299:                while (bp > buffer + 2)
                    300:                        *--bp = '0';
                    301:                --bp;
                    302:        }
                    303:        return(bp);
                    304: }
                    305: 
                    306: /*
                    307:  * This program sends string "s" to putchar. The character after
                    308:  * the end of "s" is given by "send". This allows the size of the
                    309:  * field to be computed; it is stored in "alen". "width" contains the
                    310:  * user specified length. If width<alen, the width will be taken to
                    311:  * be alen. "sign" is zero if the string is to be right-justified
                    312:  * in the field, nonzero if it is to be left-justified. "fill" is
                    313:  * 0 if the string is to be padded with '0', positive if it is to be
                    314:  * padded with ' ', and negative if an initial '-' should appear before
                    315:  * any padding in right-justification (to avoid printing "-3" as
                    316:  * "000-3" where "-0003" was intended).
                    317:  */
                    318: _p_emit(s, send)
                    319:        register char *s;
                    320:        char *send;
                    321: {
                    322:        char cfill;
                    323:        register int alen;
                    324:        int npad;
                    325:        
                    326:        alen = send - s;
                    327:        if (alen > width)
                    328:                width = alen;
                    329:        cfill = fill>0? ' ': '0';
                    330:        
                    331:        /* we may want to print a leading '-' before anything */
                    332:        if (*s == '-' && fill < 0) {
                    333:                ex_putchar(*s++);
                    334:                alen--;
                    335:                width--;
                    336:        }
                    337:        npad = width - alen;
                    338:        
                    339:        /* emit any leading pad characters */
                    340:        if (!sign)
                    341:                while (--npad >= 0)
                    342:                        ex_putchar(cfill);
                    343:                        
                    344:        /* emit the string itself */
                    345:        while (--alen >= 0)
                    346:                ex_putchar(*s++);
                    347:                
                    348:        /* emit trailing pad characters */
                    349:        if (sign)
                    350:                while (--npad >= 0)
                    351:                        ex_putchar(cfill);
                    352: }

unix.superglobalmegacorp.com

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