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)