|
|
1.1 ! root 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.4 (Berkeley) 3/9/87"; ! 9: /* The pwb version this is based on */ ! 10: static char *printf_id = "@(#) printf.c:2.2 6/5/79"; ! 11: #endif not lint ! 12: ! 13: #include <varargs.h> ! 14: ! 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: #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: /* VARARGS */ ! 33: ex_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: ex_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: ex_putchar('0'); ! 185: ex_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: ex_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: ex_putchar(cfill); ! 343: ! 344: /* emit the string itself */ ! 345: while (--alen >= 0) ! 346: ex_putchar(*s++); ! 347: ! 348: /* emit trailing pad characters */ ! 349: if (sign) ! 350: while (--npad >= 0) ! 351: ex_putchar(cfill); ! 352: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.