Files
ical2rem/contrib/remind/remind.md

7235 lines
272 KiB
Markdown

# NAME
remind - a sophisticated reminder service
# SYNOPSIS
**remind \[*options*\] *filename* \[*date*\] \[*\*rep*\] \[*time*\]**
# DESCRIPTION
**Remind** reads the supplied *filename* and executes the commands found
in it. The commands are used to issue reminders and alarms. Each
reminder or alarm can consist of a message sent to standard output, or a
program to be executed.
If *filename* is specified as a single dash \'-\', then **Remind** takes
its input from standard input. In this case, if **Remind** has been
compiled against the GNU Readline library, it will use Readline to give
you an interactive line-editing interface.
If *filename* happens to be a directory rather than a plain file, then
**Remind** reads all of the files (but not any subdirectories!) in that
directory that match the pattern \"\*.rem\". The files are read in
sorted order; the sort order may depend on your locale, but should match
the sort order used by the shell to expand \"\*.rem\".
**Remind** reads its files starting from the beginning to the end, or
until it encounters a line whose sole content is \"\_\_EOF\_\_\"
(without the quotes.) Anything after the \_\_EOF\_\_ marker is
completely ignored.
# MODES OF OPERATION
**Remind** has four major modes of operation:
**Agenda Mode**
: Agenda mode is the default mode. In this mode, **Remind** prints
today\'s reminders on standard output and exits. It may fork a
background process to pop up queued reminders for later in the day.
**Calendar Mode**
: In this mode, **Remind** generates a calendar either by drawing it
in the terminal or by sending data in computer-readable format to a
back-end program that actually draws the calendar.
**Daemon Mode**
: This is a special mode of operation in which **Remind** is invoked
by a front-end and runs as a daemon, accepting requests from the
front-end and sending messages back to the front-end. **TkRemind**
uses **Remind** in daemon mode.
**Purge Mode**
: In this mode, **Remind** produces no output, but creates new
versions of its input files with all expired reminders commented
out.
# OPTIONS
**Remind** has a slew of options. If you\'re new to the program, ignore
them for now and skip to the section \"REMINDER FILES\".
**-n**
: The **-n** option causes **Remind** to print the **next** occurrence
of each reminder in a simple calendar format. You can sort this by
date by piping the output through **sort(1)**. Note that the **-n**
option causes any **-g** option to be *ignored* and also implicitly
enables the **-o** option.
**-j\[*n*\]**
: Runs **Remind** in \"purge\" mode to get rid of expired reminders.
See the section PURGE MODE for details.
**-r**
: The **-r** option disables **RUN** directives and the **shell()**
function.
**-c**_\[flags\]n_
: The **-c** option causes **Remind** to produce a calendar that is
sent to standard output. If you supply a number *n*, then a calendar
will be generated for *n* months, starting with the current month.
By default, a calendar for only the current month is produced. This
option implicitly enables the **-o** option.
You can precede *n* (if any) with a set of flags. The flags are as
follows:
**\'+\'**
: causes a calendar for *n* weeks to be produced.
**\'a\'**
: causes **Remind** to display reminders on the calendar on the
day they actually occur *as well as* on any preceding days
specified by the reminder\'s *delta*. This *also* causes
**Remind** to include text outside %\"\...%\" sequences that
would otherwise be removed (though the actual %\" markers
themselves are removed.)
**\'l\'**
: causes **Remind** to use VT100 line-drawing characters to draw
the calendar. The characters are hard-coded and will only work
on terminals that emulate the VT00 line-drawing character set.
**\'u\'**
: is similar to \'l\', but causes **Remind** to use UNICODE
line-drawing characters to draw the calendar. The characters are
hard-coded and will only work on terminals that are set to UTF-8
character encoding. This flag also enables the use of the
UNICODE \"left-to-right\" mark that can fix up formatting
problems with right-to-left languages in the calendar display.
**\'z\'**
: causes **Remind** to use escape sequences to turn reminders with
a \"URL\" info string into hyperlinks. In order to work, your
terminal must support the escape sequences documented at
https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
**\'c\'**
: causes **Remind** to use VT100 escape sequences to approximate
SPECIAL COLOR reminders. Note that this flag is kept for
backwards-compatibility; you should use the
**-@**_\[n\]\[,m\]\[,b\]_ command-line option instead.
In a UTF-8 locale, **Remind** will use \"left-to-right marks\" when
creating a calendar with the **-c** option. Some terminals don\'t
handle this correctly and garble the rendering of the calendar; see
the documentation of **\$SuppressLRM** in the section \"SYSTEM
VARIABLES\" for a workaround.
**-@\[*n*\]\[,*m*\]\[,*b*\]**
: Tells **Remind** to approximate SPECIAL COLOR and SHADE reminders
using VT100 escape sequences. The approximation is (of necessity)
very coarse, because the VT100 only has eight different color
sequences, each with one of two brightnesses. A color component
greater than 64 is considered \"on\", and if any of the three color
components is greater than 128, the color is considered \"bright\".
If you supply the optional numeric parameters, the have the
following meanings: *n*=0 tells **Remind** to use the standard 16
VT100 colors. *n*=1 tells it to use an extended 256-color palette
supported by many terminal emulators such as xterm. And *n*=2 tells
it to use escape sequences that support true 24-bit colors, again
supported by many terminal emulators such as xterm.
If the optional *m* parameter is supplied following a comma, then
*m*=0 tells **Remind** that the terminal background is dark, and
**Remind** will brighten up dark colors to make them visible. If
*m*=1, then **Remind** assumes the terminal background is light and
it will darken bright colors to make them visible. If *m* is
specified as 2, then **Remind** does not perform any adjustments,
and some reminders may be hard or impossible to see if the color is
too close to the terminal background color. If you supply the letter
**t** rather than a number, then **Remind** attempts to guess the
background color of the terminal, *even if* stdout is not a
terminal.
On startup, if the standard output is a terminal, **Remind**
attempts to determine if the terminal background is dark or light by
sending a special escape sequence to determine the background color.
The *m* parameter can override this check (or force it if *m* is
given as **t**.)
If the optional *b* parameter is supplied following a comma, then
*b=0* tells **Remind** to ignore SPECIAL SHADE reminders (the
default) and *b=1* tells **Remind** to respect SPECIAL SHADE
reminders by emitting VT100 escape codes to color the background of
the calendar cell. Note that SHADE does not work well unless you are
using the extended 256-color palette (*n*=1) or the true 24-bit
colors (*n*=2). Note that for calendar cells that are shaded, the
clamping mechanism described earlier for *m=0* or *m=1* is skipped;
it is assumed that if you set *both* the foreground color of a
reminder and the background color of a cell, then you know what you
are doing.
**-w*col*\[,*pad*\[,*spc*\]\]\]**
: The **-w** option specifies the output width, padding and spacing of
the formatted calendar output. *Col* specifies the number of columns
in the output device. If *col* is not specified, or is specified as
0, it defaults to the larger of 71 or the actual width of your
terminal, or to 80 if standard output is not a terminal. If *col* is
specified as the letter **t**, then **Remind** attempts to get the
width of the **/dev/tty** terminal device. This is useful, for
example, if you pipe calendar output into **less**; even though
standard output is a pipe, you want the calendar to be sized
correctly for your terminal window:
remind -c -wt .reminders | less
> Note that the value of *col* is also used to set the system variable
> \$FormWidth, which is initialized to *col* - 8. See \"SYSTEM
> VARIABLES\" for details.
>
> *Pad* specifies how many lines to use to \"pad\" empty calendar boxes.
> This defaults to 5. If you have many reminders on certain days that
> make your calendar too large to fit on a page, you can try reducing
> *pad* to make the empty boxes smaller. *Spc* specifies how many blank
> lines to leave between the day number and the first reminder entry. It
> defaults to 1.
>
> Any of *col*, *pad* or *spc* can be omitted, providing you provide the
> correct number of commas. Don\'t use any spaces in the option.
**-s\[a\]n**
: The **-s** option is very similar to the **-c** option, except that
the output calendar is not formatted. It is listed in a \"simple
format\" that can be used as input for more sophisticated
calendar-drawing programs. If *n* starts with \"+\", then it is
interpreted as a number of weeks. This option also implicitly
enables the **-o** option.
If you immediately follow the **s** with the letter **a**, then
**Remind** displays reminders on the calendar on the day they
actually occur *as well as* on any preceding days specified by the
reminder\'s *delta*.
**-p\[a\]\[p\]\[p\]\[q\]\[+\]n**
: The **-p** option is very similar to the **-s** option, except that
the output contains additional information for use by a back-end
such as the **Rem2PS** program, which creates a PostScript calendar,
and various other back-end programs. If *n* starts with \"+\", then
it specifies a number of weeks rather than a number of months, and
back-ends are expected to produce weekly calendars. Note that not
all back-ends support weekly calendars; currently, only **rem2pdf**
and **rem2html** do. Specifying a weekly calendar implicitly enables
the pure JSON interchange format, similar to **-ppp**.
The format of the **-p** output is described in the **rem2ps(1)**
man page. If you immediately follow the **p** with the letter **a**,
then **Remind** displays reminders on the calendar on the day they
actually occur *as well as* on any preceding days specified by the
reminder\'s *delta*. If you follow the **p** with another **p**,
then **Remind** uses a more comprehensive JSON-based format rather
than the \"simple calendar\" format. This format is also documented
in the **rem2ps(1)** man page. Finally, if you use three p\'s, as in
**-ppp**, then **Remind** uses a pure JSON format, again documented
in **rem2ps(1)**. If you include a **q** letter with this option,
then the usual calendar-mode substitution filter is disabled and the
%\"\...%\" sequences are preserved in the output.
Note that to pass INFO strings to a back-end, you must use **-pp**
or **-ppp**. The simpler **-p** format is not capable of
transmitting the INFO strings to the back-end.
The **-p**, **-pp** and **-ppp** options implicitly enable the
**-o** option.
Note that the **-pp** or **-ppp** options also enable the **-l**
option.
**-l**
: If you use the -l option in conjunction with the -p option, then
**Remind** outputs additional information for back-end programs such
as **rem2ps**. This additional information lets the back-end
programs correlate a reminder with the source file and line number
that produced it.
**-m**
: The **-m** option causes the **-c** or **-p** options to produce a
calendar whose first column is Monday rather than Sunday. (This
conforms to the international standard.)
**-v**
: The **-v** option makes the output of **Remind** slightly more
verbose. Currently, this causes **Remind** to echo a bad line in
case of an error, and to print a security message if a script tests
the \$RunOff system variable.
**-o**
: The **-o** option causes **Remind** to ignore all **ONCE**
directives. Note that **ONCE** is also ignored if any of the **-c**,
**-n**, **-p**, or **-s** options is used, if a repetition factor
**\*n** is used, or if a date other than today\'s date is specified
on the command-line.
**-t**
: The **-t** option causes **Remind** to trigger all non-expired
reminders, regardless of the *delta* supplied for each reminder.
**-tn**
: If you supply a number *n* after the **-t** option, then **Remind**
pretends that every **REM** command has a delta of ++*n*, regardless
of any existing delta.
**-tz**
: If you supply the letter **z** after the **-t** option, then
**Remind** sets all REM statements\' deltas to zero, regardless of
the value supplied in the REM statement itself. In effect, this
disables all deltas of the form **+**_n_ and **++**_n_.
**-tt\[*n*\]**
: The **-tt** option causes **Remind** to assume a default delta of
*n* minutes for all timed reminders. If **-tt** is given with no
*n*, a default delta of 5 minutes is used.
**-h**
: The **-h** option (\"hush\...\") suppresses certain warning and
information messages. In particular, if no reminders are triggered,
this mode produces no output.
**-a**
: The **-a** option causes **Remind** not to immediately trigger timed
reminders that trigger on the current day. It also causes **Remind**
not to place timed reminders in a calendar. If you supply two or
more **-a** options, then **Remind** *will* trigger timed reminders
that are in the future, but will not trigger timed reminders whose
time has passed. (Regardless of how many **-a** options you supply,
**Remind** will not include timed reminders in the calendar if at
least one **-a** option is used.)
```{=html}
<!-- -->
```
**-q**
: The **-q** option causes **Remind** not to queue timed reminders for
later execution.
**-f**
: The **-f** option causes **Remind** to remain in the foreground when
processing queued reminders, rather than forking off a background
process to handle them.
**-e**
: The **-e** option diverts error messages (normally sent to the
standard error stream) to the standard output stream.
**-d**_chars_
: The **-d** option enables certain debugging modes. The *chars*
specify which modes to enable:
**e**
: Echo all input lines
**x**
: Trace all expression evaluation
**t**
: Display all trigger date computation
**v**
: Dump the variable table after execution of the reminder script
**l**
: Echo lines when displaying error messages
**f**
: Trace the reading of reminder files
**s**
: Trace expression parsing and display the internal expression
node tree. This is unlikely to be useful unless you are working
on **Remind**\'s expression evaluation engine.
**h**
: Dump hash-table statistics on exit.
**u**
: When **Remind** exits, print a list of variables that were SET,
but not subsequently used.
Note that the **u** debugging flag may produce spurious
warnings. For example, this sequence of commands:
DEBUG +u
SET a 1
IFTRIG Wed
MSG a = [a]
ENDIF
will issue a warning about **a** being unused unless it is run
on a Wednesday.
**n**
: Print debugging information about why **Remind** considers an
expression to be \"non-constant\"
**q**
: Output a TRANSLATE command each time the **\_()** built-in
function is called or the **%(\...)** substitution sequence is
encountered.
**-g**\[**a\|d**\[**a\|d**\[**a\|d**\[**a\|d**\]\]\]\]
: Normally, reminders are issued in the order in which they are
encountered in the reminder script. The **-g** option cause
**Remind** to sort reminders by date and time prior to issuing them.
The optional **a** and **d** characters specify the sort order
(ascending or descending) for the date, time and priority fields.
See the section \"SORTING REMINDERS\" for more information.
Note that **-g** is *ignored* if you use the **-n** option.
**-b**\[*n*\]
: Set the time format for the calendar and simple-calendar outputs.
*N* can range from 0 to 2, with the default 0. A value of 0 causes
times to be inserted in 12-hour (am/pm) format. 1 causes times to be
inserted in 24-hour format, and 2 inhibits the automatic insertion
of times in the calendar output.
**-x**\[*n*\]
: Sets the iteration limit for the **SATISFY** clause of a **REM**
command. Defaults to 1000.
**-k**_cmd_
: Instead of simply printing **MSG**-type reminders, this causes them
to be passed to the specific *cmd*. You must use \'%s\' where you
want the body to appear, and may need to enclose this option in
quotes. Note that all shell characters in the body of the reminder
are escaped with a backslash, and the entire body of the reminder is
passed as a single argument. Note that this option **overrides** the
**-r** option and the **RUN OFF** command.
> As an example, suppose you have an X Window program called
> **xmessage** that pops up a window and displays its invocation
> arguments. You could use:
>
> remind '-kxmessage %s &' ...
>
> to have all of your **MSG**-type reminders processed using xmessage.
>
> A word of warning: It is very easy to spawn dozens of xmessage
> processes with the above technique. So be very careful. Because all
> shell and whitespace characters are escaped, the program you execute
> with the **-k** option must be prepared to handle the entire message
> as a single argument.
>
> If you follow the **-k** option with a colon, then the command is
> applied only to queued timed reminders. Normal reminders are handled
> as usual. In the above example, if you want normal reminders to simply
> be displayed as usual, but queued reminders to be sent to notify-send,
> you could use:
>
> remind '-k:notify-send %s &' ...
>
> You use both **-k**_cmd1_ and **-k:**_cmd2_ to use different commands
> for queued versus non-queued reminders.
**-z**\[*n*\] Runs **Remind** in \"daemon mode\". If *n*
: is supplied, it specifies how often (in minutes) **Remind** should
wake up to check if the reminder script has been changed. *N*
defaults to 1, and can range from 1 to 60. Note that the use of the
**-z** option also enables the **-f** option.
> If **Remind** is compiled on a system that supports **inotify**(7),
> then if the reminder script supplied on the command-line is actually a
> directory, **Remind** additionally checks if all files within that
> directory have been modified since startup.
>
> If you supply the option **-zj**, **Remind** runs in a special mode
> called **server mode**. This is documented in the tkremind man page;
> see tkremind(1). The older server mode option **-z0** still works, but
> is deprecated; it uses an ad-hoc method to communicate with the client
> rather than using JSON to communicate with the client.
**-u**_name_
: Runs **Remind** with the uid and gid of the user specified by
*name*. The option changes the uid and gid as described, and sets
the environment variables HOME, SHELL and USER to the home
directory, shell, and user name, respectively, of the specified
user. LOGNAME is also set to the specified user name. This option is
meant for use in shell scripts that mail reminders to all users.
Note that as of **Remind** 3.00.17, using **-u** implies **-r** \--
the RUN directive and shell() functions are disabled. However, if
you prefix *name* with a **+**-sign, then RUN and shell() are *not*
disabled. That is, **-uwhatever** switches the user to **whatever**
and disables RUN, whereas **-u+whatever** switches the user to
**whatever** but leaves RUN enabled.
> Non-root users can also use the **-u** option. However, in this case,
> it only changes the environment variables as described above. It does
> not change the effective uid or gid.
**-+**_username_
: Causes **Remind** to trust files owned by the user *username*.
Normally, if **Remind** reads a file that you do not own, it
disables RUN and the shell() function. This option causes it to also
trust files owned by *username*. You can supply multiple **-+**
options to trust multiple users, up to a limit of 20 trusted users.
**-y**
: Causes **Remind** to synthesize a tag for any reminder that lacks a
TAG clause.
**-i**_var=expr_
: Sets the value of the specified *var* to *expr*, and **preserves**
*var*. *Expr* can be any valid **Remind** expression. See the
section \"INITIALIZING VARIABLES ON THE COMMAND LINE\" for more
details. If you omit the **=**_expr_ part, then *var* is initialized
to 0. In other words, **-i**_var_ is exactly the same as
**-i**_var=0_.
**-i**_func(args)=definition_
: Allows you to define a function on the command line.
If you supply a *date* on the command line, it must consist of *day
month year*, where *day* is the day of the month, *month* is at least
the first three letters of the English name of the month, and *year* is
a year (all 4 digits) from 1990 to about 2075. You can leave out the
*day*, which then defaults to 1.
If you do supply a *date* on the command line, then **Remind** uses it,
rather than the actual system date, as its notion of \"today.\" This
lets you create calendars for future months, or test to see how your
reminders will be triggered in the future. Similarly, you can supply a
*time* to set **Remind**\'s notion of \"now\" to a particular time.
Supplying a *time* on the command line also implicitly enables the
**-q** option and disables the **-z** option. The *time* may be
specified in 24-hour format (e.g., 13:20) or common \"AM/PM\" format
(1:20pm).
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.
In addition, you can supply a *repeat* parameter, which has the form
\**rep*. This causes **Remind** to be run *rep* times, with the date
incrementing on each iteration. You may have to enclose the parameter in
quotes to avoid shell expansion. See the subsection \"Repeated
Execution\" in the section \"CALENDAR MODE\" for more information.
# LONG OPTIONS
**Remind** supports the following long options, which *are*
case-sensitive:
**\--version**
: The **\--version** option causes **Remind** to print its version
number to standard output and then exit.
**\--hide-completed-todos**
: In Calendar Mode, **Remind** normally shows all TODOs. If you supply
this option, the it will not show TODOs that have been marked as
completed.
**\--only-todos**
: Only issue TODO-type reminders.
**\--only-events**
: Do not issue TODO-type reminders.
**\--json**
: In Agenda Mode, output JSON instead of the normal text-mode output.
**\--json** also disables sorting (the **-g** option) and disables
queueing (the **-q** option). See the section \"AGENDA MODE JSON
OUTPUT\" for more details. The **\--json** option is ignored in
Calendar Mode. Note that in JSON mode, the output from any
**RUN**-type reminder that would normally appear on standard output
is redirected to standard error instead; this is so that
**RUN**-type reminders don\'t mess up the output and cause invalid
JSON to be produced on standard output.
**\--print-errs**
: The **\--print-errs** option causes **Remind** to print all possible
error messages to standard output and then exit. The messages are
printed in a format suitable for the first argument of a TRANSLATE
command. If you TRANSLATE the error messages, then **Remind** will
use the translated versions when outputting error and warning
messages. See also TRANSLATE GENERATE in the section \"THE
TRANSLATION TABLE\".
Note that if an untranslated message contains printf-style
formatting sequences like \"%s\" or \"%d\", then the translated
message *must* contain the same sequences in the same order, or
**Remind** will ignore it and use the original untranslated message.
**\--print-config-cmd**
: This option causes **Remind** to print the exact **./configure**
command that was used when **Remind** was built. You can use this to
build a new version of **Remind** using the same configuration as an
existing one by running:
eval `remind --print-config-cmd`
from the top-level **Remind** source directory. (However, it\'s
safer to simply run **remind \--print-config-cmd** and then type in
the command once you\'ve verified that it looks OK.)
```{=html}
<!-- -->
```
**\--print-tokens**
: The **\--print-tokens** option causes **Remind** to print the tokens
used by the parser, built-in function names, and system variable
names to standard output and then exit. This output is designed to
make it easy to create a syntax-highlighting file for various text
editors. The output can be modified by hand or by a script into a
syntax-highlighting file with relative ease.
**\--max-execution-time**=_n_
: Limit the total execution time (as measured by the wall clock) to
*n* seconds. This is useful if **Remind** is invoked on
potentially-untrustworthy files that could attempt to use a lot of
resources. Note that the limit *n* is approximate and **Remind**
might execute for one or two more seconds before it is killed. If
*n* is specified as zero, then no limit is applied, just as if the
option had not been used at all.
If a limit is applied, it applies only to the foreground run of
**Remind**. If **Remind** finishes processing the script and then
starts handling queued reminders, the time limit is reset to no
limit.
**\--max-expr-complexity**=_n_
: Limit the total complexity of expression valuation for a given line
in a script to *n* nodes. Roughly speaking, each function call,
operator, constant, variable reference, etc corresponds to one
expression node. By default, the limit is set to 10000000 (ten
million). You can explicitly set it to zero if you don\'t want any
limit to apply. The default limit of ten million should never be
triggered by any sensible Remind script, however, and we don\'t
recommend changing the limit.
**\--test**
: The **\--test** long option is only for use by the acceptance tests
run by \"make test\". Do not use this option in production.
**\--flush**
: The **\--flush** long option makes **Remind**\'s standard output and
standard error streams unbuffered. It is mostly used for testing and
should probably not be used in production.
# REMINDER FILES
**Remind** uses scripts to control its operation. You can use any text
editor capable of creating plain-text files to create a **Remind**
script. The commands inside a script can range from the very simple and
almost immediately understandable:
REM Mar 31 MSG International Transgender Day of Visibility
to the baroque and obscure:
REM [date(thisyear, 1, 1) + 180] ++5 OMIT \
sat sun BEFORE MSG [ord(thisyear-1980)] payment due %b!
A reminder file consists of commands, with one command per line. Several
lines can be continued using the backslash character, as in the above
example. In this case, all of the concatenated lines are treated as a
single line by **Remind**. Note that if an error occurs, **Remind**
reports the line number of the last line of a continued line.
**Remind** ignores blank lines, and lines beginning with the \'#\' or
\';\' characters. You can use the semicolon as a comment character if
you wish to pass a **Remind** script through the C pre-processor, which
interprets the \'#\' character as the start of a pre-processing
directive.
Note that **Remind** processes line continuations before anything else.
For example:
# This is a comment \
This line is part of the comment because of line continuation \
and so on.
REM MSG This line is not ignored (no \ above)
**Remind** is not case sensitive; you can generally use any mixture of
upper- or lower-case for commands, parameters, invocation options, etc.
# THE REM COMMAND
The most powerful command in a **Remind** script is the **REM** command.
This command is responsible for issuing reminders. Its syntax is:
> **REM** \[**ONCE**\] \[*date_spec*\] \[*back*\] \[*delta*\]
> \[*repeat*\] \[**TODO**\] \[**MAX-OVERDUE** *n*\]
> \[**COMPLETE-THROUGH** *complete_date*\] \[**PRIORITY** *prio*\]
> \[**SKIP** \| **BEFORE** \| **AFTER**\] \[**OMIT** *omit_list*\]
> \[**ADDOMIT**\] \[**NOQUEUE**\] \[**OMITFUNC** *omit_function*\]
> \[**AT** *time* \[*tdelta*\] \[*trepeat*\]\] \[**SCHED**
> *sched_function*\] \[**WARN** *warn_function*\] \[**UNTIL**
> *expiry_date* \| **THROUGH** *last_date*\] \[**SCANFROM** *scan_date*
> \| **FROM** *start_date*\] \[**DURATION** *duration*\] \[**TAG**
> *tag*\] \[**TZ** *timezone*\] \[**INFO** \"*info_string*\"\] **MSG**
> \| **MSF** \| **RUN** \| **CAL** \| **SATISFY** \| **SPECIAL**
> *special* \| **PS** \| **PSFILE** *body*
The parts of the **REM** command can be specified in any order, except
that the *body* must come immediately after the **MSG**, **RUN**,
**CAL**, **PS**, **PSFILE** or **SATISFY** keyword. The portion of the
**REM** command before the **MSG**, **MSF** **RUN**, **CAL** or
**SATISFY** clause is called a *trigger*.
In earlier versions of **Remind**, the **REM** token was optional
providing that the remainder of the command cannot be mistaken for
another **Remind** command. However, this use is deprecated and will now
cause a warning to be issued. All of your reminder lines should be
written to start with the REM command.
**MSG, MSF, RUN, CAL, SPECIAL, PS and PSFILE**
These keywords denote the *type* of the reminder. (**SATISFY** is more
complicated and will be explained later.) A **MSG**-type reminder
normally prints a message to the standard output, after passing the
*body* through a special substitution filter, described in the section
\"THE SUBSTITUTION FILTER.\" However, if you have used the **-k**
command-line option, then **MSG**-type reminders are passed to the
appropriate program. Note that the options **-c**, **-s**, **-p** and
**-n** disable the **-k** option.
Earlier versions of **Remind** let you omit the reminder type, in which
case it defaulted to **MSG**. However, this usage is deprecated and will
cause a warning. Something like:
REM 6 January Dianne's Birthday
will issue the warning \"Missing REM type; assuming MSG\"
The **MSF** keyword is almost the same as the **MSG** keyword, except
that the reminder is formatted to fit into a paragraph-like format.
Three system variables control the formatting of **MSF**-type
reminders - they are **\$FirstIndent**, **\$SubsIndent** and
**\$FormWidth**. They are discussed in the section \"SYSTEM VARIABLES.\"
The **MSF** keyword causes the spacing of your reminder to be altered -
extra spaces are discarded, and two spaces are placed after periods and
other characters, as specified by the system variables **\$EndSent** and
**\$EndSentIg**. Note that if the body of the reminder includes newline
characters (placed there with the %\_ sequence), then the newlines are
treated as the beginnings of new paragraphs, and the **\$FirstIndent**
indentation is used for the next line. You can use two consecutive
newlines to have spaced paragraphs emitted from a single reminder body.
A **RUN**-type reminder also passes the *body* through the substitution
filter, but then executes the result as a system command. A **CAL**-type
reminder is used only to place entries in the calendar produced when
**Remind** is run with the **-c**, **-s** or **-p** options. When
**Remind** runs a command, it sets the command\'s standard input to come
from /dev/null.
A **PS** or **PSFILE**-type reminder is used to pass PostScript code
directly to the printer when producing PostScript calendars. This can be
used to shade certain calendar entries (see the psshade() function),
include graphics in the calendar, or almost any other purpose you can
think of. You should not use these types of reminders unless you are an
expert PostScript programmer. The **PS** and **PSFILE** reminders are
ignored unless **Remind** is run with the **-p** option. See the section
\"More about PostScript\" for more details.
A **SPECIAL**-type reminder is used to pass \"out-of-band\" information
from **Remind** to a calendar-producing back-end. It should be followed
by a word indicating the type of special data being passed. The type of
a special reminder depends on the back-end. For the **Rem2PS** back-end,
**SPECIAL PostScript** is equivalent to a **PS**-type reminder, and
**SPECIAL PSFile** is equivalent to a **PSFILE**-type reminder. The body
of a **SPECIAL** reminder is obviously dependent upon the back-end. A
back-end *must* ignore a **SPECIAL** that it does not recognize.
**DATE SPECIFICATIONS**
A *date_spec* consists of zero to four parts. These parts are *day* (day
of month), *month* (month name), *year* and *weekday.* *Month* and
*weekday* are the English names of months and weekdays. At least the
first three characters must be used. The following are examples of the
various parts of a *date_spec:*
*day:*
: 1, 22, 31, 14, 3
*month:*
: JANUARY, feb, March, ApR, may, Aug
*year:*
: 1990, 1993, 2030. The year can range from 1990 to 2075.
*weekday:*
: Monday, tue, Wed, THU, Friday, saturday, sundAy
Note that there can be several *weekday* components separated by spaces
in a *date_spec.*
**INTERPRETATION OF DATE SPECIFICATIONS**
The following examples show how date specifications are interpreted.
1\. Null date specification - the reminder is triggered every day. The
trigger date for a specific run is simply the current system date. For
example:
REM MSG This is triggered every time Remind runs
2\. Only *day* present. The reminder is triggered on the specified day
of each month. The trigger date for a particular run is the closest such
day to the current system date. For example:
REM 1 MSG First of every month.
REM 31 MSG 31st of every month that has 31 days.
3\. Only *month* present. The reminder is triggered every day of the
specified month. Example:
REM Feb MSG Every day in February
4\. *day* and *month* present. Examples:
REM 6 Jan MSG Every 6th of January
REM Feb 29 MSG Every 29th of February
5\. Only *year* present. Example:
REM 1991 MSG Every day in 1991
6\. *year* and *day* present. Examples:
REM 1 1990 MSG 1st of every month in 1990
REM 1992 23 MSG 23rd of every month in 1992
7\. *year* and *month* present. Examples:
REM Feb 1991 MSG Every day in Feb 1991
REM 1992 September MSG Every day in Sept 1992
8\. *year, month* and *day* present. Examples:
REM 8 Jan 1991 MSG 8th January 1991.
REM 1992 March 9 MSG 9th March 1992.
9\. *weekday* only. Examples:
REM Sat MSG Every Saturday
REM Mon Tue Wed Thu Fri MSG Every working day
REM Monday Wednesday MSG Every Monday and Wednesday
10\. *weekday* and *day* present. Examples:
REM Sat 1 MSG First Saturday of every month
REM Mon Tue Wed Thu Fri 15 \
MSG 1st working day on or after 15th of every month
11\. *weekday* and *month* present. Examples:
REM Mon March MSG Every Monday in March
REM Mon Tue Wed Thu Fri Feb MSG Every working day in February
12\. *weekday, month* and *day* present. Examples:
REM Mon 1 March MSG First Monday in March
REM Sat Sun 15 July MSG First Sat or Sun on or after 15 July
13\. *weekday* and *year* present. Example:
REM Sat Sun 1991 MSG Every Saturday and Sunday in 1991
14\. *weekday, day* and *year* present. Examples:
REM Mon 15 1990 MSG 1st Mon after 15th of every month in 1990
REM Mon Tue Wed Thu Fri 1 1990 \
MSG 1st working day of every month in 1990
15\. *weekday, month* and *year* present. Example:
REM Mon Wed 1991 Feb MSG Every Mon and Wed in Feb 1991.
16\. *weekday, day, month* and *year* present. Example:
REM Mon Tue Wed Thu Fri 28 Oct 1990 \
MSG 1st working day on or after 28 October 1990.
Note that when both *weekday* and *day* are specified, **Remind**
chooses the first date on or after the specified *day* that also
satisfies the *weekday* constraint. It does this by picking the first
date on or after the specified *day* that is listed in the list of
*weekdays.* Thus, a reminder like:
REM Mon Tue 28 Oct 1990 MSG Hi
would be issued only on Monday, 29 October, 1990. It would not be issued
on Tuesday, 30 October, 1990, since the 29th is the first date to
satisfy the *weekday* constraints.
**SHORT-HAND DATE SPECIFICATIONS**
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:
REM 5 June 2010 MSG Cool!
REM 2010-06-05 MSG Cool!
You can also specify a date and time as YYYY-MM-DD@HH:MM. These
statements are equivalent:
REM 19 Dec 2010 AT 16:45 MSG Hi
REM 2010-12-19@16:45 MSG Hi
There\'s one subtlety with short-hand date specifications: The following
statements are *not* equivalent:
REM 19 Dec 2010 AT 16:45 +60 MSG Hi
REM 2010-12-19@16:45 +60 MSG Hi
In the second statement, the \"+60\" is a *delta* that applies to the
date rather than a *tdelta* that applies to the time. We recommend
explicitly using the AT keyword with timed reminders.
**THE REMIND ALGORITHM**
**Remind** uses the following algorithm to compute a trigger date:
Starting from the current date, it examines each day, one at a time,
until it finds a date that satisfies the date specification, or proves
to itself that no such date exists. (Actually, **Remind** merely
*behaves* as if it used this algorithm; it would be much too slow in
practice. Internally, **Remind** uses much faster techniques to
calculate a trigger date.) See DETAILS ABOUT TRIGGER COMPUTATION for
more information.
**BACKWARD SCANNING**
Sometimes, it is necessary to specify a date as being a set amount of
time before another date. For example, the last Monday in a given month
is computed as the first Monday in the next month, minus 7 days. The
*back* specification in the reminder is used in this case:
REM Mon 1 -7 MSG Last Monday of every month.
A *back* is specified with one or two dashes followed by an integer.
This causes **Remind** to move \"backwards\" from what would normally be
the trigger date. The difference between \--7 and -7 will be explained
when the **OMIT** keyword is described.
**ADVANCE WARNING**
For some reminders, it is appropriate to receive advance warning of the
event. For example, you may wish to be reminded of someone\'s birthday
several days in advance. The *delta* portion of the **REM** command
achieves this. It is specified as one or two \"+\" signs followed by a
number *n*. Again, the difference between the \"+\" and \"++\" forms
will be explained under the **OMIT** keyword. **Remind** will trigger
the reminder on computed trigger date, as well as on each of the *n*
days before the event. Here are some examples:
REM 6 Jan +5 MSG Remind me of birthday 5 days in advance.
The above example would be triggered every 6th of January, as well as
the 1st through 5th of January.
**PERIODIC REMINDERS**
We have already seen some built-in mechanisms for certain types of
periodic reminders. For example, an event occurring every Wednesday
could be specified as:
REM Wed MSG Event!
However, events that do not repeat daily, weekly, monthly or yearly
require another approach. The *repeat* component of the **REM** command
fills this need. To use it, you must completely specify a date (year,
month and day, and optionally weekday); this is the start date of the
repetition period. The *repeat* component is an asterisk followed by a
number specifying the repetition period in days.
For example, suppose you get paid every second Wednesday, and your last
payday was Wednesday, 28 October, 1992. You can use:
REM 28 Oct 1992 *14 MSG Payday
This issues the reminder every 14 days, starting from 28 Oct 1992. You
can use *delta* and *back* with *repeat.* Note, however, that the *back*
is used only to compute the starting date; thereafter, the reminder
repeats with the specified period. Similarly, if you specify a weekday,
it is used only to calculate the starting date, and does not affect the
repetition period.
**SCANFROM and FROM**
The **SCANFROM** and **FROM** keywords are for advanced **Remind**
programmers only, and will be explained in the section \"DETAILS ABOUT
TRIGGER COMPUTATION\" near the end of this manual. Note that
**SCANFROM** is available only in versions of **Remind** from 03.00.04
up. **FROM** is available only from 03.01.00 and later.
**PRIORITY**
The **PRIORITY** keyword must be followed by a number from 0 to 9999. It
is used in calendar mode and when sorting reminders. If two reminders
have the same trigger date and time, then they are sorted by priority.
If the **PRIORITY** keyword is not supplied, a default priority of 5000
is used. (This default can be changed by adjusting the system variable
**\$DefaultPrio**. See the section \"SYSTEM VARIABLES\" for more
information.)
**EXPIRY DATES**
Some reminders should be issued periodically for a certain time, but
then expire. For example, suppose you have a class every Friday, and
that your last class is on 11 December 1992. You can use:
REM Fri UNTIL 11 Dec 1992 MSG Class today.
Another example: Suppose you have jury duty from 30 November 1992 until
4 December 1992. The following reminder will issue the message every day
of your jury duty, as well as 2 days ahead of time:
REM 1992-11-30 *1 +2 UNTIL 1992-12-04 MSG Jury duty
Note that the *repeat* of \*1 is necessary; without it, the reminder
would be issued only on 30 November (and the two days preceding.)
As a special case, you can use the **THROUGH** keyword instead of \*1
and **UNTIL**. The following two **REM** commands are equivalent:
REM 1992-11-30 *1 +2 UNTIL 1992-12-04 MSG Jury duty
REM 1992-11-30 +2 THROUGH 1992-12-04 MSG Jury duty
If you have an expiry date via the use of **THROUGH** or **UNTIL**, then
**Remind** will *never* trigger the reminder after the expiry date. For
example, if you have this:
OMIT 2021-01-08
REM 2021-01-01 THROUGH 2021-01-08 AFTER MSG Test
the reminder will not be triggered on 2021-01-08, and nor will it be
triggered on 2021-01-09; even though the AFTER keyword would normally
move the 8th\'s reminder to the 9th, the expiry date of 2021-01-08
overrides that.
**THE ONCE KEYWORD**
Sometimes, it is necessary to ensure that reminders are run only once on
a given day. For example, compare the following two reminders:
REM Fri RUN do_backup
REM Fri ONCE RUN do_backup
The first will be run every time you invoke **Remind** on a Friday,
whereas the second will be run only the first time you invoke **Remind**
on a given Friday.
If you run **Remind** from your .login script, for example, and log in
several times per day, the *do_backup* program in the first reminder
will be run each time you log in. If, however, you use the **ONCE**
keyword in the reminder, the **Remind** checks the last access date of
the reminder script. If it is the same as the current date, **Remind**
assumes that it has already been run, and will not issue reminders
containing the **ONCE** keyword.
Note that if you view or edit your reminder script, the last access date
will be updated, and the **ONCE** keyword will not operate properly. You
can fix this by setting a timestamp file for **Remind** to track the
last-run date; see the documentation of **\$OnceFile** in the **SYSTEM
VARIABLES** section. If you use standard input as your **Remind** input
file, then you *must* use **\$OnceFile** for the **ONCE** keyword to
work properly.
If you start **Remind** with the **-o** option, then the **ONCE**
keyword will be ignored and any **\$OnceFile** will be ignored.
**LOCALLY OMITTING WEEKDAYS**
The **OMIT** portion of the **REM** command is used to \"omit\" certain
days when counting the *delta* or *back*. It is specified using the
keyword **OMIT** followed by a list of weekdays. Its action is best
illustrated with examples:
REM 1 +1 OMIT Sat Sun MSG Important Event
This reminder is normally triggered on the first of every month, as well
as the day preceding it. However, if the first of the month falls on a
Sunday or Monday, then the reminder is triggered starting from the
previous Friday. This is because the *delta* of +1 does not count
Saturday or Sunday when it counts backwards from the trigger date to
determine how much advance warning to give.
Contrast this with the use of \"++1\" in the above command. In this
case, the reminder is triggered on the first of each month, as well as
the day preceding it. The omitted days are counted.
REM 1 -1 OMIT Sat Sun MSG Last working day of month
Again, in the above example, the *back* of -1 normally causes the
trigger date to be the last day of the month. However, because of the
**OMIT** clause, if the first of the month falls on a Sunday or Monday,
the trigger date is moved backwards past the weekend to Friday. (If you
have globally omitted holidays, the reminder will be moved back past
them, 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 **OMIT**.
If you locally omit weekdays but also have globally-omitted weekdays,
then the list of omitted weekdays is the union of the two. Consider this
example:
OMIT Sat Sun
REM 15 OMIT Fri Sat MSG Whatever
In the REM command, the effective list of omitted weekdays will be
Friday, Saturday and Sunday.
**COMPUTED LOCAL OMITS**
The **OMITFUNC** phrase of the **REM** command allows you to supply a
function that determines whether or not a date is omitted. Note that
**OMITFUNC** must be given just the name of a user-defined function; it
can\'t take an arbitrary expression or the name of a built-in function.
The function is passed a single parameter of type **DATE**, and must
return a non-zero integer if the date is considered \"omitted\" and 0
otherwise. Here\'s an example:
FSET _third(x) (day(x) % 3) || \
(wkdaynum(x) == 0) || \
(wkdaynum(x) == 6)
REM OMITFUNC _third AFTER MSG Working day divisible by 3
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:
**o**
: The **OMITFUNC \_third** portion causes all days for which
**\_third(x)** returns non-zero to be considered \"omitted\". This
causes all days whose day-of-month number is *not* a multiple of
three to be omitted. Note that \_third also returns non-zero if the
weekday is Sunday or Saturday.
**o**
: The **AFTER** keyword causes the reminder to be moved after a block
of omitted days.
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.
Note that if you use **OMITFUNC**, then a local **OMIT** is *ignored* as
are *all global OMITs*. 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 **OMIT** context, then your omit function will
need to test for that explicitly (using the **isomitted()** function.)
Note that an incorrect **OMITFUNC** might cause all days to be
considered omitted. For that reason, when **Remind** searches through
omitted days, it terminates the search after the **SATISFY** iteration
limit (command-line option **-x**.)
**ADDING TRIGGER DATES TO THE OMIT CONTEXT**
If the **ADDOMIT** keyword appears in a **REM** command, then the
trigger date (if one could be calculated) is automatically added to the
list of global OMITs.
The command:
REM ... whatever ... ADDOMIT MSG Foo
is identical in behavior to the sequence:
REM ... whatever ... SATISFY 1
IF trigvalid()
OMIT [trigdate()] MSG Foo
ENDIF
**TIMED REMINDERS**
Timed reminders are those that have an **AT** keyword followed by a
*time* and optional *tdelta* and *trepeat*. The *time* may be specified
in 24-hour format, with 0:00 representing midnight, 12:00 representing
noon, and 23:59 representing one minute to midnight. Alternatively, it
may be specified in common \"AM/PM\" format; in this case, the hour must
range from 1 to 12. 12:00am represents midnight, 12:00pm represents
noon, and 11:59pm represents one minute to midnight. The \"am\" and
\"pm\" portions are case-insensitive and the \"m\" is optional.
You can use either a colon or a period to separate the hours from the
minutes. That is, 13:39 and 13.39 are equivalent.
**Remind** treats timed reminders specially. If the trigger date for a
timed reminder is the same as the current system date, the reminder is
queued for later activation. When **Remind** has finished processing the
reminder file, it puts itself in the background, and activates timed
reminders when the system time reached the specified time. Note that if
you use the **NOQUEUE** modifier in the **REM** command, then this
queuing and background activation is *not* performed. **NOQUEUE** is
useful if you want a time to be associated with a reminder (e.g., in the
calendar) but are not interested in a popup reminder happening at the
specified time.
If the trigger date is *not* the same as the system date, the reminder
is not queued.
For example, the following reminder, triggered every working day, will
emit a message telling you to leave at 5:00pm:
REM Mon Tue Wed Thu Fri AT 17:00 MSG Time to leave!
The following reminder will be triggered on Thursdays and Fridays, but
will only be queued on Fridays:
REM Fri ++1 AT 1:00PM MSG Lunch at 1pm Friday.
The *tdelta* and *trepeat* have the same form as a *repeat* and *delta*,
but are specified in minutes. For example, this reminder will be
triggered at 12:00pm as well as 45 minutes before:
REM AT 12:00 +45 MSG Example
The following will be issued starting at 10:45, every half hour until
11:45, and again at noon.
REM AT 12:00 +75 *30 MSG Example2
The \"+75\" means that the reminder is issued starting 75 minutes before
noon; in other words, at 10:45. The \*30 specifies that the reminder is
subsequently to be issued every 30 minutes. Note that the reminder is
always issued at the specified time, even if the *tdelta* is not a
multiple of the *trepeat*. So the above example is issued at 10:45am,
11:15am, 11:45am, and 12:00pm. Note that in the time specification,
there is no distinction between the \"+\" and \"++\" forms of *tdelta*.
Normally, **Remind** will issue timed reminders as it processes the
reminder script, as well as queuing them for later. If you do not want
**Remind** to issue the reminders when processing the script, but only
to queue them for later, use the **-a** command-line option. If you do
not want reminders to be queued for later, use the **-q** command-line
option.
Normally, **Remind** forks a background process to handle queued
reminders. If you want **Remind** to remain in the foreground, use the
**-f** command-line option. This is useful, for example, in .xinitrc
scripts, where you can use the command:
remind -fa myreminders &
This ensures that when you exit X-Windows, the **Remind** process is
killed.
**WARNING ABOUT TIMED REMINDERS**
Note: If you use user-defined functions or variables (described later)
in the bodies of timed reminders, then when the timed reminders are
activated, the variables and functions have the definitions that were in
effect at the end of the reminder script. These definitions may *not*
necessarily be those that were in effect at the time the reminder was
queued. In addition, the OMIT context is whatever was in effect at the
end of the reminder script, which may not necessarily be the same as
when the **REM** command was first processed.
**THE SCHED AND WARN KEYWORDS**
The **SCHED** keyword allows more precise control over the triggering of
timed reminders, and the **WARN** keyword allows precise control over
the advance triggering of all types of reminders. However, discussion
must be deferred until after expressions and user-defined functions are
explained. See the subsection \"PRECISE SCHEDULING\" further on.
**TAG, INFO AND DURATION**
The **TAG** keyword lets you \"tag\" certain reminders. This facility is
used by certain back-ends or systems built around **Remind**, such as
**TkRemind**. These back-ends have specific rules about tags; see their
documentation for details.
The **TAG** keyword is followed by a tag consisting of up to 48
characters. You can have as many TAG clauses as you like in a given REM
statement. A tag can contain any character except for whitespace and a
comma.
If you supply the **-y** option to **Remind**, then any reminder that
lacks a **TAG** will have one synthesized. The synthesized tag consists
of the characters \"\_\_syn\_\_\" followed by the hexadecimal
representation of the MD5 sum of the REM command line. This lets you
give a more-or-less unique identifier to each distinct REM command.
The **INFO** keyword is similar to **TAG** but is intended to convey
metadata about an event, such as its location. Back-ends will have their
own rules about which *info_string*s they recognize, and must ignore
*info_string*s they don\'t recognize. Note that **INFO** must be
followed by a quoted string; you can include newlines in the string by
supplying them as \"\\n\".
An INFO string *must* be of the form \"Header: Value\". The header can
consist of any printable character, but cannot contain whitespace. The
value can consist of any characters you like. Space may not appear
before the colon, but can appear afterwards; such space is not
considered to be part of the value. If there is more than one INFO
string for a given reminder, there cannot be any duplicate headers. Case
is ignored when determining if a header is a duplicate of an existing
one.
For example, a hypothetical back-end might let you set the location and
description of a reminder like this:
REM 26 Feb 2025 INFO "Location: Boardroom #2" \
INFO "Description: Go over latest pull requests" \
MSG Engineering meeting
While back-ends can choose which INFO strings to support, all back-ends
should endeavor to support three standard ones: **Location:**,
**Description:** and **Url:**. TkRemind supports all three of these,
turning reminders with a **Url:** INFO string into hyper-links, and
popping up information windows for the **Location:** and
**Description:** INFO strings. **Location:** and **Url:** are
self-explanatory; **Description:** is meant for a longer, more in-depth
description of the reminder than the summary that is normally displayed.
The **DURATION** keyword makes sense only for timed reminders; it
specifies the duration of an event. For example, if you have a 90-minute
meeting starting at 1:00pm, you could use any of the following:
REM 5 March 2021 AT 13:00 DURATION 1:30 MSG Meeting
REM 5 March 2021 AT 13:00 DURATION 90 MSG Meeting
REM 5 March 2021 AT 1:00pm DURATION 1:30 MSG Meeting
REM 5 March 2021 AT 1:00pm DURATION 90 MSG Meeting
For long-duration reminders, it is convenient to use expressions to
simplify writing the DURATION. For example, if you are away from 20 Feb
2023 through 23 Feb 2023 (a total of 4 days) you could write:
REM 20 Feb AT 00:00 DURATION [4*24]:00 MSG away
REM 20 Feb AT 00:00 DURATION [4*24*60] MSG away
Note that *duration* is specified either as *hours*:*minutes* or just as
*minutes* specified as an *integer*.
If you specify a duration of 00:00 or 0, then **Remind** behaves exactly
as if no **DURATION** at all had been present. Although durations
specified as *hours*:*minutes* look superficially like a time-of-day,
they are not; the *hours* component is not limited to the range 00-23.
# SYNTACTIC SUGAR FOR REM
The REM command has syntactic sugar to let you express common reminders.
The following pairs of reminders are equivalent:
REM First Monday April MSG Foo
REM Mon 1 April MSG Foo
REM Second Monday May MSG Bar
REM Mon 8 May MSG Bar
REM Third Monday MSG Third Monday of every month
REM Mon 15 MSG Third Monday of every month
REM Fourth Sunday June 2025 MSG Fourth Sunday in June 2025
REM Sun 22 June 2025 MSG Fourth Sunday in June 2025
REM Last Monday MSG Last Monday of every month
REM Mon 1 --7 MSG Last Monday of every month
REM Last Monday April MSG Last Monday of every April
REM Mon 1 May --7 MSG Last Monday of every April
REM Last Monday December 2025 MSG Last Monday of Dec 2025
REM Monday 1 Jan 2026 --7 MSG Last Monday of Dec 2025
Note that **Last** effectively adjusts the month and year, if necessary,
to make the reminder trigger on the correct date.
The keyword **IN** is completely ignored, so you can write (for
example):
REM Second Monday in May MSG foo
REM Last Monday in December 2025 MSG Bar
An alternate form of *back* makes writing reminders easier. The
following groups of reminders are equivalent:
REM ~~1 MSG Last day of every month
REM Lastday MSG Last day of every month
REM 1 --1 MSG Last day of every month
REM May ~~1 MSG Last day of May
REM Lastday May MSG Last day of May
REM 1 June --1 MSG Last day of May
REM Dec 2025 ~~1 MSG Last day of December 2025
REM Lastday Dec 2025 MSG Last day of December 2025
REM 1 Jan 2026 --1 MSG Last day of December 2025
REM Apr ~1 OMIT SAT SUN MSG Last workday of April
REM Lastworkday April OMIT SAT SUN MSG Last workday of April
REM 1 May -1 OMIT SAT SUN MSG Last workday of April
REM Apr ~~7 MSG Seventh-last day of April
REM 1 May --7 MSG Seventh-last day of April
REM Apr ~2 OMIT SAT SUN MSG Second-last workday of April
REM 1 May -2 OMIT SAT SUN MSG Second-last workday of April
As we see, \"Lastday\" is equivalent to \~\~1 and \"Lastworkday\" to
\~1.
Note that the First/Second/Third/Fourth/Last keywords and the \~ and
\~\~ form of *back* imply a value for the day of the month; as such,
they cannot be combined with a day. Additionally,
First/Second/Third/Fourth/Last must have at least one weekday name. The
following are illegal:
REM First Monday 3 June MSG Huh?
REM April 3 ~~1 MSG What?
REM Second June MSG Where's the weekday???
# THE SUBSTITUTION FILTER
Before being processed, the body of a **REM** command is passed through
a substitution filter. The filter scans for sequences \"%x\" (where
\"x\" is any letter and certain other characters) and performs
substitutions as shown below. (All dates refer to the trigger date of
the reminder.)
**%a**
: is replaced with \"on *weekday, day month, year*\"
For example, consider the reminder:
REM 18 Oct 1990 +4 MSG Meeting with Bob %a.
On 16 October 1990, it would print \"Meeting with Bob on Thursday,
18 October, 1990.\"
On 17 October 1990, it would print \"Meeting with Bob tomorrow.\"
On 18 October 1990, it would print \"Meeting with Bob today.\"
**%b**
: is replaced with \"in *diff* day\'s time\" where *diff* is the
**actual** number of days between the current date and the trigger
date. (**OMITs** have no effect.)
For example, consider:
REM 18 Oct 1990 +4 MSG Meeting with Bob %b.
On 16 October 1990, it would print \"Meeting with Bob in 2 days\'
time.\"
On 17 October 1990, it would print \"Meeting with Bob tomorrow.\"
On 18 October 1990, it would print \"Meeting with Bob today.\"
**%c**
: is replaced with \"on *weekday*\"
Example: REM 18 Oct 1990 +4 MSG Meeting with Bob %c.
On 16 October 1990, it would print \"Meeting with Bob on Thursday.\"
On 17 October 1990, it would print \"Meeting with Bob tomorrow.\"
On 18 October 1990, it would print \"Meeting with Bob today.\"
**%d**
: is replaced with \"*day*\", the day of the month.
**%e**
: is replaced with \"on *dd-mm-yyyy*\"
**%f**
: is replaced with \"on *mm-dd-yyyy*\"
**%g**
: is replaced with \"on *weekday, day month*\"
**%h**
: is replaced with \"on *dd-mm*\"
**%i**
: is replaced with \"on *mm-dd*\"
**%j**
: is replaced with \"on *weekday, month day-th, year*\" This form
appends the characters \"st\", \"nd\", \"rd\" or \"th\" to the day
of the month, as appropriate.
**%k**
: is replaced with \"on *weekday, month day-th*\"
**%l**
: is replaced with \"on *yyyy-mm-dd*\"
**%m**
: is replaced with \"*month*\", the name of the month.
**%n**
: is replaced with the number (1 to 12) of the month.
**%o**
: is replaced with \" (today)\" if and only if the current system date
is the same as the date being used by **Remind** as the current
date. Recall that you can specify a date for **Remind** to use on
the command line. This substitution is not generally useful in a
**REM** command, but is useful in a **BANNER** command. (See \"The
BANNER Command.\")
**%p**
: is replaced with \"s\" if the *diff* between the current date and
the trigger date is not 1. You can use this to construct reminders
like:
REM 1 Jan +4 MSG %x day%p to go before New Year!
**%q**
: is replaced with \"\'s\" if the *diff* between the trigger date and
the current date is 1. Otherwise, it is replaced with \"s\'\" This
can be used as follows:
REM 1 Jan +4 MSG New Year in %x day%q time!
**%r**
: is replaced with the day of the month (01 to 31) padded with a
leading zero if needed to pad to two digits.
**%s**
: is replaced with \"st\", \"nd\", \"rd\" or \"th\" depending on the
day of the month.
**%t**
: is replaced with the number of the month (01 to 12) padded to two
digits with a leading zero.
**%u**
: is replaced with \"on *weekday, day-th month, year*\" This is
similar to **%a** except that \"st\", \"nd\", \"rd\" or \"th\" is
added to the *day* as appropriate.
**%v**
: is replaced with \"on *weekday, day-th month*\"
**%w**
: is replaced with \"*weekday*\", the name of the day of the week.
**%x**
: is replaced with the *diff* between the current date and the trigger
date. The *diff* is defined as the actual number of days between
these two dates; **OMITs** are not counted. (Strict date subtraction
is performed.)
**%y**
: is replaced with \"*year*\", the year of the trigger date.
**%z**
: is replaced with \"*yy*\", the last two digits of the year.
**%(**_any_text_**)**
: is replaced with the lookup of *any_text* in the translation table.
It is the equivalent of \[\_(\"any_text\")\] but is more convenient
to type.
**%\<**_any_text_**\>**
: is replaced with the INFO value associated with the header
*any_text* or the empty string if no such INFO value exists. It is
the equivalent of \[triginfo(\"any_text\")\] but is more convenient
to type.
**%\_**
: (percent-underscore) is replaced with a newline. You can use this to
achieve multi-line reminders. Note that calendar back-ends vary in
how they handle multi-line reminders:
**o**
: Running **remind -c** preserves newlines in the terminal
calendar output.
**o**
: **rem2pdf** preserves newlines if **remind** is invoked with the
**-pp** or **-ppp** option.
**o**
: **rem2html** preserves newlines if **remind** is invoked with
the **-pp** option.
**o**
: **tkremind** preserves newlines.
**o**
: **rem2ps** converts newlines to spaces. But **rem2ps** is
deprecated; use **rem2pdf** instead.
**o**
: The \"simple calendar\" formats (i.e., **remind**\'s **-s**,
**-n** and **-p** options) convert newlines to spaces.
All calendar back-ends collapse multiple spaces to a single space
and multiple newlines to a single newline.
**%1**
: is replaced with \"now\", \"*m* minutes from now\", \"*m* minutes
ago\", \"*h* hours from now\", \"*h* hours ago\", \"*h* hours and
*m* minutes from now\" or \"*h* hours and *m* minutes ago\", as
appropriate for a timed reminder. Note that unless you specify the
**-a** option, timed reminders will be triggered like normal
reminders, and thus a timed reminder that occurred earlier in the
day may be triggered. This causes the need for the \"\...ago\"
forms.
**%2**
: is replaced with \"at *hh*:*mm*am\" or \"..pm\" depending on the
**AT** time of the reminder.
**%3**
: is replaced with \"at *hh*:*mm*\" in 24-hour format.
**%4**
: is replaced with \"*mm*\" where *mm* is the number of minutes
between \"now\" and the time specified by **AT**. If the **AT** time
is earlier than the current time, then the result is negative.
**%5**
: is replaced with \"*ma*\" where *ma* is the absolute value of the
number produced by **%4**.
**%6**
: is replaced with \"ago\" or \"from now\", depending on the
relationship between the **AT** time and the current time.
**%7**
: is replaced with the number of hours between the **AT** time and the
current time. It is always non-negative.
**%8**
: is replaced with the number of minutes between the **AT** time and
the current time, after the hours (**%7**) have been subtracted out.
This is a number ranging from 0 to 59.
**%9**
: is replaced with \"s\" if the value produced by **%8** is not 1.
**%0**
: is replaced with \"s\" if the value produced by **%7** is not 1.
**%!**
: is replaced with \"is\" if the current date and time is before the
trigger date and the **AT** time, or \"was\" if it is after. The
**%!** sequence may be used in a non-timed reminder, in which case
only dates are compared.
**%?**
: is replaced with \"are\" if the current date and time is before the
trigger date and the **AT** time, or \"were\" if it is after. The
**%?** sequence may be used in a non-timed reminder, in which case
only dates are compared.
**%@**
: is similar to **%2** but displays the current time.
**%#**
: is similar to **%3** but displays the current time.
**%:**
: is replaced with \" (done)\" for a TODO reminder whose trigger date
is on or after its COMPLETE-THROUGH date. It is replaced with the
empty string in any other situation. Note that because **Remind**
does not display completed TODO reminders in Agenda Mode, this
escape sequence is really only useful in Calendar Mode.
**%\"**
: (percent-doublequote) is removed. This sequence is not used by the
substitution filter, but is used to tell **Remind** which text to
include in a calendar entry when the **-c**, **-s** or **-p** option
is chosen. See \"CALENDAR MODE\"
Notes:
o
: **Remind** normally prints a blank line after each reminder; if the
last character of the body is \"%\", the blank line will not be
printed. You can globally suppress the extra blank lines by setting
**\$AddBlankLines** to 0.
o
: Substitutions a, b, c, e, f, g, h, i, j, k, l, u and v all are
replaced with \"today\" if the current date equals the trigger date,
or \"tomorrow\" if the trigger date is one day after the current
date. Thus, they are **not** the same as substitutions built up from
the simpler %w, %y, etc. sequences.
o
: The a, c, e, f, g, h, i, j, k, l, u, v, 2, and 3 substitutions may
be preceded by an asterisk (for example, **%\*c**) which causes the
word \"at\" or \"on\" that would normally be included in the output
to be omitted.
o
: The ! and ? substitutions may be preceded by an asterisk (**%\*!**
or **%\*?**), in which case the comparison is made between the
trigger date and realtoday() instead of today().
o
: Any of the substitutions dealing with time (0 through 9) produce
undefined results if used in a reminder that does not have an **AT**
keyword. Also, if a reminder has a *delta* and may be triggered on
several days, the time substitutions ignore the date. Thus, the
**%1** substitution may report that a meeting is in 15 minutes, for
example, even though it may only be in 2 days time, because a
*delta* has triggered the reminder. It is recommended that you use
the time substitutions only in timed reminders with no *delta* that
are designed to be queued for timed activation.
o
: Capital letters can be used in the substitution sequence, in which
case the first character of the substituted string is capitalized
(if it is normally a lower-case letter.)
o
: All other characters following a \"%\" sign are simply copied. In
particular, to get a \"%\" sign out, use \"%%\" in the body. To
start the body of a reminder with a space, use \"% \", since
**Remind** normally scans for the first non-space character after a
**MSG,** **CAL** or **RUN** token.
# EVENTS AND TODOS
The **REM** command is normally used to create an *EVENT*. This is
something that happens at a certain time, possibly recurring, and
happens no matter what action you take. Events include things like
birthdays, holidays, meetings, etc\... pretty much everything that
occurs on a particular schedule. Once the date of an event has passed,
**Remind** will no longer remind you about the event.
A *TODO* is different; it is a task that you have to complete by a
specific date or date and time. If you don\'t explicitly mark a TODO as
done, **Remind** will keep reminding you about it *even past* the due
date..
To mark a **REM** as a TODO, simply include the TODO keyword. For
example:
REM TODO 15 August 2025 ++5 MSG Buy cat food %b.
In Agenda Mode, **Remind** will start warning you on 10 Aug 2025 that
you have to but cat food in 5 days\' time, 4 days\' time, etc\...
However, on 16 Aug 2025, **Remind** will say \"Buy cat food yesterday.\"
and it will keep reminding you of your need to buy cat food until the
end of time, or until you mark the TODO as done.
# MARKING TODOS AS DONE
There are two ways to mark a TODO as done. If the TODO is not recurring,
the simplest way is simply to remove the TODO designator from the REM
command (or indeed, to completely delete it.) The former keeps the
reminder on the calendar while the latter completely removes it.
If a TODO is recurring, use the **COMPLETE-THROUGH** clause to mark
which recurrences have been completed. For example:
REM TODO 30 April ++15 COMPLETE-THROUGH 2025-04-30 MSG File taxes
Canadian income taxes must be filed every 30 April. The above command
will remind you to pay taxes in 2026. If you don\'t update the
COMPLETE-THROUGH date, then after 30 April 2026, **Remind** will keep
reminding you until the end of time that your taxes were due on 30 April
2026. To indicate that you\'ve paid them, simply update the
COMPLETE-THROUGH date to 2026-04-30 and then **Remind** will start
reminding you of your 2027 taxes (starting 15 days before the due date.)
It is an error to specify COMPLETE-THROUGH without also specifying TODO.
# LIMITING REMINDERS ABOUT OVERDUE TODOS
Although **Remind** is happy to keep reminding you about overdue TODOs
for hundreds of years, for some things this may be pointless. If you
want **Remind** to *stop* nagging you about an overdue TODO after a
certain number of days, use the MAX-OVERDUE *n* clause. In this case,
**Remind** stops reminding you of a TODO that is overdue by more than
*n* days. Here is an example.
REM TODO 2025-08-13 ++5 MAX-OVERDUE 5 MSG Task: %b.
**Remind** *starts* reminding you of the task on 2025-08-08, because of
the ++5 back value. It keeps reminding you of the task after the due
date. However, the last time it will remind you will be on 2025-08-18,
because of the MAX-OVERDUE clause. Starting on 2025-08-19, **Remind**
will no longer remind you of the task since it\'s probably
pointless\-\--it has passed the MAX-OVERDUE period.
# MORE DETAILS ABOUT TODOS
TODOs are treated specially only in Agenda Mode. In Calendar Mode, they
appear in the calendar exactly as a normal event would.
TODOs are implemented internally by using the COMPLETE-THROUGH date plus
one day as the starting point for **Remind**\'s date-scanning algorithm.
If you have a recurring TODO without a COMPLETE-THROUGH clause, then
**Remind** starts scanning from the beginning of time, which we all know
is 1 January 1990. Consider this command:
REM TODO Wed +7 MSG Take out the trash %a (%b)
Running that command in Agenda Mode on 2025-08-13 yields the following
output:
Take out the trash on Wednesday, 3 January, 1990 (13006 days ago)
**Remind** is very persistent about reminding you of tasks! If you take
out the trash and mark it done:
REM TODO Wed +7 COMPLETE-THROUGH 2025-08-13 MSG Take out the trash %a (%b)
then you get this:
Take out the trash on Wednesday, 20 August, 2025 (in 7 days' time)
You can use **FROM** and **UNTIL** to limit the recurrence interval of
tasks just as you can with events. For example, if you are house-sitting
for the month of August and need to water plants every Wednesday:
REM TODO Wed +7 FROM 2025-08-06 UNTIL 2025-08-27 MSG Plants %b.
Running that command on 13 Aug yields: \"Plants 7 days ago.\" because
you have not told **Remind** that you completed the first watering. If
you finish your duties and add a COMPLETE-THROUGH date of 2025-08-27,
then **Remind** never reminds you of that task in the future.
In Purge Mode, **Remind** will not purge TODOs unless they have been
marked as complete. In the case of a recurring TODO, **Remind** will not
purge it until the last occurrence is marked as complete.
# THE OMIT COMMAND
In addition to being a keyword in the **REM** command, **OMIT** is a
command in its own right. Its syntax is:
> **OMIT** *weekday* \[*weekday*\...\]
>
> or:
>
> **OMIT** \[*day*\] *month* \[*year*\]
>
> or:
>
> **OMIT** \[*day1*\] *month1* \[*year1*\] **THROUGH** \[*day2*\]
> *month2* \[*year2*\]
The **OMIT** command is used to \"globally\" omit certain days (usually
holidays). These globally-omitted days are skipped by the \"-\" and
\"+\" forms of *back* and *delta*, but not by the \"\--\" and \"++\"
forms. Some examples:
OMIT Saturday Sunday
OMIT 1 Jan
OMIT 7 Sep 1992
OMIT 15 Jan THROUGH 14 Feb
OMIT May # Equivalent to OMIT May 1 THROUGH May 31
OMIT 25 Dec THROUGH 4 Jan
OMIT 2023-05-03 THROUGH 2023-05-12
OMIT Jun THROUGH July # Equivalent to OMIT Jun 1 THROUGH July 31
The first example omits every Saturday and Sunday. This is useful for
reminders that shouldn\'t trigger on weekends.
The second example specifies a holiday that occurs on the same date each
year - New Year\'s Day.
The third example specifies a holiday that changes each year - Labour
Day. For these types of holidays, you must create an **OMIT** command
for each year. (Later, in the description of expressions and some of the
more advanced features of **Remind**, you will see how to automate this
for some cases.)
As with the REM command, you can use shorthand specifiers for dates; the
following are equivalent:
OMIT 7 Sep 1992
OMIT 1992-09-07
For convenience, you can use a *delta* and **MSG** or **RUN** keyword in
the **OMIT** command. The following sequences are equivalent:
OMIT 1 Jan
REM 1 Jan +4 MSG New year's day is %b!
and
OMIT 1 Jan +4 MSG New year's day is %b!
The **THROUGH** keyword lets you conveniently OMIT a range of days. For
example, the following sequences are equivalent:
OMIT 3 Jan 2011
OMIT 4 Jan 2011
OMIT 5 Jan 2011
and
OMIT 3 Jan 2011 THROUGH 5 Jan 2011
Note that **Remind** has a compiled-in limit to the number of full
OMITs. If you omit a range of *N* fully-specified (i.e., year included)
days, then *N* full OMITs are used up. Trying to omit a very large range
may result in the error \"Too many full OMITs\"
You can make a THROUGH **OMIT** do double-duty as a **REM** command as
long as both dates are fully specified
OMIT 6 Sep 2010 THROUGH 10 Sep 2010 MSG Vacation
If you use a THROUGH clause, then either the year must be supplied
before and after the THROUGH, or it must be missing before and after the
THROUGH. The following are legal:
OMIT 25 Dec THROUGH 6 Jan
OMIT 25 Dec 2024 THROUGH 6 Jan 2025
But the following are not:
OMIT 25 Dec THROUGH 6 Jan 2025
OMIT 25 Dec 2024 THROUGH 6 Jan
You can debug your global OMITs with the following command:
OMIT DUMP
The OMIT DUMP command prints the current global omits to standard
output.
**THE BEFORE, AFTER AND SKIP KEYWORDS**
Normally, days that are omitted, whether by a global **OMIT** command or
the local **OMIT** or **OMITFUNC** keywords in a **REM** statement, only
affect the counting of the -*back* or the +*delta*. For example, suppose
you have a meeting every Wednesday. Suppose, too, that you have
indicated 11 Nov as a holiday:
OMIT 11 Nov +4 MSG Remembrance Day
REM Wed +1 MSG Code meeting %b.
The above sequence will issue a reminder about a meeting for 11 November
1992, which is a Wednesday. This is probably incorrect. There are three
options:
**BEFORE**
: This keyword moves the reminder to before any omitted days. Thus, in
the above example, use of **BEFORE** would cause the meeting
reminder to be triggered on Tuesday, 10 November 1992.
**AFTER**
: This keyword moves the reminder to after any omitted days. In the
above example, the meeting reminder would be triggered on Thursday,
12 November 1992.
**SKIP**
: This keyword causes the reminder to be skipped completely on any
omitted days. Thus, in the above example, the reminder would not be
triggered on 11 November 1992. However, it would be triggered as
usual on the following Wednesday, 18 November 1992.
The **BEFORE** and **AFTER** keywords move the trigger date of a
reminder to before or after a block of omitted days, respectively.
Suppose you normally run a backup on the first day of the month.
However, if the first day of the month is a weekend or holiday, you run
the backup on the first working day following the weekend or holiday.
You could use:
REM 1 OMIT Sat Sun AFTER RUN do_backup
Let\'s examine how the trigger date is computed. The **1** specifies the
first day of the month. The local **OMIT** keyword causes the **AFTER**
keyword to move the reminder forward past weekends. Finally, the
**AFTER** keyword will keep moving the reminder forward until it has
passed any holidays specified with global **OMIT** commands.
# TIMEZONE SUPPORT
The **REM** command supports an optional **TZ** keyword, which should be
followed by the *case-sensitive* time zone name in which the command is
to be interpreted. Note that if you use the **TZ** keyword, then you
*must also* use an **AT** clause. Here are some examples:
REM Wednesday AT 14:00 TZ America/Toronto MSG 2PM Eastern (%2).
REM Wednesday AT 23:59 TZ America/Los_Angeles SATISFY [$Td == 13] MSG Foo %b %2.
Within a **SATISFY** clause and an **OMITFUNC** function, all trigger
functions and the trigger date are interpreted _in the time zone_
_specified in the_ **REM** _command_. Outside the **REM** command,
however, trigger functions are adjusted to the local time zone. If the
local time zone is UTC and we feed **Remind** the following file on
2025-09-04 UTC:
SET $AddBlankLines 0
BANNER %
REM Wednesday AT 14:00 TZ America/Toronto MSG 2PM Eastern (%2).
set a $T
set b $Tt
REM MSG a = [a], b = [b]
REM Wednesday AT 23:59 TZ America/Los_Angeles SATISFY [$Td == 13] MSG Foo %b %2.
set c $T
set d $Tt
REM MSG c = [c], d = [d]
Then the output is as follows:
a = 2025-09-10, b = 18:00
c = 2026-05-14, d = 06:59
That is because the trigger date of the first (Wednesday, 2025-09-10 at
14:00 Eastern time) is 2025-09-10 at 18:00 UTC. In the second case,
Wednesday, 13 May 2026 is the SATISFied trigger date, which is adjusted
to Thursday, 14 May 2026 at 06:59 UTC because of the time zone
adjustment.
If you use an invalid time zone name after the **TZ** keyword, results
are undefined. As mentioned previously, time zone names *are*
case-sensitive; America/Toronto is valid, but america/toronto is not.
If you are on a system that stores time zone data in
/usr/share/zoneinfo, then **Remind** will attempt to validate the time
zone name and will warn you if it appears to be invalid. If you want to
specify a time zone that lacks a file under /usr/share/zoneinfo anyway,
and want to suppress the warning, prefix the time zone name with \"!\".
For example:
REM Thursday AT 14:45 TZ !EST+5EDT,M3.2.0/2,M11.1.0/2 MSG Old TZ format
In a reminder with the **TZ** keyword, OMIT dates are evaluated in the
specified time zone. Here\'s an example: Suppose the local time zone is
America/Toronto and you have this script:
# A Friday
OMIT 2025-09-05
# A Saturday
OMIT 2025-09-13
REM Saturday AT 01:00 TZ Europe/Amsterdam SKIP MSG Early Sat AM
On 2025-09-05 in the America/Toronto time zone, the reminder *will*
trigger. Even though 2025-09-05 has been OMITted, the SKIP keyword
evaluates the date in the Europe/Amsterdam time zone, and 2025-09-06
(the trigger date) is *not* omitted.
Conversely, on 2025-09-12 in the America/Toronto time zone, the reminder
will *not* trigger. Even though 2025-09-12 is not OMITted, 2025-09-13
is, and that is the trigger date in the Europe/Amsterdam time zone.
# THE DO, INCLUDE AND SYSINCLUDE COMMANDS
**Remind** allows you to include other files in your reminder script,
similar to the C preprocessor #include directive. For example, you might
organize different reminders into different files like this:
INCLUDE holidays.rem
INCLUDE birthdays.rem
INCLUDE "quote files with spaces.rem"
**INCLUDE** files can be nested up to a depth of 8. As shown above, if a
filename has spaces in it (not recommended!) you can use double-quotes
around the filename.
If you specify a filename of \"-\" in the **INCLUDE** command,
**Remind** will begin reading from standard input.
If you specify a *directory* as the argument to **INCLUDE**, then
**Remind** will process all files (but not subdirectories!) in that
directory that match the shell pattern \"\*.rem\". The files are
processed in sorted order; the sort order matches that used by the shell
when it expands \"\*.rem\".
Note that the file specified by an **INCLUDE** command is interpreted
relative to the _current working directory of the_ **Remind** process.
If you want to include a file relative to the directory containing the
currently-processing file, use **DO** instead. For example, if the
current file is **/home/user/.reminders/foo.rem** and Remind\'s working
directory is **/home/user**, then:
# Read /home/user/.reminders/bar.rem
DO bar.rem
# Read /usr/share/bar.rem - absolute path
DO /usr/share/bar.rem
# Read /home/user/bar.rem
INCLUDE bar.rem
# Read /usr/share/bar.rem - absolute path
INCLUDE /usr/share/bar.rem
Arguably, the **INCLUDE** command should have worked the way **DO** does
right from the start, but changing it would have broken
backward-compatibility, hence the introduction of **DO**.
Note that if the currently-processing reminders file was specified as a
symbolic link to a file that is not in the same directory as the
symbolic link itself, **DO** will fail. **Remind** does *not* resolve
the real path of symbolic links, so you should avoid using symbolic
links to files.
The **SYSINCLUDE** command is similar to **DO**, but it looks for
relative pathnames under the system directory containing standard
reminder scripts. For this installation of **Remind**, the system
directory is \"/usr/local/share/remind\".
# THE RETURN COMMAND
The **RETURN** command causes **Remind** to ignore the remaining
contents of the file currently being processed. It can be used as a
quick way to \"exit\" from an included file (though it also works at the
top-level.)
Here is an example of how **RETURN** might be used:
IF already_done
RETURN
ENDIF
set already_done 1
preserve already_done
# Do expensive processing here
# THE RUN COMMAND
If you include other files in your reminder script, you may not always
entirely trust the contents of the other files. For example, they may
contain **RUN**-type reminders that could be used to access your files
or perform undesired actions. The **RUN** command can restrict this: If
you include the command **RUN OFF** in your top-level reminder script,
any reminder or expression that would normally execute a system command
is disabled. **RUN ON** will re-enable the execution of system commands.
Note that the **RUN ON** command can *only* be used in your top-level
reminder script; it will *not* work in any files accessed by the
**INCLUDE** command. This is to protect you from someone placing a **RUN
ON** command in an included file. However, the **RUN OFF** command can
be used at top level or in an included file.
If you run **Remind** with the **-r** command-line option, **RUN**-type
reminders and the **shell()** function will be disabled, regardless of
any **RUN** commands in the reminder script. However, any command
supplied with the **-k** option will still be executed.
In addition, **Remind** contains a few other security features. It will
not read a file that is group- or world-writable. It will not run
set-uid. If it reads a file you don\'t own, it will disable RUN and the
shell() function. And if it is run as *root*, it will only read files
owned by *root*.
Note that if **Remind** reads standard input, it does *not* attempt to
check the ownership of standard input, even if it is coming from a file,
and hence does *not* disable RUN and shell() in this situation.
# THE EXPR COMMAND
**Remind** lets you completely disable expression evaluation. This could
be useful if you are running **Remind** on a somewhat-untrustworthy file
that is not expected to contain expressions. To disable expression
evaluation, use:
EXPR OFF
If **Remind** encounters an expression while EXPR OFF is in effect, it
returns an error
To re-enable expression evaluation, use:
EXPR ON
As with **RUN ON, EXPR ON** can be used only in the top-level script,
not in an included file.
# THE INCLUDECMD COMMAND
**Remind** allows you to execute a shell command and evaluate the output
of that command as if it were an included file. For example, you could
have scripts that extract reminders out of a database and print them on
stdout as REM commands. Here is an example:
INCLUDECMD extract_reminders_for dfs
We assume that the command \"extract_reminders_for\" extracts reminders
out of a central database for the named user. Another use-case of
INCLUDECMD is if you have your reminders stored in a file in some
non-Remind format; you can write a command that transforms them to
**Remind** format and then **Remind** can \"include\" the file with an
appropriate INCLUDECMD command.
Note that if RUN is disabled, then INCLUDECMD will fail with the error
message \"RUN disabled\"
**Remind** arranges so that when the command specified by INCLUDECMD is
executed, its standard input is opened to /dev/null.
INCLUDECMD passes the rest of the line to **popen**(3), meaning that the
command is executed by the shell. As such, shell meta-characters may
need escaping or arguments quoting, depending on what you\'re trying to
do. **Remind** itself does not perform any modification of the command
line (apart from the normal \[expr\] expression-pasting mechanism).
If the command passed to INCLUDECMD begins with an exclamation mark
\"!\", then **Remind** disables **RUN** for the output of the command.
If you are running a command whose output you don\'t quite trust, you
should prefix it with \"!\" so that any RUN commands it emits fail.
An **INCLUDECMD** command counts towards the INCLUDE nesting depth. For
any given **Remind** run, a given INCLUDECMD command is only executed
once and the results are cached. For example, if you generate a
calendar, each unique INCLUDECMD command is run just once, not once for
each day of the produced calendar. \"Uniqueness\" is determined by
looking at the command that will be passed to the shell, so if (for
example) your INCLUDECMD uses expression-pasting that results in
differences depending on the value of **today()**, then each *unique*
version of the command will be executed once.
If a given reminder file contains more than one identical
**INCLUDECMD**, only the first one will actually be executed. All
subsequent identical ones will use the cached output from the first one.
# THE BANNER COMMAND
When **Remind** first issues a reminder, it prints a message like this:
Reminders for Friday, 30th October, 1992 (today):
(The banner is not printed if any of the calendar-producing options is
used, or if the **-k** option is used.)
The **BANNER** command lets you change the format. It should appear
before any **REM** commands. The format is:
> **BANNER** *format*
The *format* is similar to the *body* of a **REM** command. It is passed
through the substitution filter, with an implicit trigger of the current
system date. Thus, the default banner is equivalent to:
BANNER Reminders for %w, %d%s %m, %y%o:
You can disable the banner completely with BANNER %. Or you can create a
custom banner:
BANNER Hi - here are your reminders for %y-%t-%r:
# CONTROLLING THE OMIT CONTEXT
Sometimes, it is necessary to temporarily change the global **OMITs**
that are in force for a few reminders. Three commands allow you to do
this:
**PUSH-OMIT-CONTEXT**
: This command saves the current global **OMITs** on an internal
stack.
**CLEAR-OMIT-CONTEXT**
: This command clears all of the global **OMITs**, starting you off
with a \"clean slate.\"
**POP-OMIT-CONTEXT**
: This command restores the global **OMITs** that were saved by the
most recent **PUSH-OMIT-CONTEXT**.
For example, suppose you have a block of reminders that require a clear
**OMIT** context, and that they also introduce unwanted global **OMITs**
that could interfere with later reminders. You could use the following
fragment:
PUSH-OMIT-CONTEXT # Save the current context
CLEAR-OMIT-CONTEXT # Clean the slate
# Block of reminders goes here
POP-OMIT-CONTEXT # Restore the saved omit context
# EXPRESSIONS
In certain contexts, to be described later, **Remind** will accept
expressions for evaluation. **Remind** expressions resemble C
expressions, but operate on different types of objects.
**DATA TYPES**
**Remind** expressions operate on five types of objects:
**INT**
: The **INT** data type consists of the integers representable in one
machine word. The **INT** data type corresponds to the C \"int\"
type.
**STRING**
: The **STRING** data type consists of strings of characters. It is
somewhat comparable to a C character array, but more closely
resembles the string type in BASIC.
**Remind** normally expects to be running in a UTF-8 environment. In
this environment, there is a difference between *bytes* and
*characters* since in UTF-8, a character may be represented by a
sequence of more than one byte. For example, in a UTF-8 environment,
the string \"🙂\" contains one character but four bytes. And the
string \"één\" contains three characters but five bytes.
**Remind** has a set of functions that work on *bytes*, namely
**index**, **strlen** and **substr**. These are not safe to use on
multi-byte strings; instead use **mbindex**, **mbstrlen** and
**mbsubstr**. If you know *for sure* that a string contains only
single-byte characters, then the byte-oriented versions may be used
and are faster than the multi-byte versions.
Some ancient or embedded systems may lack the C library functions
needed to deal with multi-byte strings. In that case, the
**mb**_xxx_ functions all return an error.
**TIME**
: The **TIME** data type is used for two different purposes: To
represent a time of day with one-minute precision or to represent a
duration with one-minute precision. The context of where a **TIME**
is used determines whether it is interpreted as a time of day or a
duration.
In contexts where a **TIME** represents a time of day, it may range
from 00:00 to 23:59 and is stored internally as an integer from 0 to
1439 representing the number of minutes since midnight.
In contexts where a **TIME** represents a duration, there is no
upper limit on the hour component (beyond that imposed by the
restriction that a duration expressed in minutes must fit into the
signed integer type of your CPU architecture.) Internally, a
duration is stored as an integer number of minutes.
```{=html}
<!-- -->
```
**DATE**
: The **DATE** data type consists of dates (later than 1 January
1990.) Internally, **DATE** objects are stored as the number of days
since 1 January 1990.
**DATETIME**
: The **DATETIME** data type consists of a date and time together.
Internally, **DATETIME** objects are stored as the number of minutes
since midnight, 1 January 1990. You can think of a **DATETIME**
object as being the combination of **DATE** and **TIME** parts.
**CONSTANTS**
The following examples illustrate constants in **Remind** expressions:
**INT constants**
: 12, 36, -10, 0, 1209, 0x1F, 0xfe00 (the last two demonstrate the use
of hexadecimal constants)
**STRING constants**
: \"Hello there\", \"This is a test\", \"\\nHello\\tThere\", \"\"
> Note that the empty string is represented by \"\". **Remind** supports
> the escape sequences \"\\a\", \"\\b\", \"\\f\", \"\\n\", \"\\r\",
> \"\\t\" and \"\\v\" which have the same meanings as their counterparts
> in C. It also supports \"\\xAB\" where A and B are hexadecimal digits;
> this operates just as in C. The \"\\x\" must be followed by one or two
> hex digits; the escape sequence \"\\x00\" is not permitted.
>
> To include a quote in a string, use \"\\\"\". Any other character
> preceded by a backslash is inserted into the string as-is, but the
> backslash itself is removed. To include a backslash in a string, use
> \"\\\\\".
**TIME constants**
: 12:33, 0:01, 14:15, 16:42, 12.16, 13.00, 1.11, 4:30PM, 12:20am
> Note that **TIME** constants may be written in 24-hour format or in
> common \"AM/PM\" format. If you use \"AM/PM\" format, then the hour
> can range from 1 to 12. Either a period or colon can be used to
> separate the minutes from the hours. However, **Remind** will
> consistently output times in 24-hour format using only one separator
> character. (The output separator character is chosen at compile-time.)
>
> If the **TIME** is used where **Remind** expects a time-of-day (for
> example, in an **AT** clause), then it can be written in 24-hour
> format (ranging from 00:00 to 23:59) or 12-hour format (ranging from
> 12:00am to 11:59pm). If the **TIME** is used where **Remind** expects
> a duration, it must not have an *am* or *pm* suffix and the hour can
> be as large as you want, so long as the total number of minutes in the
> duration fits in a signed integer variable.
>
> For convenience, a **TIME** constant may be surrounded by single
> quotes to match **DATE** and **DATETIME** constants, but these quotes
> are optional. That is, 12:56 and \'12:56\' represent the same **TIME**
> constant.
**DATE constants**
: **DATE** constants are expressed as \'yyyy/mm/dd\' or
\'yyyy-mm-dd\', and the single quotes *must* be supplied. This
distinguishes date constants from division or subtraction of
integers. Examples:
> \'1993/02/22\', \'1992-12-25\', \'1999/01/01\'
>
> Note that **DATE** values are *printed* without the quotes. Although
> either \'-\' or \'/\' is accepted as a date separator on input, when
> dates are printed, only one will be used. The choice of whether to use
> \'-\' or \'/\' is made at compile-time. Note also that versions of
> **Remind** prior to 03.00.01 did not support date constants. In those
> versions, you must create dates using the **date()** function. Also,
> versions prior to 03.00.02 did not support the \'-\' date separator.
**DATETIME constants**
: **DATETIME** constants are expressed similarly to **DATE** constants
with the addition of an \"@HH:MM\" part, optionally followed by
\"am\" or \"pm\". For example:
> \'2008-04-05@23:11\', \'1999/02/03@14:06\', \'2001-04-07@08:30\',
> \'2020-01-01@3:20pm\'
>
> **DATETIME** values are printed without the quotes. Notes about date
> and time separator characters for **DATE** and **TIME** constants
> apply also to **DATETIME** constants.
**ZERO VALUES AND TRUE/FALSE**
All types have an associated *zero value*, which is treated as *false*
by the IF command, the IIF function, and the logical operators. The zero
values are:
> **INT** - 0
>
> **DATE** - \'1990-01-01\'
>
> **TIME** - 00:00
>
> **DATETIME** - \'1990-01-01@00:00\'
>
> **STRING** - \"\" (the empty string)
Any value other than the *zero value* is treated as *true*.
**OPERATORS**
**Remind** has the following operators. Operators on the same line have
equal precedence, while operators on lower lines have lower precedence
than those on higher lines. The operators approximately correspond to C
operators.
! - (unary logical negation and arithmetic negation)
* / % (multiplication, division, modulus)
+ - (addition/concatenation, subtraction)
< <= > >= (comparisons)
== != (equality and inequality tests)
&& (logical AND)
|| (logical OR)
**DESCRIPTION OF OPERATORS**
**!**
: Logical negation. Can be applied to any type. If the operand is
non-zero, returns 0. Otherwise, returns 1.
**-**
: Unary minus. Can be applied to an **INT**. Returns the negative of
the operand.
**\***
: Multiplication. Returns the product of two **INT**s. Alternatively,
if one argument is a **STRING** and the other an **INT**, returns a
**STRING** consisting of the INT number of repeats of the original
STRING. In this case, the INT argument cannot be negative.
**/**
: Integer division. Returns the quotient of two **INT**s, discarding
the remainder.
**%**
: Modulus. Returns the remainder upon dividing one **INT** by another.
**+**
: Has several uses. These are:
> **INT** + **INT** - returns the sum of two **INT**s.
>
> **INT** + **TIME** or **TIME** + **INT** - returns a **TIME** obtained
> by adding **INT** minutes to the original **TIME**. The result will
> always range from 00:00 through 23:59.
>
> **TIME** + **TIME** treats the second **TIME** parameter as a
> duration, converting it to an integer number of minutes past midnight,
> and then performs addition as with **TIME** + **INT**.
>
> **INT** + **DATE** or **DATE** + **INT** - returns a **DATE** obtained
> by adding **INT** days to the original **DATE**.
>
> **INT** + **DATETIME** or **DATETIME** + **INT** - returns a
> **DATETIME** obtained by adding **INT** minutes to the original
> **DATETIME**.
>
> **DATETIME** + **TIME** or **TIME** + **DATETIME** treats the **TIME**
> parameter as a duration, converting it to an integer number of minutes
> past midnight, and then performs addition as with **DATETIME** +
> **INT**.
>
> **STRING** + **STRING** - returns a **STRING** that is the
> concatenation of the two original **STRING**s.
>
> **STRING** + anything or anything + **STRING** - converts the
> non-**STRING** argument to a **STRING**, and then performs
> concatenation. See the **coerce()** function.
**-**
: Has several uses. These are:
> **INT** - **INT** - returns the difference of two **INT**s.
>
> **DATE** - **DATE** - returns (as an **INT**) the difference in days
> between two **DATE**s.
>
> **TIME** - **TIME** - returns (as an **INT**) the difference in
> minutes between two **TIME**s.
>
> **DATETIME** - **DATETIME** - returns (as an **INT**) the difference
> in minutes between two **DATETIME**s.
>
> **DATE** - **INT** - returns a **DATE** that is **INT** days earlier
> than the original **DATE**.
>
> **TIME** - **INT** - returns a **TIME** that is **INT** minutes
> earlier than the original **TIME**.
>
> **DATETIME** - **INT** - returns a **DATETIME** that is **INT**
> minutes earlier than the original **DATETIME**.
>
> **DATETIME** - **TIME** - coerces the **TIME** to an **INT** and then
> performs subtraction as above.
**\<, \<=, \>, and \>=**
: These are the comparison operators. They can take operands of any
type, but both operands must be of the same type. The comparison
operators return 1 if the comparison is true, or 0 if it is false.
Note that string comparison is done following the lexical ordering
of characters on your system, and that upper and lower case *are*
distinct for these operators.
**==, !=**
: == tests for equality, returning 1 if its operands are equal, and 0
if they are not. != tests for inequality.
> If the operands are not of the same type, == returns 0 and !=
> returns 1. Again, string comparisons are case-sensitive.
**&&**
: This is the logical AND operator. Returns the second operand if both
operands are non-zero. Otherwise, returns whichever operand is zero.
Operands can be any type and \"zero\" is interpreted as appropriate
for each operand\'s type.
**\|\|**
: This is the logical OR operator. It returns the first operand that
is non-zero; if both operands are zero, then returns the second
operand. Operands can be any type and \"zero\" is interpreted as
appropriate for each operand\'s type.
**NOTES**
If the result of an addition, subtraction or multiplication operation
would not fit in a C \"int\" type, **Remind** issues a \"Number too
high\" error. Unlike C, integer operations will not simply give the
wrong answer in case of overflow.
Operators of equal precedence are *always* evaluated from left to right,
except where parentheses dictate otherwise. This is important, because
the enhanced \"+\" operator is not necessarily associative. For example:
1 + 2 + "string" + 3 + 4 yields "3string34"
1 + (2 + "string") + (3 + 4) yields "12string7"
12:59 + 1 + "test" yields "13:00test"
12:59 + (1 + "test") yields "12:591test"
The logical operators are so-called short-circuit operators, as they are
in C. This means that if the first operand of \|\| is true, then the
second operand is *not* evaluated. Similarly, if the first operand of &&
is false, then the second operand is *not* evaluated.
**VARIABLES**
**Remind** allows you to assign values to variables. The **SET** command
is used as follows:
**SET** *var* *expr*
*Var* is the name of a variable. It must start with a letter or
underscore, and consist only of letters, digits and underscores. Only
the first 64 characters of a variable name are significant. Variable
names are *not* case sensitive; thus, \"Afoo\" and \"afOo\" are the same
variable. Examples:
SET a 10 + (9*8)
SET b "This is a test"
SET mydir getenv("HOME")
SET time 12:15
SET date today()
Note that variables themselves have no type. They take on the type of
whatever you store in them.
Variables set with SET or on the command-line with
**-i**_var=expr_ have global scope.
To delete a variable, use the **UNSET** command:
**UNSET** *var* \[*var*\...\]
For example, to delete all the variables declared above, use:
UNSET a b mydir time date
# SYSTEM VARIABLES
In addition to the regular user variables, **Remind** has several
\"system variables\" that are used to query or control the operating
state of **Remind**. System variables are available starting from
version 03.00.07 of **Remind**.
All system variables begin with a dollar sign \'\$\'. They can be used
in **SET** commands and expressions just as regular variables can. All
system variables always hold values of a specified type. In addition,
some system variables cannot be modified, and you cannot create new
system variables. System variables can be initialized on the command
line with the **-i** option, but you may need to quote them to avoid
having the shell interpret the dollar sign. System variable names are
not case-sensitive.
The following system variables are defined. Those marked \"read-only\"
cannot be changed with the **SET** command. All system variables hold
values of type **INT**, unless otherwise specified.
**\$AddBlankLines**
: If set to 1 (the default), then **Remind** normally prints a blank
line after the banner and each reminder. (This can be suppressed by
ending the reminder or banner with a single percent sign.) If
\$AddBlankLines is set to 0, then **Remind** does not print the
blank line. In this case, ending a reminder with % has no effect. If
you *do* want a blank line after a reminder, end it with **%\_** to
insert a newline.
```{=html}
<!-- -->
```
**\$CalcUTC**
: If 1 (the default), then **Remind** uses C library functions to
calculate the number of minutes between local and Universal Time
Coordinated. This affects astronomical calculations (**sunrise()**
for example.) If 0, then you must supply the number of minutes
between local and Universal Time Coordinated in the
**\$MinsFromUTC** system variable.
**\$CalMode (read-only)**
: If non-zero, then the **-c** option was supplied on the command
line.
**\$CalType (read-only, STRING type)**
: If the **-c**, **-s** or **-p** command-line options were used, then
this variable has the value \"monthly\". If **-c+**, **-s+** or
**-p+** were used, then \"weekly\". Otherwise, \"none\".
**\$Daemon (read-only)**
: If \"daemon mode\" **-z** was invoked, contains the number of
minutes between wakeups. If not running in daemon mode, contains 0.
In server mode (either **-z0** or **-zj**), contains -1.
**\$DateSep (STRING type)**
: This variable can be set only to \"/\" or \"-\". It holds the
character used to separate portions of a date when **Remind** prints
a DATE or DATETIME value.
**\$DedupeReminders**
: If this variable is set to 1, then **Remind** will suppress
duplicate reminders. A given reminder is considered to be a
duplicate of a previous one if it has the *exact* same trigger date,
trigger time, and body. By default, this variable is set to 0 and
**Remind** does not suppress duplicate reminders.
As an example, consider the following reminder file:
SET $DedupeReminders 1
REM Wednesday MSG Phooey
REM 20 MSG Phooey
On Wednesday, 20 November 2024, only *one* \"Phooey\" will be
issued. In December of 2024, \"Phooey\" will be issued every
Wednesday as well as on Friday, 20 December 2024
If you set \$DedupeReminders to 0, then **Remind** does not even
track reminders to detect duplicates. Consider the following
example:
SET $DedupeReminders 0
REM Wednesday MSG Hello
SET $DedupeReminders 1
REM Wednesday MSG Hello
Every Wednesday, **Remind** will issue *two* \"Hello\" reminders.
Because \$DedupeReminders was 0 when the first \"Hello\" was issued,
it won\'t be tracked for potential duplicates.
Duplicates are detected after all variable expansion and
substitutions have been done. Consider the following:
SET $DedupeReminders 1
set a "foo"
REM MSG [a]
set a "bar"
REM MSG [a]
set a "foo"
REM MSG [a]
The first REM will trigger and print \"foo\". The second will
trigger and print \"bar\". The third will not trigger because it\'s
a duplicate of the first \"foo\".
**\$DefaultColor (STRING type)**
: This variable can be set to a string that has the form of three
space-separated numbers. Each number must be an integer from 0 to
255, or all three numbers must be -1. The default value of
**\$DefaultColor** is \"-1 -1 -1\", which suppresses default
coloring of MSG-type reminders. If you set **\$DefaultColor** to any
other value, then all MSG-, MSF- and CAL-type reminders are
effectively converted into SPECIAL COLOR reminders whose color value
is specified by **\$DefaultColor**.
Unlike other system variables, the value of **\$DefaultColor** is
*not* preserved between calendar iterations; rather, it is reset to
\"-1 -1 -1\" at the start of each iteration.
**\$DefaultPrio**
: The default priority assigned to reminders without a **PRIORITY**
clause. You can set this as required to adjust the priorities of
blocks of reminders without having to type priorities for individual
reminders. At startup, **\$DefaultPrio** is set to 5000; it can
range from 0 to 9999.
**\$DefaultDelta**
: You can set this variable to a number from 0 through 10000. If set
to a non-zero number, then **Remind** triggers any **REM** statement
that lacks a delta as if it had a delta of **++\$DefaultDelta**. By
default, **\$DefaultDelta** is zero.
**\$DefaultTDelta**
: The default time delta used if no +N is given in an AT clause. This
is normally 0, but can be set with the **-tt** option or explicitly
set in your script. If **\$DefaultDelta** is non-zero, you can use
an explicit delta of +0 in an AT clause to countermand the default
delta.
**\$DeltaOverride (read-only)**
: If non-zero, corresponds to the *n* argument given to a **-t**_n_
command-line option.
**\$DontFork (read-only)**
: If non-zero, then the **-c** option was supplied on the command
line.
**\$DontTrigAts (read-only)**
: The number of times that the **-a** option was supplied on the
command line.
**\$DontQueue (read-only)**
: If non-zero, then the **-q** option was supplied on the command
line.
**\$EndSent (STRING type)**
: Contains a list of characters that end a sentence. The **MSF**
keyword inserts two spaces after these characters. Initially,
**\$EndSent** is set to \".!?\" (period, exclamation mark, and
question mark.)
**\$EndSentIg (STRING type)**
: Contains a list of characters that should be ignored when **MSF**
decides whether or not to place two spaces after a sentence.
Initially, is set to \"\'\>)\]}\"+CHAR(34) (single-quote,
greater-than, right parenthesis, right bracket, right brace, and
double-quote.)
> For example, the default values work as follows:
>
> MSF He said, "Huh! (Two spaces will follow this.)" Yup.
>
> because the final parenthesis and quote are ignored (for the purposes
> of spacing) when they follow a period.
**\$ExpressionTimeLimit**
: If set to a non-zero value *n*, than any expression that takes
longer than *n* seconds to evaluate will be aborted and an error
returned. This is to prevent maliciously-crafted expressions for
creating a denial-of-service. In an included file,
\$ExpressionTimeLimit can only be lowered from its current value. In
the top-level file, it can be set to any value, including zero to
disable the time limit.
**\$FirstIndent**
: The number of spaces by which to indent the first line of a
**MSF**-type reminder. The default is 0.
**\$FoldYear**
: The standard Unix library functions may have difficulty dealing with
dates later than 2037. If this variable is set to 1, then the UTC
calculations \"fold back\" years later than 2037 before using the
Unix library functions. For example, to find out whether or not
daylight saving time is in effect in June, 2077, the year is
\"folded back\" to 2027, because both years begin on a Friday, and
both are non-leapyears. The rules for daylight saving time are thus
presumed to be identical for both years, and the Unix library
functions can handle 2027. By default, this variable is 0. Set it to
1 if the sun or UTC functions misbehave for years greater than 2037.
See also the section \"MACHINES WITH A 32-BIT TIME_T TYPE\"
**\$FormWidth**
: The maximum width of each line of text for formatting **MSF**-type
reminders. The default is the width of the terminal in columns,
minus 8, but clamped at a minimum of 20 and a maximum of 500. If
standard output is not a terminal, then the default is 72.If an
**MSF**-type reminder contains a word too long to fit in this width,
it will not be truncated - the width limit will be ignored.
**\$HideCompletedTodos (read-only)**
: If non-zero, then the **\--hide-completed-todos** option was
supplied on the command line.
**\$HushMode (read-only)**
: If non-zero, then the **-h** option was supplied on the command
line.
**\$IgnoreOnce (read-only)**
: If non-zero, then the **-o** option was supplied on the command
line, or implicitly enabled for some other reason. In this case,
**ONCE** directives will be ignored.
**\$InfDelta (read-only)**
: If non-zero, then the **-t** option was supplied on the command
line, with no *n* argument.
**\$IntMax (read-only)**
: The largest representable **INT**. On a machine with 32-bit signed
integers using twos-complement representation, this will be
2147483647.
**\$IntMin (read-only)**
: The smallest representable **INT**. On a machine with 32-bit signed
integers using twos-complement representation, this will be
-2147483648.
**\$Latitude (STRING type)**
: The latitude of your location, expressed as a string that is a
floating-point number. Because **Remind** does not have a native
floating-point type, we need to express it as a string. \$Latitude
can range from \"-90.0\" to \"90.0\", with positive numbers
representing points north of the equator and negative numbers
representing south. Note that regardless of your locale, \$Latitude
is always interpreted in the \"C\" locale and as such, the decimal
point must be a period (\".\").
**\$Longitude (STRING type)**
: The longitude of your location, expressed as a string that is a
floating-point number. Because **Remind** does not have a native
floating-point type, we need to express it as a string. \$Longitude
can range from \"-180.0\" to \"180.0\", with positive numbers
representing points east of the Greenwich Meridian and negative
numbers representing west. Note that regardless of your locale,
\$Longitude is always interpreted in the \"C\" locale and as such,
the decimal point must be a period (\".\").
For example, the coordinates of the Statue of Liberty in New York
City are approximately set by:
SET $Latitude "40.68933"
SET $Longitude "-74.04454"
**\$LatDeg, \$LatMin, \$LatSec (DEPRECATED)**
: These specify the latitude of your location. **\$LatDeg** can range
from -90 to 90, and the others from -59 to 59. Northern latitudes
are positive; southern ones are negative. For southern latitudes,
all three components should be negative. These three variables are
deprecated; you should use **\$Latitude** instead.
**\$Location (STRING type)**
: This is a string specifying the name of your location. It is usually
the name of your town or city. It can be set to whatever you like,
but good style indicates that it should be kept consistent with the
latitude and longitude system variables.
**\$LongDeg, \$LongMin, \$LongSec (DEPRECATED)**
: These specify the longitude of your location. **\$LongDeg** can
range from -180 to 180. Western longitudes are positive; eastern
ones are negative. Note that all three components should have the
same sign: All positive for western longitudes and all negative for
eastern longitudes. Note that for historical reasons, the sign for
longitude is *different* from the usual convention! If you find the
longitude of your location from a search engine, you will most
likely *need to invert the sign to have it work correctly with*
Remind. These three variables are deprecated; you should use
**\$Longitude** instead. Note also that **\$Longitude** uses the
standard convention of negative for western longitudes and positive
for eastern ones.
The latitude and longitude information is required for the functions
**sunrise()** and **sunset()**. Default values can be compiled into
**Remind**, or you can **SET** the correct values at the start of
your reminder scripts.
Note that setting any of **\$LongDec**, **\$LongMin** and
**\$LongSec** updates **\$Longitude** correspondingly, and setting
**\$Longitude** updates **\$LongDeg**, **\$LongMin** and
**\$LongSec**. Similar rules apply to **\$Latitude**, **\$LatDeg**,
**\$LatMin** and **\$LatSec**.
**\$JSONMode (read-only)**
: If non-zero, then the **\--json** command-line option was supplied.
**\$MaxLateMinutes**
: This variable controls how **Remind** reacts to a computer being
suspended and then woken. Normally, if a timed reminder is queued
and then the computer suspended, and then the computer is woken
*after* the timed reminder\'s trigger time, **Remind** will trigger
the timer anyway, despite the fact that the trigger time has already
passed.
If you set **\$MaxLateMinutes** to a non-zero integer between 1 and
1440, then **Remind** will *not* trigger a timed reminder whose
trigger time is more than **\$MaxLateMinutes** minutes in the past.
Note that **Remind** uses the value of **\$MaxLateMinutes** that is
in effect when it has finished reading the reminder file and puts
itself in the background. Generally, you should set
**\$MaxLateMinutes** once near the beginning of the file and not
change it after that.
**\$MaxSatIter**
: The maximum number of iterations for the **SATISFY** clause
(described later.) Must be at least 10.
**\$MaxStringLen**
: A limit on the longest string that **Remind** will allow you to
create. The default is 65535. If you set **\$MaxStringLen** to 0 or
to -1, then **remind** will allow you to create arbitrarily-long
strings, at least until it runs out of memory. We do not recommend
setting **\$MaxStringLen** to 0 or -1 because it is very easy to
write code that DOSes **Remind** in that case.
**\$MinsFromUTC**
: The number of minutes between Universal Time Coordinated and local
time. If **\$CalcUTC** is non-zero, this is calculated upon startup
of **Remind**. Otherwise, you must set it explicitly. If
**\$CalcUTC** is zero, then **\$MinsFromUTC** is used in the
astronomical calculations. You must adjust it for daylight saving
time yourself. Also, if you want to initialize **\$MinsFromUTC**
using the **-i** command-line option, you must also set
**\$CalcUTC** to 0 with the **-i** option.
**\$NextMode (read-only)**
: If non-zero, then the **-n** option was supplied on the command
line.
**\$MaxFullOmits (read-only)**
: The maximum number of full OMITs allowed (a compiled-in constant.)
**\$MaxPartialOmits (read-only)**
: The maximum number of partial OMITs allowed (a compiled-in
constant.)
**\$NumFullOmits (read-only)**
: The number of full OMITs in the current OMIT context.
**\$NumPartialOmits (read-only)**
: The number of partial OMITs in the current OMIT context.
**\$NumQueued (read-only)**
: Contains the number of reminders queued so far for background timed
triggering.
**\$NumTrig (read-only)**
: Contains the number of reminders triggered for the current date. One
use for this variable is as follows: Suppose you wish to shade in
the box of a PostScript calendar whenever a holiday is triggered.
You could save the value of **\$NumTrig** in a regular variable
prior to executing a block of holiday reminders. If the value of
**\$NumTrig** after the holiday block is greater than the saved
value, then at least one holiday was triggered, and you can execute
the command to shade in the calendar box. (See the section
\"Calendar Mode\".)
> Note that **\$NumTrig** is affected *only* by **REM** commands;
> triggers in **IFTRIG** commands do not affect it.
**\$OnceFile (STRING type)**
: If you set this variable to a non-empty string, then rather than
using the file access date to determine whether or not to run a
ONCE-type reminder, **Remind** will maintain a timestamp in the file
**\$OnceFile**. This is more reliable than using the access date of
the reminder file.
If **\$OnceFile** does not exist, then it will be created the first
time a **ONCE** keyword is processed. The file must be writable by
the current user. If you try to set **\$OnceFile** *after* a
**ONCE** reminder has already been processed, **Remind** will issue
a warning and ignore the attempt to set **\$OnceFile**.
**\$ParseUntriggered**
: A flag indicating whether or not **Remind** should fully parse
**REM** statements that are not triggered. 0 (the default) means to
skip parsing them and 1 means to parse them.
> For example, if we have the following **REM** statement:
>
> REM 2020-01-01 MSG ["bad_expression" / 2]
>
> Then if **\$ParseUntriggered** is set to 1, **Remind** will fully
> parse the line and issue a \"Type mismatch\" error even if the
> reminder is not triggered. However, if **\$ParseUntriggered** is set
> to 0, the default, then **Remind** will not issue the error except on
> 2020-01-01, when the reminder is triggered.
>
> Keeping **\$ParseUntriggered** at 0 may slightly improve performance,
> at the risk of not catching errors until a reminder is triggered. We
> recommend leaving it set to 0.
**\$PrefixLineNo (read-only)**
: If non-zero, then the **-l** option was supplied on the command
line.
**\$PSCal (read-only)**
: If non-zero, then the **-p** option was supplied on the command
line.
**\$RunOff (read-only)**
: If non-zero, the **RUN** directives are disabled.
**\$SimpleCal (read-only)**
: Set to a non-zero value if *either* of the **-p** or **-s**
command-line options was supplied.
**\$SortByDate (read-only)**
: Set to 0 if no **-g** option is used, 1 if sorting by date in
ascending order, or 2 if sorting by date in descending order.
**\$SortByPrio (read-only)**
: Set to 0 if no **-g** option is used, 1 if sorting by priority in
ascending order, or 2 if sorting by priority in descending order.
**\$SortByTime (read-only)**
: Set to 0 if no **-g** option is used, 1 if sorting by time in
ascending order, or 2 if sorting by time in descending order.
**\$SubsIndent**
: The number of spaces by which all lines (except the first) of an
**MSF**-type reminder should be indented. The default is 0.
**\$SuppressImplicitWarnings**
: Normally, **Remind** issues a warning if a line begins with an
unknown token and is treated as a **REM** command, or if a **REM**
command is missing a type and is treated as a **MSG**-type reminder.
Setting **\$SuppressImplicitWarnings** to 1 suppresses these
warnings. The default is 0 and we do not recommend disabling the
warnings.
**\$SuppressLRM**
: Normally, when **Remind** is run with the **-c** option in a UTF-8
locale, it emits a left-to-right mark sequence after printing day
names or reminders. Some terminals render this incorrectly, so you
can use:
SET $SuppressLRM 1
at the top of your reminder file to suppress the LRM sequences, or
you can invoke **Remind** with the option **\'-i\$SuppressLRM=1\'**.
**\$SysInclude (read-only, STRING type)**
: A directory path containing standard reminder scripts. Currently,
**Remind** ships with some standard holiday files and language
packs. The value of **\$SysInclude** is \"/usr/local/share/remind\"
on this installation.
**\$T (read-only, DATE or INT type)**
: Equivalent to **trigdate()**. (See BUILT-IN FUNCTIONS.)
**\$Tb (read-only, DATE or INT type)**
: Equivalent to **trigbase()**.
**\$Td (read-only)**
: Equivalent to **day(trigdate())**.
**\$Tm (read-only)**
: Equivalent to **monnum(trigdate())**.
**\$Tu (read-only, DATE or INT type)**
: Equivalent to **triguntil()**.
**\$Tw (read-only)**
: Equivalent to **wkdaynum(trigdate())**.
**\$Ty (read-only)**
: Equivalent to **year(trigdate())**.
**\$Tt (read-only, TIME or INT type)**
: Equivalent to **trigtime()**.
**\$TimeSep (STRING type)**
: This variable can be set only to \":\" or \".\". It holds the
character used to separate portions of a time when **Remind** prints
a TIME or DATETIME value.
**\$TimetIs64bit (read-only)**
: This variable returns 1 if the internal C **time_t** type is at
least 64 bits long. If it returns 0, then the internal C library is
unable to represent dates after about 2038, and **Remind** will use
a workaround to avoid problems. See also the section \"MACHINES WITH
A 32-BIT TIME_T TYPE\"
**\$TodoFilter (read-only)**
: If 0, then both events and TODOs are being output. If 1, then the
**\--only-todos** command-line option was supplied. If 2, then the
**\--only-events** command-line option was supplied.
**\$UntimedFirst (read-only)**
: Set to 1 if the **-g** option is used with a fourth sort character
of \"d\"; set to 0 otherwise.
**\$U (read-only, DATE type)**
: Exactly equivalent to **today()**. (See BUILT-IN FUNCTIONS.)
**\$Ud (read-only)**
: Equivalent to **day(today())**.
**\$Um (read-only)**
: Equivalent to **monnum(today())**.
**\$Uw (read-only)**
: Equivalent to **wkdaynum(today())**.
**\$Uy (read-only)**
: Equivalent to **year(today())**.
**\$UseVTColors (read-only)**
: Set to 1 if the **-@** or **-cc** options were used; 0 otherwise.
**\$UseBGVTColors (read-only)**
: Set to 1 if the **-@,,1** option was used; 0 otherwise.
**\$Use256Colors (read-only)**
: Set to 1 if the **-@1** option was used; 0 otherwise.
**\$UseTrueColors (read-only)**
: Set to 1 if the **-@2** option was used; 0 otherwise.
**\$TerminalBackground (read-only)**
: Returns -1 if the terminal background color could not be determined,
0 if it was found to be dark (or was specified as dark with the
**-@,0** option) or 1 if it was found to be light (or specified as
light with the **-@,1** option.) The terminal background is
considered to be \"dark\" if the average of the red, green and blue
components is at most 85 out of 255, and if the maximum of any
component is at most 128 out of 255.
**\$WarningLevel (STRING type)**
: As new versions of **Remind** are released, new warnings may be
added. If your formerly-fine scripts suddenly start issuing warnings
when you upgrade **Remind**, then as a *stopgap* measure, you may
set **\$WarningLevel** to a string of the form *AB*.*CD*.*EF* where
*AB*, *CD* and *EF* are pairs of decimal digits. This will suppress
any warnings that were introduced *after* **Remind** version
*AB*.*CD*.*EF*. If you do not set **\$WarningLevel**, then it
defaults to the current version of **Remind**, meaning all warnings
will be issued.
For example, if you want the warnings you receive limited to what
Remind 05.00.00 would have produced, use:
SET $WarningLevel "05.00.00"
We do *not* recommend setting **\$WarningLevel** as a matter of
course; you should use it to suppress warnings only for as long as
it takes for you to fix your remind scripts so they no longer cause
warnings to be emitted.
Note: If any of the calendar modes are in effect, then the values of
\$Daemon, \$DontFork, \$DontTrigAts, \$DontQueue, \$HushMode,
\$IgnoreOnce, \$InfDelta, and \$NextMode are not meaningful.
# SAVING AND RESTORING VARIABLES
Just as with the OMIT context, you can save and restore the values of
global variables and all (modifiable) system variables. For example:
SET a 1
UNSET b
# Save variables
PUSH-VARS $DefaultColor $AddBlankLines a b
SET $DefaultColor "255 0 0"
SET $AddBlankLines 0
SET a 3
SET b 4
REM MSG Hello
# Restore all the variables we pushed earlier
POP-VARS
# Now the changes to $DefaultColor and $AddBlankLines
# have been undone. Additionally, a is restored to 1
# and b is unset
As you see from the example, PUSH-VARS takes a list of global variable
names and/or system variable names. You can save the values of any
*modifiable* system variables and any global variable. You can even push
global variables that are not set.
The POP-VARS command restores the values of all system variables and
global variables that were pushed by the most recent PUSH-VARS command.
If you push an undefined global variable, then that variable is unset by
the POP-VARS command.
# BUILT-IN FUNCTIONS
**Remind** has a plethora of built-in functions. The syntax for a
function call is the same as in C - the function name, followed a
comma-separated list of arguments in parentheses. Function names are not
case-sensitive. If a function takes no arguments, it must be followed by
\"()\" in the function call. Otherwise, **Remind** will interpret it as
a variable name, and probably not work correctly.
In the descriptions below, short forms are used to denote acceptable
types for the arguments. The characters \"i\", \"s\", \"d\", \"t\" and
\"q\" denote **INT**, **STRING**, **DATE**, **TIME** and **DATETIME**
arguments, respectively. If an argument can be one of several types, the
characters are concatenated. For example, \"di_arg\" denotes an argument
that can be a **DATE** or an **INT**. \"x_arg\" denotes an argument that
can be of any type. The type of the argument is followed by an
underscore and an identifier naming the argument.
The built-in functions are:
**\_(s_message)**
: Returns the translation table entry for *message*. If there is no
such translation table entry, then returns *message* unmodified. For
example, consider this sequence:
TRANSLATE "Goodbye" "Tot ziens"
SET a _("Goodbye")
After those two lines have been executed, the variable **a** will be
set to \"Tot ziens\". See the section THE TRANSLATION TABLE for more
information.
In the body of a reminder, the substitution sequence
**%(**_text_**)** is (almost) the equivalent of
**\[\_(\"**_text_**\")\]**. Therefore, the following reminders are
almost equivalent:
REM MSG %(Goodbye)
REM MSG [_("Goodbye")]
The only difference is that if \_(\"Goodbye\") contains a **%**
sign, then that result will be run through the substitution filter,
whereas in the first reminder, it will not. That is because the
second **REM** command performs expression pasting followed by a
substitution filter pass, while the first one performs the
translation as part of the substitution filter (and does not make a
second substitution filter pass.)
**abs(i_num)**
: Returns the absolute value of *num*.
**access(s_file, si_mode)**
: Tests the access permissions for the file *file*. *Mode* can be a
string, containing a mix of the characters \"rwx\" for read, write
and execute permission testing. Alternatively, *mode* can be a
number as described in the UNIX **access**(2) system call. The
function returns 0 if the file can be accessed with the specified
*mode*, and -1 otherwise.
**adawn(\[dq_date\])**
: Returns the time of \"astronomical dawn\" on the specified *date*.
If *date* is omitted, defaults to **today()**. If a *datetime*
object is supplied, only the date component is used.
**adusk(\[dq_date\])**
: Returns the time of \"astronomical twilight\" on the specified
*date*. If *date* is omitted, defaults to **today()**.
**ampm(tq_time \[,s_am \[,s_pm \[,i_lz\]\]\])**
: Returns a **STRING** that is the result of converting *time* (which
is either a **TIME** or a **DATETIME** object) to \"AM/PM\" format.
The optional arguments *am* and *pm* are the strings to append in
the AM and PM case, respectively; they default to \"AM\" and \"PM\".
The optional argument *lz* specifies whether or not the hour should
be padded to two digits with a leading zero. If *lz* is zero, then a
leading 0 is not added; otherwise, the hour is padded out to two
digits with a leading zero. If not supplied, *lz* defaults to zero.
The function obeys the system variables \$DateSep, \$TimeSep and
\$DateTimeSep when formatting its output. Here are some examples of
its output:
ampm(0:22) returns "12:22AM"
ampm(17:45, "am", "pm") returns "5:45pm"
ampm(17:45, "am", "pm", 1) returns "05:45pm"
ampm('2020-03-14@21:34') returns "2020-03-14@9:34PM"
**ansicolor(i_red, i_green, i_blue \[,i_bg \[,i_clamp\]\])**
: Returns a **STRING** that contains an ANSI escape sequence for
changing the terminal text color. The parameters *red*, *green* and
*blue* are integers from 0 to 255 specifying the value of the
respective color component. As a special case, all three values can
be -1, in which case the ANSI sequence \"ESC\[0m\" is returned,
which resets all text attributes to normal.
The string returned by **ansicolor** depends on the color mode that
**Remind** is running in, as specified by the **-@** option. If
color mode is not enabled, then **ansicolor** always returns the
empty string. Otherwise, it returns the escape sequence that best
approximates the color according to the **-@** color mode.
The optional *bg* argument is either 0 or 1. If 0 (the default),
then the foreground color is set. If 1, then the background color is
set. Note that setting the background color only works in 256-color
or true-color mode.
The optional *clamp* argument is either 0 or 1. If 0 (the default),
then colors are not adjusted based on the terminal background color.
If 1, then **Remind** attempts to adjust dark or bright colors so
they have enough contrast to be visible in the terminal.
The first three arguments may alternatively be specified as a string
consisting of three space-separated numbers, as in this example:
\"128 128 0\"
As a special case, **ansicolor(\"\")** is equivalent to
**ansicolor(-1,-1,-1)** and returns the ANSI sequence to reset all
text attributes to normal.
Note that inserting ANSI color sequences in calendar mode *will*
produce garbled results. Therefore, we recommend defining functions
such as the ones below that return the empty string in calendar
mode:
IF $CalMode
FSET fg(r,g,b) ""
FSET bg(r,g,b) ""
ELSE
FSET fg(r,g,b) ansicolor(r,g,b)
FSET bg(r,g,b) ansicolor(r,g,b,1)
ENDIF
REM [fg(255,0,0)][bg(64,64,64)]Red on Gray[fg(-1,-1,-1)] in agenda mode
REM SPECIAL COLOR 0 255 0 Green in agenda and calendar mode
If you use the **ansicolor** function, don\'t forget to reset the
color back to normal with **ansicolor(-1,-1,-1)** or subsequent
reminders will continue to be colored.
**args(s_fname)**
: Returns the number of arguments expected by the user-defined
function *fname*, or -1 if no such user-defined function exists.
Note that this function examines only user-defined functions, not
built-in functions. Its main use is to determine whether or not a
particular user-defined function has been defined previously. The
**args()** function is available only in versions of **Remind** from
03.00.04 and up.
**asc(s_string)**
: Returns an **INT** that is the ASCII code of the first byte in
*string*. As a special case, **asc(\"\")** returns 0. For UTF-8
strings, this will return the UTF-8 byte with which the string
begins, which is not likely to be very useful.
**codepoint(s_string)**
: Returns an **INT** that is the code point of the first character in
*string*, treating multi-byte characters correctly. As a special
case, **codepoint(\"\")** returns 0.
**baseyr()**
: Returns the \"base year\" that was compiled into **Remind**
(normally 1990.) All dates are stored internally as the number of
days since 1 January of **baseyr()**.
**catch(x_arg1, x_arg2)**
: Evaluates **arg1** and if no error occurs, returns the resulting
value. If an error occurs during the evaluation of **arg1**,
evaluates and returns **arg2**. Note that **catch()** can only catch
run-time *evaluation* errors. It cannot catch *syntax* errors.
Here are some examples:
catch(4/2, 33) => 2, because 4/2 evaluates without error
catch(4/0, 33) => 33, because 4/0 gives a divide-by-zero error
catch(2, 1/0) => 2, and the second argument is not evaluated
catch(4/0, 1/0) results in a divide-by-zero error
Note in the last example that catch does *not* protect you from
errors in the evaluation of **arg2**.
**catcherr()**
: Returns a string representing the error message from the most
recently-evaluated **catch()** function whose first argument yielded
an error. Note that the error message is always in English even if
**Remind** has been localized; this lets you reliably test the
return value. Here are some examples:
# No "catch" invocations yet: sets a to "Ok"
set a catcherr()
# Sets b to "oops" and a to "Division by zero"
set b catch(1/0, "oops")
set a catcherr()
# Sets b to 1 and a to "Division by zero". The catch error
# is never cleared by a non-error catch()
set b catch(4-3, "not-evaluated")
set a catcherr()
**char(i_i1 \[,i_i2\...\])**
: This function can take any number of **INT** arguments. It returns a
**STRING** consisting of the bytes specified by the arguments. It is
easy to create invalid UTF-8 sequences; **char** does not check for
this. Note that none of the arguments can be 0, unless there is only
one argument. As a special case, **char(0)** returns \"\".
**mbchar(i_i1 \[,i_i2\...\])**
: This function can take any number of **INT** arguments. It returns a
**STRING** consisting of the characters specified by the arguments.
Any codepoint may be supplied and a correct multi-byte character
string will be returned. Note that none of the arguments can be 0,
unless there is only one argument. As a special case, **mbchar(0)**
returns \"\". Additionally, no argument may be a negative number.
**choose(i_index, x_arg1 \[,x_arg2\...\])**
: **Choose** must take at least two arguments, the first of which is
an **INT**. If *index* is *n*, then the *n*th subsequent argument is
returned. If *index* is less than 1, then *arg1* is returned. If
*index* is greater than the number of subsequent arguments, then the
last argument is returned. Examples:
```{=html}
<!-- -->
```
choose(0, "foo", 1:13, 1000) returns "foo"
choose(1, "foo", 1:13, 1000) returns "foo"
choose(2, "foo", 1:13, 1000) returns 1:13
choose(3, "foo", 1:13, 1000) returns 1000
choose(4, "foo", 1:13, 1000) returns 1000
> Note that only the first argument and the chosen result are evaluated.
> Any non-chosen arguments will not be evaluated.
**coerce(s_type, x_arg)**
: This function converts *arg* to the specified *type*, if such
conversion is possible. *Type* must be one of \"INT\", \"STRING\",
\"DATE\", \"TIME\" or \"DATETIME\" (case-insensitive). The
conversion rules are as follows:
If *arg* is already of the *type* specified, it is returned
unchanged.
If *type* is \"STRING\", then *arg* is converted to a string
consisting of its printed representation.
If *type* is \"DATE\", then an **INT** *arg* is converted by
interpreting it as the number of days since 1 January **baseyr()**.
A **STRING** *arg* is converted by attempting to read it as if it
were a printed date. A **DATETIME** is converted to a date by
dropping the time component. A **TIME** *arg* cannot be converted to
a date.
If *type* is \"TIME\", then an **INT** *arg* is converted by
interpreting it as the number of minutes since midnight. A
**STRING** *arg* is converted by attempting to read it as if it were
a printed time. A **DATETIME** is converted to a time by dropping
the date component. A **DATE** *arg* cannot be converted to a time.
If *type* is \"DATETIME\", then an **INT** *arg* is converted by
interpreting it as the number of minutes since midnight, 1 January
**baseyr()**. A **STRING** is converted by attempting to read it as
if it were a printed datetime. Other types cannot be converted to a
datetime.
If *type* is \"INT\", then **DATE**, **TIME** and **DATETIME**
arguments are converted using the reverse of procedures described
above. A **STRING** *arg* is converted by parsing it as an integer.
**columns(\[s_arg\])**
: If called with no arguments, **columns()** behaves as follows: If
standard output is a TTY, returns the width of the terminal in
columns. If standard output is not a TTY, attempts to open
\"/dev/tty\" to obtain the terminal size. If this fails, returns -1.
If called with a single string argument, **columns(str)** returns
the number of columns **str** will occupy if printed to a terminal.
ANSI color-changing sequences occupy zero columns whereas some
Unicode characters occupy two columns. **columns(str)** takes all of
that into account. Note that if **Remind** was compiled without
Unicode support, **columns(str)** returns a type mismatch error.
The result of **columns(str)** may be less than, equal to, or
greater than the result of **mbstrlen(str)**. This is because some
Unicode characters are so-called combining characters that add one
to the character length, but don\'t occupy any columns on their own.
And other Unicode characters are double-width characters that add
one to the character length, but two to the number of display
columns.
**const(x_arg)**
: Evaluates *arg* and returns it, but also ensures that the result is
marked \"constant\". Use with caution; incorrect use could result in
unwanted reminders being purged in Purge Mode. See also the section
\"NON-CONSTANT EXPRESSIONS\"
**current()**
: Returns the current date and time as a DATETIME object. This may be
the actual date and time, or may be the date and time supplied on
the command line.
**date(i_y, si_m, i_d)**
: The **date()** function returns a **DATE** object with the year,
month and day components specified by *y*, *m* and *d*. The month
can be specified as an integer from 1 to 12, or a string that is the
name of a month.
**datepart(dq_datetime)**
: Returns a **DATE** object representing the date portion of
*datetime*.
**datetime(args)**
: The **datetime()** function can take anywhere from two to five
arguments. It always returns a DATETIME generated from its
arguments.
If you supply two arguments, the first must be a DATE and the second
a TIME.
If you supply three arguments, the first must be a DATE and the
second and third must be INTs. The second and third arguments are
interpreted as hours and minutes and converted to a TIME.
If you supply four arguments, they are interpreted as year, month,
day and time. Year and day must be INTs. Month may be an INT from 0
to 12 or a string naming a month. Time must be a TIME.
Finally, if you supply five arguments, they must all be INTs and are
interpreted as year, month, day, hour and minute. (Actually, month
can also be a string that is the name of a month.)
**dawn(\[dq_date\])**
: Returns the time of \"civil dawn\" on the specified *date*. If
*date* is omitted, defaults to **today()**. If a *datetime* object
is supplied, only the date component is used.
**day(dq_date)**
: This function takes a **DATE** or **DATETIME** as an argument, and
returns an **INT** that is the day-of-month component of *date*.
**daysinmon(si_m, i_y) or daysinmon(dq_date)**
: Returns the number of days in month *m* (1-12) of the year *y*. The
first argument can either be an integer from 1 to 12, or a string
that is the name of a month. If given a single DATE or DATETIME
argument, returns the number of days in the month containing the
argument.
**defined(s_var)**
: Returns 1 if the variable named by *var* is defined, or 0 if it is
not.
Note that **defined()** takes a **STRING** argument; thus, to check
if variable X is defined, use:
defined("X")
and not:
defined(X)
The second example will attempt to evaluate X, and will return an
error if it is undefined or not of type **STRING**.
**dosubst(s_str \[,d_date \[,t_time\]\]) or dosubst(s_str \[,q_datetime\])**
: Returns a **STRING** that is the result of passing *str* through the
substitution filter described earlier. The parameters *date* and
*time* (or *datetime*) establish the effective trigger date and time
used by the substitution filter. If *date* and *time* are omitted,
they default to **today()** and **now()**.
Note that if *str* does not end with \"%\", a newline character will
be added to the end of the result. Also, calling **dosubst()** with
a *date* that is in the past (i.e., if *date* \< **today()**) will
produce undefined results.
**Dosubst()** is only available starting from version 03.00.04 of
**Remind**.
**dusk(\[dq_date\])**
: Returns the time of \"civil twilight\" on the specified *date*. If
*date* is omitted, defaults to **today()**.
**easterdate(\[dqi_arg\])**
: If *arg* is an **INT**, then returns the date of Easter Sunday for
the specified year. If *arg* is a **DATE** or **DATETIME**, then
returns the date of the next Easter Sunday on or after *arg*. (The
time component of a datetime is ignored.) If *arg* is omitted, then
it defaults to **today()**.
Note that **easterdate** computes the Western Easter. For the
Orthodox Easter date, see **orthodoxeaster**.
**escape(s_string \[,i_add_quotes\])**
: Returns a **STRING** that is the same as the input string, but with
all special characters backslashed-escaped. For example, the
following command:
set a escape("foo" + char(10) + "bar")
will set a to \"foo\\nbar\" where \"\\n\" is the literal sequence
\"\\\" followed by \"n\". This is useful if you want to compute a
string in a pasted-in expression that **Remind** will then parse as
a quoted string again, such as in a TRANSLATE command or an INFO
clause.
If the optional *add_quotes* argument is supplied and is non-zero,
then the return value from **escape** will include surrounding
double-quotes.
**eval(s_arg)**
: Parses the string *arg* as an expression and evaluates it, returning
the result. Note that any variable names in the parsed expression
refer to global variables, not any local variables. For example,
consider this:
> SET x 2
> FSET f(x) x + eval("1 + x")
> REM MSG F is [f(9)]
>
> The result will be \"F is 12\" because the reference to *x* inside the
> **eval()** argument refers to the *global* variable *x* and not the
> function argument.
>
> Note that for safety, **RUN** is disabled during the evaluation of
> **eval()**, which means you can\'t use the **shell()** function from
> within an **eval()**.
**evaltrig(s_trigger \[,dq_start\])**
: Evaluates *trigger* as if it were a REM or IFTRIG trigger
specification and returns the trigger date as a **DATE** (or as a
**DATETIME** if there is an **AT** clause.) Returns a negative
**INT** if no trigger could be computed.
Normally, **evaltrig** finds a trigger date on or after today. If
you supply the *start* argument, then it scans starting from there.
For example, the expression:
evaltrig("Mon 1", '2008-10-07')
returns \'2008-11-03\', since that is the first date on or after 7
October 2008 that satisfies \"Mon 1\".
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:
evaltrig("Mon 1", '2008-11-01') - evaltrig("Mon 1", '2008-10-01')
and the answer is 28. The trigger argument to **evaltrig** can have
all the usual trigger clauses (**OMIT**, **AT**, **SKIP**, etc.) but
*cannot* have a **SATISFY**, **MSG**, etc. reminder-type clause.
**filedate(s_filename)**
: Returns the modification date of *filename*. If *filename* does not
exist, or its modification date is before the year **baseyr()**,
then 1 January of **baseyr()** is returned.
**filedatetime(s_filename)**
: Returns the modification date and time of *filename*. If *filename*
does not exist, or its modification date is before the year
**baseyr()**, then midnight, 1 January of **baseyr()** is returned.
**filedir()**
: Returns the directory that contains the current file being
processed. It may be a relative or absolute pathname, but is
guaranteed to be correct for use in an **INCLUDE** command as
follows:
```{=html}
<!-- -->
```
INCLUDE [filedir()]/stuff
> This includes the file \"stuff\" in the same directory as the current
> file being processed. Note that this workaround is no longer necessary
> because **DO stuff** will achieve the same goal.
>
> Note that if the currently-processing reminders file was specified as
> a symbolic link, then **filedir()** returns the directory containing
> the symbolic link and *not* the directory containing the target of the
> symbolic link. You should avoid using symbolic links to files unless
> both the symbolic link and its target happen to be in the same
> directory.
**filename()**
: Returns (as a **STRING**) the name of the current file being
processed by **Remind**. Inside included files, returns the name of
the included file.
**getenv(s_envvar)**
: Similar to the **getenv**(2) system call. Returns a string
representing the value of the specified environment variable.
Returns \"\" if the environment variable is not defined. Note that
the names of environment variables are generally case-sensitive;
thus, getenv(\"HOME\") is not the same as getenv(\"home\").
**hebdate(i_day, s_hebmon \[,idq_yrstart \[,i_jahr \[,i_aflag\]\]\])**
: Support for Hebrew dates - see the section \"THE HEBREW CALENDAR\"
**hebday(dq_date)**
: Support for Hebrew dates - see the section \"THE HEBREW CALENDAR\"
**hebmon(dq_date)**
: Support for Hebrew dates - see the section \"THE HEBREW CALENDAR\"
**hebyear(dq_date)**
: Support for Hebrew dates - see the section \"THE HEBREW CALENDAR\"
**hex(i_n)**
: Returns a **STRING** that is the hexadecimal representation of *n*.
There is no \"0x\" prefix and any letters in the returned value are
uppper-case.
**hour(tq_time)**
: Returns the hour component of *time*.
**htmlescape(s_str)**
: Returns a modified copy of *str* where \"\<\" is replaced with
\"&lt;\"; \"\>\" is replaced with \"&gt;\" and \"&\" is replaced
with \"&amp;\"
**htmlstriptags(s_str)**
: Returns a modified copy of *str* where HTML tags are stripped out.
The stripping algorithm is fairly naive; the function starts
stripping characters when it encounters a \"\<\" and it stops
stripping when it encounters a \"\>\".
**iif(x_test1, x_arg1, \[x_test2, x_arg2,\...\], x_default)**
: If *test1* is true, returns *arg1*. Otherwise, if *test2* is true,
returns *arg2*, and so on. If all of the *test* arguments are false,
returns *default*. Note that only those arguments needed to
determine the final result are evaluated. This function accepts an
odd number of arguments - note that prior to version 03.00.05 of
**Remind**, it accepted 3 arguments only. The 3-argument version of
**iif()** is compatible with previous versions of **Remind**.
**index(s_search, s_target \[,i_start)**
: Returns an **INT** that is the location of *target* in the string
*search*. Note that **index** uses *byte* positions, not character
positions, so should not be used on non-ASCII strings. Use
**mbindex** for non-ASCII strings.
The first byte of a string is numbered 1. If *target* does not exist in
*search*, then 0 is returned.
> The optional parameter *start* specifies the position in *search* at
> which to start looking for *target*.
**mbindex(s_search, s_target \[,i_start\])**
: Similar to **index()** but returns the *character* position rather
than the *byte* position. Also, *start* is interpreted as a 1-based
character index rather than a byte index.
**isany(arg1 \[,arg2, \..., argN\]);**
: Returns 1 if the first argument *arg1* is equal to any of the
subsequent arguments *arg2* through *argN*; returns 0 otherwise.
Also returns 0 if called with only one argument.
As an example, the following two expressions are equivalent:
(a == b) || (a == c) || (a == d) || (a == e)
isany(a, b, c, d, e)
**isconst(x_any)**
: Evaluates its argument and then *throws away* the value, returning 1
if the expression is constant or 0 if it is non-constant. Note that
**isconst** does not take into account the context; if *arg* is a
constant expression but evaluated in a non-constant context,
**isconst** will still return 1. For details about constant vs.
non-constant expressions, see the section \"NON-CONSTANT
EXPRESSIONS\"
**isdst(\[d_date \[,t_time\]\]) or isdst(q_datetime)**
: Returns a positive number if daylight saving time is in effect on
the specified date and time. *Date* defaults to **today()** and
*time* defaults to midnight.
Note that this function is only as reliable as the C run-time
library functions. It is available starting with version 03.00.07 of
**Remind**.
**isleap(idq_arg)**
: Returns 1 if *arg* is a leap year, and 0 otherwise. *Arg* can be an
**INT**, **DATE** or **DATETIME** object. If a **DATE** or
**DATETIME** is supplied, then the year component is used in the
test.
**isomitted(dq_date)**
: Returns 1 if *date* is omitted, given the current global **OMIT**
context. Returns 0 otherwise. (If a datetime is supplied, only the
date part is used.) Note that any local **OMIT** or **OMITFUNC**
clauses are *not* taken into account by this function.
**language()**
: Returns a **STRING** naming the compiled-in language supported by
**Remind**. **Remind** used to support compiled-in support for other
languages, but now all localization is done at run-time. As such,
this function always returns \"English\". However, the expression
**\_(\"LANGID\")** returns the two-character ISO 639 language code
of any language pack in effect, assuming the language pack author
has written the localization correctly!
**localtoutc(q_datetime)**
: Given a **DATETIME** object interpreted in the local time zone,
return a **DATETIME** object that expresses the same time in UTC.
**lower(s_string)**
: Returns a **STRING** with all upper-case characters in *string*
converted to lower-case.
**max(x_arg1 \[,x_arg2\...)**
: Can take any number of arguments, and returns the maximum. The
arguments can be of any type, but must all be of the same type. They
are compared as with the \> operator.
**min(x_arg1 \[,x_arg2\...)**
: Can take any number of arguments, and returns the minimum. The
arguments can be of any type, but must all be of the same type. They
are compared as with the \< operator.
**minsfromutc(\[d_date \[,t_time\]\]) or minsfromutc(q_datetime)**
: Returns the number of minutes from Universal Time Coordinated
(formerly GMT) to local time on the specified date and time. *Date*
defaults to **today()** and *time* defaults to midnight. If local
time is before UTC, the result is negative. Otherwise, the result is
positive.
Note that this function is only as reliable as the C run-time
library functions. It is available starting with version 03.00.07 of
**Remind**.
**minute(tq_time)**
: Returns the minute component of *time*.
**mon(dqis_arg)**
: If *arg* is of **DATE** or **DATETIME** type, returns a string that
names the month component of the date. If *arg* is an **INT** from 1
to 12, returns a string that names the month. If *arg* is a
**STRING**, returns the name of the month. This last case might
sound silly, but for example:
mon("Mar")
will return \"March\", the full name of the month.
**monnum(dq_date)** or **monnum(s_str)**
: Returns an **INT** from 1 to 12, representing the month component of
*date*. If a **STRING** is supplied rather than a **DATE** or
**DATETIME**, then if *str* is a valid month name (or minimum
3-character abbreviation of a month name) then the corresponding
month number is returned. If *str* is not a valid month name, then
an error occurs.
**moondate(i_phase \[,d_date \[,t_time\]\]) or moondate(i_phase, q_datetime)**
: This function returns the date of the first occurrence of the phase
*phase* of the moon on or after *date* and *time*. *Phase* can range
from 0 to 3, with 0 signifying new moon, 1 first quarter, 2 full
moon, and 3 third quarter. If *date* is omitted, it defaults to
**today()**. If *time* is omitted, it defaults to midnight.
For example, the following returns the date of the next full moon:
SET fullmoon moondate(2)
**moontime(i_phase \[,d_date \[,t_time\]\]) or moontime(i_phase, q_datetime)**
: This function returns the time of the first occurrence of the phase
*phase* of the moon on or after *date* and *time*. *Phase* can range
from 0 to 3, with 0 signifying new moon, 1 first quarter, 2 full
moon, and 3 third quarter. If *date* is omitted, it defaults to
**today()**. If *time* is omitted, it defaults to midnight.
**Moontime()** is intended to be used in conjunction with
**moondate()**. The **moondate()** and **moontime()** functions are
accurate to within a couple of minutes of the times in \"Old
Farmer\'s Almanac\" for Ottawa, Ontario.
For example, the following returns the date and time of the next
full moon:
MSG Next full moon at [moontime(2)] on [moondate(2)]
**moondatetime(i_phase \[,d_date \[,t_time\]\]) or moondatetime(i_phase, q_datetime)**
: This function is similar to **moondate** and **moontime**, but
returns a DATETIME result.
**moonphase(\[d_date \[,t_time\]\]) or moonphase(q_datetime)**
: This function returns the phase of the moon on *date* and *time*,
which default to **today()** and midnight, respectively. The
returned value is an integer from 0 to 359, representing the phase
of the moon in degrees. 0 is a new moon, 180 is a full moon, 90 is
first-quarter, etc.
**moonrise(\[d_date\])**
: This function returns a DATETIME result giving the date and time of
the first moonrise on or after midnight on *date*. If *date* is not
supplied, it defaults to **today()**.
Note that it is not uncommon for a day to have no moonrise, so the
date part of the return value may not be the same as the *date*
argument. So if you want a calendar of moonrise times, you could use
something like this:
SET mr moonrise()
IF datepart(mr) == today()
REM NOQUEUE [mr] MSG Moon rises at %3.
ELSE
REM MSG No moonrise today
ENDIF
**moonrisedir(\[d_date\])**
: This function returns an INT result giving the direction from which
the moon will rise on the first moonrise on or after midnight on
*date*. If *date* is not supplied, it defaults to **today()**. The
return value ranges from 0 to 359, where 0 is North, 90 is East, 180
is South and 270 is West.
**moonset(\[d_date\])**
: This function is analogous to **moonrise()** but returns the
DATETIME of the next moonset on or after midnight on *date*.
**moonsetdir(\[d_date\])**
: This function is analogous to **moonrisedir()** but returns the
direction of moonset.
**multitrig(s_trig1 \[,s_trig2, \[\... s_trigN\]\])**
: **multitrig** evaluates each string as a trigger, similar to
**evaltrig**, and returns the *earliest* trigger date that is on or
after **today()**. **multitrig** is similar to **trig** but has the
following difference:
**trig** returns the *first* trigger date that would have triggered
today, whereas **multitrig** returns the *earliest* trigger date
later than today, regardless of whether it would have triggered
today.
If no trigger can be computed that is later than **today()**, then
**multitrig** returns 1990-01-01.
Consider the following examples, assuming that today is Sunday, 24
March 2024:
# Returns 1990-01-01 because neither would trigger today
SET a trig("Mon", "Wed")
# Returns 2024-03-25 because it's the earlier trigger date
SET a multitrig("Mon", "Wed")
# Returns 2024-03-27 because it's the first that would trigger today
SET a trig("Wed +3", "Mon +3")
# Returns 2024-03-25 because it's the earlier trigger date
SET a multitrig("Wed +3", "Mon +3")
# Returns 1990-01-01 because all triggers have expired
SET a multitrig("2000", "2022", "1998", "2023")
In general, **multitrig** works better with the **Remind** algorithm
than **trig** and should be used most of the time. As an example,
this reminder is issued at the end of each quarter:
REM [multitrig("Mar 31", "Jun 30", "Sep 30", "Dec 31")] +7 MSG \
%"End of [ord($Tm/3)] quarter%" is %b.
If you want the last working day of each quarter, you could use:
PUSH-OMIT-CONTEXT
OMIT Sat Sun
REM [multitrig("Mar ~1", "Jun ~1", "Sep ~1", "Dec ~1")] +7 MSG \
%"Last working day of [ord($Tm/3)] quarter%" is %b.
POP-OMIT-CONTEXT
Note that unlike **evaltrig**, **multitrig** always returns a
**DATE** and never a **DATETIME**. Including an **AT** clause in a
trigger supplied to **multitrig** will result in an error.
**ndawn(\[dq_date\])**
: Returns the time of \"nautical dawn\" on the specified *date*. If
*date* is omitted, defaults to **today()**. If a *datetime* object
is supplied, only the date component is used.
**ndusk(\[dq_date\])**
: Returns the time of \"nautical twilight\" on the specified *date*.
If *date* is omitted, defaults to **today()**.
**nonomitted(dq_start, dq_end \[, i_step\] \[,s_wkday\...\])**
: This function returns the number of *non-*omitted days between
*start* and *end*. If *start* is non-omitted, then it is counted.
*end* is never counted.
Note that if *end* is less than *start*, the arguments are
effectively swapped, so counting always begins from the older date.
If the third argument to **nonomitted** is an **INT**, then it must
be greater than zero, and is considered to be the *step* by which
**nonomitted** counts. For example the following expression:
nonomitted('2023-07-01', '2023-07-29', 7)
returns the number of non-omitted Saturdays from 2023-07-01 up to
(but not including) 2023-07-29. (Both 2023-07-01 and 2023-07-29 are
Saturdays.)
If no *step* argument is supplied, then a step of 1 is used.
In addition to using the global OMIT context, you can supply
additional arguments that are names of weekdays to be omitted.
However, in a **REM** command, any local **OMITFUNC** clause is
*not* taken into account by this function.
For example, the following line sets a to 11 (assuming no global
OMITs):
set a nonomitted('2007-08-01', '2007-08-16', "Sat", "Sun")
because Thursday, 16 August 2007 is the 11th working day (not
counting Saturday and Sunday) after Wednesday, 1 August 2007.
**nonomitted** has various uses. For example, many schools run on a
six-day cycle and the day number is not incremented on holidays.
Suppose the school year starts with Day 1 on 4 September 2007. The
following reminder will label day numbers in a calendar:
IF today() >= '2007-09-04'
set daynum nonomitted('2007-09-04', today(), "Sat", "Sun")
REM OMIT SAT SUN SKIP CAL Day [(daynum % 6) + 1]
ENDIF
Obviously, the answer you get from **nonomitted** depends on the
global OMIT context. If you use movable OMITs, you may get
inconsistent results.
Here is a more complex use for **nonomitted**. 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:
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
Here\'s how it works: The \_garbhol(x) user-defined function returns
1 if and only if (1) *x* is a Friday and (2) there is at least one
OMITted day from the previous Monday up to and including the Friday.
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.
**nonconst(x_arg)**
: Returns the argument *arg* unchanged, but forces the expression to
be considered *non-constant*. For details, see the section
\"NON-CONSTANT EXPRESSIONS\"
**now()**
: Returns the current system time, as a **TIME** type. This may be the
actual time, or a time supplied on the command line.
**ord(i_num)**
: Returns a string that is the ordinal number *num*. For example,
**ord(2)** returns \"2nd\", and **ord(213)** returns \"213th\".
In order to help with localization, if you define a function called
**ordx** that takes a single parameter, then calling **ord**(*n*)
invokes **ordx**(*n*) and returns whatever it does. During the
callback to **ordx**, **RUN** will be disabled.
**orthodoxeaster(\[dqi_arg\])**
: If *arg* is an **INT**, then returns the date of Orthodox Easter
Sunday for the specified year. If *arg* is a **DATE** or
**DATETIME**, then returns the date of the next Orthodox Easter
Sunday on or after *arg*. (The time component of a datetime is
ignored.) If *arg* is omitted, then it defaults to **today()**.
Note that **orthodoxeaster** computes the Orthodox Easter. For the
Western Easter date, see **easterdate**.
**ostype()**
: Returns \"UNIX\". **Remind** used to run on OS/2 and MS-DOS, but
does not any longer.
**pad(x_arg, s_padstr, i_len \[, i_right\])**
: Converts the first argument *arg* to a string if necessary, and then
if it is shorter than *len* characters, pads to to *len* characters
using as many copies (including partial copies) of *padstr* as
necessary. By default, the string is left-padded, but if *right* is
supplied and non-zero, the string will be right-padded.
Here are some examples:
pad(3, "0", 2) --> "03"
pad(465, "0", 2) --> "465"
pad("foo", " ", 5) --> " foo"
pad("foo", " ", 5, 1) --> "foo "
pad("foo", "bar", 11) --> "barbarbafoo"
```{=html}
<!-- -->
```
**plural(i_num \[,s_str1 \[,s_str2\]\])**
: Can take from one to three arguments. If one argument is supplied,
returns \"s\" if *num* is not 1, and \"\" if *num* is 1.
If two arguments are supplied, returns *str1* + \"s\" if *num* is
not 1. Otherwise, returns *str1*.
If three arguments are supplied, returns *str1* if *num* is 1, and
*str2* otherwise.
**psmoon(i_phase \[,i_size \[,s_note \[,i_notesize\]\]\])**
: \[DEPRECATED\] Returns a **STRING** consisting of PostScript code to
draw a moon in the upper-left hand corner of the calendar box.
*Phase* specifies the phase of the moon, and is 0 (new moon), 1
(first quarter), 2 (full moon) or 3 (third quarter). If *size* is
specified, it controls the radius of the moon in PostScript units
(1/72 inch.) If it is not specified or is negative, the size of the
day-number font is used.
> For example, the following four lines place moon symbols on the
> PostScript calendar:
>
> REM [moondate(0)] PS [psmoon(0)]
> REM [moondate(1)] PS [psmoon(1)]
> REM [moondate(2)] PS [psmoon(2)]
> REM [moondate(3)] PS [psmoon(3)]
>
> If *note* is specified, the text is used to annotate the moon display.
> The font is the same font used for calendar entries. If *notesize* is
> given, it specifies the font size to use for the annotation, in
> PostScript units (1/72 inch.) If *notesize* is not given, it defaults
> to the size used for calendar entries. (If you annotate the display,
> be careful not to overwrite the day number \-- **Remind** 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:
>
> REM [moondate(0)] PS [psmoon(0, -1, moontime(0)+"")]
>
> Note how the time is coerced to a string by concatenating the null
> string.
**psshade(i_gray)** or **psshade(i_red, i_green, i_blue)**
: \[DEPRECATED\] Returns a **STRING** that consists of PostScript
commands to shade a calendar box. *Num* can range from 0 (completely
black) to 100 (completely white.) If three arguments are given, they
specify red, green and blue intensity from 0 to 100. Here\'s an
example of how to use this:
REM Sat Sun PS [psshade(95)]
The above command emits PostScript code to lightly shade the boxes
for Saturday and Sunday in a PostScript calendar.
Note that **psmoon** and **psshade** are deprecated; instead you
should use the SPECIAL SHADE and SPECIAL MOON reminders as described
in \"Out-of-Band Reminders.\"
**realcurrent()**
: Returns (as a DATETIME) the true date and time of day as provided by
the operating system. This is in contrast to **current()**, which
may return a time supplied on the command line.
**realnow()**
: Returns the true time of day as provided by the operating system.
This is in contrast to **now()**, which may return a time supplied
on the command line.
**realtoday()**
: Returns the date as provided by the operating system. This is in
contrast to **Remind**\'s concept of \"today\", which may be changed
if it is running in calendar mode, or if a date has been supplied on
the command line.
**rows()**
: If standard output is a TTY, returns the height of the terminal in
rows. If standard output is not a TTY, attempts to open \"/dev/tty\"
to obtain the terminal size. If this fails, returns -1.
**sgn(i_num)**
: Returns -1 if *num* is negative, 1 if *num* is positive, and 0 if
*num* is zero.
**shell(s_cmd \[,i_maxlen\])**
: Executes *cmd* as a system command, and returns the first 511
characters of output resulting from *cmd*. Any whitespace character
in the output is converted to a space. Note that if **RUN** OFF has
been executed, or the **-r** command-line option has been used,
**shell()** will result in an error, and *cmd* will not be executed.
When **shell** runs *cmd*, it arranges for *cmd*\'s standard input
file descriptor to be connected to /dev/null.
If *maxlen* is specified, then **shell()** returns the first
*maxlen* characters of output (rather than the first 511). If
*maxlen* is specified as a negative number, then it defaults to the
value of the system variable **\$MaxStringLen**.
**shellescape(s_str)**
: Returns *str* with all shell metacharacters such as \" \", \"\*\",
etc escaped with a backslash. For example:
```{=html}
<!-- -->
```
SET a shellescape("a b*? c&d$e")
> will set **a** to:
"a\ b\*\?\ c\&d\$e"
**slide(d_start, i_amt \[, i_step\] \[,s_wkday\...\])**
: This function is the inverse of **nonomitted**. It adds *amt* (which
can be negative) chunks of *step* days to *start*, *not counting
omitted days*. If *step* is not supplied, then it is assumed to
be 1. Note that only every *step*th day is tested to see if it is
omitted. The optional *wkday* arguments are additional weekday names
to omit.
Consider this example:
OMIT 14 May 2009
SET a slide('2009-05-13', 5, "Sat", "Sun")
In this case, *a* 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:
OMIT 14 May 2009
SET a slide('2009-05-21', -5, "Sat", "Sun")
takes *a* back to 2009-05-13.
Now consider this example:
OMIT 14 May 2009
SET a slide('2009-05-07', 2, 7)
This sets *a* to \'2009-05-28\' because we skip ahead two weeks, not
counting a week where the day we land on happens to be omitted.
Contrast with this:
OMIT 13 May 2009
SET a slide('2009-05-07', 2, 7)
which sets *a* to \'2009-05-21\'. Although 2009-05-13 is omitted, we
don\'t \"land\" on it as we step forward in chunks of 7 days, so we
never see that it is omitted.
**soleq(i_which \[, dqi_start\])**
: The **soleq** function computes solstices and equinoxes. The *which*
parameter ranges from 0 to 3, and specifies which event we are
interested in: 0 is the March equinox; 1 is the June solstice; 2 is
the September equinox and 3 is the December solstice.
The optional *start* parameter can either be an integer specifying
the year of the event we are interested in, or a **DATE** or
**DATETIME** object; if the latter, then **soleq** returns the first
event on or after the date part of the *start* parameter (it ignores
the time component if *start* is a **DATETIME**.) If *start* is not
supplied, then it defaults to **today()**.
The return value of **soleq()** is a **DATETIME** object specifying
the date and time of the solstice or equinox in the local time zone.
It should be accurate to within 3 minutes or so in the worst case.
See the included file **\$SysInclude/seasons.rem** for examples of
how to use **soleq()**.
**stdout()**
: Returns a string representing where Remind\'s standard output is
going. The return values are one of the following: \"TTY\" if
standard-output is a terminal, \"BLOCKDEV\" if it is a block device
(very unlikely), \"CHARDEV\" if it is a character device (e.g.,
/dev/null), \"DIR\" if it is a directory (very unlikely), \"PIPE\"
if it is a pipe or FIFO, \"SYMLINK\" if it is a symlink (very
unlikely), \"SOCKET\" if it is a socket, or \"UNKNOWN\" if it could
not be determined.
The purpose of **stdout()** is mostly to distinguish between TTY and
non-TTY output; you may wish to change or disable colors if the
output is not going to a TTY.
**strlen(s_str)**
: Returns the length of *str* in bytes. If the length of *str* is too
large to represent as an integer, emits a \"Number too high\" error.
Note that **strlen** returns the number of *bytes* in the string,
not the number of *characters*. These numbers are the same for ASCII
strings, but may be different for UTF-8 strings.
**mbstrlen(str)**
: Similar to **strlen**, but returns the length of the string in
*characters* rather than *bytes* and is thus safe for use on
multi-byte strings.
**substr(s_str, i_start \[,i_end\])**
: Returns a **STRING** consisting of all bytes in *str* from *start*
up to and including *end*. Bytes are numbered from 1. If *end* is
not supplied, then it defaults to the length of *str*. Because
**substr** uses *byte* indexes rather than *character* indexes, it
should not be used on multi-byte strings.
**mbsubstr(s_str, i_start \[,i_end\])**
: Similar to **substr** but uses *character* indexes rather than
*byte* indexes, and is thus safe for use on multi-byte strings.
**sunrise(\[dq_date\])**
: Returns a **TIME** indicating the time of sunrise on the specified
*date* (default **today()**.) In high latitudes, there may be no
sunrise on a particular day, in which case **sunrise()** returns the
**INT** 0 if the sun never sets, or 1440 if it never rises.
**sunset(\[dq_date\])**
: Returns a **TIME** indicating the time of sunset on the specified
*date* (default **today()**.) In high latitudes, there may be no
sunset on a particular day, in which case **sunset()** returns the
**INT** 0 if the sun never rises, or 1440 if it never sets.
The functions **sunrise()** and **sunset()** are based on an
algorithm in \"Almanac for Computers for the year 1978\" by L. E.
Doggett, Nautical Almanac Office, USNO. They require the latitude
and longitude to be specified by setting the appropriate system
variables. (See \"System Variables\".) The sun functions should be
accurate to within about 4 minutes for latitudes lower than 60
degrees. The functions are available starting from version 03.00.07
of **Remind**.
**time(i_hr, i_min)**
: Creates a **TIME** with the hour and minute components specified by
*hr* and *min*.
**timepart(tq_datetime)**
: Returns a **TIME** object representing the time portion of
*datetime*.
**timezone(\[dq_datetime\])**
: Returns a string representing the local time zone name of the given
**DATETIME**. If no argument is supplied, **Remind** uses the value
of **current()**. If a **DATE** rather than **DATETIME** is
supplied, **Remind** uses a time part of 00:00.
**today()**
: Returns **Remind**\'s notion of \"today.\" This may be the actual
system date, or a date supplied on the command line, or the date of
the calendar entry currently being computed.
**trig(s_1 \[,s_2, \...\])**
: For each string argument s\_*n*, **trig** evaluates s\_*n* as if it
were a REM or IFTRIG trigger specification. If the trigger would
trigger today, then the trigger date is returned and no further
triggers are evaluated. If none of the triggers would trigger today,
then the zero date 1990-01-01 is returned.
**trig** also has a zero-argument form; this returns the trigger
date of the *most recent* **trig** function that returned a non-zero
trigger date.
**trig** can be used to make more sophisticated versions of
**IFTRIG**. For example, if you have meetings every Monday in June
and July, and you want warnings 3 days in advance, you could use:
REM [trig("Mon Jun +3", "Mon July +3")] +3 MSG Meeting %b
NOTE: We need to repeat the +3 delta outside of the **trig**
function for advance warning to work properly. This is because
**trig** returns a date constant (the trigger date) and the REM
command does not know the details of **trig**\'s arguments.
Note that because **Remind** has short-circuit logical operators,
something like:
SET a trig("Mon +7") || trig("Fri +7")
would set the value of trig() to the date of the following Monday.
Because trig(\"Mon +7\") always returns true, the logical-OR
operator does not bother evaluating trig(\"Fri +7\") which therefore
does not set **trig()**.
**Important Note**: Because **trig()** always returns an absolute
date, it will **not** work properly with a **SATISFY** clause.
Consider this reminder:
REM [trig("Mar", "Apr")] SATISFY [$Td == 15] MSG 15 Mar or April
If we run **Remind** on 5 March 2022, we might expect the trigger
date to be calculated as 15 March 2022\... but that\'s not what
happens. Instead, the **trig** function is evaluated first, and it
returns 2022-03-05. So as far as **Remind** is concerned, the REM
statement becomes:
REM 2022-03-05 SATISFY [$Td == 15] MSG 15 Mar or April
and the SATISFY expression is never true. So: *Do not mix* trig()
and SATISFY.
**trigdate()**
: Returns the calculated trigger date of the last **REM** or
**IFTRIG** command. If used in the *body* of a **REM** command,
returns that command\'s trigger date. If the most recent **REM**
command did not yield a computable trigger date, returns the integer
0.
**trigdatetime()**
: Similar to trigdate(), but returns a **DATETIME** if the most recent
triggerable **REM** command had an **AT** clause. If there was no
**AT** clause, returns a **DATE**. If no trigger could be computed,
returns the integer 0. See \"MULTI-DAY EVENTS\" for more
information.
**trigeventstart()**
: Returns a **DATETIME** representing the start of the most recent
triggerable **REM** command that had an **AT** clause. For events
without a **DURATION** or that do not span multiple days, returns
the same as **trigdatetime()**. If the **REM** command did not have
an **AT** clause, returns the integer -1 (and differs from
**trigdatetime()** in this respect.) See \"MULTI-DAY EVENTS\" for
more information.
**trigeventstarttz()**
: Similar to **trigeventstart()** but returns the DATETIME in the time
zone specified by a TZ clause, if one was present. If no TZ clause
was present, returns the same value as **trigeventstart()**.
**trigeventduration()**
: Returns a **TIME** representing the duration of the most recent
triggerable **REM** command that had an **AT** and a **DURATION**
clause. If the event does not span multiple days, returns the same
thing as **trigduration()**. If the **REM** command lacked an **AT**
or **DURATION** clause, returns -1. See \"MULTI-DAY EVENTS\" for
more information.
**trigback()**
: Returns the \"back\" amount of the last **REM** or **IFTRIG**
command. Returns a positive integer N if the \"back\" is of the form
-N, or a negative integer if it is of the form \--N. If there is no
\"back\", then returns 0.
**trigbase()**
: Returns the \"base\" date of the last **REM** or **IFTRIG** command.
If the trigger specification includes *all three* of day, month and
year, then the base date is the date formed from those components.
If the trigger specification lacks one of those components, then 0
is returned.
Here is an example of how **trigbase()** might be used:
REM 2025-05-05 *7 UNTIL 2025-05-26 \
MSG Meeting: week #[(trigdate() - trigbase())/trigrep()+1]
On 2025-05-05, it would print: \"Meeting: week #1\". On 2025-05-12,
it would print: \"Meeting: week #2\" and so on.
**trigdelta()**
: Returns the \"delta\" amount of the last **REM** or **IFTRIG**
command. Returns a positive integer N if the \"delta\" is of the
form +N, or a negative integer if it is of the form ++N. If there is
no \"delta\", then returns 0.
**trigtimedelta()**
: Similar to **trigdelta()**, but returns the delta used in the **AT**
clause of a timed reminder.
**trigrep()**
: Returns the \"repeat\" amount of the last **REM** or **IFTRIG**
command. Returns a positive integer N if the \"repeat\" is of the
form \*N. If there is no \"repeat\", then returns 0.
**trigtimerep()**
: Similar to **trigrep()**, but returns the repeat used in the **AT**
clause of a timed reminder.
**trigtz()**
: If a **TZ** clause was used in the last **REM** or **IFTRIG**
command, returns the time zone name. Otherwise returns the empty
string.
**trigduration()**
: Returns (as a TIME type) the **DURATION** parameter of a timed
reminder. If there is no **DURATION** parameter, returns the integer
-1. See \"MULTI-DAY EVENTS\" for more information.
**trigpriority()**
: Returns the **PRIORITY** of the last **REM** or **IFTRIG** command.
**triguntil()**
: Returns (as a **DATE** type) the **UNTIL** parameter of the last
**REM** or **IFTRIG** command. If there was no **UNTIL** parameter,
returns the integer -1. If there is a **THROUGH** parameter, that
will be returned by **triguntil()** since \"THROUGH yyyy-mm-dd\" is
simply syntactic sugar for \"\*1 UNTIL yyyy-mm-dd\".
**trigscanfrom()**
: Returns (as a **DATE** type) the **SCANFROM** parameter of the last
**REM** or **IFTRIG** command. If there was no **SCANFROM**
parameter, returns the integer -1. Note that **FROM** and
**SCANFROM** interact; a reminder that has a \"FROM yyyy-mm-dd\"
parameter will act as if it has a **SCANFROM** parameter whose value
is the maximum of \"yyyy-mm-dd\" and today.
**trigfrom()**
: Returns (as a **DATE** type) the **FROM** parameter of the last
**REM** or **IFTRIG** command. If there was no **FROM** parameter,
returns the integer -1.
**triginfo(s_header)**
: Returns a **STRING** that is the INFO item associated with the
header *header*. The header should *not* contain a colon. Header
name comparisons are case-insensitive.
For example, the following will assign \"At home\" to the variable a
and the empty string to variable b:
REM INFO "Location: At home" MSG test
SET a triginfo("location")
SET b triginfo("no_such_header")
**trigistodo()**
: Returns 1 if the last REM command was a **TODO** type or 0 if not.
**trigcompletethrough()**
: Returns a **DATE** object that is the COMPLETE-THROUGH date of the
most recent **REM** command. If there was no COMPLETE-THROUGH date,
returns the **INT** 0.
**trigmaxoverdue()**
: Returns an **INT** that is the MAX-OVERDUE value of the most recent
**REM** command. If there was no MAX-OVERDUE clause, returns -1.
**trigger(d_date \[,t_time \[,i_utcflag\]\]) or trigger(q_datetime \[,i_utcflag\])**
: Returns a string suitable for use in a **REM** command or a
**SCANFROM** or UNTIL clause, allowing you to calculate trigger
dates in advance. Note that in earlier versions of **Remind**,
**trigger** was required to convert a date into something the
**REM** command could consume. However, in this version of
**Remind**, you can omit it. Normally, the *date* and *time* are the
local date and time; however, if *utcflag* is non-zero, the *date*
and *time* are interpreted as UTC times, and are converted to local
time. Examples:
trigger(\'1993/04/01\')
returns \"1 April 1993\",
trigger(\'1994/08/09\', 12:33)
returns \"9 August 1994 AT 12:33\", as does:
trigger(\'1994/08/09@12:33\').
Finally:
trigger(\'1994/12/01\', 03:00, 1)
returns \"30 November 1994 AT 22:00\" for EST, which is 5 hours
behind UTC. The value for your time zone may differ.
**trigger()** will *never* return a date earlier than \"1 January
1990\" even if the UTC flag dictates that it should. So do not use
it for reminders before about 2 January 1990 in your local time
zone. I do not anticipate this restriction being a real problem.
**trigtags()**
: Returns a comma-separated list of the TAGs associated with the most
recent **REM** command that was triggered. Returns the empty string
if there were no TAGs. If there are multiple tags, they are each
separated by a single comma, not a comma and a space.
**trigtime()**
: Returns the time of the last **REM** command with an **AT** clause
*in the system default time zone*. If the last **REM** did not have
an **AT** clause, returns the integer 0. If a **REM** command has an
**AT** clause with a **DURATION**, then you can compute the end time
as **trigtime() + trigduration()**.
**trigtimetz()**
: Similar to **trigtime()** but returns the time in the time zone
specified by a TZ clause, if one was present. If no TZ clause was
present, returns the same value as **trigtime()**.
**trigvalid()**
: Returns 1 if the value returned by **trigdate()** is valid for the
most recent **REM** command, or 0 otherwise. Sometimes **REM**
commands cannot calculate a trigger date. For example, the following
**REM** command can never be triggered:
```{=html}
<!-- -->
```
REM Mon OMIT Mon SKIP MSG Impossible!
**typeof(x_arg)**
: Returns \"STRING\", \"INT\", \"DATE\", \"TIME\" or \"DATETIME\",
depending on the type of *arg*.
**tzconvert(q_datetime, s_srczone \[,s_dstzone\])**
: Converts **datetime** from the time zone named by **srczone** to the
time zone named by **dstzone**. If **srczone** is the empty string,
then the default system time zone is used as the source zone. If
**dstzone** is omitted or is the empty string, the default system
time zone is used as the destination zone. The return value is a
DATETIME. Time zone names are system-dependent; consult your
operating system for legal values. Here is an example:
tzconvert('2007-07-08@01:14', "Canada/Eastern", "Canada/Pacific")
returns
2007-07-07@22:14
If your system includes the directory /usr/share/zoneinfo,
**Remind** will warn you if you use an invalid time zone name for
**srczone** or **dstzone**. To suppress these warnings, add a \"!\"
to the beginning of the time zone name.
```{=html}
<!-- -->
```
**upper(s_string)**
: Returns a **STRING** with all lower-case characters in *string*
converted to upper-case.
**utctolocal(q_datetime)**
: Given a **DATETIME** object interpreted in UTC, return a
**DATETIME** object that expresses the same time in the local time
zone.
**value(s_varname \[,x_default\])**
: Returns the value of the specified variable. For example,
value(\"X\"+\"Y\") returns the value of variable XY, if it is
defined. If XY is not defined, an error results.
However, if you supply a second argument, it is returned if the
*varname* is not defined. The expression value(\"XY\", 0) will
return 0 if XY is not defined, and the value of XY if it is defined.
Note that **value** evaluates the second argument lazily; it is
*not* evaluated if *varname* is defined.
**version()**
: Returns a string specifying the version of **Remind**. For version
06.02.01, returns \"06.02.01\". It is guaranteed that as new
versions of **Remind** are released, the value returned by
**version()** will strictly increase, according to the rules for
string ordering.
**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 **today()**. If one argument
*date* is supplied, then returns the ISO 8601 week number for that
date. If two arguments are supplied, then *wkstart* must range from
0 to 6, and represents the first day of the week (with 0 being
Sunday and 6 being Saturday.). If *wkstart* is not supplied, then it
defaults to 1. If the third argument *daystart* is supplied, then it
specifies when Week 1 starts. If *daystart* is less than or equal to
7, then Week 1 starts on the first *wkstart* on or after January
*daystart*. Otherwise, Week 1 starts on the first *wkstart* on or
after December *daystart*. If omitted, *daystart* defaults to 29
(following the ISO 8601 definition.)
**wkday(dqi_arg)**
: If *arg* is a **DATE** or **DATETIME**, returns a string
representing the day of the week of the date. If *arg* is an **INT**
from 0 to 6, returns the corresponding weekday (\"Sunday\" to
\"Saturday\").
**wkdaynum(dq_date)** or **wkdaynum(s_str)**
: Returns a number from 0 to 6 representing the day-of-week of the
specified *date*. (0 represents Sunday, and 6 represents Saturday.)
If a **STRING** is supplied, then if *str* is a valid weekday name
(or minimum 3-character abbreviation thereof) then the corresponding
weekday number is returned. If *str* is not a valid weekday name,
then an error occurs.
**year(dq_date)**
: Returns a **INT** that is the year component of *date*.
# MACHINES WITH A 32-BIT TIME_T TYPE
Internally, the standard C library represents times as a **time_t**
type. This is a signed integer type that counts seconds since midnight,
1 January 1970 UTC. If the **time_t** type is only 32 bits in size, then
the C library cannot represent times after 19 January 2038 at 03:14:07
UTC.
To work around this limitation, **Remind** will \"fold\" years greater
than 2037 to a smaller year that begins on the same day and has the same
number of days. This results in a year that\'s very likely to have the
same daylight saving rules as the original year, unless the rules have
changed in the interim (in which case the rule change could not even be
represented on a 32-bit machine, so it\'s moot.)
**Remind** then does UTC-to-local or local-to-UTC conversions with the
folded year, and then post-conversion corrects it back. This should give
correct results for astronomical functions and conversions between local
and UTC time, providing the daylight saving time rules have not changed
between the folded year and the original year.
Note that the \$FoldYear system variable is no longer that useful;
**Remind** *always* folds years if it\'s necessary on a 32-bit system.
You can set \$FoldYear to 1 to force **Remind** to fold years even on a
64-bit system, but that\'s useful only for testing and not for
production.
# MULTI-DAY EVENTS
If you specify a start time with **AT** and a duration with
**DURATION**, you can create events that span multiple days. Consider
these two REM statements:
REM 1991-02-13 AT 16:00 DURATION 72:00 MSG 72-hour event
REM 1991-02-13 THROUGH 1991-02-16 AT 16:00 MSG Four events
The first statement creates a *single* event that starts on 13 February
1991 at 16:00 and runs through 16 February 1991 at 16:00
The second statements creates *four separate* events that start at 16:00
on 13, 14, 15 and 16 February 1991 and have indefinite duration.
**Remind** handles multi-day events specially. These are the rules:
On the *first* day of a multi-day event, **trigdatetime()** will return
the starting date and time of the event, and **trigduration()** will
return the original DURATION.
On each *subsequent* day of a multi-day event, **trigdatetime()** will
return midnight on the day in question, and **trigduration()** will
return the *remaining* duration. Consider this example:
#!/bin/sh
remind - 12 feb 1991 '*6' <<'EOF'
BANNER %
REM 1991-02-13 AT 16:00 DURATION 72:00 SATISFY 1
set a trigdatetime()
set b trigduration()
set c trigeventstart()
set d trigeventduration()
MSG now=[today()] dt=[a] dur=[b] estart=[c] edur=[d]%
EOF
The output is:
now=1991-02-12 dt=1991-02-13@16:00 dur=72:00 estart=1991-02-13@16:00 edur=72:00
now=1991-02-13 dt=1991-02-13@16:00 dur=72:00 estart=1991-02-13@16:00 edur=72:00
now=1991-02-14 dt=1991-02-14@00:00 dur=64:00 estart=1991-02-13@16:00 edur=72:00
now=1991-02-15 dt=1991-02-15@00:00 dur=40:00 estart=1991-02-13@16:00 edur=72:00
now=1991-02-16 dt=1991-02-16@00:00 dur=16:00 estart=1991-02-13@16:00 edur=72:00
now=1991-02-17 dt=1991-02-13@16:00 dur=72:00 estart=-1 edur=-1
As you see, the **trigdatetime()** and **trigduration()** functions
return the start time and duration of the *remaining* portion of a
multi-day event, whereas **trigeventstart** and **trigeventduration**
always return the original start and duration of the multi-day event.
Note also that the return value for expired reminders is not reliable;
the fact that **trigeventstart** and **trigeventduration** return -1 in
that case is an implementation artifact.
**SELF-OVERLAPPING EVENTS**
A multi-day event has the possibility of \"overlapping itself\". When
this happens, **Remind** prefers the *later* event (only one copy of an
event is ever triggered for a given date.) Consider this example:
#!/bin/sh
remind - '*5' 10 Feb 1991 <<'EOF'
BANNER %
REM MON at 0:00 DURATION 192:0 MSG [today()] [trigeventstart()] [trigduration()]%
EOF
The output is:
1991-02-10 1991-02-04@00:00 48:00
1991-02-11 1991-02-11@00:00 192:00
1991-02-12 1991-02-11@00:00 168:00
1991-02-13 1991-02-11@00:00 144:00
1991-02-14 1991-02-11@00:00 120:00
Although the event from 1991-02-04 still has 24 hours left on
1991-02-11, the fresh occurrence on 1991-02-11 takes precedences and is
the one that is triggered.
I do not recommend constructing self-overlapping multi-day events.
# EXPRESSION PASTING
An extremely powerful feature of **Remind** is its macro capability, or
\"expression pasting.\"
In almost any situation where **Remind** is not expecting an expression,
you can \"paste\" an expression in. To do this, surround the expression
with square brackets. For example:
REM [mydate] MSG foo
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.
If you want a literal \"\[\" character for some reason, simply use
\"\[\[\". For example:
REM MSG Here are [[square] brackets!
A formal description of this is: When **Remind** encounters a
\"pasted-in\" expression, it evaluates the expression, and coerces the
result to a **STRING**. It then substitutes the string for the pasted-in
expression, and continues parsing. Note, however, that expressions are
evaluated only once, not recursively. Thus, writing:
["[a+b]"]
causes **Remind** to read the token \"\[a+b\]\". It does not interpret
this as a pasted-in expression.
You can use expression pasting almost anywhere. However, there are a few
exceptions:
o
: If **Remind** is expecting an expression, as in the **SET** command,
or the **IF** command, you should **not** include square brackets.
For example, use:
```{=html}
<!-- -->
```
SET a 4+5
and not:
SET a [4+5]
o
: You cannot use expression pasting for the first token on a line. For
example, the following will not work:
```{=html}
<!-- -->
```
["SET"] a 1
> This restriction is because **Remind** must be able to unambiguously
> determine the first token of a line for the flow-control commands (to
> be discussed later.)
>
> In fact, if **Remind** cannot determine the first token on a line, it
> assumes that it is a **REM** command. If expression-pasting is used,
> **Remind** assumes it is a **REM** command. Thus, the following three
> commands are equivalent:
>
> REM 12 Nov 1993 AT 13:05 MSG BOO!
> 12 Nov 1993 AT 13:05 MSG BOO!
> [12] ["Nov " + 1993] AT [12:05+60] MSG BOO!
o
: You cannot use expression-pasting to determine the type (**MSG**,
**CAL**, etc.) of a **REM** command. You can paste expressions
before and after the **MSG**, etc. keywords, but cannot do something
like this:
REM ["12 Nov 1993 AT 13:05 " + "MSG" + " BOO!"]
However, as an escape hatch, the sequence **SPECIAL** *type* means
the same thing as just *type* where *type* is one of MSG, MSF, RUN,
CAL, PS and PSFILE. This lets you do something like this:
SET type "MSG"
REM 12 Nov 2024 SPECIAL [type] Hello
You can use this to control the types of your reminders based on
variables you set, how **Remind** is invoked, etc.
**COMMON PITFALLS WITH EXPRESSION PASTING**
Remember that extra spaces are not inserted when an expression is
pasted. Thus, something like:
REM[expr]MSG[expr]
will probably fail.
If you use an expression to calculate a *delta* or *back*, ensure that
the result is a positive number. Something like:
REM +[mydelta] Nov 12 1993 MSG foo
will fail if *mydelta* happens to be negative.
# FLOW CONTROL COMMANDS
**Remind** has commands that control the flow of a reminder script.
Normally, reminder scripts are processed sequentially. However, **IF**
and related commands allow you to process files conditionally, and skip
sections that you don\'t want interpreted.
**THE IF COMMAND**
The **IF** command has the following form:
IF expr
t-command
t-command...
ELSE
f-command
f-command...
ENDIF
Note that the commands are shown indented for clarity. Also, the
**ELSE** portion can be omitted. **IF** commands can be nested up to a
depth of 64, across *all* levels of INCLUDE.
If the *expr* evaluates to a non-zero **INT**, a **DATE** that is not
1990-01-01, a **TIME** that is not 00:00, a **DATETIME** that is not
1990-01-01@00:00, or a non-null **STRING**, then the **IF** portion is
considered true, and the *t-commands* are executed. If *expr* evaluates
to zero or null, then the *f-commands* (if the **ELSE** portion is
present) are executed.
Examples:
IF defined("want_hols")
INCLUDE /usr/share/remind/holidays
ENDIF
IF today() > '1992/2/10'
set missed_ap "You missed it!"
ELSE
set missed_ap "Still have time..."
ENDIF
**THE IFTRIG COMMAND**
The **IFTRIG** command is similar to an **IF** command, except that it
computes a trigger (as in the **REM** command), and evaluates to true if
a corresponding **REM** command would trigger. Examples:
IFTRIG 1 Nov
; Executed on 1 Nov
ELSE
; Executed except on 1 Nov
ENDIF
IFTRIG 1 -1 OMIT Sat Sun +4
; Executed on last working day of month,
; and the 4 working days preceding it
ELSE
; Executed except on above days
ENDIF
Note that the **IFTRIG** command computes a trigger date, which can be
retrieved with the **trigdate()** function. You can use all of the
normal trigger components, such as **UNTIL**, *delta*, etc. in the
**IFTRIG** command. However, you cannot use a type specifier such as
**CAL**, **MSG** or **SATISFY**; attempting to do so yields a parse
error.
# USER-DEFINED FUNCTIONS
In addition to the built-in functions, **Remind** allows you to define
your own functions. The **FSET** command does this for you:
**FSET** *fname*(*args*) *expr*
*Fname* is the name of the function, and follows the convention for
naming variables. *Args* is a comma-separated list of arguments, and
*expr* is an expression. *expr* is not evaluated at the time the
function is defined; instead, it is evaluated each time the function is
called. *Args* can be empty, in which case you define a function taking
no parameters. Here are some examples:
FSET double(x) 2*x
FSET yeardiff(date1, date2) year(date1) - year(date2)
FSET since(x) ord($Ty - x)
The last function is useful in birthday reminders. For example:
REM 1 Nov +12 MSG Dean's [since(1984)] birthday is %b.
Dean was born in 1984. The above example, on 1 November 1992, would
print:
Dean's 8th birthday is today.
Similarly, the function is useful in anniversary reminders. For example:
REM 4 June MSG [since(1989)] anniversary of the Tienanmen Square massacre
Notes:
o
: If you access a variable in *expr* that is not in the list of
arguments, the global value (if any) is used.
o
: Function and parameter names are significant to 64 characters.
o
: The **value()** function *always* accesses the global value of a
variable, even if it has the same name as an argument. For example:
fset func(x) value("x")
set x 1
set y func(5)
The above sequence sets y to 1, which is the global value of x.
o
: User-defined functions may call other functions, including other
user-defined functions. Recursive calls are allowed, but they must
terminate (for example, by using a short-circuit operator or
function that breaks the recursion) or an error will result after a
certain maximum number of recursive calls (by default, 1000.)
o
: If a user-defined function has the same name as a built-in function,
it is ignored and the built-in function is used. To prevent
conflicts with future versions of **Remind** (which may define more
built-in functions), you may wish to name all user-defined functions
beginning with an underscore.
o
: If a user-defined function is defined in a context where **RUN** is
disabled, then whenever that function is called, **RUN** will be
disabled during its evaluation, *even if* it is called from a
context where **RUN** is enabled.
To delete a user-defined function, use **FUNSET**. This takes a
space-separated list of user-defined functions to delete. For example,
after the command:
FUNSET myfunc1 otherfunc thirdfunc
it is guaranteed that no user-defined functions named myfunc1, otherfunc
or thirdfunc will exist. **Remind** does not issue an error if you try
to **FUNSET** a nonexistent user-defined function; it simply does
nothing in that case.
You can rename a user-defined function with **FRENAME**. This takes two
names: An old name and a new name. Consider this command:
FRENAME func_a func_b
If *func_a* does not exist, the command unsets *func_b* if it is
defined. However, if *func_a* exists, then it is renamed to *func_b*,
and *func_a* is no longer defined. If *func_b* was defined prior to the
**FRENAME** command, then that old definition is lost.
If either argument to the **FRENAME** command is the name of a built-in
function, the command fails with an error message and does nothing.
If you define a user-defined function and then later on redefine it,
**Remind** will issue a warning. If you do not want this warning, then
use **FUNSET** to remove the existing definition before you redefine the
function. Alternatively, you can use a \"-\" token before the function
name to suppress \"redefined function\" warnings, as in the following
example:
FSET - f(x) 2*x
# You must have space before and after the "-"
# This will NOT work:
# FSET -f(x) 2*x
# SAVING AND RESTORING FUNCTIONS
Occasionally, it is useful to redefine a function for a specific block
of reminders, but to restore its original definition at the end of that
block. Just as with variables, functions can be pushed onto and popped
off an internal stack. Here is an example:
PUSH-FUNCS msgprefix
FSET msgprefix(x) "My new prefix: "
INCLUDE block_of_reminders.rem
POP-FUNCS
The file **block_of_reminders.rem** would be executed with the
**msgprefix** function defined above. After the POP-FUNCS **msgprefix**
would be restored to its previous definition if it had one, or simply
unset if it was not previously defined.
The command PUSH-FUNCS takes a space-separated list of function names.
All of the named user-defined functions will be saved to an internal
stack. You can even push names that are not defined as any function.
After a function name has been pushed, **Remind** will not issue a
warning if you redefine it, because presumably the purpose of pushing it
in the first place is to redefine it.
The command POP-FUNCS restores the definitions of all the user-defined
functions in the corresponding PUSH-FUNCS command. If undefined
functions were pushed onto the stack, then POP-FUNCS makes those
functions undefined again. Here\'s one more example:
FUNSET a
FSET b(x) 2*x
REM MSG [b(3)] # Outputs 6
PUSH-FUNCS a b
FSET a(x) 22*x
FSET b(x) 3*x
REM MSG [a(3)] [b(3)] # Outputs 66 9
POP-FUNCS
REM MSG [a(3)] # Undefined function "a"
REM MSG [b(3)] # Outputs 6
# PRECISE SCHEDULING
The **WARN** keyword allows precise control over advance warning in a
more flexible manner than the *delta* mechanism. It should be followed
by the name of a user-defined function, *warn_function*.
If a *warn_function* is supplied, then it must take one argument of type
**INT**. **Remind** ignores any delta, and instead calls *warn_function*
successively with the arguments 1, 2, 3, \...
*Warn_function*\'s return value *n* is interpreted as follows:
o
: If *n* is positive, then the reminder is triggered exactly *n* days
before its trigger date.
o
: If *n* is negative, then it is triggered *n* days before its trigger
date, *not counting* **OMIT**ted days.
As an example, suppose you wish to be warned of American Independence
Day 5, 3, and 1 days in advance. You could use this:
FSET _wfun(x) choose(x, 5, 3, 1, 0)
REM 4 July WARN _wfun MSG American Independence Day is %b.
**NOTES**
1
: If an error occurs during the evaluation of *warn_function*, then
**Remind** stops calling it and simply issues the reminder on its
trigger date.
2
: If the absolute-values of the return values of *warn_function* are
not monotonically decreasing, **Remind** stops calling it and issues
the reminder on its trigger date.
3
: *Warn_function* should (as a matter of good style) return 0 as the
final value in its sequence of return values. However, a reminder
will *always* be triggered on its trigger date, regardless of what
*warn_function* does.
Similarly to **WARN**, the **SCHED** keyword allows precise control over
the scheduling of timed reminders. It should be followed by the name of
a user-defined function, *sched_function*.
If a scheduling function is supplied, then it must take one argument of
type **INT**. Rather than using the **AT** time, time *delta*, and time
*repeat*, **Remind** calls the scheduling function to determine when to
trigger the reminder. The first time the reminder is queued, the
scheduling function is called with an argument of 1. Each time the
reminder is triggered, it is re-scheduled by calling the scheduling
function again. On each call, the argument is incremented by one.
The return value of the scheduling function must be an **INT** or a
**TIME**. If the return value is a **TIME**, then the reminder is
re-queued to trigger at that time. If it is a positive integer *n*, then
the reminder is re-queued to trigger at the previous trigger time plus
*n* minutes. Finally, if it is a negative integer or zero, then the
reminder is re-queued to trigger *n* minutes before the **AT** time.
Note that there must be an **AT** clause for the **SCHED** clause to do
anything.
Here\'s an example:
FSET _sfun(x) choose(x, -60, 30, 15, 10, 3, 1, 1, 1, 1, 0)
REM AT 13:00 SCHED _sfun MSG foo
The reminder would first be triggered at 13:00-60 minutes, or at 12:00.
It would next be triggered 30 minutes later, at 12:30. Then, it would be
triggered at 12:45, 12:55, 12:58, 12:59, 13:00, 13:01 and 13:02.
**NOTES**
1
: If an error occurs during the evaluation of *sched_func*, then
**Remind** reverts to using the **AT** time and the *delta* and
*repeat* values, and never calls *sched_func* again.
2
: If processing *sched_func* yields a time earlier than the current
system time, it is repeatedly called with increasing argument until
it yields a value greater than or equal to the current time.
However, if the sequence of values calculated during the repetition
is not strictly increasing, then **Remind** reverts to the default
behaviour and never calls *sched_func* again.
3
: It is quite possible using *sched_func* to keep triggering a
reminder even after the **AT**-time. However, it is not possible to
reschedule a reminder past midnight - no crossing of date boundaries
is allowed. Also, it is quite possible to **not** trigger a reminder
on the **AT** time when you use a scheduling function. However, if
your scheduling function is terminated (for reasons 1 and 2) before
the **AT** time of the reminder, it *will* be triggered at the
**AT** time, because normal processing takes over.
4
: Your scheduling functions should (as a matter of good style) return
0 when no more scheduling is required. See the example.
5
: All scheduling functions are evaluated *after* the entire Remind
script has been read in. So whatever function definitions are in
effect at the end of the script are used.
# THE SATISFY CLAUSE
The form of **REM** that uses **SATISFY** is as follows:
**REM** *trigger* **SATISFY** *expr*
The way this works is as follows: **Remind** first calculates a trigger
date, in the normal fashion. Next, it sets **trigdate()** to the
calculated trigger date. It then evaluates *expr*. If the result is not
the null string or zero, processing ends. Otherwise, **Remind** computes
the next trigger date, and re-tests *expr*. This iteration continues
until *expr* evaluates to non-zero or non-null, or until the iteration
limit specified with the **-x** command-line option is reached.
If *expr* is not satisfied, then **trigvalid()** is set to 0 and the
error message \"Can\'t compute trigger\" is issued. Otherwise,
**trigvalid()** is set to 1.
This is really useful only if *expr* involves a call to the
**trigdate()** or related functions or system variables; otherwise,
*expr* will not change as **Remind** iterates. In fact, if *expr* is not
a constant and does not call **trigdate()** or related functions or
system variables, then **Remind** will issue a warning.
An example of the usefulness of **SATISFY**: Suppose you wish to be
warned of every Friday the 13th. Your first attempt may be:
# WRONG!
REM Fri 13 +2 MSG Friday the 13th is %b.
But this won\'t work. This reminder triggers on the first Friday on or
after the 13th of each month. The way to do it is with a more
complicated sequence:
REM 13 SATISFY wkdaynum(trigdate()) == 5
IF trigvalid()
REM [trigdate()] +2 MSG \
Friday the 13th is %b.
ENDIF
You can write the REM statement a little more concisely:
REM 13 SATISFY $Tw == 5
Let\'s see how this works. The **SATISFY** 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 to set up the next reminder.
We could also have written:
REM Fri SATISFY day(trigdate()) == 13
but this would result in more iterations, since \"Fridays\" occur more
often than \"13ths of the month.\"
Here is another example: Suppose you want to be reminded of something on
the 15th of January, April, July, and October. You could make four
separate reminders, or you could use:
REM 15 SATISFY [isany($Tm, 1, 4, 7, 10)] MSG 15th Reminder!
This technique of using one **REM** command to calculate a trigger date
to be used by another command is quite powerful. For example, suppose
you wanted to OMIT Labour day, which is the first Monday in September.
You could use:
# Note: SATISFY 1 is an idiom for "do nothing"
REM Mon 1 Sept SATISFY 1
OMIT [trigdate()]
**CAVEAT:** This *only* omits the *next* Labour Day, not all Labour Days
in the future. This could cause strange results, as the **OMIT** context
can change depending on the current date. For example, if you use the
following command after the above commands:
REM Mon AFTER msg hello
the result will not be as you expect. Consider producing a calendar for
September, 1992. Labour Day was on Monday, 7 September, 1992. However,
when **Remind** gets around to calculating the trigger for Tuesday, 8
September, 1992, the **OMIT** command will now be omitting Labour Day
for 1993, and the \"Mon AFTER\" command will not be triggered. (But see
the description of **SCANFROM** in the section \"DETAILS ABOUT TRIGGER
COMPUTATION.\")
It is probably best to stay away from computing **OMIT** trigger dates
unless you keep these pitfalls in mind.
For versions of **Remind** starting from 03.00.07, you can include a
**MSG**, **RUN**, etc. clause in a **SATISFY** clause as follows:
REM trigger_stuff SATISFY [expr] MSG body
Note that for this case only, the *expr* after **SATISFY** *must* be
enclosed in square brackets. It must come after all the other components
of the trigger, and immediately before the **MSG**, **RUN**, etc.
keyword. If *expr* cannot be satisfied, then the reminder is not
triggered.
Thus, the \"Friday the 13th\" example can be expressed more compactly
as:
REM 13 +2 SATISFY [$Tw == 5] MSG Friday the 13th is %b.
And you can trigger a reminder on Mondays, Wednesdays and Thursdays
occurring on odd-numbered days of the month with the following:
REM Mon Wed Thu SATISFY [$Td %2 ] MSG Here it is!!!
Note that **SATISFY** and **OMITFUNC** can often be used to solve the
same problem, though in different ways. Sometimes a **SATISFY** is
cleaner and sometimes an **OMITFUNC**; experiment and use whichever
seems clearer.
# POSSIBLY-UNCOMPUTABLE TRIGGERS
Occasionally, you may wish to suppress the \"Can\'t compute trigger\"
warnings for reminders for which a trigger date cannot be computed. For
example, the following reminder is triggered on a Monday that is not a
holiday if the following Tuesday is a holiday:
REM Mon SKIP SATISFY [isomitted($T+1)] MSG Work between holidays
However, if there are no Mondays after today\'s date that satisfy the
condition, **Remind** will print the \"Can\'t compute trigger\" error.
To suppress this, use the **MAYBE-UNCOMPUTABLE** keyword:
REM MAYBE-UNCOMPUTABLE Mon SKIP SATISFY [isomitted($T+1)] MSG Work between holidays
It\'s almost never appropriate to use **MAYBE-UNCOMPUTABLE**, but it is
provided for those rare occasions when it makes sense. If you use
**MAYBE-UNCOMPUTABLE** inside the **evaltrig()** function, then
untriggerable triggers return -1. For example:
SET a evaltrig("MAYBE-UNCOMPUTABLE Mon SKIP OMIT Mon")
will set a to -1.
# DEBUGGING REMINDER SCRIPTS
Although the command-line **-d** option is useful for debugging, it is
often overkill. For example, if you turn on the **-dx** option for a
reminder file with many complex expressions, you\'ll get a huge amount
of output. The **DEBUG** command allows you to control the debugging
flags under program control. The format is:
**DEBUG** \[+*flagson*\] \[-*flagsoff*\]
*Flagson* and *flagsoff* consist of strings of the characters
\"shextvlfqnu\" that correspond to the debugging options discussed in
the command-line options section. If preceded with a \"+\", the
corresponding group of debugging options is switched on. Otherwise, they
are switched off. For example, you could use this sequence to debug a
complicated expression:
DEBUG +x
set a very_complex_expression(many_args)
DEBUG -x
**THE DUMPVARS COMMAND**
The command **DUMPVARS** displays the values of variables in memory. Its
format is:
**DUMPVARS** \[**-c**\] \[*var*\...\]
If you supply a space-separated list of variable names, the
corresponding variables are displayed. If you do not supply a list of
variables, then all variables in memory are displayed. To dump a system
variable, put its name in the list of variables to dump. If you put a
lone dollar sign in the list of variables to dump, then all system
variables will be dumped.
If you supply the **-c** flag, then any variable determined to be
constant will have its value followed by \"\<const\>\"
**THE ERRMSG COMMAND**
The **ERRMSG** command has the following format:
**ERRMSG** *body*
The *body* is passed through the substitution filter (with an implicit
trigger date of **today()**) and printed to the error output stream.
Example:
IF !defined("critical_var")
ERRMSG You must supply a value for "critical_var"
EXIT
ENDIF
**THE EXIT COMMAND**
The above example also shows the use of the **EXIT** command. This
causes an unconditional exit from script processing. Any queued timed
reminders are discarded. If you are in calendar mode (described next),
then the calendar processing is aborted.
If you supply an **INT**-type expression after the **EXIT** command, it
is returned to the calling program as the exit status. Otherwise, an
exit status of 99 is returned.
**THE FLUSH COMMAND**
This command simply consists of the word **FLUSH** on a line by itself.
The command flushes the standard output and standard error streams used
by **Remind**. This is not terribly useful to most people, but may be
useful if you run **Remind** as a subprocess of another program, and
want to use pipes for communication.
# AGENDA MODE JSON OUTPUT
If you supply the **\--json** argument, then Remind outputs JSON instead
of the normal text output. The JSON output consists of a single JSON
array of zero or more objects. There are three possible types of objects
in the array:
**banner**
: The **banner** object, if present, will be the first object in the
array. There will be at most one **banner** object. It contains a
single key, **banner**, whose value is the banner that **Remind**
would normally print in Agenda Mode.
**noreminders**
: The **noreminders** object, if present, will be the final object in
the array. There will be at most one **noreminders** object. It
contains a single keym, **noreminders**, whose value is the phrase
\"No reminders.\", possibly localized into a different language.
**event**
: All other objects in the array are **event** objects. They are JSON
objects that contain all of the keys described in the **rem2ps**(1)
man page section \"CALENDAR ENTRIES\". However, the
**calendar_body**, **plain_body** and **raw_body** keys will not be
present.
JSON output can be used by a front-end to display an attractive list of
reminders in Agenda Mode. The \"show today\'s reminders\" feature of
**tkremind** uses the JSON output.
# CALENDAR MODE
If you supply the **-c**, **-s** or **-p** command-line option, then
**Remind** runs in \"calendar mode.\" In this mode, **Remind**
interprets the script repeatedly, performing one iteration through the
whole file for each day in the calendar. Reminders that trigger are
saved in internal buffers, and then inserted into the calendar in the
appropriate places.
If you also supply the **-a** option, then **Remind** will not include
timed reminders in the calendar.
The **-p** option is used in conjunction with the **Rem2PS** program to
produce a calendar in PostScript format. For example, the following
command will send PostScript code to standard output:
remind -p .reminders | rem2ps
You can print a PostScript calendar by piping this to the **lpr**
command.
If you have a reminder script called \".reminders\", and you execute
this command:
remind -c .reminders jan 1993
then **Remind** executes the script 31 times, once for each day in
January. Each time it executes the script, it increments the value of
**today()**. Any reminders whose trigger date matches **today()** are
entered into the calendar.
**MSG** and **CAL**-type reminders, by default, have their entire body
inserted into the calendar. **RUN**-type reminders are not normally
inserted into the calendar. However, if you enclose a portion of the
body in the %\"\...%\" sequence, only that portion is inserted. For
example, consider the following:
REM 6 Jan MSG %"Dianne's birthday%" is %b
In agenda mode, **Remind** would print \"Dianne\'s birthday is today\"
on 6 January. However, in the calendar mode, only the text \"Dianne\'s
birthday\" is inserted into the box for 6 January.
If you explicitly use the %\"\...%\" sequence in a **RUN**-type
reminder, then the text between the delimiters is inserted into the
calendar. If you use the sequence %\"%\" in a **MSG** or **CAL**-type
reminder, then no calendar entry is produced for that reminder.
**PRESERVING VARIABLES**
Because **Remind** iterates through the script for each day in the
calendar, slow operations may severely reduce the speed of producing a
calendar.
For example, suppose you set the variables \"me\" and \"hostname\" as
follows:
SET me shell("whoami")
SET hostname shell("hostname")
Normally, **Remind** clears all variables between iterations in calendar
mode. However, if certain variables are slow to compute, and will not
change between iterations, you can \"preserve\" their values with the
**PRESERVE** command. Also, since function definitions are preserved
between calendar iterations, there is no need to redefine them on each
iteration. Thus, you could use the following sequence:
IF ! defined("initialized")
set initialized 1
set me shell("whoami")
set hostname shell("hostname")
fset func(x) complex_expr
preserve initialized me hostname
ENDIF
The operation is as follows: On the first iteration through the script,
\"initialized\" is not defined. Thus, the commands between **IF** and
**ENDIF** are executed. The **PRESERVE** command ensures that the values
of initialized, me and hostname are preserved for subsequent iterations.
On the next iteration, the commands are skipped, since initialized has
remained defined. Thus, time-consuming operations that do not depend on
the value of **today()** are done only once.
Most system variables (those whose names start with \'\$\') are
automatically preserved between calendar iterations.
Note that for efficiency, **Remind** caches the reminder script (and any
**INCLUDE**d files) in memory when producing a calendar.
Timed reminders are sorted and placed into the calendar in time order.
These are followed by non-timed reminders. **Remind** automatically
places the time of timed reminders in the calendar according to the
**-b** command-line option. Reminders in calendar mode are sorted as if
the **-g** option had been used; you can change the sort order in
calendar mode by explicitly using the **-g** option to specify a
different order from the default.
**REPEATED EXECUTION**
If you supply a *repeat* parameter on the command line, and do not use
the **-c**, **-p**, or **-s** options, **Remind** operates in a similar
manner to calendar mode. It repeatedly executes the reminder script,
incrementing **today()** with each iteration. The same rules about
preserving variables and function definitions apply. Note that using
*repeat* on the command line also enables the **-q** option and disables
any **-z** option. As an example, if you want to see how **Remind** will
behave for the next week, you can type:
remind .reminders '*7'
If you want to print the dates of the next 1000 days, use:
(echo 'banner %'; echo 'msg [today()]%') | remind - '*1000'
# INITIALIZING VARIABLES ON THE COMMAND LINE
The **-i** option is used to initialize variables on the **Remind**
command line. The format is **-i**_var=expr_, where *expr* is any
valid expression. Note that you may have to use quotes or escapes to
prevent the shell from interpreting special characters in *expr*. You
can have as many **-i** options as you want on the command line, and
they are processed in order. Thus, if a variable is defined in one
**-i** option, it can be referred to by subsequent **-i** options.
Note that if you supply a date on the command line, it is not parsed
until all options have been processed. Thus, if you use **today()** in
any of the **-i** expressions, it will return the same value as
**realtoday()** and not the date supplied on the command line.
Any variables defined on the command line are **preserved** as with the
**PRESERVE** command.
You should not have any spaces between the **-i** option and the equal
sign; otherwise, strange variable names are created that can only be
accessed with the **value()** or **defined()** functions.
You can also define a function on the command line by using:
**-i**_func(args)=definition_
Be sure to protect special characters from shell interpretation.
# MORE ABOUT POSTSCRIPT
The **PS** and **PSFILE** reminders pass PostScript code directly to the
printer. They differ in that the **PS**-type reminder passes its body
directly to the PostScript output (after processing by the substitution
filter) while the **PSFILE**-type\'s body should simply consist of a
filename. The **Rem2PS** program will open the file named in the
**PSFILE**-type reminder, and include its contents in the PostScript
output.
The PostScript-type reminders for a particular day are included in the
PostScript output in sorted order of priority. Note that the order of
PostScript commands has a *major* impact on the appearance of the
calendars. For example, PostScript code to shade a calendar box will
obliterate code to draw a moon symbol if the moon symbol code is placed
in the calendar first. For this reason, you should not provide **PS** or
**PSFILE**-type reminders with priorities; instead, you should ensure
that they appear in the reminder script in the correct order. PostScript
code should draw objects working from the background to the foreground,
so that foreground objects properly overlay background ones. If you
prioritize these reminders and run the script using descending sort
order for priorities, the PostScript output will not work.
All of the PostScript code for a particular date is enclosed in a
**save**-**restore** pair. However, if several PostScript-type reminders
are triggered for a single day, each section of PostScript is not
enclosed in a **save**-**restore** pair - instead, the entire body of
included PostScript is enclosed.
PostScript-type reminders are executed by the PostScript printer before
any regular calendar entries. Thus, regular calendar entries will
overlay the PostScript-type reminders, allowing you to create shaded or
graphical backgrounds for particular days.
Before executing your PostScript code, the origin of the PostScript
coordinate system is positioned to the bottom left-hand corner of the
\"box\" in the calendar representing **today()**. This location is
exactly in the middle of the intersection of the bottom and left black
lines delineating the box - you may have to account for the thickness of
these lines when calculating positions.
Several PostScript variables are available to the PostScript code you
supply. All distance and size variables are in PostScript units (1/72
inch.) The variables are:
LineWidth
: The width of the black grid lines making up the calendar.
Border
: The border between the center of the grid lines and the space used
to print calendar entries. This border is normally blank space.
BoxWidth and BoxHeight
: The width and height of the calendar box, from center-to-center of
the black gridlines.
InBoxHeight
: The height from the center of the bottom black gridline to the top
of the regular calendar entry area. The space from here to the top
of the box is used only to draw the day number.
/DayFont, /EntryFont, /SmallFont, /TitleFont and /HeadFont
: The fonts used to draw the day numbers, the calendar entries, the
small calendars, the calendar title (month, year) and the
day-of-the-week headings, respectively.
DaySize, EntrySize, TitleSize and HeadSize
: The sizes of the above fonts. (The size of the small calendar font
is *not* defined here.) For example, if you wanted to print the
Hebrew date next to the regular day number in the calendar, use:
```{=html}
<!-- -->
```
REM PS Border BoxHeight Border sub DaySize sub moveto \
/DayFont findfont DaySize scalefont setfont \
([hebday(today())] [hebmon(today())]) show
> Note how /DayFont and DaySize are used.
Note that if you supply PostScript code, it is possible to produce
invalid PostScript files. Always test your PostScript thoroughly with a
PostScript viewer before sending it to the printer. You should not use
any document structuring comments in your PostScript code.
# DAEMON MODE
If you use the **-z** command-line option, **Remind** runs in \"daemon
mode\". In this mode, no \"normal\" reminders are issued. Instead, only
timed reminders are collected and queued, and are then issued whenever
they reach their trigger time.
In addition, **Remind** wakes up every few minutes to check the
modification date on the reminder script (the filename supplied on the
command line.) If **Remind** detects that the script has changed, it
re-executes itself in daemon mode, and interprets the changed script. If
**Remind** was compiled with support for **inotify**(7), then if the
command-line reminder script is really a directory, **Remind** also
re-executes itself if any of the files in the directory is changed.
In daemon mode, **Remind** also re-reads the remind script when it
detects that the system date has changed.
In daemon mode, **Remind** acts as if the **-f** option had been used,
so to run in daemon mode in the background, use:
remind -z .reminders &
If you use **sh** or **bash**, you may have to use the \"nohup\" command
to ensure that the daemon is not killed when you log out.
# PURGE MODE
If you supply the **-j** command-line option, **Remind** runs in *purge
mode*. In this mode, it tries to purge expired reminders from your
reminder files.
In purge mode, **Remind** reads your reminder file and creates a new
file by appending \".purged\" to the original file name. Note that
**Remind** *never* edits your original file; it always creates a new
.purged file.
If you invoke **Remind** against a directory instead of a file, then a
.purged file is created for each \*.rem file in the directory.
Normally, **Remind** does not create .purged files for INCLUDed files.
However, if you supply a numeric argument after **-j**, then **Remind**
will create .purged files for the specified level of INCLUDE. For
example, if you invoke **Remind** with the argument **-j2**, then
.purged files will be created for the file (or directory) specified on
the command line, any files included by them, and any files included by
those files. However, .purged files will not be created for
third-or-higher level INCLUDE files.
Determining which reminders have expired is extremely tricky. **Remind**
does its best, but you should always compare the .purged file to the
original file and hand-merge the changes back in.
**Remind** annotates the .purged file as follows:
An expired reminder is prefixed with: #!P: Expired:
In situations where **Remind** cannot reliably determine that something
was expired, you may see the following comments inserted before the
problematic line:
#!P: Cannot purge SATISFY-type reminders
#!P: The next IF evaluated false...
#!P: REM statements in IF block not checked for purging.
#!P: The previous IF evaluated true.
#!P: REM statements in ELSE block not checked for purging
#!P: The next IFTRIG did not trigger.
#!P: REM statements in IFTRIG block not checked for purging.
#!P: Next line has expired, but contains expression... please verify
#!P: Next line may have expired, but contains non-constant expression
#!P: or a relative SCANFROM clause
#!P! Could not parse next line: Some-Error-Message-Here
#!P! Problem calculating trigger date
**Remind** always annotates .purged files with lines beginning with
\"#!P\". If such lines are encountered in the *original* file, they are
not copied to the .purged file.
If you use the \"Hush\" flag **-h** in conjunction with the \"Purge\"
flag **-j**, then **Remind** does *not* create any of the diagnostic
comments listed above. Instead, the only change it makes to the .purged
file is to mark expired reminders with \"#!P: Expired\".
# NON-CONSTANT EXPRESSIONS
In Purge Mode, **Remind** will not mark a REM statement as expired if
its trigger specification contains a non-constant expression. A
non-constant expression is defined as one whose value might differ from
run to run, usually because it depends on the current date, but also if
it depends on something from the environment (such as the output of the
**shell()** function.)
The use of any of the following in an expression causes **Remind** to
consider it non-constant:
> **o**
>
> : A global variable that has been assigned the result of a
> non-constant expression, or that has been assigned a value in a
> *non-constant* context (to be described later.)
>
> **o**
>
> : A system variable
>
> **o**
>
> : Certain built-in functions that depend on the current date (for
> example, **today()**) or the environment (for example,
> **shell()**).
In addition, for the purposes of safely expiring reminders in Purge
Mode, **Remind** considers the following to be non-constant:
> **o**
>
> : The use of an OMITFUNC
>
> **o**
>
> : The use of a relative SCANFROM
Whenever a variable is assigned a value, **Remind** tracks whether or
not the expression whose value it was assigned is constant or
non-constant. Additionally, variables that are assigned in a
non-constant context are always assumed to be non-constant. A
non-constant context is the code in the scope of an **IF** statement
where the **IF** expression is non-constant.
Here are some examples that should make things clear:
SET d '2025-06-01' # d is constant
REM [d] MSG Hello! # eligible for purging
SET d today() - 3 # d is non-constant
REM [d] MSG Hello! # not eligible for purging
IF wkdaynum(today()) == 3
set d '2025-06-01' # d is non-constant
ELSE
set d '2026-01-01' # d is non-constant
ENDIF
SET d '2025-06-01' # d is constant
IF today() > today() + 3 # This branch is never taken, but...
SET d '2029-01-01' # d is still marked non-constant
ENDIF
# Although here d is still '2025-06-01', it is marked
# non-constant because as far as Remind is concerned,
# the IF body *might* have been executed depending on today()
Note that within the **IF**\...**ENDIF** scope, any assignments are
non-constant because the code flow depends on today\'s date, which could
change in subsequent **Remind** runs. If you want to force a variable to
be treated as constant, no matter what, then use the following just
before you use the variable:
SET var const(var)
Variables initialized on the command-line with the **-i** flag are
*always* considered to be non-constant.
If you have an expired reminder that for some reason you never want
purged, simply use the built-in function **nonconst** somewhere in the
trigger. For example:
REM 1992-01-01 MSG This will be purged after Jan 1 1992
REM [nonconst('1992-01-01')] MSG This will never be purged
REM Wed UNTIL 1993-12-31 MSG This will be purged after 1993
REM Wed UNTIL [nonconst('1993-12-31')] MSG Never purged
The **n** debugging flag prints a message to standard error whenever
**Remind** decides that an expression is non-constant. This can produce
a large amount of output, so if you want to find out why **Remind**
considers a specific expression to be non-constant, it\'s best to use
**DEBUG +n** before it and **DEBUG -n** after it to limit the amount of
output.
# SORTING REMINDERS
The **-g** option causes **Remind** 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
**Remind** has finished processing the script, it issues the saved
reminders in sorted order. The **-g** 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.
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. 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.
You can define a user-defined function called SORTBANNER that takes one
**DATE**-type argument. In sort mode, the following sequence happens:
If **Remind** notices that the next reminder to issue has a different
trigger date from the previous one (or if it is the first one to be
issued), then SORTBANNER is called with the trigger date as its
argument. The result is coerced to a string, and passed through the
substitution filter with the appropriate trigger date. The result is
then displayed.
Here\'s an example - consider the following fragment:
# Switch off the normal banner
BANNER %
REM 11 March 1993 ++1 MSG Not so important
REM 17 March 1993 ++7 MSG Way in the future
REM 10 March 1993 MSG Important Reminder
REM 11 March 1993 ++1 MSG Not so important - B
FSET sortbanner(x) iif(x == today(), \
"***** THINGS TO DO TODAY *****", \
"----- Things to do %b -----")
Running this with the **-gaa** option on 10 March 1993 produces the
following output:
***** THINGS TO DO TODAY *****
Important Reminder
----- Things to do tomorrow -----
Not so important
Not so important - B
----- Things to do in 7 days' time -----
Way in the future
You can use the **args()** built-in function to determine whether or not
SORTBANNER has been defined. (This could be used, for example, to
provide a default definition for SORTBANNER in a system-wide file
included at the end of the user\'s file.) Here\'s an example:
# Create a default sortbanner function if it hasn't already
# been defined
if args("sortbanner") != 1
fset sortbanner(x) "--- Things to do %b ---"
endif
# MSGPREFIX() AND MSGSUFFIX()
You can define two functions in your script called **msgprefix()** and
**msgsuffix()**. They should each accept one argument, a number from 0
to 9999.
In agenda mode, for **MSG**- and **MSF**-type reminders, the following
sequence occurs when **Remind** triggers a reminder:
o
: If **msgprefix()** is defined, it is evaluated with the priority of
the reminder as its argument. The result is printed. It is *not*
passed through the substitution filter.
o
: The body of the reminder is printed.
o
: If **msgsuffix()** is defined, it is evaluated with the priority of
the reminder as its argument. The result is printed. It is *not*
passed through the substitution filter.
Here\'s an example: The following definition causes priority-0 reminders
to be preceded by \"URGENT\", and priority-6000 reminders to be preceded
by \"(not important)\".
fset msgprefix(x) iif(x==0, "URGENT: ", \
x==6000, "(not important) ", "")
In Calendar Mode (with the **-c**, **-s** or **-p** options), an
analogous pair of functions named **calprefix()** and **calsuffix()**
can be defined. They work with all reminders that produce an entry in
the calendar (i.e., **CAL**- and possibly **RUN**-type reminders as well
as **MSG**-type reminders.)
**NOTES**
Normally, the body of a reminder is followed by a carriage return. Thus,
the results of **msgsuffix()** will appear on the next line. If you
don\'t want this, make sure the output of **msgsuffix** begins with a
backspace. This places the suffix *before* rather than after the
carriage return. (The backspace character itself is stripped out.) Here
is an example:
FSET msgsuffix(x) char(8) + " - suffix on same line"
If **Remind** has problems evaluating **msgprefix()**, **msgsuffix()**
or **sortbanner()**, you will see a lot of error messages. For an
example of this, define the following:
fset msgprefix(x) x/0
# COMPILE-TIME SUPPORT FOR OTHER LANGUAGES
**Remind** used to support compile-time localization to other languages,
but no longer does. All localization is now done at run-time.
# RUN-TIME SUPPORT FOR OTHER LANGUAGES
**Remind** has run-time support for other languages, and compile-time
support has been removed in favour of run-time support.
A number of system variables let you translate various phrases to other
languages. These system variables are:
**\$Monday, \$Tuesday, \$Wednesday, \$Thursday, \$Friday, \$Saturday, \$Sunday**
: Set each of these system variables to a string representing the
corresponding day\'s name in your language. Strings must be valid
UTF-8 strings.
**\$January, \$February, \$March, \$April, \$May, \$June, \$July, \$August, \$September, \$October, \$November, \$December**
: Set each of these system variables to a string representing the
corresponding month\'s name in your language. Strings must be valid
UTF-8 strings.
**\$Ago, \$Am, \$And, \$At, \$Hour, \$Is, \$Minute, \$Now, \$On, \$Pm, \$Today, \$Tomorrow, \$Was**
: Set each of these system variables to the translation of the
corresponding English word into your language. Note that **\$Am**
and **\$Pm** should be the translations of \"AM\" and \"PM\"
(morning and afternoon time indicators) respectively.
**\$Hplu, \$Mplu**
: Set these to the suffix to add to the word for \"hour\" and
\"minute\" to make them plural. In English, both would be set to
\"s\".
**\$Fromnow**
: Set this to the translation of the English phrase \"from now\"
Note that if you set any of the language-related system variables, they
should be set in a section of your script that always is evaluated. If
you set them inside an **IF** statement, for example, results are
unpredictable.
Note also that the **Rem2PS** back-end does not support the full range
of UTF-8 characters. The **TkRemind**, **rem2html** and **rem2pdf**
back-ends all do support the full UTF-8 range.
# RUN-TIME MODIFICATION OF THE SUBSTITUTION FILTER
The system variables mentioned in the previous section are not typically
sufficient to properly translate Remind\'s output to another language.
Some languages have complicated rules for AM vs PM times and others have
complex rules for making words plural. **Remind** therefore allows you
to define a number of functions that modify the behavior of the
substitution filter at run-time. The functions are:
**subst_ampm(h)**
: This function is passed a single integer, namely an hour from 0
to 23. It should return a string that indicates \"AM\" or \"PM\" or
even finer gradations in some languages.
**subst_ordinal(d)**
: This function is passed a single integer, namely a day of the month
from 1 to 31. It should return a string that is suffixed to the day
number to turn it into an ordinal number. In English, for example,
the function might return \"st\", \"nd\", \"rd\" or \"th\",
depending on *d*.
**subst\_N(alt, date, time)**
: This is actually a *family* of functions, where *N* is a letter or
number. This function *completely overrides* the substitution
sequence \"%N\". The three arguments are an integer *alt* which, if
non-zero, indicates that the alternate-mode substitution sequence
\"%\*N\" was encountered; *date* which is the trigger date of the
reminder and *time* which is the trigger time.
**subst\_Nx(alt, date, time)**
: Again, this is a *family* of functions. It is similar to the
**subst\_N** family except it is only called if *date* is two or
more days away from *today()*. This is useful if you don\'t want to
override the \"today\" or \"tomorrow\" output for most substitution
sequences.
Here\'s an example of how you might customize your substitution filter.
Suppose you want to change the \"%b\" sequence to substitute \"the day
after tomorrow\" for an event two days from now. You could do this:
FSET subst_bx(a,d,t) iif(d==today()+2, "the day after tomorrow", \
"in " + (d-today()) + " days' time")
REM [today()+3] ++3 MSG Event 1 is %b%
REM [today()+2] ++3 MSG Event 2 is %b%
REM [today()+1] ++3 MSG Event 3 is %b%
REM [today()] ++3 MSG Event 4 is %b%
The output of this script is:
Event 1 is in 3 days' time
Event 2 is the day after tomorrow
Event 3 is tomorrow
Event 4 is today
Note how Event 2\'s wording was changed from the normal \"in 2 days\'
time\", and note also that the \"tomorrow\" and \"today\" events used
the normal substitution\-\--**subst_bx** is not called for trigger days
of today or tomorrow.
As a special case, if a **subst_Nx or subst_N** function returns the
integer zero, then the normal substitution mechanism is used. Therefore,
the previous example could have been written more simply as:
FSET subst_bx(a,d,t) iif(d==today()+2, "the day after tomorrow", 0)
You can override substitution sequences that are not alphanumeric as
follows:
> Override %: with **subst_colon**
>
> Override %! with **subst_bang**
>
> Override %? with **subst_question**
>
> Override %@ with **subst_at**
>
> Override %# with **subst_hash**
You can define your own substitution sequences in addition to the
built-in ones as follows: If you define a function named
**subst\_name(alt, date, time)**, then the sequence **%{name}**
calls the function with **alt** set to 0 and **date** and **time** to
the trigger date and time, respectively. The **%{name}** sequence is
replaced with whatever the function returns. The sequence **%\*{name}**
is similar, but calls the function with **alt** set to 1.
If you use a **%{name}** sequence and the function **subst\_name** is
not defined or returns an error, then **%{name}** is replaced with the
empty string.
Note that when **Remind** invokes any callback function for a
substitution sequence, **RUN** will be disabled.
# THE TRANSLATION TABLE
To assist with localizing reminder files, **Remind** maintains a table
of translations. This is simple a lookup table that maps one string (the
original string) to a new string (the translated string.) When
**Remind** starts executing, the translation table is empty.
To add a message to the translation table, use the **TRANSLATE** command
(which may be abbreviated to **TRANS**.) The **TRANSLATE** command must
be followed by two quoted strings, separated from each other and from
the command by whitespace. For example, a Dutch language file might
contain something like this:
TRANSLATE "New Moon" "Nieuwe maan"
TRANSLATE "First Quarter" "Eerste kwartier"
TRANSLATE "Full Moon" "Volle maan"
TRANSLATE "Last Quarter" "Laatste kwartier"
To actually use the translation table, make use of the **\_** built-in
function, as follows:
REM NOQUEUE [moondatetime(0)] MSG [_("New Moon")] (%2)
REM NOQUEUE [moondatetime(1)] MSG [_("First Quarter")] (%2)
REM NOQUEUE [moondatetime(2)] MSG [_("Full Moon")] (%2)
REM NOQUEUE [moondatetime(3)] MSG [_("Last Quarter")] (%2)
By using **TRANSLATE** and **\_** judiciously, you can make your
reminder files easy to translate.
**TRANSLATE** has four additional forms: If it is followed by *one*
quoted string instead of two, then **Remind** deletes the translation
table entry for that string. If it is followed by the keyword **DUMP**,
then **Remind** dumps all translation table entries to standard output.
And if it is followed by **CLEAR**, then **Remind** deletes all of the
translation table entries.
The fourth form, **TRANSLATE GENERATE**, dumps all of the strings that
can be localized (as a series of TRANSLATE commands) to standard output.
Strings that are already localized are output with their localization;
strings that are not localized are output as:
TRANSLATE "untranslated" ""
If you want to add a new language, you can obtain a skeleton translation
file by running:
echo "TRANSLATE GENERATE" | remind -h - > /tmp/skeleton.rem
If you have an existing language file that is missing some translations,
you can update it by running:
(echo INCLUDE mylang.rem; echo TRANSLATE GENERATE) | \
remind -h - > /tmp/mylang-update.rem
and then editing **mylang-update.rem** to add in the missing
translations.
If you have some reminder scripts that use the **\_()** built-in
function or **%(\...)** substitution sequence, you can generate a list
of needed TRANSLATE commands by running:
remind -q -n -dq myscript.rem 2>&1 | grep ^TRANSLATE | sort | uniq
Note that if you **SET** various translation-related system variables
such as **\$Monday**, **\$December**, **\$Ago**, etc, then **Remind**
*also* makes a corresponding translation table entry automatically. This
is done for all of the translation-related system variables *except for*
**\$Hplu** and **\$Mplu**.
The converse applies too; creating a translation table for \"December\"
automatically sets **\$December**. And if you invoke **TRANSLATE
CLEAR**, then all translation-related system variables are set to their
default values as well.
The translation table always contains a special entry **LANGID** whose
default value is **en**. Translators are encouraged to add a **LANGID**
entry in their language files; the value should be the two-characters
ISO 639 language code.
For example, if you write a translation file for the Dutch language, add
this line:
TRANSLATE "LANGID" "nl"
Scripts can use **\_(\"LANGID\")** to query the translation language
that is in effect.
The **\_()** function uses the following procedure to obtain the
translation for a string:
> 1
>
> : Look for an exact match. If found, return.
>
> 2
>
> : If the original string had an upper-case letter, search for the
> all-lower-case equivalent. If found, make the first letter of the
> result upper-case and return.
>
> 3
>
> : If the original string started with a lower-case letter, search
> for an equivalent whose first letter is upper-case and the rest
> lower-case. If found, make the first letter of the result
> lower-case and return.
>
> 4
>
> : No translation was found. Return the original string.
# LANGUAGE PACKS
**Remind** ships with a number of language packs, which are simply
reminder scripts located in **\[\$SysInclude\]/lang**. The
currently-shipping language packs are:
da.rem (Danish), de.rem (German), es.rem (Spanish), fr.rem (French),
is.rem (Icelandic), it.rem (Italian), nl.rem (Dutch), no.rem
(Norwegian), pl.rem (Polish), pt.rem (Portuguese) and ro.rem (Romanian).
To use a language pack (in this example, de.rem), simply place this at
the top of your reminders file:
SYSINCLUDE lang/de.rem
If you want **Remind** to try to find the language pack appropriate for
your locale settings, use:
SYSINCLUDE lang/auto.rem
You are encouraged to study the language packs to see how to translate
**Remind** into additional languages.
# THE HEBREW CALENDAR
**Remind** has support for the Hebrew calendar, which is a luni-solar
calendar. This allows you to create reminders for Jewish holidays,
jahrzeits (anniversaries of deaths) and smachot (joyous occasions.)
**THE HEBREW YEAR**
The Hebrew year has 12 months, alternately 30 and 29 days long. The
months are: Tishrey, Heshvan, Kislev, Tevet, Shvat, Adar, Nisan, Iyar,
Sivan, Tamuz, Av and Elul. In Biblical times, the year started in Nisan,
but Rosh Hashana (Jewish New Year) is now celebrated on the 1st and 2nd
of Tishrey.
In a cycle of 19 years, there are 7 leap years, being years 3, 6, 8, 11,
14, 17 and 19 of the cycle. In a leap year, an extra month of 30 days is
added before Adar. The two Adars are called Adar A and Adar B.
For certain religious reasons, the year cannot start on a Sunday,
Wednesday or Friday. To adjust for this, a day is taken off Kislev or
added to Heshvan. Thus, a regular year can have from 353 to 355 days,
and a leap year from 383 to 385.
When Kislev or Heshvan is short, it is called *chaser*, or lacking. When
it is long, it is called *shalem*, or full.
The Jewish date changes at sunset. However, **Remind** will change the
date at midnight, not sunset. So in the period between sunset and
midnight, **Remind** will be a day earlier than the true Jewish date.
This should not be much of a problem in practice.
The computations for the Jewish calendar were based on the program
\"hdate\" written by Amos Shapir of the Hebrew University of Jerusalem,
Israel. He also supplied the preceding explanation of the calendar.
**HEBREW DATE FUNCTIONS**
**hebday(d_date)**
: Returns the day of the Hebrew month corresponding to the *date*
parameter. For example, 12 April 1993 corresponds to 21 Nisan 5753.
Thus, hebday(\'1993/04/12\') returns 21.
**hebmon(d_date)**
: Returns the name of the Hebrew month corresponding to *date*. For
example, hebmon(\'1993/04/12\') returns \"Nisan\".
**hebyear(d_date)**
: Returns the Hebrew year corresponding to *date*. For example,
hebyear(\'1993/04/12\') returns 5753.
**hebdate(i_day, s_hebmon \[,id_yrstart \[,i_jahr \[,i_aflag\]\]\])**
: The **hebdate()** function is the most complex of the Hebrew support
functions. It can take from 2 to 5 arguments. It returns a **DATE**
corresponding to the Hebrew date.
> The *day* parameter can range from 1 to 30, and specifies the day of
> the Hebrew month. The *hebmon* parameter is a string that must name
> one of the Hebrew months specified above. Note that the month must be
> spelled out in full, and use the English transliteration shown
> previously. You can also specify \"Adar A\" and \"Adar B.\" Month
> names are not case-sensitive.
>
> The *yrstart* parameter can either be a **DATE** or an **INT**. If it
> is a **DATE**, then the **hebdate()** scans for the first Hebrew date
> on or after that date. For example:
>
> hebdate(15, "Nisan", '1990/01/01')
>
> returns 1990/03/30, because that is the first occurrence of 15 Nisan
> on or after 1 January 1990.
>
> If *yrstart* is an **INT**, it is interpreted as a Hebrew year. Thus:
>
> hebdate(22, "Kislev", 5756)
>
> returns 1995/12/15, because that date corresponds to 22 Kislev, 5756.
> Note that none of the Hebrew date functions will work with dates
> outside **Remind\'s** normal range for dates.
>
> If *yrstart* is not supplied, it defaults to **today()**.
>
> The *jahr* modifies the behaviour of **hebdate()** as follows:
>
> If *jahr* is 0 (the default), then **hebdate()** keeps scanning until
> it finds a date that exactly satisfies the other parameters. For
> example:
>
> hebdate(30, "Adar A", 1993/01/01)
>
> returns 1995/03/02, corresponding to 30 Adar A, 5755, because that is
> the next occurrence of 30 Adar A after 1 January, 1993. This behaviour
> is appropriate for Purim Katan, which only appears in leap years.
>
> If *jahr* is 1, then the date is modified as follows:
>
> o
>
> : 30 Heshvan is converted to 1 Kislev in years when Heshvan is
> *chaser*
>
> o
>
> : 30 Kislev is converted to 1 Tevet in years when Kislev is *chaser*
>
> o
>
> : 30 Adar A is converted to 1 Nisan in non-leapyears
>
> o
>
> : Other dates in Adar A are moved to the corresponding day in Adar
> in non-leapyears
>
> This behaviour is appropriate for smachot (joyous occasions) and for
> some jahrzeits - see \"JAHRZEITS.\"
>
> if *jahr* is 2, then the date is modified as follows:
>
> o
>
> : 30 Kislev and 30 Heshvan are converted to 29 Kislev and 29
> Heshvan, respectively, if the month is *chaser*
>
> o
>
> : 30 Adar A is converted to 30 Shvat in non-leapyears
>
> o
>
> : Other dates in Adar A are moved to the corresponding day in Adar
> in non-leapyears
>
> if *jahr* is not 0, 1, or 2, it is interpreted as a Hebrew year, and
> the behaviour is calculated as described in the next section,
> \"JAHRZEITS.\"
>
> The *aflag* parameter modifies the behaviour of the function for dates
> in Adar during leap years. The *aflag* is *only* used if *yrstart* is
> a **DATE** type.
>
> The *aflag* only affects date calculations if *hebmon* is specified as
> \"Adar\". In leap years, the following algorithm is followed:
>
> o
>
> : If *aflag* is 0, then the date is triggered in Adar B. This is the
> default.
>
> o
>
> : If *aflag* is 1, then the date is triggered in Adar A. This may be
> appropriate for jahrzeits in the Ashkenazi tradition; consult a
> rabbi.
>
> o
>
> : If *aflag* is 2, then the date is triggered in both Adar A and
> Adar B of a leap year. Some Ashkenazim perform jahrzeit in both
> Adar A and Adar B.
**JAHRZEITS**
A jahrzeit is a yearly commemoration of someone\'s death. It normally
takes place on the anniversary of the death, but may be delayed if
burial is delayed - consult a rabbi for more information.
In addition, because some months change length, it is not obvious which
day the anniversary of a death is. The following rules are used:
o
: If the death occurred on 30 Heshvan, and Heshvan in the year after
the death is *chaser*, then the jahrzeit is observed on 29 Heshvan
in years when Heshvan is *chaser*. Otherwise, the jahrzeit is
observed on 1 Kislev when Heshvan is *chaser*.
o
: If the death occurred on 30 Kislev, and Kislev in the year after the
death is *chaser*, then the jahrzeit is observed on 29 Kislev in
years when Kislev is *chaser*. Otherwise, the jahrzeit is observed
on 1 Tevet when Kislev is *chaser*.
o
: If the death occurred on 1-29 Adar A, it is observed on 1-29 Adar in
non-leapyears.
o
: If the death occurred on 30 Adar A, it is observed on 30 Shvat in a
non-leapyear.
Specifying a Hebrew year for the *jahr* parameter causes the correct
behaviour to be selected for a death in that year. You may also have to
specify *aflag*, depending on your tradition.
The jahrzeit information was supplied by Frank Yellin, who quoted \"The
Comprehensive Hebrew Calendar\" by Arthur Spier, and \"Calendrical
Calculations\" by E. M. Reingold and Nachum Dershowitz.
# OUT-OF-BAND REMINDERS
The **SPECIAL** keyword is used to transmit \"out-of-band\" information
to **Remind** backends, such as **tkremind** or **Rem2PS**. They are
used only when piping data from a **remind -p** line. (Note that the
COLOR special is an exception; it works similarly to MSG when the **-p**
option is not supplied.)
The various **SPECIAL**s recognized are particular for each backend;
however, there are four **SPECIAL**s that all backends should attempt to
support. They are currently supported by **Rem2PS**, **tkremind** and
**rem2html**.
The **SHADE** special replaces the **psshade()** function. Use it like
this:
REM Sat Sun SPECIAL SHADE 128
REM Mon SPECIAL SHADE 255 0 0
The **SHADE** keyword is followed by either one or three numbers, from 0
to 255. If one number is supplied, it is interpreted as a grey-scale
value from black (0) to white (255). If three numbers are supplied, they
are interpreted as RGB components from minimum (0) to maximum (255). The
example above shades weekends a fairly dark grey and makes Mondays a
fully-saturated red. (These shadings appear in calendars produced by
**Rem2PS**, **tkremind** and **rem2html**.)
The **MOON** special replaces the **psmoon()** function. Use it like
this:
REM [moondate(0)] SPECIAL MOON 0
REM [moondate(1)] SPECIAL MOON 1
REM [moondate(2)] SPECIAL MOON 2
REM [moondate(3)] SPECIAL MOON 3
These draw little moons on the various calendars. The complete syntax of
the **MOON** special is as follows:
... SPECIAL MOON phase moonsize fontsize msg
*Phase* is a number from 0 to 3, with 0 representing a new moon, 1 the
first quarter, 2 a full moon and 3 the last quarter.
*moonsize* is the diameter in PostScript units of the moon to draw. If
omitted or supplied as -1, the backend chooses an appropriate size.
*fontsize* is the font size in PostScript units of the *msg*
*Msg* is additional text that is placed near the moon glyph.
Note that only the **Rem2PS** backend supports *moonsize* and
*fontsize*; the other backends use fixed sizes.
The **COLOR** special lets you place colored reminders in the calendar.
Use it like this:
REM ... SPECIAL COLOR 255 0 0 This is a bright red reminder
REM ... SPECIAL COLOR 0 128 0 This is a dark green reminder
You can spell COLOR either the American way (\"COLOR\") or the British
way (\"COLOUR\"). This manual will use the American way.
Immediately following COLOR should be three decimal numbers ranging from
0 to 255 specifying red, green and blue intensities, respectively. The
rest of the line is the text to put in the calendar.
The COLOR special is \"doubly special\", because in agenda mode,
**remind** treats a COLOR special just like a MSG-type reminder. Also,
if you invoke **Remind** with **-@**\[*n*\], then it approximates
SPECIAL COLOR reminders on your terminal.
See also the documentation of the **\$DefaultColor** system variable in
the section \"SYSTEM VARIABLES\".
The **WEEK** 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*n*)\" in this
example, but you can put whatever text you like after the WEEK keyword.
REM Monday SPECIAL WEEK (W[weekno()])
# MISCELLANEOUS
**COMMAND AND KEYWORD ABBREVIATIONS**
The following tokens can be abbreviated:
o
: **CLEAR-OMIT-CONTEXT** \--\> **CLEAR**
o
: **PUSH-OMIT-CONTEXT** \--\> **PUSH**
o
: **POP-OMIT-CONTEXT** \--\> **POP**
o
: **DUMPVARS** \--\> **DUMP**
o
: **BANNER** \--\> **BAN**
o
: **INCLUDE** \--\> **INC**
o
: **MAYBE-UNCOMPUTABLE** \--\> **MAYBE**
o
: **SCANFROM** \--\> **SCAN**
**NIFTY EXAMPLES**
This section is a sampling of what you can do with **Remind**.
REM 5 Feb 1991 AT 14:00 +45 *30 \
RUN mail -s "Meeting at %2" $LOGNAME </dev/null &
On 5 February, 1991, this reminder will mail you reminders of a 2:00pm
meeting at 1:15, 1:45 and 2:00. The subject of the mail message will be
\"Meeting at 2:00pm\" and the body of the message will be blank.
REM AT 17:00 RUN echo "5:00pm - GO HOME!" | xless -g +0+0 &
This reminder will pop up an xless window at 5:00pm every day. The xless
window will contain the line \"5:00pm - GO HOME!\"
REM AT 23:59 RUN (sleep 120; remind -a [filename()]) &
This reminder will run at one minute to midnight. It will cause a new
**Remind** process to start at one minute past midnight. This allows you
to have a continuous reminder service so you can work through the night
and still get timed reminders for early in the morning. Note that this
trick is no longer necessary, providing you run **Remind** in daemon
mode.
remind -c12 /dev/null Jan 1993
This invocation of **Remind** will cause it to print a calendar for
1993, with all entries left blank.
REM CAL [trigdate()-date(year(trigdate()), 1, 1)+1]
This example puts an entry in each box of a calendar showing the number
(1-365 or 366) of the day of the year.
REM Tue 2 Nov SATISFY (year(trigdate())%4) == 0
IF trigvalid()
REM [trigdate()] ++5 MSG \
U.S. Presidential Election!!
ENDIF
This example warns you 5 days ahead of each American presidential
election. The first **REM** command calculates the first Tuesday after
the first Monday in November. (This is equivalent to the first Tuesday
on or after 2 November.) The **SATISFY** clause ensures that the trigger
date is issued only in election years, which are multiples of 4. The
second **REM** command actually issues the reminder.
**DETAILS ABOUT TRIGGER COMPUTATION**
Here is a *conceptual* description of how triggers are calculated. Note
that **Remind** actually uses a much more efficient procedure, but the
results are the same as if the conceptual procedure had been followed.
**Remind** starts from the current date (that is, the value of
**today()**) and scans forward, examining each day one at a time until
it finds a date that satisfies the trigger, or can prove that no such
dates (on or later than **today()**) exist.
If **Remind** is executing a **SATISFY**-type reminder, it evaluates the
expression with **trigdate()** set to the date found above. If the
expression evaluates to zero or the null string, **Remind** continues
the scanning procedure described above, starting with the day after the
trigger found above.
The **SCANFROM** clause (having a syntax similar to **UNTIL**) can
modify the search strategy used. In this case, **Remind** begins the
scanning procedure at *scan_date*, which is the date specified in the
**SCANFROM** clause. For example:
REM Mon 1 SCANFROM 17 Jan 1992 MSG Foo
The example above will always have a trigger date of Monday, 3 February
1992. That is because **Remind** starts scanning from 17 January 1992,
and stops scanning as soon as it hits a date that satisfies \"Mon 1.\"
The main use of **SCANFROM** is in situations where you want to
calculate the positions of floating holidays. Consider the Labour Day
example shown much earlier. Labour Day is the first Monday in September.
It can move over a range of 7 days. Consider the following sequence:
REM Mon 1 Sept SCANFROM [today()-7] ADDOMIT MSG Labour Day
REM Mon AFTER MSG Hello
The **SCANFROM** clause makes sure that **Remind** begins scanning from
7 days before the current date. This ensures that Labour Day for the
current year will continue to be triggered until 7 days after it has
occurred. This allows you to safely use the AFTER keyword as shown.
As a special case, you can simply use a negative number after SCANFROM;
a negative number -N is interpreted as N days before today. Thus, the
previous example could also be written like this:
REM Mon 1 Sept SCANFROM -7 ADDOMIT MSG Labour Day
REM Mon AFTER MSG Hello
A SCANFROM that specifies a full date is called an *absolute SCANFROM*
and a SCANFROM that specifies a negative number is called a *relative
SCANFROM*.
In general, use **SCANFROM** as shown for safe movable **OMITs**. The
amount you should scan back by (7 days in the example above) depends on
the number of possible consecutive **OMITted** days that may occur, and
on the range of the movable holiday. Generally, a value of 7 is safe.
The **FROM** clause operates almost like the counterpoint to **UNTIL**.
It prevents the reminder from triggering before the **FROM** date. For
example, the following reminder:
REM Mon Thu FROM 23 Jul 2007 UNTIL 2 Aug 2007 MSG Test
will trigger on Mondays and Thursdays between 23 July 2007 and 2 August
2007 inclusive.
**FROM** is really just syntactic sugar; you could implement the
reminder above as follows:
REM Mon Thu SCANFROM [max(today(), '2007-07-23')] \
UNTIL 2 Aug 2007 MSG Test
but that\'s a lot harder to read. Internally, **Remind** treats **FROM**
exactly as illustrated using **SCANFROM**. For that reason, you cannot
use both **FROM** and **SCANFROM**.
Note that if you use one **REM** command to calculate a trigger date,
perform date calculations (addition or subtraction, for example) and
then use the modified date in a subsequent **REM** command, the results
*may not be what you intended.* This is because you have circumvented
the normal scanning mechanism. You should try to write **REM** commands
that compute trigger dates that can be used unmodified in subsequent
**REM** commands. The file \"defs.rem\" that comes with the **Remind**
distribution contains examples.
**DETAILS ABOUT TRIGVALID()**
The **trigvalid()** function returns 1 if **Remind** could find a
trigger date for the previous **REM** or **IFTRIG** command. More
specifically, it returns 1 if **Remind** finds a date *not before the
starting* date of the scanning that satisfies the trigger. In addition,
there is one special case in which **trigvalid()** returns 1 and
**trigdate()** returns a meaningful result:
If the **REM** or **IFTRIG** command did not contain an **UNTIL** or
**SATISFY** clause, and contained all of the *day*, *month* and *year*
components, then **Remind** will correctly compute a trigger date, even
if it happens to be before the start of scanning. Note that this
behaviour is not true for versions of **Remind** prior to 03.00.01.
# FILES
The traditional location of your reminders file or directory is:
$HOME/.reminders
where **\$HOME** is your home directory.
**Remind** ships with some preinstalled files for holidays and language
packs. These are located in the following directory:
/usr/local/share/remind/
Do not hard-code the above directory in your reminder files. Instead,
use the value of the \$SysInclude system variable.
# AUTHOR
Dianne Skoll \<dianne@skoll.ca\> wrote **Remind**. The moon phase code
was copied largely unmodified from \"moontool\" by John Walker. The
moonrise/moonset code comes from https://github.com/signetica/MoonRise
by Stephen R. Schmitt and Cyrus Rahman. The sunrise and sunset functions
use ideas from programs by Michael Schwartz and Marc T. Kaufman. The
Hebrew calendar support was taken from \"hdate\" by Amos Shapir. The
supported languages and their translators are listed below. Languages
marked \"complete\" support error messages in that language; all others
only support the substitution filter mechanism and month/day names.
**German** \-- Wolfgang Thronicke
**Dutch** \-- Willem Kasdorp and Erik-Jan Vens
**Finnish** \-- Mikko Silvonen (complete)
**French** \-- Laurent Duperval (complete)
**Norwegian** \-- Trygve Randen
**Danish** \-- Mogens Lynnerup
**Polish** \-- Jerzy Sobczyk (complete)
**Brazilian Portuguese** \-- Marco Paganini (complete)
**Italian** \-- Valerio Aimale
**Romanian** \-- Liviu Daia
**Spanish** \-- Rafa Couto
**Icelandic** \-- Björn Davíðsson
# BUGS
If you find a bug in Remind, please report it to: dianne@skoll.ca
There\'s no good reason why read-only system variables are not
implemented as functions, or why functions like **version()**, etc. are
not implemented as read-only system variables.
Hebrew dates in **Remind** change at midnight instead of sunset.
**Remind** has some built-in limits (for example, number of global
**OMIT**s.)
# BIBLIOGRAPHY
Nachum Dershowitz and Edward M. Reingold, \"Calendrical Calculations\",
*Software-Practice and Experience*, Vol. 20(9), Sept. 1990, pp 899-928.
L. E. Doggett, *Almanac for computers for the year 1978*, Nautical
Almanac Office, USNO.
Richard Siegel and Michael and Sharon Strassfeld, *The First Jewish*
Catalog, Jewish Publication Society of America.
Jean Meeus, *Astronomical Algorithms, Second Edition*, Willmann-Bell,
Inc.
# HOME PAGE
https://dianne.skoll.ca/projects/remind/
# MAILING LIST
https://dianne.skoll.ca/mailman/listinfo/remind-fans
# SEE ALSO
**rem**(1), **rem2ps**(1), **rem2pdf**(1), **tkremind**(1),
**rem2html**(1)