1. ftotal source code
  2. ftotal manual page
Source Code

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 Manual Page A>
     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)




Return to Home Page
Return to Metayoga Page
Return to C Language Page


The URL for this document is:
http://graham.main.nc.us/~bhammel/graham/CPROGS/ftotal.html
Created: 1997
Last Updated: May 28, 2000 Email me, Bill Hammel at
bhammel@graham.main.nc.us
READ WARNING BEFORE SENDING E-MAIL