mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-16 06:18:47 +02:00
Compare commits
105 Commits
05.05.00
...
06.00.00-B
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bf23912ae | ||
|
|
6ae0340137 | ||
|
|
0e48ace855 | ||
|
|
d1f1ddf5b7 | ||
|
|
5f9e227dc8 | ||
|
|
b770676cb6 | ||
|
|
5ee415c2fb | ||
|
|
6c2a4b66fd | ||
|
|
6c2d65c08e | ||
|
|
cd2dc3bea3 | ||
|
|
b1b80316ab | ||
|
|
f04835cf6f | ||
|
|
fb19ea6b7e | ||
|
|
e2d7796d4a | ||
|
|
de2ec1aa7b | ||
|
|
b9fb215d9d | ||
|
|
a62ed0e0c5 | ||
|
|
eceb5e3f82 | ||
|
|
d5aa93ae57 | ||
|
|
a66da78b4a | ||
|
|
af69f54bff | ||
|
|
a000a7f17e | ||
|
|
582f388500 | ||
|
|
7762f4f2d6 | ||
|
|
31c9b2afb7 | ||
|
|
119e954e9e | ||
|
|
6aa07edffd | ||
|
|
bdb9ad1a5d | ||
|
|
05384fe7cf | ||
|
|
6125001e55 | ||
|
|
78b307e387 | ||
|
|
460d0a8d88 | ||
|
|
add35377ad | ||
|
|
fccd9ed42e | ||
|
|
a49ecccb34 | ||
|
|
ae9fe78817 | ||
|
|
dbc5576312 | ||
|
|
6cbbebceaf | ||
|
|
4dc27ca7f5 | ||
|
|
d8f97ce0f1 | ||
|
|
0e1a80f2bd | ||
|
|
4a7f703ab5 | ||
|
|
101de948b2 | ||
|
|
0e2d382b33 | ||
|
|
a6c5c3cb90 | ||
|
|
da573929ee | ||
|
|
5217d9b675 | ||
|
|
79a87c6f1a | ||
|
|
cde5ffc84a | ||
|
|
6ef323a4f0 | ||
|
|
8331ea2991 | ||
|
|
db28648d9d | ||
|
|
1a5915bba9 | ||
|
|
94a50fa22c | ||
|
|
fad6076568 | ||
|
|
287039ac40 | ||
|
|
8523218ef2 | ||
|
|
fdaaf2b57a | ||
|
|
19eac9b8d5 | ||
|
|
cda4877229 | ||
|
|
0976cd64f3 | ||
|
|
10f7889ef2 | ||
|
|
2391ff4bc7 | ||
|
|
d21ae56deb | ||
|
|
773980afa6 | ||
|
|
46a80da0e1 | ||
|
|
23516aebcb | ||
|
|
b48ce0b245 | ||
|
|
e4c090374d | ||
|
|
39fcbb72fd | ||
|
|
5f2bf48752 | ||
|
|
9e5354fcb8 | ||
|
|
49bdd135f7 | ||
|
|
f9a6aba81d | ||
|
|
175772d959 | ||
|
|
2f03c75826 | ||
|
|
d617000e95 | ||
|
|
04dee13996 | ||
|
|
ebcf6fd534 | ||
|
|
c7c58e20f3 | ||
|
|
a66ca7cce7 | ||
|
|
35cae5f97c | ||
|
|
6d86d88037 | ||
|
|
89f60358c6 | ||
|
|
781e5a6acd | ||
|
|
1b5d34e5e6 | ||
|
|
cb5fa62022 | ||
|
|
9d6ce5b674 | ||
|
|
1cdd9531a5 | ||
|
|
da4633fab3 | ||
|
|
aeff3606d2 | ||
|
|
2af36b7241 | ||
|
|
a7a22d20a2 | ||
|
|
3fdbf8b3bc | ||
|
|
a7696d659c | ||
|
|
865ebae6f8 | ||
|
|
f21f8ee8d0 | ||
|
|
76b7736266 | ||
|
|
0769e3e9cb | ||
|
|
d9ab9e91b5 | ||
|
|
9199ed5cf7 | ||
|
|
68a4b23b6f | ||
|
|
814dd51270 | ||
|
|
59fdf70732 | ||
|
|
24ed30fee0 |
17
README.md
17
README.md
@@ -6,10 +6,14 @@ the GNU General Public License, Vesion 2.
|
||||
|
||||
## Prerequisites:
|
||||
|
||||
remind and rem2ps have no prerequisites beyond the standard C library and
|
||||
the standard math library.
|
||||
### Remind and Rem2PS
|
||||
|
||||
rem2html requires the JSON::MaybeXS Perl module and rem2pdf
|
||||
**remind** and **rem2ps** have no prerequisites beyond the standard C
|
||||
library and the standard math library.
|
||||
|
||||
### Rem2HTML and Rem2PDF
|
||||
|
||||
**rem2html** requires the JSON::MaybeXS Perl module and **rem2pdf**
|
||||
requires the JSON::MaybeXS, Pango and Cairo Perl modules.
|
||||
|
||||
- On Debian-like systems, these prerequisites may be installed with:
|
||||
@@ -24,7 +28,9 @@ requires the JSON::MaybeXS, Pango and Cairo Perl modules.
|
||||
|
||||
- On Arch linux, you need `pango-perl`, `cairo-perl` and `perl-json-maybexs`
|
||||
|
||||
TkRemind requires Tcl/Tk and the tcllib library.
|
||||
### TkRemind
|
||||
|
||||
**tkremind** requires Tcl/Tk and the tcllib library.
|
||||
|
||||
- On Debian-like systems, install with:
|
||||
|
||||
@@ -45,7 +51,8 @@ all of your distribution's Noto Font-related packages.
|
||||
|
||||
## Installation
|
||||
|
||||
Remind can be installed with the usual:
|
||||
Assuming you have a normal C development environment installed, Remind
|
||||
can be installed with the usual:
|
||||
|
||||
`./configure && make && make test && sudo make install`
|
||||
|
||||
|
||||
18
configure
vendored
18
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.72 for remind 05.05.00.
|
||||
# Generated by GNU Autoconf 2.72 for remind 06.00.00.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation,
|
||||
@@ -601,8 +601,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='remind'
|
||||
PACKAGE_TARNAME='remind'
|
||||
PACKAGE_VERSION='05.05.00'
|
||||
PACKAGE_STRING='remind 05.05.00'
|
||||
PACKAGE_VERSION='06.00.00'
|
||||
PACKAGE_STRING='remind 06.00.00'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL='https://dianne.skoll.ca/projects/remind/'
|
||||
|
||||
@@ -1258,7 +1258,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
'configure' configures remind 05.05.00 to adapt to many kinds of systems.
|
||||
'configure' configures remind 06.00.00 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1320,7 +1320,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of remind 05.05.00:";;
|
||||
short | recursive ) echo "Configuration of remind 06.00.00:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1408,7 +1408,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
remind configure 05.05.00
|
||||
remind configure 06.00.00
|
||||
generated by GNU Autoconf 2.72
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
@@ -1871,7 +1871,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by remind $as_me 05.05.00, which was
|
||||
It was created by remind $as_me 06.00.00, which was
|
||||
generated by GNU Autoconf 2.72. Invocation command line was
|
||||
|
||||
$ $0$ac_configure_args_raw
|
||||
@@ -4787,7 +4787,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by remind $as_me 05.05.00, which was
|
||||
This file was extended by remind $as_me 06.00.00, which was
|
||||
generated by GNU Autoconf 2.72. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -4852,7 +4852,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config='$ac_cs_config_escaped'
|
||||
ac_cs_version="\\
|
||||
remind config.status 05.05.00
|
||||
remind config.status 06.00.00
|
||||
configured by $0, generated by GNU Autoconf 2.72,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT(remind, 05.05.00, , , https://dianne.skoll.ca/projects/remind/)
|
||||
AC_INIT(remind, 06.00.00, , , https://dianne.skoll.ca/projects/remind/)
|
||||
AC_CONFIG_SRCDIR([src/queue.c])
|
||||
|
||||
cat <<'EOF'
|
||||
|
||||
@@ -110,16 +110,16 @@
|
||||
(defconst remind-keywords
|
||||
(sort
|
||||
(list "ADDOMIT" "AFTER" "AT" "BAN" "BANNER" "BEFORE" "CAL" "CLEAR"
|
||||
"CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMP" "DUMPVARS"
|
||||
"CLEAR-OMIT-CONTEXT" "COMPLETE-THROUGH" "DEBUG" "DO" "DUMP" "DUMPVARS"
|
||||
"DURATION" "ELSE" "ENDIF" "ERRMSG" "EXIT" "EXPR" "FIRST"
|
||||
"FLUSH" "FOURTH" "FRENAME" "FROM" "FSET" "FUNSET" "IF"
|
||||
"IFTRIG" "IN" "INC" "INCLUDE" "INCLUDECMD" "INFO" "LAST"
|
||||
"LASTDAY" "LASTWORKDAY" "MAYBE" "MAYBE-UNCOMPUTABLE" "MSF"
|
||||
"LASTDAY" "LASTWORKDAY" "MAX-OVERDUE" "MAYBE" "MAYBE-UNCOMPUTABLE" "MSF"
|
||||
"MSG" "NOQUEUE" "OMIT" "OMITFUNC" "ONCE" "POP"
|
||||
"POP-OMIT-CONTEXT" "POP-FUNCS" "POP-VARS" "PRESERVE" "PRIORITY" "PS"
|
||||
"PSFILE" "PUSH" "PUSH-FUNCS" "PUSH-VARS" "PUSH-OMIT-CONTEXT" "REM"
|
||||
"PSFILE" "PUSH" "PUSH-FUNCS" "PUSH-VARS" "PUSH-OMIT-CONTEXT" "REM" "RETURN"
|
||||
"RUN" "SATISFY" "SCAN" "SCANFROM" "SCHED" "SECOND" "SET"
|
||||
"SKIP" "SPECIAL" "SYSINCLUDE" "TAG" "THIRD" "THROUGH"
|
||||
"SKIP" "SPECIAL" "SYSINCLUDE" "TAG" "THIRD" "THROUGH" "TODO"
|
||||
"TRANSLATE" "TRANS" "UNSET" "UNTIL" "WARN")
|
||||
#'(lambda (a b) (> (length a) (length b)))))
|
||||
|
||||
@@ -137,8 +137,8 @@
|
||||
"$DefaultPrio" "$DefaultTDelta" "$DeltaOverride"
|
||||
"$DontFork" "$DontQueue" "$DontTrigAts" "$EndSent" "$EndSentIg"
|
||||
"$ExpressionTimeLimit" "$February" "$FirstIndent" "$FoldYear"
|
||||
"$FormWidth" "$Friday" "$Fromnow" "$Hour" "$Hplu" "$HushMode"
|
||||
"$IgnoreOnce" "$InfDelta" "$IntMax" "$IntMin" "$Is" "$January" "$July"
|
||||
"$FormWidth" "$Friday" "$Fromnow" "$HideCompletedTodos" "$Hour" "$Hplu" "$HushMode"
|
||||
"$IgnoreOnce" "$InfDelta" "$IntMax" "$IntMin" "$Is" "$January" "$JSONMode" "$July"
|
||||
"$June" "$LatDeg" "$Latitude" "$LatMin" "$LatSec" "$Location"
|
||||
"$LongDeg" "$Longitude" "$LongMin" "$LongSec" "$March" "$MaxFullOmits"
|
||||
"$MaxLateMinutes" "$MaxPartialOmits" "$MaxSatIter" "$MaxStringLen"
|
||||
@@ -148,7 +148,7 @@
|
||||
"$PrefixLineNo" "$PSCal" "$RunOff" "$Saturday" "$September"
|
||||
"$SimpleCal" "$SortByDate" "$SortByPrio" "$SortByTime" "$SubsIndent"
|
||||
"$Sunday" "$SuppressImplicitWarnings" "$SuppressLRM" "$SysInclude" "$T" "$Tb" "$Td"
|
||||
"$TerminalBackground" "$Thursday" "$TimeSep" "$TimetIs64bit" "$Tm" "$Today"
|
||||
"$TerminalBackground" "$Thursday" "$TimeSep" "$TimetIs64bit" "$Tm" "$Today" "$TodoFilter"
|
||||
"$Tomorrow" "$Tt" "$Tuesday" "$Tw" "$Ty" "$U" "$Ud" "$Um"
|
||||
"$UntimedFirst" "$Use256Colors" "$UseBGVTColors" "$UseTrueColors"
|
||||
"$UseVTColors" "$Uw" "$Uy" "$Was" "$Wednesday")
|
||||
@@ -178,9 +178,9 @@
|
||||
"ostype" "pad" "plural" "psmoon" "psshade" "realcurrent" "realnow"
|
||||
"realtoday" "rows" "sgn" "shell" "shellescape" "slide" "soleq"
|
||||
"stdout" "strlen" "substr" "sunrise" "sunset" "time" "timepart"
|
||||
"timezone" "today" "trig" "trigback" "trigbase" "trigdate" "trigdatetime"
|
||||
"timezone" "today" "trig" "trigback" "trigbase" "trigcompletethrough" "trigdate" "trigdatetime"
|
||||
"trigdelta" "trigduration" "trigeventduration" "trigeventstart"
|
||||
"trigfrom" "trigger" "triginfo" "trigpriority" "trigrep"
|
||||
"trigfrom" "trigger" "triginfo" "trigistodo" "trigmaxoverdue" "trigpriority" "trigrep"
|
||||
"trigscanfrom" "trigtags" "trigtime" "trigtimedelta" "trigtimerep"
|
||||
"triguntil" "trigvalid" "typeof" "tzconvert" "upper" "utctolocal"
|
||||
"value" "version" "weekno" "wkday" "wkdaynum" "year"
|
||||
|
||||
@@ -1,5 +1,61 @@
|
||||
CHANGES TO REMIND
|
||||
|
||||
* VERSION 6.0 Patch 0 - 2025-??-??
|
||||
|
||||
- MAJOR NEW FEATURE: remind: Introduction of TODOs. These are similar
|
||||
to normal reminders, but (in Agenda Mode) you keep getting reminded
|
||||
of them even once they are in the past, unless you specifically mark
|
||||
them as completed.
|
||||
|
||||
- MAJOR NEW FEATURE: remind: The --json long option causes Remind to
|
||||
output JSON in Agenda Mode instead of the normal text output. See
|
||||
tkremind for an example of how a front-end can use this output.
|
||||
|
||||
- MINOR NEW FEATURE: remind: The RETURN statement can be used to skip
|
||||
the rest of the current file. Useful for early exit from an
|
||||
INCLUDEd file.
|
||||
|
||||
- MINOR NEW FEATURE: remind: Allow the %:, %!, %?, %@ and %#
|
||||
substitution sequences to be overridden by defining the functions
|
||||
subst_colon, subst_bang, subst_question, subst_at and subst_hash,
|
||||
respectively.
|
||||
|
||||
- MAJOR IMPROVEMENTS: tkremind: TkRemind has been given an overhaul.
|
||||
The "Show Queue" and "Show Today's Reminders" windows now respect
|
||||
the color scheme. TkRemind lets you create TODO reminders and
|
||||
easily mark them completed. You can right-click on a day number
|
||||
to get a window with Agenda Mode reminders for that day.
|
||||
|
||||
- MINOR IMPROVEMENT: remind: Language packs can define an ordx(n)
|
||||
function that localizes ord(n). If this function is defined, then
|
||||
ord(n) automatically calls it rather than using its built-in English
|
||||
localization. Appropriate ordx(n) definitions have been added to
|
||||
all language packs.
|
||||
|
||||
- MINOR IMPROVEMENT: remind: The %b substitution sequence handles
|
||||
dates in the past (because of TODOs). The %! sequence considers
|
||||
both date and time, and can be used with non-timed reminders. The
|
||||
new %? sequence is similar to %!, but outputs "are" and "were"
|
||||
instead of "is" and "was". The new %*! and %*? sequences are
|
||||
similar to %! and %?, but compare the trigger date to realtoday()
|
||||
instead of to today().
|
||||
|
||||
- MINOR IMPROVEMENT: remind: Downgrade a SPECIAL COLOR... with
|
||||
out-of-range color values to a normal MSG-type reminder.
|
||||
|
||||
- MINOR IMPROVEMENT: include/lang/nl.rem: Use "eergisteren" for "2
|
||||
days ago" and "overmorgen" for "in 2 days' time."
|
||||
|
||||
- MINOR IMPROVEMENT: tkremind: TkRemind now passes all command-line
|
||||
options back to Remind.
|
||||
|
||||
- BUG FIX: tkremind: In a couple of places, the "eval" command was used
|
||||
where the intention was to use "catch". I blame Perl...
|
||||
|
||||
- BUG FIX: remind: SCANFROM and FROM are separated out internally, and
|
||||
in the JSON output, the original FROM or SCANFROM value is
|
||||
preserved, including relative SCANFROMs.
|
||||
|
||||
* VERSION 5.5 Patch 0 - 2025-07-28
|
||||
|
||||
- NEW FEATURE: remind: Add the PUSH-VARS / POP-VARS commands and the
|
||||
@@ -18,7 +74,7 @@ CHANGES TO REMIND
|
||||
- MINOR CHANGE: remind: All functions that want an integer month number
|
||||
will now also accept a string naming the month.
|
||||
|
||||
= UPDATE: include/holidays/chinese-new-year.rem: Add dates for Chinese
|
||||
- UPDATE: include/holidays/chinese-new-year.rem: Add dates for Chinese
|
||||
New Year for 2051 through 2100.
|
||||
|
||||
- BUG FIX: remind: Set trigdate() correctly for a fully-specified
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
if !defined("ansi_bold")
|
||||
# Disable ANSI attributes in calandar mode
|
||||
if $CalMode
|
||||
# Disable ANSI attributes in calendar mode or JSON mode
|
||||
if $CalMode || $PSCal || $JSONMode
|
||||
set ansi_normal ""
|
||||
set ansi_bold ""
|
||||
set ansi_faint ""
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
# Major Jewish Holidays
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
# Save variables and functions that we will mess with
|
||||
PUSH-VARS InIsrael IncludeIsraeliHolidays Reform
|
||||
PUSH-FUNCS _chan _h2 _PastSat _BackTwoFri _BackTwoSat
|
||||
|
||||
# Set the variable InIsrael to 1 if you live in Israel. Otherwise,
|
||||
# you get the Diaspora versions of Jewish holidays
|
||||
SET InIsrael value("InIsrael", 0)
|
||||
|
||||
# Set this if you want to include holidays that are not really
|
||||
# Jewish religious holidays, but simply Israeli holidays
|
||||
SET IncludeIsraeliHolidays value("IncludeIsraeliHolidays", 0)
|
||||
|
||||
# Set the variable Reform to 1 if you want the Reform version of the
|
||||
# Jewish calendar. Otherwise, you get the traditional version
|
||||
SET Reform value("Reform", 0)
|
||||
@@ -80,15 +88,18 @@ IF !InIsrael && !Reform
|
||||
ENDIF
|
||||
|
||||
REM [hebdate(27, "Nisan")] INFO "Url: https://en.wikipedia.org/wiki/Yom_HaShoah" MSG Yom HaShoah
|
||||
REM [_BackTwoFri(4, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Yom_HaZikaron" MSG Yom HaZikaron
|
||||
REM [_BackTwoSat(5, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Independence_Day_(Israel)" MSG Yom Ha'atzmaut
|
||||
|
||||
IF IncludeIsraeliHolidays
|
||||
REM [_BackTwoFri(4, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Yom_HaZikaron" MSG Yom HaZikaron
|
||||
REM [_BackTwoSat(5, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Independence_Day_(Israel)" MSG Yom Ha'atzmaut
|
||||
REM [hebdate(28, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Jerusalem_Day" MSG Yom Yerushalayim
|
||||
ENDIF
|
||||
|
||||
# Not sure about Reform's position on Lag B'Omer
|
||||
IF !Reform
|
||||
REM [hebdate(18, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Lag_BaOmer" MSG Lag B'Omer
|
||||
ENDIF
|
||||
|
||||
REM [hebdate(28, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Jerusalem_Day" MSG Yom Yerushalayim
|
||||
REM [hebdate(6, "Sivan")] INFO "Url: https://en.wikipedia.org/wiki/Shavuot" MSG Shavuot
|
||||
|
||||
IF !InIsrael && !Reform
|
||||
@@ -102,3 +113,7 @@ IF !Reform
|
||||
REM [_PastSat(17, "Tamuz")] INFO "Url: https://en.wikipedia.org/wiki/Seventeenth_of_Tammuz" MSG Tzom Tammuz
|
||||
REM [_PastSat(9, "Av")] INFO "Url: https://en.wikipedia.org/wiki/Tisha_B%27Av" MSG Tish'a B'Av
|
||||
ENDIF
|
||||
|
||||
# Tidy up
|
||||
POP-FUNCS
|
||||
POP-VARS
|
||||
|
||||
@@ -1,29 +1,32 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
if !defined("__autolang__")
|
||||
SET __autolang__ 1
|
||||
PRESERVE __autolang__
|
||||
PUSH-VARS autolang
|
||||
SET autolang getenv("REMIND_LANG")
|
||||
if defined("__autolang__")
|
||||
RETURN
|
||||
endif
|
||||
|
||||
IF autolang == ""
|
||||
SET autolang getenv("LC_ALL")
|
||||
ENDIF
|
||||
IF autolang == ""
|
||||
SET autolang getenv("LANGUAGE")
|
||||
ENDIF
|
||||
IF autolang == ""
|
||||
SET autolang getenv("LANG")
|
||||
ENDIF
|
||||
SET __autolang__ 1
|
||||
PRESERVE __autolang__
|
||||
|
||||
IF autolang != ""
|
||||
IF access($SysInclude + "/lang/" + lower(substr(autolang, 1, 5)) + ".rem", "r") == 0
|
||||
SYSINCLUDE lang/[lower(substr(autolang, 1, 5))].rem
|
||||
ELSE
|
||||
IF access($SysInclude + "/lang/" + lower(substr(autolang, 1, 2)) + ".rem", "r") == 0
|
||||
SYSINCLUDE lang/[lower(substr(autolang, 1, 2))].rem
|
||||
ENDIF
|
||||
ENDIF
|
||||
ENDIF
|
||||
POP-VARS
|
||||
PUSH-VARS autolang
|
||||
SET autolang getenv("REMIND_LANG")
|
||||
|
||||
IF autolang == ""
|
||||
SET autolang getenv("LC_ALL")
|
||||
ENDIF
|
||||
IF autolang == ""
|
||||
SET autolang getenv("LANGUAGE")
|
||||
ENDIF
|
||||
IF autolang == ""
|
||||
SET autolang getenv("LANG")
|
||||
ENDIF
|
||||
|
||||
IF autolang != ""
|
||||
IF access($SysInclude + "/lang/" + lower(substr(autolang, 1, 5)) + ".rem", "r") == 0
|
||||
SYSINCLUDE lang/[lower(substr(autolang, 1, 5))].rem
|
||||
ELSE
|
||||
IF access($SysInclude + "/lang/" + lower(substr(autolang, 1, 2)) + ".rem", "r") == 0
|
||||
SYSINCLUDE lang/[lower(substr(autolang, 1, 2))].rem
|
||||
ENDIF
|
||||
ENDIF
|
||||
ENDIF
|
||||
POP-VARS
|
||||
|
||||
|
||||
@@ -28,7 +28,12 @@ SET $December "desembre"
|
||||
|
||||
SET $Today "avui"
|
||||
SET $Tomorrow "demà"
|
||||
FSET subst_bx(a,d,t) iif(d==today()+2, "demà passat", "d'aquí " + (d-today()) + " dies")
|
||||
TRANSLATE "yesterday" "ahir"
|
||||
TRANSLATE "are" "són"
|
||||
TRANSLATE "were" "eren"
|
||||
TRANSLATE "done" "completada"
|
||||
|
||||
FSET subst_bx(a,d,t) iif(d==today()+2, "demà passat", d >= today(), "d'aquí " + (d-today()) + " dies", "fa " + (today()-d) + " dies")
|
||||
|
||||
# 1 d'abril vs 1 de maig.
|
||||
FSET subst_sx(a,d,t) iif(isany(substr(mon(d), 1, 1), "a", "o") , "d'", "de")
|
||||
|
||||
@@ -29,6 +29,11 @@ SET $December "December"
|
||||
SET $Today "i dag"
|
||||
SET $Tomorrow "i morgen"
|
||||
|
||||
TRANSLATE "yesterday" "i går"
|
||||
TRANSLATE "are" "er"
|
||||
TRANSLATE "were" "var"
|
||||
TRANSLATE "done" "fuldført"
|
||||
|
||||
BANNER Påmindelse for %w, %d. %m, %y%o:
|
||||
|
||||
SET $Am "am"
|
||||
@@ -51,13 +56,14 @@ SET $Mplu "ter"
|
||||
|
||||
FSET subst_ampm(h) iif(h<5, " om natten", h < 12, " om formiddagen", h < 18, " om eftermiddagen", " om aftenen")
|
||||
FSET subst_ordinal(d) "."
|
||||
FSET ordx(n) n + "."
|
||||
|
||||
FSET subst_p(alt, d, t) iif(d==today()+1, "", "e")
|
||||
FSET zeropad(s, len) pad(s, "0", len)
|
||||
FSET subst_a_alt(d) wkday(d) + ", den " + day(d) + ". " + mon(d) + " " + year(d)
|
||||
FSET subst_ax(alt, d, t) iif(alt, subst_a_alt(d), $On + " " + subst_a_alt(d))
|
||||
|
||||
FSET subst_bx(a, d, t) "om " + (d-today()) + " dage"
|
||||
FSET subst_bx(a, d, t) iif(d >= today(), "om " + (d-today()) + " dage", "for " + (today()-d) + " dage siden")
|
||||
|
||||
FSET subst_ex(alt, d, t) "den " + zeropad(day(d), 2) + $DateSep + zeropad(monnum(d), 2) + $DateSep + zeropad(year(d), 4)
|
||||
FSET subst_fx(alt, d, t) "den " + zeropad(monnum(d), 2) + $DateSep + zeropad(day(d), 2) + $DateSep + zeropad(year(d), 4)
|
||||
|
||||
@@ -31,6 +31,11 @@ SET $December "Dezember"
|
||||
SET $Today "heute"
|
||||
SET $Tomorrow "morgen"
|
||||
|
||||
TRANSLATE "yesterday" "gestern"
|
||||
TRANSLATE "are" "sind"
|
||||
TRANSLATE "were" "waren"
|
||||
TRANSLATE "done" "abgeschlossen"
|
||||
|
||||
# Banner
|
||||
BANNER Termine für %w, den %d. %m %y%o:
|
||||
|
||||
@@ -51,11 +56,12 @@ SET $Fromnow "von heute"
|
||||
|
||||
FSET subst_ampm(h) iif(h<5, " nachts", h<12, " vormittags", h<=17, " nachmittags", " abends")
|
||||
FSET subst_ordinal(d) "."
|
||||
FSET ordx(n) n + "."
|
||||
|
||||
FSET subst_a_alt(d) wkday(d) + ", den " + day(d) + ". " + mon(d) + " " + year(d)
|
||||
FSET subst_ax(alt, d, t) iif(alt, subst_a_alt(d), $On + " " + subst_a_alt(d))
|
||||
|
||||
FSET subst_bx(a, d, t) "in " + (d-today()) + " Tagen"
|
||||
FSET subst_bx(a, d, t) iif(d >= today(), "in " + (d-today()) + " Tagen", "vor " + (today()-d) + " Tagen")
|
||||
|
||||
FSET subst_g_alt(d) wkday(d) + ", den " + day(d) + ". " + mon(d)
|
||||
FSET subst_gx(alt, d, t) iif(alt, subst_g_alt(d), $On + " " + subst_g_alt(d))
|
||||
|
||||
@@ -29,6 +29,11 @@ SET $December "Diciembre"
|
||||
SET $Today "hoy"
|
||||
SET $Tomorrow "mañana"
|
||||
|
||||
TRANSLATE "yesterday" "ayer"
|
||||
TRANSLATE "are" "son"
|
||||
TRANSLATE "were" "eran"
|
||||
TRANSLATE "done" "completada"
|
||||
|
||||
BANNER Agenda para el %w, %d%s %m, %y%o:
|
||||
|
||||
SET $Am "am"
|
||||
@@ -47,4 +52,4 @@ SET $And "y"
|
||||
SET $Hplu "s"
|
||||
SET $Mplu "s"
|
||||
|
||||
FSET subst_bx(a, d, t) "dentro de " + (d-today()) + " días"
|
||||
FSET subst_bx(a, d, t) iif(d >= today(), "dentro de " + (d-today()) + " días", "hace " + (today()-d) + " dias")
|
||||
|
||||
@@ -29,6 +29,11 @@ SET $December "joulukuu"
|
||||
SET $Today "tänään"
|
||||
SET $Tomorrow "huomenna"
|
||||
|
||||
TRANSLATE "yesterday" "eilen"
|
||||
TRANSLATE "are" "ovat"
|
||||
TRANSLATE "were" "olivat"
|
||||
TRANSLATE "done" "suoritettu"
|
||||
|
||||
BANNER Viestit %wna %d. %mta %y%o:
|
||||
|
||||
SET $Am " ap."
|
||||
@@ -52,11 +57,12 @@ SET $Mplu "a"
|
||||
FSET zeropad(s, len) pad(s, "0", len)
|
||||
|
||||
FSET subst_ordinal(d) iif(d==1, ":senä", d==2, ":sena", (d%10)==2||(d%10)==3||(d%10)==6||(d%10)==8, ":ntena", ":ntenä")
|
||||
FSET ordx(d) d + subst_ordinal(d)
|
||||
|
||||
FSET subst_a_alt(d, o, p) wkday(d) + o + " " + day(d) + ". " + mon(d) + p + " " + year(d)
|
||||
FSET subst_ax(a, d, t) iif(a, subst_a_alt(d, "", ""), subst_a_alt(d, $On, "ta"))
|
||||
|
||||
FSET subst_bx(a, d, t) (d-today()) + " päivän kuluttua"
|
||||
FSET subst_bx(a, d, t) iif(d >= today(), (d-today()) + " päivän kuluttua", (today()-d) + " päivää sitten")
|
||||
FSET subst_cx(a, d, t) iif(a, wkday(d), wkday(d) + $On)
|
||||
|
||||
FSET subst_ex(a, d, t) zeropad(day(d), 2) + $DateSep + zeropad(monnum(d), 2) + $DateSep + zeropad(year(d), 4)
|
||||
|
||||
@@ -28,6 +28,12 @@ SET $December "décembre"
|
||||
|
||||
SET $Today "aujourd'hui"
|
||||
SET $Tomorrow "demain"
|
||||
|
||||
TRANSLATE "yesterday" "hier"
|
||||
TRANSLATE "are" "sont"
|
||||
TRANSLATE "were" "étaient"
|
||||
TRANSLATE "done" "accomplie"
|
||||
|
||||
SET $On "le"
|
||||
SET $At "à"
|
||||
SET $Now "maintenant"
|
||||
@@ -46,6 +52,7 @@ BANNER Rappels pour %w, %d%s %m, %y%o:
|
||||
|
||||
# Ordinal for a day (English would be "st", "nd", "rd", "th")
|
||||
FSET subst_ordinal(d) iif(d == 1, "er", "")
|
||||
FSET ordx(n) n + iif(n == 1, "er", "e")
|
||||
|
||||
# "%d hours", "%d minutes", or "%d hours and %d minutes"
|
||||
FSET subst_tdiff(hdiff, mdiff) iif(hdiff==0&&mdiff==0, $Now, \
|
||||
@@ -56,13 +63,14 @@ FSET subst_1(alt, date, time) iif(time == now(), "maintenant", \
|
||||
time > now(), "dans " + subst_tdiff((time-now())/60, (time-now())%60), \
|
||||
"il y a " + subst_tdiff ((now()-time)/60, (now()-time)%60))
|
||||
|
||||
FSET subst_bx(alt, date, time) "dans " + (date-today()) + " jours"
|
||||
FSET subst_bx(alt, date, time) iif(date >= today(), "dans " + (date-today()) + " jours", "il y a " + (today()-date) + " jours")
|
||||
FSET subst_j_alt(date) wkday(date) + ", " + day(date) + subst_ordinal(day(date)) + " " + mon(date) + ", " + year(date)
|
||||
FSET subst_jx(alt, date, time) iif(alt, subst_j_alt(date), $On + " " + subst_j_alt(date))
|
||||
|
||||
FSET subst_k_alt(date) wkday(date) + ", " + day(date) + subst_ordinal(day(date)) + " " + mon(date)
|
||||
FSET subst_kx(alt, date, time) iif(alt, subst_k_alt(date), $On + " " + subst_k_alt(date))
|
||||
|
||||
|
||||
TRANSLATE "Missing ']'" "']' manquant"
|
||||
TRANSLATE "Missing quote" "Apostrophe manquant"
|
||||
TRANSLATE "Expression too complex" "Expression trop complexe"
|
||||
|
||||
@@ -29,6 +29,11 @@ SET $December "Δεκέμβρ."
|
||||
SET $Today "σήμερα"
|
||||
SET $Tomorrow "αύριο"
|
||||
|
||||
TRANSLATE "yesterday" "εχθές"
|
||||
TRANSLATE "are" "είναι"
|
||||
TRANSLATE "were" "ήταν"
|
||||
TRANSLATE "done" "ολοκληρώθηκε"
|
||||
|
||||
BANNER Υπενθυμίσεις: %w, %d %m, %y%o:
|
||||
|
||||
SET $Am "πμ"
|
||||
@@ -49,8 +54,9 @@ SET $And "και"
|
||||
SET $Hplu ""
|
||||
SET $Mplu ""
|
||||
|
||||
FSET subst_bx(a, d, t) "σε " + (d - today()) + " ημέρες"
|
||||
FSET subst_bx(a, d, t) iif(d >= today(), "σε " + (d - today()) + " ημέρες", "πριν από " + (today()-d) + " ημέρες")
|
||||
FSET subst_ordinal(d) "."
|
||||
FSET ordx(d) d + "."
|
||||
FSET subst_a_alt(d) wkday(d) + ", " + day(d) + ". " + mon(d) + " " + year(d)
|
||||
FSET subst_ax(alt, d, t) iif(alt, subst_a_alt(d), $On + " " + subst_a_alt(d))
|
||||
FSET subst_g_alt(d) wkday(d) + ", " + day(d) + ". " + mon(d)
|
||||
|
||||
@@ -29,6 +29,11 @@ SET $December "desember"
|
||||
SET $Today "í dag"
|
||||
SET $Tomorrow "á morgun"
|
||||
|
||||
TRANSLATE "yesterday" "í gær"
|
||||
TRANSLATE "are" "eru"
|
||||
TRANSLATE "were" "voru"
|
||||
TRANSLATE "done" "lokið"
|
||||
|
||||
BANNER Minnisatriði: %w, %d%s %m, %y%o:
|
||||
|
||||
SET $Am "fh"
|
||||
@@ -49,5 +54,5 @@ SET $And "og"
|
||||
SET $Hplu "ir"
|
||||
SET $Mplu "r"
|
||||
|
||||
FSET subst_bx(a, d, t) "eftir " + (d - today()) + " daga"
|
||||
FSET subst_bx(a, d, t) iif(d >= today(), "eftir " + (d - today()) + " daga", "fyrir " + (today()-d) + " dögum")
|
||||
fset subst_p(a, d, t) iif(d == today()+1, "", "a")
|
||||
|
||||
@@ -29,6 +29,11 @@ SET $December "Dicembre"
|
||||
SET $Today "oggi"
|
||||
SET $Tomorrow "domani"
|
||||
|
||||
TRANSLATE "yesterday" "Ieri"
|
||||
TRANSLATE "are" "sono"
|
||||
TRANSLATE "were" "erano"
|
||||
TRANSLATE "done" "completato"
|
||||
|
||||
BANNER Promemoria per %w, %d %m %y%o:
|
||||
|
||||
SET $Am "am"
|
||||
@@ -48,7 +53,7 @@ SET $And "e"
|
||||
SET $Hplu "a"
|
||||
SET $Mplu "i"
|
||||
|
||||
FSET subst_bx(a, d, t) "fra " + (d-today()) + " giorni"
|
||||
FSET subst_bx(a, d, t) iif(d >= today(), "fra " + (d-today()) + " giorni", (today()-d) + " giorni fa")
|
||||
FSET subst_p(a, d, t) iif(d==today()+1, "o", "i")
|
||||
FSET subst_q(a, d, t) iif(d==today()+1, "a", "e")
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ SET $December "december"
|
||||
|
||||
SET $Today "vandaag"
|
||||
SET $Tomorrow "morgen"
|
||||
TRANSLATE "yesterday" "gisteren"
|
||||
TRANSLATE "are" "zijn"
|
||||
TRANSLATE "were" "waren"
|
||||
TRANSLATE "done" "voltooid"
|
||||
|
||||
BANNER Herinneringen voor %w, %d %m, %y%o:
|
||||
|
||||
@@ -55,9 +59,12 @@ FSET subst_1b(hdiff, mdiff) iif(hdiff==0, subst_minutes(mdiff), mdiff==0, subst_
|
||||
FSET subst_minutes(m) iif(m==1, "1 minuut", m + " minuten")
|
||||
FSET subst_hours(h) iif(h==1, "1 uur", h + " uren")
|
||||
|
||||
FSET subst_bx(a, d, t) "over " + (d-today()) + " dagen"
|
||||
FSET subst_bx(a, d, t) iif (d == today()+2, "overmorgen", d+2 == today(), "eergisteren", d >= today(), "over " + (d-today()) + " dagen", (today()-d) + " dagen geleden")
|
||||
|
||||
FSET subst_s(a, d, t) iif(day(d) == 1 || day(d) == 8, "e", day(d) < 20, "de", "te")
|
||||
|
||||
FSET ordx(n) n + "e"
|
||||
|
||||
TRANSLATE "New Moon" "Nieuwe maan"
|
||||
TRANSLATE "First Quarter" "Eerste kwartier"
|
||||
TRANSLATE "Full Moon" "Volle maan"
|
||||
|
||||
@@ -29,6 +29,11 @@ SET $December "Desember"
|
||||
SET $Today "i dag"
|
||||
SET $Tomorrow "i morgen"
|
||||
|
||||
TRANSLATE "yesterday" "i går"
|
||||
TRANSLATE "are" "er"
|
||||
TRANSLATE "were" "var"
|
||||
TRANSLATE "done" "fullført"
|
||||
|
||||
BANNER Påminnelse for %w, %d. %m, %y%o:
|
||||
|
||||
SET $Am "am"
|
||||
@@ -48,8 +53,9 @@ SET $And "og"
|
||||
SET $Hplu "r"
|
||||
SET $Mplu "er"
|
||||
|
||||
FSET subst_bx(a, d, t) "om " + (d-today()) + " dager"
|
||||
FSET subst_bx(a, d, t) iif(d >= today(), "om " + (d-today()) + " dager", "for " + (today()-d) + " dager siden")
|
||||
FSET subst_ordinal(d) "."
|
||||
FSET ordx(n) n + "."
|
||||
|
||||
FSET subst_ax(a, d, t) iif(a, subst_a_alt(d), $On + " " + subst_a_alt(d))
|
||||
FSET subst_a_alt(d) wkday(d) + ", den " + day(d) + ". " + mon(d) + " " + year(d)
|
||||
|
||||
@@ -29,6 +29,11 @@ SET $December "Grudzień"
|
||||
SET $Today "dzisiaj"
|
||||
SET $Tomorrow "jutro"
|
||||
|
||||
TRANSLATE "yesterday" "wczoraj"
|
||||
TRANSLATE "are" "są"
|
||||
TRANSLATE "were" "byli"
|
||||
TRANSLATE "done" "ukończone"
|
||||
|
||||
BANNER Terminarz na %w, %d. %m %y%o:
|
||||
|
||||
SET $Am "am"
|
||||
@@ -53,7 +58,7 @@ FSET subst_ordinal(d) ""
|
||||
|
||||
FSET subst_a_alt(d) wkday(d) + ", " + day(d) + ". " + mon(d) + " " + year(d)
|
||||
FSET subst_ax(a, d, t) iif(a, subst_a_alt(d), $On + " " + subst_a_alt(d))
|
||||
FSET subst_bx(a, d, t) "za " + (d-today()) + " dni"
|
||||
FSET subst_bx(a, d, t) iif(d >= today(), "za " + (d-today()) + " dni", (today()-d) + " dni temu")
|
||||
FSET subst_g_alt(d) wkday(d) + ", " + day(d) + ". " + mon(d)
|
||||
FSET subst_gx(a, d, t) iif(a, subst_g_alt(d), $On + " " + subst_g_alt(d))
|
||||
FSET subst_ux(a, d, t) subst_ax(a, d, t)
|
||||
|
||||
@@ -29,6 +29,11 @@ SET $December "dezembro"
|
||||
SET $Today "hoje"
|
||||
SET $Tomorrow "amanhã"
|
||||
|
||||
TRANSLATE "yesterday" "ontem"
|
||||
TRANSLATE "are" "são"
|
||||
TRANSLATE "were" "eram"
|
||||
TRANSLATE "done" "concluída"
|
||||
|
||||
BANNER Avisos para %w, %d de %m de %y%o:
|
||||
|
||||
SET $Am "am"
|
||||
@@ -53,7 +58,7 @@ FSET subst_ordinal(d) ""
|
||||
FSET subst_on_wd(d) iif(wkdaynum(d) == 1 || wkdaynum(d) == 2, "no", "na")
|
||||
|
||||
FSET subst_a_alt(d) wkday(d) + ", " + day(d) + " de " + mon(d) + " de " + year(d)
|
||||
FSET subst_bx(a, d, t) "em " + (d-today()) + " dias"
|
||||
FSET subst_bx(a, d, t) iif(d >= today(), "em " + (d-today()) + " dias", "há " + (today()-d) + " dias")
|
||||
FSET subst_c_alt(d) wkday(d)
|
||||
FSET subst_g_alt(d) wkday(d) + ", " + day(d) + " " + mon(d)
|
||||
FSET subst_ax(a, d, t) iif(a, subst_a_alt(d), subst_on_wd(d) + " " + subst_a_alt(d))
|
||||
|
||||
@@ -28,6 +28,10 @@ SET $December "Decembrie"
|
||||
|
||||
SET $Today "astăzi"
|
||||
SET $Tomorrow "mâine"
|
||||
TRANSLATE "yesterday" "ieri"
|
||||
TRANSLATE "are" "sunt"
|
||||
TRANSLATE "were" "au fost"
|
||||
TRANSLATE "done" "finalizată"
|
||||
|
||||
BANNER Reamintiri pentru %w, %d %m %y%o:
|
||||
|
||||
@@ -49,7 +53,7 @@ SET $Mplu "e"
|
||||
SET $Hplu "e"
|
||||
SET $And "şi"
|
||||
|
||||
FSET subst_bx(a, d, t) "peste " + (d-today()) + " zile"
|
||||
FSET subst_bx(a, d, t) iif(d >= today(), "peste " + (d-today()) + " zile", "acume " + (today()-d) + " zile")
|
||||
|
||||
FSET subst_ampm(h) iif(h<4, " noaptea", h<12, " dimineaţa", h<18, " după-amiaza", " seara")
|
||||
FSET subst_ordinal(d) ""
|
||||
|
||||
@@ -622,14 +622,27 @@ will be present. Its value will be a string of the form YYYY-MM-DD.
|
||||
If the reminder contains a ONCE keyword, this key will be present
|
||||
with a value of 1.
|
||||
.TP
|
||||
.B scanfrom \fIYYYY-MM-DD\fR
|
||||
.B scanfrom \fIYYYY-MM-DD\fR or \fBscanfrom\fR \fI-n\fR
|
||||
If the reminder contains a SCANFROM keyword, this key will be present
|
||||
and its value will be a string of the form YYYY-MM-DD.
|
||||
and its value will be a string of the form YYYY-MM-DD for an absolute
|
||||
SCANFROM, or a negative integer of the form -n for a relative scanfrom
|
||||
.TP
|
||||
.B from \fIYYYY-MM-DD\fR
|
||||
If the reminder contains a FROM keyword, this key will be present
|
||||
and its value will be a string of the form YYYY-MM-DD.
|
||||
.TP
|
||||
.B is_todo \fIflag\fR
|
||||
If the reminder is a TODO reminder, then \fIflag\fR will be the integer
|
||||
1. Otherwise, it will be the integer zero.
|
||||
.TP
|
||||
.B complete_through \fIYYYY-MM-DD\fR
|
||||
If the reminder has a COMPLETE-THROUGH date, then this key will be present
|
||||
and its value will be a string of the form YYYY-MM-DD.
|
||||
.TP
|
||||
.B max_overdue \fIn\fR
|
||||
If the reminder has a MAX-OVERDUE clause, then this key will be present and
|
||||
its value will be the integer argument to MAX-OVERDUE.
|
||||
.TP
|
||||
.B priority \fIn\fR
|
||||
The priority of the reminder. Always present; if no PRIORITY keyword
|
||||
is specified, then a reminder has a default priority of 5000.
|
||||
|
||||
341
man/remind.1.in
341
man/remind.1.in
@@ -25,6 +25,29 @@ match the sort order used by the shell to expand "*.rem".
|
||||
until it encounters a line whose sole content is "__EOF__" (without the quotes.)
|
||||
Anything after the __EOF__ marker is completely ignored.
|
||||
|
||||
.SH MODES OF OPERATION
|
||||
\fBRemind\fR has four major modes of operation:
|
||||
.TP
|
||||
.B Agenda Mode
|
||||
Agenda mode is the default mode. In this mode, \fBRemind\fR 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.
|
||||
.TP
|
||||
.B Calendar Mode
|
||||
In this mode, \fBRemind\fR 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.
|
||||
.TP
|
||||
.B Daemon Mode
|
||||
This is a special mode of operation in which \fBRemind\fR 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.
|
||||
\fBTkRemind\fR uses \fBRemind\fR in daemon mode.
|
||||
.TP
|
||||
.B Purge Mode
|
||||
In this mode, \fBRemind\fR produces no output, but creates new versions of
|
||||
its input files with all expired reminders commented out.
|
||||
|
||||
.SH OPTIONS
|
||||
\fBRemind\fR has a slew of options. If you're new to the program,
|
||||
ignore them for now and skip to the section "REMINDER FILES".
|
||||
@@ -209,7 +232,7 @@ format rather than the "simple calendar" format. This format is
|
||||
also documented in the \fBrem2ps(1)\fR man page. Finally, if you use
|
||||
three p's, as in \fB\-ppp\fR, then \fBRemind\fR uses a pure JSON
|
||||
format, again documented in \fBrem2ps(1)\fR. If you include a \fBq\fR
|
||||
letter with this option, then the normal calendar-mode substitution filter
|
||||
letter with this option, then the usual calendar-mode substitution filter
|
||||
is disabled and the %"...%" sequences are preserved in the output.
|
||||
.PP
|
||||
Note that to pass INFO strings to a back-end, you must use \fB\-pp\fR
|
||||
@@ -509,11 +532,33 @@ information.
|
||||
\fBRemind\fR supports the following long options, which \fIare\fR
|
||||
case-sensitive:
|
||||
|
||||
.PP
|
||||
.TP
|
||||
.B \-\-version
|
||||
The \fB\-\-version\fR option causes \fBRemind\fR to print its version number
|
||||
to standard output and then exit.
|
||||
.TP
|
||||
.B \-\-hide-completed-todos
|
||||
In Calendar Mode, \fBRemind\fR normally shows all TODOs. If you supply
|
||||
this option, the it will not show TODOs that have been marked as
|
||||
completed.
|
||||
.TP
|
||||
.B \-\-only-todos
|
||||
Only issue TODO-type reminders.
|
||||
.TP
|
||||
.B \-\-only-events
|
||||
Do not issue TODO-type reminders.
|
||||
.TP
|
||||
.B \-\-json
|
||||
In Agenda Mode, output JSON instead of the normal text-mode output.
|
||||
\fB\-\-json\fR also disables sorting (the \fB-g\fR option) and
|
||||
disables queueing (the \fB-q\fR option). See the section "AGENDA MODE
|
||||
JSON OUTPUT" for more details. The \fB\-\-json\fR option is ignored
|
||||
in Calendar Mode. Note that in JSON mode, the output from any
|
||||
\fBRUN\fR-type reminder that would normally appear on standard output
|
||||
is redirected to standard error instead; this is so that \fBRUN\fR-type
|
||||
reminders don't mess up the output and cause invalid JSON to be produced
|
||||
on standard output.
|
||||
.TP
|
||||
.B \-\-print-errs
|
||||
The \fB\-\-print-errs\fR option causes \fBRemind\fR to print all
|
||||
possible error messages to standard output and then exit. The
|
||||
@@ -626,6 +671,9 @@ Its syntax is:
|
||||
[\fIback\fR]
|
||||
[\fIdelta\fR]
|
||||
[\fIrepeat\fR]
|
||||
[\fBTODO\fR]
|
||||
[\fBMAX-OVERDUE\fR \fIn\fR]
|
||||
[\fBCOMPLETE-THROUGH\fR \fIcomplete_date\fR]
|
||||
[\fBPRIORITY\fR \fIprio\fR]
|
||||
[\fBSKIP\fR | \fBBEFORE\fR | \fBAFTER\fR]
|
||||
[\fBOMIT\fR \fIomit_list\fR]
|
||||
@@ -1777,8 +1825,16 @@ is replaced with "s" if the value produced by \fB%8\fR is not 1.
|
||||
is replaced with "s" if the value produced by \fB%7\fR is not 1.
|
||||
.TP
|
||||
.B %!
|
||||
is replaced with "is" if the current time is before the \fBAT\fR time,
|
||||
or "was" if it is after.
|
||||
is replaced with "is" if the current date and time is before the
|
||||
trigger date and the \fBAT\fR time, or "was" if it is after. The \fB%!\fR
|
||||
sequence may be used in a non-timed reminder, in which case only dates
|
||||
are compared.
|
||||
.TP
|
||||
.B %?
|
||||
is replaced with "are" if the current date and time is before the
|
||||
trigger date and the \fBAT\fR time, or "were" if it is after. The \fB%?\fR
|
||||
sequence may be used in a non-timed reminder, in which case only dates
|
||||
are compared.
|
||||
.TP
|
||||
.B %@
|
||||
is similar to \fB%2\fR but displays the current time.
|
||||
@@ -1786,9 +1842,17 @@ is similar to \fB%2\fR but displays the current time.
|
||||
.B %#
|
||||
is similar to \fB%3\fR but displays the current time.
|
||||
.TP
|
||||
.B %:
|
||||
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 \fBRemind\fR does not
|
||||
display completed TODO reminders in Agenda Mode, this escape sequence
|
||||
is really only useful in Calendar Mode.
|
||||
.TP
|
||||
.B
|
||||
%"
|
||||
(percent-doublequote - ") is removed. This sequence is not
|
||||
.\" "
|
||||
(percent-doublequote) is removed. This sequence is not
|
||||
used by the substitution filter,
|
||||
but is used to tell \fBRemind\fR which text to include in a calendar
|
||||
entry when the \fB\-c\fR, \fB\-s\fR or \fB\-p\fR option is chosen.
|
||||
@@ -1812,20 +1876,25 @@ sequences.
|
||||
.TP
|
||||
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
|
||||
be preceded by an asterisk (for example, \fB%*c\fR) which causes the word
|
||||
"at" or "on" that would normally be included in the output to be
|
||||
omitted.
|
||||
.TP
|
||||
o
|
||||
Any of the substitutions dealing with time (0 through 9 and '!')
|
||||
produce undefined results if used in a reminder that does not have
|
||||
an \fBAT\fR keyword. Also, if a reminder has a \fIdelta\fR and may
|
||||
be triggered on several days, the time substitutions ignore the date. Thus,
|
||||
the \fB%1\fR substitution may report that a meeting is in 15 minutes, for
|
||||
example, even though it may only be in 2 days time, because a \fIdelta\fR has
|
||||
triggered the reminder. It is recommended that you use the time substitutions
|
||||
only in timed reminders with no \fIdelta\fR that are designed to be
|
||||
queued for timed activation.
|
||||
The ! and ? substitutions may be preceded by an asterisk (\fB%*!\fR or \fB%*?\fR),
|
||||
in which case the comparison is made between the trigger date and
|
||||
realtoday() instead of today().
|
||||
.TP
|
||||
o
|
||||
Any of the substitutions dealing with time (0 through 9) produce
|
||||
undefined results if used in a reminder that does not have an \fBAT\fR
|
||||
keyword. Also, if a reminder has a \fIdelta\fR and may be triggered
|
||||
on several days, the time substitutions ignore the date. Thus, the
|
||||
\fB%1\fR substitution may report that a meeting is in 15 minutes, for
|
||||
example, even though it may only be in 2 days time, because a
|
||||
\fIdelta\fR has triggered the reminder. It is recommended that you
|
||||
use the time substitutions only in timed reminders with no \fIdelta\fR
|
||||
that are designed to be queued for timed activation.
|
||||
.TP
|
||||
o
|
||||
Capital letters can be used in the substitution sequence, in which case
|
||||
@@ -1843,6 +1912,130 @@ normally scans for the first non-space character after a
|
||||
or
|
||||
.B RUN
|
||||
token.
|
||||
.PP
|
||||
.SH EVENTS AND TODOS
|
||||
.PP
|
||||
The \fBREM\fR command is normally used to create an \fIEVENT\fR. 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,
|
||||
\fBRemind\fR will no longer remind you about the event.
|
||||
.PP
|
||||
A \fITODO\fR 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, \fBRemind\fR will keep reminding you about it \fIeven past
|
||||
the due date.\fR.
|
||||
.PP
|
||||
To mark a \fBREM\fR as a TODO, simply include the TODO keyword. For example:
|
||||
.PP
|
||||
.nf
|
||||
REM TODO 15 August 2025 ++5 MSG Buy cat food %b.
|
||||
.fi
|
||||
.PP
|
||||
In Agenda Mode, \fBRemind\fR will start warning you on 10 Aug 2025 that
|
||||
you have to but cat food in 5 days' time, 4 days' time, etc...
|
||||
.PP
|
||||
However, on 16 Aug 2025, \fBRemind\fR 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.
|
||||
.PP
|
||||
.SH MARKING TODOS AS DONE
|
||||
.PP
|
||||
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.
|
||||
.PP
|
||||
If a TODO is recurring, use the \fBCOMPLETE-THROUGH\fR clause to mark
|
||||
which recurrences have been completed. For example:
|
||||
.PP
|
||||
.nf
|
||||
REM TODO 30 April ++15 COMPLETE-THROUGH 2025-04-30 MSG File taxes
|
||||
.fi
|
||||
.PP
|
||||
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, \fBRemind\fR 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 \fBRemind\fR will start
|
||||
reminding you of your 2027 taxes (starting 15 days before the due
|
||||
date.)
|
||||
.PP
|
||||
It is an error to specify COMPLETE-THROUGH without also specifying TODO.
|
||||
.PP
|
||||
.SH LIMITING REMINDERS ABOUT OVERDUE TODOS
|
||||
.PP
|
||||
Although \fBRemind\fR is happy to keep reminding you about overdue
|
||||
TODOs for hundreds of years, for some things this may be pointless.
|
||||
If you want \fBRemind\fR to \fIstop\fR nagging you about an overdue
|
||||
TODO after a certain number of days, use the MAX-OVERDUE \fIn\fR clause.
|
||||
In this case, \fBRemind\fR stops reminding you of a TODO that is overdue
|
||||
by more than \fIn\fR days. Here is an example.
|
||||
.PP
|
||||
.nf
|
||||
REM TODO 2025-08-13 ++5 MAX-OVERDUE 5 MSG Task: %b.
|
||||
.fi
|
||||
.PP
|
||||
\fBRemind\fR \fIstarts\fR 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, \fBRemind\fR will no longer remind you of the task
|
||||
since it's probably pointless---it has passed the MAX-OVERDUE period.
|
||||
.PP
|
||||
.SH MORE DETAILS ABOUT TODOS
|
||||
.PP
|
||||
TODOs are treated specially only in Agenda Mode. In Calendar Mode,
|
||||
they appear in the calendar exactly as a normal event would.
|
||||
.PP
|
||||
TODOs are implemented internally by using the COMPLETE-THROUGH date
|
||||
plus one day as the starting point for \fBRemind\fR's date-scanning
|
||||
algorithm. If you have a recurring TODO without a COMPLETE-THROUGH
|
||||
clause, then \fBRemind\fR starts scanning from the beginning of time,
|
||||
which we all know is 1 January 1990. Consider this command:
|
||||
.PP
|
||||
.nf
|
||||
REM TODO Wed +7 MSG Take out the trash %a (%b)
|
||||
.fi
|
||||
.PP
|
||||
Running that command in Agenda Mode on 2025-08-13 yields the following output:
|
||||
.PP
|
||||
.nf
|
||||
Take out the trash on Wednesday, 3 January, 1990 (13006 days ago)
|
||||
.fi
|
||||
.PP
|
||||
\fBRemind\fR is very persistent about reminding you of tasks! If you take
|
||||
out the trash and mark it done:
|
||||
.PP
|
||||
.nf
|
||||
REM TODO Wed +7 COMPLETE-THROUGH 2025-08-13 MSG Take out the trash %a (%b)
|
||||
.fi
|
||||
.PP
|
||||
then you get this:
|
||||
.PP
|
||||
.nf
|
||||
Take out the trash on Wednesday, 20 August, 2025 (in 7 days' time)
|
||||
.fi
|
||||
.PP
|
||||
You can use \fBFROM\fR and \fBUNTIL\fR 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:
|
||||
.PP
|
||||
.nf
|
||||
REM TODO Wed +7 FROM 2025-08-06 UNTIL 2025-08-27 MSG Plants %b.
|
||||
.fi
|
||||
.PP
|
||||
Running that command on 13 Aug yields: "Plants 7 days ago." because you
|
||||
have not told \fBRemind\fR that you completed the first watering. If you finish
|
||||
your duties and add a COMMPLETE-THROUGH date of 2025-08-27, then \fBRemind\fR
|
||||
never reminds you of that task in the future.
|
||||
.PP
|
||||
In Purge Mode, \fBRemind\fR will not purge TODOs unless they have been marked
|
||||
as complete. In the case of a recurring TODO, \fBRemind\fR will not purge
|
||||
it until the last occurrence is marked as complete.
|
||||
.PP
|
||||
.SH THE OMIT COMMAND
|
||||
.PP
|
||||
In addition to being a keyword in the \fBREM\fR command,
|
||||
@@ -2068,6 +2261,24 @@ relative pathnames under the system directory containing standard reminder
|
||||
scripts. For this version of \fBRemind\fR, the system directory is
|
||||
"@prefix@/share/remind".
|
||||
.PP
|
||||
.SH THE RETURN COMMAND
|
||||
.PP
|
||||
The \fBRETURN\fR command causes \fBRemind\fR 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.)
|
||||
.PP
|
||||
Here is an example of how \fBRETURN\fR might be used:
|
||||
.PP
|
||||
.nf
|
||||
IF already_done
|
||||
RETURN
|
||||
ENDIF
|
||||
set already_done 1
|
||||
preserve already_done
|
||||
# Do expensive processing here
|
||||
.fi
|
||||
.PP
|
||||
.SH THE RUN COMMAND
|
||||
.PP
|
||||
If you include other files in your reminder script, you may not always
|
||||
@@ -2791,6 +3002,10 @@ output is not a terminal, then the default is 72.If an \fBMSF\fR-type
|
||||
reminder contains a word too long to fit in this width, it will not be
|
||||
truncated - the width limit will be ignored.
|
||||
.TP
|
||||
.B $HideCompletedTodos (read-only)
|
||||
If non-zero, then the \fB\-\-hide-completed-todos\fR option was supplied
|
||||
on the command line.
|
||||
.TP
|
||||
.B $HushMode (read-only)
|
||||
If non-zero, then the \fB\-h\fR option was supplied on the command line.
|
||||
.TP
|
||||
@@ -2878,6 +3093,9 @@ updates \fB$LongDeg\fR, \fB$LongMin\fR and \fB$LongSec\fR. Similar
|
||||
rules apply to \fB$Latitude\fR, \fB$LatDeg\fR, \fB$LatMin\fR and \fB$LatSec\fR.
|
||||
.RE
|
||||
.TP
|
||||
.B $JSONMode (read-only)
|
||||
If non-zero, then the \fB\-\-json\fR command-line option was supplied.
|
||||
.TP
|
||||
.B $MaxLateMinutes
|
||||
This variable controls how \fBRemind\fR reacts to a computer being suspended
|
||||
and then woken. Normally, if a timed reminder is queued and then the
|
||||
@@ -3081,6 +3299,11 @@ This variable returns 1 if the internal C \fBtime_t\fR type is at least
|
||||
to represent dates after about 2038, and \fBRemind\fR will use a workaround to avoid
|
||||
problems. See also the section "MACHINES WITH A 32-BIT TIME_T TYPE"
|
||||
.TP
|
||||
.B $TodoFilter (read-only)
|
||||
If 0, then both events and TODOs are being output. If 1, then the
|
||||
\fB\-\-only-todos\fR command-line option was supplied. If 2, then
|
||||
the \fB\-\-only-events\fR command-line option was spplied.
|
||||
.TP
|
||||
.B $UntimedFirst (read-only)
|
||||
Set to 1 if the \fB\-g\fR option is used with a fourth sort character
|
||||
of "d"; set to 0 otherwise.
|
||||
@@ -3305,8 +3528,8 @@ calendar mode:
|
||||
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 normal mode
|
||||
REM SPECIAL COLOR 0 255 0 Green in normal and calendar mode
|
||||
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
|
||||
.fi
|
||||
.PP
|
||||
If you use the \fBansicolor\fR function, don't forget to reset the color
|
||||
@@ -4078,6 +4301,13 @@ the actual time, or a time supplied on the command line.
|
||||
.B ord(i_num)
|
||||
Returns a string that is the ordinal number \fInum\fR. For example,
|
||||
\fBord(2)\fR returns "2nd", and \fBord(213)\fR returns "213th".
|
||||
.RS
|
||||
.PP
|
||||
In order to help with localization, if you define a function called
|
||||
\fBordx\fR that takes a single parameter, then calling
|
||||
\fBord\fR(\fIn\fR) invokes \fBordx\fR(\fIn\fR) and returns whatever
|
||||
it does.
|
||||
.RE
|
||||
.TP
|
||||
.B orthodoxeaster([dqi_arg])
|
||||
If \fIarg\fR is an \fBINT\fR, then returns the date of Orthodox Easter Sunday
|
||||
@@ -4557,6 +4787,18 @@ the empty string to variable b:
|
||||
.PP
|
||||
.RE
|
||||
.TP
|
||||
.B trigistodo()
|
||||
Returns 1 if the last \fRREM\fR command was a \fBTODO\fR type or 0 if not.
|
||||
.TP
|
||||
.B trigcompletethrough()
|
||||
Returns a \fBDATE\fR object that is the COMPLETE-THROUGH date of the most
|
||||
recent \fBREM\fR command. If there was no COMPLETE-THROUGH date,
|
||||
returns the \fBINT\fR 0.
|
||||
.TP
|
||||
.B trigmaxoverdue()
|
||||
Returns an \fBINT\fR that is the MAX-OVERDUE value of the most recent \fBREM\fR
|
||||
command. If there was no MAX-OVERDUE clause, returns -1.
|
||||
.TP
|
||||
.B trigger(d_date [,t_time [,i_utcflag]]) \fRor\fB trigger(q_datetime [,i_utcflag])
|
||||
Returns a string suitable for use in a \fBREM\fR command or a
|
||||
\fBSCANFROM\fR or UNTIL clause, allowing you to calculate trigger
|
||||
@@ -4700,7 +4942,7 @@ midnight, 1 January 1970 UTC. If the \fBtime_t\fR type is only
|
||||
19 January 2038 at 03:14:07 UTC.
|
||||
.PP
|
||||
To work around this limitation, \fBRemind\fR will "fold" years greater than 2037
|
||||
to a smaller year that begins on the same day and has the same numebr of
|
||||
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
|
||||
@@ -5525,6 +5767,35 @@ streams used by \fBRemind\fR. This is not terribly useful to most
|
||||
people, but may be useful if you run \fBRemind\fR as a subprocess of
|
||||
another program, and want to use pipes for communication.
|
||||
.PP
|
||||
.SH AGENDA MODE JSON OUTPUT
|
||||
.PP
|
||||
If you supply the \fB\-\-json\fR 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:
|
||||
.TP
|
||||
.B banner
|
||||
The \fBbanner\fR object, if present, will be the first object in the array.
|
||||
There will be at most one \fBbanner\fR object. It contains a single
|
||||
key, \fBbanner\fR, whose value is the banner that \fBRemind\fR would normally
|
||||
print in Agenda Mode.
|
||||
.TP
|
||||
.B noreminders
|
||||
The \fBnoreminders\fR object, if present, will be the final object in the
|
||||
array. There will be at most one \fBnoreminders\fR object. It contains
|
||||
a single keym, \fBnoreminders\fR, whose value is the phrase "No reminders.",
|
||||
possibly localized into a different language.
|
||||
.TP
|
||||
.B event
|
||||
All other objects in the array are \fBevent\fR objects. They are JSON
|
||||
objects that contain all of the keys described in the \fBrem2ps\fR(1)
|
||||
man page section "CALENDAR ENTRIES". However, the \fBcalendar_body\fR,
|
||||
\fBplain_body\fR and \fBraw_body\fR keys will not be present.
|
||||
.PP
|
||||
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
|
||||
\fBtkremind\fR uses the JSON output.
|
||||
.PP
|
||||
.SH CALENDAR MODE
|
||||
.PP
|
||||
If you supply the \fB\-c\fR, \fB\-s\fR or \fB\-p\fR
|
||||
@@ -5569,7 +5840,7 @@ example, consider the following:
|
||||
REM 6 Jan MSG %"Dianne's birthday%" is %b
|
||||
.fi
|
||||
.PP
|
||||
In the normal mode, \fBRemind\fR would print "Dianne's birthday is today"
|
||||
In agenda mode, \fBRemind\fR 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.
|
||||
.PP
|
||||
@@ -6049,7 +6320,7 @@ You can define two functions in your script called \fBmsgprefix()\fR
|
||||
and \fBmsgsuffix()\fR. They should each accept one argument, a number
|
||||
from 0 to 9999.
|
||||
.PP
|
||||
In normal mode, for \fBMSG\fR- and \fBMSF\fR-type reminders,
|
||||
In agenda mode, for \fBMSG\fR- and \fBMSF\fR-type reminders,
|
||||
the following sequence occurs when
|
||||
\fBRemind\fR triggers a reminder:
|
||||
.TP
|
||||
@@ -6218,6 +6489,20 @@ as:
|
||||
FSET subst_bx(a,d,t) iif(d==today()+2, "the day after tomorrow", 0)
|
||||
.fi
|
||||
.PP
|
||||
You can override substitution sequences that are not alphanumeric as follows:
|
||||
.RS
|
||||
.PP
|
||||
Override %: with \fBsubst_colon\fR
|
||||
.PP
|
||||
Override %! with \fBsubst_bang\fR
|
||||
.PP
|
||||
Override %? with \fBsubst_question\fR
|
||||
.PP
|
||||
Override %@ with \fBsubst_at\fR
|
||||
.PP
|
||||
Override %# with \fBsubst_hash\fR
|
||||
.RE
|
||||
.PP
|
||||
You can define your own substitution sequences in addition to the built-in
|
||||
ones as follows: If you define a function named \fBsubst_\fIname\fB(alt, date, time)\fR, then the sequence \fB%{name}\fR calls the function with \fBalt\fR
|
||||
set to 0 and \fBdate\fR and \fBtime\fR to the trigger date and time,
|
||||
@@ -6574,8 +6859,8 @@ Calculations" by E. M. Reingold and Nachum Dershowitz.
|
||||
The \fBSPECIAL\fR keyword is used to transmit "out-of-band" information
|
||||
to \fBRemind\fR backends, such as \fBtkremind\fR or \fBRem2PS\fR.
|
||||
They are used only when piping data from a \fBremind \-p\fR line.
|
||||
(Note that the COLOR special is an exception; it downgrades to the
|
||||
equivalent of MSG in \fBRemind's\fR normal mode of operation.)
|
||||
(Note that the COLOR special is an exception; it works similarly
|
||||
to MSG when the \fB\-p\fR option is not supplied.)
|
||||
.PP
|
||||
The various \fBSPECIAL\fRs recognized are particular for each
|
||||
backend; however, there are four \fBSPECIAL\fRs that all backends
|
||||
@@ -6644,10 +6929,10 @@ 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.
|
||||
.PP
|
||||
The COLOR special is "doubly special", because in its normal operating
|
||||
mode, \fBremind\fR treats a COLOR special just like a MSG-type reminder.
|
||||
Also, if you invoke \fBRemind\fR with \fB\-@\fR[\fIn\fR], then it approximates
|
||||
SPECIAL COLOR reminders on your terminal.
|
||||
The COLOR special is "doubly special", because in agenda mode,
|
||||
\fBremind\fR treats a COLOR special just like a MSG-type reminder.
|
||||
Also, if you invoke \fBRemind\fR with \fB\-@\fR[\fIn\fR], then it
|
||||
approximates SPECIAL COLOR reminders on your terminal.
|
||||
.PP
|
||||
See also the documentation of the \fB$DefaultColor\fR system variable
|
||||
in the section "SYSTEM VARIABLES".
|
||||
@@ -6810,6 +7095,10 @@ the previous example could also be written like this:
|
||||
REM Mon AFTER MSG Hello
|
||||
.fi
|
||||
.PP
|
||||
A SCANFROM that specifies a full date is called an \fIabsolute SCANFROM\fR
|
||||
and a SCANFROM that specifies a negative number is called a
|
||||
\fIrelative SCANFROM\fR.
|
||||
.PP
|
||||
In general, use \fBSCANFROM\fR as shown for safe movable \fBOMITs\fR. The
|
||||
amount you should scan back by (7 days in the example above) depends on
|
||||
the number of possible consecutive \fBOMITted\fR days that may occur, and
|
||||
|
||||
@@ -20,18 +20,16 @@ or the tkpng extension to handle PNG images.
|
||||
|
||||
.SH COMMAND-LINE OPTIONS
|
||||
\fBTkRemind\fR itself has no command-line options. However, it passes
|
||||
certain options on to \fBRemind\fR. The options it passes are
|
||||
\fB\-b\fR, \fB\-g\fR, \fB\-x\fR, \fB\-i\fR and \fB\-m\fR. See the
|
||||
\fBRemind\fR man page for details about the options. Note that
|
||||
\fBTkRemind\fR will respect the \fB\-m\fR and \fB\-b1\fR options and
|
||||
adjust its appearance accordingly.
|
||||
|
||||
any command-line argument starting with \fB\-\fR to \fBRemind\fR as an
|
||||
option. In addition, \fBTkRemind\fR will respect the \fB\-m\fR and
|
||||
\fB\-b1\fR options and adjust its appearance accordingly.
|
||||
.PP
|
||||
\fIRead_file\fR is the file from which \fBTkRemind\fR reads reminders.
|
||||
It is in standard \fBRemind\fR format. \fIWrite_file\fR is the file
|
||||
to which \fBTkRemind\fR writes reminders which you add using the GUI.
|
||||
If \fIRead_file\fR is omitted, it defaults to \fB$HOME/.reminders\fR.
|
||||
If \fIWrite_file\fR is omitted, it defaults to \fIRead_file\fR.
|
||||
|
||||
.PP
|
||||
You may wish to have a different \fIWrite_file\fR from \fIRead_file\fR if
|
||||
you want to collect all of \fBTkRemind\fR's reminders in one place. Suppose
|
||||
your main file is \fI$HOME/.reminders\fR and you want \fBTkRemind\fR to put
|
||||
@@ -96,10 +94,18 @@ The fourth control specifies which days \fBRemind\fR considers
|
||||
as part of the weekend. This can affect the interpretation of "weekday"
|
||||
in the second and third types of reminders.
|
||||
|
||||
The fifth control associates a time with the reminder.
|
||||
You can also specify advance notice, possibly repeating.
|
||||
The fifth group of controls associates a time and possible duration
|
||||
with the reminder. You can also specify advance notice, possibly
|
||||
repeating.
|
||||
|
||||
The sixth control specifies what \fBRemind\fR should do if a reminder
|
||||
The sixth control allows you to specify whether the reminder is a TODO,
|
||||
and if so, its completion date. Double-clicking in the "Complete through:"
|
||||
field automatically fills in the date of the calendar entry. Otherwise,
|
||||
enter a possible completion date in the form YYYY-MM-DD. You can also enter
|
||||
a number in the "Max overdue days:" field to limit how many days past the
|
||||
due date \fBRemind\fR will keep reminding you of the TODO.
|
||||
|
||||
The seventh control specifies what \fBRemind\fR should do if a reminder
|
||||
falls on a holiday or weekend.
|
||||
|
||||
Enter the body of the reminder into the \fBSummary:\fR text entry. If
|
||||
@@ -121,6 +127,16 @@ edit the reminder, thereby gaining access to advanced features of
|
||||
\fBRemind\fR. You can also use it simply to play around and discover
|
||||
\fBRemind\fR's idioms for expressing different types of reminders.
|
||||
|
||||
.SH SEEING A SINGLE DAY'S REMINDERS
|
||||
Right-click on any day number in the calendar to pop up a window with
|
||||
that day's reminders in Agenda Mode. You can left- or right-click the
|
||||
current date and time indicator at the bottom of the window to see today's
|
||||
reminders in Agenda Mode.
|
||||
|
||||
In the Agenda Mode display, hovering over a reminder will show ancillary
|
||||
information such as a Location, URL or Description. Clicking on a reminder
|
||||
will open an editor on the REM command that created the reminder.
|
||||
|
||||
.SH PRINTING
|
||||
To print the current month's calendar, click \fBPrint...\fR on the
|
||||
main calendar window. This brings up the print dialog. Printing
|
||||
|
||||
@@ -517,7 +517,7 @@ sub render
|
||||
}
|
||||
}
|
||||
|
||||
if ($so_far > $settings->{height} - $settings->{margin_bottom}) {
|
||||
if ($so_far > $settings->{height} - $settings->{margin_bottom} + 1) {
|
||||
print STDERR "WARNING: overfull calendar box\n";
|
||||
}
|
||||
# The vertical lines
|
||||
@@ -583,7 +583,7 @@ sub draw_row
|
||||
$self->draw_day($cr, $settings, $so_far, $day, $col, $height);
|
||||
}
|
||||
|
||||
return $so_far + $height + $settings->{border_size};
|
||||
return $so_far + $height + $settings->{border_size} * 2;
|
||||
}
|
||||
|
||||
=head2 col_box_coordinates($so_far, $col, $height, $settings)
|
||||
|
||||
@@ -158,11 +158,6 @@ if {[catch {package require json}]} {
|
||||
missing_tcllib json
|
||||
}
|
||||
|
||||
if {$tcl_platform(platform) == "windows"} {
|
||||
tk_messageBox -message "Please do not port Remind to Windows" -icon error -type ok
|
||||
exit 1
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# GetRemindVersion
|
||||
# Arguments:
|
||||
@@ -317,6 +312,8 @@ set TodayDay [string trim [clock format $now -format %e]]
|
||||
set CurMonth $TodayMonth
|
||||
set CurYear $TodayYear
|
||||
|
||||
set DateOfEventBeingEdited ""
|
||||
|
||||
# Reminder option types and skip types
|
||||
set OptionType 1
|
||||
set SkipType 1
|
||||
@@ -364,8 +361,8 @@ set HighestTagSoFar 0
|
||||
# Check Remind version
|
||||
set ver [GetRemindVersion]
|
||||
|
||||
if {"$ver" < "04.03.03"} {
|
||||
tk_messageBox -message "This version of TkRemind requires Remind version 04.03.03 or newer; you have version $ver" -icon error -type ok
|
||||
if {"$ver" < "06.00.00"} {
|
||||
tk_messageBox -message "This version of TkRemind requires Remind version 06.00.00 or newer; you have version $ver" -icon error -type ok
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -447,7 +444,10 @@ proc Initialize {} {
|
||||
if {"[lindex $argv $i]" == "-b1"} {
|
||||
set TwentyFourHourMode 1
|
||||
}
|
||||
} else {
|
||||
} elseif { [regexp -- {-.*} [lindex $argv $i]]} {
|
||||
append CommandLine " [lindex $argv $i]"
|
||||
append PSCmd " [lindex $argv $i]"
|
||||
} else {
|
||||
break
|
||||
}
|
||||
incr i
|
||||
@@ -583,7 +583,7 @@ proc CreateCalFrame { w dayNames } {
|
||||
text $w.t$f -width 12 -height $h -bd 0 -spacing3 3 -wrap word -relief flat \
|
||||
-state disabled -takefocus 0 -cursor {} -font CalboxFont -foreground $Option(TextColor) -background $Option(BackgroundColor) \
|
||||
-highlightthickness 0
|
||||
frame $w.f$f -padx 0 -pady 0 -highlightthickness 0 -relief flat -bd 0
|
||||
frame $w.f$f -padx 0 -pady 0 -highlightthickness 0 -relief flat -bd 0 -background $Option(BackgroundColor)
|
||||
$w.t$f tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$f"
|
||||
$w.t$f tag bind REM <ButtonPress-2> "OpenUrl $w.t$f"
|
||||
$w.t$f tag bind REM <ButtonPress-3> "FireEditor $w.t$f"
|
||||
@@ -650,7 +650,8 @@ proc ConfigureCalFrame { w firstDay numDays } {
|
||||
raise $w.t$i
|
||||
set d [expr $i-$first+1]
|
||||
$w.l$i configure -text $d -state normal -relief flat \
|
||||
-command "ModifyDay $d $firstDay" -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground)
|
||||
-command "ModifyDay $d $firstDay" -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground)
|
||||
bind $w.l$i <ButtonPress-3> [list ShowSpecificDayReminders $d]
|
||||
balloon_add_help $w.l$i "Add a reminder..."
|
||||
$w.t$i configure -relief sunken -takefocus 1 -state normal -foreground $Option(TextColor) -background $Option(BackgroundColor)
|
||||
$w.t$i delete 1.0 end
|
||||
@@ -753,7 +754,13 @@ proc CreateCalWindow { dayNames } {
|
||||
button .b.quit -text {Quit} -command {Quit} -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground)
|
||||
balloon_add_help .b.quit "Quit TkRemind"
|
||||
label .b.status -text "" -width 25 -relief flat -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 0
|
||||
bind .b.status <ButtonPress-1> [list ShowTodaysReminders 1 ""]
|
||||
bind .b.status <ButtonPress-3> [list ShowTodaysReminders 1 ""]
|
||||
balloon_add_help .b.status "Show Today's Reminders"
|
||||
label .b.nqueued -text "" -width 20 -relief flat -bd 0 -foreground $Option(LabelColor) -background $Option(WinBackground) -highlightthickness 0
|
||||
balloon_add_help .b.nqueued "See the queue of pending reminders (debugging purposes only)"
|
||||
bind .b.nqueued <ButtonPress-1> [list DoQueue]
|
||||
bind .b.nqueued <ButtonPress-3> [list DoQueue]
|
||||
pack .b.prev .b.this .b.next .b.goto .b.print .b.options .b.queue .b.quit -side left -fill both -padx 1
|
||||
pack .b.status -side left -fill both -expand 1 -padx 1
|
||||
pack .b.nqueued -side left -fill both -padx 1
|
||||
@@ -968,6 +975,7 @@ proc CancelOptions { } {
|
||||
global Option
|
||||
font configure CalboxFont {*}$Option(CalboxFont)
|
||||
font configure HeadingFont {*}$Option(HeadingFont)
|
||||
font configure BoldFont {*}$Option(HeadingFont) -weight bold
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
@@ -1105,6 +1113,7 @@ proc LoadOptions {} {
|
||||
}
|
||||
font configure CalboxFont {*}$Option(CalboxFont)
|
||||
font configure HeadingFont {*}$Option(HeadingFont)
|
||||
font configure BoldFont {*}$Option(HeadingFont) -weight bold
|
||||
}
|
||||
|
||||
|
||||
@@ -1694,6 +1703,38 @@ proc Quit {} {
|
||||
}
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# ShowSpecificDayReminders - show reminders for a specific day
|
||||
# Arguments:
|
||||
# d - day whose reminders should be shown
|
||||
#---------------------------------------------------------------------------
|
||||
proc ShowSpecificDayReminders { d } {
|
||||
global CurYear CurMonth
|
||||
set date [format "%04d-%02d-%02d" $CurYear [expr 1 + $CurMonth] $d]
|
||||
ShowTodaysReminders 1 $date
|
||||
}
|
||||
|
||||
proc toggle_complete_through { w } {
|
||||
global todobut
|
||||
if {$todobut} {
|
||||
$w.complete_through configure -state normal
|
||||
$w.max_overdue configure -state normal
|
||||
} else {
|
||||
$w.complete_through configure -state disabled
|
||||
$w.max_overdue configure -state disabled
|
||||
}
|
||||
}
|
||||
|
||||
proc complete_through_today { w } {
|
||||
global DateOfEventBeingEdited
|
||||
$w.complete_through delete 0 end
|
||||
if {"$DateOfEventBeingEdited" != ""} {
|
||||
$w.complete_through insert end $DateOfEventBeingEdited
|
||||
} else {
|
||||
$w.complete_through insert end [clock format [clock seconds] -format %Y-%m-%d]
|
||||
}
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# CreateModifyDialog -- create dialog for adding a reminder
|
||||
# Arguments:
|
||||
@@ -1707,7 +1748,9 @@ proc CreateModifyDialog {w day firstDay args} {
|
||||
|
||||
# Set up: Year, Month, Day, WeekdayName
|
||||
global CurYear CurMonth EnglishDayNames MonthNames OptionType SkipType
|
||||
global ModifyDialogResult TwentyFourHourMode
|
||||
global ModifyDialogResult TwentyFourHourMode DateOfEventBeingEdited
|
||||
|
||||
set DateOfEventBeingEdited ""
|
||||
|
||||
set OptionType 1
|
||||
set SkipType 1
|
||||
@@ -1724,12 +1767,13 @@ proc CreateModifyDialog {w day firstDay args} {
|
||||
frame $w.adv -bd 4
|
||||
frame $w.weekend -bd 4
|
||||
frame $w.durationbox -bd 4
|
||||
frame $w.todobox
|
||||
frame $w.time -bd 4
|
||||
frame $w.hol -bd 4
|
||||
frame $w.msg
|
||||
frame $w.buttons
|
||||
pack $w.o1 $w.o2 $w.o3 -side top -anchor w -in $w.o
|
||||
pack $w.o $w.exp $w.adv $w.weekend $w.time $w.durationbox $w.hol $w.msg -side top -anchor w -pady 4 -expand 0 -fill both
|
||||
pack $w.o $w.exp $w.adv $w.weekend $w.time $w.durationbox $w.todobox $w.hol $w.msg -side top -anchor w -pady 4 -expand 0 -fill both
|
||||
pack $w.msg -side top -anchor w -pady 4 -padx 4 -expand true -fill both
|
||||
pack $w.buttons -side top -anchor w -pady 4 -expand 0 -fill x
|
||||
|
||||
@@ -1919,6 +1963,20 @@ proc CreateModifyDialog {w day firstDay args} {
|
||||
}
|
||||
pack $w.durationbut $w.durationh $w.durationcolon $w.durationm -side left -anchor w -in $w.durationbox
|
||||
|
||||
# TODO?
|
||||
checkbutton $w.todobut -text "This is a TODO " -command [list toggle_complete_through $w]
|
||||
|
||||
balloon_add_help $w.todobut "Select if this is a TODO-type reminder"
|
||||
$w.todobut deselect
|
||||
label $w.lcomplete -text "Complete through: "
|
||||
entry $w.complete_through -width 20
|
||||
bind $w.complete_through <Double-Button-1> [list complete_through_today $w]
|
||||
balloon_add_help $w.complete_through "Enter the date of completed TODO in the form YYYY-MM-DD"
|
||||
label $w.loverdue -text "Max overdue days: "
|
||||
entry $w.max_overdue -width 6
|
||||
balloon_add_help $w.max_overdue "Enter the maximum number of days Remind should nag you about an overdue TODO"
|
||||
pack $w.todobut $w.lcomplete $w.complete_through $w.loverdue $w.max_overdue -side left -anchor w -in $w.todobox
|
||||
|
||||
# SKIP TYPE
|
||||
label $w.labhol -text "On holidays or weekends:"
|
||||
radiobutton $w.issue -variable SkipType -value 1 -text "Issue reminder as usual"
|
||||
@@ -1930,7 +1988,7 @@ proc CreateModifyDialog {w day firstDay args} {
|
||||
# TEXT ENTRY
|
||||
label $w.msglab -text "Summary: "
|
||||
entry $w.entry
|
||||
balloon_add_help $w.entry "Enter the text of the reminder"
|
||||
balloon_add_help $w.entry "Enter the text of the reminder (required)"
|
||||
grid $w.msglab -row 0 -column 0 -in $w.msg -sticky e
|
||||
grid $w.entry -row 0 -column 1 -in $w.msg -sticky nsew
|
||||
|
||||
@@ -1987,7 +2045,7 @@ proc CreateModifyDialog {w day firstDay args} {
|
||||
#***********************************************************************
|
||||
proc RemindDialogToOptions { w } {
|
||||
global OptionType SkipType repbut expbut advbut advcount
|
||||
global timebut timeadvbut timerepbut durationbut
|
||||
global timebut timeadvbut timerepbut durationbut todobut
|
||||
global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday
|
||||
set ans {}
|
||||
lappend ans "-global-OptionType" $OptionType
|
||||
@@ -2021,10 +2079,12 @@ proc RemindDialogToOptions { w } {
|
||||
#***********************************************************************
|
||||
proc OptionsToRemindDialog { w opts } {
|
||||
global OptionType SkipType repbut expbut advbut advcount
|
||||
global timebut timeadvbut timerepbut TwentyFourHourMode durationbut
|
||||
global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday
|
||||
global timebut timeadvbut timerepbut TwentyFourHourMode durationbut todobut
|
||||
global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday DateOfEventBeingEdited
|
||||
set hour ""
|
||||
set ampm ""
|
||||
$w.complete_through configure -state normal
|
||||
$w.max_overdue configure -state normal
|
||||
foreach {flag value} $opts {
|
||||
switch -glob -- $flag {
|
||||
"-text-*" {
|
||||
@@ -2072,6 +2132,7 @@ proc OptionsToRemindDialog { w opts } {
|
||||
}
|
||||
}
|
||||
}
|
||||
toggle_complete_through $w
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -2163,6 +2224,7 @@ proc ModifyDay {d firstDay} {
|
||||
wm iconname .mod "Add Reminder"
|
||||
tkwait visibility .mod
|
||||
set oldFocus [focus]
|
||||
toggle_complete_through .mod
|
||||
while {1} {
|
||||
grab .mod
|
||||
raise .mod
|
||||
@@ -2243,7 +2305,7 @@ proc CreateReminder {w} {
|
||||
set body [string trim [$w.entry get]]
|
||||
|
||||
if {"$body" == ""} {
|
||||
error "Blank body in reminder"
|
||||
error "Summary is required"
|
||||
}
|
||||
|
||||
set DidOmit 0
|
||||
@@ -2251,7 +2313,7 @@ proc CreateReminder {w} {
|
||||
# Delegate the first part to CreateReminder1, CreateReminder2, or
|
||||
# CreateReminder3
|
||||
global OptionType SkipType repbut expbut advbut advcount
|
||||
global timebut timeadvbut timerepbut durationbut
|
||||
global timebut timeadvbut timerepbut durationbut todobut
|
||||
|
||||
set rem [CreateReminder$OptionType $w]
|
||||
|
||||
@@ -2299,6 +2361,17 @@ proc CreateReminder {w} {
|
||||
}
|
||||
}
|
||||
|
||||
if {$todobut} {
|
||||
append rem " TODO"
|
||||
set ct [string trim [$w.complete_through get]]
|
||||
if {"$ct" != ""} {
|
||||
append rem " COMPLETE-THROUGH $ct"
|
||||
}
|
||||
set mo [string trim [$w.max_overdue get]]
|
||||
if {"$mo" != ""} {
|
||||
append rem " MAX-OVERDUE $mo"
|
||||
}
|
||||
}
|
||||
global SkipType
|
||||
if {$SkipType == 2} {
|
||||
append rem " SKIP"
|
||||
@@ -2845,14 +2918,15 @@ proc RestartBackgroundRemindDaemon {} {
|
||||
# Dumps the debugging queue listing
|
||||
#---------------------------------------------------------------------------
|
||||
proc ShowQueue { queue } {
|
||||
global Option
|
||||
set w .queuedbg
|
||||
catch { destroy $w }
|
||||
toplevel $w
|
||||
toplevel $w -background $Option(WinBackground)
|
||||
wm title $w "Queue (Debugging Output)"
|
||||
wm iconname $w "Queue Dbg"
|
||||
text $w.t -fg black -bg white -width 80 -height 30 -wrap word -yscrollcommand "$w.sb set"
|
||||
text $w.t -fg black -bg white -width 80 -height 30 -wrap word -yscrollcommand "$w.sb set" -foreground $Option(TextColor) -background $Option(BackgroundColor) -font CalBoxFont
|
||||
scrollbar $w.sb -orient vertical -command "$w.text yview"
|
||||
button $w.ok -text "OK" -command "destroy $w"
|
||||
button $w.ok -text "OK" -command "destroy $w" -foreground $Option(TextColor) -background $Option(BackgroundColor) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground)
|
||||
grid $w.t -row 0 -column 0 -sticky nsew
|
||||
grid $w.sb -row 0 -column 1 -sticky ns
|
||||
grid $w.ok -row 1 -column 0 -sticky w
|
||||
@@ -2864,7 +2938,6 @@ proc ShowQueue { queue } {
|
||||
set obj [lsort -command sort_q $queue]
|
||||
set did 0
|
||||
$w.t tag configure grey -background "#DDDDDD" -selectbackground "#999999"
|
||||
set toggle 0
|
||||
foreach q $obj {
|
||||
if { $did > 0 } {
|
||||
$w.t insert end "\n"
|
||||
@@ -2887,24 +2960,17 @@ proc ShowQueue { queue } {
|
||||
}
|
||||
foreach key [list time nexttime body] {
|
||||
set r [dict get $q $key]
|
||||
if { $toggle != 0 } {
|
||||
$w.t insert end "$key=$r" [list grey $fntag]
|
||||
if {"$key" != "body"} {
|
||||
$w.t insert end "; " [list grey $fntag]
|
||||
}
|
||||
} else {
|
||||
$w.t insert end "$key=$r" [list $fntag]
|
||||
if {"$key" != "body"} {
|
||||
$w.t insert end "; " [list $fntag]
|
||||
}
|
||||
$w.t insert end "$key=$r" [list $fntag]
|
||||
if {"$key" != "body"} {
|
||||
$w.t insert end "; " [list $fntag]
|
||||
}
|
||||
}
|
||||
$w.t insert end "\n"
|
||||
set toggle [expr 1 - $toggle]
|
||||
set did 1
|
||||
}
|
||||
if { $did == 0 } {
|
||||
$w.t insert end "(Queue is empty)\n"
|
||||
$w.t tag configure bold -font BoldFont
|
||||
$w.t insert end "(Queue is empty)\n" bold
|
||||
} else {
|
||||
$w.t insert end "\n\nClick on a queue item to open an editor on the corresponding REM command.\n"
|
||||
}
|
||||
@@ -3014,7 +3080,7 @@ proc DaemonReadable { file } {
|
||||
catch { unset Ignore }
|
||||
Initialize
|
||||
FillCalWindow
|
||||
ShowTodaysReminders
|
||||
ShowTodaysReminders 0 ""
|
||||
}
|
||||
"reread" {
|
||||
if {[dict exists $obj command]} {
|
||||
@@ -3195,6 +3261,7 @@ proc main {} {
|
||||
|
||||
font create CalboxFont {*}[font actual TkFixedFont]
|
||||
font create HeadingFont {*}[font actual TkDefaultFont]
|
||||
font create BoldFont {*}[font actual TkDefaultFont] -weight bold
|
||||
|
||||
global AppendFile HighestTagSoFar DayNames
|
||||
catch {
|
||||
@@ -3212,7 +3279,7 @@ proc main {} {
|
||||
}
|
||||
FindConfigFile
|
||||
LoadOptions
|
||||
ShowTodaysReminders
|
||||
ShowTodaysReminders 0 ""
|
||||
ScanForTags $AppendFile
|
||||
CreateCalWindow $DayNames
|
||||
FillCalWindow
|
||||
@@ -3284,6 +3351,9 @@ proc ReadTaggedOptions { tag date } {
|
||||
}
|
||||
}
|
||||
|
||||
if {[dict exists $obj date]} {
|
||||
lappend ans -global-DateOfEventBeingEdited $date
|
||||
}
|
||||
if {[dict exists $obj d]} {
|
||||
lappend ans -text-day1 [dict get $obj d]
|
||||
lappend ans -text-day2 [dict get $obj d]
|
||||
@@ -3509,6 +3579,24 @@ proc ReadTaggedOptions { tag date } {
|
||||
lappend ans -entry-entry [dict get $obj body]
|
||||
}
|
||||
|
||||
# Is this a TODO?
|
||||
if {[dict exists $obj is_todo]} {
|
||||
lappend ans -global-todobut [dict get $obj is_todo]
|
||||
} else {
|
||||
lappend ans -global-todobut 0
|
||||
}
|
||||
if {[dict exists $obj complete_through]} {
|
||||
lappend ans -entry-complete_through [dict get $obj complete_through]
|
||||
} else {
|
||||
lappend ans -entry-complete_through ""
|
||||
}
|
||||
|
||||
if {[dict exists $obj max_overdue]} {
|
||||
lappend ans -entry-max_overdue [dict get $obj max_overdue]
|
||||
} else {
|
||||
lappend ans -entry-max_overdue ""
|
||||
}
|
||||
|
||||
# Figure out the reminder type
|
||||
if {[dict exists $obj rep]} {
|
||||
# Repeat must be type 1
|
||||
@@ -3684,7 +3772,7 @@ proc EditableEnter { w } {
|
||||
if {"$c" != ""} {
|
||||
$w tag configure $tag -underline 1
|
||||
# underlinefg not supported on older versions of Tk
|
||||
eval { $w tag configure $tag -underlinefg $c }
|
||||
catch { $w tag configure $tag -underlinefg $c }
|
||||
} else {
|
||||
$w tag configure $tag -underline 1
|
||||
}
|
||||
@@ -3818,7 +3906,7 @@ proc EditTaggedReminder { w } {
|
||||
wm title .mod "TkRemind Edit Reminder..."
|
||||
wm iconname .mod "Edit Reminder"
|
||||
OptionsToRemindDialog .mod $opts
|
||||
|
||||
toggle_complete_through .mod
|
||||
tkwait visibility .mod
|
||||
set oldFocus [focus]
|
||||
while {1} {
|
||||
@@ -4230,7 +4318,7 @@ proc DisplayTimeContinuously {} {
|
||||
DisplayTime
|
||||
|
||||
# Reap any zombies
|
||||
eval { exec true }
|
||||
catch { exec true }
|
||||
|
||||
set secs [clock format [clock seconds] -format "%S"]
|
||||
# Doh -- don't interpret as an octal number if leading zero
|
||||
@@ -4240,47 +4328,67 @@ proc DisplayTimeContinuously {} {
|
||||
}
|
||||
|
||||
|
||||
proc daily_rem_enter { lines } {
|
||||
global Balloon
|
||||
balloon_cancel_timer
|
||||
set Balloon(HelpId) [after $Balloon(HelpTime) [list details_popup $lines]]
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: ShowTodaysReminders
|
||||
# %ARGUMENTS:
|
||||
# None
|
||||
# force -- if true, show today's reminders even if option is disabled.
|
||||
# date -- if non-blank, show reminders for specified date rather than today.
|
||||
# %RETURNS:
|
||||
# Nothing
|
||||
# %DESCRIPTION:
|
||||
# Shows all of today's non-timed reminders in a window
|
||||
#***********************************************************************
|
||||
proc ShowTodaysReminders {} {
|
||||
proc ShowTodaysReminders { force date } {
|
||||
global Option
|
||||
global Remind
|
||||
global ReminderFile
|
||||
global TwentyFourHourMode
|
||||
if {!$Option(ShowTodaysReminders)} {
|
||||
if {!$force && !$Option(ShowTodaysReminders)} {
|
||||
return
|
||||
}
|
||||
|
||||
set w .today
|
||||
catch { destroy $w }
|
||||
toplevel $w
|
||||
wm title $w "Today's Reminders"
|
||||
toplevel $w -background $Option(WinBackground)
|
||||
if {"$date" == ""} {
|
||||
set wtitle "Today's Reminders"
|
||||
} else {
|
||||
set wtitle "Reminders for $date"
|
||||
}
|
||||
wm iconname $w "Reminders"
|
||||
text $w.text -width 80 -height 20 -wrap word -yscrollcommand "$w.sb set"
|
||||
text $w.text -width 80 -height 20 -wrap word -yscrollcommand "$w.sb set" -foreground $Option(TextColor) -background $Option(BackgroundColor) -font CalboxFont -spacing1 3
|
||||
scrollbar $w.sb -orient vertical -command "$w.text yview"
|
||||
button $w.ok -text "OK" -command "destroy $w"
|
||||
button $w.ok -text "OK" -command "destroy $w" -foreground $Option(TextColor) -background $Option(BackgroundColor) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground)
|
||||
|
||||
grid $w.text -row 0 -column 0 -sticky nsew
|
||||
grid $w.sb -row 0 -column 1 -sticky ns
|
||||
grid $w.ok -row 1 -column 0 -sticky w
|
||||
|
||||
grid rowconfigure $w 0 -weight 1
|
||||
grid rowconfigure $w 1 -weight 0
|
||||
grid columnconfigure $w 0 -weight 1
|
||||
grid columnconfigure $w 1 -weight 0
|
||||
CenterWindow $w .
|
||||
|
||||
# Grab the reminders
|
||||
set stuff ""
|
||||
set cmdline "|$Remind -itkremind=1 -g -q -r "
|
||||
set cmdline "|$Remind -itkremind=1 --json -q -r "
|
||||
if {$TwentyFourHourMode} {
|
||||
append cmdline "-b1 "
|
||||
}
|
||||
append cmdline $Option(ExtraRemindArgs);
|
||||
append cmdline " $ReminderFile 2>@1"
|
||||
append cmdline " $ReminderFile"
|
||||
if {"$date" != ""} {
|
||||
append cmdline " $date"
|
||||
} else {
|
||||
set date [clock format [clock seconds] -format "%Y-%m-%d" -locale C]
|
||||
}
|
||||
append cmdline " 2>/dev/null"
|
||||
set f [open $cmdline r]
|
||||
while {[gets $f line] >= 0} {
|
||||
append stuff "$line\n"
|
||||
@@ -4290,12 +4398,163 @@ proc ShowTodaysReminders {} {
|
||||
$w.text insert end $stuff
|
||||
$w.text insert end "\n"
|
||||
$w.text insert end $err
|
||||
} else {
|
||||
$w.text insert end $stuff
|
||||
$w.text configure -state disabled
|
||||
return
|
||||
}
|
||||
|
||||
if {[catch {set arr [::json::json2dict $stuff]} err]} {
|
||||
$w.text insert end "Error converting JSON\n\n"
|
||||
$w.text insert end $err
|
||||
$w.text configure -state disabled
|
||||
return
|
||||
}
|
||||
|
||||
# If first element is banner, set window title
|
||||
set first [lindex $arr 0]
|
||||
$w.text tag configure bold -font BoldFont
|
||||
if {"[lindex $first 0]" == "banner"} {
|
||||
set banner [lindex $first 1]
|
||||
# Trim trailing colon
|
||||
set wtitle [string trimright $banner ":"]
|
||||
set arr [lreplace $arr 0 0]
|
||||
$w.text insert end "$banner" bold
|
||||
$w.text insert end "\n\n"
|
||||
}
|
||||
|
||||
# At this point, we can set the window title
|
||||
wm title $w $wtitle
|
||||
|
||||
# If first element is no reminders, FINE.
|
||||
set first [lindex $arr 0]
|
||||
if {"[lindex $first 0]" == "noreminders"} {
|
||||
$w.text insert end [lindex $first 1] bold
|
||||
$w.text insert end "\n"
|
||||
$w.text configure -state disabled
|
||||
return
|
||||
}
|
||||
|
||||
set arr [lsort -command compare_reminders $arr]
|
||||
set old_date {}
|
||||
set did_a_date 0
|
||||
set t_index 0
|
||||
foreach thing $arr {
|
||||
incr t_index
|
||||
set mydate [dict get $thing date]
|
||||
if {"$mydate" != "$old_date"} {
|
||||
if {"$old_date" != ""} {
|
||||
$w.text insert end "\n"
|
||||
}
|
||||
if {$did_a_date || "$mydate" != "$date"} {
|
||||
$w.text insert end "> $mydate\n" bold
|
||||
set did_a_date 1
|
||||
}
|
||||
}
|
||||
set old_date $mydate
|
||||
set tags [list "l_$t_index"]
|
||||
if {[dict exists $thing r] && [dict exists $thing g] && [dict exists $thing g]} {
|
||||
set r [dict get $thing r]
|
||||
set g [dict get $thing g]
|
||||
set b [dict get $thing b]
|
||||
if {$r > 255} {
|
||||
set r 255
|
||||
} elseif {$r < 0} {
|
||||
set r 0
|
||||
}
|
||||
if {$g > 255} {
|
||||
set g 255
|
||||
} elseif {$g < 0} {
|
||||
set g 0
|
||||
}
|
||||
if {$b > 255} {
|
||||
set b 255
|
||||
} elseif {$b < 0} {
|
||||
set b 0
|
||||
}
|
||||
set color [format "%02X%02X%02X" $r $g $b]
|
||||
lappend tags "clr$color"
|
||||
$w.text tag configure "clr$color" -foreground "#$color"
|
||||
}
|
||||
|
||||
set help_lines {}
|
||||
if {[dict exists $thing info]} {
|
||||
set info [dict get $thing info]
|
||||
if {[dict exists $info location]} {
|
||||
lappend help_lines [list "Location:" [dict get $info location]]
|
||||
}
|
||||
if {[dict exists $info description]} {
|
||||
lappend help_lines [list "Description:" [dict get $info description]]
|
||||
}
|
||||
if {[dict exists $info url]} {
|
||||
lappend help_lines [list "URL:" "Middle-click to open [dict get $info url]"]
|
||||
$w.text tag bind "l_$t_index" <ButtonPress-2> [list exec xdg-open [dict get $info url]]
|
||||
}
|
||||
}
|
||||
if {[llength $help_lines] >= 1} {
|
||||
$w.text tag bind "l_$t_index" <Enter> +[list daily_rem_enter $help_lines]
|
||||
$w.text tag bind "l_$t_index" <Leave> +[list details_leave $w]
|
||||
}
|
||||
if {[dict exists $thing filename]} {
|
||||
set fname [dict get $thing filename]
|
||||
# Don't make INCLUDECMD output editable
|
||||
if {![string match "*|" $fname]} {
|
||||
if {[dict exists $thing lineno_start]} {
|
||||
set l [dict get $thing lineno_start]
|
||||
} else {
|
||||
set l [dict get $thing lineno]
|
||||
}
|
||||
set fntag [string cat "FILE_" $l "_" $fname]
|
||||
$w.text tag bind "l_$t_index" <Enter> +[list $w.text tag configure "l_$t_index" -underline 1]
|
||||
$w.text tag bind "l_$t_index" <Leave> +[list $w.text tag configure "l_$t_index" -underline 0]
|
||||
$w.text tag bind "l_$t_index" <ButtonPress-1> [list FireEditor $w.text $fntag]
|
||||
$w.text tag bind "l_$t_index" <ButtonPress-3> [list FireEditor $w.text $fntag]
|
||||
}
|
||||
}
|
||||
$w.text insert end [dict get $thing body] $tags
|
||||
$w.text insert end "\n"
|
||||
}
|
||||
|
||||
#$w.text insert end "\n\n$stuff\n"
|
||||
$w.text configure -state disabled
|
||||
}
|
||||
|
||||
proc compare_reminders { a b } {
|
||||
set a_date [dict get $a date]
|
||||
set b_date [dict get $b date]
|
||||
#puts "Comparing $a_date $b_date"
|
||||
if {"$a_date" < "$b_date"} {
|
||||
return -1
|
||||
}
|
||||
if {"$a_date" > "$b_date"} {
|
||||
return 1
|
||||
}
|
||||
|
||||
if {[dict exists $a time]} {
|
||||
set a_time [dict get $a time]
|
||||
} else {
|
||||
set a_time 1441
|
||||
}
|
||||
if {[dict exists $b time]} {
|
||||
set b_time [dict get $b time]
|
||||
} else {
|
||||
set b_time 1441
|
||||
}
|
||||
if {$a_time < $b_time} {
|
||||
return -1
|
||||
}
|
||||
if {$a_time > $b_time} {
|
||||
return 1
|
||||
}
|
||||
set a_prio [dict get $a priority]
|
||||
set b_prio [dict get $b priority]
|
||||
if {$a_prio < $b_prio} {
|
||||
return -1;
|
||||
}
|
||||
if {$a_prio > $b_prio} {
|
||||
return 1;
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: InteractiveDeleteReminder
|
||||
# %ARGUMENTS:
|
||||
@@ -4516,6 +4775,7 @@ proc ChooseHeadingFont {} {
|
||||
proc SetHeadingFont {font} {
|
||||
global tmpOpt
|
||||
font configure HeadingFont {*}[font actual $font]
|
||||
font configure BoldFont {*}$Option(HeadingFont) -weight bold
|
||||
set tmpOpt(HeadingFont) [font actual $font]
|
||||
raise .opt
|
||||
}
|
||||
@@ -4616,13 +4876,13 @@ proc set_button_to_errors {} {
|
||||
}
|
||||
|
||||
proc ShowErrors {} {
|
||||
global RemindErrors
|
||||
global RemindErrors Option
|
||||
set w ".errors"
|
||||
catch { destroy $w }
|
||||
toplevel $w
|
||||
text $w.t -width 80 -height 30 -wrap word -yscrollcommand "$w.sb set"
|
||||
toplevel $w -background $Option(WinBackground)
|
||||
text $w.t -width 80 -height 30 -wrap word -yscrollcommand "$w.sb set" -foreground $Option(TextColor) -background $Option(BackgroundColor) -font CalBoxFont
|
||||
scrollbar $w.sb -orient vertical -command "$w.t yview"
|
||||
button $w.ok -text OK -command DoneShowingErrors
|
||||
button $w.ok -text OK -command DoneShowingErrors -foreground $Option(TextColor) -background $Option(BackgroundColor) -highlightthickness 1 -highlightcolor $Option(LineColor) -highlightbackground $Option(WinBackground)
|
||||
grid $w.t -row 0 -column 0 -sticky nsew
|
||||
grid $w.sb -row 0 -column 1 -sticky ns
|
||||
grid $w.ok -row 1 -column 0 -stick w
|
||||
|
||||
@@ -46,10 +46,12 @@ test: all
|
||||
.c.o:
|
||||
@CC@ -c @CPPFLAGS@ @CFLAGS@ @DEFS@ $(CEXTRA) -DSYSDIR=$(datarootdir)/remind -I. -I$(srcdir) $<
|
||||
|
||||
# Extract all tr() strings into a file. NOTE: SOURCE CODE MUST NOT HAVE
|
||||
# MORE THAN ONE tr() PER LINE!!!
|
||||
xlat.c: $(REMINDSRCS)
|
||||
@echo "#include <stddef.h>" > xlat.c
|
||||
@echo "char const *translatables[] = {" >> xlat.c
|
||||
@cat $(REMINDSRCS) | grep 'tr(".*")' | sed -e 's/.*tr."/"/' -e 's/").*/"/' | LANG=C LC_ALL=C sort | uniq | grep -E -v '^"(am|at|from now|hour|minute|now|on|pm|today|tomorrow|was)"$$' | sed -e 's/^/ /' -e 's/$$/,/' >> xlat.c
|
||||
@cat $(REMINDSRCS) | grep 'tr(".*")' | sed -e 's/.*tr."/"/' -e 's/").*/"/' | LANG=C LC_ALL=C sort | uniq | grep -E -v '^"(ago|am|and|at|from now|is|hour|minute|now|on|pm|today|tomorrow|was)"$$' | sed -e 's/^/ /' -e 's/$$/,/' >> xlat.c
|
||||
@echo " NULL" >> xlat.c
|
||||
@echo "};" >> xlat.c
|
||||
|
||||
|
||||
@@ -1777,6 +1777,7 @@ static void GenerateCalEntries(int col)
|
||||
case T_ErrMsg: r=DoErrMsg(&p); break;
|
||||
case T_Rem: r=DoCalRem(&p, col); break;
|
||||
case T_If: r=DoIf(&p); break;
|
||||
case T_Return: r=DoReturn(&p); break;
|
||||
case T_IfTrig: r=DoIfTrig(&p); break;
|
||||
case T_Else: r=DoElse(&p); break;
|
||||
case T_EndIf: r=DoEndif(&p); break;
|
||||
@@ -2018,7 +2019,7 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
}
|
||||
} else {
|
||||
/* Calculate the trigger date */
|
||||
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
|
||||
dse = ComputeTrigger(get_scanfrom(&trig), &trig, &tim, &r, 1);
|
||||
if (r) {
|
||||
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
|
||||
r = OK;
|
||||
@@ -2049,6 +2050,13 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Filter unwanted events/todos */
|
||||
if ((TodoFilter == ONLY_TODOS && !trig.is_todo) ||
|
||||
(TodoFilter == ONLY_EVENTS && trig.is_todo)) {
|
||||
FreeTrig(&trig);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Save nonconst_expr flag */
|
||||
nonconst_expr = p->nonconst_expr;
|
||||
/* Convert PS and PSF to PASSTHRU */
|
||||
@@ -2148,14 +2156,18 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
}
|
||||
(void) sscanf(DBufValue(&pre_buf), "%d %d %d",
|
||||
&col_r, &col_g, &col_b);
|
||||
if (col_r < 0) col_r = 0;
|
||||
else if (col_r > 255) col_r = 255;
|
||||
if (col_g < 0) col_g = 0;
|
||||
else if (col_g > 255) col_g = 255;
|
||||
if (col_b < 0) col_b = 0;
|
||||
else if (col_b > 255) col_b = 255;
|
||||
if (!PsCal && !DoSimpleCalendar) {
|
||||
if (col_r < 0 || col_g < 0 || col_b < 0 ||
|
||||
col_r > 255 || col_g > 255 || col_b > 255) {
|
||||
is_color = 0;
|
||||
col_r = -1;
|
||||
col_g = -1;
|
||||
col_b = -1;
|
||||
trig.passthru[0] = 0;
|
||||
DBufFree(&pre_buf);
|
||||
} else {
|
||||
if (!PsCal && !DoSimpleCalendar) {
|
||||
DBufFree(&pre_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2426,7 +2438,7 @@ WriteJSONInfoChain(TrigInfo *ti)
|
||||
}
|
||||
printf("},");
|
||||
}
|
||||
void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
|
||||
void WriteJSONTrigger(Trigger const *t, int include_tags)
|
||||
{
|
||||
/* wd is an array of days from 0=monday to 6=sunday.
|
||||
We convert to array of strings */
|
||||
@@ -2454,6 +2466,8 @@ void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
|
||||
if (t->y != NO_YR) {
|
||||
PrintJSONKeyPairInt("y", t->y);
|
||||
}
|
||||
PrintJSONKeyPairInt("is_todo", t->is_todo);
|
||||
PrintJSONKeyPairDate("complete_through", t->complete_through);
|
||||
if (t->back) {
|
||||
PrintJSONKeyPairInt("back", t->back);
|
||||
}
|
||||
@@ -2499,8 +2513,15 @@ void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
|
||||
if (t->once != NO_ONCE) {
|
||||
PrintJSONKeyPairInt("once", t->once);
|
||||
}
|
||||
if (t->scanfrom != today) {
|
||||
PrintJSONKeyPairDate("scanfrom", t->scanfrom);
|
||||
if (t->scanfrom != NO_SCANFROM) {
|
||||
if (t->scanfrom >= 0) {
|
||||
PrintJSONKeyPairDate("scanfrom", t->scanfrom);
|
||||
} else {
|
||||
PrintJSONKeyPairInt("scanfrom", t->scanfrom);
|
||||
}
|
||||
}
|
||||
if (t->max_overdue >= 0) {
|
||||
PrintJSONKeyPairInt("max_overdue", t->max_overdue);
|
||||
}
|
||||
PrintJSONKeyPairDate("from", t->from);
|
||||
PrintJSONKeyPairInt("priority", t->priority);
|
||||
@@ -2528,7 +2549,7 @@ void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
|
||||
static void WriteSimpleEntryProtocol2(CalEntry *e)
|
||||
{
|
||||
char const *s;
|
||||
if (DoPrefixLineNo) {
|
||||
@@ -2555,7 +2576,7 @@ static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
|
||||
PrintJSONKeyPairInt("trep", e->tt.rep);
|
||||
}
|
||||
}
|
||||
WriteJSONTrigger(&e->trig, 0, today);
|
||||
WriteJSONTrigger(&e->trig, 0);
|
||||
if (e->nonconst_expr) {
|
||||
PrintJSONKeyPairInt("nonconst_expr", e->nonconst_expr);
|
||||
}
|
||||
@@ -2660,7 +2681,7 @@ static void WriteSimpleEntries(int col, int dse)
|
||||
}
|
||||
DidADay = 1;
|
||||
printf("{\"date\":\"%04d-%02d-%02d\",", y, m+1, d);
|
||||
WriteSimpleEntryProtocol2(e, dse);
|
||||
WriteSimpleEntryProtocol2(e);
|
||||
printf("}");
|
||||
if (PsCal != PSCAL_LEVEL3) {
|
||||
printf("\n");
|
||||
@@ -2893,7 +2914,8 @@ char const *SimpleTime(int tim)
|
||||
if (h == 0) hh=12;
|
||||
else if (h > 12) hh=h-12;
|
||||
else hh=h;
|
||||
snprintf(buf, sizeof(buf), "%d%c%02d%.64s ", hh, TimeSep, min, (h>=12) ? tr("pm") : tr("am"));
|
||||
snprintf(buf, sizeof(buf), "%d%c%02d%.64s ", hh, TimeSep, min, (h>=12) ? tr("pm") :
|
||||
tr("am"));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
531
src/dorem.c
531
src/dorem.c
@@ -32,6 +32,80 @@ static int ParseUntil (ParsePtr s, Trigger *t, int type);
|
||||
static int ShouldTriggerBasedOnWarn (Trigger const *t, int dse, int *err);
|
||||
static int ComputeTrigDuration(TimeTrig const *t);
|
||||
|
||||
void remove_trailing_newlines(DynamicBuffer *buf)
|
||||
{
|
||||
char *s = (char *) DBufValue(buf) + DBufLen(buf) - 1;
|
||||
while (s >= DBufValue(buf)) {
|
||||
if (*s == '\n') {
|
||||
*s = 0;
|
||||
s--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static int todo_filtered(Trigger const *t)
|
||||
{
|
||||
if (t->is_todo && TodoFilter == ONLY_EVENTS) return 1;
|
||||
if (!t->is_todo && TodoFilter == ONLY_TODOS) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_raw_scanfrom(Trigger const *t)
|
||||
{
|
||||
if (t->from != NO_DATE) {
|
||||
if (t->from > DSEToday) return t->from;
|
||||
return DSEToday;
|
||||
}
|
||||
if (t->scanfrom == NO_SCANFROM) return NO_SCANFROM;
|
||||
if (t->scanfrom > 0) return t->scanfrom;
|
||||
|
||||
/* Relative SCANFROM is negative, so subtract from today() */
|
||||
return DSEToday + t->scanfrom;
|
||||
}
|
||||
|
||||
int
|
||||
get_scanfrom(Trigger const *t)
|
||||
{
|
||||
int calmode = (DoSimpleCalendar || DoCalendar) ? 1 : 0;
|
||||
|
||||
/* TODOs are treated just like events in calendar mode */
|
||||
if (!calmode && t->is_todo && t->from != NO_DATE) {
|
||||
if (t->complete_through != NO_DATE) {
|
||||
if (t->complete_through+1 > t->from) {
|
||||
return t->complete_through+1;
|
||||
} else {
|
||||
return t->from;
|
||||
}
|
||||
} else {
|
||||
return t->from;
|
||||
}
|
||||
}
|
||||
if (get_raw_scanfrom(t) != NO_SCANFROM) {
|
||||
if (!calmode && t->complete_through != NO_DATE) {
|
||||
if (t->complete_through+1 > get_raw_scanfrom(t)) {
|
||||
return t->complete_through+1;
|
||||
} else {
|
||||
return get_raw_scanfrom(t);
|
||||
}
|
||||
} else {
|
||||
return get_raw_scanfrom(t);
|
||||
}
|
||||
}
|
||||
if (!calmode) {
|
||||
if (t->complete_through != NO_DATE) {
|
||||
return t->complete_through+1;
|
||||
}
|
||||
if (t->is_todo) {
|
||||
/* TODO with no COMPLETE-THROUGH.
|
||||
Scan from the beginning of time */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return DSEToday;
|
||||
}
|
||||
|
||||
static int
|
||||
ensure_expr_references_first_local_arg(expr_node *node)
|
||||
{
|
||||
@@ -213,6 +287,18 @@ int DoRem(ParsePtr p)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (trig.complete_through != NO_DATE && !trig.is_todo) {
|
||||
PurgeEchoLine("%s\n", CurLine);
|
||||
FreeTrig(&trig);
|
||||
return E_COMPLETE_WITHOUT_TODO;
|
||||
}
|
||||
|
||||
if (trig.max_overdue >= 0 && !trig.is_todo) {
|
||||
PurgeEchoLine("%s\n", CurLine);
|
||||
FreeTrig(&trig);
|
||||
return E_MAX_OVERDUE_WITHOUT_TODO;
|
||||
}
|
||||
|
||||
if (trig.typ == NO_TYPE) {
|
||||
if (!Hush) {
|
||||
PurgeEchoLine("%s\n", "#!P! Cannot parse next line");
|
||||
@@ -286,7 +372,7 @@ int DoRem(ParsePtr p)
|
||||
}
|
||||
} else {
|
||||
/* Calculate the trigger date */
|
||||
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
|
||||
dse = ComputeTrigger(get_scanfrom(&trig), &trig, &tim, &r, 1);
|
||||
if (r) {
|
||||
if (PurgeMode) {
|
||||
if (!Hush) {
|
||||
@@ -311,7 +397,7 @@ int DoRem(ParsePtr p)
|
||||
}
|
||||
}
|
||||
if (PurgeMode) {
|
||||
if (trig.expired || dse < DSEToday) {
|
||||
if (trig.expired || (!trig.is_todo && dse < DSEToday)) {
|
||||
if (p->expr_happened) {
|
||||
if (p->nonconst_expr) {
|
||||
if (!Hush) {
|
||||
@@ -339,8 +425,11 @@ int DoRem(ParsePtr p)
|
||||
if (dse == DSEToday &&
|
||||
!(!IgnoreOnce &&
|
||||
trig.once != NO_ONCE &&
|
||||
GetOnceDate() == DSEToday))
|
||||
QueueReminder(p, &trig, &tim, trig.sched);
|
||||
GetOnceDate() == DSEToday)) {
|
||||
if (!todo_filtered(&trig)) {
|
||||
QueueReminder(p, &trig, &tim, trig.sched);
|
||||
}
|
||||
}
|
||||
/* If we're in daemon mode, do nothing over here */
|
||||
if (Daemon) {
|
||||
FreeTrig(&trig);
|
||||
@@ -349,7 +438,72 @@ int DoRem(ParsePtr p)
|
||||
|
||||
r = OK;
|
||||
if (ShouldTriggerReminder(&trig, &tim, dse, &err)) {
|
||||
if ( (r=TriggerReminder(p, &trig, &tim, dse, 0, NULL)) ) {
|
||||
/* Filter unwanted events/todos */
|
||||
if (todo_filtered(&trig)) {
|
||||
FreeTrig(&trig);
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (JSONMode) {
|
||||
DynamicBuffer body;
|
||||
int y, m, d;
|
||||
int if_depth = get_if_pointer() - get_base_if_pointer();
|
||||
DBufInit(&body);
|
||||
int red=-1, green=-1, blue=-1;
|
||||
r=TriggerReminder(p, &trig, &tim, dse, 0, &body, &red, &green, &blue);
|
||||
if (r) {
|
||||
FreeTrig(&trig);
|
||||
return r;
|
||||
}
|
||||
/* Remove trailing newlines from body */
|
||||
remove_trailing_newlines(&body);
|
||||
|
||||
if (!*DBufValue(&body)) {
|
||||
FreeTrig(&trig);
|
||||
return r;
|
||||
}
|
||||
if (JSONLinesEmitted) {
|
||||
printf("},\n");
|
||||
}
|
||||
JSONLinesEmitted++;
|
||||
FromDSE(dse, &y, &m, &d);
|
||||
printf("{\"date\":\"%04d-%02d-%02d\",", y, m+1, d);
|
||||
PrintJSONKeyPairString("filename", GetCurrentFilename());
|
||||
PrintJSONKeyPairInt("lineno", LineNo);
|
||||
if (LineNoStart != LineNo) {
|
||||
PrintJSONKeyPairInt("lineno_start", LineNoStart);
|
||||
}
|
||||
PrintJSONKeyPairString("passthru", trig.passthru);
|
||||
if (trig.duration_days) {
|
||||
PrintJSONKeyPairInt("duration", trig.duration_days);
|
||||
}
|
||||
if (tim.ttime != NO_TIME) {
|
||||
PrintJSONKeyPairInt("time", tim.ttime);
|
||||
}
|
||||
if (p->nonconst_expr) {
|
||||
PrintJSONKeyPairInt("nonconst_expr", 1);
|
||||
}
|
||||
if (if_depth) {
|
||||
PrintJSONKeyPairInt("if_depth", if_depth);
|
||||
}
|
||||
if (tim.delta) {
|
||||
PrintJSONKeyPairInt("tdelta", tim.delta);
|
||||
}
|
||||
if (tim.rep) {
|
||||
PrintJSONKeyPairInt("trep", tim.rep);
|
||||
}
|
||||
if (red >= 0 && red <= 255 && green >= 0 && green <= 255 && blue >=0 && blue <= 255) {
|
||||
PrintJSONKeyPairInt("r", red);
|
||||
PrintJSONKeyPairInt("g", green);
|
||||
PrintJSONKeyPairInt("b", blue);
|
||||
}
|
||||
|
||||
WriteJSONTrigger(&trig, 1);
|
||||
printf("\"body\":\"");
|
||||
PrintJSONString(DBufValue(&body));
|
||||
printf("\"");
|
||||
} else {
|
||||
r=TriggerReminder(p, &trig, &tim, dse, 0, NULL, NULL, NULL, NULL);
|
||||
FreeTrig(&trig);
|
||||
return r;
|
||||
}
|
||||
@@ -369,6 +523,106 @@ int DoRem(ParsePtr p)
|
||||
return r;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* GetFullDate - get a full date, either YYYY-MM-DD or */
|
||||
/* YEAR MON DAY */
|
||||
/* */
|
||||
/* Returns OK on success or an error code on failure. Sets */
|
||||
/* *dse on success. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static int GetFullDate(ParsePtr s, char const *prefix, int *dse)
|
||||
{
|
||||
Token tok;
|
||||
DynamicBuffer buf;
|
||||
int y = NO_YR, m = NO_MON, d = NO_DAY;
|
||||
int r;
|
||||
*dse = NO_DATE;
|
||||
|
||||
DBufInit(&buf);
|
||||
|
||||
while(1) {
|
||||
r = ParseToken(s, &buf);
|
||||
if (r) return r;
|
||||
FindToken(DBufValue(&buf), &tok);
|
||||
switch(tok.type) {
|
||||
case T_Year:
|
||||
DBufFree(&buf);
|
||||
if (y != NO_YR) {
|
||||
Eprint("%s: %s", prefix, GetErr(E_YR_TWICE));
|
||||
return E_YR_TWICE;
|
||||
}
|
||||
y = tok.val;
|
||||
break;
|
||||
|
||||
case T_Month:
|
||||
DBufFree(&buf);
|
||||
if (m != NO_MON) {
|
||||
Eprint("%s: %s", prefix, GetErr(E_MON_TWICE));
|
||||
return E_MON_TWICE;
|
||||
}
|
||||
m = tok.val;
|
||||
break;
|
||||
|
||||
case T_Day:
|
||||
DBufFree(&buf);
|
||||
if (d != NO_DAY) {
|
||||
Eprint("%s: %s", prefix, GetErr(E_DAY_TWICE));
|
||||
return E_DAY_TWICE;
|
||||
}
|
||||
d = tok.val;
|
||||
break;
|
||||
|
||||
case T_Date:
|
||||
DBufFree(&buf);
|
||||
if (y != NO_YR) {
|
||||
Eprint("%s: %s", prefix, GetErr(E_YR_TWICE));
|
||||
return E_YR_TWICE;
|
||||
}
|
||||
if (m != NO_MON) {
|
||||
Eprint("%s: %s", prefix, GetErr(E_MON_TWICE));
|
||||
return E_MON_TWICE;
|
||||
}
|
||||
if (d != NO_DAY) {
|
||||
Eprint("%s: %s", prefix, GetErr(E_DAY_TWICE));
|
||||
return E_DAY_TWICE;
|
||||
}
|
||||
if (*dse != NO_DATE) {
|
||||
return E_DAY_TWICE;
|
||||
}
|
||||
*dse = tok.val;
|
||||
/* We're done here! */
|
||||
return OK;
|
||||
|
||||
default:
|
||||
if (tok.type == T_Illegal && tok.val < 0) {
|
||||
Eprint("%s: `%s'", GetErr(-tok.val), DBufValue(&buf));
|
||||
DBufFree(&buf);
|
||||
return -tok.val;
|
||||
}
|
||||
if (*dse == NO_DATE && (y == NO_YR || m == NO_MON || d == NO_DAY)) {
|
||||
Eprint("%s: %s", prefix, GetErr(E_INCOMPLETE));
|
||||
DBufFree(&buf);
|
||||
return E_INCOMPLETE;
|
||||
}
|
||||
if (*dse != NO_DATE) {
|
||||
PushToken(DBufValue(&buf), s);
|
||||
DBufFree(&buf);
|
||||
return OK;
|
||||
}
|
||||
if (!DateOK(y, m, d)) {
|
||||
DBufFree(&buf);
|
||||
return E_BAD_DATE;
|
||||
}
|
||||
*dse = DSE(y, m, d);
|
||||
PushToken(DBufValue(&buf), s);
|
||||
DBufFree(&buf);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* ParseRem */
|
||||
@@ -383,6 +637,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
||||
DynamicBuffer buf;
|
||||
Token tok;
|
||||
int y, m, d;
|
||||
int dse;
|
||||
int seen_delta = 0;
|
||||
|
||||
DBufInit(&buf);
|
||||
@@ -401,7 +656,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
||||
trig->addomit = 0;
|
||||
trig->noqueue = 0;
|
||||
trig->typ = NO_TYPE;
|
||||
trig->scanfrom = NO_DATE;
|
||||
trig->scanfrom = NO_SCANFROM;
|
||||
trig->from = NO_DATE;
|
||||
trig->priority = DefaultPrio;
|
||||
trig->sched[0] = 0;
|
||||
@@ -418,6 +673,9 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
||||
tim->rep = NO_REP;
|
||||
tim->duration = NO_TIME;
|
||||
trig->need_wkday = 0;
|
||||
trig->is_todo = 0;
|
||||
trig->max_overdue = -1;
|
||||
trig->complete_through = NO_DATE;
|
||||
trig->adj_for_last = 0;
|
||||
trig->infos = NULL;
|
||||
|
||||
@@ -430,6 +688,11 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
||||
/* Figure out what we've got */
|
||||
FindToken(DBufValue(&buf), &tok);
|
||||
switch(tok.type) {
|
||||
case T_Todo:
|
||||
if (trig->is_todo) return E_TODO_TWICE;
|
||||
trig->is_todo = 1;
|
||||
break;
|
||||
|
||||
case T_In:
|
||||
/* Completely ignored */
|
||||
DBufFree(&buf);
|
||||
@@ -502,6 +765,25 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
||||
trig->skip = tok.val;
|
||||
break;
|
||||
|
||||
case T_MaxOverdue:
|
||||
if (trig->max_overdue >= 0) return E_MAX_OVERDUE_TWICE;
|
||||
DBufFree(&buf);
|
||||
r = ParseToken(s, &buf);
|
||||
if (r) return r;
|
||||
FindToken(DBufValue(&buf), &tok);
|
||||
DBufFree(&buf);
|
||||
if (tok.type == T_Illegal) {
|
||||
return -tok.val;
|
||||
}
|
||||
if (tok.type != T_Day && tok.type != T_Year && tok.type != T_Number) {
|
||||
return E_EXPECTING_NUMBER;
|
||||
}
|
||||
if (tok.val < 0) {
|
||||
return E_2LOW;
|
||||
}
|
||||
trig->max_overdue = tok.val;
|
||||
break;
|
||||
|
||||
case T_Priority:
|
||||
DBufFree(&buf);
|
||||
r=ParsePriority(s, trig);
|
||||
@@ -556,6 +838,13 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
||||
if (r) return r;
|
||||
break;
|
||||
|
||||
case T_CompleteThrough:
|
||||
if (trig->complete_through != NO_DATE) return E_COMPLETE_THROUGH_TWICE;
|
||||
r = GetFullDate(s, "COMPLETE-THROUGH", &dse);
|
||||
if (r != OK) return r;
|
||||
trig->complete_through = dse;
|
||||
break;
|
||||
|
||||
case T_Until:
|
||||
DBufFree(&buf);
|
||||
r=ParseUntil(s, trig, tok.type);
|
||||
@@ -767,8 +1056,8 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
||||
if (trig->until != NO_UNTIL && trig->until < trig->from) {
|
||||
Wprint(tr("Warning: UNTIL/THROUGH date earlier than FROM date"));
|
||||
}
|
||||
} else if (trig->scanfrom != NO_DATE) {
|
||||
if (trig->until != NO_UNTIL && trig->until < trig->scanfrom) {
|
||||
} else if (get_raw_scanfrom(trig) != NO_SCANFROM) {
|
||||
if (trig->until != NO_UNTIL && trig->until < get_raw_scanfrom(trig)) {
|
||||
Wprint(tr("Warning: UNTIL/THROUGH date earlier than SCANFROM date"));
|
||||
}
|
||||
}
|
||||
@@ -778,11 +1067,6 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
||||
Wprint(tr("Warning: Useless use of UNTIL with fully-specified date and no *rep"));
|
||||
}
|
||||
|
||||
/* Set scanfrom to default if not set explicitly */
|
||||
if (trig->scanfrom == NO_DATE) {
|
||||
trig->scanfrom = DSEToday;
|
||||
}
|
||||
|
||||
/* Check that any SCHED / WARN / OMITFUNC functions refer to
|
||||
their arguments */
|
||||
check_trigger_function(trig->sched, "SCHED");
|
||||
@@ -884,93 +1168,25 @@ static int ParseLocalOmit(ParsePtr s, Trigger *t)
|
||||
/***************************************************************/
|
||||
static int ParseUntil(ParsePtr s, Trigger *t, int type)
|
||||
{
|
||||
int y = NO_YR,
|
||||
m = NO_MON,
|
||||
d = NO_DAY;
|
||||
|
||||
char const *which;
|
||||
int dse;
|
||||
|
||||
if (type == T_Until) {
|
||||
which = "UNTIL";
|
||||
} else {
|
||||
which = "THROUGH";
|
||||
}
|
||||
Token tok;
|
||||
int r;
|
||||
DynamicBuffer buf;
|
||||
DBufInit(&buf);
|
||||
|
||||
if (t->until != NO_UNTIL) return E_UNTIL_TWICE;
|
||||
|
||||
while(1) {
|
||||
r = ParseToken(s, &buf);
|
||||
if (r) return r;
|
||||
FindToken(DBufValue(&buf), &tok);
|
||||
switch(tok.type) {
|
||||
case T_Year:
|
||||
DBufFree(&buf);
|
||||
if (y != NO_YR) {
|
||||
Eprint("%s: %s", which, GetErr(E_YR_TWICE));
|
||||
return E_YR_TWICE;
|
||||
}
|
||||
y = tok.val;
|
||||
break;
|
||||
|
||||
case T_Month:
|
||||
DBufFree(&buf);
|
||||
if (m != NO_MON) {
|
||||
Eprint("%s: %s", which, GetErr(E_MON_TWICE));
|
||||
return E_MON_TWICE;
|
||||
}
|
||||
m = tok.val;
|
||||
break;
|
||||
|
||||
case T_Day:
|
||||
DBufFree(&buf);
|
||||
if (d != NO_DAY) {
|
||||
Eprint("%s: %s", which, GetErr(E_DAY_TWICE));
|
||||
return E_DAY_TWICE;
|
||||
}
|
||||
d = tok.val;
|
||||
break;
|
||||
|
||||
case T_Date:
|
||||
DBufFree(&buf);
|
||||
if (y != NO_YR) {
|
||||
Eprint("%s: %s", which, GetErr(E_YR_TWICE));
|
||||
return E_YR_TWICE;
|
||||
}
|
||||
if (m != NO_MON) {
|
||||
Eprint("%s: %s", which, GetErr(E_MON_TWICE));
|
||||
return E_MON_TWICE;
|
||||
}
|
||||
if (d != NO_DAY) {
|
||||
Eprint("%s: %s", which, GetErr(E_DAY_TWICE));
|
||||
return E_DAY_TWICE;
|
||||
}
|
||||
FromDSE(tok.val, &y, &m, &d);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (tok.type == T_Illegal && tok.val < 0) {
|
||||
Eprint("%s: `%s'", GetErr(-tok.val), DBufValue(&buf));
|
||||
DBufFree(&buf);
|
||||
return -tok.val;
|
||||
}
|
||||
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
|
||||
Eprint("%s: %s", which, GetErr(E_INCOMPLETE));
|
||||
DBufFree(&buf);
|
||||
return E_INCOMPLETE;
|
||||
}
|
||||
if (!DateOK(y, m, d)) {
|
||||
DBufFree(&buf);
|
||||
return E_BAD_DATE;
|
||||
}
|
||||
t->until = DSE(y, m, d);
|
||||
PushToken(DBufValue(&buf), s);
|
||||
DBufFree(&buf);
|
||||
return OK;
|
||||
}
|
||||
int r = GetFullDate(s, which, &dse);
|
||||
if (r != OK) {
|
||||
return r;
|
||||
}
|
||||
|
||||
t->until = dse;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
@@ -980,12 +1196,9 @@ static int ParseUntil(ParsePtr s, Trigger *t, int type)
|
||||
/***************************************************************/
|
||||
static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
|
||||
{
|
||||
int y = NO_YR,
|
||||
m = NO_MON,
|
||||
d = NO_DAY;
|
||||
|
||||
Token tok;
|
||||
int r;
|
||||
int y = NO_YR, m = NO_MON, d = NO_DAY;
|
||||
Token tok;
|
||||
DynamicBuffer buf;
|
||||
char const *word;
|
||||
|
||||
@@ -996,8 +1209,8 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
|
||||
word = "FROM";
|
||||
}
|
||||
|
||||
if (t->scanfrom != NO_DATE) return E_SCAN_TWICE;
|
||||
|
||||
if (t->scanfrom != NO_SCANFROM) return E_SCAN_TWICE;
|
||||
if (t->from != NO_DATE) return E_SCAN_TWICE;
|
||||
while(1) {
|
||||
r = ParseToken(s, &buf);
|
||||
if (r) return r;
|
||||
@@ -1044,8 +1257,12 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
|
||||
Eprint("%s: %s", word, GetErr(E_DAY_TWICE));
|
||||
return E_DAY_TWICE;
|
||||
}
|
||||
FromDSE(tok.val, &y, &m, &d);
|
||||
break;
|
||||
if (type == FROM_TYPE) {
|
||||
t->from = tok.val;
|
||||
} else {
|
||||
t->scanfrom = tok.val;
|
||||
}
|
||||
return OK;
|
||||
|
||||
case T_Back:
|
||||
DBufFree(&buf);
|
||||
@@ -1065,15 +1282,14 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
|
||||
Eprint("%s: %s", word, GetErr(E_DAY_TWICE));
|
||||
return E_DAY_TWICE;
|
||||
}
|
||||
if (tok.val < 0) {
|
||||
if (tok.val > 0) {
|
||||
tok.val = -tok.val;
|
||||
}
|
||||
FromDSE(DSEToday - tok.val, &y, &m, &d);
|
||||
/* Don't purge reminders with a relative scanfrom */
|
||||
t->scanfrom = tok.val;
|
||||
s->expr_happened = 1;
|
||||
nonconst_debug(s->nonconst_expr, tr("Relative SCANFROM counts as a non-constant expression"));
|
||||
s->nonconst_expr = 1;
|
||||
break;
|
||||
return OK;
|
||||
|
||||
default:
|
||||
if (tok.type == T_Illegal && tok.val < 0) {
|
||||
@@ -1090,14 +1306,10 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
|
||||
DBufFree(&buf);
|
||||
return E_BAD_DATE;
|
||||
}
|
||||
t->scanfrom = DSE(y, m, d);
|
||||
if (type == FROM_TYPE) {
|
||||
t->from = t->scanfrom;
|
||||
if (t->scanfrom < DSEToday) {
|
||||
t->scanfrom = DSEToday;
|
||||
}
|
||||
t->from = DSE(y, m, d);
|
||||
} else {
|
||||
t->from = NO_DATE;
|
||||
t->scanfrom = DSE(y, m, d);
|
||||
}
|
||||
|
||||
PushToken(DBufValue(&buf), s);
|
||||
@@ -1115,7 +1327,7 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
|
||||
/* Trigger the reminder if it's a RUN or MSG type. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is_queued, DynamicBuffer *output)
|
||||
int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is_queued, DynamicBuffer *output, int *rr, int *gg, int *bb)
|
||||
{
|
||||
int r, y, m, d;
|
||||
int adjusted_for_newline = 0;
|
||||
@@ -1180,17 +1392,37 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is
|
||||
DBufFree(&buf);
|
||||
if (r) return r;
|
||||
t->typ = MSG_TYPE;
|
||||
|
||||
if (red < 0 || green < 0 || blue < 0 || red > 255 || green > 255 || blue > 255) {
|
||||
red = -1;
|
||||
green = -1;
|
||||
blue = -1;
|
||||
t->passthru[0] = 0;
|
||||
}
|
||||
}
|
||||
/* If it's a MSG-type reminder, and no -k option was used, issue the banner. */
|
||||
if ((t->typ == MSG_TYPE || t->typ == MSF_TYPE)
|
||||
&& !DidMsgReminder && !NextMode && !msg_command && !is_queued) {
|
||||
DynamicBuffer buf2;
|
||||
DBufInit(&buf2);
|
||||
DidMsgReminder = 1;
|
||||
if (!DoSubstFromString(DBufValue(&Banner), &buf,
|
||||
if (!DoSubstFromString(DBufValue(&Banner), &buf2,
|
||||
DSEToday, NO_TIME) &&
|
||||
DBufLen(&buf)) {
|
||||
printf("%s\n", DBufValue(&buf));
|
||||
DBufLen(&buf2)) {
|
||||
if (!JSONMode) {
|
||||
printf("%s\n", DBufValue(&buf2));
|
||||
} else {
|
||||
if (JSONLinesEmitted) {
|
||||
printf("},\n");
|
||||
}
|
||||
JSONLinesEmitted++;
|
||||
printf("{\"banner\":\"");
|
||||
remove_trailing_newlines(&buf2);
|
||||
PrintJSONString(DBufValue(&buf2));
|
||||
printf("\"");
|
||||
}
|
||||
}
|
||||
DBufFree(&buf);
|
||||
DBufFree(&buf2);
|
||||
}
|
||||
|
||||
/* If it's NextMode, process as a ADVANCE_MODE-type entry, and issue
|
||||
@@ -1265,7 +1497,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is
|
||||
}
|
||||
|
||||
/* Correct colors */
|
||||
if (UseVTColors) {
|
||||
if (JSONMode || UseVTColors) {
|
||||
if (red == -1 && green == -1 && blue == -1) {
|
||||
if (DefaultColorR != -1 && DefaultColorG != -1 && DefaultColorB != -1) {
|
||||
red = DefaultColorR;
|
||||
@@ -1279,6 +1511,17 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is
|
||||
if (green > 255) green = 255;
|
||||
if (blue > 255) blue = 255;
|
||||
}
|
||||
if (rr) *rr = red;
|
||||
if (gg) *gg = green;
|
||||
if (bb) *bb = blue;
|
||||
|
||||
/* Don't ANSI-colorize JSON output! */
|
||||
if (JSONMode) {
|
||||
is_color = 0;
|
||||
red = -1;
|
||||
green = -1;
|
||||
blue = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Put the substituted string into the substitution buffer */
|
||||
@@ -1430,13 +1673,41 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is
|
||||
int ShouldTriggerReminder(Trigger const *t, TimeTrig const *tim, int dse, int *err)
|
||||
{
|
||||
int r, omit;
|
||||
int calmode = (DoSimpleCalendar || DoCalendar) ? 1 : 0;
|
||||
if (HideCompletedTodos) calmode = 0;
|
||||
|
||||
*err = 0;
|
||||
|
||||
/* Handle the ONCE modifier in the reminder. */
|
||||
if (!IgnoreOnce && t->once !=NO_ONCE && GetOnceDate() == DSEToday)
|
||||
return 0;
|
||||
|
||||
if (dse < DSEToday) return 0;
|
||||
/* TODOs are handled differently */
|
||||
if (t->is_todo && !calmode) {
|
||||
/* Do NOT trigger if TODO has been completed through today (or later) */
|
||||
if (t->complete_through != NO_DATE && t->complete_through >= DSEToday && dse <= t->complete_through) {
|
||||
return 0;
|
||||
}
|
||||
/* DO trigger if has not been completed through trigger date */
|
||||
if (t->complete_through == NO_DATE || t->complete_through < dse) {
|
||||
/* Trigger date is in the past - overdue, Trigger unless we're
|
||||
more than max_overdue days late */
|
||||
if (dse < DSEToday) {
|
||||
if (t->max_overdue >= 0) {
|
||||
if (dse + t->max_overdue < DSEToday) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/* Trigger date in future - use normal Remind rules */
|
||||
} else {
|
||||
/* We're complete as of trigger date */
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (dse < DSEToday) return 0;
|
||||
}
|
||||
|
||||
/* Don't trigger timed reminders if DontIssueAts is true, and if the
|
||||
reminder is for today */
|
||||
@@ -1530,7 +1801,7 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
|
||||
ensure_satnode_mentions_trigdate(sat_node);
|
||||
|
||||
iter = 0;
|
||||
start = trig->scanfrom;
|
||||
start = get_scanfrom(trig);
|
||||
while (iter++ < MaxSatIter) {
|
||||
dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, 0);
|
||||
if (r) {
|
||||
@@ -1569,7 +1840,7 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
|
||||
}
|
||||
if ((v.type == INT_TYPE && v.v.val) ||
|
||||
(v.type == STR_TYPE && *v.v.str)) {
|
||||
AdjustTriggerForDuration(trig->scanfrom, dse, trig, tt, 1);
|
||||
AdjustTriggerForDuration(get_scanfrom(trig), dse, trig, tt, 1);
|
||||
if (DebugFlag & DB_PRTTRIG) {
|
||||
int y, m, d;
|
||||
FromDSE(LastTriggerDate, &y, &m, &d);
|
||||
@@ -1712,6 +1983,32 @@ static int ShouldTriggerBasedOnWarn(Trigger const *t, int dse, int *err)
|
||||
int r, omit;
|
||||
Value v;
|
||||
int lastReturnVal = 0; /* Silence compiler warning */
|
||||
int calmode = (DoSimpleCalendar || DoCalendar) ? 1 : 0;
|
||||
|
||||
/* TODOs are handled differently */
|
||||
if (t->is_todo && !calmode) {
|
||||
/* Do NOT trigger if TODO has been completed through today (or later) */
|
||||
if (t->complete_through != NO_DATE && t->complete_through >= DSEToday) {
|
||||
return 0;
|
||||
}
|
||||
/* DO trigger if has not been completed through trigger date */
|
||||
if (t->complete_through == NO_DATE || t->complete_through < dse) {
|
||||
/* Trigger date is in the past - overdue, Trigger unless we're
|
||||
more than max_overdue days late */
|
||||
if (dse < DSEToday) {
|
||||
if (t->max_overdue >= 0) {
|
||||
if (dse + t->max_overdue < DSEToday) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/* Trigger date in future - use normal Remind rules */
|
||||
} else {
|
||||
/* We're complete as of trigger date */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no proper function exists, barf... */
|
||||
if (UserFuncExists(t->warn) != 1) {
|
||||
|
||||
115
src/dosubst.c
115
src/dosubst.c
@@ -31,6 +31,39 @@
|
||||
|
||||
#define SHIP_OUT(s) if(DBufPuts(dbuf, s) != OK) return E_NO_MEM
|
||||
|
||||
static char const *
|
||||
get_function_override(int c, int addx)
|
||||
{
|
||||
static char func[32];
|
||||
|
||||
if (isalnum(c) || c == '_') {
|
||||
if (addx) {
|
||||
snprintf(func, sizeof(func), "subst_%cx", tolower(c));
|
||||
} else {
|
||||
snprintf(func, sizeof(func), "subst_%c", tolower(c));
|
||||
}
|
||||
return func;
|
||||
}
|
||||
if (addx) {
|
||||
switch(c) {
|
||||
case ':': return "subst_colonx";
|
||||
case '!': return "subst_bangx";
|
||||
case '?': return "subst_questionx";
|
||||
case '@': return "subst_atx";
|
||||
case '#': return "subst_hashx";
|
||||
}
|
||||
} else {
|
||||
switch(c) {
|
||||
case ':': return "subst_colon";
|
||||
case '!': return "subst_bang";
|
||||
case '?': return "subst_question";
|
||||
case '@': return "subst_at";
|
||||
case '#': return "subst_hash";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
check_subst_args(UserFunc *f, int n)
|
||||
{
|
||||
@@ -57,6 +90,8 @@ check_subst_args(UserFunc *f, int n)
|
||||
int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int dse, int mode)
|
||||
{
|
||||
int diff = dse - DSEToday;
|
||||
int rdiff = dse - RealToday;
|
||||
int bangdiff = diff;
|
||||
int curtime = MinutesPastMidnight(0);
|
||||
int err, done;
|
||||
int c;
|
||||
@@ -67,12 +102,13 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
char const *pm, *cpm;
|
||||
int tdiff, adiff, mdiff, hdiff;
|
||||
char const *mplu, *hplu, *when, *plu;
|
||||
char const *is, *was;
|
||||
int has_quote = 0;
|
||||
char *ss;
|
||||
char const *expr;
|
||||
char *os;
|
||||
char s[256];
|
||||
char uf[32];
|
||||
char const *substname;
|
||||
char mypm[64];
|
||||
char mycpm[64];
|
||||
char myplu[64];
|
||||
@@ -98,7 +134,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
mplu = (mdiff == 1 ? "" : DynamicMplu);
|
||||
hplu = (hdiff == 1 ? "" : DynamicHplu);
|
||||
|
||||
when = (tdiff < 0) ? tr("ago") : tr("from now");
|
||||
when = (tdiff < 0) ? tr("ago") :
|
||||
tr("from now");
|
||||
|
||||
h = tim / 60;
|
||||
min = tim % 60;
|
||||
@@ -122,7 +159,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
}
|
||||
}
|
||||
if (r != OK) {
|
||||
pm = (h < 12) ? tr("am") : tr("pm");
|
||||
pm = (h < 12) ? tr("am") :
|
||||
tr("pm");
|
||||
}
|
||||
|
||||
hh = (h == 12 || h == 0) ? 12 : h % 12;
|
||||
@@ -149,7 +187,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
}
|
||||
}
|
||||
if (r != OK) {
|
||||
cpm = (h < 12) ? tr("am") : tr("pm");
|
||||
cpm = (h < 12) ? tr("am") :
|
||||
tr("pm");
|
||||
}
|
||||
chh = (ch == 0 || ch == 12) ? 12 : ch % 12;
|
||||
|
||||
@@ -334,11 +373,15 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
continue;
|
||||
}
|
||||
done = 0;
|
||||
snprintf(uf, sizeof(uf), "subst_%c", tolower(c));
|
||||
func = FindUserFunc(uf);
|
||||
substname = get_function_override(c, 0);
|
||||
if (substname) {
|
||||
func = FindUserFunc(substname);
|
||||
} else {
|
||||
func = NULL;
|
||||
}
|
||||
if (func && check_subst_args(func, 3)) {
|
||||
snprintf(s, sizeof(s), "subst_%c(%d,'%04d-%02d-%02d',%02d:%02d)",
|
||||
tolower(c), altmode ? 1 : 0, y, m+1, d, h, min);
|
||||
snprintf(s, sizeof(s), "%s(%d,'%04d-%02d-%02d',%02d:%02d)",
|
||||
substname, altmode ? 1 : 0, y, m+1, d, h, min);
|
||||
expr = (char const *) s;
|
||||
r = EvalExpr(&expr, &v, NULL);
|
||||
if (r == OK) {
|
||||
@@ -358,7 +401,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
}
|
||||
}
|
||||
|
||||
if (diff <= 1) {
|
||||
if (abs(diff) <= 1) {
|
||||
switch(UPPER(c)) {
|
||||
case 'A':
|
||||
case 'B':
|
||||
@@ -373,7 +416,9 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
case 'L':
|
||||
case 'U':
|
||||
case 'V':
|
||||
snprintf(s, sizeof(s), "%s", (diff ? tr("tomorrow") : tr("today")));
|
||||
snprintf(s, sizeof(s), "%s", (diff == 1 ? tr("tomorrow") :
|
||||
diff == -1 ? tr("yesterday") :
|
||||
tr("today")));
|
||||
SHIP_OUT(s);
|
||||
done = 1;
|
||||
break;
|
||||
@@ -384,11 +429,15 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
|
||||
|
||||
if (!done) {
|
||||
snprintf(uf, sizeof(uf), "subst_%cx", tolower(c));
|
||||
func = FindUserFunc(uf);
|
||||
substname = get_function_override(c, 1);
|
||||
if (substname) {
|
||||
func = FindUserFunc(substname);
|
||||
} else {
|
||||
func = NULL;
|
||||
}
|
||||
if (func && check_subst_args(func, 3)) {
|
||||
snprintf(s, sizeof(s), "subst_%cx(%d,'%04d-%02d-%02d',%02d:%02d)",
|
||||
tolower(c), altmode ? 1 : 0, y, m+1, d, h, min);
|
||||
snprintf(s, sizeof(s), "%s(%d,'%04d-%02d-%02d',%02d:%02d)",
|
||||
substname, altmode ? 1 : 0, y, m+1, d, h, min);
|
||||
expr = (char const *) s;
|
||||
r = EvalExpr(&expr, &v, NULL);
|
||||
if (r == OK) {
|
||||
@@ -408,7 +457,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
}
|
||||
}
|
||||
if (origtime == NO_TIME) {
|
||||
if ((c >= '0' && c <= '9') || (c == '!')) {
|
||||
if ((c >= '0' && c <= '9')) {
|
||||
Wprint(tr("`%%%c' substitution sequence should not be used without an AT clause"), c);
|
||||
}
|
||||
}
|
||||
@@ -426,7 +475,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
snprintf(s, sizeof(s), "in %d days' time", diff);
|
||||
if (diff > 0) {
|
||||
snprintf(s, sizeof(s), "in %d days' time", diff);
|
||||
} else {
|
||||
snprintf(s, sizeof(s), "%d days ago", -diff);
|
||||
}
|
||||
SHIP_OUT(s);
|
||||
break;
|
||||
|
||||
@@ -605,6 +658,12 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
SHIP_OUT(s);
|
||||
break;
|
||||
|
||||
case ':':
|
||||
if (t->is_todo && t->complete_through != NO_DATE && t->complete_through >= dse) {
|
||||
snprintf(s, sizeof(s), " (%s)", tr("done"));
|
||||
SHIP_OUT(s);
|
||||
}
|
||||
break;
|
||||
case '1':
|
||||
if (tdiff == 0)
|
||||
snprintf(s, sizeof(s), "%s", tr("now"));
|
||||
@@ -614,7 +673,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
snprintf(s, sizeof(s), "%d %s%s %s", hdiff, tr("hour"), hplu, when);
|
||||
else
|
||||
snprintf(s, sizeof(s), "%d %s%s %s %d %s%s %s", hdiff, tr("hour"), hplu,
|
||||
tr("and"), mdiff, tr("minute"), mplu, when);
|
||||
tr("and"), mdiff,
|
||||
tr("minute"), mplu, when);
|
||||
SHIP_OUT(s);
|
||||
break;
|
||||
|
||||
@@ -672,7 +732,26 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int
|
||||
break;
|
||||
|
||||
case '!':
|
||||
snprintf(s, sizeof(s), "%s", (tdiff >= 0 ? tr("is") : tr("was")));
|
||||
case '?':
|
||||
if (c == '!') {
|
||||
is = tr("is");
|
||||
was = tr("was");
|
||||
} else {
|
||||
is = tr("are");
|
||||
was = tr("were");
|
||||
}
|
||||
if (altmode) {
|
||||
bangdiff = rdiff;
|
||||
} else {
|
||||
bangdiff = diff;
|
||||
}
|
||||
if (bangdiff > 0) {
|
||||
snprintf(s, sizeof(s), "%s", is);
|
||||
} else if (bangdiff < 0) {
|
||||
snprintf(s, sizeof(s), "%s", was);
|
||||
} else {
|
||||
snprintf(s, sizeof(s), "%s", (tdiff >= 0 ? is : was));
|
||||
}
|
||||
SHIP_OUT(s);
|
||||
break;
|
||||
|
||||
|
||||
14
src/err.h
14
src/err.h
@@ -76,7 +76,7 @@
|
||||
#define E_DAY_TWICE 52
|
||||
#define E_UNKNOWN_TOKEN 53
|
||||
#define E_SPEC_MON 54
|
||||
/* #define E_2MANY_PART 55 */
|
||||
#define E_TODO_TWICE 55
|
||||
#define E_2MANY_FULL 56
|
||||
#define E_PUSH_NOPOP 57
|
||||
#define E_ERR_READING 58
|
||||
@@ -114,7 +114,7 @@
|
||||
#define E_MISS_EQ 90
|
||||
#define E_MISS_VAR 91
|
||||
#define E_MISS_EXPR 92
|
||||
/* #define M_CANTSET_ACCESS 93 */
|
||||
#define E_COMPLETE_THROUGH_TWICE 93
|
||||
#define M_I_OPTION 94
|
||||
#define E_NOREMINDERS 95
|
||||
#define M_QUEUED 96
|
||||
@@ -129,6 +129,9 @@
|
||||
#define E_REPEATED_ARG 105
|
||||
#define E_EXPR_DISABLED 106
|
||||
#define E_TIME_EXCEEDED 107
|
||||
#define E_COMPLETE_WITHOUT_TODO 108
|
||||
#define E_MAX_OVERDUE_TWICE 109
|
||||
#define E_MAX_OVERDUE_WITHOUT_TODO 110
|
||||
|
||||
#ifdef MK_GLOBALS
|
||||
#undef EXTERN
|
||||
@@ -202,7 +205,7 @@ EXTERN char *ErrMsg[]
|
||||
/* E_DAY_TWICE */ "Day specified twice",
|
||||
/* E_UNKNOWN_TOKEN */ "Unknown token",
|
||||
/* E_SPEC_MON */ "Must specify month in OMIT command",
|
||||
/* E_2MANY_PART */ "",
|
||||
/* E_TODO_TWICE */ "TODO specified twice",
|
||||
/* E_2MANY_FULL */ "Too many full OMITs (max. " STR(MAX_FULL_OMITS) ")",
|
||||
/* E_PUSH_NOPOP */ "Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT",
|
||||
/* E_ERR_READING */ "Error reading",
|
||||
@@ -240,7 +243,7 @@ EXTERN char *ErrMsg[]
|
||||
/* E_MISS_EQ */ "Missing '=' sign",
|
||||
/* E_MISS_VAR */ "Missing variable name",
|
||||
/* E_MISS_EXPR */ "Missing expression",
|
||||
/* M_CANTSET_ACCESS */ "",
|
||||
/* E_COMPLETE_THROUGH_TWICE */ "COMPLETE-THROUGH specified twice",
|
||||
/* M_I_OPTION */ "Remind: '-i' option: %s",
|
||||
/* E_NOREMINDERS */ "No reminders.",
|
||||
/* M_QUEUED */ "%d reminder(s) queued for later today.",
|
||||
@@ -255,6 +258,9 @@ EXTERN char *ErrMsg[]
|
||||
/* E_REPEATED_ARG */ "Duplicate argument name",
|
||||
/* E_EXPR_DISABLED */ "Expression evaluation is disabled",
|
||||
/* E_TIME_EXCEEDED */ "Time limit for expression evaluation exceeded",
|
||||
/* E_COMPLETE_WITHOUT_TODO */ "COMPLETE-THROUGH specified without TODO",
|
||||
/* E_MAX_OVERDUE_TWICE */ "MAX-OVERDUE specified twice",
|
||||
/* E_MAX_OVERDUE_WITHOUT_TODO */ "MAX-OVERDUE specified without TODO",
|
||||
}
|
||||
#endif /* MK_GLOBALS */
|
||||
;
|
||||
|
||||
25
src/files.c
25
src/files.c
@@ -179,17 +179,14 @@ got_a_fresh_line(void)
|
||||
WarnedAboutImplicit = 0;
|
||||
}
|
||||
|
||||
static void set_cloexec(FILE *fp)
|
||||
void set_cloexec(int fd)
|
||||
{
|
||||
int flags;
|
||||
int fd;
|
||||
if (fp) {
|
||||
fd = fileno(fp);
|
||||
flags = fcntl(fd, F_GETFD);
|
||||
if (flags >= 0) {
|
||||
flags |= FD_CLOEXEC;
|
||||
fcntl(fd, F_SETFD, flags);
|
||||
}
|
||||
|
||||
flags = fcntl(fd, F_GETFD);
|
||||
if (flags >= 0) {
|
||||
flags |= FD_CLOEXEC;
|
||||
fcntl(fd, F_SETFD, flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +215,7 @@ static void OpenPurgeFile(char const *fname, char const *mode)
|
||||
fprintf(ErrFp, tr("Cannot open `%s' for writing: %s"), DBufValue(&fname_buf), strerror(errno));
|
||||
fprintf(ErrFp, "\n");
|
||||
}
|
||||
set_cloexec(PurgeFP);
|
||||
set_cloexec(fileno(PurgeFP));
|
||||
DBufFree(&fname_buf);
|
||||
}
|
||||
|
||||
@@ -427,7 +424,9 @@ static int OpenFile(char const *fname)
|
||||
}
|
||||
} else {
|
||||
fp = fopen(fname, "r");
|
||||
set_cloexec(fp);
|
||||
if (fp) {
|
||||
set_cloexec(fileno(fp));
|
||||
}
|
||||
if (DebugFlag & DB_TRACE_FILES) {
|
||||
fprintf(ErrFp, tr("Reading `%s': Opening file on disk"), fname);
|
||||
fprintf(ErrFp, "\n");
|
||||
@@ -449,7 +448,7 @@ static int OpenFile(char const *fname)
|
||||
if (strcmp(fname, "-")) {
|
||||
fp = fopen(fname, "r");
|
||||
if (!fp || !CheckSafety()) return E_CANT_OPEN;
|
||||
set_cloexec(fp);
|
||||
set_cloexec(fileno(fp));
|
||||
if (PurgeMode) OpenPurgeFile(fname, "w");
|
||||
} else {
|
||||
fp = stdin;
|
||||
@@ -650,7 +649,7 @@ static int PopFile(void)
|
||||
if (strcmp(i->filename, "-")) {
|
||||
fp = fopen(i->filename, "r");
|
||||
if (!fp || !CheckSafety()) return E_CANT_OPEN;
|
||||
set_cloexec(fp);
|
||||
set_cloexec(fileno(fp));
|
||||
if (PurgeMode) OpenPurgeFile(i->filename, "a");
|
||||
} else {
|
||||
fp = stdin;
|
||||
|
||||
75
src/funcs.c
75
src/funcs.c
@@ -173,6 +173,7 @@ static int FToday (func_info *);
|
||||
static int FTrig (func_info *);
|
||||
static int FTrigback (func_info *);
|
||||
static int FTrigbase (func_info *info);
|
||||
static int FTrigcompletethrough (func_info *);
|
||||
static int FTrigdate (func_info *);
|
||||
static int FTrigdatetime (func_info *);
|
||||
static int FTrigdelta (func_info *);
|
||||
@@ -182,6 +183,8 @@ static int FTrigeventduration(func_info *);
|
||||
static int FTrigeventstart (func_info *);
|
||||
static int FTrigfrom (func_info *);
|
||||
static int FTrigger (func_info *);
|
||||
static int FTrigistodo (func_info *);
|
||||
static int FTrigmaxoverdue (func_info *);
|
||||
static int FTrigpriority (func_info *);
|
||||
static int FTrigrep (func_info *);
|
||||
static int FTrigscanfrom (func_info *);
|
||||
@@ -347,6 +350,7 @@ BuiltinFunc Func[] = {
|
||||
{ "trig", 0, NO_MAX, 0, FTrig, NULL },
|
||||
{ "trigback", 0, 0, 0, FTrigback, NULL },
|
||||
{ "trigbase", 0, 0, 0, FTrigbase, NULL },
|
||||
{ "trigcompletethrough", 0, 0, 0, FTrigcompletethrough, NULL },
|
||||
{ "trigdate", 0, 0, 0, FTrigdate, NULL },
|
||||
{ "trigdatetime", 0, 0, 0, FTrigdatetime, NULL },
|
||||
{ "trigdelta", 0, 0, 0, FTrigdelta, NULL },
|
||||
@@ -356,6 +360,8 @@ BuiltinFunc Func[] = {
|
||||
{ "trigfrom", 0, 0, 0, FTrigfrom, NULL },
|
||||
{ "trigger", 1, 3, 0, FTrigger, NULL },
|
||||
{ "triginfo", 1, 1, 0, FTriginfo, NULL },
|
||||
{ "trigistodo", 0, 0, 0, FTrigistodo, NULL },
|
||||
{ "trigmaxoverdue", 0, 0, 0, FTrigmaxoverdue, NULL },
|
||||
{ "trigpriority", 0, 0, 0, FTrigpriority, NULL },
|
||||
{ "trigrep", 0, 0, 0, FTrigrep, NULL },
|
||||
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom, NULL },
|
||||
@@ -1150,6 +1156,7 @@ static int FAmpm(func_info *info)
|
||||
/***************************************************************/
|
||||
static int FOrd(func_info *info)
|
||||
{
|
||||
static int in_ford = 0;
|
||||
int t, u, v;
|
||||
char const *s;
|
||||
|
||||
@@ -1157,6 +1164,36 @@ static int FOrd(func_info *info)
|
||||
|
||||
ASSERT_TYPE(0, INT_TYPE);
|
||||
|
||||
if (!in_ford && UserFuncExists("ordx") == 1) {
|
||||
expr_node *n;
|
||||
int r;
|
||||
char const *e = buf;
|
||||
Value val;
|
||||
int nonconst;
|
||||
|
||||
val.type = ERR_TYPE;
|
||||
snprintf(buf, sizeof(buf), "ordx(%d)", ARGV(0));
|
||||
n = parse_expression(&e, &r, NULL);
|
||||
if (r != OK) {
|
||||
return r;
|
||||
}
|
||||
in_ford = 1;
|
||||
r = evaluate_expr_node(n, NULL, &val, &nonconst);
|
||||
in_ford = 0;
|
||||
free_expr_tree(n);
|
||||
if (r != OK) {
|
||||
return r;
|
||||
}
|
||||
if (nonconst) info->nonconst = nonconst;
|
||||
r = DoCoerce(STR_TYPE, &val);
|
||||
if (r != OK) {
|
||||
DestroyValue(val);
|
||||
return r;
|
||||
}
|
||||
DCOPYVAL(RetVal, val);
|
||||
return OK;
|
||||
}
|
||||
|
||||
v = ARGV(0);
|
||||
if (v < 0) {
|
||||
t = (-v) % 100;
|
||||
@@ -1866,6 +1903,32 @@ static int FTrigback(func_info *info)
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigcompletethrough(func_info *info)
|
||||
{
|
||||
if (!LastTrigger.is_todo || LastTrigger.complete_through == NO_DATE) {
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = 0;
|
||||
return OK;
|
||||
}
|
||||
RetVal.type = DATE_TYPE;
|
||||
RETVAL = LastTrigger.complete_through;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigistodo(func_info *info)
|
||||
{
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = LastTrigger.is_todo;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigmaxoverdue(func_info *info)
|
||||
{
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = LastTrigger.max_overdue;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigdelta(func_info *info)
|
||||
{
|
||||
RetVal.type = INT_TYPE;
|
||||
@@ -1967,12 +2030,12 @@ static int FTriguntil(func_info *info)
|
||||
|
||||
static int FTrigscanfrom(func_info *info)
|
||||
{
|
||||
if (LastTrigger.scanfrom == NO_DATE) {
|
||||
if (get_scanfrom(&LastTrigger) == NO_DATE) {
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = -1;
|
||||
} else {
|
||||
RetVal.type = DATE_TYPE;
|
||||
RETVAL = LastTrigger.scanfrom;
|
||||
RETVAL = get_scanfrom(&LastTrigger);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
@@ -4147,10 +4210,10 @@ FEvalTrig(func_info *info)
|
||||
return E_PARSE_ERR;
|
||||
}
|
||||
if (scanfrom == NO_DATE) {
|
||||
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
|
||||
dse = ComputeTrigger(get_scanfrom(&trig), &trig, &tim, &r, 0);
|
||||
} else {
|
||||
/* Hokey... */
|
||||
if (trig.scanfrom != DSEToday) {
|
||||
if (get_scanfrom(&trig) != DSEToday) {
|
||||
Wprint(tr("Warning: SCANFROM is ignored in two-argument form of evaltrig()"));
|
||||
}
|
||||
dse = ComputeTrigger(scanfrom, &trig, &tim, &r, 0);
|
||||
@@ -4209,7 +4272,7 @@ FMultiTrig(func_info *info)
|
||||
Eprint(tr("Cannot use AT clause in multitrig() function"));
|
||||
return E_PARSE_ERR;
|
||||
}
|
||||
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
|
||||
dse = ComputeTrigger(get_scanfrom(&trig), &trig, &tim, &r, 0);
|
||||
DestroyParser(&p);
|
||||
|
||||
if (r != E_CANT_TRIG) {
|
||||
@@ -4262,7 +4325,7 @@ FTrig(func_info *info)
|
||||
FreeTrig(&trig);
|
||||
return E_PARSE_ERR;
|
||||
}
|
||||
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
|
||||
dse = ComputeTrigger(get_scanfrom(&trig), &trig, &tim, &r, 0);
|
||||
DestroyParser(&p);
|
||||
|
||||
if (r == E_CANT_TRIG) {
|
||||
|
||||
@@ -35,6 +35,10 @@ EXTERN FILE *ErrFp;
|
||||
|
||||
#define MINUTES_PER_DAY 1440
|
||||
|
||||
#define TODOS_AND_EVENTS 0
|
||||
#define ONLY_TODOS 1
|
||||
#define ONLY_EVENTS 2
|
||||
|
||||
#define DaysInYear(y) (((y) % 4) ? 365 : ((!((y) % 100) && ((y) % 400)) ? 365 : 366 ))
|
||||
#define IsLeapYear(y) (((y) % 4) ? 0 : ((!((y) % 100) && ((y) % 400)) ? 0 : 1 ))
|
||||
#define DaysInMonth(m, y) ((m) != 1 ? MonthDays[m] : 28 + IsLeapYear(y))
|
||||
@@ -52,6 +56,8 @@ EXTERN int FreshLine;
|
||||
EXTERN int WarnedAboutImplicit;
|
||||
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
|
||||
|
||||
EXTERN INIT( int JSONMode, 0);
|
||||
EXTERN INIT( int JSONLinesEmitted, 0);
|
||||
EXTERN INIT( int MaxLateMinutes, 0);
|
||||
EXTERN INIT( int NumTrustedUsers, 0);
|
||||
EXTERN INIT( char const *MsgCommand, NULL);
|
||||
@@ -61,6 +67,7 @@ EXTERN INIT( int DebugFlag, 0);
|
||||
EXTERN INIT( int DoCalendar, 0);
|
||||
EXTERN INIT( int DoSimpleCalendar, 0);
|
||||
EXTERN INIT( int DoSimpleCalDelta, 0);
|
||||
EXTERN INIT( int HideCompletedTodos, 0);
|
||||
EXTERN INIT( int DoPrefixLineNo, 0);
|
||||
EXTERN INIT( int MondayFirst, 0);
|
||||
EXTERN INIT( int AddBlankLines, 1);
|
||||
@@ -72,6 +79,7 @@ EXTERN INIT( int CalMonths, 0);
|
||||
EXTERN INIT( char const *CalType, "none");
|
||||
EXTERN INIT( int Hush, 0);
|
||||
EXTERN INIT( int NextMode, 0);
|
||||
EXTERN INIT( int TodoFilter, TODOS_AND_EVENTS);
|
||||
EXTERN INIT( int InfiniteDelta, 0);
|
||||
EXTERN INIT( int DefaultTDelta, 0);
|
||||
EXTERN INIT( int DefaultDelta, NO_DELTA);
|
||||
|
||||
22
src/ifelse.c
22
src/ifelse.c
@@ -24,6 +24,9 @@ static int if_pointer = 0;
|
||||
/* The base pointer for the current file */
|
||||
static int base_pointer = 0;
|
||||
|
||||
/* True if a "RETURN" statement was encountered in current file */
|
||||
static int return_encountered = 0;
|
||||
|
||||
/*
|
||||
* The current state of the IF...ELSE...ENDIF context is stored in
|
||||
* an array of "ifentry" objects, from the outermost to the
|
||||
@@ -103,6 +106,19 @@ encounter_else(void)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* DoReturn - handle the RETURN command */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int
|
||||
DoReturn(ParsePtr p)
|
||||
{
|
||||
int r = VerifyEoln(p);
|
||||
return_encountered = 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* encounter_endif - note that the most-recently-pushed IF */
|
||||
@@ -162,6 +178,10 @@ int
|
||||
should_ignore_line(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (return_encountered) {
|
||||
return 1;
|
||||
}
|
||||
for (i=base_pointer; i<if_pointer; i++) {
|
||||
if (( IfArray[i].if_true && !IfArray[i].before_else) ||
|
||||
(!IfArray[i].if_true && IfArray[i].before_else)) {
|
||||
@@ -193,11 +213,13 @@ in_constant_context(void)
|
||||
/* */
|
||||
/* pop_excess_ifs - pop excess IFs from the stack, printing */
|
||||
/* error messages as needed. */
|
||||
/* Also resets return_encountered */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
void
|
||||
pop_excess_ifs(char const *fname)
|
||||
{
|
||||
return_encountered = 0;
|
||||
if (if_pointer <= base_pointer) {
|
||||
return;
|
||||
}
|
||||
|
||||
46
src/init.c
46
src/init.c
@@ -798,6 +798,15 @@ void InitRemind(int argc, char const *argv[])
|
||||
|
||||
}
|
||||
|
||||
/* JSON mode turns off sorting */
|
||||
if (JSONMode) {
|
||||
SortByTime = SORT_NONE;
|
||||
SortByDate = SORT_NONE;
|
||||
SortByPrio = SORT_NONE;
|
||||
/* Make sure we don't blat errors to stdout! */
|
||||
ErrFp = stderr;
|
||||
}
|
||||
|
||||
/* Figure out the offset from UTC */
|
||||
if (CalculateUTC) {
|
||||
(void) CalcMinsFromUTC(DSEToday, MinutesPastMidnight(0),
|
||||
@@ -848,6 +857,16 @@ void Usage(void)
|
||||
fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n");
|
||||
fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n");
|
||||
fprintf(ErrFp, " -j[n] Run in 'purge' mode. [n = INCLUDE depth]\n");
|
||||
fprintf(ErrFp, "\nLong Options:\n");
|
||||
fprintf(ErrFp, " --version Print Remind version\n");
|
||||
fprintf(ErrFp, " --hide-completed-todos Don't show completed todos on calendar\n");
|
||||
fprintf(ErrFp, " --only-todos Only issue TODO reminders\n");
|
||||
fprintf(ErrFp, " --only-events Do not issue TODO reminders\n");
|
||||
fprintf(ErrFp, " --json Use JSON output instead of plain-text\n");
|
||||
fprintf(ErrFp, " --max-execution-time=n Limit execution time to n seconds\n");
|
||||
fprintf(ErrFp, " --print-config-cmd Print ./configure cmd used to build Remind\n");
|
||||
fprintf(ErrFp, " --print-errs Print all possible error messages\n");
|
||||
fprintf(ErrFp, " --print-tokens Print all possible Remind tokens\n");
|
||||
fprintf(ErrFp, "\nRemind home page: %s\n", PACKAGE_URL);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -1131,6 +1150,28 @@ ProcessLongOption(char const *arg)
|
||||
|
||||
return;
|
||||
}
|
||||
if (!strcmp(arg, "only-todos")) {
|
||||
if (TodoFilter == ONLY_EVENTS) {
|
||||
fprintf(ErrFp, "remind: Cannot combine --only-todos and --only-events\n");
|
||||
exit(1);
|
||||
}
|
||||
TodoFilter = ONLY_TODOS;
|
||||
return;
|
||||
}
|
||||
if (!strcmp(arg, "only-events")) {
|
||||
if (TodoFilter == ONLY_TODOS) {
|
||||
fprintf(ErrFp, "remind: Cannot combine --only-todos and --only-events\n");
|
||||
exit(1);
|
||||
}
|
||||
TodoFilter = ONLY_EVENTS;
|
||||
return;
|
||||
}
|
||||
if (!strcmp(arg, "json")) {
|
||||
JSONMode = 1;
|
||||
DontQueue = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(arg, "version")) {
|
||||
printf("%s\n", VERSION);
|
||||
exit(EXIT_SUCCESS);
|
||||
@@ -1149,6 +1190,11 @@ ProcessLongOption(char const *arg)
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (!strcmp(arg, "hide-completed-todos")) {
|
||||
HideCompletedTodos = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(arg, "print-tokens")) {
|
||||
print_remind_tokens();
|
||||
print_builtinfunc_tokens();
|
||||
|
||||
63
src/main.c
63
src/main.c
@@ -172,6 +172,9 @@ int main(int argc, char *argv[])
|
||||
ShouldCache = (Iterations > 1);
|
||||
|
||||
while (Iterations--) {
|
||||
if (JSONMode) {
|
||||
printf("[\n");
|
||||
}
|
||||
PerIterationInit();
|
||||
DoReminders();
|
||||
|
||||
@@ -194,7 +197,35 @@ int main(int argc, char *argv[])
|
||||
Eprint("%s", GetErr(E_PUSHF_NO_POP));
|
||||
}
|
||||
if (!Daemon && !NextMode && !NumTriggered && !NumQueued) {
|
||||
printf("%s\n", GetErr(E_NOREMINDERS));
|
||||
if (!JSONMode) {
|
||||
printf("%s\n", GetErr(E_NOREMINDERS));
|
||||
} else {
|
||||
if (!DidMsgReminder) {
|
||||
DynamicBuffer buf;
|
||||
DBufInit(&buf);
|
||||
/* Do a banner in JSON mode*/
|
||||
if (!DoSubstFromString(DBufValue(&Banner), &buf,
|
||||
DSEToday, NO_TIME) &&
|
||||
DBufLen(&buf)) {
|
||||
if (JSONLinesEmitted) {
|
||||
printf("},\n");
|
||||
}
|
||||
JSONLinesEmitted++;
|
||||
printf("{\"banner\":\"");
|
||||
remove_trailing_newlines(&buf);
|
||||
PrintJSONString(DBufValue(&buf));
|
||||
printf("\"");
|
||||
}
|
||||
DBufFree(&buf);
|
||||
}
|
||||
if (JSONLinesEmitted) {
|
||||
printf("},\n");
|
||||
}
|
||||
printf("{\"noreminders\":\"");
|
||||
PrintJSONString(GetErr(E_NOREMINDERS));
|
||||
printf("\"");
|
||||
JSONLinesEmitted++;
|
||||
}
|
||||
} else if (!Daemon && !NextMode && !NumTriggered) {
|
||||
printf(GetErr(M_QUEUED), NumQueued);
|
||||
printf("\n");
|
||||
@@ -204,6 +235,12 @@ int main(int argc, char *argv[])
|
||||
/* If there are sorted reminders, handle them */
|
||||
if (SortByDate) IssueSortedReminders();
|
||||
|
||||
if (JSONMode) {
|
||||
if (JSONLinesEmitted) {
|
||||
printf("}\n");
|
||||
}
|
||||
printf("]\n");
|
||||
}
|
||||
/* If there are any background reminders queued up, handle them */
|
||||
if (NumQueued || Daemon) {
|
||||
|
||||
@@ -252,6 +289,7 @@ PerIterationInit(void)
|
||||
DefaultColorG = -1;
|
||||
DefaultColorB = -1;
|
||||
NumTriggered = 0;
|
||||
JSONLinesEmitted = 0;
|
||||
ClearLastTriggers();
|
||||
ClearDedupeTable();
|
||||
}
|
||||
@@ -333,6 +371,7 @@ static void DoReminders(void)
|
||||
case T_Rem: r=DoRem(&p); purge_handled = 1; break;
|
||||
case T_ErrMsg: r=DoErrMsg(&p); break;
|
||||
case T_If: r=DoIf(&p); break;
|
||||
case T_Return: r=DoReturn(&p); break;
|
||||
case T_IfTrig: r=DoIfTrig(&p); break;
|
||||
case T_Else: r=DoElse(&p); break;
|
||||
case T_EndIf: r=DoEndif(&p); break;
|
||||
@@ -1251,7 +1290,7 @@ int DoIfTrig(ParsePtr p)
|
||||
} else {
|
||||
if ( (r=ParseRem(p, &trig, &tim)) ) return r;
|
||||
if (trig.typ != NO_TYPE) return E_PARSE_ERR;
|
||||
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
|
||||
dse = ComputeTrigger(get_scanfrom(&trig), &trig, &tim, &r, 1);
|
||||
if (r) {
|
||||
if (r != E_CANT_TRIG || !trig.maybe_uncomputable) {
|
||||
if (!Hush || r != E_RUN_DISABLED) {
|
||||
@@ -1537,6 +1576,15 @@ void DoExit(ParsePtr p)
|
||||
|
||||
if (PurgeMode) return;
|
||||
|
||||
if (JSONMode) {
|
||||
if (JSONLinesEmitted) {
|
||||
printf("}\n");
|
||||
}
|
||||
/* Close the reminder list */
|
||||
printf("]\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
r = EvaluateExpr(p, &v);
|
||||
if (r || v.type != INT_TYPE) exit(99);
|
||||
exit(v.v.val);
|
||||
@@ -2017,11 +2065,15 @@ ClearLastTriggers(void)
|
||||
LastTrigger.warn[0] = 0;
|
||||
LastTrigger.omitfunc[0] = 0;
|
||||
LastTrigger.passthru[0] = 0;
|
||||
LastTrigger.is_todo = 0;
|
||||
LastTrigger.complete_through = NO_DATE;
|
||||
LastTrigger.max_overdue = -1;
|
||||
FreeTrig(&LastTrigger);
|
||||
LastTimeTrig.ttime = NO_TIME;
|
||||
LastTimeTrig.delta = NO_DELTA;
|
||||
LastTimeTrig.rep = NO_REP;
|
||||
LastTimeTrig.duration = NO_TIME;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2098,7 +2150,12 @@ System(char const *cmd, int is_queued)
|
||||
}
|
||||
}
|
||||
/* This is the child process or original if we never forked */
|
||||
(void) system(cmd);
|
||||
if (JSONMode) {
|
||||
|
||||
(void) system_to_stderr(cmd);
|
||||
} else {
|
||||
(void) system(cmd);
|
||||
}
|
||||
if (do_exit) {
|
||||
/* In the child process, so exit! */
|
||||
exit(0);
|
||||
|
||||
@@ -512,6 +512,14 @@ DumpOmits(void)
|
||||
{
|
||||
int i;
|
||||
int y, m, d;
|
||||
|
||||
/* Do nothing in --json mode */
|
||||
if (JSONMode) {
|
||||
return;
|
||||
}
|
||||
if (PurgeMode) {
|
||||
return;
|
||||
}
|
||||
printf("Global Full OMITs (%d of maximum allowed %d):\n", NumFullOmits, MAX_FULL_OMITS);
|
||||
if (!NumFullOmits) {
|
||||
printf("\tNone.\n");
|
||||
|
||||
10
src/protos.h
10
src/protos.h
@@ -51,7 +51,7 @@ int DoRem (ParsePtr p);
|
||||
int DoFlush (ParsePtr p);
|
||||
void DoExit (ParsePtr p);
|
||||
int ParseRem (ParsePtr s, Trigger *trig, TimeTrig *tim);
|
||||
int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is_queued, DynamicBuffer *output);
|
||||
int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is_queued, DynamicBuffer *output, int *r, int *g, int *b);
|
||||
int ShouldTriggerReminder (Trigger const *t, TimeTrig const *tim, int dse, int *err);
|
||||
int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig const *tt, int dse, int mode);
|
||||
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int dse, int tim);
|
||||
@@ -103,8 +103,8 @@ int SystemDate (int *y, int *m, int *d);
|
||||
int DoIf (ParsePtr p);
|
||||
int DoElse (ParsePtr p);
|
||||
int DoEndif (ParsePtr p);
|
||||
int DoReturn (ParsePtr p);
|
||||
int DoIfTrig (ParsePtr p);
|
||||
int ShouldIgnoreLine (void);
|
||||
int VerifyEoln (ParsePtr p);
|
||||
int DoRun (ParsePtr p);
|
||||
int DoExpr (ParsePtr p);
|
||||
@@ -218,7 +218,7 @@ void clear_callstack(void);
|
||||
int print_callstack(FILE *fp);
|
||||
void pop_call(void);
|
||||
void FixSpecialType(Trigger *trig);
|
||||
void WriteJSONTrigger(Trigger const *t, int include_tags, int today);
|
||||
void WriteJSONTrigger(Trigger const *t, int include_tags);
|
||||
void WriteJSONTimeTrigger(TimeTrig const *tt);
|
||||
int GetOnceDate(void);
|
||||
#ifdef REM_USE_WCHAR
|
||||
@@ -290,3 +290,7 @@ void pop_excess_ifs(char const *fname);
|
||||
|
||||
void SetCurrentFilename(char const *fname);
|
||||
char const *GetCurrentFilename(void);
|
||||
int get_scanfrom(Trigger const *t);
|
||||
void remove_trailing_newlines(DynamicBuffer *buf);
|
||||
void set_cloexec(int fd);
|
||||
int system_to_stderr(char const *cmd);
|
||||
|
||||
@@ -436,7 +436,7 @@ void HandleQueuedReminders(void)
|
||||
if (DaemonJSON) {
|
||||
DynamicBuffer out;
|
||||
DBufInit(&out);
|
||||
(void) TriggerReminder(&p, &tcopy, &q->tt, DSEToday, 1, &out);
|
||||
(void) TriggerReminder(&p, &tcopy, &q->tt, DSEToday, 1, &out, NULL, NULL, NULL);
|
||||
if (q->typ != RUN_TYPE) {
|
||||
printf("\"body\":\"");
|
||||
chomp(&out);
|
||||
@@ -445,7 +445,7 @@ void HandleQueuedReminders(void)
|
||||
}
|
||||
DBufFree(&out);
|
||||
} else {
|
||||
(void) TriggerReminder(&p, &tcopy, &q->tt, DSEToday, 1, NULL);
|
||||
(void) TriggerReminder(&p, &tcopy, &q->tt, DSEToday, 1, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
if (IsServerMode() && !DaemonJSON && q->typ != RUN_TYPE) {
|
||||
printf("NOTE endreminder\n");
|
||||
@@ -704,7 +704,7 @@ json_queue(QueuedRem const *q)
|
||||
}
|
||||
done = 1;
|
||||
printf("{");
|
||||
WriteJSONTrigger(&(q->t), 1, DSEToday);
|
||||
WriteJSONTrigger(&(q->t), 1);
|
||||
WriteJSONTimeTrigger(&(q->tt));
|
||||
if (TestMode) {
|
||||
snprintf(idbuf, sizeof(idbuf), "42424242");
|
||||
|
||||
@@ -46,7 +46,8 @@ Token TokArray[] = {
|
||||
{ "banner", 3, T_Banner, 0 },
|
||||
{ "before", 6, T_Skip, BEFORE_SKIP },
|
||||
{ "cal", 3, T_RemType, CAL_TYPE },
|
||||
{ "clear-omit-context", 5, T_Clr, 0 },
|
||||
{ "clear-omit-context", 5, T_Clr, 0 },
|
||||
{ "complete-through", 16, T_CompleteThrough, 0 },
|
||||
{ "debug", 5, T_Debug, 0 },
|
||||
{ "december", 3, T_Month, 11 },
|
||||
{ "do", 2, T_IncludeR, 0 },
|
||||
@@ -79,6 +80,7 @@ Token TokArray[] = {
|
||||
{ "lastday", 7, T_BackAdj, -1 },
|
||||
{ "lastworkday", 11, T_BackAdj, 1 },
|
||||
{ "march", 3, T_Month, 2 },
|
||||
{ "max-overdue", 11, T_MaxOverdue, 0 },
|
||||
{ "may", 3, T_Month, 4 },
|
||||
{ "maybe-uncomputable", 5, T_MaybeUncomputable, 0},
|
||||
{ "monday", 3, T_WkDay, 0 },
|
||||
@@ -101,6 +103,7 @@ Token TokArray[] = {
|
||||
{ "push-omit-context", 4, T_Push, 0 },
|
||||
{ "push-vars", 9, T_PushVars, 0 },
|
||||
{ "rem", 3, T_Rem, 0 },
|
||||
{ "return", 6, T_Return, 0 },
|
||||
{ "run", 3, T_RemType, RUN_TYPE },
|
||||
{ "satisfy", 7, T_RemType, SAT_TYPE },
|
||||
{ "saturday", 3, T_WkDay, 5 },
|
||||
@@ -117,6 +120,7 @@ Token TokArray[] = {
|
||||
{ "third", 5, T_Ordinal, 2 },
|
||||
{ "through", 7, T_Through, 0 },
|
||||
{ "thursday", 3, T_WkDay, 3 },
|
||||
{ "todo", 4, T_Todo, 0 },
|
||||
{ "translate", 5, T_Translate, 0 },
|
||||
{ "tuesday", 3, T_WkDay, 1 },
|
||||
{ "unset", 5, T_UnSet, 0 },
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
@@ -63,6 +64,9 @@ GenerateTranslationTemplate(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (JSONMode) {
|
||||
return;
|
||||
}
|
||||
printf("# Translation table template\n\n");
|
||||
|
||||
printf("TRANSLATE \"LANGID\" ");
|
||||
@@ -233,6 +237,10 @@ DumpTranslationTable(FILE *fp, int json)
|
||||
XlateItem *item;
|
||||
int done = 0;
|
||||
char const *t;
|
||||
|
||||
if (fileno(fp) == STDOUT_FILENO && JSONMode) {
|
||||
return;
|
||||
}
|
||||
if (!json) {
|
||||
fprintf(fp, "# Translation table\n");
|
||||
/* Always to LANGID first */
|
||||
|
||||
@@ -311,14 +311,26 @@ static int DSEYear(int dse)
|
||||
static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart)
|
||||
{
|
||||
int simple, mod, omit;
|
||||
int calmode = (DoSimpleCalendar || DoCalendar) ? 1 : 0;
|
||||
if (HideCompletedTodos) calmode = 0;
|
||||
|
||||
/* First: Have we passed the UNTIL date? */
|
||||
if (trig->until != NO_UNTIL &&
|
||||
if (!trig->is_todo &&
|
||||
trig->until != NO_UNTIL &&
|
||||
trig->until < start) {
|
||||
trig->expired = 1;
|
||||
return -1; /* expired */
|
||||
}
|
||||
|
||||
/* If it's a TODO and complete_through is past today, we're good */
|
||||
if (!calmode &&
|
||||
trig->is_todo &&
|
||||
trig->complete_through != NO_DATE &&
|
||||
trig->complete_through >= start) {
|
||||
trig->expired = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Next: If it's an "AFTER"-type skip, back up
|
||||
until we're at the start of a block of holidays */
|
||||
if (trig->skip == AFTER_SKIP) {
|
||||
|
||||
12
src/types.h
12
src/types.h
@@ -136,6 +136,8 @@ typedef struct {
|
||||
int from;
|
||||
int adj_for_last; /* Adjust month/year for use of LAST */
|
||||
int need_wkday; /* Set if we *need* a weekday */
|
||||
int is_todo; /* This is a TODO reminder */
|
||||
int complete_through; /* DSE of complete-through date */
|
||||
int priority;
|
||||
int duration_days; /* Duration converted to days to search */
|
||||
int eventstart; /* Original event start (datetime) */
|
||||
@@ -143,6 +145,7 @@ typedef struct {
|
||||
int maybe_uncomputable; /* Suppress "can't compute trigger" warnings */
|
||||
int addomit; /* Add trigger date to global OMITs */
|
||||
int noqueue; /* Don't queue even if timed */
|
||||
int max_overdue; /* Stop warning if TODO is too far overdue */
|
||||
char sched[VAR_NAME_LEN+1]; /* Scheduling function */
|
||||
char warn[VAR_NAME_LEN+1]; /* Warning function */
|
||||
char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */
|
||||
@@ -194,6 +197,7 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
|
||||
#define AFTER_SKIP 3
|
||||
|
||||
#define NO_TIME INT_MAX
|
||||
#define NO_SCANFROM INT_MIN
|
||||
|
||||
#define NO_PRIORITY 5000 /* Default priority is midway between 0 and 9999 */
|
||||
|
||||
@@ -226,16 +230,16 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
|
||||
/* Enumeration of the tokens */
|
||||
enum TokTypes
|
||||
{ T_Illegal,
|
||||
T_AddOmit, T_At, T_Back, T_BackAdj, T_Banner, T_Clr, T_Comment,
|
||||
T_AddOmit, T_At, T_Back, T_BackAdj, T_Banner, T_Clr, T_Comment, T_CompleteThrough,
|
||||
T_Date, T_DateTime, T_Day, T_Debug, T_Delta, T_Dumpvars, T_Duration,
|
||||
T_Else, T_Empty, T_EndIf, T_ErrMsg, T_Exit, T_Expr, T_Flush,
|
||||
T_Frename, T_Fset, T_Funset, T_If, T_IfTrig, T_In, T_Include,
|
||||
T_IncludeCmd, T_IncludeR, T_IncludeSys, T_Info, T_LastBack,
|
||||
T_LongTime, T_MaybeUncomputable, T_Month, T_NoQueue, T_Number,
|
||||
T_LongTime, T_MaxOverdue, T_MaybeUncomputable, T_Month, T_NoQueue, T_Number,
|
||||
T_Omit, T_OmitFunc, T_Once, T_Ordinal, T_Pop, T_PopFuncs, T_PopVars,
|
||||
T_Preserve, T_Priority, T_Push, T_PushFuncs, T_PushVars, T_Rem,
|
||||
T_RemType, T_Rep, T_Scanfrom, T_Sched, T_Set, T_Skip, T_Tag,
|
||||
T_Through, T_Time, T_Translate, T_UnSet, T_Until, T_Warn, T_WkDay,
|
||||
T_RemType, T_Rep, T_Return, T_Scanfrom, T_Sched, T_Set, T_Skip, T_Tag,
|
||||
T_Through, T_Time, T_Todo, T_Translate, T_UnSet, T_Until, T_Warn, T_WkDay,
|
||||
T_Year
|
||||
};
|
||||
|
||||
|
||||
38
src/utils.c
38
src/utils.c
@@ -17,6 +17,7 @@ static char const DontEscapeMe[] =
|
||||
#include "err.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
@@ -30,6 +31,43 @@ static char const DontEscapeMe[] =
|
||||
#include "globals.h"
|
||||
#include "protos.h"
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* system_to_stderr */
|
||||
/* */
|
||||
/* Run system(...) but with stdout redirected to stderr */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int system_to_stderr(char const *cmd)
|
||||
{
|
||||
int stdout_dup = dup(STDOUT_FILENO);
|
||||
int r;
|
||||
|
||||
if (stdout_dup < 0) {
|
||||
perror("dup");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Duplicate STDERR onto STDOUT */
|
||||
if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) {
|
||||
(void) close(stdout_dup);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set close-on-exec flag on stdout_dup */
|
||||
set_cloexec(stdout_dup);
|
||||
|
||||
r = system(cmd);
|
||||
|
||||
/* Restore original stdout */
|
||||
/* If this dup2 fails... there's not a whole lot we can do. */
|
||||
(void) dup2(stdout_dup, STDOUT_FILENO);
|
||||
if (STDOUT_FILENO != stdout_dup) {
|
||||
(void) close(stdout_dup);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* StrnCpy */
|
||||
|
||||
@@ -761,6 +761,7 @@ int DoDump(ParsePtr p)
|
||||
int dump_constness = 0;
|
||||
|
||||
if (PurgeMode) return OK;
|
||||
if (JSONMode) return OK;
|
||||
|
||||
DBufInit(&buf);
|
||||
r = ParseToken(p, &buf);
|
||||
@@ -992,6 +993,7 @@ static SysVar SysVarArr[] = {
|
||||
{"FormWidth", 1, INT_TYPE, &FormWidth, 20, 500 },
|
||||
{"Friday", 1, TRANS_TYPE, "Friday", 0, 0 },
|
||||
{"Fromnow", 1, TRANS_TYPE, "from now", 0, 0 },
|
||||
{"HideCompletedTodos", 0, INT_TYPE, &HideCompletedTodos, 0, 0 },
|
||||
{"Hour", 1, TRANS_TYPE, "hour", 0, 0 },
|
||||
{"Hplu", 1, STR_TYPE, &DynamicHplu, 0, 0 },
|
||||
{"HushMode", 0, INT_TYPE, &Hush, 0, 0 },
|
||||
@@ -1001,6 +1003,7 @@ static SysVar SysVarArr[] = {
|
||||
{"IntMin", 0, INT_TYPE, &IntMin, 0, 0 },
|
||||
{"Is", 1, TRANS_TYPE, "is", 0, 0 },
|
||||
{"January", 1, TRANS_TYPE, "January", 0, 0 },
|
||||
{"JSONMode", 0, INT_TYPE, &JSONMode, 0, 0 },
|
||||
{"July", 1, TRANS_TYPE, "July", 0, 0 },
|
||||
{"June", 1, TRANS_TYPE, "June", 0, 0 },
|
||||
{"LatDeg", 1, SPECIAL_TYPE, latdeg_func, 0, 0 },
|
||||
@@ -1058,6 +1061,7 @@ static SysVar SysVarArr[] = {
|
||||
{"TimetIs64bit", 0, SPECIAL_TYPE, timet_is_64_func, 0, 0 },
|
||||
{"Tm", 0, SPECIAL_TYPE, trig_mon_func, 0, 0 },
|
||||
{"Today", 1, TRANS_TYPE, "today", 0, 0 },
|
||||
{"TodoFilter", 0, INT_TYPE, &TodoFilter, 0, 0 },
|
||||
{"Tomorrow", 1, TRANS_TYPE, "tomorrow", 0, 0 },
|
||||
{"Tt", 0, SPECIAL_TYPE, trig_time_func, 0, 0 },
|
||||
{"Tu", 0, SPECIAL_TYPE, trig_until_func, 0, 0 },
|
||||
|
||||
5
tests/json-redirect.rem
Normal file
5
tests/json-redirect.rem
Normal file
@@ -0,0 +1,5 @@
|
||||
BANNER %
|
||||
SET $AddBlankLines 0
|
||||
REM MSG Hello
|
||||
REM RUN echo This is executed by the shell.
|
||||
REM MSG Goodbye
|
||||
5
tests/ret1.rem
Normal file
5
tests/ret1.rem
Normal file
@@ -0,0 +1,5 @@
|
||||
DO ret2.rem
|
||||
IF ($Ud % 5) != 0
|
||||
RETURN
|
||||
ENDIF
|
||||
REM MSG On days divisible by 5
|
||||
7
tests/ret2.rem
Normal file
7
tests/ret2.rem
Normal file
@@ -0,0 +1,7 @@
|
||||
REM MSG Always
|
||||
IF $Ud % 2
|
||||
REM MSG On odd days
|
||||
RETURN
|
||||
REM MSG Won't appear
|
||||
ENDIF
|
||||
REM MSG On even days
|
||||
@@ -704,7 +704,7 @@ EOF
|
||||
|
||||
# Test diagnostics when using a timed substitution without an AT clause
|
||||
../src/remind - 1 Feb 2024 1:00 <<EOF >> ../tests/test.out 2>&1
|
||||
REM MSG %0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %! hahaha
|
||||
REM MSG %0 %1 %2 %3 %4 %5 %6 %7 %8 %9 hahaha
|
||||
EOF
|
||||
|
||||
# Test translate table dumping
|
||||
@@ -716,6 +716,11 @@ EOF
|
||||
../src/remind -ppp - 1 Feb 2024 <<EOF >> ../tests/test.out 2>&1
|
||||
TRANSLATE "\x03" "BREAK"
|
||||
EOF
|
||||
|
||||
# SCANFROM should be preserved even if it is today
|
||||
../src/remind -ppp - 1 Feb 2024 <<EOF >> ../tests/test.out 2>&1
|
||||
REM SCANFROM 2024-02-01 MSG Preserve SCANFROM
|
||||
EOF
|
||||
# Languages
|
||||
for i in ../include/lang/??.rem ; do
|
||||
../src/remind -r -q "-ii=\"$i\"" ../tests/tstlang.rem 1 Feb 2024 13:34 >> ../tests/test.out 2>&1
|
||||
@@ -745,9 +750,44 @@ set y 1000
|
||||
unset y
|
||||
EOF
|
||||
|
||||
# Test RETURN statement
|
||||
../src/remind ../tests/ret1.rem 4 June 2000 >> ../tests/test.out 2>&1
|
||||
../src/remind ../tests/ret1.rem 5 June 2000 >> ../tests/test.out 2>&1
|
||||
../src/remind ../tests/ret1.rem 7 June 2000 >> ../tests/test.out 2>&1
|
||||
../src/remind -s ../tests/ret1.rem 1 June 2000 >> ../tests/test.out 2>&1
|
||||
|
||||
# Make sure all the include files are ok
|
||||
find ../include -type f -name '*.rem' | while read x; do ../src/remind -du -n $x 1 Jan 2024 2>>../tests/test.out 1>/dev/null; done
|
||||
|
||||
# Test todos
|
||||
echo "" >> ../tests/test.out 2>&1
|
||||
echo "Testing TODOS in agenda mode" >> ../tests/test.out 2>&1
|
||||
../src/remind ../tests/todos.rem 2025-08-13 >> ../tests/test.out 2>&1
|
||||
echo "" >> ../tests/test.out 2>&1
|
||||
echo "Testing TODOS in calendar mode" >> ../tests/test.out 2>&1
|
||||
../src/remind -s ../tests/todos.rem 2025-08-13 >> ../tests/test.out 2>&1
|
||||
echo "" >> ../tests/test.out 2>&1
|
||||
echo "Testing TODOS in calendar mode with completed todos hidden" >> ../tests/test.out 2>&1
|
||||
../src/remind -s --hide-completed-todos ../tests/todos.rem 2025-08-13 >> ../tests/test.out 2>&1
|
||||
echo "Testing TODOS and JSON mode" >> ../tests/test.out 2>&1
|
||||
../src/remind --json ../tests/todos.rem 2025-08-13 >> ../tests/test.out 2>&1
|
||||
|
||||
echo "Testing proper redirection of RUN stdout in JSON mode... here's stdout" >> ../tests/test.out 2>&1
|
||||
../src/remind --json ../tests/json-redirect.rem 1 Jan 2025 >> ../tests/test.out 2>/dev/null
|
||||
|
||||
echo "... and here is stderr" >> ../tests/test.out 2>&1
|
||||
../src/remind --json ../tests/json-redirect.rem 1 Jan 2025 > /dev/null 2>> ../tests/test.out
|
||||
|
||||
# Test %: substitution sequence in all the languages
|
||||
for i in ../include/lang/??.rem ; do
|
||||
../src/remind "-ii=\"$i\"" -p - 2025-08-13 <<'EOF' 2>&1 | grep 2025/ >> ../tests/test.out
|
||||
DO [i]
|
||||
REM TODO 2025-08-13 MSG %(LANGID) Task1%:
|
||||
REM TODO 2025-08-13 COMPLETE-THROUGH 2025-08-12 MSG %(LANGID) Task2%:
|
||||
REM TODO 2025-08-13 COMPLETE-THROUGH 2025-08-13 MSG %(LANGID) Task3%:
|
||||
EOF
|
||||
done
|
||||
|
||||
cmp -s ../tests/test.out ../tests/test.cmp
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "Remind: Acceptance test PASSED"
|
||||
|
||||
3366
tests/test.cmp
3366
tests/test.cmp
File diff suppressed because it is too large
Load Diff
@@ -1707,6 +1707,15 @@ set a c()
|
||||
|
||||
DEBUG -xe
|
||||
|
||||
fset subst_colon(a, b, c) "subst_colon"
|
||||
fset subst_bang(a, b, c) "subst_bang"
|
||||
fset subst_question(a, b, c) "subst_question"
|
||||
fset subst_at(a, b, c) "subst_at"
|
||||
fset subst_hash(a, b, c) "subst_hash"
|
||||
|
||||
REM MSG Overridden: %: %! %? %@ %#
|
||||
|
||||
|
||||
# Don't want Remind to queue reminders
|
||||
EXIT
|
||||
|
||||
|
||||
32
tests/todos.rem
Normal file
32
tests/todos.rem
Normal file
@@ -0,0 +1,32 @@
|
||||
BANNER %
|
||||
SET $AddBlankLines 0
|
||||
|
||||
REM TODO 1 Aug 2025 MSG %"First%" %l
|
||||
REM TODO 1 Aug COMPLETE-THROUGH 2022-07-31 MSG %"Second%" %l
|
||||
REM TODO 1 Aug COMPLETE-THROUGH 2022-08-01 MSG %"Third%" %l
|
||||
REM TODO 20 Aug 2025 +7 MSG %"Fourth%" %l
|
||||
REM TODO 13 Aug 2025 +7 MSG %"Fifth%" %l
|
||||
REM TODO 6 Aug 2025 +7 MSG %"Sixth%" %l
|
||||
REM TODO COMPLETE-THROUGH 2025-08-06 6 Aug 2025 +7 MSG %"Seventh%" %l
|
||||
REM TODO Wed +7 COMPLETE-THROUGH 2025-08-13 MSG %"Eighth%" %l
|
||||
REM TODO Wed +7 COMPLETE-THROUGH 2025-08-12 MSG %"Ninth%" %l
|
||||
|
||||
# Test MAX-OVERDUE
|
||||
REM TODO 2025-08-13 MAX-OVERDUE 3 MSG %"Yup%" %l
|
||||
REM TODO 2025-08-12 MAX-OVERDUE 3 MSG %"Yup2%" %l
|
||||
REM TODO 2025-08-11 MAX-OVERDUE 3 MSG %"Yup3%" %l
|
||||
REM TODO 2025-08-10 MAX-OVERDUE 3 MSG %"Yup4%" %l
|
||||
REM TODO 2025-08-9 MAX-OVERDUE 3 MSG %"Nope%" %l
|
||||
|
||||
IF !$JSONMode
|
||||
REM TODO 2025-09-09 COMPLETE-THROUGH 2024-12-31 MAX-OVERDUE 3 MSG %"Nope%" %l
|
||||
debug +x
|
||||
set a trigistodo()
|
||||
set a trigcompletethrough()
|
||||
set a trigmaxoverdue()
|
||||
REM 2025-09-09 MSG blork
|
||||
set a trigistodo()
|
||||
set a trigcompletethrough()
|
||||
set a trigmaxoverdue()
|
||||
debug -x
|
||||
ENDIF
|
||||
@@ -29,6 +29,7 @@ if !$RunOff || !$DontQueue || $DontTrigAts
|
||||
exit
|
||||
endif
|
||||
|
||||
set $AddBlankLines 0
|
||||
# Include a language file, if that's given as "-ii=/path"
|
||||
|
||||
if defined("i")
|
||||
@@ -37,7 +38,7 @@ endif
|
||||
|
||||
REM MSG Language: %(LANGID)
|
||||
# Set up a few useful definitions
|
||||
fset show(x) "%%" + x + " yields: " + char(34) + "%" + x + char(34) + "% and %%*" + x + " yields: " + char(34) + "%*" + x + char(34) + "%"
|
||||
fset show(x) iif(x == "!" || x == "?", "%%" + x + " yields: " + char(34) + "%" + x + char(34), "%%" + x + " yields: " + char(34) + "%" + x + char(34) + "% and %%*" + x + " yields: " + char(34) + "%*" + x + char(34) + "%")
|
||||
set a trigger(today()+2) + " ++2"
|
||||
set l language()
|
||||
set tt now()+134
|
||||
@@ -298,6 +299,14 @@ REM [a] MSG [show("x")]
|
||||
REM [a] MSG [show("y")]
|
||||
REM [a] MSG [show("z")]
|
||||
|
||||
MSG %_%_The %%b substitutions for 1, 2 and 3 days ago
|
||||
SET a today()-1
|
||||
REM TODO [a] MSG [show("b")]
|
||||
SET a today()-2
|
||||
REM TODO [a] MSG [show("b")]
|
||||
SET a today()-3
|
||||
REM TODO [a] MSG [show("b")]
|
||||
|
||||
MSG %_Time substitutions for [now()] where now() = [now()]
|
||||
REM AT [now()] MSG [show("1")]
|
||||
REM AT [now()] MSG [show("2")]
|
||||
@@ -310,6 +319,7 @@ REM AT [now()] MSG [show("8")]
|
||||
REM AT [now()] MSG [show("9")]
|
||||
REM AT [now()] MSG [show("0")]
|
||||
REM AT [now()] MSG [show("!")]
|
||||
REM AT [now()] MSG [show("?")]
|
||||
REM AT [now()] MSG [show("@")]
|
||||
REM AT [now()] MSG [show("#")]
|
||||
MSG %_Time substitutions for [now()+134] where now() = [now()]
|
||||
@@ -324,6 +334,7 @@ REM AT [now()+134] MSG [show("8")]
|
||||
REM AT [now()+134] MSG [show("9")]
|
||||
REM AT [now()+134] MSG [show("0")]
|
||||
REM AT [now()+134] MSG [show("!")]
|
||||
REM AT [now()+134] MSG [show("?")]
|
||||
REM AT [now()+134] MSG [show("@")]
|
||||
REM AT [now()+134] MSG [show("#")]
|
||||
MSG %_Time substitutions for [now()-134] where now() = [now()]
|
||||
@@ -338,6 +349,7 @@ REM AT [now()-134] MSG [show("8")]
|
||||
REM AT [now()-134] MSG [show("9")]
|
||||
REM AT [now()-134] MSG [show("0")]
|
||||
REM AT [now()-134] MSG [show("!")]
|
||||
REM AT [now()-134] MSG [show("?")]
|
||||
REM AT [now()-134] MSG [show("@")]
|
||||
REM AT [now()-134] MSG [show("#")]
|
||||
MSG %_Time substitutions for [now()+60] where now() = [now()]
|
||||
@@ -352,6 +364,7 @@ REM AT [now()+60] MSG [show("8")]
|
||||
REM AT [now()+60] MSG [show("9")]
|
||||
REM AT [now()+60] MSG [show("0")]
|
||||
REM AT [now()+60] MSG [show("!")]
|
||||
REM AT [now()+60] MSG [show("?")]
|
||||
REM AT [now()+60] MSG [show("@")]
|
||||
REM AT [now()+60] MSG [show("#")]
|
||||
MSG %_Time substitutions for [now()-60] where now() = [now()]
|
||||
@@ -366,6 +379,7 @@ REM AT [now()-60] MSG [show("8")]
|
||||
REM AT [now()-60] MSG [show("9")]
|
||||
REM AT [now()-60] MSG [show("0")]
|
||||
REM AT [now()-60] MSG [show("!")]
|
||||
REM AT [now()-60] MSG [show("?")]
|
||||
REM AT [now()-60] MSG [show("@")]
|
||||
REM AT [now()-60] MSG [show("#")]
|
||||
MSG %_Time substitutions for [now()+120] where now() = [now()]
|
||||
@@ -380,6 +394,7 @@ REM AT [now()+120] MSG [show("8")]
|
||||
REM AT [now()+120] MSG [show("9")]
|
||||
REM AT [now()+120] MSG [show("0")]
|
||||
REM AT [now()+120] MSG [show("!")]
|
||||
REM AT [now()+120] MSG [show("?")]
|
||||
REM AT [now()+120] MSG [show("@")]
|
||||
REM AT [now()+120] MSG [show("#")]
|
||||
MSG %_Time substitutions for [now()-120] where now() = [now()]
|
||||
@@ -394,6 +409,7 @@ REM AT [now()-120] MSG [show("8")]
|
||||
REM AT [now()-120] MSG [show("9")]
|
||||
REM AT [now()-120] MSG [show("0")]
|
||||
REM AT [now()-120] MSG [show("!")]
|
||||
REM AT [now()-120] MSG [show("?")]
|
||||
REM AT [now()-120] MSG [show("@")]
|
||||
REM AT [now()-120] MSG [show("#")]
|
||||
MSG %_Time substitutions for [now()+1] where now() = [now()]
|
||||
@@ -408,6 +424,7 @@ REM AT [now()+1] MSG [show("8")]
|
||||
REM AT [now()+1] MSG [show("9")]
|
||||
REM AT [now()+1] MSG [show("0")]
|
||||
REM AT [now()+1] MSG [show("!")]
|
||||
REM AT [now()+1] MSG [show("?")]
|
||||
REM AT [now()+1] MSG [show("@")]
|
||||
REM AT [now()+1] MSG [show("#")]
|
||||
MSG %_Time substitutions for [now()-1] where now() = [now()]
|
||||
@@ -422,6 +439,7 @@ REM AT [now()-1] MSG [show("8")]
|
||||
REM AT [now()-1] MSG [show("9")]
|
||||
REM AT [now()-1] MSG [show("0")]
|
||||
REM AT [now()-1] MSG [show("!")]
|
||||
REM AT [now()-1] MSG [show("?")]
|
||||
REM AT [now()-1] MSG [show("@")]
|
||||
REM AT [now()-1] MSG [show("#")]
|
||||
MSG %_Time substitutions for [now()+2] where now() = [now()]
|
||||
@@ -436,6 +454,7 @@ REM AT [now()+2] MSG [show("8")]
|
||||
REM AT [now()+2] MSG [show("9")]
|
||||
REM AT [now()+2] MSG [show("0")]
|
||||
REM AT [now()+2] MSG [show("!")]
|
||||
REM AT [now()+2] MSG [show("?")]
|
||||
REM AT [now()+2] MSG [show("@")]
|
||||
REM AT [now()+2] MSG [show("#")]
|
||||
MSG %_Time substitutions for [now()-2] where now() = [now()]
|
||||
@@ -450,6 +469,7 @@ REM AT [now()-2] MSG [show("8")]
|
||||
REM AT [now()-2] MSG [show("9")]
|
||||
REM AT [now()-2] MSG [show("0")]
|
||||
REM AT [now()-2] MSG [show("!")]
|
||||
REM AT [now()-2] MSG [show("?")]
|
||||
REM AT [now()-2] MSG [show("@")]
|
||||
REM AT [now()-2] MSG [show("#")]
|
||||
MSG %_Time substitutions for [0:00] where now() = [now()]
|
||||
@@ -464,6 +484,7 @@ REM AT [0:00] MSG [show("8")]
|
||||
REM AT [0:00] MSG [show("9")]
|
||||
REM AT [0:00] MSG [show("0")]
|
||||
REM AT [0:00] MSG [show("!")]
|
||||
REM AT [0:00] MSG [show("?")]
|
||||
REM AT [0:00] MSG [show("@")]
|
||||
REM AT [0:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [1:00] where now() = [now()]
|
||||
@@ -478,6 +499,7 @@ REM AT [1:00] MSG [show("8")]
|
||||
REM AT [1:00] MSG [show("9")]
|
||||
REM AT [1:00] MSG [show("0")]
|
||||
REM AT [1:00] MSG [show("!")]
|
||||
REM AT [1:00] MSG [show("?")]
|
||||
REM AT [1:00] MSG [show("@")]
|
||||
REM AT [1:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [2:00] where now() = [now()]
|
||||
@@ -492,6 +514,7 @@ REM AT [2:00] MSG [show("8")]
|
||||
REM AT [2:00] MSG [show("9")]
|
||||
REM AT [2:00] MSG [show("0")]
|
||||
REM AT [2:00] MSG [show("!")]
|
||||
REM AT [2:00] MSG [show("?")]
|
||||
REM AT [2:00] MSG [show("@")]
|
||||
REM AT [2:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [3:00] where now() = [now()]
|
||||
@@ -506,6 +529,7 @@ REM AT [3:00] MSG [show("8")]
|
||||
REM AT [3:00] MSG [show("9")]
|
||||
REM AT [3:00] MSG [show("0")]
|
||||
REM AT [3:00] MSG [show("!")]
|
||||
REM AT [3:00] MSG [show("?")]
|
||||
REM AT [3:00] MSG [show("@")]
|
||||
REM AT [3:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [4:00] where now() = [now()]
|
||||
@@ -520,6 +544,7 @@ REM AT [4:00] MSG [show("8")]
|
||||
REM AT [4:00] MSG [show("9")]
|
||||
REM AT [4:00] MSG [show("0")]
|
||||
REM AT [4:00] MSG [show("!")]
|
||||
REM AT [4:00] MSG [show("?")]
|
||||
REM AT [4:00] MSG [show("@")]
|
||||
REM AT [4:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [5:00] where now() = [now()]
|
||||
@@ -534,6 +559,7 @@ REM AT [5:00] MSG [show("8")]
|
||||
REM AT [5:00] MSG [show("9")]
|
||||
REM AT [5:00] MSG [show("0")]
|
||||
REM AT [5:00] MSG [show("!")]
|
||||
REM AT [5:00] MSG [show("?")]
|
||||
REM AT [5:00] MSG [show("@")]
|
||||
REM AT [5:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [6:00] where now() = [now()]
|
||||
@@ -548,6 +574,7 @@ REM AT [6:00] MSG [show("8")]
|
||||
REM AT [6:00] MSG [show("9")]
|
||||
REM AT [6:00] MSG [show("0")]
|
||||
REM AT [6:00] MSG [show("!")]
|
||||
REM AT [6:00] MSG [show("?")]
|
||||
REM AT [6:00] MSG [show("@")]
|
||||
REM AT [6:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [7:00] where now() = [now()]
|
||||
@@ -562,6 +589,7 @@ REM AT [7:00] MSG [show("8")]
|
||||
REM AT [7:00] MSG [show("9")]
|
||||
REM AT [7:00] MSG [show("0")]
|
||||
REM AT [7:00] MSG [show("!")]
|
||||
REM AT [7:00] MSG [show("?")]
|
||||
REM AT [7:00] MSG [show("@")]
|
||||
REM AT [7:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [8:00] where now() = [now()]
|
||||
@@ -576,6 +604,7 @@ REM AT [8:00] MSG [show("8")]
|
||||
REM AT [8:00] MSG [show("9")]
|
||||
REM AT [8:00] MSG [show("0")]
|
||||
REM AT [8:00] MSG [show("!")]
|
||||
REM AT [8:00] MSG [show("?")]
|
||||
REM AT [8:00] MSG [show("@")]
|
||||
REM AT [8:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [9:00] where now() = [now()]
|
||||
@@ -590,6 +619,7 @@ REM AT [9:00] MSG [show("8")]
|
||||
REM AT [9:00] MSG [show("9")]
|
||||
REM AT [9:00] MSG [show("0")]
|
||||
REM AT [9:00] MSG [show("!")]
|
||||
REM AT [9:00] MSG [show("?")]
|
||||
REM AT [9:00] MSG [show("@")]
|
||||
REM AT [9:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [10:00] where now() = [now()]
|
||||
@@ -604,6 +634,7 @@ REM AT [10:00] MSG [show("8")]
|
||||
REM AT [10:00] MSG [show("9")]
|
||||
REM AT [10:00] MSG [show("0")]
|
||||
REM AT [10:00] MSG [show("!")]
|
||||
REM AT [10:00] MSG [show("?")]
|
||||
REM AT [10:00] MSG [show("@")]
|
||||
REM AT [10:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [11:00] where now() = [now()]
|
||||
@@ -618,6 +649,7 @@ REM AT [11:00] MSG [show("8")]
|
||||
REM AT [11:00] MSG [show("9")]
|
||||
REM AT [11:00] MSG [show("0")]
|
||||
REM AT [11:00] MSG [show("!")]
|
||||
REM AT [11:00] MSG [show("?")]
|
||||
REM AT [11:00] MSG [show("@")]
|
||||
REM AT [11:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [11:59] where now() = [now()]
|
||||
@@ -632,6 +664,7 @@ REM AT [11:59] MSG [show("8")]
|
||||
REM AT [11:59] MSG [show("9")]
|
||||
REM AT [11:59] MSG [show("0")]
|
||||
REM AT [11:59] MSG [show("!")]
|
||||
REM AT [11:59] MSG [show("?")]
|
||||
REM AT [11:59] MSG [show("@")]
|
||||
REM AT [11:59] MSG [show("#")]
|
||||
MSG %_Time substitutions for [12:00] where now() = [now()]
|
||||
@@ -646,6 +679,7 @@ REM AT [12:00] MSG [show("8")]
|
||||
REM AT [12:00] MSG [show("9")]
|
||||
REM AT [12:00] MSG [show("0")]
|
||||
REM AT [12:00] MSG [show("!")]
|
||||
REM AT [12:00] MSG [show("?")]
|
||||
REM AT [12:00] MSG [show("@")]
|
||||
REM AT [12:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [12:01] where now() = [now()]
|
||||
@@ -660,6 +694,7 @@ REM AT [12:01] MSG [show("8")]
|
||||
REM AT [12:01] MSG [show("9")]
|
||||
REM AT [12:01] MSG [show("0")]
|
||||
REM AT [12:01] MSG [show("!")]
|
||||
REM AT [12:01] MSG [show("?")]
|
||||
REM AT [12:01] MSG [show("@")]
|
||||
REM AT [12:01] MSG [show("#")]
|
||||
MSG %_Time substitutions for [13:00] where now() = [now()]
|
||||
@@ -674,6 +709,7 @@ REM AT [13:00] MSG [show("8")]
|
||||
REM AT [13:00] MSG [show("9")]
|
||||
REM AT [13:00] MSG [show("0")]
|
||||
REM AT [13:00] MSG [show("!")]
|
||||
REM AT [13:00] MSG [show("?")]
|
||||
REM AT [13:00] MSG [show("@")]
|
||||
REM AT [13:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [14:00] where now() = [now()]
|
||||
@@ -688,6 +724,7 @@ REM AT [14:00] MSG [show("8")]
|
||||
REM AT [14:00] MSG [show("9")]
|
||||
REM AT [14:00] MSG [show("0")]
|
||||
REM AT [14:00] MSG [show("!")]
|
||||
REM AT [14:00] MSG [show("?")]
|
||||
REM AT [14:00] MSG [show("@")]
|
||||
REM AT [14:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [15:00] where now() = [now()]
|
||||
@@ -702,6 +739,7 @@ REM AT [15:00] MSG [show("8")]
|
||||
REM AT [15:00] MSG [show("9")]
|
||||
REM AT [15:00] MSG [show("0")]
|
||||
REM AT [15:00] MSG [show("!")]
|
||||
REM AT [15:00] MSG [show("?")]
|
||||
REM AT [15:00] MSG [show("@")]
|
||||
REM AT [15:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [16:00] where now() = [now()]
|
||||
@@ -716,6 +754,7 @@ REM AT [16:00] MSG [show("8")]
|
||||
REM AT [16:00] MSG [show("9")]
|
||||
REM AT [16:00] MSG [show("0")]
|
||||
REM AT [16:00] MSG [show("!")]
|
||||
REM AT [16:00] MSG [show("?")]
|
||||
REM AT [16:00] MSG [show("@")]
|
||||
REM AT [16:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [17:00] where now() = [now()]
|
||||
@@ -730,6 +769,7 @@ REM AT [17:00] MSG [show("8")]
|
||||
REM AT [17:00] MSG [show("9")]
|
||||
REM AT [17:00] MSG [show("0")]
|
||||
REM AT [17:00] MSG [show("!")]
|
||||
REM AT [17:00] MSG [show("?")]
|
||||
REM AT [17:00] MSG [show("@")]
|
||||
REM AT [17:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [18:00] where now() = [now()]
|
||||
@@ -744,6 +784,7 @@ REM AT [18:00] MSG [show("8")]
|
||||
REM AT [18:00] MSG [show("9")]
|
||||
REM AT [18:00] MSG [show("0")]
|
||||
REM AT [18:00] MSG [show("!")]
|
||||
REM AT [18:00] MSG [show("?")]
|
||||
REM AT [18:00] MSG [show("@")]
|
||||
REM AT [18:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [19:00] where now() = [now()]
|
||||
@@ -758,6 +799,7 @@ REM AT [19:00] MSG [show("8")]
|
||||
REM AT [19:00] MSG [show("9")]
|
||||
REM AT [19:00] MSG [show("0")]
|
||||
REM AT [19:00] MSG [show("!")]
|
||||
REM AT [19:00] MSG [show("?")]
|
||||
REM AT [19:00] MSG [show("@")]
|
||||
REM AT [19:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [20:00] where now() = [now()]
|
||||
@@ -772,6 +814,7 @@ REM AT [20:00] MSG [show("8")]
|
||||
REM AT [20:00] MSG [show("9")]
|
||||
REM AT [20:00] MSG [show("0")]
|
||||
REM AT [20:00] MSG [show("!")]
|
||||
REM AT [20:00] MSG [show("?")]
|
||||
REM AT [20:00] MSG [show("@")]
|
||||
REM AT [20:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [21:00] where now() = [now()]
|
||||
@@ -786,6 +829,7 @@ REM AT [21:00] MSG [show("8")]
|
||||
REM AT [21:00] MSG [show("9")]
|
||||
REM AT [21:00] MSG [show("0")]
|
||||
REM AT [21:00] MSG [show("!")]
|
||||
REM AT [21:00] MSG [show("?")]
|
||||
REM AT [21:00] MSG [show("@")]
|
||||
REM AT [21:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [22:00] where now() = [now()]
|
||||
@@ -800,6 +844,7 @@ REM AT [22:00] MSG [show("8")]
|
||||
REM AT [22:00] MSG [show("9")]
|
||||
REM AT [22:00] MSG [show("0")]
|
||||
REM AT [22:00] MSG [show("!")]
|
||||
REM AT [22:00] MSG [show("?")]
|
||||
REM AT [22:00] MSG [show("@")]
|
||||
REM AT [22:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [23:00] where now() = [now()]
|
||||
@@ -814,6 +859,7 @@ REM AT [23:00] MSG [show("8")]
|
||||
REM AT [23:00] MSG [show("9")]
|
||||
REM AT [23:00] MSG [show("0")]
|
||||
REM AT [23:00] MSG [show("!")]
|
||||
REM AT [23:00] MSG [show("?")]
|
||||
REM AT [23:00] MSG [show("@")]
|
||||
REM AT [23:00] MSG [show("#")]
|
||||
MSG %_Time substitutions for [23:59] where now() = [now()]
|
||||
@@ -828,6 +874,7 @@ REM AT [23:59] MSG [show("8")]
|
||||
REM AT [23:59] MSG [show("9")]
|
||||
REM AT [23:59] MSG [show("0")]
|
||||
REM AT [23:59] MSG [show("!")]
|
||||
REM AT [23:59] MSG [show("?")]
|
||||
REM AT [23:59] MSG [show("@")]
|
||||
REM AT [23:59] MSG [show("#")]
|
||||
|
||||
@@ -857,6 +904,49 @@ msg [showmon(10)]
|
||||
msg [showmon(11)]
|
||||
msg [showmon(12)]
|
||||
|
||||
msg %_Here are some ordinal numbers for %(LANGID):
|
||||
MSG ord(0) = [ord(0)]
|
||||
MSG ord(1) = [ord(1)]
|
||||
MSG ord(2) = [ord(2)]
|
||||
MSG ord(3) = [ord(3)]
|
||||
MSG ord(4) = [ord(4)]
|
||||
MSG ord(5) = [ord(5)]
|
||||
MSG ord(6) = [ord(6)]
|
||||
MSG ord(7) = [ord(7)]
|
||||
MSG ord(8) = [ord(8)]
|
||||
MSG ord(9) = [ord(9)]
|
||||
MSG ord(10) = [ord(10)]
|
||||
MSG ord(11) = [ord(11)]
|
||||
MSG ord(12) = [ord(12)]
|
||||
MSG ord(13) = [ord(13)]
|
||||
MSG ord(14) = [ord(14)]
|
||||
MSG ord(15) = [ord(15)]
|
||||
MSG ord(16) = [ord(16)]
|
||||
MSG ord(17) = [ord(17)]
|
||||
MSG ord(18) = [ord(18)]
|
||||
MSG ord(19) = [ord(19)]
|
||||
MSG ord(20) = [ord(20)]
|
||||
MSG ord(21) = [ord(21)]
|
||||
MSG ord(22) = [ord(22)]
|
||||
MSG ord(23) = [ord(23)]
|
||||
MSG ord(24) = [ord(24)]
|
||||
MSG ord(25) = [ord(25)]
|
||||
MSG ord(26) = [ord(26)]
|
||||
MSG ord(27) = [ord(27)]
|
||||
MSG ord(28) = [ord(28)]
|
||||
MSG ord(29) = [ord(29)]
|
||||
MSG ord(30) = [ord(30)]
|
||||
MSG ord(31) = [ord(31)]
|
||||
MSG ord(32) = [ord(32)]
|
||||
MSG ord(33) = [ord(33)]
|
||||
MSG ord(34) = [ord(34)]
|
||||
MSG ord(35) = [ord(35)]
|
||||
MSG ord(36) = [ord(36)]
|
||||
MSG ord(37) = [ord(37)]
|
||||
MSG ord(38) = [ord(38)]
|
||||
MSG ord(39) = [ord(39)]
|
||||
MSG ord(40) = [ord(40)]
|
||||
|
||||
MSG $Ago is [$Ago]%
|
||||
MSG $Am is [$Am]%
|
||||
MSG $And is [$And]%
|
||||
|
||||
Reference in New Issue
Block a user