calendar-like program
Oscar M. Nierstrasz
oscar at utcsrgv.UUCP
Sun May 13 03:50:06 AEST 1984
echo README
sed 's/^|//' > README << 'Rosebud'
|Here are a few shell scripts and a C program for dealing with future
|events. `dates' is a program similar to `calendar' except that you can
|ask it to report future events as well as today's. I find it useful
|for birthdays, seminars, and anything that needs reminding more than a
|day in advance. See `dates.1'. I've been using the program for quite
|a while now, and believe it to be stable (recently caught a leap-year bug).
|
|`events' is a shell script that calls `dates' on a single, publicly
|accessible file. A flag lets you edit it while temporarily locking out
|other attempts to do so. I use it for keeping track of upcoming films,
|but it clearly has other applications.
|
|`remind' is a shell script that does more-or-less what `leave' does.
|The difference is that it won't go away if you log out, and it will
|contact you even if you change terminals. It calls the enclosed shell
|script `hi' to do this.
|
|Note: fix paths in `events' and `remind'.
|
|Enjoy.
| Oscar Nierstrasz
|
|{ akgua allegra decvax decwrl floyd ihnp4 linus ... }!utcsrgv!oscar
Rosebud
chmod 0644 README
echo dates.1
sed 's/^|//' > dates.1 << 'Rosebud'
|.TH DATES 1
|.UC
|.SH NAME
|dates \- report upcoming events
|.SH SYNOPSIS
|.B dates
|[ -t days ] file ...
|.SH DESCRIPTION
|.I Dates
|examines a file containing information about upcoming events
|and reports any that are to take place within the next seven days.
|.PP
|The event file is expected to contain entries of the form:
|.IP
|mmdd
|.br
|event information
|.br
| ...
|.PP
|if that event takes place on a single day, or:
|.IP
|mmdd-mmdd
|.br
|event information
|.br
| ...
|.PP
|if it takes place over a range of dates.
|Comment lines beginning with a '#' are ignored.
|.PP
|For example, if your event file contains an entry for:
|.IP
|1206
|.in +5
|Saint Nicholas' Day!
|.PP
|then
|.IP
|dates eventfile
|.PP
|will yield:
|.IP
|Tue Dec 6:
|.in +5
|Saint Nicholas' Day!
|.PP
|assuming, of course, that it falls within seven days.
|Events occurring the same day or the next are reported as
|taking place "Today" or "Tomorrow".
|.PP
|You can shorten or lengthen the time period for which events are
|reported by using the '-t' flag.
|For example:
|.IP
|dates -t 0 eventfile
|.PP
|will report only those events taking place today.
|.PP
|Event entries may be listed in any order, but be warned that
|.I dates
|does not sort its output.
|Upcoming events are reported in the order that they appear.
|Obsolete entries are not deleted by
|.I dates
|since it has no way of telling that an event will not recur
|next year (like birthdays).
|.PP
|It is often useful to put a call to
|.I dates
|in your .login or .logout (with the "C" shell) or your .profile
|(with the Bourne shell).
|.SH BUGS
|Doesn't seem to work quite right at midnight or New Year's.
|.SH AUTHOR
|Oscar Nierstrasz at the University of Toronto.
|.SH SEE ALSO
|events(1), calendar(1), at(1), leave(1), time(2).
Rosebud
chmod 0644 dates.1
echo dates.c
sed 's/^|//' > dates.c << 'Rosebud'
|
|/* FILE: DATES.C Jan. 1983
| *
| * AUTHOR: OSCAR NIERSTRASZ
| *
| * Usage: dates [-t <days>] <file> ...
| *
| * Checks files of events and warns you if they
| * are coming up soon.
| * Flags and files may appear in any order.
| *
| * -t sets the number of days
| *
| * Assumes files have either structure:
| * mmdd
| * event
| * ...
| * mmdd-mmdd
| * event
| * ...
| */
|
|#include <stdio.h>
|#include <sgtty.h>
|#include <sys/types.h>
|#include <sys/timeb.h>
|#define TRUE 1
|#define FALSE 0
|#define MAX 500
|
|#define EOS '\0'
|#define RANGE '-'
|#define COMMENT '#'
|
|#define DLEN 30 /* date buffer length */
|
|#define NEXT 1 /* NEXT: use next year's date if this */
|#define THIS 0 /* year's has passed; THIS: don't */
|
|#define TDIF 5 /* 5 hours earlier than Greenwich */
|#define DAYS 7 /* default warning period */
|#define num(n) (n - '0')
|#define dysize(yr) (365 + (((yr%4)==0)?1:0))
|#define dmsize(yr, m) (dm[m] + (((yr % 4) == 0) && m >= 2))
|#define month_name(n) ((n < 1 || n > 12) ? name[0] : name[n])
|#define day_name(n) weekday[((n)%7+7)%7]
|
|long *time();
|int days = DAYS, putline = FALSE;
|
|struct ymdhms{
| int year;
| int month;
| int day;
| int hour;
| int min;
| int sec;
| int wday;
|} t; /* Today's date */
|
|static int dm[13] =
|{
| 0,
| 31,
| 59,
| 90,
| 120,
| 151,
| 181,
| 212,
| 243,
| 273,
| 304,
| 334,
| 365
|};
|
|static char *name[] = {
| "illegal month",
| "Jan",
| "Feb",
| "March",
| "April",
| "May",
| "June",
| "July",
| "Aug",
| "Sept",
| "Oct",
| "Nov",
| "Dec"
| };
|
|static char *weekday[] = {
| "Wed",
| "Thu",
| "Fri",
| "Sat",
| "Sun",
| "Mon",
| "Tue"
| };
|
|char *nom(s)
|char *s;
|{
| char *c;
|
| c = s;
| while(*c != EOS){
| if(*c == ','){
| *c = EOS;
| c++;
| while(*c == ' ')
| c++;
| return(c);
| }
| c++;
| }
| return(c);
|}
|
|main(argc, argv)
|int argc;
|char *argv[];
|{
| FILE *fp;
| int i=1, ll;
| char s[MAX];
|
| if(argc == 1){
| fprintf(stderr, "Usage: dates [-t <days>] <file> ...\n");
| exit(1);
| }
| rtime();
| while(i<argc){
| if(argv[i][0] == '-'){
| switch(argv[i][1]){
| case 't':
| i++;
| if(i == argc){
| fprintf(stderr, "dates: missing arg\n");
| }
| else days = atoi(argv[i]);
| break;
| default:
| fprintf(stderr, "dates: unknown flag %s\n", argv[i]);
| }
| }
| else{
| if((fp = fopen(argv[i], "r")) == NULL)
| fprintf(stderr, "dates: can't open %s\n", argv[i]);
| else{
| while((ll = getline(s, fp)) != EOF){
| if(ll == MAX)
| fprintf(stderr, "dates: line too long: %s\n", s);
| if(s[0] != COMMENT)
| if(data(s)){
| if (putline)
| printf("%s\n", s);
| }
| else tcheck(s);
| }
| fclose(fp);
| }
| }
| i++;
| }
|}
|
|rtime()
|{
|/* sets today's date in t. */
|
| int i, days;
| long tbuf;
|
| time(&tbuf); /* seconds */
| t.sec = tbuf % 60;
| tbuf = tbuf / 60; /* minutes */
| t.min = tbuf % 60;
| tbuf = tbuf / 60 - TDIF; /* hours */
| t.hour = tbuf % 24;
| tbuf = 1 + tbuf / 24; /* days */
| t.wday = tbuf % 7;
| t.year = 1970;
| days = dysize(t.year);
| while(tbuf > days){
| (t.year)++;
| tbuf -= days;
| days = dysize(t.year);
| }
| for(i=1; i<=12; i++){
| days = dmsize(t.year, i);
| if(tbuf < days)
| break;
| }
| t.month = i;
| t.day = tbuf - dmsize(t.year, i-1);
|}
|
|tcheck(s)
|char *s;
|{
| char *sn, *f, date1[DLEN], date2[DLEN];
| int dif1, dif2;
|
| getday(s, &dif1, date1, NEXT);
| if(s[4] == EOS){
| if(dif1 <= days){
| putline = TRUE;
| printf("%s :\n", date1);
| }
| else putline = FALSE;
| }
| else if(s[4] == RANGE){
| getday(s+5, &dif2, date2, NEXT);
| /* if date1 has passed but date2 hasn't, */
| /* force getday to use this year for date1 */
| if(dif2 < dif1)
| getday(s, &dif1, date1, THIS);
| if((dif1 <= days) && (dif2 >= 0)){
| putline = TRUE;
| printf("%s to %s :\n", date1, date2);
| }
| else putline = FALSE;
| }
|}
|
|getday(s, pdif, date, next)
|char *s, *date;
|int *pdif, next;
|{
| int m, d, dif;
|
| m = num(s[0])*10 + num(s[1]);
| d = num(s[2])*10 + num(s[3]);
| *pdif = dif = dmsize(t.year, m-1) + d
| - (dmsize(t.year, t.month-1) + t.day);
| if(next && dif < 0)
| *pdif = dif = dysize(1+t.year) + dmsize(1+t.year, m)
| + d - (dmsize(t.year, t.month) + t.day);
| if(dif == -1)
| sprintf(date, "Yesterday");
| else if(dif == 0)
| sprintf(date, "Today");
| else if(dif == 1)
| sprintf(date, "Tomorrow");
| else
| sprintf(date, "%s %s %d", day_name(dif+t.wday),
| month_name(m), d);
|}
|data(s)
|char *s;
|{
| /* Returns TRUE if line is data */
| /* FALSE if date line */
| /* Acceptable formats are "mmdd" */
| /* and "mmdd-mmdd" */
| int i;
|
| for(i=0; i<4; i++)
| if(s[i] < '0' || '9' < s[i])
| return(TRUE);
| if(s[4] == EOS)
| return(FALSE);
| /* date may be a range */
| if(s[4] == RANGE){
| /* Can't have "nested" ranges */
| if(s[9] != EOS)
| return(TRUE);
| return(data(s+5));
| }
| return(TRUE);
|}
|getline(s,file)
| char *s;
| FILE *file;
|{
| /* get a line of input up to MAX characters */
| /* return length of input or EOF or MAX */
| int i=0;
| char c;
|
| while((c=fgetc(file)) != '\n'){
| if(c == EOF){
| rewind(file);
| return(EOF);
| }
| s[i] = c;
| i++;
| if(i == MAX){
| s[i-1] = '\0';
| return(MAX);
| }
| }
| s[i] = '\0';
| return(i);
|}
Rosebud
chmod 0644 dates.c
echo events
sed 's/^|//' > events << 'Rosebud'
|#! /bin/sh
|# events [N]|-[vhe]|[-em]|[-rm]
|# List today's events or events for the next N days.
|# With the -v, -h, -e or -em flags, vi, hed, ed or emacs
|# are invoked on the database.
|# The -rm flag removes the lock file.
|# Make sure that $e is writeable by all.
|# $B is the location of the `dates' program.
|# Author : Oscar Nierstrasz @ ..!utcsrgv!oscar
|e=/usr/pub/events
|B=/usr/local
|l=/tmp/lock_events
|u="Usage: events [#days] | [-vi] | [-ed] | [-hed] | [-emacs]"
|case $# in
|0 ) arg=0 ;;
|1 ) arg=$1 ;;
|* ) echo "$u" 1>&2
| exit ;;
|esac
|case $arg in
|-v ) ed=vi ;;
|-vi ) ed=vi ;;
|-h ) ed=hed ;;
|-hed ) ed=hed ;;
|-e ) ed=ed ;;
|-ed ) ed=ed ;;
|-em ) ed=emacs ;;
|-emacs ) ed=emacs ;;
|-rm ) rm -f $l
| exit ;;
|-* ) echo "events : unknown flag" 1>&2
| exit ;;
|[0-9]* ) $B/dates -t $arg $e
| exit ;;
|* ) echo "$u" 1>&2
| exit ;;
|esac
|
|umask 0777
|if (echo > $l) 2> /dev/null
|then
| umask 022
| $ed $e
| rm -f $l
|else
| echo "Sorry, someone is already editing the events file!" 1>&2
|fi
Rosebud
chmod 0755 events
echo hi
sed 's/^|//' > hi << 'Rosebud'
|#! /bin/sh
|# hi user msg
|# Write a message on every tty that a user is logged onto.
|# With the -m flag, the message will be mailed if the user
|# is not logged in (useful in shell scripts).
|# Author : Oscar Nierstrasz @ ..!utcsrgv!oscar
|
|case $# in
|0 ) echo "Usage: hi user [-m] msg"
| echo " hi user -f <file> ..."
| echo " <cmd> | hi user"
| exit ;;
|esac
|u=$1
|shift
|case $# in
|0 ) f=/tmp/hi$$
| cat > $f ;;
|1 ) ;;
|* ) case $1 in
| -f ) shift
| f=$* ;;
| -m ) shift
| m=y ;;
| esac ;;
|esac
|w=`who | fgrep $u`
|case $w in
|"" ) case $m in
| y ) echo "$*" | mail $u ;;
| *) echo "$u not logged in" ;;
| esac ;;
|* ) case $f in
| "" ) echo "$w" | sed -e "s%^.*tty%/dev/tty%" -e "s/ .*$//" \
| -e "s/^/echo \"$*\" > /" | /bin/sh ;;
| * ) echo "$w" | sed -e "s%^.*tty%/dev/tty%" -e "s/ .*$//" \
| -e "s%^%cat $f > %" | /bin/sh ;;
| esac ;;
|esac
|rm -f /tmp/hi$$
Rosebud
chmod 0755 hi
echo remind
sed 's/^|//' > remind << 'Rosebud'
|#! /bin/sh
|# remind [time] [-m|-c] [message] ... 840214
|# Echo a message at a later time.
|# With the -m flag, `mail' is used if you have logged off.
|# With the -c flag, the message is executed as a command.
|# Calls the shell script `hi' to get you wherever you are!
|# SEE ALSO : at(1), leave(1).
|# Author : Oscar Nierstrasz @ utcsrgv!oscar
|C=/u3/oscar/cmd
|case $# in
|0 ) w='{ split($4, from, ":") ; print from[1] ":" from[2] }'
| echo "It's" `date | awk "$w"`
| echo -n "When shall I call you? : "
| read t ;;
|* ) t=$1
| shift ;;
|esac
|case $t in
|[0-9] ) t=$t:00 ;;
|[0-1][0-9] ) t=$t:00 ;;
|2[0-4] ) t=$t:00 ;;
|[0-9]:[0-5][0-9] ) ;;
|[0-1][0-9]:[0-5][0-9] ) ;;
|2[0-9]:[0-5][0-9] ) ;;
|* ) echo "Enter time as hh or hh:mm"
| exit ;;
|esac
|case $# in
|0 ) echo -n "Message? : "
| read m ;;
|* ) case $1 in
| -c ) shift
| c=$* ;;
| -m ) hi=-m
| shift
| m=$* ;;
| * ) m=$* ;;
| esac ;;
|esac
|case $c in
|"" ) case $m in
| "" ) m="Hi! -- It's $t" ;;
| * ) m="It's $t -- $m" ;;
| esac ;;
|esac
|# Awk script:
|w='NR == 1 { split($4, from, ":") }
|NR == 2 { split($1, to, ":") }
|END {
| hrs = to[1] - from[1]
| mins = to[2] - from[2]
| time = 60 * hrs + mins
| if (time < 0) {
| time += 60 * 12
| if ((to[1] > 12) || (time < 0))
| time += 60 * 12
| }
| print 60 * time
| }'
|s=`(date ; echo $t ) | awk "$w"`
|case $s in
|60 ) ;;
|* ) x="s" ;;
|esac
|echo "See you in" `expr $s / 60` "minute$x ..."
|case $c in
|"" ) (sleep $s ; $C/hi $USER $hi "$m") & ;;
|* ) (sleep $s ; echo "$c" | /bin/sh) & ;;
|esac
Rosebud
chmod 0755 remind
More information about the Comp.sources.unix
mailing list