[mod.sources] v08i081: Phase of the moon, date routines

sources-request@mirror.UUCP (02/28/87)

Submitted by: Jef Poskanzer <unisoft!charming>
Mod.sources: Volume 8, Issue 81
Archive-name: phoon

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README Makefile deltime.c deltime.man dtime.c dtimep.lex lexedit.sed
#	lexstring.c libtws.man parsetime.c phoon.c phoon.man tws.h
# This archive created by
# Jef Poskanzer (Paratheo-Anametamystikhood Of Eris Esoteric, Ada Lovelace Cabal)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(2571 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XSecond distribution of phoon, deltime, and libtws - 24feb87.
X
X
XThis package contains two programs and a library:
X
X    phoon - program to display the PHase of the mOON.  Unlike other
X    such programs, which just tell you how long since first quarter
X    or something like that, phoon *shows* you the phase with a little
X    picture.  I've put an example at the end of this file.  I first
X    wrote this program in Pascal / TOPS-20 at CMU in 1979; I translated
X    it to Ratfor / Software Tools in 1981; and now it's in C / Unix*.
X
X    deltime - program to subtract date/times.  Tells you the difference
X    between two date/times, or between now and a specified date/time.
X    I once used this to help a friend quit smoking - every time she
X    logged in, the computer told her how many days since her last
X    cigarette.  I also use it in my .login, to tell me how old I am.
X
X    libtws - date/time library.  Unlike the standard Unix*
X    date/time routines, libtws lets you parse a date/time string
X    into internal form.  Most of this library came from version
X    6.5 of the MH message handling system, courtesy of Marshall Rose.
X    I extended it somewhat and added the manual entry.
X
X
XFiles in this distribution:
X
X    README		this
X    Makefile		guess
X    deltime.c		source for time subtraction tool
X    deltime.man		manual for time subtraction tool
X    dtime.c		source for most of the time routines
X    dtimep.lex		source for time-parsing routine
X    lexedit.sed		script to modify output of lex
X    lexstring.c		front end for time-parsing routine
X    libtws.man		manual for time library
X    parsetime.c		source for test program
X    phoon.c		source for phase of moon program
X    phoon.man		manual for phase of moon program
X    tws.h		include file for time library
X
X
XUnpack the files, edit Makefile and change the options to suit,
Xmake, and enjoy!  I've tested this stuff under 4.2 BSD, 4.3 BSD,
Xand System V rel 2.  Nevertheless, I'm sure bugs remain.  Feedback
Xis welcome - send bug reports, enhancements, checks, money orders,
Xetc. to the addresses below.
X
X
X     Jef Poskanzer, UniSoft Systems, Berkeley
X	 unisoft!jef@ucbvax.Berkeley.Edu
X	      ...ucbvax!unisoft!jef
X		  (415)644-1230
X
X
X* Unix is a virus from outer space.
X
X
X                 .--
X             .--
X          .-' 
X       .-'@ 
X      /@@@ 
X    ./    
X   /@@  o
X  /@@@@  
X  |@@@@@
X /@@@@@ 		Last Quarter + 
X | @@@@ 		4  1:36:10
X |@ @@@		New Moon -     
X |      		3  7:34:53
X \  . @ 
X  |     
X  \     @
X   \  o  
X    `\    
X      \    
X       `-.  
X          `-. 
X             `--
X                 `--
SHAR_EOF
if test 2571 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 2571 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(2137 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X# Makefile for phoon, deltime, parsetime, and libtws (stolen from mh).
X
X
X# Valid options:
X#   BSD42      Set this if your system is BSD 4.2 or later.
X#   SYS5       Set this if your system is System V.
X#   EUROPE     Makes nn/nn/nn mean dd/mm/yy instead of mm/dd/yy.
X#   ATZ        This has something to do with alpha-numeric time zones.
X#   DSTXXX     This has something to do with daylight savings time.
X#   HUJI       I don't
X#   INETONLY           know what
X#   LEXDEBUG                     the rest of these
X#   ONECASE                                        do.
XOPTIONS	=	-DBSD42 -DATZ -DDSTXXX -DONECASE
X
X
XCC      =	cc
XCFLAGS  =	-O $(OPTIONS)
XLDFLAGS =	-ns
X
X.SUFFIXES:	.man .cat
X.man.cat:
X		nroff -h -man $< > $@
X
X
Xall:		phoon phoon.cat deltime deltime.cat libtws.cat
X
X
Xphoon:		phoon.o libtws.a
X		$(CC) $(LDFLAGS) -o phoon phoon.o -lm libtws.a
X
Xphoon.o:	phoon.c tws.h
X
X
Xdeltime:	deltime.o libtws.a
X		$(CC) $(LDFLAGS) -o deltime deltime.o libtws.a
X
Xdeltime.o:	deltime.c tws.h
X
X
Xparsetime:	parsetime.o libtws.a
X		$(CC) $(LDFLAGS) -o parsetime parsetime.o libtws.a
X
Xparsetime.o:	parsetime.c tws.h
X
X
Xlibtws.a:	dtime.o dtimep.o lexstring.o
X		ar r libtws.a dtime.o dtimep.o lexstring.o
X# The following amusing bullshit makes sure that ranlib
X# gets executed if it is present, no matter which shell
X# make uses.  If there's a better way to do this, someone
X# please tell me!
X		-if test -r /usr/bin/ranlib ; then ranlib libtws.a ; fi
X		-if ( -r /usr/bin/ranlib ) ranlib libtws.a
X
X
Xdtime.o:	dtime.c tws.h
X
X
Xdtimep.o:	dtimep.c tws.h
X
Xdtimep.c:	dtimep.lex
X		lex -nt dtimep.lex | sed -f lexedit.sed > dtimep.c
X
X
Xlexstring.o:	lexstring.c
X		$(CC) $(CFLAGS) -c lexstring.c
X
X
Xclean:
X		-rm -f dtimep.c *.o libtws.a phoon deltime parsetime *.cat phoon.shar* core
X
Xphoon.shar:	phoon.shar1 phoon.shar2
X
Xphoon.shar1:	README Makefile deltime.c deltime.man dtime.c dtimep.lex
X		shar -v -c -p X README Makefile deltime.c deltime.man dtime.c dtimep.lex > phoon.shar1
X
Xphoon.shar2:	lexedit.sed lexstring.c libtws.man parsetime.c phoon.c phoon.man tws.h
X		shar -v -c -p X lexedit.sed lexstring.c libtws.man parsetime.c phoon.c phoon.man tws.h > phoon.shar2
SHAR_EOF
if test 2137 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 2137 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'deltime.c'" '(2156 characters)'
if test -f 'deltime.c'
then
	echo shar: will not over-write existing file "'deltime.c'"
else
sed 's/^X//' << \SHAR_EOF > 'deltime.c'
X/* deltime.c - subtract date/times
X
Xver  date   who remarks
X--- ------- --- -------------------------------------------------------------
X01B 15nov86 JP  Modified to use twsubtract().
X01A 08nov86 JP  Written.
X
XCopyright (C) 1986 by Jef Poskanzer.  Permission to use, copy,
Xmodify, and distribute this software and its documentation for any
Xpurpose and without fee is hereby granted, provided that this copyright
Xnotice appear in all copies and in all supporting documentation.  No
Xrepresentation is made about the suitability of this software for any
Xpurpose.  It is provided "as is" without express or implied warranty.
X
X*/
X
Xstatic char copyright[] = "\nCopyright (C) 1986 by Jef Poskanzer.\n";
X
X
X#include "tws.h"
X#include <stdio.h>
X
X#define SECSPERMINUTE 60
X#define SECSPERHOUR (60 * SECSPERMINUTE)
X#define SECSPERDAY (24 * SECSPERHOUR)
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X    {
X    struct tws tws1, tws2, *twp;
X    long delta, days, hours, minutes, secs;
X    char *illdt = "illegal date/time: %s\n";
X
X    if ( argc == 2 )
X	{
X	twp = dparsetime( argv[1] );
X	if ( twp == NULL || twp -> tw_flags & TW_JUNK )
X	    {
X	    fprintf( stderr, illdt, argv[1] );
X	    exit( 1 );
X	    }
X	twscopy( &tws1, twp );
X	twscopy( &tws2, dtwstime( ) );
X	}
X    else if ( argc == 3 )
X	{
X	twp = dparsetime( argv[1] );
X	if ( twp == NULL || twp -> tw_flags & TW_JUNK )
X	    {
X	    fprintf( stderr, illdt, argv[1] );
X	    exit( 1 );
X	    }
X	twscopy( &tws1, twp );
X	twp = dparsetime( argv[2] );
X	if ( twp == NULL || twp -> tw_flags & TW_JUNK )
X	    {
X	    fprintf( stderr, illdt, argv[2] );
X	    exit( 1 );
X	    }
X	twscopy( &tws2, twp );
X	}
X    else
X	{
X	fprintf( stderr, "usage:  %s  <time>  [ <time2> ]\n", argv[0] );
X	exit( 1 );
X	}
X    
X    delta = twsubtract( &tws2, &tws1 );
X    if ( delta < 0 )
X	{
X	printf( "-" );
X	delta = -delta;
X	}
X
X    days = delta / SECSPERDAY;
X    delta = delta - days * SECSPERDAY;
X    hours = delta / SECSPERHOUR;
X    delta = delta - hours * SECSPERHOUR;
X    minutes = delta / SECSPERMINUTE;
X    delta = delta - minutes * SECSPERMINUTE;
X    secs = delta;
X
X    printf( "%ld %2ld:%02ld:%02ld\n", days, hours, minutes, secs );
X
X    exit( 0 );
X    }
SHAR_EOF
if test 2156 -ne "`wc -c < 'deltime.c'`"
then
	echo shar: error transmitting "'deltime.c'" '(should have been 2156 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'deltime.man'" '(803 characters)'
if test -f 'deltime.man'
then
	echo shar: will not over-write existing file "'deltime.man'"
else
sed 's/^X//' << \SHAR_EOF > 'deltime.man'
X.TH example 1 "08 November 1986"
X.SH NAME
Xdeltime \- compute a delta time
X.SH SYNOPSIS
X.in +.5i
X.ti -.5i
Xdeltime  <time>  \%[ <time2> ]
X.in -.5i
X.SH DESCRIPTION
X.PP
X.I Deltime
Xcomputes the elapsed time between now and a
Xspecified date/time, or between two specified date/times.
XThe format for specifying date/times is pretty loose - basically
Xthe same as the format for date/times in network mail.
XJust be careful to put them in quotes if they contain spaces.
XThe output format is dddd hh:mm:ss.
X.PP
XTimes earlier than 1970
X.I can
Xbe handled, because the internal Unix* time format is not used.
XHowever, time spans greater than 66 years
X.I cannot
Xbe handled, because that's 2**31 seconds.
X.SH "SEE\ ALSO"
X.IR phoon(1),
X.IR libtws(3)
X.SH AUTHOR
XJef Poskanzer
X.SH NOTE
X* Unix is a virus from outer space.
SHAR_EOF
if test 803 -ne "`wc -c < 'deltime.man'`"
then
	echo shar: error transmitting "'deltime.man'" '(should have been 803 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'dtime.c'" '(9035 characters)'
if test -f 'dtime.c'
then
	echo shar: will not over-write existing file "'dtime.c'"
else
sed 's/^X//' << \SHAR_EOF > 'dtime.c'
X/* dtime.c - routines to do ``ARPA-style'' time structures
X
Xver  date   who remarks
X--- ------- --- -------------------------------------------------------------
X01B 15nov86 JP  Thouroughly hacked by Jef Poskanzer.
X01A ??????? MTR Original version from the MH 6.5 distribution, courtesy
X	          of Marshall Rose.
X
X*/
X
X
X#include "tws.h"
X#include <stdio.h>
X#include <sys/types.h>
X#include <time.h>
X#ifdef  SYS5
X#include <string.h>
X#else SYS5
X#include <strings.h>
X#include <sys/timeb.h>
X#endif SYS5
X
X#ifdef	SYS5
Xextern int  daylight;
Xextern long timezone;
Xextern char *tzname[];
X#endif	SYS5
X
X/*  */
X
X#define	abs(a) ( a >= 0 ? a : -a )
X
Xchar *tw_moty[] = {
X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
X
Xchar *tw_dotw[] = {
X    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
X
Xchar *tw_ldotw[] = {
X    "Sunday", "Monday", "Tuesday", "Wednesday",
X    "Thursday", "Friday", "Saturday", NULL };
X
X/*  */
X
Xstatic struct zone
X    {
X    char *std;
X    char *dst;
X    int shift;
X    }
X    zones[] = {
X	"GMT", "BST", 0,
X	"EST", "EDT", -5,
X	"CST", "CDT", -6,
X	"MST", NULL, -7,
X	"PST", "PDT", -8,
X	"A", NULL, -1,
X	"B", NULL, -2,
X	"C", NULL, -3,
X	"D", NULL, -4,
X	"E", NULL, -5,
X	"F", NULL, -6,
X	"G", NULL, -7,
X	"H", NULL, -8,
X	"I", NULL, -9,
X	"K", NULL, -10,
X	"L", NULL, -11,
X	"M", NULL, -12,
X	"N", NULL, 1,
X#ifndef	HUJI
X	"O", NULL, 2,
X#else	HUJI
X	"JST", "JDT", 2,
X#endif	HUJI
X	"P", NULL, 3,
X	"Q", NULL, 4,
X	"R", NULL, 5,
X	"S", NULL, 6,
X	"T", NULL, 7,
X	"U", NULL, 8,
X	"V", NULL, 9,
X	"W", NULL, 10,
X	"X", NULL, 11,
X	"Y", NULL, 12,
X	NULL };
X
X#define CENTURY 19
X
Xlong time( );
Xstruct tm *localtime( );
X
X/*  */
X
Xchar *dtimenow( )
X    {
X    long clock;
X
X    (void) time( &clock );
X    return ( dtime( &clock ) );
X    }
X
X
Xchar *
Xdctime( tw )
Xstruct tws *tw;
X    {
X    static char buffer[25];
X
X    if ( tw == NULL )
X	return ( NULL );
X
X    (void) sprintf( buffer, "%.3s %.3s %02d %02d:%02d:%02d %.4d\n",
X	    tw_dotw[tw -> tw_wday], tw_moty[tw -> tw_mon], tw -> tw_mday,
X	    tw -> tw_hour, tw -> tw_min, tw -> tw_sec,
X	    tw -> tw_year >= 100 ? tw -> tw_year : 1900 + tw -> tw_year );
X
X    return ( buffer );
X    }
X
X/*  */
X
Xstruct tws *
Xdtwstime( )
X    {
X    long clock;
X
X    (void) time( &clock );
X    return ( dlocaltime( &clock ) );
X    }
X
X
Xstruct tws *
Xdlocaltime( clock )
Xlong *clock;
X    {
X    register struct tm *tm;
X#ifndef SYS5
X    struct timeb tb;
X#endif not SYS5
X    static struct tws tw;
X
X    if ( clock == NULL )
X	return ( NULL );
X    tw.tw_flags = TW_NULL;
X
X    tm = localtime( clock );
X    tw.tw_sec = tm -> tm_sec;
X    tw.tw_min = tm -> tm_min;
X    tw.tw_hour = tm -> tm_hour;
X    tw.tw_mday = tm -> tm_mday;
X    tw.tw_mon = tm -> tm_mon;
X    tw.tw_year = tm -> tm_year;
X    tw.tw_wday = tm -> tm_wday;
X    tw.tw_yday = tm -> tm_yday;
X    if ( tm -> tm_isdst )
X	tw.tw_flags |= TW_DST;
X#ifndef  SYS5
X    ftime( &tb );
X    tw.tw_zone = -tb.timezone;
X#else   SYS5
X    tzset( );
X    tw.tw_zone = -(timezone / 60);
X#endif  SYS5
X    tw.tw_flags &= ~TW_SDAY;
X    tw.tw_flags |= TW_SEXP;
X    tw.tw_clock = *clock;
X
X    return ( &tw );
X    }
X
X
Xstruct tws *
Xdgmtime( clock )
Xlong *clock;
X    {
X    register struct tm *tm;
X    static struct tws tw;
X
X    if ( clock == NULL )
X	return ( NULL );
X    tw.tw_flags = TW_NULL;
X
X    tm = gmtime( clock );
X    tw.tw_sec = tm -> tm_sec;
X    tw.tw_min = tm -> tm_min;
X    tw.tw_hour = tm -> tm_hour;
X    tw.tw_mday = tm -> tm_mday;
X    tw.tw_mon = tm -> tm_mon;
X    tw.tw_year = tm -> tm_year;
X    tw.tw_wday = tm -> tm_wday;
X    tw.tw_yday = tm -> tm_yday;
X    if ( tm -> tm_isdst )
X	tw.tw_flags |= TW_DST;
X    tw.tw_zone = 0;
X    tw.tw_flags &= ~TW_SDAY;
X    tw.tw_flags |= TW_SEXP;
X    tw.tw_clock = *clock;
X
X    return( &tw );
X    }
X
X/*  */
X
Xchar *
Xdasctime( tw, flags )
Xstruct tws *tw;
Xint flags;
X    {
X    static char buffer[80], result[80];
X
X    if ( tw == NULL )
X	return ( NULL );
X
X    (void) sprintf( buffer, "%02d %s %02d %02d:%02d:%02d %s",
X	    tw -> tw_mday, tw_moty[tw -> tw_mon], tw -> tw_year,
X	    tw -> tw_hour, tw -> tw_min, tw -> tw_sec,
X	    dtimezone( tw -> tw_zone, tw -> tw_flags | flags ) );
X
X    if ( (tw -> tw_flags & TW_SDAY) == TW_SEXP )
X	(void) sprintf( result, "%s, %s", tw_dotw[tw -> tw_wday], buffer );
X    else
X	if ( (tw -> tw_flags & TW_SDAY) == TW_SNIL )
X	    (void) strcpy( result, buffer );
X	else
X	    (void) sprintf( result, "%s (%s)", buffer, tw_dotw[tw -> tw_wday] );
X
X    return ( result );
X    }
X
X/*  */
X
Xchar *
Xdtimezone( offset, flags )
Xint offset, flags;
X    {
X    register int hours, mins;
X    register struct zone *z;
X    static char buffer[10];
X
X    if ( offset < 0 )
X	{
X	mins = -((-offset) % 60);
X	hours = -((-offset) / 60);
X	}
X    else
X	{
X	mins = offset % 60;
X	hours = offset / 60;
X	}
X
X    if ( !(flags & TW_ZONE) && mins == 0 )
X	for ( z = zones; z -> std; z++ )
X	    if ( z -> shift == hours )
X		return ( z -> dst && (flags & TW_DST) ? z -> dst : z -> std );
X
X#ifdef	DSTXXX
X    if ( flags & TW_DST )
X	hours += 1;
X#endif	DSTXXX
X    (void) sprintf( buffer, "%s%02d%02d",
X	    offset < 0 ? "-" : "+", abs( hours ), abs( mins ) );
X    return ( buffer );
X    }
X
X/*  */
X
Xvoid
Xtwscopy( tb, tw )
Xstruct tws *tb, *tw;
X    {
X#ifdef	notdef
X    tb -> tw_sec = tw -> tw_sec;
X    tb -> tw_min = tw -> tw_min;
X    tb -> tw_hour = tw -> tw_hour;
X    tb -> tw_mday = tw -> tw_mday;
X    tb -> tw_mon = tw -> tw_mon;
X    tb -> tw_year = tw -> tw_year;
X    tb -> tw_wday = tw -> tw_wday;
X    tb -> tw_yday = tw -> tw_yday;
X    tb -> tw_zone = tw -> tw_zone;
X    tb -> tw_clock = tw -> tw_clock;
X    tb -> tw_flags = tw -> tw_flags;
X#else	not notdef
X    *tb = *tw;
X#endif	not notdef
X    }
X
X
Xint
Xtwsort( tw1, tw2 )
Xstruct tws *tw1, *tw2;
X    {
X    register long c1, c2;
X
X    (void) twclock( tw1 );
X    (void) twclock( tw2 );
X
X    return ( (c1 = tw1 -> tw_clock) > (c2 = tw2 -> tw_clock) ? 1
X	    : c1 == c2 ? 0 : -1 );
X    }
X
X/*  */
X
X
X/* Julian day number of the Unix* clock's origin, 01 Jan 1970. */
X#define JD1970 2440587L
X
X
Xlong
Xtwjuliandate( tw )
Xstruct tws *tw;
X    {
X    register int mday, mon, year;
X    register long a, b;
X    double jd;
X
X    if ( (mday = tw -> tw_mday) < 1 || mday > 31 ||
X	    (mon = tw -> tw_mon + 1) < 1 || mon > 12 ||
X	    (year = tw -> tw_year) < 1 || year > 10000 )
X	return ( -1L );
X    if ( year < 100 )
X	year += CENTURY * 100;
X
X    if ( mon == 1 || mon == 2 )
X	{
X	--year;
X	mon += 12;
X	}
X    if ( year < 1583 )
X	return ( -1L );
X    a = year / 100;
X    b = 2 - a + a / 4;
X    b += (long) ( (double) year * 365.25 );
X    b += (long) ( 30.6001 * ( (double) mon + 1.0 ) );
X    jd = mday + b + 1720994.5;
X    return ( (long) jd );
X    }
X
X
Xlong
Xtwsubdayclock( tw )
Xstruct tws *tw;
X    {
X    register int i, sec, min, hour;
X    register long result;
X
X    if ( (sec = tw -> tw_sec) < 0 || sec > 59 ||
X	    (min = tw -> tw_min) < 0 || min > 59 ||
X	    (hour = tw -> tw_hour) < 0 || hour > 23 )
X	return ( -1L );
X
X    result = ( hour * 60 + min ) * 60 + sec;
X    result -= 60 * tw -> tw_zone;
X    if ( tw -> tw_flags & TW_DST )
X	result -= 60 * 60;
X
X    return ( result );
X    }
X
X
Xlong
Xtwclock( tw )
Xstruct tws *tw;
X    {
X    register long jd, sdc, result;
X
X    if ( tw -> tw_clock != 0L )
X	return ( tw -> tw_clock );
X
X    if ( ( jd = twjuliandate( tw ) ) == -1L )
X	return ( tw -> tw_clock = -1L );
X    if ( ( sdc = twsubdayclock( tw ) ) == -1L )
X	return ( tw -> tw_clock = -1L );
X
X    result = ( jd - JD1970 ) * 24 * 60 * 60 + sdc;
X
X    return ( tw -> tw_clock = result );
X    }
X
X/*  */
X
X/*** twsubtract - subtract tw2 from tw1, returning result in seconds
X
XThe point of this routine is that using twclock( tw1 ) - twclock( tw2 )
Xwould limit you to dates after the Unix* Epoch ( 01 January 1970 ).  This
Xroutine avoids that limit.  However, because the result is represented
Xby 32 bits, it is still limited to a span of two billion seconds, which is
Xabout 66 years.
X
X*/
X
Xlong
Xtwsubtract( tw1, tw2 )
Xstruct tws *tw1, *tw2;
X    {
X    register long jd1, jd2, sdc1, sdc2, result;
X
X    if ( ( jd1 = twjuliandate( tw1 ) ) == -1L )
X	return ( 0L );
X    if ( ( sdc1 = twsubdayclock( tw1 ) ) == -1L )
X	return ( 0L );
X
X    if ( ( jd2 = twjuliandate( tw2 ) ) == -1L )
X	return ( 0L );
X    if ( ( sdc2 = twsubdayclock( tw2 ) ) == -1L )
X	return ( 0L );
X    
X    result = ( jd1 - jd2 ) * 24 * 60 * 60 + ( sdc1 - sdc2 );
X
X    return ( result );
X    }
X
X/*  */
X
X/*
X *    Simple calculation of day of the week.  Algorithm used is Zeller's
X *    congruence.  Currently, we assume if tw -> tw_year < 100
X *    then the century is CENTURY.
X */
X
Xset_dotw( tw )
Xstruct tws *tw;
X    {
X    register int month, day, year, century;
X
X    month = tw -> tw_mon - 1;
X    day = tw -> tw_mday;
X    year = tw -> tw_year % 100;
X    century = tw -> tw_year >= 100 ? tw -> tw_year / 100 : CENTURY;
X
X    if ( month <= 0 )
X	{
X	month += 12;
X	if ( --year < 0 )
X	    {
X	    year += 100;
X	    century--;
X	    }
X	}
X
X    tw -> tw_wday =
X	((26 * month - 2) / 10 + day + year + year / 4
X	    - 3 * century / 4 + 1) % 7;
X
X    tw -> tw_flags &= ~TW_SDAY;
X    tw -> tw_flags |= TW_SIMP;
X    }
X
X
X/* * Unix is a virus from outer space. */
SHAR_EOF
if test 9035 -ne "`wc -c < 'dtime.c'`"
then
	echo shar: error transmitting "'dtime.c'" '(should have been 9035 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'dtimep.lex'" '(7327 characters)'
if test -f 'dtimep.lex'
then
	echo shar: will not over-write existing file "'dtimep.lex'"
else
sed 's/^X//' << \SHAR_EOF > 'dtimep.lex'
X%e 2000
X%p 5000
X%n 1000
X%a 4000
X%START	Z
Xsun	(sun(day)?)
Xmon	(mon(day)?)
Xtue	(tue(sday)?)
Xwed	(wed(nesday)?)
Xthu	(thu(rsday)?)
Xfri	(fri(day)?)
Xsat	(sat(urday)?)
X
XDAY	({sun}|{mon}|{tue}|{wed}|{thu}|{fri}|{sat})
X
Xjan	(jan(uary)?)
Xfeb	(feb(ruary)?)
Xmar	(mar(ch)?)
Xapr	(apr(il)?)
Xmay	(may)
Xjun	(jun(e)?)
Xjul	(jul(y)?)
Xaug	(aug(ust)?)
Xsep	(sep(tember)?)
Xoct	(oct(ober)?)
Xnov	(nov(ember)?)
Xdec	(dec(ember)?)
X
XMONTH	({jan}|{feb}|{mar}|{apr}|{may}|{jun}|{jul}|{aug}|{sep}|{oct}|{nov}|{dec})
X
Xw	([ \t]*)
XW	([ \t]+)
XD	([0-9]?[0-9])
Xd	[0-9]
X%{
X/* dtimep.lex - routines to do ``ARPA-style'' time parsing
X
Xver  date   who remarks
X--- ------- --- -------------------------------------------------------------
X01B 15nov86 JP  Thouroughly hacked by Jef Poskanzer.
X01A ??????? MTR Original version from the MH 6.5 distribution, courtesy
X	          of Marshall Rose.
X
X*/
X
X#include "tws.h"
X#include <ctype.h>
X#include <sys/types.h>
X#include <time.h>
X#ifdef SYS5
X#include <string.h>
X#else SYS5
X#include <strings.h>
X#include <sys/timeb.h>
X#endif SYS5
X
X#ifdef SYS5
Xextern int  daylight;
Xextern long timezone;
Xextern char *tzname[];
X#endif SYS5
X
X/*
X * Table to convert month names to numeric month.  We use the
X * fact that the low order 5 bits of the sum of the 2nd & 3rd
X * characters of the name is a hash with no collisions for the 12
X * valid month names.  (The mask to 5 bits maps any combination of
X * upper and lower case into the same hash value).
X */
Xstatic int month_map[] = {
X	0,
X	6,	/* 1 - Jul */
X	3,	/* 2 - Apr */
X	5,	/* 3 - Jun */
X	0,
X	10,	/* 5 - Nov */
X	0,
X	1,	/* 7 - Feb */
X	11,	/* 8 - Dec */
X	0,
X	0,
X	0,
X	0,
X	0,
X	0,
X	0,	/*15 - Jan */
X	0,
X	0,
X	0,
X	2,	/*19 - Mar */
X	0,
X	8,	/*21 - Sep */
X	0,
X	9,	/*23 - Oct */
X	0,
X	0,
X	4,	/*26 - May */
X	0,
X	7 };	/*28 - Aug */
X/*
X * Same trick for day-of-week using the hash function
X *  (c1 & 7) + (c2 & 4)
X */
Xstatic int day_map[] = {
X	0,
X	0,
X	0,
X	6,	/* 3 - Sat */
X	4,	/* 4 - Thu */
X	0,
X	5,	/* 6 - Fri */
X	0,	/* 7 - Sun */
X	2,	/* 8 - Tue */
X	1	/* 9 - Mon */,
X	0,
X	3 };	/*11 - Wed */
X#define SETDAY tw.tw_wday= day_map[(cp[0] & 7) + (cp[1] & 4)];\
X		tw.tw_flags |= TW_SEXP;\
X		cp += 2;
X#define SETMONTH tw.tw_mon = month_map[(cp[0] + cp[1]) & 0x1f]; gotdate++;\
X		 cp += 2;\
X		 SKIPD;
X#define CVT1OR2 (i=(*cp++ - '0'), isdigit(*cp)? i*10 + (*cp++ - '0') : i)
X#define CVT2 ( (*cp++ - '0')*10 + (*cp++ - '0') )
X#define CVT3 ( ( (*cp++ - '0')*10 + (*cp++ - '0') )*10 + (*cp++ - '0') )
X#define CVT4 ( ( ( (*cp++ - '0')*10 + (*cp++ - '0') )*10 + (*cp++ - '0') )*10 + (*cp++ - '0') )
X#define SKIPD while ( ! isdigit( *cp++ ) ) ; --cp;
X#define ZONE(x) tw.tw_zone=(x);
X#define ZONED(x) tw.tw_zone=(x); tw.tw_flags |= TW_DST;
X#define LC(c) (isupper( c ) ? tolower( c ) : ( c ))
X%}
X%%
X%{
Xstruct tws *
Xdparsetime( str )
Xchar *str;
X    {
X    register int i;
X    static struct tws tw;
X    register char *cp;
X    register int gotdate = 0;
X#ifndef SYS5
X    struct timeb	tb;
X#endif not SYS5
X    long clock;
X
X    start_cond = 0;
X
X    /* Zero out the struct. */
X    bzero( (char *) &tw, sizeof tw );
X
X    /* Set default time zone. */
X#ifndef SYS5
X    ftime( &tb );
X    tw.tw_zone = -tb.timezone;
X#else SYS5
X    tzset( );
X    tw.tw_zone = -(timezone / 60);
X#endif SYS5
X
X    for ( ; ; )
X	switch ( cp = str, lex_string( &str, start_cond ) )
X	    {
X	    case -1:
X		if ( ! gotdate )
X			return ( NULL );
X		tw.tw_flags |= TW_JUNK;
X		/* fall through */
X	    case 0:
X		if ( tw.tw_year == 0 )
X		    {
X		    /* Set default year. */
X		    time( &clock );
X		    tw.tw_year = localtime( &clock ) -> tm_year;
X		    }
X		return ( &tw );
X
X%}
X{DAY}","?{w}				SETDAY;
X"("{DAY}")"(","?)			cp++, SETDAY;
X
X{D}(("-"{D}"-")|("/"{D}"/")){D}?{d}{d}{w}	{
X#ifdef EUROPE
X					tw.tw_mday = CVT1OR2; cp++;
X					tw.tw_mon  = CVT1OR2 - 1; cp++;
X#else EUROPE
X					tw.tw_mon = CVT1OR2 - 1; cp++;
X					tw.tw_mday  = CVT1OR2; cp++;
X#endif EUROPE
X					for ( i = 0; isdigit( *cp ); )
X						i = i * 10 + (*cp++ - '0');
X					tw.tw_year = i;
X					gotdate++;
X					}
X{D}("/"|"-"){D}{w}			{
X#ifdef EUROPE
X					tw.tw_mday = CVT1OR2; cp++;
X					tw.tw_mon  = CVT1OR2 - 1;
X#else EUROPE
X					tw.tw_mon = CVT1OR2 - 1; cp++;
X					tw.tw_mday  = CVT1OR2;
X#endif EUROPE
X					gotdate++;
X					}
X{D}(("-"{MONTH}"-")|(" "{MONTH}" ")|({MONTH})){D}?{d}{d}({W}at)?{w}	{
X					tw.tw_mday = CVT1OR2;
X					while ( ! isalpha( *cp++ ) )
X						;
X					SETMONTH;
X					for ( i = 0; isdigit( *cp ); )
X						i = i * 10 + (*cp++ - '0');
X					tw.tw_year = i;
X					gotdate++;
X					}
X{D}"-"?{MONTH}({W}at)?{w}		{
X					tw.tw_mday = CVT1OR2;
X					while ( ! isalpha( *cp++ ) )
X						;
X					SETMONTH;
X					gotdate++;
X					}
X{MONTH}{W}{D}","{W}{D}?{d}{d}{w}	{
X					cp++;
X					SETMONTH;
X					tw.tw_mday = CVT1OR2;
X					SKIPD;
X					for ( i = 0; isdigit( *cp ); )
X						i = i * 10 + (*cp++ - '0');
X					tw.tw_year = i;
X					gotdate++;
X					}
X{MONTH}{W}{D}{w}			{
X					cp++;
X					SETMONTH;
X					tw.tw_mday = CVT1OR2;
X					gotdate++;
X					}
X
X{D}:{D}:{D}({w}am)?{w}			{
X					tw.tw_hour = CVT1OR2; cp++;
X					tw.tw_min  = CVT1OR2; cp++;
X					tw.tw_sec  = CVT1OR2;
X					BEGIN Z;
X					}
X{D}:{D}:{D}{w}pm{w}			{
X					tw.tw_hour = CVT1OR2 + 12; cp++;
X					tw.tw_min  = CVT1OR2; cp++;
X					tw.tw_sec  = CVT1OR2;
X					BEGIN Z;
X					}
X{D}:{D}({w}am)?{w}			{
X					tw.tw_hour = CVT1OR2; cp++;
X					tw.tw_min  = CVT1OR2;
X					BEGIN Z;
X					}
X{D}:{D}{w}pm{w}				{
X					tw.tw_hour = CVT1OR2 + 12; cp++;
X					tw.tw_min  = CVT1OR2;
X					BEGIN Z;
X					}
X[0-2]{d}{d}{d}{d}{d}{w}			{
X					tw.tw_hour = CVT1OR2;
X					tw.tw_min  = CVT1OR2;
X					tw.tw_sec  = CVT1OR2;
X					BEGIN Z;
X					}
X[0-2]{d}{d}{d}{w}			{
X					tw.tw_hour = CVT1OR2;
X					tw.tw_min  = CVT1OR2;
X					BEGIN Z;
X					}
X<Z>"-"?ut				ZONE(0 * 60);
X<Z>"-"?gmt				ZONE(0 * 60);
X<Z>"-"?jst				ZONE(2 * 60);
X<Z>"-"?jdt				ZONED(2 * 60);
X<Z>"-"?est				ZONE(-5 * 60);
X<Z>"-"?edt				ZONED(-5 * 60);
X<Z>"-"?cst				ZONE(-6 * 60);
X<Z>"-"?cdt				ZONED(-6 * 60);
X<Z>"-"?mst				ZONE(-7 * 60);
X<Z>"-"?mdt				ZONED(-7 * 60);
X<Z>"-"?pst				ZONE(-8 * 60);
X<Z>"-"?pdt				ZONED(-8 * 60);
X<Z>"-"?nst				ZONE(-(3 * 60 + 30));
X<Z>"-"?ast				ZONE(-4 * 60);
X<Z>"-"?adt				ZONED(-4 * 60);
X<Z>"-"?yst				ZONE(-9 * 60);
X<Z>"-"?ydt				ZONED(-9 * 60);
X<Z>"-"?hst				ZONE(-10 * 60);
X<Z>"-"?hdt				ZONED(-10 * 60);
X<Z>"-"?bst				ZONED(-1 * 60);
X<Z>[a-i]				tw.tw_zone = 60 * (('a'-1) - LC (*cp));
X<Z>[k-m]				tw.tw_zone = 60 * ('a' - LC (*cp));
X<Z>[n-y]				tw.tw_zone = 60 * (LC (*cp) - 'm');
X<Z>"+"[0-1]{d}{d}{d}			{
X					cp++;
X					tw.tw_zone = ((cp[0] * 10 + cp[1])
X						     -('0' * 10   + '0'))*60
X						    +((cp[2] * 10 + cp[3])
X						     -('0' * 10   + '0'));
X#ifdef DSTXXX
X					zonehack (&tw);
X#endif DSTXXX
X					cp += 4;
X					}
X<Z>"-"[0-1]{d}{d}{d}			{
X					cp++;
X					tw.tw_zone = (('0' * 10   + '0')
X						     -(cp[0] * 10 + cp[1]))*60
X						    +(('0' * 10   + '0')
X						     -(cp[2] * 10 + cp[3]));
X#ifdef DSTXXX
X					zonehack (&tw);
X#endif DSTXXX
X					cp += 4;
X					}
X
X<Z>{W}{d}{d}{d}{d}			{
X					SKIPD;
X					tw.tw_year = CVT4;
X					}
X\n	|
X{W}	;
X%%
X
X#ifdef DSTXXX
Xstatic
Xzonehack( tw )
Xregister struct tws *tw;
X    {
X    register struct tm *tm;
X
X    if ( twclock( tw ) == -1L )
X	return;
X
X    tm = localtime( &tw -> tw_clock );
X    if ( tm -> tm_isdst )
X	{
X	tw -> tw_flags |= TW_DST;
X	tw -> tw_zone -= 60;
X	}
X    }
X#endif DSTXXX
X
X
X#ifdef SYS5
X/* Not all SYS5's have bzero( ). */
X
Xbzero( b, length )
Xchar *b;
Xint length;
X    {
X    while ( length-- > 0 )
X	*b++ = 0;
X    }
X#endif
SHAR_EOF
if test 7327 -ne "`wc -c < 'dtimep.lex'`"
then
	echo shar: error transmitting "'dtimep.lex'" '(should have been 7327 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'lexedit.sed'" '(356 characters)'
if test -f 'lexedit.sed'
then
	echo shar: will not over-write existing file "'lexedit.sed'"
else
sed 's/^X//' << \SHAR_EOF > 'lexedit.sed'
X2,/^extern int yylineno;$/c\
Xstatic int start_cond = 0;\
X#define BEGIN start_cond =
X/^struct yysvf \*yyestate;$/,/^extern struct yysvf yysvec/d
X/^# define YYNEWLINE /,/^int nstr;/d
X/^while((nstr = yylook()/,/^if(yywrap()) /d
X/^case -1:$/,/^fprintf(yyout,"bad switch yylook /c\
X	default: return(0);
X/^struct yysvf *yybgin = yysvec+1;$/d
X/^int yylineno /,$d
SHAR_EOF
if test 356 -ne "`wc -c < 'lexedit.sed'`"
then
	echo shar: error transmitting "'lexedit.sed'" '(should have been 356 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'lexstring.c'" '(3765 characters)'
if test -f 'lexstring.c'
then
	echo shar: will not over-write existing file "'lexstring.c'"
else
sed 's/^X//' << \SHAR_EOF > 'lexstring.c'
X#include <stdio.h>
X#include <ctype.h>
X
X#define YYLERR yysvec
X#define YYTYPE int
X#define YYLMAX 256
X
Xstruct yysvf { 
X	struct yywork *yystoff;
X	struct yysvf *yyother;
X	int *yystops;
X};
X
Xstruct yywork { 
X	YYTYPE	verify;
X	YYTYPE	advance; 
X}; 
X
Xextern int yyvstop[];
Xextern struct yywork yycrank[];
Xextern struct yysvf yysvec[];
Xextern struct yywork *yytop;
Xextern char yymatch[];
Xextern char yyextra[];
X
X#ifdef LEXDEBUG
Xstatic int debug = 0;
X#endif LEXDEBUG
X
Xlex_string( strptr, start_cond)
X	char	**strptr;
X	int	start_cond;
X{
X	register struct yysvf *state, **lsp;
X	register struct yywork *tran;
X	register int ch;
X	register char	*cp = *strptr;
X	register int	*found;
X	struct	yysvf *yylstate[YYLMAX];
X
X	/* start off machines */
X	lsp = yylstate;
X	state = yysvec+1+start_cond;
X	for (;;){
X# ifdef LEXDEBUG
X		if(debug)
X			fprintf(stderr,"state %d\n",state-yysvec-1);
X# endif
X		tran = state->yystoff;
X		if(tran == yycrank)
X			/* may not be any transitions */
X			if (state->yyother == 0 ||
X			    state->yyother->yystoff == yycrank)
X				break;
X
X		ch = *cp++;
X#ifdef ONECASE
X		if (isupper(ch) )
X			ch = tolower(ch);
X#endif ONECASE
Xtryagain:
X# ifdef LEXDEBUG
X		if(debug){
X			fprintf(stderr,"char ");
X			allprint(ch);
X			putchar('\n');
X		}
X# endif
X		if ( tran > yycrank){
X			tran += ch;
X			if (tran <= yytop && tran->verify+yysvec == state){
X				if ((state = tran->advance+yysvec) == YYLERR){
X					/* error transitions */
X					--cp;
X					break;
X				}
X				*lsp++ = state;
X				goto contin;
X			}
X
X		} else if(tran < yycrank) {
X			/* r < yycrank */
X			tran = yycrank+(yycrank-tran) + ch;
X# ifdef LEXDEBUG
X			if (debug)
X				fprintf(stderr,"compressed state\n");
X# endif
X			if(tran <= yytop && tran->verify+yysvec == state){
X				if ((state = tran->advance+yysvec) == YYLERR)
X					/* error transitions */
X					break;
X
X				*lsp++ = state;
X				goto contin;
X			}
X			tran += (yymatch[ch] - ch);
X# ifdef LEXDEBUG
X			if(debug){
X				fprintf(stderr,"try fall back character ");
X				allprint(yymatch[ch]);
X				putchar('\n');
X			}
X# endif
X			if(tran <= yytop && tran->verify+yysvec == state){
X				if(tran->advance+yysvec == YYLERR)
X					/* error transition */
X					break;
X
X				*lsp++ = state = tran->advance+yysvec;
X				goto contin;
X			}
X		}
X		if ((state = state->yyother) &&
X		    (tran = state->yystoff) != yycrank){
X# ifdef LEXDEBUG
X			if(debug)
X				fprintf(stderr,"fall back to state %d\n",
X					state-yysvec-1);
X# endif
X			goto tryagain;
X		} else
X			break;
X
Xcontin:
X# ifdef LEXDEBUG
X		if(debug){
X			fprintf(stderr,"state %d char ",state-yysvec-1);
X			allprint(ch);
X			putchar('\n');
X		}
X# endif
X		;
X	}
X# ifdef LEXDEBUG
X	if(debug){
X		fprintf(stderr,"stopped at %d with ",*(lsp-1)-yysvec-1);
X		allprint(ch);
X		putchar('\n');
X	}
X# endif
X	while (lsp-- > yylstate){
X		if (*lsp != 0 && (found= (*lsp)->yystops) && *found > 0){
X			if(yyextra[*found]){
X				/* must backup */
X				ch = -*found;
X				do {
X					while (*found && *found++ != ch)
X						;
X				 } while (lsp > yylstate &&
X					  (found = (*--lsp)->yystops));
X			}
X# ifdef LEXDEBUG
X			if(debug){
X				fprintf(stderr,"\nmatch ");
X				for ( cp = *strptr;
X				      cp <= ((*strptr)+(lsp-yylstate));
X				      cp++)
X					allprint( *cp );
X				fprintf(stderr," action %d\n",*found);
X			}
X# endif
X			*strptr += (lsp - yylstate + 1);
X			return(*found);
X		}
X	}
X	/* the string didn't match anything - if we're looking at
X	 * eos, just return 0.  Otherwise, bump the string pointer
X	 * and return -1.
X	 */
X# ifdef LEXDEBUG
X	if(debug)
X		fprintf(stderr,"\nno match\n");
X#endif LEXDEBUG
X	if ( **strptr ) {
X		(*strptr)++;
X		return (-1);
X	}
X	return (0);
X}
X
X#ifdef LEXDEBUG
Xallprint(c)
X	char c;
X{
X	if ( c < 32 ) {
X	    putc( '^', stderr );
X	    c += 32;
X	} else if ( c == 127 ) {
X	    putc( '^', stderr );
X	    c = '?';
X	}
X	putc( c, stderr );
X}
X#endif LEXDEBUG
SHAR_EOF
if test 3765 -ne "`wc -c < 'lexstring.c'`"
then
	echo shar: error transmitting "'lexstring.c'" '(should have been 3765 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'libtws.man'" '(2241 characters)'
if test -f 'libtws.man'
then
	echo shar: will not over-write existing file "'libtws.man'"
else
sed 's/^X//' << \SHAR_EOF > 'libtws.man'
X.TH libtws 3 "08 November 1986"
X.SH NAME
Xlibtws \- alternate date and time routines including parsing
X.SH SYNOPSIS
X.nf
X.fc ^ ~
X.ta \w'char *dtimezone( offset, flags );  'u
Xinclude "tws.h"
X.PP
X^struct tws *dlocaltime( clock );~^/* local clock into tws */
Xlong *clock;
X.PP
X^struct tws *gmtime( clock );~^/* GMT clock into tws */
Xlong *clock;
X.PP
X^char *dtime( clock );~^/* clock into string */
Xlong *clock;
X.PP
X^long twclock( t );~^/* tws into clock */
Xstruct tws *t;
X.PP
X^long twjuliandate( t );~^/* tws into Julian day number */
Xstruct tws *t;
X.PP
X^struct tws *dparsetime( str );~^/* string into tws */
Xchar *str;
X.PP
X^char *dctime( t );~^/* tws into string */
Xstruct tws *t;
X.PP
X^char *dasctime( t, flags );~^/* tws into string */
Xstruct tws *t;
Xint flags;
X.PP
X^char *dtimezone( offset, flags );~^/* timezone into string */
Xint offset, flags;
X.PP
X^char *dtwszone( t );~^/* tws's timezone into string */
Xstruct tws *t;
X.PP
X^char *dtimemow( );~^/* current time into string */
X.PP
X^struct tws *dtwstime( );~^/* current time into tws */
X.PP
X^void twscopy( tot, fromt );~^/* copy a tws */
Xstruct tws *tot, *fromt;
X.PP
X^int twsort( t1, t2 );~^/* compare two tws's */
Xstruct tws *t1, *t2;
X.PP
X^long twsubtract( t1, t2 );~^/* seconds between t2 and t1 */
Xstruct tws *t1, *t2;
X.fi
X.SH DESCRIPTION
X.I Libtws
Xis a fairly complete date/time library.
XUnlike the standard Unix* date/time routines,
X.I libtws
Xwill parse date/time strings into internal form.
XThe format for specifying date/time strings is pretty loose - basically
Xthe same as the format for date/times in network mail.
X.PP
XMost of the routines do not use the Unix* "clock" time
Xformat, and therefore are not limited to dates after 01 January 1970.
XIn particular, twsubtract() lets you subtract two dates without
Xconverting them to "clock" form.
X.SH "SEE\ ALSO"
X.IR ctime(3),
X.IR time(3)
X.SH AUTHOR
XMost of
X.I libtws
Xcame from version 6.5 of the MH message
Xhandling system, courtesy of Marshall Rose.
XSome improvements (?) were added by Jef Poskanzer.
X.SH BUGS
XThe return values point to static data whose contents are overwritten
Xby the next call.
X.PP
XThe basic Unix* time format (clock) only goes back to 1970, limiting
Xapplications somewhat.
X.SH NOTE
X* Unix is a virus from outer space.
SHAR_EOF
if test 2241 -ne "`wc -c < 'libtws.man'`"
then
	echo shar: error transmitting "'libtws.man'" '(should have been 2241 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'parsetime.c'" '(1756 characters)'
if test -f 'parsetime.c'
then
	echo shar: will not over-write existing file "'parsetime.c'"
else
sed 's/^X//' << \SHAR_EOF > 'parsetime.c'
X/* parsetime.c - parse a date/time and display the results
X
Xver  date   who remarks
X--- ------- --- -------------------------------------------------------------
X01A 15nov86 JP  Written.
X
XCopyright (C) 1986 by Jef Poskanzer.  Permission to use, copy,
Xmodify, and distribute this software and its documentation for any
Xpurpose and without fee is hereby granted, provided that this copyright
Xnotice appear in all copies and in all supporting documentation.  No
Xrepresentation is made about the suitability of this software for any
Xpurpose.  It is provided "as is" without express or implied warranty.
X
X*/
X
Xstatic char copyright[] = "\nCopyright (C) 1986 by Jef Poskanzer.\n";
X
X
X#include "tws.h"
X#include <stdio.h>
X
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X    {
X    char buf[200];
X    int i;
X    struct tws *twp;
X
X    strcpy( buf, "" );
X    for ( i = 1; i < argc; i++ )
X	{
X	if ( i > 1 )
X	    strcat( buf, " " );
X	strcat( buf, argv[i] );
X	}
X
X    twp = dparsetime( buf );
X    if ( twp == NULL )
X	{
X	fprintf( stderr, "illegal date/time: %s\n", buf );
X	exit( 1 );
X	}
X
X    printf( "dparsetime( \"%s\" ):\n", buf );
X    printf( "  tw_sec = %d\n", twp->tw_sec );
X    printf( "  tw_min = %d\n", twp->tw_min );
X    printf( "  tw_hour = %d\n", twp->tw_hour );
X    printf( "  tw_mday = %d\n", twp->tw_mday );
X    printf( "  tw_mon = %d\n", twp->tw_mon );
X    printf( "  tw_year = %d\n", twp->tw_year );
X    printf( "  tw_wday = %d\n", twp->tw_wday );
X    printf( "  tw_yday = %d\n", twp->tw_yday );
X    printf( "  tw_zone = %d\n", twp->tw_zone );
X    printf( "  tw_clock = %ld\n", twp->tw_clock );
X    printf( "  tw_flags = %d (0x%04x)\n", twp->tw_flags, twp->tw_flags );
X    printf( "\n" );
X    printf( "dasctime: %s\n", dasctime( twp, 0 ) );
X
X    exit( 0 );
X    }
SHAR_EOF
if test 1756 -ne "`wc -c < 'parsetime.c'`"
then
	echo shar: error transmitting "'parsetime.c'" '(should have been 1756 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'phoon.c'" '(12899 characters)'
if test -f 'phoon.c'
then
	echo shar: will not over-write existing file "'phoon.c'"
else
sed 's/^X//' << \SHAR_EOF > 'phoon.c'
X/* phoon - show the phase of the moon
X
Xver  date   who remarks
X--- ------- --- -------------------------------------------------------------
X01C 26jan87 JP  Added backgrounds for 29 and 18 lines.
X01B 28dec86 JP  Added -l flag, and backgrounds for 19 and 24 lines.
X01A 08nov86 JP  Translated from the ratfor version of 12nov85, which itself
X                  was translated from the Pascal version of 05apr79.
X
XCopyright (C) 1986 by Jeffrey A. Poskanzer.  Permission to use, copy,
Xmodify, and distribute this software and its documentation for any
Xpurpose and without fee is hereby granted, provided that this copyright
Xnotice appear in all copies and in all supporting documentation.  No
Xrepresentation is made about the suitability of this software for any
Xpurpose.  It is provided "as is" without express or implied warranty.
X
X*/
X
Xstatic char copyright[] = "\nCopyright (C) 1986 by Jeffrey A. Poskanzer.\n";
X
X
X#include <stdio.h>
X#include <math.h>
X#include "tws.h"
X
X
X/* Global defines and declarations. */
X
X#define SECSPERMINUTE 60
X#define SECSPERHOUR (60 * SECSPERMINUTE)
X#define SECSPERDAY (24 * SECSPERHOUR)
X
X#define PI 3.14159
X
X#define DEFAULTNUMLINES 23
X#define MOONSTARTCOL 18
X#define QUARTERLITLEN 16
X#define QUARTERLITLENPLUSONE 17
X
X/* If you change the aspect ratio, the canned backgrounds won't work. */
X#define ASPECTRATIO 0.5
X
X/* Main program. */
X
Xmain( argc, argv, envp )
Xint argc;
Xchar *argv[], *envp[];
X    {
X    struct tws t, *twp;
X    char buf[100];
X    int numlines, argi, i;
X    char *usage = "usage:  %s  [ -l <lines> ]  [ <date/time> ]\n";
X
X    /* Parge args. */
X    argi = 1;
X    /* Check for -l flag. */
X    numlines = DEFAULTNUMLINES;
X    if ( argc - argi >= 1 )
X	{
X	if ( argv[argi][0] == '-' )
X	    {
X	    if ( argv[argi][1] != 'l' | argv[argi][2] != '\0' )
X		{
X		fprintf( stderr, usage, argv[0] );
X		exit( 1 );
X		}
X	    else
X		{
X		if ( argc - argi < 2 )
X		    {
X		    fprintf( stderr, usage, argv[0] );
X		    exit( 1 );
X		    }
X		if ( sscanf( argv[argi + 1], "%d", &numlines ) != 1 )
X		    {
X		    fprintf( stderr, usage, argv[0] );
X		    exit( 1 );
X		    }
X		argi += 2;
X		}
X	    }
X	}
X
X    /* Figure out what date and time to use. */
X    if ( argc - argi == 0 )
X	{
X	/* No arguments present - use the current date and time. */
X	twscopy( &t, dtwstime( ) );
X	}
X    else if ( argc - argi == 1 || argc - argi == 2 || argc - argi == 3 )
X	{
X	/* One, two, or three args - use them. */
X	strcpy( buf, argv[argi] );
X	if ( argc - argi > 1 )
X	    {
X	    strcat( buf, " " );
X	    strcat( buf, argv[argi + 1] );
X	    if ( argc - argi > 2 )
X		{
X		strcat( buf, " " );
X		strcat( buf, argv[argi + 2] );
X		}
X	    }
X	twp = dparsetime( buf );
X	if ( twp == NULL || twp -> tw_flags & TW_JUNK )
X	    {
X	    fprintf( stderr, "illegal date/time: %s\n", buf );
X	    exit( 1 );
X	    }
X	twscopy( &t, twp );
X	}
X    else
X	{
X	/* Too many args! */
X	fprintf( stderr, usage, argv[0] );
X	exit( 1 );
X	}
X
X    /* Pseudo-randomly decide what the moon is made of, and print it. */
X    if ( twclock( dtwstime( ) ) % 17 == 3 )
X	putmoon( &t, numlines, "GREENCHEESE" );
X    else
X	putmoon( &t, numlines, "@" );
X
X    /* All done. */
X    exit( 0 );
X    }
X
X
Xputmoon( t, numlines, atfiller )
Xstruct tws *t;
Xint numlines;
Xchar *atfiller;
X    {
X    struct tws twsanewmoon;
X    long secsynodic = 29*SECSPERDAY + 12*SECSPERHOUR + 44*SECSPERMINUTE + 3;
X    long secdiff, secphase;
X    int atflrlen, atflridx, lin, col, midlin, qlitidx;
X    float angphase, mcap, yrad, xrad, y, xright, xleft;
X    int colright, colleft, i;
X    char c;
X
X    static char background18[18][37] = {
X	"             .----------.            ",
X	"         .--'   o    .   `--.        ",
X	"       .'@  @@@@@@ O   .   . `.      ",
X	"     .'@@  @@@@@@@@   @@@@   . `.    ",
X	"   .'    . @@@@@@@@  @@@@@@    . `.  ",
X	"  / @@ o    @@@@@@.   @@@@    O   @\\ ",
X	"  |@@@@               @@@@@@     @@| ",
X	" / @@@@@   `.-.    . @@@@@@@@  .  @@\\",
X	" | @@@@   --`-'  .  o  @@@@@@@      |",
X	" |@ @@                 @@@@@@ @@@   |",
X	" \\      @@    @   . ()  @@   @@@@@  /",
X	"  |   @      @@@         @@@  @@@  | ",
X	"  \\  .   @@  @\\  .      .  @@    o / ",
X	"   `.   @@@@  _\\ /     .      o  .'  ",
X	"     `.  @@    ()---           .'    ",
X	"       `.     / |  .    o    .'      ",
X	"         `--./   .       .--'        ",
X	"             `----------'            "};
X
X    static char background19[19][39] = {
X	"              .----------.             ",
X	"          .--'   o    .   `--.         ",
X	"       .-'@  @@@@@@ O   .   . `-.      ",
X	"     .' @@  @@@@@@@@   @@@@   .  `.    ",
X	"    /     . @@@@@@@@  @@@@@@     . \\   ",
X	"   /@@  o    @@@@@@.   @@@@    O   @\\  ",
X	"  /@@@@                @@@@@@     @@@\\ ",
X	" . @@@@@   `.-./    . @@@@@@@@  .  @@ .",
X	" | @@@@   --`-'  .      @@@@@@@       |",
X	" |@ @@        `      o  @@@@@@ @@@@   |",
X	" |      @@        o      @@   @@@@@@  |",
X	" ` .  @       @@     ()   @@@  @@@@   '",
X	"  \\     @@   @@@@        . @@   .  o / ",
X	"   \\   @@@@  @@\\  .           o     /  ",
X	"    \\ . @@     _\\ /    .      .-.  /   ",
X	"     `.    .    ()---        `-' .'    ",
X	"       `-.    ./ |  .   o     .-'      ",
X	"          `--./   .       .--'         ",
X	"              `----------'             "};
X
X    static char background23[23][47] = {
X	"                 .------------.                ",
X	"             .--'  o     . .   `--.            ",
X	"          .-'   .    O   .       . `-.         ",
X	"       .-'@   @@@@@@@   .  @@@@@      `-.      ",
X	"      /@@@  @@@@@@@@@@@   @@@@@@@   .    \\     ",
X	"    ./    o @@@@@@@@@@@   @@@@@@@       . \\.   ",
X	"   /@@  o   @@@@@@@@@@@.   @@@@@@@   O      \\  ",
X	"  /@@@@   .   @@@@@@@o    @@@@@@@@@@     @@@ \\ ",
X	"  |@@@@@               . @@@@@@@@@@@@@ o @@@@| ",
X	" /@@@@@  O  `.-./  .      @@@@@@@@@@@@    @@  \\",
X	" | @@@@    --`-'       o     @@@@@@@@ @@@@    |",
X	" |@ @@@        `    o      .  @@   . @@@@@@@  |",
X	" |       @@  @         .-.     @@@   @@@@@@@  |",
X	" \\  . @        @@@     `-'   . @@@@   @@@@  o /",
X	"  |      @@   @@@@@ .           @@   .       | ",
X	"  \\     @@@@  @\\@@    /  .  O    .     o   . / ",
X	"   \\  o  @@     \\ \\  /         .    .       /  ",
X	"    `\\     .    .\\.-.___   .      .   .-. /'   ",
X	"      \\           `-'                `-' /     ",
X	"       `-.   o   / |     o    O   .   .-'      ",
X	"          `-.   /     .       .    .-'         ",
X	"             `--.       .      .--'            ",
X	"                 `------------'                "};
X    
X    static char background24[24][49] = {
X	"                  .------------.                 ",
X	"             .---' o     .  .   `---.            ",
X	"          .-'   .    O    .       .  `-.         ",
X	"        .'@   @@@@@@@   .   @@@@@       `.       ",
X	"      .'@@  @@@@@@@@@@@    @@@@@@@   .    `.     ",
X	"     /    o @@@@@@@@@@@    @@@@@@@       .  \\    ",
X	"    /@  o   @@@@@@@@@@@.    @@@@@@@   O      \\   ",
X	"   /@@@   .   @@@@@@@o     @@@@@@@@@@     @@@ \\  ",
X	"  /@@@@@               .  @@@@@@@@@@@@@ o @@@@ \\ ",
X	"  |@@@@  O  `.-./  .       @@@@@@@@@@@@    @@  | ",
X	" / @@@@    --`-'       o      @@@@@@@@ @@@@     \\",
X	" |@ @@@     @  `           .   @@     @@@@@@@   |",
X	" |      @           o          @      @@@@@@@   |",
X	" \\       @@            .-.      @@@    @@@@  o  /",
X	"  | . @        @@@     `-'    . @@@@           | ",
X	"  \\      @@   @@@@@ .            @@   .        / ",
X	"   \\    @@@@  @\\@@    /  .   O    .     o   . /  ",
X	"    \\ o  @@     \\ \\  /          .    .       /   ",
X	"     \\     .    .\\.-.___    .      .   .-.  /    ",
X	"      `.          `-'                 `-' .'     ",
X	"        `.   o   / |      o    O   .    .'       ",
X	"          `-.   /      .       .     .-'         ",
X	"             `---.       .      .---'            ",
X	"                  `------------'                 "};
X    static char background29[29][59] = {
X	"                      .--------------.                     ",
X	"                 .---'  o        .    `---.                ",
X	"              .-'    .    O  .         .   `-.             ",
X	"           .-'     @@@@@@       .             `-.          ",
X	"         .'@@   @@@@@@@@@@@       @@@@@@@   .    `.        ",
X	"       .'@@@  @@@@@@@@@@@@@@     @@@@@@@@@         `.      ",
X	"      /@@@  o @@@@@@@@@@@@@@     @@@@@@@@@     O     \\     ",
X	"     /        @@@@@@@@@@@@@@  @   @@@@@@@@@ @@     .  \\    ",
X	"    /@  o      @@@@@@@@@@@   .  @@  @@@@@@@@@@@     @@ \\   ",
X	"   /@@@      .   @@@@@@ o       @  @@@@@@@@@@@@@ o @@@@ \\  ",
X	"  /@@@@@                  @ .      @@@@@@@@@@@@@@  @@@@@ \\ ",
X	"  |@@@@@    O    `.-./  .        .  @@@@@@@@@@@@@   @@@  | ",
X	" / @@@@@        --`-'       o        @@@@@@@@@@@ @@@    . \\",
X	" |@ @@@@ .  @  @    `    @            @@      . @@@@@@    |",
X	" |   @@                         o    @@   .     @@@@@@    |",
X	" |  .     @   @ @       o              @@   o   @@@@@@.   |",
X	" \\     @    @       @       .-.       @@@@       @@@      /",
X	"  |  @    @  @              `-'     . @@@@     .    .    | ",
X	"  \\ .  o       @  @@@@  .              @@  .           . / ",
X	"   \\      @@@    @@@@@@       .                   o     /  ",
X	"    \\    @@@@@   @@\\@@    /        O          .        /   ",
X	"     \\ o  @@@       \\ \\  /  __        .   .     .--.  /    ",
X	"      \\      .     . \\.-.---                   `--'  /     ",
X	"       `.             `-'      .                   .'      ",
X	"         `.    o     / | `           O     .     .'        ",
X	"           `-.      /  |        o             .-'          ",
X	"              `-.          .         .     .-'             ",
X	"                 `---.        .       .---'                ",
X	"                      `--------------'                     "};
X
X    static char qlits[8][16] = {
X	"New Moon +     ",
X	"First Quarter +",
X	"Full Moon +    ",
X	"Last Quarter + ",
X	"First Quarter -",
X	"Full Moon -    ",
X	"Last Quarter - ",
X	"New Moon -     " };
X
X
X    /* Find the length of the atfiller string. */
X    atflrlen = strlen( atfiller );
X
X    /* Convert a new moon date from a string to a tws. */
X    twscopy( &twsanewmoon, dparsetime( "05jan81 23:24:00 PST" ) );
X
X    /* Subtract the new moon date from the desired date to get the interval
X       since the new moon. */
X    secdiff = twsubtract( t, &twsanewmoon );
X
X    /* Figure out the phase - the interval since the last new moon. */
X    secphase = secdiff % secsynodic;
X    if ( secphase < 0L )
X	secphase += secsynodic;  /* fucking mathematician language designers */
X    angphase = (float) secphase / (float) secsynodic * 2.0 * PI;
X    mcap = -cos( angphase );
X
X    /* Figure out how big the moon is. */
X    yrad = numlines / 2.0;
X    xrad = yrad / ASPECTRATIO;
X
X    /* Figure out some other random stuff. */
X    midlin = numlines / 2;
X    qlitidx = angphase / PI * 2.0;
X
X    /* Now output the moon, a slice at a time. */
X    atflridx = 0;
X    for ( lin = 0; lin < numlines; lin = lin + 1 )
X	{
X	/* Compute the edges of this slice. */
X	y = lin + 0.5 - yrad;
X	xright = xrad * sqrt( 1.0 - ( y * y ) / ( yrad * yrad ) );
X	xleft = -xright;
X	if ( angphase >= 0.0 && angphase < PI )
X	    xleft = mcap * xleft;
X	else
X	    xright = mcap * xright;
X	colleft = (int) (xrad + 0.5) + (int) (xleft + 0.5);
X	colright = (int) (xrad + 0.5) + (int) (xright + 0.5);
X
X	/* Now output the slice. */
X	for ( i = 0; i < colleft; i++ )
X	    putchar( ' ' );
X	for ( col = colleft; col <= colright; col = col + 1 )
X	    {
X	    switch ( numlines )
X		{
X		case 18:
X		    c = background18[lin][col];
X		    break;
X		case 19:
X		    c = background19[lin][col];
X		    break;
X	        case 23:
X		    c = background23[lin][col];
X		    break;
X	        case 24:
X		    c = background24[lin][col];
X		    break;
X	        case 29:
X		    c = background29[lin][col];
X		    break;
X		default:
X		    c = '@';
X		}
X	    if ( c != '@' )
X		putchar( c );
X	    else
X		{
X		putchar( atfiller[atflridx] );
X		atflridx = ( atflridx + 1 ) % atflrlen;
X		}
X	    }
X
X	/* Output the end-of-line information, if any. */
X	if ( lin == midlin - 2 )
X	    {
X	    putchar( '\t' );
X	    putchar( '\t' );
X	    fputs( qlits[qlitidx], stdout );
X	    }
X	else if ( lin == midlin - 1)
X	    {
X	    putchar( '\t' );
X	    putchar( '\t' );
X	    putseconds( secphase % (secsynodic / 4) );
X	    }
X	else if ( lin == midlin )
X	    {
X	    putchar( '\t' );
X	    putchar( '\t' );
X	    fputs( qlits[qlitidx + 4], stdout );
X	    }
X	else if ( lin == midlin + 1 )
X	    {
X	    putchar( '\t' );
X	    putchar( '\t' );
X	    putseconds( (secsynodic - secphase) % (secsynodic / 4) );
X	    }
X
X	putchar( '\n' );
X	}
X
X    }
X
X
Xputseconds( secs )
Xlong secs;
X    {
X    long days, hours, minutes;
X
X    days = secs / SECSPERDAY;
X    secs = secs - days * SECSPERDAY;
X    hours = secs / SECSPERHOUR;
X    secs = secs - hours * SECSPERHOUR;
X    minutes = secs / SECSPERMINUTE;
X    secs = secs - minutes * SECSPERMINUTE;
X
X    printf( "%ld %2ld:%02ld:%02ld", days, hours, minutes, secs );
X    }
SHAR_EOF
if test 12899 -ne "`wc -c < 'phoon.c'`"
then
	echo shar: error transmitting "'phoon.c'" '(should have been 12899 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'phoon.man'" '(696 characters)'
if test -f 'phoon.man'
then
	echo shar: will not over-write existing file "'phoon.man'"
else
sed 's/^X//' << \SHAR_EOF > 'phoon.man'
X.TH phoon 1 "08 November 1986"
X.SH NAME
Xphoon \- show the PHase of the mOON
X.SH SYNOPSIS
X.in +.5i
X.ti -.5i
Xphoon  \%[ -l <lines> ]  \%[ <date> ]
X.in -.5i
X.SH DESCRIPTION
X.I Phoon
Xdisplays the phase of the moon, either currently
Xor at a specified date / time.
XUnlike other such programs, which just tell you how long since first quarter
Xor something like that, phoon
X.I shows
Xyou the phase with a cute little picture.
XYou can vary the size of the picture with the -l flag, but only some
Xsizes have pictures defined - other sizes use @'s.
X.SH "SEE\ ALSO"
X.IR deltime(1),
X.IR libtws(3)
X.SH AUTHOR
XJef Poskanzer
X.SH BUGS
XThe algorithm for determining the phase is very simple, but not very
Xaccurate.
SHAR_EOF
if test 696 -ne "`wc -c < 'phoon.man'`"
then
	echo shar: error transmitting "'phoon.man'" '(should have been 696 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'tws.h'" '(2290 characters)'
if test -f 'tws.h'
then
	echo shar: will not over-write existing file "'tws.h'"
else
sed 's/^X//' << \SHAR_EOF > 'tws.h'
X/* tws.h - header file for libtws date/time library */
X
X
X/* Definition of the tws data structure. */
X
Xstruct tws {
X    int     tw_sec;
X    int     tw_min;
X    int     tw_hour;
X
X    int     tw_mday;
X    int     tw_mon;
X    int     tw_year;
X
X    int     tw_wday;
X    int     tw_yday;
X
X    int     tw_zone;
X
X    long    tw_clock;
X
X    int     tw_flags;
X#define TW_NULL 0x0000
X#define TW_SDAY 0x0007		/* how day-of-week was determined */
X#define   TW_SNIL 0x0000	/*   not given */
X#define   TW_SEXP 0x0001	/*   explicitly given */
X#define   TW_SIMP 0x0002	/*   implicitly given */
X#define TW_DST  0x0010		/* daylight savings time */
X#define TW_ZONE 0x0020		/* use numeric timezones only */
X#define TW_JUNK 0x0040		/* date string contained junk */
X};
X
X
X/* Declarations of routines. */
X
Xvoid twscopy( );
X	/* twscopy( &totws, &fromtws ) copies a tws */
Xint twsort( );
X	/* twsort( &tws1, &tws2 ) compares two tws's: 1 means tws1 is
X	   later; -1 means tws1 is earlier; 0 means they are equal */
Xlong twclock( );
X	/* twclock( &tws ) turns a tws into a time(3)-style clock value */
Xlong twjuliandate( );
X	/* twjuliandate( &tws ) returns the Julian day number of a tws */
Xlong twsubtract( );
X	/* twsubtract( &tws1, &tws2 ) returns seconds of difference */
X
X/* These routines are functionally similar to the ctime(3) routines
X   in the standard Unix library. */
Xchar *dctime( );
X	/* dctime( &tws ) returns a string for the date/time passed in */
Xstruct tws *dlocaltime( );
X	/* dlocaltime( &clock ) turns a time(3) clock value into a tws */
Xstruct tws *dgmtime( );
X	/* dgmtime( &clock ) turns a time(3) clock value into a tws */
Xchar *dasctime( );
X	/* dasctime( &tws, flags ) turns a tws into a string */
Xchar *dtimezone( );
X	/* dtimezone( offset, flags ) returns the name of the time zone */
X
Xchar *dtimenow( );
X	/* dtimenow( ) returns a string for the current date/time */
X
Xstruct tws *dparsetime( );
X	/* dparsetime( &str ) turns a string into a tws */
X
Xstruct tws *dtwstime( );
X	/* dtwstime( ) returns a tws for the current date/time */
X
X#ifdef ATZ
X#define dtime(cl) dasctime( dlocaltime( cl ), TW_NULL )
X#else ATZ
X#define dtime(cl) dasctime( dlocaltime( cl ), TW_ZONE )
X#endif ATZ
X
X#define dtwszone(tw) dtimezone( tw -> tw_zone, tw -> tw_flags )
X
X
Xextern char   *tw_dotw[], *tw_ldotw[], *tw_moty[];
SHAR_EOF
if test 2290 -ne "`wc -c < 'tws.h'`"
then
	echo shar: error transmitting "'tws.h'" '(should have been 2290 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0