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: #if !defined(lint) && defined(DOSCCS) 8: static char *sccsid = "@(#)printf.c 7.3 (Berkeley) 6/7/85"; 9: 10: /* The pwb version this is based on */ 11: static char *printf_id = "@(#) printf.c:2.2 6/5/79"; 12: #endif 13: 14: #include "varargs.h" 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: 24: #define MAXOCT 11 /* Maximum octal digits in a long */ 25: #define MAXINT 32767 /* largest normal length positive integer */ 26: #define BIG 1000000000 /* largest power of 10 less than an unsigned long */ 27: #define MAXDIGS 10 /* number of digits in BIG */ 28: 29: static int width, sign, fill; 30: 31: char *_p_dconv(); 32: 33: 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: 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: putchar('0'); 185: 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: 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: putchar(cfill); 343: 344: /* emit the string itself */ 345: while (--alen >= 0) 346: putchar(*s++); 347: 348: /* emit trailing pad characters */ 349: if (sign) 350: while (--npad >= 0) 351: putchar(cfill); 352: }