Compare commits

..

121 Commits

Author SHA1 Message Date
Dianne Skoll
695a2a3c2d Add "dp" to hunspell dictionary. 2026-02-15 16:46:51 -05:00
Dianne Skoll
47aa542d4f Update WHATSNEW 2026-02-15 16:45:28 -05:00
Dianne Skoll
5b4d1ae264 Bump version to 06.02.04 2026-02-15 11:09:26 -05:00
Dianne Skoll
721ccb9af9 Add explicit dates to most Remind invocations in test-rem 2026-02-15 11:03:28 -05:00
Dianne Skoll
ab1a6c412a Add tests for push/pop in different files warnings. 2026-02-15 10:57:31 -05:00
Dianne Skoll
c3a555942b Don't warn if a POP... is in a different file from a PUSH... unless the -dp flag is used. 2026-02-15 10:53:08 -05:00
Dianne Skoll
0d15977875 Tweak man pages. 2026-02-05 22:47:28 -05:00
Dianne Skoll
0a7e6ee219 Fix wording. 2026-02-05 22:42:15 -05:00
Dianne Skoll
baf049662f Fix typo 2026-02-05 22:40:16 -05:00
Dianne Skoll
fd5d9a479d *sigh* don't put an extra period after the version in "rem2html --version" 2026-02-05 22:33:43 -05:00
Dianne Skoll
01d3081f19 Make TkRemind support --version 2026-02-05 22:29:53 -05:00
Dianne Skoll
7841077fc6 Make all programs support --version 2026-02-05 22:25:10 -05:00
Dianne Skoll
2003c7a703 Add --version option to rem2pdf. 2026-02-05 22:18:17 -05:00
Dianne Skoll
4a603ce60d Tweak the CSS. 2026-02-05 19:25:39 -05:00
Dianne Skoll
caad7f5aa3 Add the $Shaded system variable. 2026-02-05 13:14:22 -05:00
Dianne Skoll
ea2312c0b2 Add mblower and mbupper functions.
These are Unicode-safe versions of lower() and upper()
2026-02-05 12:41:36 -05:00
Dianne Skoll
c0c49be0b5 Bump to version 06.02.03 2026-02-05 10:08:21 -05:00
Dianne Skoll
c0594811bf Integrate some CSS from Robert Black. 2026-02-04 17:49:58 -05:00
Dianne Skoll
b7e13845b6 Move yaag CSS to one place 2026-02-04 17:33:53 -05:00
Dianne Skoll
94b340305c Make year-at-a-glance CSS classes all start with rem-yaag- 2026-02-02 11:12:27 -05:00
Dianne Skoll
f477757ac0 Update tests for correct trigbase output format. 2026-02-02 11:09:02 -05:00
Dianne Skoll
a8017c6fc7 Fix JSON format of trigbase
Reported by Georg Simon.
2026-02-02 11:05:29 -05:00
Dianne Skoll
aad746bca3 Improve --yaag CSS 2026-01-30 14:31:34 -05:00
Dianne Skoll
953ff8c49e Add "--yaag" option to rem2html to create a "year-at-a-glance" formatted calendar. 2026-01-30 12:00:41 -05:00
Dianne Skoll
b5258b1eb5 Refactor. 2026-01-22 18:09:09 -05:00
Dianne Skoll
82733e817b Increase default value of $MaxSatIter from 1000 to 10000. 2026-01-20 15:19:23 -05:00
Dianne Skoll
86e94009a4 Better error than "type mismatch" if we assign a bad value to a system variable. 2026-01-19 18:49:03 -05:00
Dianne Skoll
04ea056820 Add MOON, SHADE, WEEK, COLOR and COLOUR to keyword list even though they are not really keywords. 2026-01-18 14:24:40 -05:00
Dianne Skoll
d6ee16cc13 Avoid "use of uninitialized variable" 2026-01-13 17:02:43 -05:00
Dianne Skoll
ead660fe41 Document default setting of $TerminalHyperlinks. 2026-01-11 17:52:38 -05:00
Dianne Skoll
58e5ae15b0 Fix URL. 2026-01-11 15:22:07 -05:00
Dianne Skoll
85a8a4b016 Only set default for TerminalHyperlinks if it hasn't explicitly been set
(for example, with '-i$TerminalHyperlinks=n')
2026-01-11 10:58:30 -05:00
Dianne Skoll
c43eaec274 Default $TerminalHyperlinks to 1 if stdout is a TTY. 2026-01-11 10:56:19 -05:00
Dianne Skoll
13fd54b990 Add URLs for sunrise and sunset. 2026-01-11 10:54:34 -05:00
Dianne Skoll
a48b2ec02e Fix typo 2026-01-10 20:11:18 -05:00
Dianne Skoll
4e3562e2e4 Prep release date. 2026-01-10 11:07:26 -05:00
Dianne Skoll
2020ae35c1 Add another bugfix doc. 2026-01-10 11:03:29 -05:00
Dianne Skoll
9418043bb6 When printing weekly calendars, start from the right date. 2026-01-10 10:54:50 -05:00
Dianne Skoll
e2f786580c Make the 'z' flag of the "-c" command-line option work as it did in 06.00.00. 2026-01-10 10:35:52 -05:00
Dianne Skoll
5aabb20630 Fix typo 2026-01-09 21:50:23 -05:00
Dianne Skoll
a3c9ac2457 Add missing variable. 2026-01-09 21:49:28 -05:00
Dianne Skoll
80e3671f9b Add incompatibility note. 2026-01-09 21:46:30 -05:00
Dianne Skoll
e8e4362839 Add missing blank line 2026-01-09 21:42:37 -05:00
Dianne Skoll
61ac3ca6ed Update WHATSNEW. 2026-01-09 21:40:47 -05:00
Dianne Skoll
eaf982e1cc Bump version number to 06.02.02. 2026-01-09 21:29:10 -05:00
Dianne Skoll
0c27503a83 Make popup windows obey color scheme. 2026-01-09 21:25:17 -05:00
Dianne Skoll
5878c2a714 Cache $Ud, $Um, $Uy 2026-01-09 21:06:10 -05:00
Dianne Skoll
6aa4d681e8 Refactor code. 2026-01-09 17:07:55 -05:00
Dianne Skoll
790a9ee384 Add option to suppress blank lines between reminders in Calendar Mode. 2026-01-09 16:56:44 -05:00
Dianne Skoll
d091af6e5b Fixify wording. 2026-01-09 15:45:15 -05:00
Dianne Skoll
3ca9a69100 Document that now() in Calendar Mode always returns 00:00. 2026-01-09 15:44:05 -05:00
Dianne Skoll
f6253d0fca Add $TerminalHyperlinks system variable.
This lets you turn any reminder with an INFO "Url: ..." string
into a hyperlink on the terminal.
2026-01-08 14:13:34 -05:00
Dianne Skoll
3e6233b6f0 Fix edge-cases where a WARN REM might not trigger on the trigger date. 2026-01-05 12:38:54 -05:00
Dianne Skoll
0ee5efa4df Keep track of dynamic buffer allocations. 2025-12-31 17:28:25 -05:00
Dianne Skoll
d4ed89f5ba Update copyright date. 2025-12-31 11:05:21 -05:00
Dianne Skoll
34c864a38c Allow "COMPLETED-THROUGH" as a synonym for COMPLETE-THROUGH. 2025-12-30 11:52:25 -05:00
Dianne Skoll
6d4c38126e Try stderr if we're asking for terminal size if stdout is not connected to a tty. 2025-12-29 17:30:56 -05:00
Dianne Skoll
59c434ce34 Reorganize man page. 2025-12-29 15:06:11 -05:00
Dianne Skoll
a550af8fa6 Fix typo. 2025-12-29 15:03:34 -05:00
Dianne Skoll
3399646896 Correct the spelling of Sivan - should be סיון and not סיוון 2025-12-29 14:59:43 -05:00
Dianne Skoll
00e85e5ca2 Document Iyyar alternate. 2025-12-27 15:48:52 -05:00
Dianne Skoll
9867d3cf34 Format code a bit better. 2025-12-27 15:46:50 -05:00
Dianne Skoll
0f4326726a Allow alternate transliterations of Hebrew months. 2025-12-27 15:44:21 -05:00
Dianne Skoll
1d208400cd Add tests for invalid multibyte sequences and mbpad 2025-12-24 16:17:21 -05:00
Dianne Skoll
b9b7e0d42a Fix typo 2025-12-24 16:15:35 -05:00
Dianne Skoll
93316d754c Add the mbpad function. 2025-12-24 16:05:25 -05:00
Dianne Skoll
14b6e23eaa Remove unnecessary #ifndef...#endif pair 2025-12-23 11:22:08 -05:00
Dianne Skoll
7ae7edcb42 Assume standard functions strcasecmp, strncasecmp and strdup are always available. 2025-12-22 15:53:37 -05:00
Dianne Skoll
20a558f817 Add some words to hunspell dictionary. 2025-12-22 11:16:04 -05:00
Dianne Skoll
5118ccd120 Add ivritmon built-in function. 2025-12-22 11:11:18 -05:00
Dianne Skoll
18c4ed1c6d Allow use of Hebrew month spellings in hebdate() 2025-12-22 10:55:46 -05:00
Dianne Skoll
62e1a467f5 Make <wchar.t> and mbstowcs mandatory. Get rid of some conditional compilation. 2025-12-18 15:21:18 -05:00
Dianne Skoll
0933cd83b1 Colors. 2025-12-11 15:41:24 -05:00
Dianne Skoll
1ed7c83b24 Minor tidying. 2025-12-08 15:27:29 -05:00
Dianne Skoll
3bae02f27d Fix up localizations. 2025-12-08 15:23:54 -05:00
Dianne Skoll
3b485f0632 Move localizations. 2025-12-08 15:14:19 -05:00
Dianne Skoll
a023d9dc5d Move translations around. 2025-12-07 23:48:12 -05:00
Dianne Skoll
4ccdfac8b8 Finalize "make uninstall-script" command. 2025-12-07 23:37:28 -05:00
Dianne Skoll
1c52718ef0 Add "make uninstall" target. 2025-12-07 23:28:31 -05:00
Dianne Skoll
4dde2a4b9d Fix logic. 2025-12-04 12:39:15 -05:00
Dianne Skoll
24f923ecfc Start moving specific localizations into their own files. 2025-12-04 12:35:59 -05:00
Dianne Skoll
45c0ba5e8f Split Chanukah into separate reminders. 2025-11-30 19:54:30 -05:00
Dianne Skoll
bccfe94921 Better Hunspell detection. 2025-11-30 16:43:43 -05:00
Dianne Skoll
f7e83ed082 Stricter test for hunspell 2025-11-30 10:37:43 -05:00
Dianne Skoll
40b87eff60 Fix man page formatting. 2025-11-28 11:30:07 -05:00
Dianne Skoll
a8607cb012 Add some terms to hunspell dictionary. 2025-11-10 12:15:34 -05:00
Dianne Skoll
6caa404e59 Prep for 06.02.01 release. 2025-11-10 12:14:28 -05:00
Dianne Skoll
13e1e19855 Add some tests; make tess pass on MUSL. 2025-11-10 12:08:58 -05:00
Dianne Skoll
96d40b81df Make early exit contingent upon ParseUntriggered. 2025-11-10 12:02:47 -05:00
Dianne Skoll
30e4a9fc50 Catch possible error 2025-11-06 21:42:57 -05:00
Dianne Skoll
6d0fbeed20 Hide font chooser if we kill .opts 2025-11-06 21:40:58 -05:00
Dianne Skoll
3f1aaeefd2 Raise .opts when font chooser is dismissed. 2025-11-06 21:39:42 -05:00
Dianne Skoll
326604fe18 Free trigger resources if we exit early because of expired reminder. 2025-11-04 17:07:09 -05:00
Dianne Skoll
57e93553bf Exit early if a reminder has expired. 2025-11-04 17:05:02 -05:00
Dianne Skoll
a5aa5d901b Prevent test failures. 2025-11-03 10:33:10 -05:00
Dianne Skoll
1e0d43b63c Tweak WHATSNEW. 2025-11-03 10:16:37 -05:00
Dianne Skoll
188efaebba Update test file. 2025-11-03 10:14:15 -05:00
Dianne Skoll
b701dc575f Prep for 06.02.00 release. 2025-11-03 10:13:16 -05:00
Dianne Skoll
c9ae1c82f0 Make all weekly boxes the same height. 2025-11-02 21:44:31 -05:00
Dianne Skoll
13cea56cce Draw moon phases left-aligned on weekly calendars. 2025-11-02 21:32:36 -05:00
Dianne Skoll
6661f32faf In weekly calendars, draw moon phases smaller and in days without moon
phases, don't leave a big gap at the top.
2025-11-02 21:28:44 -05:00
Dianne Skoll
f6ab660c5e Correct positioning of WEEK special. 2025-11-02 21:18:17 -05:00
Dianne Skoll
523cfb7bf5 Document common INFO strings. 2025-11-02 20:15:30 -05:00
Dianne Skoll
82a4ba777d Update WHATSNEW 2025-11-02 14:07:43 -05:00
Dianne Skoll
8f02868486 Refactor code. 2025-11-02 14:00:59 -05:00
Dianne Skoll
12d8e8e948 Add support for turning reminders with "URL" info strings into hyperlinks if your terminal supports it.
Use the "z" flag with -c.
2025-11-02 13:29:41 -05:00
Dianne Skoll
f5f364507b Add not about Jochen Sprickerhof's work on test-rem. 2025-11-02 12:33:36 -05:00
Dianne Skoll
d514389c39 Sort the dictionary. :) 2025-11-02 12:31:44 -05:00
Dianne Skoll
52c615ff61 Revert warning if BANNER is used after a banner has already been issued.
https://dianne.skoll.ca/pipermail/remind-fans/2025/005268.html
2025-11-02 12:21:12 -05:00
Dianne Skoll
7d3e6b3a72 Warn if we see a BANNER command when the banner has already been issued. 2025-11-02 11:28:48 -05:00
Dianne Skoll
c4e5190ec2 Add missing key bindings. 2025-11-02 10:59:39 -05:00
Dianne Skoll
f197f5ef9d Document keyboard shortcuts 2025-11-02 10:55:58 -05:00
Dianne Skoll
153cbfe276 A bunch more key bindings. 2025-11-02 10:52:39 -05:00
Dianne Skoll
2d9bea444b Add a bunch more key bindings. 2025-11-02 10:48:40 -05:00
Dianne Skoll
2ae8e51bec Style fix. 2025-11-02 09:43:13 -05:00
Dianne Skoll
05d1608081 Update man page. 2025-11-02 09:32:52 -05:00
Dianne Skoll
d093e8dea3 Make "Esc" close agenda-mode window. 2025-11-02 09:31:21 -05:00
Dianne Skoll
f9fac22bbf Bind "KeyPress-t" to ShowTodaysReminders. 2025-11-02 09:28:16 -05:00
Dianne Skoll
9ecbfbb314 Make details popup work again. 2025-11-02 09:25:29 -05:00
Dianne Skoll
612f3e7f16 Make sure .balloonhelp doesn't exist if we try to create it. 2025-11-02 09:20:07 -05:00
Dianne Skoll
d22f9979a5 Make sure .balloonhelp doesn't exist if we try to create it. 2025-11-02 09:16:23 -05:00
108 changed files with 2394 additions and 895 deletions

View File

@@ -3,7 +3,7 @@ THE REMIND COPYRIGHT
1. REMIND refers to the entire set of files and documentation in the
REMIND package.
2. REMIND is Copyright (C) 1992-2025 Dianne Skoll, except where noted in
2. REMIND is Copyright (C) 1992-2026 Dianne Skoll, except where noted in
individual files.
3. DISTRIBUTION AND USE

View File

@@ -11,6 +11,33 @@ all: src/Makefile
@echo ""
@cd src && $(MAKE) all LANGDEF=$(LANGDEF)
@$(MAKE) -C rem2pdf -f Makefile.top
uninstall-script:
@echo "" >&2
@echo "*****************************" >&2
@echo "* *" >&2
@echo "* Creating Uninstall Script *" >&2
@echo "* *" >&2
@echo "*****************************" >&2
@echo "" >&2
@echo "#!/bin/sh"
@echo "echo 'This script will uninstall Remind'"
@echo "echo 'Enter y to uninstall Remind or anything else to abort'"
@echo "read ans"
@echo 'if test "$$ans" != "y" ; then'
@echo " echo 'NOT uninstalling Remind'"
@echo " exit 0"
@echo "fi"
@echo "echo 'Uninstalling Remind...'"
-@rm -rf `pwd`/.uninstall-dir > /dev/null 2>&1
@mkdir `pwd`/.uninstall-dir >&2
@$(MAKE) install DESTDIR=`pwd`/.uninstall-dir >&2
@cd `pwd`/.uninstall-dir && find . -type f | while read x ; do x=`echo $$x | sed -e 's|^\./|/|'`; echo "rm -f $$x"; done;
@echo "echo 'Done'"
-@rm -rf `pwd`/.uninstall-dir > /dev/null 2>&1
install:
@echo ""
@echo "**********************************"
@@ -19,9 +46,9 @@ install:
@echo "* *"
@echo "**********************************"
@echo ""
@$(MAKE) -C src install
@$(MAKE) -C rem2html install
@$(MAKE) -C rem2pdf -f Makefile.top install INSTALL_BASE=$(INSTALL_BASE)
@$(MAKE) -C src install DESTDIR=$(DESTDIR)
@$(MAKE) -C rem2html install DESTDIR=$(DESTDIR)
@$(MAKE) -C rem2pdf -f Makefile.top install INSTALL_BASE=$(INSTALL_BASE) DESTDIR=$(DESTDIR)
clean:
-find . -name '*~' -exec rm {} \;
-$(MAKE) -C src clean
@@ -35,9 +62,9 @@ install-stripped:
@echo "* *"
@echo "**********************************"
@echo ""
@$(MAKE) -C src install-stripped
@$(MAKE) -C rem2html install
@$(MAKE) -C rem2pdf -f Makefile.top install INSTALL_BASE=$(INSTALL_BASE)
@$(MAKE) -C src install-stripped DESTDIR=$(DESTDIR)
@$(MAKE) -C rem2html install DESTDIR=$(DESTDIR)
@$(MAKE) -C rem2pdf -f Makefile.top install INSTALL_BASE=$(INSTALL_BASE) DESTDIR=$(DESTDIR)
test: test-basic test-tz

View File

@@ -8,7 +8,7 @@
# A cheesy graphical front-end for building and installing REMIND.
#
# This file is part of REMIND.
# Copyright (C) 1992-2025 Dianne Skoll
# Copyright (C) 1992-2026 Dianne Skoll
#
#--------------------------------------------------------------

41
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.72 for remind 06.01.09.
# Generated by GNU Autoconf 2.72 for remind 06.02.04.
#
#
# 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='06.01.09'
PACKAGE_STRING='remind 06.01.09'
PACKAGE_VERSION='06.02.04'
PACKAGE_STRING='remind 06.02.04'
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 06.01.09 to adapt to many kinds of systems.
'configure' configures remind 06.02.04 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 06.01.09:";;
short | recursive ) echo "Configuration of remind 06.02.04:";;
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 06.01.09
remind configure 06.02.04
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 06.01.09, which was
It was created by remind $as_me 06.02.04, which was
generated by GNU Autoconf 2.72. Invocation command line was
$ $0$ac_configure_args_raw
@@ -4316,24 +4316,12 @@ if test "$?" != 0 ; then
echo "*** COULD NOT DETERMINE RELEASE DATE: docs/WHATSNEW is incorrect!"
exit 1
fi
ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup"
if test "x$ac_cv_func_strdup" = xyes
then :
printf "%s\n" "#define HAVE_STRDUP 1" >>confdefs.h
if test "$ac_cv_header_wctype_h" != "yes" ; then
echo "*** Remind requires the <wctype.h> header"
exit 1
fi
ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp"
if test "x$ac_cv_func_strcasecmp" = xyes
then :
printf "%s\n" "#define HAVE_STRCASECMP 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "strncasecmp" "ac_cv_func_strncasecmp"
if test "x$ac_cv_func_strncasecmp" = xyes
then :
printf "%s\n" "#define HAVE_STRNCASECMP 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "setenv" "ac_cv_func_setenv"
if test "x$ac_cv_func_setenv" = xyes
then :
@@ -4384,6 +4372,11 @@ then :
fi
if test "$ac_cv_func_mbstowcs" != "yes"; then
echo "*** Remind requires the mbstowcs function"
exit 1
fi
VERSION=$PACKAGE_VERSION
CONFIG_CMD="$0$ac_configure_args_raw"
CONFIG_CMD=`echo "$CONFIG_CMD" | sed -e 's/"/\\\\"/g'`
@@ -4899,7 +4892,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 06.01.09, which was
This file was extended by remind $as_me 06.02.04, which was
generated by GNU Autoconf 2.72. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -4964,7 +4957,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 06.01.09
remind config.status 06.02.04
configured by $0, generated by GNU Autoconf 2.72,
with options \\"\$ac_cs_config\\"

View File

@@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(remind, 06.01.09, , , https://dianne.skoll.ca/projects/remind/)
AC_INIT(remind, 06.02.04, , , https://dianne.skoll.ca/projects/remind/)
AC_CONFIG_SRCDIR([src/queue.c])
cat <<'EOF'
@@ -103,7 +103,18 @@ if test "$?" != 0 ; then
echo "*** COULD NOT DETERMINE RELEASE DATE: docs/WHATSNEW is incorrect!"
exit 1
fi
AC_CHECK_FUNCS(strdup strcasecmp strncasecmp setenv unsetenv glob mbstowcs setlocale initgroups inotify_init1 readline)
if test "$ac_cv_header_wctype_h" != "yes" ; then
echo "*** Remind requires the <wctype.h> header"
exit 1
fi
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale initgroups inotify_init1 readline)
if test "$ac_cv_func_mbstowcs" != "yes"; then
echo "*** Remind requires the mbstowcs function"
exit 1
fi
VERSION=$PACKAGE_VERSION
CONFIG_CMD="$0$ac_configure_args_raw"

View File

@@ -106,11 +106,12 @@
"Syntax table for `remind-conf-mode'.")
;;; keyword sets
;;; MOON, WEEK, SHADE, COLOR and COLOUR are not really keywords,
;;; but they are widely-supported SPECIALS, so I add them here.
(defconst remind-keywords
(sort
(list "ADDOMIT" "AFTER" "AT" "BAN" "BANNER" "BEFORE" "CAL" "CLEAR"
"CLEAR-OMIT-CONTEXT" "COMPLETE-THROUGH" "DEBUG" "DO" "DUMP" "DUMPVARS"
"CLEAR-OMIT-CONTEXT" "COMPLETE-THROUGH" "COMPLETED-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"
@@ -120,7 +121,8 @@
"PSFILE" "PUSH" "PUSH-FUNCS" "PUSH-VARS" "PUSH-OMIT-CONTEXT" "REM" "RETURN"
"RUN" "SATISFY" "SCAN" "SCANFROM" "SCHED" "SECOND" "SET"
"SKIP" "SPECIAL" "SYSINCLUDE" "TAG" "THIRD" "THROUGH" "TODO"
"TRANSLATE" "TRANS" "TZ" "UNSET" "UNTIL" "WARN")
"TRANSLATE" "TRANS" "TZ" "UNSET" "UNTIL" "WARN"
"MOON" "WEEK" "SHADE" "COLOR" "COLOUR")
#'(lambda (a b) (> (length a) (length b)))))
@@ -131,7 +133,7 @@
(defconst remind-builtin-variables
(sort
(list " $AddBlankLines" "$Ago" "$Am" "$And" "$April" "$At" "$August"
(list "$AddBlankLines" "$Ago" "$Am" "$And" "$April" "$At" "$August"
"$CalcUTC" "$CalMode" "$CalType" "$Daemon" "$DateSep" "$DateTimeSep"
"$December" "$DedupeReminders" "$DefaultColor" "$DefaultDelta"
"$DefaultPrio" "$DefaultTDelta" "$DeltaOverride"
@@ -145,10 +147,10 @@
"$May" "$MinsFromUTC" "$Minute" "$Monday" "$Mplu" "$NextMode"
"$November" "$Now" "$NumFullOmits" "$NumPartialOmits" "$NumQueued"
"$NumTrig" "$October" "$On" "$OnceFile" "$ParseUntriggered" "$Pm"
"$PrefixLineNo" "$PSCal" "$RunOff" "$Saturday" "$September"
"$PrefixLineNo" "$PSCal" "$RunOff" "$Saturday" "$September" "$Shaded"
"$SimpleCal" "$SortByDate" "$SortByPrio" "$SortByTime" "$SubsIndent"
"$Sunday" "$SuppressImplicitWarnings" "$SuppressLRM" "$SysInclude" "$T" "$Tb" "$Td"
"$TerminalBackground" "$Thursday" "$TimeSep" "$TimetIs64bit" "$Tm" "$Today" "$TodoFilter"
"$TerminalBackground" "$TerminalHyperlinks" "$Thursday" "$TimeSep" "$TimetIs64bit" "$Tm" "$Today" "$TodoFilter"
"$Tomorrow" "$Tt" "$Tuesday" "$Tw" "$Ty" "$U" "$Ud" "$Um"
"$UntimedFirst" "$Use256Colors" "$UseBGVTColors" "$UseTrueColors"
"$UseVTColors" "$Uw" "$Uy" "$WarningLevel" "$Was" "$Wednesday")
@@ -165,26 +167,151 @@
(defconst remind-builtin-functions
(sort
(list "_" "abs" "access" "adawn" "adusk" "ampm" "ansicolor" "args" "asc"
"baseyr" "catch" "catcherr" "char" "choose" "codepoint" "coerce" "columns" "const" "current" "date"
"datepart" "datetime" "dawn" "day" "daysinmon" "defined" "dosubst"
"dusk" "easterdate" "escape" "eval" "evaltrig" "filedate" "filedatetime"
"filedir" "filename" "getenv" "hebdate" "hebday" "hebmon" "hebyear" "hex"
"hour" "htmlescape" "htmlstriptags" "iif" "index" "isany" "isconst" "isdst"
"isleap" "isomitted" "language" "localtoutc" "lower" "max"
"mbasc" "mbindex" "mbstrlen" "mbsubstr" "min"
"minsfromutc" "minute" "mon" "monnum" "moondate" "moondatetime"
"moonphase" "moonrise" "moonrisedir" "moonset" "moonsetdir" "moontime"
"multitrig" "ndawn" "ndusk" "nonconst" "nonomitted" "now" "ord" "orthodoxeaster"
"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" "trigcompletethrough" "trigdate" "trigdatetime"
"trigdelta" "trigduration" "trigeventduration" "trigeventstart" "trigeventstarttz"
"trigfrom" "trigger" "triginfo" "trigistodo" "trigmaxoverdue" "trigpriority" "trigrep"
"trigscanfrom" "trigtags" "trigtime" "trigtimedelta" "trigtimerep" "trigtimetz" "trigtz"
"triguntil" "trigvalid" "typeof" "tzconvert" "upper" "utctolocal"
"value" "version" "weekno" "wkday" "wkdaynum" "year"
(list
"_"
"abs"
"access"
"adawn"
"adusk"
"ampm"
"ansicolor"
"args"
"asc"
"baseyr"
"catch"
"catcherr"
"char"
"choose"
"codepoint"
"coerce"
"columns"
"const"
"current"
"date"
"datepart"
"datetime"
"dawn"
"day"
"daysinmon"
"defined"
"dosubst"
"dusk"
"easterdate"
"escape"
"eval"
"evaltrig"
"filedate"
"filedatetime"
"filedir"
"filename"
"getenv"
"hebdate"
"hebday"
"hebmon"
"hebyear"
"hex"
"hour"
"htmlescape"
"htmlstriptags"
"iif"
"index"
"isany"
"isconst"
"isdst"
"isleap"
"isomitted"
"ivritmon"
"language"
"localtoutc"
"lower"
"max"
"mbasc"
"mbindex"
"mblower"
"mbstrlen"
"mbsubstr"
"mbupper"
"min"
"minsfromutc"
"minute"
"mon"
"monnum"
"moondate"
"moondatetime"
"moonphase"
"moonrise"
"moonrisedir"
"moonset"
"moonsetdir"
"moontime"
"multitrig"
"ndawn"
"ndusk"
"nonconst"
"nonomitted"
"now"
"ord"
"orthodoxeaster"
"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"
"trigcompletethrough"
"trigdate"
"trigdatetime"
"trigdelta"
"trigduration"
"trigeventduration"
"trigeventstart"
"trigeventstarttz"
"trigfrom"
"trigger"
"triginfo"
"trigistodo"
"trigmaxoverdue"
"trigpriority"
"trigrep"
"trigscanfrom"
"trigtags"
"trigtime"
"trigtimedelta"
"trigtimerep"
"trigtimetz"
"trigtz"
"triguntil"
"trigvalid"
"typeof"
"tzconvert"
"upper"
"utctolocal"
"value"
"version"
"weekno"
"wkday"
"wkdaynum"
"year"
)
#'(lambda (a b) (> (length a) (length b)))))

View File

@@ -1,11 +1,135 @@
CHANGES TO REMIND
* VERSION 06.01.09 - 2025-11-??
* VERSION 06.02.04 - 2026-02-15
- IMPROVEMENT: remind: Add the mblower and mbupper functions, which are
multibyte counterparts to lower and upper.
- MINOR NEW FEATURE: remind: Add the $Shaded system variable that counts
how many times a "SPECIAL SHADE" reminder has triggered. See the
man page for an example of how this can be useful.
- MINOR IMPROVEMENT: Make all programs that ship with Remind (remind,
rem2ps, rem2pdf, rem2html and tkremind) accept a --version long option.
- CHANGE: remind: Remind used to warn if the POP-OMIT-CONTEXT, POP-VARS
or POP-FUNCS command corresponding to the relevant PUSH command was
in a different file than the PUSH command. But there are valid use
cases for this, so Remind no longer emits the warning unless you use
the "-dp" debugging flag.
* VERSION 06.02.03 - 2026-02-05
- NEW FEATURE: rem2html: Add a new --yaag option to produce a calendar
in the "year-at-a-glance" format. This format features a table with
an entire month in each row. Thanks to Robert Black for suggesting
this and for helping out with the CSS.
- CHANGE: remind: If standard output is a TTY, then default
$TerminalHyperlinks to 1
- CHANGE: remind: Increase the default value of $MaxSatIter from 1000
to 10000, reflecting the higher speed of the new expression
evaluation engine as well as the speed of modern CPUs.
- UPDATE: examples/remind.vim: Update the URL to point to maintained
version.
- IMPROVEMENT: include/sun.rem: Add Wikipedia links for sunrise/sunset
- IMPROVEMENT: Add MOON, SHADE, WEEK, COLOR and COLOUR to the Emacs
syntax highlighting keyword list.
- IMPROVEMENT: If an invalid value is assigned to a system variable,
issue the error "Invalid value for system variable" rather than
"Type mismatch"
- DOC FIX: Fix typo in man page
- BUG FIX: rem2html: Eliminate "use of uninitialized variable"
warning.
- BUG FIX: remind: The "trigbase" JSON key in "remind -pp" output had
an incorrectly-formatted value. This has been fixed; thanks to
Georg Simon for reporting this bug.
* VERSION 06.02.02 - 2026-01-10
- NEW FEATURE: remind: Turn reminders with a "Url:" INFO string into
hyperlinks if you set the $TerminalHyperlinks system variable to 1.
Note that your terminal must support the "OSC 8" hyperlink escape
sequence; see
https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
for details.
For backward compatibility, the 'z' flag of the "-c" command-line
option sets $TerminalHyperlinks to 1.
- NEW FEATURE: remind: Add another parameter to the "-w" option to
remove blank lines between reminders, thereby making the calendar
more compact.
- IMPROVEMENT: TkRemind: Make the window that pops up for background
reminders obey the color options chosen under "Options..."
- CHANGE: remind: The header <wchar.h> and the functions mbstowcs and
wcstombs are now mandatory. This should not affect any vaguely modern
UNIX system.
- IMPROVEMENT: remind: Allow Hebrew spellings of Hebrew month names. For
example, you can use "Iyar" or "אייר".
- IMPROVEMENT: remind: Allow different Hebrew transliterations of month names.
For example, you can use "Shvat" or "Shevat". See the man page for
the full list of possibilities.
- IMPROVEMENT: remind: Add the mbpad() function, which is the
character-oriented counterpart to pad().
- MINOR NEW FEATURE: Add a "make uninstall-script" Makefile target. This
generates a script that if run as root after "make install", will remove
Remind.
- MINOR IMPROVEMENT: remind: Make COMPLETED-THROUGH a synonym for
COMPLETE-THROUGH.
- BUG FIX: TkRemind: When we print a weekly calendar, make sure we start
from the same date as the currently-displayed calendar.
- BUG FIX: remind: Fix an edge case where a REM command with a WARN function
may not trigger on its actual trigger date.
- BUG FIX: include/holidays/jewish.rem: Split Chanukah into separate
reminders to improve iCal export.
- DOC FIX: remind.1: Fix bad man page formatting.
- DOC FIX: Document that now() returns 00:00 in Calendar Mode.
* VERSION 06.02.01 - 2025-11-10
- BUG FIX: remind: Obey $ParseUntriggered in Calendar Mode. Before,
$ParseUntriggered was always being treated as 1 in Calendar Mode.
- BUG FIX: TkRemind: Fix some buggy interactions between the Options
dialog and the font chooser.
- TEST FIX: One test was consistently failing under MUSL, and it is
not clear whether MUSL's or glibc's interpretation is correct.
Remove that test so all tests pass under MUSL.
* VERSION 06.02.00 - 2025-11-03
- MAJOR NEW FEATURE: TkRemind: A new "View..." menu lets you choose a
calendar view from the following choices: Entire month, 1 week, 2
weeks or 4 weeks.
- NEW FEATURE: remind: The "z" flag for the "-c" option makes Remind
turn reminders with a "Url:" INFO string into clickable hyperlinks.
Note that your terminal must support the escape sequences at
https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
for this feature to work.
- IMPROVEMENT: TkRemind: The Print dialog now allows you to preview
(and if you wish, adjust) the command used to print a calendar.
@@ -13,6 +137,10 @@ CHANGES TO REMIND
Reminders") has navigation buttons for moving back or forward one
day at a time.
- IMPROVEMENT: TkRemind: Add many keyboard shortcuts. All pop-up
windows can be closed with Esc or Control-W. Other shortcuts are
documented in the tkremind man page.
- CHANGE: TkRemind: If you hand-edit a reminder in the "Preview
Reminder" dialog box, it is marked as non-editable by TkRemind.
@@ -22,6 +150,23 @@ CHANGES TO REMIND
- IMPROVEMENT: remind: Improve error reporting if there's extraneous
content after an expression.
- IMPROVEMENT: tests: test-rem was tweaked to allow testing of an
installed Remind installation. This work was done by Jochen
Sprickerhof.
- IMPROVEMENT: rem2pdf: When rendering weekly calendars, reduce the
default size when drawing moons; if a day does not have a moon
indicator, don't leave a big gap before the first reminder entry.
- IMPROVEMENT: rem2pdf: Draw moon phases left-aligned.
- IMPROVEMENT: rem2pdf: For weekly calendars with 4 weeks per page,
make all of the boxes the same height.
- DOCUMENTATION IMPROVEMENT: remind: Document the INFO strings that
back-ends should strive to support (Url:, Location: and
Description:)
- BUG FIX: TkRemind: Bind the Home/End/PgUp/PgDn keys on the numeric
keyboard for navigation.

View File

@@ -21,7 +21,7 @@
# "#PSSTUFF" for nifty PostScript examples #
# #
# This file is part of REMIND. #
# Copyright (C) 1992-2025 Dianne Skoll #
# Copyright (C) 1992-2026 Dianne Skoll #
# SPDX-License-Identifier: GPL-2.0-only
# #
#############################################################################

View File

@@ -3,7 +3,7 @@
" Maintainer: Davide Alberani <da@erlug.linux.it>
" Last Change: 02 Nov 2015 + 13 Mar 2022 by Dianne Skoll <dianne@skoll.ca>
" Version: 0.7+dianne1
" URL: http://ismito.it/vim/syntax/remind.vim
" URL: https://github.com/alberanid/vim-config/blob/master/syntax/remind.vim
"
" remind is a sophisticated reminder service
" you can download remind from:

View File

@@ -2,7 +2,7 @@
# Not all sequences are supported by all terminals.
# This file is part of REMIND
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# SPDX-License-Identifier: GPL-2.0-only
if !defined("ansi_bold")

View File

@@ -1,4 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
# Localize if we can
IF access($SysInclude + "/translations/" + _("LANGID") + "/holidays/chinese-new-year.rem", "r") >= 0
SYSINCLUDE translations/[_("LANGID")]/holidays/chinese-new-year.rem
ENDIF
REM 1 Feb 2022 INFO "Url: https://en.wikipedia.org/wiki/Tiger_(zodiac)" MSG %"%(Chinese New Year) (%(Tiger))%" %! %b.
REM 22 Jan 2023 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %"%(Chinese New Year) (%(Rabbit))%" %! %b.
REM 10 Feb 2024 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %"%(Chinese New Year) (%(Dragon))%" %! %b.

View File

@@ -37,10 +37,19 @@ REM [hebdate(21, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Hoshana_Ra
REM [hebdate(22, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Shemini_Atzeret" MSG %"Shemini Atzeret%" %! %b.
REM [_h2I(22, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Simchat_Torah" MSG %"Simchat Torah%" %! %b.
# If the reminder has expired, $T can be zero, hence the
# ($T || $U) below
REM [hebdate(25, "Kislev",$U-9)] through [hebdate(25, "Kislev",$U-9)+7] \
INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG %"Chanukah [($T || $U) - hebdate(25,"Kislev",$U-9) + 1]%" %! %b.
# This reminder used to be done as a single reminder. I have split it
# into 8 separate reminders because the "rem2dav" script uses
# synthetic tags as UUIDs and it incorrectly coalesces the 8 days'
# worth of reminders into a single 8-day reminder.
REM [hebdate(25, "Kislev", $U-9)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG %"Chanukah 1%" %! %b.
REM [hebdate(25, "Kislev", $U-9)+1] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG %"Chanukah 2%" %! %b.
REM [hebdate(25, "Kislev", $U-9)+2] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG %"Chanukah 3%" %! %b.
REM [hebdate(25, "Kislev", $U-9)+3] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG %"Chanukah 4%" %! %b.
REM [hebdate(25, "Kislev", $U-9)+4] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG %"Chanukah 5%" %! %b.
REM [hebdate(25, "Kislev", $U-9)+5] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG %"Chanukah 6%" %! %b.
REM [hebdate(25, "Kislev", $U-9)+6] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG %"Chanukah 7%" %! %b.
REM [hebdate(25, "Kislev", $U-9)+7] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG %"Chanukah 8%" %! %b.
IF !Reform
REM [hebdate(10, "Tevet")] INFO "Url: https://en.wikipedia.org/wiki/Tenth_of_Tevet" MSG %"Tzom Tevet%" %! %b.

View File

@@ -1,6 +1,6 @@
# Support for the Catalan language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file was created by Eloi Torrents <eloitor@disroot.org>
TRANSLATE "LANGID" "ca"

View File

@@ -1,6 +1,6 @@
# Support for the Danish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Mogens Lynnerup.
TRANSLATE "LANGID" "da"

View File

@@ -1,6 +1,6 @@
# Support for the German language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Wolfgang Thronicke
TRANSLATE "LANGID" "de"
@@ -73,34 +73,8 @@ FSET - subst_p(alt, d, t) iif(d == today()+1, "", "en")
# Localization of various astronomical events
TRANSLATE "Perihelion" "Perihel"
TRANSLATE "Vernal Equinox" "Frühlingsanfang"
TRANSLATE "Summer Solstice" "Sommeranfang"
TRANSLATE "Aphelion" "Aphel"
TRANSLATE "Autumnal Equinox" "Herbstanfang"
TRANSLATE "Winter Solstice" "Winteranfang"
TRANSLATE "Daylight Saving Time Starts" "Beginn Sommerzeit"
TRANSLATE "Daylight Saving Time Ends" "Ende Sommerzeit"
TRANSLATE "New Moon" "Neumond"
TRANSLATE "First Quarter" "zunehmender Halbmond"
TRANSLATE "Full Moon" "Vollmond"
TRANSLATE "Last Quarter" "abnehmender Halbmond"
TRANSLATE "Chinese New Year" "Chinesisches Neujahr"
TRANSLATE "Snake" "Schlange"
TRANSLATE "Horse" "Pferd"
TRANSLATE "Goat" "Ziege"
TRANSLATE "Monkey" "Affe"
TRANSLATE "Rooster" "Hahn"
TRANSLATE "Dog" "Hund"
TRANSLATE "Pig" "Schwein"
TRANSLATE "Rat" "Ratte"
TRANSLATE "Ox" "Ochse"
TRANSLATE "Tiger" "Tiger"
TRANSLATE "Rabbit" "Kaninchen"
TRANSLATE "Dragon" "Drachen"
TRANSLATE "Sunrise" "Sonnenaufgang"
TRANSLATE "Sunset" "Sonnenuntergang"
TRANSLATE "No reminders." "Keine Termine."

View File

@@ -1,4 +1,4 @@
# Support for the English language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# Nothing to do for English since it is the default.

View File

@@ -1,6 +1,6 @@
# Support for the Spanish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Rafa Couto <rafacouto@biogate.com>
TRANSLATE "LANGID" "es"

View File

@@ -1,6 +1,6 @@
# Support for the Finnish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Mikko Silvonen
TRANSLATE "LANGID" "fi"

View File

@@ -1,6 +1,6 @@
# Support for the French language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Laurent Duperval
TRANSLATE "LANGID" "fr"

View File

@@ -1,6 +1,6 @@
# Support for the Hellenic (Greek) language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by jarlaxl lamat (jarlaxl@freemail.gr)
TRANSLATE "LANGID" "gr"

View File

@@ -1,6 +1,6 @@
# Support for the Icelanding language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Björn Davíðsson (bjossi@snerpa.is)
TRANSLATE "LANGID" "is"

View File

@@ -1,6 +1,6 @@
# Support for the Italian language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Valerio Aimale
TRANSLATE "LANGID" "it"

View File

@@ -1,6 +1,6 @@
# Support for the Dutch language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Willem Kasdorp and Erik-Jan Vens
TRANSLATE "LANGID" "nl"
@@ -65,33 +65,6 @@ FSET - subst_s(a, d, t) iif(day(d) == 1 || day(d) == 8, "e", day(d) < 20, "de",
FSET - ordx(n) n + "e"
TRANSLATE "New Moon" "Nieuwe maan"
TRANSLATE "First Quarter" "Eerste kwartier"
TRANSLATE "Full Moon" "Volle maan"
TRANSLATE "Last Quarter" "Laatste kwartier"
TRANSLATE "Vernal Equinox" "Lente-equinox"
TRANSLATE "Summer Solstice" "Zomerzonnewende"
TRANSLATE "Autumnal Equinox" "Herfst-equinox"
TRANSLATE "Winter Solstice" "Winterzonnewende"
TRANSLATE "Chinese New Year" "Chinees Nieuwjaar"
TRANSLATE "Snake" "Slang"
TRANSLATE "Horse" "Paard"
TRANSLATE "Goat" "Geit"
TRANSLATE "Monkey" "Aap"
TRANSLATE "Rooster" "Haan"
TRANSLATE "Dog" "Hond"
TRANSLATE "Pig" "Varken"
TRANSLATE "Rat" "Rat"
TRANSLATE "Ox" "Os"
TRANSLATE "Tiger" "Tijger"
TRANSLATE "Rabbit" "Konijn"
TRANSLATE "Dragon" "Draak"
TRANSLATE "Sunrise" "Zonsopgang"
TRANSLATE "Sunset" "Zonsondergang"
TRANSLATE "No reminders." "Geen herinneringen."
TRANSLATE "Daylight Saving Time Begins" "Daglicht-sparende tijd begint"

View File

@@ -1,6 +1,6 @@
# Support for the Norwegian language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Trygve Randen
TRANSLATE "LANGID" "no"

View File

@@ -1,6 +1,6 @@
# Support for the Polish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Jerzy Sobczyk
TRANSLATE "LANGID" "pl"

View File

@@ -1,6 +1,6 @@
# Support for the (Brazilian) Portuguese language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Marco Paganini
TRANSLATE "LANGID" "pt"

View File

@@ -1,6 +1,6 @@
# Support for the Romanian language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# REMIND is Copyright (C) 1992-2026 by Dianne Skoll
# This file is derived from a translation by Liviu Daia
TRANSLATE "LANGID" "ro"

View File

@@ -1,6 +1,11 @@
# Moon phases
# SPDX-License-Identifier: GPL-2.0-only
# Localize if we can
IF access($SysInclude + "/translations/" + _("LANGID") + "/moonphases.rem", "r") >= 0
SYSINCLUDE translations/[_("LANGID")]/moonphases.rem
ENDIF
IF $CalMode || $PsCal
REM [moondate(0)] INFO "Url: https://en.wikipedia.org/wiki/New_moon" SPECIAL MOON 0 -1 -1 [moontime(0)]
REM [moondate(1)] INFO "Url: https://en.wikipedia.org/wiki/Lunar_phase" SPECIAL MOON 1 -1 -1 [moontime(1)]

View File

@@ -1,6 +1,11 @@
# Equinoxes and solstices
# SPDX-License-Identifier: GPL-2.0-only
# Localize if we can
IF access($SysInclude + "/translations/" + _("LANGID") + "/seasons.rem", "r") >= 0
SYSINCLUDE translations/[_("LANGID")]/seasons.rem
ENDIF
IF $LatDeg >= 0
# Northern Hemisphere
REM NOQUEUE [soleq(0)] INFO "Url: https://en.wikipedia.org/wiki/March_equinox" MSG %"%(Vernal Equinox)%" [$Is] %3.

View File

@@ -1,7 +1,12 @@
# Sunrise and sunset
# SPDX-License-Identifier: GPL-2.0-only
IF !$CalMode && !$PsCal
REM NOQUEUE AT [sunrise()] MSG %"%"%(Sunrise) %! %2.
REM NOQUEUE AT [sunset()] MSG %"%"%(Sunset) %! %2.
# Localize if we can
IF access($SysInclude + "/translations/" + _("LANGID") + "/sun.rem", "r") >= 0
SYSINCLUDE translations/[_("LANGID")]/sun.rem
ENDIF
IF !$CalMode && !$PsCal
REM INFO "Url: https://en.wikipedia.org/wiki/Sunrise" NOQUEUE AT [sunrise()] MSG %"%"%(Sunrise) %! %2.
REM INFO "Url: https://en.wikipedia.org/wiki/Sunset" NOQUEUE AT [sunset()] MSG %"%"%(Sunset) %! %2.
ENDIF

View File

@@ -0,0 +1,17 @@
The files here contain additional translations for various files
distributed with Remind.
If you create a file in $SysInclude whose name is "myfile.rem", then
you can enable translation by putting this at the top of your
file:
#===================================================================
# Localize if we can
IF access($SysInclude + "/translations/" + _("LANGID") + "/myfile.rem", "r") >= 0
SYSINCLUDE translations/[_("LANGID")]/myfile.rem
ENDIF
#===================================================================
Then you can localize your file by putting appropriate TRANSLATION directives
in the file $SysInclude/translations/<LC>/myfile.rem where <LC> is the
two-character language code.

View File

@@ -0,0 +1,13 @@
TRANSLATE "Chinese New Year" "Chinesisches Neujahr"
TRANSLATE "Snake" "Schlange"
TRANSLATE "Horse" "Pferd"
TRANSLATE "Goat" "Ziege"
TRANSLATE "Monkey" "Affe"
TRANSLATE "Rooster" "Hahn"
TRANSLATE "Dog" "Hund"
TRANSLATE "Pig" "Schwein"
TRANSLATE "Rat" "Ratte"
TRANSLATE "Ox" "Ochse"
TRANSLATE "Tiger" "Tiger"
TRANSLATE "Rabbit" "Kaninchen"
TRANSLATE "Dragon" "Drachen"

View File

@@ -0,0 +1,4 @@
TRANSLATE "New Moon" "Neumond"
TRANSLATE "First Quarter" "zunehmender Halbmond"
TRANSLATE "Full Moon" "Vollmond"
TRANSLATE "Last Quarter" "abnehmender Halbmond"

View File

@@ -0,0 +1,4 @@
TRANSLATE "Vernal Equinox" "Frühlingsanfang"
TRANSLATE "Summer Solstice" "Sommeranfang"
TRANSLATE "Autumnal Equinox" "Herbstanfang"
TRANSLATE "Winter Solstice" "Winteranfang"

View File

@@ -0,0 +1,2 @@
TRANSLATE "Sunrise" "Sonnenaufgang"
TRANSLATE "Sunset" "Sonnenuntergang"

View File

@@ -0,0 +1,13 @@
TRANSLATE "Chinese New Year" "Chinees Nieuwjaar"
TRANSLATE "Snake" "Slang"
TRANSLATE "Horse" "Paard"
TRANSLATE "Goat" "Geit"
TRANSLATE "Monkey" "Aap"
TRANSLATE "Rooster" "Haan"
TRANSLATE "Dog" "Hond"
TRANSLATE "Pig" "Varken"
TRANSLATE "Rat" "Rat"
TRANSLATE "Ox" "Os"
TRANSLATE "Tiger" "Tijger"
TRANSLATE "Rabbit" "Konijn"
TRANSLATE "Dragon" "Draak"

View File

@@ -0,0 +1,4 @@
TRANSLATE "New Moon" "Nieuwe maan"
TRANSLATE "First Quarter" "Eerste kwartier"
TRANSLATE "Full Moon" "Volle maan"
TRANSLATE "Last Quarter" "Laatste kwartier"

View File

@@ -0,0 +1,4 @@
TRANSLATE "Vernal Equinox" "Lente-equinox"
TRANSLATE "Summer Solstice" "Zomerzonnewende"
TRANSLATE "Autumnal Equinox" "Herfst-equinox"
TRANSLATE "Winter Solstice" "Winterzonnewende"

View File

@@ -0,0 +1,2 @@
TRANSLATE "Sunrise" "Zonsopgang"
TRANSLATE "Sunset" "Zonsondergang"

View File

@@ -21,6 +21,9 @@ render characters outside the ASCII character set, see
.SH OPTIONS
.TP
.B \-\-version
Print the version of \fBrem2ps\fR and exit.
.TP
.B \-v
Be more verbose. This causes \fBrem2ps\fR to print progress messages
to the standard error stream. Normally, it is silent.

View File

@@ -102,6 +102,10 @@ flag also enables the use of the UNICODE "left-to-right" mark that
can fix up formatting problems with right-to-left languages in the calendar
display.
.TP
.B 'z'
has the effect of setting the system variable \fB$TerminalHyperlinks\fR
to 1. See the documentation of this variable in the section "SYSTEM VARIABLES"
.TP
.B 'c'
causes \fBRemind\fR to use VT100 escape sequences to approximate
SPECIAL COLOR reminders. Note that this flag is kept for
@@ -161,7 +165,7 @@ foreground color of a reminder and the background color of a cell,
then you know what you are doing.
.RE
.TP
.B \-w\fR\fIcol\fR[,\fIpad\fR[,\fIspc\fR]]]
.B \-w\fR\fIcol\fR[,\fIpad\fR[,\fIspc\fR[,\fIspc2\fR]]]]
The \fB\-w\fR option specifies the output width, padding and spacing
of the formatted calendar output. \fICol\fR specifies the number of
columns in the output device. If \fIcol\fR is not specified, or is
@@ -192,7 +196,9 @@ have many reminders on certain days that make your calendar too large
to fit on a page, you can try reducing \fIpad\fR to make the empty
boxes smaller. \fISpc\fR specifies how many blank lines to leave
between the day number and the first reminder entry. It defaults to
1.
1. \fIspc2\fR may be 0 or 1 and it specifies whether or not blank
lines should be printed in between reminders on the same day. The
default is 1, which causes the blank lines to be printed.
.PP
Any of \fIcol\fR, \fIpad\fR or \fIspc\fR can be omitted, providing you
provide the correct number of commas. Don't use any spaces in the option.
@@ -343,6 +349,10 @@ Echo lines when displaying error messages
.B f
Trace the reading of reminder files
.TP
.B p
Issue warnings if a POP-OMIT-CONTEXT, POP-VARS or POP-FUNCS matches
a corresponding PUSH that is in a different file.
.TP
.B s
Trace expression parsing and display the internal expression node
tree. This is unlikely to be useful unless you are working on
@@ -1354,7 +1364,7 @@ minutes. That is, 13:39 and 13.39 are equivalent.
for a timed reminder is the same as the current system date, the
reminder is queued for later activation. When \fBRemind\fR has
finished processing the reminder file, it puts itself in the
background, and activates timed reminders when the system time reached
background, and activates timed reminders when the system time reaches
the specified time. Note that if you use the \fBNOQUEUE\fR modifier
in the \fBREM\fR command, then this queuing and background activation
is \fInot\fR performed. \fBNOQUEUE\fR is useful if you want a time
@@ -1485,6 +1495,15 @@ and description of a reminder like this:
MSG Engineering meeting
.fi
.PP
While back-ends can choose which INFO strings to support, all back-ends
should endeavor to support three standard ones: \fBLocation:\fR,
\fBDescription:\fR and \fBUrl:\fR. TkRemind supports all three of these,
turning reminders with a \fBUrl:\fR INFO string into hyper-links, and
popping up information windows for the \fBLocation:\fR and \fBDescription:\fR
INFO strings. \fBLocation:\fR and \fBUrl:\fR are self-explanatory;
\fBDescription:\fR is meant for a longer, more in-depth description
of the reminder than the summary that is normally displayed.
.PP
The \fBDURATION\fR keyword makes sense only for timed reminders; it
specifies the duration of an event. For example, if you have a
90-minute meeting starting at 1:00pm, you could use any of the following:
@@ -1980,6 +1999,7 @@ 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.
The keyword COMPLETED-THROUGH may be used as a synonym for COMPLETE-THROUGH.
.PP
.SH LIMITING REMINDERS ABOUT OVERDUE TODOS
.PP
@@ -2572,16 +2592,13 @@ a sequence of more than one byte. For example, in a UTF-8 environment,
the string "🙂" contains one character but four bytes. And the string
"één" contains three characters but five bytes.
.PP
\fBRemind\fR has a set of functions
that work on \fIbytes\fR, namely \fBindex\fR, \fBstrlen\fR and \fBsubstr\fR.
These are not safe to use on multi-byte strings; instead use
\fBmbindex\fR, \fBmbstrlen\fR and \fBmbsubstr\fR. If you know \fIfor sure\fR
that a string contains only single-byte characters, then the byte-oriented
versions may be used and are faster than the multi-byte versions.
.PP
Some ancient or embedded systems may lack the C library functions needed
to deal with multi-byte strings. In that case, the \fBmb\fIxxx\fR functions
all return an error.
\fBRemind\fR has a set of functions that work on \fIbytes\fR, namely
\fBindex\fR, \fBstrlen\fR and \fBsubstr\fR, and several more. These
are not safe to use on multi-byte strings; instead use \fBmbindex\fR,
\fBmbstrlen\fR and \fBmbsubstr\fR, and the \fBmb\fR variants of the
others. If you know \fIfor sure\fR that a string contains only
single-byte characters, then the byte-oriented versions may be used
and are faster than the multi-byte versions.
.RE
.TP
.B TIME
@@ -2622,7 +2639,7 @@ The following examples illustrate constants in \fBRemind\fR expressions:
12, 36, \-10, 0, 1209, 0x1F, 0xfe00 (the last two demonstrate the use of hexadecimal constants)
.TP
.B STRING constants
"Hello there", "This is a test", "\\nHello\\tThere", ""
"Hello there", "This is a test", "\\nHello\\tThere", "", "π is Cool! 🙂"
.PP
.RS
Note that the empty string is represented by "". \fBRemind\fR supports
@@ -3243,7 +3260,7 @@ near the beginning of the file and not change it after that.
.TP
.B $MaxSatIter
The maximum number of iterations for the \fBSATISFY\fR clause
(described later.) Must be at least 10.
(described later.) Must be at least 10. The default value is 10,000.
.TP
.B $MaxStringLen
A limit on the longest string that \fBRemind\fR will allow you
@@ -3345,6 +3362,30 @@ If non-zero, then the \fB\-p\fR option was supplied on the command line.
.B $RunOff (read-only)
If non-zero, the \fBRUN\fR directives are disabled.
.TP
.B $Shaded (read-only)
Returns the number of times a \fBSHADE\fR special reminder has triggered.
\fIThis variable is set only in calendar mode, not agenda mode\fR. You
can use this variable to avoid shading a calendar day that has already
been shaded.
.RS
.PP
For example, suppose you want to shade all calendar boxes yellow
\fIif\fR any reminders have triggered on that day. But if a box has
been explicitly shaded, you don't want to overwrite that shading.
You could use something like this:
.PP
.nf
SET n $NumTrig
# Do all your reminders here...
# If anything has triggered and the box is
# not already shaded, then shade it yellow
IF $NumTrig > n && !$Shaded
REM SPECIAL SHADE 255 255 128
ENDIF
.fi
.RE
.TP
.B $SimpleCal (read-only)
Set to a non-zero value if \fIeither\fR of the \fB\-p\fR or \fB\-s\fR
command-line options was supplied.
@@ -3472,6 +3513,13 @@ to be "dark" if the average of the red, green and blue components is
at most 85 out of 255, and if the maximum of any component is at most
128 out of 255.
.TP
.B $TerminalHyperlinks (INT type)
If your terminal supports escape sequences to allow HTML-like
anchors around text (see https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda), then you can set this variable to 1. \fBRemind\fR will then
make any reminder with a "Url:" info string into a hyperlink in your
terminal. By default, \fB$TerminalHyperlinks\fR is set to 1 if \fBRemind\fR's
standard output is a terminal, or to 0 if it is not.
.TP
.B $WarningLevel (STRING type)
As new versions of \fBRemind\fR are released, new warnings may be added.
If your formerly-fine scripts suddenly start issuing warnings when you
@@ -3833,9 +3881,10 @@ integer.
.TP
.B columns([s_arg])
If called with no arguments, \fBcolumns()\fR behaves as follows:
If standard output is a TTY, returns the width of the terminal in columns.
If standard output is not a TTY, attempts to open "/dev/tty" to obtain
the terminal size. If this fails, returns -1.
If either standard output or standard error is a TTY, returns the
width of the terminal in columns. If neither standard output nor
standard error is a TTY, attempts to open "/dev/tty" to obtain the
terminal size. If this fails, returns -1.
.RS
.PP
If called with a single string argument, \fBcolumns(str)\fR returns
@@ -4127,10 +4176,10 @@ Returns an \fBINT\fR that is the location of \fItarget\fR in the
string \fIsearch\fR. Note that \fBindex\fR uses \fIbyte\fR positions,
not character positions, so should not be used on non-ASCII strings. Use
\fBmbindex\fR for non-ASCII strings.
.RS
.PP
The first byte of a string is numbered 1. If \fItarget\fR does not
exist in \fIsearch\fR, then 0 is returned.
.RS
.PP
The optional parameter \fIstart\fR specifies the position in
\fIsearch\fR at which to start looking for \fItarget\fR.
@@ -4199,8 +4248,15 @@ Given a \fBDATETIME\fR object interpreted in the local time zone, return
a \fBDATETIME\fR object that expresses the same time in UTC.
.TP
.B lower(s_string)
Returns a \fBSTRING\fR with all upper-case bytes in \fIstring\fR
converted to lower-case. \fBNote:\fR This function works correctly
only for ASCII strings. If you are using Unicode characters outside
the ASCII set, use \fBmblower\fR instead.
.TP
.B mblower(s_string)
Returns a \fBSTRING\fR with all upper-case characters in \fIstring\fR
converted to lower-case.
converted to lower-case. This function works correctly on any
Unicode string.
.TP
.B max(x_arg1 [,x_arg2...)
Can take any number of arguments, and returns the maximum. The arguments
@@ -4483,7 +4539,8 @@ to be considered \fInon-constant\fR. For details, see the section
.TP
.B now()
Returns the current system time, as a \fBTIME\fR type. This may be
the actual time, or a time supplied on the command line.
the actual time, or a time supplied on the command line. Note that
in Calendar Mode, \fBnow()\fR always returns 00:00.
.TP
.B ord(i_num)
Returns a string that is the ordinal number \fInum\fR. For example,
@@ -4514,8 +4571,8 @@ any longer.
.TP
.B pad(x_arg, s_padstr, i_len [, i_right])
Converts the first argument \fIarg\fR to a string if necessary, and
then if it is shorter than \fIlen\fR characters, pads to to
\fIlen\fR characters using as many copies (including partial copies)
then if it is shorter than \fIlen\fR bytes, pads to to
\fIlen\fR bytes using as many copies (including partial copies)
of \fIpadstr\fR as necessary. By default, the string is left-padded,
but if \fIright\fR is supplied and non-zero, the string will
be right-padded.
@@ -4532,6 +4589,11 @@ Here are some examples:
.fi
.RE
.TP
.B mbpad(x_arg, s_padstr, i_len [, i_right])
This is the multibyte counterpart to \fBpad\fR. The length is
specified in characters rather than bytes. Use \fBmbpad\fR rather
than \fBpad\fR if either of the strings contains non-ASCII characters.
.TP
.B plural(i_num [,s_str1 [,s_str2]])
Can take from one to three arguments. If one argument is supplied, returns
@@ -4610,7 +4672,7 @@ may return a time supplied on the command line.
.B realnow()
Returns the true time of day as provided by the operating system.
This is in contrast to \fBnow()\fR, which may return a time supplied
on the command line.
on the command line, or 00:00 in Calendar Mode.
.TP
.B realtoday()
Returns the date as provided by the operating system. This is in contrast to
@@ -4618,9 +4680,10 @@ Returns the date as provided by the operating system. This is in contrast to
in calendar mode, or if a date has been supplied on the command line.
.TP
.B rows()
If standard output is a TTY, returns the height of the terminal in rows.
If standard output is not a TTY, attempts to open "/dev/tty" to obtain
the terminal size. If this fails, returns -1.
If either standard output or standard error is a TTY, returns the
height of the terminal in rows. If neither standard output nor
standard error is a TTY, attempts to open "/dev/tty" to obtain the
terminal size. If this fails, returns -1.
.TP
.B sgn(i_num)
Returns \-1 if \fInum\fR is negative, 1 if \fInum\fR is positive,
@@ -4808,9 +4871,9 @@ value of \fBcurrent()\fR. If a \fBDATE\fR rather than \fBDATETIME\fR
is supplied, \fBRemind\fR uses a time part of 00:00.
.TP
.B today()
Returns \fBRemind\fR's notion of "today." This may be the actual system
date, or a date supplied on the command line, or the date of the
calendar entry currently being computed.
Returns \fBRemind\fR's notion of "today." This may be the actual
system date, or a date supplied on the command line, or (in Calendar
Mode) the date of the calendar entry currently being computed.
.TP
.B trig(s_1 [,s_2, ...])
For each string argument s_\fIn\fR, \fBtrig\fR evaluates s_\fIn\fR
@@ -5102,8 +5165,15 @@ of the time zone name.
.PP
.TP
.B upper(s_string)
Returns a \fBSTRING\fR with all lower-case bytes in \fIstring\fR
converted to upper-case. \fBNote:\fR This function works correctly
only for ASCII strings. If you are using Unicode characters outside
the ASCII set, use \fBmbupper\fR instead.
.TP
.B mbupper(s_string)
Returns a \fBSTRING\fR with all lower-case characters in \fIstring\fR
converted to upper-case.
converted to upper-case. This function works correctly on any
Unicode string.
.TP
.B utctolocal(q_datetime)
Given a \fBDATETIME\fR object interpreted in UTC, return a
@@ -6904,14 +6974,43 @@ jahrzeits (anniversaries of deaths) and smachot (joyous occasions.)
.PP
.B THE HEBREW YEAR
.PP
The Hebrew year has 12 months, alternately 30 and 29 days long. The months
are: Tishrey, Heshvan, Kislev, Tevet, Shvat, Adar, Nisan, Iyar, Sivan, Tamuz,
Av and Elul. In Biblical times, the year started in Nisan, but Rosh Hashana
(Jewish New Year) is now celebrated on the 1st and 2nd of Tishrey.
The Hebrew year has 12 months, alternately 30 and 29 days long. The
months are: Tishrey, Heshvan, Kislev, Tevet, Shvat, Adar, Nisan, Iyar,
Sivan, Tamuz, Av and Elul. If you are in a UTF-8 locale, you can
\fIalso\fR use the UTF-8-encoded Hebrew spellings for the month names,
namely:
.PP
תשרי, חשוון, כסלו, טבת, שבט, אדר, ניסן, אייר, סיון, תמוז, אב, אלול.
.PP
In a cycle of 19 years, there are 7 leap years, being years 3, 6, 8, 11,
14, 17 and 19 of the cycle. In a leap year, an extra month of 30 days
is added before Adar. The two Adars are called Adar A and Adar B.
is added before Adar. The two Adars are called Adar A and Adar B,
or in Hebrew, 'אדר א and 'אדר ב.
.PP
\fBRemind\fR also permits the following alternative spellings for
Hebrew month names:
.TP
.B Tishrey
Can also be spelled Tishri or Tishrei
.TP
.B Heshvan
Can also be spelled Cheshvan or Kheshvan
.TP
.B Shvat
Can also be spelled Shevat
.TP
.B Tamuz
Can also be spelled Tammuz
.TP
.B Adar A
Can also be spelled Adar 1, Adar I, אדר א or אדר 1.
.TP
.B Adar B
Can also be spelled Adar 2, Adar II, אדר ב or אדר 2.
.TP
.B Iyar
Can also be spelled Iyyar.
.PP
For certain religious reasons, the year cannot start on a Sunday, Wednesday
or Friday. To adjust for this, a day is taken off Kislev or added to Heshvan.
@@ -6941,6 +7040,11 @@ Thus, hebday('1993/04/12') returns 21.
Returns the name of the Hebrew month corresponding to \fIdate\fR.
For example, hebmon('1993/04/12') returns "Nisan".
.TP
.B ivritmon(d_date)
Returns the name of the Hebrew month corresponding to \fIdate\fR,
in UTF-8-encoded Hebrew script. For example, ivritmon('1993/04/12')
returns "ניסן".
.TP
.B hebyear(d_date)
Returns the Hebrew year corresponding to \fIdate\fR. For example,
hebyear('1993/04/12') returns 5753.
@@ -6954,7 +7058,8 @@ corresponding to the Hebrew date.
The \fIday\fR parameter can range from 1 to 30, and specifies the day of
the Hebrew month. The \fIhebmon\fR parameter is a string that must name
one of the Hebrew months specified above. Note that the month must be spelled
out in full, and use the English transliteration shown previously. You can
out in full, and use either the English transliteration shown previously, or
the Hebrew spelling \fIencoded in UTF-8\fR. You can
also specify "Adar A" and "Adar B." Month names are not case-sensitive.
.PP
The \fIyrstart\fR parameter can either be a \fBDATE\fR or an \fBINT\fR. If

View File

@@ -18,10 +18,12 @@ binary. If you are using Tcl/Tk 8.5, you may also need either the Img
or the tkpng extension to handle PNG images.
.SH COMMAND-LINE OPTIONS
\fBTkRemind\fR itself has no command-line options. However, it passes
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.
\fBTkRemind\fR itself has only one command-line option:
\fB\-\-version\fR, which makes it print the version of \fBTkRemind\fR
and exit. Any other 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
@@ -61,15 +63,17 @@ box appears completely full.
.SH NAVIGATING
To change to the previous or next month, click the \fB<\-\fR
or \fB\->\fR button, respectively. You can also use the left/right arrow
keys or PgUp/PgDn to navigate.
keys or \fBPgUp\fR/\fBPgDn\fR to navigate.
To change back to the current month, click \fBToday\fR or press the
Home key. To go to a specific month, click \fBGo To Date...\fR. This
pops up a dialog box which allows you to select a month and enter a
year. Once you've done this, click \fBGo\fR to go to the date, or
\fBCancel\fR to cancel.
\fBHome\fR key. To go to a specific month, click \fBGo To Date...\fR
or press \fBg\fR. This pops up a dialog box which allows you to
select a month and enter a year. Once you've done this, click
\fBGo\fR to go to the date, or \fBCancel\fR to cancel. Note also that
all pop-up windows in \fBTkRemind\fR can be dismissed by pressing
\fBEsc\fR or \fBControl-w\fR.
To exit \fBTkRemind\fR, click \fBQuit\fR.
To exit \fBTkRemind\fR, click \fBQuit\fR or press \fBControl-q\fR..
.SH CHANGING THE VIEW
By default, \fBTkRemind\fR shows the calendar for an entire month.
@@ -151,21 +155,25 @@ You will have to hand-edit it to change it.
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 calendar window
to see today's reminders in Agenda Mode.
to see today's reminders in Agenda Mode. You can also press \fBt\fR
over the main calendar 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. You can
also navigate in the Agenda Mode window one day at a time using the
forward and back arrow buttons or left/right arrow keys or PgUp/PgDn.
forward and back arrow buttons or left/right arrow keys or \fBPgUp\fR/\fBPgDn\fR.
You can get back to today by clicking \fBToday\fR or pressing the
Home key.
\fBHome\fR key.
You can dismiss the Agenda Mode window by clicking \fBOK\fR or pressing
the \fBEsc\fR key.
.SH PRINTING
To print the current month's calendar, click \fBPrint...\fR on the
main calendar window. This brings up the print dialog. Printing
either produces a PostScript or PDF file, or sends PostScript or PDF
to a UNIX command.
main calendar window or press \fBp\fR or \fBControl-p\fR. This brings
up the print dialog. Printing either produces a PostScript or PDF
file, or sends PostScript or PDF to a UNIX command.
Note that you must have \fBrem2pdf\fR installed in order to be
able to print.
@@ -259,7 +267,8 @@ option of "turning off" the reminder for the rest of the day.
.SH OPTIONS
The final button on the calendar window, \fBOptions\fR, lets you configure
certain aspects of \fBTkRemind\fR. The configuration options are:
certain aspects of \fBTkRemind\fR. You can also pop up the options
window by pressing \fBo\fR. The configuration options are:
.TP
.B Start up Iconified
@@ -352,22 +361,6 @@ press \fBApply Options\fR to put them into effect, \fBSave Options\fR
to put them into effect and save them in $HOME/.config/tkremindrc, or
\fBCancel\fR to cancel any changes you made.
.SH KEYBOARD SHORTCUTS
\fBTkRemind\fR's main window includes the following keyboard shortcuts:
.TP
.B Ctrl-Q
Quit
.TP
.B Left Arrow
Previous Month
.TP
.B Right Arrow
Next Month
.TP
.B Home
Today
.SH IMMEDIATE UPDATES
If you are running \fBTkRemind\fR on Linux and \fBRemind\fR has been
@@ -571,7 +564,7 @@ asynchronous status messages.
.SH AUTHOR
TkRemind was written by Dianne Skoll <dianne@skoll.ca>
\fBTkRemind\fR is Copyright (C) 1996-2025 by Dianne Skoll.
\fBTkRemind\fR is Copyright (C) 1996-2026 by Dianne Skoll.
.SH FILES

View File

@@ -96,6 +96,14 @@ without any E<lt>htmlE<gt> or E<lt>bodyE<gt> tags.
Use I<title> as the content between E<lt>titleE<gt> and E<lt>/titleE<gt>
tags.
=item --yaag
Instead of making 7-column tables for each month, show each month
as a I<single> table row of 38 columns. This is the so-called
"year-at-a-glance" format. You must use the "-ppp" option to
C<remind> or the --yaag option will be ignored. And this format
works best if you create a calendar for an entire year (so, starting
in January and using "-ppp12" to get 12 months' worth of reminders.)
=item --prologue I<html_text>
@@ -188,6 +196,7 @@ Options:
--title string What to put in <title>...</title> tags
--prologue html_text Text to insert at the top of the body
--epilogue html_text Text to insert at the end of the body
--yaag Output one month per row for year-at-a-glance format
EOM
exit($exit_status);
}
@@ -218,6 +227,7 @@ sub parse_options
"man",
"utf8",
"pngs",
"yaag",
"version",
"stylesheet=s",
"nostyle",
@@ -316,6 +326,10 @@ sub parse_input
if ($_ eq '[') {
return parse_input_ppp();
}
if ($Options{yaag}) {
$Options{yaag} = 0;
print STDERR "Ignoring option --yaag: You must use remind -ppp for this option\n";
}
if (/# translations/) {
slurp_translations();
next;
@@ -472,6 +486,10 @@ sub parse_input_ppp
}
if (exists($array->[0]{caltype}) &&
$array->[0]{caltype} eq 'weekly') {
if ($Options{yaag}) {
$Options{yaag} = 0;
print STDERR "Ignoring option --yaag for a weekly calendar\n";
}
emit_ppp_calendars($array, 'weekly');
} else {
emit_ppp_calendars($array, 'monthly');
@@ -488,11 +506,51 @@ sub parse_input_ppp
}
}
sub print_yaag_weekday_row
{
my ($cal) = @_;
print "<tr class=\"rem-yaag-weekday-row\">";
print "<th class=\"rem-yaag-empty-header\">&nbsp;</th>";
my $ex;
for (my $i=0; $i<37; $i++) {
my $day;
if ($cal->{mondayfirst}) {
$day = $cal->{daynames}->[($i+1) % 7];
} else {
$day = $cal->{daynames}->[$i % 7];
}
if (($i % 7) == 6) {
$ex = " rem-yaag-end-of-week";
} else {
$ex = "";
}
print "<th class=\"rem-yaag-weekday-header$ex\">$day</th>";
}
print "</tr>\n";
}
sub emit_ppp_calendars
{
my ($array, $type) = @_;
my $prev_year = 0;
my $done_one = 0;
foreach my $cal (@$array) {
if ($Options{yaag}) {
if ($cal->{year} != $prev_year) {
$prev_year = $cal->{year};
if ($done_one) {
print "</table>\n";
}
print "<span class=\"year_heading\">$prev_year</span>\n";
print "<table class=\"rem-yaag\">\n";
print_yaag_weekday_row($cal);
}
}
emit_one_ppp_calendar($cal, $type);
$done_one = 1;
}
if ($done_one) {
print "</table>\n";
}
}
@@ -766,42 +824,79 @@ sub output_calendar
# Start the table
my $class;
if ($Options{nostyle}) {
print '<table width="100%" border="1" cellspacing=\"0\"><caption>' .
$Month . ' ' . $Year . '</caption>' . "\n";
print '<tr>';
$class = ' width="14%"';
} else {
if ($type eq 'monthly') {
print '<table class="rem-cal"><caption class="rem-cal-caption">' .
$Month . ' ' . $Year . '</caption>' . "\n";
if (!$Options{yaag}) {
if ($Options{nostyle}) {
print '<table width="100%" border="1" cellspacing="0">';
if ($type eq 'monthly') {
print "<caption>$Month $Year </caption>";
}
print "\n<tr>";
$class = ' width="14%"';
} else {
print '<table class="rem-cal">' . "\n";
if ($type eq 'monthly') {
print '<table class="rem-cal"><caption class="rem-cal-caption">' .
$Month . ' ' . $Year . '</caption>' . "\n";
} else {
print '<table class="rem-cal">' . "\n";
}
print '<tr class="rem-cal-hdr-row">';
$class = ' class="rem-cal-hdr"';
}
print '<tr class="rem-cal-hdr-row">';
$class = ' class="rem-cal-hdr"';
}
if ($type eq 'monthly') {
if (!$Mondayfirst) {
print "<th$class>" . $Daynames[0] . '</th>';
if ($type eq 'monthly') {
if (!$Mondayfirst) {
print "<th$class>" . $Daynames[0] . '</th>';
}
for (my $i=1; $i<7; $i++) {
print "<th$class>" . $Daynames[$i] . '</th>';
}
if ($Mondayfirst) {
print "<th$class>" . $Daynames[0] . '</th>';
}
} else {
for (my $i=0; $i<7; $i++) {
my $inf = $date_info->[$i];
print "<th$class>" . $inf->{dayname} . "<br>" .
$inf->{day} . '&nbsp;' .
$inf->{month} . '&nbsp;' .
$inf->{year} . '</th>';
}
}
for (my $i=1; $i<7; $i++) {
print "<th$class>" . $Daynames[$i] . '</th>';
}
if ($Mondayfirst) {
print "<th$class>" . $Daynames[0] . '</th>';
}
} else {
for (my $i=0; $i<7; $i++) {
my $inf = $date_info->[$i];
print "<th$class>" . $inf->{dayname} . "<br>" .
$inf->{day} . '&nbsp;' .
$inf->{month} . '&nbsp;' .
$inf->{year} . '</th>';
}
}
print "</tr>\n";
print "</tr>\n";
} else {
# For year-at-a-glance calendar, it's just a row
print '<tr class="rem-yaag-cal-row">';
print '<th class="rem-yaag-cal-hdr">' . $Month . "</th>\n";
my $cells_drawn = 0;
# Print the blank ones
for (my $i=0; $i<$first_col; $i++) {
print "<td class=\"rem-yaag-cal-blank\">&nbsp;</td>";
$cells_drawn++;
}
# All the entries
for (my $day=1; $day <= $Numdays; $day++) {
if (($cells_drawn % 7) == 6) {
draw_day_cell($day, 1, $type, ' rem-yaag-end-of-week');
} else {
draw_day_cell($day, 1, $type);
}
$cells_drawn++;
}
# And fill in the remaining ones
while ($cells_drawn < 37) {
if (($cells_drawn % 7) == 6) {
print "<td class=\"rem-yaag-cal-blank rem-yaag-end-of-week\">&nbsp;</td>";
} else {
print "<td class=\"rem-yaag-cal-blank\">&nbsp;</td>";
}
$cells_drawn++;
}
print "</tr>\n";
return;
}
# Start the calendar rows
my $col = 0;
if ($Options{nostyle}) {
@@ -895,9 +990,10 @@ sub output_calendar
sub draw_day_cell
{
my($day, $number_of_rows, $type) = @_;
my($day, $number_of_rows, $type, $extra_class) = @_;
my $shade = $shades->[$day];
my $week = '';
$extra_class = '' unless defined($extra_class);
if (exists($weeks->{$day})) {
if ($weeks->{$day}->{url}) {
$week = ' <a href="' . $weeks->{$day}->{url} . '">' . escape_html($weeks->{$day}->{body}) . '</a>';
@@ -905,19 +1001,22 @@ sub draw_day_cell
$week = ' ' . escape_html($weeks->{$day}->{body});
}
}
my $class;
if ($Options{nostyle}) {
$class = $classes->[$day] || '';
} else {
$class = $classes->[$day] || "rem-cell rem-cell-$number_of_rows-rows";
my $class = $classes->[$day] || '';
if (!$Options{nostyle}) {
$class .= ' ' if $class ne '';
if ($Options{yaag}) {
$class .= "rem-yaag-cell"
} else {
$class .= "rem-cell rem-cell-$number_of_rows-rows";
}
}
if ($shade) {
$shade = " style=\"background: $shade;\"";
} else {
$shade = "";
}
if ($class ne '') {
print "<td class=\"$class\"$shade>\n";
if ($class ne '' || $extra_class ne '') {
print "<td class=\"$class$extra_class\"$shade>\n";
} else {
print "<td valign=\"top\" $shade>\n";
}
@@ -982,7 +1081,11 @@ sub draw_day_cell
print "<div style=\"float: right\">$day$week</div>\n";
print "<p>&nbsp;</p>\n";
} else {
print "<div class=\"rem-daynumber\">$day$week</div>\n";
if ($Options{yaag}) {
print "<div class=\"rem-yaag-daynumber\">$day$week</div>\n";
} else {
print "<div class=\"rem-daynumber\">$day$week</div>\n";
}
}
} else {
if ($Options{nostyle}) {
@@ -1016,7 +1119,7 @@ if ($Options{help}) {
system("perldoc $0");
exit(0);
} elsif ($Options{version}) {
print "rem2html version $rem2html_version.\n";
print "rem2html version $rem2html_version\n";
exit(0);
}
@@ -1048,6 +1151,11 @@ table.rem-cal {
font-size: 12pt;
}
span.year_heading {
font-family: helvetica, arial, sans-serif;
font-size: 28pt;
}
table.rem-sc-table {
font-family: helvetica, arial, sans-serif;
font-size: 10pt;
@@ -1073,14 +1181,6 @@ td.rem-empty, td.rem-cell, td.rem-small-calendar {
border-width: 1px;
vertical-align: top;
}
td.rem-today {
width: 14%;
height: 7em;
border-style: solid;
border-width: 2px;
border-color: #EE3333;
vertical-align: top;
}
table.rem-cal {
width: 100%;
@@ -1116,5 +1216,84 @@ td.rem-sc-empty-cell, td.rem-sc-cell {
caption.rem-sc-caption {
font-size: 12pt;
}
table.rem-yaag {
font-family: helvetica, arial, sans-serif;
font-size: 8pt;
table-layout: fixed;
cellspacing: 0;
border-collapse: collapse;
}
td.rem-yaag-cell {
height: 7em;
border-style: solid;
border-color: #adadad;
border-width: 1px;
vertical-align: top;
}
th.rem-yaag-weekday-header {
font-weight: 100;
font-size: 9pt;
padding: 6px 0 0 6px;
text-align:left;
border-style: solid;
border-color: #adadad;
border-width: 1px;
vertical-align: top;
}
td.rem-yaag-cal-blank {
height: 7em;
border-style: solid;
border-width: 1px;
border-color: #adadad;
background-color: #d5d6d5;
vertical-align: top;
}
td.rem-yaag-end-of-week {
border-right-width: 3;
}
th.rem-yaag-end-of-week {
border-right-width: 3;
}
th.rem-yaag-cal-hdr {
text-align: right;
padding-top: 8px;
padding-right: 5px;
font-weight: 100;
font-size: 9pt;
border-style: solid;
border-color: #adadad;
border-width: 1px;
vertical-align: top;
}
div.rem-yaag-daynumber {
float: right;
text-align: right;
vertical-align: top;
font-size: 10pt;
}
tr.rem-yaag-cal-row:nth-child(3n+1) {
border-bottom: 3px solid #000;
}
.rem-yaag-weekday-row .rem-yaag-empty-header {
height: 20pt;
width: 70px !important;
}
td.rem-today {
border-style: solid;
border-width: 2px;
border-color: #EE3333;
}
EOF
}

View File

@@ -31,6 +31,7 @@ my $media_to_size = {
};
my $help = 0;
my $version = 0;
my $settings = {
landscape => 0,
@@ -51,7 +52,7 @@ my $settings = {
title_url => '',
title_size => 14,
header_size => 12,
daynum_size => 14,
daynum_size => -1,
entry_size => 8,
border_size => 4,
@@ -126,6 +127,7 @@ Options:
--title-url=URL Link calendar title to URL
--verbose, -v Print progress messages
--help Display this help
--version Print version and exit
EOF
}
@@ -166,6 +168,7 @@ my $ret = GetOptions('landscape|l' => \$settings->{landscape},
'header-color=s' => \$settings->{header_color},
'daynum-color=s' => \$settings->{daynum_color},
'smallcal-color=s' => \$settings->{smallcal_color},
'version' => \$version,
'help' => \$help
);
if (!$ret) {
@@ -178,6 +181,11 @@ if ($help) {
exit(0);
}
if ($version) {
print "rem2pdf version $VERSION\n";
exit(0);
}
my $bad = 0;
foreach my $setting (qw(bg_color line_color title_color header_color daynum_color smallcal_color)) {
my $c = $settings->{$setting};
@@ -526,7 +534,9 @@ Specify the size of the header font in 1/72ndths of an inch. The default is 14.
=item --daynum-size=I<n>
Specify the size of the day number font in 1/72ndths of an inch. The
default is 14.
default is 14 for monthly calendars or 10 for weekly calendars. (Weekly
calendars don't have day numbers in the calendar boxes, but this setting
is used to scale the size of moon phase indicators.)
=item --entry-size=I<n>
@@ -618,6 +628,14 @@ to print per page; it is an integer that can range from 1 to 4.
Print (on STDERR) the name of the month and year for each month that
is rendered.
=item --version
Print the version of rem2pdf and exit.
=item --help
Print a brief summary of rem2pdf usage.
=back
=head1 USAGE

View File

@@ -468,6 +468,9 @@ sub render
{
my ($self, $cr, $settings, $index, $total) = @_;
if ($settings->{daynum_size} < 0) {
$settings->{daynum_size} = 14;
}
if ($settings->{svg} || $settings->{eps}) {
if ($index > 1) {
if ($index == 2) {
@@ -1111,6 +1114,9 @@ Remind::PDF::Weekly - render a weekly calendar
sub render
{
my ($self, $cr, $settings, $index, $total) = @_;
if ($settings->{daynum_size} < 0) {
$settings->{daynum_size} = 10;
}
if ($settings->{svg} || $settings->{eps}) {
if ($index > $settings->{weeks_per_page}) {
if ($index == $settings->{weeks_per_page}+1) {
@@ -1130,7 +1136,7 @@ sub render
}
}
$settings->{numbers_on_left} = 1;
$settings->{numbers_on_left} = 0;
# Set up bounding box
if ($settings->{weeks_per_page} == 1) {
$self->{bounding_box} = [
@@ -1139,22 +1145,16 @@ sub render
$settings->{width} - $settings->{margin_right},
$settings->{height} - $settings->{margin_bottom}]
} else {
my $gap = $settings->{margin_top} * 0.5;
my $total_height = $settings->{height} - $settings->{margin_top} - $settings->{margin_bottom};
my $week_height = $total_height / $settings->{weeks_per_page};
my $top_offset = (($index-1) % $settings->{weeks_per_page}) * $week_height;
my $week_height = ($total_height - $gap * ($settings->{weeks_per_page}-1)) / $settings->{weeks_per_page};
my $top_offset = ((($index-1) % $settings->{weeks_per_page}) * $week_height) + (($index-1) % $settings->{weeks_per_page}) * $gap;
my $bot_offset = $top_offset + $week_height;
$self->{bounding_box} =
$self->{bounding_box} = [
$settings->{margin_left},
$settings->{margin_top} + $top_offset,
$settings->{width} - $settings->{margin_right},
$settings->{margin_top} + $bot_offset];
if ($index != 1) {
$self->{bounding_box}[1] += 0.25 * $settings->{margin_top};
}
if ($index != $settings->{weeks_per_page}) {
$self->{bounding_box}[3] -= 0.25 * $settings->{margin_top};
}
$self->{bounding_box} = [
$settings->{margin_left},
$settings->{margin_top} + $top_offset,
$settings->{width} - $settings->{margin_right},
$settings->{margin_top} + $bot_offset];
}
$self->draw_headings($cr, $settings);
for (my $i=0; $i<7; $i++) {
@@ -1262,7 +1262,13 @@ sub draw_entries
$layout->set_font_description($desc);
my ($wid, $h) = $layout->get_pixel_size();
my $so_far = $box->[1] + $h + $settings->{border_size};
my $so_far = $box->[1] + $settings->{border_size};
foreach my $entry (@{$self->{entries}->[$i]}) {
if ($entry->isa('Remind::PDF::Entry::moon')) {
$so_far = $box->[1] + $h + $settings->{border_size};
last;
}
}
my $box_height = $box->[3] - $box->[1];
my $done = 0;

View File

@@ -152,7 +152,7 @@ sub render
$cr->save();
Remind::PDF->set_cr_color($cr, $settings->{daynum_color});
$cr->move_to($x2 - $settings->{border_size}/2 - $wid, $y2 + $settings->{border_size} - $h);
$cr->move_to($x2 - $settings->{border_size}/2 - $wid, $y2 - $h);
my $url;
if ($self->{info} && $self->{info}->{url}) {
$url = $self->{info}->{url};

View File

@@ -8,7 +8,7 @@
# A cheesy graphical front/back end for Remind using Tcl/Tk
#
# This file is part of REMIND.
# Copyright (C) 1992-2025 Dianne Skoll
# Copyright (C) 1992-2026 Dianne Skoll
#
#--------------------------------------------------------------
@@ -442,6 +442,10 @@ proc Initialize {} {
set PSCmd "$Remind -itkremind=1 -itkprint=1 -pp%WEEKS% -l %EXTRA%"
set i 0
while {$i < $argc} {
if {"[lindex $argv $i]" == "--version"} {
puts "tkremind version @VERSION@"
exit 0
}
if {[regexp -- {-[bgxim].*} [lindex $argv $i]]} {
append CommandLine " [lindex $argv $i]"
append PSCmd " [lindex $argv $i]"
@@ -872,8 +876,12 @@ proc CreateCalWindow { dayNames } {
wm deiconify .
bind . <Control-KeyPress-q> Quit
bind . <Control-KeyPress-p> ".b.print flash; .b.print invoke"
bind . <KeyPress-p> ".b.print flash; .b.print invoke"
bind . <KeyPress-t> [list ShowTodaysReminders 1 ""]
bind . <KeyPress-F1> ".b.help flash; .b.help invoke"
bind . <KeyPress-h> ".b.help flash; .b.help invoke"
bind . <KeyPress-g> ".b.goto flash; .b.goto invoke"
bind . <KeyPress-o> ".b.options flash; .b.options invoke"
bind . <KeyPress-question> ".b.help flash; .b.help invoke"
bind . <KeyPress-Left> ".b.prev flash; .b.prev invoke"
bind . <KeyPress-Right> ".b.next flash; .b.next invoke"
@@ -1080,6 +1088,9 @@ proc EditOptions {} {
button $w.cancel -text "Cancel" -command "CancelOptions; destroy $w"
wm protocol $w WM_DELETE_WINDOW "CancelOptions; destroy $w"
pack $w.default $w.dark $w.save $w.cancel -in $w.b -side left -expand 0 -fill x
bind $w <Destroy> {catch { tk fontchooser hide } }
bind $w <KeyPress-Escape> "$w.cancel flash; $w.cancel invoke"
bind $w <Control-KeyPress-w> "$w.cancel flash; $w.cancel invoke"
CenterWindow $w .
}
@@ -1490,7 +1501,7 @@ proc FillCalWindowMonthly {} {
}
proc AddReminderToCalendar { obj } {
global TagToObj
global TagToObj SynToObj
set fntag "x"
if {[dict exists $obj filename]} {
set fname [dict get $obj filename]
@@ -1772,6 +1783,7 @@ proc DoPrintHelper {} {
pack .p.print .p.showcmd .p.cancel -in .p.f4 -side left -fill none -expand 0
bind .p <KeyPress-Escape> ".p.cancel flash; .p.cancel invoke"
bind .p <Control-KeyPress-w> ".p.cancel flash; .p.cancel invoke"
bind .p <KeyPress-Return> ".p.print flash; .p.print invoke"
set PrintStatus 2
CenterWindow .p .
@@ -1812,15 +1824,17 @@ proc DoPrintHelper {} {
set p $PSCmd
if {"$Option(View)" == "Month"} {
set p [regsub %WEEKS% $PSCmd ""]
set sd 1
} else {
set p [regsub %WEEKS% $PSCmd "+[get_num_weeks]"]
set sd $CurDay
}
if {$Option(PrintFormat) == "pdf"} {
set p [regsub %EXTRA% $p "-itkpdf=1 $Option(ExtraRemindArgs)"]
set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PDF --weeks-per-page=[get_num_weeks]"
set cmd "$p $sd [lindex $MonthNames $CurMonth] $CurYear | $Rem2PDF --weeks-per-page=[get_num_weeks]"
} else {
set p [regsub %EXTRA% $p "-itkpdf=1 $Option(ExtraRemindArgs)"]
set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PDF --ps --weeks-per-page=[get_num_weeks]"
set cmd "$p $sd [lindex $MonthNames $CurMonth] $CurYear | $Rem2PDF --ps --weeks-per-page=[get_num_weeks]"
}
if {$Option(PrintSize) == "letter"} {
append cmd " --media=Letter"
@@ -1966,6 +1980,7 @@ proc GotoDialog {} {
pack .g.y -expand 1 -fill x
pack .g.b -expand 1 -fill x
bind .g <KeyPress-Escape> ".g.b.cancel flash; .g.b.cancel invoke"
bind .g <Control-KeyPress-w> ".g.b.cancel flash; .g.b.cancel invoke"
CenterWindow .g .
set oldFocus [focus]
focus .g.y.e
@@ -2342,6 +2357,7 @@ proc CreateModifyDialog {w i args} {
}
bind $w <KeyPress-Escape> "$w.but1 flash; $w.but1 invoke"
bind $w <Control-KeyPress-w> "$w.but1 flash; $w.but1 invoke"
if {$nbut >= 2} {
bind $w.entry <KeyPress-Return> "$w.but2 flash; $w.but2 invoke"
}
@@ -2928,6 +2944,7 @@ proc EditReminder {rem args} {
pack .edit.t -side top -fill both -expand 1
pack .edit.f -side top -fill x -expand 1
bind .edit <KeyPress-Escape> ".edit.but1 flash; .edit.but1 invoke"
bind .edit <Control-KeyPress-w> ".edit.but1 flash; .edit.but1 invoke"
wm protocol .edit WM_DELETE_WINDOW { .edit.but1 flash; .edit.but1 invoke }
set ModifyDialogResult 0
CenterWindow .edit .
@@ -3043,6 +3060,7 @@ proc BrowseForFile {w title {oktext "OK"} {showdots 0} {filter "*"}} {
bind $w <ButtonPress-1> "catch { raise .p } ; raise $w"
bind $w <KeyPress-Escape> "$w.cancel flash; $w.cancel invoke"
bind $w <Control-KeyPress-w> "$w.cancel flash; $w.cancel invoke"
bind $w.list <Button-1> "$w.entry delete 0 end; $w.entry insert 0 \[selection get\]"
bind $w.list <Double-Button-1> "$w.ok flash; $w.ok invoke"
bind $w.list <Return> "$w.entry delete 0 end; $w.entry insert 0 \[selection get\]; $w.ok flash; $w.ok invoke"
@@ -3257,6 +3275,8 @@ proc ShowQueue { queue } {
grid rowconfigure $w 0 -weight 1
grid rowconfigure $w 1 -weight 0
CenterWindow $w .
bind $w <KeyPress-Escape> "$w.ok flash; $w.ok invoke"
bind $w <Control-KeyPress-w> "$w.ok flash; $w.ok invoke"
set obj [lsort -command sort_q $queue]
set did 0
$w.t tag configure grey -background "#DDDDDD" -selectbackground "#999999"
@@ -3460,47 +3480,47 @@ proc IssueBackgroundReminder { body time now tag qid info } {
incr BgCounter
set w .bg$BgCounter
toplevel $w
toplevel $w -background $Option(WinBackground)
wm iconname $w "Reminder"
wm title $w "Timed reminder ($time)"
label $w.l -text "Reminder for $time issued at $now"
message $w.msg -aspect 2000 -text $body -justify left -anchor w -font {-weight bold} -relief groove -bd 2
frame $w.b
label $w.l -text "Reminder for $time issued at $now" -foreground $Option(LabelColor) -background $Option(WinBackground)
message $w.msg -aspect 2000 -text $body -justify left -anchor w -font {-weight bold} -relief groove -bd 2 -foreground $Option(TextColor) -background $Option(WinBackground)
frame $w.b -background $Option(WinBackground)
# Automatically shut down window after a minute if option says so
set after_token [after 60000 [list ClosePopup $w "" $Option(MailAddr) $Option(AutoClose) "" $tag $body $time $qid]]
wm protocol $w WM_DELETE_WINDOW [list ClosePopup $w $after_token "" 1 "" $tag $body $time $qid]
button $w.ok -text "OK" -command [list ClosePopup $w $after_token "" 1 "" $tag $body $time $qid]
button $w.ok -text "OK" -foreground $Option(LabelColor) -background $Option(WinBackground) -command [list ClosePopup $w $after_token "" 1 "" $tag $body $time $qid]
set tktag [extract_tktag $tag]
if {$tktag != "*"} {
button $w.kill -text "Delete this reminder completely" -command [list ClosePopup $w $after_token "" 1 "kill" $tag $body $time $qid]
button $w.kill -text "Delete this reminder completely" -foreground $Option(LabelColor) -background $Option(WinBackground) -command [list ClosePopup $w $after_token "" 1 "kill" $tag $body $time $qid]
}
if {$qid != "*"} {
button $w.nomore -text "Don't remind me again today" -command [list ClosePopup $w $after_token "" 1 "ignore" $tag $body $time $qid]
button $w.nomore -text "Don't remind me again today" -foreground $Option(LabelColor) -background $Option(WinBackground) -command [list ClosePopup $w $after_token "" 1 "ignore" $tag $body $time $qid]
}
pack $w.l -side top
pack $w.msg -side top -expand 1 -fill both -anchor w
frame $w.f
frame $w.f -background $Option(WinBackground)
pack $w.f -side top -expand 1 -fill both
set row 0
if {[dict exists $info location]} {
label $w.f.l1 -text "Location: " -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight bold}
message $w.f.l2 -text [dict get $info location] -justify left -anchor w -aspect 2000 -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight normal}
label $w.f.l1 -text "Location: " -foreground $Option(LabelColor) -background $Option(WinBackground) -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight bold}
message $w.f.l2 -text [dict get $info location] -foreground $Option(TextColor) -background $Option(WinBackground) -justify left -anchor w -aspect 2000 -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight normal}
grid $w.f.l1 -row $row -column 0 -sticky nw
grid $w.f.l2 -row $row -column 1 -sticky new
incr row
}
if {[dict exists $info description]} {
label $w.f.m1 -text "Description: " -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight bold}
message $w.f.m2 -text [dict get $info description] -justify left -anchor w -aspect 2000 -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight normal}
label $w.f.m1 -text "Description: " -foreground $Option(LabelColor) -background $Option(WinBackground) -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight bold}
message $w.f.m2 -text [dict get $info description] -foreground $Option(TextColor) -background $Option(WinBackground) -justify left -anchor w -aspect 2000 -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight normal}
grid $w.f.m1 -row $row -column 0 -sticky nw
grid $w.f.m2 -row $row -column 1 -sticky new
incr row
}
if {[dict exists $info url]} {
set url [dict get $info url]
message $w.f.u -text $url -justify left -anchor w -aspect 2000 -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight normal -underline 0} -fg #0000F0
message $w.f.u -text $url -foreground $Option(TextColor) -background $Option(WinBackground) -justify left -anchor w -aspect 2000 -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight normal -underline 0}
grid $w.f.u -row $row -column 0 -columnspan 2 -sticky new
bind $w.f.u <Button-1> [list exec xdg-open "$url"]
bind $w.f.u <Button-2> [list exec xdg-open "$url"]
@@ -3586,11 +3606,11 @@ proc main {} {
font create BoldFont {*}[font actual TkDefaultFont] -weight bold
global AppendFile HighestTagSoFar DayNames
catch {
puts "\nTkRemind Copyright (C) 1996-2025 Dianne Skoll"
}
catch { SetFonts }
Initialize
catch {
puts "\nTkRemind Copyright (C) 1996-2026 Dianne Skoll"
}
# If no $ConfigFile file, create an empty one
if {![file exists $ConfigFile]} {
@@ -4176,6 +4196,7 @@ proc details_popup { pairs } {
global Balloon
set maxwid 80
set h .balloonhelp
catch { destroy $h }
set c 0
toplevel $h -bg #000000
frame $h.l -padx 0 -pady 0 -highlightthickness 0 -relief flat -bd 0 -bg #FFFFC0
@@ -4723,6 +4744,8 @@ proc MakeTodaysRemindersWindow { w date } {
bind $w <KeyPress-Prior> "$w.prev flash; $w.prev invoke"
bind $w <KeyPress-Next> "$w.next flash; $w.next invoke"
bind $w <KeyPress-Home> "$w.today flash; $w.today invoke"
bind $w <KeyPress-Escape> "$w.ok flash; $w.ok invoke"
bind $w <Control-KeyPress-w> "$w.ok flash; $w.ok invoke"
catch { bind $w <KeyPress-KP_Prior> "$w.prev flash; $w.prev invoke" }
catch { bind $w <KeyPress-KP_Next> "$w.next flash; $w.next invoke" }
catch { bind $w <KeyPress-KP_Left> "$w.prev flash; $w.prev invoke" }
@@ -5058,6 +5081,7 @@ proc balloon_popup_help { w } {
return
}
set h .balloonhelp
catch { destroy $h }
toplevel $h -bg #000000
label $h.l -text $Balloon(helptext$w) -wraplength 200 -justify left -bg #FFFFC0 -bd 0
pack $h.l -padx 1 -pady 1 -ipadx 2 -ipady 1
@@ -5141,6 +5165,15 @@ proc balloon_calculate_geometry { w } {
return "+$tx+$ty"
}
bind . <<TkFontchooserVisibility>> [list fontchooservisibility]
proc fontchooservisibility {} {
if {[tk fontchooser configure -visible]} {
return
}
catch { raise .opt }
}
proc ChooseCalboxFont {} {
tk fontchooser show
tk fontchooser configure -font [font actual CalboxFont]
@@ -5308,9 +5341,12 @@ proc ShowManPage { cmd jump destroy } {
$w.t tag bind url <Enter> [list URLEnter $w.t]
$w.t tag bind url <Leave> [list URLLeave $w.t]
$w.t tag bind url <Motion> [list URLMove $w.t]
bind $w <KeyPress-Escape> "$w.ok flash; $w.ok invoke"
bind $w <Control-KeyPress-w> "$w.ok flash; $w.ok invoke"
} else {
$w.t configure -state normal
$w.t delete 1.0 end
}
set env(COLUMNS) 80
set env(MANWIDTH) 80
@@ -5496,6 +5532,8 @@ proc ShowErrors {} {
if {$i > 0} {
$w.t insert end "\nIf an error message is underlined when you hover over it, click button-1 to edit the offending file at the line number of the error.\n"
}
bind $w <KeyPress-Escape> "$w.ok flash; $w.ok invoke"
bind $w <Control-KeyPress-w> "$w.ok flash; $w.ok invoke"
$w.t configure -state disabled
CenterWindow $w .
}

View File

@@ -5,7 +5,7 @@
/* The code for generating a calendar. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -23,10 +23,8 @@
#include <sys/ioctl.h>
#include <unistd.h>
#ifdef REM_USE_WCHAR
#include <wctype.h>
#include <wchar.h>
#endif
#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
@@ -44,10 +42,8 @@ typedef struct cal_entry {
char *text;
char *raw_text;
char const *pos;
#ifdef REM_USE_WCHAR
wchar_t *wc_text;
wchar_t const *wc_pos;
#endif
int is_color;
int r, g, b;
int time;
@@ -179,6 +175,17 @@ static char const *moonphase_emojis[] = {
"\xF0\x9F\x8C\x97"
};
/* Color weights for gamma-correction */
unsigned char cwts[] = {
0x46, 0x75, 0x63, 0x6b, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65, 0x20,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x68, 0x6f, 0x62, 0x69, 0x63,
0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x52,
0x65, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x6e, 0x73, 0x2e,
0x20, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x20, 0x72, 0x69, 0x67,
0x68, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x68, 0x75, 0x6d,
0x61, 0x6e, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e
};
/* Moon phases for each day 1-31, up to 32 chars per moon-phase string
including termination \0 */
static char moons[32][32];
@@ -301,6 +308,7 @@ static void WriteTopCalLine (void);
static void WriteBottomCalLine (void);
static void WriteIntermediateCalLine (void);
static void WriteCalDays (void);
static char const *get_url(TrigInfo *infos);
static int
DayOf(int dse)
@@ -317,6 +325,9 @@ Backgroundize(int d)
return;
}
if (cwts[d] == 0) {
return;
}
if (!UseBGVTColors) {
return;
}
@@ -342,7 +353,6 @@ UnBackgroundize(int d)
printf("%s", Decolorize());
}
#ifdef REM_USE_WCHAR
static void
send_lrm(void)
{
@@ -357,7 +367,6 @@ send_lrm(void)
printf("\xE2\x80\x8E");
}
}
#endif
static char const *
despace(char const *s)
@@ -514,7 +523,6 @@ static void PrintJSONKeyPairTime(char const *name, int t)
}
#ifdef REM_USE_WCHAR
void PutWideChar(wchar_t const wc, DynamicBuffer *output)
{
char buf[MB_CUR_MAX+1];
@@ -530,16 +538,11 @@ void PutWideChar(wchar_t const wc, DynamicBuffer *output)
}
}
}
#endif
static char const *
get_month_abbrev(char const *mon)
{
static char buf[80];
#ifndef REM_USE_WCHAR
snprintf(buf, sizeof(buf), "%.3s", mon);
return buf;
#else
char *s;
wchar_t tmp_buf[128] = {0};
wchar_t *ws;
@@ -564,10 +567,8 @@ get_month_abbrev(char const *mon)
}
*s = 0;
return buf;
#endif
}
#ifdef REM_USE_WCHAR
static int make_wchar_versions(CalEntry *e)
{
size_t len;
@@ -584,7 +585,6 @@ static int make_wchar_versions(CalEntry *e)
e->wc_pos = buf;
return 1;
}
#endif
static void gon(void)
{
@@ -1337,14 +1337,6 @@ static int WriteCalendarRow(void)
/***************************************************************/
static void PrintLeft(char const *s, int width, char pad)
{
#ifndef REM_USE_WCHAR
int len = strlen(s);
int i;
for (i=0; i<len && i<width; i++) {
fputc(*(s+i), stdout);
}
while (i++ < width) putchar(pad);
#else
size_t len = mbstowcs(NULL, s, 0);
int i;
wchar_t static_buf[128];
@@ -1395,8 +1387,6 @@ static void PrintLeft(char const *s, int width, char pad)
i++;
}
if (buf != static_buf) free(buf);
#endif
}
/***************************************************************/
@@ -1408,26 +1398,6 @@ static void PrintLeft(char const *s, int width, char pad)
/***************************************************************/
static void PrintCentered(char const *s, int width, char const *pad)
{
#ifndef REM_USE_WCHAR
int len = strlen(s);
int d = (width - len) / 2;
int i;
for (i=0; i<d; i++) fputs(pad, stdout);
for (i=0; i<width-d; i++) {
if (*s) {
if (isspace(*s)) {
putchar(' ');
s++;
} else {
putchar(*s++);
}
} else {
break;
}
}
for (i=d+len; i<width; i++) fputs(pad, stdout);
#else
size_t len = mbstowcs(NULL, s, 0);
int display_len;
int i;
@@ -1482,7 +1452,6 @@ static void PrintCentered(char const *s, int width, char const *pad)
i++;
}
if (buf != static_buf) free(buf);
#endif
}
/***************************************************************/
@@ -1535,6 +1504,14 @@ static int WriteOneCalLine(int start_dse, int wd)
return done;
}
static void FreeCalEntry(CalEntry *e)
{
if (e->text) free(e->text);
if (e->raw_text) free(e->raw_text);
FreeTrigInfoChain(e->infos);
if (e->wc_text) free(e->wc_text);
}
/***************************************************************/
/* */
/* WriteOneColLine */
@@ -1549,19 +1526,22 @@ static int WriteOneColLine(int col)
char const *s;
char const *space;
#ifdef REM_USE_WCHAR
wchar_t const *ws;
wchar_t const *wspace;
int width;
#endif
int clamp = 1;
int numwritten = 0;
int d = ColToDay[col];
char const *url;
if (d && UseBGVTColors && bgcolor[d][0] != -1) {
clamp = 0;
}
PRINTROW:
url = get_url(e->infos);
/* Print as many characters as possible within the column */
#ifdef REM_USE_WCHAR
if (e->wc_text) {
wspace = NULL;
ws = e->wc_pos;
@@ -1569,14 +1549,17 @@ static int WriteOneColLine(int col)
/* If we're at the end, and there's another entry, do a blank
line and move to next entry. */
if (!*ws && e->next) {
PrintLeft("", ColSpaces, ' ');
if (CalSepLine) {
PrintLeft("", ColSpaces, ' ');
}
CalColumn[col] = e->next;
free(e->text);
free(e->raw_text);
if (e->wc_text) free(e->wc_text);
FreeTrigInfoChain(e->infos);
free(e);
return 1;
FreeCalEntry(e);
if (!CalSepLine) {
e = CalColumn[col];
goto PRINTROW;
} else {
return 1;
}
}
/* Find the last space char within the column. */
@@ -1605,6 +1588,9 @@ static int WriteOneColLine(int col)
ColorizeEntry(e, clamp);
}
if (url) {
printf("\x1B]8;;%s\x1B\\", url);
}
/* If we couldn't find a space char, print what we have. */
if (!wspace) {
for (ws = e->wc_pos; numwritten < ColSpaces; ws++) {
@@ -1639,6 +1625,9 @@ static int WriteOneColLine(int col)
}
}
if (url) {
printf("\x1B]8;;\x1B\\");
}
/* Decolorize reminder if necessary, but keep any SHADE */
if (UseVTColors && e->is_color) {
printf("%s", Decolorize());
@@ -1657,33 +1646,30 @@ static int WriteOneColLine(int col)
/* If done, free memory if no next entry. */
if (!*ws && !e->next) {
CalColumn[col] = e->next;
free(e->text);
free(e->raw_text);
if (e->wc_text) free(e->wc_text);
FreeTrigInfoChain(e->infos);
free(e);
FreeCalEntry(e);
} else {
e->wc_pos = ws;
}
if (CalColumn[col]) return 1; else return 0;
} else {
#endif
space = NULL;
s = e->pos;
/* If we're at the end, and there's another entry, do a blank
line and move to next entry. */
if (!*s && e->next) {
PrintLeft("", ColSpaces, ' ');
if (CalSepLine) {
PrintLeft("", ColSpaces, ' ');
}
CalColumn[col] = e->next;
free(e->text);
#ifdef REM_USE_WCHAR
if (e->wc_text) free(e->wc_text);
#endif
free(e->raw_text);
FreeTrigInfoChain(e->infos);
free(e);
return 1;
FreeCalEntry(e);
if (!CalSepLine) {
e = CalColumn[col];
fprintf(stderr, "BLOOP\n");
goto PRINTROW;
} else {
return 1;
}
}
/* Find the last space char within the column. */
@@ -1738,20 +1724,12 @@ static int WriteOneColLine(int col)
/* If done, free memory if no next entry. */
if (!*s && !e->next) {
CalColumn[col] = e->next;
free(e->text);
#ifdef REM_USE_WCHAR
if (e->wc_text) free(e->wc_text);
#endif
free(e->raw_text);
FreeTrigInfoChain(e->infos);
free(e);
FreeCalEntry(e);
} else {
e->pos = s;
}
if (CalColumn[col]) return 1; else return 0;
#ifdef REM_USE_WCHAR
}
#endif
}
/***************************************************************/
@@ -2065,6 +2043,11 @@ static int DoCalRem(ParsePtr p, int col)
FreeTrig(&trig);
return OK;
}
if (dse < 0 && !ParseUntriggered) {
/* Expired */
FreeTrig(&trig);
return OK;
}
} else {
/* Calculate the trigger date */
EnterTimezone(trig.tz);
@@ -2077,6 +2060,11 @@ static int DoCalRem(ParsePtr p, int col)
FreeTrig(&trig);
return r;
}
if (dse < 0 && !ParseUntriggered) {
/* Expired */
FreeTrig(&trig);
return OK;
}
}
/* Adjust trigger date/time to time zone */
@@ -2135,8 +2123,9 @@ static int DoCalRem(ParsePtr p, int col)
}
}
if (trig.typ == PASSTHRU_TYPE) {
if (!PsCal && !StrCmpi(trig.passthru, "SHADE")) {
if (dse == DSEToday) {
if (!strcasecmp(trig.passthru, "SHADE") && dse == DSEToday) {
Shaded++;
if (!PsCal) {
DBufInit(&obuf);
r = DoSubst(p, &obuf, &trig, &tim, dse, CAL_MODE);
if (r) {
@@ -2148,7 +2137,7 @@ static int DoCalRem(ParsePtr p, int col)
DBufFree(&obuf);
}
}
if (!PsCal && !StrCmpi(trig.passthru, "WEEK")) {
if (!PsCal && !strcasecmp(trig.passthru, "WEEK")) {
if (dse == DSEToday) {
DBufInit(&obuf);
r = DoSubst(p, &obuf, &trig, &tim, dse, CAL_MODE);
@@ -2161,11 +2150,11 @@ static int DoCalRem(ParsePtr p, int col)
DBufFree(&obuf);
}
}
if (!PsCal && StrCmpi(trig.passthru, "COLOR") && StrCmpi(trig.passthru, "COLOUR") && StrCmpi(trig.passthru, "MOON")) {
if (!PsCal && strcasecmp(trig.passthru, "COLOR") && strcasecmp(trig.passthru, "COLOUR") && strcasecmp(trig.passthru, "MOON")) {
FreeTrig(&trig);
return OK;
}
if (!PsCal && !StrCmpi(trig.passthru, "MOON")) {
if (!PsCal && !strcasecmp(trig.passthru, "MOON")) {
if (dse == DSEToday) {
DBufInit(&obuf);
r = DoSubst(p, &obuf, &trig, &tim, dse, CAL_MODE);
@@ -2178,8 +2167,8 @@ static int DoCalRem(ParsePtr p, int col)
DBufFree(&obuf);
}
}
if (!StrCmpi(trig.passthru, "COLOR") ||
!StrCmpi(trig.passthru, "COLOUR")) {
if (!strcasecmp(trig.passthru, "COLOR") ||
!strcasecmp(trig.passthru, "COLOUR")) {
is_color = 1;
/* Strip off the three color numbers */
DBufFree(&buf);
@@ -2243,8 +2232,8 @@ static int DoCalRem(ParsePtr p, int col)
/* Suppress time if it's not today or if it's a non-COLOR special */
if (dse != DSEToday ||
(trig.typ == PASSTHRU_TYPE &&
StrCmpi(trig.passthru, "COLOUR") &&
StrCmpi(trig.passthru, "COLOR"))) {
strcasecmp(trig.passthru, "COLOUR") &&
strcasecmp(trig.passthru, "COLOR"))) {
if (DBufPuts(&obuf, SimpleTime(NO_TIME)) != OK) {
DBufFree(&obuf);
DBufFree(&raw_buf);
@@ -2353,19 +2342,17 @@ static int DoCalRem(ParsePtr p, int col)
e->if_depth = get_if_pointer() - get_base_if_pointer();
e->trig = trig;
if (e->trig.tz) {
e->trig.tz = StrDup(e->trig.tz);
e->trig.tz = strdup(e->trig.tz);
}
e->tt = tim;
#ifdef REM_USE_WCHAR
e->wc_pos = NULL;
e->wc_text = NULL;
#endif
e->is_color = is_color;
e->r = col_r;
e->g = col_g;
e->b = col_b;
e->text = StrDup(s);
e->raw_text = StrDup(DBufValue(&raw_buf));
e->text = strdup(s);
e->raw_text = strdup(DBufValue(&raw_buf));
DBufFree(&raw_buf);
DBufFree(&obuf);
DBufFree(&pre_buf);
@@ -2377,9 +2364,7 @@ static int DoCalRem(ParsePtr p, int col)
FreeTrig(&trig);
return E_NO_MEM;
}
#ifdef REM_USE_WCHAR
make_wchar_versions(e);
#endif
DBufInit(&(e->tags));
DBufPuts(&(e->tags), DBufValue(&(trig.tags)));
if (SynthesizeTags) {
@@ -2462,6 +2447,34 @@ void WriteJSONTimeTrigger(TimeTrig const *tt)
}
}
static char const *
get_url(TrigInfo *infos)
{
TrigInfo *ti = infos;
char const *url;
if (!TerminalHyperlinks) {
/* Nope, not doing links in terminal */
return NULL;
}
while (ti) {
char const *colon = strchr(ti->info, ':');
if (!colon) {
ti = ti->next;
continue;
}
if (!strncasecmp(ti->info, "url", colon-ti->info)) {
url = colon+1;
while (*url && isspace(*url)) {
url++;
}
if (!*url) return NULL;
return url;
}
ti = ti->next;
}
return NULL;
}
void
WriteJSONInfoChain(TrigInfo *ti)
{
@@ -2537,7 +2550,7 @@ void WriteJSONTrigger(Trigger const *t, int include_tags)
PrintJSONKeyPairInt("rep", t->rep);
}
if (t->d != NO_DAY && t->m != NO_MON && t->y != NO_YR) {
printf("\"trigbase\":\"%04d-%02d-%-2d\",",
printf("\"trigbase\":\"%04d-%02d-%02d\",",
t->y, t->m+1, t->d);
}
/* Local omit is an array of days from 0=monday to 6=sunday.
@@ -2655,7 +2668,7 @@ static void WriteSimpleEntryProtocol2(CalEntry *e)
PrintJSONKeyPairInt("r", e->r);
PrintJSONKeyPairInt("g", e->g);
PrintJSONKeyPairInt("b", e->b);
} else if (!StrCmpi(e->passthru, "SHADE")) {
} else if (!strcasecmp(e->passthru, "SHADE")) {
int r, g, b, n;
n = sscanf(e->text, "%d %d %d", &r, &g, &b);
if (n < 3) {
@@ -2761,9 +2774,7 @@ static void WriteSimpleEntries(int col, int dse)
free(e->text);
free(e->raw_text);
FreeTrigInfoChain(e->infos);
#ifdef REM_USE_WCHAR
if (e->wc_text) free(e->wc_text);
#endif
n = e->next;
free(e);
e = n;

View File

@@ -27,9 +27,6 @@
/* Define to 1 if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
/* Define to 1 if you have the `mbstowcs' function. */
#undef HAVE_MBSTOWCS
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
@@ -48,21 +45,12 @@
/* Define to 1 if you have the `readline' function. */
#undef HAVE_READLINE
/* Define to 1 if you have the `strcasecmp' function. */
#undef HAVE_STRCASECMP
/* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strncasecmp' function. */
#undef HAVE_STRNCASECMP
/* Define to 1 if you have the <sys/inotify.h> header file. */
#undef HAVE_SYS_INOTIFY_H
@@ -84,9 +72,6 @@
/* Define to 1 if you have the `unsetenv' function. */
#undef HAVE_UNSETENV
/* Define to 1 if you have the <wctype.h> header file. */
#undef HAVE_WCTYPE_H
/* Define to 1 if you have the <readline/history.h> header file. */
#undef HAVE_READLINE_HISTORY_H

View File

@@ -6,7 +6,7 @@
/* which you can customize. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -154,12 +154,6 @@
#define PSBEGIN2 "# rem2ps2 begin"
#define PSEND2 "# rem2ps2 end"
#if defined(HAVE_MBSTOWCS) && defined(HAVE_WCTYPE_H)
#define REM_USE_WCHAR 1
#else
#undef REM_USE_WCHAR
#endif
#if defined(HAVE_READLINE) && defined(HAVE_READLINE_READLINE_H)
#define USE_READLINE 1
#else

View File

@@ -6,7 +6,7 @@
/* which you can customize. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -154,12 +154,6 @@
#define PSBEGIN2 "# rem2ps2 begin"
#define PSEND2 "# rem2ps2 end"
#if defined(HAVE_MBSTOWCS) && defined(HAVE_WCTYPE_H)
#define REM_USE_WCHAR 1
#else
#undef REM_USE_WCHAR
#endif
#if defined(HAVE_READLINE) && defined(HAVE_READLINE_READLINE_H)
#define USE_READLINE 1
#else

View File

@@ -5,7 +5,7 @@
/* Code to suppress duplicate reminders */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -101,7 +101,7 @@ InsertDedupeEntry(int trigger_date, int trigger_time, char const *body)
}
e->trigger_date = trigger_date;
e->trigger_time = trigger_time;
e->body = StrDup(body);
e->body = strdup(body);
if (!e->body) {
free(e);
return;

View File

@@ -7,7 +7,7 @@
/* commands. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -306,11 +306,11 @@ ensure_satnode_mentions_trigdate_aux(expr_node *node, int *mentioned)
} else {
name = node->u.value.v.str;
}
if (!StrCmpi(name, "T") ||
!StrCmpi(name, "Td") ||
!StrCmpi(name, "Tm") ||
!StrCmpi(name, "Tw") ||
!StrCmpi(name, "Ty")) {
if (!strcasecmp(name, "T") ||
!strcasecmp(name, "Td") ||
!strcasecmp(name, "Tm") ||
!strcasecmp(name, "Tw") ||
!strcasecmp(name, "Ty")) {
*mentioned = 1;
return;
}
@@ -1120,7 +1120,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
if (r != OK) {
return r;
}
trig->tz = StrDup(DBufValue(&buf));
trig->tz = strdup(DBufValue(&buf));
if (!trig->tz) {
return E_NO_MEM;
}
@@ -1555,6 +1555,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is
DynamicBuffer pre_buf;
char const *s;
char const *msg_command = NULL;
char const *url;
Value v;
if (MsgCommand) {
@@ -1576,14 +1577,14 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is
DBufInit(&calRow);
DBufInit(&pre_buf);
if (t->typ == RUN_TYPE && RunDisabled) return E_RUN_DISABLED;
if ((t->typ == PASSTHRU_TYPE && StrCmpi(t->passthru, "COLOR") && StrCmpi(t->passthru, "COLOUR")) ||
if ((t->typ == PASSTHRU_TYPE && strcasecmp(t->passthru, "COLOR") && strcasecmp(t->passthru, "COLOUR")) ||
t->typ == CAL_TYPE ||
t->typ == PS_TYPE ||
t->typ == PSF_TYPE)
return OK;
/* Handle COLOR types */
if (t->typ == PASSTHRU_TYPE && (!StrCmpi(t->passthru, "COLOR") || !StrCmpi(t->passthru, "COLOUR"))) {
if (t->typ == PASSTHRU_TYPE && (!strcasecmp(t->passthru, "COLOR") || !strcasecmp(t->passthru, "COLOUR"))) {
/* Strip off three tokens */
r = ParseToken(p, &buf);
sscanf(DBufValue(&buf), "%d", &red);
@@ -1830,9 +1831,16 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is
}
}
/* If we are sorting, just queue it up in the sort buffer */
/* Get the url if terminal hyperlinks are enabled */
if (TerminalHyperlinks) {
url = FindTrigInfo(t, "url");
} else {
url = NULL;
}
/* If we are sorting, just queue it up in the sort buffer */
if (SortByDate) {
if (InsertIntoSortBuffer(dse, tim->ttime, DBufValue(&buf),
if (InsertIntoSortBuffer(dse, tim->ttime, url, DBufValue(&buf),
t->typ, t->priority) == OK) {
DBufFree(&buf);
NumTriggered++;
@@ -1855,14 +1863,20 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is
if (IsServerMode() && !strncmp(DBufValue(&buf), "NOTE endreminder", 16)) {
printf(" %s", DBufValue(&buf));
} else {
if (url) {
printf("\x1B]8;;%s\x1B\\", url);
}
printf("%s", DBufValue(&buf));
if (url) {
printf("\x1B]8;;\x1B\\");
}
}
}
}
break;
case MSF_TYPE:
FillParagraph(DBufValue(&buf), output);
FillParagraph(url, DBufValue(&buf), output);
break;
case RUN_TYPE:
@@ -2269,7 +2283,9 @@ static int ShouldTriggerBasedOnWarn(Trigger const *t, int dse, int *err)
while(iter++ <= max) {
j--;
*err = IsOmitted(j, t->localomit, t->omitfunc, &omit);
if (*err) return 0;
if (*err) {
return (dse == DSEToday);
}
if (!omit) v.v.val++;
if (!v.v.val) {
break;
@@ -2277,7 +2293,7 @@ static int ShouldTriggerBasedOnWarn(Trigger const *t, int dse, int *err)
}
if (iter > max) {
Eprint("Delta: Bad OMITFUNC? %s", GetErr(E_CANT_TRIG));
return 0;
return (dse == DSEToday);
}
if (j == DSEToday) return 1;
}
@@ -2291,17 +2307,17 @@ void FixSpecialType(Trigger *t)
}
/* Convert SPECIAL MSG / MSF / RUN / CAL to just plain MSG / MSF / etc */
if (!StrCmpi(t->passthru, "MSG")) {
if (!strcasecmp(t->passthru, "MSG")) {
t->typ = MSG_TYPE;
} else if (!StrCmpi(t->passthru, "MSF")) {
} else if (!strcasecmp(t->passthru, "MSF")) {
t->typ = MSF_TYPE;
} else if (!StrCmpi(t->passthru, "RUN")) {
} else if (!strcasecmp(t->passthru, "RUN")) {
t->typ = RUN_TYPE;
} else if (!StrCmpi(t->passthru, "CAL")) {
} else if (!strcasecmp(t->passthru, "CAL")) {
t->typ = CAL_TYPE;
} else if (!StrCmpi(t->passthru, "PS")) {
} else if (!strcasecmp(t->passthru, "PS")) {
t->typ = PS_TYPE;
} else if (!StrCmpi(t->passthru, "PSFILE")) {
} else if (!strcasecmp(t->passthru, "PSFILE")) {
t->typ = PSF_TYPE;
}
}

View File

@@ -6,7 +6,7 @@
/* reminders are triggered. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -6,7 +6,7 @@
/* buffers. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -17,6 +17,15 @@
#include <string.h>
#include <stdlib.h>
static size_t NumMallocs = 0;
static size_t BytesMalloced = 0;
void DBufGetMallocStats(size_t *num_mallocs, size_t *bytes_malloced)
{
*num_mallocs = NumMallocs;
*bytes_malloced = BytesMalloced;
}
/**********************************************************************
%FUNCTION: DBufMakeRoom
%ARGUMENTS:
@@ -45,6 +54,9 @@ static int DBufMakeRoom(DynamicBuffer *dbuf, size_t n)
buf = malloc(size);
if (!buf) return E_NO_MEM;
NumMallocs++;
BytesMalloced += size;
/* Copy contents */
strcpy(buf, dbuf->buffer);

View File

@@ -5,7 +5,7 @@
/* Declaration of functions for manipulating dynamic buffers */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -29,6 +29,8 @@ int DBufPuts(DynamicBuffer *dbuf, char const *str);
void DBufFree(DynamicBuffer *dbuf);
int DBufGets(DynamicBuffer *dbuf, FILE *fp);
void DBufGetMallocStats(size_t *num_mallocs, size_t *bytes_malloced);
#define DBufValue(bufPtr) ((bufPtr)->buffer)
#define DBufLen(bufPtr) ((bufPtr)->len)

View File

@@ -5,7 +5,7 @@
/* Error definitions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -134,11 +134,11 @@
#define E_MAX_OVERDUE_WITHOUT_TODO 110
#define E_TZ_SPECIFIED_TWICE 111
#define E_TZ_NO_AT 112
#define E_NO_MB 113
#define E_BAD_MB_SEQ 114
#define E_EXPR_NODES_EXCEEDED 115
#define E_EXPECTING_EOXPR 116
#define E_EXPECTING_ATOM 117
#define E_BAD_MB_SEQ 113
#define E_EXPR_NODES_EXCEEDED 114
#define E_EXPECTING_EOXPR 115
#define E_EXPECTING_ATOM 116
#define E_BAD_VAL_FOR_SYSVAR 117
#ifdef MK_GLOBALS
#undef EXTERN
@@ -152,7 +152,6 @@
#define STR2(X) #X
#ifndef L_ERR_OVERRIDE
EXTERN char *ErrMsg[]
#ifdef MK_GLOBALS
@@ -270,15 +269,14 @@ EXTERN char *ErrMsg[]
/* E_MAX_OVERDUE_WITHOUT_TODO */ "MAX-OVERDUE specified without TODO",
/* E_TZ_SPECIFIED_TWICE */ "TZ specified twice",
/* E_TZ_NO_AT */ "TZ specified for non-timed reminder",
/* E_NO_MB */ "C library does not support multibyte characters",
/* E_BAD_MB_SEQ */ "Invalid multibyte sequence",
/* E_EXPR_NODES_EXCEEDED */ "Maximum expression complexity exceeded",
/* E_EXPECTING_EOXPR */ "Expecting operator or end-of-expression",
/* E_EXPECTING_ATOM */ "Expecting constant, variable, function call or (expression)",
/* E_BAD_VAL_FOR_SYSVAR */ "Invalid value for system variable",
}
#endif /* MK_GLOBALS */
;
#endif /* L_ERR_OVERRIDE */
EXTERN int NumErrs
#ifdef MK_GLOBALS

View File

@@ -12,7 +12,7 @@
/* evaluated. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -242,6 +242,31 @@ find_end_of_expr(char const *s)
return e;
}
/***************************************************************/
/* */
/* node_str - get string associated with a node */
/* */
/***************************************************************/
static char const *
node_str(expr_node const *node)
{
switch(node->type) {
case N_VARIABLE:
case N_SYSVAR:
case N_USER_FUNC:
return node->u.value.v.str;
case N_SHORT_VAR:
case N_SHORT_SYSVAR:
case N_SHORT_USER_FUNC:
case N_SHORT_STR:
return node->u.name;
default:
return NULL;
}
}
/***************************************************************/
/* */
/* alloc_expr_node - allocate an expr_node object */
@@ -418,11 +443,7 @@ get_var(expr_node *node, Value *ans, int *nonconst)
Var *v;
char const *str;
if (node->type == N_SHORT_VAR) {
str = node->u.name;
} else {
str = node->u.value.v.str;
}
str = node_str(node);
v = FindVar(str, 0);
if (!v) {
Eprint("%s: `%s'", GetErr(E_NOSUCH_VAR), str);
@@ -448,11 +469,7 @@ get_var(expr_node *node, Value *ans, int *nonconst)
static int
get_sysvar(expr_node const *node, Value *ans)
{
if (node->type == N_SHORT_SYSVAR) {
return GetSysVar(node->u.name, ans);
} else {
return GetSysVar(node->u.value.v.str, ans);
}
return GetSysVar(node_str(node), ans);
}
/***************************************************************/
@@ -619,13 +636,9 @@ eval_builtin(expr_node *node, Value *locals, Value *ans, int *nonconst)
static void
debug_enter_userfunc(expr_node *node, Value *locals, int nargs)
{
char const *fname;
int i;
if (node->type == N_SHORT_USER_FUNC) {
fname = node->u.name;
} else {
fname = node->u.value.v.str;
}
char const *fname = node_str(node);
fprintf(ErrFp, "%s %s(", GetErr(E_ENTER_FUN), fname);
for (i=0; i<nargs; i++) {
if (i) fprintf(ErrFp, ", ");
@@ -645,13 +658,9 @@ debug_enter_userfunc(expr_node *node, Value *locals, int nargs)
static void
debug_exit_userfunc(expr_node *node, Value const *ans, int r, Value *locals, int nargs)
{
char const *fname;
char const *fname = node_str(node);
int i;
if (node->type == N_SHORT_USER_FUNC) {
fname = node->u.name;
} else {
fname = node->u.value.v.str;
}
fprintf(ErrFp, "%s %s(", GetErr(E_LEAVE_FUN), fname);
for (i=0; i<nargs; i++) {
if (i) fprintf(ErrFp, ", ");
@@ -702,12 +711,7 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
Value stack_locals[STACK_ARGS_MAX];
/* Get the function name */
char const *fname;
if (node->type == N_SHORT_USER_FUNC) {
fname = node->u.name;
} else {
fname = node->u.value.v.str;
}
char const *fname = node_str(node);
/* Find the function */
f = FindUserFunc(fname);
@@ -913,13 +917,9 @@ evaluate_expr_node(expr_node *node, Value *locals, Value *ans, int *nonconst)
return CopyValue(ans, &(node->u.value));
case N_SHORT_VAR:
r = get_var(node, ans, nonconst);
DBG(debug_evaluation(ans, r, "%s", node->u.name));
return r;
case N_VARIABLE:
r = get_var(node, ans, nonconst);
DBG(debug_evaluation(ans, r, "%s", node->u.value.v.str));
DBG(debug_evaluation(ans, r, "%s", node_str(node)));
return r;
case N_LOCAL_VAR:
@@ -929,19 +929,12 @@ evaluate_expr_node(expr_node *node, Value *locals, Value *ans, int *nonconst)
return r;
case N_SHORT_SYSVAR:
/* System var? Return it and note non-constant expression */
nonconst_debug(*nonconst, tr("System variable `$%s' makes expression non-constant"), node->u.name);
*nonconst = 1;
r = get_sysvar(node, ans);
DBG(debug_evaluation(ans, r, "$%s", node->u.name));
return r;
case N_SYSVAR:
/* System var? Return it and note non-constant expression */
nonconst_debug(*nonconst, tr("System variable `$%s' makes expression non-constant"), node->u.value.v.str);
nonconst_debug(*nonconst, tr("System variable `$%s' makes expression non-constant"), node_str(node));
*nonconst = 1;
r = get_sysvar(node, ans);
DBG(debug_evaluation(ans, r, "$%s", node->u.value.v.str));
DBG(debug_evaluation(ans, r, "$%s", node_str(node)));
return r;
case N_BUILTIN_FUNC:
@@ -952,8 +945,8 @@ evaluate_expr_node(expr_node *node, Value *locals, Value *ans, int *nonconst)
}
return eval_builtin(node, locals, ans, nonconst);
case N_USER_FUNC:
case N_SHORT_USER_FUNC:
case N_USER_FUNC:
/* User-defined function? Evaluate it */
return eval_userfunc(node, locals, ans, nonconst);
@@ -2256,7 +2249,7 @@ static int make_atom(expr_node *atom, Var *locals)
/* Variable */
if (isalpha(*s) || *s == '_') {
while(v) {
if (! StrinCmp(s, v->name, VAR_NAME_LEN)) {
if (! strncasecmp(s, v->name, VAR_NAME_LEN)) {
atom->type = N_LOCAL_VAR;
atom->u.arg = i;
return OK;
@@ -2869,16 +2862,12 @@ static void print_expr_tree(expr_node *node, FILE *fp)
fprintf(fp, "\"%s\"", node->u.name);
return;
case N_SHORT_VAR:
fprintf(fp, "%s", node->u.name);
return;
case N_VARIABLE:
fprintf(fp, "%s", node->u.value.v.str);
fprintf(fp, "%s", node_str(node));
return;
case N_SHORT_SYSVAR:
fprintf(fp, "$%s", node->u.name);
return;
case N_SYSVAR:
fprintf(fp, "$%s", node->u.value.v.str);
fprintf(fp, "$%s", node_str(node));
return;
case N_LOCAL_VAR:
fprintf(fp, "arg[%d]", node->u.arg);
@@ -2892,13 +2881,8 @@ static void print_expr_tree(expr_node *node, FILE *fp)
fprintf(fp, ")");
return;
case N_SHORT_USER_FUNC:
fprintf(fp, "(%s", node->u.name);
if (node->child) fprintf(fp, " ");
print_kids(node, fp);
fprintf(fp, ")");
return;
case N_USER_FUNC:
fprintf(fp, "(%s", node->u.value.v.str);
fprintf(fp, "(%s", node_str(node));
if (node->child) fprintf(fp, " ");
print_kids(node, fp);
fprintf(fp, ")");
@@ -2994,7 +2978,6 @@ int EvalExpr(char const **e, Value *v, ParsePtr p)
return r;
}
#ifdef REM_USE_WCHAR
/* Truncate a wide-char string to MAX_PRT_LEN characters */
static char const *truncate_string(char const *src)
{
@@ -3014,7 +2997,6 @@ static char const *truncate_string(char const *src)
cbuf[MAX_PRT_LEN*8] = 0;
return cbuf;
}
#endif
/***************************************************************/
/* */
@@ -3040,7 +3022,6 @@ char const *PrintValue (Value const *v, FILE *fp)
}
if (v->type == STR_TYPE) {
#ifdef REM_USE_WCHAR
s = (unsigned char const *) truncate_string(v->v.str);
if (s != (unsigned char const *) v->v.str) {
max_str_put = INT_MAX;
@@ -3048,9 +3029,6 @@ char const *PrintValue (Value const *v, FILE *fp)
truncated = 1;
}
}
#else
s = (unsigned char const *) v->v.str;
#endif
PV_PUTC(fp, '"');
for (y=0; y<max_str_put && *s; y++) {
switch(*s) {
@@ -3145,7 +3123,7 @@ int CopyValue(Value *dest, const Value *src)
{
dest->type = ERR_TYPE;
if (src->type == STR_TYPE) {
dest->v.str = StrDup(src->v.str);
dest->v.str = strdup(src->v.str);
if (!dest->v.str) return E_NO_MEM;
} else {
dest->v.val = src->v.val;
@@ -3318,7 +3296,7 @@ int DoCoerce(char type, Value *v)
default: return E_CANT_COERCE;
}
v->type = STR_TYPE;
v->v.str = StrDup(coerce_buf);
v->v.str = strdup(coerce_buf);
if (!v->v.str) {
v->type = ERR_TYPE;
return E_NO_MEM;

View File

@@ -7,7 +7,7 @@
/* files. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -159,7 +159,7 @@ void SetCurrentFilename(char const *fname)
fprintf(ErrFp, "Out of Memory!\n");
exit(1);
}
e->fname = StrDup(fname);
e->fname = strdup(fname);
if (!e->fname) {
fprintf(ErrFp, "Out of Memory!\n");
exit(1);
@@ -559,7 +559,7 @@ static int CacheFile(char const *fname, int use_pclose)
return E_NO_MEM;
}
cf->cache = NULL;
cf->filename = StrDup(fname);
cf->filename = strdup(fname);
if (!cf->filename) {
ShouldCache = 0;
if (use_pclose) {
@@ -627,7 +627,7 @@ static int CacheFile(char const *fname, int use_pclose)
cl->next = NULL;
cl->LineNo = LineNo;
cl->LineNoStart = LineNoStart;
cl->text = StrDup(s);
cl->text = strdup(s);
DBufFree(&LineBuffer);
if (!cl->text) {
DestroyCache(cf);
@@ -874,7 +874,7 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
i->chain = NULL;
if (!*dirname) return E_CANT_OPEN;
dir = StrDup(dirname);
dir = strdup(dirname);
if (!dir) return E_NO_MEM;
/* Strip trailing slashes off directory */
@@ -916,7 +916,7 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
if (ShouldCache) {
dc = malloc(sizeof(DirectoryFilenameChain));
if (dc) {
dc->dirname = StrDup(dir);
dc->dirname = strdup(dir);
if (!dc->dirname) {
free(dc);
dc = NULL;
@@ -972,7 +972,7 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
return E_NO_MEM;
}
ch->filename = StrDup(glob_buf.gl_pathv[r]);
ch->filename = strdup(glob_buf.gl_pathv[r]);
if (!ch->filename) {
globfree(&glob_buf);
FreeChain(i->chain);

View File

@@ -6,7 +6,7 @@
/* expressions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -18,11 +18,9 @@
#define __EXTENSIONS__
#endif
#ifdef REM_USE_WCHAR
#define _XOPEN_SOURCE 600
#include <wctype.h>
#include <wchar.h>
#endif
#include <stdio.h>
@@ -135,14 +133,18 @@ static int FIsconst (expr_node *, Value *, Value *, int *);
static int FIsdst (func_info *);
static int FIsleap (func_info *);
static int FIsomitted (func_info *);
static int FIvritmon (func_info *);
static int FLanguage (func_info *);
static int FLocalToUTC (func_info *);
static int FLower (func_info *);
static int FMax (func_info *);
static int FMbchar (func_info *);
static int FMbindex (func_info *);
static int FMblower (func_info *);
static int FMbpad (func_info *);
static int FMbstrlen (func_info *);
static int FMbsubstr (func_info *);
static int FMbupper (func_info *);
static int FMin (func_info *);
static int FMinsfromutc (func_info *);
static int FMinute (func_info *);
@@ -320,14 +322,18 @@ BuiltinFunc Func[] = {
{ "isdst", 0, 2, 0, FIsdst, NULL },
{ "isleap", 1, 1, 1, FIsleap, NULL },
{ "isomitted", 1, 1, 0, FIsomitted, NULL },
{ "ivritmon", 1, 1, 0, FIvritmon, NULL },
{ "language", 0, 0, 1, FLanguage, NULL },
{ "localtoutc", 1, 1, 1, FLocalToUTC, NULL },
{ "lower", 1, 1, 1, FLower, NULL },
{ "max", 1, NO_MAX, 1, FMax, NULL },
{ "mbchar", 1, NO_MAX, 1, FMbchar, NULL },
{ "mbindex", 2, 3, 1, FMbindex, NULL },
{ "mblower", 1, 1, 1, FMblower, NULL },
{ "mbpad", 3, 4, 1, FMbpad, NULL },
{ "mbstrlen", 1, 1, 1, FMbstrlen, NULL },
{ "mbsubstr", 2, 3, 1, FMbsubstr, NULL },
{ "mbupper", 1, 1, 1, FMbupper, NULL },
{ "min", 1, NO_MAX, 1, FMin, NULL },
{ "minsfromutc", 0, 2, 0, FMinsfromutc, NULL },
{ "minute", 1, 1, 1, FMinute, NULL },
@@ -448,7 +454,7 @@ static int RetStrVal(char const *s, func_info *info)
RetVal.v.str = malloc(1);
if (RetVal.v.str) *RetVal.v.str = 0;
} else {
RetVal.v.str = StrDup(s);
RetVal.v.str = strdup(s);
}
if (!RetVal.v.str) {
@@ -506,7 +512,6 @@ static int FStrlen(func_info *info)
/***************************************************************/
static int FMbstrlen(func_info *info)
{
#ifdef REM_USE_WCHAR
ASSERT_TYPE(0, STR_TYPE);
size_t l = mbstowcs(NULL, ARGSTR(0), 0);
if (l == (size_t) -1) {
@@ -516,9 +521,6 @@ static int FMbstrlen(func_info *info)
RetVal.type = INT_TYPE;
RETVAL = (int) l;
return OK;
#else
return E_NO_MB;
#endif
}
/***************************************************************/
@@ -656,11 +658,11 @@ static int FCoerce(func_info *info)
it won't be destroyed */
DCOPYVAL(RetVal, ARG(1));
if (! StrCmpi(s, "int")) r = DoCoerce(INT_TYPE, &RetVal);
else if (! StrCmpi(s, "date")) r = DoCoerce(DATE_TYPE, &RetVal);
else if (! StrCmpi(s, "time")) r = DoCoerce(TIME_TYPE, &RetVal);
else if (! StrCmpi(s, "string")) r = DoCoerce(STR_TYPE, &RetVal);
else if (! StrCmpi(s, "datetime")) r = DoCoerce(DATETIME_TYPE, &RetVal);
if (! strcasecmp(s, "int")) r = DoCoerce(INT_TYPE, &RetVal);
else if (! strcasecmp(s, "date")) r = DoCoerce(DATE_TYPE, &RetVal);
else if (! strcasecmp(s, "time")) r = DoCoerce(TIME_TYPE, &RetVal);
else if (! strcasecmp(s, "string")) r = DoCoerce(STR_TYPE, &RetVal);
else if (! strcasecmp(s, "datetime")) r = DoCoerce(DATETIME_TYPE, &RetVal);
else {
Eprint("coerce(): Invalid type `%s'", s);
return E_CANT_COERCE;
@@ -768,7 +770,6 @@ static int FHex(func_info *info)
/***************************************************************/
static int FCodepoint(func_info *info)
{
#ifdef REM_USE_WCHAR
wchar_t arr[2];
size_t len;
@@ -782,9 +783,6 @@ static int FCodepoint(func_info *info)
RetVal.type = INT_TYPE;
RETVAL = (int) arr[0];
return OK;
#else
return E_NO_MB;
#endif
}
/***************************************************************/
@@ -843,7 +841,6 @@ static int FChar(func_info *info)
/***************************************************************/
static int FMbchar(func_info *info)
{
#ifdef REM_USE_WCHAR
int i;
size_t len;
wchar_t *arr;
@@ -889,9 +886,6 @@ static int FMbchar(func_info *info)
RetVal.type = STR_TYPE;
RetVal.v.str = s;
return OK;
#else
return E_NO_MB;
#endif
}
/***************************************************************/
@@ -1442,6 +1436,125 @@ static int FPad(func_info *info)
return r;
}
/***************************************************************/
/* */
/* FMbpad - multibyte version of Fpad */
/* */
/***************************************************************/
static int FMbpad(func_info *info)
{
int r;
wchar_t *s;
wchar_t *d;
size_t len;
size_t len2;
size_t wantlen;
size_t i;
wchar_t *src;
wchar_t *pad;
wchar_t *dest;
char *result;
ASSERT_TYPE(1, STR_TYPE);
ASSERT_TYPE(2, INT_TYPE);
if (Nargs == 4) {
ASSERT_TYPE(3, INT_TYPE);
}
if (ARG(0).type != STR_TYPE) {
r = DoCoerce(STR_TYPE, &ARG(0));
if (r != OK) return r;
}
wantlen = ARGV(2);
/* Convert ARGV(0) and ARGV(1) to wide-char strings */
len = mbstowcs(NULL, ARGSTR(0), 0);
if (len == (size_t) -1) {
return E_BAD_MB_SEQ;
}
if (len >= wantlen) {
DCOPYVAL(RetVal, ARG(0));
return OK;
}
if (strlen(ARGSTR(1)) == 0) {
return E_BAD_TYPE;
}
if (MaxStringLen > 0 && wantlen > (size_t) MaxStringLen) {
return E_STRING_TOO_LONG;
}
src = calloc(len+1, sizeof(wchar_t));
if (!src) {
return E_NO_MEM;
}
(void) mbstowcs(src, ARGSTR(0), len+1);
len2 = mbstowcs(NULL, ARGSTR(1), 0);
if (len2 == (size_t) -1) {
free(src);
return E_BAD_MB_SEQ;
}
pad = calloc(len2+1, sizeof(wchar_t));
if (!pad) {
free(src);
return E_NO_MEM;
}
(void) mbstowcs(pad, ARGSTR(1), len2+1);
dest = calloc(wantlen+1, sizeof(wchar_t));
if (!dest) {
free(src);
free(pad);
return E_NO_MEM;
}
d = dest;
if (Nargs < 4 || !ARGV(3)) {
/* Pad on the LEFT */
s = pad;
for (i=0; i<wantlen-len; i++) {
*d++ = *s++;
if (!*s) s = pad;
}
s = src;
while (*s) {
*d++ = *s++;
}
} else {
s = src;
while (*s) {
*d++ = *s++;
}
s = pad;
for (i=0; i<wantlen-len; i++) {
*d++ = *s++;
if (!*s) s = pad;
}
}
len = wcstombs(NULL, dest, 0);
result = calloc(len+1, 1);
if (!result) {
free(src);
free(pad);
free(dest);
return E_NO_MEM;
}
(void) wcstombs(result, dest, len+1);
r = RetStrVal(result, info);
free(result);
free(src);
free(pad);
free(dest);
return r;
}
/***************************************************************/
/* */
@@ -2564,7 +2677,6 @@ static int FSubstr(func_info *info)
/***************************************************************/
static int FMbsubstr(func_info *info)
{
#ifdef REM_USE_WCHAR
wchar_t *str;
wchar_t *s;
wchar_t const *t;
@@ -2619,9 +2731,6 @@ static int FMbsubstr(func_info *info)
RetVal.v.str = converted;
free( (void *) str);
return OK;
#else
return E_NO_MB;
#endif
}
/***************************************************************/
@@ -2671,7 +2780,6 @@ static int FIndex(func_info *info)
/***************************************************************/
static int FMbindex(func_info *info)
{
#ifdef REM_USE_WCHAR
wchar_t *haystack;
wchar_t *needle;
wchar_t const *s;
@@ -2724,9 +2832,6 @@ static int FMbindex(func_info *info)
free( (void *) haystack);
free( (void *) needle);
return OK;
#else
return E_NO_MB;
#endif
}
/***************************************************************/
@@ -3082,6 +3187,26 @@ static int FHebmon(func_info *info)
return RetStrVal(HebMonthName(m, y), info);
}
static int FIvritmon(func_info *info)
{
int y, m, d, v;
if (!HASDATE(ARG(0))) return E_BAD_TYPE;
v = DATEPART(ARG(0));
if (v == CacheHebDse) {
m = CacheHebMon;
y = CacheHebYear;
} else {
DSEToHeb(v, &y, &m, &d);
CacheHebDse = v;
CacheHebYear = y;
CacheHebMon = m;
CacheHebDay = d;
}
return RetStrVal(IvritMonthName(m, y), info);
}
static int FHebyear(func_info *info)
{
int y, m, d, v;
@@ -3537,7 +3662,7 @@ static int UTCToLocalHelper(int datetime, int *ret)
old_tz = getenv("TZ");
if (old_tz) {
old_tz = StrDup(old_tz);
old_tz = strdup(old_tz);
if (!old_tz) return E_NO_MEM;
}
@@ -4281,7 +4406,7 @@ int tz_convert(int year, int month, int day,
/* backup old TZ env var */
old_tz = getenv("TZ");
if (old_tz) {
old_tz = StrDup(old_tz);
old_tz = strdup(old_tz);
if (!old_tz) return E_NO_MEM;
}
if (tgt_tz == NULL || !*tgt_tz) {
@@ -4768,10 +4893,13 @@ rows_or_cols(func_info *info, int want_rows)
{
struct winsize w;
int fd = STDOUT_FILENO;
int opened = 0;
RetVal.type = INT_TYPE;
if (!isatty(fd)) {
/* Try STDERR fd if STDOUT fd is not a tty */
fd = STDERR_FILENO;
}
if (!isatty(fd)) {
fd = open("/dev/tty", O_RDONLY);
if (fd < 0) {
@@ -4798,16 +4926,14 @@ static int FRows(func_info *info)
}
static int FColumns(func_info *info)
{
#ifdef REM_USE_WCHAR
size_t len;
wchar_t *buf, *s;
int width;
#endif
if (Nargs == 0) {
return rows_or_cols(info, 0);
}
ASSERT_TYPE(0, STR_TYPE);
#ifdef REM_USE_WCHAR
len = mbstowcs(NULL, ARGSTR(0), 0);
if (len == (size_t) -1) return E_NO_MEM;
buf = calloc(len+1, sizeof(wchar_t));
@@ -4835,9 +4961,6 @@ static int FColumns(func_info *info)
RetVal.type = INT_TYPE;
RETVAL = width;
return OK;
#else
return E_BAD_TYPE;
#endif
}
/* The following sets of functions are for computing solstices and equinoxes.
@@ -5054,3 +5177,50 @@ print_builtinfunc_tokens(void)
printf("%s\n", Func[i].name);
}
}
static int mbupper_lower(func_info *info, int upper)
{
wchar_t *ws;
char *s;
size_t i, len;
int r;
ASSERT_TYPE(0, STR_TYPE);
len = mbstowcs(NULL, ARGSTR(0), 0);
if (len == (size_t) -1) {
return E_BAD_MB_SEQ;
}
ws = calloc(len+1, sizeof(wchar_t));
if (!ws) {
return E_NO_MEM;
}
(void) mbstowcs(ws, ARGSTR(0), len+1);
for (i=0; i<len; i++) {
if (upper) {
ws[i] = towupper(ws[i]);
} else {
ws[i] = towlower(ws[i]);
}
}
len = wcstombs(NULL, ws, 0);
s = calloc(len+1, 1);
if (!s) {
free(ws);
return E_NO_MEM;
}
(void) wcstombs(s, ws, len+1);
r = RetStrVal(s, info);
free(s);
free(ws);
return r;
}
static int FMblower(func_info *info)
{
return mbupper_lower(info, 0);
}
static int FMbupper(func_info *info)
{
return mbupper_lower(info, 1);
}

View File

@@ -8,7 +8,7 @@
/* globals.h and err.h */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -7,7 +7,7 @@
/* MK_GLOBALS. Also contains useful macro definitions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -106,6 +106,7 @@ EXTERN INIT( int DefaultPrio, NO_PRIORITY);
EXTERN INIT( int SysTime, -1);
EXTERN INIT( int LocalSysTime, -1);
EXTERN INIT( int ParseUntriggered, 0);
EXTERN INIT( int Shaded, 0);
EXTERN char const *InitialFile;
EXTERN char const *LocalTimeZone;
@@ -127,7 +128,7 @@ EXTERN INIT( int DefaultColorB, -1);
EXTERN INIT( int DefaultColorG, -1);
EXTERN INIT( int SynthesizeTags, 0);
EXTERN INIT( int ScFormat, SC_AMPM);
EXTERN INIT( int MaxSatIter, 1000);
EXTERN INIT( int MaxSatIter, 10000);
EXTERN INIT( int MaxStringLen, MAX_STR_LEN);
EXTERN INIT( int UseStdin, 0);
EXTERN INIT( int PurgeMode, 0);
@@ -146,6 +147,7 @@ EXTERN int ArgC;
EXTERN char const **ArgV;
EXTERN INIT( int CalLines, CAL_LINES);
EXTERN INIT( int CalPad, 1);
EXTERN INIT( int CalSepLine, 1);
EXTERN INIT( int UseVTChars, 0);
EXTERN INIT( int UseBGVTColors, 0);
EXTERN INIT( int UseUTF8Chars, 0);
@@ -170,6 +172,10 @@ EXTERN INIT( double Latitude, DEFAULT_LATITUDE);
EXTERN INIT( char *Location, LOCATION);
/* Support hyperlinks in terminal emulators?
https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
*/
EXTERN INIT( int TerminalHyperlinks, -1);
/* UTC calculation stuff */
EXTERN INIT( int MinsFromUTC, 0);
EXTERN INIT( int CalculateUTC, 1);

View File

@@ -5,7 +5,7 @@
/* Implementation of hash table. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Header file for hash-table related functions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Utility function to print hash table stats. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Support for the Hebrew calendar */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/* Derived from code written by Amos Shapir in 1978; revised */
@@ -61,10 +61,58 @@
#define ADAR2ADARA 1
#define ADAR2BOTH 2
struct AltMonthName {
char const *name;
int mon;
};
static char const *HebMonthNames[] = {
"Tishrey", "Heshvan", "Kislev", "Tevet", "Shvat", "Adar A", "Adar B",
"Nisan", "Iyar", "Sivan", "Tamuz", "Av", "Elul", "Adar"};
static char const *IvritMonthNames[] = {
"תשרי",
"חשוון",
"כסלו",
"טבת",
"שבט",
"אדר א'",
"אדר ב'",
"ניסן",
"אייר",
"סיון",
"תמוז",
"אב",
"אלול",
"אדר" };
/* Alternate spellings */
static struct AltMonthName AltMonthSpellings[] = {
{ "Tishri", TISHREY },
{ "Tishrei", TISHREY },
{ "Cheshvan", HESHVAN },
{ "Kheshvan", HESHVAN },
{ "Shevat", SHVAT },
{ "Tammuz", TAMUZ },
{ "Adar 1", ADARA },
{ "Adar I", ADARA },
{ "אדר א", ADARA },
{ "אדר 1", ADARA },
{ "אדר I", ADARA },
{ "Adar 2", ADARB },
{ "Adar II", ADARB },
{ "אדר ב", ADARB },
{ "אדר 2", ADARB },
{ "אדר II", ADARB },
{ "Iyyar", IYAR }
};
static char MaxMonLen[] = {
30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29, 29};
@@ -245,14 +293,32 @@ int HebNameToNum(char const *mname)
int i;
int m=-1;
for (i=0; i<14; i++)
if (!StrCmpi(mname, HebMonthNames[i])) {
for (i=0; i<14; i++) {
if (!strcasecmp(mname, HebMonthNames[i])) {
m = i;
break;
}
}
if (m == -1) {
for (i=0; i<14; i++) {
if (!strcmp(mname, IvritMonthNames[i])) {
m = i;
break;
}
}
}
/* Try the alternate spellings */
if (m == -1) {
for (i=0; i < (int) (sizeof(AltMonthSpellings) / sizeof(AltMonthSpellings[0])); i++) {
if (!strcasecmp(mname, AltMonthSpellings[i].name)) {
m = AltMonthSpellings[i].mon;
break;
}
}
}
return m;
}
}
/***************************************************************/
/* */
@@ -270,6 +336,22 @@ char const *HebMonthName(int m, int y)
else return HebMonthNames[m];
}
/***************************************************************/
/* */
/* IvritMonthname */
/* */
/* Convert a Hebrew month's number to its name in Hebrew */
/* script, given the year. */
/* */
/***************************************************************/
char const *IvritMonthName(int m, int y)
{
if (m != ADARA && m != ADARB) return IvritMonthNames[m];
if (!HebIsLeap[(y-1)%19]) return IvritMonthNames[ADAR];
else return IvritMonthNames[m];
}
/***************************************************************/
/* */
/* GetValidHebDate */

View File

@@ -5,7 +5,7 @@
/* Logic for tracking the state of the IF... ELSE... ENDIF */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -7,7 +7,7 @@
/* in normal mode. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -196,7 +196,7 @@ void InitRemind(int argc, char const *argv[])
/* Initialize local time zone */
LocalTimeZone = getenv("TZ");
if (LocalTimeZone) {
LocalTimeZone = StrDup(LocalTimeZone);
LocalTimeZone = strdup(LocalTimeZone);
if (!LocalTimeZone) {
fprintf(stderr, "Out of memory!\n");
exit(1);
@@ -514,6 +514,11 @@ void InitRemind(int argc, char const *argv[])
arg++;
continue;
}
if (*arg == 'z' || *arg == 'Z') {
TerminalHyperlinks = 1;
arg++;
continue;
}
if (*arg == 'c' || *arg == 'C') {
UseVTColors = 1;
arg++;
@@ -644,8 +649,17 @@ void InitRemind(int argc, char const *argv[])
}
if (*arg == ',') {
arg++;
PARSENUM(CalPad, arg);
if (CalPad > 20) CalPad = 20;
if (*arg != ',') {
PARSENUM(CalPad, arg);
if (CalPad > 20) CalPad = 20;
}
if (*arg == ',') {
arg++;
PARSENUM(CalSepLine, arg);
if (CalSepLine) {
CalSepLine = 1;
}
}
}
}
break;
@@ -654,6 +668,7 @@ void InitRemind(int argc, char const *argv[])
case 'D':
while (*arg) {
switch(*arg++) {
case 'p': case 'P': DebugFlag |= DB_PUSHPOP; break;
case 's': case 'S': DebugFlag |= DB_PARSE_EXPR; break;
case 'h': case 'H': DebugFlag |= DB_HASHSTATS; break;
case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break;
@@ -835,6 +850,15 @@ void InitRemind(int argc, char const *argv[])
(void) CalcMinsFromUTC(DSEToday, MinutesPastMidnight(0),
&MinsFromUTC, NULL);
}
/* If stdout is a tty, enable terminal hyperlinks by default */
if (TerminalHyperlinks == -1) {
if (isatty(STDOUT_FILENO)) {
TerminalHyperlinks = 1;
} else {
TerminalHyperlinks = 0;
}
}
}
/***************************************************************/
@@ -847,7 +871,7 @@ void InitRemind(int argc, char const *argv[])
#ifndef L_USAGE_OVERRIDE
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s Copyright (C) 1992-2025 Dianne Skoll\n", VERSION);
fprintf(ErrFp, "\nREMIND %s Copyright (C) 1992-2026 Dianne Skoll\n", VERSION);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif

View File

@@ -6,7 +6,7 @@
/* routines, etc. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -39,10 +39,8 @@
#include <time.h>
#include <sys/types.h>
#ifdef REM_USE_WCHAR
#include <wctype.h>
#include <wchar.h>
#endif
#include "types.h"
#include "protos.h"
@@ -64,12 +62,17 @@ exitfunc(void)
/* Kill any execution-time-limiter process */
unlimit_execution_time();
size_t num_mallocs, bytes_malloced;
if (DebugFlag & DB_UNUSED_VARS) {
DumpUnusedVars();
}
if (DebugFlag & DB_HASHSTATS) {
fflush(stdout);
fflush(ErrFp);
DBufGetMallocStats(&num_mallocs, &bytes_malloced);
fprintf(ErrFp, "DynBuf Mallocs: %lu mallocs; %lu bytes\n",
(unsigned long) num_mallocs, (unsigned long) bytes_malloced);
fprintf(ErrFp, "Variable hash table statistics:\n");
dump_var_hash_stats();
@@ -292,6 +295,7 @@ PerIterationInit(void)
DefaultColorG = -1;
DefaultColorB = -1;
NumTriggered = 0;
Shaded = 0;
JSONLinesEmitted = 0;
ClearLastTriggers();
ClearDedupeTable();
@@ -1385,6 +1389,12 @@ static int DoDebug(ParsePtr p)
val = 0;
break;
case 'p':
case 'P':
if (val) DebugFlag |= DB_PUSHPOP;
else DebugFlag &= ~DB_PUSHPOP;
break;
case 'e':
case 'E':
if (val) DebugFlag |= DB_ECHO_LINE;
@@ -1518,11 +1528,11 @@ int DoRun(ParsePtr p)
if ( (r=ParseToken(p, &buf)) ) return r;
/* Only allow RUN ON in top-level script */
if (! StrCmpi(DBufValue(&buf), "ON")) {
if (! strcasecmp(DBufValue(&buf), "ON")) {
if (TopLevel()) RunDisabled &= ~RUN_SCRIPT;
}
/* But allow RUN OFF anywhere */
else if (! StrCmpi(DBufValue(&buf), "OFF"))
else if (! strcasecmp(DBufValue(&buf), "OFF"))
RunDisabled |= RUN_SCRIPT;
else {
DBufFree(&buf);
@@ -1550,11 +1560,11 @@ int DoExpr(ParsePtr p)
if ( (r=ParseToken(p, &buf)) ) return r;
/* Only allow EXPR ON in top-level script */
if (! StrCmpi(DBufValue(&buf), "ON")) {
if (! strcasecmp(DBufValue(&buf), "ON")) {
if (TopLevel()) ExpressionEvaluationDisabled = 0;
}
/* But allow EXPR OFF anywhere */
else if (! StrCmpi(DBufValue(&buf), "OFF"))
else if (! strcasecmp(DBufValue(&buf), "OFF"))
ExpressionEvaluationDisabled = 1;
else {
DBufFree(&buf);
@@ -1730,7 +1740,6 @@ static char const *OutputEscapeSequences(char const *s, int print, DynamicBuffer
return s;
}
#ifdef REM_USE_WCHAR
#define ISWBLANK(c) (iswspace(c) && (c) != '\n')
static wchar_t const *OutputEscapeSequencesWS(wchar_t const *s, int print, DynamicBuffer *output)
{
@@ -1848,7 +1857,7 @@ FillParagraphWC(char const *s, DynamicBuffer *output)
free(buf);
return OK;
}
#endif
/***************************************************************/
/* */
/* FillParagraph */
@@ -1864,7 +1873,7 @@ FillParagraphWC(char const *s, DynamicBuffer *output)
/* A macro safe ONLY if used with arg with no side effects! */
#define ISBLANK(c) (isspace(c) && (c) != '\n')
void FillParagraph(char const *s, DynamicBuffer *output)
void FillParagraph(char const *url, char const *s, DynamicBuffer *output)
{
int line = 0;
@@ -1881,11 +1890,16 @@ void FillParagraph(char const *s, DynamicBuffer *output)
while(ISBLANK(*s)) s++;
if (!*s) return;
#ifdef REM_USE_WCHAR
if (url) {
printf("\x1B]8;;%s\x1B\\", url);
}
if (FillParagraphWC(s, output) == OK) {
if (url) {
printf("\x1B]8;;\x1B\\");
}
return;
}
#endif
/* Start formatting */
while(1) {
@@ -1899,6 +1913,9 @@ void FillParagraph(char const *s, DynamicBuffer *output)
continue;
}
if (!*s) {
if (url) {
printf("\x1B]8;;\x1B\\");
}
return;
}
/* Over here, we're at the beginning of a line. Emit the correct
@@ -1933,6 +1950,9 @@ void FillParagraph(char const *s, DynamicBuffer *output)
len++;
}
if (s == t) {
if (url) {
printf("\x1B]8;;\x1B\\");
}
return;
}
if (!pendspace || len+pendspace <= roomleft) {
@@ -2122,7 +2142,7 @@ SaveLastTrigger(Trigger const *t)
DBufInit(&(LastTrigger.tags));
if (LastTrigger.tz) {
LastTrigger.tz = StrDup(LastTrigger.tz);
LastTrigger.tz = strdup(LastTrigger.tz);
}
DBufPuts(&(LastTrigger.tags), DBufValue(&(t->tags)));
TrigInfo *cur = t->infos;

View File

@@ -5,7 +5,7 @@
/* Calculations for figuring out moon phases. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -6,7 +6,7 @@
/* the data structures for OMITted dates. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -176,8 +176,10 @@ int PopOmitContext(ParsePtr p)
/* Remove the context from the stack */
SavedOmitContexts = c->next;
if (c->filename && fname && strcmp(c->filename, fname)) {
Wprint(tr("POP-OMIT-CONTEXT at %s:%d matches PUSH-OMIT-CONTEXT in different file: %s:%d"), fname, LineNo, c->filename, c->lineno);
if (DebugFlag & DB_PUSHPOP) {
if (c->filename && fname && strcmp(c->filename, fname)) {
Wprint(tr("POP-OMIT-CONTEXT at %s:%d matches PUSH-OMIT-CONTEXT in different file: %s:%d"), fname, LineNo, c->filename, c->lineno);
}
}
/* Free memory used by the saved context */
if (c->partsave) free(c->partsave);
@@ -501,6 +503,9 @@ int DoOmit(ParsePtr p)
int
AddGlobalOmit(int dse)
{
if (dse < 0) {
return OK;
}
if (NumFullOmits == MAX_FULL_OMITS) return E_2MANY_FULL;
if (!BexistsIntArray(FullOmitArray, NumFullOmits, dse)) {
InsertIntoSortedArray(FullOmitArray, NumFullOmits, dse);

View File

@@ -5,7 +5,7 @@
/* Function Prototypes. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -13,20 +13,8 @@
/* Suppress unused variable warnings */
#define UNUSED(x) (void) x
#ifdef HAVE_STRDUP
#define StrDup strdup
#endif
#ifdef HAVE_STRNCASECMP
#define StrinCmp strncasecmp
#endif
#ifdef HAVE_STRCASECMP
#define StrCmpi strcasecmp
#endif
/* Define a string assignment macro - be careful!!! */
#define STRSET(x, str) { if (x) free(x); (x) = StrDup(str); }
#define STRSET(x, str) { if (x) free(x); (x) = strdup(str); }
/* Define a general malloc routine for creating pointers to objects */
#define NEW(type) (malloc(sizeof(type)))
@@ -131,18 +119,6 @@ int ComputeTriggerNoAdjustDuration (int today, Trigger *trig, TimeTrig const *ti
int AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int save_in_globals);
char *StrnCpy (char *dest, char const *source, int n);
#ifndef HAVE_STRNCASECMP
int StrinCmp (char const *s1, char const *s2, int n);
#endif
#ifndef HAVE_STRDUP
char *StrDup (char const *s);
#endif
#ifndef HAVE_STRCASECMP
int StrCmpi (char const *s1, char const *s2);
#endif
void strtolower(char *s);
Var *FindVar (char const *str, int create);
@@ -168,13 +144,14 @@ int ParseNonSpaceChar (ParsePtr p, int *err, int peek);
unsigned int HashVal_preservecase(char const *str);
int DateOK (int y, int m, int d);
BuiltinFunc *FindBuiltinFunc (char const *name);
int InsertIntoSortBuffer (int dse, int tim, char const *body, int typ, int prio);
int InsertIntoSortBuffer (int dse, int tim, char const *url, char const *body, int typ, int prio);
void IssueSortedReminders (void);
UserFunc *FindUserFunc(char const *name);
int UserFuncExists (char const *fn);
void DSEToHeb (int dse, int *hy, int *hm, int *hd);
int HebNameToNum (char const *mname);
char const *HebMonthName (int m, int y);
char const *IvritMonthName (int m, int y);
int HebToDSE (int hy, int hm, int hd);
int GetValidHebDate (int yin, int min, int din, int adarbehave, int *mout, int *dout, int yahr);
int GetNextHebrewDate (int dsestart, int hm, int hd, int yahr, int adarbehave, int *ans);
@@ -183,7 +160,7 @@ int GetSysVar (char const *name, Value *val);
int SetSysVar (char const *name, Value *val);
void DumpSysVarByName (char const *name);
int CalcMinsFromUTC (int dse, int tim, int *mins, int *isdst);
void FillParagraph (char const *s, DynamicBuffer *output);
void FillParagraph (char const *url, char const *s, DynamicBuffer *output);
void LocalToUTC (int locdate, int loctime, int *utcdate, int *utctime);
void UTCToLocal (int utcdate, int utctime, int *locdate, int *loctime);
int MoonPhase (int date, int time);
@@ -224,12 +201,10 @@ void FixSpecialType(Trigger *trig);
void WriteJSONTrigger(Trigger const *t, int include_tags);
void WriteJSONTimeTrigger(TimeTrig const *tt);
int GetOnceDate(void);
#ifdef REM_USE_WCHAR
#define _XOPEN_SOURCE 600
#include <wctype.h>
#include <wchar.h>
void PutWideChar(wchar_t const wc, DynamicBuffer *output);
#endif
/* These functions are in utils.c and are used to detect overflow
in various arithmetic operators. They have to be in separate

View File

@@ -5,7 +5,7 @@
/* Queue up reminders for subsequent execution. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -140,7 +140,7 @@ int QueueReminder(ParsePtr p, Trigger *trig,
TimeTrig const *tim, char const *sched)
{
QueuedRem *qelem;
TrigInfo *ti;
if (DontQueue ||
trig->noqueue ||
tim->ttime == NO_TIME ||
@@ -155,7 +155,7 @@ int QueueReminder(ParsePtr p, Trigger *trig,
qelem->red = DefaultColorR;
qelem->green = DefaultColorG;
qelem->blue = DefaultColorB;
qelem->text = StrDup(p->pos); /* Guaranteed that parser is not nested. */
qelem->text = strdup(p->pos); /* Guaranteed that parser is not nested. */
if (!qelem->text) {
free(qelem);
return E_NO_MEM;
@@ -169,8 +169,13 @@ int QueueReminder(ParsePtr p, Trigger *trig,
qelem->tt = *tim;
qelem->t = *trig;
/* Take over infos */
trig->infos = NULL;
/* Copy infos */
qelem->t.infos = NULL;
ti = trig->infos;
while(ti) {
(void) AppendTrigInfo(&qelem->t, ti->info);
ti = ti->next;
}
DBufInit(&(qelem->t.tags));
DBufPuts(&(qelem->t.tags), DBufValue(&(trig->tags)));

View File

@@ -5,7 +5,7 @@
/* Print a PostScript calendar. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -154,24 +154,6 @@ put_escaped_string(char const *s)
}
}
/***************************************************************/
/* */
/* StrCmpi */
/* */
/* Compare strings, case insensitive. */
/* */
/***************************************************************/
static int StrCmpi(char const *s1, char const *s2)
{
int r;
while (*s1 && *s2) {
r = toupper(*s1) - toupper(*s2);
if (r) return r;
s1++;
s2++;
}
return toupper(*s1) - toupper(*s2);
}
/***************************************************************/
/* */
/* Parse the new-style JSON intermediate format */
@@ -229,18 +211,18 @@ JSONToCalEntry(DynamicBuffer const *buf)
} else if (!strcmp(nm, "passthru")) {
if (v->type == json_string) {
s = v->u.string.ptr;
if (!StrCmpi(s, "PostScript")) {
if (!strcasecmp(s, "PostScript")) {
c->special = SPECIAL_POSTSCRIPT;
} else if (!StrCmpi(s, "SHADE")) {
} else if (!strcasecmp(s, "SHADE")) {
c->special = SPECIAL_SHADE;
} else if (!StrCmpi(s, "MOON")) {
} else if (!strcasecmp(s, "MOON")) {
c->special = SPECIAL_MOON;
} else if (!StrCmpi(s, "WEEK")) {
} else if (!strcasecmp(s, "WEEK")) {
c->special = SPECIAL_WEEK;
} else if (!StrCmpi(s, "PSFile")) {
} else if (!strcasecmp(s, "PSFile")) {
c->special = SPECIAL_PSFILE;
} else if (!StrCmpi(s, "COLOUR") ||
!StrCmpi(s, "COLOR")) {
} else if (!strcasecmp(s, "COLOUR") ||
!strcasecmp(s, "COLOR")) {
c->special = SPECIAL_COLOR;
} else {
c->special = SPECIAL_UNKNOWN;
@@ -301,20 +283,20 @@ TextToCalEntry(DynamicBuffer *buf)
strcpy(c->entry, startOfBody);
/* Save the type of SPECIAL */
if (!StrCmpi(passthru, "PostScript")) {
if (!strcasecmp(passthru, "PostScript")) {
c->special = SPECIAL_POSTSCRIPT;
} else if (!StrCmpi(passthru, "SHADE")) {
} else if (!strcasecmp(passthru, "SHADE")) {
c->special = SPECIAL_SHADE;
} else if (!StrCmpi(passthru, "MOON")) {
} else if (!strcasecmp(passthru, "MOON")) {
c->special = SPECIAL_MOON;
} else if (!StrCmpi(passthru, "WEEK")) {
} else if (!strcasecmp(passthru, "WEEK")) {
c->special = SPECIAL_WEEK;
} else if (!StrCmpi(passthru, "PSFile")) {
} else if (!strcasecmp(passthru, "PSFile")) {
c->special = SPECIAL_PSFILE;
} else if (!StrCmpi(passthru, "COLOUR") ||
!StrCmpi(passthru, "COLOR")) {
} else if (!strcasecmp(passthru, "COLOUR") ||
!strcasecmp(passthru, "COLOR")) {
c->special = SPECIAL_COLOR;
} else if (StrCmpi(passthru, "*")) {
} else if (strcasecmp(passthru, "*")) {
c->special = SPECIAL_UNKNOWN;
}
return c;
@@ -350,7 +332,7 @@ int main(int argc, char const *argv[])
!strcmp(DBufValue(&buf), PSBEGIN2)) {
if (!validfile) {
if (Verbose) {
fprintf(stderr, "Rem2PS: Version %s Copyright (C) 1992-2025 by Dianne Skoll\n\n", VERSION);
fprintf(stderr, "Rem2PS: Version %s Copyright (C) 1992-2026 by Dianne Skoll\n\n", VERSION);
fprintf(stderr, "Generating PostScript calendar\n");
}
}
@@ -1003,6 +985,14 @@ static void Init(int argc, char const *argv[])
case 'e': FillPage = 1; break;
case '-':
if (!strcmp(s, "version")) {
printf("rem2ps version %s\n", VERSION);
exit(0);
}
Usage("Unrecognized option");
break;
default: Usage("Unrecognized option");
}
}
@@ -1034,6 +1024,7 @@ void Usage(char const *s)
fprintf(stderr, "-e Make calendar fill entire page\n");
fprintf(stderr, "-x Put day numbers on left instead of right\n");
fprintf(stderr, "-o[lrtb] marg Specify left, right, top and bottom margins\n");
fprintf(stderr, "--version Print the version of rem2ps and exit\n");
exit(EXIT_FAILURE);
}

View File

@@ -5,7 +5,7 @@
/* Define the PostScript prologue */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -14,7 +14,7 @@ char *PSProlog1[] =
{
"% This file was produced by Remind and Rem2PS, written by",
"% Dianne Skoll.",
"% Remind and Rem2PS are Copyright (C) 1992-2025 Dianne Skoll.",
"% Remind and Rem2PS are Copyright (C) 1992-2026 Dianne Skoll.",
"/ISOLatin1Encoding where { pop save true }{ false } ifelse",
" /ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus",
" StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute",

View File

@@ -5,7 +5,7 @@
/* Routines for sorting reminders by trigger date */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -25,6 +25,7 @@
typedef struct sortrem {
struct sortrem *next;
char const *text;
char const *url;
int trigdate;
int trigtime;
int typ;
@@ -34,7 +35,7 @@ typedef struct sortrem {
/* The sorted reminder queue */
static Sortrem *SortedQueue = (Sortrem *) NULL;
static Sortrem *MakeSortRem (int dse, int tim, char const *body, int typ, int prio);
static Sortrem *MakeSortRem (int dse, int tim, char const *url, char const *body, int typ, int prio);
static void IssueSortBanner (int dse);
/***************************************************************/
@@ -44,23 +45,33 @@ static void IssueSortBanner (int dse);
/* Create a new Sortrem entry - return NULL on failure. */
/* */
/***************************************************************/
static Sortrem *MakeSortRem(int dse, int tim, char const *body, int typ, int prio)
static Sortrem *MakeSortRem(int dse, int tim, char const *url, char const *body, int typ, int prio)
{
Sortrem *new = NEW(Sortrem);
if (!new) return NULL;
Sortrem *srem = NEW(Sortrem);
if (!srem) return NULL;
new->text = StrDup(body);
if (!new->text) {
free(new);
srem->text = strdup(body);
if (!srem->text) {
free(srem);
return NULL;
}
new->trigdate = dse;
new->trigtime = tim;
new->typ = typ;
new->priority = prio;
new->next = NULL;
return new;
if (url) {
srem->url = strdup(url);
if (!srem->url) {
free((char *) srem->text);
free(srem);
return NULL;
}
} else {
srem->url = NULL;
}
srem->trigdate = dse;
srem->trigtime = tim;
srem->typ = typ;
srem->priority = prio;
srem->next = NULL;
return srem;
}
/***************************************************************/
@@ -70,13 +81,13 @@ static Sortrem *MakeSortRem(int dse, int tim, char const *body, int typ, int pri
/* Insert a reminder into the sort buffer */
/* */
/***************************************************************/
int InsertIntoSortBuffer(int dse, int tim, char const *body, int typ, int prio)
int InsertIntoSortBuffer(int dse, int tim, char const *url, char const *body, int typ, int prio)
{
Sortrem *new = MakeSortRem(dse, tim, body, typ, prio);
Sortrem *srem = MakeSortRem(dse, tim, url, body, typ, prio);
Sortrem *cur = SortedQueue, *prev = NULL;
int ShouldGoAfter;
if (!new) {
if (!srem) {
Eprint("%s", GetErr(E_NO_MEM));
IssueSortedReminders();
SortByDate = 0;
@@ -88,11 +99,11 @@ int InsertIntoSortBuffer(int dse, int tim, char const *body, int typ, int prio)
/* Find the correct place in the sorted list */
if (!SortedQueue) {
SortedQueue = new;
SortedQueue = srem;
return OK;
}
while (cur) {
ShouldGoAfter = CompareRems(new->trigdate, new->trigtime, new->priority,
ShouldGoAfter = CompareRems(srem->trigdate, srem->trigtime, srem->priority,
cur->trigdate, cur->trigtime, cur->priority,
SortByDate, SortByTime, SortByPrio, UntimedBeforeTimed);
@@ -101,22 +112,21 @@ int InsertIntoSortBuffer(int dse, int tim, char const *body, int typ, int prio)
cur = cur->next;
} else {
if (prev) {
prev->next = new;
new->next = cur;
prev->next = srem;
srem->next = cur;
} else {
SortedQueue = new;
new->next = cur;
SortedQueue = srem;
srem->next = cur;
}
return OK;
}
}
prev->next = new;
new->next = cur; /* For safety - actually redundant */
prev->next = srem;
srem->next = cur; /* For safety - actually redundant */
return OK;
}
/***************************************************************/
/* */
/* IssueSortedReminders */
@@ -141,7 +151,13 @@ void IssueSortedReminders(void)
IssueSortBanner(cur->trigdate);
olddate = cur->trigdate;
}
if (cur->url) {
printf("\x1B]8;;%s\x1B\\", cur->url);
}
printf("%s", cur->text);
if (cur->url) {
printf("\x1B]8;;\x1B\\");
}
}
break;
@@ -150,7 +166,7 @@ void IssueSortedReminders(void)
IssueSortBanner(cur->trigdate);
olddate = cur->trigdate;
}
FillParagraph(cur->text, NULL);
FillParagraph(cur->url, cur->text, NULL);
break;
case RUN_TYPE:
@@ -159,6 +175,9 @@ void IssueSortedReminders(void)
}
free((char *) cur->text);
if (cur->url) {
free((char *) cur->url);
}
free(cur);
cur = next;
}

View File

@@ -6,7 +6,7 @@
/* classifying the tokens parsed. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -48,6 +48,7 @@ Token TokArray[] = {
{ "cal", 3, T_RemType, CAL_TYPE },
{ "clear-omit-context", 5, T_Clr, 0 },
{ "complete-through", 16, T_CompleteThrough, 0 },
{ "completed-through", 17, T_CompleteThrough, 0 },
{ "debug", 5, T_Debug, 0 },
{ "december", 3, T_Month, 11 },
{ "do", 2, T_IncludeR, 0 },

View File

@@ -6,7 +6,7 @@
/* the TRANSLATE keyword. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -443,19 +443,19 @@ DoTranslate(ParsePtr p)
r = ParseToken(p, &orig);
if (r) return r;
r = VerifyEoln(p);
if (!StrCmpi(DBufValue(&orig), "dump")) {
if (!strcasecmp(DBufValue(&orig), "dump")) {
DBufFree(&orig);
if (r) return r;
DumpTranslationTable(stdout, 0);
return OK;
}
if (!StrCmpi(DBufValue(&orig), "clear")) {
if (!strcasecmp(DBufValue(&orig), "clear")) {
DBufFree(&orig);
if (r) return r;
ClearTranslationTable();
return OK;
}
if (!StrCmpi(DBufValue(&orig), "generate")) {
if (!strcasecmp(DBufValue(&orig), "generate")) {
DBufFree(&orig);
if (r) return r;
GenerateTranslationTemplate();

View File

@@ -5,7 +5,7 @@
/* Routines for figuring out the trigger date of a reminder */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -738,7 +738,7 @@ NewTrigInfo(char const *i)
return NULL;
}
ti->next = NULL;
ti->info = StrDup(i);
ti->info = strdup(i);
if (!ti->info) {
free(ti);
return NULL;

View File

@@ -5,7 +5,7 @@
/* Type definitions all dumped here. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -221,18 +221,19 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
#define NO_MAX 127
/* DEFINES for debugging flags */
#define DB_PRTLINE 0x001
#define DB_PRTEXPR 0x002
#define DB_PRTTRIG 0x004
#define DB_DUMP_VARS 0x008
#define DB_ECHO_LINE 0x010
#define DB_TRACE_FILES 0x020
#define DB_PARSE_EXPR 0x040
#define DB_HASHSTATS 0x080
#define DB_TRANSLATE 0x100
#define DB_NONCONST 0x200
#define DB_UNUSED_VARS 0x400
#define DB_SWITCH_ZONE 0x800
#define DB_PRTLINE 0x0001
#define DB_PRTEXPR 0x0002
#define DB_PRTTRIG 0x0004
#define DB_DUMP_VARS 0x0008
#define DB_ECHO_LINE 0x0010
#define DB_TRACE_FILES 0x0020
#define DB_PARSE_EXPR 0x0040
#define DB_HASHSTATS 0x0080
#define DB_TRANSLATE 0x0100
#define DB_NONCONST 0x0200
#define DB_UNUSED_VARS 0x0400
#define DB_SWITCH_ZONE 0x0800
#define DB_PUSHPOP 0x1000
/* Enumeration of the tokens */
enum TokTypes

View File

@@ -6,7 +6,7 @@
/* functions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -318,7 +318,7 @@ int DoFset(ParsePtr p)
}
/* If we've already seen this local variable, error */
for (i=0; i<func->nargs; i++) {
if (!StrinCmp(DBufValue(&buf), local_array[i].name, VAR_NAME_LEN)) {
if (!strncasecmp(DBufValue(&buf), local_array[i].name, VAR_NAME_LEN)) {
DBufFree(&buf);
DestroyUserFunc(func);
return E_REPEATED_ARG;
@@ -393,7 +393,7 @@ int DoFset(ParsePtr p)
return E_NO_MEM;
}
for (i=0; i<func->nargs; i++) {
func->args[i] = StrDup(local_array[i].name);
func->args[i] = strdup(local_array[i].name);
if (!func->args[i]) {
DestroyUserFunc(func);
return E_NO_MEM;
@@ -619,7 +619,7 @@ static UserFunc *clone_userfunc(char const *name, int *r)
return NULL;
}
for (i=0; i<dest->nargs; i++) {
dest->args[i] = StrDup(src->args[i]);
dest->args[i] = strdup(src->args[i]);
if (!dest->args[i]) {
DestroyUserFunc(dest);
return NULL;
@@ -744,8 +744,10 @@ int PopUserFuncs(ParsePtr p)
return E_POPF_NO_PUSH;
}
UserFuncStack = UserFuncStack->next;
if (strcmp(pf->filename, GetCurrentFilename())) {
Wprint(tr("POP-FUNCS at %s:%d matches PUSH-FUNCS in different file: %s:%d"), GetCurrentFilename(), LineNo, pf->filename, pf->lineno);
if (DebugFlag & DB_PUSHPOP) {
if (strcmp(pf->filename, GetCurrentFilename())) {
Wprint(tr("POP-FUNCS at %s:%d matches PUSH-FUNCS in different file: %s:%d"), GetCurrentFilename(), LineNo, pf->filename, pf->lineno);
}
}
for (i=0; i<pf->num_funcs; i++) {
UserFunc *clone = pf->funcs[i];

View File

@@ -5,7 +5,7 @@
/* Useful utility functions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -140,67 +140,6 @@ char *StrnCpy(char *dest, char const *source, int n)
return odest;
}
#ifndef HAVE_STRNCASECMP
/***************************************************************/
/* */
/* StrinCmp - compare strings, case-insensitive */
/* */
/***************************************************************/
int StrinCmp(char const *s1, char const *s2, int n)
{
register int r;
while (n && *s1 && *s2) {
n--;
r = toupper(*s1) - toupper(*s2);
if (r) return r;
s1++;
s2++;
}
if (n) return (toupper(*s1) - toupper(*s2)); else return 0;
}
#endif
#ifndef HAVE_STRDUP
/***************************************************************/
/* */
/* StrDup */
/* */
/* Like ANSI strdup */
/* */
/***************************************************************/
char *StrDup(char const *s)
{
char *ret = malloc(strlen(s)+1);
if (!ret) return NULL;
strcpy(ret, s);
return ret;
}
#endif
#ifndef HAVE_STRCASECMP
/***************************************************************/
/* */
/* StrCmpi */
/* */
/* Compare strings, case insensitive. */
/* */
/***************************************************************/
int StrCmpi(char const *s1, char const *s2)
{
int r;
while (*s1 && *s2) {
r = toupper(*s1) - toupper(*s2);
if (r) return r;
s1++;
s2++;
}
return toupper(*s1) - toupper(*s2);
}
#endif
/***************************************************************/
/* */
/* DateOK */

View File

@@ -6,7 +6,7 @@
/* user- and system-defined variables. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* Copyright (C) 1992-2026 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -52,7 +52,7 @@ static int VarCompareFunc(void const *a, void const *b)
{
Var *x = (Var *) a;
Var *y = (Var *) b;
return StrCmpi(x->name, y->name);
return strcasecmp(x->name, y->name);
}
void
@@ -172,7 +172,7 @@ static int latitude_longitude_func(int do_set, Value *val, double *var, double m
} else {
if (val->type != STR_TYPE) return E_BAD_TYPE;
x = strtod_in_c_locale(val->v.str, &endptr);
if (*endptr) return E_BAD_TYPE;
if (*endptr) return E_BAD_VAL_FOR_SYSVAR;
}
if (x < min) return E_2LOW;
if (x > max) return E_2HIGH;
@@ -220,15 +220,15 @@ static int warning_level_func(int do_set, Value *val)
if (!strcmp(val->v.str, VERSION)) {
WarningLevel = NULL;
} else {
WarningLevel = StrDup(val->v.str);
WarningLevel = strdup(val->v.str);
if (!WarningLevel) return E_NO_MEM;
}
return OK;
}
if (!WarningLevel) {
val->v.str = StrDup(VERSION);
val->v.str = strdup(VERSION);
} else {
val->v.str = StrDup(WarningLevel);
val->v.str = strdup(WarningLevel);
}
if (!val->v.str) {
return E_NO_MEM;
@@ -257,14 +257,14 @@ static int oncefile_func(int do_set, Value *val)
if (OnceFile) {
free( (void *) OnceFile);
}
OnceFile = StrDup(val->v.str);
OnceFile = strdup(val->v.str);
if (!OnceFile) return E_NO_MEM;
return OK;
}
if (!OnceFile) {
val->v.str = StrDup("");
val->v.str = strdup("");
} else {
val->v.str = StrDup(OnceFile);
val->v.str = strdup(OnceFile);
}
if (!val->v.str) return E_NO_MEM;
val->type = STR_TYPE;
@@ -403,6 +403,14 @@ static int trig_wday_func(int do_set, Value *val)
return OK;
}
/* Cache $Ud, $Um and $Uy */
static int Ucached = -1;
static int Udcached = -1;
static int Umcached = -1;
static int Uycached = -1;
#define FILL_U_CACHE(x) do { if (Ucached != x) { FromDSE(x, &Uycached, &Umcached, &Udcached); Ucached = x; } } while(0)
static int today_date_func(int do_set, Value *val)
{
UNUSED(do_set);
@@ -412,31 +420,28 @@ static int today_date_func(int do_set, Value *val)
}
static int today_day_func(int do_set, Value *val)
{
int d;
UNUSED(do_set);
val->type = INT_TYPE;
FromDSE(DSEToday, NULL, NULL, &d);
val->v.val = d;
FILL_U_CACHE(DSEToday);
val->v.val = Udcached;
return OK;
}
static int today_mon_func(int do_set, Value *val)
{
int m;
UNUSED(do_set);
val->type = INT_TYPE;
FromDSE(DSEToday, NULL, &m, NULL);
val->v.val = m+1;
FILL_U_CACHE(DSEToday);
val->v.val = Umcached + 1;
return OK;
}
static int today_year_func(int do_set, Value *val)
{
int y;
UNUSED(do_set);
val->type = INT_TYPE;
FromDSE(DSEToday, &y, NULL, NULL);
val->v.val = y;
FILL_U_CACHE(DSEToday);
val->v.val = Uycached;
return OK;
}
@@ -461,7 +466,7 @@ static int datetime_sep_func(int do_set, Value *val)
if (val->type != STR_TYPE) return E_BAD_TYPE;
if (strcmp(val->v.str, "T") &&
strcmp(val->v.str, "@")) {
return E_BAD_TYPE;
return E_BAD_VAL_FOR_SYSVAR;
}
DateTimeSep = val->v.str[0];
return OK;
@@ -507,7 +512,7 @@ static int default_color_func(int do_set, Value *val)
}
if (val->type != STR_TYPE) return E_BAD_TYPE;
if (sscanf(val->v.str, "%d %d %d", &col_r, &col_g, &col_b) != 3) {
return E_BAD_TYPE;
return E_BAD_VAL_FOR_SYSVAR;
}
/* They either all have to be -1, or all between 0 and 255 */
if (col_r == -1 && col_g == -1 && col_b == -1) {
@@ -542,7 +547,7 @@ static int date_sep_func(int do_set, Value *val)
if (val->type != STR_TYPE) return E_BAD_TYPE;
if (strcmp(val->v.str, "/") &&
strcmp(val->v.str, "-")) {
return E_BAD_TYPE;
return E_BAD_VAL_FOR_SYSVAR;
}
DateSep = val->v.str[0];
return OK;
@@ -561,7 +566,7 @@ static int time_sep_func(int do_set, Value *val)
if (val->type != STR_TYPE) return E_BAD_TYPE;
if (strcmp(val->v.str, ":") &&
strcmp(val->v.str, ".")) {
return E_BAD_TYPE;
return E_BAD_VAL_FOR_SYSVAR;
}
TimeSep = val->v.str[0];
return OK;
@@ -1096,6 +1101,7 @@ static SysVar SysVarArr[] = {
{"RunOff", 0, INT_TYPE, &RunDisabled, 0, 0 },
{"Saturday", 1, TRANS_TYPE, "Saturday", 0, 0 },
{"September", 1, TRANS_TYPE, "September", 0, 0 },
{"Shaded" , 0, INT_TYPE, &Shaded, 0, 0 },
{"SimpleCal", 0, INT_TYPE, &DoSimpleCalendar, 0, 0 },
{"SortByDate", 0, INT_TYPE, &SortByDate, 0, 0 },
{"SortByPrio", 0, INT_TYPE, &SortByPrio, 0, 0 },
@@ -1109,6 +1115,7 @@ static SysVar SysVarArr[] = {
{"Tb", 0, SPECIAL_TYPE, trig_base_func, 0, 0 },
{"Td", 0, SPECIAL_TYPE, trig_day_func, 0, 0 },
{"TerminalBackground", 0, SPECIAL_TYPE, terminal_bg_func, 0, 0 },
{"TerminalHyperlinks", 1, INT_TYPE, &TerminalHyperlinks, 0, 1 },
{"Thursday", 1, TRANS_TYPE, "Thursday", 0, 0 },
{"TimeSep", 1, SPECIAL_TYPE, time_sep_func, 0, 0 },
{"TimetIs64bit", 0, SPECIAL_TYPE, timet_is_64_func, 0, 0 },
@@ -1337,8 +1344,10 @@ PopVars(ParsePtr p)
return E_POPV_NO_PUSH;
}
VarStack = VarStack->next;
if (strcmp(pv->filename, GetCurrentFilename())) {
Wprint(tr("POP-VARS at %s:%d matches PUSH-VARS in different file: %s:%d"), GetCurrentFilename(), LineNo, pv->filename, pv->lineno);
if (DebugFlag & DB_PUSHPOP) {
if (strcmp(pv->filename, GetCurrentFilename())) {
Wprint(tr("POP-VARS at %s:%d matches PUSH-VARS in different file: %s:%d"), GetCurrentFilename(), LineNo, pv->filename, pv->lineno);
}
}
/* Pop the sysvars */
@@ -1397,9 +1406,9 @@ static int GetTranslatableVariable(SysVar const *v, Value *value)
{
char const *translated = tr((char const *) v->value);
if (translated) {
value->v.str = StrDup(translated);
value->v.str = strdup(translated);
} else {
value->v.str = StrDup("");
value->v.str = strdup("");
}
if (!value->v.str) return E_NO_MEM;
value->type = STR_TYPE;
@@ -1491,9 +1500,9 @@ int GetSysVar(char const *name, Value *val)
return f(0, val);
} else if (v->type == STR_TYPE) {
if (! * (char **) v->value) {
val->v.str = StrDup("");
val->v.str = strdup("");
} else {
val->v.str = StrDup(*((char **) v->value));
val->v.str = strdup(*((char **) v->value));
}
if (!val->v.str) return E_NO_MEM;
} else {
@@ -1524,7 +1533,7 @@ SysVar *FindSysVar(char const *name)
int r;
while (top >= bottom) {
r = StrCmpi(name, SysVarArr[mid].name);
r = strcasecmp(name, SysVarArr[mid].name);
if (!r) return &SysVarArr[mid];
else if (r>0) bottom = mid+1;
else top = mid-1;

View File

@@ -76,10 +76,12 @@ COLOUR
CONTEXTs
CPAN
CPP's
CPUs
CalMode
CalType
CalcMinsFromUTC
CalcUTC
Chanukah
Clément
Config
Conover
@@ -135,6 +137,7 @@ Emanuele
EndSent
EndSentIg
EntrySize
Esc
Example2
Expr
ExpressionTimeLimit
@@ -158,6 +161,7 @@ FreeBSD
Fromnow
GPL
Gedalia
Georg
Getopt
GhostView
Gurman
@@ -210,6 +214,7 @@ Joop
Kamens
Kasdorp
Katan
Kheshvan
Kiefte
Koningsdag
Kristian
@@ -243,6 +248,9 @@ MSC
MSF
MSGPREFIX
MSGSUFFIX
MUSL
MUSL
MUSL's
Madsen
Makefile
Makefiles
@@ -397,9 +405,11 @@ Tcl
Td
Terbeck
TerminalBackground
TerminalHyperlinks
Thronicke
TimeSep
TimetIs64bit
Tishrei
Tishrey
TitleSize
Tk
@@ -533,6 +543,7 @@ difftime
doesn
dosubst
doublequote
dp
dq
dqi
dqis
@@ -591,6 +602,7 @@ gaa
garbhol
gcc
getenv
glibc's
grey
greyed
gridline
@@ -635,6 +647,7 @@ itkpdf
itkprint
itkremind
ivar
ivritmon
j2
jahr
jahrzeit
@@ -675,8 +688,12 @@ maxlen
maybexs
mbchar
mbindex
mblower
mbpad
mbstowcs
mbstrlen
mbsubstr
mbupper
md
memcpy
messageBox
@@ -768,6 +785,7 @@ popen
pp12
pp3
ppp
ppp12
pre
preprocessor
prev
@@ -822,6 +840,7 @@ soleq
somefile
sortbanner
spc
spc2
spellintian
src
srczone
@@ -942,6 +961,8 @@ varname
ve
w0
wakeups
wchar
wcstombs
weekno
wfun
whoami
@@ -962,6 +983,7 @@ xsiz
xsiz1
y1
y2
yaag
year1
year2
yeardiff
@@ -976,3 +998,21 @@ ziens
zj
zn
één
π
א
אב
אדר
אדר
אדר
אייר
אלול
ב
חשוון
טבת
כסלו
ניסן
ניסן
סיון
שבט
תמוז
תשרי

15
tests/shaded.rem Normal file
View File

@@ -0,0 +1,15 @@
REM Wed SPECIAL SHADE 255 0 0
IF !$Shaded
REM 15 SPECIAL SHADE 0 255 0
ENDIF
IF !$Shaded
REM SATISFY [$Td % 4 == 0] SPECIAL SHADE 0 0 255
ENDIF
IF !$Shaded
REM Sunday SPECIAL SHADE 0 255 255
ENDIF
IF !$Shaded
REM SPECIAL SHADE 255 255 0
ENDIF

4
tests/test-pushpop1.rem Normal file
View File

@@ -0,0 +1,4 @@
PUSH-OMIT-CONTEXT
PUSH-FUNCS a b c
PUSH-VARS a b c
DO test-pushpop2.rem

4
tests/test-pushpop2.rem Normal file
View File

@@ -0,0 +1,4 @@
POP-VARS
POP-FUNCS
POP-OMIT-CONTEXT

View File

@@ -7,7 +7,7 @@
# in the build directory.
#
# This file is part of REMIND.
# Copyright (C) 1992-2025 Dianne Skoll
# Copyright (C) 1992-2026 Dianne Skoll
# SPDX-License-Identifier: GPL-2.0-only
# ---------------------------------------------------------------------------
@@ -35,8 +35,14 @@ CMP="../tests/test.cmp"
# Set a known timezone so moon phases show up in predictable places
TZ=UTC
export TZ
# No localization, but we want a UTF-8 locale.
LANG=C.UTF-8
export LANG
LC_ALL=C.UTF-8
export LC_ALL
unset LC_PAPER
# Check if "grep" accepts "-a" flag
echo TEST | grep -a TEST > /dev/null 2>&1
@@ -66,25 +72,6 @@ else
DELAY=1
fi
# If we're already in a utf-8 locale, do
# nothing; otherwise, set LC_ALL
OK=0
if echo $LC_ALL | grep -i utf-8 > /dev/null 2>&1 ; then
OK=1
fi
if test -z "$LC_ALL" ; then
if echo $LANG | grep -i utf-8 > /dev/null 2>&1 ; then
export LC_ALL="$LANG"
OK=1
fi
fi
if test "$OK" = 0 ; then
export LC_ALL=C.UTF-8
export LANG=C.UTF-8
fi
chmod 000 include_dir/04cantread.rem
TEST_GETENV="foo bar baz" ; export TEST_GETENV
echo "Test 1" > $OUT
@@ -468,8 +455,8 @@ $REMIND -c ../tests/test-addomit.rem 1 Sep 2021 >> $OUT
$REMIND -cu ../tests/utf-8.rem 1 Nov 2019 >> $OUT
$REMIND -cu '-i$SuppressLRM=1' ../tests/utf-8.rem 1 Nov 2019 >> $OUT
TZ=America/Toronto $REMIND -dxe ../tests/tz.rem >> $OUT 2>&1
TZ=Europe/Berlin $REMIND -dxe ../tests/tz.rem >> $OUT 2>&1
TZ=America/Toronto $REMIND -dxe ../tests/tz.rem 2026-02-01 >> $OUT 2>&1
TZ=Europe/Berlin $REMIND -dxe ../tests/tz.rem 2026-02-01 >> $OUT 2>&1
$REMIND ../tests/soleq.rem 1 April 2044 >> $OUT 2>&1
@@ -492,18 +479,18 @@ echo "REM May 22 +10 MSG Bar %b" | $REMIND -tz - 2023-05-21 >> $OUT 2>&1
rm -rf include_dir/ww
touch include_dir/ww
chmod 0666 include_dir/ww
$REMIND include_dir/ww >> $OUT 2>&1
$REMIND include_dir/ww 2026-02-01 >> $OUT 2>&1
rm -rf include_dir/ww
# World-writable directory
mkdir -p include_dir/ww
touch include_dir/ww/0.rem
chmod 0777 include_dir/ww
$REMIND include_dir/ww >> $OUT 2>&1
$REMIND include_dir/ww 2026-02-01 >> $OUT 2>&1
rm -rf include_dir/ww
# This segfaulted in 04.02.03
$REMIND -h '-imsgprefix(x)="foo"' /dev/null >> $OUT 2>&1
$REMIND -h '-imsgprefix(x)="foo"' /dev/null 2026-02-01 >> $OUT 2>&1
# Test --version long option
$REMIND --version >> $OUT 2>&1
@@ -598,19 +585,19 @@ EOF
(echo 'BANNER %'; echo 'REM 29 MSG No bug') | $REMIND -dt - 29 Feb 2024 >> $OUT 2>&1
$REMIND -ifoo - <<'EOF' >> $OUT 2>&1
$REMIND -ifoo - 2026-02-01 <<'EOF' >> $OUT 2>&1
BANNER %
DUMP
EOF
$REMIND '-i$AddBlankLines' - <<'EOF' >> $OUT 2>&1
$REMIND '-i$AddBlankLines' - 2026-02-01 <<'EOF' >> $OUT 2>&1
BANNER %
DUMP $AddBlankLines
EOF
$REMIND ../tests/expr.rem >> $OUT 2>&1
$REMIND ../tests/expr.rem 2026-02-01 >> $OUT 2>&1
$REMIND - <<'EOF' >> $OUT 2>&1
$REMIND - 2026-02-01 <<'EOF' >> $OUT 2>&1
PUSH
POP
PUSH
@@ -694,9 +681,18 @@ If hunspell is installed, its output (if any) follows...
EOF
HUNSPELL="hunspell -d en_US -l -p manpage-personal-dict"
GOT_HUNSPELL=0
$HUNSPELL /dev/null < /dev/null > /dev/null 2>&1
if test $? = 0; then
# Hunspell runs. Do we have the en_US dictionary?
if test $? = 0 ; then
X=`(echo color; echo colour; echo returm) | hunspell -d en_US -l 2>/dev/null`
X=`echo $X | sed -e 's/\n/ /g'`
if test "$X" = "colour returm" ; then
GOT_HUNSPELL=1
fi
fi
if test "$GOT_HUNSPELL" = "1"; then
echo "Spell-checking man pages, WHATSNEW and README.md"
cat ../man/*.1 $PERLMANS | $HUNSPELL -n >> $OUT 2>&1
cat ../docs/WHATSNEW | $HUNSPELL >> $OUT 2>&1
@@ -713,7 +709,7 @@ echo "" >> $OUT
$REMIND --print-tokens < /dev/null >> $OUT 2>&1
# Torture test #2
$REMIND ../tests/torture2.rem >> $OUT 2>&1
$REMIND ../tests/torture2.rem 2026-02-01 >> $OUT 2>&1
# Expression error-reporting
$REMIND -de - 1 Feb 2024 <<'EOF' >> $OUT 2>&1
@@ -814,10 +810,10 @@ REM Wed MSG Wookie
EOF
# Test year-folding
TZ=America/Toronto $REMIND -dx ../tests/yearfold.rem >> $OUT 2>&1
TZ=America/Toronto $REMIND -dx ../tests/yearfold.rem 2026-02-01 >> $OUT 2>&1
# Test unused-variable debugging
$REMIND -du - <<'EOF' >> $OUT 2>&1
$REMIND -du - 2026-02-01 <<'EOF' >> $OUT 2>&1
set a 1
set b a*2
set c "What"
@@ -954,7 +950,49 @@ REM 2025 Oct [1] MSG Expr but not nonconst [today()]
REM 2025-10-01 MSG No expr seen [1+2]
EOF
# Purge mode
# Early exit from calendar processing
$REMIND -p - 2026-01-01 <<'EOF' >> $OUT 2>&1
REM 1 Jan 1994 MSG 1/0 = [1/0]
EOF
# No early exit from calendar processing
$REMIND -p - 2026-01-01 <<'EOF' >> $OUT 2>&1
SET $ParseUntriggered 1
REM 1 Jan 1994 MSG 1/0 = [1/0]
EOF
# Calendars with hyperlinks
$REMIND -w,0,0 -@2 -c - 1 Jan 2020 <<'EOF' >> $OUT 2>&1
SET $TerminalHyperlinks 1
REM 15 INFO "Url: https://dianne.skoll.ca" MSG Hello, linky!
REM 16 INFO "Url: https://dianne.skoll.ca" MSF Hello, linky!
REM 17 INFO "Url: https://dianne.skoll.ca" CAL Hello, linky!
REM 18 INFO "Url: https://dianne.skoll.ca" SPECIAL COLOR 255 0 0 Hello, linky!
EOF
# Turn off spacing between reminders, and test the 'z' -c flag.
$REMIND -w,0,0,0 -@2 -cz - 1 Jan 2020 <<'EOF' >> $OUT 2>&1
REM 15 INFO "Url: https://dianne.skoll.ca" MSG Hello, linky 1!
REM 15 INFO "Url: https://dianne.skoll.ca" MSF Hello, linky 2!
REM 15 INFO "Url: https://dianne.skoll.ca" CAL Hello, linky 3!
REM 15 INFO "Url: https://dianne.skoll.ca" SPECIAL COLOR 255 0 0 Hello, linky 4!
EOF
# Turn on spacing between reminders..
$REMIND -w,0,0,1 -@2 -c - 1 Jan 2020 <<'EOF' >> $OUT 2>&1
SET $TerminalHyperlinks 1
REM 15 INFO "Url: https://dianne.skoll.ca" MSG Hello, linky 1!
REM 15 INFO "Url: https://dianne.skoll.ca" MSF Hello, linky 2!
REM 15 INFO "Url: https://dianne.skoll.ca" CAL Hello, linky 3!
REM 15 INFO "Url: https://dianne.skoll.ca" SPECIAL COLOR 255 0 0 Hello, linky 4!
EOF
# Test the $Shaded system variable
$REMIND -pp ../tests/shaded.rem 2026-02-01 >> $OUT 2>&1
# Test the push/pop warnings
$REMIND ../tests/test-pushpop1.rem 2026-01-01 >> $OUT 2>&1
$REMIND -dp ../tests/test-pushpop1.rem 2026-01-01 >> $OUT 2>&1
cmp -s $OUT $CMP
if [ "$?" = "0" ]; then

View File

@@ -1046,7 +1046,7 @@ set a057 value("a05"+"6")
"a05" + "6" => "a056"
value("a056") => "SDFJHSDF KSJDFH KJSDFH KSJDFH"
set a058 version()
version() => "06.01.09"
version() => "06.02.04"
set a059 wkday(today())
today() => 1991-02-16
wkday(1991-02-16) => "Saturday"
@@ -2609,7 +2609,7 @@ a056 "SDFJHSDF KSJDFH KJSDFH KSJDFH"
a007 "1991-02-16"
a057 "SDFJHSDF KSJDFH KJSDFH KSJDFH"
a008 "11:44"
a058 "06.01.09"
a058 "06.02.04"
a059 "Saturday"
a010 12
a060 6
@@ -5563,8 +5563,8 @@ REM SATISFY ""
REM SATISFY [version() > "01.00.00"]
../tests/test.rem(1074): SATISFY: expression has no reference to trigdate() or $T...
../tests/test.rem(1074): Trig = Saturday, 16 February, 1991
version() => "06.01.09"
"06.01.09" > "01.00.00" => 1
version() => "06.02.04"
"06.02.04" > "01.00.00" => 1
../tests/test.rem(1074): Trig(satisfied) = Saturday, 16 February, 1991
REM SATISFY [max(x, max(x, 1, 2, 3), 4, 5, 6) * 5]
../tests/test.rem(1075): SATISFY: expression has no reference to trigdate() or $T...
@@ -16657,6 +16657,121 @@ mbchar(0, 120) => Number too low
../tests/test.rem(1767): mbchar(): Number too low
mbchar(120, 0) => Number too low
../tests/test.rem(1768): mbchar(): Number too low
hebdate(1, "Tishrey") => 1991-09-09
hebdate(1, "Tishri") => 1991-09-09
hebdate(1, "Tishrei") => 1991-09-09
hebdate(1, "תשרי") => 1991-09-09
hebdate(1, "Cheshvan") => 1991-10-09
hebdate(1, "Kheshvan") => 1991-10-09
hebdate(1, "Heshvan") => 1991-10-09
hebdate(1, "חשוון") => 1991-10-09
hebdate(1, "Kislev") => 1991-11-08
hebdate(1, "כסלו") => 1991-11-08
hebdate(1, "Tevet") => 1991-12-08
hebdate(1, "טבת") => 1991-12-08
hebdate(1, "Shvat") => 1992-01-06
hebdate(1, "Shevat") => 1992-01-06
hebdate(1, "שבט") => 1992-01-06
hebdate(1, "Adar A") => 1992-02-05
hebdate(1, "Adar 1") => 1992-02-05
hebdate(1, "Adar I") => 1992-02-05
hebdate(1, "×<>×ר ×<>'") => 1992-02-05
hebdate(1, "×<>×ר ×<>") => 1992-02-05
hebdate(1, "×<>×ר 1") => 1992-02-05
hebdate(1, "×<>×ר I") => 1992-02-05
hebdate(1, "Adar B") => 1992-03-06
hebdate(1, "Adar 2") => 1992-03-06
hebdate(1, "Adar II") => 1992-03-06
hebdate(1, "×<>×ר ×'") => 1992-03-06
hebdate(1, "×<>×ר ×") => 1992-03-06
hebdate(1, "×<>×ר 2") => 1992-03-06
hebdate(1, "×<>×ר II") => 1992-03-06
hebdate(1, "Nisan") => 1991-03-16
hebdate(1, "ניסן") => 1991-03-16
hebdate(1, "Iyar") => 1991-04-15
hebdate(1, "Iyyar") => 1991-04-15
hebdate(1, "×<>××ר") => 1991-04-15
hebdate(1, "Sivan") => 1991-05-14
hebdate(1, "סיון") => 1991-05-14
hebdate(1, "Tamuz") => 1991-06-13
hebdate(1, "Tammuz") => 1991-06-13
hebdate(1, "תמוז") => 1991-06-13
hebdate(1, "Av") => 1991-07-12
hebdate(1, "×<>×") => 1991-07-12
hebdate(1, "Elul") => 1991-08-11
hebdate(1, "×<>ל×ל") => 1991-08-11
hebdate(1, "Adar") => 1992-03-06
hebdate(1, "×<>×ר") => 1992-03-06
hebmon(1991-09-09) => "Tishrey"
ivritmon(1991-09-09) => "תשרי"
hebmon(1991-10-09) => "Heshvan"
ivritmon(1991-10-09) => "חשוון"
hebmon(1991-11-08) => "Kislev"
ivritmon(1991-11-08) => "כסלו"
hebmon(1991-12-08) => "Tevet"
ivritmon(1991-12-08) => "טבת"
hebmon(1992-01-06) => "Shvat"
ivritmon(1992-01-06) => "שבט"
hebmon(1992-02-05) => "Adar A"
ivritmon(1992-02-05) => "×<>×ר ×<>'"
hebmon(1992-03-06) => "Adar B"
ivritmon(1992-03-06) => "×<>×ר ×'"
hebmon(1991-03-16) => "Nisan"
ivritmon(1991-03-16) => "ניסן"
hebmon(1991-04-15) => "Iyar"
ivritmon(1991-04-15) => "×<>××ר"
hebmon(1991-05-14) => "Sivan"
ivritmon(1991-05-14) => "סיון"
hebmon(1991-06-13) => "Tamuz"
ivritmon(1991-06-13) => "תמוז"
hebmon(1991-07-12) => "Av"
ivritmon(1991-07-12) => "×<>×"
hebmon(1991-08-11) => "Elul"
ivritmon(1991-08-11) => "×<>ל×ל"
mbpad("foo", "bar", 3) => "foo"
mbpad("foo", "bar", 3, 1) => "foo"
mbpad("foo", "bar", 8) => "barbafoo"
mbpad("foo", "bar", 8, 1) => "foobarba"
mbpad("foo", "🙂💩", 3) => "foo"
mbpad("foo", "🙂💩", 3, 1) => "foo"
mbpad("foo", "🙂💩", 8) => "ðŸ™ðŸ©ðŸ™ðŸ©ðŸ™foo"
mbpad("foo", "🙂💩", 8, 1) => "fooðŸ™ðŸ©ðŸ™ðŸ©ðŸ™"
char(255) => "ÿ"
bad => "ÿ"
mbpad("foo", "ÿ", 3) => "foo"
bad => "ÿ"
mbpad("foo", "ÿ", 3, 1) => "foo"
bad => "ÿ"
mbpad("foo", "ÿ", 8) => Invalid multibyte sequence
../tests/test.rem(1886): mbpad(): Invalid multibyte sequence
bad => "ÿ"
mbpad("foo", "ÿ", 8, 1) => Invalid multibyte sequence
../tests/test.rem(1887): mbpad(): Invalid multibyte sequence
bad => "ÿ"
mbpad("ÿ", "bar", 0) => Invalid multibyte sequence
../tests/test.rem(1888): mbpad(): Invalid multibyte sequence
bad => "ÿ"
mbpad("ÿ", "bar", 0, 1) => Invalid multibyte sequence
../tests/test.rem(1889): mbpad(): Invalid multibyte sequence
bad => "ÿ"
mbpad("ÿ", "bar", 8) => Invalid multibyte sequence
../tests/test.rem(1890): mbpad(): Invalid multibyte sequence
bad => "ÿ"
mbpad("ÿ", "bar", 8, 1) => Invalid multibyte sequence
../tests/test.rem(1891): mbpad(): Invalid multibyte sequence
]8;;https://dianne.skoll.ca\Hello, linky!
]8;;\]8;;https://dianne.skoll.ca\Hello, linky!
]8;;\]8;;https://dianne.skoll.ca\Hello, linky!
]8;;\../tests/test.rem(1900): Invalid value for system variable
../tests/test.rem(1901): Invalid value for system variable
../tests/test.rem(1902): Invalid value for system variable
../tests/test.rem(1903): Invalid value for system variable
../tests/test.rem(1904): Invalid value for system variable
mbupper("öÖçÇéôñÑÉÊ") => "ÖÖÇÇÉÔÑÑÉÊ"
mblower("öÖçÇéôñÑÉÊ") => "ööççéôññéê"
upper("öÖçÇéôñÑÉÊ") => "öÖçÇéôñÑÉÊ"
lower("öÖçÇéôñÑÉÊ") => "öÖçÇéôñÑÉÊ"
DynBuf Mallocs: 1132 mallocs; 31873408 bytes
Variable hash table statistics:
Entries: 100146; Buckets: 87719; Non-empty Buckets: 66303
Maxlen: 5; Minlen: 0; Avglen: 1.142; Stddev: 0.878; Avg nonempty len: 1.510
@@ -16678,7 +16793,7 @@ Expression nodes high-water: 302076
Expression nodes leaked: 0
Parse level high-water: 34
Max expr node evaluations per line: 2001
Total expression node evaluations: 106471
Total expression node evaluations: 106746
Test 2
@@ -20657,7 +20772,7 @@ No reminders.
<< /PageSize [612 792] >> setpagedevice
% This file was produced by Remind and Rem2PS, written by
% Dianne Skoll.
% Remind and Rem2PS are Copyright (C) 1992-2025 Dianne Skoll.
% Remind and Rem2PS are Copyright (C) 1992-2026 Dianne Skoll.
/ISOLatin1Encoding where { pop save true }{ false } ifelse
/ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus
StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute
@@ -21761,7 +21876,7 @@ showpage
<< /PageSize [612 792] >> setpagedevice
% This file was produced by Remind and Rem2PS, written by
% Dianne Skoll.
% Remind and Rem2PS are Copyright (C) 1992-2025 Dianne Skoll.
% Remind and Rem2PS are Copyright (C) 1992-2026 Dianne Skoll.
/ISOLatin1Encoding where { pop save true }{ false } ifelse
/ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus
StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute
@@ -23716,7 +23831,7 @@ SECURITY: Won't read world-writable file or directory!
Error reading include_dir/ww: Can't open file
SECURITY: Won't read world-writable file or directory!
Error reading include_dir/ww: No files matching *.rem
06.01.09
06.02.04
Enabling test mode: This is meant for the acceptance test.
Do not use --test in production.
In test mode, the system time is fixed at 2025-01-06@19:00
@@ -24274,6 +24389,7 @@ Parsed expression: isany("foo", 1 + 1, 2:00 + 1, '2021-01-01' + 1, '2021-01-01@1
"f" + "oo" => "foo"
isany("foo", 2, 02:01, 2021-01-02, 2021-01-01@14:01, "foo", ?) => 1
No reminders.
DynBuf Mallocs: 21 mallocs; 6400 bytes
Variable hash table statistics:
Entries: 1; Buckets: 7; Non-empty Buckets: 1
Maxlen: 1; Minlen: 0; Avglen: 0.143; Stddev: 0.350; Avg nonempty len: 1.000
@@ -24488,6 +24604,7 @@ cal
clear
clear-omit-context
complete-through
completed-through
debug
do
dump
@@ -24656,14 +24773,18 @@ isconst
isdst
isleap
isomitted
ivritmon
language
localtoutc
lower
max
mbchar
mbindex
mblower
mbpad
mbstrlen
mbsubstr
mbupper
min
minsfromutc
minute
@@ -24830,6 +24951,7 @@ $PSCal
$RunOff
$Saturday
$September
$Shaded
$SimpleCal
$SortByDate
$SortByPrio
@@ -24843,6 +24965,7 @@ $T
$Tb
$Td
$TerminalBackground
$TerminalHyperlinks
$Thursday
$TimeSep
$TimetIs64bit
@@ -24869,6 +24992,7 @@ $WarningLevel
$Was
$Wednesday
No reminders.
DynBuf Mallocs: 180071 mallocs; 42974784 bytes
Variable hash table statistics:
Entries: 1; Buckets: 7; Non-empty Buckets: 1
Maxlen: 1; Minlen: 0; Avglen: 0.143; Stddev: 0.350; Avg nonempty len: 1.000
@@ -25071,11 +25195,11 @@ TRANSLATE "MAX-OVERDUE specified twice" ""
TRANSLATE "MAX-OVERDUE specified without TODO" ""
TRANSLATE "TZ specified twice" ""
TRANSLATE "TZ specified for non-timed reminder" ""
TRANSLATE "C library does not support multibyte characters" ""
TRANSLATE "Invalid multibyte sequence" ""
TRANSLATE "Maximum expression complexity exceeded" ""
TRANSLATE "Expecting operator or end-of-expression" ""
TRANSLATE "Expecting constant, variable, function call or (expression)" ""
TRANSLATE "Invalid value for system variable" ""
# Other Messages
TRANSLATE "%s function `%s' defined at %s(%s) does not use its argument" ""
@@ -39559,7 +39683,6 @@ trigger(2060-08-01@23:55, 1) => "1 August 2060 AT 19:55"
utctolocal(2050-01-01@01:00) => 2049-12-31@20:00
localtoutc(2050-12-31@23:44) => 2051-01-01@04:44
localtoutc(2050-03-13@00:00) => 2050-03-13@05:00
localtoutc(2050-03-13@02:00) => 2050-03-13@07:00
localtoutc(2050-11-06@00:00) => 2050-11-06@04:00
localtoutc(2050-11-06@02:00) => 2050-11-06@07:00
utctolocal(2051-01-01@04:44) => 2050-12-31@23:44
@@ -39671,6 +39794,14 @@ Fifth today
Sixth on 2025-08-06
Eighth on 2025-08-20
Ninth today
First on 2025-08-01
Second on 2022-08-01
Third on 2023-08-01
Fourth on 2025-08-20
Fifth today
Sixth on 2025-08-06
Eighth on 2025-08-20
Ninth today
Yup today
Yup2 yesterday
Yup3 on 2025-08-11
@@ -39686,6 +39817,13 @@ Testing TODOS in calendar mode
2025/08/01 * * * * First
2025/08/01 * * * * Second
2025/08/01 * * * * Third
2025/08/01 * * * * First
2025/08/01 * * * * Second
2025/08/01 * * * * Third
2025/08/06 * * * * Sixth
2025/08/06 * * * * Seventh
2025/08/06 * * * * Eighth
2025/08/06 * * * * Ninth
2025/08/06 * * * * Sixth
2025/08/06 * * * * Seventh
2025/08/06 * * * * Eighth
@@ -39697,10 +39835,18 @@ Testing TODOS in calendar mode
2025/08/13 * * * * Fifth
2025/08/13 * * * * Eighth
2025/08/13 * * * * Ninth
2025/08/13 * * * * Fifth
2025/08/13 * * * * Eighth
2025/08/13 * * * * Ninth
2025/08/13 * * * * Yup
2025/08/20 * * * * Fourth
2025/08/20 * * * * Eighth
2025/08/20 * * * * Ninth
2025/08/20 * * * * Fourth
2025/08/20 * * * * Eighth
2025/08/20 * * * * Ninth
2025/08/27 * * * * Eighth
2025/08/27 * * * * Ninth
2025/08/27 * * * * Eighth
2025/08/27 * * * * Ninth
@@ -39708,6 +39854,10 @@ Testing TODOS in calendar mode with completed todos hidden
2025/08/01 * * * * First
2025/08/01 * * * * Second
2025/08/01 * * * * Third
2025/08/01 * * * * First
2025/08/01 * * * * Second
2025/08/01 * * * * Third
2025/08/06 * * * * Sixth
2025/08/06 * * * * Sixth
2025/08/09 * * * * Nope
2025/08/10 * * * * Yup4
@@ -39715,26 +39865,41 @@ Testing TODOS in calendar mode with completed todos hidden
2025/08/12 * * * * Yup2
2025/08/13 * * * * Fifth
2025/08/13 * * * * Ninth
2025/08/13 * * * * Fifth
2025/08/13 * * * * Ninth
2025/08/13 * * * * Yup
2025/08/20 * * * * Fourth
2025/08/20 * * * * Eighth
2025/08/20 * * * * Ninth
2025/08/20 * * * * Fourth
2025/08/20 * * * * Eighth
2025/08/20 * * * * Ninth
2025/08/27 * * * * Eighth
2025/08/27 * * * * Ninth
2025/08/27 * * * * Eighth
2025/08/27 * * * * Ninth
Testing TODOS and JSON mode
[
{"date":"2025-08-01","filename":"../tests/todos.rem","lineno":4,"d":1,"m":8,"y":2025,"is_todo":1,"trigbase":"2025-08-1 ","priority":5000,"body":"First on 2025-08-01"},
{"date":"2025-08-01","filename":"../tests/todos.rem","lineno":4,"d":1,"m":8,"y":2025,"is_todo":1,"trigbase":"2025-08-01","priority":5000,"body":"First on 2025-08-01"},
{"date":"2022-08-01","filename":"../tests/todos.rem","lineno":5,"d":1,"m":8,"is_todo":1,"complete_through":"2022-07-31","priority":5000,"body":"Second on 2022-08-01"},
{"date":"2023-08-01","filename":"../tests/todos.rem","lineno":6,"d":1,"m":8,"is_todo":1,"complete_through":"2022-08-01","priority":5000,"body":"Third on 2023-08-01"},
{"date":"2025-08-20","filename":"../tests/todos.rem","lineno":7,"d":20,"m":8,"y":2025,"is_todo":1,"delta":7,"trigbase":"2025-08-20","priority":5000,"body":"Fourth on 2025-08-20"},
{"date":"2025-08-13","filename":"../tests/todos.rem","lineno":8,"d":13,"m":8,"y":2025,"is_todo":1,"delta":7,"trigbase":"2025-08-13","priority":5000,"body":"Fifth today"},
{"date":"2025-08-06","filename":"../tests/todos.rem","lineno":9,"d":6,"m":8,"y":2025,"is_todo":1,"delta":7,"trigbase":"2025-08-6 ","priority":5000,"body":"Sixth on 2025-08-06"},
{"date":"2025-08-06","filename":"../tests/todos.rem","lineno":9,"d":6,"m":8,"y":2025,"is_todo":1,"delta":7,"trigbase":"2025-08-06","priority":5000,"body":"Sixth on 2025-08-06"},
{"date":"2025-08-20","filename":"../tests/todos.rem","lineno":11,"wd":["Wednesday"],"is_todo":1,"complete_through":"2025-08-13","delta":7,"priority":5000,"body":"Eighth on 2025-08-20"},
{"date":"2025-08-13","filename":"../tests/todos.rem","lineno":12,"wd":["Wednesday"],"is_todo":1,"complete_through":"2025-08-12","delta":7,"priority":5000,"body":"Ninth today"},
{"date":"2025-08-13","filename":"../tests/todos.rem","lineno":15,"d":13,"m":8,"y":2025,"is_todo":1,"trigbase":"2025-08-13","max_overdue":3,"priority":5000,"body":"Yup today"},
{"date":"2025-08-12","filename":"../tests/todos.rem","lineno":16,"d":12,"m":8,"y":2025,"is_todo":1,"trigbase":"2025-08-12","max_overdue":3,"priority":5000,"body":"Yup2 yesterday"},
{"date":"2025-08-11","filename":"../tests/todos.rem","lineno":17,"d":11,"m":8,"y":2025,"is_todo":1,"trigbase":"2025-08-11","max_overdue":3,"priority":5000,"body":"Yup3 on 2025-08-11"},
{"date":"2025-08-10","filename":"../tests/todos.rem","lineno":18,"d":10,"m":8,"y":2025,"is_todo":1,"trigbase":"2025-08-10","max_overdue":3,"priority":5000,"body":"Yup4 on 2025-08-10"}
{"date":"2025-08-01","filename":"../tests/todos.rem","lineno":14,"d":1,"m":8,"y":2025,"is_todo":1,"trigbase":"2025-08-01","priority":5000,"body":"First on 2025-08-01"},
{"date":"2022-08-01","filename":"../tests/todos.rem","lineno":15,"d":1,"m":8,"is_todo":1,"complete_through":"2022-07-31","priority":5000,"body":"Second on 2022-08-01"},
{"date":"2023-08-01","filename":"../tests/todos.rem","lineno":16,"d":1,"m":8,"is_todo":1,"complete_through":"2022-08-01","priority":5000,"body":"Third on 2023-08-01"},
{"date":"2025-08-20","filename":"../tests/todos.rem","lineno":17,"d":20,"m":8,"y":2025,"is_todo":1,"delta":7,"trigbase":"2025-08-20","priority":5000,"body":"Fourth on 2025-08-20"},
{"date":"2025-08-13","filename":"../tests/todos.rem","lineno":18,"d":13,"m":8,"y":2025,"is_todo":1,"delta":7,"trigbase":"2025-08-13","priority":5000,"body":"Fifth today"},
{"date":"2025-08-06","filename":"../tests/todos.rem","lineno":19,"d":6,"m":8,"y":2025,"is_todo":1,"delta":7,"trigbase":"2025-08-06","priority":5000,"body":"Sixth on 2025-08-06"},
{"date":"2025-08-20","filename":"../tests/todos.rem","lineno":21,"wd":["Wednesday"],"is_todo":1,"complete_through":"2025-08-13","delta":7,"priority":5000,"body":"Eighth on 2025-08-20"},
{"date":"2025-08-13","filename":"../tests/todos.rem","lineno":22,"wd":["Wednesday"],"is_todo":1,"complete_through":"2025-08-12","delta":7,"priority":5000,"body":"Ninth today"},
{"date":"2025-08-13","filename":"../tests/todos.rem","lineno":25,"d":13,"m":8,"y":2025,"is_todo":1,"trigbase":"2025-08-13","max_overdue":3,"priority":5000,"body":"Yup today"},
{"date":"2025-08-12","filename":"../tests/todos.rem","lineno":26,"d":12,"m":8,"y":2025,"is_todo":1,"trigbase":"2025-08-12","max_overdue":3,"priority":5000,"body":"Yup2 yesterday"},
{"date":"2025-08-11","filename":"../tests/todos.rem","lineno":27,"d":11,"m":8,"y":2025,"is_todo":1,"trigbase":"2025-08-11","max_overdue":3,"priority":5000,"body":"Yup3 on 2025-08-11"},
{"date":"2025-08-10","filename":"../tests/todos.rem","lineno":28,"d":10,"m":8,"y":2025,"is_todo":1,"trigbase":"2025-08-10","max_overdue":3,"priority":5000,"body":"Yup4 on 2025-08-10"}
]
Testing proper redirection of RUN stdout in JSON mode... here's stdout
[
@@ -39858,6 +40023,7 @@ fib(24) = 46368
-stdin-(13): `-': Maximum expression complexity exceeded
-stdin-(3): [#0] In function `fib'
[remaining call frames omitted]
DynBuf Mallocs: 3 mallocs; 192 bytes
Variable hash table statistics:
Entries: 0; Buckets: 7; Non-empty Buckets: 0
Maxlen: 0; Minlen: 0; Avglen: 0.000; Stddev: 0.000; Avg nonempty len: 0.000
@@ -39883,6 +40049,7 @@ Total expression node evaluations: 3999940
a = 493; hex(a) = 1ED
hex(-1) = FFFFFFFF
a = 32767; hex(a) = 7FFF
DynBuf Mallocs: 5 mallocs; 320 bytes
Variable hash table statistics:
Entries: 1; Buckets: 7; Non-empty Buckets: 1
Maxlen: 1; Minlen: 0; Avglen: 0.143; Stddev: 0.350; Avg nonempty len: 1.000
@@ -39940,9 +40107,9 @@ devnull test b
No reminders.
[
{"banner":"Reminders for Wednesday, 1st October, 2025:"},
{"date":"2025-10-01","filename":"-stdin-","lineno":3,"d":1,"m":10,"y":2025,"is_todo":0,"trigbase":"2025-10-1 ","priority":5000,"body":"Nonconst NOT set 2025-10-01"},
{"date":"2025-10-01","filename":"-stdin-","lineno":4,"nonconst_expr":1,"d":1,"m":10,"y":2025,"is_todo":0,"trigbase":"2025-10-1 ","priority":5000,"body":"Nonconst IS set 2025-10-01"},
{"date":"2025-10-01","filename":"-stdin-","lineno":5,"nonconst_expr":1,"d":1,"m":10,"y":2025,"is_todo":0,"trigbase":"2025-10-1 ","priority":5000,"body":"Nonconst IS set"}
{"date":"2025-10-01","filename":"-stdin-","lineno":3,"d":1,"m":10,"y":2025,"is_todo":0,"trigbase":"2025-10-01","priority":5000,"body":"Nonconst NOT set 2025-10-01"},
{"date":"2025-10-01","filename":"-stdin-","lineno":4,"nonconst_expr":1,"d":1,"m":10,"y":2025,"is_todo":0,"trigbase":"2025-10-01","priority":5000,"body":"Nonconst IS set 2025-10-01"},
{"date":"2025-10-01","filename":"-stdin-","lineno":5,"nonconst_expr":1,"d":1,"m":10,"y":2025,"is_todo":0,"trigbase":"2025-10-01","priority":5000,"body":"Nonconst IS set"}
]
# Nonconst-expr in trigger
set $ParseUntriggered 1
@@ -39957,3 +40124,157 @@ REM 2025 Oct [a] MSG Nonconst IS set
#!P: Next line has expired, but contains expression... please verify
#!P: Expired: REM 2025 Oct [1] MSG Expr but not nonconst [today()]
#!P: Expired: REM 2025-10-01 MSG No expr seen [1+2]
# translations
{"LANGID":"en"}
# rem2ps begin
January 2026 31 4 0
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
December 31
February 28
# rem2ps end
# translations
{"LANGID":"en"}
# rem2ps begin
January 2026 31 4 0
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
December 31
February 28
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
-stdin-(2): `/': Division by zero
# rem2ps end
+----------------------------------------------------------------------------+
| January 2020‎ |
+----------+----------+----------+----------+----------+----------+----------+
| Sunday‎ | Monday‎ | Tuesday‎ |Wednesday‎ | Thursday‎ | Friday‎ | Saturday‎ |
+----------+----------+----------+----------+----------+----------+----------+
| | | |1 ‎ |2 ‎ |3 ‎ |4 ‎ |
+----------+----------+----------+----------+----------+----------+----------+
|5 ‎ |6 ‎ |7 ‎ |8 ‎ |9 ‎ |10 ‎ |11 ‎ |
+----------+----------+----------+----------+----------+----------+----------+
|12 ‎ |13 ‎ |14 ‎ |15 ‎ |16 ‎ |17 ‎ |18 ‎ |
| | | |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ |
| | | |]8;;https://dianne.skoll.ca\linky!]8;;\‎ |]8;;https://dianne.skoll.ca\linky!]8;;\‎ |]8;;https://dianne.skoll.ca\linky!]8;;\‎ |]8;;https://dianne.skoll.ca\linky!]8;;\‎ |
+----------+----------+----------+----------+----------+----------+----------+
|19 ‎ |20 ‎ |21 ‎ |22 ‎ |23 ‎ |24 ‎ |25 ‎ |
+----------+----------+----------+----------+----------+----------+----------+
|26 ‎ |27 ‎ |28 ‎ |29 ‎ |30 ‎ |31 ‎ | |
+----------+----------+----------+----------+----------+----------+----------+
+----------------------------------------------------------------------------+
| January 2020‎ |
+----------+----------+----------+----------+----------+----------+----------+
| Sunday‎ | Monday‎ | Tuesday‎ |Wednesday‎ | Thursday‎ | Friday‎ | Saturday‎ |
+----------+----------+----------+----------+----------+----------+----------+
| | | |1 ‎ |2 ‎ |3 ‎ |4 ‎ |
+----------+----------+----------+----------+----------+----------+----------+
|5 ‎ |6 ‎ |7 ‎ |8 ‎ |9 ‎ |10 ‎ |11 ‎ |
+----------+----------+----------+----------+----------+----------+----------+
|12 ‎ |13 ‎ |14 ‎ |15 ‎ |16 ‎ |17 ‎ |18 ‎ |
| | | |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ | | | |
| | | |]8;;https://dianne.skoll.ca\linky 1!]8;;\‎ | | | |
| | | |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ | | | |
| | | |]8;;https://dianne.skoll.ca\linky 2!]8;;\‎ | | | |
| | | |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ | | | |
| | | |]8;;https://dianne.skoll.ca\linky 3!]8;;\‎ | | | |
| | | |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ | | | |
| | | |]8;;https://dianne.skoll.ca\linky 4!]8;;\‎ | | | |
+----------+----------+----------+----------+----------+----------+----------+
|19 ‎ |20 ‎ |21 ‎ |22 ‎ |23 ‎ |24 ‎ |25 ‎ |
+----------+----------+----------+----------+----------+----------+----------+
|26 ‎ |27 ‎ |28 ‎ |29 ‎ |30 ‎ |31 ‎ | |
+----------+----------+----------+----------+----------+----------+----------+
+----------------------------------------------------------------------------+
| January 2020‎ |
+----------+----------+----------+----------+----------+----------+----------+
| Sunday‎ | Monday‎ | Tuesday‎ |Wednesday‎ | Thursday‎ | Friday‎ | Saturday‎ |
+----------+----------+----------+----------+----------+----------+----------+
| | | |1 ‎ |2 ‎ |3 ‎ |4 ‎ |
+----------+----------+----------+----------+----------+----------+----------+
|5 ‎ |6 ‎ |7 ‎ |8 ‎ |9 ‎ |10 ‎ |11 ‎ |
+----------+----------+----------+----------+----------+----------+----------+
|12 ‎ |13 ‎ |14 ‎ |15 ‎ |16 ‎ |17 ‎ |18 ‎ |
| | | |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ | | | |
| | | |]8;;https://dianne.skoll.ca\linky 1!]8;;\‎ | | | |
| | | | | | | |
| | | |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ | | | |
| | | |]8;;https://dianne.skoll.ca\linky 2!]8;;\‎ | | | |
| | | | | | | |
| | | |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ | | | |
| | | |]8;;https://dianne.skoll.ca\linky 3!]8;;\‎ | | | |
| | | | | | | |
| | | |]8;;https://dianne.skoll.ca\Hello,]8;;\‎ | | | |
| | | |]8;;https://dianne.skoll.ca\linky 4!]8;;\‎ | | | |
+----------+----------+----------+----------+----------+----------+----------+
|19 ‎ |20 ‎ |21 ‎ |22 ‎ |23 ‎ |24 ‎ |25 ‎ |
+----------+----------+----------+----------+----------+----------+----------+
|26 ‎ |27 ‎ |28 ‎ |29 ‎ |30 ‎ |31 ‎ | |
+----------+----------+----------+----------+----------+----------+----------+
# translations
{"LANGID":"en"}
# rem2ps2 begin
February 2026 28 0 0
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
January 31
March 31
{"date":"2026-02-01","filename":"../tests/shaded.rem","lineno":10,"passthru":"SHADE","wd":["Sunday"],"is_todo":0,"priority":5000,"if_depth":1,"r":0,"g":255,"b":255,"body":"0 255 255"}
{"date":"2026-02-02","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-03","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-04","filename":"../tests/shaded.rem","lineno":1,"passthru":"SHADE","wd":["Wednesday"],"is_todo":0,"priority":5000,"r":255,"g":0,"b":0,"body":"255 0 0"}
{"date":"2026-02-05","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-06","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-07","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-08","filename":"../tests/shaded.rem","lineno":6,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":0,"g":0,"b":255,"body":"0 0 255"}
{"date":"2026-02-09","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-10","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-11","filename":"../tests/shaded.rem","lineno":1,"passthru":"SHADE","wd":["Wednesday"],"is_todo":0,"priority":5000,"r":255,"g":0,"b":0,"body":"255 0 0"}
{"date":"2026-02-12","filename":"../tests/shaded.rem","lineno":6,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":0,"g":0,"b":255,"body":"0 0 255"}
{"date":"2026-02-13","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-14","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-15","filename":"../tests/shaded.rem","lineno":3,"passthru":"SHADE","d":15,"is_todo":0,"priority":5000,"if_depth":1,"r":0,"g":255,"b":0,"body":"0 255 0"}
{"date":"2026-02-16","filename":"../tests/shaded.rem","lineno":6,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":0,"g":0,"b":255,"body":"0 0 255"}
{"date":"2026-02-17","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-18","filename":"../tests/shaded.rem","lineno":1,"passthru":"SHADE","wd":["Wednesday"],"is_todo":0,"priority":5000,"r":255,"g":0,"b":0,"body":"255 0 0"}
{"date":"2026-02-19","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-20","filename":"../tests/shaded.rem","lineno":6,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":0,"g":0,"b":255,"body":"0 0 255"}
{"date":"2026-02-21","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-22","filename":"../tests/shaded.rem","lineno":10,"passthru":"SHADE","wd":["Sunday"],"is_todo":0,"priority":5000,"if_depth":1,"r":0,"g":255,"b":255,"body":"0 255 255"}
{"date":"2026-02-23","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-24","filename":"../tests/shaded.rem","lineno":6,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":0,"g":0,"b":255,"body":"0 0 255"}
{"date":"2026-02-25","filename":"../tests/shaded.rem","lineno":1,"passthru":"SHADE","wd":["Wednesday"],"is_todo":0,"priority":5000,"r":255,"g":0,"b":0,"body":"255 0 0"}
{"date":"2026-02-26","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-27","filename":"../tests/shaded.rem","lineno":14,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":255,"g":255,"b":0,"body":"255 255 0"}
{"date":"2026-02-28","filename":"../tests/shaded.rem","lineno":6,"passthru":"SHADE","is_todo":0,"priority":5000,"if_depth":1,"r":0,"g":0,"b":255,"body":"0 0 255"}
# rem2ps2 end
No reminders.
../tests/test-pushpop2.rem(1): POP-VARS at ../tests/test-pushpop2.rem:1 matches PUSH-VARS in different file: ../tests/test-pushpop1.rem:3
../tests/test-pushpop2.rem(2): POP-FUNCS at ../tests/test-pushpop2.rem:2 matches PUSH-FUNCS in different file: ../tests/test-pushpop1.rem:2
../tests/test-pushpop2.rem(3): POP-OMIT-CONTEXT at ../tests/test-pushpop2.rem:3 matches PUSH-OMIT-CONTEXT in different file: ../tests/test-pushpop1.rem:1
No reminders.

View File

@@ -1769,7 +1769,148 @@ set a mbchar(120, 0)
# Make sure trailing space doesn't cause a diagnostic.
set a "foo"
# Hebrew dates
SET a hebdate(1, "Tishrey")
SET a hebdate(1, "Tishri")
SET a hebdate(1, "Tishrei")
SET a hebdate(1, "תשרי")
SET a hebdate(1, "Cheshvan")
SET a hebdate(1, "Kheshvan")
SET a hebdate(1, "Heshvan")
SET a hebdate(1, "חשוון")
SET a hebdate(1, "Kislev")
SET a hebdate(1, "כסלו")
SET a hebdate(1, "Tevet")
SET a hebdate(1, "טבת")
SET a hebdate(1, "Shvat")
SET a hebdate(1, "Shevat")
SET a hebdate(1, "שבט")
SET a hebdate(1, "Adar A")
SET a hebdate(1, "Adar 1")
SET a hebdate(1, "Adar I")
SET a hebdate(1, "אדר א'")
SET a hebdate(1, "אדר א")
SET a hebdate(1, "אדר 1")
SET a hebdate(1, "אדר I")
SET a hebdate(1, "Adar B")
SET a hebdate(1, "Adar 2")
SET a hebdate(1, "Adar II")
SET a hebdate(1, "אדר ב'")
SET a hebdate(1, "אדר ב")
SET a hebdate(1, "אדר 2")
SET a hebdate(1, "אדר II")
SET a hebdate(1, "Nisan")
SET a hebdate(1, "ניסן")
SET a hebdate(1, "Iyar")
SET a hebdate(1, "Iyyar")
SET a hebdate(1, "אייר")
SET a hebdate(1, "Sivan")
SET a hebdate(1, "סיון")
SET a hebdate(1, "Tamuz")
SET a hebdate(1, "Tammuz")
SET a hebdate(1, "תמוז")
SET a hebdate(1, "Av")
SET a hebdate(1, "אב")
SET a hebdate(1, "Elul")
SET a hebdate(1, "אלול")
SET a hebdate(1, "Adar")
SET a hebdate(1, "אדר")
set a hebmon('1991-09-09')
set a ivritmon('1991-09-09')
set a hebmon('1991-10-09')
set a ivritmon('1991-10-09')
set a hebmon('1991-11-08')
set a ivritmon('1991-11-08')
set a hebmon('1991-12-08')
set a ivritmon('1991-12-08')
set a hebmon('1992-01-06')
set a ivritmon('1992-01-06')
set a hebmon('1992-02-05')
set a ivritmon('1992-02-05')
set a hebmon('1992-03-06')
set a ivritmon('1992-03-06')
set a hebmon('1991-03-16')
set a ivritmon('1991-03-16')
set a hebmon('1991-04-15')
set a ivritmon('1991-04-15')
set a hebmon('1991-05-14')
set a ivritmon('1991-05-14')
set a hebmon('1991-06-13')
set a ivritmon('1991-06-13')
set a hebmon('1991-07-12')
set a ivritmon('1991-07-12')
set a hebmon('1991-08-11')
set a ivritmon('1991-08-11')
# mbpad
set a mbpad("foo", "bar", 3)
set a mbpad("foo", "bar", 3, 1)
set a mbpad("foo", "bar", 8)
set a mbpad("foo", "bar", 8, 1)
set a mbpad("foo", "🙂💩", 3)
set a mbpad("foo", "🙂💩", 3, 1)
set a mbpad("foo", "🙂💩", 8)
set a mbpad("foo", "🙂💩", 8, 1)
set bad char(255)
set a mbpad("foo", bad, 3)
set a mbpad("foo", bad, 3, 1)
set a mbpad("foo", bad, 8)
set a mbpad("foo", bad, 8, 1)
set a mbpad(bad, "bar", 0)
set a mbpad(bad, "bar", 0, 1)
set a mbpad(bad, "bar", 8)
set a mbpad(bad, "bar", 8, 1)
DEBUG -x
SET $TerminalHyperlinks 1
REM INFO "Url: https://dianne.skoll.ca" MSG Hello, linky!
REM INFO "Url: https://dianne.skoll.ca" MSF Hello, linky!
REM INFO "Url: https://dianne.skoll.ca" SPECIAL COLOR 255 0 0 Hello, linky!
# Bad values for system variables
SET $Latitude "Cabbage"
SET $Longitude "Carrots"
SET $TimeSep "FOO"
SET $DateSep "BAR"
SET $DefaultColor "My oh my, what lovely eyes!"
# mbupper and mblower
DEBUG +x
SET a mbupper("öÖçÇéôñÑÉÊ")
SET a mblower("öÖçÇéôñÑÉÊ")
SET a upper("öÖçÇéôñÑÉÊ")
SET a lower("öÖçÇéôñÑÉÊ")
DEBUG -x
# Don't want Remind to queue reminders
EXIT

View File

@@ -11,6 +11,16 @@ 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
REM TODO 1 Aug 2025 MSG %"First%" %l
REM TODO 1 Aug COMPLETED-THROUGH 2022-07-31 MSG %"Second%" %l
REM TODO 1 Aug COMPLETED-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 COMPLETED-THROUGH 2025-08-06 6 Aug 2025 +7 MSG %"Seventh%" %l
REM TODO Wed +7 COMPLETED-THROUGH 2025-08-13 MSG %"Eighth%" %l
REM TODO Wed +7 COMPLETED-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

View File

@@ -11,7 +11,7 @@
# Use the output to verify your translations.
#
# This file is part of REMIND.
# Copyright (C) 1992-2025 Dianne Skoll
# Copyright (C) 1992-2026 Dianne Skoll
# SPDX-License-Identifier: GPL-2.0-only
#
# ---------------------------------------------------------------------------

View File

@@ -26,7 +26,9 @@ set a utctolocal('2050-01-01@01:00')
set a localtoutc('2050-12-31@23:44')
set a localtoutc('2050-03-13@00:00')
set a localtoutc('2050-03-13@02:00')
# This next one fails on MUSL, so it's commented out.
# We expect 2050-03-13@07:00 but MUSL gives 2050-03-13@06:00
#set a localtoutc('2050-03-13@02:00')
set a localtoutc('2050-11-06@00:00')
set a localtoutc('2050-11-06@02:00')

View File

@@ -1,6 +1,6 @@
# Makefile.in for installing WWW server calendar scripts
# This file is part of REMIND.
# Copyright (C) 1992-2025 by Dianne Skoll
# Copyright (C) 1992-2026 by Dianne Skoll
# The complete path to where the scripts actually live, as seen by
# the UNIX operating system.

View File

@@ -1,7 +1,7 @@
#!/bin/sh
# This file is part of REMIND.
# Copyright (C) 1992-2025 by Dianne Skoll
# Copyright (C) 1992-2026 by Dianne Skoll
# CAL_DISPATCH -- Shell script for CGI directory to dispatch calendar
# commands.

View File

@@ -2,7 +2,7 @@
# PostScript calendar shell script
#
# This file is part of REMIND.
# Copyright (C) 1992-2025 by Dianne Skoll
# Copyright (C) 1992-2026 by Dianne Skoll
echo "Content-type: application/pdf"
echo

View File

@@ -2,7 +2,7 @@
# PostScript calendar shell script
#
# This file is part of REMIND.
# Copyright (C) 1992-2025 by Dianne Skoll
# Copyright (C) 1992-2026 by Dianne Skoll
echo "Content-type: application/postscript"
echo

View File

@@ -2,7 +2,7 @@
# Hebrew date shell script
#
# This file is part of REMIND.
# Copyright (C) 1992-2025 by Dianne Skoll
# Copyright (C) 1992-2026 by Dianne Skoll
echo Content-type: text/html
echo ""

View File

@@ -1,7 +1,7 @@
# Hebrew date reminder file
#
# This file is part of REMIND.
# Copyright (C) 1992-2025 by Dianne Skoll
# Copyright (C) 1992-2026 by Dianne Skoll
BANNER %
IF !$PSCAL

View File

@@ -2,7 +2,7 @@
# HTML calendar shell script
#
# This file is part of REMIND.
# Copyright (C) 1992-2025 by Dianne Skoll
# Copyright (C) 1992-2026 by Dianne Skoll
echo "Content-Type: text/html"
echo ""

Some files were not shown because too many files have changed in this diff Show More