[comp.sources.misc] v17i097: calentool - day/week/month/year-at-a-glance SunView tool, Part16/23

billr@saab.CNA.TEK.COM (Bill Randle) (04/06/91)

Submitted-by: Bill Randle <billr@saab.CNA.TEK.COM>
Posting-number: Volume 17, Issue 97
Archive-name: calentool/part16

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 16 (of 23)."
# Contents:  ct.h dates/celtic dates/sports month2ct.c utils.c
# Wrapped by billr@saab on Thu Mar 28 08:38:27 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'ct.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ct.h'\"
else
echo shar: Extracting \"'ct.h'\" \(8475 characters\)
sed "s/^X//" >'ct.h' <<'END_OF_FILE'
X/*
X * $Header: ct.h,v 2.5 91/03/27 16:45:12 billr Exp $
X */
X/*
X * ct.h - header file for calentool
X *
X * Author: Philip Heller, Sun Microsystems. Inc. <terrapin!heller@sun.com>
X *
X * Original source Copyright (C) 1987, Sun Microsystems, Inc.
X *	All Rights Reserved
X * Permission is hereby granted to use and modify this program in source
X * or binary form as long as it is not sold for profit and this copyright
X * notice remains intact.
X *
X *
X * Changes/additions by: Bill Randle, Tektronix, Inc. <billr@saab.CNA.TEK.COM>
X *
X * Changes and additions Copyright (C) 1988, 1989, 1991 Tektronix, Inc.
X *	All Rights Reserved
X * Permission is hereby granted to use and modify the modifications in source
X * or binary form as long as they are not sold for profit and this copyright
X * notice remains intact.
X */
X
X/*
X * If calentool is too big and you want a stripped-down version
X * define some or all of these here or in the Makefile. Combined,
X * they save ~100K bytes for a statically linked object.
X */
X#define NO_PRINTER		/* exclude printer support code */
X/*#define NO_HOLIDAYS		/* exclude holiday checking code */
X/*#define NO_SUN_MOON		/* exclude Sun/Moon data frames */
X
X/* ignore several things for calencheck program */
X#ifdef CALENCHECK
X#	define NO_PRINTER
X#	define NO_HOLIDAYS
X#	define NO_SUN_MOON
X#	define NOTOOL
X#endif
X
X/* directory for date/event files */
X#ifndef DATELIB_DIR
X#	define DATELIB_DIR	"/usr/net/lib/calentool"
X#endif
X
X#ifndef NO_PRINTER
X/* command string for sending a file to the Postscript printer */
X#	ifndef PRINT_CMD
X#		define PRINT_CMD	"lpr -Plw"
X#	endif
X
X/*#	define RASTER_ONLY	/* define this if no PostScript printer available */
X#	ifndef PS_NOTE_FONT
X#		define PS_NOTE_FONT     "Helvetica-Narrow"
X#	endif
X/*#	define LANGUAGE		/* for natural language support */
X				/* see the file pcaldw.c for details */
X#else
X#	define RASTER_ONLY	/* do not change this line */
X#endif /* NO_PRINTER */
X
X#ifndef MAILPROG
X#	define MAILPROG		"/usr/ucb/mail"
X				/* assumes -s option is available */
X#endif
X
X/* define NR_WEEKDAYS for desired week display */
X/* NR_WEEKDAYS		display   */
X/*	5		Mon-Fri   */
X/*	6		Mon-Sat	  */
X/*	7		Sun-Sat	or Mon-Sun  */
X/**/
X#ifndef NR_WEEKDAYS
X#	define NR_WEEKDAYS	5
X#endif
X#ifndef MON_FIRST
X#	define MON_FIRST	0	/* 0=Sun-Sat, 1=Mon-Sun */
X#endif
X
X#ifndef START_HOUR
X#	define START_HOUR	8	/* 8am */
X#endif					/*  to */
X#ifndef END_HOUR
X#	define END_HOUR		18	/* 6pm */
X#endif
X#ifndef HOUR_24
X#	define HOUR_24		0	/* 0=12hr time, 1=24hr time */
X#endif
X#ifndef DAY_FIRST
X#	define DAY_FIRST	0	/* 0=M/D/Y, 1=D/M/Y */
X#endif
X
X#ifndef START_YEAR
X#	define START_YEAR	90
X#endif
X#ifndef NR_YEARS
X#	define NR_YEARS		5	/* number of years in menu */
X#endif
X
X#ifndef N_NOTESLOTS
X#	define N_NOTESLOTS	10	/* number of slots for notes */
X#endif
X
X#ifndef UPDATE_RATE
X#	define UPDATE_RATE	"second"	/* update time */
X#endif 					/* options are "second" & "minute" */
X#define TIME_OUT	2		/* check appts every 5 minutes */
X
X/*
X * APPT_CHECK_LIMIT is typically either "n_tslots"
X * or "n_slots" depending on whether we include the
X * notes section when indicating that we still have
X * appts today.
X */
X#ifndef APPT_CHECK_LIMIT
X#	define APPT_CHECK_LIMIT	n_tslots
X#endif
X
X/*********************************************************************/
X/* Nothing below here should need to be changed (typically)          */
X/*********************************************************************/
X
X#ifndef TRUE
X#	define TRUE	1
X#endif
X#ifndef FALSE
X#	define FALSE	0
X#endif
X
X#define MAX_FUTURE_ENTRIES	32	/* number of appts displayed in popup window */
X
X/* Dimensions of 30-minute week slot.
X * Message size determines width - everything else keyed
X * off font size and message size
X */
X#define WEEK_MESSAGE_SIZE	12
X
X#define MAX_INCLUDE_NESTING	4	/* number of allowed include files */
X
X#define DISPLAYING_DAY          1       /* Defs for state of main */
X#define DISPLAYING_WEEK         2	/* subwindow (mainsw_state) */
X#define DISPLAYING_MONTH        3
X#define DISPLAYING_YEAR         4
X
X#define BACKSPACE               8	/* editing chars */
X#define CTRL_R                  18
X#define CTRL_U                  21
X#define CTRL_W                  23
X#define DEL                     127
X
X#define NONE			0
X#define DAY			1	/* Defs for "selected_type" (type of */
X#define WEEK			2	/* object selected by month click). */
X#define MONTH			3
X
X#define JUSTIFY_LEFT	0		/* text justification in day slot */
X#define JUSTIFY_RIGHT	1
X#define JUSTIFY_INDEX	2
X
X#define FOUND_SLOT	1		/* event tags for day display */
X#define FOUND_MORE	2
X#define FOUND_LARROW	3
X#define FOUND_RARROW	4
X
X#define MMODIFY		1		/* order of entries in day menu */
X#define MCUT		2
X#define MPASTE		3
X#define MCOPY		4
X#define MDELETE		5
X#define MUNDELETE	6
X
X#define PR_DEFAULT	0		/* print options */
X#define PR_ASCII	1
X#define PR_POSTSCRIPT	2
X#define PR_RASTER	3
X
X#define SUN		0		/* days of the week */
X#define MON		1
X#define TUE		2
X#define WED		3
X#define THU		4
X#define FRI		5
X#define SAT		6
X
X#define JAN		0		/* selected months */
X#define FEB		1
X#define DEC		11
X
X#define ALL_YEARS	0x1		/* flags for special case appts */
X#define ALL_MONTHS	0x2
X#define ALL_DAYS	0x4
X#define REPEAT		0x8
X	/* check for any repeating type appt */
X#	define Repeating(d)	((d)&(ALL_YEARS|ALL_MONTHS|ALL_DAYS|REPEAT|EVERY_MON_FRI))
X#define A_COMMENT	0x10
X#define EVERY_SUN	0x20
X#define EVERY_MON	0x40
X#define EVERY_TUE	0x60
X#define EVERY_WED	0x80
X#define EVERY_THU	0xa0
X#define EVERY_FRI	0xc0
X#define EVERY_SAT	0xe0
X#define	EVERY_SOMEDAY	0xe0
X	/* convert flag value to day-of-week number */
X#	define Pickday(d)	((((d)&EVERY_SOMEDAY)>>5)-1)	
X	/* convert day of week to flag value */
X#	define Setday(d)	(((d)+1)<<5)
X#define LOOKAHEAD	0x100
X#define READONLY	0x200
X#define A_NOTE		0x400
X#define MARKED		0x800	/* don't show in month/year display */
X#define MARKED_NOTE	0xc00
X#define DELETED		0x1000	/* don't show the appt that matches this */
X#define RUN		0x2000
X#define EVERY_MON_FRI	0x4000
X
X/* format of repeat field for every_someday type appts */
X#define WEEK1		0x1
X#define WEEK2		0x2
X#define WEEK3		0x4
X#define WEEK4		0x8
X#define WEEK5		0x10
X#define ALL_WEEKS	0x1f
X#define LAST_WEEK	0x20
X#define WEEK_LIMIT	0x3f
X
X/* error reporting flags */
X#define NON_FATAL	0
X#define FATAL		1
X
X/* icon identifiers */
X#define STD_ICON	0		/* flags for icon currently displayed */
X#define REV_ICON	1
X#define NA_ICON		2
X
X/* arguments to print_apts() */
X#define PRI_DAY			1
X#define PRI_WEEK		2
X#define PRI_MONTH		3
X#define PRI_XNOTES		4
X#define PRI_DAY_XNOTES		(PRI_DAY|PRI_XNOTES)
X#define PRI_WEEK_XNOTES		(PRI_WEEK|PRI_XNOTES)
X#define PRI_MONTH_XNOTES 	(PRI_MONTH|PRI_XNOTES)
X#define DST_STDOUT		1
X#define DST_MAIL		2
X
X/* return codes from get_day_appts() */
X#define NO_ENTRIES	0
X#define SOME_APPTS	1
X#define SOME_NOTES	2
X#define SOME_MKNOTES	4
X#define SOME_FUTURES	8
X
X/* header line in appts file implies one-based entries and 99 memo flag */
X#define HEADER		"# CalenTool V2.2 - DO NOT REMOVE THIS LINE\n"
X#define OHEADER		"# CalenTool V2 - DO NOT REMOVE THIS LINE\n"
X
X#define MAX_STRLEN	256	/* max size of strings */
Xstruct appt_entry {
X	/* describes an entry in the appointments file */
X	int year, month, day, hour, minute, arrows;
X	int repeat, lookahead, flags, sindex;
X	int runlength, warn;
X	char str[MAX_STRLEN];
X	struct appt_entry *next;	/* ptr to next appt in list */
X};					/* NULL if last entry */
X
Xstruct rect_pos {
X	/* location of a given rect in the canvas */
X	int top, bottom, left, right;
X};
X
Xstruct dayslot {
X	/* struct for storing relevant info for 30 min day slot */
X	struct rect_pos slot_pos; /* slot position in day display */
X	struct rect_pos larrow_pos; /* position of left scroll arrow */
X	struct rect_pos rarrow_pos; /* position of right scroll arrow */
X	struct rect_pos moreb_pos; /* position of "more" button */
X	int active;	/* number of appts that originate here */
X	int count;	/* number of appts in this slot */
X	int arrow_pos;	/* bitmap of arrow locations on screen */
X	struct appt_entry *cur_appt;	/* ptr to current appt in list */
X	struct appt_entry *first;	/* ptr to first appt in list */
X};					/* NULL if no entries */
X
Xstruct weekrect {
X	/* info for week display */
X	struct rect_pos wday_pos; /* screen position of this day */
X	struct rect_pos moreb_pos; /* position of "more" button */
X	int more;
X	struct dayslot *weekslots; /* array of slots for this day */
X};
X
Xstruct rect_limits {
X	int lowx;
X	int lowy;
X	int highx;
X	int highy;
X};
X
Xstruct week_arrow {
X	int top;
X	int bottom;
X	int left;
X	int right;
X	int active;
X};
END_OF_FILE
if test 8475 -ne `wc -c <'ct.h'`; then
    echo shar: \"'ct.h'\" unpacked with wrong size!
fi
# end of 'ct.h'
fi
if test -f 'dates/celtic' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dates/celtic'\"
else
echo shar: Extracting \"'dates/celtic'\" \(541 characters\)
sed "s/^X//" >'dates/celtic' <<'END_OF_FILE'
X# CalenTool V2.2 - nflag=1 range=2,11 - DO NOT REMOVE THIS LINE
X# $Header: celtic,v 2.3 91/03/07 16:21:04 billr Exp $
X# Special days file for calentool (rel 2.1); modified from network posting by
X# RPC Rodgers, UCSF, Nov. 1988
X# Dates of interest to Celts
X#
X** 02 01 99 99 00 Oimelc (Winter purification & approach of spring)
X** 05 01 99 99 00 Beltaine (Feast of sun god Bel)
X** 08 01 99 99 00 Lughnasa (Feast of god Lugh, 30 day Celtic feast centers on this day)
X** 11 01 99 99 00 Samhain (beginning of Celtic year, most important holiday)
END_OF_FILE
if test 541 -ne `wc -c <'dates/celtic'`; then
    echo shar: \"'dates/celtic'\" unpacked with wrong size!
fi
# end of 'dates/celtic'
fi
if test -f 'dates/sports' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dates/sports'\"
else
echo shar: Extracting \"'dates/sports'\" \(8498 characters\)
sed "s/^X//" >'dates/sports' <<'END_OF_FILE'
X# CalenTool V2.2 - nflag=1 range=1,12 - DO NOT REMOVE THIS LINE
X# $Header: sports,v 1.2 91/03/07 16:21:32 billr Exp $
X# Special dates in sports history
X# Today in History dates provided by Robert Heckendorn at
X# Hewlett-Packard in Fort Collins, Colorado.
X# Any corrections or additions may be sent to robert@fc.hp.com
X#
X# Additional dates provided from ProLine's today file
X#
X# Converted to calentool format by Larry Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
X# and further edited and merged by Bill Randle (billr@saab.cna.tek.com).
X#
X** 01 01 99 99 00 1st Rose Bowl game held in Pasadena, California. (1902)
X** 01 01 99 99 00 1st running of SF's famed "Bay to Breakers" race (7.63 miles) (1912)
X** 01 01 99 99 00 All registered thoroughbred and quarter horses are "born" on this day
X** 01 16 99 99 00 First college basketball game, Iowa vs Chicago (1896)
X** 01 29 99 99 00 1st athletic letters given: to Univ of Chicago football team. (1904)
X** 02 02 99 99 00 National Baseball League formed with 8 teams. (1876)
X** 02 04 99 99 00 1st Winter Olympics held (At Lake Placid, NY). (1932)
X** 02 12 99 99 00 The six cars entered in the New York to Paris road race set off on their 12116 mile race through Alaska and Russia. America won. (1908)
X** 03 11 99 99 00 1st public game of basketball. (1892)
X** 03 28 99 99 00 A New York judge rules that the contest between the American catamaran and the Australian monohull was not fair competition and the America's Cup was returned to the Australians (1989)
X** 04 04 99 99 00 President William Howard Taft throws out the first ball of the season to a game between Washington and Philadelphia. Thus starting a tradition (1910)
X** 04 04 99 99 00 Hank Aaron of Atlanta Braves ties Babe Ruth's home run record at 714 (1974)
X** 04 08 99 99 00 Hammerin' Hank Aaron hits 715th home run, beats Babe Ruth's record. (1974)
X** 04 11 99 99 00 Jackie Robinson breaks the color barrier in baseball when he plays for the Brooklyn Dodgers (1947)
X** 04 12 99 99 00 The catcher's mask was first used in a baseball game. (1877)
X** 04 14 99 99 00 President Taft starts the tradition of throwing out the 1st baseball (1910)
X** 04 16 99 99 00 Bob Feller of the Cleveland Indians pitched a no-hitter on opening day of the American League season (1940)
X** 04 23 99 99 00 Hank Aaron hits his first home run (1954)
X** 04 28 99 99 00 Muhammad Ali (Heavyweight Champ) refused to be inducted into Army (1967)
X** 05 02 99 99 00 Lou Gehrig sets record for being in most consecutive games (2130). (1939)
X** 05 17 99 99 00 First Kentucky Derby held (1875)
X** 05 17 99 99 00 The first Kentucky Derby was run at Churchill Downs. (1875)
X** 05 25 99 99 00 Babe Ruth hits his 714th and final home run of his career (1935)
X** 05 30 99 99 00 Indianapolis 500 car race run for 1st time. (1911)
X** 06 01 99 99 00 Lou Gehrig starts in 1st of 2130 consecutive games, a record. (1925)
X** 06 11 99 99 00 1st auto race. (1895)
X** 06 12 99 99 00 The National Baseball Hall of Fame and Museum was dedicated. (1939)
X** 06 12 99 99 00 the 1st baseball game is played in America (1839)
X** 06 12 99 99 00 the 3rd baseball strike starts. (1981)
X** 07 05 99 99 00 New York Mets defeated Atlanta Braves, 16-13, in 19 inning game that lasted 6 hours and 10 min. ending just before 4 a.m. (1985)
X** 07 06 99 99 00 1st All-Star baseball game.  American League won 5-2. (1933)
X** 07 11 99 99 00 Houston Astros pitcher, Nolan Ryan struck out 4000 batters. (1985)
X** 07 13 99 99 00 Women first compete in Olympic games (1908)
X** 07 18 99 99 00 Ty Cobb gets 4000th base hit (1927)
X** 07 20 99 99 00 admission fee 1st charged to see a baseball game (50 cents). (1859)
X** 07 21 99 99 00 Eddy Merckx won his first of five Tour de France victories (1969)
X** 07 23 99 99 00 Greg LeMond wins his second Tour de France, beating Laurent Fignon in the final 15 mile time trial by turning a 50 second deficit into a win by 8 seconds! (1989)
X** 07 29 99 99 00 King George VI opened the Olympic games in London (1948)
X** 08 01 99 99 00 Adolph Hitler opened the Olympic Games in Berlin. (1936)
X** 08 02 99 99 00 Several former members of the Chicago White Sox and two others were acquitted in the "Black Sox" scandal (1921)
X** 08 06 99 99 00 Cy Young pitches first major league game (1890)
X** 08 06 99 99 00 Gertrude Ederle of New York is the first American woman to swim the English Channel (1926)
X** 08 08 99 99 00 the first America's Cup race (1870)
X** 08 10 99 99 00 Pete Rose tops Stan Musial's record of 3630 hits. (1981)
X** 08 20 99 99 00 Diana Nyad becomes the first woman to swim the 89 miles from the Bahamas to Florida (time: 27h 38m) (1979)
X** 08 21 99 99 00 Babe Ruth hit his 600th career home run. (1931)
X** 08 22 99 99 00 Althea Gibson becomes the first black tennis plaer to be accepted in competition for the national chapionship (1950)
X** 08 22 99 99 00 the yacht America wins in race against 14 yachts of England in the first America Cup sailing race (1851)
X** 08 25 99 99 00 Captain Matthew Webb becomes the first person to swim the English Channel, travelling from Dover to Calais in 22 hours (1875)
X** 08 26 99 99 00 The summer Olympics opened in Munich, West Germany. (1972)
X** 08 29 99 99 00 Lou Brock eclipsed the stolen-bases record as he stole two bases against the San Diego Padres, bring his total to 893 (1977)
X** 08 31 99 99 00 The 1st U.S. tennis championships were played in Newport, R.I. (1882)
X** 09 01 99 99 00 Bobby Fischer defeats Boris Spassky in World Chess Match (1972)
X** 09 04 99 99 00 Mark Spitz becomes first man to win 7 gold medals in the Olympics (1972)
X** 09 06 99 99 00 Czechoslovakian tennis star, Martina Navratilova, requested political asylum while in New York for the U.S. open (1975)
X** 09 07 99 99 00 ESPN, the sports cable network, makes its debut (1979)
X** 09 13 99 99 00 Fay Vincent was named commissioner of Major League Baseball. (1989)
X** 09 13 99 99 00 The ladies Professional Golf Association of America was formed. (1949)
X** 09 17 99 99 00 The American Professional Football Association was formed. (1920)
X** 09 23 99 99 00 1st closed circuit pay-TV telecast of a sports event. (1952)
X** 09 23 99 99 00 New York Knickerbockers becomes first U.S. Baseball club (1845)
X** 09 24 99 99 00 Babe Ruth makes his farewell regular baseball player for the New York Yankees (1934)
X** 09 26 99 99 00 Australia II won the America's Cup yacht race. (1983)
X** 09 28 99 99 00 eight members of the Chicago White Sox were indicted for allegedly throwing the 1919 World Series against the Cincinnati Reds in the "Black Sox" scandal (1920)
X** 09 29 99 99 00 The 1st night football game was played in Mansfield, Pennsylvania. (1892)
X** 10 01 99 99 00 1st World Series starts between the National & American Leagues (1903)
X** 10 07 99 99 00 Georgia Tech beat Cumberland University 222-0 in a football game. (1916)
X** 10 07 99 99 00 Lynnette Woodward becomes the first female Harlem Globetrotter (1985)
X** 10 12 99 99 00 The race horse Man O'War's last race (1920)
X** 10 13 99 99 00 The International Olympic committee announced it would restore the two gold medals it had taken from Jim Thorpe (1982)
X** 10 13 99 99 00 The first world series game is played (1903)
X** 10 18 99 99 00 Connie Mack, the "Grand Old Man" of major league baseball, announced he would retire as manager of the Philadelphia Athletics (1950)
X** 10 18 99 99 00 the Ivy League establishes rules for college football. (1873)
X** 10 19 99 99 00 Jim Ochowicz, manager of the Seven-Eleven cycling team announced that the team will be sponsored by Motorola (1990)
X** 11 01 99 99 00 Notre Dame's football team upsets Army 35-13 in a game that help popularize the forward pass (1913)
X** 11 06 99 99 00 the first formal intercollegiate football game played (Rutgers 6 - Princeton 4) (1869)
X** 11 25 99 99 00 Radio station WTAW of college station, Texas, broadcast the first play-by-play description of a football game (1920)
X** 11 28 99 99 00 The first automobile race was held from Chicago to Waukegan through the snow; 6 cars, 55 miles, winner averaged 7 MPH (1895)
X** 11 29 99 99 00 1st Army-Navy football game.  Score: Navy 25, Army 0. (1890)
X** 12 04 99 99 00 Numbers first appear on football uniforms (1908)
X** 12 15 99 99 00 James Naismith, a Canadian, invents basketball, while working at the Y.M.C.A. College at Springfield, Massachusetts (1891)
X** 12 17 99 99 00 1st professional football game: Chicago Bears vs. NY Giants. (1933)
X** 12 26 99 99 00 1st East-West football game at Ewing Park before 25,000 fans. (1925)
END_OF_FILE
if test 8498 -ne `wc -c <'dates/sports'`; then
    echo shar: \"'dates/sports'\" unpacked with wrong size!
fi
# end of 'dates/sports'
fi
if test -f 'month2ct.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'month2ct.c'\"
else
echo shar: Extracting \"'month2ct.c'\" \(4022 characters\)
sed "s/^X//" >'month2ct.c' <<'END_OF_FILE'
X/*
X * $Header: month2ct.c,v 2.2 91/02/01 12:20:10 billr Exp $
X */
X/*
X * month2ct - convert month schedule files to calentool style files
X *
X * Author: Bill Randle, Tektronix, Inc. <billr@saab.CNA.TEK.COM>
X *
X * Copyright (C) 1989, 1991 Tektronix, Inc.  All Rights Reserved
X *
X * Permission is hereby granted to use and modify this code in source
X * or binary form as long as it is not sold for profit and this copyright
X * notice remains intact.
X */
X
X#include "month.h"
X#include "ct.h"
X#include <stdio.h>
X
Xstruct appt_entry appt;
Xstruct event_rec events;
XFILE *fp;
Xchar filename[128];
Xchar *dir, *getenv();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	if (argc > 1)
X		dir = argv[1];
X	else {
X		strcpy(filename, getenv("HOME"));
X		dir = filename;
X	}
X
X	if (read_schedule(dir, READ_ONLY)) {
X		fprintf(stderr, "no reminders read from %s/.month\n", dir);
X		exit(1);
X	}
X	strcpy(filename, getenv("HOME"));
X	strcat(filename, "/.appointments");
X	if ((fp = fopen(filename, "w")) == NULL) {
X		fprintf(stderr, "can't open .appointments file for writing\n");
X		exit(1);
X	}
X	write_ct_file();
X}
X
X/*
X * write out the new .appointments file
X */
Xwrite_ct_file()
X{
X	struct event_rec *evt;
X	int length, oflags, i;
X
X	evt = &events;
X	fputs(HEADER, fp);
X	/* first event is empty */
X	evt = evt->next_event;
X	while (evt) {
X		/* DEBUG
X		fprintf(stderr,"evt struct:\n  mly=%d, yly=%d, evry=%d\n  nth=%d, last=%d, nthon=%d\n  str=%s\n",
X			evt->monthly, evt->yearly, evt->every, evt->nth, evt->last, evt->nth_is_on, evt->event_string);
X		*/
X		appt.flags = appt.repeat = appt.lookahead = 0;
X		appt.warn = 10;  /* default */
X		appt.year = evt->start_date.year - 1900;
X		appt.month = evt->start_date.month - 1;
X		appt.day = evt->start_date.day;
X		strcpy(appt.str, evt->event_string);
X		if (evt->monthly)
X			appt.flags |= ALL_MONTHS;
X		if (evt->yearly)
X			appt.flags |= ALL_YEARS;
X		appt.hour = evt->start_time.hour;
X		appt.minute = evt->start_time.minute;
X		if (appt.hour > 23 || appt.hour < 0 || appt.minute > 59 || appt.minute < 0)
X			appt.flags |= A_NOTE;
X		if (appt.minute < 15)
X			appt.minute = 0;
X		else if (appt.minute < 45)
X			appt.minute = 30;
X		else {
X			appt.minute = 0;
X			appt.hour++;
X		}
X		length = evt->duration.hour * 60 + evt->duration.minute;
X		appt.arrows = length / 30 - 1;
X		if (appt.arrows < 0)
X			appt.arrows = 0;
X		if (evt->anti)
X			appt.flags |= DELETED;
X		if (evt->warning.hour >= 24)
X			appt.lookahead = evt->warning.hour / 24;
X		else
X			appt.warn = evt->warning.hour * 60 + evt->warning.minute;
X		if (evt->until) {
X			fprintf(stderr, "this appointment runs more than 1 day,\n");
X			fprintf(stderr, "modify the calentool entry after conversion:\n");
X			fprintf(stderr, "start date (m/d/y): %d/%d/%d, ",
X			  evt->start_date.month, evt->start_date.day,
X			  evt->start_date.year);
X			fprintf(stderr, "start time: %d:%d, ", evt->start_time.hour,
X			  evt->start_time.minute);
X			fprintf(stderr, "runs until (m/d/y): %d/%d/%d\n",
X			  evt->until_date.month, evt->until_date.day,
X			  evt->until_date.year);
X		}
X		if (evt->every) {
X			/* event occurs on an every something */
X			appt.flags |= REPEAT;
X			if (evt->last)
X				appt.repeat = LAST_WEEK;
X			else if (evt->nth_is_on)
X				appt.repeat = 1<<(evt->nth_is_on-1);
X			else
X				appt.repeat = ALL_WEEKS;
X			oflags = appt.flags;
X			/* check for mon-fri */
X			if (!evt->smtwtfs[0] && !evt->smtwtfs[6] &&
X			    evt->smtwtfs[1] && evt->smtwtfs[2] &&
X			    evt->smtwtfs[3] && evt->smtwtfs[4] &&
X			    evt->smtwtfs[5]) {
X				appt.flags |= EVERY_MON_FRI;
X				if (put_aentry(fp, &appt)) {
X					fprintf(stderr,
X					  "error writing .appointments file\n");
X					return;
X				}
X			} else
X				for (i=0; i<7; i++) {
X					if (evt->smtwtfs[i]) {
X						appt.flags = oflags | Setday(i);
X						if (put_aentry(fp, &appt)) {
X							fprintf(stderr,
X							  "error writing .appointments file\n");
X							return;
X						}
X					}
X				}
X		} else
X			if (put_aentry(fp, &appt)) {
X				fprintf(stderr, "error writing .appointments file\n");
X				return;
X			}
X		fputs("\n", fp);
X		evt = evt->next_event;
X	}
X}
END_OF_FILE
if test 4022 -ne `wc -c <'month2ct.c'`; then
    echo shar: \"'month2ct.c'\" unpacked with wrong size!
fi
# end of 'month2ct.c'
fi
if test -f 'utils.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'utils.c'\"
else
echo shar: Extracting \"'utils.c'\" \(29701 characters\)
sed "s/^X//" >'utils.c' <<'END_OF_FILE'
X/*
X * $Header: utils.c,v 2.8 91/03/27 16:46:39 billr Exp $
X */
X/*
X * utils.c
X *
X * calentool - a year/month/week/day-at-a-glance calendar for Sun workstations.
X *
X * Author: Philip Heller, Sun Microsystems. Inc. <terrapin!heller@sun.com>
X *
X * Original source Copyright (C) 1987, Sun Microsystems, Inc.
X *	All Rights Reserved
X * Permission is hereby granted to use and modify this program in source
X * or binary form as long as it is not sold for profit and this copyright
X * notice remains intact.
X *
X *
X * Changes/additions by: Bill Randle, Tektronix, Inc. <billr@saab.CNA.TEK.COM>
X *
X * Changes and additions Copyright (C) 1988, 1989, 1991 Tektronix, Inc.
X *	All Rights Reserved
X * Permission is hereby granted to use and modify the modifications in source
X * or binary form as long as they are not sold for profit and this copyright
X * notice remains intact.
X * Modified parse_date to allow +nnn and -nnn syntax for dates relative to the
X * current date.  Peter Marshall <peter.marshall@uwo.ca>. 1989-09-19.
X */
X/********************************************
X *					    *
X *              Utility routines.	    *
X *					    *
X ********************************************/
X
X
X
X#include "ct.h"
X#include <stdio.h>
X#ifndef NOTOOL
X#include <suntool/sunview.h>
X#include <suntool/canvas.h>
X#endif  /* NOTOOL */
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/file.h>
X#include <sys/stat.h>
X#include <sys/errno.h>
X
X
Xextern struct tm today, current;
Xextern struct tm First;
Xextern int day_is_open, read_only;
Xextern int n_slots;
Xextern struct dayslot *slots;
Xextern char apts_pathname[], tmpapts_pathname[];
Xextern char *progname;
Xextern int one_based, version2, new_entry;
Xextern char apts_dir[], lib_dir[];
Xextern int include_old, save_old, expire_days;
X#ifndef NOTOOL
Xextern Frame frame;
Xextern Canvas canvas;
Xextern Pixwin *main_pixwin;
Xextern int mainsw_state;
Xextern Pixfont *font, *sfont;
Xextern Frame prompt_frame;
Xextern int update_interval;
Xextern int monday_first, hour24, day_first;
X#endif  /* NOTOOL */
Xextern int week_ofs;
Xextern int errno;
X
Xchar inbuf[512], strbuf[256], errbuf[128];
Xchar clockstr[32];
Xstatic int include_level = 0;
Xstatic int log_to_console;
Xchar *daynames[] = {"Sunday","Monday","Tuesday","Wednesday",
X			   "Thursday","Friday","Saturday"};
Xchar *monthnames[] = {"January","February","March","April",
X			     "May","June","July","August",
X			     "September","October","November","December"};
Xchar *smonthnames[] = {"Jan","Feb","Mar","Apr",
X			     "May","Jun","Jul","Aug",
X			     "Sep","Oct","Nov","Dec"};
Xchar *dayname[8] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA", "MF"};
X
Xextern char *strcpy(), *strcat();
X
X/*
X * sets "today" and current time
X */
Xvoid
Xget_today()
X{
X	struct tm *tm;
X	struct timeval tv;
X	char timstr[16];
X
X	gettimeofday(&tv, 0);
X	tm = localtime(&tv.tv_sec);
X
X	today = *tm;
X
X#ifndef CALENCHECK
X	if (day_first)
X		sprintf(clockstr, "%3.3s %d %s %d, ", daynames[today.tm_wday],
X		    today.tm_mday, smonthnames[today.tm_mon], today.tm_year+1900);
X	else
X		sprintf(clockstr, "%3.3s %s %d %d, ", daynames[today.tm_wday],
X		    smonthnames[today.tm_mon], today.tm_mday, today.tm_year+1900);
X	if (update_interval >= 60)
X		sprintf(timstr, "%02d:%02d", today.tm_hour, today.tm_min);
X	else
X		sprintf(timstr, "%02d:%02d:%02d", today.tm_hour, today.tm_min, today.tm_sec);
X	if (!hour24) {
X		/* display am/pm for 12-hour time */
X		if (today.tm_hour > 12) {
X			strcat(timstr, "pm");
X			timstr[0] = ((today.tm_hour - 12) / 10) + '0';
X			timstr[1] = ((today.tm_hour - 12) % 10) + '0';
X		} else if (today.tm_hour == 12) {
X			strcat(timstr, "pm");
X		} else {
X			strcat(timstr, "am");
X		}
X		if (timstr[0] == '0')
X			timstr[0] = ' ';
X	}
X	strcat(clockstr, timstr);
X#endif  /* CALENCHECK */
X}
X
X/*
X *	Reset some values in current tm structure. Year, month and
X *	day-of-month are valid but day and/or month may be < 0 or
X *	greater than the maximum value, in which case they are adjusted
X *	accordingly. Day-of-year and day-of-week are then recalculated.
X */
Xvoid
Xfix_current_day()
X{
X	int month, totdays = 0;
X	struct tm from, to;
X
X	if (current.tm_mon < JAN) {
X		current.tm_mon = DEC;
X		current.tm_year--;
X	} else if (current.tm_mon > DEC) {
X		current.tm_mon = JAN;
X		current.tm_year++;
X	}
X	if (current.tm_mday < 1) {
X		current.tm_mon--;
X		if (current.tm_mon < JAN) {
X			current.tm_mon = DEC;
X			current.tm_year--;
X		}
X		current.tm_mday += monthlength(current.tm_mon);
X	} else if (current.tm_mday > monthlength(current.tm_mon)) {
X		current.tm_mday -= monthlength(current.tm_mon);
X		current.tm_mon++;
X		if (current.tm_mon > DEC) {
X			current.tm_mon = JAN;
X			current.tm_year++;
X		}
X	}
X	current.tm_yday = day_of_year((double)current.tm_mday, current.tm_mon+1, current.tm_year+1900) - 1;
X	current.tm_wday = get_day_of_week((double)current.tm_mday, current.tm_mon+1, current.tm_year+1900);
X}
X
X/*
X * Compares two sets of year/month/day.  Returns -1 if the first is earlier than
X * the second, +1 if later, 0 if they are the same.
X */
Xymd_compare(day0, day1)
Xstruct tm day0, day1;
X{
X        if (day0.tm_year > day1.tm_year) return(1);
X        if (day0.tm_year < day1.tm_year) return(-1);
X        if (day0.tm_mon > day1.tm_mon) return(1);
X        if (day0.tm_mon < day1.tm_mon) return(-1);
X        if (day0.tm_mday > day1.tm_mday) return(1);
X        if (day0.tm_mday < day1.tm_mday) return(-1);
X        return(0);
X}
X
X/*
X * Compares two sets of year/month/day.  Returns -1 if the first is earlier than
X * the second, +1 if later, 0 if they are the same.  Similar to
X * ymd_compare() only compares given date to date of an appt entry.
X */
Xymd2_compare(day0, aday)
Xstruct tm *day0;
Xstruct appt_entry *aday;
X{
X        if (day0->tm_year > aday->year) return(1);
X        if (day0->tm_year < aday->year) return(-1);
X        if (day0->tm_mon > aday->month) return(1);
X        if (day0->tm_mon < aday->month) return(-1);
X        if (day0->tm_mday > aday->day) return(1);
X        if (day0->tm_mday < aday->day) return(-1);
X        return(0);
X}
X
Xint
Xmonthlength(month)
Xint	month;
X{
X	static int	monthlengths[] = {31,28,31,30,31,30,31,31,30,31,30,31};
X
X	if (month == FEB && (length_of_year(current.tm_year + 1900) == 366))
X		return(29);
X	else
X		return(monthlengths[month]);
X}
X
X/*
X *
X * Append data from active timeslots to end of "tmp.appointments"
X * file, then copy "tmp.appointments" to "appointments".  Note that
X * when we opened the current day we filtered "appointments":
X * all items that applied to the current day were displayed and
X * stored in slots; all others were copied to "tmp.appointments".
X * So by now "tmp.appointments" contains no entries for the
X * current day.
X * As an optimization, if nothing changed in the day then the
X * original appointments file is left unchanged.
X *
X */
X
Xclose_day()
X{
X        int i, j;
X        FILE *f;
X	struct stat sbuf;
X	struct appt_entry *aptr, *optr;
X
X	if (read_only || !new_entry) {
X		new_entry = 0;
X		day_is_open = FALSE;
X		return(0);
X	}
X
X#ifndef CALENCHECK
X	f = fopen(tmpapts_pathname, "a+");
X	if (f == NULL) {
X		err_rpt("can't open temp file for appending", NON_FATAL);
X		day_is_open = FALSE;
X		return(1);
X	}
X	
X	for (i=0; i<n_slots; i++) {
X                if (slots[i].first != NULL) {
X			aptr = slots[i].first;
X			if (put_aentry(f, aptr))
X				/* write error */
X				break;
X			optr = aptr;
X			while (aptr = aptr->next) {
X				free(optr);
X				if (put_aentry(f, aptr))
X					/* write error */
X					break;
X				optr = aptr;
X			}
X			free(optr);
X		}
X        }
X	if (ferror(f))
X		err_rpt("write on temp file failed", FATAL);
X        fclose(f);
X	new_entry = 0;
X	day_is_open = FALSE;
X	/* don't rename zero length files */
X	stat(tmpapts_pathname, &sbuf);
X	if (sbuf.st_size == (off_t) 0)
X		return(1);
X	xrename(tmpapts_pathname, apts_pathname);
X#endif  /* CALENCHECK */
X	return(0);
X}
X
X/*
X * get entry from appointments file
X */
Xget_aentry(apts_file, appt, noInclude, noUmkNotes, target)
XFILE *apts_file;
Xstruct appt_entry *appt;
Xint noInclude;
Xint noUmkNotes;
Xint target;
X{
X	char *ptr, *str;
X	char *fgets(), *index();
X	char *incl_ptr, incl_buf[128], wday[3];
X	int i, lib, parse_options, nodata = 1;
X	int n, nflag, lrange, hrange;
X	struct stat sbuf;
X	static FILE *include[MAX_INCLUDE_NESTING];
X
X	appt->flags = appt->repeat = appt->lookahead = 0;
X	appt->sindex = 0;
X	appt->runlength = 0;
X	appt->warn = 10;
X	appt->next = NULL;
X	/* If noInclude is set then don't follow include files, i.e.
X	 * treat #include directives as comments. This is useful for
X	 * copying the appts file.
X	 */
X	while (nodata) {
X		if (include_level) {
X			if (fgets(inbuf, 512, include[include_level-1]) == NULL) {
X				/* end of include file - get next entry
X				 * from previous level of nesting
X				 */
X			    unwind:
X				fclose(include[include_level-1]);
X				include_level--;
X			} else {
X				/* don't modify stuff from include files */
X				appt->flags |= READONLY;
X				nodata = 0;	/* still data in file */
X			}
X		} else {
X			if (fgets(inbuf, 512, apts_file) == NULL)
X				return(EOF);
X			else
X				nodata = 0;	/* still data in file */
X		}
X	}
X	ptr = inbuf;
X	if (noInclude && *ptr == '#') {
X		appt->flags |= A_COMMENT;
X		return(0);
X	}
X	if (*ptr == '#') {
X		if (!include_level && (!strcmp(inbuf, OHEADER) ||
X		    !strncmp(inbuf, HEADER, 18))) {
X			/* first line in base file read */
X			if (include_old && (First.tm_year <= today.tm_year)) {
X				/* read in old include file (if it exists) */
X				/* prepend directory info */
X				sprintf(incl_buf, "%s.%02d",
X					apts_pathname, First.tm_year);
X				if (!stat(incl_buf, &sbuf)) {
X					if ((include[include_level] = fopen(incl_buf, "r")) == NULL) {
X						strcpy(errbuf, "can't open include file <");
X						strcat(errbuf, incl_buf);
X						strcat(errbuf, "> (ignored)");
X						err_rpt(errbuf, NON_FATAL);
X					} else
X						include_level++;
X				}
X			}
X			if (!strcmp(inbuf, OHEADER))
X				/* substitute new header format */
X				strcpy(inbuf, HEADER);
X		} else if (!strncmp(inbuf, HEADER, 18)) {
X			/* found a ver 2.2 header - get statistics */
X			n = sscanf(inbuf, "%*[^-]- nflag=%d range=%d,%d",
X				&nflag, &lrange, &hrange);
X			if (n == 3 && include_level) {
X				/* proper match found */
X				if (noUmkNotes && nflag)
X					goto unwind;
X				if (target && (target < lrange || target > hrange))
X					goto unwind;
X			}
X		} else if (!strncmp(inbuf, "#include", 8)) {
X			/* include file */
X			if (include_level > MAX_INCLUDE_NESTING) {
X				err_rpt("include files nested too deep (ignored)", NON_FATAL);
X				appt->flags |= A_COMMENT;
X				return(0);
X			}
X			incl_ptr = strbuf;
X			if ((ptr = index(inbuf, '"')) == NULL)
X
X				if ((ptr = index(inbuf, '<')) == NULL) {
X					err_rpt("missing '\"' or '<' in include file spec", NON_FATAL);
X					appt->flags |= A_COMMENT;
X					return(0);
X				} else {
X					lib = 1;
X				}
X			else
X				lib = 0;
X			ptr++;
X			while (*ptr && *ptr != '"' && *ptr != '>')
X				*incl_ptr++ = *ptr++;
X			if (! *ptr) {
X				err_rpt("missing '\"' or '>' in include file spec", NON_FATAL);
X				appt->flags |= A_COMMENT;
X				return(0);
X			}
X			*incl_ptr = '\0';
X			if (strbuf[0] == '/')
X				/* full pathname provided */
X				strcpy(incl_buf, strbuf);
X			else
X				/* prepend directory info */
X				if (lib)
X					sprintf(incl_buf, "%s/%s", lib_dir, strbuf);
X				else
X					sprintf(incl_buf, "%s/%s", apts_dir, strbuf);
X			if ((include[include_level] = fopen(incl_buf, "r")) == NULL) {
X				strcpy(errbuf, "can't open include file <");
X				strcat(errbuf, incl_buf);
X				strcat(errbuf, "> (ignored)");
X				err_rpt(errbuf, NON_FATAL);
X			} else 
X				include_level++;
X		}
X		appt->flags |= A_COMMENT;
X		return(0);
X	}
X	while (isspace(*ptr))
X		++ptr;
X	if (!*ptr) {
X		/* empty line */
X		appt->flags |= A_COMMENT;
X		return(0);
X	}
X	if (*ptr == '*') {
X		appt->flags |= ALL_YEARS;
X		appt->year = START_YEAR;
X		++ptr;	/* point to second '*' */
X		++ptr;	/* point to space */
X	} else {
X		appt->year = 0;
X		while (isdigit(*ptr)) {
X			appt->year *= 10;
X			appt->year += *ptr++ - '0';
X		}
X		/* sanity check */
X		if (appt->year < 0) {
X			sprintf(errbuf, "illegal year value [%d] (ignored)", appt->year);
X			err_rpt(errbuf, NON_FATAL);
X			return(1);
X		}
X	}
X	while (isspace(*ptr))
X		++ptr;
X	if (*ptr == '*') {
X		appt->flags |= ALL_MONTHS;
X		appt->month = 0;
X		++ptr;
X	} else {
X		appt->month = (*ptr - '0') * 10;
X		appt->month += *++ptr - '0';
X		if (one_based) (appt->month)--;
X		/* sanity check */
X		if (appt->month < JAN || appt->month > DEC) {
X			sprintf(errbuf, "illegal month value [%d] (ignored)", appt->month);
X			err_rpt(errbuf, NON_FATAL);
X			return(1);
X		}
X	}
X	++ptr;
X	while (isspace(*ptr))
X		++ptr;
X	if (*ptr == '*') {
X		appt->flags |= ALL_DAYS;
X		appt->day = 1;
X		appt->repeat = 1;
X		++ptr;
X	} else if (isdigit(*ptr)) {
X		appt->day = (*ptr - '0') * 10;
X		appt->day += *++ptr - '0';
X		if (!one_based) (appt->day)++;
X		/* sanity check */
X		if (appt->day < 1 || appt->day > 31) {
X			sprintf(errbuf, "illegal day value [%d] (ignored)", appt->day);
X			err_rpt(errbuf, NON_FATAL);
X			return(1);
X		}
X	} else {
X		/* check for day names */
X		wday[0] = islower(*ptr) ? toupper(*ptr) : *ptr;
X		++ptr;
X		wday[1] = islower(*ptr) ? toupper(*ptr) : *ptr;
X		wday[2] = '\0';
X		i = 0;
X		if (!strcmp(wday, dayname[i++]))
X			appt->flags |= EVERY_SUN;
X		else if (!strcmp(wday, dayname[i++]))
X			appt->flags |= EVERY_MON;
X		else if (!strcmp(wday, dayname[i++]))
X			appt->flags |= EVERY_TUE;
X		else if (!strcmp(wday, dayname[i++]))
X			appt->flags |= EVERY_WED;
X		else if (!strcmp(wday, dayname[i++]))
X			appt->flags |= EVERY_THU;
X		else if (!strcmp(wday, dayname[i++]))
X			appt->flags |= EVERY_FRI;
X		else if (!strcmp(wday, dayname[i++]))
X			appt->flags |= EVERY_SAT;
X		else if (!strcmp(wday, dayname[i]))
X			appt->flags |= EVERY_MON_FRI;
X		else {
X			/* sanity check */
X			sprintf(errbuf, "illegal day name [%s] (ignored)", wday);
X			err_rpt(errbuf, NON_FATAL);
X			return(1);
X		}
X		appt->day = 1;
X		if (appt->flags & EVERY_MON_FRI) {
X			appt->repeat = 1;
X		} else {
X			appt->flags |= REPEAT;
X			appt->repeat = ALL_WEEKS;	/* default to every week */
X		}
X	}
X	++ptr;
X	while (isspace(*ptr))
X		++ptr;
X	appt->hour = (*ptr - '0') * 10;
X	appt->hour += *++ptr - '0';
X	/* sanity check */
X	if (appt->hour < 0 || (appt->hour > 23 && appt->hour != 99)) {
X		sprintf(errbuf, "illegal hour value [%d] (ignored)", appt->hour);
X		err_rpt(errbuf, NON_FATAL);
X		return(1);
X	}
X	if ((version2 && appt->hour == 99) || (!version2 && appt->hour == 0))
X		appt->flags |= A_NOTE;
X	++ptr;
X	while (isspace(*ptr))
X		++ptr;
X	appt->minute = (*ptr - '0') * 10;
X	appt->minute += *++ptr - '0';
X	/* sanity check */
X	if (appt->minute < 0 || (appt->minute > 59 && appt->minute != 99)) {
X		/* minutes currently can only be 00 or 30
X		 * unless it's a note.
X		 */
X		sprintf(errbuf, "illegal minute value [%d] (ignored)", appt->minute);
X		err_rpt(errbuf, NON_FATAL);
X		return(1);
X	}
X	if ((appt->flags & A_NOTE) && version2 && appt->minute == 99)
X		appt->flags |= MARKED;  /* don't show in mon/yr display */
X	++ptr;
X	while (isspace(*ptr))
X		++ptr;
X	appt->arrows = (*ptr - '0') * 10;
X	appt->arrows += *++ptr - '0';
X	/* sanity check */
X	if (appt->arrows < 0 || appt->arrows > 48) {
X		sprintf(errbuf, "illegal arrow value [%d] (ignored)", appt->arrows);
X		err_rpt(errbuf, NON_FATAL);
X		return(1);
X	}
X	++ptr;
X	while (isspace(*ptr))
X		++ptr;
X	/* lookahead and repeat entries are free format, i.e. they */
X	/* can occur in any order */
X	parse_options = TRUE;
X	while (parse_options) {
X		switch (*ptr) {
X			case '\\':
X				/* start of string text */
X				parse_options = FALSE;
X				++ptr;
X				break;
X
X			case '%':
X				/* advance warning time (minutes) */
X				appt->warn = 0;
X				while (isdigit(*++ptr))
X					appt->warn = appt->warn * 10 + (int)(*ptr - '0');
X				if (appt->warn < 0) {
X					err_rpt("illegal advance warning (ignored)", NON_FATAL);
X					appt->warn = 10;
X				}
X				break;
X
X			case '[':
X				/* repeating appointment */
X				appt->flags |= REPEAT;
X				if (appt->flags & EVERY_SOMEDAY) {
X					if ((appt->repeat = do_wk_repeat(&ptr)) < 0)
X						return(1);
X				} else {
X					if ((appt->repeat = do_repeat(&ptr)) < 0)
X						return(1);
X				}
X				break;
X			
X			case '<':
X				/* remind us ahead of time */
X				appt->flags |= LOOKAHEAD;
X				if ((appt->lookahead = do_lookahead(&ptr)) < 0)
X					return(1);
X				break;
X			
X			case '+':
X				/* this appointment lasts for n days */
X				appt->flags |= RUN;
X				while (isdigit(*++ptr))
X					appt->runlength = appt->runlength * 10 + (int)(*ptr - '0');
X				if (appt->runlength < 0)
X					return(1);
X				if (!(appt->flags & REPEAT)) {
X					/* default to run of days */
X					appt->flags |= REPEAT;
X					appt->repeat = 1;
X				}
X				break;
X
X			case '#':
X				/* deleted appointment */
X				appt->flags |= DELETED;
X				++ptr;
X				break;
X			
X			default:
X				parse_options = FALSE;
X				break;
X		}
X		while (isspace(*ptr))
X			++ptr;
X	}
X	str = strbuf;
X	while (*ptr && *ptr != '\n')
X		*str++ = *ptr++;
X	*str = '\0';
X	strcpy(appt->str, strbuf);
X	if (appt->flags & DELETED)
X		/* ignore some flags */
X		appt->flags &= ~(RUN | REPEAT);
X
X	return(0);
X}
X
X/* parse normal repeated entry field */
Xdo_repeat(ptr)
Xchar **ptr;
X{
X	int repeat = 0;
X
X	while (isdigit(*++*ptr))
X		repeat = repeat * 10 + (int)(**ptr - '0');
X	if (**ptr != ']') {
X		err_rpt("bad entry (ignored)", NON_FATAL);
X		return(-1);
X	}
X	/* sanity check */
X	if (repeat < 0) {
X		err_rpt("illegal repeat interval (ignored)", NON_FATAL);
X		return(-1);
X	}
X	++*ptr;
X	return(repeat);
X}
X
X/* parse weekly repeated entry field */
Xdo_wk_repeat(ptr)
Xchar **ptr;
X{
X	int repeat = 0;
X
X	while (*++*ptr != ']') {
X		if (**ptr == ',')
X			continue;	/* get next week */
X		if (isdigit(**ptr)) {
X			repeat |= 0x1<<(**ptr - '1');
X		} else if (**ptr == 'L' || **ptr == 'l') {
X			/* last week in month */
X			repeat |= LAST_WEEK;
X		} else {
X			/* format error */
X			err_rpt("illegal repeat specification (ignored)", NON_FATAL);
X			return(-1);
X		}
X	}
X	/* sanity check */
X	if ((unsigned int)repeat > WEEK_LIMIT) {
X		err_rpt("illegal weekly repeat (ignored)", NON_FATAL);
X		return(-1);
X	}
X	++*ptr;
X	return(repeat);
X}
X
X/* parse lookahead entry field */
Xdo_lookahead(ptr)
Xchar **ptr;
X{
X	int lookahead = 0;
X
X	while (isdigit(*++*ptr))
X		lookahead = lookahead * 10 + (int)(**ptr - '0');
X	if (**ptr != '>') {
X		err_rpt("bad entry (ignored)", NON_FATAL);
X		return(-1);
X	}
X	/* sanity check */
X	if (lookahead < 0) {
X		err_rpt("illegal lookahead interval (ignored)", NON_FATAL);
X		return(-1);
X	}
X	++*ptr;
X	return(lookahead);
X}
X
X#ifndef CALENCHECK
X/*
X * put entry into appointments file
X */
Xput_aentry(apts_file, appt)
XFILE *apts_file;
Xstruct appt_entry *appt;
X{
X	char *to_str();
X
X	if (read_only)
X		return(0);
X
X	if (appt->flags & READONLY)
X		/* don't copy include file entries */
X		/* (the include directive is copied as a comment) */
X		return(0);
X	if (appt->flags & A_COMMENT) {
X		fputs(inbuf, apts_file);
X		return(ferror(apts_file));
X	}
X	if (appt->flags & ALL_YEARS)
X		fputs("** ", apts_file);
X	else if (appt->year > 99)
X		fprintf(apts_file, "%03d ", appt->year);
X	else
X		fprintf(apts_file, "%02d ", appt->year);
X	if (appt->flags & ALL_MONTHS)
X		fputs("** ", apts_file);
X	else
X		fprintf(apts_file, "%02d ", one_based ? appt->month+1 : appt->month);
X	if (appt->flags & ALL_DAYS)
X		fputs("** ", apts_file);
X	else if (appt->flags & EVERY_SOMEDAY) {
X		switch (appt->flags & EVERY_SOMEDAY) {
X			case EVERY_SUN:
X				fputs("Su ", apts_file);
X				break;
X			case EVERY_MON:
X				fputs("Mo ", apts_file);
X				break;
X			case EVERY_TUE:
X				fputs("Tu ", apts_file);
X				break;
X			case EVERY_WED:
X				fputs("We ", apts_file);
X				break;
X			case EVERY_THU:
X				fputs("Th ", apts_file);
X				break;
X			case EVERY_FRI:
X				fputs("Fr ", apts_file);
X				break;
X			case EVERY_SAT:
X				fputs("Sa ", apts_file);
X				break;
X		}
X	} else if (appt->flags & EVERY_MON_FRI) {
X		fputs("MF ", apts_file);
X	} else
X		fprintf(apts_file, "%02d ", one_based ? appt->day : appt->day-1);
X	if (appt->flags & A_NOTE) {
X		appt->hour = 99;
X		appt->minute = 0;	/* assume unmarked note */
X	}
X	if ((appt->flags & MARKED_NOTE) == MARKED_NOTE)
X		appt->minute = 99;
X	if (!(appt->flags & (ALL_DAYS|DELETED|EVERY_MON_FRI)) && appt->flags & REPEAT) {
X		if (appt->flags & EVERY_SOMEDAY)
X			fprintf(apts_file, "%02d %02d %02d %s ", appt->hour, appt->minute, appt->arrows, to_str(appt->repeat));
X		else
X			fprintf(apts_file, "%02d %02d %02d [%d] ", appt->hour, appt->minute, appt->arrows, appt->repeat);
X	} else
X		fprintf(apts_file, "%02d %02d %02d ", appt->hour, appt->minute, appt->arrows);
X
X	if (appt->flags & LOOKAHEAD)
X		fprintf(apts_file, "<%d> ", appt->lookahead);
X	if (appt->flags & RUN)
X		fprintf(apts_file, "+%d ", appt->runlength);
X	if (appt->warn != 10)
X		fprintf(apts_file, "%%%d ", appt->warn);
X	if (appt->flags & DELETED)
X		fputs("# ", apts_file);
X	if (isalnum(*(appt->str)))
X		fprintf(apts_file, "%s\n", appt->str);
X	else
X		fprintf(apts_file, "\\%s\n", appt->str);
X	
X	/* check for failure (e.g. file system full) */
X	return(ferror(apts_file));
X}
X
Xchar rptstr[10];
X
X/* convert repeat bit map to printable string */
Xchar *
Xto_str(repeat)
Xint repeat;
X{
X	int i, j = 0;
X
X	if (repeat == ALL_WEEKS)
X		/* if it's every week, then don't write [] spec */
X		rptstr[0] = '\0';
X	else {
X		rptstr[j++] = '[';
X		for (i=0; i<5; i++) {
X			if (repeat & (0x1<<i)) {
X				rptstr[j++] = i+1 + '0';
X				rptstr[j++] = ',';
X			}
X		}
X		if (repeat & LAST_WEEK) {
X			rptstr[j++] = 'L';
X			rptstr[j++] = ',';
X		}
X		rptstr[j] = '\0';
X		rptstr[--j] = ']';
X	}
X	return (rptstr);
X}
X
X/*
X * Convert from version 1 appts files to version 2 file format.
X */
Xver1to2()
X{
X	FILE *oappts, *nappts, *fp;
X	struct appt_entry appt;
X	int err_flag, save_base;
X	char save_file[128];
X	struct stat stbuf;
X
X	/*
X	 * The main difference is that the ver 2 files are one-based, i.e
X	 * days and months start with 1, rather than 0. Another difference
X	 * is that a hour entry of 99 is used to flag a memo entry, rather
X	 * than 00. This allows for 24-hour appointments.
X	 * Version 2 appts files are marked with a special header line
X	 * defined by the HEADER string (in ct.h).  Version 2 files
X	 * also support a "lookahead" reminder service to remind one
X	 * in advance of a future appointment.
X	 * If "save_old" is set, then any appointments for years prior
X	 * to this one are saved in a special file of the form
X	 * ".appointments.YY", where YY is the year.
X	 */
X
X	if (read_only != 0) {
X		err_rpt("appts file is read-only, no conversion done", NON_FATAL);
X		return;
X	}
X
X	 /* open files, etc */
X	if ((oappts = fopen(apts_pathname, "r")) == NULL) {
X		err_rpt("can't open appts file for reading", FATAL);
X		/* NOT REACHED */
X	 }
X	if ((nappts = fopen(tmpapts_pathname, "w")) == NULL) {
X		err_rpt("can't open temp file for writing", NON_FATAL);
X		return;
X	 }
X	 /* write new header line */
X	 fputs(HEADER, nappts);
X
X	 /* copy existing entries to the new file */
X	 save_base = one_based;
X	 while ((err_flag = get_aentry(oappts, &appt, TRUE, 0, 0)) != EOF) {
X		if (err_flag)
X			continue;	/* ignore badly formatted input */
X		if (appt.hour == 0)
X			appt.flags |= A_NOTE;
X		one_based = 1;		/* force new format output */
X		if (save_old && !(appt.flags & ALL_YEARS) && (appt.year < today.tm_year)
X		   && !((appt.flags & REPEAT) && !(appt.flags & EVERY_SOMEDAY))
X		   && !(appt.flags & A_COMMENT)) {
X			/* prepend directory info */
X			sprintf(save_file, "%s.%02d",
X				apts_pathname, appt.year);
X			if (stat(save_file, &stbuf) && errno == ENOENT) {
X				/* new file*/
X				if ((fp = fopen(save_file, "w")) == NULL)
X					err_rpt("can't open save file, bailing out", FATAL);
X				fputs(HEADER, fp);
X				fclose(fp);
X			}
X			if ((fp = fopen(save_file, "a+")) == NULL)
X				err_rpt("can't open save file, bailing out", FATAL);
X			else {
X				if (put_aentry(fp, &appt))
X					err_rpt("write to save appt file failed, bailing out", FATAL);
X				fclose(fp);
X			}
X		} else {
X			if (appt.flags & A_COMMENT)
X				fputs(inbuf, nappts);
X			else
X				if (put_aentry(nappts, &appt))
X					err_rpt("write to new appt file failed, bailing out", FATAL);
X		}
X		one_based = save_base;	/* (maybe) force old format input */
X	}
X	fclose(oappts);
X	fclose(nappts);
X	xrename(tmpapts_pathname, apts_pathname);
X	one_based = 1;
X	version2 = 1;
X}
X
X/*
X * parse the date on the given string and reset the "current"
X * date to reflect that date. The date may take the form of a
X * day name (e.g. Tu, Tue, Tuesday) or a date in m/d/y format
X * where the month and/or year may be missing (e.g. 27 = 27th
X * of this month, 8/27 = August 27 of this year, 8/27/89 =
X * August 27 of 1989. If 'cmdline' is true, then the string
X * came from the command line '-d' option.
X * If the first character of the date is + or - scan the number and
X * use it as an offset in days from the current date.  Thus -1 becomes
X * yesterday and +1 becomes tomorrow. pbm.
X */
Xint
Xparse_date(str, cmdline)
Xchar *str;
Xint cmdline;
X{
X	char c[4];
X	int i, dow = -1, m = -1, d = -1, y = -1;
X
X	if (isdigit(*str)) {
X		/* must be a m/d/y date */
X		/* assume it's a month first */
X		m = *str++ - '0';
X		if (isdigit(*str))
X			m = m*10 + *str++ - '0';
X		if (!*str) {
X			/* no more chars => day only */
X			d = m;
X			m = -1;
X		} else if (*str++ != '/') {
X			if (cmdline)
X				err_rpt("badly formed date for -d option (ignored)", NON_FATAL);
X			else
X				err_rpt("badly formed date - please reenter", NON_FATAL);
X			return(1);
X		} else {
X			d = *str++ - '0';
X			if (isdigit(*str))
X				d = d*10 + *str++ - '0';
X			if (*str++ == '/') {
X				/* year also specified */
X				y = *str++ - '0';
X				if (isdigit(*str)) {
X					y = y*10 + *str++ - '0';
X					if (*str && isdigit(*str))
X						y = y*10 + *str++ - '0';
X					if (*str && isdigit(*str))
X						y = y*10 + *str++ - '0';
X				}
X			}
X		}
X		if (y > 0) {
X			if (y > 1900)
X				y -= 1900;
X			current.tm_year = y;
X		}
X		if (day_first) {
X			if (m > 0) {
X				current.tm_mon = d - 1;
X				current.tm_mday = m;
X			} else if (d > 0)
X				current.tm_mday = d;
X		} else {
X			if (m > 0) {
X				current.tm_mon = m - 1;
X				current.tm_mday = d;
X			} else if (d > 0)
X				current.tm_mday = d;
X		}
X		fix_current_day();
X	} else if (*str == '-' || *str == '+') {
X		/*
X		 * If the argument begins with a + or - assume that it is an
X		 * offset in days from the current date. Use current date if the
X		 * number doesn't scan after the - or +. pbm
X		 */
X		if (sscanf(str, "%d", &i) == 1) {
X			current.tm_mday += i;
X			fix_current_day();
X		}
X	} else {
X		/* day of week */
X		/* check for day names */
X		c[0] = islower(*str) ? toupper(*str) : *str;
X		++str;
X		c[1] = islower(*str) ? toupper(*str) : *str;
X		c[2] = '\0';
X		for (i=0; i<7; i++) {
X			if (!strcmp(c, dayname[i])) {
X				dow = i;
X				break;
X			}
X		}
X		if (dow >= 0) {
X			/* match found */
X			current.tm_mday += dow - current.tm_wday;
X			fix_current_day();
X		} else if (!strncmp(c, "TOM", 3)) {
X			/* tommorrow */
X			current.tm_mday++;
X			fix_current_day();
X		} else if (!strncmp(c, "YES", 3)) {
X			/* yesterday */
X			current.tm_mday--;
X			fix_current_day();
X		} else {
X			if (cmdline)
X				err_rpt("badly formed date for -d option (ignored)", NON_FATAL);
X			else
X				err_rpt("badly formed date - please reenter", NON_FATAL);
X			return(1);
X		}
X	}
X	return(0);
X}
X#endif  /* CALENCHECK */
X
X/* set error logging flag */
Xerr2console(state)
Xint state;
X{
X	/*
X	 * if TRUE, forces error messages to the console, even
X	 * if the base frame is running
X	 */
X	log_to_console = state;
X}
X
X/*
X * Error reporting. Try first to put message in a popup frame, then
X * the console, then stderr as a last resort.
X */
Xerr_rpt(errstr, fatal_flag)
Xchar *errstr;
Xint fatal_flag;
X{
X	FILE	*f;
X	int	closed;
X	char *getenv();
X
X#ifndef NOTOOL
X	closed = (int) window_get(frame, FRAME_CLOSED);
X	if (frame && !log_to_console && !closed) {
X		/* base frame exists */
X		create_prompt_frame(errstr, FALSE);
X		(void) window_loop(prompt_frame);
X		window_set(prompt_frame, WIN_SHOW, FALSE, 0);
X	} else if ((f=fopen("/dev/console", "w")) != NULL) {
X#else
X	if (getenv("WINDOW_PARENT") != NULL && (f=fopen("/dev/console", "w")) != NULL) {
X#endif
X		fprintf(f, "%s: %s\n", progname, errstr);
X		fclose(f);
X	} else
X		fprintf(stderr, "%s: %s\n", progname, errstr);
X	if (fatal_flag)
X		exit(1);
X}
X
X#ifndef CALENCHECK
X/* Clean-up */
Xcleanup()
X{
X	if (day_is_open)
X		close_day();
X
X	/* create outdated include files (if necessary) */
X	if (save_old || expire_days)
X		expire(expire_days);
X			
X	/* delete tmp file */
X	if (access(tmpapts_pathname, R_OK) == 0 && unlink(tmpapts_pathname) < 0)
X		perror(tmpapts_pathname);
X}
X
Xchar sysbuf[512];
X
X/* Rename files, copying if necessary */
Xxrename(from, to)
Xchar *from, *to;
X{
X	if (rename(from, to) == -1) {
X		/* rename sys call fialed, try doing a copy */
X		sprintf(sysbuf, "cp %s %s", from, to);
X		if (system(sysbuf) != 0)
X			err_rpt("couldn't rename/copy tmp file", NON_FATAL);
X	}
X}
X
X/*
X *  Conventional and ISO standard week numbers (week starts with monday)
X *  Assume if moday_first is set TRUE then ISO format is desired.
X */
X
Xweek_number()
X{
X	int week_n, week_d, W, r, day, year, leap;
X
X	/*  First day of this week */
X	if (monday_first)
X		week_d = (current.tm_wday?(current.tm_wday-1):6);
X	else
X		week_d = current.tm_wday;
X	current.tm_mday -= week_d;
X	fix_current_day();
X	day = current.tm_yday + 1;
X	week_n = day / 7 + 1;       /*  "Raw" week number  */ 
X	r = day % 7 - 1;           /*  No of days in the first week this year  */
X
X	if (!monday_first) {
X		if (week_n == 53)
X			week_n = 1;
X		else if (r > 0 && day > r)
X			if (++week_n == 53 && (day + 6) > length_of_year(current.tm_year+1900))
X				week_n = 1;
X	} else {
X		if (r >= 4) week_n++;       /*  First week has more than three days  */
X		if (week_n == 53) {         /*  Week number of last week of year  */
X			year = current.tm_year + 1900;
X			leap = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0);   
X			day += 7 - ( leap ? 366 : 365 );
X			W = day / 7 + 1;
X			r = day % 7 - 1;
X			if (r >= 4) W++;
X			if (W == 2) week_n = 1;
X		    }
X	}
X	current.tm_mday += week_d;
X	fix_current_day();
X	return week_n;
X}
X#endif  /* CALENCHECK */
END_OF_FILE
if test 29701 -ne `wc -c <'utils.c'`; then
    echo shar: \"'utils.c'\" unpacked with wrong size!
fi
# end of 'utils.c'
fi
echo shar: End of archive 16 \(of 23\).
cp /dev/null ark16isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 23 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.