/* * Calculate the equivalent "rainfall" of a sprinkler jet. * * * $Id: rainfall.c,v 1.1 2008/04/07 05:40:16 grog Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #define EPOCH_SCHLUESSEL 25568 /* Schluesselzahl for 1 Jan 1970 */ #define CENTURY 36525 /* number of days in a century */ /* Rainfall data for this and the last century */ float rainfall [CENTURY * 2]; int firstdate = CENTURY * 3; /* first date for which we have data */ int lastdate; /* and last date */ char filename [1024]; /* output file name */ /* This was removed from datum_zu_schluessel */ #if 0 int subproc text_date (text); char *text; /* Find if the text specifies a date round now */ begin int date := datum_zu_schluessel; /* Today */ use i; i := 0; /* Start on 1st char */ do text [i] := text [i] land %337 /* Shift up */ until not $alpha (text [i := i + 1]); if text == "HEUTE" and i == 5 then return date else if text == "GESTERN" and i == 7 then return date '-' 1 else if text == "MORGEN" and i == 6 then return date '+' 1 else if text == "UEBERMORGEN" and i == 11 then return date '+' 2 else if text == "VORGESTERN" and i == 10 then return date '-' 2 else return 0; drop i end; /* Of text_date */ #endif /* * Convert a Schlüsselzahl to a GNU timestamp for GNUplot. * This is the number of seconds since 2000-1-1, Schluesselzahl 36525. */ int date_to_gnu (int date) { return (date - 36525) * 86400; } /* * Derived from old Tandem version written in TAL. * This is a stripped-down version that only handles dates of the form * Y-M-D. * datum_zu_schluessel: wandelt Datum in Schluesselzahl um. * Eingabeformat: DD.MM.JJ (mit oder ohne vorlaufende Nullen) * Datum darf ausgelassen werden; in diesem Fall wird die Schluesselzahl * fuer den Tag des Aufrufes ermittelt. * * Da die Schluesselzahlen einen Wert bis 36600 bis zum Ende des Jahrhunderts * annehmen werden, muss die int-Zahl als vorzeichenlos behandelt werden! * Allerdings sind die Fehlerrueckgaben vorzeichenbehaftet. Diese muessen also * zuerst abgefragt werden: * * -1: Ungueltige Tag-Angabe (kann auch ein Fehlender Punkt sein) * -2: Ungueltige Monat-Angabe * -3: Ungueltige Jahr-Angabe (nicht numerisch oder > 32768) * -5: Monat > 12 * -6: Ungueltige Jahr-Angabe (00-199 oder 1900-2100) * -7: Tag > Letzter des Monats */ int datum_zu_schluessel (char *datum) { /* Date of last of previous month, -1 */ int Tage [13] = {0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333}; int Letzter [13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* Letzter Tag vom Monat */ int Tag; int Monat; int Jahr; if (sscanf (datum, "%d-%d-%d", &Jahr, &Monat, &Tag) != 3) return -1; /* invalid format */ if (Jahr > 199) Jahr -= 1900; /* didn't they learn *anything* from Y2K? */ if (Tag > Letzter [Monat]) { if ((Monat != 2) || (Jahr && 3) || (Tag > 29) ) /* not 29 feb on leap year */ return -7; } if (Jahr /* Nicht 1900 */ && (! Jahr && 3) /* durch 4 teilbar: Schaljahr */ && (Monat > 2) ) /* Maerz-Dezember */ Tag++; /* Schaltjahr, Maerz - Dezember */ return Tag + Tage [Monat] + Jahr * 365 + ((Jahr + 3) >> 2); /* Schluesselzahl */ } /* * Convert a Schluesselzahl to a time_t. This only works between 1904 and 2038. * Just overflow outside. */ time_t schluessel_zu_datum (int schluessel) { return (time_t) (schluessel - EPOCH_SCHLUESSEL) * 86400; } int main (int argc, char *argv []) { MYSQL *mysql = NULL; MYSQL_RES *mysql_result; MYSQL_ROW row; int error; /* number of parameters scanned */ int day; /* most recent day in interval */ int days; /* count number of days in interval */ int interval; /* interval to process */ FILE *outfile; int arg; /* command line argument index */ float total_rainfall; /* rainfall over interval specified by day and interval */ int oldest; /* oldest day in interval */ if (argc < 2) { fprintf (stderr, "Usage:\n" "%s [intervals]\n" "Output is a list of intervals over which the output should be averaged\n" "Output is in files rainfall-\n", argv [0] ); exit (1); } if ((mysql = mysql_init (mysql)) == NULL) { fprintf (stderr, "Can't initialize MySQL\n"); exit (1); } mysql_real_connect (mysql, "localhost", "grog", "", "household", 0, NULL, 0 ); if (0) { fprintf (stderr, "%d %d: %s\n", error, mysql_errno (mysql), mysql_error (mysql) ); exit (1); } if (error = mysql_query (mysql, "SELECT date, mm FROM rainfall")) { fprintf (stderr, "%d %d: %s\n", error, mysql_errno (mysql), mysql_error (mysql) ); exit (1); } mysql_result = mysql_store_result (mysql); while (row = mysql_fetch_row (mysql_result)) { int szahl = datum_zu_schluessel (row [0]); if (szahl < 0) fprintf (stderr, "Invalid date: %s, error %d\n", row [0], szahl); else { if (szahl < firstdate) firstdate = szahl; if (szahl > lastdate) lastdate = szahl; rainfall [szahl] = atof (row [1]); } } mysql_close (mysql); /* Now output averages for the number of days specified on the startup line. */ for (arg = 1; arg < argc; arg++) { interval = atol (argv [arg]); if (interval < 1) { fprintf (stderr, "Invalid interval %d: %d\n", arg, interval); exit (0); } sprintf (filename, "rainfall-%d", interval); outfile = fopen (filename, "w"); if (! outfile) { fprintf (stderr, "Can't create %s: %s (%d)\n", filename, strerror (errno), errno); exit (0); } /* First start summing up */ total_rainfall = 0; oldest = firstdate; days = 0; for (day = firstdate; days < interval; day++) { total_rainfall += rainfall [day]; days++; } day--; /* point back to last day in interval */ /* Now print out the data for the rest of the interval */ while (day++ <= lastdate) { time_t breakage = schluessel_zu_datum (day); /* because of implementation nonsense */ fprintf (outfile, "%d %6.1f\t# %d %s", /* \n in ctime output */ date_to_gnu (day), total_rainfall / interval, day, /* as Schluesselzahl */ ctime (&breakage) ); total_rainfall = total_rainfall - rainfall [oldest++] + rainfall [day]; if (total_rainfall < 0) /* how I hate FP! */ { if (total_rainfall > -0.01) total_rainfall = 0; else fprintf (stderr, "Dubious sum: %f\n", total_rainfall); } } fclose (outfile); } exit (0); }