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