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