mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-17 23:08:40 +02:00
Compare commits
274 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e33bf4e80a | ||
|
|
b3af44d212 | ||
|
|
1e753d5209 | ||
|
|
4bf31005ea | ||
|
|
7c86bc910a | ||
|
|
4f146a99a9 | ||
|
|
a6a638e0e6 | ||
|
|
325814f5e1 | ||
|
|
5c4ea7d09e | ||
|
|
2bf73987ac | ||
|
|
3e9eeea8dc | ||
|
|
d164d72c1c | ||
|
|
632cee62d9 | ||
|
|
7a40260f0d | ||
|
|
09f043b3de | ||
|
|
c0341c8ba3 | ||
|
|
850c717803 | ||
|
|
f13f9e18bd | ||
|
|
8bdca0d684 | ||
|
|
129bf5612e | ||
|
|
829962fae1 | ||
|
|
c5f9ed8541 | ||
|
|
4a7cef4644 | ||
|
|
0e010b56ec | ||
|
|
ee179ee2f5 | ||
|
|
e28712cef3 | ||
|
|
8f0a2a7e79 | ||
|
|
ef23bba77f | ||
|
|
602086ae2d | ||
|
|
f5a170acbd | ||
|
|
8125b96f0b | ||
|
|
0bb7d89bb9 | ||
|
|
eb109bbbc0 | ||
|
|
1a0809fd31 | ||
|
|
09625b9d68 | ||
|
|
4e164c4268 | ||
|
|
691185f22c | ||
|
|
a8bfb41a9e | ||
|
|
fafb30db05 | ||
|
|
243e816523 | ||
|
|
b49c0f52bd | ||
|
|
07fca94a7f | ||
|
|
73917ee537 | ||
|
|
76f9edecf6 | ||
|
|
d77d9854d2 | ||
|
|
c2b53f95a4 | ||
|
|
caef8b80d6 | ||
|
|
5e016768af | ||
|
|
ee08ce98d7 | ||
|
|
581bd95838 | ||
|
|
bb92dab1ab | ||
|
|
83b5c52c76 | ||
|
|
93eca25141 | ||
|
|
34421cb10e | ||
|
|
29b87898aa | ||
|
|
e9e4db94bd | ||
|
|
c95ad0261a | ||
|
|
7fef456483 | ||
|
|
386131e74d | ||
|
|
824d3c88f1 | ||
|
|
18a206abd2 | ||
|
|
8dbae776c9 | ||
|
|
b78702cc53 | ||
|
|
d2b43605ad | ||
|
|
7728e09337 | ||
|
|
2666353ce6 | ||
|
|
0b8a306483 | ||
|
|
b51a0b2d08 | ||
|
|
959355b19c | ||
|
|
9c3f0f1994 | ||
|
|
dac337a65b | ||
|
|
98739dfdbc | ||
|
|
17b7a1ea84 | ||
|
|
4d45925758 | ||
|
|
8cadb23f48 | ||
|
|
63211b65c2 | ||
|
|
1be84525b1 | ||
|
|
67ae95a464 | ||
|
|
c03a95ad94 | ||
|
|
51aa7aecb9 | ||
|
|
592cfe5a20 | ||
|
|
b4cf15e73e | ||
|
|
862e143372 | ||
|
|
1f10ca49ad | ||
|
|
4a0c4ffdca | ||
|
|
27c8737f3a | ||
|
|
ecf45fc453 | ||
|
|
0a1178cfd7 | ||
|
|
20a35dc627 | ||
|
|
79887c06f0 | ||
|
|
f7ff424904 | ||
|
|
6678721fe3 | ||
|
|
496302097b | ||
|
|
fe3e2b9a20 | ||
|
|
400a6b066f | ||
|
|
76d181e7fc | ||
|
|
77373eed2d | ||
|
|
6b52be388f | ||
|
|
0518a12a91 | ||
|
|
362a02c4b8 | ||
|
|
3e3a0cde47 | ||
|
|
c16f93effd | ||
|
|
61b27c02b5 | ||
|
|
ba28eaad53 | ||
|
|
92c2d0cc9f | ||
|
|
21d5e8a095 | ||
|
|
60417d68a7 | ||
|
|
7d25387403 | ||
|
|
b454cf5b20 | ||
|
|
9ea6385b72 | ||
|
|
55b7908444 | ||
|
|
e9ff66478b | ||
|
|
d3240d711d | ||
|
|
a8d63a4199 | ||
|
|
a4807a21c3 | ||
|
|
a394ef53a0 | ||
|
|
eb8243743a | ||
|
|
8444bb15c5 | ||
|
|
b86245c4c6 | ||
|
|
499fcfad41 | ||
|
|
bddbbf061b | ||
|
|
05136f4cf0 | ||
|
|
e62e3d5d03 | ||
|
|
595fdaa4a4 | ||
|
|
133febc2c1 | ||
|
|
f8c6d7ff6c | ||
|
|
db3341db91 | ||
|
|
8cbcd3ec01 | ||
|
|
4c6512e9b6 | ||
|
|
4769789a8f | ||
|
|
b4a8cb085c | ||
|
|
4f816d52fd | ||
|
|
94b3a0248d | ||
|
|
5fbf1d82e4 | ||
|
|
55eb3ebe95 | ||
|
|
2afa3c5558 | ||
|
|
30d9a42db2 | ||
|
|
74d357b84d | ||
|
|
09c98a93ec | ||
|
|
ed89ab7c04 | ||
|
|
27c74be02b | ||
|
|
8f22ab39dc | ||
|
|
795c53f4ce | ||
|
|
3fd18a9cc0 | ||
|
|
a5afb4a87e | ||
|
|
379fc4542d | ||
|
|
538ef6c8ce | ||
|
|
95c7e8856c | ||
|
|
95523c8f10 | ||
|
|
97b53d5e40 | ||
|
|
fb688850b1 | ||
|
|
5b1bad2650 | ||
|
|
e5ff132c5e | ||
|
|
a0830ad23c | ||
|
|
9290f53466 | ||
|
|
e5711032bd | ||
|
|
08e3c1d5a2 | ||
|
|
29c579a301 | ||
|
|
61f55bceee | ||
|
|
6586fae3eb | ||
|
|
d5a86f3e4f | ||
|
|
96551ccaa4 | ||
|
|
c83ee86d10 | ||
|
|
c913306cbd | ||
|
|
03d385df97 | ||
|
|
61fcc1b275 | ||
|
|
26977a4ac0 | ||
|
|
28acd05215 | ||
|
|
be4eed8b20 | ||
|
|
cdb0850373 | ||
|
|
0d55e04284 | ||
|
|
f4cce54b70 | ||
|
|
2dc6ca44f1 | ||
|
|
d1d833f0f3 | ||
|
|
1d44577ce9 | ||
|
|
1be7c2d6d7 | ||
|
|
b1f418ee42 | ||
|
|
72b0bf96fe | ||
|
|
3388849fa5 | ||
|
|
dc9650d5fa | ||
|
|
8eb40ae748 | ||
|
|
89184f1d0f | ||
|
|
e899c790b9 | ||
|
|
bd6d695020 | ||
|
|
20d4626a71 | ||
|
|
8ff94c5031 | ||
|
|
ee185a0eeb | ||
|
|
06f8932efd | ||
|
|
1dc627148c | ||
|
|
3cdde5351f | ||
|
|
6e93b8a73d | ||
|
|
267e8533cf | ||
|
|
d3bfb0a28f | ||
|
|
5a31bc7058 | ||
|
|
746bde71bd | ||
|
|
b274ac635c | ||
|
|
9e0a74e583 | ||
|
|
0f782f7697 | ||
|
|
8efde3e9af | ||
|
|
3bf3137dc4 | ||
|
|
63ec32d28d | ||
|
|
d2f4177cdb | ||
|
|
1d958fb7a8 | ||
|
|
fcd580d42e | ||
|
|
34dab68805 | ||
|
|
216dd03922 | ||
|
|
5eef9ac621 | ||
|
|
6b798d5f7c | ||
|
|
22ccce0934 | ||
|
|
fe2af14952 | ||
|
|
8e99ed27e7 | ||
|
|
bb12362cc8 | ||
|
|
1bfc630a64 | ||
|
|
987983f8ae | ||
|
|
657a6118aa | ||
|
|
43e7e6ec7f | ||
|
|
b8b3c19fbf | ||
|
|
69298c96a5 | ||
|
|
7356138872 | ||
|
|
616966f5df | ||
|
|
a59e277c21 | ||
|
|
740ae2c3e9 | ||
|
|
25b7a40f2b | ||
|
|
2beaab1a2f | ||
|
|
60793d53c6 | ||
|
|
4f869c8c81 | ||
|
|
8955180a35 | ||
|
|
a30cbf5797 | ||
|
|
b2bd6109dc | ||
|
|
9455ec48d7 | ||
|
|
f751f5defa | ||
|
|
994edbebbe | ||
|
|
70959b791c | ||
|
|
524ece5119 | ||
|
|
6334bd61b6 | ||
|
|
2e56edd557 | ||
|
|
8cae1d21cd | ||
|
|
1de6ed16eb | ||
|
|
860cb94f41 | ||
|
|
6b505704e9 | ||
|
|
167631451d | ||
|
|
fa5180b94d | ||
|
|
ae01d7be43 | ||
|
|
d5ce39ade1 | ||
|
|
a043dfe8b9 | ||
|
|
7cfb75e3b3 | ||
|
|
a18f0d982f | ||
|
|
0e2dc805c2 | ||
|
|
4c1e11df2c | ||
|
|
76776d054a | ||
|
|
45ebd05cb6 | ||
|
|
0203ce3979 | ||
|
|
72d10178bf | ||
|
|
96f4e26d53 | ||
|
|
4fd86f1b6a | ||
|
|
2f3ee0aec3 | ||
|
|
a5dde31160 | ||
|
|
b45428df05 | ||
|
|
d938763643 | ||
|
|
e4e2157622 | ||
|
|
04b349c6c7 | ||
|
|
7fe3eb7391 | ||
|
|
c1992b577a | ||
|
|
632283d47f | ||
|
|
1d9e46997c | ||
|
|
861ce34022 | ||
|
|
32e8db322d | ||
|
|
3df2b72175 | ||
|
|
e7ac4f95be | ||
|
|
e7ed69287b | ||
|
|
2e80417f53 | ||
|
|
ee435d2bb9 | ||
|
|
bb516946be | ||
|
|
81157e1cb5 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,6 +16,7 @@ man/remind.1
|
|||||||
man/tkremind.1
|
man/tkremind.1
|
||||||
pm_to_blib
|
pm_to_blib
|
||||||
rem2html/Makefile
|
rem2html/Makefile
|
||||||
|
rem2html/rem2html
|
||||||
rem2html/rem2html.1
|
rem2html/rem2html.1
|
||||||
rem2pdf/Makefile.PL
|
rem2pdf/Makefile.PL
|
||||||
rem2pdf/Makefile.old
|
rem2pdf/Makefile.old
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
workflow:
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH =~ /wip/
|
||||||
|
when: never
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
image: 'debian:stable-slim'
|
image: 'debian:stable-slim'
|
||||||
before_script:
|
before_script:
|
||||||
|
|||||||
@@ -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-2023 Dianne Skoll, except where noted in
|
2. REMIND is Copyright 1992-2024 Dianne Skoll, except where noted in
|
||||||
individual files.
|
individual files.
|
||||||
|
|
||||||
3. DISTRIBUTION AND USE
|
3. DISTRIBUTION AND USE
|
||||||
@@ -16,7 +16,7 @@ individual files.
|
|||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
675 Mass Ave, Cambridge, MA 02139, USA
|
51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
MICROSOFT WINDOWS
|
|
||||||
=================
|
|
||||||
|
|
||||||
I used to prohibit porting Remind to Microsoft Windows. However, this
|
|
||||||
may cause problems with the GPL, so I have removed that restriction.
|
|
||||||
|
|
||||||
Although I cannot prevent you from porting Remind to Windows, I appeal
|
|
||||||
to you not to do it. I am trying to encourage the growth of free
|
|
||||||
software, not proprietary software.
|
|
||||||
|
|
||||||
If you port Remind to Windows, I will not provide support or answers to
|
|
||||||
questions -- you're on your own. On the other hand, I will feel no guilt
|
|
||||||
in taking enhancements and merging them into the UNIX stream.
|
|
||||||
|
|
||||||
APPLE
|
|
||||||
=====
|
|
||||||
|
|
||||||
I can't prevent you from using Remind on Apple's products, but I hope
|
|
||||||
you don't. Apple's corporate culture is the very antithesis of Free
|
|
||||||
Software. Rather than using Mac OS X, I encourage you to switch to
|
|
||||||
Linux or FreeBSD, two Free Software operating systems that are every
|
|
||||||
bit as capable as Mac OS X and which are unencumbered by Apple's
|
|
||||||
arbitrary restrictions.
|
|
||||||
|
|
||||||
And if you're looking to port Remind to other Apple products like the
|
|
||||||
iPhone or iPad, please don't. Those products enforce Apple's rigorous
|
|
||||||
controls much more stringently than Mac OS X on an Apple PC.
|
|
||||||
|
|
||||||
--
|
|
||||||
Dianne Skoll
|
|
||||||
2
Makefile
2
Makefile
@@ -44,7 +44,7 @@ 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
|
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
|
||||||
|
|
||||||
src/Makefile: src/Makefile.in
|
src/Makefile: src/Makefile.in
|
||||||
./configure
|
./configure
|
||||||
|
|||||||
54
build.tk
Normal file → Executable file
54
build.tk
Normal file → Executable file
@@ -15,6 +15,8 @@
|
|||||||
# the next line restarts using wish \
|
# the next line restarts using wish \
|
||||||
exec wish "$0" "$@"
|
exec wish "$0" "$@"
|
||||||
|
|
||||||
|
global RemindExecutable
|
||||||
|
|
||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
# %PROCEDURE: SetConfigDefaults
|
# %PROCEDURE: SetConfigDefaults
|
||||||
# %ARGUMENTS:
|
# %ARGUMENTS:
|
||||||
@@ -27,10 +29,10 @@ exec wish "$0" "$@"
|
|||||||
proc SetConfigDefaults {} {
|
proc SetConfigDefaults {} {
|
||||||
global Config
|
global Config
|
||||||
set Config(LAT_DEG) 45
|
set Config(LAT_DEG) 45
|
||||||
set Config(LAT_MIN) 24
|
set Config(LAT_MIN) 25
|
||||||
set Config(LAT_SEC) 14
|
set Config(LAT_SEC) 14
|
||||||
set Config(LON_DEG) 75
|
set Config(LON_DEG) 75
|
||||||
set Config(LON_MIN) 39
|
set Config(LON_MIN) 41
|
||||||
set Config(LON_SEC) 23
|
set Config(LON_SEC) 23
|
||||||
set Config(LOCATION) "Ottawa"
|
set Config(LOCATION) "Ottawa"
|
||||||
set Config(DEFAULT_PAGE) "Letter"
|
set Config(DEFAULT_PAGE) "Letter"
|
||||||
@@ -40,7 +42,7 @@ proc SetConfigDefaults {} {
|
|||||||
set Config(WESTERN_HEMISPHERE) 1
|
set Config(WESTERN_HEMISPHERE) 1
|
||||||
set Config(LANGUAGE) "English"
|
set Config(LANGUAGE) "English"
|
||||||
set Config(INST_DIR) "/usr/local/bin"
|
set Config(INST_DIR) "/usr/local/bin"
|
||||||
set Config(MAN_DIR) "/usr/local/man"
|
set Config(MAN_DIR) "/usr/local/share/man"
|
||||||
}
|
}
|
||||||
|
|
||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
@@ -53,7 +55,7 @@ proc SetConfigDefaults {} {
|
|||||||
# Pops up an error dialog; then calls exit.
|
# Pops up an error dialog; then calls exit.
|
||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
proc Bail { msg } {
|
proc Bail { msg } {
|
||||||
tk_dialog .err "Remind Configuration Error" $msg error 0 "Bummer"
|
tk_messageBox -message "Remind Build Error" -detail $msg -icon error -type ok
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +126,7 @@ proc CreateMainDialog {} {
|
|||||||
# Creates the "installation directories" dialog.
|
# Creates the "installation directories" dialog.
|
||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
proc CreateInstallDirDialog { w } {
|
proc CreateInstallDirDialog { w } {
|
||||||
global Config
|
global Config RemindExecutable
|
||||||
label $w.binlabel -text "Location for programs: "
|
label $w.binlabel -text "Location for programs: "
|
||||||
entry $w.bin -width 30
|
entry $w.bin -width 30
|
||||||
$w.bin insert end $Config(INST_DIR)
|
$w.bin insert end $Config(INST_DIR)
|
||||||
@@ -133,16 +135,19 @@ proc CreateInstallDirDialog { w } {
|
|||||||
entry $w.man -width 30
|
entry $w.man -width 30
|
||||||
$w.man insert end $Config(MAN_DIR)
|
$w.man insert end $Config(MAN_DIR)
|
||||||
|
|
||||||
text $w.blurb -width 1 -height 5 -wrap word -relief flat -takefocus 0
|
text $w.blurb -width 1 -height 20 -wrap word -relief flat -takefocus 0
|
||||||
$w.blurb insert end "\n(Tabbed-notebook Tcl code taken from \"Effective Tcl/Tk Programming\" by Mark Harrison and Michael McLennan, Addison-Wesley Professional Computing Series.)"
|
if { "$RemindExecutable" != "" } {
|
||||||
$w.blurb configure -state disabled
|
$w.blurb insert end "Note: Default settings were obtained by querying the existing installed version of Remind found at: $RemindExecutable\n"
|
||||||
# Disable all text-window behaviour
|
}
|
||||||
bindtags $w.blurb {NoSuchTag}
|
$w.blurb insert end "\n(Tabbed-notebook Tcl code taken from \"Effective Tcl/Tk Programming\" by Mark Harrison and Michael McLennan, Addison-Wesley Professional Computing Series.)\n"
|
||||||
grid $w.binlabel -row 0 -column 0 -sticky e
|
grid $w.binlabel -row 0 -column 0 -sticky e
|
||||||
grid $w.bin -row 0 -column 1 -sticky nsew
|
grid $w.bin -row 0 -column 1 -sticky nsew
|
||||||
grid $w.manlabel -row 1 -column 0 -sticky e
|
grid $w.manlabel -row 1 -column 0 -sticky e
|
||||||
grid $w.man -row 1 -column 1 -sticky nsew
|
grid $w.man -row 1 -column 1 -sticky nsew
|
||||||
grid $w.blurb - -sticky nsew
|
grid $w.blurb - -sticky nsew
|
||||||
|
# Disable all text-window behaviour
|
||||||
|
bindtags $w.blurb {NoSuchTag}
|
||||||
|
$w.blurb configure -state disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
@@ -190,8 +195,8 @@ proc CreateLocationDialog { w } {
|
|||||||
|
|
||||||
grid $w.north $w.west
|
grid $w.north $w.west
|
||||||
grid $w.south $w.east
|
grid $w.south $w.east
|
||||||
grid $w.loclab -sticky e
|
grid $w.loclab -sticky e
|
||||||
grid $w.location -sticky nsew -row 6 -column 1
|
grid $w.location -sticky nsew -row 8 -column 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
@@ -293,9 +298,9 @@ proc BuildRemind {} {
|
|||||||
|
|
||||||
.msgs insert end "\n>>> Creating src/custom.h...\n\n" green
|
.msgs insert end "\n>>> Creating src/custom.h...\n\n" green
|
||||||
CreateCustomH
|
CreateCustomH
|
||||||
.msgs insert end ">>> Calling `./configure'...\n\n" green
|
.msgs insert end "\n>>> Calling `./configure'...\n\n" green
|
||||||
CallConfigure
|
CallConfigure
|
||||||
.msgs insert end ">>> Calling `make'...\n\n" green
|
.msgs insert end "\n>>> Calling `make'...\n\n" green
|
||||||
CallMake
|
CallMake
|
||||||
.msgs insert end "\n----------------------------------------------\n\n"
|
.msgs insert end "\n----------------------------------------------\n\n"
|
||||||
.msgs insert end "Remind" red
|
.msgs insert end "Remind" red
|
||||||
@@ -447,12 +452,12 @@ proc CreateCustomH {} {
|
|||||||
"#define DEFAULT_LATITUDE *" {
|
"#define DEFAULT_LATITUDE *" {
|
||||||
set lat [expr $LAT_DEG + ($LAT_MIN/60.0) + ($LAT_SEC/3600.0)];
|
set lat [expr $LAT_DEG + ($LAT_MIN/60.0) + ($LAT_SEC/3600.0)];
|
||||||
puts $out "#define DEFAULT_LATITUDE $lat"
|
puts $out "#define DEFAULT_LATITUDE $lat"
|
||||||
.msgs insert end "#define DEFAULT_LATITUDE $lat"
|
.msgs insert end "#define DEFAULT_LATITUDE $lat\n"
|
||||||
}
|
}
|
||||||
"#define DEFAULT_LONGITUDE *" {
|
"#define DEFAULT_LONGITUDE *" {
|
||||||
set lon [expr -1.0 * ($LON_DEG + ($LON_MIN/60.0) + ($LON_SEC/3600.0))]
|
set lon [expr -1.0 * ($LON_DEG + ($LON_MIN/60.0) + ($LON_SEC/3600.0))]
|
||||||
puts $out "#define DEFAULT_LONGITUDE $lon"
|
puts $out "#define DEFAULT_LONGITUDE $lon"
|
||||||
.msgs insert end "#define DEFAULT_LONGITUDE $lon"
|
.msgs insert end "#define DEFAULT_LONGITUDE $lon\n"
|
||||||
}
|
}
|
||||||
"#define LOCATION *" {
|
"#define LOCATION *" {
|
||||||
puts $out "#define LOCATION \"$Config(LOCATION)\""
|
puts $out "#define LOCATION \"$Config(LOCATION)\""
|
||||||
@@ -506,7 +511,13 @@ proc CallMake {} {
|
|||||||
"Icelandic" { set lang ICELANDIC }
|
"Icelandic" { set lang ICELANDIC }
|
||||||
default { set lang ENGLISH }
|
default { set lang ENGLISH }
|
||||||
}
|
}
|
||||||
RunCommand "make \"LANGDEF=-DLANG=$lang\""
|
set nproc 0
|
||||||
|
catch { set nproc [exec nproc] }
|
||||||
|
if { $nproc != 0 } {
|
||||||
|
RunCommand "make -j $nproc \"LANGDEF=-DLANG=$lang\""
|
||||||
|
} else {
|
||||||
|
RunCommand "make \"LANGDEF=-DLANG=$lang\""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -721,7 +732,7 @@ proc notebook_fix_size {win} {
|
|||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
proc FindRemind {} {
|
proc FindRemind {} {
|
||||||
global env
|
global env
|
||||||
set path [concat [split $env(PATH) ":"] "/bin" "/usr/bin" "/usr/local/bin"]
|
set path [concat [split $env(PATH) ":"] "/usr/local/bin" "/bin" "/usr/bin" ]
|
||||||
foreach thing $path {
|
foreach thing $path {
|
||||||
if [file executable [file join $thing "remind"]] {
|
if [file executable [file join $thing "remind"]] {
|
||||||
return [file join $thing "remind"]
|
return [file join $thing "remind"]
|
||||||
@@ -739,16 +750,17 @@ proc FindRemind {} {
|
|||||||
# sensible defaults.
|
# sensible defaults.
|
||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
proc SetConfigFromRemind {} {
|
proc SetConfigFromRemind {} {
|
||||||
global Config
|
global Config RemindExecutable
|
||||||
SetConfigDefaults
|
SetConfigDefaults
|
||||||
set rem [FindRemind]
|
set rem [FindRemind]
|
||||||
|
set RemindExecutable $rem
|
||||||
if {"$rem" == ""} {
|
if {"$rem" == ""} {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
set dir [file dirname $rem]
|
set dir [file dirname $rem]
|
||||||
set Config(INST_DIR) $dir
|
set Config(INST_DIR) $dir
|
||||||
if {"$dir" == "/usr/local/bin"} {
|
if {"$dir" == "/usr/local/bin"} {
|
||||||
set Config(MAN_DIR) "/usr/local/man"
|
set Config(MAN_DIR) "/usr/local/share/man"
|
||||||
} elseif {$dir == "/usr/bin"} {
|
} elseif {$dir == "/usr/bin"} {
|
||||||
set Config(MAN_DIR) "/usr/share/man"
|
set Config(MAN_DIR) "/usr/share/man"
|
||||||
}
|
}
|
||||||
@@ -758,6 +770,8 @@ proc SetConfigFromRemind {} {
|
|||||||
set Config(MAN_DIR) "/usr/share/man"
|
set Config(MAN_DIR) "/usr/share/man"
|
||||||
} elseif {[file readable "/usr/man/man1/remind.1"]} {
|
} elseif {[file readable "/usr/man/man1/remind.1"]} {
|
||||||
set Config(MAN_DIR) "/usr/man"
|
set Config(MAN_DIR) "/usr/man"
|
||||||
|
} elseif {[file readable "/usr/local/share/man/man1/remind.1"]} {
|
||||||
|
set Config(MAN_DIR) "/usr/local/share/man"
|
||||||
} elseif {[file readable "/usr/local/man/man1/remind.1"]} {
|
} elseif {[file readable "/usr/local/man/man1/remind.1"]} {
|
||||||
set Config(MAN_DIR) "/usr/local/man"
|
set Config(MAN_DIR) "/usr/local/man"
|
||||||
}
|
}
|
||||||
|
|||||||
130
configure
vendored
130
configure
vendored
@@ -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.
|
# Generated by GNU Autoconf 2.71 for remind 05.00.00.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
|
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
|
||||||
@@ -606,12 +606,12 @@ MFLAGS=
|
|||||||
MAKEFLAGS=
|
MAKEFLAGS=
|
||||||
|
|
||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME=''
|
PACKAGE_NAME='remind'
|
||||||
PACKAGE_TARNAME=''
|
PACKAGE_TARNAME='remind'
|
||||||
PACKAGE_VERSION=''
|
PACKAGE_VERSION='05.00.00'
|
||||||
PACKAGE_STRING=''
|
PACKAGE_STRING='remind 05.00.00'
|
||||||
PACKAGE_BUGREPORT=''
|
PACKAGE_BUGREPORT=''
|
||||||
PACKAGE_URL=''
|
PACKAGE_URL='https://dianne.skoll.ca/projects/remind/'
|
||||||
|
|
||||||
ac_unique_file="src/queue.c"
|
ac_unique_file="src/queue.c"
|
||||||
# Factoring default headers for most tests.
|
# Factoring default headers for most tests.
|
||||||
@@ -757,7 +757,7 @@ localstatedir='${prefix}/var'
|
|||||||
runstatedir='${localstatedir}/run'
|
runstatedir='${localstatedir}/run'
|
||||||
includedir='${prefix}/include'
|
includedir='${prefix}/include'
|
||||||
oldincludedir='/usr/include'
|
oldincludedir='/usr/include'
|
||||||
docdir='${datarootdir}/doc/${PACKAGE}'
|
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
|
||||||
infodir='${datarootdir}/info'
|
infodir='${datarootdir}/info'
|
||||||
htmldir='${docdir}'
|
htmldir='${docdir}'
|
||||||
dvidir='${docdir}'
|
dvidir='${docdir}'
|
||||||
@@ -1264,7 +1264,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 this package to adapt to many kinds of systems.
|
\`configure' configures remind 05.00.00 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@@ -1313,7 +1313,7 @@ Fine tuning of the installation directories:
|
|||||||
--infodir=DIR info documentation [DATAROOTDIR/info]
|
--infodir=DIR info documentation [DATAROOTDIR/info]
|
||||||
--localedir=DIR locale-dependent data [DATAROOTDIR/locale]
|
--localedir=DIR locale-dependent data [DATAROOTDIR/locale]
|
||||||
--mandir=DIR man documentation [DATAROOTDIR/man]
|
--mandir=DIR man documentation [DATAROOTDIR/man]
|
||||||
--docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
|
--docdir=DIR documentation root [DATAROOTDIR/doc/remind]
|
||||||
--htmldir=DIR html documentation [DOCDIR]
|
--htmldir=DIR html documentation [DOCDIR]
|
||||||
--dvidir=DIR dvi documentation [DOCDIR]
|
--dvidir=DIR dvi documentation [DOCDIR]
|
||||||
--pdfdir=DIR pdf documentation [DOCDIR]
|
--pdfdir=DIR pdf documentation [DOCDIR]
|
||||||
@@ -1325,7 +1325,9 @@ _ACEOF
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
|
case $ac_init_help in
|
||||||
|
short | recursive ) echo "Configuration of remind 05.00.00:";;
|
||||||
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
Optional Features:
|
Optional Features:
|
||||||
@@ -1348,6 +1350,7 @@ Use these variables to override the choices made by `configure' or to help
|
|||||||
it to find libraries and programs with nonstandard names/locations.
|
it to find libraries and programs with nonstandard names/locations.
|
||||||
|
|
||||||
Report bugs to the package provider.
|
Report bugs to the package provider.
|
||||||
|
remind home page: <https://dianne.skoll.ca/projects/remind/>.
|
||||||
_ACEOF
|
_ACEOF
|
||||||
ac_status=$?
|
ac_status=$?
|
||||||
fi
|
fi
|
||||||
@@ -1411,7 +1414,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
|
||||||
configure
|
remind configure 05.00.00
|
||||||
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.
|
||||||
@@ -1861,7 +1864,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 $as_me, which was
|
It was created by remind $as_me 05.00.00, 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
|
||||||
@@ -2450,7 +2453,6 @@ as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
|
|||||||
as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
|
as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
|
||||||
as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
|
as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
|
||||||
as_fn_append ac_header_c_list " sys/time.h sys_time_h HAVE_SYS_TIME_H"
|
as_fn_append ac_header_c_list " sys/time.h sys_time_h HAVE_SYS_TIME_H"
|
||||||
as_fn_append ac_header_c_list " utime.h utime_h HAVE_UTIME_H"
|
|
||||||
|
|
||||||
# Auxiliary files required by this configure script.
|
# Auxiliary files required by this configure script.
|
||||||
ac_aux_files="install-sh"
|
ac_aux_files="install-sh"
|
||||||
@@ -4004,6 +4006,12 @@ printf "%s\n" "#define SIZEOF_TIME_T $ac_cv_sizeof_time_t" >>confdefs.h
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ac_fn_c_check_header_compile "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default"
|
||||||
|
if test "x$ac_cv_header_strings_h" = xyes
|
||||||
|
then :
|
||||||
|
printf "%s\n" "#define HAVE_STRINGS_H 1" >>confdefs.h
|
||||||
|
|
||||||
|
fi
|
||||||
ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default"
|
ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default"
|
||||||
if test "x$ac_cv_header_sys_types_h" = xyes
|
if test "x$ac_cv_header_sys_types_h" = xyes
|
||||||
then :
|
then :
|
||||||
@@ -4034,6 +4042,12 @@ then :
|
|||||||
printf "%s\n" "#define HAVE_LANGINFO_H 1" >>confdefs.h
|
printf "%s\n" "#define HAVE_LANGINFO_H 1" >>confdefs.h
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
ac_fn_c_check_header_compile "$LINENO" "sys/inotify.h" "ac_cv_header_sys_inotify_h" "$ac_includes_default"
|
||||||
|
if test "x$ac_cv_header_sys_inotify_h" = xyes
|
||||||
|
then :
|
||||||
|
printf "%s\n" "#define HAVE_SYS_INOTIFY_H 1" >>confdefs.h
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
|
||||||
@@ -4074,60 +4088,6 @@ printf "%s\n" "#define TM_IN_SYS_TIME 1" >>confdefs.h
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether utime accepts a null argument" >&5
|
|
||||||
printf %s "checking whether utime accepts a null argument... " >&6; }
|
|
||||||
if test ${ac_cv_func_utime_null+y}
|
|
||||||
then :
|
|
||||||
printf %s "(cached) " >&6
|
|
||||||
else $as_nop
|
|
||||||
rm -f conftest.data; >conftest.data
|
|
||||||
# Sequent interprets utime(file, 0) to mean use start of epoch. Wrong.
|
|
||||||
if test "$cross_compiling" = yes
|
|
||||||
then :
|
|
||||||
ac_cv_func_utime_null='guessing yes'
|
|
||||||
else $as_nop
|
|
||||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
||||||
/* end confdefs.h. */
|
|
||||||
$ac_includes_default
|
|
||||||
#ifdef HAVE_UTIME_H
|
|
||||||
# include <utime.h>
|
|
||||||
#endif
|
|
||||||
int
|
|
||||||
main (void)
|
|
||||||
{
|
|
||||||
struct stat s, t;
|
|
||||||
return ! (stat ("conftest.data", &s) == 0
|
|
||||||
&& utime ("conftest.data", 0) == 0
|
|
||||||
&& stat ("conftest.data", &t) == 0
|
|
||||||
&& t.st_mtime >= s.st_mtime
|
|
||||||
&& t.st_mtime - s.st_mtime < 120);
|
|
||||||
;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
_ACEOF
|
|
||||||
if ac_fn_c_try_run "$LINENO"
|
|
||||||
then :
|
|
||||||
ac_cv_func_utime_null=yes
|
|
||||||
else $as_nop
|
|
||||||
ac_cv_func_utime_null=no
|
|
||||||
fi
|
|
||||||
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
|
|
||||||
conftest.$ac_objext conftest.beam conftest.$ac_ext
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_utime_null" >&5
|
|
||||||
printf "%s\n" "$ac_cv_func_utime_null" >&6; }
|
|
||||||
if test "x$ac_cv_func_utime_null" != xno; then
|
|
||||||
ac_cv_func_utime_null=yes
|
|
||||||
|
|
||||||
printf "%s\n" "#define HAVE_UTIME_NULL 1" >>confdefs.h
|
|
||||||
|
|
||||||
fi
|
|
||||||
rm -f conftest.data
|
|
||||||
|
|
||||||
if test "$GCC" = yes; then
|
if test "$GCC" = yes; then
|
||||||
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
|
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
|
||||||
# Check for link-time optimization support
|
# Check for link-time optimization support
|
||||||
@@ -4175,6 +4135,24 @@ if test "$?" != 0 ; then
|
|||||||
echo "*** COULD NOT DETERMINE RELEASE DATE: docs/WHATSNEW is incorrect!"
|
echo "*** COULD NOT DETERMINE RELEASE DATE: docs/WHATSNEW is incorrect!"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup"
|
||||||
|
if test "x$ac_cv_func_strdup" = xyes
|
||||||
|
then :
|
||||||
|
printf "%s\n" "#define HAVE_STRDUP 1" >>confdefs.h
|
||||||
|
|
||||||
|
fi
|
||||||
|
ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp"
|
||||||
|
if test "x$ac_cv_func_strcasecmp" = xyes
|
||||||
|
then :
|
||||||
|
printf "%s\n" "#define HAVE_STRCASECMP 1" >>confdefs.h
|
||||||
|
|
||||||
|
fi
|
||||||
|
ac_fn_c_check_func "$LINENO" "strncasecmp" "ac_cv_func_strncasecmp"
|
||||||
|
if test "x$ac_cv_func_strncasecmp" = xyes
|
||||||
|
then :
|
||||||
|
printf "%s\n" "#define HAVE_STRNCASECMP 1" >>confdefs.h
|
||||||
|
|
||||||
|
fi
|
||||||
ac_fn_c_check_func "$LINENO" "setenv" "ac_cv_func_setenv"
|
ac_fn_c_check_func "$LINENO" "setenv" "ac_cv_func_setenv"
|
||||||
if test "x$ac_cv_func_setenv" = xyes
|
if test "x$ac_cv_func_setenv" = xyes
|
||||||
then :
|
then :
|
||||||
@@ -4211,14 +4189,20 @@ then :
|
|||||||
printf "%s\n" "#define HAVE_INITGROUPS 1" >>confdefs.h
|
printf "%s\n" "#define HAVE_INITGROUPS 1" >>confdefs.h
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
ac_fn_c_check_func "$LINENO" "inotify_init1" "ac_cv_func_inotify_init1"
|
||||||
|
if test "x$ac_cv_func_inotify_init1" = xyes
|
||||||
|
then :
|
||||||
|
printf "%s\n" "#define HAVE_INOTIFY_INIT1 1" >>confdefs.h
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
VERSION=04.02.08
|
VERSION=$PACKAGE_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h rem2html/Makefile rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1"
|
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h rem2html/Makefile rem2html/rem2html rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1"
|
||||||
|
|
||||||
cat >confcache <<\_ACEOF
|
cat >confcache <<\_ACEOF
|
||||||
# This file is a shell script that caches the results of configure
|
# This file is a shell script that caches the results of configure
|
||||||
@@ -4719,7 +4703,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 $as_me, which was
|
This file was extended by remind $as_me 05.00.00, 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 +4759,8 @@ $config_files
|
|||||||
Configuration headers:
|
Configuration headers:
|
||||||
$config_headers
|
$config_headers
|
||||||
|
|
||||||
Report bugs to the package provider."
|
Report bugs to the package provider.
|
||||||
|
remind home page: <https://dianne.skoll.ca/projects/remind/>."
|
||||||
|
|
||||||
_ACEOF
|
_ACEOF
|
||||||
ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
|
ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
|
||||||
@@ -4783,7 +4768,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="\\
|
||||||
config.status
|
remind config.status 05.00.00
|
||||||
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\\"
|
||||||
|
|
||||||
@@ -4910,6 +4895,7 @@ do
|
|||||||
"www/Makefile") CONFIG_FILES="$CONFIG_FILES www/Makefile" ;;
|
"www/Makefile") CONFIG_FILES="$CONFIG_FILES www/Makefile" ;;
|
||||||
"src/version.h") CONFIG_FILES="$CONFIG_FILES src/version.h" ;;
|
"src/version.h") CONFIG_FILES="$CONFIG_FILES src/version.h" ;;
|
||||||
"rem2html/Makefile") CONFIG_FILES="$CONFIG_FILES rem2html/Makefile" ;;
|
"rem2html/Makefile") CONFIG_FILES="$CONFIG_FILES rem2html/Makefile" ;;
|
||||||
|
"rem2html/rem2html") CONFIG_FILES="$CONFIG_FILES rem2html/rem2html" ;;
|
||||||
"rem2pdf/Makefile.PL") CONFIG_FILES="$CONFIG_FILES rem2pdf/Makefile.PL" ;;
|
"rem2pdf/Makefile.PL") CONFIG_FILES="$CONFIG_FILES rem2pdf/Makefile.PL" ;;
|
||||||
"rem2pdf/Makefile.top") CONFIG_FILES="$CONFIG_FILES rem2pdf/Makefile.top" ;;
|
"rem2pdf/Makefile.top") CONFIG_FILES="$CONFIG_FILES rem2pdf/Makefile.top" ;;
|
||||||
"rem2pdf/bin/rem2pdf") CONFIG_FILES="$CONFIG_FILES rem2pdf/bin/rem2pdf" ;;
|
"rem2pdf/bin/rem2pdf") CONFIG_FILES="$CONFIG_FILES rem2pdf/bin/rem2pdf" ;;
|
||||||
|
|||||||
14
configure.in
14
configure.in
@@ -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
|
AC_INIT(remind, 05.00.00, , , https://dianne.skoll.ca/projects/remind/)
|
||||||
AC_CONFIG_SRCDIR([src/queue.c])
|
AC_CONFIG_SRCDIR([src/queue.c])
|
||||||
|
|
||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
@@ -30,7 +30,7 @@ AC_PATH_PROG([PERL], [perl])
|
|||||||
|
|
||||||
dnl Checks for libraries.
|
dnl Checks for libraries.
|
||||||
AC_CHECK_LIB(m, sqrt)
|
AC_CHECK_LIB(m, sqrt)
|
||||||
AC_CHECK_HEADERS_ONCE([sys/time.h])
|
AC_CHECK_HEADERS_ONCE([sys/time.h stdint.h])
|
||||||
|
|
||||||
dnl Integer sizes
|
dnl Integer sizes
|
||||||
AC_CHECK_SIZEOF(unsigned int)
|
AC_CHECK_SIZEOF(unsigned int)
|
||||||
@@ -38,13 +38,11 @@ AC_CHECK_SIZEOF(unsigned long)
|
|||||||
AC_CHECK_SIZEOF(time_t)
|
AC_CHECK_SIZEOF(time_t)
|
||||||
|
|
||||||
dnl Checks for header files.
|
dnl Checks for header files.
|
||||||
AC_CHECK_HEADERS(sys/types.h glob.h wctype.h locale.h langinfo.h)
|
AC_CHECK_HEADERS(strings.h sys/types.h glob.h wctype.h locale.h langinfo.h sys/inotify.h)
|
||||||
|
|
||||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_STRUCT_TM
|
AC_STRUCT_TM
|
||||||
|
|
||||||
dnl Checks for library functions.
|
|
||||||
AC_FUNC_UTIME_NULL
|
|
||||||
if test "$GCC" = yes; then
|
if test "$GCC" = yes; then
|
||||||
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
|
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
|
||||||
# Check for link-time optimization support
|
# Check for link-time optimization support
|
||||||
@@ -86,13 +84,13 @@ if test "$?" != 0 ; then
|
|||||||
echo "*** COULD NOT DETERMINE RELEASE DATE: docs/WHATSNEW is incorrect!"
|
echo "*** COULD NOT DETERMINE RELEASE DATE: docs/WHATSNEW is incorrect!"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale initgroups)
|
AC_CHECK_FUNCS(strdup strcasecmp strncasecmp setenv unsetenv glob mbstowcs setlocale initgroups inotify_init1)
|
||||||
|
|
||||||
VERSION=04.02.08
|
VERSION=$PACKAGE_VERSION
|
||||||
AC_SUBST(VERSION)
|
AC_SUBST(VERSION)
|
||||||
AC_SUBST(PERL)
|
AC_SUBST(PERL)
|
||||||
AC_SUBST(PERLARTIFACTS)
|
AC_SUBST(PERLARTIFACTS)
|
||||||
AC_SUBST(RELEASE_DATE)
|
AC_SUBST(RELEASE_DATE)
|
||||||
AC_CONFIG_FILES([src/Makefile www/Makefile src/version.h rem2html/Makefile rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1])
|
AC_CONFIG_FILES([src/Makefile www/Makefile src/version.h rem2html/Makefile rem2html/rem2html rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
chmod a+x rem2pdf/bin/rem2pdf
|
chmod a+x rem2pdf/bin/rem2pdf
|
||||||
|
|||||||
@@ -19,8 +19,7 @@
|
|||||||
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
;; You should have received a copy of the GNU General Public License
|
||||||
;; along with this program; if not, write to the Free Software
|
;; along with this program; if not, write to the Free Software
|
||||||
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
|
||||||
;; 02111-1307, USA.
|
|
||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ Norman Walsh.
|
|||||||
#!/usr/local/bin/wish
|
#!/usr/local/bin/wish
|
||||||
wm withdraw .
|
wm withdraw .
|
||||||
after 15000 { destroy . ; exit }
|
after 15000 { destroy . ; exit }
|
||||||
tk_dialog .d { Message } $argv warning 0 { OK }
|
tk_messageBox -message Message -detail $argv -icon info -type ok
|
||||||
destroy .
|
destroy .
|
||||||
exit
|
exit
|
||||||
-------------- Cut Here ---------- Cut Here ---------- Cut Here -------------
|
-------------- Cut Here ---------- Cut Here ---------- Cut Here -------------
|
||||||
|
|||||||
280
docs/WHATSNEW
280
docs/WHATSNEW
@@ -1,5 +1,285 @@
|
|||||||
CHANGES TO REMIND
|
CHANGES TO REMIND
|
||||||
|
|
||||||
|
* VERSION 5.0 Patch 0 - 2024-06-06
|
||||||
|
|
||||||
|
* MAJOR CHANGE: The expression evaluation engine has been completely replaced
|
||||||
|
with a new one that splits parsing and evaluating into two separate steps.
|
||||||
|
It also features short-circuit evaluation of &&, ||, iif() and choose().
|
||||||
|
This should speed up expression-heavy reminder files.
|
||||||
|
|
||||||
|
NOTE INCOMPATIBILITY: In expressions with side-effects, the short-circuit
|
||||||
|
evaluation might change the result you get. For example, consider
|
||||||
|
running the following file through: remind file.rem 2024-06-04
|
||||||
|
|
||||||
|
SET a trig("Mon +7") || trig("Thu +7")
|
||||||
|
MSG trig = [trig()]
|
||||||
|
|
||||||
|
Older Remind versions will output:
|
||||||
|
|
||||||
|
trig = 2024-06-06
|
||||||
|
|
||||||
|
whereas this version outputs:
|
||||||
|
|
||||||
|
trig = 2024-06-10
|
||||||
|
|
||||||
|
because the second part of the "||" expression is not evaluated. The vast
|
||||||
|
majority of Remind expressions do not have side-effects and should yield
|
||||||
|
the same results as before.
|
||||||
|
|
||||||
|
The newer expression engine also permits recursive functions, but
|
||||||
|
these are not recommended. Still, if you want to, you can do:
|
||||||
|
|
||||||
|
fset factorial(n) iif(n <= 1, 1, n*factorial(n-1))
|
||||||
|
|
||||||
|
and it will work for values of n that don't cause integer overflow.
|
||||||
|
|
||||||
|
* IMPROVEMENT: If there's an unmatched PUSH-OMIT-CONTEXT, print the
|
||||||
|
filename and line number containing it.
|
||||||
|
|
||||||
|
* IMPROVEMENT: If there's an IF with a missing ENDIF, print the filename
|
||||||
|
and line number of the IF statement.
|
||||||
|
|
||||||
|
* NEW FEATURE: Add EXPR OFF command to completely disable expression
|
||||||
|
evaluation. Useful if you INCLUDE files that you don't expect to
|
||||||
|
contain expressions and may come from slightly untrustworthy sources.
|
||||||
|
|
||||||
|
* NEW FEATURE: Add $ExpressionTimeLimit system variable to enforce a
|
||||||
|
maximum limit on how long evaluating an expression is allowed to take.
|
||||||
|
|
||||||
|
* NEW FEATURE: Add --max-execution-time=n command-line option to terminate
|
||||||
|
Remind if it runs for more than n seconds.
|
||||||
|
|
||||||
|
* CHANGE: Make the command-line option "-ifoo" equivalent to "-ifoo=0"
|
||||||
|
|
||||||
|
* CHANGE: Permit a literal [ in a reminder by using the sequence [[
|
||||||
|
The old ["["] still works.
|
||||||
|
|
||||||
|
* BUG FIX: In "purge" mode, Remind would sometimes purge reminders with
|
||||||
|
a relative "SCANFROM" which haven't actually expired. This has been fixed.
|
||||||
|
|
||||||
|
* BUG FIX: Disallow something like: FSET func(x, x) expr
|
||||||
|
which shouldn't have been allowed in the first place.
|
||||||
|
|
||||||
|
* BUG FIX: Replace leading spaces with tabs in Makefiles (per Emanuele Torre
|
||||||
|
and Tim Chase)
|
||||||
|
|
||||||
|
* VERSION 4.3 Patch 7 - 2024-04-29
|
||||||
|
|
||||||
|
* IMPROVEMENT: build.tk: Add a note if build.tk obtains default settings
|
||||||
|
from an existing Remind installation.
|
||||||
|
|
||||||
|
* IMPROVEMENT: configure: Pass all args to AC_INIT including the Remind
|
||||||
|
home page. Remove some unused autoconf cruft.
|
||||||
|
|
||||||
|
* IMPROVEMENT: Use standard C library versions of strdup, strcasecmp and
|
||||||
|
strncasecmp where available, rather than using our own versions.
|
||||||
|
|
||||||
|
* MINOR FEATURE: remind: Make $Tt a synonym for trigtime().
|
||||||
|
|
||||||
|
* BUG FIX: remind: Make sure shellescape() doesn't mangle UTF-8 characters
|
||||||
|
with high-bits set.
|
||||||
|
|
||||||
|
* BUG FIX: remind: Don't rely on undefined behavior of "%" operator in
|
||||||
|
the ord() built-in function.
|
||||||
|
|
||||||
|
* BUG FIX: remind: Do not clear out trigtime() unnecessarily. Before,
|
||||||
|
you could not write things like the following; now you can:
|
||||||
|
|
||||||
|
REM Tue AT 11:30 DURATION 0:30 MSG Thing 1
|
||||||
|
REM Tue AT [trigtime()+trigduration()] DURATION 1:00 MSG Thing 2
|
||||||
|
REM Tue AT [trigtime()+trigduration()] DURATION 0:45 MSG Thing 3
|
||||||
|
|
||||||
|
for successive reminders that should be moved as a block if the time of
|
||||||
|
the first one changes.
|
||||||
|
|
||||||
|
* BUG FIX: Don't update trigdate() or trigtime() while parsing a REM
|
||||||
|
statement... only when actually computing the trigger.
|
||||||
|
|
||||||
|
* VERSION 4.3 Patch 6 - 2024-04-02
|
||||||
|
|
||||||
|
* NEW FILE: Add [$SysInclude]/holidays/pt.rem - Portuguese holidays, courtesy
|
||||||
|
of Joop Kiefte.
|
||||||
|
|
||||||
|
* BUG FIX: remind: Fix compile error on systems that don't support inotify(7).
|
||||||
|
|
||||||
|
* BUG FIX: remind: Fix test failures on FreeBSD. On FreeBSD, you have to copy
|
||||||
|
the result of getenv() or else a subsequent setenv() can change the stored
|
||||||
|
value.
|
||||||
|
|
||||||
|
* VERSION 4.3 Patch 5 - 2024-04-01
|
||||||
|
|
||||||
|
* IMPROVEMENT: remind: Use inotify to detect reminder file changes
|
||||||
|
even in regular daemon mode (-zn where n>0).
|
||||||
|
|
||||||
|
* INTERNAL IMPROVEMENTS: Rearrange and refactor some code.
|
||||||
|
|
||||||
|
* FIXES: Various fixes and improvements to man pages.
|
||||||
|
|
||||||
|
* BUG FIX: remind: Handle queued "SPECIAL COLOR" reminders correctly.
|
||||||
|
|
||||||
|
* BUG FIX: remind: Preserve the value of $DefaultColor that was in effect
|
||||||
|
when a reminder was queued; restore it before issuing the queued reminder.
|
||||||
|
|
||||||
|
* VERSION 4.3 Patch 4 - 2024-03-25
|
||||||
|
|
||||||
|
* NEW FEATURE: remind: Add the new "multitrig" function, which is how "trig"
|
||||||
|
should have worked in the first place. See man page for details.
|
||||||
|
|
||||||
|
* IMPROVEMENT: tkremind: Make errors in your reminders file stand out more
|
||||||
|
prominently.
|
||||||
|
|
||||||
|
* IMPROVEMENT: tkremind: If you click on an error in the "Errors..." popup,
|
||||||
|
tkremind will open a text editor on the offending file and line.
|
||||||
|
|
||||||
|
* IMPROVEMENT: tkremind: Format the "Queue..." output better and make queue
|
||||||
|
items clickable; clicking on a queue item opens a text editor on the
|
||||||
|
corresponding file and line.
|
||||||
|
|
||||||
|
* IMPROVEMENT: Add a standard [$SysInclude]/moonphases.rem file to display
|
||||||
|
moon phases on your calendar.
|
||||||
|
|
||||||
|
* IMPROVEMENT: Clean up the demo code in www/ and add PDF output.
|
||||||
|
|
||||||
|
* BUG FIX: tkremind: Correctly handle filenames containing spaces and other
|
||||||
|
characters that tend to confuse the shell.
|
||||||
|
|
||||||
|
* BUG FIX: tkremind: Raise dialog boxes after errors so that they
|
||||||
|
remain visible.
|
||||||
|
|
||||||
|
* CLEANUP: tkremind: Remove some dead code.
|
||||||
|
|
||||||
|
* VERSION 4.3 Patch 3 - 2024-03-18
|
||||||
|
|
||||||
|
* IMPROVEMENT: tkremind: Update icon to include a white border so it shows
|
||||||
|
up better on dark backgrounds.
|
||||||
|
|
||||||
|
* IMPROVEMENT: C code: Fix a number of cppcheck static-analysis warnings.
|
||||||
|
|
||||||
|
* IMPROVEMENT: remind: Update the "-zj" protocol to include a queue-id for
|
||||||
|
each queued reminder and add the DEL client command to delete a specific
|
||||||
|
item from the queue. Used by tkremind to implement "don't remind me about
|
||||||
|
this again today."
|
||||||
|
|
||||||
|
* MINOR NEW FEATURE: Add a "-ds" debugging flag to print out expression-parsing
|
||||||
|
stack high-water marks on exit. This esoteric feature is of no use to
|
||||||
|
anyone but the Remind author.
|
||||||
|
|
||||||
|
* IMPROVEMENT: tkremind: Stop using the deprecated tk_dialog command in favor
|
||||||
|
of the newer tk_messageBox command.
|
||||||
|
|
||||||
|
* IMPROVEMENT: remind: In server mode, try to minimize redraws by
|
||||||
|
consuming inotify events until at least 0.2s elapses without an
|
||||||
|
event appearing.
|
||||||
|
|
||||||
|
* BUG FIX: tkremind: The "Don't remind me about this again today" feature
|
||||||
|
was unreliable and only worked for reminders created with TkRemind itself.
|
||||||
|
It has been made more reliable and works with any reminder.
|
||||||
|
|
||||||
|
* BUG FIX: remind: Make it a syntax error if a local OMIT in a REM statement
|
||||||
|
is not followed by at least one weekday name.
|
||||||
|
|
||||||
|
* VERSION 4.3 Patch 2 - 2024-03-01
|
||||||
|
|
||||||
|
- BUG FIX: remind: Fix a logic error when implementing the RUN command in
|
||||||
|
server mode. As it turns out, the error is harmless, but it's best to do
|
||||||
|
things correctly.
|
||||||
|
|
||||||
|
- BUG FIX: The Makefile would install the tkremind.png and tkremind.desktop
|
||||||
|
files in the wrong location. This has been fixed.
|
||||||
|
|
||||||
|
* VERSION 4.3 Patch 1 - 2024-02-29
|
||||||
|
|
||||||
|
- BUG FIX: tests: "make test" could fail because of a bad test. This
|
||||||
|
has been fixed. There are no actual code changes to any of the programs
|
||||||
|
in Remind compared to 04.03.00.
|
||||||
|
|
||||||
|
* VERSION 4.3 Patch 0 - 2024-02-29
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: If Remind is compiled on a system that supports
|
||||||
|
inotify, then in server mode (-z0 or -zj) it monitors the reminders file
|
||||||
|
and restarts itself if it detects a change, and also notifies the client.
|
||||||
|
Moving inotify support directly into Remind means that tkremind no longer
|
||||||
|
has to invoke a separate inotifywait process.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Set the CLOEXEC flag on files we open so we
|
||||||
|
don't leak file descriptors to programs that we run. While I don't
|
||||||
|
think there's a security issue here (any program you run can do
|
||||||
|
anything as your userid anyway) it's best to be clean and tidy.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Add localization for the Catalan language, courtesy
|
||||||
|
of Eloi Torrents.
|
||||||
|
|
||||||
|
- IMPROVEMENT: tkremind: Add a .desktop file and icon so TkRemind can be
|
||||||
|
integrated into the desktop menu system, courtesy of Eloi Torrents.
|
||||||
|
|
||||||
|
- CHANGE: Add a new server mode with the "-zj" flag. This is just
|
||||||
|
like "-z0" except it uses JSON messages to communicate with the
|
||||||
|
client rather than an ad-hoc protocol. The "-z0" mode is still
|
||||||
|
supported, but is deprecated.
|
||||||
|
|
||||||
|
- CHANGE: In server mode (-z0 or -zj) any RUN-type reminders, or message
|
||||||
|
commands of the "-kcommand" type are run with standard input and standard
|
||||||
|
output connected to /dev/null. NOTE INCOMPATIBILITY: If you previously
|
||||||
|
relied on RUN-type reminders to pop up reminders in TkRemind, they no
|
||||||
|
longer do. If you want this, you'll have to get the command that you
|
||||||
|
run to pop up its own window with "xmessage" or something similar.
|
||||||
|
|
||||||
|
- IMPROVEMENT: tkremind: Make the "Go to date..." dialog non-modal.
|
||||||
|
|
||||||
|
- CHANGE: remind: Allow the argument to easterdate() and
|
||||||
|
orthodoxeaster() to be omitted, in which case it defaults to
|
||||||
|
today().
|
||||||
|
|
||||||
|
- BUG FIX: Miscellaneous man page fixes.
|
||||||
|
|
||||||
|
- BUG FIX: Fix a leap-year edge-case. The reminder: REM 29 MSG whatever
|
||||||
|
was not triggered on Feb 29 of leap years.
|
||||||
|
|
||||||
|
- BUG FIX: rem2html: Make the version of rem2html track the version of
|
||||||
|
Remind. Noted by Ian! D. Allen.
|
||||||
|
|
||||||
|
* VERSION 4.2 Patch 9 - 2024-02-04
|
||||||
|
|
||||||
|
- CHANGE: remind: Do not attempt to guess terminal background color on
|
||||||
|
startup. Only obtain it as needed. This can prevent mojibake from
|
||||||
|
appearing on terminals that don't support the color query escape
|
||||||
|
sequence.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Add new system variables $NumFullOmits,
|
||||||
|
$MaxFullOmits, $NumPartialOmits and $MaxPartialOmits.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Issue a warning if someone OMITs every possible date.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: In several error messages complaining about limits
|
||||||
|
being exceeded, include the actual limit in the error message. Clarify
|
||||||
|
the man page regarding limits on the number of OMITs.
|
||||||
|
|
||||||
|
- MINOR NEW FEATURE: remind: The expression STRING * INT or INT * STRING
|
||||||
|
is now accepted and yields a string that is INT concatenations of the
|
||||||
|
original STRING. In this case, INT must be non-negative and the total
|
||||||
|
string length can't exceed $MaxStringLen.
|
||||||
|
|
||||||
|
- DOCUMENTATION: Add "Astronomical Algorithms" by Jean Meeus to bibliography.
|
||||||
|
|
||||||
|
- DOCUMENTATION FIX: Update address of the Free Software Foundation in the
|
||||||
|
license file.
|
||||||
|
|
||||||
|
- DOCUMENTATION: Note that rem2ps is deprecated and will not received any
|
||||||
|
new features. Further development will happen on rem2pdf.
|
||||||
|
|
||||||
|
- BUG FIX: Preserve the filename() and priority context for queued reminders.
|
||||||
|
Previously, the filename information was lost and the priority was
|
||||||
|
coming from uninitialized memory (yikes!). bug found by Alexander
|
||||||
|
Möller.
|
||||||
|
|
||||||
|
- BUG FIX: build.tk: Various minor improvements.
|
||||||
|
|
||||||
|
- BUG FIX: remind: In server mode, if we de-queue a reminder without
|
||||||
|
triggering it, issue a "NOTE queued %d" message to update the
|
||||||
|
client's notion of the queue size.
|
||||||
|
|
||||||
|
- BUG FIX: tkremind: Fix typo found by Lorenzo Bazzanini.
|
||||||
|
|
||||||
* VERSION 4.2 Patch 8 - 2023-12-14
|
* VERSION 4.2 Patch 8 - 2023-12-14
|
||||||
|
|
||||||
- NEW FEATURE: Add the $MaxLateMinutes system variable. This suppresses
|
- NEW FEATURE: Add the $MaxLateMinutes system variable. This suppresses
|
||||||
|
|||||||
@@ -16,7 +16,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-2023 Dianne Skoll #
|
# Copyright (C) 1992-2024 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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 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")
|
||||||
|
|||||||
@@ -106,7 +106,3 @@ IF !Reform
|
|||||||
[_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b.
|
[_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b.
|
||||||
[_PastSat(9, "Av")] ++4 MSG %"Tish'a B'Av%" is %b.
|
[_PastSat(9, "Av")] ++4 MSG %"Tish'a B'Av%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
# Clean up
|
|
||||||
FUNSET _h _h2 _PastSat _BackTwoFri _BackTwoSat _chan
|
|
||||||
|
|
||||||
|
|||||||
17
include/holidays/pt.rem
Normal file
17
include/holidays/pt.rem
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Portuguese holidays
|
||||||
|
# Courtesy of Joop Kiefte
|
||||||
|
|
||||||
|
OMIT 1 Jan MSG Ano Novo
|
||||||
|
OMIT [easterdate()-47] MSG Carnaval
|
||||||
|
OMIT [easterdate()-2] MSG Sexta-feira Santa
|
||||||
|
OMIT [easterdate()] MSG Domingo de Páscoa
|
||||||
|
OMIT 25 Apr MSG Dia da Liberdade
|
||||||
|
OMIT 1 May MSG Dia do Trabalhador
|
||||||
|
OMIT [easterdate()+60] MSG Corpo de Deus
|
||||||
|
OMIT 10 Jun MSG Dia de Portugal, de Camões e das Comunidades Portuguesas
|
||||||
|
OMIT 15 Aug MSG Assunção de Nossa Senhora
|
||||||
|
OMIT 5 Oct MSG Implantação da República
|
||||||
|
OMIT 1 Nov MSG Dia de Todos os Santos
|
||||||
|
OMIT 1 Dec MSG Restauração da Independência
|
||||||
|
OMIT 8 Dec MSG Imaculada Conceição
|
||||||
|
OMIT 25 Dec MSG Natal
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# US holidays
|
# US holidays
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# Copyright (C) 1992-2023 Dianne Skoll
|
# Copyright (C) 1992-2024 Dianne Skoll
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
REM [easterdate($Uy)-46] MSG Ash Wednesday
|
REM [easterdate($Uy)-46] MSG Ash Wednesday
|
||||||
|
|||||||
@@ -1,24 +1,28 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
SET autolang getenv("REMIND_LANG")
|
if !defined("__autolang__")
|
||||||
|
SET __autolang__ 1
|
||||||
|
PRESERVE __autolang__
|
||||||
|
SET autolang getenv("REMIND_LANG")
|
||||||
|
|
||||||
IF autolang == ""
|
IF autolang == ""
|
||||||
SET autolang getenv("LC_ALL")
|
SET autolang getenv("LC_ALL")
|
||||||
ENDIF
|
ENDIF
|
||||||
IF autolang == ""
|
IF autolang == ""
|
||||||
SET autolang getenv("LANGUAGE")
|
SET autolang getenv("LANGUAGE")
|
||||||
ENDIF
|
ENDIF
|
||||||
IF autolang == ""
|
IF autolang == ""
|
||||||
SET autolang getenv("LANG")
|
SET autolang getenv("LANG")
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
IF autolang != ""
|
IF autolang != ""
|
||||||
IF access($SysInclude + "/lang/" + lower(substr(autolang, 1, 5)) + ".rem", "r") == 0
|
IF access($SysInclude + "/lang/" + lower(substr(autolang, 1, 5)) + ".rem", "r") == 0
|
||||||
INCLUDE [$SysInclude]/lang/[lower(substr(autolang, 1, 5))].rem
|
INCLUDE [$SysInclude]/lang/[lower(substr(autolang, 1, 5))].rem
|
||||||
ELSE
|
ELSE
|
||||||
IF access($SysInclude + "/lang/" + lower(substr(autolang, 1, 2)) + ".rem", "r") == 0
|
IF access($SysInclude + "/lang/" + lower(substr(autolang, 1, 2)) + ".rem", "r") == 0
|
||||||
INCLUDE [$SysInclude]/lang/[lower(substr(autolang, 1, 2))].rem
|
INCLUDE [$SysInclude]/lang/[lower(substr(autolang, 1, 2))].rem
|
||||||
|
ENDIF
|
||||||
ENDIF
|
ENDIF
|
||||||
ENDIF
|
ENDIF
|
||||||
|
UNSET autolang
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
UNSET autolang
|
|
||||||
|
|||||||
53
include/lang/ca.rem
Normal file
53
include/lang/ca.rem
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Support for the Catalan language.
|
||||||
|
# This file is part of REMIND.
|
||||||
|
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
||||||
|
# This file was created by Eloi Torrents <eloitor@disroot.org>
|
||||||
|
|
||||||
|
SET $Monday "dilluns"
|
||||||
|
SET $Tuesday "dimarts"
|
||||||
|
SET $Wednesday "dimecres"
|
||||||
|
SET $Thursday "dijous"
|
||||||
|
SET $Friday "divendres"
|
||||||
|
SET $Saturday "dissabte"
|
||||||
|
SET $Sunday "diumenge"
|
||||||
|
|
||||||
|
SET $January "gener"
|
||||||
|
SET $February "febrer"
|
||||||
|
SET $March "març"
|
||||||
|
SET $April "abril"
|
||||||
|
SET $May "maig"
|
||||||
|
SET $June "juny"
|
||||||
|
SET $July "juliol"
|
||||||
|
SET $August "agost"
|
||||||
|
SET $September "setembre"
|
||||||
|
SET $October "octubre"
|
||||||
|
SET $November "novembre"
|
||||||
|
SET $December "desembre"
|
||||||
|
|
||||||
|
SET $Today "avui"
|
||||||
|
SET $Tomorrow "demà"
|
||||||
|
FSET subst_bx(a,d,t) iif(d==today()+2, "demà passat", "d'aquí " + (d-today()) + " dies")
|
||||||
|
|
||||||
|
# 1 d'abril vs 1 de maig.
|
||||||
|
FSET subst_sx(a,d,t) iif(isany(substr(mon(d), 1, 1), "a", "o") , "d'", "de")
|
||||||
|
FSET subst_ordinal(d) ""
|
||||||
|
|
||||||
|
BANNER Agenda pel %w, %d %s %m de %y%o:
|
||||||
|
|
||||||
|
SET $Am "am"
|
||||||
|
SET $Pm "pm"
|
||||||
|
|
||||||
|
SET $Ago "fa"
|
||||||
|
SET $Fromnow "des d'avui"
|
||||||
|
SET $On "el dia"
|
||||||
|
SET $Now "ara"
|
||||||
|
SET $At "a les"
|
||||||
|
|
||||||
|
SET $Minute "minut"
|
||||||
|
SET $Mplu "s"
|
||||||
|
SET $Hour "hora"
|
||||||
|
FSET subst_hours(h) iif(h==1, "1 hora", h + " hores")
|
||||||
|
|
||||||
|
SET $Is "és"
|
||||||
|
SET $Was "va ser"
|
||||||
|
SET $And "i"
|
||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
||||||
# This file is derived from a translation by Mogens Lynnerup.
|
# This file is derived from a translation by Mogens Lynnerup.
|
||||||
|
|
||||||
SET $Sunday "Søndag"
|
SET $Sunday "Søndag"
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
||||||
# This file is derived from a translation by Wolfgang Thronicke
|
# This file is derived from a translation by Wolfgang Thronicke
|
||||||
|
|
||||||
# Day names
|
# Day names
|
||||||
@@ -87,3 +87,5 @@ SET daylightST_starts_str "Beginn Sommerzeit"
|
|||||||
|
|
||||||
# Daylight saving time ends
|
# Daylight saving time ends
|
||||||
SET daylightST_ends_str "Ende Sommerzeit"
|
SET daylightST_ends_str "Ende Sommerzeit"
|
||||||
|
|
||||||
|
PRESERVE earthseasons_Perihelion_str earthseasons_EquinoxMar_str earthseasons_SolsticeJun_str earthseasons_Aphelion_str earthseasons_EquinoxSep_str earthseasons_SolsticeDec_str daylightST_starts_str daylightST_ends_str
|
||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
||||||
# Nothing to do for English since it is the default.
|
# Nothing to do for English since it is the default.
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 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>
|
||||||
|
|
||||||
SET $Sunday "Domingo"
|
SET $Sunday "Domingo"
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
||||||
# This file is derived from a translation by Mikko Silvonen
|
# This file is derived from a translation by Mikko Silvonen
|
||||||
|
|
||||||
SET $Sunday "sunnuntai"
|
SET $Sunday "sunnuntai"
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
||||||
# This file is derived from a translation by Laurent Duperval
|
# This file is derived from a translation by Laurent Duperval
|
||||||
|
|
||||||
SET $Sunday "dimanche"
|
SET $Sunday "dimanche"
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 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)
|
||||||
|
|
||||||
SET $Sunday "Κυριακή"
|
SET $Sunday "Κυριακή"
|
||||||
@@ -81,3 +81,5 @@ SET daylightST_starts_str "Έναρξη θέρους"
|
|||||||
|
|
||||||
# Daylight saving time ends
|
# Daylight saving time ends
|
||||||
SET daylightST_ends_str "Τέλος θέρους"
|
SET daylightST_ends_str "Τέλος θέρους"
|
||||||
|
|
||||||
|
PRESERVE earthseasons_Perihelion_str earthseasons_EquinoxMar_str earthseasons_SolsticeJun_str earthseasons_Aphelion_str earthseasons_EquinoxSep_str earthseasons_SolsticeDec_str daylightST_starts_str daylightST_ends_str
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 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)
|
||||||
|
|
||||||
SET $Sunday "sunnudagur"
|
SET $Sunday "sunnudagur"
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
||||||
# This file is derived from a translation by Valerio Aimale
|
# This file is derived from a translation by Valerio Aimale
|
||||||
|
|
||||||
SET $Sunday "Domenica"
|
SET $Sunday "Domenica"
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 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
|
||||||
|
|
||||||
SET $Sunday "zondag"
|
SET $Sunday "zondag"
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
||||||
# This file is derived from a translation by Trygve Randen
|
# This file is derived from a translation by Trygve Randen
|
||||||
|
|
||||||
SET $Sunday "Søndag"
|
SET $Sunday "Søndag"
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
||||||
# This file is derived from a translation by Jerzy Sobczyk
|
# This file is derived from a translation by Jerzy Sobczyk
|
||||||
|
|
||||||
SET $Sunday "Niedziela"
|
SET $Sunday "Niedziela"
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
||||||
# This file is derived from a translation by Marco Paganini
|
# This file is derived from a translation by Marco Paganini
|
||||||
|
|
||||||
SET $Sunday "domingo"
|
SET $Sunday "domingo"
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll
|
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
|
||||||
# This file is derived from a translation by Liviu Daia
|
# This file is derived from a translation by Liviu Daia
|
||||||
|
|
||||||
SET $Sunday "Duminică"
|
SET $Sunday "Duminică"
|
||||||
|
|||||||
14
include/moonphases.rem
Normal file
14
include/moonphases.rem
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Moon phases
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
IF $CalMode || $PsCal
|
||||||
|
REM [moondate(0)] SPECIAL MOON 0 -1 -1 [moontime(0)]
|
||||||
|
REM [moondate(1)] SPECIAL MOON 1 -1 -1 [moontime(1)]
|
||||||
|
REM [moondate(2)] SPECIAL MOON 2 -1 -1 [moontime(2)]
|
||||||
|
REM [moondate(3)] SPECIAL MOON 3 -1 -1 [moontime(3)]
|
||||||
|
ELSE
|
||||||
|
REM NOQUEUE [moondatetime(0)] MSG New Moon (%2)
|
||||||
|
REM NOQUEUE [moondatetime(1)] MSG First Quarter (%2)
|
||||||
|
REM NOQUEUE [moondatetime(2)] MSG Full Moon (%2)
|
||||||
|
REM NOQUEUE [moondatetime(3)] MSG Last Quarter (%2)
|
||||||
|
ENDIF
|
||||||
@@ -5,22 +5,25 @@ rem2ps \- draw a PostScript calendar from Remind output
|
|||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B rem2ps [\fIoptions\fR]
|
.B rem2ps [\fIoptions\fR]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
\fBRem2ps\fR reads the standard input, which should be the results of
|
\fBrem2ps\fR reads the standard input, which should be the results of
|
||||||
running \fBRemind\fR with the \fB\-p\fR or \fB\-pp\fR option. It
|
running \fBRemind\fR with the \fB\-p\fR or \fB\-pp\fR option. It
|
||||||
emits PostScript code (which draws a calendar) to the standard output.
|
emits PostScript code (which draws a calendar) to the standard output.
|
||||||
.PP
|
.PP
|
||||||
See the section "Rem2PS Input Format" for details about the \fB\-p\fR
|
Although \fBrem2ps\fR will be maintained, no new features will be added
|
||||||
|
to it. Instead, all new development will continue on \fBrem2pdf\fR.
|
||||||
|
.PP
|
||||||
|
See the section "REM2PS INPUT FORMAT" for details about the \fB\-p\fR
|
||||||
data. This may be useful if you wish to create other \fBRemind\fR
|
data. This may be useful if you wish to create other \fBRemind\fR
|
||||||
back-ends.
|
back-ends.
|
||||||
.PP
|
.PP
|
||||||
Note that \fBRem2PS\fR does not handle UTF-8 input. If you need to
|
Note that \fBrem2ps\fR does not handle UTF-8 input. If you need to
|
||||||
render characters outside the ASCII character set, see
|
render characters outside the ASCII character set, see
|
||||||
\fBrem2pdf\fR instead.
|
\fBrem2pdf\fR instead.
|
||||||
|
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
.B \-v
|
.B \-v
|
||||||
Be more verbose. This causes \fBRem2ps\fR to print progress messages
|
Be more verbose. This causes \fBrem2ps\fR to print progress messages
|
||||||
to the standard error stream. Normally, it is silent.
|
to the standard error stream. Normally, it is silent.
|
||||||
.TP
|
.TP
|
||||||
.B \-p file
|
.B \-p file
|
||||||
@@ -133,7 +136,7 @@ numbers.
|
|||||||
|
|
||||||
.PP
|
.PP
|
||||||
Type "rem2ps \-m help" for a list of available media. Note that the media
|
Type "rem2ps \-m help" for a list of available media. Note that the media
|
||||||
type (and all \fBRem2ps\fR options) are case-sensitive. If you don't use
|
type (and all \fBrem2ps\fR options) are case-sensitive. If you don't use
|
||||||
the \fB\-m\fR option, the media defaults to a compiled-in default - this
|
the \fB\-m\fR option, the media defaults to a compiled-in default - this
|
||||||
is usually Letter for North America and A4 for Europe. The "\-m help"
|
is usually Letter for North America and A4 for Europe. The "\-m help"
|
||||||
option will display the compiled-in default.
|
option will display the compiled-in default.
|
||||||
@@ -193,8 +196,8 @@ for good output:
|
|||||||
rem2ps \-ol 72 \-sh 12
|
rem2ps \-ol 72 \-sh 12
|
||||||
.fi
|
.fi
|
||||||
.SH USAGE
|
.SH USAGE
|
||||||
To use \fBRem2ps\fR, you should pipe the output of \fBRemind\fR with the \fB\-p\fR
|
To use \fBrem2ps\fR, you should pipe the output of \fBRemind\fR with the \fB\-p\fR
|
||||||
option to \fBRem2ps\fR, and then send the result to a printer. This is most easily
|
option to \fBrem2ps\fR, and then send the result to a printer. This is most easily
|
||||||
illustrated with examples:
|
illustrated with examples:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
@@ -228,10 +231,10 @@ calendar entries. This border is normally blank space.
|
|||||||
.TP
|
.TP
|
||||||
BoxWidth and BoxHeight
|
BoxWidth and BoxHeight
|
||||||
The width and height of the calendar box, from center-to-center of the
|
The width and height of the calendar box, from center-to-center of the
|
||||||
black gridlines.
|
black grid lines.
|
||||||
.TP
|
.TP
|
||||||
InBoxHeight
|
InBoxHeight
|
||||||
The height from the center of the bottom black gridline to the top
|
The height from the center of the bottom black grid line to the top
|
||||||
of the regular calendar entry area. The space from here to the top
|
of the regular calendar entry area. The space from here to the top
|
||||||
of the box is used only to draw the day number.
|
of the box is used only to draw the day number.
|
||||||
.TP
|
.TP
|
||||||
@@ -260,7 +263,7 @@ PostScript files. Always test your PostScript thoroughly with a PostScript
|
|||||||
viewer before sending it to the printer. You should not use any document
|
viewer before sending it to the printer. You should not use any document
|
||||||
structuring comments in your PostScript code.
|
structuring comments in your PostScript code.
|
||||||
.PP
|
.PP
|
||||||
In addition, prior to drawing a calendar page, \fBRem2ps\fR emits
|
In addition, prior to drawing a calendar page, \fBrem2ps\fR emits
|
||||||
the following PostScript code:
|
the following PostScript code:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
@@ -320,8 +323,8 @@ For an example, create a file called "myprolog" whose contents are:
|
|||||||
} bind def
|
} bind def
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
Use that file with the \fBRem2ps\fR \fB\-p\fR option to create calendars
|
Use that file with the \fBrem2ps\fR \fB\-p\fR option to create calendars
|
||||||
with the year and month in large grey letters in the background of the
|
with the year and month in large gray letters in the background of the
|
||||||
calendar.
|
calendar.
|
||||||
.PP
|
.PP
|
||||||
.SH REM2PS INPUT FORMAT (-P OPTION)
|
.SH REM2PS INPUT FORMAT (-P OPTION)
|
||||||
@@ -380,7 +383,7 @@ been set to "-". The consistent use of "/" is designed to ease parsing.
|
|||||||
.PP
|
.PP
|
||||||
\fIspecial\fR is a string used
|
\fIspecial\fR is a string used
|
||||||
for "out-of-band" communication with back-ends. If the reminder
|
for "out-of-band" communication with back-ends. If the reminder
|
||||||
is a normal reminder, \fIspecial\fR is "*". The \fBRem2PS\fR
|
is a normal reminder, \fIspecial\fR is "*". The \fBrem2ps\fR
|
||||||
back-end understands the specials \fBPostScript\fR and \fBPSFile\fR.
|
back-end understands the specials \fBPostScript\fR and \fBPSFile\fR.
|
||||||
Other back-ends may understand other specials. A back end should
|
Other back-ends may understand other specials. A back end should
|
||||||
\fIsilently ignore\fR a reminder with a special it doesn't understand.
|
\fIsilently ignore\fR a reminder with a special it doesn't understand.
|
||||||
@@ -674,17 +677,17 @@ is desired.
|
|||||||
|
|
||||||
|
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Rem2PS was written by Dianne Skoll <dianne@skoll.ca>
|
rem2ps was written by Dianne Skoll <dianne@skoll.ca>
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
All \fBRem2ps\fR options are case-sensitive, unlike \fBRemind\fR.
|
All \fBrem2ps\fR options are case-sensitive, unlike \fBRemind\fR.
|
||||||
Any time you supply
|
Any time you supply
|
||||||
a font name or size, line thickness, or border width, it is treated as a
|
a font name or size, line thickness, or border width, it is treated as a
|
||||||
string and sent straight to the PostScript interpreter. Thus, if you
|
string and sent straight to the PostScript interpreter. Thus, if you
|
||||||
supply invalid fonts or sizes, \fBRem2ps\fR will not complain, but the
|
supply invalid fonts or sizes, \fBrem2ps\fR will not complain, but the
|
||||||
resulting PostScript output will probably not work.
|
resulting PostScript output will probably not work.
|
||||||
.PP
|
.PP
|
||||||
You should ensure that the values you supply for margin widths are sensible.
|
You should ensure that the values you supply for margin widths are sensible.
|
||||||
If they are too big for the media size, \fBRem2ps\fR will not complain,
|
If they are too big for the media size, \fBrem2ps\fR will not complain,
|
||||||
but again, the PostScript output will probably not work.
|
but again, the PostScript output will probably not work.
|
||||||
.SH HOME PAGE
|
.SH HOME PAGE
|
||||||
https://dianne.skoll.ca/projects/remind/
|
https://dianne.skoll.ca/projects/remind/
|
||||||
|
|||||||
354
man/remind.1.in
354
man/remind.1.in
@@ -28,10 +28,6 @@ Anything after the __EOF__ marker is completely ignored.
|
|||||||
\fBRemind\fR has a slew of options. If you're new to the program,
|
\fBRemind\fR has a slew of options. If you're new to the program,
|
||||||
ignore them for now and skip to the section "REMINDER FILES".
|
ignore them for now and skip to the section "REMINDER FILES".
|
||||||
.TP
|
.TP
|
||||||
.B \-\-version
|
|
||||||
The \fB\-\-version\fR option causes \fBRemind\fR to print its version number
|
|
||||||
to standard output and then exit.
|
|
||||||
.TP
|
|
||||||
.B \-n
|
.B \-n
|
||||||
The \fB\-n\fR option causes \fBRemind\fR to print the \fBnext\fR occurrence
|
The \fB\-n\fR option causes \fBRemind\fR to print the \fBnext\fR occurrence
|
||||||
of each reminder in a simple calendar format. You can sort this by
|
of each reminder in a simple calendar format. You can sort this by
|
||||||
@@ -66,7 +62,7 @@ causes \fBRemind\fR to display reminders on the calendar on the
|
|||||||
day they actually occur \fIas well as\fR on any preceding days
|
day they actually occur \fIas well as\fR on any preceding days
|
||||||
specified by the reminder's \fIdelta\fR. This \fIalso\fR causes
|
specified by the reminder's \fIdelta\fR. This \fIalso\fR causes
|
||||||
\fBRemind\fR to include text outside %"...%" sequences that would
|
\fBRemind\fR to include text outside %"...%" sequences that would
|
||||||
otherwise be removed (though the actual %" markers themselves are removed.)
|
otherwise be removed (though the actual %" markers themselves are removed.) \"" Add comment to avoid Emacs highlighting problems
|
||||||
.TP
|
.TP
|
||||||
.B 'l'
|
.B 'l'
|
||||||
causes \fBRemind\fR to use VT100 line-drawing characters to draw
|
causes \fBRemind\fR to use VT100 line-drawing characters to draw
|
||||||
@@ -300,6 +296,11 @@ Echo lines when displaying error messages
|
|||||||
.TP
|
.TP
|
||||||
.B f
|
.B f
|
||||||
Trace the reading of reminder files
|
Trace the reading of reminder files
|
||||||
|
.TP
|
||||||
|
.B s
|
||||||
|
Trace expression parsing and display the internal expression node
|
||||||
|
tree. This is unlikely to be useful unless you are working on
|
||||||
|
\fBRemind\fR's expression evaluation engine.
|
||||||
.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]]]]
|
||||||
@@ -361,16 +362,24 @@ You use both \fB\-k\fR\fIcmd1\fR and \fB\-k:\fR\fIcmd2\fR to use different
|
|||||||
commands for queued versus non-queued reminders.
|
commands for queued versus non-queued reminders.
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
\fB\-z\fR[\fIn\fR] Runs \fBRemind\fR in the daemon mode. If \fIn\fR
|
\fB\-z\fR[\fIn\fR] Runs \fBRemind\fR in "daemon mode". If \fIn\fR
|
||||||
is supplied, it specifies how often (in minutes) \fBRemind\fR should
|
is supplied, it specifies how often (in minutes) \fBRemind\fR should
|
||||||
wake up to check if the reminder script has been changed. \fIN\fR
|
wake up to check if the reminder script has been changed. \fIN\fR
|
||||||
defaults to 1, and can range from 1 to 60. Note that the use of the
|
defaults to 1, and can range from 1 to 60. Note that the use of the
|
||||||
\fB\-z\fR option also enables the \fB\-f\fR option.
|
\fB\-z\fR option also enables the \fB\-f\fR option.
|
||||||
.PP
|
.PP
|
||||||
.RS
|
.RS
|
||||||
If you supply the option \fB\-z0\fR, \fBRemind\fR runs in a
|
If \fBRemind\fR is compiled on a system that supports
|
||||||
|
\fBinotify\fR(7), then if the reminder script supplied on the
|
||||||
|
command-line is actually a directory, \fBRemind\fR additionally checks
|
||||||
|
if all files within that directory have been modified since startup.
|
||||||
|
.PP
|
||||||
|
If you supply the option \fB\-zj\fR, \fBRemind\fR runs in a
|
||||||
special mode called \fBserver mode\fR. This is documented
|
special mode called \fBserver mode\fR. This is documented
|
||||||
in the tkremind man page; see tkremind(1).
|
in the tkremind man page; see tkremind(1). The older server mode
|
||||||
|
option \fB\-z0\fR still works, but is deprecated; it uses an ad-hoc
|
||||||
|
method to communicate with the client rather than using JSON to communicate
|
||||||
|
with the client.
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
\fB\-u\fR\fIname\fR
|
\fB\-u\fR\fIname\fR
|
||||||
@@ -407,7 +416,9 @@ TAG clause.
|
|||||||
\fB\-i\fR\fIvar\fR\fB=\fR\fIexpr\fR
|
\fB\-i\fR\fIvar\fR\fB=\fR\fIexpr\fR
|
||||||
Sets the value of the specified \fIvar\fR to \fIexpr\fR, and \fBpreserves\fR
|
Sets the value of the specified \fIvar\fR to \fIexpr\fR, and \fBpreserves\fR
|
||||||
\fIvar\fR. \fIExpr\fR can be any valid \fBRemind\fR expression. See the
|
\fIvar\fR. \fIExpr\fR can be any valid \fBRemind\fR expression. See the
|
||||||
section "INITIALIZING VARIABLES ON THE COMMAND LINE" for more details.
|
section "INITIALIZING VARIABLES ON THE COMMAND LINE" for more details. If
|
||||||
|
you omit the \fB=\fR\fIexpr\fR part, then \fIvar\fR is initialized to 0.
|
||||||
|
In other words, \fB\-i\fIvar\fR is exactly the same as \fB\-i\fIvar\fR\fB=\fR0.
|
||||||
.TP
|
.TP
|
||||||
\fB\-i\fR\fIfunc\fR(\fIargs\fR)=\fIdefinition\fR
|
\fB\-i\fR\fIfunc\fR(\fIargs\fR)=\fIdefinition\fR
|
||||||
Allows you to define a function on the command line.
|
Allows you to define a function on the command line.
|
||||||
@@ -438,6 +449,30 @@ with the date incrementing on each iteration. You may have to enclose
|
|||||||
the parameter in quotes to avoid shell expansion. See the subsection
|
the parameter in quotes to avoid shell expansion. See the subsection
|
||||||
"Repeated Execution" in the section "CALENDAR MODE" for more
|
"Repeated Execution" in the section "CALENDAR MODE" for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
|
.SH LONG OPTIONS
|
||||||
|
|
||||||
|
\fBRemind\fR supports the following long options, which \fIare\fR
|
||||||
|
case-sensitive:
|
||||||
|
|
||||||
|
.RP
|
||||||
|
.B \-\-version
|
||||||
|
The \fB\-\-version\fR option causes \fBRemind\fR to print its version number
|
||||||
|
to standard output and then exit.
|
||||||
|
.TP
|
||||||
|
.B \-\-max-execution-time\fR=\fIn\fR
|
||||||
|
Limit the total execution time (as measured by the wall clock) to
|
||||||
|
\fIn\fR seconds. This is useful if \fBRemind\fR is invoked on
|
||||||
|
potentially-untrustworthy files that could attempt to use a lot of
|
||||||
|
resources. Note that the limit \fIn\fR is approximate and
|
||||||
|
\fBRemind\fR might execute for one or two more seconds before it is
|
||||||
|
killed. If \fIn\fR is specified as zero, then no limit is applied, just
|
||||||
|
as if the option had not been used at all.
|
||||||
|
.PP
|
||||||
|
If a limit is applied, it applies only to the foreground run of \fBRemind\fR.
|
||||||
|
If \fBRemind\fR finishes processing the script and then starts handling
|
||||||
|
queued reminders, the time limit is reset to no limit.
|
||||||
|
.PP
|
||||||
.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
|
||||||
@@ -446,14 +481,14 @@ text editor capable of creating plain-text files to create a
|
|||||||
very simple and almost immediately understandable:
|
very simple and almost immediately understandable:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
REM 6 Jan MSG Dianne's birthday
|
REM Mar 31 MSG International Transgender Day of Visibility
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
to the baroque and obscure:
|
to the baroque and obscure:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
REM [date(thisyear, 1, 1) + 180] ++5 OMIT \\
|
REM [date(thisyear, 1, 1) + 180] ++5 OMIT \\
|
||||||
sat sun BEFORE MSG [ord(thisyear-1980)] payment due %b!
|
sat sun BEFORE MSG [ord(thisyear-1980)] payment due %b!
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
A reminder file consists of commands, with one command per line. Several
|
A reminder file consists of commands, with one command per line. Several
|
||||||
@@ -1138,7 +1173,7 @@ reminder is queued for later activation. When \fBRemind\fR has
|
|||||||
finished processing the reminder file, it puts itself in the
|
finished processing the reminder file, it puts itself in the
|
||||||
background, and activates timed reminders when the system time reached
|
background, and activates timed reminders when the system time reached
|
||||||
the specified time. Note that if you use the \fBNOQUEUE\fR modifier
|
the specified time. Note that if you use the \fBNOQUEUE\fR modifier
|
||||||
in the \fBREM\fR command, then this queueing and background activation
|
in the \fBREM\fR command, then this queuing and background activation
|
||||||
is \fInot\fR performed. \fBNOQUEUE\fR is useful if you want a time
|
is \fInot\fR performed. \fBNOQUEUE\fR is useful if you want a time
|
||||||
to be associated with a reminder (eg, in the calendar) but are not
|
to be associated with a reminder (eg, in the calendar) but are not
|
||||||
interested in a popup reminder happening at the specified time.
|
interested in a popup reminder happening at the specified time.
|
||||||
@@ -1210,7 +1245,9 @@ in the bodies of timed reminders, then when the timed reminders are
|
|||||||
activated, the variables and functions have the definitions that were
|
activated, the variables and functions have the definitions that were
|
||||||
in effect at the end of the reminder script. These definitions may
|
in effect at the end of the reminder script. These definitions may
|
||||||
\fInot\fR necessarily be those that were in effect at the time the reminder
|
\fInot\fR necessarily be those that were in effect at the time the reminder
|
||||||
was queued.
|
was queued. In addition, the OMIT context is whatever was in effect at
|
||||||
|
the end of the reminder script, which may not necessarily be the same
|
||||||
|
as when the \fBREM\fR command was first processed.
|
||||||
.PP
|
.PP
|
||||||
.B THE SCHED AND WARN KEYWORDS
|
.B THE SCHED AND WARN KEYWORDS
|
||||||
.PP
|
.PP
|
||||||
@@ -1704,6 +1741,11 @@ For example, the following sequences are equivalent:
|
|||||||
OMIT 3 Jan 2011 THROUGH 5 Jan 2011
|
OMIT 3 Jan 2011 THROUGH 5 Jan 2011
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
|
Note that \fBRemind\fR has a compiled-in limit to the number of full
|
||||||
|
OMITs. If you omit a range of \fIN\fR fully-specified (ie, year
|
||||||
|
included) days, then \fIN\fR full OMITs are used up. Trying to omit a
|
||||||
|
very large range may result in the error "Too many full OMITs"
|
||||||
|
.PP
|
||||||
You can make a THROUGH \fBOMIT\fR do double-duty as a \fBREM\fR command as
|
You can make a THROUGH \fBOMIT\fR do double-duty as a \fBREM\fR command as
|
||||||
long as both dates are fully specified
|
long as both dates are fully specified
|
||||||
.PP
|
.PP
|
||||||
@@ -1860,24 +1902,6 @@ If you run \fBRemind\fR with the \fB\-r\fR command-line option,
|
|||||||
regardless of any \fBRUN\fR commands in the reminder script. However,
|
regardless of any \fBRUN\fR commands in the reminder script. However,
|
||||||
any command supplied with the \fB\-k\fR option will still be executed.
|
any command supplied with the \fB\-k\fR option will still be executed.
|
||||||
.PP
|
.PP
|
||||||
One use of the \fBRUN\fR command is to provide a secure interface
|
|
||||||
between \fBRemind\fR and the \fBElm\fR mail system. The \fBElm\fR
|
|
||||||
system can automatically scan incoming mail for reminder or calendar
|
|
||||||
entries, and place them in your calendar file. To use this feature,
|
|
||||||
you should set the calendar filename option under \fBElm\fR to be something
|
|
||||||
like "~/.reminders.in", \fInot\fR your main reminder file! This is
|
|
||||||
so that any \fBRUN ON\fR commands mailed to you can never be activated.
|
|
||||||
.PP
|
|
||||||
Then, you can use the \fBElm\fR \fIscan message for calendar entries\fR
|
|
||||||
command to place reminders prefaced by "->" into .reminders.in. In
|
|
||||||
your main .reminders file, include the following lines:
|
|
||||||
.PP
|
|
||||||
.nf
|
|
||||||
RUN OFF # Disable RUN
|
|
||||||
INCLUDE .reminders.in
|
|
||||||
RUN ON # Re-enable RUN
|
|
||||||
.fi
|
|
||||||
.PP
|
|
||||||
In addition, \fBRemind\fR contains a few other security
|
In addition, \fBRemind\fR contains a few other security
|
||||||
features. It will not read a file that is group- or world-writable.
|
features. It will not read a file that is group- or world-writable.
|
||||||
It will not run set-uid. If it reads a file you don't own, it will
|
It will not run set-uid. If it reads a file you don't own, it will
|
||||||
@@ -1889,6 +1913,30 @@ attempt to check the ownership of standard input, even if it is
|
|||||||
coming from a file, and hence does \fInot\fR disable RUN and shell()
|
coming from a file, and hence does \fInot\fR disable RUN and shell()
|
||||||
in this situation.
|
in this situation.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.SH THE EXPR COMMAND
|
||||||
|
.PP
|
||||||
|
\fBRemind\fR lets you completely disable expression evaluation. This
|
||||||
|
could be useful if you are running Remind on a somewhat-untrustworthy
|
||||||
|
file that is not expected to contain expressions. To disable
|
||||||
|
expression evaluation, use:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
EXPR OFF
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
If \fBRemind\fR encounters an expression while EXPR OFF is in effect, it
|
||||||
|
returns an error
|
||||||
|
.PP
|
||||||
|
To re-enable expression evaluation, use:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
EXPR ON
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
As with \fBRUN ON\fB, \fBEXPR ON\fR can be used only in the top-level
|
||||||
|
script, not in an included file.
|
||||||
|
.PP
|
||||||
.SH THE INCLUDECMD COMMAND
|
.SH THE INCLUDECMD COMMAND
|
||||||
.PP
|
.PP
|
||||||
\fBRemind\fR allows you to execute a shell command and evaluate the
|
\fBRemind\fR allows you to execute a shell command and evaluate the
|
||||||
@@ -2141,13 +2189,13 @@ than those on higher lines. The operators approximately correspond to
|
|||||||
C operators.
|
C operators.
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
! - (unary logical negation and arithmetic negation)
|
! - (unary logical negation and arithmetic negation)
|
||||||
* / %
|
* / % (multiplication, division, modulus)
|
||||||
+ -
|
+ - (addition/concatenation, subtraction)
|
||||||
< <= > >=
|
< <= > >= (comparisons)
|
||||||
== !=
|
== != (equality and inequality tests)
|
||||||
&&
|
&& (logical AND)
|
||||||
||
|
|| (logical OR)
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
.B DESCRIPTION OF OPERATORS
|
.B DESCRIPTION OF OPERATORS
|
||||||
@@ -2162,7 +2210,10 @@ Unary minus. Can be applied to an \fBINT\fR. Returns the negative
|
|||||||
of the operand.
|
of the operand.
|
||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
Multiplication. Returns the product of two \fBINT\fRs.
|
Multiplication. Returns the product of two \fBINT\fRs. Alternatively, if
|
||||||
|
one argument is a \fBSTRING\fR and the other an \fBINT\fR, returns a
|
||||||
|
\fBSTRING\fR consisting of the INT number of repeats of the original STRING.
|
||||||
|
In this case, the INT argument cannot be negative.
|
||||||
.TP
|
.TP
|
||||||
.B /
|
.B /
|
||||||
Integer division. Returns the quotient of two \fBINT\fRs, discarding the
|
Integer division. Returns the quotient of two \fBINT\fRs, discarding the
|
||||||
@@ -2256,16 +2307,15 @@ If the operands are not of the same type, == returns 0 and != returns
|
|||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B &&
|
.B &&
|
||||||
This is the logical AND operator. Both of its operands must be of the
|
This is the logical AND operator. Neither of its operands can be
|
||||||
same type and must not be \fBSTRING\fR type. Returns the second
|
\fBSTRING\fR type. Returns the second operand if both operands are
|
||||||
operand if both operands are non-zero. Otherwise, returns a zero
|
non-zero. Otherwise, returns whichever operand is zero.
|
||||||
of the same type as the operands.
|
|
||||||
.TP
|
.TP
|
||||||
.B ||
|
.B ||
|
||||||
This is the logical OR operator. Both of its operands must be of
|
This is the logical OR operator. Neither of its operands can be
|
||||||
the same type and must not be of \fBSTRING\fR type. It returns
|
\fBSTRING\fR type. It returns the first operand that is non-zero; if
|
||||||
the first operand that is non-zero; if both operands are zero, then
|
both operands are zero, then returns the second operand.
|
||||||
returns a zero of the same type as the operands.
|
|
||||||
.PP
|
.PP
|
||||||
.B NOTES
|
.B NOTES
|
||||||
.PP
|
.PP
|
||||||
@@ -2286,15 +2336,10 @@ For example:
|
|||||||
12:59 + (1 + "test") yields "12:591test"
|
12:59 + (1 + "test") yields "12:591test"
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
The logical operators are \fInot\fR so-called short-circuit operators, as
|
The logical operators are so-called short-circuit operators, as
|
||||||
they are in C. Both operands are always evaluated. Thus, an expression
|
they are in C. This means that if the first operand of || is true,
|
||||||
such as:
|
then the second operand is \fInot\fR evaluated. Similarly, if the first
|
||||||
.PP
|
operand of && is false, then the second operand is \fInot\fR evaluated.
|
||||||
.nf
|
|
||||||
(f!=0) && (100/f <= 3)
|
|
||||||
.fi
|
|
||||||
.PP
|
|
||||||
will cause an error if f is zero.
|
|
||||||
.PP
|
.PP
|
||||||
.B VARIABLES
|
.B VARIABLES
|
||||||
.PP
|
.PP
|
||||||
@@ -2376,9 +2421,9 @@ Universal Time Coordinated in the \fB$MinsFromUTC\fR system variable.
|
|||||||
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 $Daemon (read-only)
|
.B $Daemon (read-only)
|
||||||
If the 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.
|
0. In server mode (either \fB-z0\fR or \fB-zj\fR), contains -1.
|
||||||
.TP
|
.TP
|
||||||
.B $DateSep
|
.B $DateSep
|
||||||
This variable can be set only to "/" or "-". It holds the character
|
This variable can be set only to "/" or "-". It holds the character
|
||||||
@@ -2451,6 +2496,14 @@ because the final parenthesis and quote are ignored (for the purposes
|
|||||||
of spacing) when they follow a period.
|
of spacing) when they follow a period.
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
|
.B $ExpressionTimeLimit
|
||||||
|
If set to a non-zero value \fIn\fR, than any expression that takes longer than
|
||||||
|
\fIn\fR seconds to evaluate will be aborted and an error returned. This is
|
||||||
|
to prevent maliciously-crafted expressions for creating a denial-of-service.
|
||||||
|
In an included file, $ExpressionTimeLimit can only be lowered from its
|
||||||
|
current value. In the top-level file, it can be set to any value, including
|
||||||
|
zero to disable the time limit.
|
||||||
|
.TP
|
||||||
.B $FirstIndent
|
.B $FirstIndent
|
||||||
The number of spaces by which to indent the first line of a \fBMSF\fR-type
|
The number of spaces by which to indent the first line of a \fBMSF\fR-type
|
||||||
reminder. The default is 0.
|
reminder. The default is 0.
|
||||||
@@ -2588,7 +2641,9 @@ The maximum number of iterations for the \fBSATISFY\fR clause
|
|||||||
A limit on the longest string that \fBRemind\fR will allow you
|
A limit on the longest string that \fBRemind\fR will allow you
|
||||||
to create. The default is 65535. If you set \fB$MaxStringLen\fR to 0
|
to create. The default is 65535. If you set \fB$MaxStringLen\fR to 0
|
||||||
or to -1, then \fBremind\fR will allow you to create arbitrarily-long
|
or to -1, then \fBremind\fR will allow you to create arbitrarily-long
|
||||||
strings, at least until it runs out of memory.
|
strings, at least until it runs out of memory. We do not recommend
|
||||||
|
setting \fB$MaxStringLen\fR to 0 or -1 because it is very easy to write
|
||||||
|
code that DOSes \fBRemind\fR in that case.
|
||||||
.TP
|
.TP
|
||||||
.B $MinsFromUTC
|
.B $MinsFromUTC
|
||||||
The number of minutes between Universal Time Coordinated and local time. If
|
The number of minutes between Universal Time Coordinated and local time. If
|
||||||
@@ -2603,6 +2658,18 @@ must also set \fB$CalcUTC\fR to 0 with the \fB\-i\fR option.
|
|||||||
.B $NextMode (read-only)
|
.B $NextMode (read-only)
|
||||||
If non-zero, then the \fB\-n\fR option was supplied on the command line.
|
If non-zero, then the \fB\-n\fR option was supplied on the command line.
|
||||||
.TP
|
.TP
|
||||||
|
.B $MaxFullOmits (read-only)
|
||||||
|
The maximum number of full OMITs allowed (a compiled-in constant.)
|
||||||
|
.TP
|
||||||
|
.B $MaxPartialOmits (read-only)
|
||||||
|
The maximum number of partial OMITs allowed (a compiled-in constant.)
|
||||||
|
.TP
|
||||||
|
.B $NumFullOmits (read-only)
|
||||||
|
The number of full OMITs in the current OMIT context.
|
||||||
|
.TP
|
||||||
|
.B $NumPartialOmits (read-only)
|
||||||
|
The number of partial OMITs in the current OMIT context.
|
||||||
|
.TP
|
||||||
.B $NumQueued (read-only)
|
.B $NumQueued (read-only)
|
||||||
Contains the number of reminders queued so far for background
|
Contains the number of reminders queued so far for background
|
||||||
timed triggering.
|
timed triggering.
|
||||||
@@ -2710,6 +2777,9 @@ Equivalent to \fBwkdaynum(trigdate())\fR.
|
|||||||
.B $Ty (read-only)
|
.B $Ty (read-only)
|
||||||
Equivalent to \fByear(trigdate())\fR.
|
Equivalent to \fByear(trigdate())\fR.
|
||||||
.TP
|
.TP
|
||||||
|
.B $Tt (read-only, TIME type)
|
||||||
|
Equivalent to \fBtrigtime()\fR.
|
||||||
|
.TP
|
||||||
.B $TimeSep
|
.B $TimeSep
|
||||||
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
|
||||||
@@ -3056,11 +3126,12 @@ will produce undefined results.
|
|||||||
Returns the time of "civil twilight" on the specified \fIdate\fR. If
|
Returns the time of "civil twilight" on the specified \fIdate\fR. If
|
||||||
\fIdate\fR is omitted, defaults to \fBtoday()\fR.
|
\fIdate\fR is omitted, defaults to \fBtoday()\fR.
|
||||||
.TP
|
.TP
|
||||||
.B easterdate(dqi_arg)
|
.B easterdate([dqi_arg])
|
||||||
If \fIarg\fR is an \fBINT\fR, then returns the date of Easter Sunday
|
If \fIarg\fR is an \fBINT\fR, then returns the date of Easter Sunday
|
||||||
for the specified year. If \fIarg\fR is a \fBDATE\fR or
|
for the specified year. If \fIarg\fR is a \fBDATE\fR or
|
||||||
\fBDATETIME\fR, then returns the date of the next Easter Sunday on or
|
\fBDATETIME\fR, then returns the date of the next Easter Sunday on or
|
||||||
after \fIarg\fR. (The time component of a datetime is ignored.)
|
after \fIarg\fR. (The time component of a datetime is ignored.) If \fIarg\fR
|
||||||
|
is omitted, then it defaults to \fBtoday()\fR.
|
||||||
.RS
|
.RS
|
||||||
.P
|
.P
|
||||||
Note that \fBeasterdate\fR computes the Western Easter. For the Orthodox
|
Note that \fBeasterdate\fR computes the Western Easter. For the Orthodox
|
||||||
@@ -3322,6 +3393,62 @@ 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 multitrig(s_trig1 [,s_trig2, [... s_trigN]])
|
||||||
|
\fBmultitrig\fR evaluates each string as a trigger, similar to \fBevaltrig\fR,
|
||||||
|
and returns the \fIearliest\fR trigger date that is on or after \fBtoday()\fR.
|
||||||
|
\fBmultitrig\fR is similar to \fBtrig\fR but has the following difference:
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
\fBtrig\fR returns the \fIfirst\fR trigger date that would have triggered today,
|
||||||
|
whereas \fBmultitrig\fR returns the \fIearliest\fR trigger date later than
|
||||||
|
today, regardless of whether it would have triggered today.
|
||||||
|
.PP
|
||||||
|
If no trigger can be computed that is later than \fBtoday()\fR, then
|
||||||
|
\fBmultitrig\fR returns 1990-01-01.
|
||||||
|
.PP
|
||||||
|
Consider the following examples, assuming that today is Sunday, 24 March 2024:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
# Returns 1990-01-01 because neither would trigger today
|
||||||
|
SET a trig("Mon", "Wed")
|
||||||
|
|
||||||
|
# Returns 2024-03-25 because it's the earlier trigger date
|
||||||
|
SET a multitrig("Mon", "Wed")
|
||||||
|
|
||||||
|
# Returns 2024-03-27 because it's the first that would trigger today
|
||||||
|
SET a trig("Wed +3", "Mon +3")
|
||||||
|
|
||||||
|
# Returns 2024-03-25 because it's the earlier trigger date
|
||||||
|
SET a multitrig("Wed +3", "Mon +3")
|
||||||
|
|
||||||
|
# Returns 1990-01-01 because all triggers have expired
|
||||||
|
SET a multitrig("2000", "2022", "1998", "2023")
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
In general, \fBmultitrig\fR works better with the Remind algorithm than
|
||||||
|
\fBtrig\fR and should be used most of the time. As an example, this
|
||||||
|
reminder is issued at the end of each quarter:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
REM [multitrig("Mar 31", "Jun 30", "Sep 30", "Dec 31")] +7 MSG \\
|
||||||
|
%"End of [ord($Tm/3)] quarter%" is %b.
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
If you want the last working day of each quarter, you could use:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
PUSH-OMIT-CONTEXT
|
||||||
|
OMIT Sat Sun
|
||||||
|
REM [multitrig("Mar ~1", "Jun ~1", "Sep ~1", "Dec ~1")] +7 MSG \\
|
||||||
|
%"Last working day of [ord($Tm/3)] quarter%" is %b.
|
||||||
|
POP-OMIT-CONTEXT
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
Note that unlike \fBevaltrig\fR, \fBmultitrig\fR always returns a \fBDATE\fR
|
||||||
|
and never a \fBDATETIME\fR. Including an \fBAT\fR clause in a trigger
|
||||||
|
supplied to \fBmultitrig\fR will result in an error.
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
.B ndawn([dq_date])
|
.B ndawn([dq_date])
|
||||||
Returns the time of "nautical dawn" on the specified \fIdate\fR. If
|
Returns the time of "nautical dawn" on the specified \fIdate\fR. If
|
||||||
\fIdate\fR is omitted, defaults to \fBtoday()\fR. If a \fIdatetime\fR object
|
\fIdate\fR is omitted, defaults to \fBtoday()\fR. If a \fIdatetime\fR object
|
||||||
@@ -3415,11 +3542,12 @@ the actual time, or a time supplied on the command line.
|
|||||||
Returns a string that is the ordinal number \fInum\fR. For example,
|
Returns a string that is the ordinal number \fInum\fR. For example,
|
||||||
\fBord(2)\fR returns "2nd", and \fBord(213)\fR returns "213th".
|
\fBord(2)\fR returns "2nd", and \fBord(213)\fR returns "213th".
|
||||||
.TP
|
.TP
|
||||||
.B orthodoxeaster(dqi_arg)
|
.B orthodoxeaster([dqi_arg])
|
||||||
If \fIarg\fR is an \fBINT\fR, then returns the date of Orthodox Easter Sunday
|
If \fIarg\fR is an \fBINT\fR, then returns the date of Orthodox Easter Sunday
|
||||||
for the specified year. If \fIarg\fR is a \fBDATE\fR or
|
for the specified year. If \fIarg\fR is a \fBDATE\fR or
|
||||||
\fBDATETIME\fR, then returns the date of the next Orthodox Easter Sunday on or
|
\fBDATETIME\fR, then returns the date of the next Orthodox Easter Sunday on or
|
||||||
after \fIarg\fR. (The time component of a datetime is ignored.)
|
after \fIarg\fR. (The time component of a datetime is ignored.) If \fIarg\fR
|
||||||
|
is omitted, then it defaults to \fBtoday()\fR.
|
||||||
.RS
|
.RS
|
||||||
.P
|
.P
|
||||||
Note that \fBorthodoxeaster\fR computes the Orthodox Easter. For the Western
|
Note that \fBorthodoxeaster\fR computes the Orthodox Easter. For the Western
|
||||||
@@ -3640,7 +3768,7 @@ not supplied, then it defaults to \fBtoday()\fR.
|
|||||||
.PP
|
.PP
|
||||||
The return value of \fBsoleq()\fR is a \fBDATETIME\fR object specifying
|
The return value of \fBsoleq()\fR is a \fBDATETIME\fR object specifying
|
||||||
the date and time of the solstice or equinox in the local time zone. It
|
the date and time of the solstice or equinox in the local time zone. It
|
||||||
should be accurate to within 3 minues or so in the worst case.
|
should be accurate to within 3 minutes or so in the worst case.
|
||||||
.PP
|
.PP
|
||||||
See the included file \fB$SysInclude/seasons.rem\fR for examples of how
|
See the included file \fB$SysInclude/seasons.rem\fR for examples of how
|
||||||
to use \fBsoleq()\fR.
|
to use \fBsoleq()\fR.
|
||||||
@@ -3740,7 +3868,7 @@ function for advance warning to work properly. This is because
|
|||||||
\fBtrig\fR returns a date constant (the trigger date) and the
|
\fBtrig\fR returns a date constant (the trigger date) and the
|
||||||
REM command does not know the details of \fBtrig\fR's arguments.
|
REM command does not know the details of \fBtrig\fR's arguments.
|
||||||
.PP
|
.PP
|
||||||
Note that because \fBRemind\fR does not have short-circuit logical
|
Note that because \fBRemind\fR has short-circuit logical
|
||||||
operators, something like:
|
operators, something like:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
@@ -3748,58 +3876,9 @@ operators, something like:
|
|||||||
.fi
|
.fi
|
||||||
|
|
||||||
would set the value of trig() to the date of the following
|
would set the value of trig() to the date of the following
|
||||||
Thursday. Even though trig("Mon +7") always returns true,
|
Monday. Because trig("Mon +7") always returns true,
|
||||||
the logical-OR operator still evaluates trig("Fri +7") which
|
the logical-OR operator does not bother evaluating trig("Fri +7") which
|
||||||
\fIalso\fR returns true and sets \fBtrig()\fR.
|
therefore does not set \fBtrig()\fR.
|
||||||
.PP
|
|
||||||
You can work around the lack of a short-circuit logical-OR as follows:
|
|
||||||
If \fBtrig\fR returns a true value, the specific value it returns
|
|
||||||
can be coerced to a DATE which is the trigger date. So the following code:
|
|
||||||
.PP
|
|
||||||
.nf
|
|
||||||
SET a trig("Mon +4") || trig("Fri +4")
|
|
||||||
IF a
|
|
||||||
REM [a] +4 MSG [wkday($T)] %b.
|
|
||||||
ENDIF
|
|
||||||
.fi
|
|
||||||
.PP
|
|
||||||
would operate as follows:
|
|
||||||
.PP
|
|
||||||
.nf
|
|
||||||
On Monday: Monday today.
|
|
||||||
On Tuesday: Friday in 3 days' time.
|
|
||||||
On Wednesday: Friday in 2 days' time.
|
|
||||||
On Thursday: Monday in 4 days' time.
|
|
||||||
On Friday: Monday in 3 days' time.
|
|
||||||
On Saturday: Monday in 2 days' time.
|
|
||||||
On Sunday: Monday tomorrow.
|
|
||||||
.fi
|
|
||||||
.PP
|
|
||||||
Compare with the following:
|
|
||||||
.PP
|
|
||||||
.nf
|
|
||||||
SET a trig("Mon +4") || trig("Fri +4")
|
|
||||||
IF a
|
|
||||||
REM [trig()] +4 MSG [wkday($T)] %b.
|
|
||||||
ENDIF
|
|
||||||
.fi
|
|
||||||
.PP
|
|
||||||
which yields:
|
|
||||||
.PP
|
|
||||||
.nf
|
|
||||||
On Monday: Friday in 4 days' time.
|
|
||||||
On Tuesday: Friday in 3 days' time.
|
|
||||||
On Wednesday: Friday in 2 days' time.
|
|
||||||
On Thursday: Friday tomorrow.
|
|
||||||
On Friday: Friday today.
|
|
||||||
On Saturday: Monday in 2 days' time.
|
|
||||||
On Sunday: Monday tomorrow.
|
|
||||||
.fi
|
|
||||||
.PP
|
|
||||||
That is because \fBtrig()\fR returns the trigger date of
|
|
||||||
the \fIlast\fR trig function that returns true,
|
|
||||||
whereas the value of \fBa\fR is the trigger date of the \fIfirst\fR
|
|
||||||
trig function that returns true.
|
|
||||||
.PP
|
.PP
|
||||||
\fBImportant Note\fR: Because \fBtrig()\fR always returns an absolute
|
\fBImportant Note\fR: Because \fBtrig()\fR always returns an absolute
|
||||||
date, it will \fBnot\fR work properly with a \fBSATISFY\fR clause.
|
date, it will \fBnot\fR work properly with a \fBSATISFY\fR clause.
|
||||||
@@ -4139,6 +4218,14 @@ with square brackets. For example:
|
|||||||
This evaluates the expression "mydate", where "mydate" is
|
This evaluates the expression "mydate", where "mydate" is
|
||||||
presumably some pre-computed variable, and then "pastes" the result
|
presumably some pre-computed variable, and then "pastes" the result
|
||||||
into the command-line for the parser to process.
|
into the command-line for the parser to process.
|
||||||
|
.PP
|
||||||
|
If you want a literal "[" character for some reason, simply use "[[". For
|
||||||
|
example:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
REM MSG Here are [[square] brackets!
|
||||||
|
.fi
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
A formal description of this is: When \fBRemind\fR encounters a
|
A formal description of this is: When \fBRemind\fR encounters a
|
||||||
"pasted-in" expression, it evaluates the expression, and coerces the
|
"pasted-in" expression, it evaluates the expression, and coerces the
|
||||||
@@ -4686,7 +4773,7 @@ under program control. The format is:
|
|||||||
.PP
|
.PP
|
||||||
\fBDEBUG\fR [+\fIflagson\fR] [\-\fIflagsoff\fR]
|
\fBDEBUG\fR [+\fIflagson\fR] [\-\fIflagsoff\fR]
|
||||||
.PP
|
.PP
|
||||||
\fIFlagson\fR and \fIflagsoff\fR consist of strings of the characters "extvlf"
|
\fIFlagson\fR and \fIflagsoff\fR consist of strings of the characters "extvlfs"
|
||||||
that correspond to the debugging options discussed in the command-line
|
that correspond to the debugging options discussed in the command-line
|
||||||
options section. If preceded with a "+", the corresponding group of
|
options section. If preceded with a "+", the corresponding group of
|
||||||
debugging options is switched on. Otherwise, they are switched off.
|
debugging options is switched on. Otherwise, they are switched off.
|
||||||
@@ -4990,21 +5077,25 @@ structuring comments in your PostScript code.
|
|||||||
.PP
|
.PP
|
||||||
.SH DAEMON MODE
|
.SH DAEMON MODE
|
||||||
.PP
|
.PP
|
||||||
If you use the \fB\-z\fR command-line option, \fBRemind\fR runs in the
|
If you use the \fB\-z\fR command-line option, \fBRemind\fR runs in
|
||||||
"daemon" mode. In this mode, no "normal" reminders are issued.
|
"daemon mode". In this mode, no "normal" reminders are issued.
|
||||||
Instead, only timed reminders are collected and queued, and are then
|
Instead, only timed reminders are collected and queued, and are then
|
||||||
issued whenever they reach their trigger time.
|
issued whenever they reach their trigger time.
|
||||||
.PP
|
.PP
|
||||||
In addition, \fBRemind\fR wakes up every few minutes to check the modification
|
In addition, \fBRemind\fR wakes up every few minutes to check the
|
||||||
date on the reminder script (the filename supplied on the command line.)
|
modification date on the reminder script (the filename supplied on the
|
||||||
If \fBRemind\fR detects that the script has changed, it re-executes itself
|
command line.) If \fBRemind\fR detects that the script has changed,
|
||||||
in daemon mode, and interprets the changed script.
|
it re-executes itself in daemon mode, and interprets the changed
|
||||||
|
script. If \fBRemind\fR was compiled with support for
|
||||||
|
\fBinotify\fR(7), then if the command-line reminder script is really a
|
||||||
|
directory, \fBRemind\fR also re-executes itself if any of the files in
|
||||||
|
the directory is changed.
|
||||||
.PP
|
.PP
|
||||||
In daemon mode, \fBRemind\fR also re-reads the remind script when it
|
In daemon mode, \fBRemind\fR also re-reads the remind script when it
|
||||||
detects that the system date has changed.
|
detects that the system date has changed.
|
||||||
.PP
|
.PP
|
||||||
In daemon mode, \fBRemind\fR acts as if the \fB\-f\fR option had been used,
|
In daemon mode, \fBRemind\fR acts as if the \fB\-f\fR option had been used,
|
||||||
so to run in the daemon mode in the background, use:
|
so to run in daemon mode in the background, use:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
remind \-z .reminders &
|
remind \-z .reminders &
|
||||||
@@ -5231,7 +5322,7 @@ A number of system variables let you translate various phrases
|
|||||||
to other languages. These system variables are:
|
to other languages. These system variables are:
|
||||||
.PP
|
.PP
|
||||||
.TP
|
.TP
|
||||||
.B $Monday, $Tuesday, $Wednesday, $Thursday, $Friday, $Saturday
|
.B $Monday, $Tuesday, $Wednesday, $Thursday, $Friday, $Saturday, $Sunday
|
||||||
Set each of these system variables to a string representing the corresponding
|
Set each of these system variables to a string representing the corresponding
|
||||||
day's name in your language. Strings must be valid UTF-8 strings.
|
day's name in your language. Strings must be valid UTF-8 strings.
|
||||||
.TP
|
.TP
|
||||||
@@ -5334,7 +5425,7 @@ as:
|
|||||||
.PP
|
.PP
|
||||||
You can define your own substitution sequences in addition to the built-in
|
You can define your own substitution sequences in addition to the built-in
|
||||||
ones as follows: If you define a function named \fBsubst_\fIname\fB(alt, date, time)\fR, then the sequence \fB%{name}\fR calls the function with \fBalt\fR
|
ones as follows: If you define a function named \fBsubst_\fIname\fB(alt, date, time)\fR, then the sequence \fB%{name}\fR calls the function with \fBalt\fR
|
||||||
set to 0 and \fBdate\fR and \fRtime\fR to the trigger date and time,
|
set to 0 and \fBdate\fR and \fBtime\fR to the trigger date and time,
|
||||||
respectively. The \fB%{name}\fR sequence is replaced with whatever the
|
respectively. The \fB%{name}\fR sequence is replaced with whatever the
|
||||||
function returns. The sequence \fB%*{name}\fR is similar, but calls
|
function returns. The sequence \fB%*{name}\fR is similar, but calls
|
||||||
the function with \fBalt\fR set to 1.
|
the function with \fBalt\fR set to 1.
|
||||||
@@ -5537,13 +5628,13 @@ the anniversary of a death is. The following rules are used:
|
|||||||
o
|
o
|
||||||
If the death occurred on 30 Heshvan, and Heshvan in the year after the
|
If the death occurred on 30 Heshvan, and Heshvan in the year after the
|
||||||
death is \fIchaser\fR, then the jahrzeit is observed on 29 Heshvan in years
|
death is \fIchaser\fR, then the jahrzeit is observed on 29 Heshvan in years
|
||||||
when Heshvan is \fIchaser\fR. Otherwise, the yahrzeit is observed on 1
|
when Heshvan is \fIchaser\fR. Otherwise, the jahrzeit is observed on 1
|
||||||
Kislev when Heshvan is \fIchaser\fR.
|
Kislev when Heshvan is \fIchaser\fR.
|
||||||
.TP
|
.TP
|
||||||
o
|
o
|
||||||
If the death occurred on 30 Kislev, and Kislev in the year after the
|
If the death occurred on 30 Kislev, and Kislev in the year after the
|
||||||
death is \fIchaser\fR, then the jahrzeit is observed on 29 Kislev in years
|
death is \fIchaser\fR, then the jahrzeit is observed on 29 Kislev in years
|
||||||
when Kislev is \fIchaser\fR. Otherwise, the yahrzeit is observed on 1
|
when Kislev is \fIchaser\fR. Otherwise, the jahrzeit is observed on 1
|
||||||
Tevet when Kislev is \fIchaser\fR.
|
Tevet when Kislev is \fIchaser\fR.
|
||||||
.TP
|
.TP
|
||||||
o
|
o
|
||||||
@@ -5950,6 +6041,9 @@ Almanac Office, USNO.
|
|||||||
.PP
|
.PP
|
||||||
Richard Siegel and Michael and Sharon Strassfeld, \fIThe First Jewish
|
Richard Siegel and Michael and Sharon Strassfeld, \fIThe First Jewish
|
||||||
Catalog\fR, Jewish Publication Society of America.
|
Catalog\fR, Jewish Publication Society of America.
|
||||||
|
.PP
|
||||||
|
Jean Meeus, \fIAstronomical Algorithms, Second Edition\fR, Willmann-Bell, Inc.
|
||||||
|
|
||||||
.SH HOME PAGE
|
.SH HOME PAGE
|
||||||
https://dianne.skoll.ca/projects/remind/
|
https://dianne.skoll.ca/projects/remind/
|
||||||
.SH MAILING LIST
|
.SH MAILING LIST
|
||||||
|
|||||||
@@ -184,7 +184,9 @@ on the reminder.
|
|||||||
If there are any errors in your reminder file, the "Queue..." button
|
If there are any errors in your reminder file, the "Queue..." button
|
||||||
changes to "Errors...". Click on "Errors..." to see the Remind error
|
changes to "Errors...". Click on "Errors..." to see the Remind error
|
||||||
output. Click "OK" to close the error window; this makes the button
|
output. Click "OK" to close the error window; this makes the button
|
||||||
in the main TkRemind window to revert to "Queue..."
|
in the main TkRemind window to revert to "Queue..." You can click on
|
||||||
|
any error message to open an editor on the file and line number that
|
||||||
|
caused the error.
|
||||||
|
|
||||||
.SH BACKGROUND REMINDERS
|
.SH BACKGROUND REMINDERS
|
||||||
|
|
||||||
@@ -192,7 +194,7 @@ If you create "timed" reminders, \fBTkRemind\fR will queue them in
|
|||||||
the background and pop up boxes as they are triggered. Additionally,
|
the background and pop up boxes as they are triggered. Additionally,
|
||||||
if you created the reminder using \fBTkRemind\fR, you will be given the
|
if you created the reminder using \fBTkRemind\fR, you will be given the
|
||||||
option of "turning off" the reminder for the rest of the day.
|
option of "turning off" the reminder for the rest of the day.
|
||||||
\fBTkRemind\fR achieves queueing of background reminders by running
|
\fBTkRemind\fR achieves queuing of background reminders by running
|
||||||
\fBRemind\fR in \fIserver mode\fR, described later.
|
\fBRemind\fR in \fIserver mode\fR, described later.
|
||||||
|
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
@@ -301,11 +303,11 @@ Today
|
|||||||
|
|
||||||
.SH IMMEDIATE UPDATES
|
.SH IMMEDIATE UPDATES
|
||||||
|
|
||||||
If you are running \fBTkRemind\fR on Linux and have the
|
If you are running \fBTkRemind\fR on Linux and \fBRemind\fR has been
|
||||||
\fBinotifywait\fR program installed (part of the \fBinotify-tools\fR
|
compiled with \fBinotify\fR(7) support, then \fBTkRemind\fR redraws
|
||||||
or similar package), then \fBTkRemind\fR redraws the calendar window
|
the calendar window \fIimmediately\fR if \fB$HOME/.reminders\fR
|
||||||
\fIimmediately\fR if \fB$HOME/.reminders\fR changes (or, if it is a
|
changes (or, if it is a directory, any files in that directory
|
||||||
directory, any files in that directory change.)
|
change.)
|
||||||
.PP
|
.PP
|
||||||
This lets \fBTkRemind\fR react immediately to hand-edited reminders or
|
This lets \fBTkRemind\fR react immediately to hand-edited reminders or
|
||||||
to reminder files that are imported from another calendar system (for example,
|
to reminder files that are imported from another calendar system (for example,
|
||||||
@@ -366,80 +368,110 @@ your hand-edited files in a separate \fB*.rem\fR file than \fBTkRemind\fR's
|
|||||||
|
|
||||||
\fBRemind\fR has a special mode for interacting with programs like
|
\fBRemind\fR has a special mode for interacting with programs like
|
||||||
\fBTkRemind\fR. This mode is called \fIserver mode\fR and is
|
\fBTkRemind\fR. This mode is called \fIserver mode\fR and is
|
||||||
selected by supplying the \fB\-z0\fR option to \fBRemind\fR.
|
selected by supplying the \fB\-zj\fR option to \fBRemind\fR.
|
||||||
|
|
||||||
In server mode, \fBRemind\fR operates similar to daemon mode, except
|
In server mode, \fBRemind\fR operates similar to daemon mode, except
|
||||||
it reads commands (one per line)
|
it reads commands (one per line) from standard input and writes status
|
||||||
from standard input and writes status lines to standard output.
|
lines to standard output. Each status line is a JSON object.
|
||||||
|
|
||||||
The commands accepted in server mode are:
|
The commands accepted in server mode are:
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
EXIT
|
EXIT
|
||||||
Terminate the \fBRemind\fR process. EOF on standard input does the
|
Terminate the \fBRemind\fR process. EOF on standard input does the
|
||||||
same thing.
|
same thing. \fBRemind\fR exits immediately without printing
|
||||||
|
a JSON status line.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
STATUS
|
STATUS
|
||||||
Return the number of queued reminders.
|
Return the number of queued reminders. The JSON object looks
|
||||||
|
something like this:
|
||||||
|
.nf
|
||||||
|
|
||||||
|
{"response":"queued","nqueued":n,"command":"STATUS"}
|
||||||
|
|
||||||
|
.fi
|
||||||
|
where \fIn\fR is the number of reminders queued.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
QUEUE
|
QUEUE or JSONQUEUE
|
||||||
Returns the contents of the queue, printed between "NOTE queue" and
|
Returns the contents of the queue. The JSON object looks something
|
||||||
"NOTE endqueue" lines.
|
like this:
|
||||||
|
.nf
|
||||||
|
|
||||||
|
{"response":"queue","queue":[ ... ],"command":"QUEUE"}
|
||||||
|
|
||||||
|
.fi
|
||||||
|
The value of the \fBqueue\fR key is an array of JSON objects, each
|
||||||
|
representing a queued reminder.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
JSONQUEUE
|
DEL \fIqid\fR
|
||||||
Returns the contents of the queue in JSON format, printed between
|
Delete the reminder with queue-id \fIqid\fR from the queue.
|
||||||
"NOTE JSONQUEUE" and "NOTE ENDJSONQUEUE" lines.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
REREAD
|
REREAD
|
||||||
Re-read the reminder file
|
Re-read the reminder file. Returns the following status line:
|
||||||
|
|
||||||
|
.nf
|
||||||
|
|
||||||
|
{"response":"reread","command":"REREAD"}
|
||||||
|
|
||||||
|
.fi
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
The status lines written are as follows:
|
Additional status lines written are as follows:
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
NOTE reminder \fItime\fR \fItag\fR
|
.nf
|
||||||
Signifies the beginning of a timed reminder whose trigger time is
|
|
||||||
\fItime\fR with tag \fItag\fR. If the reminder has no tag, an
|
|
||||||
asterisk is supplied for \fItag\fR. All lines following this line
|
|
||||||
are the body of the reminder, until the line \fBNOTE endreminder\fR
|
|
||||||
is transmitted.
|
|
||||||
|
|
||||||
|
{"response":"reminder","ttime":tt,"now":now,"tags":tags,"qid":qid,"body":body}
|
||||||
|
|
||||||
|
.fi
|
||||||
|
In this line, \fItt\fR is the trigger time of the reminder (expressed
|
||||||
|
as a string), \fInow\fR is the current time, \fItags\fR (if present)
|
||||||
|
is the tag or tags associated with the reminder, and \fIbody\fR is the
|
||||||
|
body of the reminder. This response causes \fBTkRemind\fR to pop up a
|
||||||
|
reminder notification. \fIqid\fR is a unique identifier for this
|
||||||
|
reminder. You may delete it from the queue by sending a \fBDEL\fR
|
||||||
|
\fIqid\fR command to the server. Note that \fIqid\fRs are not stable
|
||||||
|
across re-reads; if \fBRemind\fR restarts itself to re-read the reminder
|
||||||
|
file, then the \fIqid\fR values are likely to change, and any reminder
|
||||||
|
deleted with a \fBDEL\fR \fIqid\fR command is likely to be re-queued.
|
||||||
.TP
|
.TP
|
||||||
NOTE newdate
|
.nf
|
||||||
|
|
||||||
|
{"response":"newdate"}
|
||||||
|
|
||||||
|
.fi
|
||||||
|
|
||||||
This line is emitted whenever \fBRemind\fR has detected a rollover of
|
This line is emitted whenever \fBRemind\fR has detected a rollover of
|
||||||
the system date. The front-end program should redraw its calendar
|
the system date. The front-end program should redraw its calendar
|
||||||
or take whatever other action is needed.
|
or take whatever other action is needed.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
NOTE reread
|
.nf
|
||||||
This line is emitted whenever the number of reminders in \fBRemind\fR's
|
|
||||||
queue changes because of a date rollover or a \fBREREAD\fR command.
|
|
||||||
The front-end should issue a \fBSTATUS\fR command in response to this
|
|
||||||
message.
|
|
||||||
|
|
||||||
.TP
|
{"response":"reread","command":"inotify"}
|
||||||
NOTE queued \fIn\fR
|
|
||||||
This line is emitted in response to a \fBSTATUS\fR command. The number
|
|
||||||
\fIn\fR is the number of reminders in the queue.
|
|
||||||
|
|
||||||
.TP
|
.fi
|
||||||
NOTE queue
|
|
||||||
Indicates that queue contents are about to follow. The end of the
|
|
||||||
queue is indicated by a NOTE endqueue line.
|
|
||||||
|
|
||||||
.TP
|
If \fBRemind\fR was compiled with support for \fBinotify\fR(7), then
|
||||||
NOTE JSONQUEUE
|
if it detects a change to the top-level reminder file or directory,
|
||||||
Indicates that queue contents in JSON format are about to follow. The
|
it issues the above response. The front-end should redraw its
|
||||||
end of the queue is indicated by a NOTE ENDJSONQUEUE line.
|
calendar since this response indicates that a change has been made
|
||||||
|
to the reminder file or directory.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
Please note that \fBRemind\fR can write a status message \fIat any time\fR
|
||||||
|
and not just in response to a command sent to its standard input. Therefore,
|
||||||
|
a program that runs \fBRemind\fR in server mode must be prepared to handle
|
||||||
|
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-2023 by Dianne Skoll.
|
\fBTkRemind\fR is Copyright 1996-2024 by Dianne Skoll.
|
||||||
|
|
||||||
.SH FILES
|
.SH FILES
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ install:
|
|||||||
@if test "$(PERL)" = "" ; then \
|
@if test "$(PERL)" = "" ; then \
|
||||||
echo "Not installing rem2html; Perl is required"; exit 0; fi; \
|
echo "Not installing rem2html; 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 > /dev/null 2>&1; \
|
||||||
if test $$? != 0 ; then echo "Not installing rem2html; missing $$m"; exit 0; fi; \
|
if test $$? != 0 ; then echo "Not installing rem2html; missing $$m"; exit 0; fi; \
|
||||||
done; \
|
done; \
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use Encode;
|
|||||||
|
|
||||||
my %Options;
|
my %Options;
|
||||||
|
|
||||||
my $rem2html_version = '2.1';
|
my $rem2html_version = '@VERSION@';
|
||||||
|
|
||||||
my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mondayfirst, $weeks,
|
my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mondayfirst, $weeks,
|
||||||
@Daynames, $Nextmon, $Nextlen, $Prevmon, $Prevlen);
|
@Daynames, $Nextmon, $Nextlen, $Prevmon, $Prevlen);
|
||||||
@@ -486,7 +486,7 @@ output for the invalid reminder.
|
|||||||
=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>
|
||||||
and I<y> are floating-point numbers, then the Pango marked-up test is
|
and I<y> are floating-point numbers, then the Pango marked-up text is
|
||||||
positioned absolutely with respect to the day's box (and is not
|
positioned absolutely with respect to the day's box (and is not
|
||||||
counted when calculating the box's height.)
|
counted when calculating the box's height.)
|
||||||
|
|
||||||
|
|||||||
15
resources/tkremind.desktop
Executable file
15
resources/tkremind.desktop
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Exec=tkremind
|
||||||
|
StartupNotify=true
|
||||||
|
Icon=tkremind
|
||||||
|
Terminal=false
|
||||||
|
Name=tkremind
|
||||||
|
Comment=TkRemind Calendar Program
|
||||||
|
Categories=Office;Calendar;
|
||||||
|
Keywords=Calendar;remind;
|
||||||
|
Keywords[ca]=Calendari;remind;
|
||||||
|
Keywords[de]=Kalender;remind;
|
||||||
|
Keywords[en_GB]=Calendar;remind;
|
||||||
|
Keywords[es]=Calendario;remind;
|
||||||
|
|
||||||
BIN
resources/tkremind.png
Normal file
BIN
resources/tkremind.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
654
scripts/tkremind
654
scripts/tkremind
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,7 @@ REMINDSRCS= calendar.c dynbuf.c dorem.c dosubst.c expr.c files.c funcs.c \
|
|||||||
globals.c hbcal.c init.c main.c md5.c moon.c omit.c queue.c \
|
globals.c hbcal.c init.c main.c md5.c moon.c omit.c queue.c \
|
||||||
sort.c token.c trigger.c userfns.c utils.c var.c
|
sort.c token.c trigger.c userfns.c utils.c var.c
|
||||||
|
|
||||||
REMINDHDRS=config.h custom.h dynbuf.h err.h expr.h globals.h lang.h \
|
REMINDHDRS=config.h custom.h dynbuf.h err.h globals.h lang.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)
|
||||||
|
|
||||||
@@ -63,6 +63,16 @@ install: all
|
|||||||
done
|
done
|
||||||
-mkdir -p $(DESTDIR)$(datarootdir)/remind || true
|
-mkdir -p $(DESTDIR)$(datarootdir)/remind || true
|
||||||
cp -R ../include/* $(DESTDIR)$(datarootdir)/remind
|
cp -R ../include/* $(DESTDIR)$(datarootdir)/remind
|
||||||
|
chmod -R a+rX $(DESTDIR)$(datarootdir)/remind
|
||||||
|
-mkdir -p $(DESTDIR)$(prefix)/share/pixmaps
|
||||||
|
-mkdir -p $(DESTDIR)$(prefix)/share/applications
|
||||||
|
$(INSTALL_DATA) $(srcdir)/../resources/tkremind.png $(DESTDIR)$(prefix)/share/pixmaps
|
||||||
|
$(INSTALL_PROGRAM) $(srcdir)/../resources/tkremind.desktop $(DESTDIR)$(prefix)/share/applications
|
||||||
|
-if test "$(DESTDIR)" = ""; then \
|
||||||
|
update-desktop-database < /dev/null > /dev/null 2>&1 ; \
|
||||||
|
xdg-icon-resource install --novendor --size 64 $(DESTDIR)$(prefix)/share/pixmaps/tkremind.png < /dev/null > /dev/null 2>&1 || true; \
|
||||||
|
xdg-desktop-menu install --novendor $(DESTDIR)$(prefix)/share/applications/tkremind.desktop < /dev/null > /dev/null 2>&1 || true; \
|
||||||
|
fi
|
||||||
|
|
||||||
install-stripped: install
|
install-stripped: install
|
||||||
strip $(DESTDIR)$(bindir)/remind || true
|
strip $(DESTDIR)$(bindir)/remind || true
|
||||||
@@ -71,9 +81,6 @@ install-stripped: install
|
|||||||
clean:
|
clean:
|
||||||
rm -f *.o *~ core *.bak $(PROGS)
|
rm -f *.o *~ core *.bak $(PROGS)
|
||||||
|
|
||||||
cppcheck:
|
|
||||||
cppcheck --force --enable=all --suppress=variableScope --suppress=ConfigurationNotChecked *.c
|
|
||||||
|
|
||||||
clobber:
|
clobber:
|
||||||
rm -f *.o *~ remind rem2ps test.out core *.bak
|
rm -f *.o *~ remind rem2ps test.out core *.bak
|
||||||
|
|
||||||
@@ -83,6 +90,9 @@ depend:
|
|||||||
# The next targets are not very useful to you. I use them to build
|
# The next targets are not very useful to you. I use them to build
|
||||||
# distributions, etc.
|
# distributions, etc.
|
||||||
|
|
||||||
|
cppcheck:
|
||||||
|
cppcheck -j`nproc` --force --enable=all --suppress=ConfigurationNotChecked --suppress=unmatchedSuppression --suppress=variableScope --inline-suppr .
|
||||||
|
|
||||||
# Build a tar file based on all files checked into git.
|
# Build a tar file based on all files checked into git.
|
||||||
distro:
|
distro:
|
||||||
cd .. && git archive --worktree-attributes --format=tar --prefix=remind-$(VERSION)/ HEAD > src/remind-$(VERSION).tar
|
cd .. && git archive --worktree-attributes --format=tar --prefix=remind-$(VERSION)/ HEAD > src/remind-$(VERSION).tar
|
||||||
|
|||||||
221
src/calendar.c
221
src/calendar.c
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -35,7 +35,6 @@
|
|||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "expr.h"
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "md5.h"
|
#include "md5.h"
|
||||||
@@ -475,7 +474,7 @@ void PrintJSONKeyPairTime(char const *name, int t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef REM_USE_WCHAR
|
#ifdef REM_USE_WCHAR
|
||||||
void PutWideChar(wchar_t const wc)
|
void PutWideChar(wchar_t const wc, DynamicBuffer *output)
|
||||||
{
|
{
|
||||||
char buf[MB_CUR_MAX+1];
|
char buf[MB_CUR_MAX+1];
|
||||||
int len;
|
int len;
|
||||||
@@ -483,7 +482,11 @@ void PutWideChar(wchar_t const wc)
|
|||||||
len = wctomb(buf, wc);
|
len = wctomb(buf, wc);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
buf[len] = 0;
|
buf[len] = 0;
|
||||||
fputs(buf, stdout);
|
if (output) {
|
||||||
|
DBufPuts(output, buf);
|
||||||
|
} else {
|
||||||
|
fputs(buf, stdout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -556,11 +559,11 @@ static void goff(void)
|
|||||||
static void
|
static void
|
||||||
ClampColor(int *r, int *g, int *b)
|
ClampColor(int *r, int *g, int *b)
|
||||||
{
|
{
|
||||||
if (TerminalBackground == TERMINAL_BACKGROUND_UNKNOWN) {
|
if (GetTerminalBackground() == TERMINAL_BACKGROUND_UNKNOWN) {
|
||||||
/* No special clamping if terminal background is unknown */
|
/* No special clamping if terminal background is unknown */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (TerminalBackground == TERMINAL_BACKGROUND_DARK) {
|
if (GetTerminalBackground() == TERMINAL_BACKGROUND_DARK) {
|
||||||
if (*r <= 64 && *g <= 64 && *b <= 64) {
|
if (*r <= 64 && *g <= 64 && *b <= 64) {
|
||||||
int max = *r;
|
int max = *r;
|
||||||
double factor;
|
double factor;
|
||||||
@@ -579,7 +582,7 @@ ClampColor(int *r, int *g, int *b)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (TerminalBackground == TERMINAL_BACKGROUND_LIGHT) {
|
if (GetTerminalBackground() == TERMINAL_BACKGROUND_LIGHT) {
|
||||||
if (*r > 191 && *g > 191 && *b > 191) {
|
if (*r > 191 && *g > 191 && *b > 191) {
|
||||||
int min = *r;
|
int min = *r;
|
||||||
if (*g < min) min = *g;
|
if (*g < min) min = *g;
|
||||||
@@ -667,11 +670,11 @@ Colorize(int r, int g, int b, int bg, int clamp)
|
|||||||
if (b > 64) b = 1;
|
if (b > 64) b = 1;
|
||||||
else b = 0;
|
else b = 0;
|
||||||
|
|
||||||
if (clamp && TerminalBackground == TERMINAL_BACKGROUND_DARK && !bg) {
|
if (clamp && GetTerminalBackground() == TERMINAL_BACKGROUND_DARK && !bg) {
|
||||||
/* Convert black-on-black to grey */
|
/* Convert black-on-black to grey */
|
||||||
if (!r && !g && !b) return VT100Colors[1][0][0][0];
|
if (!r && !g && !b) return VT100Colors[1][0][0][0];
|
||||||
}
|
}
|
||||||
if (clamp && TerminalBackground == TERMINAL_BACKGROUND_LIGHT && !bg) {
|
if (clamp && GetTerminalBackground() == TERMINAL_BACKGROUND_LIGHT && !bg) {
|
||||||
/* Convert white-on-white to grey */
|
/* Convert white-on-white to grey */
|
||||||
if (r && g && b) return VT100Colors[1][0][0][0];
|
if (r && g && b) return VT100Colors[1][0][0][0];
|
||||||
}
|
}
|
||||||
@@ -1037,7 +1040,7 @@ static void DoCalendarOneMonth(void)
|
|||||||
printf("\"entries\":[\n");
|
printf("\"entries\":[\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (WriteCalendarRow()) continue;
|
while (WriteCalendarRow()) /* continue */;
|
||||||
|
|
||||||
if (PsCal == PSCAL_LEVEL1) {
|
if (PsCal == PSCAL_LEVEL1) {
|
||||||
printf("%s\n", PSEND);
|
printf("%s\n", PSEND);
|
||||||
@@ -1227,7 +1230,7 @@ static void PrintLeft(char const *s, int width, char pad)
|
|||||||
ws = buf;
|
ws = buf;
|
||||||
for (i=0; i<width;) {
|
for (i=0; i<width;) {
|
||||||
if (*ws) {
|
if (*ws) {
|
||||||
PutWideChar(*ws++);
|
PutWideChar(*ws++, NULL);
|
||||||
i+= wcwidth(*ws);
|
i+= wcwidth(*ws);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@@ -1235,7 +1238,7 @@ static void PrintLeft(char const *s, int width, char pad)
|
|||||||
}
|
}
|
||||||
/* Mop up any potential combining characters */
|
/* Mop up any potential combining characters */
|
||||||
while (*ws && wcwidth(*ws) == 0) {
|
while (*ws && wcwidth(*ws) == 0) {
|
||||||
PutWideChar(*ws++);
|
PutWideChar(*ws++, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Possibly send lrm control sequence */
|
/* Possibly send lrm control sequence */
|
||||||
@@ -1308,7 +1311,7 @@ static void PrintCentered(char const *s, int width, char *pad)
|
|||||||
for (i=0; i<d; i++) fputs(pad, stdout);
|
for (i=0; i<d; i++) fputs(pad, stdout);
|
||||||
for (i=0; i<width; i++) {
|
for (i=0; i<width; i++) {
|
||||||
if (*ws) {
|
if (*ws) {
|
||||||
PutWideChar(*ws++);
|
PutWideChar(*ws++, NULL);
|
||||||
if (wcwidth(*ws) == 0) {
|
if (wcwidth(*ws) == 0) {
|
||||||
/* Don't count this character... it's zero-width */
|
/* Don't count this character... it's zero-width */
|
||||||
i--;
|
i--;
|
||||||
@@ -1319,7 +1322,7 @@ static void PrintCentered(char const *s, int width, char *pad)
|
|||||||
}
|
}
|
||||||
/* Mop up any potential combining characters */
|
/* Mop up any potential combining characters */
|
||||||
while (*ws && wcwidth(*ws) == 0) {
|
while (*ws && wcwidth(*ws) == 0) {
|
||||||
PutWideChar(*ws++);
|
PutWideChar(*ws++, NULL);
|
||||||
}
|
}
|
||||||
/* Possibly send lrm control sequence */
|
/* Possibly send lrm control sequence */
|
||||||
send_lrm();
|
send_lrm();
|
||||||
@@ -1448,7 +1451,7 @@ static int WriteOneColLine(int col)
|
|||||||
}
|
}
|
||||||
numwritten += wcwidth(*ws);
|
numwritten += wcwidth(*ws);
|
||||||
}
|
}
|
||||||
PutWideChar(*ws);
|
PutWideChar(*ws, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e->wc_pos = ws;
|
e->wc_pos = ws;
|
||||||
@@ -1463,7 +1466,7 @@ static int WriteOneColLine(int col)
|
|||||||
if (wcwidth(*ws) > 0) {
|
if (wcwidth(*ws) > 0) {
|
||||||
numwritten += wcwidth(*ws);
|
numwritten += wcwidth(*ws);
|
||||||
}
|
}
|
||||||
PutWideChar(*ws);
|
PutWideChar(*ws, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1666,6 +1669,7 @@ static void GenerateCalEntries(int col)
|
|||||||
case T_Pop: r=PopOmitContext(&p); break;
|
case T_Pop: r=PopOmitContext(&p); break;
|
||||||
case T_Push: r=PushOmitContext(&p); break;
|
case T_Push: r=PushOmitContext(&p); break;
|
||||||
case T_Preserve: r=DoPreserve(&p); break;
|
case T_Preserve: r=DoPreserve(&p); break;
|
||||||
|
case T_Expr: r = DoExpr(&p); break;
|
||||||
case T_RemType: if (tok.val == RUN_TYPE) {
|
case T_RemType: if (tok.val == RUN_TYPE) {
|
||||||
r=DoRun(&p);
|
r=DoRun(&p);
|
||||||
break;
|
break;
|
||||||
@@ -1766,7 +1770,7 @@ static int DoCalRem(ParsePtr p, int col)
|
|||||||
DBufInit(&raw_buf);
|
DBufInit(&raw_buf);
|
||||||
|
|
||||||
/* Parse the trigger date and time */
|
/* Parse the trigger date and time */
|
||||||
if ( (r=ParseRem(p, &trig, &tim, 1)) ) {
|
if ( (r=ParseRem(p, &trig, &tim)) ) {
|
||||||
FreeTrig(&trig);
|
FreeTrig(&trig);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -2211,10 +2215,114 @@ static void WriteSimpleEntryProtocol1(CalEntry *e)
|
|||||||
printf("%s\n", e->text);
|
printf("%s\n", e->text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WriteJSONTimeTrigger(TimeTrig const *tt)
|
||||||
|
{
|
||||||
|
PrintJSONKeyPairTime("time", tt->ttime);
|
||||||
|
PrintJSONKeyPairTime("nexttime", tt->nexttime);
|
||||||
|
PrintJSONKeyPairInt("tdelta", tt->delta);
|
||||||
|
PrintJSONKeyPairInt("trep", tt->rep);
|
||||||
|
if (tt->duration != NO_TIME) {
|
||||||
|
PrintJSONKeyPairInt("duration", tt->duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
|
||||||
|
{
|
||||||
|
/* wd is an array of days from 0=monday to 6=sunday.
|
||||||
|
We convert to array of strings */
|
||||||
|
if (t->wd != NO_WD) {
|
||||||
|
printf("\"wd\":[");
|
||||||
|
int done = 0;
|
||||||
|
int i;
|
||||||
|
for (i=0; i<7; i++) {
|
||||||
|
if (t->wd & (1 << i)) {
|
||||||
|
if (done) {
|
||||||
|
printf(",");
|
||||||
|
}
|
||||||
|
done = 1;
|
||||||
|
printf("\"%s\"", EnglishDayName[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("],");
|
||||||
|
}
|
||||||
|
if (t->d != NO_DAY) {
|
||||||
|
PrintJSONKeyPairInt("d", t->d);
|
||||||
|
}
|
||||||
|
if (t->m != NO_MON) {
|
||||||
|
PrintJSONKeyPairInt("m", t->m+1);
|
||||||
|
}
|
||||||
|
if (t->y != NO_YR) {
|
||||||
|
PrintJSONKeyPairInt("y", t->y);
|
||||||
|
}
|
||||||
|
if (t->back) {
|
||||||
|
PrintJSONKeyPairInt("back", t->back);
|
||||||
|
}
|
||||||
|
if (t->delta) {
|
||||||
|
PrintJSONKeyPairInt("delta", t->delta);
|
||||||
|
}
|
||||||
|
if (t->rep) {
|
||||||
|
PrintJSONKeyPairInt("rep", t->rep);
|
||||||
|
}
|
||||||
|
/* Local omit is an array of days from 0=monday to 6=sunday.
|
||||||
|
We convert to array of strings */
|
||||||
|
if (t->localomit != NO_WD) {
|
||||||
|
printf("\"localomit\":[");
|
||||||
|
int done = 0;
|
||||||
|
int i;
|
||||||
|
for (i=0; i<7; i++) {
|
||||||
|
if (t->localomit & (1 << i)) {
|
||||||
|
if (done) {
|
||||||
|
printf(",");
|
||||||
|
}
|
||||||
|
done = 1;
|
||||||
|
printf("\"%s\"", EnglishDayName[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("],");
|
||||||
|
}
|
||||||
|
switch(t->skip) {
|
||||||
|
case SKIP_SKIP:
|
||||||
|
PrintJSONKeyPairString("skip", "SKIP");
|
||||||
|
break;
|
||||||
|
case BEFORE_SKIP:
|
||||||
|
PrintJSONKeyPairString("skip", "BEFORE");
|
||||||
|
break;
|
||||||
|
case AFTER_SKIP:
|
||||||
|
PrintJSONKeyPairString("skip", "AFTER");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PrintJSONKeyPairDate("until", t->until);
|
||||||
|
if (t->once != NO_ONCE) {
|
||||||
|
PrintJSONKeyPairInt("once", t->once);
|
||||||
|
}
|
||||||
|
if (t->scanfrom != today) {
|
||||||
|
PrintJSONKeyPairDate("scanfrom", t->scanfrom);
|
||||||
|
}
|
||||||
|
PrintJSONKeyPairDate("from", t->from);
|
||||||
|
PrintJSONKeyPairInt("priority", t->priority);
|
||||||
|
PrintJSONKeyPairDateTime("eventstart", t->eventstart);
|
||||||
|
if (t->eventduration != NO_TIME) {
|
||||||
|
PrintJSONKeyPairInt("eventduration", t->eventduration);
|
||||||
|
}
|
||||||
|
if (t->maybe_uncomputable) {
|
||||||
|
PrintJSONKeyPairInt("maybe_uncomputable", 1);
|
||||||
|
}
|
||||||
|
if (t->noqueue) {
|
||||||
|
PrintJSONKeyPairInt("noqueue", 1);
|
||||||
|
}
|
||||||
|
PrintJSONKeyPairString("sched", t->sched);
|
||||||
|
PrintJSONKeyPairString("warn", t->warn);
|
||||||
|
PrintJSONKeyPairString("omitfunc", t->omitfunc);
|
||||||
|
if (t->addomit) {
|
||||||
|
PrintJSONKeyPairInt("addomit", 1);
|
||||||
|
}
|
||||||
|
if (include_tags) {
|
||||||
|
PrintJSONKeyPairString("tags", DBufValue(&(t->tags)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
|
static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
|
||||||
{
|
{
|
||||||
int done = 0;
|
|
||||||
char const *s;
|
char const *s;
|
||||||
if (DoPrefixLineNo) {
|
if (DoPrefixLineNo) {
|
||||||
PrintJSONKeyPairString("filename", e->filename);
|
PrintJSONKeyPairString("filename", e->filename);
|
||||||
@@ -2234,88 +2342,13 @@ static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
|
|||||||
PrintJSONKeyPairInt("trep", e->tt.rep);
|
PrintJSONKeyPairInt("trep", e->tt.rep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (e->trig.eventduration != NO_TIME) {
|
WriteJSONTrigger(&e->trig, 0, today);
|
||||||
PrintJSONKeyPairInt("eventduration", e->trig.eventduration);
|
|
||||||
}
|
|
||||||
/* wd is an array of days from 0=monday to 6=sunday.
|
|
||||||
We convert to array of strings */
|
|
||||||
if (e->trig.wd != NO_WD) {
|
|
||||||
printf("\"wd\":[");
|
|
||||||
done = 0;
|
|
||||||
int i;
|
|
||||||
for (i=0; i<7; i++) {
|
|
||||||
if (e->trig.wd & (1 << i)) {
|
|
||||||
if (done) {
|
|
||||||
printf(",");
|
|
||||||
}
|
|
||||||
done = 1;
|
|
||||||
printf("\"%s\"", EnglishDayName[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("],");
|
|
||||||
}
|
|
||||||
if (e->trig.d != NO_DAY) {
|
|
||||||
PrintJSONKeyPairInt("d", e->trig.d);
|
|
||||||
}
|
|
||||||
if (e->trig.m != NO_MON) {
|
|
||||||
PrintJSONKeyPairInt("m", e->trig.m+1);
|
|
||||||
}
|
|
||||||
if (e->trig.y != NO_YR) {
|
|
||||||
PrintJSONKeyPairInt("y", e->trig.y);
|
|
||||||
}
|
|
||||||
PrintJSONKeyPairDateTime("eventstart", e->trig.eventstart);
|
|
||||||
if (e->trig.back) {
|
|
||||||
PrintJSONKeyPairInt("back", e->trig.back);
|
|
||||||
}
|
|
||||||
if (e->trig.delta) {
|
|
||||||
PrintJSONKeyPairInt("delta", e->trig.delta);
|
|
||||||
}
|
|
||||||
if (e->trig.rep) {
|
|
||||||
PrintJSONKeyPairInt("rep", e->trig.rep);
|
|
||||||
}
|
|
||||||
if (e->nonconst_expr) {
|
if (e->nonconst_expr) {
|
||||||
PrintJSONKeyPairInt("nonconst_expr", e->nonconst_expr);
|
PrintJSONKeyPairInt("nonconst_expr", e->nonconst_expr);
|
||||||
}
|
}
|
||||||
if (e->if_depth) {
|
if (e->if_depth) {
|
||||||
PrintJSONKeyPairInt("if_depth", e->if_depth);
|
PrintJSONKeyPairInt("if_depth", e->if_depth);
|
||||||
}
|
}
|
||||||
switch(e->trig.skip) {
|
|
||||||
case SKIP_SKIP:
|
|
||||||
PrintJSONKeyPairString("skip", "SKIP");
|
|
||||||
break;
|
|
||||||
case BEFORE_SKIP:
|
|
||||||
PrintJSONKeyPairString("skip", "BEFORE");
|
|
||||||
break;
|
|
||||||
case AFTER_SKIP:
|
|
||||||
PrintJSONKeyPairString("skip", "AFTER");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Local omit is an array of days from 0=monday to 6=sunday.
|
|
||||||
We convert to array of strings */
|
|
||||||
if (e->trig.localomit != NO_WD) {
|
|
||||||
printf("\"localomit\":[");
|
|
||||||
done = 0;
|
|
||||||
int i;
|
|
||||||
for (i=0; i<7; i++) {
|
|
||||||
if (e->trig.localomit & (1 << i)) {
|
|
||||||
if (done) {
|
|
||||||
printf(",");
|
|
||||||
}
|
|
||||||
done = 1;
|
|
||||||
printf("\"%s\"", EnglishDayName[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("],");
|
|
||||||
}
|
|
||||||
PrintJSONKeyPairDate("until", e->trig.until);
|
|
||||||
if (e->trig.once != NO_ONCE) {
|
|
||||||
PrintJSONKeyPairInt("once", e->trig.once);
|
|
||||||
}
|
|
||||||
if (e->trig.scanfrom != today) {
|
|
||||||
PrintJSONKeyPairDate("scanfrom", e->trig.scanfrom);
|
|
||||||
}
|
|
||||||
PrintJSONKeyPairDate("from", e->trig.from);
|
|
||||||
PrintJSONKeyPairInt("priority", e->trig.priority);
|
|
||||||
|
|
||||||
if (e->is_color) {
|
if (e->is_color) {
|
||||||
PrintJSONKeyPairInt("r", e->r);
|
PrintJSONKeyPairInt("r", e->r);
|
||||||
|
|||||||
@@ -24,27 +24,46 @@ if (!$ARGV[0]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
my $lang = $ARGV[0];
|
my $lang = $ARGV[0];
|
||||||
if (!exists($language_map->{$lang})) {
|
my $rc = 0;
|
||||||
print STDERR "$lang is not a valid language.\n";
|
if ($lang eq 'all') {
|
||||||
exit(1);
|
foreach my $l (sort(keys(%$language_map))) {
|
||||||
}
|
if (check($l)) {
|
||||||
|
$rc = 1;
|
||||||
my $flag = $language_map->{$lang};
|
}
|
||||||
print STDERR "Testing for: $lang - $flag.\n";
|
}
|
||||||
my_sys("make clean > /dev/null 2>&1") && die("make clean failed");
|
|
||||||
my_sys("make -j6 all LANGDEF=-DLANG=$flag > /dev/null 2>&1") && die("make all failed");
|
|
||||||
my_sys("./remind -q -r ../tests/tstlang.rem 2022-03-23 11:44 > test-$lang-compiled.out 2>&1");
|
|
||||||
|
|
||||||
my_sys("make clean > /dev/null 2>&1") && die("make clean failed");
|
|
||||||
my_sys("make -j6 all > /dev/null 2>&1") && die("make all failed");
|
|
||||||
my_sys("./remind -q -r -ii=\\\"../include/lang/$lang.rem\\\" ../tests/tstlang.rem 2022-03-23 11:44 > test-$lang-runtime.out 2>&1");
|
|
||||||
|
|
||||||
my $rc = my_sys("cmp test-$lang-compiled.out test-$lang-runtime.out > /dev/null 2>&1");
|
|
||||||
if ($rc == 0) {
|
|
||||||
print STDERR "Congrats! Compiled and runtime language output matches for $lang.\n";
|
|
||||||
} else {
|
} else {
|
||||||
print STDERR "Whoops. Compiled and runtime language output differs for $lang.\n"
|
$rc = check($lang);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit($rc);
|
||||||
|
|
||||||
|
sub check
|
||||||
|
{
|
||||||
|
my ($lang) = @_;
|
||||||
|
if (!exists($language_map->{$lang})) {
|
||||||
|
print STDERR "$lang is not a valid language.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $flag = $language_map->{$lang};
|
||||||
|
print STDERR "Testing for: $lang - $flag.\n";
|
||||||
|
my_sys("make clean > /dev/null 2>&1") && die("make clean failed");
|
||||||
|
my_sys("make -j18 all LANGDEF=-DLANG=$flag > /dev/null 2>&1") && die("make all failed");
|
||||||
|
my_sys("./remind -q -r ../tests/tstlang.rem 2022-03-23 11:44 > test-$lang-compiled.out 2>&1");
|
||||||
|
|
||||||
|
my_sys("make clean > /dev/null 2>&1") && die("make clean failed");
|
||||||
|
my_sys("make -j18 all > /dev/null 2>&1") && die("make all failed");
|
||||||
|
my_sys("./remind -q -r -ii=\\\"../include/lang/$lang.rem\\\" ../tests/tstlang.rem 2022-03-23 11:44 > test-$lang-runtime.out 2>&1");
|
||||||
|
|
||||||
|
my $rc = my_sys("cmp test-$lang-compiled.out test-$lang-runtime.out > /dev/null 2>&1");
|
||||||
|
if ($rc == 0) {
|
||||||
|
print STDERR "Congrats! Compiled and runtime language output matches for $lang.\n";
|
||||||
|
} else {
|
||||||
|
print STDERR "Whoops. Compiled and runtime language output differs for $lang.\n"
|
||||||
|
}
|
||||||
|
return $rc;
|
||||||
|
}
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
sub my_sys
|
sub my_sys
|
||||||
|
|||||||
@@ -1,22 +1,30 @@
|
|||||||
/* Define if utime(file, NULL) sets file's timestamp to the present. */
|
|
||||||
#undef HAVE_UTIME_NULL
|
|
||||||
|
|
||||||
/* Define if you can safely include both <sys/time.h> and <time.h>. */
|
|
||||||
#undef TIME_WITH_SYS_TIME
|
|
||||||
|
|
||||||
/* Define if your <sys/time.h> declares struct tm. */
|
/* Define if your <sys/time.h> declares struct tm. */
|
||||||
#undef TM_IN_SYS_TIME
|
#undef TM_IN_SYS_TIME
|
||||||
|
|
||||||
/* Define if you have the <sys/types.h> header file. */
|
/* Define if you have the <sys/types.h> header file. */
|
||||||
#undef HAVE_SYS_TYPES_H
|
#undef HAVE_SYS_TYPES_H
|
||||||
|
|
||||||
|
/* Define if you have the <sys/inotify.h> header file. */
|
||||||
|
#undef HAVE_SYS_INOTIFY_H
|
||||||
|
|
||||||
/* Define if you have the <glob.h> header file */
|
/* Define if you have the <glob.h> header file */
|
||||||
#undef HAVE_GLOB_H
|
#undef HAVE_GLOB_H
|
||||||
|
|
||||||
|
/* Define if you have <stdint.h> */
|
||||||
|
#undef HAVE_STDINT_H
|
||||||
|
|
||||||
|
#undef HAVE_STRINGS_H
|
||||||
|
|
||||||
|
#undef HAVE_STRDUP
|
||||||
|
#undef HAVE_STRCASECMP
|
||||||
|
#undef HAVE_STRNCASECMP
|
||||||
|
|
||||||
#undef HAVE_WCTYPE_H
|
#undef HAVE_WCTYPE_H
|
||||||
|
|
||||||
#undef HAVE_LOCALE_H
|
#undef HAVE_LOCALE_H
|
||||||
|
|
||||||
|
#undef HAVE_INOTIFY_INIT1
|
||||||
|
|
||||||
#undef HAVE_LANGINFO_H
|
#undef HAVE_LANGINFO_H
|
||||||
|
|
||||||
#undef HAVE_GLOB
|
#undef HAVE_GLOB
|
||||||
@@ -37,4 +45,8 @@
|
|||||||
/* The number of bytes in a unsigned long. */
|
/* The number of bytes in a unsigned long. */
|
||||||
#undef SIZEOF_UNSIGNED_LONG
|
#undef SIZEOF_UNSIGNED_LONG
|
||||||
|
|
||||||
|
#define PACKAGE_NAME "@PACKAGE_NAME@"
|
||||||
|
#define PACKAGE_URL "@PACKAGE_URL@"
|
||||||
|
|
||||||
#include "custom.h"
|
#include "custom.h"
|
||||||
|
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
/* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */
|
/* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
#define VAL_STACK_SIZE 1000
|
#define VAL_STACK_SIZE 100
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */
|
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */
|
||||||
@@ -166,6 +166,10 @@
|
|||||||
|
|
||||||
#define PASSTHRU_LEN 32
|
#define PASSTHRU_LEN 32
|
||||||
|
|
||||||
|
#define MAX_RECURSION_LEVEL 1000
|
||||||
|
|
||||||
|
#define MAX_FUNC_ARGS 64
|
||||||
|
|
||||||
#define PSBEGIN "# rem2ps begin"
|
#define PSBEGIN "# rem2ps begin"
|
||||||
#define PSEND "# rem2ps end"
|
#define PSEND "# rem2ps end"
|
||||||
|
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
/* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */
|
/* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
#define VAL_STACK_SIZE 1000
|
#define VAL_STACK_SIZE 100
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */
|
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */
|
||||||
@@ -166,6 +166,10 @@
|
|||||||
|
|
||||||
#define PASSTHRU_LEN 32
|
#define PASSTHRU_LEN 32
|
||||||
|
|
||||||
|
#define MAX_RECURSION_LEVEL 1000
|
||||||
|
|
||||||
|
#define MAX_FUNC_ARGS 64
|
||||||
|
|
||||||
#define PSBEGIN "# rem2ps begin"
|
#define PSBEGIN "# rem2ps begin"
|
||||||
#define PSEND "# rem2ps end"
|
#define PSEND "# rem2ps end"
|
||||||
|
|
||||||
|
|||||||
118
src/dorem.c
118
src/dorem.c
@@ -7,7 +7,7 @@
|
|||||||
/* commands. */
|
/* commands. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -23,9 +23,8 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "expr.h"
|
|
||||||
|
|
||||||
static int ParseTimeTrig (ParsePtr s, TimeTrig *tim, int save_in_globals);
|
static int ParseTimeTrig (ParsePtr s, TimeTrig *tim);
|
||||||
static int ParseLocalOmit (ParsePtr s, Trigger *t);
|
static int ParseLocalOmit (ParsePtr s, Trigger *t);
|
||||||
static int ParseScanFrom (ParsePtr s, Trigger *t, int type);
|
static int ParseScanFrom (ParsePtr s, Trigger *t, int type);
|
||||||
static int ParsePriority (ParsePtr s, Trigger *t);
|
static int ParsePriority (ParsePtr s, Trigger *t);
|
||||||
@@ -63,7 +62,7 @@ int DoRem(ParsePtr p)
|
|||||||
DBufInit(&buf);
|
DBufInit(&buf);
|
||||||
|
|
||||||
/* Parse the trigger date and time */
|
/* Parse the trigger date and time */
|
||||||
if ( (r=ParseRem(p, &trig, &tim, 1)) ) {
|
if ( (r=ParseRem(p, &trig, &tim)) ) {
|
||||||
FreeTrig(&trig);
|
FreeTrig(&trig);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -163,6 +162,7 @@ int DoRem(ParsePtr p)
|
|||||||
if (p->expr_happened) {
|
if (p->expr_happened) {
|
||||||
if (p->nonconst_expr) {
|
if (p->nonconst_expr) {
|
||||||
PurgeEchoLine("%s\n", "#!P: Next line may have expired, but contains non-constant expression");
|
PurgeEchoLine("%s\n", "#!P: Next line may have expired, but contains non-constant expression");
|
||||||
|
PurgeEchoLine("%s\n", "#!P: or a relative SCANFROM clause");
|
||||||
PurgeEchoLine("%s\n", CurLine);
|
PurgeEchoLine("%s\n", CurLine);
|
||||||
} else {
|
} else {
|
||||||
PurgeEchoLine("%s\n", "#!P: Next line has expired, but contains expression... please verify");
|
PurgeEchoLine("%s\n", "#!P: Next line has expired, but contains expression... please verify");
|
||||||
@@ -192,7 +192,7 @@ int DoRem(ParsePtr p)
|
|||||||
|
|
||||||
r = OK;
|
r = OK;
|
||||||
if (ShouldTriggerReminder(&trig, &tim, dse, &err)) {
|
if (ShouldTriggerReminder(&trig, &tim, dse, &err)) {
|
||||||
if ( (r=TriggerReminder(p, &trig, &tim, dse, 0)) ) {
|
if ( (r=TriggerReminder(p, &trig, &tim, dse, 0, NULL)) ) {
|
||||||
FreeTrig(&trig);
|
FreeTrig(&trig);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -220,7 +220,7 @@ int DoRem(ParsePtr p)
|
|||||||
/* trigger structure. */
|
/* trigger structure. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
|
||||||
{
|
{
|
||||||
register int r;
|
register int r;
|
||||||
DynamicBuffer buf;
|
DynamicBuffer buf;
|
||||||
@@ -262,10 +262,6 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
trig->need_wkday = 0;
|
trig->need_wkday = 0;
|
||||||
trig->adj_for_last = 0;
|
trig->adj_for_last = 0;
|
||||||
|
|
||||||
if (save_in_globals) {
|
|
||||||
LastTriggerTime = NO_TIME;
|
|
||||||
}
|
|
||||||
|
|
||||||
int parsing = 1;
|
int parsing = 1;
|
||||||
while(parsing) {
|
while(parsing) {
|
||||||
/* Read space-delimited string */
|
/* Read space-delimited string */
|
||||||
@@ -315,10 +311,6 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
trig->m = m;
|
trig->m = m;
|
||||||
trig->d = d;
|
trig->d = d;
|
||||||
tim->ttime = (tok.val % MINUTES_PER_DAY);
|
tim->ttime = (tok.val % MINUTES_PER_DAY);
|
||||||
if (save_in_globals) {
|
|
||||||
LastTriggerTime = tim->ttime;
|
|
||||||
SaveLastTimeTrig(tim);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_WkDay:
|
case T_WkDay:
|
||||||
@@ -355,14 +347,14 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
if (tim->ttime != NO_TIME) return E_TIME_TWICE;
|
if (tim->ttime != NO_TIME) return E_TIME_TWICE;
|
||||||
tim->ttime = tok.val;
|
tim->ttime = tok.val;
|
||||||
r = ParseTimeTrig(s, tim, save_in_globals);
|
r = ParseTimeTrig(s, tim);
|
||||||
if (r) return r;
|
if (r) return r;
|
||||||
trig->duration_days = ComputeTrigDuration(tim);
|
trig->duration_days = ComputeTrigDuration(tim);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_At:
|
case T_At:
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
r=ParseTimeTrig(s, tim, save_in_globals);
|
r=ParseTimeTrig(s, tim);
|
||||||
if (r) return r;
|
if (r) return r;
|
||||||
trig->duration_days = ComputeTrigDuration(tim);
|
trig->duration_days = ComputeTrigDuration(tim);
|
||||||
break;
|
break;
|
||||||
@@ -481,10 +473,10 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
r=ParseToken(s, &buf);
|
r=ParseToken(s, &buf);
|
||||||
if (r) return r;
|
if (r) return r;
|
||||||
StrnCpy(trig->omitfunc, DBufValue(&buf), VAR_NAME_LEN);
|
StrnCpy(trig->omitfunc, DBufValue(&buf), VAR_NAME_LEN);
|
||||||
|
strtolower(trig->omitfunc);
|
||||||
/* An OMITFUNC counts as a nonconst_expr! */
|
/* An OMITFUNC counts as a nonconst_expr! */
|
||||||
s->expr_happened = 1;
|
s->expr_happened = 1;
|
||||||
s->nonconst_expr = 1;
|
s->nonconst_expr = 1;
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -492,6 +484,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
r=ParseToken(s, &buf);
|
r=ParseToken(s, &buf);
|
||||||
if(r) return r;
|
if(r) return r;
|
||||||
StrnCpy(trig->warn, DBufValue(&buf), VAR_NAME_LEN);
|
StrnCpy(trig->warn, DBufValue(&buf), VAR_NAME_LEN);
|
||||||
|
strtolower(trig->warn);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -522,9 +515,6 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
} else {
|
} else {
|
||||||
tim->duration = NO_TIME;
|
tim->duration = NO_TIME;
|
||||||
}
|
}
|
||||||
if (save_in_globals) {
|
|
||||||
SaveLastTimeTrig(tim);
|
|
||||||
}
|
|
||||||
trig->duration_days = ComputeTrigDuration(tim);
|
trig->duration_days = ComputeTrigDuration(tim);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -536,6 +526,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
r=ParseToken(s, &buf);
|
r=ParseToken(s, &buf);
|
||||||
if(r) return r;
|
if(r) return r;
|
||||||
StrnCpy(trig->sched, DBufValue(&buf), VAR_NAME_LEN);
|
StrnCpy(trig->sched, DBufValue(&buf), VAR_NAME_LEN);
|
||||||
|
strtolower(trig->sched);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -608,7 +599,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
/* ParseTimeTrig - parse the AT part of a timed reminder */
|
/* ParseTimeTrig - parse the AT part of a timed reminder */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
|
static int ParseTimeTrig(ParsePtr s, TimeTrig *tim)
|
||||||
{
|
{
|
||||||
Token tok;
|
Token tok;
|
||||||
int r;
|
int r;
|
||||||
@@ -643,11 +634,6 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
|
|||||||
default:
|
default:
|
||||||
if (tim->ttime == NO_TIME) return E_EXPECT_TIME;
|
if (tim->ttime == NO_TIME) return E_EXPECT_TIME;
|
||||||
|
|
||||||
/* Save trigger time in global variable */
|
|
||||||
if (save_in_globals) {
|
|
||||||
LastTriggerTime = tim->ttime;
|
|
||||||
SaveLastTimeTrig(tim);
|
|
||||||
}
|
|
||||||
PushToken(DBufValue(&buf), s);
|
PushToken(DBufValue(&buf), s);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
return OK;
|
return OK;
|
||||||
@@ -679,6 +665,9 @@ static int ParseLocalOmit(ParsePtr s, Trigger *t)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
if (t->localomit == NO_WD) {
|
||||||
|
return E_EXPECTING_WEEKDAY;
|
||||||
|
}
|
||||||
PushToken(DBufValue(&buf), s);
|
PushToken(DBufValue(&buf), s);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
return OK;
|
return OK;
|
||||||
@@ -873,6 +862,9 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
|
|||||||
tok.val = -tok.val;
|
tok.val = -tok.val;
|
||||||
}
|
}
|
||||||
FromDSE(DSEToday - tok.val, &y, &m, &d);
|
FromDSE(DSEToday - tok.val, &y, &m, &d);
|
||||||
|
/* Don't purge reminders with a relative scanfrom */
|
||||||
|
s->expr_happened = 1;
|
||||||
|
s->nonconst_expr = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -910,7 +902,7 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
|
|||||||
/* Trigger the reminder if it's a RUN or MSG type. */
|
/* Trigger the reminder if it's a RUN or MSG type. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued)
|
int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued, DynamicBuffer *output)
|
||||||
{
|
{
|
||||||
int r, y, m, d;
|
int r, y, m, d;
|
||||||
char PrioExpr[VAR_NAME_LEN+25];
|
char PrioExpr[VAR_NAME_LEN+25];
|
||||||
@@ -977,7 +969,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
|||||||
}
|
}
|
||||||
/* If it's a MSG-type reminder, and no -k option was used, issue the banner. */
|
/* If it's a MSG-type reminder, and no -k option was used, issue the banner. */
|
||||||
if ((t->typ == MSG_TYPE || t->typ == MSF_TYPE)
|
if ((t->typ == MSG_TYPE || t->typ == MSF_TYPE)
|
||||||
&& !DidMsgReminder && !NextMode && !msg_command) {
|
&& !DidMsgReminder && !NextMode && !msg_command && !is_queued) {
|
||||||
DidMsgReminder = 1;
|
DidMsgReminder = 1;
|
||||||
if (!DoSubstFromString(DBufValue(&Banner), &buf,
|
if (!DoSubstFromString(DBufValue(&Banner), &buf,
|
||||||
DSEToday, NO_TIME) &&
|
DSEToday, NO_TIME) &&
|
||||||
@@ -1044,11 +1036,18 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
|||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%s%s%s\n", DBufValue(&calRow), DBufValue(&pre_buf), DBufValue(&buf));
|
r = OK;
|
||||||
|
if (output) {
|
||||||
|
if (DBufPuts(output, DBufValue(&calRow)) != OK) r = E_NO_MEM;
|
||||||
|
if (DBufPuts(output, DBufValue(&pre_buf)) != OK) r = E_NO_MEM;
|
||||||
|
if (DBufPuts(output, DBufValue(&buf)) != OK) r = E_NO_MEM;
|
||||||
|
} else {
|
||||||
|
printf("%s%s%s\n", DBufValue(&calRow), DBufValue(&pre_buf), DBufValue(&buf));
|
||||||
|
}
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
DBufFree(&pre_buf);
|
DBufFree(&pre_buf);
|
||||||
DBufFree(&calRow);
|
DBufFree(&calRow);
|
||||||
return OK;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Correct colors */
|
/* Correct colors */
|
||||||
@@ -1144,23 +1143,27 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
|
|||||||
case MSG_TYPE:
|
case MSG_TYPE:
|
||||||
case PASSTHRU_TYPE:
|
case PASSTHRU_TYPE:
|
||||||
if (msg_command) {
|
if (msg_command) {
|
||||||
DoMsgCommand(msg_command, DBufValue(&buf));
|
DoMsgCommand(msg_command, DBufValue(&buf), is_queued);
|
||||||
} else {
|
} else {
|
||||||
/* Add a space before "NOTE endreminder" */
|
if (output) {
|
||||||
if (Daemon < 0 && !strncmp(DBufValue(&buf), "NOTE endreminder", 16)) {
|
DBufPuts(output, DBufValue(&buf));
|
||||||
printf(" %s", DBufValue(&buf));
|
|
||||||
} else {
|
} else {
|
||||||
printf("%s", DBufValue(&buf));
|
/* Add a space before "NOTE endreminder" */
|
||||||
|
if (IsServerMode() && !strncmp(DBufValue(&buf), "NOTE endreminder", 16)) {
|
||||||
|
printf(" %s", DBufValue(&buf));
|
||||||
|
} else {
|
||||||
|
printf("%s", DBufValue(&buf));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSF_TYPE:
|
case MSF_TYPE:
|
||||||
FillParagraph(DBufValue(&buf));
|
FillParagraph(DBufValue(&buf), output);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RUN_TYPE:
|
case RUN_TYPE:
|
||||||
System(DBufValue(&buf));
|
System(DBufValue(&buf), is_queued);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: /* Unknown/illegal type? */
|
default: /* Unknown/illegal type? */
|
||||||
@@ -1270,20 +1273,28 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
|
|||||||
{
|
{
|
||||||
int iter, dse, r, start;
|
int iter, dse, r, start;
|
||||||
Value v;
|
Value v;
|
||||||
char const *s;
|
expr_node *sat_node;
|
||||||
char const *t;
|
int nonconst = 0;
|
||||||
|
|
||||||
t = p->pos;
|
sat_node = ParseExpr(p, &r);
|
||||||
|
if (r != OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (!sat_node) {
|
||||||
|
return E_SWERR;
|
||||||
|
}
|
||||||
iter = 0;
|
iter = 0;
|
||||||
start = trig->scanfrom;
|
start = trig->scanfrom;
|
||||||
while (iter++ < MaxSatIter) {
|
while (iter++ < MaxSatIter) {
|
||||||
dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, 0);
|
dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, 0);
|
||||||
if (r) {
|
if (r) {
|
||||||
|
free_expr_tree(sat_node);
|
||||||
if (r == E_CANT_TRIG) return OK; else return r;
|
if (r == E_CANT_TRIG) return OK; else return r;
|
||||||
}
|
}
|
||||||
if (dse != start && trig->duration_days) {
|
if (dse != start && trig->duration_days) {
|
||||||
dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, trig->duration_days);
|
dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, trig->duration_days);
|
||||||
if (r) {
|
if (r) {
|
||||||
|
free_expr_tree(sat_node);
|
||||||
if (r == E_CANT_TRIG) return OK; else return r;
|
if (r == E_CANT_TRIG) return OK; else return r;
|
||||||
}
|
}
|
||||||
} else if (dse == start) {
|
} else if (dse == start) {
|
||||||
@@ -1296,13 +1307,18 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
|
|||||||
SaveAllTriggerInfo(trig, tt, dse, tt->ttime, 1);
|
SaveAllTriggerInfo(trig, tt, dse, tt->ttime, 1);
|
||||||
}
|
}
|
||||||
if (dse == -1) {
|
if (dse == -1) {
|
||||||
|
free_expr_tree(sat_node);
|
||||||
return E_EXPIRED;
|
return E_EXPIRED;
|
||||||
}
|
}
|
||||||
s = p->pos;
|
r = evaluate_expression(sat_node, NULL, &v, &nonconst);
|
||||||
r = EvaluateExpr(p, &v);
|
if (r) {
|
||||||
t = p->pos;
|
free_expr_tree(sat_node);
|
||||||
if (r) return r;
|
return r;
|
||||||
if (v.type != INT_TYPE && v.type != STR_TYPE) return E_BAD_TYPE;
|
}
|
||||||
|
if (v.type != INT_TYPE && v.type != STR_TYPE) {
|
||||||
|
free_expr_tree(sat_node);
|
||||||
|
return E_BAD_TYPE;
|
||||||
|
}
|
||||||
if ((v.type == INT_TYPE && v.v.val) ||
|
if ((v.type == INT_TYPE && v.v.val) ||
|
||||||
(v.type == STR_TYPE && *v.v.str)) {
|
(v.type == STR_TYPE && *v.v.str)) {
|
||||||
AdjustTriggerForDuration(trig->scanfrom, dse, trig, tt, 1);
|
AdjustTriggerForDuration(trig->scanfrom, dse, trig, tt, 1);
|
||||||
@@ -1327,17 +1343,17 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
|
|||||||
}
|
}
|
||||||
fprintf(ErrFp, "\n");
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
|
free_expr_tree(sat_node);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
p->pos = s;
|
|
||||||
if (dse+trig->duration_days < start) {
|
if (dse+trig->duration_days < start) {
|
||||||
start++;
|
start++;
|
||||||
} else {
|
} else {
|
||||||
start = dse+trig->duration_days+1;
|
start = dse+trig->duration_days+1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p->pos = t;
|
|
||||||
LastTrigValid = 0;
|
LastTrigValid = 0;
|
||||||
|
free_expr_tree(sat_node);
|
||||||
return E_CANT_TRIG;
|
return E_CANT_TRIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1387,7 +1403,7 @@ static int ParsePriority(ParsePtr s, Trigger *t)
|
|||||||
/* Execute the '-k' command, escaping shell chars in message. */
|
/* Execute the '-k' command, escaping shell chars in message. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int DoMsgCommand(char const *cmd, char const *msg)
|
int DoMsgCommand(char const *cmd, char const *msg, int is_queued)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
int i, l;
|
int i, l;
|
||||||
@@ -1424,7 +1440,7 @@ int DoMsgCommand(char const *cmd, char const *msg)
|
|||||||
}
|
}
|
||||||
r = OK;
|
r = OK;
|
||||||
|
|
||||||
System(DBufValue(&execBuffer));
|
System(DBufValue(&execBuffer), is_queued);
|
||||||
|
|
||||||
finished:
|
finished:
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
/* reminders are triggered. */
|
/* reminders are triggered. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "expr.h"
|
#include "types.h"
|
||||||
#define L_IN_DOSUBST
|
#define L_IN_DOSUBST
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
@@ -50,7 +49,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
int err, done;
|
int err, done;
|
||||||
int c;
|
int c;
|
||||||
int d, m, y;
|
int d, m, y;
|
||||||
int tim = tt->ttime;
|
int tim = NO_TIME;
|
||||||
int h, min, hh, ch, cmin, chh;
|
int h, min, hh, ch, cmin, chh;
|
||||||
int i;
|
int i;
|
||||||
char const *pm, *cpm;
|
char const *pm, *cpm;
|
||||||
@@ -72,6 +71,9 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
|
|
||||||
FromDSE(dse, &y, &m, &d);
|
FromDSE(dse, &y, &m, &d);
|
||||||
|
|
||||||
|
if (tt) {
|
||||||
|
tim = tt->ttime;
|
||||||
|
}
|
||||||
if (tim == NO_TIME) tim = curtime;
|
if (tim == NO_TIME) tim = curtime;
|
||||||
tdiff = tim - curtime;
|
tdiff = tim - curtime;
|
||||||
adiff = ABS(tdiff);
|
adiff = ABS(tdiff);
|
||||||
@@ -239,7 +241,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i < 64) {
|
if (i < 64) {
|
||||||
*ss++ = c;
|
*ss++ = tolower(c);
|
||||||
*ss = 0;
|
*ss = 0;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@@ -266,10 +268,10 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
done = 0;
|
done = 0;
|
||||||
snprintf(uf, sizeof(uf), "subst_%c", c);
|
snprintf(uf, sizeof(uf), "subst_%c", tolower(c));
|
||||||
if (UserFuncExists(uf) == 3) {
|
if (UserFuncExists(uf) == 3) {
|
||||||
snprintf(s, sizeof(s), "subst_%c(%d,'%04d-%02d-%02d',%02d:%02d)",
|
snprintf(s, sizeof(s), "subst_%c(%d,'%04d-%02d-%02d',%02d:%02d)",
|
||||||
c, altmode ? 1 : 0, y, m+1, d, h, min);
|
tolower(c), altmode ? 1 : 0, y, m+1, d, h, min);
|
||||||
expr = (char const *) s;
|
expr = (char const *) s;
|
||||||
r = EvalExpr(&expr, &v, NULL);
|
r = EvalExpr(&expr, &v, NULL);
|
||||||
if (r == OK) {
|
if (r == OK) {
|
||||||
@@ -341,10 +343,10 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
|
|
||||||
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
snprintf(uf, sizeof(uf), "subst_%cx", c);
|
snprintf(uf, sizeof(uf), "subst_%cx", tolower(c));
|
||||||
if (UserFuncExists(uf) == 3) {
|
if (UserFuncExists(uf) == 3) {
|
||||||
snprintf(s, sizeof(s), "subst_%cx(%d,'%04d-%02d-%02d',%02d:%02d)",
|
snprintf(s, sizeof(s), "subst_%cx(%d,'%04d-%02d-%02d',%02d:%02d)",
|
||||||
c, altmode ? 1 : 0, y, m+1, d, h, min);
|
tolower(c), altmode ? 1 : 0, y, m+1, d, h, min);
|
||||||
expr = (char const *) s;
|
expr = (char const *) s;
|
||||||
r = EvalExpr(&expr, &v, NULL);
|
r = EvalExpr(&expr, &v, NULL);
|
||||||
if (r == OK) {
|
if (r == OK) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* buffers. */
|
/* buffers. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -124,7 +124,9 @@ int DBufPuts(DynamicBuffer *dbuf, char const *str)
|
|||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
void DBufFree(DynamicBuffer *dbuf)
|
void DBufFree(DynamicBuffer *dbuf)
|
||||||
{
|
{
|
||||||
if (dbuf->buffer != dbuf->staticBuf) free(dbuf->buffer);
|
if (dbuf->buffer != NULL && dbuf->buffer != dbuf->staticBuf) {
|
||||||
|
free(dbuf->buffer);
|
||||||
|
}
|
||||||
DBufInit(dbuf);
|
DBufInit(dbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
223
src/err.h
223
src/err.h
@@ -5,7 +5,7 @@
|
|||||||
/* Error definitions. */
|
/* Error definitions. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -121,6 +121,11 @@
|
|||||||
#define E_STRING_TOO_LONG 101
|
#define E_STRING_TOO_LONG 101
|
||||||
#define E_TIME_TWICE 102
|
#define E_TIME_TWICE 102
|
||||||
#define E_DURATION_NO_AT 103
|
#define E_DURATION_NO_AT 103
|
||||||
|
#define E_EXPECTING_WEEKDAY 104
|
||||||
|
#define E_REPEATED_ARG 105
|
||||||
|
#define E_EXPR_DISABLED 106
|
||||||
|
#define E_TIME_EXCEEDED 107
|
||||||
|
|
||||||
#ifdef MK_GLOBALS
|
#ifdef MK_GLOBALS
|
||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
#define EXTERN
|
#define EXTERN
|
||||||
@@ -129,115 +134,123 @@
|
|||||||
#define EXTERN extern
|
#define EXTERN extern
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define STR(X) STR2(X)
|
||||||
|
#define STR2(X) #X
|
||||||
|
|
||||||
|
|
||||||
#ifndef L_ERR_OVERRIDE
|
#ifndef L_ERR_OVERRIDE
|
||||||
EXTERN char *ErrMsg[]
|
EXTERN char *ErrMsg[]
|
||||||
|
|
||||||
#ifdef MK_GLOBALS
|
#ifdef MK_GLOBALS
|
||||||
= {
|
= {
|
||||||
"Ok",
|
/* OK */ "Ok",
|
||||||
"Missing ']'",
|
/* E_MISS_END */ "Missing ']'",
|
||||||
"Missing quote",
|
/* E_MISS_QUOTE */ "Missing quote",
|
||||||
"Expression too complex - too many operators",
|
/* E_OP_STK_OVER */ "Expression too complex",
|
||||||
"Expression too complex - too many operands",
|
/* E_VA_STK_OVER */ "Expression too complex - too many operands",
|
||||||
"Missing ')'",
|
/* E_MISS_RIGHT_PAREN */ "Missing ')'",
|
||||||
"Undefined function",
|
/* E_UNDEF_FUNC */ "Undefined function",
|
||||||
"Illegal character",
|
/* E_ILLEGAL_CHAR */ "Illegal character",
|
||||||
"Expecting binary operator",
|
/* E_EXPECTING_BINOP */ "Expecting binary operator",
|
||||||
"Out of memory",
|
/* E_NO_MEM */ "Out of memory",
|
||||||
"Ill-formed number",
|
/* E_BAD_NUMBER */ "Ill-formed number",
|
||||||
"Op stack underflow - internal error",
|
/* E_OP_STK_UNDER */ "Op stack underflow - internal error",
|
||||||
"Va stack underflow - internal error",
|
/* E_VA_STK_UNDER */ "Va stack underflow - internal error",
|
||||||
"Can't coerce",
|
/* E_CANT_COERCE */ "Can't coerce",
|
||||||
"Type mismatch",
|
/* E_BAD_TYPE */ "Type mismatch",
|
||||||
"Date overflow",
|
/* E_DATE_OVER */ "Date overflow",
|
||||||
"Stack error - internal error",
|
/* E_STACK_ERR */ "Stack error - internal error",
|
||||||
"Division by zero",
|
/* E_DIV_ZERO */ "Division by zero",
|
||||||
"Undefined variable",
|
/* E_NOSUCH_VAR */ "Undefined variable",
|
||||||
"Unexpected end of line",
|
/* E_EOLN */ "Unexpected end of line",
|
||||||
"Unexpected end of file",
|
/* E_EOF */ "Unexpected end of file",
|
||||||
"I/O error",
|
/* E_IO_ERR */ "I/O error",
|
||||||
"Line too long",
|
/* E_LINE_2_LONG */ "Line too long",
|
||||||
"Internal error",
|
/* E_SWERR */ "Internal error",
|
||||||
"Bad date specification",
|
/* E_BAD_DATE */ "Bad date specification",
|
||||||
"Not enough arguments",
|
/* E_2FEW_ARGS */ "Not enough arguments",
|
||||||
"Too many arguments",
|
/* E_2MANY_ARGS */ "Too many arguments",
|
||||||
"Ill-formed time",
|
/* E_BAD_TIME */ "Ill-formed time",
|
||||||
"Number too high",
|
/* E_2HIGH */ "Number too high",
|
||||||
"Number too low",
|
/* E_2LOW */ "Number too low",
|
||||||
"Can't open file",
|
/* E_CANT_OPEN */ "Can't open file",
|
||||||
"INCLUDE nested too deeply",
|
/* E_NESTED_INCLUDE */ "INCLUDE nested too deeply (max. " STR(INCLUDE_NEST) ")",
|
||||||
"Parse error",
|
/* E_PARSE_ERR */ "Parse error",
|
||||||
"Can't compute trigger",
|
/* E_CANT_TRIG */ "Can't compute trigger",
|
||||||
"Too many nested IFs",
|
/* E_NESTED_IF */ "Too many nested IFs",
|
||||||
"ELSE with no matching IF",
|
/* E_ELSE_NO_IF */ "ELSE with no matching IF",
|
||||||
"ENDIF with no matching IF",
|
/* E_ENDIF_NO_IF */ "ENDIF with no matching IF",
|
||||||
"Can't OMIT every weekday",
|
/* E_2MANY_LOCALOMIT */ "Can't OMIT every weekday",
|
||||||
"Extraneous token(s) on line",
|
/* E_EXTRANEOUS_TOKEN */ "Extraneous token(s) on line",
|
||||||
"POP-OMIT-CONTEXT without matching PUSH-OMIT-CONTEXT",
|
/* E_POP_NO_PUSH */ "POP-OMIT-CONTEXT without matching PUSH-OMIT-CONTEXT",
|
||||||
"RUN disabled",
|
/* E_RUN_DISABLED */ "RUN disabled",
|
||||||
"Domain error",
|
/* E_DOMAIN_ERR */ "Domain error",
|
||||||
"Invalid identifier",
|
/* E_BAD_ID */ "Invalid identifier",
|
||||||
"Recursive function call detected",
|
/* E_RECURSIVE */ "Too many recursive function calls",
|
||||||
"",
|
/* E_PARSE_AS_REM */ "",
|
||||||
"Cannot modify system variable",
|
/* E_CANT_MODIFY */ "Cannot modify system variable",
|
||||||
"C library function can't represent date/time",
|
/* E_MKTIME_PROBLEM */ "C library function can't represent date/time",
|
||||||
"Attempt to redefine built-in function",
|
/* E_REDEF_FUNC */ "Attempt to redefine built-in function",
|
||||||
"Can't nest function definition in expression",
|
/* E_CANTNEST_FDEF */ "Can't nest function definition in expression",
|
||||||
"Must fully specify date to use repeat factor",
|
/* E_REP_FULSPEC */ "Must fully specify date to use repeat factor",
|
||||||
"Year specified twice",
|
/* E_YR_TWICE */ "Year specified twice",
|
||||||
"Month specified twice",
|
/* E_MON_TWICE */ "Month specified twice",
|
||||||
"Day specified twice",
|
/* E_DAY_TWICE */ "Day specified twice",
|
||||||
"Unknown token",
|
/* E_UNKNOWN_TOKEN */ "Unknown token",
|
||||||
"Must specify month in OMIT command",
|
/* E_SPEC_MON */ "Must specify month in OMIT command",
|
||||||
"Too many partial OMITs",
|
/* E_2MANY_PART */ "Too many partial OMITs (max. " STR(MAX_PARTIAL_OMITS) ")",
|
||||||
"Too many full OMITs",
|
/* E_2MANY_FULL */ "Too many full OMITs (max. " STR(MAX_FULL_OMITS) ")",
|
||||||
"Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT",
|
/* E_PUSH_NOPOP */ "Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT",
|
||||||
"Error reading",
|
/* E_ERR_READING */ "Error reading",
|
||||||
"Expecting end-of-line",
|
/* E_EXPECTING_EOL */ "Expecting end-of-line",
|
||||||
"Invalid Hebrew date",
|
/* E_BAD_HEBDATE */ "Invalid Hebrew date",
|
||||||
"IIF needs odd number of arguments",
|
/* E_IIF_ODD */ "IIF needs odd number of arguments",
|
||||||
"Warning: Missing ENDIF",
|
/* E_MISS_ENDIF */ "Warning: Missing ENDIF",
|
||||||
"Expecting comma",
|
/* E_EXPECT_COMMA */ "Expecting comma",
|
||||||
"Weekday specified twice",
|
/* E_WD_TWICE */ "Weekday specified twice",
|
||||||
"Only use one of BEFORE, AFTER or SKIP",
|
/* E_SKIP_ERR */ "Only use one of BEFORE, AFTER or SKIP",
|
||||||
"Can't nest MSG, MSF, RUN, etc. in expression",
|
/* E_CANT_NEST_RTYPE */ "Can't nest MSG, MSF, RUN, etc. in expression",
|
||||||
"Repeat value specified twice",
|
/* E_REP_TWICE */ "Repeat value specified twice",
|
||||||
"Delta value specified twice",
|
/* E_DELTA_TWICE */ "Delta value specified twice",
|
||||||
"Back value specified twice",
|
/* E_BACK_TWICE */ "Back value specified twice",
|
||||||
"ONCE keyword used twice. (Hah.)",
|
/* E_ONCE_TWICE */ "ONCE keyword used twice. (Hah.)",
|
||||||
"Expecting time after AT",
|
/* E_EXPECT_TIME */ "Expecting time after AT",
|
||||||
"THROUGH/UNTIL keyword used twice",
|
/* E_UNTIL_TWICE */ "THROUGH/UNTIL keyword used twice",
|
||||||
"Incomplete date specification",
|
/* E_INCOMPLETE */ "Incomplete date specification",
|
||||||
"FROM/SCANFROM keyword used twice",
|
/* E_SCAN_TWICE */ "FROM/SCANFROM keyword used twice",
|
||||||
"Variable",
|
/* E_VAR */ "Variable",
|
||||||
"Value",
|
/* E_VAL */ "Value",
|
||||||
"*UNDEFINED*",
|
/* E_UNDEF */ "*UNDEFINED*",
|
||||||
"Entering UserFN",
|
/* E_ENTER_FUN */ "Entering UserFN",
|
||||||
"Leaving UserFN",
|
/* E_LEAVE_FUN */ "Leaving UserFN",
|
||||||
"Expired",
|
/* E_EXPIRED */ "Expired",
|
||||||
"fork() failed - can't do queued reminders",
|
/* E_CANTFORK */ "fork() failed - can't do queued reminders",
|
||||||
"Can't access file",
|
/* E_CANTACCESS */ "Can't access file",
|
||||||
"Illegal system date: Year is less than %d\n",
|
/* M_BAD_SYS_DATE */ "Illegal system date: Year is less than %d\n",
|
||||||
"Unknown debug flag '%c'\n",
|
/* M_BAD_DB_FLAG */ "Unknown debug flag '%c'\n",
|
||||||
"Unknown option '%c'\n",
|
/* M_BAD_OPTION */ "Unknown option '%c'\n",
|
||||||
"Unknown user '%s'\n",
|
/* M_BAD_USER */ "Unknown user '%s'\n",
|
||||||
"Could not change gid to %d\n",
|
/* M_NO_CHG_GID */ "Could not change gid to %d\n",
|
||||||
"Could not change uid to %d\n",
|
/* M_NO_CHG_UID */ "Could not change uid to %d\n",
|
||||||
"Out of memory for environment\n",
|
/* M_NOMEM_ENV */ "Out of memory for environment\n",
|
||||||
"Missing '=' sign",
|
/* E_MISS_EQ */ "Missing '=' sign",
|
||||||
"Missing variable name",
|
/* E_MISS_VAR */ "Missing variable name",
|
||||||
"Missing expression",
|
/* E_MISS_EXPR */ "Missing expression",
|
||||||
"Can't reset access date of %s\n",
|
/* M_CANTSET_ACCESS */ "Can't reset access date of %s\n",
|
||||||
"Remind: '-i' option: %s\n",
|
/* M_I_OPTION */ "Remind: '-i' option: %s\n",
|
||||||
"No reminders.",
|
/* E_NOREMINDERS */ "No reminders.",
|
||||||
"%d reminder(s) queued for later today.\n",
|
/* M_QUEUED */ "%d reminder(s) queued for later today.\n",
|
||||||
"Expecting number",
|
/* E_EXPECTING_NUMBER */ "Expecting number",
|
||||||
"Bad function in WARN clause",
|
/* M_BAD_WARN_FUNC */ "Bad function in WARN clause",
|
||||||
"Can't convert between time zones",
|
/* E_CANT_CONVERT_TZ */ "Can't convert between time zones",
|
||||||
"No files matching *.rem",
|
/* E_NO_MATCHING_REMS */ "No files matching *.rem",
|
||||||
"String too long",
|
/* E_STRING_TOO_LONG */ "String too long",
|
||||||
"Time specified twice",
|
/* E_TIME_TWICE */ "Time specified twice",
|
||||||
"Cannot specify DURATION without specifying AT"
|
/* E_DURATION_NO_AT */ "Cannot specify DURATION without specifying AT",
|
||||||
|
/* E_EXPECTING_WEEKDAY */ "Expecting weekday name",
|
||||||
|
/* E_REPEATED_ARG */ "Duplicate argument name",
|
||||||
|
/* E_EXPR_DISABLED */ "Expression evaluation is disabled",
|
||||||
|
/* E_TIME_EXCEEDED */ "Time limit for expression evaluation exceeded",
|
||||||
}
|
}
|
||||||
#endif /* MK_GLOBALS */
|
#endif /* MK_GLOBALS */
|
||||||
;
|
;
|
||||||
|
|||||||
3612
src/expr.c
3612
src/expr.c
File diff suppressed because it is too large
Load Diff
65
src/expr.h
65
src/expr.h
@@ -1,65 +0,0 @@
|
|||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* EXPR.H */
|
|
||||||
/* */
|
|
||||||
/* Contains a few definitions used by expression evaluator. */
|
|
||||||
/* */
|
|
||||||
/* This file is part of REMIND. */
|
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
|
|
||||||
/* Define the types of values */
|
|
||||||
#define ERR_TYPE 0
|
|
||||||
#define INT_TYPE 1
|
|
||||||
#define TIME_TYPE 2
|
|
||||||
#define DATE_TYPE 3
|
|
||||||
#define STR_TYPE 4
|
|
||||||
#define DATETIME_TYPE 5
|
|
||||||
#define SPECIAL_TYPE 6 /* Only for system variables */
|
|
||||||
|
|
||||||
/* Define stuff for parsing expressions */
|
|
||||||
#define BEG_OF_EXPR '['
|
|
||||||
#define END_OF_EXPR ']'
|
|
||||||
#define COMMA ','
|
|
||||||
|
|
||||||
#define UN_OP 0 /* Unary operator */
|
|
||||||
#define BIN_OP 1 /* Binary Operator */
|
|
||||||
#define FUNC 2 /* Function */
|
|
||||||
|
|
||||||
/* Make the pushing and popping of values and operators in-line code
|
|
||||||
for speed. BEWARE: These macros invoke return if an error happens ! */
|
|
||||||
|
|
||||||
#define PushOpStack(op) \
|
|
||||||
if (OpStackPtr >= OP_STACK_SIZE) \
|
|
||||||
return E_OP_STK_OVER; \
|
|
||||||
else \
|
|
||||||
OpStack[OpStackPtr++] = (op)
|
|
||||||
|
|
||||||
#define PopOpStack(op) \
|
|
||||||
if (OpStackPtr <= 0) \
|
|
||||||
return E_OP_STK_UNDER; \
|
|
||||||
else \
|
|
||||||
(op) = OpStack[--OpStackPtr]
|
|
||||||
|
|
||||||
#define PushValStack(val) \
|
|
||||||
if (ValStackPtr >= VAL_STACK_SIZE) \
|
|
||||||
return E_VA_STK_OVER; \
|
|
||||||
else \
|
|
||||||
ValStack[ValStackPtr++] = (val)
|
|
||||||
|
|
||||||
#define PopValStack(val) \
|
|
||||||
if (ValStackPtr <= 0) \
|
|
||||||
return E_VA_STK_UNDER; \
|
|
||||||
else \
|
|
||||||
(val) = ValStack[--ValStackPtr]
|
|
||||||
|
|
||||||
/* These functions are in utils.c and are used to detect overflow
|
|
||||||
in various arithmetic operators. They have to be in separate
|
|
||||||
functions with extern linkage to defeat compiler optimizations
|
|
||||||
that would otherwise break the overflow checks. */
|
|
||||||
extern int _private_mul_overflow(int a, int b);
|
|
||||||
extern int _private_add_overflow(int a, int b);
|
|
||||||
extern int _private_sub_overflow(int a, int b);
|
|
||||||
|
|
||||||
40
src/files.c
40
src/files.c
@@ -7,7 +7,7 @@
|
|||||||
/* files. */
|
/* files. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -42,8 +42,8 @@
|
|||||||
|
|
||||||
|
|
||||||
/* Convenient macros for closing files */
|
/* Convenient macros for closing files */
|
||||||
#define FCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL))
|
#define FCLOSE(fp) ((((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL))
|
||||||
#define PCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (pclose(fp),(fp)=NULL) : ((fp)=NULL))
|
#define PCLOSE(fp) ((((fp)!=stdin)) ? (pclose(fp),(fp)=NULL) : ((fp)=NULL))
|
||||||
|
|
||||||
/* Define the structures needed by the file caching system */
|
/* Define the structures needed by the file caching system */
|
||||||
typedef struct cache {
|
typedef struct cache {
|
||||||
@@ -79,6 +79,7 @@ typedef struct {
|
|||||||
int LineNo;
|
int LineNo;
|
||||||
unsigned int IfFlags;
|
unsigned int IfFlags;
|
||||||
int NumIfs;
|
int NumIfs;
|
||||||
|
int IfLinenos[IF_NEST];
|
||||||
long offset;
|
long offset;
|
||||||
CachedLine *CLine;
|
CachedLine *CLine;
|
||||||
int ownedByMe;
|
int ownedByMe;
|
||||||
@@ -100,6 +101,22 @@ static int CheckSafety (void);
|
|||||||
static int CheckSafetyAux (struct stat *statbuf);
|
static int CheckSafetyAux (struct stat *statbuf);
|
||||||
static int PopFile (void);
|
static int PopFile (void);
|
||||||
static int IncludeCmd(char const *);
|
static int IncludeCmd(char const *);
|
||||||
|
|
||||||
|
void set_cloexec(FILE *fp)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
int fd;
|
||||||
|
if (fp) {
|
||||||
|
fd = fileno(fp);
|
||||||
|
flags = fcntl(fd, F_GETFD);
|
||||||
|
if (flags >= 0) {
|
||||||
|
flags |= FD_CLOEXEC;
|
||||||
|
fcntl(fd, F_SETFD, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void OpenPurgeFile(char const *fname, char const *mode)
|
static void OpenPurgeFile(char const *fname, char const *mode)
|
||||||
{
|
{
|
||||||
DynamicBuffer fname_buf;
|
DynamicBuffer fname_buf;
|
||||||
@@ -123,6 +140,7 @@ static void OpenPurgeFile(char const *fname, char const *mode)
|
|||||||
if (!PurgeFP) {
|
if (!PurgeFP) {
|
||||||
fprintf(ErrFp, "Cannot open `%s' for writing: %s\n", DBufValue(&fname_buf), strerror(errno));
|
fprintf(ErrFp, "Cannot open `%s' for writing: %s\n", DBufValue(&fname_buf), strerror(errno));
|
||||||
}
|
}
|
||||||
|
set_cloexec(PurgeFP);
|
||||||
DBufFree(&fname_buf);
|
DBufFree(&fname_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,6 +345,7 @@ int OpenFile(char const *fname)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fp = fopen(fname, "r");
|
fp = fopen(fname, "r");
|
||||||
|
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, "Reading `%s': Opening file on disk\n", fname);
|
||||||
}
|
}
|
||||||
@@ -346,6 +365,7 @@ int OpenFile(char const *fname)
|
|||||||
if (strcmp(fname, "-")) {
|
if (strcmp(fname, "-")) {
|
||||||
fp = fopen(fname, "r");
|
fp = fopen(fname, "r");
|
||||||
if (!fp || !CheckSafety()) return E_CANT_OPEN;
|
if (!fp || !CheckSafety()) return E_CANT_OPEN;
|
||||||
|
set_cloexec(fp);
|
||||||
if (PurgeMode) OpenPurgeFile(fname, "w");
|
if (PurgeMode) OpenPurgeFile(fname, "w");
|
||||||
} else {
|
} else {
|
||||||
fp = stdin;
|
fp = stdin;
|
||||||
@@ -507,8 +527,14 @@ static int NextChainedFile(IncludeStruct *i)
|
|||||||
static int PopFile(void)
|
static int PopFile(void)
|
||||||
{
|
{
|
||||||
IncludeStruct *i;
|
IncludeStruct *i;
|
||||||
|
int j;
|
||||||
|
|
||||||
if (!Hush && NumIfs) Eprint("%s", ErrMsg[E_MISS_ENDIF]);
|
if (!Hush && NumIfs) {
|
||||||
|
Eprint("%s", ErrMsg[E_MISS_ENDIF]);
|
||||||
|
for (j=NumIfs-1; j >=0; j--) {
|
||||||
|
fprintf(ErrFp, "%s(%d): IF without ENDIF\n", FileName, IfLinenos[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!IStackPtr) return E_EOF;
|
if (!IStackPtr) return E_EOF;
|
||||||
i = &IStack[IStackPtr-1];
|
i = &IStack[IStackPtr-1];
|
||||||
|
|
||||||
@@ -528,6 +554,7 @@ static int PopFile(void)
|
|||||||
|
|
||||||
LineNo = i->LineNo;
|
LineNo = i->LineNo;
|
||||||
IfFlags = i->IfFlags;
|
IfFlags = i->IfFlags;
|
||||||
|
memcpy(IfLinenos, i->IfLinenos, IF_NEST);
|
||||||
NumIfs = i->NumIfs;
|
NumIfs = i->NumIfs;
|
||||||
CLine = i->CLine;
|
CLine = i->CLine;
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
@@ -542,6 +569,7 @@ static int PopFile(void)
|
|||||||
if (strcmp(i->filename, "-")) {
|
if (strcmp(i->filename, "-")) {
|
||||||
fp = fopen(i->filename, "r");
|
fp = fopen(i->filename, "r");
|
||||||
if (!fp || !CheckSafety()) return E_CANT_OPEN;
|
if (!fp || !CheckSafety()) return E_CANT_OPEN;
|
||||||
|
set_cloexec(fp);
|
||||||
if (PurgeMode) OpenPurgeFile(i->filename, "a");
|
if (PurgeMode) OpenPurgeFile(i->filename, "a");
|
||||||
} else {
|
} else {
|
||||||
fp = stdin;
|
fp = stdin;
|
||||||
@@ -851,6 +879,7 @@ static int IncludeCmd(char const *cmd)
|
|||||||
i->LineNo = LineNo;
|
i->LineNo = LineNo;
|
||||||
i->NumIfs = NumIfs;
|
i->NumIfs = NumIfs;
|
||||||
i->IfFlags = IfFlags;
|
i->IfFlags = IfFlags;
|
||||||
|
memcpy(i->IfLinenos, IfLinenos, IF_NEST);
|
||||||
i->CLine = CLine;
|
i->CLine = CLine;
|
||||||
i->offset = -1L;
|
i->offset = -1L;
|
||||||
i->chain = NULL;
|
i->chain = NULL;
|
||||||
@@ -953,6 +982,7 @@ int IncludeFile(char const *fname)
|
|||||||
i->LineNo = LineNo;
|
i->LineNo = LineNo;
|
||||||
i->NumIfs = NumIfs;
|
i->NumIfs = NumIfs;
|
||||||
i->IfFlags = IfFlags;
|
i->IfFlags = IfFlags;
|
||||||
|
memcpy(i->IfLinenos, IfLinenos, IF_NEST);
|
||||||
i->CLine = CLine;
|
i->CLine = CLine;
|
||||||
i->offset = -1L;
|
i->offset = -1L;
|
||||||
i->chain = NULL;
|
i->chain = NULL;
|
||||||
|
|||||||
706
src/funcs.c
706
src/funcs.c
@@ -6,11 +6,10 @@
|
|||||||
/* expressions. */
|
/* expressions. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@@ -24,6 +23,11 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_STRINGS_H
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
@@ -50,12 +54,13 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "expr.h"
|
|
||||||
|
|
||||||
/* Defines that used to be static variables */
|
/* Defines that used to be static variables */
|
||||||
#define Nargs (info->nargs)
|
#define Nargs (info->nargs)
|
||||||
#define RetVal (info->retval)
|
#define RetVal (info->retval)
|
||||||
|
|
||||||
|
#define DBG(x) do { if (DebugFlag & DB_PRTEXPR) { x; } } while(0)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
solstice_equinox_for_year(int y, int which);
|
solstice_equinox_for_year(int y, int which);
|
||||||
|
|
||||||
@@ -66,13 +71,11 @@ static int FAbs (func_info *);
|
|||||||
static int FAccess (func_info *);
|
static int FAccess (func_info *);
|
||||||
static int FAmpm (func_info *);
|
static int FAmpm (func_info *);
|
||||||
static int FAnsicolor (func_info *);
|
static int FAnsicolor (func_info *);
|
||||||
static int FTrig (func_info *);
|
|
||||||
static int FIsAny (func_info *);
|
|
||||||
static int FArgs (func_info *);
|
static int FArgs (func_info *);
|
||||||
static int FAsc (func_info *);
|
static int FAsc (func_info *);
|
||||||
static int FBaseyr (func_info *);
|
static int FBaseyr (func_info *);
|
||||||
static int FChar (func_info *);
|
static int FChar (func_info *);
|
||||||
static int FChoose (func_info *);
|
static int FChoose (expr_node *, Value *, Value *, int *);
|
||||||
static int FCoerce (func_info *);
|
static int FCoerce (func_info *);
|
||||||
static int FColumns (func_info *);
|
static int FColumns (func_info *);
|
||||||
static int FCurrent (func_info *);
|
static int FCurrent (func_info *);
|
||||||
@@ -99,8 +102,9 @@ static int FHebyear (func_info *);
|
|||||||
static int FHour (func_info *);
|
static int FHour (func_info *);
|
||||||
static int FHtmlEscape (func_info *);
|
static int FHtmlEscape (func_info *);
|
||||||
static int FHtmlStriptags (func_info *);
|
static int FHtmlStriptags (func_info *);
|
||||||
static int FIif (func_info *);
|
static int FIif (expr_node *, Value *, Value *, int *);
|
||||||
static int FIndex (func_info *);
|
static int FIndex (func_info *);
|
||||||
|
static int FIsAny (func_info *);
|
||||||
static int FIsdst (func_info *);
|
static int FIsdst (func_info *);
|
||||||
static int FIsleap (func_info *);
|
static int FIsleap (func_info *);
|
||||||
static int FIsomitted (func_info *);
|
static int FIsomitted (func_info *);
|
||||||
@@ -117,6 +121,7 @@ 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 FMoontime (func_info *);
|
static int FMoontime (func_info *);
|
||||||
|
static int FMultiTrig (func_info *);
|
||||||
static int FNDawn (func_info *);
|
static int FNDawn (func_info *);
|
||||||
static int FNDusk (func_info *);
|
static int FNDusk (func_info *);
|
||||||
static int FNonomitted (func_info *);
|
static int FNonomitted (func_info *);
|
||||||
@@ -134,6 +139,7 @@ static int FRealtoday (func_info *);
|
|||||||
static int FRows (func_info *);
|
static int FRows (func_info *);
|
||||||
static int FSgn (func_info *);
|
static int FSgn (func_info *);
|
||||||
static int FShell (func_info *);
|
static int FShell (func_info *);
|
||||||
|
static int FShellescape (func_info *);
|
||||||
static int FSlide (func_info *);
|
static int FSlide (func_info *);
|
||||||
static int FSoleq (func_info *);
|
static int FSoleq (func_info *);
|
||||||
static int FStdout (func_info *);
|
static int FStdout (func_info *);
|
||||||
@@ -156,9 +162,9 @@ static int FTrigeventstart (func_info *);
|
|||||||
static int FTrigfrom (func_info *);
|
static int FTrigfrom (func_info *);
|
||||||
static int FTrigger (func_info *);
|
static int FTrigger (func_info *);
|
||||||
static int FTrigpriority (func_info *);
|
static int FTrigpriority (func_info *);
|
||||||
static int FTrigtags (func_info *);
|
|
||||||
static int FTrigrep (func_info *);
|
static int FTrigrep (func_info *);
|
||||||
static int FTrigscanfrom (func_info *);
|
static int FTrigscanfrom (func_info *);
|
||||||
|
static int FTrigtags (func_info *);
|
||||||
static int FTrigtime (func_info *);
|
static int FTrigtime (func_info *);
|
||||||
static int FTrigtimedelta (func_info *);
|
static int FTrigtimedelta (func_info *);
|
||||||
static int FTrigtimerep (func_info *);
|
static int FTrigtimerep (func_info *);
|
||||||
@@ -166,24 +172,18 @@ static int FTriguntil (func_info *);
|
|||||||
static int FTrigvalid (func_info *);
|
static int FTrigvalid (func_info *);
|
||||||
static int FTypeof (func_info *);
|
static int FTypeof (func_info *);
|
||||||
static int FTzconvert (func_info *);
|
static int FTzconvert (func_info *);
|
||||||
static int FUpper (func_info *);
|
|
||||||
static int FUTCToLocal (func_info *);
|
static int FUTCToLocal (func_info *);
|
||||||
|
static int FUpper (func_info *);
|
||||||
static int FValue (func_info *);
|
static int FValue (func_info *);
|
||||||
static int FVersion (func_info *);
|
static int FVersion (func_info *);
|
||||||
static int FWeekno (func_info *);
|
static int FWeekno (func_info *);
|
||||||
static int FWkday (func_info *);
|
static int FWkday (func_info *);
|
||||||
static int FWkdaynum (func_info *);
|
static int FWkdaynum (func_info *);
|
||||||
static int FYear (func_info *);
|
static int FYear (func_info *);
|
||||||
static int FShellescape (func_info *);
|
|
||||||
|
|
||||||
static int CleanUpAfterFunc (func_info *);
|
|
||||||
static int CheckArgs (BuiltinFunc *f, int nargs);
|
|
||||||
static int SunStuff (int rise, double cosz, int dse);
|
static int SunStuff (int rise, double cosz, int dse);
|
||||||
static int tz_set_tz (char const *tz);
|
static int tz_set_tz (char const *tz);
|
||||||
|
|
||||||
/* "Overload" the struct Operator definition */
|
|
||||||
#define NO_MAX 127
|
|
||||||
|
|
||||||
/* Caches for extracting months, days, years from dates - may
|
/* Caches for extracting months, days, years from dates - may
|
||||||
improve performance slightly. */
|
improve performance slightly. */
|
||||||
static int CacheDse = -1;
|
static int CacheDse = -1;
|
||||||
@@ -192,13 +192,9 @@ static int CacheYear, CacheMon, CacheDay;
|
|||||||
static int CacheHebDse = -1;
|
static int CacheHebDse = -1;
|
||||||
static int CacheHebYear, CacheHebMon, CacheHebDay;
|
static int CacheHebYear, CacheHebMon, CacheHebDay;
|
||||||
|
|
||||||
/* We need access to the value stack */
|
|
||||||
extern Value ValStack[];
|
|
||||||
extern int ValStackPtr;
|
|
||||||
|
|
||||||
/* Macro for accessing arguments from the value stack - args are numbered
|
/* Macro for accessing arguments from the value stack - args are numbered
|
||||||
from 0 to (Nargs - 1) */
|
from 0 to (Nargs - 1) */
|
||||||
#define ARG(x) (ValStack[ValStackPtr - Nargs + (x)])
|
#define ARG(x) (info->args[x])
|
||||||
|
|
||||||
#define ARGV(x) ARG(x).v.val
|
#define ARGV(x) ARG(x).v.val
|
||||||
#define ARGSTR(x) ARG(x).v.str
|
#define ARGSTR(x) ARG(x).v.str
|
||||||
@@ -226,214 +222,127 @@ extern int ValStackPtr;
|
|||||||
|
|
||||||
/* The array holding the built-in functions. */
|
/* The array holding the built-in functions. */
|
||||||
BuiltinFunc Func[] = {
|
BuiltinFunc Func[] = {
|
||||||
/* Name minargs maxargs is_constant func */
|
/* Name minargs maxargs is_constant func newfunc*/
|
||||||
|
|
||||||
{ "abs", 1, 1, 1, FAbs },
|
{ "abs", 1, 1, 1, FAbs, NULL },
|
||||||
{ "access", 2, 2, 0, FAccess },
|
{ "access", 2, 2, 0, FAccess, NULL },
|
||||||
{ "adawn", 0, 1, 0, FADawn},
|
{ "adawn", 0, 1, 0, FADawn, NULL},
|
||||||
{ "adusk", 0, 1, 0, FADusk},
|
{ "adusk", 0, 1, 0, FADusk, NULL},
|
||||||
{ "ampm", 1, 3, 1, FAmpm },
|
{ "ampm", 1, 3, 1, FAmpm, NULL },
|
||||||
{ "ansicolor", 1, 5, 1, FAnsicolor },
|
{ "ansicolor", 1, 5, 1, FAnsicolor, NULL },
|
||||||
{ "args", 1, 1, 0, FArgs },
|
{ "args", 1, 1, 0, FArgs, NULL },
|
||||||
{ "asc", 1, 1, 1, FAsc },
|
{ "asc", 1, 1, 1, FAsc, NULL },
|
||||||
{ "baseyr", 0, 0, 1, FBaseyr },
|
{ "baseyr", 0, 0, 1, FBaseyr, NULL },
|
||||||
{ "char", 1, NO_MAX, 1, FChar },
|
{ "char", 1, NO_MAX, 1, FChar, NULL },
|
||||||
{ "choose", 2, NO_MAX, 1, FChoose },
|
{ "choose", 2, NO_MAX, 1, NULL, FChoose }, /*NEW-STYLE*/
|
||||||
{ "coerce", 2, 2, 1, FCoerce },
|
{ "coerce", 2, 2, 1, FCoerce, NULL },
|
||||||
{ "columns", 0, 1, 0, FColumns },
|
{ "columns", 0, 1, 0, FColumns, NULL },
|
||||||
{ "current", 0, 0, 0, FCurrent },
|
{ "current", 0, 0, 0, FCurrent, NULL },
|
||||||
{ "date", 3, 3, 1, FDate },
|
{ "date", 3, 3, 1, FDate, NULL },
|
||||||
{ "datepart", 1, 1, 1, FDatepart },
|
{ "datepart", 1, 1, 1, FDatepart, NULL },
|
||||||
{ "datetime", 2, 5, 1, FDateTime },
|
{ "datetime", 2, 5, 1, FDateTime, NULL },
|
||||||
{ "dawn", 0, 1, 0, FDawn},
|
{ "dawn", 0, 1, 0, FDawn, NULL },
|
||||||
{ "day", 1, 1, 1, FDay },
|
{ "day", 1, 1, 1, FDay, NULL },
|
||||||
{ "daysinmon", 2, 2, 1, FDaysinmon },
|
{ "daysinmon", 2, 2, 1, FDaysinmon, NULL },
|
||||||
{ "defined", 1, 1, 0, FDefined },
|
{ "defined", 1, 1, 0, FDefined, NULL },
|
||||||
{ "dosubst", 1, 3, 0, FDosubst },
|
{ "dosubst", 1, 3, 0, FDosubst, NULL },
|
||||||
{ "dusk", 0, 1, 0, FDusk },
|
{ "dusk", 0, 1, 0, FDusk, NULL },
|
||||||
{ "easterdate", 1, 1, 0, FEasterdate },
|
{ "easterdate", 0, 1, 0, FEasterdate, NULL },
|
||||||
{ "evaltrig", 1, 2, 0, FEvalTrig },
|
{ "evaltrig", 1, 2, 0, FEvalTrig, NULL },
|
||||||
{ "filedate", 1, 1, 0, FFiledate },
|
{ "filedate", 1, 1, 0, FFiledate, NULL },
|
||||||
{ "filedatetime", 1, 1, 0, FFiledatetime },
|
{ "filedatetime", 1, 1, 0, FFiledatetime, NULL },
|
||||||
{ "filedir", 0, 0, 0, FFiledir },
|
{ "filedir", 0, 0, 0, FFiledir, NULL },
|
||||||
{ "filename", 0, 0, 0, FFilename },
|
{ "filename", 0, 0, 0, FFilename, NULL },
|
||||||
{ "getenv", 1, 1, 0, FGetenv },
|
{ "getenv", 1, 1, 0, FGetenv, NULL },
|
||||||
{ "hebdate", 2, 5, 0, FHebdate },
|
{ "hebdate", 2, 5, 0, FHebdate, NULL },
|
||||||
{ "hebday", 1, 1, 0, FHebday },
|
{ "hebday", 1, 1, 0, FHebday, NULL },
|
||||||
{ "hebmon", 1, 1, 0, FHebmon },
|
{ "hebmon", 1, 1, 0, FHebmon, NULL },
|
||||||
{ "hebyear", 1, 1, 0, FHebyear },
|
{ "hebyear", 1, 1, 0, FHebyear, NULL },
|
||||||
{ "hour", 1, 1, 1, FHour },
|
{ "hour", 1, 1, 1, FHour, NULL },
|
||||||
{ "htmlescape", 1, 1, 1, FHtmlEscape },
|
{ "htmlescape", 1, 1, 1, FHtmlEscape, NULL },
|
||||||
{ "htmlstriptags",1, 1, 1, FHtmlStriptags },
|
{ "htmlstriptags",1, 1, 1, FHtmlStriptags, NULL },
|
||||||
{ "iif", 1, NO_MAX, 1, FIif },
|
{ "iif", 1, NO_MAX, 1, NULL, FIif }, /*NEW-STYLE*/
|
||||||
{ "index", 2, 3, 1, FIndex },
|
{ "index", 2, 3, 1, FIndex, NULL },
|
||||||
{ "isany", 1, NO_MAX, 1, FIsAny },
|
{ "isany", 1, NO_MAX, 1, FIsAny, NULL },
|
||||||
{ "isdst", 0, 2, 0, FIsdst },
|
{ "isdst", 0, 2, 0, FIsdst, NULL },
|
||||||
{ "isleap", 1, 1, 1, FIsleap },
|
{ "isleap", 1, 1, 1, FIsleap, NULL },
|
||||||
{ "isomitted", 1, 1, 0, FIsomitted },
|
{ "isomitted", 1, 1, 0, FIsomitted, NULL },
|
||||||
{ "language", 0, 0, 1, FLanguage },
|
{ "language", 0, 0, 1, FLanguage, NULL },
|
||||||
{ "localtoutc", 1, 1, 1, FLocalToUTC },
|
{ "localtoutc", 1, 1, 1, FLocalToUTC, NULL },
|
||||||
{ "lower", 1, 1, 1, FLower },
|
{ "lower", 1, 1, 1, FLower, NULL },
|
||||||
{ "max", 1, NO_MAX, 1, FMax },
|
{ "max", 1, NO_MAX, 1, FMax, NULL },
|
||||||
{ "min", 1, NO_MAX, 1, FMin },
|
{ "min", 1, NO_MAX, 1, FMin, NULL },
|
||||||
{ "minsfromutc", 0, 2, 0, FMinsfromutc },
|
{ "minsfromutc", 0, 2, 0, FMinsfromutc, NULL },
|
||||||
{ "minute", 1, 1, 1, FMinute },
|
{ "minute", 1, 1, 1, FMinute, NULL },
|
||||||
{ "mon", 1, 1, 1, FMon },
|
{ "mon", 1, 1, 1, FMon, NULL },
|
||||||
{ "monnum", 1, 1, 1, FMonnum },
|
{ "monnum", 1, 1, 1, FMonnum, NULL },
|
||||||
{ "moondate", 1, 3, 0, FMoondate },
|
{ "moondate", 1, 3, 0, FMoondate, NULL },
|
||||||
{ "moondatetime", 1, 3, 0, FMoondatetime },
|
{ "moondatetime", 1, 3, 0, FMoondatetime, NULL },
|
||||||
{ "moonphase", 0, 2, 0, FMoonphase },
|
{ "moonphase", 0, 2, 0, FMoonphase, NULL },
|
||||||
{ "moontime", 1, 3, 0, FMoontime },
|
{ "moontime", 1, 3, 0, FMoontime, NULL },
|
||||||
{ "ndawn", 0, 1, 0, FNDawn},
|
{ "multitrig", 1, NO_MAX, 0, FMultiTrig, NULL },
|
||||||
{ "ndusk", 0, 1, 0, FNDusk},
|
{ "ndawn", 0, 1, 0, FNDawn, NULL },
|
||||||
{ "nonomitted", 2, NO_MAX, 0, FNonomitted },
|
{ "ndusk", 0, 1, 0, FNDusk, NULL },
|
||||||
{ "now", 0, 0, 0, FNow },
|
{ "nonomitted", 2, NO_MAX, 0, FNonomitted, NULL },
|
||||||
{ "ord", 1, 1, 1, FOrd },
|
{ "now", 0, 0, 0, FNow, NULL },
|
||||||
{ "orthodoxeaster",1, 1, 0, FOrthodoxeaster },
|
{ "ord", 1, 1, 1, FOrd, NULL },
|
||||||
{ "ostype", 0, 0, 1, FOstype },
|
{ "orthodoxeaster",0, 1, 0, FOrthodoxeaster, NULL },
|
||||||
{ "pad", 3, 4, 1, FPad },
|
{ "ostype", 0, 0, 1, FOstype, NULL },
|
||||||
{ "plural", 1, 3, 1, FPlural },
|
{ "pad", 3, 4, 1, FPad, NULL },
|
||||||
{ "psmoon", 1, 4, 1, FPsmoon},
|
{ "plural", 1, 3, 1, FPlural, NULL },
|
||||||
{ "psshade", 1, 3, 1, FPsshade},
|
{ "psmoon", 1, 4, 1, FPsmoon, NULL },
|
||||||
{ "realcurrent", 0, 0, 0, FRealCurrent},
|
{ "psshade", 1, 3, 1, FPsshade, NULL },
|
||||||
{ "realnow", 0, 0, 0, FRealnow},
|
{ "realcurrent", 0, 0, 0, FRealCurrent, NULL },
|
||||||
{ "realtoday", 0, 0, 0, FRealtoday },
|
{ "realnow", 0, 0, 0, FRealnow, NULL },
|
||||||
{ "rows", 0, 0, 0, FRows },
|
{ "realtoday", 0, 0, 0, FRealtoday, NULL },
|
||||||
{ "sgn", 1, 1, 1, FSgn },
|
{ "rows", 0, 0, 0, FRows, NULL },
|
||||||
{ "shell", 1, 2, 0, FShell },
|
{ "sgn", 1, 1, 1, FSgn, NULL },
|
||||||
{ "shellescape", 1, 1, 1, FShellescape },
|
{ "shell", 1, 2, 0, FShell, NULL },
|
||||||
{ "slide", 2, NO_MAX, 0, FSlide },
|
{ "shellescape", 1, 1, 1, FShellescape, NULL },
|
||||||
{ "soleq", 1, 2, 0, FSoleq },
|
{ "slide", 2, NO_MAX, 0, FSlide, NULL },
|
||||||
{ "stdout", 0, 0, 1, FStdout },
|
{ "soleq", 1, 2, 0, FSoleq, NULL },
|
||||||
{ "strlen", 1, 1, 1, FStrlen },
|
{ "stdout", 0, 0, 1, FStdout, NULL },
|
||||||
{ "substr", 2, 3, 1, FSubstr },
|
{ "strlen", 1, 1, 1, FStrlen, NULL },
|
||||||
{ "sunrise", 0, 1, 0, FSunrise},
|
{ "substr", 2, 3, 1, FSubstr, NULL },
|
||||||
{ "sunset", 0, 1, 0, FSunset },
|
{ "sunrise", 0, 1, 0, FSunrise, NULL },
|
||||||
{ "time", 2, 2, 1, FTime },
|
{ "sunset", 0, 1, 0, FSunset, NULL },
|
||||||
{ "timepart", 1, 1, 1, FTimepart },
|
{ "time", 2, 2, 1, FTime, NULL },
|
||||||
{ "timezone", 0, 1, 1, FTimezone },
|
{ "timepart", 1, 1, 1, FTimepart, NULL },
|
||||||
{ "today", 0, 0, 0, FToday },
|
{ "timezone", 0, 1, 1, FTimezone, NULL },
|
||||||
{ "trig", 0, NO_MAX, 0, FTrig },
|
{ "today", 0, 0, 0, FToday, NULL },
|
||||||
{ "trigback", 0, 0, 0, FTrigback },
|
{ "trig", 0, NO_MAX, 0, FTrig, NULL },
|
||||||
{ "trigdate", 0, 0, 0, FTrigdate },
|
{ "trigback", 0, 0, 0, FTrigback, NULL },
|
||||||
{ "trigdatetime", 0, 0, 0, FTrigdatetime },
|
{ "trigdate", 0, 0, 0, FTrigdate, NULL },
|
||||||
{ "trigdelta", 0, 0, 0, FTrigdelta },
|
{ "trigdatetime", 0, 0, 0, FTrigdatetime, NULL },
|
||||||
{ "trigduration", 0, 0, 0, FTrigduration },
|
{ "trigdelta", 0, 0, 0, FTrigdelta, NULL },
|
||||||
{ "trigeventduration", 0, 0, 0, FTrigeventduration },
|
{ "trigduration", 0, 0, 0, FTrigduration, NULL },
|
||||||
{ "trigeventstart", 0, 0, 0, FTrigeventstart },
|
{ "trigeventduration", 0, 0, 0, FTrigeventduration, NULL },
|
||||||
{ "trigfrom", 0, 0, 0, FTrigfrom },
|
{ "trigeventstart", 0, 0, 0, FTrigeventstart, NULL },
|
||||||
{ "trigger", 1, 3, 0, FTrigger },
|
{ "trigfrom", 0, 0, 0, FTrigfrom, NULL },
|
||||||
{ "trigpriority", 0, 0, 0, FTrigpriority },
|
{ "trigger", 1, 3, 0, FTrigger, NULL },
|
||||||
{ "trigrep", 0, 0, 0, FTrigrep },
|
{ "trigpriority", 0, 0, 0, FTrigpriority, NULL },
|
||||||
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom },
|
{ "trigrep", 0, 0, 0, FTrigrep, NULL },
|
||||||
{ "trigtags", 0, 0, 0, FTrigtags },
|
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom, NULL },
|
||||||
{ "trigtime", 0, 0, 0, FTrigtime },
|
{ "trigtags", 0, 0, 0, FTrigtags, NULL },
|
||||||
{ "trigtimedelta",0, 0, 0, FTrigtimedelta },
|
{ "trigtime", 0, 0, 0, FTrigtime, NULL },
|
||||||
{ "trigtimerep", 0, 0, 0, FTrigtimerep },
|
{ "trigtimedelta",0, 0, 0, FTrigtimedelta, NULL },
|
||||||
{ "triguntil", 0, 0, 0, FTriguntil },
|
{ "trigtimerep", 0, 0, 0, FTrigtimerep, NULL },
|
||||||
{ "trigvalid", 0, 0, 0, FTrigvalid },
|
{ "triguntil", 0, 0, 0, FTriguntil, NULL },
|
||||||
{ "typeof", 1, 1, 1, FTypeof },
|
{ "trigvalid", 0, 0, 0, FTrigvalid, NULL },
|
||||||
{ "tzconvert", 2, 3, 0, FTzconvert },
|
{ "typeof", 1, 1, 1, FTypeof, NULL },
|
||||||
{ "upper", 1, 1, 1, FUpper },
|
{ "tzconvert", 2, 3, 0, FTzconvert, NULL },
|
||||||
{ "utctolocal", 1, 1, 1, FUTCToLocal },
|
{ "upper", 1, 1, 1, FUpper, NULL },
|
||||||
{ "value", 1, 2, 0, FValue },
|
{ "utctolocal", 1, 1, 1, FUTCToLocal, NULL },
|
||||||
{ "version", 0, 0, 1, FVersion },
|
{ "value", 1, 2, 0, FValue, NULL },
|
||||||
{ "weekno", 0, 3, 1, FWeekno },
|
{ "version", 0, 0, 1, FVersion, NULL },
|
||||||
{ "wkday", 1, 1, 1, FWkday },
|
{ "weekno", 0, 3, 1, FWeekno, NULL },
|
||||||
{ "wkdaynum", 1, 1, 1, FWkdaynum },
|
{ "wkday", 1, 1, 1, FWkday, NULL },
|
||||||
{ "year", 1, 1, 1, FYear }
|
{ "wkdaynum", 1, 1, 1, FWkdaynum, NULL },
|
||||||
|
{ "year", 1, 1, 1, FYear, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Need a variable here - Func[] array not really visible to outside. */
|
/* Need a variable here - Func[] array not really visible to outside. */
|
||||||
int NumFuncs = sizeof(Func) / sizeof(Operator) ;
|
int NumFuncs = sizeof(Func) / sizeof(BuiltinFunc) ;
|
||||||
|
|
||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* CallFunc */
|
|
||||||
/* */
|
|
||||||
/* Call a function given a pointer to it, and the number */
|
|
||||||
/* of arguments supplied. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
int CallFunc(BuiltinFunc *f, int nargs)
|
|
||||||
{
|
|
||||||
register int r = CheckArgs(f, nargs);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
func_info info_obj;
|
|
||||||
func_info *info = &info_obj;
|
|
||||||
|
|
||||||
Nargs = nargs;
|
|
||||||
RetVal.type = ERR_TYPE;
|
|
||||||
|
|
||||||
if (DebugFlag & DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s(", f->name);
|
|
||||||
for (i=0; i<nargs; i++) {
|
|
||||||
PrintValue(&ARG(i), ErrFp);
|
|
||||||
if (i<nargs-1) fprintf(ErrFp, ", ");
|
|
||||||
}
|
|
||||||
fprintf(ErrFp, ") => ");
|
|
||||||
if (r) {
|
|
||||||
fprintf(ErrFp, "%s\n", ErrMsg[r]);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (r) {
|
|
||||||
Eprint("%s(): %s", f->name, ErrMsg[r]);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = (*(f->func))(info);
|
|
||||||
if (r) {
|
|
||||||
DestroyValue(RetVal);
|
|
||||||
if (DebugFlag & DB_PRTEXPR)
|
|
||||||
fprintf(ErrFp, "%s\n", ErrMsg[r]);
|
|
||||||
else
|
|
||||||
Eprint("%s(): %s", f->name, ErrMsg[r]);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
if (DebugFlag & DB_PRTEXPR) {
|
|
||||||
PrintValue(&RetVal, ErrFp);
|
|
||||||
fprintf(ErrFp, "\n");
|
|
||||||
}
|
|
||||||
r = CleanUpAfterFunc(info);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* CheckArgs */
|
|
||||||
/* */
|
|
||||||
/* Check that the right number of args have been supplied */
|
|
||||||
/* for a function. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
static int CheckArgs(BuiltinFunc *f, int nargs)
|
|
||||||
{
|
|
||||||
if (nargs < f->minargs) return E_2FEW_ARGS;
|
|
||||||
if (nargs > f->maxargs && f->maxargs != NO_MAX) return E_2MANY_ARGS;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* CleanUpAfterFunc */
|
|
||||||
/* */
|
|
||||||
/* Clean up the stack after a function call - remove */
|
|
||||||
/* args and push the new value. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
static int CleanUpAfterFunc(func_info *info)
|
|
||||||
{
|
|
||||||
Value v;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=0; i<Nargs; i++) {
|
|
||||||
PopValStack(v);
|
|
||||||
DestroyValue(v);
|
|
||||||
}
|
|
||||||
PushValStack(RetVal);
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
@@ -1107,8 +1016,11 @@ static int FOrd(func_info *info)
|
|||||||
ASSERT_TYPE(0, INT_TYPE);
|
ASSERT_TYPE(0, INT_TYPE);
|
||||||
|
|
||||||
v = ARGV(0);
|
v = ARGV(0);
|
||||||
t = v % 100;
|
if (v < 0) {
|
||||||
if (t < 0) t = -t;
|
t = (-v) % 100;
|
||||||
|
} else {
|
||||||
|
t = v % 100;
|
||||||
|
}
|
||||||
u = t % 10;
|
u = t % 10;
|
||||||
s = "th";
|
s = "th";
|
||||||
if (u == 1 && t != 11) s = "st";
|
if (u == 1 && t != 11) s = "st";
|
||||||
@@ -1270,6 +1182,9 @@ static int FIsAny(func_info *info)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Debugging helpers for "choose()" and "iif() */
|
||||||
|
#define PUT(x) DBufPuts(&DebugBuf, x)
|
||||||
|
#define OUT() do { fprintf(ErrFp, "%s\n", DBufValue(&DebugBuf)); DBufFree(&DebugBuf); } while(0)
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* FChoose */
|
/* FChoose */
|
||||||
@@ -1278,15 +1193,63 @@ static int FIsAny(func_info *info)
|
|||||||
/* from 1. */
|
/* from 1. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static int FChoose(func_info *info)
|
static int FChoose(expr_node *node, Value *locals, Value *ans, int *nonconst)
|
||||||
{
|
{
|
||||||
int v;
|
DynamicBuffer DebugBuf;
|
||||||
|
expr_node *cur;
|
||||||
|
int r;
|
||||||
|
int n;
|
||||||
|
int nargs = node->num_kids;
|
||||||
|
Value(v);
|
||||||
|
DBG(DBufInit(&DebugBuf));
|
||||||
|
DBG(PUT("choose("));
|
||||||
|
|
||||||
ASSERT_TYPE(0, INT_TYPE);
|
cur = node->child;
|
||||||
v = ARGV(0);
|
r = evaluate_expr_node(cur, locals, &v, nonconst);
|
||||||
if (v < 1) v = 1;
|
if (r != OK) {
|
||||||
if (v > Nargs-1) v = Nargs-1;
|
DBG(DBufFree(&DebugBuf));
|
||||||
DCOPYVAL(RetVal, ARG(v));
|
return r;
|
||||||
|
}
|
||||||
|
DBG(PUT(PrintValue(&v, NULL)));
|
||||||
|
if (v.type != INT_TYPE) {
|
||||||
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
|
cur = cur->sibling;
|
||||||
|
while(cur) {
|
||||||
|
PUT(", ?");
|
||||||
|
cur = cur->sibling;
|
||||||
|
}
|
||||||
|
PUT(") => ");
|
||||||
|
PUT(ErrMsg[E_BAD_TYPE]);
|
||||||
|
OUT();
|
||||||
|
}
|
||||||
|
return E_BAD_TYPE;
|
||||||
|
}
|
||||||
|
n = v.v.val;
|
||||||
|
if (n < 1) n = 1;
|
||||||
|
if (n > nargs-1) n = nargs-1;
|
||||||
|
|
||||||
|
while(n--) {
|
||||||
|
cur = cur->sibling;
|
||||||
|
DBG(if (n) { PUT(", ?"); });
|
||||||
|
if (!cur) return E_SWERR; /* Should not happen! */
|
||||||
|
}
|
||||||
|
r = evaluate_expr_node(cur, locals, ans, nonconst);
|
||||||
|
if (r != OK) {
|
||||||
|
DBG(DBufFree(&DebugBuf));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
|
PUT(", ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
cur = cur->sibling;
|
||||||
|
while(cur) {
|
||||||
|
PUT(", ?");
|
||||||
|
cur = cur->sibling;
|
||||||
|
}
|
||||||
|
PUT(") => ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
OUT();
|
||||||
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1472,7 +1435,7 @@ static int FValue(func_info *info)
|
|||||||
ASSERT_TYPE(0, STR_TYPE);
|
ASSERT_TYPE(0, STR_TYPE);
|
||||||
switch(Nargs) {
|
switch(Nargs) {
|
||||||
case 1:
|
case 1:
|
||||||
return GetVarValue(ARGSTR(0), &RetVal, NULL, NULL);
|
return GetVarValue(ARGSTR(0), &RetVal);
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
v = FindVar(ARGSTR(0), 0);
|
v = FindVar(ARGSTR(0), 0);
|
||||||
@@ -1944,33 +1907,101 @@ static int FIndex(func_info *info)
|
|||||||
/* */
|
/* */
|
||||||
/* FIif */
|
/* FIif */
|
||||||
/* */
|
/* */
|
||||||
/* The IIF function. */
|
/* The IIF function. Uses new-style evaluation */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static int FIif(func_info *info)
|
static int FIif(expr_node *node, Value *locals, Value *ans, int *nonconst)
|
||||||
{
|
{
|
||||||
int istrue;
|
int istrue;
|
||||||
int arg;
|
int r;
|
||||||
|
int done;
|
||||||
|
Value v;
|
||||||
|
expr_node *cur;
|
||||||
|
DynamicBuffer DebugBuf;
|
||||||
|
|
||||||
if (!(Nargs % 2)) return E_IIF_ODD;
|
DBG(DBufInit(&DebugBuf));
|
||||||
|
DBG(PUT("iif("));
|
||||||
|
cur = node->child;
|
||||||
|
|
||||||
for (arg=0; arg<Nargs-1; arg += 2) {
|
if (!(node->num_kids % 2)) {
|
||||||
if (ARG(arg).type != STR_TYPE && ARG(arg).type != INT_TYPE)
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
return E_BAD_TYPE;
|
r = 0;
|
||||||
|
while(cur) {
|
||||||
if (ARG(arg).type == INT_TYPE)
|
if (r) PUT(", ");
|
||||||
istrue = ARG(arg).v.val;
|
r=1;
|
||||||
else
|
PUT("?");
|
||||||
istrue = *(ARG(arg).v.str);
|
cur = cur->sibling;
|
||||||
|
}
|
||||||
if (istrue) {
|
PUT(") => ");
|
||||||
DCOPYVAL(RetVal, ARG(arg+1));
|
PUT(ErrMsg[E_IIF_ODD]);
|
||||||
return OK;
|
OUT();
|
||||||
}
|
}
|
||||||
|
return E_IIF_ODD;
|
||||||
}
|
}
|
||||||
|
|
||||||
DCOPYVAL(RetVal, ARG(Nargs-1));
|
|
||||||
return OK;
|
done = 0;
|
||||||
|
while(cur->sibling) {
|
||||||
|
r = evaluate_expr_node(cur, locals, &v, nonconst);
|
||||||
|
if (r != OK) {
|
||||||
|
DBG(DBufFree(&DebugBuf));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
|
if (done) PUT(", ");
|
||||||
|
done = 1;
|
||||||
|
PUT(PrintValue(&v, NULL));
|
||||||
|
}
|
||||||
|
if (v.type != STR_TYPE && v.type != INT_TYPE) {
|
||||||
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
|
cur = cur->sibling;
|
||||||
|
while(cur) {
|
||||||
|
PUT(", ?");
|
||||||
|
cur = cur->sibling;
|
||||||
|
}
|
||||||
|
PUT(") => ");
|
||||||
|
PUT(ErrMsg[E_BAD_TYPE]);
|
||||||
|
OUT();
|
||||||
|
}
|
||||||
|
return E_BAD_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v.type == INT_TYPE) {
|
||||||
|
istrue = v.v.val;
|
||||||
|
} else {
|
||||||
|
istrue = *(v.v.str);
|
||||||
|
}
|
||||||
|
if (istrue) {
|
||||||
|
r = evaluate_expr_node(cur->sibling, locals, ans, nonconst);
|
||||||
|
if (r == OK && (DebugFlag & DB_PRTEXPR)) {
|
||||||
|
PUT(", ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
cur = cur->sibling->sibling;
|
||||||
|
while(cur) {
|
||||||
|
PUT(", ?");
|
||||||
|
cur = cur->sibling;
|
||||||
|
}
|
||||||
|
PUT(") => ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
OUT();
|
||||||
|
}
|
||||||
|
DBG(DBufFree(&DebugBuf));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
DBG(PUT(", ?"));
|
||||||
|
cur = cur->sibling->sibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the last arg */
|
||||||
|
r = evaluate_expr_node(cur, locals, ans, nonconst);
|
||||||
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
|
if (done) PUT(", ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
PUT(") => ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
OUT();
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -2092,6 +2123,7 @@ static int FArgs(func_info *info)
|
|||||||
{
|
{
|
||||||
ASSERT_TYPE(0, STR_TYPE);
|
ASSERT_TYPE(0, STR_TYPE);
|
||||||
RetVal.type = INT_TYPE;
|
RetVal.type = INT_TYPE;
|
||||||
|
strtolower(ARGSTR(0));
|
||||||
RETVAL = UserFuncExists(ARGSTR(0));
|
RETVAL = UserFuncExists(ARGSTR(0));
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -2364,13 +2396,21 @@ static int FEasterdate(func_info *info)
|
|||||||
{
|
{
|
||||||
int y, m, d;
|
int y, m, d;
|
||||||
int g, c, x, z, e, n;
|
int g, c, x, z, e, n;
|
||||||
if (ARG(0).type == INT_TYPE) {
|
int base;
|
||||||
y = ARGV(0);
|
if (Nargs == 0) {
|
||||||
if (y < BASE) return E_2LOW;
|
base = DSEToday;
|
||||||
else if (y > BASE+YR_RANGE) return E_2HIGH;
|
FromDSE(DSEToday, &y, &m, &d);
|
||||||
} else if (HASDATE(ARG(0))) {
|
} else {
|
||||||
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
|
if (ARG(0).type == INT_TYPE) {
|
||||||
} else return E_BAD_TYPE;
|
base = -1;
|
||||||
|
y = ARGV(0);
|
||||||
|
if (y < BASE) return E_2LOW;
|
||||||
|
else if (y > BASE+YR_RANGE) return E_2HIGH;
|
||||||
|
} else if (HASDATE(ARG(0))) {
|
||||||
|
base = DATEPART(ARG(0));
|
||||||
|
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
|
||||||
|
} else return E_BAD_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
g = (y % 19) + 1; /* golden number */
|
g = (y % 19) + 1; /* golden number */
|
||||||
@@ -2393,7 +2433,7 @@ static int FEasterdate(func_info *info)
|
|||||||
|
|
||||||
RetVal.type = DATE_TYPE;
|
RetVal.type = DATE_TYPE;
|
||||||
RETVAL = DSE(y, m, d);
|
RETVAL = DSE(y, m, d);
|
||||||
y++; } while (HASDATE(ARG(0)) && RETVAL < DATEPART(ARG(0)));
|
y++; } while (base > -1 && RETVAL < base);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -2409,13 +2449,20 @@ static int FOrthodoxeaster(func_info *info)
|
|||||||
{
|
{
|
||||||
int y, m, d;
|
int y, m, d;
|
||||||
int a, b, c, dd, e, f, dse;
|
int a, b, c, dd, e, f, dse;
|
||||||
if (ARG(0).type == INT_TYPE) {
|
int base = -1;
|
||||||
y = ARGV(0);
|
if (Nargs == 0) {
|
||||||
if (y < BASE) return E_2LOW;
|
base = DSEToday;
|
||||||
else if (y > BASE+YR_RANGE) return E_2HIGH;
|
FromDSE(DSEToday, &y, &m, &d);
|
||||||
} else if (HASDATE(ARG(0))) {
|
} else {
|
||||||
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
|
if (ARG(0).type == INT_TYPE) {
|
||||||
} else return E_BAD_TYPE;
|
y = ARGV(0);
|
||||||
|
if (y < BASE) return E_2LOW;
|
||||||
|
else if (y > BASE+YR_RANGE) return E_2HIGH;
|
||||||
|
} else if (HASDATE(ARG(0))) {
|
||||||
|
base = DATEPART(ARG(0));
|
||||||
|
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
|
||||||
|
} else return E_BAD_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
a = y % 4;
|
a = y % 4;
|
||||||
@@ -2432,7 +2479,7 @@ static int FOrthodoxeaster(func_info *info)
|
|||||||
RetVal.type = DATE_TYPE;
|
RetVal.type = DATE_TYPE;
|
||||||
RETVAL = dse;
|
RETVAL = dse;
|
||||||
y++;
|
y++;
|
||||||
} while (HASDATE(ARG(0)) && RETVAL < DATEPART(ARG(0)));
|
} while (base > -1 && RETVAL < base);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -2566,6 +2613,10 @@ static int UTCToLocalHelper(int datetime, int *ret)
|
|||||||
min = (datetime % MINUTES_PER_DAY) % 60;
|
min = (datetime % MINUTES_PER_DAY) % 60;
|
||||||
|
|
||||||
old_tz = getenv("TZ");
|
old_tz = getenv("TZ");
|
||||||
|
if (old_tz) {
|
||||||
|
old_tz = StrDup(old_tz);
|
||||||
|
if (!old_tz) return E_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
tz_set_tz("UTC");
|
tz_set_tz("UTC");
|
||||||
|
|
||||||
@@ -2579,6 +2630,9 @@ static int UTCToLocalHelper(int datetime, int *ret)
|
|||||||
utc.tm_isdst = 0;
|
utc.tm_isdst = 0;
|
||||||
utc_t = mktime(&utc);
|
utc_t = mktime(&utc);
|
||||||
tz_set_tz(old_tz);
|
tz_set_tz(old_tz);
|
||||||
|
if (old_tz) {
|
||||||
|
free( (void *) old_tz);
|
||||||
|
}
|
||||||
|
|
||||||
if (utc_t == -1) {
|
if (utc_t == -1) {
|
||||||
return E_MKTIME_PROBLEM;
|
return E_MKTIME_PROBLEM;
|
||||||
@@ -3213,6 +3267,10 @@ static int tz_convert(int year, int month, int day,
|
|||||||
|
|
||||||
/* backup old TZ env var */
|
/* backup old TZ env var */
|
||||||
old_tz = getenv("TZ");
|
old_tz = getenv("TZ");
|
||||||
|
if (old_tz) {
|
||||||
|
old_tz = StrDup(old_tz);
|
||||||
|
if (!old_tz) return E_NO_MEM;
|
||||||
|
}
|
||||||
if (tgt_tz == NULL) {
|
if (tgt_tz == NULL) {
|
||||||
tgt_tz = old_tz;
|
tgt_tz = old_tz;
|
||||||
}
|
}
|
||||||
@@ -3220,6 +3278,8 @@ static int tz_convert(int year, int month, int day,
|
|||||||
/* set source TZ */
|
/* set source TZ */
|
||||||
r = tz_set_tz(src_tz);
|
r = tz_set_tz(src_tz);
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
|
tz_set_tz(old_tz);
|
||||||
|
if (old_tz) free((void *) old_tz);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3227,14 +3287,16 @@ static int tz_convert(int year, int month, int day,
|
|||||||
t = mktime(tm);
|
t = mktime(tm);
|
||||||
|
|
||||||
if (t == (time_t) -1) {
|
if (t == (time_t) -1) {
|
||||||
tz_set_tz(old_tz);
|
tz_set_tz(old_tz);
|
||||||
|
if (old_tz) free((void *) old_tz);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set target TZ */
|
/* set target TZ */
|
||||||
r = tz_set_tz(tgt_tz);
|
r = tz_set_tz(tgt_tz);
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
tz_set_tz(old_tz);
|
tz_set_tz(old_tz);
|
||||||
|
if (old_tz) free((void *) old_tz);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3243,6 +3305,7 @@ static int tz_convert(int year, int month, int day,
|
|||||||
|
|
||||||
/* restore old TZ */
|
/* restore old TZ */
|
||||||
tz_set_tz(old_tz);
|
tz_set_tz(old_tz);
|
||||||
|
if (old_tz) free((void *) old_tz);
|
||||||
|
|
||||||
/* return result */
|
/* return result */
|
||||||
if (res == NULL) {
|
if (res == NULL) {
|
||||||
@@ -3473,7 +3536,7 @@ FEvalTrig(func_info *info)
|
|||||||
|
|
||||||
CreateParser(ARGSTR(0), &p);
|
CreateParser(ARGSTR(0), &p);
|
||||||
p.allownested = 0;
|
p.allownested = 0;
|
||||||
r = ParseRem(&p, &trig, &tim, 0);
|
r = ParseRem(&p, &trig, &tim);
|
||||||
if (r) {
|
if (r) {
|
||||||
DestroyParser(&p);
|
DestroyParser(&p);
|
||||||
return r;
|
return r;
|
||||||
@@ -3512,6 +3575,57 @@ FEvalTrig(func_info *info)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
FMultiTrig(func_info *info)
|
||||||
|
{
|
||||||
|
Parser p;
|
||||||
|
Trigger trig;
|
||||||
|
TimeTrig tim;
|
||||||
|
int dse;
|
||||||
|
int r;
|
||||||
|
int i;
|
||||||
|
int earliest = -1;
|
||||||
|
|
||||||
|
RetVal.type = DATE_TYPE;
|
||||||
|
RETVAL = 0;
|
||||||
|
|
||||||
|
for (i=0; i<Nargs; i++) {
|
||||||
|
ASSERT_TYPE(i, STR_TYPE);
|
||||||
|
}
|
||||||
|
for (i=0; i<Nargs; i++) {
|
||||||
|
CreateParser(ARGSTR(i), &p);
|
||||||
|
p.allownested = 0;
|
||||||
|
r = ParseRem(&p, &trig, &tim);
|
||||||
|
if (r) {
|
||||||
|
DestroyParser(&p);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (trig.typ != NO_TYPE) {
|
||||||
|
DestroyParser(&p);
|
||||||
|
FreeTrig(&trig);
|
||||||
|
return E_PARSE_ERR;
|
||||||
|
}
|
||||||
|
if (tim.ttime != NO_TIME) {
|
||||||
|
Eprint("Cannot use AT clause in multitrig() function");
|
||||||
|
return E_PARSE_ERR;
|
||||||
|
}
|
||||||
|
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
|
||||||
|
DestroyParser(&p);
|
||||||
|
|
||||||
|
if (r != E_CANT_TRIG) {
|
||||||
|
if (dse < earliest || earliest < 0) {
|
||||||
|
earliest = dse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FreeTrig(&trig);
|
||||||
|
}
|
||||||
|
if (earliest >= 0) {
|
||||||
|
RETVAL = earliest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int LastTrig = 0;
|
static int LastTrig = 0;
|
||||||
static int
|
static int
|
||||||
FTrig(func_info *info)
|
FTrig(func_info *info)
|
||||||
@@ -3538,7 +3652,7 @@ FTrig(func_info *info)
|
|||||||
for (i=0; i<Nargs; i++) {
|
for (i=0; i<Nargs; i++) {
|
||||||
CreateParser(ARGSTR(i), &p);
|
CreateParser(ARGSTR(i), &p);
|
||||||
p.allownested = 0;
|
p.allownested = 0;
|
||||||
r = ParseRem(&p, &trig, &tim, 0);
|
r = ParseRem(&p, &trig, &tim);
|
||||||
if (r) {
|
if (r) {
|
||||||
DestroyParser(&p);
|
DestroyParser(&p);
|
||||||
return r;
|
return r;
|
||||||
@@ -3549,20 +3663,18 @@ FTrig(func_info *info)
|
|||||||
return E_PARSE_ERR;
|
return E_PARSE_ERR;
|
||||||
}
|
}
|
||||||
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
|
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
|
||||||
|
DestroyParser(&p);
|
||||||
|
|
||||||
if (r == E_CANT_TRIG) {
|
if (r == E_CANT_TRIG) {
|
||||||
DestroyParser(&p);
|
|
||||||
FreeTrig(&trig);
|
FreeTrig(&trig);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ShouldTriggerReminder(&trig, &tim, dse, &r)) {
|
if (ShouldTriggerReminder(&trig, &tim, dse, &r)) {
|
||||||
LastTrig = dse;
|
LastTrig = dse;
|
||||||
RETVAL = dse;
|
RETVAL = dse;
|
||||||
DestroyParser(&p);
|
|
||||||
FreeTrig(&trig);
|
FreeTrig(&trig);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
DestroyParser(&p);
|
|
||||||
FreeTrig(&trig);
|
FreeTrig(&trig);
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
@@ -3675,11 +3787,8 @@ mean_december_solstice(double y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Cosine of an angle specified in degrees */
|
/* Cosine of an angle specified in degrees */
|
||||||
static double
|
#define PI_BY_180 0.01745329251994329576923690768
|
||||||
cosd(double degrees)
|
#define cosd(theta) cos( (theta) * PI_BY_180)
|
||||||
{
|
|
||||||
return cos((degrees / 180.0) * 3.14159265358979);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Astronomical Algorithms by Meeus, p. 179
|
/* Astronomical Algorithms by Meeus, p. 179
|
||||||
These weird periodic components refine the mean solstice/equinox dates
|
These weird periodic components refine the mean solstice/equinox dates
|
||||||
@@ -3817,3 +3926,38 @@ FSoleq(func_info *info)
|
|||||||
RETVAL = ret;
|
RETVAL = ret;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compare two strings case-insensitively, where we KNOW
|
||||||
|
that the second string is definitely lower-case */
|
||||||
|
static int strcmp_lcfirst(char const *s1, char const *s2)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
while (*s1 && *s2) {
|
||||||
|
r = tolower(*s1) - *s2;
|
||||||
|
if (r) return r;
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
return tolower(*s1) - *s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FindBuiltinFunc */
|
||||||
|
/* */
|
||||||
|
/* Find a built-in function. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
BuiltinFunc *FindBuiltinFunc(char const *name)
|
||||||
|
{
|
||||||
|
int top=NumFuncs-1, bot=0;
|
||||||
|
int mid, r;
|
||||||
|
while (top >= bot) {
|
||||||
|
mid = (top + bot) / 2;
|
||||||
|
r = strcmp_lcfirst(name, Func[mid].name);
|
||||||
|
if (!r) return &Func[mid];
|
||||||
|
else if (r > 0) bot = mid+1;
|
||||||
|
else top = mid-1;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#define INIT(var, val) var
|
#define INIT(var, val) var
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
#ifdef HAVE_SYS_TYPES_H
|
#ifdef HAVE_SYS_TYPES_H
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -39,7 +40,7 @@ EXTERN FILE *ErrFp;
|
|||||||
#define IsLeapYear(y) (((y) % 4) ? 0 : ((!((y) % 100) && ((y) % 400)) ? 0 : 1 ))
|
#define IsLeapYear(y) (((y) % 4) ? 0 : ((!((y) % 100) && ((y) % 400)) ? 0 : 1 ))
|
||||||
#define DaysInMonth(m, y) ((m) != 1 ? MonthDays[m] : 28 + IsLeapYear(y))
|
#define DaysInMonth(m, y) ((m) != 1 ? MonthDays[m] : 28 + IsLeapYear(y))
|
||||||
|
|
||||||
#define DestroyValue(x) (void) (((x).type == STR_TYPE && (x).v.str) ? (free((x).v.str),(x).v.str = NULL,(x).type = ERR_TYPE) : 0)
|
#define DestroyValue(x) do { if ((x).type == STR_TYPE && (x).v.str) { free((x).v.str); (x).v.str = NULL; } (x).type = ERR_TYPE; } while (0)
|
||||||
|
|
||||||
EXTERN int DSEToday;
|
EXTERN int DSEToday;
|
||||||
EXTERN int RealToday;
|
EXTERN int RealToday;
|
||||||
@@ -73,13 +74,16 @@ EXTERN INIT( int InfiniteDelta, 0);
|
|||||||
EXTERN INIT( int DefaultTDelta, 0);
|
EXTERN INIT( int DefaultTDelta, 0);
|
||||||
EXTERN INIT( int DeltaOverride, 0);
|
EXTERN INIT( int DeltaOverride, 0);
|
||||||
EXTERN INIT( int RunDisabled, 0);
|
EXTERN INIT( int RunDisabled, 0);
|
||||||
|
EXTERN INIT( int ExpressionEvaluationDisabled, 0);
|
||||||
|
EXTERN INIT( int ExpressionEvaluationTimeLimit, 0);
|
||||||
|
EXTERN INIT( volatile sig_atomic_t ExpressionTimeLimitExceeded, 0);
|
||||||
EXTERN INIT( int IgnoreOnce, 0);
|
EXTERN INIT( int IgnoreOnce, 0);
|
||||||
EXTERN INIT( int SortByTime, 0);
|
EXTERN INIT( int SortByTime, 0);
|
||||||
EXTERN INIT( int SortByDate, 0);
|
EXTERN INIT( int SortByDate, 0);
|
||||||
EXTERN INIT( int SortByPrio, 0);
|
EXTERN INIT( int SortByPrio, 0);
|
||||||
EXTERN INIT( int UntimedBeforeTimed, 0);
|
EXTERN INIT( int UntimedBeforeTimed, 0);
|
||||||
EXTERN INIT( int DefaultPrio, NO_PRIORITY);
|
EXTERN INIT( int DefaultPrio, NO_PRIORITY);
|
||||||
EXTERN INIT( long SysTime, -1L);
|
EXTERN INIT( int SysTime, -1);
|
||||||
EXTERN INIT( int ParseUntriggered, 1);
|
EXTERN INIT( int ParseUntriggered, 1);
|
||||||
|
|
||||||
EXTERN char const *InitialFile;
|
EXTERN char const *InitialFile;
|
||||||
@@ -92,6 +96,7 @@ EXTERN INIT( int DontQueue, 0);
|
|||||||
EXTERN INIT( int NumQueued, 0);
|
EXTERN INIT( int NumQueued, 0);
|
||||||
EXTERN INIT( int DontIssueAts, 0);
|
EXTERN INIT( int DontIssueAts, 0);
|
||||||
EXTERN INIT( int Daemon, 0);
|
EXTERN INIT( int Daemon, 0);
|
||||||
|
EXTERN INIT( int DaemonJSON, 0);
|
||||||
EXTERN INIT( char DateSep, DATESEP);
|
EXTERN INIT( char DateSep, DATESEP);
|
||||||
EXTERN INIT( char TimeSep, TIMESEP);
|
EXTERN INIT( char TimeSep, TIMESEP);
|
||||||
EXTERN INIT( char DateTimeSep, DATETIMESEP);
|
EXTERN INIT( char DateTimeSep, DATETIMESEP);
|
||||||
@@ -102,18 +107,19 @@ EXTERN INIT( int SynthesizeTags, 0);
|
|||||||
EXTERN INIT( int ScFormat, SC_AMPM);
|
EXTERN INIT( int ScFormat, SC_AMPM);
|
||||||
EXTERN INIT( int MaxSatIter, 1000);
|
EXTERN INIT( int MaxSatIter, 1000);
|
||||||
EXTERN INIT( int MaxStringLen, MAX_STR_LEN);
|
EXTERN INIT( int MaxStringLen, MAX_STR_LEN);
|
||||||
EXTERN INIT( char *FileName, NULL);
|
EXTERN INIT( char *FileName, NULL);
|
||||||
EXTERN INIT( int UseStdin, 0);
|
EXTERN INIT( int UseStdin, 0);
|
||||||
EXTERN INIT( int PurgeMode, 0);
|
EXTERN INIT( int PurgeMode, 0);
|
||||||
EXTERN INIT( int PurgeIncludeDepth, 0);
|
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 LastTrigValid, 0);
|
EXTERN INIT( int LastTrigValid, 0);
|
||||||
EXTERN Trigger LastTrigger;
|
EXTERN Trigger LastTrigger;
|
||||||
EXTERN TimeTrig LastTimeTrig;
|
EXTERN TimeTrig LastTimeTrig;
|
||||||
EXTERN INIT( int LastTriggerDate, 0);
|
EXTERN INIT( int LastTriggerDate, 0);
|
||||||
EXTERN INIT( int LastTriggerTime, 0);
|
EXTERN INIT( int LastTriggerTime, NO_TIME);
|
||||||
EXTERN INIT( int ShouldCache, 0);
|
EXTERN INIT( int ShouldCache, 0);
|
||||||
EXTERN char const *CurLine;
|
EXTERN char const *CurLine;
|
||||||
EXTERN INIT( int NumTriggered, 0);
|
EXTERN INIT( int NumTriggered, 0);
|
||||||
@@ -157,6 +163,12 @@ EXTERN INIT( char *EndSentIg, "\"')]}>");
|
|||||||
EXTERN DynamicBuffer Banner;
|
EXTERN DynamicBuffer Banner;
|
||||||
EXTERN DynamicBuffer LineBuffer;
|
EXTERN DynamicBuffer LineBuffer;
|
||||||
EXTERN DynamicBuffer ExprBuf;
|
EXTERN DynamicBuffer ExprBuf;
|
||||||
|
|
||||||
|
/* User-func recursion level */
|
||||||
|
EXTERN INIT( unsigned int FuncRecursionLevel, 0);
|
||||||
|
|
||||||
|
extern int NumFullOmits, NumPartialOmits;
|
||||||
|
|
||||||
/* List of months */
|
/* List of months */
|
||||||
EXTERN char *EnglishMonthName[]
|
EXTERN char *EnglishMonthName[]
|
||||||
#ifdef MK_GLOBALS
|
#ifdef MK_GLOBALS
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 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 */
|
||||||
@@ -20,6 +20,12 @@
|
|||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_STRINGS_H
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define HOUR 1080L
|
#define HOUR 1080L
|
||||||
#define DAY (24L*HOUR)
|
#define DAY (24L*HOUR)
|
||||||
#define WEEK (7L*DAY)
|
#define WEEK (7L*DAY)
|
||||||
|
|||||||
142
src/init.c
142
src/init.c
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <time.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -38,7 +38,6 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "expr.h"
|
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
|
|
||||||
static int should_guess_terminal_background = 1;
|
static int should_guess_terminal_background = 1;
|
||||||
@@ -78,6 +77,7 @@ static void ProcessLongOption(char const *arg);
|
|||||||
* t = Display trigger dates
|
* t = Display trigger dates
|
||||||
* v = Dump variables at end
|
* v = Dump variables at end
|
||||||
* l = Display entire line in error messages
|
* l = Display entire line in error messages
|
||||||
|
* s = Display expression-parsing stack usage before exit
|
||||||
* -e = Send messages normally sent to stderr to stdout instead
|
* -e = Send messages normally sent to stderr to stdout instead
|
||||||
* -z[n] = Daemon mode waking up every n (def 1) minutes.
|
* -z[n] = Daemon mode waking up every n (def 1) minutes.
|
||||||
* -bn = Time format for cal (0, 1, or 2)
|
* -bn = Time format for cal (0, 1, or 2)
|
||||||
@@ -176,7 +176,6 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
int x;
|
int x;
|
||||||
int dse;
|
int dse;
|
||||||
int ttyfd;
|
int ttyfd;
|
||||||
int r, g, b;
|
|
||||||
|
|
||||||
dse = NO_DATE;
|
dse = NO_DATE;
|
||||||
|
|
||||||
@@ -426,7 +425,11 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
case 'z':
|
case 'z':
|
||||||
case 'Z':
|
case 'Z':
|
||||||
DontFork = 1;
|
DontFork = 1;
|
||||||
if (*arg == '0') {
|
if (*arg == 'j' || *arg == 'J') {
|
||||||
|
while (*arg) arg++;
|
||||||
|
Daemon = -1;
|
||||||
|
DaemonJSON = 1;
|
||||||
|
} else if (*arg == '0') {
|
||||||
PARSENUM(Daemon, arg);
|
PARSENUM(Daemon, arg);
|
||||||
if (Daemon == 0) Daemon = -1;
|
if (Daemon == 0) Daemon = -1;
|
||||||
else if (Daemon < 1) Daemon = 1;
|
else if (Daemon < 1) Daemon = 1;
|
||||||
@@ -601,6 +604,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
case 'D':
|
case 'D':
|
||||||
while (*arg) {
|
while (*arg) {
|
||||||
switch(*arg++) {
|
switch(*arg++) {
|
||||||
|
case 's': case 'S': DebugFlag |= DB_PARSE_EXPR; 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;
|
||||||
@@ -649,17 +653,6 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (should_guess_terminal_background) {
|
|
||||||
guess_terminal_background(&r, &g, &b);
|
|
||||||
if (r >= 0 && g >= 0 && b >= 0) {
|
|
||||||
if (r+g+b <= 85*3 && r <= 128 && g <= 128 && b <= 128) {
|
|
||||||
TerminalBackground = TERMINAL_BACKGROUND_DARK;
|
|
||||||
} else {
|
|
||||||
TerminalBackground = TERMINAL_BACKGROUND_LIGHT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the filename. */
|
/* Get the filename. */
|
||||||
if (!InvokedAsRem) {
|
if (!InvokedAsRem) {
|
||||||
if (i >= argc) {
|
if (i >= argc) {
|
||||||
@@ -779,7 +772,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 (%s version) Copyright 1992-2023 Dianne Skoll\n", VERSION, L_LANGNAME);
|
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||||
#ifdef BETA
|
#ifdef BETA
|
||||||
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
|
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -812,6 +805,7 @@ void Usage(void)
|
|||||||
fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n");
|
fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n");
|
||||||
fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n");
|
fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n");
|
||||||
fprintf(ErrFp, " -j[n] Run in 'purge' mode. [n = INCLUDE depth]\n");
|
fprintf(ErrFp, " -j[n] Run in 'purge' mode. [n = INCLUDE depth]\n");
|
||||||
|
fprintf(ErrFp, "\nRemind home page: %s\n", PACKAGE_URL);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
#endif /* L_USAGE_OVERRIDE */
|
#endif /* L_USAGE_OVERRIDE */
|
||||||
@@ -931,7 +925,12 @@ static void InitializeVar(char const *str)
|
|||||||
r = 0;
|
r = 0;
|
||||||
while (*str && *str != '=') {
|
while (*str && *str != '=') {
|
||||||
if (r < VAR_NAME_LEN) {
|
if (r < VAR_NAME_LEN) {
|
||||||
varname[r++] = *str;
|
if (isalpha(*str) || *str == '_' || (r > 0 && *str == '(') || (r == 0 && *str == '$') || (r > 0 && isdigit(*str))) {
|
||||||
|
varname[r++] = *str;
|
||||||
|
} else {
|
||||||
|
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_ILLEGAL_CHAR]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (*str == '(') {
|
if (*str == '(') {
|
||||||
/* Do a function definition if we see a paren */
|
/* Do a function definition if we see a paren */
|
||||||
@@ -941,10 +940,28 @@ static void InitializeVar(char const *str)
|
|||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
varname[r] = 0;
|
varname[r] = 0;
|
||||||
if (!*str) {
|
if (!*varname) {
|
||||||
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_EQ]);
|
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_VAR]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!*str) {
|
||||||
|
/* Setting a system var does require =expr on the commandline */
|
||||||
|
if (*varname == '$') {
|
||||||
|
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_EQ]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val.type = INT_TYPE;
|
||||||
|
val.v.val = 0;
|
||||||
|
r = SetVar(varname, &val);
|
||||||
|
if (!r) {
|
||||||
|
r = PreserveVar(varname);
|
||||||
|
}
|
||||||
|
if (r) {
|
||||||
|
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!*varname) {
|
if (!*varname) {
|
||||||
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_VAR]);
|
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_VAR]);
|
||||||
return;
|
return;
|
||||||
@@ -997,13 +1014,65 @@ AddTrustedUser(char const *username)
|
|||||||
NumTrustedUsers++;
|
NumTrustedUsers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static pid_t LimiterPid = (pid_t) -1;
|
||||||
|
|
||||||
|
void unlimit_execution_time(void)
|
||||||
|
{
|
||||||
|
if (LimiterPid != (pid_t) -1) {
|
||||||
|
kill(LimiterPid, SIGTERM);
|
||||||
|
LimiterPid = (pid_t) -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void limit_execution_time(int t)
|
||||||
|
{
|
||||||
|
pid_t parent = getpid();
|
||||||
|
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
perror("fork");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid > 0) {
|
||||||
|
LimiterPid = pid;
|
||||||
|
/* In the parent */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In the child */
|
||||||
|
time_t start = time(NULL);
|
||||||
|
while(1) {
|
||||||
|
sleep(1);
|
||||||
|
if (kill(parent, 0) < 0) {
|
||||||
|
/* Parent has probably exited */
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (time(NULL) - start > t) {
|
||||||
|
kill(parent, SIGXCPU);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ProcessLongOption(char const *arg)
|
ProcessLongOption(char const *arg)
|
||||||
{
|
{
|
||||||
|
int t;
|
||||||
if (!strcmp(arg, "version")) {
|
if (!strcmp(arg, "version")) {
|
||||||
printf("%s\n", VERSION);
|
printf("%s\n", VERSION);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
if (sscanf(arg, "max-execution-time=%d", &t) == 1) {
|
||||||
|
if (t < 0) {
|
||||||
|
fprintf(ErrFp, "%s: --max-execution-time must be non-negative\n", ArgV[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (t > 0) {
|
||||||
|
limit_execution_time(t);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
fprintf(ErrFp, "%s: Unknown long option --%s\n", ArgV[0], arg);
|
fprintf(ErrFp, "%s: Unknown long option --%s\n", ArgV[0], arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1012,7 +1081,7 @@ guess_terminal_background(int *r, int *g, int *b)
|
|||||||
{
|
{
|
||||||
int ttyfd;
|
int ttyfd;
|
||||||
struct pollfd p;
|
struct pollfd p;
|
||||||
int rr, gg, bb;
|
unsigned int rr, gg, bb;
|
||||||
char buf[128];
|
char buf[128];
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
@@ -1042,7 +1111,12 @@ guess_terminal_background(int *r, int *g, int *b)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tty_raw(ttyfd);
|
tty_raw(ttyfd);
|
||||||
write(ttyfd, "\033]11;?\033\\", 8);
|
n = write(ttyfd, "\033]11;?\033\\", 8);
|
||||||
|
|
||||||
|
if (n != 8) {
|
||||||
|
/* write failed... WTF? Not much we can do */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Wait up to 0.1s for terminal to respond */
|
/* Wait up to 0.1s for terminal to respond */
|
||||||
p.fd = ttyfd;
|
p.fd = ttyfd;
|
||||||
@@ -1073,9 +1147,9 @@ guess_terminal_background(int *r, int *g, int *b)
|
|||||||
/* Couldn't scan color codes */
|
/* Couldn't scan color codes */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*r = (rr >> 8) & 255;
|
*r = (int) ((rr >> 8) & 255);
|
||||||
*g = (gg >> 8) & 255;
|
*g = (int) ((gg >> 8) & 255);
|
||||||
*b = (bb >> 8) & 255;
|
*b = (int) ((bb >> 8) & 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct termios orig_termios;
|
static struct termios orig_termios;
|
||||||
@@ -1110,3 +1184,21 @@ tty_reset(int fd)
|
|||||||
{
|
{
|
||||||
tcsetattr(fd, TCSAFLUSH, &orig_termios);
|
tcsetattr(fd, TCSAFLUSH, &orig_termios);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
GetTerminalBackground(void)
|
||||||
|
{
|
||||||
|
int r, g, b;
|
||||||
|
if (should_guess_terminal_background) {
|
||||||
|
guess_terminal_background(&r, &g, &b);
|
||||||
|
if (r >= 0 && g >= 0 && b >= 0) {
|
||||||
|
if (r+g+b <= 85*3 && r <= 128 && g <= 128 && b <= 128) {
|
||||||
|
TerminalBackground = TERMINAL_BACKGROUND_DARK;
|
||||||
|
} else {
|
||||||
|
TerminalBackground = TERMINAL_BACKGROUND_LIGHT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
should_guess_terminal_background = 0;
|
||||||
|
}
|
||||||
|
return TerminalBackground;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
/* Header file for language support for various languages. */
|
/* Header file for language support for various languages. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* */
|
/* */
|
||||||
/* REMIND is Copyright (C) 1992-2023 by Dianne Skoll */
|
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* This file is Copyright (C) 1993 by Mogens Lynnerup. */
|
/* This file is Copyright (C) 1993 by Mogens Lynnerup. */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
/* Further corrections by Erik-Jan Vens */
|
/* Further corrections by Erik-Jan Vens */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
/* Support for the English language. */
|
/* Support for the English language. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* This file is Copyright (C) 1993-1998 by Mikko Silvonen. */
|
/* This file is Copyright (C) 1993-1998 by Mikko Silvonen. */
|
||||||
/* REMIND is Copyright (C) 1992-2023 by Dianne Skoll */
|
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -145,7 +145,7 @@ EXTERN char *ErrMsg[] =
|
|||||||
"Ok",
|
"Ok",
|
||||||
"Puuttuva ']'",
|
"Puuttuva ']'",
|
||||||
"Puuttuva lainausmerkki",
|
"Puuttuva lainausmerkki",
|
||||||
"Liian monimutkainen lauseke - liikaa operaattoreita",
|
"Liian monimutkainen lauseke",
|
||||||
"Liian monimutkainen lauseke - liikaa operandeja",
|
"Liian monimutkainen lauseke - liikaa operandeja",
|
||||||
"Puuttuva ')'",
|
"Puuttuva ')'",
|
||||||
"Määrittelemätön funktio",
|
"Määrittelemätön funktio",
|
||||||
@@ -245,7 +245,11 @@ EXTERN char *ErrMsg[] =
|
|||||||
"No files matching *.rem",
|
"No files matching *.rem",
|
||||||
"String too long",
|
"String too long",
|
||||||
"Time specified twice",
|
"Time specified twice",
|
||||||
"Cannot specify DURATION without specifying AT"
|
"Cannot specify DURATION without specifying AT",
|
||||||
|
"Odotettu viikonpäivän nimi",
|
||||||
|
"Päällekkäinen argumentin nimi",
|
||||||
|
"Lausekkeiden arviointi on poistettu käytöstä",
|
||||||
|
|
||||||
};
|
};
|
||||||
#endif /* MK_GLOBALS */
|
#endif /* MK_GLOBALS */
|
||||||
|
|
||||||
@@ -254,7 +258,7 @@ EXTERN char *ErrMsg[] =
|
|||||||
#define L_USAGE_OVERRIDE 1
|
#define L_USAGE_OVERRIDE 1
|
||||||
void Usage(void)
|
void Usage(void)
|
||||||
{
|
{
|
||||||
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2023 Dianne Skoll\n", VERSION, L_LANGNAME);
|
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||||
#ifdef BETA
|
#ifdef BETA
|
||||||
fprintf(ErrFp, ">>>> BETAVERSIO <<<<\n");
|
fprintf(ErrFp, ">>>> BETAVERSIO <<<<\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -271,12 +275,10 @@ void Usage(void)
|
|||||||
fprintf(ErrFp, " -o Älä noudata ONCE-lauseita\n");
|
fprintf(ErrFp, " -o Älä noudata ONCE-lauseita\n");
|
||||||
fprintf(ErrFp, " -t Laukaise kaikki viestit deltan arvosta välittämättä\n");
|
fprintf(ErrFp, " -t Laukaise kaikki viestit deltan arvosta välittämättä\n");
|
||||||
fprintf(ErrFp, " -h Suppeat tulostukset\n");
|
fprintf(ErrFp, " -h Suppeat tulostukset\n");
|
||||||
#ifdef HAVE_QUEUED
|
|
||||||
fprintf(ErrFp, " -a Älä laukaise viestejä heti - lisää ne jonoon\n");
|
fprintf(ErrFp, " -a Älä laukaise viestejä heti - lisää ne jonoon\n");
|
||||||
fprintf(ErrFp, " -q Älä lisää viestejä jonoon\n");
|
fprintf(ErrFp, " -q Älä lisää viestejä jonoon\n");
|
||||||
fprintf(ErrFp, " -f Laukaise viestit, pysy etualalla\n");
|
fprintf(ErrFp, " -f Laukaise viestit, pysy etualalla\n");
|
||||||
fprintf(ErrFp, " -z[n] Käynnisty demonina, herätys n:n (5:n) minuutin välein\n");
|
fprintf(ErrFp, " -z[n] Käynnisty demonina, herätys n:n (5:n) minuutin välein\n");
|
||||||
#endif
|
|
||||||
fprintf(ErrFp, " -d... Virheenetsintä: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
|
fprintf(ErrFp, " -d... Virheenetsintä: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
|
||||||
fprintf(ErrFp, " -e Ohjaa virhetulostus stdout-vuohon\n");
|
fprintf(ErrFp, " -e Ohjaa virhetulostus stdout-vuohon\n");
|
||||||
fprintf(ErrFp, " -b[n] Ajan ilmaisu: 0=ap/ip, 1=24 tuntia, 2=ei aikoja\n");
|
fprintf(ErrFp, " -b[n] Ajan ilmaisu: 0=ap/ip, 1=24 tuntia, 2=ei aikoja\n");
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* */
|
/* */
|
||||||
/* REMIND is Copyright (C) 1992-2023 by Dianne Skoll */
|
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* This file is Copyright (C) 1993 by Laurent Duperval and */
|
/* This file is Copyright (C) 1993 by Laurent Duperval and */
|
||||||
/* Dianne Skoll. */
|
/* Dianne Skoll. */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
@@ -119,7 +119,7 @@ EXTERN char *ErrMsg[] =
|
|||||||
"Ok",
|
"Ok",
|
||||||
"']' manquant",
|
"']' manquant",
|
||||||
"Apostrophe manquant",
|
"Apostrophe manquant",
|
||||||
"Expression trop complexe - trop d'opérateurs",
|
"Expression trop complexe",
|
||||||
"Expression trop complexe - trop d'opérandes",
|
"Expression trop complexe - trop d'opérandes",
|
||||||
"')' manquante",
|
"')' manquante",
|
||||||
"Fonction non-définie",
|
"Fonction non-définie",
|
||||||
@@ -219,7 +219,11 @@ EXTERN char *ErrMsg[] =
|
|||||||
"No files matching *.rem",
|
"No files matching *.rem",
|
||||||
"String too long",
|
"String too long",
|
||||||
"Time specified twice",
|
"Time specified twice",
|
||||||
"Cannot specify DURATION without specifying AT"
|
"Cannot specify DURATION without specifying AT",
|
||||||
|
"Nom du jour de la semaine attendu",
|
||||||
|
"Nom de l'argument en double",
|
||||||
|
"L'évaluation de l'expression est désactivée",
|
||||||
|
|
||||||
};
|
};
|
||||||
#endif /* MK_GLOBALS */
|
#endif /* MK_GLOBALS */
|
||||||
|
|
||||||
@@ -228,7 +232,7 @@ EXTERN char *ErrMsg[] =
|
|||||||
#define L_USAGE_OVERRIDE 1
|
#define L_USAGE_OVERRIDE 1
|
||||||
void Usage(void)
|
void Usage(void)
|
||||||
{
|
{
|
||||||
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2023 Dianne Skoll\n", VERSION, L_LANGNAME);
|
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||||
#ifdef BETA
|
#ifdef BETA
|
||||||
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
|
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -245,12 +249,10 @@ void Usage(void)
|
|||||||
fprintf(ErrFp, " -o Ignorer instructions ONCE\n");
|
fprintf(ErrFp, " -o Ignorer instructions ONCE\n");
|
||||||
fprintf(ErrFp, " -t Déclencher tous les rappels peu importe le delta\n");
|
fprintf(ErrFp, " -t Déclencher tous les rappels peu importe le delta\n");
|
||||||
fprintf(ErrFp, " -h Mode silencieux\n");
|
fprintf(ErrFp, " -h Mode silencieux\n");
|
||||||
#ifdef HAVE_QUEUED
|
|
||||||
fprintf(ErrFp, " -a Ne pas déclencher les rappels minutés immédiatement - les mettre en file\n");
|
fprintf(ErrFp, " -a Ne pas déclencher les rappels minutés immédiatement - les mettre en file\n");
|
||||||
fprintf(ErrFp, " -q Ne pas mettre les rappels minutés en file\n");
|
fprintf(ErrFp, " -q Ne pas mettre les rappels minutés en file\n");
|
||||||
fprintf(ErrFp, " -f Déclencher les rappels minutés immédiatement en restant en avant-plan\n");
|
fprintf(ErrFp, " -f Déclencher les rappels minutés immédiatement en restant en avant-plan\n");
|
||||||
fprintf(ErrFp, " -z[n] Entrer en mode 'daemon', réveil chaque n (5) minutes\n");
|
fprintf(ErrFp, " -z[n] Entrer en mode 'daemon', réveil chaque n (5) minutes\n");
|
||||||
#endif
|
|
||||||
fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
|
fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
|
||||||
fprintf(ErrFp, " -e Envoyer les messages de stderr à stdout\n");
|
fprintf(ErrFp, " -e Envoyer les messages de stderr à stdout\n");
|
||||||
fprintf(ErrFp, " -b[n] Formats de l'heure pour le calendrier: 0=am/pm, 1=24hr, 2=aucun\n");
|
fprintf(ErrFp, " -b[n] Formats de l'heure pour le calendrier: 0=am/pm, 1=24hr, 2=aucun\n");
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
/* I don't speak German. */
|
/* I don't speak German. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
/* Support for the Icelandic language. */
|
/* Support for the Icelandic language. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* Translated by Björn Davíðsson (bjossi@snerpa.is) */
|
/* Translated by Björn Davíðsson (bjossi@snerpa.is) */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* It is Copyright (C) 1996 by Valerio Aimale */
|
/* It is Copyright (C) 1996 by Valerio Aimale */
|
||||||
/* */
|
/* */
|
||||||
/* Remind is copyright (C) 1992-2023 by Dianne Skoll */
|
/* Remind is copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* This file is Copyright (C) 1993 by Trygve Randen. */
|
/* This file is Copyright (C) 1993 by Trygve Randen. */
|
||||||
/* Remind is Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Remind is Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
/* Polish. */
|
/* Polish. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -135,7 +135,7 @@ EXTERN char *ErrMsg[] =
|
|||||||
"OK",
|
"OK",
|
||||||
"Brakujący ']'",
|
"Brakujący ']'",
|
||||||
"Brakujący nawias",
|
"Brakujący nawias",
|
||||||
"Zbyt skomplikowane wyrażenie - za dużo operatorów",
|
"Zbyt skomplikowane wyrażenie",
|
||||||
"Zbyt skomplikowane wyrażenie - za dużo argumentów",
|
"Zbyt skomplikowane wyrażenie - za dużo argumentów",
|
||||||
"Brakujący ')'",
|
"Brakujący ')'",
|
||||||
"Nie zdefiniowana funkcja",
|
"Nie zdefiniowana funkcja",
|
||||||
@@ -235,7 +235,10 @@ EXTERN char *ErrMsg[] =
|
|||||||
"No files matching *.rem",
|
"No files matching *.rem",
|
||||||
"String too long",
|
"String too long",
|
||||||
"Time specified twice",
|
"Time specified twice",
|
||||||
"Cannot specify DURATION without specifying AT"
|
"Cannot specify DURATION without specifying AT",
|
||||||
|
"Oczekiwana nazwa dnia tygodnia",
|
||||||
|
"Zduplikowana nazwa argumentu",
|
||||||
|
"Ocena wyrażeń jest wyłączona",
|
||||||
};
|
};
|
||||||
#endif /* MK_GLOBALS */
|
#endif /* MK_GLOBALS */
|
||||||
|
|
||||||
@@ -244,7 +247,7 @@ EXTERN char *ErrMsg[] =
|
|||||||
#define L_USAGE_OVERRIDE 1
|
#define L_USAGE_OVERRIDE 1
|
||||||
void Usage(void)
|
void Usage(void)
|
||||||
{
|
{
|
||||||
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2023 Dianne Skoll\n", VERSION, L_LANGNAME);
|
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||||
#ifdef BETA
|
#ifdef BETA
|
||||||
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
|
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -261,12 +264,10 @@ void Usage(void)
|
|||||||
fprintf(ErrFp, " -o Ignoruj instrukcje ONCE\n");
|
fprintf(ErrFp, " -o Ignoruj instrukcje ONCE\n");
|
||||||
fprintf(ErrFp, " -t Odpal wszystkie przyszłe przypomnienia niezależnie od delty\n");
|
fprintf(ErrFp, " -t Odpal wszystkie przyszłe przypomnienia niezależnie od delty\n");
|
||||||
fprintf(ErrFp, " -h Praca bezszmerowa\n");
|
fprintf(ErrFp, " -h Praca bezszmerowa\n");
|
||||||
#ifdef HAVE_QUEUED
|
|
||||||
fprintf(ErrFp, " -a Nie odpalaj przyponień czasowych - kolejkuj je\n");
|
fprintf(ErrFp, " -a Nie odpalaj przyponień czasowych - kolejkuj je\n");
|
||||||
fprintf(ErrFp, " -q Nie kolejkuj przyponień czasowych\n");
|
fprintf(ErrFp, " -q Nie kolejkuj przyponień czasowych\n");
|
||||||
fprintf(ErrFp, " -f Nie przechodź do pracy w tle\n");
|
fprintf(ErrFp, " -f Nie przechodź do pracy w tle\n");
|
||||||
fprintf(ErrFp, " -z[n] Pracuj jako demon, budząc się co n (5) minut\n");
|
fprintf(ErrFp, " -z[n] Pracuj jako demon, budząc się co n (5) minut\n");
|
||||||
#endif
|
|
||||||
fprintf(ErrFp, " -d... Odpluskwianie: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
|
fprintf(ErrFp, " -d... Odpluskwianie: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
|
||||||
fprintf(ErrFp, " -e Komunikaty o błędach skieruj na stdout\n");
|
fprintf(ErrFp, " -e Komunikaty o błędach skieruj na stdout\n");
|
||||||
fprintf(ErrFp, " -b[n] Format czasu: 0=am/pm, 1=24godz., 2=żaden\n");
|
fprintf(ErrFp, " -b[n] Format czasu: 0=am/pm, 1=24godz., 2=żaden\n");
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* */
|
/* */
|
||||||
/* REMIND is Copyright (C) 1992-2023 by Dianne Skoll */
|
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* This file is Copyright (C) 1996 by Marco Paganini and */
|
/* This file is Copyright (C) 1996 by Marco Paganini and */
|
||||||
/* Dianne Skoll. */
|
/* Dianne Skoll. */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
@@ -144,7 +144,7 @@ EXTERN char *ErrMsg[] =
|
|||||||
"Ok",
|
"Ok",
|
||||||
"Falta um ']'",
|
"Falta um ']'",
|
||||||
"Falta uma aspa",
|
"Falta uma aspa",
|
||||||
"Expressao muito complexa - muitos operadores",
|
"Expressao muito complexa",
|
||||||
"Expressao muito complexa - muitos operandos",
|
"Expressao muito complexa - muitos operandos",
|
||||||
"Falta um ')'",
|
"Falta um ')'",
|
||||||
"Funcao nao definida",
|
"Funcao nao definida",
|
||||||
@@ -244,7 +244,10 @@ EXTERN char *ErrMsg[] =
|
|||||||
"No files matching *.rem",
|
"No files matching *.rem",
|
||||||
"String too long",
|
"String too long",
|
||||||
"Time specified twice",
|
"Time specified twice",
|
||||||
"Cannot specify DURATION without specifying AT"
|
"Cannot specify DURATION without specifying AT",
|
||||||
|
"Esperando nome do dia da semana",
|
||||||
|
"Nome de argumento duplicado",
|
||||||
|
"A avaliação da expressão está desabilitada",
|
||||||
};
|
};
|
||||||
#endif /* MK_GLOBALS */
|
#endif /* MK_GLOBALS */
|
||||||
|
|
||||||
@@ -253,7 +256,7 @@ EXTERN char *ErrMsg[] =
|
|||||||
#define L_USAGE_OVERRIDE 1
|
#define L_USAGE_OVERRIDE 1
|
||||||
void Usage(void)
|
void Usage(void)
|
||||||
{
|
{
|
||||||
fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-2023 Dianne Skoll\n", VERSION, L_LANGNAME);
|
fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||||
#ifdef BETA
|
#ifdef BETA
|
||||||
fprintf(ErrFp, ">>>> VERSAO BETA <<<<\n");
|
fprintf(ErrFp, ">>>> VERSAO BETA <<<<\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -270,12 +273,10 @@ void Usage(void)
|
|||||||
fprintf(ErrFp, " -o Ignora diretivas ONCE\n");
|
fprintf(ErrFp, " -o Ignora diretivas ONCE\n");
|
||||||
fprintf(ErrFp, " -t Aciona todos os compromissos futuros, sem considerar o delta\n");
|
fprintf(ErrFp, " -t Aciona todos os compromissos futuros, sem considerar o delta\n");
|
||||||
fprintf(ErrFp, " -h Modo `Hush' - quieto\n");
|
fprintf(ErrFp, " -h Modo `Hush' - quieto\n");
|
||||||
#ifdef HAVE_QUEUED
|
|
||||||
fprintf(ErrFp, " -a Nao aciona compromissos com hora imediatamente - apenas coloca na fila\n");
|
fprintf(ErrFp, " -a Nao aciona compromissos com hora imediatamente - apenas coloca na fila\n");
|
||||||
fprintf(ErrFp, " -q Nao coloca compromissos com hora na fila\n");
|
fprintf(ErrFp, " -q Nao coloca compromissos com hora na fila\n");
|
||||||
fprintf(ErrFp, " -f Aciona compromissos com hora em modo foreground\n");
|
fprintf(ErrFp, " -f Aciona compromissos com hora em modo foreground\n");
|
||||||
fprintf(ErrFp, " -z[n] Modo `daemon', acordando a cada n (5) minutos.\n");
|
fprintf(ErrFp, " -z[n] Modo `daemon', acordando a cada n (5) minutos.\n");
|
||||||
#endif
|
|
||||||
fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trigger v=dumpvars l=showline\n");
|
fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trigger v=dumpvars l=showline\n");
|
||||||
fprintf(ErrFp, " -e Desvia mensagens normalmente enviadas a stderr para stdout\n");
|
fprintf(ErrFp, " -e Desvia mensagens normalmente enviadas a stderr para stdout\n");
|
||||||
fprintf(ErrFp, " -b[n] Formato da hora para o cal: 0=am/pm, 1=24hr, 2=nenhum\n");
|
fprintf(ErrFp, " -b[n] Formato da hora para o cal: 0=am/pm, 1=24hr, 2=nenhum\n");
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* */
|
/* */
|
||||||
/* REMIND is Copyright (C) 1992-2023 by Dianne Skoll */
|
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* This file is Copyright (C) 1996-1998 by Liviu Daia */
|
/* This file is Copyright (C) 1996-1998 by Liviu Daia */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
/* Author: Rafa Couto <rafacouto@biogate.com> */
|
/* Author: Rafa Couto <rafacouto@biogate.com> */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|||||||
361
src/main.c
361
src/main.c
@@ -6,7 +6,7 @@
|
|||||||
/* routines, etc. */
|
/* routines, etc. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -14,12 +14,19 @@
|
|||||||
#define _XOPEN_SOURCE 600
|
#define _XOPEN_SOURCE 600
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_STRINGS_H
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#ifdef HAVE_LOCALE_H
|
#ifdef HAVE_LOCALE_H
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
@@ -39,12 +46,41 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "expr.h"
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
|
|
||||||
static void DoReminders(void);
|
static void DoReminders(void);
|
||||||
|
|
||||||
|
/* Macro for simplifying common block so as not to litter code */
|
||||||
|
#define OUTPUT(c) do { if (output) { DBufPutc(output, c); } else { putchar(c); } } while(0)
|
||||||
|
|
||||||
|
void
|
||||||
|
exitfunc(void)
|
||||||
|
{
|
||||||
|
/* Kill any execution-time-limiter process */
|
||||||
|
unlimit_execution_time();
|
||||||
|
|
||||||
|
if (DebugFlag & DB_PARSE_EXPR) {
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
UnsetAllUserFuncs();
|
||||||
|
print_expr_nodes_stats();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sigalrm(int)
|
||||||
|
{
|
||||||
|
if (ExpressionEvaluationTimeLimit) {
|
||||||
|
ExpressionTimeLimitExceeded = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sigxcpu(int)
|
||||||
|
{
|
||||||
|
write(STDERR_FILENO, "\n\nmax-execution-time exceeded.\n\n", 32);
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/** **/
|
/** **/
|
||||||
@@ -56,6 +92,8 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
|
struct sigaction act;
|
||||||
|
|
||||||
#ifdef HAVE_SETLOCALE
|
#ifdef HAVE_SETLOCALE
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
#endif
|
#endif
|
||||||
@@ -68,9 +106,30 @@ int main(int argc, char *argv[])
|
|||||||
ArgV = (char const **) argv;
|
ArgV = (char const **) argv;
|
||||||
|
|
||||||
InitRemind(argc, (char const **) argv);
|
InitRemind(argc, (char const **) argv);
|
||||||
|
|
||||||
|
act.sa_handler = sigalrm;
|
||||||
|
sigemptyset(&act.sa_mask);
|
||||||
|
act.sa_flags = SA_RESTART;
|
||||||
|
if (sigaction(SIGALRM, &act, NULL) < 0) {
|
||||||
|
fprintf(stderr, "%s: sigaction() failed: %s\n",
|
||||||
|
argv[0], strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
act.sa_handler = sigxcpu;
|
||||||
|
act.sa_flags = SA_RESTART;
|
||||||
|
sigemptyset(&act.sa_mask);
|
||||||
|
if (sigaction(SIGXCPU, &act, NULL) < 0) {
|
||||||
|
fprintf(stderr, "%s: sigaction() failed: %s\n",
|
||||||
|
argv[0], strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
DBufInit(&(LastTrigger.tags));
|
DBufInit(&(LastTrigger.tags));
|
||||||
ClearLastTriggers();
|
ClearLastTriggers();
|
||||||
|
|
||||||
|
atexit(exitfunc);
|
||||||
|
|
||||||
if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) {
|
if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) {
|
||||||
ProduceCalendar();
|
ProduceCalendar();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -94,7 +153,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!Hush) {
|
if (!Hush) {
|
||||||
if (DestroyOmitContexts())
|
if (DestroyOmitContexts(1))
|
||||||
Eprint("%s", ErrMsg[E_PUSH_NOPOP]);
|
Eprint("%s", ErrMsg[E_PUSH_NOPOP]);
|
||||||
if (!Daemon && !NextMode && !NumTriggered && !NumQueued) {
|
if (!Daemon && !NextMode && !NumTriggered && !NumQueued) {
|
||||||
printf("%s\n", ErrMsg[E_NOREMINDERS]);
|
printf("%s\n", ErrMsg[E_NOREMINDERS]);
|
||||||
@@ -147,7 +206,7 @@ void
|
|||||||
PerIterationInit(void)
|
PerIterationInit(void)
|
||||||
{
|
{
|
||||||
ClearGlobalOmits();
|
ClearGlobalOmits();
|
||||||
DestroyOmitContexts();
|
DestroyOmitContexts(1);
|
||||||
DestroyVars(0);
|
DestroyVars(0);
|
||||||
DefaultColorR = -1;
|
DefaultColorR = -1;
|
||||||
DefaultColorG = -1;
|
DefaultColorG = -1;
|
||||||
@@ -274,9 +333,11 @@ static void DoReminders(void)
|
|||||||
case T_Pop: r=PopOmitContext(&p); break;
|
case T_Pop: r=PopOmitContext(&p); break;
|
||||||
case T_Preserve: r=DoPreserve(&p); break;
|
case T_Preserve: r=DoPreserve(&p); break;
|
||||||
case T_Push: r=PushOmitContext(&p); break;
|
case T_Push: r=PushOmitContext(&p); break;
|
||||||
|
case T_Expr: r = DoExpr(&p); break;
|
||||||
case T_RemType: if (tok.val == RUN_TYPE) {
|
case T_RemType: if (tok.val == RUN_TYPE) {
|
||||||
r=DoRun(&p);
|
r=DoRun(&p);
|
||||||
} else {
|
} else {
|
||||||
|
DestroyParser(&p);
|
||||||
CreateParser(CurLine, &p);
|
CreateParser(CurLine, &p);
|
||||||
r=DoRem(&p);
|
r=DoRem(&p);
|
||||||
purge_handled = 1;
|
purge_handled = 1;
|
||||||
@@ -285,10 +346,8 @@ static void DoReminders(void)
|
|||||||
|
|
||||||
|
|
||||||
/* If we don't recognize the command, do a REM by default */
|
/* If we don't recognize the command, do a REM by default */
|
||||||
/* Note: Since the parser hasn't been used yet, we don't */
|
|
||||||
/* need to destroy it here. */
|
|
||||||
|
|
||||||
default: CreateParser(CurLine, &p); purge_handled = 1; r=DoRem(&p); break;
|
default: DestroyParser(&p); CreateParser(CurLine, &p); purge_handled = 1; r=DoRem(&p); break;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (r && (!Hush || r != E_RUN_DISABLED)) {
|
if (r && (!Hush || r != E_RUN_DISABLED)) {
|
||||||
@@ -446,6 +505,16 @@ int ParseChar(ParsePtr p, int *err, int peek)
|
|||||||
return *(p->pos++);
|
return *(p->pos++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert [[ to just a literal [ */
|
||||||
|
if (*p->pos == BEG_OF_EXPR && *(p->pos+1) == BEG_OF_EXPR) {
|
||||||
|
if (peek) {
|
||||||
|
return *(p->pos+1);
|
||||||
|
} else {
|
||||||
|
p->pos++;
|
||||||
|
return *(p->pos++);
|
||||||
|
}
|
||||||
|
}
|
||||||
p->expr_happened = 1;
|
p->expr_happened = 1;
|
||||||
p->pos++;
|
p->pos++;
|
||||||
r = EvalExpr(&(p->pos), &val, p);
|
r = EvalExpr(&(p->pos), &val, p);
|
||||||
@@ -454,8 +523,15 @@ int ParseChar(ParsePtr p, int *err, int peek)
|
|||||||
DestroyParser(p);
|
DestroyParser(p);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
while(*p->pos && (isempty(*p->pos))) {
|
||||||
|
p->pos++;
|
||||||
|
}
|
||||||
if (*p->pos != END_OF_EXPR) {
|
if (*p->pos != END_OF_EXPR) {
|
||||||
*err = E_MISS_END;
|
if (*p->pos) {
|
||||||
|
*err = E_PARSE_ERR;
|
||||||
|
} else {
|
||||||
|
*err = E_MISS_END;
|
||||||
|
}
|
||||||
DestroyParser(p);
|
DestroyParser(p);
|
||||||
DestroyValue(val);
|
DestroyValue(val);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -570,6 +646,57 @@ int ParseIdentifier(ParsePtr p, DynamicBuffer *dbuf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* ParseExpr */
|
||||||
|
/* */
|
||||||
|
/* We are expecting an expression here. Parse it and return */
|
||||||
|
/* the value node tree. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
expr_node * ParseExpr(ParsePtr p, int *r)
|
||||||
|
{
|
||||||
|
|
||||||
|
int bracketed = 0;
|
||||||
|
expr_node *node;
|
||||||
|
|
||||||
|
if (p->isnested) {
|
||||||
|
*r = E_PARSE_ERR; /* Can't nest expressions */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!p->pos) {
|
||||||
|
*r = E_PARSE_ERR; /* Missing expression */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (isempty(*p->pos)) (p->pos)++;
|
||||||
|
if (!*(p->pos)) {
|
||||||
|
*r = E_EOLN;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (*p->pos == BEG_OF_EXPR) {
|
||||||
|
(p->pos)++;
|
||||||
|
bracketed = 1;
|
||||||
|
}
|
||||||
|
node = parse_expression(&(p->pos), r, NULL);
|
||||||
|
if (*r) {
|
||||||
|
return free_expr_tree(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bracketed) {
|
||||||
|
if (*p->pos != END_OF_EXPR) {
|
||||||
|
if (*p->pos) {
|
||||||
|
*r = E_PARSE_ERR;
|
||||||
|
} else {
|
||||||
|
*r = E_MISS_END;
|
||||||
|
}
|
||||||
|
return free_expr_tree(node);
|
||||||
|
}
|
||||||
|
(p->pos)++;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* EvaluateExpr */
|
/* EvaluateExpr */
|
||||||
@@ -581,21 +708,22 @@ int ParseIdentifier(ParsePtr p, DynamicBuffer *dbuf)
|
|||||||
int EvaluateExpr(ParsePtr p, Value *v)
|
int EvaluateExpr(ParsePtr p, Value *v)
|
||||||
{
|
{
|
||||||
|
|
||||||
int bracketed = 0;
|
|
||||||
int r;
|
int r;
|
||||||
|
int nonconst = 0;
|
||||||
|
expr_node *node = ParseExpr(p, &r);
|
||||||
|
|
||||||
if (p->isnested) return E_PARSE_ERR; /* Can't nest expressions */
|
if (r != OK) {
|
||||||
while (isempty(*p->pos)) (p->pos)++;
|
return r;
|
||||||
if (!p->pos) return E_PARSE_ERR; /* Missing expression */
|
|
||||||
if (*p->pos == BEG_OF_EXPR) {
|
|
||||||
(p->pos)++;
|
|
||||||
bracketed = 1;
|
|
||||||
}
|
}
|
||||||
r = EvalExpr(&(p->pos), v, p);
|
if (!node) {
|
||||||
|
return E_SWERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = evaluate_expression(node, NULL, v, &nonconst);
|
||||||
|
free_expr_tree(node);
|
||||||
if (r) return r;
|
if (r) return r;
|
||||||
if (bracketed) {
|
if (nonconst) {
|
||||||
if (*p->pos != END_OF_EXPR) return E_MISS_END;
|
p->nonconst_expr = 1;
|
||||||
(p->pos)++;
|
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -631,36 +759,36 @@ void Wprint(char const *fmt, ...)
|
|||||||
void Eprint(char const *fmt, ...)
|
void Eprint(char const *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
|
char const *fname;
|
||||||
|
|
||||||
/* Check if more than one error msg. from this line */
|
/* Check if more than one error msg. from this line */
|
||||||
if (!FreshLine && !ShowAllErrors) return;
|
if (!FreshLine && !ShowAllErrors) return;
|
||||||
|
|
||||||
if (FreshLine && FileName) {
|
if (!FileName) {
|
||||||
FreshLine = 0;
|
return;
|
||||||
if (strcmp(FileName, "-")) {
|
|
||||||
(void) fprintf(ErrFp, "%s(%d): ", FileName, LineNo);
|
|
||||||
if (print_callstack(ErrFp)) {
|
|
||||||
(void) fprintf(ErrFp, ": ");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(void) fprintf(ErrFp, "-stdin-(%d): ", LineNo);
|
|
||||||
if (print_callstack(ErrFp)) {
|
|
||||||
(void) fprintf(ErrFp, ": ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (DebugFlag & DB_PRTLINE) OutputLine(ErrFp);
|
|
||||||
} else if (FileName) {
|
|
||||||
fprintf(ErrFp, " ");
|
|
||||||
if (print_callstack(ErrFp)) {
|
|
||||||
(void) fprintf(ErrFp, ": ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(FileName, "-")) {
|
||||||
|
fname = FileName;
|
||||||
|
} else {
|
||||||
|
fname = "-stdin-";
|
||||||
|
}
|
||||||
|
if (FreshLine) {
|
||||||
|
(void) fprintf(ErrFp, "%s(%d): ", fname, LineNo);
|
||||||
|
} else {
|
||||||
|
fprintf(ErrFp, " ");
|
||||||
|
}
|
||||||
va_start(argptr, fmt);
|
va_start(argptr, fmt);
|
||||||
(void) vfprintf(ErrFp, fmt, argptr);
|
(void) vfprintf(ErrFp, fmt, argptr);
|
||||||
(void) fputc('\n', ErrFp);
|
(void) fputc('\n', ErrFp);
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
return;
|
if (print_callstack(ErrFp)) {
|
||||||
|
(void) fprintf(ErrFp, "\n");
|
||||||
|
}
|
||||||
|
if (FreshLine) {
|
||||||
|
if (DebugFlag & DB_PRTLINE) OutputLine(ErrFp);
|
||||||
|
}
|
||||||
|
FreshLine = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -747,17 +875,17 @@ int PushToken(char const *tok, ParsePtr p)
|
|||||||
/* Return the system time in seconds past midnight */
|
/* Return the system time in seconds past midnight */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
long SystemTime(int realtime)
|
int SystemTime(int realtime)
|
||||||
{
|
{
|
||||||
time_t now;
|
time_t now;
|
||||||
struct tm *t;
|
struct tm *t;
|
||||||
|
|
||||||
if (!realtime && (SysTime != -1L)) return SysTime;
|
if (!realtime && (SysTime != -1)) return SysTime;
|
||||||
|
|
||||||
now = time(NULL);
|
now = time(NULL);
|
||||||
t = localtime(&now);
|
t = localtime(&now);
|
||||||
return (long) t->tm_hour * 3600L + (long) t->tm_min * 60L +
|
return t->tm_hour * 3600L + t->tm_min * 60L +
|
||||||
(long) t->tm_sec;
|
t->tm_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -769,7 +897,7 @@ long SystemTime(int realtime)
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int MinutesPastMidnight(int realtime)
|
int MinutesPastMidnight(int realtime)
|
||||||
{
|
{
|
||||||
return (int) (SystemTime(realtime) / 60);
|
return (SystemTime(realtime) / 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -829,6 +957,7 @@ int DoIf(ParsePtr p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IfLinenos[NumIfs] = LineNo;
|
||||||
NumIfs++;
|
NumIfs++;
|
||||||
IfFlags &= ~(IF_MASK << (2*NumIfs - 2));
|
IfFlags &= ~(IF_MASK << (2*NumIfs - 2));
|
||||||
IfFlags |= syndrome << (2 * NumIfs - 2);
|
IfFlags |= syndrome << (2 * NumIfs - 2);
|
||||||
@@ -893,7 +1022,7 @@ int DoIfTrig(ParsePtr p)
|
|||||||
if ((size_t) NumIfs >= IF_NEST) return E_NESTED_IF;
|
if ((size_t) NumIfs >= IF_NEST) return E_NESTED_IF;
|
||||||
if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE;
|
if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE;
|
||||||
else {
|
else {
|
||||||
if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r;
|
if ( (r=ParseRem(p, &trig, &tim)) ) return r;
|
||||||
if (trig.typ != NO_TYPE) return E_PARSE_ERR;
|
if (trig.typ != NO_TYPE) return E_PARSE_ERR;
|
||||||
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
|
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
|
||||||
if (r) {
|
if (r) {
|
||||||
@@ -1011,6 +1140,12 @@ int DoDebug(ParsePtr p)
|
|||||||
else DebugFlag &= ~DB_ECHO_LINE;
|
else DebugFlag &= ~DB_ECHO_LINE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
case 'S':
|
||||||
|
if (val) DebugFlag |= DB_PARSE_EXPR;
|
||||||
|
else DebugFlag &= ~DB_PARSE_EXPR;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
if (val) DebugFlag |= DB_PRTEXPR;
|
if (val) DebugFlag |= DB_PRTEXPR;
|
||||||
@@ -1076,7 +1211,7 @@ int DoBanner(ParsePtr p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBufFree(&Banner);
|
DBufFree(&Banner);
|
||||||
|
|
||||||
err = DBufPuts(&Banner, DBufValue(&buf));
|
err = DBufPuts(&Banner, DBufValue(&buf));
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
return err;
|
return err;
|
||||||
@@ -1088,7 +1223,6 @@ int DoBanner(ParsePtr p)
|
|||||||
/* */
|
/* */
|
||||||
/* Enable or disable the RUN command under program control */
|
/* Enable or disable the RUN command under program control */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int DoRun(ParsePtr p)
|
int DoRun(ParsePtr p)
|
||||||
{
|
{
|
||||||
@@ -1115,6 +1249,38 @@ int DoRun(ParsePtr p)
|
|||||||
return VerifyEoln(p);
|
return VerifyEoln(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* DoExpr */
|
||||||
|
/* */
|
||||||
|
/* Enable or disable expression evaluation */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
int DoExpr(ParsePtr p)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
DynamicBuffer buf;
|
||||||
|
DBufInit(&buf);
|
||||||
|
|
||||||
|
if ( (r=ParseToken(p, &buf)) ) return r;
|
||||||
|
|
||||||
|
/* Only allow EXPR ON in top-level script */
|
||||||
|
if (! StrCmpi(DBufValue(&buf), "ON")) {
|
||||||
|
if (TopLevel()) ExpressionEvaluationDisabled = 0;
|
||||||
|
}
|
||||||
|
/* But allow EXPR OFF anywhere */
|
||||||
|
else if (! StrCmpi(DBufValue(&buf), "OFF"))
|
||||||
|
ExpressionEvaluationDisabled = 1;
|
||||||
|
else {
|
||||||
|
DBufFree(&buf);
|
||||||
|
return E_PARSE_ERR;
|
||||||
|
}
|
||||||
|
DBufFree(&buf);
|
||||||
|
|
||||||
|
return VerifyEoln(p);
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* DoFlush */
|
/* DoFlush */
|
||||||
@@ -1251,19 +1417,19 @@ int CalcMinsFromUTC(int dse, int tim, int *mins, int *isdst)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char const *OutputEscapeSequences(char const *s, int print)
|
static char const *OutputEscapeSequences(char const *s, int print, DynamicBuffer *output)
|
||||||
{
|
{
|
||||||
while (*s == 0x1B && *(s+1) == '[') {
|
while (*s == 0x1B && *(s+1) == '[') {
|
||||||
if (print) putchar(*s);
|
if (print) OUTPUT(*s);
|
||||||
s++;
|
s++;
|
||||||
if (print) putchar(*s);
|
if (print) OUTPUT(*s);
|
||||||
s++;
|
s++;
|
||||||
while (*s && (*s < 0x40 || *s > 0x7E)) {
|
while (*s && (*s < 0x40 || *s > 0x7E)) {
|
||||||
if (print) putchar(*s);
|
if (print) OUTPUT(*s);
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
if (*s) {
|
if (*s) {
|
||||||
if (print) putchar(*s);
|
if (print) OUTPUT(*s);
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1272,19 +1438,19 @@ static char const *OutputEscapeSequences(char const *s, int print)
|
|||||||
|
|
||||||
#ifdef REM_USE_WCHAR
|
#ifdef REM_USE_WCHAR
|
||||||
#define ISWBLANK(c) (iswspace(c) && (c) != '\n')
|
#define ISWBLANK(c) (iswspace(c) && (c) != '\n')
|
||||||
static wchar_t const *OutputEscapeSequencesWS(wchar_t const *s, int print)
|
static wchar_t const *OutputEscapeSequencesWS(wchar_t const *s, int print, DynamicBuffer *output)
|
||||||
{
|
{
|
||||||
while (*s == 0x1B && *(s+1) == '[') {
|
while (*s == 0x1B && *(s+1) == '[') {
|
||||||
if (print) PutWideChar(*s);
|
if (print) PutWideChar(*s, output);
|
||||||
s++;
|
s++;
|
||||||
if (print) PutWideChar(*s);
|
if (print) PutWideChar(*s, output);
|
||||||
s++;
|
s++;
|
||||||
while (*s && (*s < 0x40 || *s > 0x7E)) {
|
while (*s && (*s < 0x40 || *s > 0x7E)) {
|
||||||
if (print) PutWideChar(*s);
|
if (print) PutWideChar(*s, output);
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
if (*s) {
|
if (*s) {
|
||||||
if (print) PutWideChar(*s);
|
if (print) PutWideChar(*s, output);
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1293,7 +1459,7 @@ static wchar_t const *OutputEscapeSequencesWS(wchar_t const *s, int print)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FillParagraphWCAux(wchar_t const *s)
|
FillParagraphWCAux(wchar_t const *s, DynamicBuffer *output)
|
||||||
{
|
{
|
||||||
int line = 0;
|
int line = 0;
|
||||||
int i, j;
|
int i, j;
|
||||||
@@ -1308,7 +1474,7 @@ FillParagraphWCAux(wchar_t const *s)
|
|||||||
|
|
||||||
/* If it's a carriage return, output it and start new paragraph */
|
/* If it's a carriage return, output it and start new paragraph */
|
||||||
if (*s == '\n') {
|
if (*s == '\n') {
|
||||||
putchar('\n');
|
OUTPUT('\n');
|
||||||
s++;
|
s++;
|
||||||
line = 0;
|
line = 0;
|
||||||
while(ISWBLANK(*s)) s++;
|
while(ISWBLANK(*s)) s++;
|
||||||
@@ -1321,7 +1487,7 @@ FillParagraphWCAux(wchar_t const *s)
|
|||||||
number of spaces */
|
number of spaces */
|
||||||
j = line ? SubsIndent : FirstIndent;
|
j = line ? SubsIndent : FirstIndent;
|
||||||
for (i=0; i<j; i++) {
|
for (i=0; i<j; i++) {
|
||||||
putchar(' ');
|
OUTPUT(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the amount of room left on this line */
|
/* Calculate the amount of room left on this line */
|
||||||
@@ -1334,7 +1500,7 @@ FillParagraphWCAux(wchar_t const *s)
|
|||||||
if (*s == '\n') break;
|
if (*s == '\n') break;
|
||||||
while(1) {
|
while(1) {
|
||||||
t = s;
|
t = s;
|
||||||
s = OutputEscapeSequencesWS(s, 1);
|
s = OutputEscapeSequencesWS(s, 1, output);
|
||||||
if (s == t) break;
|
if (s == t) break;
|
||||||
while(ISWBLANK(*s)) s++;
|
while(ISWBLANK(*s)) s++;
|
||||||
}
|
}
|
||||||
@@ -1342,7 +1508,7 @@ FillParagraphWCAux(wchar_t const *s)
|
|||||||
len = 0;
|
len = 0;
|
||||||
while(*s && !iswspace(*s)) {
|
while(*s && !iswspace(*s)) {
|
||||||
if (*s == 0x1B && *(s+1) == '[') {
|
if (*s == 0x1B && *(s+1) == '[') {
|
||||||
s = OutputEscapeSequencesWS(s, 0);
|
s = OutputEscapeSequencesWS(s, 0, output);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
len += wcwidth(*s);
|
len += wcwidth(*s);
|
||||||
@@ -1353,17 +1519,17 @@ FillParagraphWCAux(wchar_t const *s)
|
|||||||
}
|
}
|
||||||
if (!pendspace || len+pendspace <= roomleft) {
|
if (!pendspace || len+pendspace <= roomleft) {
|
||||||
for (i=0; i<pendspace; i++) {
|
for (i=0; i<pendspace; i++) {
|
||||||
putchar(' ');
|
OUTPUT(' ');
|
||||||
}
|
}
|
||||||
while(t < s) {
|
while(t < s) {
|
||||||
PutWideChar(*t);
|
PutWideChar(*t, output);
|
||||||
if (strchr(EndSent, *t)) doublespace = 2;
|
if (strchr(EndSent, *t)) doublespace = 2;
|
||||||
else if (!strchr(EndSentIg, *t)) doublespace = 1;
|
else if (!strchr(EndSentIg, *t)) doublespace = 1;
|
||||||
t++;
|
t++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s = t;
|
s = t;
|
||||||
putchar('\n');
|
OUTPUT('\n');
|
||||||
line++;
|
line++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1374,7 +1540,7 @@ FillParagraphWCAux(wchar_t const *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
FillParagraphWC(char const *s)
|
FillParagraphWC(char const *s, DynamicBuffer *output)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
wchar_t *buf;
|
wchar_t *buf;
|
||||||
@@ -1384,7 +1550,7 @@ FillParagraphWC(char const *s)
|
|||||||
buf = calloc(len+1, sizeof(wchar_t));
|
buf = calloc(len+1, sizeof(wchar_t));
|
||||||
if (!buf) return E_NO_MEM;
|
if (!buf) return E_NO_MEM;
|
||||||
(void) mbstowcs(buf, s, len+1);
|
(void) mbstowcs(buf, s, len+1);
|
||||||
FillParagraphWCAux(buf);
|
FillParagraphWCAux(buf, output);
|
||||||
free(buf);
|
free(buf);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -1404,7 +1570,7 @@ FillParagraphWC(char const *s)
|
|||||||
/* A macro safe ONLY if used with arg with no side effects! */
|
/* A macro safe ONLY if used with arg with no side effects! */
|
||||||
#define ISBLANK(c) (isspace(c) && (c) != '\n')
|
#define ISBLANK(c) (isspace(c) && (c) != '\n')
|
||||||
|
|
||||||
void FillParagraph(char const *s)
|
void FillParagraph(char const *s, DynamicBuffer *output)
|
||||||
{
|
{
|
||||||
|
|
||||||
int line = 0;
|
int line = 0;
|
||||||
@@ -1422,7 +1588,7 @@ void FillParagraph(char const *s)
|
|||||||
if (!*s) return;
|
if (!*s) return;
|
||||||
|
|
||||||
#ifdef REM_USE_WCHAR
|
#ifdef REM_USE_WCHAR
|
||||||
if (FillParagraphWC(s) == OK) {
|
if (FillParagraphWC(s, output) == OK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1432,7 +1598,7 @@ void FillParagraph(char const *s)
|
|||||||
|
|
||||||
/* If it's a carriage return, output it and start new paragraph */
|
/* If it's a carriage return, output it and start new paragraph */
|
||||||
if (*s == '\n') {
|
if (*s == '\n') {
|
||||||
putchar('\n');
|
OUTPUT('\n');
|
||||||
s++;
|
s++;
|
||||||
line = 0;
|
line = 0;
|
||||||
while(ISBLANK(*s)) s++;
|
while(ISBLANK(*s)) s++;
|
||||||
@@ -1445,7 +1611,7 @@ void FillParagraph(char const *s)
|
|||||||
number of spaces */
|
number of spaces */
|
||||||
j = line ? SubsIndent : FirstIndent;
|
j = line ? SubsIndent : FirstIndent;
|
||||||
for (i=0; i<j; i++) {
|
for (i=0; i<j; i++) {
|
||||||
putchar(' ');
|
OUTPUT(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the amount of room left on this line */
|
/* Calculate the amount of room left on this line */
|
||||||
@@ -1458,7 +1624,7 @@ void FillParagraph(char const *s)
|
|||||||
if (*s == '\n') break;
|
if (*s == '\n') break;
|
||||||
while(1) {
|
while(1) {
|
||||||
t = s;
|
t = s;
|
||||||
s = OutputEscapeSequences(s, 1);
|
s = OutputEscapeSequences(s, 1, output);
|
||||||
if (s == t) break;
|
if (s == t) break;
|
||||||
while(ISBLANK(*s)) s++;
|
while(ISBLANK(*s)) s++;
|
||||||
}
|
}
|
||||||
@@ -1466,7 +1632,7 @@ void FillParagraph(char const *s)
|
|||||||
len = 0;
|
len = 0;
|
||||||
while(*s && !isspace(*s)) {
|
while(*s && !isspace(*s)) {
|
||||||
if (*s == 0x1B && *(s+1) == '[') {
|
if (*s == 0x1B && *(s+1) == '[') {
|
||||||
s = OutputEscapeSequences(s, 0);
|
s = OutputEscapeSequences(s, 0, output);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
@@ -1477,17 +1643,17 @@ void FillParagraph(char const *s)
|
|||||||
}
|
}
|
||||||
if (!pendspace || len+pendspace <= roomleft) {
|
if (!pendspace || len+pendspace <= roomleft) {
|
||||||
for (i=0; i<pendspace; i++) {
|
for (i=0; i<pendspace; i++) {
|
||||||
putchar(' ');
|
OUTPUT(' ');
|
||||||
}
|
}
|
||||||
while(t < s) {
|
while(t < s) {
|
||||||
putchar(*t);
|
OUTPUT(*t);
|
||||||
if (strchr(EndSent, *t)) doublespace = 2;
|
if (strchr(EndSent, *t)) doublespace = 2;
|
||||||
else if (!strchr(EndSentIg, *t)) doublespace = 1;
|
else if (!strchr(EndSentIg, *t)) doublespace = 1;
|
||||||
t++;
|
t++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s = t;
|
s = t;
|
||||||
putchar('\n');
|
OUTPUT('\n');
|
||||||
line++;
|
line++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1651,12 +1817,51 @@ SaveLastTimeTrig(TimeTrig const *t)
|
|||||||
memcpy(&LastTimeTrig, t, sizeof(LastTimeTrig));
|
memcpy(&LastTimeTrig, t, sizeof(LastTimeTrig));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wrapper to ignore warnings about ignoring return value of system() */
|
/* Wrapper to ignore warnings about ignoring return value of system()
|
||||||
|
Also redirects stdin and stdout to /dev/null for queued reminders */
|
||||||
|
|
||||||
void
|
void
|
||||||
System(char const *cmd)
|
System(char const *cmd, int is_queued)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
pid_t kid;
|
||||||
|
int fd;
|
||||||
|
int status;
|
||||||
|
int do_exit = 0;
|
||||||
|
if (is_queued && IsServerMode()) {
|
||||||
|
do_exit = 1;
|
||||||
|
/* Server mode... redirect stdin and stdout to /dev/null */
|
||||||
|
kid = fork();
|
||||||
|
if (kid == (pid_t) -1) {
|
||||||
|
/* Fork failed... nothing we can do */
|
||||||
|
return;
|
||||||
|
} else if (kid == 0) {
|
||||||
|
/* In the child */
|
||||||
|
(void) close(STDIN_FILENO);
|
||||||
|
(void) close(STDOUT_FILENO);
|
||||||
|
fd = open("/dev/null", O_RDONLY);
|
||||||
|
if (fd >= 0 && fd != STDIN_FILENO) {
|
||||||
|
dup2(fd, STDIN_FILENO);
|
||||||
|
close(STDIN_FILENO);
|
||||||
|
}
|
||||||
|
fd = open("/dev/null", O_WRONLY);
|
||||||
|
if (fd >= 0 && fd != STDOUT_FILENO) {
|
||||||
|
dup2(fd, STDOUT_FILENO);
|
||||||
|
close(STDOUT_FILENO);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* In the parent */
|
||||||
|
while (waitpid(kid, &status, 0) != kid) /* continue */ ;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* This is the child process or original if we never forked */
|
||||||
r = system(cmd);
|
r = system(cmd);
|
||||||
|
if (do_exit) {
|
||||||
|
/* In the child process, so exit! */
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/md5.h
10
src/md5.h
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_STDINT_H
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef uint32_t uint32;
|
||||||
|
#else
|
||||||
#if SIZEOF_UNSIGNED_INT == 4
|
#if SIZEOF_UNSIGNED_INT == 4
|
||||||
typedef unsigned int uint32;
|
typedef unsigned int uint32;
|
||||||
#elif SIZEOF_UNSIGNED_LONG == 4
|
#elif SIZEOF_UNSIGNED_LONG == 4
|
||||||
@@ -13,6 +17,7 @@ typedef unsigned long uint32;
|
|||||||
#else
|
#else
|
||||||
# error Could not find a 32-bit integer type
|
# error Could not find a 32-bit integer type
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
struct MD5Context {
|
struct MD5Context {
|
||||||
uint32 buf[4];
|
uint32 buf[4];
|
||||||
@@ -26,9 +31,4 @@ void MD5Update(struct MD5Context *context, unsigned char const *buf,
|
|||||||
void MD5Final(unsigned char digest[16], struct MD5Context *context);
|
void MD5Final(unsigned char digest[16], struct MD5Context *context);
|
||||||
void MD5Transform(uint32 buf[4], uint32 const in[16]);
|
void MD5Transform(uint32 buf[4], uint32 const in[16]);
|
||||||
|
|
||||||
/*
|
|
||||||
* This is needed to make RSAREF happy on some MS-DOS compilers.
|
|
||||||
*/
|
|
||||||
typedef struct MD5Context MD5_CTX;
|
|
||||||
|
|
||||||
#endif /* !MD5_H */
|
#endif /* !MD5_H */
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -66,7 +66,6 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "expr.h"
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
|
|
||||||
@@ -412,7 +411,7 @@ static double phase(double pdate,
|
|||||||
Day = pdate - epoch; /* Date within epoch */
|
Day = pdate - epoch; /* Date within epoch */
|
||||||
N = fixangle((360 / 365.2422) * Day); /* Mean anomaly of the Sun */
|
N = fixangle((360 / 365.2422) * Day); /* Mean anomaly of the Sun */
|
||||||
M = fixangle(N + elonge - elongp); /* Convert from perigee
|
M = fixangle(N + elonge - elongp); /* Convert from perigee
|
||||||
co-ordinates to epoch 1980.0 */
|
coordinates to epoch 1980.0 */
|
||||||
Ec = kepler(M, eccent); /* Solve equation of Kepler */
|
Ec = kepler(M, eccent); /* Solve equation of Kepler */
|
||||||
Ec = sqrt((1 + eccent) / (1 - eccent)) * tan(Ec / 2);
|
Ec = sqrt((1 + eccent) / (1 - eccent)) * tan(Ec / 2);
|
||||||
Ec = 2 * todeg(atan(Ec)); /* 1 anomaly */
|
Ec = 2 * todeg(atan(Ec)); /* 1 anomaly */
|
||||||
|
|||||||
39
src/omit.c
39
src/omit.c
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -14,15 +14,14 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "expr.h"
|
|
||||||
|
|
||||||
static int BexistsIntArray (int array[], int num, int key);
|
static int BexistsIntArray (int const array[], int num, int key);
|
||||||
static void InsertIntoSortedArray (int *array, int num, int key);
|
static void InsertIntoSortedArray (int *array, int num, int key);
|
||||||
|
|
||||||
/* Arrays for the global omits */
|
/* Arrays for the global omits */
|
||||||
@@ -32,11 +31,13 @@ static int PartialOmitArray[MAX_PARTIAL_OMITS];
|
|||||||
/* WeekdayOmits is declared in global.h */
|
/* WeekdayOmits is declared in global.h */
|
||||||
|
|
||||||
/* How many of each omit types do we have? */
|
/* How many of each omit types do we have? */
|
||||||
static int NumFullOmits, NumPartialOmits;
|
int NumFullOmits, NumPartialOmits;
|
||||||
|
|
||||||
/* The structure for saving and restoring OMIT contexts */
|
/* The structure for saving and restoring OMIT contexts */
|
||||||
typedef struct omitcontext {
|
typedef struct omitcontext {
|
||||||
struct omitcontext *next;
|
struct omitcontext *next;
|
||||||
|
char *filename;
|
||||||
|
int lineno;
|
||||||
int numfull, numpart;
|
int numfull, numpart;
|
||||||
int *fullsave;
|
int *fullsave;
|
||||||
int *partsave;
|
int *partsave;
|
||||||
@@ -79,19 +80,25 @@ int DoClear(ParsePtr p)
|
|||||||
/* */
|
/* */
|
||||||
/* Free all the memory used by saved OMIT contexts. */
|
/* Free all the memory used by saved OMIT contexts. */
|
||||||
/* As a side effect, return the number of OMIT contexts */
|
/* As a side effect, return the number of OMIT contexts */
|
||||||
/* destroyed. */
|
/* destroyed. If print_unmatched is true, print an error for */
|
||||||
|
/* each undestroyed OMIT contect */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int DestroyOmitContexts(void)
|
int DestroyOmitContexts(int print_unmatched)
|
||||||
{
|
{
|
||||||
OmitContext *c = SavedOmitContexts;
|
OmitContext *c = SavedOmitContexts;
|
||||||
OmitContext *d;
|
OmitContext *d;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
|
|
||||||
while (c) {
|
while (c) {
|
||||||
|
if (print_unmatched) {
|
||||||
|
Wprint("Unmatched PUSH-OMIT-CONTEXT at %s(%d)",
|
||||||
|
c->filename, c->lineno);
|
||||||
|
}
|
||||||
num++;
|
num++;
|
||||||
if (c->fullsave) free(c->fullsave);
|
if (c->fullsave) free(c->fullsave);
|
||||||
if (c->partsave) free(c->partsave);
|
if (c->partsave) free(c->partsave);
|
||||||
|
if (c->filename) free(c->filename);
|
||||||
d = c->next;
|
d = c->next;
|
||||||
free(c);
|
free(c);
|
||||||
c = d;
|
c = d;
|
||||||
@@ -116,16 +123,28 @@ int PushOmitContext(ParsePtr p)
|
|||||||
context = NEW(OmitContext);
|
context = NEW(OmitContext);
|
||||||
if (!context) return E_NO_MEM;
|
if (!context) return E_NO_MEM;
|
||||||
|
|
||||||
|
if (FileName) {
|
||||||
|
context->filename = StrDup(FileName);
|
||||||
|
} else {
|
||||||
|
context->filename = StrDup("");
|
||||||
|
}
|
||||||
|
if (!context->filename) {
|
||||||
|
free(context);
|
||||||
|
return E_NO_MEM;
|
||||||
|
}
|
||||||
|
context->lineno = LineNo;
|
||||||
context->numfull = NumFullOmits;
|
context->numfull = NumFullOmits;
|
||||||
context->numpart = NumPartialOmits;
|
context->numpart = NumPartialOmits;
|
||||||
context->weekdaysave = WeekdayOmits;
|
context->weekdaysave = WeekdayOmits;
|
||||||
context->fullsave = malloc(NumFullOmits * sizeof(int));
|
context->fullsave = malloc(NumFullOmits * sizeof(int));
|
||||||
if (NumFullOmits && !context->fullsave) {
|
if (NumFullOmits && !context->fullsave) {
|
||||||
|
free(context->filename);
|
||||||
free(context);
|
free(context);
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
context->partsave = malloc(NumPartialOmits * sizeof(int));
|
context->partsave = malloc(NumPartialOmits * sizeof(int));
|
||||||
if (NumPartialOmits && !context->partsave) {
|
if (NumPartialOmits && !context->partsave) {
|
||||||
|
free(context->filename);
|
||||||
free(context->fullsave);
|
free(context->fullsave);
|
||||||
free(context);
|
free(context);
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
@@ -175,6 +194,7 @@ int PopOmitContext(ParsePtr p)
|
|||||||
/* 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);
|
||||||
|
if (c->filename) free(c->filename);
|
||||||
free(c);
|
free(c);
|
||||||
|
|
||||||
return VerifyEoln(p);
|
return VerifyEoln(p);
|
||||||
@@ -251,7 +271,7 @@ int IsOmitted(int dse, int localomit, char const *omitfunc, int *omit)
|
|||||||
/* element is found, 0 otherwise. */
|
/* element is found, 0 otherwise. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static int BexistsIntArray(int array[], int num, int key)
|
static int BexistsIntArray(int const array[], int num, int key)
|
||||||
{
|
{
|
||||||
int top=num-1, bot=0, mid;
|
int top=num-1, bot=0, mid;
|
||||||
|
|
||||||
@@ -445,6 +465,9 @@ int DoOmit(ParsePtr p)
|
|||||||
if (!BexistsIntArray(PartialOmitArray, NumPartialOmits, syndrome)) {
|
if (!BexistsIntArray(PartialOmitArray, NumPartialOmits, syndrome)) {
|
||||||
InsertIntoSortedArray(PartialOmitArray, NumPartialOmits, syndrome);
|
InsertIntoSortedArray(PartialOmitArray, NumPartialOmits, syndrome);
|
||||||
NumPartialOmits++;
|
NumPartialOmits++;
|
||||||
|
if (NumPartialOmits == 366) {
|
||||||
|
Wprint("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]) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
84
src/protos.h
84
src/protos.h
@@ -5,7 +5,7 @@
|
|||||||
/* Function Prototypes. */
|
/* Function Prototypes. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -13,6 +13,18 @@
|
|||||||
/* Suppress unused variable warnings */
|
/* Suppress unused variable warnings */
|
||||||
#define UNUSED(x) (void) x
|
#define UNUSED(x) (void) x
|
||||||
|
|
||||||
|
#ifdef HAVE_STRDUP
|
||||||
|
#define StrDup strdup
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_STRNCASECMP
|
||||||
|
#define StrinCmp strncasecmp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_STRCASECMP
|
||||||
|
#define StrCmpi strcasecmp
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Define a string assignment macro - be careful!!! */
|
/* Define a string assignment macro - be careful!!! */
|
||||||
#define STRSET(x, str) { if (x) free(x); (x) = StrDup(str); }
|
#define STRSET(x, str) { if (x) free(x); (x) = StrDup(str); }
|
||||||
|
|
||||||
@@ -22,28 +34,39 @@
|
|||||||
/* Characters to ignore */
|
/* Characters to ignore */
|
||||||
#define isempty(c) (isspace(c) || ((c) == '\\'))
|
#define isempty(c) (isspace(c) || ((c) == '\\'))
|
||||||
|
|
||||||
|
#define IsServerMode() (Daemon < 0)
|
||||||
|
#define ShouldFork (!DontFork)
|
||||||
|
|
||||||
#include "dynbuf.h"
|
#include "dynbuf.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
int CallUserFunc (char const *name, int nargs, ParsePtr p);
|
int CallUserFunc (char const *name, int nargs, ParsePtr p);
|
||||||
int DoFset (ParsePtr p);
|
int DoFset (ParsePtr p);
|
||||||
int DoFunset (ParsePtr p);
|
int DoFunset (ParsePtr p);
|
||||||
|
void UnsetAllUserFuncs(void);
|
||||||
void ProduceCalendar (void);
|
void ProduceCalendar (void);
|
||||||
char const *SimpleTime (int tim);
|
char const *SimpleTime (int tim);
|
||||||
char const *CalendarTime (int tim, int duration);
|
char const *CalendarTime (int tim, int duration);
|
||||||
int DoRem (ParsePtr p);
|
int DoRem (ParsePtr p);
|
||||||
int DoFlush (ParsePtr p);
|
int DoFlush (ParsePtr p);
|
||||||
void DoExit (ParsePtr p);
|
void DoExit (ParsePtr p);
|
||||||
int ParseRem (ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals);
|
int ParseRem (ParsePtr s, Trigger *trig, TimeTrig *tim);
|
||||||
int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued);
|
int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued, DynamicBuffer *output);
|
||||||
int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int dse, int *err);
|
int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int dse, int *err);
|
||||||
int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse, int mode);
|
int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse, int mode);
|
||||||
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int dse, int tim);
|
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int dse, int tim);
|
||||||
int ParseLiteralDate (char const **s, int *dse, int *tim);
|
int ParseLiteralDate (char const **s, int *dse, int *tim);
|
||||||
int ParseLiteralTime (char const **s, int *tim);
|
int ParseLiteralTime (char const **s, int *tim);
|
||||||
|
expr_node *parse_expression(char const **e, int *r, Var *locals);
|
||||||
|
|
||||||
|
int evaluate_expression(expr_node *node, Value *locals, Value *ans, int *nonconst);
|
||||||
|
int evaluate_expr_node(expr_node *node, Value *locals, Value *ans, int *nonconst);
|
||||||
|
void print_expr_tree(expr_node *node, FILE *fp);
|
||||||
|
void unlimit_execution_time(void);
|
||||||
|
expr_node *free_expr_tree(expr_node *node);
|
||||||
int EvalExpr (char const **e, Value *v, ParsePtr p);
|
int EvalExpr (char const **e, Value *v, ParsePtr p);
|
||||||
int DoCoerce (char type, Value *v);
|
int DoCoerce (char type, Value *v);
|
||||||
void PrintValue (Value *v, FILE *fp);
|
char const *PrintValue (Value *v, FILE *fp);
|
||||||
int CopyValue (Value *dest, const Value *src);
|
int CopyValue (Value *dest, const Value *src);
|
||||||
int ReadLine (void);
|
int ReadLine (void);
|
||||||
int OpenFile (char const *fname);
|
int OpenFile (char const *fname);
|
||||||
@@ -62,8 +85,9 @@ 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 ParseIdentifier (ParsePtr p, DynamicBuffer *dbuf);
|
int ParseIdentifier (ParsePtr p, DynamicBuffer *dbuf);
|
||||||
|
expr_node * ParseExpr(ParsePtr p, int *r);
|
||||||
|
void print_expr_nodes_stats(void);
|
||||||
int EvaluateExpr (ParsePtr p, Value *v);
|
int EvaluateExpr (ParsePtr p, Value *v);
|
||||||
int Evaluate (char const **s, Var *locals, ParsePtr p);
|
|
||||||
int FnPopValStack (Value *val);
|
int FnPopValStack (Value *val);
|
||||||
void Eprint (char const *fmt, ...);
|
void Eprint (char const *fmt, ...);
|
||||||
void Wprint (char const *fmt, ...);
|
void Wprint (char const *fmt, ...);
|
||||||
@@ -71,7 +95,7 @@ void OutputLine (FILE *fp);
|
|||||||
void CreateParser (char const *s, ParsePtr p);
|
void CreateParser (char const *s, ParsePtr p);
|
||||||
void DestroyParser (ParsePtr p);
|
void DestroyParser (ParsePtr p);
|
||||||
int PushToken (char const *tok, ParsePtr p);
|
int PushToken (char const *tok, ParsePtr p);
|
||||||
long SystemTime (int realtime);
|
int SystemTime (int realtime);
|
||||||
int MinutesPastMidnight (int realtime);
|
int MinutesPastMidnight (int realtime);
|
||||||
int SystemDate (int *y, int *m, int *d);
|
int SystemDate (int *y, int *m, int *d);
|
||||||
int DoIf (ParsePtr p);
|
int DoIf (ParsePtr p);
|
||||||
@@ -83,10 +107,11 @@ int VerifyEoln (ParsePtr p);
|
|||||||
int DoDebug (ParsePtr p);
|
int DoDebug (ParsePtr p);
|
||||||
int DoBanner (ParsePtr p);
|
int DoBanner (ParsePtr p);
|
||||||
int DoRun (ParsePtr p);
|
int DoRun (ParsePtr p);
|
||||||
|
int DoExpr (ParsePtr p);
|
||||||
int DoErrMsg (ParsePtr p);
|
int DoErrMsg (ParsePtr p);
|
||||||
int ClearGlobalOmits (void);
|
int ClearGlobalOmits (void);
|
||||||
int DoClear (ParsePtr p);
|
int DoClear (ParsePtr p);
|
||||||
int DestroyOmitContexts (void);
|
int DestroyOmitContexts (int print_unmatched);
|
||||||
int PushOmitContext (ParsePtr p);
|
int PushOmitContext (ParsePtr p);
|
||||||
int PopOmitContext (ParsePtr p);
|
int PopOmitContext (ParsePtr p);
|
||||||
int IsOmitted (int dse, int localomit, char const *omitfunc, int *omit);
|
int IsOmitted (int dse, int localomit, char const *omitfunc, int *omit);
|
||||||
@@ -100,13 +125,26 @@ int ComputeTrigger (int today, Trigger *trig, TimeTrig *tim, int *err, int save_
|
|||||||
int ComputeTriggerNoAdjustDuration (int today, Trigger *trig, TimeTrig *tim, int *err, int save_in_globals, int duration_days);
|
int ComputeTriggerNoAdjustDuration (int today, Trigger *trig, TimeTrig *tim, int *err, int save_in_globals, int duration_days);
|
||||||
int AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int save_in_globals);
|
int AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int save_in_globals);
|
||||||
char *StrnCpy (char *dest, char const *source, int n);
|
char *StrnCpy (char *dest, char const *source, int n);
|
||||||
|
|
||||||
|
#ifndef HAVE_STRNCASECMP
|
||||||
int StrinCmp (char const *s1, char const *s2, int n);
|
int StrinCmp (char const *s1, char const *s2, int n);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_STRDUP
|
||||||
char *StrDup (char const *s);
|
char *StrDup (char const *s);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_STRCASECMP
|
||||||
int StrCmpi (char const *s1, char const *s2);
|
int StrCmpi (char const *s1, char const *s2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void strtolower(char *s);
|
||||||
|
|
||||||
Var *FindVar (char const *str, int create);
|
Var *FindVar (char const *str, int create);
|
||||||
|
SysVar *FindSysVar (char const *name);
|
||||||
int DeleteVar (char const *str);
|
int DeleteVar (char const *str);
|
||||||
int SetVar (char const *str, Value *val);
|
int SetVar (char const *str, Value const *val);
|
||||||
int GetVarValue (char const *str, Value *val, Var *locals, ParsePtr p);
|
int GetVarValue (char const *str, Value *val);
|
||||||
int DoSet (Parser *p);
|
int DoSet (Parser *p);
|
||||||
int DoUnset (Parser *p);
|
int DoUnset (Parser *p);
|
||||||
int DoDump (ParsePtr p);
|
int DoDump (ParsePtr p);
|
||||||
@@ -115,14 +153,14 @@ void DestroyVars (int all);
|
|||||||
int PreserveVar (char const *name);
|
int PreserveVar (char const *name);
|
||||||
int DoPreserve (Parser *p);
|
int DoPreserve (Parser *p);
|
||||||
int DoSatRemind (Trigger *trig, TimeTrig *tt, ParsePtr p);
|
int DoSatRemind (Trigger *trig, TimeTrig *tt, ParsePtr p);
|
||||||
int DoMsgCommand (char const *cmd, char const *msg);
|
int DoMsgCommand (char const *cmd, char const *msg, int is_queued);
|
||||||
int ParseNonSpaceChar (ParsePtr p, int *err, int peek);
|
int ParseNonSpaceChar (ParsePtr p, int *err, int peek);
|
||||||
unsigned int HashVal (char const *str);
|
unsigned int HashVal (char const *str);
|
||||||
int DateOK (int y, int m, int d);
|
int DateOK (int y, int m, int d);
|
||||||
Operator *FindOperator (char const *name, Operator where[], int num);
|
BuiltinFunc *FindBuiltinFunc (char const *name);
|
||||||
BuiltinFunc *FindFunc (char const *name, BuiltinFunc where[], int num);
|
|
||||||
int InsertIntoSortBuffer (int dse, int tim, char const *body, int typ, int prio);
|
int InsertIntoSortBuffer (int dse, int tim, char const *body, int typ, int prio);
|
||||||
void IssueSortedReminders (void);
|
void IssueSortedReminders (void);
|
||||||
|
UserFunc *FindUserFunc(char const *name);
|
||||||
int UserFuncExists (char const *fn);
|
int UserFuncExists (char const *fn);
|
||||||
void DSEToHeb (int dse, int *hy, int *hm, int *hd);
|
void DSEToHeb (int dse, int *hy, int *hm, int *hd);
|
||||||
int HebNameToNum (char const *mname);
|
int HebNameToNum (char const *mname);
|
||||||
@@ -139,7 +177,7 @@ int GetSysVar (char const *name, Value *val);
|
|||||||
int SetSysVar (char const *name, Value *val);
|
int SetSysVar (char const *name, Value *val);
|
||||||
void DumpSysVarByName (char const *name);
|
void DumpSysVarByName (char const *name);
|
||||||
int CalcMinsFromUTC (int dse, int tim, int *mins, int *isdst);
|
int CalcMinsFromUTC (int dse, int tim, int *mins, int *isdst);
|
||||||
void FillParagraph (char const *s);
|
void FillParagraph (char const *s, DynamicBuffer *output);
|
||||||
void LocalToUTC (int locdate, int loctime, int *utcdate, int *utctime);
|
void LocalToUTC (int locdate, int loctime, int *utcdate, int *utctime);
|
||||||
void UTCToLocal (int utcdate, int utctime, int *locdate, int *loctime);
|
void UTCToLocal (int utcdate, int utctime, int *locdate, int *loctime);
|
||||||
int MoonPhase (int date, int time);
|
int MoonPhase (int date, int time);
|
||||||
@@ -165,23 +203,39 @@ void PrintJSONKeyPairString(char const *name, char const *val);
|
|||||||
void PrintJSONKeyPairDate(char const *name, int dse);
|
void PrintJSONKeyPairDate(char const *name, int dse);
|
||||||
void PrintJSONKeyPairDateTime(char const *name, int dt);
|
void PrintJSONKeyPairDateTime(char const *name, int dt);
|
||||||
void PrintJSONKeyPairTime(char const *name, int t);
|
void PrintJSONKeyPairTime(char const *name, int t);
|
||||||
void System(char const *cmd);
|
void System(char const *cmd, int queued);
|
||||||
int ShellEscape(char const *in, DynamicBuffer *out);
|
int ShellEscape(char const *in, DynamicBuffer *out);
|
||||||
int AddGlobalOmit(int dse);
|
int AddGlobalOmit(int dse);
|
||||||
void set_lat_and_long_from_components(void);
|
void set_lat_and_long_from_components(void);
|
||||||
void set_components_from_lat_and_long(void);
|
void set_components_from_lat_and_long(void);
|
||||||
|
|
||||||
|
void DebugExitFunc(void);
|
||||||
|
|
||||||
|
int GetTerminalBackground(void);
|
||||||
|
|
||||||
char const *get_day_name(int wkday);
|
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);
|
||||||
int push_call(char const *filename, char const *func, int lineno);
|
int push_call(char const *filename, char const *func, int lineno);
|
||||||
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 WriteJSONTimeTrigger(TimeTrig const *tt);
|
||||||
#ifdef REM_USE_WCHAR
|
#ifdef REM_USE_WCHAR
|
||||||
#define _XOPEN_SOURCE 600
|
#define _XOPEN_SOURCE 600
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
void PutWideChar(wchar_t const wc);
|
void PutWideChar(wchar_t const wc, DynamicBuffer *output);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* These functions are in utils.c and are used to detect overflow
|
||||||
|
in various arithmetic operators. They have to be in separate
|
||||||
|
functions with extern linkage to defeat compiler optimizations
|
||||||
|
that would otherwise break the overflow checks. */
|
||||||
|
extern int _private_mul_overflow(int a, int b);
|
||||||
|
extern int _private_add_overflow(int a, int b);
|
||||||
|
extern int _private_sub_overflow(int a, int b);
|
||||||
|
|||||||
532
src/queue.c
532
src/queue.c
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -24,16 +24,33 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "expr.h"
|
|
||||||
|
#undef USE_INOTIFY
|
||||||
|
#if defined(HAVE_SYS_INOTIFY_H) && defined(HAVE_INOTIFY_INIT1)
|
||||||
|
#define USE_INOTIFY 1
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
|
||||||
|
int watch_fd = -1;
|
||||||
|
static void consume_inotify_events(int fd);
|
||||||
|
static int setup_inotify_watch(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A list of filenames associated with queued reminders */
|
||||||
|
typedef struct queuedfname {
|
||||||
|
struct queuedfname *next;
|
||||||
|
char const *fname;
|
||||||
|
} QueuedFilename;
|
||||||
|
|
||||||
|
|
||||||
/* List structure for holding queued reminders */
|
/* List structure for holding queued reminders */
|
||||||
typedef struct queuedrem {
|
typedef struct queuedrem {
|
||||||
@@ -42,16 +59,19 @@ typedef struct queuedrem {
|
|||||||
int RunDisabled;
|
int RunDisabled;
|
||||||
int ntrig;
|
int ntrig;
|
||||||
char const *text;
|
char const *text;
|
||||||
|
char const *fname;
|
||||||
|
int lineno;
|
||||||
char passthru[PASSTHRU_LEN+1];
|
char passthru[PASSTHRU_LEN+1];
|
||||||
char sched[VAR_NAME_LEN+1];
|
char sched[VAR_NAME_LEN+1];
|
||||||
DynamicBuffer tags;
|
|
||||||
Trigger t;
|
Trigger t;
|
||||||
TimeTrig tt;
|
TimeTrig tt;
|
||||||
|
int red, green, blue;
|
||||||
} QueuedRem;
|
} QueuedRem;
|
||||||
|
|
||||||
/* Global variables */
|
/* Global variables */
|
||||||
|
|
||||||
static QueuedRem *QueueHead;
|
static QueuedRem *QueueHead = NULL;
|
||||||
|
static QueuedFilename *Files = NULL;
|
||||||
static time_t FileModTime;
|
static time_t FileModTime;
|
||||||
static struct stat StatBuf;
|
static struct stat StatBuf;
|
||||||
|
|
||||||
@@ -59,9 +79,108 @@ static void CheckInitialFile (void);
|
|||||||
static int CalculateNextTime (QueuedRem *q);
|
static int CalculateNextTime (QueuedRem *q);
|
||||||
static QueuedRem *FindNextReminder (void);
|
static QueuedRem *FindNextReminder (void);
|
||||||
static int CalculateNextTimeUsingSched (QueuedRem *q);
|
static int CalculateNextTimeUsingSched (QueuedRem *q);
|
||||||
static void DaemonWait (struct timeval *sleep_tv);
|
static void ServerWait (struct timeval *sleep_tv);
|
||||||
static void reread (void);
|
static void reread (void);
|
||||||
static void PrintQueue(void);
|
static void PrintQueue(void);
|
||||||
|
static char const *QueueFilename(char const *fname);
|
||||||
|
|
||||||
|
static void chomp(DynamicBuffer *buf)
|
||||||
|
{
|
||||||
|
char *s = DBufValue(buf);
|
||||||
|
int l = DBufLen(buf);
|
||||||
|
while (l) {
|
||||||
|
if (s[l-1] == '\n') {
|
||||||
|
s[l-1] = 0;
|
||||||
|
DBufLen(buf)--;
|
||||||
|
l--;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char const *SimpleTimeNoSpace(int tim)
|
||||||
|
{
|
||||||
|
char *s = (char *) SimpleTime(tim);
|
||||||
|
if (s && *s) {
|
||||||
|
size_t l = strlen(s);
|
||||||
|
if (l > 0 && s[l-1] == ' ') {
|
||||||
|
s[l-1] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* QueueFilename */
|
||||||
|
/* */
|
||||||
|
/* Add fname to the list of queued filenames if it's not */
|
||||||
|
/* already present. Either way, return a pointer to the */
|
||||||
|
/* filename. Returns NULL if out of memory */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
static QueuedFilename *last_file_found = NULL;
|
||||||
|
static char const *QueueFilename(char const *fname)
|
||||||
|
{
|
||||||
|
QueuedFilename *elem = Files;
|
||||||
|
|
||||||
|
/* Optimization: We are very likely in the same file as
|
||||||
|
before... */
|
||||||
|
if (last_file_found && !strcmp(fname, last_file_found->fname)) {
|
||||||
|
return last_file_found->fname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No such luck; search the list */
|
||||||
|
while(elem) {
|
||||||
|
if (!strcmp(elem->fname, fname)) {
|
||||||
|
last_file_found = elem;
|
||||||
|
return elem->fname;
|
||||||
|
}
|
||||||
|
elem = elem->next;
|
||||||
|
}
|
||||||
|
/* Not found... queue it */
|
||||||
|
elem = NEW(QueuedFilename);
|
||||||
|
if (!elem) return NULL;
|
||||||
|
elem->fname = StrDup(fname);
|
||||||
|
if (!elem->fname) {
|
||||||
|
free(elem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
elem->next = Files;
|
||||||
|
Files = elem;
|
||||||
|
last_file_found = elem;
|
||||||
|
return elem->fname;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void del_reminder(QueuedRem *qid)
|
||||||
|
{
|
||||||
|
QueuedRem *q = QueueHead;
|
||||||
|
QueuedRem *next;
|
||||||
|
if (!q) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (q == qid) {
|
||||||
|
QueueHead = q->next;
|
||||||
|
if (q->text) free((void *) q->text);
|
||||||
|
free(q);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while(q->next) {
|
||||||
|
next = q->next;
|
||||||
|
if (q->next == qid) {
|
||||||
|
q->next = q->next->next;
|
||||||
|
if (next->text) free((void *) next->text);
|
||||||
|
free(next);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void del_reminder_ul(unsigned long qid) {
|
||||||
|
del_reminder((QueuedRem *) qid);
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
@@ -72,7 +191,7 @@ static void PrintQueue(void);
|
|||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int QueueReminder(ParsePtr p, Trigger *trig,
|
int QueueReminder(ParsePtr p, Trigger *trig,
|
||||||
TimeTrig *tim, char const *sched)
|
TimeTrig *tim, char const *sched)
|
||||||
{
|
{
|
||||||
QueuedRem *qelem;
|
QueuedRem *qelem;
|
||||||
|
|
||||||
@@ -87,26 +206,36 @@ int QueueReminder(ParsePtr p, Trigger *trig,
|
|||||||
if (!qelem) {
|
if (!qelem) {
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
|
qelem->red = DefaultColorR;
|
||||||
|
qelem->green = DefaultColorG;
|
||||||
|
qelem->blue = DefaultColorB;
|
||||||
qelem->text = StrDup(p->pos); /* Guaranteed that parser is not nested. */
|
qelem->text = StrDup(p->pos); /* Guaranteed that parser is not nested. */
|
||||||
if (!qelem->text) {
|
if (!qelem->text) {
|
||||||
free(qelem);
|
free(qelem);
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
|
qelem->fname = QueueFilename(FileName);
|
||||||
|
if (!qelem->fname) {
|
||||||
|
free((void *) qelem->text);
|
||||||
|
free(qelem);
|
||||||
|
return E_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
qelem->lineno = LineNo;
|
||||||
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;
|
||||||
DBufInit(&(qelem->t.tags));
|
DBufInit(&(qelem->t.tags));
|
||||||
|
DBufPuts(&(qelem->t.tags), DBufValue(&(trig->tags)));
|
||||||
|
if (SynthesizeTags) {
|
||||||
|
AppendTag(&(qelem->t.tags), SynthesizeTag());
|
||||||
|
}
|
||||||
qelem->next = QueueHead;
|
qelem->next = QueueHead;
|
||||||
qelem->RunDisabled = RunDisabled;
|
qelem->RunDisabled = RunDisabled;
|
||||||
qelem->ntrig = 0;
|
qelem->ntrig = 0;
|
||||||
strcpy(qelem->sched, sched);
|
strcpy(qelem->sched, sched);
|
||||||
DBufInit(&(qelem->tags));
|
|
||||||
DBufPuts(&(qelem->tags), DBufValue(&(trig->tags)));
|
|
||||||
if (SynthesizeTags) {
|
|
||||||
AppendTag(&(qelem->tags), SynthesizeTag());
|
|
||||||
}
|
|
||||||
QueueHead = qelem;
|
QueueHead = qelem;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -141,6 +270,28 @@ SigContHandler(int d)
|
|||||||
UNUSED(d);
|
UNUSED(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_num_queued(void)
|
||||||
|
{
|
||||||
|
int nqueued = 0;
|
||||||
|
QueuedRem *q = QueueHead;
|
||||||
|
while(q) {
|
||||||
|
if (q->tt.nexttime != NO_TIME) {
|
||||||
|
nqueued++;
|
||||||
|
}
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
if (DaemonJSON) {
|
||||||
|
printf("{");
|
||||||
|
PrintJSONKeyPairString("response", "queued");
|
||||||
|
PrintJSONKeyPairInt("nqueued", nqueued);
|
||||||
|
printf("\"command\":\"STATUS\"}\n");
|
||||||
|
} else {
|
||||||
|
printf("NOTE queued %d\n", nqueued);
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* HandleQueuedReminders */
|
/* HandleQueuedReminders */
|
||||||
@@ -154,17 +305,26 @@ void HandleQueuedReminders(void)
|
|||||||
int TimeToSleep;
|
int TimeToSleep;
|
||||||
unsigned SleepTime;
|
unsigned SleepTime;
|
||||||
Parser p;
|
Parser p;
|
||||||
Trigger trig;
|
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
struct timeval sleep_tv;
|
struct timeval sleep_tv;
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
char qid[64];
|
||||||
|
|
||||||
/* Suppress the BANNER from being issued */
|
/* Disable any potential pending SIGALRMs */
|
||||||
DidMsgReminder = 1;
|
alarm(0);
|
||||||
|
|
||||||
|
/* Un-limit execution time */
|
||||||
|
unlimit_execution_time();
|
||||||
|
|
||||||
/* Turn off sorting -- otherwise, TriggerReminder has no effect! */
|
/* Turn off sorting -- otherwise, TriggerReminder has no effect! */
|
||||||
SortByDate = 0;
|
SortByDate = 0;
|
||||||
|
|
||||||
|
/* Free FileName if necessary */
|
||||||
|
if (FileName) {
|
||||||
|
free(FileName);
|
||||||
|
FileName = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* If we are not connected to a tty, then we must close the
|
/* If we are not connected to a tty, then we must close the
|
||||||
* standard file descriptors. This is to prevent someone
|
* standard file descriptors. This is to prevent someone
|
||||||
* doing:
|
* doing:
|
||||||
@@ -174,7 +334,7 @@ void HandleQueuedReminders(void)
|
|||||||
* processed correctly are RUN commands, provided they mail
|
* processed correctly are RUN commands, provided they mail
|
||||||
* the result back or use their own resource (as a window).
|
* the result back or use their own resource (as a window).
|
||||||
*/
|
*/
|
||||||
if (!DontFork) {
|
if (ShouldFork) {
|
||||||
maybe_close(STDIN_FILENO);
|
maybe_close(STDIN_FILENO);
|
||||||
maybe_close(STDOUT_FILENO);
|
maybe_close(STDOUT_FILENO);
|
||||||
maybe_close(STDERR_FILENO);
|
maybe_close(STDERR_FILENO);
|
||||||
@@ -197,14 +357,18 @@ void HandleQueuedReminders(void)
|
|||||||
q = q->next;
|
q = q->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DontFork || Daemon) {
|
if (ShouldFork || Daemon) {
|
||||||
sa.sa_handler = SigIntHandler;
|
sa.sa_handler = SigIntHandler;
|
||||||
sa.sa_flags = 0;
|
sa.sa_flags = SA_RESTART;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
(void) sigaction(SIGINT, &sa, NULL);
|
(void) sigaction(SIGINT, &sa, NULL);
|
||||||
sa.sa_handler = SigContHandler;
|
sa.sa_handler = SigContHandler;
|
||||||
(void) sigaction(SIGCONT, &sa, NULL);
|
(void) sigaction(SIGCONT, &sa, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_INOTIFY
|
||||||
|
watch_fd = setup_inotify_watch();
|
||||||
|
#endif
|
||||||
/* Sit in a loop, issuing reminders when necessary */
|
/* Sit in a loop, issuing reminders when necessary */
|
||||||
while(1) {
|
while(1) {
|
||||||
q = FindNextReminder();
|
q = FindNextReminder();
|
||||||
@@ -213,7 +377,7 @@ void HandleQueuedReminders(void)
|
|||||||
if (!q && !Daemon) break;
|
if (!q && !Daemon) break;
|
||||||
|
|
||||||
if (Daemon && !q) {
|
if (Daemon && !q) {
|
||||||
if (Daemon < 0) {
|
if (IsServerMode()) {
|
||||||
/* Sleep until midnight */
|
/* Sleep until midnight */
|
||||||
TimeToSleep = MINUTES_PER_DAY*60 - SystemTime(1);
|
TimeToSleep = MINUTES_PER_DAY*60 - SystemTime(1);
|
||||||
} else {
|
} else {
|
||||||
@@ -230,9 +394,7 @@ void HandleQueuedReminders(void)
|
|||||||
SleepTime = 60*Daemon;
|
SleepTime = 60*Daemon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wake up once a minute to recalibrate sleep time in
|
if (IsServerMode()) {
|
||||||
case of laptop hibernation */
|
|
||||||
if (Daemon < 0) {
|
|
||||||
/* Wake up on the next exact minute */
|
/* Wake up on the next exact minute */
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
sleep_tv.tv_sec = 60 - (tv.tv_sec % 60);
|
sleep_tv.tv_sec = 60 - (tv.tv_sec % 60);
|
||||||
@@ -242,7 +404,9 @@ void HandleQueuedReminders(void)
|
|||||||
} else {
|
} else {
|
||||||
sleep_tv.tv_usec = 0;
|
sleep_tv.tv_usec = 0;
|
||||||
}
|
}
|
||||||
DaemonWait(&sleep_tv);
|
ServerWait(&sleep_tv);
|
||||||
|
/* A DEL command might have deleted our queued reminder! */
|
||||||
|
q = FindNextReminder();
|
||||||
} else {
|
} else {
|
||||||
sleep(SleepTime);
|
sleep(SleepTime);
|
||||||
}
|
}
|
||||||
@@ -260,10 +424,12 @@ void HandleQueuedReminders(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Daemon > 0 && SleepTime) CheckInitialFile();
|
if (Daemon > 0 && SleepTime) {
|
||||||
|
CheckInitialFile();
|
||||||
|
}
|
||||||
|
|
||||||
if (Daemon && !q) {
|
if (Daemon && !q) {
|
||||||
if (Daemon < 0) {
|
if (IsServerMode()) {
|
||||||
/* Sleep until midnight */
|
/* Sleep until midnight */
|
||||||
TimeToSleep = MINUTES_PER_DAY*60 - SystemTime(1);
|
TimeToSleep = MINUTES_PER_DAY*60 - SystemTime(1);
|
||||||
} else {
|
} else {
|
||||||
@@ -286,25 +452,52 @@ void HandleQueuedReminders(void)
|
|||||||
(MaxLateMinutes == 0 || SystemTime(1) - (q->tt.nexttime * 60) <= 60 * MaxLateMinutes))) {
|
(MaxLateMinutes == 0 || SystemTime(1) - (q->tt.nexttime * 60) <= 60 * MaxLateMinutes))) {
|
||||||
/* Trigger the reminder */
|
/* Trigger the reminder */
|
||||||
CreateParser(q->text, &p);
|
CreateParser(q->text, &p);
|
||||||
trig.typ = q->typ;
|
|
||||||
strcpy(trig.passthru, q->passthru);
|
|
||||||
RunDisabled = q->RunDisabled;
|
RunDisabled = q->RunDisabled;
|
||||||
if (Daemon < 0) {
|
if (IsServerMode() && q->typ != RUN_TYPE) {
|
||||||
printf("NOTE reminder %s",
|
if (DaemonJSON) {
|
||||||
SimpleTime(q->tt.ttime));
|
printf("{\"response\":\"reminder\",");
|
||||||
printf("%s", SimpleTime(MinutesPastMidnight(1)));
|
snprintf(qid, sizeof(qid), "%lx", (unsigned long) q);
|
||||||
if (!*DBufValue(&q->tags)) {
|
PrintJSONKeyPairString("qid", qid);
|
||||||
printf("*\n");
|
PrintJSONKeyPairString("ttime", SimpleTimeNoSpace(q->tt.ttime));
|
||||||
} else {
|
PrintJSONKeyPairString("now", SimpleTimeNoSpace(MinutesPastMidnight(1)));
|
||||||
printf("%s\n", DBufValue(&(q->tags)));
|
PrintJSONKeyPairString("tags", DBufValue(&q->t.tags));
|
||||||
}
|
} else {
|
||||||
|
printf("NOTE reminder %s",
|
||||||
|
SimpleTime(q->tt.ttime));
|
||||||
|
printf("%s", SimpleTime(MinutesPastMidnight(1)));
|
||||||
|
if (!*DBufValue(&q->t.tags)) {
|
||||||
|
printf("*\n");
|
||||||
|
} else {
|
||||||
|
printf("%s\n", DBufValue(&(q->t.tags)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up global variables so some functions like trigdate()
|
/* Set up global variables so some functions like trigdate()
|
||||||
and trigtime() work correctly */
|
and trigtime() work correctly */
|
||||||
SaveAllTriggerInfo(&(q->t), &(q->tt), DSEToday, q->tt.ttime, 1);
|
SaveAllTriggerInfo(&(q->t), &(q->tt), DSEToday, q->tt.ttime, 1);
|
||||||
(void) TriggerReminder(&p, &trig, &q->tt, DSEToday, 1);
|
FileName = (char *) q->fname;
|
||||||
if (Daemon < 0) {
|
DefaultColorR = q->red;
|
||||||
|
DefaultColorG = q->green;
|
||||||
|
DefaultColorB = q->blue;
|
||||||
|
/* Make a COPY of q->t because TriggerReminder can change q->t.typ */
|
||||||
|
Trigger tcopy = q->t;
|
||||||
|
if (DaemonJSON) {
|
||||||
|
DynamicBuffer out;
|
||||||
|
DBufInit(&out);
|
||||||
|
(void) TriggerReminder(&p, &tcopy, &q->tt, DSEToday, 1, &out);
|
||||||
|
if (q->typ != RUN_TYPE) {
|
||||||
|
printf("\"body\":\"");
|
||||||
|
chomp(&out);
|
||||||
|
PrintJSONString(DBufValue(&out));
|
||||||
|
printf("\"}\n");
|
||||||
|
}
|
||||||
|
DBufFree(&out);
|
||||||
|
} else {
|
||||||
|
(void) TriggerReminder(&p, &tcopy, &q->tt, DSEToday, 1, NULL);
|
||||||
|
}
|
||||||
|
FileName = NULL;
|
||||||
|
if (IsServerMode() && !DaemonJSON && q->typ != RUN_TYPE) {
|
||||||
printf("NOTE endreminder\n");
|
printf("NOTE endreminder\n");
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@@ -314,14 +507,23 @@ void HandleQueuedReminders(void)
|
|||||||
/* Calculate the next trigger time */
|
/* Calculate the next trigger time */
|
||||||
q->tt.nexttime = CalculateNextTime(q);
|
q->tt.nexttime = CalculateNextTime(q);
|
||||||
|
|
||||||
/* If trigger time is way in the past because computer has been
|
|
||||||
suspended or hibernated, remove from queue */
|
|
||||||
if (q->tt.nexttime != NO_TIME) {
|
if (q->tt.nexttime != NO_TIME) {
|
||||||
|
/* If trigger time is way in the past because computer has been
|
||||||
|
suspended or hibernated, remove from queue */
|
||||||
if (q->tt.ttime < MinutesPastMidnight(1) - MaxLateMinutes &&
|
if (q->tt.ttime < MinutesPastMidnight(1) - MaxLateMinutes &&
|
||||||
q->tt.nexttime < MinutesPastMidnight(1) - MaxLateMinutes) {
|
q->tt.nexttime < MinutesPastMidnight(1) - MaxLateMinutes) {
|
||||||
q->tt.nexttime = NO_TIME;
|
q->tt.nexttime = NO_TIME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If queued reminder has expired, actually remove it from queue
|
||||||
|
and update status */
|
||||||
|
if (q->tt.nexttime == NO_TIME) {
|
||||||
|
del_reminder(q);
|
||||||
|
if (IsServerMode()) {
|
||||||
|
print_num_queued();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
@@ -441,7 +643,25 @@ static void CheckInitialFile(void)
|
|||||||
/* If date has rolled around, or file has changed, spawn a new version. */
|
/* If date has rolled around, or file has changed, spawn a new version. */
|
||||||
time_t tim = FileModTime;
|
time_t tim = FileModTime;
|
||||||
int y, m, d;
|
int y, m, d;
|
||||||
|
#ifdef USE_INOTIFY
|
||||||
|
char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
|
||||||
|
int n;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_INOTIFY
|
||||||
|
/* If there are any inotify events, reread */
|
||||||
|
if (watch_fd >= 0) {
|
||||||
|
while(1) {
|
||||||
|
n = read(watch_fd, buf, sizeof(buf));
|
||||||
|
if (n < 0 && errno == EINTR) continue;
|
||||||
|
if (n > 0) {
|
||||||
|
close(watch_fd);
|
||||||
|
reread();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (stat(InitialFile, &StatBuf) == 0) tim = StatBuf.st_mtime;
|
if (stat(InitialFile, &StatBuf) == 0) tim = StatBuf.st_mtime;
|
||||||
if (tim != FileModTime ||
|
if (tim != FileModTime ||
|
||||||
RealToday != SystemDate(&y, &m, &d)) {
|
RealToday != SystemDate(&y, &m, &d)) {
|
||||||
@@ -519,7 +739,11 @@ static void
|
|||||||
json_queue(QueuedRem const *q)
|
json_queue(QueuedRem const *q)
|
||||||
{
|
{
|
||||||
int done = 0;
|
int done = 0;
|
||||||
|
if (DaemonJSON) {
|
||||||
|
printf("{\"response\":\"queue\",\"queue\":");
|
||||||
|
}
|
||||||
printf("[");
|
printf("[");
|
||||||
|
char idbuf[64];
|
||||||
while(q) {
|
while(q) {
|
||||||
if (q->tt.nexttime == NO_TIME) {
|
if (q->tt.nexttime == NO_TIME) {
|
||||||
q = q->next;
|
q = q->next;
|
||||||
@@ -530,6 +754,14 @@ json_queue(QueuedRem const *q)
|
|||||||
}
|
}
|
||||||
done = 1;
|
done = 1;
|
||||||
printf("{");
|
printf("{");
|
||||||
|
WriteJSONTrigger(&(q->t), 1, DSEToday);
|
||||||
|
WriteJSONTimeTrigger(&(q->tt));
|
||||||
|
snprintf(idbuf, sizeof(idbuf), "%lx", (unsigned long) q);
|
||||||
|
PrintJSONKeyPairString("qid", idbuf);
|
||||||
|
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
|
||||||
|
PrintJSONKeyPairInt("ntrig", q->ntrig);
|
||||||
|
PrintJSONKeyPairString("filename", q->fname);
|
||||||
|
PrintJSONKeyPairInt("lineno", q->lineno);
|
||||||
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;
|
||||||
@@ -539,29 +771,12 @@ json_queue(QueuedRem const *q)
|
|||||||
case PS_TYPE: PrintJSONKeyPairString("type", "PS_TYPE"); break;
|
case PS_TYPE: PrintJSONKeyPairString("type", "PS_TYPE"); break;
|
||||||
case PSF_TYPE: PrintJSONKeyPairString("type", "PSF_TYPE"); break;
|
case PSF_TYPE: PrintJSONKeyPairString("type", "PSF_TYPE"); break;
|
||||||
case MSF_TYPE: PrintJSONKeyPairString("type", "MSF_TYPE"); break;
|
case MSF_TYPE: PrintJSONKeyPairString("type", "MSF_TYPE"); break;
|
||||||
case PASSTHRU_TYPE: PrintJSONKeyPairString("type", "PASSTHRU_TYPE"); break;
|
case PASSTHRU_TYPE:
|
||||||
|
PrintJSONKeyPairString("type", "PASSTHRU_TYPE");
|
||||||
|
PrintJSONKeyPairString("passthru", q->passthru);
|
||||||
|
break;
|
||||||
default: PrintJSONKeyPairString("type", "?"); break;
|
default: PrintJSONKeyPairString("type", "?"); break;
|
||||||
}
|
}
|
||||||
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
|
|
||||||
PrintJSONKeyPairInt("ntrig", q->ntrig);
|
|
||||||
PrintJSONKeyPairTime("ttime", q->tt.ttime);
|
|
||||||
PrintJSONKeyPairTime("nextttime", q->tt.nexttime);
|
|
||||||
PrintJSONKeyPairInt("delta", q->tt.delta);
|
|
||||||
if (q->tt.rep != NO_TIME) {
|
|
||||||
PrintJSONKeyPairInt("rep", q->tt.rep);
|
|
||||||
}
|
|
||||||
if (q->tt.duration != NO_TIME) {
|
|
||||||
PrintJSONKeyPairInt("duration", q->tt.duration);
|
|
||||||
}
|
|
||||||
if (q->passthru[0]) {
|
|
||||||
PrintJSONKeyPairString("passthru", q->passthru);
|
|
||||||
}
|
|
||||||
if (q->sched[0]) {
|
|
||||||
PrintJSONKeyPairString("sched", q->sched);
|
|
||||||
}
|
|
||||||
if (DBufLen(&(q->tags))) {
|
|
||||||
PrintJSONKeyPairString("tags", DBufValue(&(q->tags)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Last one is a special case - no trailing comma */
|
/* Last one is a special case - no trailing comma */
|
||||||
printf("\"");
|
printf("\"");
|
||||||
@@ -575,30 +790,48 @@ json_queue(QueuedRem const *q)
|
|||||||
printf("\"}");
|
printf("\"}");
|
||||||
q = q->next;
|
q = q->next;
|
||||||
}
|
}
|
||||||
printf("]\n");
|
printf("]");
|
||||||
|
if (DaemonJSON) {
|
||||||
|
printf(",\"command\":\"QUEUE\"}\n");
|
||||||
|
} else {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* DaemonWait */
|
/* ServerWait */
|
||||||
/* */
|
/* */
|
||||||
/* Sleep or read command from stdin in "daemon -1" mode */
|
/* Sleep or read command from stdin in server mode */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static void DaemonWait(struct timeval *sleep_tv)
|
static void ServerWait(struct timeval *sleep_tv)
|
||||||
{
|
{
|
||||||
fd_set readSet;
|
fd_set readSet;
|
||||||
int retval;
|
int retval;
|
||||||
int y, m, d;
|
int y, m, d;
|
||||||
|
int max = 1;
|
||||||
char cmdLine[256];
|
char cmdLine[256];
|
||||||
|
|
||||||
FD_ZERO(&readSet);
|
FD_ZERO(&readSet);
|
||||||
FD_SET(0, &readSet);
|
FD_SET(0, &readSet);
|
||||||
retval = select(1, &readSet, NULL, NULL, sleep_tv);
|
|
||||||
|
#ifdef USE_INOTIFY
|
||||||
|
if (watch_fd >= 0) {
|
||||||
|
FD_SET(watch_fd, &readSet);
|
||||||
|
if (watch_fd > max-1)
|
||||||
|
max = watch_fd+1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
retval = select(max, &readSet, NULL, NULL, sleep_tv);
|
||||||
|
|
||||||
/* If date has rolled around, restart */
|
/* If date has rolled around, restart */
|
||||||
if (RealToday != SystemDate(&y, &m, &d)) {
|
if (RealToday != SystemDate(&y, &m, &d)) {
|
||||||
printf("NOTE newdate\nNOTE reread\n");
|
if (DaemonJSON) {
|
||||||
|
printf("{\"response\":\"newdate\"}\n{\"response\":\"reread\",\"command\":\"newdate\"}\n");
|
||||||
|
} else {
|
||||||
|
printf("NOTE newdate\nNOTE reread\n");
|
||||||
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
reread();
|
reread();
|
||||||
}
|
}
|
||||||
@@ -606,6 +839,24 @@ static void DaemonWait(struct timeval *sleep_tv)
|
|||||||
/* If nothing readable or interrupted system call, return */
|
/* If nothing readable or interrupted system call, return */
|
||||||
if (retval <= 0) return;
|
if (retval <= 0) return;
|
||||||
|
|
||||||
|
/* If inotify watch descriptor is readable, handle it */
|
||||||
|
#ifdef USE_INOTIFY
|
||||||
|
if (watch_fd >= 0) {
|
||||||
|
if (FD_ISSET(watch_fd, &readSet)) {
|
||||||
|
consume_inotify_events(watch_fd);
|
||||||
|
if (DaemonJSON) {
|
||||||
|
printf("{\"response\":\"reread\",\"command\":\"inotify\"}\n");
|
||||||
|
} else {
|
||||||
|
/* In deprecated server mode, we need to spit out
|
||||||
|
a NOTE newdate to force the front-end to redraw
|
||||||
|
the calendar */
|
||||||
|
printf("NOTE newdate\nNOTE reread\n");
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
reread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/* If stdin not readable, return */
|
/* If stdin not readable, return */
|
||||||
if (!FD_ISSET(0, &readSet)) return;
|
if (!FD_ISSET(0, &readSet)) return;
|
||||||
|
|
||||||
@@ -622,54 +873,74 @@ static void DaemonWait(struct timeval *sleep_tv)
|
|||||||
if (!strcmp(cmdLine, "EXIT\n")) {
|
if (!strcmp(cmdLine, "EXIT\n")) {
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
} else if (!strcmp(cmdLine, "STATUS\n")) {
|
} else if (!strcmp(cmdLine, "STATUS\n")) {
|
||||||
int nqueued = 0;
|
print_num_queued();
|
||||||
QueuedRem *q = QueueHead;
|
|
||||||
while(q) {
|
|
||||||
if (q->tt.nexttime != NO_TIME) {
|
|
||||||
nqueued++;
|
|
||||||
}
|
|
||||||
q = q->next;
|
|
||||||
}
|
|
||||||
printf("NOTE queued %d\n", nqueued);
|
|
||||||
fflush(stdout);
|
|
||||||
} else if (!strcmp(cmdLine, "QUEUE\n")) {
|
} else if (!strcmp(cmdLine, "QUEUE\n")) {
|
||||||
printf("NOTE queue\n");
|
if (DaemonJSON) {
|
||||||
QueuedRem *q = QueueHead;
|
json_queue(QueueHead);
|
||||||
while (q) {
|
} else {
|
||||||
if (q->tt.nexttime != NO_TIME) {
|
printf("NOTE queue\n");
|
||||||
switch (q->typ) {
|
QueuedRem *q = QueueHead;
|
||||||
case NO_TYPE: printf("NO_TYPE "); break;
|
while (q) {
|
||||||
case MSG_TYPE: printf("MSG_TYPE "); break;
|
if (q->tt.nexttime != NO_TIME) {
|
||||||
case RUN_TYPE: printf("RUN_TYPE "); break;
|
switch (q->typ) {
|
||||||
case CAL_TYPE: printf("CAL_TYPE "); break;
|
case NO_TYPE: printf("NO_TYPE"); break;
|
||||||
case SAT_TYPE: printf("SAT_TYPE "); break;
|
case MSG_TYPE: printf("MSG_TYPE"); break;
|
||||||
case PS_TYPE: printf("PS_TYPE "); break;
|
case RUN_TYPE: printf("RUN_TYPE"); break;
|
||||||
case PSF_TYPE: printf("PSF_TYPE "); break;
|
case CAL_TYPE: printf("CAL_TYPE"); break;
|
||||||
case MSF_TYPE: printf("MSF_TYPE "); break;
|
case SAT_TYPE: printf("SAT_TYPE"); break;
|
||||||
case PASSTHRU_TYPE: printf("PASSTHRU_TYPE "); break;
|
case PS_TYPE: printf("PS_TYPE"); break;
|
||||||
default: printf("? "); break;
|
case PSF_TYPE: printf("PSF_TYPE"); break;
|
||||||
}
|
case MSF_TYPE: printf("MSF_TYPE"); break;
|
||||||
printf("RunDisabled=%d ntrig=%d ttime=%02d:%02d nexttime=%02d:%02d delta=%d rep=%d duration=%d ", q->RunDisabled, q->ntrig, q->tt.ttime/60, q->tt.ttime % 60, q->tt.nexttime / 60, q->tt.nexttime % 60, q->tt.delta, (q->tt.rep != NO_TIME ? q->tt.rep : -1), (q->tt.duration != NO_TIME ? q->tt.duration : -1));
|
case PASSTHRU_TYPE: printf("PASSTHRU_TYPE"); break;
|
||||||
printf("%s %s %s\n",
|
default: printf("?"); break;
|
||||||
(q->passthru[0] ? q->passthru : "*"),
|
}
|
||||||
(q->sched[0] ? q->sched : "*"),
|
printf(" RunDisabled=%d ntrig=%d ttime=%02d:%02d nexttime=%02d:%02d delta=%d rep=%d duration=%d ", q->RunDisabled, q->ntrig, q->tt.ttime/60, q->tt.ttime % 60, q->tt.nexttime / 60, q->tt.nexttime % 60, q->tt.delta, (q->tt.rep != NO_TIME ? q->tt.rep : -1), (q->tt.duration != NO_TIME ? q->tt.duration : -1));
|
||||||
q->text ? q->text : "NULL");
|
printf("%s %s %s\n",
|
||||||
|
(q->passthru[0] ? q->passthru : "*"),
|
||||||
|
(q->sched[0] ? q->sched : "*"),
|
||||||
|
q->text ? q->text : "NULL");
|
||||||
|
}
|
||||||
|
q = q->next;
|
||||||
}
|
}
|
||||||
q = q->next;
|
printf("NOTE endqueue\n");
|
||||||
}
|
}
|
||||||
printf("NOTE endqueue\n");
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
} else if (!strcmp(cmdLine, "JSONQUEUE\n")) {
|
} else if (!strcmp(cmdLine, "JSONQUEUE\n")) {
|
||||||
printf("NOTE JSONQUEUE\n");
|
if (!DaemonJSON) {
|
||||||
|
printf("NOTE JSONQUEUE\n");
|
||||||
|
}
|
||||||
json_queue(QueueHead);
|
json_queue(QueueHead);
|
||||||
printf("NOTE ENDJSONQUEUE\n");
|
if (!DaemonJSON) {
|
||||||
|
printf("NOTE ENDJSONQUEUE\n");
|
||||||
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
} else if (!strcmp(cmdLine, "REREAD\n")) {
|
} else if (!strcmp(cmdLine, "REREAD\n")) {
|
||||||
printf("NOTE reread\n");
|
if (DaemonJSON) {
|
||||||
|
printf("{\"response\":\"reread\",\"command\":\"REREAD\"}\n");
|
||||||
|
} else {
|
||||||
|
printf("NOTE reread\n");
|
||||||
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
reread();
|
reread();
|
||||||
|
} else if (!strncmp(cmdLine, "DEL ", 4)) {
|
||||||
|
unsigned long qid;
|
||||||
|
if (sscanf(cmdLine, "DEL %lx", &qid) == 1) {
|
||||||
|
del_reminder_ul(qid);
|
||||||
|
}
|
||||||
|
print_num_queued();
|
||||||
|
fflush(stdout);
|
||||||
} else {
|
} else {
|
||||||
printf("ERR Invalid daemon command: %s", cmdLine);
|
if (DaemonJSON) {
|
||||||
|
size_t l = strlen(cmdLine);
|
||||||
|
if (l && cmdLine[l-1] == '\n') {
|
||||||
|
cmdLine[l-1] = 0;
|
||||||
|
}
|
||||||
|
printf("{\"response\":\"error\",\"error\":\"Unknown command\",\"command\":\"");
|
||||||
|
PrintJSONString(cmdLine);
|
||||||
|
printf("\"}\n");
|
||||||
|
} else {
|
||||||
|
printf("ERR Invalid daemon command: %s", cmdLine);
|
||||||
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -686,3 +957,56 @@ static void reread(void)
|
|||||||
execvp(ArgV[0], (char **) ArgV);
|
execvp(ArgV[0], (char **) ArgV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_INOTIFY
|
||||||
|
static void consume_inotify_events(int fd)
|
||||||
|
{
|
||||||
|
char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
struct timespec sleeptime;
|
||||||
|
|
||||||
|
int slept = 0;
|
||||||
|
/* Consume all the inotify events */
|
||||||
|
while(1) {
|
||||||
|
n = read(fd, buf, sizeof(buf));
|
||||||
|
if (n > 0) {
|
||||||
|
/* Something new since we slept */
|
||||||
|
slept = 0;
|
||||||
|
}
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
if (slept) {
|
||||||
|
/* Nothing new since we slept */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
slept = 1;
|
||||||
|
/* HACK: sleep for 0.2 seconds to let multiple events queue up so we
|
||||||
|
only do a single reread */
|
||||||
|
sleeptime.tv_sec = 0;
|
||||||
|
sleeptime.tv_nsec = 200000000;
|
||||||
|
nanosleep(&sleeptime, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setup_inotify_watch(void)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* Don't inotify_watch stdin */
|
||||||
|
if (!strcmp(InitialFile, "-")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||||
|
if (fd < 0) {
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
if (inotify_add_watch(fd, InitialFile, IN_CLOSE_WRITE | IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO) < 0) {
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -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-2023 by Dianne Skoll\n\n", VERSION);
|
fprintf(stderr, "Rem2PS: Version %s Copyright 1992-2024 by Dianne Skoll\n\n", VERSION);
|
||||||
fprintf(stderr, "Generating PostScript calendar\n");
|
fprintf(stderr, "Generating PostScript calendar\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 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-2023 Dianne Skoll.",
|
"% Remind and Rem2PS are Copyright 1992-2024 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",
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "expr.h"
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
|
|
||||||
@@ -136,7 +135,7 @@ void IssueSortedReminders(void)
|
|||||||
switch(cur->typ) {
|
switch(cur->typ) {
|
||||||
case MSG_TYPE:
|
case MSG_TYPE:
|
||||||
if (MsgCommand && *MsgCommand) {
|
if (MsgCommand && *MsgCommand) {
|
||||||
DoMsgCommand(MsgCommand, cur->text);
|
DoMsgCommand(MsgCommand, cur->text, 0);
|
||||||
} else {
|
} else {
|
||||||
if (cur->trigdate != olddate) {
|
if (cur->trigdate != olddate) {
|
||||||
IssueSortBanner(cur->trigdate);
|
IssueSortBanner(cur->trigdate);
|
||||||
@@ -151,11 +150,11 @@ void IssueSortedReminders(void)
|
|||||||
IssueSortBanner(cur->trigdate);
|
IssueSortBanner(cur->trigdate);
|
||||||
olddate = cur->trigdate;
|
olddate = cur->trigdate;
|
||||||
}
|
}
|
||||||
FillParagraph(cur->text);
|
FillParagraph(cur->text, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RUN_TYPE:
|
case RUN_TYPE:
|
||||||
System(cur->text);
|
System(cur->text, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -56,6 +56,7 @@ Token TokArray[] = {
|
|||||||
{ "endif", 5, T_EndIf, 0 },
|
{ "endif", 5, T_EndIf, 0 },
|
||||||
{ "errmsg", 6, T_ErrMsg, 0 },
|
{ "errmsg", 6, T_ErrMsg, 0 },
|
||||||
{ "exit", 4, T_Exit, 0 },
|
{ "exit", 4, T_Exit, 0 },
|
||||||
|
{ "expr", 4, T_Expr, 0 },
|
||||||
{ "february", 3, T_Month, 1 },
|
{ "february", 3, T_Month, 1 },
|
||||||
{ "first", 5, T_Ordinal, 0 },
|
{ "first", 5, T_Ordinal, 0 },
|
||||||
{ "flush", 5, T_Flush, 0 },
|
{ "flush", 5, T_Flush, 0 },
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
/* 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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "expr.h"
|
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
@@ -72,7 +71,10 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
|||||||
m++;
|
m++;
|
||||||
if (m == 12) { m = 0; y++; }
|
if (m == 12) { m = 0; y++; }
|
||||||
}
|
}
|
||||||
while (trig->d > DaysInMonth(m, trig->y)) m++;
|
while (trig->d > DaysInMonth(m, y)) {
|
||||||
|
m++;
|
||||||
|
if (m == 12) { m = 0; y++; }
|
||||||
|
}
|
||||||
j = DSE(y, m, trig->d);
|
j = DSE(y, m, trig->d);
|
||||||
return j;
|
return j;
|
||||||
|
|
||||||
@@ -241,6 +243,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
|||||||
|
|
||||||
case GOT_WD+GOT_MON+GOT_YR:
|
case GOT_WD+GOT_MON+GOT_YR:
|
||||||
if (y > trig->y || (y == trig->y && m > trig->m)) return -1;
|
if (y > trig->y || (y == trig->y && m > trig->m)) return -1;
|
||||||
|
/* cppcheck-suppress knownConditionTrueFalse */
|
||||||
if (trig->y > y || (trig->y == y && trig->m > m)) {
|
if (trig->y > y || (trig->y == y && trig->m > m)) {
|
||||||
j = DSE(trig->y, trig->m, 1);
|
j = DSE(trig->y, trig->m, 1);
|
||||||
ADVANCE_TO_WD(j, trig->wd);
|
ADVANCE_TO_WD(j, trig->wd);
|
||||||
@@ -324,8 +327,11 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
start--;
|
start--;
|
||||||
|
if (start < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (iter > MaxSatIter) {
|
if (start < 0 || iter > MaxSatIter) {
|
||||||
/* omitfunc must have returned "true" too often */
|
/* omitfunc must have returned "true" too often */
|
||||||
*err = E_CANT_TRIG;
|
*err = E_CANT_TRIG;
|
||||||
return -2;
|
return -2;
|
||||||
@@ -388,6 +394,10 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
simple--;
|
simple--;
|
||||||
|
if (simple < 0) {
|
||||||
|
*err = E_CANT_TRIG;
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (iter > MaxSatIter) {
|
if (iter > MaxSatIter) {
|
||||||
*err = E_CANT_TRIG;
|
*err = E_CANT_TRIG;
|
||||||
|
|||||||
93
src/types.h
93
src/types.h
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -13,6 +13,22 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "dynbuf.h"
|
#include "dynbuf.h"
|
||||||
|
|
||||||
|
typedef struct udf_struct UserFunc;
|
||||||
|
|
||||||
|
/* Define the types of values */
|
||||||
|
#define ERR_TYPE 0
|
||||||
|
#define INT_TYPE 1
|
||||||
|
#define TIME_TYPE 2
|
||||||
|
#define DATE_TYPE 3
|
||||||
|
#define STR_TYPE 4
|
||||||
|
#define DATETIME_TYPE 5
|
||||||
|
#define SPECIAL_TYPE 6 /* Only for system variables */
|
||||||
|
#define CONST_INT_TYPE 7 /* Only for system variables */
|
||||||
|
|
||||||
|
#define BEG_OF_EXPR '['
|
||||||
|
#define END_OF_EXPR ']'
|
||||||
|
#define COMMA ','
|
||||||
|
|
||||||
/* Values */
|
/* Values */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char type;
|
char type;
|
||||||
@@ -22,29 +38,61 @@ typedef struct {
|
|||||||
} v;
|
} v;
|
||||||
} Value;
|
} Value;
|
||||||
|
|
||||||
/* Define the type of operators */
|
/* New-style expr_node structure and constants */
|
||||||
typedef struct {
|
enum expr_node_type
|
||||||
char const *name;
|
{
|
||||||
char prec;
|
N_FREE,
|
||||||
char type;
|
N_ERROR,
|
||||||
int (*func)(void);
|
N_CONSTANT,
|
||||||
} Operator;
|
N_LOCAL_VAR,
|
||||||
|
N_SHORT_VAR,
|
||||||
|
N_VARIABLE,
|
||||||
|
N_SHORT_SYSVAR,
|
||||||
|
N_SYSVAR,
|
||||||
|
N_BUILTIN_FUNC,
|
||||||
|
N_SHORT_USER_FUNC,
|
||||||
|
N_USER_FUNC,
|
||||||
|
N_OPERATOR,
|
||||||
|
};
|
||||||
|
|
||||||
/* Structure for passing in Nargs and out RetVal from functions */
|
/* Structure for passing in Nargs and out RetVal from functions */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int nargs;
|
int nargs;
|
||||||
|
Value *args;
|
||||||
Value retval;
|
Value retval;
|
||||||
} func_info;
|
} func_info;
|
||||||
|
|
||||||
|
/* Forward reference */
|
||||||
|
typedef struct expr_node_struct expr_node;
|
||||||
|
|
||||||
/* Define the type of user-functions */
|
/* Define the type of user-functions */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char const *name;
|
char const *name;
|
||||||
char minargs;
|
char minargs;
|
||||||
char maxargs;
|
char maxargs;
|
||||||
char is_constant;
|
char is_constant;
|
||||||
|
/* Old-style function calling convention */
|
||||||
int (*func)(func_info *);
|
int (*func)(func_info *);
|
||||||
|
|
||||||
|
/* New-style function calling convention */
|
||||||
|
int (*newfunc)(expr_node *node, Value *locals, Value *ans, int *nonconst);
|
||||||
} BuiltinFunc;
|
} BuiltinFunc;
|
||||||
|
|
||||||
|
#define SHORT_NAME_BUF 16
|
||||||
|
typedef struct expr_node_struct {
|
||||||
|
struct expr_node_struct *child;
|
||||||
|
struct expr_node_struct *sibling;
|
||||||
|
enum expr_node_type type;
|
||||||
|
int num_kids;
|
||||||
|
union {
|
||||||
|
Value value;
|
||||||
|
int arg;
|
||||||
|
BuiltinFunc *builtin_func;
|
||||||
|
char name[SHORT_NAME_BUF];
|
||||||
|
int (*operator_func) (struct expr_node_struct *node, Value *locals, Value *ans, int *nonconst);
|
||||||
|
} u;
|
||||||
|
} expr_node;
|
||||||
|
|
||||||
/* Define the structure of a variable */
|
/* Define the structure of a variable */
|
||||||
typedef struct var {
|
typedef struct var {
|
||||||
struct var *next;
|
struct var *next;
|
||||||
@@ -142,6 +190,8 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
|
|||||||
#define MSF_TYPE 7
|
#define MSF_TYPE 7
|
||||||
#define PASSTHRU_TYPE 8
|
#define PASSTHRU_TYPE 8
|
||||||
|
|
||||||
|
/* For function arguments */
|
||||||
|
#define NO_MAX 127
|
||||||
|
|
||||||
/* DEFINES for debugging flags */
|
/* DEFINES for debugging flags */
|
||||||
#define DB_PRTLINE 1
|
#define DB_PRTLINE 1
|
||||||
@@ -150,6 +200,7 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
|
|||||||
#define DB_DUMP_VARS 8
|
#define DB_DUMP_VARS 8
|
||||||
#define DB_ECHO_LINE 16
|
#define DB_ECHO_LINE 16
|
||||||
#define DB_TRACE_FILES 32
|
#define DB_TRACE_FILES 32
|
||||||
|
#define DB_PARSE_EXPR 64
|
||||||
|
|
||||||
/* Enumeration of the tokens */
|
/* Enumeration of the tokens */
|
||||||
enum TokTypes
|
enum TokTypes
|
||||||
@@ -183,7 +234,8 @@ enum TokTypes
|
|||||||
T_MaybeUncomputable,
|
T_MaybeUncomputable,
|
||||||
T_Ordinal,
|
T_Ordinal,
|
||||||
T_In,
|
T_In,
|
||||||
T_LastBack
|
T_LastBack,
|
||||||
|
T_Expr
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The structure of a token */
|
/* The structure of a token */
|
||||||
@@ -243,3 +295,26 @@ typedef struct {
|
|||||||
#define TERMINAL_BACKGROUND_UNKNOWN -1
|
#define TERMINAL_BACKGROUND_UNKNOWN -1
|
||||||
#define TERMINAL_BACKGROUND_DARK 0
|
#define TERMINAL_BACKGROUND_DARK 0
|
||||||
#define TERMINAL_BACKGROUND_LIGHT 1
|
#define TERMINAL_BACKGROUND_LIGHT 1
|
||||||
|
|
||||||
|
typedef int (*SysVarFunc)(int, Value *);
|
||||||
|
/* The structure of a system variable */
|
||||||
|
typedef struct {
|
||||||
|
char const *name;
|
||||||
|
char modifiable;
|
||||||
|
int type;
|
||||||
|
void *value;
|
||||||
|
int min; /* Or const-value */
|
||||||
|
int max;
|
||||||
|
} SysVar;
|
||||||
|
|
||||||
|
/* Define the data structure used to hold a user-defined function */
|
||||||
|
typedef struct udf_struct {
|
||||||
|
struct udf_struct *next;
|
||||||
|
char name[VAR_NAME_LEN+1];
|
||||||
|
expr_node *node;
|
||||||
|
char **args;
|
||||||
|
int nargs;
|
||||||
|
char const *filename;
|
||||||
|
int lineno;
|
||||||
|
} UserFunc;
|
||||||
|
|
||||||
|
|||||||
331
src/userfns.c
331
src/userfns.c
@@ -6,7 +6,7 @@
|
|||||||
/* functions. */
|
/* functions. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -16,43 +16,46 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_STRINGS_H
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "expr.h"
|
|
||||||
|
|
||||||
#define FUNC_HASH_SIZE 32 /* Size of User-defined function hash table */
|
#define FUNC_HASH_SIZE 32 /* Size of User-defined function hash table */
|
||||||
|
|
||||||
/* Define the data structure used to hold a user-defined function */
|
|
||||||
typedef struct udf_struct {
|
|
||||||
struct udf_struct *next;
|
|
||||||
char name[VAR_NAME_LEN+1];
|
|
||||||
char const *text;
|
|
||||||
Var *locals;
|
|
||||||
char IsActive;
|
|
||||||
int nargs;
|
|
||||||
char const *filename;
|
|
||||||
int lineno;
|
|
||||||
} UserFunc;
|
|
||||||
|
|
||||||
/* The hash table */
|
/* The hash table */
|
||||||
static UserFunc *FuncHash[FUNC_HASH_SIZE];
|
static UserFunc *FuncHash[FUNC_HASH_SIZE];
|
||||||
|
|
||||||
/* Access to built-in functions */
|
|
||||||
extern int NumFuncs;
|
|
||||||
extern BuiltinFunc Func[];
|
|
||||||
|
|
||||||
/* We need access to the expression evaluation stack */
|
|
||||||
extern Value ValStack[];
|
|
||||||
extern int ValStackPtr;
|
|
||||||
|
|
||||||
static void DestroyUserFunc (UserFunc *f);
|
static void DestroyUserFunc (UserFunc *f);
|
||||||
static void FUnset (char const *name);
|
static void FUnset (char const *name);
|
||||||
static void FSet (UserFunc *f);
|
static void FSet (UserFunc *f);
|
||||||
static int SetUpLocalVars (UserFunc *f);
|
|
||||||
static void DestroyLocalVals (UserFunc *f);
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* HashVal */
|
||||||
|
/* Given a string, compute the hash value. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
unsigned int HashVal_nocase(char const *str)
|
||||||
|
{
|
||||||
|
register unsigned int i=0;
|
||||||
|
register unsigned int j=1;
|
||||||
|
register unsigned int len=0;
|
||||||
|
|
||||||
|
while(*str && len < VAR_NAME_LEN) {
|
||||||
|
i += j * (*str);
|
||||||
|
str++;
|
||||||
|
len++;
|
||||||
|
j = 3-j;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
@@ -75,6 +78,7 @@ int DoFunset(ParsePtr p)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
seen_one = 1;
|
seen_one = 1;
|
||||||
|
strtolower(DBufValue(&buf));
|
||||||
FUnset(DBufValue(&buf));
|
FUnset(DBufValue(&buf));
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
}
|
}
|
||||||
@@ -93,8 +97,11 @@ int DoFset(ParsePtr p)
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
int c;
|
int c;
|
||||||
|
int i;
|
||||||
UserFunc *func;
|
UserFunc *func;
|
||||||
Var *v;
|
UserFunc *existing;
|
||||||
|
Var *locals = NULL;
|
||||||
|
Var local_array[MAX_FUNC_ARGS];
|
||||||
int orig_namelen;
|
int orig_namelen;
|
||||||
|
|
||||||
DynamicBuffer buf;
|
DynamicBuffer buf;
|
||||||
@@ -119,6 +126,21 @@ int DoFset(ParsePtr p)
|
|||||||
return E_PARSE_ERR;
|
return E_PARSE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert to lower-case */
|
||||||
|
strtolower(DBufValue(&buf));
|
||||||
|
|
||||||
|
/* If the function exists and was defined at the same line of the same
|
||||||
|
file, do nothing */
|
||||||
|
existing = FindUserFunc(DBufValue(&buf));
|
||||||
|
if (existing) {
|
||||||
|
if (!strcmp(existing->filename, FileName) &&
|
||||||
|
strcmp(existing->filename, "[cmdline]") &&
|
||||||
|
existing->lineno == LineNo) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
/* We already have it! Our work here is done. */
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
func = NEW(UserFunc);
|
func = NEW(UserFunc);
|
||||||
if (!func) {
|
if (!func) {
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
@@ -137,25 +159,22 @@ int DoFset(ParsePtr p)
|
|||||||
StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN);
|
StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
if (!Hush) {
|
if (!Hush) {
|
||||||
if (FindFunc(func->name, Func, NumFuncs)) {
|
if (FindBuiltinFunc(func->name)) {
|
||||||
Eprint("%s: `%s'", ErrMsg[E_REDEF_FUNC], func->name);
|
Eprint("%s: `%s'", ErrMsg[E_REDEF_FUNC], func->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func->locals = NULL;
|
func->node = NULL;
|
||||||
func->text = NULL;
|
|
||||||
func->IsActive = 0;
|
|
||||||
func->nargs = 0;
|
func->nargs = 0;
|
||||||
|
func->args = NULL;
|
||||||
|
|
||||||
/* Get the local variables - we insert the local variables in REVERSE
|
/* Get the local variables */
|
||||||
order, but that's OK, because we pop them off the stack in reverse
|
|
||||||
order, too, so everything works out just fine. */
|
|
||||||
|
|
||||||
c=ParseNonSpaceChar(p, &r, 1);
|
c=ParseNonSpaceChar(p, &r, 1);
|
||||||
if (r) return r;
|
if (r) return r;
|
||||||
if (c == ')') {
|
if (c == ')') {
|
||||||
(void) ParseNonSpaceChar(p, &r, 0);
|
(void) ParseNonSpaceChar(p, &r, 0);
|
||||||
}
|
} else {
|
||||||
else {
|
locals = local_array;
|
||||||
while(1) {
|
while(1) {
|
||||||
if ( (r=ParseIdentifier(p, &buf)) ) return r;
|
if ( (r=ParseIdentifier(p, &buf)) ) return r;
|
||||||
if (*DBufValue(&buf) == '$') {
|
if (*DBufValue(&buf) == '$') {
|
||||||
@@ -163,18 +182,25 @@ int DoFset(ParsePtr p)
|
|||||||
DestroyUserFunc(func);
|
DestroyUserFunc(func);
|
||||||
return E_BAD_ID;
|
return E_BAD_ID;
|
||||||
}
|
}
|
||||||
v = NEW(Var);
|
/* If we've already seen this local variable, error */
|
||||||
if (!v) {
|
for (i=0; i<func->nargs; i++) {
|
||||||
DBufFree(&buf);
|
if (!StrinCmp(DBufValue(&buf), local_array[i].name, VAR_NAME_LEN)) {
|
||||||
DestroyUserFunc(func);
|
DBufFree(&buf);
|
||||||
return E_NO_MEM;
|
DestroyUserFunc(func);
|
||||||
}
|
return E_REPEATED_ARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = func->nargs;
|
||||||
|
if (i >= MAX_FUNC_ARGS-1) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
DestroyUserFunc(func);
|
||||||
|
return E_2MANY_ARGS;
|
||||||
|
}
|
||||||
|
local_array[i].v.type = ERR_TYPE;
|
||||||
|
StrnCpy(local_array[i].name, DBufValue(&buf), VAR_NAME_LEN);
|
||||||
|
local_array[i].next = &(local_array[i+1]);
|
||||||
|
local_array[i+1].next = NULL;
|
||||||
func->nargs++;
|
func->nargs++;
|
||||||
v->v.type = ERR_TYPE;
|
|
||||||
StrnCpy(v->name, DBufValue(&buf), VAR_NAME_LEN);
|
|
||||||
DBufFree(&buf);
|
|
||||||
v->next = func->locals;
|
|
||||||
func->locals = v;
|
|
||||||
c = ParseNonSpaceChar(p, &r, 0);
|
c = ParseNonSpaceChar(p, &r, 0);
|
||||||
if (c == ')') break;
|
if (c == ')') break;
|
||||||
else if (c != ',') {
|
else if (c != ',') {
|
||||||
@@ -189,17 +215,42 @@ int DoFset(ParsePtr p)
|
|||||||
if (c == '=') {
|
if (c == '=') {
|
||||||
(void) ParseNonSpaceChar(p, &r, 0);
|
(void) ParseNonSpaceChar(p, &r, 0);
|
||||||
}
|
}
|
||||||
/* Copy the text over */
|
|
||||||
if (p->isnested) {
|
if (p->isnested) {
|
||||||
Eprint("%s", ErrMsg[E_CANTNEST_FDEF]);
|
Eprint("%s", ErrMsg[E_CANTNEST_FDEF]);
|
||||||
DestroyUserFunc(func);
|
DestroyUserFunc(func);
|
||||||
return E_PARSE_ERR;
|
return E_PARSE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
func->text = StrDup(p->pos);
|
while(*(p->pos) && isspace(*(p->pos))) {
|
||||||
if (!func->text) {
|
p->pos++;
|
||||||
DestroyUserFunc(func);
|
}
|
||||||
return E_NO_MEM;
|
if (!*(p->pos)) {
|
||||||
|
DestroyUserFunc(func);
|
||||||
|
return E_EOLN;
|
||||||
|
}
|
||||||
|
/* Parse the expression */
|
||||||
|
func->node = parse_expression(&(p->pos), &r, locals);
|
||||||
|
if (!func->node) {
|
||||||
|
DestroyUserFunc(func);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = ParseNonSpaceChar(p, &r, 1);
|
||||||
|
if (c != 0) {
|
||||||
|
DestroyUserFunc(func);
|
||||||
|
return E_EXPECTING_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the argument names */
|
||||||
|
if (func->nargs) {
|
||||||
|
func->args = calloc(sizeof(char *), func->nargs);
|
||||||
|
for (i=0; i<func->nargs; i++) {
|
||||||
|
func->args[i] = StrDup(local_array[i].name);
|
||||||
|
if (!func->args[i]) {
|
||||||
|
DestroyUserFunc(func);
|
||||||
|
return E_NO_MEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If an old definition of this function exists, destroy it */
|
/* If an old definition of this function exists, destroy it */
|
||||||
@@ -223,23 +274,22 @@ int DoFset(ParsePtr p)
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static void DestroyUserFunc(UserFunc *f)
|
static void DestroyUserFunc(UserFunc *f)
|
||||||
{
|
{
|
||||||
Var *v, *prev;
|
int i;
|
||||||
|
|
||||||
/* Free the local variables first */
|
|
||||||
v = f->locals;
|
|
||||||
while(v) {
|
|
||||||
DestroyValue(v->v);
|
|
||||||
prev = v;
|
|
||||||
v = v->next;
|
|
||||||
free(prev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free the function definition */
|
/* Free the function definition */
|
||||||
if (f->text) free( (char *) f->text);
|
if (f->node) free_expr_tree(f->node);
|
||||||
|
|
||||||
/* Free the filename */
|
/* Free the filename */
|
||||||
if (f->filename) free( (char *) f->filename);
|
if (f->filename) free( (char *) f->filename);
|
||||||
|
|
||||||
|
/* Free arg names */
|
||||||
|
if (f->args) {
|
||||||
|
for (i=0; i<f->nargs; i++) {
|
||||||
|
if (f->args[i]) free(f->args[i]);
|
||||||
|
}
|
||||||
|
free(f->args);
|
||||||
|
}
|
||||||
|
|
||||||
/* Free the data structure itself */
|
/* Free the data structure itself */
|
||||||
free(f);
|
free(f);
|
||||||
}
|
}
|
||||||
@@ -257,12 +307,12 @@ static void FUnset(char const *name)
|
|||||||
UserFunc *cur, *prev;
|
UserFunc *cur, *prev;
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
h = HashVal(name) % FUNC_HASH_SIZE;
|
h = HashVal_nocase(name) % FUNC_HASH_SIZE;
|
||||||
|
|
||||||
cur = FuncHash[h];
|
cur = FuncHash[h];
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
while(cur) {
|
while(cur) {
|
||||||
if (! StrinCmp(name, cur->name, VAR_NAME_LEN)) break;
|
if (! strncmp(name, cur->name, VAR_NAME_LEN)) break;
|
||||||
prev = cur;
|
prev = cur;
|
||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
}
|
}
|
||||||
@@ -280,132 +330,22 @@ static void FUnset(char const *name)
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static void FSet(UserFunc *f)
|
static void FSet(UserFunc *f)
|
||||||
{
|
{
|
||||||
int h = HashVal(f->name) % FUNC_HASH_SIZE;
|
int h = HashVal_nocase(f->name) % FUNC_HASH_SIZE;
|
||||||
f->next = FuncHash[h];
|
f->next = FuncHash[h];
|
||||||
FuncHash[h] = f;
|
FuncHash[h] = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
UserFunc *FindUserFunc(char const *name)
|
||||||
/* */
|
|
||||||
/* CallUserFunc */
|
|
||||||
/* */
|
|
||||||
/* Call a user-defined function. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
int CallUserFunc(char const *name, int nargs, ParsePtr p)
|
|
||||||
{
|
{
|
||||||
UserFunc *f;
|
UserFunc *f;
|
||||||
int h = HashVal(name) % FUNC_HASH_SIZE;
|
int h = HashVal_nocase(name) % FUNC_HASH_SIZE;
|
||||||
int i;
|
|
||||||
char const *s;
|
|
||||||
|
|
||||||
/* Search for the function */
|
/* Search for the function */
|
||||||
f = FuncHash[h];
|
f = FuncHash[h];
|
||||||
while (f && StrinCmp(name, f->name, VAR_NAME_LEN)) f = f->next;
|
while (f && strncmp(name, f->name, VAR_NAME_LEN)) f = f->next;
|
||||||
if (!f) {
|
return f;
|
||||||
Eprint("%s: `%s'", ErrMsg[E_UNDEF_FUNC], name);
|
|
||||||
return E_UNDEF_FUNC;
|
|
||||||
}
|
|
||||||
/* Debugging stuff */
|
|
||||||
if (DebugFlag & DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s %s(", ErrMsg[E_ENTER_FUN], f->name);
|
|
||||||
for (i=0; i<nargs; i++) {
|
|
||||||
PrintValue(&ValStack[ValStackPtr - nargs + i], ErrFp);
|
|
||||||
if (i<nargs-1) fprintf(ErrFp, ", ");
|
|
||||||
}
|
|
||||||
fprintf(ErrFp, ")\n");
|
|
||||||
}
|
|
||||||
/* Detect illegal recursive call */
|
|
||||||
if (f->IsActive) {
|
|
||||||
if (DebugFlag &DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
|
|
||||||
fprintf(ErrFp, "%s\n", ErrMsg[E_RECURSIVE]);
|
|
||||||
}
|
|
||||||
return E_RECURSIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check number of args */
|
|
||||||
if (nargs != f->nargs) {
|
|
||||||
if (DebugFlag &DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
|
|
||||||
fprintf(ErrFp, "%s\n",
|
|
||||||
ErrMsg[(nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS]);
|
|
||||||
}
|
|
||||||
return (nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS;
|
|
||||||
}
|
|
||||||
/* Found the function - set up a local variable frame */
|
|
||||||
h = SetUpLocalVars(f);
|
|
||||||
if (h) {
|
|
||||||
if (DebugFlag &DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
|
|
||||||
fprintf(ErrFp, "%s\n", ErrMsg[h]);
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Evaluate the expression */
|
|
||||||
f->IsActive = 1;
|
|
||||||
s = f->text;
|
|
||||||
|
|
||||||
/* Skip the opening bracket, if there's one */
|
|
||||||
while (isempty(*s)) s++;
|
|
||||||
if (*s == BEG_OF_EXPR) s++;
|
|
||||||
push_call(f->filename, f->name, f->lineno);
|
|
||||||
h = Evaluate(&s, f->locals, p);
|
|
||||||
if (h == OK) {
|
|
||||||
pop_call();
|
|
||||||
}
|
|
||||||
f->IsActive = 0;
|
|
||||||
DestroyLocalVals(f);
|
|
||||||
if (DebugFlag &DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
|
|
||||||
if (h) fprintf(ErrFp, "%s\n", ErrMsg[h]);
|
|
||||||
else {
|
|
||||||
PrintValue(&ValStack[ValStackPtr-1], ErrFp);
|
|
||||||
fprintf(ErrFp, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* SetUpLocalVars */
|
|
||||||
/* */
|
|
||||||
/* Set up the local variables from the stack frame. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
static int SetUpLocalVars(UserFunc *f)
|
|
||||||
{
|
|
||||||
int i, r;
|
|
||||||
Var *var;
|
|
||||||
|
|
||||||
for (i=0, var=f->locals; var && i<f->nargs; var=var->next, i++) {
|
|
||||||
if ( (r=FnPopValStack(&(var->v))) ) {
|
|
||||||
DestroyLocalVals(f);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* DestroyLocalVals */
|
|
||||||
/* */
|
|
||||||
/* Destroy the values of all local variables after evaluating */
|
|
||||||
/* the function. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
static void DestroyLocalVals(UserFunc *f)
|
|
||||||
{
|
|
||||||
Var *v = f->locals;
|
|
||||||
|
|
||||||
while(v) {
|
|
||||||
DestroyValue(v->v);
|
|
||||||
v = v->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* UserFuncExists */
|
/* UserFuncExists */
|
||||||
@@ -416,12 +356,33 @@ static void DestroyLocalVals(UserFunc *f)
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int UserFuncExists(char const *fn)
|
int UserFuncExists(char const *fn)
|
||||||
{
|
{
|
||||||
UserFunc *f;
|
UserFunc *f = FindUserFunc(fn);
|
||||||
int h = HashVal(fn) % FUNC_HASH_SIZE;
|
|
||||||
|
|
||||||
f = FuncHash[h];
|
|
||||||
while (f && StrinCmp(fn, f->name, VAR_NAME_LEN)) f = f->next;
|
|
||||||
if (!f) return -1;
|
if (!f) return -1;
|
||||||
else return f->nargs;
|
else return f->nargs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* UnsetAllUserFuncs */
|
||||||
|
/* */
|
||||||
|
/* Call FUNSET on all user funcs. Used with -ds flag to */
|
||||||
|
/* ensure no expr_node memory leaks. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
void
|
||||||
|
UnsetAllUserFuncs(void)
|
||||||
|
{
|
||||||
|
UserFunc *f;
|
||||||
|
UserFunc *next;
|
||||||
|
int i;
|
||||||
|
for (i=0; i<FUNC_HASH_SIZE; i++) {
|
||||||
|
f = FuncHash[i];
|
||||||
|
while(f) {
|
||||||
|
next = f->next;
|
||||||
|
DestroyUserFunc(f);
|
||||||
|
f = next;
|
||||||
|
}
|
||||||
|
FuncHash[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
101
src/utils.c
101
src/utils.c
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -17,6 +17,11 @@ static char const DontEscapeMe[] =
|
|||||||
#include "err.h"
|
#include "err.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_STRINGS_H
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
@@ -36,11 +41,17 @@ char *StrnCpy(char *dest, char const *source, int n)
|
|||||||
{
|
{
|
||||||
char *odest = dest;
|
char *odest = dest;
|
||||||
|
|
||||||
|
if (n <= 0) {
|
||||||
|
*dest = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
while (n-- && (*dest++ = *source++)) ;
|
while (n-- && (*dest++ = *source++)) ;
|
||||||
if (*(dest-1)) *dest = 0;
|
if (*(dest-1)) *dest = 0;
|
||||||
return odest;
|
return odest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef HAVE_STRNCASECMP
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* StrinCmp - compare strings, case-insensitive */
|
/* StrinCmp - compare strings, case-insensitive */
|
||||||
@@ -59,6 +70,9 @@ int StrinCmp(char const *s1, char const *s2, int n)
|
|||||||
if (n) return (toupper(*s1) - toupper(*s2)); else return 0;
|
if (n) return (toupper(*s1) - toupper(*s2)); else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_STRDUP
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* StrDup */
|
/* StrDup */
|
||||||
@@ -74,6 +88,9 @@ char *StrDup(char const *s)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_STRCASECMP
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* StrCmpi */
|
/* StrCmpi */
|
||||||
@@ -93,6 +110,8 @@ int StrCmpi(char const *s1, char const *s2)
|
|||||||
return toupper(*s1) - toupper(*s2);
|
return toupper(*s1) - toupper(*s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* DateOK */
|
/* DateOK */
|
||||||
@@ -108,7 +127,15 @@ int DateOK(int y, int m, int d)
|
|||||||
m > 11 ||
|
m > 11 ||
|
||||||
y > BASE + YR_RANGE ||
|
y > BASE + YR_RANGE ||
|
||||||
d > DaysInMonth(m, y) ) return 0;
|
d > DaysInMonth(m, y) ) return 0;
|
||||||
else return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void strtolower(char *s)
|
||||||
|
{
|
||||||
|
while (*s) {
|
||||||
|
*s = tolower(*s);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Functions designed to defeat gcc optimizer */
|
/* Functions designed to defeat gcc optimizer */
|
||||||
@@ -146,11 +173,15 @@ int _private_sub_overflow(int a, int b)
|
|||||||
int
|
int
|
||||||
ShellEscape(char const *in, DynamicBuffer *out)
|
ShellEscape(char const *in, DynamicBuffer *out)
|
||||||
{
|
{
|
||||||
while(*in) {
|
unsigned char const *i = (unsigned char const *) in;
|
||||||
if (!strchr(DontEscapeMe, *in)) {
|
while(*i) {
|
||||||
if (DBufPutc(out, '\\') != OK) return E_NO_MEM;
|
/* Don't escape chars with high bit set. That will mangle UTF-8 */
|
||||||
|
if (! (*i & 0x80) ) {
|
||||||
|
if (!strchr(DontEscapeMe, *i)) {
|
||||||
|
if (DBufPutc(out, '\\') != OK) return E_NO_MEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (DBufPutc(out, *in++) != OK) return E_NO_MEM;
|
if (DBufPutc(out, *i++) != OK) return E_NO_MEM;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -164,31 +195,33 @@ typedef struct cs_s {
|
|||||||
} cs;
|
} cs;
|
||||||
|
|
||||||
static cs *callstack = NULL;
|
static cs *callstack = NULL;
|
||||||
|
static cs *freecs = NULL;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
destroy_cs(cs *entry)
|
destroy_cs(cs *entry)
|
||||||
{
|
{
|
||||||
if (entry->filename) free( (void *) entry->filename);
|
entry->next = freecs;
|
||||||
if (entry->func) free( (void *) entry->func);
|
freecs = entry;
|
||||||
free( (void *) entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
push_call(char const *filename, char const *func, int lineno)
|
push_call(char const *filename, char const *func, int lineno)
|
||||||
{
|
{
|
||||||
cs *entry = NEW(cs);
|
cs *entry;
|
||||||
if (!entry) {
|
if (freecs) {
|
||||||
return E_NO_MEM;
|
entry = freecs;
|
||||||
|
freecs = freecs->next;
|
||||||
|
} else {
|
||||||
|
entry = NEW(cs);
|
||||||
|
if (!entry) {
|
||||||
|
return E_NO_MEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
entry->next = NULL;
|
entry->next = NULL;
|
||||||
entry->filename = StrDup(filename);
|
entry->filename = filename;
|
||||||
entry->func = StrDup(func);
|
entry->func = func;
|
||||||
entry->lineno = lineno;
|
entry->lineno = lineno;
|
||||||
if (!entry->filename || !entry->func) {
|
|
||||||
destroy_cs(entry);
|
|
||||||
return E_NO_MEM;
|
|
||||||
}
|
|
||||||
entry->next = callstack;
|
entry->next = callstack;
|
||||||
callstack = entry;
|
callstack = entry;
|
||||||
return OK;
|
return OK;
|
||||||
@@ -210,11 +243,35 @@ clear_callstack(void)
|
|||||||
static void
|
static void
|
||||||
print_callstack_aux(FILE *fp, cs *entry)
|
print_callstack_aux(FILE *fp, cs *entry)
|
||||||
{
|
{
|
||||||
if (entry) {
|
int i = 0;
|
||||||
print_callstack_aux(fp, entry->next);
|
char const *in = "In";
|
||||||
fprintf(fp, "\n");
|
cs *prev = NULL;
|
||||||
(void) fprintf(fp, "%s(%d): In function `%s'", entry->filename, entry->lineno, entry->func);
|
while(entry) {
|
||||||
|
if (prev) {
|
||||||
|
in = "Called from";
|
||||||
|
}
|
||||||
|
if (!prev || strcmp(prev->func, entry->func) || strcmp(prev->filename, entry->filename) || prev->lineno != entry->lineno) {
|
||||||
|
if (prev) {
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
}
|
||||||
|
(void) fprintf(fp, " %s(%d): [#%d] %s function `%s'", entry->filename, entry->lineno, i, in, entry->func);
|
||||||
|
}
|
||||||
|
prev = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
i++;
|
||||||
|
if (i > 10) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (entry) {
|
||||||
|
(void) fprintf(fp, "\n [remaining call frames omitted]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
have_callstack(void)
|
||||||
|
{
|
||||||
|
return (callstack != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
114
src/var.c
114
src/var.c
@@ -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-2023 by Dianne Skoll */
|
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "expr.h"
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
@@ -39,8 +38,6 @@ static int IntMax = INT_MAX;
|
|||||||
|
|
||||||
static Var *VHashTbl[VAR_HASH_SIZE];
|
static Var *VHashTbl[VAR_HASH_SIZE];
|
||||||
|
|
||||||
typedef int (*SysVarFunc)(int, Value *);
|
|
||||||
|
|
||||||
static double
|
static double
|
||||||
strtod_in_c_locale(char const *str, char **endptr)
|
strtod_in_c_locale(char const *str, char **endptr)
|
||||||
{
|
{
|
||||||
@@ -167,6 +164,26 @@ static int latitude_func(int do_set, Value *val)
|
|||||||
return latitude_longitude_func(do_set, val, &Latitude, -90.0, 90.0);
|
return latitude_longitude_func(do_set, val, &Latitude, -90.0, 90.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int terminal_bg_func(int do_set, Value *val)
|
||||||
|
{
|
||||||
|
UNUSED(do_set);
|
||||||
|
val->type = INT_TYPE;
|
||||||
|
val->v.val = GetTerminalBackground();
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int trig_time_func(int do_set, Value *val)
|
||||||
|
{
|
||||||
|
UNUSED(do_set);
|
||||||
|
if (LastTriggerTime != NO_TIME) {
|
||||||
|
val->type = TIME_TYPE;
|
||||||
|
val->v.val = LastTriggerTime;
|
||||||
|
} else {
|
||||||
|
val->type = INT_TYPE;
|
||||||
|
val->v.val = 0;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int trig_date_func(int do_set, Value *val)
|
static int trig_date_func(int do_set, Value *val)
|
||||||
{
|
{
|
||||||
@@ -302,6 +319,29 @@ static int datetime_sep_func(int do_set, Value *val)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int expr_time_limit_func(int do_set, Value *val)
|
||||||
|
{
|
||||||
|
if (!do_set) {
|
||||||
|
val->type = INT_TYPE;
|
||||||
|
val->v.val = ExpressionEvaluationTimeLimit;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
if (val->type != INT_TYPE) return E_BAD_TYPE;
|
||||||
|
if (val->v.val < 0) return E_2LOW;
|
||||||
|
|
||||||
|
if (!TopLevel()) {
|
||||||
|
/* Ignore attempts to set from non-toplevel unless it's
|
||||||
|
lower than current value */
|
||||||
|
if (val->v.val == 0 ||
|
||||||
|
val->v.val >= ExpressionEvaluationTimeLimit) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionEvaluationTimeLimit = val->v.val;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int default_color_func(int do_set, Value *val)
|
static int default_color_func(int do_set, Value *val)
|
||||||
{
|
{
|
||||||
int col_r, col_g, col_b;
|
int col_r, col_g, col_b;
|
||||||
@@ -470,10 +510,10 @@ int DeleteVar(char const *str)
|
|||||||
/* */
|
/* */
|
||||||
/* SetVar */
|
/* SetVar */
|
||||||
/* */
|
/* */
|
||||||
/* Set the indicate variable to the specified value. */
|
/* Set the indicated variable to the specified value. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int SetVar(char const *str, Value *val)
|
int SetVar(char const *str, Value const *val)
|
||||||
{
|
{
|
||||||
Var *v = FindVar(str, 1);
|
Var *v = FindVar(str, 1);
|
||||||
|
|
||||||
@@ -491,20 +531,10 @@ int SetVar(char const *str, Value *val)
|
|||||||
/* Get a copy of the value of the variable. */
|
/* Get a copy of the value of the variable. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int GetVarValue(char const *str, Value *val, Var *locals, ParsePtr p)
|
int GetVarValue(char const *str, Value *val)
|
||||||
{
|
{
|
||||||
Var *v;
|
Var *v;
|
||||||
|
|
||||||
/* Try searching local variables first */
|
|
||||||
v = locals;
|
|
||||||
while (v) {
|
|
||||||
if (! StrinCmp(str, v->name, VAR_NAME_LEN))
|
|
||||||
return CopyValue(val, &v->v);
|
|
||||||
v = v->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Global variable... mark expression as non-constant */
|
|
||||||
if (p) p->nonconst_expr = 1;
|
|
||||||
v=FindVar(str, 0);
|
v=FindVar(str, 0);
|
||||||
|
|
||||||
if (!v) {
|
if (!v) {
|
||||||
@@ -525,7 +555,9 @@ int DoSet (Parser *p)
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
DynamicBuffer buf;
|
DynamicBuffer buf;
|
||||||
|
DynamicBuffer buf2;
|
||||||
DBufInit(&buf);
|
DBufInit(&buf);
|
||||||
|
DBufInit(&buf2);
|
||||||
|
|
||||||
r = ParseIdentifier(p, &buf);
|
r = ParseIdentifier(p, &buf);
|
||||||
if (r) return r;
|
if (r) return r;
|
||||||
@@ -535,12 +567,24 @@ int DoSet (Parser *p)
|
|||||||
ParseNonSpaceChar(p, &r, 0);
|
ParseNonSpaceChar(p, &r, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p->isnested) {
|
||||||
|
Eprint("%s", "Do not use [] around expression in SET command");
|
||||||
|
return E_CANTNEST_FDEF;
|
||||||
|
}
|
||||||
|
|
||||||
r = EvaluateExpr(p, &v);
|
r = EvaluateExpr(p, &v);
|
||||||
if (r) {
|
if (r) {
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = ParseToken(p, &buf2);
|
||||||
|
if (r) return r;
|
||||||
|
if (DBufLen(&buf2)) {
|
||||||
|
DBufFree(&buf2);
|
||||||
|
return E_EXPECTING_EOL;
|
||||||
|
}
|
||||||
|
DBufFree(&buf2);
|
||||||
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) {
|
||||||
@@ -756,15 +800,9 @@ int DoPreserve (Parser *p)
|
|||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
||||||
/* The structure of a system variable */
|
/* Macro to access "min" but as a constval. Just to make source more
|
||||||
typedef struct {
|
readable */
|
||||||
char const *name;
|
#define constval min
|
||||||
char modifiable;
|
|
||||||
int type;
|
|
||||||
void *value;
|
|
||||||
int min;
|
|
||||||
int max;
|
|
||||||
} SysVar;
|
|
||||||
|
|
||||||
/* If the type of a sys variable is STR_TYPE, then min is redefined
|
/* If the type of a sys variable is STR_TYPE, then min is redefined
|
||||||
to be a flag indicating whether or not the value has been malloc'd. */
|
to be a flag indicating whether or not the value has been malloc'd. */
|
||||||
@@ -798,6 +836,7 @@ static SysVar SysVarArr[] = {
|
|||||||
{"DontTrigAts", 0, INT_TYPE, &DontIssueAts, 0, 0 },
|
{"DontTrigAts", 0, INT_TYPE, &DontIssueAts, 0, 0 },
|
||||||
{"EndSent", 1, STR_TYPE, &EndSent, 0, 0 },
|
{"EndSent", 1, STR_TYPE, &EndSent, 0, 0 },
|
||||||
{"EndSentIg", 1, STR_TYPE, &EndSentIg, 0, 0 },
|
{"EndSentIg", 1, STR_TYPE, &EndSentIg, 0, 0 },
|
||||||
|
{"ExpressionTimeLimit", 1, SPECIAL_TYPE, expr_time_limit_func, 0, 0 },
|
||||||
{"February", 1, STR_TYPE, &DynamicMonthName[1], 0, 0 },
|
{"February", 1, STR_TYPE, &DynamicMonthName[1], 0, 0 },
|
||||||
{"FirstIndent", 1, INT_TYPE, &FirstIndent, 0, 132 },
|
{"FirstIndent", 1, INT_TYPE, &FirstIndent, 0, 132 },
|
||||||
{"FoldYear", 1, INT_TYPE, &FoldYear, 0, 1 },
|
{"FoldYear", 1, INT_TYPE, &FoldYear, 0, 1 },
|
||||||
@@ -825,7 +864,9 @@ static SysVar SysVarArr[] = {
|
|||||||
{"LongMin", 1, SPECIAL_TYPE, longmin_func, 0, 0 },
|
{"LongMin", 1, SPECIAL_TYPE, longmin_func, 0, 0 },
|
||||||
{"LongSec", 1, SPECIAL_TYPE, longsec_func, 0, 0 },
|
{"LongSec", 1, SPECIAL_TYPE, longsec_func, 0, 0 },
|
||||||
{"March", 1, STR_TYPE, &DynamicMonthName[2], 0, 0 },
|
{"March", 1, STR_TYPE, &DynamicMonthName[2], 0, 0 },
|
||||||
|
{"MaxFullOmits", 0, CONST_INT_TYPE, NULL, MAX_FULL_OMITS, 0},
|
||||||
{"MaxLateMinutes", 1, INT_TYPE, &MaxLateMinutes, 0, 1440 },
|
{"MaxLateMinutes", 1, INT_TYPE, &MaxLateMinutes, 0, 1440 },
|
||||||
|
{"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 },
|
||||||
{"May", 1, STR_TYPE, &DynamicMonthName[4], 0, 0 },
|
{"May", 1, STR_TYPE, &DynamicMonthName[4], 0, 0 },
|
||||||
@@ -836,6 +877,8 @@ static SysVar SysVarArr[] = {
|
|||||||
{"NextMode", 0, INT_TYPE, &NextMode, 0, 0 },
|
{"NextMode", 0, INT_TYPE, &NextMode, 0, 0 },
|
||||||
{"November", 1, STR_TYPE, &DynamicMonthName[10],0, 0 },
|
{"November", 1, STR_TYPE, &DynamicMonthName[10],0, 0 },
|
||||||
{"Now", 1, STR_TYPE, &DynamicNow, 0, 0 },
|
{"Now", 1, STR_TYPE, &DynamicNow, 0, 0 },
|
||||||
|
{"NumFullOmits", 0, INT_TYPE, &NumFullOmits, 0, 0 },
|
||||||
|
{"NumPartialOmits",0, INT_TYPE, &NumPartialOmits, 0, 0 },
|
||||||
{"NumQueued", 0, INT_TYPE, &NumQueued, 0, 0 },
|
{"NumQueued", 0, INT_TYPE, &NumQueued, 0, 0 },
|
||||||
{"NumTrig", 0, INT_TYPE, &NumTriggered, 0, 0 },
|
{"NumTrig", 0, INT_TYPE, &NumTriggered, 0, 0 },
|
||||||
{"October", 1, STR_TYPE, &DynamicMonthName[9], 0, 0 },
|
{"October", 1, STR_TYPE, &DynamicMonthName[9], 0, 0 },
|
||||||
@@ -857,12 +900,13 @@ static SysVar SysVarArr[] = {
|
|||||||
{"SysInclude", 0, STR_TYPE, &SysDir, 0, 0 },
|
{"SysInclude", 0, STR_TYPE, &SysDir, 0, 0 },
|
||||||
{"T", 0, SPECIAL_TYPE, trig_date_func, 0, 0 },
|
{"T", 0, SPECIAL_TYPE, trig_date_func, 0, 0 },
|
||||||
{"Td", 0, SPECIAL_TYPE, trig_day_func, 0, 0 },
|
{"Td", 0, SPECIAL_TYPE, trig_day_func, 0, 0 },
|
||||||
{"TerminalBackground", 0, INT_TYPE, &TerminalBackground, 0, 0 },
|
{"TerminalBackground", 0, SPECIAL_TYPE, terminal_bg_func, 0, 0 },
|
||||||
{"Thursday", 1, STR_TYPE, &DynamicDayName[3], 0, 0 },
|
{"Thursday", 1, STR_TYPE, &DynamicDayName[3], 0, 0 },
|
||||||
{"TimeSep", 1, SPECIAL_TYPE, time_sep_func, 0, 0 },
|
{"TimeSep", 1, SPECIAL_TYPE, time_sep_func, 0, 0 },
|
||||||
{"Tm", 0, SPECIAL_TYPE, trig_mon_func, 0, 0 },
|
{"Tm", 0, SPECIAL_TYPE, trig_mon_func, 0, 0 },
|
||||||
{"Today", 1, STR_TYPE, &DynamicToday, 0, 0 },
|
{"Today", 1, STR_TYPE, &DynamicToday, 0, 0 },
|
||||||
{"Tomorrow", 1, STR_TYPE, &DynamicTomorrow, 0, 0 },
|
{"Tomorrow", 1, STR_TYPE, &DynamicTomorrow, 0, 0 },
|
||||||
|
{"Tt", 0, SPECIAL_TYPE, trig_time_func, 0, 0 },
|
||||||
{"Tuesday", 1, STR_TYPE, &DynamicDayName[1], 0, 0 },
|
{"Tuesday", 1, STR_TYPE, &DynamicDayName[1], 0, 0 },
|
||||||
{"Tw", 0, SPECIAL_TYPE, trig_wday_func, 0, 0 },
|
{"Tw", 0, SPECIAL_TYPE, trig_wday_func, 0, 0 },
|
||||||
{"Ty", 0, SPECIAL_TYPE, trig_year_func, 0, 0 },
|
{"Ty", 0, SPECIAL_TYPE, trig_year_func, 0, 0 },
|
||||||
@@ -881,7 +925,6 @@ static SysVar SysVarArr[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define NUMSYSVARS ( sizeof(SysVarArr) / sizeof(SysVar) )
|
#define NUMSYSVARS ( sizeof(SysVarArr) / sizeof(SysVar) )
|
||||||
static SysVar *FindSysVar (char const *name);
|
|
||||||
static void DumpSysVar (char const *name, const SysVar *v);
|
static void DumpSysVar (char const *name, const SysVar *v);
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
@@ -895,13 +938,13 @@ int SetSysVar(char const *name, Value *value)
|
|||||||
int r;
|
int r;
|
||||||
SysVar *v = FindSysVar(name);
|
SysVar *v = FindSysVar(name);
|
||||||
if (!v) return E_NOSUCH_VAR;
|
if (!v) return E_NOSUCH_VAR;
|
||||||
if (v->type != SPECIAL_TYPE &&
|
|
||||||
v->type != value->type) return E_BAD_TYPE;
|
|
||||||
if (!v->modifiable) {
|
if (!v->modifiable) {
|
||||||
Eprint("%s: `$%s'", ErrMsg[E_CANT_MODIFY], name);
|
Eprint("%s: `$%s'", ErrMsg[E_CANT_MODIFY], name);
|
||||||
return E_CANT_MODIFY;
|
return E_CANT_MODIFY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (v->type != SPECIAL_TYPE &&
|
||||||
|
v->type != value->type) return E_BAD_TYPE;
|
||||||
if (v->type == SPECIAL_TYPE) {
|
if (v->type == SPECIAL_TYPE) {
|
||||||
SysVarFunc f = (SysVarFunc) v->value;
|
SysVarFunc f = (SysVarFunc) v->value;
|
||||||
r = f(1, value);
|
r = f(1, value);
|
||||||
@@ -942,6 +985,11 @@ int GetSysVar(char const *name, Value *val)
|
|||||||
|
|
||||||
val->type = ERR_TYPE;
|
val->type = ERR_TYPE;
|
||||||
if (!v) return E_NOSUCH_VAR;
|
if (!v) return E_NOSUCH_VAR;
|
||||||
|
if (v->type == CONST_INT_TYPE) {
|
||||||
|
val->v.val = v->constval;
|
||||||
|
val->type = INT_TYPE;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
if (v->type == SPECIAL_TYPE) {
|
if (v->type == SPECIAL_TYPE) {
|
||||||
SysVarFunc f = (SysVarFunc) v->value;
|
SysVarFunc f = (SysVarFunc) v->value;
|
||||||
return f(0, val);
|
return f(0, val);
|
||||||
@@ -973,7 +1021,7 @@ int GetSysVar(char const *name, Value *val)
|
|||||||
/* Find a system var with specified name. */
|
/* Find a system var with specified name. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static SysVar *FindSysVar(char const *name)
|
SysVar *FindSysVar(char const *name)
|
||||||
{
|
{
|
||||||
int top=NUMSYSVARS-1, bottom=0;
|
int top=NUMSYSVARS-1, bottom=0;
|
||||||
int mid=(top + bottom) / 2;
|
int mid=(top + bottom) / 2;
|
||||||
@@ -1035,7 +1083,9 @@ static void DumpSysVar(char const *name, const SysVar *v)
|
|||||||
if (name) strcat(buffer, name); else strcat(buffer, v->name);
|
if (name) strcat(buffer, name); else strcat(buffer, v->name);
|
||||||
fprintf(ErrFp, "%16s ", buffer);
|
fprintf(ErrFp, "%16s ", buffer);
|
||||||
if (v) {
|
if (v) {
|
||||||
if (v->type == SPECIAL_TYPE) {
|
if (v->type == CONST_INT_TYPE) {
|
||||||
|
fprintf(ErrFp, "%d\n", v->constval);
|
||||||
|
} else if (v->type == SPECIAL_TYPE) {
|
||||||
SysVarFunc f = (SysVarFunc) v->value;
|
SysVarFunc f = (SysVarFunc) v->value;
|
||||||
f(0, &vtmp);
|
f(0, &vtmp);
|
||||||
PrintValue(&vtmp, ErrFp);
|
PrintValue(&vtmp, ErrFp);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ MSG UseVTColors is: [$UseVTColors]%
|
|||||||
MSG Use256Colors is: [$Use256Colors]%
|
MSG Use256Colors is: [$Use256Colors]%
|
||||||
MSG UseTrueColors is: [$UseTrueColors]%
|
MSG UseTrueColors is: [$UseTrueColors]%
|
||||||
MSG UseBGVTColors is: [$UseBGVTColors]%
|
MSG UseBGVTColors is: [$UseBGVTColors]%
|
||||||
set n ansicolor("")]
|
set n ansicolor("")
|
||||||
MSG This is [ansicolor(0,255,0)]green[n], [ansicolor("255 0 0")]red[n] and [ansicolor("0 0 255")]blue[n] text.%
|
MSG This is [ansicolor(0,255,0)]green[n], [ansicolor("255 0 0")]red[n] and [ansicolor("0 0 255")]blue[n] text.%
|
||||||
MSG This is [ansicolor(0,0,0)][ansicolor(0,255,0,1)]black text on a green background[n]%
|
MSG This is [ansicolor(0,0,0)][ansicolor(0,255,0,1)]black text on a green background[n]%
|
||||||
MSG This is [ansicolor(0,0,0,0,1)]clamped black text[n]%
|
MSG This is [ansicolor(0,0,0,0,1)]clamped black text[n]%
|
||||||
@@ -35,8 +35,8 @@ set a ansicolor(-1, 0, 0)
|
|||||||
set a ansicolor(42, 42, 256)
|
set a ansicolor(42, 42, 256)
|
||||||
set a ansicolor("foo")
|
set a ansicolor("foo")
|
||||||
set a ansicolor("1 1")
|
set a ansicolor("1 1")
|
||||||
set a ansicolor("-1 -1 0");
|
set a ansicolor("-1 -1 0")
|
||||||
set a ansicolor("256 1 1");
|
set a ansicolor("256 1 1")
|
||||||
set a ansicolor(128, 128, 128, 2)
|
set a ansicolor(128, 128, 128, 2)
|
||||||
set a ansicolor(128, 128, 128, -1)
|
set a ansicolor(128, 128, 128, -1)
|
||||||
set a ansicolor(128, 128, 128, 0, 2)
|
set a ansicolor(128, 128, 128, 0, 2)
|
||||||
|
|||||||
51
tests/expr.rem
Normal file
51
tests/expr.rem
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
debug +sx
|
||||||
|
|
||||||
|
set a 1
|
||||||
|
|
||||||
|
set a 0&&0
|
||||||
|
set a 0&&1
|
||||||
|
set a 1&&0
|
||||||
|
set a 1&&1
|
||||||
|
|
||||||
|
set a 0||0
|
||||||
|
set a 0||1
|
||||||
|
set a 1||0
|
||||||
|
set a 1||1
|
||||||
|
|
||||||
|
set a 2, 3
|
||||||
|
|
||||||
|
set a iif(0, "foo", 0, "bar", 1, "blech", 0, "quux", 1, "borhy", "wacka")
|
||||||
|
|
||||||
|
set a max(2*3, 4+5, min(6*7+8, 7+6*8))
|
||||||
|
|
||||||
|
set a max(1,,1)
|
||||||
|
|
||||||
|
set a 5%0
|
||||||
|
|
||||||
|
set a 5/0
|
||||||
|
|
||||||
|
set a -$IntMin
|
||||||
|
|
||||||
|
set a $IntMin / -1
|
||||||
|
set a $IntMin % -1
|
||||||
|
|
||||||
|
set a (7+5)*(8+2)/(9-4)
|
||||||
|
|
||||||
|
set a "foo" * 5
|
||||||
|
set a "foo" / 5
|
||||||
|
set a "foo" * "five"
|
||||||
|
set a "foo" + "bar"
|
||||||
|
set a '2024-01-02' + 3
|
||||||
|
set a 3 + '2024-01-02'
|
||||||
|
set a 11:33 + 75
|
||||||
|
set a 75 + 11:33
|
||||||
|
set a '2024-01-01@11:33' + 1500
|
||||||
|
set a 1500 + '2024-01-01@11:33'
|
||||||
|
|
||||||
|
set a '2024-03-02' - '2024-01-01'
|
||||||
|
set a 15:00 - 14:44
|
||||||
|
|
||||||
|
|
||||||
|
set a (1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
|
||||||
|
|
||||||
|
set a (1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
|
||||||
4
tests/if1.rem
Normal file
4
tests/if1.rem
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
BANNER %
|
||||||
|
set $AddBlankLines 0
|
||||||
|
IF 1
|
||||||
|
INCLUDE [filedir()]/if2.rem
|
||||||
5
tests/if2.rem
Normal file
5
tests/if2.rem
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Another unmatched IF
|
||||||
|
IF 0
|
||||||
|
ELSE
|
||||||
|
IF 1
|
||||||
|
|
||||||
6
tests/queue1.rem
Normal file
6
tests/queue1.rem
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
FSET msgprefix(x) "Priority: " + x + "; Filename: " + filename() + ": "
|
||||||
|
|
||||||
|
REM at 23:56 MSG foo
|
||||||
|
REM PRIORITY 42 at 23:57 MSG bar
|
||||||
|
REM PRIORITY 999 at 23:58 MSQ quux
|
||||||
|
DO queue2.rem
|
||||||
1
tests/queue2.rem
Normal file
1
tests/queue2.rem
Normal file
@@ -0,0 +1 @@
|
|||||||
|
REM at 23:59 PRIORITY 2 MSG XXXX
|
||||||
133
tests/test-rem
133
tests/test-rem
@@ -7,7 +7,7 @@
|
|||||||
# in the build directory.
|
# in the build directory.
|
||||||
#
|
#
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# Copyright (C) 1992-2023 Dianne Skoll
|
# Copyright (C) 1992-2024 Dianne Skoll
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -31,6 +31,15 @@ fi
|
|||||||
TZ=UTC
|
TZ=UTC
|
||||||
export TZ
|
export TZ
|
||||||
|
|
||||||
|
RESULT=`(echo 'BANNER %'; echo 'IF now() > 23:55'; echo 'MSG late%'; echo 'ENDIF') | ../src/remind -h -`
|
||||||
|
|
||||||
|
if test "$RESULT" = "late" ; then
|
||||||
|
echo ""
|
||||||
|
echo "*** Please do not run the test suite between 23:55 and 00:00 UTC; it will fail."
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# If we're already in a utf-8 locale, do
|
# If we're already in a utf-8 locale, do
|
||||||
# nothing; otherwise, set LC_ALL
|
# nothing; otherwise, set LC_ALL
|
||||||
OK=0
|
OK=0
|
||||||
@@ -167,7 +176,7 @@ REM 1 Jan 2012 AT 10:00 MSG 10am: Should show up
|
|||||||
MSG [$DontTrigAts]
|
MSG [$DontTrigAts]
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# An OMITFUNC should indicate nonconst_expr
|
# OMITFUNC should indicate nonconst_expr
|
||||||
../src/remind -pp - 1 jan 2012 9:00 <<'EOF' >> ../tests/test.out 2>&1
|
../src/remind -pp - 1 jan 2012 9:00 <<'EOF' >> ../tests/test.out 2>&1
|
||||||
REM Mon OMITFUNC foo MSG bar
|
REM Mon OMITFUNC foo MSG bar
|
||||||
EOF
|
EOF
|
||||||
@@ -440,6 +449,126 @@ rm -rf include_dir/ww
|
|||||||
# Test --version long option
|
# Test --version long option
|
||||||
../src/remind --version >> ../tests/test.out 2>&1
|
../src/remind --version >> ../tests/test.out 2>&1
|
||||||
|
|
||||||
|
# Test queueing. Because eventstart depends on the actual system
|
||||||
|
# date, we have to convert it to some constant (in this case,
|
||||||
|
# VOLATILE) so that tests are not dependent on the system date.
|
||||||
|
echo JSONQUEUE | ../src/remind -z0 ../tests/queue1.rem 2>&1 | sed -e 's/"eventstart":"................"/"eventstart":"VOLATILE"/g' | sed -e 's/"qid":"[0-9a-f]*",//g' >> ../tests/test.out 2>&1
|
||||||
|
echo QUEUE | ../src/remind -zj ../tests/queue1.rem 2>&1 | sed -e 's/"eventstart":"................"/"eventstart":"VOLATILE"/g' | sed -e 's/"qid":"[0-9a-f]*",//g' >> ../tests/test.out 2>&1
|
||||||
|
|
||||||
|
# Test for leap year bug that was fixed
|
||||||
|
../src/remind -dte - 28 Feb 2024 <<'EOF' >> ../tests/test.out 2>&1
|
||||||
|
BANNER %
|
||||||
|
REM 29 MSG One
|
||||||
|
REM 29 Feb MSG two
|
||||||
|
REM 29 2024 MSG three
|
||||||
|
REM 29 Feb 2024 MSG four
|
||||||
|
REM Thursday 29 MSG One
|
||||||
|
REM Thursday 29 Feb MSG two
|
||||||
|
REM Thursday 29 2024 MSG three
|
||||||
|
REM Thursday 29 Feb 2024 MSG four
|
||||||
|
REM Wednesday 29 MSG One
|
||||||
|
REM Wednesday 29 Feb MSG two
|
||||||
|
REM Wednesday 29 2024 MSG three
|
||||||
|
REM Wednesday 29 Feb 2024 MSG four
|
||||||
|
REM Friday 29 MSG One
|
||||||
|
REM Friday 29 Feb MSG two
|
||||||
|
REM Friday 29 2024 MSG three
|
||||||
|
REM Friday 29 Feb 2024 MSG four
|
||||||
|
EOF
|
||||||
|
|
||||||
|
../src/remind -dte - 1 Mar 2024 <<'EOF' >> ../tests/test.out 2>&1
|
||||||
|
BANNER %
|
||||||
|
REM 29 MSG One
|
||||||
|
REM 29 Feb MSG two
|
||||||
|
REM 29 2024 MSG three
|
||||||
|
REM 29 Feb 2024 MSG four
|
||||||
|
REM Thursday 29 MSG One
|
||||||
|
REM Thursday 29 Feb MSG two
|
||||||
|
REM Thursday 29 2024 MSG three
|
||||||
|
REM Thursday 29 Feb 2024 MSG four
|
||||||
|
REM Wednesday 29 MSG One
|
||||||
|
REM Wednesday 29 Feb MSG two
|
||||||
|
REM Wednesday 29 2024 MSG three
|
||||||
|
REM Wednesday 29 Feb 2024 MSG four
|
||||||
|
REM Friday 29 MSG One
|
||||||
|
REM Friday 29 Feb MSG two
|
||||||
|
REM Friday 29 2024 MSG three
|
||||||
|
REM Friday 29 Feb 2024 MSG four
|
||||||
|
EOF
|
||||||
|
|
||||||
|
../src/remind -dte - 28 Feb 2025 <<'EOF' >> ../tests/test.out 2>&1
|
||||||
|
BANNER %
|
||||||
|
REM 29 MSG One
|
||||||
|
REM 29 Feb MSG two
|
||||||
|
REM 29 2025 MSG three
|
||||||
|
REM 29 Feb 2025 MSG four
|
||||||
|
REM Thursday 29 MSG One
|
||||||
|
REM Thursday 29 Feb MSG two
|
||||||
|
REM Thursday 29 2025 MSG three
|
||||||
|
REM Thursday 29 Feb 2025 MSG four
|
||||||
|
REM Wednesday 29 MSG One
|
||||||
|
REM Wednesday 29 Feb MSG two
|
||||||
|
REM Wednesday 29 2025 MSG three
|
||||||
|
REM Wednesday 29 Feb 2025 MSG four
|
||||||
|
REM Friday 29 MSG One
|
||||||
|
REM Friday 29 Feb MSG two
|
||||||
|
REM Friday 29 2025 MSG three
|
||||||
|
REM Friday 29 Feb 2025 MSG four
|
||||||
|
EOF
|
||||||
|
|
||||||
|
../src/remind -dte - 1 Mar 2025 <<'EOF' >> ../tests/test.out 2>&1
|
||||||
|
BANNER %
|
||||||
|
REM 29 MSG One
|
||||||
|
REM 29 Feb MSG two
|
||||||
|
REM 29 2025 MSG three
|
||||||
|
REM 29 Feb 2025 MSG four
|
||||||
|
REM Thursday 29 MSG One
|
||||||
|
REM Thursday 29 Feb MSG two
|
||||||
|
REM Thursday 29 2025 MSG three
|
||||||
|
REM Thursday 29 Feb 2025 MSG four
|
||||||
|
REM Wednesday 29 MSG One
|
||||||
|
REM Wednesday 29 Feb MSG two
|
||||||
|
REM Wednesday 29 2025 MSG three
|
||||||
|
REM Wednesday 29 Feb 2025 MSG four
|
||||||
|
REM Friday 29 MSG One
|
||||||
|
REM Friday 29 Feb MSG two
|
||||||
|
REM Friday 29 2025 MSG three
|
||||||
|
REM Friday 29 Feb 2025 MSG four
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
(echo 'BANNER %'; echo 'REM 29 MSG No bug') | ../src/remind -dt - 29 Feb 2024 >> ../tests/test.out 2>&1
|
||||||
|
|
||||||
|
../src/remind -ifoo - <<'EOF' >> ../tests/test.out 2>&1
|
||||||
|
BANNER %
|
||||||
|
DUMP
|
||||||
|
EOF
|
||||||
|
|
||||||
|
../src/remind '-i$AddBlankLines' - <<'EOF' >> ../tests/test.out 2>&1
|
||||||
|
BANNER %
|
||||||
|
DUMP
|
||||||
|
EOF
|
||||||
|
|
||||||
|
../src/remind ../tests/expr.rem >> ../tests/test.out 2>&1
|
||||||
|
|
||||||
|
../src/remind - <<'EOF' >> ../tests/test.out 2>&1
|
||||||
|
PUSH
|
||||||
|
POP
|
||||||
|
PUSH
|
||||||
|
PUSH
|
||||||
|
POP
|
||||||
|
POP
|
||||||
|
PUSH
|
||||||
|
PUSH
|
||||||
|
POP
|
||||||
|
PUSH
|
||||||
|
POP
|
||||||
|
PUSH
|
||||||
|
POP
|
||||||
|
EOF
|
||||||
|
|
||||||
|
../src/remind ../tests/if1.rem 2020-03-03 >> ../tests/test.out 2>&1
|
||||||
|
|
||||||
# Remove references to SysInclude, which is build-specific
|
# Remove references to SysInclude, which is build-specific
|
||||||
grep -F -v '$SysInclude' < ../tests/test.out > ../tests/test.out.1 && mv -f ../tests/test.out.1 ../tests/test.out
|
grep -F -v '$SysInclude' < ../tests/test.out > ../tests/test.out.1 && mv -f ../tests/test.out.1 ../tests/test.out
|
||||||
cmp -s ../tests/test.out ../tests/test.cmp
|
cmp -s ../tests/test.out ../tests/test.cmp
|
||||||
|
|||||||
2770
tests/test.cmp
2770
tests/test.cmp
File diff suppressed because one or more lines are too long
@@ -329,6 +329,7 @@ set a052 time(1+2, 3+4)
|
|||||||
rem 10 jan 1992 AT 11:22 CAL
|
rem 10 jan 1992 AT 11:22 CAL
|
||||||
set a053 trigdate()
|
set a053 trigdate()
|
||||||
set a054 trigtime()
|
set a054 trigtime()
|
||||||
|
set a054b $Tt
|
||||||
set a055 trigvalid()
|
set a055 trigvalid()
|
||||||
set a056 upper("sdfjhsdf ksjdfh kjsdfh ksjdfh")
|
set a056 upper("sdfjhsdf ksjdfh kjsdfh ksjdfh")
|
||||||
set a057 value("a05"+"6")
|
set a057 value("a05"+"6")
|
||||||
@@ -381,9 +382,11 @@ msg [a076]%
|
|||||||
set a077 dosubst("%*Y %*Z", '1992/5/5')
|
set a077 dosubst("%*Y %*Z", '1992/5/5')
|
||||||
msg [a077]%
|
msg [a077]%
|
||||||
set a078 easterdate(today())
|
set a078 easterdate(today())
|
||||||
|
set a078 easterdate()
|
||||||
set a079 easterdate(1992)
|
set a079 easterdate(1992)
|
||||||
set a080 easterdate(1995)
|
set a080 easterdate(1995)
|
||||||
set a078 orthodoxeaster(today())
|
set a078 orthodoxeaster(today())
|
||||||
|
set a078 orthodoxeaster()
|
||||||
set a079 orthodoxeaster(1992)
|
set a079 orthodoxeaster(1992)
|
||||||
set a080 orthodoxeaster(1995)
|
set a080 orthodoxeaster(1995)
|
||||||
set a080 orthodoxeaster(2023)
|
set a080 orthodoxeaster(2023)
|
||||||
@@ -455,6 +458,7 @@ set a129 23:30 + '2019-02-02@16:44'
|
|||||||
REM 13 AT 16:00 DURATION 72:00 MSG 72-hour event
|
REM 13 AT 16:00 DURATION 72:00 MSG 72-hour event
|
||||||
set a130 trigdate()
|
set a130 trigdate()
|
||||||
set a131 trigtime()
|
set a131 trigtime()
|
||||||
|
set a131b $Tt
|
||||||
set a132 trigdatetime()
|
set a132 trigdatetime()
|
||||||
set a133 trigduration()
|
set a133 trigduration()
|
||||||
set a134 trigeventstart()
|
set a134 trigeventstart()
|
||||||
@@ -773,15 +777,27 @@ ENDIF
|
|||||||
# Trig with a good warnfunc
|
# Trig with a good warnfunc
|
||||||
FSET w(x) choose(x, 5, 3, 1, 0)
|
FSET w(x) choose(x, 5, 3, 1, 0)
|
||||||
|
|
||||||
# Ugh. This is where short-circuit logical operators
|
Short-circuit operators
|
||||||
# would really come in handy.
|
|
||||||
IF trig("sun warn w") || trig("thu warn w")
|
IF trig("sun warn w") || trig("thu warn w")
|
||||||
REM [trig()] +5 MSG Foo %b
|
REM [trig()] +5 MSG Foo %b
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
|
IF trig("thu warn w") || trig("sun warn w")
|
||||||
|
REM [trig()] +5 MSG Foo %b
|
||||||
|
ENDIF
|
||||||
|
|
||||||
REM [trig("Mon", "Tue", "Wed", "Sat")] MSG foo
|
REM [trig("Mon", "Tue", "Wed", "Sat")] MSG foo
|
||||||
REM [trig("Mon", "Tue", "Wed")] MSG bar
|
REM [trig("Mon", "Tue", "Wed")] MSG bar
|
||||||
|
|
||||||
|
# Multitrig
|
||||||
|
REM [multitrig("10", "17")] MSG multitrig-1
|
||||||
|
REM [multitrig("Feb 15", "Mar 20")] MSG multitrig-2
|
||||||
|
REM [multitrig("Oct 7 1992", "1991")] MSG multitrig-3
|
||||||
|
REM [multitrig("16 Feb AFTER OMIT Sat Sun", "29 March")] MSG multitrig-4
|
||||||
|
REM [multitrig("2", "3", "5", "7")] MSG multitrig-5
|
||||||
|
REM [multitrig("15 SCANFROM -7", "14 SCANFROM -7")] MSG multitrig-6
|
||||||
|
REM [multitrig("15 SCANFROM -7", "14 SCANFROM -7")] SCANFROM -7 MSG multitrig-7
|
||||||
|
|
||||||
# The new syntactic sugar
|
# The new syntactic sugar
|
||||||
REM First Monday January MSG x
|
REM First Monday January MSG x
|
||||||
REM Second Tuesday in April MSG x
|
REM Second Tuesday in April MSG x
|
||||||
@@ -882,11 +898,53 @@ set a htmlstriptags("this is > whut <b>foo</b>")
|
|||||||
set a htmlstriptags("<img src=\"foo\">")
|
set a htmlstriptags("<img src=\"foo\">")
|
||||||
|
|
||||||
# $ParseUntriggered
|
# $ParseUntriggered
|
||||||
REM 2 Jan 1990 MSG ["bad_expr" * 2]
|
REM 2 Jan 1990 MSG ["bad_expr" / 2]
|
||||||
SET $ParseUntriggered 0
|
SET $ParseUntriggered 0
|
||||||
REM 2 Jan 1990 MSG ["bad_expr" * 2]
|
REM 2 Jan 1990 MSG ["bad_expr" / 2]
|
||||||
SET $ParseUntriggered 1
|
SET $ParseUntriggered 1
|
||||||
|
|
||||||
|
# String multiplication
|
||||||
|
|
||||||
|
set a "low" * (-1)
|
||||||
|
set a (-1) * "low"
|
||||||
|
|
||||||
|
set a "zero" * 0
|
||||||
|
set a 0 * "zero"
|
||||||
|
|
||||||
|
set a "" * 10000000
|
||||||
|
set a 10000000 * ""
|
||||||
|
|
||||||
|
# Too long for default limits
|
||||||
|
set a "wookie" * 1000000
|
||||||
|
set a 1000000 * "wookie"
|
||||||
|
|
||||||
|
set a "Cabbage! " * 7
|
||||||
|
set a 7 * "Cabbage! "
|
||||||
|
|
||||||
|
# Should result in errors
|
||||||
|
set pqxya 1+2)
|
||||||
|
|
||||||
|
# Should result in an error
|
||||||
|
REM Tue OMIT 2024-01-01 MSG Wookie
|
||||||
|
|
||||||
|
# No error
|
||||||
|
REM Tue OMIT Wed 2024-01-01 MSG Blort
|
||||||
|
|
||||||
|
# Make sure trigtime() is not reset between invocations
|
||||||
|
REM Tue AT 16:00 DURATION 30 MSG Thing One
|
||||||
|
REM [$T] AT [trigtime()+trigduration()] DURATION 15 MSG Thing Two
|
||||||
|
REM [$T] AT [$Tt+trigduration()] DURATION 30 MSG Thing Three
|
||||||
|
REM [$T] AT [trigtime()+trigduration()] DURATION 10 MSG Last Thing
|
||||||
|
|
||||||
|
# Make sure trigtime is not reset during parsing
|
||||||
|
REM Tue AT 16:00 MSG blort
|
||||||
|
REM Tue AT 10:00 DURATION [$Tt] MSG blort
|
||||||
|
REM Tue AT 16:00 MSG blort
|
||||||
|
REM Tue AT 10:00 DURATION [trigtime()] MSG blort
|
||||||
|
|
||||||
|
# Make sure shellescape does not mangle UTF-8 characters
|
||||||
|
msg [shellescape("😆")]
|
||||||
|
|
||||||
# Don't want Remind to queue reminders
|
# Don't want Remind to queue reminders
|
||||||
EXIT
|
EXIT
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
# Use the output to verify your translations.
|
# Use the output to verify your translations.
|
||||||
#
|
#
|
||||||
# This file is part of REMIND.
|
# This file is part of REMIND.
|
||||||
# Copyright (C) 1992-2023 Dianne Skoll
|
# Copyright (C) 1992-2024 Dianne Skoll
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
#
|
#
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user