[comp.sources.sun] v01i013: Calendar/planning tool: Part 04/09

mcgrew@dartagnan.rutgers.edu (Charles Mcgrew) (05/28/89)

Submitted-by: Bill Randle <billr@saab.cna.tek.com>
Posting-number: Volume 1, Issue 13
Archive-name: calentool/part04

#! /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:
#	devent.c
#	dpaint.c
#	holidays.c
# This archive created: Sat May 27 13:12:02 1989
export PATH; PATH=/bin:$PATH
echo shar: extracting "'devent.c'" '(27402 characters)'
if test -f 'devent.c'
then
	echo shar: will not over-write existing file "'devent.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'devent.c'
	X/*
	X * $Header: devent.c,v 2.1 89/05/09 14:18:59 billr Exp $
	X */
	X/*
	X * devent.c
	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 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 *      Day event routines for main subwindow.		*
	X *							*
	X ********************************************************/
	X
	X
	X#include <stdio.h>
	X#include <suntool/sunview.h>
	X#include <suntool/canvas.h>
	X#include <suntool/panel.h>
	X#include <suntool/menu.h>
	X#include <sys/time.h>
	X#include <fcntl.h>
	X#include "ct.h"
	X#include "event.h"
	X
	Xextern Menu day_sel_menu;
	Xextern Frame attr_frame;
	Xextern Panel_item everyx_pi, repeat_pi, remind_pi;
	Xextern Panel_item whichwk_pi, marked_pi;
	Xextern Panel_item del_choice_pi;
	Xextern Frame del_frame;
	Xextern Panel del_panel;
	Xextern Pixrect tri_right_pr, tri_up_pr;
	Xextern Pixrect *leftarrow, *rightarrow, *morebutton;
	Xextern int n_tslots;
	Xint attr_bi;
	Xstruct appt_entry shelf_appt = {0};
	Xint old_slot = -1;	/* for text cursor location */
	X
	Xday_inputevent(canvas, event)
	XCanvas canvas;
	XEvent *event;
	X{
	X	Menu_item an_item;
	X	int box_index, x, y, found_flag;
	X	int i, j, active_above, strl;
	X	struct appt_entry *aptr;
	X	static int start_arrow_box = -1, prev_box = 0;
	X	static int expecting = 0;
	X
	X        found_flag = 0;                	/* See if cursor is in a box. */
	X	/* translate coordinates back to pixwin space */
	X	event = canvas_window_event(canvas, event);
	X        x = event_x(event);
	X        y = event_y(event);
	X	/*fix_event(canvas, event);	/* check for LOC_RGNENTER */
	X	if (event_id(event) == LOC_RGNEXIT && old_slot >= 0) {
	X		/* erase text cursor */
	X		text_cursor(old_slot);
	X		old_slot = -1;
	X	}
	X
	X        for (box_index=0; box_index<N_SLOTS; box_index++) {
	X		/* is cursor inside a slot ? */
	X                if (x>=slots[box_index].slot_pos.left && x<=slots[box_index].slot_pos.right &&
	X                    y>=slots[box_index].slot_pos.top && y<=slots[box_index].slot_pos.bottom) {
	X                        found_flag = FOUND_SLOT;
	X                        break;
	X                }
	X		/* is cursor inside a "more" button ? */
	X                if (x>=slots[box_index].moreb_pos.left && x<=slots[box_index].moreb_pos.right &&
	X                    y>=slots[box_index].moreb_pos.top && y<=slots[box_index].moreb_pos.bottom) {
	X			if (slots[box_index].count > 1) {
	X				/* "more" button is active */
	X				found_flag = FOUND_MORE;
	X				break;
	X			}
	X		}
	X		/* is cursor inside a "leftarrow" button ? */
	X                if (x>=slots[box_index].larrow_pos.left && x<=slots[box_index].larrow_pos.right &&
	X                    y>=slots[box_index].larrow_pos.top && y<=slots[box_index].larrow_pos.bottom) {
	X			found_flag = FOUND_LARROW;
	X			break;
	X		}
	X		/* is cursor inside a "rightarrow" button ? */
	X                if (x>=slots[box_index].rarrow_pos.left && x<=slots[box_index].rarrow_pos.right &&
	X                    y>=slots[box_index].rarrow_pos.top && y<=slots[box_index].rarrow_pos.bottom) {
	X			found_flag = FOUND_RARROW;
	X			break;
	X		}
	X	}
	X	if (old_slot >= 0) {
	X		/* erase text cursor at old location */
	X		text_cursor(old_slot);
	X		old_slot = -1;
	X	}
	X
	X        if (!found_flag && !expecting)
	X                return(0);		/* Not in a box => ignore. */
	X
	X	if (event_id(event) == LOC_STILL || (event_is_button(event) && event_is_up(event))) {
	X		if (found_flag == FOUND_SLOT && box_index != old_slot)
	X			/* in a different slot than we were before */
	X			if (slots[box_index].active == ACTIVE)
	X				/* display cursor at new location */
	X				text_cursor(box_index);
	X	}
	X        if (found_flag == FOUND_SLOT && event_id(event) <= ASCII_LAST) {
	X		/* Process a kbd event. */
	X                if (slots[box_index].active != ACTIVE)
	X                        return(0);
	X		if (event_id(event) == CTRL_R) {
	X                        rewrite_string(box_index, JUSTIFY_LEFT);
	X                        return(0);
	X		}
	X		new_entry = 1;	/* flag for file updating */
	X		strl = strlen(slots[box_index].cur_appt->str);
	X                if (event_id(event) == CTRL_U) {
	X                        slots[box_index].cur_appt->str[0] = '\0';
	X                        rewrite_string(box_index, JUSTIFY_LEFT);
	X                } else if (event_id(event) == CTRL_W) {
	X                        while (strl > 0 && slots[box_index].cur_appt->str[strl-1] != ' ') {
	X                                slots[box_index].cur_appt->str[strl-1] = '\0';
	X				strl--;
	X                        }
	X			rewrite_string(box_index, JUSTIFY_RIGHT);
	X                } else if (event_id(event) == DEL || event_id(event) == BACKSPACE) {
	X			if (strl > 0) {
	X                                slots[box_index].cur_appt->str[strl-1] = '\0';
	X                                rewrite_string(box_index, JUSTIFY_RIGHT);
	X                        }
	X                } else if (event_id(event) >= (int)' ' && strl < MAX_STRLEN-2) {
	X                        slots[box_index].cur_appt->str[strl] = (char)event_id(event);
	X			slots[box_index].cur_appt->str[strl+1] = '\0';
	X                        rewrite_string(box_index, JUSTIFY_RIGHT);
	X                }
	X		/* display cursor at new location */
	X		text_cursor(box_index);
	X	} else if (event_id(event) == MS_LEFT && event_is_down(event)) {
	X		/* LB down event */
	X		switch (found_flag) {
	X			case FOUND_SLOT:
	X				break;
	X			case FOUND_MORE:
	X				/* reverse video "more" button */
	X				pw_rop(main_pixwin, slots[box_index].moreb_pos.left, slots[box_index].moreb_pos.top,
	X					morebutton->pr_width, morebutton->pr_height, PIX_NOT(PIX_DST),
	X					morebutton, 0, 0);
	X				expecting = box_index + (FOUND_MORE<<8);
	X				break;
	X			case FOUND_LARROW:
	X				do_left_arrow(canvas, box_index);
	X				break;
	X			case FOUND_RARROW:
	X				do_right_arrow(canvas, box_index);
	X				break;
	X		}
	X	} else if (event_id(event) == MS_LEFT && event_is_up(event)) {
	X		/* Process an LB up click. */
	X		i = expecting>>8;
	X		if (expecting && found_flag != i) {
	X			/* return button to normal video */
	X			if (i == FOUND_MORE) {
	X				/* "more" button */
	X				i = expecting & 0xff;
	X				pw_rop(main_pixwin, slots[i].moreb_pos.left, slots[i].moreb_pos.top,
	X					morebutton->pr_width, morebutton->pr_height, PIX_SRC,
	X					morebutton, 0, 0);
	X			}
	X		} else {
	X			switch (found_flag) {
	X				case FOUND_SLOT:
	X					make_box_active(box_index);
	X					new_entry = 1;
	X					break;
	X				case FOUND_MORE:
	X					next_appt(box_index, TRUE);
	X					/* normal video "more" button */
	X					pw_rop(main_pixwin, slots[box_index].moreb_pos.left, slots[box_index].moreb_pos.top,
	X						morebutton->pr_width, morebutton->pr_height, PIX_SRC,
	X						morebutton, 0, 0);
	X					break;
	X				case FOUND_LARROW:
	X					break;
	X				case FOUND_RARROW:
	X					break;
	X			}
	X		}
	X		expecting = 0;
	X        } else if (found_flag == FOUND_SLOT && event_id(event) == MS_MIDDLE) {
	X		/* Process a MB click. */
	X		if (box_index >= n_tslots)
	X			/* don't flow into notes section */
	X			box_index = n_tslots - 1;
	X		if (event_is_down(event)) {
	X			/* try to start dragging from here */
	X			if (slots[box_index].active != ACTIVE) {
	X				start_arrow_box = -1;
	X				return(0);
	X			}
	X			if (slots[box_index].cur_appt->arrows > 0) {
	X				/* remove old arrows and adjust counts */
	X				(void)deactivate_lower_arrows(box_index);
	X				j = slots[box_index].cur_appt->arrows;
	X				while (j > 0)
	X					slots[box_index+(j--)].count--;
	X				slots[box_index].cur_appt->arrows = 0;
	X			}
	X			prev_box = start_arrow_box = box_index;
	X		} else {
	X			/* end of dragging => end of arrow */
	X			if (box_index < start_arrow_box || start_arrow_box == -1) {
	X				start_arrow_box = -1;
	X				return(0);
	X			}
	X			if (box_index > start_arrow_box) {
	X				i = start_arrow_box;
	X				slots[i].cur_appt->arrows = box_index - start_arrow_box;
	X				while (++i < box_index) {
	X					slots[i].count++;
	X					if (slots[i].active == INACTIVE)
	X						slots[i].active = ARROW_SHAFT;
	X					/*
	X					 * erase arrow shaft on boxes - it will be
	X					 * replaced by a real arrowshaft during redraw
	X					 */
	X					pw_rop(main_pixwin, slots[i].slot_pos.left+1,
	X						slots[i].slot_pos.top+1,
	X						dayslot_width-2, dayslot_height-2,
	X						PIX_SRC^PIX_DST, arrowshaft_pr,
	X						0, 0);
	X				}
	X				slots[i].count++;
	X				if (slots[i].active == INACTIVE)
	X					slots[i].active = ARROW_HEAD;
	X				/*
	X				 * erase arrow shaft on last box - it will be
	X				 * replaced by an arrowhead during redraw
	X				 */
	X				pw_rop(main_pixwin, slots[i].slot_pos.left+1,
	X					slots[i].slot_pos.top+1,
	X					dayslot_width-2, dayslot_height-2,
	X					PIX_SRC^PIX_DST, arrowshaft_pr,
	X					0, 0);
	X			}
	X			start_arrow_box = -1;
	X			new_entry = 1;
	X			draw_day_appts();
	X		}
	X	} else if (found_flag == FOUND_SLOT && event_id(event) == LOC_DRAG) {
	X		/* mouse dragging - is it the middle button ? */
	X		if ((int)window_get(canvas, WIN_EVENT_STATE, MS_MIDDLE) && start_arrow_box >= 0) {
	X			if (box_index >= n_tslots)
	X				/* don't flow into notes section */
	X				box_index = n_tslots - 1;
	X			/*
	X			 * xor arrow shaft thru current slot so
	X			 * we can see where we're dragging
	X			 */
	X			if (box_index > prev_box) {
	X				while (++prev_box <= box_index) {
	X					pw_rop(main_pixwin, slots[prev_box].slot_pos.left+1,
	X						slots[prev_box].slot_pos.top+1,
	X						dayslot_width-2, dayslot_height-2,
	X						PIX_SRC^PIX_DST, arrowshaft_pr,
	X						0, 0);
	X				}
	X				prev_box = box_index;
	X			} else if (box_index < prev_box && box_index >= start_arrow_box) {
	X				/* going backwards - cleanup as we go */
	X				while (prev_box > box_index) {
	X					pw_rop(main_pixwin, slots[prev_box].slot_pos.left+1,
	X						slots[prev_box].slot_pos.top+1,
	X						dayslot_width-2, dayslot_height-2,
	X						PIX_SRC^PIX_DST, arrowshaft_pr,
	X						0, 0);
	X					--prev_box;
	X				}
	X			}
	X		}
	X	} else if (found_flag == FOUND_SLOT && event_id(event) == MS_RIGHT && event_is_down(event)) {
	X		/* Process a RB click. */
	X		/*
	X		 * display popup menu of choices, but first disable
	X		 * certain entries if this is a readonly appointment
	X		 * or an empty slot.
	X		 */
	X		/* undelete - almost always inactive */
	X		an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MUNDELETE);
	X		menu_set(an_item, MENU_INACTIVE, TRUE, 0);
	X		if (!slots[box_index].first) {
	X			/* empty slot. only paste active */
	X			paste_only();
	X		} else if (slots[box_index].cur_appt->flags & READONLY) {
	X			/* readonly => paste and copy only */
	X			paste_only();
	X			/* copy */
	X			an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MCOPY);
	X			menu_set(an_item, MENU_INACTIVE, FALSE, 0);
	X		} else {
	X			/* delete */
	X			an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MDELETE);
	X			menu_set(an_item, MENU_INACTIVE, FALSE, 0);
	X			/* cut */
	X			an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MCUT);
	X			menu_set(an_item, MENU_INACTIVE, FALSE, 0);
	X			/* copy */
	X			an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MCOPY);
	X			menu_set(an_item, MENU_INACTIVE, FALSE, 0);
	X			/* modify */
	X			an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MMODIFY);
	X			menu_set(an_item, MENU_INACTIVE, FALSE, 0);
	X			for (aptr=slots[box_index].first; aptr; aptr=aptr->next)
	X				if (aptr->flags & DELETED) {
	X					if (slots[box_index].active != ACTIVE)
	X						/* only paste and undelete */
	X						paste_only();
	X					/* undelete */
	X					an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MUNDELETE);
	X					menu_set(an_item, MENU_INACTIVE, FALSE, 0);
	X					break;
	X				}
	X		}
	X		i = (int) menu_show(day_sel_menu, canvas, event, 0);
	X		if (i > 0)
	X			switch (i) {
	X				case MDELETE:
	X					delete_appt(box_index, canvas);
	X					break;
	X				case MCUT:
	X					cut_appt(box_index, canvas);
	X					break;
	X				case MCOPY:
	X					copy_appt(box_index);
	X					break;
	X				case MPASTE:
	X					paste_appt(box_index);
	X					break;
	X				case MMODIFY:
	X					modify_appt(box_index, canvas);
	X					break;
	X				case MUNDELETE:
	X					undelete_appt(box_index);
	X					break;
	X			}
	X		if (new_entry) {
	X			close_day();
	X			draw_day();	/* redraw display */
	X		}
	X	} else
	X		window_default_event_proc(canvas, event, 0);
	X
	X}
	X
	X/* make "paste" the only active menu entry */
	Xpaste_only()
	X{
	X	Menu_item an_item;
	X
	X	/* delete */
	X	an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MDELETE);
	X	menu_set(an_item, MENU_INACTIVE, TRUE, 0);
	X	/* cut */
	X	an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MCUT);
	X	menu_set(an_item, MENU_INACTIVE, TRUE, 0);
	X	/* copy */
	X	an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MCOPY);
	X	menu_set(an_item, MENU_INACTIVE, TRUE, 0);
	X	/* modify */
	X	an_item = menu_get(day_sel_menu, MENU_NTH_ITEM, MMODIFY);
	X	menu_set(an_item, MENU_INACTIVE, TRUE, 0);
	X}
	X
	X/* draw (or erase) text cursor in a day slot */
	Xtext_cursor(slotno)
	Xint slotno;
	X{
	X	int	strl, x;
	X
	X	strl = strlen(&slots[slotno].cur_appt->str[slots[slotno].cur_appt->sindex]);
	X	if (strl > (day_message_size-1)) {
	X		pw_write(main_pixwin, slots[slotno].slot_pos.right, slots[slotno].slot_pos.bottom-4,
	X		  8, 8, PIX_SRC^PIX_DST, &tri_right_pr, 0, 0);
	X	} else {
	X		x = slots[slotno].slot_pos.left + strl * font->pf_defaultsize.x;
	X		pw_write(main_pixwin, x, slots[slotno].slot_pos.bottom-4,
	X		  16, 16, PIX_SRC^PIX_DST, &tri_up_pr, 0, 0);
	X	}
	X	old_slot = slotno;
	X}
	X
	X/* make slot active */
	Xmake_box_active(bi)
	Xint bi;
	X{
	X	add_to_slot(bi, NULL, TRUE);
	X	fill_appt(bi);
	X	rewrite_string(bi, JUSTIFY_LEFT);
	X	text_cursor(bi);
	X}
	X
	X/* activate a hidden appt and make it visible */
	Xint
	Xactivate_slot(bi, dpyflag)
	Xint bi;
	Xint dpyflag;
	X{
	X	int n, e_slot;
	X
	X	if (slots[bi].count <= 0)
	X		/* nothing to activate */
	X		return(0);
	X	if (slots[bi].cur_appt == NULL) {
	X		/* may be hidden arrows */
	X		/* find appt that they came from so we can see if
	X		 * it should be arrow shaft or arrow head
	X		 */
	X		n = bi;
	X		while (--n >= 0 && slots[n].active != ACTIVE)
	X			;
	X		if (n >= 0) {
	X			e_slot = n + slots[n].cur_appt->arrows;
	X			if (e_slot < bi)
	X				/* no arrows here to show */
	X				return(0);
	X			while (++n < e_slot && slots[n].active != ACTIVE)
	X				slots[n].active = ARROW_SHAFT;
	X			if (slots[n].active != ACTIVE)
	X				slots[n].active = ARROW_HEAD;
	X		} else
	X			/* no active appt above */
	X			return(0);
	X	} else {
	X		/* there's a real appt hidden */
	X		slots[bi].active = ACTIVE;
	X		if (slots[bi].cur_appt->arrows > 0) {
	X			e_slot = bi + slots[bi].cur_appt->arrows;
	X			while (++bi < e_slot && slots[bi].active != ACTIVE)
	X				slots[bi].active = ARROW_SHAFT;
	X			if (slots[bi].active != ACTIVE)
	X				slots[bi].active = ARROW_HEAD;
	X		}
	X	}
	X	if (dpyflag)
	X		draw_day_appts();	/* redraw display */
	X	return(1);
	X}
	X
	X/* clears a day slot */
	Xdeactivate_slot(bi, dpyflag)
	Xint bi;
	X{
	X	slots[bi].active = INACTIVE;
	X	if (!dpyflag)
	X		return;
	X	/* erase text cursor at old location */
	X	if (old_slot >= 0) {
	X		text_cursor(old_slot);
	X		old_slot = -1;
	X	}
	X	/* erase displayed slot */
	X	if (!ymd_compare(current, today))
	X		pw_write(main_pixwin, slots[bi].slot_pos.left, slots[bi].slot_pos.top,
	X		  dayslot_width, dayslot_height, PIX_SRC, timeslot_td_pr, 0, 0);
	X	else
	X		pw_write(main_pixwin, slots[bi].slot_pos.left+1, slots[bi].slot_pos.top+1,
	X		  dayslot_width-2, dayslot_height-2, PIX_CLR, NULL, 0, 0);
	X}
	X
	X/* returns pointer to slot containing arrow head */
	Xint
	Xdeactivate_lower_arrows(bi, dpyflag)
	Xint bi;
	X{
	X	while (bi < N_SLOTS-1) {
	X		bi++;
	X		if (slots[bi].active != ARROW_SHAFT &&
	X		    slots[bi].active != ARROW_HEAD)
	X			return(bi-1);
	X		slots[bi].active = INACTIVE;
	X		if (!dpyflag)
	X			continue;
	X		/* erase displayed slot */
	X		if (!ymd_compare(current, today))
	X			pw_write(main_pixwin, slots[bi].slot_pos.left, slots[bi].slot_pos.top,
	X			  dayslot_width, dayslot_height, PIX_SRC, timeslot_td_pr, 0, 0);
	X		else
	X			pw_write(main_pixwin, slots[bi].slot_pos.left+1, slots[bi].slot_pos.top+1,
	X			  dayslot_width-2, dayslot_height-2, PIX_CLR, NULL, 0, 0);
	X	}
	X}
	X
	X/* fill in appt struct with current info */
	Xfill_appt(bi)
	Xint bi;
	X{
	X	int s_hour, s_minute, n_arrows;
	X
	X	slots[bi].cur_appt->year = current.tm_year;
	X	slots[bi].cur_appt->month = current.tm_mon;
	X	slots[bi].cur_appt->day = current.tm_mday;
	X	slots[bi].cur_appt->arrows = 0;
	X	slots[bi].cur_appt->flags = slots[bi].cur_appt->repeat = 0;
	X	slots[bi].cur_appt->lookahead = slots[bi].cur_appt->sindex = 0;
	X	if (bi >= n_tslots) {
	X		/* notes section */
	X		slots[bi].cur_appt->hour = 99;
	X		slots[bi].cur_appt->minute = 0;
	X		slots[bi].cur_appt->flags = A_NOTE;
	X	} else {
	X		/* regular appt */
	X		slots[bi].cur_appt->hour = bi/2 + START_HOUR;
	X		slots[bi].cur_appt->minute = (bi % 2) * 30;
	X	}
	X	slots[bi].cur_appt->str[0] = '\0';
	X}
	X
	X/*
	X * Display delete popup window to let user choose delete mode for
	X * recurring appts (delete this one only or delete all), otherwise,
	X * just wipe it out with no options.
	X */
	Xdelete_appt(bi, canvas)
	Xint bi;
	XCanvas canvas;
	X{
	X	Rect *canvas_r;
	X	int top, left, width, height;
	X
	X	if (slots[bi].cur_appt->flags & READONLY) {
	X		err_rpt("Can't delete a read-only appt", NON_FATAL);
	X		return;
	X	}
	X	if (slots[bi].cur_appt->flags & (REPEAT|ALL_YEARS|ALL_MONTHS|ALL_DAYS)) {
	X		attr_bi = bi;	/* set global index for notify func */
	X
	X		/* get x,y position of canvas window on the screen so we
	X		 * can center popup window in it.
	X		 */
	X		canvas_r = (Rect *) window_get(canvas, WIN_RECT);
	X		panel_set(del_choice_pi, PANEL_CHOICE_STRINGS,
	X			"Delete this occurrance only",
	X			"Delete all occurrances", 0,
	X			PANEL_CLIENT_DATA, 0,
	X			0);
	X		window_fit(del_panel);
	X		window_fit(del_frame);
	X		width = (int) window_get(del_frame, WIN_WIDTH);
	X		height = (int) window_get(del_frame, WIN_HEIGHT);
	X		left =  canvas_r->r_left + (canvas_r->r_width - width) / 2;
	X		top =  canvas_r->r_top + (canvas_r->r_height - height) / 2;
	X		window_set(del_frame, WIN_X, left, WIN_Y, top, 0);
	X		panel_set_value(del_choice_pi, 0);
	X
	X		window_loop(del_frame);	/* let user select things */
	X	} else {
	X		cut_delete(bi);
	X		new_entry = 1;
	X	}
	X}
	X
	Xcut_appt(bi, canvas)
	Xint bi;
	XCanvas canvas;
	X{
	X	Rect *canvas_r;
	X	int top, left, width, height;
	X	int i;
	X
	X	/* cut (delete) current entry, saving the info on the "shelf" */
	X	if (slots[bi].cur_appt->flags & READONLY) {
	X		err_rpt("Can't cut a read-only appt", NON_FATAL);
	X		return;
	X	}
	X	shelf_appt = *slots[bi].cur_appt;
	X	if (slots[bi].cur_appt->flags & (REPEAT|ALL_YEARS|ALL_MONTHS|ALL_DAYS)) {
	X		attr_bi = bi;	/* set global index for notify func */
	X
	X		/* get x,y position of canvas window on the screen so we
	X		 * can center popup window in it.
	X		 */
	X		canvas_r = (Rect *) window_get(canvas, WIN_RECT);
	X		panel_set(del_choice_pi, PANEL_CHOICE_STRINGS,
	X			"Move this occurrance only",
	X			"Move all occurrances", 0,
	X			PANEL_CLIENT_DATA, 1,
	X			0);
	X		window_fit(del_panel);
	X		window_fit(del_frame);
	X		width = (int) window_get(del_frame, WIN_WIDTH);
	X		height = (int) window_get(del_frame, WIN_HEIGHT);
	X		left =  canvas_r->r_left + (canvas_r->r_width - width) / 2;
	X		top =  canvas_r->r_top + (canvas_r->r_height - height) / 2;
	X		window_set(del_frame, WIN_X, left, WIN_Y, top, 0);
	X		panel_set_value(del_choice_pi, 0);
	X
	X		window_loop(del_frame);	/* let user select things */
	X	} else {
	X		cut_delete(bi);
	X		new_entry = 1;
	X	}
	X}
	X
	Xcut_delete(bi)
	Xint bi;
	X{
	X	int j;
	X	struct appt_entry *aptr, *cptr, *optr;
	X
	X	cptr = slots[bi].cur_appt;
	X	slots[bi].count--;
	X	deactivate_slot(bi, TRUE);
	X	if ( (j = cptr->arrows) > 0) {
	X		/* remove old arrows and adjust counts */
	X		(void) deactivate_lower_arrows(bi, TRUE);
	X		while (j > 0)
	X			slots[bi+(j--)].count--;
	X	}
	X	if (slots[bi].cur_appt == slots[bi].first) {
	X		/* displaying first entry in list */
	X		/* see if there's any more */
	X		if (slots[bi].first->next)
	X			slots[bi].first = slots[bi].first->next;
	X		else {
	X			/* last one */
	X			slots[bi].first = NULL;
	X			slots[bi].active = INACTIVE;
	X		}
	X		slots[bi].cur_appt = slots[bi].first;
	X	} else {
	X		/* not first, so find previous one to this */
	X		for (aptr=slots[bi].first; slots[bi].cur_appt!=aptr; optr=aptr,aptr=aptr->next)
	X			;
	X		slots[bi].cur_appt = optr->next = aptr->next;
	X		if (!optr->next)
	X			slots[bi].cur_appt = slots[bi].first;
	X	}
	X	free(cptr);
	X	(void)activate_slot(bi, TRUE);	/* show any hidden appts */
	X}
	X
	Xcopy_appt(bi)
	Xint bi;
	X{
	X	/* copy current entry, saving the info on the "shelf" */
	X	shelf_appt = *slots[bi].cur_appt;
	X}
	X
	Xpaste_appt(bi)
	Xint bi;
	X{
	X	int j;
	X
	X	/* insert the saved entry (if any) */
	X	if (shelf_appt.str[0] == '\0') {
	X		err_rpt("nothing to paste", NON_FATAL);
	X		return;
	X	}
	X	shelf_appt.year = current.tm_year;
	X	shelf_appt.month = current.tm_mon;
	X	shelf_appt.day = current.tm_mday;
	X	if (bi >= N_TSLOTS) {
	X		/* notes section */
	X		shelf_appt.hour = 99;
	X		shelf_appt.minute = 0;
	X		/* just in case converting from time to note */
	X		shelf_appt.flags |= A_NOTE;
	X	} else {
	X		/* regular appt */
	X		shelf_appt.hour = bi/2 + START_HOUR;
	X		shelf_appt.minute = (bi % 2) * 30;
	X		/* just in case converting from note to time */
	X		shelf_appt.flags &= ~MARKED_NOTE;
	X	}
	X	add_to_slot(bi, &shelf_appt, TRUE);
	X	new_entry = 1;
	X}
	X
	X/*
	X * Display attributes popup window to let user modify
	X * various appointment options (such as repeat interval,
	X * etc.)
	X */
	Xmodify_appt(bi, canvas)
	Xint bi;
	XCanvas canvas;
	X{
	X	Rect *canvas_r;
	X	int top, left, width, height;
	X
	X	if (slots[bi].cur_appt->flags & READONLY) {
	X		err_rpt("Can't modify a read-only appt", NON_FATAL);
	X		return;
	X	}
	X	attr_bi = bi;	/* set global index for notify func */
	X	set_attr();	/* set panel item current values */
	X
	X	/* get x,y position of canvas window on the screen so we
	X	 * can center this one in it.
	X	 */
	X	canvas_r = (Rect *) window_get(canvas, WIN_RECT);
	X	width = (int) window_get(attr_frame, WIN_WIDTH);
	X	height = (int) window_get(attr_frame, WIN_HEIGHT);
	X	left =  canvas_r->r_left + (canvas_r->r_width - width) / 2;
	X	top =  canvas_r->r_top + (canvas_r->r_height - height) / 2;
	X	window_set(attr_frame, WIN_X, left, WIN_Y, top, 0);
	X
	X	window_loop(attr_frame);	/* let user select things */
	X	window_set(attr_frame, WIN_SHOW, FALSE, 0);
	X}
	X
	X/* undelete a recurring appointment for this day */
	X/* we only get here if a deleted appt exits */
	Xundelete_appt(bi)
	Xint bi;
	X{
	X	struct appt_entry *aptr, *optr;
	X
	X	/* search list to find deleted entry */
	X	for (optr=aptr=slots[bi].first; aptr; optr=aptr,aptr=aptr->next)
	X		if (aptr->flags & DELETED)
	X			break;
	X	if (aptr == slots[bi].first)
	X		slots[bi].first = aptr->next;
	X	else
	X		optr->next = aptr->next;
	X	slots[bi].count++;
	X	if (slots[bi].active == INACTIVE) {
	X		slots[bi].cur_appt = slots[bi].first;
	X		(void)activate_slot(bi, TRUE);
	X	}
	X	free(aptr);
	X	new_entry = 1;
	X}
	X
	Xset_attr()
	X{
	X	int everyx_val = 0, whichwk_val = 0;
	X	char str[5];
	X	struct appt_entry *apt = slots[attr_bi].cur_appt;
	X
	X	panel_set_value(repeat_pi, "");	/* set default */
	X	panel_set_value(remind_pi, "");	/* set default */
	X	if (apt->flags & ALL_DAYS)
	X		everyx_val |= 0x1;
	X	if (apt->flags & ALL_MONTHS)
	X		everyx_val |= 0x4;
	X	if (apt->flags & ALL_YEARS)
	X		everyx_val |= 0x8;
	X	if (apt->flags & EVERY_SOMEDAY) {
	X		everyx_val |= 0x2;
	X		whichwk_val = apt->repeat;
	X		panel_set(repeat_pi, PANEL_SHOW_ITEM, FALSE, 0);
	X		panel_set(whichwk_pi, PANEL_SHOW_ITEM, TRUE, 0);
	X	} else {
	X		if (apt->repeat) {
	X			sprintf(str, "%d", apt->repeat);
	X			panel_set_value(repeat_pi, str);
	X		}
	X		panel_set(whichwk_pi, PANEL_SHOW_ITEM, FALSE, 0);
	X		panel_set(repeat_pi, PANEL_SHOW_ITEM, TRUE, 0);
	X	}
	X	panel_set_value(everyx_pi, everyx_val);
	X	panel_set_value(whichwk_pi, whichwk_val);
	X	if (apt->flags & LOOKAHEAD) {
	X		sprintf(str, "%d", apt->lookahead);
	X		panel_set_value(remind_pi, str);
	X	}
	X	panel_set_value(marked_pi, (apt->flags & MARKED ? 1 : 0));
	X	if (apt->flags & A_NOTE)
	X		panel_set(marked_pi, PANEL_SHOW_ITEM, TRUE, 0);
	X	else
	X		panel_set(marked_pi, PANEL_SHOW_ITEM, FALSE, 0);
	X}
	X
	X/* "more" button selected. Display next appt in rotation. */
	Xnext_appt(bi, dpyflag)
	Xint bi;
	Xint dpyflag;
	X{
	X	if (slots[bi].active == ACTIVE) {
	X		deactivate_slot(bi, dpyflag);
	X		if (slots[bi].cur_appt->arrows > 0)
	X			(void)deactivate_lower_arrows(bi, dpyflag);
	X	} else
	X		/* must have arrows displayed */
	X		(void)deactivate_lower_arrows(bi, dpyflag);
	X
	X	if (slots[bi].cur_appt == NULL)
	X		/* end of the chain */
	X		slots[bi].cur_appt = slots[bi].first;
	X	else
	X		/* activate next in chain */
	X		slots[bi].cur_appt = slots[bi].cur_appt->next;
	X	/* make sure it is not a deleted one */
	X	if (chk_deleted(bi))
	X		next_appt(bi, dpyflag); /* try next in chain */
	X	else if (!activate_slot(bi, dpyflag))
	X		next_appt(bi, dpyflag); /* try next in chain */
	X}
	X
	X/* check to see if current is deleted */
	Xint
	Xchk_deleted(bi)
	Xint bi;
	X{
	X	int found = 0;
	X	struct appt_entry *aptr;
	X
	X	if (slots[bi].cur_appt == NULL)
	X		return(0);
	X	if (slots[bi].cur_appt->flags & DELETED)
	X		return(1);
	X	/* run through the list to see if there are any deleted */
	X	for (aptr=slots[bi].first; aptr; aptr=aptr->next)
	X		if (aptr->flags & DELETED) {
	X			found = 1;
	X			break;
	X		}
	X	/* now see if the current one matches */
	X	if (found && !strcmp(aptr->str, slots[bi].cur_appt->str))
	X		return(1);
	X	
	X	return(0);
	X}
	X
	X/* left scroll arrow selected */
	Xdo_left_arrow(canvas, bi)
	XCanvas canvas;
	Xint bi;
	X{
	X	struct timeval timeout;
	X	Event event;
	X	int fd, ertn, flags;
	X
	X	if (slots[bi].active != ACTIVE || strlen(slots[bi].cur_appt->str) < day_message_size)
	X		return;
	X	timeout.tv_sec = 0L;
	X	timeout.tv_usec = 100000L;	/* 1/10 sec */
	X	fd = (int)window_get(canvas, WIN_FD);
	X	flags = fcntl(fd, F_GETFL, 0);
	X	(void)fcntl(fd, F_SETFL, flags|FNDELAY);
	X	/* reverse video the arrow */
	X	pw_rop(main_pixwin, slots[bi].larrow_pos.left, slots[bi].larrow_pos.top,
	X		19, 14, PIX_NOT(PIX_DST), leftarrow, 0, 0);
	X	while (TRUE) {
	X		if (slots[bi].cur_appt->sindex < strlen(slots[bi].cur_appt->str)) {
	X			++slots[bi].cur_appt->sindex;
	X			rewrite_string(bi, JUSTIFY_INDEX);
	X			/* reverse video the arrow (rewrite changed it) */
	X			pw_rop(main_pixwin, slots[bi].larrow_pos.left, slots[bi].larrow_pos.top,
	X				19, 14, PIX_NOT(PIX_DST), leftarrow, 0, 0);
	X		}
	X		/* do this garbage to handle a repeat function */
	X		(void)select(0, NULL, NULL, NULL, &timeout);
	X		ertn = window_read_event(canvas, &event);
	X		if (ertn != -1 && event_is_up(&event))
	X			break;
	X	}
	X	/* put arrow back to normal */
	X	pw_rop(main_pixwin, slots[bi].larrow_pos.left, slots[bi].larrow_pos.top,
	X		19, 14, PIX_SRC, leftarrow, 0, 0);
	X	(void)fcntl(fd, F_SETFL, flags & ~FNDELAY);
	X}
	X
	X/* right scroll arrow selected */
	Xdo_right_arrow(canvas, bi)
	XCanvas canvas;
	Xint bi;
	X{
	X	struct timeval timeout;
	X	Event event;
	X	int fd, ertn, flags;
	X
	X	if (slots[bi].active != ACTIVE || strlen(slots[bi].cur_appt->str) < day_message_size)
	X		return;
	X	timeout.tv_sec = 0L;
	X	timeout.tv_usec = 100000L;	/* 1/10 sec */
	X	fd = (int)window_get(canvas, WIN_FD);
	X	flags = fcntl(fd, F_GETFL, 0);
	X	(void)fcntl(fd, F_SETFL, flags|FNDELAY);
	X	/* reverse video the arrow */
	X	pw_rop(main_pixwin, slots[bi].rarrow_pos.left, slots[bi].rarrow_pos.top,
	X		19, 14, PIX_NOT(PIX_DST), rightarrow, 0, 0);
	X	while (TRUE) {
	X		if (slots[bi].cur_appt->sindex > 0) {
	X			--slots[bi].cur_appt->sindex;
	X			rewrite_string(bi, JUSTIFY_INDEX);
	X			/* reverse video the arrow (rewrite changed it) */
	X			pw_rop(main_pixwin, slots[bi].rarrow_pos.left, slots[bi].rarrow_pos.top,
	X				19, 14, PIX_NOT(PIX_DST), rightarrow, 0, 0);
	X		}
	X		/* do this garbage to handle a repeat function */
	X		(void)select(0, NULL, NULL, NULL, &timeout);
	X		ertn = window_read_event(canvas, &event);
	X		if (ertn != -1 && event_is_up(&event))
	X			break;
	X	}
	X	pw_rop(main_pixwin, slots[bi].rarrow_pos.left, slots[bi].rarrow_pos.top,
	X		19, 14, PIX_SRC, rightarrow, 0, 0);
	X	(void)fcntl(fd, F_SETFL, flags & ~FNDELAY);
	X}
SHAR_EOF
if test 27402 -ne "`wc -c < 'devent.c'`"
then
	echo shar: error transmitting "'devent.c'" '(should have been 27402 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'dpaint.c'" '(24098 characters)'
if test -f 'dpaint.c'
then
	echo shar: will not over-write existing file "'dpaint.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'dpaint.c'
	X/*
	X * $Header: dpaint.c,v 2.2 89/05/10 10:06:20 billr Exp $
	X */
	X/*
	X * dpaint.c
	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 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 *	Artistic routines that draw in the main    *
	X * subwindow for the day display.		   *
	X *						   *
	X ***************************************************/
	X
	X#include <suntool/sunview.h>
	X#include <suntool/canvas.h>
	X#include <ctype.h>
	X#include <sys/time.h>
	X#include <stdio.h>
	X#include "ct.h"
	X#include "paint.h"
	X#include "riseset.h"
	X#define J1970   2440587.5 /* VAX clock Epoch 1970 Jan 1 (0h UT) */
	X
	X#ifndef NO_SUN_MOON
	Xextern Frame mframe, sframe;
	Xextern Canvas mcanvas, scanvas;
	Xextern Panel_item mdate_pi, sdate_pi;
	X#endif
	Xextern Pixrect *leftarrow, *rightarrow;
	Xextern Pixrect *arrowshaft_pr, *arrowhead_pr;
	Xextern int day_message_size;
	Xextern char riseset_buf[][64];
	Xextern int old_slot;
	Xextern int show_future;
	Xextern char *index();
	X
	Xstruct tm save_day;
	Xstruct appt_entry future[MAX_FUTURE_ENTRIES];
	Xint findex = 0;		/* index into struct future array */
	X
	X/*
	X * This one draws the current selected day in the
	X * main subwindow.
	X */
	X
	Xdraw_day()
	X{
	X	draw_day1();
	X	draw_future_appts();
	X#ifndef NO_SUN_MOON
	X	if (sframe)
	X		write_sun_data();
	X	if (mframe)
	X		write_moon_data();
	X#endif
	X}
	X
	X/*
	X * Draw main day page without future appts or Sun/Moon data
	X */
	Xdraw_day1()
	X{
	X	lock_cursors();
	X	fix_current_day();
	X	working(TRUE);
	X	pw_batch_on(main_pixwin);
	X	draw_day_outline();
	X	pw_batch_off(main_pixwin);
	X	get_day_appts();
	X	working(FALSE);
	X	pw_batch_on(main_pixwin);
	X	draw_day_appts();
	X	pw_batch_off(main_pixwin);
	X	day_is_open = TRUE;
	X	unlock_cursors();
	X}
	X
	X/*
	X * Utility for draw_day ... draws the outline of a day.
	X */
	Xdraw_day_outline()
	X{
	X	char timestring[6], daystring[31], buf[64], *src;
	X	int x, y, starty, i, d;
	X	Rect *rect;
	X
	X	/* First erase the window. */
	X	rect = (Rect *) window_get(canvas, WIN_RECT);
	X        pw_writebackground(main_pixwin, 0, 0,
	X	  rect->r_width, rect->r_height, PIX_CLR);
	X	old_slot = -1;	/* text cursor no longer displayed */
	X
	X	/* Calculate coords of top-left corner of big box. */
	X	x = (rect->r_width - dayslot_width) / 2;
	X	starty = y = (rect->r_height - (N_SLOTS * dayslot_height)) / 2;
	X
	X	/* Format daystring to say, for example, */
	X	/* Tuesday, March 12, 1985 */
	X	sprintf(daystring, "%s %s %d, %d",
	X		daynames[current.tm_wday], monthnames[current.tm_mon],
	X		current.tm_mday, 1900 + current.tm_year);
	X	pw_text(main_pixwin, (rect->r_width - bigfont->pf_defaultsize.x*strlen(daystring))/2, starty/2 + 7,
	X	  PIX_SRC, bigfont, daystring);
	X
	X	for (i=0; i<N_SLOTS; i++) {	/* Init and draw each 30 minute slot. */
	X                slots[i].slot_pos.top = y;
	X		slots[i].slot_pos.left = x;
	X		slots[i].slot_pos.bottom = y + dayslot_height + 1;
	X		slots[i].slot_pos.right = x + dayslot_width + 1;
	X		slots[i].moreb_pos.top = y;
	X		slots[i].moreb_pos.left = rect->r_width - 8 - morebutton->pr_size.x;
	X		slots[i].moreb_pos.bottom = y + morebutton->pr_size.y;
	X		slots[i].moreb_pos.right = rect->r_width - 8;
	X		slots[i].larrow_pos.top = slots[i].slot_pos.top+(dayslot_height-leftarrow->pr_size.y)/2;
	X		slots[i].larrow_pos.left = slots[i].slot_pos.right + 8;
	X		slots[i].larrow_pos.bottom = slots[i].larrow_pos.top + leftarrow->pr_size.y;
	X		slots[i].larrow_pos.right = slots[i].larrow_pos.left + leftarrow->pr_size.x;
	X		slots[i].rarrow_pos.top = slots[i].larrow_pos.top;
	X		slots[i].rarrow_pos.left = slots[i].larrow_pos.right + 8;
	X		slots[i].rarrow_pos.bottom = slots[i].larrow_pos.bottom;
	X		slots[i].rarrow_pos.right = slots[i].rarrow_pos.left + rightarrow->pr_size.x;
	X		if (!ymd_compare(current, today))
	X			pw_write(main_pixwin,x,y,dayslot_width,dayslot_height,PIX_SRC,timeslot_td_pr,0,0);
	X		else
	X			pw_write(main_pixwin,x,y,dayslot_width,dayslot_height,PIX_SRC,timeslot_pr,0,0);
	X		if (i < n_tslots) {
	X			/* display time */
	X			sprintf(timestring, "%2d:%s",
	X				(START_HOUR+(i/2))%12 == 0 ? 12 : (START_HOUR+(i/2))%12,
	X				i%2 == 0 ? "00" : "30");
	X		} else if (i == n_tslots) {
	X			sprintf(timestring, "Notes");
	X		} else {
	X			sprintf(timestring, "     ");
	X		}
	X		pw_text(main_pixwin,x-8*font->pf_defaultsize.x,y+font->pf_defaultsize.y,PIX_SRC,font,timestring);
	X		y += dayslot_height - 1;
	X	}
	X
	X	pw_vector(main_pixwin,x,starty,x+dayslot_width-1,starty,PIX_SET,1);
	X        pw_vector(main_pixwin,x,y,x+dayslot_width-1,y,PIX_SET,1);
	X	y += (dayslot_height - 1) * 2;
	X	sprintf(buf, "Day of year: %d  --  %d days remaining",
	X		day_of_year((double)current.tm_mday, current.tm_mon+1, current.tm_year),
	X		days_remaining_in_year((double)current.tm_mday, current.tm_mon+1, current.tm_year));
	X	pw_text(main_pixwin, x, y, PIX_SRC, font, buf);
	X	sun_moon_buttons(TRUE);
	X	print_button(TRUE);
	X}
	X
	X
	X/*
	X * Fills in appointments for the day.  
	X * The ".tmp.aptsXXXXX" file is filled out
	X * with all the lines from the ".appointments" file 
	X * which do not pertain to the current day.
	X */
	Xget_day_appts()
	X{
	X	FILE *apts, *temp_apts;
	X	int slotno, n_arrows, i;
	X	int read_stat;
	X	struct appt_entry appt;
	X	struct appt_entry *nappt, *aptr;
	X	char buf[MAX_STRLEN], *sptr;
	X
	X	if ((apts = fopen(apts_pathname, "r")) == NULL)
	X		err_rpt("can't open appointments file", FATAL);
	X
	X	if (!read_only)
	X	        if ((temp_apts = fopen(tmpapts_pathname, "w")) == NULL)
	X			err_rpt("can't open temp file for writing", FATAL);
	X
	X	for (i=0; i<N_SLOTS; i++) {	/* init each slot */
	X                slots[i].active = INACTIVE;
	X		slots[i].count = 0;
	X		slots[i].cur_appt = NULL;
	X		slots[i].first = NULL;
	X	}
	X	First = current;
	X	findex = 0;
	X
	X#ifndef NO_HOLIDAYS
	X	/*
	X	 * First check to see if the user has selected any holiday
	X	 * options and add them in.
	X	 */
	X	if (a_dates(&appt, holiday_a))
	X		add_note(&appt);
	X	if (c_dates(&appt, holiday_c))
	X		add_note(&appt);
	X	working(FALSE);
	X	if (i = i_dates(&appt, holiday_i))
	X		if (i == 2) {
	X			/* two notes in one */
	X			strcpy(buf, appt.str);
	X			/* look for \n */
	X			sptr = index(appt.str, '\n');
	X			*sptr = '\0';
	X			add_note(&appt);
	X			/* now second half of string in the next note */
	X			strcpy(appt.str, &buf[(int)(sptr-appt.str)+1]);
	X			add_note(&appt);
	X		} else
	X			add_note(&appt);
	X	working(TRUE);
	X	if (j_dates(&appt, holiday_j))
	X		add_note(&appt);
	X	if (s_dates(&appt, holiday_s))
	X		add_note(&appt);
	X#endif
	X			
	X	/*
	X	 * now go thru the appointments file
	X	 */
	X	while ((read_stat=get_aentry(apts, &appt)) != EOF) {
	X		if (read_stat)
	X			continue;	/* read error (ignore) */
	X		if (appt.flags & A_COMMENT) {
	X			if (put_aentry(temp_apts, &appt)) {
	X				/* write error */
	X				break;
	X			}
	X			continue;
	X		}
	X		current.tm_year = appt.year;
	X		current.tm_mon = appt.month;
	X		current.tm_mday = appt.day;
	X		if (appt.flags & ALL_YEARS)
	X			current.tm_year = First.tm_year;
	X		if (appt.flags & ALL_MONTHS)
	X			current.tm_mon = First.tm_mon;
	X		if (appt.flags & ALL_DAYS)
	X			current.tm_mday = First.tm_mday;
	X		else if (appt.flags & EVERY_SOMEDAY) {
	X			if (Pickday(appt.flags) == First.tm_wday) {
	X				if (chk_week(appt.repeat, First.tm_mday))
	X					current.tm_mday = First.tm_mday;
	X			}
	X		} else if (appt.flags & REPEAT) {
	X			while (ymd_compare(current, First) < 0) {
	X				current.tm_mday += appt.repeat;
	X				fix_current_day();
	X			}
	X		}
	X		if (ymd_compare(current, First) == 0) {
	X			/* if it's for this day, fill in slot info */
	X			if (appt.flags & A_NOTE)
	X				/* notes section */
	X				add_note(&appt);
	X			else {
	X				/* regular appointment */
	X				slotno = (appt.hour-START_HOUR) * 2 + appt.minute / 30;
	X				if (slotno < 0)
	X					slotno = 0;
	X				if (slotno >= n_tslots)
	X					slotno = n_tslots - 1;
	X				/* add this appt to the list of appts for the slot */
	X				/* and update all the reference counts */
	X				add_to_slot(slotno, &appt, FALSE);
	X			}
	X		} else if (appt.flags & LOOKAHEAD) {
	X			/* This lookahead appt was not for today, so
	X			 * put it in the temp file.
	X			 */
	X			if (put_aentry(temp_apts, &appt)) {
	X				/* write error */
	X				break;
	X			}
	X			if (appt.flags & EVERY_SOMEDAY) {
	X				/* find next occurance of this appt */
	X				/* starting from the current day */
	X				current.tm_mday = First.tm_mday;
	X				fix_current_day();
	X				find_date(&appt); /* may modify current */
	X			}
	X			if (ymd_compare(current, First) > 0) {
	X				/* this appt is happening in
	X				 * the future, so remind us of it if
	X				 * it is within the lookahead window.
	X				 */
	X				save_day = current;
	X				current.tm_mday -= appt.lookahead;
	X				fix_current_day();
	X				if (ymd_compare(current, First) <=0) {
	X					/* save this one for the future popup window */
	X					if (findex > MAX_FUTURE_ENTRIES-1) {
	X						err_rpt("Too many future reminders", NON_FATAL);
	X						continue;
	X					}
	X					future[findex] = appt;
	X					/* fix up ymd */
	X					future[findex].year = save_day.tm_year;
	X					future[findex].month = save_day.tm_mon;
	X					future[findex].day = save_day.tm_mday;
	X					++findex;
	X				}
	X			}
	X                } else { 	/* line is not for today */
	X			/* copy it to temp file */
	X			if (put_aentry(temp_apts, &appt)) {
	X				/* write error */
	X				break;
	X			}
	X		}
	X        }
	X	if (!read_only) {
	X		if (ferror(temp_apts))
	X			err_rpt("write on temp file failed", FATAL);
	X        	fclose(temp_apts);        
	X	}
	X        fclose(apts);             
	X	current = First;
	X	fix_current_day();
	X}
	X
	X
	X/* check for match on weekly re-ocurring appts */
	Xchk_week(repeat, curday)
	Xint repeat, curday;
	X{
	X	int weeknr = 0;
	X
	X	if ((repeat & ALL_WEEKS) == ALL_WEEKS)
	X		return(1);	/* every week */
	X	if ((repeat & LAST_WEEK) && ((curday+7) > monthlength(current.tm_mon)))
	X		return(1);	/* last week in month */
	X
	X	while (curday > 7) {
	X		/* find which week this day is in */
	X		curday -= 7;
	X		weeknr++;
	X	}
	X	if (repeat & (0x1<<weeknr))
	X		return(1);
	X	
	X	return(0);	/* no match */
	X}
	X
	X
	X/*
	X * get date of next occurrance of a weekly repeated appt
	X * (it may bridge into next week, month or year)
	X */
	Xfind_date(appt)
	Xstruct appt_entry *appt;
	X{
	X	struct tm save;
	X
	X	save = current;
	X	/* set current to match dow of repeated appt */
	X	current.tm_mday += Pickday(appt->flags) - current.tm_wday;
	X	fix_current_day();
	X	if (ymd_compare(current, save) < 0) {
	X		/* already happened, so start looking next week */
	X		current.tm_mday += 7;
	X		fix_current_day();
	X	}
	X	/* search for first matching week */
	X	while (!chk_week(appt->repeat, current.tm_mday)) {
	X		current.tm_mday += 7;
	X		fix_current_day();
	X	}
	X	/* now check to make sure this is legal, i.e. there
	X	 * were no month or year restrictions
	X	 */
	X	if ((!(appt->flags & ALL_YEARS) && current.tm_year != save.tm_year)
	X	   || (!(appt->flags & ALL_MONTHS) && current.tm_mon != save.tm_mon))
	X		/* invalid date, due to month or year wrap */
	X		current = save;
	X}
	X
	X		
	X/* add a note to the current day */
	Xadd_note(appt)
	Xstruct appt_entry *appt;
	X{
	X	int	slotno;
	X
	X	/* auto-hunt for free note slot */
	X	for (slotno=n_tslots; slotno<N_SLOTS; slotno++)
	X		if (slots[slotno].active == INACTIVE)
	X			break;
	X	if (slotno == N_SLOTS) {
	X		/* overflow of notes field, so
	X		 * add to last note field list
	X		 */
	X		slotno = N_SLOTS - 1;
	X	}
	X	add_to_slot(slotno, appt, FALSE);
	X}
	X
	X/* draw in todays appointments */
	Xdraw_day_appts()
	X{
	X	int slotno = 0;
	X
	X	while (slotno < N_SLOTS) {
	X		if (slots[slotno].count > 0) {
	X			switch (slots[slotno].active) {
	X				case ACTIVE:
	X					rewrite_string(slotno, JUSTIFY_LEFT);
	X					break;
	X				case ARROW_SHAFT:
	X					draw_arrowshaft(slotno);
	X					break;
	X				case ARROW_HEAD:
	X					draw_arrowhead(slotno);
	X					break;
	X				case INACTIVE:
	X					break;
	X			}
	X			more_check(slotno);
	X		}
	X		++slotno;
	X	}
	X}
	X
	X/* Blacks out day-slot and then re-writes string. */
	Xrewrite_string(bi, justify)
	Xint bi, justify;  
	X{
	X	char slot_str[MAX_STRLEN];
	X	char *ptr;
	X	int strl, *iptr;
	X
	X	strl = strlen(slots[bi].cur_appt->str);
	X	iptr = &slots[bi].cur_appt->sindex;
	X	if (strl < day_message_size) {
	X		*iptr = 0; /* just in case */
	X		strcpy(slot_str, slots[bi].cur_appt->str);
	X		/* erase any previously existing scroll arrows */
	X		pw_writebackground(main_pixwin, slots[bi].larrow_pos.left,
	X			slots[bi].larrow_pos.top, slots[bi].rarrow_pos.right-slots[bi].larrow_pos.left,
	X			slots[bi].larrow_pos.bottom-slots[bi].larrow_pos.top,
	X			PIX_CLR);
	X	} else {
	X		if (justify == JUSTIFY_RIGHT) {
	X			/* show trailing part */
	X			ptr = &slots[bi].cur_appt->str[strl - day_message_size + 1];
	X			*iptr = strl - day_message_size + 1;
	X			strcpy(slot_str, ptr);
	X		} else {
	X			/* show leading or indexed part */
	X			if (justify == JUSTIFY_LEFT)
	X				*iptr = 0;
	X			if (*iptr > (strl - day_message_size + 1))
	X				*iptr = strl - day_message_size + 1;
	X			if (strlen(&slots[bi].cur_appt->str[*iptr]) >= day_message_size-1) {
	X				strncpy(slot_str, &slots[bi].cur_appt->str[*iptr], day_message_size-1);
	X				slot_str[day_message_size-1] = '\0';
	X			} else
	X				strcpy(slot_str, &slots[bi].cur_appt->str[*iptr]);
	X		}
	X		/* display scroll arrows */
	X		pw_write(main_pixwin, slots[bi].larrow_pos.left,
	X			slots[bi].larrow_pos.top, leftarrow->pr_size.x,
	X			leftarrow->pr_size.y, PIX_SRC, leftarrow, 0, 0);
	X		pw_write(main_pixwin, slots[bi].rarrow_pos.left,
	X			slots[bi].rarrow_pos.top, rightarrow->pr_size.x,
	X			rightarrow->pr_size.y, PIX_SRC, rightarrow, 0, 0);
	X	}
	X        pw_write(main_pixwin, slots[bi].slot_pos.left+1, slots[bi].slot_pos.top+1,
	X                dayslot_width-2, dayslot_height-2, PIX_SET, NULL, 0, 0);
	X        pw_text(main_pixwin, slots[bi].slot_pos.left+5, slots[bi].slot_pos.top+font->pf_defaultsize.y,
	X                PIX_NOT(PIX_SRC), font, slot_str);
	X}
	X
	X/* display "more" button if necessary */
	Xmore_check(slotno)
	Xint slotno;
	X{
	X	int x, y, w;
	X
	X	x = morebutton->pr_size.x;
	X	y = morebutton->pr_size.y;
	X
	X	/* clear any previous button that may be there */
	X	pw_write(main_pixwin, slots[slotno].moreb_pos.left, slots[slotno].moreb_pos.top,
	X		x, y, PIX_CLR, NULL, 0, 0);
	X	/* button displayed when more than 1 reference
	X	 * and at least one real appt for this slot.
	X	 */
	X	if (slots[slotno].count > 1 && slots[slotno].first)
	X		/* display more button to right of slot */
	X		pw_write(main_pixwin, slots[slotno].moreb_pos.left, slots[slotno].moreb_pos.top,
	X			x, y, PIX_SRC, morebutton, 0, 0);
	X}
	X
	Xdraw_arrowshaft(i)
	Xint i;
	X{
	X	pw_rop(main_pixwin, slots[i].slot_pos.left+1, slots[i].slot_pos.top+1,
	X	  dayslot_width-2, dayslot_height-2, PIX_SRC|PIX_DST, arrowshaft_pr, 0, 0);
	X	slots[i].active = ARROW_SHAFT;
	X}
	X
	X
	X
	Xdraw_arrowhead(i)
	Xint i;
	X{
	X        pw_rop(main_pixwin, slots[i].slot_pos.left+1, slots[i].slot_pos.top+1,
	X          dayslot_width-2, dayslot_height-2, PIX_SRC|PIX_DST, arrowhead_pr, 0, 0);
	X        slots[i].active = ARROW_HEAD;
	X}
	X
	X/*
	X * Routine to create popup window with future appts shown in it
	X */
	Xdraw_future_appts()
	X{
	X	if (show_future && findex && (ymd_compare(current, today) == 0)) {
	X		create_future_popup();
	X	} else {
	X		/* nothing to show */
	X		/* destroy future appts popup, if it exists */
	X		if (fframe) {
	X			window_destroy(fframe);
	X			fframe = 0;
	X		}
	X	}
	X}
	X
	X/*
	X * Add an appointment entry pointed to by aptr to the day slot
	X * specified by slotno. This routine is also used by paste()
	X * when copying an entry off the save shelf. If dpyflag is true,
	X * then any deactivated slots are cleared on the display (used by
	X * paste). Also used to add a deleted entry for a specific day.
	X */
	Xadd_to_slot(slotno, aptr, dpyflag)
	Xint slotno;
	Xstruct appt_entry *aptr;
	Xint dpyflag;
	X{
	X	struct appt_entry *nappt, *optr;
	X	int n_arrows, n, nbi, found = 0, i;
	X	int deactivate_lower_arrows();
	X
	X	if ((nappt = (struct appt_entry *)malloc(sizeof(struct appt_entry))) == NULL)
	X		err_rpt("out of memory", FATAL);
	X	if (aptr == NULL) {
	X		/* fill in some needed fields */
	X		nappt->arrows = nappt->flags = 0;
	X		nappt->sindex = 0;
	X		nappt->str[0] = '\0';
	X	} else
	X		*nappt = *aptr;
	X	nappt->next = NULL;
	X	/* add appt to list of appts for this slot */
	X	if (slots[slotno].first == NULL) {
	X		slots[slotno].first = nappt;
	X		slots[slotno].cur_appt = nappt;
	X	} else {
	X		/* search for end of list */
	X		for (optr=slots[slotno].first;optr->next;optr=optr->next)
	X			;
	X		optr->next = nappt;
	X	}
	X	/* make sure it doesn't extend too far and truncate if neccessary */
	X	if (slotno >= n_tslots)
	X		nappt->arrows = 0;	/* force notes to have no arrows */
	X	else if ((slotno + nappt->arrows) >= n_tslots)
	X		nappt->arrows = n_tslots - slotno - 1;	/* truncate */
	X	n_arrows = nappt->arrows;
	X	if (nappt->flags & DELETED) {
	X		/* look for matching non-deleted appt in list */
	X		for (optr=slots[slotno].first;optr;optr=optr->next)
	X			if (!strcmp(nappt->str, optr->str) && !(optr->flags & DELETED)) {
	X				found = 1;
	X				break;
	X			}
	X		if (found && slots[slotno].cur_appt == optr) {
	X			/* the deleted appt is the current one */
	X			/* if it's active, undisplay it and display
	X			 * next one in list (if any)
	X			 */
	X			if (slots[slotno].active == ACTIVE) {
	X				if (slots[slotno].count > 1)
	X					/* there's another one here */
	X					next_appt(slotno, dpyflag);
	X				else {
	X					deactivate_slot(slotno, dpyflag);
	X					if (slots[slotno].cur_appt->arrows > 0)
	X						(void)deactivate_lower_arrows(slotno, dpyflag);
	X				}
	X				/* adjust reference counts */
	X				slots[slotno].count--;
	X				i = 1;
	X				while (i <= n_arrows) {
	X					if (--(slots[slotno+i].count) > 0)
	X						/* try to activate any hidden ones */
	X						(void)activate_slot(slotno+i, dpyflag);
	X					++i;
	X				}
	X			} else {
	X				/* currently inactive */
	X				/* set current to next one in the list */
	X				if (optr->next)
	X					slots[slotno].cur_appt = optr->next;
	X				else
	X					slots[slotno].cur_appt = slots[slotno].first;
	X				while (n_arrows >= 0)
	X					slots[slotno+(n_arrows--)].count--;
	X			}
	X		} else {
	X			/* just adjust the counts */
	X			while (n_arrows >= 0)
	X				slots[slotno+(n_arrows--)].count--;
	X		}
	X	} else {
	X		/* look for matching deleted appt in list */
	X		for (optr=slots[slotno].first;optr;optr=optr->next)
	X			if (!strcmp(nappt->str, optr->str) && optr->flags & DELETED) {
	X				found = 1;
	X				break;
	X			}
	X		if (found) {
	X			/* just adjust reference counts and return */
	X			while (n_arrows >= 0)
	X				slots[slotno+(n_arrows--)].count++;
	X			return;
	X		}
	X		/*
	X		 * Make sure there are no overlaps with the appt we
	X		 * are adding. If there are, hide the overlapping appt.
	X		 */
	X		nbi = slotno;
	X		do {
	X			if (slots[nbi].active == ACTIVE) {
	X				deactivate_slot(nbi, dpyflag);
	X				if (slots[nbi].cur_appt->arrows > 0)
	X					nbi = deactivate_lower_arrows(nbi, dpyflag);
	X			} else if (slots[nbi].active != INACTIVE)
	X				nbi = deactivate_lower_arrows(nbi, dpyflag);
	X			while (++nbi <= slotno+n_arrows)
	X				if (slots[nbi].active == ACTIVE)
	X					break;
	X		} while (nbi <= slotno + n_arrows);
	X		/* set current one to the new one */
	X		slots[slotno].cur_appt = nappt;
	X		/* now go back and put in the info for the appt we're inserting */
	X		slots[slotno].active = ACTIVE;
	X		slots[slotno].count++;
	X		if (n_arrows > 0) {
	X			slots[slotno+n_arrows].count++;
	X			slots[slotno+n_arrows].active = ARROW_HEAD;
	X			while (--n_arrows > 0) {
	X				slots[slotno+n_arrows].count++;
	X				slots[slotno+n_arrows].active = ARROW_SHAFT;
	X			}
	X		}
	X	}
	X	if (dpyflag)
	X		draw_day_appts();	/* redraw display */
	X}
	X
	X
	X#ifndef NO_SUN_MOON
	X/*
	X * write sun data to the popup canvas
	X */
	Xwrite_sun_data()
	X{
	X	int	x, y, height;
	X	char	buf[64];
	X	Pixwin	*spixwin;
	X	Rect	*rect;
	X	struct	timeval tp;
	X	double	jdays, secs, offset;
	X	double	julian_day();
	X
	X	/* first erase the window. */
	X	spixwin = (Pixwin *)canvas_pixwin(scanvas);
	X	rect = (Rect *) window_get(scanvas, WIN_RECT);
	X        pw_writebackground(spixwin, 0, 0,
	X	  rect->r_width, rect->r_height, PIX_CLR);
	X
	X	x = font->pf_defaultsize.x;
	X	height = y = font->pf_defaultsize.y;
	X
	X	gettimeofday(&tp, 0);
	X	if (ymd_compare(current, today) == 0) {
	X		/* use current time */
	X		write_times();
	X		panel_set(sdate_pi, PANEL_LABEL_STRING, riseset_buf[B_DMY], 0);
	X		y += 11 * height;
	X	} else {
	X		/* convert today's date to approx. seconds from 1-1-1970 */
	X		jdays = julian_day((double)today.tm_mday, today.tm_mon+1, today.tm_year+1900) - J1970;
	X		/* seconds from 00:00 GMT to now */
	X		offset = tp.tv_sec - (jdays * 24. * 3600.);
	X		/* convert this date to approx. seconds from 1-1-1970 */
	X		jdays = julian_day((double)current.tm_mday, current.tm_mon+1, current.tm_year+1900) - J1970;
	X		/* seconds to the same time on selected day */
	X		secs = (jdays * 24.0 * 3600.) + offset;
	X		riseset((long)secs);
	X		panel_set(sdate_pi, PANEL_LABEL_STRING, riseset_buf[B_DMY], 0);
	X		pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_JLD]);
	X		y += height;
	X	}
	X	sprintf(buf, "Sun Rise    (today): %s", riseset_buf[B_SRD]);
	X	pw_text(spixwin, x, y, PIX_SRC, font, buf);
	X	y += height;
	X	sprintf(buf, "Sun Set     (today): %s", riseset_buf[B_SSD]);
	X	pw_text(spixwin, x, y, PIX_SRC, font, buf);
	X	y += height;
	X	sprintf(buf, "Sun Rise (tomorrow): %s", riseset_buf[B_SRT]);
	X	pw_text(spixwin, x, y, PIX_SRC, font, buf);
	X	y += height;
	X	sprintf(buf, "Sun Set  (tomorrow): %s", riseset_buf[B_SST]);
	X	pw_text(spixwin, x, y, PIX_SRC, font, buf);
	X}
	X
	X/*
	X * write sun time data to the popup canvas
	X */
	Xwrite_times()
	X{
	X	int	x, y, height;
	X	Pixwin	*spixwin;
	X	struct	timeval tp;
	X
	X	/* only update these if displaying today's page */
	X	if (ymd_compare(current, today) != 0)
	X		return;
	X
	X	spixwin = (Pixwin *)canvas_pixwin(scanvas);
	X
	X	x = font->pf_defaultsize.x;
	X	y = height = font->pf_defaultsize.y;
	X
	X	gettimeofday(&tp, 0);
	X	riseset(tp.tv_sec);
	X	pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_GMT]);
	X	y += height;
	X	pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_TDT]);
	X	y += height;
	X	pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_LCT]);
	X	y += height;
	X	pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_LMT]);
	X	y += height;
	X	pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_GST]);
	X	y += height;
	X	pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_LST]);
	X	y += height;
	X	pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_JLD]);
	X	y += height;
	X	pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_LHA]);
	X	y += height;
	X	pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_SDE]);
	X	y += height;
	X	pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_SAZ]);
	X	y += height;
	X	pw_text(spixwin, x, y, PIX_SRC, font, riseset_buf[B_SEL]);
	X}
	X
	X/*
	X * write moon data to the popup canvas
	X */
	Xwrite_moon_data()
	X{
	X	int	x, y, height;
	X	char	buf[64];
	X	Pixwin	*mpixwin;
	X	Rect	*rect;
	X	struct	timeval tp;
	X	double	jdays, secs, offset;
	X	double	julian_day();
	X
	X	/* first erase the window. */
	X	mpixwin = (Pixwin *)canvas_pixwin(mcanvas);
	X	rect = (Rect *) window_get(mcanvas, WIN_RECT);
	X        pw_writebackground(mpixwin, 0, 0,
	X	  rect->r_width, rect->r_height, PIX_CLR);
	X
	X	x = font->pf_defaultsize.x;
	X	y = height = font->pf_defaultsize.y;
	X
	X	gettimeofday(&tp, 0);
	X	if (ymd_compare(current, today) == 0) {
	X		/* use current time */
	X		riseset(tp.tv_sec);
	X		moon_data(tp.tv_sec);
	X	} else {
	X		/* convert today's date to approx. seconds from 1-1-1970 */
	X		jdays = julian_day((double)today.tm_mday, today.tm_mon+1, today.tm_year+1900) - J1970;
	X		/* seconds from 00:00 GMT to now */
	X		offset = tp.tv_sec - (jdays * 24. * 3600.);
	X		/* convert this date to seconds from 1-1-1970 */
	X		jdays = julian_day((double)current.tm_mday, current.tm_mon+1, current.tm_year+1900) - J1970;
	X		/* seconds to the same time on selected day */
	X		secs = (jdays * 24.0 * 3600.) + offset;
	X		riseset((long)secs);
	X		moon_data((long)secs);
	X	}
	X	panel_set(mdate_pi, PANEL_LABEL_STRING, riseset_buf[B_DMY], 0);
	X	y = 6 * height;
	X	sprintf(buf, "Moon Rise    (today): %s", riseset_buf[B_MRD]);
	X	pw_text(mpixwin, x, y, PIX_SRC, font, buf);
	X	y += height;
	X	sprintf(buf, "Moon Set     (today): %s", riseset_buf[B_MSD]);
	X	pw_text(mpixwin, x, y, PIX_SRC, font, buf);
	X	y += height;
	X	sprintf(buf, "Moon Rise (tomorrow): %s", riseset_buf[B_MRT]);
	X	pw_text(mpixwin, x, y, PIX_SRC, font, buf);
	X	y += height;
	X	sprintf(buf, "Moon Set  (tomorrow): %s", riseset_buf[B_MST]);
	X	pw_text(mpixwin, x, y, PIX_SRC, font, buf);
	X}
	X#endif	/* NO_SUN_MOON */
SHAR_EOF
if test 24098 -ne "`wc -c < 'dpaint.c'`"
then
	echo shar: error transmitting "'dpaint.c'" '(should have been 24098 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'holidays.c'" '(9579 characters)'
if test -f 'holidays.c'
then
	echo shar: will not over-write existing file "'holidays.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'holidays.c'
	X/*
	X * $Header: holidays.c,v 2.1 89/05/09 14:19:10 billr Exp $
	X */
	X/*
	X * holidays.c
	X *
	X * Author: Bill Randle, Tektronix, Inc. <billr@saab.CNA.TEK.COM>
	X *	(based on a test driver by R.P.C. Rodgers)
	X *
	X * Copyright (C) 1989, 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 * functions from datelib (by R.P.C. Rodgers)
	X */
	X#include "ct.h"		/* for the NO_HOLIDAYS #define */
	X#ifndef NO_HOLIDAYS
	X
	X#include <sys/time.h>
	X
	Xdouble	election_day();			/* Secular US holidays */
	X
	Xdouble	autumn_equinox(),		/* Astronomical events */
	X	summer_solstice(),
	X	vernal_equinox(),
	X	winter_solstice();
	X
	Xdouble	ascension_day(),		/* Christian holidays */
	X	ash_wednesday(),
	X	corpus_christi(),
	X	easter(),
	X	easter_monday(),
	X	easter_offset(),
	X	first_sunday_advent(),
	X	first_sunday_lent(),
	X	fourth_sunday_lent(),
	X	good_friday(),
	X	maundy_thursday(),
	X	palm_sunday(),
	X	passion_sunday(),
	X	rogation_sunday(),
	X	septuagesima(),
	X	sexagesima(),
	X	quinquagesima(),
	X	second_sunday_lent(),
	X	shrove_monday(),
	X	shrove_tuesday(),
	X	third_sunday_lent(),
	X	trinity_sunday(),
	X	whitsunday();
	X
	Xdouble	islamic_new_year(),		/* Islamic holidays */
	X	muharram_9(),
	X	muharram_10(),
	X	muharram_16(),
	X	eid_i_milad_un_nabi(),
	X	jumada_al_akhir_23(),
	X	shab_e_miraj(),
	X	shab_e_barat(),
	X	shab_e_qadr(),
	X	ramadan(),
	X	eid_al_fitr(),
	X	dhul_hijja_9(),
	X	eid_al_adha(),
	X	ghadir();
	X
	Xdouble	chanukah(),			/* Jewish holidays */
	X	passover(),
	X	passover_offset(),
	X	purim(),
	X	rosh_hashanah(),
	X	shavuot(),
	X	simchat_torah(),
	X	sukkot(),
	X	yom_kippur();
	X
	Xint	check_date();
	X
	Xextern struct tm current;	/* current day displayed from calentool */
	Xint	marked_note;
	X
	Xint
	Xa_dates(appt, flag)
	Xstruct appt_entry *appt;
	Xint flag;
	X{
	X	/*
	X	 * Astromonical Events
	X	 */
	X	if (!flag)
	X		return(0);
	X	marked_note = flag - 1;
	X	if (check_date(appt, "Vernal Equinox", vernal_equinox, TRUE))
	X		return(1);
	X	if (check_date(appt, "Summer Solstice", summer_solstice, TRUE))
	X		return(1);
	X	if (check_date(appt, "Autumn Equinox", autumn_equinox, TRUE))
	X		return(1);
	X	if (check_date(appt, "Winter Solstice", winter_solstice, TRUE))
	X		return(1);
	X	return(0);
	X}
	X
	Xint
	Xc_dates(appt, flag)
	Xstruct appt_entry *appt;
	Xint flag;
	X{
	X	/*
	X	 * Christian holidays
	X	 */
	X	if (!flag)
	X		return(0);
	X	marked_note = flag - 1;
	X	if (check_date(appt, "Septuagesima Sunday", septuagesima, FALSE))
	X		return(1);
	X	if (check_date(appt, "Sexagesima Sunday", sexagesima, FALSE))
	X		return(1);
	X	if (check_date(appt, "Quinquagesima Sunday", quinquagesima, FALSE))
	X		return(1);
	X	if (check_date(appt, "Shrove Monday", shrove_monday, FALSE))
	X		return(1);
	X	if (check_date(appt, "Shrove Tuesday (Mardi Gras)", shrove_tuesday, FALSE))
	X		return(1);
	X	if (check_date(appt, "Ash Wednesday", ash_wednesday, FALSE))
	X		return(1);
	X	if (check_date(appt, "First Sunday in Lent", first_sunday_lent, FALSE))
	X		return(1);
	X	if (check_date(appt, "Second Sunday in Lent", second_sunday_lent, FALSE))
	X		return(1);
	X	if (check_date(appt, "Third Sunday in Lent", third_sunday_lent, FALSE))
	X		return(1);
	X	if (check_date(appt, "Fourth Sunday in Lent", fourth_sunday_lent, FALSE))
	X		return(1);
	X	if (check_date(appt, "Passion Sunday", passion_sunday, FALSE))
	X		return(1);
	X	if (check_date(appt, "Palm Sunday", palm_sunday, FALSE))
	X		return(1);
	X	if (check_date(appt, "Maundy Thursday", maundy_thursday, FALSE))
	X		return(1);
	X	if (check_date(appt, "Good Friday", good_friday, FALSE))
	X		return(1);
	X	if (check_date(appt, "Easter", easter, FALSE))
	X		return(1);
	X	if (check_date(appt, "Easter Monday (Canada)", easter_monday, FALSE))
	X		return(1);
	X	if (check_date(appt, "Rogation Sunday", rogation_sunday, FALSE))
	X		return(1);
	X	if (check_date(appt, "Ascension Day", ascension_day, FALSE))
	X		return(1);
	X	if (check_date(appt, "Whitsunday", whitsunday, FALSE))
	X		return(1);
	X	if (check_date(appt, "Trinity Sunday", trinity_sunday, FALSE))
	X		return(1);
	X	if (check_date(appt, "Corpus Christi", corpus_christi, FALSE))
	X		return(1);
	X	if (check_date(appt, "First Sunday in Advent", first_sunday_advent, FALSE))
	X		return(1);
	X	return(0);
	X}
	X
	Xint
	Xi_dates(appt, flag)
	Xstruct appt_entry *appt;
	Xint flag;
	X{
	X	double day, date1, date2;
	X	int ndates, myear1, myear2=0;
	X	int month, year;
	X	char buf[16];
	X
	X	/*
	X	 * Islamic holidays
	X	 */
	X	if (!flag)
	X		return(0);
	X	marked_note = flag - 1;
	X	if (check_idate(appt, "Muharram 1, %d A.H.: Islamic New Year", islamic_new_year))
	X		return(1);
	X	if (check_idate(appt, "Muharram 9, %d A.H.: Day of fasting", muharram_9))
	X		return(1);
	X	if (check_idate(appt,
	X	    "Muharram 10, %d A.H.: Deliverance of Moses from the Pharoah (for Shia Islam, martyrdom of Husain)", muharram_10))
	X		return(1);
	X	if (check_idate(appt, "Muharram 16, %d A.H. (Imamat Day; Ismaili Khoja)", muharram_16))
	X		return(1);
	X	if (check_idate(appt, "Rabi I 12, %d A.H. (Eid-i-Milad-un-Nabi: The Prophet's Birthday)", eid_i_milad_un_nabi))
	X		return(1);
	X	if (check_idate(appt, "Jumada al-Akhir 23, %d A.H. (Birth of Agha Khan IV, Ismaili)", jumada_al_akhir_23))
	X		return(1);
	X	if (check_idate(appt, "Rajab 27, %d A.H. (Shab-e-Mi'raj: The Prophet's Ascension)", shab_e_miraj))
	X		return(1);
	X	if (check_idate(appt, "Shaban 15, %d A.H. (Shab-e-Bara't: Night, followed by day of fasting)", shab_e_barat))
	X		return(1);
	X	if (check_idate(appt, "Ramadan 1, %d A.H. (Fasting month begins)", ramadan))
	X		return(1);
	X	if (check_idate(appt, "Ramadan 27, %d A.H. (Shab-e-Qadr: Night vigil))", shab_e_qadr))
	X		return(1);
	X	if (check_idate(appt, "Shawwal 1, %d A.H. (Eid-al-Fitr: Day of Feast)", eid_al_fitr))
	X		return(1);
	X	if (check_idate(appt, "Dhul-Hijj 9, %d A.H. (Day of Pilgrimage at Arafat, Mecca)", dhul_hijja_9))
	X		return(1);
	X	if (check_idate(appt, "Dhul-Hijj 10, %d A.H. (Eid-al-Azha: Day of Abraham's Sacrifice)", eid_al_adha))
	X		return(1);
	X	if (check_idate(appt, "Dhul-Hijj 18, %d A.H. (Ghadir: Ali's Nomination)", ghadir))
	X		return(1);
	X	return(0);
	X}
	X
	Xint
	Xj_dates(appt, flag)
	Xstruct appt_entry *appt;
	Xint flag;
	X{
	X	char buf[24];
	X	int jyear;
	X
	X	/*
	X	 * Jewish holidays
	X	 */
	X	if (!flag)
	X		return(0);
	X	marked_note = flag - 1;
	X	if (check_jdate(appt, "Purim", purim))
	X		return(1);
	X	if (check_jdate(appt, "First day of Passover", passover))
	X		return(1);
	X	if (check_jdate(appt, "Shavuot", shavuot))
	X		return(1);
	X	if (check_jdate(appt, "Rosh Hashanah (Jewish New Year)", rosh_hashanah))
	X		return(1);
	X	if (check_jdate(appt, "Yom Kippur", yom_kippur))
	X		return(1);
	X	if (check_jdate(appt, "First day of Sukkot (9 days)", sukkot))
	X		return(1);
	X	if (check_jdate(appt, "Simchat Torah", simchat_torah))
	X		return(1);
	X	if (check_jdate(appt, "First day of Chanukah (8 days)", chanukah))
	X		return(1);
	X	return(0);
	X}
	X
	Xint
	Xs_dates(appt, flag)
	Xstruct appt_entry *appt;
	Xint flag;
	X{
	X	/*
	X	 * SECULAR US HOLIDAYS
	X	 * [Holidays specified as a given date (e.g. July 4) or as
	X	 *  a known nth mday of a month (e.g. 2nd Monday) are not
	X	 *  calculated here.  They are available from one of the
	X	 *  auxillary date files.]
	X	 */
	X	if (!flag)
	X		return(0);
	X	marked_note = flag - 1;
	X	if (check_date(appt, "Election Day", election_day, FALSE))
	X		return(1);
	X	return(0);
	X}
	X
	X/*
	X * check for gregorian (i.e. US secular & Christian) holidays
	X */
	Xint
	Xcheck_date(aptr, str, func, timeflag)
	Xstruct appt_entry *aptr;
	Xchar *str;
	Xdouble (*func)();
	Xint timeflag;
	X{
	X	int	month, year;
	X	double	day, hday;
	X	char 	*julian_time();
	X
	X	hday = (*func)(current.tm_year+1900);
	X	gregorian_date(&day, &month, &year, hday);
	X	if (current.tm_mon == --month && current.tm_mday == (int)day) {
	X		aptr->year = current.tm_year;
	X		aptr->month = current.tm_mon;
	X		aptr->day = current.tm_mday;
	X		aptr->arrows = aptr->repeat = aptr->lookahead = 0;
	X		aptr->flags = (A_NOTE | READONLY);
	X		if (marked_note)
	X			aptr->flags |= MARKED;
	X		strcpy(aptr->str, str);
	X		if (timeflag) {
	X			strcat(aptr->str, julian_time(hday));
	X			strcat(aptr->str, " GMT");
	X		}
	X		return(1);
	X	}
	X	return(0);
	X}
	X
	X/*
	X * check for Islamic holidays
	X */
	Xint
	Xcheck_idate(aptr, str, func)
	Xstruct appt_entry *aptr;
	Xchar *str;
	Xint (*func)();
	X{
	X	double	day, date1, date2;
	X	int	nr_dates, year1, year2;
	X	int	month, year;
	X	int	match = 0;
	X
	X	(void)(*func)(current.tm_year+1900, &nr_dates, &date1, &date2, &year1, &year2);
	X	gregorian_date(&day, &month, &year, date1);
	X	if (current.tm_mon == --month && current.tm_mday == (int)day)
	X		match = 1;
	X	else if (nr_dates == 2) {
	X		gregorian_date(&day, &month, &year, date2);
	X		if (current.tm_mon == --month && current.tm_mday == (int)day)
	X			match = 2;
	X	}
	X	if (match) {
	X		aptr->year = current.tm_year;
	X		aptr->month = current.tm_mon;
	X		aptr->day = current.tm_mday;
	X		aptr->arrows = aptr->repeat = aptr->lookahead = 0;
	X		aptr->flags = (A_NOTE | READONLY);
	X		if (marked_note)
	X			aptr->flags |= MARKED;
	X		if (match == 1)
	X			/* match was on first year */
	X			sprintf(aptr->str, str, year1);
	X		else
	X			/* must have been second year */
	X			sprintf(aptr->str, str, year2);
	X		return(1);
	X	}
	X	return(0);
	X}
	X
	X/*
	X * check for Jewish holidays
	X */
	Xint
	Xcheck_jdate(aptr, str, func)
	Xstruct appt_entry *aptr;
	Xchar *str;
	Xdouble (*func)();
	X{
	X	int	month, year, jyear;
	X	double	hday, day;
	X	char	buf[32];
	X
	X	hday = (*func)(current.tm_year+1900, &jyear);
	X	gregorian_date(&day, &month, &year, hday);
	X	if (current.tm_mon == --month && current.tm_mday == (int)day) {
	X
	X		aptr->year = current.tm_year;
	X		aptr->month = current.tm_mon;
	X		aptr->day = current.tm_mday;
	X		aptr->arrows = aptr->repeat = aptr->lookahead = 0;
	X		aptr->flags = (A_NOTE | READONLY);
	X		if (marked_note)
	X			aptr->flags |= MARKED;
	X		strcpy(aptr->str, str);
	X		sprintf(buf, " [Jewish year %d]", jyear);
	X		strcat(aptr->str, buf);
	X		return(1);
	X	}
	X	return(0);
	X}
	X#endif	/* NO_HOLIDAYS */
SHAR_EOF
if test 9579 -ne "`wc -c < 'holidays.c'`"
then
	echo shar: error transmitting "'holidays.c'" '(should have been 9579 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0