me%pinot@zehntel.UUCP (Mike Essex) (02/20/87)
echo x - README.new sed 's/^X//' >README.new <<'*-*-END-of-README.new-*-*' X VCAL AND FRIENDS 2/19/87 X X------------------------------------------------------------------- XThis is the second release of vcal and friends. XIt has fixed a number of problems and incorporated some suggestions XI recieved in your responses. For the most part I have received Xenthusiastic replies and I thank you for the responses. There Xwere a number of sites who didn't recieve both pieces and some Xwho had pieces truncated. Hopefully, this release will get through Xto all. X XChanges include: X Xvcal - Changed terminal handler routines to take advantage of X termcap(3) capabilites allow vcal to be used with a greater X number of terminal types. Changed start up cursor position X to current date. Fixed several minor bugs. X Xautocall - Fixed a loop bug which was causing core dumps in some X instances. Changed message buffer size. X Xcallme - No change. X Xappts.c - Changed message size so that long messages from a manually X edited data file does not cause a core dump. X Xeappts - Changed message buffer size. X Xlcal - Changed message buffer size. X------------------------------------------------------------------- Xdef.: a set of calendar and appointment utility programs to replace X the traditional paper calendar. X XVcal and friends allow the user to view a calendar, enter dates and Xtimes of activities, set times for prompts to the CRT and to produce Xlists of a month's activities. Multiple data files may be used to Xallow the user to have one calendar for personal activities, one for Xbusiness activities, one for project milestones, etc. X XThese programs are written in 'C' and run under UNIX. To date they Xhave been compiled and execute on the following systems: X XDEC PDP 11/70 UNIX Version 7 XDEC VAX 11/750 UNIX BSD 4.2 and 4.3 XSun 2/170 UNIX BSD 4.2 XSun 3/160 UNIX BSD 4.2 XSun 3/260 UNIX BSD 4.2 XDEC MicroVAX ULTRIX X XIncluded in this package are six source files, six manual files, a Xmakefile and this introduction. The makefile is for use with the Xstandard "make" utility on a VAX 11/750 under BSD 4.3. For use with Xa PDP 11/70 BSD Version 7 change the makefile library entry from X"termlib" to "termcap". X XAll the "vcal" files have been combined here with the "shar" script. XSince the combined size of the files are greater than 65,000 Xcharacters they have been broken into two parts for transmission. XPart 1 contains makefile, appts.c, autocall.c and callme.c along Xwith the manual pages for these. Part 2 contains eappts.c, lcal.c Xand vcal.c and their manual pages. X XSynopsis of files: X Xappts displays the current or specified day's activities X Xautocall starts background reminder processes for each of the X current day's activities X Xcallme starts a background reminder process for a specified X time and activity X Xeappts allows activities to be entered into a data file from X the command line X Xlcal produces a tabular listing of the current or specified X month's activities X Xvcal visual calendar displaying the current or specified X month's activities; allows entries to be added, changed X or deleted X Xmakefile makefile for all of the "vcal" programs X Xmanual pages: appts.l autocall.l callme.l eappts.l lcal.l vcal.l X XComments and suggestions will be appreciated and considered. X XMike Essex (~me) X X ....!ucbvax!zehntel!me X ....!decvax!sytek!zehntel!me X ...."zehntel!me"@BERKELEY *-*-END-of-README.new-*-* echo x - eappts.c sed 's/^X//' >eappts.c <<'*-*-END-of-eappts.c-*-*' X/* X * Module: eappts.c X * X * Purpose: enters data into appointments file X * X * Author: Mike Essex X * X * Date: Sep. 16, 1986 X * X * Includes: X * stdio.h X * Discussion: X * Inputs data from standard input and writes it to ~/.appointments X * file X * X * X * Edit History X * ==== ======= X * X * Date Who What X * ---- --- ---------------------------------------------- X * 12/1/86 me added multifile capability X * 12/1/86 me changed 'home' from *home[80] to home[80] X * X */ X X#include <stdio.h> X#define NL '\010' X X X/* X * Procedure: main X * X * Function: inputs data and writes to users .appointments file X * X * Discussion: X * Prompts users for required appointment information, inputs X * that info and then appends it to ~/.appointments file. X */ X Xmain(argc,argv) X Xint argc; Xchar *argv[]; X X{ X FILE *fptr; X char tmpbuf[80]; X int i,j; X char *getenv(); X char home[80]; X char datedata[20]; X char timedata[20]; X char msgdata[40]; X int month,day,year,time; X int index[5]; X X if (argc == 2) { X strcpy(home,argv[1]); X } X else { X strcpy(home,getenv("HOME")); X strcat(home,"/.appointments"); X } X X fptr = fopen(home,"a"); X if (fptr) { X printf("What is the date of appointment? (mm dd yyyy) "); X fgets(datedata,20,stdin); X i = 0; X j = 0; X while(i < 20) { X while ((i < 20) && (datedata[i] == ' ')) i++; X index[j++] = i; X while ((i < 20) && (datedata[i] != ' ')) i++; X } X month = atoi(&datedata[index[0]]); X day = atoi(&datedata[index[1]]); X year = atoi(&datedata[index[2]]); X if (year < 100) year += 1900; X X printf("What time (24 hour time) is the appointment? (tttt) "); X fgets(timedata,20,stdin); X time = atoi(timedata); X printf("What is the message? "); X fgets(msgdata,79,stdin); X msgdata[strlen(msgdata)-1] = NULL; X fprintf(fptr,"%d,%d,%d,%4d,%s\n",month,day,year,time,msgdata); X } X else { X printf("Error: Cannot open %s file",argv[1]); X abort(); X } X fclose(fptr); X} /* main */ *-*-END-of-eappts.c-*-* echo x - eappts.l sed 's/^X//' >eappts.l <<'*-*-END-of-eappts.l-*-*' X.TH EAPPTS 1 X.SH NAME Xeappts \- enter appointments X.SH SYNOPSIS X.B eappts [ filename ] X.SH DESCRIPTION X.I Eappts Xis a program which is used to enter appointment data into the user's X~/.appointments file by default or the file specified in the optional Xfilename argument. X.PP XThe user is prompted for a date, time and message. XThe date is entered as three numeric values separated by spaces. XA two or four digit year value should be used. X.PP XData entered using X.I eappts Xmay be used by four companion programs. XThese are: X.br X.sp X.nf Xvcal calendar and notes program Xappts displays current or seleted day's appoinments Xautocall set appointment reminders for the current day Xlcal displays the month's appointments in tabular form X.fi X.sp XFor further information on these, reference the appropriate "man" Xentries. X.SH AUTHOR XMike Essex X.SH FILES Xeappts X.br X~/.appointments X.br X.SH "SEE ALSO" Xvcal(1), appts(1), autocall(1), lcal(1), callme(1) X.SH BUGS XThere are year 2000 time bombs. *-*-END-of-eappts.l-*-* echo x - lcal.c sed 's/^X//' >lcal.c <<'*-*-END-of-lcal.c-*-*' X/* X * Module: lcal.c X * X * Purpose: print month's appointments X * X * Author: Mike Essex X * X * Date: Sep. 16, 1986 X * X * Includes: X * time.h, stdio.h, ctype.h, signal.h X * X * Discussion: X * Reads data from ~/.appointments and/or designated file and X * writes to standard * out any appoinments which fall in X * the current or optionally specified month. X * X * X * Edit History X * ==== ======= X * X * Date Who What X * ---- --- ---------------------------------------------- X * X */ X X#include <stdio.h> X#include <signal.h> X#include <ctype.h> X#include <time.h> X X Xchar *malloc(); X Xint monthdata[1000]; /* month data */ Xint daydata[1000]; /* month data */ Xint yeardata[1000]; /* month data */ Xchar *msgdata[1000]; /* message pointers */ Xchar msghold[40]; Xint maxentries; Xint maxmsgs; Xint cmonth,cday,cyear; Xint argvindex; X X X X/* X * Procedure: main() X * X * Function: prints out listing of appointments X * X * Discussion: X * Parses command line for optional month and year, initializes X * varialbes, calls required funtions. X */ X Xmain (argc,argv) X X int argc; X char *argv[]; X{ X X int month,day,year; X int i; X int tempmonth,tempyear; X int atoi(); X int maxindex; X extern int abort(); X X timeset(); X year = cyear; X month = cmonth; X day = cday; X X if (argc > 2) { X tempmonth = atoi(argv[1]); X tempyear = atoi(argv[2]); X if (tempmonth && tempyear){ X month = tempmonth; X year = tempyear; X if (year < 100) year += 1900; X if (argc > 3) { X argvindex = 3; X maxindex = argc; X } X else { X argvindex = 0; X maxindex = 1; X } X } X else { X if (tempmonth || tempyear) { X printf("Syntax error: Incorrect date arguments\n"); X exit(1); X } X else { X argvindex = 1; X maxindex = argc; X } X } X } X else { X if (argc == 1) { X argvindex = 0; X maxindex = argc; X } X else { X argvindex = 1; X maxindex = argc; X } X } X X X signal(2,abort); X signal(3,abort); X X day = 1; X maxentries = 1000; X maxmsgs = 18; X msghold[0] = NULL; X X printf(" C A L E N D A R L I S T\n"); X while (argvindex < maxindex) { X loaddata(argv[argvindex]); X table(month,day,year,argv[argvindex]); X argvindex++; X } X X printf("------------------------------------------------------------------------------\n"); X} /* main */ X X X/* X * Procedure: abort() X * X * Function: error exit routine X */ X Xabort() X X{ X exit(1); X} /* abort */ X X X/* X * Procedure: table(month,day,year) X * X * Function: outputs appointments in tabular format X * X * Parameters: X * p1 - int - month X * p2 - int - day X * p3 - int - year X * p3 - char * - file name X * X * Discussion: X * Searches data arrays for appointments in the specified X * month and year and outputs them in tabular form to standard out. X */ X Xtable(month,day,year,filename) X X int month,day,year; X char *filename; X X{ X int i,j,k,d,dow,monthday,searchcnt,first; X int getdow(); X X static char *dayw[]= { X "Sat ","Sun ","Mon ", "Tue ", X "Wed ", "Thu ", "Fri " X }; X X static char *smon[]= { X "JANUARY ", "FEBRUARY ", "MARCH ", "APRIL ", X "MAY ", "JUNE ", "JULY ", "AUGUST ", X "SEPTEMBER ", "OCTOBER ", "NOVEMBER ", "DECEMBER " X }; X X printf("------------------------------------------------------------------------------\n"); X if (argvindex) { X printf("| %-10.10s%u %30.30s |\n", smon[month-1], year,filename); X } X else { X printf("| %-10.10s%u |\n", smon[month-1], year); X } X monthday = 0; X while (++monthday <= 31) { X searchcnt = 0; X first = 1; X while (searchcnt <= maxentries) { X if ((yeardata[searchcnt] == year) && X (monthdata[searchcnt] == month) && X (daydata[searchcnt] == monthday)) { X if (first) { X dow = getdow(month,monthday,year); X first = 0; X /* printf("|----------------------------------------------------------------------------|\n"); */ X printf("| |\n"); X printf("| %-7.7s%2d %-64.64s|\n",dayw[dow],monthday,msgdata[searchcnt]); X } X else { X printf("| %-64.64s|\n",msgdata[searchcnt]); X } X } X searchcnt++; X } X } X} /* table */ X X X/* X * Procedure: getdow(tmonth,tday,tyear) X * X * Function: calculates day of week X * X * Parameters: X * p1 - int - month X * p2 - int - day X * p3 - int - year X * X * Return Values: X * interger value of day of week, sat=0, . . ., etc X * X * Discussion: X * calculates number of days from 1,1,1979 and determines dow X */ X Xgetdow(tmonth,tday,tyear) X X int tmonth,tday,tyear; X{ X X static int mdays[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; X int month,day,year,mcnt; X long days; X int tdow; X X month = 1; X day = 1; X year = 79; X X if ((tmonth == month) && (tyear == year)) { X days = abs(day - tday); X } X else { X days = mdays[month] - day; X if (tyear == year) { X while (++month < tmonth) { X days += mdays[month]; X if ((month == 2) && ((year % 4) == 0)) days++; X } X } X else { X while (++month < 13) { X days += mdays[month]; X if ((month == 2) && ((year % 4) == 0)) days++; X } X while (++year < tyear) { X days += 365; X if ((year % 4) == 0 ) days ++; X } X X mcnt = 0; X while (++mcnt < tmonth) { X days += mdays[mcnt]; X if ((mcnt == 2) && ((tyear % 4) == 0)) days++; X } X } X days += tday; X } X X tdow = (days%7); X X return(tdow); X} /* get dow */ X X X/* X * Procedure: loaddata() X * X * Function: loads appointment data from ~/.appointments file X * X * Return Values: X * various global arrays loaded with appointment data X * X */ X Xloaddata(filename) X Xchar *filename; X X{ X char basedata[80]; X char tmpbuf[80]; X char *getenv(); X char home[80]; X FILE *fptr; X int i,j,k,l,field; X X i = 0; X while (i < maxentries) { X daydata[i] = 0; X monthdata[i] = 0; X yeardata[i] = 0; X msgdata[i] = 0; X i++; X } X X X if (argvindex == 0) { X strcpy(home,getenv("HOME")); X strcat(home,"/.appointments"); X } X else { X strcpy(home,filename); X } X if ((fptr = fopen(home,"r")) != NULL) { X i = 0; X while((fgets(basedata,80,fptr) != NULL)) { X X basedata[strlen(basedata)-1] = NULL; X X j = 0; X k = 0; X field = 0; X while (basedata[j] != NULL ) { X X if (basedata[j] != ',') { X X tmpbuf[k++] = basedata[j]; X } X else { X switch (field) { X X case 0 : { X tmpbuf[k] = NULL; X monthdata[i] = atoi(tmpbuf); X k = 0; X break; X } X case 1 : { X tmpbuf[k] = NULL; X daydata[i] = atoi(tmpbuf); X k = 0; X break; X } X case 2 : { X tmpbuf[k] = NULL; X yeardata[i] = atoi(tmpbuf); X k = 0; X break; X } X case 3 : { X tmpbuf[k++] = ' '; X tmpbuf[k++] = ' '; X break; X } X } X field++; X } X j++; X } X tmpbuf[k] = '\0'; X msgdata[i] = malloc(80); X strncpy(msgdata[i],tmpbuf,80); X msgdata[79] = NULL; X X if (i >= maxentries) { X printf("Warning: Over 1000 entries in %s file. Data truncated.\n",filename); X break; X } X i++; X } X fclose(fptr); X } X else { X printf("Error: Cannot open %s file.\n",filename); X } X} /* loaddata */ X X X/* X * Procedure: timeset() X * X * Function: Gets current time and date X * X * Return Values: X * loads time and date info into global variables X * X */ X Xtimeset() X X{ X struct tm *localtime(); X X struct tm *tp; /* time structure */ X long tloc; /* number of seconds since 1970 */ X X time(&tloc); /* fills tloc */ X X tp = localtime(&tloc); X X cyear = tp->tm_year; X cmonth = tp->tm_mon + 1; X cday = tp->tm_mday; X X cyear += 1900; X X} /* timeset */ *-*-END-of-lcal.c-*-* echo x - lcal.l sed 's/^X//' >lcal.l <<'*-*-END-of-lcal.l-*-*' X.TH LCAL 1 X.SH NAME Xlcal \- display current or selected month's appointments X.SH SYNOPSIS X.B lcal X[ month year ] [ filename(s) ] X.sp Xwhere X.I month Xis a numeric value between 1 and 12, X.I year Xis a numeric four digit value and X.I filename(s) Xare the data files to be searched. X.SH DESCRIPTION X.I Lcal Xis a program which uses the data stored by "vcal" or "eappts" to Xdisplay the user's appointments to standard out. X.PP XWhen an argument is present, X.I lcal Xwill display appointments for the requested month and year. XThe default argument values are the current month and year. XIf no filename is specified ~/.appointments will be searched. XIf one or more filenames arguments are used those files will Xbe searched. X.SH AUTHOR XMike Essex X.SH FILES Xlcal X.br X~/.appointments X.br X.SH "SEE ALSO" Xvcal(1), appts(1), eappts(1), autocall(1), callme(1) X.SH BUGS XThere are year 2000 time bombs. *-*-END-of-lcal.l-*-* echo x - vcal.c sed 's/^X//' >vcal.c <<'*-*-END-of-vcal.c-*-*' X/* X * Module: vcal.c X * X * Purpose: visual appointment calendar X * X * Author: Mike Essex X * X * Date: Sep. 16, 1986 X * X * Includes: X * time.h, stdio.h, ctype.h, signal.h X * X * Discussion: X * displays a calendar to the screen for the current or optionally X * specified month. User may move the cursor any day of the month X * and view or enter appointments for that date. X * X * X * Edit History X * ==== ======= X * X * Date Who What X * ---- --- ---------------------------------------------- X *11/25/86 me added multiple data file capability X *11/25/86 me fixed array "home" from *home[80] to home[80] X *11/25/86 me fixed "space" and "area" to be global X *11/26/86 me changed help message routines X * 2/06/86 me changed calendar header from printing a default X * NULL for .appointments file to not printing X *02/19/86 me reworked terminal handler to make correct use X * of termcap(3) functions for greater terminal X * portability. modified so that cursor comes to X * current day of month on startup. Fixed minor X * bugs and changed a few messages. X * X */ X X#include <stdio.h> X#include <signal.h> X#include <ctype.h> X#include <time.h> X#include <sgtty.h> X X#define LF '\012' X#define BS '\010' X#define ESC '\033' X Xint mon[] = { X 0, X 31, 29, 31, 30, X 31, 30, 31, 31, X 30, 31, 30, 31, X}; X Xint tputc(); /* termcap dependent output */ Xchar space[BUFSIZ]; /* used by area */ Xchar *area = space; /* termcap required variable */ Xchar *BC; /* backspace string pointer */ Xchar *backstring = "\b"; /* backspace string */ Xchar PC; /* number pad characters */ Xchar *UP; /* cursor up string */ Xextern short ospeed; /* output speed */ Xchar *CM; /* cursor motion */ Xchar *CL; /* clear screen */ Xchar *TI; /* begin cm */ Xchar *TE; /* end cm */ Xchar *SO; /* standout*/ Xchar *SE; /* end standout*/ Xchar *tgoto(); Xchar *malloc(); Xchar tcolumns = 0; /* terminal columns */ Xchar tlines = 0; /* terminal lines */ X Xint xposition[32]; /* calendar x axis position */ Xint yposition[32]; /* calendar y axis position */ Xint active[33]; /* highlight day array */ X Xint monthdata[1000]; /* month data */ Xint daydata[1000]; /* month data */ Xint yeardata[1000]; /* month data */ Xchar *msgdata[1000]; /* message pointers */ Xchar msghold[80]; Xint dayindex[18]; /* index to day's msgs */ Xint maxentries; Xint maxmsgs; Xint tmonth,tday,tyear; X Xint maxchars; Xint notclear; Xint help1,help2; /* help message flags */ X Xchar dayw[] = { X " S M T W T F S " X}; X Xchar *smon[]= { X "JANUARY ", "FEBRUARY ", "MARCH ", "APRIL ", X "MAY ", "JUNE ", "JULY ", "AUGUST ", X "SEPTEMBER ", "OCTOBER ", "NOVEMBER ", "DECEMBER ", X}; X X X X/* X * Procedure: main(argv[1],argv[2],argv[3]) X * X * Function: Front end for calendar program X * X * Parameters: X * p1 - character pointer - optional month X * p2 - character pointer - optional year X * p3 - character pointer - optional data file name X * X * Discussion: X * This module parses command line, intializes variables and calls X * init functions. It then drops into a character interpreter X * loop, taking input from standard in. Each input either changes X * cursor position or invokes a function. X */ X Xmain (argc,argv) X X int argc; X char *argv[]; X{ X X int month,day,year; X char key; X char *datafile; X extern int abort(); X int i; X X datafile = NULL; X day = 1; X if (argc == 1) { X timeset(); X month = tmonth; X day = tday; X year = tyear; X } X else { X if (argc == 3) { X month = atoi(argv[1]); X year = atoi(argv[2]); X if (year < 100) year += 1900; X if (!month || !year) { X printf("Syntax Error: non-numeric argument\n"); X abort(1); X } X } X else { X if (argc == 2) { X timeset(); X month = tmonth; X day = tday; X year = tyear; X datafile = argv[1]; X } X else { X if ( argc == 4) { X month = atoi(argv[1]); X year = atoi(argv[2]); X if (year < 100) year += 1900; X if (!month || !year) { X printf("Syntax Error: non-numeric argument\n"); X abort(1); X } X datafile = argv[3]; X } X else { X printf("Syntax Error: incorrect number of arguments\n"); X abort(1); X } X } X } X } X signal(2,abort); X signal(3,abort); X X system("stty cbreak -echo"); X X tinit(); X tputs(TI,1,tputc); X maxchars = 38; X maxentries = 1000; X maxmsgs = 18; X msghold[0] = NULL; X help1 = 0; X help2 = 0; X X loaddata(datafile); X cal(month,day,year,datafile); X movcur(day); X X key = 'a'; X while (key != LF) { X X key = getchar(); X X switch (key) { X X case 'H' : X X helpcal(); X X break; X X case 'p' : X X if (--month < 1) { X month = 12; X year--; X } X day = 1; X notclear = 0; X cal(month,day,year,datafile); X X break; X X case 'n' : X X if (++month == 13) { X month = 1; X year++; X } X day = 1; X notclear = 0; X cal(month,day,year,datafile); X X break; X X case 'h' : X X if (--day <= 0) { X day = mon[month]; X } X if (notclear) { X clearmsgs(); X } X X break; X X case 'l' : X X if (++day > mon[month]) { X day = 1; X } X if (notclear) { X clearmsgs(); X } X X break; X X case 'j' : X X if ((day += 7) > mon[month]) { X day = day % 7; X if (day == 0) { X day = 7; X } X } X if (notclear) { X clearmsgs(); X } X X break; X X case 'k' : X X if ((day -= 7) <= 0) { X day += 35; X if (day > mon[month]) { X day -= 7; X } X } X if (notclear) { X clearmsgs(); X } X X break; X X case 'e' : X X day = mon[month]; X if (notclear) { X clearmsgs(); X } X X break; X X case 'b' : X X day = 1; X if (notclear) { X clearmsgs(); X } X X break; X X case 'c' : X X clearday(month,day,year); X X break; X X case ' ' : X X notes(month,day,year); X X break; X X case 'm' : X X modnotes(month,day,year); X X break; X X X } X movcur(day); X } X closefile(datafile); X tputs(TE,1,tputc); X system("stty -cbreak echo"); X if (help1 || help2) { X helpclr(); X } X mov(1,24); X} /* main */ X X X/* X * Procedure: <routine name> X * X * Function: abort() X * X * Discussion: X * Reset tty parameters and exits with an error code. X */ X Xabort() X X{ X system("stty -cbreak echo"); X tputs(SE,1,tputc); X if (help1 || help2) { X helpclr(); X } X mov(1,24); X tputs(TE,1,tputc); X exit(1); X} /* abort */ X X X X/* X * Procedure: cal(month,day,year,datafile) X * X * Function: produces the visual calendar to the screen X * X * Parameters: X * p1 - int - month X * p2 - int - day X * p3 - int - year X * p4 - char * - datafile name X * X * Discussion: X * Calculates current months parameters, such as, starting X * day of week, number of days and days on which there are X * appointments. This data is then used to draw a calendar X * to the screen. X */ X Xcal(month,day,year,datafile) X X int month,day,year; X char *datafile; X X{ X int i,j,k,d; X X tputs(CL,24,tputc); X if (datafile == NULL) { X printf("V I S U A L C A L E N D A R\n"); X } X else { X printf("V I S U A L C A L E N D A R\t\t%s\n",datafile); X } X printf("-------------------------------------------------------------------------------\n"); X printf("\t\t\t\t%s%u\n", smon[month-1], year); X printf("-------------------------------------------------------------------------------\n\n"); X printf("%s\n\n", dayw); X X X d = jan1(year); X mon[2] = 29; X mon[9] = 30; X X X i = 1; X while (i <= 32) { X active[i++] = 0; X } X X i = 0; X while (i < maxentries) { X if ((yeardata[i] == year) && (monthdata[i] == month) ) { X active[daydata[i]] = 1; X } X i++; X } X X switch((jan1(year+1)+7-d)%7) { X X /* X * non-leap year X */ X case 1: X mon[2] = 28; X break; X X /* X * 1752 X */ X default: X mon[9] = 19; X break; X X /* X * leap year X */ X case 2: X ; X } X X /* calculate days from beginning of year */ X X for(i=1; i<month; i++) { X d += mon[i]; X } X X d %= 7; X i = 0; X X /* inset to first day of week position */ X X while (i++ < (5*d)) { X printf(" "); X } X X k = 0; X i = d; X X for (j=1;j<=31;j++) { X xposition[j] = (i*5) + 2; X yposition[j] = (k*2) + 7; X if (++i == 7) { X i = 0; X k++; X } X } X X for(i=1; i<=mon[month]; i++) { X if(i==3 && mon[month]==19) { X i += 11; X mon[month] += 11; X } X if (active[i]) { X if(i > 9) { X printf(" "); X tputs(SO,1,tputc); X printf("%d",i/10); X tputs(SE,1,tputc); X } X else { X printf(" "); X tputs(SO,1,tputc); X printf(" "); X tputs(SE,1,tputc); X } X tputs(SO,1,tputc); X printf("%d",i%10); X tputs(SE,1,tputc); X if (*SO == NULL) { X printf("* "); X } X else { X printf(" "); X } X } X else { X if(i > 9) { X printf(" %d",i/10); X } X else { X printf(" "); X } X printf("%d ",i%10); X } X X if(++d == 7) { X d = 0; X printf(" \n\n"); X } X } X X helpclr(); X X mov(42,5); X printf ("TIME MESSAGE"); X} /* cal */ X X X/* X * Procedure: jan1(year) X * X * Function: calculates day of week of Jan 1 on specified year X * X * Parameters: X * p1 - int - year X * X * Return Values: X * integer representation day of the week X */ X Xjan1(year) X X int year; X{ X X register y, d; X/* X * normal gregorian calendar X * one extra day per four years X */ X X y = year; X d = 4+y+(y+3)/4; X X/* X * julian calendar X * regular gregorian X * less three days per 400 X */ X X if(y > 1800) { X d -= (y-1701)/100; X d += (y-1601)/400; X } X X/* X * great calendar changeover instant X */ X X if(y > 1752) X d += 3; X X return(d%7); X} /* jan1 */ X X X X/* X * Procedure: movcur(day) X * X * Function: moves the cursor to the specified day's position X * X * Parameters: X * p1 - int - day X * X * Discussion: X * uses termcap values to move the cursor to a matrix position X * stored in a global array X */ X Xmovcur(day) X X int day; X{ X tputs( tgoto( CM, xposition[day],yposition[day]), 1, tputc ); X} /* movcur */ X X X/* X * Procedure: setday(day) X * X * Function: places day in calendar display with appointment X * days highlighted X * X * Parameters: X * p1 - int - day X * X * Discussion: X * Uses day arguement, termcap values and calendar position X * matrices to write a day to the screen with days with appointment X * days highlighted. X */ X Xsetday(day) X X int day; X{ X tputs( tgoto( CM, xposition[day]-1,yposition[day]), 1, tputc ); X if (active[day]) { X if(day > 9) { X tputs(SO,1,tputc); X printf("%d",day/10); X tputs(SE,1,tputc); X } X else { X tputs(SO,1,tputc); X printf(" "); X tputs(SE,1,tputc); X } X tputs(SO,1,tputc); X printf("%d",day%10); X tputs(SE,1,tputc); X if (*SO == NULL) { X printf("*"); X } X else { X printf(" "); X } X } X else { X if(day > 9) { X printf("%d",day/10); X } X else { X printf(" "); X } X printf("%d ",day%10); X } X} /* setday */ X X X X/* X * Procedure: tinit() X * X * Function: gets termcap entries X * X * Return Values: X * loads global variables with termcap parameters X * X * Discussion: X * Initial various termcap variables so that they can later X * be used to move the cursor and highlight certain displays. X */ X Xtinit() /* termcap initalization */ X X{ X struct sgttyb speed; X X char term[BUFSIZ]; /* holds termcap entry */ X char name[16]; /* terminal name */ X char *np; /* termcap name pointer */ X char *NADA = { "\0" }; /* null string */ X char *tgetstr(); X char *getenv(); X X if( (np = getenv( "TERM" )) != NULL ) { X strncpy( name, np, 16 ); X } X else { X printf("TERM environment variable does not exist\n"); X abort(); X } X X if( tgetent( term, name ) != 1 ) { X printf("Termcap for %s does not exist\n",name); X abort(); X } X X /* if a capability does not exist, point it to a null X * string not NULL X */ X X gtty(stdout,&speed); X ospeed = speed.sg_ospeed; X X tlines = tgetnum( "li" ); X tcolumns = tgetnum( "co" ); X X if( (CM = tgetstr( "cm", &area )) == NULL) { X CM = NADA; X printf("Error: No termcap 'cm' entry for this terminal type\n"); X abort(); X } X if( (CL = tgetstr( "cl", &area )) == NULL) X CL = NADA; X if( (UP = tgetstr( "up", &area )) == NULL) X UP = NADA; X if( (SO = tgetstr( "so", &area )) == NULL) X SO = NADA; X if( (SE = tgetstr( "se", &area )) == NULL) X SE = NADA; X if( (TI = tgetstr( "ti", &area)) == NULL) X TI = NADA; X if( (TE = tgetstr( "te", &area)) == NULL) X TE = NADA; X if( tgetnum( "sg", &area) > 0) { X SO = NADA; X SE = NADA; X } X if ( (BC = tgetstr( "bc", &area)) == NULL) { X BC = backstring; X } X X} /* tinit */ X X X X/* X * Procedure: loaddata(datafile) X * X * Function: loads data file X * X * Return Values: X * Various global arrays loaded with appointment data X * X * Discussion: X * Opens user's data file and reads it in, placing X * the data in appropriate arrays. X */ X Xloaddata(datafile) X X char *datafile; X{ X char basedata[80]; X char tmpbuf[80]; X char *getenv(); X char home[80]; X FILE *fptr; X int i,j,k,l,field; X X i = 0; X while (i < maxentries) { X daydata[i] = 0; X monthdata[i] = 0; X yeardata[i] = 0; X msgdata[i] = 0; X i++; X } X X if (datafile == NULL) { X strcpy(home,getenv("HOME")); X strcat(home,"/.appointments"); X } X else { X strcpy(home,datafile); X } X if ((fptr = fopen(home,"r")) != NULL) { X i = 0; X while((fgets(basedata,80,fptr) != NULL)) { X X basedata[strlen(basedata)-1] = NULL; X X j = 0; X k = 0; X field = 0; X while (basedata[j] != NULL ) { X X if (basedata[j] != ',') { X X tmpbuf[k++] = basedata[j]; X } X else { X switch (field) { X X case 0 : { X tmpbuf[k] = NULL; X monthdata[i] = atoi(tmpbuf); X k = 0; X break; X } X case 1 : { X tmpbuf[k] = NULL; X daydata[i] = atoi(tmpbuf); X k = 0; X break; X } X case 2 : { X tmpbuf[k] = NULL; X yeardata[i] = atoi(tmpbuf); X k = 0; X break; X } X case 3 : { X tmpbuf[k++] = ' '; X tmpbuf[k++] = ' '; X break; X } X } X field++; X } X j++; X } X tmpbuf[k] = NULL; X msgdata[i] = malloc(80); X strncpy(msgdata[i],tmpbuf,80); X msgdata[79] = NULL; X X if (i >= maxentries) { X printf("Warning: Over 1000 entries in data file. Data truncated.\n"); X break; X } X i++; X } X fclose(fptr); X } X} /* loaddata */ X X X/* X * Procedure: closefile(datafile) X * X * Function: writes appointment data to file X * X * Discussion: X * Opens the user's designated data file and writes the current X * data into it. X */ X Xclosefile(datafile) X Xchar *datafile; X{ X FILE *fptr; X char tmpbuf[80]; X int i; X char *getenv(); X char home[80]; X X if (datafile == NULL) { X strcpy(home,getenv("HOME")); X strcat(home,"/.appointments"); X } X else { X strcpy(home,datafile); X } X if ((fptr = fopen(home,"w")) == NULL) { X printf("Error: Cannot open %s file",datafile); X abort(); X } X i = 0; X while (i < maxentries) { X if (daydata[i]) { X strcpy(tmpbuf,msgdata[i]); X tmpbuf[4] = NULL; X fprintf(fptr,"%d,%d,%d,%4.4s,%s\n",monthdata[i],daydata[i],yeardata[i],tmpbuf,&tmpbuf[6]); X } X i++; X } X fclose(fptr); X} /* closefile */ X X X X X/* X * Procedure: notes(month,day,year) X * X * Function: displays the current day's appointments X * X * Parameters: X * p1 - int - month X * p2 - int - day X * p3 - int - year X * X * Discussion: X * Writes to notes section of screen notes for day to X * which the cursor was pointing. X */ X Xnotes(month,day,year) X X int month,day,year; X{ X int i,j,k; X X if (help1) { X helpclr(); X help1 = 0; X } X X i = 0; X while (i < 18) { X dayindex[i++] = 0; X } X X mov(64,5); X printf("%2d/%2d/%2d",month,day,year); X X i = 0; X j = 0; X k = 6; X X while (i < maxentries) { X if ((yeardata[i] == year) && (monthdata[i] == month) && (daydata[i] == day)) { X dayindex[j++] = i; X notclear++; X mov(42,k++); X printf("%-32.32s",msgdata[i]); X } X if (j > maxmsgs) { X mov(42,24); X printf("* too many entries to print *"); X break; X } X i++; X } X i = 0; X while (i < maxentries) { X if (daydata[i] == 0) { X dayindex[j++] = i; X if (j >= maxmsgs) { X break; X } X } X i++; X } X} /* notes */ X X X X/* X * Procedure: modnotes(month,day,year) X * X * Function: add, delete and modify appointment list X * X * Parameters: X * p1 - int - month X * p2 - int - day X * p3 - int - year X * X * Return Values: X * changes data in global message and date arrays X * X * Discussion: X * Allows the user to add, delete and modify a specified day's X * appointment list. Routine contains a small character X * interpreter which moves the cursor through the notes list X * and selects routines to modify the list. X */ X Xmodnotes (month,day,year) X X int month,day,year; X{ X X char key,c; X int xcoord,ycoord; X int i,cnt,total; X char tmpmsg[39]; X X notes(month,day,year); X xcoord = 42; X ycoord = 6; X i = 0; X mov(xcoord,ycoord); X key = 'a'; X X while (key != LF) { X X key = getchar(); X X switch (key) { X X case 'H' : X X helpnotes(); X X break; X X case 'j' : X i++; X if (++ycoord > 23) { X ycoord = 6; X i = 0; X } X break; X X case 'k' : X i--; X if (--ycoord < 6) { X ycoord = 23; X i = 17; X } X break; X X case 'd' : X X tputs(SO,1,tputc); X printf(" "); X tputs(SE,1,tputc); X mov (xcoord,ycoord); X monthdata[dayindex[i]] = 0; X daydata[dayindex[i]] = 0; X yeardata[dayindex[i]] = 0; X strcpy(msghold,msgdata[dayindex[i]]); X if (msgdata[dayindex[i]]) { X free(msgdata[dayindex[i]]); X msgdata[dayindex[i]] = 0; X } X break; X X case 'y' : X X strcpy(msghold,msgdata[dayindex[i]]); X X break; X X case 'p' : X X if (msgdata[dayindex[i]] == 0) { X msgdata[dayindex[i]] = malloc(80); X } X strncpy(msgdata[dayindex[i]],msghold,80); X yeardata[dayindex[i]] = year; X daydata[dayindex[i]] = day; X monthdata[dayindex[i]] = month; X printf("%s",msgdata[dayindex[i]]); X X break; X X case 'i' : X X tputs(SO,1,tputc); X printf(" "); X X mov (xcoord,ycoord); X X c = '0'; X cnt = 0; X while (c != ESC) { X c = getchar(); X if (c != ESC ) { X if (c == BS) { X if (cnt > 0) { X cnt--; X if (cnt == 5) { X cnt = 3; X mov(46,ycoord); X } X printf("%s %s",BC,BC); X } X } X else { X if (c != LF) { X if ( cnt < maxchars) { X tmpmsg[cnt] = c; X cnt++; X printf("%c",c); X } X if (cnt == 4) { X tmpmsg[4] = ' '; X tmpmsg[5] = ' '; X cnt = 6; X mov(48,ycoord); X } X } X else { X c = ESC; X } X } X } X } X tputs(SE,1,tputc); X if (cnt) { X tmpmsg[cnt] = NULL; X if (msgdata[dayindex[i]] == 0) { X msgdata[dayindex[i]] = malloc(80); X } X strncpy(msgdata[dayindex[i]],tmpmsg,80); X monthdata[dayindex[i]] = month; X daydata[dayindex[i]] = day; X yeardata[dayindex[i]] = year; X } X else { X monthdata[dayindex[i]] = 0; X daydata[dayindex[i]] = 0; X yeardata[dayindex[i]] = 0; X if (msgdata[dayindex[i]]) { X free(msgdata[dayindex[i]]); X msgdata[dayindex[i]] = 0; X } X } X X break; X X default :; X } X mov (xcoord,ycoord); X } X X active[day] = 0; X i = 0; X while (i < maxentries) { X if ((yeardata[i] == year) && (monthdata[i] == month)) { X notclear = 18; X active[daydata[i]] = 1; X } X i++; X } X X notclear = 18; X clearmsgs(); X if (active[day]) { X notes(month,day,year); X } X setday(day); X if (help2) { X helpclr(); X help2 = 0; X } X} /* modnotes */ X X X/* X * Procedure: tputc(character) X * X * Function: moves cursor on screen X * X * Parameters: X * p1 - int - character X * X * Discussion: X * Outputs a character to crt. Used as an argument to tputs(). X */ X Xtputc(c) X int c; X{ X putchar(c); X} X X X/* X * Procedure: mov(column,row) X * X * Function: moves cursor on screen X * X * Parameters: X * p1 - int - crt column X * p2 - int - crt row X * X * Discussion: X * Moves the cursor to specified column and row on screen using X * termcap data. X */ X Xmov(col, row) X Xint col,row; X X{ X tputs( tgoto( CM, (col - 1),(row - 1)), 1, tputc ); X} /* move */ X X X/* X * Procedure: clearday(month,day,year) X * X * Function: deletes specified day's appointments X * X * Parameters: X * p1 - int - month X * p2 - int - day X * p2 - int - year X * X * Return Values: X * changes various global arrays X * X * Discussion: X * Removes appointment entries for the specified day from X * message and date tables and from the crt X */ X Xclearday (month,day,year) X X int month,day,year; X{ X int i; X X i = 0; X while (i < maxentries) { X if ((yeardata[i] == year) && (monthdata[i] == month) && (daydata[i] == day)) { X active[day] = 0; X monthdata[i] = 0; X daydata[i] = 0; X yeardata[i] = 0; X if (msgdata[i]) { X free(msgdata[i]); X msgdata[i] = 0; X } X } X i++; X } X clearmsgs(); X setday(day); X} /* clearday */ X X X/* X * Procedure: clearmsgs() X * X * Function: clears the notes section of the crt X */ X Xclearmsgs() X X{ X int i; X X mov(64,5); X printf(" "); X X if (notclear > maxmsgs) notclear = maxmsgs; X X i = 6; X while (i < (notclear+6)) { X mov(42,i++); X printf(" "); X } X mov(42,24); X printf(" "); X notclear = 0; X} /* clearmsgs */ X X X/* X * Procedure: helpcal() X * X * Function: displays calendar help messages to crt X */ X Xhelpcal() X X{ X mov(1,19); X printf("j/k/h/l: cursor down/up/left/right \n"); X printf("b: first day e: last day \n"); X printf("space: display notes m: modify notes \n"); X printf("c: clear notes CR: exit program \n"); X printf("p: previous month n: next month \n"); X printf("BRK: exit w/o changes "); X help1++; X} /* helpcal */ X X X/* X * Procedure: helpnotes() X * X * Function: displays notes help messages to crt X */ X Xhelpnotes() X X{ X mov(1,19); X printf("j/k: cursor down/up \n"); X printf("i: enter insert ESC/CR: exit insert\n"); X printf("d: delete entry CR: exit notes \n"); X printf("y/p: yank/put a line \n"); X printf(" \n"); X printf(" "); X help2++; X} /* helpnotes */ X X X/* X * Procedure: helpclr() X * X * Function: clears notes area of screen X */ X Xhelpclr () X{ X mov(1,19); X printf(" \n"); X printf(" \n"); X printf(" \n"); X printf(" \n"); X printf(" Type 'H' for help \n"); X printf(" "); X} /* helpclr */ X X X/* X * Procedure: timeset() X * X * Function: sets current month, day and year variables X * X * Return Values: X * tday, tmonth and tyear variables set to current date X */ X Xtimeset() X X{ X struct tm *localtime(); X X struct tm *tp; /* time structure */ X long tloc; /* number of seconds since 1970 */ X X time(&tloc); /* fills tloc */ X X tp = localtime(&tloc); X X tyear = tp->tm_year; X tmonth = tp->tm_mon + 1; X tday = tp->tm_mday; X X tyear += 1900; X X} /* timeset */ *-*-END-of-vcal.c-*-* echo x - vcal.l sed 's/^X//' >vcal.l <<'*-*-END-of-vcal.l-*-*' X.TH VCAL 1 X.SH NAME Xvcal \- visual calendar and notes program X.SH SYNOPSIS X.B vcal X[ month year ] [ filename ] X.sp Xwhere X.I month Xis a numeric value between 1 and 12, X.I year Xis a numeric four digit value and X.I filename Xis the data file to be accessed. X.SH DESCRIPTION X.I Vcal Xis a visual calendar program which allows the user to enter notes Xand appointments for each day of the month. It can be used to Xreplace the "paper" desk or wall calendar with an electronic one Xwhich can be accessed from any terminal or modem connected to the Xcomputer system. X.PP XWhen a date argument is present, X.I vcal Xwill display the requested month and year. The default argument values Xare the current month and year. When a filename argument is used X.I vcal Xwill uses that file instead of the default ~/.appointments file. XIf ~/.appointments is not used the filename of the current file Xwill appear at the top of the X.I vcal Xcalendar. X.SH OPERATION X.I Vcal Xis entered from UNIX by typing the Xcommand followed by an optional month and year value. A calendar Xwill be displayed on the screen with the cursor located on the first Xday of the month. The cursor may be moved to different days Xin the following manner. X.br X.sp X.nf Xkey function X--- -------- Xj move cursor down Xk move cursor up Xl move cursor to the next day Xh move cursor to the previous day Xb move cursor to the beginning of the month Xe move cursor to the end of the month X.sp X.fi X.PP XPrevious and following months may also be accessed. X.br X.sp X.nf Xkey function X--- -------- Xp previous month Xn next month X.sp X.fi X.PP XUp to eighteen appointments may be entered on each day of the month. XThese may be displayed, modified or cleared in with the following keys. XThey will operate on the day selected by the current cursor position. X.br X.sp 4 X.nf Xkey function X--- -------- Xspace display appointments for the selected day Xm enter or modify appointments Xc clear all appointments for the selected day X.sp X.fi X.PP XWhen the 'm' is pressed X.I vcal Xenters notes mode. While in this mode notes may be added, modified, Xdeleted, yanked or put. X.br X.sp X.nf Xkey function X--- -------- Xj move cursor down Xk move cursor up Xi begin data insertion XESC/CR end data insertion (only while in insert) Xd delete the selected line Xy hold the current line Xp insert the held message XCR exit notes mode and return to the calendar X.sp X.fi XData must begin with the appointment time in 24 hour format X(no ':' should be used). Entering new data will erase the current Xmessage on that line. A held line will be available to insert until Xit is changed or the user exits X.I vcal. XA line which is deleted using the 'd' key will be placed in the hold Xbuffer. X.PP XWhen the cursor is on the calendar a carriage return will cause the Xthe appointment data to be saved and X.I vcal Xto exit. Break or delete will cause X.I vcal Xto exit without updating the ~/.appointments file. X.PP XA 'H' will display help messages. A calendar help message Xwill be printed when Xthe cursor is on calendar days. A notes help message Xis printed when the cursor is in the notes area. X.PP XFive companion programs are available to use with the X.I vcal Xprogram. These are: X.br X.sp X.nf Xappts display current or selected days appointments Xeappts enter appointments from the UNIX command line Xautocall set appointment reminders for the current day Xlcal displays month's appointments in tabular form Xcallme sets appointment reminders X.fi X.sp XFor further information on these, reference the appropriate "man" Xentries. X.SH AUTHOR XMike Essex X.SH FILES Xvcal X.br X/etc/termcap X.br X~/.appointments X.br X.SH "SEE ALSO" Xappts(1), eappts(1), autocall(1), lcal(1), callme(1) X.SH BUGS X.I Vcal Xmay not work with extremely brain damaged terminals. There must be Xa 'CM' entry in the termcap for X.I vcal Xto draw the screen. There are year 2000 time bombs. X.br *-*-END-of-vcal.l-*-* exit