mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-19 07:48:40 +02:00
Compare commits
180 Commits
4e7cfc20ce
...
05.03.05
| Author | SHA1 | Date | |
|---|---|---|---|
| 79f45169c8 | |||
| b9f09b9a2d | |||
| f53a174d65 | |||
| ed15b7deb5 | |||
| caf5f81eb0 | |||
| d48910eca9 | |||
| c004944a59 | |||
| f2d1a21a4e | |||
| 81a5241097 | |||
| eced4de4a2 | |||
| 2c8fa39af0 | |||
| 6ac5e96260 | |||
| deda94a69e | |||
| 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 | |||
| d650b8564c | |||
| 4f2e4030eb | |||
| 447bda5c91 | |||
| 4f351c089e | |||
| 6b31778973 | |||
| dcf8b46beb | |||
| 0f582ccb60 | |||
| 8d0743dd3e | |||
| 436526c27d | |||
| 5f3f3b410f | |||
| 4f79b0d42a | |||
| c96f9f21ed | |||
| dc192f2a69 | |||
| ac3dd1ec7c | |||
| b5717828f0 | |||
| c0d73fb9d1 | |||
| 3a2ac067b0 | |||
| 1d467ab9ed | |||
| c2ec4e9d29 | |||
| 96c11e89eb | |||
| a35920f28e | |||
| 17ccf5d2b4 | |||
| 788a09b2cd | |||
| 9f0e23a307 | |||
| 542620c188 | |||
| 50419bd83a | |||
| 2b7c582392 | |||
| 812a2af64b | |||
| 17d7abd4a4 | |||
| 098e98c59e | |||
| c5e0dbf2e5 | |||
| 18c8bc719f | |||
| 195ed15167 | |||
| 51677cd7b5 | |||
| aef5b353cd | |||
| 8a99c29533 | |||
| 0bf2b0772a | |||
| a033a48acd | |||
| 0feb81c8cc | |||
| 1850607542 | |||
| 213138a7b7 | |||
| 562cec3dc8 | |||
| 18b57d26b4 | |||
| c80d72f623 | |||
| 2739a41651 | |||
| 5a56f4c61b | |||
| 77080ff600 | |||
| c4aa21ff51 | |||
| 34c513ba3b | |||
| 35c16a060a | |||
| 69dedc577f | |||
| a7d8f3c887 | |||
| 800a4b15b2 | |||
| 3e981fd8be | |||
| 7c530d3068 | |||
| 58f9cf641b | |||
| 53906035fe | |||
| 4804325863 | |||
| 5f5e7054f4 | |||
| 078dba1e98 | |||
| 8ebec9584c | |||
| 2504b39be2 | |||
| e394f402f8 | |||
| 5a2914f6c7 | |||
| a19b009f7c | |||
| 6373ae8ca5 | |||
| b8c4786b33 |
@@ -1,2 +0,0 @@
|
|||||||
|
|
||||||
liberapay: dskoll
|
|
||||||
@@ -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
|
|
||||||
@@ -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 .
|
|
||||||
+1
-1
@@ -23,7 +23,6 @@ rem2pdf/Makefile.old
|
|||||||
rem2pdf/Makefile.top
|
rem2pdf/Makefile.top
|
||||||
rem2pdf/bin/rem2pdf
|
rem2pdf/bin/rem2pdf
|
||||||
scripts/tkremind
|
scripts/tkremind
|
||||||
set-irc-topic
|
|
||||||
src/*.tar.gz*
|
src/*.tar.gz*
|
||||||
src/Makefile
|
src/Makefile
|
||||||
src/config.h
|
src/config.h
|
||||||
@@ -35,3 +34,4 @@ tests/test.out
|
|||||||
www/Makefile
|
www/Makefile
|
||||||
gmon.out
|
gmon.out
|
||||||
tests/once.timestamp
|
tests/once.timestamp
|
||||||
|
src/xlat.c
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ THE REMIND COPYRIGHT
|
|||||||
1. REMIND refers to the entire set of files and documentation in the
|
1. REMIND refers to the entire set of files and documentation in the
|
||||||
REMIND package.
|
REMIND package.
|
||||||
|
|
||||||
2. REMIND is Copyright 1992-2024 Dianne Skoll, except where noted in
|
2. REMIND is Copyright (C) 1992-2025 Dianne Skoll, except where noted in
|
||||||
individual files.
|
individual files.
|
||||||
|
|
||||||
3. DISTRIBUTION AND USE
|
3. DISTRIBUTION AND USE
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ install:
|
|||||||
@$(MAKE) -C rem2html install
|
@$(MAKE) -C rem2html install
|
||||||
@$(MAKE) -C rem2pdf -f Makefile.top install INSTALL_BASE=$(INSTALL_BASE)
|
@$(MAKE) -C rem2pdf -f Makefile.top install INSTALL_BASE=$(INSTALL_BASE)
|
||||||
clean:
|
clean:
|
||||||
find . -name '*~' -exec rm {} \;
|
-find . -name '*~' -exec rm {} \;
|
||||||
-rm man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1 scripts/tkremind
|
|
||||||
-$(MAKE) -C src clean
|
-$(MAKE) -C src clean
|
||||||
-$(MAKE) -C rem2pdf clean
|
-$(MAKE) -C rem2pdf clean
|
||||||
|
|
||||||
@@ -44,7 +43,9 @@ test:
|
|||||||
@$(MAKE) -C src -s test
|
@$(MAKE) -C src -s test
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f config.cache config.log config.status src/Makefile src/config.h tests/test.out www/Makefile rem2pdf/Makefile.top rem2pdf/Makefile.old rem2pdf/Makefile rem2pdf/Makefile.PL rem2pdf/bin/rem2pdf rem2html/rem2html
|
-rm -f config.cache config.log config.status src/Makefile src/version.h src/config.h tests/test.out www/Makefile rem2pdf/Makefile.top rem2pdf/Makefile.old rem2pdf/Makefile rem2pdf/Makefile.PL rem2pdf/bin/rem2pdf rem2html/rem2html
|
||||||
|
-rm -f man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1 scripts/tkremind
|
||||||
|
-rm -rf autom4te.cache rem2html/Makefile rem2html/rem2html.1
|
||||||
|
|
||||||
src/Makefile: src/Makefile.in
|
src/Makefile: src/Makefile.in
|
||||||
./configure
|
./configure
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
REMIND
|
|
||||||
|
|
||||||
Remind is a full-featured calendar/alarm program. Copying policy is
|
|
||||||
in the file "COPYRIGHT" in this directory.
|
|
||||||
|
|
||||||
Installation notes for various operating systems are in "docs". See
|
|
||||||
the appropriate README file for installation on your system.
|
|
||||||
|
|
||||||
Manual pages are in "man".
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Quick UNIX installation instructions for the very impatient:
|
|
||||||
|
|
||||||
If you have Tcl/Tk (wish 4.1 or higher) installed and are running X Windows:
|
|
||||||
--------------------------------------------------------------
|
|
||||||
|
|
||||||
1) Type: wish ./build.tk from this directory. Fill in the various
|
|
||||||
options and hit "Build Remind"
|
|
||||||
|
|
||||||
2) Type: "make install" -- you may need to be root to do this.
|
|
||||||
|
|
||||||
If you do NOT have Tcl/Tk or are NOT running X Windows:
|
|
||||||
-------------------------------------------------------
|
|
||||||
|
|
||||||
1) Edit the file "src/custom.h" according to your preferences.
|
|
||||||
|
|
||||||
2) Edit the file "src/lang.h" to choose a language.
|
|
||||||
|
|
||||||
3) Type: "./configure" (You can supply options; type "./configure --help"
|
|
||||||
for details.)
|
|
||||||
|
|
||||||
4) Type: "make"
|
|
||||||
|
|
||||||
5) Type: "make install" -- you may need to be root to do this.
|
|
||||||
|
|
||||||
PREREQUISITES:
|
|
||||||
--------------
|
|
||||||
|
|
||||||
Remind and rem2ps have no prerequisites beyond the standard C library and
|
|
||||||
the standard math library.
|
|
||||||
|
|
||||||
Rem2HTML requires the JSON::MaybeXS Perl module.
|
|
||||||
Rem2PDF requires the JSON::MaybeXS, Pango and Cairo Perl modules.
|
|
||||||
|
|
||||||
- On Debian-like systems, these prerequisites may be installed with:
|
|
||||||
|
|
||||||
apt install libjson-maybexs-perl libpango-perl libcairo-perl
|
|
||||||
|
|
||||||
- On RPM-based systems, you need perl-Pango, perl-Cairo and perl-JSON-MaybeXS
|
|
||||||
|
|
||||||
- On Gentoo, you need dev-perl/Pango, dev-perl/Cairo and dev-perl/JSON-MaybeXS.
|
|
||||||
|
|
||||||
- On Arch linux, you need pango-perl, cairo-perl and perl-json-maybexs
|
|
||||||
|
|
||||||
TkRemind requires Tcl/Tk and the tcllib library.
|
|
||||||
|
|
||||||
- On Debian-like systems, install with:
|
|
||||||
|
|
||||||
apt install tcl tk tcllib
|
|
||||||
|
|
||||||
- On RPM-based systems, you need tcl, tk and tcllib
|
|
||||||
|
|
||||||
- On Arch Linux, you need tk and tcllib. The latter is available at
|
|
||||||
https://aur.archlinux.org/packages/tcllib
|
|
||||||
|
|
||||||
If the little arrows for "Previous Month" and "Next Month" do not display
|
|
||||||
correctly in TkRemind, you may need to install the Noto Fonts. Install
|
|
||||||
all of your distribution's Nonto Font-related packages.
|
|
||||||
|
|
||||||
- On Debian-like systems, install with:
|
|
||||||
|
|
||||||
apt install fonts-noto-core fonts-noto-color-emoji \
|
|
||||||
fonts-noto-extra fonts-noto-ui-core fonts-noto-ui-extra
|
|
||||||
|
|
||||||
==========================================================================
|
|
||||||
Contact info: mailto:dianne@skoll.ca
|
|
||||||
Home page: https://dianne.skoll.ca/projects/remind/
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
# REMIND
|
||||||
|
|
||||||
|
Remind is a full-featured calendar/alarm program. Copying policy is
|
||||||
|
in the file "COPYRIGHT" included with the source; Remind is licensed under
|
||||||
|
the GNU General Public License, Vesion 2.
|
||||||
|
|
||||||
|
## Prerequisites:
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
- On Debian-like systems, these prerequisites may be installed with:
|
||||||
|
|
||||||
|
`apt install libjson-maybexs-perl libpango-perl libcairo-perl`
|
||||||
|
|
||||||
|
- On RPM-based systems, you need `perl-Pango`, `perl-Cairo` and
|
||||||
|
`perl-JSON-MaybeXS`
|
||||||
|
|
||||||
|
- On Gentoo, you need `dev-perl/Pango`, `dev-perl/Cairo` and
|
||||||
|
`dev-perl/JSON-MaybeXS`.
|
||||||
|
|
||||||
|
- On Arch linux, you need `pango-perl`, `cairo-perl` and `perl-json-maybexs`
|
||||||
|
|
||||||
|
TkRemind requires Tcl/Tk and the tcllib library.
|
||||||
|
|
||||||
|
- On Debian-like systems, install with:
|
||||||
|
|
||||||
|
`apt install tcl tk tcllib`
|
||||||
|
|
||||||
|
- On RPM-based systems, you need `tcl`, `tk` and `tcllib`
|
||||||
|
|
||||||
|
- On Arch Linux, you need `tk` and `tcllib`. The latter is available at
|
||||||
|
https://aur.archlinux.org/packages/tcllib
|
||||||
|
|
||||||
|
If the little arrows for "Previous Month" and "Next Month" do not display
|
||||||
|
correctly in TkRemind, you may need to install the Noto Fonts. Install
|
||||||
|
all of your distribution's Nonto Font-related packages.
|
||||||
|
|
||||||
|
- On Debian-like systems, install with:
|
||||||
|
|
||||||
|
`apt install fonts-noto-core fonts-noto-color-emoji fonts-noto-extra fonts-noto-ui-core fonts-noto-ui-extra`
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
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 have Tcl/Tk installed, you can use the graphical build tool to
|
||||||
|
edit custom.h on your behalf:
|
||||||
|
|
||||||
|
`wish ./build.tk`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Contact info: dianne@skoll.ca
|
||||||
|
|
||||||
|
Home page: [https://dianne.skoll.ca/projects/remind/](https://dianne.skoll.ca/projects/remind/)
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
# A cheesy graphical front-end for building and installing REMIND.
|
# A cheesy graphical front-end for building and installing REMIND.
|
||||||
#
|
#
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# Copyright (C) 1992-2018 Dianne Skoll
|
# Copyright (C) 1992-2025 Dianne Skoll
|
||||||
#
|
#
|
||||||
#--------------------------------------------------------------
|
#--------------------------------------------------------------
|
||||||
|
|
||||||
@@ -487,7 +487,7 @@ proc CallMake {} {
|
|||||||
# Michael McLennan, Bell Labs Innovations for Lucent Technologies
|
# Michael McLennan, Bell Labs Innovations for Lucent Technologies
|
||||||
# Addison-Wesley Professional Computing Series
|
# Addison-Wesley Professional Computing Series
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
# Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison
|
# Copyright (C) 1996-1997 Lucent Technologies Inc. and Mark Harrison
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
|
|
||||||
option add *Tabnotebook.tabs.background #666666 widgetDefault
|
option add *Tabnotebook.tabs.background #666666 widgetDefault
|
||||||
@@ -601,7 +601,7 @@ proc tabnotebook_display {win name} {
|
|||||||
# Michael McLennan, Bell Labs Innovations for Lucent Technologies
|
# Michael McLennan, Bell Labs Innovations for Lucent Technologies
|
||||||
# Addison-Wesley Professional Computing Series
|
# Addison-Wesley Professional Computing Series
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
# Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison
|
# Copyright (C) 1996-1997 Lucent Technologies Inc. and Mark Harrison
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
|
|
||||||
option add *Notebook.borderWidth 2 widgetDefault
|
option add *Notebook.borderWidth 2 widgetDefault
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# Guess values for system-dependent variables and create Makefiles.
|
||||||
# Generated by GNU Autoconf 2.71 for remind 05.02.00.
|
# Generated by GNU Autoconf 2.71 for remind 05.03.05.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
|
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
|
||||||
@@ -608,8 +608,8 @@ MAKEFLAGS=
|
|||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='remind'
|
PACKAGE_NAME='remind'
|
||||||
PACKAGE_TARNAME='remind'
|
PACKAGE_TARNAME='remind'
|
||||||
PACKAGE_VERSION='05.02.00'
|
PACKAGE_VERSION='05.03.05'
|
||||||
PACKAGE_STRING='remind 05.02.00'
|
PACKAGE_STRING='remind 05.03.05'
|
||||||
PACKAGE_BUGREPORT=''
|
PACKAGE_BUGREPORT=''
|
||||||
PACKAGE_URL='https://dianne.skoll.ca/projects/remind/'
|
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.
|
# 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.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
cat <<_ACEOF
|
||||||
\`configure' configures remind 05.02.00 to adapt to many kinds of systems.
|
\`configure' configures remind 05.03.05 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@@ -1327,7 +1327,7 @@ fi
|
|||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of remind 05.02.00:";;
|
short | recursive ) echo "Configuration of remind 05.03.05:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@@ -1415,7 +1415,7 @@ fi
|
|||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
remind configure 05.02.00
|
remind configure 05.03.05
|
||||||
generated by GNU Autoconf 2.71
|
generated by GNU Autoconf 2.71
|
||||||
|
|
||||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||||
@@ -1865,7 +1865,7 @@ cat >config.log <<_ACEOF
|
|||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
It was created by remind $as_me 05.02.00, which was
|
It was created by remind $as_me 05.03.05, which was
|
||||||
generated by GNU Autoconf 2.71. Invocation command line was
|
generated by GNU Autoconf 2.71. Invocation command line was
|
||||||
|
|
||||||
$ $0$ac_configure_args_raw
|
$ $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
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by remind $as_me 05.02.00, which was
|
This file was extended by remind $as_me 05.03.05, which was
|
||||||
generated by GNU Autoconf 2.71. Invocation command line was
|
generated by GNU Autoconf 2.71. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
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
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config='$ac_cs_config_escaped'
|
ac_cs_config='$ac_cs_config_escaped'
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
remind config.status 05.02.00
|
remind config.status 05.03.05
|
||||||
configured by $0, generated by GNU Autoconf 2.71,
|
configured by $0, generated by GNU Autoconf 2.71,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
dnl Process this file with autoconf to produce a configure script.
|
dnl Process this file with autoconf to produce a configure script.
|
||||||
|
|
||||||
AC_INIT(remind, 05.02.00, , , https://dianne.skoll.ca/projects/remind/)
|
AC_INIT(remind, 05.03.05, , , https://dianne.skoll.ca/projects/remind/)
|
||||||
AC_CONFIG_SRCDIR([src/queue.c])
|
AC_CONFIG_SRCDIR([src/queue.c])
|
||||||
|
|
||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
|
|||||||
@@ -112,7 +112,7 @@
|
|||||||
(list "ADDOMIT" "AFTER" "AT" "BAN" "BANNER" "BEFORE" "CAL" "CLEAR"
|
(list "ADDOMIT" "AFTER" "AT" "BAN" "BANNER" "BEFORE" "CAL" "CLEAR"
|
||||||
"CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMP" "DUMPVARS" "DURATION" "ELSE"
|
"CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMP" "DUMPVARS" "DURATION" "ELSE"
|
||||||
"ENDIF" "ERRMSG" "EXIT" "EXPR" "FIRST" "FLUSH" "FOURTH" "FRENAME" "FROM" "FSET"
|
"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"
|
"LASTDAY" "LASTWORKDAY" "MAYBE" "MAYBE-UNCOMPUTABLE" "MSF" "MSG"
|
||||||
"NOQUEUE" "OMIT" "OMITFUNC" "ONCE" "POP" "POP-OMIT-CONTEXT" "PRESERVE"
|
"NOQUEUE" "OMIT" "OMITFUNC" "ONCE" "POP" "POP-OMIT-CONTEXT" "PRESERVE"
|
||||||
"PRIORITY" "PS" "PSFILE" "PUSH" "PUSH-OMIT-CONTEXT" "REM" "RUN"
|
"PRIORITY" "PS" "PSFILE" "PUSH" "PUSH-OMIT-CONTEXT" "REM" "RUN"
|
||||||
@@ -130,8 +130,8 @@
|
|||||||
(defconst remind-builtin-variables
|
(defconst remind-builtin-variables
|
||||||
(sort
|
(sort
|
||||||
(list " $AddBlankLines" "$Ago" "$Am" "$And" "$April" "$At" "$August"
|
(list " $AddBlankLines" "$Ago" "$Am" "$And" "$April" "$At" "$August"
|
||||||
"$CalcUTC" "$CalMode" "$Daemon" "$DateSep" "$DateTimeSep" "$December"
|
"$CalcUTC" "$CalMode" "$CalType" "$Daemon" "$DateSep" "$DateTimeSep"
|
||||||
"$DedupeReminders" "$DefaultColor" "$DefaultDelta"
|
"$December" "$DedupeReminders" "$DefaultColor" "$DefaultDelta"
|
||||||
"$DefaultPrio" "$DefaultTDelta" "$DeltaOverride"
|
"$DefaultPrio" "$DefaultTDelta" "$DeltaOverride"
|
||||||
"$DontFork" "$DontQueue" "$DontTrigAts" "$EndSent" "$EndSentIg"
|
"$DontFork" "$DontQueue" "$DontTrigAts" "$EndSent" "$EndSentIg"
|
||||||
"$ExpressionTimeLimit" "$February" "$FirstIndent" "$FoldYear"
|
"$ExpressionTimeLimit" "$February" "$FirstIndent" "$FoldYear"
|
||||||
@@ -166,7 +166,7 @@
|
|||||||
(list "_" "abs" "access" "adawn" "adusk" "ampm" "ansicolor" "args" "asc"
|
(list "_" "abs" "access" "adawn" "adusk" "ampm" "ansicolor" "args" "asc"
|
||||||
"baseyr" "char" "choose" "coerce" "columns" "current" "date"
|
"baseyr" "char" "choose" "coerce" "columns" "current" "date"
|
||||||
"datepart" "datetime" "dawn" "day" "daysinmon" "defined" "dosubst"
|
"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"
|
"filename" "getenv" "hebdate" "hebday" "hebmon" "hebyear" "hour"
|
||||||
"htmlescape" "htmlstriptags" "iif" "index" "isany" "isdst" "isleap"
|
"htmlescape" "htmlstriptags" "iif" "index" "isany" "isdst" "isleap"
|
||||||
"isomitted" "language" "localtoutc" "lower" "max" "min" "minsfromutc"
|
"isomitted" "language" "localtoutc" "lower" "max" "min" "minsfromutc"
|
||||||
@@ -177,7 +177,7 @@
|
|||||||
"slide" "soleq" "stdout" "strlen" "substr" "sunrise" "sunset" "time"
|
"slide" "soleq" "stdout" "strlen" "substr" "sunrise" "sunset" "time"
|
||||||
"timepart" "timezone" "today" "trig" "trigback" "trigdate"
|
"timepart" "timezone" "today" "trig" "trigback" "trigdate"
|
||||||
"trigdatetime" "trigdelta" "trigduration" "trigeventduration"
|
"trigdatetime" "trigdelta" "trigduration" "trigeventduration"
|
||||||
"trigeventstart" "trigfrom" "trigger" "trigpriority" "trigrep"
|
"trigeventstart" "trigfrom" "trigger" "triginfo" "trigpriority" "trigrep"
|
||||||
"trigscanfrom" "trigtags" "trigtime" "trigtimedelta" "trigtimerep"
|
"trigscanfrom" "trigtags" "trigtime" "trigtimedelta" "trigtimerep"
|
||||||
"triguntil" "trigvalid" "typeof" "tzconvert" "upper" "utctolocal"
|
"triguntil" "trigvalid" "typeof" "tzconvert" "upper" "utctolocal"
|
||||||
"value" "version" "weekno" "wkday" "wkdaynum" "year")
|
"value" "version" "weekno" "wkday" "wkdaynum" "year")
|
||||||
|
|||||||
+4
-79
@@ -1,6 +1,6 @@
|
|||||||
REMIND version 3.2 for UNIX
|
Remind for UNIX and Linux
|
||||||
|
|
||||||
REMIND is a sophisticated alarm/calendar program. Details are given
|
Remind is a sophisticated alarm/calendar program. Details are given
|
||||||
in the man page, "remind.1".
|
in the man page, "remind.1".
|
||||||
|
|
||||||
INSTALLING REMIND:
|
INSTALLING REMIND:
|
||||||
@@ -19,88 +19,13 @@ If you do NOT have Tcl/Tk or are NOT running X11:
|
|||||||
|
|
||||||
1) Edit the file "src/custom.h" according to your preferences.
|
1) Edit the file "src/custom.h" according to your preferences.
|
||||||
|
|
||||||
2) Edit the file "src/lang.h" to choose a language.
|
2) Type: "make"
|
||||||
|
|
||||||
3) Type: "make"
|
3) Type: "make install" -- you may need to be root to do this.
|
||||||
|
|
||||||
4) Type: "make install" -- you may need to be root to do this.
|
|
||||||
|
|
||||||
The subdirectory "www" contains scripts for making a nice calendar
|
The subdirectory "www" contains scripts for making a nice calendar
|
||||||
web server. See the files README and Makefile in that directory.
|
web server. See the files README and Makefile in that directory.
|
||||||
|
|
||||||
The file "examples/defs.rem" has some sample Remind definitions and
|
|
||||||
commands, as well as U.S. and Jewish holidays.
|
|
||||||
|
|
||||||
OTHER LANGUAGE SUPPORT
|
|
||||||
|
|
||||||
Remind has support for languages other than English. See the file
|
|
||||||
"src/lang.h" for details. The language support may vary - you can change
|
|
||||||
only the substitution filter, or you can translate all of the usage
|
|
||||||
instructions and error messages as well. See "src/langs/french.h" for an
|
|
||||||
example of the latter.
|
|
||||||
|
|
||||||
To compile Remind for a non-english language, look at the constants
|
|
||||||
defined in "src/lang.h". Then, to compile Remind for Italian (as an
|
|
||||||
example), type:
|
|
||||||
|
|
||||||
make "LANGDEF=-DLANG=ITALIAN"
|
|
||||||
|
|
||||||
If you add support for a non-English language, Remind will accept both the
|
|
||||||
English and non-English names of months and weekdays in an input script.
|
|
||||||
However, you should not rely on this feature if you want to write portable
|
|
||||||
Remind scripts.
|
|
||||||
|
|
||||||
At a minimum, you should support month and day names in the foreign
|
|
||||||
language, and should modify the substitution filter appropriately.
|
|
||||||
If you are truly diligent, you can translate usage and error messages
|
|
||||||
too.
|
|
||||||
|
|
||||||
Take a look at the files "src/langs/english.h" and
|
|
||||||
"src/langs/german.h" if you want to add support for your favourite
|
|
||||||
language. If you do add another language to Remind, please let me
|
|
||||||
know! Here are the basic guidelines:
|
|
||||||
|
|
||||||
- Your language file should be called "src/langs/lxxx.h", where lxxx
|
|
||||||
is the first 8 characters of the ENGLISH name of your language.
|
|
||||||
|
|
||||||
- Your language file should define L_LANGNAME to be the full English
|
|
||||||
name of your language, with the first letter capitalized and the rest
|
|
||||||
lower-case.
|
|
||||||
|
|
||||||
- You can test your language file with the script "tests/tstlang.rem"
|
|
||||||
|
|
||||||
- Your localized strings must be encoded using UTF-8.
|
|
||||||
|
|
||||||
RELEASE NOTES -- miscellaneous info that couldn't go anywhere else!
|
|
||||||
|
|
||||||
1. POPUP REMINDERS
|
|
||||||
|
|
||||||
If you're running under X11 and you have the Tcl tools, you can create
|
|
||||||
simple pop-up reminders by creating the following Tcl script called
|
|
||||||
'popup'. It pops a message on to the screen and waits for you to
|
|
||||||
press the 'OK' button. If you don't press the OK button within 15
|
|
||||||
seconds, it exits anyway. To use it, you can use the '-k' option for
|
|
||||||
Remind as follows:
|
|
||||||
|
|
||||||
remind "-kpopup '%s'&" .reminders
|
|
||||||
|
|
||||||
Or use the following in your Remind script:
|
|
||||||
|
|
||||||
REM AT 17:00 RUN popup 'Time to go home.' &
|
|
||||||
|
|
||||||
This Tcl script is a slightly modified version of one submitted by
|
|
||||||
Norman Walsh.
|
|
||||||
|
|
||||||
-------------- Cut Here ---------- Cut Here ---------- Cut Here -------------
|
|
||||||
#!/usr/local/bin/wish
|
|
||||||
wm withdraw .
|
|
||||||
after 15000 { destroy . ; exit }
|
|
||||||
tk_messageBox -message Message -detail $argv -icon info -type ok
|
|
||||||
destroy .
|
|
||||||
exit
|
|
||||||
-------------- Cut Here ---------- Cut Here ---------- Cut Here -------------
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
Dianne Skoll <dianne@skoll.ca>
|
Dianne Skoll <dianne@skoll.ca>
|
||||||
https://dianne.skoll.ca/projects/remind/
|
https://dianne.skoll.ca/projects/remind/
|
||||||
|
|||||||
+164
-4
@@ -1,10 +1,162 @@
|
|||||||
CHANGES TO REMIND
|
CHANGES TO REMIND
|
||||||
|
|
||||||
* VERSION 5.2 Patch 0 - ????-??=??
|
* VERSION 5.3 Patch 5 - 2025-03-23
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: Add moonrise, moonset, moonrisedir and moonsetdir
|
||||||
|
functions. The first two functions calculate the time of the next
|
||||||
|
moonrise and moonset, and the second two calculate in which direction
|
||||||
|
the moon will rise or set. See the examples/astro script for examples
|
||||||
|
of how to use the moonrise/moonset functions.
|
||||||
|
|
||||||
|
- CODE CLEANUPS: remind: Some minor code cleanups with no user-visible effects.
|
||||||
|
|
||||||
|
- IMPROVEMENT: Add tests for the astronomical calculation functions.
|
||||||
|
|
||||||
|
- UPDATE: Update the included json.c and json.h files to the latest versions
|
||||||
|
from https://github.com/udp/json-parser
|
||||||
|
|
||||||
|
- BUG FIX: remind: The %2 and %@ sequences would print "0:34am" for the
|
||||||
|
time 00:34, instead of the correct "12:34am". This has been fixed.
|
||||||
|
|
||||||
|
- BUG FIX: TkRemind: Fix bug that broke the ability to open a text editor
|
||||||
|
on a reminder from the "Queue..." listing.
|
||||||
|
|
||||||
|
* VERSION 5.3 Patch 4 - 2025-03-09
|
||||||
|
|
||||||
|
- BUG FIX: remind: "make test" could fail if Remind was built in a locale
|
||||||
|
other than "C". This has been fixed.
|
||||||
|
|
||||||
|
- BUG FIX: Fix a typo in the remind man page.
|
||||||
|
|
||||||
|
* VERSION 5.3 Patch 3 - 2025-03-03
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: If a command spans more than one line (because of
|
||||||
|
backslash line continuation) output both the starting and ending line
|
||||||
|
number in error messages.
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: In the JSON -pp and -ppp output, include a new key
|
||||||
|
lineno_start to specify the starting line of a multi-line reminder.
|
||||||
|
The existing lineno key specifies the ending line; this is maintained
|
||||||
|
for backward-compatibility.
|
||||||
|
|
||||||
|
- MINOR IMPROVEMENT: include/holidays/misc.rem: Add a few new holidays and
|
||||||
|
URL INFO strings.
|
||||||
|
|
||||||
|
- CHANGE: remind: Issue a warning if a time-related substitution sequence
|
||||||
|
is used with a non-timed REM command.
|
||||||
|
|
||||||
|
- BUG FIX: remind: Fix a memory leak.
|
||||||
|
|
||||||
|
* VERSION 5.3 Patch 2 - 2025-02-09
|
||||||
|
|
||||||
|
- CHANGE: remind: Revert a change to the way "-y" tags are generated that
|
||||||
|
was introduced in 05.03.01. The change broke a library that depended
|
||||||
|
on it being generated in the old way.
|
||||||
|
|
||||||
|
* VERSION 5.3 Patch 1 - 2025-02-07
|
||||||
|
|
||||||
|
- IMPROVEMENT: TkRemind: When we pop up a timed reminder, make any "Url:"
|
||||||
|
info string into a clickable link.
|
||||||
|
|
||||||
|
- IMPROVEMENT: rem2pdf: Improve the layout of the small monthly calendars.
|
||||||
|
|
||||||
|
- BUG FIX: rem2pdf: Add checks for all Perl dependencies.
|
||||||
|
|
||||||
|
* VERSION 5.3 Patch 0 - 2025-02-04
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: Add the "INFO" clause to the REM command. This
|
||||||
|
is intended for storing additional metadata about an event, such as
|
||||||
|
the location and a longer description. The intention is to make
|
||||||
|
Remind <-> iCal conversions preserve as much information as possible.
|
||||||
|
|
||||||
|
- NEW FEATURE: rem2html, rem2pdf, tkremind: Add support for the "Url:"
|
||||||
|
info string that turns reminders into hyper-links. For example,
|
||||||
|
consider this reminder:
|
||||||
|
|
||||||
|
REM 15 INFO "Url: https://foo.example" MSG Foo
|
||||||
|
|
||||||
|
The text "Foo" will be made into a link to "https://foo.example"
|
||||||
|
by rem2html and rem2pdf. If you middle-click it in tkremind, it
|
||||||
|
will open the URL.
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: Add the triginfo() built-in function so a reminder
|
||||||
|
body can refer to INFO data. Add the %<...> substitution filter as a
|
||||||
|
shorthand for [triginfo("...")]
|
||||||
|
|
||||||
|
- NEW FEATURE: TkRemind: Add "Location" and "Description" fields when
|
||||||
|
creating a reminder; these are converted to INFO clauses. Also support
|
||||||
|
a popup window with the extra information when hovering over a reminder
|
||||||
|
in the calendar display.
|
||||||
|
|
||||||
|
- IMPROVEMENT: Update the reminder files included with Remind to add
|
||||||
|
INFO strings with Wikipedia URLs for various holidays and
|
||||||
|
astronomical events.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Add the "\xAB" escape sequence for parsing quoted
|
||||||
|
strings, where "AB" is a pair of hex digits.
|
||||||
|
|
||||||
|
- 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
|
||||||
|
Remind.
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: Add "q" debug flag for tracing calls to _()
|
||||||
|
or %(...) in the substitution filter; this will help with localizing
|
||||||
|
reminder files.
|
||||||
|
|
||||||
|
- NEW FILES: remind: Add holidays/lgbtq.rem for LGBTQ holidays. Add
|
||||||
|
country-specific files in holidays/lgbtq/*.rem
|
||||||
|
|
||||||
|
- IMPROVEMENT: TkRemind: use "info patchlevel" to display full Tcl/Tk
|
||||||
|
version.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: The DEBUG command issues a warning if given an
|
||||||
|
unknown debug flag.
|
||||||
|
|
||||||
|
- BUG FIX: remind: "make test" will now succeed even if run between
|
||||||
|
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
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: The "-p+" option lets you produce weekly calendars;
|
||||||
|
so far, the rem2pdf and rem2html back-ends support rendering of weekly
|
||||||
|
calendars.
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: The $CalType system variable indicates the type of
|
||||||
|
calendar being produced; its value is one of "monthly", "weekly",
|
||||||
|
or "none". "none" signifies agenda mode rather than calendar mode.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Warn if a POP-OMIT-CONTEXT matches a
|
||||||
|
PUSH-OMIT-CONTEXT that is in a different file.
|
||||||
|
|
||||||
|
- CHANGE: remind: Split the "-ds" debug option into two separate options:
|
||||||
|
"-ds" for debugging expression-parsing and "-dh" for printing hash
|
||||||
|
table statistics on exit.
|
||||||
|
|
||||||
|
* VERSION 5.2 Patch 1 - 2024-12-16
|
||||||
|
|
||||||
|
- BUG FIX: remind: Fix a logic error that only showed itself on big-endian
|
||||||
|
architectures. Found thanks to Debian testing and a notification from
|
||||||
|
Jochen Sprickerhof.
|
||||||
|
|
||||||
|
* VERSION 5.2 Patch 0 - 2024-12-16
|
||||||
|
|
||||||
- MAJOR NEW FEATURE: remind: Add the TRANSLATE command, the _()
|
- MAJOR NEW FEATURE: remind: Add the TRANSLATE command, the _()
|
||||||
built-in function and the %(...) substitution sequence. These allow
|
built-in function and the %(...) substitution sequence. These allow
|
||||||
you to localize your reminder files more easily.
|
you to localize your reminder files more easily. The translation table
|
||||||
|
is also made available to back-ends like rem2pdf and tkremind,
|
||||||
|
which they can use as they see fit.
|
||||||
|
|
||||||
|
- MINOR FEATURE: tkremind, rem2html: Localize the names of the moon
|
||||||
|
phases.
|
||||||
|
|
||||||
- MAJOR CHANGE: remind: Remind used to support compile-time localization
|
- MAJOR CHANGE: remind: Remind used to support compile-time localization
|
||||||
into different languages (French, English, etc.) That compile-time
|
into different languages (French, English, etc.) That compile-time
|
||||||
@@ -27,6 +179,10 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
INCLUDE [$SysInclude]/foo/bar.rem
|
INCLUDE [$SysInclude]/foo/bar.rem
|
||||||
|
|
||||||
|
- MINOR IMPROVEMENT: Allow INCLUDE, DO and SYSINCLUDE to include files with
|
||||||
|
spaces in their names; in this case, you have to put the filename inside
|
||||||
|
double-quotes.
|
||||||
|
|
||||||
- IMPROVEMENT: remind: Refuse to open subdirectories named "*.rem"
|
- IMPROVEMENT: remind: Refuse to open subdirectories named "*.rem"
|
||||||
under a top-level directory rather than trying and failing with a
|
under a top-level directory rather than trying and failing with a
|
||||||
confusing error.
|
confusing error.
|
||||||
@@ -43,8 +199,12 @@ CHANGES TO REMIND
|
|||||||
- MINOR FIXES: remind: Fix typos in comments; use memcpy to copy OMIT
|
- MINOR FIXES: remind: Fix typos in comments; use memcpy to copy OMIT
|
||||||
contexts internally.
|
contexts internally.
|
||||||
|
|
||||||
- BUG FIX: Actually allow the documented 9 levels of INCLUDE rather than
|
- BUG FIX: remind: Actually allow the documented 9 levels of INCLUDE
|
||||||
8.
|
rather than 8.
|
||||||
|
|
||||||
|
- BUG FIX: remind: If an INCLUDE statement failed inside an IF statement,
|
||||||
|
Remind would print spurious errors about unmatched IF/ENDIF. This has
|
||||||
|
been fixed.
|
||||||
|
|
||||||
* VERSION 5.1 Patch 1 - 2024-11-18
|
* VERSION 5.1 Patch 1 - 2024-11-18
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,24 @@ EOF
|
|||||||
|
|
||||||
remind -g "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
|
remind -g "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
|
||||||
SET $AddBlankLines 0
|
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 %
|
BANNER %
|
||||||
IF $TerminalBackground == 0
|
IF $TerminalBackground == 0
|
||||||
REM [moondatetime(0)] +60 SPECIAL COLOR 255 255 0 New moon: 🌑 [$T] %3 (%b)
|
REM [moondatetime(0)] +60 SPECIAL COLOR 255 255 0 New moon: 🌑 [$T] %3 (%b)
|
||||||
@@ -48,6 +66,50 @@ EOF
|
|||||||
|
|
||||||
echo ""
|
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'
|
remind -g "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
|
||||||
SET $AddBlankLines 0
|
SET $AddBlankLines 0
|
||||||
BANNER %
|
BANNER %
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@
|
|||||||
# "#PSSTUFF" for nifty PostScript examples #
|
# "#PSSTUFF" for nifty PostScript examples #
|
||||||
# #
|
# #
|
||||||
# This file is part of REMIND. #
|
# This file is part of REMIND. #
|
||||||
# Copyright (C) 1992-2024 Dianne Skoll #
|
# Copyright (C) 1992-2025 Dianne Skoll #
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
# #
|
# #
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# Not all sequences are supported by all terminals.
|
# Not all sequences are supported by all terminals.
|
||||||
|
|
||||||
# This file is part of REMIND
|
# This file is part of REMIND
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
if !defined("ansi_bold")
|
if !defined("ansi_bold")
|
||||||
|
|||||||
@@ -1,29 +1,30 @@
|
|||||||
REM 1 Feb 2022 MSG %(Chinese New Year) (%(Tiger))
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
REM 22 Jan 2023 MSG %(Chinese New Year) (%(Rabbit))
|
REM 1 Feb 2022 INFO "Url: https://en.wikipedia.org/wiki/Tiger_(zodiac)" MSG %(Chinese New Year) (%(Tiger))
|
||||||
REM 10 Feb 2024 MSG %(Chinese New Year) (%(Dragon))
|
REM 22 Jan 2023 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %(Chinese New Year) (%(Rabbit))
|
||||||
REM 29 Jan 2025 MSG %(Chinese New Year) (%(Snake))
|
REM 10 Feb 2024 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %(Chinese New Year) (%(Dragon))
|
||||||
REM 17 Feb 2026 MSG %(Chinese New Year) (%(Horse))
|
REM 29 Jan 2025 INFO "Url: https://en.wikipedia.org/wiki/Snake_(zodiac)" MSG %(Chinese New Year) (%(Snake))
|
||||||
REM 6 Feb 2027 MSG %(Chinese New Year) (%(Goat))
|
REM 17 Feb 2026 INFO "Url: https://en.wikipedia.org/wiki/Horse_(zodiac)" MSG %(Chinese New Year) (%(Horse))
|
||||||
REM 26 Jan 2028 MSG %(Chinese New Year) (%(Monkey))
|
REM 6 Feb 2027 INFO "Url: https://en.wikipedia.org/wiki/Goat_(zodiac)" MSG %(Chinese New Year) (%(Goat))
|
||||||
REM 13 Feb 2029 MSG %(Chinese New Year) (%(Rooster))
|
REM 26 Jan 2028 INFO "Url: https://en.wikipedia.org/wiki/Monkey_(zodiac)" MSG %(Chinese New Year) (%(Monkey))
|
||||||
REM 3 Feb 2030 MSG %(Chinese New Year) (%(Dog))
|
REM 13 Feb 2029 INFO "Url: https://en.wikipedia.org/wiki/Rooster_(zodiac)" MSG %(Chinese New Year) (%(Rooster))
|
||||||
REM 23 Jan 2031 MSG %(Chinese New Year) (%(Pig))
|
REM 3 Feb 2030 INFO "Url: https://en.wikipedia.org/wiki/Dog_(zodiac)" MSG %(Chinese New Year) (%(Dog))
|
||||||
REM 11 Feb 2032 MSG %(Chinese New Year) (%(Rat))
|
REM 23 Jan 2031 INFO "Url: https://en.wikipedia.org/wiki/Pig_(zodiac)" MSG %(Chinese New Year) (%(Pig))
|
||||||
REM 31 Jan 2033 MSG %(Chinese New Year) (%(Ox))
|
REM 11 Feb 2032 INFO "Url: https://en.wikipedia.org/wiki/Rat_(zodiac)" MSG %(Chinese New Year) (%(Rat))
|
||||||
REM 19 Feb 2034 MSG %(Chinese New Year) (%(Tiger))
|
REM 31 Jan 2033 INFO "Url: https://en.wikipedia.org/wiki/Ox_(zodiac)" MSG %(Chinese New Year) (%(Ox))
|
||||||
REM 8 Feb 2035 MSG %(Chinese New Year) (%(Rabbit))
|
REM 19 Feb 2034 INFO "Url: https://en.wikipedia.org/wiki/Tiger_(zodiac)" MSG %(Chinese New Year) (%(Tiger))
|
||||||
REM 28 Jan 2036 MSG %(Chinese New Year) (%(Dragon))
|
REM 8 Feb 2035 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %(Chinese New Year) (%(Rabbit))
|
||||||
REM 15 Feb 2037 MSG %(Chinese New Year) (%(Snake))
|
REM 28 Jan 2036 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %(Chinese New Year) (%(Dragon))
|
||||||
REM 4 Feb 2038 MSG %(Chinese New Year) (%(Horse))
|
REM 15 Feb 2037 INFO "Url: https://en.wikipedia.org/wiki/Snake_(zodiac)" MSG %(Chinese New Year) (%(Snake))
|
||||||
REM 24 Jan 2039 MSG %(Chinese New Year) (%(Goat))
|
REM 4 Feb 2038 INFO "Url: https://en.wikipedia.org/wiki/Horse_(zodiac)" MSG %(Chinese New Year) (%(Horse))
|
||||||
REM 12 Feb 2040 MSG %(Chinese New Year) (%(Monkey))
|
REM 24 Jan 2039 INFO "Url: https://en.wikipedia.org/wiki/Goat_(zodiac)" MSG %(Chinese New Year) (%(Goat))
|
||||||
REM 1 Feb 2041 MSG %(Chinese New Year) (%(Rooster))
|
REM 12 Feb 2040 INFO "Url: https://en.wikipedia.org/wiki/Monkey_(zodiac)" MSG %(Chinese New Year) (%(Monkey))
|
||||||
REM 22 Jan 2042 MSG %(Chinese New Year) (%(Dog))
|
REM 1 Feb 2041 INFO "Url: https://en.wikipedia.org/wiki/Rooster_(zodiac)" MSG %(Chinese New Year) (%(Rooster))
|
||||||
REM 10 Feb 2043 MSG %(Chinese New Year) (%(Pig))
|
REM 22 Jan 2042 INFO "Url: https://en.wikipedia.org/wiki/Dog_(zodiac)" MSG %(Chinese New Year) (%(Dog))
|
||||||
REM 30 Jan 2044 MSG %(Chinese New Year) (%(Rat))
|
REM 10 Feb 2043 INFO "Url: https://en.wikipedia.org/wiki/Pig_(zodiac)" MSG %(Chinese New Year) (%(Pig))
|
||||||
REM 17 Feb 2045 MSG %(Chinese New Year) (%(Ox))
|
REM 30 Jan 2044 INFO "Url: https://en.wikipedia.org/wiki/Rat_(zodiac)" MSG %(Chinese New Year) (%(Rat))
|
||||||
REM 6 Feb 2046 MSG %(Chinese New Year) (%(Tiger))
|
REM 17 Feb 2045 INFO "Url: https://en.wikipedia.org/wiki/Ox_(zodiac)" MSG %(Chinese New Year) (%(Ox))
|
||||||
REM 26 Jan 2047 MSG %(Chinese New Year) (%(Rabbit))
|
REM 6 Feb 2046 INFO "Url: https://en.wikipedia.org/wiki/Tiger_(zodiac)" MSG %(Chinese New Year) (%(Tiger))
|
||||||
REM 14 Feb 2048 MSG %(Chinese New Year) (%(Dragon))
|
REM 26 Jan 2047 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %(Chinese New Year) (%(Rabbit))
|
||||||
REM 2 Feb 2049 MSG %(Chinese New Year) (%(Snake))
|
REM 14 Feb 2048 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %(Chinese New Year) (%(Dragon))
|
||||||
REM 23 Jan 2050 MSG %(Chinese New Year) (%(Horse))
|
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))
|
||||||
|
|||||||
+37
-37
@@ -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 InIsrael VALUE("InIsrael", 0)
|
||||||
SET Reform VALUE("Reform", 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
|
# No RH-2 or Tzom Gedalia in Reform
|
||||||
IF !Reform
|
IF !Reform
|
||||||
REM [hebdate(2, "Tishrey")] MSG Rosh Hashana 2
|
REM [hebdate(2, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Rosh_Hashanah" MSG Rosh Hashana 2
|
||||||
REM [_PastSat(3, "Tishrey")] MSG Tzom Gedalia
|
REM [_PastSat(3, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Fast_of_Gedalia" MSG Tzom Gedalia
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
REM [hebdate(10, "Tishrey")] MSG Yom Kippur
|
REM [hebdate(10, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Yom_Kippur" MSG Yom Kippur
|
||||||
REM [hebdate(15, "Tishrey")] MSG Sukkot 1
|
REM [hebdate(15, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Sukkot" MSG Sukkot 1
|
||||||
|
|
||||||
IF !InIsrael
|
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
|
ENDIF
|
||||||
|
|
||||||
REM [hebdate(21, "Tishrey")] MSG Hoshana Rabba
|
REM [hebdate(21, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Hoshana_Rabbah" MSG Hoshana Rabba
|
||||||
REM [hebdate(22, "Tishrey")] MSG Shemini Atzeret
|
REM [hebdate(22, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Shemini_Atzeret" MSG Shemini Atzeret
|
||||||
|
|
||||||
IF InIsrael
|
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
|
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
|
ENDIF
|
||||||
|
|
||||||
# Because Kislev can change length, we must be more careful about Chanukah
|
# Because Kislev can change length, we must be more careful about Chanukah
|
||||||
FSET _chan(x) HEBDATE(24, "Kislev", $U-9)+x
|
FSET _chan(x) HEBDATE(24, "Kislev", $U-9)+x
|
||||||
REM [_chan(1)] MSG Chanukah 1
|
REM [_chan(1)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 1
|
||||||
REM [_chan(2)] MSG Chanukah 2
|
REM [_chan(2)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 2
|
||||||
REM [_chan(3)] MSG Chanukah 3
|
REM [_chan(3)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 3
|
||||||
REM [_chan(4)] MSG Chanukah 4
|
REM [_chan(4)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 4
|
||||||
REM [_chan(5)] MSG Chanukah 5
|
REM [_chan(5)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 5
|
||||||
REM [_chan(6)] MSG Chanukah 6
|
REM [_chan(6)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 6
|
||||||
REM [_chan(7)] MSG Chanukah 7
|
REM [_chan(7)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 7
|
||||||
REM [_chan(8)] MSG Chanukah 8
|
REM [_chan(8)] INFO "Url: https://en.wikipedia.org/wiki/Hanukkah" MSG Chanukah 8
|
||||||
|
|
||||||
# Not sure about Reform's position on the next one.
|
# Not sure about Reform's position on the next one.
|
||||||
IF !Reform
|
IF !Reform
|
||||||
# 10 Tevet will never be a Saturday, so whether or not to
|
# 10 Tevet will never be a Saturday, so whether or not to
|
||||||
# move it is moot. (Thanks to Art Werschulz.)
|
# 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
|
ENDIF
|
||||||
|
|
||||||
REM [hebdate(15, "Shvat")] MSG Tu B'Shvat
|
REM [hebdate(15, "Shvat")] INFO "Url: https://en.wikipedia.org/wiki/Tu_BiShvat" MSG Tu B'Shvat
|
||||||
REM [hebdate(14, "Adar A")] MSG Purim Katan
|
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 Purim is on Sunday, then Fast of Esther is 11 Adar.
|
||||||
IF WKDAYNUM(_h2(13, "Adar")) != 6
|
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
|
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
|
ENDIF
|
||||||
REM [hebdate(14, "Adar")] MSG Purim
|
REM [hebdate(14, "Adar")] INFO "Url: https://en.wikipedia.org/wiki/Purim" MSG Purim
|
||||||
REM [hebdate(15, "Nisan")] MSG Pesach
|
REM [hebdate(15, "Nisan")] INFO "Url: https://en.wikipedia.org/wiki/Passover" MSG Pesach
|
||||||
|
|
||||||
IF !InIsrael
|
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
|
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
|
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
|
ENDIF
|
||||||
|
|
||||||
REM [hebdate(27, "Nisan")] MSG Yom HaShoah
|
REM [hebdate(27, "Nisan")] INFO "Url: https://en.wikipedia.org/wiki/Yom_HaShoah" MSG Yom HaShoah
|
||||||
REM [_BackTwoFri(4, "Iyar")] MSG Yom HaZikaron
|
REM [_BackTwoFri(4, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Yom_HaZikaron" MSG Yom HaZikaron
|
||||||
REM [_BackTwoSat(5, "Iyar")] MSG Yom Ha'atzmaut
|
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
|
# Not sure about Reform's position on Lag B'Omer
|
||||||
IF !Reform
|
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
|
ENDIF
|
||||||
|
|
||||||
REM [hebdate(28, "Iyar")] MSG Yom Yerushalayim
|
REM [hebdate(28, "Iyar")] INFO "Url: https://en.wikipedia.org/wiki/Jerusalem_Day" MSG Yom Yerushalayim
|
||||||
REM [hebdate(6, "Sivan")] MSG Shavuot
|
REM [hebdate(6, "Sivan")] INFO "Url: https://en.wikipedia.org/wiki/Shavuot" MSG Shavuot
|
||||||
|
|
||||||
IF !InIsrael && !Reform
|
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
|
ENDIF
|
||||||
|
|
||||||
# Fairly sure Reform Jews don't observe the next two
|
# Fairly sure Reform Jews don't observe the next two
|
||||||
IF !Reform
|
IF !Reform
|
||||||
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
|
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
|
||||||
# fall on a Saturday
|
# fall on a Saturday
|
||||||
REM [_PastSat(17, "Tamuz")] MSG Tzom Tammuz
|
REM [_PastSat(17, "Tamuz")] INFO "Url: https://en.wikipedia.org/wiki/Seventeenth_of_Tammuz" MSG Tzom Tammuz
|
||||||
REM [_PastSat(9, "Av")] MSG Tish'a B'Av
|
REM [_PastSat(9, "Av")] INFO "Url: https://en.wikipedia.org/wiki/Tisha_B%27Av" MSG Tish'a B'Av
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# List of LGBTQ awareness days
|
||||||
|
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
|
||||||
|
# These are the internationally-recognized days.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# List of LGBTQ awareness days
|
||||||
|
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
|
||||||
|
# These are the holidays recognized in Australia
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
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
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# List of LGBTQ awareness days
|
||||||
|
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
|
||||||
|
# These are the holidays recognized in Brazil
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
REM 29 Jan MSG National Day of Transgender Visibility
|
||||||
|
REM 20 Feb MSG Trans Men and Transmasculine Day
|
||||||
|
REM 25 Mar MSG National Gay Pride Day
|
||||||
|
REM 29 Aug MSG National Day of Lesbian Visibility
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# List of LGBTQ awareness days
|
||||||
|
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
|
||||||
|
# These are the holidays recognized in Canada
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
REM 1 Oct INFO "Url: https://en.wikipedia.org/wiki/LGBT_History_Month" MSG Start of LGBT History Month
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# List of LGBTQ awareness days
|
||||||
|
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
|
||||||
|
# These are the holidays recognized in Chile
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
REM 9 Jul INFO "Url: https://en.wikipedia.org/wiki/Lesbian_Visibility_Day" MSG Lesbian Visibility Day
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# List of LGBTQ awareness days
|
||||||
|
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
|
||||||
|
# These are the holidays recognized in Ireland
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
REM 22 May INFO "Url: https://en.wikipedia.org/wiki/Thirty-fourth_Amendment_of_the_Constitution_of_Ireland" MSG Irish Marriage Referendum Day
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# List of LGBTQ awareness days
|
||||||
|
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
|
||||||
|
# These are the holidays recognized in India
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
REM 2 Jul INFO "Url: https://en.wikipedia.org/wiki/Indian_Coming_Out_Day" MSG Indian Coming Out Day
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# List of LGBTQ awareness days
|
||||||
|
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
|
||||||
|
# These are the holidays recognized in the Netherlands
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
REM Fri 8 Dec MSG Purple Friday
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# List of LGBTQ awareness days
|
||||||
|
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
|
||||||
|
# These are the holidays recognized in Ukraine
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
REM 12 Dec MSG Day of Remembrance of Homosexuals in Ukraine (victims of the totalitarian Soviet regime)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# List of LGBTQ awareness days
|
||||||
|
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
|
||||||
|
# These are the holidays recognized in the United Kingdom
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# List of LGBTQ awareness days
|
||||||
|
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
|
||||||
|
# These are the holidays recognized in the United States of America
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
REM 1 Mar MSG Start of Bisexual Health Awareness Month
|
||||||
|
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 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 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 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
|
||||||
@@ -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
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Support for the Catalan language.
|
# Support for the Catalan language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file was created by Eloi Torrents <eloitor@disroot.org>
|
# This file was created by Eloi Torrents <eloitor@disroot.org>
|
||||||
|
|
||||||
TRANSLATE "LANGID" "ca"
|
TRANSLATE "LANGID" "ca"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Support for the Danish language.
|
# Support for the Danish language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Mogens Lynnerup.
|
# This file is derived from a translation by Mogens Lynnerup.
|
||||||
|
|
||||||
TRANSLATE "LANGID" "da"
|
TRANSLATE "LANGID" "da"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Support for the German language.
|
# Support for the German language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Wolfgang Thronicke
|
# This file is derived from a translation by Wolfgang Thronicke
|
||||||
|
|
||||||
TRANSLATE "LANGID" "de"
|
TRANSLATE "LANGID" "de"
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
# Support for the English language.
|
# Support for the English language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# Nothing to do for English since it is the default.
|
# Nothing to do for English since it is the default.
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Support for the Spanish language.
|
# Support for the Spanish language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Rafa Couto <rafacouto@biogate.com>
|
# This file is derived from a translation by Rafa Couto <rafacouto@biogate.com>
|
||||||
|
|
||||||
TRANSLATE "LANGID" "es"
|
TRANSLATE "LANGID" "es"
|
||||||
|
|||||||
+10
-10
@@ -1,6 +1,6 @@
|
|||||||
# Support for the Finnish language.
|
# Support for the Finnish language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Mikko Silvonen
|
# This file is derived from a translation by Mikko Silvonen
|
||||||
|
|
||||||
TRANSLATE "LANGID" "fi"
|
TRANSLATE "LANGID" "fi"
|
||||||
@@ -170,19 +170,19 @@ TRANSLATE "Leaving UserFN" "Poistutaan funktiosta"
|
|||||||
TRANSLATE "Expired" "Vanhentunut"
|
TRANSLATE "Expired" "Vanhentunut"
|
||||||
TRANSLATE "fork() failed - can't do queued reminders" "fork() epäonnistui - jonomuistutukset eivät toimi"
|
TRANSLATE "fork() failed - can't do queued reminders" "fork() epäonnistui - jonomuistutukset eivät toimi"
|
||||||
TRANSLATE "Can't access file" "Tiedoston avaus ei onnistu"
|
TRANSLATE "Can't access file" "Tiedoston avaus ei onnistu"
|
||||||
TRANSLATE "Illegal system date: Year is less than %d\n" "Virheellinen järjestelmäpäiväys: vuosi on vähemmän kuin %d\n"
|
TRANSLATE "Illegal system date: Year is less than %d" "Virheellinen järjestelmäpäiväys: vuosi on vähemmän kuin %d"
|
||||||
TRANSLATE "Unknown debug flag '%c'\n" "Tuntematon virheenetsintätarkenne '%c'\n"
|
TRANSLATE "Unknown debug flag '%c'" "Tuntematon virheenetsintätarkenne '%c'"
|
||||||
TRANSLATE "Unknown option '%c'\n" "Tuntematon tarkenne '%c'\n"
|
TRANSLATE "Unknown option '%c'" "Tuntematon tarkenne '%c'"
|
||||||
TRANSLATE "Unknown user '%s'\n" "Tuntematon käyttäjä '%s'\n"
|
TRANSLATE "Unknown user '%s'" "Tuntematon käyttäjä '%s'"
|
||||||
TRANSLATE "Could not change gid to %d\n" "Ryhmänumeron vaihto %d:ksi ei onnistunut\n"
|
TRANSLATE "Could not change gid to %d" "Ryhmänumeron vaihto %d:ksi ei onnistunut"
|
||||||
TRANSLATE "Could not change uid to %d\n" "Käyttäjänumeron vaihto %d:ksi ei onnistunut\n"
|
TRANSLATE "Could not change uid to %d" "Käyttäjänumeron vaihto %d:ksi ei onnistunut"
|
||||||
TRANSLATE "Out of memory for environment\n" "Muisti ei riitä ympäristölle\n"
|
TRANSLATE "Out of memory for environment" "Muisti ei riitä ympäristölle"
|
||||||
TRANSLATE "Missing '=' sign" "Puuttuva '='-merkki"
|
TRANSLATE "Missing '=' sign" "Puuttuva '='-merkki"
|
||||||
TRANSLATE "Missing variable name" "Puuttuva muuttujanimi"
|
TRANSLATE "Missing variable name" "Puuttuva muuttujanimi"
|
||||||
TRANSLATE "Missing expression" "Puuttuva lauseke"
|
TRANSLATE "Missing expression" "Puuttuva lauseke"
|
||||||
TRANSLATE "Remind: '-i' option: %s\n" "Remind: tarkenne '-i': %s\n"
|
TRANSLATE "Remind: '-i' option: %s" "Remind: tarkenne '-i': %s"
|
||||||
TRANSLATE "No reminders." "Ei viestejä."
|
TRANSLATE "No reminders." "Ei viestejä."
|
||||||
TRANSLATE "%d reminder(s) queued for later today.\n" "%d viesti(ä) tämän päivän jonossa.\n"
|
TRANSLATE "%d reminder(s) queued for later today." "%d viesti(ä) tämän päivän jonossa."
|
||||||
TRANSLATE "Expecting number" "Numero puuttuu"
|
TRANSLATE "Expecting number" "Numero puuttuu"
|
||||||
TRANSLATE "Undefined WARN function" "Virheellinen funktio WARN-lausekkeessa"
|
TRANSLATE "Undefined WARN function" "Virheellinen funktio WARN-lausekkeessa"
|
||||||
TRANSLATE "Can't convert between time zones" "Aikavyöhykkeiden välillä ei voi muuntaa"
|
TRANSLATE "Can't convert between time zones" "Aikavyöhykkeiden välillä ei voi muuntaa"
|
||||||
|
|||||||
+11
-9
@@ -1,6 +1,6 @@
|
|||||||
# Support for the French language.
|
# Support for the French language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Laurent Duperval
|
# This file is derived from a translation by Laurent Duperval
|
||||||
|
|
||||||
TRANSLATE "LANGID" "fr"
|
TRANSLATE "LANGID" "fr"
|
||||||
@@ -138,17 +138,17 @@ TRANSLATE "Leaving UserFN" "Sortie de UserFN"
|
|||||||
TRANSLATE "Expired" "Expiré"
|
TRANSLATE "Expired" "Expiré"
|
||||||
TRANSLATE "fork() failed - can't do queued reminders" "fork() échoué - impossible de faire les appels en queue"
|
TRANSLATE "fork() failed - can't do queued reminders" "fork() échoué - impossible de faire les appels en queue"
|
||||||
TRANSLATE "Can't access file" "Impossible d'accéder au fichier"
|
TRANSLATE "Can't access file" "Impossible d'accéder au fichier"
|
||||||
TRANSLATE "Illegal system date: Year is less than %d\n" "Date système illégale: Année est inférieure à %d\n"
|
TRANSLATE "Illegal system date: Year is less than %d" "Date système illégale: Année est inférieure à %d"
|
||||||
TRANSLATE "Unknown debug flag '%c'\n" "Option de déverminage inconnue '%c'\n"
|
TRANSLATE "Unknown debug flag '%c'" "Option de déverminage inconnue '%c'"
|
||||||
TRANSLATE "Unknown option '%c'\n" "Option inconnue '%c'\n"
|
TRANSLATE "Unknown option '%c'" "Option inconnue '%c'"
|
||||||
TRANSLATE "Unknown user '%s'\n" "Usager inconnu '%s'\n"
|
TRANSLATE "Unknown user '%s'" "Usager inconnu '%s'"
|
||||||
TRANSLATE "Could not change gid to %d\n" "Impossible de changer gid pour %d\n"
|
TRANSLATE "Could not change gid to %d" "Impossible de changer gid pour %d"
|
||||||
TRANSLATE "Could not change uid to %d\n" "Impossible de changer uid pour %d\n"
|
TRANSLATE "Could not change uid to %d" "Impossible de changer uid pour %d"
|
||||||
TRANSLATE "Out of memory for environment\n" "Manque de mémoire pour environnement\n"
|
TRANSLATE "Out of memory for environment" "Manque de mémoire pour environnement"
|
||||||
TRANSLATE "Missing '=' sign" "Signe '=' manquant"
|
TRANSLATE "Missing '=' sign" "Signe '=' manquant"
|
||||||
TRANSLATE "Missing variable name" "Nom de variable absent"
|
TRANSLATE "Missing variable name" "Nom de variable absent"
|
||||||
TRANSLATE "Missing expression" "Expression absente"
|
TRANSLATE "Missing expression" "Expression absente"
|
||||||
TRANSLATE "%d reminder(s) queued for later today.\n" "%d rappel(s) en file pour aujourd'hui.\n"
|
TRANSLATE "%d reminder(s) queued for later today." "%d rappel(s) en file pour aujourd'hui."
|
||||||
TRANSLATE "Expecting number" "Nombre attendu"
|
TRANSLATE "Expecting number" "Nombre attendu"
|
||||||
TRANSLATE "Undefined WARN function" "Fonction illégale après WARN"
|
TRANSLATE "Undefined WARN function" "Fonction illégale après WARN"
|
||||||
TRANSLATE "Can't convert between time zones" "Impossible de convertir entre les fuseaux horaires"
|
TRANSLATE "Can't convert between time zones" "Impossible de convertir entre les fuseaux horaires"
|
||||||
@@ -160,3 +160,5 @@ TRANSLATE "Expecting weekday name" "Nom du jour de la semaine attendu"
|
|||||||
TRANSLATE "Duplicate argument name" "Nom de l'argument en double"
|
TRANSLATE "Duplicate argument name" "Nom de l'argument en double"
|
||||||
TRANSLATE "Expression evaluation is disabled" "L'évaluation de l'expression est désactivée"
|
TRANSLATE "Expression evaluation is disabled" "L'évaluation de l'expression est désactivée"
|
||||||
TRANSLATE "Time limit for expression evaluation exceeded" "Délai d'évaluation de l'expression dépassé"
|
TRANSLATE "Time limit for expression evaluation exceeded" "Délai d'évaluation de l'expression dépassé"
|
||||||
|
TRANSLATE "here" "ici"
|
||||||
|
TRANSLATE "did you mean" "voulais-vous dire"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Support for the Hellenic (Greek) language.
|
# Support for the Hellenic (Greek) language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by jarlaxl lamat (jarlaxl@freemail.gr)
|
# This file is derived from a translation by jarlaxl lamat (jarlaxl@freemail.gr)
|
||||||
|
|
||||||
TRANSLATE "LANGID" "gr"
|
TRANSLATE "LANGID" "gr"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Support for the Icelanding language.
|
# Support for the Icelanding language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Björn Davíðsson (bjossi@snerpa.is)
|
# This file is derived from a translation by Björn Davíðsson (bjossi@snerpa.is)
|
||||||
|
|
||||||
TRANSLATE "LANGID" "is"
|
TRANSLATE "LANGID" "is"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Support for the Italian language.
|
# Support for the Italian language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Valerio Aimale
|
# This file is derived from a translation by Valerio Aimale
|
||||||
|
|
||||||
TRANSLATE "LANGID" "it"
|
TRANSLATE "LANGID" "it"
|
||||||
|
|||||||
+4
-1
@@ -1,6 +1,6 @@
|
|||||||
# Support for the Dutch language.
|
# Support for the Dutch language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Willem Kasdorp and Erik-Jan Vens
|
# This file is derived from a translation by Willem Kasdorp and Erik-Jan Vens
|
||||||
|
|
||||||
TRANSLATE "LANGID" "nl"
|
TRANSLATE "LANGID" "nl"
|
||||||
@@ -86,3 +86,6 @@ TRANSLATE "Sunrise" "Zonsopgang"
|
|||||||
TRANSLATE "Sunset" "Zonsondergang"
|
TRANSLATE "Sunset" "Zonsondergang"
|
||||||
|
|
||||||
TRANSLATE "No reminders." "Geen herinneringen."
|
TRANSLATE "No reminders." "Geen herinneringen."
|
||||||
|
|
||||||
|
TRANSLATE "Daylight Saving Time Begins" "Daglicht-sparende tijd begint"
|
||||||
|
TRANSLATE "Daylight Saving Time Ends" "Daglicht-sparende tijd eindigt"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Support for the Norwegian language.
|
# Support for the Norwegian language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Trygve Randen
|
# This file is derived from a translation by Trygve Randen
|
||||||
|
|
||||||
TRANSLATE "LANGID" "no"
|
TRANSLATE "LANGID" "no"
|
||||||
|
|||||||
+10
-10
@@ -1,6 +1,6 @@
|
|||||||
# Support for the Polish language.
|
# Support for the Polish language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Jerzy Sobczyk
|
# This file is derived from a translation by Jerzy Sobczyk
|
||||||
|
|
||||||
TRANSLATE "LANGID" "pl"
|
TRANSLATE "LANGID" "pl"
|
||||||
@@ -146,19 +146,19 @@ TRANSLATE "Leaving UserFN" "Koniec UserFN"
|
|||||||
TRANSLATE "Expired" "Przemineło"
|
TRANSLATE "Expired" "Przemineło"
|
||||||
TRANSLATE "fork() failed - can't do queued reminders" "Niepowodzenie w funkcji fork() - nie mogę kolejkować przypomnień"
|
TRANSLATE "fork() failed - can't do queued reminders" "Niepowodzenie w funkcji fork() - nie mogę kolejkować przypomnień"
|
||||||
TRANSLATE "Can't access file" "Nie ma dostępu do pliku"
|
TRANSLATE "Can't access file" "Nie ma dostępu do pliku"
|
||||||
TRANSLATE "Illegal system date: Year is less than %d\n" "Błędna data systemowa: Rok mniejszy niż %d\n"
|
TRANSLATE "Illegal system date: Year is less than %d" "Błędna data systemowa: Rok mniejszy niż %d"
|
||||||
TRANSLATE "Unknown debug flag '%c'\n" "Nieznana flaga odpluskwiania '%c'\n"
|
TRANSLATE "Unknown debug flag '%c'" "Nieznana flaga odpluskwiania '%c'"
|
||||||
TRANSLATE "Unknown option '%c'\n" "Nieznana opcja '%c'\n"
|
TRANSLATE "Unknown option '%c'" "Nieznana opcja '%c'"
|
||||||
TRANSLATE "Unknown user '%s'\n" "Nieznany użytkownik '%s'\n"
|
TRANSLATE "Unknown user '%s'" "Nieznany użytkownik '%s'"
|
||||||
TRANSLATE "Could not change gid to %d\n" "Nie mogę zmienić gid na %d\n"
|
TRANSLATE "Could not change gid to %d" "Nie mogę zmienić gid na %d"
|
||||||
TRANSLATE "Could not change uid to %d\n" "Nie mogę zmienić uid na %d\n"
|
TRANSLATE "Could not change uid to %d" "Nie mogę zmienić uid na %d"
|
||||||
TRANSLATE "Out of memory for environment\n" "Brak pamięci na zmienne środowiska\n"
|
TRANSLATE "Out of memory for environment" "Brak pamięci na zmienne środowiska"
|
||||||
TRANSLATE "Missing '=' sign" "Brak znaku '='"
|
TRANSLATE "Missing '=' sign" "Brak znaku '='"
|
||||||
TRANSLATE "Missing variable name" "Brak nazwy zmiennej"
|
TRANSLATE "Missing variable name" "Brak nazwy zmiennej"
|
||||||
TRANSLATE "Missing expression" "Brak wyrażenia"
|
TRANSLATE "Missing expression" "Brak wyrażenia"
|
||||||
TRANSLATE "Remind: '-i' option: %s\n" "Remind: '-i' option: %s\n"
|
TRANSLATE "Remind: '-i' option: %s" "Remind: '-i' option: %s"
|
||||||
TRANSLATE "No reminders." "Brak przypomnień."
|
TRANSLATE "No reminders." "Brak przypomnień."
|
||||||
TRANSLATE "%d reminder(s) queued for later today.\n" "%d Przypomnienia zakolejkowane na później.\n"
|
TRANSLATE "%d reminder(s) queued for later today." "%d Przypomnienia zakolejkowane na później."
|
||||||
TRANSLATE "Expecting number" "Spodziewana liczba"
|
TRANSLATE "Expecting number" "Spodziewana liczba"
|
||||||
TRANSLATE "Undefined WARN function" "Nielegalna funkcja w klauzuli WARN:"
|
TRANSLATE "Undefined WARN function" "Nielegalna funkcja w klauzuli WARN:"
|
||||||
TRANSLATE "Can't convert between time zones" "Nie można konwertować między strefami czasowymi"
|
TRANSLATE "Can't convert between time zones" "Nie można konwertować między strefami czasowymi"
|
||||||
|
|||||||
+10
-10
@@ -1,6 +1,6 @@
|
|||||||
# Support for the (Brazilian) Portuguese language.
|
# Support for the (Brazilian) Portuguese language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Marco Paganini
|
# This file is derived from a translation by Marco Paganini
|
||||||
|
|
||||||
TRANSLATE "LANGID" "pt"
|
TRANSLATE "LANGID" "pt"
|
||||||
@@ -145,19 +145,19 @@ TRANSLATE "Leaving UserFN" "Saindo UserFN"
|
|||||||
TRANSLATE "Expired" "Expirou"
|
TRANSLATE "Expired" "Expirou"
|
||||||
TRANSLATE "fork() failed - can't do queued reminders" "fork() falhou - Nao posso processar compromissos na fila"
|
TRANSLATE "fork() failed - can't do queued reminders" "fork() falhou - Nao posso processar compromissos na fila"
|
||||||
TRANSLATE "Can't access file" "Nao consigo acessar o arquivo"
|
TRANSLATE "Can't access file" "Nao consigo acessar o arquivo"
|
||||||
TRANSLATE "Illegal system date: Year is less than %d\n" "Data do sistema ilegal: Ano e menor que %d\n"
|
TRANSLATE "Illegal system date: Year is less than %d" "Data do sistema ilegal: Ano e menor que %d"
|
||||||
TRANSLATE "Unknown debug flag '%c'\n" "Flag de debug desconhecido '%c'\n"
|
TRANSLATE "Unknown debug flag '%c'" "Flag de debug desconhecido '%c'"
|
||||||
TRANSLATE "Unknown option '%c'\n" "Opcao desconhecida '%c'\n"
|
TRANSLATE "Unknown option '%c'" "Opcao desconhecida '%c'"
|
||||||
TRANSLATE "Unknown user '%s'\n" "Usuario desconhecido '%s'\n"
|
TRANSLATE "Unknown user '%s'" "Usuario desconhecido '%s'"
|
||||||
TRANSLATE "Could not change gid to %d\n" "Nao consigo mudar gid para %d\n"
|
TRANSLATE "Could not change gid to %d" "Nao consigo mudar gid para %d"
|
||||||
TRANSLATE "Could not change uid to %d\n" "Nao consigo mudar uid para %d\n"
|
TRANSLATE "Could not change uid to %d" "Nao consigo mudar uid para %d"
|
||||||
TRANSLATE "Out of memory for environment\n" "Sem memoria para o environment\n"
|
TRANSLATE "Out of memory for environment" "Sem memoria para o environment"
|
||||||
TRANSLATE "Missing '=' sign" "Falta o sinal de '='"
|
TRANSLATE "Missing '=' sign" "Falta o sinal de '='"
|
||||||
TRANSLATE "Missing variable name" "Falta o nome da variavel"
|
TRANSLATE "Missing variable name" "Falta o nome da variavel"
|
||||||
TRANSLATE "Missing expression" "Falta a expressao"
|
TRANSLATE "Missing expression" "Falta a expressao"
|
||||||
TRANSLATE "Remind: '-i' option: %s\n" "Remind: '-i' opcao: %s\n"
|
TRANSLATE "Remind: '-i' option: %s" "Remind: '-i' opcao: %s"
|
||||||
TRANSLATE "No reminders." "Sem compromissos."
|
TRANSLATE "No reminders." "Sem compromissos."
|
||||||
TRANSLATE "%d reminder(s) queued for later today.\n" "%d compromisso(s) colocados na fila para mais tarde.\n"
|
TRANSLATE "%d reminder(s) queued for later today." "%d compromisso(s) colocados na fila para mais tarde."
|
||||||
TRANSLATE "Expecting number" "Esperando numero"
|
TRANSLATE "Expecting number" "Esperando numero"
|
||||||
TRANSLATE "Undefined WARN function" "Funcao ilegal na clausula WARN"
|
TRANSLATE "Undefined WARN function" "Funcao ilegal na clausula WARN"
|
||||||
TRANSLATE "Can't convert between time zones" "Não consigo converter entre fusos horários"
|
TRANSLATE "Can't convert between time zones" "Não consigo converter entre fusos horários"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Support for the Romanian language.
|
# Support for the Romanian language.
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
|
||||||
# This file is derived from a translation by Liviu Daia
|
# This file is derived from a translation by Liviu Daia
|
||||||
|
|
||||||
TRANSLATE "LANGID" "ro"
|
TRANSLATE "LANGID" "ro"
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
IF $CalMode || $PsCal
|
IF $CalMode || $PsCal
|
||||||
REM [moondate(0)] SPECIAL MOON 0 -1 -1 [moontime(0)]
|
REM [moondate(0)] INFO "Url: https://en.wikipedia.org/wiki/New_moon" SPECIAL MOON 0 -1 -1 [moontime(0)]
|
||||||
REM [moondate(1)] SPECIAL MOON 1 -1 -1 [moontime(1)]
|
REM [moondate(1)] INFO "Url: https://en.wikipedia.org/wiki/Lunar_phase" SPECIAL MOON 1 -1 -1 [moontime(1)]
|
||||||
REM [moondate(2)] SPECIAL MOON 2 -1 -1 [moontime(2)]
|
REM [moondate(2)] INFO "Url: https://en.wikipedia.org/wiki/Full_moon" SPECIAL MOON 2 -1 -1 [moontime(2)]
|
||||||
REM [moondate(3)] SPECIAL MOON 3 -1 -1 [moontime(3)]
|
REM [moondate(3)] INFO "Url: https://en.wikipedia.org/wiki/Lunar_phase" SPECIAL MOON 3 -1 -1 [moontime(3)]
|
||||||
ELSE
|
ELSE
|
||||||
REM NOQUEUE [moondatetime(0)] MSG %(New Moon) (%2)
|
REM NOQUEUE INFO "Url: https://en.wikipedia.org/wiki/New_moon" [moondatetime(0)] MSG %(New Moon) (%2)
|
||||||
REM NOQUEUE [moondatetime(1)] MSG %(First Quarter) (%2)
|
REM NOQUEUE INFO "Url: https://en.wikipedia.org/wiki/Lunar_phase" [moondatetime(1)] MSG %(First Quarter) (%2)
|
||||||
REM NOQUEUE [moondatetime(2)] MSG %(Full Moon) (%2)
|
REM NOQUEUE INFO "Url: https://en.wikipedia.org/wiki/Full_moon" [moondatetime(2)] MSG %(Full Moon) (%2)
|
||||||
REM NOQUEUE [moondatetime(3)] MSG %(Last Quarter) (%2)
|
REM NOQUEUE INFO "Url: https://en.wikipedia.org/wiki/Lunar_phase" [moondatetime(3)] MSG %(Last Quarter) (%2)
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|||||||
+8
-8
@@ -3,14 +3,14 @@
|
|||||||
|
|
||||||
IF $LatDeg >= 0
|
IF $LatDeg >= 0
|
||||||
# Northern Hemisphere
|
# Northern Hemisphere
|
||||||
REM NOQUEUE [soleq(0)] MSG %"%(Vernal Equinox)%" [$Is] %3.
|
REM NOQUEUE [soleq(0)] INFO "Url: https://en.wikipedia.org/wiki/March_equinox" MSG %"%(Vernal Equinox)%" [$Is] %3.
|
||||||
REM NOQUEUE [soleq(1)] MSG %"%(Summer Solstice)%" [$Is] %3.
|
REM NOQUEUE [soleq(1)] INFO "Url: https://en.wikipedia.org/wiki/Summer_solstice" MSG %"%(Summer Solstice)%" [$Is] %3.
|
||||||
REM NOQUEUE [soleq(2)] MSG %"%(Autumnal Equinox)%" [$Is] %3.
|
REM NOQUEUE [soleq(2)] INFO "Url: https://en.wikipedia.org/wiki/September_equinox" MSG %"%(Autumnal Equinox)%" [$Is] %3.
|
||||||
REM NOQUEUE [soleq(3)] MSG %"%(Winter Solstice)%" [$Is] %3.
|
REM NOQUEUE [soleq(3)] INFO "Url: https://en.wikipedia.org/wiki/Winter_solstice" MSG %"%(Winter Solstice)%" [$Is] %3.
|
||||||
ELSE
|
ELSE
|
||||||
# Southern Hemisphere
|
# Southern Hemisphere
|
||||||
REM NOQUEUE [soleq(0)] MSG %"%(Autumnal Equinox)%" [$Is] %3.
|
REM NOQUEUE [soleq(0)] INFO "Url: https://en.wikipedia.org/wiki/March_equinox" MSG %"%(Autumnal Equinox)%" [$Is] %3.
|
||||||
REM NOQUEUE [soleq(1)] MSG %"%(Winter Solstice)%" [$Is] %3.
|
REM NOQUEUE [soleq(1)] INFO "Url: https://en.wikipedia.org/wiki/Winter_solstice" MSG %"%(Winter Solstice)%" [$Is] %3.
|
||||||
REM NOQUEUE [soleq(2)] MSG %"%(Vernal Equinox)%" [$Is] %3.
|
REM NOQUEUE [soleq(2)] INFO "Url: https://en.wikipedia.org/wiki/September_equinox" MSG %"%(Vernal Equinox)%" [$Is] %3.
|
||||||
REM NOQUEUE [soleq(3)] MSG %"%(Summer Solstice)%" [$Is] %3.
|
REM NOQUEUE [soleq(3)] INFO "Url: https://en.wikipedia.org/wiki/Summer_solstice" MSG %"%(Summer Solstice)%" [$Is] %3.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|||||||
+88
-28
@@ -492,6 +492,13 @@ The filename in which the reminder was found.
|
|||||||
.B lineno \fIn\fR
|
.B lineno \fIn\fR
|
||||||
The line number within the file on which the reminder was found.
|
The line number within the file on which the reminder was found.
|
||||||
.TP
|
.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
|
.B nonconst_expr 1
|
||||||
If the reminder contained a non-constant expression that had to be evaluated
|
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.
|
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
|
If any TAG clauses are present, the \fBtags\fR key will be present and consist
|
||||||
of a comma-separated list of tags.
|
of a comma-separated list of tags.
|
||||||
.TP
|
.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
|
.B time \fIt\fR
|
||||||
If an AT clause was present, this key will contain the time of the AT clause
|
If an AT clause was present, this key will contain the time of the AT clause
|
||||||
in minutes after midnight.
|
in minutes after midnight.
|
||||||
@@ -637,70 +667,100 @@ However, back-ends should keep reading until EOF in case more data for
|
|||||||
subsequent months is forthcoming.
|
subsequent months is forthcoming.
|
||||||
.PP
|
.PP
|
||||||
|
|
||||||
.SH REM2PS PURE JSON INPUT FORMAT (-PPP OPTION)
|
.SH REM2PS PURE JSON INPUT FORMAT (-PPP OR -P+ OPTION)
|
||||||
\fBRemind \-ppp\fR emits \fIpure JSON\fR output. The format is
|
\fBRemind \-ppp\fR and \fBremind \-p+\fR emit \fIpure JSON\fR output.
|
||||||
as follows:
|
The format is as follows:
|
||||||
.PP
|
.PP
|
||||||
\fBRemind\fR outputs a JSON array. Each element of the array is a
|
\fBRemind\fR outputs a JSON array. Each element of the array is a
|
||||||
\fImonth descriptor\fR.
|
\fImonth descriptor\fR or a \fIweek descriptor\fR in the case of
|
||||||
|
\fBremind \-p+\fR.
|
||||||
.PP
|
.PP
|
||||||
Each month descriptor is a JSON object with the following elements:
|
Each descriptor is a JSON object with the following elements:
|
||||||
|
.TP
|
||||||
|
.B caltype \fItype\fR
|
||||||
|
The calendar type, either \fBmonthly\fR or \fBweekly\fR. Older versions
|
||||||
|
of \fBRemind\fR did not include a \fBcaltype\fR element, so a missing
|
||||||
|
\fBcaltype\fR should be treated as \fBmonthly\fR.
|
||||||
.TP
|
.TP
|
||||||
.B monthname \fIname\fR
|
.B monthname \fIname\fR
|
||||||
The name of the month.
|
The name of the month. Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B year \fIyyyy\fR
|
.B year \fIyyyy\fR
|
||||||
The year.
|
The year. Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B daysinmonnth \fIn\fR
|
.B daysinmonnth \fIn\fR
|
||||||
The number of days in the current month.
|
The number of days in the current month. Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B firstwkday \fIn\fR
|
.B firstwkday \fIn\fR
|
||||||
The weekday of the first day of the month (0 = Sunday, 1 = Monday, 6 = Saturday).
|
The weekday of the first day of the month (0 = Sunday, 1 = Monday, 6 = Saturday). Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B mondayfirst \fIn\fR
|
.B mondayfirst \fIn\fR
|
||||||
An indicator of whether or not the calendar week should start with
|
An indicator of whether or not the calendar week should start with
|
||||||
Sunday (n=0) or Monday (n=1).
|
Sunday (n=0) or Monday (n=1). Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B daynames \fR[\fIdays\fR]
|
.B daynames \fR[\fIdays\fR]
|
||||||
A seven-element array of day names; each element is a string representing
|
A seven-element array of day names; each element is a string representing
|
||||||
the names of the days from Sunday through Saturday.
|
the names of the days from Sunday through Saturday. Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B prevmonthname \fIname\fR
|
.B prevmonthname \fIname\fR
|
||||||
The name of the previous month.
|
The name of the previous month. Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B daysinprevmonth \fIn\fR
|
.B daysinprevmonth \fIn\fR
|
||||||
The number of days in the previous month.
|
The number of days in the previous month. Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B prevmonthyear \fIyyyy\fR
|
.B prevmonthyear \fIyyyy\fR
|
||||||
The year of the previous month. (The same as \fByear\fR unless the current
|
The year of the previous month. (The same as \fByear\fR unless the current
|
||||||
month is January.)
|
month is January.) Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B nextmonthname \fIname\fR
|
.B nextmonthname \fIname\fR
|
||||||
The name of the following month.
|
The name of the following month. Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B daysinnextmonth \fIn\fR
|
.B daysinnextmonth \fIn\fR
|
||||||
The number of days in the following month.
|
The number of days in the following month. Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B nextmonthyear \fIyyyy\fR
|
.B nextmonthyear \fIyyyy\fR
|
||||||
The year of the following month. (The same as \fByear\fR unless the
|
The year of the following month. (The same as \fByear\fR unless the
|
||||||
current month is December.)
|
current month is December.) Present in monthly calendar types only.
|
||||||
.TP
|
.TP
|
||||||
.B translations \fR{\fIobject\fR}
|
.B translations \fR{\fIobject\fR}
|
||||||
A complete dump of the Remind translation table. In output for multiple
|
A complete dump of the Remind translation table. In output for multiple
|
||||||
months, the translation table is included only with the first month.
|
months or weeks, the translation table is included only with the first month
|
||||||
|
or week. Present in both weekly and monthly calendar types.
|
||||||
.TP
|
.TP
|
||||||
.B entries \fR[\fIarray\fR]
|
.B entries \fR[\fIarray\fR]
|
||||||
The \fBentries\fR key consists of an array of calendar entries; each
|
The \fBentries\fR key, present in both weekly and monthly calendar
|
||||||
entry is a JSON object that has the same format as described in the
|
types, consists of an array of calendar entries; each entry is a JSON
|
||||||
\fBCALENDAR ENTRIES\fR section in the \fB\-PP FORMAT\fR section,
|
object that has the same format as described in the \fBCALENDAR
|
||||||
\fIwith the following difference\fR: In \fB\-PP\fR mode, if a reminder
|
ENTRIES\fR section in the \fB\-PP FORMAT\fR section, \fIwith the
|
||||||
has \fB%"\fR markers, only the text between the markers
|
following difference\fR: In \fB\-PP\fR mode, if a reminder has
|
||||||
is included in the \fBbody\fR element. In \fB\-PPP\fR mode, the
|
\fB%"\fR markers, only the text between the markers is included in the
|
||||||
entire text \fIincluding\fR the \fB%"\fR markers is included and it's up to
|
\fBbody\fR element. In \fB\-PPP\fR mode, the entire text
|
||||||
the back-end to extract the portion between the markers if that
|
\fIincluding\fR the \fB%"\fR markers is included and it's up to the
|
||||||
is desired.
|
back-end to extract the portion between the markers if that is
|
||||||
|
desired.
|
||||||
|
.TP
|
||||||
|
.B dates \fR[\fIarray\fR]
|
||||||
|
The \fBdates\fR key, present in weekly calendar types only,
|
||||||
|
contains seven entries; one for each column in the weekly
|
||||||
|
calendar. Each entry is a JSON object containing the following
|
||||||
|
key/value pairs:
|
||||||
|
.RS
|
||||||
|
.TP
|
||||||
|
.B date \fR\fIYYYY-MM-DD\fR
|
||||||
|
The date of the column.
|
||||||
|
.TP
|
||||||
|
.B day \fR\fIDD\fR
|
||||||
|
The day number of the column.
|
||||||
|
.TP
|
||||||
|
.B dayname \fR\fIweekday_name\fR
|
||||||
|
The name of the weekday (possibly localized).
|
||||||
|
.TP
|
||||||
|
.B month \fR\fImonth_name\fR
|
||||||
|
The name of the month (possibly localized).
|
||||||
|
.TP
|
||||||
|
.B year \fR\fIYYYY\fR
|
||||||
|
The year.
|
||||||
|
.RE
|
||||||
|
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
rem2ps was written by Dianne Skoll <dianne@skoll.ca>
|
rem2ps was written by Dianne Skoll <dianne@skoll.ca>
|
||||||
|
|||||||
+256
-86
@@ -182,12 +182,18 @@ If you immediately follow the \fBs\fR with the letter
|
|||||||
day they actually occur \fIas well as\fR on any preceding days specified
|
day they actually occur \fIas well as\fR on any preceding days specified
|
||||||
by the reminder's \fIdelta\fR.
|
by the reminder's \fIdelta\fR.
|
||||||
.TP
|
.TP
|
||||||
.B \-p\fR[\fBa\fR][\fBp\fR][\fBp\fR][\fBq\fR]\fIn\fR
|
.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
|
The \fB\-p\fR option is very similar to the \fB\-s\fR option, except
|
||||||
that the output contains additional information for use by the
|
that the output contains additional information for use by a back-end
|
||||||
\fBRem2PS\fR program, which creates a PostScript calendar, and various
|
such as the \fBRem2PS\fR program, which creates a PostScript calendar,
|
||||||
other back-end programs. For this
|
and various other back-end programs. If \fIn\fR starts with "+", then
|
||||||
option, \fIn\fR cannot start with "+"; it must specify a number of months.
|
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
|
The format of the \fB\-p\fR output is described in the \fBrem2ps(1)\fR
|
||||||
man page. If you immediately follow the \fBp\fR with the letter
|
man page. If you immediately follow the \fBp\fR with the letter
|
||||||
\fBa\fR, then \fBRemind\fR displays reminders on the calendar on the
|
\fBa\fR, then \fBRemind\fR displays reminders on the calendar on the
|
||||||
@@ -200,7 +206,10 @@ three p's, as in \fB\-ppp\fR, then \fBRemind\fR uses a pure JSON
|
|||||||
format, again documented in \fBrem2ps(1)\fR. If you include a \fBq\fR
|
format, again documented in \fBrem2ps(1)\fR. If you include a \fBq\fR
|
||||||
letter with this option, then the normal calendar-mode substitution filter
|
letter with this option, then the normal calendar-mode substitution filter
|
||||||
is disabled and the %"...%" sequences are preserved in the output.
|
is disabled and the %"...%" sequences are preserved in the output.
|
||||||
.RS
|
.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
|
.PP
|
||||||
The \fB\-p\fR, \fB\-pp\fR and \fB\-ppp\fR options implicitly enable
|
The \fB\-p\fR, \fB\-pp\fR and \fB\-ppp\fR options implicitly enable
|
||||||
the \fB\-o\fR option.
|
the \fB\-o\fR option.
|
||||||
@@ -310,6 +319,13 @@ Trace the reading of reminder files
|
|||||||
Trace expression parsing and display the internal expression node
|
Trace expression parsing and display the internal expression node
|
||||||
tree. This is unlikely to be useful unless you are working on
|
tree. This is unlikely to be useful unless you are working on
|
||||||
\fBRemind\fR's expression evaluation engine.
|
\fBRemind\fR's expression evaluation engine.
|
||||||
|
.TP
|
||||||
|
.B h
|
||||||
|
Dump hash-table statistics on exit.
|
||||||
|
.TP
|
||||||
|
.B q
|
||||||
|
Output a TRANSLATE command each time the \fB_()\fR built-in function
|
||||||
|
is called or the \fB%(...)\fR substitution sequence is encountered.
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
\fB\-g\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR]]]]
|
\fB\-g\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR]]]]
|
||||||
@@ -470,11 +486,13 @@ The \fB\-\-version\fR option causes \fBRemind\fR to print its version number
|
|||||||
to standard output and then exit.
|
to standard output and then exit.
|
||||||
.TP
|
.TP
|
||||||
.B \-\-print-errs
|
.B \-\-print-errs
|
||||||
The \fB\-\-print-errs\fR option causes \fBRemind\fR to print all possible
|
The \fB\-\-print-errs\fR option causes \fBRemind\fR to print all
|
||||||
error messages to standard output and then exit. The messages are printed
|
possible error messages to standard output and then exit. The
|
||||||
in a format suitable for the first argument of a TRANSLATE command. If
|
messages are printed in a format suitable for the first argument of a
|
||||||
you TRANSLATE the error messages, then \fBRemind\fR will use the translated
|
TRANSLATE command. If you TRANSLATE the error messages, then
|
||||||
versions when outputting error and warning messages.
|
\fBRemind\fR will use the translated versions when outputting error
|
||||||
|
and warning messages. See also TRANSLATE GENERATE in the section
|
||||||
|
"THE TRANSLATION TABLE".
|
||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
Note that if an untranslated message contains printf-style formatting
|
Note that if an untranslated message contains printf-style formatting
|
||||||
@@ -516,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
|
\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
|
killed. If \fIn\fR is specified as zero, then no limit is applied, just
|
||||||
as if the option had not been used at all.
|
as if the option had not been used at all.
|
||||||
|
.RS
|
||||||
.PP
|
.PP
|
||||||
If a limit is applied, it applies only to the foreground run of \fBRemind\fR.
|
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
|
If \fBRemind\fR finishes processing the script and then starts handling
|
||||||
queued reminders, the time limit is reset to no limit.
|
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
|
.SH REMINDER FILES
|
||||||
.PP
|
.PP
|
||||||
\fBRemind\fR uses scripts to control its operation. You can use any
|
\fBRemind\fR uses scripts to control its operation. You can use any
|
||||||
@@ -587,8 +610,9 @@ Its syntax is:
|
|||||||
[\fBSCANFROM\fR \fIscan_date\fR | \fBFROM\fR \fIstart_date\fR]
|
[\fBSCANFROM\fR \fIscan_date\fR | \fBFROM\fR \fIstart_date\fR]
|
||||||
[\fBDURATION\fR \fIduration\fR]
|
[\fBDURATION\fR \fIduration\fR]
|
||||||
[\fBTAG\fR \fItag\fR]
|
[\fBTAG\fR \fItag\fR]
|
||||||
<\fBMSG\fR | \fBMSF\fR | \fBRUN\fR | \fBCAL\fR | \fBSATISFY\fR |
|
[\fBINFO\fR "\fIinfo_string\fR"]
|
||||||
\fBSPECIAL\fR \fIspecial\fR | \fBPS\fR | \fBPSFILE\fR>
|
\fBMSG\fR | \fBMSF\fR | \fBRUN\fR | \fBCAL\fR | \fBSATISFY\fR |
|
||||||
|
\fBSPECIAL\fR \fIspecial\fR | \fBPS\fR | \fBPSFILE\fR
|
||||||
.I body
|
.I body
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
@@ -1324,7 +1348,7 @@ However, discussion must be deferred until after
|
|||||||
expressions and user-defined functions are explained. See the subsection
|
expressions and user-defined functions are explained. See the subsection
|
||||||
"PRECISE SCHEDULING" further on.
|
"PRECISE SCHEDULING" further on.
|
||||||
.PP
|
.PP
|
||||||
.B TAG AND DURATION
|
.B TAG, INFO AND DURATION
|
||||||
.PP
|
.PP
|
||||||
The \fBTAG\fR keyword lets you "tag" certain reminders. This facility
|
The \fBTAG\fR keyword lets you "tag" certain reminders. This facility
|
||||||
is used by certain back-ends or systems built around \fBRemind\fR,
|
is used by certain back-ends or systems built around \fBRemind\fR,
|
||||||
@@ -1343,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
|
command line. This lets you give a more-or-less unique identifier
|
||||||
to each distinct REM command.
|
to each distinct REM command.
|
||||||
.PP
|
.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
|
The \fBDURATION\fR keyword makes sense only for timed reminders; it
|
||||||
specifies the duration of an event. For example, if you have a
|
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:
|
90-minute meeting starting at 1:00pm, you could use any of the following:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
REM 5 March 2021 AT 13:00 DURATION 1:30 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 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 1:30 MSG Meeting
|
||||||
REM 5 March 2021 AT 1:00pm DURATION 90 MSG Meeting
|
REM 5 March 2021 AT 1:00pm DURATION 90 MSG Meeting
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
For long-duration reminders, it is convenient to use expressions
|
For long-duration reminders, it is convenient to use expressions
|
||||||
@@ -1381,26 +1430,26 @@ The REM command has syntactic sugar to let you express common
|
|||||||
reminders. The following pairs of reminders are equivalent:
|
reminders. The following pairs of reminders are equivalent:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
REM First Monday April MSG Foo
|
REM First Monday April MSG Foo
|
||||||
REM Mon 1 April MSG Foo
|
REM Mon 1 April MSG Foo
|
||||||
|
|
||||||
REM Second Monday May MSG Bar
|
REM Second Monday May MSG Bar
|
||||||
REM Mon 8 May MSG Bar
|
REM Mon 8 May MSG Bar
|
||||||
|
|
||||||
REM Third Monday 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 Mon 15 MSG Third Monday of every month
|
||||||
|
|
||||||
REM Fourth Sunday 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 Sun 22 June 2025 MSG Fourth Sunday in June 2025
|
||||||
|
|
||||||
REM Last Monday 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 Mon 1 --7 MSG Last Monday of every month
|
||||||
|
|
||||||
REM Last Monday April 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 Mon 1 May --7 MSG Last Monday of every April
|
||||||
|
|
||||||
REM Last Monday December 2025 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
|
REM Monday 1 Jan 2026 --7 MSG Last Monday of Dec 2025
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
Note that \fBLast\fR effectively adjusts the month and year, if necessary, to
|
Note that \fBLast\fR effectively adjusts the month and year, if necessary, to
|
||||||
@@ -1409,35 +1458,35 @@ make the reminder trigger on the correct date.
|
|||||||
The keyword \fBIN\fR is completely ignored, so you can write (for example):
|
The keyword \fBIN\fR is completely ignored, so you can write (for example):
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
REM Second Monday in May MSG foo
|
REM Second Monday in May MSG foo
|
||||||
REM Last Monday in December 2025 MSG Bar
|
REM Last Monday in December 2025 MSG Bar
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
An alternate form of \fIback\fR makes writing reminders easier.
|
An alternate form of \fIback\fR makes writing reminders easier.
|
||||||
The following groups of reminders are equivalent:
|
The following groups of reminders are equivalent:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
REM ~~1 MSG Last day of every month
|
REM ~~1 MSG Last day of every month
|
||||||
REM Lastday 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 --1 MSG Last day of every month
|
||||||
|
|
||||||
REM May ~~1 MSG Last day of May
|
REM May ~~1 MSG Last day of May
|
||||||
REM Lastday May MSG Last day of May
|
REM Lastday May MSG Last day of May
|
||||||
REM 1 June --1 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 Dec 2025 ~~1 MSG Last day of December 2025
|
||||||
REM Lastday Dec 2025 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 1 Jan 2026 --1 MSG Last day of December 2025
|
||||||
|
|
||||||
REM Apr ~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 Lastworkday April OMIT SAT SUN MSG Last workday of April
|
||||||
REM 1 May -1 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 Apr ~~7 MSG Seventh-last day of April
|
||||||
REM 1 May --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 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 1 May -2 OMIT SAT SUN MSG Second-last workday of April
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
As we see, "Lastday" is equivalent to ~~1 and "Lastworkday" to ~1.
|
As we see, "Lastday" is equivalent to ~~1 and "Lastworkday" to ~1.
|
||||||
@@ -1448,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:
|
must have at least one weekday name. The following are illegal:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
REM First Monday 3 June MSG Huh?
|
REM First Monday 3 June MSG Huh?
|
||||||
REM April 3 ~~1 MSG What?
|
REM April 3 ~~1 MSG What?
|
||||||
REM Second June MSG Where's the weekday???
|
REM Second June MSG Where's the weekday???
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
.SH THE SUBSTITUTION FILTER
|
.SH THE SUBSTITUTION FILTER
|
||||||
@@ -1616,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.
|
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.
|
It is the equivalent of [_("any_text")] but is more convenient to type.
|
||||||
.TP
|
.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 %_
|
.B %_
|
||||||
(percent-underscore) is replaced with a newline. You can use this to
|
(percent-underscore) is replaced with a newline. You can use this to
|
||||||
achieve multi-line reminders. Note that calendar back-ends vary in
|
achieve multi-line reminders. Note that calendar back-ends vary in
|
||||||
@@ -1927,19 +1981,18 @@ commands.
|
|||||||
.SH THE DO, INCLUDE AND SYSINCLUDE COMMANDS
|
.SH THE DO, INCLUDE AND SYSINCLUDE COMMANDS
|
||||||
.PP
|
.PP
|
||||||
\fBRemind\fR allows you to include other files in your reminder script,
|
\fBRemind\fR allows you to include other files in your reminder script,
|
||||||
similar to the C preprocessor #include directive. For example, your
|
similar to the C preprocessor #include directive. For example, you
|
||||||
system administrator may maintain a file of holidays or system-wide
|
might organize different reminders into different files like this:
|
||||||
reminders. You can include these in your reminder script as follows:
|
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
INCLUDE /usr/share/remind/holidays
|
INCLUDE holidays.rem
|
||||||
INCLUDE /usr/share/remind/reminders
|
INCLUDE birthdays.rem
|
||||||
|
INCLUDE "quote files with spaces.rem"
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
(The actual pathnames vary from system to system - ask your system
|
\fBINCLUDE\fR files can be nested up to a depth of 8. As shown above, if a
|
||||||
administrator.)
|
filename has spaces in it (not recommended!) you can use double-quotes
|
||||||
.PP
|
around the filename.
|
||||||
\fBINCLUDE\fR files can be nested up to a depth of 8.
|
|
||||||
.PP
|
.PP
|
||||||
If you specify a filename of "-" in the \fBINCLUDE\fR command, \fBRemind\fR
|
If you specify a filename of "-" in the \fBINCLUDE\fR command, \fBRemind\fR
|
||||||
will begin reading from standard input.
|
will begin reading from standard input.
|
||||||
@@ -1983,7 +2036,7 @@ symbolic links to files.
|
|||||||
.PP
|
.PP
|
||||||
The \fBSYSINCLUDE\fR command is similar to \fBDO\fR, but it looks for
|
The \fBSYSINCLUDE\fR command is similar to \fBDO\fR, but it looks for
|
||||||
relative pathnames under the system directory containing standard reminder
|
relative pathnames under the system directory containing standard reminder
|
||||||
scripts. For thie version of \fBRemind\fR, the system directory is
|
scripts. For this version of \fBRemind\fR, the system directory is
|
||||||
"@prefix@/share/remind".
|
"@prefix@/share/remind".
|
||||||
.PP
|
.PP
|
||||||
.SH THE RUN COMMAND
|
.SH THE RUN COMMAND
|
||||||
@@ -2210,6 +2263,10 @@ The following examples illustrate constants in \fBRemind\fR expressions:
|
|||||||
Note that the empty string is represented by "". Remind supports
|
Note that the empty string is represented by "". Remind supports
|
||||||
the escape sequences "\\a", "\\b", "\\f", "\\n", "\\r", "\\t"
|
the escape sequences "\\a", "\\b", "\\f", "\\n", "\\r", "\\t"
|
||||||
and "\\v" which have the same meanings as their counterparts in C.
|
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
|
To include a quote in a string, use "\\"". Any other character
|
||||||
preceded by a backslash is inserted into the string as-is, but the
|
preceded by a backslash is inserted into the string as-is, but the
|
||||||
backslash itself is removed. To include a backslash in a string,
|
backslash itself is removed. To include a backslash in a string,
|
||||||
@@ -2535,12 +2592,17 @@ Universal Time Coordinated in the \fB$MinsFromUTC\fR system variable.
|
|||||||
.B $CalMode (read-only)
|
.B $CalMode (read-only)
|
||||||
If non-zero, then the \fB\-c\fR option was supplied on the command line.
|
If non-zero, then the \fB\-c\fR option was supplied on the command line.
|
||||||
.TP
|
.TP
|
||||||
|
.B $CalType (read-only, STRING type)
|
||||||
|
If the \fB\-c\fR, \fB\-s\fR or \fB\-p\fR command-line options were
|
||||||
|
used, then this variable has the value "monthly". If \fB\-c+\fR,
|
||||||
|
\fB\-s+\fR or \fB\-p+\fR were used, then "weekly". Otherwise, "none".
|
||||||
|
.TP
|
||||||
.B $Daemon (read-only)
|
.B $Daemon (read-only)
|
||||||
If "daemon mode" \fB\-z\fR was invoked, contains the number of
|
If "daemon mode" \fB\-z\fR was invoked, contains the number of
|
||||||
minutes between wakeups. If not running in daemon mode, contains
|
minutes between wakeups. If not running in daemon mode, contains
|
||||||
0. In server mode (either \fB-z0\fR or \fB-zj\fR), contains -1.
|
0. In server mode (either \fB-z0\fR or \fB-zj\fR), contains -1.
|
||||||
.TP
|
.TP
|
||||||
.B $DateSep
|
.B $DateSep (STRING type)
|
||||||
This variable can be set only to "/" or "-". It holds the character
|
This variable can be set only to "/" or "-". It holds the character
|
||||||
used to separate portions of a date when \fBRemind\fR prints a DATE or
|
used to separate portions of a date when \fBRemind\fR prints a DATE or
|
||||||
DATETIME value.
|
DATETIME value.
|
||||||
@@ -2595,7 +2657,7 @@ print "bar". The third will not trigger because it's a duplicate of the
|
|||||||
first "foo".
|
first "foo".
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B $DefaultColor
|
.B $DefaultColor (STRING type)
|
||||||
This variable can be set to a string that has the form of three
|
This variable can be set to a string that has the form of three
|
||||||
space-separated numbers. Each number must be an integer from 0 to
|
space-separated numbers. Each number must be an integer from 0 to
|
||||||
255, or all three numbers must be -1. The default value of
|
255, or all three numbers must be -1. The default value of
|
||||||
@@ -2972,7 +3034,7 @@ Equivalent to \fByear(trigdate())\fR.
|
|||||||
.B $Tt (read-only, TIME type)
|
.B $Tt (read-only, TIME type)
|
||||||
Equivalent to \fBtrigtime()\fR.
|
Equivalent to \fBtrigtime()\fR.
|
||||||
.TP
|
.TP
|
||||||
.B $TimeSep
|
.B $TimeSep (STRING type)
|
||||||
This variable can be set only to ":" or ".". It holds the character
|
This variable can be set only to ":" or ".". It holds the character
|
||||||
used to separate portions of a time when \fBRemind\fR prints a TIME or
|
used to separate portions of a time when \fBRemind\fR prints a TIME or
|
||||||
DATETIME value.
|
DATETIME value.
|
||||||
@@ -3373,6 +3435,25 @@ Note that \fBeasterdate\fR computes the Western Easter. For the Orthodox
|
|||||||
Easter date, see \fBorthodoxeaster\fR.
|
Easter date, see \fBorthodoxeaster\fR.
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.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])
|
.B evaltrig(s_trigger [,dq_start])
|
||||||
Evaluates \fItrigger\fR as if it were a REM or IFTRIG trigger specification
|
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
|
and returns the trigger date as a \fBDATE\fR (or as a \fBDATETIME\fR if
|
||||||
@@ -3535,7 +3616,7 @@ clauses are \fInot\fR taken into account by this function.
|
|||||||
Returns a \fBSTRING\fR naming the compiled-in language supported by
|
Returns a \fBSTRING\fR naming the compiled-in language supported by
|
||||||
\fBRemind\fR. Remind used to support compiled-in support for other
|
\fBRemind\fR. Remind used to support compiled-in support for other
|
||||||
languages, but now all localization is done at run-time. As such,
|
languages, but now all localization is done at run-time. As such,
|
||||||
this function always returnes "English". However, the expression
|
this function always returns "English". However, the expression
|
||||||
\fB_("LANGID")\fR returns the two-character ISO 639 language code
|
\fB_("LANGID")\fR returns the two-character ISO 639 language code
|
||||||
of any language pack in effect, assuming the language pack author has
|
of any language pack in effect, assuming the language pack author has
|
||||||
written the localization correctly!
|
written the localization correctly!
|
||||||
@@ -3630,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
|
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.
|
in degrees. 0 is a new moon, 180 is a full moon, 90 is first-quarter, etc.
|
||||||
.TP
|
.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]])
|
.B multitrig(s_trig1 [,s_trig2, [... s_trigN]])
|
||||||
\fBmultitrig\fR evaluates each string as a trigger, similar to \fBevaltrig\fR,
|
\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.
|
and returns the \fIearliest\fR trigger date that is on or after \fBtoday()\fR.
|
||||||
@@ -3667,18 +3785,18 @@ In general, \fBmultitrig\fR works better with the Remind algorithm than
|
|||||||
reminder is issued at the end of each quarter:
|
reminder is issued at the end of each quarter:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
REM [multitrig("Mar 31", "Jun 30", "Sep 30", "Dec 31")] +7 MSG \\
|
REM [multitrig("Mar 31", "Jun 30", "Sep 30", "Dec 31")] +7 MSG \\
|
||||||
%"End of [ord($Tm/3)] quarter%" is %b.
|
%"End of [ord($Tm/3)] quarter%" is %b.
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
If you want the last working day of each quarter, you could use:
|
If you want the last working day of each quarter, you could use:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
PUSH-OMIT-CONTEXT
|
PUSH-OMIT-CONTEXT
|
||||||
OMIT Sat Sun
|
OMIT Sat Sun
|
||||||
REM [multitrig("Mar ~1", "Jun ~1", "Sep ~1", "Dec ~1")] +7 MSG \\
|
REM [multitrig("Mar ~1", "Jun ~1", "Sep ~1", "Dec ~1")] +7 MSG \\
|
||||||
%"Last working day of [ord($Tm/3)] quarter%" is %b.
|
%"Last working day of [ord($Tm/3)] quarter%" is %b.
|
||||||
POP-OMIT-CONTEXT
|
POP-OMIT-CONTEXT
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
Note that unlike \fBevaltrig\fR, \fBmultitrig\fR always returns a \fBDATE\fR
|
Note that unlike \fBevaltrig\fR, \fBmultitrig\fR always returns a \fBDATE\fR
|
||||||
@@ -3706,7 +3824,7 @@ are effectively swapped, so counting always begins from the older
|
|||||||
date.
|
date.
|
||||||
.PP
|
.PP
|
||||||
If the third argument to \fBnonomitted\fR is an \fBINT\fR, then it must
|
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:
|
\fBnonomitted\fR counts. For example the following expression:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
@@ -4220,7 +4338,23 @@ whose value is the maximum of "yyyy-mm-dd" and today.
|
|||||||
.B trigfrom()
|
.B trigfrom()
|
||||||
Returns (as a \fBDATE\fR type) the \fBFROM\fR parameter of the last \fBREM\fR or
|
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.
|
\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
|
.TP
|
||||||
.B trigger(d_date [,t_time [,i_utcflag]]) \fRor\fB trigger(q_datetime [,i_utcflag])
|
.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
|
Returns a string suitable for use in a \fBREM\fR command or a
|
||||||
@@ -5742,13 +5876,48 @@ function, as follows:
|
|||||||
By using \fBTRANSLATE\fR and \fB_\fR judiciously, you can make your
|
By using \fBTRANSLATE\fR and \fB_\fR judiciously, you can make your
|
||||||
reminder files easy to translate.
|
reminder files easy to translate.
|
||||||
.PP
|
.PP
|
||||||
\fBTRANSLATE\fR has three additional forms: If it is followed
|
\fBTRANSLATE\fR has four additional forms: If it is followed
|
||||||
by \fIone\fR quoted string instead of two, then \fBRemind\fR deletes the
|
by \fIone\fR quoted string instead of two, then \fBRemind\fR deletes the
|
||||||
translation table entry for that string. If it is followed by
|
translation table entry for that string. If it is followed by
|
||||||
the keyword \fBDUMP\fR, then \fBRemind\fR dumps all translation table entries
|
the keyword \fBDUMP\fR, then \fBRemind\fR dumps all translation table entries
|
||||||
to standard output. And if it is followed by \fBCLEAR\fR, then
|
to standard output. And if it is followed by \fBCLEAR\fR, then
|
||||||
\fBRemind\fR deletes all of the translation table entries.
|
\fBRemind\fR deletes all of the translation table entries.
|
||||||
.PP
|
.PP
|
||||||
|
The fourth form, \fBTRANSLATE GENERATE\fR, dumps all of the
|
||||||
|
strings that can be localized (as a series of TRANSLATE commands) to
|
||||||
|
standard output. Strings that are already localized are output
|
||||||
|
with their localization; strings that are not localized are
|
||||||
|
output as:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
TRANSLATE "untranslated" ""
|
||||||
|
.nf
|
||||||
|
.PP
|
||||||
|
If you want to add a new language, you can obtain a skeleton translation
|
||||||
|
file by running:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
echo "TRANSLATE GENERATE" | remind -h - > /tmp/skeleton.rem
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
If you have an existing language file that is missing some translations,
|
||||||
|
you can update it by running:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
(echo INCLUDE mylang.rem; echo TRANSLATE GENERATE) | \\
|
||||||
|
remind -h - > /tmp/mylang-update.rem
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
and then editing \fBmylang-update.rem\fR to add in the missing translations.
|
||||||
|
.PP
|
||||||
|
If you have some reminder scripts that use the \fB_()\fR built-in function
|
||||||
|
or \fB%(...)\fR substitution sequence, you can generate a list of needed
|
||||||
|
TRANSLATE commands by running:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
remind -q -n -dq myscript.rem 2>&1 | grep ^TRANSLATE | sort | uniq
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
Note that if you \fBSET\fR various translation-related system
|
Note that if you \fBSET\fR various translation-related system
|
||||||
variables such as \fB$Monday\fR, \fB$December\fR, \fB$Ago\fR, etc,
|
variables such as \fB$Monday\fR, \fB$December\fR, \fB$Ago\fR, etc,
|
||||||
then \fBRemind\fR \fIalso\fR makes a corresponding translation
|
then \fBRemind\fR \fIalso\fR makes a corresponding translation
|
||||||
@@ -6328,14 +6497,15 @@ Do not hard-code the above directory in your reminder files. Instead,
|
|||||||
use the value of the $SysInclude system variable.
|
use the value of the $SysInclude system variable.
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
.PP
|
.PP
|
||||||
Dianne Skoll <dianne@skoll.ca> wrote \fBRemind\fR. The moon code was
|
Dianne Skoll <dianne@skoll.ca> wrote \fBRemind\fR. The moon phase
|
||||||
copied largely unmodified from "moontool" by John Walker. The sunrise
|
code was copied largely unmodified from "moontool" by John Walker.
|
||||||
and sunset functions use ideas from programs by Michael Schwartz and
|
The moonrise/moonset code comes from
|
||||||
Marc T. Kaufman. The Hebrew calendar support was taken from "hdate"
|
https://github.com/signetica/MoonRise by Stephen R. Schmitt and Cyrus
|
||||||
by Amos Shapir. OS/2 support was done by Darrel Hankerson, Russ
|
Rahman. The sunrise and sunset functions use ideas from programs by
|
||||||
Herman, and Norman Walsh. The supported languages and their
|
Michael Schwartz and Marc T. Kaufman. The Hebrew calendar support was
|
||||||
translators are listed below. Languages marked "complete" support
|
taken from "hdate" by Amos Shapir. The supported languages and
|
||||||
error messages in that language; all others only support the
|
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.
|
substitution filter mechanism and month/day names.
|
||||||
.PP
|
.PP
|
||||||
\fBGerman\fR --
|
\fBGerman\fR --
|
||||||
|
|||||||
+15
-2
@@ -102,7 +102,11 @@ You can also specify advance notice, possibly repeating.
|
|||||||
The sixth control specifies what \fBRemind\fR should do if a reminder
|
The sixth control specifies what \fBRemind\fR should do if a reminder
|
||||||
falls on a holiday or weekend.
|
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 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
|
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
|
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
|
you can edit it in a text editor by either left- or right-clicking
|
||||||
on the reminder.
|
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
|
.SH ERRORS
|
||||||
|
|
||||||
@@ -512,7 +525,7 @@ asynchronous status messages.
|
|||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
TkRemind was written by Dianne Skoll <dianne@skoll.ca>
|
TkRemind was written by Dianne Skoll <dianne@skoll.ca>
|
||||||
|
|
||||||
\fBTkRemind\fR is Copyright 1996-2024 by Dianne Skoll.
|
\fBTkRemind\fR is Copyright (C) 1996-2025 by Dianne Skoll.
|
||||||
|
|
||||||
.SH FILES
|
.SH FILES
|
||||||
|
|
||||||
|
|||||||
+336
-74
@@ -20,18 +20,20 @@ my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mond
|
|||||||
my $TIDY_PROGNAME = $0;
|
my $TIDY_PROGNAME = $0;
|
||||||
$TIDY_PROGNAME =~ s|^.*/||;
|
$TIDY_PROGNAME =~ s|^.*/||;
|
||||||
|
|
||||||
# rem2html -- convert the output of "remind -pp" to HTML
|
# rem2html -- convert the output of "remind -pp" or "remind -ppp" to HTML
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
rem2html - Convert the output of "remind -pp" to HTML
|
rem2html - Convert the output of "remind -pp" or "remind -ppp" to HTML
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
remind -ppp [remind_options] file | rem2html [options]
|
||||||
|
|
||||||
remind -pp [remind_options] file | rem2html [options]
|
remind -pp [remind_options] file | rem2html [options]
|
||||||
|
|
||||||
You can also use the old interchange format as below, but the -pp
|
You can also use the old interchange format as below, but the -pp
|
||||||
version is preferred.
|
or -ppp versions are preferred.
|
||||||
|
|
||||||
remind -p [remind_options] file | rem2html [options]
|
remind -p [remind_options] file | rem2html [options]
|
||||||
|
|
||||||
@@ -126,6 +128,13 @@ The standard SPECIALs supported by all back-ends
|
|||||||
|
|
||||||
=back
|
=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
|
=head1 HIGHLIGHTING TODAY
|
||||||
|
|
||||||
Older versions of rem2html used to highlight today's date with a red outline.
|
Older versions of rem2html used to highlight today's date with a red outline.
|
||||||
@@ -155,9 +164,10 @@ sub usage
|
|||||||
$exit_status = 1;
|
$exit_status = 1;
|
||||||
}
|
}
|
||||||
print STDERR <<"EOM";
|
print STDERR <<"EOM";
|
||||||
$TIDY_PROGNAME: Produce an HTML calendar from the output of "remind -pp"
|
$TIDY_PROGNAME: Produce an HTML calendar from the output of "remind -pp[p]"
|
||||||
|
|
||||||
Usage: remind -pp [remind_options] file | rem2html [options]
|
Usage: remind -pp [remind_options] file | rem2html [options]
|
||||||
|
or: remind -ppp [remind_options] file | rem2html [options]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
@@ -303,6 +313,9 @@ sub parse_input
|
|||||||
my $found_data = 0;
|
my $found_data = 0;
|
||||||
while(<STDIN>) {
|
while(<STDIN>) {
|
||||||
chomp;
|
chomp;
|
||||||
|
if ($_ eq '[') {
|
||||||
|
return parse_input_ppp();
|
||||||
|
}
|
||||||
if (/# translations/) {
|
if (/# translations/) {
|
||||||
slurp_translations();
|
slurp_translations();
|
||||||
next;
|
next;
|
||||||
@@ -353,10 +366,14 @@ sub parse_input
|
|||||||
chomp;
|
chomp;
|
||||||
last if /^\# rem2ps2? end$/;
|
last if /^\# rem2ps2? end$/;
|
||||||
next if /^\#/;
|
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*(.*)$/) {
|
if (m/^(\d*).(\d*).(\d*)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/) {
|
||||||
($y, $m, $d, $special, $tag, $duration, $time, $body) =
|
($y, $m, $d, $special, $tag, $duration, $time, $body) =
|
||||||
($1, $2, $3, $4, $5, $6, $7, $8);
|
($1, $2, $3, $4, $5, $6, $7, $8);
|
||||||
|
$title = '';
|
||||||
} elsif (/\{/) {
|
} elsif (/\{/) {
|
||||||
my $obj;
|
my $obj;
|
||||||
if ($Options{utf8}) {
|
if ($Options{utf8}) {
|
||||||
@@ -365,6 +382,11 @@ sub parse_input
|
|||||||
$obj = decode_json($_);
|
$obj = decode_json($_);
|
||||||
}
|
}
|
||||||
next unless ($obj->{date} =~ /^(\d+)-(\d+)-(\d+)$/);
|
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;
|
$y = $1;
|
||||||
$m = $2;
|
$m = $2;
|
||||||
$d = $3;
|
$d = $3;
|
||||||
@@ -373,6 +395,7 @@ sub parse_input
|
|||||||
$duration = $obj->{duration} || '*';
|
$duration = $obj->{duration} || '*';
|
||||||
$time = $obj->{time} || '*';
|
$time = $obj->{time} || '*';
|
||||||
$body = $obj->{body};
|
$body = $obj->{body};
|
||||||
|
$title = info_to_title($obj->{info});
|
||||||
} else {
|
} else {
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
@@ -386,7 +409,8 @@ sub parse_input
|
|||||||
} elsif ($special eq 'WEEK') {
|
} elsif ($special eq 'WEEK') {
|
||||||
$body =~ s/^\s+//;
|
$body =~ s/^\s+//;
|
||||||
$body =~ s/\s+$//;
|
$body =~ s/\s+$//;
|
||||||
$weeks->{$d1} = $body;
|
$weeks->{$d1}->{body} = $body;
|
||||||
|
$weeks->{$d1}->{url} = $url;
|
||||||
} elsif ($special eq 'MOON') {
|
} elsif ($special eq 'MOON') {
|
||||||
if ($body =~ /(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) {
|
if ($body =~ /(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) {
|
||||||
my ($phase, $moonsize, $fontsize, $msg) = ($1, $2, $3, $4);
|
my ($phase, $moonsize, $fontsize, $msg) = ($1, $2, $3, $4);
|
||||||
@@ -396,6 +420,7 @@ sub parse_input
|
|||||||
$moons->[$d]->{'phase'} = $1;
|
$moons->[$d]->{'phase'} = $1;
|
||||||
$moons->[$d]->{'msg'} = '';
|
$moons->[$d]->{'msg'} = '';
|
||||||
}
|
}
|
||||||
|
$moons->[$d]->{url} = $url;
|
||||||
} elsif ($special eq 'SHADE') {
|
} elsif ($special eq 'SHADE') {
|
||||||
if ($body =~ /(\d+)\s+(\d+)\s+(\d+)/) {
|
if ($body =~ /(\d+)\s+(\d+)\s+(\d+)/) {
|
||||||
$shades->[$d] = sprintf("#%02X%02X%02X",
|
$shades->[$d] = sprintf("#%02X%02X%02X",
|
||||||
@@ -409,15 +434,202 @@ sub parse_input
|
|||||||
my($r, $g, $b, $text) = ($1, $2, $3, $4);
|
my($r, $g, $b, $text) = ($1, $2, $3, $4);
|
||||||
my $color = sprintf("style=\"color: #%02X%02X%02X;\"",
|
my $color = sprintf("style=\"color: #%02X%02X%02X;\"",
|
||||||
$r % 256, $g % 256, $b % 256);
|
$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 '*') {
|
} 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;
|
return $found_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub parse_input_ppp
|
||||||
|
{
|
||||||
|
my $json = "[\n";
|
||||||
|
my $curlies = 0;
|
||||||
|
my $did_a_calendar = 0;
|
||||||
|
while(<STDIN>) {
|
||||||
|
$json .= $_;
|
||||||
|
$curlies++ if ($_ eq "{\n");
|
||||||
|
$curlies-- if ($_ eq "}\n");
|
||||||
|
$curlies-- if ($_ eq "},\n");
|
||||||
|
if ($_ eq "]\n" && !$curlies) {
|
||||||
|
my $array;
|
||||||
|
eval {
|
||||||
|
if ($Options{utf8}) {
|
||||||
|
$array = decode_json(encode('UTF-8', $json, Encode::FB_DEFAULT));
|
||||||
|
} else {
|
||||||
|
$array = decode_json($json);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!$array) {
|
||||||
|
print STDERR "Could not decode JSON.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!$did_a_calendar) {
|
||||||
|
start_output();
|
||||||
|
$did_a_calendar = 1;
|
||||||
|
}
|
||||||
|
if (exists($array->[0]{caltype}) &&
|
||||||
|
$array->[0]{caltype} eq 'weekly') {
|
||||||
|
emit_ppp_calendars($array, 'weekly');
|
||||||
|
} else {
|
||||||
|
emit_ppp_calendars($array, 'monthly');
|
||||||
|
}
|
||||||
|
$json = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$did_a_calendar) {
|
||||||
|
print STDERR "$TIDY_PROGNAME: Could not find any calendar data on STDIN.\n";
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
end_output();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub emit_ppp_calendars
|
||||||
|
{
|
||||||
|
my ($array, $type) = @_;
|
||||||
|
foreach my $cal (@$array) {
|
||||||
|
emit_one_ppp_calendar($cal, $type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) = @_;
|
||||||
|
|
||||||
|
undef $days;
|
||||||
|
undef $shades;
|
||||||
|
undef $moons;
|
||||||
|
undef $classes;
|
||||||
|
undef $weeks;
|
||||||
|
|
||||||
|
my $dates_to_day_index;
|
||||||
|
my $cols_to_date_info;
|
||||||
|
if (exists($c->{translations})) {
|
||||||
|
$Translations = $c->{translations};
|
||||||
|
}
|
||||||
|
if ($type eq 'monthly') {
|
||||||
|
$Month = $c->{monthname};
|
||||||
|
$Year = $c->{year};
|
||||||
|
$Numdays = $c->{daysinmonth};
|
||||||
|
$Firstwkday = $c->{firstwkday};
|
||||||
|
$Mondayfirst = $c->{mondayfirst};
|
||||||
|
@Daynames = @{$c->{daynames}};
|
||||||
|
$Prevmon = $c->{prevmonthname};
|
||||||
|
$Prevlen = $c->{daysinprevmonth};
|
||||||
|
$Nextmon = $c->{nextmonthname};
|
||||||
|
$Nextlen = $c->{daysinnextmonth};
|
||||||
|
} else {
|
||||||
|
my $idx = 0;
|
||||||
|
$Numdays = 7;
|
||||||
|
foreach my $date (@{$c->{dates}}) {
|
||||||
|
$Daynames[$idx] = $date->{dayname};
|
||||||
|
$dates_to_day_index->{$date->{date}} = $idx;
|
||||||
|
$cols_to_date_info->[$idx] = $date;
|
||||||
|
$idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $class;
|
||||||
|
if ($Options{nostyle}) {
|
||||||
|
$class = '';
|
||||||
|
} else {
|
||||||
|
$class = ' class="rem-entry"';
|
||||||
|
}
|
||||||
|
foreach my $obj (@{$c->{entries}}) {
|
||||||
|
next unless ($obj->{date} =~ /^(\d+)-(\d+)-(\d+)$/);
|
||||||
|
my $y = $1;
|
||||||
|
my $m = $2;
|
||||||
|
my $d = $3;
|
||||||
|
my $col;
|
||||||
|
if ($type eq 'weekly') {
|
||||||
|
$col = $dates_to_day_index->{$obj->{date}};
|
||||||
|
} else {
|
||||||
|
$col = $d;
|
||||||
|
$col =~ s/^0+//;
|
||||||
|
}
|
||||||
|
my $special = $obj->{passthru} || '*';
|
||||||
|
my $tag = $obj->{tags} || '*';
|
||||||
|
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);
|
||||||
|
} elsif ($special eq 'HTMLCLASS') {
|
||||||
|
$classes->[$col] = $body;
|
||||||
|
} elsif ($special eq 'WEEK') {
|
||||||
|
$body =~ s/^\s+//;
|
||||||
|
$body =~ s/\s+$//;
|
||||||
|
$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);
|
||||||
|
$moons->[$col]->{'phase'} = $phase;
|
||||||
|
$moons->[$col]->{'msg'} = $msg;
|
||||||
|
} elsif ($body =~ /(\S+)/) {
|
||||||
|
$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",
|
||||||
|
($1 % 256), ($2 % 256), ($3 % 256));
|
||||||
|
} elsif ($body =~ /(\d+)/) {
|
||||||
|
$shades->[$col] = sprintf("#%02X%02X%02X",
|
||||||
|
($1 % 256), ($1 % 256), ($1 % 256));
|
||||||
|
}
|
||||||
|
} elsif ($special eq 'COLOR' || $special eq 'COLOUR') {
|
||||||
|
if ($body =~ /(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/s) {
|
||||||
|
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$title $color>" . $url_pre . fix_whitespace(escape_html($text)) . $url_post . '</p>');
|
||||||
|
}
|
||||||
|
} elsif ($special eq '*') {
|
||||||
|
push(@{$days->[$col]}, "<p$class$title>" . $url_pre . fix_whitespace(escape_html($body)) . $url_post . '</p>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output_calendar($type, $cols_to_date_info);
|
||||||
|
}
|
||||||
|
|
||||||
sub fix_whitespace
|
sub fix_whitespace
|
||||||
{
|
{
|
||||||
my ($text) = @_;
|
my ($text) = @_;
|
||||||
@@ -523,23 +735,33 @@ sub small_calendar
|
|||||||
sub output_calendar
|
sub output_calendar
|
||||||
{
|
{
|
||||||
# Which column is 1st of month in?
|
# Which column is 1st of month in?
|
||||||
my $first_col = $Firstwkday;
|
my ($type, $date_info) = @_;
|
||||||
if ($Mondayfirst) {
|
|
||||||
$first_col--;
|
|
||||||
if ($first_col < 0) {
|
|
||||||
$first_col = 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Last column
|
my ($first_col, $last_col, $number_of_rows);
|
||||||
my $last_col = ($first_col + $Numdays - 1) % 7;
|
|
||||||
|
|
||||||
# Figure out how many rows
|
if ($type eq 'monthly') {
|
||||||
my $number_of_rows = int(($first_col + $Numdays ) / 7 + 0.999);
|
$first_col = $Firstwkday;
|
||||||
|
if ($Mondayfirst) {
|
||||||
|
$first_col--;
|
||||||
|
if ($first_col < 0) {
|
||||||
|
$first_col = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Add a row for small calendars if necessary
|
# Last column
|
||||||
if ($first_col == 0 && $last_col == 6) {
|
$last_col = ($first_col + $Numdays - 1) % 7;
|
||||||
|
|
||||||
|
# Figure out how many rows
|
||||||
|
$number_of_rows = int(($first_col + $Numdays ) / 7 + 0.999);
|
||||||
|
|
||||||
|
# Add a row for small calendars if necessary
|
||||||
|
if ($first_col == 0 && $last_col == 6) {
|
||||||
$number_of_rows++;
|
$number_of_rows++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$first_col = 0;
|
||||||
|
$last_col = 6;
|
||||||
|
$number_of_rows = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Start the table
|
# Start the table
|
||||||
@@ -550,22 +772,36 @@ sub output_calendar
|
|||||||
print '<tr>';
|
print '<tr>';
|
||||||
$class = ' width="14%"';
|
$class = ' width="14%"';
|
||||||
} else {
|
} else {
|
||||||
print '<table class="rem-cal"><caption class="rem-cal-caption">' .
|
if ($type eq 'monthly') {
|
||||||
$Month . ' ' . $Year . '</caption>' . "\n";
|
print '<table class="rem-cal"><caption class="rem-cal-caption">' .
|
||||||
|
$Month . ' ' . $Year . '</caption>' . "\n";
|
||||||
|
} else {
|
||||||
|
print '<table class="rem-cal">' . "\n";
|
||||||
|
}
|
||||||
print '<tr class="rem-cal-hdr-row">';
|
print '<tr class="rem-cal-hdr-row">';
|
||||||
$class = ' class="rem-cal-hdr"';
|
$class = ' class="rem-cal-hdr"';
|
||||||
}
|
}
|
||||||
if (!$Mondayfirst) {
|
if ($type eq 'monthly') {
|
||||||
print "<th$class>" . $Daynames[0] . '</th>';
|
if (!$Mondayfirst) {
|
||||||
|
print "<th$class>" . $Daynames[0] . '</th>';
|
||||||
|
}
|
||||||
|
for (my $i=1; $i<7; $i++) {
|
||||||
|
print "<th$class>" . $Daynames[$i] . '</th>';
|
||||||
|
}
|
||||||
|
if ($Mondayfirst) {
|
||||||
|
print "<th$class>" . $Daynames[0] . '</th>';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (my $i=0; $i<7; $i++) {
|
||||||
|
my $inf = $date_info->[$i];
|
||||||
|
print "<th$class>" . $inf->{dayname} . "<br>" .
|
||||||
|
$inf->{day} . ' ' .
|
||||||
|
$inf->{month} . ' ' .
|
||||||
|
$inf->{year} . '</th>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (my $i=1; $i<7; $i++) {
|
|
||||||
print "<th$class>" . $Daynames[$i] . '</th>';
|
|
||||||
}
|
|
||||||
if ($Mondayfirst) {
|
|
||||||
print "<th$class>" . $Daynames[0] . '</th>';
|
|
||||||
}
|
|
||||||
print "</tr>\n";
|
|
||||||
|
|
||||||
|
print "</tr>\n";
|
||||||
# Start the calendar rows
|
# Start the calendar rows
|
||||||
my $col = 0;
|
my $col = 0;
|
||||||
if ($Options{nostyle}) {
|
if ($Options{nostyle}) {
|
||||||
@@ -573,16 +809,18 @@ sub output_calendar
|
|||||||
} else {
|
} else {
|
||||||
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
|
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
|
||||||
}
|
}
|
||||||
if ($first_col > 0) {
|
if ($type eq 'monthly') {
|
||||||
small_calendar($Prevmon, $Prevlen, $Options{backurl},
|
if ($first_col > 0) {
|
||||||
($Firstwkday - $Prevlen + 35) % 7);
|
small_calendar($Prevmon, $Prevlen, $Options{backurl},
|
||||||
$col++;
|
($Firstwkday - $Prevlen + 35) % 7);
|
||||||
}
|
$col++;
|
||||||
|
}
|
||||||
|
|
||||||
if ($last_col == 6 && $first_col > 0) {
|
if ($last_col == 6 && $first_col > 0) {
|
||||||
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
|
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
|
||||||
($Firstwkday + $Numdays) % 7);
|
($Firstwkday + $Numdays) % 7);
|
||||||
$col++;
|
$col++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ($Options{nostyle}) {
|
if ($Options{nostyle}) {
|
||||||
$class = ' width="14%"';
|
$class = ' width="14%"';
|
||||||
@@ -595,7 +833,7 @@ sub output_calendar
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (my $day=1; $day<=$Numdays; $day++) {
|
for (my $day=1; $day<=$Numdays; $day++) {
|
||||||
draw_day_cell($day, $number_of_rows);
|
draw_day_cell($day, $number_of_rows, $type);
|
||||||
$col++;
|
$col++;
|
||||||
if ($col == 7) {
|
if ($col == 7) {
|
||||||
$col = 0;
|
$col = 0;
|
||||||
@@ -610,32 +848,33 @@ sub output_calendar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($col) {
|
if ($type eq 'monthly') {
|
||||||
while ($col < 7) {
|
if ($col) {
|
||||||
if ($col == 5) {
|
while ($col < 7) {
|
||||||
if ($first_col == 0) {
|
if ($col == 5) {
|
||||||
small_calendar($Prevmon, $Prevlen, $Options{backurl},
|
if ($first_col == 0) {
|
||||||
($Firstwkday - $Prevlen + 35) % 7);
|
small_calendar($Prevmon, $Prevlen, $Options{backurl},
|
||||||
} else {
|
($Firstwkday - $Prevlen + 35) % 7);
|
||||||
print("<td$class> </td>\n");
|
} else {
|
||||||
}
|
print("<td$class> </td>\n");
|
||||||
} elsif ($col == 6) {
|
}
|
||||||
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
|
} elsif ($col == 6) {
|
||||||
($Firstwkday + $Numdays) % 7);
|
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
|
||||||
} else {
|
($Firstwkday + $Numdays) % 7);
|
||||||
print("<td$class> </td>\n");
|
} else {
|
||||||
}
|
print("<td$class> </td>\n");
|
||||||
$col++;
|
}
|
||||||
}
|
$col++;
|
||||||
print "</tr>\n";
|
}
|
||||||
}
|
print "</tr>\n";
|
||||||
|
}
|
||||||
|
|
||||||
# Add a row for small calendars if they were not yet done!
|
# Add a row for small calendars if they were not yet done!
|
||||||
if ($first_col == 0 && $last_col == 6) {
|
if ($first_col == 0 && $last_col == 6) {
|
||||||
if ($Options{nostyle}) {
|
if ($Options{nostyle}) {
|
||||||
print "<tr>\n";
|
print "<tr>\n";
|
||||||
} else {
|
} else {
|
||||||
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
|
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
|
||||||
}
|
}
|
||||||
small_calendar($Prevmon, $Prevlen, $Options{backurl},
|
small_calendar($Prevmon, $Prevlen, $Options{backurl},
|
||||||
($Firstwkday - $Prevlen + 35) % 7);
|
($Firstwkday - $Prevlen + 35) % 7);
|
||||||
@@ -645,18 +884,26 @@ sub output_calendar
|
|||||||
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
|
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
|
||||||
($Firstwkday + $Numdays) % 7);
|
($Firstwkday + $Numdays) % 7);
|
||||||
print("</tr>\n");
|
print("</tr>\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
# End the table
|
# End the table
|
||||||
print "</table>\n";
|
print "</table>\n";
|
||||||
|
if ($type eq 'weekly') {
|
||||||
|
print " <br />\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub draw_day_cell
|
sub draw_day_cell
|
||||||
{
|
{
|
||||||
my($day, $number_of_rows) = @_;
|
my($day, $number_of_rows, $type) = @_;
|
||||||
my $shade = $shades->[$day];
|
my $shade = $shades->[$day];
|
||||||
my $week = '';
|
my $week = '';
|
||||||
if (exists($weeks->{$day})) {
|
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;
|
my $class;
|
||||||
if ($Options{nostyle}) {
|
if ($Options{nostyle}) {
|
||||||
@@ -717,18 +964,33 @@ sub draw_day_cell
|
|||||||
$alt = 'last';
|
$alt = 'last';
|
||||||
$title = escape_html(t('Last Quarter'));
|
$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}) {
|
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 {
|
} 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>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Options{nostyle}) {
|
if ($type eq 'monthly') {
|
||||||
print "<div style=\"float: right\">$day$week</div>\n";
|
if ($Options{nostyle}) {
|
||||||
print "<p> </p>\n";
|
print "<div style=\"float: right\">$day$week</div>\n";
|
||||||
|
print "<p> </p>\n";
|
||||||
|
} else {
|
||||||
|
print "<div class=\"rem-daynumber\">$day$week</div>\n";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
print "<div class=\"rem-daynumber\">$day$week</div>\n";
|
if ($Options{nostyle}) {
|
||||||
|
print "<div style=\"float: right\">$week</div>\n";
|
||||||
|
print "<p> </p>\n";
|
||||||
|
} else {
|
||||||
|
print "<div class=\"rem-daynumber\">$week</div>\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ($days->[$day]) {
|
if ($days->[$day]) {
|
||||||
print(join("\n", @{$days->[$day]}));
|
print(join("\n", @{$days->[$day]}));
|
||||||
@@ -768,7 +1030,7 @@ while(1) {
|
|||||||
last if (!parse_input());
|
last if (!parse_input());
|
||||||
start_output() unless $found_something;
|
start_output() unless $found_something;
|
||||||
$found_something = 1;
|
$found_something = 1;
|
||||||
output_calendar();
|
output_calendar('monthly', undef);
|
||||||
}
|
}
|
||||||
if ($found_something) {
|
if ($found_something) {
|
||||||
end_output();
|
end_output();
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ WriteMakefile(
|
|||||||
'Getopt::Long' => 0,
|
'Getopt::Long' => 0,
|
||||||
'Cairo' => 0,
|
'Cairo' => 0,
|
||||||
'Pango' => 0,
|
'Pango' => 0,
|
||||||
|
'JSON::MaybeXS' => 0,
|
||||||
|
'Encode' => 0,
|
||||||
},
|
},
|
||||||
EXE_FILES => [ 'bin/rem2pdf' ]
|
EXE_FILES => [ 'bin/rem2pdf' ]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,16 +7,18 @@ bindir=@bindir@
|
|||||||
datadir=@datadir@
|
datadir=@datadir@
|
||||||
datarootdir=@datarootdir@
|
datarootdir=@datarootdir@
|
||||||
PERL=@PERL@
|
PERL=@PERL@
|
||||||
PERLMODS_NEEDED=Getopt::Long Cairo Pango
|
PERLMODS_NEEDED=Cairo Encode ExtUtils::MakeMaker Getopt::Long JSON::MaybeXS Pango
|
||||||
|
|
||||||
all: Makefile
|
all: Makefile
|
||||||
@if test "$(PERL)" = "" ; then \
|
@if test "$(PERL)" = "" ; then \
|
||||||
echo "Not building rem2pdf; Perl is required"; exit 0; fi; \
|
echo "Not building rem2pdf; Perl is required"; exit 0; fi; \
|
||||||
|
OK=1; \
|
||||||
for m in $(PERLMODS_NEEDED) ; \
|
for m in $(PERLMODS_NEEDED) ; \
|
||||||
do \
|
do \
|
||||||
$(PERL) -M$$m -e 1 > /dev/null 2>&1; \
|
$(PERL) -M$$m -e 1 ; \
|
||||||
if test $$? != 0 ; then echo "Not building rem2pdf; missing $$m"; exit 0; fi; \
|
if test $$? != 0 ; then echo "Missing Perl module: $$m"; OK=0; fi; \
|
||||||
done; \
|
done; \
|
||||||
|
if test "$$OK" != "1" ; then echo "Not building rem2pdf because of missing perl module(s)"; exit 0; fi; \
|
||||||
$(MAKE) all && exit 0; \
|
$(MAKE) all && exit 0; \
|
||||||
exit 1;
|
exit 1;
|
||||||
|
|
||||||
@@ -25,7 +27,7 @@ install:
|
|||||||
echo "Not installing rem2pdf; Perl is required"; exit 0; fi; \
|
echo "Not installing rem2pdf; Perl is required"; exit 0; fi; \
|
||||||
for m in $(PERLMODS_NEEDED) ; \
|
for m in $(PERLMODS_NEEDED) ; \
|
||||||
do \
|
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; \
|
if test $$? != 0 ; then echo "Not installing rem2pdf; missing $$m"; exit 0; fi; \
|
||||||
done; \
|
done; \
|
||||||
echo "Installing rem2pdf"; \
|
echo "Installing rem2pdf"; \
|
||||||
|
|||||||
+36
-13
@@ -64,6 +64,8 @@ my $settings = {
|
|||||||
ps => 0,
|
ps => 0,
|
||||||
eps => 0,
|
eps => 0,
|
||||||
verbose => 0,
|
verbose => 0,
|
||||||
|
|
||||||
|
weeks_per_page => 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
my $me = $0;
|
my $me = $0;
|
||||||
@@ -81,17 +83,18 @@ Usage: remind -pp [options] filename | $me [options] > out.pdf
|
|||||||
Options:
|
Options:
|
||||||
|
|
||||||
--landscape, -l Print in landscape orientation
|
--landscape, -l Print in landscape orientation
|
||||||
--small-calendars=N Choose location for small calendars
|
--small-calendars=N Location for small calendars (monthly calendars only)
|
||||||
--svg Output SVG instead of PDF
|
--svg Output SVG instead of PDF
|
||||||
--ps Output PostScript instead of PDF
|
--ps Output PostScript instead of PDF
|
||||||
--eps Output encapsulated PostScript instead of PDF
|
--eps Output encapsulated PostScript instead of PDF
|
||||||
-cN Synonym for --small-calendars=N
|
-cN Synonym for --small-calendars=N
|
||||||
--left-numbers, -x Print day numbers on the left
|
--left-numbers, -x Print day numbers on the left (monthly calendars only)
|
||||||
--fill-page, -e Fill the entire page
|
--fill-page, -e Fill the entire page (monthly calendars only)
|
||||||
--media=MEDIA, -mMEDIA Size for specified media
|
--media=MEDIA, -mMEDIA Size for specified media
|
||||||
--width=W, -wW Specify media width in 1/72nds of an inch
|
--width=W, -wW Specify media width in 1/72nds of an inch
|
||||||
--height=H, -hH Specify media height in 1/72nds of an inch
|
--height=H, -hH Specify media height in 1/72nds of an inch
|
||||||
--wrap, -y Make calendar fit in at most 5 rows
|
--wrap, -y Make calendar fit in 5 rows (monthly calendars only)
|
||||||
|
--weeks-per-page=N, -pN Number of weeks per page (weekly calendars only)
|
||||||
--title-font=FONT Specify font for calendar title
|
--title-font=FONT Specify font for calendar title
|
||||||
--header-font=FONT Specify font for weekday names
|
--header-font=FONT Specify font for weekday names
|
||||||
--daynum-font=FONT Specify font for day numbers
|
--daynum-font=FONT Specify font for day numbers
|
||||||
@@ -121,6 +124,7 @@ my $ret = GetOptions('landscape|l' => \$settings->{landscape},
|
|||||||
'ps' => \$settings->{ps},
|
'ps' => \$settings->{ps},
|
||||||
'eps' => \$settings->{eps},
|
'eps' => \$settings->{eps},
|
||||||
'fill-page|e' => \$settings->{fill_entire_page},
|
'fill-page|e' => \$settings->{fill_entire_page},
|
||||||
|
'weeks-per-page|p=i' => \$settings->{weeks_per_page},
|
||||||
'media|m=s' => \$settings->{media},
|
'media|m=s' => \$settings->{media},
|
||||||
'width|w=i' => \$settings->{width},
|
'width|w=i' => \$settings->{width},
|
||||||
'wrap|y' => \$settings->{wrap_calendar},
|
'wrap|y' => \$settings->{wrap_calendar},
|
||||||
@@ -153,6 +157,12 @@ if ($help) {
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($settings->{weeks_per_page} < 1) {
|
||||||
|
$settings->{weeks_per_page} = 1;}
|
||||||
|
elsif ($settings->{weeks_per_page} > 4) {
|
||||||
|
$settings->{weeks_per_page} = 4;
|
||||||
|
}
|
||||||
|
|
||||||
if ($settings->{width} <= 0 ||
|
if ($settings->{width} <= 0 ||
|
||||||
$settings->{height} <= 0) {
|
$settings->{height} <= 0) {
|
||||||
my $size = $media_to_size->{ucfirst($settings->{media})};
|
my $size = $media_to_size->{ucfirst($settings->{media})};
|
||||||
@@ -247,6 +257,7 @@ if ($settings->{ps} && $settings->{landscape}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
my $warned = 0;
|
my $warned = 0;
|
||||||
|
my $index = 0;
|
||||||
while(1) {
|
while(1) {
|
||||||
if ($settings->{ps}) {
|
if ($settings->{ps}) {
|
||||||
$surface->dsc_begin_page_setup();
|
$surface->dsc_begin_page_setup();
|
||||||
@@ -267,14 +278,8 @@ while(1) {
|
|||||||
}
|
}
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
if (($settings->{eps} || $settings->{svg}) && $done_one) {
|
$index++;
|
||||||
if (!$warned) {
|
$obj->render($cr, $settings, $index, -1);
|
||||||
print STDERR "WARNING: --eps and --svg can only output one page; ignoring subsequent\nmonths in a multi-month calendar.\n";
|
|
||||||
$warned = 1;
|
|
||||||
}
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
$obj->render($cr, $settings);
|
|
||||||
$done_one = 1;
|
$done_one = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,7 +397,7 @@ month. Possible values for I<n> are:
|
|||||||
|
|
||||||
=item Z<>0
|
=item Z<>0
|
||||||
|
|
||||||
Do not draw any small calendares
|
Do not draw any small calendars
|
||||||
|
|
||||||
=item Z<>1
|
=item Z<>1
|
||||||
|
|
||||||
@@ -521,6 +526,11 @@ first row of the calendar, and adjust the small calendar positions
|
|||||||
as needed. This results in a calendar that only requires 5 rows, but
|
as needed. This results in a calendar that only requires 5 rows, but
|
||||||
with the last day or two appearing in the I<first> row.
|
with the last day or two appearing in the I<first> row.
|
||||||
|
|
||||||
|
=item --weeks-per-page=I<n>, -pI<n>.
|
||||||
|
|
||||||
|
This option is only used for weekly calendars. I<n> is the number of weeks
|
||||||
|
to print per page; it is an integer that can range from 1 to 4.
|
||||||
|
|
||||||
=item --verbose, -v
|
=item --verbose, -v
|
||||||
|
|
||||||
Print (on STDERR) the name of the month and year for each month that
|
Print (on STDERR) the name of the month and year for each month that
|
||||||
@@ -563,6 +573,19 @@ it is syntactically correct. If you use invalid Pango markup, the
|
|||||||
Pango library will print a warning and B<rem2pdf> will not render any
|
Pango library will print a warning and B<rem2pdf> will not render any
|
||||||
output for the invalid reminder.
|
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
|
||||||
|
B<-p+> option. the B<--weeks-per-page> option specifies how many
|
||||||
|
weeks' worth of reminders to print per page, and can range from 1 to 4.
|
||||||
|
|
||||||
=head1 ABSOLUTELY-POSITIONED TEXT
|
=head1 ABSOLUTELY-POSITIONED TEXT
|
||||||
|
|
||||||
If your B<PANGO> special reminder starts with C<@I<x>,I<y>> where I<x>
|
If your B<PANGO> special reminder starts with C<@I<x>,I<y>> where I<x>
|
||||||
|
|||||||
+281
-23
@@ -62,6 +62,9 @@ sub create_from_hash
|
|||||||
{
|
{
|
||||||
my ($class, $hash, $specials_accepted) = @_;
|
my ($class, $hash, $specials_accepted) = @_;
|
||||||
|
|
||||||
|
if (exists($hash->{caltype}) && ($hash->{caltype} eq 'weekly')) {
|
||||||
|
return Remind::PDF::Weekly->create_from_hash($hash, $specials_accepted);
|
||||||
|
}
|
||||||
bless $hash, $class;
|
bless $hash, $class;
|
||||||
|
|
||||||
my $filtered_entries = [];
|
my $filtered_entries = [];
|
||||||
@@ -463,8 +466,16 @@ C<rem2pdf> for the contents of C<$settings>
|
|||||||
=cut
|
=cut
|
||||||
sub render
|
sub render
|
||||||
{
|
{
|
||||||
my ($self, $cr, $settings) = @_;
|
my ($self, $cr, $settings, $index, $total) = @_;
|
||||||
|
|
||||||
|
if ($settings->{svg} || $settings->{eps}) {
|
||||||
|
if ($index > 1) {
|
||||||
|
if ($index == 2) {
|
||||||
|
print STDERR "WARNING: --svg/--eps can only output one page; ignoring subsequent\nmonths in a multi-month calendar.\n";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
$self->setup_daymap($settings);
|
$self->setup_daymap($settings);
|
||||||
$self->{horiz_lines} = [];
|
$self->{horiz_lines} = [];
|
||||||
$cr->set_line_cap('square');
|
$cr->set_line_cap('square');
|
||||||
@@ -525,7 +536,7 @@ sub render
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($settings->{verbose}) {
|
if ($settings->{verbose}) {
|
||||||
print STDERR "remdp2f: Rendered " . $self->{monthname} . ' ' . $self->{year} . "\n";
|
print STDERR "rem2pdf: Rendered " . $self->{monthname} . ' ' . $self->{year} . "\n";
|
||||||
}
|
}
|
||||||
# Done this page
|
# Done this page
|
||||||
$cr->show_page();
|
$cr->show_page();
|
||||||
@@ -810,7 +821,6 @@ sub draw_small_calendar
|
|||||||
$layout->set_text('88 ');
|
$layout->set_text('88 ');
|
||||||
my ($wid, $h) = $layout->get_pixel_size();
|
my ($wid, $h) = $layout->get_pixel_size();
|
||||||
$h += 1;
|
$h += 1;
|
||||||
|
|
||||||
# Month name
|
# Month name
|
||||||
$layout = Pango::Cairo::create_layout($cr);
|
$layout = Pango::Cairo::create_layout($cr);
|
||||||
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
|
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
|
||||||
@@ -824,6 +834,7 @@ sub draw_small_calendar
|
|||||||
|
|
||||||
$y += $h;
|
$y += $h;
|
||||||
# Day names
|
# Day names
|
||||||
|
$wid = $width / 7;
|
||||||
for (my $col=0; $col <7; $col++) {
|
for (my $col=0; $col <7; $col++) {
|
||||||
my $j;
|
my $j;
|
||||||
if ($self->{mondayfirst}) {
|
if ($self->{mondayfirst}) {
|
||||||
@@ -849,7 +860,11 @@ sub draw_small_calendar
|
|||||||
for (my $d=1; $d <= $days; $d++) {
|
for (my $d=1; $d <= $days; $d++) {
|
||||||
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
|
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
|
||||||
$layout->set_font_description($desc);
|
$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->save();
|
||||||
$cr->move_to($x + $col*$wid, $y);
|
$cr->move_to($x + $col*$wid, $y);
|
||||||
Pango::Cairo::show_layout($cr, $layout);
|
Pango::Cairo::show_layout($cr, $layout);
|
||||||
@@ -881,20 +896,23 @@ sub calculate_small_calendar_font_size
|
|||||||
my $font_size = int($scale * 10);
|
my $font_size = int($scale * 10);
|
||||||
|
|
||||||
# Check
|
# Check
|
||||||
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
|
while(1) {
|
||||||
$layout->set_font_description($desc);
|
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
|
||||||
$layout->set_text('88 88 88 88 88 88 88');
|
$layout->set_font_description($desc);
|
||||||
($wid, $h) = $layout->get_pixel_size();
|
$layout->set_text('88 88 88 88 88 88 88');
|
||||||
$h += 1;
|
($wid, $h) = $layout->get_pixel_size();
|
||||||
$h *= ($rows + 2); # row for month name; row for day names
|
$h += 1;
|
||||||
|
$h *= ($rows + 2); # row for month name; row for day names
|
||||||
|
|
||||||
$scale = $width / $wid;
|
$scale = $width / $wid;
|
||||||
if (($height / $h) < $scale) {
|
if (($height / $h) < $scale) {
|
||||||
$scale = $height / $h;
|
$scale = $height / $h;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($scale < 1) { # Font size is too big
|
if ($scale >= 1) { # Font size is OK
|
||||||
$font_size--;
|
last;
|
||||||
|
}
|
||||||
|
$font_size -= 0.1;
|
||||||
}
|
}
|
||||||
return $font_size;
|
return $font_size;
|
||||||
}
|
}
|
||||||
@@ -1008,20 +1026,260 @@ as were read from the C<remind -ppp> stream
|
|||||||
sub render
|
sub render
|
||||||
{
|
{
|
||||||
my ($self, $cr, $settings) = @_;
|
my ($self, $cr, $settings) = @_;
|
||||||
my $done = 0;
|
my $index = 0;
|
||||||
my $warned = 0;
|
my $total = scalar(@{$self->{entries}});
|
||||||
|
|
||||||
foreach my $e (@{$self->{entries}}) {
|
foreach my $e (@{$self->{entries}}) {
|
||||||
if ($settings->{svg} && $done) {
|
$index++;
|
||||||
if (!$warned) {
|
$e->render($cr, $settings, $index, $total);
|
||||||
print STDERR "WARNING: --svg can only output one page; ignoring subsequent\nmonths in a multi-month calendar.\n";
|
}
|
||||||
$warned = 1;
|
}
|
||||||
|
|
||||||
|
package Remind::PDF::Weekly;
|
||||||
|
use base qw(Remind::PDF);
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Remind::PDF::Weekly - render a weekly calendar
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub render
|
||||||
|
{
|
||||||
|
my ($self, $cr, $settings, $index, $total) = @_;
|
||||||
|
if ($settings->{svg} || $settings->{eps}) {
|
||||||
|
if ($index > $settings->{weeks_per_page}) {
|
||||||
|
if ($index == $settings->{weeks_per_page}+1) {
|
||||||
|
print STDERR "WARNING: --svg/--eps can only output one page; ignoring subsequent pages.\n";
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$settings->{numbers_on_left} = 1;
|
||||||
|
# Set up bounding box
|
||||||
|
if ($settings->{weeks_per_page} == 1) {
|
||||||
|
$self->{bounding_box} = [
|
||||||
|
$settings->{margin_left},
|
||||||
|
$settings->{margin_top},
|
||||||
|
$settings->{width} - $settings->{margin_right},
|
||||||
|
$settings->{height} - $settings->{margin_bottom}]
|
||||||
|
} else {
|
||||||
|
my $total_height = $settings->{height} - $settings->{margin_top} - $settings->{margin_bottom};
|
||||||
|
my $week_height = $total_height / $settings->{weeks_per_page};
|
||||||
|
my $top_offset = (($index-1) % $settings->{weeks_per_page}) * $week_height;
|
||||||
|
my $bot_offset = $top_offset + $week_height;
|
||||||
|
$self->{bounding_box} =
|
||||||
|
$self->{bounding_box} = [
|
||||||
|
$settings->{margin_left},
|
||||||
|
$settings->{margin_top} + $top_offset,
|
||||||
|
$settings->{width} - $settings->{margin_right},
|
||||||
|
$settings->{margin_top} + $bot_offset];
|
||||||
|
if ($index != 1) {
|
||||||
|
$self->{bounding_box}[1] += 0.25 * $settings->{margin_top};
|
||||||
|
}
|
||||||
|
if ($index != $settings->{weeks_per_page}) {
|
||||||
|
$self->{bounding_box}[3] -= 0.25 * $settings->{margin_top};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$self->draw_headings($cr, $settings);
|
||||||
|
for (my $i=0; $i<7; $i++) {
|
||||||
|
$self->draw_entries($cr, $settings, $i);
|
||||||
|
}
|
||||||
|
$self->draw_lines($cr, $settings);
|
||||||
|
if ($index == $total || ($index % $settings->{weeks_per_page}) == 0) {
|
||||||
|
$cr->show_page();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($settings->{verbose}) {
|
||||||
|
print STDERR "rem2pdf: Rendered " . $self->{dates}->[0]->{date} . " to " . $self->{dates}->[6]->{date} . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub draw_headings
|
||||||
|
{
|
||||||
|
my ($self, $cr, $settings) = @_;
|
||||||
|
my $ymax = 0;
|
||||||
|
my $cell = ($settings->{width} - $settings->{margin_left} - $settings->{margin_right})/7;
|
||||||
|
|
||||||
|
for (my $i=0; $i<7; $i++) {
|
||||||
|
my $date = $self->{dates}[$i];
|
||||||
|
my $month = $date->{month};
|
||||||
|
my $year = $date->{year};
|
||||||
|
my $day = $date->{day};
|
||||||
|
my $dayname = $date->{dayname};
|
||||||
|
|
||||||
|
my $layout = Pango::Cairo::create_layout($cr);
|
||||||
|
$layout->set_text(Encode::decode('UTF-8', $dayname));
|
||||||
|
|
||||||
|
my $desc = Pango::FontDescription->from_string($settings->{header_font} . ' ' . $settings->{header_size} . 'px');
|
||||||
|
$layout->set_font_description($desc);
|
||||||
|
|
||||||
|
my ($wid, $h) = $layout->get_pixel_size();
|
||||||
|
$cr->save;
|
||||||
|
$cr->move_to($settings->{margin_left} + $i * $cell + $cell/2 - $wid/2, $self->{bounding_box}[1]);
|
||||||
|
Pango::Cairo::show_layout($cr, $layout);
|
||||||
|
$cr->restore();
|
||||||
|
|
||||||
|
$layout = Pango::Cairo::create_layout($cr);
|
||||||
|
$layout->set_text(Encode::decode('UTF-8', $day . " " . $month . " " . $year));
|
||||||
|
my $es = $settings->{entry_size};
|
||||||
|
if ($es > 8) {
|
||||||
|
$es = 8;
|
||||||
|
}
|
||||||
|
$desc = Pango::FontDescription->from_string($settings->{entry_font} . ' ' . $es . 'px');
|
||||||
|
$layout->set_font_description($desc);
|
||||||
|
|
||||||
|
my ($wid2, $h2) = $layout->get_pixel_size();
|
||||||
|
$cr->save;
|
||||||
|
$cr->move_to($settings->{margin_left} + $i * $cell + $cell/2 - $wid2/2, $self->{bounding_box}[1] + $h);
|
||||||
|
Pango::Cairo::show_layout($cr, $layout);
|
||||||
|
$cr->restore();
|
||||||
|
|
||||||
|
if ($h + $h2 > $ymax) {
|
||||||
|
$ymax = $h + $h2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$self->{heading_bottom_y} = $ymax + $self->{bounding_box}[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
sub draw_entries
|
||||||
|
{
|
||||||
|
my ($self, $cr, $settings, $i) = @_;
|
||||||
|
|
||||||
|
my $cell = ($settings->{width} - $settings->{margin_left} - $settings->{margin_right})/7;
|
||||||
|
|
||||||
|
# Coordinates of box from line-to-line
|
||||||
|
my $l2l_box = [$i * $cell + $settings->{margin_left},
|
||||||
|
$self->{heading_bottom_y},
|
||||||
|
($i+1) * $cell + $settings->{margin_left},
|
||||||
|
$self->{bounding_box}[3]];
|
||||||
|
|
||||||
|
# Coordinates of drawing-space box
|
||||||
|
my $box = [$l2l_box->[0] + $settings->{border_size},
|
||||||
|
$l2l_box->[1] + $settings->{border_size},
|
||||||
|
$l2l_box->[2] - $settings->{border_size},
|
||||||
|
$l2l_box->[3] - $settings->{border_size}];
|
||||||
|
|
||||||
|
$self->{l2l_box} = $l2l_box;
|
||||||
|
$self->{box} = $box;
|
||||||
|
|
||||||
|
# Do shading, if any
|
||||||
|
my $shade = $self->find_last_special('shade', $self->{entries}->[$i]);
|
||||||
|
if ($shade) {
|
||||||
|
$cr->save;
|
||||||
|
$cr->set_source_rgb($shade->{r} / 255,
|
||||||
|
$shade->{g} / 255,
|
||||||
|
$shade->{b} / 255);
|
||||||
|
$cr->rectangle($l2l_box->[0], $l2l_box->[1],
|
||||||
|
$l2l_box->[2] - $l2l_box->[0],
|
||||||
|
$l2l_box->[3] - $l2l_box->[1]);
|
||||||
|
$cr->fill();
|
||||||
|
$cr->restore;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the "day number" size to leave room for moon and week specials
|
||||||
|
my $layout = Pango::Cairo::create_layout($cr);
|
||||||
|
$layout->set_text("31");
|
||||||
|
my $desc = Pango::FontDescription->from_string($settings->{daynum_font} . ' ' . $settings->{daynum_size} . 'px');
|
||||||
|
|
||||||
|
$layout->set_font_description($desc);
|
||||||
|
my ($wid, $h) = $layout->get_pixel_size();
|
||||||
|
|
||||||
|
my $so_far = $box->[1] + $h + $settings->{border_size};
|
||||||
|
|
||||||
|
my $box_height = $box->[3] - $box->[1];
|
||||||
|
my $done = 0;
|
||||||
|
foreach my $entry (@{$self->{entries}->[$i]}) {
|
||||||
|
# Moon and week should not adjust height
|
||||||
|
if ($entry->isa('Remind::PDF::Entry::moon') ||
|
||||||
|
$entry->isa('Remind::PDF::Entry::week')) {
|
||||||
|
$entry->render($self, $cr, $settings, $box->[1], $i, $i, $box_height);
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# An absolutely-positioned Pango markup should not adjust height
|
||||||
|
# either
|
||||||
|
if ($entry->isa('Remind::PDF::Entry::pango') &&
|
||||||
|
defined($entry->{atx}) && defined($entry->{aty})) {
|
||||||
|
$entry->render($self, $cr, $settings, $box->[1], $i, $i, $box_height);
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Shade is done already
|
||||||
|
if ($entry->isa('Remind::PDF::Entry::shade')) {
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($done) {
|
||||||
|
$so_far += $settings->{border_size};
|
||||||
|
}
|
||||||
$done = 1;
|
$done = 1;
|
||||||
$e->render($cr, $settings);
|
my $h2 = $entry->render($self, $cr, $settings, $so_far, $i, $i, $box_height);
|
||||||
|
$so_far += $h2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub col_box_coordinates
|
||||||
|
{
|
||||||
|
|
||||||
|
my ($self, $so_far, $col, $height, $settings) = @_;
|
||||||
|
return (@{$self->{l2l_box}});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sub draw_lines
|
||||||
|
{
|
||||||
|
my ($self, $cr, $settings) = @_;
|
||||||
|
|
||||||
|
# Top horizonal line
|
||||||
|
$cr->move_to($self->{bounding_box}[0], $self->{bounding_box}[1]);
|
||||||
|
$cr->line_to($self->{bounding_box}[2], $self->{bounding_box}[1]);
|
||||||
|
$cr->stroke();
|
||||||
|
|
||||||
|
# Horizontal line below headings
|
||||||
|
$cr->move_to($self->{bounding_box}[0], $self->{heading_bottom_y});
|
||||||
|
$cr->line_to($self->{bounding_box}[2], $self->{heading_bottom_y});
|
||||||
|
$cr->stroke();
|
||||||
|
|
||||||
|
# Bottom horizontal line
|
||||||
|
$cr->move_to($self->{bounding_box}[0], $self->{bounding_box}[3]);
|
||||||
|
$cr->line_to($self->{bounding_box}[2], $self->{bounding_box}[3]);
|
||||||
|
$cr->stroke();
|
||||||
|
|
||||||
|
# Vertical lines
|
||||||
|
my $w = ($settings->{width} - $settings->{margin_left} - $settings->{margin_right})/7;
|
||||||
|
for (my $i=0; $i<=7; $i++) {
|
||||||
|
my $x = $settings->{margin_left} + ($i * $w);
|
||||||
|
$cr->move_to($x, $self->{bounding_box}[1]);
|
||||||
|
$cr->line_to($x, $self->{bounding_box}[3]);
|
||||||
|
$cr->stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub create_from_hash
|
||||||
|
{
|
||||||
|
my ($class, $hash, $specials_accepted) = @_;
|
||||||
|
bless $hash, $class;
|
||||||
|
|
||||||
|
my $filtered_entries = [];
|
||||||
|
my $date_to_index;
|
||||||
|
for (my $i=0; $i<7; $i++) {
|
||||||
|
$date_to_index->{$hash->{dates}[$i]->{date}} = $i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (my $i=0; $i<7; $i++) {
|
||||||
|
$filtered_entries->[$i] = [];
|
||||||
|
}
|
||||||
|
foreach my $e (@{$hash->{entries}}) {
|
||||||
|
if ($hash->accept_special($e, $specials_accepted)) {
|
||||||
|
my $index = $date_to_index->{$e->{date}};
|
||||||
|
push(@{$filtered_entries->[$index]}, Remind::PDF::Entry->new_from_hash($e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$hash->{entries} = $filtered_entries;
|
||||||
|
return $hash;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,10 @@ sub render
|
|||||||
my ($x1, $y1, $x2, $y2) = $pdf->col_box_coordinates($so_far, $col, $height, $settings);
|
my ($x1, $y1, $x2, $y2) = $pdf->col_box_coordinates($so_far, $col, $height, $settings);
|
||||||
my $layout = Pango::Cairo::create_layout($cr);
|
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_width(1024 * ($x2 - $x1 - 2 * $settings->{border_size}));
|
||||||
$layout->set_wrap('word-char');
|
$layout->set_wrap('word-char');
|
||||||
my $body;
|
my $body;
|
||||||
@@ -108,7 +112,13 @@ sub render
|
|||||||
$self->{g} / 255,
|
$self->{g} / 255,
|
||||||
$self->{b} / 255);
|
$self->{b} / 255);
|
||||||
$cr->move_to($x1 + $settings->{border_size}, $so_far);
|
$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);
|
Pango::Cairo::show_layout($cr, $layout);
|
||||||
|
if ($url) {
|
||||||
|
$cr->tag_end(Cairo::TAG_LINK);
|
||||||
|
}
|
||||||
$cr->restore();
|
$cr->restore();
|
||||||
}
|
}
|
||||||
return $h;
|
return $h;
|
||||||
@@ -142,7 +152,18 @@ sub render
|
|||||||
|
|
||||||
$cr->save();
|
$cr->save();
|
||||||
$cr->move_to($x2 - $settings->{border_size}/4 - $wid, $y2 - $settings->{border_size}/4 - $h);
|
$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);
|
Pango::Cairo::show_layout($cr, $layout);
|
||||||
|
if ($url) {
|
||||||
|
$cr->tag_end(Cairo::TAG_LINK);
|
||||||
|
}
|
||||||
$cr->restore();
|
$cr->restore();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -204,12 +225,30 @@ sub render
|
|||||||
$xc = $x1 + $settings->{border_size} + ($self->{size} / 2);
|
$xc = $x1 + $settings->{border_size} + ($self->{size} / 2);
|
||||||
$yc = $so_far + $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);
|
$self->draw_moon($xc, $yc, $cr);
|
||||||
|
if ($url) {
|
||||||
|
$cr->tag_end(Cairo::TAG_LINK);
|
||||||
|
}
|
||||||
if ($layout) {
|
if ($layout) {
|
||||||
$cr->save();
|
$cr->save();
|
||||||
$cr->move_to ($xc + ($self->{size}/2) + $settings->{border_size},
|
$cr->move_to ($xc + ($self->{size}/2) + $settings->{border_size},
|
||||||
$yc + ($self->{size}/2) - $self->{fontsize} );
|
$yc + ($self->{size}/2) - $self->{fontsize} );
|
||||||
|
if ($url) {
|
||||||
|
$cr->tag_begin(Cairo::TAG_LINK, "uri='$url'");
|
||||||
|
}
|
||||||
Pango::Cairo::show_layout($cr, $layout);
|
Pango::Cairo::show_layout($cr, $layout);
|
||||||
|
if ($url) {
|
||||||
|
$cr->tag_end(Cairo::TAG_LINK);
|
||||||
|
}
|
||||||
$cr->restore();
|
$cr->restore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,6 +323,10 @@ sub render
|
|||||||
my ($self, $pdf, $cr, $settings, $so_far, $day, $col, $height) = @_;
|
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 ($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);
|
my $layout = Pango::Cairo::create_layout($cr);
|
||||||
|
|
||||||
$layout->set_width(1024 * ($x2 - $x1 - 2 * $settings->{border_size}));
|
$layout->set_width(1024 * ($x2 - $x1 - 2 * $settings->{border_size}));
|
||||||
@@ -316,7 +359,13 @@ sub render
|
|||||||
} else {
|
} else {
|
||||||
$cr->move_to($x1 + $settings->{border_size}, $so_far);
|
$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);
|
Pango::Cairo::show_layout($cr, $layout);
|
||||||
|
if ($url) {
|
||||||
|
$cr->tag_end(Cairo::TAG_LINK);
|
||||||
|
}
|
||||||
$cr->restore();
|
$cr->restore();
|
||||||
}
|
}
|
||||||
return $h;
|
return $h;
|
||||||
|
|||||||
+240
-28
@@ -8,7 +8,7 @@
|
|||||||
# A cheesy graphical front/back end for Remind using Tcl/Tk
|
# A cheesy graphical front/back end for Remind using Tcl/Tk
|
||||||
#
|
#
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# Copyright (C) 1992-2024 Dianne Skoll
|
# Copyright (C) 1992-2025 Dianne Skoll
|
||||||
#
|
#
|
||||||
#--------------------------------------------------------------
|
#--------------------------------------------------------------
|
||||||
|
|
||||||
@@ -280,6 +280,9 @@ set AppendFile $ReminderFile
|
|||||||
# Array of tags -> JSON dicts
|
# Array of tags -> JSON dicts
|
||||||
array unset TagToObj
|
array unset TagToObj
|
||||||
|
|
||||||
|
# Array of __syn__ tags -> JSON dicts
|
||||||
|
array unset SynToObj
|
||||||
|
|
||||||
set SetFontsWorked 0
|
set SetFontsWorked 0
|
||||||
#---------------- DON'T CHANGE STUFF BELOW HERE ------------------
|
#---------------- DON'T CHANGE STUFF BELOW HERE ------------------
|
||||||
|
|
||||||
@@ -582,6 +585,7 @@ proc CreateCalFrame { w dayNames } {
|
|||||||
-highlightthickness 0
|
-highlightthickness 0
|
||||||
frame $w.f$f -padx 0 -pady 0 -highlightthickness 0 -relief flat -bd 0
|
frame $w.f$f -padx 0 -pady 0 -highlightthickness 0 -relief flat -bd 0
|
||||||
$w.t$f tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$f"
|
$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"
|
$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.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
|
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 delete $t
|
||||||
}
|
}
|
||||||
$w.t$i tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$i"
|
$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 tag bind REM <ButtonPress-3> "FireEditor $w.t$i"
|
||||||
$w.t$i configure -state disabled -takefocus 0
|
$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 delete $t
|
||||||
}
|
}
|
||||||
$w.t$i tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$i"
|
$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 tag bind REM <ButtonPress-3> "FireEditor $w.t$i"
|
||||||
$w.t$i configure -state disabled -takefocus 0
|
$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 delete $t
|
||||||
}
|
}
|
||||||
$w.t$i tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$i"
|
$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 tag bind REM <ButtonPress-3> "FireEditor $w.t$i"
|
||||||
$w.t$i configure -state disabled -takefocus 0
|
$w.t$i configure -state disabled -takefocus 0
|
||||||
}
|
}
|
||||||
@@ -798,7 +805,7 @@ proc EditOptions {} {
|
|||||||
pack $w.f -side top -expand 1 -fill both
|
pack $w.f -side top -expand 1 -fill both
|
||||||
pack $w.b -side top -expand 0 -fill x
|
pack $w.b -side top -expand 0 -fill x
|
||||||
|
|
||||||
label $w.ver -text "TkRemind version @VERSION@ on Tcl/Tk version [info tclversion] with Remind version $ver"
|
label $w.ver -text "TkRemind version @VERSION@ on Tcl/Tk version [info patchlevel] with Remind version $ver"
|
||||||
pack $w.ver -in $w.f -side top -expand 0 -fill x
|
pack $w.ver -in $w.f -side top -expand 0 -fill x
|
||||||
# Start iconified
|
# Start iconified
|
||||||
checkbutton $w.startIconified -text "Start up Iconified" \
|
checkbutton $w.startIconified -text "Start up Iconified" \
|
||||||
@@ -1138,9 +1145,10 @@ proc ConfigureCalWindow { month year firstDay numDays } {
|
|||||||
proc FillCalWindow {} {
|
proc FillCalWindow {} {
|
||||||
set FileName ""
|
set FileName ""
|
||||||
set LineNo 0
|
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 TagToObj
|
||||||
|
array unset SynToObj
|
||||||
|
|
||||||
Status "Firing off Remind..."
|
Status "Firing off Remind..."
|
||||||
set_button_to_queue
|
set_button_to_queue
|
||||||
@@ -1204,7 +1212,12 @@ proc FillCalWindow {} {
|
|||||||
set fname [dict get $obj filename]
|
set fname [dict get $obj filename]
|
||||||
# Don't make INCLUDECMD output editable
|
# Don't make INCLUDECMD output editable
|
||||||
if {![string match "*|" $fname]} {
|
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 day [string trimleft $day 0]
|
||||||
set n [expr $day+$offset]
|
set n [expr $day+$offset]
|
||||||
set month [string trimleft $month 0]
|
set month [string trimleft $month 0]
|
||||||
set extratags ""
|
set extratags {}
|
||||||
switch -nocase -- $type {
|
switch -nocase -- $type {
|
||||||
"WEEK" {
|
"WEEK" {
|
||||||
set stuff [string trimleft $stuff]
|
set stuff [string trimleft $stuff]
|
||||||
@@ -1269,9 +1282,9 @@ proc FillCalWindow {} {
|
|||||||
set b 0
|
set b 0
|
||||||
}
|
}
|
||||||
set color [format "%02X%02X%02X" $r $g $b]
|
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 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
|
.cal.t$n configure -state disabled -takefocus 0
|
||||||
set stuff $stuff
|
set stuff $stuff
|
||||||
set type "COLOR"
|
set type "COLOR"
|
||||||
@@ -1288,18 +1301,27 @@ proc FillCalWindow {} {
|
|||||||
set stuff [regsub -all {\n[ \t]} $stuff "\n"]
|
set stuff [regsub -all {\n[ \t]} $stuff "\n"]
|
||||||
set stuff [regsub -all {\n+} $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"} {
|
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 insert end [string trim $stuff] [concat 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" <Enter> [list TaggedEnter .cal.t$n]
|
||||||
.cal.t$n tag bind "TKTAG$tagno" <Leave> "TaggedLeave .cal.t$n"
|
.cal.t$n tag bind "TKTAG$tagno" <Leave> [list TaggedLeave .cal.t$n]
|
||||||
set TagToObj(TKTAG$tagno) $obj
|
set TagToObj($all) $obj
|
||||||
} else {
|
} else {
|
||||||
if {"$fntag" == "x" } {
|
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 {
|
} else {
|
||||||
.cal.t$n insert end [string trim $stuff] [list REM $extratags $fntag]
|
.cal.t$n insert end [string trim $stuff] [concat REM $extratags $fntag]
|
||||||
.cal.t$n tag bind $fntag <Enter> "EditableEnter .cal.t$n"
|
.cal.t$n tag bind $fntag <Enter> [list EditableEnter .cal.t$n]
|
||||||
.cal.t$n tag bind $fntag <Leave> "EditableLeave .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"
|
.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.msg
|
||||||
frame $w.buttons
|
frame $w.buttons
|
||||||
pack $w.o1 $w.o2 $w.o3 -side top -anchor w -in $w.o
|
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.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.buttons -side top -anchor w -pady 4 -expand 1 -fill x
|
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
|
# TYPE 1 REMINDER
|
||||||
radiobutton $w.type1 -variable OptionType -value 1
|
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
|
pack $w.labhol $w.issue $w.skip $w.before $w.after -side top -anchor w -in $w.hol
|
||||||
|
|
||||||
# TEXT ENTRY
|
# TEXT ENTRY
|
||||||
label $w.msglab -text "Body:"
|
label $w.msglab -text "Summary: "
|
||||||
entry $w.entry
|
entry $w.entry
|
||||||
balloon_add_help $w.entry "Enter the text of the reminder"
|
balloon_add_help $w.entry "Enter the text of the reminder"
|
||||||
pack $w.msglab -side left -anchor w -in $w.msg
|
grid $w.msglab -row 0 -column 0 -in $w.msg -sticky e
|
||||||
pack $w.entry -side left -anchor w -expand 1 -fill x -in $w.msg
|
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
|
# BUTTONS
|
||||||
set nbut 0
|
set nbut 0
|
||||||
foreach but $args {
|
foreach but $args {
|
||||||
@@ -1988,6 +2036,11 @@ proc OptionsToRemindDialog { w opts } {
|
|||||||
set hour $value
|
set hour $value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"-txtentry-*" {
|
||||||
|
set win [string range $flag 10 end]
|
||||||
|
$w.$win delete 1.0 end
|
||||||
|
$w.$win insert end $value
|
||||||
|
}
|
||||||
"-global-*" {
|
"-global-*" {
|
||||||
set win [string range $flag 8 end]
|
set win [string range $flag 8 end]
|
||||||
set $win $value
|
set $win $value
|
||||||
@@ -2170,6 +2223,13 @@ proc CenterWindow {w {parent {}}} {
|
|||||||
wm deiconify $w
|
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
|
# CreateReminder -- create the reminder
|
||||||
# Arguments:
|
# Arguments:
|
||||||
@@ -2255,7 +2315,21 @@ proc CreateReminder {w} {
|
|||||||
append rem " OMIT [GetWeekend $w 1]"
|
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!
|
# Check it out!
|
||||||
global Remind
|
global Remind
|
||||||
set f [open "|$Remind -arq -e - 2>@1" r+]
|
set f [open "|$Remind -arq -e - 2>@1" r+]
|
||||||
@@ -2798,7 +2872,11 @@ proc ShowQueue { queue } {
|
|||||||
set fntag ""
|
set fntag ""
|
||||||
catch {
|
catch {
|
||||||
set fname [dict get $q filename]
|
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]
|
set fntag [string cat "FILE_" $lineno "_" $fname]
|
||||||
}
|
}
|
||||||
if { "$fntag" != "" } {
|
if { "$fntag" != "" } {
|
||||||
@@ -2916,11 +2994,16 @@ proc DaemonReadable { file } {
|
|||||||
set tag [dict get $obj tags]
|
set tag [dict get $obj tags]
|
||||||
}
|
}
|
||||||
set body [dict get $obj body]
|
set body [dict get $obj body]
|
||||||
|
if {[dict exists $obj info]} {
|
||||||
|
set info [dict get $obj info]
|
||||||
|
} else {
|
||||||
|
set info [dict create]
|
||||||
|
}
|
||||||
set qid "*"
|
set qid "*"
|
||||||
if {[dict exists $obj qid]} {
|
if {[dict exists $obj qid]} {
|
||||||
set qid [dict get $obj qid]
|
set qid [dict get $obj qid]
|
||||||
}
|
}
|
||||||
IssueBackgroundReminder $body $time $now $tag $qid
|
IssueBackgroundReminder $body $time $now $tag $qid $info
|
||||||
}
|
}
|
||||||
"queue" {
|
"queue" {
|
||||||
set queue [dict get $obj queue]
|
set queue [dict get $obj queue]
|
||||||
@@ -2964,7 +3047,7 @@ proc DaemonReadable { file } {
|
|||||||
# Description:
|
# Description:
|
||||||
# Reads a background reminder from daemon and pops up window.
|
# 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
|
global BgCounter Option Ignore DaemonFile HAVE_SYSNOTIFY NOTIFY_SEND_PATH
|
||||||
if {$Option(Deiconify)} {
|
if {$Option(Deiconify)} {
|
||||||
wm deiconify .
|
wm deiconify .
|
||||||
@@ -2993,7 +3076,7 @@ proc IssueBackgroundReminder { body time now tag qid } {
|
|||||||
wm iconname $w "Reminder"
|
wm iconname $w "Reminder"
|
||||||
wm title $w "Timed reminder ($time)"
|
wm title $w "Timed reminder ($time)"
|
||||||
label $w.l -text "Reminder for $time issued at $now"
|
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
|
frame $w.b
|
||||||
|
|
||||||
# Automatically shut down window after a minute if option says so
|
# 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]
|
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.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.b -side top
|
||||||
pack $w.ok -in $w.b -side left
|
pack $w.ok -in $w.b -side left
|
||||||
if {$qid != "*"} {
|
if {$qid != "*"} {
|
||||||
@@ -3086,7 +3198,7 @@ proc main {} {
|
|||||||
|
|
||||||
global AppendFile HighestTagSoFar DayNames
|
global AppendFile HighestTagSoFar DayNames
|
||||||
catch {
|
catch {
|
||||||
puts "\nTkRemind Copyright (C) 1996-2024 Dianne Skoll"
|
puts "\nTkRemind Copyright (C) 1996-2025 Dianne Skoll"
|
||||||
}
|
}
|
||||||
catch { SetFonts }
|
catch { SetFonts }
|
||||||
Initialize
|
Initialize
|
||||||
@@ -3443,6 +3555,19 @@ proc ReadTaggedOptions { tag date } {
|
|||||||
lappend ans -text-year3 $y
|
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
|
return $ans
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3573,6 +3698,93 @@ proc EditableLeave { w } {
|
|||||||
set tag [lindex $tags $index]
|
set tag [lindex $tags $index]
|
||||||
$w tag configure $tag -underline 0
|
$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
|
# %PROCEDURE: EditTaggedReminder
|
||||||
# %ARGUMENTS:
|
# %ARGUMENTS:
|
||||||
@@ -4421,7 +4633,7 @@ proc ShowErrors {} {
|
|||||||
set l [split $RemindErrors "\n"]
|
set l [split $RemindErrors "\n"]
|
||||||
set i 0
|
set i 0
|
||||||
foreach line $l {
|
foreach line $l {
|
||||||
if {[regexp {^(.*)\(([0-9]+)\)} $line dummy fname lineno]} {
|
if {[regexp {^(.*)\(([0-9]+)} $line dummy fname lineno]} {
|
||||||
incr i
|
incr i
|
||||||
set fntag [string cat "FILE_" $lineno "_" $fname]
|
set fntag [string cat "FILE_" $lineno "_" $fname]
|
||||||
$w.t insert end $line [list ERR "ERR$i" $fntag]
|
$w.t insert end $line [list ERR "ERR$i" $fntag]
|
||||||
|
|||||||
+11
-2
@@ -31,9 +31,11 @@ REMINDSRCS= calendar.c dedupe.c dynbuf.c dorem.c dosubst.c expr.c \
|
|||||||
hbcal.c init.c main.c md5.c moon.c omit.c queue.c \
|
hbcal.c init.c main.c md5.c moon.c omit.c queue.c \
|
||||||
sort.c token.c trans.c trigger.c userfns.c utils.c var.c
|
sort.c token.c trans.c trigger.c userfns.c utils.c var.c
|
||||||
|
|
||||||
|
XLATSRC= xlat.c
|
||||||
|
|
||||||
REMINDHDRS=config.h custom.h dynbuf.h err.h globals.h hashtab.h \
|
REMINDHDRS=config.h custom.h dynbuf.h err.h globals.h hashtab.h \
|
||||||
md5.h protos.h rem2ps.h types.h version.h
|
md5.h protos.h rem2ps.h types.h version.h
|
||||||
REMINDOBJS= $(REMINDSRCS:.c=.o)
|
REMINDOBJS= $(REMINDSRCS:.c=.o) $(XLATSRC:.c=.o)
|
||||||
|
|
||||||
all: remind rem2ps
|
all: remind rem2ps
|
||||||
|
|
||||||
@@ -43,6 +45,13 @@ test: all
|
|||||||
.c.o:
|
.c.o:
|
||||||
@CC@ -c @CPPFLAGS@ @CFLAGS@ @DEFS@ $(CEXTRA) -DSYSDIR=$(datarootdir)/remind -I. -I$(srcdir) $<
|
@CC@ -c @CPPFLAGS@ @CFLAGS@ @DEFS@ $(CEXTRA) -DSYSDIR=$(datarootdir)/remind -I. -I$(srcdir) $<
|
||||||
|
|
||||||
|
xlat.c: $(REMINDSRCS)
|
||||||
|
@echo "#include <stddef.h>" > xlat.c
|
||||||
|
@echo "char const *translatables[] = {" >> xlat.c
|
||||||
|
@cat $(REMINDSRCS) | grep 'tr(".*")' | sed -e 's/.*tr."/"/' -e 's/").*/"/' | LANG=C LC_ALL=C sort | uniq | grep -E -v '^"(am|at|from now|hour|minute|now|on|pm|today|tomorrow|was)"$$' | sed -e 's/^/ /' -e 's/$$/,/' >> xlat.c
|
||||||
|
@echo " NULL" >> xlat.c
|
||||||
|
@echo "};" >> xlat.c
|
||||||
|
|
||||||
$(REMINDOBJS): $(REMINDHDRS)
|
$(REMINDOBJS): $(REMINDHDRS)
|
||||||
|
|
||||||
rem2ps: rem2ps.o dynbuf.o json.o
|
rem2ps: rem2ps.o dynbuf.o json.o
|
||||||
@@ -80,7 +89,7 @@ install-stripped: install
|
|||||||
strip $(DESTDIR)$(bindir)/rem2ps || true
|
strip $(DESTDIR)$(bindir)/rem2ps || true
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *~ core *.bak $(PROGS)
|
rm -f *.o *~ core *.bak $(PROGS) $(XLATSRC)
|
||||||
|
|
||||||
clobber:
|
clobber:
|
||||||
rm -f *.o *~ remind rem2ps test.out core *.bak
|
rm -f *.o *~ remind rem2ps test.out core *.bak
|
||||||
|
|||||||
+163
-34
@@ -5,7 +5,7 @@
|
|||||||
/* The code for generating a calendar. */
|
/* The code for generating a calendar. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -57,10 +57,12 @@ typedef struct cal_entry {
|
|||||||
int duration;
|
int duration;
|
||||||
char *filename;
|
char *filename;
|
||||||
int lineno;
|
int lineno;
|
||||||
|
int lineno_start;
|
||||||
Trigger trig;
|
Trigger trig;
|
||||||
TimeTrig tt;
|
TimeTrig tt;
|
||||||
int nonconst_expr;
|
int nonconst_expr;
|
||||||
int if_depth;
|
int if_depth;
|
||||||
|
TrigInfo *infos;
|
||||||
} CalEntry;
|
} CalEntry;
|
||||||
|
|
||||||
/* Line-drawing sequences */
|
/* Line-drawing sequences */
|
||||||
@@ -274,6 +276,7 @@ static int ColToDay[7];
|
|||||||
static int ColSpaces;
|
static int ColSpaces;
|
||||||
|
|
||||||
static int DidAMonth;
|
static int DidAMonth;
|
||||||
|
static int DidAWeek;
|
||||||
static int DidADay;
|
static int DidADay;
|
||||||
|
|
||||||
static void ColorizeEntry(CalEntry const *e, int clamp);
|
static void ColorizeEntry(CalEntry const *e, int clamp);
|
||||||
@@ -386,7 +389,13 @@ void PrintJSONChar(char c) {
|
|||||||
case '\t': printf("\\t"); break;
|
case '\t': printf("\\t"); break;
|
||||||
case '"': printf("\\\""); break;
|
case '"': printf("\\\""); 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,7 +410,36 @@ void PrintJSONString(char const *s)
|
|||||||
case '\t': printf("\\t"); break;
|
case '\t': printf("\\t"); break;
|
||||||
case '"': printf("\\\""); break;
|
case '"': printf("\\\""); 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++;
|
s++;
|
||||||
}
|
}
|
||||||
@@ -498,7 +536,7 @@ get_month_abbrev(char const *mon)
|
|||||||
{
|
{
|
||||||
static char buf[80];
|
static char buf[80];
|
||||||
#ifndef REM_USE_WCHAR
|
#ifndef REM_USE_WCHAR
|
||||||
sprintf(buf, "%.3s", mon);
|
snprintf(buf, sizeof(buf), "%.3s", mon);
|
||||||
return buf;
|
return buf;
|
||||||
#else
|
#else
|
||||||
char *s;
|
char *s;
|
||||||
@@ -625,9 +663,9 @@ Colorize256(int r, int g, int b, int bg, int clamp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bg) {
|
if (bg) {
|
||||||
sprintf(buf, "\x1B[48;5;%dm", best);
|
snprintf(buf, sizeof(buf), "\x1B[48;5;%dm", best);
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf, "\x1B[38;5;%dm", best);
|
snprintf(buf, sizeof(buf), "\x1B[38;5;%dm", best);
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
@@ -640,9 +678,9 @@ ColorizeTrue(int r, int g, int b, int bg, int clamp)
|
|||||||
ClampColor(&r, &g, &b);
|
ClampColor(&r, &g, &b);
|
||||||
}
|
}
|
||||||
if (bg) {
|
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 {
|
} 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;
|
return buf;
|
||||||
}
|
}
|
||||||
@@ -834,12 +872,33 @@ void ProduceCalendar(void)
|
|||||||
WriteIntermediateCalLine();
|
WriteIntermediateCalLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (CalWeeks--)
|
DidAWeek = 0;
|
||||||
|
if (PsCal == PSCAL_LEVEL3) {
|
||||||
|
printf("[\n");
|
||||||
|
}
|
||||||
|
while (CalWeeks--) {
|
||||||
DoCalendarOneWeek(CalWeeks);
|
DoCalendarOneWeek(CalWeeks);
|
||||||
|
DidAWeek = 1;
|
||||||
|
}
|
||||||
|
if (PsCal == PSCAL_LEVEL3) {
|
||||||
|
printf("\n]\n");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
SendTranslationTable(int pslevel)
|
||||||
|
{
|
||||||
|
if (pslevel < PSCAL_LEVEL3) {
|
||||||
|
printf("# translations\n");
|
||||||
|
}
|
||||||
|
DumpTranslationTable(stdout, 1);
|
||||||
|
if (pslevel < PSCAL_LEVEL3) {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* DoCalendarOneWeek */
|
/* DoCalendarOneWeek */
|
||||||
@@ -870,9 +929,33 @@ static void DoCalendarOneWeek(int nleft)
|
|||||||
/* Output the entries */
|
/* Output the entries */
|
||||||
/* If it's "Simple Calendar" format, do it simply... */
|
/* If it's "Simple Calendar" format, do it simply... */
|
||||||
if (DoSimpleCalendar) {
|
if (DoSimpleCalendar) {
|
||||||
|
if (PsCal == PSCAL_LEVEL3) {
|
||||||
|
if (DidAWeek) {
|
||||||
|
printf(",\n");
|
||||||
|
}
|
||||||
|
printf("{\n\"caltype\":\"weekly\",");
|
||||||
|
if (!DidAWeek) {
|
||||||
|
printf("\"translations\":");
|
||||||
|
SendTranslationTable(PsCal);
|
||||||
|
printf(",");
|
||||||
|
}
|
||||||
|
printf("\"dates\":[");
|
||||||
|
for (i=0; i<7; i++) {
|
||||||
|
if (i != 0) {
|
||||||
|
printf(",");
|
||||||
|
}
|
||||||
|
FromDSE(OrigDse+i-wd, &y, &m, &d);
|
||||||
|
printf("{\"dayname\":\"%s\",\"date\":\"%04d-%02d-%02d\",\"year\":%d,\"month\":\"%s\",\"day\":%d}", get_day_name((OrigDse+i-wd)%7),y, m+1, d, y, get_month_name(m), d);
|
||||||
|
}
|
||||||
|
printf("],\"entries\":[");
|
||||||
|
}
|
||||||
|
DidADay = 0;
|
||||||
for (i=0; i<7; i++) {
|
for (i=0; i<7; i++) {
|
||||||
WriteSimpleEntries(i, OrigDse+i-wd);
|
WriteSimpleEntries(i, OrigDse+i-wd);
|
||||||
}
|
}
|
||||||
|
if (PsCal == PSCAL_LEVEL3) {
|
||||||
|
printf("\n]\n}");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -965,18 +1048,6 @@ static void DoCalendarOneWeek(int nleft)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
SendTranslationTable(int pslevel)
|
|
||||||
{
|
|
||||||
if (pslevel < PSCAL_LEVEL3) {
|
|
||||||
printf("# translations\n");
|
|
||||||
}
|
|
||||||
DumpTranslationTable(stdout, 1);
|
|
||||||
if (pslevel < PSCAL_LEVEL3) {
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* DoSimpleCalendarOneMonth */
|
/* DoSimpleCalendarOneMonth */
|
||||||
@@ -1030,6 +1101,7 @@ static void DoSimpleCalendarOneMonth(void)
|
|||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
} else {
|
} else {
|
||||||
|
PrintJSONKeyPairString("caltype", "monthly");
|
||||||
PrintJSONKeyPairString("monthname", get_month_name(m));
|
PrintJSONKeyPairString("monthname", get_month_name(m));
|
||||||
PrintJSONKeyPairInt("year", y);
|
PrintJSONKeyPairInt("year", y);
|
||||||
PrintJSONKeyPairInt("daysinmonth", DaysInMonth(m, y));
|
PrintJSONKeyPairInt("daysinmonth", DaysInMonth(m, y));
|
||||||
@@ -1272,7 +1344,7 @@ static void PrintLeft(char const *s, int width, char pad)
|
|||||||
buf = calloc(len+1, sizeof(wchar_t));
|
buf = calloc(len+1, sizeof(wchar_t));
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
/* Uh-oh... cannot recover */
|
/* Uh-oh... cannot recover */
|
||||||
fprintf(stderr, "%s\n", GetErr(E_NO_MEM));
|
fprintf(ErrFp, "%s\n", GetErr(E_NO_MEM));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1357,7 +1429,7 @@ static void PrintCentered(char const *s, int width, char *pad)
|
|||||||
buf = calloc(len+1, sizeof(wchar_t));
|
buf = calloc(len+1, sizeof(wchar_t));
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
/* Uh-oh... cannot recover */
|
/* Uh-oh... cannot recover */
|
||||||
fprintf(stderr, "%s\n", GetErr(E_NO_MEM));
|
fprintf(ErrFp, "%s\n", GetErr(E_NO_MEM));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1469,6 +1541,7 @@ static int WriteOneColLine(int col)
|
|||||||
free(e->raw_text);
|
free(e->raw_text);
|
||||||
free(e->filename);
|
free(e->filename);
|
||||||
if (e->wc_text) free(e->wc_text);
|
if (e->wc_text) free(e->wc_text);
|
||||||
|
FreeTrigInfoChain(e->infos);
|
||||||
free(e);
|
free(e);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1555,6 +1628,7 @@ static int WriteOneColLine(int col)
|
|||||||
free(e->raw_text);
|
free(e->raw_text);
|
||||||
free(e->filename);
|
free(e->filename);
|
||||||
if (e->wc_text) free(e->wc_text);
|
if (e->wc_text) free(e->wc_text);
|
||||||
|
FreeTrigInfoChain(e->infos);
|
||||||
free(e);
|
free(e);
|
||||||
} else {
|
} else {
|
||||||
e->wc_pos = ws;
|
e->wc_pos = ws;
|
||||||
@@ -1576,6 +1650,7 @@ static int WriteOneColLine(int col)
|
|||||||
if (e->wc_text) free(e->wc_text);
|
if (e->wc_text) free(e->wc_text);
|
||||||
#endif
|
#endif
|
||||||
free(e->raw_text);
|
free(e->raw_text);
|
||||||
|
FreeTrigInfoChain(e->infos);
|
||||||
free(e);
|
free(e);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1638,6 +1713,7 @@ static int WriteOneColLine(int col)
|
|||||||
if (e->wc_text) free(e->wc_text);
|
if (e->wc_text) free(e->wc_text);
|
||||||
#endif
|
#endif
|
||||||
free(e->raw_text);
|
free(e->raw_text);
|
||||||
|
FreeTrigInfoChain(e->infos);
|
||||||
free(e);
|
free(e);
|
||||||
} else {
|
} else {
|
||||||
e->pos = s;
|
e->pos = s;
|
||||||
@@ -1777,7 +1853,7 @@ static void WriteCalHeader(void)
|
|||||||
int y, m, d;
|
int y, m, d;
|
||||||
|
|
||||||
FromDSE(DSEToday, &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();
|
WriteTopCalLine();
|
||||||
|
|
||||||
@@ -1981,7 +2057,7 @@ static int DoCalRem(ParsePtr p, int col)
|
|||||||
trig.typ == MSF_TYPE) {
|
trig.typ == MSF_TYPE) {
|
||||||
if (PsCal && is_color) {
|
if (PsCal && is_color) {
|
||||||
char cbuf[24];
|
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);
|
DBufPuts(&pre_buf, cbuf);
|
||||||
strcpy(trig.passthru, "COLOR");
|
strcpy(trig.passthru, "COLOR");
|
||||||
/* Don't change trig.typ or next if() will trigger! */
|
/* Don't change trig.typ or next if() will trigger! */
|
||||||
@@ -2114,7 +2190,7 @@ static int DoCalRem(ParsePtr p, int col)
|
|||||||
if (trig.typ != PASSTHRU_TYPE &&
|
if (trig.typ != PASSTHRU_TYPE &&
|
||||||
UserFuncExists("calprefix")==1) {
|
UserFuncExists("calprefix")==1) {
|
||||||
char evalBuf[64];
|
char evalBuf[64];
|
||||||
sprintf(evalBuf, "calprefix(%d)", trig.priority);
|
snprintf(evalBuf, sizeof(evalBuf), "calprefix(%d)", trig.priority);
|
||||||
s2 = evalBuf;
|
s2 = evalBuf;
|
||||||
r = EvalExpr(&s2, &v, NULL);
|
r = EvalExpr(&s2, &v, NULL);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
@@ -2157,7 +2233,7 @@ static int DoCalRem(ParsePtr p, int col)
|
|||||||
if (trig.typ != PASSTHRU_TYPE &&
|
if (trig.typ != PASSTHRU_TYPE &&
|
||||||
UserFuncExists("calsuffix")==1) {
|
UserFuncExists("calsuffix")==1) {
|
||||||
char evalBuf[64];
|
char evalBuf[64];
|
||||||
sprintf(evalBuf, "calsuffix(%d)", trig.priority);
|
snprintf(evalBuf, sizeof(evalBuf), "calsuffix(%d)", trig.priority);
|
||||||
s2 = evalBuf;
|
s2 = evalBuf;
|
||||||
r = EvalExpr(&s2, &v, NULL);
|
r = EvalExpr(&s2, &v, NULL);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
@@ -2197,6 +2273,7 @@ static int DoCalRem(ParsePtr p, int col)
|
|||||||
FreeTrig(&trig);
|
FreeTrig(&trig);
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
|
e->infos = NULL;
|
||||||
e->nonconst_expr = nonconst_expr;
|
e->nonconst_expr = nonconst_expr;
|
||||||
e->if_depth = NumIfs;
|
e->if_depth = NumIfs;
|
||||||
e->trig = trig;
|
e->trig = trig;
|
||||||
@@ -2217,6 +2294,7 @@ static int DoCalRem(ParsePtr p, int col)
|
|||||||
if (!e->text || !e->raw_text) {
|
if (!e->text || !e->raw_text) {
|
||||||
if (e->text) free(e->text);
|
if (e->text) free(e->text);
|
||||||
if (e->raw_text) free(e->raw_text);
|
if (e->raw_text) free(e->raw_text);
|
||||||
|
FreeTrigInfoChain(e->infos);
|
||||||
free(e);
|
free(e);
|
||||||
FreeTrig(&trig);
|
FreeTrig(&trig);
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
@@ -2230,12 +2308,17 @@ static int DoCalRem(ParsePtr p, int col)
|
|||||||
AppendTag(&(e->tags), SynthesizeTag());
|
AppendTag(&(e->tags), SynthesizeTag());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Take over any TrigInfo! */
|
||||||
|
e->infos = trig.infos;
|
||||||
|
trig.infos = NULL;
|
||||||
|
|
||||||
/* Don't need tags any more */
|
/* Don't need tags any more */
|
||||||
FreeTrig(&trig);
|
FreeTrig(&trig);
|
||||||
e->duration = tim.duration;
|
e->duration = tim.duration;
|
||||||
e->priority = trig.priority;
|
e->priority = trig.priority;
|
||||||
e->filename = StrDup(FileName);
|
e->filename = StrDup(FileName);
|
||||||
if(!e->filename) {
|
if(!e->filename) {
|
||||||
|
FreeTrigInfoChain(e->infos);
|
||||||
if (e->text) free(e->text);
|
if (e->text) free(e->text);
|
||||||
if (e->raw_text) free(e->raw_text);
|
if (e->raw_text) free(e->raw_text);
|
||||||
#ifdef REM_USE_WCHAR
|
#ifdef REM_USE_WCHAR
|
||||||
@@ -2245,6 +2328,7 @@ static int DoCalRem(ParsePtr p, int col)
|
|||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
e->lineno = LineNo;
|
e->lineno = LineNo;
|
||||||
|
e->lineno_start = LineNoStart;
|
||||||
|
|
||||||
if (trig.typ == PASSTHRU_TYPE || is_color) {
|
if (trig.typ == PASSTHRU_TYPE || is_color) {
|
||||||
StrnCpy(e->passthru, trig.passthru, PASSTHRU_LEN);
|
StrnCpy(e->passthru, trig.passthru, PASSTHRU_LEN);
|
||||||
@@ -2307,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)
|
void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
|
||||||
{
|
{
|
||||||
/* wd is an array of days from 0=monday to 6=sunday.
|
/* wd is an array of days from 0=monday to 6=sunday.
|
||||||
@@ -2398,6 +2517,9 @@ void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
|
|||||||
PrintJSONKeyPairInt("addomit", 1);
|
PrintJSONKeyPairInt("addomit", 1);
|
||||||
}
|
}
|
||||||
if (include_tags) {
|
if (include_tags) {
|
||||||
|
if (t->infos) {
|
||||||
|
WriteJSONInfoChain(t->infos);
|
||||||
|
}
|
||||||
PrintJSONKeyPairString("tags", DBufValue(&(t->tags)));
|
PrintJSONKeyPairString("tags", DBufValue(&(t->tags)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2408,9 +2530,15 @@ static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
|
|||||||
if (DoPrefixLineNo) {
|
if (DoPrefixLineNo) {
|
||||||
PrintJSONKeyPairString("filename", e->filename);
|
PrintJSONKeyPairString("filename", e->filename);
|
||||||
PrintJSONKeyPairInt("lineno", e->lineno);
|
PrintJSONKeyPairInt("lineno", e->lineno);
|
||||||
|
if (e->lineno != e->lineno_start) {
|
||||||
|
PrintJSONKeyPairInt("lineno_start", e->lineno_start);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PrintJSONKeyPairString("passthru", e->passthru);
|
PrintJSONKeyPairString("passthru", e->passthru);
|
||||||
PrintJSONKeyPairString("tags", DBufValue(&(e->tags)));
|
PrintJSONKeyPairString("tags", DBufValue(&(e->tags)));
|
||||||
|
if (e->infos) {
|
||||||
|
WriteJSONInfoChain(e->infos);
|
||||||
|
}
|
||||||
if (e->duration != NO_TIME) {
|
if (e->duration != NO_TIME) {
|
||||||
PrintJSONKeyPairInt("duration", e->duration);
|
PrintJSONKeyPairInt("duration", e->duration);
|
||||||
}
|
}
|
||||||
@@ -2541,6 +2669,7 @@ static void WriteSimpleEntries(int col, int dse)
|
|||||||
free(e->text);
|
free(e->text);
|
||||||
free(e->raw_text);
|
free(e->raw_text);
|
||||||
free(e->filename);
|
free(e->filename);
|
||||||
|
FreeTrigInfoChain(e->infos);
|
||||||
#ifdef REM_USE_WCHAR
|
#ifdef REM_USE_WCHAR
|
||||||
if (e->wc_text) free(e->wc_text);
|
if (e->wc_text) free(e->wc_text);
|
||||||
#endif
|
#endif
|
||||||
@@ -2701,7 +2830,7 @@ CalendarTime(int tim, int duration)
|
|||||||
else hh2 = h2;
|
else hh2 = h2;
|
||||||
|
|
||||||
if (days) {
|
if (days) {
|
||||||
sprintf(daybuf, "+%d", days);
|
snprintf(daybuf, sizeof(daybuf), "+%d", days);
|
||||||
} else {
|
} else {
|
||||||
daybuf[0] = 0;
|
daybuf[0] = 0;
|
||||||
}
|
}
|
||||||
@@ -2724,12 +2853,12 @@ CalendarTime(int tim, int duration)
|
|||||||
|
|
||||||
switch(ScFormat) {
|
switch(ScFormat) {
|
||||||
case SC_AMPM:
|
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);
|
hh, TimeSep, min, ampm1, hh2, TimeSep, min2, ampm2, daybuf);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SC_MIL:
|
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);
|
h, TimeSep, min, h2, TimeSep, min2, daybuf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2747,7 +2876,7 @@ CalendarTime(int tim, int duration)
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
char const *SimpleTime(int tim)
|
char const *SimpleTime(int tim)
|
||||||
{
|
{
|
||||||
static char buf[32];
|
static char buf[128];
|
||||||
int h, min, hh;
|
int h, min, hh;
|
||||||
|
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
@@ -2761,7 +2890,7 @@ char const *SimpleTime(int tim)
|
|||||||
if (h == 0) hh=12;
|
if (h == 0) hh=12;
|
||||||
else if (h > 12) hh=h-12;
|
else if (h > 12) hh=h-12;
|
||||||
else hh=h;
|
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;
|
break;
|
||||||
|
|
||||||
@@ -2769,7 +2898,7 @@ char const *SimpleTime(int tim)
|
|||||||
if (tim != NO_TIME) {
|
if (tim != NO_TIME) {
|
||||||
h = tim / 60;
|
h = tim / 60;
|
||||||
min = tim % 60;
|
min = tim % 60;
|
||||||
sprintf(buf, "%02d%c%02d ", h, TimeSep, min);
|
snprintf(buf, sizeof(buf), "%02d%c%02d ", h, TimeSep, min);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2821,7 +2950,7 @@ char const *SynthesizeTag(void)
|
|||||||
MD5Init(&ctx);
|
MD5Init(&ctx);
|
||||||
MD5Update(&ctx, (unsigned char *) CurLine, strlen(CurLine));
|
MD5Update(&ctx, (unsigned char *) CurLine, strlen(CurLine));
|
||||||
MD5Final(buf, &ctx);
|
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[0], (unsigned int) buf[1],
|
||||||
(unsigned int) buf[2], (unsigned int) buf[3],
|
(unsigned int) buf[2], (unsigned int) buf[3],
|
||||||
(unsigned int) buf[4], (unsigned int) buf[5],
|
(unsigned int) buf[4], (unsigned int) buf[5],
|
||||||
|
|||||||
+1
-1
@@ -116,4 +116,4 @@
|
|||||||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||||
#undef TM_IN_SYS_TIME
|
#undef TM_IN_SYS_TIME
|
||||||
|
|
||||||
#include <custom.h>
|
#include "custom.h"
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
/* which you can customize. */
|
/* which you can customize. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
/* which you can customize. */
|
/* which you can customize. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
+4
-8
@@ -5,7 +5,7 @@
|
|||||||
/* Code to suppress duplicate reminders */
|
/* Code to suppress duplicate reminders */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -167,17 +167,13 @@ InitDedupeTable(void)
|
|||||||
if (hash_table_init(&DedupeTable,
|
if (hash_table_init(&DedupeTable,
|
||||||
offsetof(DedupeEntry, link),
|
offsetof(DedupeEntry, link),
|
||||||
DedupeHashFunc, CompareDedupes) < 0) {
|
DedupeHashFunc, CompareDedupes) < 0) {
|
||||||
fprintf(stderr, "Unable to initialize function hash table: Out of memory. Exiting.\n");
|
fprintf(ErrFp, "Unable to initialize function hash table: Out of memory. Exiting.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
get_dedupe_hash_stats(int *total, int *maxlen, double *avglen)
|
dump_dedupe_hash_stats(void)
|
||||||
{
|
{
|
||||||
struct hash_table_stats s;
|
hash_table_dump_stats(&DedupeTable, ErrFp);
|
||||||
hash_table_get_stats(&DedupeTable, &s);
|
|
||||||
*total = s.num_entries;
|
|
||||||
*maxlen = s.max_len;
|
|
||||||
*avglen = s.avg_len;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-24
@@ -7,7 +7,7 @@
|
|||||||
/* commands. */
|
/* commands. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -67,18 +67,18 @@ check_trigger_function(char const *fname, char const *type)
|
|||||||
if (!f) {
|
if (!f) {
|
||||||
if (strcmp(type, "WARN")) {
|
if (strcmp(type, "WARN")) {
|
||||||
/* Undefined WARN functions are diagnosed elsewhere... */
|
/* Undefined WARN functions are diagnosed elsewhere... */
|
||||||
Wprint("Undefined %s function: `%s'", type, fname);
|
Wprint(tr("Undefined %s function: `%s'"), type, fname);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (f->nargs != 1) {
|
if (f->nargs != 1) {
|
||||||
Wprint("%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;
|
return;
|
||||||
}
|
}
|
||||||
if (ensure_expr_references_first_local_arg(f->node)) {
|
if (ensure_expr_references_first_local_arg(f->node)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Wprint("%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
|
static void
|
||||||
@@ -154,7 +154,7 @@ static void ensure_satnode_mentions_trigdate(expr_node *node)
|
|||||||
if (node->type == N_CONSTANT) {
|
if (node->type == N_CONSTANT) {
|
||||||
if (node->u.value.type == INT_TYPE) {
|
if (node->u.value.type == INT_TYPE) {
|
||||||
if (node->u.value.v.val == 0) {
|
if (node->u.value.v.val == 0) {
|
||||||
Wprint("SATISFY: constant 0 will never be true");
|
Wprint(tr("SATISFY: constant 0 will never be true"));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -166,14 +166,14 @@ static void ensure_satnode_mentions_trigdate(expr_node *node)
|
|||||||
str = node->u.name;
|
str = node->u.name;
|
||||||
}
|
}
|
||||||
if (!*str) {
|
if (!*str) {
|
||||||
Wprint("SATISFY: constant \"\" will never be true");
|
Wprint(tr("SATISFY: constant \"\" will never be true"));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_satnode_mentions_trigdate_aux(node, &mentioned);
|
ensure_satnode_mentions_trigdate_aux(node, &mentioned);
|
||||||
if (!mentioned) {
|
if (!mentioned) {
|
||||||
Wprint("SATISFY: expression has no reference to trigdate() or $T...");
|
Wprint(tr("SATISFY: expression has no reference to trigdate() or $T..."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,6 +408,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
|||||||
tim->duration = NO_TIME;
|
tim->duration = NO_TIME;
|
||||||
trig->need_wkday = 0;
|
trig->need_wkday = 0;
|
||||||
trig->adj_for_last = 0;
|
trig->adj_for_last = 0;
|
||||||
|
trig->infos = NULL;
|
||||||
|
|
||||||
int parsing = 1;
|
int parsing = 1;
|
||||||
while(parsing) {
|
while(parsing) {
|
||||||
@@ -615,7 +616,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
|||||||
case T_Omit:
|
case T_Omit:
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
if (trig->omitfunc[0]) {
|
if (trig->omitfunc[0]) {
|
||||||
Wprint("Warning: OMIT is ignored if you use OMITFUNC");
|
Wprint(tr("Warning: OMIT is ignored if you use OMITFUNC"));
|
||||||
}
|
}
|
||||||
|
|
||||||
r = ParseLocalOmit(s, trig);
|
r = ParseLocalOmit(s, trig);
|
||||||
@@ -629,7 +630,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
|||||||
|
|
||||||
case T_OmitFunc:
|
case T_OmitFunc:
|
||||||
if (trig->localomit) {
|
if (trig->localomit) {
|
||||||
Wprint("Warning: OMIT is ignored if you use OMITFUNC");
|
Wprint(tr("Warning: OMIT is ignored if you use OMITFUNC"));
|
||||||
}
|
}
|
||||||
r=ParseToken(s, &buf);
|
r=ParseToken(s, &buf);
|
||||||
if (r) return r;
|
if (r) return r;
|
||||||
@@ -649,6 +650,15 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
|||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
break;
|
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:
|
case T_Tag:
|
||||||
r = ParseToken(s, &buf);
|
r = ParseToken(s, &buf);
|
||||||
if (r) return r;
|
if (r) return r;
|
||||||
@@ -707,7 +717,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
|||||||
trig->typ = MSG_TYPE;
|
trig->typ = MSG_TYPE;
|
||||||
if (s->isnested) return E_CANT_NEST_RTYPE;
|
if (s->isnested) return E_CANT_NEST_RTYPE;
|
||||||
if (!WarnedAboutImplicit && !SuppressImplicitRemWarnings) {
|
if (!WarnedAboutImplicit && !SuppressImplicitRemWarnings) {
|
||||||
Wprint("Missing REM type; assuming MSG");
|
Wprint(tr("Missing REM type; assuming MSG"));
|
||||||
WarnedAboutImplicit = 1;
|
WarnedAboutImplicit = 1;
|
||||||
}
|
}
|
||||||
parsing = 0;
|
parsing = 0;
|
||||||
@@ -738,22 +748,22 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
|||||||
if (!s->nonconst_expr) {
|
if (!s->nonconst_expr) {
|
||||||
if (trig->y != NO_YR && trig->m != NO_MON && trig->d != NO_DAY && trig->until != NO_UNTIL) {
|
if (trig->y != NO_YR && trig->m != NO_MON && trig->d != NO_DAY && trig->until != NO_UNTIL) {
|
||||||
if (DSE(trig->y, trig->m, trig->d) > trig->until) {
|
if (DSE(trig->y, trig->m, trig->d) > trig->until) {
|
||||||
Wprint("Warning: UNTIL/THROUGH date earlier than start date");
|
Wprint(tr("Warning: UNTIL/THROUGH date earlier than start date"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (trig->from != NO_DATE) {
|
if (trig->from != NO_DATE) {
|
||||||
if (trig->until != NO_UNTIL && trig->until < trig->from) {
|
if (trig->until != NO_UNTIL && trig->until < trig->from) {
|
||||||
Wprint("Warning: UNTIL/THROUGH date earlier than FROM date");
|
Wprint(tr("Warning: UNTIL/THROUGH date earlier than FROM date"));
|
||||||
}
|
}
|
||||||
} else if (trig->scanfrom != NO_DATE) {
|
} else if (trig->scanfrom != NO_DATE) {
|
||||||
if (trig->until != NO_UNTIL && trig->until < trig->scanfrom) {
|
if (trig->until != NO_UNTIL && trig->until < trig->scanfrom) {
|
||||||
Wprint("Warning: UNTIL/THROUGH date earlier than SCANFROM date");
|
Wprint(tr("Warning: UNTIL/THROUGH date earlier than SCANFROM date"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trig->y != NO_YR && trig->m != NO_MON && trig->d != NO_DAY && trig->until != NO_UNTIL && trig->rep == NO_REP) {
|
if (trig->y != NO_YR && trig->m != NO_MON && trig->d != NO_DAY && trig->until != NO_UNTIL && trig->rep == NO_REP) {
|
||||||
Wprint("Warning: Useless use of UNTIL with fully-specified date and no *rep");
|
Wprint(tr("Warning: Useless use of UNTIL with fully-specified date and no *rep"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set scanfrom to default if not set explicitly */
|
/* Set scanfrom to default if not set explicitly */
|
||||||
@@ -1180,7 +1190,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
FromDSE(dse, &y, &m, &d);
|
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) {
|
if (DBufPuts(&calRow, tmpBuf) != OK) {
|
||||||
DBufFree(&calRow);
|
DBufFree(&calRow);
|
||||||
DBufFree(&pre_buf);
|
DBufFree(&pre_buf);
|
||||||
@@ -1201,9 +1211,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
|||||||
DBufPuts(&calRow, "* ");
|
DBufPuts(&calRow, "* ");
|
||||||
}
|
}
|
||||||
if (tim->duration != NO_TIME) {
|
if (tim->duration != NO_TIME) {
|
||||||
sprintf(tmpBuf, "%d ", tim->duration);
|
snprintf(tmpBuf, sizeof(tmpBuf), "%d ", tim->duration);
|
||||||
} else {
|
} else {
|
||||||
sprintf(tmpBuf, "* ");
|
snprintf(tmpBuf, sizeof(tmpBuf), "* ");
|
||||||
}
|
}
|
||||||
if (DBufPuts(&calRow, tmpBuf) != OK) {
|
if (DBufPuts(&calRow, tmpBuf) != OK) {
|
||||||
DBufFree(&calRow);
|
DBufFree(&calRow);
|
||||||
@@ -1211,9 +1221,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
|||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
if (tim->ttime != NO_TIME) {
|
if (tim->ttime != NO_TIME) {
|
||||||
sprintf(tmpBuf, "%d ", tim->ttime);
|
snprintf(tmpBuf, sizeof(tmpBuf), "%d ", tim->ttime);
|
||||||
} else {
|
} else {
|
||||||
sprintf(tmpBuf, "* ");
|
snprintf(tmpBuf, sizeof(tmpBuf), "* ");
|
||||||
}
|
}
|
||||||
if (DBufPuts(&calRow, tmpBuf) != OK) {
|
if (DBufPuts(&calRow, tmpBuf) != OK) {
|
||||||
DBufFree(&calRow);
|
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 */
|
/* Don't use msgprefix() on RUN-type reminders */
|
||||||
if (t->typ != RUN_TYPE) {
|
if (t->typ != RUN_TYPE) {
|
||||||
if (UserFuncExists("msgprefix") == 1) {
|
if (UserFuncExists("msgprefix") == 1) {
|
||||||
sprintf(PrioExpr, "msgprefix(%d)", t->priority);
|
snprintf(PrioExpr, sizeof(PrioExpr), "msgprefix(%d)", t->priority);
|
||||||
s = PrioExpr;
|
s = PrioExpr;
|
||||||
r = EvalExpr(&s, &v, NULL);
|
r = EvalExpr(&s, &v, NULL);
|
||||||
if (!r) {
|
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 (t->typ != RUN_TYPE) {
|
||||||
if (UserFuncExists("msgsuffix") == 1) {
|
if (UserFuncExists("msgsuffix") == 1) {
|
||||||
sprintf(PrioExpr, "msgsuffix(%d)", t->priority);
|
snprintf(PrioExpr, sizeof(PrioExpr), "msgsuffix(%d)", t->priority);
|
||||||
s = PrioExpr;
|
s = PrioExpr;
|
||||||
r = EvalExpr(&s, &v, NULL);
|
r = EvalExpr(&s, &v, NULL);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
@@ -1548,8 +1558,8 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
|
|||||||
if (DebugFlag & DB_PRTTRIG) {
|
if (DebugFlag & DB_PRTTRIG) {
|
||||||
int y, m, d;
|
int y, m, d;
|
||||||
FromDSE(LastTriggerDate, &y, &m, &d);
|
FromDSE(LastTriggerDate, &y, &m, &d);
|
||||||
fprintf(ErrFp, "%s(%d): Trig(satisfied) = %s, %d %s, %d",
|
fprintf(ErrFp, "%s(%s): Trig(satisfied) = %s, %d %s, %d",
|
||||||
FileName, LineNo,
|
FileName, line_range(LineNoStart, LineNo),
|
||||||
get_day_name(LastTriggerDate % 7),
|
get_day_name(LastTriggerDate % 7),
|
||||||
d,
|
d,
|
||||||
get_month_name(m),
|
get_month_name(m),
|
||||||
@@ -1694,7 +1704,7 @@ static int ShouldTriggerBasedOnWarn(Trigger *t, int dse, int *err)
|
|||||||
return (dse == DSEToday);
|
return (dse == DSEToday);
|
||||||
}
|
}
|
||||||
for (i=1; ; i++) {
|
for (i=1; ; i++) {
|
||||||
sprintf(buffer, "%s(%d)", t->warn, i);
|
snprintf(buffer, sizeof(buffer), "%s(%d)", t->warn, i);
|
||||||
s = buffer;
|
s = buffer;
|
||||||
r = EvalExpr(&s, &v, NULL);
|
r = EvalExpr(&s, &v, NULL);
|
||||||
if (r) {
|
if (r) {
|
||||||
|
|||||||
+48
-8
@@ -6,7 +6,7 @@
|
|||||||
/* reminders are triggered. */
|
/* reminders are triggered. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -40,8 +40,8 @@ check_subst_args(UserFunc *f, int n)
|
|||||||
if (f->nargs == n) {
|
if (f->nargs == n) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Wprint("Function `%s' defined at %s:%d should take %d argument%s, but actually takes %d",
|
Wprint(tr("Function `%s' defined at %s(%s) should take %d argument%s, but actually takes %d"),
|
||||||
f->name, f->filename, f->lineno, n, (n == 1 ? "" : "s"), f->nargs);
|
f->name, f->filename, line_range(f->lineno_start, f->lineno), n, (n == 1 ? "" : "s"), f->nargs);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -79,6 +79,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
int origLen = DBufLen(dbuf);
|
int origLen = DBufLen(dbuf);
|
||||||
int altmode;
|
int altmode;
|
||||||
int r;
|
int r;
|
||||||
|
int origtime;
|
||||||
Value v;
|
Value v;
|
||||||
UserFunc *func;
|
UserFunc *func;
|
||||||
|
|
||||||
@@ -87,6 +88,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
if (tt) {
|
if (tt) {
|
||||||
tim = tt->ttime;
|
tim = tt->ttime;
|
||||||
}
|
}
|
||||||
|
origtime = tim;
|
||||||
if (tim == NO_TIME) tim = curtime;
|
if (tim == NO_TIME) tim = curtime;
|
||||||
tdiff = tim - curtime;
|
tdiff = tim - curtime;
|
||||||
adiff = ABS(tdiff);
|
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");
|
pm = (h < 12) ? tr("am") : tr("pm");
|
||||||
}
|
}
|
||||||
|
|
||||||
hh = (h == 12) ? 12 : h % 12;
|
hh = (h == 12 || h == 0) ? 12 : h % 12;
|
||||||
|
|
||||||
ch = curtime / 60;
|
ch = curtime / 60;
|
||||||
cmin = curtime % 60;
|
cmin = curtime % 60;
|
||||||
@@ -149,7 +151,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
cpm = (h < 12) ? tr("am") : tr("pm");
|
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");
|
func = FindUserFunc("subst_ordinal");
|
||||||
if (func && check_subst_args(func, 1)) {
|
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) {
|
if (!c) {
|
||||||
break;
|
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 == '(') {
|
if (c == '(') {
|
||||||
DynamicBuffer orig;
|
DynamicBuffer orig;
|
||||||
DynamicBuffer translated;
|
DynamicBuffer translated;
|
||||||
@@ -232,7 +261,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
DBufPutc(&orig, c);
|
DBufPutc(&orig, c);
|
||||||
}
|
}
|
||||||
if (!c) {
|
if (!c) {
|
||||||
Wprint("Warning: Unterminated %%(...) substitution sequence");
|
Wprint(tr("Warning: Unterminated %%(...) substitution sequence"));
|
||||||
}
|
}
|
||||||
err = OK;
|
err = OK;
|
||||||
if (GetTranslatedStringTryingVariants(DBufValue(&orig), &translated)) {
|
if (GetTranslatedStringTryingVariants(DBufValue(&orig), &translated)) {
|
||||||
@@ -240,6 +269,9 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
} else {
|
} else {
|
||||||
err = DBufPuts(dbuf, DBufValue(&orig));
|
err = DBufPuts(dbuf, DBufValue(&orig));
|
||||||
}
|
}
|
||||||
|
if (DebugFlag & DB_TRANSLATE) {
|
||||||
|
TranslationTemplate(DBufValue(&orig));
|
||||||
|
}
|
||||||
DBufFree(&orig);
|
DBufFree(&orig);
|
||||||
DBufFree(&translated);
|
DBufFree(&translated);
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
@@ -275,11 +307,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!c) {
|
if (!c) {
|
||||||
Wprint("Warning: Unterminated %%{...} substitution sequence");
|
Wprint(tr("Warning: Unterminated %%{...} substitution sequence"));
|
||||||
}
|
}
|
||||||
func = FindUserFunc(s);
|
func = FindUserFunc(s);
|
||||||
if (!func) {
|
if (!func) {
|
||||||
Wprint("No substition function `%s' defined", s);
|
Wprint(tr("No substition function `%s' defined"), s);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,6 +407,12 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
Eprint("%s", GetErr(r));
|
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)) {
|
switch(UPPER(c)) {
|
||||||
case 'A':
|
case 'A':
|
||||||
if (altmode == '*' || !strcmp(tr("on"), "")) {
|
if (altmode == '*' || !strcmp(tr("on"), "")) {
|
||||||
@@ -752,6 +790,8 @@ int DoSubstFromString(char const *source, DynamicBuffer *dbuf,
|
|||||||
if (tim == NO_TIME) tim=MinutesPastMidnight(0);
|
if (tim == NO_TIME) tim=MinutesPastMidnight(0);
|
||||||
CreateParser(source, &tempP);
|
CreateParser(source, &tempP);
|
||||||
tempP.allownested = 0;
|
tempP.allownested = 0;
|
||||||
|
tempTrig.infos = NULL;
|
||||||
|
DBufInit(&tempTrig.tags);
|
||||||
tempTrig.typ = MSG_TYPE;
|
tempTrig.typ = MSG_TYPE;
|
||||||
tempTime.ttime = tim;
|
tempTime.ttime = tim;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
/* buffers. */
|
/* buffers. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
/* Declaration of functions for manipulating dynamic buffers */
|
/* Declaration of functions for manipulating dynamic buffers */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
/* Error definitions. */
|
/* Error definitions. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -230,20 +230,20 @@ EXTERN char *ErrMsg[]
|
|||||||
/* E_EXPIRED */ "Expired",
|
/* E_EXPIRED */ "Expired",
|
||||||
/* E_CANTFORK */ "fork() failed - can't do queued reminders",
|
/* E_CANTFORK */ "fork() failed - can't do queued reminders",
|
||||||
/* E_CANTACCESS */ "Can't access file",
|
/* E_CANTACCESS */ "Can't access file",
|
||||||
/* M_BAD_SYS_DATE */ "Illegal system date: Year is less than %d\n",
|
/* M_BAD_SYS_DATE */ "Illegal system date: Year is less than %d",
|
||||||
/* M_BAD_DB_FLAG */ "Unknown debug flag '%c'\n",
|
/* M_BAD_DB_FLAG */ "Unknown debug flag '%c'",
|
||||||
/* M_BAD_OPTION */ "Unknown option '%c'\n",
|
/* M_BAD_OPTION */ "Unknown option '%c'",
|
||||||
/* M_BAD_USER */ "Unknown user '%s'\n",
|
/* M_BAD_USER */ "Unknown user '%s'",
|
||||||
/* M_NO_CHG_GID */ "Could not change gid to %d\n",
|
/* M_NO_CHG_GID */ "Could not change gid to %d",
|
||||||
/* M_NO_CHG_UID */ "Could not change uid to %d\n",
|
/* M_NO_CHG_UID */ "Could not change uid to %d",
|
||||||
/* M_NOMEM_ENV */ "Out of memory for environment\n",
|
/* M_NOMEM_ENV */ "Out of memory for environment",
|
||||||
/* E_MISS_EQ */ "Missing '=' sign",
|
/* E_MISS_EQ */ "Missing '=' sign",
|
||||||
/* E_MISS_VAR */ "Missing variable name",
|
/* E_MISS_VAR */ "Missing variable name",
|
||||||
/* E_MISS_EXPR */ "Missing expression",
|
/* E_MISS_EXPR */ "Missing expression",
|
||||||
/* M_CANTSET_ACCESS */ "",
|
/* M_CANTSET_ACCESS */ "",
|
||||||
/* M_I_OPTION */ "Remind: '-i' option: %s\n",
|
/* M_I_OPTION */ "Remind: '-i' option: %s",
|
||||||
/* E_NOREMINDERS */ "No reminders.",
|
/* E_NOREMINDERS */ "No reminders.",
|
||||||
/* M_QUEUED */ "%d reminder(s) queued for later today.\n",
|
/* M_QUEUED */ "%d reminder(s) queued for later today.",
|
||||||
/* E_EXPECTING_NUMBER */ "Expecting number",
|
/* E_EXPECTING_NUMBER */ "Expecting number",
|
||||||
/* M_BAD_WARN_FUNC */ "Undefined WARN function",
|
/* M_BAD_WARN_FUNC */ "Undefined WARN function",
|
||||||
/* E_CANT_CONVERT_TZ */ "Can't convert between time zones",
|
/* E_CANT_CONVERT_TZ */ "Can't convert between time zones",
|
||||||
|
|||||||
+112
-25
@@ -12,7 +12,7 @@
|
|||||||
/* evaluated. */
|
/* evaluated. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -197,7 +197,47 @@ static char const *get_operator_name(expr_node *node);
|
|||||||
static UserFunc *CurrentUserFunc = NULL;
|
static UserFunc *CurrentUserFunc = NULL;
|
||||||
|
|
||||||
/* How many expr_node objects to allocate at a time */
|
/* 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)
|
||||||
|
{
|
||||||
|
char const *e = s;
|
||||||
|
int in_quoted_string = 0;
|
||||||
|
int escaped = 0;
|
||||||
|
|
||||||
|
while(*e) {
|
||||||
|
if (in_quoted_string) {
|
||||||
|
if (escaped) {
|
||||||
|
escaped = 0;
|
||||||
|
e++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*e == '\\') {
|
||||||
|
escaped = 1;
|
||||||
|
e++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*e == '"') {
|
||||||
|
in_quoted_string = 0;
|
||||||
|
e++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
e++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*e == '"') {
|
||||||
|
in_quoted_string = 1;
|
||||||
|
e++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*e == ']') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e++;
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
@@ -586,6 +626,18 @@ debug_exit_userfunc(expr_node *node, Value *ans, int r, Value *locals, int nargs
|
|||||||
fprintf(ErrFp, "\n");
|
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 */
|
/* eval_userfunc - evaluate a user-defined function */
|
||||||
@@ -627,12 +679,12 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
|
|||||||
|
|
||||||
/* Make sure we have the right number of arguments */
|
/* Make sure we have the right number of arguments */
|
||||||
if (node->num_kids < f->nargs) {
|
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));
|
Eprint("%s(): %s", f->name, GetErr(E_2FEW_ARGS));
|
||||||
return E_2FEW_ARGS;
|
return E_2FEW_ARGS;
|
||||||
}
|
}
|
||||||
if (node->num_kids > f->nargs) {
|
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));
|
Eprint("%s(): %s", f->name, GetErr(E_2MANY_ARGS));
|
||||||
return E_2MANY_ARGS;
|
return E_2MANY_ARGS;
|
||||||
}
|
}
|
||||||
@@ -683,7 +735,7 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
|
|||||||
FuncRecursionLevel++;
|
FuncRecursionLevel++;
|
||||||
|
|
||||||
/* Add a call to the call stack for better error messages */
|
/* 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));
|
DBG(debug_enter_userfunc(node, new_locals, f->nargs));
|
||||||
|
|
||||||
@@ -1090,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 either is a string, coerce them both to strings and concatenate */
|
||||||
if (v1.type == STR_TYPE || v2.type == STR_TYPE) {
|
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 o1 = v1;
|
||||||
Value o2 = v2;
|
Value o2 = v2;
|
||||||
if ( (r = DoCoerce(STR_TYPE, &v1)) ) {
|
if ( (r = DoCoerce(STR_TYPE, &v1)) ) {
|
||||||
@@ -1124,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, v1.v.str);
|
||||||
strcpy(ans->v.str+l1, v2.v.str);
|
strcpy(ans->v.str+l1, v2.v.str);
|
||||||
DBG(debug_evaluation_binop(ans, OK, &o1, &o2, "+"));
|
DBG(debug_evaluation_binop(ans, OK, &o1, &o2, "+"));
|
||||||
|
DestroyValue(v1);
|
||||||
|
DestroyValue(v2);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1506,6 +1560,8 @@ static int parse_expr_token(DynamicBuffer *buf, char const **in)
|
|||||||
{
|
{
|
||||||
|
|
||||||
char c;
|
char c;
|
||||||
|
char c2;
|
||||||
|
char hexbuf[3];
|
||||||
|
|
||||||
DBufFree(buf);
|
DBufFree(buf);
|
||||||
|
|
||||||
@@ -1541,7 +1597,7 @@ static int parse_expr_token(DynamicBuffer *buf, char const **in)
|
|||||||
}
|
}
|
||||||
(*in)++;
|
(*in)++;
|
||||||
} else {
|
} else {
|
||||||
Eprint("%s `%c' (did you mean `%c%c'?)", GetErr(E_PARSE_ERR), c, c, c);
|
Eprint("%s `%c' (%s `%c%c'?)", GetErr(E_PARSE_ERR), c, tr("did you mean"), c, c);
|
||||||
return E_PARSE_ERR;
|
return E_PARSE_ERR;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
@@ -1593,8 +1649,32 @@ static int parse_expr_token(DynamicBuffer *buf, char const **in)
|
|||||||
case 'v':
|
case 'v':
|
||||||
r = DBufPutc(buf, '\v');
|
r = DBufPutc(buf, '\v');
|
||||||
break;
|
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:
|
default:
|
||||||
r = DBufPutc(buf, **in);
|
r = DBufPutc(buf, **in);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
(*in)++;
|
(*in)++;
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
@@ -1837,8 +1917,8 @@ static expr_node * parse_function_call(char const **e, int *r, Var *locals, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ptr = *e;
|
||||||
if (TOKEN_IS(")")) {
|
if (TOKEN_IS(")")) {
|
||||||
ptr = *e;
|
|
||||||
*r = GET_TOKEN();
|
*r = GET_TOKEN();
|
||||||
if (*r != OK) {
|
if (*r != OK) {
|
||||||
return free_expr_tree(node);
|
return free_expr_tree(node);
|
||||||
@@ -2122,7 +2202,6 @@ static expr_node *parse_atom(char const **e, int *r, Var *locals, int level)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!ISID(*s) &&
|
if (!ISID(*s) &&
|
||||||
*s != '%' &&
|
|
||||||
*s != '$' &&
|
*s != '$' &&
|
||||||
*s != '"' &&
|
*s != '"' &&
|
||||||
*s != '\'') {
|
*s != '\'') {
|
||||||
@@ -2137,6 +2216,7 @@ static expr_node *parse_atom(char const **e, int *r, Var *locals, int level)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* It's a constant or a variable reference */
|
/* It's a constant or a variable reference */
|
||||||
|
char const *olds = *e;
|
||||||
*r = GET_TOKEN();
|
*r = GET_TOKEN();
|
||||||
if (*r != OK) return NULL;
|
if (*r != OK) return NULL;
|
||||||
node = alloc_expr_node(r);
|
node = alloc_expr_node(r);
|
||||||
@@ -2145,6 +2225,8 @@ static expr_node *parse_atom(char const **e, int *r, Var *locals, int level)
|
|||||||
}
|
}
|
||||||
*r = make_atom(node, locals);
|
*r = make_atom(node, locals);
|
||||||
if (*r != OK) {
|
if (*r != OK) {
|
||||||
|
/* Preserve location for error position when we print ^-- here */
|
||||||
|
*e = olds;
|
||||||
return free_expr_tree(node);
|
return free_expr_tree(node);
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
@@ -2498,6 +2580,7 @@ expr_node *parse_expression(char const **e, int *r, Var *locals)
|
|||||||
{
|
{
|
||||||
char const *orig = *e;
|
char const *orig = *e;
|
||||||
char const *o2 = *e;
|
char const *o2 = *e;
|
||||||
|
char const *end_of_expr;
|
||||||
if (ExpressionEvaluationDisabled) {
|
if (ExpressionEvaluationDisabled) {
|
||||||
*r = E_EXPR_DISABLED;
|
*r = E_EXPR_DISABLED;
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -2529,25 +2612,29 @@ expr_node *parse_expression(char const **e, int *r, Var *locals)
|
|||||||
*r == E_2FEW_ARGS ||
|
*r == E_2FEW_ARGS ||
|
||||||
*r == E_PARSE_ERR ||
|
*r == E_PARSE_ERR ||
|
||||||
*r == E_EOLN ||
|
*r == E_EOLN ||
|
||||||
|
*r == E_BAD_NUMBER ||
|
||||||
|
*r == E_BAD_DATE ||
|
||||||
|
*r == E_BAD_TIME ||
|
||||||
*r == E_ILLEGAL_CHAR) {
|
*r == E_ILLEGAL_CHAR) {
|
||||||
orig = o2;
|
end_of_expr = find_end_of_expr(orig);
|
||||||
while (*orig) {
|
while (**e && isempty(**e)) {
|
||||||
|
(*e)++;
|
||||||
|
}
|
||||||
|
while (*orig && ((orig < end_of_expr) || (orig <= *e))) {
|
||||||
if (*orig == '\n') {
|
if (*orig == '\n') {
|
||||||
fprintf(ErrFp, " ");
|
fprintf(ErrFp, " ");
|
||||||
orig++;
|
|
||||||
} else if (*orig == ']' && ! *(orig+1)) {
|
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(ErrFp, "%c", *orig++);
|
fprintf(ErrFp, "%c", *orig);
|
||||||
}
|
}
|
||||||
|
orig++;
|
||||||
}
|
}
|
||||||
fprintf(ErrFp, "\n");
|
fprintf(ErrFp, "\n");
|
||||||
orig = o2;
|
orig = o2;
|
||||||
while ((orig < *e) && *orig) {
|
while (*orig && (orig < *e || isspace(*orig))) {
|
||||||
orig++;
|
orig++;
|
||||||
fprintf(ErrFp, " ");
|
fprintf(ErrFp, " ");
|
||||||
}
|
}
|
||||||
fprintf(ErrFp, "^-- here\n");
|
fprintf(ErrFp, "^-- %s\n", tr("here"));
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -2966,12 +3053,12 @@ int DoCoerce(char type, Value *v)
|
|||||||
}
|
}
|
||||||
case STR_TYPE:
|
case STR_TYPE:
|
||||||
switch(v->type) {
|
switch(v->type) {
|
||||||
case INT_TYPE: sprintf(coerce_buf, "%d", v->v.val); break;
|
case INT_TYPE: snprintf(coerce_buf, sizeof(coerce_buf), "%d", v->v.val); break;
|
||||||
case TIME_TYPE: sprintf(coerce_buf, "%02d%c%02d", v->v.val / 60,
|
case TIME_TYPE: snprintf(coerce_buf, sizeof(coerce_buf), "%02d%c%02d", v->v.val / 60,
|
||||||
TimeSep, v->v.val % 60);
|
TimeSep, v->v.val % 60);
|
||||||
break;
|
break;
|
||||||
case DATE_TYPE: FromDSE(v->v.val, &y, &m, &d);
|
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);
|
y, DateSep, m+1, DateSep, d);
|
||||||
break;
|
break;
|
||||||
case DATETIME_TYPE:
|
case DATETIME_TYPE:
|
||||||
@@ -2980,7 +3067,7 @@ int DoCoerce(char type, Value *v)
|
|||||||
k = v->v.val % MINUTES_PER_DAY;
|
k = v->v.val % MINUTES_PER_DAY;
|
||||||
h = k / 60;
|
h = k / 60;
|
||||||
i = 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);
|
y, DateSep, m+1, DateSep, d, DateTimeSep, h, TimeSep, i);
|
||||||
break;
|
break;
|
||||||
default: return E_CANT_COERCE;
|
default: return E_CANT_COERCE;
|
||||||
@@ -3088,10 +3175,10 @@ int DoCoerce(char type, Value *v)
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
void print_expr_nodes_stats(void)
|
void print_expr_nodes_stats(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, " Expression nodes allocated: %d\n", ExprNodesAllocated);
|
fprintf(ErrFp, " Expression nodes allocated: %d\n", ExprNodesAllocated);
|
||||||
fprintf(stderr, "Expression nodes high-water: %d\n", ExprNodesHighWater);
|
fprintf(ErrFp, "Expression nodes high-water: %d\n", ExprNodesHighWater);
|
||||||
fprintf(stderr, " Expression nodes leaked: %d\n", ExprNodesUsed);
|
fprintf(ErrFp, " Expression nodes leaked: %d\n", ExprNodesUsed);
|
||||||
fprintf(stderr, " Parse level high-water: %d\n", parse_level_high_water);
|
fprintf(ErrFp, " Parse level high-water: %d\n", parse_level_high_water);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return 1 if a value is "true" for its type, 0 if "false" */
|
/* Return 1 if a value is "true" for its type, 0 if "false" */
|
||||||
|
|||||||
+39
-15
@@ -7,7 +7,7 @@
|
|||||||
/* files. */
|
/* files. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -50,6 +50,7 @@ typedef struct cache {
|
|||||||
struct cache *next;
|
struct cache *next;
|
||||||
char const *text;
|
char const *text;
|
||||||
int LineNo;
|
int LineNo;
|
||||||
|
int LineNoStart;
|
||||||
} CachedLine;
|
} CachedLine;
|
||||||
|
|
||||||
typedef struct cheader {
|
typedef struct cheader {
|
||||||
@@ -77,6 +78,7 @@ typedef struct {
|
|||||||
char const *filename;
|
char const *filename;
|
||||||
FilenameChain *chain;
|
FilenameChain *chain;
|
||||||
int LineNo;
|
int LineNo;
|
||||||
|
int LineNoStart;
|
||||||
unsigned int IfFlags;
|
unsigned int IfFlags;
|
||||||
int NumIfs;
|
int NumIfs;
|
||||||
int IfLinenos[IF_NEST];
|
int IfLinenos[IF_NEST];
|
||||||
@@ -145,7 +147,8 @@ static void OpenPurgeFile(char const *fname, char const *mode)
|
|||||||
if (DBufPuts(&fname_buf, ".purged") != OK) return;
|
if (DBufPuts(&fname_buf, ".purged") != OK) return;
|
||||||
PurgeFP = fopen(DBufValue(&fname_buf), mode);
|
PurgeFP = fopen(DBufValue(&fname_buf), mode);
|
||||||
if (!PurgeFP) {
|
if (!PurgeFP) {
|
||||||
fprintf(ErrFp, "Cannot open `%s' for writing: %s\n", DBufValue(&fname_buf), strerror(errno));
|
fprintf(ErrFp, tr("Cannot open `%s' for writing: %s"), DBufValue(&fname_buf), strerror(errno));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
set_cloexec(PurgeFP);
|
set_cloexec(PurgeFP);
|
||||||
DBufFree(&fname_buf);
|
DBufFree(&fname_buf);
|
||||||
@@ -188,6 +191,7 @@ int ReadLine(void)
|
|||||||
if (CLine) {
|
if (CLine) {
|
||||||
CurLine = CLine->text;
|
CurLine = CLine->text;
|
||||||
LineNo = CLine->LineNo;
|
LineNo = CLine->LineNo;
|
||||||
|
LineNoStart = CLine->LineNoStart;
|
||||||
CLine = CLine->next;
|
CLine = CLine->next;
|
||||||
got_a_fresh_line();
|
got_a_fresh_line();
|
||||||
clear_callstack();
|
clear_callstack();
|
||||||
@@ -217,6 +221,7 @@ static int ReadLineFromFile(int use_pclose)
|
|||||||
DBufInit(&buf);
|
DBufInit(&buf);
|
||||||
DBufFree(&LineBuffer);
|
DBufFree(&LineBuffer);
|
||||||
|
|
||||||
|
LineNoStart = LineNo+1;
|
||||||
while(fp) {
|
while(fp) {
|
||||||
if (DBufGets(&buf, fp) != OK) {
|
if (DBufGets(&buf, fp) != OK) {
|
||||||
DBufFree(&LineBuffer);
|
DBufFree(&LineBuffer);
|
||||||
@@ -325,11 +330,13 @@ int OpenFile(char const *fname)
|
|||||||
while (h) {
|
while (h) {
|
||||||
if (!strcmp(fname, h->filename)) {
|
if (!strcmp(fname, h->filename)) {
|
||||||
if (DebugFlag & DB_TRACE_FILES) {
|
if (DebugFlag & DB_TRACE_FILES) {
|
||||||
fprintf(ErrFp, "Reading `%s': Found in cache\n", fname);
|
fprintf(ErrFp, tr("Reading `%s': Found in cache"), fname);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
CLine = h->cache;
|
CLine = h->cache;
|
||||||
STRSET(FileName, fname);
|
STRSET(FileName, fname);
|
||||||
LineNo = 0;
|
LineNo = 0;
|
||||||
|
LineNoStart = 0;
|
||||||
if (!h->ownedByMe) {
|
if (!h->ownedByMe) {
|
||||||
RunDisabled |= RUN_NOTOWNER;
|
RunDisabled |= RUN_NOTOWNER;
|
||||||
} else {
|
} else {
|
||||||
@@ -348,13 +355,14 @@ int OpenFile(char const *fname)
|
|||||||
PurgeFP = stdout;
|
PurgeFP = stdout;
|
||||||
}
|
}
|
||||||
if (DebugFlag & DB_TRACE_FILES) {
|
if (DebugFlag & DB_TRACE_FILES) {
|
||||||
fprintf(ErrFp, "Reading `-': Reading stdin\n");
|
fprintf(ErrFp, "%s\n", tr("Reading `-': Reading stdin"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fp = fopen(fname, "r");
|
fp = fopen(fname, "r");
|
||||||
set_cloexec(fp);
|
set_cloexec(fp);
|
||||||
if (DebugFlag & DB_TRACE_FILES) {
|
if (DebugFlag & DB_TRACE_FILES) {
|
||||||
fprintf(ErrFp, "Reading `%s': Opening file on disk\n", fname);
|
fprintf(ErrFp, tr("Reading `%s': Opening file on disk"), fname);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
if (PurgeMode) {
|
if (PurgeMode) {
|
||||||
OpenPurgeFile(fname, "w");
|
OpenPurgeFile(fname, "w");
|
||||||
@@ -364,6 +372,7 @@ int OpenFile(char const *fname)
|
|||||||
CLine = NULL;
|
CLine = NULL;
|
||||||
if (ShouldCache) {
|
if (ShouldCache) {
|
||||||
LineNo = 0;
|
LineNo = 0;
|
||||||
|
LineNoStart = 0;
|
||||||
r = CacheFile(fname, 0);
|
r = CacheFile(fname, 0);
|
||||||
if (r == OK) {
|
if (r == OK) {
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
@@ -382,6 +391,7 @@ int OpenFile(char const *fname)
|
|||||||
}
|
}
|
||||||
STRSET(FileName, fname);
|
STRSET(FileName, fname);
|
||||||
LineNo = 0;
|
LineNo = 0;
|
||||||
|
LineNoStart = 0;
|
||||||
if (FileName) return OK; else return E_NO_MEM;
|
if (FileName) return OK; else return E_NO_MEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,7 +411,8 @@ static int CacheFile(char const *fname, int use_pclose)
|
|||||||
char const *s;
|
char const *s;
|
||||||
|
|
||||||
if (DebugFlag & DB_TRACE_FILES) {
|
if (DebugFlag & DB_TRACE_FILES) {
|
||||||
fprintf(ErrFp, "Caching file `%s' in memory\n", fname);
|
fprintf(ErrFp, tr("Caching file `%s' in memory"), fname);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
cl = NULL;
|
cl = NULL;
|
||||||
/* Create a file header */
|
/* Create a file header */
|
||||||
@@ -483,6 +494,7 @@ static int CacheFile(char const *fname, int use_pclose)
|
|||||||
}
|
}
|
||||||
cl->next = NULL;
|
cl->next = NULL;
|
||||||
cl->LineNo = LineNo;
|
cl->LineNo = LineNo;
|
||||||
|
cl->LineNoStart = LineNoStart;
|
||||||
cl->text = StrDup(s);
|
cl->text = StrDup(s);
|
||||||
DBufFree(&LineBuffer);
|
DBufFree(&LineBuffer);
|
||||||
if (!cl->text) {
|
if (!cl->text) {
|
||||||
@@ -539,7 +551,8 @@ static int PopFile(void)
|
|||||||
if (!Hush && NumIfs) {
|
if (!Hush && NumIfs) {
|
||||||
Eprint("%s", GetErr(E_MISS_ENDIF));
|
Eprint("%s", GetErr(E_MISS_ENDIF));
|
||||||
for (j=NumIfs-1; j >=0; j--) {
|
for (j=NumIfs-1; j >=0; j--) {
|
||||||
fprintf(ErrFp, "%s(%d): IF without ENDIF\n", FileName, IfLinenos[j]);
|
fprintf(ErrFp, tr("%s(%d): IF without ENDIF"), FileName, IfLinenos[j]);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!IStackPtr) return E_EOF;
|
if (!IStackPtr) return E_EOF;
|
||||||
@@ -560,6 +573,7 @@ static int PopFile(void)
|
|||||||
IStackPtr--;
|
IStackPtr--;
|
||||||
|
|
||||||
LineNo = i->LineNo;
|
LineNo = i->LineNo;
|
||||||
|
LineNoStart = i->LineNoStart;
|
||||||
IfFlags = i->IfFlags;
|
IfFlags = i->IfFlags;
|
||||||
memcpy(IfLinenos, i->IfLinenos, IF_NEST);
|
memcpy(IfLinenos, i->IfLinenos, IF_NEST);
|
||||||
NumIfs = i->NumIfs;
|
NumIfs = i->NumIfs;
|
||||||
@@ -608,7 +622,7 @@ int DoInclude(ParsePtr p, enum TokTypes tok)
|
|||||||
DBufInit(&buf);
|
DBufInit(&buf);
|
||||||
DBufInit(&fullname);
|
DBufInit(&fullname);
|
||||||
DBufInit(&path);
|
DBufInit(&path);
|
||||||
if ( (r=ParseToken(p, &buf)) ) return r;
|
if ( (r=ParseTokenOrQuotedString(p, &buf)) ) return r;
|
||||||
e = VerifyEoln(p);
|
e = VerifyEoln(p);
|
||||||
if (e) Eprint("%s", GetErr(e));
|
if (e) Eprint("%s", GetErr(e));
|
||||||
|
|
||||||
@@ -760,8 +774,9 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
|
|||||||
while(dc) {
|
while(dc) {
|
||||||
if (!strcmp(dc->dirname, dir)) {
|
if (!strcmp(dc->dirname, dir)) {
|
||||||
if (DebugFlag & DB_TRACE_FILES) {
|
if (DebugFlag & DB_TRACE_FILES) {
|
||||||
fprintf(ErrFp, "Found cached directory listing for `%s'\n",
|
fprintf(ErrFp, tr("Found cached directory listing for `%s'"),
|
||||||
dir);
|
dir);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
free(dir);
|
free(dir);
|
||||||
i->chain = dc->chain;
|
i->chain = dc->chain;
|
||||||
@@ -771,7 +786,8 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (DebugFlag & DB_TRACE_FILES) {
|
if (DebugFlag & DB_TRACE_FILES) {
|
||||||
fprintf(ErrFp, "Scanning directory `%s' for *.rem files\n", dir);
|
fprintf(ErrFp, tr("Scanning directory `%s' for *.rem files"), dir);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldCache) {
|
if (ShouldCache) {
|
||||||
@@ -785,7 +801,8 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
|
|||||||
}
|
}
|
||||||
if (dc) {
|
if (dc) {
|
||||||
if (DebugFlag & DB_TRACE_FILES) {
|
if (DebugFlag & DB_TRACE_FILES) {
|
||||||
fprintf(ErrFp, "Caching directory `%s' listing\n", dir);
|
fprintf(ErrFp, tr("Caching directory `%s' listing"), dir);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
dc->chain = NULL;
|
dc->chain = NULL;
|
||||||
@@ -898,6 +915,7 @@ static int IncludeCmd(char const *cmd)
|
|||||||
}
|
}
|
||||||
i->ownedByMe = 1;
|
i->ownedByMe = 1;
|
||||||
i->LineNo = LineNo;
|
i->LineNo = LineNo;
|
||||||
|
i->LineNoStart = LineNo;
|
||||||
i->NumIfs = NumIfs;
|
i->NumIfs = NumIfs;
|
||||||
i->IfFlags = IfFlags;
|
i->IfFlags = IfFlags;
|
||||||
memcpy(i->IfLinenos, IfLinenos, IF_NEST);
|
memcpy(i->IfLinenos, IfLinenos, IF_NEST);
|
||||||
@@ -917,12 +935,14 @@ static int IncludeCmd(char const *cmd)
|
|||||||
while(h) {
|
while(h) {
|
||||||
if (!strcmp(fname, h->filename)) {
|
if (!strcmp(fname, h->filename)) {
|
||||||
if (DebugFlag & DB_TRACE_FILES) {
|
if (DebugFlag & DB_TRACE_FILES) {
|
||||||
fprintf(ErrFp, "Reading command `%s': Found in cache\n", fname);
|
fprintf(ErrFp, tr("Reading command `%s': Found in cache"), fname);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
CLine = h->cache;
|
CLine = h->cache;
|
||||||
STRSET(FileName, fname);
|
STRSET(FileName, fname);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
LineNo = 0;
|
LineNo = 0;
|
||||||
|
LineNoStart = 0;
|
||||||
if (!h->ownedByMe) {
|
if (!h->ownedByMe) {
|
||||||
RunDisabled |= RUN_NOTOWNER;
|
RunDisabled |= RUN_NOTOWNER;
|
||||||
} else {
|
} else {
|
||||||
@@ -934,8 +954,9 @@ static int IncludeCmd(char const *cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (DebugFlag & DB_TRACE_FILES) {
|
if (DebugFlag & DB_TRACE_FILES) {
|
||||||
fprintf(ErrFp, "Executing `%s' for INCLUDECMD and caching as `%s'\n",
|
fprintf(ErrFp, tr("Executing `%s' for INCLUDECMD and caching as `%s'"),
|
||||||
cmd, fname);
|
cmd, fname);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not found in cache */
|
/* Not found in cache */
|
||||||
@@ -953,6 +974,7 @@ static int IncludeCmd(char const *cmd)
|
|||||||
}
|
}
|
||||||
fp = fp2;
|
fp = fp2;
|
||||||
LineNo = 0;
|
LineNo = 0;
|
||||||
|
LineNoStart = 0;
|
||||||
|
|
||||||
/* Temporarily turn of file tracing */
|
/* Temporarily turn of file tracing */
|
||||||
old_flag = DebugFlag;
|
old_flag = DebugFlag;
|
||||||
@@ -968,6 +990,7 @@ static int IncludeCmd(char const *cmd)
|
|||||||
fp = NULL;
|
fp = NULL;
|
||||||
CLine = CachedFiles->cache;
|
CLine = CachedFiles->cache;
|
||||||
LineNo = 0;
|
LineNo = 0;
|
||||||
|
LineNoStart = 0;
|
||||||
STRSET(FileName, fname);
|
STRSET(FileName, fname);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
return OK;
|
return OK;
|
||||||
@@ -1004,6 +1027,7 @@ int IncludeFile(char const *fname)
|
|||||||
i->filename = NULL;
|
i->filename = NULL;
|
||||||
}
|
}
|
||||||
i->LineNo = LineNo;
|
i->LineNo = LineNo;
|
||||||
|
i->LineNoStart = LineNoStart;
|
||||||
i->NumIfs = NumIfs;
|
i->NumIfs = NumIfs;
|
||||||
i->IfFlags = IfFlags;
|
i->IfFlags = IfFlags;
|
||||||
memcpy(i->IfLinenos, IfLinenos, IF_NEST);
|
memcpy(i->IfLinenos, IfLinenos, IF_NEST);
|
||||||
@@ -1201,7 +1225,7 @@ static int CheckSafetyAux(struct stat *statbuf)
|
|||||||
if (!geteuid()) {
|
if (!geteuid()) {
|
||||||
/* Reject files not owned by root or group/world writable */
|
/* Reject files not owned by root or group/world writable */
|
||||||
if (statbuf->st_uid != 0) {
|
if (statbuf->st_uid != 0) {
|
||||||
fprintf(ErrFp, "SECURITY: Won't read non-root-owned file or directory when running as root!\n");
|
fprintf(ErrFp, "%s\n", tr("SECURITY: Won't read non-root-owned file or directory when running as root!"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1211,7 +1235,7 @@ static int CheckSafetyAux(struct stat *statbuf)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if ((statbuf->st_mode & S_IWOTH)) {
|
if ((statbuf->st_mode & S_IWOTH)) {
|
||||||
fprintf(ErrFp, "SECURITY: Won't read world-writable file or directory!\n");
|
fprintf(ErrFp, "%s\n", tr("SECURITY: Won't read world-writable file or directory!"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+207
-34
@@ -6,7 +6,7 @@
|
|||||||
/* expressions. */
|
/* expressions. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -93,6 +93,7 @@ static int FDefined (func_info *);
|
|||||||
static int FDosubst (func_info *);
|
static int FDosubst (func_info *);
|
||||||
static int FDusk (func_info *);
|
static int FDusk (func_info *);
|
||||||
static int FEasterdate (func_info *);
|
static int FEasterdate (func_info *);
|
||||||
|
static int FEscape (func_info *);
|
||||||
static int FEvalTrig (func_info *);
|
static int FEvalTrig (func_info *);
|
||||||
static int FFiledate (func_info *);
|
static int FFiledate (func_info *);
|
||||||
static int FFiledatetime (func_info *);
|
static int FFiledatetime (func_info *);
|
||||||
@@ -124,6 +125,10 @@ static int FMonnum (func_info *);
|
|||||||
static int FMoondate (func_info *);
|
static int FMoondate (func_info *);
|
||||||
static int FMoondatetime (func_info *);
|
static int FMoondatetime (func_info *);
|
||||||
static int FMoonphase (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 FMoontime (func_info *);
|
||||||
static int FMultiTrig (func_info *);
|
static int FMultiTrig (func_info *);
|
||||||
static int FNDawn (func_info *);
|
static int FNDawn (func_info *);
|
||||||
@@ -161,6 +166,7 @@ static int FTrigdate (func_info *);
|
|||||||
static int FTrigdatetime (func_info *);
|
static int FTrigdatetime (func_info *);
|
||||||
static int FTrigdelta (func_info *);
|
static int FTrigdelta (func_info *);
|
||||||
static int FTrigduration (func_info *);
|
static int FTrigduration (func_info *);
|
||||||
|
static int FTriginfo (func_info *);
|
||||||
static int FTrigeventduration(func_info *);
|
static int FTrigeventduration(func_info *);
|
||||||
static int FTrigeventstart (func_info *);
|
static int FTrigeventstart (func_info *);
|
||||||
static int FTrigfrom (func_info *);
|
static int FTrigfrom (func_info *);
|
||||||
@@ -252,6 +258,7 @@ BuiltinFunc Func[] = {
|
|||||||
{ "dosubst", 1, 3, 0, FDosubst, NULL },
|
{ "dosubst", 1, 3, 0, FDosubst, NULL },
|
||||||
{ "dusk", 0, 1, 0, FDusk, NULL },
|
{ "dusk", 0, 1, 0, FDusk, NULL },
|
||||||
{ "easterdate", 0, 1, 0, FEasterdate, NULL },
|
{ "easterdate", 0, 1, 0, FEasterdate, NULL },
|
||||||
|
{ "escape", 1, 2, 1, FEscape, NULL },
|
||||||
{ "evaltrig", 1, 2, 0, FEvalTrig, NULL },
|
{ "evaltrig", 1, 2, 0, FEvalTrig, NULL },
|
||||||
{ "filedate", 1, 1, 0, FFiledate, NULL },
|
{ "filedate", 1, 1, 0, FFiledate, NULL },
|
||||||
{ "filedatetime", 1, 1, 0, FFiledatetime, NULL },
|
{ "filedatetime", 1, 1, 0, FFiledatetime, NULL },
|
||||||
@@ -283,6 +290,10 @@ BuiltinFunc Func[] = {
|
|||||||
{ "moondate", 1, 3, 0, FMoondate, NULL },
|
{ "moondate", 1, 3, 0, FMoondate, NULL },
|
||||||
{ "moondatetime", 1, 3, 0, FMoondatetime, NULL },
|
{ "moondatetime", 1, 3, 0, FMoondatetime, NULL },
|
||||||
{ "moonphase", 0, 2, 0, FMoonphase, 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 },
|
{ "moontime", 1, 3, 0, FMoontime, NULL },
|
||||||
{ "multitrig", 1, NO_MAX, 0, FMultiTrig, NULL },
|
{ "multitrig", 1, NO_MAX, 0, FMultiTrig, NULL },
|
||||||
{ "ndawn", 0, 1, 0, FNDawn, NULL },
|
{ "ndawn", 0, 1, 0, FNDawn, NULL },
|
||||||
@@ -324,6 +335,7 @@ BuiltinFunc Func[] = {
|
|||||||
{ "trigeventstart", 0, 0, 0, FTrigeventstart, NULL },
|
{ "trigeventstart", 0, 0, 0, FTrigeventstart, NULL },
|
||||||
{ "trigfrom", 0, 0, 0, FTrigfrom, NULL },
|
{ "trigfrom", 0, 0, 0, FTrigfrom, NULL },
|
||||||
{ "trigger", 1, 3, 0, FTrigger, NULL },
|
{ "trigger", 1, 3, 0, FTrigger, NULL },
|
||||||
|
{ "triginfo", 1, 1, 1, FTriginfo, NULL },
|
||||||
{ "trigpriority", 0, 0, 0, FTrigpriority, NULL },
|
{ "trigpriority", 0, 0, 0, FTrigpriority, NULL },
|
||||||
{ "trigrep", 0, 0, 0, FTrigrep, NULL },
|
{ "trigrep", 0, 0, 0, FTrigrep, NULL },
|
||||||
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom, NULL },
|
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom, NULL },
|
||||||
@@ -392,6 +404,9 @@ static int F_(func_info *info)
|
|||||||
}
|
}
|
||||||
r = RetStrVal(DBufValue(&translated), info);
|
r = RetStrVal(DBufValue(&translated), info);
|
||||||
DBufFree(&translated);
|
DBufFree(&translated);
|
||||||
|
if (DebugFlag & DB_TRANSLATE) {
|
||||||
|
TranslationTemplate(ARGSTR(0));
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1073,7 +1088,7 @@ static int FOrd(func_info *info)
|
|||||||
if (u == 1 && t != 11) s = "st";
|
if (u == 1 && t != 11) s = "st";
|
||||||
if (u == 2 && t != 12) s = "nd";
|
if (u == 2 && t != 12) s = "nd";
|
||||||
if (u == 3 && t != 13) s = "rd";
|
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);
|
return RetStrVal(buf, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1615,6 +1630,17 @@ static int FTrigeventduration(func_info *info)
|
|||||||
return OK;
|
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)
|
static int FTrigeventstart(func_info *info)
|
||||||
{
|
{
|
||||||
if (LastTrigger.eventstart == NO_TIME) {
|
if (LastTrigger.eventstart == NO_TIME) {
|
||||||
@@ -1825,10 +1851,10 @@ static int FTrigger(func_info *info)
|
|||||||
|
|
||||||
FromDSE(date, &y, &m, &d);
|
FromDSE(date, &y, &m, &d);
|
||||||
if (tim != NO_TIME) {
|
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);
|
tim/60, tim%60);
|
||||||
} else {
|
} 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);
|
return RetStrVal(buf, info);
|
||||||
}
|
}
|
||||||
@@ -2360,6 +2386,89 @@ static int FHebyear(func_info *info)
|
|||||||
return OK;
|
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 & */
|
/* htmlescape - replace <. > and & by < > and & */
|
||||||
@@ -3009,6 +3118,7 @@ static int FPsshade(func_info *info)
|
|||||||
char psbuff[256];
|
char psbuff[256];
|
||||||
char *s = psbuff;
|
char *s = psbuff;
|
||||||
int i;
|
int i;
|
||||||
|
size_t len = sizeof(psbuff);
|
||||||
|
|
||||||
/* 1 or 3 args */
|
/* 1 or 3 args */
|
||||||
if (Nargs != 1 && Nargs != 3) return E_2MANY_ARGS;
|
if (Nargs != 1 && Nargs != 3) return E_2MANY_ARGS;
|
||||||
@@ -3021,19 +3131,22 @@ static int FPsshade(func_info *info)
|
|||||||
|
|
||||||
if (!psshade_warned) {
|
if (!psshade_warned) {
|
||||||
psshade_warned = 1;
|
psshade_warned = 1;
|
||||||
Wprint("psshade() is deprecated; use SPECIAL SHADE instead.");
|
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);
|
s += strlen(s);
|
||||||
sprintf(s, "_A _A moveto ");
|
snprintf(s, len, "_A _A moveto ");
|
||||||
|
len -= strlen(s);
|
||||||
s += 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);
|
s += strlen(s);
|
||||||
if (Nargs == 1) {
|
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 {
|
} 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);
|
return RetStrVal(psbuff, info);
|
||||||
}
|
}
|
||||||
@@ -3056,6 +3169,7 @@ static int FPsmoon(func_info *info)
|
|||||||
char const *extra = NULL;
|
char const *extra = NULL;
|
||||||
int size = -1;
|
int size = -1;
|
||||||
int fontsize = -1;
|
int fontsize = -1;
|
||||||
|
size_t len = sizeof(psbuff);
|
||||||
|
|
||||||
ASSERT_TYPE(0, INT_TYPE);
|
ASSERT_TYPE(0, INT_TYPE);
|
||||||
if (ARGV(0) < 0) return E_2LOW;
|
if (ARGV(0) < 0) return E_2LOW;
|
||||||
@@ -3076,63 +3190,74 @@ static int FPsmoon(func_info *info)
|
|||||||
}
|
}
|
||||||
if (!psmoon_warned) {
|
if (!psmoon_warned) {
|
||||||
psmoon_warned = 1;
|
psmoon_warned = 1;
|
||||||
Wprint("psmoon() is deprecated; use SPECIAL MOON instead.");
|
Wprint(tr("psmoon() is deprecated; use SPECIAL MOON instead."));
|
||||||
}
|
}
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
sprintf(sizebuf, "%d", size);
|
snprintf(sizebuf, sizeof(sizebuf), "%d", size);
|
||||||
} else {
|
} else {
|
||||||
strcpy(sizebuf, "DaySize 2 div");
|
strcpy(sizebuf, "DaySize 2 div");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fontsize > 0) {
|
if (fontsize > 0) {
|
||||||
sprintf(fontsizebuf, "%d", fontsize);
|
snprintf(fontsizebuf, sizeof(fontsizebuf), "%d", fontsize);
|
||||||
} else {
|
} else {
|
||||||
strcpy(fontsizebuf, "EntrySize");
|
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);
|
sizebuf, sizebuf);
|
||||||
|
len -= strlen(s);
|
||||||
s += 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);
|
s += strlen(s);
|
||||||
switch(ARGV(0)) {
|
switch(ARGV(0)) {
|
||||||
case 0:
|
case 0:
|
||||||
sprintf(s, " fill");
|
snprintf(s, len, " fill");
|
||||||
|
len -= strlen(s);
|
||||||
s += strlen(s);
|
s += strlen(s);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
sprintf(s, " stroke");
|
snprintf(s, len, " stroke");
|
||||||
|
len -= strlen(s);
|
||||||
s += strlen(s);
|
s += strlen(s);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
sprintf(s, " stroke");
|
snprintf(s, len, " stroke");
|
||||||
|
len -= strlen(s);
|
||||||
s += 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);
|
sizebuf, sizebuf);
|
||||||
|
len -= strlen(s);
|
||||||
s += 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);
|
s += strlen(s);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sprintf(s, " stroke");
|
snprintf(s, len, " stroke");
|
||||||
|
len -= strlen(s);
|
||||||
s += 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);
|
sizebuf, sizebuf);
|
||||||
|
len -= strlen(s);
|
||||||
s += 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);
|
s += strlen(s);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (extra) {
|
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);
|
sizebuf, sizebuf, sizebuf, sizebuf, fontsizebuf, extra);
|
||||||
|
len -= strlen(s);
|
||||||
s += strlen(s);
|
s += strlen(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(s, " grestore");
|
snprintf(s, len, " grestore");
|
||||||
return RetStrVal(psbuff, info);
|
return RetStrVal(psbuff, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3199,6 +3324,54 @@ static int FMoondatetime(func_info *info)
|
|||||||
return MoonStuff(DATETIME_TYPE, 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)
|
static int MoonStuff(int type_wanted, func_info *info)
|
||||||
{
|
{
|
||||||
int startdate, starttim;
|
int startdate, starttim;
|
||||||
@@ -3263,20 +3436,20 @@ static int FDatepart(func_info *info)
|
|||||||
* used for the timezone stuff! */
|
* used for the timezone stuff! */
|
||||||
static int setenv(char const *varname, char const *val, int overwrite)
|
static int setenv(char const *varname, char const *val, int overwrite)
|
||||||
{
|
{
|
||||||
static char tzbuf[256];
|
static char tzbuf[128];
|
||||||
if (strcmp(varname, "TZ")) {
|
if (strcmp(varname, "TZ")) {
|
||||||
fprintf(stderr, "built-in setenv can only be used with TZ\n");
|
fprintf(ErrFp, "built-in setenv can only be used with TZ\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
if (!overwrite) {
|
if (!overwrite) {
|
||||||
fprintf(stderr, "built-in setenv must have overwrite=1\n");
|
fprintf(ErrFp, "built-in setenv must have overwrite=1\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(val) > 250) {
|
if (strlen(val) > 250) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
sprintf(tzbuf, "%s=%s", varname, val);
|
snprintf(tzbuf, sizeof(tzbuf), "%s=%s", varname, val);
|
||||||
return(putenv(tzbuf));
|
return(putenv(tzbuf));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -3285,12 +3458,12 @@ static int setenv(char const *varname, char const *val, int overwrite)
|
|||||||
* used for the timezone stuff! */
|
* used for the timezone stuff! */
|
||||||
static void unsetenv(char const *varname)
|
static void unsetenv(char const *varname)
|
||||||
{
|
{
|
||||||
static char tzbuf[8];
|
static char tzbuf[128];
|
||||||
if (strcmp(varname, "TZ")) {
|
if (strcmp(varname, "TZ")) {
|
||||||
fprintf(stderr, "built-in unsetenv can only be used with TZ\n");
|
fprintf(ErrFp, "built-in unsetenv can only be used with TZ\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
sprintf(tzbuf, "%s", varname);
|
snprintf(tzbuf, sizeof(tzbuf), "%s", varname);
|
||||||
putenv(tzbuf);
|
putenv(tzbuf);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -3622,7 +3795,7 @@ FEvalTrig(func_info *info)
|
|||||||
} else {
|
} else {
|
||||||
/* Hokey... */
|
/* Hokey... */
|
||||||
if (trig.scanfrom != DSEToday) {
|
if (trig.scanfrom != DSEToday) {
|
||||||
Wprint("Warning: SCANFROM is ignored in two-argument form of evaltrig()");
|
Wprint(tr("Warning: SCANFROM is ignored in two-argument form of evaltrig()"));
|
||||||
}
|
}
|
||||||
dse = ComputeTrigger(scanfrom, &trig, &tim, &r, 0);
|
dse = ComputeTrigger(scanfrom, &trig, &tim, &r, 0);
|
||||||
}
|
}
|
||||||
@@ -3677,7 +3850,7 @@ FMultiTrig(func_info *info)
|
|||||||
return E_PARSE_ERR;
|
return E_PARSE_ERR;
|
||||||
}
|
}
|
||||||
if (tim.ttime != NO_TIME) {
|
if (tim.ttime != NO_TIME) {
|
||||||
Eprint("Cannot use AT clause in multitrig() function");
|
Eprint(tr("Cannot use AT clause in multitrig() function"));
|
||||||
return E_PARSE_ERR;
|
return E_PARSE_ERR;
|
||||||
}
|
}
|
||||||
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
|
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
/* globals.h and err.h */
|
/* globals.h and err.h */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
+10
-2
@@ -7,7 +7,7 @@
|
|||||||
/* MK_GLOBALS. Also contains useful macro definitions. */
|
/* MK_GLOBALS. Also contains useful macro definitions. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -47,6 +47,7 @@ EXTERN int CurDay;
|
|||||||
EXTERN int CurMon;
|
EXTERN int CurMon;
|
||||||
EXTERN int CurYear;
|
EXTERN int CurYear;
|
||||||
EXTERN int LineNo;
|
EXTERN int LineNo;
|
||||||
|
EXTERN int LineNoStart;
|
||||||
EXTERN int FreshLine;
|
EXTERN int FreshLine;
|
||||||
EXTERN int WarnedAboutImplicit;
|
EXTERN int WarnedAboutImplicit;
|
||||||
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
|
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
|
||||||
@@ -68,6 +69,7 @@ EXTERN INIT( int PsCal, 0);
|
|||||||
EXTERN INIT( int CalWidth, 80);
|
EXTERN INIT( int CalWidth, 80);
|
||||||
EXTERN INIT( int CalWeeks, 0);
|
EXTERN INIT( int CalWeeks, 0);
|
||||||
EXTERN INIT( int CalMonths, 0);
|
EXTERN INIT( int CalMonths, 0);
|
||||||
|
EXTERN INIT( char const *CalType, "none");
|
||||||
EXTERN INIT( int Hush, 0);
|
EXTERN INIT( int Hush, 0);
|
||||||
EXTERN INIT( int NextMode, 0);
|
EXTERN INIT( int NextMode, 0);
|
||||||
EXTERN INIT( int InfiniteDelta, 0);
|
EXTERN INIT( int InfiniteDelta, 0);
|
||||||
@@ -118,7 +120,7 @@ EXTERN INIT( int PurgeIncludeDepth, 0);
|
|||||||
EXTERN INIT( FILE *PurgeFP, NULL);
|
EXTERN INIT( FILE *PurgeFP, NULL);
|
||||||
EXTERN INIT( int NumIfs, 0);
|
EXTERN INIT( int NumIfs, 0);
|
||||||
EXTERN INIT( unsigned int IfFlags, 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 INIT( int LastTrigValid, 0);
|
||||||
EXTERN Trigger LastTrigger;
|
EXTERN Trigger LastTrigger;
|
||||||
EXTERN TimeTrig LastTimeTrig;
|
EXTERN TimeTrig LastTimeTrig;
|
||||||
@@ -175,6 +177,9 @@ EXTERN INIT( unsigned int FuncRecursionLevel, 0);
|
|||||||
/* Suppress warnings about implicit REM and MSG */
|
/* Suppress warnings about implicit REM and MSG */
|
||||||
EXTERN INIT( int SuppressImplicitRemWarnings, 0);
|
EXTERN INIT( int SuppressImplicitRemWarnings, 0);
|
||||||
|
|
||||||
|
/* Test mode - used by the acceptance tests */
|
||||||
|
EXTERN INIT( int TestMode, 0);
|
||||||
|
|
||||||
extern int NumFullOmits, NumPartialOmits;
|
extern int NumFullOmits, NumPartialOmits;
|
||||||
|
|
||||||
/* List of months */
|
/* List of months */
|
||||||
@@ -236,3 +241,6 @@ EXTERN int SuppressLRM
|
|||||||
= 0
|
= 0
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* Translatable messages */
|
||||||
|
extern char const *translatables[];
|
||||||
|
|||||||
+9
-28
@@ -5,7 +5,7 @@
|
|||||||
/* Implementation of hash table. */
|
/* Implementation of hash table. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
* These are used as choices for the number of hash buckets in the table
|
* These are used as choices for the number of hash buckets in the table
|
||||||
*/
|
*/
|
||||||
static size_t bucket_choices[] = {
|
static size_t bucket_choices[] = {
|
||||||
17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911, 43853, 87719,
|
7, 17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911, 43853, 87719,
|
||||||
175447, 350899, 701819, 1403641, 2807303, 5614657, 11229331, 22458671,
|
175447, 350899, 701819, 1403641, 2807303, 5614657, 11229331, 22458671,
|
||||||
44917381, 89834777, 179669557, 359339171, 718678369, 1437356741 };
|
44917381, 89834777, 179669557, 359339171, 718678369, 1437356741 };
|
||||||
|
|
||||||
@@ -108,6 +108,8 @@ hash_table_init(hash_table *t,
|
|||||||
t->hashfunc = hashfunc;
|
t->hashfunc = hashfunc;
|
||||||
t->compare = compare;
|
t->compare = compare;
|
||||||
t->buckets = malloc(sizeof(void *) * bucket_choices[0]);
|
t->buckets = malloc(sizeof(void *) * bucket_choices[0]);
|
||||||
|
t->num_growths = 0;
|
||||||
|
t->num_shrinks = 0;
|
||||||
if (!t->buckets) {
|
if (!t->buckets) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -216,6 +218,11 @@ hash_table_resize(hash_table *t, int dir)
|
|||||||
/* Out of memory... just don't resize? */
|
/* Out of memory... just don't resize? */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (dir == 1) {
|
||||||
|
t->num_growths++;
|
||||||
|
} else {
|
||||||
|
t->num_shrinks++;
|
||||||
|
}
|
||||||
for (size_t j=0; j<num_new_buckets; j++) {
|
for (size_t j=0; j<num_new_buckets; j++) {
|
||||||
new_buckets[j] = NULL;
|
new_buckets[j] = NULL;
|
||||||
}
|
}
|
||||||
@@ -305,32 +312,6 @@ hash_table_find(hash_table *t, void *candidate)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Find the next item in a hash table
|
|
||||||
*
|
|
||||||
* \param t Pointer to a hash table object
|
|
||||||
* \param obj Pointer to an object that was perviously returned by
|
|
||||||
* hash_table_find() or hash_table_find_next().
|
|
||||||
*
|
|
||||||
* \return A pointer to the next object matching obj, or NULL if
|
|
||||||
* no more exist
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
hash_table_find_next(hash_table *t, void *obj)
|
|
||||||
{
|
|
||||||
if (!obj) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
void *ptr = LINK(t, obj)->next;
|
|
||||||
while(ptr) {
|
|
||||||
if (!t->compare(obj, ptr)) {
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
ptr = LINK(t, ptr)->next;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Delete an item from a hash table
|
* \brief Delete an item from a hash table
|
||||||
*
|
*
|
||||||
|
|||||||
+5
-28
@@ -5,7 +5,7 @@
|
|||||||
/* Header file for hash-table related functions. */
|
/* Header file for hash-table related functions. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -29,6 +29,8 @@ struct hash_link {
|
|||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int bucket_choice_index; /**< Index into array of possible bucket counts */
|
unsigned int bucket_choice_index; /**< Index into array of possible bucket counts */
|
||||||
|
size_t num_growths; /**< How many times have we grown the hash table? */
|
||||||
|
size_t num_shrinks; /**< How many times have we grown the hash table? */
|
||||||
size_t num_entries; /**< Number of entries in the hash table */
|
size_t num_entries; /**< Number of entries in the hash table */
|
||||||
size_t hash_link_offset; /**< Offset of the struct hash_link in the container */
|
size_t hash_link_offset; /**< Offset of the struct hash_link in the container */
|
||||||
void **buckets; /**< Array of buckets */
|
void **buckets; /**< Array of buckets */
|
||||||
@@ -45,6 +47,8 @@ struct hash_table_stats {
|
|||||||
size_t num_nonempty_buckets; /**< Number of non-emptry buckets */
|
size_t num_nonempty_buckets; /**< Number of non-emptry buckets */
|
||||||
size_t max_len; /**< Length of longest chain in the hash table */
|
size_t max_len; /**< Length of longest chain in the hash table */
|
||||||
size_t min_len; /**< Length of the shortest chain in the hash table */
|
size_t min_len; /**< Length of the shortest chain in the hash table */
|
||||||
|
size_t num_growths; /**< How many times have we grown the hash table? */
|
||||||
|
size_t num_shrinks; /**< How many times have we grown the hash table? */
|
||||||
double avg_len; /**< Average chain length */
|
double avg_len; /**< Average chain length */
|
||||||
double avg_nonempty_len; /**< Average chain length of non-empty bucket */
|
double avg_nonempty_len; /**< Average chain length of non-empty bucket */
|
||||||
double stddev; /**< Standard deviation of chain lengths */
|
double stddev; /**< Standard deviation of chain lengths */
|
||||||
@@ -60,7 +64,6 @@ size_t hash_table_num_buckets(hash_table *t);
|
|||||||
size_t hash_table_chain_len(hash_table *t, size_t i);
|
size_t hash_table_chain_len(hash_table *t, size_t i);
|
||||||
int hash_table_insert(hash_table *t, void *item);
|
int hash_table_insert(hash_table *t, void *item);
|
||||||
void *hash_table_find(hash_table *t, void *candidate);
|
void *hash_table_find(hash_table *t, void *candidate);
|
||||||
void *hash_table_find_next(hash_table *t, void *obj);
|
|
||||||
int hash_table_delete(hash_table *t, void *item);
|
int hash_table_delete(hash_table *t, void *item);
|
||||||
int hash_table_delete_no_resize(hash_table *t, void *item);
|
int hash_table_delete_no_resize(hash_table *t, void *item);
|
||||||
void *hash_table_next(hash_table *t, void *cur);
|
void *hash_table_next(hash_table *t, void *cur);
|
||||||
@@ -84,29 +87,3 @@ void hash_table_get_stats(hash_table *t, struct hash_table_stats *stat);
|
|||||||
(item); \
|
(item); \
|
||||||
(item) = hash_table_next((t), (item)))
|
(item) = hash_table_next((t), (item)))
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Iterate over all items in a hash table that match a candidate
|
|
||||||
*
|
|
||||||
* This macro iterates over all items in a hash table that match a
|
|
||||||
* candidate object. (In general, a hash table may contain multiple
|
|
||||||
* objects with the same key.) Here is an example assuming that the hash
|
|
||||||
* table holds objects of type struct int_object:
|
|
||||||
*
|
|
||||||
* struct int_object {
|
|
||||||
* int value;
|
|
||||||
* struct hash_link link;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* hash_table tab;
|
|
||||||
* int_object candidate;
|
|
||||||
*
|
|
||||||
* candidate.value = 7;
|
|
||||||
* int_object *item;
|
|
||||||
* hash_table_for_each_matching(item, &candidate, &tab) {
|
|
||||||
* // Do something with item, which will match "7"
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
#define hash_table_for_each_matching(item, candidate, t) \
|
|
||||||
for ((item) = hash_table_find((t), (candidate)); \
|
|
||||||
(item); \
|
|
||||||
(item) = hash_table_find_next((t), (item)))
|
|
||||||
|
|||||||
+6
-3
@@ -5,7 +5,7 @@
|
|||||||
/* Utility function to print hash table stats. */
|
/* Utility function to print hash table stats. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -33,14 +33,15 @@ hash_table_dump_stats(hash_table *t, FILE *fp)
|
|||||||
{
|
{
|
||||||
struct hash_table_stats stat;
|
struct hash_table_stats stat;
|
||||||
hash_table_get_stats(t, &stat);
|
hash_table_get_stats(t, &stat);
|
||||||
fprintf(fp, "#Entries: %lu\n#Buckets: %lu\n#Non-empty Buckets: %lu\n",
|
fprintf(fp, " Entries: %lu; Buckets: %lu; Non-empty Buckets: %lu\n",
|
||||||
(unsigned long) stat.num_entries,
|
(unsigned long) stat.num_entries,
|
||||||
(unsigned long) stat.num_buckets,
|
(unsigned long) stat.num_buckets,
|
||||||
(unsigned long) stat.num_nonempty_buckets);
|
(unsigned long) stat.num_nonempty_buckets);
|
||||||
fprintf(fp, "Max len: %lu\nMin len: %lu\nAvg len: %.4f\nStd dev: %.4f\nAvg nonempty len: %.4f\n",
|
fprintf(fp, " Maxlen: %lu; Minlen: %lu; Avglen: %.3f; Stddev: %.3f; Avg nonempty len: %.3f\n",
|
||||||
(unsigned long) stat.max_len,
|
(unsigned long) stat.max_len,
|
||||||
(unsigned long) stat.min_len,
|
(unsigned long) stat.min_len,
|
||||||
stat.avg_len, stat.stddev, stat.avg_nonempty_len);
|
stat.avg_len, stat.stddev, stat.avg_nonempty_len);
|
||||||
|
fprintf(fp, " Growths: %lu; Shrinks: %lu\n", (unsigned long) stat.num_growths, (unsigned long) stat.num_shrinks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,6 +68,8 @@ hash_table_get_stats(hash_table *t, struct hash_table_stats *stat)
|
|||||||
stat->stddev = 0.0;
|
stat->stddev = 0.0;
|
||||||
stat->num_nonempty_buckets = 0;
|
stat->num_nonempty_buckets = 0;
|
||||||
stat->avg_nonempty_len = 0.0;
|
stat->avg_nonempty_len = 0.0;
|
||||||
|
stat->num_growths = t->num_growths;
|
||||||
|
stat->num_shrinks = t->num_shrinks;
|
||||||
double sum = 0.0;
|
double sum = 0.0;
|
||||||
double sumsq = 0.0;
|
double sumsq = 0.0;
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -5,7 +5,7 @@
|
|||||||
/* Support for the Hebrew calendar */
|
/* Support for the Hebrew calendar */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/* Derived from code written by Amos Shapir in 1978; revised */
|
/* Derived from code written by Amos Shapir in 1978; revised */
|
||||||
@@ -324,7 +324,7 @@ int GetValidHebDate(int yin, int min, int din, int adarbehave,
|
|||||||
case ADAR2ADARB: *mout = min = ADARB; break;
|
case ADAR2ADARB: *mout = min = ADARB; break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Eprint("GetValidHebDate: Bad adarbehave value %d", adarbehave);
|
Eprint(tr("GetValidHebDate: Bad adarbehave value %d"), adarbehave);
|
||||||
return E_SWERR;
|
return E_SWERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -464,7 +464,7 @@ int ComputeJahr(int y, int m, int d, int *ans)
|
|||||||
|
|
||||||
/* Check for Adar A */
|
/* Check for Adar A */
|
||||||
if (m == ADARA && monlen[m] == 0) {
|
if (m == ADARA && monlen[m] == 0) {
|
||||||
Eprint("No Adar A in %d", y);
|
Eprint(tr("No Adar A in %d"), y);
|
||||||
return E_BAD_HEBDATE;
|
return E_BAD_HEBDATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+72
-16
@@ -7,7 +7,7 @@
|
|||||||
/* in normal mode. */
|
/* in normal mode. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -149,7 +149,7 @@ static char const *DefaultFilename(void)
|
|||||||
|
|
||||||
s = getenv("HOME");
|
s = getenv("HOME");
|
||||||
if (!s) {
|
if (!s) {
|
||||||
fprintf(stderr, "HOME environment variable not set. Unable to determine reminder file.\n");
|
fprintf(ErrFp, "HOME environment variable not set. Unable to determine reminder file.\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
DBufPuts(&default_filename_buf, s);
|
DBufPuts(&default_filename_buf, s);
|
||||||
@@ -217,6 +217,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
RealToday = SystemDate(&CurYear, &CurMon, &CurDay);
|
RealToday = SystemDate(&CurYear, &CurMon, &CurDay);
|
||||||
if (RealToday < 0) {
|
if (RealToday < 0) {
|
||||||
fprintf(ErrFp, GetErr(M_BAD_SYS_DATE), BASE);
|
fprintf(ErrFp, GetErr(M_BAD_SYS_DATE), BASE);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
DSEToday = RealToday;
|
DSEToday = RealToday;
|
||||||
@@ -237,7 +238,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
InvokedAsRem = 1;
|
InvokedAsRem = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Invoked with a NULL argv[0]; bailing because that's just plain bizarre.\n");
|
fprintf(ErrFp, "Invoked with a NULL argv[0]; bailing because that's just plain bizarre.\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,8 +367,8 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
PARSENUM(DefaultTDelta, arg);
|
PARSENUM(DefaultTDelta, arg);
|
||||||
if (DefaultTDelta < 0) {
|
if (DefaultTDelta < 0) {
|
||||||
DefaultTDelta = 0;
|
DefaultTDelta = 0;
|
||||||
} else if (DefaultTDelta > 1440) {
|
} else if (DefaultTDelta > MINUTES_PER_DAY) {
|
||||||
DefaultTDelta = 1440;
|
DefaultTDelta = MINUTES_PER_DAY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!*arg) {
|
} else if (!*arg) {
|
||||||
@@ -501,9 +502,11 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (weeks) {
|
if (weeks) {
|
||||||
|
CalType = "weekly";
|
||||||
PARSENUM(CalWeeks, arg);
|
PARSENUM(CalWeeks, arg);
|
||||||
if (!CalWeeks) CalWeeks = 1;
|
if (!CalWeeks) CalWeeks = 1;
|
||||||
} else {
|
} else {
|
||||||
|
CalType = "monthly";
|
||||||
PARSENUM(CalMonths, arg);
|
PARSENUM(CalMonths, arg);
|
||||||
if (!CalMonths) CalMonths = 1;
|
if (!CalMonths) CalMonths = 1;
|
||||||
}
|
}
|
||||||
@@ -528,9 +531,11 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (weeks) {
|
if (weeks) {
|
||||||
|
CalType = "weekly";
|
||||||
PARSENUM(CalWeeks, arg);
|
PARSENUM(CalWeeks, arg);
|
||||||
if (!CalWeeks) CalWeeks = 1;
|
if (!CalWeeks) CalWeeks = 1;
|
||||||
} else {
|
} else {
|
||||||
|
CalType = "monthly";
|
||||||
PARSENUM(CalMonths, arg);
|
PARSENUM(CalMonths, arg);
|
||||||
if (!CalMonths) CalMonths = 1;
|
if (!CalMonths) CalMonths = 1;
|
||||||
}
|
}
|
||||||
@@ -541,10 +546,14 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
DoSimpleCalendar = 1;
|
DoSimpleCalendar = 1;
|
||||||
IgnoreOnce = 1;
|
IgnoreOnce = 1;
|
||||||
PsCal = PSCAL_LEVEL1;
|
PsCal = PSCAL_LEVEL1;
|
||||||
|
weeks = 0;
|
||||||
while (*arg == 'a' || *arg == 'A' ||
|
while (*arg == 'a' || *arg == 'A' ||
|
||||||
*arg == 'q' || *arg == 'Q' ||
|
*arg == 'q' || *arg == 'Q' ||
|
||||||
|
*arg == '+' ||
|
||||||
*arg == 'p' || *arg == 'P') {
|
*arg == 'p' || *arg == 'P') {
|
||||||
if (*arg == 'a' || *arg == 'A') {
|
if (*arg == '+') {
|
||||||
|
weeks = 1;
|
||||||
|
} else if (*arg == 'a' || *arg == 'A') {
|
||||||
DoSimpleCalDelta = 1;
|
DoSimpleCalDelta = 1;
|
||||||
} else if (*arg == 'p' || *arg == 'P') {
|
} else if (*arg == 'p' || *arg == 'P') {
|
||||||
/* JSON interchange formats always include
|
/* JSON interchange formats always include
|
||||||
@@ -560,8 +569,16 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
}
|
}
|
||||||
arg++;
|
arg++;
|
||||||
}
|
}
|
||||||
PARSENUM(CalMonths, arg);
|
if (weeks) {
|
||||||
if (!CalMonths) CalMonths = 1;
|
CalType = "weekly";
|
||||||
|
PARSENUM(CalWeeks, arg);
|
||||||
|
if (!CalWeeks) CalWeeks = 1;
|
||||||
|
PsCal = PSCAL_LEVEL3;
|
||||||
|
} else {
|
||||||
|
CalType = "monthly";
|
||||||
|
PARSENUM(CalMonths, arg);
|
||||||
|
if (!CalMonths) CalMonths = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
@@ -577,7 +594,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
/* -wt means get width from /dev/tty */
|
/* -wt means get width from /dev/tty */
|
||||||
ttyfd = open("/dev/tty", O_RDONLY);
|
ttyfd = open("/dev/tty", O_RDONLY);
|
||||||
if (ttyfd < 0) {
|
if (ttyfd < 0) {
|
||||||
fprintf(stderr, "%s: `-wt': Cannot open /dev/tty: %s\n",
|
fprintf(ErrFp, "%s: `-wt': Cannot open /dev/tty: %s\n",
|
||||||
argv[0], strerror(errno));
|
argv[0], strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
InitCalWidthAndFormWidth(ttyfd);
|
InitCalWidthAndFormWidth(ttyfd);
|
||||||
@@ -618,14 +635,17 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
while (*arg) {
|
while (*arg) {
|
||||||
switch(*arg++) {
|
switch(*arg++) {
|
||||||
case 's': case 'S': DebugFlag |= DB_PARSE_EXPR; break;
|
case 's': case 'S': DebugFlag |= DB_PARSE_EXPR; break;
|
||||||
|
case 'h': case 'H': DebugFlag |= DB_HASHSTATS; break;
|
||||||
case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break;
|
case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break;
|
||||||
case 'x': case 'X': DebugFlag |= DB_PRTEXPR; break;
|
case 'x': case 'X': DebugFlag |= DB_PRTEXPR; break;
|
||||||
case 't': case 'T': DebugFlag |= DB_PRTTRIG; break;
|
case 't': case 'T': DebugFlag |= DB_PRTTRIG; break;
|
||||||
case 'v': case 'V': DebugFlag |= DB_DUMP_VARS; break;
|
case 'v': case 'V': DebugFlag |= DB_DUMP_VARS; break;
|
||||||
case 'l': case 'L': DebugFlag |= DB_PRTLINE; break;
|
case 'l': case 'L': DebugFlag |= DB_PRTLINE; break;
|
||||||
case 'f': case 'F': DebugFlag |= DB_TRACE_FILES; break;
|
case 'f': case 'F': DebugFlag |= DB_TRACE_FILES; break;
|
||||||
|
case 'q': case 'Q': DebugFlag |= DB_TRANSLATE; break;
|
||||||
default:
|
default:
|
||||||
fprintf(ErrFp, GetErr(M_BAD_DB_FLAG), *(arg-1));
|
fprintf(ErrFp, GetErr(M_BAD_DB_FLAG), *(arg-1));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -661,6 +681,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(ErrFp, GetErr(M_BAD_OPTION), *(arg-1));
|
fprintf(ErrFp, GetErr(M_BAD_OPTION), *(arg-1));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -728,7 +749,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
if (tok.type == T_Illegal && tok.val < 0) {
|
if (tok.type == T_Illegal && tok.val < 0) {
|
||||||
fprintf(stderr, "%s: `%s'\n", GetErr(-tok.val), arg);
|
fprintf(ErrFp, "%s: `%s'\n", GetErr(-tok.val), arg);
|
||||||
Usage();
|
Usage();
|
||||||
}
|
}
|
||||||
Usage();
|
Usage();
|
||||||
@@ -774,10 +795,11 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out the offset from UTC */
|
/* Figure out the offset from UTC */
|
||||||
if (CalculateUTC)
|
if (CalculateUTC) {
|
||||||
(void) CalcMinsFromUTC(DSEToday, MinutesPastMidnight(0),
|
(void) CalcMinsFromUTC(DSEToday, MinutesPastMidnight(0),
|
||||||
&MinsFromUTC, NULL);
|
&MinsFromUTC, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -790,7 +812,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
#ifndef L_USAGE_OVERRIDE
|
#ifndef L_USAGE_OVERRIDE
|
||||||
void Usage(void)
|
void Usage(void)
|
||||||
{
|
{
|
||||||
fprintf(ErrFp, "\nREMIND %s Copyright 1992-2024 Dianne Skoll\n", VERSION);
|
fprintf(ErrFp, "\nREMIND %s Copyright (C) 1992-2025 Dianne Skoll\n", VERSION);
|
||||||
#ifdef BETA
|
#ifdef BETA
|
||||||
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
|
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -853,6 +875,7 @@ static void ChgUser(char const *user)
|
|||||||
|
|
||||||
if (!pwent) {
|
if (!pwent) {
|
||||||
fprintf(ErrFp, GetErr(M_BAD_USER), user);
|
fprintf(ErrFp, GetErr(M_BAD_USER), user);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -861,16 +884,19 @@ static void ChgUser(char const *user)
|
|||||||
#ifdef HAVE_INITGROUPS
|
#ifdef HAVE_INITGROUPS
|
||||||
if (initgroups(pwent->pw_name, pwent->pw_gid) < 0) {
|
if (initgroups(pwent->pw_name, pwent->pw_gid) < 0) {
|
||||||
fprintf(ErrFp, GetErr(M_NO_CHG_GID), pwent->pw_gid);
|
fprintf(ErrFp, GetErr(M_NO_CHG_GID), pwent->pw_gid);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
if (setgid(pwent->pw_gid) < 0) {
|
if (setgid(pwent->pw_gid) < 0) {
|
||||||
fprintf(ErrFp, GetErr(M_NO_CHG_GID), pwent->pw_gid);
|
fprintf(ErrFp, GetErr(M_NO_CHG_GID), pwent->pw_gid);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setuid(pwent->pw_uid) < 0) {
|
if (setuid(pwent->pw_uid) < 0) {
|
||||||
fprintf(ErrFp, GetErr(M_NO_CHG_UID), pwent->pw_uid);
|
fprintf(ErrFp, GetErr(M_NO_CHG_UID), pwent->pw_uid);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -878,6 +904,7 @@ static void ChgUser(char const *user)
|
|||||||
home = malloc(strlen(pwent->pw_dir) + 6);
|
home = malloc(strlen(pwent->pw_dir) + 6);
|
||||||
if (!home) {
|
if (!home) {
|
||||||
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
|
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
sprintf(home, "HOME=%s", pwent->pw_dir);
|
sprintf(home, "HOME=%s", pwent->pw_dir);
|
||||||
@@ -886,6 +913,7 @@ static void ChgUser(char const *user)
|
|||||||
shell = malloc(strlen(pwent->pw_shell) + 7);
|
shell = malloc(strlen(pwent->pw_shell) + 7);
|
||||||
if (!shell) {
|
if (!shell) {
|
||||||
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
|
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
sprintf(shell, "SHELL=%s", pwent->pw_shell);
|
sprintf(shell, "SHELL=%s", pwent->pw_shell);
|
||||||
@@ -895,6 +923,7 @@ static void ChgUser(char const *user)
|
|||||||
username = malloc(strlen(pwent->pw_name) + 6);
|
username = malloc(strlen(pwent->pw_name) + 6);
|
||||||
if (!username) {
|
if (!username) {
|
||||||
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
|
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
sprintf(username, "USER=%s", pwent->pw_name);
|
sprintf(username, "USER=%s", pwent->pw_name);
|
||||||
@@ -902,6 +931,7 @@ static void ChgUser(char const *user)
|
|||||||
logname= malloc(strlen(pwent->pw_name) + 9);
|
logname= malloc(strlen(pwent->pw_name) + 9);
|
||||||
if (!logname) {
|
if (!logname) {
|
||||||
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
|
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
sprintf(logname, "LOGNAME=%s", pwent->pw_name);
|
sprintf(logname, "LOGNAME=%s", pwent->pw_name);
|
||||||
@@ -947,6 +977,7 @@ static void InitializeVar(char const *str)
|
|||||||
varname[r++] = *str;
|
varname[r++] = *str;
|
||||||
} else {
|
} else {
|
||||||
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_ILLEGAL_CHAR));
|
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_ILLEGAL_CHAR));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -960,12 +991,14 @@ static void InitializeVar(char const *str)
|
|||||||
varname[r] = 0;
|
varname[r] = 0;
|
||||||
if (!*varname) {
|
if (!*varname) {
|
||||||
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_VAR));
|
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_VAR));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!*str) {
|
if (!*str) {
|
||||||
/* Setting a system var does require =expr on the commandline */
|
/* Setting a system var does require =expr on the commandline */
|
||||||
if (*varname == '$') {
|
if (*varname == '$') {
|
||||||
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_EQ));
|
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_EQ));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
val.type = INT_TYPE;
|
val.type = INT_TYPE;
|
||||||
@@ -976,40 +1009,51 @@ static void InitializeVar(char const *str)
|
|||||||
}
|
}
|
||||||
if (r) {
|
if (r) {
|
||||||
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
|
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*varname) {
|
if (!*varname) {
|
||||||
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_VAR));
|
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_VAR));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
expr = str+1;
|
expr = str+1;
|
||||||
if (!*expr) {
|
if (!*expr) {
|
||||||
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_EXPR));
|
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_EXPR));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
r=EvalExpr(&expr, &val, NULL);
|
r=EvalExpr(&expr, &val, NULL);
|
||||||
if (r) {
|
if (r) {
|
||||||
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
|
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*varname == '$') {
|
if (*varname == '$') {
|
||||||
r=SetSysVar(varname+1, &val);
|
r=SetSysVar(varname+1, &val);
|
||||||
DestroyValue(val);
|
DestroyValue(val);
|
||||||
if (r) fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
|
if (r) {
|
||||||
|
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
r=SetVar(varname, &val);
|
r=SetVar(varname, &val);
|
||||||
if (r) {
|
if (r) {
|
||||||
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
|
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
r=PreserveVar(varname);
|
r=PreserveVar(varname);
|
||||||
if (r) fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
|
if (r) {
|
||||||
|
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1018,7 +1062,7 @@ AddTrustedUser(char const *username)
|
|||||||
{
|
{
|
||||||
struct passwd *pwent;
|
struct passwd *pwent;
|
||||||
if (NumTrustedUsers >= MAX_TRUSTED_USERS) {
|
if (NumTrustedUsers >= MAX_TRUSTED_USERS) {
|
||||||
fprintf(stderr, "Too many trusted users (%d max)\n",
|
fprintf(ErrFp, "Too many trusted users (%d max)\n",
|
||||||
MAX_TRUSTED_USERS);
|
MAX_TRUSTED_USERS);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@@ -1026,6 +1070,7 @@ AddTrustedUser(char const *username)
|
|||||||
pwent = getpwnam(username);
|
pwent = getpwnam(username);
|
||||||
if (!pwent) {
|
if (!pwent) {
|
||||||
fprintf(ErrFp, GetErr(M_BAD_USER), username);
|
fprintf(ErrFp, GetErr(M_BAD_USER), username);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
TrustedUsers[NumTrustedUsers] = pwent->pw_uid;
|
TrustedUsers[NumTrustedUsers] = pwent->pw_uid;
|
||||||
@@ -1077,6 +1122,17 @@ static void
|
|||||||
ProcessLongOption(char const *arg)
|
ProcessLongOption(char const *arg)
|
||||||
{
|
{
|
||||||
int t;
|
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")) {
|
if (!strcmp(arg, "version")) {
|
||||||
printf("%s\n", VERSION);
|
printf("%s\n", VERSION);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
|||||||
+86
-74
@@ -1,7 +1,7 @@
|
|||||||
/* vim: set et ts=3 sw=3 sts=3 ft=c:
|
/* vim: set et ts=3 sw=3 sts=3 ft=c:
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
|
* Copyright (C) 2012-2021 the json-parser authors All rights reserved.
|
||||||
* https://github.com/udp/json-parser
|
* https://github.com/json-parser/json-parser
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -29,36 +29,49 @@
|
|||||||
|
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
|
|
||||||
#define UNUSED(x) ( (void) x )
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||||
|
/* C99 might give us uintptr_t and UINTPTR_MAX but they also might not be provided */
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const struct _json_value json_value_none;
|
#ifndef JSON_INT_T_OVERRIDDEN
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
/* https://docs.microsoft.com/en-us/cpp/cpp/data-type-ranges */
|
||||||
|
#define JSON_INT_MAX 9223372036854775807LL
|
||||||
|
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||||
|
/* C99 */
|
||||||
|
#define JSON_INT_MAX INT_FAST64_MAX
|
||||||
|
#else
|
||||||
|
/* C89 */
|
||||||
|
#include <limits.h>
|
||||||
|
#define JSON_INT_MAX LONG_MAX
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#ifndef JSON_INT_MAX
|
||||||
#include <string.h>
|
#define JSON_INT_MAX (json_int_t)(((unsigned json_int_t)(-1)) / (unsigned json_int_t)2);
|
||||||
#include <ctype.h>
|
#endif
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
typedef unsigned int json_uchar;
|
typedef unsigned int json_uchar;
|
||||||
|
|
||||||
/* There has to be a better way to do this */
|
const struct _json_value json_value_none;
|
||||||
static const json_int_t JSON_INT_MAX = sizeof(json_int_t) == 1
|
|
||||||
? INT8_MAX
|
|
||||||
: (sizeof(json_int_t) == 2
|
|
||||||
? INT16_MAX
|
|
||||||
: (sizeof(json_int_t) == 4
|
|
||||||
? INT32_MAX
|
|
||||||
: INT64_MAX));
|
|
||||||
|
|
||||||
static unsigned char hex_value (json_char c)
|
static unsigned char hex_value (json_char c)
|
||||||
{
|
{
|
||||||
if (isdigit(c))
|
if (isdigit((unsigned char)c))
|
||||||
return c - '0';
|
return c - '0';
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
@@ -79,10 +92,7 @@ static int would_overflow (json_int_t value, json_char b)
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned long used_memory;
|
size_t used_memory;
|
||||||
|
|
||||||
unsigned int uint_max;
|
|
||||||
unsigned long ulong_max;
|
|
||||||
|
|
||||||
json_settings settings;
|
json_settings settings;
|
||||||
int first_pass;
|
int first_pass;
|
||||||
@@ -94,19 +104,19 @@ typedef struct
|
|||||||
|
|
||||||
static void * default_alloc (size_t size, int zero, void * user_data)
|
static void * default_alloc (size_t size, int zero, void * user_data)
|
||||||
{
|
{
|
||||||
UNUSED(user_data);
|
(void)user_data; /* ignore unused-parameter warn */
|
||||||
return zero ? calloc (1, size) : malloc (size);
|
return zero ? calloc (1, size) : malloc (size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_free (void * ptr, void * user_data)
|
static void default_free (void * ptr, void * user_data)
|
||||||
{
|
{
|
||||||
UNUSED(user_data);
|
(void)user_data; /* ignore unused-parameter warn */
|
||||||
free (ptr);
|
free (ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void * json_alloc (json_state * state, unsigned long size, int zero)
|
static void * json_alloc (json_state * state, size_t size, int zero)
|
||||||
{
|
{
|
||||||
if ((state->ulong_max - state->used_memory) < size)
|
if ((ULONG_MAX - 8 - state->used_memory) < size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (state->settings.max_memory
|
if (state->settings.max_memory
|
||||||
@@ -123,7 +133,7 @@ static int new_value (json_state * state,
|
|||||||
json_type type)
|
json_type type)
|
||||||
{
|
{
|
||||||
json_value * value;
|
json_value * value;
|
||||||
int values_size;
|
size_t values_size;
|
||||||
|
|
||||||
if (!state->first_pass)
|
if (!state->first_pass)
|
||||||
{
|
{
|
||||||
@@ -157,14 +167,16 @@ static int new_value (json_state * state,
|
|||||||
values_size = sizeof (*value->u.object.values) * value->u.object.length;
|
values_size = sizeof (*value->u.object.values) * value->u.object.length;
|
||||||
|
|
||||||
if (! (value->u.object.values = (json_object_entry *) json_alloc
|
if (! (value->u.object.values = (json_object_entry *) json_alloc
|
||||||
(state, values_size + ((unsigned long) value->u.object.values), 0)) )
|
#ifdef UINTPTR_MAX
|
||||||
|
(state, values_size + ((uintptr_t) value->u.object.values), 0)) )
|
||||||
|
#else
|
||||||
|
(state, values_size + ((size_t) value->u.object.values), 0)) )
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *s = (char *) value->u.object.values;
|
value->_reserved.object_mem = (void *) (((char *) value->u.object.values) + values_size);
|
||||||
s += values_size;
|
|
||||||
value->_reserved.object_mem = s;
|
|
||||||
|
|
||||||
value->u.object.length = 0;
|
value->u.object.length = 0;
|
||||||
break;
|
break;
|
||||||
@@ -213,8 +225,8 @@ static int new_value (json_state * state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define whitespace \
|
#define whitespace \
|
||||||
case '\n': ++ state.cur_line; state.cur_col = 0; /* FALLTHRU */ \
|
case '\n': ++ state.cur_line; state.cur_col = 0; /* FALLTHRU */ \
|
||||||
case ' ': case '\t': case '\r'
|
case ' ': /* FALLTHRU */ case '\t': /* FALLTHRU */ case '\r'
|
||||||
|
|
||||||
#define string_add(b) \
|
#define string_add(b) \
|
||||||
do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0);
|
do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0);
|
||||||
@@ -245,13 +257,13 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
size_t length,
|
size_t length,
|
||||||
char * error_buf)
|
char * error_buf)
|
||||||
{
|
{
|
||||||
json_char error [json_error_max];
|
char error [json_error_max];
|
||||||
const json_char * end;
|
const json_char * end;
|
||||||
json_value * top, * root, * alloc = 0;
|
json_value * top, * root, * alloc = 0;
|
||||||
json_state state = { 0 };
|
json_state state = { 0 };
|
||||||
long flags;
|
long flags;
|
||||||
double num_digits = 0, num_e = 0;
|
int num_digits = 0;
|
||||||
double num_fraction = 0;
|
double num_e = 0, num_fraction = 0;
|
||||||
|
|
||||||
/* Skip UTF-8 BOM
|
/* Skip UTF-8 BOM
|
||||||
*/
|
*/
|
||||||
@@ -274,12 +286,6 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
if (!state.settings.mem_free)
|
if (!state.settings.mem_free)
|
||||||
state.settings.mem_free = default_free;
|
state.settings.mem_free = default_free;
|
||||||
|
|
||||||
memset (&state.uint_max, 0xFF, sizeof (state.uint_max));
|
|
||||||
memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max));
|
|
||||||
|
|
||||||
state.uint_max -= 8; /* limit of how much can be added before next check */
|
|
||||||
state.ulong_max -= 8;
|
|
||||||
|
|
||||||
for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass)
|
for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass)
|
||||||
{
|
{
|
||||||
json_uchar uchar;
|
json_uchar uchar;
|
||||||
@@ -299,11 +305,11 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
if (flags & flag_string)
|
if (flags & flag_string)
|
||||||
{
|
{
|
||||||
if (!b)
|
if (!b)
|
||||||
{ sprintf (error, "Unexpected EOF in string (at %u:%u)", line_and_col);
|
{ sprintf (error, "%u:%u: Unexpected EOF in string", line_and_col);
|
||||||
goto e_failed;
|
goto e_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string_length > state.uint_max)
|
if (string_length > UINT_MAX - 8)
|
||||||
goto e_overflow;
|
goto e_overflow;
|
||||||
|
|
||||||
if (flags & flag_escaped)
|
if (flags & flag_escaped)
|
||||||
@@ -325,7 +331,7 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
|
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
|
||||||
(uc_b4 = 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);
|
sprintf (error, "%u:%u: Invalid character value `%c`", line_and_col, b);
|
||||||
goto e_failed;
|
goto e_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +348,7 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
|
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
|
||||||
(uc_b4 = 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);
|
sprintf (error, "%u:%u: Invalid character value `%c`", line_and_col, b);
|
||||||
goto e_failed;
|
goto e_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,11 +432,12 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
|
|
||||||
case json_object:
|
case json_object:
|
||||||
|
|
||||||
if (state.first_pass) {
|
if (state.first_pass) {
|
||||||
char *s = (char *) top->u.object.values;
|
json_char **chars = (json_char **) &top->u.object.values;
|
||||||
s += string_length+1;
|
chars[0] += string_length + 1;
|
||||||
top->u.object.values = (void *) s;
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
top->u.object.values [top->u.object.length].name
|
top->u.object.values [top->u.object.length].name
|
||||||
= (json_char *) top->_reserved.object_mem;
|
= (json_char *) top->_reserved.object_mem;
|
||||||
|
|
||||||
@@ -527,7 +534,7 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
default:
|
default:
|
||||||
|
|
||||||
sprintf (error, "%u:%u: Trailing garbage: `%c`",
|
sprintf (error, "%u:%u: Trailing garbage: `%c`",
|
||||||
state.cur_line, state.cur_col, b);
|
line_and_col, b);
|
||||||
|
|
||||||
goto e_failed;
|
goto e_failed;
|
||||||
};
|
};
|
||||||
@@ -545,7 +552,7 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
if (top && top->type == json_array)
|
if (top && top->type == json_array)
|
||||||
flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next;
|
flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next;
|
||||||
else
|
else
|
||||||
{ sprintf (error, "%u:%u: Unexpected ]", line_and_col);
|
{ sprintf (error, "%u:%u: Unexpected `]`", line_and_col);
|
||||||
goto e_failed;
|
goto e_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,8 +568,8 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf (error, "%u:%u: Expected , before %c",
|
sprintf (error, "%u:%u: Expected `,` before `%c`",
|
||||||
state.cur_line, state.cur_col, b);
|
line_and_col, b);
|
||||||
|
|
||||||
goto e_failed;
|
goto e_failed;
|
||||||
}
|
}
|
||||||
@@ -576,8 +583,8 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf (error, "%u:%u: Expected : before %c",
|
sprintf (error, "%u:%u: Expected `:` before `%c`",
|
||||||
state.cur_line, state.cur_col, b);
|
line_and_col, b);
|
||||||
|
|
||||||
goto e_failed;
|
goto e_failed;
|
||||||
}
|
}
|
||||||
@@ -616,7 +623,7 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
|
|
||||||
if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' ||
|
if ((end - state.ptr) <= 3 || *(++ state.ptr) != 'r' ||
|
||||||
*(++ state.ptr) != 'u' || *(++ state.ptr) != 'e')
|
*(++ state.ptr) != 'u' || *(++ state.ptr) != 'e')
|
||||||
{
|
{
|
||||||
goto e_unknown_value;
|
goto e_unknown_value;
|
||||||
@@ -632,7 +639,7 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
|
|
||||||
if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' ||
|
if ((end - state.ptr) <= 4 || *(++ state.ptr) != 'a' ||
|
||||||
*(++ state.ptr) != 'l' || *(++ state.ptr) != 's' ||
|
*(++ state.ptr) != 'l' || *(++ state.ptr) != 's' ||
|
||||||
*(++ state.ptr) != 'e')
|
*(++ state.ptr) != 'e')
|
||||||
{
|
{
|
||||||
@@ -647,7 +654,7 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
|
|
||||||
if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' ||
|
if ((end - state.ptr) <= 3 || *(++ state.ptr) != 'u' ||
|
||||||
*(++ state.ptr) != 'l' || *(++ state.ptr) != 'l')
|
*(++ state.ptr) != 'l' || *(++ state.ptr) != 'l')
|
||||||
{
|
{
|
||||||
goto e_unknown_value;
|
goto e_unknown_value;
|
||||||
@@ -661,14 +668,14 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
if (isdigit (b) || b == '-')
|
if (isdigit ((unsigned char) b) || b == '-')
|
||||||
{
|
{
|
||||||
if (!new_value (&state, &top, &root, &alloc, json_integer))
|
if (!new_value (&state, &top, &root, &alloc, json_integer))
|
||||||
goto e_alloc_failure;
|
goto e_alloc_failure;
|
||||||
|
|
||||||
if (!state.first_pass)
|
if (!state.first_pass)
|
||||||
{
|
{
|
||||||
while (isdigit (b) || b == '+' || b == '-'
|
while (isdigit ((unsigned char) b) || b == '+' || b == '-'
|
||||||
|| b == 'e' || b == 'E' || b == '.')
|
|| b == 'e' || b == 'E' || b == '.')
|
||||||
{
|
{
|
||||||
if ( (++ state.ptr) == end)
|
if ( (++ state.ptr) == end)
|
||||||
@@ -702,7 +709,7 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ sprintf (error, "%u:%u: Unexpected %c when seeking value", line_and_col, b);
|
{ sprintf (error, "%u:%u: Unexpected `%c` when seeking value", line_and_col, b);
|
||||||
goto e_failed;
|
goto e_failed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -722,7 +729,7 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
case '"':
|
case '"':
|
||||||
|
|
||||||
if (flags & flag_need_comma)
|
if (flags & flag_need_comma)
|
||||||
{ sprintf (error, "%u:%u: Expected , before \"", line_and_col);
|
{ sprintf (error, "%u:%u: Expected `,` before `\"`", line_and_col);
|
||||||
goto e_failed;
|
goto e_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,8 +751,8 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
{
|
{
|
||||||
flags &= ~ flag_need_comma;
|
flags &= ~ flag_need_comma;
|
||||||
break;
|
break;
|
||||||
}
|
} /* FALLTHRU */
|
||||||
/* FALLTHROUGH */
|
|
||||||
default:
|
default:
|
||||||
sprintf (error, "%u:%u: Unexpected `%c` in object", line_and_col, b);
|
sprintf (error, "%u:%u: Unexpected `%c` in object", line_and_col, b);
|
||||||
goto e_failed;
|
goto e_failed;
|
||||||
@@ -756,7 +763,7 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
case json_integer:
|
case json_integer:
|
||||||
case json_double:
|
case json_double:
|
||||||
|
|
||||||
if (isdigit (b))
|
if (isdigit ((unsigned char)b))
|
||||||
{
|
{
|
||||||
++ num_digits;
|
++ num_digits;
|
||||||
|
|
||||||
@@ -780,10 +787,12 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (would_overflow(top->u.integer, b))
|
if (would_overflow(top->u.integer, b))
|
||||||
{ -- num_digits;
|
{
|
||||||
|
json_int_t integer = top->u.integer;
|
||||||
|
-- num_digits;
|
||||||
-- state.ptr;
|
-- state.ptr;
|
||||||
top->type = json_double;
|
top->type = json_double;
|
||||||
top->u.dbl = (double)top->u.integer;
|
top->u.dbl = (double)integer;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,13 +822,15 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
}
|
}
|
||||||
else if (b == '.' && top->type == json_integer)
|
else if (b == '.' && top->type == json_integer)
|
||||||
{
|
{
|
||||||
|
json_int_t integer = top->u.integer;
|
||||||
|
|
||||||
if (!num_digits)
|
if (!num_digits)
|
||||||
{ sprintf (error, "%u:%u: Expected digit before `.`", line_and_col);
|
{ sprintf (error, "%u:%u: Expected digit before `.`", line_and_col);
|
||||||
goto e_failed;
|
goto e_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
top->type = json_double;
|
top->type = json_double;
|
||||||
top->u.dbl = (double) top->u.integer;
|
top->u.dbl = (double) integer;
|
||||||
|
|
||||||
flags |= flag_num_got_decimal;
|
flags |= flag_num_got_decimal;
|
||||||
num_digits = 0;
|
num_digits = 0;
|
||||||
@@ -844,8 +855,9 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
|
|
||||||
if (top->type == json_integer)
|
if (top->type == json_integer)
|
||||||
{
|
{
|
||||||
|
json_int_t integer = top->u.integer;
|
||||||
top->type = json_double;
|
top->type = json_double;
|
||||||
top->u.dbl = (double) top->u.integer;
|
top->u.dbl = (double) integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_digits = 0;
|
num_digits = 0;
|
||||||
@@ -926,7 +938,7 @@ json_value * json_parse_ex (json_settings * settings,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (++ top->parent->u.array.length) > state.uint_max)
|
if ( (++ top->parent->u.array.length) > UINT_MAX - 8)
|
||||||
goto e_overflow;
|
goto e_overflow;
|
||||||
|
|
||||||
top = top->parent;
|
top = top->parent;
|
||||||
|
|||||||
+22
-14
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
/* vim: set et ts=3 sw=3 sts=3 ft=c:
|
/* vim: set et ts=3 sw=3 sts=3 ft=c:
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
|
* Copyright (C) 2012-2021 the json-parser authors All rights reserved.
|
||||||
* https://github.com/udp/json-parser
|
* https://github.com/json-parser/json-parser
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -35,15 +36,22 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef json_int_t
|
#ifndef json_int_t
|
||||||
#ifndef _MSC_VER
|
#undef JSON_INT_T_OVERRIDDEN
|
||||||
#include <inttypes.h>
|
#if defined(_MSC_VER)
|
||||||
#define json_int_t int64_t
|
|
||||||
#else
|
|
||||||
#define json_int_t __int64
|
#define json_int_t __int64
|
||||||
|
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__cplusplus) && __cplusplus >= 201103L)
|
||||||
|
/* C99 and C++11 */
|
||||||
|
#include <stdint.h>
|
||||||
|
#define json_int_t int_fast64_t
|
||||||
|
#else
|
||||||
|
/* C89 */
|
||||||
|
#define json_int_t long
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
#define JSON_INT_T_OVERRIDDEN 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
@@ -56,7 +64,7 @@
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned long max_memory;
|
unsigned long max_memory; /* should be size_t, but would modify the API */
|
||||||
int settings;
|
int settings;
|
||||||
|
|
||||||
/* Custom allocator support (leave null to use malloc/free)
|
/* Custom allocator support (leave null to use malloc/free)
|
||||||
@@ -122,11 +130,11 @@ typedef struct _json_value
|
|||||||
|
|
||||||
json_object_entry * values;
|
json_object_entry * values;
|
||||||
|
|
||||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
#if defined(__cplusplus)
|
||||||
decltype(values) begin () const
|
json_object_entry * begin () const
|
||||||
{ return values;
|
{ return values;
|
||||||
}
|
}
|
||||||
decltype(values) end () const
|
json_object_entry * end () const
|
||||||
{ return values + length;
|
{ return values + length;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -138,11 +146,11 @@ typedef struct _json_value
|
|||||||
unsigned int length;
|
unsigned int length;
|
||||||
struct _json_value ** values;
|
struct _json_value ** values;
|
||||||
|
|
||||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
#if defined(__cplusplus)
|
||||||
decltype(values) begin () const
|
_json_value ** begin () const
|
||||||
{ return values;
|
{ return values;
|
||||||
}
|
}
|
||||||
decltype(values) end () const
|
_json_value ** end () const
|
||||||
{ return values + length;
|
{ return values + length;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+139
-71
@@ -6,7 +6,7 @@
|
|||||||
/* routines, etc. */
|
/* routines, etc. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -60,19 +60,21 @@ exitfunc(void)
|
|||||||
/* Kill any execution-time-limiter process */
|
/* Kill any execution-time-limiter process */
|
||||||
unlimit_execution_time();
|
unlimit_execution_time();
|
||||||
|
|
||||||
int maxlen, total;
|
if (DebugFlag & DB_HASHSTATS) {
|
||||||
double avglen;
|
|
||||||
if (DebugFlag & DB_PARSE_EXPR) {
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fflush(stderr);
|
fflush(ErrFp);
|
||||||
get_var_hash_stats(&total, &maxlen, &avglen);
|
fprintf(ErrFp, "Variable hash table statistics:\n");
|
||||||
fprintf(stderr, " Var hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
|
dump_var_hash_stats();
|
||||||
get_userfunc_hash_stats(&total, &maxlen, &avglen);
|
|
||||||
fprintf(stderr, " Func hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
|
fprintf(ErrFp, "Function hash table statistics:\n");
|
||||||
get_dedupe_hash_stats(&total, &maxlen, &avglen);
|
dump_userfunc_hash_stats();
|
||||||
fprintf(stderr, "Dedup hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
|
|
||||||
get_translation_hash_stats(&total, &maxlen, &avglen);
|
fprintf(ErrFp, "Dedupe hash table statistics:\n");
|
||||||
fprintf(stderr, "Trans hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
|
dump_dedupe_hash_stats();
|
||||||
|
|
||||||
|
fprintf(ErrFp, "Translation hash table statistics:\n");
|
||||||
|
dump_translation_hash_stats();
|
||||||
|
|
||||||
UnsetAllUserFuncs();
|
UnsetAllUserFuncs();
|
||||||
print_expr_nodes_stats();
|
print_expr_nodes_stats();
|
||||||
}
|
}
|
||||||
@@ -128,7 +130,7 @@ int main(int argc, char *argv[])
|
|||||||
sigemptyset(&act.sa_mask);
|
sigemptyset(&act.sa_mask);
|
||||||
act.sa_flags = SA_RESTART;
|
act.sa_flags = SA_RESTART;
|
||||||
if (sigaction(SIGALRM, &act, NULL) < 0) {
|
if (sigaction(SIGALRM, &act, NULL) < 0) {
|
||||||
fprintf(stderr, "%s: sigaction() failed: %s\n",
|
fprintf(ErrFp, "%s: sigaction() failed: %s\n",
|
||||||
argv[0], strerror(errno));
|
argv[0], strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -137,12 +139,13 @@ int main(int argc, char *argv[])
|
|||||||
act.sa_flags = SA_RESTART;
|
act.sa_flags = SA_RESTART;
|
||||||
sigemptyset(&act.sa_mask);
|
sigemptyset(&act.sa_mask);
|
||||||
if (sigaction(SIGXCPU, &act, NULL) < 0) {
|
if (sigaction(SIGXCPU, &act, NULL) < 0) {
|
||||||
fprintf(stderr, "%s: sigaction() failed: %s\n",
|
fprintf(ErrFp, "%s: sigaction() failed: %s\n",
|
||||||
argv[0], strerror(errno));
|
argv[0], strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBufInit(&(LastTrigger.tags));
|
DBufInit(&(LastTrigger.tags));
|
||||||
|
LastTrigger.infos = NULL;
|
||||||
ClearLastTriggers();
|
ClearLastTriggers();
|
||||||
|
|
||||||
atexit(exitfunc);
|
atexit(exitfunc);
|
||||||
@@ -177,6 +180,7 @@ int main(int argc, char *argv[])
|
|||||||
printf("%s\n", GetErr(E_NOREMINDERS));
|
printf("%s\n", GetErr(E_NOREMINDERS));
|
||||||
} else if (!Daemon && !NextMode && !NumTriggered) {
|
} else if (!Daemon && !NextMode && !NumTriggered) {
|
||||||
printf(GetErr(M_QUEUED), NumQueued);
|
printf(GetErr(M_QUEUED), NumQueued);
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,7 +375,7 @@ static void DoReminders(void)
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
if (!SuppressImplicitRemWarnings) {
|
if (!SuppressImplicitRemWarnings) {
|
||||||
Wprint("Unrecognized command; interpreting as REM");
|
Wprint(tr("Unrecognized command; interpreting as REM"));
|
||||||
WarnedAboutImplicit = 1;
|
WarnedAboutImplicit = 1;
|
||||||
}
|
}
|
||||||
DestroyParser(&p);
|
DestroyParser(&p);
|
||||||
@@ -600,6 +604,24 @@ int ParseNonSpaceChar(ParsePtr p, int *err, int peek)
|
|||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* ParseTokenOrQuotedString */
|
||||||
|
/* */
|
||||||
|
/* Parse either a token or a double-quote-delimited string. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
int ParseTokenOrQuotedString(ParsePtr p, DynamicBuffer *dbuf)
|
||||||
|
{
|
||||||
|
int c, err;
|
||||||
|
c = ParseNonSpaceChar(p, &err, 1);
|
||||||
|
if (err) return err;
|
||||||
|
if (c != '"') {
|
||||||
|
return ParseToken(p, dbuf);
|
||||||
|
}
|
||||||
|
return ParseQuotedString(p, dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* ParseQuotedString */
|
/* ParseQuotedString */
|
||||||
@@ -609,7 +631,9 @@ int ParseNonSpaceChar(ParsePtr p, int *err, int peek)
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int ParseQuotedString(ParsePtr p, DynamicBuffer *dbuf)
|
int ParseQuotedString(ParsePtr p, DynamicBuffer *dbuf)
|
||||||
{
|
{
|
||||||
int c, err;
|
int c, err, c2;
|
||||||
|
char hexbuf[3];
|
||||||
|
|
||||||
DBufFree(dbuf);
|
DBufFree(dbuf);
|
||||||
c = ParseNonSpaceChar(p, &err, 0);
|
c = ParseNonSpaceChar(p, &err, 0);
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
@@ -653,6 +677,34 @@ int ParseQuotedString(ParsePtr p, DynamicBuffer *dbuf)
|
|||||||
case 'v':
|
case 'v':
|
||||||
err = DBufPutc(dbuf, '\v');
|
err = DBufPutc(dbuf, '\v');
|
||||||
break;
|
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:
|
default:
|
||||||
err = DBufPutc(dbuf, c);
|
err = DBufPutc(dbuf, c);
|
||||||
}
|
}
|
||||||
@@ -845,11 +897,21 @@ void Wprint(char const *fmt, ...)
|
|||||||
va_list argptr;
|
va_list argptr;
|
||||||
|
|
||||||
|
|
||||||
|
/* We can't use line_range because caller might have used it */
|
||||||
if (FileName) {
|
if (FileName) {
|
||||||
if (strcmp(FileName, "-"))
|
if (strcmp(FileName, "-")) {
|
||||||
(void) fprintf(ErrFp, "%s(%d): ", FileName, LineNo);
|
if (LineNoStart == LineNo) {
|
||||||
else
|
(void) fprintf(ErrFp, "%s(%d): ", FileName, LineNo);
|
||||||
(void) fprintf(ErrFp, "-stdin-(%d): ", 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);
|
va_start(argptr, fmt);
|
||||||
@@ -881,7 +943,12 @@ void Eprint(char const *fmt, ...)
|
|||||||
fname = "-stdin-";
|
fname = "-stdin-";
|
||||||
}
|
}
|
||||||
if (FreshLine) {
|
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 {
|
} else {
|
||||||
fprintf(ErrFp, " ");
|
fprintf(ErrFp, " ");
|
||||||
}
|
}
|
||||||
@@ -989,6 +1056,11 @@ int SystemTime(int realtime)
|
|||||||
|
|
||||||
if (!realtime && (SysTime != -1)) return SysTime;
|
if (!realtime && (SysTime != -1)) return SysTime;
|
||||||
|
|
||||||
|
if (TestMode) {
|
||||||
|
/* Pretend it's 7:00PM in test mode */
|
||||||
|
return 19 * 3600;
|
||||||
|
}
|
||||||
|
|
||||||
now = time(NULL);
|
now = time(NULL);
|
||||||
t = localtime(&now);
|
t = localtime(&now);
|
||||||
return t->tm_hour * 3600L + t->tm_min * 60L +
|
return t->tm_hour * 3600L + t->tm_min * 60L +
|
||||||
@@ -1022,6 +1094,14 @@ int SystemDate(int *y, int *m, int *d)
|
|||||||
time_t now;
|
time_t now;
|
||||||
struct tm *t;
|
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);
|
now = time(NULL);
|
||||||
t = localtime(&now);
|
t = localtime(&now);
|
||||||
|
|
||||||
@@ -1052,8 +1132,7 @@ int DoIf(ParsePtr p)
|
|||||||
syndrome = IF_TRUE | BEFORE_ELSE;
|
syndrome = IF_TRUE | BEFORE_ELSE;
|
||||||
Eprint("%s", GetErr(r));
|
Eprint("%s", GetErr(r));
|
||||||
} else
|
} else
|
||||||
if ( (v.type != STR_TYPE && v.v.val) ||
|
if (truthy(&v)) {
|
||||||
(v.type == STR_TYPE && strcmp(v.v.str, "")) ) {
|
|
||||||
syndrome = IF_TRUE | BEFORE_ELSE;
|
syndrome = IF_TRUE | BEFORE_ELSE;
|
||||||
} else {
|
} else {
|
||||||
syndrome = IF_FALSE | BEFORE_ELSE;
|
syndrome = IF_FALSE | BEFORE_ELSE;
|
||||||
@@ -1247,12 +1326,24 @@ int DoDebug(ParsePtr p)
|
|||||||
else DebugFlag &= ~DB_ECHO_LINE;
|
else DebugFlag &= ~DB_ECHO_LINE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'q':
|
||||||
|
case 'Q':
|
||||||
|
if (val) DebugFlag |= DB_TRANSLATE;
|
||||||
|
else DebugFlag &= ~DB_TRANSLATE;
|
||||||
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
if (val) DebugFlag |= DB_PARSE_EXPR;
|
if (val) DebugFlag |= DB_PARSE_EXPR;
|
||||||
else DebugFlag &= ~DB_PARSE_EXPR;
|
else DebugFlag &= ~DB_PARSE_EXPR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
case 'H':
|
||||||
|
if (val) DebugFlag |= DB_HASHSTATS;
|
||||||
|
else DebugFlag &= ~DB_HASHSTATS;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
if (val) DebugFlag |= DB_PRTEXPR;
|
if (val) DebugFlag |= DB_PRTEXPR;
|
||||||
@@ -1282,6 +1373,9 @@ int DoDebug(ParsePtr p)
|
|||||||
if (val) DebugFlag |= DB_TRACE_FILES;
|
if (val) DebugFlag |= DB_TRACE_FILES;
|
||||||
else DebugFlag &= ~DB_TRACE_FILES;
|
else DebugFlag &= ~DB_TRACE_FILES;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
Wprint(GetErr(M_BAD_DB_FLAG), ch);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1866,6 +1960,10 @@ void
|
|||||||
FreeTrig(Trigger *t)
|
FreeTrig(Trigger *t)
|
||||||
{
|
{
|
||||||
DBufFree(&(t->tags));
|
DBufFree(&(t->tags));
|
||||||
|
if (t->infos) {
|
||||||
|
FreeTrigInfoChain(t->infos);
|
||||||
|
}
|
||||||
|
t->infos = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1891,8 +1989,7 @@ ClearLastTriggers(void)
|
|||||||
LastTrigger.warn[0] = 0;
|
LastTrigger.warn[0] = 0;
|
||||||
LastTrigger.omitfunc[0] = 0;
|
LastTrigger.omitfunc[0] = 0;
|
||||||
LastTrigger.passthru[0] = 0;
|
LastTrigger.passthru[0] = 0;
|
||||||
DBufFree(&(LastTrigger.tags));
|
FreeTrig(&LastTrigger);
|
||||||
|
|
||||||
LastTimeTrig.ttime = NO_TIME;
|
LastTimeTrig.ttime = NO_TIME;
|
||||||
LastTimeTrig.delta = NO_DELTA;
|
LastTimeTrig.delta = NO_DELTA;
|
||||||
LastTimeTrig.rep = NO_REP;
|
LastTimeTrig.rep = NO_REP;
|
||||||
@@ -1912,10 +2009,19 @@ SaveAllTriggerInfo(Trigger const *t, TimeTrig const *tt, int trigdate, int trigt
|
|||||||
void
|
void
|
||||||
SaveLastTrigger(Trigger const *t)
|
SaveLastTrigger(Trigger const *t)
|
||||||
{
|
{
|
||||||
DBufFree(&(LastTrigger.tags));
|
FreeTrig(&LastTrigger);
|
||||||
memcpy(&LastTrigger, t, sizeof(LastTrigger));
|
memcpy(&LastTrigger, t, sizeof(LastTrigger));
|
||||||
|
|
||||||
|
/* DON'T hang on to the invalid info chain! */
|
||||||
|
LastTrigger.infos = NULL;
|
||||||
DBufInit(&(LastTrigger.tags));
|
DBufInit(&(LastTrigger.tags));
|
||||||
|
|
||||||
DBufPuts(&(LastTrigger.tags), DBufValue(&(t->tags)));
|
DBufPuts(&(LastTrigger.tags), DBufValue(&(t->tags)));
|
||||||
|
TrigInfo *cur = t->infos;
|
||||||
|
while(cur) {
|
||||||
|
AppendTrigInfo(&LastTrigger, cur->info);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1930,7 +2036,6 @@ SaveLastTimeTrig(TimeTrig const *t)
|
|||||||
void
|
void
|
||||||
System(char const *cmd, int is_queued)
|
System(char const *cmd, int is_queued)
|
||||||
{
|
{
|
||||||
int r;
|
|
||||||
pid_t kid;
|
pid_t kid;
|
||||||
int fd;
|
int fd;
|
||||||
int status;
|
int status;
|
||||||
@@ -1963,15 +2068,12 @@ System(char const *cmd, int is_queued)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* This is the child process or original if we never forked */
|
/* This is the child process or original if we never forked */
|
||||||
r = system(cmd);
|
(void) system(cmd);
|
||||||
if (do_exit) {
|
if (do_exit) {
|
||||||
/* In the child process, so exit! */
|
/* In the child process, so exit! */
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
if (r == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char const *
|
char const *
|
||||||
@@ -1980,7 +2082,7 @@ get_day_name(int wkday)
|
|||||||
if (wkday < 0 || wkday > 6) {
|
if (wkday < 0 || wkday > 6) {
|
||||||
return "INVALID_WKDAY";
|
return "INVALID_WKDAY";
|
||||||
}
|
}
|
||||||
return t(DayName[wkday]);
|
return tr(DayName[wkday]);
|
||||||
}
|
}
|
||||||
|
|
||||||
char const *
|
char const *
|
||||||
@@ -1989,7 +2091,7 @@ get_month_name(int mon)
|
|||||||
if (mon < 0 || mon > 11) {
|
if (mon < 0 || mon > 11) {
|
||||||
return "INVALID_MON";
|
return "INVALID_MON";
|
||||||
}
|
}
|
||||||
return t(MonthName[mon]);
|
return tr(MonthName[mon]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GetOnceDateFromFile(void)
|
static int GetOnceDateFromFile(void)
|
||||||
@@ -2008,7 +2110,7 @@ static int GetOnceDateFromFile(void)
|
|||||||
/* Save today to file */
|
/* Save today to file */
|
||||||
fp = fopen(OnceFile, "w");
|
fp = fopen(OnceFile, "w");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
Wprint("Warning: Unable to save ONCE timestamp to %s: %s",
|
Wprint(tr("Warning: Unable to save ONCE timestamp to %s: %s"),
|
||||||
OnceFile, strerror(errno));
|
OnceFile, strerror(errno));
|
||||||
return once_date;
|
return once_date;
|
||||||
}
|
}
|
||||||
@@ -2029,25 +2131,9 @@ int GetOnceDate(void)
|
|||||||
return OnceDate;
|
return OnceDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
get_printf_escapes(char const *str, DynamicBuffer *out)
|
|
||||||
{
|
|
||||||
char const *s = str;
|
|
||||||
while(*s) {
|
|
||||||
if (*s == '%' && *(s+1) != 0) {
|
|
||||||
s++;
|
|
||||||
DBufPutc(out, *s);
|
|
||||||
}
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char const *GetErr(int r)
|
char const *GetErr(int r)
|
||||||
{
|
{
|
||||||
char const *msg;
|
char const *msg;
|
||||||
DynamicBuffer origEscapes;
|
|
||||||
DynamicBuffer translatedEscapes;
|
|
||||||
int dangerous;
|
|
||||||
|
|
||||||
if (r < 0 || r >= NumErrs) {
|
if (r < 0 || r >= NumErrs) {
|
||||||
r = E_SWERR;
|
r = E_SWERR;
|
||||||
@@ -2058,23 +2144,5 @@ char const *GetErr(int r)
|
|||||||
return ErrMsg[r];
|
return ErrMsg[r];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need to make sure both the original and translated version
|
return msg;
|
||||||
have the *SAME* printf-style escapes to avoid a malicious
|
|
||||||
translation file doing a format-string attack */
|
|
||||||
DBufInit(&origEscapes);
|
|
||||||
DBufInit(&translatedEscapes);
|
|
||||||
|
|
||||||
get_printf_escapes(ErrMsg[r], &origEscapes);
|
|
||||||
get_printf_escapes(msg, &translatedEscapes);
|
|
||||||
|
|
||||||
dangerous = strcmp(DBufValue(&origEscapes), DBufValue(&translatedEscapes));
|
|
||||||
|
|
||||||
DBufFree(&origEscapes);
|
|
||||||
DBufFree(&translatedEscapes);
|
|
||||||
|
|
||||||
if (dangerous) {
|
|
||||||
return ErrMsg[r];
|
|
||||||
} else {
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+407
-1
@@ -5,7 +5,7 @@
|
|||||||
/* Calculations for figuring out moon phases. */
|
/* Calculations for figuring out moon phases. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -546,3 +546,409 @@ void HuntPhase(int startdate, int starttim, int phas, int *date, int *time)
|
|||||||
t1 = h*60 + min;
|
t1 = h*60 + min;
|
||||||
UTCToLocal(d1, t1, date, time);
|
UTCToLocal(d1, t1, date, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Moonrise and Moonset calculations
|
||||||
|
Derived from: https://github.com/signetica/MoonRise
|
||||||
|
Original license from that project:
|
||||||
|
|
||||||
|
Copyright 2007 Stephen R. Schmitt
|
||||||
|
Subsequent work Copyright 2020 Cyrus Rahman
|
||||||
|
|
||||||
|
You may use or modify this source code in any way you find useful,
|
||||||
|
provided that you agree that the author(s) have no warranty,
|
||||||
|
obligations or liability. You must determine the suitability of this
|
||||||
|
source code for your use.
|
||||||
|
|
||||||
|
Redistributions of this source code must retain this copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* How many hours to search for moonrise / moonset? We search
|
||||||
|
half a window on either side of the starting point */
|
||||||
|
#define MR_WINDOW 48
|
||||||
|
|
||||||
|
/* K1 tide cycle is 1.0027379 cycles per solar day */
|
||||||
|
#define K1 15*(PI/180)*1.0027379
|
||||||
|
|
||||||
|
#define remainder(x, y) ((x) - (y) * rint((x)/(y)))
|
||||||
|
|
||||||
|
struct MoonInfo {
|
||||||
|
time_t queryTime;
|
||||||
|
time_t riseTime;
|
||||||
|
time_t setTime;
|
||||||
|
double riseAz;
|
||||||
|
double setAz;
|
||||||
|
int hasRise;
|
||||||
|
int hasSet;
|
||||||
|
int isVisible;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void init_moon_info(struct MoonInfo *info)
|
||||||
|
{
|
||||||
|
info->queryTime = (time_t) 0;
|
||||||
|
info->riseTime = (time_t) 0;
|
||||||
|
info->setTime = (time_t) 0;
|
||||||
|
info->riseAz = 0.0;
|
||||||
|
info->setAz = 0.0;
|
||||||
|
info->hasRise = 0;
|
||||||
|
info->hasSet = 0;
|
||||||
|
info->isVisible = 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Local Sidereal Time
|
||||||
|
Provides local sidereal time in degrees, requires longitude in degrees
|
||||||
|
and time in fractional Julian days since Jan 1, 2000, 1200UTC (e.g. the
|
||||||
|
Julian date - 2451545).
|
||||||
|
cf. USNO Astronomical Almanac and
|
||||||
|
https://astronomy.stackexchange.com/questions/24859/local-sidereal-time
|
||||||
|
*/
|
||||||
|
|
||||||
|
static double local_sidereal_time(double offset_days, double longitude)
|
||||||
|
{
|
||||||
|
double ltime = (15.0L * (6.697374558L + 0.06570982441908L * offset_days +
|
||||||
|
remainder(offset_days, 1) * 24 + 12 +
|
||||||
|
0.000026 * (offset_days / 36525) * (offset_days / 36525)) + longitude) / 360.0;
|
||||||
|
ltime -= floor(ltime);
|
||||||
|
return ltime * 360.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double julian_from_time_t(time_t t)
|
||||||
|
{
|
||||||
|
return ((double) t) / 86400.0L + 2440587.5L;
|
||||||
|
}
|
||||||
|
|
||||||
|
static time_t time_t_from_dse(int dse)
|
||||||
|
{
|
||||||
|
int y, m, d;
|
||||||
|
struct tm local;
|
||||||
|
FromDSE(dse, &y, &m, &d);
|
||||||
|
|
||||||
|
local.tm_sec = 0;
|
||||||
|
local.tm_min = 0;
|
||||||
|
local.tm_hour = 0;
|
||||||
|
local.tm_mday = d;
|
||||||
|
local.tm_mon = m;
|
||||||
|
local.tm_year = y-1900;
|
||||||
|
local.tm_isdst = -1;
|
||||||
|
|
||||||
|
return mktime(&local);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int datetime_from_time_t(time_t t)
|
||||||
|
{
|
||||||
|
struct tm *local;
|
||||||
|
int ans;
|
||||||
|
|
||||||
|
/* Round to nearest minute */
|
||||||
|
int min_offset = ((long) t) % 60;
|
||||||
|
if (min_offset >= 30) {
|
||||||
|
t += (60 - min_offset);
|
||||||
|
} else {
|
||||||
|
t -= min_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
local = localtime(&t);
|
||||||
|
|
||||||
|
ans = DSE(local->tm_year + 1900, local->tm_mon, local->tm_mday) * MINUTES_PER_DAY;
|
||||||
|
ans += local->tm_hour * 60;
|
||||||
|
ans += local->tm_min;
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3-point interpolation */
|
||||||
|
static double interpolate(double f0, double f1, double f2, double p)
|
||||||
|
{
|
||||||
|
double a = f1-f0;
|
||||||
|
double b = f2-f1-a;
|
||||||
|
return f0 + p * (2*a + b * (2*p - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Moon position using fundamental arguments
|
||||||
|
Van Flandern & Pulkkinen, 1979) */
|
||||||
|
void moon_position(double dayOffset, double *ra, double *declination, double *distance)
|
||||||
|
{
|
||||||
|
double l = 0.606434 + 0.03660110129 * dayOffset;
|
||||||
|
double m = 0.374897 + 0.03629164709 * dayOffset;
|
||||||
|
double f = 0.259091 + 0.03674819520 * dayOffset;
|
||||||
|
double d = 0.827362 + 0.03386319198 * dayOffset;
|
||||||
|
double n = 0.347343 - 0.00014709391 * dayOffset;
|
||||||
|
double g = 0.993126 + 0.00273777850 * dayOffset;
|
||||||
|
|
||||||
|
l = 2 * PI * (l - floor(l));
|
||||||
|
m = 2 * PI * (m - floor(m));
|
||||||
|
f = 2 * PI * (f - floor(f));
|
||||||
|
d = 2 * PI * (d - floor(d));
|
||||||
|
n = 2 * PI * (n - floor(n));
|
||||||
|
g = 2 * PI * (g - floor(g));
|
||||||
|
|
||||||
|
double v, u, w;
|
||||||
|
v = 0.39558 * sin(f + n)
|
||||||
|
+ 0.08200 * sin(f)
|
||||||
|
+ 0.03257 * sin(m - f - n)
|
||||||
|
+ 0.01092 * sin(m + f + n)
|
||||||
|
+ 0.00666 * sin(m - f)
|
||||||
|
- 0.00644 * sin(m + f - 2*d + n)
|
||||||
|
- 0.00331 * sin(f - 2*d + n)
|
||||||
|
- 0.00304 * sin(f - 2*d)
|
||||||
|
- 0.00240 * sin(m - f - 2*d - n)
|
||||||
|
+ 0.00226 * sin(m + f)
|
||||||
|
- 0.00108 * sin(m + f - 2*d)
|
||||||
|
- 0.00079 * sin(f - n)
|
||||||
|
+ 0.00078 * sin(f + 2*d + n);
|
||||||
|
u = 1
|
||||||
|
- 0.10828 * cos(m)
|
||||||
|
- 0.01880 * cos(m - 2*d)
|
||||||
|
- 0.01479 * cos(2*d)
|
||||||
|
+ 0.00181 * cos(2*m - 2*d)
|
||||||
|
- 0.00147 * cos(2*m)
|
||||||
|
- 0.00105 * cos(2*d - g)
|
||||||
|
- 0.00075 * cos(m - 2*d + g);
|
||||||
|
w = 0.10478 * sin(m)
|
||||||
|
- 0.04105 * sin(2*f + 2*n)
|
||||||
|
- 0.02130 * sin(m - 2*d)
|
||||||
|
- 0.01779 * sin(2*f + n)
|
||||||
|
+ 0.01774 * sin(n)
|
||||||
|
+ 0.00987 * sin(2*d)
|
||||||
|
- 0.00338 * sin(m - 2*f - 2*n)
|
||||||
|
- 0.00309 * sin(g)
|
||||||
|
- 0.00190 * sin(2*f)
|
||||||
|
- 0.00144 * sin(m + n)
|
||||||
|
- 0.00144 * sin(m - 2*f - n)
|
||||||
|
- 0.00113 * sin(m + 2*f + 2*n)
|
||||||
|
- 0.00094 * sin(m - 2*d + g)
|
||||||
|
- 0.00092 * sin(2*m - 2*d);
|
||||||
|
|
||||||
|
double s;
|
||||||
|
s = w / sqrt(u - v*v);
|
||||||
|
*ra = l + atan(s / sqrt(1 - s*s)); // Right ascension
|
||||||
|
|
||||||
|
s = v / sqrt(u);
|
||||||
|
*declination = atan(s / sqrt(1 - s*s)); // Declination
|
||||||
|
*distance = 60.40974 * sqrt(u); // Distance
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search for moonrise / moonset events during an hour */
|
||||||
|
static void test_moon_event(int k, double offset_days, struct MoonInfo *moon_info,
|
||||||
|
double latitude, double longitude,
|
||||||
|
double const ra[], double declination[], double const distance[])
|
||||||
|
{
|
||||||
|
double ha[3], VHz[3];
|
||||||
|
double lSideTime;
|
||||||
|
|
||||||
|
/* Get (local_sidereal_time - MR_WINDOW / 2) hours in radians. */
|
||||||
|
lSideTime = local_sidereal_time(offset_days, longitude) * PI / 180.0;
|
||||||
|
|
||||||
|
/* Calculate hour angle */
|
||||||
|
ha[0] = lSideTime - ra[0] + k*K1;
|
||||||
|
ha[2] = lSideTime - ra[2] + k*K1 + K1;
|
||||||
|
|
||||||
|
// Hour Angle and declination at half hour.
|
||||||
|
ha[1] = (ha[2] + ha[0])/2;
|
||||||
|
declination[1] = (declination[2] + declination[0])/2;
|
||||||
|
|
||||||
|
double s = sin((PI / 180) * latitude);
|
||||||
|
double c = cos((PI / 180) * latitude);
|
||||||
|
|
||||||
|
// refraction + semidiameter at horizon + distance correction
|
||||||
|
double z = cos((PI / 180) * (90.567 - 41.685 / distance[0]));
|
||||||
|
|
||||||
|
VHz[0] = s * sin(declination[0]) + c * cos(declination[0]) * cos(ha[0]) - z;
|
||||||
|
VHz[2] = s * sin(declination[2]) + c * cos(declination[2]) * cos(ha[2]) - z;
|
||||||
|
|
||||||
|
if (signbit(VHz[0]) == signbit(VHz[2]))
|
||||||
|
goto noevent; // No event this hour.
|
||||||
|
|
||||||
|
VHz[1] = s * sin(declination[1]) + c * cos(declination[1]) * cos(ha[1]) - z;
|
||||||
|
|
||||||
|
double a, b, d, e, time;
|
||||||
|
a = 2 * VHz[2] - 4 * VHz[1] + 2 * VHz[0];
|
||||||
|
b = 4 * VHz[1] - 3 * VHz[0] - VHz[2];
|
||||||
|
d = b * b - 4 * a * VHz[0];
|
||||||
|
|
||||||
|
if (d < 0)
|
||||||
|
goto noevent; // No event this hour.
|
||||||
|
|
||||||
|
d = sqrt(d);
|
||||||
|
e = (-b + d) / (2 * a);
|
||||||
|
if ((e < 0) || (e > 1))
|
||||||
|
e = (-b - d) / (2 * a);
|
||||||
|
time = k + e + 1 / 120; // Time since k=0 of event (in hours).
|
||||||
|
|
||||||
|
// The time we started searching + the time from the start of the search to the
|
||||||
|
// event is the time of the event. Add (time since k=0) - window/2 hours.
|
||||||
|
time_t eventTime;
|
||||||
|
eventTime = moon_info->queryTime + (time - MR_WINDOW / 2) *60 *60;
|
||||||
|
|
||||||
|
double hz, nz, dz, az;
|
||||||
|
hz = ha[0] + e * (ha[2] - ha[0]); // Azimuth of the moon at the event.
|
||||||
|
nz = -cos(declination[1]) * sin(hz);
|
||||||
|
dz = c * sin(declination[1]) - s * cos(declination[1]) * cos(hz);
|
||||||
|
az = atan2(nz, dz) * (180 / PI);
|
||||||
|
if (az < 0) {
|
||||||
|
az += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no previously recorded event of this type, save this event.
|
||||||
|
//
|
||||||
|
// If this event is previous to queryTime, and is the nearest event to queryTime
|
||||||
|
// of events of its type previous to queryType, save this event, replacing the
|
||||||
|
// previously recorded event of its type. Events subsequent to queryTime are
|
||||||
|
// treated similarly, although since events are tested in chronological order
|
||||||
|
// no replacements will occur as successive events will be further from
|
||||||
|
// queryTime.
|
||||||
|
//
|
||||||
|
// If this event is subsequent to queryTime and there is an event of its type
|
||||||
|
// previous to queryTime, then there is an event of the other type between the
|
||||||
|
// two events of this event's type. If the event of the other type is
|
||||||
|
// previous to queryTime, then it is the nearest event to queryTime that is
|
||||||
|
// previous to queryTime. In this case save the current event, replacing
|
||||||
|
// the previously recorded event of its type. Otherwise discard the current
|
||||||
|
// event.
|
||||||
|
//
|
||||||
|
if ((VHz[0] < 0) && (VHz[2] > 0)) {
|
||||||
|
if (!moon_info->hasRise ||
|
||||||
|
((moon_info->riseTime < moon_info->queryTime) == (eventTime < moon_info->queryTime) &&
|
||||||
|
labs(moon_info->riseTime - moon_info->queryTime) > labs(eventTime - moon_info->queryTime)) ||
|
||||||
|
((moon_info->riseTime < moon_info->queryTime) != (eventTime < moon_info->queryTime) &&
|
||||||
|
(moon_info->hasSet &&
|
||||||
|
(moon_info->riseTime < moon_info->queryTime) == (moon_info->setTime < moon_info->queryTime)))) {
|
||||||
|
moon_info->riseTime = eventTime;
|
||||||
|
moon_info->riseAz = az;
|
||||||
|
moon_info->hasRise = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((VHz[0] > 0) && (VHz[2] < 0)) {
|
||||||
|
if (!moon_info->hasSet ||
|
||||||
|
((moon_info->setTime < moon_info->queryTime) == (eventTime < moon_info->queryTime) &&
|
||||||
|
labs(moon_info->setTime - moon_info->queryTime) > labs(eventTime - moon_info->queryTime)) ||
|
||||||
|
((moon_info->setTime < moon_info->queryTime) != (eventTime < moon_info->queryTime) &&
|
||||||
|
(moon_info->hasRise &&
|
||||||
|
(moon_info->setTime < moon_info->queryTime) == (moon_info->riseTime < moon_info->queryTime)))) {
|
||||||
|
moon_info->setTime = eventTime;
|
||||||
|
moon_info->setAz = az;
|
||||||
|
moon_info->hasSet = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
noevent:
|
||||||
|
// There are obscure cases in the polar regions that require extra logic.
|
||||||
|
if (!moon_info->hasRise && !moon_info->hasSet)
|
||||||
|
moon_info->isVisible = !signbit(VHz[2]);
|
||||||
|
else if (moon_info->hasRise && !moon_info->hasSet)
|
||||||
|
moon_info->isVisible = (moon_info->queryTime > moon_info->riseTime);
|
||||||
|
else if (!moon_info->hasRise && moon_info->hasSet)
|
||||||
|
moon_info->isVisible = (moon_info->queryTime < moon_info->setTime);
|
||||||
|
else
|
||||||
|
moon_info->isVisible = ((moon_info->riseTime < moon_info->setTime && moon_info->riseTime < moon_info->queryTime && moon_info->setTime > moon_info->queryTime) ||
|
||||||
|
(moon_info->riseTime > moon_info->setTime && (moon_info->riseTime < moon_info->queryTime || moon_info->setTime > moon_info->queryTime)));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
calculate_moonrise_moonset(double latitude, double longitude, time_t t,
|
||||||
|
struct MoonInfo *mi)
|
||||||
|
{
|
||||||
|
double ra[3], declination[3], distance[3];
|
||||||
|
double offset_days;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
init_moon_info(mi);
|
||||||
|
|
||||||
|
mi->queryTime = t;
|
||||||
|
|
||||||
|
/* Days since Jan 1, 2000 12:00UTC */
|
||||||
|
offset_days = julian_from_time_t(t) - 2451545L;
|
||||||
|
|
||||||
|
offset_days -= (double) MR_WINDOW / (2.0 * 24.0);
|
||||||
|
|
||||||
|
for (i=0; i<3; i++) {
|
||||||
|
moon_position(offset_days + i * ((double) MR_WINDOW / (2.0 * 24.0)), &ra[i], &declination[i], &distance[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ra[1] <= ra[0]) {
|
||||||
|
ra[1] += 2*PI;
|
||||||
|
}
|
||||||
|
if (ra[2] <= ra[1]) {
|
||||||
|
ra[2] += 2*PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
double window_ra[3], window_declination[3], window_distance[3];
|
||||||
|
|
||||||
|
window_ra[0] = ra[0];
|
||||||
|
window_declination[0] = declination[0];
|
||||||
|
window_distance[0] = distance[0];
|
||||||
|
|
||||||
|
for (int k=0; k < MR_WINDOW; k++) {
|
||||||
|
double ph = (double) (k+1) / (double) MR_WINDOW;
|
||||||
|
window_ra[2] = interpolate(ra[0], ra[1], ra[2], ph);
|
||||||
|
window_declination[2] = interpolate(declination[0], declination[1], declination[2], ph);
|
||||||
|
window_distance[2] = interpolate(distance[0], distance[1], distance[2], ph);
|
||||||
|
test_moon_event(k, offset_days, mi, latitude, longitude, window_ra, window_declination, window_distance);
|
||||||
|
|
||||||
|
/* Step to next interval */
|
||||||
|
window_ra[0] = window_ra[2];
|
||||||
|
window_declination[0] = window_declination[2];
|
||||||
|
window_distance[0] = window_distance[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get next moonrise or moonset in minutes after midnight of BASEYR
|
||||||
|
starting from given DSE.
|
||||||
|
Returns 0 if no moonrise could be computed
|
||||||
|
If want_angle is true, then returns the azimuth of the event rather
|
||||||
|
than the time of the event */
|
||||||
|
|
||||||
|
#define ME_SEARCH_DAYS 180
|
||||||
|
static int GetMoonevent(int dse, int is_rise, int want_angle)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int angle;
|
||||||
|
struct MoonInfo mi;
|
||||||
|
time_t t = time_t_from_dse(dse);
|
||||||
|
for (i=0; i<ME_SEARCH_DAYS; i++) {
|
||||||
|
calculate_moonrise_moonset(Latitude, Longitude, t + i * 86400, &mi);
|
||||||
|
if (is_rise) {
|
||||||
|
if (mi.hasRise && mi.riseTime >= t) {
|
||||||
|
if (want_angle) {
|
||||||
|
angle = (int) (mi.riseAz + 0.5);
|
||||||
|
return angle;
|
||||||
|
} else {
|
||||||
|
return datetime_from_time_t(mi.riseTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mi.hasSet && mi.setTime >= t) {
|
||||||
|
if (want_angle) {
|
||||||
|
angle = (int) (mi.setAz + 0.5);
|
||||||
|
return angle;
|
||||||
|
} else {
|
||||||
|
return datetime_from_time_t(mi.setTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (want_angle) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetMoonrise(int dse)
|
||||||
|
{
|
||||||
|
return GetMoonevent(dse, 1, 0);
|
||||||
|
}
|
||||||
|
int GetMoonset(int dse)
|
||||||
|
{
|
||||||
|
return GetMoonevent(dse, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetMoonrise_angle(int dse)
|
||||||
|
{
|
||||||
|
return GetMoonevent(dse, 1, 1);
|
||||||
|
}
|
||||||
|
int GetMoonset_angle(int dse)
|
||||||
|
{
|
||||||
|
return GetMoonevent(dse, 0, 1);
|
||||||
|
}
|
||||||
|
|||||||
+12
-8
@@ -6,7 +6,7 @@
|
|||||||
/* the data structures for OMITted dates. */
|
/* the data structures for OMITted dates. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -92,7 +92,7 @@ int DestroyOmitContexts(int print_unmatched)
|
|||||||
|
|
||||||
while (c) {
|
while (c) {
|
||||||
if (print_unmatched) {
|
if (print_unmatched) {
|
||||||
Wprint("Unmatched PUSH-OMIT-CONTEXT at %s(%d)",
|
Wprint(tr("Unmatched PUSH-OMIT-CONTEXT at %s(%d)"),
|
||||||
c->filename, c->lineno);
|
c->filename, c->lineno);
|
||||||
}
|
}
|
||||||
num++;
|
num++;
|
||||||
@@ -185,6 +185,9 @@ int PopOmitContext(ParsePtr p)
|
|||||||
/* Remove the context from the stack */
|
/* Remove the context from the stack */
|
||||||
SavedOmitContexts = c->next;
|
SavedOmitContexts = c->next;
|
||||||
|
|
||||||
|
if (c->filename && FileName && strcmp(c->filename, FileName)) {
|
||||||
|
Wprint(tr("POP-OMIT-CONTEXT at %s:%d matches PUSH-OMIT-CONTEXT in different file: %s:%d"), FileName, LineNo, c->filename, c->lineno);
|
||||||
|
}
|
||||||
/* Free memory used by the saved context */
|
/* Free memory used by the saved context */
|
||||||
if (c->partsave) free(c->partsave);
|
if (c->partsave) free(c->partsave);
|
||||||
if (c->fullsave) free(c->fullsave);
|
if (c->fullsave) free(c->fullsave);
|
||||||
@@ -215,7 +218,7 @@ int IsOmitted(int dse, int localomit, char const *omitfunc, int *omit)
|
|||||||
Value v;
|
Value v;
|
||||||
|
|
||||||
FromDSE(dse, &y, &m, &d);
|
FromDSE(dse, &y, &m, &d);
|
||||||
sprintf(expr, "%s('%04d-%02d-%02d')",
|
snprintf(expr, sizeof(expr), "%s('%04d-%02d-%02d')",
|
||||||
omitfunc, y, m+1, d);
|
omitfunc, y, m+1, d);
|
||||||
s = expr;
|
s = expr;
|
||||||
r = EvalExpr(&s, &v, NULL);
|
r = EvalExpr(&s, &v, NULL);
|
||||||
@@ -385,6 +388,7 @@ int DoOmit(ParsePtr p)
|
|||||||
case T_RemType:
|
case T_RemType:
|
||||||
case T_Priority:
|
case T_Priority:
|
||||||
case T_Tag:
|
case T_Tag:
|
||||||
|
case T_Info:
|
||||||
case T_Duration:
|
case T_Duration:
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
parsing = 0;
|
parsing = 0;
|
||||||
@@ -392,7 +396,7 @@ int DoOmit(ParsePtr p)
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
if (tok.type == T_Until) {
|
if (tok.type == T_Until) {
|
||||||
Eprint("OMIT: UNTIL not allowed; did you mean THROUGH?");
|
Eprint(tr("OMIT: UNTIL not allowed; did you mean THROUGH?"));
|
||||||
} else if (tok.type == T_Illegal && tok.val < 0) {
|
} else if (tok.type == T_Illegal && tok.val < 0) {
|
||||||
Eprint("%s: `%s'", GetErr(-tok.val), DBufValue(&buf));
|
Eprint("%s: `%s'", GetErr(-tok.val), DBufValue(&buf));
|
||||||
} else {
|
} else {
|
||||||
@@ -412,7 +416,7 @@ int DoOmit(ParsePtr p)
|
|||||||
return E_2MANY_LOCALOMIT;
|
return E_2MANY_LOCALOMIT;
|
||||||
}
|
}
|
||||||
WeekdayOmits |= wd;
|
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;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,7 +466,7 @@ int DoOmit(ParsePtr p)
|
|||||||
InsertIntoSortedArray(PartialOmitArray, NumPartialOmits, syndrome);
|
InsertIntoSortedArray(PartialOmitArray, NumPartialOmits, syndrome);
|
||||||
NumPartialOmits++;
|
NumPartialOmits++;
|
||||||
if (NumPartialOmits == 366) {
|
if (NumPartialOmits == 366) {
|
||||||
Wprint("You have OMITted everything! The space-time continuum is at risk.");
|
Wprint(tr("You have OMITted everything! The space-time continuum is at risk."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mc == m[1] && dc == d[1]) {
|
if (mc == m[1] && dc == d[1]) {
|
||||||
@@ -484,7 +488,7 @@ int DoOmit(ParsePtr p)
|
|||||||
start = DSE(y[0], m[0], d[0]);
|
start = DSE(y[0], m[0], d[0]);
|
||||||
end = DSE(y[1], m[1], d[1]);
|
end = DSE(y[1], m[1], d[1]);
|
||||||
if (end < start) {
|
if (end < start) {
|
||||||
Eprint("Error: THROUGH date earlier than start date");
|
Eprint(tr("Error: THROUGH date earlier than start date"));
|
||||||
return E_BAD_DATE;
|
return E_BAD_DATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,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;
|
return OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-8
@@ -5,7 +5,7 @@
|
|||||||
/* Function Prototypes. */
|
/* Function Prototypes. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -88,6 +88,7 @@ int JulianToGregorianOffset(int y, int m);
|
|||||||
int ParseChar (ParsePtr p, int *err, int peek);
|
int ParseChar (ParsePtr p, int *err, int peek);
|
||||||
int ParseToken (ParsePtr p, DynamicBuffer *dbuf);
|
int ParseToken (ParsePtr p, DynamicBuffer *dbuf);
|
||||||
int ParseQuotedString (ParsePtr p, DynamicBuffer *dbuf);
|
int ParseQuotedString (ParsePtr p, DynamicBuffer *dbuf);
|
||||||
|
int ParseTokenOrQuotedString (ParsePtr p, DynamicBuffer *dbuf);
|
||||||
int ParseIdentifier (ParsePtr p, DynamicBuffer *dbuf);
|
int ParseIdentifier (ParsePtr p, DynamicBuffer *dbuf);
|
||||||
expr_node * ParseExpr(ParsePtr p, int *r);
|
expr_node * ParseExpr(ParsePtr p, int *r);
|
||||||
void print_expr_nodes_stats(void);
|
void print_expr_nodes_stats(void);
|
||||||
@@ -225,10 +226,9 @@ char const *get_day_name(int wkday);
|
|||||||
char const *get_month_name(int mon);
|
char const *get_month_name(int mon);
|
||||||
|
|
||||||
void set_cloexec(FILE *fp);
|
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);
|
void clear_callstack(void);
|
||||||
int print_callstack(FILE *fp);
|
int print_callstack(FILE *fp);
|
||||||
int have_callstack(void);
|
|
||||||
void pop_call(void);
|
void pop_call(void);
|
||||||
void FixSpecialType(Trigger *trig);
|
void FixSpecialType(Trigger *trig);
|
||||||
void WriteJSONTrigger(Trigger const *t, int include_tags, int today);
|
void WriteJSONTrigger(Trigger const *t, int include_tags, int today);
|
||||||
@@ -255,10 +255,10 @@ void print_builtinfunc_tokens(void);
|
|||||||
void print_remind_tokens(void);
|
void print_remind_tokens(void);
|
||||||
|
|
||||||
/* Stats for -ds output */
|
/* Stats for -ds output */
|
||||||
void get_var_hash_stats(int *total, int *maxlen, double *avglen);
|
void dump_var_hash_stats(void);
|
||||||
void get_userfunc_hash_stats(int *total, int *maxlen, double *avglen);
|
void dump_userfunc_hash_stats(void);
|
||||||
void get_dedupe_hash_stats(int *total, int *maxlen, double *avglen);
|
void dump_dedupe_hash_stats(void);
|
||||||
void get_translation_hash_stats(int *total, int *maxlen, double *avglen);
|
void dump_translation_hash_stats(void);
|
||||||
|
|
||||||
/* Dedupe code */
|
/* Dedupe code */
|
||||||
int ShouldDedupe(int trigger_date, int trigger_time, char const *body);
|
int ShouldDedupe(int trigger_date, int trigger_time, char const *body);
|
||||||
@@ -271,6 +271,21 @@ void InitTranslationTable(void);
|
|||||||
char const *GetTranslatedString(char const *orig);
|
char const *GetTranslatedString(char const *orig);
|
||||||
int GetTranslatedStringTryingVariants(char const *orig, DynamicBuffer *out);
|
int GetTranslatedStringTryingVariants(char const *orig, DynamicBuffer *out);
|
||||||
char const *GetErr(int r);
|
char const *GetErr(int r);
|
||||||
char const *t(char const *s);
|
|
||||||
char const *tr(char const *s);
|
char const *tr(char const *s);
|
||||||
void print_escaped_string(FILE *fp, 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, 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
-5
@@ -5,7 +5,7 @@
|
|||||||
/* Queue up reminders for subsequent execution. */
|
/* Queue up reminders for subsequent execution. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -61,6 +61,7 @@ typedef struct queuedrem {
|
|||||||
char const *text;
|
char const *text;
|
||||||
char const *fname;
|
char const *fname;
|
||||||
int lineno;
|
int lineno;
|
||||||
|
int lineno_start;
|
||||||
char passthru[PASSTHRU_LEN+1];
|
char passthru[PASSTHRU_LEN+1];
|
||||||
char sched[VAR_NAME_LEN+1];
|
char sched[VAR_NAME_LEN+1];
|
||||||
Trigger t;
|
Trigger t;
|
||||||
@@ -163,6 +164,7 @@ static void del_reminder(QueuedRem *qid)
|
|||||||
if (q == qid) {
|
if (q == qid) {
|
||||||
QueueHead = q->next;
|
QueueHead = q->next;
|
||||||
if (q->text) free((void *) q->text);
|
if (q->text) free((void *) q->text);
|
||||||
|
FreeTrig(&(q->t));
|
||||||
free(q);
|
free(q);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -171,6 +173,7 @@ static void del_reminder(QueuedRem *qid)
|
|||||||
if (q->next == qid) {
|
if (q->next == qid) {
|
||||||
q->next = q->next->next;
|
q->next = q->next->next;
|
||||||
if (next->text) free((void *) next->text);
|
if (next->text) free((void *) next->text);
|
||||||
|
FreeTrig(&(next->t));
|
||||||
free(next);
|
free(next);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -222,11 +225,16 @@ int QueueReminder(ParsePtr p, Trigger *trig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
qelem->lineno = LineNo;
|
qelem->lineno = LineNo;
|
||||||
|
qelem->lineno_start = LineNoStart;
|
||||||
NumQueued++;
|
NumQueued++;
|
||||||
qelem->typ = trig->typ;
|
qelem->typ = trig->typ;
|
||||||
strcpy(qelem->passthru, trig->passthru);
|
strcpy(qelem->passthru, trig->passthru);
|
||||||
qelem->tt = *tim;
|
qelem->tt = *tim;
|
||||||
qelem->t = *trig;
|
qelem->t = *trig;
|
||||||
|
|
||||||
|
/* Take over infos */
|
||||||
|
trig->infos = NULL;
|
||||||
|
|
||||||
DBufInit(&(qelem->t.tags));
|
DBufInit(&(qelem->t.tags));
|
||||||
DBufPuts(&(qelem->t.tags), DBufValue(&(trig->tags)));
|
DBufPuts(&(qelem->t.tags), DBufValue(&(trig->tags)));
|
||||||
if (SynthesizeTags) {
|
if (SynthesizeTags) {
|
||||||
@@ -346,8 +354,9 @@ void HandleQueuedReminders(void)
|
|||||||
/* If we're a daemon, get the mod time of initial file */
|
/* If we're a daemon, get the mod time of initial file */
|
||||||
if (Daemon > 0) {
|
if (Daemon > 0) {
|
||||||
if (stat(InitialFile, &StatBuf)) {
|
if (stat(InitialFile, &StatBuf)) {
|
||||||
fprintf(ErrFp, "Cannot stat %s - not running as daemon!\n",
|
fprintf(ErrFp, tr("Cannot stat %s - not running as daemon!"),
|
||||||
InitialFile);
|
InitialFile);
|
||||||
|
fprintf(ErrFp, "\n");
|
||||||
Daemon = 0;
|
Daemon = 0;
|
||||||
} else FileModTime = StatBuf.st_mtime;
|
} else FileModTime = StatBuf.st_mtime;
|
||||||
}
|
}
|
||||||
@@ -459,10 +468,17 @@ void HandleQueuedReminders(void)
|
|||||||
if (IsServerMode() && q->typ != RUN_TYPE) {
|
if (IsServerMode() && q->typ != RUN_TYPE) {
|
||||||
if (DaemonJSON) {
|
if (DaemonJSON) {
|
||||||
printf("{\"response\":\"reminder\",");
|
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("qid", qid);
|
||||||
PrintJSONKeyPairString("ttime", SimpleTimeNoSpace(q->tt.ttime));
|
PrintJSONKeyPairString("ttime", SimpleTimeNoSpace(q->tt.ttime));
|
||||||
PrintJSONKeyPairString("now", SimpleTimeNoSpace(MinutesPastMidnight(1)));
|
PrintJSONKeyPairString("now", SimpleTimeNoSpace(MinutesPastMidnight(1)));
|
||||||
|
if (q->t.infos) {
|
||||||
|
WriteJSONInfoChain(q->t.infos);
|
||||||
|
}
|
||||||
PrintJSONKeyPairString("tags", DBufValue(&q->t.tags));
|
PrintJSONKeyPairString("tags", DBufValue(&q->t.tags));
|
||||||
} else {
|
} else {
|
||||||
printf("NOTE reminder %s",
|
printf("NOTE reminder %s",
|
||||||
@@ -485,6 +501,7 @@ void HandleQueuedReminders(void)
|
|||||||
DefaultColorB = q->blue;
|
DefaultColorB = q->blue;
|
||||||
/* Make a COPY of q->t because TriggerReminder can change q->t.typ */
|
/* Make a COPY of q->t because TriggerReminder can change q->t.typ */
|
||||||
Trigger tcopy = q->t;
|
Trigger tcopy = q->t;
|
||||||
|
|
||||||
if (DaemonJSON) {
|
if (DaemonJSON) {
|
||||||
DynamicBuffer out;
|
DynamicBuffer out;
|
||||||
DBufInit(&out);
|
DBufInit(&out);
|
||||||
@@ -697,7 +714,7 @@ static int CalculateNextTimeUsingSched(QueuedRem *q)
|
|||||||
to be a security hole! */
|
to be a security hole! */
|
||||||
while(1) {
|
while(1) {
|
||||||
char exprBuf[VAR_NAME_LEN+32];
|
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;
|
s = exprBuf;
|
||||||
r = EvalExpr(&s, &v, NULL);
|
r = EvalExpr(&s, &v, NULL);
|
||||||
if (r) {
|
if (r) {
|
||||||
@@ -759,12 +776,19 @@ json_queue(QueuedRem const *q)
|
|||||||
printf("{");
|
printf("{");
|
||||||
WriteJSONTrigger(&(q->t), 1, DSEToday);
|
WriteJSONTrigger(&(q->t), 1, DSEToday);
|
||||||
WriteJSONTimeTrigger(&(q->tt));
|
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);
|
PrintJSONKeyPairString("qid", idbuf);
|
||||||
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
|
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
|
||||||
PrintJSONKeyPairInt("ntrig", q->ntrig);
|
PrintJSONKeyPairInt("ntrig", q->ntrig);
|
||||||
PrintJSONKeyPairString("filename", q->fname);
|
PrintJSONKeyPairString("filename", q->fname);
|
||||||
PrintJSONKeyPairInt("lineno", q->lineno);
|
PrintJSONKeyPairInt("lineno", q->lineno);
|
||||||
|
if (q->lineno_start != q->lineno) {
|
||||||
|
PrintJSONKeyPairInt("lineno_start", q->lineno_start);
|
||||||
|
}
|
||||||
switch(q->typ) {
|
switch(q->typ) {
|
||||||
case NO_TYPE: PrintJSONKeyPairString("type", "NO_TYPE"); break;
|
case NO_TYPE: PrintJSONKeyPairString("type", "NO_TYPE"); break;
|
||||||
case MSG_TYPE: PrintJSONKeyPairString("type", "MSG_TYPE"); break;
|
case MSG_TYPE: PrintJSONKeyPairString("type", "MSG_TYPE"); break;
|
||||||
|
|||||||
+6
-6
@@ -5,7 +5,7 @@
|
|||||||
/* Print a PostScript calendar. */
|
/* Print a PostScript calendar. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -342,7 +342,7 @@ int main(int argc, char *argv[])
|
|||||||
while (!feof(stdin)) {
|
while (!feof(stdin)) {
|
||||||
DBufGets(&buf, stdin);
|
DBufGets(&buf, stdin);
|
||||||
if (first_line && (!strcmp(DBufValue(&buf), "["))) {
|
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);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
first_line = 0;
|
first_line = 0;
|
||||||
@@ -350,7 +350,7 @@ int main(int argc, char *argv[])
|
|||||||
!strcmp(DBufValue(&buf), PSBEGIN2)) {
|
!strcmp(DBufValue(&buf), PSBEGIN2)) {
|
||||||
if (!validfile) {
|
if (!validfile) {
|
||||||
if (Verbose) {
|
if (Verbose) {
|
||||||
fprintf(stderr, "Rem2PS: Version %s Copyright 1992-2024 by Dianne Skoll\n\n", VERSION);
|
fprintf(stderr, "Rem2PS: Version %s Copyright (C) 1992-2025 by Dianne Skoll\n\n", VERSION);
|
||||||
fprintf(stderr, "Generating PostScript calendar\n");
|
fprintf(stderr, "Generating PostScript calendar\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1222,7 +1222,7 @@ int DoQueuedPs(void)
|
|||||||
if (moonsize < 0) {
|
if (moonsize < 0) {
|
||||||
size = "DaySize 2 div";
|
size = "DaySize 2 div";
|
||||||
} else {
|
} else {
|
||||||
sprintf(buffer, "%d", moonsize);
|
snprintf(buffer, sizeof(buffer), "%d", moonsize);
|
||||||
size = buffer;
|
size = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1235,7 +1235,7 @@ int DoQueuedPs(void)
|
|||||||
if (fontsize < 0) {
|
if (fontsize < 0) {
|
||||||
fsize = "EntrySize";
|
fsize = "EntrySize";
|
||||||
} else {
|
} else {
|
||||||
sprintf(fbuffer, "%d", fontsize);
|
snprintf(fbuffer, sizeof(fbuffer), "%d", fontsize);
|
||||||
fsize = fbuffer;
|
fsize = fbuffer;
|
||||||
}
|
}
|
||||||
printf("/EntryFont findfont %s scalefont setfont (",
|
printf("/EntryFont findfont %s scalefont setfont (",
|
||||||
@@ -1273,7 +1273,7 @@ int DoQueuedPs(void)
|
|||||||
if (fontsize < 0) {
|
if (fontsize < 0) {
|
||||||
fsize = "EntrySize";
|
fsize = "EntrySize";
|
||||||
} else {
|
} else {
|
||||||
sprintf(fbuffer, "%d", fontsize);
|
snprintf(fbuffer, sizeof(fbuffer), "%d", fontsize);
|
||||||
fsize = fbuffer;
|
fsize = fbuffer;
|
||||||
}
|
}
|
||||||
printf("/EntryFont findfont %s scalefont setfont (",
|
printf("/EntryFont findfont %s scalefont setfont (",
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@
|
|||||||
/* Define the PostScript prologue */
|
/* Define the PostScript prologue */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -14,7 +14,7 @@ char *PSProlog1[] =
|
|||||||
{
|
{
|
||||||
"% This file was produced by Remind and Rem2PS, written by",
|
"% This file was produced by Remind and Rem2PS, written by",
|
||||||
"% Dianne Skoll.",
|
"% Dianne Skoll.",
|
||||||
"% Remind and Rem2PS are Copyright 1992-2024 Dianne Skoll.",
|
"% Remind and Rem2PS are Copyright (C) 1992-2025 Dianne Skoll.",
|
||||||
"/ISOLatin1Encoding where { pop save true }{ false } ifelse",
|
"/ISOLatin1Encoding where { pop save true }{ false } ifelse",
|
||||||
" /ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus",
|
" /ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus",
|
||||||
" StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute",
|
" StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute",
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@
|
|||||||
/* Routines for sorting reminders by trigger date */
|
/* Routines for sorting reminders by trigger date */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -183,7 +183,7 @@ static void IssueSortBanner(int dse)
|
|||||||
if (UserFuncExists("sortbanner") != 1) return;
|
if (UserFuncExists("sortbanner") != 1) return;
|
||||||
|
|
||||||
FromDSE(dse, &y, &m, &d);
|
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);
|
y = EvalExpr(&s, &v, NULL);
|
||||||
if (y) return;
|
if (y) return;
|
||||||
if (DoCoerce(STR_TYPE, &v)) return;
|
if (DoCoerce(STR_TYPE, &v)) return;
|
||||||
|
|||||||
+2
-1
@@ -6,7 +6,7 @@
|
|||||||
/* classifying the tokens parsed. */
|
/* classifying the tokens parsed. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -71,6 +71,7 @@ Token TokArray[] = {
|
|||||||
{ "in", 2, T_In, 0 },
|
{ "in", 2, T_In, 0 },
|
||||||
{ "include", 3, T_Include, 0 },
|
{ "include", 3, T_Include, 0 },
|
||||||
{ "includecmd", 10, T_IncludeCmd, 0 },
|
{ "includecmd", 10, T_IncludeCmd, 0 },
|
||||||
|
{ "info", 4, T_Info, 0 },
|
||||||
{ "january", 3, T_Month, 0 },
|
{ "january", 3, T_Month, 0 },
|
||||||
{ "july", 3, T_Month, 6 },
|
{ "july", 3, T_Month, 6 },
|
||||||
{ "june", 3, T_Month, 5 },
|
{ "june", 3, T_Month, 5 },
|
||||||
|
|||||||
+153
-20
@@ -6,7 +6,7 @@
|
|||||||
/* the TRANSLATE keyword. */
|
/* the TRANSLATE keyword. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -34,6 +34,71 @@ typedef struct xlat {
|
|||||||
|
|
||||||
hash_table TranslationTable;
|
hash_table TranslationTable;
|
||||||
|
|
||||||
|
static XlateItem *FindTranslation(char const *orig);
|
||||||
|
static int printf_formatters_are_safe(char const *orig, char const *translated);
|
||||||
|
|
||||||
|
void
|
||||||
|
TranslationTemplate(char const *in)
|
||||||
|
{
|
||||||
|
if (!*in) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strcmp(in, "LANGID")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("TRANSLATE ");
|
||||||
|
print_escaped_string_helper(stdout, in, 1, 0);
|
||||||
|
if (FindTranslation(in)) {
|
||||||
|
printf(" ");
|
||||||
|
print_escaped_string_helper(stdout, tr(in), 1, 0);
|
||||||
|
printf("\n");
|
||||||
|
} else {
|
||||||
|
printf(" \"\"\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
GenerateTranslationTemplate(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
printf("# Translation table template\n\n");
|
||||||
|
|
||||||
|
printf("TRANSLATE \"LANGID\" ");
|
||||||
|
print_escaped_string_helper(stdout, tr("LANGID"), 1, 0);
|
||||||
|
printf("\n\n");
|
||||||
|
|
||||||
|
printf("BANNER %s\n", DBufValue(&Banner));
|
||||||
|
|
||||||
|
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, 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, 0);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n# Other Translation-related System Variables\n");
|
||||||
|
GenerateSysvarTranslationTemplates();
|
||||||
|
|
||||||
|
printf("\n# Error Messages\n");
|
||||||
|
for (i=0; i<NumErrs; i++) {
|
||||||
|
TranslationTemplate(ErrMsg[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n# Other Messages\n");
|
||||||
|
for (i=0; translatables[i] != NULL; i++) {
|
||||||
|
TranslationTemplate(translatables[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* AllocateXlateItem - Allocate a new translation item */
|
/* AllocateXlateItem - Allocate a new translation item */
|
||||||
@@ -113,6 +178,17 @@ ClearTranslationTable(void)
|
|||||||
void
|
void
|
||||||
print_escaped_string(FILE *fp, char const *s)
|
print_escaped_string(FILE *fp, char const *s)
|
||||||
{
|
{
|
||||||
|
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, int json) {
|
||||||
putc('"', fp);
|
putc('"', fp);
|
||||||
while(*s) {
|
while(*s) {
|
||||||
switch(*s) {
|
switch(*s) {
|
||||||
@@ -126,7 +202,20 @@ print_escaped_string(FILE *fp, char const *s)
|
|||||||
case '"': putc('\\', fp); putc('"', fp); break;
|
case '"': putc('\\', fp); putc('"', fp); break;
|
||||||
case '\\': putc('\\', fp); putc('\\', fp); break;
|
case '\\': putc('\\', fp); putc('\\', fp); break;
|
||||||
default:
|
default:
|
||||||
putc(*s, fp); break;
|
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 {
|
||||||
|
if (esc_for_remind && *s == '[') {
|
||||||
|
fprintf(fp, "[\"[\"]");
|
||||||
|
} else {
|
||||||
|
putc(*s, fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
@@ -171,9 +260,9 @@ DumpTranslationTable(FILE *fp, int json)
|
|||||||
fprintf(fp, ",");
|
fprintf(fp, ",");
|
||||||
}
|
}
|
||||||
done=1;
|
done=1;
|
||||||
print_escaped_string(fp, item->orig);
|
print_escaped_string_json(fp, item->orig);
|
||||||
fprintf(fp, ":");
|
fprintf(fp, ":");
|
||||||
print_escaped_string(fp, item->translated);
|
print_escaped_string_json(fp, item->translated);
|
||||||
}
|
}
|
||||||
item = hash_table_next(&TranslationTable, item);
|
item = hash_table_next(&TranslationTable, item);
|
||||||
}
|
}
|
||||||
@@ -202,7 +291,7 @@ InitTranslationTable(void)
|
|||||||
{
|
{
|
||||||
if (hash_table_init(&TranslationTable, offsetof(XlateItem, link),
|
if (hash_table_init(&TranslationTable, offsetof(XlateItem, link),
|
||||||
HashXlateItem, CompareXlateItems) < 0) {
|
HashXlateItem, CompareXlateItems) < 0) {
|
||||||
fprintf(stderr, "Unable to initialize translation hash table: Out of memory. Exiting.\n");
|
fprintf(ErrFp, "Unable to initialize translation hash table: Out of memory. Exiting.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
InsertTranslation("LANGID", "en");
|
InsertTranslation("LANGID", "en");
|
||||||
@@ -221,7 +310,13 @@ FindTranslation(char const *orig)
|
|||||||
int
|
int
|
||||||
InsertTranslation(char const *orig, char const *translated)
|
InsertTranslation(char const *orig, char const *translated)
|
||||||
{
|
{
|
||||||
XlateItem *item = FindTranslation(orig);
|
XlateItem *item;
|
||||||
|
|
||||||
|
if (!printf_formatters_are_safe(orig, translated)) {
|
||||||
|
Eprint(tr("Invalid translation: Both original and translated must have the same printf-style formatting sequences in the same order."));
|
||||||
|
return E_PARSE_ERR;
|
||||||
|
}
|
||||||
|
item = FindTranslation(orig);
|
||||||
if (item) {
|
if (item) {
|
||||||
if (!strcmp(item->translated, translated)) {
|
if (!strcmp(item->translated, translated)) {
|
||||||
/* Translation is the same; do nothing */
|
/* Translation is the same; do nothing */
|
||||||
@@ -230,7 +325,6 @@ InsertTranslation(char const *orig, char const *translated)
|
|||||||
RemoveTranslation(item);
|
RemoveTranslation(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TRANSLATE "foo" "foo" means to remove the translation */
|
|
||||||
if (strcmp(orig, "LANGID") && (!strcmp(orig, translated))) {
|
if (strcmp(orig, "LANGID") && (!strcmp(orig, translated))) {
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -313,7 +407,7 @@ GetTranslatedStringTryingVariants(char const *orig, DynamicBuffer *out)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char const *t(char const *orig)
|
char const *tr(char const *orig)
|
||||||
{
|
{
|
||||||
char const *n = GetTranslatedString(orig);
|
char const *n = GetTranslatedString(orig);
|
||||||
if (n) {
|
if (n) {
|
||||||
@@ -322,12 +416,6 @@ char const *t(char const *orig)
|
|||||||
return orig;
|
return orig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If another "t" is in scope... */
|
|
||||||
char const *tr(char const *orig)
|
|
||||||
{
|
|
||||||
return t(orig);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
DoTranslate(ParsePtr p)
|
DoTranslate(ParsePtr p)
|
||||||
{
|
{
|
||||||
@@ -359,6 +447,12 @@ DoTranslate(ParsePtr p)
|
|||||||
ClearTranslationTable();
|
ClearTranslationTable();
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
if (!StrCmpi(DBufValue(&orig), "generate")) {
|
||||||
|
DBufFree(&orig);
|
||||||
|
if (r) return r;
|
||||||
|
GenerateTranslationTemplate();
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
return E_PARSE_ERR;
|
return E_PARSE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,12 +486,51 @@ DoTranslate(ParsePtr p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
get_translation_hash_stats(int *total, int *maxlen, double *avglen)
|
dump_translation_hash_stats(void)
|
||||||
{
|
{
|
||||||
struct hash_table_stats s;
|
hash_table_dump_stats(&TranslationTable, ErrFp);
|
||||||
hash_table_get_stats(&TranslationTable, &s);
|
|
||||||
*total = s.num_entries;
|
|
||||||
*maxlen = s.max_len;
|
|
||||||
*avglen = s.avg_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_printf_escapes(char const *str, DynamicBuffer *out)
|
||||||
|
{
|
||||||
|
char const *s = str;
|
||||||
|
while(*s) {
|
||||||
|
if (*s == '%' && *(s+1) != 0) {
|
||||||
|
|
||||||
|
/* %% is safe and does not need to be replicated in translation */
|
||||||
|
if (*(s+1) == '%') {
|
||||||
|
s += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
DBufPutc(out, *s);
|
||||||
|
while (*s && *(s+1) && strchr("#0- +'I%123456789.hlqLjzZt", *s)) {
|
||||||
|
s++;
|
||||||
|
DBufPutc(out, *s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
printf_formatters_are_safe(char const *orig, char const *translated)
|
||||||
|
{
|
||||||
|
DynamicBuffer origEscapes;
|
||||||
|
DynamicBuffer translatedEscapes;
|
||||||
|
int dangerous;
|
||||||
|
|
||||||
|
DBufInit(&origEscapes);
|
||||||
|
DBufInit(&translatedEscapes);
|
||||||
|
|
||||||
|
get_printf_escapes(orig, &origEscapes);
|
||||||
|
get_printf_escapes(translated, &translatedEscapes);
|
||||||
|
|
||||||
|
dangerous = strcmp(DBufValue(&origEscapes), DBufValue(&translatedEscapes));
|
||||||
|
|
||||||
|
if (dangerous) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|||||||
+161
-12
@@ -5,15 +5,16 @@
|
|||||||
/* Routines for figuring out the trigger date of a reminder */
|
/* Routines for figuring out the trigger date of a reminder */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
@@ -451,8 +452,8 @@ AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int sav
|
|||||||
r = today;
|
r = today;
|
||||||
if (DebugFlag & DB_PRTTRIG) {
|
if (DebugFlag & DB_PRTTRIG) {
|
||||||
FromDSE(r, &y, &m, &d);
|
FromDSE(r, &y, &m, &d);
|
||||||
fprintf(ErrFp, "%s(%d): Trig(adj) = %s, %d %s, %d",
|
fprintf(ErrFp, "%s(%s): Trig(adj) = %s, %d %s, %d",
|
||||||
FileName, LineNo,
|
FileName, line_range(LineNoStart, LineNo),
|
||||||
get_day_name(r % 7),
|
get_day_name(r % 7),
|
||||||
d,
|
d,
|
||||||
get_month_name(m),
|
get_month_name(m),
|
||||||
@@ -579,8 +580,8 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
|
|||||||
if (result == -1) {
|
if (result == -1) {
|
||||||
trig->expired = 1;
|
trig->expired = 1;
|
||||||
if (DebugFlag & DB_PRTTRIG) {
|
if (DebugFlag & DB_PRTTRIG) {
|
||||||
fprintf(ErrFp, "%s(%d): %s\n",
|
fprintf(ErrFp, "%s(%s): %s\n",
|
||||||
FileName, LineNo, GetErr(E_EXPIRED));
|
FileName, line_range(LineNoStart, LineNo), GetErr(E_EXPIRED));
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -602,8 +603,8 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
|
|||||||
}
|
}
|
||||||
if (DebugFlag & DB_PRTTRIG) {
|
if (DebugFlag & DB_PRTTRIG) {
|
||||||
FromDSE(result, &y, &m, &d);
|
FromDSE(result, &y, &m, &d);
|
||||||
fprintf(ErrFp, "%s(%d): Trig = %s, %d %s, %d",
|
fprintf(ErrFp, "%s(%s): Trig = %s, %d %s, %d",
|
||||||
FileName, LineNo,
|
FileName, line_range(LineNoStart, LineNo),
|
||||||
get_day_name(result % 7),
|
get_day_name(result % 7),
|
||||||
d,
|
d,
|
||||||
get_month_name(m),
|
get_month_name(m),
|
||||||
@@ -629,8 +630,8 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
|
|||||||
trig->rep == NO_REP) {
|
trig->rep == NO_REP) {
|
||||||
trig->expired = 1;
|
trig->expired = 1;
|
||||||
if (DebugFlag & DB_PRTTRIG) {
|
if (DebugFlag & DB_PRTTRIG) {
|
||||||
fprintf(ErrFp, "%s(%d): %s\n",
|
fprintf(ErrFp, "%s(%s): %s\n",
|
||||||
FileName, LineNo, GetErr(E_EXPIRED));
|
FileName, line_range(LineNoStart, LineNo), GetErr(E_EXPIRED));
|
||||||
}
|
}
|
||||||
if (save_in_globals) {
|
if (save_in_globals) {
|
||||||
LastTriggerDate = result;
|
LastTriggerDate = result;
|
||||||
@@ -654,8 +655,8 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
|
|||||||
}
|
}
|
||||||
trig->expired = 1;
|
trig->expired = 1;
|
||||||
if (DebugFlag & DB_PRTTRIG) {
|
if (DebugFlag & DB_PRTTRIG) {
|
||||||
fprintf(ErrFp, "%s(%d): %s\n",
|
fprintf(ErrFp, "%s(%s): %s\n",
|
||||||
FileName, LineNo, GetErr(E_EXPIRED));
|
FileName, line_range(LineNoStart, LineNo), GetErr(E_EXPIRED));
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -668,3 +669,151 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
|
|||||||
return -1;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
+32
-23
@@ -5,7 +5,7 @@
|
|||||||
/* Type definitions all dumped here. */
|
/* Type definitions all dumped here. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -58,7 +58,7 @@ enum expr_node_type
|
|||||||
N_SHORT_USER_FUNC,
|
N_SHORT_USER_FUNC,
|
||||||
N_USER_FUNC,
|
N_USER_FUNC,
|
||||||
N_OPERATOR,
|
N_OPERATOR,
|
||||||
N_ERROR = 32767,
|
N_ERROR = 0x7FFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Structure for passing in Nargs and out RetVal from functions */
|
/* Structure for passing in Nargs and out RetVal from functions */
|
||||||
@@ -107,6 +107,11 @@ typedef struct var {
|
|||||||
Value v;
|
Value v;
|
||||||
} Var;
|
} Var;
|
||||||
|
|
||||||
|
typedef struct triginfo {
|
||||||
|
struct triginfo *next;
|
||||||
|
char const *info;
|
||||||
|
} TrigInfo;
|
||||||
|
|
||||||
/* A trigger */
|
/* A trigger */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int expired;
|
int expired;
|
||||||
@@ -138,6 +143,7 @@ typedef struct {
|
|||||||
char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */
|
char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */
|
||||||
DynamicBuffer tags;
|
DynamicBuffer tags;
|
||||||
char passthru[PASSTHRU_LEN+1];
|
char passthru[PASSTHRU_LEN+1];
|
||||||
|
TrigInfo *infos;
|
||||||
} Trigger;
|
} Trigger;
|
||||||
|
|
||||||
/* A time trigger */
|
/* A time trigger */
|
||||||
@@ -200,13 +206,15 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
|
|||||||
#define NO_MAX 127
|
#define NO_MAX 127
|
||||||
|
|
||||||
/* DEFINES for debugging flags */
|
/* DEFINES for debugging flags */
|
||||||
#define DB_PRTLINE 1
|
#define DB_PRTLINE 0x001
|
||||||
#define DB_PRTEXPR 2
|
#define DB_PRTEXPR 0x002
|
||||||
#define DB_PRTTRIG 4
|
#define DB_PRTTRIG 0x004
|
||||||
#define DB_DUMP_VARS 8
|
#define DB_DUMP_VARS 0x008
|
||||||
#define DB_ECHO_LINE 16
|
#define DB_ECHO_LINE 0x010
|
||||||
#define DB_TRACE_FILES 32
|
#define DB_TRACE_FILES 0x020
|
||||||
#define DB_PARSE_EXPR 64
|
#define DB_PARSE_EXPR 0x040
|
||||||
|
#define DB_HASHSTATS 0x080
|
||||||
|
#define DB_TRANSLATE 0x100
|
||||||
|
|
||||||
/* Enumeration of the tokens */
|
/* Enumeration of the tokens */
|
||||||
enum TokTypes
|
enum TokTypes
|
||||||
@@ -215,9 +223,9 @@ enum TokTypes
|
|||||||
T_Date, T_DateTime, T_Day, T_Debug, T_Delta, T_Dumpvars, T_Duration,
|
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_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_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_Include, T_IncludeCmd, T_IncludeR, T_IncludeSys, T_Info, T_LastBack,
|
||||||
T_MaybeUncomputable, T_Month, T_NoQueue, T_Number, T_Omit, T_OmitFunc,
|
T_LongTime, T_MaybeUncomputable, T_Month, T_NoQueue, T_Number, T_Omit,
|
||||||
T_Once, T_Ordinal, T_Pop, T_Preserve, T_Priority, T_Push,T_Rem,
|
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_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
|
T_Time, T_Translate, T_UnSet, T_Until, T_Warn, T_WkDay, T_Year
|
||||||
};
|
};
|
||||||
@@ -231,13 +239,13 @@ typedef struct {
|
|||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
/* Flags for the state of the "if" stack */
|
/* Flags for the state of the "if" stack */
|
||||||
#define IF_TRUE 0
|
#define IF_TRUE 0x00
|
||||||
#define IF_FALSE 1
|
#define IF_FALSE 0x01
|
||||||
#define BEFORE_ELSE 0
|
#define BEFORE_ELSE 0x00
|
||||||
#define AFTER_ELSE 2
|
#define AFTER_ELSE 0x02
|
||||||
#define IF_MASK 3
|
#define IF_MASK 0x03
|
||||||
#define IF_TRUE_MASK 1
|
#define IF_TRUE_MASK 0x01
|
||||||
#define IF_ELSE_MASK 2
|
#define IF_ELSE_MASK 0x02
|
||||||
|
|
||||||
/* Flags for the DoSubst function */
|
/* Flags for the DoSubst function */
|
||||||
#define NORMAL_MODE 0
|
#define NORMAL_MODE 0
|
||||||
@@ -247,9 +255,9 @@ typedef struct {
|
|||||||
#define QUOTE_MARKER 1 /* Unlikely character to appear in reminder */
|
#define QUOTE_MARKER 1 /* Unlikely character to appear in reminder */
|
||||||
|
|
||||||
/* Flags for disabling run */
|
/* Flags for disabling run */
|
||||||
#define RUN_CMDLINE 1
|
#define RUN_CMDLINE 0x01
|
||||||
#define RUN_SCRIPT 2
|
#define RUN_SCRIPT 0x02
|
||||||
#define RUN_NOTOWNER 4
|
#define RUN_NOTOWNER 0x04
|
||||||
|
|
||||||
/* Flags for the SimpleCalendar format */
|
/* Flags for the SimpleCalendar format */
|
||||||
#define SC_AMPM 0 /* Time shown as 3:00am, etc. */
|
#define SC_AMPM 0 /* Time shown as 3:00am, etc. */
|
||||||
@@ -286,7 +294,7 @@ typedef struct {
|
|||||||
char const *name;
|
char const *name;
|
||||||
char modifiable;
|
char modifiable;
|
||||||
int type;
|
int type;
|
||||||
void const *value;
|
void *value;
|
||||||
int min; /* Or const-value */
|
int min; /* Or const-value */
|
||||||
int max;
|
int max;
|
||||||
} SysVar;
|
} SysVar;
|
||||||
@@ -300,5 +308,6 @@ typedef struct udf_struct {
|
|||||||
int nargs;
|
int nargs;
|
||||||
char const *filename;
|
char const *filename;
|
||||||
int lineno;
|
int lineno;
|
||||||
|
int lineno_start;
|
||||||
int recurse_flag;
|
int recurse_flag;
|
||||||
} UserFunc;
|
} UserFunc;
|
||||||
|
|||||||
+8
-11
@@ -6,7 +6,7 @@
|
|||||||
/* functions. */
|
/* functions. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -56,7 +56,7 @@ InitUserFunctions(void)
|
|||||||
offsetof(UserFunc, link),
|
offsetof(UserFunc, link),
|
||||||
HashUserFunc,
|
HashUserFunc,
|
||||||
CompareUserFuncs) < 0) {
|
CompareUserFuncs) < 0) {
|
||||||
fprintf(stderr, "Unable to initialize function hash table: Out of memory. Exiting.\n");
|
fprintf(ErrFp, "Unable to initialize function hash table: Out of memory. Exiting.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,8 +208,8 @@ int DoFset(ParsePtr p)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
/* Warn about redefinition */
|
/* Warn about redefinition */
|
||||||
Wprint("Function %s redefined (previously defined at %s:%d)",
|
Wprint(tr("Function `%s' redefined: previously defined at %s(%s)"),
|
||||||
existing->name, existing->filename, existing->lineno);
|
existing->name, existing->filename, line_range(existing->lineno_start, existing->lineno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Should be followed by '(' */
|
/* Should be followed by '(' */
|
||||||
@@ -238,6 +238,7 @@ int DoFset(ParsePtr p)
|
|||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
func->lineno = LineNo;
|
func->lineno = LineNo;
|
||||||
|
func->lineno_start = LineNoStart;
|
||||||
func->recurse_flag = 0;
|
func->recurse_flag = 0;
|
||||||
StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN);
|
StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
@@ -352,7 +353,7 @@ int DoFset(ParsePtr p)
|
|||||||
/* Add the function definition */
|
/* Add the function definition */
|
||||||
FSet(func);
|
FSet(func);
|
||||||
if (orig_namelen > VAR_NAME_LEN) {
|
if (orig_namelen > VAR_NAME_LEN) {
|
||||||
Wprint("Warning: Function name `%s...' truncated to `%s'",
|
Wprint(tr("Warning: Function name `%s...' truncated to `%s'"),
|
||||||
func->name, func->name);
|
func->name, func->name);
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
@@ -506,12 +507,8 @@ RenameUserFunc(char const *oldname, char const *newname)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
get_userfunc_hash_stats(int *total, int *maxlen, double *avglen)
|
dump_userfunc_hash_stats(void)
|
||||||
{
|
{
|
||||||
struct hash_table_stats s;
|
hash_table_dump_stats(&FuncHash, ErrFp);
|
||||||
hash_table_get_stats(&FuncHash, &s);
|
|
||||||
*total = s.num_entries;
|
|
||||||
*maxlen = s.max_len;
|
|
||||||
*avglen = s.avg_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+24
-12
@@ -5,7 +5,7 @@
|
|||||||
/* Useful utility functions. */
|
/* Useful utility functions. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -192,6 +192,7 @@ typedef struct cs_s {
|
|||||||
char const *filename;
|
char const *filename;
|
||||||
char const *func;
|
char const *func;
|
||||||
int lineno;
|
int lineno;
|
||||||
|
int lineno_start;
|
||||||
} cs;
|
} cs;
|
||||||
|
|
||||||
static cs *callstack = NULL;
|
static cs *callstack = NULL;
|
||||||
@@ -206,7 +207,7 @@ destroy_cs(cs *entry)
|
|||||||
|
|
||||||
|
|
||||||
int
|
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;
|
cs *entry;
|
||||||
if (freecs) {
|
if (freecs) {
|
||||||
@@ -222,6 +223,7 @@ push_call(char const *filename, char const *func, int lineno)
|
|||||||
entry->filename = filename;
|
entry->filename = filename;
|
||||||
entry->func = func;
|
entry->func = func;
|
||||||
entry->lineno = lineno;
|
entry->lineno = lineno;
|
||||||
|
entry->lineno_start = lineno_start;
|
||||||
entry->next = callstack;
|
entry->next = callstack;
|
||||||
callstack = entry;
|
callstack = entry;
|
||||||
return OK;
|
return OK;
|
||||||
@@ -244,17 +246,18 @@ static void
|
|||||||
print_callstack_aux(FILE *fp, cs *entry)
|
print_callstack_aux(FILE *fp, cs *entry)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
char const *in = "In";
|
char const *in = tr("In");
|
||||||
cs *prev = NULL;
|
cs *prev = NULL;
|
||||||
while(entry) {
|
while(entry) {
|
||||||
if (prev) {
|
if (prev) {
|
||||||
in = "Called from";
|
in = tr("Called from");
|
||||||
}
|
}
|
||||||
if (!prev || strcmp(prev->func, entry->func) || strcmp(prev->filename, entry->filename) || prev->lineno != entry->lineno) {
|
if (!prev || strcmp(prev->func, entry->func) || strcmp(prev->filename, entry->filename) || prev->lineno != entry->lineno) {
|
||||||
if (prev) {
|
if (prev) {
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
}
|
}
|
||||||
(void) fprintf(fp, " %s(%d): [#%d] %s function `%s'", entry->filename, entry->lineno, i, in, entry->func);
|
fprintf(fp, " ");
|
||||||
|
fprintf(fp, tr("%s(%s): [#%d] %s function `%s'"), entry->filename, line_range(entry->lineno_start, entry->lineno), i, in, entry->func);
|
||||||
}
|
}
|
||||||
prev = entry;
|
prev = entry;
|
||||||
entry = entry->next;
|
entry = entry->next;
|
||||||
@@ -264,14 +267,11 @@ print_callstack_aux(FILE *fp, cs *entry)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entry) {
|
if (entry) {
|
||||||
(void) fprintf(fp, "\n [remaining call frames omitted]");
|
(void) fprintf(fp, "\n [");
|
||||||
}
|
(void) fprintf(fp, "%s", tr("remaining call frames omitted"));
|
||||||
}
|
(void) fprintf(fp, "]");
|
||||||
|
|
||||||
int
|
}
|
||||||
have_callstack(void)
|
|
||||||
{
|
|
||||||
return (callstack != NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -291,3 +291,15 @@ pop_call(void)
|
|||||||
destroy_cs(entry);
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* user- and system-defined variables. */
|
/* user- and system-defined variables. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 1992-2025 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -56,7 +56,7 @@ InitVars(void)
|
|||||||
{
|
{
|
||||||
if (hash_table_init(&VHashTbl, offsetof(Var, link),
|
if (hash_table_init(&VHashTbl, offsetof(Var, link),
|
||||||
VarHashFunc, VarCompareFunc) < 0) {
|
VarHashFunc, VarCompareFunc) < 0) {
|
||||||
fprintf(stderr, "Unable to initialize variable hash table: Out of memory. Exiting.\n");
|
fprintf(ErrFp, "Unable to initialize variable hash table: Out of memory. Exiting.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ strtod_in_c_locale(char const *str, char **endptr)
|
|||||||
if (**endptr) {
|
if (**endptr) {
|
||||||
x = strtod(str, endptr);
|
x = strtod(str, endptr);
|
||||||
if (!**endptr) {
|
if (!**endptr) {
|
||||||
Wprint("Accepting \"%s\" for $Latitude/$Longitude, but you should use the \"C\" locale decimal separator \".\" instead", str);
|
Wprint(tr("Accepting \"%s\" for $Latitude/$Longitude, but you should use the \"C\" locale decimal separator \".\" instead"), str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
@@ -94,7 +94,7 @@ strtod_in_c_locale(char const *str, char **endptr)
|
|||||||
static void deprecated_var(char const *var, char const *instead)
|
static void deprecated_var(char const *var, char const *instead)
|
||||||
{
|
{
|
||||||
if (DebugFlag & DB_PRTLINE) {
|
if (DebugFlag & DB_PRTLINE) {
|
||||||
Wprint("%s is deprecated; use %s instead", var, instead);
|
Wprint(tr("%s is deprecated; use %s instead"), var, instead);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ static int oncefile_func(int do_set, Value *val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ProcessedOnce) {
|
if (ProcessedOnce) {
|
||||||
Wprint("Not setting $OnceFile: Already processed a reminder with a ONCE clause");
|
Wprint(tr("Not setting $OnceFile: Already processed a reminder with a ONCE clause"));
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
if (OnceFile) {
|
if (OnceFile) {
|
||||||
@@ -608,7 +608,7 @@ int DoSet (Parser *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (p->isnested) {
|
if (p->isnested) {
|
||||||
Eprint("%s", "Do not use [] around expression in SET command");
|
Eprint("%s", tr("Do not use [] around expression in SET command"));
|
||||||
return E_CANTNEST_FDEF;
|
return E_CANTNEST_FDEF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,7 +628,7 @@ int DoSet (Parser *p)
|
|||||||
if (*DBufValue(&buf) == '$') r = SetSysVar(DBufValue(&buf)+1, &v);
|
if (*DBufValue(&buf) == '$') r = SetSysVar(DBufValue(&buf)+1, &v);
|
||||||
else r = SetVar(DBufValue(&buf), &v);
|
else r = SetVar(DBufValue(&buf), &v);
|
||||||
if (buf.len > VAR_NAME_LEN) {
|
if (buf.len > VAR_NAME_LEN) {
|
||||||
Wprint("Warning: Variable name `%.*s...' truncated to `%.*s'",
|
Wprint(tr("Warning: Variable name `%.*s...' truncated to `%.*s'"),
|
||||||
VAR_NAME_LEN, DBufValue(&buf), VAR_NAME_LEN, DBufValue(&buf));
|
VAR_NAME_LEN, DBufValue(&buf), VAR_NAME_LEN, DBufValue(&buf));
|
||||||
}
|
}
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
@@ -723,7 +723,7 @@ int DoDump(ParsePtr p)
|
|||||||
/* */
|
/* */
|
||||||
/* DumpVarTable */
|
/* DumpVarTable */
|
||||||
/* */
|
/* */
|
||||||
/* Dump the variable table to stderr. */
|
/* Dump the variable table to ErrFp. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
void DumpVarTable(void)
|
void DumpVarTable(void)
|
||||||
@@ -853,6 +853,7 @@ static SysVar SysVarArr[] = {
|
|||||||
{"August", 1, TRANS_TYPE, "August", 0, 0 },
|
{"August", 1, TRANS_TYPE, "August", 0, 0 },
|
||||||
{"CalcUTC", 1, INT_TYPE, &CalculateUTC, 0, 1 },
|
{"CalcUTC", 1, INT_TYPE, &CalculateUTC, 0, 1 },
|
||||||
{"CalMode", 0, INT_TYPE, &DoCalendar, 0, 0 },
|
{"CalMode", 0, INT_TYPE, &DoCalendar, 0, 0 },
|
||||||
|
{"CalType", 0, STR_TYPE, &CalType, 0, 0 },
|
||||||
{"Daemon", 0, INT_TYPE, &Daemon, 0, 0 },
|
{"Daemon", 0, INT_TYPE, &Daemon, 0, 0 },
|
||||||
{"DateSep", 1, SPECIAL_TYPE, date_sep_func, 0, 0 },
|
{"DateSep", 1, SPECIAL_TYPE, date_sep_func, 0, 0 },
|
||||||
{"DateTimeSep", 1, SPECIAL_TYPE, datetime_sep_func, 0, 0 },
|
{"DateTimeSep", 1, SPECIAL_TYPE, datetime_sep_func, 0, 0 },
|
||||||
@@ -861,7 +862,7 @@ static SysVar SysVarArr[] = {
|
|||||||
{"DefaultColor", 1, SPECIAL_TYPE, default_color_func, 0, 0 },
|
{"DefaultColor", 1, SPECIAL_TYPE, default_color_func, 0, 0 },
|
||||||
{"DefaultDelta", 1, INT_TYPE, &DefaultDelta, 0, 10000 },
|
{"DefaultDelta", 1, INT_TYPE, &DefaultDelta, 0, 10000 },
|
||||||
{"DefaultPrio", 1, INT_TYPE, &DefaultPrio, 0, 9999 },
|
{"DefaultPrio", 1, INT_TYPE, &DefaultPrio, 0, 9999 },
|
||||||
{"DefaultTDelta", 1, INT_TYPE, &DefaultTDelta, 0, 1440 },
|
{"DefaultTDelta", 1, INT_TYPE, &DefaultTDelta, 0, MINUTES_PER_DAY },
|
||||||
{"DeltaOverride", 0, INT_TYPE, &DeltaOverride, 0, 0 },
|
{"DeltaOverride", 0, INT_TYPE, &DeltaOverride, 0, 0 },
|
||||||
{"DontFork", 0, INT_TYPE, &DontFork, 0, 0 },
|
{"DontFork", 0, INT_TYPE, &DontFork, 0, 0 },
|
||||||
{"DontQueue", 0, INT_TYPE, &DontQueue, 0, 0 },
|
{"DontQueue", 0, INT_TYPE, &DontQueue, 0, 0 },
|
||||||
@@ -897,7 +898,7 @@ static SysVar SysVarArr[] = {
|
|||||||
{"LongSec", 1, SPECIAL_TYPE, longsec_func, 0, 0 },
|
{"LongSec", 1, SPECIAL_TYPE, longsec_func, 0, 0 },
|
||||||
{"March", 1, TRANS_TYPE, "March", 0, 0 },
|
{"March", 1, TRANS_TYPE, "March", 0, 0 },
|
||||||
{"MaxFullOmits", 0, CONST_INT_TYPE, NULL, MAX_FULL_OMITS, 0},
|
{"MaxFullOmits", 0, CONST_INT_TYPE, NULL, MAX_FULL_OMITS, 0},
|
||||||
{"MaxLateMinutes", 1, INT_TYPE, &MaxLateMinutes, 0, 1440 },
|
{"MaxLateMinutes", 1, INT_TYPE, &MaxLateMinutes, 0, MINUTES_PER_DAY },
|
||||||
{"MaxPartialOmits",0, CONST_INT_TYPE, NULL, MAX_PARTIAL_OMITS, 0},
|
{"MaxPartialOmits",0, CONST_INT_TYPE, NULL, MAX_PARTIAL_OMITS, 0},
|
||||||
{"MaxSatIter", 1, INT_TYPE, &MaxSatIter, 10, ANY },
|
{"MaxSatIter", 1, INT_TYPE, &MaxSatIter, 10, ANY },
|
||||||
{"MaxStringLen", 1, INT_TYPE, &MaxStringLen, -1, ANY },
|
{"MaxStringLen", 1, INT_TYPE, &MaxStringLen, -1, ANY },
|
||||||
@@ -968,7 +969,7 @@ static int SetTranslatableVariable(SysVar *v, Value *value)
|
|||||||
|
|
||||||
static int GetTranslatableVariable(SysVar *v, Value *value)
|
static int GetTranslatableVariable(SysVar *v, Value *value)
|
||||||
{
|
{
|
||||||
char const *translated = t((char const *) v->value);
|
char const *translated = tr((char const *) v->value);
|
||||||
if (translated) {
|
if (translated) {
|
||||||
value->v.str = StrDup(translated);
|
value->v.str = StrDup(translated);
|
||||||
} else {
|
} else {
|
||||||
@@ -1005,7 +1006,7 @@ static int SetSysVarHelper(SysVar *v, Value *value)
|
|||||||
|
|
||||||
if (v->type == STR_TYPE) {
|
if (v->type == STR_TYPE) {
|
||||||
/* If it's already the same, don't bother doing anything */
|
/* If it's already the same, don't bother doing anything */
|
||||||
if (!strcmp(value->v.str, (char const *) v->value)) {
|
if (!strcmp(value->v.str, * (char const **) v->value)) {
|
||||||
DestroyValue(*value);
|
DestroyValue(*value);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -1077,7 +1078,7 @@ int GetSysVar(char const *name, Value *val)
|
|||||||
/* In "verbose" mode, print attempts to test $RunOff */
|
/* In "verbose" mode, print attempts to test $RunOff */
|
||||||
if (DebugFlag & DB_PRTLINE) {
|
if (DebugFlag & DB_PRTLINE) {
|
||||||
if (v->value == (void *) &RunDisabled) {
|
if (v->value == (void *) &RunDisabled) {
|
||||||
Wprint("(Security note: $RunOff variable tested.)");
|
Wprint(tr("(Security note: $RunOff variable tested.)"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
@@ -1238,6 +1239,46 @@ set_components_from_lat_and_long(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GenerateSysvarTranslationTemplates(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
char const *msg;
|
||||||
|
for (i=0; i< (int) NUMSYSVARS; i++) {
|
||||||
|
if (SysVarArr[i].type == TRANS_TYPE) {
|
||||||
|
int done=0;
|
||||||
|
msg = (char const *) SysVarArr[i].value;
|
||||||
|
/* We've already done month and day names */
|
||||||
|
for (j=0; j<7; j++) {
|
||||||
|
if (!strcmp(msg, DayName[j])) {
|
||||||
|
done=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (done) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (j=0; j<12; j++) {
|
||||||
|
if (!strcmp(msg, MonthName[j])) {
|
||||||
|
done=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (done) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf("SET $%s ", SysVarArr[i].name);
|
||||||
|
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, 0);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
void
|
void
|
||||||
print_sysvar_tokens(void)
|
print_sysvar_tokens(void)
|
||||||
{
|
{
|
||||||
@@ -1249,11 +1290,7 @@ print_sysvar_tokens(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
get_var_hash_stats(int *total, int *maxlen, double *avglen)
|
dump_var_hash_stats(void)
|
||||||
{
|
{
|
||||||
struct hash_table_stats s;
|
hash_table_dump_stats(&VHashTbl, ErrFp);
|
||||||
hash_table_get_stats(&VHashTbl, &s);
|
|
||||||
*total = s.num_entries;
|
|
||||||
*maxlen = s.max_len;
|
|
||||||
*avglen = s.avg_len;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
debug +sx
|
debug +hsx
|
||||||
|
|
||||||
set a 1
|
set a 1
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
FSET msgprefix(x) "Priority: " + x + "; Filename: " + filename() + ": "
|
FSET msgprefix(x) "Priority: " + x + "; Filename: " + filename() + ": "
|
||||||
|
|
||||||
REM at 23:56 MSG foo
|
REM at 23:56 MSG foo
|
||||||
REM PRIORITY 42 at 23:57 MSG bar
|
REM PRIORITY 42 at 23:57 INFO "Info: yuppers" MSG bar
|
||||||
REM PRIORITY 999 at 23:58 MSG quux
|
REM PRIORITY 999 at 23:58 INFO "Info2: Nope" INFO "Info3: heh" MSG quux
|
||||||
DO queue2.rem
|
DO queue2.rem
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
SET $LatDeg 45
|
|
||||||
SET $LatMin 24
|
|
||||||
SET $LatSec 0
|
|
||||||
SET $LongDeg 75
|
|
||||||
SET $LongMin 39
|
|
||||||
SET $LongSec 0
|
|
||||||
SET $MinsFromUTC -300
|
|
||||||
SET $CalcUTC 0
|
|
||||||
|
|
||||||
MSG Dawn: [dawn()]
|
|
||||||
MSG Sunrise: [sunrise()]
|
|
||||||
MSG Sunset: [sunset()]
|
|
||||||
MSG Dusk: [dusk()]
|
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
set $AddBlankLines 0
|
||||||
|
banner %
|
||||||
|
|
||||||
|
set d '2011-01-01'
|
||||||
|
set x adawn(d)
|
||||||
|
if x < 5:53 || x > 5:57
|
||||||
|
REM MSG adawn() is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x dawn(d)
|
||||||
|
if x < 7:06 || x > 7:10
|
||||||
|
REM MSG dawn() is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x sunrise(d)
|
||||||
|
if x < 7:40 || x > 7:44
|
||||||
|
REM MSG sunrise() is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x sunset(d)
|
||||||
|
if x < 16:28 || x > 16:32
|
||||||
|
REM MSG sunset() is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x dusk(d)
|
||||||
|
if x < 17:02 || x > 17:06
|
||||||
|
REM MSG dusk() is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x adusk(d)
|
||||||
|
if x < 18:15 || x > 18:19
|
||||||
|
REM MSG adusk() is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x moonrise(d)
|
||||||
|
if x < '2011-01-01@5:14' || x > '2011-01-01@5:18'
|
||||||
|
REM MSG moonrise() is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x moonset(d)
|
||||||
|
if x < '2011-01-01@13:59' || x > '2011-01-01@14:03'
|
||||||
|
REM MSG moonset() is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x moonphase(d, 0:00)
|
||||||
|
if x < 319 || x > 323
|
||||||
|
REM MSG moonphase() is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x moondatetime(0, d, 0:00)
|
||||||
|
if x < '2011-01-04@04:02' || x > '2011-01-04@04:06'
|
||||||
|
REM MSG moondatetime(0) is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x moondatetime(1, d, 0:00)
|
||||||
|
if x < '2011-01-12@06:31' || x > '2011-01-12@06:35'
|
||||||
|
REM MSG moondatetime(1) is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x moondatetime(2, d, 0:00)
|
||||||
|
if x < '2011-01-19@16:20' || x > '2011-01-19@16:24'
|
||||||
|
REM MSG moondatetime(2) is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x moondatetime(3, d, 0:00)
|
||||||
|
if x < '2011-01-26@07:57' || x > '2011-01-26@08:01'
|
||||||
|
REM MSG moondatetime(3) is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x soleq(0, 2011)
|
||||||
|
if x < '2011-03-20@19:18' || x > '2011-03-20@19:22'
|
||||||
|
REM MSG soleq(0) is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x soleq(1, 2011)
|
||||||
|
if x < '2011-06-21@13:14' || x > '2011-06-21@13:18'
|
||||||
|
REM MSG soleq(1) is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x soleq(2, 2011)
|
||||||
|
if x < '2011-09-23@05:02' || x > '2011-09-23@05:06'
|
||||||
|
REM MSG soleq(2) is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
set x soleq(3, 2011)
|
||||||
|
if x < '2011-12-22@00:28' || x > '2011-12-22@00:32'
|
||||||
|
REM MSG soleq(3) is inaccurate! - [x]
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
if $NumTrig == 0
|
||||||
|
REM MSG All astronomical functions look OK
|
||||||
|
endif
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user