Compare commits

...

61 Commits

Author SHA1 Message Date
David F. Skoll
e18b4ed119 Update copyright. 2009-05-31 13:06:05 -04:00
David F. Skoll
51f6ffc093 Document changes. 2009-05-31 13:05:05 -04:00
David F. Skoll
72de7c6b14 Make CallFunc and built-in functions re-entrant. 2009-05-26 22:35:57 -04:00
David F. Skoll
bd4785d631 Remove spurious trigger() function calls from examples.
Bump version to 3.1.7
2009-05-16 10:56:12 -04:00
David F. Skoll
cb08f12470 Add another test. 2009-05-16 10:47:54 -04:00
David F. Skoll
04146db69b More man page updates. 2009-05-16 10:47:10 -04:00
David F. Skoll
d3fe045a39 Make slide function diagnose "Can't OMIT every weekday" 2009-05-16 10:42:43 -04:00
David F. Skoll
2be1e16087 Add some tests. 2009-05-16 10:30:25 -04:00
David F. Skoll
051e44ae3e Update man page. 2009-05-16 10:22:43 -04:00
David F. Skoll
6d5ae7a258 Allow short-hand date specs after UNTIL and SCANFROM.
Start updating man page.
2009-05-16 10:07:57 -04:00
David F. Skoll
2e69e140eb Accept a T_Date or T_DateTime on cmdline to set now() and today(). 2009-05-12 22:46:01 -04:00
David F. Skoll
516c4e2c39 Allow literal dates and datetimes in REM and OMIT statements.
This lets us avoid cluttering up files with [trigger(expr)]; we can
use [expr] directly.
2009-05-09 16:41:15 -04:00
David F. Skoll
b58ed62000 Simplify. 2009-05-09 00:17:11 -04:00
David F. Skoll
c685818783 Use macro to refer to RetVal.v.val 2009-05-09 00:10:45 -04:00
David F. Skoll
3e20ce56c9 Add the slide(date, amt [,localomits]) built-in function. 2009-05-09 00:07:59 -04:00
David F. Skoll
dd8d67f659 Update man page. 2009-02-03 23:11:50 -05:00
David F. Skoll
5ef4061819 Let Remind accept a date of the form YYYY-MM-DD on cmdline. 2009-02-03 23:08:27 -05:00
David F. Skoll
a146a0c819 Update WHATSNEW; fix typo in man page. 2008-11-16 11:01:01 -05:00
David F. Skoll
0f5a93cdf1 Fix up man page. 2008-11-16 10:51:10 -05:00
David F. Skoll
7db51e913e Clarify WEEK example. 2008-11-15 09:24:09 -05:00
David F. Skoll
93ac1aebf7 Document WEEK special. Clean up rem2ps handling of WEEK. 2008-11-15 09:20:54 -05:00
David F. Skoll
56ebedb9de Proper implementation of WEEK special. 2008-11-14 17:02:51 -05:00
David F. Skoll
e87d33de50 Handle the WEEK special. 2008-11-14 16:56:08 -05:00
David F. Skoll
a5774fd793 Document weekno() function. 2008-11-14 16:16:13 -05:00
David F. Skoll
adb60f3400 Fix example in man page. 2008-11-14 16:07:25 -05:00
David F. Skoll
47a0f63caa Fix tests. 2008-10-05 14:29:31 -04:00
David F. Skoll
30a385a7bb Fix bug in IsTopLevel. 2008-10-05 14:29:03 -04:00
David F. Skoll
9f2ae1773c Document evaltrig. 2008-10-05 14:11:58 -04:00
David F. Skoll
f470297958 Make max. string length controllable with $MaxStringLen system variable. 2008-10-05 13:49:45 -04:00
David F. Skoll
93dfc7995c Fix man page. 2008-09-23 22:39:12 -04:00
David F. Skoll
c96869817f Rejigger infrastructure to detect recursive OMITFUNC calls in evaltrig() 2008-09-23 22:21:39 -04:00
David F. Skoll
1bffa0e00b Allow any of the args to date() function to be a date,
in which case we just extract the appropriate part.
2008-09-20 11:07:33 -04:00
David F. Skoll
36035dda01 Issue a warning if we detect a SCANFROM used in two-arg evaltrig(). 2008-09-20 00:14:13 -04:00
David F. Skoll
50a15cf089 Make evaltrig return a DATETIME if there's an AT clause. 2008-09-20 00:03:38 -04:00
David F. Skoll
b59d4ed4a4 Add "evaltrig" function. 2008-09-19 23:49:11 -04:00
David F. Skoll
4c53710279 Set maximum string length to 65535 to minimize chances of self-DOS. 2008-09-19 23:28:19 -04:00
David F. Skoll
2274e88485 Remove extraneous semicolon 2008-09-19 23:10:57 -04:00
David F. Skoll
984a4677f2 Clean up funcs.c; add weekno function for ISO week number. 2008-09-19 23:08:15 -04:00
David F. Skoll
5e3dc54725 Document sorting of timed vs. untimed reminders.
Add an $UntimedFirst system variable.
2008-09-18 17:30:31 -04:00
David F. Skoll
53a7bf9773 Make tests pass. 2008-09-18 17:20:09 -04:00
David F. Skoll
1dcc3897d6 Allow sorting of untimed before timed. 2008-09-18 17:17:38 -04:00
David F. Skoll
fbc0375739 Fix bug if MON DAY WKDAY crosses year boundary. 2008-09-16 22:10:09 -04:00
David F. Skoll
4a74c03fa4 Small man-page fix. 2008-08-31 15:51:25 -04:00
David F. Skoll
d8833e6ce2 Updated man page. 2008-08-31 15:44:57 -04:00
David F. Skoll
2b8b9a56aa Fix typo. 2008-08-31 10:32:25 -04:00
David F. Skoll
85a8ebb357 Slight efficiency improvement in OMIT testing. 2008-08-31 10:30:59 -04:00
David F. Skoll
a67d9e2524 Change behaviour: OMITFUNC ignores local/global OMIT context. Only sane
way to solve garbage-day problem; also allows for more flexibility.
2008-08-31 10:29:28 -04:00
David F. Skoll
6845e72fd5 Communicate errors back for bad OMITFUNCs. 2008-08-30 22:10:06 -04:00
David F. Skoll
0ab977fa05 Whitespace cleanup 2008-08-30 21:43:38 -04:00
David F. Skoll
ad64a12b2a Update man page. 2008-08-30 16:35:48 -04:00
David F. Skoll
cfde4b50bb Updated man page. 2008-08-29 21:28:25 -04:00
David F. Skoll
f302c8eb95 Document OMITFUNC and fix huge bug. :-) 2008-08-29 21:22:48 -04:00
David F. Skoll
7ecc355358 Add test for OMITFUNC. 2008-08-29 21:03:01 -04:00
David F. Skoll
a52216d7e7 Update test.cmp for version. 2008-08-29 20:56:22 -04:00
David F. Skoll
8d8d4b667d Implement OMITFUNC clause in REM command. 2008-08-29 20:48:58 -04:00
David F. Skoll
670369121e Remove -a flag from "ShowTodaysReminders" 2008-08-28 12:29:38 -04:00
David F. Skoll
4365e580ee If main reminder file is a directory and AppendFile does not exist,
create AppendFile.
2008-04-16 21:54:05 -04:00
David F. Skoll
a8a09a905e Update test.cmp for new version. 2008-04-16 21:45:58 -04:00
David F. Skoll
dbb7381eb1 Update version number in configure. 2008-04-16 21:44:44 -04:00
David F. Skoll
aa3531a6bf Merge branch 'master' of ssh://source.roaringpenguin.com/home/dfs/personal-git-repos/Remind 2008-04-16 13:35:36 -04:00
David F. Skoll
2848203d75 Note new behaviour: set var [expr] no longer works. 2008-04-16 13:34:38 -04:00
36 changed files with 1783 additions and 693 deletions

2
configure vendored
View File

@@ -5284,7 +5284,7 @@ _ACEOF
fi
done
VERSION=03.01.05
VERSION=03.01.07
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h"

View File

@@ -45,6 +45,6 @@ if test "$GCC" = yes; then
fi
AC_CHECK_FUNCS(setenv unsetenv glob)
VERSION=03.01.05
VERSION=03.01.07
AC_SUBST(VERSION)
AC_OUTPUT(src/Makefile www/Makefile src/version.h)

View File

@@ -1,5 +1,42 @@
CHANGES TO REMIND
* Version 3.1 Patch 7 - 2009-05-31
- ENHANCEMENT: Wherever you could write "day Mon year", the parser now
accepts "YYYY-MM-DD". This applies on the command-line and to the
REM and OMIT keywords. You can avoid wrapping date calculations in
the trigger() function in many cases.
- ENHANCEMENT: New slide() built-in function eases some complicated reminders.
* Version 3.1 Patch 6 - 2008-11-16
- MAJOR ENHANCEMENT: A new OMITFUNC clause gives you additional
control and flexibility over "omitted days" calculations. This is
useful when holidays influence the timing of events several days
later. See "COMPUTED LOCAL OMITS" in the man page.
- ENHANCEMENT: The new evaltrig() built-in function lets you evaluate triggers
from within an expression.
- ENHANCEMENT: The new weekno() built-in function returns the ISO 8601
week number of a date.
- ENHANCEMENT: The "WEEK" special lets you annotate calendar output with the
week number. The TkRemind, rem2ps and rem2html back-ends support WEEK.
- MINOR ENHANCEMENT: You can control whether timed reminders come before or
after non-timed reminders with the "-g" flag.
- BUG FIX: TkRemind did not work correctly if ~/.reminders was a directory.
- BUG FIX: TkRemind incorrectly invoked Remind with the "-a" flag when
showing today's reminders.
- BUG FIX: In certain cases, a trigger containing a day, month and
weekday would fail if it needed to cross a year boundary. This has
been fixed.
* Version 3.1 Patch 5 - 2008-04-15
- MAJOR ENHANCEMENT: If you supply a directory name on the command line

View File

@@ -27,8 +27,8 @@ RUN OFF
################################################
# Ensure required version of remind is used... #
################################################
IF version() < "03.01.02"
ERRMSG This file requires at least version 03.01.02 of Remind.%
IF version() < "03.01.07"
ERRMSG This file requires at least version 03.01.07 of Remind.%
ERRMSG This version is version [version()].
EXIT
ENDIF
@@ -95,11 +95,8 @@ SET Week_3 15
SET Week_4 22
FSET _last(mo) "1 " + MON((mo%12)+1) + " --7"
# Shorthand for commonly used expression...
FSET _trig() TRIGGER(TRIGDATE())
# Handy function to provide SCANFROM dates...
FSET _back(days) TRIGGER(TODAY()-days)
FSET _back(days) TODAY()-days
###########################################################
# Function which returns a string in "am/pm" format based #
@@ -169,14 +166,14 @@ FSET _mail(from, subj) "fastmail -f " + \
REM 4 July SCANFROM [_back(7)] SATISFY 1
IF WKDAYNUM(TRIGDATE()) == Sat
REM [TRIGGER(TRIGDATE())] MSG Independence day (actual)
OMIT [TRIGGER(TRIGDATE()-1)] MSG Independence day (observed)
REM [TRIGDATE()] MSG Independence day (actual)
OMIT [TRIGDATE()-1] MSG Independence day (observed)
ELSE
IF WKDAYNUM(TRIGDATE()) == Sun
REM [TRIGGER(TRIGDATE())] MSG Independence day (actual)
OMIT [TRIGGER(TRIGDATE()+1)] MSG Independence day (observed)
REM [TRIGDATE()] MSG Independence day (actual)
OMIT [TRIGDATE()+1] MSG Independence day (observed)
ELSE
OMIT [TRIGGER(TRIGDATE())] MSG Independence day
OMIT [TRIGDATE()] MSG Independence day
ENDIF
ENDIF
@@ -197,7 +194,7 @@ REM Mon 8 SATISFY 1
# But only actually trigger the delayed meeting if the previous
# Monday was a holiday
IF ISOMITTED(TRIGDATE()-7)
REM [TRIGGER(TRIGDATE())] MSG Delayed meeting
REM [TRIGDATE()] MSG Delayed meeting
ENDIF
############################################################################
@@ -288,12 +285,12 @@ REM Sat Sun SPECIAL SHADE 220
SET SaveTrig $NumTrig
SET easter EASTERDATE(YEAR(TODAY()))
REM [TRIGGER(easter-46)] MSG %"Ash Wednesday%"
REM [TRIGGER(easter-7)] MSG %"Palm Sunday%"
OMIT [TRIGGER(easter-2)] MSG %"Good Friday%"
OMIT [TRIGGER(easter)] MSG %"Easter%" Sunday
REM [TRIGGER(easter+39)] MSG %"Ascension Day%"
REM [TRIGGER(easter+49)] MSG %"Pentecost%"
REM [easter-46] MSG %"Ash Wednesday%"
REM [easter-7] MSG %"Palm Sunday%"
OMIT [easter-2] MSG %"Good Friday%"
OMIT [easter] MSG %"Easter%" Sunday
REM [easter+39] MSG %"Ascension Day%"
REM [easter+49] MSG %"Pentecost%"
# Some holidays are omitted, some are not. You may want to change
# which ones are omitted - use the general forms shown below.
@@ -305,7 +302,7 @@ REM Mon Jan [Week_3] MSG Martin Luther King - %"MLK Day%"
REM Feb 2 MSG %"Ground Hog Day%"
REM Feb 14 MSG %"Valentine's%" Day
REM Mon Feb [Week_3] SCANFROM [_back(7)] SATISFY 1
OMIT [_trig()] MSG %"President's Day%"
OMIT [trigdate()] MSG %"President's Day%"
REM Mar 17 MSG %"St. Patrick's%" Day
# The DST rules are accurate for most locations in
@@ -320,11 +317,11 @@ REM Sat May [Week_1] MSG %"Kentucky Derby%"
REM Sun May [Week_2] MSG %"Mother's Day%"
REM Sat May [Week_3] MSG %"Armed Forces Day%"
REM Mon [_last(May)] SCANFROM [_back(7)] SATISFY 1
OMIT [_trig()] MSG %"Memorial Day%"
OMIT [trigdate()] MSG %"Memorial Day%"
REM Jun 14 MSG %"Flag Day%"
REM Sun Jun [Week_3] MSG %"Father's Day%"
REM Mon Sep [Week_1] SCANFROM [_back(7)] SATISFY 1
OMIT [_trig()] MSG %"Labor Day%"
OMIT [trigdate()] MSG %"Labor Day%"
REM Mon Oct [Week_2] MSG %"Columbus Day%"
REM Nov 11 MSG %"Veterans Day%"
@@ -339,9 +336,9 @@ REM Tue Nov 2 SCANFROM [_back(7)] \
SATISFY [(YEAR(TRIGDATE()) % 4) == 0] \
MSG %"Election%" Day
REM Thu Nov [Week_4] SCANFROM [_back(7)] SATISFY 1
OMIT [_trig()] MSG %"Thanksgiving%" Day
OMIT [trigdate()] MSG %"Thanksgiving%" Day
REM Fri Nov [Week_4+1] SCANFROM [_back(7)] SATISFY 1
OMIT [_trig()] MSG %"Thanksgiving%" (cont.)
OMIT [trigdate()] MSG %"Thanksgiving%" (cont.)
OMIT Dec 24 MSG %"Christmas Eve%"
OMIT Dec 25 MSG %"Christmas%" Day
@@ -379,10 +376,10 @@ REM PS Border Border moveto \
([hebday(today())] [hebmon(today())]) show
# Fill in the phases of the moon on the PostScript calendar
[trigger(moondate(0))] SPECIAL MOON 0
[trigger(moondate(1))] SPECIAL MOON 1
[trigger(moondate(2))] SPECIAL MOON 2
[trigger(moondate(3))] SPECIAL MOON 3
[moondate(0)] SPECIAL MOON 0
[moondate(1)] SPECIAL MOON 1
[moondate(2)] SPECIAL MOON 2
[moondate(3)] SPECIAL MOON 3
# The following example puts sunrise and sunset times in PostScript in the
# calendar - the sizes are hard-coded, however, and work best in landscape.
@@ -435,11 +432,11 @@ SET InIsrael 0
SET Reform 0
# Convenient function definition to save typing
FSET _h(x, y) TRIGGER(HEBDATE(x,y))
FSET _h(x, y) HEBDATE(x,y)
FSET _h2(x, y) HEBDATE(x, y, TODAY()-7)
FSET _PastSat(x, y) TRIGGER(IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)+1))
FSET _PastSun(x, y) TRIGGER(IIF(WKDAYNUM(_h2(x,y))!=0, _h2(x,y), _h2(x,y)+1))
FSET _PastMon(x, y) TRIGGER(IIF(WKDAYNUM(_h2(x,y))!=1, _h2(x,y), _h2(x,y)+1))
FSET _PastSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)+1)
FSET _PastSun(x, y) IIF(WKDAYNUM(_h2(x,y))!=0, _h2(x,y), _h2(x,y)+1)
FSET _PastMon(x, y) IIF(WKDAYNUM(_h2(x,y))!=1, _h2(x,y), _h2(x,y)+1)
# Default values in case InIsrael and Reform are not set
SET InIsrael VALUE("InIsrael", 0)
@@ -470,7 +467,7 @@ ELSE
ENDIF
# Because Kislev can change length, we must be more careful about Chanukah
FSET _chan(x) TRIGGER(HEBDATE(24, "Kislev", today()-9)+x)
FSET _chan(x) HEBDATE(24, "Kislev", today()-9)+x
[_chan(1)] ++4 MSG %"Chanukah 1%" is %b.
[_chan(2)] MSG %"Chanukah 2%"
[_chan(3)] MSG %"Chanukah 3%"
@@ -493,9 +490,9 @@ ENDIF
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
IF WKDAYNUM(_h2(13, "Adar")) != 6
REM [TRIGGER(_h2(13, "Adar"))] ++4 MSG %"Fast of Esther%" is %b.
REM [_h2(13, "Adar")] ++4 MSG %"Fast of Esther%" is %b.
ELSE
REM [TRIGGER(_h2(11, "Adar"))] ++4 MSG %"Fast of Esther%" is %b.
REM [_h2(11, "Adar")] ++4 MSG %"Fast of Esther%" is %b.
ENDIF
[_h(14, "Adar")] ++4 MSG %"Purim%" is %b.
[_h(15, "Adar")] ++4 MSG %"Shushan Purim%" is %b.
@@ -521,7 +518,7 @@ IF WKDAYNUM(_h2(4, "Iyar")) == 5
[_h(2, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
[_h(3, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
ELSE
IF WKDAYNUM(_h2, 4, "Iyar") == 0
IF WKDAYNUM(_h2(4, "Iyar")) == 0
[_h(5, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
[_h(6, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
ELSE

View File

@@ -1,4 +1,4 @@
.TH REMIND 1 "1 July 2007"
.TH REMIND 1 "31 August 2008"
.UC 4
.SH NAME
remind \- a sophisticated reminder service
@@ -182,13 +182,14 @@ Echo lines when displaying error messages
Trace the reading of reminder files
.RE
.TP
\fB\-g\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR]]]
Normally, reminders are issued in the order in which they are encountered
in the reminder script. The \fB\-g\fR option cause \fBRemind\fR to
sort reminders by date and time prior to issuing them. The optional
\fBa\fR and \fBd\fR characters specify the sort order (ascending or
descending) for the date, time and priority fields. See the section "Sorting
Reminders" for more information.
\fB\-g\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR]]]]
Normally, reminders are issued in the order in which they are
encountered in the reminder script. The \fB\-g\fR option cause
\fBRemind\fR to sort reminders by date and time prior to issuing them.
The optional \fBa\fR and \fBd\fR characters specify the sort order
(ascending or descending) for the date, time and priority fields. See
the section "Sorting Reminders" for more information.
.TP
\fB\-b\fR[\fIn\fR]
Set the time format for the calendar and simple-calendar outputs. \fIN\fR
@@ -285,6 +286,10 @@ set \fBRemind\fR's notion of "now" to a particular time. Supplying
a \fItime\fR on the command line also implicitly enables the \fB\-q\fR
option and disables the \fB\-z\fR option.
.PP
If you would rather specify the date more succinctly, you can supply
it as YYYY-MM-DD or YYYY/MM/DD. You can even supply a date and
time on the command line as one argument: YYYY-MM-DD@HH:MM.
.PP
In addition, you can supply a \fIrepeat\fR parameter, which has the
form *\fInum\fR. This causes \fBRemind\fR to be run \fInum\fR times,
with the date incrementing on each iteration. You may have to enclose
@@ -305,7 +310,7 @@ very simple and almost immediately understandable:
to the baroque and obscure:
.PP
.nf
REM [trigger(date(thisyear, 1, 1) + 180)] ++5 OMIT \\
REM [date(thisyear, 1, 1) + 180] ++5 OMIT \\
sat sun BEFORE MSG [ord(thisyear-1980)] payment due %b!
.fi
.PP
@@ -337,6 +342,7 @@ Its syntax is:
[\fBPRIORITY\fR \fIprio\fR]
[\fBSKIP\fR | \fBBEFORE\fR | \fBAFTER\fR]
[\fBOMIT\fR \fIomit_list\fR]
[\fBOMITFUNC\fR \fIomit_function\fR]
[\fBAT\fR \fItime\fR [\fItdelta\fR] [\fItrepeat\fR]]
[\fBSCHED\fR \fIsched_function\fR]
[\fBWARN\fR \fIwarn_function\fR]
@@ -631,6 +637,37 @@ the
.I weekday
constraints.
.PP
.B SHORT-HAND DATE SPECIFICATIONS
.PP
In addition to spelling out the day, month and year separately, you
can specify YYYY-MM-DD or YYYY/MM/DD. For example, the following statements
are equivalent:
.PP
.nf
REM 5 June 2010 MSG Cool!
REM 2010-06-05 MSG Cool!
.fi
.PP
You can also specify a date and time as YYYY-MM-DD@HH:MM. These
statements are equivalent:
.PP
.nf
REM 19 Dec 2010 AT 16:45 MSG Hi
REM 2010-12-19@16:45 MSG Hi
.fi
.PP
There's one subtlety with short-hand date specifications: The following
statements are \fInot\fR equivalent:
.PP
.nf
REM 19 Dec 2010 AT 16:45 +60 MSG Hi
REM 2010-12-19@16:45 +60 MSG Hi
.fi
.PP
In the second statement, the "+60" is a \fIdelta\fR that applies to the
date rather than a \fItdelta\fR that applies to the time. We recommend
explicitly using the AT keyword with timed reminders.
.PP
.B BACKWARD SCANNING
.PP
Sometimes, it is necessary to specify a date as being a set amount of
@@ -728,7 +765,7 @@ Another example: Suppose you have jury duty from 30 November 1992 until
of your jury duty, as well as 2 days ahead of time:
.PP
.nf
REM 30 Nov 1992 *1 +2 UNTIL 4 Dec 1992 MSG Jury duty
REM 1992-11-30 *1 +2 UNTIL 1992-12-04 MSG Jury duty
.fi
.PP
Note that the \fIrepeat\fR of *1 is necessary; without it, the reminder
@@ -794,6 +831,50 @@ also. See "The OMIT command" for more details.)
By comparison, if we had used "\-\-1", the reminder would be triggered on
the last day of the month, regardless of the \fBOMIT\fR.
.PP
.B COMPUTED LOCAL OMITS
.PP
The \fBOMITFUNC\fR phrase of the \fBREM\fR command allows you to
supply a function that determines whether or not a date is omitted.
The function is passed a single parameter of type \fBDATE\fR, and must
return a non-zero integer if the date is considered "omitted" and 0
otherwise. Here's an example:
.PP
.nf
FSET _third(x) (day(x) % 3) || \\
(wkdaynum(x) == 0) || \\
(wkdaynum(x) == 6)
REM OMITFUNC _third AFTER MSG Working day divisible by 3
.fi
.PP
In the example above, the reminder is triggered every Monday to Friday whose
day-of-month number is divisible by three. Here's how it works:
.TP
.B o
The \fBOMITFUNC _third\fR portion causes all days for which \fB_third(x)\fR
returns non-zero to be considered "omitted". This causes all days whose
day-of-month number is \fInot\fR a multiple of three to be omitted. Note
that _third also returns non-zero if the weekday is Sunday or Saturday.
.TP
.B o
The \fBAFTER\fR keyword causes the reminder to be moved after a block of
omitted days.
.PP
The combination of OMITFUNC and AFTER keyword causes the reminder to
be issued on all days whose day-of-month number is divisible by three,
but not on Saturday or Sunday.
.PP
Note that if you use \fBOMITFUNC\fR, then a local \fBOMIT\fR is
\fIignored\fR as are \fIall global OMITs\fR. If you want to omit specific
weekdays, your omit function will need to test for them specifically. If
you want to take into account the global \fBOMIT\fR context, then your omit
function will need to test for that explicitly (using the \fBisomitted()\fR
function.)
.PP
Note that an incorrect \fBOMITFUNC\fR might cause all days to be considered
omitted. For that reason, when \fBRemind\fR searches through omitted days,
it terminates the search after the \fBSATISFY\fR iteration limit
(command-line option \fB\-x\fR.)
.PP
.B TIMED REMINDERS
.PP
Timed reminders are those that have an \fBAT\fR keyword followed
@@ -1211,6 +1292,14 @@ must create an \fBOMIT\fR command for each year. (Later, in the
description of expressions and some of the more advanced features of
\fBRemind\fR, you will see how to automate this for some cases.)
.PP
As with the REM command, you can use shorthand specifiers for dates;
the following are equivalent:
.PP
.nf
OMIT 7 Sep 1992
OMIT 1992-09-07
.fi
.PP
For convenience, you can use a \fIdelta\fR and \fBMSG\fR or \fBRUN\fR
keyword in the \fBOMIT\fR command. The following sequences are exactly
equivalent:
@@ -1226,11 +1315,11 @@ equivalent:
.PP
.B THE BEFORE, AFTER AND SKIP KEYWORDS
.PP
Normally, days that are omitted, whether by a global \fBOMIT\fR command
or the local \fBOMIT\fR keyword in a \fBREM\fR statement, only affect the
counting of the \-\fIback\fR or the +\fIdelta\fR. For example, suppose
you have a meeting every Wednesday. Suppose, too, that you have indicated
11 Nov as a holiday:
Normally, days that are omitted, whether by a global \fBOMIT\fR
command or the local \fBOMIT\fR or \fBOMITFUNC\fR keywords in a
\fBREM\fR statement, only affect the counting of the \-\fIback\fR or
the +\fIdelta\fR. For example, suppose you have a meeting every
Wednesday. Suppose, too, that you have indicated 11 Nov as a holiday:
.PP
.nf
OMIT 11 Nov +4 MSG Remembrance Day
@@ -1888,6 +1977,10 @@ $IgnoreOnce, $InfDelta, and $NextMode are not meaningful.
This variable can be set only to ":" or ".". It holds the character
used to separate portions of a time when \fBRemind\fR prints a TIME or
DATETIME value.
.TP
.B $UntimedFirst (read-only)
Set to 1 if the \fB\-g\fR option is used with a fourth sort character
of "d"; set to 0 otherwise.
.PP
.B BUILT-IN FUNCTIONS
.PP
@@ -2093,6 +2186,37 @@ for the specified year. If \fIarg\fR is a \fBDATE\fR or
\fBDATETIME\fR, then returns the date of the next Easter Sunday on or
after \fIarg\fR. (The time component of a datetime is ignored.)
.TP
.B evaltrig(s_trigger [,dq_start])
Evaluates \fItrigger\fR as if it were a REM or IFTRIG trigger specification
and returns the trigger date as a \fBDATE\fR (or as a \fBDATETIME\fR if
there is an \fBAT\fR clause.) Returns a negative \fBINT\fR if no trigger
could be computed.
.RS
.PP
Normally, \fBevaltrig\fR finds a trigger date on or after today. If
you supply the \fIstart\fR argument, then it scans starting from there.
.PP
For example, the expression:
.PP
.nf
evaltrig("Mon 1", '2008-10-07')
.fi
.PP
returns '2008-11-03', since that is the first date on or after
7 October 2008 that satisfies "Mon 1".
.PP
If you want to see how many days it is from the first Monday in October, 2008
to the first Monday in November, 2008, use:
.PP
.nf
evaltrig("Mon 1", '2008-11-01') - evaltrig("Mon 1", '2008-10-01')
.fi
.PP
and the answer is 28. The trigger argument to \fBevaltrig\fR can have
all the usual trigger clauses (\fBOMIT\fR, \fBAT\fR, \fBSKIP\fR, etc.) but
\fIcannot\fR have a \fBSATISFY\fR, \fBMSG\fR, etc. reminder-type clause.
.RE
.TP
.B filedate(s_filename)
Returns the modification date of \fIfilename\fR. If \fIfilename\fR
does not exist, or its modification date is before the year
@@ -2170,7 +2294,8 @@ or \fBDATETIME\fR is supplied, then the year component is used in the test.
.B isomitted(dq_date)
Returns 1 if \fIdate\fR is omitted, given the current global \fBOMIT\fR
context. Returns 0 otherwise. (If a datetime is supplied, only the
date part is used.)
date part is used.) Note that any local \fBOMIT\fR or \fBOMITFUNC\fR
clauses are \fInot\fR taken into account by this function.
.TP
.B hebdate(i_day, s_hebmon [,idq_yrstart [,i_jahr [,i_aflag]]])
Support for Hebrew dates - see the section "The Hebrew Calendar"
@@ -2284,10 +2409,11 @@ This function returns the number of \fInon-\fRomitted days between
counted. \fIend\fR is never counted.
.RS
.PP
Note that \fIend\fR must be greater than or
equal to \fIstart\fR or an error is reported. In addition to using
the global OMIT context, you can supply additional arguments that are
names of weekdays to be omitted.
Note that \fIend\fR must be greater than or equal to \fIstart\fR or an
error is reported. In addition to using the global OMIT context, you
can supply additional arguments that are names of weekdays to be
omitted. However, in a \fBREM\fR command, any local \fBOMITFUNC\fR
clause is \fInot\fR taken into account by this function.
.PP
For example, the following line sets a to 11 (assuming no global OMITs):
.PP
@@ -2310,36 +2436,30 @@ reminder will label day numbers in a calendar:
ENDIF
.fi
.PP
Here's a more complex example: Suppose your normal garbage-collection
day is Thursday, but if any of Monday through Thursday of a week is a holiday,
the collection day moves to Friday. Here's one way to solve it:
.PP
.nf
FSET prev_monday(x) x - wkdaynum(x-1)
REM Thu Fri SATISFY [wkdaynum(trigdate()) == 4 && \\
nonomitted(prev_monday(today()), today()+1) == 4 || \\
wkdaynum(trigdate()) == 5 && \\
nonomitted(prev_monday(today()), today()+1) <= 4] \\
MSG Garbage Day
.fi
.PP
Whew! (You'll need to see "THE SATISFY CLAUSE" later on.) We'd
better explain that one: The prev_monday helper function takes a date
and returns the date of the previous Monday. The REM command will
trigger on the first Thursday or Friday that satisfies one of the
following conditions:
.PP
1) Either it's a Thursday and there are exactly four non-omitted days between
the previous Monday and tomorrow, or
.PP
2) It's a Friday and there are four or fewer non-omitted days between the
previous Monday and tomorrow. We need the "or fewer" condition to handle
the case of more than one holiday in a given week. If that happens,
garbage day still only moves by one day.
.PP
Obviously, the answer you get from \fBnonomitted\fR depends on the global
OMIT context. If you use moveable OMITs, you may get inconsistent results.
.PP
Here is a more complex use for \fBnonomitted\fR. My garbage collection
follows two interleaved 14-day cycles: One Friday, garbage and paper
recycling ("Black Box") are collected. The next Friday, garbage and
plastic recycling ("Blue Box") are collected. If any of Monday-Friday
is a holiday, collection is delayed until the Saturday. Here's a way
to encode these rules:
.PP
.nf
fset _garbhol(x) wkdaynum(x) == 5 && nonomitted(x-4, x+1) < 5
REM 12 November 1999 *14 AFTER OMITFUNC _garbhol MSG Black Box
REM 19 November 1999 *14 AFTER OMITFUNC _garbhol MSG Blue Box
.fi
.PP
Here's how it works: The _garbhol(x) user-defined function returns 1
if and only if (1) \fIx\fR is a Friday and (2) there is at least one
OMITted day from the previous Monday up to and including the Friday.
.PP
The first REM statement sets up the 14-day black-box cycle. The AFTER
keyword makes it move collection to the Saturday if _garbhol returns 1.
The second REM statement sets up the 14-day blue-box cycle with a similar
adjustment made by AFTER in conjunction with _garbhol.
.RE
.TP
.B now()
@@ -2381,10 +2501,10 @@ For example, the following four lines place moon symbols on the PostScript
calendar:
.PP
.nf
REM [trigger(moondate(0))] PS [psmoon(0)]
REM [trigger(moondate(1))] PS [psmoon(1)]
REM [trigger(moondate(2))] PS [psmoon(2)]
REM [trigger(moondate(3))] PS [psmoon(3)]
REM [moondate(0)] PS [psmoon(0)]
REM [moondate(1)] PS [psmoon(1)]
REM [moondate(2)] PS [psmoon(2)]
REM [moondate(3)] PS [psmoon(3)]
.fi
.PP
If \fInote\fR is specified, the text is used to annotate the moon
@@ -2397,7 +2517,7 @@ does not check for this.) For example, if you want the time of each new
moon displayed, you could use this in your reminder script:
.PP
.nf
REM [trigger(moondate(0))] PS [psmoon(0, -1, moontime(0)+"")]
REM [moondate(0)] PS [psmoon(0, -1, moontime(0)+"")]
.fi
.PP
Note how the time is coerced to a string by concatenating the null string.
@@ -2449,11 +2569,38 @@ character in the output is converted to a space. Note that if \fBRUN
OFF\fR has been executed, or the \fB\-r\fR command-line option has
been used, \fBshell()\fR will result in an error, and \fIcmd\fR will
not be executed.
.RS
.PP
If \fImaxlen\fR is specified, then \fBshell()\fR returns the first
\fImaxlen\fR characters of output (rather than the first 511). If
\fImaxlen\fR is specified as a negative number, then \fIall\fR the
output from \fIcmd\fR is returned.
.RE
.TP
.B slide(d_start, i_amt [,s_wkday...])
This function is the inverse of \fBnonomitted\fR. It adds \fIamt\fR
days (which can be negative) to \fIstart\fR, \fInot counting omitted days\fR.
The optional \fIwkday\fR arguments are additional weekday names to omit.
.RS
.PP
Consider this example:
.PP
.nf
OMIT 14 May 2009
SET a slide('2009-05-13', 5, "Sat", "Sun")
.fi
.PP
In this case, \fIa\fR is set to 2009-05-21. That's because we slide forward
by 5 days, not including Thursday, May 14 or Saturday and Sunday,
May 16 and 17. You can go backwards, too, so:
.PP
.nf
OMIT 14 May 2009
SET a slide('2009-05-21', -5, "Sat", "Sun")
.fi
.PP
takes \fIa\fR back to 2009-05-13.
.RE
.TP
.B strlen(s_str)
Returns the length of \fIstr\fR.
@@ -2511,15 +2658,18 @@ triggerable \fBREM\fR command had an \fBAT\fR clause. If there was no
returns the integer 0.
.TP
.B trigger(d_date [,t_time [,i_utcflag]]) \fRor\fB trigger(q_datetime [,i_utcflag])
Returns a string suitable for use in a \fBREM\fR command, allowing you
to calculate trigger dates in advance. (See the section "Expression
pasting" for more information.) Note that \fBtrigger()\fR
\fIalways\fR returns its result in English, even for foreign-language
versions of \fBRemind\fR. This is to avoid problems with certain C
libraries that do not handle accented characters properly. Normally,
the \fIdate\fR and \fItime\fR are the local date and time; however, if
\fIutcflag\fR is non-zero, the \fIdate\fR and \fItime\fR are
interpreted as UTC times, and are converted to local time. Examples:
Returns a string suitable for use in a \fBREM\fR command or a SCANFROM
or UNTIL clause, allowing you to calculate trigger dates in advance.
Note that in earlier versions of \fBRemind\fR, \fBtrigger\fR was
required to convert a date into something the \fBREM\fR command could
consume. However, in this version of \fBRemind\fR, you can omit it.
Note that \fBtrigger()\fR \fIalways\fR returns its result in English,
even for foreign-language versions of \fBRemind\fR. This is to avoid
problems with certain C libraries that do not handle accented
characters properly. Normally, the \fIdate\fR and \fItime\fR are the
local date and time; however, if \fIutcflag\fR is non-zero, the
\fIdate\fR and \fItime\fR are interpreted as UTC times, and are
converted to local time. Examples:
.RS
.PP
trigger('1993/04/01')
@@ -2596,6 +2746,21 @@ Returns a string specifying the version of \fBRemind\fR. For version
\fBRemind\fR are released, the value returned by \fBversion()\fR will
strictly increase, according to the rules for string ordering.
.TP
.B weekno([dq_date, [i_wkstart, [i_daystart]]])
Returns the week number of the year. If no arguments are supplied,
returns the ISO 8601 week number for \fBtoday()\fR. If one
argument \fIdate\fR is supplied, then returns the ISO 8601 week
number for that date. If two arguments are supplied, then
\fIwkstart\fR must range from 0 to 6, and represents the first
day of the week (with 0 being Sunday and 6 being Saturday.). If
\fIwkstart\fR is not supplied, then it defaults to 1. If the
third argument \fIdaystart\fR is supplied, then it specifies
when Week 1 starts. If \fIdaystart\fR is less than or equal to 7,
then Week 1 starts on the first \fIwkstart\fR on or after
January \fIdaystart\fR. Otherwise, Week 1 starts on the first
\fIwkstart\fR on or after December \fIdaystart\fR. If omitted,
\fIdaystart\fR defaults to 29 (following the ISO 8601 definition.)
.TP
.B wkday(dqi_arg)
If \fIarg\fR is a \fBDATE\fR or \fBDATETIME\fR, returns a string
representing the day of the week of the date. If \fIarg\fR is an
@@ -2618,10 +2783,10 @@ you can "paste" an expression in. To do this, surround the expression
with square brackets. For example:
.PP
.nf
REM [trigger(mydate)] MSG foo
REM [mydate] MSG foo
.fi
.PP
This evaluates the expression "trigger(mydate)", where "mydate" is
This evaluates the expression "mydate", where "mydate" is
presumably some pre-computed variable, and then "pastes" the result
into the command-line for the parser to process.
.PP
@@ -2644,8 +2809,16 @@ exceptions:
.TP
o
If \fBRemind\fR is expecting an expression, as in the \fBSET\fR command,
or the \fBIF\fR command, then no expression pasting takes place. The
expression is simply evaluated as if the square brackets were not there.
or the \fBIF\fR command, you should \fBnot\fR include square brackets.
FOr example, use:
.PP
.nf
SET a 4+5
.fi
and not:
.nf
SET a [4+5]
.fi
.TP
o
You cannot use expression pasting for the first token on a line.
@@ -2993,7 +3166,7 @@ more complicated sequence:
.nf
REM 13 SATISFY wkdaynum(trigdate()) == 5
IF trigvalid()
REM [trigger(trigdate())] +2 MSG \\
REM [trigdate()] +2 MSG \\
Friday the 13th is %b.
ENDIF
.fi
@@ -3001,8 +3174,7 @@ more complicated sequence:
Let's see how this works. The \fBSATISFY\fR clause iterates through
all the 13ths of successive months, until a trigger date is found whose
day-of-week is Friday (== 5). If a valid date was found, we use the
calculated trigger date (converted into a trigger format with the
\fBtrigger()\fR function) to set up the next reminder.
calculated trigger date to set up the next reminder.
.PP
We could also have written:
.PP
@@ -3021,7 +3193,7 @@ could use:
.nf
# Note: SATISFY 1 is an idiom for "do nothing"
REM Mon 1 Sept SATISFY 1
OMIT [trigger(trigdate())]
OMIT [trigdate()]
.fi
.PP
\fBCAVEAT:\fR This \fIonly\fR omits the \fInext\fR Labour Day, not
@@ -3073,6 +3245,10 @@ occurring on odd-numbered days of the month with the following:
MSG Here it is!!!
.fi
.PP
Note that \fBSATISFY\fR and \fBOMITFUNC\fR can often be used to solve the
same problem, though in different ways. Sometimes a \fBSATISFY\fR is cleaner
and sometimes an \fBOMITFUNC\fR; experiment and use whichever seems clearer.
.PP
.SH DEBUGGING REMINDER SCRIPTS
.PP
Although the command-line \fB\-d\fR option is useful for debugging, it
@@ -3412,24 +3588,26 @@ to ensure that the daemon is not killed when you log out.
.PP
.SH SORTING REMINDERS
.PP
The \fB\-g\fR option causes \fBRemind\fR to sort reminders by
trigger date, time and priority before issuing them. Note that reminders are
still calculated in the order encountered in the script. However, rather
than being issued immediately, they are saved in an internal buffer.
When \fBRemind\fR has finished processing the script, it issues the
saved reminders in sorted order. The \fB\-g\fR option can be followed
by up to three characters that must all be "a" or "d". The first character
specifies the sort order by trigger date (ascending or descending),
the second specifies the sort order by trigger time and the third
specifies the sort order by priority. The default is
to sort all fields in ascending order.
The \fB\-g\fR option causes \fBRemind\fR to sort reminders by trigger
date, time and priority before issuing them. Note that reminders are
still calculated in the order encountered in the script. However,
rather than being issued immediately, they are saved in an internal
buffer. When \fBRemind\fR has finished processing the script, it
issues the saved reminders in sorted order. The \fB\-g\fR option can
be followed by up to four characters that must all be "a" or "d". The
first character specifies the sort order by trigger date (ascending or
descending), the second specifies the sort order by trigger time and
the third specifies the sort order by priority. If the fourth
character is "d", the untimed reminders are sorted before timed
reminders. The default is to sort all fields in ascending order and
to sort untimed reminders after timed reminders.
.PP
In ascending order, reminders are issued with the most imminent first.
Descending order is the reverse. Reminders are always sorted by
trigger date, and reminders with the same trigger date are then sorted
by trigger time. Non-timed reminders are always issued after timed
reminders in this mode. If two reminders have the same date and time,
then the priority is used to break ties. Reminders with the same date,
by trigger time. If two reminders have the same date and time, then
the priority is used to break ties. Reminders with the same date,
time and priority are issued in the order they were encountered.
.PP
You can define a user-defined function called SORTBANNER that takes one
@@ -3782,10 +3960,10 @@ in calendars produced by \fBRem2PS\fR, \fBtkremind\fR and \fBrem2html\fR.)
The \fBMOON\fR special replaces the \fBpsmoon()\fR function. Use it
like this:
.nf
REM [trigger(moondate(0))] SPECIAL MOON 0
REM [trigger(moondate(1))] SPECIAL MOON 1
REM [trigger(moondate(2))] SPECIAL MOON 2
REM [trigger(moondate(3))] SPECIAL MOON 3
REM [moondate(0)] SPECIAL MOON 0
REM [moondate(1)] SPECIAL MOON 1
REM [moondate(2)] SPECIAL MOON 2
REM [moondate(3)] SPECIAL MOON 3
.fi
These draw little moons on the various calendars. The complete syntax
of the \fBMOON\fR special is as follows:
@@ -3823,6 +4001,16 @@ The COLOR special is "doubly special", because in its normal operating
mode, \fBremind\fR treats a COLOR special just like a MSG-type reminder.
Also, if you invoke \fBRemind\fR with \fB\-cc\fR..., then it approximates
SPECIAL COLOR reminders on your terminal.
.PP
The \fBWEEK\fR special lets you place annotations such as the week
number in the calendar. For example, this would number each Monday
with the ISO 8601 week number. The week number is shown like this:
"(W\fIn\fR)" in this example, but you can put whatever text you like
after the WEEK keyword.
.nf
REM Monday SPECIAL WEEK (W[weekno()])
.fi
.SH MISCELLANEOUS
.PP
@@ -3904,7 +4092,7 @@ This example puts an entry in each box of a calendar showing the number
.nf
REM Tue 2 Nov SATISFY (year(trigdate())%4) == 0
IF trigvalid()
REM [trigger(trigdate())] ++5 MSG \\
REM [trigdate()] ++5 MSG \\
U.S. Presidential Election!!
ENDIF
.fi
@@ -3955,8 +4143,8 @@ in September. It can move over a range of 7 days. Consider the
following sequence:
.PP
.nf
REM Mon 1 Sept SCANFROM [trigger(today()-7)] SATISFY 1
OMIT [trigger(trigdate())]
REM Mon 1 Sept SCANFROM [today()-7] SATISFY 1
OMIT [trigdate()]
REM Mon AFTER MSG Hello
.fi
@@ -3986,7 +4174,7 @@ will trigger on Mondays and Thursdays between 23 July 2007 and
the reminder above as follows:
.PP
.nf
REM Mon Thu SCANFROM [trigger(max(today(), '2007-07-23'))] \\
REM Mon Thu SCANFROM [max(today(), '2007-07-23')] \\
UNTIL 2 Aug 2007 MSG Test
.fi
.PP
@@ -4079,8 +4267,9 @@ Hebrew dates in \fBRemind\fR change at midnight instead of sunset.
.PP
Language should be selectable at run-time, not compile-time. Don't
expect this to happen soon!
\fBRemind\fR has some built-in limits (for example,
number of global \fBOMIT\fRs.)
.PP
\fBRemind\fR has some built-in limits (for example, number of global
\fBOMIT\fRs.)
.PP
.SH BIBLIOGRAPHY
.PP

View File

@@ -8,7 +8,7 @@
#
# This file is part of REMIND.
# Copyright (C) 1992-1998 David F. Skoll
# Copyright (C) 1999-2008 Roaring Penguin Software Inc.
# Copyright (C) 1999-2009 Roaring Penguin Software Inc.
#
#--------------------------------------------------------------
@@ -208,6 +208,12 @@ proc Initialize {} {
exit 1
}
if {[file isdirectory $ReminderFile] && ! [file exists $AppendFile]} {
if {![catch {close [open "$AppendFile" "a"]}]} {
tk_dialog .error "Created File" "Created blank file `$AppendFile'" info 0 "OK"
}
}
if {! [file writable $AppendFile]} {
tk_dialog .error Error "Can't write reminder file `$AppendFile'" error 0 Ok
exit 1
@@ -747,6 +753,13 @@ proc FillCalWindow {} {
set month [string trimleft $month 0]
set extratags ""
switch -exact -- $type {
"WEEK" {
set stuff [string trimleft $stuff]
set stuff [string trimright $stuff]
set label [expr $firstWkday + $day - 1]
.cal.l$label configure -text "$day $stuff"
continue
}
"SHADE" {
DoShadeSpecial $n $stuff
continue
@@ -2258,7 +2271,7 @@ proc main {} {
global AppendFile HighestTagSoFar DayNames
catch {
puts "\nTkRemind Copyright (C) 1996-1998 David F. Skoll"
puts "Copyright (C) 1999-2008 Roaring Penguin Software Inc."
puts "Copyright (C) 1999-2009 Roaring Penguin Software Inc."
}
catch { SetFonts }
LoadOptions
@@ -2796,7 +2809,7 @@ proc ShowTodaysReminders {} {
CenterWindow $w
# Grab the reminders
set stuff [exec -keepnewline $Remind -g -q -a -r $ReminderFile 2>/dev/null]
set stuff [exec -keepnewline $Remind -g -q -r $ReminderFile 2>/dev/null]
$w.text insert end $stuff
$w.text configure -state disabled
}

View File

@@ -748,7 +748,7 @@ static int DoCalRem(ParsePtr p, int col)
Trigger trig;
TimeTrig tim;
Value v;
int r;
int r, err;
int jul;
CalEntry *CurCol = CalColumn[col];
CalEntry *e;
@@ -763,7 +763,7 @@ static int DoCalRem(ParsePtr p, int col)
DBufInit(&pre_buf);
/* Parse the trigger date and time */
if ( (r=ParseRem(p, &trig, &tim)) ) return r;
if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r;
/* Don't include timed reminders in calendar if -a option supplied. */
if (DontIssueAts && tim.ttime != NO_TIME) return OK;
@@ -793,7 +793,7 @@ static int DoCalRem(ParsePtr p, int col)
if (!LastTrigValid) return OK;
} else {
/* Calculate the trigger date */
jul = ComputeTrigger(trig.scanfrom, &trig, &r);
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1);
if (r) return r;
}
@@ -845,7 +845,7 @@ static int DoCalRem(ParsePtr p, int col)
DBufInit(&obuf);
if ((jul == JulianToday) ||
(DoSimpleCalDelta &&
ShouldTriggerReminder(&trig, &tim, jul))) {
ShouldTriggerReminder(&trig, &tim, jul, &err))) {
NumTriggered++;
if (DoSimpleCalendar || tim.ttime != NO_TIME) {
@@ -1265,7 +1265,7 @@ static void SortCol(CalEntry **col)
while (cur->next &&
CompareRems(0, cur->time, cur->priority,
0, cur->next->time, cur->next->priority,
SortByDate, SortByTime, SortByPrio) <= 0) {
SortByDate, SortByTime, SortByPrio, UntimedBeforeTimed) <= 0) {
next = cur->next;
/* Swap cur and next */
if (!prev) {

View File

@@ -148,6 +148,12 @@
/*---------------------------------------------------------------------*/
#define MAX_PRT_LEN 40
/*---------------------------------------------------------------------*/
/* MAX_STR_LEN: If non-zero, Remind will limit the maximum length */
/* of string values to avoid eating up all of memory... */
/*---------------------------------------------------------------------*/
#define MAX_STR_LEN 65535
/*---------------------------------------------------------------------*/
/* OP_STACK_SIZE: The size of the operator stack for expr. parsing */
/*---------------------------------------------------------------------*/

View File

@@ -148,6 +148,12 @@
/*---------------------------------------------------------------------*/
#define MAX_PRT_LEN 40
/*---------------------------------------------------------------------*/
/* MAX_STR_LEN: If non-zero, Remind will limit the maximum length */
/* of string values to avoid eating up all of memory... */
/*---------------------------------------------------------------------*/
#define MAX_STR_LEN 65535
/*---------------------------------------------------------------------*/
/* OP_STACK_SIZE: The size of the operator stack for expr. parsing */
/*---------------------------------------------------------------------*/

View File

@@ -29,12 +29,12 @@
static char const DontEscapeMe[] =
"1234567890_-=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.,";
static int ParseTimeTrig (ParsePtr s, TimeTrig *tim);
static int ParseTimeTrig (ParsePtr s, TimeTrig *tim, int save_in_globals);
static int ParseLocalOmit (ParsePtr s, Trigger *t);
static int ParseScanFrom (ParsePtr s, Trigger *t, int type);
static int ParsePriority (ParsePtr s, Trigger *t);
static int ParseUntil (ParsePtr s, Trigger *t);
static int ShouldTriggerBasedOnWarn (Trigger *t, int jul);
static int ShouldTriggerBasedOnWarn (Trigger *t, int jul, int *err);
/***************************************************************/
/* */
@@ -48,7 +48,7 @@ int DoRem(ParsePtr p)
Trigger trig;
TimeTrig tim;
int r;
int r, err;
int jul;
DynamicBuffer buf;
Token tok;
@@ -56,7 +56,7 @@ int DoRem(ParsePtr p)
DBufInit(&buf);
/* Parse the trigger date and time */
if ( (r=ParseRem(p, &trig, &tim)) ) return r;
if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r;
if (trig.typ == NO_TYPE) return E_EOLN;
if (trig.typ == SAT_TYPE) {
@@ -90,7 +90,7 @@ int DoRem(ParsePtr p)
if (!LastTrigValid) return OK;
} else {
/* Calculate the trigger date */
jul = ComputeTrigger(trig.scanfrom, &trig, &r);
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1);
if (r) return r;
}
@@ -103,7 +103,7 @@ int DoRem(ParsePtr p)
/* If we're in daemon mode, do nothing over here */
if (Daemon) return OK;
if (ShouldTriggerReminder(&trig, &tim, jul)) {
if (ShouldTriggerReminder(&trig, &tim, jul, &err)) {
if ( (r=TriggerReminder(p, &trig, &tim, jul)) )
{
return r;
@@ -121,12 +121,14 @@ int DoRem(ParsePtr p)
/* trigger structure. */
/* */
/***************************************************************/
int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
{
register int r;
DynamicBuffer buf;
Token tok;
int y, m, d;
DBufInit(&buf);
trig->y = NO_YR;
@@ -145,13 +147,16 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
trig->priority = DefaultPrio;
trig->sched[0] = 0;
trig->warn[0] = 0;
trig->omitfunc[0] = 0;
trig->tag[0] = 0;
trig->passthru[0] = 0;
tim->ttime = NO_TIME;
tim->delta = NO_DELTA;
tim->rep = NO_REP;
tim->duration = NO_TIME;
LastTriggerTime = NO_TIME;
if (save_in_globals) {
LastTriggerTime = NO_TIME;
}
while(1) {
/* Read space-delimited string */
@@ -161,6 +166,32 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
/* Figure out what we've got */
FindToken(DBufValue(&buf), &tok);
switch(tok.type) {
case T_Date:
DBufFree(&buf);
if (trig->d != NO_DAY) return E_DAY_TWICE;
if (trig->m != NO_MON) return E_MON_TWICE;
if (trig->y != NO_YR) return E_YR_TWICE;
FromJulian(tok.val, &y, &m, &d);
trig->y = y;
trig->m = m;
trig->d = d;
break;
case T_DateTime:
DBufFree(&buf);
if (trig->d != NO_DAY) return E_DAY_TWICE;
if (trig->m != NO_MON) return E_MON_TWICE;
if (trig->y != NO_YR) return E_YR_TWICE;
FromJulian(tok.val / MINUTES_PER_DAY, &y, &m, &d);
trig->y = y;
trig->m = m;
trig->d = d;
tim->ttime = (tok.val % MINUTES_PER_DAY);
if (save_in_globals) {
LastTriggerTime = tim->ttime;
}
break;
case T_WkDay:
DBufFree(&buf);
if (trig->wd & (1 << tok.val)) return E_WD_TWICE;
@@ -187,7 +218,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
case T_At:
DBufFree(&buf);
r=ParseTimeTrig(s, tim);
r=ParseTimeTrig(s, tim, save_in_globals);
if (r) return r;
break;
@@ -257,6 +288,10 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
case T_Omit:
DBufFree(&buf);
if (trig->omitfunc[0]) {
Eprint("Warning: OMIT is ignored if you use OMITFUNC");
}
r = ParseLocalOmit(s, trig);
if (r) return r;
break;
@@ -266,6 +301,16 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
if (trig->scanfrom == NO_DATE) trig->scanfrom = JulianToday;
return OK;
case T_OmitFunc:
if (trig->localomit) {
Eprint("Warning: OMIT is ignored if you use OMITFUNC");
}
r=ParseToken(s, &buf);
if (r) return r;
StrnCpy(trig->omitfunc, DBufValue(&buf), VAR_NAME_LEN);
DBufFree(&buf);
break;
case T_Warn:
r=ParseToken(s, &buf);
if(r) return r;
@@ -322,7 +367,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
/* ParseTimeTrig - parse the AT part of a timed reminder */
/* */
/***************************************************************/
static int ParseTimeTrig(ParsePtr s, TimeTrig *tim)
static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
{
Token tok;
int r;
@@ -354,7 +399,9 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim)
if (tim->ttime == NO_TIME) return E_EXPECT_TIME;
/* Save trigger time in global variable */
LastTriggerTime = tim->ttime;
if (save_in_globals) {
LastTriggerTime = tim->ttime;
}
PushToken(DBufValue(&buf), s);
DBufFree(&buf);
return OK;
@@ -443,6 +490,23 @@ static int ParseUntil(ParsePtr s, Trigger *t)
d = tok.val;
break;
case T_Date:
DBufFree(&buf);
if (y != NO_YR) {
Eprint("UNTIL: %s", ErrMsg[E_YR_TWICE]);
return E_YR_TWICE;
}
if (m != NO_MON) {
Eprint("UNTIL: %s", ErrMsg[E_MON_TWICE]);
return E_MON_TWICE;
}
if (d != NO_DAY) {
Eprint("UNTIL: %s", ErrMsg[E_DAY_TWICE]);
return E_DAY_TWICE;
}
FromJulian(tok.val, &y, &m, &d);
break;
default:
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
Eprint("UNTIL: %s", ErrMsg[E_INCOMPLETE]);
@@ -518,6 +582,23 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
d = tok.val;
break;
case T_Date:
DBufFree(&buf);
if (y != NO_YR) {
Eprint("%s: %s", word, ErrMsg[E_YR_TWICE]);
return E_YR_TWICE;
}
if (m != NO_MON) {
Eprint("%s: %s", word, ErrMsg[E_MON_TWICE]);
return E_MON_TWICE;
}
if (d != NO_DAY) {
Eprint("%s: %s", word, ErrMsg[E_DAY_TWICE]);
return E_DAY_TWICE;
}
FromJulian(tok.val, &y, &m, &d);
break;
default:
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]);
@@ -551,7 +632,7 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
{
int r, y, m, d;
char PrioExpr[25];
char PrioExpr[VAR_NAME_LEN+25];
char tmpBuf[64];
DynamicBuffer buf, calRow;
DynamicBuffer pre_buf;
@@ -744,7 +825,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
DBufFree(&buf);
NumTriggered++;
return OK;
}
}
/***************************************************************/
/* */
@@ -752,12 +833,13 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
/* */
/* Return 1 if we should trigger a reminder, based on today's */
/* date and the trigger. Return 0 if reminder should not be */
/* triggered. */
/* triggered. Sets *err non-zero in event of an error. */
/* */
/***************************************************************/
int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int jul)
int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int jul, int *err)
{
int r;
int r, omit;
*err = 0;
/* Handle the ONCE modifier in the reminder. */
if (!IgnoreOnce && t->once !=NO_ONCE && FileAccessDate == JulianToday)
@@ -786,7 +868,7 @@ int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int jul)
return 1;
}
}
return ShouldTriggerBasedOnWarn(t, jul);
return ShouldTriggerBasedOnWarn(t, jul, err);
}
/* Move back by delta days, if any */
@@ -795,9 +877,22 @@ int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int jul)
jul = jul + t->delta;
else {
r = t->delta;
while(r && jul > JulianToday) {
int iter = 0;
int max = MaxSatIter;
if (max < r*2) max = r*2;
while(iter++ < max) {
if (!r || (jul <= JulianToday)) {
break;
}
jul--;
if (!IsOmitted(jul, t->localomit)) r--;
*err = IsOmitted(jul, t->localomit, t->omitfunc, &omit);
if (*err) return 0;
if (!omit) r--;
}
if (iter > max) {
*err = E_CANT_TRIG;
Eprint("Delta: Bad OMITFUNC? %s", ErrMsg[E_CANT_TRIG]);
return 0;
}
}
}
@@ -824,7 +919,7 @@ int DoSatRemind(Trigger *trig, TimeTrig *tim, ParsePtr p)
iter = 0;
jul = trig->scanfrom;
while (iter++ < MaxSatIter) {
jul = ComputeTrigger(jul, trig, &r);
jul = ComputeTrigger(jul, trig, &r, 1);
if (r) {
if (r == E_CANT_TRIG) return OK; else return r;
}
@@ -953,12 +1048,12 @@ finished:
/* function. */
/* */
/***************************************************************/
static int ShouldTriggerBasedOnWarn(Trigger *t, int jul)
static int ShouldTriggerBasedOnWarn(Trigger *t, int jul, int *err)
{
char buffer[VAR_NAME_LEN+32];
int i;
char const *s;
int r;
int r, omit;
Value v;
int lastReturnVal = 0; /* Silence compiler warning */
@@ -996,9 +1091,21 @@ static int ShouldTriggerBasedOnWarn(Trigger *t, int jul)
if (JulianToday + v.v.val == jul) return 1;
} else {
int j = jul;
while (v.v.val) {
int iter = 0;
int max = MaxSatIter;
if (max < v.v.val * 2) max = v.v.val*2;
while(iter++ <= max) {
j--;
if (!IsOmitted(j, t->localomit)) v.v.val++;
*err = IsOmitted(j, t->localomit, t->omitfunc, &omit);
if (*err) return 0;
if (!omit) v.v.val++;
if (!v.v.val) {
break;
}
}
if (iter > max) {
Eprint("Delta: Bad OMITFUNC? %s", ErrMsg[E_CANT_TRIG]);
return 0;
}
if (j == JulianToday) return 1;
}

View File

@@ -118,6 +118,7 @@
#define M_BAD_WARN_FUNC 98
#define E_CANT_CONVERT_TZ 99
#define E_NO_MATCHING_REMS 100
#define E_STRING_TOO_LONG 101
#ifdef MK_GLOBALS
#undef EXTERN
@@ -232,7 +233,8 @@ EXTERN char *ErrMsg[]
"Expecting number",
"Bad function in WARN clause",
"Can't convert between time zones",
"No files matching *.rem"
"No files matching *.rem",
"String too long"
}
#endif /* MK_GLOBALS */
;

View File

@@ -42,7 +42,6 @@ static int Multiply(void), Divide(void), Mod(void), Add(void),
Compare(int);
static int MakeValue (char const *s, Value *v, Var *locals);
static int ParseLiteralDate (char const **s, int *jul, int *tim);
/* Binary operators - all left-associative */
@@ -73,9 +72,7 @@ Operator UnOp[] = {
};
#define NUM_UN_OPS (sizeof(UnOp) / sizeof(Operator))
/* Functions have the same definitions as operators, except the prec field
is used to indicate how many arguments are needed. */
extern Operator Func[];
extern BuiltinFunc Func[];
Operator OpStack[OP_STACK_SIZE];
Value ValStack[VAL_STACK_SIZE];
@@ -333,7 +330,8 @@ int Evaluate(char const **s, Var *locals)
{
int OpBase, ValBase;
int r;
Operator *f;
Operator *o;
BuiltinFunc *f;
int args; /* Number of function arguments */
Operator op, op2;
Value va;
@@ -410,10 +408,10 @@ int Evaluate(char const **s, Var *locals)
if (r) return r;
}
} else { /* Unary operator */
f = FindFunc(DBufValue(&ExprBuf), UnOp, NUM_UN_OPS);
if (f) {
o = FindOperator(DBufValue(&ExprBuf), UnOp, NUM_UN_OPS);
if (o) {
DBufFree(&ExprBuf);
PushOpStack(*f);
PushOpStack(*o);
continue; /* Still looking for an atomic vlue */
} else if (!ISID(*DBufValue(&ExprBuf)) &&
*DBufValue(&ExprBuf) != '$' &&
@@ -459,13 +457,13 @@ int Evaluate(char const **s, Var *locals)
return OK;
}
/* Must be a binary operator */
f = FindFunc(DBufValue(&ExprBuf), BinOp, NUM_BIN_OPS);
o = FindOperator(DBufValue(&ExprBuf), BinOp, NUM_BIN_OPS);
DBufFree(&ExprBuf);
if (!f) return E_EXPECTING_BINOP;
if (!o) return E_EXPECTING_BINOP;
/* While operators of higher or equal precedence are on the stack,
pop them off and evaluate */
while (OpStackPtr > OpBase && OpStack[OpStackPtr-1].prec >= f->prec) {
while (OpStackPtr > OpBase && OpStack[OpStackPtr-1].prec >= o->prec) {
PopOpStack(op2);
if (r) return r;
if (DebugFlag & DB_PRTEXPR)
@@ -477,7 +475,7 @@ int Evaluate(char const **s, Var *locals)
return r;
}
}
PushOpStack(*f);
PushOpStack(*o);
}
}
@@ -737,6 +735,8 @@ static int Add(void)
Value v1, v2, v3;
int r;
size_t l1, l2;
PopValStack(v2);
if ( (r = FnPopValStack(&v1)) ) {
DestroyValue(v2);
@@ -791,7 +791,13 @@ static int Add(void)
return r;
}
v3.type = STR_TYPE;
v3.v.str = malloc(strlen(v1.v.str) + strlen(v2.v.str) + 1);
l1 = strlen(v1.v.str);
l2 = strlen(v2.v.str);
if (MaxStringLen && (l1 + l2 > MaxStringLen)) {
DestroyValue(v1); DestroyValue(v2);
return E_STRING_TOO_LONG;
}
v3.v.str = malloc(l1 + l2 + 1);
if (!v3.v.str) {
DestroyValue(v1); DestroyValue(v2);
return E_NO_MEM;
@@ -1118,7 +1124,28 @@ static int LogNot(void)
/* Find a function. */
/* */
/***************************************************************/
Operator *FindFunc(char const *name, Operator where[], int num)
Operator *FindOperator(char const *name, Operator where[], int num)
{
int top=num-1, bot=0;
int mid, r;
while (top >= bot) {
mid = (top + bot) / 2;
r = StrCmpi(name, where[mid].name);
if (!r) return &where[mid];
else if (r > 0) bot = mid+1;
else top = mid-1;
}
return NULL;
}
/***************************************************************/
/* */
/* FindFunc */
/* */
/* Find a function. */
/* */
/***************************************************************/
BuiltinFunc *FindFunc(char const *name, BuiltinFunc where[], int num)
{
int top=num-1, bot=0;
int mid, r;
@@ -1194,7 +1221,7 @@ int CopyValue(Value *dest, const Value *src)
/* and tim; update s. */
/* */
/***************************************************************/
static int ParseLiteralDate(char const **s, int *jul, int *tim)
int ParseLiteralDate(char const **s, int *jul, int *tim)
{
int y, m, d;
int hour, min;

View File

@@ -723,7 +723,7 @@ static void DestroyCache(CachedFile *cf)
/***************************************************************/
int TopLevel(void)
{
return !IStackPtr;
return IStackPtr <= 1;
}
/***************************************************************/

File diff suppressed because it is too large Load Diff

View File

@@ -59,6 +59,7 @@ EXTERN INIT( int IgnoreOnce, 0);
EXTERN INIT( int SortByTime, 0);
EXTERN INIT( int SortByDate, 0);
EXTERN INIT( int SortByPrio, 0);
EXTERN INIT( int UntimedBeforeTimed, 0);
EXTERN INIT( int DefaultPrio, NO_PRIORITY);
EXTERN INIT( long SysTime, -1L);
@@ -75,6 +76,7 @@ EXTERN INIT( char TimeSep, TIMESEP);
EXTERN INIT( int SynthesizeTags, 0);
EXTERN INIT( int ScFormat, SC_AMPM);
EXTERN INIT( int MaxSatIter, 150);
EXTERN INIT( int MaxStringLen, MAX_STR_LEN);
EXTERN INIT( char *FileName, NULL);
EXTERN INIT( int UseStdin, 0);
EXTERN FILE *ErrFp;

View File

@@ -133,6 +133,11 @@ void InitRemind(int argc, char const *argv[])
char const *s;
int weeks;
int jul, tim;
jul = NO_DATE;
tim = NO_TIME;
/* Initialize global dynamic buffers */
DBufInit(&Banner);
DBufInit(&LineBuffer);
@@ -248,6 +253,7 @@ void InitRemind(int argc, char const *argv[])
SortByDate = SORT_ASCEND;
SortByTime = SORT_ASCEND;
SortByPrio = SORT_ASCEND;
UntimedBeforeTimed = 0;
if (*arg) {
if (*arg == 'D' || *arg == 'd')
SortByDate = SORT_DESCEND;
@@ -263,6 +269,11 @@ void InitRemind(int argc, char const *argv[])
SortByPrio = SORT_DESCEND;
arg++;
}
if (*arg) {
if (*arg == 'D' || *arg == 'd')
UntimedBeforeTimed = 1;
arg++;
}
break;
case 'u':
@@ -474,18 +485,32 @@ void InitRemind(int argc, char const *argv[])
}
break;
case T_DateTime:
if (SysTime != -1L) Usage();
if (m != NO_MON || d != NO_DAY || y != NO_YR || jul != NO_DATE) Usage();
SysTime = (tok.val % MINUTES_PER_DAY) * 60;
DontQueue = 1;
Daemon = 0;
jul = tok.val / MINUTES_PER_DAY;
break;
case T_Date:
if (m != NO_MON || d != NO_DAY || y != NO_YR || jul != NO_DATE) Usage();
jul = tok.val;
break;
case T_Month:
if (m != NO_MON) Usage();
if (m != NO_MON || jul != NO_DATE) Usage();
else m = tok.val;
break;
case T_Day:
if (d != NO_DAY) Usage();
if (d != NO_DAY || jul != NO_DATE) Usage();
else d = tok.val;
break;
case T_Year:
if (y != NO_YR) Usage();
if (y != NO_YR || jul != NO_DATE) Usage();
else y = tok.val;
break;
@@ -494,7 +519,8 @@ void InitRemind(int argc, char const *argv[])
else rep = tok.val;
break;
default: Usage();
default:
Usage();
}
}
@@ -504,6 +530,9 @@ void InitRemind(int argc, char const *argv[])
Daemon = 0;
}
if (jul != NO_DATE) {
FromJulian(jul, &y, &m, &d);
}
/* Must supply date in the form: day, mon, yr OR mon, yr */
if (m != NO_MON || y != NO_YR || d != NO_DAY) {
if (m == NO_MON || y == NO_YR) {
@@ -549,7 +578,7 @@ void InitRemind(int argc, char const *argv[])
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-1998 David F. Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "Copyright 1999-2008 Roaring Penguin Software Inc.\n");
fprintf(ErrFp, "Copyright 1999-2009 Roaring Penguin Software Inc.\n");
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
@@ -576,7 +605,7 @@ void Usage(void)
fprintf(ErrFp, " -b[n] Time format for cal: 0=am/pm, 1=24hr, 2=none\n");
fprintf(ErrFp, " -x[n] Iteration limit for SATISFY clause (def=150)\n");
fprintf(ErrFp, " -kcmd Run `cmd' for MSG-type reminders\n");
fprintf(ErrFp, " -g[ddd] Sort reminders by date, time and priority before issuing\n");
fprintf(ErrFp, " -g[dddd] Sort reminders by date, time, priority, and 'timedness'\n");
fprintf(ErrFp, " -ivar=val Initialize var to val and preserve var\n");
fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n");
fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n");

View File

@@ -308,7 +308,8 @@ EXTERN char *ErrMsg[] =
"Numero puuttuu",
"Virheellinen funktio WARN-lausekkeessa",
"Can't convert between time zones",
"No files matching *.rem"
"No files matching *.rem",
"String too long"
#elif IBMEXTENDED
"Ok",
@@ -411,7 +412,9 @@ EXTERN char *ErrMsg[] =
"Numero puuttuu"
"Virheellinen funktio WARN-lausekkeessa",
"Can't convert between time zones",
"No files matching *.rem"
"No files matching *.rem",
"String too long"
#else
"Ok",
"Puuttuva ']'",
@@ -513,7 +516,9 @@ EXTERN char *ErrMsg[] =
"Numero puuttuu",
"Virheellinen funktio WARN-lausekkeessa",
"Can't convert between time zones",
"No files matching *.rem"
"No files matching *.rem",
"String too long"
#endif
};

View File

@@ -245,7 +245,9 @@ EXTERN char *ErrMsg[] =
"Nombre attendu",
"Fonction ill\351gale apr\350s WARN",
"Can't convert between time zones",
"No files matching *.rem"
"No files matching *.rem",
"String too long"
#else /* ISOLATIN1 */
"Ok",
"']' manquant",
@@ -347,7 +349,8 @@ EXTERN char *ErrMsg[] =
"Nombre attendu",
"Fonction illegale apres WARN",
"Can't convert between time zones",
"No files matching *.rem"
"No files matching *.rem",
"String too long"
#endif /* ISOLATIN1 */
};
#endif /* MK_GLOBALS */

View File

@@ -280,7 +280,8 @@ EXTERN char *ErrMsg[] =
"Spodziewana liczba",
"Illegal function in WARN clause (NEEDS TRANSLATION TO POLISH)",
"Can't convert between time zones",
"No files matching *.rem"
"No files matching *.rem",
"String too long"
#else /* ISOLATIN1 */
"OK",
"Brakujacy ']'",
@@ -382,7 +383,8 @@ EXTERN char *ErrMsg[] =
"Spodziewana liczba",
"Illegal function in WARN clause (NEEDS TRANSLATION TO POLISH)",
"Can't convert between time zones",
"No files matching *.rem"
"No files matching *.rem",
"String too long"
#endif /* ISOLATIN1 */
};
#endif /* MK_GLOBALS */

View File

@@ -246,7 +246,8 @@ EXTERN char *ErrMsg[] =
"Esperando numero",
"Funcao ilegal na clausula WARN",
"Can't convert between time zones",
"No files matching *.rem"
"No files matching *.rem",
"String too long"
};
#endif /* MK_GLOBALS */

View File

@@ -7,7 +7,7 @@
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-1998 by David F. Skoll */
/* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */
/* Copyright (C) 1999-2009 by Roaring Penguin Software Inc. */
/* */
/***************************************************************/
@@ -724,7 +724,7 @@ int DoEndif(ParsePtr p)
/***************************************************************/
int DoIfTrig(ParsePtr p)
{
int r;
int r, err;
unsigned syndrome;
Trigger trig;
TimeTrig tim;
@@ -734,12 +734,12 @@ int DoIfTrig(ParsePtr p)
if (NumIfs >= IF_NEST) return E_NESTED_IF;
if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE;
else {
if ( (r=ParseRem(p, &trig, &tim)) ) return r;
if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r;
if (trig.typ != NO_TYPE) return E_PARSE_ERR;
jul = ComputeTrigger(trig.scanfrom, &trig, &r);
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1);
if (r) syndrome = IF_TRUE | BEFORE_ELSE;
else {
if (ShouldTriggerReminder(&trig, &tim, jul))
if (ShouldTriggerReminder(&trig, &tim, jul, &err))
syndrome = IF_TRUE | BEFORE_ELSE;
else
syndrome = IF_FALSE | BEFORE_ELSE;

View File

@@ -20,6 +20,7 @@
#include "protos.h"
#include "globals.h"
#include "err.h"
#include "expr.h"
static int BexistsIntArray (int array[], int num, int key);
static void InsertIntoSortedArray (int *array, int num, int key);
@@ -177,26 +178,57 @@ int PopOmitContext(ParsePtr p)
/* */
/* IsOmitted */
/* */
/* Return non-zero if date is OMITted, zero if it is not. */
/* Set *omit to non-zero if date is omitted, else 0. Returns */
/* OK or an error code. */
/* */
/***************************************************************/
int IsOmitted(int jul, int localomit)
int IsOmitted(int jul, int localomit, char const *omitfunc, int *omit)
{
int y, m, d;
/* If we have an omitfunc, we *only* use it and ignore local/global
OMITs */
if (omitfunc && *omitfunc && UserFuncExists(omitfunc)) {
char expr[VAR_NAME_LEN + 32];
char const *s;
int r;
Value v;
FromJulian(jul, &y, &m, &d);
sprintf(expr, "%s('%04d-%02d-%02d')",
omitfunc, y, m+1, d);
s = expr;
r = EvalExpr(&s, &v);
if (r) return r;
if (v.type == INT_TYPE && v.v.val != 0) {
*omit = 1;
} else {
*omit = 0;
}
return OK;
}
/* Is it omitted because of local omits? */
if (localomit & (1 << (jul % 7))) return 1;
if (localomit & (1 << (jul % 7))) {
*omit = 1;
return OK;
}
/* Is it omitted because of fully-specified omits? */
if (BexistsIntArray(FullOmitArray, NumFullOmits, jul)) return 1;
if (BexistsIntArray(FullOmitArray, NumFullOmits, jul)) {
*omit = 1;
return OK;
}
/* Get the syndrome */
FromJulian(jul, &y, &m, &d);
if (BexistsIntArray(PartialOmitArray, NumPartialOmits, (m << 5) + d))
return 1;
if (BexistsIntArray(PartialOmitArray, NumPartialOmits, (m << 5) + d)) {
*omit = 1;
return OK;
}
/* Not omitted */
return 0;
*omit = 0;
return OK;
}
/***************************************************************/
@@ -262,6 +294,14 @@ int DoOmit(ParsePtr p)
if ( (r=ParseToken(p, &buf)) ) return r;
FindToken(DBufValue(&buf), &tok);
switch (tok.type) {
case T_Date:
DBufFree(&buf);
if (y != NO_YR) return E_YR_TWICE;
if (m != NO_MON) return E_MON_TWICE;
if (d != NO_DAY) return E_DAY_TWICE;
FromJulian(tok.val, &y, &m, &d);
break;
case T_Year:
DBufFree(&buf);
if (y != NO_YR) return E_YR_TWICE;
@@ -279,7 +319,7 @@ int DoOmit(ParsePtr p)
if (d != NO_DAY) return E_DAY_TWICE;
d = tok.val;
break;
case T_Delta:
DBufFree(&buf);
break;

View File

@@ -26,11 +26,12 @@ char const *CalendarTime (int tim, int duration);
int DoRem (ParsePtr p);
int DoFlush (ParsePtr p);
void DoExit (ParsePtr p);
int ParseRem (ParsePtr s, Trigger *trig, TimeTrig *tim);
int ParseRem (ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals);
int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int jul);
int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int jul);
int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int jul, int *err);
int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul, int mode);
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int jul, int tim);
int ParseLiteralDate (char const **s, int *jul, int *tim);
int EvalExpr (char const **e, Value *v);
int DoCoerce (char type, Value *v);
void PrintValue (Value *v, FILE *fp);
@@ -42,7 +43,7 @@ int IncludeFile (char const *fname);
int GetAccessDate (char const *file);
int SetAccessDate (char const *fname, int jul);
int TopLevel (void);
int CallFunc (Operator *f, int nargs);
int CallFunc (BuiltinFunc *f, int nargs);
void InitRemind (int argc, char const *argv[]);
void Usage (void);
int Julian (int year, int month, int day);
@@ -75,14 +76,14 @@ int DoClear (ParsePtr p);
int DestroyOmitContexts (void);
int PushOmitContext (ParsePtr p);
int PopOmitContext (ParsePtr p);
int IsOmitted (int jul, int localomit);
int IsOmitted (int jul, int localomit, char const *omitfunc, int *omit);
int DoOmit (ParsePtr p);
int QueueReminder (ParsePtr p, Trigger *trig, TimeTrig *tim, char const *sched);
void HandleQueuedReminders (void);
char const *FindInitialToken (Token *tok, char const *s);
void FindToken (char const *s, Token *tok);
void FindNumericToken (char const *s, Token *t);
int ComputeTrigger (int today, Trigger *trig, int *err);
int ComputeTrigger (int today, Trigger *trig, int *err, int save_in_globals);
char *StrnCpy (char *dest, char const *source, int n);
int StrMatch (char const *s1, char const *s2, int n);
int StrinCmp (char const *s1, char const *s2, int n);
@@ -104,7 +105,8 @@ int DoMsgCommand (char const *cmd, char const *msg);
int ParseNonSpaceChar (ParsePtr p, int *err, int peek);
unsigned int HashVal (char const *str);
int DateOK (int y, int m, int d);
Operator *FindFunc (char const *name, Operator where[], int num);
Operator *FindOperator (char const *name, Operator where[], int num);
BuiltinFunc *FindFunc (char const *name, BuiltinFunc where[], int num);
int InsertIntoSortBuffer (int jul, int tim, char const *body, int typ, int prio);
void IssueSortedReminders (void);
int UserFuncExists (char const *fn);
@@ -128,7 +130,7 @@ void LocalToUTC (int locdate, int loctime, int *utcdate, int *utctime);
void UTCToLocal (int utcdate, int utctime, int *locdate, int *loctime);
int MoonPhase (int date, int time);
void HuntPhase (int startdate, int starttim, int phas, int *date, int *time);
int CompareRems (int dat1, int tim1, int prio1, int dat2, int tim2, int prio2, int bydate, int bytime, int byprio);
int CompareRems (int dat1, int tim1, int prio1, int dat2, int tim2, int prio2, int bydate, int bytime, int byprio, int untimed_first);
void SigIntHandler (int d);
void GotSigInt (void);
void SynthesizeTag(char *);

View File

@@ -30,6 +30,7 @@
#define SPECIAL_MOON 3
#define SPECIAL_SHADE 4
#define SPECIAL_COLOR 5
#define SPECIAL_WEEK 6
typedef struct calentry {
struct calentry *next;
@@ -306,6 +307,7 @@ void DoPsCal(void)
if (!strcmp(passthru, "PostScript") ||
!strcmp(passthru, "PSFile") ||
!strcmp(passthru, "MOON") ||
!strcmp(passthru, "WEEK") ||
!strcmp(passthru, "SHADE")) {
is_ps = 1;
}
@@ -324,6 +326,8 @@ void DoPsCal(void)
c->special = SPECIAL_SHADE;
} else if (!strcmp(passthru, "MOON")) {
c->special = SPECIAL_MOON;
} else if (!strcmp(passthru, "WEEK")) {
c->special = SPECIAL_WEEK;
} else {
c->special = SPECIAL_PSFILE;
}
@@ -887,6 +891,7 @@ int DoQueuedPs(void)
int fnoff;
char buffer[512];
char const *size, *extra;
char const *s;
int num, r, g, b, phase, fontsize, moonsize;
unsigned char c;
@@ -954,6 +959,22 @@ int DoQueuedPs(void)
r/255.0, g/255.0, b/255.0);
break;
case SPECIAL_WEEK: /* Week number */
printf("gsave Border Border 2 div moveto /EntryFont findfont EntrySize 1.2 div scalefont setfont (");
s = e->entry+fnoff;
while(*s && isspace(*s)) {
s++;
}
while(*s) {
if (*s == '\\' || *s == '(' || *s == ')') {
PutChar('\\');
}
PutChar(*s);
s++;
}
printf(") show grestore\n");
break;
case SPECIAL_MOON: /* Moon phase */
num = sscanf(e->entry+fnoff, "%d %d %d", &phase, &moonsize,
&fontsize);

View File

@@ -83,6 +83,7 @@ int InsertIntoSortBuffer(int jul, int tim, char const *body, int typ, int prio)
SortByDate = 0;
SortByTime = 0;
SortByPrio = 0;
UntimedBeforeTimed = 0;
return E_NO_MEM;
}
@@ -94,8 +95,8 @@ int InsertIntoSortBuffer(int jul, int tim, char const *body, int typ, int prio)
while (cur) {
ShouldGoAfter = CompareRems(new->trigdate, new->trigtime, new->priority,
cur->trigdate, cur->trigtime, cur->priority,
SortByDate, SortByTime, SortByPrio);
SortByDate, SortByTime, SortByPrio, UntimedBeforeTimed);
if (ShouldGoAfter <= 0) {
prev = cur;
cur = cur->next;
@@ -203,19 +204,27 @@ static void IssueSortBanner(int jul)
/***************************************************************/
int CompareRems(int dat1, int tim1, int prio1,
int dat2, int tim2, int prio2,
int bydate, int bytime, int byprio)
int bydate, int bytime, int byprio,
int untimed_first)
{
int dafter, tafter, pafter;
int dafter, tafter, pafter, uafter;
dafter = (bydate != SORT_DESCEND) ? 1 : -1;
tafter = (bytime != SORT_DESCEND) ? 1 : -1;
pafter = (byprio != SORT_DESCEND) ? 1 : -1;
uafter = (untimed_first) ? -1 : 1;
if (dat1 < dat2) return dafter;
if (dat1 > dat2) return -dafter;
if (tim1 == NO_TIME && tim2 != NO_TIME) return -1;
if (tim1 != NO_TIME && tim2 == NO_TIME) return 1;
if (tim1 == NO_TIME && tim2 != NO_TIME) {
return -uafter;
}
if (tim1 != NO_TIME && tim2 == NO_TIME) {
return uafter;
}
if (tim1 < tim2) return tafter;
if (tim1 > tim2) return -tafter;

View File

@@ -74,6 +74,7 @@ Token TokArray[] = {
{ "november", 3, T_Month, 10 },
{ "october", 3, T_Month, 9 },
{ "omit", 3, T_Omit, 0 },
{ "omitfunc", 8, T_OmitFunc, 0 },
{ "once", 3, T_Once, 0 },
{ "pop-omit-context", 3, T_Pop, 0 },
{ "preserve", 8, T_Preserve, 0 },
@@ -255,12 +256,30 @@ void FindToken(char const *s, Token *tok)
void FindNumericToken(char const *s, Token *t)
{
int mult = 1, hour, min;
char const *s_orig = s;
t->type = T_Illegal;
t->val = 0;
if (isdigit(*s)) {
PARSENUM(t->val, s);
/* If we hit a '-' or a '/', we may have a date or a datetime */
if (*s == '-' || *s == '/') {
char const *p = s_orig;
int jul, tim;
if (ParseLiteralDate(&p, &jul, &tim) == OK) {
if (*p) return;
if (tim == NO_TIME) {
t->type = T_Date;
t->val = jul;
return;
}
t->type = T_DateTime;
t->val = MINUTES_PER_DAY * jul + tim;
}
return;
}
/* If we hit a comma, swallow it. This allows stuff
like Jan 6, 1998 */
if (*s == ',') {

View File

@@ -206,16 +206,27 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
*err = E_BAD_DATE;
return -1;
}
/* Back up a year in case we'll cross a year boundary*/
if (y > BASE) {
y--;
}
/* Move up to the first valid year */
while (trig->d > DaysInMonth(trig->m, y)) y++;
/* Try last year */
j = Julian(y, trig->m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
if (j >= startdate) return j;
/* Try this year */
y++;
j = Julian(y, trig->m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
if (j >= startdate) return j;
/* Must be next year */
y = y + 1;
y++;
while (trig->d > DaysInMonth(trig->m, y)) y++;
j = Julian(y, trig->m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
@@ -286,7 +297,7 @@ static int JYear(int jul)
/***************************************************************/
static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart)
{
int simple, mod;
int simple, mod, omit;
/* First: Have we passed the UNTIL date? */
if (trig->until != NO_UNTIL &&
@@ -294,8 +305,22 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
/* Next: If it's an "AFTER"-type skip, back up
until we're at the start of a block of holidays */
if (trig->skip == AFTER_SKIP)
while (IsOmitted(start-1, trig->localomit)) start--;
if (trig->skip == AFTER_SKIP) {
int iter = 0;
while (iter++ <= MaxSatIter) {
*err = IsOmitted(start-1, trig->localomit, trig->omitfunc, &omit);
if (*err) return -2;
if (!omit) {
break;
}
start--;
}
if (iter > MaxSatIter) {
/* omitfunc must have returned "true" too often */
*err = E_CANT_TRIG;
return -2;
}
}
/* Find the next simple trigger */
simple = NextSimpleTrig(start, trig, err);
@@ -309,12 +334,29 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
/* If there's a BACK, back up... */
if (trig->back != NO_BACK) {
mod = trig->back;
if (mod < 0) simple += mod;
else
while(mod) {
simple--;
if (!IsOmitted(simple, trig->localomit)) mod--;
if (mod < 0) {
simple += mod;
}
else {
int iter = 0;
int max = MaxSatIter;
if (max < mod*2) {
max = mod*2;
}
while(iter++ <= max) {
if (!mod) {
break;
}
simple--;
*err = IsOmitted(simple, trig->localomit, trig->omitfunc, &omit);
if (*err) return -2;
if (!omit) mod--;
}
if (iter > max) {
*err = E_CANT_TRIG;
return -2;
}
}
}
/* If there's a REP, calculate the next occurrence */
@@ -327,12 +369,38 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
}
/* If it's a "BEFORE"-type skip, back up */
if (trig->skip == BEFORE_SKIP)
while(IsOmitted(simple, trig->localomit)) simple--;
if (trig->skip == BEFORE_SKIP) {
int iter = 0;
while(iter++ <= MaxSatIter) {
*err = IsOmitted(simple, trig->localomit, trig->omitfunc, &omit);
if (*err) return -2;
if (!omit) {
break;
}
simple--;
}
if (iter > MaxSatIter) {
*err = E_CANT_TRIG;
return -2;
}
}
/* If it's an "AFTER"-type skip, jump ahead */
if (trig->skip == AFTER_SKIP)
while (IsOmitted(simple, trig->localomit)) simple++;
if (trig->skip == AFTER_SKIP) {
int iter = 0;
while (iter++ <= MaxSatIter) {
*err = IsOmitted(simple, trig->localomit, trig->omitfunc, &omit);
if (*err) return -2;
if (!omit) {
break;
}
simple++;
}
if (iter > MaxSatIter) {
*err = E_CANT_TRIG;
return -2;
}
}
/* Return the date */
return simple;
@@ -346,15 +414,15 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
/* today's date. */
/* */
/***************************************************************/
int ComputeTrigger(int today, Trigger *trig, int *err)
int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
{
int nattempts = 0,
start = today,
nextstart = 0,
y, m, d,
y, m, d, omit,
result;
LastTrigValid = 0;
if (save_in_globals) LastTrigValid = 0;
/* Assume everything works */
*err = OK;
@@ -373,8 +441,8 @@ int ComputeTrigger(int today, Trigger *trig, int *err)
*err = E_REP_FULSPEC;
return -1;
}
while (nattempts++ < TRIG_ATTEMPTS) {
result = GetNextTriggerDate(trig, start, err, &nextstart);
@@ -389,10 +457,18 @@ int ComputeTrigger(int today, Trigger *trig, int *err)
}
/* If result is >= today, great! */
if (trig->skip == SKIP_SKIP) {
*err = IsOmitted(result, trig->localomit, trig->omitfunc, &omit);
if (*err) return -1;
} else {
omit = 0;
}
if (result >= today &&
(trig->skip != SKIP_SKIP || !IsOmitted(result, trig->localomit))) {
LastTriggerDate = result; /* Save in global var */
LastTrigValid = 1;
(trig->skip != SKIP_SKIP || !omit)) {
if (save_in_globals) {
LastTriggerDate = result; /* Save in global var */
LastTrigValid = 1;
}
if (DebugFlag & DB_PRTTRIG) {
FromJulian(result, &y, &m, &d);
fprintf(ErrFp, "%s(%d): Trig = %s, %d %s, %d\n",
@@ -414,14 +490,16 @@ int ComputeTrigger(int today, Trigger *trig, int *err)
FileName, LineNo, ErrMsg[E_EXPIRED]);
}
if (result != -1) {
LastTriggerDate = result;
LastTrigValid = 1;
if (save_in_globals) {
LastTriggerDate = result;
LastTrigValid = 1;
}
}
return -1;
}
if (trig->skip == SKIP_SKIP &&
IsOmitted(result, trig->localomit) &&
omit &&
nextstart <= start &&
result >= start) {
nextstart = result + 1;
@@ -430,8 +508,10 @@ int ComputeTrigger(int today, Trigger *trig, int *err)
/* Keep scanning... unless there's no point in doing it.*/
if (nextstart <= start) {
if (result != -1) {
LastTriggerDate = result;
LastTrigValid = 1;
if (save_in_globals) {
LastTriggerDate = result;
LastTrigValid = 1;
}
}
if (DebugFlag & DB_PRTTRIG) {
fprintf(ErrFp, "%s(%d): %s\n",

View File

@@ -30,6 +30,20 @@ typedef struct {
int (*func)(void);
} Operator;
/* Structure for passing in Nargs and out RetVal from functions */
typedef struct {
int nargs;
Value retval;
} func_info;
/* Define the type of user-functions */
typedef struct {
char const *name;
char minargs;
char maxargs;
int (*func)(func_info *);
} BuiltinFunc;
/* Define the structure of a variable */
typedef struct var {
struct var *next;
@@ -56,6 +70,7 @@ typedef struct {
int priority;
char sched[VAR_NAME_LEN+1]; /* Scheduling function */
char warn[VAR_NAME_LEN+1]; /* Warning function */
char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */
char tag[TAG_LEN+1];
char passthru[PASSTHRU_LEN+1];
} Trigger;
@@ -132,7 +147,7 @@ enum TokTypes
T_IfTrig, T_ErrMsg,
T_Set, T_UnSet, T_Fset, T_Omit, T_Banner, T_Exit,
T_WkDay,
T_Month, T_Time,
T_Month, T_Time, T_Date, T_DateTime,
T_Skip, T_At, T_RemType, T_Until, T_Year, T_Day, T_Rep, T_Delta, T_Back,
T_Once,
T_Empty,
@@ -148,7 +163,8 @@ enum TokTypes
T_Warn,
T_Tag,
T_Duration,
T_LongTime
T_LongTime,
T_OmitFunc
};
/* The structure of a token */

View File

@@ -40,7 +40,7 @@ static UserFunc *FuncHash[FUNC_HASH_SIZE];
/* Access to built-in functions */
extern int NumFuncs;
extern Operator Func[];
extern BuiltinFunc Func[];
/* We need access to the expression evaluation stack */
extern Value ValStack[];

View File

@@ -223,7 +223,7 @@ int DoSet (Parser *p)
r = ParseIdentifier(p, &buf);
if (r) return r;
/* Allow option equals-sign: SET var = value */
/* Allow optional equals-sign: SET var = value */
if (ParseNonSpaceChar(p, &r, 1) == '=') {
ParseNonSpaceChar(p, &r, 0);
}
@@ -488,6 +488,7 @@ static SysVar SysVarArr[] = {
{ "LongMin", 1, INT_TYPE, &LongMin, -59, 59 },
{ "LongSec", 1, INT_TYPE, &LongSec, -59, 59 },
{ "MaxSatIter", 1, INT_TYPE, &MaxSatIter, 10, ANY },
{ "MaxStringLen", 1, INT_TYPE, &MaxStringLen, -1, ANY },
{ "MinsFromUTC", 1, INT_TYPE, &MinsFromUTC, -13*60, 13*60 },
{ "NextMode", 0, INT_TYPE, &NextMode, 0, 0 },
{ "NumQueued", 0, INT_TYPE, &NumQueued, 0, 0 },
@@ -500,7 +501,8 @@ static SysVar SysVarArr[] = {
{ "SortByPrio", 0, INT_TYPE, &SortByPrio, 0, 0},
{ "SortByTime", 0, INT_TYPE, &SortByTime, 0, 0},
{ "SubsIndent", 1, INT_TYPE, &SubsIndent, 0, 132},
{ "TimeSep", 1, SPECIAL_TYPE, time_sep_func, 0, 0 }
{ "TimeSep", 1, SPECIAL_TYPE, time_sep_func, 0, 0 },
{ "UntimedFirst", 0, INT_TYPE, &UntimedBeforeTimed, 0, 0 }
};
#define NUMSYSVARS ( sizeof(SysVarArr) / sizeof(SysVar) )

3
tests/runinc.rem Normal file
View File

@@ -0,0 +1,3 @@
set s shell("echo 3")
run on
set s shell("echo 3")

6
tests/runtest.rem Normal file
View File

@@ -0,0 +1,6 @@
run off
set a shell("echo 2")
run on
set a shell("echo 2")
run off
include ../tests/runinc.rem

View File

@@ -60,6 +60,15 @@ chmod 644 include_dir/04cantread.rem
echo "Color Test" >> ../tests/test.out
../src/remind -ccl ../tests/colors.rem 1 aug 2007 >> ../tests/test.out
echo "MON WKDAY DAY across year test" >> ../tests/test.out
echo 'REM Mon 29 Dec MSG x' | ../src/remind -dt - 1 Jan 2000 >> ../tests/test.out 2>&1
echo "Sort Test" >> ../tests/test.out
(echo "REM AT 12:00 MSG Untimed"; echo "REM MSG Timed") | ../src/remind -gaaa - 1 Jan 2000 >> ../tests/test.out 2>&1
(echo "REM AT 12:00 MSG Untimed"; echo "REM MSG Timed") | ../src/remind -gaaad - 1 Jan 2000 >> ../tests/test.out 2>&1
../src/remind ../tests/runtest.rem >> ../tests/test.out 2>&1
cmp -s ../tests/test.out ../tests/test.cmp
if [ "$?" = "0" ]; then
echo "Remind: Acceptance test PASSED"

View File

@@ -431,7 +431,7 @@ REM 1 Mar --1 MSG 1 mar --1
../tests/test.rem(133): Trig = Thursday, 28 February, 1991
REM 28 Feb BEFORE MSG 28 Feb BEFORE
../tests/test.rem(134): Trig = Thursday, 28 February, 1991
REM 28 Feb SKIP MSG 28 Feb SKIP
REM 28 Feb SKIP MSG 28 Feb SKIP
../tests/test.rem(135): Trig = Thursday, 28 February, 1991
REM 28 Feb AFTER MSG 28 Feb AFTER
../tests/test.rem(136): Trig = Thursday, 28 February, 1991
@@ -451,7 +451,7 @@ REM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted)
REM 13 March 1991 *1 UNTIL 19 March 1991 MSG 13-19 Mar 91
../tests/test.rem(146): Trig = Wednesday, 13 March, 1991
# Test BACK
CLEAR-OMIT-CONTEXT
REM 18 Feb 1991 +1 MSG 18 Feb 1991 +1
@@ -488,6 +488,200 @@ REM Fri after MSG 16 Feb 1991
16 Feb 1991
CLEAR-OMIT-CONTEXT
# Test omitfunc
fset _ofunc(x) (day(x) < 7 || day(x) % 2)
REM 1 March OMITFUNC _ofunc AFTER MSG OmitFunc Test
Entering UserFN _ofunc(1991-02-15)
x => 1991-02-15
day(1991-02-15) => 15
15 < 7 => 0
x => 1991-02-15
day(1991-02-15) => 15
15 % 2 => 1
0 || 1 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-02-14)
x => 1991-02-14
day(1991-02-14) => 14
14 < 7 => 0
x => 1991-02-14
day(1991-02-14) => 14
14 % 2 => 0
0 || 0 => 0
Leaving UserFN _ofunc() => 0
Entering UserFN _ofunc(1991-03-01)
x => 1991-03-01
day(1991-03-01) => 1
1 < 7 => 1
x => 1991-03-01
day(1991-03-01) => 1
1 % 2 => 1
1 || 1 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-02)
x => 1991-03-02
day(1991-03-02) => 2
2 < 7 => 1
x => 1991-03-02
day(1991-03-02) => 2
2 % 2 => 0
1 || 0 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-03)
x => 1991-03-03
day(1991-03-03) => 3
3 < 7 => 1
x => 1991-03-03
day(1991-03-03) => 3
3 % 2 => 1
1 || 1 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-04)
x => 1991-03-04
day(1991-03-04) => 4
4 < 7 => 1
x => 1991-03-04
day(1991-03-04) => 4
4 % 2 => 0
1 || 0 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-05)
x => 1991-03-05
day(1991-03-05) => 5
5 < 7 => 1
x => 1991-03-05
day(1991-03-05) => 5
5 % 2 => 1
1 || 1 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-06)
x => 1991-03-06
day(1991-03-06) => 6
6 < 7 => 1
x => 1991-03-06
day(1991-03-06) => 6
6 % 2 => 0
1 || 0 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-07)
x => 1991-03-07
day(1991-03-07) => 7
7 < 7 => 0
x => 1991-03-07
day(1991-03-07) => 7
7 % 2 => 1
0 || 1 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-08)
x => 1991-03-08
day(1991-03-08) => 8
8 < 7 => 0
x => 1991-03-08
day(1991-03-08) => 8
8 % 2 => 0
0 || 0 => 0
Leaving UserFN _ofunc() => 0
../tests/test.rem(169): Trig = Friday, 8 March, 1991
REM 8 March OMITFUNC _ofunc -1 MSG OmitFunc Test 2
Entering UserFN _ofunc(1991-03-07)
x => 1991-03-07
day(1991-03-07) => 7
7 < 7 => 0
x => 1991-03-07
day(1991-03-07) => 7
7 % 2 => 1
0 || 1 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-06)
x => 1991-03-06
day(1991-03-06) => 6
6 < 7 => 1
x => 1991-03-06
day(1991-03-06) => 6
6 % 2 => 0
1 || 0 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-05)
x => 1991-03-05
day(1991-03-05) => 5
5 < 7 => 1
x => 1991-03-05
day(1991-03-05) => 5
5 % 2 => 1
1 || 1 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-04)
x => 1991-03-04
day(1991-03-04) => 4
4 < 7 => 1
x => 1991-03-04
day(1991-03-04) => 4
4 % 2 => 0
1 || 0 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-03)
x => 1991-03-03
day(1991-03-03) => 3
3 < 7 => 1
x => 1991-03-03
day(1991-03-03) => 3
3 % 2 => 1
1 || 1 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-02)
x => 1991-03-02
day(1991-03-02) => 2
2 < 7 => 1
x => 1991-03-02
day(1991-03-02) => 2
2 % 2 => 0
1 || 0 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-03-01)
x => 1991-03-01
day(1991-03-01) => 1
1 < 7 => 1
x => 1991-03-01
day(1991-03-01) => 1
1 % 2 => 1
1 || 1 => 1
Leaving UserFN _ofunc() => 1
Entering UserFN _ofunc(1991-02-28)
x => 1991-02-28
day(1991-02-28) => 28
28 < 7 => 0
x => 1991-02-28
day(1991-02-28) => 28
28 % 2 => 0
0 || 0 => 0
Leaving UserFN _ofunc() => 0
../tests/test.rem(170): Trig = Thursday, 28 February, 1991
# omitfunc ignores local/global omits
fset _ofunc(x) 0
OMIT 1 March
OMIT 2 March 1991
REM 1 March OMIT Sun OMITFUNC _ofunc AFTER MSG Should trigger 1 March
../tests/test.rem(176): Warning: OMIT is ignored if you use OMITFUNC
Entering UserFN _ofunc(1991-02-15)
Leaving UserFN _ofunc() => 0
Entering UserFN _ofunc(1991-03-01)
Leaving UserFN _ofunc() => 0
../tests/test.rem(176): Trig = Friday, 1 March, 1991
REM 1 March OMIT Sun AFTER MSG Should trigger 4 March
../tests/test.rem(177): Trig = Monday, 4 March, 1991
# Test shorthand reminders
REM 1991-02-28 MSG Feb 28
../tests/test.rem(180): Trig = Thursday, 28 February, 1991
REM 1991/02/28@14:45 MSG Feb 28
../tests/test.rem(181): Trig = Thursday, 28 February, 1991
REM Wed UNTIL 1991-01-01 MSG Expired
../tests/test.rem(182): Expired
REM Wed SCANFROM 1991-02-26 MSG SCANFROM
../tests/test.rem(183): Trig = Wednesday, 27 February, 1991
set a000 abs(1)
abs(1) => 1
set a001 abs(-1)
@@ -510,7 +704,7 @@ set a008 coerce("string", 11:44)
coerce("string", 11:44) => "11:44"
set a009 coerce("int", "badnews")
coerce("int", "badnews") => Can't coerce
../tests/test.rem(175): Can't coerce
../tests/test.rem(194): Can't coerce
set a010 coerce("int", "12")
coerce("int", "12") => 12
set a011 coerce("int", 11:44)
@@ -522,7 +716,7 @@ set a013 date(1992, 2, 2)
date(1992, 2, 2) => 1992-02-02
set a014 date(1993, 2, 29)
date(1993, 2, 29) => Bad date specification
../tests/test.rem(180): Bad date specification
../tests/test.rem(199): Bad date specification
set a015 day(today())
today() => 1991-02-16
day(1991-02-16) => 16
@@ -617,15 +811,15 @@ strlen("sadjflkhsldkfhsdlfjhk") => 21
set a050 substr(a049, 2)
a049 => 21
substr(21, 2) => Type mismatch
../tests/test.rem(218): Type mismatch
../tests/test.rem(237): Type mismatch
set a051 substr(a050, 2, 6)
a050 => ../tests/test.rem(219): Undefined variable: a050
a050 => ../tests/test.rem(238): Undefined variable: a050
set a052 time(1+2, 3+4)
1 + 2 => 3
3 + 4 => 7
time(3, 7) => 03:07
rem 10 jan 1992 AT 11:22 CAL
../tests/test.rem(221): Trig = Friday, 10 January, 1992
../tests/test.rem(240): Trig = Friday, 10 January, 1992
set a053 trigdate()
trigdate() => 1992-01-10
set a054 trigtime()
@@ -638,7 +832,7 @@ set a057 value("a05"+"6")
"a05" + "6" => "a056"
value("a056") => "SDFJHSDF KSJDFH KJSDFH KSJDFH"
set a058 version()
version() => "03.01.05"
version() => "03.01.07"
set a059 wkday(today())
today() => 1991-02-16
wkday(1991-02-16) => "Saturday"
@@ -717,31 +911,31 @@ y => 11:33
x => "foo"
y => 11:33
"foo" * 11:33 => Type mismatch
../tests/test.rem(244): `*': Type mismatch
../tests/test.rem(263): `*': Type mismatch
Leaving UserFN h() => Type mismatch
set a074 dosubst("%a %b %c %d %e %f %g %h", '1992/5/5')
dosubst("%a %b %c %d %e %f %g %h", 1992-05-05) => "on Tuesday, 5 May, 1992 in 444 days' tim"...
msg [a074]%
../tests/test.rem(246): Trig = Saturday, 16 February, 1991
../tests/test.rem(265): Trig = Saturday, 16 February, 1991
a074 => "on Tuesday, 5 May, 1992 in 444 days' tim"...
on Tuesday, 5 May, 1992 in 444 days' time on Tuesday 5 on 05-05-1992 on 05-05-1992 on Tuesday, 5 May on 05-05
set a075 dosubst("%i %j %k %l %m %n %o %p", '1992/5/5')
dosubst("%i %j %k %l %m %n %o %p", 1992-05-05) => "on 05-05 on Tuesday, May 5th, 1992 on Tu"...
msg [a075]%
../tests/test.rem(248): Trig = Saturday, 16 February, 1991
../tests/test.rem(267): Trig = Saturday, 16 February, 1991
a075 => "on 05-05 on Tuesday, May 5th, 1992 on Tu"...
on 05-05 on Tuesday, May 5th, 1992 on Tuesday, May 5th on 1992-05-05 May 5 s
set a076 dosubst("%q %r %s %t %u %v %w %x", '1992/5/5')
dosubst("%q %r %s %t %u %v %w %x", 1992-05-05) => "s' 05 th 05 on Tuesday, 5th May, 1992 on"...
msg [a076]%
../tests/test.rem(250): Trig = Saturday, 16 February, 1991
../tests/test.rem(269): Trig = Saturday, 16 February, 1991
a076 => "s' 05 th 05 on Tuesday, 5th May, 1992 on"...
s' 05 th 05 on Tuesday, 5th May, 1992 on Tuesday, 5th May Tuesday 444
set a077 dosubst("%y %z", '1992/5/5')
dosubst("%y %z", 1992-05-05) => "1992 92
"
msg [a077]%
../tests/test.rem(252): Trig = Saturday, 16 February, 1991
../tests/test.rem(271): Trig = Saturday, 16 February, 1991
a077 => "1992 92
"
1992 92
@@ -753,6 +947,16 @@ easterdate(1992) => 1992-04-19
set a080 easterdate(1995)
easterdate(1995) => 1995-04-16
set a081 ""
OMIT 1991-03-11
set a082 slide('1991-03-01', 7, "Sat", "Sun")
slide(1991-03-01, 7, "Sat", "Sun") => 1991-03-13
set a083 slide('1991-04-01', -7, "Sat")
- 7 => -7
slide(1991-04-01, -7, "Sat") => 1991-03-24
set a084 nonomitted('1991-03-01', '1991-03-13', "Sat", "Sun")
nonomitted(1991-03-01, 1991-03-13, "Sat", "Sun") => 7
set a085 nonomitted('1991-03-24', '1991-04-01', "Sat")
nonomitted(1991-03-24, 1991-04-01, "Sat") => 7
dump
Variable Value
@@ -764,6 +968,7 @@ dump
a027 0
a046 "ies"
a065 1
a084 7
a018 1
a037 1991-02-15
a056 "SDFJHSDF KSJDFH KJSDFH KSJDFH"
@@ -771,6 +976,7 @@ dump
a028 1
a047 -1
a066 0
a085 7
a019 0
a038 33
a057 "SDFJHSDF KSJDFH KJSDFH KSJDFH"
@@ -779,7 +985,7 @@ dump
a048 "foo"
a067 "INT"
a039 "February"
a058 "03.01.05"
a058 "03.01.07"
a077 "1992 92
"
a049 21
@@ -827,6 +1033,7 @@ dump
a025 4
a044 "s"
a063 0
a082 1991-03-13
a016 28
a035 1
a054 11:22
@@ -834,6 +1041,7 @@ dump
a026 7
a045 "iess"
a064 1
a083 1991-03-24
Test 2
@@ -1922,4 +2130,23 @@ Color Test
(0x(B (0x(B (0x(BBright (0x(B (0x(B (0x(B (0x(B (0x(B
(0x(B (0x(B (0x(BWhite (0x(B (0x(B (0x(B (0x(B (0x(B
(0mqqqqqqqqqqvqqqqqqqqqqvqqqqqqqqqqvqqqqqqqqqqvqqqqqqqqqqvqqqqqqqqqqvqqqqqqqqqqj(B
MON WKDAY DAY across year test
-(1): Trig = Monday, 3 January, 2000
No reminders.
Sort Test
Reminders for Saturday, 1st January, 2000:
Untimed
Timed
Reminders for Saturday, 1st January, 2000:
Timed
Untimed
../tests/runtest.rem(2): shell(): RUN disabled
../tests/runinc.rem(1): shell(): RUN disabled
../tests/runinc.rem(3): shell(): RUN disabled
No reminders.

View File

@@ -132,7 +132,7 @@ CLEAR-OMIT-CONTEXT
REM 1 Mar -1 MSG 1 mar -1
REM 1 Mar --1 MSG 1 mar --1
REM 28 Feb BEFORE MSG 28 Feb BEFORE
REM 28 Feb SKIP MSG 28 Feb SKIP
REM 28 Feb SKIP MSG 28 Feb SKIP
REM 28 Feb AFTER MSG 28 Feb AFTER
POP-OMIT-CONTEXT
@@ -144,7 +144,7 @@ REM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted)
REM 13 March 1991 *1 UNTIL 19 March 1991 MSG 13-19 Mar 91
# Test BACK
CLEAR-OMIT-CONTEXT
REM 18 Feb 1991 +1 MSG 18 Feb 1991 +1
@@ -163,6 +163,25 @@ REM Fri SCANFROM [trigger(today()-7)] SATISFY 1
OMIT [trigger(trigdate())]
REM Fri after MSG 16 Feb 1991
CLEAR-OMIT-CONTEXT
# Test omitfunc
fset _ofunc(x) (day(x) < 7 || day(x) % 2)
REM 1 March OMITFUNC _ofunc AFTER MSG OmitFunc Test
REM 8 March OMITFUNC _ofunc -1 MSG OmitFunc Test 2
# omitfunc ignores local/global omits
fset _ofunc(x) 0
OMIT 1 March
OMIT 2 March 1991
REM 1 March OMIT Sun OMITFUNC _ofunc AFTER MSG Should trigger 1 March
REM 1 March OMIT Sun AFTER MSG Should trigger 4 March
# Test shorthand reminders
REM 1991-02-28 MSG Feb 28
REM 1991/02/28@14:45 MSG Feb 28
REM Wed UNTIL 1991-01-01 MSG Expired
REM Wed SCANFROM 1991-02-26 MSG SCANFROM
set a000 abs(1)
set a001 abs(-1)
set a002 asc("foo")
@@ -254,4 +273,9 @@ set a078 easterdate(today())
set a079 easterdate(1992)
set a080 easterdate(1995)
set a081 ""
OMIT 1991-03-11
set a082 slide('1991-03-01', 7, "Sat", "Sun")
set a083 slide('1991-04-01', -7, "Sat")
set a084 nonomitted('1991-03-01', '1991-03-13', "Sat", "Sun")
set a085 nonomitted('1991-03-24', '1991-04-01', "Sat")
dump

View File

@@ -9,7 +9,7 @@ my %Options;
my $rem2html_version = '2.0';
my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mondayfirst,
my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mondayfirst, $weeks,
@Daynames, $Nextmon, $Nextlen, $Prevmon, $Prevlen);
my $TIDY_PROGNAME = $0;
@@ -186,6 +186,7 @@ sub parse_input
undef $shades;
undef $moons;
undef $classes;
undef $weeks;
my $found_data = 0;
while(<STDIN>) {
@@ -232,10 +233,16 @@ sub parse_input
next unless m/^(\d*).(\d*).(\d*)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/;
my ($y, $m, $d, $special, $tag, $duration, $time, $body) =
($1, $2, $3, $4, $5, $6, $7, $8);
my $d1 = $d;
$d1 =~ s/^0+//;
if ($special eq 'HTML') {
push(@{$days->[$d]}, $body);
} elsif ($special eq 'HTMLCLASS') {
$classes->[$d] = $body;
} elsif ($special eq 'WEEK') {
$body =~ s/^\s+//;
$body =~ s/\s+$//;
$weeks->{$d1} = $body;
} elsif ($special eq 'MOON') {
if ($body =~ /(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) {
my ($phase, $moonsize, $fontsize, $msg) = ($1, $2, $3, $4);
@@ -362,7 +369,6 @@ sub output_calendar
# Last column
my $last_col = ($first_col + $Numdays - 1) % 7;
# Start the table
my $class;
if ($Options{'nostyle'}) {
@@ -475,6 +481,10 @@ sub draw_day_cell
{
my($day) = @_;
my $shade = $shades->[$day];
my $week = '';
if (exists($weeks->{$day})) {
$week = ' ' . $weeks->{$day};
}
my $class;
if ($Options{'nostyle'}) {
$class = $classes->[$day] || '';
@@ -529,10 +539,10 @@ sub draw_day_cell
}
if ($Options{'nostyle'}) {
print "<div style=\"float: right\">$day</div>\n";
print "<div style=\"float: right\">$day$week</div>\n";
print "<p>&nbsp;</p>\n";
} else {
print "<div class=\"rem-daynumber\">$day</div>\n";
print "<div class=\"rem-daynumber\">$day$week</div>\n";
}
if ($days->[$day]) {
print(join("\n", @{$days->[$day]}));