ajs@hpfcla.UUCP (01/07/84)
#N:hpfcla:43600003:000:9109 hpfcla!ajs Jan 5 22:16:00 1984 Due to the response to my article in net.auto, I'm posting a gas mileage compiler, manual page, and cute (but undocumented) shell script here, the proper place for it. It's not a shell archive; sorry, you'll have to unpack this manually. Also, the manual page has never been through nroff -- WYSIWYG (what you see is what you get). Enjoy! Alan Silverstein, Hewlett-Packard Fort Collins Systems Division, Colorado {ihnp4 | hplabs}!hpfcla!ajs, 303-226-3800 x3053, N 40 31'31" W 105 00'43" ---------- gas.c ---------- /* * Read raw gas mileage data and print statistics. * * See the manual page for more information. * * Copyright Hewlett-Packard Company, 1984. Permission is granted for * unlimited modification, use, and distribution, except that this software * may not be sold for profit directly nor as part of any software package. * This software is made available with no warranty of any kind, express * or implied. * * Author: * Alan Silverstein, Hewlett-Packard Fort Collins Systems Division * {ihnp4 | hplabs}!hpfcla!ajs */ #include <stdio.h> #define ANNUAL 0 /* for printline() */ #define TOTAL -1 /* * Line formats: */ char *HEAD = "NUM DATE DAYS MILEAG MILES GALS COST PL MPG MPD CPG CPD\n"; char *SEP = "=== ====== ==== ====== ===== ===== ====== == ==== === ==== =====\n"; char *LINE0 = "%3d %6d %7d\n"; char *LINE = "%3d %6d %5d %7d %6d %6.1f %7.2f %2s"; char *LINET = " %5d %6d %6.1f %7.2f "; char *AVG = " %5.1f %5.0f %5.2f %5.2f"; int cflag; /* chart requested? */ char *myname; /* how invoked */ long Adays = 0; /* annual subtotals */ long Amiles = 0; float Agallons = 0; float Adollars = 0; long Tdays = 0; /* grand totals */ long Tmiles = 0; float Tgallons = 0; float Tdollars = 0; /****************************************************************/ main (argc, argv) int argc; char **argv; { long fields; /* number read in */ long number; /* current line number */ long prevdate; /* previous date */ long date; /* current date */ long days; /* since previous */ long prevodom; /* previous odometer */ long odometer; /* current odometer */ long miles; /* since previous */ long dgallons; /* current decigallons */ float gallons; /* current gallons */ long pennies; /* current cost */ float dollars; /* dollars and cents */ char place[3]; /* where bought */ /* * Check args and open input file: */ myname = *argv++; if (cflag = (! strcmp (*argv, "-c"))) { argc--; argv++; } if (argc != 2) usage(); if (freopen (*argv, "r", stdin) == NULL) { fprintf (stderr, "%s: can't open %s\n", myname, *argv); exit (1); } /* * Print header and first line: */ printf (HEAD); printf (SEP); /* * Read lines and print data: */ for (number = 0; ; number++) { fields = scanf ("%d%d%d%d%s", &date, &odometer, &dgallons, &pennies, place); if (fields == EOF) break; if (fields != 5) { fprintf (stderr, "%s: invalid input line %d\n", myname, number); exit (1); } if (number == 0) /* first line only */ printf (LINE0, 0, date, odometer); else { days = julian (date) - julian (prevdate); miles = odometer - prevodom; gallons = dgallons / 10.0; dollars = pennies / 100.0; if ((date / 10000) != (prevdate / 10000)) /* new year */ printline (ANNUAL, 0, Adays, 0, Amiles, Agallons, Adollars, ""); printline (number, date, days, odometer, miles, gallons, dollars, place); } prevdate = date; prevodom = odometer; } /* for */ printline (ANNUAL, 0, Adays, 0, Amiles, Agallons, Adollars, ""); printline (TOTAL, 0, Tdays, 0, Tmiles, Tgallons, Tdollars, ""); } /**************************************************************** * Tell correct usage: */ usage () { fprintf (stderr, "usage: %s [-c] gasdatafile\n", myname); exit (1); } /**************************************************************** * Convert to Julian date (within century): */ julian (date) long date; /* number in YYMMDD format */ { static days[] = { /* days before starts of months */ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; long year = (date / 10000); long month = (date / 100) % 100; long day = (date % 100); long leap = (year / 4) - (((year % 4) == 0) && (month < 3)); return ((year * 365) + (days [month - 1]) + day + leap); } /**************************************************************** * Print one line (data, subtotal, or total): * Increments [sub]totals as needed. */ printline (number, date, days, odometer, miles, gallons, dollars, place) long number; /* line num or type */ long date; /* if normal line */ long days; /* delta or total */ long odometer; /* if normal line */ long miles; /* delta or total */ float gallons; /* current or total */ float dollars; /* current or total */ char *place; /* if normal line */ { int normal = ((number != ANNUAL) && (number != TOTAL)); if (normal) { printf (LINE, number, date, days, odometer, miles, gallons, dollars, place); Adays += days; /* increment subtotals */ Amiles += miles; Agallons += gallons; Adollars += dollars; } else { if (number == ANNUAL) printf ("\n"); /* no need before TOTAL */ printf (LINET, days, miles, gallons, dollars); if (number == ANNUAL) /* increment totals */ { Tdays += Adays; Tmiles += Amiles; Tgallons += Agallons; Tdollars += Adollars; Adays = 0; Amiles = 0; Agallons = 0; Adollars = 0; } } days += (days < 1); /* don't divide by zero */ printf (AVG, (miles / gallons), (miles / (days + 0.0)), (dollars / gallons), (dollars / days)); if (normal) { if (cflag) /* add chart to right */ { long mpg = (miles / gallons + 0.5); printf ("%*s*\n", mpg, ""); } else printf ("\n"); } else printf ("\n\n"); } ---------- gas.1 ---------- GAS(1) HP EXPERIMENTAL GAS(1) NAME gas -- gas mileage "compiler" SYNOPSIS gas [-c] gasdatafile DESCRIPTION This program reads lines of gas mileage data from a file and "compiles" it to a final form (e.g., prints a report). Each input line is of the form: DATE ODOMETER DECIGALLONS PENNIES PLACE Fields are separated by white space. DATE is the date gas was bought (YYMMDD == year, month, day). ODOMETER is the mileage reading to the nearest mile. DECIGALLONS is the gallons and tenths bought, without a decimal point. PENNIES is the cost of the gas, again without a decimal point. PLACE is a two-character alpha field, free-form, representing the brand name of the gas. For example: 840105 50345 84 1132 EX The first input line is an initialization entry; only DATE and ODOMETER must be valid. The output starts with two header lines followed by data lines. Each input line generates one output line containing these fields: NUM DATE DAYS MILEAG MILES GALS COST PL MPG MPD CPG CPD NUM is a sequence number. DATE is the same as before; DAYS is the number of days elapsed since the last DATE. MILEAG is as before; MILES is the elapsed mileage. GALS is the gallons and tenths (with decimal point); COST is the dollars and cents; PL is the place. MPG and MPD are the miles per gallon and per day, respectively. CPG and CPD are the cost per gallon and per day. All averages are rounded as appropriate and division by zero DAYS is avoided. Each time the year changes, the program inserts a special line showing subtotals for DAYS, MILES, GALS, and COST, and averages for MPG, MPD, CPG, and CPD. A similar grand totals line is printed at the end. The output format just fits in 80 columns. The -c (chart) option causes the program to add blanks and stars to the right of each detail line, so as to chart the MPG (try it). This output fits in 132 columns as long as your MPG isn't incredibly high. DIAGNOSTICS Prints an appropriate error message to standard error and returns nonzero if invoked wrong, if it can't open gasdatafile, or if any input line doesn't scan correctly. AUTHOR Alan Silverstein, Hewlett-Packard Fort Collins Systems Division {ihnp4 | hplabs}!hpfcla!ajs (Distributed to USENET on 840105) ---------- gaspl ---------- # Script to show statistics on places gas was bought. file=gasdata # where to read data. awk <$file ' NR > 1 {print $5}' | # get places from "real" lines. sort | uniq -c | # count each type. sort -nr | # show greatest first. sed \ -e "s/66/Phillips 66/" \ -e "s/76/Union 76/" \ -e "s/AR/Arco/" \ -e "s/CH/Chevron/" \ -e "s/CO/Conoco/" \ -e "s/EX/Exxon/" \ -e "s/HU/Husky/" \ -e "s/MO/Mobil/" \ -e "s/PE/Pester/" \ -e "s/RO/Royal/" \ -e "s/SH/Shell/" \ -e "s/SI/Sinclair/" \ -e "s/SK/Skelly/" \ -e "s/TE/Texaco/" \ -e "s/VI/Vickers/" | # unabbreviate places. awk ' {print; sum += $1} END {printf ("%4d\n", sum)} # add a total. '