Annotation of 43BSDTahoe/ucb/ex/printf.c, revision 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.