[net.sources] bug fixes for visual-calendar/time-browser recently posted

tims@zeus.UUCP (Tim Stoehr) (05/09/86)

I got a report of a couple bugs which are fixed in the files included
herein.  Pardon the redundancy as this is being posted to both net.sources
and mod.sources.  This is for the 'month' program I recently posted.

#!/bin/sh-----cut here-----cut here-----cut here-----cut here-----
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	display.c #	month.c #	schedule.c 
echo shar: extracting display.c
cat - << \SHAR_EOF > display.c
#include <curses.h>
#include "month.h"

short days;
short crow, ccol;
short current_area;
short message_line_filled;
char *blankout = "                        ";
extern short SCHEDULE_ROW, SKID_ROW;

char *days_of_week =
"Sunday    Monday   Tuesday Wednesday  Thursday    Friday  Saturday";

short schedule_cols[] = {
	0, SMONTH_COL, SDAY_COL, SYEAR_COL, MONTHLY_COL, YEARLY_COL,
	EVERY_COL, NTH_COL, LAST_COL, SMTWTFS_COL,
	SMTWTFS_COL+3, SMTWTFS_COL+6, SMTWTFS_COL+9, SMTWTFS_COL+12,
	SMTWTFS_COL+15, SMTWTFS_COL+18, -1
};

char *month_names[] = {
	"         ",
	"JANUARY  ",
	"FEBRUARY ",
	"MARCH    ",
	"APRIL    ",
	"MAY      ",
	"JUNE     ",
	"JULY     ",
	"AUGUST   ",
	"SEPTEMBER",
	"OCTOBER  ",
	"NOVEMBER ",
	"DECEMBER " ,
	"         "
};

char *smtwtfs_names[] = {
	"Sun",
	"Mon",
	"Tue",
	"Wed",
	"Thu",
	"Fri",
	"Sat",
};

extern short month, day, year, start_day, edit_flag;
extern short this_month, this_day, this_year;
extern struct event_rec current_event;
short first_year;

print_screen()
{
	print_month(month);
	print_year(year);
	print_day_headers();
	print_cal(month, year, 0);
	print_all_months();
	print_all_years(year);
	hl_month_year(month, 1, year, 1);
}

print_month(month)
int month;
{
	mvaddstr(0, 35, month_names[month]);
}

print_year(year)
int year;
{
	char nbuf[8];

	sprintf(nbuf, "%4d", year);
	mvaddstr(0, 47, nbuf);
}

print_day_headers()
{
	mvaddstr(2, 12, days_of_week);
}

print_cal(month, year, all_events_list)
register month, year;
char *all_events_list;
{
	short i, month_is_current, cday;
	short row = 4, col = 13, standing_out = 0;
	char nbuf[6];

	start_day = get_start_day(month, year);
	days = days_in(month, year);
	if (day > days) {
		day = days;
	} else if (day < 1) {
		day = 1;
	}

	month_is_current = ((month == this_month) && (year == this_year));

	for (i = 1, cday = 1; i <= 42; i++) {

		if ((cday <= days) && (i >= (start_day + 1))) {
			if (all_events_list && all_events_list[cday]) {
				sprintf(nbuf, "(%2d)", cday);
			} else {
				sprintf(nbuf, " %2d ", cday);
			}
			cday++;
		} else {
			strcpy(nbuf, "    ");
		}
		if (month_is_current && ((cday-1) == this_day)) {
			standout();
			standing_out = 1;
			month_is_current = 0;
		}
		mvaddstr(row, col, nbuf);

		if (standing_out) {
			standing_out = 0;
			standend();
		}
		if ((i % 7) == 0) {
			row += 2;
			col = 13;
		} else {
			col += 10;
		}
	}
}

print_all_months()
{
	short i;

	standout();
	for (i = 0; i <= 13; i++) {
		mvaddstr(TOP_MONTH_ROW + i, 0, month_names[i]);
	}
	standend();
}

print_all_years(year)
int year;
{
	short i;
	char nbuf[8];

	first_year = year - 4;
	standout();
	move(YEAR_ROW, YEAR_COL);
	addstr("<<");
	for (i = first_year; i < (first_year + 10); i++) {
		sprintf(nbuf, " %4d ", i);
		addstr(nbuf);
	}
	addstr(">>");
	standend();
}

hl_month_year(month, mflag, year, yflag)
short month, mflag, year, yflag;
{
	short i;

	if (mflag != -1) {
		if (!mflag) {
			standout();
		}
		mvaddstr(TOP_MONTH_ROW + month, 0, month_names[month]);
		if (!mflag) {
			standend();
		}
	}
	if (yflag != -1) {
		if (!yflag) {
			standout();
		}
		move(YEAR_ROW, 14 + (6 * (year - first_year)));
		for (i = 0; i < 6; i++) {
			addch(inch());
		}
		if (!yflag) {
			standend();
		}
	}
}

start_display()
{
	goto_day(day);
}

goto_this_day(gmonth, gday, gyear)
int gmonth, gday, gyear;
{
	month = gmonth;
	year = gyear;
	day = gday;

	print_screen();

	switch(current_area) {
	case MONTHS:
		goto_month(month);
		break;
	case DAYS:
		goto_day(day);
		break;
	case YEARS:
		goto_year(year);
		break;
	}
}

goto_month(month)
int month;
{
	crow = TOP_MONTH_ROW + month;
	ccol = 9;
	current_area = MONTHS;
}

goto_day(tday)
short tday;
{
	day = tday;
	get_row_col_from_day(&crow, &ccol, day);
	current_area = DAYS;
}

goto_year(year)
int year;
{
	crow = YEAR_ROW;
	ccol = YEAR_COL + 3 + (6 * (year - first_year));
	current_area = YEARS;
}

goto_schedule()
{
	current_area = SCHEDULE;
	crow = SKID_ROW;
	ccol = MONTHLY_COL;
}

move_cursor(dir)
register short dir;
{
	short mday, row, col;

	if ((current_area != SCHEDULE) &&
	    ((dir == 'm') || (dir == 'y') || (dir == 'd'))) {
		if (dir == 'm') {
			goto_month(month);
		} else if (dir == 'y') {
			goto_year(year);
		} else {
			goto_day(day);
		}
		return;
	}
	switch (current_area) {
	case MONTHS:
		switch(dir) {
		case 'j':
			if (crow <= (TOP_MONTH_ROW + 12)) {
				crow++;
			}
			break;
		case 'k':
			if (crow > TOP_MONTH_ROW) {
				crow--;
			}
			break;
		}
		break;
	case YEARS:
		switch(dir) {
		case 'h':
			if (ccol > YEAR_COL) {
				if (ccol == (YEAR_COL + 3)) {
					ccol = YEAR_COL;
				} else {
					ccol -= 6;
				}
			} else {
				shift_years(-1);
			}
			break;
		case 'l':
			if (ccol < LAST_YEAR_COL) {
				if (ccol == (LAST_YEAR_COL - 6)) {
					ccol = LAST_YEAR_COL;
				} else if (ccol == YEAR_COL) {
					ccol = YEAR_COL + 3;
				} else {
					ccol += 6;
				}
			} else {
				shift_years(1);
			}
			break;
		}
		break;
	case DAYS:

		row = crow;
		col = ccol;

		switch(dir) {
		case 'h':
			if (col > 15) {
				col -= 10;
			}
			break;
		case 'j':
			if (row < 14) {
				row += 2;
			}
			break;
		case 'k':
			if (row > 4) {
				row -= 2;
			}
			break;
		case 'l':
			if (col < 74 ) {
				col += 10;
			}
			break;
		}
		if ((mday = get_day_from_row_col(row, col)) > 0) {
			day = mday;
			crow = row;
			ccol = col;
		}
		break;
	case SCHEDULE:
		schedule_move_cursor(dir);
		break;
	}
}

schedule_move_cursor(dir)
short dir;
{
	short i;

	switch(dir) {
	case 'H':
		if (crow == SKID_ROW) {
			ccol = DATE_COL;
		}
		break;
	case 'L':
		if (crow == SKID_ROW) {
			ccol = SMTWTFS_COL + 18;
		}
		break;
	case 'h':
	case 'l':
		if (crow == SKID_ROW) {
			i = 0;
			while (schedule_cols[++i] != ccol) ;
			i += ((dir == 'h') ? -1 : 1);
			if (schedule_cols[i] != -1) {
				ccol = schedule_cols[i];
			}
		} else if ((crow == TIME_ROW) || (crow == DURATION_ROW)) {
			ccol = (dir == 'h') ? TIME_COL : MINUTE_COL;
		} else if (crow == ACCEPT_ROW) {
			ccol = (dir == 'h') ? ACCEPT_COL : CANCEL_COL;
		}
		break;
	case '\t':
	case '\n':
	case '\r':
		if (crow == SKID_ROW) {
			crow += 2;
			ccol = TIME_COL;
		} else if (crow == DESCRIPTION_ROW) {
			crow = ACCEPT_ROW;
			ccol = ACCEPT_COL;
		} else if (crow == ACCEPT_ROW)  {
			crow = SKID_ROW;
			ccol = MONTHLY_COL;
		} else if (crow == DURATION_ROW) {
			crow = DESCRIPTION_ROW;
			ccol = TIME_COL + strlen(current_event.event_string);
			handle_event_description();
		} else {
			crow++;
		}
		break;
	case '\033':
		goto_day(day);
		break;
	}
}

selection()
{
	short new_year;
	int x;

	switch(current_area) {
		case MONTHS:
			if ((crow - TOP_MONTH_ROW) != month) {
				if (crow <= TOP_MONTH_ROW) {
					hl_month_year(month, 0, 0, -1);
					month = 12;
					shift_years(-1);
					hl_month_year(month, 1, 0, -1);
					crow = TOP_MONTH_ROW + 13;
				} else if (crow > (TOP_MONTH_ROW + 12)) {
					hl_month_year(month, 0, 0, -1);
					month = 1;
					shift_years(1);
					hl_month_year(month, 1, 0, -1);
					crow = TOP_MONTH_ROW;
				} else {
					hl_month_year(month, 0, 0, -1);
					month = crow - TOP_MONTH_ROW;
					hl_month_year(month, 1, 0, -1);
					print_cal(month, year, 0);
				}
				print_month(month);
			}
			break;
		case YEARS:
			if (ccol == YEAR_COL) {
				shift_years(-10);
			} else if (ccol == LAST_YEAR_COL) {
				shift_years(10);
			} else {
				new_year = first_year +
					   ((ccol - (YEAR_COL + 3)) / 6);
				if (new_year != year) {
					hl_month_year(0, -1, year, 0);
					year = new_year;
				}
				print_cal_hl_year(month, year);
			}
			break;
		case SCHEDULE:
			if (crow == SKID_ROW) {
				select_regularity_col(ccol);
			} else if (crow == ACCEPT_ROW) {
				x = (ccol == ACCEPT_COL) ? ACCEPT : CANCEL;
				accept_cancel(ccol == ACCEPT_COL);
				if (edit_flag) {
					return(x);
				}
			} else {
				move_cursor('\t');
			}
			break;
	}
	return(NOTHING);
}

shift_years(shift)
short shift;
{
	if (((year + shift) < (first_year + 10)) &&
	    ((year + shift) >= first_year)) {
		hl_month_year(0, -1, year, 0);
		year += shift;
		hl_month_year(0, -1, year, 1);
	} else {
		year += shift;
		print_all_years(first_year + shift + 4);
	}
	print_cal_hl_year(month, year);
}

print_cal_hl_year(month, year)
int month, year;
{
	print_cal(month, year, 0);
	print_year(year);
	hl_month_year(0, -1, year, 1);
}

get_row_col_from_day(row, col, day)
short *row, *col, day;
{
	*row =  4 + (((start_day + day - 1) / 7) *  2);
	*col = 15 + (((start_day + day - 1) % 7) * 10);
}

get_day_from_row_col(row, col)
short row, col;
{
	short mday;

	mday = (7 * ((row - 4)) / 2) +
	       ((col - 14) / 10) - start_day + 1;

	if ((mday <= days) && (mday > 0)) {
		return(mday);
	}
	return(0);
}

print_event_regularity(event)
struct event_rec *event;
{
	if (event->monthly) {
		standout();
	}
	mvaddstr(SKID_ROW, MONTHLY_COL, "monthly");
	standend();
	if (event->yearly) {
		standout();
	}
	mvaddstr(SKID_ROW, YEARLY_COL, "yearly");
	standend();
	if (event->every) {
		standout();
	}
	mvaddstr(SKID_ROW, EVERY_COL, "every");
	standend();
	print_smtwtfs(event->smtwtfs);
	print_nth(event);
	if (event->last) {
		standout();
	}
	mvaddstr(SKID_ROW, LAST_COL, "last");
	standend();
}

print_smtwtfs(smtwtfs)
char smtwtfs[];
{
	short i;
	char *s;

	move(SKID_ROW, SMTWTFS_COL);

	for (i = 0; i < 7; i++) {
		if (smtwtfs[i]) {
			standout();
		}
		addstr(smtwtfs_names[i]);
		if (smtwtfs[i]) {
			standend();
		}
	}
}

hl_schedule(col, hflag)
register col, hflag;
{
	register int ch;
	short i;

	move(SKID_ROW, col);

	if (hflag) {
		standout();
	}

	if ((col < SMTWTFS_COL) || (col > (SMTWTFS_COL+18))) {
		while((ch = inch()) != ' ') {
			move(SKID_ROW, col);
			addch(ch);
			col++;
		}
	} else {
		move(SKID_ROW, col);

		for (i = 0; i < 3; i++) {
			addch(inch());
		}
	}
	standend();
}

display_event(event)
struct event_rec *event;
{
	clear_schedule_area();
	print_date(event->event_month, event->event_day, event->event_year);
	print_event_regularity(event);
	print_time(event);
	print_duration(event);
	print_event_description(event);
	print_accept();
}

print_accept()
{
	mvaddstr(ACCEPT_ROW, TIME_COL, "Accept/Cancel");
}

print_time(event)
struct event_rec *event;
{
	char buf[32];
	short hour;
	char *apm;

	hour = event->hour;
	apm = (hour < 12) ? "AM" : "PM";

	if (hour > 12) {
		hour = hour % 12;
	}
	if (hour == 0) {
		hour = 12;
	}
	sprintf(buf, "time:  %2d:%02d %s", hour, event->minute, apm);
	mvaddstr(TIME_ROW, 4, buf);
}

print_duration(event)
struct event_rec *event;
{
	char buf[32];

	sprintf(buf, "duration:  %2d:%02d", event->duration_hours,
		event->duration_minutes);
	mvaddstr(DURATION_ROW, 0, buf);
}

print_event_description(event)
struct event_rec *event;
{
	char buf[100];

	sprintf(buf, "event:  %s", event->event_string);
	mvaddstr(DESCRIPTION_ROW, 3, buf);
}

scroll_time(dir)
register dir;
{
	short hour, minute, d;

	if (crow == TIME_ROW) {
		hour = current_event.hour;
		minute = current_event.minute;
	} else if (crow == DURATION_ROW) {
		hour = current_event.duration_hours;
		minute = current_event.duration_minutes;
	} else if (crow != SKID_ROW) {
		return;
	}
	if (ccol == TIME_COL) {
		if (dir == ' ') {
			hour = (hour + 1) % 24;
		} else {
			hour = (hour + 23) % 24;
		}
	} else if (ccol == MINUTE_COL) {
		if (dir == ' ') {
			minute = (minute + 15) % 60;
		} else {
			minute = (minute + 45) % 60;
		}
	} else  {
		if (ccol == SMONTH_COL) {
			current_event.event_month += ((dir == ' ') ? 1 : -1);
			if (current_event.event_month > 12) {
				current_event.event_month = 1;
			} else if (current_event.event_month <= 0) {
				current_event.event_month = 12;
			}
		} else if (ccol == SDAY_COL) {
			d = days_in(current_event.event_month,
			    current_event.event_year);
			current_event.event_day += ((dir == ' ') ? 1 : -1);
			if (current_event.event_day > d) {
				current_event.event_day = 1;
			} else if (current_event.event_day <= 0) {
				current_event.event_day = d;
			}
		} else if (ccol == SYEAR_COL) {
			current_event.event_year += ((dir == ' ') ? 1 : -1);
			if (current_event.event_year < 0) {
				current_event.event_year = this_year;
			}
		} else if (ccol == NTH_COL) {
			current_event.nth += ((dir == ' ') ? 1 : -1);
			if (current_event.nth < 1) {
				current_event.nth = 53;
			} else if (current_event.nth > 53) {
				current_event.nth = 1;
			}
		}
	}
	if (crow == TIME_ROW) {
		current_event.hour = hour;
		current_event.minute = minute;
		print_time(&current_event);
	} else if (crow == DURATION_ROW) {
		current_event.duration_hours = hour;
		current_event.duration_minutes = minute;
		print_duration(&current_event);
	} else if (ccol <= SYEAR_COL) {
		print_date(current_event.event_month,
		    current_event.event_day, current_event.event_year);
	} else if (ccol == NTH_COL) {
		current_event.nth_is_on = 1;
		print_nth(&current_event);

	}
}

hl_all(event, mf, yf, ef, nf, lf, xf)
struct event_rec *event;
register mf, yf, ef, nf, lf, xf;
{
	short i;

	toggle_char(&(event->monthly), mf, MONTHLY_COL);
	toggle_char(&(event->yearly), yf, YEARLY_COL);
	toggle_char(&(event->every), ef, EVERY_COL);
	toggle_char(&(event->nth_is_on), nf, NTH_COL);
	toggle_char(&(event->last), lf, LAST_COL);

	if (xf != -1) {
		for (i = 0; i < 7; i++) {
			toggle_char(&(event->smtwtfs[i]), xf,
			    (SMTWTFS_COL+(3*i)));
		}
	}
}

toggle_char(c, f, col)
char *c;
register f, col;
{
	if (f == 1) {
		if (!(*c)) {
			*c = 1;
			hl_schedule(col, f);
		}
	} else if (!f) {
		if (*c) {
			*c = 0;
			hl_schedule(col, f);
		}
	}
}

print_date(month, day, year)
int month, day, year;
{
	char buf[64];

	standout();
	sprintf(buf, "%2d/%2d/%4d", month, day, year);
	mvaddstr(SKID_ROW, DATE_COL, buf);
	standend();
}

error_message(str, sound)
char *str;
int sound;
{
	mvaddstr(0, 0, blankout);
	mvaddstr(0, 0, str);
	refresh();
	if (sound) {
		sound_bell();
	}
	message_line_filled = 1;
}

sound_bell()
{
	putchar(7);
	fflush(stdout);
}

clear_schedule_area()
{
	move(SCHEDULE_ROW, 0);
	clrtobot();
}

blank_out(col)
int col;
{
	while (col < 35) {
		addch(' ');
		col++;
	}
}
print_nth(event)
struct event_rec *event;
{
	char *ns, buf[10];
	short n;

	if (event->nth_is_on) {
		standout();
	}
	n = event->nth;
	if (event->nth > 13) {
		n %= 10;
	}

	switch(n) {
	case 0:
	case 4:
	case 5:
	case 6:
	case 7:
	case 8:
	case 9:
	case 10:
	case 11:
	case 12:
	case 13:
		ns = "th";
		break;
	case 1:
		ns = "st";
		break;
	case 2:
		ns = "nd";
		break;

	case 3:
		ns = "rd";
		break;
	}
	sprintf(buf, "%02d%s", event->nth, ns);
	mvaddstr(SKID_ROW, NTH_COL, buf);
	standend();
}

remind(str, minutes)
char *str;
int minutes;
{
	char s[50];

	if (minutes > 1) {
		sprintf(s, "In %d minutes", minutes);
	} else if (minutes == 1) {
		strcpy(s, "In 1 minute");
	} else {
		strcpy(s, "Right now");
	}
	printf("\n%s   \n%s.   \n", str, s);
	sound_bell();
}

clear_message_line()
{
	message_line_filled = 0;
	mvaddstr(0, 0, blankout);
}

incr(ch)
int ch;
{
	short inc;

	inc = ((ch == 'n') || (ch == '+')) ? 1 : -1;

	switch (current_area) {
	case MONTHS:
		hl_month_year(month, 0, 0, -1);
		if ((month == 1) && (inc < 0)) {
			shift_years(-1);
			month = 12;
		} else if ((month == 12) && (inc > 0)) {
			shift_years(1);
			month = 1;
		} else {
			month += inc;
		}
		hl_month_year(month, 1, 0, -1);
		print_month(month);
		goto_month(month);
		print_cal(month, year, 0);
		break;
	case DAYS:
		if (((inc > 0) && (day < days)) || ((inc < 0) && (day > 1))) {
			goto_day(day + inc);
		}
		break;
	case YEARS:
		shift_years(inc);
		goto_year(year);
		break;
	}
}
SHAR_EOF
echo shar: extracting month.c
cat - << \SHAR_EOF > month.c
#include <curses.h>
#include <signal.h>
#include <utmp.h>
#include "month.h"

short initialized = 0;
short dhour, dminute, dsecond;
extern short crow, ccol, update_schedule, updating;
extern short this_month, this_day, this_year, SCHEDULE_ROW, SKID_ROW;
extern struct event_rec events;
extern struct mdate mdates[];

main(argc, argv)
int argc;
char *argv[];
{
	check_args(argc, argv);
	initialize();
	print_screen();
	start_display();
	user();
	terminate();
}

initialize()
{
	int blast_out(), i;

	signal(SIGINT, blast_out);
	signal(SIGQUIT, blast_out);
	get_current_date();
	read_schedule();

	for (i = 0; i < 12; i++) {
		mdates[i].month = this_month;
		mdates[i].year = this_year;
	}
	initscr();
	SCHEDULE_ROW = (LINES < 25) ? 17 : 18;
	SKID_ROW = 18;
	initialized = 1;
	crmode();
	noecho();
}

terminate()
{
	if (updating) {
		return;
	}
	signal(SIGINT, SIG_IGN);
	signal(SIGTSTP, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	if (initialized) {
		if (update_schedule) {
			mvaddstr(0, 0, "updating schedule\t");
		} else {
			mvaddstr(0, 0, "schedule unchanged\t");
		}
		refresh();
		if (update_schedule) {
			if (write_schedule() == -1) {
				sound_bell();
				mvaddstr(0, 0, "cannot create .month");
			}
		}
	move(LINES-1, 0);
	clrtoeol();
	refresh();
	endwin();
	}
	exit(0);
}

blast_out()
{
	update_schedule = 0;
	terminate();
}

check_args(argc, argv)
int argc;
char *argv[];
{
	short i, daemon = 0;

	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch(argv[i][1]) {
			case 'd':
				daemon = i;
				break;
			default:
				goto BA;
			}
		} else {
BA:			printf("Bad argument: %s\n", argv[i]);
			terminate();
		}
	}
	if (daemon) {
		if (!fork()) {
			signal(SIGINT, SIG_IGN);
			signal(SIGQUIT, SIG_IGN);
			signal(SIGTSTP, SIG_IGN);
			daemonize();
		}
		exit(0);
	}
}

daemonize()
{
	int do_nothing();
	struct event_rec *eptr;
	short minutes, eminutes, diff, seconds;

	printf("daemon started\n");
	fflush(stdout);
AGAIN:
	get_current_date();
	minutes = (60 * dhour) + dminute;

	seconds = (60 * (15 - (dminute % 15) - 1)) + (60 - dsecond);
	if (seconds < 60) {
		seconds = 900;
	}
	signal(SIGALRM, do_nothing);
	alarm(seconds);
	if (!logged_in()) {
		terminate();
	}
	read_schedule();

	eptr = events.next_event;

	while (eptr) {

		if (event_matches_date(eptr)) {
			eminutes = (((short)60) * ((short)eptr->hour)) +
			    ((short)eptr->minute);
			diff = eminutes - minutes;
			if ((diff >= 0) && (diff <= 15)) {
				remind(eptr->event_string, diff);
			}
		}
		eptr = eptr->next_event;
	}
	pause();
	goto AGAIN;
}

logged_in()
{
	static struct utmp u_buf;
	struct utmp t_buf;
	int fd, retval = 0;
	static short called_before = 0;
	char *ttyname(), *tname;
AGAIN:
	if ((fd = open("/etc/utmp", 0)) < 0) {
		return(0);
	}
	if (!called_before) {
		tname = ttyname(0) + 5;
	}
	while (read(fd, &t_buf, sizeof(struct utmp)) > 0) {
		if (!called_before) {
			if (!strcmp(tname, t_buf.ut_line)) {
				u_buf = t_buf;
				break;
			}
		} else if (byte_comp(&u_buf, &t_buf, sizeof(struct utmp))) {
				close(fd);
				retval = 1;
				break;
		}
	}
	close(fd);
	if (!called_before) {
		called_before = 1;
		goto AGAIN;
	}
	return(retval);
}

do_nothing()
{
}

byte_comp(s1, s2, n)
register char *s1, *s2;
register int n;
{
	short i;

	for (i = 0; i < n; i++) {
		if (*(s1++) != *(s2++)) {
			return(0);
		}
	}
	return(1);
}
SHAR_EOF
echo shar: extracting schedule.c
cat - << \SHAR_EOF > schedule.c
#include <curses.h>
#include "month.h"

struct event_rec events = {0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0},
0, 0, 0, 0, 0, 0, 0, 0, 0};
struct event_rec current_event = {0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0},
1, 0, 0, 10, 0, 1, 0, "", 0};
short update_schedule = 0;
short updating = 0, edit_flag = 0, put_into_schedule, parsed_correctly;
char schedule_file_name[75];
short SCHEDULE_ROW, SKID_ROW;

char *grids[] = {
"mid.  .  .  1a .  .  .  2a .  .  .  3a .  .  .  4a .  .  .  5a .  .  .  6a",
"6a .  .  .  7a .  .  .  8a .  .  .  9a .  .  .  10a.  .  .  11a.  .  .  noon",
"noon  .  .  1p .  .  .  2p .  .  .  3p .  .  .  4p .  .  .  5p .  .  .  6p",
"6p .  .  .  7p .  .  .  8p .  .  .  9p .  .  .  10p.  .  .  11p.  .  .  mid"
};
extern short month, day, year, days;

post_event(month, day, year)
short month, day, year;
{
	goto_schedule();
	current_event.event_month = month;
	current_event.event_day = day;
	current_event.event_year = year;
	display_event(&current_event);
}

read_schedule()
{
	char *getenv(), *malloc(), *s;
	int fd, rec_size;
	struct event_rec event_buf, *event_ptr, *chain_ptr;

	chain_ptr = events.next_event;	/* free old events */
	while (chain_ptr) {
		event_ptr = chain_ptr;
		chain_ptr = chain_ptr->next_event;
		free(event_ptr);
	}
	events.next_event = 0;

	if (!(s = getenv("HOME"))) {
		s = ".";
	}
	strcpy(schedule_file_name, s);
	strcat(schedule_file_name, "/.month");

	rec_size = sizeof(struct event_rec);

	if ((fd = open(schedule_file_name, 0)) != -1) {

		chain_ptr = &events;

		while (read(fd, &event_buf, rec_size) == rec_size) {
			if (event_ptr = (struct event_rec *) malloc(rec_size)) {
				chain_ptr->next_event = event_ptr;
				chain_ptr = event_ptr;
				*chain_ptr = event_buf;
				chain_ptr->next_event = (struct event_rec *)0;
			} else {
				break;
			}
		}
		close(fd);
	}
}

write_schedule()
{
	int fd;
	struct event_rec *chain_ptr;

	updating = 1;

	if ((fd = creat(schedule_file_name, 0640)) == -1) {
		return(-1);
	}
	chain_ptr = events.next_event;

	while (chain_ptr) {
		if (!is_passed_event(chain_ptr)) {
			write(fd, (char *)chain_ptr, sizeof(struct event_rec));
		}
		chain_ptr = chain_ptr->next_event;
	}
	close(fd);
	updating = 0;
	return(0);
}

select_regularity_col(col)
register col;
{
	short i, hflag;

	switch(col) {
	case MONTHLY_COL:
		hl_all(&current_event, (current_event.monthly ? 0 : 1),
		    0, -1, -1, -1, -1);
		break;
	case YEARLY_COL:
		hl_all(&current_event, 0, (current_event.yearly ? 0 : 1),
		    -1, -1, -1, -1);
		break;
	case EVERY_COL:
		hl_all(&current_event, -1, -1,
		   (current_event.every ? 0 : 1), -1, -1, -1);
		break;
	case SMTWTFS_COL:
	case SMTWTFS_COL + 3:
	case SMTWTFS_COL + 6:
	case SMTWTFS_COL + 9:
	case SMTWTFS_COL + 12:
	case SMTWTFS_COL + 15:
	case SMTWTFS_COL + 18:
		i = (col - SMTWTFS_COL) / 3;
		hflag = (current_event.smtwtfs[i] = !current_event.smtwtfs[i]);
		hl_schedule(col, hflag);
		hl_all(&current_event, -1, -1, -1, -1, -1, -1);
		break;
	case NTH_COL:
		hl_all(&current_event, -1, -1, -1,
		    (current_event.nth_is_on ? 0 : 1), -1, -1);
		break;
	case LAST_COL:
		hl_all(&current_event, -1, -1, -1, -1,
		    (current_event.last ? 0 : 1), -1);
		break;
	}
}

accept_cancel(is_accept)
short is_accept;
{
	if (is_accept) {
		accept_current_event();
	} else {
		cancel_current_event();
		display_event(&current_event);
	}
	goto_day(day);
}

accept_current_event()
{
	if ((parse_event(&current_event) != -1)) {
		if (get_answer("Put into schedule? ", "done", "change cancelled")
		    == 'y') {
			if (!edit_flag) {
				link_event(&current_event);
			}
			put_into_schedule = 1;
		}
	}
}

cancel_current_event()
{
	if (!edit_flag) {
		current_event = events;
	}
}

link_event(event)
struct event_rec *event;
{
	struct event_rec *t, *ptr;
	char *malloc();

	if (!(ptr = (struct event_rec *)
	    malloc(sizeof(struct event_rec)))) {
		return;
	}
	*ptr = *event;
	t = events.next_event;
	events.next_event = ptr;
	ptr->next_event = t;
	update_schedule++;
}

parse_event(event)
struct event_rec *event;
{
	short hs;

	hs = has_smtwtfs(event->smtwtfs);

	if ((event->every || event->nth_is_on || event->last) && !hs) {
		error_message("missing day of week", 1);
		return(-1);
	}
	if (hs && !event->every && !event->nth_is_on && !event->last) {
MQ:		error_message("missing qualifier", 1);
		return(-1);
	}
	if (!event->every &&
	    (event->monthly || event->yearly) &&
		(event->nth_is_on || event->last)) {
		error_message("need 'every'", 1);
		return(-1);
	}
	if (event->last && !event->monthly && !event->yearly) {
		error_message("monthly or yearly?", 1);
		return(-1);
	}
	if ((event->nth_is_on || event->last) &&
	    (!event->monthly && !event->yearly && !event->every)) {
		goto MQ;
	}
	parsed_correctly = 1;
	return(0);
}


overview()
{
	short i, j, row, col, hour, minute, duration, n;
	struct event_rec *events_today[MAX_DAILY_EVENTS];
	char *grid;

	get_daily_events(events_today);

	clear_schedule_area();

	for (i = 0; i < 4; i++) {
		mvaddstr((SCHEDULE_ROW + i + i), 1, grids[i]);
	}

	standout();
	i = 0;

	while (events_today[i]) {

		hour = events_today[i]->hour;
		minute = events_today[i]->minute;

		row = SCHEDULE_ROW + ((hour / 6) * 2);

		if (row > (LINES - 1)) {
			break;
		}
		duration = (events_today[i]->duration_hours * 60) +
		    events_today[i]->duration_minutes;
		col = 1 + (12 * (hour % 6)) + (3 * (minute / 15));
		n = hour / 6;
		grid = grids[n];
		duration /= 15;

		move(row, col);

		for (j = 0; j < duration; j++) {
			addch(grid[col - 1]);
			addch(grid[col]);
			addch(grid[col + 1]);

			col += 3;
			if (col > 72) {
				col = 1;
				row += 2;

				if (row > (SCHEDULE_ROW + 6)) {
					row = SCHEDULE_ROW;
				}
				move(row, col);
				grid = grids[++n % 4];
			}
		}
		i++;
	}
	standend();
}

get_daily_events(events_today)
struct event_rec *events_today[];
{
	short i = 0;
	struct event_rec *eptr;

	eptr = events.next_event;

	while (eptr && (i < (MAX_DAILY_EVENTS - 1))) {
		if (event_matches_date(eptr)) {
			if (!events_today) {
				return(1);
			}
			events_today[i++] = eptr;
		}
		eptr = eptr->next_event;
	}
	if (events_today) {
		events_today[i] = 0;
	}
	return(i);
}

scan_today_events()
{
	struct event_rec *events_today[MAX_DAILY_EVENTS];
	short i, j, k, ch, n;

	if ((n = get_daily_events(events_today)) <= 0) {
		error_message("No events this day", 0);
		clear_schedule_area();
		return;
	}
	sort_events(events_today, n);

	for (i = 0; i < n; i++) {
		current_event = *events_today[i];
		display_event(events_today[i]);
GETCH:
		ch = get_npdeq();

		switch(ch) {
		case '\0':
			i--;
			break;
		case '\033':
		case 'q':
			goto OUT;
		case 'n':
			j = i + 1;
			while ((j < n) && (!events_today[j])) {
				j++;
			}
			if (j >= n) {
				/*sound_bell();
				goto GETCH;*/
				goto OUT;
			}
			i = j - 1;
			break;
		case 'p':
			j = i - 1;
			while ((j >= 0) && (!events_today[j])) {
				j--;
			}
			if (j < 0) {
				sound_bell();
				goto GETCH;
			}
			i = j - 1;
			break;
		case 'd':
			delete_event(events_today[i]);
			events_today[i] = 0;
			for (k = i+1; k < n; k++) {
				if (events_today[k] != 0) {
					i = k;
					break;
				}
			}
			if (events_today[i] == 0) {
				for (k = i-1; k >= 0; k--) {
					if (events_today[k] != 0) {
						i = k;
						break;
					}
				}
			}
			if (events_today[i] != 0) {
				i--;
			} else {
				goto OUT;
			}
			break;
		case 'e':
EDIT:		goto_schedule();
			edit_flag = 1;
			parsed_correctly = 0;
			put_into_schedule = 0;
			if (user() == ACCEPT) {
				if (parsed_correctly && put_into_schedule) {
					*events_today[i] = current_event;
					update_schedule++;
				} else if (!parsed_correctly) {
					goto EDIT;
				}
			} else {
				display_event(events_today[i]);
			}
			edit_flag = 0;
			i--;
			break;
		}
	}
OUT:	goto_day(day);
}

scan_every_event()
{
	register short ch;
	struct event_rec *ptr;

	ptr = events.next_event;

	while (ptr) {
		current_event = *ptr;
		display_event(ptr);

		ch = get_nq();

		switch(ch) {
			case 'n':
				ptr = ptr->next_event;
				break;
			case 'q':
				goto RET;
				break;
		}
	}
RET: ;
}

delete_event(event)
struct event_rec *event;
{
	struct event_rec *ptr;

	ptr = &events;

	while (ptr && (ptr->next_event != event)) {
		ptr = ptr->next_event;
	}
	if (ptr) {
		ptr->next_event = ptr->next_event->next_event;
		free((char *)event);
	}
	update_schedule++;
}

sort_events(e, n)
register struct event_rec *e[];
int n;
{
	register struct event_rec *t;
	register i, j;
	short f;

	for (i = 0; i < n; i++) {
		for (j = (n - 1), f = 0; j > 0; j--) {
			if ((e[j]->hour < e[j-1]->hour) ||
			    ((e[j]->hour == e[j-1]->hour) &&
			    (e[j]->minute < e[j-1]->minute))) {
				t = e[j];
				e[j] = e[j-1];
				e[j-1] = t;
				f++;
			}
		}
		if (f == 0) {
			break;
		}
	}
}

show_all_events(month, year)
register month, year;
{
	register struct event_rec *eptr;
	short i;
	char match_list[32];
	short tday;

	tday = day;

	for (i = 1; i <= days; i++) {

		eptr = events.next_event;
		match_list[i] = 0;
		day = i;

		while (eptr) {
			if (event_matches_date(eptr)) {
				match_list[i] = 1;
				break;
			}
			eptr = eptr->next_event;
		}
	}
	day = tday;
	print_cal(month, year, match_list);
}
SHAR_EOF