In some C standard libraries, the 'l' of the conversions "lf" and "ld" in the format strings of sprintf() are not necessary. If the compiler balks at this (I doubt it), then simply remove the modifying 'l's.
/* ftotal.c
*
*
* Extend to allow the handling of multiple files.
*
* Allow option to change the separation between date segment and totaling
* segment of the output line.
*
*/
#include <sys/types.h>
#include <time.h>
#include <stdio.h>
#include <stdfun.h>
#include <string.h>
#include <ascii.h>
#include <math.h>
#define MAXLINE 512
#define LABELSZ 40
#define FILENAMESZ 15
#define FALSE 0
#define TRUE 1
#define OPTSTRING "DsdxvfL:N:S:M:A:c:n:"
#define USAGESTRING "Usage: ftotal [-Ddxf][-L label][-s[-v]][-S #][-N #][-c|n # | -M|A \"# #\"]"
#define MULTOP 0
#define PLUSOP 1
int skipln;
int main( argc, argv )
int argc;
char *argv[];
{
extern int getopt();
extern int optind;
extern char *optarg;
int c_opt;
char *mkdates();
double colscan();
int mkpristr();
FILE *rptr;
char line[MAXLINE], D[30], pstr[12];
char llabel[LABELSZ + 1];
char flname[FILENAMESZ + 1];
double p, Total;
double p1, p2;
double av, s, Totalsqs;
int lno;
int plns = 0;
int arithop = -1;
int stats = FALSE;
int decimal = FALSE;
int no_date = FALSE;
int no_nl = FALSE;
int nflag = 0;
int verbose = FALSE;
int col = 1;
int col2 = 1;
int startline = 1;
int putlabel = FALSE;
int putfilename = FALSE;
/* No command line arguments means take stdin for input */
while( ( c_opt = getopt( argc, argv, OPTSTRING ) ) != EOF ) {
switch( c_opt ) {
case 'L':
/* Use Label argument to -L in output after
* final numerical output field.
*/
if( sscanf( optarg, "%s", llabel ) != 1 ) {
printf( "uvtotal: Bad Argument to -L\n" );
puts( USAGESTRING );
exit( 1 );
}
strcpy( llabel, optarg );
putlabel = TRUE;
break;
case 'N':
/* Only use plns number of lines
* instead of all of them.
*/
if( sscanf( optarg, "%d", &plns ) != 1 ) {
printf( "uvtotal: Bad Argument to -N\n" );
puts( USAGESTRING );
exit( 1 );
}
break;
case 'S':
/* Start processing lines at data line number
* instead of the first;
*/
if( sscanf( optarg, "%d", &startline ) != 1 ) {
printf( "uvtotal: Bad Argument to -S\n" );
puts( USAGESTRING );
exit( 1 );
}
break;
case 'D':
/* Print result converted to decimal;
* default is as float.
*/
decimal = TRUE;
break;
case 'x':
/* Suppress new line in output;
* default is with new line
*/
no_nl = TRUE;
break;
case 'd':
/* Don't output dated line, just output total;
* default is dated line
*/
no_date = TRUE;
break;
case 'c':
/* Do sum on column (1-12) indicated by
* argument; default is 1.
*/
if( sscanf( optarg, "%d", &col ) != 1 ) {
printf( "uvtotal: Bad Argument to -c\n" );
puts( USAGESTRING );
exit( 1 );
}
if( col > 12 ) {
fprintf( stderr, "Argument to -c out of range\n" );
puts( USAGESTRING );
exit( 1 );
}
break;
case 'M':
arithop = MULTOP;
/* Do sum on multiply of 2 columns (1-12)
* indicated by string "d d" argument;
*/
if( sscanf( optarg, "%d %d", &col, &col2 ) != 2 ) {
printf( "uvtotal: Bad Argument to -M\n" );
puts( USAGESTRING );
exit( 1 );
}
if( col > 12 || col2 > 12 ) {
fprintf( stderr, "Arguments to -M out of range\n" );
puts( USAGESTRING );
exit( 1 );
}
break;
case 'A':
arithop = PLUSOP;
/* Do sum on add of 2 columns (1-12)
* indicated by string "d d" argument;
*/
if( sscanf( optarg, "%d %d", &col, &col2 ) != 2 ) {
printf( "uvtotal: Bad Argument to -A\n" );
puts( USAGESTRING );
exit( 1 );
}
if( col > 12 || col2 > 12 ) {
fprintf( stderr, "Arguments to -A out of range\n" );
puts( USAGESTRING );
exit( 1 );
}
break;
case 'n':
nflag = TRUE;
/* Do sum on column at absolute position
* argument; default is 0.
*/
if( sscanf( optarg, "%d", &col ) != 1 ) {
printf( "uvtotal: Bad Argument to -n\n" );
puts( USAGESTRING );
exit( 1 );
}
break;
case 's':
/* Also print average and standard deviation.
* default is not
*/
stats = TRUE;
break;
case 'v':
/* Also label the printed average and standard
* deviation; default is not.
*/
verbose = TRUE;
break;
case 'f':
/* Also print filename at left with colon;
* ; default is not.
*/
putfilename = TRUE;
break;
default:
printf( "uvtotal: Bad Option\n" );
puts( USAGESTRING );
exit( 1 );
}
} /* End while getting options */
if( argv[ optind ] == (char *)0 ) {
/* If we do not get a file name, assume input is coming from
* standard input in a pipeline.
*/
sprintf( flname, "%s", "stdin" );
rptr = stdin;
}
else {
sprintf( flname, "%s", argv[ optind ] );
if( (rptr = fopen( argv[ optind ], "r" )) == NULL ) {
fprintf( stderr, "Cannot read %s\n", argv[ optind ] );
exit( 1 );
}
}
Total = (double)0;
Totalsqs = (double)0;
lno = 0;
skipln = FALSE; /* Used with colscan() */
while( fgets( line, MAXLINE, rptr ) != NULL ) {
if( *line == LF )
continue;
if( nflag == 1 ) {
/* -n option */
if( sscanf( &line[ col ], "%lf", &p ) != 1 )
continue;
}
else {
/* -c option */
if( arithop == MULTOP ) {
skipln = FALSE;
p1 = colscan( line, col );
p2 = colscan( line, col2 );
if( skipln == TRUE )
continue;
p = p1 * p2;
}
else if( arithop == PLUSOP ) {
skipln = FALSE;
p1 = colscan( line, col );
p2 = colscan( line, col2 );
if( skipln == TRUE )
continue;
p = p1 + p2;
}
else {
skipln = FALSE;
p = colscan( line, col );
if( skipln == TRUE )
continue;
}
}
/* We increment line number only for real data lines
* with an actual data item.
*/
++lno;
if( lno < startline ) {
continue;
}
/* Acculate the data */
Total += p;
if( stats ) {
Totalsqs += p*p;
}
if( plns != 0 && (lno - startline + 1) >= plns ) {
/* If -N option is specified and we have reached
* the specified number of real data lines.
*/
break;
}
} /* End while processing input lines */
mkpristr( decimal, pstr, Total );
/*------------ Do final printing ------------*/
if( putfilename ) {
printf( "%s:\t", flname );
}
if( stats ) {
if( lno == 0 ) {
av = (double)0;
s = (double)0;
}
else {
av = Total / (double)lno;
s = Totalsqs / (double)lno - av * av;
if( lno == 1 )
s = (double)0;
else
s = s * ((double)lno / (double)(lno - 1));
}
s = sqrt( s );
if( verbose ) {
if( no_date ) {
printf( "Total: %s Number: %d Average: %lf Std Dev: %lf", pstr, lno, av, s );
}
else {
printf( "%s Total: %s Number: %d Average: %lf Std Dev: %lf", mkdates( D ), pstr, lno, av, s );
}
}
else {
if( no_date ) {
printf( "%s %d %lf %lf", pstr, lno, av, s );
}
else {
printf( "%s %s %d %lf %lf", mkdates( D ), pstr, lno, av, s );
}
}
}
else {
if( no_date ) {
printf( "%s", pstr );
}
else {
printf( "%s %s", mkdates( D ), pstr );
}
}
if( putlabel ) {
printf( " %s", llabel );
}
if( no_nl == FALSE )
putchar( '\n' );
exit( 0 );
return( 0 );
} /* End main() */
double colscan( line, col )
char *line;
int col;
{
double p;
switch( col ) {
case 1:
if( sscanf( line , "%lf", &p ) != 1 )
skipln = TRUE;
break;
case 2:
if( sscanf( line , "%*s%lf", &p ) != 1 )
skipln = TRUE;
break;
case 3:
if( sscanf( line , "%*s%*s%lf", &p ) != 1 )
skipln = TRUE;
break;
case 4:
if( sscanf( line , "%*s%*s%*s%lf", &p ) != 1 )
skipln = TRUE;
break;
case 5:
if( sscanf( line , "%*s%*s%*s%*s%lf", &p ) != 1 )
skipln = TRUE;
break;
case 6:
if( sscanf( line , "%*s%*s%*s%*s%*s%lf", &p ) != 1 )
skipln = TRUE;
break;
case 7:
/* Correct for the dated line that is the
* output of uvtotal.
*/
if( sscanf( line , "%*s%*s%*s%*s%*s%*s%lf", &p ) != 1 )
skipln = TRUE;
break;
case 8:
if( sscanf( line , "%*s%*s%*s%*s%*s%*s%*s%lf", &p ) != 1 )
skipln = TRUE;
break;
case 9:
if( sscanf( line , "%*s%*s%*s%*s%*s%*s%*s%*s%lf", &p ) != 1 )
skipln = TRUE;
break;
case 10:
if( sscanf( line , "%*s%*s%*s%*s%*s%*s%*s%*s%*s%lf", &p ) != 1 )
skipln = TRUE;
break;
case 11:
if( sscanf( line , "%*s%*s%*s%*s%*s%*s%*s%*s%*s%*s%lf", &p ) != 1 )
skipln = TRUE;
break;
case 12:
if( sscanf( line , "%*s%*s%*s%*s%*s%*s%*s%*s%*s%*s%*s%lf", &p ) != 1 )
skipln = TRUE;
break;
}
return( p );
}
char *mkdates( D )
char *D;
{
extern long time();
extern char *strncpy();
void xnl();
char d[26];
long now;
now = time( (long *)0 );
sprintf( d, "%s", ctime( &now ) );
strncpy( D, d, 20 );
sprintf( &D[20], "%s %s", tzname[daylight], &d[20] );
xnl( D );
return( D );
}
int mkpristr( decimal, pstr, p )
int decimal;
char *pstr;
double p;
{
if( decimal == 1 ) {
if( p < 10.00 )
sprintf( pstr, " %ld", (long)p );
else if( p < 100.00 )
sprintf( pstr, " %ld", (long)p );
else if( p < 1000.00 )
sprintf( pstr, " %ld", (long)p );
else if( p < 10000.00 )
sprintf( pstr, " %ld", (long)p );
else if( p < 100000.00 )
sprintf( pstr, "%ld", (long)p );
else
sprintf( pstr, "%ld", (long)p );
}
else {
if( p < 10.00 )
sprintf( pstr, " %.2lf", p );
else if( p < 100.00 )
sprintf( pstr, " %.2lf", p );
else if( p < 1000.00 )
sprintf( pstr, " %.2lf", p );
else if( p < 10000.00 )
sprintf( pstr, " %.2lf", p );
else if( p < 100000.00 )
sprintf( pstr, "%.2lf", p );
else
sprintf( pstr, "%.2lf", p );
}
return( 0 );
}
void xnl( a ) /* Zap newline to NUL in an array */
char *a;
{
while( *a != LF ) {
if( *a == NUL ) {
/* Safety insurance */
return;
}
++a;
}
*a = NUL;
} /* End xnl() */
FTOTAL(LOCAL) XENIX System V (LM) FTOTAL(LOCAL)
NAME
ftotal - sum arithmetic functions of fields in a file
SYNOPSIS
ftotal [-Ddxf][-L label][-s[-v]][-S #][-N #][-c|n # | -M|A
"# #"] [file]
DESCRIPTION
Ftotal reads the named file or input if none is given. A
sum is performed of quantities, read as floating point
decimal, that are simple arithmetic functions of fields
specified by the options -c, -n, -M and -A. The -N option
delimits the number of real data lines used, while the -S
option specifies the data line number to begin. The
remaining options LDdxsvf specify the form of the output.
The default output line has the form,
Mon Jan 31 22:40:20 EDT 1994 4389.92
where the output sum appears in column 7 specified for the
-c option. The leading date string is always 28 characters
long and is followed by two tab characters. Thus the same
final floating point field can be specified using the -n
option with argument 30.
OPTIONS
-c # Column: find the single field on which
the sum is to be performed as the #th
column. Columns are numbered starting
with 1. The field separator is white
space of any length. Initial white
space before the field is ignored.
-n # Number: find the single field on which
the sum is to be performed as that which
begins at the #th character on a line.
Character positions are numbered
starting with 0. Initial white space
before the field is ignored.
-S # Start: perform the specified arithmetic
operation only on data lines beginning
with the #th data line. Non data lines
and blank lines are not counted and are
ignored.
-N # Number: perform the specified arithmetic
operation for only the first # real data
lines after the start line. Non data
lines and blank lines are not counted
and are ignored.
Page 1 (printed 11/1/97)
FTOTAL(LOCAL) XENIX System V (LM) FTOTAL(LOCAL)
-M"n m" Multiply: perform the sum on quantities
that are products of fields found in
columns n and m. Columns are specified
by the rules of the -c option.
-A"n m" Add: perform the sum on quantities that
are sums of fields found in columns n
and m. Columns are specified by the
rules of the -c option.
-L label Append label to the output line allowing
one space separation. If there is more
than one word to the label, the entire
label should be enclosed in double or
single quotes. To avoid an possible
shell expansions, single quotes are
safest.
-D Decimal: output the result as integer
formed by truncation of the internally
computed floating point result.
-d Date: suppress date and time in output
line.
-x Suppress newline in output.
-s Statistics: include them in output line.
In order left to right they numbers are:
the total requested, the number of items
in the total, the average of those
items, the sample standard deviation of
the items.
-v Verbose: with the -s option, label the
output statistics.
-f Precede output line with with the name
of the file being processed followed by
a colon ':' and a single tab character.
SEE ALSO
plus(LOCAL) mult(LOCAL) divide(LOCAL) cut(C) paste(C)
sort(C)
FILES
/usr/bin/ftotal the executable pathname
Page 2 (printed 11/1/97)