Path: utzoo!attcan!uunet!tut.cis.ohio-state.edu!purdue!tippy!sawmill!buhrt From: buhrt@sawmill.uucp (Jeffery A Buhrt) Newsgroups: comp.sources.bugs Subject: Sc6.10 missing function format.c Message-ID: <1990Oct29.132848.16331@sawmill.uucp> Date: 29 Oct 90 13:28:48 GMT Organization: Grauel Enterprises Lines: 581 Sorry, format.c was not included in the patch set. -Jeff Buhrt 317-477-6000 sequent!sawmill!buhrt #!/bin/sh # This is a shell archive (shar 3.20) # made 10/29/1990 13:28 UTC by buhrt@sawmill # Source directory /users/buhrt/src/sc # # existing files WILL be overwritten # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 13822 -r--r--r-- format.c # if touch 2>&1 | fgrep '[-amc]' > /dev/null then TOUCH=touch else TOUCH=true fi # ============= format.c ============== echo "x - extracting format.c (Text)" sed 's/^X//' << 'SHAR_EOF' > format.c && X/***************************************************************************** X * X * Mark Nagel X * 20 July 1989 X * X * $Revision: 6.10 $ X * X * bool X * format(fmt, num, buf, buflen) X * char *fmt; X * double num; X * char buf[]; X * int buflen; X * X * The format function will produce a string representation of a number X * given a _format_ (described below) and a double value. The result is X * written into the passed buffer -- if the resulting string is too X * long to fit into the passed buffer, the function returns false. X * Otherwise the function returns true. X * X * The fmt parameter contains the format to use to convert the number. X * X * # Digit placeholder. If the number has fewer digits on either X * side of the decimal point than there are '#' characters in X * the format, the extra '#' characters are ignored. The number X * is rounded to the number of digit placeholders as there are X * to the right of the decimal point. If there are more digits X * in the number than there are digit placeholders on the left X * side of the decimal point, then those digits are displayed. X * X * 0 Digit placeholder. Same as for '#' except that the number X * is padded with zeroes on either side of the decimal point. X * The number of zeroes used in padding is determined by the X * number of digit placeholders after the '0' for digits on X * the left side of the decimal point and by the number of X * digit placeholders before the '0' for digits on the right X * side of the decimal point. X * X * . Decimal point. Determines how many digits are placed on X * the right and left sides of the decimal point in the number. X * Note that numbers smaller than 1 will begin with a decimal X * point if the left side of the decimal point contains only X * a '#' digit placeholder. Use a '0' placeholder to get a X * leading zero in decimal formats. X * X * % Percentage. For each '%' character in the format, the actual X * number gets multiplied by 100 (only for purposes of formatting X * -- the original number is left unmodified) and the '%' character X * is placed in the same position as it is in the format. X * X * , Thousands separator. The presence of a ',' in the format X * (multiple commas are treated as one) will cause the number X * to be formatted with a ',' separating each set of three digits X * in the integer part of the number with numbering beginning X * from the right end of the integer. X * X * \ Quote. This character causes the next character to be X * inserted into the formatted string directly with no X * special interpretation. X * X * E- E+ e- e+ X * Scientific format. Causes the number to formatted in scientific X * notation. The case of the 'E' or 'e' given is preserved. If X * the format uses a '+', then the sign is always given for the X * exponent value. If the format uses a '-', then the sign is X * only given when the exponent value is negative. Note that if X * there is no digit placeholder following the '+' or '-', then X * that part of the formatted number is left out. In general, X * there should be one or more digit placeholders after the '+' X * or '-'. X * X * ; Format selector. Use this character to separate the format X * into two distinct formats. The format to the left of the X * ';' character will be used if the number given is zero or X * positive. The format to the right of the ';' character is X * used if the number given is negative. X * X * Any X * Self insert. Any other character will be inserted directly X * into the formatted number with no change made to the actual X * number. X * X *****************************************************************************/ X X/*****************************************************************************/ X X#include X X#define bool int X#define true 1 X#define false 0 X#define EOS '\0' X#define MAXBUF 256 X Xextern char X *strcpy(); X Xstatic char X *fmt_int(), X *fmt_frac(), X *fmt_exp(); X Xstatic void X reverse(); X X/*****************************************************************************/ X Xbool Xformat(fmt, val, buf, buflen) X char *fmt; X double val; X char *buf; X int buflen; X{ X register char *cp; X char *tmp, *tp, *tmpfmt; X bool comma = false, negative = false; X char *integer = NULL, *decimal = NULL; X char *exponent = NULL; X int exp_val, width; X char prtfmt[32]; X char *mantissa; X char *fraction = NULL; X int zero_pad = 0; X X if (fmt == NULL) X return(true); X X fmt = tmpfmt = strcpy((char *) xmalloc(strlen(fmt) + 1), fmt); X mantissa = (char *) xmalloc(buflen + 1); X X /* X * select positive or negative format if necessary X */ X for (cp = fmt; *cp != ';' && *cp != EOS; cp++) X { X if (*cp == '\\') X cp++; X } X if (*cp == ';') X { X if (val < 0.0) X { X val = -val; /* format should provide sign if desired */ X fmt = cp + 1; X } X else X { X *cp = EOS; X } X } X X /* X * extract other information from format and produce new X * malloc'ed format string X */ X tmp = (char *) xmalloc(strlen(fmt) + 1); X for (cp = fmt, tp = tmp; *cp != EOS; cp++) X { X switch (*cp) X { X case '\\': X *tp++ = *cp++; X *tp++ = *cp; X break; X X case ',': X comma = true; X break; X X case '.': X if (decimal == NULL) X decimal = tp; X *tp++ = *cp; X break; X X case '%': X val *= 100.0; X *tp++ = *cp; X break; X X default: X *tp++ = *cp; X break; X } X } X *tp = EOS; X xfree(tmpfmt); X fmt = tmp; X X /* X * extract the exponent from the format if present X */ X for (cp = fmt; *cp != EOS; cp++) X { X if (*cp == '\\') X { X cp++; X } X else if (*cp == 'e' || *cp == 'E') X { X if (cp[1] == '+' || cp[1] == '-') X { X tmp = (char *) xmalloc(strlen(cp) + 1); X exponent = strcpy(tmp, cp); X *cp = EOS; X exp_val = 0; X while (val < 1.0) X { X val *= 10.0; X exp_val--; X } X while (val >= 10.0) X { X val /= 10.0; X exp_val++; X } X break; X } X } X } X X /* X * determine maximum decimal places and use sprintf X * to build initial character form of formatted value. X */ X width = 0; X if (decimal) X { X *decimal++ = EOS; X for (cp = decimal; *cp != EOS; cp++) X { X switch (*cp) X { X case '\\': X cp++; X break; X X case '#': X width++; X break; X X case '0': X zero_pad = ++width; X break; X } X } X zero_pad = strlen(decimal) - zero_pad; X } X if (val < 0.0) X { X negative = true; X val = -val; X } X sprintf(prtfmt, "%%.%dlf", width); X sprintf(mantissa, prtfmt, val); X for (cp = integer = mantissa; *cp != '.' && *cp != EOS; cp++) X { X if (*integer == '0') X integer++; X } X if (*cp == '.') X { X fraction = cp + 1; X *cp = EOS; X cp = fraction + strlen(fraction) - 1; X for (; zero_pad > 0; zero_pad--, cp--) X { X if (*cp == '0') X *cp = EOS; X } X } X X /* X * format the puppy X */ X { X char *ci, *cf, *ce; X int len_ci, len_cf, len_ce; X bool ret = false; X X ci = fmt_int(integer, fmt, comma, negative); X ci = strcpy((char *)xmalloc((len_ci = strlen(ci)) + 1), ci); X cf = (fraction) ? fmt_frac(fraction, decimal) : ""; X cf = strcpy((char *)xmalloc((len_cf = strlen(cf)) + 1), cf); X ce = (exponent) ? fmt_exp(exp_val, exponent) : ""; X ce = strcpy((char *)xmalloc((len_ce = strlen(ce)) + 1), ce); X if (len_ci + len_cf + len_ce < buflen) X { X sprintf(buf, "%s%s%s", ci, cf, ce); X ret = true; X } X X /* X * free up malloc'ed memory X */ X xfree(mantissa); X xfree(fmt); X if (exponent) xfree(exponent); X xfree(ci); X xfree(cf); X xfree(ce); X X return (ret); X } X} X X/*****************************************************************************/ X Xstatic char * Xfmt_int(val, fmt, comma, negative) X char *val; /* integer part of the value to be formatted */ X char *fmt; /* integer part of the format */ X bool comma; /* true if we should comma-ify the value */ X bool negative; /* true if the value is actually negative */ X{ X int digit, f, v; X int thousands = 0; X char *cp; X static char buf[MAXBUF]; X char *bufptr = buf; X X /* X * locate the leftmost digit placeholder X */ X for (cp = fmt; *cp != EOS; cp++) X { X if (*cp == '\\') X cp++; X else if (*cp == '#' || *cp == '0') X break; X } X digit = (*cp == EOS) ? -1 : cp - fmt; X X /* X * format the value X */ X f = strlen(fmt) - 1; X v = (digit >= 0) ? strlen(val) - 1 : -1; X while (f >= 0 || v >= 0) X { X if (f > 0 && fmt[f-1] == '\\') X { X *bufptr++ = fmt[f--]; X } X else if (f >= 0 && (fmt[f] == '#' || fmt[f] == '0')) X { X if (v >= 0 || fmt[f] == '0') X { X *bufptr++ = v < 0 ? '0' : val[v]; X if (comma && (thousands = (thousands + 1) % 3) == 0 && v > 0) X { X *bufptr++ = ','; X } X v--; X } X } X else if (f >= 0) X { X *bufptr++ = fmt[f]; X } X if (v >= 0 && f == digit) X { X continue; X } X f--; X } X X if (negative && digit >= 0) X *bufptr++ = '-'; X *bufptr = EOS; X reverse(buf); X X return (buf); X} X X/*****************************************************************************/ X Xstatic char * Xfmt_frac(val, fmt) X char *val; /* fractional part of the value to be formatted */ X char *fmt; /* fractional portion of format */ X{ X static char buf[MAXBUF]; X register char *bufptr = buf; X register char *fmtptr = fmt, *valptr = val; X X *bufptr++ = '.'; X while (*fmtptr != EOS) X { X if (*fmtptr == '\\') X { X *bufptr++ = *++fmtptr; X } X else if (*fmtptr == '#' || *fmtptr == '0') X { X if (*valptr != EOS || *fmtptr == '0') X { X *bufptr++ = (*valptr != EOS) ? *valptr++ : *fmtptr; X } X } X else X { X *bufptr++ = *fmtptr; X } X fmtptr++; X } X *bufptr = EOS; X X return (buf); X} X X/*****************************************************************************/ X Xstatic char * Xfmt_exp(val, fmt) X int val; /* value of the exponent */ X char *fmt; /* exponent part of the format */ X{ X static char buf[MAXBUF]; X register char *bufptr = buf; X char valbuf[64]; X bool negative = false; X X *bufptr++ = *fmt++; X if (*fmt++ == '+') X *bufptr++ = (val < 0) ? '-' : '+'; X else if (val < 0) X *bufptr++ = '-'; X *bufptr = EOS; X X if (val < 0) X { X val = -val; X negative = true; X } X sprintf(valbuf, "%d", val); X X strcat(buf, fmt_int(valbuf, fmt, false, negative)); X return (buf); X} X X/*****************************************************************************/ X Xstatic void Xreverse(buf) X register char *buf; X{ X register char *cp = buf + strlen(buf) - 1; X register char tmp; X X while (buf < cp) X { X tmp = *cp; X *cp-- = *buf; X *buf++ = tmp; X } X} X X/*****************************************************************************/ X/* X * Tom Anderson X * 10/14/90 X * X * This routine takes a value and formats it using fixed, scientific, X * or engineering notation. The format command 'f' determines which X * format is used. The formats are: example X * 0: Fixed point (default) 0.00010 X * 1: Scientific 1.00E-04 X * 2: Engineering 100.00u X * X * The format command 'f' now uses three values. The first two are the X * width and precision, and the last one is the format value 0, 1, or 2 as X * described above. The format value is passed in the variable fmt. X * X * This formatted value is written into the passed buffer. if the X * resulting string is too long to fit into the passed buffer, the X * function returns false. Otherwise the function returns true. X * X * When a number is formatted as engineering and is outside of the range X * of typically used engineering exponents, the format reverts to X * scientific. X * X * To preserve compatability with old spreadsheet files, the third value X * may be missing, and the default will be fixed point (format 0). X * X * When an old style sheet is saved, the third value will be stored. X * X */ X X#define REFMTFIX 0 X#define REFMTFLT 1 X#define REFMTENG 2 Xchar engmult[] = "afpnum kMGT"; X Xbool Xengformat(fmt, width, precision, val, buf, buflen) Xint fmt; Xint width; Xint precision; Xdouble val; Xchar *buf; Xint buflen; X{ X int engind = 0; X double engmant, pow(), engabs, engexp; X if (buflen < width) return (false); X if (fmt == REFMTFIX) X (void)sprintf(buf,"%*.*f", width, precision, val); X if (fmt == REFMTFLT) X (void)sprintf(buf,"%*.*E", width, precision, val); X if (fmt == REFMTENG) X { X if (val == 0e0) /* Hack to get zeroes to line up in engr fmt */ X { X (void)sprintf((buf-1),"%*.*f ", width, precision, val); X } X else X { X engabs=(val); X if (engabs < 0e0) engabs= -engabs; X if ((engabs >= 1e-18) && (engabs < 1e-15 )) engind=0; X if ((engabs >= 1e-15) && (engabs < 1e-12 )) engind=1; X if ((engabs >= 1e-12) && (engabs < 1e-9 )) engind=2; X if ((engabs >= 1e-9) && (engabs < 1e-6 )) engind=3; X if ((engabs >= 1e-6) && (engabs < 1e-3 )) engind=4; X if ((engabs >= 1e-3) && (engabs < 1 )) engind=5; X if ((engabs >= 1) && (engabs < 1e3 )) engind=6; X if ((engabs >= 1e3) && (engabs < 1e6 )) engind=7; X if ((engabs >= 1e6) && (engabs < 1e9 )) engind=8; X if ((engabs >= 1e9) && (engabs < 1e12 )) engind=9; X if ((engabs >= 1e12) && (engabs < 1e15 )) engind=10; X if ((engabs <1e-18) || (engabs >=1e15)) X { X /* Revert to floating point */ X (void)sprintf(buf,"%*.*E", width, precision, val); X } X else X { X engexp= (double) (engind-6)*3; X engmant= val/pow(10.0e0,engexp); X (void)sprintf(buf,"%*.*f%c", width-1, X precision, engmant, engmult[engind]); X } X } X } X return (true); X} SHAR_EOF $TOUCH -am 1026165790 format.c && chmod 0444 format.c || echo "restore of format.c failed" set `wc -c format.c`;Wc_c=$1 if test "$Wc_c" != "13822"; then echo original size 13822, current size $Wc_c fi exit 0