cute verbose "date"

Fred Fish fnf at unisoft.UUCP
Fri Jan 25 13:13:35 AEST 1985


[...........]

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 <stdio.h>
Z#include <time.h>
Z#ifdef unix
Z#include <ctype.h>
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



More information about the Comp.sources.unix mailing list