mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-16 06:18:47 +02:00
Compare commits
100 Commits
05.02.03-B
...
05.03.05-B
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abb8cbb1bf | ||
|
|
ee4e3e9073 | ||
|
|
220014e60f | ||
|
|
3d0d07ce29 | ||
|
|
38615adb41 | ||
|
|
3d8f0e3907 | ||
|
|
160f85a1f8 | ||
|
|
5cb062166c | ||
|
|
81fa6c667f | ||
|
|
190dfa3a8f | ||
|
|
a22c674846 | ||
|
|
ba224445b1 | ||
|
|
6aeee47bfa | ||
|
|
c506fa4613 | ||
|
|
04404a252e | ||
|
|
be746f9fa7 | ||
|
|
2393a86970 | ||
|
|
143ad08b3f | ||
|
|
44afdfcb44 | ||
|
|
4b905dbc02 | ||
|
|
0f76750e05 | ||
|
|
b32f56134e | ||
|
|
60b0b468df | ||
|
|
52ce99af80 | ||
|
|
5915eb4973 | ||
|
|
aa8d23fd87 | ||
|
|
917d943953 | ||
|
|
9ade3876b2 | ||
|
|
471ecff267 | ||
|
|
762bf97473 | ||
|
|
563f3ea088 | ||
|
|
939078428f | ||
|
|
5acbb907b4 | ||
|
|
21ecc28ea4 | ||
|
|
b37a7cd993 | ||
|
|
64679817ae | ||
|
|
1ef1033379 | ||
|
|
7d42750043 | ||
|
|
1dc0afc0ca | ||
|
|
a0aede4069 | ||
|
|
a5a7637696 | ||
|
|
38a597a374 | ||
|
|
66ba9257a5 | ||
|
|
c5374c09fb | ||
|
|
9c93e7e6a1 | ||
|
|
3487f6f46a | ||
|
|
da8a72d7cd | ||
|
|
f391b6221f | ||
|
|
a8c0b20f9e | ||
|
|
5684a86df9 | ||
|
|
3abaaacd98 | ||
|
|
7eae7a9157 | ||
|
|
a0d8c93a34 | ||
|
|
8bf22dbb36 | ||
|
|
6b2622f3d3 | ||
|
|
8abdf6d988 | ||
|
|
991e409739 | ||
|
|
3c2bb76523 | ||
|
|
8555352c18 | ||
|
|
34f8486c10 | ||
|
|
5adb5d893e | ||
|
|
2f11b6fdc8 | ||
|
|
49d46c1397 | ||
|
|
1641f99f97 | ||
|
|
f9f9552850 | ||
|
|
3b43222585 | ||
|
|
231d9d77e7 | ||
|
|
6140221bf3 | ||
|
|
51b831fb6a | ||
|
|
35a4994b3e | ||
|
|
0ebaaa4097 | ||
|
|
2f43aca21c | ||
|
|
930bab0fde | ||
|
|
694c4099d1 | ||
|
|
ca56b4c90e | ||
|
|
5c965e2083 | ||
|
|
d58ccbef69 | ||
|
|
17ad03be69 | ||
|
|
75a4e98de2 | ||
|
|
1408f77303 | ||
|
|
af76dd67fb | ||
|
|
f7a19d1570 | ||
|
|
e7ec975ff0 | ||
|
|
8c4ca12ca7 | ||
|
|
e832eb868c | ||
|
|
cb0acb3077 | ||
|
|
9376c7a36d | ||
|
|
e6ceeee2ec | ||
|
|
bbeece644e | ||
|
|
8d09abc363 | ||
|
|
3dcd353fb5 | ||
|
|
124c5c4e7e | ||
|
|
77024562b3 | ||
|
|
35c33ae915 | ||
|
|
901831ff75 | ||
|
|
e0c5e878a8 | ||
|
|
ffba7fcb03 | ||
|
|
b3f3cb9ce0 | ||
|
|
6f11e727f8 | ||
|
|
9f7ea96e87 |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,2 +0,0 @@
|
||||
|
||||
liberapay: dskoll
|
||||
7
.github/README.md
vendored
7
.github/README.md
vendored
@@ -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
|
||||
29
.github/workflows/github-action.yml
vendored
29
.github/workflows/github-action.yml
vendored
@@ -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 .
|
||||
6
Makefile
6
Makefile
@@ -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,8 @@ 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/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
|
||||
|
||||
src/Makefile: src/Makefile.in
|
||||
./configure
|
||||
|
||||
12
README.md
12
README.md
@@ -6,11 +6,11 @@ the GNU General Public License, Vesion 2.
|
||||
|
||||
## Prerequisites:
|
||||
|
||||
`remind` and `rem2ps` have no prerequisites beyond the standard C library and
|
||||
remind and rem2ps have no prerequisites beyond the standard C library and
|
||||
the standard math library.
|
||||
|
||||
`rem2html` requires the `JSON::MaybeXS` Perl module and `rem2pdf`
|
||||
requires the `JSON::MaybeXS`, `Pango` and `Cairo` Perl modules.
|
||||
rem2html requires the JSON::MaybeXS Perl module and rem2pdf
|
||||
requires the JSON::MaybeXS, Pango and Cairo Perl modules.
|
||||
|
||||
- On Debian-like systems, these prerequisites may be installed with:
|
||||
|
||||
@@ -24,7 +24,7 @@ requires the `JSON::MaybeXS`, `Pango` and `Cairo` Perl modules.
|
||||
|
||||
- On Arch linux, you need `pango-perl`, `cairo-perl` and `perl-json-maybexs`
|
||||
|
||||
TkRemind requires Tcl/Tk and the `tcllib` library.
|
||||
TkRemind requires Tcl/Tk and the tcllib library.
|
||||
|
||||
- On Debian-like systems, install with:
|
||||
|
||||
@@ -49,9 +49,9 @@ Remind can be installed with the usual:
|
||||
|
||||
`./configure && make && make test && sudo make install`
|
||||
|
||||
You can edit `custom.h` to configure some aspects of Remind. Or, if
|
||||
You can edit custom.h to configure some aspects of Remind. Or, if
|
||||
you have Tcl/Tk installed, you can use the graphical build tool to
|
||||
edit `custom.h` on your behalf:
|
||||
edit custom.h on your behalf:
|
||||
|
||||
`wish ./build.tk`
|
||||
|
||||
|
||||
18
configure
vendored
18
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.71 for remind 05.02.03.
|
||||
# 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.02.03'
|
||||
PACKAGE_STRING='remind 05.02.03'
|
||||
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.02.03 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.02.03:";;
|
||||
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.02.03
|
||||
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.02.03, 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.02.03, 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.02.03
|
||||
remind config.status 05.03.05
|
||||
configured by $0, generated by GNU Autoconf 2.71,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT(remind, 05.02.03, , , 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'
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
(list "ADDOMIT" "AFTER" "AT" "BAN" "BANNER" "BEFORE" "CAL" "CLEAR"
|
||||
"CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMP" "DUMPVARS" "DURATION" "ELSE"
|
||||
"ENDIF" "ERRMSG" "EXIT" "EXPR" "FIRST" "FLUSH" "FOURTH" "FRENAME" "FROM" "FSET"
|
||||
"FUNSET" "IF" "IFTRIG" "IN" "INC" "INCLUDE" "INCLUDECMD" "LAST"
|
||||
"FUNSET" "IF" "IFTRIG" "IN" "INC" "INCLUDE" "INCLUDECMD" "INFO" "LAST"
|
||||
"LASTDAY" "LASTWORKDAY" "MAYBE" "MAYBE-UNCOMPUTABLE" "MSF" "MSG"
|
||||
"NOQUEUE" "OMIT" "OMITFUNC" "ONCE" "POP" "POP-OMIT-CONTEXT" "PRESERVE"
|
||||
"PRIORITY" "PS" "PSFILE" "PUSH" "PUSH-OMIT-CONTEXT" "REM" "RUN"
|
||||
@@ -166,7 +166,7 @@
|
||||
(list "_" "abs" "access" "adawn" "adusk" "ampm" "ansicolor" "args" "asc"
|
||||
"baseyr" "char" "choose" "coerce" "columns" "current" "date"
|
||||
"datepart" "datetime" "dawn" "day" "daysinmon" "defined" "dosubst"
|
||||
"dusk" "easterdate" "evaltrig" "filedate" "filedatetime" "filedir"
|
||||
"dusk" "easterdate" "escape" "evaltrig" "filedate" "filedatetime" "filedir"
|
||||
"filename" "getenv" "hebdate" "hebday" "hebmon" "hebyear" "hour"
|
||||
"htmlescape" "htmlstriptags" "iif" "index" "isany" "isdst" "isleap"
|
||||
"isomitted" "language" "localtoutc" "lower" "max" "min" "minsfromutc"
|
||||
@@ -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")
|
||||
|
||||
101
docs/WHATSNEW
101
docs/WHATSNEW
@@ -1,6 +1,100 @@
|
||||
CHANGES TO REMIND
|
||||
|
||||
* VERSION 5.2 Patch 3 - 2025-??-??
|
||||
* VERSION 5.3 Patch 5 - 2025-03-??
|
||||
|
||||
- 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.
|
||||
|
||||
- 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 subsitution 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.
|
||||
|
||||
- NEW FUNCTION: remind: Add the escape() built-in function that converts
|
||||
problematic characters within a string to the \-escaped versions.
|
||||
It's essentially the inverse of how Remind parses a quoted string.
|
||||
|
||||
* VERSION 5.2 Patch 3 - 2025-01-22
|
||||
|
||||
- NEW FEATURE: remind: Add "TRANSLATE GENERATE" command for generating
|
||||
a skeleton set of TRANSLATE commands to make it easier to localize
|
||||
@@ -20,7 +114,10 @@ CHANGES TO REMIND
|
||||
unknown debug flag.
|
||||
|
||||
- BUG FIX: remind: "make test" will now succeed even if run between
|
||||
23:55 and 00:00 UTC.
|
||||
23:55 and 00:00 UTC. This is done with a new --test flag for remind.
|
||||
|
||||
- BUG FIX: remind: Avoid potential buffer overflow if someone supplies
|
||||
ridiculously-long translations for "am" or "pm".
|
||||
|
||||
* VERSION 5.2 Patch 2 - 2025-01-06
|
||||
|
||||
|
||||
@@ -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 %
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
9
include/holidays/misc.rem
Normal file
9
include/holidays/misc.rem
Normal 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
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -516,6 +523,29 @@ MOON, etc.)
|
||||
If any TAG clauses are present, the \fBtags\fR key will be present and consist
|
||||
of a comma-separated list of tags.
|
||||
.TP
|
||||
.B info \fR{ \fIhash\fR }
|
||||
If any INFO clauses are present, the \fBinfo\fR key will be present. Its
|
||||
value will be a hash of info key-value pairs. Each key is the header
|
||||
from an INFO string, \fIconverted to all lower-case\fR. The value is the
|
||||
value from the INFO string.
|
||||
.RS
|
||||
.PP
|
||||
For example, the following REM command:
|
||||
.PP
|
||||
.nf
|
||||
REM INFO "Location: Boardroom" INFO "Summary: None" MSG whatever
|
||||
.fi
|
||||
.PP
|
||||
will produce the following \fBinfo\fR hash:
|
||||
.PP
|
||||
.nf
|
||||
"info" : {
|
||||
"location" : "Boardroom",
|
||||
"summary" : "None"
|
||||
},
|
||||
.fi
|
||||
.RE
|
||||
.TP
|
||||
.B time \fIt\fR
|
||||
If an AT clause was present, this key will contain the time of the AT clause
|
||||
in minutes after midnight.
|
||||
|
||||
253
man/remind.1.in
253
man/remind.1.in
@@ -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
|
||||
@@ -530,11 +534,16 @@ resources. Note that the limit \fIn\fR is approximate and
|
||||
\fBRemind\fR might execute for one or two more seconds before it is
|
||||
killed. If \fIn\fR is specified as zero, then no limit is applied, just
|
||||
as if the option had not been used at all.
|
||||
.RS
|
||||
.PP
|
||||
If a limit is applied, it applies only to the foreground run of \fBRemind\fR.
|
||||
If \fBRemind\fR finishes processing the script and then starts handling
|
||||
queued reminders, the time limit is reset to no limit.
|
||||
.PP
|
||||
.RE
|
||||
.TP
|
||||
.B \-\-test
|
||||
The \fB\-\-test\fR long option is only for use by the acceptance tests
|
||||
run by "make test". Do not use this option in production.
|
||||
.SH REMINDER FILES
|
||||
.PP
|
||||
\fBRemind\fR uses scripts to control its operation. You can use any
|
||||
@@ -601,8 +610,9 @@ Its syntax is:
|
||||
[\fBSCANFROM\fR \fIscan_date\fR | \fBFROM\fR \fIstart_date\fR]
|
||||
[\fBDURATION\fR \fIduration\fR]
|
||||
[\fBTAG\fR \fItag\fR]
|
||||
<\fBMSG\fR | \fBMSF\fR | \fBRUN\fR | \fBCAL\fR | \fBSATISFY\fR |
|
||||
\fBSPECIAL\fR \fIspecial\fR | \fBPS\fR | \fBPSFILE\fR>
|
||||
[\fBINFO\fR "\fIinfo_string\fR"]
|
||||
\fBMSG\fR | \fBMSF\fR | \fBRUN\fR | \fBCAL\fR | \fBSATISFY\fR |
|
||||
\fBSPECIAL\fR \fIspecial\fR | \fBPS\fR | \fBPSFILE\fR
|
||||
.I body
|
||||
.RE
|
||||
.PP
|
||||
@@ -1338,7 +1348,7 @@ However, discussion must be deferred until after
|
||||
expressions and user-defined functions are explained. See the subsection
|
||||
"PRECISE SCHEDULING" further on.
|
||||
.PP
|
||||
.B TAG AND DURATION
|
||||
.B TAG, INFO AND DURATION
|
||||
.PP
|
||||
The \fBTAG\fR keyword lets you "tag" certain reminders. This facility
|
||||
is used by certain back-ends or systems built around \fBRemind\fR,
|
||||
@@ -1357,15 +1367,40 @@ by the hexadecimal representation of the MD5 sum of the REM
|
||||
command line. This lets you give a more-or-less unique identifier
|
||||
to each distinct REM command.
|
||||
.PP
|
||||
The \fBINFO\fR keyword is similar to \fBTAG\fR but is intended to convey
|
||||
metadata about an event, such as its location. Back-ends will have their
|
||||
own rules about which \fIinfo_string\fRs they recognize, and must ignore
|
||||
\fIinfo_string\fRs they don't recognize. Note that \fBINFO\fR must
|
||||
be followed by a quoted string; you can include newlines in the string
|
||||
by supplying them as "\\n".
|
||||
.PP
|
||||
An INFO string \fImust\fR be of the form "Header: Value". The header
|
||||
can consist of any printable character, but cannot contain whitespace.
|
||||
The value can consist of any characters you like. Space may not
|
||||
appear before the colon, but can appear afterwards; such space is not
|
||||
considered to be part of the value. If there is more than one INFO
|
||||
string for a given reminder, there cannot be any duplicate headers.
|
||||
Case is ignored when determining if a header is a duplicate of an
|
||||
existing one.
|
||||
.PP
|
||||
For example, a hypothetical back-end might let you set the location
|
||||
and description of a reminder like this:
|
||||
.PP
|
||||
.nf
|
||||
REM 26 Feb 2025 INFO "Location: Boardroom #2" \\
|
||||
INFO "Description: Go over latest pull requests" \\
|
||||
MSG Engineering meeting
|
||||
.fi
|
||||
.PP
|
||||
The \fBDURATION\fR keyword makes sense only for timed reminders; it
|
||||
specifies the duration of an event. For example, if you have a
|
||||
90-minute meeting starting at 1:00pm, you could use any of the following:
|
||||
.PP
|
||||
.nf
|
||||
REM 5 March 2021 AT 13:00 DURATION 1:30 MSG Meeting
|
||||
REM 5 March 2021 AT 13:00 DURATION 90 MSG Meeting
|
||||
REM 5 March 2021 AT 1:00pm DURATION 1:30 MSG Meeting
|
||||
REM 5 March 2021 AT 1:00pm DURATION 90 MSG Meeting
|
||||
REM 5 March 2021 AT 13:00 DURATION 1:30 MSG Meeting
|
||||
REM 5 March 2021 AT 13:00 DURATION 90 MSG Meeting
|
||||
REM 5 March 2021 AT 1:00pm DURATION 1:30 MSG Meeting
|
||||
REM 5 March 2021 AT 1:00pm DURATION 90 MSG Meeting
|
||||
.fi
|
||||
.PP
|
||||
For long-duration reminders, it is convenient to use expressions
|
||||
@@ -1395,26 +1430,26 @@ The REM command has syntactic sugar to let you express common
|
||||
reminders. The following pairs of reminders are equivalent:
|
||||
.PP
|
||||
.nf
|
||||
REM First Monday April MSG Foo
|
||||
REM Mon 1 April MSG Foo
|
||||
REM First Monday April MSG Foo
|
||||
REM Mon 1 April MSG Foo
|
||||
|
||||
REM Second Monday May MSG Bar
|
||||
REM Mon 8 May MSG Bar
|
||||
REM Second Monday May MSG Bar
|
||||
REM Mon 8 May MSG Bar
|
||||
|
||||
REM Third Monday MSG Third Monday of every month
|
||||
REM Mon 15 MSG Third Monday of every month
|
||||
REM Third Monday MSG Third Monday of every month
|
||||
REM Mon 15 MSG Third Monday of every month
|
||||
|
||||
REM Fourth Sunday June 2025 MSG Fourth Sunday in June 2025
|
||||
REM Sun 22 June 2025 MSG Fourth Sunday in June 2025
|
||||
REM Fourth Sunday June 2025 MSG Fourth Sunday in June 2025
|
||||
REM Sun 22 June 2025 MSG Fourth Sunday in June 2025
|
||||
|
||||
REM Last Monday MSG Last Monday of every month
|
||||
REM Mon 1 --7 MSG Last Monday of every month
|
||||
REM Last Monday MSG Last Monday of every month
|
||||
REM Mon 1 --7 MSG Last Monday of every month
|
||||
|
||||
REM Last Monday April MSG Last Monday of every April
|
||||
REM Mon 1 May --7 MSG Last Monday of every April
|
||||
REM Last Monday April MSG Last Monday of every April
|
||||
REM Mon 1 May --7 MSG Last Monday of every April
|
||||
|
||||
REM Last Monday December 2025 MSG Last Monday of Dec 2025
|
||||
REM Monday 1 Jan 2026 --7 MSG Last Monday of Dec 2025
|
||||
REM Last Monday December 2025 MSG Last Monday of Dec 2025
|
||||
REM Monday 1 Jan 2026 --7 MSG Last Monday of Dec 2025
|
||||
.fi
|
||||
.PP
|
||||
Note that \fBLast\fR effectively adjusts the month and year, if necessary, to
|
||||
@@ -1423,35 +1458,35 @@ make the reminder trigger on the correct date.
|
||||
The keyword \fBIN\fR is completely ignored, so you can write (for example):
|
||||
.PP
|
||||
.nf
|
||||
REM Second Monday in May MSG foo
|
||||
REM Last Monday in December 2025 MSG Bar
|
||||
REM Second Monday in May MSG foo
|
||||
REM Last Monday in December 2025 MSG Bar
|
||||
.fi
|
||||
.PP
|
||||
An alternate form of \fIback\fR makes writing reminders easier.
|
||||
The following groups of reminders are equivalent:
|
||||
.PP
|
||||
.nf
|
||||
REM ~~1 MSG Last day of every month
|
||||
REM Lastday MSG Last day of every month
|
||||
REM 1 --1 MSG Last day of every month
|
||||
REM ~~1 MSG Last day of every month
|
||||
REM Lastday MSG Last day of every month
|
||||
REM 1 --1 MSG Last day of every month
|
||||
|
||||
REM May ~~1 MSG Last day of May
|
||||
REM Lastday May MSG Last day of May
|
||||
REM 1 June --1 MSG Last day of May
|
||||
REM May ~~1 MSG Last day of May
|
||||
REM Lastday May MSG Last day of May
|
||||
REM 1 June --1 MSG Last day of May
|
||||
|
||||
REM Dec 2025 ~~1 MSG Last day of December 2025
|
||||
REM Lastday Dec 2025 MSG Last day of December 2025
|
||||
REM 1 Jan 2026 --1 MSG Last day of December 2025
|
||||
REM Dec 2025 ~~1 MSG Last day of December 2025
|
||||
REM Lastday Dec 2025 MSG Last day of December 2025
|
||||
REM 1 Jan 2026 --1 MSG Last day of December 2025
|
||||
|
||||
REM Apr ~1 OMIT SAT SUN MSG Last workday of April
|
||||
REM Lastworkday April OMIT SAT SUN MSG Last workday of April
|
||||
REM 1 May -1 OMIT SAT SUN MSG Last workday of April
|
||||
REM Apr ~1 OMIT SAT SUN MSG Last workday of April
|
||||
REM Lastworkday April OMIT SAT SUN MSG Last workday of April
|
||||
REM 1 May -1 OMIT SAT SUN MSG Last workday of April
|
||||
|
||||
REM Apr ~~7 MSG Seventh-last day of April
|
||||
REM 1 May --7 MSG Seventh-last day of April
|
||||
REM Apr ~~7 MSG Seventh-last day of April
|
||||
REM 1 May --7 MSG Seventh-last day of April
|
||||
|
||||
REM Apr ~2 OMIT SAT SUN MSG Second-last workday of April
|
||||
REM 1 May -2 OMIT SAT SUN MSG Second-last workday of April
|
||||
REM Apr ~2 OMIT SAT SUN MSG Second-last workday of April
|
||||
REM 1 May -2 OMIT SAT SUN MSG Second-last workday of April
|
||||
.fi
|
||||
.PP
|
||||
As we see, "Lastday" is equivalent to ~~1 and "Lastworkday" to ~1.
|
||||
@@ -1462,9 +1497,9 @@ be combined with a day. Additionally, First/Second/Third/Fourth/Last
|
||||
must have at least one weekday name. The following are illegal:
|
||||
.PP
|
||||
.nf
|
||||
REM First Monday 3 June MSG Huh?
|
||||
REM April 3 ~~1 MSG What?
|
||||
REM Second June MSG Where's the weekday???
|
||||
REM First Monday 3 June MSG Huh?
|
||||
REM April 3 ~~1 MSG What?
|
||||
REM Second June MSG Where's the weekday???
|
||||
.fi
|
||||
.PP
|
||||
.SH THE SUBSTITUTION FILTER
|
||||
@@ -1630,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
|
||||
@@ -2223,6 +2263,10 @@ The following examples illustrate constants in \fBRemind\fR expressions:
|
||||
Note that the empty string is represented by "". Remind supports
|
||||
the escape sequences "\\a", "\\b", "\\f", "\\n", "\\r", "\\t"
|
||||
and "\\v" which have the same meanings as their counterparts in C.
|
||||
It also supports "\\xAB" where A and B are hexadecimal digits;
|
||||
this operates just as in C. The "\\x" must be followed by one or
|
||||
two hex digits; the escape sequence "\\x00" is not permitted.
|
||||
.PP
|
||||
To include a quote in a string, use "\\"". Any other character
|
||||
preceded by a backslash is inserted into the string as-is, but the
|
||||
backslash itself is removed. To include a backslash in a string,
|
||||
@@ -3391,6 +3435,25 @@ Note that \fBeasterdate\fR computes the Western Easter. For the Orthodox
|
||||
Easter date, see \fBorthodoxeaster\fR.
|
||||
.RE
|
||||
.TP
|
||||
.B escape(s_string [,i_add_quotes])
|
||||
Returns a \fBSTRING\fR that is the same as the input string, but with
|
||||
all special characters backslashed-escaped. For example, the following
|
||||
command:
|
||||
.RS
|
||||
.PP
|
||||
.nf
|
||||
set a escape("foo" + char(10) + "bar")
|
||||
.fi
|
||||
.PP
|
||||
will set a to "foo\\nbar" where "\\n" is the literal sequence "\\" followed
|
||||
by "n". This is useful if you want to compute a string in a pasted-in
|
||||
expression that \fBRemind\fR will then parse as a quoted string again,
|
||||
such as in a TRANSLATE command or an INFO clause.
|
||||
.PP
|
||||
If the optional \fIadd_quotes\fR argument is supplied and is non-zero, then
|
||||
the return value from \fBescape\fR will include surrounding double-quotes.
|
||||
.RE
|
||||
.TP
|
||||
.B evaltrig(s_trigger [,dq_start])
|
||||
Evaluates \fItrigger\fR as if it were a REM or IFTRIG trigger specification
|
||||
and returns the trigger date as a \fBDATE\fR (or as a \fBDATETIME\fR if
|
||||
@@ -3648,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.
|
||||
@@ -3685,18 +3785,18 @@ In general, \fBmultitrig\fR works better with the Remind algorithm than
|
||||
reminder is issued at the end of each quarter:
|
||||
.PP
|
||||
.nf
|
||||
REM [multitrig("Mar 31", "Jun 30", "Sep 30", "Dec 31")] +7 MSG \\
|
||||
%"End of [ord($Tm/3)] quarter%" is %b.
|
||||
REM [multitrig("Mar 31", "Jun 30", "Sep 30", "Dec 31")] +7 MSG \\
|
||||
%"End of [ord($Tm/3)] quarter%" is %b.
|
||||
.fi
|
||||
.PP
|
||||
If you want the last working day of each quarter, you could use:
|
||||
.PP
|
||||
.nf
|
||||
PUSH-OMIT-CONTEXT
|
||||
OMIT Sat Sun
|
||||
REM [multitrig("Mar ~1", "Jun ~1", "Sep ~1", "Dec ~1")] +7 MSG \\
|
||||
%"Last working day of [ord($Tm/3)] quarter%" is %b.
|
||||
POP-OMIT-CONTEXT
|
||||
PUSH-OMIT-CONTEXT
|
||||
OMIT Sat Sun
|
||||
REM [multitrig("Mar ~1", "Jun ~1", "Sep ~1", "Dec ~1")] +7 MSG \\
|
||||
%"Last working day of [ord($Tm/3)] quarter%" is %b.
|
||||
POP-OMIT-CONTEXT
|
||||
.fi
|
||||
.PP
|
||||
Note that unlike \fBevaltrig\fR, \fBmultitrig\fR always returns a \fBDATE\fR
|
||||
@@ -3724,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
|
||||
@@ -4238,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
|
||||
@@ -6381,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 --
|
||||
|
||||
@@ -102,7 +102,11 @@ You can also specify advance notice, possibly repeating.
|
||||
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 \fBBody:\fR text entry.
|
||||
Enter the body of the reminder into the \fBSummary:\fR text entry. If
|
||||
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
|
||||
@@ -178,6 +182,15 @@ is editable with an editor but was not created using \fBTkRemind\fR,
|
||||
it will be underlined when you move the cursor over it, and
|
||||
you can edit it in a text editor by either left- or right-clicking
|
||||
on the reminder.
|
||||
.PP
|
||||
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
|
||||
|
||||
|
||||
@@ -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 .= "
";
|
||||
}
|
||||
$done_one = 1;
|
||||
my $val = escape_html($info->{$key});
|
||||
$val =~ s/\n/
/g;
|
||||
$val =~ s/"/"/g;
|
||||
$val =~ s/</</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>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ WriteMakefile(
|
||||
'Getopt::Long' => 0,
|
||||
'Cairo' => 0,
|
||||
'Pango' => 0,
|
||||
'JSON::MaybeXS' => 0,
|
||||
'Encode' => 0,
|
||||
},
|
||||
EXE_FILES => [ 'bin/rem2pdf' ]
|
||||
);
|
||||
|
||||
@@ -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"; \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -280,6 +280,9 @@ set AppendFile $ReminderFile
|
||||
# Array of tags -> JSON dicts
|
||||
array unset TagToObj
|
||||
|
||||
# Array of __syn__ tags -> JSON dicts
|
||||
array unset SynToObj
|
||||
|
||||
set SetFontsWorked 0
|
||||
#---------------- DON'T CHANGE STUFF BELOW HERE ------------------
|
||||
|
||||
@@ -582,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
|
||||
@@ -632,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
|
||||
}
|
||||
@@ -653,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
|
||||
}
|
||||
@@ -683,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
|
||||
}
|
||||
@@ -1138,9 +1145,10 @@ proc ConfigureCalWindow { month year firstDay numDays } {
|
||||
proc FillCalWindow {} {
|
||||
set FileName ""
|
||||
set LineNo 0
|
||||
global DayNames CurYear CurMonth MonthNames CommandLine Option TagToObj RemindErrors MondayFirst
|
||||
global DayNames CurYear CurMonth MonthNames CommandLine Option TagToObj SynToObj RemindErrors MondayFirst
|
||||
|
||||
array unset TagToObj
|
||||
array unset SynToObj
|
||||
|
||||
Status "Firing off Remind..."
|
||||
set_button_to_queue
|
||||
@@ -1204,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]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1230,7 +1243,7 @@ proc FillCalWindow {} {
|
||||
set day [string trimleft $day 0]
|
||||
set n [expr $day+$offset]
|
||||
set month [string trimleft $month 0]
|
||||
set extratags ""
|
||||
set extratags {}
|
||||
switch -nocase -- $type {
|
||||
"WEEK" {
|
||||
set stuff [string trimleft $stuff]
|
||||
@@ -1269,9 +1282,9 @@ proc FillCalWindow {} {
|
||||
set b 0
|
||||
}
|
||||
set color [format "%02X%02X%02X" $r $g $b]
|
||||
set extratags "clr$color"
|
||||
lappend extratags "clr$color"
|
||||
.cal.t$n configure -state normal
|
||||
.cal.t$n tag configure $extratags -foreground "#$color"
|
||||
.cal.t$n tag configure "clr$color" -foreground "#$color"
|
||||
.cal.t$n configure -state disabled -takefocus 0
|
||||
set stuff $stuff
|
||||
set type "COLOR"
|
||||
@@ -1288,18 +1301,27 @@ proc FillCalWindow {} {
|
||||
set stuff [regsub -all {\n[ \t]} $stuff "\n"]
|
||||
set stuff [regsub -all {\n+} $stuff "\n"]
|
||||
|
||||
if {[regexp {__syn__([0-9a-f]+)} $tag syntag]} {
|
||||
set SynToObj($syntag) $obj
|
||||
lappend extratags $syntag
|
||||
.cal.t$n tag bind $syntag <Enter> [list details_enter .cal.t$n]
|
||||
.cal.t$n tag bind $syntag <Leave> [list details_leave .cal.t$n]
|
||||
} else {
|
||||
set syntag ""
|
||||
}
|
||||
|
||||
if {[regexp {TKTAG([0-9]+)} $tag all tagno] && "$fntag" != "x"} {
|
||||
.cal.t$n insert end [string trim $stuff] [list REM TAGGED "TKTAG$tagno" "date_$date" $extratags $fntag]
|
||||
.cal.t$n tag bind "TKTAG$tagno" <Enter> "TaggedEnter .cal.t$n"
|
||||
.cal.t$n tag bind "TKTAG$tagno" <Leave> "TaggedLeave .cal.t$n"
|
||||
set TagToObj(TKTAG$tagno) $obj
|
||||
.cal.t$n insert end [string trim $stuff] [concat REM TAGGED "TKTAG$tagno" "date_$date" $extratags $fntag]
|
||||
.cal.t$n tag bind "TKTAG$tagno" <Enter> [list TaggedEnter .cal.t$n]
|
||||
.cal.t$n tag bind "TKTAG$tagno" <Leave> [list TaggedLeave .cal.t$n]
|
||||
set TagToObj($all) $obj
|
||||
} else {
|
||||
if {"$fntag" == "x" } {
|
||||
.cal.t$n insert end [string trim $stuff] [list REM $extratags]
|
||||
.cal.t$n insert end [string trim $stuff] [concat REM $extratags]
|
||||
} else {
|
||||
.cal.t$n insert end [string trim $stuff] [list REM $extratags $fntag]
|
||||
.cal.t$n tag bind $fntag <Enter> "EditableEnter .cal.t$n"
|
||||
.cal.t$n tag bind $fntag <Leave> "EditableLeave .cal.t$n"
|
||||
.cal.t$n insert end [string trim $stuff] [concat REM $extratags $fntag]
|
||||
.cal.t$n tag bind $fntag <Enter> [list EditableEnter .cal.t$n]
|
||||
.cal.t$n tag bind $fntag <Leave> [list EditableLeave .cal.t$n]
|
||||
.cal.t$n tag bind $fntag <ButtonPress-1> "FireEditor .cal.t$n"
|
||||
}
|
||||
}
|
||||
@@ -1707,8 +1729,9 @@ proc CreateModifyDialog {w day firstDay args} {
|
||||
frame $w.msg
|
||||
frame $w.buttons
|
||||
pack $w.o1 $w.o2 $w.o3 -side top -anchor w -in $w.o
|
||||
pack $w.o $w.exp $w.adv $w.weekend $w.time $w.durationbox $w.hol $w.msg -side top -anchor w -pady 4 -expand 1 -fill both
|
||||
pack $w.buttons -side top -anchor w -pady 4 -expand 1 -fill x
|
||||
pack $w.o $w.exp $w.adv $w.weekend $w.time $w.durationbox $w.hol $w.msg -side top -anchor w -pady 4 -expand 0 -fill both
|
||||
pack $w.msg -side top -anchor w -pady 4 -padx 4 -expand true -fill both
|
||||
pack $w.buttons -side top -anchor w -pady 4 -expand 0 -fill x
|
||||
|
||||
# TYPE 1 REMINDER
|
||||
radiobutton $w.type1 -variable OptionType -value 1
|
||||
@@ -1905,12 +1928,37 @@ proc CreateModifyDialog {w day firstDay args} {
|
||||
pack $w.labhol $w.issue $w.skip $w.before $w.after -side top -anchor w -in $w.hol
|
||||
|
||||
# TEXT ENTRY
|
||||
label $w.msglab -text "Body:"
|
||||
label $w.msglab -text "Summary: "
|
||||
entry $w.entry
|
||||
balloon_add_help $w.entry "Enter the text of the reminder"
|
||||
pack $w.msglab -side left -anchor w -in $w.msg
|
||||
pack $w.entry -side left -anchor w -expand 1 -fill x -in $w.msg
|
||||
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, 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 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 0
|
||||
grid rowconfigure $w.msg 3 -weight 1
|
||||
# BUTTONS
|
||||
set nbut 0
|
||||
foreach but $args {
|
||||
@@ -1988,6 +2036,11 @@ proc OptionsToRemindDialog { w opts } {
|
||||
set hour $value
|
||||
}
|
||||
}
|
||||
"-txtentry-*" {
|
||||
set win [string range $flag 10 end]
|
||||
$w.$win delete 1.0 end
|
||||
$w.$win insert end $value
|
||||
}
|
||||
"-global-*" {
|
||||
set win [string range $flag 8 end]
|
||||
set $win $value
|
||||
@@ -2170,6 +2223,13 @@ proc CenterWindow {w {parent {}}} {
|
||||
wm deiconify $w
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# RemQuotedString - return a quoted string with difficult characters escaped
|
||||
#---------------------------------------------------------------------------
|
||||
proc RemQuotedString { str } {
|
||||
set str [string map {"\n" "\\n" "\"" "\\\"" "[" "[\"[\"]"} $str]
|
||||
return "\"$str\""
|
||||
}
|
||||
#---------------------------------------------------------------------------
|
||||
# CreateReminder -- create the reminder
|
||||
# Arguments:
|
||||
@@ -2255,7 +2315,21 @@ proc CreateReminder {w} {
|
||||
append rem " OMIT [GetWeekend $w 1]"
|
||||
}
|
||||
|
||||
|
||||
set location [string trim [$w.location get]]
|
||||
if {$location != ""} {
|
||||
set location "Location: $location"
|
||||
append rem " INFO [RemQuotedString $location]"
|
||||
}
|
||||
set description [string trim [$w.description get 1.0 end]]
|
||||
if {$description != ""} {
|
||||
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+]
|
||||
@@ -2798,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" != "" } {
|
||||
@@ -2916,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]
|
||||
@@ -2964,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 .
|
||||
@@ -2993,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
|
||||
@@ -3009,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 != "*"} {
|
||||
@@ -3443,6 +3555,19 @@ proc ReadTaggedOptions { tag date } {
|
||||
lappend ans -text-year3 $y
|
||||
}
|
||||
}
|
||||
|
||||
if {[dict exists $obj info]} {
|
||||
set info [dict get $obj info]
|
||||
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]
|
||||
}
|
||||
}
|
||||
return $ans
|
||||
}
|
||||
|
||||
@@ -3573,6 +3698,93 @@ proc EditableLeave { w } {
|
||||
set tag [lindex $tags $index]
|
||||
$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]
|
||||
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)
|
||||
set lines {}
|
||||
if {![dict exists $obj info]} {
|
||||
return
|
||||
}
|
||||
set info [dict get $obj info]
|
||||
set llen 0
|
||||
if {[dict exists $info location]} {
|
||||
lappend lines [list "Location:" [dict get $info location]]
|
||||
}
|
||||
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;
|
||||
}
|
||||
balloon_cancel_timer
|
||||
|
||||
set Balloon(HelpId) [after $Balloon(HelpTime) [list details_popup $lines]]
|
||||
}
|
||||
|
||||
proc details_leave { w } {
|
||||
balloon_cancel_timer
|
||||
catch { destroy .balloonhelp }
|
||||
}
|
||||
|
||||
proc details_popup { pairs } {
|
||||
global Balloon
|
||||
set maxwid 80
|
||||
set h .balloonhelp
|
||||
set c 0
|
||||
toplevel $h -bg #000000
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
wm overrideredirect $h 1
|
||||
set geom [balloon_calculate_geometry $h]
|
||||
wm geometry $h $geom
|
||||
set Balloon(HelpId) [after 10000 "catch { destroy $h }"]
|
||||
set Balloon(MustLeave) 1
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: EditTaggedReminder
|
||||
# %ARGUMENTS:
|
||||
@@ -4421,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]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
130
src/calendar.c
130
src/calendar.c
@@ -57,10 +57,12 @@ typedef struct cal_entry {
|
||||
int duration;
|
||||
char *filename;
|
||||
int lineno;
|
||||
int lineno_start;
|
||||
Trigger trig;
|
||||
TimeTrig tt;
|
||||
int nonconst_expr;
|
||||
int if_depth;
|
||||
TrigInfo *infos;
|
||||
} CalEntry;
|
||||
|
||||
/* Line-drawing sequences */
|
||||
@@ -387,7 +389,13 @@ void PrintJSONChar(char c) {
|
||||
case '\t': printf("\\t"); break;
|
||||
case '"': printf("\\\""); break;
|
||||
case '\\': printf("\\\\"); break;
|
||||
default: printf("%c", c);
|
||||
default:
|
||||
if ((c > 0 && c < 32) || c == 0x7f) {
|
||||
printf("\\u%04x", (unsigned int) c);
|
||||
} else {
|
||||
printf("%c", c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +410,36 @@ void PrintJSONString(char const *s)
|
||||
case '\t': printf("\\t"); break;
|
||||
case '"': printf("\\\""); break;
|
||||
case '\\': printf("\\\\"); break;
|
||||
default: printf("%c", *s);
|
||||
default:
|
||||
if ((*s > 0 && *s < 32) || *s == 0x7f) {
|
||||
printf("\\u%04x", (unsigned int) *s);
|
||||
} else {
|
||||
printf("%c", *s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintJSONStringLC(char const *s)
|
||||
{
|
||||
while (*s) {
|
||||
switch(*s) {
|
||||
case '\b': printf("\\b"); break;
|
||||
case '\f': printf("\\f"); break;
|
||||
case '\n': printf("\\n"); break;
|
||||
case '\r': printf("\\r"); break;
|
||||
case '\t': printf("\\t"); break;
|
||||
case '"': printf("\\\""); break;
|
||||
case '\\': printf("\\\\"); break;
|
||||
default:
|
||||
if ((*s > 0 && *s < 32) || *s == 0x7f) {
|
||||
printf("\\u%04x", (unsigned int) *s);
|
||||
} else {
|
||||
printf("%c", tolower(*s));
|
||||
}
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
@@ -499,7 +536,7 @@ get_month_abbrev(char const *mon)
|
||||
{
|
||||
static char buf[80];
|
||||
#ifndef REM_USE_WCHAR
|
||||
sprintf(buf, "%.3s", mon);
|
||||
snprintf(buf, sizeof(buf), "%.3s", mon);
|
||||
return buf;
|
||||
#else
|
||||
char *s;
|
||||
@@ -626,9 +663,9 @@ Colorize256(int r, int g, int b, int bg, int clamp)
|
||||
}
|
||||
}
|
||||
if (bg) {
|
||||
sprintf(buf, "\x1B[48;5;%dm", best);
|
||||
snprintf(buf, sizeof(buf), "\x1B[48;5;%dm", best);
|
||||
} else {
|
||||
sprintf(buf, "\x1B[38;5;%dm", best);
|
||||
snprintf(buf, sizeof(buf), "\x1B[38;5;%dm", best);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
@@ -641,9 +678,9 @@ ColorizeTrue(int r, int g, int b, int bg, int clamp)
|
||||
ClampColor(&r, &g, &b);
|
||||
}
|
||||
if (bg) {
|
||||
sprintf(buf, "\x1B[48;2;%d;%d;%dm", r, g, b);
|
||||
snprintf(buf, sizeof(buf), "\x1B[48;2;%d;%d;%dm", r, g, b);
|
||||
} else {
|
||||
sprintf(buf, "\x1B[38;2;%d;%d;%dm", r, g, b);
|
||||
snprintf(buf, sizeof(buf), "\x1B[38;2;%d;%d;%dm", r, g, b);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
@@ -1504,6 +1541,7 @@ static int WriteOneColLine(int col)
|
||||
free(e->raw_text);
|
||||
free(e->filename);
|
||||
if (e->wc_text) free(e->wc_text);
|
||||
FreeTrigInfoChain(e->infos);
|
||||
free(e);
|
||||
return 1;
|
||||
}
|
||||
@@ -1590,6 +1628,7 @@ static int WriteOneColLine(int col)
|
||||
free(e->raw_text);
|
||||
free(e->filename);
|
||||
if (e->wc_text) free(e->wc_text);
|
||||
FreeTrigInfoChain(e->infos);
|
||||
free(e);
|
||||
} else {
|
||||
e->wc_pos = ws;
|
||||
@@ -1611,6 +1650,7 @@ static int WriteOneColLine(int col)
|
||||
if (e->wc_text) free(e->wc_text);
|
||||
#endif
|
||||
free(e->raw_text);
|
||||
FreeTrigInfoChain(e->infos);
|
||||
free(e);
|
||||
return 1;
|
||||
}
|
||||
@@ -1673,6 +1713,7 @@ static int WriteOneColLine(int col)
|
||||
if (e->wc_text) free(e->wc_text);
|
||||
#endif
|
||||
free(e->raw_text);
|
||||
FreeTrigInfoChain(e->infos);
|
||||
free(e);
|
||||
} else {
|
||||
e->pos = s;
|
||||
@@ -1812,7 +1853,7 @@ static void WriteCalHeader(void)
|
||||
int y, m, d;
|
||||
|
||||
FromDSE(DSEToday, &y, &m, &d);
|
||||
sprintf(buf, "%s %d", get_month_name(m), y);
|
||||
snprintf(buf, sizeof(buf), "%s %d", get_month_name(m), y);
|
||||
|
||||
WriteTopCalLine();
|
||||
|
||||
@@ -2016,7 +2057,7 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
trig.typ == MSF_TYPE) {
|
||||
if (PsCal && is_color) {
|
||||
char cbuf[24];
|
||||
sprintf(cbuf, "%d %d %d ", col_r, col_g, col_b);
|
||||
snprintf(cbuf, sizeof(cbuf), "%d %d %d ", col_r, col_g, col_b);
|
||||
DBufPuts(&pre_buf, cbuf);
|
||||
strcpy(trig.passthru, "COLOR");
|
||||
/* Don't change trig.typ or next if() will trigger! */
|
||||
@@ -2149,7 +2190,7 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
if (trig.typ != PASSTHRU_TYPE &&
|
||||
UserFuncExists("calprefix")==1) {
|
||||
char evalBuf[64];
|
||||
sprintf(evalBuf, "calprefix(%d)", trig.priority);
|
||||
snprintf(evalBuf, sizeof(evalBuf), "calprefix(%d)", trig.priority);
|
||||
s2 = evalBuf;
|
||||
r = EvalExpr(&s2, &v, NULL);
|
||||
if (!r) {
|
||||
@@ -2192,7 +2233,7 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
if (trig.typ != PASSTHRU_TYPE &&
|
||||
UserFuncExists("calsuffix")==1) {
|
||||
char evalBuf[64];
|
||||
sprintf(evalBuf, "calsuffix(%d)", trig.priority);
|
||||
snprintf(evalBuf, sizeof(evalBuf), "calsuffix(%d)", trig.priority);
|
||||
s2 = evalBuf;
|
||||
r = EvalExpr(&s2, &v, NULL);
|
||||
if (!r) {
|
||||
@@ -2232,6 +2273,7 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
FreeTrig(&trig);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
e->infos = NULL;
|
||||
e->nonconst_expr = nonconst_expr;
|
||||
e->if_depth = NumIfs;
|
||||
e->trig = trig;
|
||||
@@ -2252,6 +2294,7 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
if (!e->text || !e->raw_text) {
|
||||
if (e->text) free(e->text);
|
||||
if (e->raw_text) free(e->raw_text);
|
||||
FreeTrigInfoChain(e->infos);
|
||||
free(e);
|
||||
FreeTrig(&trig);
|
||||
return E_NO_MEM;
|
||||
@@ -2265,12 +2308,17 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
AppendTag(&(e->tags), SynthesizeTag());
|
||||
}
|
||||
|
||||
/* Take over any TrigInfo! */
|
||||
e->infos = trig.infos;
|
||||
trig.infos = NULL;
|
||||
|
||||
/* Don't need tags any more */
|
||||
FreeTrig(&trig);
|
||||
e->duration = tim.duration;
|
||||
e->priority = trig.priority;
|
||||
e->filename = StrDup(FileName);
|
||||
if(!e->filename) {
|
||||
FreeTrigInfoChain(e->infos);
|
||||
if (e->text) free(e->text);
|
||||
if (e->raw_text) free(e->raw_text);
|
||||
#ifdef REM_USE_WCHAR
|
||||
@@ -2280,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);
|
||||
@@ -2342,6 +2391,41 @@ void WriteJSONTimeTrigger(TimeTrig const *tt)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WriteJSONInfoChain(TrigInfo *ti)
|
||||
{
|
||||
printf("\"info\":{");
|
||||
while (ti) {
|
||||
/* Skanky... */
|
||||
char *colon = (char *) strchr(ti->info, ':');
|
||||
char const *value;
|
||||
if (!colon) {
|
||||
/* Should be impossible... */
|
||||
ti = ti->next;
|
||||
continue;
|
||||
}
|
||||
/* Terminate the string at the colon */
|
||||
*colon = 0;
|
||||
|
||||
value = colon+1;
|
||||
while(*value && isspace(*value)) {
|
||||
value++;
|
||||
}
|
||||
printf("\"");
|
||||
PrintJSONStringLC(ti->info);
|
||||
printf("\":\"");
|
||||
PrintJSONString(value);
|
||||
printf("\"");
|
||||
|
||||
/* Restore the value of the colon */
|
||||
*colon = ':';
|
||||
if (ti->next) {
|
||||
printf(",");
|
||||
}
|
||||
ti = ti->next;
|
||||
}
|
||||
printf("},");
|
||||
}
|
||||
void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
|
||||
{
|
||||
/* wd is an array of days from 0=monday to 6=sunday.
|
||||
@@ -2433,6 +2517,9 @@ void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
|
||||
PrintJSONKeyPairInt("addomit", 1);
|
||||
}
|
||||
if (include_tags) {
|
||||
if (t->infos) {
|
||||
WriteJSONInfoChain(t->infos);
|
||||
}
|
||||
PrintJSONKeyPairString("tags", DBufValue(&(t->tags)));
|
||||
}
|
||||
}
|
||||
@@ -2443,9 +2530,15 @@ 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)));
|
||||
if (e->infos) {
|
||||
WriteJSONInfoChain(e->infos);
|
||||
}
|
||||
if (e->duration != NO_TIME) {
|
||||
PrintJSONKeyPairInt("duration", e->duration);
|
||||
}
|
||||
@@ -2576,6 +2669,7 @@ static void WriteSimpleEntries(int col, int dse)
|
||||
free(e->text);
|
||||
free(e->raw_text);
|
||||
free(e->filename);
|
||||
FreeTrigInfoChain(e->infos);
|
||||
#ifdef REM_USE_WCHAR
|
||||
if (e->wc_text) free(e->wc_text);
|
||||
#endif
|
||||
@@ -2736,7 +2830,7 @@ CalendarTime(int tim, int duration)
|
||||
else hh2 = h2;
|
||||
|
||||
if (days) {
|
||||
sprintf(daybuf, "+%d", days);
|
||||
snprintf(daybuf, sizeof(daybuf), "+%d", days);
|
||||
} else {
|
||||
daybuf[0] = 0;
|
||||
}
|
||||
@@ -2759,12 +2853,12 @@ CalendarTime(int tim, int duration)
|
||||
|
||||
switch(ScFormat) {
|
||||
case SC_AMPM:
|
||||
sprintf(buf, "%d%c%02d%s-%d%c%02d%s%s ",
|
||||
snprintf(buf, sizeof(buf), "%d%c%02d%s-%d%c%02d%s%s ",
|
||||
hh, TimeSep, min, ampm1, hh2, TimeSep, min2, ampm2, daybuf);
|
||||
break;
|
||||
|
||||
case SC_MIL:
|
||||
sprintf(buf, "%02d%c%02d-%02d%c%02d%s ",
|
||||
snprintf(buf, sizeof(buf), "%02d%c%02d-%02d%c%02d%s ",
|
||||
h, TimeSep, min, h2, TimeSep, min2, daybuf);
|
||||
break;
|
||||
}
|
||||
@@ -2782,7 +2876,7 @@ CalendarTime(int tim, int duration)
|
||||
/***************************************************************/
|
||||
char const *SimpleTime(int tim)
|
||||
{
|
||||
static char buf[32];
|
||||
static char buf[128];
|
||||
int h, min, hh;
|
||||
|
||||
buf[0] = 0;
|
||||
@@ -2796,7 +2890,7 @@ char const *SimpleTime(int tim)
|
||||
if (h == 0) hh=12;
|
||||
else if (h > 12) hh=h-12;
|
||||
else hh=h;
|
||||
sprintf(buf, "%d%c%02d%s ", hh, TimeSep, min, (h>=12) ? tr("pm") : tr("am"));
|
||||
snprintf(buf, sizeof(buf), "%d%c%02d%.64s ", hh, TimeSep, min, (h>=12) ? tr("pm") : tr("am"));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2804,7 +2898,7 @@ char const *SimpleTime(int tim)
|
||||
if (tim != NO_TIME) {
|
||||
h = tim / 60;
|
||||
min = tim % 60;
|
||||
sprintf(buf, "%02d%c%02d ", h, TimeSep, min);
|
||||
snprintf(buf, sizeof(buf), "%02d%c%02d ", h, TimeSep, min);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2856,7 +2950,7 @@ char const *SynthesizeTag(void)
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, (unsigned char *) CurLine, strlen(CurLine));
|
||||
MD5Final(buf, &ctx);
|
||||
sprintf(out, "__syn__%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
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],
|
||||
(unsigned int) buf[2], (unsigned int) buf[3],
|
||||
(unsigned int) buf[4], (unsigned int) buf[5],
|
||||
|
||||
@@ -116,4 +116,4 @@
|
||||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||
#undef TM_IN_SYS_TIME
|
||||
|
||||
#include <custom.h>
|
||||
#include "custom.h"
|
||||
|
||||
34
src/dorem.c
34
src/dorem.c
@@ -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
|
||||
@@ -408,6 +408,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
||||
tim->duration = NO_TIME;
|
||||
trig->need_wkday = 0;
|
||||
trig->adj_for_last = 0;
|
||||
trig->infos = NULL;
|
||||
|
||||
int parsing = 1;
|
||||
while(parsing) {
|
||||
@@ -649,6 +650,15 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
||||
DBufFree(&buf);
|
||||
break;
|
||||
|
||||
case T_Info:
|
||||
r = ParseQuotedString(s, &buf);
|
||||
if (r != OK) {
|
||||
return r;
|
||||
}
|
||||
r = AppendTrigInfo(trig, DBufValue(&buf));
|
||||
DBufFree(&buf);
|
||||
if (r) return r;
|
||||
break;
|
||||
case T_Tag:
|
||||
r = ParseToken(s, &buf);
|
||||
if (r) return r;
|
||||
@@ -1180,7 +1190,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
||||
return OK;
|
||||
}
|
||||
FromDSE(dse, &y, &m, &d);
|
||||
sprintf(tmpBuf, "%04d/%02d/%02d ", y, m+1, d);
|
||||
snprintf(tmpBuf, sizeof(tmpBuf), "%04d/%02d/%02d ", y, m+1, d);
|
||||
if (DBufPuts(&calRow, tmpBuf) != OK) {
|
||||
DBufFree(&calRow);
|
||||
DBufFree(&pre_buf);
|
||||
@@ -1201,9 +1211,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
||||
DBufPuts(&calRow, "* ");
|
||||
}
|
||||
if (tim->duration != NO_TIME) {
|
||||
sprintf(tmpBuf, "%d ", tim->duration);
|
||||
snprintf(tmpBuf, sizeof(tmpBuf), "%d ", tim->duration);
|
||||
} else {
|
||||
sprintf(tmpBuf, "* ");
|
||||
snprintf(tmpBuf, sizeof(tmpBuf), "* ");
|
||||
}
|
||||
if (DBufPuts(&calRow, tmpBuf) != OK) {
|
||||
DBufFree(&calRow);
|
||||
@@ -1211,9 +1221,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
||||
return E_NO_MEM;
|
||||
}
|
||||
if (tim->ttime != NO_TIME) {
|
||||
sprintf(tmpBuf, "%d ", tim->ttime);
|
||||
snprintf(tmpBuf, sizeof(tmpBuf), "%d ", tim->ttime);
|
||||
} else {
|
||||
sprintf(tmpBuf, "* ");
|
||||
snprintf(tmpBuf, sizeof(tmpBuf), "* ");
|
||||
}
|
||||
if (DBufPuts(&calRow, tmpBuf) != OK) {
|
||||
DBufFree(&calRow);
|
||||
@@ -1263,7 +1273,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
||||
/* Don't use msgprefix() on RUN-type reminders */
|
||||
if (t->typ != RUN_TYPE) {
|
||||
if (UserFuncExists("msgprefix") == 1) {
|
||||
sprintf(PrioExpr, "msgprefix(%d)", t->priority);
|
||||
snprintf(PrioExpr, sizeof(PrioExpr), "msgprefix(%d)", t->priority);
|
||||
s = PrioExpr;
|
||||
r = EvalExpr(&s, &v, NULL);
|
||||
if (!r) {
|
||||
@@ -1289,7 +1299,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
||||
|
||||
if (t->typ != RUN_TYPE) {
|
||||
if (UserFuncExists("msgsuffix") == 1) {
|
||||
sprintf(PrioExpr, "msgsuffix(%d)", t->priority);
|
||||
snprintf(PrioExpr, sizeof(PrioExpr), "msgsuffix(%d)", t->priority);
|
||||
s = PrioExpr;
|
||||
r = EvalExpr(&s, &v, NULL);
|
||||
if (!r) {
|
||||
@@ -1548,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),
|
||||
@@ -1694,7 +1704,7 @@ static int ShouldTriggerBasedOnWarn(Trigger *t, int dse, int *err)
|
||||
return (dse == DSEToday);
|
||||
}
|
||||
for (i=1; ; i++) {
|
||||
sprintf(buffer, "%s(%d)", t->warn, i);
|
||||
snprintf(buffer, sizeof(buffer), "%s(%d)", t->warn, i);
|
||||
s = buffer;
|
||||
r = EvalExpr(&s, &v, NULL);
|
||||
if (r) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
61
src/expr.c
61
src/expr.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1546,6 +1560,8 @@ static int parse_expr_token(DynamicBuffer *buf, char const **in)
|
||||
{
|
||||
|
||||
char c;
|
||||
char c2;
|
||||
char hexbuf[3];
|
||||
|
||||
DBufFree(buf);
|
||||
|
||||
@@ -1633,8 +1649,32 @@ static int parse_expr_token(DynamicBuffer *buf, char const **in)
|
||||
case 'v':
|
||||
r = DBufPutc(buf, '\v');
|
||||
break;
|
||||
case 'x':
|
||||
c2 = *(*in + 1);
|
||||
if (!isxdigit(c2)) {
|
||||
r = DBufPutc(buf, **in);
|
||||
break;
|
||||
}
|
||||
hexbuf[0] = c2;
|
||||
hexbuf[1] = 0;
|
||||
(*in)++;
|
||||
c2 = *(*in + 1);
|
||||
if (isxdigit(c2)) {
|
||||
hexbuf[1] = c2;
|
||||
hexbuf[2] = 0;
|
||||
(*in)++;
|
||||
}
|
||||
c2 = (int) strtol(hexbuf, NULL, 16);
|
||||
if (!c2) {
|
||||
Eprint(tr("\\x00 is not a valid escape sequence"));
|
||||
r = E_PARSE_ERR;
|
||||
} else {
|
||||
r = DBufPutc(buf, c2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
r = DBufPutc(buf, **in);
|
||||
break;
|
||||
}
|
||||
(*in)++;
|
||||
if (r != OK) {
|
||||
@@ -1877,8 +1917,8 @@ static expr_node * parse_function_call(char const **e, int *r, Var *locals, int
|
||||
}
|
||||
}
|
||||
}
|
||||
ptr = *e;
|
||||
if (TOKEN_IS(")")) {
|
||||
ptr = *e;
|
||||
*r = GET_TOKEN();
|
||||
if (*r != OK) {
|
||||
return free_expr_tree(node);
|
||||
@@ -2162,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 != '\'') {
|
||||
@@ -3014,12 +3053,12 @@ int DoCoerce(char type, Value *v)
|
||||
}
|
||||
case STR_TYPE:
|
||||
switch(v->type) {
|
||||
case INT_TYPE: sprintf(coerce_buf, "%d", v->v.val); break;
|
||||
case TIME_TYPE: sprintf(coerce_buf, "%02d%c%02d", v->v.val / 60,
|
||||
case INT_TYPE: snprintf(coerce_buf, sizeof(coerce_buf), "%d", v->v.val); break;
|
||||
case TIME_TYPE: snprintf(coerce_buf, sizeof(coerce_buf), "%02d%c%02d", v->v.val / 60,
|
||||
TimeSep, v->v.val % 60);
|
||||
break;
|
||||
case DATE_TYPE: FromDSE(v->v.val, &y, &m, &d);
|
||||
sprintf(coerce_buf, "%04d%c%02d%c%02d",
|
||||
snprintf(coerce_buf, sizeof(coerce_buf), "%04d%c%02d%c%02d",
|
||||
y, DateSep, m+1, DateSep, d);
|
||||
break;
|
||||
case DATETIME_TYPE:
|
||||
@@ -3028,7 +3067,7 @@ int DoCoerce(char type, Value *v)
|
||||
k = v->v.val % MINUTES_PER_DAY;
|
||||
h = k / 60;
|
||||
i = k % 60;
|
||||
sprintf(coerce_buf, "%04d%c%02d%c%02d%c%02d%c%02d",
|
||||
snprintf(coerce_buf, sizeof(coerce_buf), "%04d%c%02d%c%02d%c%02d%c%02d",
|
||||
y, DateSep, m+1, DateSep, d, DateTimeSep, h, TimeSep, i);
|
||||
break;
|
||||
default: return E_CANT_COERCE;
|
||||
|
||||
14
src/files.c
14
src/files.c
@@ -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);
|
||||
|
||||
222
src/funcs.c
222
src/funcs.c
@@ -93,6 +93,7 @@ static int FDefined (func_info *);
|
||||
static int FDosubst (func_info *);
|
||||
static int FDusk (func_info *);
|
||||
static int FEasterdate (func_info *);
|
||||
static int FEscape (func_info *);
|
||||
static int FEvalTrig (func_info *);
|
||||
static int FFiledate (func_info *);
|
||||
static int FFiledatetime (func_info *);
|
||||
@@ -124,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 *);
|
||||
@@ -161,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 *);
|
||||
@@ -252,6 +258,7 @@ BuiltinFunc Func[] = {
|
||||
{ "dosubst", 1, 3, 0, FDosubst, NULL },
|
||||
{ "dusk", 0, 1, 0, FDusk, NULL },
|
||||
{ "easterdate", 0, 1, 0, FEasterdate, NULL },
|
||||
{ "escape", 1, 2, 1, FEscape, NULL },
|
||||
{ "evaltrig", 1, 2, 0, FEvalTrig, NULL },
|
||||
{ "filedate", 1, 1, 0, FFiledate, NULL },
|
||||
{ "filedatetime", 1, 1, 0, FFiledatetime, NULL },
|
||||
@@ -283,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 },
|
||||
@@ -324,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 },
|
||||
@@ -1076,7 +1088,7 @@ static int FOrd(func_info *info)
|
||||
if (u == 1 && t != 11) s = "st";
|
||||
if (u == 2 && t != 12) s = "nd";
|
||||
if (u == 3 && t != 13) s = "rd";
|
||||
sprintf(buf, "%d%s", v, s);
|
||||
snprintf(buf, sizeof(buf), "%d%s", v, s);
|
||||
return RetStrVal(buf, info);
|
||||
}
|
||||
|
||||
@@ -1618,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) {
|
||||
@@ -1828,10 +1851,10 @@ static int FTrigger(func_info *info)
|
||||
|
||||
FromDSE(date, &y, &m, &d);
|
||||
if (tim != NO_TIME) {
|
||||
sprintf(buf, "%d %s %d AT %02d:%02d", d, MonthName[m], y,
|
||||
snprintf(buf, sizeof(buf), "%d %s %d AT %02d:%02d", d, MonthName[m], y,
|
||||
tim/60, tim%60);
|
||||
} else {
|
||||
sprintf(buf, "%d %s %d", d, MonthName[m], y);
|
||||
snprintf(buf, sizeof(buf), "%d %s %d", d, MonthName[m], y);
|
||||
}
|
||||
return RetStrVal(buf, info);
|
||||
}
|
||||
@@ -2363,6 +2386,89 @@ static int FHebyear(func_info *info)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* escape - escape special characters with "\xx" sequences */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
static int FEscape(func_info *info)
|
||||
{
|
||||
DynamicBuffer dbuf;
|
||||
char const *s;
|
||||
char hexbuf[16];
|
||||
int r;
|
||||
int include_quotes = 0;
|
||||
ASSERT_TYPE(0, STR_TYPE);
|
||||
if (Nargs >= 2) {
|
||||
ASSERT_TYPE(1, INT_TYPE);
|
||||
include_quotes = ARGV(1);
|
||||
}
|
||||
|
||||
DBufInit(&dbuf);
|
||||
if (include_quotes) {
|
||||
r = DBufPutc(&dbuf, '"');
|
||||
if (r != OK) {
|
||||
DBufFree(&dbuf);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
s = ARGSTR(0);
|
||||
while(*s) {
|
||||
switch(*s) {
|
||||
case '\a':
|
||||
r = DBufPuts(&dbuf, "\\a");
|
||||
break;
|
||||
case '\b':
|
||||
r = DBufPuts(&dbuf, "\\b");
|
||||
break;
|
||||
case '\f':
|
||||
r = DBufPuts(&dbuf, "\\f");
|
||||
break;
|
||||
case '\n':
|
||||
r = DBufPuts(&dbuf, "\\n");
|
||||
break;
|
||||
case '\r':
|
||||
r = DBufPuts(&dbuf, "\\r");
|
||||
break;
|
||||
case '\t':
|
||||
r = DBufPuts(&dbuf, "\\t");
|
||||
break;
|
||||
case '\v':
|
||||
r = DBufPuts(&dbuf, "\\v");
|
||||
break;
|
||||
case '\\':
|
||||
r = DBufPuts(&dbuf, "\\\\");
|
||||
break;
|
||||
case '"':
|
||||
r = DBufPuts(&dbuf, "\\\"");
|
||||
break;
|
||||
default:
|
||||
if ((*s > 0 && *s < ' ') || *s == 0x7f) {
|
||||
snprintf(hexbuf, sizeof(hexbuf), "\\x%02x", (unsigned int) *s);
|
||||
r = DBufPuts(&dbuf, hexbuf);
|
||||
} else {
|
||||
r = DBufPutc(&dbuf, *s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (r != OK) {
|
||||
DBufFree(&dbuf);
|
||||
return r;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if (include_quotes) {
|
||||
r = DBufPutc(&dbuf, '"');
|
||||
if (r != OK) {
|
||||
DBufFree(&dbuf);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
r = RetStrVal(DBufValue(&dbuf), info);
|
||||
DBufFree(&dbuf);
|
||||
return r;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* htmlescape - replace <. > and & by < > and & */
|
||||
@@ -3012,6 +3118,7 @@ static int FPsshade(func_info *info)
|
||||
char psbuff[256];
|
||||
char *s = psbuff;
|
||||
int i;
|
||||
size_t len = sizeof(psbuff);
|
||||
|
||||
/* 1 or 3 args */
|
||||
if (Nargs != 1 && Nargs != 3) return E_2MANY_ARGS;
|
||||
@@ -3027,16 +3134,19 @@ static int FPsshade(func_info *info)
|
||||
Wprint(tr("psshade() is deprecated; use SPECIAL SHADE instead."));
|
||||
}
|
||||
|
||||
sprintf(s, "/_A LineWidth 2 div def ");
|
||||
snprintf(s, len, "/_A LineWidth 2 div def ");
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
sprintf(s, "_A _A moveto ");
|
||||
snprintf(s, len, "_A _A moveto ");
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
sprintf(s, "BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto ");
|
||||
snprintf(s, len, "BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto ");
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
if (Nargs == 1) {
|
||||
sprintf(s, "_A BoxHeight _A sub lineto closepath %d 100 div setgray fill 0.0 setgray", ARGV(0));
|
||||
snprintf(s, len, "_A BoxHeight _A sub lineto closepath %d 100 div setgray fill 0.0 setgray", ARGV(0));
|
||||
} else {
|
||||
sprintf(s, "_A BoxHeight _A sub lineto closepath %d 100 div %d 100 div %d 100 div setrgbcolor fill 0.0 setgray", ARGV(0), ARGV(1), ARGV(2));
|
||||
snprintf(s, len, "_A BoxHeight _A sub lineto closepath %d 100 div %d 100 div %d 100 div setrgbcolor fill 0.0 setgray", ARGV(0), ARGV(1), ARGV(2));
|
||||
}
|
||||
return RetStrVal(psbuff, info);
|
||||
}
|
||||
@@ -3059,6 +3169,7 @@ static int FPsmoon(func_info *info)
|
||||
char const *extra = NULL;
|
||||
int size = -1;
|
||||
int fontsize = -1;
|
||||
size_t len = sizeof(psbuff);
|
||||
|
||||
ASSERT_TYPE(0, INT_TYPE);
|
||||
if (ARGV(0) < 0) return E_2LOW;
|
||||
@@ -3082,60 +3193,71 @@ static int FPsmoon(func_info *info)
|
||||
Wprint(tr("psmoon() is deprecated; use SPECIAL MOON instead."));
|
||||
}
|
||||
if (size > 0) {
|
||||
sprintf(sizebuf, "%d", size);
|
||||
snprintf(sizebuf, sizeof(sizebuf), "%d", size);
|
||||
} else {
|
||||
strcpy(sizebuf, "DaySize 2 div");
|
||||
}
|
||||
|
||||
if (fontsize > 0) {
|
||||
sprintf(fontsizebuf, "%d", fontsize);
|
||||
snprintf(fontsizebuf, sizeof(fontsizebuf), "%d", fontsize);
|
||||
} else {
|
||||
strcpy(fontsizebuf, "EntrySize");
|
||||
}
|
||||
|
||||
sprintf(s, "gsave 0 setgray newpath Border %s add BoxHeight Border sub %s sub",
|
||||
snprintf(s, len, "gsave 0 setgray newpath Border %s add BoxHeight Border sub %s sub",
|
||||
sizebuf, sizebuf);
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
sprintf(s, " %s 0 360 arc closepath", sizebuf);
|
||||
snprintf(s, len, " %s 0 360 arc closepath", sizebuf);
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
switch(ARGV(0)) {
|
||||
case 0:
|
||||
sprintf(s, " fill");
|
||||
snprintf(s, len, " fill");
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
sprintf(s, " stroke");
|
||||
snprintf(s, len, " stroke");
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
sprintf(s, " stroke");
|
||||
snprintf(s, len, " stroke");
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
sprintf(s, " newpath Border %s add BoxHeight Border sub %s sub",
|
||||
snprintf(s, len, " newpath Border %s add BoxHeight Border sub %s sub",
|
||||
sizebuf, sizebuf);
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
sprintf(s, " %s 90 270 arc closepath fill", sizebuf);
|
||||
snprintf(s, len, " %s 90 270 arc closepath fill", sizebuf);
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(s, " stroke");
|
||||
snprintf(s, len, " stroke");
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
sprintf(s, " newpath Border %s add BoxHeight Border sub %s sub",
|
||||
snprintf(s, len, " newpath Border %s add BoxHeight Border sub %s sub",
|
||||
sizebuf, sizebuf);
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
sprintf(s, " %s 270 90 arc closepath fill", sizebuf);
|
||||
snprintf(s, len, " %s 270 90 arc closepath fill", sizebuf);
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
break;
|
||||
}
|
||||
if (extra) {
|
||||
sprintf(s, " Border %s add %s add Border add BoxHeight border sub %s sub %s sub moveto /EntryFont findfont %s scalefont setfont (%s) show",
|
||||
snprintf(s, len, " Border %s add %s add Border add BoxHeight border sub %s sub %s sub moveto /EntryFont findfont %s scalefont setfont (%s) show",
|
||||
sizebuf, sizebuf, sizebuf, sizebuf, fontsizebuf, extra);
|
||||
len -= strlen(s);
|
||||
s += strlen(s);
|
||||
}
|
||||
|
||||
sprintf(s, " grestore");
|
||||
snprintf(s, len, " grestore");
|
||||
return RetStrVal(psbuff, info);
|
||||
}
|
||||
|
||||
@@ -3202,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;
|
||||
@@ -3266,7 +3436,7 @@ static int FDatepart(func_info *info)
|
||||
* used for the timezone stuff! */
|
||||
static int setenv(char const *varname, char const *val, int overwrite)
|
||||
{
|
||||
static char tzbuf[256];
|
||||
static char tzbuf[128];
|
||||
if (strcmp(varname, "TZ")) {
|
||||
fprintf(ErrFp, "built-in setenv can only be used with TZ\n");
|
||||
abort();
|
||||
@@ -3279,7 +3449,7 @@ static int setenv(char const *varname, char const *val, int overwrite)
|
||||
if (strlen(val) > 250) {
|
||||
return -1;
|
||||
}
|
||||
sprintf(tzbuf, "%s=%s", varname, val);
|
||||
snprintf(tzbuf, sizeof(tzbuf), "%s=%s", varname, val);
|
||||
return(putenv(tzbuf));
|
||||
}
|
||||
#endif
|
||||
@@ -3288,12 +3458,12 @@ static int setenv(char const *varname, char const *val, int overwrite)
|
||||
* used for the timezone stuff! */
|
||||
static void unsetenv(char const *varname)
|
||||
{
|
||||
static char tzbuf[8];
|
||||
static char tzbuf[128];
|
||||
if (strcmp(varname, "TZ")) {
|
||||
fprintf(ErrFp, "built-in unsetenv can only be used with TZ\n");
|
||||
abort();
|
||||
}
|
||||
sprintf(tzbuf, "%s", varname);
|
||||
snprintf(tzbuf, sizeof(tzbuf), "%s", varname);
|
||||
putenv(tzbuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
@@ -176,6 +177,9 @@ EXTERN INIT( unsigned int FuncRecursionLevel, 0);
|
||||
/* Suppress warnings about implicit REM and MSG */
|
||||
EXTERN INIT( int SuppressImplicitRemWarnings, 0);
|
||||
|
||||
/* Test mode - used by the acceptance tests */
|
||||
EXTERN INIT( int TestMode, 0);
|
||||
|
||||
extern int NumFullOmits, NumPartialOmits;
|
||||
|
||||
/* List of months */
|
||||
|
||||
16
src/init.c
16
src/init.c
@@ -795,10 +795,11 @@ void InitRemind(int argc, char const *argv[])
|
||||
|
||||
}
|
||||
|
||||
/* Figure out the offset from UTC */
|
||||
if (CalculateUTC)
|
||||
/* Figure out the offset from UTC */
|
||||
if (CalculateUTC) {
|
||||
(void) CalcMinsFromUTC(DSEToday, MinutesPastMidnight(0),
|
||||
&MinsFromUTC, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
@@ -1121,6 +1122,17 @@ static void
|
||||
ProcessLongOption(char const *arg)
|
||||
{
|
||||
int t;
|
||||
if (!strcmp(arg, "test")) {
|
||||
fprintf(stderr, "Enabling test mode: This is meant for the acceptance test.\nDo not use --test in production.\nIn test mode, the system time is fixed at 2025-01-06@19:00\n");
|
||||
TestMode = 1;
|
||||
|
||||
/* Update RealToday because of TestMode */
|
||||
RealToday = SystemDate(&CurYear, &CurMon, &CurDay);
|
||||
DSEToday = RealToday;
|
||||
FromDSE(DSEToday, &CurYear, &CurMon, &CurDay);
|
||||
|
||||
return;
|
||||
}
|
||||
if (!strcmp(arg, "version")) {
|
||||
printf("%s\n", VERSION);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
40
src/json.c
40
src/json.c
@@ -299,7 +299,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
if (flags & flag_string)
|
||||
{
|
||||
if (!b)
|
||||
{ sprintf (error, "Unexpected EOF in string (at %u:%u)", line_and_col);
|
||||
{ snprintf (error, sizeof(error), "Unexpected EOF in string (at %u:%u)", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
|
||||
(uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
|
||||
{
|
||||
sprintf (error, "Invalid character value `%c` (at %u:%u)", b, line_and_col);
|
||||
snprintf (error, sizeof(error), "Invalid character value `%c` (at %u:%u)", b, line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
|
||||
(uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
|
||||
{
|
||||
sprintf (error, "Invalid character value `%c` (at %u:%u)", b, line_and_col);
|
||||
snprintf (error, sizeof(error), "Invalid character value `%c` (at %u:%u)", b, line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
@@ -472,7 +472,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
if (flags & flag_block_comment)
|
||||
{
|
||||
if (!b)
|
||||
{ sprintf (error, "%u:%u: Unexpected EOF in block comment", line_and_col);
|
||||
{ snprintf (error, sizeof(error), "%u:%u: Unexpected EOF in block comment", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
@@ -488,12 +488,12 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
else if (b == '/')
|
||||
{
|
||||
if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object)
|
||||
{ sprintf (error, "%u:%u: Comment not allowed here", line_and_col);
|
||||
{ snprintf (error, sizeof(error), "%u:%u: Comment not allowed here", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
if (++ state.ptr == end)
|
||||
{ sprintf (error, "%u:%u: EOF unexpected", line_and_col);
|
||||
{ snprintf (error, sizeof(error), "%u:%u: EOF unexpected", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
@@ -508,7 +508,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
continue;
|
||||
|
||||
default:
|
||||
sprintf (error, "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b);
|
||||
snprintf (error, sizeof(error), "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b);
|
||||
goto e_failed;
|
||||
};
|
||||
}
|
||||
@@ -526,7 +526,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
|
||||
default:
|
||||
|
||||
sprintf (error, "%u:%u: Trailing garbage: `%c`",
|
||||
snprintf (error, sizeof(error), "%u:%u: Trailing garbage: `%c`",
|
||||
state.cur_line, state.cur_col, b);
|
||||
|
||||
goto e_failed;
|
||||
@@ -545,7 +545,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
|
||||
{ sprintf (error, "%u:%u: Unexpected ]", line_and_col);
|
||||
{ snprintf (error, sizeof(error), "%u:%u: Unexpected ]", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
@@ -561,7 +561,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (error, "%u:%u: Expected , before %c",
|
||||
snprintf (error, sizeof(error), "%u:%u: Expected , before %c",
|
||||
state.cur_line, state.cur_col, b);
|
||||
|
||||
goto e_failed;
|
||||
@@ -576,7 +576,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (error, "%u:%u: Expected : before %c",
|
||||
snprintf (error, sizeof(error), "%u:%u: Expected : before %c",
|
||||
state.cur_line, state.cur_col, b);
|
||||
|
||||
goto e_failed;
|
||||
@@ -702,7 +702,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ sprintf (error, "%u:%u: Unexpected %c when seeking value", line_and_col, b);
|
||||
{ snprintf (error, sizeof(error), "%u:%u: Unexpected %c when seeking value", line_and_col, b);
|
||||
goto e_failed;
|
||||
}
|
||||
};
|
||||
@@ -722,7 +722,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
case '"':
|
||||
|
||||
if (flags & flag_need_comma)
|
||||
{ sprintf (error, "%u:%u: Expected , before \"", line_and_col);
|
||||
{ snprintf (error, sizeof(error), "%u:%u: Expected , before \"", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
@@ -747,7 +747,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
sprintf (error, "%u:%u: Unexpected `%c` in object", line_and_col, b);
|
||||
snprintf (error, sizeof(error), "%u:%u: Unexpected `%c` in object", line_and_col, b);
|
||||
goto e_failed;
|
||||
};
|
||||
|
||||
@@ -765,7 +765,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
if (! (flags & flag_num_e))
|
||||
{
|
||||
if (flags & flag_num_zero)
|
||||
{ sprintf (error, "%u:%u: Unexpected `0` before `%c`", line_and_col, b);
|
||||
{ snprintf (error, sizeof(error), "%u:%u: Unexpected `0` before `%c`", line_and_col, b);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
@@ -814,7 +814,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
else if (b == '.' && top->type == json_integer)
|
||||
{
|
||||
if (!num_digits)
|
||||
{ sprintf (error, "%u:%u: Expected digit before `.`", line_and_col);
|
||||
{ snprintf (error, sizeof(error), "%u:%u: Expected digit before `.`", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
@@ -831,7 +831,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
if (top->type == json_double)
|
||||
{
|
||||
if (!num_digits)
|
||||
{ sprintf (error, "%u:%u: Expected digit after `.`", line_and_col);
|
||||
{ snprintf (error, sizeof(error), "%u:%u: Expected digit after `.`", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
@@ -857,7 +857,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
else
|
||||
{
|
||||
if (!num_digits)
|
||||
{ sprintf (error, "%u:%u: Expected digit after `e`", line_and_col);
|
||||
{ snprintf (error, sizeof(error), "%u:%u: Expected digit after `e`", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
@@ -942,7 +942,7 @@ json_value * json_parse_ex (json_settings * settings,
|
||||
|
||||
e_unknown_value:
|
||||
|
||||
sprintf (error, "%u:%u: Unknown value", line_and_col);
|
||||
snprintf (error, sizeof(error), "%u:%u: Unknown value", line_and_col);
|
||||
goto e_failed;
|
||||
|
||||
e_alloc_failure:
|
||||
@@ -952,7 +952,7 @@ e_alloc_failure:
|
||||
|
||||
e_overflow:
|
||||
|
||||
sprintf (error, "%u:%u: Too long (caught overflow)", line_and_col);
|
||||
snprintf (error, sizeof(error), "%u:%u: Too long (caught overflow)", line_and_col);
|
||||
goto e_failed;
|
||||
|
||||
e_failed:
|
||||
|
||||
100
src/main.c
100
src/main.c
@@ -145,6 +145,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
DBufInit(&(LastTrigger.tags));
|
||||
LastTrigger.infos = NULL;
|
||||
ClearLastTriggers();
|
||||
|
||||
atexit(exitfunc);
|
||||
@@ -630,7 +631,9 @@ int ParseTokenOrQuotedString(ParsePtr p, DynamicBuffer *dbuf)
|
||||
/***************************************************************/
|
||||
int ParseQuotedString(ParsePtr p, DynamicBuffer *dbuf)
|
||||
{
|
||||
int c, err;
|
||||
int c, err, c2;
|
||||
char hexbuf[3];
|
||||
|
||||
DBufFree(dbuf);
|
||||
c = ParseNonSpaceChar(p, &err, 0);
|
||||
if (err) return err;
|
||||
@@ -674,6 +677,34 @@ int ParseQuotedString(ParsePtr p, DynamicBuffer *dbuf)
|
||||
case 'v':
|
||||
err = DBufPutc(dbuf, '\v');
|
||||
break;
|
||||
case 'x':
|
||||
/* \x Followed by one or two hex digits */
|
||||
c2 = ParseChar(p, &err, 1);
|
||||
if (err) break;
|
||||
if (!isxdigit(c2)) {
|
||||
err = DBufPutc(dbuf, c);
|
||||
break;
|
||||
}
|
||||
hexbuf[0] = c2;
|
||||
hexbuf[1] = 0;
|
||||
c2 = ParseChar(p, &err, 0);
|
||||
if (err) break;
|
||||
c2 = ParseChar(p, &err, 1);
|
||||
if (err) break;
|
||||
if (isxdigit(c2)) {
|
||||
hexbuf[1] = c2;
|
||||
hexbuf[2] = 0;
|
||||
c2 = ParseChar(p, &err, 0);
|
||||
if (err) break;
|
||||
}
|
||||
c2 = (int) strtol(hexbuf, NULL, 16);
|
||||
if (!c2) {
|
||||
Eprint(tr("\\x00 is not a valid escape sequence"));
|
||||
err = E_PARSE_ERR;
|
||||
} else {
|
||||
err = DBufPutc(dbuf, c2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
err = DBufPutc(dbuf, c);
|
||||
}
|
||||
@@ -866,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);
|
||||
@@ -902,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, " ");
|
||||
}
|
||||
@@ -1010,6 +1056,11 @@ int SystemTime(int realtime)
|
||||
|
||||
if (!realtime && (SysTime != -1)) return SysTime;
|
||||
|
||||
if (TestMode) {
|
||||
/* Pretend it's 7:00PM in test mode */
|
||||
return 19 * 3600;
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
t = localtime(&now);
|
||||
return t->tm_hour * 3600L + t->tm_min * 60L +
|
||||
@@ -1043,6 +1094,14 @@ int SystemDate(int *y, int *m, int *d)
|
||||
time_t now;
|
||||
struct tm *t;
|
||||
|
||||
/* In test mode, always return 6 January 2025 */
|
||||
if (TestMode) {
|
||||
*y = 2025;
|
||||
*m = 0;
|
||||
*d = 6;
|
||||
return 12789; /* 2025-01-06 */
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
t = localtime(&now);
|
||||
|
||||
@@ -1073,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;
|
||||
@@ -1902,6 +1960,10 @@ void
|
||||
FreeTrig(Trigger *t)
|
||||
{
|
||||
DBufFree(&(t->tags));
|
||||
if (t->infos) {
|
||||
FreeTrigInfoChain(t->infos);
|
||||
}
|
||||
t->infos = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1927,8 +1989,7 @@ ClearLastTriggers(void)
|
||||
LastTrigger.warn[0] = 0;
|
||||
LastTrigger.omitfunc[0] = 0;
|
||||
LastTrigger.passthru[0] = 0;
|
||||
DBufFree(&(LastTrigger.tags));
|
||||
|
||||
FreeTrig(&LastTrigger);
|
||||
LastTimeTrig.ttime = NO_TIME;
|
||||
LastTimeTrig.delta = NO_DELTA;
|
||||
LastTimeTrig.rep = NO_REP;
|
||||
@@ -1948,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
|
||||
@@ -1966,7 +2036,6 @@ SaveLastTimeTrig(TimeTrig const *t)
|
||||
void
|
||||
System(char const *cmd, int is_queued)
|
||||
{
|
||||
int r;
|
||||
pid_t kid;
|
||||
int fd;
|
||||
int status;
|
||||
@@ -1999,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 *
|
||||
|
||||
403
src/moon.c
403
src/moon.c
@@ -546,3 +546,406 @@ 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 on either side of
|
||||
starting point */
|
||||
#define MR_WINDOW 48
|
||||
|
||||
#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) * 1440;
|
||||
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 ra[], double declination[], double 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) * 2 * PI / 360.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 in minutes after midnight of BASEYR
|
||||
starting from given DSE.
|
||||
Returns 0 if no moonrise could be computes */
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ int IsOmitted(int dse, int localomit, char const *omitfunc, int *omit)
|
||||
Value v;
|
||||
|
||||
FromDSE(dse, &y, &m, &d);
|
||||
sprintf(expr, "%s('%04d-%02d-%02d')",
|
||||
snprintf(expr, sizeof(expr), "%s('%04d-%02d-%02d')",
|
||||
omitfunc, y, m+1, d);
|
||||
s = expr;
|
||||
r = EvalExpr(&s, &v, NULL);
|
||||
@@ -388,6 +388,7 @@ int DoOmit(ParsePtr p)
|
||||
case T_RemType:
|
||||
case T_Priority:
|
||||
case T_Tag:
|
||||
case T_Info:
|
||||
case T_Duration:
|
||||
DBufFree(&buf);
|
||||
parsing = 0;
|
||||
@@ -415,7 +416,7 @@ int DoOmit(ParsePtr p)
|
||||
return E_2MANY_LOCALOMIT;
|
||||
}
|
||||
WeekdayOmits |= wd;
|
||||
if (tok.type == T_Tag || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
|
||||
if (tok.type == T_Tag || tok.type == T_Info || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -500,7 +501,7 @@ int DoOmit(ParsePtr p)
|
||||
}
|
||||
}
|
||||
|
||||
if (tok.type == T_Tag || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
|
||||
if (tok.type == T_Tag || tok.type == T_Info || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
|
||||
return OK;
|
||||
|
||||
}
|
||||
|
||||
17
src/protos.h
17
src/protos.h
@@ -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);
|
||||
@@ -273,6 +273,19 @@ int GetTranslatedStringTryingVariants(char const *orig, DynamicBuffer *out);
|
||||
char const *GetErr(int r);
|
||||
char const *tr(char const *s);
|
||||
void print_escaped_string(FILE *fp, char const *s);
|
||||
void print_escaped_string_helper(FILE *fp, char const *s, int esc_for_remind);
|
||||
void print_escaped_string_helper(FILE *fp, char const *s, int esc_for_remind, int json);
|
||||
void GenerateSysvarTranslationTemplates(void);
|
||||
void TranslationTemplate(char const *msg);
|
||||
TrigInfo *NewTrigInfo(char const *i);
|
||||
void FreeTrigInfo(TrigInfo *ti);
|
||||
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);
|
||||
|
||||
29
src/queue.c
29
src/queue.c
@@ -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;
|
||||
@@ -163,6 +164,7 @@ static void del_reminder(QueuedRem *qid)
|
||||
if (q == qid) {
|
||||
QueueHead = q->next;
|
||||
if (q->text) free((void *) q->text);
|
||||
FreeTrig(&(q->t));
|
||||
free(q);
|
||||
return;
|
||||
}
|
||||
@@ -171,6 +173,7 @@ static void del_reminder(QueuedRem *qid)
|
||||
if (q->next == qid) {
|
||||
q->next = q->next->next;
|
||||
if (next->text) free((void *) next->text);
|
||||
FreeTrig(&(next->t));
|
||||
free(next);
|
||||
return;
|
||||
}
|
||||
@@ -222,11 +225,16 @@ int QueueReminder(ParsePtr p, Trigger *trig,
|
||||
}
|
||||
|
||||
qelem->lineno = LineNo;
|
||||
qelem->lineno_start = LineNoStart;
|
||||
NumQueued++;
|
||||
qelem->typ = trig->typ;
|
||||
strcpy(qelem->passthru, trig->passthru);
|
||||
qelem->tt = *tim;
|
||||
qelem->t = *trig;
|
||||
|
||||
/* Take over infos */
|
||||
trig->infos = NULL;
|
||||
|
||||
DBufInit(&(qelem->t.tags));
|
||||
DBufPuts(&(qelem->t.tags), DBufValue(&(trig->tags)));
|
||||
if (SynthesizeTags) {
|
||||
@@ -460,10 +468,17 @@ void HandleQueuedReminders(void)
|
||||
if (IsServerMode() && q->typ != RUN_TYPE) {
|
||||
if (DaemonJSON) {
|
||||
printf("{\"response\":\"reminder\",");
|
||||
snprintf(qid, sizeof(qid), "%lx", (unsigned long) q);
|
||||
if (TestMode) {
|
||||
snprintf(qid, sizeof(qid), "42424242");
|
||||
} else {
|
||||
snprintf(qid, sizeof(qid), "%lx", (unsigned long) q);
|
||||
}
|
||||
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",
|
||||
@@ -486,6 +501,7 @@ void HandleQueuedReminders(void)
|
||||
DefaultColorB = q->blue;
|
||||
/* Make a COPY of q->t because TriggerReminder can change q->t.typ */
|
||||
Trigger tcopy = q->t;
|
||||
|
||||
if (DaemonJSON) {
|
||||
DynamicBuffer out;
|
||||
DBufInit(&out);
|
||||
@@ -698,7 +714,7 @@ static int CalculateNextTimeUsingSched(QueuedRem *q)
|
||||
to be a security hole! */
|
||||
while(1) {
|
||||
char exprBuf[VAR_NAME_LEN+32];
|
||||
sprintf(exprBuf, "%s(%d)", q->sched, q->ntrig);
|
||||
snprintf(exprBuf, sizeof(exprBuf), "%s(%d)", q->sched, q->ntrig);
|
||||
s = exprBuf;
|
||||
r = EvalExpr(&s, &v, NULL);
|
||||
if (r) {
|
||||
@@ -760,12 +776,19 @@ json_queue(QueuedRem const *q)
|
||||
printf("{");
|
||||
WriteJSONTrigger(&(q->t), 1, DSEToday);
|
||||
WriteJSONTimeTrigger(&(q->tt));
|
||||
snprintf(idbuf, sizeof(idbuf), "%lx", (unsigned long) q);
|
||||
if (TestMode) {
|
||||
snprintf(idbuf, sizeof(idbuf), "42424242");
|
||||
} else {
|
||||
snprintf(idbuf, sizeof(idbuf), "%lx", (unsigned long) q);
|
||||
}
|
||||
PrintJSONKeyPairString("qid", idbuf);
|
||||
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
@@ -1222,7 +1222,7 @@ int DoQueuedPs(void)
|
||||
if (moonsize < 0) {
|
||||
size = "DaySize 2 div";
|
||||
} else {
|
||||
sprintf(buffer, "%d", moonsize);
|
||||
snprintf(buffer, sizeof(buffer), "%d", moonsize);
|
||||
size = buffer;
|
||||
}
|
||||
|
||||
@@ -1235,7 +1235,7 @@ int DoQueuedPs(void)
|
||||
if (fontsize < 0) {
|
||||
fsize = "EntrySize";
|
||||
} else {
|
||||
sprintf(fbuffer, "%d", fontsize);
|
||||
snprintf(fbuffer, sizeof(fbuffer), "%d", fontsize);
|
||||
fsize = fbuffer;
|
||||
}
|
||||
printf("/EntryFont findfont %s scalefont setfont (",
|
||||
@@ -1273,7 +1273,7 @@ int DoQueuedPs(void)
|
||||
if (fontsize < 0) {
|
||||
fsize = "EntrySize";
|
||||
} else {
|
||||
sprintf(fbuffer, "%d", fontsize);
|
||||
snprintf(fbuffer, sizeof(fbuffer), "%d", fontsize);
|
||||
fsize = fbuffer;
|
||||
}
|
||||
printf("/EntryFont findfont %s scalefont setfont (",
|
||||
|
||||
@@ -183,7 +183,7 @@ static void IssueSortBanner(int dse)
|
||||
if (UserFuncExists("sortbanner") != 1) return;
|
||||
|
||||
FromDSE(dse, &y, &m, &d);
|
||||
sprintf(BanExpr, "sortbanner('%04d/%02d/%02d')", y, m+1, d);
|
||||
snprintf(BanExpr, sizeof(BanExpr), "sortbanner('%04d/%02d/%02d')", y, m+1, d);
|
||||
y = EvalExpr(&s, &v, NULL);
|
||||
if (y) return;
|
||||
if (DoCoerce(STR_TYPE, &v)) return;
|
||||
|
||||
@@ -71,6 +71,7 @@ Token TokArray[] = {
|
||||
{ "in", 2, T_In, 0 },
|
||||
{ "include", 3, T_Include, 0 },
|
||||
{ "includecmd", 10, T_IncludeCmd, 0 },
|
||||
{ "info", 4, T_Info, 0 },
|
||||
{ "january", 3, T_Month, 0 },
|
||||
{ "july", 3, T_Month, 6 },
|
||||
{ "june", 3, T_Month, 5 },
|
||||
|
||||
39
src/trans.c
39
src/trans.c
@@ -48,10 +48,10 @@ TranslationTemplate(char const *in)
|
||||
}
|
||||
|
||||
printf("TRANSLATE ");
|
||||
print_escaped_string_helper(stdout, in, 1);
|
||||
print_escaped_string_helper(stdout, in, 1, 0);
|
||||
if (FindTranslation(in)) {
|
||||
printf(" ");
|
||||
print_escaped_string_helper(stdout, tr(in), 1);
|
||||
print_escaped_string_helper(stdout, tr(in), 1, 0);
|
||||
printf("\n");
|
||||
} else {
|
||||
printf(" \"\"\n");
|
||||
@@ -66,7 +66,7 @@ GenerateTranslationTemplate(void)
|
||||
printf("# Translation table template\n\n");
|
||||
|
||||
printf("TRANSLATE \"LANGID\" ");
|
||||
print_escaped_string_helper(stdout, tr("LANGID"), 1);
|
||||
print_escaped_string_helper(stdout, tr("LANGID"), 1, 0);
|
||||
printf("\n\n");
|
||||
|
||||
printf("BANNER %s\n", DBufValue(&Banner));
|
||||
@@ -74,14 +74,14 @@ GenerateTranslationTemplate(void)
|
||||
printf("\n# Weekday Names\n");
|
||||
for (i=0; i<7; i++) {
|
||||
printf("SET $%s ", DayName[i]);
|
||||
print_escaped_string_helper(stdout, tr(DayName[i]), 1);
|
||||
print_escaped_string_helper(stdout, tr(DayName[i]), 1, 0);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("\n# Month Names\n");
|
||||
for (i=0; i<12; i++) {
|
||||
printf("SET $%s ", MonthName[i]);
|
||||
print_escaped_string_helper(stdout, tr(MonthName[i]), 1);
|
||||
print_escaped_string_helper(stdout, tr(MonthName[i]), 1, 0);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -178,11 +178,17 @@ ClearTranslationTable(void)
|
||||
void
|
||||
print_escaped_string(FILE *fp, char const *s)
|
||||
{
|
||||
print_escaped_string_helper(fp, s, 0);
|
||||
print_escaped_string_helper(fp, s, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
print_escaped_string_json(FILE *fp, char const *s)
|
||||
{
|
||||
print_escaped_string_helper(fp, s, 0, 1);
|
||||
}
|
||||
|
||||
void
|
||||
print_escaped_string_helper(FILE *fp, char const *s, int esc_for_remind) {
|
||||
print_escaped_string_helper(FILE *fp, char const *s, int esc_for_remind, int json) {
|
||||
putc('"', fp);
|
||||
while(*s) {
|
||||
switch(*s) {
|
||||
@@ -196,11 +202,20 @@ print_escaped_string_helper(FILE *fp, char const *s, int esc_for_remind) {
|
||||
case '"': putc('\\', fp); putc('"', fp); break;
|
||||
case '\\': putc('\\', fp); putc('\\', fp); break;
|
||||
default:
|
||||
if (esc_for_remind && *s == '[') {
|
||||
fprintf(fp, "[\"[\"]");
|
||||
if ((*s > 0 && *s < 32) || *s == 0x7f) {
|
||||
if (json) {
|
||||
fprintf(fp, "\\u%04x", (unsigned int) *s);
|
||||
} else {
|
||||
fprintf(fp, "\\x%02x", (unsigned int) *s);
|
||||
}
|
||||
} else {
|
||||
putc(*s, fp); break;
|
||||
if (esc_for_remind && *s == '[') {
|
||||
fprintf(fp, "[\"[\"]");
|
||||
} else {
|
||||
putc(*s, fp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
@@ -245,9 +260,9 @@ DumpTranslationTable(FILE *fp, int json)
|
||||
fprintf(fp, ",");
|
||||
}
|
||||
done=1;
|
||||
print_escaped_string(fp, item->orig);
|
||||
print_escaped_string_json(fp, item->orig);
|
||||
fprintf(fp, ":");
|
||||
print_escaped_string(fp, item->translated);
|
||||
print_escaped_string_json(fp, item->translated);
|
||||
}
|
||||
item = hash_table_next(&TranslationTable, item);
|
||||
}
|
||||
|
||||
171
src/trigger.c
171
src/trigger.c
@@ -12,8 +12,9 @@
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "protos.h"
|
||||
#include "globals.h"
|
||||
@@ -451,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),
|
||||
@@ -579,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;
|
||||
}
|
||||
@@ -602,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),
|
||||
@@ -629,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;
|
||||
@@ -654,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;
|
||||
}
|
||||
@@ -668,3 +669,151 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* NewTrigInfo */
|
||||
/* */
|
||||
/* Create a new TrigInfo object with the specified contents. */
|
||||
/* Returns NULL if memory allocation fails. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
TrigInfo *
|
||||
NewTrigInfo(char const *i)
|
||||
{
|
||||
TrigInfo *ti = malloc(sizeof(TrigInfo));
|
||||
|
||||
if (!ti) {
|
||||
return NULL;
|
||||
}
|
||||
ti->next = NULL;
|
||||
ti->info = StrDup(i);
|
||||
if (!ti->info) {
|
||||
free(ti);
|
||||
return NULL;
|
||||
}
|
||||
return ti;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* FreeTrigInfo */
|
||||
/* */
|
||||
/* Free a TrigInfo objects. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
void
|
||||
FreeTrigInfo(TrigInfo *ti)
|
||||
{
|
||||
if (ti->info) {
|
||||
free( (void *) ti->info);
|
||||
ti->info = NULL;
|
||||
}
|
||||
ti->next = NULL;
|
||||
free(ti);
|
||||
}
|
||||
|
||||
void
|
||||
FreeTrigInfoChain(TrigInfo *ti)
|
||||
{
|
||||
TrigInfo *next;
|
||||
|
||||
while(ti) {
|
||||
next = ti->next;
|
||||
FreeTrigInfo(ti);
|
||||
ti = next;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* AppendTrigInfo */
|
||||
/* */
|
||||
/* Append an info item to a trigger. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int
|
||||
AppendTrigInfo(Trigger *t, char const *info)
|
||||
{
|
||||
TrigInfo *ti;
|
||||
TrigInfo *last;
|
||||
|
||||
if (!TrigInfoIsValid(info)) {
|
||||
Eprint("%s", tr("Invalid INFO string: Must be of the form \"Header: Value\""));
|
||||
return E_PARSE_ERR;
|
||||
}
|
||||
|
||||
ti = NewTrigInfo(info);
|
||||
last = t->infos;
|
||||
if (!ti) {
|
||||
return E_NO_MEM;
|
||||
}
|
||||
if (!last) {
|
||||
t->infos = ti;
|
||||
return OK;
|
||||
}
|
||||
if (TrigInfoHeadersAreTheSame(info, last->info)) {
|
||||
Eprint("%s", tr("Duplicate INFO headers are not permitted"));
|
||||
FreeTrigInfo(ti);
|
||||
return E_PARSE_ERR;
|
||||
}
|
||||
while (last->next) {
|
||||
last = last->next;
|
||||
if (TrigInfoHeadersAreTheSame(info, last->info)) {
|
||||
Eprint("%s", tr("Duplicate INFO headers are not permitted"));
|
||||
FreeTrigInfo(ti);
|
||||
return E_PARSE_ERR;
|
||||
}
|
||||
}
|
||||
last->next = ti;
|
||||
return OK;
|
||||
}
|
||||
|
||||
int
|
||||
TrigInfoHeadersAreTheSame(char const *i1, char const *i2)
|
||||
{
|
||||
char const *c1 = strchr(i1, ':');
|
||||
char const *c2 = strchr(i2, ':');
|
||||
if (!c1 || !c2) return 1;
|
||||
if (c1 - i1 != c2 - i2) return 0;
|
||||
if (!strncasecmp(i1, i2, (c1 - i1))) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
TrigInfoIsValid(char const *info)
|
||||
{
|
||||
char const *t;
|
||||
char const *s = strchr(info, ':');
|
||||
if (!s) return 0;
|
||||
if (s == info) return 0;
|
||||
|
||||
t = info;
|
||||
while (t < s) {
|
||||
if (isspace(*t) || iscntrl(*t)) return 0;
|
||||
t++;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
13
src/types.h
13
src/types.h
@@ -107,6 +107,11 @@ typedef struct var {
|
||||
Value v;
|
||||
} Var;
|
||||
|
||||
typedef struct triginfo {
|
||||
struct triginfo *next;
|
||||
char const *info;
|
||||
} TrigInfo;
|
||||
|
||||
/* A trigger */
|
||||
typedef struct {
|
||||
int expired;
|
||||
@@ -138,6 +143,7 @@ typedef struct {
|
||||
char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */
|
||||
DynamicBuffer tags;
|
||||
char passthru[PASSTHRU_LEN+1];
|
||||
TrigInfo *infos;
|
||||
} Trigger;
|
||||
|
||||
/* A time trigger */
|
||||
@@ -217,9 +223,9 @@ enum TokTypes
|
||||
T_Date, T_DateTime, T_Day, T_Debug, T_Delta, T_Dumpvars, T_Duration,
|
||||
T_Else, T_Empty, T_EndIf, T_ErrMsg, T_Exit, T_Expr,
|
||||
T_Flush, T_Frename, T_Fset, T_Funset, T_If, T_IfTrig, T_In,
|
||||
T_Include, T_IncludeCmd, T_IncludeR, T_IncludeSys, T_LastBack, T_LongTime,
|
||||
T_MaybeUncomputable, T_Month, T_NoQueue, T_Number, T_Omit, T_OmitFunc,
|
||||
T_Once, T_Ordinal, T_Pop, T_Preserve, T_Priority, T_Push,T_Rem,
|
||||
T_Include, T_IncludeCmd, T_IncludeR, T_IncludeSys, T_Info, T_LastBack,
|
||||
T_LongTime, T_MaybeUncomputable, T_Month, T_NoQueue, T_Number, T_Omit,
|
||||
T_OmitFunc, T_Once, T_Ordinal, T_Pop, T_Preserve, T_Priority, T_Push,T_Rem,
|
||||
T_RemType, T_Rep, T_Scanfrom, T_Sched, T_Set, T_Skip, T_Tag, T_Through,
|
||||
T_Time, T_Translate, T_UnSet, T_Until, T_Warn, T_WkDay, T_Year
|
||||
};
|
||||
@@ -302,5 +308,6 @@ typedef struct udf_struct {
|
||||
int nargs;
|
||||
char const *filename;
|
||||
int lineno;
|
||||
int lineno_start;
|
||||
int recurse_flag;
|
||||
} UserFunc;
|
||||
|
||||
@@ -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);
|
||||
|
||||
18
src/utils.c
18
src/utils.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1268,13 +1268,13 @@ void GenerateSysvarTranslationTemplates(void)
|
||||
continue;
|
||||
}
|
||||
printf("SET $%s ", SysVarArr[i].name);
|
||||
print_escaped_string_helper(stdout, tr(msg), 1);
|
||||
print_escaped_string_helper(stdout, tr(msg), 1, 0);
|
||||
printf("\n");
|
||||
} else if (!strcmp(SysVarArr[i].name, "Hplu") ||
|
||||
!strcmp(SysVarArr[i].name, "Mplu")) {
|
||||
msg = * (char const **) SysVarArr[i].value;
|
||||
printf("SET $%s ", SysVarArr[i].name);
|
||||
print_escaped_string_helper(stdout, tr(msg), 1);
|
||||
print_escaped_string_helper(stdout, tr(msg), 1, 0);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
FSET msgprefix(x) "Priority: " + x + "; Filename: " + filename() + ": "
|
||||
|
||||
REM at 23:56 MSG foo
|
||||
REM PRIORITY 42 at 23:57 MSG bar
|
||||
REM PRIORITY 999 at 23:58 MSG quux
|
||||
REM PRIORITY 42 at 23:57 INFO "Info: yuppers" MSG bar
|
||||
REM PRIORITY 999 at 23:58 INFO "Info2: Nope" INFO "Info3: heh" MSG quux
|
||||
DO queue2.rem
|
||||
|
||||
104
tests/test-rem
104
tests/test-rem
@@ -32,18 +32,10 @@ fi
|
||||
# ../src/remind. This trick was suggested by Jochen Sprickerhof
|
||||
alias remind="echo You should be using ../src/remind explicitly in test-rem >&2; exit 1"
|
||||
|
||||
|
||||
# Set a known timezone so moon phases show up in predictable places
|
||||
TZ=UTC
|
||||
export TZ
|
||||
|
||||
DO_QUEUE_TESTS=1
|
||||
RESULT=`(echo 'BANNER %'; echo 'IF now() > 23:55'; echo 'MSG late%'; echo 'ENDIF') | ../src/remind -h -`
|
||||
|
||||
if test "$RESULT" = "late" ; then
|
||||
DO_QUEUE_TESTS=0
|
||||
fi
|
||||
|
||||
# If we're already in a utf-8 locale, do
|
||||
# nothing; otherwise, set LC_ALL
|
||||
OK=0
|
||||
@@ -189,11 +181,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
|
||||
@@ -474,22 +468,9 @@ rm -rf include_dir/ww
|
||||
../src/remind --version >> ../tests/test.out 2>&1
|
||||
|
||||
# Test queueing. Because eventstart depends on the actual system
|
||||
# date, we have to convert it to some constant (in this case,
|
||||
# VOLATILE) so that tests are not dependent on the system date.
|
||||
if test "$DO_QUEUE_TESTS" = 1 ; then
|
||||
echo JSONQUEUE | ../src/remind -z0 ../tests/queue1.rem 2>&1 | sed -e 's/"eventstart":"................"/"eventstart":"VOLATILE"/g' | sed -e 's/"qid":"[0-9a-f]*",//g' >> ../tests/test.out 2>&1
|
||||
echo QUEUE | ../src/remind -zj ../tests/queue1.rem 2>&1 | sed -e 's/"eventstart":"................"/"eventstart":"VOLATILE"/g' | sed -e 's/"qid":"[0-9a-f]*",//g' >> ../tests/test.out 2>&1
|
||||
else
|
||||
echo "*** Skipping queueing tests between 23:55 and 00:00 UTC"
|
||||
echo "*** If you want to run these tests, wait until 00:00 UTC"
|
||||
# Fake the output we expect from above
|
||||
cat >> ../tests/test.out <<'EOF'
|
||||
NOTE JSONQUEUE
|
||||
[{"priority":2,"eventstart":"VOLATILE","time":"23:59","nexttime":"23:59","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue2.rem","lineno":1,"type":"MSG_TYPE","body":"XXXX"},{"priority":999,"eventstart":"VOLATILE","time":"23:58","nexttime":"23:58","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":5,"type":"MSG_TYPE","body":"quux"},{"priority":42,"eventstart":"VOLATILE","time":"23:57","nexttime":"23:57","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":4,"type":"MSG_TYPE","body":"bar"},{"priority":5000,"eventstart":"VOLATILE","time":"23:56","nexttime":"23:56","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":3,"type":"MSG_TYPE","body":"foo"}]
|
||||
NOTE ENDJSONQUEUE
|
||||
{"response":"queue","queue":[{"priority":2,"eventstart":"VOLATILE","time":"23:59","nexttime":"23:59","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue2.rem","lineno":1,"type":"MSG_TYPE","body":"XXXX"},{"priority":999,"eventstart":"VOLATILE","time":"23:58","nexttime":"23:58","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":5,"type":"MSG_TYPE","body":"quux"},{"priority":42,"eventstart":"VOLATILE","time":"23:57","nexttime":"23:57","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":4,"type":"MSG_TYPE","body":"bar"},{"priority":5000,"eventstart":"VOLATILE","time":"23:56","nexttime":"23:56","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":3,"type":"MSG_TYPE","body":"foo"}],"command":"QUEUE"}
|
||||
EOF
|
||||
fi
|
||||
# date, we use the --test flag to fake the date and time.
|
||||
echo JSONQUEUE | ../src/remind --test -z0 ../tests/queue1.rem >> ../tests/test.out 2>&1
|
||||
echo QUEUE | ../src/remind --test -zj ../tests/queue1.rem >> ../tests/test.out 2>&1
|
||||
|
||||
# Test for leap year bug that was fixed
|
||||
../src/remind -dte - 28 Feb 2024 <<'EOF' >> ../tests/test.out 2>&1
|
||||
@@ -656,6 +637,75 @@ EOF
|
||||
TRANSLATE GENERATE
|
||||
EOF
|
||||
|
||||
# Make sure stupidly-long translations of "am" and "pm" can't cause a
|
||||
# segmentation fault
|
||||
../src/remind -c - 1 Feb 2024 <<'EOF' >> ../tests/test.out 2>&1
|
||||
TRANS "am" "alsdkjalksdj alksjd alksdj alksjd laksjd laksjd laksjd laksjd laksjd laksjd laksjd laksjd lkasjd laksjd laksjd lkajs dlkajs dlkasj dlkasjd lkajsd lkajs dlkasjd lkasj dlkajsd lkasjd lkasjd laksjd laksjd laksjd alskdj alskdj alksdj alksdj alskdj alksdj aslkdj"
|
||||
TRANS "pm" "oiwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwjwwwwwwwwwwwwwwwjwpqoejkpqwojepqowjepqojwepqowjepqowjepqowjepqowjepqowjepqowjepqojwepqowjepqowjepqowjepqowjepqowjeqpweoj"
|
||||
|
||||
REM WED AT 11:00 MSG wookie
|
||||
REM WED AT 13:00 MSG blah
|
||||
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 [triginfo("location")] %<summary> %<nonexist> [triginfo("cabbage")]
|
||||
EOF
|
||||
|
||||
# Invalid info strings
|
||||
../src/remind - 1 Feb 2024 <<'EOF' >> ../tests/test.out 2>&1
|
||||
REM Thu INFO "Invalid" MSG wookie
|
||||
REM Fri INFO ": foo" MSG blat
|
||||
REM Sun INFO "foo bar baz : blork" MSG uua
|
||||
|
||||
# Duplicate info string
|
||||
REM Sat INFO "Location: here" INFO "location: there" MSG blort
|
||||
EOF
|
||||
|
||||
# Test parsing of quoted strings and the "escape" function
|
||||
../src/remind - 1 Feb 2024 <<'EOF' >> ../tests/test.out 2>&1
|
||||
BANNER %
|
||||
SET $AddBlankLines 0
|
||||
TRANSLATE "foo" "test: \\\" \a\b\f\\n\r\t\v\x3\x1b haha"
|
||||
REM msg foo translation = %(foo)
|
||||
FLUSH
|
||||
set a "vartest: \\\" \a\b\f\\n\r\t\v\x3\x1b haha"
|
||||
REM msg a = [a]
|
||||
FLUSH
|
||||
dump a
|
||||
set b escape(a)
|
||||
REM msg b = [b]
|
||||
set b escape(a,1)
|
||||
REM msg b = [b]
|
||||
FLUSH
|
||||
dump b
|
||||
FLUSH
|
||||
set a "\x"
|
||||
dump a
|
||||
FLUSH
|
||||
set a "\xPOO"
|
||||
dump a
|
||||
FLUSH
|
||||
set a "\x0"
|
||||
set a "\x00"
|
||||
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"
|
||||
TRANSLATE DUMP
|
||||
EOF
|
||||
|
||||
../src/remind -ppp - 1 Feb 2024 <<EOF >> ../tests/test.out 2>&1
|
||||
TRANSLATE "\x03" "BREAK"
|
||||
EOF
|
||||
# Languages
|
||||
for i in ../include/lang/??.rem ; do
|
||||
../src/remind -r -q "-ii=\"$i\"" ../tests/tstlang.rem 1 Feb 2024 13:34 >> ../tests/test.out 2>&1
|
||||
|
||||
351
tests/test.cmp
351
tests/test.cmp
@@ -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.02.03"
|
||||
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.02.03"
|
||||
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.02.03"
|
||||
"05.02.03" > "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
|
||||
@@ -22389,44 +22389,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,11 +23200,17 @@ 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.02.03
|
||||
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
|
||||
NOTE JSONQUEUE
|
||||
[{"priority":2,"eventstart":"VOLATILE","time":"23:59","nexttime":"23:59","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue2.rem","lineno":1,"type":"MSG_TYPE","body":"XXXX"},{"priority":999,"eventstart":"VOLATILE","time":"23:58","nexttime":"23:58","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":5,"type":"MSG_TYPE","body":"quux"},{"priority":42,"eventstart":"VOLATILE","time":"23:57","nexttime":"23:57","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":4,"type":"MSG_TYPE","body":"bar"},{"priority":5000,"eventstart":"VOLATILE","time":"23:56","nexttime":"23:56","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":3,"type":"MSG_TYPE","body":"foo"}]
|
||||
[{"priority":2,"eventstart":"2025-01-06T23:59","time":"23:59","nexttime":"23:59","tdelta":0,"trep":0,"qid":"42424242","rundisabled":0,"ntrig":1,"filename":"../tests/queue2.rem","lineno":1,"type":"MSG_TYPE","body":"XXXX"},{"priority":999,"eventstart":"2025-01-06T23:58","info":{"info2":"Nope","info3":"heh"},"time":"23:58","nexttime":"23:58","tdelta":0,"trep":0,"qid":"42424242","rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":5,"type":"MSG_TYPE","body":"quux"},{"priority":42,"eventstart":"2025-01-06T23:57","info":{"info":"yuppers"},"time":"23:57","nexttime":"23:57","tdelta":0,"trep":0,"qid":"42424242","rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":4,"type":"MSG_TYPE","body":"bar"},{"priority":5000,"eventstart":"2025-01-06T23:56","time":"23:56","nexttime":"23:56","tdelta":0,"trep":0,"qid":"42424242","rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":3,"type":"MSG_TYPE","body":"foo"}]
|
||||
NOTE ENDJSONQUEUE
|
||||
{"response":"queue","queue":[{"priority":2,"eventstart":"VOLATILE","time":"23:59","nexttime":"23:59","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue2.rem","lineno":1,"type":"MSG_TYPE","body":"XXXX"},{"priority":999,"eventstart":"VOLATILE","time":"23:58","nexttime":"23:58","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":5,"type":"MSG_TYPE","body":"quux"},{"priority":42,"eventstart":"VOLATILE","time":"23:57","nexttime":"23:57","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":4,"type":"MSG_TYPE","body":"bar"},{"priority":5000,"eventstart":"VOLATILE","time":"23:56","nexttime":"23:56","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":3,"type":"MSG_TYPE","body":"foo"}],"command":"QUEUE"}
|
||||
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
|
||||
{"response":"queue","queue":[{"priority":2,"eventstart":"2025-01-06T23:59","time":"23:59","nexttime":"23:59","tdelta":0,"trep":0,"qid":"42424242","rundisabled":0,"ntrig":1,"filename":"../tests/queue2.rem","lineno":1,"type":"MSG_TYPE","body":"XXXX"},{"priority":999,"eventstart":"2025-01-06T23:58","info":{"info2":"Nope","info3":"heh"},"time":"23:58","nexttime":"23:58","tdelta":0,"trep":0,"qid":"42424242","rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":5,"type":"MSG_TYPE","body":"quux"},{"priority":42,"eventstart":"2025-01-06T23:57","info":{"info":"yuppers"},"time":"23:57","nexttime":"23:57","tdelta":0,"trep":0,"qid":"42424242","rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":4,"type":"MSG_TYPE","body":"bar"},{"priority":5000,"eventstart":"2025-01-06T23:56","time":"23:56","nexttime":"23:56","tdelta":0,"trep":0,"qid":"42424242","rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":3,"type":"MSG_TYPE","body":"foo"}],"command":"QUEUE"}
|
||||
BANNER %
|
||||
REM 29 MSG One
|
||||
-(2): Trig = Thursday, 29 February, 2024
|
||||
@@ -23975,6 +23981,7 @@ in
|
||||
inc
|
||||
include
|
||||
includecmd
|
||||
info
|
||||
last
|
||||
lastday
|
||||
lastworkday
|
||||
@@ -24084,6 +24091,7 @@ defined
|
||||
dosubst
|
||||
dusk
|
||||
easterdate
|
||||
escape
|
||||
evaltrig
|
||||
filedate
|
||||
filedatetime
|
||||
@@ -24115,6 +24123,10 @@ monnum
|
||||
moondate
|
||||
moondatetime
|
||||
moonphase
|
||||
moonrise
|
||||
moonrisedir
|
||||
moonset
|
||||
moonsetdir
|
||||
moontime
|
||||
multitrig
|
||||
ndawn
|
||||
@@ -24156,6 +24168,7 @@ trigeventduration
|
||||
trigeventstart
|
||||
trigfrom
|
||||
trigger
|
||||
triginfo
|
||||
trigpriority
|
||||
trigrep
|
||||
trigscanfrom
|
||||
@@ -24482,11 +24495,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" ""
|
||||
@@ -24496,13 +24509,15 @@ TRANSLATE "Cannot open `%s' for writing: %s" ""
|
||||
TRANSLATE "Cannot stat %s - not running as daemon!" ""
|
||||
TRANSLATE "Cannot use AT clause in multitrig() function" ""
|
||||
TRANSLATE "Do not use ["["]] around expression in SET command" ""
|
||||
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\"" ""
|
||||
TRANSLATE "Invalid translation: Both original and translated must have the same printf-style formatting sequences in the same order." ""
|
||||
TRANSLATE "Missing REM type; assuming MSG" ""
|
||||
TRANSLATE "No Adar A in %d" ""
|
||||
@@ -24531,15 +24546,181 @@ 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." ""
|
||||
TRANSLATE "psshade() is deprecated; use SPECIAL SHADE instead." ""
|
||||
TRANSLATE "remaining call frames omitted" ""
|
||||
+----------------------------------------------------------------------------+
|
||||
| February 2024 |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
| Sunday | Monday | Tuesday |Wednesday | Thursday | Friday | Saturday |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
| | | | |1 |2 |3 |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
|4 |5 |6 |7 |8 |9 |10 |
|
||||
| | | | | | | |
|
||||
| | | |11:00alsdk| | | |
|
||||
| | | |jalksdj | | | |
|
||||
| | | |alksjd | | | |
|
||||
| | | |alksdj | | | |
|
||||
| | | |alksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd la | | | |
|
||||
| | | |wookie | | | |
|
||||
| | | | | | | |
|
||||
| | | |1:00oiwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wjwwwwwwww| | | |
|
||||
| | | |wwwwwwwjwp| | | |
|
||||
| | | |qoejkpqw | | | |
|
||||
| | | |blah | | | |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
|11 |12 |13 |14 |15 |16 |17 |
|
||||
| | | | | | | |
|
||||
| | | |11:00alsdk| | | |
|
||||
| | | |jalksdj | | | |
|
||||
| | | |alksjd | | | |
|
||||
| | | |alksdj | | | |
|
||||
| | | |alksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd la | | | |
|
||||
| | | |wookie | | | |
|
||||
| | | | | | | |
|
||||
| | | |1:00oiwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wjwwwwwwww| | | |
|
||||
| | | |wwwwwwwjwp| | | |
|
||||
| | | |qoejkpqw | | | |
|
||||
| | | |blah | | | |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
|18 |19 |20 |21 |22 |23 |24 |
|
||||
| | | | | | | |
|
||||
| | | |11:00alsdk| | | |
|
||||
| | | |jalksdj | | | |
|
||||
| | | |alksjd | | | |
|
||||
| | | |alksdj | | | |
|
||||
| | | |alksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd la | | | |
|
||||
| | | |wookie | | | |
|
||||
| | | | | | | |
|
||||
| | | |1:00oiwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wjwwwwwwww| | | |
|
||||
| | | |wwwwwwwjwp| | | |
|
||||
| | | |qoejkpqw | | | |
|
||||
| | | |blah | | | |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
|25 |26 |27 |28 |29 | | |
|
||||
| | | | | | | |
|
||||
| | | |11:00alsdk| | | |
|
||||
| | | |jalksdj | | | |
|
||||
| | | |alksjd | | | |
|
||||
| | | |alksdj | | | |
|
||||
| | | |alksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd | | | |
|
||||
| | | |laksjd la | | | |
|
||||
| | | |wookie | | | |
|
||||
| | | | | | | |
|
||||
| | | |1:00oiwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wwwwwwwwww| | | |
|
||||
| | | |wjwwwwwwww| | | |
|
||||
| | | |wwwwwwwjwp| | | |
|
||||
| | | |qoejkpqw | | | |
|
||||
| | | |blah | | | |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
# translations
|
||||
{"LANGID":"en"}
|
||||
# rem2ps2 begin
|
||||
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,"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"
|
||||
-stdin-(3): Invalid INFO string: Must be of the form "Header: Value"
|
||||
-stdin-(6): Duplicate INFO headers are not permitted
|
||||
No reminders.
|
||||
foo translation = test: \" \n
haha
|
||||
a = vartest: \" \n
haha
|
||||
Variable Value
|
||||
|
||||
a "vartest: \\\" \a\b\f\\n\r\t\v\x03\x1b haha"
|
||||
b = vartest: \\\" \a\b\f\\n\r\t\v\x03\x1b haha
|
||||
b = "vartest: \\\" \a\b\f\\n\r\t\v\x03\x1b haha"
|
||||
Variable Value
|
||||
|
||||
b "\"vartest: \\\\\\\" \\a\\b\\f\\\\n\\r\\t\\v\\x03\\x1b h"...
|
||||
Variable Value
|
||||
|
||||
a "x"
|
||||
Variable Value
|
||||
|
||||
a "xPOO"
|
||||
-stdin-(23): \x00 is not a valid escape sequence
|
||||
-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"
|
||||
No reminders.
|
||||
[
|
||||
{
|
||||
"translations":{"LANGID":"en","\u0003":"BREAK"},"caltype":"monthly","monthname":"February","year":2024,"daysinmonth":29,"firstwkday":4,"mondayfirst":0,"daynames":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"prevmonthname":"January","daysinprevmonth":31,"prevmonthyear":2024,"nextmonthname":"March","daysinnextmonth":31,"nextmonthyear":2024,"entries":[
|
||||
]
|
||||
}
|
||||
]
|
||||
Agenda pel dijous, 1 de febrer de 2024:
|
||||
|
||||
Language: ca
|
||||
@@ -24956,7 +25137,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"
|
||||
@@ -25858,7 +26039,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"
|
||||
@@ -26760,7 +26941,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"
|
||||
@@ -27662,7 +27843,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"
|
||||
@@ -28564,7 +28745,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"
|
||||
@@ -29466,7 +29647,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"
|
||||
@@ -30368,7 +30549,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"
|
||||
@@ -31270,7 +31451,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"
|
||||
@@ -32172,7 +32353,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"
|
||||
@@ -33074,7 +33255,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"
|
||||
@@ -33976,7 +34157,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"
|
||||
@@ -34878,7 +35059,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"
|
||||
@@ -35780,7 +35961,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"
|
||||
@@ -36682,7 +36863,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"
|
||||
@@ -37584,7 +37765,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"
|
||||
|
||||
Reference in New Issue
Block a user