Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1 6/24/83; site unisoft.UUCP Path: utzoo!watmath!clyde!burl!ulysses!mhuxr!mhuxj!houxm!ihnp4!zehntel!dual!unisoft!fnf From: fnf@unisoft.UUCP (Fred Fish) Newsgroups: net.sources Subject: cute verbose "date" Message-ID: <398@unisoft.UUCP> Date: Thu, 24-Jan-85 22:13:35 EST Article-I.D.: unisoft.398 Posted: Thu Jan 24 22:13:35 1985 Date-Received: Sun, 27-Jan-85 06:33:17 EST Organization: UniSoft Corp., Berkeley Lines: 969 [...........] Another cute little program from an old DECUS C distribution. This one puts out something of the form: "Today is Thursday, the twenty-fourth day of January, nineteen eighty-five. The time is twelve minutes and forty seconds after seven PM, Daylight Savings Time. The moon is new." --Fred #--------CUT---------CUT---------CUT---------CUT--------# ######################################################### # # # This is a shell archive file. To extract files: # # # # 1) Make a directory for the files. # # 2) Write a file, such as "file.shar", containing # # this archive file into the directory. # # 3) Type "sh file.shar". Do not use csh. # # # ######################################################### # # echo Extracting Makefile: sed 's/^Z//' >Makefile <<\STUNKYFLUFF Z# Z# Makefile for very verbose date command (today). Z ZOBJ = datetx.o moontx.o nbrtxt.o timetx.o today.o Z Ztoday: $(OBJ) Z $(CC) -o $@ $(OBJ) Z STUNKYFLUFF set `sum Makefile` if test 62527 != $1 then echo Makefile: Checksum error. Is: $1, should be: 62527. fi # # echo Extracting datetx.c: sed 's/^Z//' >datetx.c <<\STUNKYFLUFF Z# Z/* Z * Convert Date to Readable Format. Z * Z * Synopsis: Z * Z * char *datetxt(buffer, year, month, day); Z * char *buffer; -- Output string goes here Z * int year; -- Year, 1979 = 1979 Z * int month; -- Month, January = 1 Z * int day; -- Day, 1 = 1 Z * Z * The readable date will be written into the outpub buffer, terminated by Z * a null byte. datetxt returns a pointer to the null byte. Z * Z * External routines called: Z * Z * nbrtxt (Number to ascii conversion) Z * copyst (String copy routine) Z */ Z Zextern char *nbrtxt(); Zextern char *copyst(); Zextern char *datetxt(); Z Zstatic char *daynames[] = { Z "Sunday", /* Sunday is day zero */ Z "Monday", Z "Tuesday", Z "Wednesday", Z "Thursday", Z "Friday", Z "Saturday", Z}; Z Zstatic char *monthnames[] = { Z "?Nomember?", /* Illegal month */ Z "January", Z "February", Z "March", Z "April", Z "May", Z "June", Z "July", Z "August", Z "September", Z "October", Z "November", Z "December", Z}; Z Zchar *datetxt(buffer, year, month, day) Zchar *buffer; /* Output goes here */ Zint year; /* Year, 1979 = 1979 */ Zint month; /* Month of year, Jan = 1 */ Zint day; /* Day in the month 1 = 1 */ Z/* Z * Output the date in readable format: Z * Tuesday, the third of October Z */ Z{ Z register char *op; /* Output pointer */ Z Z op = buffer; /* Setup output pointer */ Z op = copyst(op, daynames[dayofweek(year, month, day)]); Z op = copyst(op, ", the "); Z op = nbrtxt(op, day, 1); Z op = copyst(op, " day of "); Z op = copyst(op, monthnames[(month < 0 || month > 12) ? 0 : month]); Z op = copyst(op, ", "); Z if (year < 1000 || year >= 2000) Z return(nbrtxt(op, year, 0)); Z else { Z op = nbrtxt(op, year/100, 0); Z op = copyst(op, " "); Z if ((year = year % 100) == 0) Z return(copyst(op, "hundred")); Z else Z return(nbrtxt(op, year, 0)); Z } Z} Z Zdayofweek(year, month, day) Zint year; /* Year, 1978 = 1978 */ Zint month; /* Month, January = 1 */ Zint day; /* Day of month, 1 = 1 */ Z/* Z * Return the day of the week on which this date falls: Sunday = 0. Z * Note, this routine is valid only for the Gregorian calender. Z */ Z{ Z register int yearfactor; Z Z yearfactor = year + (month - 14)/12; Z return (( (13 * (month + 10 - (month + 10)/13*12) - 1)/5 Z + day + 77 + 5 * (yearfactor % 100)/4 Z + yearfactor / 400 Z - yearfactor / 100 * 2) % 7); Z} STUNKYFLUFF set `sum datetx.c` if test 65180 != $1 then echo datetx.c: Checksum error. Is: $1, should be: 65180. fi # # echo Extracting moontx.c: sed 's/^Z//' >moontx.c <<\STUNKYFLUFF Z# Z/* Z * Phase of the Moon Conversion. Z * Z * Synopsis Z * Z * char *moontxt(buffer, year, month, day) Z * char *buffer; -- Output goes here. Z * int year; -- Year 1979 = 1979 Z * int month; -- Month Jan. = 1 Z * int day; -- Day 1 = 1 Z * Z * The phase of the moon (in readable ascii) is written into the buffer, Z * followed by a null. The routine returns a pointer to the trailing null. Z * Z * External routines called: Z * Z * copyst (String copy routine) Z */ Z Zextern char *copyst(); /* String output routine */ Z Zstatic char *phasetxt[] = { Z "new", Z "waxing crescent", Z "in its first quarter", Z "waxing gibbous", Z "full", Z "waning gibbous", Z "in its last quarter", Z "waning crescent" Z}; Z Zstatic int day_year[] = { /* Days in year for each month */ Z -1, -1, 30, 58, 89, 119, 150, 180, 211, 241, 272, 303, 333 Z}; /* Note: Jan. 1 will equal zero */ Z Zchar *moontxt(buffer, year, month, day) Zchar *buffer; /* Where to put the text */ Zint year; /* Year, 1978 = 1978 */ Zint month; /* Month, Jan = 1 */ Zint day; /* Day, 1 = 1 */ Z/* Z * Output the phase of the moon for the given year, month, day. Z * The routine calculates the year's epact (the age of the moon on Jan 1.), Z * adds this to the number of days in the year, and calculates the phase Z * of the moon for this date. Z * Z * In the algorithm: Z * Z * diy Is the day of the year - 1 (i.e., Jan 1 is day 0). Z * Z * golden Is the number of the year in the Mentonic cycle, used to Z * determine the position of the calender moon. Z * Z * epact Is the age of the calender moon (in days) at the beginning Z * of the year. To calculate epact, two century-based Z * corrections are applied: Z * Gregorian: (3 * cent)/4 - 12 Z * is the number of years such as 1700, 1800 when Z * leap year was not held. Z * Clavian: (((8 * cent) + 5) / 25) - 5 Z * is a correction to the Mentonic cycle of about Z * 8 days evry 2500 years. Note that this will Z * overflow 16 bits in the year 409600. Beware. Z * Z * The algorithm is accurate for the Gregorian calender only. Z * Z * The magic numbers used in the phase calculation are as follows: Z * 29.5 The moon's period in days. Z * 177 29.5 scaled by 6 Z * 22 (29.5 / 8) scaled by 6 (this gets the phase) Z * 11 ((29.5 / 8) / 2) scaled by 6 Z * Z * Theoretically, this should yield a number in the range 0 .. 7. However, Z * two days per year, things don't work out too well. Z * Z * Epact is calculated by the algorithm given in Knuth vol. 1 (calculation Z * of Easter). See also the article on Calenders in the Encyclopaedia Z * Britannica and Knuth's algorithm in CACM April 1962, page 209. Z */ Z{ Z int phase; /* Moon phase */ Z register int cent; /* Century number (1979 = 20) */ Z register int epact; /* Age of the moon on Jan. 1 */ Z register int diy; /* Day in the year */ Z int golden; /* Moon's golden number */ Z Z if (month < 0 || month > 12) month = 0; /* Just in case */ Z diy = day + day_year[month]; /* Day in the year */ Z if ((month > 2) && ((year % 4 == 0) && Z ((year % 400 == 0) || (year % 100 != 0)))) Z diy++; /* Leapyear fixup */ Z cent = (year / 100) + 1; /* Century number */ Z golden = (year % 19) + 1; /* Golden number */ Z epact = ((11 * golden) + 20 /* Golden number */ Z + (((8 * cent) + 5) / 25) - 5 /* 400 year cycle */ Z - (((3 * cent) / 4) - 12)) % 30;/* Leap year correction */ Z if (epact <= 0) Z epact += 30; /* Age range is 1 .. 30 */ Z if ((epact == 25 && golden > 11) || epact == 24) Z epact++; Z /* Z * Calculate the phase, using the magic numbers defined above. Z * Note that (phase and 7) is equivalent to (phase mod 8) and Z * is needed on two days per year (when the algorithm yields 8). Z */ Z phase = (((((diy + epact) * 6) + 11) % 177) / 22) & 7; Z return(copyst(buffer, phasetxt[phase])); Z} STUNKYFLUFF set `sum moontx.c` if test 12622 != $1 then echo moontx.c: Checksum error. Is: $1, should be: 12622. fi # # echo Extracting nbrtxt.c: sed 's/^Z//' >nbrtxt.c <<\STUNKYFLUFF Z# Z/* Z * Integer to Readable ASCII Conversion Routine. Z * Z * Synopsis: Z * Z * char *nbrtxt(buffer, value, ordinal) Z * char *buffer; -- The output buffer Z * int value; -- The number to output Z * int ordinal; -- Non-zero for ordinal number Z * Z * Z * The value is converted to a readable number and put in the output Z * buffer (null-terminated). A pointer to the first free location Z * in the buffer (i.e., the null) is returned. The ordinal Z * flag distinguishes between cardinal and ordinal numbers: Z * Z * nbrtxt(buffer, 1, 0) = "one" Z * nbrtxt(buffer, 1, 1) = "first" Z * Z * The longest output string is: Z * Z * Twenty-seven thousand, three hundred and seventy-seventh. Z * Z * Z * Z * Copy a String Z * Z * Synopsis Z * Z * char *copyst(out, in) Z * char *out; -- The output string Z * char *in; -- The input string Z * Z * The input string is copied into the output string. Copyst returns Z * a pointer to the null trailer. Z * Z */ Z Zextern char *nbrtxt(); Zextern char *copyst(); Z Zstatic char *cardinal[] = { Z "zero", Z "one", Z "two", Z "three", Z "four", Z "five", Z "six", Z "seven", Z "eight", Z "nine", Z "ten", Z "eleven", Z "twelve", Z "thirteen", Z "fourteen", Z "fifteen", Z "sixteen", Z "seventeen", Z "eighteen", Z "nineteen" Z}; Z Zstatic char *ordinal[] = { Z "zeroth", Z "first", Z "second", Z "third", Z "fourth", Z "fifth", Z "sixth", Z "seventh", Z "eighth", Z "ninth", Z "tenth", Z "eleventh", Z "twelfth" Z}; Z Zstatic char *twenties[] = { Z "twen", Z "thir", Z "for", Z "fif", Z "six", Z "seven", Z "eigh", Z "nine" Z}; Z Zchar *nbrtxt(buffer, datum, ordflag) Zchar *buffer; /* Output string buffer */ Zint datum; /* what to translate */ Zint ordflag; /* 0 if cardinal, 1 if ordinal */ Z/* Z * Translate a number to a readable text string, punctuation and all. Z * If ordflag is non-zero, ordinal numbers ("first, second") will Z * be generated, rather than cardinal ("one, two"). Z * Note: nbrtxt() is recursive. Z */ Z{ Z Z register int value; Z register char *op; Z Z op = buffer; Z value = datum; Z if (value < 0) { Z op = copyst(op, "minus "); Z value = (-value); Z if (value < 0) { /* Hack -32768 */ Z op = copyst(op, twenties[1]); Z value = 2768; Z } Z } Z if (value >= 1000) { Z op = nbrtxt(op, value/1000, 0); Z op = copyst(op, " thousand"); Z value = value % 1000; Z if (value == 0) goto exit; Z op = copyst(op, (value >= 100) ? ", " : " and "); Z } Z if (value >= 100) { Z op = copyst(op, cardinal[value/100]); Z op = copyst(op, " hundred"); Z value = value % 100; Z if (value == 0) goto exit; Z op = copyst(op, " "); Z } Z if (value >= 20) { Z if (value == 90 && ordflag) Z return(copyst(op, "nintieth")); Z op = copyst(op, twenties[(value-20) / 10]); Z value = value % 10; Z if (value == 0) { Z return(copyst(op, (ordflag) ? "tieth" : "ty")); Z } Z op = copyst(op, "ty-"); Z } Z if (value <= 12) { Z return(copyst(op, Z (ordflag) ? ordinal[value] : cardinal[value])); Z } Z op = copyst(op, cardinal[value]); /* fourteen, fourteenth */ Z /* Z * Here on 100, 14000, etc. Z */ Zexit: if (ordflag) op = copyst(op, "th"); Z return(op); Z} Z Zchar * Zcopyst(buffer, string) Zchar *buffer; Zchar *string; Z/* Z * Copy a string into buffer. Return the free pointer. Z */ Z{ Z register char *ip; Z register char *op; Z Z ip = string; Z op = buffer; Z Z while ((*op = *ip++)) op++; Z return (op); Z} STUNKYFLUFF set `sum nbrtxt.c` if test 30886 != $1 then echo nbrtxt.c: Checksum error. Is: $1, should be: 30886. fi # # echo Extracting timetx.c: sed 's/^Z//' >timetx.c <<\STUNKYFLUFF Z# Z/* Z * Convert Time to a Readable Format. Z * Z * Synopsis: Z * Z * char *timetxt(buffer, hour, minute, second, daylight); Z * char *buffer; -- Where output goes Z * int hour; -- Hour, range is 0 to 24 Z * int minute; -- Minute, range is -1 to 59 Z * int second; -- Seconds, range is -1 to 59 Z * int daylight; -- Daylight savings time if non-zero. Z * Z * Note: if minute or second is less than zero, the value is not calculated. Z * This distinguishes between "unknown seconds" and "exactly no seconds." Z * If hour is less than zero, a null string is returned. Z * Timetxt converts the time to a null-trailed string. It returns a pointer Z * to the first free byte (i.e. the null); Z * Z * The output follows the syntax of Robert J. Lurtsema, and includes: Z * Z * In twenty-five seconds, the time will be ten minutes before noon. Z * Z * Z * External routines called: Z * Z * nbrtxt (Number to ascii conversion) Z * copyst (String copy routine) Z */ Z Zextern char *nbrtxt(); Zextern char *copyst(); Z Zchar *timetxt(buffer, hour, minute, second, daylight) Zchar *buffer; /* Output buffer */ Zint hour; /* Hours 00 - 23 */ Zint minute; /* Minutes */ Zint second; /* Seconds */ Zint daylight; /* Non-zero if savings time */ Z/* Z * Output time of day. Z */ Z{ Z char *op; /* Output pointer */ Z register int late; /* after hour or afternoon */ Z register int sec; /* Seconds temp */ Z char *stuff(); /* Buffer stuffer */ Z Z op = buffer; /* Setup buffer pointer */ Z if (hour < 0) { /* If it's a dummy call, */ Z *op = 0; /* Return a null string */ Z return(op); Z } Z if (daylight == 0101010) { /* Secret flag */ Z op = copyst(op, "The big hand is on the "); Z op = nbrtxt(op, (((minute + 2 + second/30)/5 + 11)%12)+1, 0); Z op = copyst(op," and the little hand is on the "); Z op = nbrtxt(op, ((hour + 11) % 12) + 1, 0); Z return(copyst(op, ". ")); Z } Z /* Z * Check if the time is more than 30 minutes past the hour. Z * If so, output the time before the next hour. Z */ Z if (minute < 0) second = (-2); /* No minutes means no seconds */ Z else if ((late = (minute > 30 || (minute == 30 && second > 0)))) { Z if (second > 0) { /* Before next hour */ Z second = 60 - second; Z minute += 1; /* Diddle the minute, too */ Z } Z minute = 60 - minute; /* Minutes before next hour */ Z hour += 1; /* Frobozz next hour getter */ Z } Z /* Z * Decisions, decisions: Z * Minutes Seconds => Z * 00 00 Exactly Noon Z * 00 01 One second after noon Z * 01 00 Exactly one minute after noon Z * 30 00 Exactly half past noon Z * 59 00 Exactly one minute before noon Z * 59 59 In one second, the time will be noon Z */ Z if (late && second > 0) { /* Respectfully dedicated to */ Z /* Robert J. Lurtsema */ Z op = stuff(op, second, 1, "In ", " second"); Z op = copyst(op, ", the time will be "); Z sec = -2; /* We've done seconds already */ Z } Z else { Z op = copyst(op, "The time is "); Z sec = second; /* Seconds still to be done */ Z } Z if (sec == 0) { Z op = copyst(op, "exactly "); Z if (minute == 30) Z op = copyst(op, "half past "); Z else op = stuff(op, minute, 1, " ", " minute"); Z } Z else { /* Non exact or missing seconds */ Z op = stuff(op, minute, 0, " ", " minute"); Z op = stuff(op, sec, (minute > 0), " and ", " second"); Z } Z op = copyst(op, (minute < 0 || (minute == 0 && late) Z || (second == 0 Z && ((minute == 0 && late == 0) Z || minute == 30))) ? " " Z : (late) ? " before " : " after "); Z /* Z * Hours are not quite so bad Z */ Z if (hour == 0 || hour == 24) Z op = copyst(op, "midnight"); Z else if (hour == 12) Z op = copyst(op, "noon"); Z else { Z if (late = (hour > 12)) Z hour = hour - 12; Z op = nbrtxt(op, hour, 0); Z op = copyst(op, (late) ? " PM" : " AM"); Z } Z return(copyst(op, (daylight) Z ? ", Daylight Savings Time. " Z : ", Digital Standard Time. ")); Z} Z Zstatic char * Zstuff(buffer, value, flag, leading, trailing) Zchar *buffer; /* Output goes here */ Zint value; /* The value to print if > 0 */ Zint flag; /* flag is set to print leading */ Zchar *leading; /* preceeded by ... */ Zchar *trailing; /* and followed by ... */ Z/* Z * If value <= zero, output nothing. Else, output "leading" value "trailing". Z * Note: leading is output only if flag is set. Z * If value is not one, output an "s", too. Z */ Z{ Z register char *op; /* Output pointer */ Z Z op = buffer; /* Setup buffer pointer */ Z if (value > 0) { Z if (flag) Z op = copyst(op, leading); Z op = nbrtxt(op, value, 0); Z op = copyst(op, trailing); Z if (value != 1) Z op = copyst(op, "s"); Z } Z return(op); Z} STUNKYFLUFF set `sum timetx.c` if test 32974 != $1 then echo timetx.c: Checksum error. Is: $1, should be: 32974. fi # # echo Extracting today.c: sed 's/^Z//' >today.c <<\STUNKYFLUFF Z# Z/* Z * T O D A Y Z * Z * time of day Z * Z * Define UNIX for "native" Unix Z */ Z Z/*)BUILD $(PROGRAM) = today Z $(FILES) = { today datetx timetx nbrtxt moontx } Z $(TKBOPTIONS) = { Z TASK = ...TOD Z } Z*/ Z Z#ifdef DOCUMENTATION Z Ztitle today Date and Time in English Zindex Date and Time in English Z Zsynopsis Z Z today [-] [x] | [date] Z Zdescription Z Z Today prints the date, time, and phase of the moon in English. Z The following options are available: Z .lm +8 Z .s.i -8;- or x Read date strings from the standard input file. Z .s.i -8;date Print information for the indicated date. Z .s.lm -8 Z Date and time information is given in ISO numeric notation. For Z example, November 6, 1980 would be represented as "801106". If Z a time is needed, it would be appended to the date, using 24-hour Z notation: "801106110402" would be a time which is exact to the Z second. To specify the century, the two-digit century number Z may be preceeded by '+' as in "+18801106". Z .s Z Non-numeric separators between the various fields are permitted: Z "+1776.07.04-11:15:21". Note that the full two digit entry must be Z given. Z .s Z If no parameter is given, today outputs the current date and time. Z Zdiagnostics Z Z .lm +8 Z .s.i -8;Bad parameters or date out of range in ... Z .s Z An input date or time is incorrect. Z .lm -8 Z Zauthor Z Z Martin Minow Z Zbugs Z Z The algorithm is only valid for the Gregorian calender. Z Z#endif Z Z#define APRIL_FOOLS Z Zint __narg = 1; /* No prompt if no args */ Z#define LINEWIDTH 72 /* Width of line */ Z Z#include Z#include Z#ifdef unix Z#include Z#undef NULL Z#endif Z Z#define NULL 0 Z#define EOS 0 Z#define FALSE 0 Z#define TRUE 1 Z Zint day_month[] = { /* Needed for dotexttime() */ Z 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 Z}; Zint ccpos; /* Current line position */ Zchar lastbyte; /* Memory for output() */ Zchar line[100]; /* Data line for input function */ Zchar *valptr; /* Needed for number converter */ Zchar wordbuffer[LINEWIDTH]; /* Buffer for output function */ Zchar *wordptr = wordbuffer; /* Free byte in wordbuffer */ Zchar linebuffer[LINEWIDTH+2]; /* Output text buffer */ Zchar *lineptr = linebuffer; /* Free byte in linebuffer */ Zint polish; /* Funny mode flag */ Z Zextern char *datetxt(); /* Date getter */ Zextern char *timetxt(); /* Time of day getter */ Zextern char *moontxt(); /* Phase of the moon getter */ Z Zmain(argc, argv) Zint argc; Zchar *argv[]; Z/* Z * Driver for time routines. Usage: Z * Z * today Prints current time of day in readable form, Z * followed by a cookie. Z * Z * today {+cc}yymmddhhmmss Prints indicated time of day. Z * Note, hh, mm, ss may be omitted. Z * For example: Z * today 401106 = Nov. 6, 1940 Z * today +19401106 = Nov. 6, 1940 Z * today 4011061015 = Nov. 6, 1940 10:15 AM Z * Z * today - Data is read from the standard input and Z * today x output as needed. The format of each Z * line is identical to the command format. Z * ("today x" is needed for vms.) Z */ Z Z{ Z ccpos = 0; /* New line now */ Z wordptr = wordbuffer; /* Nothing buffered */ Z lineptr = linebuffer; /* Nothing in output buffer too */ Z polish = 0; /* Normal mode */ Z if (argc > 1 && tolower(argv[1][0]) == 'p') { Z polish = 1; Z argc--; Z argv++; Z } Z if (argc == 2 && ((argv[1][0] == '-') || (argv[1][0] | 040) == 'x')) { Z while (!getline()) { /* Read and print times */ Z dotexttime(line); Z } Z return; Z } Z else if (argc > 1) { Z if (dotexttime(argv[1]) == 0) Z return; Z } Z /* Z * Here if no parameters or an error in the parameter field. Z */ Z dotime(); /* Print the time. */ Z output("\n"); /* Space before cookie */ Z#ifdef UNIX Z execl(COOKIEPROGRAM, "cookie", 0); Z#endif Z} Z Zdotime() Z/* Z * Print the time of day for Unix or VMS native mode. Z */ Z{ Z int tvec[2]; /* Buffer for time function */ Z struct tm *localtime(); /* Unix time decompile function */ Z struct tm *p; /* Local pointer to time of day */ Z int year; Z int month; Z Z time(tvec); /* Get the time of day */ Z p = localtime(tvec); /* Make it more understandable */ Z year = p->tm_year + 1900; Z month = p->tm_mon + 1; Z#ifdef APRIL_FOOLS Z if (month == 4 && p->tm_mday == 1) Z polish = !polish; Z#endif Z process(year, month, p->tm_mday, p->tm_hour, Z p->tm_min, p->tm_sec, p->tm_wday); Z} Z Zdotexttime(text) Zchar *text; /* Time text */ Z/* Z * Create the time values and print them, return 1 on error. Z */ Z Z{ Z int epoch; /* Which century */ Z int year; Z int month; Z int day; Z int hour; Z int minute; Z int second; Z int leapyear; Z Z valptr = text; /* Setup for getval() */ Z while (*valptr == ' ') valptr++; /* Leading blanks skip */ Z if (*valptr != '+') Z epoch = 1900; /* Default for now */ Z else { Z valptr++; Z if ((epoch = getval(-1, 00, 99)) < 0) goto bad; Z epoch *= 100; /* Make it a real epoch */ Z } Z Z if ((year = getval(-1, 00, 99)) < 0) goto bad; Z year += epoch; Z leapyear = ((year%4) == 0) && (((year%400) == 0) || (year%100 != 0)); Z if ((month = getval(-1, 1, 12)) < 0) goto bad; Z if ((day = getval(-1, 1, Z (month == 2 && leapyear) ? 29 : day_month[month])) < 0) Z goto bad; Z if ((hour = getval(-2, 0, 23)) == -1) goto bad; Z if ((minute = getval(-2, 0, 59)) == -1) goto bad; Z if ((second = getval(-2, 0, 59)) == -1) goto bad; Z process(year, month, day, hour, minute, second, 0); Z return(0); /* Normal exit */ Z Zbad: output("Bad parameters or date out of range in \""); Z output(text); Z output("\" after scanning \""); Z *valptr = '\0'; Z output(text); Z output("\".\n"); Z return(1); /* Error exit */ Z} Z Zstatic char outline[500]; /* Output buffer */ Z Zprocess(year, month, day, hour, minute, second, daylight) Zint year; /* Year 1900 = 1900 */ Zint month; /* Month January = 1 */ Zint day; /* Day 1 = 1 */ Zint hour; /* Hour 0 .. 23 */ Zint minute; /* Minute 0 .. 59 */ Zint second; /* Second 0 .. 59 */ Zint daylight; /* Daylight savings time if 1 */ Z/* Z * Output the information. Note that the parameters are within range. Z */ Z{ Z Z output("Today is "); Z datetxt(outline, year, month, day); Z output(outline); Z output(". "); Z timetxt(outline, hour, minute, second, Z (polish) ? 0101010 : daylight); Z output(outline); Z output("The moon is "); Z moontxt(outline, year, month, day); Z output(outline); Z output(". \n"); Z} Z Z Zoutput(text) Zchar *text; /* What to print */ Z/* Z * Output routine. Text is output using put() so that lines are Z * not more than LINEWIDTH bytes long. Current position is in global ccpos. Z * (put is equivalent to putchar() except that it is locally buffered.) Z */ Z{ Z register char *in; /* Current pos. in scan */ Z register char c; /* Current character */ Z register char *wp; /* Word pointer */ Z Z in = text; Z while (c = *in++) { Z switch (c) { Z case '\n': /* Force new line */ Z case ' ': /* or a space seen */ Z if ((wordptr-wordbuffer) + ccpos >= LINEWIDTH) { Z put('\n'); /* Current word */ Z ccpos = 0; /* won't fit, dump it. */ Z } Z if (wordptr > wordbuffer) { Z if (ccpos) { /* Leading space needed */ Z put(' '); Z ccpos++; Z } Z for (wp = wordbuffer; wp < wordptr;) { Z put(*wp++); Z } Z ccpos += (wordptr - wordbuffer); Z wordptr = wordbuffer; /* Empty buffer */ Z } Z if (c == '\n') { Z put('\n'); /* Print a newline */ Z ccpos = 0; /* and reset the cursor */ Z } Z break; Z Z default: Z *wordptr++ = c; /* Save piece of word */ Z } Z } Z} Z Zput(c) Zregister char c; Z/* Z * Actual output routine Z */ Z{ Z if (c == '\n' || (lineptr - linebuffer) >= LINEWIDTH) { Z *lineptr = EOS; Z puts(linebuffer); Z lineptr = linebuffer; Z if (c == '\n') Z return; Z } Z *lineptr++ = c; Z} Z Zgetline() Z/* Z * Read text to global line[]. Return 1 on end of file, zero on ok. Z */ Z{ Z register char *t; Z Z return (gets(line) == NULL); Z} Z Zgetval(flag, low, high) Zint flag; Zint low; Zint high; Z/* Z * Global valptr points to a 2-digit positive decimal integer. Z * Skip over leading non-numbers and return the value. Z * Return flag if text[0] == '\0'. Return -1 if the text is bad, Z * or if the value is out of the low:high range. Z */ Z{ Z register int value; Z register int i; Z register int temp; Z Z if (*valptr == '\0') return(flag); /* Default? */ Z while (*valptr && (*valptr < '0' || *valptr > '9')) *valptr++; Z /* The above allows for 78.04.22 format */ Z for (value = i = 0; i < 2; i++) { Z temp = *valptr++ - '0'; Z if (temp < 0 || temp > 9) return(-1); Z value = (value*10) + temp; Z } Z return((value >= low && value <= high) ? value : -1); Z} Z STUNKYFLUFF set `sum today.c` if test 43354 != $1 then echo today.c: Checksum error. Is: $1, should be: 43354. fi echo ALL DONE BUNKY! exit 0