Subject: calendar(1) extension... RFC
To: None <tech-userlevel@netbsd.org>
From: Mason Loring Bliss <mason@acheron.middleboro.ma.us>
List: tech-userlevel
Date: 11/17/2002 01:45:08
--GV0iVqYguTV4Q9ER
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
What do you folks think about this? It's a trivially small amount of code
that makes calendar(1) truly useful, as opposed to fairly marginal in
utility.
To summarize the change, this adds a flag, '-x', that extends calendar(1)'s
syntax a bit, allowing the processing of calendar file lines like this:
07/01 +15@1962 Matt
This would start noting this event fifteen days in advance, and the output
would look something like this:
In 5 days: 12/19 Matt (1962: 40 years ago)
The +foo and @bar markers can be placed anywhere in the string, in any
order, and they don't have to be adjacent. If they are preceded by a space
character, this is omitted from the final output along with the markers
themselves.
The point of this is that you can set an arbitrary amount of notice for
events, thus receiving sufficient and persistent warning (sufficient being
something you define) to prepare for birthdays, anniversaries, and other
such events. As it is now, calendar(1) provides no way to extend the amount
of warning you get for events without getting a large amount of advance
warning for *everything*, which, to me, is a bit annoying.
An important thing to note is that if you don't do anything to your
calendar files and don't use the '-x' switch, effectively nothing changes.
Here's the patch, for your inspection. Thanks in advance for comments. I'd
like to commit this sometime, if folks don't disapprove of it. (About the
only change I can think of is requiring a '-v' flag to turn on the "in foo
days" prefix, independant of the '-x' flag...)
--- /usr/src/usr.bin/calendar/calendar.c Tue Dec 4 10:55:32 2001
+++ calendar.c Sun Nov 17 01:30:11 2002
@@ -78,6 +78,7 @@
static char *fname =3D "calendar", *datestr =3D NULL;
static struct passwd *pw;
static int doall;
+static int extendsyntax;
static char path[MAXPATHLEN + 1];
=20
/* 1-based month, 0-based days, cumulative */
@@ -86,7 +87,8 @@
{ 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
};
static struct tm *tp;
-static int *cumdays, offset, yrdays;
+static int *cumdays, offset, yrdays, yearofevent, yearselapsed,
+ haveyear, realoffset;
static char dayname[10];
=20
static struct iovec header[] =3D {
@@ -118,6 +120,9 @@
static void getmmdd(struct tm *, char *);
static int getmonth(char *);
static int isnow(char *);
+static int geteventoffset(char *);
+static void getyears(char *);
+static void stripmarker(char *, char *);
static FILE *opencal(void);
static void settime(void);
static void usage(void) __attribute__((__noreturn__));
@@ -130,7 +135,7 @@
int ch;
const char *caldir;
=20
- while ((ch =3D getopt(argc, argv, "-ad:f:l:w:")) !=3D -1)
+ while ((ch =3D getopt(argc, argv, "-ad:f:l:w:x")) !=3D -1)
switch (ch) {
case '-': /* backward contemptible */
case 'a':
@@ -152,6 +157,9 @@
case 'w':
atodays(ch, optarg, &weekend);
break;
+ case 'x':
+ extendsyntax =3D 1;
+ break;
case '?':
default:
usage();
@@ -185,7 +193,7 @@
{
int printing;
FILE *fp;
- char *line;
+ char *line, *plural;
=20
if ((fp =3D opencal()) =3D=3D NULL)
return;
@@ -194,8 +202,33 @@
continue;
if (line[0] !=3D '\t')
printing =3D isnow(line) ? 1 : 0;
- if (printing)
- (void)fprintf(fp, "%s\n", line);
+ if (printing) {
+ if (extendsyntax) {
+ if (realoffset =3D=3D 0)
+ (void)fputs("Today: ", fp);
+ else if (realoffset =3D=3D 1)
+ (void)fputs("Tomorrow: ", fp);
+ else
+ (void)fprintf(fp, "In %d days: ",
+ realoffset);
+ }
+ (void)fprintf(fp, "%s", line);
+ if (extendsyntax && haveyear) {
+ plural =3D abs(yearselapsed) =3D=3D 1 ? "" : "s";
+ if (yearselapsed =3D=3D 0)
+ (void)fprintf(fp, " (%d: this year)",
+ yearofevent);
+ else if (yearselapsed < 0)
+ (void)fprintf(fp, " (%d: in %d year%s)",
+ yearofevent, abs(yearselapsed),
+ plural);
+ else
+ (void)fprintf(fp,
+ " (%d: %d year%s ago)", yearofevent,
+ yearselapsed, plural);
+ }
+ (void)fputc('\n', fp);
+ }
free(line);
=20
}
@@ -240,7 +273,8 @@
isnow(endp)
char *endp;
{
- int day, flags, month, v1, v2;
+ int day, flags, month, v1, v2, eventoffset;
+ char *savebuf =3D endp;
=20
#define F_ISMONTH 0x01
#define F_ISDAY 0x02
@@ -273,16 +307,89 @@
day =3D tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
day =3D cumdays[month] + day;
=20
- /* if today or today + offset days */
- if (day >=3D tp->tm_yday && day <=3D tp->tm_yday + offset)
+ /* if event-specific offset present, don't use standard offset */
+ if (extendsyntax) {
+ eventoffset =3D geteventoffset(savebuf);
+ (void) getyears(savebuf);
+ if (haveyear)
+ yearselapsed =3D tp->tm_year - (yearofevent - 1900);
+ } else
+ eventoffset =3D offset;
+
+ /* if today or today + eventoffset days */
+ if (day >=3D tp->tm_yday && day <=3D tp->tm_yday + eventoffset) {
+ realoffset =3D day - tp->tm_yday;
return (1);
+ }
/* if number of days left in this year + days to event in next year */
- if (yrdays - tp->tm_yday + day <=3D offset)
+ if (yrdays - tp->tm_yday + day <=3D eventoffset) {
+ realoffset =3D yrdays - tp->tm_yday + day;
return (1);
+ }
return (0);
}
=20
static int
+geteventoffset(buf)
+ char *buf;
+{
+ int eventoffset;
+ char *p;
+
+ /* see if we have an offset marker */
+ if ((p =3D strchr(buf, '+')) =3D=3D '\0')
+ return (offset);
+
+ if (sscanf((char *) (p + 1), "%i", &eventoffset) =3D=3D 1) {
+ (void) stripmarker(buf, p);
+ return (eventoffset);
+ }
+
+ return (offset);
+}
+
+static void
+getyears(buf)
+ char *buf;
+{
+ char *p;
+
+ /* see if we have an offset marker */
+ if ((p =3D strchr(buf, '@')) =3D=3D '\0') {
+ haveyear =3D 0;
+ return;
+ }
+
+ if (sscanf((char *) (p + 1), "%i", &yearofevent) =3D=3D 1) {
+ (void) stripmarker(buf, p);
+ haveyear =3D 1;
+ return;
+ }
+
+ haveyear =3D 0;
+ return;
+}
+
+static void
+stripmarker(buf, mark)
+ char *buf, *mark;
+{
+ int i, cal_buffsize;
+ char *marker =3D mark;
+
+ cal_buffsize =3D strlen(buf);
+
+ /* find extent of marker; remove marker and leading space */
+ i =3D (marker - buf) + 1; /* offset to start of digits */
+ while (isdigit(buf[i]) && i < cal_buffsize)
+ ++i;
+ if (isspace(*(marker - 1)))
+ --marker;
+ memmove((void *) marker, (void *) (buf + i), cal_buffsize - i + 1);
+}
+
+
+static int
getfield(p, endp, flags)
char *p, **endp;
int *flags;
@@ -516,6 +623,6 @@
usage(void)
{
(void)fprintf(stderr, "Usage: %s [-a] [-d MMDD[[YY]YY]"
- " [-f fname] [-l days] [-w days]\n", getprogname());
+ " [-f fname] [-l days] [-w days] [-x]\n", getprogname());
exit(1);
}
--- /usr/src/usr.bin/calendar/calendar.1 Thu Feb 7 20:36:20 2002
+++ calendar.1 Sun Nov 17 01:22:05 2002
@@ -46,6 +46,7 @@
.Op Fl l Ar days
.Op Fl w Ar days
.Op Fl d Ar MMDD[[YY]YY]
+.Op Fl x
.Sh DESCRIPTION
The
.Nm
@@ -82,6 +83,12 @@
value is two, which causes
.Nm
to print entries through the weekend on Fridays.
+.It Fl x
+Allow for extended syntax of two forms, +n where n is one or more digits
+denoting the number of days' warning this event is to be given, and @y,
+where y is the year in which the event has taken or will take place. Either
+option may be individually present or absent. Entries will, in any case, be
+printed with slightly more verbose output format.
.El
.Pp
Lines should begin with a month and day.
--=20
Mason Loring Bliss mason@acheron.middleboro.ma.us Ewige Blumenkraft!
https://www.deadsexy.org/ awake ? sleep : random() & 2 ? dream : sleep;
--GV0iVqYguTV4Q9ER
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (NetBSD)
iD8DBQE91zr0ykMMY715wXIRAuATAJ9DrUa3aKjye9cfXFrOtG7BADVzWgCghdnV
yDdJX2waM21+S69iIpQmUeQ=
=aYh+
-----END PGP SIGNATURE-----
--GV0iVqYguTV4Q9ER--