From 05f9d94067c09a6a76a9753e618fa9a6d4d5509f Mon Sep 17 00:00:00 2001 From: Paolo Donadeo Date: Sun, 10 May 2026 01:47:31 +0200 Subject: [PATCH] DOC: Remind manual in Markdown replaced with a simple txt --- contrib/remind/remind.md | 7234 ------------------------------ contrib/remind/remind_manual.txt | 5302 ++++++++++++++++++++++ 2 files changed, 5302 insertions(+), 7234 deletions(-) delete mode 100644 contrib/remind/remind.md create mode 100644 contrib/remind/remind_manual.txt diff --git a/contrib/remind/remind.md b/contrib/remind/remind.md deleted file mode 100644 index 90c9681..0000000 --- a/contrib/remind/remind.md +++ /dev/null @@ -1,7234 +0,0 @@ -# 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 - \"<\"; \"\>\" is replaced with \">\" and \"&\" is replaced - with \"&\" - -**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 \"\\" - -**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 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) diff --git a/contrib/remind/remind_manual.txt b/contrib/remind/remind_manual.txt new file mode 100644 index 0000000..1373da9 --- /dev/null +++ b/contrib/remind/remind_manual.txt @@ -0,0 +1,5302 @@ +REMIND(1) VERSION 06.02.05 REMIND(1) + +NAME + remind - a sophisticated reminder service + +THE BOOK OF REMIND + This man page is a good reference for Remind. However, if you are a novice wishing to learn Remind, I suggest + downloading "The Book of Remind" from the Remind home page at https://dianne.skoll.ca/projects/remind/ + +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 re‐ + minders 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 com‐ + puter-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, ac‐ + cepting 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 re‐ + minders 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 "RE‐ + MINDER 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 num‐ + ber 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 en‐ + coding. This flag also enables the use of the UNICODE "left-to-right" mark that can fix up for‐ + matting problems with right-to-left languages in the calendar display. + + 'z' has the effect of setting the system variable $TerminalHyperlinks to 1. See the documentation of + this variable in the section "SYSTEM VARIABLES" + + '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 op‐ + tion 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 documenta‐ + tion 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 approxi‐ + mation 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 termi‐ + nal 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 back‐ + ground is dark, and Remind will brighten up dark colors to make them visible. If m=1, then Remind as‐ + sumes 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 impossi‐ + ble 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. + + -wcol[,pad[,spc[,spc2]]]] + 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 stan‐ + dard 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. spc2 may be 0 or 1 and it specifies whether or not blank lines + should be printed in between reminders on the same day. The default is 1, which causes the blank lines + to be printed. + + 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 en‐ + ables 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 out‐ + put. + + Note that to pass INFO strings to a back-end, you must use -pp or -ppp. The simpler -p format is not ca‐ + pable 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 vari‐ + able. + + -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, re‐ + gardless 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 re‐ + minders 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 re‐ + minders in the calendar if at least one -a option is used.) + + -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. + + -dchars + 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 + + p Issue warnings if a POP-OMIT-CONTEXT, POP-VARS or POP-FUNCS matches a corresponding PUSH that is + in a different file. + + 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 com‐ + mands: + + 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 %(...) substitu‐ + tion 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 char‐ + acters 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 de‐ + fault 0. A value of 0 causes times to be inserted in 12-hour (am/pm) format. 1 causes times to be in‐ + serted 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. + + -kcmd 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 -kcmd1 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. + + -uname 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, us‐ + ing -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 vari‐ + ables 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. + + -ivar=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, -ivar is exactly the same as -ivar=0. + + -ifunc(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 no‐ + tion 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 de‐ + tails. 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 run‐ + ning: + + 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.) + + --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 sensi‐ + ble 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 op‐ + tion 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 back‐ + slash 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, parame‐ + ters, invocation options, etc. + +THE REM COMMAND + The most powerful command in a Remind script is the REM command. This command is responsible for issuing re‐ + minders. 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 com‐ + mand-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 us‐ + age 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 para‐ + graph-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 con‐ + secutive 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 sys‐ + tem 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 re‐ + minder depends on the back-end. For the Rem2PS back-end, SPECIAL PostScript is equivalent to a PS-type re‐ + minder, 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 par‐ + ticular 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 TRIG‐ + GER 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 key‐ + word 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 compo‐ + nent 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 ver‐ + sions 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 PRI‐ + ORITY 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 re‐ + minder 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 spec‐ + ified 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 con‐ + sidered "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 "omit‐ + ted". 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 spe‐ + cific 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 automati‐ + cally 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 repre‐ + senting 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 reaches 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 is‐ + sued 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 al‐ + lows precise control over the advance triggering of all types of reminders. However, discussion must be de‐ + ferred until after expressions and user-defined functions are explained. See the subsection "PRECISE SCHEDUL‐ + ING" 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 syn‐ + thesized 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_strings they recognize, and must ignore info_strings 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 can‐ + not 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 stan‐ + dard 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 dig‐ + its. + + %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 ac‐ + tual number of days between these two dates; OMITs are not counted. (Strict date subtraction is per‐ + formed.) + + %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. + + % + 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 new‐ + line. + + %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:mmam" 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-nega‐ + tive. + + %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 com‐ + pared. + + %? 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 com‐ + pared. + + %@ 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 "CAL‐ + ENDAR 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 $Ad‐ + dBlankLines 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 exam‐ + ple, %*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 re‐ + minder. 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 sub‐ + stituted 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, meet‐ + ings, 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 ex‐ + ample: + + 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. The keyword COMPLETED-THROUGH may be + used as a synonym for COMPLETE-THROUGH. + +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 Re‐ + mind'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 week‐ + ends. + + 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 ad‐ + vanced 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 equiv‐ + alent: + + 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 exam‐ + ple, 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: Sup‐ + pose 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 direc‐ + tive. 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 recom‐ + mended!) 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 subdirecto‐ + ries!) 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 contain‐ + ing standard reminder scripts. For this installation of Remind, the system directory is "/usr/local/share/re‐ + mind". + +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 un‐ + desired actions. The RUN command can restrict this: If you include the command RUN OFF in your top-level re‐ + minder 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 re‐ + minder script; it will not work in any files accessed by the INCLUDE command. This is to protect you from some‐ + one 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() func‐ + tion. 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 ap‐ + propriate 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 it‐ + self 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 exe‐ + cuted. 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 im‐ + plicit 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 intro‐ + duce 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 corre‐ + sponds to the C "int" type. + + STRING The STRING data type consists of strings of characters. It is somewhat comparable to a C character ar‐ + ray, 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, and several more. + These are not safe to use on multi-byte strings; instead use mbindex, mbstrlen and mbsubstr, and the mb + variants of the others. 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. + + TIME The TIME data type is used for two different purposes: To represent a time of day with one-minute preci‐ + sion or to represent a duration with one-minute precision. The context of where a TIME is used deter‐ + mines 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 inter‐ + nally 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. + + 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", "", "π is Cool! 🙂" + + 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, op‐ + tionally 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, re‐ + turns 1. + + - Unary minus. Can be applied to an INT. Returns the negative of the operand. + + * Multiplication. Returns the product of two INTs. 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 INTs, 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 INTs. + + INT + TIME or TIME + INT - returns a TIME obtained by adding INT minutes to the original TIME. The re‐ + sult 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 STRINGs. + + 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 INTs. + + DATE - DATE - returns (as an INT) the difference in days between two DATEs. + + TIME - TIME - returns (as an INT) the difference in minutes between two TIMEs. + + DATETIME - DATETIME - returns (as an INT) the difference in minutes between two DATETIMEs. + + 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 in‐ + equality. + + 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 other‐ + wise. 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 -ivar=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 con‐ + trol 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. + + $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 $MinsFro‐ + mUTC 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 dae‐ + mon 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 consid‐ + ered 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. Con‐ + sider 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 fol‐ + lowing: + + 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 re‐ + minders 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, $De‐ + faultDelta 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 -tn 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 char‐ + acters. 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 pe‐ + riod. + + $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 out‐ + put 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 represen‐ + tation, this will be 2147483647. + + $IntMin (read-only) + The smallest representable INT. On a machine with 32-bit signed integers using twos-complement represen‐ + tation, 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" lo‐ + cale 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 nega‐ + tive 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 lat‐ + itude 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 rea‐ + sons, 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 re‐ + minder 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. The de‐ + fault value is 10,000. + + $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 un‐ + til 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 your‐ + self. 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 fol‐ + lows: 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 re‐ + minders. 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 sec‐ + tion "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 Re‐ + mind 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. + + $Shaded (read-only) + Returns the number of times a SHADE special reminder has triggered. This variable is set only in calen‐ + dar mode, not agenda mode. You can use this variable to avoid shading a calendar day that has already + been shaded. + + For example, suppose you want to shade all calendar boxes yellow if any reminders have triggered on that + day. But if a box has been explicitly shaded, you don't want to overwrite that shading. You could use + something like this: + + SET n $NumTrig + # Do all your reminders here... + + # If anything has triggered and the box is + # not already shaded, then shade it yellow + IF $NumTrig > n && !$Shaded + REM SPECIAL SHADE 255 255 128 + ENDIF + + $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 de‐ + scending 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 prior‐ + ity 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 de‐ + scending 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 $SuppressImplicit‐ + Warnings to 1 suppresses these warnings. The default is 0 and we do not recommend disabling the warn‐ + ings. + + $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 holi‐ + day files and language packs. The value of $SysInclude is "/usr/local/share/remind" on this installa‐ + tion. + + $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. + + $TerminalHyperlinks (INT type) + If your terminal supports escape sequences to allow HTML-like anchors around text (see + https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda), then you can set this variable to 1. + Remind will then make any reminder with a "Url:" info string into a hyperlink in your terminal. By de‐ + fault, $TerminalHyperlinks is set to 1 if Remind's standard output is a terminal, or to 0 if it is not. + + $WarningLevel (STRING type) + As new versions of Remind are released, new warnings may be added. If your formerly-fine scripts sud‐ + denly start issuing warnings when you upgrade Remind, then as a stopgap measure, you may set $Warn‐ + ingLevel 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 $Warn‐ + ingLevel, 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, $Don‐ + tQueue, $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) sys‐ + tem 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 vari‐ + ables 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 fol‐ + lowed 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 re‐ + turns 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 to‐ + day(). + + 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, re‐ + spectively; 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; other‐ + wise, 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 parame‐ + ters red, green and blue are integers from 0 to 255 specifying the value of the respective color compo‐ + nent. As a special case, all three values can be -1, in which case the ANSI sequence "ESC[0m" is re‐ + turned, 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 ansi‐ + color(-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-de‐ + fined function exists. Note that this function examines only user-defined functions, not built-in func‐ + tions. 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 evalu‐ + ation 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 speci‐ + fied 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) re‐ + turns "". + + 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 nth sub‐ + sequent 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: + + 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 mid‐ + night. 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 either standard output or standard error is + a TTY, returns the width of the terminal in columns. If neither standard output nor standard error is 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 with‐ + out 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 charac‐ + ters 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 gen‐ + erated 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 sec‐ + ond 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 compo‐ + nent 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, re‐ + turns 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 sub‐ + stitution 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-es‐ + caped. 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 com‐ + puted. + + 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 No‐ + vember, 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 be‐ + fore 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: + + 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() re‐ + turns the directory containing the symbolic link and not the directory containing the target of the sym‐ + bolic 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, re‐ + turns 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 environ‐ + ment variable. Returns "" if the environment variable is not defined. Note that the names of environ‐ + ment 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 "<"; ">" is replaced with ">" and "&" is + replaced with "&" + + 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 in‐ + terpreted 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; re‐ + turns 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 ex‐ + pression but evaluated in a non-constant context, isconst will still return 1. For details about con‐ + stant 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 de‐ + faults 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 start‐ + ing 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 date‐ + time 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 bytes in string converted to lower-case. Note: This function works + correctly only for ASCII strings. If you are using Unicode characters outside the ASCII set, use mblower + instead. + + mblower(s_string) + Returns a STRING with all upper-case characters in string converted to lower-case. This function works + correctly on any Unicode string. + + 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 speci‐ + fied 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 start‐ + ing 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() func‐ + tions are accurate to within a couple of minutes of the times in "Old Farmer's Almanac" for Ottawa, On‐ + tario. + + 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, re‐ + spectively. The returned value is an integer from 0 to 359, representing the phase of the moon in de‐ + grees. 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 mid‐ + night 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 moon‐ + rise 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 mid‐ + night 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 earli‐ + est 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 week‐ + days 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 Wednes‐ + day, 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 plas‐ + tic 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 de‐ + tails, 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. Note that in Calendar Mode, now() always returns 00:00. + + 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 bytes, pads + to to len bytes 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" + + mbpad(x_arg, s_padstr, i_len [, i_right]) + This is the multibyte counterpart to pad. The length is specified in characters rather than bytes. Use + mbpad rather than pad if either of the strings contains non-ASCII characters. + + 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 Post‐ + Script 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 Post‐ + Script 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, or 00:00 in Calendar Mode. + + realtoday() + Returns the date as provided by the operating system. This is in contrast to Remind's concept of "to‐ + day", which may be changed if it is running in calendar mode, or if a date has been supplied on the com‐ + mand line. + + rows() If either standard output or standard error is a TTY, returns the height of the terminal in rows. If + neither standard output nor standard error is 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: + + 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 stepth 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 speci‐ + fies 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 sup‐ + plied, 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 lati‐ + tudes, 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 sup‐ + plied, 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 com‐ + mand line, or (in Calendar Mode) 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 de‐ + tails 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 com‐ + mand, 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 trigdate‐ + time(). If the REM command did not have an AT clause, returns the integer -1 (and differs from trigdate‐ + time() 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 informa‐ + tion. + + 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 trig‐ + ger 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 "re‐ + peat" 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 SCAN‐ + FROM 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 pa‐ + rameter, 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 calcu‐ + late 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 trig‐ + gered. Returns the empty string if there were no TAGs. If there are multiple tags, they are each sepa‐ + rated 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: + + 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. + + upper(s_string) + Returns a STRING with all lower-case bytes in string converted to upper-case. Note: This function works + correctly only for ASCII strings. If you are using Unicode characters outside the ASCII set, use mbupper + instead. + + mbupper(s_string) + Returns a STRING with all lower-case characters in string converted to upper-case. This function works + correctly on any Unicode string. + + 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.05, returns "06.02.05". It is + guaranteed that as new versions of Remind are released, the value returned by version() will strictly in‐ + crease, 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 (follow‐ + ing 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 can‐ + not 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 cor‐ + rects 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: + + 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: + + ["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 in‐ + voked, 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 se‐ + quentially. 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 exe‐ + cuted. + + 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; in‐ + stead, 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 de‐ + fault, 1000.) + + o If a user-defined function has the same name as a built-in function, it is ignored and the built-in func‐ + tion is used. To prevent conflicts with future versions of Remind (which may define more built-in func‐ + tions), 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 en‐ + abled. + + 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. Con‐ + sider 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 re‐ + named 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. Alterna‐ + tively, 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 in‐ + ternal 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 previ‐ + ously 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 in‐ + stead 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 OMITted 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_func‐ + tion 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 re‐ + minder. 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 re‐ + minder 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 re‐ + minder, 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 re‐ + quired. 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 com‐ + mand-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 trig‐ + date() 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 trig‐ + ger 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 pow‐ + erful. 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 re‐ + sults, as the OMIT context can change depending on the current date. For example, if you use the following com‐ + mand 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 Septem‐ + ber, 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 op‐ + tions 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 "" + + 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 pro‐ + cessing. Any queued timed reminders are discarded. If you are in calendar mode (described next), then the cal‐ + endar 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 ar‐ + ray: + + 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 de‐ + scribed 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 to‐ + day'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 calen‐ + dar. + + 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 %"...%" se‐ + quence, 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 in‐ + serted 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 com‐ + mand. 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 itera‐ + tions. + + Note that for efficiency, Remind caches the reminder script (and any INCLUDEd 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 re‐ + minders. 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 re‐ + peat 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 -ivar=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 op‐ + tions. + + 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: + + -ifunc(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 re‐ + minder 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 PS‐ + FILE-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 pri‐ + ority. 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 Post‐ + Script-type reminders are triggered for a single day, each section of PostScript is not enclosed in a save-re‐ + store 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 bot‐ + tom 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 bor‐ + der 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: + + 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 docu‐ + ment 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 file‐ + name 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 com‐ + pare 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 com‐ + ments 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 re‐ + minders 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-con‐ + stant 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 environ‐ + ment (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 as‐ + sumed to be non-constant. A non-constant context is the code in the scope of an IF statement where the IF ex‐ + pression 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-con‐ + stant. 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 imme‐ + diately, 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 speci‐ + fies 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. Re‐ + minders 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 ar‐ + gument, 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 prior‐ + ity-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 calsuf‐ + fix() can be defined. They work with all reminders that produce an entry in the calendar (i.e., CAL- and possi‐ + bly 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 mes‐ + sages. 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 lan‐ + guage. 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 lan‐ + guage. 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 lan‐ + guage. Note that $Am and $Pm should be the translations of "AM" and "PM" (morning and afternoon time in‐ + dicators) 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 unpre‐ + dictable. + + 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 Re‐ + mind'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 over‐ + rides the substitution sequence "%N". The three arguments are an integer alt which, if non-zero, indi‐ + cates 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" se‐ + quence 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 ta‐ + ble that maps one string (the original string) to a new string (the translated string.) When Remind starts exe‐ + cuting, 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 transla‐ + tion-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 encour‐ + aged 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 let‐ + ter 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. If you are in a UTF-8 locale, you can also use the + UTF-8-encoded Hebrew spellings for the month names, namely: + + תשרי, חשוון, כסלו, טבת, שבט, אדר, ניסן, אייר, סיון, תמוז, אב, אלול. + + 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, or in Hebrew, + 'אדר א and 'אדר ב. + + Remind also permits the following alternative spellings for Hebrew month names: + + Tishrey + Can also be spelled Tishri or Tishrei + + Heshvan + Can also be spelled Cheshvan or Kheshvan + + Shvat Can also be spelled Shevat + + Tamuz Can also be spelled Tammuz + + Adar A Can also be spelled Adar 1, Adar I, אדר א or אדר 1. + + Adar B Can also be spelled Adar 2, Adar II, אדר ב or אדר 2. + + Iyar Can also be spelled Iyyar. + + 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 pe‐ + riod 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 cor‐ + responds 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". + + ivritmon(d_date) + Returns the name of the Hebrew month corresponding to date, in UTF-8-encoded Hebrew script. For example, + ivritmon('1993/04/12') returns "ניסן". + + 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 ar‐ + guments. 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 parame‐ + ter 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 either the English transliteration shown previously, or the Hebrew spelling + encoded in UTF-8. 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 de‐ + scribed 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 Ashke‐ + nazim 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 excep‐ + tion; it works similarly to MSG when the -p option is not supplied.) + + The various SPECIALs recognized are particular for each backend; however, there are four SPECIALs that all back‐ + ends 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 inter‐ + preted 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 ter‐ + minal. + + 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: "(Wn)" 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 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 OMITs.) + +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 Amer‐ + ica. + + 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) + +Remind 2026-03-02 REMIND(1)