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