|
|
1.1 ! root 1: /* ! 2: * Alas, doprnt is not documented, so people feel they have license to ! 3: * change the parameters. The 3B implementation does not even look ! 4: * callable from C, and without documentation is not comprehensible. ! 5: * Since many systems have their own doprnt which is written in assembly ! 6: * language, and thus faster, but callable from C, we try to use the ! 7: * standard system version where possible. The ifdefs below attempt ! 8: * to decide where it is possible - it may need to be updated later. ! 9: */ ! 10: ! 11: #ifdef u3b ! 12: #define NEEDDOPRNT ! 13: #endif ! 14: ! 15: #ifdef NEEDDOPRNT ! 16: /* @(#) doprnt.c: 1.1 10/15/83 (1.4 10/27/82) */ ! 17: /* @(#)doprnt.c 2.4 */ ! 18: /*LINTLIBRARY*/ ! 19: /* ! 20: * _doprnt: common code for printf, fprintf, sprintf ! 21: */ ! 22: ! 23: #include <stdio.h> ! 24: #include <ctype.h> ! 25: #include <varargs.h> ! 26: #include <values.h> ! 27: ! 28: /* @(#)print.h 1.3 */ ! 29: /* Maximum number of digits in any integer representation */ ! 30: #define MAXDIGS 11 ! 31: ! 32: /* Maximum total number of digits in E format */ ! 33: #define MAXECVT 17 ! 34: ! 35: /* Maximum number of digits after decimal point in F format */ ! 36: #define MAXFCVT 60 ! 37: ! 38: /* Maximum significant figures in a floating-point number */ ! 39: #define MAXFSIG 17 ! 40: ! 41: /* Maximum number of characters in an exponent */ ! 42: #if u3b ! 43: #define MAXESIZ 5 ! 44: #else ! 45: #define MAXESIZ 4 ! 46: #endif ! 47: ! 48: /* Maximum (positive) exponent */ ! 49: #if u3b ! 50: #define MAXEXP 310 ! 51: #else ! 52: #define MAXEXP 40 ! 53: #endif ! 54: ! 55: /* Data type for flags */ ! 56: typedef char bool; ! 57: ! 58: /* Convert a digit character to the corresponding number */ ! 59: #define tonumber(x) ((x)-'0') ! 60: ! 61: /* Convert a number between 0 and 9 to the corresponding digit */ ! 62: #define todigit(x) ((x)+'0') ! 63: ! 64: /* Max and Min macros */ ! 65: #define max(a,b) ((a) > (b)? (a): (b)) ! 66: #define min(a,b) ((a) < (b)? (a): (b)) ! 67: /* end of print.h */ ! 68: ! 69: static char * ! 70: memcpy(dest, src, n) ! 71: register char *dest, *src; ! 72: register int n; ! 73: { ! 74: register char *rv = dest; ! 75: ! 76: while (n--) ! 77: *dest++ = *src++; ! 78: return rv; ! 79: } ! 80: ! 81: #define PUT(p, n) if (n == 1) (void) putc(*p, iop); \ ! 82: else if (iop->_file == _NFILE) \ ! 83: iop->_ptr = (unsigned char *) \ ! 84: memcpy((char *)iop->_ptr, p, n) +n; \ ! 85: else (void) fwrite(p, 1, n, iop) ! 86: ! 87: /* ! 88: * C-Library routines for floating conversion ! 89: */ ! 90: extern char *fcvt(), *ecvt(); ! 91: ! 92: extern int strlen(), fwrite(); ! 93: ! 94: int ! 95: _doprnt(format, args, iop) ! 96: register char *format; ! 97: va_list args; ! 98: register FILE *iop; ! 99: { ! 100: /* This variable counts output characters. */ ! 101: int count = 0; ! 102: ! 103: /* Starting and ending points for value to be printed */ ! 104: register char *bp, *p; ! 105: ! 106: /* Field width and precision */ ! 107: int width, prec; ! 108: ! 109: /* Format code */ ! 110: register int fcode; ! 111: ! 112: /* Number of padding zeroes required on the left and right */ ! 113: int lzero, rzero; ! 114: ! 115: /* Flags - nonzero if corresponding character is in format */ ! 116: int length; /* l */ ! 117: int fplus; /* + */ ! 118: int fminus; /* - */ ! 119: int fblank; /* blank */ ! 120: int fsharp; /* # */ ! 121: ! 122: /* Values are developed in this buffer */ ! 123: char buf[max(MAXDIGS, 1+max(MAXFCVT+MAXEXP, MAXECVT))]; ! 124: ! 125: /* Pointer to sign, "0x", "0X", or empty */ ! 126: char *prefix; ! 127: ! 128: /* Exponent or empty */ ! 129: char *suffix; ! 130: ! 131: /* Buffer to create exponent */ ! 132: char expbuf[MAXESIZ + 1]; ! 133: ! 134: /* The value being converted, if integer */ ! 135: long val; ! 136: ! 137: /* The value being converted, if real */ ! 138: double dval; ! 139: ! 140: /* Output values from fcvt and ecvt */ ! 141: int decpt, sign; ! 142: ! 143: /* Pointer to a translate table for digits of whatever radix */ ! 144: char *tab; ! 145: ! 146: /* Work variables */ ! 147: int k, n, hradix, lowbit; ! 148: ! 149: expbuf[MAXESIZ] = '\0'; ! 150: ! 151: /* ! 152: * The main loop -- this loop goes through one iteration ! 153: * for each string of ordinary characters or format specification. ! 154: */ ! 155: for ( ; ; ) { ! 156: for (bp = format; ! 157: (fcode = *format) != '\0' && fcode != '%'; format++) ! 158: ; ! 159: if (n = format - bp) { /* ordinary non-% characters */ ! 160: count += n; ! 161: PUT(bp, n); ! 162: } ! 163: if (fcode == '\0') /* end of format; normal return */ ! 164: return (ferror(iop) ? EOF : count); ! 165: /* ! 166: * % has been found. ! 167: * First, parse the format specification. ! 168: */ ! 169: fplus = fminus = fblank = fsharp = lzero = 0; ! 170: for ( ; ; ) { /* Scan the <flags> */ ! 171: switch (fcode = *++format) { ! 172: case '+': ! 173: fplus++; ! 174: continue; ! 175: case '-': ! 176: fminus++; ! 177: continue; ! 178: case ' ': ! 179: fblank++; ! 180: continue; ! 181: case '#': ! 182: fsharp++; ! 183: continue; ! 184: } ! 185: break; ! 186: } ! 187: ! 188: /* Scan the field width */ ! 189: if (fcode == '*') { ! 190: width = va_arg(args, int); ! 191: if (width < 0) { ! 192: width = -width; ! 193: fminus++; ! 194: } ! 195: format++; ! 196: } else { ! 197: if (fcode == '0') /* obsolescent spec. */ ! 198: lzero++; /* pad with leading zeros */ ! 199: for (width = 0; isdigit(fcode = *format); format++) ! 200: width = width * 10 + tonumber(fcode); ! 201: } ! 202: ! 203: /* Scan the precision */ ! 204: if (*format != '.') ! 205: prec = lzero ? width : -1; ! 206: else if (*++format == '*') { /* '*' instead of digits? */ ! 207: prec = va_arg(args, int); ! 208: format++; ! 209: } else ! 210: for (prec = 0; isdigit(fcode = *format); format++) ! 211: prec = prec * 10 + tonumber(fcode); ! 212: ! 213: /* Scan the length modifier */ ! 214: length = 0; ! 215: switch (*format) { ! 216: case 'l': ! 217: length++; ! 218: /* No break */ ! 219: case 'h': ! 220: format++; ! 221: } ! 222: ! 223: /* ! 224: * The character addressed by format must be ! 225: * the format letter -- there is nothing ! 226: * left for it to be. ! 227: * ! 228: * The status of the +, -, #, and blank ! 229: * flags are reflected in the variables ! 230: * "fplus", "fminus", "fsharp", and ! 231: * "fblank". "width" and "prec" contain ! 232: * numbers corresponding to the digit ! 233: * strings before and after the decimal ! 234: * point, respectively. If there was no ! 235: * decimal point, "prec" is -1. ! 236: * ! 237: * The following switch sets things up ! 238: * for printing. What ultimately gets ! 239: * printed will be padding blanks, a ! 240: * prefix, left padding zeroes, a value, ! 241: * right padding zeroes, a suffix, and ! 242: * more padding blanks. Padding blanks ! 243: * will not appear simultaneously on both ! 244: * the left and the right. Each case in ! 245: * this switch will compute the value, and ! 246: * leave in several variables the informa- ! 247: * tion necessary to construct what is to ! 248: * be printed. ! 249: * ! 250: * The prefix is a sign, a blank, "0x", ! 251: * "0X", or null, and is addressed by ! 252: * "prefix". ! 253: * ! 254: * The suffix is either null or an ! 255: * exponent, and is addressed by "suffix". ! 256: * ! 257: * The value to be printed starts at "bp" ! 258: * and continues up to and not including ! 259: * "p". ! 260: * ! 261: * "lzero" and "rzero" will contain the ! 262: * number of padding zeroes required on ! 263: * the left and right, respectively. If ! 264: * either of these variables is negative, ! 265: * it will be treated as if it were zero. ! 266: * ! 267: * The number of padding blanks, and ! 268: * whether they go on the left or the ! 269: * right, will be computed on exit from ! 270: * the switch. ! 271: */ ! 272: ! 273: prefix = ""; ! 274: suffix = &expbuf[MAXESIZ]; ! 275: lzero = rzero = 0; ! 276: ! 277: switch (fcode = *format++) { ! 278: ! 279: /* ! 280: * fixed point representations ! 281: * ! 282: * "hradix" is half the radix for the ! 283: * conversion. Conversion is unsigned ! 284: * unless fcode is 'd'. HIBITL is 100...000 ! 285: * binary, and is equal to the maximum ! 286: * negative number. ! 287: * We assume a 2's complement machine ! 288: */ ! 289: ! 290: case 'd': ! 291: case 'u': ! 292: hradix = 10/2; ! 293: goto fixed; ! 294: ! 295: case 'o': ! 296: hradix = 8/2; ! 297: goto fixed; ! 298: ! 299: case 'X': ! 300: case 'x': ! 301: hradix = 16/2; ! 302: ! 303: fixed: ! 304: /* Establish default precision */ ! 305: if (prec < 0) ! 306: prec = 1; ! 307: ! 308: /* Fetch the argument to be printed */ ! 309: if(length) ! 310: val = va_arg(args, long); ! 311: else if(fcode == 'd') ! 312: val = va_arg(args, int); ! 313: else ! 314: val = va_arg(args, unsigned); ! 315: ! 316: /* If signed conversion, make sign */ ! 317: if(fcode == 'd') { ! 318: if(val < 0) { ! 319: prefix = "-"; ! 320: /* ! 321: * Negate, checking in ! 322: * advance for possible ! 323: * overflow. ! 324: */ ! 325: if(val != HIBITL) ! 326: val = -val; ! 327: } else if (fplus) ! 328: prefix = "+"; ! 329: else if (fblank) ! 330: prefix = " "; ! 331: } ! 332: ! 333: /* Set translate table for digits */ ! 334: tab = (fcode == 'X') ? ! 335: "0123456789ABCDEF" : "0123456789abcdef"; ! 336: ! 337: /* Develop the digits of the value */ ! 338: p = bp = buf + MAXDIGS; ! 339: while (val != 0) { ! 340: lowbit = val & 1; ! 341: val = (val >> 1) & ~HIBITL; ! 342: *--bp = tab[val % hradix * 2 + lowbit]; ! 343: val /= hradix; ! 344: } ! 345: ! 346: /* Calculate padding zero requirement */ ! 347: lzero = bp - p + prec; ! 348: ! 349: /* Handle the # flag */ ! 350: if (fsharp && bp != p) ! 351: switch (fcode) { ! 352: case 'o': ! 353: if (lzero < 1) ! 354: lzero = 1; ! 355: break; ! 356: case 'x': ! 357: prefix = "0x"; ! 358: break; ! 359: case 'X': ! 360: prefix = "0X"; ! 361: break; ! 362: } ! 363: ! 364: break; ! 365: ! 366: case 'E': ! 367: case 'e': ! 368: /* ! 369: * E-format. The general strategy ! 370: * here is fairly easy: we take ! 371: * what ecvt gives us and re-format it. ! 372: */ ! 373: ! 374: /* Establish default precision */ ! 375: if (prec < 0) ! 376: prec = 6; ! 377: ! 378: /* Fetch the value */ ! 379: dval = va_arg(args, double); ! 380: ! 381: /* Develop the mantissa */ ! 382: bp = ecvt(dval, min(prec + 1, MAXECVT), &decpt, &sign); ! 383: ! 384: /* Determine the prefix */ ! 385: e_merge: ! 386: if (sign) ! 387: prefix = "-"; ! 388: else if (fplus) ! 389: prefix = "+"; ! 390: else if (fblank) ! 391: prefix = " "; ! 392: ! 393: /* Place the first digit in the buffer*/ ! 394: p = &buf[0]; ! 395: *p++ = (*bp != '\0') ? *bp++ : '0'; ! 396: ! 397: /* Put in a decimal point if needed */ ! 398: if (prec != 0 || fsharp) ! 399: *p++ = '.'; ! 400: ! 401: /* Create the rest of the mantissa */ ! 402: for (rzero = prec; rzero > 0 && *bp != '\0'; --rzero) ! 403: *p++ = *bp++; ! 404: ! 405: bp = &buf[0]; ! 406: ! 407: /* Create the exponent */ ! 408: if (dval != 0) { ! 409: n = decpt - 1; ! 410: if (n < 0) ! 411: n = -n; ! 412: for ( ; n != 0; n /= 10) ! 413: *--suffix = todigit(n % 10); ! 414: } ! 415: ! 416: /* Prepend leading zeroes to the exponent */ ! 417: while (suffix > &expbuf[MAXESIZ - 2]) ! 418: *--suffix = '0'; ! 419: ! 420: /* Put in the exponent sign */ ! 421: *--suffix = (decpt > 0 || dval == 0) ? '+' : '-'; ! 422: ! 423: /* Put in the e */ ! 424: *--suffix = isupper(fcode) ? 'E' : 'e'; ! 425: ! 426: break; ! 427: ! 428: case 'f': ! 429: /* ! 430: * F-format floating point. This is a ! 431: * good deal less simple than E-format. ! 432: * The overall strategy will be to call ! 433: * fcvt, reformat its result into buf, ! 434: * and calculate how many trailing ! 435: * zeroes will be required. There will ! 436: * never be any leading zeroes needed. ! 437: */ ! 438: ! 439: /* Establish default precision */ ! 440: if (prec < 0) ! 441: prec = 6; ! 442: ! 443: /* Fetch the value */ ! 444: dval = va_arg(args, double); ! 445: ! 446: /* Do the conversion */ ! 447: bp = fcvt(dval, min(prec, MAXFCVT), &decpt, &sign); ! 448: ! 449: /* Determine the prefix */ ! 450: f_merge: ! 451: if (sign && decpt > -prec && *bp != '0') ! 452: prefix = "-"; ! 453: else if (fplus) ! 454: prefix = "+"; ! 455: else if (fblank) ! 456: prefix = " "; ! 457: ! 458: /* Initialize buffer pointer */ ! 459: p = &buf[0]; ! 460: ! 461: /* Emit the digits before the decimal point */ ! 462: n = decpt; ! 463: k = 0; ! 464: do { ! 465: *p++ = (n <= 0 || *bp == '\0' || k >= MAXFSIG) ? ! 466: '0' : (k++, *bp++); ! 467: } while (--n > 0); ! 468: ! 469: /* Decide whether we need a decimal point */ ! 470: if (fsharp || prec > 0) ! 471: *p++ = '.'; ! 472: ! 473: /* Digits (if any) after the decimal point */ ! 474: n = min(prec, MAXFCVT); ! 475: rzero = prec - n; ! 476: while (--n >= 0) ! 477: *p++ = (++decpt <= 0 || *bp == '\0' || ! 478: k >= MAXFSIG) ? '0' : (k++, *bp++); ! 479: ! 480: bp = &buf[0]; ! 481: ! 482: break; ! 483: ! 484: case 'G': ! 485: case 'g': ! 486: /* ! 487: * g-format. We play around a bit ! 488: * and then jump into e or f, as needed. ! 489: */ ! 490: ! 491: /* Establish default precision */ ! 492: if (prec < 0) ! 493: prec = 6; ! 494: ! 495: /* Fetch the value */ ! 496: dval = va_arg(args, double); ! 497: ! 498: /* Do the conversion */ ! 499: bp = ecvt(dval, min(prec, MAXECVT), &decpt, &sign); ! 500: if (dval == 0) ! 501: decpt = 1; ! 502: ! 503: k = prec; ! 504: if (!fsharp) { ! 505: n = strlen(bp); ! 506: if (n < k) ! 507: k = n; ! 508: while (k >= 1 && bp[k-1] == '0') ! 509: --k; ! 510: } ! 511: ! 512: if (decpt < -3 || decpt > prec) { ! 513: prec = k - 1; ! 514: goto e_merge; ! 515: } ! 516: prec = k - decpt; ! 517: goto f_merge; ! 518: ! 519: /* case '%': */ ! 520: default: ! 521: buf[0] = fcode; ! 522: goto c_merge; ! 523: ! 524: case 'c': ! 525: buf[0] = va_arg(args, int); ! 526: c_merge: ! 527: p = (bp = &buf[0]) + 1; ! 528: break; ! 529: ! 530: case 's': ! 531: p = bp = va_arg(args, char *); ! 532: if (prec < 0) ! 533: p += strlen(bp); ! 534: else { /* a strnlen function would be useful here! */ ! 535: while (*p++ != '\0' && --prec >= 0) ! 536: ; ! 537: --p; ! 538: } ! 539: break; ! 540: ! 541: case '\0': /* unexpected end of format; return error */ ! 542: return (EOF); ! 543: ! 544: } ! 545: ! 546: /* Calculate number of padding blanks */ ! 547: if (lzero < 0) ! 548: lzero = 0; ! 549: if (rzero < 0) ! 550: rzero = 0; ! 551: k = (n = p - bp) + lzero + rzero + ! 552: (prefix[0] == '\0' ? 0 : prefix[1] == '\0' ? 1 : 2) + ! 553: (&expbuf[MAXESIZ] - suffix); ! 554: count += (width > k) ? width : k; ! 555: ! 556: /* Blanks on left if required */ ! 557: if (!fminus) ! 558: while (--width >= k) ! 559: (void) putc(' ', iop); ! 560: ! 561: /* Prefix, if any */ ! 562: while (*prefix != '\0') ! 563: (void) putc(*prefix++, iop); ! 564: ! 565: /* Zeroes on the left */ ! 566: while (--lzero >= 0) ! 567: (void) putc('0', iop); ! 568: ! 569: /* The value itself */ ! 570: if (n > 0) ! 571: PUT(bp, n); ! 572: ! 573: /* Zeroes on the right */ ! 574: while (--rzero >= 0) ! 575: (void) putc('0', iop); ! 576: ! 577: /* The suffix */ ! 578: while (*suffix != '\0') ! 579: (void) putc(*suffix++, iop); ! 580: ! 581: /* Blanks on the right if required */ ! 582: while (--width >= k) ! 583: (void) putc(' ', iop); ! 584: } ! 585: } ! 586: #else ! 587: /* This is just to keep from getting a diagnostic from ranlib. */ ! 588: __dpdummy__() ! 589: { ! 590: } ! 591: #endif NEEDDOPRNT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.