israel@umcp-cs.UUCP (Bruce Israel) (09/27/84)
: Run this shell script with "sh" not "csh" PATH=:/bin:/usr/bin:/usr/ucb export PATH all=FALSE if [ $1x = -ax ]; then all=TRUE fi /bin/echo 'Extracting calend.c' sed 's/^X//' <<'//go.sysin dd *' >calend.c X/* Copyright 1983 - University of Maryland */ X/* * * calend - An appointment calendar maintainer * * calend is used to remind a user about appointments. * * When calend is called, it looks at the users appointments * in the .calrc file in his home directory. This file is made * up of lines of the form: * * <opts> <start-date> <end-date> <message string> * * where <opts> is a string made up of * any of 'm','a','1','r','d', 'x', '+', '*' and <start-date> and * and <end-date> are either days of the week, (e.g. 'Wed') or * a date of the year of the form: * mm/dd (eg 11/20), month dd (eg Nov 20), or dd Month (eg 20 Nov) * * In addition, <end-date> can be an '*' instead, signifying the * same day or date as start-date. start-date and end-date must * both be either dates or days. * * When the current date is between <start-date> and <end-date> * inclusive (or if they are days then the day of the week is between * them) then the message will be processed according to the specified * options. The meanings of the various options are as follows: * * 'm' : mail the message to the user. The first time that 'calend' * is called during that period, send mail to the user using * the message-string as mail-text. * 'a' : always print the message. Every time 'calend' is called * during that period, print the message string on the terminal. * '1' : print the message once. Print the message on the terminal * the first time 'calend' is run during that period. * 'r' : run the remind program. The first four non-blank digits * of the message string should be a time-of-day of the form * 'hhmm' which remind can use. * 'd' : delete this entry from the file when 'calend' is finished * with it. * 'x' : the message is executed as a process. The '1' or 'a' says * whether to do it once or always during a period. If neither, * the default is 'a'. * '+' : move the message dates when it's done. The first word of * the message should be the offset of the form: * + [ <months> {m,/} ] [ <days> [d] ] * where '[' & ']' mean optional, and '{' & '}' mean a choice. * For example, +14 (two weeks), +3m (three months), +3/2 * (three months and two days), +3m2d (same). * '*' : 'pending' flag used by the program internally to indicate * that more processing needs to be done. * '#' : comment flag to indicate that this line shouldn't be processed * at all. * ':' : comment flag, not deleted by 'calend -c'. * * Author: Bruce Israel, umcp-cs!israel, israel@Maryland */ #include <signal.h> #include "globals.h" #include "process.h" struct tm *localtime(); onintr() { char tmname[BUFSIZ]; int i; for (i = 0; i <= level; i++) { sprintf(tmname,"%s-%c",tmplate,'A' + level); unlink(tmname); } exit(1); } main(argc, argv) int argc; char *argv[]; { char *ptr; char fname[BUFSIZ]; /* file name */ int f_opt = NO; long tmptime; /* place to put time */ struct tm *curtim; /* current time structure */ bool debugdate; /* user-specified date? */ int userdate,userday; /* specifiable date for debugging */ argc--, argv++; while (argc > 0) { ptr = *argv; while (*ptr) switch (*ptr++) { case '-': break; case 'C': case 'c': clean = YES; break; case 'f': case 'F': f_opt = YES; if (*ptr == 0) { argv++; if (*argv == 0) { fprintf(stderr, "calend: no file given with '-f'.\n"); exit(1); } strcpy(fname,*argv); } else { strcpy(fname,ptr); *ptr = 0; } break; case 'I': case 'i': i_opt = YES; break; case 'R': case 'r': remonly = YES; break; case 'D': case 'd': debugdate = YES; if (*ptr == 0) { fprintf(stderr, "calend: no date given with '-D'.\n"); exit(1); } userday = *ptr++ - '0'; userdate = atoi(ptr); *ptr = 0; break; default: fprintf(stderr, "Unknown option '%c' - ignored\n",ptr[-1]); } argc--, argv++; } /* get current date */ if (debugdate) { cdate = userdate; cwday = userday; } else { time(&tmptime); curtim = localtime(&tmptime); cwday = curtim -> tm_wday; cdate = (curtim -> tm_mon) * 100 + curtim -> tm_mday + 100; } setgid(getegid()); setuid(geteuid()); /* get dates file name */ if (! f_opt) sprintf(fname,"%s/%s",getenv("HOME"),RCFILE); sprintf(tmplate,"/tmp/cal-%d",getpid()); level = 0; signal(SIGINT,onintr); process_file(fname,1); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 calend.c /bin/echo -n ' '; /bin/ls -ld calend.c fi /bin/echo 'Extracting process.c' sed 's/^X//' <<'//go.sysin dd *' >process.c #include "globals.h" #include "process.h" #define CKPERIOD(start,end,t) ((start <= end) ? ((t >= start) && (t <= end)) \ : ((t >= start) || (t <= end))) #define CURSIZE(a,b) ((a >= b) ? (a - b) : (1200 + a - b)) process_file(fname,writeerrors) char *fname; int writeerrors; { char tmname[1024]; /* temp file name */ char *ptr; int i,j; /* counters for for loops */ int plusmoved; /* has entry been shifted because of aa '+' */ int msgptr = 0; /* pointer to message in 'line' */ char flags[BUFSIZ]; /* options per line */ FILE *fil; /* dates file descriptor */ FILE *tfil; /* temp file descriptor */ int plusbmsg; /* message plus blanks for plus option */ int modflag; /* has dates file been modified? */ int modline; /* has current line been modified? */ char incname[BUFSIZ]; /* include file name */ /* Command option flags */ bool execute; /* execute message line as process? */ bool mail; /* send mail? */ bool always; /* always print? */ bool once; /* print first time only? */ bool remind; /* run remind program? */ bool plusdate; /* move date when ready? */ bool pending; /* should something be done with this line? */ bool newpending; /* pending afterwards? */ bool ignore; /* commented out? */ bool ignoresave; /* keep comment? */ bool delete; /* delete later? */ bool includefile; /* additionally use other dates file? */ bool nodates; /* no dates for parsing on line */ int in_period; /* currently within period? */ int real_in_period; char cmdbuf[BUFSIZ]; int canwrite; fil = fopen(fname,"r"); if (fil == NULL) { perror(fname); exit(errno); } canwrite = 1; if (access(fname,2)) { canwrite = 0; if (writeerrors) fprintf(stderr,"calend: can't write out %s.\n", fname); } /* open temp for copying */ sprintf(tmname,"%s-%c",tmplate,'A'+level); tfil = fopen(tmname,"w"); if (tfil == NULL) { perror(tmname); exit(errno); } modflag = 0; /* Main loop */ while(fgets(cmdbuf,sizeof cmdbuf,fil)) { /* Reset flags */ strcpy(flags,"#"); strcpy(line,""); if (*cmdbuf == ':' || *cmdbuf == '#' || *cmdbuf == '<') sscanf(cmdbuf,"%1s%[^\n]\n",flags,line); else sscanf(cmdbuf,"%s%[^\n]\n",flags,line); mail = NO; always = NO; once = NO; remind = NO; plusdate = NO; execute = NO; delete = NO; pending = NO; newpending = NO; ignore = NO; ignoresave = NO; nodates = NO; includefile = NO; ptr = flags; lineptr = 0; monthmax = 0; daymax = 0; in_period = 0; modline = 0; while(*ptr) switch(*ptr++) { case 'M' : case 'm' : mail = YES; break; case 'A' : case 'a' : always = YES; break; case '1' : once = YES; break; case 'D' : case 'd' : delete = YES; break; case 'R' : case 'r' : remind = YES; break; case '+' : plusdate = YES; break; case 'X' : case 'x' : execute = YES; break; case '*' : pending = YES; break; case '<' : includefile = YES; nodates = YES; break; case ',' : break; case ':' : ignoresave = YES; case '#' : ignore = YES; nodates = YES; break; default : fprintf(stderr,"Illegal flag %c\n",*(ptr-1)); } if (nodates) { if (includefile) { sscanf(line,"%s",incname); level++; process_file(incname,0); level--; } goto copy; } /* ignore everything but remind lines if remind-only is set */ if (remonly && !remind) { newpending = pending; goto copy; } /* ignore comments and error lines */ if (ignore || yyparse()) goto copy; plusbmsg = lineptr; while (line[lineptr] == ' ' || line[lineptr] == '\t') lineptr++; msgptr = lineptr; if (plusdate) get_plus_parts(); while (line[lineptr] == ' ' || line[lineptr] == '\t') lineptr++; if (plusdate && offmonth == 0 && offday == 0) fprintf(stderr,"No offset given for '+' option in: %s\n", line+msgptr); /* handle '*[{+-}offset]' appropriately */ if ((type1 * type2) == 0) { dtype = 0; monthmax = 1; month1[0] = 0; month2 = 0; } else dtype = 1; tdate = dtype ? cdate : cwday; if ((type1 == -1) || (type2 == -1)) { if ((type1 == 2) || (type2 == 2)) for (i=0;(i < monthmax) && (! in_period);i++) { dayt1 = month1[i] * 100 + day1[i]; dayt2 = add_date(dayt1,star); if (type1 == -1) SWAP(dayt1,dayt2); in_period = CKPERIOD(dayt1,dayt2,tdate); } else { for (i=0;(i < monthmax) && (! in_period);i++) for (j=0;(j < daymax) && (! in_period);j++) { dayt1 = month1[i] * 100 + day1[j]; dayt2 = add_date(dayt1,star); if (type1 == -1) SWAP(dayt1,dayt2); in_period = CKPERIOD(dayt1,dayt2,tdate); } } } else { dayt1 = month1[0]*100+day1[0]; dayt2 = month2 * 100 + day2; in_period = CKPERIOD(dayt1,dayt2,tdate); } mptr = message; plusmoved = 0; if (plusdate && in_period && (newpending = 1,dtype == 0)) { int diff1; int diff2; diff1 = dayt1 - tdate - ((dayt1 <= tdate) ? 0 : 7); diff2 = dayt2 - tdate + ((tdate <= dayt2) ? 0 : 7); dtype = 1; tdate = cdate; plusmoved = 1; dayt1 = add_date(cdate,diff1); dayt2 = add_date(cdate,diff2); } if (plusdate && (dtype == 1) && (! in_period) && ((monthmax * daymax) == 1) && (offday > 0 || offmonth > 0)) { int diff,newdate,tmon,tday,oldsize, pnd = pending; diff = ((dayt2 < dayt1) ? (dayt1 - dayt2) : (365 - (1 + dayt2 - dayt1))) / 2; newdate = add_date(dayt2,diff); oldsize = 1200; while (CKPERIOD((dayt2+1),newdate,tdate) && (CURSIZE(newdate,(dayt2+1)) < oldsize)) { oldsize = CURSIZE(newdate,(dayt2+1)); if (! pnd && ! i_opt && ! execute && ! remind) { if (mptr != message) *mptr++ = '\n'; create_message(line+lineptr); create_message(" [old message from %2]"); real_in_period = in_period; in_period = 1; } pnd = 0; plusmoved = 1; modline++; tmon = dayt1 / 100 + offmonth; tday = dayt1 % 100 + offday; dayt1 = add_date((tmon * 100 + tday),0); tmon = dayt2 / 100 + offmonth; tday = dayt2 % 100 + offday; dayt2 = add_date((tmon * 100 + tday),0); } if (CKPERIOD(dayt1,dayt2,tdate)) { if (mptr != message) *mptr++ = '\n'; create_message(line+lineptr); in_period = 1; pending = 0; } } else if (in_period) create_message(line+lineptr); if (in_period) { if (execute) { if (! once) always = YES; if (always || (once && ! pending)) execute_thing(); if (!always) newpending = YES; } else { if (remind) run_remind(); if (mail && ! pending) send_mail(); if (once && ! pending) pr_message(); if (always) pr_message(); if (once || mail) newpending = YES; if ((once || mail) && (!remind) && (!always) && delete) { ignore = YES; modline++; } } if (delete) newpending = YES; if (plusdate && real_in_period) newpending = YES; } else { newpending = NO; if (delete && pending) { ignore = YES; modline++; } } copy: if (canwrite) { char opts[10]; if (newpending != pending) modline++; if (! modline) { if (!clean || !ignore || ignoresave) fprintf(tfil,"%s",cmdbuf); continue; } modflag++; ptr = opts; if (ignore) *ptr++ = ignoresave ? ':' : '#'; if (execute) *ptr++ = 'x'; if (once) *ptr++ = '1'; if (always) *ptr++ = 'a'; if (remind) *ptr++ = 'r'; if (mail) *ptr++ = 'm'; if (delete) *ptr++ = 'd'; if (plusdate) *ptr++ = '+'; if (newpending && ! ignore) *ptr++ = '*'; *ptr = 0; if (!clean || !ignore || ignoresave) { fprintf(tfil,"%s", opts); if (ignore || ! plusmoved) fprintf(tfil,"%s\n", line); else { char *l = line; while (*l == ' ' || *l == '\t') putc(*l++,tfil); if (type1 == -1) { if (star == 0) fprintf(tfil,"*"); else if (star < 0) fprintf(tfil,"*%d",star); else fprintf(tfil,"*+%d",star); } else { mptr = message; create_message("%1"); fprintf(tfil,"%s",message); } fprintf(tfil,"\t"); if (type2 == -1) { if (star == 0) fprintf(tfil,"*"); else if (star < 0) fprintf(tfil,"*%d",star); else fprintf(tfil,"*+%d",star); } else { mptr = message; create_message("%2"); fprintf(tfil,"%s",message); } if (lastchar != '}') putc(lastchar,tfil); fprintf(tfil,"%s\n",line+msgptr); } } } } fclose(tfil); if (canwrite && modflag) copy_file(tmname,fname); unlink(tmname); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 process.c /bin/echo -n ' '; /bin/ls -ld process.c fi /bin/echo 'Extracting util.c' sed 's/^X//' <<'//go.sysin dd *' >util.c X/* Copyright 1983 - University of Maryland */ #include <signal.h> #include <ctype.h> #include "globals.h" FILE *popen(); char *getlogin(); struct passwd *getpwuid(); int onintr(); #ifdef USG #define MAIL "/usr/bin/mailx -s 'Reminder Service' %s" #else #define MAIL "/usr/ucb/mail -s 'Reminder Service' %s" #endif char *mon_nm[]={ "January","February","March","April","May","June","July","August", "September","October","November","December" }; char *relative[]={ "the day before yesterday", "yesterday", "today", "tomorrow", "the day after tomorrow" }; int mon_len[]={ 31,28,31,30,31,30,31,31,30,31,30,31 }; char *day_nm[]={ "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday" }; get_plus_parts() { int num = 0; char c; offmonth = 0; offday = 0; if (line[lineptr] != '+') return; lineptr++; while (isdigit(c = line[lineptr++])) num = num * 10 + c - '0'; lineptr--; if (line[lineptr] == 'd' || line[lineptr] == 'D') { lineptr++; offday = num; return; } if (line[lineptr] != '/' && line[lineptr] != 'm' && line[lineptr] != 'M') { offday = num; return; } offmonth = num; num = 0; lineptr++; while (isdigit(c = line[lineptr++])) num = num * 10 + c - '0'; lineptr--; if (line[lineptr] == 'd' || line[lineptr] == 'D') lineptr++; offday = num; return; } char *datestr(datenum,mtype,forward) int datenum,mtype,forward; { register char dstri[BUFSIZ]; int ddiff; if ((mtype == 3) && (abs(ddiff = reldiff(datenum,tdate,forward)) < 3)) { sprintf(dstri,"%s", relative[ddiff+2]); return(dstri); } if (dtype) { if (mtype == 2) sprintf(dstri,"%d",datenum % 100); else if (mtype == 1) sprintf(dstri,"%s",mon_nm[(datenum / 100 - 1) % 12]); else sprintf(dstri,"%s %d",mon_nm[(datenum / 100 - 1) % 12], datenum % 100); return(dstri); } if (mtype == 1) return(""); return day_nm[datenum % 7]; } int reldiff(d1,d2,firstmore) int d1,d2,firstmore; { int count = 0; if (firstmore) SWAP(d1,d2); while ((d1 != d2) && (count < 3)) { count++; d1 = add_date(d1,1); } if (! firstmore) count = 0 - count; return(count); } int add_date(date, offset) int date, offset; { int mo, da, sum; if (!dtype) { sum = date + offset; while (sum < 0) sum = sum + 7; sum = sum % 7; return (sum); } mo = date / 100; da = date % 100 + offset; mo = mo % 12; if (mo == 0) mo = 12; while (da < 1) { mo--; if (mo == 0) mo = 12; da = da + mon_len[mo - 1]; } while (da > mon_len[mo - 1]) { da = da - mon_len[mo - 1]; mo++; if (mo == 13) mo = 1; } return (mo * 100 + da); } getnextchar() { return(lastchar = line[lineptr++]); } create_message(str) char *str; { register char c, *cstr, nstr[20], m; int i,mt; while (c = *str++) { if (c == '%') { if (((m = *str++) == 'm') || (m == 'M')) mt = 1; else if ((m == 'd') || (m == 'D')) mt = 2; else if ((m == 'r') || (m == 'R')) mt = 3; else { str--; mt = 0; } switch (c = *str++) { case '1' : cstr = datestr(dayt1,mt,0); break; case '2' : cstr = datestr(dayt2,mt,1); break; case 'c' : case 'C' : cstr = datestr(tdate,mt,0); break; case '%' : cstr = "%"; break; default : cstr = "%"; str--; if (mt) str--; break; } while(*mptr++ = *cstr++); mptr--; } else *mptr++ = c; } *mptr = '\0'; } send_mail () { register char *name = getlogin(); register FILE *mpipe; char linebuf[BUFSIZ]; if (!name) name = getpwuid(getuid()) -> pw_name; sprintf(linebuf,MAIL,name); mpipe = popen(linebuf,"w"); fprintf(mpipe,"%s\n",message); pclose(mpipe); } run_remind() { register char time[BUFSIZ]; register char restmsg[BUFSIZ]; int tmp; sscanf(message,"%s %[^\n]",time,restmsg); strcpy(message,restmsg); /* get new message for other options */ if((tmp = fork()) == 0) { execl(REMIND,"remind","-f",time,restmsg,0); _exit(-999); } if (tmp == -1) { fprintf(stderr,"Help, I'm unforkable!\n"); } } execute_thing() { int pid; if ((pid = fork()) == 0) { execl("/bin/csh", "csh", "-cf", message, 0); perror("Fork of /bin/csh"); _exit(1); } else if (pid == -1) fprintf(stderr,"Couldn't fork to run '%s'.\n",message); } pr_message() { printf("%s\n",message); } copy_file(from,to) char *from, *to; { FILE *fromfile, *tofile; char fline[BUFSIZ]; signal(SIGINT,SIG_IGN); if ((fromfile = fopen(from,"r")) == NULL) { perror(from); onintr(); exit(errno); } if ((tofile = fopen(to,"w")) == NULL) { perror(to); fclose(fromfile); signal(SIGINT,onintr); return; } while (fgets(fline, sizeof fline, fromfile)) fputs(fline,tofile); fclose(fromfile); fclose(tofile); signal(SIGINT,onintr); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 util.c /bin/echo -n ' '; /bin/ls -ld util.c fi /bin/echo 'Extracting parser' sed 's/^X//' <<'//go.sysin dd *' >parser X/* Copyright 1983 - University of Maryland */ %{ #include "globals.h" #include "pars.h" %} %start pgm %token MONTH NUM DAY STAR OCURL CCURL SLASH DASH %% pgm : MONTH numsecd { ADDMONTH($1); type1= 1; YYACCEPT;} | NUM mosecd { if (monthmax) ADDDAY($1); else ADDMONTH($1); type1= 1; YYACCEPT;} | scurly lstsec { type2 = -1; YYACCEPT;} | DAY secday { type1= 0; ADDDAY($1); YYACCEPT; } | STAR either { type1 = -1; star = $1; YYACCEPT;} ; numsecd : NUM secdate { ADDDAY($1); } | scurly numlst CCURL STAR { copydays(0); type2 = -1; star = $4; } ; mosecd : MONTH secdate { ADDMONTH($1); } | scurly monlst CCURL STAR { type2 = -1; star = $4; } | sldash NUM secdate { ADDDAY($2); } | sldash scurly numlst CCURL STAR { copydays(0); type2 = -1; star = $5; } ; lstsec : monlst CCURL nums STAR { type1 = 1; copydays(0); star = $4; } | numlst CCURL sldash nums STAR { type1 = 1; copymonths(0); copydays(1); star = $5; } | numlst CCURL months STAR { type1 = 1; copydays(0); star = $4; } | daylst CCURL STAR { type1 = 0; star = $3; } | datl CCURL STAR { type1 = 2; star = $3; } ; secday : STAR { type2 = -1; star = $1; } | DAY { type2 = 0; day2 = $1; } ; either : MONTH nums { ADDMONTH($1); copydays(0); type2 = 1; } | NUM sldash nums { ADDMONTH($1); copydays(0); type2 = 1; } | NUM months { ADDDAY($1); type2 = 1; } | DAY { ADDDAY($1); type2 = 0; } | scurly restlst ; secdate : MONTH NUM { month2 = $1; day2 = $2; type2 = 1; } | NUM sldash NUM { month2 = $1; day2 = $3; type2 = 1; } | NUM MONTH { month2 = $2; day2 = $1; type2 = 1; } | STAR { type2 = -1; star = $1; } ; months : MONTH { ADDMONTH($1); } | scurly monlst CCURL ; nums : NUM { allocnum(); ADDNUM($1); } | scurly numlst CCURL ; restlst : restdat { type2 = 1;} | daylst CCURL { type2 = 0;} | datl CCURL { type2 = 2;} ; restdat : monlst CCURL nums { copydays(0); } | numlst CCURL sldash nums { copymonths(0); copydays(1); } | numlst CCURL months { copydays(0); } ; datl : nnl | mnl | nml ; nnl : NUM SLASH NUM { ADDMONTH($1); ADDDAY($3); } | nnl NUM SLASH NUM { ADDMONTH($2); ADDDAY($4); } ; mnl : MONTH NUM { ADDMONTH($1); ADDDAY($2); } | mnl MONTH NUM { ADDMONTH($2); ADDDAY($3); } ; nml : NUM MONTH { ADDMONTH($2); ADDDAY($1); } | nml NUM MONTH { ADDMONTH($3); ADDDAY($2); } ; numlst : NUM { ADDNUM($1); } | numlst NUM { ADDNUM($2); } | NUM DASH NUM { addnumseq($1,$3); } ; monlst : MONTH { ADDMONTH($1); } | monlst MONTH { ADDMONTH($2); } | MONTH DASH MONTH { addmonseq($1,$3); } ; daylst : DAY { ADDDAY($1); } | daylst DAY { ADDDAY($2); } | DAY DASH DAY { adddayseq($1,$3); } ; sldash : SLASH | DASH ; scurly : OCURL { allocnum(); } ; %% #include "lex.yy.c" yyerror(s) char *s; { fprintf(stderr,"%s:(%s)\n",s,line); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 parser /bin/echo -n ' '; /bin/ls -ld parser fi /bin/echo 'Extracting scanner' sed 's/^X//' <<'//go.sysin dd *' >scanner X/* Copyright 1983 - University of Maryland */ %{ #include "y.tab.h" #undef input #undef output #undef unput #define allprint(c) (putchar(c)) #define sprint(str) (printf("%s",str)) #define output(c) (putchar(c)) #define input() (yytchar=yysptr>yysbuf?U(*--yysptr):getnextchar()) #define unput(c) (*yysptr++=(c)) #define yywrap() 1 %} star \* dash \- slash \/ plus \+ ocurl \{ ccurl \} space [ \t] nu [0-9][0-9]* arb [a-zA-Z]* a [aA] b [bB] c [cC] d [dD] e [eE] f [fF] g [gG] h [hH] i [iI] j [jJ] k [kK] l [lL] m [mM] n [nN] o [oO] p [pP] q [qQ] r [rR] s [sS] t [tT] u [uU] v [vV] w [wW] x [xX] y [yY] z [zZ] %% {star}{space} {yylval=0;return(STAR);} {star}{plus}{nu} {sscanf(yytext,"*%d",&yylval); return(STAR);} {star}{dash}{nu} {sscanf(yytext,"*%d",&yylval); return(STAR);} {nu} {sscanf(yytext,"%d",&yylval); return(NUM);} {ocurl} {return(OCURL);} {ccurl} {return(CCURL);} {dash} {return(DASH);} {slash} {return(SLASH);} {j}{a}{n}{arb} {yylval=1;return(MONTH);} {f}{e}{b}{arb} {yylval=2;return(MONTH);} {m}{a}{r}{arb} {yylval=3;return(MONTH);} {a}{p}{r}{arb} {yylval=4;return(MONTH);} {m}{a}{y}{arb} {yylval=5;return(MONTH);} {j}{u}{n}{arb} {yylval=6;return(MONTH);} {j}{u}{l}{arb} {yylval=7;return(MONTH);} {a}{u}{g}{arb} {yylval=8;return(MONTH);} {s}{e}{p}{arb} {yylval=9;return(MONTH);} {o}{c}{t}{arb} {yylval=10;return(MONTH);} {n}{o}{v}{arb} {yylval=11;return(MONTH);} {d}{e}{c}{arb} {yylval=12;return(MONTH);} {s}{u}{n}{arb} {yylval=0;return(DAY);} {m}{o}{n}{arb} {yylval=1;return(DAY);} {t}{u}{e}{arb} {yylval=2;return(DAY);} {w}{e}{d}{arb} {yylval=3;return(DAY);} {t}{h}{u}{arb} {yylval=4;return(DAY);} {f}{r}{i}{arb} {yylval=5;return(DAY);} {s}{a}{t}{arb} {yylval=6;return(DAY);} [ \t,] ; //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 scanner /bin/echo -n ' '; /bin/ls -ld scanner fi /bin/echo 'Extracting globals.h' sed 's/^X//' <<'//go.sysin dd *' >globals.h X/* Copyright 1983 - University of Maryland */ #include <stdio.h> #include <pwd.h> #include <time.h> #define NO 0 #define YES 1 #define RCFILE ".calrc" /* user's rc file */ #define REMIND "/usr/local/remind" #define SWAP(a,b) { int temp; temp = a; a = b; b = temp; } typedef char bool; extern int errno; char line[BUFSIZ]; /* dates and string on rest of line */ int lineptr; /* current location in 'line' */ char lastchar; /* last character sent to 'yacc' */ int type1, type2; /* date types for first and second date, -1 - *, 0 - day, 1 - date, 2 - date_list */ int dtype; /* day or date type for line, 0,1 as above */ int star; /* offset if relative dates */ int month1[35],day1[35]; /* arrays for month and day elements */ int monthmax, daymax; /* max locations for days and months arrays */ int month2, day2; /* second day items */ int tnum[2][35]; /* temp nums list */ int tnummax[2]; /* max location for tnums */ int cnum; /* current number array */ int tdate; char message[BUFSIZ]; /* buffer for creating the message */ char *mptr; /* pointer into message array */ int dayt1, dayt2; int offmonth, offday; /* offsets for '+' option */ //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 globals.h /bin/echo -n ' '; /bin/ls -ld globals.h fi /bin/echo 'Extracting process.h' sed 's/^X//' <<'//go.sysin dd *' >process.h X/* Copyright 1983 - University of Maryland */ int level; /* level of recursion on included files '<' */ char tmplate[BUFSIZ]; /* temp file name template "/tmp/cal-<pid>-A,B ..." */ bool clean; /* was '-c' (clean up) option given? */ bool i_opt; /* was '-i' (ignore old messages) given? */ bool remonly; /* '-r' (remind only) */ int cdate,cwday; /* current date and weekday */ //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 process.h /bin/echo -n ' '; /bin/ls -ld process.h fi /bin/echo 'Extracting pars.h' sed 's/^X//' <<'//go.sysin dd *' >pars.h X/* Copyright 1983 - University of Maryland */ #define ADDMONTH(var) month1[monthmax++]=var #define ADDDAY(var) day1[daymax++]=var #define ADDNUM(var) tnum[cnum][tnummax[cnum]++]=var allocnum() { if (tnummax[0] > 0) cnum = 1; else cnum = 0; } addnumseq(st,fin) int st,fin; { int i; for (i=st; i <= fin; i++) ADDNUM(i); } addmonseq(st,fin) int st,fin; { int i; fin++; if (fin > 12) fin = 1; ADDMONTH(st); for (i = st + 1; i != fin; i = (i >= 12) ? 1 : i+1) ADDMONTH(i); } adddayseq(st,fin) int st,fin; { int i; fin++; if (fin > 7) fin = 1; ADDDAY(st); for (i = st + 1; i != fin; i = (i >= 7) ? 1 : i+1) ADDDAY(i); } copydays(ar) int ar; { int i; for (i = 0; i < tnummax[ar]; i++) day1[i] = tnum[ar][i]; daymax = i; tnummax[ar] = 0; } copymonths(ar) int ar; { int i; for (i = 0; i < tnummax[ar]; i++) month1[i] = tnum[ar][i]; monthmax = i; tnummax[ar] = 0; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 pars.h /bin/echo -n ' '; /bin/ls -ld pars.h fi /bin/echo 'Extracting calend.1l' sed 's/^X//' <<'//go.sysin dd *' >calend.1l X.TH CALENDAR 1 X.SH NAME calend \- An appointment calendar maintainer X.SH SYNOPSIS X.B calend [ X.B \-c ] [ X.B \-i ] [ X.B \-r ] [ X.B \-DdMMDD ] [ X.B \-F <file> ] X.SH DESCRIPTION X.IR calend is used to remind a user about appointments. When calend is called, it looks at the users appointments in the .calrc file in his home directory. This file is made up of lines of the form: X.sp X.ce <opts> <start-date> <end-date> <message string> X.sp where <opts> is a string made up of any of X.B 'xma1rd+*' either contiguous or separated by commas, and <start-date> and <end-date> are either days of the week, (e.g. 'Wed'), dates of the year of the form: mm/dd (eg 11/20), month dd (eg Nov 20), or dd Month (eg 20 Nov), or a relative offset. A relative offset is either an '*', which means replace this date by the other date, '*+<num>', which means add the number to the other date to get this date, or '*-<num>', which means that <num> should be subtracted from the other date to get this date. Both dates must be of the same type, either both days, or both dates, and they cannot both be relative offsets. X.PP If one of the dates is a relative offset, then the other can be a set specification. For days of the week a set specification is a list or range of days within curly braces, (e.g. "{ sun tues thurs }" or "{tues - fri}"). For a date of the year specification, Any or all of the month and dates can be sets, (e.g. "{3 7 11}/1", "Jan {1 3 5}", or "{Jan - March} 1"). You can also have dates of the form "{1/3 2/14 11/22}" or "{jan 25, mar 3, sep 24}" but you cannot nest them. X.PP When the current date is between any element of <start-date> and <end-date> inclusive (or if they are days then the day of the week is between them) then the message will be processed according to the specified options. The meanings of the various options are as follows: X.br X.TP X.I x execute the message as a process. If the 'x' option is given, all other options except '1', 'a', '+', and 'd' will be ignored. The 'd' option will act as normal, but the '1' and 'a' options will indicate whether to do the execution the first time in the period or always during the period. [If neither is given, then always is assumed.] X.TP X.I < The rest of the line is expected to be a file name that X.B calend will recursively process as a dates file. This is useful for groups of people with many entries in common (i.e. meetings and talks announcements, paydays, etc.) X.TP X.I m mail the message to the user. The first time that 'calend' is called during that period, send mail to the user using the message-string as mail-text. X.TP X.I a always print the message. Every time 'calend' is called during that period, print the message string on the terminal. X.TP X.I 1 print the message once. Print the message on the terminal the first time 'calend' is run during that period. X.TP X.I r run the remind program. The first four non-blank digits of the message string should be a time-of-day of the form 'hhmm' which remind can use. X.TP X.I d delete this entry from the file when 'calend' is finished with it. When an entry is deleted, it is actually commented out from the file with a '#' flag. X.TP X.I + move the dates of this entry forward when done. The first word of the message is the amount of months and days to move the message forward by (i.e. +14 or 14d (two weeks), +1/2 (one month and two days), +3m2d (three months and two days) etc). The dates are expected to be dates of the year (i.e. month and date of month) and can only be single dates or a '*' specification. Sets of dates will not be moved. If the period is specified in days of the week, then they will automatically be converted to dates the first time X.B calend is run in that period. X.sp X.B calend uses a simple heuristic to decide when to move the dates of a line with the '+' option. The dates of a line will be moved when the current date is in the first half of the inverse of the period. For example, If you have the line: X.sp X.nf a+ sept 23 * +14 Payday today X.fi X.sp then the dates will be moved to October 7 (or later) when X.B calend is executed during the first half of the 364 day period from september 24 through September 22. If the current date was after October 7, the dates will continue to be moved until the current date is within or before that period. This is used when X.B calend is not run within the period. If the -i option is not set, then each old message that was missed will be printed out (marked as such). X.TP X.I * \&'pending' flag used by the program internally to indicate that more processing needs to be done. X.PP If a line in the .calrc flag starts with a '#' or a ':', that line is considered to be a comment and is not processed. X.PP The '-c' (clean) option says to actually delete all lines beginning with a '#' rather than just ignoring them. Comments beginning with ':' are still kept in the file. X.PP The '-i' (ignore old messages) option says not to print out previously missed messages from the '+' option. X.PP The '-r' (remind only) option says to only process lines that are remind calls, and not to process everything. X.PP The '-f <file>' option instructs X.B calend to use an alternate file instead of using $HOME/.calrc. X.PP The '-D' (set date) option is for debugging a .calrc. It should be immediately followed by a decimal of the form: dMMDD where 'd' is a '0' - '6' meaning Sunday thru Saturday, and MMDD is the month and date put together (e.g. -D31001 means run calend as if it were Wednesday, October first). These dates are not checked for validity. X.PP There are three variable specifications that can go in the message string. These are '%1', '%2' and '%c'. Any occurrences of '%1' in the message string will be replaced by the starting day or date. All occurrences of '%2' will be replaced by the ending day or date from the same line, and '%c' will be replaced by the current day or date. If any of these have the letter 'm' as a modifier (e.g. %m1, %m2, %mc) then the month name of that date will be substituted. If the modifier is 'd', then the numeric day of the month will be used (note that the %d specification will print out the numeric version of the day if the date specification was in days of the week.) If the modifier is 'r', then a relative (to the current date) term will be used. The available relative terms are, the day before yesterday, yesterday, today, tomorrow, and the day after tomorrow. If none of these are applicable, the the regular date will be used. In addition, '%%' will insert a '%' sign into that location in the message text. All other two character pairs starting with '%' will be inserted as is. An example .calrc is as follows: X.sp X.in +5 X.nf : temporary dates ad *-7 7/21 Party at bill's on %2 : permanent reminders am *-7 {jan - dec} 1 %m2's Rent is due r {mon wed fri} * 1358 Go to math class 1m *-7 11/14 mother's birthday is %r2 1m *-7 {jan 12, apr 14, sept 15, dec 10} insurance payment by %2 X.fi X.in -5 X.sp which says to a) print out the message "Party at bill's on July 21" every time X.B calend is called from July 14 through July 21 and then delete it after July 21, b) print out "<month>'s rent is due" the week before the first of the month, and also mail it to me, tell me to log off the system and go to my math class at 1:58 in the afternoon on Mondays, Wednesdays, and Fridays, d) inform me the week before my mother's birthday that it's coming up, and e) tell me the week before an insurance payment is due. X.SH AUTHOR Bruce Israel X.SH FILES \&.calrc which contains the file of dates. X.br X/tmp/cal-* X.br remind, mail subprocesses X.SH "SEE ALSO" mail(1), remind(1l) X.SH BUGS X.PP Poor error messages for illegal dates. X.PP Leap years are not recognized, so if a date is moved past February 29 of a leap year by the '+' option, that date will be off by one. X.PP Deletes on a line with multiple dates, (e.g. {july 21, sept 10}) will not work properly. X.PP The arguments of X.IR Remind are not checked for validity. X.PP X.IR Remind processes don't delete themselves until just before they are ready to print out a message, so extra processes could be floating around. //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 calend.1l /bin/echo -n ' '; /bin/ls -ld calend.1l fi /bin/echo 'Extracting Makefile' sed 's/^X//' <<'//go.sysin dd *' >Makefile SRCS=calend.c process.c util.c parser scanner globals.h process.h pars.h MISC=calend.1l Makefile remind.c remind.1l README addcal addcal.1l addcal.usg LOCDIR=/usr/local CFLAGS = -O calend: calend.o process.o util.o y.tab.o cc $(CFLAGS) -o calend calend.o process.o util.o y.tab.o calend.c: globals.h process.h process.c: globals.h process.h util.c: globals.h y.tab.c: parser lex.yy.c yacc -d parser lex.yy.c: scanner lex scanner parser: globals.h pars.h remind: remind.c cc $(CFLAGS) -o remind remind.c clean: rm -f y.* lex.* *.o calend remind print: pr $(SRCS) Makefile | lpr $(LOCDIR)/calend: calend rm -f $(LOCDIR)/calend cp calend $(LOCDIR)/calend inst-calend: $(LOCDIR)/calend $(LOCDIR)/addcal: addcal rm -f $(LOCDIR)/addcal cp addcal $(LOCDIR)/addcal inst-addcal: $(LOCDIR)/addcal $(LOCDIR)/remind: remind rm -f $(LOCDIR)/remind cp remind $(LOCDIR)/remind inst-remind: $(LOCDIR)/remind inst-man: /usr/man/man1/calend.1l /usr/man/man1/remind.1l \ /usr/man/man1/addcal.1l X/usr/man/man1/calend.1l: calend.1l cp calend.1l /usr/man/man1/calend.1l X/usr/man/man1/addcal.1l: addcal.1l cp addcal.1l /usr/man/man1/addcal.1l X/usr/man/man1/remind.1l: remind.1l cp remind.1l /usr/man/man1/remind.1l all: calend remind inst-all: inst-calend inst-addcal inst-remind inst-man @echo Installed //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 Makefile /bin/echo -n ' '; /bin/ls -ld Makefile fi /bin/echo 'Extracting remind.c' sed 's/^X//' <<'//go.sysin dd *' >remind.c X/* Copyright 1983 - University of Maryland */ X/* * remind [-f] [-#otlm] [time] ["reminder message"] * * (where time is in the form or hhmm or +Nm (minutes) or +Nh (hours)) * * Reminds you when you have to leave, and why you have to leave. * Remind prompts for input and goes away if you hit return. * It nags you like a Nice Jewish Mother should. * * printing added 19 January 1982 by umcp-cs!andrew * "You have to <>" printing added by umcp-cs!andrew * +N[hm] added 13sep83 by umcp-cs!andrew * 24hr time understanding added by umcp-cs!andrew * -f option added 25sep83 by umcp-cs!andrew * * last update->Sun Sep 25 15:01:13 1983 * * this was originally the leave(1) program * */ #include <stdio.h> #include <signal.h> static char *sccsid = "@(#)remind.c 1.1 (U of MuD) 09/13/83"; char origlogin[20], thislogin[20]; char *whenleave; char buff[100], buff1[100]; int ntimes = -1; /* # of times to bother */ char *ctime(); char *getlogin(); int hoursp(); main(argc, argv) int argc; char **argv; { long when, tod, now, diff, hours, minutes; int *nv; int atoi(); int *localtime(); char absolute=0; /* 1 if 24 hour time */ char quiet=0; /* 1 if not to bitch */ if(argv[1][0] == '-') { /* set ntimes */ ntimes = atoi(argv[1]+1); /* hoser! give it a pointer! */ if(argv[1][1] == 'f') { quiet=1; /* invocation from a program */ argv++; /* sneakily hack argv */ *argv = argv[-1]; /* hurrah for no bounds checking! */ argc--; ntimes = -1; if(argv[1][0] == '-') { ntimes=atoi(argv[1]+1); argv++; *argv = argv[-1]; argc--; } } else { argv++; /* sneakily hack argv */ *argv = argv[-1]; argc--; /* don't forget argc, twit! */ } } if(argc < 2) { printf("When do you have to leave? "); fflush(stdout); buff[read(0, buff, sizeof buff)] = 0; /* get answer */ if(*buff == '\n') exit(0); /* if \n exit */ if(!*buff) exit(0); /* if eof exit */ printf("What do you have to do? "); fflush(stdout); buff1[read(0, buff1, sizeof buff1)-1] = 0; /*kill the \n*/ } else if(argc == 2) { /* remind time */ printf("What do you have to do? "); fflush(stdout); buff1[read(0, buff1, sizeof buff1)-1] = 0; /*kill the \n*/ if(*buff1 == '\n') exit(0); strcpy(buff, argv[1]); } else { /* remind time "message" */ strcpy(buff, argv[1]); strcpy(buff1, argv[2]); } strcpy(origlogin, getlogin()); /* do getlogin here so we won't barf */ if(*buff == '+') { diff = atoi(buff+1); if(hoursp(buff+1)) diff *= 60; /* 60 mins/hour */ doalarm(diff); } if(*buff < '0' || *buff > '9') { if(!quiet) printf( "usage: %s [ -#otlm ] [time] [\"reminder-message\"]\n", *argv); exit(1); } tod = atoi(buff); hours = tod / 100; /* * times like 2300 or 0730 don't get frobbed to the nearest 12 hours * */ if(hours > 12) absolute = 1; if(*buff == '0') absolute = 1; if(!absolute && hours == 12) hours = 0; minutes = tod % 100; if(hours < 0 || hours > (absolute ? 24 : 12) || minutes < 0 || minutes > 59) { if(!quiet) printf( "usage: %s [ -#otlm ] [time] [\"reminder message\"]\n", *argv); exit(1); } time(&now); nv = localtime(&now); when = (60 * hours) + minutes; if(!absolute && nv[2] > 12) nv[2] -= 12; /* do am/pm bit */ now = (60 * nv[2]) + nv[1]; diff = when - now; if (now > when && absolute) { if (! quiet) printf("It is already past that time.\n"); exit(0); } while(diff < 0) diff += (absolute ? 24 : 12) * 60; if((diff > (absolute ? 23 : 11) * 60) && !quiet) printf( "That time has recently passed, but I'll remind you anyway.\n"); doalarm(diff); exit(0); } doalarm(nmins) long nmins; { char *msg1, *msg2, *msg3, *msg4; register int i; long slp1, slp2, slp3, slp4; long seconds, gseconds; long daytime; int pid; seconds = 60 * nmins; if(seconds <= 0) seconds = 1; gseconds = seconds; msg1 = "You have to %s in 5 minutes!"; if(seconds <= 60*5) { slp1 = 0; } else { slp1 = seconds - 60*5; seconds = 60*5; } msg2 = "Just one more minute before you have to %s!"; if(seconds <= 60) { slp2 = 0; } else { slp2 = seconds - 60; seconds = 60; } msg3 = "Time to leave and %s!"; slp3 = seconds; msg4 = "You're going to be too late to %s!"; slp4 = 60; time(&daytime); daytime += gseconds; whenleave = ctime(&daytime); printf("You have to %s at %s", buff1, whenleave); if(pid=fork()) { if(pid == -1) { perror("can't fork"); exit(1); } exit(0); } signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTTOU, SIG_IGN); #ifdef SIGTSTP signal(SIGTSTP, SIG_IGN); #endif if(slp1) bother(slp1, msg1); if(slp2) bother(slp2, msg2); bother(slp3, msg3); if(ntimes != -1) { for(;ntimes--;) bother(slp4, msg4); exit(0); } for(;;) { bother(slp4, msg4); /* be annoying */ } } bother(slp, msg) long slp; char *msg; { delay(slp); printf("\7\7\7"); printf(msg, buff1); printf("\r\n"); } X/* * delay is like sleep but does it in 100 sec pieces and * knows what zero means. */ delay(secs) long secs; { int n; while(secs > 0) { n = 100; secs = secs - 100; if(secs < 0) { n = n + secs; } if(n > 0) sleep(n); strcpy(thislogin, getlogin()); if(strcmp(origlogin, thislogin)) exit(0); } } #ifdef V6 char *getlogin() { #include <utmp.h> static struct utmp ubuf; int ufd; ufd = open("/etc/utmp", 0); seek(ufd, ttyn(0)*sizeof(ubuf), 0); read(ufd, &ubuf, sizeof(ubuf)); ubuf.ut_name[sizeof(ubuf.ut_name)] = 0; return(&ubuf.ut_name); } #endif X/* * return 1 if s is in the form of +[0-9]*h, 0 otherwise * */ int hoursp(s) char *s; { char numflg = 0; if(!*s) return 0; while(*s >= '0' && *s <= '9') s++; /* skip the number */ if(*s == 'h') return 1; return 0; } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 remind.c /bin/echo -n ' '; /bin/ls -ld remind.c fi /bin/echo 'Extracting remind.1l' sed 's/^X//' <<'//go.sysin dd *' >remind.1l X.TH REMIND 1 X.UC X.SH NAME remind \- remind you when you have to leave and why X.SH SYNOPSIS X.B remind [ -f ] [ -#otlm ] [ time ] ["reminder-message"] X.SH DESCRIPTION X.I Remind waits until the specified time or for the specified interval, then reminds you that you have to leave. You are reminded 5 minutes and 1 minute before the actual time, at the time, and every minute thereafter, unless you give the #otlm parameter, which is the number of messages telling you that you're too late that X.I remind will print before giving up. X.I Remind won't complain about errors if you give the -f option (ala rm(1)). When you log off, X.I Remind exits just before it would have printed the next message. X.PP Time can be expressed in a number of formats. The simplest is hhmm, where hh is the hour that you want to be reminded about, and mm is the minute. X.PP If you give hh as a 24 hour time (i.e. 0700 for 7 am, or 1900 for 7 pm), you will be reminded at that exact time of the current day. If it is past that time on the same day, then you will not be reminded. X.PP Otherwise (you gave it something like 700), you will be reminded within the next twelve hours. An alternate form for the tod is +mm where mm is the number of minutes for remind to hang out for; ie remind +240 "go to lunch" will tell remind to remind you in 4 hours to go to lunch. A much simpler way to do this is remind +4h "go to lunch", which will also remind you to go to lunch in four hours. X.PP If not enough arguments are given, X.I remind prompts with "When do you have to leave?". A reply of newline causes X.I remind to exit, otherwise the reply is assumed to be a time. Then, X.I remind prompts with "What do you have to do?". A reply of newline will cause remind to exit. This form is suitable for inclusion in a X.I .login or X.I .profile. X.PP Remind ignores interrupts, quits, and terminates. To get rid of it you should either log off or kill it giving its process id. X.SH SEE ALSO calendar(1), leave(1) X.SH AUTHORS Mark Horton X.PP Andrew Scott Beals X.SH BUGS X.I Remind is a pain in the ``neck''. X.PP If you do something like remind +24 "you've been hacking too long\\!", logout, login within remind's 100 sec sleep cycle, and login to the terminal that you started remind from, you will get reminded none the less. Perhaps X.I remind should look in utmp and check the login date instead of just checking to see if the same person is logged in. //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 remind.1l /bin/echo -n ' '; /bin/ls -ld remind.1l fi /bin/echo 'Extracting README' sed 's/^X//' <<'//go.sysin dd *' >README This directory contains the source for two programs; 1) calend - an appointment calendar maintainer 2) remind - a program that reminds you to log off the system and why; Calend is a program that takes apointments specified in a .calrc and notifies the user about them when the user wants to be notified. An example .calrc is as follows: : print out a message about bill's party on July 21 the week : before it; delete when done. ad *-7 7/21 Party at bill's on %2 : tell me by mail the week before the monthly rent is due. m *-7 {jan - dec} 1 %m2's Rent is due : remind me to get off the system for math class every mon wed and fri at 2. r {mon wed fri} * 1400 Go to math class : the week before its due, tell me about my insurance payment once 1 *-7 {jan 12, apr 14, sept 15, dec 10} insurance payment by %2 : tell me on the next payday, and then move the message forward two weeks. : (i.e. tell me about bi-weekly paydays) a+ sept 23 * +14 Payday today In addition, there is a shell script here called 'addcal' which makes it a little easier to add an entry to your .calrc. The remind program nags you to get off the system at some time. An example call is: remind 1830 'go home for dinner' which will nag you to get off the system for dinner at 6:30pm. This program is a modification of the 'leave' program. To install: 1) First modify the variable LOCDIR in the file "Makefile" to reflect, where on your system the executables should go. 2) Next, modify the config file globals.h to indicate where you chose to store the "remind" executable. 3) If you are on a USG system, then add a "#define USG" to globals.h and do a 'mv addcal.usg addcal'. 4) run 'make inst-all' which will make and install the executables and the manual entries. //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 README /bin/echo -n ' '; /bin/ls -ld README fi /bin/echo 'Extracting addcal' sed 's/^X//' <<'//go.sysin dd *' >addcal #! /bin/csh -f set rcfile=~/.calrc remtime="" movo="" movc="" mov="" remc="" noglob if (x$1 != x) set rcfile = $1 echo -n "Flags [<ra1mxd] " set flgs = $< while ("$flgs" == '?' || "$flgs" == ) echo "Flags:" echo "< - use alternate dates file" echo "r - remind at certain time" echo "a - print always during period" echo "1 - print once during period" ; echo "m - send mail" echo "x - execute program - a,1 say how often" echo "d - delete when finished" ; echo "" echo -n "Flags [ra1mxd] " ; set flgs = $< end echo $flgs | grep -s "<" if ($status == 0) then echo -n "Alternate file: "; set altfile = $< while ("$altfile" == '?' || "$altfile" == ) echo "The alternate file will be used as another dates file." echo -n "Alternate file: "; set altfile = $< end echo "< $altfile" echo "< $altfile" >> $rcfile exit 0 endif echo $flgs | grep -s "r" if ($status == 0) then echo -n "Remind time [hhmm]: " ; set remc = " " remtime = $< while ("$remtime" == '?') echo "Remind expects a four digit time, i.e. 2330." echo -n "Remind time [hhmm]: " ; set remtime = $< end endif echo $flgs | grep -s "d" if ($status == 1) then echo -n "Move forward [+<num>]: " set movc = "" mov = $< while ("$mov" == '?') echo "Enter months and days, eg: +3m2d, +14d, +1m" echo -n "Move forward [+<num>]: " set mov = $< end echo $mov | egrep -s "^\+" if ($status == 1) then if ("$mov" != no && "$mov" != n && "$mov" != ) echo "bad date - $mov." set mov = "" endif if ("$mov" != ) set movo = "+" movc = " " endif echo -n "Start date: " ; set date1 = $< while ("$date1" == '?') echo "Enter starting date; default is '*'" echo -n "Start date: " ; set date1 = $< end if ("$date1" == ) set date1 = "*" echo -n "End date: " ; set date2 = $< while ("$date2" == '?') echo "Enter ending date; default is '*'" echo -n "End date: " ; set date2 = $< end if ("$date2" == ) set date2 = "*" if ("$date1$date2" == "**") then echo "No dates given." exit 1 endif echo $flgs | grep -s "x" if ($status == 0) then set cmd echo -n "Command: " else echo -n "Message: " endif set msg = $< while ("$msg" == '?' || "$msg" == ) if ($?cmd) then echo "Enter command to be executed between $date1 and $date2" echo -n "Command: " else echo "Any message you want printed between $date1 and $date2" echo -n "Message: " endif set msg = $< end echo "$flgs$movo $date1 $date2 $mov$movc$remtime$remc$msg" echo "$flgs$movo $date1 $date2 $mov$movc$remtime$remc$msg" >>$rcfile //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 755 addcal /bin/echo -n ' '; /bin/ls -ld addcal fi /bin/echo 'Extracting addcal.1l' sed 's/^X//' <<'//go.sysin dd *' >addcal.1l X.TH CALENDAR 1 X.SH NAME addcal \- Add an appointment to an appointment calendar X.SH SYNOPSIS X.B addcal [ X.B <file> ] X.SH DESCRIPTION X.IR addcal is used to add entries to an appointment calendar file as used by X.B calend. X.PP X.B addcal is a simple shell script that makes sure that all required fields are in the entry. It prompts for each field and any prompt can be given a "?" to get help. X.PP if an argument is given, then it uses that argument as the dates file. Otherwise, it uses $HOME/.calrc. X.SH AUTHOR Bruce Israel X.SH FILES \&.calrc which contains the file of dates. X.SH "SEE ALSO" calend(1) //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 addcal.1l /bin/echo -n ' '; /bin/ls -ld addcal.1l fi /bin/echo 'Extracting addcal.usg' sed 's/^X//' <<'//go.sysin dd *' >addcal.usg #! /bin/sh ## modified for sh instead of csh by sfjec!mjm doentry() ## mjm: function called once for each entry { remtime="" movo="" movc="" mov="" remc="" set -f ## mjm: noglob ?? echo "Flags [<ra1mxd]: \c" read flgs while [ "$flgs" = "?" -o "$flgs" = "" ] do echo "Flags:" echo "< - use alternate dates file" echo "r - remind at certain time" echo "a - print always during period" echo "1 - print once during period" echo "m - send mail" echo "x - execute program - a,1 say how often" echo "d - delete when finished" echo "q - quit; exit $0 now" ## mjm echo "\nFlags [<ra1mxdq]: \c" read flgs done set -- `getopt "<ra1mxdq" "-$flgs"` if [ $? != 0 ] then echo "Usage: Legal flags are: <ra1mxdq" return 1; fi aflg=0 ## not used flg1=0 ## not used mflg=0 ## not used xflg=0 dflg=0 for OPT in $* do case $OPT in -q) exit 255;; ## mjm: No more input -\<) echo "Alternate file: \c"; read altfile; while [ "$altfile" = "?" -o "$altfile" = "" ] do echo "The alternate file will be used as another dates file." echo "Alternate file: \c"; read altfile; done echo "< $altfile" echo "< $altfile" >> $rcfile return 0;; -r) echo "Remind time [hhmm]: \c"; remc=" "; read remtime; while [ "$remtime" = "?" ] do echo "Remind expects a four digit time, i.e. 2330." echo "Remind time [hhmm]: \c"; read remtime; done;; -a) aflg=1;; -1) flg1=1;; -m) mflg=1;; -x) xflg=1;; -d) dflg=1;; esac done if [ "$dflg" = "0" ] then echo "Move forward [+<num>]: \c" movc=""; read mov while [ "$mov" = "?" ] do echo "Enter months and days, eg: +3m2d, +14d, +1m" echo "Move forward [+<num>]: \c" read mov done case $mov in ## mjm was: echo $mov | egrep "^\+" +*) stat=0;; *) stat=1;; esac if [ "$stat" = "1" ] then if [ "$mov" != "no" -a "$mov" != "n" -a "$mov" != "" ] then echo "bad date - $mov." fi mov="" fi if [ "$mov" != "" ] then movo="+"; movc=" "; fi fi echo "Start date: \c"; read date1 while [ "$date1" = "?" ] do echo "Enter starting date; default is '*'" echo "Start date: \c"; read date1; done if [ "$date1" = "" ] then date1="*"; fi echo "End date: \c"; read date2; while [ "$date2" = "?" ] do echo "Enter ending date; default is '*'" echo "End date: \c"; read date2; done if [ "$date2" = "" ] then date2="*"; fi if [ "$date1$date2" = "**" ] then echo "No dates given." return 1; fi if [ "$xflg" = "1" ] then echo "Command: \c"; else echo "Message: \c"; fi read msg; while [ "$msg" = "?" -o "$msg" = "" ] do if [ "$xflg" = "1" ] then echo "Enter command to be executed between $date1 and $date2" echo "Command: \c" else echo "Any message you want printed between $date1 and $date2" echo "Message: \c" fi read msg; done echo "$flgs$movo $date1 $date2 $mov$movc$remtime$remc$msg" echo "$flgs$movo $date1 $date2 $mov$movc$remtime$remc$msg" >>$rcfile return 0; } ## mjm: Begins here; call function doentry repeatedly. rcfile=$HOME/.calrc if [ "x$1" != "x" ] then rcfile=$1 fi E=1 EC=1 while [ "$E" = "0" -o "$E" = "1" ] do doentry; E="$?" if [ "$E" = "0" ] then EC=0 ## Got at least one success fi if [ "$E" = "255" ] then exit 0; fi done exit $EC; ## 0, at least one success; 1, no entries added //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 755 addcal.usg /bin/echo -n ' '; /bin/ls -ld addcal.usg fi -- Bruce Israel University of Maryland, Computer Science {rlgvax,seismo}!umcp-cs!israel (Usenet) israel@Maryland (Arpanet)