[net.sources] Gas mileage compiler

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.
'