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: }