Compare commits

...

80 Commits

Author SHA1 Message Date
Dianne Skoll
79f45169c8 Set release date. 2025-03-23 13:37:51 -04:00
Dianne Skoll
b9f09b9a2d Fix some cppcheck warnings. 2025-03-23 13:24:38 -04:00
Dianne Skoll
f53a174d65 Update WHATSNEW 2025-03-23 13:15:14 -04:00
Dianne Skoll
ed15b7deb5 Update JSON parser to latest version from https://github.com/udp/json-parser 2025-03-22 12:09:30 -04:00
Dianne Skoll
caf5f81eb0 Add a few more removals to "make distclean" 2025-03-22 11:18:56 -04:00
Dianne Skoll
d48910eca9 Update "make distclean" target; remove obsolete unconfigure script. 2025-03-22 11:16:54 -04:00
Dianne Skoll
c004944a59 Replace '1440' with 'MINUTES_PER_DAY' in a bunch of spots. 2025-03-20 17:20:25 -04:00
Dianne Skoll
f2d1a21a4e Update docs. 2025-03-20 15:40:33 -04:00
Dianne Skoll
81a5241097 Add tests for soleq. 2025-03-20 11:53:11 -04:00
Dianne Skoll
eced4de4a2 Explicitly supply date. 2025-03-20 11:45:11 -04:00
Dianne Skoll
2c8fa39af0 Add tests for astronomical functions. 2025-03-20 11:38:18 -04:00
Dianne Skoll
6ac5e96260 Fix logic bug in astro. 2025-03-20 10:20:08 -04:00
Dianne Skoll
deda94a69e Comment and code cleanups. 2025-03-19 18:08:28 -04:00
Dianne Skoll
abb8cbb1bf Update docs 2025-03-19 17:43:38 -04:00
Dianne Skoll
ee4e3e9073 Bump version to 05.03.05. 2025-03-19 17:38:33 -04:00
Dianne Skoll
220014e60f Document moonrise and moonset functions. 2025-03-19 17:31:29 -04:00
Dianne Skoll
3d0d07ce29 Remove note about OS/2. 2025-03-19 15:41:15 -04:00
Dianne Skoll
38615adb41 Update tests for fixes to 12:XXam 2025-03-19 12:38:36 -04:00
Dianne Skoll
3d8f0e3907 Code cleanup; fix astro example. 2025-03-19 12:35:51 -04:00
Dianne Skoll
160f85a1f8 Fix %2 and %@ formatters to print "12:XXam" instead of "0:XXam" 2025-03-19 12:35:25 -04:00
Dianne Skoll
5cb062166c Add moonrise/moonset to astro example. 2025-03-19 12:18:19 -04:00
Dianne Skoll
81fa6c667f Update unit test. 2025-03-19 11:57:23 -04:00
Dianne Skoll
190dfa3a8f Add moonrisedir and moonsetdir functions. 2025-03-19 11:57:01 -04:00
Dianne Skoll
a22c674846 Add moonrise and moonset functions. 2025-03-19 11:45:34 -04:00
Dianne Skoll
ba224445b1 Allocate 256 expr_nodes in a chunk instead of 64. 2025-03-16 10:55:42 -04:00
Dianne Skoll
6aeee47bfa Remove unused code. 2025-03-16 10:47:54 -04:00
Dianne Skoll
c506fa4613 Refactor code. 2025-03-13 23:51:22 -04:00
Dianne Skoll
04404a252e Remove check for '%' in parse_atom. 2025-03-13 23:45:21 -04:00
Dianne Skoll
be746f9fa7 Print placeholder args when printing error message for user function invoked with incorrect number of arguments. 2025-03-13 23:33:19 -04:00
Dianne Skoll
2393a86970 Fix typo that broke opening reminder file from queue listing. 2025-03-10 17:52:59 -04:00
Dianne Skoll
143ad08b3f Update release notes. 2025-03-09 10:51:13 -04:00
Dianne Skoll
44afdfcb44 Update version to 05.03.04 2025-03-09 10:48:43 -04:00
Dianne Skoll
4b905dbc02 Set LC_ALL and LANG right before sort. 2025-03-08 23:09:30 -05:00
Dianne Skoll
0f76750e05 Set locale for sorting. 2025-03-08 23:04:38 -05:00
Dianne Skoll
b32f56134e Don't redirect stderr to /dev/null on failure to use a required Perl module. 2025-03-04 11:11:34 -05:00
Dianne Skoll
60b0b468df Fix typo 2025-03-03 19:55:52 -05:00
Dianne Skoll
52ce99af80 Document changes since 05.03.02. 2025-03-03 11:27:29 -05:00
Dianne Skoll
5915eb4973 Bump version to 05.03.03. 2025-03-03 11:23:10 -05:00
Dianne Skoll
aa8d23fd87 Add a couple of Dutch translations. 2025-03-01 13:34:37 -05:00
Dianne Skoll
917d943953 Avoid memory leak. 2025-03-01 12:01:15 -05:00
Dianne Skoll
9ade3876b2 Make TkRemind open editor at first line of reminder. 2025-02-16 20:36:50 -05:00
Dianne Skoll
471ecff267 Report both starting and ending lines for commands spanning multiple lines because of \-line continuation.
This affects error and warning messages primarily.  The JSON
interchange format has an additional lineno_start entry for
reminders that span multiple lines.  (Historically, lineno
was the *last* line of the reminder statement and I kept
that for compatibility.)
2025-02-16 20:30:16 -05:00
Dianne Skoll
762bf97473 Add some URLs and a couple of miscellaneous days. 2025-02-13 17:43:02 -05:00
Dianne Skoll
563f3ea088 Remove obsolete files. 2025-02-12 14:39:55 -05:00
Dianne Skoll
939078428f Add some miscellaneous holidays not found in other files. 2025-02-12 13:13:08 -05:00
Dianne Skoll
5acbb907b4 Issue warning if a substitution sequence related to time is used without an AT clause.
All checks were successful
Remind unit tests / tests (push) Successful in 31s
2025-02-10 09:23:43 -05:00
Dianne Skoll
21ecc28ea4 Prep for 05.03.02 release.
All checks were successful
Remind unit tests / tests (push) Successful in 34s
2025-02-09 09:56:45 -05:00
Dianne Skoll
b37a7cd993 Revert change to how -y generates tags.
All checks were successful
Remind unit tests / tests (push) Successful in 48s
Commit e7ec975ff0 changed how the
MD5 sum was calculated to include the filename and line number.

This commit reverts that change; the tag is generated purely
on the REM command line.
2025-02-08 22:25:09 -05:00
Dianne Skoll
64679817ae Update WHATSNEW in preparation for release.
All checks were successful
Remind unit tests / tests (push) Successful in 52s
2025-02-07 13:08:20 -05:00
Dianne Skoll
1ef1033379 Add dependencies to Makefile.PL.in
All checks were successful
Remind unit tests / tests (push) Successful in 45s
2025-02-05 10:58:47 -05:00
Dianne Skoll
7d42750043 Better checks for Perl modules. 2025-02-05 10:57:28 -05:00
Dianne Skoll
1dc0afc0ca Improve small calendar display.
All checks were successful
Remind unit tests / tests (push) Successful in 26s
2025-02-04 22:27:32 -05:00
Dianne Skoll
a0aede4069 Add clickable URL in popup reminder if we have an INFO "Url: ..." string. 2025-02-04 13:58:23 -05:00
Dianne Skoll
a5a7637696 Bump version in preparation for next release. 2025-02-04 13:49:00 -05:00
Dianne Skoll
38a597a374 We're releasing today!
All checks were successful
Remind unit tests / tests (push) Successful in 53s
2025-02-04 10:28:25 -05:00
Dianne Skoll
66ba9257a5 Add INFO strings for Jewish holidays. 2025-02-04 10:23:13 -05:00
Dianne Skoll
c5374c09fb Yet more INFO strings. 2025-02-04 10:11:36 -05:00
Dianne Skoll
9c93e7e6a1 Better error message.
All checks were successful
Remind unit tests / tests (push) Successful in 1m17s
2025-02-03 23:09:17 -05:00
Dianne Skoll
3487f6f46a Document that it takes at least -pp to pass info strings to a back-end. 2025-02-03 23:05:18 -05:00
Dianne Skoll
da8a72d7cd Add info strings. 2025-02-03 22:59:43 -05:00
Dianne Skoll
f391b6221f Add INFO strings. 2025-02-03 22:54:10 -05:00
Dianne Skoll
a8c0b20f9e Line things up better. 2025-02-03 22:47:40 -05:00
Dianne Skoll
5684a86df9 Add INFO strings. 2025-02-03 22:45:26 -05:00
Dianne Skoll
3abaaacd98 Add some more INFO strings. 2025-02-03 22:38:50 -05:00
Dianne Skoll
7eae7a9157 Add some INFO strings. 2025-02-03 22:36:09 -05:00
Dianne Skoll
a0d8c93a34 Make tkremind handle "Url:" info strings.
All checks were successful
Remind unit tests / tests (push) Successful in 39s
2025-02-03 15:18:44 -05:00
Dianne Skoll
8bf22dbb36 Document support for "Url:" info string. 2025-02-03 14:52:42 -05:00
Dianne Skoll
6b2622f3d3 Document "Url" INFO string support. 2025-02-03 14:38:23 -05:00
Dianne Skoll
8abdf6d988 Make rem2html respect "Url:" INFO string for moon phases and week numbers. 2025-02-03 14:32:52 -05:00
Dianne Skoll
991e409739 Make rem2pdf obey the "Url:" INFO string. 2025-02-03 14:20:45 -05:00
Dianne Skoll
3c2bb76523 Turn reminders with a "Url:" info string into hyper-links. 2025-02-03 13:56:21 -05:00
Dianne Skoll
8555352c18 Add popup for location and description in HTML calendar. 2025-02-03 11:36:19 -05:00
Dianne Skoll
34f8486c10 Update docs.
All checks were successful
Remind unit tests / tests (push) Successful in 42s
2025-02-02 11:21:38 -05:00
Dianne Skoll
5adb5d893e Final (??) tweaks of popup appearance. :)
All checks were successful
Remind unit tests / tests (push) Successful in 34s
2025-02-01 15:58:51 -05:00
Dianne Skoll
2f11b6fdc8 Tweak appearance of popups and background reminders. 2025-02-01 15:52:13 -05:00
Dianne Skoll
49d46c1397 Improve reminder popups. 2025-02-01 15:38:13 -05:00
Dianne Skoll
1641f99f97 Include the "info" element in pop-up reminders. 2025-02-01 15:02:54 -05:00
Dianne Skoll
f9f9552850 Avoid segfault if we call dosubst("%<foo>") 2025-02-01 14:50:49 -05:00
Dianne Skoll
3b43222585 Add the triginfo("header") function and corresponding %<...> substitution sequence. 2025-02-01 14:39:06 -05:00
Dianne Skoll
231d9d77e7 Save the info chain when saving the last trigger. 2025-02-01 14:16:17 -05:00
59 changed files with 1672 additions and 540 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1,2 +0,0 @@
liberapay: dskoll

7
.github/README.md vendored
View File

@@ -1,7 +0,0 @@
# Remind has moved
For various reasons, I have decided to move Remind off GitHub. This repo
will be archived. To create merge requests or issues, please visit
Remind's new home at https://salsa.debian.org/dskoll/remind
-- Dianne Skoll

View File

@@ -1,29 +0,0 @@
# language: bash
---
name: Remind unit tests
on:
push
jobs:
tests:
runs-on: ubuntu-latest
steps:
- name: Checkout Remind
uses: actions/checkout@v2
- name: Add test user
run: |
sudo adduser --home /home/testuser --gecos 'Test User' --disabled-password testuser
- name: Fix ownership
run: |
sudo chown -R testuser .
- name: Build
run: |
sudo su -c './configure && make' testuser
- name: Run Tests
run: |
sudo su -c 'make test' testuser
- name: Fix up permissions so GitHub does not complain
run: |
sudo chmod -R a+rwX .

View File

@@ -23,8 +23,7 @@ install:
@$(MAKE) -C rem2html install
@$(MAKE) -C rem2pdf -f Makefile.top install INSTALL_BASE=$(INSTALL_BASE)
clean:
find . -name '*~' -exec rm {} \;
-rm man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1 scripts/tkremind
-find . -name '*~' -exec rm {} \;
-$(MAKE) -C src clean
-$(MAKE) -C rem2pdf clean
@@ -44,7 +43,9 @@ test:
@$(MAKE) -C src -s test
distclean: clean
rm -f config.cache config.log config.status src/Makefile src/config.h tests/test.out www/Makefile rem2pdf/Makefile.top rem2pdf/Makefile.old rem2pdf/Makefile rem2pdf/Makefile.PL rem2pdf/bin/rem2pdf rem2html/rem2html
-rm -f config.cache config.log config.status src/Makefile src/version.h src/config.h tests/test.out www/Makefile rem2pdf/Makefile.top rem2pdf/Makefile.old rem2pdf/Makefile rem2pdf/Makefile.PL rem2pdf/bin/rem2pdf rem2html/rem2html
-rm -f man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1 scripts/tkremind
-rm -rf autom4te.cache rem2html/Makefile rem2html/rem2html.1
src/Makefile: src/Makefile.in
./configure

18
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for remind 05.03.00.
# Generated by GNU Autoconf 2.71 for remind 05.03.05.
#
#
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -608,8 +608,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='remind'
PACKAGE_TARNAME='remind'
PACKAGE_VERSION='05.03.00'
PACKAGE_STRING='remind 05.03.00'
PACKAGE_VERSION='05.03.05'
PACKAGE_STRING='remind 05.03.05'
PACKAGE_BUGREPORT=''
PACKAGE_URL='https://dianne.skoll.ca/projects/remind/'
@@ -1265,7 +1265,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures remind 05.03.00 to adapt to many kinds of systems.
\`configure' configures remind 05.03.05 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1327,7 +1327,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of remind 05.03.00:";;
short | recursive ) echo "Configuration of remind 05.03.05:";;
esac
cat <<\_ACEOF
@@ -1415,7 +1415,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
remind configure 05.03.00
remind configure 05.03.05
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1865,7 +1865,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by remind $as_me 05.03.00, which was
It was created by remind $as_me 05.03.05, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -4710,7 +4710,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by remind $as_me 05.03.00, which was
This file was extended by remind $as_me 05.03.05, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -4775,7 +4775,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
remind config.status 05.03.00
remind config.status 05.03.05
configured by $0, generated by GNU Autoconf 2.71,
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, 05.03.00, , , https://dianne.skoll.ca/projects/remind/)
AC_INIT(remind, 05.03.05, , , https://dianne.skoll.ca/projects/remind/)
AC_CONFIG_SRCDIR([src/queue.c])
cat <<'EOF'

View File

@@ -177,7 +177,7 @@
"slide" "soleq" "stdout" "strlen" "substr" "sunrise" "sunset" "time"
"timepart" "timezone" "today" "trig" "trigback" "trigdate"
"trigdatetime" "trigdelta" "trigduration" "trigeventduration"
"trigeventstart" "trigfrom" "trigger" "trigpriority" "trigrep"
"trigeventstart" "trigfrom" "trigger" "triginfo" "trigpriority" "trigrep"
"trigscanfrom" "trigtags" "trigtime" "trigtimedelta" "trigtimerep"
"triguntil" "trigvalid" "typeof" "tzconvert" "upper" "utctolocal"
"value" "version" "weekno" "wkday" "wkdaynum" "year")

View File

@@ -1,17 +1,97 @@
CHANGES TO REMIND
* VERSION 5.3 Patch 0 - 2025-02-??
* VERSION 5.3 Patch 5 - 2025-03-23
- NEW FEATURE: remind: Add moonrise, moonset, moonrisedir and moonsetdir
functions. The first two functions calculate the time of the next
moonrise and moonset, and the second two calculate in which direction
the moon will rise or set. See the examples/astro script for examples
of how to use the moonrise/moonset functions.
- CODE CLEANUPS: remind: Some minor code cleanups with no user-visible effects.
- IMPROVEMENT: Add tests for the astronomical calculation functions.
- UPDATE: Update the included json.c and json.h files to the latest versions
from https://github.com/udp/json-parser
- BUG FIX: remind: The %2 and %@ sequences would print "0:34am" for the
time 00:34, instead of the correct "12:34am". This has been fixed.
- BUG FIX: TkRemind: Fix bug that broke the ability to open a text editor
on a reminder from the "Queue..." listing.
* VERSION 5.3 Patch 4 - 2025-03-09
- BUG FIX: remind: "make test" could fail if Remind was built in a locale
other than "C". This has been fixed.
- BUG FIX: Fix a typo in the remind man page.
* VERSION 5.3 Patch 3 - 2025-03-03
- NEW FEATURE: remind: If a command spans more than one line (because of
backslash line continuation) output both the starting and ending line
number in error messages.
- NEW FEATURE: remind: In the JSON -pp and -ppp output, include a new key
lineno_start to specify the starting line of a multi-line reminder.
The existing lineno key specifies the ending line; this is maintained
for backward-compatibility.
- MINOR IMPROVEMENT: include/holidays/misc.rem: Add a few new holidays and
URL INFO strings.
- CHANGE: remind: Issue a warning if a time-related substitution sequence
is used with a non-timed REM command.
- BUG FIX: remind: Fix a memory leak.
* VERSION 5.3 Patch 2 - 2025-02-09
- CHANGE: remind: Revert a change to the way "-y" tags are generated that
was introduced in 05.03.01. The change broke a library that depended
on it being generated in the old way.
* VERSION 5.3 Patch 1 - 2025-02-07
- IMPROVEMENT: TkRemind: When we pop up a timed reminder, make any "Url:"
info string into a clickable link.
- IMPROVEMENT: rem2pdf: Improve the layout of the small monthly calendars.
- BUG FIX: rem2pdf: Add checks for all Perl dependencies.
* VERSION 5.3 Patch 0 - 2025-02-04
- NEW FEATURE: remind: Add the "INFO" clause to the REM command. This
is intended for storing additional metadata about an event, such as
the location and a longer description. The intention is to make
Remind <-> iCal conversions preserve as much information as possible.
- NEW FEATURE: rem2html, rem2pdf, tkremind: Add support for the "Url:"
info string that turns reminders into hyper-links. For example,
consider this reminder:
REM 15 INFO "Url: https://foo.example" MSG Foo
The text "Foo" will be made into a link to "https://foo.example"
by rem2html and rem2pdf. If you middle-click it in tkremind, it
will open the URL.
- NEW FEATURE: remind: Add the triginfo() built-in function so a reminder
body can refer to INFO data. Add the %<...> substitution filter as a
shorthand for [triginfo("...")]
- NEW FEATURE: TkRemind: Add "Location" and "Description" fields when
creating a reminder; these are converted to INFO clauses. Also support
a popup window with the extra information when hovering over a reminder
in the calendar display.
- IMPROVEMENT: Update the reminder files included with Remind to add
INFO strings with Wikipedia URLs for various holidays and
astronomical events.
- IMPROVEMENT: remind: Add the "\xAB" escape sequence for parsing quoted
strings, where "AB" is a pair of hex digits.

View File

@@ -32,6 +32,24 @@ EOF
remind -g "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
SET $AddBlankLines 0
FSET angle_to_direction(x) \
IIF(x > 348 || x <= 11, "North", \
x > 11 && x <= 34, "North North-East", \
x > 34 && x <= 56, "North-East", \
x > 56 && x <= 79, "East North-East", \
x > 79 && x <= 101, "East", \
x > 101 && x <= 124, "East South-East", \
x > 124 && x <= 146, "South-East", \
x > 146 && x <= 169, "South South-East", \
x > 169 && x <= 191, "South", \
x > 191 && x <= 214, "South South-West", \
x > 214 && x <= 236, "South-West", \
x > 236 && x <= 259, "West South-West", \
x > 259 && x <= 281, "West", \
x > 281 && x <= 304, "West North-West", \
x > 304 && x <= 326, "North-West", \
"North North-West")
BANNER %
IF $TerminalBackground == 0
REM [moondatetime(0)] +60 SPECIAL COLOR 255 255 0 New moon: 🌑 [$T] %3 (%b)
@@ -48,6 +66,50 @@ EOF
echo ""
remind -g "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
SET $AddBlankLines 0
FSET angle_to_direction(x) \
IIF(x > 348 && x <= 11, "North", \
x > 11 && x <= 34, "North North-East", \
x > 34 && x <= 56, "North-East", \
x > 56 && x <= 79, "East North-East", \
x > 79 && x <= 101, "East", \
x > 101 && x <= 124, "East South-East", \
x > 124 && x <= 146, "South-East", \
x > 146 && x <= 169, "South South-East", \
x > 169 && x <= 191, "South", \
x > 191 && x <= 214, "South South-West", \
x > 214 && x <= 236, "South-West", \
x > 236 && x <= 259, "West South-West", \
x > 259 && x <= 281, "West", \
x > 281 && x <= 304, "West North-West", \
x > 304 && x <= 326, "North-West", \
"North North-West")
BANNER %
set mr moonrise()
set ms moonset()
set mr_a moonrisedir()
set ms_a moonsetdir()
IF mr < ms
REM NOQUEUE [mr] MSG The moon rises %3 in the [angle_to_direction(mr_a)] ([mr_a] degrees)
REM NOQUEUE [ms] MSG The moon sets %3 in the [angle_to_direction(ms_a)] ([ms_a] degrees)
ELSE
REM NOQUEUE [ms] MSG The moon sets %3 in the [angle_to_direction(ms_a)] ([ms_a] degrees)
REM NOQUEUE [mr] MSG The moon rises %3 in the [angle_to_direction(mr_a)] ([mr_a] degrees)
ENDIF
IF (datepart(mr) != today())
REM MSG There is no moonrise today
ENDIF
IF (datepart(ms) != today())
REM MSG There is no moonset today
ENDIF
EOF
echo ""
remind -g "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
SET $AddBlankLines 0
BANNER %

View File

@@ -1,30 +1,30 @@
# SPDX-License-Identifier: GPL-2.0-only
REM 1 Feb 2022 MSG %(Chinese New Year) (%(Tiger))
REM 22 Jan 2023 MSG %(Chinese New Year) (%(Rabbit))
REM 10 Feb 2024 MSG %(Chinese New Year) (%(Dragon))
REM 29 Jan 2025 MSG %(Chinese New Year) (%(Snake))
REM 17 Feb 2026 MSG %(Chinese New Year) (%(Horse))
REM 6 Feb 2027 MSG %(Chinese New Year) (%(Goat))
REM 26 Jan 2028 MSG %(Chinese New Year) (%(Monkey))
REM 13 Feb 2029 MSG %(Chinese New Year) (%(Rooster))
REM 3 Feb 2030 MSG %(Chinese New Year) (%(Dog))
REM 23 Jan 2031 MSG %(Chinese New Year) (%(Pig))
REM 11 Feb 2032 MSG %(Chinese New Year) (%(Rat))
REM 31 Jan 2033 MSG %(Chinese New Year) (%(Ox))
REM 19 Feb 2034 MSG %(Chinese New Year) (%(Tiger))
REM 8 Feb 2035 MSG %(Chinese New Year) (%(Rabbit))
REM 28 Jan 2036 MSG %(Chinese New Year) (%(Dragon))
REM 15 Feb 2037 MSG %(Chinese New Year) (%(Snake))
REM 4 Feb 2038 MSG %(Chinese New Year) (%(Horse))
REM 24 Jan 2039 MSG %(Chinese New Year) (%(Goat))
REM 12 Feb 2040 MSG %(Chinese New Year) (%(Monkey))
REM 1 Feb 2041 MSG %(Chinese New Year) (%(Rooster))
REM 22 Jan 2042 MSG %(Chinese New Year) (%(Dog))
REM 10 Feb 2043 MSG %(Chinese New Year) (%(Pig))
REM 30 Jan 2044 MSG %(Chinese New Year) (%(Rat))
REM 17 Feb 2045 MSG %(Chinese New Year) (%(Ox))
REM 6 Feb 2046 MSG %(Chinese New Year) (%(Tiger))
REM 26 Jan 2047 MSG %(Chinese New Year) (%(Rabbit))
REM 14 Feb 2048 MSG %(Chinese New Year) (%(Dragon))
REM 2 Feb 2049 MSG %(Chinese New Year) (%(Snake))
REM 23 Jan 2050 MSG %(Chinese New Year) (%(Horse))
REM 1 Feb 2022 INFO "Url: https://en.wikipedia.org/wiki/Tiger_(zodiac)" MSG %(Chinese New Year) (%(Tiger))
REM 22 Jan 2023 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %(Chinese New Year) (%(Rabbit))
REM 10 Feb 2024 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %(Chinese New Year) (%(Dragon))
REM 29 Jan 2025 INFO "Url: https://en.wikipedia.org/wiki/Snake_(zodiac)" MSG %(Chinese New Year) (%(Snake))
REM 17 Feb 2026 INFO "Url: https://en.wikipedia.org/wiki/Horse_(zodiac)" MSG %(Chinese New Year) (%(Horse))
REM 6 Feb 2027 INFO "Url: https://en.wikipedia.org/wiki/Goat_(zodiac)" MSG %(Chinese New Year) (%(Goat))
REM 26 Jan 2028 INFO "Url: https://en.wikipedia.org/wiki/Monkey_(zodiac)" MSG %(Chinese New Year) (%(Monkey))
REM 13 Feb 2029 INFO "Url: https://en.wikipedia.org/wiki/Rooster_(zodiac)" MSG %(Chinese New Year) (%(Rooster))
REM 3 Feb 2030 INFO "Url: https://en.wikipedia.org/wiki/Dog_(zodiac)" MSG %(Chinese New Year) (%(Dog))
REM 23 Jan 2031 INFO "Url: https://en.wikipedia.org/wiki/Pig_(zodiac)" MSG %(Chinese New Year) (%(Pig))
REM 11 Feb 2032 INFO "Url: https://en.wikipedia.org/wiki/Rat_(zodiac)" MSG %(Chinese New Year) (%(Rat))
REM 31 Jan 2033 INFO "Url: https://en.wikipedia.org/wiki/Ox_(zodiac)" MSG %(Chinese New Year) (%(Ox))
REM 19 Feb 2034 INFO "Url: https://en.wikipedia.org/wiki/Tiger_(zodiac)" MSG %(Chinese New Year) (%(Tiger))
REM 8 Feb 2035 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %(Chinese New Year) (%(Rabbit))
REM 28 Jan 2036 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %(Chinese New Year) (%(Dragon))
REM 15 Feb 2037 INFO "Url: https://en.wikipedia.org/wiki/Snake_(zodiac)" MSG %(Chinese New Year) (%(Snake))
REM 4 Feb 2038 INFO "Url: https://en.wikipedia.org/wiki/Horse_(zodiac)" MSG %(Chinese New Year) (%(Horse))
REM 24 Jan 2039 INFO "Url: https://en.wikipedia.org/wiki/Goat_(zodiac)" MSG %(Chinese New Year) (%(Goat))
REM 12 Feb 2040 INFO "Url: https://en.wikipedia.org/wiki/Monkey_(zodiac)" MSG %(Chinese New Year) (%(Monkey))
REM 1 Feb 2041 INFO "Url: https://en.wikipedia.org/wiki/Rooster_(zodiac)" MSG %(Chinese New Year) (%(Rooster))
REM 22 Jan 2042 INFO "Url: https://en.wikipedia.org/wiki/Dog_(zodiac)" MSG %(Chinese New Year) (%(Dog))
REM 10 Feb 2043 INFO "Url: https://en.wikipedia.org/wiki/Pig_(zodiac)" MSG %(Chinese New Year) (%(Pig))
REM 30 Jan 2044 INFO "Url: https://en.wikipedia.org/wiki/Rat_(zodiac)" MSG %(Chinese New Year) (%(Rat))
REM 17 Feb 2045 INFO "Url: https://en.wikipedia.org/wiki/Ox_(zodiac)" MSG %(Chinese New Year) (%(Ox))
REM 6 Feb 2046 INFO "Url: https://en.wikipedia.org/wiki/Tiger_(zodiac)" MSG %(Chinese New Year) (%(Tiger))
REM 26 Jan 2047 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %(Chinese New Year) (%(Rabbit))
REM 14 Feb 2048 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %(Chinese New Year) (%(Dragon))
REM 2 Feb 2049 INFO "Url: https://en.wikipedia.org/wiki/Snake_(zodiac)" MSG %(Chinese New Year) (%(Snake))
REM 23 Jan 2050 INFO "Url: https://en.wikipedia.org/wiki/Horse_(zodiac)" MSG %(Chinese New Year) (%(Horse))

View File

@@ -18,90 +18,90 @@ FSET _BackTwoSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)-2)
SET InIsrael VALUE("InIsrael", 0)
SET Reform VALUE("Reform", 0)
REM [hebdate(1, "Tishrey")] MSG Rosh Hashana 1
REM [hebdate(1, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Rosh_Hashanah" MSG Rosh Hashana 1
# No RH-2 or Tzom Gedalia in Reform
IF !Reform
REM [hebdate(2, "Tishrey")] MSG Rosh Hashana 2
REM [_PastSat(3, "Tishrey")] MSG Tzom Gedalia
REM [hebdate(2, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Rosh_Hashanah" MSG Rosh Hashana 2
REM [_PastSat(3, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Fast_of_Gedalia" MSG Tzom Gedalia
ENDIF
REM [hebdate(10, "Tishrey")] MSG Yom Kippur
REM [hebdate(15, "Tishrey")] MSG Sukkot 1
REM [hebdate(10, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Yom_Kippur" MSG Yom Kippur
REM [hebdate(15, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Sukkot" MSG Sukkot 1
IF !InIsrael
REM [hebdate(16, "Tishrey")] MSG Sukkot 2
REM [hebdate(16, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Sukkot" MSG Sukkot 2
ENDIF
REM [hebdate(21, "Tishrey")] MSG Hoshana Rabba
REM [hebdate(22, "Tishrey")] MSG Shemini Atzeret
REM [hebdate(21, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Hoshana_Rabbah" MSG Hoshana Rabba
REM [hebdate(22, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Shemini_Atzeret" MSG Shemini Atzeret
IF InIsrael
REM [hebdate(22, "Tishrey")] MSG Simchat Torah
REM [hebdate(22, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Simchat_Torah" MSG Simchat Torah
ELSE
REM [hebdate(23, "Tishrey")] MSG Simchat Torah
REM [hebdate(23, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Simchat_Torah" MSG Simchat Torah
ENDIF
# Because Kislev can change length, we must be more careful about Chanukah
FSET _chan(x) HEBDATE(24, "Kislev", $U-9)+x
REM [_chan(1)] MSG Chanukah 1
REM [_chan(2)] MSG Chanukah 2
REM [_chan(3)] MSG Chanukah 3
REM [_chan(4)] MSG Chanukah 4
REM [_chan(5)] MSG Chanukah 5
REM [_chan(6)] MSG Chanukah 6
REM [_chan(7)] MSG Chanukah 7
REM [_chan(8)] MSG Chanukah 8
REM [_chan(1)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 1
REM [_chan(2)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 2
REM [_chan(3)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 3
REM [_chan(4)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 4
REM [_chan(5)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 5
REM [_chan(6)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 6
REM [_chan(7)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 7
REM [_chan(8)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 8
# Not sure about Reform's position on the next one.
IF !Reform
# 10 Tevet will never be a Saturday, so whether or not to
# move it is moot. (Thanks to Art Werschulz.)
REM [hebdate(10, "Tevet")] MSG Tzom Tevet
REM [hebdate(10, "Tevet")] INFO "Url: https://en.wikipedia.org/wiki/Tenth_of_Tevet" MSG Tzom Tevet
ENDIF
REM [hebdate(15, "Shvat")] MSG Tu B'Shvat
REM [hebdate(14, "Adar A")] MSG Purim Katan
REM [hebdate(15, "Shvat")] INFO "Url: https://en.wikipedia.org/wiki/Tu_BiShvat" MSG Tu B'Shvat
REM [hebdate(14, "Adar A")] INFO "Url: https://en.wikipedia.org/wiki/Purim#Purim_Katan" MSG Purim Katan
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
IF WKDAYNUM(_h2(13, "Adar")) != 6
REM [_h2(13, "Adar")] MSG Fast of Esther
REM [_h2(13, "Adar")] INFO "Url: https://en.wikipedia.org/wiki/Fast_of_Esther" MSG Fast of Esther
ELSE
REM [_h2(11, "Adar")] MSG Fast of Esther
REM [_h2(11, "Adar")] INFO "Url: https://en.wikipedia.org/wiki/Fast_of_Esther" MSG Fast of Esther
ENDIF
REM [hebdate(14, "Adar")] MSG Purim
REM [hebdate(15, "Nisan")] MSG Pesach
REM [hebdate(14, "Adar")] INFO "Url: https://en.wikipedia.org/wiki/Purim" MSG Purim
REM [hebdate(15, "Nisan")] INFO "Url: https://en.wikipedia.org/wiki/Passover" MSG Pesach
IF !InIsrael
REM [hebdate(16, "Nisan")] MSG Pesach 2
REM [hebdate(16, "Nisan")] INFO "Url: https://en.wikipedia.org/wiki/Passover" MSG Pesach 2
ENDIF
REM [hebdate(21, "Nisan")] MSG Pesach 7
REM [hebdate(21, "Nisan")] INFO "Url: https://en.wikipedia.org/wiki/Passover" MSG Pesach 7
IF !InIsrael && !Reform
REM [hebdate(22, "Nisan")] MSG Pesach 8
REM [hebdate(22, "Nisan")] INFO "Url: https://en.wikipedia.org/wiki/Passover" MSG Pesach 8
ENDIF
REM [hebdate(27, "Nisan")] MSG Yom HaShoah
REM [_BackTwoFri(4, "Iyar")] MSG Yom HaZikaron
REM [_BackTwoSat(5, "Iyar")] MSG Yom Ha'atzmaut
REM [hebdate(27, "Nisan")] INFO "Url: https://en.wikipedia.org/wiki/Yom_HaShoah" MSG Yom HaShoah
REM [_BackTwoFri(4, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Yom_HaZikaron" MSG Yom HaZikaron
REM [_BackTwoSat(5, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Independence_Day_(Israel)" MSG Yom Ha'atzmaut
# Not sure about Reform's position on Lag B'Omer
IF !Reform
REM [hebdate(18, "Iyar")] MSG Lag B'Omer
REM [hebdate(18, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Lag_BaOmer" MSG Lag B'Omer
ENDIF
REM [hebdate(28, "Iyar")] MSG Yom Yerushalayim
REM [hebdate(6, "Sivan")] MSG Shavuot
REM [hebdate(28, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Jerusalem_Day" MSG Yom Yerushalayim
REM [hebdate(6, "Sivan")] INFO "Url: https://en.wikipedia.org/wiki/Shavuot" MSG Shavuot
IF !InIsrael && !Reform
REM [hebdate(7, "Sivan")] MSG Shavuot 2
REM [hebdate(7, "Sivan")] INFO "Url: https://en.wikipedia.org/wiki/Shavuot" MSG Shavuot 2
ENDIF
# Fairly sure Reform Jews don't observe the next two
IF !Reform
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
# fall on a Saturday
REM [_PastSat(17, "Tamuz")] MSG Tzom Tammuz
REM [_PastSat(9, "Av")] MSG Tish'a B'Av
REM [_PastSat(17, "Tamuz")] INFO "Url: https://en.wikipedia.org/wiki/Seventeenth_of_Tammuz" MSG Tzom Tammuz
REM [_PastSat(9, "Av")] INFO "Url: https://en.wikipedia.org/wiki/Tisha_B%27Av" MSG Tish'a B'Av
ENDIF

View File

@@ -4,31 +4,31 @@
#
# SPDX-License-Identifier: GPL-2.0-only
REM Sun 14 Feb MSG Start of Aromantic Spectrum Awareness Week
REM 1 Mar MSG Zero Discrimination Day
REM 31 Mar MSG Trans Day of Visibility
REM 6 Apr MSG International Asexuality Day
REM Wed 8 Apr MSG International Day of Pink
REM 26 Apr MSG Lesbian Visibility Day
REM 17 May MSG International Day Against Homophobia, Biphobia and Transphobia
REM 19 May MSG Agender Pride Day
REM 24 May MSG Pansexual & Panromantic Awareness Day
REM 1 Jun MSG Start of LGBT Pride Month
REM 5 Jun MSG Aromantic Visibility Day
REM Mon 8 Jul MSG Start of Non-Binary Awareness Week
REM 14 Jul MSG Non-Binary People's Day
REM 16 Jul MSG Drag Day
REM 9 Aug MSG Start of Dyke Week
REM 16 Sep MSG Start of Bisexual Awareness Week
REM 23 Sep MSG Celebrate Bisexuality Day
REM 8 Oct MSG Lesbian Day
REM 11 Oct MSG National Coming Out Day
REM Wed 15 Oct MSG Pronouns Day
REM 17 Oct MSG Start of Genderfluid Visibility Week
REM Sun 19 Oct MSG Start of Ace Week
REM 26 Oct MSG Intersex Awareness Day
REM 8 Nov MSG Intersex Day of Remembrance
REM 1 Nov MSG Start of Trans Awareness Month
REM Sun 1 Nov MSG Trans Parent Day
REM 13 Nov MSG Start of Trans Awareness Week
REM 20 Nov MSG Transgender Day of Remembrance
REM Sun 14 Feb INFO "Url: https://en.wikipedia.org/wiki/Aromantic_Spectrum_Awareness_Week" MSG Start of Aromantic Spectrum Awareness Week
REM 1 Mar INFO "Url: https://en.wikipedia.org/wiki/Zero_Discrimination_Day" MSG Zero Discrimination Day
REM 31 Mar INFO "Url: https://en.wikipedia.org/wiki/International_Transgender_Day_of_Visibility" MSG Trans Day of Visibility
REM 6 Apr INFO "Url: https://en.wikipedia.org/wiki/Asexuality#International_Asexuality_Day" MSG International Asexuality Day
REM Wed 8 Apr INFO "Url: https://en.wikipedia.org/wiki/International_Day_of_Pink" MSG International Day of Pink
REM 26 Apr INFO "Url: https://en.wikipedia.org/wiki/Lesbian_Visibility_Day" MSG Lesbian Visibility Day
REM 17 May INFO "Url: https://en.wikipedia.org/wiki/International_Day_Against_Homophobia,_Biphobia_and_Transphobia" MSG International Day Against Homophobia, Biphobia and Transphobia
REM 19 May MSG Agender Pride Day
REM 24 May MSG Pansexual & Panromantic Awareness Day
REM 1 Jun INFO "Url: https://en.wikipedia.org/wiki/LGBT_Pride_Month" MSG Start of LGBT Pride Month
REM 5 Jun INFO "Url: https://en.wikipedia.org/wiki/Aromantic_Visibility_Day" MSG Aromantic Visibility Day
REM Mon 8 Jul MSG Start of Non-Binary Awareness Week
REM 14 Jul INFO "Url: https://en.wikipedia.org/wiki/International_Non-Binary_People%27s_Day" MSG International Non-Binary People's Day
REM 16 Jul INFO "Url: https://en.wikipedia.org/wiki/International_Drag_Day" MSG International Drag Day
REM 9 Aug MSG Start of Dyke Week
REM 16 Sep INFO "Url: https://en.wikipedia.org/wiki/Bisexual_Awareness_Week" MSG Start of Bisexual Awareness Week
REM 23 Sep INFO "Url: https://en.wikipedia.org/wiki/Celebrate_Bisexuality_Day" MSG Celebrate Bisexuality Day
REM 8 Oct MSG Lesbian Day
REM 11 Oct INFO "Url: https://en.wikipedia.org/wiki/National_Coming_Out_Day" MSG National Coming Out Day
REM Wed 15 Oct INFO "Url: https://en.wikipedia.org/wiki/Preferred_gender_pronoun" MSG Pronouns Day
REM 17 Oct MSG Start of Genderfluid Visibility Week
REM Sun 19 Oct INFO "Url: https://en.wikipedia.org/wiki/Asexuality#Ace_Week" MSG Start of Ace Week
REM 26 Oct INFO "Url: https://en.wikipedia.org/wiki/Intersex_Awareness_Day" MSG Intersex Awareness Day
REM 8 Nov INFO "Url: https://en.wikipedia.org/wiki/Intersex_Day_of_Remembrance" MSG Intersex Day of Remembrance
REM 1 Nov MSG Start of Trans Awareness Month
REM Sun 1 Nov MSG Trans Parent Day
REM 13 Nov INFO "Url: https://en.wikipedia.org/wiki/Transgender_Awareness_Week" MSG Start of Trans Awareness Week
REM 20 Nov INFO "Url: https://en.wikipedia.org/wiki/Transgender_Day_of_Remembrance" MSG Transgender Day of Remembrance

View File

@@ -3,6 +3,6 @@
# These are the holidays recognized in Australia
#
# SPDX-License-Identifier: GPL-2.0-only
REM Sat 1 Mar MSG Mardi Gras Parade
REM Fri 1 Sep --7 MSG Wear it Purple Day
REM 1 Oct MSG Start of LGBT History Month
REM Sat 1 Mar INFO "Url: https://en.wikipedia.org/wiki/Sydney_Gay_and_Lesbian_Mardi_Gras" MSG Mardi Gras Parade
REM Fri 1 Sep --7 INFO "Url: https://en.wikipedia.org/wiki/Wear_it_Purple_Day" MSG Wear it Purple Day
REM 1 Oct INFO "Url: https://en.wikipedia.org/wiki/LGBT_History_Month" MSG Start of LGBT History Month

View File

@@ -4,4 +4,4 @@
#
# SPDX-License-Identifier: GPL-2.0-only
REM 1 Oct MSG Start of LGBT History Month
REM 1 Oct INFO "Url: https://en.wikipedia.org/wiki/LGBT_History_Month" MSG Start of LGBT History Month

View File

@@ -4,4 +4,4 @@
#
# SPDX-License-Identifier: GPL-2.0-only
REM 9 Jul MSG Lesbian Visibility Day
REM 9 Jul INFO "Url: https://en.wikipedia.org/wiki/Lesbian_Visibility_Day" MSG Lesbian Visibility Day

View File

@@ -4,4 +4,4 @@
#
# SPDX-License-Identifier: GPL-2.0-only
REM 22 May MSG Irish Marriage Referendum Day
REM 22 May INFO "Url: https://en.wikipedia.org/wiki/Thirty-fourth_Amendment_of_the_Constitution_of_Ireland" MSG Irish Marriage Referendum Day

View File

@@ -4,4 +4,4 @@
#
# SPDX-License-Identifier: GPL-2.0-only
REM 2 Jul MSG Indian Coming Out Day
REM 2 Jul INFO "Url: https://en.wikipedia.org/wiki/Indian_Coming_Out_Day" MSG Indian Coming Out Day

View File

@@ -4,5 +4,5 @@
#
# SPDX-License-Identifier: GPL-2.0-only
REM 1 Feb MSG Start of LGBT History Month
REM 6 May MSG Start of Trans+ History Week
REM 1 Feb INFO "Url: https://en.wikipedia.org/wiki/LGBT_History_Month" MSG Start of LGBT History Month
REM 6 May INFO "Url: https://en.wikipedia.org/wiki/Trans%2B_History_Week" MSG Start of Trans+ History Week

View File

@@ -5,12 +5,12 @@
# SPDX-License-Identifier: GPL-2.0-only
REM 1 Mar MSG Start of Bisexual Health Awareness Month
REM Fri 8 Apr MSG Day of Silence
REM Fri 8 Apr INFO "Url: https://en.wikipedia.org/wiki/Day_of_Silence" MSG Day of Silence
REM 9 Apr MSG Sapphic Visibility Day
REM 22 May MSG Harvey Milk Day
REM 22 May INFO "Url: https://en.wikipedia.org/wiki/Harvey_Milk_Day" MSG Harvey Milk Day
REM 5 Jun MSG HIV Long-Term Survivors Awareness Day
REM 12 Jun MSG Pulse Night of Remembrance
REM 28 Jun MSG Stonewall Riots Anniversary
REM 12 Jun INFO "Url: https://en.wikipedia.org/wiki/Orlando_nightclub_shooting" MSG Pulse Night of Remembrance
REM 28 Jun INFO "Url: https://en.wikipedia.org/wiki/Stonewall_Riots" MSG Stonewall Riots Anniversary
REM 1 Aug MSG Start of Transgender History Month (CA)
REM 1 Oct MSG Start of LGBT History Month
REM Thu 15 Oct MSG Spirit Day
REM 1 Oct INFO "Url: https://en.wikipedia.org/wiki/LGBT_History_Month" MSG Start of LGBT History Month
REM Thu 15 Oct INFO "Url: https://en.wikipedia.org/wiki/Spirit_Day" MSG Spirit Day

View File

@@ -0,0 +1,9 @@
# Miscellaneous holidays
#
# SPDX-License-Identifier: GPL-2.0-only
REM 1 February INFO "Url: https://en.wikipedia.org/wiki/Black_History_Month" MSG Start of Black History Month
REM 1 March INFO "Url: https://en.wikipedia.org/wiki/Women%27s_History_Month" MSG Start of Women's History Month
REM 8 March INFO "Url: https://en.wikipedia.org/wiki/International_Women%27s_Day" MSG International Women's Day
REM Thu 1 May INFO "Url: https://en.wikipedia.org/wiki/National_Day_of_Reason" MSG National Day of Reason
REM 23 March INFO "Url: https://www.atheistrepublic.com/atheist-day" MSG Atheist Day

View File

@@ -86,3 +86,6 @@ TRANSLATE "Sunrise" "Zonsopgang"
TRANSLATE "Sunset" "Zonsondergang"
TRANSLATE "No reminders." "Geen herinneringen."
TRANSLATE "Daylight Saving Time Begins" "Daglicht-sparende tijd begint"
TRANSLATE "Daylight Saving Time Ends" "Daglicht-sparende tijd eindigt"

View File

@@ -2,13 +2,13 @@
# SPDX-License-Identifier: GPL-2.0-only
IF $CalMode || $PsCal
REM [moondate(0)] SPECIAL MOON 0 -1 -1 [moontime(0)]
REM [moondate(1)] SPECIAL MOON 1 -1 -1 [moontime(1)]
REM [moondate(2)] SPECIAL MOON 2 -1 -1 [moontime(2)]
REM [moondate(3)] SPECIAL MOON 3 -1 -1 [moontime(3)]
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)]
REM [moondate(2)] INFO "Url: https://en.wikipedia.org/wiki/Full_moon" SPECIAL MOON 2 -1 -1 [moontime(2)]
REM [moondate(3)] INFO "Url: https://en.wikipedia.org/wiki/Lunar_phase" SPECIAL MOON 3 -1 -1 [moontime(3)]
ELSE
REM NOQUEUE [moondatetime(0)] MSG %(New Moon) (%2)
REM NOQUEUE [moondatetime(1)] MSG %(First Quarter) (%2)
REM NOQUEUE [moondatetime(2)] MSG %(Full Moon) (%2)
REM NOQUEUE [moondatetime(3)] MSG %(Last Quarter) (%2)
REM NOQUEUE INFO "Url: https://en.wikipedia.org/wiki/New_moon" [moondatetime(0)] MSG %(New Moon) (%2)
REM NOQUEUE INFO "Url: https://en.wikipedia.org/wiki/Lunar_phase" [moondatetime(1)] MSG %(First Quarter) (%2)
REM NOQUEUE INFO "Url: https://en.wikipedia.org/wiki/Full_moon" [moondatetime(2)] MSG %(Full Moon) (%2)
REM NOQUEUE INFO "Url: https://en.wikipedia.org/wiki/Lunar_phase" [moondatetime(3)] MSG %(Last Quarter) (%2)
ENDIF

View File

@@ -3,14 +3,14 @@
IF $LatDeg >= 0
# Northern Hemisphere
REM NOQUEUE [soleq(0)] MSG %"%(Vernal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(1)] MSG %"%(Summer Solstice)%" [$Is] %3.
REM NOQUEUE [soleq(2)] MSG %"%(Autumnal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(3)] MSG %"%(Winter Solstice)%" [$Is] %3.
REM NOQUEUE [soleq(0)] INFO "Url: https://en.wikipedia.org/wiki/March_equinox" MSG %"%(Vernal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(1)] INFO "Url: https://en.wikipedia.org/wiki/Summer_solstice" MSG %"%(Summer Solstice)%" [$Is] %3.
REM NOQUEUE [soleq(2)] INFO "Url: https://en.wikipedia.org/wiki/September_equinox" MSG %"%(Autumnal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(3)] INFO "Url: https://en.wikipedia.org/wiki/Winter_solstice" MSG %"%(Winter Solstice)%" [$Is] %3.
ELSE
# Southern Hemisphere
REM NOQUEUE [soleq(0)] MSG %"%(Autumnal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(1)] MSG %"%(Winter Solstice)%" [$Is] %3.
REM NOQUEUE [soleq(2)] MSG %"%(Vernal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(3)] MSG %"%(Summer Solstice)%" [$Is] %3.
REM NOQUEUE [soleq(0)] INFO "Url: https://en.wikipedia.org/wiki/March_equinox" MSG %"%(Autumnal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(1)] INFO "Url: https://en.wikipedia.org/wiki/Winter_solstice" MSG %"%(Winter Solstice)%" [$Is] %3.
REM NOQUEUE [soleq(2)] INFO "Url: https://en.wikipedia.org/wiki/September_equinox" MSG %"%(Vernal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(3)] INFO "Url: https://en.wikipedia.org/wiki/Summer_solstice" MSG %"%(Summer Solstice)%" [$Is] %3.
ENDIF

View File

@@ -492,6 +492,13 @@ The filename in which the reminder was found.
.B lineno \fIn\fR
The line number within the file on which the reminder was found.
.TP
.B lineno_start \fIn\fR
If a reminder spans multiple lines because of backslash
line-continuation, then the \fBlineno\fR entry is the \fIlast\fR line
of the reminder; the \fBlineno_start\fR entry is the \fIfirst\fR line. If
a reminder does \fInot\fR span multiple lines, then only the \fBlineno\fR
entry is present; the \fBlineno_start\fR entry is absent in that case.
.TP
.B nonconst_expr 1
If the reminder contained a non-constant expression that had to be evaluated
to determine the trigger date, this key will be present with the value 1.

View File

@@ -184,14 +184,14 @@ by the reminder's \fIdelta\fR.
.TP
.B \-p\fR[\fBa\fR][\fBp\fR][\fBp\fR][\fBq\fR][+]\fIn\fR
The \fB\-p\fR option is very similar to the \fB\-s\fR option, except
that the output contains additional information for use by a back-end such as the
\fBRem2PS\fR program, which creates a PostScript calendar, and various
other back-end programs. If \fIn\fR starts with "+", then it specifies
a number of weeks rather than a number of months, and back-ends are expected
to produce weekly calendars. Note that not all back-ends support
weekly calendars; currently, only \fBrem2pdf\fR does. Specifying a weekly
calendar implicitly enables the pure JSON interchange format, similar
to \fB\-ppp\fR.
that the output contains additional information for use by a back-end
such as the \fBRem2PS\fR program, which creates a PostScript calendar,
and various other back-end programs. If \fIn\fR starts with "+", then
it specifies a number of weeks rather than a number of months, and
back-ends are expected to produce weekly calendars. Note that not all
back-ends support weekly calendars; currently, only \fBrem2pdf\fR and
\fBrem2html\fR do. Specifying a weekly calendar implicitly enables
the pure JSON interchange format, similar to \fB\-ppp\fR.
.RS
.PP
The format of the \fB\-p\fR output is described in the \fBrem2ps(1)\fR
@@ -207,6 +207,10 @@ format, again documented in \fBrem2ps(1)\fR. If you include a \fBq\fR
letter with this option, then the normal calendar-mode substitution filter
is disabled and the %"...%" sequences are preserved in the output.
.PP
Note that to pass INFO strings to a back-end, you must use \fB\-pp\fR
or \fB\-ppp\fR. The simpler \fB\-p\fR format is not capable of
transmitting the INFO strings to the back-end.
.PP
The \fB\-p\fR, \fB\-pp\fR and \fB\-ppp\fR options implicitly enable
the \fB\-o\fR option.
.PP
@@ -1661,6 +1665,11 @@ is replaced with "\fIyy\fR", the last two digits of the year.
is replaced with the lookup of \fIany_text\fR in the translation table.
It is the equivalent of [_("any_text")] but is more convenient to type.
.TP
.B %<\fIany_text\fR\fB>
is replaced with the INFO value associated with the header \fIany_text\fR
or the empty string if no such INFO value exists. It is the
equivalent of [triginfo("any_text")] but is more convenient to type.
.TP
.B %_
(percent-underscore) is replaced with a newline. You can use this to
achieve multi-line reminders. Note that calendar back-ends vary in
@@ -3702,6 +3711,43 @@ which default to \fBtoday()\fR and midnight, respectively. The returned
value is an integer from 0 to 359, representing the phase of the moon
in degrees. 0 is a new moon, 180 is a full moon, 90 is first-quarter, etc.
.TP
.B moonrise([d_date])
This function returns a DATETIME result giving the date and time of the
first moonrise on or after midnight on \fIdate\fR. If \fIdate\fR is not
supplied, it defaults to \fBtoday()\fR.
.RS
.PP
Note that it is not uncommon for a day to have no moonrise, so the date
part of the return value may not be the same as the \fIdate\fR argument.
So if you want a calendar of moonrise times, you could use something
like this:
.PP
.nf
SET mr moonrise()
IF datepart(mr) == today()
REM NOQUEUE [mr] MSG Moon rises at %3.
ELSE
REM MSG No moonrise today
ENDIF
.fi
.PP
.RE
.TP
.B moonrisedir([d_date])
This function returns an INT result giving the direction from which
the moon will rise on the first moonrise on or after midnight on
\fIdate\fR. If \fIdate\fR is not supplied, it defaults to
\fBtoday()\fR. The return value ranges from 0 to 359, where 0 is North,
90 is East, 180 is South and 270 is West.
.TP
.B moonset([d_date])
This function is analogous to \fBmoonrise()\fR but returns the DATETIME of
the next moonset on or after midnight on \fIdate\fR.
.TP
.B moonsetdir([d_date])
This function is analogous to \fBmoonrisedir()\fR but returns the
direction of moonset.
.TP
.B multitrig(s_trig1 [,s_trig2, [... s_trigN]])
\fBmultitrig\fR evaluates each string as a trigger, similar to \fBevaltrig\fR,
and returns the \fIearliest\fR trigger date that is on or after \fBtoday()\fR.
@@ -3778,7 +3824,7 @@ are effectively swapped, so counting always begins from the older
date.
.PP
If the third argument to \fBnonomitted\fR is an \fBINT\fR, then it must
be greater than zero, and is consider to be the \fIstep\fR by which
be greater than zero, and is considered to be the \fIstep\fR by which
\fBnonomitted\fR counts. For example the following expression:
.PP
.nf
@@ -4292,7 +4338,23 @@ whose value is the maximum of "yyyy-mm-dd" and today.
.B trigfrom()
Returns (as a \fBDATE\fR type) the \fBFROM\fR parameter of the last \fBREM\fR or
\fBIFTRIG\fR command. If there was no \fBFROM\fR parameter, returns the integer -1.
.TP
.B triginfo(s_header)
Returns a \fBSTRING\fR that is the INFO item associated with the header
\fIheader\fR. The header should \fInot\fR contain a colon. Header name
comparisons are case-insensitive.
.RS
.PP
For example, the following will assign "At home" to the variable a and
the empty string to variable b:
.PP
.nf
REM INFO "Location: At home" MSG test
SET a triginfo("location")
SET b triginfo("no_such_header")
.fi
.PP
.RE
.TP
.B trigger(d_date [,t_time [,i_utcflag]]) \fRor\fB trigger(q_datetime [,i_utcflag])
Returns a string suitable for use in a \fBREM\fR command or a
@@ -6435,14 +6497,15 @@ Do not hard-code the above directory in your reminder files. Instead,
use the value of the $SysInclude system variable.
.SH AUTHOR
.PP
Dianne Skoll <dianne@skoll.ca> wrote \fBRemind\fR. The moon code was
copied largely unmodified from "moontool" by John Walker. The sunrise
and sunset functions use ideas from programs by Michael Schwartz and
Marc T. Kaufman. The Hebrew calendar support was taken from "hdate"
by Amos Shapir. OS/2 support was done by Darrel Hankerson, Russ
Herman, and Norman Walsh. The supported languages and their
translators are listed below. Languages marked "complete" support
error messages in that language; all others only support the
Dianne Skoll <dianne@skoll.ca> wrote \fBRemind\fR. The moon phase
code was copied largely unmodified from "moontool" by John Walker.
The moonrise/moonset code comes from
https://github.com/signetica/MoonRise by Stephen R. Schmitt and Cyrus
Rahman. The sunrise and sunset functions use ideas from programs by
Michael Schwartz and Marc T. Kaufman. The Hebrew calendar support was
taken from "hdate" by Amos Shapir. The supported languages and
their translators are listed below. Languages marked "complete"
support error messages in that language; all others only support the
substitution filter mechanism and month/day names.
.PP
\fBGerman\fR --

View File

@@ -103,9 +103,10 @@ The sixth control specifies what \fBRemind\fR should do if a reminder
falls on a holiday or weekend.
Enter the body of the reminder into the \fBSummary:\fR text entry. If
you want, you can enter a location and longer description in the
\fBLocation:\fR and \fBDescription:\fR boxes. If you enter anything
here, they will be added as \fBINFO\fR items to the reminder.
you want, you can enter a location, a URL, and and longer description
in the \fBLocation:\fR, \fBURL:\fR and \fBDescription:\fR boxes. If
you enter anything here, they will be added as \fBINFO\fR items to the
reminder.
To add the reminder to the reminder file, click \fBAdd to reminder file\fR.
To close the dialog without adding the reminder to the file, click
@@ -186,6 +187,11 @@ If a reminder has location or description \fBINFO\fR items, then
hovering over the reminder will pop up a window containing the
location and/or description information.
.SH HYPERLINKS
If a reminder has a "Url:" INFO string set, then middle-clicking
will open the URL using \fBxdg-open\fR.
.SH ERRORS
If there are any errors in your reminder file, the "Queue..." button

View File

@@ -128,6 +128,13 @@ The standard SPECIALs supported by all back-ends
=back
=head1 INFO STRINGS SUPPORTED
Rem2html supports one INFO string, namely C<Url>. Its value
should be a URL. If the C<Url> INFO string is supplied for
a normal reminder, a COLOR special, a MOON special or a WEEK
special, the corresponding output is turned into a hyperlink.
=head1 HIGHLIGHTING TODAY
Older versions of rem2html used to highlight today's date with a red outline.
@@ -359,10 +366,14 @@ sub parse_input
chomp;
last if /^\# rem2ps2? end$/;
next if /^\#/;
my ($y, $m, $d, $special, $tag, $duration, $time, $body);
my ($y, $m, $d, $special, $tag, $duration, $time, $body, $title);
my $url_pre = '';
my $url_post = '';
my $url;
if (m/^(\d*).(\d*).(\d*)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/) {
($y, $m, $d, $special, $tag, $duration, $time, $body) =
($1, $2, $3, $4, $5, $6, $7, $8);
$title = '';
} elsif (/\{/) {
my $obj;
if ($Options{utf8}) {
@@ -371,6 +382,11 @@ sub parse_input
$obj = decode_json($_);
}
next unless ($obj->{date} =~ /^(\d+)-(\d+)-(\d+)$/);
if ($obj->{info} && $obj->{info}->{url}) {
$url = $obj->{info}->{url};
$url_pre = "<a href=\"$url\">";
$url_post = "</a>";
}
$y = $1;
$m = $2;
$d = $3;
@@ -379,6 +395,7 @@ sub parse_input
$duration = $obj->{duration} || '*';
$time = $obj->{time} || '*';
$body = $obj->{body};
$title = info_to_title($obj->{info});
} else {
next;
}
@@ -392,7 +409,8 @@ sub parse_input
} elsif ($special eq 'WEEK') {
$body =~ s/^\s+//;
$body =~ s/\s+$//;
$weeks->{$d1} = $body;
$weeks->{$d1}->{body} = $body;
$weeks->{$d1}->{url} = $url;
} elsif ($special eq 'MOON') {
if ($body =~ /(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) {
my ($phase, $moonsize, $fontsize, $msg) = ($1, $2, $3, $4);
@@ -402,6 +420,7 @@ sub parse_input
$moons->[$d]->{'phase'} = $1;
$moons->[$d]->{'msg'} = '';
}
$moons->[$d]->{url} = $url;
} elsif ($special eq 'SHADE') {
if ($body =~ /(\d+)\s+(\d+)\s+(\d+)/) {
$shades->[$d] = sprintf("#%02X%02X%02X",
@@ -415,10 +434,10 @@ sub parse_input
my($r, $g, $b, $text) = ($1, $2, $3, $4);
my $color = sprintf("style=\"color: #%02X%02X%02X;\"",
$r % 256, $g % 256, $b % 256);
push(@{$days->[$d]}, "<p$class $color>" . fix_whitespace(escape_html($text)) . '</p>');
push(@{$days->[$d]}, "<p$class$title $color>" . $url_pre . fix_whitespace(escape_html($text)) . $url_post . '</p>');
}
} elsif ($special eq '*') {
push(@{$days->[$d]}, "<p$class>" . fix_whitespace(escape_html($body)) . '</p>');
push(@{$days->[$d]}, "<p$class$title>" . $url_pre . fix_whitespace(escape_html($body)) . $url_post . '</p>');
}
}
return $found_data;
@@ -477,6 +496,29 @@ sub emit_ppp_calendars
}
}
sub info_to_title
{
my ($info) = @_;
if (!$info) {
return '';
}
my $done_one = 0;
my $title = '';
foreach my $key ('location', 'description') {
next unless $info->{$key};
if ($done_one) {
$title .= "&#010";
}
$done_one = 1;
my $val = escape_html($info->{$key});
$val =~ s/\n/&#010/g;
$val =~ s/"/&#034;/g;
$val =~ s/</&lt;/g;
$title .= ucfirst($key) . ': ' . $val;
}
return " title=\"$title\"";
}
sub emit_one_ppp_calendar
{
my ($c, $type) = @_;
@@ -537,6 +579,15 @@ sub emit_one_ppp_calendar
my $duration = $obj->{duration} || '*';
my $time = $obj->{time} || '*';
my $body = $obj->{body};
my $title = info_to_title($obj->{info});
my $url_pre = '';
my $url_post = '';
my $url = '';
if ($obj->{info} && $obj->{info}->{url}) {
$url = $obj->{info}->{url};
$url_pre = "<a href=\"$url\">";
$url_post = "</a>";
}
$special = uc($special);
if ($special eq 'HTML') {
push(@{$days->[$col]}, $body);
@@ -545,7 +596,8 @@ sub emit_one_ppp_calendar
} elsif ($special eq 'WEEK') {
$body =~ s/^\s+//;
$body =~ s/\s+$//;
$weeks->{$col} = $body;
$weeks->{$col}->{body} = $body;
$weeks->{$col}->{url} = $url;
} elsif ($special eq 'MOON') {
if ($body =~ /(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) {
my ($phase, $moonsize, $fontsize, $msg) = ($1, $2, $3, $4);
@@ -555,6 +607,7 @@ sub emit_one_ppp_calendar
$moons->[$col]->{'phase'} = $1;
$moons->[$col]->{'msg'} = '';
}
$moons->[$col]->{url} = $url;
} elsif ($special eq 'SHADE') {
if ($body =~ /(\d+)\s+(\d+)\s+(\d+)/) {
$shades->[$col] = sprintf("#%02X%02X%02X",
@@ -568,10 +621,10 @@ sub emit_one_ppp_calendar
my($r, $g, $b, $text) = ($1, $2, $3, $4);
my $color = sprintf("style=\"color: #%02X%02X%02X;\"",
$r % 256, $g % 256, $b % 256);
push(@{$days->[$col]}, "<p$class $color>" . fix_whitespace(escape_html($text)) . '</p>');
push(@{$days->[$col]}, "<p$class$title $color>" . $url_pre . fix_whitespace(escape_html($text)) . $url_post . '</p>');
}
} elsif ($special eq '*') {
push(@{$days->[$col]}, "<p$class>" . fix_whitespace(escape_html($body)) . '</p>');
push(@{$days->[$col]}, "<p$class$title>" . $url_pre . fix_whitespace(escape_html($body)) . $url_post . '</p>');
}
}
output_calendar($type, $cols_to_date_info);
@@ -846,7 +899,11 @@ sub draw_day_cell
my $shade = $shades->[$day];
my $week = '';
if (exists($weeks->{$day})) {
$week = ' ' . $weeks->{$day};
if ($weeks->{$day}->{url}) {
$week = ' <a href="' . $weeks->{$day}->{url} . '">' . escape_html($weeks->{$day}->{body}) . '</a>';
} else {
$week = ' ' . escape_html($weeks->{$day}->{body});
}
}
my $class;
if ($Options{nostyle}) {
@@ -907,10 +964,16 @@ sub draw_day_cell
$alt = 'last';
$title = escape_html(t('Last Quarter'));
}
my $url_pre = '';
my $url_post = '';
if ($moons->[$day]->{url}) {
$url_pre = '<a href="' . $moons->[$day]->{url} . '">';
$url_post = '</a>';
}
if ($Options{nostyle}) {
print("<div style=\"float: left\"><img border=\"0\" width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">$msg</div>");
print("<div style=\"float: left\">$url_pre<img border=\"0\" width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">msg$url_post</div>");
} else {
print("<div class=\"rem-moon\"><img width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">$msg</div>");
print("<div class=\"rem-moon\">$url_pre<img width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">$msg$url_post</div>");
}
}

View File

@@ -18,6 +18,8 @@ WriteMakefile(
'Getopt::Long' => 0,
'Cairo' => 0,
'Pango' => 0,
'JSON::MaybeXS' => 0,
'Encode' => 0,
},
EXE_FILES => [ 'bin/rem2pdf' ]
);

View File

@@ -7,16 +7,18 @@ bindir=@bindir@
datadir=@datadir@
datarootdir=@datarootdir@
PERL=@PERL@
PERLMODS_NEEDED=Getopt::Long Cairo Pango
PERLMODS_NEEDED=Cairo Encode ExtUtils::MakeMaker Getopt::Long JSON::MaybeXS Pango
all: Makefile
@if test "$(PERL)" = "" ; then \
echo "Not building rem2pdf; Perl is required"; exit 0; fi; \
OK=1; \
for m in $(PERLMODS_NEEDED) ; \
do \
$(PERL) -M$$m -e 1 > /dev/null 2>&1; \
if test $$? != 0 ; then echo "Not building rem2pdf; missing $$m"; exit 0; fi; \
$(PERL) -M$$m -e 1 ; \
if test $$? != 0 ; then echo "Missing Perl module: $$m"; OK=0; fi; \
done; \
if test "$$OK" != "1" ; then echo "Not building rem2pdf because of missing perl module(s)"; exit 0; fi; \
$(MAKE) all && exit 0; \
exit 1;
@@ -25,7 +27,7 @@ install:
echo "Not installing rem2pdf; Perl is required"; exit 0; fi; \
for m in $(PERLMODS_NEEDED) ; \
do \
$(PERL) -M$$m -e 1 > /dev/null 2>&1; \
$(PERL) -M$$m -e 1 ; \
if test $$? != 0 ; then echo "Not installing rem2pdf; missing $$m"; exit 0; fi; \
done; \
echo "Installing rem2pdf"; \

View File

@@ -573,6 +573,13 @@ it is syntactically correct. If you use invalid Pango markup, the
Pango library will print a warning and B<rem2pdf> will not render any
output for the invalid reminder.
=head1 INFO STRINGS SUPPORTED
rem2pdf supports one INFO string, namely C<Url>. Its value should be
a URL. If the C<Url> INFO string is supplied for a normal reminder, a
COLOR special, a MOON special, a PANGO special or a WEEK special, the
corresponding output is turned into a hyperlink.
=head1 WEEKLY CALENDARS
B<rem2pdf> will produce weekly calendars if you invoke B<remind> with the

View File

@@ -821,7 +821,6 @@ sub draw_small_calendar
$layout->set_text('88 ');
my ($wid, $h) = $layout->get_pixel_size();
$h += 1;
# Month name
$layout = Pango::Cairo::create_layout($cr);
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
@@ -835,6 +834,7 @@ sub draw_small_calendar
$y += $h;
# Day names
$wid = $width / 7;
for (my $col=0; $col <7; $col++) {
my $j;
if ($self->{mondayfirst}) {
@@ -860,7 +860,11 @@ sub draw_small_calendar
for (my $d=1; $d <= $days; $d++) {
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
$layout->set_font_description($desc);
$layout->set_text($d);
my $dt = $d;
if (length($dt) < 2) {
$dt = ' ' . $dt;
}
$layout->set_text($dt);
$cr->save();
$cr->move_to($x + $col*$wid, $y);
Pango::Cairo::show_layout($cr, $layout);
@@ -892,20 +896,23 @@ sub calculate_small_calendar_font_size
my $font_size = int($scale * 10);
# Check
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
$layout->set_font_description($desc);
$layout->set_text('88 88 88 88 88 88 88');
($wid, $h) = $layout->get_pixel_size();
$h += 1;
$h *= ($rows + 2); # row for month name; row for day names
while(1) {
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
$layout->set_font_description($desc);
$layout->set_text('88 88 88 88 88 88 88');
($wid, $h) = $layout->get_pixel_size();
$h += 1;
$h *= ($rows + 2); # row for month name; row for day names
$scale = $width / $wid;
if (($height / $h) < $scale) {
$scale = $height / $h;
}
$scale = $width / $wid;
if (($height / $h) < $scale) {
$scale = $height / $h;
}
if ($scale < 1) { # Font size is too big
$font_size--;
if ($scale >= 1) { # Font size is OK
last;
}
$font_size -= 0.1;
}
return $font_size;
}

View File

@@ -75,6 +75,10 @@ sub render
my ($x1, $y1, $x2, $y2) = $pdf->col_box_coordinates($so_far, $col, $height, $settings);
my $layout = Pango::Cairo::create_layout($cr);
my $url;
if ($self->{info} && $self->{info}->{url}) {
$url = $self->{info}->{url};
}
$layout->set_width(1024 * ($x2 - $x1 - 2 * $settings->{border_size}));
$layout->set_wrap('word-char');
my $body;
@@ -108,7 +112,13 @@ sub render
$self->{g} / 255,
$self->{b} / 255);
$cr->move_to($x1 + $settings->{border_size}, $so_far);
if ($url) {
$cr->tag_begin(Cairo::TAG_LINK, "uri='$url'");
}
Pango::Cairo::show_layout($cr, $layout);
if ($url) {
$cr->tag_end(Cairo::TAG_LINK);
}
$cr->restore();
}
return $h;
@@ -142,7 +152,18 @@ sub render
$cr->save();
$cr->move_to($x2 - $settings->{border_size}/4 - $wid, $y2 - $settings->{border_size}/4 - $h);
my $url;
if ($self->{info} && $self->{info}->{url}) {
$url = $self->{info}->{url};
}
if ($url) {
$cr->tag_begin(Cairo::TAG_LINK, "uri='$url'");
}
Pango::Cairo::show_layout($cr, $layout);
if ($url) {
$cr->tag_end(Cairo::TAG_LINK);
}
$cr->restore();
return 0;
@@ -204,12 +225,30 @@ sub render
$xc = $x1 + $settings->{border_size} + ($self->{size} / 2);
$yc = $so_far + $settings->{border_size} + ($self->{size} / 2);
}
my $url;
if ($self->{info} && $self->{info}->{url}) {
$url = $self->{info}->{url};
}
if ($url) {
$cr->tag_begin(Cairo::TAG_LINK, "uri='$url'");
}
$self->draw_moon($xc, $yc, $cr);
if ($url) {
$cr->tag_end(Cairo::TAG_LINK);
}
if ($layout) {
$cr->save();
$cr->move_to ($xc + ($self->{size}/2) + $settings->{border_size},
$yc + ($self->{size}/2) - $self->{fontsize} );
if ($url) {
$cr->tag_begin(Cairo::TAG_LINK, "uri='$url'");
}
Pango::Cairo::show_layout($cr, $layout);
if ($url) {
$cr->tag_end(Cairo::TAG_LINK);
}
$cr->restore();
}
}
@@ -284,6 +323,10 @@ sub render
my ($self, $pdf, $cr, $settings, $so_far, $day, $col, $height) = @_;
my ($x1, $y1, $x2, $y2) = $pdf->col_box_coordinates($so_far, $col, $height, $settings);
my $url;
if ($self->{info} && $self->{info}->{url}) {
$url = $self->{info}->{url};
}
my $layout = Pango::Cairo::create_layout($cr);
$layout->set_width(1024 * ($x2 - $x1 - 2 * $settings->{border_size}));
@@ -316,7 +359,13 @@ sub render
} else {
$cr->move_to($x1 + $settings->{border_size}, $so_far);
}
if ($url) {
$cr->tag_begin(Cairo::TAG_LINK, "uri='$url'");
}
Pango::Cairo::show_layout($cr, $layout);
if ($url) {
$cr->tag_end(Cairo::TAG_LINK);
}
$cr->restore();
}
return $h;

View File

@@ -585,6 +585,7 @@ proc CreateCalFrame { w dayNames } {
-highlightthickness 0
frame $w.f$f -padx 0 -pady 0 -highlightthickness 0 -relief flat -bd 0
$w.t$f tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$f"
$w.t$f tag bind REM <ButtonPress-2> "OpenUrl $w.t$f"
$w.t$f tag bind REM <ButtonPress-3> "FireEditor $w.t$f"
pack $w.l$f -in $w.f$f -side top -expand 0 -fill x
pack $w.t$f -in $w.f$f -side top -expand 1 -fill both
@@ -635,6 +636,7 @@ proc ConfigureCalFrame { w firstDay numDays } {
$w.t$i tag delete $t
}
$w.t$i tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$i"
$w.t$i tag bind REM <ButtonPress-2> "OpenUrl $w.t$i"
$w.t$i tag bind REM <ButtonPress-3> "FireEditor $w.t$i"
$w.t$i configure -state disabled -takefocus 0
}
@@ -656,6 +658,7 @@ proc ConfigureCalFrame { w firstDay numDays } {
$w.t$i tag delete $t
}
$w.t$i tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$i"
$w.t$i tag bind REM <ButtonPress-2> "OpenUrl $w.t$i"
$w.t$i tag bind REM <ButtonPress-3> "FireEditor $w.t$i"
$w.t$i configure -state disabled -takefocus 0
}
@@ -686,6 +689,7 @@ proc ConfigureCalFrame { w firstDay numDays } {
$w.t$i tag delete $t
}
$w.t$i tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$i"
$w.t$i tag bind REM <ButtonPress-2> "OpenUrl $w.t$i"
$w.t$i tag bind REM <ButtonPress-3> "FireEditor $w.t$i"
$w.t$i configure -state disabled -takefocus 0
}
@@ -1208,7 +1212,12 @@ proc FillCalWindow {} {
set fname [dict get $obj filename]
# Don't make INCLUDECMD output editable
if {![string match "*|" $fname]} {
set fntag [string cat "FILE_" [dict get $obj lineno] "_" $fname]
if {[dict exists $obj lineno_start]} {
set l [dict get $obj lineno_start]
} else {
set l [dict get $obj lineno]
}
set fntag [string cat "FILE_" $l "_" $fname]
}
}
@@ -1925,24 +1934,31 @@ proc CreateModifyDialog {w day firstDay args} {
grid $w.msglab -row 0 -column 0 -in $w.msg -sticky e
grid $w.entry -row 0 -column 1 -in $w.msg -sticky nsew
# LOCATION and DESCRIPTION
# LOCATION, DESCRIPTION and URL
label $w.loclab -text "Location: "
entry $w.location
balloon_add_help $w.location "Enter the location, if any"
grid $w.loclab -row 1 -column 0 -in $w.msg -sticky e
grid $w.location -row 1 -column 1 -in $w.msg -sticky nsew
label $w.urllab -text "URL: "
entry $w.url
balloon_add_help $w.url "Enter the URL, if any"
grid $w.urllab -row 2 -column 0 -in $w.msg -sticky e
grid $w.url -row 2 -column 1 -in $w.msg -sticky nsew
label $w.desclab -text "Description: "
text $w.description -width 80 -height 5
balloon_add_help $w.description "Enter a detailed description, if any"
grid $w.desclab -row 2 -column 0 -in $w.msg -sticky e
grid $w.description -row 2 -column 1 -in $w.msg -sticky nsew
grid $w.desclab -row 3 -column 0 -in $w.msg -sticky e
grid $w.description -row 3 -column 1 -in $w.msg -sticky nsew
grid columnconfigure $w.msg 0 -weight 0
grid columnconfigure $w.msg 1 -weight 1
grid rowconfigure $w.msg 0 -weight 0
grid rowconfigure $w.msg 1 -weight 0
grid rowconfigure $w.msg 2 -weight 1
grid rowconfigure $w.msg 2 -weight 0
grid rowconfigure $w.msg 3 -weight 1
# BUTTONS
set nbut 0
foreach but $args {
@@ -2309,6 +2325,11 @@ proc CreateReminder {w} {
set description "Description: $description"
append rem " INFO [RemQuotedString $description]"
}
set url [string trim [$w.url get]]
if {$url != ""} {
set url "Url: $url"
append rem " INFO [RemQuotedString $url]"
}
# Check it out!
global Remind
set f [open "|$Remind -arq -e - 2>@1" r+]
@@ -2851,7 +2872,11 @@ proc ShowQueue { queue } {
set fntag ""
catch {
set fname [dict get $q filename]
set lineno [dict get $q lineno]
if {[dict exists $q lineno_start]} {
set lineno [dict get $q lineno_start]
} else {
set lineno [dict get $q lineno]
}
set fntag [string cat "FILE_" $lineno "_" $fname]
}
if { "$fntag" != "" } {
@@ -2969,11 +2994,16 @@ proc DaemonReadable { file } {
set tag [dict get $obj tags]
}
set body [dict get $obj body]
if {[dict exists $obj info]} {
set info [dict get $obj info]
} else {
set info [dict create]
}
set qid "*"
if {[dict exists $obj qid]} {
set qid [dict get $obj qid]
}
IssueBackgroundReminder $body $time $now $tag $qid
IssueBackgroundReminder $body $time $now $tag $qid $info
}
"queue" {
set queue [dict get $obj queue]
@@ -3017,7 +3047,7 @@ proc DaemonReadable { file } {
# Description:
# Reads a background reminder from daemon and pops up window.
#---------------------------------------------------------------------------
proc IssueBackgroundReminder { body time now tag qid } {
proc IssueBackgroundReminder { body time now tag qid info } {
global BgCounter Option Ignore DaemonFile HAVE_SYSNOTIFY NOTIFY_SEND_PATH
if {$Option(Deiconify)} {
wm deiconify .
@@ -3046,7 +3076,7 @@ proc IssueBackgroundReminder { body time now tag qid } {
wm iconname $w "Reminder"
wm title $w "Timed reminder ($time)"
label $w.l -text "Reminder for $time issued at $now"
message $w.msg -width 6i -text $body
message $w.msg -aspect 2000 -text $body -justify left -anchor w -font {-weight bold} -relief groove -bd 2
frame $w.b
# Automatically shut down window after a minute if option says so
@@ -3062,7 +3092,36 @@ proc IssueBackgroundReminder { body time now tag qid } {
button $w.nomore -text "Don't remind me again today" -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
pack $w.msg -side top -expand 1 -fill both -anchor w
frame $w.f
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}
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}
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
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"]
bind $w.f.u <Button-3> [list exec xdg-open "$url"]
bind $w.f.u <Enter> [list $w.f.u configure -font {-weight normal -underline 1}]
bind $w.f.u <Leave> [list $w.f.u configure -font {-weight normal -underline 0}]
balloon_add_help $w.f.u "Click to open $url"
incr row
}
pack $w.b -side top
pack $w.ok -in $w.b -side left
if {$qid != "*"} {
@@ -3502,6 +3561,9 @@ proc ReadTaggedOptions { tag date } {
if {[dict exists $info location]} {
lappend ans -entry-location [dict get $info location]
}
if {[dict exists $info url]} {
lappend ans -entry-url [dict get $info url]
}
if {[dict exists $info description]} {
lappend ans -txtentry-description [dict get $info description]
}
@@ -3637,6 +3699,29 @@ proc EditableLeave { w } {
$w tag configure $tag -underline 0
}
proc OpenUrl { w } {
global SynToObj Balloon
set tags [$w tag names current]
set index [lsearch -glob $tags "__syn__*"]
if {$index < 0} {
return
}
set syntag [lindex $tags $index]
if {![info exists SynToObj($syntag)]} {
return
}
set obj $SynToObj($syntag)
if {![dict exists $obj info]} {
return
}
set info [dict get $obj info]
if {![dict exists $info url]} {
return
}
set url [dict get $info url]
exec xdg-open "$url"
}
proc details_enter { w } {
global SynToObj Balloon
set tags [$w tag names current]
@@ -3651,7 +3736,7 @@ proc details_enter { w } {
set obj $SynToObj($syntag)
set lines {}
if {![dict exists $obj info]} {
return;
return
}
set info [dict get $obj info]
set llen 0
@@ -3661,6 +3746,9 @@ proc details_enter { w } {
if {[dict exists $info description]} {
lappend lines [list "Description:" [dict get $info description]]
}
if {[dict exists $info url]} {
lappend lines [list "URL:" "Middle-click to open [dict get $info url]"]
}
if {[llength $lines] < 1} {
return;
}
@@ -3678,42 +3766,22 @@ proc details_popup { pairs } {
global Balloon
set maxwid 80
set h .balloonhelp
set c 0
toplevel $h -bg #000000
text $h.l -width $maxwid -height 16 -bd 0 -wrap word -relief flat -bg #FFFFC0
$h.l tag configure bold -font {-weight bold}
$h.l tag configure medium -font {-weight normal}
frame $h.l -padx 0 -pady 0 -highlightthickness 0 -relief flat -bd 0 -bg #FFFFC0
pack $h.l -side top -padx 1 -pady 1 -ipadx 2 -ipady 1
foreach pair $pairs {
$h.l insert end [lindex $pair 0] bold " " medium [lindex $pair 1] medium "\n" medium
label $h.lab$c -text "[lindex $pair 0] " -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -bg #FFFFC0 -font {-weight bold}
message $h.m$c -text "[lindex $pair 1] " -justify left -anchor w -aspect 2000 -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -bg #FFFFC0 -font {-weight normal}
grid $h.lab$c -in $h.l -row $c -column 0 -sticky nw
grid $h.m$c -in $h.l -row $c -column 1 -sticky new
incr c
}
# Now calculate actual text window size
set wid 0
set height 0
set text [$h.l get 1.0 end]
set text [string trim $text]
set lines [split $text "\n"]
foreach line $lines {
incr height
set len [string length $line]
incr len
if {$len > $wid} {
set wid $len
}
}
if {$wid > $maxwid} {
set wid $maxwid
}
### NOTE: I should be using "count -displaylines" to size
### the window, but Tk gives the wrong answer. I think
### there is a bug in the text widget. So we count the
### number of lines and add 5 and hope for the best...
incr height 5
$h.l configure -width $wid -height $height
pack $h.l -padx 1 -pady 1 -ipadx 2 -ipady 1
$h.l configure -state disabled
wm overrideredirect $h 1
set geom [balloon_calculate_geometry $h]
wm geometry $h $geom
set Balloon(HelpId) [after $Balloon(StayTime) [list catch { destroy $h }]]
set Balloon(HelpId) [after 10000 "catch { destroy $h }"]
set Balloon(MustLeave) 1
}
@@ -4565,7 +4633,7 @@ proc ShowErrors {} {
set l [split $RemindErrors "\n"]
set i 0
foreach line $l {
if {[regexp {^(.*)\(([0-9]+)\)} $line dummy fname lineno]} {
if {[regexp {^(.*)\(([0-9]+)} $line dummy fname lineno]} {
incr i
set fntag [string cat "FILE_" $lineno "_" $fname]
$w.t insert end $line [list ERR "ERR$i" $fntag]

View File

@@ -48,7 +48,7 @@ test: all
xlat.c: $(REMINDSRCS)
@echo "#include <stddef.h>" > xlat.c
@echo "char const *translatables[] = {" >> xlat.c
@cat $(REMINDSRCS) | grep 'tr(".*")' | sed -e 's/.*tr."/"/' -e 's/").*/"/' | sort | uniq | grep -E -v '^"(am|at|from now|hour|minute|now|on|pm|today|tomorrow|was)"$$' | sed -e 's/^/ /' -e 's/$$/,/' >> xlat.c
@cat $(REMINDSRCS) | grep 'tr(".*")' | sed -e 's/.*tr."/"/' -e 's/").*/"/' | LANG=C LC_ALL=C sort | uniq | grep -E -v '^"(am|at|from now|hour|minute|now|on|pm|today|tomorrow|was)"$$' | sed -e 's/^/ /' -e 's/$$/,/' >> xlat.c
@echo " NULL" >> xlat.c
@echo "};" >> xlat.c

View File

@@ -57,6 +57,7 @@ typedef struct cal_entry {
int duration;
char *filename;
int lineno;
int lineno_start;
Trigger trig;
TimeTrig tt;
int nonconst_expr;
@@ -2327,6 +2328,7 @@ static int DoCalRem(ParsePtr p, int col)
return E_NO_MEM;
}
e->lineno = LineNo;
e->lineno_start = LineNoStart;
if (trig.typ == PASSTHRU_TYPE || is_color) {
StrnCpy(e->passthru, trig.passthru, PASSTHRU_LEN);
@@ -2389,7 +2391,7 @@ void WriteJSONTimeTrigger(TimeTrig const *tt)
}
}
static void
void
WriteJSONInfoChain(TrigInfo *ti)
{
printf("\"info\":{");
@@ -2528,6 +2530,9 @@ static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
if (DoPrefixLineNo) {
PrintJSONKeyPairString("filename", e->filename);
PrintJSONKeyPairInt("lineno", e->lineno);
if (e->lineno != e->lineno_start) {
PrintJSONKeyPairInt("lineno_start", e->lineno_start);
}
}
PrintJSONKeyPairString("passthru", e->passthru);
PrintJSONKeyPairString("tags", DBufValue(&(e->tags)));
@@ -2944,9 +2949,6 @@ char const *SynthesizeTag(void)
static char out[128];
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) CurLine, strlen(CurLine));
MD5Update(&ctx, (unsigned char *) FileName, strlen(FileName));
snprintf((char *) buf, sizeof(buf), "%d", LineNo);
MD5Update(&ctx, buf, strlen( (char *) buf));
MD5Final(buf, &ctx);
snprintf(out, sizeof(out), "__syn__%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
(unsigned int) buf[0], (unsigned int) buf[1],

View File

@@ -72,13 +72,13 @@ check_trigger_function(char const *fname, char const *type)
return;
}
if (f->nargs != 1) {
Wprint(tr("%s function `%s' defined at %s:%d should take 1 argument but actually takes %d"), type, fname, f->filename, f->lineno, f->nargs);
Wprint(tr("%s function `%s' defined at %s(%s) should take 1 argument but actually takes %d"), type, fname, f->filename, line_range(f->lineno_start, f->lineno), f->nargs);
return;
}
if (ensure_expr_references_first_local_arg(f->node)) {
return;
}
Wprint(tr("%s function `%s' defined at %s:%d does not use its argument"), type, fname, f->filename, f->lineno);
Wprint(tr("%s function `%s' defined at %s(%s) does not use its argument"), type, fname, f->filename, line_range(f->lineno_start, f->lineno));
}
static void
@@ -1558,8 +1558,8 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
if (DebugFlag & DB_PRTTRIG) {
int y, m, d;
FromDSE(LastTriggerDate, &y, &m, &d);
fprintf(ErrFp, "%s(%d): Trig(satisfied) = %s, %d %s, %d",
FileName, LineNo,
fprintf(ErrFp, "%s(%s): Trig(satisfied) = %s, %d %s, %d",
FileName, line_range(LineNoStart, LineNo),
get_day_name(LastTriggerDate % 7),
d,
get_month_name(m),

View File

@@ -40,8 +40,8 @@ check_subst_args(UserFunc *f, int n)
if (f->nargs == n) {
return 1;
}
Wprint(tr("Function `%s' defined at %s:%d should take %d argument%s, but actually takes %d"),
f->name, f->filename, f->lineno, n, (n == 1 ? "" : "s"), f->nargs);
Wprint(tr("Function `%s' defined at %s(%s) should take %d argument%s, but actually takes %d"),
f->name, f->filename, line_range(f->lineno_start, f->lineno), n, (n == 1 ? "" : "s"), f->nargs);
return 0;
}
/***************************************************************/
@@ -79,6 +79,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
int origLen = DBufLen(dbuf);
int altmode;
int r;
int origtime;
Value v;
UserFunc *func;
@@ -87,6 +88,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
if (tt) {
tim = tt->ttime;
}
origtime = tim;
if (tim == NO_TIME) tim = curtime;
tdiff = tim - curtime;
adiff = ABS(tdiff);
@@ -123,7 +125,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
pm = (h < 12) ? tr("am") : tr("pm");
}
hh = (h == 12) ? 12 : h % 12;
hh = (h == 12 || h == 0) ? 12 : h % 12;
ch = curtime / 60;
cmin = curtime % 60;
@@ -149,7 +151,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
if (r != OK) {
cpm = (h < 12) ? tr("am") : tr("pm");
}
chh = (ch == 12) ? 12 : ch % 12;
chh = (ch == 0 || ch == 12) ? 12 : ch % 12;
func = FindUserFunc("subst_ordinal");
if (func && check_subst_args(func, 1)) {
@@ -215,6 +217,33 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
if (!c) {
break;
}
if (c == '<') {
DynamicBuffer header;
char const *val;
DBufInit(&header);
while(1) {
c = ParseChar(p, &err, 0);
if (err) {
DBufFree(&header);
return err;
}
if (!c || c == '>') {
break;
}
DBufPutc(&header, c);
}
if (!c) {
Wprint(tr("Warning: Unterminated %%<...> substitution sequence"));
}
err = OK;
val = FindTrigInfo(t, DBufValue(&header));
DBufFree(&header);
if (val) {
SHIP_OUT(val);
}
continue;
}
if (c == '(') {
DynamicBuffer orig;
DynamicBuffer translated;
@@ -378,6 +407,12 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
Eprint("%s", GetErr(r));
}
}
if (origtime == NO_TIME) {
if ((c >= '0' && c <= '9') || (c == '!')) {
Wprint(tr("`%%%c' substitution sequence should not be used without an AT clause"), c);
}
}
switch(UPPER(c)) {
case 'A':
if (altmode == '*' || !strcmp(tr("on"), "")) {
@@ -755,6 +790,8 @@ int DoSubstFromString(char const *source, DynamicBuffer *dbuf,
if (tim == NO_TIME) tim=MinutesPastMidnight(0);
CreateParser(source, &tempP);
tempP.allownested = 0;
tempTrig.infos = NULL;
DBufInit(&tempTrig.tags);
tempTrig.typ = MSG_TYPE;
tempTime.ttime = tim;

View File

@@ -197,7 +197,7 @@ static char const *get_operator_name(expr_node *node);
static UserFunc *CurrentUserFunc = NULL;
/* How many expr_node objects to allocate at a time */
#define ALLOC_CHUNK 64
#define ALLOC_CHUNK 256
static char const *
find_end_of_expr(char const *s)
@@ -626,6 +626,18 @@ debug_exit_userfunc(expr_node *node, Value *ans, int r, Value *locals, int nargs
fprintf(ErrFp, "\n");
}
static void
print_placeholders(int n)
{
int i;
for (i=0; i<n; i++) {
if (i > 0) {
fprintf(ErrFp, ", ");
}
fprintf(ErrFp, "?");
}
}
/***************************************************************/
/* */
/* eval_userfunc - evaluate a user-defined function */
@@ -667,12 +679,12 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* Make sure we have the right number of arguments */
if (node->num_kids < f->nargs) {
DBG(fprintf(ErrFp, "%s(...) => %s\n", fname, GetErr(E_2FEW_ARGS)));
DBG(fprintf(ErrFp, "%s(", fname); print_placeholders(node->num_kids); fprintf(ErrFp, ") => %s\n", GetErr(E_2FEW_ARGS)));
Eprint("%s(): %s", f->name, GetErr(E_2FEW_ARGS));
return E_2FEW_ARGS;
}
if (node->num_kids > f->nargs) {
DBG(fprintf(ErrFp, "%s(...) => %s\n", fname, GetErr(E_2MANY_ARGS)));
DBG(fprintf(ErrFp, "%s(", fname); print_placeholders(node->num_kids); fprintf(ErrFp, ") => %s\n", GetErr(E_2MANY_ARGS)));
Eprint("%s(): %s", f->name, GetErr(E_2MANY_ARGS));
return E_2MANY_ARGS;
}
@@ -723,7 +735,7 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
FuncRecursionLevel++;
/* Add a call to the call stack for better error messages */
pushed = push_call(f->filename, f->name, f->lineno);
pushed = push_call(f->filename, f->name, f->lineno, f->lineno_start);
DBG(debug_enter_userfunc(node, new_locals, f->nargs));
@@ -1130,7 +1142,7 @@ static int add(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* If either is a string, coerce them both to strings and concatenate */
if (v1.type == STR_TYPE || v2.type == STR_TYPE) {
/* Skanky... copy the values shallowly fode debug */
/* Skanky... copy the values shallowly for debug */
Value o1 = v1;
Value o2 = v2;
if ( (r = DoCoerce(STR_TYPE, &v1)) ) {
@@ -1164,6 +1176,8 @@ static int add(expr_node *node, Value *locals, Value *ans, int *nonconst)
strcpy(ans->v.str, v1.v.str);
strcpy(ans->v.str+l1, v2.v.str);
DBG(debug_evaluation_binop(ans, OK, &o1, &o2, "+"));
DestroyValue(v1);
DestroyValue(v2);
return OK;
}
@@ -2188,7 +2202,6 @@ static expr_node *parse_atom(char const **e, int *r, Var *locals, int level)
return NULL;
}
if (!ISID(*s) &&
*s != '%' &&
*s != '$' &&
*s != '"' &&
*s != '\'') {

View File

@@ -50,6 +50,7 @@ typedef struct cache {
struct cache *next;
char const *text;
int LineNo;
int LineNoStart;
} CachedLine;
typedef struct cheader {
@@ -77,6 +78,7 @@ typedef struct {
char const *filename;
FilenameChain *chain;
int LineNo;
int LineNoStart;
unsigned int IfFlags;
int NumIfs;
int IfLinenos[IF_NEST];
@@ -189,6 +191,7 @@ int ReadLine(void)
if (CLine) {
CurLine = CLine->text;
LineNo = CLine->LineNo;
LineNoStart = CLine->LineNoStart;
CLine = CLine->next;
got_a_fresh_line();
clear_callstack();
@@ -218,6 +221,7 @@ static int ReadLineFromFile(int use_pclose)
DBufInit(&buf);
DBufFree(&LineBuffer);
LineNoStart = LineNo+1;
while(fp) {
if (DBufGets(&buf, fp) != OK) {
DBufFree(&LineBuffer);
@@ -332,6 +336,7 @@ int OpenFile(char const *fname)
CLine = h->cache;
STRSET(FileName, fname);
LineNo = 0;
LineNoStart = 0;
if (!h->ownedByMe) {
RunDisabled |= RUN_NOTOWNER;
} else {
@@ -367,6 +372,7 @@ int OpenFile(char const *fname)
CLine = NULL;
if (ShouldCache) {
LineNo = 0;
LineNoStart = 0;
r = CacheFile(fname, 0);
if (r == OK) {
fp = NULL;
@@ -385,6 +391,7 @@ int OpenFile(char const *fname)
}
STRSET(FileName, fname);
LineNo = 0;
LineNoStart = 0;
if (FileName) return OK; else return E_NO_MEM;
}
@@ -487,6 +494,7 @@ static int CacheFile(char const *fname, int use_pclose)
}
cl->next = NULL;
cl->LineNo = LineNo;
cl->LineNoStart = LineNoStart;
cl->text = StrDup(s);
DBufFree(&LineBuffer);
if (!cl->text) {
@@ -565,6 +573,7 @@ static int PopFile(void)
IStackPtr--;
LineNo = i->LineNo;
LineNoStart = i->LineNoStart;
IfFlags = i->IfFlags;
memcpy(IfLinenos, i->IfLinenos, IF_NEST);
NumIfs = i->NumIfs;
@@ -906,6 +915,7 @@ static int IncludeCmd(char const *cmd)
}
i->ownedByMe = 1;
i->LineNo = LineNo;
i->LineNoStart = LineNo;
i->NumIfs = NumIfs;
i->IfFlags = IfFlags;
memcpy(i->IfLinenos, IfLinenos, IF_NEST);
@@ -932,6 +942,7 @@ static int IncludeCmd(char const *cmd)
STRSET(FileName, fname);
DBufFree(&buf);
LineNo = 0;
LineNoStart = 0;
if (!h->ownedByMe) {
RunDisabled |= RUN_NOTOWNER;
} else {
@@ -963,6 +974,7 @@ static int IncludeCmd(char const *cmd)
}
fp = fp2;
LineNo = 0;
LineNoStart = 0;
/* Temporarily turn of file tracing */
old_flag = DebugFlag;
@@ -978,6 +990,7 @@ static int IncludeCmd(char const *cmd)
fp = NULL;
CLine = CachedFiles->cache;
LineNo = 0;
LineNoStart = 0;
STRSET(FileName, fname);
DBufFree(&buf);
return OK;
@@ -1014,6 +1027,7 @@ int IncludeFile(char const *fname)
i->filename = NULL;
}
i->LineNo = LineNo;
i->LineNoStart = LineNoStart;
i->NumIfs = NumIfs;
i->IfFlags = IfFlags;
memcpy(i->IfLinenos, IfLinenos, IF_NEST);

View File

@@ -125,6 +125,10 @@ static int FMonnum (func_info *);
static int FMoondate (func_info *);
static int FMoondatetime (func_info *);
static int FMoonphase (func_info *);
static int FMoonrise (func_info *);
static int FMoonrisedir (func_info *);
static int FMoonset (func_info *);
static int FMoonsetdir (func_info *);
static int FMoontime (func_info *);
static int FMultiTrig (func_info *);
static int FNDawn (func_info *);
@@ -162,6 +166,7 @@ static int FTrigdate (func_info *);
static int FTrigdatetime (func_info *);
static int FTrigdelta (func_info *);
static int FTrigduration (func_info *);
static int FTriginfo (func_info *);
static int FTrigeventduration(func_info *);
static int FTrigeventstart (func_info *);
static int FTrigfrom (func_info *);
@@ -285,6 +290,10 @@ BuiltinFunc Func[] = {
{ "moondate", 1, 3, 0, FMoondate, NULL },
{ "moondatetime", 1, 3, 0, FMoondatetime, NULL },
{ "moonphase", 0, 2, 0, FMoonphase, NULL },
{ "moonrise", 0, 1, 0, FMoonrise, NULL },
{ "moonrisedir", 0, 1, 0, FMoonrisedir, NULL },
{ "moonset", 0, 1, 0, FMoonset, NULL },
{ "moonsetdir", 0, 1, 0, FMoonsetdir, NULL },
{ "moontime", 1, 3, 0, FMoontime, NULL },
{ "multitrig", 1, NO_MAX, 0, FMultiTrig, NULL },
{ "ndawn", 0, 1, 0, FNDawn, NULL },
@@ -326,6 +335,7 @@ BuiltinFunc Func[] = {
{ "trigeventstart", 0, 0, 0, FTrigeventstart, NULL },
{ "trigfrom", 0, 0, 0, FTrigfrom, NULL },
{ "trigger", 1, 3, 0, FTrigger, NULL },
{ "triginfo", 1, 1, 1, FTriginfo, NULL },
{ "trigpriority", 0, 0, 0, FTrigpriority, NULL },
{ "trigrep", 0, 0, 0, FTrigrep, NULL },
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom, NULL },
@@ -1620,6 +1630,17 @@ static int FTrigeventduration(func_info *info)
return OK;
}
static int FTriginfo(func_info *info)
{
char const *s;
ASSERT_TYPE(0, STR_TYPE);
s = FindTrigInfo(&LastTrigger, ARGSTR(0));
if (!s) {
return RetStrVal("", info);
}
return RetStrVal(s, info);
}
static int FTrigeventstart(func_info *info)
{
if (LastTrigger.eventstart == NO_TIME) {
@@ -3303,6 +3324,54 @@ static int FMoondatetime(func_info *info)
return MoonStuff(DATETIME_TYPE, info);
}
static int FMoonrise(func_info *info)
{
int start = DSEToday;
if (Nargs >= 1) {
if (!HASDATE(ARG(0))) return E_BAD_TYPE;
start = DATEPART(ARG(0));
}
RetVal.type = DATETIME_TYPE;
RETVAL = GetMoonrise(start);
return OK;
}
static int FMoonset(func_info *info)
{
int start = DSEToday;
if (Nargs >= 1) {
if (!HASDATE(ARG(0))) return E_BAD_TYPE;
start = DATEPART(ARG(0));
}
RetVal.type = DATETIME_TYPE;
RETVAL = GetMoonset(start);
return OK;
}
static int FMoonrisedir(func_info *info)
{
int start = DSEToday;
if (Nargs >= 1) {
if (!HASDATE(ARG(0))) return E_BAD_TYPE;
start = DATEPART(ARG(0));
}
RetVal.type = INT_TYPE;
RETVAL = GetMoonrise_angle(start);
return OK;
}
static int FMoonsetdir(func_info *info)
{
int start = DSEToday;
if (Nargs >= 1) {
if (!HASDATE(ARG(0))) return E_BAD_TYPE;
start = DATEPART(ARG(0));
}
RetVal.type = INT_TYPE;
RETVAL = GetMoonset_angle(start);
return OK;
}
static int MoonStuff(int type_wanted, func_info *info)
{
int startdate, starttim;

View File

@@ -47,6 +47,7 @@ EXTERN int CurDay;
EXTERN int CurMon;
EXTERN int CurYear;
EXTERN int LineNo;
EXTERN int LineNoStart;
EXTERN int FreshLine;
EXTERN int WarnedAboutImplicit;
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
@@ -119,7 +120,7 @@ EXTERN INIT( int PurgeIncludeDepth, 0);
EXTERN INIT( FILE *PurgeFP, NULL);
EXTERN INIT( int NumIfs, 0);
EXTERN INIT( unsigned int IfFlags, 0);
EXTERN INIT( int IfLinenos[IF_NEST], {0});
EXTERN INIT( int IfLinenos[IF_NEST], {0});
EXTERN INIT( int LastTrigValid, 0);
EXTERN Trigger LastTrigger;
EXTERN TimeTrig LastTimeTrig;

View File

@@ -367,8 +367,8 @@ void InitRemind(int argc, char const *argv[])
PARSENUM(DefaultTDelta, arg);
if (DefaultTDelta < 0) {
DefaultTDelta = 0;
} else if (DefaultTDelta > 1440) {
DefaultTDelta = 1440;
} else if (DefaultTDelta > MINUTES_PER_DAY) {
DefaultTDelta = MINUTES_PER_DAY;
}
}
} else if (!*arg) {

View File

@@ -1,7 +1,7 @@
/* vim: set et ts=3 sw=3 sts=3 ft=c:
*
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
* https://github.com/udp/json-parser
* Copyright (C) 2012-2021 the json-parser authors All rights reserved.
* https://github.com/json-parser/json-parser
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,36 +29,49 @@
#include "json.h"
#define UNUSED(x) ( (void) x )
#ifdef _MSC_VER
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 might give us uintptr_t and UINTPTR_MAX but they also might not be provided */
#include <stdint.h>
#endif
const struct _json_value json_value_none;
#ifndef JSON_INT_T_OVERRIDDEN
#if defined(_MSC_VER)
/* https://docs.microsoft.com/en-us/cpp/cpp/data-type-ranges */
#define JSON_INT_MAX 9223372036854775807LL
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 */
#define JSON_INT_MAX INT_FAST64_MAX
#else
/* C89 */
#include <limits.h>
#define JSON_INT_MAX LONG_MAX
#endif
#endif
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#ifndef JSON_INT_MAX
#define JSON_INT_MAX (json_int_t)(((unsigned json_int_t)(-1)) / (unsigned json_int_t)2);
#endif
typedef unsigned int json_uchar;
/* There has to be a better way to do this */
static const json_int_t JSON_INT_MAX = sizeof(json_int_t) == 1
? INT8_MAX
: (sizeof(json_int_t) == 2
? INT16_MAX
: (sizeof(json_int_t) == 4
? INT32_MAX
: INT64_MAX));
const struct _json_value json_value_none;
static unsigned char hex_value (json_char c)
{
if (isdigit(c))
if (isdigit((unsigned char)c))
return c - '0';
switch (c) {
@@ -79,10 +92,7 @@ static int would_overflow (json_int_t value, json_char b)
typedef struct
{
unsigned long used_memory;
unsigned int uint_max;
unsigned long ulong_max;
size_t used_memory;
json_settings settings;
int first_pass;
@@ -94,19 +104,19 @@ typedef struct
static void * default_alloc (size_t size, int zero, void * user_data)
{
UNUSED(user_data);
return zero ? calloc (1, size) : malloc (size);
(void)user_data; /* ignore unused-parameter warn */
return zero ? calloc (1, size) : malloc (size);
}
static void default_free (void * ptr, void * user_data)
{
UNUSED(user_data);
free (ptr);
(void)user_data; /* ignore unused-parameter warn */
free (ptr);
}
static void * json_alloc (json_state * state, unsigned long size, int zero)
static void * json_alloc (json_state * state, size_t size, int zero)
{
if ((state->ulong_max - state->used_memory) < size)
if ((ULONG_MAX - 8 - state->used_memory) < size)
return 0;
if (state->settings.max_memory
@@ -123,7 +133,7 @@ static int new_value (json_state * state,
json_type type)
{
json_value * value;
int values_size;
size_t values_size;
if (!state->first_pass)
{
@@ -157,14 +167,16 @@ static int new_value (json_state * state,
values_size = sizeof (*value->u.object.values) * value->u.object.length;
if (! (value->u.object.values = (json_object_entry *) json_alloc
(state, values_size + ((unsigned long) value->u.object.values), 0)) )
#ifdef UINTPTR_MAX
(state, values_size + ((uintptr_t) value->u.object.values), 0)) )
#else
(state, values_size + ((size_t) value->u.object.values), 0)) )
#endif
{
return 0;
}
char *s = (char *) value->u.object.values;
s += values_size;
value->_reserved.object_mem = s;
value->_reserved.object_mem = (void *) (((char *) value->u.object.values) + values_size);
value->u.object.length = 0;
break;
@@ -213,8 +225,8 @@ static int new_value (json_state * state,
}
#define whitespace \
case '\n': ++ state.cur_line; state.cur_col = 0; /* FALLTHRU */ \
case ' ': case '\t': case '\r'
case '\n': ++ state.cur_line; state.cur_col = 0; /* FALLTHRU */ \
case ' ': /* FALLTHRU */ case '\t': /* FALLTHRU */ case '\r'
#define string_add(b) \
do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0);
@@ -245,13 +257,13 @@ json_value * json_parse_ex (json_settings * settings,
size_t length,
char * error_buf)
{
json_char error [json_error_max];
char error [json_error_max];
const json_char * end;
json_value * top, * root, * alloc = 0;
json_state state = { 0 };
long flags;
double num_digits = 0, num_e = 0;
double num_fraction = 0;
int num_digits = 0;
double num_e = 0, num_fraction = 0;
/* Skip UTF-8 BOM
*/
@@ -274,12 +286,6 @@ json_value * json_parse_ex (json_settings * settings,
if (!state.settings.mem_free)
state.settings.mem_free = default_free;
memset (&state.uint_max, 0xFF, sizeof (state.uint_max));
memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max));
state.uint_max -= 8; /* limit of how much can be added before next check */
state.ulong_max -= 8;
for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass)
{
json_uchar uchar;
@@ -299,11 +305,11 @@ json_value * json_parse_ex (json_settings * settings,
if (flags & flag_string)
{
if (!b)
{ snprintf (error, sizeof(error), "Unexpected EOF in string (at %u:%u)", line_and_col);
{ sprintf (error, "%u:%u: Unexpected EOF in string", line_and_col);
goto e_failed;
}
if (string_length > state.uint_max)
if (string_length > UINT_MAX - 8)
goto e_overflow;
if (flags & flag_escaped)
@@ -325,7 +331,7 @@ json_value * json_parse_ex (json_settings * settings,
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
(uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
{
snprintf (error, sizeof(error), "Invalid character value `%c` (at %u:%u)", b, line_and_col);
sprintf (error, "%u:%u: Invalid character value `%c`", line_and_col, b);
goto e_failed;
}
@@ -342,7 +348,7 @@ json_value * json_parse_ex (json_settings * settings,
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
(uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
{
snprintf (error, sizeof(error), "Invalid character value `%c` (at %u:%u)", b, line_and_col);
sprintf (error, "%u:%u: Invalid character value `%c`", line_and_col, b);
goto e_failed;
}
@@ -426,11 +432,12 @@ json_value * json_parse_ex (json_settings * settings,
case json_object:
if (state.first_pass) {
char *s = (char *) top->u.object.values;
s += string_length+1;
top->u.object.values = (void *) s;
} else {
if (state.first_pass) {
json_char **chars = (json_char **) &top->u.object.values;
chars[0] += string_length + 1;
}
else
{
top->u.object.values [top->u.object.length].name
= (json_char *) top->_reserved.object_mem;
@@ -472,7 +479,7 @@ json_value * json_parse_ex (json_settings * settings,
if (flags & flag_block_comment)
{
if (!b)
{ snprintf (error, sizeof(error), "%u:%u: Unexpected EOF in block comment", line_and_col);
{ sprintf (error, "%u:%u: Unexpected EOF in block comment", line_and_col);
goto e_failed;
}
@@ -488,12 +495,12 @@ json_value * json_parse_ex (json_settings * settings,
else if (b == '/')
{
if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object)
{ snprintf (error, sizeof(error), "%u:%u: Comment not allowed here", line_and_col);
{ sprintf (error, "%u:%u: Comment not allowed here", line_and_col);
goto e_failed;
}
if (++ state.ptr == end)
{ snprintf (error, sizeof(error), "%u:%u: EOF unexpected", line_and_col);
{ sprintf (error, "%u:%u: EOF unexpected", line_and_col);
goto e_failed;
}
@@ -508,7 +515,7 @@ json_value * json_parse_ex (json_settings * settings,
continue;
default:
snprintf (error, sizeof(error), "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b);
sprintf (error, "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b);
goto e_failed;
};
}
@@ -526,8 +533,8 @@ json_value * json_parse_ex (json_settings * settings,
default:
snprintf (error, sizeof(error), "%u:%u: Trailing garbage: `%c`",
state.cur_line, state.cur_col, b);
sprintf (error, "%u:%u: Trailing garbage: `%c`",
line_and_col, b);
goto e_failed;
};
@@ -545,7 +552,7 @@ json_value * json_parse_ex (json_settings * settings,
if (top && top->type == json_array)
flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next;
else
{ snprintf (error, sizeof(error), "%u:%u: Unexpected ]", line_and_col);
{ sprintf (error, "%u:%u: Unexpected `]`", line_and_col);
goto e_failed;
}
@@ -561,8 +568,8 @@ json_value * json_parse_ex (json_settings * settings,
}
else
{
snprintf (error, sizeof(error), "%u:%u: Expected , before %c",
state.cur_line, state.cur_col, b);
sprintf (error, "%u:%u: Expected `,` before `%c`",
line_and_col, b);
goto e_failed;
}
@@ -576,8 +583,8 @@ json_value * json_parse_ex (json_settings * settings,
}
else
{
snprintf (error, sizeof(error), "%u:%u: Expected : before %c",
state.cur_line, state.cur_col, b);
sprintf (error, "%u:%u: Expected `:` before `%c`",
line_and_col, b);
goto e_failed;
}
@@ -616,7 +623,7 @@ json_value * json_parse_ex (json_settings * settings,
case 't':
if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' ||
if ((end - state.ptr) <= 3 || *(++ state.ptr) != 'r' ||
*(++ state.ptr) != 'u' || *(++ state.ptr) != 'e')
{
goto e_unknown_value;
@@ -632,7 +639,7 @@ json_value * json_parse_ex (json_settings * settings,
case 'f':
if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' ||
if ((end - state.ptr) <= 4 || *(++ state.ptr) != 'a' ||
*(++ state.ptr) != 'l' || *(++ state.ptr) != 's' ||
*(++ state.ptr) != 'e')
{
@@ -647,7 +654,7 @@ json_value * json_parse_ex (json_settings * settings,
case 'n':
if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' ||
if ((end - state.ptr) <= 3 || *(++ state.ptr) != 'u' ||
*(++ state.ptr) != 'l' || *(++ state.ptr) != 'l')
{
goto e_unknown_value;
@@ -661,14 +668,14 @@ json_value * json_parse_ex (json_settings * settings,
default:
if (isdigit (b) || b == '-')
if (isdigit ((unsigned char) b) || b == '-')
{
if (!new_value (&state, &top, &root, &alloc, json_integer))
goto e_alloc_failure;
if (!state.first_pass)
{
while (isdigit (b) || b == '+' || b == '-'
while (isdigit ((unsigned char) b) || b == '+' || b == '-'
|| b == 'e' || b == 'E' || b == '.')
{
if ( (++ state.ptr) == end)
@@ -702,7 +709,7 @@ json_value * json_parse_ex (json_settings * settings,
continue;
}
else
{ snprintf (error, sizeof(error), "%u:%u: Unexpected %c when seeking value", line_and_col, b);
{ sprintf (error, "%u:%u: Unexpected `%c` when seeking value", line_and_col, b);
goto e_failed;
}
};
@@ -722,7 +729,7 @@ json_value * json_parse_ex (json_settings * settings,
case '"':
if (flags & flag_need_comma)
{ snprintf (error, sizeof(error), "%u:%u: Expected , before \"", line_and_col);
{ sprintf (error, "%u:%u: Expected `,` before `\"`", line_and_col);
goto e_failed;
}
@@ -744,10 +751,10 @@ json_value * json_parse_ex (json_settings * settings,
{
flags &= ~ flag_need_comma;
break;
}
/* FALLTHROUGH */
} /* FALLTHRU */
default:
snprintf (error, sizeof(error), "%u:%u: Unexpected `%c` in object", line_and_col, b);
sprintf (error, "%u:%u: Unexpected `%c` in object", line_and_col, b);
goto e_failed;
};
@@ -756,7 +763,7 @@ json_value * json_parse_ex (json_settings * settings,
case json_integer:
case json_double:
if (isdigit (b))
if (isdigit ((unsigned char)b))
{
++ num_digits;
@@ -765,7 +772,7 @@ json_value * json_parse_ex (json_settings * settings,
if (! (flags & flag_num_e))
{
if (flags & flag_num_zero)
{ snprintf (error, sizeof(error), "%u:%u: Unexpected `0` before `%c`", line_and_col, b);
{ sprintf (error, "%u:%u: Unexpected `0` before `%c`", line_and_col, b);
goto e_failed;
}
@@ -780,10 +787,12 @@ json_value * json_parse_ex (json_settings * settings,
}
if (would_overflow(top->u.integer, b))
{ -- num_digits;
{
json_int_t integer = top->u.integer;
-- num_digits;
-- state.ptr;
top->type = json_double;
top->u.dbl = (double)top->u.integer;
top->u.dbl = (double)integer;
continue;
}
@@ -813,13 +822,15 @@ json_value * json_parse_ex (json_settings * settings,
}
else if (b == '.' && top->type == json_integer)
{
json_int_t integer = top->u.integer;
if (!num_digits)
{ snprintf (error, sizeof(error), "%u:%u: Expected digit before `.`", line_and_col);
{ sprintf (error, "%u:%u: Expected digit before `.`", line_and_col);
goto e_failed;
}
top->type = json_double;
top->u.dbl = (double) top->u.integer;
top->u.dbl = (double) integer;
flags |= flag_num_got_decimal;
num_digits = 0;
@@ -831,7 +842,7 @@ json_value * json_parse_ex (json_settings * settings,
if (top->type == json_double)
{
if (!num_digits)
{ snprintf (error, sizeof(error), "%u:%u: Expected digit after `.`", line_and_col);
{ sprintf (error, "%u:%u: Expected digit after `.`", line_and_col);
goto e_failed;
}
@@ -844,8 +855,9 @@ json_value * json_parse_ex (json_settings * settings,
if (top->type == json_integer)
{
json_int_t integer = top->u.integer;
top->type = json_double;
top->u.dbl = (double) top->u.integer;
top->u.dbl = (double) integer;
}
num_digits = 0;
@@ -857,7 +869,7 @@ json_value * json_parse_ex (json_settings * settings,
else
{
if (!num_digits)
{ snprintf (error, sizeof(error), "%u:%u: Expected digit after `e`", line_and_col);
{ sprintf (error, "%u:%u: Expected digit after `e`", line_and_col);
goto e_failed;
}
@@ -926,7 +938,7 @@ json_value * json_parse_ex (json_settings * settings,
};
}
if ( (++ top->parent->u.array.length) > state.uint_max)
if ( (++ top->parent->u.array.length) > UINT_MAX - 8)
goto e_overflow;
top = top->parent;
@@ -942,7 +954,7 @@ json_value * json_parse_ex (json_settings * settings,
e_unknown_value:
snprintf (error, sizeof(error), "%u:%u: Unknown value", line_and_col);
sprintf (error, "%u:%u: Unknown value", line_and_col);
goto e_failed;
e_alloc_failure:
@@ -952,7 +964,7 @@ e_alloc_failure:
e_overflow:
snprintf (error, sizeof(error), "%u:%u: Too long (caught overflow)", line_and_col);
sprintf (error, "%u:%u: Too long (caught overflow)", line_and_col);
goto e_failed;
e_failed:

View File

@@ -1,7 +1,8 @@
/* vim: set et ts=3 sw=3 sts=3 ft=c:
*
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
* https://github.com/udp/json-parser
* Copyright (C) 2012-2021 the json-parser authors All rights reserved.
* https://github.com/json-parser/json-parser
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,15 +36,22 @@
#endif
#ifndef json_int_t
#ifndef _MSC_VER
#include <inttypes.h>
#define json_int_t int64_t
#else
#undef JSON_INT_T_OVERRIDDEN
#if defined(_MSC_VER)
#define json_int_t __int64
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__cplusplus) && __cplusplus >= 201103L)
/* C99 and C++11 */
#include <stdint.h>
#define json_int_t int_fast64_t
#else
/* C89 */
#define json_int_t long
#endif
#else
#define JSON_INT_T_OVERRIDDEN 1
#endif
#include <stdlib.h>
#include <stddef.h>
#ifdef __cplusplus
@@ -56,7 +64,7 @@
typedef struct
{
unsigned long max_memory;
unsigned long max_memory; /* should be size_t, but would modify the API */
int settings;
/* Custom allocator support (leave null to use malloc/free)
@@ -122,11 +130,11 @@ typedef struct _json_value
json_object_entry * values;
#if defined(__cplusplus) && __cplusplus >= 201103L
decltype(values) begin () const
#if defined(__cplusplus)
json_object_entry * begin () const
{ return values;
}
decltype(values) end () const
json_object_entry * end () const
{ return values + length;
}
#endif
@@ -138,11 +146,11 @@ typedef struct _json_value
unsigned int length;
struct _json_value ** values;
#if defined(__cplusplus) && __cplusplus >= 201103L
decltype(values) begin () const
#if defined(__cplusplus)
_json_value ** begin () const
{ return values;
}
decltype(values) end () const
_json_value ** end () const
{ return values + length;
}
#endif

View File

@@ -145,6 +145,7 @@ int main(int argc, char *argv[])
}
DBufInit(&(LastTrigger.tags));
LastTrigger.infos = NULL;
ClearLastTriggers();
atexit(exitfunc);
@@ -896,11 +897,21 @@ void Wprint(char const *fmt, ...)
va_list argptr;
/* We can't use line_range because caller might have used it */
if (FileName) {
if (strcmp(FileName, "-"))
(void) fprintf(ErrFp, "%s(%d): ", FileName, LineNo);
else
(void) fprintf(ErrFp, "-stdin-(%d): ", LineNo);
if (strcmp(FileName, "-")) {
if (LineNoStart == LineNo) {
(void) fprintf(ErrFp, "%s(%d): ", FileName, LineNo);
} else {
(void) fprintf(ErrFp, "%s(%d:%d): ", FileName, LineNoStart, LineNo);
}
} else {
if (LineNoStart == LineNo) {
(void) fprintf(ErrFp, "-stdin-(%d): ", LineNo);
} else {
(void) fprintf(ErrFp, "-stdin-(%d:%d): ", LineNoStart, LineNo);
}
}
}
va_start(argptr, fmt);
@@ -932,7 +943,12 @@ void Eprint(char const *fmt, ...)
fname = "-stdin-";
}
if (FreshLine) {
(void) fprintf(ErrFp, "%s(%d): ", fname, LineNo);
/* We can't use line_range because caller might have used it */
if (LineNo == LineNoStart) {
(void) fprintf(ErrFp, "%s(%d): ", fname, LineNo);
} else {
(void) fprintf(ErrFp, "%s(%d:%d): ", fname, LineNoStart, LineNo);
}
} else {
fprintf(ErrFp, " ");
}
@@ -1116,8 +1132,7 @@ int DoIf(ParsePtr p)
syndrome = IF_TRUE | BEFORE_ELSE;
Eprint("%s", GetErr(r));
} else
if ( (v.type != STR_TYPE && v.v.val) ||
(v.type == STR_TYPE && strcmp(v.v.str, "")) ) {
if (truthy(&v)) {
syndrome = IF_TRUE | BEFORE_ELSE;
} else {
syndrome = IF_FALSE | BEFORE_ELSE;
@@ -1945,7 +1960,9 @@ void
FreeTrig(Trigger *t)
{
DBufFree(&(t->tags));
FreeTrigInfoChain(t->infos);
if (t->infos) {
FreeTrigInfoChain(t->infos);
}
t->infos = NULL;
}
@@ -1972,8 +1989,7 @@ ClearLastTriggers(void)
LastTrigger.warn[0] = 0;
LastTrigger.omitfunc[0] = 0;
LastTrigger.passthru[0] = 0;
DBufFree(&(LastTrigger.tags));
LastTrigger.infos = NULL;
FreeTrig(&LastTrigger);
LastTimeTrig.ttime = NO_TIME;
LastTimeTrig.delta = NO_DELTA;
LastTimeTrig.rep = NO_REP;
@@ -1993,10 +2009,19 @@ SaveAllTriggerInfo(Trigger const *t, TimeTrig const *tt, int trigdate, int trigt
void
SaveLastTrigger(Trigger const *t)
{
DBufFree(&(LastTrigger.tags));
FreeTrig(&LastTrigger);
memcpy(&LastTrigger, t, sizeof(LastTrigger));
/* DON'T hang on to the invalid info chain! */
LastTrigger.infos = NULL;
DBufInit(&(LastTrigger.tags));
DBufPuts(&(LastTrigger.tags), DBufValue(&(t->tags)));
TrigInfo *cur = t->infos;
while(cur) {
AppendTrigInfo(&LastTrigger, cur->info);
cur = cur->next;
}
}
void
@@ -2011,7 +2036,6 @@ SaveLastTimeTrig(TimeTrig const *t)
void
System(char const *cmd, int is_queued)
{
int r;
pid_t kid;
int fd;
int status;
@@ -2044,15 +2068,12 @@ System(char const *cmd, int is_queued)
}
}
/* This is the child process or original if we never forked */
r = system(cmd);
(void) system(cmd);
if (do_exit) {
/* In the child process, so exit! */
exit(0);
}
if (r == 0) {
return;
}
return;
}
char const *

View File

@@ -525,7 +525,7 @@ void HuntPhase(int startdate, int starttim, int phas, int *date, int *time)
/* Convert from Remind representation to year/mon/day */
FromDSE(utcd, &y, &m, &d);
/* Convert to a true Julian date */
jdorig = jtime(y, m, d, (utct / 60), (utct % 60), 0);
jdorig = jtime(y, m, d, (utct / 60), (utct % 60), 0);
jd = jdorig - 45.0;
nt1 = meanphase(jd, 0.0, &k1);
while(1) {
@@ -546,3 +546,409 @@ void HuntPhase(int startdate, int starttim, int phas, int *date, int *time)
t1 = h*60 + min;
UTCToLocal(d1, t1, date, time);
}
/*
Moonrise and Moonset calculations
Derived from: https://github.com/signetica/MoonRise
Original license from that project:
Copyright 2007 Stephen R. Schmitt
Subsequent work Copyright 2020 Cyrus Rahman
You may use or modify this source code in any way you find useful,
provided that you agree that the author(s) have no warranty,
obligations or liability. You must determine the suitability of this
source code for your use.
Redistributions of this source code must retain this copyright notice.
*/
/* How many hours to search for moonrise / moonset? We search
half a window on either side of the starting point */
#define MR_WINDOW 48
/* K1 tide cycle is 1.0027379 cycles per solar day */
#define K1 15*(PI/180)*1.0027379
#define remainder(x, y) ((x) - (y) * rint((x)/(y)))
struct MoonInfo {
time_t queryTime;
time_t riseTime;
time_t setTime;
double riseAz;
double setAz;
int hasRise;
int hasSet;
int isVisible;
};
static void init_moon_info(struct MoonInfo *info)
{
info->queryTime = (time_t) 0;
info->riseTime = (time_t) 0;
info->setTime = (time_t) 0;
info->riseAz = 0.0;
info->setAz = 0.0;
info->hasRise = 0;
info->hasSet = 0;
info->isVisible = 0;
}
/*
Local Sidereal Time
Provides local sidereal time in degrees, requires longitude in degrees
and time in fractional Julian days since Jan 1, 2000, 1200UTC (e.g. the
Julian date - 2451545).
cf. USNO Astronomical Almanac and
https://astronomy.stackexchange.com/questions/24859/local-sidereal-time
*/
static double local_sidereal_time(double offset_days, double longitude)
{
double ltime = (15.0L * (6.697374558L + 0.06570982441908L * offset_days +
remainder(offset_days, 1) * 24 + 12 +
0.000026 * (offset_days / 36525) * (offset_days / 36525)) + longitude) / 360.0;
ltime -= floor(ltime);
return ltime * 360.0;
}
static double julian_from_time_t(time_t t)
{
return ((double) t) / 86400.0L + 2440587.5L;
}
static time_t time_t_from_dse(int dse)
{
int y, m, d;
struct tm local;
FromDSE(dse, &y, &m, &d);
local.tm_sec = 0;
local.tm_min = 0;
local.tm_hour = 0;
local.tm_mday = d;
local.tm_mon = m;
local.tm_year = y-1900;
local.tm_isdst = -1;
return mktime(&local);
}
static int datetime_from_time_t(time_t t)
{
struct tm *local;
int ans;
/* Round to nearest minute */
int min_offset = ((long) t) % 60;
if (min_offset >= 30) {
t += (60 - min_offset);
} else {
t -= min_offset;
}
local = localtime(&t);
ans = DSE(local->tm_year + 1900, local->tm_mon, local->tm_mday) * MINUTES_PER_DAY;
ans += local->tm_hour * 60;
ans += local->tm_min;
return ans;
}
/* 3-point interpolation */
static double interpolate(double f0, double f1, double f2, double p)
{
double a = f1-f0;
double b = f2-f1-a;
return f0 + p * (2*a + b * (2*p - 1));
}
/* Moon position using fundamental arguments
Van Flandern & Pulkkinen, 1979) */
void moon_position(double dayOffset, double *ra, double *declination, double *distance)
{
double l = 0.606434 + 0.03660110129 * dayOffset;
double m = 0.374897 + 0.03629164709 * dayOffset;
double f = 0.259091 + 0.03674819520 * dayOffset;
double d = 0.827362 + 0.03386319198 * dayOffset;
double n = 0.347343 - 0.00014709391 * dayOffset;
double g = 0.993126 + 0.00273777850 * dayOffset;
l = 2 * PI * (l - floor(l));
m = 2 * PI * (m - floor(m));
f = 2 * PI * (f - floor(f));
d = 2 * PI * (d - floor(d));
n = 2 * PI * (n - floor(n));
g = 2 * PI * (g - floor(g));
double v, u, w;
v = 0.39558 * sin(f + n)
+ 0.08200 * sin(f)
+ 0.03257 * sin(m - f - n)
+ 0.01092 * sin(m + f + n)
+ 0.00666 * sin(m - f)
- 0.00644 * sin(m + f - 2*d + n)
- 0.00331 * sin(f - 2*d + n)
- 0.00304 * sin(f - 2*d)
- 0.00240 * sin(m - f - 2*d - n)
+ 0.00226 * sin(m + f)
- 0.00108 * sin(m + f - 2*d)
- 0.00079 * sin(f - n)
+ 0.00078 * sin(f + 2*d + n);
u = 1
- 0.10828 * cos(m)
- 0.01880 * cos(m - 2*d)
- 0.01479 * cos(2*d)
+ 0.00181 * cos(2*m - 2*d)
- 0.00147 * cos(2*m)
- 0.00105 * cos(2*d - g)
- 0.00075 * cos(m - 2*d + g);
w = 0.10478 * sin(m)
- 0.04105 * sin(2*f + 2*n)
- 0.02130 * sin(m - 2*d)
- 0.01779 * sin(2*f + n)
+ 0.01774 * sin(n)
+ 0.00987 * sin(2*d)
- 0.00338 * sin(m - 2*f - 2*n)
- 0.00309 * sin(g)
- 0.00190 * sin(2*f)
- 0.00144 * sin(m + n)
- 0.00144 * sin(m - 2*f - n)
- 0.00113 * sin(m + 2*f + 2*n)
- 0.00094 * sin(m - 2*d + g)
- 0.00092 * sin(2*m - 2*d);
double s;
s = w / sqrt(u - v*v);
*ra = l + atan(s / sqrt(1 - s*s)); // Right ascension
s = v / sqrt(u);
*declination = atan(s / sqrt(1 - s*s)); // Declination
*distance = 60.40974 * sqrt(u); // Distance
}
/* Search for moonrise / moonset events during an hour */
static void test_moon_event(int k, double offset_days, struct MoonInfo *moon_info,
double latitude, double longitude,
double const ra[], double declination[], double const distance[])
{
double ha[3], VHz[3];
double lSideTime;
/* Get (local_sidereal_time - MR_WINDOW / 2) hours in radians. */
lSideTime = local_sidereal_time(offset_days, longitude) * PI / 180.0;
/* Calculate hour angle */
ha[0] = lSideTime - ra[0] + k*K1;
ha[2] = lSideTime - ra[2] + k*K1 + K1;
// Hour Angle and declination at half hour.
ha[1] = (ha[2] + ha[0])/2;
declination[1] = (declination[2] + declination[0])/2;
double s = sin((PI / 180) * latitude);
double c = cos((PI / 180) * latitude);
// refraction + semidiameter at horizon + distance correction
double z = cos((PI / 180) * (90.567 - 41.685 / distance[0]));
VHz[0] = s * sin(declination[0]) + c * cos(declination[0]) * cos(ha[0]) - z;
VHz[2] = s * sin(declination[2]) + c * cos(declination[2]) * cos(ha[2]) - z;
if (signbit(VHz[0]) == signbit(VHz[2]))
goto noevent; // No event this hour.
VHz[1] = s * sin(declination[1]) + c * cos(declination[1]) * cos(ha[1]) - z;
double a, b, d, e, time;
a = 2 * VHz[2] - 4 * VHz[1] + 2 * VHz[0];
b = 4 * VHz[1] - 3 * VHz[0] - VHz[2];
d = b * b - 4 * a * VHz[0];
if (d < 0)
goto noevent; // No event this hour.
d = sqrt(d);
e = (-b + d) / (2 * a);
if ((e < 0) || (e > 1))
e = (-b - d) / (2 * a);
time = k + e + 1 / 120; // Time since k=0 of event (in hours).
// The time we started searching + the time from the start of the search to the
// event is the time of the event. Add (time since k=0) - window/2 hours.
time_t eventTime;
eventTime = moon_info->queryTime + (time - MR_WINDOW / 2) *60 *60;
double hz, nz, dz, az;
hz = ha[0] + e * (ha[2] - ha[0]); // Azimuth of the moon at the event.
nz = -cos(declination[1]) * sin(hz);
dz = c * sin(declination[1]) - s * cos(declination[1]) * cos(hz);
az = atan2(nz, dz) * (180 / PI);
if (az < 0) {
az += 360;
}
// If there is no previously recorded event of this type, save this event.
//
// If this event is previous to queryTime, and is the nearest event to queryTime
// of events of its type previous to queryType, save this event, replacing the
// previously recorded event of its type. Events subsequent to queryTime are
// treated similarly, although since events are tested in chronological order
// no replacements will occur as successive events will be further from
// queryTime.
//
// If this event is subsequent to queryTime and there is an event of its type
// previous to queryTime, then there is an event of the other type between the
// two events of this event's type. If the event of the other type is
// previous to queryTime, then it is the nearest event to queryTime that is
// previous to queryTime. In this case save the current event, replacing
// the previously recorded event of its type. Otherwise discard the current
// event.
//
if ((VHz[0] < 0) && (VHz[2] > 0)) {
if (!moon_info->hasRise ||
((moon_info->riseTime < moon_info->queryTime) == (eventTime < moon_info->queryTime) &&
labs(moon_info->riseTime - moon_info->queryTime) > labs(eventTime - moon_info->queryTime)) ||
((moon_info->riseTime < moon_info->queryTime) != (eventTime < moon_info->queryTime) &&
(moon_info->hasSet &&
(moon_info->riseTime < moon_info->queryTime) == (moon_info->setTime < moon_info->queryTime)))) {
moon_info->riseTime = eventTime;
moon_info->riseAz = az;
moon_info->hasRise = 1;
}
}
if ((VHz[0] > 0) && (VHz[2] < 0)) {
if (!moon_info->hasSet ||
((moon_info->setTime < moon_info->queryTime) == (eventTime < moon_info->queryTime) &&
labs(moon_info->setTime - moon_info->queryTime) > labs(eventTime - moon_info->queryTime)) ||
((moon_info->setTime < moon_info->queryTime) != (eventTime < moon_info->queryTime) &&
(moon_info->hasRise &&
(moon_info->setTime < moon_info->queryTime) == (moon_info->riseTime < moon_info->queryTime)))) {
moon_info->setTime = eventTime;
moon_info->setAz = az;
moon_info->hasSet = 1;
}
}
noevent:
// There are obscure cases in the polar regions that require extra logic.
if (!moon_info->hasRise && !moon_info->hasSet)
moon_info->isVisible = !signbit(VHz[2]);
else if (moon_info->hasRise && !moon_info->hasSet)
moon_info->isVisible = (moon_info->queryTime > moon_info->riseTime);
else if (!moon_info->hasRise && moon_info->hasSet)
moon_info->isVisible = (moon_info->queryTime < moon_info->setTime);
else
moon_info->isVisible = ((moon_info->riseTime < moon_info->setTime && moon_info->riseTime < moon_info->queryTime && moon_info->setTime > moon_info->queryTime) ||
(moon_info->riseTime > moon_info->setTime && (moon_info->riseTime < moon_info->queryTime || moon_info->setTime > moon_info->queryTime)));
return;
}
static void
calculate_moonrise_moonset(double latitude, double longitude, time_t t,
struct MoonInfo *mi)
{
double ra[3], declination[3], distance[3];
double offset_days;
int i;
init_moon_info(mi);
mi->queryTime = t;
/* Days since Jan 1, 2000 12:00UTC */
offset_days = julian_from_time_t(t) - 2451545L;
offset_days -= (double) MR_WINDOW / (2.0 * 24.0);
for (i=0; i<3; i++) {
moon_position(offset_days + i * ((double) MR_WINDOW / (2.0 * 24.0)), &ra[i], &declination[i], &distance[i]);
}
if (ra[1] <= ra[0]) {
ra[1] += 2*PI;
}
if (ra[2] <= ra[1]) {
ra[2] += 2*PI;
}
double window_ra[3], window_declination[3], window_distance[3];
window_ra[0] = ra[0];
window_declination[0] = declination[0];
window_distance[0] = distance[0];
for (int k=0; k < MR_WINDOW; k++) {
double ph = (double) (k+1) / (double) MR_WINDOW;
window_ra[2] = interpolate(ra[0], ra[1], ra[2], ph);
window_declination[2] = interpolate(declination[0], declination[1], declination[2], ph);
window_distance[2] = interpolate(distance[0], distance[1], distance[2], ph);
test_moon_event(k, offset_days, mi, latitude, longitude, window_ra, window_declination, window_distance);
/* Step to next interval */
window_ra[0] = window_ra[2];
window_declination[0] = window_declination[2];
window_distance[0] = window_distance[2];
}
}
/* Get next moonrise or moonset in minutes after midnight of BASEYR
starting from given DSE.
Returns 0 if no moonrise could be computed
If want_angle is true, then returns the azimuth of the event rather
than the time of the event */
#define ME_SEARCH_DAYS 180
static int GetMoonevent(int dse, int is_rise, int want_angle)
{
int i;
int angle;
struct MoonInfo mi;
time_t t = time_t_from_dse(dse);
for (i=0; i<ME_SEARCH_DAYS; i++) {
calculate_moonrise_moonset(Latitude, Longitude, t + i * 86400, &mi);
if (is_rise) {
if (mi.hasRise && mi.riseTime >= t) {
if (want_angle) {
angle = (int) (mi.riseAz + 0.5);
return angle;
} else {
return datetime_from_time_t(mi.riseTime);
}
}
} else {
if (mi.hasSet && mi.setTime >= t) {
if (want_angle) {
angle = (int) (mi.setAz + 0.5);
return angle;
} else {
return datetime_from_time_t(mi.setTime);
}
}
}
}
if (want_angle) {
return -1;
} else {
return 0;
}
}
int GetMoonrise(int dse)
{
return GetMoonevent(dse, 1, 0);
}
int GetMoonset(int dse)
{
return GetMoonevent(dse, 0, 0);
}
int GetMoonrise_angle(int dse)
{
return GetMoonevent(dse, 1, 1);
}
int GetMoonset_angle(int dse)
{
return GetMoonevent(dse, 0, 1);
}

View File

@@ -226,7 +226,7 @@ char const *get_day_name(int wkday);
char const *get_month_name(int mon);
void set_cloexec(FILE *fp);
int push_call(char const *filename, char const *func, int lineno);
int push_call(char const *filename, char const *func, int lineno, int lineno_start);
void clear_callstack(void);
int print_callstack(FILE *fp);
void pop_call(void);
@@ -282,3 +282,10 @@ void FreeTrigInfoChain(TrigInfo *ti);
int AppendTrigInfo(Trigger *t, char const *info);
int TrigInfoHeadersAreTheSame(char const *i1, char const *i2);
int TrigInfoIsValid(char const *info);
char const *FindTrigInfo(Trigger *t, char const *header);
void WriteJSONInfoChain(TrigInfo *ti);
char const *line_range(int lineno_start, int lineno);
int GetMoonrise(int dse);
int GetMoonset(int dse);
int GetMoonrise_angle(int dse);
int GetMoonset_angle(int dse);

View File

@@ -61,6 +61,7 @@ typedef struct queuedrem {
char const *text;
char const *fname;
int lineno;
int lineno_start;
char passthru[PASSTHRU_LEN+1];
char sched[VAR_NAME_LEN+1];
Trigger t;
@@ -224,6 +225,7 @@ int QueueReminder(ParsePtr p, Trigger *trig,
}
qelem->lineno = LineNo;
qelem->lineno_start = LineNoStart;
NumQueued++;
qelem->typ = trig->typ;
strcpy(qelem->passthru, trig->passthru);
@@ -474,6 +476,9 @@ void HandleQueuedReminders(void)
PrintJSONKeyPairString("qid", qid);
PrintJSONKeyPairString("ttime", SimpleTimeNoSpace(q->tt.ttime));
PrintJSONKeyPairString("now", SimpleTimeNoSpace(MinutesPastMidnight(1)));
if (q->t.infos) {
WriteJSONInfoChain(q->t.infos);
}
PrintJSONKeyPairString("tags", DBufValue(&q->t.tags));
} else {
printf("NOTE reminder %s",
@@ -781,6 +786,9 @@ json_queue(QueuedRem const *q)
PrintJSONKeyPairInt("ntrig", q->ntrig);
PrintJSONKeyPairString("filename", q->fname);
PrintJSONKeyPairInt("lineno", q->lineno);
if (q->lineno_start != q->lineno) {
PrintJSONKeyPairInt("lineno_start", q->lineno_start);
}
switch(q->typ) {
case NO_TYPE: PrintJSONKeyPairString("type", "NO_TYPE"); break;
case MSG_TYPE: PrintJSONKeyPairString("type", "MSG_TYPE"); break;

View File

@@ -342,7 +342,7 @@ int main(int argc, char *argv[])
while (!feof(stdin)) {
DBufGets(&buf, stdin);
if (first_line && (!strcmp(DBufValue(&buf), "["))) {
fprintf(stderr, "Rem2PS: It appears that you have invoked Remind with the -ppp option.\n Please use either -p or -pp, but not -ppp.\n");
fprintf(stderr, "Rem2PS: It appears that you have invoked Remind with the -ppp option.\n Please use either -p or -pp, but not -ppp. Also, Rem2PS does\n not support weekly calendars, so do not use -p+ or -pp+.\n");
exit(EXIT_FAILURE);
}
first_line = 0;

View File

@@ -452,8 +452,8 @@ AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int sav
r = today;
if (DebugFlag & DB_PRTTRIG) {
FromDSE(r, &y, &m, &d);
fprintf(ErrFp, "%s(%d): Trig(adj) = %s, %d %s, %d",
FileName, LineNo,
fprintf(ErrFp, "%s(%s): Trig(adj) = %s, %d %s, %d",
FileName, line_range(LineNoStart, LineNo),
get_day_name(r % 7),
d,
get_month_name(m),
@@ -580,8 +580,8 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
if (result == -1) {
trig->expired = 1;
if (DebugFlag & DB_PRTTRIG) {
fprintf(ErrFp, "%s(%d): %s\n",
FileName, LineNo, GetErr(E_EXPIRED));
fprintf(ErrFp, "%s(%s): %s\n",
FileName, line_range(LineNoStart, LineNo), GetErr(E_EXPIRED));
}
return -1;
}
@@ -603,8 +603,8 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
}
if (DebugFlag & DB_PRTTRIG) {
FromDSE(result, &y, &m, &d);
fprintf(ErrFp, "%s(%d): Trig = %s, %d %s, %d",
FileName, LineNo,
fprintf(ErrFp, "%s(%s): Trig = %s, %d %s, %d",
FileName, line_range(LineNoStart, LineNo),
get_day_name(result % 7),
d,
get_month_name(m),
@@ -630,8 +630,8 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
trig->rep == NO_REP) {
trig->expired = 1;
if (DebugFlag & DB_PRTTRIG) {
fprintf(ErrFp, "%s(%d): %s\n",
FileName, LineNo, GetErr(E_EXPIRED));
fprintf(ErrFp, "%s(%s): %s\n",
FileName, line_range(LineNoStart, LineNo), GetErr(E_EXPIRED));
}
if (save_in_globals) {
LastTriggerDate = result;
@@ -655,8 +655,8 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
}
trig->expired = 1;
if (DebugFlag & DB_PRTTRIG) {
fprintf(ErrFp, "%s(%d): %s\n",
FileName, LineNo, GetErr(E_EXPIRED));
fprintf(ErrFp, "%s(%s): %s\n",
FileName, line_range(LineNoStart, LineNo), GetErr(E_EXPIRED));
}
return -1;
}
@@ -706,7 +706,9 @@ FreeTrigInfo(TrigInfo *ti)
{
if (ti->info) {
free( (void *) ti->info);
ti->info = NULL;
}
ti->next = NULL;
free(ti);
}
@@ -792,3 +794,26 @@ TrigInfoIsValid(char const *info)
}
return 1;
}
char const *
FindTrigInfo(Trigger *t, char const *header)
{
TrigInfo *ti;
size_t len;
char const *s;
if (!t || !header || !*header) return NULL;
ti = t->infos;
len = strlen(header);
while(ti) {
if (!strncasecmp(ti->info, header, len) &&
ti->info[len] == ':') {
s = ti->info + len + 1;
while(isspace(*s)) s++;
return s;
}
ti = ti->next;
}
return NULL;
}

View File

@@ -308,5 +308,6 @@ typedef struct udf_struct {
int nargs;
char const *filename;
int lineno;
int lineno_start;
int recurse_flag;
} UserFunc;

View File

@@ -208,8 +208,8 @@ int DoFset(ParsePtr p)
return OK;
}
/* Warn about redefinition */
Wprint(tr("Function `%s' redefined (previously defined at %s:%d)"),
existing->name, existing->filename, existing->lineno);
Wprint(tr("Function `%s' redefined: previously defined at %s(%s)"),
existing->name, existing->filename, line_range(existing->lineno_start, existing->lineno));
}
/* Should be followed by '(' */
@@ -238,6 +238,7 @@ int DoFset(ParsePtr p)
return E_NO_MEM;
}
func->lineno = LineNo;
func->lineno_start = LineNoStart;
func->recurse_flag = 0;
StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN);
DBufFree(&buf);

View File

@@ -192,6 +192,7 @@ typedef struct cs_s {
char const *filename;
char const *func;
int lineno;
int lineno_start;
} cs;
static cs *callstack = NULL;
@@ -206,7 +207,7 @@ destroy_cs(cs *entry)
int
push_call(char const *filename, char const *func, int lineno)
push_call(char const *filename, char const *func, int lineno, int lineno_start)
{
cs *entry;
if (freecs) {
@@ -222,6 +223,7 @@ push_call(char const *filename, char const *func, int lineno)
entry->filename = filename;
entry->func = func;
entry->lineno = lineno;
entry->lineno_start = lineno_start;
entry->next = callstack;
callstack = entry;
return OK;
@@ -255,7 +257,7 @@ print_callstack_aux(FILE *fp, cs *entry)
fprintf(fp, "\n");
}
fprintf(fp, " ");
fprintf(fp, tr("%s(%d): [#%d] %s function `%s'"), entry->filename, entry->lineno, i, in, entry->func);
fprintf(fp, tr("%s(%s): [#%d] %s function `%s'"), entry->filename, line_range(entry->lineno_start, entry->lineno), i, in, entry->func);
}
prev = entry;
entry = entry->next;
@@ -289,3 +291,15 @@ pop_call(void)
destroy_cs(entry);
}
}
char const *
line_range(int lineno_start, int lineno)
{
static char buf[128];
if (lineno_start == lineno) {
snprintf(buf, sizeof(buf), "%d", lineno);
} else {
snprintf(buf, sizeof(buf), "%d:%d", lineno_start, lineno);
}
return buf;
}

View File

@@ -862,7 +862,7 @@ static SysVar SysVarArr[] = {
{"DefaultColor", 1, SPECIAL_TYPE, default_color_func, 0, 0 },
{"DefaultDelta", 1, INT_TYPE, &DefaultDelta, 0, 10000 },
{"DefaultPrio", 1, INT_TYPE, &DefaultPrio, 0, 9999 },
{"DefaultTDelta", 1, INT_TYPE, &DefaultTDelta, 0, 1440 },
{"DefaultTDelta", 1, INT_TYPE, &DefaultTDelta, 0, MINUTES_PER_DAY },
{"DeltaOverride", 0, INT_TYPE, &DeltaOverride, 0, 0 },
{"DontFork", 0, INT_TYPE, &DontFork, 0, 0 },
{"DontQueue", 0, INT_TYPE, &DontQueue, 0, 0 },
@@ -898,7 +898,7 @@ static SysVar SysVarArr[] = {
{"LongSec", 1, SPECIAL_TYPE, longsec_func, 0, 0 },
{"March", 1, TRANS_TYPE, "March", 0, 0 },
{"MaxFullOmits", 0, CONST_INT_TYPE, NULL, MAX_FULL_OMITS, 0},
{"MaxLateMinutes", 1, INT_TYPE, &MaxLateMinutes, 0, 1440 },
{"MaxLateMinutes", 1, INT_TYPE, &MaxLateMinutes, 0, MINUTES_PER_DAY },
{"MaxPartialOmits",0, CONST_INT_TYPE, NULL, MAX_PARTIAL_OMITS, 0},
{"MaxSatIter", 1, INT_TYPE, &MaxSatIter, 10, ANY },
{"MaxStringLen", 1, INT_TYPE, &MaxStringLen, -1, ANY },

View File

@@ -1,13 +0,0 @@
SET $LatDeg 45
SET $LatMin 24
SET $LatSec 0
SET $LongDeg 75
SET $LongMin 39
SET $LongSec 0
SET $MinsFromUTC -300
SET $CalcUTC 0
MSG Dawn: [dawn()]
MSG Sunrise: [sunrise()]
MSG Sunset: [sunset()]
MSG Dusk: [dusk()]

93
tests/sunmoon.rem Normal file
View File

@@ -0,0 +1,93 @@
set $AddBlankLines 0
banner %
set d '2011-01-01'
set x adawn(d)
if x < 5:53 || x > 5:57
REM MSG adawn() is inaccurate! - [x]
endif
set x dawn(d)
if x < 7:06 || x > 7:10
REM MSG dawn() is inaccurate! - [x]
endif
set x sunrise(d)
if x < 7:40 || x > 7:44
REM MSG sunrise() is inaccurate! - [x]
endif
set x sunset(d)
if x < 16:28 || x > 16:32
REM MSG sunset() is inaccurate! - [x]
endif
set x dusk(d)
if x < 17:02 || x > 17:06
REM MSG dusk() is inaccurate! - [x]
endif
set x adusk(d)
if x < 18:15 || x > 18:19
REM MSG adusk() is inaccurate! - [x]
endif
set x moonrise(d)
if x < '2011-01-01@5:14' || x > '2011-01-01@5:18'
REM MSG moonrise() is inaccurate! - [x]
endif
set x moonset(d)
if x < '2011-01-01@13:59' || x > '2011-01-01@14:03'
REM MSG moonset() is inaccurate! - [x]
endif
set x moonphase(d, 0:00)
if x < 319 || x > 323
REM MSG moonphase() is inaccurate! - [x]
endif
set x moondatetime(0, d, 0:00)
if x < '2011-01-04@04:02' || x > '2011-01-04@04:06'
REM MSG moondatetime(0) is inaccurate! - [x]
endif
set x moondatetime(1, d, 0:00)
if x < '2011-01-12@06:31' || x > '2011-01-12@06:35'
REM MSG moondatetime(1) is inaccurate! - [x]
endif
set x moondatetime(2, d, 0:00)
if x < '2011-01-19@16:20' || x > '2011-01-19@16:24'
REM MSG moondatetime(2) is inaccurate! - [x]
endif
set x moondatetime(3, d, 0:00)
if x < '2011-01-26@07:57' || x > '2011-01-26@08:01'
REM MSG moondatetime(3) is inaccurate! - [x]
endif
set x soleq(0, 2011)
if x < '2011-03-20@19:18' || x > '2011-03-20@19:22'
REM MSG soleq(0) is inaccurate! - [x]
endif
set x soleq(1, 2011)
if x < '2011-06-21@13:14' || x > '2011-06-21@13:18'
REM MSG soleq(1) is inaccurate! - [x]
endif
set x soleq(2, 2011)
if x < '2011-09-23@05:02' || x > '2011-09-23@05:06'
REM MSG soleq(2) is inaccurate! - [x]
endif
set x soleq(3, 2011)
if x < '2011-12-22@00:28' || x > '2011-12-22@00:32'
REM MSG soleq(3) is inaccurate! - [x]
endif
if $NumTrig == 0
REM MSG All astronomical functions look OK
endif

View File

@@ -153,9 +153,7 @@ rm -f ../tests/purge_dir/*.rem.purged >> ../tests/test.out 2>&1
../src/remind -p ../tests/shade.rem 1 August 2009 | ../src/rem2ps -e -l -c3 >> ../tests/test.out 2>&1
../src/remind -pp ../tests/shade.rem 1 August 2009 | ../src/rem2ps -e -l -c3 >> ../tests/test.out 2>&1
# The sun tests can fail due to math roundoff error changing the times
# by a minute...
# ../src/remind -p12 ../tests/sun.rem 1 Jan 2011 >> ../tests/test.out 2>&1
TZ=America/Toronto ../src/remind ../tests/sunmoon.rem 1 Jan 2011 >> ../tests/test.out 2>&1
# Test -a vs -aa
../src/remind -q -a - 1 Jan 2012 9:00 <<'EOF' >> ../tests/test.out 2>&1
@@ -181,11 +179,13 @@ EOF
../src/remind -pppq - 1 Jan 2012 9:00 <<'EOF' >> ../tests/test.out 2>&1
REM 2 MSG Normal
SET $DefaultColor "255 0 0"
REM 3 MSG %"Red%" on the calendar!
REM 3 \
MSG %"Red%" on the calendar!
SET $DefaultColor "-1 -1 -1"
REM 4 MSG Normal
# Should give an error
SET $DefaultColor "256 0 0"
# Should give an error - split on two lines to test line number reporting
SET $DefaultColor \
"256 0 0"
EOF
# Test default color with weekly calendar
@@ -647,7 +647,7 @@ EOF
# The INFO keyword
../src/remind -pp - 1 Feb 2024 <<'EOF' >> ../tests/test.out 2>&1
REM Wed INFO "Location: here" INFO "Summary: Nope" MSG Meeting
REM Wed INFO "Location: here" INFO "Summary: Nope" MSG Meeting [triginfo("location")] %<summary> %<nonexist> [triginfo("cabbage")]
EOF
# Invalid info strings
@@ -690,6 +690,11 @@ set a "\x0P"
set a "\x00P"
EOF
# Test diagnostics when using a timed substitution without an AT clause
../src/remind - 1 Feb 2024 1:00 <<EOF >> ../tests/test.out 2>&1
REM MSG %0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %! hahaha
EOF
# Test translate table dumping
../src/remind - 1 Feb 2024 <<EOF >> ../tests/test.out 2>&1
TRANSLATE "\x03" "BREAK"

View File

@@ -801,12 +801,12 @@ Leaving UserFN _ofunc(1991-02-28) => 0
# omitfunc ignores local/global omits
fset _ofunc(x) 0
../tests/test.rem(227): Function `_ofunc' redefined (previously defined at ../tests/test.rem:222)
../tests/test.rem(227): Function `_ofunc' redefined: previously defined at ../tests/test.rem(222)
OMIT 1 March
OMIT 2 March 1991
REM 1 March OMIT Sun OMITFUNC _ofunc AFTER MSG Should trigger 1 March
../tests/test.rem(230): Warning: OMIT is ignored if you use OMITFUNC
../tests/test.rem(230): OMITFUNC function `_ofunc' defined at ../tests/test.rem:227 does not use its argument
../tests/test.rem(230): OMITFUNC function `_ofunc' defined at ../tests/test.rem(227) does not use its argument
Entering UserFN _ofunc(1991-02-15)
Leaving UserFN _ofunc(1991-02-15) => 0
Entering UserFN _ofunc(1991-03-01)
@@ -1047,7 +1047,7 @@ set a057 value("a05"+"6")
"a05" + "6" => "a056"
value("a056") => "SDFJHSDF KSJDFH KJSDFH KSJDFH"
set a058 version()
version() => "05.03.00"
version() => "05.03.05"
set a059 wkday(today())
today() => 1991-02-16
wkday(1991-02-16) => "Saturday"
@@ -2611,7 +2611,7 @@ a056 "SDFJHSDF KSJDFH KJSDFH KSJDFH"
a007 "1991-02-16"
a057 "SDFJHSDF KSJDFH KJSDFH KSJDFH"
a008 "11:44"
a058 "05.03.00"
a058 "05.03.05"
a059 "Saturday"
a010 12
a060 6
@@ -4004,7 +4004,7 @@ psmoon(0) => ../tests/test.rem(813): psmoon() is deprecated; use SPECIAL MOON in
FSET _f(x) 0
SET tmp evaltrig("Wed SKIP OMITFUNC _f",date(1992,1,8))
date(1992, 1, 8) => 1992-01-08
evaltrig("Wed SKIP OMITFUNC _f", 1992-01-08) => ../tests/test.rem(817): OMITFUNC function `_f' defined at ../tests/test.rem:816 does not use its argument
evaltrig("Wed SKIP OMITFUNC _f", 1992-01-08) => ../tests/test.rem(817): OMITFUNC function `_f' defined at ../tests/test.rem(816) does not use its argument
Entering UserFN _f(1992-01-08)
Leaving UserFN _f(1992-01-08) => 0
../tests/test.rem(817): Trig = Wednesday, 8 January, 1992
@@ -4050,7 +4050,7 @@ ENDIF
# Trig with a good warnfunc
FSET w(x) choose(x, 5, 3, 1, 0)
../tests/test.rem(832): Function `w' redefined (previously defined at ../tests/test.rem:826)
../tests/test.rem(832): Function `w' redefined: previously defined at ../tests/test.rem(826)
# Short-circuit operators
IF trig("sun warn w") || trig("thu warn w")
@@ -4998,7 +4998,7 @@ Undefined:
FSET subst_bad() "foo"
REM MSG %{bad}
../tests/test.rem(933): Trig = Saturday, 16 February, 1991
../tests/test.rem(933): Function `subst_bad' defined at ../tests/test.rem:932 should take 3 arguments, but actually takes 0
../tests/test.rem(933): Function `subst_bad' defined at ../tests/test.rem(932) should take 3 arguments, but actually takes 0
@@ -5006,8 +5006,8 @@ FSET subst_ampm(a, b, c, d, e, f, g) "wookie"
REM AT 11:00 MSG %2
../tests/test.rem(937): Trig = Saturday, 16 February, 1991 AT 11:00
../tests/test.rem(937): Function `subst_ampm' defined at ../tests/test.rem:935 should take 1 argument, but actually takes 7
../tests/test.rem(937): Function `subst_ampm' defined at ../tests/test.rem:935 should take 1 argument, but actually takes 7
../tests/test.rem(937): Function `subst_ampm' defined at ../tests/test.rem(935) should take 1 argument, but actually takes 7
../tests/test.rem(937): Function `subst_ampm' defined at ../tests/test.rem(935) should take 1 argument, but actually takes 7
at 11:00am
FUNSET subst_ampm
@@ -5182,7 +5182,7 @@ FSET f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a1
# This should give an error
FSET f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, a62, a63, a64) 3
../tests/test.rem(1023): Function `f' redefined (previously defined at ../tests/test.rem:1020)
../tests/test.rem(1023): Function `f' redefined: previously defined at ../tests/test.rem(1020)
../tests/test.rem(1023): Too many arguments
# Check that SATISFY expressions that don't reference trigdate are diagnosed
@@ -5632,8 +5632,8 @@ REM SATISFY ""
REM SATISFY [version() > "01.00.00"]
../tests/test.rem(1050): SATISFY: expression has no reference to trigdate() or $T...
../tests/test.rem(1050): Trig = Saturday, 16 February, 1991
version() => "05.03.00"
"05.03.00" > "01.00.00" => 1
version() => "05.03.05"
"05.03.05" > "01.00.00" => 1
../tests/test.rem(1050): Trig(satisfied) = Saturday, 16 February, 1991
REM SATISFY [max(x, max(x, 1, 2, 3), 4, 5, 6) * 5]
../tests/test.rem(1051): SATISFY: expression has no reference to trigdate() or $T...
@@ -5647,63 +5647,63 @@ max(3, 3, 4, 5, 6) => 6
FSET gg(x) 0
REM WARN gg MSG Wookie
../tests/test.rem(1054): WARN function `gg' defined at ../tests/test.rem:1053 does not use its argument
../tests/test.rem(1054): WARN function `gg' defined at ../tests/test.rem(1053) does not use its argument
../tests/test.rem(1054): Trig = Saturday, 16 February, 1991
Entering UserFN gg(1)
Leaving UserFN gg(1) => 0
Wookie
REM AT 11:00 SCHED gg MSG blork
../tests/test.rem(1055): SCHED function `gg' defined at ../tests/test.rem:1053 does not use its argument
../tests/test.rem(1055): SCHED function `gg' defined at ../tests/test.rem(1053) does not use its argument
../tests/test.rem(1055): Trig = Saturday, 16 February, 1991 AT 11:00
blork
REM OMITFUNC gg MSG hehe
../tests/test.rem(1056): OMITFUNC function `gg' defined at ../tests/test.rem:1053 does not use its argument
../tests/test.rem(1056): OMITFUNC function `gg' defined at ../tests/test.rem(1053) does not use its argument
../tests/test.rem(1056): Trig = Saturday, 16 February, 1991
hehe
FSET gg(x,y,z) 0
../tests/test.rem(1058): Function `gg' redefined (previously defined at ../tests/test.rem:1053)
../tests/test.rem(1058): Function `gg' redefined: previously defined at ../tests/test.rem(1053)
REM WARN gg MSG Wookie
../tests/test.rem(1059): WARN function `gg' defined at ../tests/test.rem:1058 should take 1 argument but actually takes 3
../tests/test.rem(1059): WARN function `gg' defined at ../tests/test.rem(1058) should take 1 argument but actually takes 3
../tests/test.rem(1059): Trig = Saturday, 16 February, 1991
../tests/test.rem(1059): Undefined WARN function: `gg'
Wookie
REM AT 11:00 SCHED gg MSG blork
../tests/test.rem(1060): SCHED function `gg' defined at ../tests/test.rem:1058 should take 1 argument but actually takes 3
../tests/test.rem(1060): SCHED function `gg' defined at ../tests/test.rem(1058) should take 1 argument but actually takes 3
../tests/test.rem(1060): Trig = Saturday, 16 February, 1991 AT 11:00
blork
REM OMITFUNC gg MSG hehe
../tests/test.rem(1061): OMITFUNC function `gg' defined at ../tests/test.rem:1058 should take 1 argument but actually takes 3
../tests/test.rem(1061): OMITFUNC function `gg' defined at ../tests/test.rem(1058) should take 1 argument but actually takes 3
../tests/test.rem(1061): Trig = Saturday, 16 February, 1991
hehe
FSET gg() 0
../tests/test.rem(1063): Function `gg' redefined (previously defined at ../tests/test.rem:1058)
../tests/test.rem(1063): Function `gg' redefined: previously defined at ../tests/test.rem(1058)
REM WARN gg MSG Wookie
../tests/test.rem(1064): WARN function `gg' defined at ../tests/test.rem:1063 should take 1 argument but actually takes 0
../tests/test.rem(1064): WARN function `gg' defined at ../tests/test.rem(1063) should take 1 argument but actually takes 0
../tests/test.rem(1064): Trig = Saturday, 16 February, 1991
../tests/test.rem(1064): Undefined WARN function: `gg'
Wookie
REM AT 11:00 SCHED gg MSG blork
../tests/test.rem(1065): SCHED function `gg' defined at ../tests/test.rem:1063 should take 1 argument but actually takes 0
../tests/test.rem(1065): SCHED function `gg' defined at ../tests/test.rem(1063) should take 1 argument but actually takes 0
../tests/test.rem(1065): Trig = Saturday, 16 February, 1991 AT 11:00
blork
REM OMITFUNC gg MSG hehe
../tests/test.rem(1066): OMITFUNC function `gg' defined at ../tests/test.rem:1063 should take 1 argument but actually takes 0
../tests/test.rem(1066): OMITFUNC function `gg' defined at ../tests/test.rem(1063) should take 1 argument but actually takes 0
../tests/test.rem(1066): Trig = Saturday, 16 February, 1991
hehe
FSET gg(x) x-x
../tests/test.rem(1068): Function `gg' redefined (previously defined at ../tests/test.rem:1063)
../tests/test.rem(1068): Function `gg' redefined: previously defined at ../tests/test.rem(1063)
REM WARN gg MSG Wookie
../tests/test.rem(1069): Trig = Saturday, 16 February, 1991
Entering UserFN gg(1)
@@ -5833,10 +5833,10 @@ max()
fset dooby(x) 1
set zxk dooby()
dooby(...) => Not enough arguments
dooby() => Not enough arguments
../tests/test.rem(1123): dooby(): Not enough arguments
set zxk dooby(1, 2)
dooby(...) => Too many arguments
dooby(?, ?) => Too many arguments
../tests/test.rem(1124): dooby(): Too many arguments
set zxk dooby(1)
Entering UserFN dooby(1)
@@ -5973,7 +5973,7 @@ Hello
On the next line
FSET msgsuffix(x) char(8) + " on the same line"
../tests/test.rem(1184): Function `msgsuffix' redefined (previously defined at ../tests/test.rem:1181)
../tests/test.rem(1184): Function `msgsuffix' redefined: previously defined at ../tests/test.rem(1181)
REM MSG Hello
../tests/test.rem(1185): Trig = Saturday, 16 February, 1991
Entering UserFN msgsuffix(5000)
@@ -16271,7 +16271,7 @@ Translation 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
Growths: 0; Shrinks: 0
Expression nodes allocated: 300096
Expression nodes allocated: 300288
Expression nodes high-water: 300073
Expression nodes leaked: 0
Parse level high-water: 25
@@ -22332,6 +22332,7 @@ grestore
showpage
%%Trailer
%%Pages: 1
All astronomical functions look OK
Reminders for Sunday, 1st January, 2012:
1
@@ -22389,44 +22390,44 @@ February 29
{"date":"2012-01-23","filename":"-","lineno":1,"wd":["Monday"],"priority":5000,"omitfunc":"foo","nonconst_expr":1,"body":"bar"}
{"date":"2012-01-30","filename":"-","lineno":1,"wd":["Monday"],"priority":5000,"omitfunc":"foo","nonconst_expr":1,"body":"bar"}
# rem2ps2 end
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(7): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
-stdin-(8:9): Number too high
[
{
"translations":{"LANGID":"en"},"caltype":"monthly","monthname":"January","year":2012,"daysinmonth":31,"firstwkday":0,"mondayfirst":0,"daynames":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"prevmonthname":"December","daysinprevmonth":31,"prevmonthyear":2011,"nextmonthname":"February","daysinnextmonth":29,"nextmonthyear":2012,"entries":[
{"date":"2012-01-02","filename":"-","lineno":1,"d":2,"priority":5000,"body":"Normal"},
{"date":"2012-01-03","filename":"-","lineno":3,"passthru":"COLOR","d":3,"priority":5000,"r":255,"g":0,"b":0,"rawbody":"%\"Red%\" on the calendar!","calendar_body":"Red","plain_body":"Red on the calendar!","body":"255 0 0 %\"Red%\" on the calendar!"},
{"date":"2012-01-04","filename":"-","lineno":5,"d":4,"priority":5000,"body":"Normal"}
{"date":"2012-01-03","filename":"-","lineno":4,"lineno_start":3,"passthru":"COLOR","d":3,"priority":5000,"r":255,"g":0,"b":0,"rawbody":"%\"Red%\" on the calendar!","calendar_body":"Red","plain_body":"Red on the calendar!","body":"255 0 0 %\"Red%\" on the calendar!"},
{"date":"2012-01-04","filename":"-","lineno":6,"d":4,"priority":5000,"body":"Normal"}
]
}
]
@@ -23200,7 +23201,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
05.03.00
05.03.05
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
@@ -24123,6 +24124,10 @@ monnum
moondate
moondatetime
moonphase
moonrise
moonrisedir
moonset
moonsetdir
moontime
multitrig
ndawn
@@ -24164,6 +24169,7 @@ trigeventduration
trigeventstart
trigfrom
trigger
triginfo
trigpriority
trigrep
trigscanfrom
@@ -24490,11 +24496,11 @@ TRANSLATE "Expression evaluation is disabled" ""
TRANSLATE "Time limit for expression evaluation exceeded" ""
# Other Messages
TRANSLATE "%s function `%s' defined at %s:%d does not use its argument" ""
TRANSLATE "%s function `%s' defined at %s:%d should take 1 argument but actually takes %d" ""
TRANSLATE "%s function `%s' defined at %s(%s) does not use its argument" ""
TRANSLATE "%s function `%s' defined at %s(%s) should take 1 argument but actually takes %d" ""
TRANSLATE "%s is deprecated; use %s instead" ""
TRANSLATE "%s(%d): IF without ENDIF" ""
TRANSLATE "%s(%d): ["["]#%d] %s function `%s'" ""
TRANSLATE "%s(%s): ["["]#%d] %s function `%s'" ""
TRANSLATE "(Security note: $RunOff variable tested.)" ""
TRANSLATE "Accepting \"%s\" for $Latitude/$Longitude, but you should use the \"C\" locale decimal separator \".\" instead" ""
TRANSLATE "Caching directory `%s' listing" ""
@@ -24508,8 +24514,8 @@ TRANSLATE "Duplicate INFO headers are not permitted" ""
TRANSLATE "Error: THROUGH date earlier than start date" ""
TRANSLATE "Executing `%s' for INCLUDECMD and caching as `%s'" ""
TRANSLATE "Found cached directory listing for `%s'" ""
TRANSLATE "Function `%s' defined at %s:%d should take %d argument%s, but actually takes %d" ""
TRANSLATE "Function `%s' redefined (previously defined at %s:%d)" ""
TRANSLATE "Function `%s' defined at %s(%s) should take %d argument%s, but actually takes %d" ""
TRANSLATE "Function `%s' redefined: previously defined at %s(%s)" ""
TRANSLATE "GetValidHebDate: Bad adarbehave value %d" ""
TRANSLATE "In" ""
TRANSLATE "Invalid INFO string: Must be of the form \"Header: Value\"" ""
@@ -24541,11 +24547,13 @@ TRANSLATE "Warning: UNTIL/THROUGH date earlier than SCANFROM date" ""
TRANSLATE "Warning: UNTIL/THROUGH date earlier than start date" ""
TRANSLATE "Warning: Unable to save ONCE timestamp to %s: %s" ""
TRANSLATE "Warning: Unterminated %%(...) substitution sequence" ""
TRANSLATE "Warning: Unterminated %%<...> substitution sequence" ""
TRANSLATE "Warning: Unterminated %%{...} substitution sequence" ""
TRANSLATE "Warning: Useless use of UNTIL with fully-specified date and no *rep" ""
TRANSLATE "Warning: Variable name `%.*s...' truncated to `%.*s'" ""
TRANSLATE "You have OMITted everything! The space-time continuum is at risk." ""
TRANSLATE "\\x00 is not a valid escape sequence" ""
TRANSLATE "`%%%c' substitution sequence should not be used without an AT clause" ""
TRANSLATE "did you mean" ""
TRANSLATE "here" ""
TRANSLATE "psmoon() is deprecated; use SPECIAL MOON instead." ""
@@ -24659,10 +24667,10 @@ February 2024 29 4 0
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
January 31
March 31
{"date":"2024-02-07","filename":"-","lineno":1,"info":{"location":"here","summary":"Nope"},"wd":["Wednesday"],"priority":5000,"body":"Meeting"}
{"date":"2024-02-14","filename":"-","lineno":1,"info":{"location":"here","summary":"Nope"},"wd":["Wednesday"],"priority":5000,"body":"Meeting"}
{"date":"2024-02-21","filename":"-","lineno":1,"info":{"location":"here","summary":"Nope"},"wd":["Wednesday"],"priority":5000,"body":"Meeting"}
{"date":"2024-02-28","filename":"-","lineno":1,"info":{"location":"here","summary":"Nope"},"wd":["Wednesday"],"priority":5000,"body":"Meeting"}
{"date":"2024-02-07","filename":"-","lineno":1,"info":{"location":"here","summary":"Nope"},"wd":["Wednesday"],"priority":5000,"rawbody":"Meeting [triginfo(\"location\")] %<summary> %<nonexist> [triginfo(\"cabbage\")]","body":"Meeting here Nope "}
{"date":"2024-02-14","filename":"-","lineno":1,"info":{"location":"here","summary":"Nope"},"wd":["Wednesday"],"priority":5000,"rawbody":"Meeting [triginfo(\"location\")] %<summary> %<nonexist> [triginfo(\"cabbage\")]","body":"Meeting here Nope "}
{"date":"2024-02-21","filename":"-","lineno":1,"info":{"location":"here","summary":"Nope"},"wd":["Wednesday"],"priority":5000,"rawbody":"Meeting [triginfo(\"location\")] %<summary> %<nonexist> [triginfo(\"cabbage\")]","body":"Meeting here Nope "}
{"date":"2024-02-28","filename":"-","lineno":1,"info":{"location":"here","summary":"Nope"},"wd":["Wednesday"],"priority":5000,"rawbody":"Meeting [triginfo(\"location\")] %<summary> %<nonexist> [triginfo(\"cabbage\")]","body":"Meeting here Nope "}
# rem2ps2 end
-stdin-(1): Invalid INFO string: Must be of the form "Header: Value"
-stdin-(2): Invalid INFO string: Must be of the form "Header: Value"
@@ -24689,6 +24697,21 @@ a "xPOO"
-stdin-(24): \x00 is not a valid escape sequence
-stdin-(25): \x00 is not a valid escape sequence
-stdin-(26): \x00 is not a valid escape sequence
-stdin-(1): `%0' substitution sequence should not be used without an AT clause
-stdin-(1): `%1' substitution sequence should not be used without an AT clause
-stdin-(1): `%2' substitution sequence should not be used without an AT clause
-stdin-(1): `%3' substitution sequence should not be used without an AT clause
-stdin-(1): `%4' substitution sequence should not be used without an AT clause
-stdin-(1): `%5' substitution sequence should not be used without an AT clause
-stdin-(1): `%6' substitution sequence should not be used without an AT clause
-stdin-(1): `%7' substitution sequence should not be used without an AT clause
-stdin-(1): `%8' substitution sequence should not be used without an AT clause
-stdin-(1): `%9' substitution sequence should not be used without an AT clause
-stdin-(1): `%!' substitution sequence should not be used without an AT clause
Reminders for Thursday, 1st February, 2024:
s now at 1:00am at 01:00 0 0 from now 0 0 s is hahaha
# Translation table
TRANSLATE "LANGID" "en"
TRANSLATE "\x03" "BREAK"
@@ -25115,7 +25138,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 horas i 34 minuts fa" and %*1 yields: "13 horas i 34 minuts fa"
%2 yields: "a les 0:00am" and %*2 yields: "0:00am"
%2 yields: "a les 12:00am" and %*2 yields: "12:00am"
%3 yields: "a les 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -26017,7 +26040,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 timer og 34 minutter siden" and %*1 yields: "13 timer og 34 minutter siden"
%2 yields: "kl. 0:00 om natten" and %*2 yields: "0:00 om natten"
%2 yields: "kl. 12:00 om natten" and %*2 yields: "12:00 om natten"
%3 yields: "kl. 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -26919,7 +26942,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 Stunden und 34 Minuten vorher" and %*1 yields: "13 Stunden und 34 Minuten vorher"
%2 yields: "um 0:00 nachts" and %*2 yields: "0:00 nachts"
%2 yields: "um 12:00 nachts" and %*2 yields: "12:00 nachts"
%3 yields: "um 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -27821,7 +27844,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 hours and 34 minutes ago" and %*1 yields: "13 hours and 34 minutes ago"
%2 yields: "at 0:00am" and %*2 yields: "0:00am"
%2 yields: "at 12:00am" and %*2 yields: "12:00am"
%3 yields: "at 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -28723,7 +28746,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 horas y 34 minutos hace" and %*1 yields: "13 horas y 34 minutos hace"
%2 yields: "a las 0:00am" and %*2 yields: "0:00am"
%2 yields: "a las 12:00am" and %*2 yields: "12:00am"
%3 yields: "a las 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -29625,7 +29648,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 tuntia 34 minuuttia sitten" and %*1 yields: "13 tuntia 34 minuuttia sitten"
%2 yields: "klo 0:00 ap." and %*2 yields: "0:00 ap."
%2 yields: "klo 12:00 ap." and %*2 yields: "12:00 ap."
%3 yields: "klo 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -30527,7 +30550,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "il y a 13 heures et 34 minutes" and %*1 yields: "il y a 13 heures et 34 minutes"
%2 yields: "à 0:00am" and %*2 yields: "0:00am"
%2 yields: "à 12:00am" and %*2 yields: "12:00am"
%3 yields: "à 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -31429,7 +31452,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 ώρες και 34 λεπτά πριν" and %*1 yields: "13 ώρες και 34 λεπτά πριν"
%2 yields: "στις 0:00πμ" and %*2 yields: "0:00πμ"
%2 yields: "στις 12:00πμ" and %*2 yields: "12:00πμ"
%3 yields: "στις 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -32331,7 +32354,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 klukkustundir og 34 mínútur síðan" and %*1 yields: "13 klukkustundir og 34 mínútur síðan"
%2 yields: "kl. 0:00fh" and %*2 yields: "0:00fh"
%2 yields: "kl. 12:00fh" and %*2 yields: "12:00fh"
%3 yields: "kl. 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -33233,7 +33256,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 ore e 34 minuti fa" and %*1 yields: "13 ore e 34 minuti fa"
%2 yields: "alle 0:00am" and %*2 yields: "0:00am"
%2 yields: "alle 12:00am" and %*2 yields: "12:00am"
%3 yields: "alle 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -34135,7 +34158,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 uren en 34 minuten geleden" and %*1 yields: "13 uren en 34 minuten geleden"
%2 yields: "op 0:00am" and %*2 yields: "0:00am"
%2 yields: "op 12:00am" and %*2 yields: "12:00am"
%3 yields: "op 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -35037,7 +35060,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 timer og 34 minutter siden" and %*1 yields: "13 timer og 34 minutter siden"
%2 yields: "kl. 0:00am" and %*2 yields: "0:00am"
%2 yields: "kl. 12:00am" and %*2 yields: "12:00am"
%3 yields: "kl. 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -35939,7 +35962,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 godzin i 34 minuty temu" and %*1 yields: "13 godzin i 34 minuty temu"
%2 yields: "o 0:00 w nocy" and %*2 yields: "0:00 w nocy"
%2 yields: "o 12:00 w nocy" and %*2 yields: "12:00 w nocy"
%3 yields: "o 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -36841,7 +36864,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "13 horas e 34 minutos atrás" and %*1 yields: "13 horas e 34 minutos atrás"
%2 yields: "as 0:00am" and %*2 yields: "0:00am"
%2 yields: "as 12:00am" and %*2 yields: "12:00am"
%3 yields: "as 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"
@@ -37743,7 +37766,7 @@ Time substitutions for 13:32 where now() = 13:34
Time substitutions for 00:00 where now() = 13:34
%1 yields: "acum 13 ore şi 34 minute" and %*1 yields: "acum 13 ore şi 34 minute"
%2 yields: "la ora 0:00 noaptea" and %*2 yields: "0:00 noaptea"
%2 yields: "la ora 12:00 noaptea" and %*2 yields: "12:00 noaptea"
%3 yields: "la ora 00:00" and %*3 yields: "00:00"
%4 yields: "-814" and %*4 yields: "-814"
%5 yields: "814" and %*5 yields: "814"

View File

@@ -1,6 +0,0 @@
#!/bin/sh
echo "Unconfiguring Remind..."
echo rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile rem2html/Makefile
rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile rem2html/Makefile
exit 0