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