home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume10
/
uformat
< prev
next >
Wrap
Text File
|
1990-02-26
|
6KB
|
252 lines
Newsgroups: comp.sources.misc
From: allbery@uunet.UU.NET
Subject: v10i085: numeric formatting function
Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Posting-number: Volume 10, Issue 85
Submitted-by: allbery@uunet.UU.NET
Archive-name: uformat
Report generators for database managers often use numeric formatting which
is based on "pictures" like "($,$$$,$$#.&&)" or "<<<<<#". Here's my version
of a function to perform such formatting. To test it, compile with -DTEST
to produce the executable "format"; run it with two arguments, a format
string (quoted to protect it from the shell) and a floating-point number.
Called from a program, it's uformat(buffer, formatstring, doublevalue) and
stores its result in buffer.
++Brandon
-------------------------------------------------------------------------------
#! /bin/sh
# This file was wrapped with "dummyshar". "sh" this file to extract.
# Contents: format.c
echo extracting 'format.c'
if test -f 'format.c' -a -z "$1"; then echo Not overwriting 'format.c'; else
sed 's/^X//' << \EOF > 'format.c'
X/*
X * Process a format, as used by various report generators, to format a value.
X * Format characters:
X *
X * * Digit or asterisk prefix
X * $ Digit or dollar-sign prefix
X * - Digit or minus-sign prefix if negative
X * + Digit or sign prefix
X * ( Digit or left-parenthesis prefix if negative
X * # Digit or blank prefix
X * & Digit or zero prefix
X * ) Right-parenthesis suffix if negative
X * . Decimal point
X * , Comma or space prefix
X * < Digit or space appended after format (left justification)
X *
X * This may not be the fastest possible implementation, but it's plenty fast
X * enough for my purposes.
X *
X * This routine uses only fabs(), fmod(), and floor(); it should be compatible
X * with any system that has a standard C math library.
X */
X
X#ifdef TEST
X#include <stdio.h>
X#endif
X
Xextern double fabs();
Xextern double fmod();
Xextern double floor();
X
Xvoid
Xuformat(buf, val, fmt)
X char *fmt, *buf;
X double val;
X{
X double decval;
X int didlead, didsign, pad, signum, overflow;
X register char *fmtp, *bufp, *decp;
X char tbuf[1024];
X
X signum = (val < 0.0);
X val = fabs(val);
X for (decp = fmt; *decp; decp++)
X if (*decp == '.')
X break;
X /*
X * Make a first pass to calculate a rounding value.
X */
X decval = 0.5;
X for (fmtp = decp; *fmtp; fmtp++)
X {
X switch (*fmtp)
X {
X case '*':
X case '$':
X case '-':
X case '+':
X case '(':
X case '#':
X case '&':
X case '<':
X decval /= 10.0;
X break;
X }
X }
X val += decval;
X fmtp = decp;
X decval = val - floor(val);
X val = floor(val);
X pad = 0;
X didlead = 0;
X didsign = 0;
X bufp = tbuf;
X#ifdef TEST
X fprintf(stderr, "fmt = %.*s, decp = %s, val = %s%.14g, decval = %.14g\n",
X (decp - fmt), fmt, decp, (signum? "-": ""), val, decval);
X#endif
X while (fmtp != fmt)
X {
X switch (*--fmtp)
X {
X case '#':
X case '<':
X if (val < 1.0)
X {
X if (*fmtp == '<')
X pad++;
X else
X *bufp++ = ' ';
X break;
X }
X /*FALLTHROUGH*/
X case '&':
X *bufp++ = (int) fmod(val, 10.0) + '0';
X val /= 10.0;
X break;
X case '*':
X if (val >= 1.0)
X {
X *bufp++ = (int) fmod(val, 10.0) + '0';
X val /= 10.0;
X break;
X }
X *bufp++ = (didlead? ' ': '*');
X didlead = 1;
X break;
X case '$':
X if (val >= 1.0)
X {
X *bufp++ = (int) fmod(val, 10.0) + '0';
X val /= 10.0;
X break;
X }
X *bufp++ = (didlead? ' ': '$');
X didlead = 1;
X break;
X case '-':
X if (val >= 1.0)
X {
X *bufp++ = (int) fmod(val, 10.0) + '0';
X val /= 10.0;
X break;
X }
X *bufp++ = (didsign? ' ': (signum? '-': ' '));
X didsign = 1;
X break;
X case '+':
X if (val >= 1.0)
X {
X *bufp++ = (int) fmod(val, 10.0) + '0';
X val /= 10.0;
X break;
X }
X *bufp++ = (didsign? ' ': (signum? '-': '+'));
X didsign = 1;
X break;
X case '(':
X if (val >= 1.0)
X {
X *bufp++ = (int) fmod(val, 10.0) + '0';
X val /= 10.0;
X break;
X }
X *bufp++ = (didsign? ' ': (signum? '(': ' '));
X didsign = 1;
X break;
X case ')':
X *bufp++ = (signum? ')': ' ');
X break;
X case ',':
X *bufp++ = (val < 1.0? ' ': ',');
X break;
X default:
X *bufp++ = *fmtp;
X }
X }
X overflow = (val >= 1.0);
X while (bufp-- != tbuf)
X *buf++ = (overflow? '*': *bufp);
X /*
X * Decimals turn out to be easy, since we can parse forward and all the
X * potential digit chars can be treated as "&". Also, extracting digits
X * is done via (decval *= 10.0; floor(decval)) instead of slow fmod().
X */
X while (*decp)
X {
X if (overflow)
X *buf++ = '*';
X else
X {
X switch (*decp)
X {
X case '*':
X case '$':
X case '-':
X case '+':
X case '(':
X case '#':
X case '&':
X case '<':
X decval *= 10.0;
X *buf++ = (int) floor(decval) + '0';
X decval -= floor(decval);
X break;
X case ')':
X *buf++ = (signum? ')': ' ');
X break;
X default:
X *buf++ = *decp;
X break;
X }
X }
X decp++;
X }
X while (pad--)
X *buf++ = (overflow? '*': ' ');
X *buf = '\0';
X}
X
X#ifdef TEST
X
Xextern double atof();
X
Xmain(argc, argv)
X char **argv;
X{
X char buf[1024];
X
X if (argc != 3)
X {
X fprintf(stderr, "usage: %s format-string value\n", argv[0]);
X exit(1);
X }
X uformat(buf, atof(argv[2]), argv[1]);
X puts(buf);
X exit(0);
X}
X
X#endif
EOF
chars=`wc -c < 'format.c'`
if test $chars != 4232; then echo 'format.c' is $chars characters, should be 4232 characters!; fi
fi
exit 0