
/*****************************************************************************

	calend.c	calender program		v1.0
			copywrite: 	Harold Z. Bencowitz
					Beaumont, Texas
					10-mar-87

******************************************************************************

description:

	calender is a program written in whitesmith's C to display the
	calender for the selected month. it will accept and year from
	1983 - 32000. the program has been tested only on a PDP-11/73
	system under TSX+ v6.16. it requires a vt100 or vt200 series
	terminal.

operating instructions:

	run calend month,year
	or
	run calend month year
	or
	calend
	>

	month must be a number 1 - 12. if the year is < 100, 1900 is added
	ie one can enter 1987 or 87. if no month or year is given, the
	current date is used. once the initial calender is displayed,
	the arrow keys are active. up and down will increase and decrease
	the year whereas right and left will increase and decrease the month.
	the program can be terminated by control-c or <delete>. it will not
	run unless the terminal is a vt1** or vt2**.

revision history:

	v1.0 completed		march 10, 1987

installation/building:

	the distribution kit consists of calend.c (source code),
	vt.(c, obj) (video terminal library), hclib (c, obj) (my c library),
	and calend.sav. to compile the Whitesmith's C compiler (and library)
	is needed.

ttt
*****************************************************************************/

#include	<std.h>
#include	<rt11.h>

#define MODE 8
#define ROW 1
#define COL 51
#define ERROR -1
#define DELETE 22

int main(ac, av)

int	ac;
char	**av;

{
	int process(), istsx(), call_emt(), enter(), ttflush(), vtttid();
	int vtesc(), btoi(), instr(), lenstr(), date();
	int d[3], i, k, l;
	unsigned int ijob;
	extern int nmonth, year;
/*
 *		parse command line arguments to month and year
 */
	i = instr(av[1], "=");
	l = lenstr(av[1]) - i - 1;
	k = l - i - 1;
	if(av[1][i] != '\0') {
	   btoi(av[1], i, &year, 10);
	   btoi(&av[1][i+1], k, &nmonth, 10);
	}
	else if(av[1][(i = instr(av[1], ","))] != '\0') {
	   btoi(av[1], i, &nmonth, 10);
	   btoi(&av[1][i+1], k, &year, 10);
	}
	else {
	   date(d);
	   nmonth = d[0];
	   year = d[2];
	}
/*
 *		get day of week of first day of month and number of days
 */
	if(year < 100)
	   year += 1900;
/*
 *		set TSX singlechar mode, find terminal type
 */
	if(istsx())				/* if running TSX+ */
	   i = call_emt(0152, 0, 'S');		/* set singlechar mode */
	if(i < 0) {
       putstr(STDERR,"\ncalender - unable to set singlechar mode\n",NULL);
	   exit();
	}
	i = vtttid();				/* get terminal type */
	if(i != 200) {
    putstr(STDERR,"\ncalender - illegal terminal type, not vt200\n",NULL);
	   exit();
	}
/*
 *		set terminal special mode, arrows to application mode
 */
	ijob = JSW;
	JSW = ijob | 010000;
	vtesc("[?1h");			/* arrow key application mode */
	ttflush();
/*
 *		await keyboard input
 */
	while(enter(&process))		/* respond to keyboard input */
	   ;
/*
 *		reset terminal and JSW
 */
	JSW = ijob;			/* reset JSW */
	vtesc("[?1l");			/* arrow key movement mode */
}

/****************************************************************************/

int cal_display()

{
	static char d_month[]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31};
	char ns[18], ds[31];
	char *cpystr(), *month();
	register int i, j, k;
	static int rowlast = 0;
	int day_1, row, dthismonth;
	int d_of_week(), lenstr(), center_text(), itob(), is_leap();
	extern int year, nmonth;

	if(nmonth < 1) {
	   nmonth = 12;
	   --year;
	}
	if(nmonth > 12) {
	   nmonth = 1;
	   ++year;
	}

	if((day_1 = d_of_week(1, nmonth, year)) < 0) {
	  putstr(STDERR,"\ncalender - month or year out of range\n",NULL);
	   exit();
	}

	if(is_leap(year))
	   d_month[1] = 29;
	else
	   d_month[1] = 28;

	dthismonth = d_month[nmonth-1];

	ds[30] = '\0';
	cpystr(ns, month(nmonth), " ", NULL);
	i = lenstr(ns);
	i += itob(&ns[i], year, 10);
	ns[i] = '\0';
	center_text(ds, ns, 30, ' ');

	row = ROW;
	vtmode(MODE);
	vttxt(row++, COL,   "                              ");
	vttxt(row++, COL, ds);
	vttxt(row++, COL, "                              ");
	vttxt(row++, COL, "  Sun Mon Tue Wed Thr Fri Sat ");
	vttxt(row++, COL, "                              ");

	for(k = 0; k < 30; k++) ds[k] = ' ';

	for(j = 3, i = 1; i <= dthismonth; i++) {
	   if(i == 10)
	      j--;
	   itob(&ds[day_1 * 4 + j], i, 10);
	   if(++day_1 > 6 || i >= dthismonth) {
	      day_1 = 0;
	      vttxt(row++, COL, ds);
	      for(k = 0; k < 30; k++) ds[k] = ' ';
	   }
	}

	vttxt(row, COL,"                              ");
	vtmode(0);

	for(i = 1; i <= rowlast - row; i++)
	   vttxt(row+i, COL,"                              ");
	rowlast = row;

	vtmova(23, 0);
}

/****************************************************************************/

int is_leap(year)	/* given the year, returns YES if it was a leapyear */

int	year;

{
	if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
	   return(YES);
	else
	   return(NO);
}

/****************************************************************************/

int d_of_week(day, nmonth, year) /* determines the day of the week given the
				date. the day of the week is returned as an
integer 0 - 6 for Sunday through Saturday. inappropriate arguments result
in a return of < 0. years must be no earlier than 1583. internally months are
0 - 11, days and years are the true value. */

int	day, nmonth, year;

{
	static char d_month[]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31};
	register int i, dweek, d_this_year;
	int leap_years(), is_leap();

	if(year < 1583 || year > 32000)
	   return(-1);

	nmonth--;
	if(nmonth < 0 || nmonth > 11)
	   return(-2);

	if(is_leap(year))
	   d_month[1] = 29;
	else
	   d_month[1] = 28;

	if(day < 1 || day > d_month[nmonth])
	   return(-3);
/*
 *
 */
	for(d_this_year = 0, i = 0; i < nmonth; i++)
	    d_this_year += d_month[i - 0];
	d_this_year += day;
/*
 *		days this year is the number of days since jan 1 of the
 *	current year. the day of the week is increased one day for every
 *	year except +2 in leap years (thus (year-1583)+nleap) where nleap is
 *	the number of leap years since 1583. jan 1, 1583 was a saturday
 *	(ie day 6).
 */
	dweek = d_this_year + (year - 1583) + leap_years(year) + 5;
	dweek %= 7;

	return(dweek);
}

/****************************************************************************/

int leap_years(year)	/* given the year, returns the number of leap years
			since 1583. */
register int	year;

{
	register int nleap = 0, centuries;
	int is_leap();

	if(year <= 1583)
	   return(0);

	centuries = (year - 1600) / 100;
	nleap = centuries * 24 + (year / 400 - 3); /* 24 per century */
						/* plus one every 400 years */
	if(year >= 1600)		/* number in current century */
	   nleap += ((year % 100) / 4) + 4;	/* 1600 added above */
	else
	   nleap += (year - 1584) / 4 + 1;

	if(is_leap(year))
	   nleap--;

	return(nleap);
}

/****************************************************************************/

int vtesc(s)				/* output string s to STDERR preceded
					by <ESC>. */

char	*s;

{
	int putstr();

	putstr(STDERR, "", s, NULL);
}

/****************************************************************************/

int key()		/* get input from one keyboard key. returns code
			value. */

{
	char c, cc[2], cget();
	int code;
/*
 *
 */
	if((c = cget()) != ESCAPE)
	   switch (c) {
	      case '\177':
	         code = DELETE;
	         break;
	      default:
	         return(ERROR);
           }
	else if((c = cget()) == 'O') {		/* SS3 introducer */
	   c = cget();
	   switch (c) {
	      case 'A':			/* arrows */
	         code = UP;
	         break;
	      case 'B':
	         code = DOWN;
	         break;
	      case 'C':
	         code = RIGHT;
	         break;
	      case 'D':
	         code = LEFT;
	         break;
	      default:
	         return(ERROR);
	   }
	}
	return(code);
}

/****************************************************************************/

int process()			/* process the responses to keystrokes */

{
	int code;
	int key(), leave(), cal_display();
	extern nmonth, year;

	cal_display();
	FOREVER {
	   code = key();
	   if(code == DELETE)
	      leave(NO);
	   else if(code == UP) {
	      ++year;
	      cal_display();
	   }
	   else if(code == DOWN) {
	      --year;
	      cal_display();
	   }
	   else if(code == RIGHT) {
	      ++nmonth;
	      cal_display();
	   }
	   else if(code == LEFT) {
	      --nmonth;
	      cal_display();
	   }
	   else
	      errfmt("");
	}
}

/****************************************************************************/

	int nmonth = 0, year = 0;
