mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-17 14:59:20 +02:00
Compare commits
365 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6c166ae0c | ||
|
|
e9c89b770f | ||
|
|
df6298bd63 | ||
|
|
739d285e36 | ||
|
|
ee1c931932 | ||
|
|
0806b6738f | ||
|
|
020e82d575 | ||
|
|
a20f2b588e | ||
|
|
631e721a96 | ||
|
|
8453e17c6c | ||
|
|
76c1e2abb3 | ||
|
|
3389f1c91b | ||
|
|
b2d47ae979 | ||
|
|
e2c615f310 | ||
|
|
e8492a4303 | ||
|
|
4695efaabd | ||
|
|
c433f42587 | ||
|
|
4708e59a43 | ||
|
|
d56ac6332a | ||
|
|
b054baf590 | ||
|
|
42f5e3467d | ||
|
|
97013ae89b | ||
|
|
2acead9118 | ||
|
|
a53a80acb4 | ||
|
|
56e62b1b4d | ||
|
|
c645db5ede | ||
|
|
ef6b9c3783 | ||
|
|
019bee26cb | ||
|
|
152cd4090b | ||
|
|
b7fc2b5776 | ||
|
|
723aba9b7c | ||
|
|
8a5b88338b | ||
|
|
7236441e02 | ||
|
|
e4bab0dda4 | ||
|
|
5b7d4a07ec | ||
|
|
8c3d2c4003 | ||
|
|
f485d607ff | ||
|
|
a0effa5f0b | ||
|
|
7d501cda6f | ||
|
|
5d7f55c8d5 | ||
|
|
097bf92bea | ||
|
|
b9dea59206 | ||
|
|
46aa144b65 | ||
|
|
914971308d | ||
|
|
a22e81040f | ||
|
|
72f74f03cf | ||
|
|
d0e45e727e | ||
|
|
ce2b2e80da | ||
|
|
11771b7d3d | ||
|
|
01cb028532 | ||
|
|
58b6f43b9c | ||
|
|
1dedb667e8 | ||
|
|
8a96236788 | ||
|
|
2a13163659 | ||
|
|
336a9684d4 | ||
|
|
86945c6e18 | ||
|
|
684280db5e | ||
|
|
d801408933 | ||
|
|
79b3da3820 | ||
|
|
ed021d3f46 | ||
|
|
27d0fda280 | ||
|
|
ef12da4ec6 | ||
|
|
7b098e95ad | ||
|
|
7d13f4b09e | ||
|
|
cecdfe6ade | ||
|
|
216bbd6378 | ||
|
|
30e2e9c633 | ||
|
|
bf2aabd610 | ||
|
|
c019221d15 | ||
|
|
b7bd6faf07 | ||
|
|
80d58220fe | ||
|
|
cd8624e176 | ||
|
|
8515fb7ddd | ||
|
|
84f9f4ae0a | ||
|
|
e201ebcfa4 | ||
|
|
4e15c3ec35 | ||
|
|
1adccf9b1f | ||
|
|
a1aa5c2ad9 | ||
|
|
1e0d650737 | ||
|
|
553d092ca8 | ||
|
|
dc62841517 | ||
|
|
326e7bfc53 | ||
|
|
b9dc7c16ad | ||
|
|
abd54b016b | ||
|
|
db02b54067 | ||
|
|
40a78dfbbb | ||
|
|
c860b46baa | ||
|
|
1458ba8856 | ||
|
|
7b9b6ebc96 | ||
|
|
7ee4073c7a | ||
|
|
8c072cd9b6 | ||
|
|
b794a45c3f | ||
|
|
98e491ed1d | ||
|
|
c397cc06da | ||
|
|
8616236b3c | ||
|
|
702704af1a | ||
|
|
a0d1b19050 | ||
|
|
a5c8ae491c | ||
|
|
b3cf741d15 | ||
|
|
0b28dde9c7 | ||
|
|
5a3980b5b8 | ||
|
|
a8e33118d6 | ||
|
|
2223277f64 | ||
|
|
c72413e3c1 | ||
|
|
fa1033db6f | ||
|
|
61e3edd2ac | ||
|
|
093c97ff91 | ||
|
|
6e64b175aa | ||
|
|
09dba4bc94 | ||
|
|
2e443ac5b7 | ||
|
|
59a8c88178 | ||
|
|
40eab03d84 | ||
|
|
e993bf59cf | ||
|
|
c6de5a2c8f | ||
|
|
51cc939d0c | ||
|
|
c857192e6d | ||
|
|
4591c2b181 | ||
|
|
7843a1b2ba | ||
|
|
649481cf01 | ||
|
|
c253bdfcbe | ||
|
|
1910808fd7 | ||
|
|
1d8cb9749e | ||
|
|
e3f9380fcd | ||
|
|
326c3f59b0 | ||
|
|
03f1c5a047 | ||
|
|
02122491c3 | ||
|
|
735f6f5686 | ||
|
|
ac033d75c0 | ||
|
|
e2185e773a | ||
|
|
d9ae417e01 | ||
|
|
e1d0948538 | ||
|
|
357ddf285a | ||
|
|
41859fc484 | ||
|
|
07275e71b0 | ||
|
|
f68521cb95 | ||
|
|
526610bdd2 | ||
|
|
973e3448ae | ||
|
|
9a3f28f6fc | ||
|
|
a3e32d2dc4 | ||
|
|
a8b78eff00 | ||
|
|
460db83298 | ||
|
|
4560712778 | ||
|
|
ce8803dde9 | ||
|
|
60ca5d45e3 | ||
|
|
4454613d00 | ||
|
|
0704808500 | ||
|
|
166b1ac499 | ||
|
|
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 |
2
.gitignore
vendored
2
.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
|
||||||
@@ -32,3 +33,4 @@ src/version.h
|
|||||||
tests/test.out
|
tests/test.out
|
||||||
www/Makefile
|
www/Makefile
|
||||||
gmon.out
|
gmon.out
|
||||||
|
tests/once.timestamp
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
30
build.tk
30
build.tk
@@ -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:
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
@@ -727,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"]
|
||||||
@@ -745,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"
|
||||||
}
|
}
|
||||||
@@ -764,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.06.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# 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.06'
|
||||||
PACKAGE_STRING=''
|
PACKAGE_STRING='remind 05.00.06'
|
||||||
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.06 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.06:";;
|
||||||
|
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.06
|
||||||
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.06, 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.09
|
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.06, 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.06
|
||||||
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.06, , , 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.09
|
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
|
||||||
|
|||||||
3
contrib/ical2rem-0.7/GITHUB
Normal file
3
contrib/ical2rem-0.7/GITHUB
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
The upstream GitHub project for ical2rem is:
|
||||||
|
|
||||||
|
https://github.com/jbalcorn/ical2rem
|
||||||
21
contrib/ical2rem-0.7/LICENSE
Normal file
21
contrib/ical2rem-0.7/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Justin B. Alcorn
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
103
contrib/ical2rem-0.7/README.md
Normal file
103
contrib/ical2rem-0.7/README.md
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# ical2rem
|
||||||
|
The original iCal to Remind script, first released in 2005.
|
||||||
|
|
||||||
|
Reads iCal files and outputs remind-compatible files. Tested ONLY with
|
||||||
|
calendar files created by Mozilla Calendar/Sunbird. Use at your own risk.
|
||||||
|
|
||||||
|
## License
|
||||||
|
In 2005, this was released with the Gnu Public License V2. However, I am changing it to the MIT License, since that provides greater freedom to do with this code what you want.
|
||||||
|
|
||||||
|
Copyright (c) 2005, 2007, 2019 Justin B. Alcorn
|
||||||
|
|
||||||
|
## How I use Remind and Google Calendar together
|
||||||
|
|
||||||
|
- My family has a Google Email domain, and our email addresses all end in the same domain. We all use Google Calendars and I want to mail reminders to each of the family members containing both Google Calendar and .reminder information.
|
||||||
|
- Under my ~/.rem/ directory each family member has a directory. Each directory contains a standard remind file called 'reminders' that at the very least has the line "INCLUDE /home/jalcorn/.rem/<username>/ical2rem" and flag files indicating whether they want Daily or Weekly reminders. My reminders files references my standard .reminders file, and I also have a flag so if I run a Test run I'll get it. There's actually a lot more files (I have a big family).
|
||||||
|
````
|
||||||
|
./rem
|
||||||
|
./son1:
|
||||||
|
drwxrwxr-x 2 jalcorn jalcorn 4096 Dec 12 14:02 .
|
||||||
|
drwxr-xr-x 12 jalcorn jalcorn 4096 Dec 12 14:13 ..
|
||||||
|
-rw-rw-r-- 1 jalcorn jalcorn 51 Mar 3 06:10 ical2rem
|
||||||
|
lrwxrwxrwx 1 jalcorn jalcorn 33 Oct 27 2016 son1.ics -> /home/jalcorn/calendars/son1.ics
|
||||||
|
-rw-rw-r-- 1 jalcorn jalcorn 976 Dec 12 14:02 reminders
|
||||||
|
-rw-rw-r-- 1 jalcorn jalcorn 0 Oct 27 2016 Weekly
|
||||||
|
|
||||||
|
./justin:
|
||||||
|
drwxrwxr-x 2 jalcorn jalcorn 4096 Feb 27 08:29 .
|
||||||
|
drwxr-xr-x 12 jalcorn jalcorn 4096 Dec 12 14:13 ..
|
||||||
|
lrwxrwxrwx 1 jalcorn jalcorn 32 Oct 27 2016 son1.ics -> /home/jalcorn/calendars/son1.ics
|
||||||
|
-rw-rw-r-- 1 jalcorn jalcorn 0 Nov 7 2016 Daily
|
||||||
|
lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 family.ics -> /home/jalcorn/calendars/family.ics
|
||||||
|
-rw-rw-r-- 1 jalcorn jalcorn 37320 Mar 3 06:10 ical2rem
|
||||||
|
lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 justin.ics -> /home/jalcorn/calendars/justin.ics
|
||||||
|
lrwxrwxrwx 1 jalcorn jalcorn 24 Nov 7 2016 reminders -> /home/jalcorn/.reminders
|
||||||
|
lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 vmd.ics -> /home/jalcorn/calendars/vmd.ics
|
||||||
|
-rw-rw-r-- 1 jalcorn jalcorn 0 Oct 27 2016 Test
|
||||||
|
-rw-rw-r-- 1 jalcorn jalcorn 0 Nov 7 2016 Weekly
|
||||||
|
````
|
||||||
|
- bin/getgooglecals.sh runs out of crontab and downloads whatever calendars I want. Note that we can also download organization calendars, I've included a public one here (Cleveland Heights Vocal Music Department calendar).
|
||||||
|
- dailyreminders.sh is linked to weeklyreminders.sh and testreminders.sh so I can run it in different modes. The concatenate the various calendar outputs as a single remind file then send the reminders via email.
|
||||||
|
### Example: .rem/son1/reminders file:
|
||||||
|
````
|
||||||
|
INCLUDE /home/jalcorn/.rem/defs.rem
|
||||||
|
INCLUDE /home/jalcorn/.rem/float
|
||||||
|
INCLUDE /home/jalcorn/.rem/son1/ical2rem
|
||||||
|
fset _weeks() coerce("STRING", (trigdate()-today())/7) + plural((trigdate()-today())/7, " week")
|
||||||
|
FSET _sfun(x) choose(x, -60, 30, 5, 0)
|
||||||
|
FSET oldfloat(y,m,d) trigger(MAX(realtoday(), date(y,m,d)))
|
||||||
|
FSET due(y,m,d) "(" + (date(y,m,d)-trigdate()) + ")"
|
||||||
|
SET fullmoon moondate(2)
|
||||||
|
REM [trigger(realtoday())] SPECIAL SHADE 145 70 100 %
|
||||||
|
REM [float(2019,4,15,105)] MSG File tax return [due(2017,4,15)]%
|
||||||
|
REM PRIORITY 9999 MSG %"%"%
|
||||||
|
INCLUDE /home/jalcorn/.rem/bdays
|
||||||
|
SET $LongDeg 81
|
||||||
|
SET $LongMin 11
|
||||||
|
SET $LongSec 11
|
||||||
|
SET $LatDeg 41
|
||||||
|
SET $LatMin 11
|
||||||
|
SET $LatSec 11
|
||||||
|
REM [trigger(moondate(2))] +1 MSG %"Full Moon%" %b%
|
||||||
|
fset _srtd() coerce("STRING", _no_lz(_am_pm(sunrise(today()))))
|
||||||
|
fset _sstd() coerce("STRING", _no_lz(_am_pm(sunset(today()))))
|
||||||
|
MSG Sun is up today from [_srtd()] to [_sstd()].%"%"%
|
||||||
|
````
|
||||||
|
## Revision History
|
||||||
|
### Version 0.7 2024-09-04
|
||||||
|
- ISSUE 8: New version of remind complains if _sfun isn't defined. Output a header
|
||||||
|
to define a function that does nothing if the function doesn't exist.
|
||||||
|
### Version 0.6 2019-03-01
|
||||||
|
- Publish on GitHub and change license to MIT License
|
||||||
|
- Add supporting files and explanation of how I use it
|
||||||
|
### version 0.5.2 2007-03-23
|
||||||
|
- BUG: leadtime for recurring events had a max of 4 instead of DEFAULT_LEAD_TIME
|
||||||
|
- remove project-lead-time, since Category was a non-standard attribute
|
||||||
|
- NOTE: There is a bug in iCal::Parser v1.14 that causes multiple calendars to
|
||||||
|
fail if a calendar with recurring events is followed by a calendar with no
|
||||||
|
recurring events. This has been reported to the iCal::Parser author.
|
||||||
|
### version 0.5.1 2007-03-21
|
||||||
|
- BUG: Handle multiple calendars on STDIN
|
||||||
|
- add --heading option for priority on section headers
|
||||||
|
### version 0.5 2007-03-21
|
||||||
|
- Add more help options
|
||||||
|
- --project-lead-time option
|
||||||
|
- Supress printing of heading if there are no todos to print
|
||||||
|
### version 0.4
|
||||||
|
- Version 0.4 changes all written or inspired by, and thanks to Mark Stosberg
|
||||||
|
- Change to GetOptions
|
||||||
|
- Change to pipe
|
||||||
|
- Add --label, --help options
|
||||||
|
- Add Help Text
|
||||||
|
- Change to subroutines
|
||||||
|
- Efficiency and Cleanup
|
||||||
|
### version 0.3
|
||||||
|
- Convert to GPL (Thanks to Mark Stosberg)
|
||||||
|
- Add usage
|
||||||
|
### version 0.2
|
||||||
|
- add command line switches
|
||||||
|
- add debug code
|
||||||
|
- add SCHED _sfun keyword
|
||||||
|
- fix typos
|
||||||
|
### version 0.1 - ALPHA CODE.
|
||||||
|
|
||||||
82
contrib/ical2rem-0.7/cal_futureonly.pl
Normal file
82
contrib/ical2rem-0.7/cal_futureonly.pl
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
#
|
||||||
|
# cal_futureonly.pl -
|
||||||
|
# Reads iCal files and outputs events between 1 month ago and 1 year from now.
|
||||||
|
# Copyright (c) 2005, 2007, 2019 Justin B. Alcorn
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
cal_futureonly.pl --file=filname.ics > output.ics
|
||||||
|
|
||||||
|
--help Usage
|
||||||
|
--man Complete man page
|
||||||
|
--infile (REQUIRED) name of input calendar file
|
||||||
|
--file (REQUIRED) name of output calendar file
|
||||||
|
|
||||||
|
Expects an ICAL stream on STDIN. Converts it to the format
|
||||||
|
used by the C<remind> script and prints it to STDOUT.
|
||||||
|
|
||||||
|
=head2 --infile
|
||||||
|
|
||||||
|
Input file
|
||||||
|
|
||||||
|
=head2 --file
|
||||||
|
|
||||||
|
Output File
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Data::ICal;
|
||||||
|
use Data::ICal::Entry;
|
||||||
|
use DateTime::Span;
|
||||||
|
use Data::ICal::DateTime;
|
||||||
|
use DateTime;
|
||||||
|
use Getopt::Long 2.24 qw':config auto_help';
|
||||||
|
use Pod::Usage;
|
||||||
|
use Data::Dumper;
|
||||||
|
use vars '$VERSION';
|
||||||
|
$VERSION = "0.1";
|
||||||
|
|
||||||
|
my $help;
|
||||||
|
my $man;
|
||||||
|
my $infile;
|
||||||
|
my $file;
|
||||||
|
my $debug = 0;
|
||||||
|
|
||||||
|
GetOptions (
|
||||||
|
"help|?" => \$help,
|
||||||
|
"man" => \$man,
|
||||||
|
"debug" => \$debug,
|
||||||
|
"infile=s" => \$infile,
|
||||||
|
"file=s" => \$file
|
||||||
|
);
|
||||||
|
pod2usage(1) if $help;
|
||||||
|
pod2usage(1) if (! $file);
|
||||||
|
pod2usage(-verbose => 2) if $man;
|
||||||
|
|
||||||
|
my $limit = DateTime->now();
|
||||||
|
$limit->subtract( months => 1);
|
||||||
|
my $endlimit = DateTime->now()->add(years =>1);
|
||||||
|
print STDERR "including events from: ",$limit->ymd," to: ".$endlimit->ymd,"\n" if $debug;
|
||||||
|
my $span = DateTime::Span->from_datetimes( start => $limit, end => $endlimit );
|
||||||
|
print STDERR "Parsing $infile\n" if $debug;
|
||||||
|
my $cal = Data::ICal->new(filename => $infile);
|
||||||
|
if (! $cal) {
|
||||||
|
die "Died Trying to read $infile :".$cal->error_message;
|
||||||
|
}
|
||||||
|
#my $archive = Data::ICal->new(filename => 'archive.ics');
|
||||||
|
print "Output = $file\n" if $debug;
|
||||||
|
my $new = Data::ICal->new();
|
||||||
|
if (! $new) {
|
||||||
|
die $new->error_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
my @events = $cal->events($span);
|
||||||
|
$new->add_entries(@events);
|
||||||
|
|
||||||
|
open(NEW, ">$file");
|
||||||
|
print NEW $new->as_string;
|
||||||
|
close NEW;
|
||||||
|
exit 0;
|
||||||
|
#:vim set ft=perl ts=4 sts=4 expandtab :
|
||||||
45
contrib/ical2rem-0.7/dailyreminders.sh
Normal file
45
contrib/ical2rem-0.7/dailyreminders.sh
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
r=`basename $0`
|
||||||
|
|
||||||
|
if [ $r == 'weeklyreminders.sh' ];
|
||||||
|
then
|
||||||
|
t=14;
|
||||||
|
w=Weekly;
|
||||||
|
elif [ $r == 'dailyreminders.sh' ];
|
||||||
|
then
|
||||||
|
t=3;
|
||||||
|
w=Daily;
|
||||||
|
else
|
||||||
|
t=5
|
||||||
|
w=Test;
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd .rem
|
||||||
|
for d in * ;
|
||||||
|
do
|
||||||
|
if [ "$( ls -A $d/$w 2>/dev/null )" ];
|
||||||
|
then
|
||||||
|
echo "Sending a $w reminder to $d"
|
||||||
|
ft=/tmp/$d-t-$$.txt
|
||||||
|
f=/tmp/$d-$$.txt
|
||||||
|
echo "Reminders for next $t days:" >> $f
|
||||||
|
cat /dev/null > $d/ical2rem
|
||||||
|
for c in $d/*.ics
|
||||||
|
do
|
||||||
|
calname=`basename $c .ics | tr a-z A-Z`
|
||||||
|
cat $c 2>/dev/null | sed -e "s/^SUMMARY:/SUMMARY: {${calname}} /" \
|
||||||
|
| sed -e 's/DT\([A-Z]*\);TZID=UTC:\([0-9T]*\)/DT\1:\2Z/' >> $ft
|
||||||
|
done
|
||||||
|
cat $ft | ~/bin/ical2rem.pl --label "Online Calendar" --heading "PRIORITY 9999" --lead-time $t >> $d/ical2rem
|
||||||
|
if [ -e $d/reminders ];then r="${d}/reminders"; else r="${d}/ical2rem";fi
|
||||||
|
/usr/bin/remind -q -iplain=1 $r >> $f
|
||||||
|
echo "
|
||||||
|
All calendars can be accessed by logging into https://calendar.google.com/ as $d@jalcorn.net
|
||||||
|
" >> $f
|
||||||
|
cat $f | mail -s "$w Reminders for $d" $d@jalcorn.net;
|
||||||
|
cat $f
|
||||||
|
rm $f
|
||||||
|
rm $ft
|
||||||
|
fi;
|
||||||
|
done
|
||||||
21
contrib/ical2rem-0.7/getgooglecals.sh
Normal file
21
contrib/ical2rem-0.7/getgooglecals.sh
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Get google calendars, fix issues caused by changes in Google calendars, and remove all past events.
|
||||||
|
#
|
||||||
|
# Obviously, I've removed the private hashes from private calendars.
|
||||||
|
#
|
||||||
|
cd ~/calendars
|
||||||
|
wget -q -O full/justin.ics --no-check-certificate https://www.google.com/calendar/ical/jbalcorn\%40gmail.com/private-aaaaaaaaaaaaaaaaaaaaaaaaaa/basic.ics
|
||||||
|
wget -q -O full/family.ics --no-check-certificate https://www.google.com/calendar/ical/jalcorn.net_aaaaaaaaaaaaaaaaaaaaaaaaaa\%40group.calendar.google.com/private-6c42a79dec0b3b3bb7b9b0ebf9776bc1/basic.ics
|
||||||
|
wget -q -O full/son1.ics --no-check-certificate https://www.google.com/calendar/ical/son1\%40jalcorn.net/private-aaaaaaaaaaaaaaaaaaaaaaaaaa/basic.ics
|
||||||
|
wget -q -O full/vmd.ics --no-check-certificate https://calendar.google.com/calendar/ical/chuh.org_0pmkefjkiqc4snoel7occlslh8%40group.calendar.google.com/public/basic.ics
|
||||||
|
|
||||||
|
for i in full/*.ics;do
|
||||||
|
cat $i 2>/dev/null | sed -e 's/DT\([A-Z]*\);TZID=UTC:\([0-9T]*\)/DT\1:\2Z/' > /tmp/temp.ics
|
||||||
|
cp /tmp/temp.ics $i
|
||||||
|
done
|
||||||
|
|
||||||
|
~/bin/cal_futureonly.pl --infile=full/justin.ics --file=justin.ics
|
||||||
|
~/bin/cal_futureonly.pl --infile=full/family.ics --file=family.ics
|
||||||
|
~/bin/cal_futureonly.pl --infile=full/son1.ics --file=son1.ics
|
||||||
|
~/bin/cal_futureonly.pl --infile=full/vmd.ics --file=vmd.ics
|
||||||
@@ -19,7 +19,8 @@
|
|||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
#
|
# version 0.6 2019-03-01
|
||||||
|
# - Updates to put on GitHub
|
||||||
# version 0.5.2 2007-03-23
|
# version 0.5.2 2007-03-23
|
||||||
# - BUG: leadtime for recurring events had a max of 4 instead of DEFAULT_LEAD_TIME
|
# - BUG: leadtime for recurring events had a max of 4 instead of DEFAULT_LEAD_TIME
|
||||||
# - remove project-lead-time, since Category was a non-standard attribute
|
# - remove project-lead-time, since Category was a non-standard attribute
|
||||||
@@ -32,7 +33,7 @@
|
|||||||
# version 0.5 2007-03-21
|
# version 0.5 2007-03-21
|
||||||
# - Add more help options
|
# - Add more help options
|
||||||
# - --project-lead-time option
|
# - --project-lead-time option
|
||||||
# - Suppress printing of heading if there are no todos to print
|
# - Supress printing of heading if there are no todos to print
|
||||||
# version 0.4
|
# version 0.4
|
||||||
# - Version 0.4 changes all written or inspired by, and thanks to Mark Stosberg
|
# - Version 0.4 changes all written or inspired by, and thanks to Mark Stosberg
|
||||||
# - Change to GetOptions
|
# - Change to GetOptions
|
||||||
@@ -56,12 +57,19 @@
|
|||||||
cat /path/to/file*.ics | ical2rem.pl > ~/.ical2rem
|
cat /path/to/file*.ics | ical2rem.pl > ~/.ical2rem
|
||||||
|
|
||||||
All options have reasonable defaults:
|
All options have reasonable defaults:
|
||||||
--label Calendar name (Default: Calendar)
|
--label Calendar name (Default: Calendar)
|
||||||
|
--start Start of time period to parse (parsed by str2time)
|
||||||
|
--end End of time period to parse
|
||||||
--lead-time Advance days to start reminders (Default: 3)
|
--lead-time Advance days to start reminders (Default: 3)
|
||||||
--todos, --no-todos Process Todos? (Default: Yes)
|
--todos, --no-todos Process Todos? (Default: Yes)
|
||||||
--heading Define a priority for static entries
|
--iso8601 Use YYYY-MM-DD date format
|
||||||
--help Usage
|
--locations, --no-locations Include location? (Default: Yes)
|
||||||
--man Complete man page
|
--end-times, --no-end-times Include event end times in reminder text
|
||||||
|
(Default: No)
|
||||||
|
--heading Define a priority for static entries
|
||||||
|
--help Usage
|
||||||
|
--debug Enable debug output
|
||||||
|
--man Complete man page
|
||||||
|
|
||||||
Expects an ICAL stream on STDIN. Converts it to the format
|
Expects an ICAL stream on STDIN. Converts it to the format
|
||||||
used by the C<remind> script and prints it to STDOUT.
|
used by the C<remind> script and prints it to STDOUT.
|
||||||
@@ -74,6 +82,14 @@ The syntax generated includes a label for the calendar parsed.
|
|||||||
By default this is "Calendar". You can customize this with
|
By default this is "Calendar". You can customize this with
|
||||||
the "--label" option.
|
the "--label" option.
|
||||||
|
|
||||||
|
=head2 --iso8601
|
||||||
|
|
||||||
|
Use YYYY-MM-DD date format in output instead of Mmm DD YYYY
|
||||||
|
|
||||||
|
=head2 --locations, --no-locations
|
||||||
|
|
||||||
|
Whether or not to include locations in events
|
||||||
|
|
||||||
=head2 --lead-time
|
=head2 --lead-time
|
||||||
|
|
||||||
ical2rem.pl --lead-time 3
|
ical2rem.pl --lead-time 3
|
||||||
@@ -84,7 +100,7 @@ How may days in advance to start getting reminders about the events. Defaults to
|
|||||||
|
|
||||||
ical2rem.pl --no-todos
|
ical2rem.pl --no-todos
|
||||||
|
|
||||||
If you don't care about the ToDos the calendar, this will suppress
|
If you don't care about the ToDos the calendar, this will surpress
|
||||||
printing of the ToDo heading, as well as skipping ToDo processing.
|
printing of the ToDo heading, as well as skipping ToDo processing.
|
||||||
|
|
||||||
=head2 --heading
|
=head2 --heading
|
||||||
@@ -98,6 +114,7 @@ the calendar entries. See the file defs.rem from the remind distribution for mo
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use iCal::Parser;
|
use iCal::Parser;
|
||||||
|
use Date::Parse;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use Getopt::Long 2.24 qw':config auto_help';
|
use Getopt::Long 2.24 qw':config auto_help';
|
||||||
use Pod::Usage;
|
use Pod::Usage;
|
||||||
@@ -108,19 +125,31 @@ $VERSION = "0.5.2";
|
|||||||
# Declare how many days in advance to remind
|
# Declare how many days in advance to remind
|
||||||
my $DEFAULT_LEAD_TIME = 3;
|
my $DEFAULT_LEAD_TIME = 3;
|
||||||
my $PROCESS_TODOS = 1;
|
my $PROCESS_TODOS = 1;
|
||||||
my $HEADING = "";
|
my $HEADING = "";
|
||||||
my $help;
|
my $help;
|
||||||
|
my $debug;
|
||||||
my $man;
|
my $man;
|
||||||
|
my $iso8601;
|
||||||
|
my $do_location = 1;
|
||||||
|
my $do_end_times;
|
||||||
|
my $start;
|
||||||
|
my $end;
|
||||||
|
|
||||||
my $label = 'Calendar';
|
my $label = 'Calendar';
|
||||||
GetOptions (
|
GetOptions (
|
||||||
"label=s" => \$label,
|
"label=s" => \$label,
|
||||||
|
"start=s" => \$start,
|
||||||
|
"end=s" => \$end,
|
||||||
"lead-time=i" => \$DEFAULT_LEAD_TIME,
|
"lead-time=i" => \$DEFAULT_LEAD_TIME,
|
||||||
"todos!" => \$PROCESS_TODOS,
|
"todos!" => \$PROCESS_TODOS,
|
||||||
|
"iso8601!" => \$iso8601,
|
||||||
|
"locations!" => \$do_location,
|
||||||
|
"end-times!" => \$do_end_times,
|
||||||
"heading=s" => \$HEADING,
|
"heading=s" => \$HEADING,
|
||||||
"help|?" => \$help,
|
"help|?" => \$help,
|
||||||
|
"debug" => \$debug,
|
||||||
"man" => \$man
|
"man" => \$man
|
||||||
);
|
) or pod2usage(1);
|
||||||
pod2usage(1) if $help;
|
pod2usage(1) if $help;
|
||||||
pod2usage(-verbose => 2) if $man;
|
pod2usage(-verbose => 2) if $man;
|
||||||
|
|
||||||
@@ -136,8 +165,22 @@ while (<>) {
|
|||||||
$in = "";
|
$in = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
my $parser = iCal::Parser->new();
|
print STDERR "Read all calendars\n" if $debug;
|
||||||
|
my(%parser_opts) = ("debug" => $debug);
|
||||||
|
if ($start) {
|
||||||
|
my $t = str2time($start);
|
||||||
|
die "Invalid time $start\n" if (! $t);
|
||||||
|
$parser_opts{'start'} = DateTime->from_epoch(epoch => $t);
|
||||||
|
}
|
||||||
|
if ($end) {
|
||||||
|
my $t = str2time($end);
|
||||||
|
die "Invalid time $end\n" if (! $t);
|
||||||
|
$parser_opts{'end'} = DateTime->from_epoch(epoch => $t);
|
||||||
|
}
|
||||||
|
print STDERR "About to parse calendars\n" if $debug;
|
||||||
|
my $parser = iCal::Parser->new(%parser_opts);
|
||||||
my $hash = $parser->parse_strings(@calendars);
|
my $hash = $parser->parse_strings(@calendars);
|
||||||
|
print STDERR "Calendars parsed\n" if $debug;
|
||||||
|
|
||||||
##############################################################
|
##############################################################
|
||||||
#
|
#
|
||||||
@@ -209,6 +252,13 @@ sub _process_todos {
|
|||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
# Issue 8 https://github.com/jbalcorn/ical2rem/issues/8
|
||||||
|
# Make sure there is a _sfun function declared in the reminder file. We'll just make it do nothing here.
|
||||||
|
print 'IF args("_sfun") < 1
|
||||||
|
FSET _sfun(x) choose(x,0)
|
||||||
|
ENDIF
|
||||||
|
';
|
||||||
|
|
||||||
print _process_todos($hash->{'todos'}) if $PROCESS_TODOS;
|
print _process_todos($hash->{'todos'}) if $PROCESS_TODOS;
|
||||||
|
|
||||||
my ($leadtime, $yearkey, $monkey, $daykey,$uid,%eventsbyuid);
|
my ($leadtime, $yearkey, $monkey, $daykey,$uid,%eventsbyuid);
|
||||||
@@ -260,20 +310,67 @@ foreach $yearkey (sort keys %{$events} ) {
|
|||||||
$leadtime = "+".$DEFAULT_LEAD_TIME;
|
$leadtime = "+".$DEFAULT_LEAD_TIME;
|
||||||
}
|
}
|
||||||
my $start = $event->{'DTSTART'};
|
my $start = $event->{'DTSTART'};
|
||||||
print "REM ".$start->month_abbr." ".$start->day." ".$start->year." $leadtime ";
|
my $end = $event->{'DTEND'};
|
||||||
if ($start->hour > 0) {
|
my $duration = "";
|
||||||
print " AT ";
|
if ($end and ($start->hour or $start->minute or $end->hour or $end->minute)) {
|
||||||
print $start->strftime("%H:%M");
|
# We need both an HH:MM version of the delta, to put in the
|
||||||
print " SCHED _sfun MSG %a %2 ";
|
# DURATION specifier, and a human-readable version of the
|
||||||
} else {
|
# delta, to put in the message if the user requested it.
|
||||||
print " MSG %a ";
|
my $seconds = $end->epoch - $start->epoch;
|
||||||
|
my $minutes = int($seconds / 60);
|
||||||
|
my $hours = int($minutes / 60);
|
||||||
|
$minutes -= $hours * 60;
|
||||||
|
$duration = sprintf("DURATION %d:%02d ", $hours, $minutes);
|
||||||
}
|
}
|
||||||
print "%\"$event->{'SUMMARY'}";
|
print "REM ";
|
||||||
print " at $event->{'LOCATION'}" if $event->{'LOCATION'};
|
if ($iso8601) {
|
||||||
print "\%\"%\n";
|
print $start->strftime("%F ");
|
||||||
|
} else {
|
||||||
|
print $start->month_abbr." ".$start->day." ".$start->year." ";
|
||||||
|
}
|
||||||
|
print "$leadtime ";
|
||||||
|
if ($duration or $start->hour > 0 or $start->minute > 0) {
|
||||||
|
print "AT ";
|
||||||
|
print $start->strftime("%H:%M");
|
||||||
|
print " SCHED _sfun ${duration}MSG %a %2 ";
|
||||||
|
} else {
|
||||||
|
print "MSG %a ";
|
||||||
|
}
|
||||||
|
print "%\"", "e($event->{'SUMMARY'});
|
||||||
|
print(" at ", "e($event->{'LOCATION'}))
|
||||||
|
if ($do_location and $event->{'LOCATION'});
|
||||||
|
print "\%\"";
|
||||||
|
if ($do_end_times and ($start->hour or $start->minute or
|
||||||
|
$end->hour or $end->minute)) {
|
||||||
|
my $start_date = $start->strftime("%F");
|
||||||
|
my $start_time = $start->strftime("%k:%M");
|
||||||
|
my $end_date = $end->strftime("%F");
|
||||||
|
my $end_time = $end->strftime("%k:%M");
|
||||||
|
# We don't want leading whitespace; some strftime's support
|
||||||
|
# disabling the pdding in the format string, but not all,
|
||||||
|
# so for maximum portability we do it ourselves.
|
||||||
|
$start_time =~ s/^\s+//;
|
||||||
|
$end_time =~ s/^\s+//;
|
||||||
|
my(@pieces);
|
||||||
|
if ($start_date ne $end_date) {
|
||||||
|
push(@pieces, $end_date);
|
||||||
|
}
|
||||||
|
if ($start_time ne $end_time) {
|
||||||
|
push(@pieces, $end_time);
|
||||||
|
}
|
||||||
|
print " (-", join(" ", @pieces), ")";
|
||||||
|
}
|
||||||
|
print "%\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub quote {
|
||||||
|
local($_) = @_;
|
||||||
|
s/\[/["["]/g;
|
||||||
|
return $_;
|
||||||
|
}
|
||||||
|
|
||||||
exit 0;
|
exit 0;
|
||||||
#:vim set ft=perl ts=4 sts=4 expandtab :
|
#:vim set ft=perl ts=4 sts=4 expandtab :
|
||||||
@@ -109,18 +109,15 @@
|
|||||||
|
|
||||||
(defconst remind-keywords
|
(defconst remind-keywords
|
||||||
(sort
|
(sort
|
||||||
(list "ADDOMIT" "AFTER" "AT" "BANNER" "BEFORE"
|
(list "ADDOMIT" "AFTER" "AT" "BAN" "BANNER" "BEFORE" "CAL" "CLEAR"
|
||||||
"CAL" "CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMPVARS"
|
"CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMP" "DUMPVARS" "DURATION" "ELSE"
|
||||||
"DURATION" "ELSE" "ENDIF" "ERRMSG" "EXIT" "FIRST"
|
"ENDIF" "ERRMSG" "EXIT" "EXPR" "FIRST" "FLUSH" "FOURTH" "FROM" "FSET"
|
||||||
"FLUSH" "FOURTH" "FROM" "FSET" "IF" "IFTRIG" "IN"
|
"FUNSET" "IF" "IFTRIG" "IN" "INC" "INCLUDE" "INCLUDECMD" "LAST"
|
||||||
"INCLUDE" "INCLUDECMD" "LAST" "LASTDAY"
|
"LASTDAY" "LASTWORKDAY" "MAYBE" "MAYBE-UNCOMPUTABLE" "MSF" "MSG"
|
||||||
"LASTWORKDAY" "MAYBE-UNCOMPUTABLE" "MSF"
|
"NOQUEUE" "OMIT" "OMITFUNC" "ONCE" "POP" "POP-OMIT-CONTEXT" "PRESERVE"
|
||||||
"MSG" "OMIT" "OMITFUNC" "ONCE"
|
"PRIORITY" "PS" "PSFILE" "PUSH" "PUSH-OMIT-CONTEXT" "REM" "RUN"
|
||||||
"POP-OMIT-CONTEXT" "PRESERVE" "PRIORITY" "PS" "PSFILE"
|
"SATISFY" "SCAN" "SCANFROM" "SCHED" "SECOND" "SET" "SKIP" "SPECIAL"
|
||||||
"PUSH-OMIT-CONTEXT" "REM" "RUN" "SATISFY" "SCANFROM"
|
"TAG" "THIRD" "THROUGH" "UNSET" "UNTIL" "WARN")
|
||||||
"SCHED" "SECOND" "SET" "SKIP" "SPECIAL"
|
|
||||||
"TAG" "THIRD" "THROUGH" "UNSET" "UNTIL"
|
|
||||||
"WARN")
|
|
||||||
#'(lambda (a b) (> (length a) (length b)))))
|
#'(lambda (a b) (> (length a) (length b)))))
|
||||||
|
|
||||||
|
|
||||||
@@ -131,50 +128,57 @@
|
|||||||
|
|
||||||
(defconst remind-builtin-variables
|
(defconst remind-builtin-variables
|
||||||
(sort
|
(sort
|
||||||
(list "$Ago" "$Am" "$And" "$April" "$At" "$August" "$CalcUTC" "$CalMode" "$Daemon" "$DateSep"
|
(list "$AddBlankLines" "$Ago" "$Am" "$And" "$April" "$At" "$August"
|
||||||
"$DateTimeSep" "$December" "$DefaultColor" "$DefaultPrio"
|
"$CalcUTC" "$CalMode" "$Daemon" "$DateSep" "$DateTimeSep" "$December"
|
||||||
"$DefaultTDelta" "$DeltaOffset" "$DontFork" "$DontQueue"
|
"$DefaultColor" "$DefaultPrio" "$DefaultTDelta" "$DeltaOverride"
|
||||||
"$DontTrigAts" "$EndSent" "$EndSentIg" "$February" "$FirstIndent"
|
"$DontFork" "$DontQueue" "$DontTrigAts" "$EndSent" "$EndSentIg"
|
||||||
"$FoldYear" "$FormWidth" "$Friday" "$Fromnow" "$Hour" "$Hplu" "$HushMode" "$IgnoreOnce"
|
"$ExpressionTimeLimit" "$February" "$FirstIndent" "$FoldYear"
|
||||||
"$InfDelta" "$IntMax" "$IntMin" "$Is" "$January" "$July" "$June" "$LatDeg"
|
"$FormWidth" "$Friday" "$Fromnow" "$Hour" "$Hplu" "$HushMode"
|
||||||
"$Latitude" "$LatMin" "$LatSec" "$Location" "$LongDeg" "$Longitude"
|
"$IgnoreOnce" "$InfDelta" "$IntMax" "$IntMin" "$Is" "$January" "$July"
|
||||||
"$LongMin" "$LongSec" "$March" "$MaxSatIter" "$MaxStringLen" "$May"
|
"$June" "$LatDeg" "$Latitude" "$LatMin" "$LatSec" "$Location"
|
||||||
"$MinsFromUTC" "$Minute" "$Monday" "$Mplu" "$NextMode" "$November" "$Now" "$NumQueued"
|
"$LongDeg" "$Longitude" "$LongMin" "$LongSec" "$March" "$MaxFullOmits"
|
||||||
"$NumTrig" "$October" "$On" "$Pm" "$PrefixLineNo" "$PSCal" "$RunOff" "$Saturday"
|
"$MaxLateMinutes" "$MaxPartialOmits" "$MaxSatIter" "$MaxStringLen"
|
||||||
"$September" "$SimpleCal" "$SortByDate" "$SortByPrio" "$SortByTime"
|
"$May" "$MinsFromUTC" "$Minute" "$Monday" "$Mplu" "$NextMode"
|
||||||
"$SubsIndent" "$Sunday" "$SysInclude" "$T" "$Td" "$Thursday" "$TimeSep" "$Tm"
|
"$November" "$Now" "$NumFullOmits" "$NumPartialOmits" "$NumQueued"
|
||||||
"$Today" "$Tomorrow" "$Tuesday" "$Tw" "$Ty" "$U" "$Ud" "$Um" "$UntimedFirst" "$Uw" "$Uy"
|
"$NumTrig" "$October" "$On" "$OnceFile" "$ParseUntriggered" "$Pm"
|
||||||
"$Was" "$Wednesday")
|
"$PrefixLineNo" "$PSCal" "$RunOff" "$Saturday" "$September"
|
||||||
|
"$SimpleCal" "$SortByDate" "$SortByPrio" "$SortByTime" "$SubsIndent"
|
||||||
|
"$Sunday" "$SuppressImplicitWarnings" "$SuppressLRM" "$SysInclude" "$T" "$Td"
|
||||||
|
"$TerminalBackground" "$Thursday" "$TimeSep" "$Tm" "$Today"
|
||||||
|
"$Tomorrow" "$Tt" "$Tuesday" "$Tw" "$Ty" "$U" "$Ud" "$Um"
|
||||||
|
"$UntimedFirst" "$Use256Colors" "$UseBGVTColors" "$UseTrueColors"
|
||||||
|
"$UseVTColors" "$Uw" "$Uy" "$Was" "$Wednesday")
|
||||||
#'(lambda (a b) (> (length a) (length b)))))
|
#'(lambda (a b) (> (length a) (length b)))))
|
||||||
|
|
||||||
|
|
||||||
(defconst remind-time-words
|
(defconst remind-time-words
|
||||||
(sort
|
(sort
|
||||||
(list "Jan" "January" "Feb" "Mar" "Apr" "Jun" "Jul" "Aug" "Sept" "Sep" "Oct" "Nov" "Dec"
|
(list "Apr" "April" "Aug" "August" "Dec" "December" "Feb" "February"
|
||||||
"February" "March" "April" "May" "June" "July" "August" "September" "October"
|
"Jan" "January" "Jul" "July" "Jun" "June" "Mar" "March" "May"
|
||||||
"November" "December" "Mon" "Monday" "Tue" "Tues" "Tuesday" "Wed" "Wednesday"
|
"Nov" "November" "Oct" "October" "Sep" "September" "Fri"
|
||||||
"Thu" "Thursday" "Thurs" "Fri" "Friday" "Saturday" "Sat" "Sun" "Sunday")
|
"Friday" "Mon" "Monday" "Sat" "Saturday" "Sun" "Sunday" "Thu"
|
||||||
|
"Thursday" "Tue" "Tuesday" "Wed" "Wednesday")
|
||||||
#'(lambda (a b) (> (length a) (length b)))))
|
#'(lambda (a b) (> (length a) (length b)))))
|
||||||
|
|
||||||
|
|
||||||
(defconst remind-builtin-functions
|
(defconst remind-builtin-functions
|
||||||
(sort
|
(sort
|
||||||
(list "abs" "access" "adawn" "adusk" "ampm" "args" "asc" "baseyr" "char"
|
(list "abs" "access" "adawn" "adusk" "ampm" "ansicolor" "args" "asc"
|
||||||
"choose" "coerce" "current" "date" "datepart" "datetime" "dawn" "day"
|
"baseyr" "char" "choose" "coerce" "columns" "current" "date"
|
||||||
"daysinmon" "defined" "dosubst" "dusk" "easterdate" "evaltrig"
|
"datepart" "datetime" "dawn" "day" "daysinmon" "defined" "dosubst"
|
||||||
"filedate" "filedatetime" "filedir" "filename" "getenv" "hebdate"
|
"dusk" "easterdate" "evaltrig" "filedate" "filedatetime" "filedir"
|
||||||
"hebday" "hebmon" "hebyear" "hour" "iif" "index" "isany" "isdst"
|
"filename" "getenv" "hebdate" "hebday" "hebmon" "hebyear" "hour"
|
||||||
"isleap" "isomitted" "language" "lower" "max" "min" "minsfromutc"
|
"htmlescape" "htmlstriptags" "iif" "index" "isany" "isdst" "isleap"
|
||||||
|
"isomitted" "language" "localtoutc" "lower" "max" "min" "minsfromutc"
|
||||||
"minute" "mon" "monnum" "moondate" "moondatetime" "moonphase"
|
"minute" "mon" "monnum" "moondate" "moondatetime" "moonphase"
|
||||||
"moontime" "ndawn" "ndusk" "nonomitted" "now" "ord" "ostype" "pad" "plural"
|
"moontime" "multitrig" "ndawn" "ndusk" "nonomitted" "now" "ord"
|
||||||
"psmoon" "psshade" "realcurrent" "realnow" "realtoday" "sgn" "shell"
|
"orthodoxeaster" "ostype" "pad" "plural" "psmoon" "psshade"
|
||||||
"shellescape" "slide" "strlen" "substr" "sunrise" "sunset" "time"
|
"realcurrent" "realnow" "realtoday" "rows" "sgn" "shell" "shellescape"
|
||||||
"timepart" "today" "trig" "trigback" "trigdate" "trigdatetime"
|
"slide" "soleq" "stdout" "strlen" "substr" "sunrise" "sunset" "time"
|
||||||
"trigdelta" "trigduration" "trigeventduration" "trigeventstart"
|
"timepart" "timezone" "today" "trig" "trigback" "trigdate"
|
||||||
"trigfrom" "trigger" "trigpriority" "trigrep" "trigscanfrom"
|
"trigdatetime" "trigdelta" "trigduration" "trigeventduration"
|
||||||
"trigtime" "trigtimedelta" "trigtimerep" "triguntil" "trigvalid"
|
"trigeventstart" "trigfrom" "trigger" "trigpriority" "trigrep"
|
||||||
"typeof" "tzconvert" "upper" "value" "version" "weekno" "wkday"
|
"trigscanfrom" "trigtags" "trigtime" "trigtimedelta" "trigtimerep"
|
||||||
"wkdaynum" "year")
|
"triguntil" "trigvalid" "typeof" "tzconvert" "upper" "utctolocal"
|
||||||
|
"value" "version" "weekno" "wkday" "wkdaynum" "year")
|
||||||
#'(lambda (a b) (> (length a) (length b)))))
|
#'(lambda (a b) (> (length a) (length b)))))
|
||||||
|
|
||||||
;;; faces
|
;;; faces
|
||||||
@@ -290,7 +294,7 @@
|
|||||||
|
|
||||||
(defconst remind-conf-font-lock-keywords-1
|
(defconst remind-conf-font-lock-keywords-1
|
||||||
(list
|
(list
|
||||||
'("^[\;\#]\\s-+.*$" . remind-comment-face)
|
'("^\s*[\;\#].*$" . remind-comment-face)
|
||||||
'(remind-keywords-matcher . remind-conf-keyword-face)
|
'(remind-keywords-matcher . remind-conf-keyword-face)
|
||||||
'("%[\"_]" . font-lock-warning-face)
|
'("%[\"_]" . font-lock-warning-face)
|
||||||
'("\\(%[a-mops-w]\\)" . remind-conf-substitutes-face)
|
'("\\(%[a-mops-w]\\)" . remind-conf-substitutes-face)
|
||||||
|
|||||||
@@ -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 -------------
|
||||||
|
|||||||
502
docs/WHATSNEW
502
docs/WHATSNEW
@@ -1,5 +1,391 @@
|
|||||||
CHANGES TO REMIND
|
CHANGES TO REMIND
|
||||||
|
|
||||||
|
* VERSION 5.0 Patch 6 - 2024-09-16
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: Include a file containing the dates of Chinese
|
||||||
|
New Year through 2050.
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: Add $SuppressImplicitWarnings system variable.
|
||||||
|
Setting this to 1 suppresses the warnings "Unrecognized command;
|
||||||
|
interpreting as REM" and "Missing REM type; assuming MSG"
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: Add --print-tokens command-line argument. This
|
||||||
|
simply prints all of Remind's built-in tokens, functions, and system
|
||||||
|
variables. It's designed to help people who are writing editor
|
||||||
|
add-ons for syntax highlighting.
|
||||||
|
|
||||||
|
- CHANGE: remind: allow '12:34' to be parsed as a TIME constant. This
|
||||||
|
matches DATEs and DATETIMEs which are enclosed in single-quotes.
|
||||||
|
(The quotes are optional for TIME constants, however.)
|
||||||
|
|
||||||
|
- IMPROVEMENT: Improve many error emssages and warnings.
|
||||||
|
|
||||||
|
- UPDATE: contrib/ical2rem: Update to upstream version 0.7
|
||||||
|
|
||||||
|
- IMPROVEMENT: contrib/remind-conf-mode: Improve the Emacs
|
||||||
|
remind-conf-mode package. Add new keywords and make comment
|
||||||
|
highlighting correct.
|
||||||
|
|
||||||
|
- FIX: remind man page: Remove note saying REM can be omitted.
|
||||||
|
|
||||||
|
* VERSION 5.0 Patch 5 - 2024-09-02
|
||||||
|
|
||||||
|
- CHANGE: remind: When using the "-c" option and with the SHADE special
|
||||||
|
enabled, shade the entire calendar box including the line containing the
|
||||||
|
day number.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Better error messages when diagnosing certain
|
||||||
|
errors in expressions.
|
||||||
|
|
||||||
|
- IMPROVEMENT: include/holidays/jewish.rem: Remove unnecessary _h()
|
||||||
|
function definition.
|
||||||
|
|
||||||
|
- BUG FIX: remind: In a couple of spots when we parsed a character, we did
|
||||||
|
not check for an error return. This has been fixed.
|
||||||
|
|
||||||
|
- BUG FIX: remind: Fix edge-case bugs in "remind -c" output formatting.
|
||||||
|
|
||||||
|
- BUG FIX: make test: Fix a test that was broken for all of September 2024.
|
||||||
|
|
||||||
|
- BUG FIX: remind: Fix a couple of potential file-descriptor leaks.
|
||||||
|
|
||||||
|
- BUG FIX: contrib/ical2rem.pl: Replace "SCHED _sfun" with "+15" to
|
||||||
|
hard-code 15-minutes advance warning rather than using an undefined
|
||||||
|
scheduling function. If this is not what you want, you should edit
|
||||||
|
ical2rem.pl to suit your taste; it's not officially part of Remind and
|
||||||
|
is meant more as a starting point for you to customize than a finished
|
||||||
|
product.
|
||||||
|
|
||||||
|
- DOCUMENTATION FIX: Remove obsolete info from Remind man page.
|
||||||
|
|
||||||
|
* VERSION 5.0 Patch 4 - 2024-08-29
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: When checking if a SATISFY expression refers to the
|
||||||
|
trigger date, look recursively at any user-defined functions it calls.
|
||||||
|
This reduces spurious warnings.
|
||||||
|
|
||||||
|
- CHANGE: remind: Allow any type to be used as the test argument for IIF.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind man page: Clarify how various types are treated
|
||||||
|
in boolean context.
|
||||||
|
|
||||||
|
* VERSION 5.0 Patch 3 - 2024-08-28
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Preserve newlines ("%_" sequences) in calendar
|
||||||
|
mode in most cases. See the remind man page for details.
|
||||||
|
|
||||||
|
- IMPROVEMENT: rem2pdf: rem2pdf can now produce PostScript and
|
||||||
|
Encapsulated PostScript output in addition to PDF and SVG.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Emit warnings if a subst_XXX function takes the
|
||||||
|
wrong number of arguments, or for custom sequences, if the function
|
||||||
|
is not defined.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Emit warnings if WARN/SCHED/OMITFUNC functions
|
||||||
|
do not reference their argument.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Allow strings to be used with logical
|
||||||
|
operators. The empty string "" is considered false and all other
|
||||||
|
strings are considered true.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Emit warnings for lines that are implicitly
|
||||||
|
treated as REM commands; add warnings for REM commands that are
|
||||||
|
implicitly treated as MSG-type reminders.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Add an optional fourth argument to the built-in
|
||||||
|
ampm() function that specifies not to suppress a leading zero in the
|
||||||
|
hour component.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: If a SATISFY expression is not constant and
|
||||||
|
doesn't reference the trigger date somehow, issue a warning.
|
||||||
|
|
||||||
|
- IMPROVEMENT: remind: Add a warning if a user-defined function is
|
||||||
|
redefined. If you do have a use-case that requires you to redefine
|
||||||
|
a function, simply FUNSET it first before FSETting it for the second
|
||||||
|
time.
|
||||||
|
|
||||||
|
- DOCUMENTATION FIX: Clarify man pages and remove some information that
|
||||||
|
has become incorrect as Remind has evolved.
|
||||||
|
|
||||||
|
- BUG FIX: Fix typos in man pages
|
||||||
|
|
||||||
|
* VERSION 5.0 Patch 2 - 2024-07-26
|
||||||
|
|
||||||
|
- IMPROVEMENT: Remind: Revamp how ONCE works. You can now set a
|
||||||
|
special variable $OnceFile to be the path to a timestamp file. The
|
||||||
|
ONCE directive uses this timestamp file to track when it was last
|
||||||
|
run rather than the access date of the main reminder script. This
|
||||||
|
is more reliable because it doesn't rely on the atime of a file
|
||||||
|
(which might not be maintained accurately) and is not affected if
|
||||||
|
you edit your reminder script.
|
||||||
|
|
||||||
|
- CHANGE: Taking input from stdin no longer implies the "-o" option; ONCE can
|
||||||
|
work if you set $OnceFile
|
||||||
|
|
||||||
|
- CHANGE: Any of the -c, -n, -p and -s options implicitly enable the
|
||||||
|
-o option. As before, specifying a repeat factor *N or a date that
|
||||||
|
is not today on the command-line also implies -o.
|
||||||
|
|
||||||
|
- MINOR NEW FEATURE: Rem2PDF: Add the "--svg" command-line option to produce
|
||||||
|
SVG output rather than PDF.
|
||||||
|
|
||||||
|
- MINOR IMPROVEMENT: Remind: Improve the storage efficiency of short
|
||||||
|
string constants in compiled expression trees.
|
||||||
|
|
||||||
|
- MINOR IMPROVEMENT: Remind: Remove some obsolete macro definitions
|
||||||
|
|
||||||
|
* VERSION 5.0 Patch 1 - 2024-06-08
|
||||||
|
|
||||||
|
- MINOR IMPROVEMENT: Add short-circuit evaluation to the isany() function,
|
||||||
|
which now only evaluates those arguments absolutely necessary to determine
|
||||||
|
the result.
|
||||||
|
|
||||||
|
- BUG FIX: Mark weekno() as a non-constant function (the zero-argument form
|
||||||
|
depends on external conditions.)
|
||||||
|
|
||||||
|
- BUG FIX: Fix a couple of memory leaks.
|
||||||
|
|
||||||
|
- BUG FIX: Don't rely on support for unnamed function parameters; this caused
|
||||||
|
compilation failures with older versions of gcc.
|
||||||
|
|
||||||
|
* 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
|
* VERSION 4.2 Patch 9 - 2024-02-04
|
||||||
|
|
||||||
- CHANGE: remind: Do not attempt to guess terminal background color on
|
- CHANGE: remind: Do not attempt to guess terminal background color on
|
||||||
@@ -18,7 +404,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- MINOR NEW FEATURE: remind: The expression STRING * INT or INT * STRING
|
- MINOR NEW FEATURE: remind: The expression STRING * INT or INT * STRING
|
||||||
is now accepted and yields a string that is INT concatenations of the
|
is now accepted and yields a string that is INT concatenations of the
|
||||||
origina STRING. In this case, INT must be non-negative and the total
|
original STRING. In this case, INT must be non-negative and the total
|
||||||
string length can't exceed $MaxStringLen.
|
string length can't exceed $MaxStringLen.
|
||||||
|
|
||||||
- DOCUMENTATION: Add "Astronomical Algorithms" by Jean Meeus to bibliography.
|
- DOCUMENTATION: Add "Astronomical Algorithms" by Jean Meeus to bibliography.
|
||||||
@@ -910,7 +1296,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- MINOR IMPROVEMENT: Add the "ampm()" built-in function.
|
- MINOR IMPROVEMENT: Add the "ampm()" built-in function.
|
||||||
|
|
||||||
* Version 3.3 Patch 0 - 2020-01-31
|
* VERSION 3.3 Patch 0 - 2020-01-31
|
||||||
|
|
||||||
- FIX: rem2ps: Add a %%PageBoundingBox: document structuring convention
|
- FIX: rem2ps: Add a %%PageBoundingBox: document structuring convention
|
||||||
comment.
|
comment.
|
||||||
@@ -945,7 +1331,7 @@ CHANGES TO REMIND
|
|||||||
- CHANGE: SPECIALs are now case-insensitive. Before, only SPECIAL COLOR
|
- CHANGE: SPECIALs are now case-insensitive. Before, only SPECIAL COLOR
|
||||||
would work. Now you can use Special Color, special color, etc.
|
would work. Now you can use Special Color, special color, etc.
|
||||||
|
|
||||||
* Version 3.2 Patch 0 - 2020-01-03
|
* VERSION 3.2 Patch 0 - 2020-01-03
|
||||||
|
|
||||||
- IMPROVEMENT: Add support for events spanning multiple days (with AT
|
- IMPROVEMENT: Add support for events spanning multiple days (with AT
|
||||||
and DURATION). Add trigeventstart() and trigeventduration()
|
and DURATION). Add trigeventstart() and trigeventduration()
|
||||||
@@ -987,7 +1373,7 @@ CHANGES TO REMIND
|
|||||||
- BUG FIX: TkRemind: Fix startup failure of TkRemind if options are at
|
- BUG FIX: TkRemind: Fix startup failure of TkRemind if options are at
|
||||||
default. :(
|
default. :(
|
||||||
|
|
||||||
* Version 3.1 Patch 17 - 2019-11-15
|
* VERSION 3.1 Patch 17 - 2019-11-15
|
||||||
|
|
||||||
- IMPROVEMENT: Add "Extra Remind Options" setting to TkRemind.
|
- IMPROVEMENT: Add "Extra Remind Options" setting to TkRemind.
|
||||||
|
|
||||||
@@ -1004,7 +1390,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- BUG FIX: Fix various documentation errors and update man page.
|
- BUG FIX: Fix various documentation errors and update man page.
|
||||||
|
|
||||||
* Version 3.1 Patch 16 - 2018-11-09
|
* VERSION 3.1 Patch 16 - 2018-11-09
|
||||||
|
|
||||||
- IMPROVEMENT: Add patch from Stephen Morgan to calculate astronomical and
|
- IMPROVEMENT: Add patch from Stephen Morgan to calculate astronomical and
|
||||||
nautical twilight in addition to civil twilight.
|
nautical twilight in addition to civil twilight.
|
||||||
@@ -1034,7 +1420,7 @@ CHANGES TO REMIND
|
|||||||
- BUG FIX: In "remind -z0" mode, remind wakes up exactly on the minute instead
|
- BUG FIX: In "remind -z0" mode, remind wakes up exactly on the minute instead
|
||||||
of sleeping for 60 seconds each time, which could cause it to fall behind.
|
of sleeping for 60 seconds each time, which could cause it to fall behind.
|
||||||
|
|
||||||
* Version 3.1 Patch 15 - 2015-07-27
|
* VERSION 3.1 Patch 15 - 2015-07-27
|
||||||
|
|
||||||
- BUG FIX: Fix a buffer overflow found by Alexander Keller
|
- BUG FIX: Fix a buffer overflow found by Alexander Keller
|
||||||
|
|
||||||
@@ -1044,7 +1430,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- BUG FIX: Make parser reject repeated delta or *repeat values.
|
- BUG FIX: Make parser reject repeated delta or *repeat values.
|
||||||
|
|
||||||
* Version 3.1 Patch 14 - 2015-04-24
|
* VERSION 3.1 Patch 14 - 2015-04-24
|
||||||
|
|
||||||
- NEW FEATURE: Putting the line __EOF__ in a .rem file causes Remind
|
- NEW FEATURE: Putting the line __EOF__ in a .rem file causes Remind
|
||||||
to treat it as end-of-file.
|
to treat it as end-of-file.
|
||||||
@@ -1061,7 +1447,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- BUG FIX: Typo in Spanish translation was fixed.
|
- BUG FIX: Typo in Spanish translation was fixed.
|
||||||
|
|
||||||
* Version 3.1 Patch 13 - 2013-03-22
|
* VERSION 3.1 Patch 13 - 2013-03-22
|
||||||
|
|
||||||
- BUG FIX: Sunrise/Sunset calculations greatly improved thanks to John
|
- BUG FIX: Sunrise/Sunset calculations greatly improved thanks to John
|
||||||
McGowan. Accuracy should now be within a couple of minutes in most
|
McGowan. Accuracy should now be within a couple of minutes in most
|
||||||
@@ -1078,7 +1464,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- BUG FIX: Spurious test harness failure was fixed.
|
- BUG FIX: Spurious test harness failure was fixed.
|
||||||
|
|
||||||
* Version 3.1 Patch 12 - 2012-01-23
|
* VERSION 3.1 Patch 12 - 2012-01-23
|
||||||
|
|
||||||
- NEW FEATURE: Many substitution sequences "%x" have an alternate mode
|
- NEW FEATURE: Many substitution sequences "%x" have an alternate mode
|
||||||
denoted by "%*x". This alternate mode leaves out prepositions. For
|
denoted by "%*x". This alternate mode leaves out prepositions. For
|
||||||
@@ -1090,7 +1476,7 @@ CHANGES TO REMIND
|
|||||||
so the results may be off by a minute or two compared to previous versions
|
so the results may be off by a minute or two compared to previous versions
|
||||||
of Remind.
|
of Remind.
|
||||||
|
|
||||||
* Version 3.1 Patch 11 - 2011-12-16
|
* VERSION 3.1 Patch 11 - 2011-12-16
|
||||||
|
|
||||||
- BUG FIX: For some inexplicable reason, dawn was considered to happen when
|
- BUG FIX: For some inexplicable reason, dawn was considered to happen when
|
||||||
the sun was 14 degrees below the horizon instead of the standard 6
|
the sun was 14 degrees below the horizon instead of the standard 6
|
||||||
@@ -1104,7 +1490,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- BUG FIX: Apply minor Debian cleanups reported by Kurt B. Kaiser.
|
- BUG FIX: Apply minor Debian cleanups reported by Kurt B. Kaiser.
|
||||||
|
|
||||||
* Version 3.1 Patch 10 - 2010-11-01
|
* VERSION 3.1 Patch 10 - 2010-11-01
|
||||||
|
|
||||||
- NOTE: This is the 20th anniversary of Remind's first public release.
|
- NOTE: This is the 20th anniversary of Remind's first public release.
|
||||||
|
|
||||||
@@ -1128,7 +1514,7 @@ CHANGES TO REMIND
|
|||||||
- BUG FIX: Don't declare variables in the middle of statements (old C
|
- BUG FIX: Don't declare variables in the middle of statements (old C
|
||||||
compilers choke.)
|
compilers choke.)
|
||||||
|
|
||||||
* Version 3.1 Patch 9 - 2010-06-20
|
* VERSION 3.1 Patch 9 - 2010-06-20
|
||||||
|
|
||||||
- MAJOR ENHANCEMENT: New "purge mode" to delete expired reminders. See
|
- MAJOR ENHANCEMENT: New "purge mode" to delete expired reminders. See
|
||||||
the PURGE MODE section of the remind man page.
|
the PURGE MODE section of the remind man page.
|
||||||
@@ -1144,7 +1530,7 @@ CHANGES TO REMIND
|
|||||||
- BUG FIX: Yom HaShoah is moved to Thursday if it would normally fall on
|
- BUG FIX: Yom HaShoah is moved to Thursday if it would normally fall on
|
||||||
a Friday. Thanks to Jonathan Kamens for pointing this out.
|
a Friday. Thanks to Jonathan Kamens for pointing this out.
|
||||||
|
|
||||||
* Version 3.1 Patch 8 - 2010-03-09
|
* VERSION 3.1 Patch 8 - 2010-03-09
|
||||||
|
|
||||||
- ENHANCEMENT: Include some useful scripts in contrib/
|
- ENHANCEMENT: Include some useful scripts in contrib/
|
||||||
|
|
||||||
@@ -1164,7 +1550,7 @@ CHANGES TO REMIND
|
|||||||
- BUG FIX: Fix bug in SCHED calculations if Remind is started in the middle
|
- BUG FIX: Fix bug in SCHED calculations if Remind is started in the middle
|
||||||
of a SCHED interval.
|
of a SCHED interval.
|
||||||
|
|
||||||
* Version 3.1 Patch 7 - 2009-05-31
|
* VERSION 3.1 Patch 7 - 2009-05-31
|
||||||
|
|
||||||
- ENHANCEMENT: Wherever you could write "day Mon year", the parser now
|
- ENHANCEMENT: Wherever you could write "day Mon year", the parser now
|
||||||
accepts "YYYY-MM-DD". This applies on the command-line and to the
|
accepts "YYYY-MM-DD". This applies on the command-line and to the
|
||||||
@@ -1173,7 +1559,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- ENHANCEMENT: New slide() built-in function eases some complicated reminders.
|
- ENHANCEMENT: New slide() built-in function eases some complicated reminders.
|
||||||
|
|
||||||
* Version 3.1 Patch 6 - 2008-11-16
|
* VERSION 3.1 Patch 6 - 2008-11-16
|
||||||
|
|
||||||
- MAJOR ENHANCEMENT: A new OMITFUNC clause gives you additional
|
- MAJOR ENHANCEMENT: A new OMITFUNC clause gives you additional
|
||||||
control and flexibility over "omitted days" calculations. This is
|
control and flexibility over "omitted days" calculations. This is
|
||||||
@@ -1201,7 +1587,7 @@ CHANGES TO REMIND
|
|||||||
weekday would fail if it needed to cross a year boundary. This has
|
weekday would fail if it needed to cross a year boundary. This has
|
||||||
been fixed.
|
been fixed.
|
||||||
|
|
||||||
* Version 3.1 Patch 5 - 2008-04-15
|
* VERSION 3.1 Patch 5 - 2008-04-15
|
||||||
|
|
||||||
- MAJOR ENHANCEMENT: If you supply a directory name on the command line
|
- MAJOR ENHANCEMENT: If you supply a directory name on the command line
|
||||||
or for an INCLUDE command, then Remind reads all *.rem file in that
|
or for an INCLUDE command, then Remind reads all *.rem file in that
|
||||||
@@ -1231,7 +1617,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- BUG FIX: Parse error in calendar mode was fixed.
|
- BUG FIX: Parse error in calendar mode was fixed.
|
||||||
|
|
||||||
* Version 3.1 Patch 4 - 2008-02-03
|
* VERSION 3.1 Patch 4 - 2008-02-03
|
||||||
|
|
||||||
- ENHANCEMENT: tkremind respects the "-b1" option and operates in 24-hour
|
- ENHANCEMENT: tkremind respects the "-b1" option and operates in 24-hour
|
||||||
clock mode if the option is supplied.
|
clock mode if the option is supplied.
|
||||||
@@ -1253,7 +1639,7 @@ CHANGES TO REMIND
|
|||||||
- BUG FIX: The "-ivar=value" command-line option failed if Remind re-execed
|
- BUG FIX: The "-ivar=value" command-line option failed if Remind re-execed
|
||||||
itself because we overwrote argv[]. This has been fixed.
|
itself because we overwrote argv[]. This has been fixed.
|
||||||
|
|
||||||
* Version 3.1 Patch 3 - 2007-10-15
|
* VERSION 3.1 Patch 3 - 2007-10-15
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1272,7 +1658,7 @@ CHANGES TO REMIND
|
|||||||
is not evaluated. This helps avoid spurious error messages in some
|
is not evaluated. This helps avoid spurious error messages in some
|
||||||
reminders.
|
reminders.
|
||||||
|
|
||||||
* Version 3.1 Patch 2 - 2007-09-12
|
* VERSION 3.1 Patch 2 - 2007-09-12
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1326,7 +1712,7 @@ CHANGES TO REMIND
|
|||||||
- Using the psshade() or psmoon() functions emits a warning on stderr. You
|
- Using the psshade() or psmoon() functions emits a warning on stderr. You
|
||||||
should use SPECIAL SHADE or SPECIAL MOON instead.
|
should use SPECIAL SHADE or SPECIAL MOON instead.
|
||||||
|
|
||||||
* Version 3.1 Patch 1 - 2007-08-23
|
* VERSION 3.1 Patch 1 - 2007-08-23
|
||||||
|
|
||||||
+ MAJOR ENHANCEMENTS
|
+ MAJOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1356,7 +1742,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Various man-page fixes.
|
- Various man-page fixes.
|
||||||
|
|
||||||
* Version 3.1 Patch 0 - 2007-07-14
|
* VERSION 3.1 Patch 0 - 2007-07-14
|
||||||
|
|
||||||
+ MAJOR ENHANCEMENTS
|
+ MAJOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1419,7 +1805,7 @@ CHANGES TO REMIND
|
|||||||
- rem2ps would produce invalid PostScript in some rare cases
|
- rem2ps would produce invalid PostScript in some rare cases
|
||||||
(eg, for February 2007). This has been fixed.
|
(eg, for February 2007). This has been fixed.
|
||||||
|
|
||||||
* Version 3.0 Patch 24 - 2005-11-19
|
* VERSION 3.0 Patch 24 - 2005-11-19
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1442,7 +1828,7 @@ CHANGES TO REMIND
|
|||||||
- Fixed a bug in the tokenizer that could make Remind segfault. Fix courtesy
|
- Fixed a bug in the tokenizer that could make Remind segfault. Fix courtesy
|
||||||
of Stan Tobias.
|
of Stan Tobias.
|
||||||
|
|
||||||
* Version 3.0 Patch 23 - 2005-04-14
|
* VERSION 3.0 Patch 23 - 2005-04-14
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1466,7 +1852,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Fixed parser error for unterminated date constant: '2005/01/01
|
- Fixed parser error for unterminated date constant: '2005/01/01
|
||||||
|
|
||||||
* Version 3.0 Patch 22 - 2000-06-16
|
* VERSION 3.0 Patch 22 - 2000-06-16
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1488,7 +1874,7 @@ CHANGES TO REMIND
|
|||||||
- Fixed serious bug in which background queued reminders were ignored and
|
- Fixed serious bug in which background queued reminders were ignored and
|
||||||
Remind simply exited. Doh! Sorry about that.
|
Remind simply exited. Doh! Sorry about that.
|
||||||
|
|
||||||
* Version 3.0 Patch 21 - 2000-03-15
|
* VERSION 3.0 Patch 21 - 2000-03-15
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1519,7 +1905,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Fixed compilation problem on FreeBSD, IRIX, Tru64 and other UNIXes.
|
- Fixed compilation problem on FreeBSD, IRIX, Tru64 and other UNIXes.
|
||||||
|
|
||||||
* Version 3.0 Patch 20 - 1999-04-12
|
* VERSION 3.0 Patch 20 - 1999-04-12
|
||||||
|
|
||||||
+ LICENSE CHANGE
|
+ LICENSE CHANGE
|
||||||
|
|
||||||
@@ -1541,7 +1927,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Fixed a typo in danish.h, courtesy of Niels Kristian Bech Jensen.
|
- Fixed a typo in danish.h, courtesy of Niels Kristian Bech Jensen.
|
||||||
|
|
||||||
* Version 3.0 Patch 19 - 1998-05-09
|
* VERSION 3.0 Patch 19 - 1998-05-09
|
||||||
|
|
||||||
+ MAJOR ENHANCEMENTS
|
+ MAJOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1583,7 +1969,7 @@ CHANGES TO REMIND
|
|||||||
- Lots more silly little bugs squashed -- too many to go into in
|
- Lots more silly little bugs squashed -- too many to go into in
|
||||||
detail.
|
detail.
|
||||||
|
|
||||||
* Version 3.0 Patch 18 - 1998-02-15
|
* VERSION 3.0 Patch 18 - 1998-02-15
|
||||||
|
|
||||||
+ MAJOR ENHANCEMENTS
|
+ MAJOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1647,7 +2033,7 @@ CHANGES TO REMIND
|
|||||||
- Getting rid of fixed-sized buffers meant lots of changes to code.
|
- Getting rid of fixed-sized buffers meant lots of changes to code.
|
||||||
No doubt, I missed a few regression tests.
|
No doubt, I missed a few regression tests.
|
||||||
|
|
||||||
* Version 3.0 Patch 17 - 1997-09-07
|
* VERSION 3.0 Patch 17 - 1997-09-07
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1688,7 +2074,7 @@ CHANGES TO REMIND
|
|||||||
library. All three of these fixes are courtesy of Christopher
|
library. All three of these fixes are courtesy of Christopher
|
||||||
J. Madsen <madsen@iglobal.net>. Thanks, Christopher.
|
J. Madsen <madsen@iglobal.net>. Thanks, Christopher.
|
||||||
|
|
||||||
* Version 3.0 Patch 16 - 1997-02-11
|
* VERSION 3.0 Patch 16 - 1997-02-11
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1716,7 +2102,7 @@ CHANGES TO REMIND
|
|||||||
- Fixed a problem under Solaris 2.5 whereby rem2ps was skipping some
|
- Fixed a problem under Solaris 2.5 whereby rem2ps was skipping some
|
||||||
latin1 characters which it interpreted as white space.
|
latin1 characters which it interpreted as white space.
|
||||||
|
|
||||||
* Version 3.0 Patch 15 - 1996-10-27
|
* VERSION 3.0 Patch 15 - 1996-10-27
|
||||||
|
|
||||||
+ IMPORTANT NOTES
|
+ IMPORTANT NOTES
|
||||||
|
|
||||||
@@ -1746,7 +2132,7 @@ CHANGES TO REMIND
|
|||||||
- Fixed bug in TkRemind which caused a crash if the "-m" option was used
|
- Fixed bug in TkRemind which caused a crash if the "-m" option was used
|
||||||
for a month beginning on Sunday. Doh!!!
|
for a month beginning on Sunday. Doh!!!
|
||||||
|
|
||||||
* Version 3.0 Patch 14 - 1996-05-25
|
* VERSION 3.0 Patch 14 - 1996-05-25
|
||||||
|
|
||||||
+ CHANGE IN COPYING POLICY
|
+ CHANGE IN COPYING POLICY
|
||||||
|
|
||||||
@@ -1805,7 +2191,7 @@ CHANGES TO REMIND
|
|||||||
_not_ support MS Windows, and in fact do not allow Remind to run
|
_not_ support MS Windows, and in fact do not allow Remind to run
|
||||||
under Windows (see COPYRIGHT).
|
under Windows (see COPYRIGHT).
|
||||||
|
|
||||||
* Version 3.0 Patch 13 - 1994-05-06
|
* VERSION 3.0 Patch 13 - 1994-05-06
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1840,7 +2226,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Updated the copyright notices everywhere.
|
- Updated the copyright notices everywhere.
|
||||||
|
|
||||||
* Version 3.0 Patch 12 - 1994-02-01
|
* VERSION 3.0 Patch 12 - 1994-02-01
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1859,7 +2245,7 @@ CHANGES TO REMIND
|
|||||||
- Fixed a problem with the '-k' option which resulted in a newline being
|
- Fixed a problem with the '-k' option which resulted in a newline being
|
||||||
placed after the message text. This was giving sh(1) heartburn...
|
placed after the message text. This was giving sh(1) heartburn...
|
||||||
|
|
||||||
* Version 3.0 Patch 11 - 1993-11-26
|
* VERSION 3.0 Patch 11 - 1993-11-26
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -1891,7 +2277,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Fixed typos in french.h
|
- Fixed typos in french.h
|
||||||
|
|
||||||
* Version 3.0 Patch 10
|
* VERSION 3.0 Patch 10
|
||||||
|
|
||||||
+ MAJOR ENHANCEMENT
|
+ MAJOR ENHANCEMENT
|
||||||
|
|
||||||
@@ -1939,7 +2325,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Fixed the Finnish language support which was missing a few newlines.
|
- Fixed the Finnish language support which was missing a few newlines.
|
||||||
|
|
||||||
* Version 3.0 Patch 9 - 1993-10-04
|
* VERSION 3.0 Patch 9 - 1993-10-04
|
||||||
|
|
||||||
+ NOTES
|
+ NOTES
|
||||||
|
|
||||||
@@ -1996,7 +2382,7 @@ CHANGES TO REMIND
|
|||||||
so that newlines in the body start new paragraphs, rather than being
|
so that newlines in the body start new paragraphs, rather than being
|
||||||
swallowed as white-space.
|
swallowed as white-space.
|
||||||
|
|
||||||
* Version 3.0 Patch 8 - 1993-09-08
|
* VERSION 3.0 Patch 8 - 1993-09-08
|
||||||
|
|
||||||
+ MAJOR ENHANCEMENTS
|
+ MAJOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -2048,7 +2434,7 @@ CHANGES TO REMIND
|
|||||||
range [-128, 255] (but not 0) so that char(asc(s)) works even
|
range [-128, 255] (but not 0) so that char(asc(s)) works even
|
||||||
on machines with signed char types.
|
on machines with signed char types.
|
||||||
|
|
||||||
* Version 3.0 Patch 7 - 1993-07-22
|
* VERSION 3.0 Patch 7 - 1993-07-22
|
||||||
|
|
||||||
+ MAJOR ENHANCEMENTS
|
+ MAJOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -2091,7 +2477,7 @@ CHANGES TO REMIND
|
|||||||
- Changed kall so that "kall sh" doesn't commit suicide - patch courtesy
|
- Changed kall so that "kall sh" doesn't commit suicide - patch courtesy
|
||||||
of Michael Salmon.
|
of Michael Salmon.
|
||||||
|
|
||||||
* Version 3.0 Patch 6 - 1993-05-05
|
* VERSION 3.0 Patch 6 - 1993-05-05
|
||||||
|
|
||||||
+ MINOR ENHANCEMENTS
|
+ MINOR ENHANCEMENTS
|
||||||
|
|
||||||
@@ -2114,7 +2500,7 @@ CHANGES TO REMIND
|
|||||||
- Fixed a bug in the -u option which sometimes caused a core dump
|
- Fixed a bug in the -u option which sometimes caused a core dump
|
||||||
(embarrassed grin!) The fix is due to Tina Hoeltig. Thanks, Tina!
|
(embarrassed grin!) The fix is due to Tina Hoeltig. Thanks, Tina!
|
||||||
|
|
||||||
* Version 3.0 Patch 5 - 1993-04-27
|
* VERSION 3.0 Patch 5 - 1993-04-27
|
||||||
|
|
||||||
+ MAJOR ENHANCEMENTS:
|
+ MAJOR ENHANCEMENTS:
|
||||||
|
|
||||||
@@ -2149,7 +2535,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Fixed a bug in the man page - thanks to Ed Oskiewicz.
|
- Fixed a bug in the man page - thanks to Ed Oskiewicz.
|
||||||
|
|
||||||
* Version 3.0 Patch 4 - 1993-03-08
|
* VERSION 3.0 Patch 4 - 1993-03-08
|
||||||
|
|
||||||
- Added the -g option - this sorts reminders by date/time before
|
- Added the -g option - this sorts reminders by date/time before
|
||||||
issuing them. (You can see I'm running out of letters to
|
issuing them. (You can see I'm running out of letters to
|
||||||
@@ -2208,13 +2594,13 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Put my new mailing address in the README files.
|
- Put my new mailing address in the README files.
|
||||||
|
|
||||||
* Version 3.0 Patch 3 - 1993-02-21
|
* VERSION 3.0 Patch 3 - 1993-02-21
|
||||||
|
|
||||||
- Corrected bugs in Remind and Rem2PS. No new features added. You
|
- Corrected bugs in Remind and Rem2PS. No new features added. You
|
||||||
should NOT use patch level 2 - either stick to 3.0.1 or upgrade to
|
should NOT use patch level 2 - either stick to 3.0.1 or upgrade to
|
||||||
3.0.3.
|
3.0.3.
|
||||||
|
|
||||||
* Version 3.0 Patch 2 - 1993-02-04
|
* VERSION 3.0 Patch 2 - 1993-02-04
|
||||||
|
|
||||||
- Added the -u option to Remind so that root can run it as any user.
|
- Added the -u option to Remind so that root can run it as any user.
|
||||||
This simplifies the remind-all scripts, and makes them more efficient.
|
This simplifies the remind-all scripts, and makes them more efficient.
|
||||||
@@ -2254,7 +2640,7 @@ CHANGES TO REMIND
|
|||||||
- Changed Remind so that supplying the -a option causes timed reminders
|
- Changed Remind so that supplying the -a option causes timed reminders
|
||||||
not to be placed into the calendar in calendar mode.
|
not to be placed into the calendar in calendar mode.
|
||||||
|
|
||||||
* Version 3.0 Patch 1 - 1992-12-18
|
* VERSION 3.0 Patch 1 - 1992-12-18
|
||||||
|
|
||||||
- Wrote the Rem2ps program to produce PostScript calendars
|
- Wrote the Rem2ps program to produce PostScript calendars
|
||||||
|
|
||||||
@@ -2294,7 +2680,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Re-formatted the WHATSNEW.30 file.
|
- Re-formatted the WHATSNEW.30 file.
|
||||||
|
|
||||||
* Version 3.0 - 1992-11-09
|
* VERSION 3.0 - 1992-11-09
|
||||||
|
|
||||||
- Total rewrite from previous versions
|
- Total rewrite from previous versions
|
||||||
|
|
||||||
@@ -2315,23 +2701,23 @@ CHANGES TO REMIND
|
|||||||
- Fixed a lurking bug in trigger date calculation which, amazingly, had not
|
- Fixed a lurking bug in trigger date calculation which, amazingly, had not
|
||||||
been caught in the couple of years that Remind has been out!
|
been caught in the couple of years that Remind has been out!
|
||||||
|
|
||||||
* Version 2.3 Patch 5 - 1992-04-11
|
* VERSION 2.3 Patch 5 - 1992-04-11
|
||||||
|
|
||||||
- Added the "c+n" option for printing a calendar by
|
- Added the "c+n" option for printing a calendar by
|
||||||
weeks instead of months, courtesy Dennis Cottel (dennis@peanuts.nosc.mil).
|
weeks instead of months, courtesy Dennis Cottel (dennis@peanuts.nosc.mil).
|
||||||
|
|
||||||
* Version 2.3 Patch 4 - 1991-11-06
|
* VERSION 2.3 Patch 4 - 1991-11-06
|
||||||
|
|
||||||
- Made the init.c file nicer. Made the Makefile
|
- Made the init.c file nicer. Made the Makefile
|
||||||
prettier. Added "make test", "make tar" and "make shar" Makefile targets.
|
prettier. Added "make test", "make tar" and "make shar" Makefile targets.
|
||||||
|
|
||||||
* Version 2.3 Patch 3 - 1991-09-11
|
* VERSION 2.3 Patch 3 - 1991-09-11
|
||||||
|
|
||||||
- Added a command-line option for Remind to process
|
- Added a command-line option for Remind to process
|
||||||
queued reminders in the foreground. This makes automatic termination
|
queued reminders in the foreground. This makes automatic termination
|
||||||
of Remind processes from within X-Windows and Sunview easier.
|
of Remind processes from within X-Windows and Sunview easier.
|
||||||
|
|
||||||
* Version 2.3 Patch 2 - 1991-07-19
|
* VERSION 2.3 Patch 2 - 1991-07-19
|
||||||
|
|
||||||
- Fixed up a problem with timed reminders which resulted
|
- Fixed up a problem with timed reminders which resulted
|
||||||
in cursor not starting from left side of screen on some systems.
|
in cursor not starting from left side of screen on some systems.
|
||||||
@@ -2348,7 +2734,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Made the Makefile more portable
|
- Made the Makefile more portable
|
||||||
|
|
||||||
* Version 2.3 Patch 1 - 1991-03-08
|
* VERSION 2.3 Patch 1 - 1991-03-08
|
||||||
|
|
||||||
- Added the "-t" command-line option to get Remind
|
- Added the "-t" command-line option to get Remind
|
||||||
to trigger all non-expired reminders.
|
to trigger all non-expired reminders.
|
||||||
@@ -2362,7 +2748,7 @@ CHANGES TO REMIND
|
|||||||
|
|
||||||
- Added manual pages for "kall" and "rem".
|
- Added manual pages for "kall" and "rem".
|
||||||
|
|
||||||
* Version 2.3 - 1991-02-20
|
* VERSION 2.3 - 1991-02-20
|
||||||
|
|
||||||
- Added the UNTIL keyword for forcing reminders to expire.
|
- Added the UNTIL keyword for forcing reminders to expire.
|
||||||
|
|
||||||
@@ -2384,32 +2770,32 @@ CHANGES TO REMIND
|
|||||||
- Modified the calendar and SimpleCalendar formats so that the % escape
|
- Modified the calendar and SimpleCalendar formats so that the % escape
|
||||||
substitutions ARE performed.
|
substitutions ARE performed.
|
||||||
|
|
||||||
* Version 2.2 - Patch 5 - 1990-12-03
|
* VERSION 2.2 - Patch 5 - 1990-12-03
|
||||||
|
|
||||||
- Added the BEFORE, AFTER and SKIP tokens to make the
|
- Added the BEFORE, AFTER and SKIP tokens to make the
|
||||||
handling of holidays more sensible. Also corrected a few more bugs.
|
handling of holidays more sensible. Also corrected a few more bugs.
|
||||||
|
|
||||||
* Version 2.2 - Patch 3 - 1990-11-28
|
* VERSION 2.2 - Patch 3 - 1990-11-28
|
||||||
|
|
||||||
- Added the MSG or RUN tokens in an OMIT command; also
|
- Added the MSG or RUN tokens in an OMIT command; also
|
||||||
allowed RUN-type reminders to be explicitly included in the calendar by
|
allowed RUN-type reminders to be explicitly included in the calendar by
|
||||||
using the %" escape sequence.
|
using the %" escape sequence.
|
||||||
|
|
||||||
* Version 2.2 - 1990-11-16
|
* VERSION 2.2 - 1990-11-16
|
||||||
|
|
||||||
- Added the AT keyword, the timed reminders daemon, and the
|
- Added the AT keyword, the timed reminders daemon, and the
|
||||||
calendar facility.
|
calendar facility.
|
||||||
|
|
||||||
* Version 2.1 - 1990-11-06
|
* VERSION 2.1 - 1990-11-06
|
||||||
|
|
||||||
- Added the "repeat" token for repeating reminders with a period
|
- Added the "repeat" token for repeating reminders with a period
|
||||||
other than 7 days. Also fixed some bugs from version 2.0
|
other than 7 days. Also fixed some bugs from version 2.0
|
||||||
|
|
||||||
* Version 2.0 - 1990-11-01
|
* VERSION 2.0 - 1990-11-01
|
||||||
|
|
||||||
- first public release. Included advanced date specifications,
|
- first public release. Included advanced date specifications,
|
||||||
character substitution, and the RUN keyword.
|
character substitution, and the RUN keyword.
|
||||||
|
|
||||||
* Version 1.0
|
* VERSION 1.0
|
||||||
|
|
||||||
- never publicly released.
|
- never publicly released.
|
||||||
|
|||||||
@@ -6,6 +6,11 @@
|
|||||||
# Cut and paste as desired! Also, near the end, there are a bunch of #
|
# Cut and paste as desired! Also, near the end, there are a bunch of #
|
||||||
# holiday definitions for the U.S. #
|
# holiday definitions for the U.S. #
|
||||||
# #
|
# #
|
||||||
|
# *** NOTE *** #
|
||||||
|
# #
|
||||||
|
# This file is simply a grab-bag of examples. It is NOT meant to be #
|
||||||
|
# included as-is in a live reminder file. #
|
||||||
|
# #
|
||||||
# Some examples provided by George M. Sipe <gsipe@pyratl.ga.pyramid.com> #
|
# Some examples provided by George M. Sipe <gsipe@pyratl.ga.pyramid.com> #
|
||||||
# #
|
# #
|
||||||
# U.S. holidays provided by Dave Rickel <drickel@sjc.mentorg.com> #
|
# U.S. holidays provided by Dave Rickel <drickel@sjc.mentorg.com> #
|
||||||
@@ -27,7 +32,7 @@ RUN OFF
|
|||||||
# Ensure required version of remind is used... #
|
# Ensure required version of remind is used... #
|
||||||
################################################
|
################################################
|
||||||
IF version() < "03.04.02"
|
IF version() < "03.04.02"
|
||||||
ERRMSG This file requires at least version 03.01.10 of Remind.%
|
ERRMSG This file requires at least version 03.04.02 of Remind.%
|
||||||
ERRMSG This version is version [version()].
|
ERRMSG This version is version [version()].
|
||||||
EXIT
|
EXIT
|
||||||
ENDIF
|
ENDIF
|
||||||
@@ -305,51 +310,51 @@ FSET _PastMon(x, y) IIF(WKDAYNUM(_h2(x,y))!=1, _h2(x,y), _h2(x,y)+1)
|
|||||||
SET InIsrael VALUE("InIsrael", 0)
|
SET InIsrael VALUE("InIsrael", 0)
|
||||||
SET Reform VALUE("Reform", 0)
|
SET Reform VALUE("Reform", 0)
|
||||||
|
|
||||||
[_h(1, "Tishrey")] ++4 MSG %"Rosh Hashana 1%" is %b.
|
REM [_h(1, "Tishrey")] ++4 MSG %"Rosh Hashana 1%" is %b.
|
||||||
|
|
||||||
# No RH-2 or Tzom Gedalia in Reform
|
# No RH-2 or Tzom Gedalia in Reform
|
||||||
IF !Reform
|
IF !Reform
|
||||||
[_h(2, "Tishrey")] ++4 MSG %"Rosh Hashana 2%" is %b.
|
REM [_h(2, "Tishrey")] ++4 MSG %"Rosh Hashana 2%" is %b.
|
||||||
[_PastSat(3, "Tishrey")] ++4 MSG %"Tzom Gedalia%" is %b.
|
REM [_PastSat(3, "Tishrey")] ++4 MSG %"Tzom Gedalia%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(10, "Tishrey")] ++4 MSG %"Yom Kippur%" is %b.
|
REM [_h(10, "Tishrey")] ++4 MSG %"Yom Kippur%" is %b.
|
||||||
[_h(15, "Tishrey")] ++4 MSG %"Sukkot 1%" is %b.
|
REM [_h(15, "Tishrey")] ++4 MSG %"Sukkot 1%" is %b.
|
||||||
|
|
||||||
IF !InIsrael
|
IF !InIsrael
|
||||||
[_h(16, "Tishrey")] MSG %"Sukkot 2%"
|
REM [_h(16, "Tishrey")] MSG %"Sukkot 2%"
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(21, "Tishrey")] ++4 MSG %"Hoshana Rabba%" is %b.
|
REM [_h(21, "Tishrey")] ++4 MSG %"Hoshana Rabba%" is %b.
|
||||||
[_h(22, "Tishrey")] ++4 MSG %"Shemini Atzeret%" is %b.
|
REM [_h(22, "Tishrey")] ++4 MSG %"Shemini Atzeret%" is %b.
|
||||||
|
|
||||||
IF InIsrael
|
IF InIsrael
|
||||||
[_h(22, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
|
REM [_h(22, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
|
||||||
ELSE
|
ELSE
|
||||||
[_h(23, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
|
REM [_h(23, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
# Because Kislev can change length, we must be more careful about Chanukah
|
# Because Kislev can change length, we must be more careful about Chanukah
|
||||||
FSET _chan(x) HEBDATE(24, "Kislev", $U-9)+x
|
FSET _chan(x) HEBDATE(24, "Kislev", $U-9)+x
|
||||||
[_chan(1)] ++4 MSG %"Chanukah 1%" is %b.
|
REM [_chan(1)] ++4 MSG %"Chanukah 1%" is %b.
|
||||||
[_chan(2)] MSG %"Chanukah 2%"
|
REM [_chan(2)] MSG %"Chanukah 2%"
|
||||||
[_chan(3)] MSG %"Chanukah 3%"
|
REM [_chan(3)] MSG %"Chanukah 3%"
|
||||||
[_chan(4)] MSG %"Chanukah 4%"
|
REM [_chan(4)] MSG %"Chanukah 4%"
|
||||||
[_chan(5)] MSG %"Chanukah 5%"
|
REM [_chan(5)] MSG %"Chanukah 5%"
|
||||||
[_chan(6)] MSG %"Chanukah 6%"
|
REM [_chan(6)] MSG %"Chanukah 6%"
|
||||||
[_chan(7)] MSG %"Chanukah 7%"
|
REM [_chan(7)] MSG %"Chanukah 7%"
|
||||||
[_chan(8)] MSG %"Chanukah 8%"
|
REM [_chan(8)] MSG %"Chanukah 8%"
|
||||||
|
|
||||||
# Not sure about Reform's position on the next one.
|
# Not sure about Reform's position on the next one.
|
||||||
IF !Reform
|
IF !Reform
|
||||||
# 10 Tevet will never be a Saturday, so whether or not to
|
# 10 Tevet will never be a Saturday, so whether or not to
|
||||||
# move it is moot. (Thanks to Art Werschulz.)
|
# move it is moot. (Thanks to Art Werschulz.)
|
||||||
[_h(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
|
REM [_h(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(15, "Shvat")] ++4 MSG %"Tu B'Shvat%" is %b.
|
REM [_h(15, "Shvat")] ++4 MSG %"Tu B'Shvat%" is %b.
|
||||||
[_h(14, "Adar A")] ++4 MSG %"Purim Katan%" is %b.
|
REM [_h(14, "Adar A")] ++4 MSG %"Purim Katan%" is %b.
|
||||||
[_h(15, "Adar A")] ++4 MSG %"Shushan Purim Katan%" is %b.
|
REM [_h(15, "Adar A")] ++4 MSG %"Shushan Purim Katan%" is %b.
|
||||||
|
|
||||||
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
|
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
|
||||||
IF WKDAYNUM(_h2(13, "Adar")) != 6
|
IF WKDAYNUM(_h2(13, "Adar")) != 6
|
||||||
@@ -357,18 +362,18 @@ IF WKDAYNUM(_h2(13, "Adar")) != 6
|
|||||||
ELSE
|
ELSE
|
||||||
REM [_h2(11, "Adar")] ++4 MSG %"Fast of Esther%" is %b.
|
REM [_h2(11, "Adar")] ++4 MSG %"Fast of Esther%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
[_h(14, "Adar")] ++4 MSG %"Purim%" is %b.
|
REM [_h(14, "Adar")] ++4 MSG %"Purim%" is %b.
|
||||||
[_h(15, "Adar")] ++4 MSG %"Shushan Purim%" is %b.
|
REM [_h(15, "Adar")] ++4 MSG %"Shushan Purim%" is %b.
|
||||||
[_h(15, "Nisan")] ++4 MSG %"Pesach%" is %b.
|
REM [_h(15, "Nisan")] ++4 MSG %"Pesach%" is %b.
|
||||||
|
|
||||||
IF !InIsrael
|
IF !InIsrael
|
||||||
[_h(16, "Nisan")] MSG %"Pesach 2%"
|
REM [_h(16, "Nisan")] MSG %"Pesach 2%"
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(21, "Nisan")] MSG %"Pesach 7%"
|
REM [_h(21, "Nisan")] MSG %"Pesach 7%"
|
||||||
|
|
||||||
IF !InIsrael && !Reform
|
IF !InIsrael && !Reform
|
||||||
[_h(22, "Nisan")] MSG %"Pesach 8%"
|
REM [_h(22, "Nisan")] MSG %"Pesach 8%"
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
REM [_PastSun(27, "Nisan")] SATISFY 1
|
REM [_PastSun(27, "Nisan")] SATISFY 1
|
||||||
@@ -384,36 +389,36 @@ ENDIF
|
|||||||
# Thursday. If 4 Iyar is a Sunday, then Yom Hazikaron
|
# Thursday. If 4 Iyar is a Sunday, then Yom Hazikaron
|
||||||
# moves to 5 Iyar and Yom Ha'atzmaut to 6 Iyar.
|
# moves to 5 Iyar and Yom Ha'atzmaut to 6 Iyar.
|
||||||
IF WKDAYNUM(_h2(4, "Iyar")) == 4 || WKDAYNUM(_h2(4, "Iyar")) == 5
|
IF WKDAYNUM(_h2(4, "Iyar")) == 4 || WKDAYNUM(_h2(4, "Iyar")) == 5
|
||||||
[_h(2, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
|
REM [_h(2, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
|
||||||
[_h(3, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
|
REM [_h(3, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
|
||||||
ELSE
|
ELSE
|
||||||
IF WKDAYNUM(_h2(4, "Iyar")) == 0
|
IF WKDAYNUM(_h2(4, "Iyar")) == 0
|
||||||
[_h(5, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
|
REM [_h(5, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
|
||||||
[_h(6, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
|
REM [_h(6, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
|
||||||
ELSE
|
ELSE
|
||||||
[_h(4, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
|
REM [_h(4, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
|
||||||
[_h(5, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
|
REM [_h(5, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
# Not sure about Reform's position on Lag B'Omer
|
# Not sure about Reform's position on Lag B'Omer
|
||||||
IF !Reform
|
IF !Reform
|
||||||
[_h(18, "Iyar")] ++4 MSG %"Lag B'Omer%" is %b.
|
REM [_h(18, "Iyar")] ++4 MSG %"Lag B'Omer%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(28, "Iyar")] ++4 MSG %"Yom Yerushalayim%" is %b.
|
REM [_h(28, "Iyar")] ++4 MSG %"Yom Yerushalayim%" is %b.
|
||||||
[_h(6, "Sivan")] ++4 MSG %"Shavuot%" is %b.
|
REM [_h(6, "Sivan")] ++4 MSG %"Shavuot%" is %b.
|
||||||
|
|
||||||
IF !InIsrael && !Reform
|
IF !InIsrael && !Reform
|
||||||
[_h(7, "Sivan")] MSG %"Shavuot 2%"
|
REM [_h(7, "Sivan")] MSG %"Shavuot 2%"
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
# Fairly sure Reform Jews don't observe the next two
|
# Fairly sure Reform Jews don't observe the next two
|
||||||
IF !Reform
|
IF !Reform
|
||||||
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
|
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
|
||||||
# fall on a Saturday
|
# fall on a Saturday
|
||||||
[_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b.
|
REM [_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b.
|
||||||
[_PastSat(9, "Av")] ++4 MSG %"Tish'a B'Av%" is %b.
|
REM [_PastSat(9, "Av")] ++4 MSG %"Tish'a B'Av%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
# Counting the omer - do the whole spiel, i.e:
|
# Counting the omer - do the whole spiel, i.e:
|
||||||
|
|||||||
29
include/holidays/chinese-new-year.rem
Normal file
29
include/holidays/chinese-new-year.rem
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
REM 1 Feb 2022 MSG Chinese New Year (Tiger)
|
||||||
|
REM 22 Jan 2023 MSG Chinese New Year (Rabbit)
|
||||||
|
REM 10 Feb 2024 MSG Chinese New Year (Dragon)
|
||||||
|
REM 29 Jan 2025 MSG Chinese New Year (Snake)
|
||||||
|
REM 17 Feb 2026 MSG Chinese New Year (Horse)
|
||||||
|
REM 6 Feb 2027 MSG Chinese New Year (Goat)
|
||||||
|
REM 26 Jan 2028 MSG Chinese New Year (Monkey)
|
||||||
|
REM 13 Feb 2029 MSG Chinese New Year (Rooster)
|
||||||
|
REM 3 Feb 2030 MSG Chinese New Year (Dog)
|
||||||
|
REM 23 Jan 2031 MSG Chinese New Year (Pig)
|
||||||
|
REM 11 Feb 2032 MSG Chinese New Year (Rat)
|
||||||
|
REM 31 Jan 2033 MSG Chinese New Year (Ox)
|
||||||
|
REM 19 Feb 2034 MSG Chinese New Year (Tiger)
|
||||||
|
REM 8 Feb 2035 MSG Chinese New Year (Rabbit)
|
||||||
|
REM 28 Jan 2036 MSG Chinese New Year (Dragon)
|
||||||
|
REM 15 Feb 2037 MSG Chinese New Year (Snake)
|
||||||
|
REM 4 Feb 2038 MSG Chinese New Year (Horse)
|
||||||
|
REM 24 Jan 2039 MSG Chinese New Year (Goat)
|
||||||
|
REM 12 Feb 2040 MSG Chinese New Year (Monkey)
|
||||||
|
REM 1 Feb 2041 MSG Chinese New Year (Rooster)
|
||||||
|
REM 22 Jan 2042 MSG Chinese New Year (Dog)
|
||||||
|
REM 10 Feb 2043 MSG Chinese New Year (Pig)
|
||||||
|
REM 30 Jan 2044 MSG Chinese New Year (Rat)
|
||||||
|
REM 17 Feb 2045 MSG Chinese New Year (Ox)
|
||||||
|
REM 6 Feb 2046 MSG Chinese New Year (Tiger)
|
||||||
|
REM 26 Jan 2047 MSG Chinese New Year (Rabbit)
|
||||||
|
REM 14 Feb 2048 MSG Chinese New Year (Dragon)
|
||||||
|
REM 2 Feb 2049 MSG Chinese New Year (Snake)
|
||||||
|
REM 23 Jan 2050 MSG Chinese New Year (Horse)
|
||||||
@@ -10,7 +10,7 @@ REM 28 Oct MSG ΟΧΙ
|
|||||||
REM 25 Dec MSG ΧΡΙΣΤΟΥΓΕΝΝΑ
|
REM 25 Dec MSG ΧΡΙΣΤΟΥΓΕΝΝΑ
|
||||||
REM 26 Dec MSG ΧΡΙΣΤΟΥΓΕΝΝΑ2
|
REM 26 Dec MSG ΧΡΙΣΤΟΥΓΕΝΝΑ2
|
||||||
|
|
||||||
REM [orthodoxeaster($Uy)+1] ΔΕΥΤΕΡΑ ΤΟΥ ΠΑΣΧΑ
|
REM [orthodoxeaster($Uy)+1] MSG ΔΕΥΤΕΡΑ ΤΟΥ ΠΑΣΧΑ
|
||||||
|
|
||||||
|
|
||||||
# May first is a national holiday except if Sunday, day of great week (week before easter) or Monday after easter, then
|
# May first is a national holiday except if Sunday, day of great week (week before easter) or Monday after easter, then
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ SET InIsrael value("InIsrael", 0)
|
|||||||
SET Reform value("Reform", 0)
|
SET Reform value("Reform", 0)
|
||||||
|
|
||||||
# Convenient function definition to save typing
|
# Convenient function definition to save typing
|
||||||
FSET _h(x, y) HEBDATE(x,y)
|
|
||||||
FSET _h2(x, y) HEBDATE(x, y, $U-7)
|
FSET _h2(x, y) HEBDATE(x, y, $U-7)
|
||||||
FSET _PastSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)+1)
|
FSET _PastSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)+1)
|
||||||
FSET _BackTwoFri(x, y) IIF(WKDAYNUM(_h2(x,y))!=5, _h2(x,y), _h2(x,y)-2)
|
FSET _BackTwoFri(x, y) IIF(WKDAYNUM(_h2(x,y))!=5, _h2(x,y), _h2(x,y)-2)
|
||||||
@@ -19,50 +18,50 @@ FSET _BackTwoSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)-2)
|
|||||||
SET InIsrael VALUE("InIsrael", 0)
|
SET InIsrael VALUE("InIsrael", 0)
|
||||||
SET Reform VALUE("Reform", 0)
|
SET Reform VALUE("Reform", 0)
|
||||||
|
|
||||||
[_h(1, "Tishrey")] ++4 MSG %"Rosh Hashana 1%" is %b.
|
REM [hebdate(1, "Tishrey")] ++4 MSG %"Rosh Hashana 1%" is %b.
|
||||||
|
|
||||||
# No RH-2 or Tzom Gedalia in Reform
|
# No RH-2 or Tzom Gedalia in Reform
|
||||||
IF !Reform
|
IF !Reform
|
||||||
[_h(2, "Tishrey")] ++4 MSG %"Rosh Hashana 2%" is %b.
|
REM [hebdate(2, "Tishrey")] ++4 MSG %"Rosh Hashana 2%" is %b.
|
||||||
[_PastSat(3, "Tishrey")] ++4 MSG %"Tzom Gedalia%" is %b.
|
REM [_PastSat(3, "Tishrey")] ++4 MSG %"Tzom Gedalia%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(10, "Tishrey")] ++4 MSG %"Yom Kippur%" is %b.
|
REM [hebdate(10, "Tishrey")] ++4 MSG %"Yom Kippur%" is %b.
|
||||||
[_h(15, "Tishrey")] ++4 MSG %"Sukkot 1%" is %b.
|
REM [hebdate(15, "Tishrey")] ++4 MSG %"Sukkot 1%" is %b.
|
||||||
|
|
||||||
IF !InIsrael
|
IF !InIsrael
|
||||||
[_h(16, "Tishrey")] MSG %"Sukkot 2%"
|
REM [hebdate(16, "Tishrey")] MSG %"Sukkot 2%"
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(21, "Tishrey")] ++4 MSG %"Hoshana Rabba%" is %b.
|
REM [hebdate(21, "Tishrey")] ++4 MSG %"Hoshana Rabba%" is %b.
|
||||||
[_h(22, "Tishrey")] ++4 MSG %"Shemini Atzeret%" is %b.
|
REM [hebdate(22, "Tishrey")] ++4 MSG %"Shemini Atzeret%" is %b.
|
||||||
|
|
||||||
IF InIsrael
|
IF InIsrael
|
||||||
[_h(22, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
|
REM [hebdate(22, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
|
||||||
ELSE
|
ELSE
|
||||||
[_h(23, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
|
REM [hebdate(23, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
# Because Kislev can change length, we must be more careful about Chanukah
|
# Because Kislev can change length, we must be more careful about Chanukah
|
||||||
FSET _chan(x) HEBDATE(24, "Kislev", $U-9)+x
|
FSET _chan(x) HEBDATE(24, "Kislev", $U-9)+x
|
||||||
[_chan(1)] ++4 MSG %"Chanukah 1%" is %b.
|
REM [_chan(1)] ++4 MSG %"Chanukah 1%" is %b.
|
||||||
[_chan(2)] MSG %"Chanukah 2%"
|
REM [_chan(2)] MSG %"Chanukah 2%"
|
||||||
[_chan(3)] MSG %"Chanukah 3%"
|
REM [_chan(3)] MSG %"Chanukah 3%"
|
||||||
[_chan(4)] MSG %"Chanukah 4%"
|
REM [_chan(4)] MSG %"Chanukah 4%"
|
||||||
[_chan(5)] MSG %"Chanukah 5%"
|
REM [_chan(5)] MSG %"Chanukah 5%"
|
||||||
[_chan(6)] MSG %"Chanukah 6%"
|
REM [_chan(6)] MSG %"Chanukah 6%"
|
||||||
[_chan(7)] MSG %"Chanukah 7%"
|
REM [_chan(7)] MSG %"Chanukah 7%"
|
||||||
[_chan(8)] MSG %"Chanukah 8%"
|
REM [_chan(8)] MSG %"Chanukah 8%"
|
||||||
|
|
||||||
# Not sure about Reform's position on the next one.
|
# Not sure about Reform's position on the next one.
|
||||||
IF !Reform
|
IF !Reform
|
||||||
# 10 Tevet will never be a Saturday, so whether or not to
|
# 10 Tevet will never be a Saturday, so whether or not to
|
||||||
# move it is moot. (Thanks to Art Werschulz.)
|
# move it is moot. (Thanks to Art Werschulz.)
|
||||||
[_h(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
|
REM [hebdate(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(15, "Shvat")] ++4 MSG %"Tu B'Shvat%" is %b.
|
REM [hebdate(15, "Shvat")] ++4 MSG %"Tu B'Shvat%" is %b.
|
||||||
[_h(14, "Adar A")] ++4 MSG %"Purim Katan%" is %b.
|
REM [hebdate(14, "Adar A")] ++4 MSG %"Purim Katan%" is %b.
|
||||||
|
|
||||||
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
|
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
|
||||||
IF WKDAYNUM(_h2(13, "Adar")) != 6
|
IF WKDAYNUM(_h2(13, "Adar")) != 6
|
||||||
@@ -70,43 +69,39 @@ IF WKDAYNUM(_h2(13, "Adar")) != 6
|
|||||||
ELSE
|
ELSE
|
||||||
REM [_h2(11, "Adar")] ++4 MSG %"Fast of Esther%" is %b.
|
REM [_h2(11, "Adar")] ++4 MSG %"Fast of Esther%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
[_h(14, "Adar")] ++4 MSG %"Purim%" is %b.
|
REM [hebdate(14, "Adar")] ++4 MSG %"Purim%" is %b.
|
||||||
[_h(15, "Nisan")] ++4 MSG %"Pesach%" is %b.
|
REM [hebdate(15, "Nisan")] ++4 MSG %"Pesach%" is %b.
|
||||||
|
|
||||||
IF !InIsrael
|
IF !InIsrael
|
||||||
[_h(16, "Nisan")] MSG %"Pesach 2%"
|
REM [hebdate(16, "Nisan")] MSG %"Pesach 2%"
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(21, "Nisan")] MSG %"Pesach 7%"
|
REM [hebdate(21, "Nisan")] MSG %"Pesach 7%"
|
||||||
|
|
||||||
IF !InIsrael && !Reform
|
IF !InIsrael && !Reform
|
||||||
[_h(22, "Nisan")] MSG %"Pesach 8%"
|
REM [hebdate(22, "Nisan")] MSG %"Pesach 8%"
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(27, "Nisan")] ++4 MSG %"Yom HaShoah%" is %b.
|
REM [hebdate(27, "Nisan")] ++4 MSG %"Yom HaShoah%" is %b.
|
||||||
[_BackTwoFri(4, "Iyar")] ++4 MSG %"Yom HaZikaron%" is %b.
|
REM [_BackTwoFri(4, "Iyar")] ++4 MSG %"Yom HaZikaron%" is %b.
|
||||||
[_BackTwoSat(5, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
|
REM [_BackTwoSat(5, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
|
||||||
|
|
||||||
# Not sure about Reform's position on Lag B'Omer
|
# Not sure about Reform's position on Lag B'Omer
|
||||||
IF !Reform
|
IF !Reform
|
||||||
[_h(18, "Iyar")] ++4 MSG %"Lag B'Omer%" is %b.
|
REM [hebdate(18, "Iyar")] ++4 MSG %"Lag B'Omer%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(28, "Iyar")] ++4 MSG %"Yom Yerushalayim%" is %b.
|
REM [hebdate(28, "Iyar")] ++4 MSG %"Yom Yerushalayim%" is %b.
|
||||||
[_h(6, "Sivan")] ++4 MSG %"Shavuot%" is %b.
|
REM [hebdate(6, "Sivan")] ++4 MSG %"Shavuot%" is %b.
|
||||||
|
|
||||||
IF !InIsrael && !Reform
|
IF !InIsrael && !Reform
|
||||||
[_h(7, "Sivan")] MSG %"Shavuot 2%"
|
REM [hebdate(7, "Sivan")] MSG %"Shavuot 2%"
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
# Fairly sure Reform Jews don't observe the next two
|
# Fairly sure Reform Jews don't observe the next two
|
||||||
IF !Reform
|
IF !Reform
|
||||||
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
|
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
|
||||||
# fall on a Saturday
|
# fall on a Saturday
|
||||||
[_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b.
|
REM [_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b.
|
||||||
[_PastSat(9, "Av")] ++4 MSG %"Tish'a B'Av%" is %b.
|
REM [_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,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"
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
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
|
||||||
@@ -525,9 +525,9 @@ contains the back value. If the "back" value was \-n, the value will
|
|||||||
be positive; if it was \-\-n, the value will be negative.
|
be positive; if it was \-\-n, the value will be negative.
|
||||||
.TP
|
.TP
|
||||||
.B delta \fIn\fR
|
.B delta \fIn\fR
|
||||||
If the reminder contained a "delta" clause (\+n or \+\+n), this key
|
If the reminder contained a "delta" clause (+n or ++n), this key
|
||||||
contains the delta value. If the "delta" value was \+n, the value will
|
contains the delta value. If the "delta" value was +n, the value will
|
||||||
be positive; if it was \+\+n, the value will be negative.
|
be positive; if it was ++n, the value will be negative.
|
||||||
.TP
|
.TP
|
||||||
.B rep \fIn\fR
|
.B rep \fIn\fR
|
||||||
If the reminder contained a "repeat" clause (*n), this key contains
|
If the reminder contained a "repeat" clause (*n), this key contains
|
||||||
|
|||||||
543
man/remind.1.in
543
man/remind.1.in
@@ -11,8 +11,8 @@ reminder or alarm can consist of a message sent to standard output, or
|
|||||||
a program to be executed.
|
a program to be executed.
|
||||||
.PP
|
.PP
|
||||||
If \fIfilename\fR is specified as a single dash '-', then \fBRemind\fR
|
If \fIfilename\fR is specified as a single dash '-', then \fBRemind\fR
|
||||||
takes its input from standard input. This also implicitly enables
|
takes its input from standard input.
|
||||||
the \fB\-o\fR option, described below.
|
|
||||||
.PP
|
.PP
|
||||||
If \fIfilename\fR happens to
|
If \fIfilename\fR happens to
|
||||||
be a directory rather than a plain file, then \fBRemind\fR reads all of
|
be a directory rather than a plain file, then \fBRemind\fR reads all of
|
||||||
@@ -28,15 +28,12 @@ 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
|
||||||
date by piping the output through \fBsort(1)\fR. Note that the \fB\-n\fR
|
date by piping the output through \fBsort(1)\fR. Note that the \fB\-n\fR
|
||||||
option causes any \fB\-g\fR option to be \fIignored\fR.
|
option causes any \fB\-g\fR option to be \fIignored\fR and also implicitly
|
||||||
|
enables the \fB\-o\fR option.
|
||||||
.TP
|
.TP
|
||||||
.B \-j\fR[\fIn\fR]
|
.B \-j\fR[\fIn\fR]
|
||||||
Runs \fBRemind\fR in "purge" mode to get rid of expired reminders.
|
Runs \fBRemind\fR in "purge" mode to get rid of expired reminders.
|
||||||
@@ -51,7 +48,7 @@ The \fB\-c\fR option causes \fBRemind\fR to produce a calendar that is
|
|||||||
sent to standard output. If you supply a number \fIn\fR, then a
|
sent to standard output. If you supply a number \fIn\fR, then a
|
||||||
calendar will be generated for \fIn\fR months, starting with the
|
calendar will be generated for \fIn\fR months, starting with the
|
||||||
current month. By default, a calendar for only the current month is
|
current month. By default, a calendar for only the current month is
|
||||||
produced.
|
produced. This option implicitly enables the \fB\-o\fR option.
|
||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
You can precede \fIn\fR (if any) with a set of flags. The flags
|
You can precede \fIn\fR (if any) with a set of flags. The flags
|
||||||
@@ -66,7 +63,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
|
||||||
@@ -177,7 +174,7 @@ The \fB\-s\fR option is very similar to the \fB\-c\fR option, except
|
|||||||
that the output calendar is not formatted. It is listed in a "simple
|
that the output calendar is not formatted. It is listed in a "simple
|
||||||
format" that can be used as input for more sophisticated calendar-drawing
|
format" that can be used as input for more sophisticated calendar-drawing
|
||||||
programs. If \fIn\fR starts with "+", then it is interpreted as a number
|
programs. If \fIn\fR starts with "+", then it is interpreted as a number
|
||||||
of weeks.
|
of weeks. This option also implicitly enables the \fB\-o\fR option.
|
||||||
|
|
||||||
If you immediately follow the \fBs\fR with the letter
|
If you immediately follow the \fBs\fR with the letter
|
||||||
\fBa\fR, then \fBRemind\fR displays reminders on the calendar on the
|
\fBa\fR, then \fBRemind\fR displays reminders on the calendar on the
|
||||||
@@ -204,6 +201,9 @@ letter with this option, then the normal calendar-mode substitution filter
|
|||||||
is disabled and the %"...%" sequences are preserved in the output.
|
is disabled and the %"...%" sequences are preserved in the output.
|
||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
|
The \fB\-p\fR, \fB\-pp\fR and \fB\-ppp\fR options implicitly enable
|
||||||
|
the \fB\-o\fR option.
|
||||||
|
.PP
|
||||||
Note that the \fB\-pp\fR or \fB\-ppp\fR options also enable the \fB\-l\fR
|
Note that the \fB\-pp\fR or \fB\-ppp\fR options also enable the \fB\-l\fR
|
||||||
option.
|
option.
|
||||||
.RE
|
.RE
|
||||||
@@ -227,7 +227,11 @@ error, and to print a security message if a script tests the
|
|||||||
$RunOff system variable.
|
$RunOff system variable.
|
||||||
.TP
|
.TP
|
||||||
.B \-o
|
.B \-o
|
||||||
The \fB\-o\fR option causes \fBRemind\fR to ignore all \fBONCE\fR directives.
|
The \fB\-o\fR option causes \fBRemind\fR to ignore all \fBONCE\fR
|
||||||
|
directives. Note that \fBONCE\fR is also ignored if any of the
|
||||||
|
\fB\-c\fR, \fB\-n\fR, \fB\-p\fR, or \fB\-s\fR options is used, if a
|
||||||
|
repetition factor \fB*n\fR is used, or if a date other than today's
|
||||||
|
date is specified on the command-line.
|
||||||
.TP
|
.TP
|
||||||
.B \-t
|
.B \-t
|
||||||
The \fB\-t\fR option causes \fBRemind\fR to trigger all non-expired reminders,
|
The \fB\-t\fR option causes \fBRemind\fR to trigger all non-expired reminders,
|
||||||
@@ -236,13 +240,13 @@ regardless of the \fIdelta\fR supplied for each reminder.
|
|||||||
.B \-t\fR\fIn\fR
|
.B \-t\fR\fIn\fR
|
||||||
If you supply a number \fIn\fR after the \fB\-t\fR option, then
|
If you supply a number \fIn\fR after the \fB\-t\fR option, then
|
||||||
\fBRemind\fR pretends that echo \fBREM\fR command has a delta
|
\fBRemind\fR pretends that echo \fBREM\fR command has a delta
|
||||||
of \+\+\fIn\fR, regardless of any existing delta.
|
of ++\fIn\fR, regardless of any existing delta.
|
||||||
.TP
|
.TP
|
||||||
.B \-tz\fR
|
.B \-tz\fR
|
||||||
If you supply the letter \fBz\fR after the \fB\-t\fR option, then
|
If you supply the letter \fBz\fR after the \fB\-t\fR option, then
|
||||||
\fBRemind\fR sets all REM statements' deltas to zero, regardless of the
|
\fBRemind\fR sets all REM statements' deltas to zero, regardless of the
|
||||||
value supplied in the REM statement itself. In effect, this disables
|
value supplied in the REM statement itself. In effect, this disables
|
||||||
all deltas of the form \fB\+\fIn\fR and \fB\+\+\fIn\fR.
|
all deltas of the form \fB+\fIn\fR and \fB++\fIn\fR.
|
||||||
.TP
|
.TP
|
||||||
.B \-tt\fR[\fIn\fR]
|
.B \-tt\fR[\fIn\fR]
|
||||||
The \fB-tt\fR option causes \fBRemind\fR to assume a default delta of
|
The \fB-tt\fR option causes \fBRemind\fR to assume a default delta of
|
||||||
@@ -300,6 +304,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 +370,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 +424,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 +457,38 @@ 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:
|
||||||
|
|
||||||
|
.PP
|
||||||
|
.B \-\-version
|
||||||
|
The \fB\-\-version\fR option causes \fBRemind\fR to print its version number
|
||||||
|
to standard output and then exit.
|
||||||
|
.TP
|
||||||
|
.B \-\-print-tokens
|
||||||
|
The \fB\-\-print-tokens\fR option causes \fBRemind\fR to print the tokens
|
||||||
|
used by the parser, built-in function names, and system variable names
|
||||||
|
to standard output and then exit. This output is designed to make it easy
|
||||||
|
to create a syntax-highlighting file for various text editors. The output
|
||||||
|
can be modified by hand or by a script into a syntax-highlighting file
|
||||||
|
with relative ease.
|
||||||
|
.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 +497,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
|
||||||
@@ -512,12 +563,15 @@ Its syntax is:
|
|||||||
The parts of the \fBREM\fR command can be specified in any order, except
|
The parts of the \fBREM\fR command can be specified in any order, except
|
||||||
that the \fIbody\fR must come immediately after the \fBMSG\fR,
|
that the \fIbody\fR must come immediately after the \fBMSG\fR,
|
||||||
\fBRUN\fR, \fBCAL\fR, \fBPS\fR, \fBPSFILE\fR or \fBSATISFY\fR keyword.
|
\fBRUN\fR, \fBCAL\fR, \fBPS\fR, \fBPSFILE\fR or \fBSATISFY\fR keyword.
|
||||||
|
The portion of the \fBREM\fR command before the \fBMSG\fR, \fBMSF\fR
|
||||||
|
\fBRUN\fR, \fBCAL\fR or \fBSATISFY\fR clause is called a
|
||||||
|
\fItrigger\fR.
|
||||||
.PP
|
.PP
|
||||||
The \fBREM\fR token is optional, providing that the remainder
|
In earlier versions of \fBRemind\fR, the \fBREM\fR token was optional
|
||||||
of the command cannot be mistaken for another \fBRemind\fR command
|
providing that the remainder of the command cannot be mistaken for
|
||||||
such as \fBOMIT\fR or \fBRUN\fR. The portion of the \fBREM\fR command
|
another \fBRemind\fR command. However, this use is deprecated and will
|
||||||
before the \fBMSG\fR, \fBMSF\fR \fBRUN\fR, \fBCAL\fR or \fBSATISFY\fR clause
|
now cause a warning to be issued. All of your reminder lines should
|
||||||
is called a \fItrigger\fR.
|
be written to start with the REM command.
|
||||||
.PP
|
.PP
|
||||||
.B "MSG, MSF, RUN, CAL, SPECIAL, PS and PSFILE"
|
.B "MSG, MSF, RUN, CAL, SPECIAL, PS and PSFILE"
|
||||||
.PP
|
.PP
|
||||||
@@ -530,14 +584,16 @@ used the \fB\-k\fR command-line option, then \fBMSG\fR-type reminders are
|
|||||||
passed to the appropriate program. Note that the options \fB\-c\fR,
|
passed to the appropriate program. Note that the options \fB\-c\fR,
|
||||||
\fB\-s\fR, \fB\-p\fR and \fB\-n\fR disable the \fB\-k\fR option.
|
\fB\-s\fR, \fB\-p\fR and \fB\-n\fR disable the \fB\-k\fR option.
|
||||||
.PP
|
.PP
|
||||||
Note that you can omit the reminder type, in which case it
|
Earlier versions of \fBRemind\fR let you omit the reminder type,
|
||||||
defaults to \fBMSG\fR. So you can write:
|
in which case it defaulted to \fBMSG\fR. However, this usage is
|
||||||
|
deprecated and will cause a warning. Something like:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
6 January Dianne's Birthday
|
REM 6 January Dianne's Birthday
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
although this is not recommended.
|
will issue the warning "Missing REM type; assuming MSG"
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
The \fBMSF\fR keyword is almost the same as the \fBMSG\fR keyword,
|
The \fBMSF\fR keyword is almost the same as the \fBMSG\fR keyword,
|
||||||
except that the reminder is formatted to fit into a paragraph-like
|
except that the reminder is formatted to fit into a paragraph-like
|
||||||
@@ -984,26 +1040,35 @@ overrides that.
|
|||||||
.B THE ONCE KEYWORD
|
.B THE ONCE KEYWORD
|
||||||
.PP
|
.PP
|
||||||
Sometimes, it is necessary to ensure that reminders are run only once
|
Sometimes, it is necessary to ensure that reminders are run only once
|
||||||
on a given day. For example, if you have a reminder that makes a backup
|
on a given day. For example, compare the following two reminders:
|
||||||
of your files every Friday:
|
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
REM Fri RUN do_backup
|
REM Fri RUN do_backup
|
||||||
|
REM Fri ONCE RUN do_backup
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
(Here, \fIdo_backup\fR is assumed to be a program or shell script that
|
The first will be run every time you invoke \fBRemind\fR on a Friday,
|
||||||
does the work.) If you run \fBRemind\fR from your .login script, for
|
whereas the second will be run only the first time you invoke
|
||||||
example, and log in several times per day, the \fIdo_backup\fR program
|
\fBRemind\fR on a given Friday.
|
||||||
will be run each time you log in. If, however, you use the \fBONCE\fR
|
.PP
|
||||||
keyword in the reminder, the \fBRemind\fR checks the last access date of
|
If you run \fBRemind\fR from your .login script, for example, and log
|
||||||
the reminder script. If it is the same as the current date, \fBRemind\fR
|
in several times per day, the \fIdo_backup\fR program in the first
|
||||||
assumes that it has already been run, and will not issue reminders containing
|
reminder will be run each time you log in. If, however, you use the
|
||||||
the \fBONCE\fR keyword.
|
\fBONCE\fR keyword in the reminder, the \fBRemind\fR checks the last
|
||||||
|
access date of the reminder script. If it is the same as the current
|
||||||
|
date, \fBRemind\fR assumes that it has already been run, and will not
|
||||||
|
issue reminders containing the \fBONCE\fR keyword.
|
||||||
.PP
|
.PP
|
||||||
Note that if you view or edit your reminder script, the last access date
|
Note that if you view or edit your reminder script, the last access date
|
||||||
will be updated, and the \fBONCE\fR keyword will not operate properly.
|
will be updated, and the \fBONCE\fR keyword will not operate properly.
|
||||||
|
You can fix this by setting a timestamp file for \fBRemind\fR to track
|
||||||
|
the last-run date; see the documentation of \fB$OnceFile\fR in the
|
||||||
|
\fBSYSTEM VARIABLES\fR section. If you use standard input as your
|
||||||
|
\fBRemind\fR input file, then you \fImust\fR use \fB$OnceFile\fR for the
|
||||||
|
\fBONCE\fR keyword to work properly.
|
||||||
|
.PP
|
||||||
If you start \fBRemind\fR with the \fB\-o\fR option, then the \fBONCE\fR
|
If you start \fBRemind\fR with the \fB\-o\fR option, then the \fBONCE\fR
|
||||||
keyword will be ignored.
|
keyword will be ignored and any \fB$OnceFile\fR will be ignored.
|
||||||
.PP
|
.PP
|
||||||
.B LOCALLY OMITTING WEEKDAYS
|
.B LOCALLY OMITTING WEEKDAYS
|
||||||
.PP
|
.PP
|
||||||
@@ -1513,7 +1578,35 @@ is replaced with "\fIyy\fR", the last two digits of the year.
|
|||||||
.TP
|
.TP
|
||||||
.B %_
|
.B %_
|
||||||
(percent-underscore) is replaced with a newline. You can use this to
|
(percent-underscore) is replaced with a newline. You can use this to
|
||||||
achieve multi-line reminders.
|
achieve multi-line reminders. Note that calendar back-ends vary in
|
||||||
|
how they handle multi-line reminders:
|
||||||
|
.RS
|
||||||
|
.TP
|
||||||
|
.B o
|
||||||
|
Running \fBremind -c\fR preserves newlines in the terminal calendar output.
|
||||||
|
.TP
|
||||||
|
.B o
|
||||||
|
\fBrem2pdf\fR preserves newlines if \fBremind\fR is invoked with the \fB\-pp\fR
|
||||||
|
or \fB\-ppp\fR option.
|
||||||
|
.TP
|
||||||
|
.B o
|
||||||
|
\fBrem2html\fR preserves newlines if \fBremind\fR is invoked with the
|
||||||
|
\fB\-pp\fR option.
|
||||||
|
.TP
|
||||||
|
.B o
|
||||||
|
\fBtkremind\fR preserves newlines.\fR
|
||||||
|
.TP
|
||||||
|
.B o
|
||||||
|
\fBrem2ps\fR converts newlines to spaces. But \fBrem2ps\fR is deprecated;
|
||||||
|
use \fBrem2pdf\fR instead.
|
||||||
|
.TP
|
||||||
|
.B o
|
||||||
|
The "simple calendar" formats (ie, \fBremind\fR's \fB\-s\fR, \fB\-n\fR and
|
||||||
|
\fB\-p\fR options) convert newlines to spaces.
|
||||||
|
.PP
|
||||||
|
All calendar back-ends collapse multiple spaces to a single space and
|
||||||
|
multiple newlines to a single newline.
|
||||||
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B %1
|
.B %1
|
||||||
is replaced with "now", "\fIm\fR minutes from now", "\fIm\fR minutes ago",
|
is replaced with "now", "\fIm\fR minutes from now", "\fIm\fR minutes ago",
|
||||||
@@ -1647,7 +1740,7 @@ or:
|
|||||||
The \fBOMIT\fR command is used to "globally" omit certain days
|
The \fBOMIT\fR command is used to "globally" omit certain days
|
||||||
(usually holidays). These globally-omitted days are skipped by the
|
(usually holidays). These globally-omitted days are skipped by the
|
||||||
"\-" and "+" forms of \fIback\fR and \fIdelta\fR, but not by the
|
"\-" and "+" forms of \fIback\fR and \fIdelta\fR, but not by the
|
||||||
"\-\-" and "\+\+" forms. Some examples:
|
"\-\-" and "++" forms. Some examples:
|
||||||
.PP
|
.PP
|
||||||
.nf
|
.nf
|
||||||
OMIT Saturday Sunday
|
OMIT Saturday Sunday
|
||||||
@@ -1867,24 +1960,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
|
||||||
@@ -1896,6 +1971,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
|
||||||
@@ -1937,6 +2036,10 @@ your INCLUDECMD uses expression-pasting that results in differences depending
|
|||||||
on the value of \fBtoday()\fR, then each \fIunique\fR version of the
|
on the value of \fBtoday()\fR, then each \fIunique\fR version of the
|
||||||
command will be executed once.
|
command will be executed once.
|
||||||
.PP
|
.PP
|
||||||
|
If a given reminder file contains more than one identical
|
||||||
|
\fBINCLUDECMD\fR, only the first one will actually be executed. All
|
||||||
|
subsequent identical ones will use the cached output from the first one.
|
||||||
|
.PP
|
||||||
|
|
||||||
.SH THE BANNER COMMAND
|
.SH THE BANNER COMMAND
|
||||||
.PP
|
.PP
|
||||||
@@ -2086,6 +2189,11 @@ If the \fBTIME\fR is used where \fBRemind\fR expects a time-of-day
|
|||||||
\fIpm\fR suffix and the hour can be as large as you want, so long
|
\fIpm\fR suffix and the hour can be as large as you want, so long
|
||||||
as the total number of minutes in the duration fits in a signed integer
|
as the total number of minutes in the duration fits in a signed integer
|
||||||
variable.
|
variable.
|
||||||
|
.PP
|
||||||
|
For convenience, a \fBTIME\fR constant may be surrounded by single
|
||||||
|
quotes to match \fBDATE\fR and \fBDATETIME\fR constants, but these
|
||||||
|
quotes are optional. That is, 12:56 and '12:56' represent the same
|
||||||
|
\fBTIME\fR constant.
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B DATE constants
|
.B DATE constants
|
||||||
@@ -2120,11 +2228,11 @@ and time separator characters for \fBDATE\fR and \fBTIME\fR constants apply
|
|||||||
also to \fBDATETIME\fR constants.
|
also to \fBDATETIME\fR constants.
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
.B ZERO VALUES
|
.B ZERO VALUES AND TRUE/FALSE
|
||||||
.PP
|
.PP
|
||||||
The non-string types all have an associated \fIzero\fR value, which is
|
All types have an associated \fIzero value\fR, which is treated as
|
||||||
treated as "false" by the IF command and the logical operators. The
|
\fIfalse\fR by the IF command, the IIF function, and the logical
|
||||||
zero values are:
|
operators. The zero values are:
|
||||||
.PP
|
.PP
|
||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
@@ -2135,10 +2243,11 @@ zero values are:
|
|||||||
\fBTIME\fR - 00:00
|
\fBTIME\fR - 00:00
|
||||||
.PP
|
.PP
|
||||||
\fBDATETIME\fR - '1990-01-01@00:00'
|
\fBDATETIME\fR - '1990-01-01@00:00'
|
||||||
|
.PP
|
||||||
|
\fBSTRING\fR - "" (the empty string)
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
Additionally, for the purpose of the IF command (but \fInot\fR the
|
Any value other than the \fIzero value\fR is treated as \fItrue\fR.
|
||||||
logical operators) the empty string "" is considered a false value.
|
|
||||||
.PP
|
.PP
|
||||||
.B OPERATORS
|
.B OPERATORS
|
||||||
.PP
|
.PP
|
||||||
@@ -2148,21 +2257,21 @@ 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
|
||||||
.PP
|
.PP
|
||||||
.TP
|
.TP
|
||||||
.B !
|
.B !
|
||||||
Logical negation. Can be applied to an \fBINT\fR type. If the operand
|
Logical negation. Can be applied to any type. If the operand
|
||||||
is non-zero, returns zero. Otherwise, returns 1.
|
is non-zero, returns 0. Otherwise, returns 1.
|
||||||
.TP
|
.TP
|
||||||
.B \-
|
.B \-
|
||||||
Unary minus. Can be applied to an \fBINT\fR. Returns the negative
|
Unary minus. Can be applied to an \fBINT\fR. Returns the negative
|
||||||
@@ -2266,16 +2375,16 @@ 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. Returns the second operand if both
|
||||||
same type and must not be \fBSTRING\fR type. Returns the second
|
operands are non-zero. Otherwise, returns whichever operand is zero.
|
||||||
operand if both operands are non-zero. Otherwise, returns a zero
|
Operands can be any type and "zero" is interpreted as appropriate for
|
||||||
of the same type as the operands.
|
each operand's type.
|
||||||
.TP
|
.TP
|
||||||
.B ||
|
.B ||
|
||||||
This is the logical OR operator. Both of its operands must be of
|
This is the logical OR operator. It returns the first operand that is
|
||||||
the same type and must not be of \fBSTRING\fR type. It returns
|
non-zero; if both operands are zero, then returns the second operand.
|
||||||
the first operand that is non-zero; if both operands are zero, then
|
Operands can be any type and "zero" is interpreted as appropriate for
|
||||||
returns a zero of the same type as the operands.
|
each operand's type.
|
||||||
.PP
|
.PP
|
||||||
.B NOTES
|
.B NOTES
|
||||||
.PP
|
.PP
|
||||||
@@ -2296,15 +2405,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
|
||||||
@@ -2386,9 +2490,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
|
||||||
@@ -2461,6 +2565,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.
|
||||||
@@ -2489,9 +2601,9 @@ truncated - the width limit will be ignored.
|
|||||||
If non-zero, then the \fB\-h\fR option was supplied on the command line.
|
If non-zero, then the \fB\-h\fR option was supplied on the command line.
|
||||||
.TP
|
.TP
|
||||||
.B $IgnoreOnce (read-only)
|
.B $IgnoreOnce (read-only)
|
||||||
If non-zero, then the \fB\-o\fR option was supplied on the command line,
|
If non-zero, then the \fB\-o\fR option was supplied on the command
|
||||||
or a date different from today's true date was supplied. If non-zero,
|
line, or implicitly enabled for some other reason. In this case,
|
||||||
then \fBONCE\fR directives will be ignored.
|
\fBONCE\fR directives will be ignored.
|
||||||
.TP
|
.TP
|
||||||
.B $InfDelta (read-only)
|
.B $InfDelta (read-only)
|
||||||
If non-zero, then the \fB\-t\fR option was supplied on the command line,
|
If non-zero, then the \fB\-t\fR option was supplied on the command line,
|
||||||
@@ -2648,6 +2760,20 @@ by \fBREM\fR commands; triggers in \fBIFTRIG\fR commands do
|
|||||||
not affect it.
|
not affect it.
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
|
.B $OnceFile (STRING type)
|
||||||
|
If you set this variable to a non-empty string, then rather than using
|
||||||
|
the file access date to determine whether or not to run a ONCE-type
|
||||||
|
reminder, \fBRemind\fR will maintain a timestamp in the file \fB$OnceFile\fR.
|
||||||
|
This is more reliable than using the access date of the reminder file.
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
If \fB$OnceFile\fR does not exist, then it will be created the first time
|
||||||
|
a \fBONCE\fR keyword is processed. The file must be writable by the
|
||||||
|
current user. If you try to set \fB$OnceFile\fR \fIafter\fR a \fBONCE\fR
|
||||||
|
reminder has already been processed, \fBRemind\fR will issue a warning
|
||||||
|
and ignore the attempt to set \fB$OnceFile\fR.
|
||||||
|
.RE
|
||||||
|
.TP
|
||||||
.B $ParseUntriggered
|
.B $ParseUntriggered
|
||||||
A flag indicating whether or not \fBRemind\fR should fully parse \fBREM\fR
|
A flag indicating whether or not \fBRemind\fR should fully parse \fBREM\fR
|
||||||
statements that are not triggered. 0 means to skip parsing them and 1
|
statements that are not triggered. 0 means to skip parsing them and 1
|
||||||
@@ -2699,8 +2825,15 @@ order, or 2 if sorting by time in descending order.
|
|||||||
The number of spaces by which all lines (except the first) of an
|
The number of spaces by which all lines (except the first) of an
|
||||||
\fBMSF\fR-type reminder should be indented. The default is 0.
|
\fBMSF\fR-type reminder should be indented. The default is 0.
|
||||||
.TP
|
.TP
|
||||||
|
.B $SuppressImplicitWarnings
|
||||||
|
Normally, \fBRemind\fR issues a warning if a line begins with an unknown
|
||||||
|
token and is treated as a \fBREM\fR command, or if a \fBREM\fR command
|
||||||
|
is missing a type and is treated as a \fBMSG\fR-type reminder. Setting
|
||||||
|
\fB$SuppressImplicitWarnings\fR to 1 suppresses these warnings. The default
|
||||||
|
is 0 and we do not recommend disabling the warnings.
|
||||||
|
.TP
|
||||||
.B $SuppressLRM
|
.B $SuppressLRM
|
||||||
Normally, when Remind is run with the \fB\-c\fR option in a UTF-8 locale,
|
Normally, when \fBRemind\fR is run with the \fB\-c\fR option in a UTF-8 locale,
|
||||||
it emits a left-to-right mark sequence after printing day names or
|
it emits a left-to-right mark sequence after printing day names or
|
||||||
reminders. Some terminals render this incorrectly, so you can use:
|
reminders. Some terminals render this incorrectly, so you can use:
|
||||||
.RS
|
.RS
|
||||||
@@ -2734,6 +2867,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
|
||||||
@@ -2823,18 +2959,25 @@ is supplied, only the date component is used.
|
|||||||
Returns the time of "astronomical twilight" on the specified \fIdate\fR. If
|
Returns the time of "astronomical 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 ampm(tq_time [,s_am [,s_pm]])
|
.B ampm(tq_time [,s_am [,s_pm [,i_lz]]])
|
||||||
Returns a \fBSTRING\fR that is the result of converting \fItime\fR
|
Returns a \fBSTRING\fR that is the result of converting \fItime\fR
|
||||||
(which is either a \fBTIME\fR or a \fBDATETIME\fR object) to "AM/PM"
|
(which is either a \fBTIME\fR or a \fBDATETIME\fR object) to "AM/PM"
|
||||||
format. The optional arguments \fIam\fR and \fIpm\fR are the strings
|
format. The optional arguments \fIam\fR and \fIpm\fR are the strings
|
||||||
to append in the AM and PM case, respectively; they default to "AM"
|
to append in the AM and PM case, respectively; they default to "AM"
|
||||||
and "PM". The function obeys the system variables $DateSep,
|
and "PM". The optional argument \fIlz\fR specifies whether or not
|
||||||
$TimeSep and $DateTimeSep when formatting its output. For example:
|
the hour should be padded to two digits with a leading zero. If \fIlz\fR is
|
||||||
|
zero, then a leading 0 is not added; otherwise, the hour is padded out to
|
||||||
|
two digits with a leading zero. If not supplied, \fIlz\fR defaults to zero.
|
||||||
.RS
|
.RS
|
||||||
.PP
|
.PP
|
||||||
|
The function obeys the system variables $DateSep, $TimeSep and
|
||||||
|
$DateTimeSep when formatting its output. Here are some examples of
|
||||||
|
its output:
|
||||||
|
.PP
|
||||||
.nf
|
.nf
|
||||||
ampm(0:22) returns "12:22AM"
|
ampm(0:22) returns "12:22AM"
|
||||||
ampm(17:45, "am", "pm") returns "5:45pm"
|
ampm(17:45, "am", "pm") returns "5:45pm"
|
||||||
|
ampm(17:45, "am", "pm", 1) returns "05:45pm"
|
||||||
ampm('2020-03-14@21:34') returns "2020-03-14@9:34PM"
|
ampm('2020-03-14@21:34') returns "2020-03-14@9:34PM"
|
||||||
.fi
|
.fi
|
||||||
.PP
|
.PP
|
||||||
@@ -3080,11 +3223,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
|
||||||
@@ -3193,14 +3337,14 @@ out. The stripping algorithm is fairly naive; the function starts
|
|||||||
stripping characters when it encounters a "<" and it stops stripping
|
stripping characters when it encounters a "<" and it stops stripping
|
||||||
when it encounters a ">".
|
when it encounters a ">".
|
||||||
.TP
|
.TP
|
||||||
.B iif(si_test1, x_arg1, [si_test2, x_arg2,...], x_default)
|
.B iif(x_test1, x_arg1, [x_test2, x_arg2,...], x_default)
|
||||||
If \fItest1\fR is not zero or the null string, returns \fIarg1\fR.
|
If \fItest1\fR is true, returns \fIarg1\fR. Otherwise, if \fItest2\fR
|
||||||
Otherwise, if \fItest2\fR is not zero or the null string, returns
|
is true, returns \fIarg2\fR, and so on. If all of the \fItest\fR
|
||||||
\fIarg2\fR, and so on. If all of the \fItest\fR arguments are false,
|
arguments are false, returns \fIdefault\fR. Note that all arguments
|
||||||
returns \fIdefault\fR. Note that all arguments are \fIalways\fR evaluated.
|
are \fIalways\fR evaluated. This function accepts an odd number of
|
||||||
This function accepts an odd number of arguments - note that prior to version
|
arguments - note that prior to version 03.00.05 of \fBRemind\fR, it
|
||||||
03.00.05 of \fBRemind\fR, it accepted 3 arguments only. The 3-argument
|
accepted 3 arguments only. The 3-argument version of \fBiif()\fR is
|
||||||
version of \fBiif()\fR is compatible with previous versions of \fBRemind\fR.
|
compatible with previous versions of \fBRemind\fR.
|
||||||
.TP
|
.TP
|
||||||
.B index(s_search, s_target [,i_start)
|
.B index(s_search, s_target [,i_start)
|
||||||
Returns an \fBINT\fR that is the location of \fItarget\fR in the
|
Returns an \fBINT\fR that is the location of \fItarget\fR in the
|
||||||
@@ -3346,6 +3490,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
|
||||||
@@ -3439,11 +3639,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
|
||||||
@@ -3764,7 +3965,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
|
||||||
@@ -3772,58 +3973,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.
|
||||||
@@ -4163,6 +4315,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
|
||||||
@@ -4399,11 +4559,10 @@ The above sequence sets y to 1, which is the global value of x.
|
|||||||
.TP
|
.TP
|
||||||
o
|
o
|
||||||
User-defined functions may call other functions, including other user-defined
|
User-defined functions may call other functions, including other user-defined
|
||||||
functions. However, recursive calls are not allowed.
|
functions. Recursive calls are allowed, but they must terminate (for
|
||||||
.TP
|
example, by using a short-circuit operator or function that breaks the
|
||||||
o
|
recursion) or an error will result after a certain maximum number of
|
||||||
User-defined functions are not syntax-checked when they are defined; parsing
|
recursive calls (by default, 1000.)
|
||||||
occurs only when they are called.
|
|
||||||
.TP
|
.TP
|
||||||
o
|
o
|
||||||
If a user-defined function has the same name as a built-in function,
|
If a user-defined function has the same name as a built-in function,
|
||||||
@@ -4425,6 +4584,11 @@ or thirdfunc will exist. \fBRemind\fR does not issue an error if you
|
|||||||
try to \fBFUNSET\fR a nonexistent user-defined function; it simply
|
try to \fBFUNSET\fR a nonexistent user-defined function; it simply
|
||||||
does nothing in that case.
|
does nothing in that case.
|
||||||
.PP
|
.PP
|
||||||
|
If you define a user-defined function and then later on redefine it,
|
||||||
|
\fBRemind\fR will issue a warning. If you do not want this warning,
|
||||||
|
then use \fBFUNSET\fR to remove the existing definition before you
|
||||||
|
redefine the function.
|
||||||
|
.PP
|
||||||
.SH PRECISE SCHEDULING
|
.SH PRECISE SCHEDULING
|
||||||
.PP
|
.PP
|
||||||
The \fBWARN\fR keyword allows precise control over advance warning in
|
The \fBWARN\fR keyword allows precise control over advance warning in
|
||||||
@@ -4558,8 +4722,11 @@ the error message "Can't compute trigger" is issued. Otherwise,
|
|||||||
\fBtrigvalid()\fR is set to 1.
|
\fBtrigvalid()\fR is set to 1.
|
||||||
.PP
|
.PP
|
||||||
This is really useful only if \fIexpr\fR involves a call to the
|
This is really useful only if \fIexpr\fR involves a call to the
|
||||||
\fBtrigdate()\fR or related functions; otherwise, \fIexpr\fR will not change as
|
\fBtrigdate()\fR or related functions or system variables; otherwise,
|
||||||
\fBRemind\fR iterates.
|
\fIexpr\fR will not change as \fBRemind\fR iterates. In fact, if
|
||||||
|
\fIexpr\fR is not a constant and does not call \fBtrigdate()\fR or
|
||||||
|
related functions or system variables, then \fBRemind\fR will issue a
|
||||||
|
warning.
|
||||||
.PP
|
.PP
|
||||||
An example of the usefulness of \fBSATISFY\fR: Suppose you wish to
|
An example of the usefulness of \fBSATISFY\fR: Suppose you wish to
|
||||||
be warned of every Friday the 13th. Your first attempt may be:
|
be warned of every Friday the 13th. Your first attempt may be:
|
||||||
@@ -4710,7 +4877,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.
|
||||||
@@ -5014,21 +5181,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 &
|
||||||
@@ -5255,7 +5426,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
|
||||||
@@ -5358,7 +5529,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.
|
||||||
@@ -5686,10 +5857,6 @@ after the WEEK keyword.
|
|||||||
The following tokens can be abbreviated:
|
The following tokens can be abbreviated:
|
||||||
.TP
|
.TP
|
||||||
o
|
o
|
||||||
\fBREM\fR can be omitted - it is implied if no other valid command
|
|
||||||
is present.
|
|
||||||
.TP
|
|
||||||
o
|
|
||||||
\fBCLEAR-OMIT-CONTEXT\fR --> \fBCLEAR\fR
|
\fBCLEAR-OMIT-CONTEXT\fR --> \fBCLEAR\fR
|
||||||
.TP
|
.TP
|
||||||
o
|
o
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -264,7 +266,7 @@ Useful strings might be "emacs +%d %s" or "gvim +%d %s"
|
|||||||
.TP
|
.TP
|
||||||
.B Extra Argument for Remind
|
.B Extra Argument for Remind
|
||||||
This specifies any extra arguments that should be passed to Remind
|
This specifies any extra arguments that should be passed to Remind
|
||||||
when \BTkRemind\fR invokes \fBremind\fR. Unless you know what
|
when \fBTkRemind\fR invokes \fBremind\fR. Unless you know what
|
||||||
you are doing, leave this blank.
|
you are doing, leave this blank.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
@@ -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,75 +368,99 @@ 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
|
.PP
|
||||||
Please note that \fBRemind\fR can write a status message \fIat any time\fR
|
Please note that \fBRemind\fR can write a status message \fIat any time\fR
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -374,19 +374,37 @@ sub parse_input
|
|||||||
($1 % 256), ($1 % 256), ($1 % 256));
|
($1 % 256), ($1 % 256), ($1 % 256));
|
||||||
}
|
}
|
||||||
} elsif ($special eq 'COLOR' || $special eq 'COLOUR') {
|
} elsif ($special eq 'COLOR' || $special eq 'COLOUR') {
|
||||||
if ($body =~ /(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/) {
|
if ($body =~ /(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/s) {
|
||||||
my($r, $g, $b, $text) = ($1, $2, $3, $4);
|
my($r, $g, $b, $text) = ($1, $2, $3, $4);
|
||||||
my $color = sprintf("style=\"color: #%02X%02X%02X;\"",
|
my $color = sprintf("style=\"color: #%02X%02X%02X;\"",
|
||||||
$r % 256, $g % 256, $b % 256);
|
$r % 256, $g % 256, $b % 256);
|
||||||
push(@{$days->[$d]}, "<p$class $color>" . escape_html($text) . '</p>');
|
push(@{$days->[$d]}, "<p$class $color>" . fix_whitespace(escape_html($text)) . '</p>');
|
||||||
}
|
}
|
||||||
} elsif ($special eq '*') {
|
} elsif ($special eq '*') {
|
||||||
push(@{$days->[$d]}, "<p$class>" . escape_html($body) . '</p>');
|
push(@{$days->[$d]}, "<p$class>" . fix_whitespace(escape_html($body)) . '</p>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $found_data;
|
return $found_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub fix_whitespace
|
||||||
|
{
|
||||||
|
my ($text) = @_;
|
||||||
|
|
||||||
|
# Collapse multiple spaces/tabs to a single space
|
||||||
|
$text =~ s/[ \t]+/ /gs;
|
||||||
|
|
||||||
|
# Remove whitespace before/after newlines
|
||||||
|
$text =~ s/\s+\n/\n/gs;
|
||||||
|
$text =~ s/\n\s+/\n/gs;
|
||||||
|
# Collapse multiple newlines to a single newline
|
||||||
|
$text =~ s/\n+/\n/gs;
|
||||||
|
|
||||||
|
# Convert newlines to <br />
|
||||||
|
$text =~ s|\n|<br />|g;
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
sub small_calendar
|
sub small_calendar
|
||||||
{
|
{
|
||||||
my($month, $monlen, $url, $first_col) = @_;
|
my($month, $monlen, $url, $first_col) = @_;
|
||||||
@@ -60,7 +60,9 @@ my $settings = {
|
|||||||
margin_bottom => 36,
|
margin_bottom => 36,
|
||||||
margin_left => 36,
|
margin_left => 36,
|
||||||
margin_right => 36,
|
margin_right => 36,
|
||||||
|
svg => 0,
|
||||||
|
ps => 0,
|
||||||
|
eps => 0,
|
||||||
verbose => 0,
|
verbose => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,6 +82,9 @@ Options:
|
|||||||
|
|
||||||
--landscape, -l Print in landscape orientation
|
--landscape, -l Print in landscape orientation
|
||||||
--small-calendars=N Choose location for small calendars
|
--small-calendars=N Choose location for small calendars
|
||||||
|
--svg Output SVG instead of PDF
|
||||||
|
--ps Output PostScript instead of PDF
|
||||||
|
--eps Output encapsulated PostScript instead of PDF
|
||||||
-cN Synonym for --small-calendars=N
|
-cN Synonym for --small-calendars=N
|
||||||
--left-numbers, -x Print day numbers on the left
|
--left-numbers, -x Print day numbers on the left
|
||||||
--fill-page, -e Fill the entire page
|
--fill-page, -e Fill the entire page
|
||||||
@@ -112,6 +117,9 @@ Getopt::Long::Configure('bundling_values');
|
|||||||
my $ret = GetOptions('landscape|l' => \$settings->{landscape},
|
my $ret = GetOptions('landscape|l' => \$settings->{landscape},
|
||||||
'small-calendars|c=i' => \$settings->{small_calendars},
|
'small-calendars|c=i' => \$settings->{small_calendars},
|
||||||
'left-numbers|x' => \$settings->{numbers_on_left},
|
'left-numbers|x' => \$settings->{numbers_on_left},
|
||||||
|
'svg' => \$settings->{svg},
|
||||||
|
'ps' => \$settings->{ps},
|
||||||
|
'eps' => \$settings->{eps},
|
||||||
'fill-page|e' => \$settings->{fill_entire_page},
|
'fill-page|e' => \$settings->{fill_entire_page},
|
||||||
'media|m=s' => \$settings->{media},
|
'media|m=s' => \$settings->{media},
|
||||||
'width|w=i' => \$settings->{width},
|
'width|w=i' => \$settings->{width},
|
||||||
@@ -176,6 +184,17 @@ if ($settings->{landscape}) {
|
|||||||
$settings->{height} = $tmp;
|
$settings->{height} = $tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($settings->{svg} && $settings->{ps} ||
|
||||||
|
$settings->{svg} && $settings->{eps} ||
|
||||||
|
$settings->{eps} && $settings->{ps}) {
|
||||||
|
print STDERR "Only one of --eps, --ps or --svg may be used.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($settings->{eps}) {
|
||||||
|
$settings->{ps} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
# Don't read from a terminal
|
# Don't read from a terminal
|
||||||
if (-t STDIN) { ## no critic
|
if (-t STDIN) { ## no critic
|
||||||
print STDERR "I can't read data from a terminal. Please run like this:\n";
|
print STDERR "I can't read data from a terminal. Please run like this:\n";
|
||||||
@@ -187,8 +206,25 @@ my $done_one = 0;
|
|||||||
|
|
||||||
my $errored_out = 0;
|
my $errored_out = 0;
|
||||||
|
|
||||||
my $surface = Cairo::PdfSurface->create_for_stream(sub { print $_[1] unless $errored_out; }, undef,
|
my $surface;
|
||||||
$settings->{width}, $settings->{height});
|
if ($settings->{svg}) {
|
||||||
|
$surface = Cairo::SvgSurface->create_for_stream(sub { print $_[1] unless $errored_out; }, undef,
|
||||||
|
$settings->{width}, $settings->{height});
|
||||||
|
} elsif ($settings->{ps}) {
|
||||||
|
if ($settings->{landscape}) {
|
||||||
|
$surface = Cairo::PsSurface->create_for_stream(sub { print $_[1] unless $errored_out; }, undef,
|
||||||
|
$settings->{height}, $settings->{width});
|
||||||
|
} else {
|
||||||
|
$surface = Cairo::PsSurface->create_for_stream(sub { print $_[1] unless $errored_out; }, undef,
|
||||||
|
$settings->{width}, $settings->{height});
|
||||||
|
}
|
||||||
|
if ($settings->{eps}) {
|
||||||
|
$surface->set_eps(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$surface = Cairo::PdfSurface->create_for_stream(sub { print $_[1] unless $errored_out; }, undef,
|
||||||
|
$settings->{width}, $settings->{height});
|
||||||
|
}
|
||||||
|
|
||||||
# set_metadata not available in older versions of Cairo
|
# set_metadata not available in older versions of Cairo
|
||||||
eval { $surface->set_metadata('title', 'Calendar'); };
|
eval { $surface->set_metadata('title', 'Calendar'); };
|
||||||
@@ -196,10 +232,26 @@ eval { $surface->set_metadata('author', 'Remind (https://dianne.skoll.ca/project
|
|||||||
eval { $surface->set_metadata('creator', 'rem2pdf (https://dianne.skoll.ca/projects/remind/)'); };
|
eval { $surface->set_metadata('creator', 'rem2pdf (https://dianne.skoll.ca/projects/remind/)'); };
|
||||||
eval { $surface->set_metadata('subject', 'Calendar'); };
|
eval { $surface->set_metadata('subject', 'Calendar'); };
|
||||||
|
|
||||||
|
if ($settings->{ps}) {
|
||||||
|
$surface->dsc_comment('%%Title: Calendar');
|
||||||
|
$surface->dsc_comment('%%Producer: rem2pdf (https://dianne.skoll.ca/projects/remind/)');
|
||||||
|
$surface->dsc_comment('%%PageOrientation: ' . (($settings->{landscape}) ? 'Landscape' : 'Portrait'));
|
||||||
|
$surface->dsc_begin_setup();
|
||||||
|
}
|
||||||
|
|
||||||
my $cr = Cairo::Context->create($surface);
|
my $cr = Cairo::Context->create($surface);
|
||||||
$cr->set_line_width($settings->{line_thickness});
|
$cr->set_line_width($settings->{line_thickness});
|
||||||
|
if ($settings->{ps} && $settings->{landscape}) {
|
||||||
|
$cr->translate(0, $settings->{width});
|
||||||
|
$cr->rotate(-1.5707963267949); # Rotate -90 degrees
|
||||||
|
}
|
||||||
|
|
||||||
|
my $warned = 0;
|
||||||
while(1) {
|
while(1) {
|
||||||
|
if ($settings->{ps}) {
|
||||||
|
$surface->dsc_begin_page_setup();
|
||||||
|
$surface->dsc_comment('%%PageOrientation: ' . (($settings->{landscape}) ? 'Landscape' : 'Portrait'));
|
||||||
|
}
|
||||||
my ($obj, $err) = Remind::PDF->create_from_stream(*STDIN,
|
my ($obj, $err) = Remind::PDF->create_from_stream(*STDIN,
|
||||||
{color => 1,
|
{color => 1,
|
||||||
shade => 1,
|
shade => 1,
|
||||||
@@ -215,8 +267,15 @@ while(1) {
|
|||||||
}
|
}
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
$done_one = 1;
|
if (($settings->{eps} || $settings->{svg}) && $done_one) {
|
||||||
|
if (!$warned) {
|
||||||
|
print STDERR "WARNING: --eps and --svg can only output one page; ignoring subsequent\nmonths in a multi-month calendar.\n";
|
||||||
|
$warned = 1;
|
||||||
|
}
|
||||||
|
next;
|
||||||
|
}
|
||||||
$obj->render($cr, $settings);
|
$obj->render($cr, $settings);
|
||||||
|
$done_one = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$surface->finish();
|
$surface->finish();
|
||||||
@@ -273,17 +332,22 @@ __END__
|
|||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
rem2pdf - draw a PDF calendar from Remind output
|
rem2pdf - draw a PDF, SVG or PostScript calendar from Remind output
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
remind -pp [options] file | rem2pdf [options] > output.pdf
|
remind -pp [options] file | rem2pdf [options] > output.pdf
|
||||||
|
remind -pp [options] file | rem2pdf --svg [options] > output.svg
|
||||||
|
remind -pp [options] file | rem2pdf --ps [options] > output.ps
|
||||||
|
remind -pp [options] file | rem2pdf --eps [options] > output.eps
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
B<rem2pdf> reads the standard input, which should be the results of
|
B<rem2pdf> reads the standard input, which should be the results of
|
||||||
running B<remind> with the B<-p>, B<-pp> or B<-ppp> options. It emits
|
running B<remind> with the B<-p>, B<-pp> or B<-ppp> options. It emits
|
||||||
PDF code that draws a calendar to standard output.
|
PDF, SVG or PostScript code that draws a calendar to standard output. (The
|
||||||
|
addition of support for SVG and PostScript means that rem2pdf is increasingly
|
||||||
|
misnamed...)
|
||||||
|
|
||||||
B<rem2pdf> uses the Pango text formatting library (L<https://pango.gnome.org/>)
|
B<rem2pdf> uses the Pango text formatting library (L<https://pango.gnome.org/>)
|
||||||
and the Cairo graphics library (L<https://www.cairographics.org/>) to produce
|
and the Cairo graphics library (L<https://www.cairographics.org/>) to produce
|
||||||
@@ -298,6 +362,22 @@ output at all.
|
|||||||
|
|
||||||
=over
|
=over
|
||||||
|
|
||||||
|
=item --ps
|
||||||
|
|
||||||
|
Output PostScript instead of PDF.
|
||||||
|
|
||||||
|
=item --eps
|
||||||
|
|
||||||
|
Output Encapsulated PostScript instead of PDF. In this case, you
|
||||||
|
should feed C<rem2pdf> only one month's worth of calendar data,
|
||||||
|
because it cannot create a multi-page encapsulated PostScript file.
|
||||||
|
|
||||||
|
=item --svg
|
||||||
|
|
||||||
|
Output SVG instead of PDF. In this case, you should feed C<rem2pdf>
|
||||||
|
only one month's worth of calendar data, because it cannot create
|
||||||
|
a multi-page SVG file.
|
||||||
|
|
||||||
=item --landscape, -l
|
=item --landscape, -l
|
||||||
|
|
||||||
Print the calendar in landscape orientation. Essentially, this swaps
|
Print the calendar in landscape orientation. Essentially, this swaps
|
||||||
@@ -486,7 +566,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.)
|
||||||
|
|
||||||
|
|||||||
@@ -1008,7 +1008,17 @@ as were read from the C<remind -ppp> stream
|
|||||||
sub render
|
sub render
|
||||||
{
|
{
|
||||||
my ($self, $cr, $settings) = @_;
|
my ($self, $cr, $settings) = @_;
|
||||||
|
my $done = 0;
|
||||||
|
my $warned = 0;
|
||||||
foreach my $e (@{$self->{entries}}) {
|
foreach my $e (@{$self->{entries}}) {
|
||||||
|
if ($settings->{svg} && $done) {
|
||||||
|
if (!$warned) {
|
||||||
|
print STDERR "WARNING: --svg can only output one page; ignoring subsequent\nmonths in a multi-month calendar.\n";
|
||||||
|
$warned = 1;
|
||||||
|
}
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
$done = 1;
|
||||||
$e->render($cr, $settings);
|
$e->render($cr, $settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,18 @@ sub render
|
|||||||
} else {
|
} else {
|
||||||
$body = $self->{body};
|
$body = $self->{body};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Clean up the body:
|
||||||
|
|
||||||
|
# Collapse multiple spaces/tabs to a single space
|
||||||
|
$body =~ s/[ \t]+/ /gs;
|
||||||
|
|
||||||
|
# Remove whitespace before/after newlines
|
||||||
|
$body =~ s/\s+\n/\n/gs;
|
||||||
|
$body =~ s/\n\s+/\n/gs;
|
||||||
|
# Collapse multiple newlines to a single newline
|
||||||
|
$body =~ s/\n+/\n/gs;
|
||||||
|
|
||||||
$layout->set_text(Encode::decode('UTF-8', $body));
|
$layout->set_text(Encode::decode('UTF-8', $body));
|
||||||
my $desc = Pango::FontDescription->from_string($settings->{entry_font} . ' ' . $settings->{entry_size} . 'px');
|
my $desc = Pango::FontDescription->from_string($settings->{entry_font} . ' ' . $settings->{entry_size} . 'px');
|
||||||
$layout->set_font_description($desc);
|
$layout->set_font_description($desc);
|
||||||
|
|||||||
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 |
659
scripts/tkremind
659
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
|
||||||
|
|||||||
149
src/calendar.c
149
src/calendar.c
@@ -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"
|
||||||
@@ -282,6 +281,7 @@ static void ColorizeEntry(CalEntry const *e, int clamp);
|
|||||||
static void SortCol (CalEntry **col);
|
static void SortCol (CalEntry **col);
|
||||||
static void DoCalendarOneWeek (int nleft);
|
static void DoCalendarOneWeek (int nleft);
|
||||||
static void DoCalendarOneMonth (void);
|
static void DoCalendarOneMonth (void);
|
||||||
|
static void DoSimpleCalendarOneMonth (void);
|
||||||
static int WriteCalendarRow (void);
|
static int WriteCalendarRow (void);
|
||||||
static void WriteWeekHeaderLine (void);
|
static void WriteWeekHeaderLine (void);
|
||||||
static void WritePostHeaderLine (void);
|
static void WritePostHeaderLine (void);
|
||||||
@@ -339,6 +339,7 @@ UnBackgroundize(int d)
|
|||||||
printf("%s", Decolorize());
|
printf("%s", Decolorize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef REM_USE_WCHAR
|
||||||
static void
|
static void
|
||||||
send_lrm(void)
|
send_lrm(void)
|
||||||
{
|
{
|
||||||
@@ -353,6 +354,7 @@ send_lrm(void)
|
|||||||
printf("\xE2\x80\x8E");
|
printf("\xE2\x80\x8E");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static char const *
|
static char const *
|
||||||
despace(char const *s)
|
despace(char const *s)
|
||||||
@@ -475,7 +477,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 +485,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
|
||||||
@@ -523,9 +529,9 @@ get_month_abbrev(char const *mon)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef REM_USE_WCHAR
|
||||||
static int make_wchar_versions(CalEntry *e)
|
static int make_wchar_versions(CalEntry *e)
|
||||||
{
|
{
|
||||||
#ifdef REM_USE_WCHAR
|
|
||||||
size_t len;
|
size_t len;
|
||||||
wchar_t *buf;
|
wchar_t *buf;
|
||||||
len = mbstowcs(NULL, e->text, 0);
|
len = mbstowcs(NULL, e->text, 0);
|
||||||
@@ -539,10 +545,8 @@ static int make_wchar_versions(CalEntry *e)
|
|||||||
e->wc_text = buf;
|
e->wc_text = buf;
|
||||||
e->wc_pos = buf;
|
e->wc_pos = buf;
|
||||||
return 1;
|
return 1;
|
||||||
#else
|
|
||||||
return 1;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void gon(void)
|
static void gon(void)
|
||||||
{
|
{
|
||||||
@@ -755,13 +759,11 @@ SetMoonEntry(int dse, char const *moon)
|
|||||||
if (sscanf(moon, "%d %*d %*d %27[^\x01]", &phase, msg) < 4) {
|
if (sscanf(moon, "%d %*d %*d %27[^\x01]", &phase, msg) < 4) {
|
||||||
if (sscanf(moon, "%d", &phase) != 1) {
|
if (sscanf(moon, "%d", &phase) != 1) {
|
||||||
/* Malformed MOON special; ignore */
|
/* Malformed MOON special; ignore */
|
||||||
fprintf(stderr, "Oops 1\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (phase < 0 || phase > 3) {
|
if (phase < 0 || phase > 3) {
|
||||||
/* Bad phase */
|
/* Bad phase */
|
||||||
fprintf(stderr, "Oops 2\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FromDSE(dse, &y, &m, &d);
|
FromDSE(dse, &y, &m, &d);
|
||||||
@@ -899,13 +901,17 @@ static void DoCalendarOneWeek(int nleft)
|
|||||||
if (UseVTColors) {
|
if (UseVTColors) {
|
||||||
printf("\x1B[1m"); /* Bold */
|
printf("\x1B[1m"); /* Bold */
|
||||||
}
|
}
|
||||||
|
Backgroundize(d);
|
||||||
PrintLeft(buf, ColSpaces-1, '*');
|
PrintLeft(buf, ColSpaces-1, '*');
|
||||||
|
putchar(' ');
|
||||||
|
UnBackgroundize(d);
|
||||||
if (UseVTColors) {
|
if (UseVTColors) {
|
||||||
printf("\x1B[0m"); /* Normal */
|
printf("\x1B[0m"); /* Normal */
|
||||||
}
|
}
|
||||||
putchar(' ');
|
|
||||||
} else {
|
} else {
|
||||||
|
Backgroundize(d);
|
||||||
PrintLeft(buf, ColSpaces, ' ');
|
PrintLeft(buf, ColSpaces, ' ');
|
||||||
|
UnBackgroundize(d);
|
||||||
}
|
}
|
||||||
gon();
|
gon();
|
||||||
DRAW(tb);
|
DRAW(tb);
|
||||||
@@ -962,21 +968,20 @@ static void DoCalendarOneWeek(int nleft)
|
|||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* DoCalendarOneMonth */
|
/* DoSimpleCalendarOneMonth */
|
||||||
/* */
|
/* */
|
||||||
/* Produce a calendar for the current month. */
|
/* Produce a "simple" calendar for the current month. */
|
||||||
|
/* */
|
||||||
|
/* A simple calendar is produced if the -s or -p option */
|
||||||
|
/* was used. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static void DoCalendarOneMonth(void)
|
static void DoSimpleCalendarOneMonth(void)
|
||||||
{
|
{
|
||||||
int y, m, d, mm, yy, i, j;
|
int y, m, d, mm, yy, i, j;
|
||||||
|
|
||||||
InitMoonsAndShades();
|
InitMoonsAndShades();
|
||||||
|
|
||||||
if (!DoSimpleCalendar) WriteCalHeader();
|
|
||||||
|
|
||||||
DidADay = 0;
|
DidADay = 0;
|
||||||
|
|
||||||
if (PsCal) {
|
if (PsCal) {
|
||||||
FromDSE(DSEToday, &y, &m, &d);
|
FromDSE(DSEToday, &y, &m, &d);
|
||||||
if (PsCal == PSCAL_LEVEL1) {
|
if (PsCal == PSCAL_LEVEL1) {
|
||||||
@@ -1037,7 +1042,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);
|
||||||
@@ -1049,7 +1054,29 @@ static void DoCalendarOneMonth(void)
|
|||||||
}
|
}
|
||||||
printf("]\n}");
|
printf("]\n}");
|
||||||
}
|
}
|
||||||
if (!DoSimpleCalendar) WriteCalTrailer();
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* DoCalendarOneMonth */
|
||||||
|
/* */
|
||||||
|
/* Produce a calendar for the current month. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
static void DoCalendarOneMonth(void)
|
||||||
|
{
|
||||||
|
InitMoonsAndShades();
|
||||||
|
|
||||||
|
if (DoSimpleCalendar) {
|
||||||
|
DoSimpleCalendarOneMonth();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteCalHeader();
|
||||||
|
|
||||||
|
while (WriteCalendarRow()) /* continue */;
|
||||||
|
|
||||||
|
WriteCalTrailer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -1121,13 +1148,17 @@ static int WriteCalendarRow(void)
|
|||||||
if (UseVTColors) {
|
if (UseVTColors) {
|
||||||
printf("\x1B[1m"); /* Bold */
|
printf("\x1B[1m"); /* Bold */
|
||||||
}
|
}
|
||||||
|
Backgroundize(d+i-wd);
|
||||||
PrintLeft(buf, ColSpaces-1, '*');
|
PrintLeft(buf, ColSpaces-1, '*');
|
||||||
|
putchar(' ');
|
||||||
if (UseVTColors) {
|
if (UseVTColors) {
|
||||||
printf("\x1B[0m"); /* Normal */
|
printf("\x1B[0m"); /* Normal */
|
||||||
}
|
}
|
||||||
putchar(' ');
|
UnBackgroundize(d+i-wd);
|
||||||
} else {
|
} else {
|
||||||
|
Backgroundize(d+i-wd);
|
||||||
PrintLeft(buf, ColSpaces, ' ');
|
PrintLeft(buf, ColSpaces, ' ');
|
||||||
|
UnBackgroundize(d+i-wd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gon();
|
gon();
|
||||||
@@ -1195,15 +1226,17 @@ static void PrintLeft(char const *s, int width, char pad)
|
|||||||
{
|
{
|
||||||
#ifndef REM_USE_WCHAR
|
#ifndef REM_USE_WCHAR
|
||||||
int len = strlen(s);
|
int len = strlen(s);
|
||||||
printf("%s", s);
|
int i;
|
||||||
while (len++ < width) putchar(pad);
|
for (i=0; i<len && i<width; i++) {
|
||||||
|
fputc(*(s+i), stdout);
|
||||||
|
}
|
||||||
|
while (i++ < width) putchar(pad);
|
||||||
#else
|
#else
|
||||||
size_t len = mbstowcs(NULL, s, 0);
|
size_t len = mbstowcs(NULL, s, 0);
|
||||||
int i;
|
int i;
|
||||||
wchar_t static_buf[128];
|
wchar_t static_buf[128];
|
||||||
wchar_t *buf;
|
wchar_t *buf;
|
||||||
wchar_t *ws;
|
wchar_t *ws;
|
||||||
int display_len;
|
|
||||||
|
|
||||||
if (!len) {
|
if (!len) {
|
||||||
for (i=0; i<width; i++) {
|
for (i=0; i<width; i++) {
|
||||||
@@ -1222,26 +1255,32 @@ static void PrintLeft(char const *s, int width, char pad)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
(void) mbstowcs(buf, s, len+1);
|
(void) mbstowcs(buf, s, len+1);
|
||||||
display_len = wcswidth(buf, len+1);
|
|
||||||
|
|
||||||
ws = buf;
|
ws = buf;
|
||||||
for (i=0; i<width;) {
|
i=0;
|
||||||
|
while (i<width) {
|
||||||
if (*ws) {
|
if (*ws) {
|
||||||
PutWideChar(*ws++);
|
if (i + wcwidth(*ws) > width) {
|
||||||
i+= wcwidth(*ws);
|
break;
|
||||||
|
}
|
||||||
|
i += wcwidth(*ws);
|
||||||
|
PutWideChar(*ws++, NULL);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* 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();
|
||||||
|
|
||||||
for (i=display_len; i<width; i++) fputc(pad, stdout);
|
while (i<width) {
|
||||||
|
fputc(pad, stdout);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
if (buf != static_buf) free(buf);
|
if (buf != static_buf) free(buf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1262,7 +1301,7 @@ static void PrintCentered(char const *s, int width, char *pad)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
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-d; i++) {
|
||||||
if (*s) {
|
if (*s) {
|
||||||
if (isspace(*s)) {
|
if (isspace(*s)) {
|
||||||
putchar(' ');
|
putchar(' ');
|
||||||
@@ -1306,25 +1345,29 @@ static void PrintCentered(char const *s, int width, char *pad)
|
|||||||
if (d < 0) d = 0;
|
if (d < 0) d = 0;
|
||||||
ws = buf;
|
ws = buf;
|
||||||
for (i=0; i<d; i++) fputs(pad, stdout);
|
for (i=0; i<d; i++) fputs(pad, stdout);
|
||||||
for (i=0; i<width; i++) {
|
i=0;
|
||||||
|
while (i+d < width) {
|
||||||
if (*ws) {
|
if (*ws) {
|
||||||
PutWideChar(*ws++);
|
if (i+d + wcwidth(*ws) > width) {
|
||||||
if (wcwidth(*ws) == 0) {
|
break;
|
||||||
/* Don't count this character... it's zero-width */
|
|
||||||
i--;
|
|
||||||
}
|
}
|
||||||
|
i += wcwidth(*ws);
|
||||||
|
PutWideChar(*ws++, NULL);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* 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();
|
||||||
|
|
||||||
for (i=d+display_len; i<width; i++) fputs(pad, stdout);
|
while (i+d<width) {
|
||||||
|
fputs(pad, stdout);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
if (buf != static_buf) free(buf);
|
if (buf != static_buf) free(buf);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1411,7 +1454,7 @@ static int WriteOneColLine(int col)
|
|||||||
/* Find the last space char within the column. */
|
/* Find the last space char within the column. */
|
||||||
width = 0;
|
width = 0;
|
||||||
while (width <= ColSpaces) {
|
while (width <= ColSpaces) {
|
||||||
if (!*ws) {
|
if (!*ws || *ws == '\n') {
|
||||||
wspace = ws;
|
wspace = ws;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1448,7 +1491,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 +1506,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1517,7 +1560,7 @@ static int WriteOneColLine(int col)
|
|||||||
|
|
||||||
/* Find the last space char within the column. */
|
/* Find the last space char within the column. */
|
||||||
while (s - e->pos <= ColSpaces) {
|
while (s - e->pos <= ColSpaces) {
|
||||||
if (!*s) {space = s; break;}
|
if (!*s || *s == '\n') {space = s; break;}
|
||||||
if (isspace(*s)) space = s;
|
if (isspace(*s)) space = s;
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
@@ -1666,6 +1709,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;
|
||||||
@@ -1679,7 +1723,12 @@ static void GenerateCalEntries(int col)
|
|||||||
/* Note: Since the parser hasn't been used yet, we don't */
|
/* Note: Since the parser hasn't been used yet, we don't */
|
||||||
/* need to destroy it here. */
|
/* need to destroy it here. */
|
||||||
|
|
||||||
default: CreateParser(CurLine, &p);
|
default:
|
||||||
|
if (!SuppressImplicitRemWarnings) {
|
||||||
|
Wprint("Unrecognized command; interpreting as REM");
|
||||||
|
WarnedAboutImplicit = 1;
|
||||||
|
}
|
||||||
|
CreateParser(CurLine, &p);
|
||||||
r=DoCalRem(&p, col);
|
r=DoCalRem(&p, col);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1766,7 +1815,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;
|
||||||
}
|
}
|
||||||
@@ -2138,7 +2187,9 @@ static int DoCalRem(ParsePtr p, int col)
|
|||||||
FreeTrig(&trig);
|
FreeTrig(&trig);
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
|
#ifdef REM_USE_WCHAR
|
||||||
make_wchar_versions(e);
|
make_wchar_versions(e);
|
||||||
|
#endif
|
||||||
DBufInit(&(e->tags));
|
DBufInit(&(e->tags));
|
||||||
DBufPuts(&(e->tags), DBufValue(&(trig.tags)));
|
DBufPuts(&(e->tags), DBufValue(&(trig.tags)));
|
||||||
if (SynthesizeTags) {
|
if (SynthesizeTags) {
|
||||||
@@ -2306,15 +2357,9 @@ void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
|
|||||||
if (t->noqueue) {
|
if (t->noqueue) {
|
||||||
PrintJSONKeyPairInt("noqueue", 1);
|
PrintJSONKeyPairInt("noqueue", 1);
|
||||||
}
|
}
|
||||||
if (*t->sched) {
|
PrintJSONKeyPairString("sched", t->sched);
|
||||||
PrintJSONKeyPairString("sched", t->sched);
|
PrintJSONKeyPairString("warn", t->warn);
|
||||||
}
|
PrintJSONKeyPairString("omitfunc", t->omitfunc);
|
||||||
if (*t->warn) {
|
|
||||||
PrintJSONKeyPairString("warn", t->warn);
|
|
||||||
}
|
|
||||||
if (*t->omitfunc) {
|
|
||||||
PrintJSONKeyPairString("omitfunc", t->omitfunc);
|
|
||||||
}
|
|
||||||
if (t->addomit) {
|
if (t->addomit) {
|
||||||
PrintJSONKeyPairInt("addomit", 1);
|
PrintJSONKeyPairInt("addomit", 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
22
src/custom.h
22
src/custom.h
@@ -20,7 +20,7 @@
|
|||||||
/* western hemisphere. */
|
/* western hemisphere. */
|
||||||
/* */
|
/* */
|
||||||
/* The default values are initially set to the city hall in Ottawa, */
|
/* The default values are initially set to the city hall in Ottawa, */
|
||||||
/* Ontario, Canada. */
|
/* Ontario, Canada. */
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
#define DEFAULT_LATITUDE 45.420556
|
#define DEFAULT_LATITUDE 45.420556
|
||||||
#define DEFAULT_LONGITUDE -75.689722
|
#define DEFAULT_LONGITUDE -75.689722
|
||||||
@@ -68,12 +68,6 @@
|
|||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
/* WANT_SHELL_ESCAPING: Define this if you want special shell */
|
|
||||||
/* characters to be escaped with a backslash for the -k option. */
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
#define WANT_SHELL_ESCAPING 1
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
/* BASE: The base year for date calculation. NOTE! January 1 of the */
|
/* BASE: The base year for date calculation. NOTE! January 1 of the */
|
||||||
/* base year MUST be a Monday, else Remind will not work! */
|
/* base year MUST be a Monday, else Remind will not work! */
|
||||||
@@ -109,16 +103,6 @@
|
|||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
#define MAX_STR_LEN 65535
|
#define MAX_STR_LEN 65535
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
/* OP_STACK_SIZE: The size of the operator stack for expr. parsing */
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
#define OP_STACK_SIZE 100
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
/* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
#define VAL_STACK_SIZE 1000
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */
|
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
@@ -166,6 +150,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"
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
/* western hemisphere. */
|
/* western hemisphere. */
|
||||||
/* */
|
/* */
|
||||||
/* The default values are initially set to the city hall in Ottawa, */
|
/* The default values are initially set to the city hall in Ottawa, */
|
||||||
/* Ontario, Canada. */
|
/* Ontario, Canada. */
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
#define DEFAULT_LATITUDE 45.420556
|
#define DEFAULT_LATITUDE 45.420556
|
||||||
#define DEFAULT_LONGITUDE -75.689722
|
#define DEFAULT_LONGITUDE -75.689722
|
||||||
@@ -68,12 +68,6 @@
|
|||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
/* WANT_SHELL_ESCAPING: Define this if you want special shell */
|
|
||||||
/* characters to be escaped with a backslash for the -k option. */
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
#define WANT_SHELL_ESCAPING 1
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
/* BASE: The base year for date calculation. NOTE! January 1 of the */
|
/* BASE: The base year for date calculation. NOTE! January 1 of the */
|
||||||
/* base year MUST be a Monday, else Remind will not work! */
|
/* base year MUST be a Monday, else Remind will not work! */
|
||||||
@@ -109,16 +103,6 @@
|
|||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
#define MAX_STR_LEN 65535
|
#define MAX_STR_LEN 65535
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
/* OP_STACK_SIZE: The size of the operator stack for expr. parsing */
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
#define OP_STACK_SIZE 100
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
/* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
#define VAL_STACK_SIZE 1000
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */
|
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
@@ -166,6 +150,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"
|
||||||
|
|
||||||
|
|||||||
320
src/dorem.c
320
src/dorem.c
@@ -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);
|
||||||
@@ -33,6 +32,152 @@ static int ParseUntil (ParsePtr s, Trigger *t, int type);
|
|||||||
static int ShouldTriggerBasedOnWarn (Trigger *t, int dse, int *err);
|
static int ShouldTriggerBasedOnWarn (Trigger *t, int dse, int *err);
|
||||||
static int ComputeTrigDuration(TimeTrig *t);
|
static int ComputeTrigDuration(TimeTrig *t);
|
||||||
|
|
||||||
|
static int
|
||||||
|
ensure_expr_references_first_local_arg(expr_node *node)
|
||||||
|
{
|
||||||
|
expr_node *other;
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (node->type == N_LOCAL_VAR && node->u.arg == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (ensure_expr_references_first_local_arg(node->child)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
other = node->sibling;
|
||||||
|
while (other) {
|
||||||
|
if (ensure_expr_references_first_local_arg(other)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
other = other->sibling;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_trigger_function(char const *fname, char const *type)
|
||||||
|
{
|
||||||
|
UserFunc *f;
|
||||||
|
if (!*fname) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
f = FindUserFunc(fname);
|
||||||
|
if (!f) {
|
||||||
|
if (strcmp(type, "WARN")) {
|
||||||
|
/* Undefined WARN functions are diagnosed elsewhere... */
|
||||||
|
Wprint("Undefined %s function: `%s'", type, fname);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (f->nargs != 1) {
|
||||||
|
Wprint("%s function `%s' defined at %s:%d should take 1 argument but actually takes %d", type, fname, f->filename, f->lineno, f->nargs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ensure_expr_references_first_local_arg(f->node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Wprint("%s function `%s' defined at %s:%d does not use its argument", type, fname, f->filename, f->lineno);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ensure_satnode_mentions_trigdate_aux(expr_node *node, int *mentioned)
|
||||||
|
{
|
||||||
|
char const *name;
|
||||||
|
expr_node *other;
|
||||||
|
UserFunc *f;
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*mentioned) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type == N_BUILTIN_FUNC) {
|
||||||
|
name = node->u.builtin_func->name;
|
||||||
|
if (!strcmp(name, "trigdate") ||
|
||||||
|
!strcmp(name, "trigdatetime")) {
|
||||||
|
*mentioned = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (node->type == N_SHORT_SYSVAR || node->type == N_SYSVAR) {
|
||||||
|
if (node->type == N_SHORT_SYSVAR) {
|
||||||
|
name = node->u.name;
|
||||||
|
} else {
|
||||||
|
name = node->u.value.v.str;
|
||||||
|
}
|
||||||
|
if (!StrCmpi(name, "T") ||
|
||||||
|
!StrCmpi(name, "Td") ||
|
||||||
|
!StrCmpi(name, "Tm") ||
|
||||||
|
!StrCmpi(name, "Tw") ||
|
||||||
|
!StrCmpi(name, "Ty")) {
|
||||||
|
*mentioned = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (node->type == N_SHORT_USER_FUNC || node->type == N_USER_FUNC) {
|
||||||
|
if (node->type == N_SHORT_USER_FUNC) {
|
||||||
|
name = node->u.name;
|
||||||
|
} else {
|
||||||
|
name = node->u.value.v.str;
|
||||||
|
}
|
||||||
|
f = FindUserFunc(name);
|
||||||
|
if (f && !f->recurse_flag) {
|
||||||
|
f->recurse_flag = 1;
|
||||||
|
ensure_satnode_mentions_trigdate_aux(f->node, mentioned);
|
||||||
|
f->recurse_flag = 0;
|
||||||
|
if (*mentioned) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ensure_satnode_mentions_trigdate_aux(node->child, mentioned);
|
||||||
|
if (*mentioned) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
other = node->sibling;
|
||||||
|
while (other) {
|
||||||
|
ensure_satnode_mentions_trigdate_aux(other, mentioned);
|
||||||
|
if (*mentioned) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
other = other->sibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ensure_satnode_mentions_trigdate(expr_node *node)
|
||||||
|
{
|
||||||
|
int mentioned = 0;
|
||||||
|
char const *str;
|
||||||
|
if (node->type == N_CONSTANT || node->type == N_SHORT_STR) {
|
||||||
|
if (node->type == N_CONSTANT) {
|
||||||
|
if (node->u.value.type == INT_TYPE) {
|
||||||
|
if (node->u.value.v.val == 0) {
|
||||||
|
Wprint("SATISFY: constant 0 will never be true");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node->u.value.type != STR_TYPE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
str = node->u.value.v.str;
|
||||||
|
} else {
|
||||||
|
str = node->u.name;
|
||||||
|
}
|
||||||
|
if (!*str) {
|
||||||
|
Wprint("SATISFY: constant \"\" will never be true");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_satnode_mentions_trigdate_aux(node, &mentioned);
|
||||||
|
if (!mentioned) {
|
||||||
|
Wprint("SATISFY: expression has no reference to trigdate() or $T...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ComputeTrigDuration(TimeTrig *t)
|
ComputeTrigDuration(TimeTrig *t)
|
||||||
{
|
{
|
||||||
@@ -63,7 +208,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)) != OK ) {
|
||||||
FreeTrig(&trig);
|
FreeTrig(&trig);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -163,6 +308,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");
|
||||||
@@ -182,7 +328,7 @@ int DoRem(ParsePtr p)
|
|||||||
if (dse == DSEToday &&
|
if (dse == DSEToday &&
|
||||||
!(!IgnoreOnce &&
|
!(!IgnoreOnce &&
|
||||||
trig.once != NO_ONCE &&
|
trig.once != NO_ONCE &&
|
||||||
FileAccessDate == DSEToday))
|
GetOnceDate() == DSEToday))
|
||||||
QueueReminder(p, &trig, &tim, trig.sched);
|
QueueReminder(p, &trig, &tim, trig.sched);
|
||||||
/* If we're in daemon mode, do nothing over here */
|
/* If we're in daemon mode, do nothing over here */
|
||||||
if (Daemon) {
|
if (Daemon) {
|
||||||
@@ -192,7 +338,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 +366,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 +408,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 */
|
||||||
@@ -295,10 +437,17 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Date:
|
case T_Date:
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
if (trig->d != NO_DAY) return E_DAY_TWICE;
|
if (trig->d != NO_DAY) {
|
||||||
if (trig->m != NO_MON) return E_MON_TWICE;
|
return E_DAY_TWICE;
|
||||||
if (trig->y != NO_YR) return E_YR_TWICE;
|
}
|
||||||
|
if (trig->m != NO_MON) {
|
||||||
|
return E_MON_TWICE;
|
||||||
|
}
|
||||||
|
if (trig->y != NO_YR) {
|
||||||
|
return E_YR_TWICE;
|
||||||
|
}
|
||||||
|
|
||||||
FromDSE(tok.val, &y, &m, &d);
|
FromDSE(tok.val, &y, &m, &d);
|
||||||
trig->y = y;
|
trig->y = y;
|
||||||
trig->m = m;
|
trig->m = m;
|
||||||
@@ -315,10 +464,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 +500,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;
|
||||||
@@ -404,6 +549,12 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
if (r) return r;
|
if (r) return r;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_Number:
|
||||||
|
DBufFree(&buf);
|
||||||
|
Eprint("`%d' is not recognized as a year (%d-%d) or a day number (1-31)",
|
||||||
|
tok.val, BASE, BASE+YR_RANGE);
|
||||||
|
return E_PARSE_ERR;
|
||||||
|
|
||||||
case T_Year:
|
case T_Year:
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
if (trig->y != NO_YR) return E_YR_TWICE;
|
if (trig->y != NO_YR) return E_YR_TWICE;
|
||||||
@@ -481,10 +632,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 +643,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 +674,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 +685,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;
|
||||||
|
|
||||||
@@ -545,10 +695,19 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
if (tok.type == T_Illegal && tok.val < 0) {
|
||||||
|
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
|
||||||
|
DBufFree(&buf);
|
||||||
|
return -tok.val;
|
||||||
|
}
|
||||||
PushToken(DBufValue(&buf), s);
|
PushToken(DBufValue(&buf), s);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
trig->typ = MSG_TYPE;
|
trig->typ = MSG_TYPE;
|
||||||
if (s->isnested) return E_CANT_NEST_RTYPE;
|
if (s->isnested) return E_CANT_NEST_RTYPE;
|
||||||
|
if (!WarnedAboutImplicit && !SuppressImplicitRemWarnings) {
|
||||||
|
Wprint("Missing REM type; assuming MSG");
|
||||||
|
WarnedAboutImplicit = 1;
|
||||||
|
}
|
||||||
parsing = 0;
|
parsing = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -600,6 +759,11 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
|||||||
trig->scanfrom = DSEToday;
|
trig->scanfrom = DSEToday;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check that any SCHED / WARN / OMITFUNC functions refer to
|
||||||
|
their arguments */
|
||||||
|
check_trigger_function(trig->sched, "SCHED");
|
||||||
|
check_trigger_function(trig->warn, "WARN");
|
||||||
|
check_trigger_function(trig->omitfunc, "OMITFUNC");
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,7 +772,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;
|
||||||
@@ -641,13 +805,13 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
if (tok.type == T_Illegal && tok.val < 0) {
|
||||||
|
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
|
||||||
|
DBufFree(&buf);
|
||||||
|
return -tok.val;
|
||||||
|
}
|
||||||
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 +843,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;
|
||||||
@@ -760,6 +927,11 @@ static int ParseUntil(ParsePtr s, Trigger *t, int type)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
if (tok.type == T_Illegal && tok.val < 0) {
|
||||||
|
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
|
||||||
|
DBufFree(&buf);
|
||||||
|
return -tok.val;
|
||||||
|
}
|
||||||
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
|
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
|
||||||
Eprint("%s: %s", which, ErrMsg[E_INCOMPLETE]);
|
Eprint("%s: %s", which, ErrMsg[E_INCOMPLETE]);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
@@ -873,9 +1045,17 @@ 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:
|
||||||
|
if (tok.type == T_Illegal && tok.val < 0) {
|
||||||
|
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
|
||||||
|
DBufFree(&buf);
|
||||||
|
return -tok.val;
|
||||||
|
}
|
||||||
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
|
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
|
||||||
Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]);
|
Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
@@ -910,7 +1090,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 +1157,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 +1224,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 +1331,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 (IsServerMode() && !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? */
|
||||||
@@ -1188,7 +1379,7 @@ int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int dse, int *err)
|
|||||||
*err = 0;
|
*err = 0;
|
||||||
|
|
||||||
/* Handle the ONCE modifier in the reminder. */
|
/* Handle the ONCE modifier in the reminder. */
|
||||||
if (!IgnoreOnce && t->once !=NO_ONCE && FileAccessDate == DSEToday)
|
if (!IgnoreOnce && t->once !=NO_ONCE && GetOnceDate() == DSEToday)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (dse < DSEToday) return 0;
|
if (dse < DSEToday) return 0;
|
||||||
@@ -1270,20 +1461,32 @@ 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;
|
||||||
|
|
||||||
|
sat_node = ParseExpr(p, &r);
|
||||||
|
if (r != OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (!sat_node) {
|
||||||
|
return E_SWERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Diagnose if SAT_NODE does not reference trigdate */
|
||||||
|
ensure_satnode_mentions_trigdate(sat_node);
|
||||||
|
|
||||||
t = p->pos;
|
|
||||||
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 +1499,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 +1535,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 +1595,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 +1632,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);
|
||||||
|
|||||||
@@ -12,15 +12,13 @@
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "expr.h"
|
#include "types.h"
|
||||||
#define L_IN_DOSUBST
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#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"
|
||||||
@@ -33,6 +31,19 @@
|
|||||||
|
|
||||||
#define SHIP_OUT(s) if(DBufPuts(dbuf, s) != OK) return E_NO_MEM
|
#define SHIP_OUT(s) if(DBufPuts(dbuf, s) != OK) return E_NO_MEM
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_subst_args(UserFunc *f, int n)
|
||||||
|
{
|
||||||
|
if (!f) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (f->nargs == n) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Wprint("Function `%s' defined at %s:%d should take %d argument%s, but actually takes %d",
|
||||||
|
f->name, f->filename, f->lineno, n, (n == 1 ? "" : "s"), f->nargs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* DoSubst */
|
/* DoSubst */
|
||||||
@@ -50,7 +61,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;
|
||||||
@@ -69,9 +80,13 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
int altmode;
|
int altmode;
|
||||||
int r;
|
int r;
|
||||||
Value v;
|
Value v;
|
||||||
|
UserFunc *func;
|
||||||
|
|
||||||
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);
|
||||||
@@ -99,7 +114,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
L_AMPM_OVERRIDE (pm, h)
|
L_AMPM_OVERRIDE (pm, h)
|
||||||
#else
|
#else
|
||||||
r = -1;
|
r = -1;
|
||||||
if (UserFuncExists("subst_ampm") == 1) {
|
func = FindUserFunc("subst_ampm");
|
||||||
|
if (func && check_subst_args(func, 1)) {
|
||||||
snprintf(s, sizeof(s), "subst_ampm(%d)", h);
|
snprintf(s, sizeof(s), "subst_ampm(%d)", h);
|
||||||
expr = (char const *) s;
|
expr = (char const *) s;
|
||||||
r = EvalExpr(&expr, &v, NULL);
|
r = EvalExpr(&expr, &v, NULL);
|
||||||
@@ -128,7 +144,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
L_AMPM_OVERRIDE (cpm, ch)
|
L_AMPM_OVERRIDE (cpm, ch)
|
||||||
#else
|
#else
|
||||||
r = -1;
|
r = -1;
|
||||||
if (UserFuncExists("subst_ampm") == 1) {
|
func = FindUserFunc("subst_ampm");
|
||||||
|
if (func && check_subst_args(func, 1)) {
|
||||||
snprintf(s, sizeof(s), "subst_ampm(%d)", ch);
|
snprintf(s, sizeof(s), "subst_ampm(%d)", ch);
|
||||||
expr = (char const *) s;
|
expr = (char const *) s;
|
||||||
r = EvalExpr(&expr, &v, NULL);
|
r = EvalExpr(&expr, &v, NULL);
|
||||||
@@ -139,6 +156,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
} else {
|
} else {
|
||||||
r = -1;
|
r = -1;
|
||||||
}
|
}
|
||||||
|
DestroyValue(v);
|
||||||
} else {
|
} else {
|
||||||
Eprint("%s", ErrMsg[r]);
|
Eprint("%s", ErrMsg[r]);
|
||||||
}
|
}
|
||||||
@@ -152,7 +170,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
#ifdef L_ORDINAL_OVERRIDE
|
#ifdef L_ORDINAL_OVERRIDE
|
||||||
L_ORDINAL_OVERRIDE;
|
L_ORDINAL_OVERRIDE;
|
||||||
#else
|
#else
|
||||||
if (UserFuncExists("subst_ordinal") == 1) {
|
func = FindUserFunc("subst_ordinal");
|
||||||
|
if (func && check_subst_args(func, 1)) {
|
||||||
snprintf(s, sizeof(s), "subst_ordinal(%d)", d);
|
snprintf(s, sizeof(s), "subst_ordinal(%d)", d);
|
||||||
expr = (char const *) s;
|
expr = (char const *) s;
|
||||||
r = EvalExpr(&expr, &v, NULL);
|
r = EvalExpr(&expr, &v, NULL);
|
||||||
@@ -163,6 +182,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
} else {
|
} else {
|
||||||
r = -1;
|
r = -1;
|
||||||
}
|
}
|
||||||
|
DestroyValue(v);
|
||||||
} else {
|
} else {
|
||||||
Eprint("%s", ErrMsg[r]);
|
Eprint("%s", ErrMsg[r]);
|
||||||
}
|
}
|
||||||
@@ -239,7 +259,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++;
|
||||||
}
|
}
|
||||||
@@ -247,7 +267,13 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
if (!c) {
|
if (!c) {
|
||||||
Wprint("Warning: Unterminated %%{...} substitution sequence");
|
Wprint("Warning: Unterminated %%{...} substitution sequence");
|
||||||
}
|
}
|
||||||
if (UserFuncExists(s) != 3) {
|
func = FindUserFunc(s);
|
||||||
|
if (!func) {
|
||||||
|
Wprint("No substition function `%s' defined", s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check_subst_args(func, 3)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
snprintf(ss, sizeof(s) - (ss-s), "(%d,'%04d-%02d-%02d',%02d:%02d)",
|
snprintf(ss, sizeof(s) - (ss-s), "(%d,'%04d-%02d-%02d',%02d:%02d)",
|
||||||
@@ -266,10 +292,11 @@ 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) {
|
func = FindUserFunc(uf);
|
||||||
|
if (func && check_subst_args(func, 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 +368,11 @@ 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) {
|
func = FindUserFunc(uf);
|
||||||
|
if (func && check_subst_args(func, 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) {
|
||||||
@@ -794,7 +822,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '_':
|
case '_':
|
||||||
if (PsCal == PSCAL_LEVEL2 || PsCal == PSCAL_LEVEL3 || (mode != CAL_MODE && mode != ADVANCE_MODE && !(MsgCommand && *MsgCommand))) {
|
if (PsCal == PSCAL_LEVEL2 || PsCal == PSCAL_LEVEL3 || DoCalendar || (mode != CAL_MODE && mode != ADVANCE_MODE && !(MsgCommand && *MsgCommand))) {
|
||||||
snprintf(s, sizeof(s), "%s", NL);
|
snprintf(s, sizeof(s), "%s", NL);
|
||||||
} else {
|
} else {
|
||||||
snprintf(s, sizeof(s), " ");
|
snprintf(s, sizeof(s), " ");
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +152,6 @@ int DBufGets(DynamicBuffer *dbuf, FILE *fp)
|
|||||||
/* Try reading the first few bytes right into the buffer --
|
/* Try reading the first few bytes right into the buffer --
|
||||||
we can usually save some unnecessary copying */
|
we can usually save some unnecessary copying */
|
||||||
|
|
||||||
*(dbuf->buffer) = 0;
|
|
||||||
if (fgets(dbuf->buffer, dbuf->allocatedLen, fp) == NULL) {
|
if (fgets(dbuf->buffer, dbuf->allocatedLen, fp) == NULL) {
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|||||||
217
src/err.h
217
src/err.h
@@ -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
|
||||||
@@ -138,110 +143,114 @@ 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 (max. " STR(INCLUDE_NEST) ")",
|
/* 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 (max. " STR(MAX_PARTIAL_OMITS) ")",
|
/* E_2MANY_PART */ "Too many partial OMITs (max. " STR(MAX_PARTIAL_OMITS) ")",
|
||||||
"Too many full OMITs (max. " STR(MAX_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(): odd number of arguments required",
|
||||||
"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 */ "Undefined WARN function",
|
||||||
"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 */
|
||||||
;
|
;
|
||||||
|
|||||||
3736
src/expr.c
3736
src/expr.c
File diff suppressed because it is too large
Load Diff
66
src/expr.h
66
src/expr.h
@@ -1,66 +0,0 @@
|
|||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* EXPR.H */
|
|
||||||
/* */
|
|
||||||
/* Contains a few definitions used by expression evaluator. */
|
|
||||||
/* */
|
|
||||||
/* This file is part of REMIND. */
|
|
||||||
/* Copyright (C) 1992-2024 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 CONST_INT_TYPE 7 /* 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);
|
|
||||||
|
|
||||||
53
src/files.c
53
src/files.c
@@ -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,29 @@ 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 *);
|
||||||
|
|
||||||
|
static void
|
||||||
|
got_a_fresh_line(void)
|
||||||
|
{
|
||||||
|
FreshLine = 1;
|
||||||
|
WarnedAboutImplicit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 +147,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +189,7 @@ int ReadLine(void)
|
|||||||
CurLine = CLine->text;
|
CurLine = CLine->text;
|
||||||
LineNo = CLine->LineNo;
|
LineNo = CLine->LineNo;
|
||||||
CLine = CLine->next;
|
CLine = CLine->next;
|
||||||
FreshLine = 1;
|
got_a_fresh_line();
|
||||||
clear_callstack();
|
clear_callstack();
|
||||||
if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp);
|
if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp);
|
||||||
return OK;
|
return OK;
|
||||||
@@ -265,7 +290,7 @@ static int ReadLineFromFile(int use_pclose)
|
|||||||
CurLine = DBufValue(&LineBuffer);
|
CurLine = DBufValue(&LineBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
FreshLine = 1;
|
got_a_fresh_line();
|
||||||
clear_callstack();
|
clear_callstack();
|
||||||
if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp);
|
if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp);
|
||||||
return OK;
|
return OK;
|
||||||
@@ -327,6 +352,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 +372,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 +534,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 +561,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 +576,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;
|
||||||
@@ -821,7 +856,7 @@ static int IncludeCmd(char const *cmd)
|
|||||||
char const *fname;
|
char const *fname;
|
||||||
int old_flag;
|
int old_flag;
|
||||||
|
|
||||||
FreshLine = 1;
|
got_a_fresh_line();
|
||||||
clear_callstack();
|
clear_callstack();
|
||||||
if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE;
|
if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE;
|
||||||
i = &IStack[IStackPtr];
|
i = &IStack[IStackPtr];
|
||||||
@@ -851,6 +886,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;
|
||||||
@@ -939,7 +975,7 @@ int IncludeFile(char const *fname)
|
|||||||
int oldRunDisabled;
|
int oldRunDisabled;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
FreshLine = 1;
|
got_a_fresh_line();
|
||||||
clear_callstack();
|
clear_callstack();
|
||||||
if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE;
|
if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE;
|
||||||
i = &IStack[IStackPtr];
|
i = &IStack[IStackPtr];
|
||||||
@@ -953,6 +989,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;
|
||||||
|
|||||||
810
src/funcs.c
810
src/funcs.c
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
@@ -48,6 +49,7 @@ EXTERN int CurMon;
|
|||||||
EXTERN int CurYear;
|
EXTERN int CurYear;
|
||||||
EXTERN int LineNo;
|
EXTERN int LineNo;
|
||||||
EXTERN int FreshLine;
|
EXTERN int FreshLine;
|
||||||
|
EXTERN int WarnedAboutImplicit;
|
||||||
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
|
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
|
||||||
|
|
||||||
EXTERN INIT( int MaxLateMinutes, 0);
|
EXTERN INIT( int MaxLateMinutes, 0);
|
||||||
@@ -73,10 +75,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( char const *OnceFile, NULL);
|
||||||
EXTERN INIT( int SortByDate, 0);
|
EXTERN INIT( int OnceDate, -1);
|
||||||
EXTERN INIT( int SortByPrio, 0);
|
EXTERN INIT( int ProcessedOnce, 0);
|
||||||
|
EXTERN INIT( int SortByTime, SORT_NONE);
|
||||||
|
EXTERN INIT( int SortByDate, SORT_NONE);
|
||||||
|
EXTERN INIT( int SortByPrio, SORT_NONE);
|
||||||
EXTERN INIT( int UntimedBeforeTimed, 0);
|
EXTERN INIT( int UntimedBeforeTimed, 0);
|
||||||
EXTERN INIT( int DefaultPrio, NO_PRIORITY);
|
EXTERN INIT( int DefaultPrio, NO_PRIORITY);
|
||||||
EXTERN INIT( int SysTime, -1);
|
EXTERN INIT( int SysTime, -1);
|
||||||
@@ -92,6 +100,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);
|
||||||
@@ -109,11 +118,12 @@ 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);
|
||||||
@@ -158,6 +168,12 @@ 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);
|
||||||
|
|
||||||
|
/* Suppress warnings about implicit REM and MSG */
|
||||||
|
EXTERN INIT( int SuppressImplicitRemWarnings, 0);
|
||||||
|
|
||||||
extern int NumFullOmits, NumPartialOmits;
|
extern int NumFullOmits, NumPartialOmits;
|
||||||
|
|
||||||
/* List of months */
|
/* List of months */
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
120
src/init.c
120
src/init.c
@@ -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)
|
||||||
@@ -241,7 +241,6 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
arg++;
|
arg++;
|
||||||
if (!*arg) {
|
if (!*arg) {
|
||||||
UseStdin = 1;
|
UseStdin = 1;
|
||||||
IgnoreOnce = 1;
|
|
||||||
i--;
|
i--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -324,6 +323,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
NextMode = 1;
|
NextMode = 1;
|
||||||
DontQueue = 1;
|
DontQueue = 1;
|
||||||
Daemon = 0;
|
Daemon = 0;
|
||||||
|
IgnoreOnce = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
@@ -425,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;
|
||||||
@@ -453,6 +457,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
case 'C':
|
case 'C':
|
||||||
|
IgnoreOnce = 1;
|
||||||
DoCalendar = 1;
|
DoCalendar = 1;
|
||||||
weeks = 0;
|
weeks = 0;
|
||||||
/* Parse the flags */
|
/* Parse the flags */
|
||||||
@@ -497,6 +502,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
DoSimpleCalendar = 1;
|
DoSimpleCalendar = 1;
|
||||||
|
IgnoreOnce = 1;
|
||||||
weeks = 0;
|
weeks = 0;
|
||||||
while(*arg) {
|
while(*arg) {
|
||||||
if (*arg == 'a' || *arg == 'A') {
|
if (*arg == 'a' || *arg == 'A') {
|
||||||
@@ -523,6 +529,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
case 'p':
|
case 'p':
|
||||||
case 'P':
|
case 'P':
|
||||||
DoSimpleCalendar = 1;
|
DoSimpleCalendar = 1;
|
||||||
|
IgnoreOnce = 1;
|
||||||
PsCal = PSCAL_LEVEL1;
|
PsCal = PSCAL_LEVEL1;
|
||||||
while (*arg == 'a' || *arg == 'A' ||
|
while (*arg == 'a' || *arg == 'A' ||
|
||||||
*arg == 'q' || *arg == 'Q' ||
|
*arg == 'q' || *arg == 'Q' ||
|
||||||
@@ -600,6 +607,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;
|
||||||
@@ -709,12 +717,17 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
if (tok.type == T_Illegal && tok.val < 0) {
|
||||||
|
fprintf(stderr, "%s: `%s'\n", ErrMsg[-tok.val], arg);
|
||||||
|
Usage();
|
||||||
|
}
|
||||||
Usage();
|
Usage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rep > 0) {
|
if (rep > 0) {
|
||||||
Iterations = rep;
|
Iterations = rep;
|
||||||
|
IgnoreOnce = 1;
|
||||||
DontQueue = 1;
|
DontQueue = 1;
|
||||||
Daemon = 0;
|
Daemon = 0;
|
||||||
}
|
}
|
||||||
@@ -800,6 +813,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 */
|
||||||
@@ -919,7 +933,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 */
|
||||||
@@ -929,10 +948,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;
|
||||||
@@ -985,13 +1022,71 @@ 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 (!strcmp(arg, "print-tokens")) {
|
||||||
|
print_remind_tokens();
|
||||||
|
print_builtinfunc_tokens();
|
||||||
|
print_sysvar_tokens();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1000,7 +1095,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;
|
||||||
|
|
||||||
@@ -1034,6 +1129,8 @@ guess_terminal_background(int *r, int *g, int *b)
|
|||||||
|
|
||||||
if (n != 8) {
|
if (n != 8) {
|
||||||
/* write failed... WTF? Not much we can do */
|
/* write failed... WTF? Not much we can do */
|
||||||
|
tty_reset(ttyfd);
|
||||||
|
close(ttyfd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1057,6 +1154,7 @@ guess_terminal_background(int *r, int *g, int *b)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tty_reset(ttyfd);
|
tty_reset(ttyfd);
|
||||||
|
close(ttyfd);
|
||||||
buf[n+1] = 0;
|
buf[n+1] = 0;
|
||||||
if (n < 25) {
|
if (n < 25) {
|
||||||
/* Too short */
|
/* Too short */
|
||||||
@@ -1066,9 +1164,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;
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|
||||||
@@ -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");
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|
||||||
@@ -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");
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|
||||||
@@ -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");
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|
||||||
@@ -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");
|
||||||
|
|||||||
407
src/main.c
407
src/main.c
@@ -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,48 @@
|
|||||||
|
|
||||||
#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 sig)
|
||||||
|
{
|
||||||
|
UNUSED(sig);
|
||||||
|
if (ExpressionEvaluationTimeLimit) {
|
||||||
|
ExpressionTimeLimitExceeded = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sigxcpu(int sig)
|
||||||
|
{
|
||||||
|
|
||||||
|
UNUSED(sig);
|
||||||
|
int r = write(STDERR_FILENO, "\n\nmax-execution-time exceeded.\n\n", 32);
|
||||||
|
|
||||||
|
/* Pretend to use r to avoid compiler warning */
|
||||||
|
/* cppcheck-suppress duplicateExpression */
|
||||||
|
/* cppcheck-suppress knownArgument */
|
||||||
|
_exit(1 + (r-r));
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/** **/
|
/** **/
|
||||||
@@ -56,6 +99,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 +113,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 +160,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 +213,7 @@ void
|
|||||||
PerIterationInit(void)
|
PerIterationInit(void)
|
||||||
{
|
{
|
||||||
ClearGlobalOmits();
|
ClearGlobalOmits();
|
||||||
DestroyOmitContexts();
|
DestroyOmitContexts(1);
|
||||||
DestroyVars(0);
|
DestroyVars(0);
|
||||||
DefaultColorR = -1;
|
DefaultColorR = -1;
|
||||||
DefaultColorG = -1;
|
DefaultColorG = -1;
|
||||||
@@ -176,7 +242,8 @@ static void DoReminders(void)
|
|||||||
if (!UseStdin) {
|
if (!UseStdin) {
|
||||||
FileAccessDate = GetAccessDate(InitialFile);
|
FileAccessDate = GetAccessDate(InitialFile);
|
||||||
} else {
|
} else {
|
||||||
FileAccessDate = DSEToday;
|
FileAccessDate = DSEToday - 1;
|
||||||
|
if (FileAccessDate < 0) FileAccessDate = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FileAccessDate < 0) {
|
if (FileAccessDate < 0) {
|
||||||
@@ -274,9 +341,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;
|
||||||
@@ -284,11 +353,18 @@ static void DoReminders(void)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/* If we don't recognize the command, do a REM by default */
|
/* If we don't recognize the command, do a REM by default, but warn */
|
||||||
/* 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:
|
||||||
|
if (!SuppressImplicitRemWarnings) {
|
||||||
|
Wprint("Unrecognized command; interpreting as REM");
|
||||||
|
WarnedAboutImplicit = 1;
|
||||||
|
}
|
||||||
|
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 +522,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 +540,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 +663,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 +725,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 +776,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -829,6 +974,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 +1039,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 +1157,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 +1228,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 +1240,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 +1266,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 +1434,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 +1455,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 +1476,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 +1491,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 +1504,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 +1517,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 +1525,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 +1536,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 +1557,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 +1567,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 +1587,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 +1605,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 +1615,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 +1628,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 +1641,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 +1649,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 +1660,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 +1834,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;
|
||||||
}
|
}
|
||||||
@@ -1681,3 +1903,40 @@ get_month_name(int mon)
|
|||||||
if (DynamicMonthName[mon]) return DynamicMonthName[mon];
|
if (DynamicMonthName[mon]) return DynamicMonthName[mon];
|
||||||
return MonthName[mon];
|
return MonthName[mon];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int GetOnceDateFromFile(void)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
int once_date = 0;
|
||||||
|
|
||||||
|
fp = fopen(OnceFile, "r");
|
||||||
|
if (fp) {
|
||||||
|
if (fscanf(fp, "%d", &once_date) != 1) {
|
||||||
|
once_date = 0;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
/* Save today to file */
|
||||||
|
fp = fopen(OnceFile, "w");
|
||||||
|
if (!fp) {
|
||||||
|
Wprint("Warning: Unable to save ONCE timestamp to %s: %s",
|
||||||
|
OnceFile, strerror(errno));
|
||||||
|
return once_date;
|
||||||
|
}
|
||||||
|
fprintf(fp, "%d\n# This is a timestamp file used by Remind to track ONCE reminders.\n# Do not edit or delete it.\n", DSEToday);
|
||||||
|
fclose(fp);
|
||||||
|
return once_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetOnceDate(void)
|
||||||
|
{
|
||||||
|
ProcessedOnce = 1;
|
||||||
|
if (IgnoreOnce || !OnceFile || !*OnceFile) {
|
||||||
|
return FileAccessDate;
|
||||||
|
}
|
||||||
|
if (OnceDate < 0) {
|
||||||
|
OnceDate = GetOnceDateFromFile();
|
||||||
|
}
|
||||||
|
return OnceDate;
|
||||||
|
}
|
||||||
|
|||||||
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 */
|
||||||
|
|||||||
17
src/moon.c
17
src/moon.c
@@ -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"
|
||||||
|
|
||||||
@@ -101,21 +100,12 @@ static double phase (double, double *, double *, double *, double *, double *, d
|
|||||||
#define mmlong 64.975464 /* Moon's mean lonigitude at the epoch */
|
#define mmlong 64.975464 /* Moon's mean lonigitude at the epoch */
|
||||||
#define mmlongp 349.383063 /* Mean longitude of the perigee at the
|
#define mmlongp 349.383063 /* Mean longitude of the perigee at the
|
||||||
epoch */
|
epoch */
|
||||||
#define mlnode 151.950429 /* Mean longitude of the node at the
|
|
||||||
epoch */
|
|
||||||
#define minc 5.145396 /* Inclination of the Moon's orbit */
|
|
||||||
#define mecc 0.054900 /* Eccentricity of the Moon's orbit */
|
#define mecc 0.054900 /* Eccentricity of the Moon's orbit */
|
||||||
#define mangsiz 0.5181 /* Moon's angular size at distance a
|
#define mangsiz 0.5181 /* Moon's angular size at distance a
|
||||||
from Earth */
|
from Earth */
|
||||||
#define msmax 384401.0 /* Semi-major axis of Moon's orbit in km */
|
#define msmax 384401.0 /* Semi-major axis of Moon's orbit in km */
|
||||||
#define mparallax 0.9507 /* Parallax at distance a from Earth */
|
|
||||||
#define synmonth 29.53058868 /* Synodic month (new Moon to new Moon) */
|
#define synmonth 29.53058868 /* Synodic month (new Moon to new Moon) */
|
||||||
#define lunatbase 2423436.0 /* Base date for E. W. Brown's numbered
|
|
||||||
series of lunations (1923 January 16) */
|
|
||||||
|
|
||||||
/* Properties of the Earth */
|
|
||||||
|
|
||||||
#define earthrad 6378.16 /* Radius of Earth in kilometres */
|
|
||||||
#ifdef PI
|
#ifdef PI
|
||||||
#undef PI
|
#undef PI
|
||||||
#endif
|
#endif
|
||||||
@@ -124,11 +114,6 @@ static double phase (double, double *, double *, double *, double *, double *, d
|
|||||||
|
|
||||||
/* Handy mathematical functions */
|
/* Handy mathematical functions */
|
||||||
|
|
||||||
#ifdef sgn
|
|
||||||
#undef sgn
|
|
||||||
#endif
|
|
||||||
#define sgn(x) (((x) < 0) ? -1 : ((x) > 0 ? 1 : 0)) /* Extract sign */
|
|
||||||
|
|
||||||
#ifdef abs
|
#ifdef abs
|
||||||
#undef abs
|
#undef abs
|
||||||
#endif
|
#endif
|
||||||
@@ -144,7 +129,7 @@ static double phase (double, double *, double *, double *, double *, double *, d
|
|||||||
/* */
|
/* */
|
||||||
/* jdate */
|
/* jdate */
|
||||||
/* */
|
/* */
|
||||||
/* Convert a date and time to DSE day and fraction. */
|
/* Convert a date and time to Julian day and fraction. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static long jdate(int y, int mon, int day)
|
static long jdate(int y, int mon, int day)
|
||||||
|
|||||||
38
src/omit.c
38
src/omit.c
@@ -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 */
|
||||||
@@ -37,6 +36,8 @@ 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,17 +123,31 @@ 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->fullsave);
|
free(context->filename);
|
||||||
|
if (context->fullsave) {
|
||||||
|
free(context->fullsave);
|
||||||
|
}
|
||||||
free(context);
|
free(context);
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
@@ -175,6 +196,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 +273,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;
|
||||||
|
|
||||||
@@ -379,6 +401,8 @@ int DoOmit(ParsePtr p)
|
|||||||
default:
|
default:
|
||||||
if (tok.type == T_Until) {
|
if (tok.type == T_Until) {
|
||||||
Eprint("OMIT: UNTIL not allowed; did you mean THROUGH?");
|
Eprint("OMIT: UNTIL not allowed; did you mean THROUGH?");
|
||||||
|
} else if (tok.type == T_Illegal && tok.val < 0) {
|
||||||
|
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
|
||||||
} else {
|
} else {
|
||||||
Eprint("%s: `%s' (OMIT)", ErrMsg[E_UNKNOWN_TOKEN],
|
Eprint("%s: `%s' (OMIT)", ErrMsg[E_UNKNOWN_TOKEN],
|
||||||
DBufValue(&buf));
|
DBufValue(&buf));
|
||||||
|
|||||||
83
src/protos.h
83
src/protos.h
@@ -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); }
|
||||||
|
|
||||||
@@ -31,22 +43,32 @@
|
|||||||
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 ParseLiteralDateOrTime (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);
|
||||||
|
int truthy(Value const *v);
|
||||||
|
|
||||||
|
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);
|
||||||
@@ -65,8 +87,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, ...);
|
||||||
@@ -86,10 +109,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);
|
||||||
@@ -103,13 +127,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);
|
||||||
@@ -118,14 +155,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);
|
||||||
@@ -142,7 +179,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);
|
||||||
@@ -168,27 +205,45 @@ 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);
|
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 WriteJSONTrigger(Trigger const *t, int include_tags, int today);
|
||||||
void WriteJSONTimeTrigger(TimeTrig const *tt);
|
void WriteJSONTimeTrigger(TimeTrig const *tt);
|
||||||
|
int GetOnceDate(void);
|
||||||
#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);
|
||||||
|
|
||||||
|
/* Utility functions for dumping tokens */
|
||||||
|
void print_sysvar_tokens(void);
|
||||||
|
void print_builtinfunc_tokens(void);
|
||||||
|
void print_remind_tokens(void);
|
||||||
|
|||||||
381
src/queue.c
381
src/queue.c
@@ -24,16 +24,26 @@
|
|||||||
#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 */
|
/* A list of filenames associated with queued reminders */
|
||||||
typedef struct queuedfname {
|
typedef struct queuedfname {
|
||||||
@@ -55,6 +65,7 @@ typedef struct queuedrem {
|
|||||||
char sched[VAR_NAME_LEN+1];
|
char sched[VAR_NAME_LEN+1];
|
||||||
Trigger t;
|
Trigger t;
|
||||||
TimeTrig tt;
|
TimeTrig tt;
|
||||||
|
int red, green, blue;
|
||||||
} QueuedRem;
|
} QueuedRem;
|
||||||
|
|
||||||
/* Global variables */
|
/* Global variables */
|
||||||
@@ -68,11 +79,38 @@ 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 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 */
|
/* QueueFilename */
|
||||||
@@ -115,6 +153,34 @@ static char const *QueueFilename(char const *fname)
|
|||||||
return elem->fname;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
@@ -140,6 +206,9 @@ 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);
|
||||||
@@ -212,7 +281,14 @@ print_num_queued(void)
|
|||||||
}
|
}
|
||||||
q = q->next;
|
q = q->next;
|
||||||
}
|
}
|
||||||
printf("NOTE queued %d\n", nqueued);
|
if (DaemonJSON) {
|
||||||
|
printf("{");
|
||||||
|
PrintJSONKeyPairString("response", "queued");
|
||||||
|
PrintJSONKeyPairInt("nqueued", nqueued);
|
||||||
|
printf("\"command\":\"STATUS\"}\n");
|
||||||
|
} else {
|
||||||
|
printf("NOTE queued %d\n", nqueued);
|
||||||
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,9 +308,13 @@ void HandleQueuedReminders(void)
|
|||||||
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;
|
||||||
@@ -279,12 +359,16 @@ void HandleQueuedReminders(void)
|
|||||||
|
|
||||||
if (ShouldFork || 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();
|
||||||
@@ -310,8 +394,6 @@ void HandleQueuedReminders(void)
|
|||||||
SleepTime = 60*Daemon;
|
SleepTime = 60*Daemon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wake up once a minute to recalibrate sleep time in
|
|
||||||
case of laptop hibernation */
|
|
||||||
if (IsServerMode()) {
|
if (IsServerMode()) {
|
||||||
/* Wake up on the next exact minute */
|
/* Wake up on the next exact minute */
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
@@ -322,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);
|
||||||
}
|
}
|
||||||
@@ -340,7 +424,9 @@ void HandleQueuedReminders(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Daemon > 0 && SleepTime) CheckInitialFile();
|
if (Daemon > 0 && SleepTime) {
|
||||||
|
CheckInitialFile();
|
||||||
|
}
|
||||||
|
|
||||||
if (Daemon && !q) {
|
if (Daemon && !q) {
|
||||||
if (IsServerMode()) {
|
if (IsServerMode()) {
|
||||||
@@ -367,24 +453,51 @@ void HandleQueuedReminders(void)
|
|||||||
/* Trigger the reminder */
|
/* Trigger the reminder */
|
||||||
CreateParser(q->text, &p);
|
CreateParser(q->text, &p);
|
||||||
RunDisabled = q->RunDisabled;
|
RunDisabled = q->RunDisabled;
|
||||||
if (IsServerMode()) {
|
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->t.tags)) {
|
PrintJSONKeyPairString("qid", qid);
|
||||||
printf("*\n");
|
PrintJSONKeyPairString("ttime", SimpleTimeNoSpace(q->tt.ttime));
|
||||||
} else {
|
PrintJSONKeyPairString("now", SimpleTimeNoSpace(MinutesPastMidnight(1)));
|
||||||
printf("%s\n", DBufValue(&(q->t.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);
|
||||||
FileName = (char *) q->fname;
|
FileName = (char *) q->fname;
|
||||||
(void) TriggerReminder(&p, &q->t, &q->tt, DSEToday, 1);
|
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;
|
FileName = NULL;
|
||||||
if (IsServerMode()) {
|
if (IsServerMode() && !DaemonJSON && q->typ != RUN_TYPE) {
|
||||||
printf("NOTE endreminder\n");
|
printf("NOTE endreminder\n");
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@@ -394,7 +507,6 @@ void HandleQueuedReminders(void)
|
|||||||
/* Calculate the next trigger time */
|
/* Calculate the next trigger time */
|
||||||
q->tt.nexttime = CalculateNextTime(q);
|
q->tt.nexttime = CalculateNextTime(q);
|
||||||
|
|
||||||
/* If it's dequeued, update num_queued */
|
|
||||||
if (q->tt.nexttime != NO_TIME) {
|
if (q->tt.nexttime != NO_TIME) {
|
||||||
/* If trigger time is way in the past because computer has been
|
/* If trigger time is way in the past because computer has been
|
||||||
suspended or hibernated, remove from queue */
|
suspended or hibernated, remove from queue */
|
||||||
@@ -404,9 +516,13 @@ void HandleQueuedReminders(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have dequeued a reminder, update controlling process */
|
/* If queued reminder has expired, actually remove it from queue
|
||||||
if (q->tt.nexttime == NO_TIME && IsServerMode()) {
|
and update status */
|
||||||
print_num_queued();
|
if (q->tt.nexttime == NO_TIME) {
|
||||||
|
del_reminder(q);
|
||||||
|
if (IsServerMode()) {
|
||||||
|
print_num_queued();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
@@ -527,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)) {
|
||||||
@@ -605,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;
|
||||||
@@ -618,6 +756,8 @@ json_queue(QueuedRem const *q)
|
|||||||
printf("{");
|
printf("{");
|
||||||
WriteJSONTrigger(&(q->t), 1, DSEToday);
|
WriteJSONTrigger(&(q->t), 1, DSEToday);
|
||||||
WriteJSONTimeTrigger(&(q->tt));
|
WriteJSONTimeTrigger(&(q->tt));
|
||||||
|
snprintf(idbuf, sizeof(idbuf), "%lx", (unsigned long) q);
|
||||||
|
PrintJSONKeyPairString("qid", idbuf);
|
||||||
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
|
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
|
||||||
PrintJSONKeyPairInt("ntrig", q->ntrig);
|
PrintJSONKeyPairInt("ntrig", q->ntrig);
|
||||||
PrintJSONKeyPairString("filename", q->fname);
|
PrintJSONKeyPairString("filename", q->fname);
|
||||||
@@ -631,7 +771,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,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();
|
||||||
}
|
}
|
||||||
@@ -678,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;
|
||||||
|
|
||||||
@@ -696,43 +875,72 @@ static void DaemonWait(struct timeval *sleep_tv)
|
|||||||
} else if (!strcmp(cmdLine, "STATUS\n")) {
|
} else if (!strcmp(cmdLine, "STATUS\n")) {
|
||||||
print_num_queued();
|
print_num_queued();
|
||||||
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -749,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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
166
src/token.c
166
src/token.c
@@ -39,23 +39,24 @@ while (isdigit(*(string))) { \
|
|||||||
Token TokArray[] = {
|
Token TokArray[] = {
|
||||||
/* NAME MINLEN TYPE VALUE */
|
/* NAME MINLEN TYPE VALUE */
|
||||||
{ "addomit", 7, T_AddOmit, 0 },
|
{ "addomit", 7, T_AddOmit, 0 },
|
||||||
{ "after", 3, T_Skip, AFTER_SKIP },
|
{ "after", 5, T_Skip, AFTER_SKIP },
|
||||||
{ "april", 3, T_Month, 3 },
|
{ "april", 3, T_Month, 3 },
|
||||||
{ "at", 2, T_At, 0 },
|
{ "at", 2, T_At, 0 },
|
||||||
{ "august", 3, T_Month, 7 },
|
{ "august", 3, T_Month, 7 },
|
||||||
{ "banner", 3, T_Banner, 0 },
|
{ "banner", 3, T_Banner, 0 },
|
||||||
{ "before", 3, T_Skip, BEFORE_SKIP },
|
{ "before", 6, T_Skip, BEFORE_SKIP },
|
||||||
{ "cal", 3, T_RemType, CAL_TYPE },
|
{ "cal", 3, T_RemType, CAL_TYPE },
|
||||||
{ "clear-omit-context", 5, T_Clr, 0 },
|
{ "clear-omit-context", 5, T_Clr, 0 },
|
||||||
{ "debug", 5, T_Debug, 0 },
|
{ "debug", 5, T_Debug, 0 },
|
||||||
{ "december", 3, T_Month, 11 },
|
{ "december", 3, T_Month, 11 },
|
||||||
{ "do", 2, T_IncludeR, 0 },
|
{ "do", 2, T_IncludeR, 0 },
|
||||||
{ "dumpvars", 4, T_Dumpvars, 0 },
|
{ "dumpvars", 4, T_Dumpvars, 0 },
|
||||||
{ "duration", 3, T_Duration, 0 },
|
{ "duration", 8, T_Duration, 0 },
|
||||||
{ "else", 4, T_Else, 0 },
|
{ "else", 4, T_Else, 0 },
|
||||||
{ "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 },
|
||||||
@@ -84,9 +85,9 @@ Token TokArray[] = {
|
|||||||
{ "noqueue", 7, T_NoQueue, 0 },
|
{ "noqueue", 7, T_NoQueue, 0 },
|
||||||
{ "november", 3, T_Month, 10 },
|
{ "november", 3, T_Month, 10 },
|
||||||
{ "october", 3, T_Month, 9 },
|
{ "october", 3, T_Month, 9 },
|
||||||
{ "omit", 3, T_Omit, 0 },
|
{ "omit", 4, T_Omit, 0 },
|
||||||
{ "omitfunc", 8, T_OmitFunc, 0 },
|
{ "omitfunc", 8, T_OmitFunc, 0 },
|
||||||
{ "once", 3, T_Once, 0 },
|
{ "once", 4, T_Once, 0 },
|
||||||
{ "pop-omit-context", 3, T_Pop, 0 },
|
{ "pop-omit-context", 3, T_Pop, 0 },
|
||||||
{ "preserve", 8, T_Preserve, 0 },
|
{ "preserve", 8, T_Preserve, 0 },
|
||||||
{ "priority", 8, T_Priority, 0 },
|
{ "priority", 8, T_Priority, 0 },
|
||||||
@@ -102,7 +103,7 @@ Token TokArray[] = {
|
|||||||
{ "second", 6, T_Ordinal, 1 },
|
{ "second", 6, T_Ordinal, 1 },
|
||||||
{ "september", 3, T_Month, 8 },
|
{ "september", 3, T_Month, 8 },
|
||||||
{ "set", 3, T_Set, 0 },
|
{ "set", 3, T_Set, 0 },
|
||||||
{ "skip", 3, T_Skip, SKIP_SKIP },
|
{ "skip", 4, T_Skip, SKIP_SKIP },
|
||||||
{ "special", 7, T_RemType, PASSTHRU_TYPE },
|
{ "special", 7, T_RemType, PASSTHRU_TYPE },
|
||||||
{ "sunday", 3, T_WkDay, 6 },
|
{ "sunday", 3, T_WkDay, 6 },
|
||||||
{ "tag", 3, T_Tag, 0 },
|
{ "tag", 3, T_Tag, 0 },
|
||||||
@@ -111,13 +112,28 @@ Token TokArray[] = {
|
|||||||
{ "thursday", 3, T_WkDay, 3 },
|
{ "thursday", 3, T_WkDay, 3 },
|
||||||
{ "tuesday", 3, T_WkDay, 1 },
|
{ "tuesday", 3, T_WkDay, 1 },
|
||||||
{ "unset", 5, T_UnSet, 0 },
|
{ "unset", 5, T_UnSet, 0 },
|
||||||
{ "until", 3, T_Until, 0 },
|
{ "until", 5, T_Until, 0 },
|
||||||
{ "warn", 4, T_Warn, 0 },
|
{ "warn", 4, T_Warn, 0 },
|
||||||
{ "wednesday", 3, T_WkDay, 2 }
|
{ "wednesday", 3, T_WkDay, 2 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int TokStrCmp (Token const *t, char const *s);
|
static int TokStrCmp (Token const *t, char const *s);
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_token(Token *t)
|
||||||
|
{
|
||||||
|
t->name = NULL;
|
||||||
|
t->type = T_Illegal;
|
||||||
|
t->val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
token_error(Token *t, int errcode)
|
||||||
|
{
|
||||||
|
t->type = T_Illegal;
|
||||||
|
t->val = -errcode;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* FindInitialToken */
|
/* FindInitialToken */
|
||||||
@@ -131,7 +147,7 @@ char const *FindInitialToken(Token *tok, char const *s)
|
|||||||
DynamicBuffer buf;
|
DynamicBuffer buf;
|
||||||
DBufInit(&buf);
|
DBufInit(&buf);
|
||||||
|
|
||||||
tok->type = T_Illegal;
|
init_token(tok);
|
||||||
|
|
||||||
while (isempty(*s)) s++;
|
while (isempty(*s)) s++;
|
||||||
|
|
||||||
@@ -158,7 +174,7 @@ void FindToken(char const *s, Token *tok)
|
|||||||
int top, bot, mid, r, max;
|
int top, bot, mid, r, max;
|
||||||
int l;
|
int l;
|
||||||
|
|
||||||
tok->type = T_Illegal;
|
init_token(tok);
|
||||||
if (! *s) {
|
if (! *s) {
|
||||||
tok->type = T_Empty;
|
tok->type = T_Empty;
|
||||||
return;
|
return;
|
||||||
@@ -232,9 +248,9 @@ void FindNumericToken(char const *s, Token *t)
|
|||||||
int mult = 1, hour, min;
|
int mult = 1, hour, min;
|
||||||
char const *s_orig = s;
|
char const *s_orig = s;
|
||||||
int ampm = 0;
|
int ampm = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
t->type = T_Illegal;
|
init_token(t);
|
||||||
t->val = 0;
|
|
||||||
if (isdigit(*s)) {
|
if (isdigit(*s)) {
|
||||||
PARSENUM(t->val, s);
|
PARSENUM(t->val, s);
|
||||||
|
|
||||||
@@ -242,22 +258,37 @@ void FindNumericToken(char const *s, Token *t)
|
|||||||
if (*s == '-' || *s == '/') {
|
if (*s == '-' || *s == '/') {
|
||||||
char const *p = s_orig;
|
char const *p = s_orig;
|
||||||
int dse, tim;
|
int dse, tim;
|
||||||
if (ParseLiteralDate(&p, &dse, &tim) == OK) {
|
r = ParseLiteralDateOrTime(&p, &dse, &tim);
|
||||||
if (*p) return;
|
if (r == OK) {
|
||||||
|
if (*p) {
|
||||||
|
if (tim == NO_TIME) {
|
||||||
|
t->val = -E_BAD_DATE;
|
||||||
|
} else {
|
||||||
|
t->val = -E_BAD_TIME;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (tim == NO_TIME) {
|
if (tim == NO_TIME) {
|
||||||
t->type = T_Date;
|
t->type = T_Date;
|
||||||
t->val = dse;
|
t->val = dse;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (dse == NO_DATE) {
|
||||||
|
t->type = T_Time;
|
||||||
|
t->val = tim;
|
||||||
|
return;
|
||||||
|
}
|
||||||
t->type = T_DateTime;
|
t->type = T_DateTime;
|
||||||
t->val = MINUTES_PER_DAY * dse + tim;
|
t->val = MINUTES_PER_DAY * dse + tim;
|
||||||
}
|
} else {
|
||||||
|
token_error(t, r);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we hit a comma, swallow it. This allows stuff
|
/* If we hit a comma, swallow it. This allows stuff
|
||||||
like Jan 6, 1998 */
|
like Jan 6, 1998 */
|
||||||
if (*s == ',') {
|
if (*s == ',' && *(s+1) == 0) {
|
||||||
/* Classify the number we've got */
|
/* Classify the number we've got */
|
||||||
if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
|
if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
|
||||||
else if (t->val >= 1 && t->val <= 31) t->type = T_Day;
|
else if (t->val >= 1 && t->val <= 31) t->type = T_Day;
|
||||||
@@ -268,8 +299,16 @@ void FindNumericToken(char const *s, Token *t)
|
|||||||
if (*s == ':' || *s == '.' || *s == TimeSep) {
|
if (*s == ':' || *s == '.' || *s == TimeSep) {
|
||||||
s++;
|
s++;
|
||||||
hour = t->val;
|
hour = t->val;
|
||||||
|
if (!isdigit(*s)) {
|
||||||
|
token_error(t, E_BAD_TIME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
PARSENUM(min, s);
|
PARSENUM(min, s);
|
||||||
if (min > 59) return; /* Illegal time */
|
if (min > 59) {
|
||||||
|
/* Illegal time */
|
||||||
|
token_error(t, E_BAD_TIME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* Check for p[m] or a[m] */
|
/* Check for p[m] or a[m] */
|
||||||
if (*s == 'A' || *s == 'a' || *s == 'P' || *s == 'p') {
|
if (*s == 'A' || *s == 'a' || *s == 'P' || *s == 'p') {
|
||||||
ampm = tolower(*s);
|
ampm = tolower(*s);
|
||||||
@@ -278,9 +317,15 @@ void FindNumericToken(char const *s, Token *t)
|
|||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*s) return; /* Illegal time */
|
if (*s) {
|
||||||
|
token_error(t, E_BAD_TIME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (ampm) {
|
if (ampm) {
|
||||||
if (hour < 1 || hour > 12) return;
|
if (hour < 1 || hour > 12) {
|
||||||
|
token_error(t, E_BAD_TIME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (ampm == 'a') {
|
if (ampm == 'a') {
|
||||||
if (hour == 12) {
|
if (hour == 12) {
|
||||||
hour = 0;
|
hour = 0;
|
||||||
@@ -302,45 +347,70 @@ void FindNumericToken(char const *s, Token *t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If we hit a non-digit, error! */
|
/* If we hit a non-digit, error! */
|
||||||
if (*s) return;
|
if (*s) {
|
||||||
|
token_error(t, E_BAD_NUMBER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Classify the number we've got */
|
/* Classify the number we've got */
|
||||||
if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
|
if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
|
||||||
else if (t->val >= 1 && t->val <= 31) t->type = T_Day;
|
else if (t->val >= 1 && t->val <= 31) t->type = T_Day;
|
||||||
else t->type = T_Number;
|
else t->type = T_Number;
|
||||||
return;
|
return;
|
||||||
} else if (*s == '*') {
|
}
|
||||||
|
|
||||||
|
switch (*s) {
|
||||||
|
case '*':
|
||||||
s++;
|
s++;
|
||||||
PARSENUM(t->val, s);
|
PARSENUM(t->val, s);
|
||||||
if (*s) return; /* Illegal token if followed by non-numeric char */
|
if (*s) {
|
||||||
|
/* Illegal token if followed by non-numeric char */
|
||||||
|
token_error(t, E_BAD_NUMBER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
t->type = T_Rep;
|
t->type = T_Rep;
|
||||||
return;
|
return;
|
||||||
} else if (*s == '+') {
|
|
||||||
|
case '+':
|
||||||
s++;
|
s++;
|
||||||
if (*s == '+') { mult = -1; s++; }
|
if (*s == '+') { mult = -1; s++; }
|
||||||
PARSENUM(t->val, s);
|
PARSENUM(t->val, s);
|
||||||
if (*s) return; /* Illegal token if followed by non-numeric char */
|
if (*s) {
|
||||||
|
/* Illegal token if followed by non-numeric char */
|
||||||
|
token_error(t, E_BAD_NUMBER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
t->type = T_Delta;
|
t->type = T_Delta;
|
||||||
t->val *= mult;
|
t->val *= mult;
|
||||||
return;
|
return;
|
||||||
} else if (*s == '-') {
|
case '-':
|
||||||
s++;
|
s++;
|
||||||
if (*s == '-') { mult = -1; s++; }
|
if (*s == '-') { mult = -1; s++; }
|
||||||
PARSENUM(t->val, s);
|
PARSENUM(t->val, s);
|
||||||
if (*s) return; /* Illegal token if followed by non-numeric char */
|
if (*s) {
|
||||||
|
/* Illegal token if followed by non-numeric char */
|
||||||
|
token_error(t, E_BAD_NUMBER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
t->type = T_Back;
|
t->type = T_Back;
|
||||||
t->val *= mult;
|
t->val *= mult;
|
||||||
return;
|
return;
|
||||||
} else if (*s == '~') {
|
|
||||||
|
case '~':
|
||||||
s++;
|
s++;
|
||||||
if (*s == '~') { mult = -1; s++; }
|
if (*s == '~') { mult = -1; s++; }
|
||||||
PARSENUM(t->val, s);
|
PARSENUM(t->val, s);
|
||||||
if (*s) return; /* Illegal token if followed by non-numeric char */
|
if (*s) {
|
||||||
|
/* Illegal token if followed by non-numeric char */
|
||||||
|
token_error(t, E_BAD_NUMBER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
t->type = T_BackAdj;
|
t->type = T_BackAdj;
|
||||||
t->val *= mult;
|
t->val *= mult;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
default: return;
|
||||||
}
|
}
|
||||||
return; /* Unknown token type */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -367,3 +437,43 @@ static int TokStrCmp(Token const *t, char const *s)
|
|||||||
if (!*s || (*s == ',' && !*(s+1))) return 0;
|
if (!*s || (*s == ',' && !*(s+1))) return 0;
|
||||||
return (*tk - tolower(*s));
|
return (*tk - tolower(*s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_token(Token *tok)
|
||||||
|
{
|
||||||
|
if (tok->MinLen < (int) strlen(tok->name)) {
|
||||||
|
printf("%.*s\n", tok->MinLen, tok->name);
|
||||||
|
}
|
||||||
|
printf("%s\n", tok->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_remind_tokens(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Token *tok;
|
||||||
|
int num = (int) (sizeof(TokArray) / sizeof(TokArray[0]));
|
||||||
|
printf("# Remind Tokens\n\n");
|
||||||
|
for (i=0; i<num; i++) {
|
||||||
|
tok = &TokArray[i];
|
||||||
|
if (tok->type != T_Month && tok->type != T_WkDay) {
|
||||||
|
print_token(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n# Month Names\n\n");
|
||||||
|
for (i=0; i<num; i++) {
|
||||||
|
tok = &TokArray[i];
|
||||||
|
if (tok->type == T_Month) {
|
||||||
|
print_token(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n# Weekdays\n\n");
|
||||||
|
for (i=0; i<num; i++) {
|
||||||
|
tok = &TokArray[i];
|
||||||
|
if (tok->type == T_WkDay) {
|
||||||
|
print_token(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
93
src/types.h
93
src/types.h
@@ -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,62 @@ 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_SHORT_STR,
|
||||||
|
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 +191,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 +201,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 +235,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 +296,27 @@ 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;
|
||||||
|
int recurse_flag;
|
||||||
|
} UserFunc;
|
||||||
|
|
||||||
|
|||||||
346
src/userfns.c
346
src/userfns.c
@@ -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;
|
||||||
@@ -108,6 +115,25 @@ int DoFset(ParsePtr p)
|
|||||||
}
|
}
|
||||||
orig_namelen = buf.len;
|
orig_namelen = buf.len;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
/* Warn about redefinition */
|
||||||
|
Wprint("Function %s redefined (previously defined at %s:%d)",
|
||||||
|
existing->name, existing->filename, existing->lineno);
|
||||||
|
}
|
||||||
|
|
||||||
/* Should be followed by '(' */
|
/* Should be followed by '(' */
|
||||||
c = ParseNonSpaceChar(p, &r, 0);
|
c = ParseNonSpaceChar(p, &r, 0);
|
||||||
if (r) {
|
if (r) {
|
||||||
@@ -134,28 +160,26 @@ int DoFset(ParsePtr p)
|
|||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
func->lineno = LineNo;
|
func->lineno = LineNo;
|
||||||
|
func->recurse_flag = 0;
|
||||||
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,19 +187,31 @@ 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 (r) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
DestroyUserFunc(func);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
if (c == ')') break;
|
if (c == ')') break;
|
||||||
else if (c != ',') {
|
else if (c != ',') {
|
||||||
DestroyUserFunc(func);
|
DestroyUserFunc(func);
|
||||||
@@ -186,20 +222,50 @@ int DoFset(ParsePtr p)
|
|||||||
|
|
||||||
/* Allow an optional = sign: FSET f(x) = x*x */
|
/* Allow an optional = sign: FSET f(x) = x*x */
|
||||||
c = ParseNonSpaceChar(p, &r, 1);
|
c = ParseNonSpaceChar(p, &r, 1);
|
||||||
|
if (r) {
|
||||||
|
DestroyUserFunc(func);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
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 || r != 0) {
|
||||||
|
DestroyUserFunc(func);
|
||||||
|
if (r != 0) return r;
|
||||||
|
return E_EXPECTING_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the argument names */
|
||||||
|
if (func->nargs) {
|
||||||
|
func->args = calloc(func->nargs, sizeof(char *));
|
||||||
|
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 +289,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 +322,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,134 +345,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 */
|
||||||
@@ -418,12 +371,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
92
src/utils.c
92
src/utils.c
@@ -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>
|
||||||
|
|
||||||
@@ -46,6 +51,7 @@ char *StrnCpy(char *dest, char const *source, int n)
|
|||||||
return odest;
|
return odest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef HAVE_STRNCASECMP
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* StrinCmp - compare strings, case-insensitive */
|
/* StrinCmp - compare strings, case-insensitive */
|
||||||
@@ -64,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 */
|
||||||
@@ -79,6 +88,9 @@ char *StrDup(char const *s)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_STRCASECMP
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* StrCmpi */
|
/* StrCmpi */
|
||||||
@@ -98,6 +110,8 @@ int StrCmpi(char const *s1, char const *s2)
|
|||||||
return toupper(*s1) - toupper(*s2);
|
return toupper(*s1) - toupper(*s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* DateOK */
|
/* DateOK */
|
||||||
@@ -116,6 +130,14 @@ int DateOK(int y, int m, int d)
|
|||||||
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 */
|
||||||
|
|
||||||
int _private_mul_overflow(int a, int b)
|
int _private_mul_overflow(int a, int b)
|
||||||
@@ -151,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;
|
||||||
}
|
}
|
||||||
@@ -169,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;
|
||||||
@@ -215,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
|
||||||
|
|||||||
131
src/var.c
131
src/var.c
@@ -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,40 @@ 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 oncefile_func(int do_set, Value *val)
|
||||||
|
{
|
||||||
|
if (do_set) {
|
||||||
|
if (val->type != STR_TYPE) return E_BAD_TYPE;
|
||||||
|
if (! (*val->v.str) && (!OnceFile || !*OnceFile)) {
|
||||||
|
/* Trying to set already-empty string to empty string */
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
if (OnceFile && !strcmp(OnceFile, val->v.str)) {
|
||||||
|
/* Trying to set to the exact same value */
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ProcessedOnce) {
|
||||||
|
Wprint("Not setting $OnceFile: Already processed a reminder with a ONCE clause");
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
if (OnceFile) {
|
||||||
|
free( (void *) OnceFile);
|
||||||
|
}
|
||||||
|
OnceFile = StrDup(val->v.str);
|
||||||
|
if (!OnceFile) return E_NO_MEM;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
if (!OnceFile) {
|
||||||
|
val->v.str = StrDup("");
|
||||||
|
} else {
|
||||||
|
val->v.str = StrDup(OnceFile);
|
||||||
|
}
|
||||||
|
if (!val->v.str) return E_NO_MEM;
|
||||||
|
val->type = STR_TYPE;
|
||||||
|
return OK;
|
||||||
|
|
||||||
|
}
|
||||||
static int terminal_bg_func(int do_set, Value *val)
|
static int terminal_bg_func(int do_set, Value *val)
|
||||||
{
|
{
|
||||||
UNUSED(do_set);
|
UNUSED(do_set);
|
||||||
@@ -175,6 +206,19 @@ static int terminal_bg_func(int do_set, Value *val)
|
|||||||
return OK;
|
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)
|
||||||
{
|
{
|
||||||
UNUSED(do_set);
|
UNUSED(do_set);
|
||||||
@@ -309,6 +353,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;
|
||||||
@@ -477,10 +544,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);
|
||||||
|
|
||||||
@@ -498,24 +565,14 @@ 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) {
|
||||||
Eprint("%s: %s", ErrMsg[E_NOSUCH_VAR], str);
|
Eprint("%s: `%s'", ErrMsg[E_NOSUCH_VAR], str);
|
||||||
return E_NOSUCH_VAR;
|
return E_NOSUCH_VAR;
|
||||||
}
|
}
|
||||||
return CopyValue(val, &v->v);
|
return CopyValue(val, &v->v);
|
||||||
@@ -530,7 +587,7 @@ int DoSet (Parser *p)
|
|||||||
{
|
{
|
||||||
Value v;
|
Value v;
|
||||||
int r;
|
int r;
|
||||||
|
int ch;
|
||||||
DynamicBuffer buf;
|
DynamicBuffer buf;
|
||||||
DynamicBuffer buf2;
|
DynamicBuffer buf2;
|
||||||
DBufInit(&buf);
|
DBufInit(&buf);
|
||||||
@@ -540,8 +597,16 @@ int DoSet (Parser *p)
|
|||||||
if (r) return r;
|
if (r) return r;
|
||||||
|
|
||||||
/* Allow optional equals-sign: SET var = value */
|
/* Allow optional equals-sign: SET var = value */
|
||||||
if (ParseNonSpaceChar(p, &r, 1) == '=') {
|
ch = ParseNonSpaceChar(p, &r, 1);
|
||||||
|
if (r) return r;
|
||||||
|
if (ch == '=') {
|
||||||
ParseNonSpaceChar(p, &r, 0);
|
ParseNonSpaceChar(p, &r, 0);
|
||||||
|
if (r) return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
@@ -772,16 +837,6 @@ int DoPreserve (Parser *p)
|
|||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
/* Macro to access "min" but as a constval. Just to make source more
|
/* Macro to access "min" but as a constval. Just to make source more
|
||||||
readable */
|
readable */
|
||||||
#define constval min
|
#define constval min
|
||||||
@@ -818,6 +873,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 },
|
||||||
@@ -864,6 +920,7 @@ static SysVar SysVarArr[] = {
|
|||||||
{"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 },
|
||||||
{"On", 1, STR_TYPE, &DynamicOn, 0, 0 },
|
{"On", 1, STR_TYPE, &DynamicOn, 0, 0 },
|
||||||
|
{"OnceFile", 1, SPECIAL_TYPE, oncefile_func, 0, 0 },
|
||||||
{"ParseUntriggered", 1, INT_TYPE, &ParseUntriggered, 0, 1 },
|
{"ParseUntriggered", 1, INT_TYPE, &ParseUntriggered, 0, 1 },
|
||||||
{"Pm", 1, STR_TYPE, &DynamicPm, 0, 0 },
|
{"Pm", 1, STR_TYPE, &DynamicPm, 0, 0 },
|
||||||
{"PrefixLineNo", 0, INT_TYPE, &DoPrefixLineNo, 0, 0 },
|
{"PrefixLineNo", 0, INT_TYPE, &DoPrefixLineNo, 0, 0 },
|
||||||
@@ -877,6 +934,7 @@ static SysVar SysVarArr[] = {
|
|||||||
{"SortByTime", 0, INT_TYPE, &SortByTime, 0, 0 },
|
{"SortByTime", 0, INT_TYPE, &SortByTime, 0, 0 },
|
||||||
{"SubsIndent", 1, INT_TYPE, &SubsIndent, 0, 132 },
|
{"SubsIndent", 1, INT_TYPE, &SubsIndent, 0, 132 },
|
||||||
{"Sunday", 1, STR_TYPE, &DynamicDayName[6], 0, 0 },
|
{"Sunday", 1, STR_TYPE, &DynamicDayName[6], 0, 0 },
|
||||||
|
{"SuppressImplicitWarnings", 1, INT_TYPE, &SuppressImplicitRemWarnings, 0, 1},
|
||||||
{"SuppressLRM", 1, INT_TYPE, &SuppressLRM, 0, 1 },
|
{"SuppressLRM", 1, INT_TYPE, &SuppressLRM, 0, 1 },
|
||||||
{"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 },
|
||||||
@@ -887,6 +945,7 @@ static SysVar SysVarArr[] = {
|
|||||||
{"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 },
|
||||||
@@ -905,7 +964,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);
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
@@ -1002,7 +1060,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;
|
||||||
@@ -1062,7 +1120,7 @@ static void DumpSysVar(char const *name, const SysVar *v)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
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, "%25s ", buffer);
|
||||||
if (v) {
|
if (v) {
|
||||||
if (v->type == CONST_INT_TYPE) {
|
if (v->type == CONST_INT_TYPE) {
|
||||||
fprintf(ErrFp, "%d\n", v->constval);
|
fprintf(ErrFp, "%d\n", v->constval);
|
||||||
@@ -1141,3 +1199,12 @@ set_components_from_lat_and_long(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_sysvar_tokens(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
printf("\n# System Variables\n\n");
|
||||||
|
for (i=0; i< (int) NUMSYSVARS; i++) {
|
||||||
|
printf("$%s\n", SysVarArr[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
55
tests/expr.rem
Normal file
55
tests/expr.rem
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
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)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
|
||||||
|
|
||||||
|
set a isany(1)
|
||||||
|
set a isany(1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6)
|
||||||
|
set a isany("foo", 1 + 1, 2:00 + 1, '2021-01-01' + 1, '2021-01-01@14:00' + 1, "f" + "oo", "fo" + "o")
|
||||||
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
|
||||||
|
|
||||||
@@ -2,5 +2,5 @@ FSET msgprefix(x) "Priority: " + x + "; Filename: " + filename() + ": "
|
|||||||
|
|
||||||
REM at 23:56 MSG foo
|
REM at 23:56 MSG foo
|
||||||
REM PRIORITY 42 at 23:57 MSG bar
|
REM PRIORITY 42 at 23:57 MSG bar
|
||||||
REM PRIORITY 999 at 23:58 MSQ quux
|
REM PRIORITY 999 at 23:58 MSG quux
|
||||||
DO queue2.rem
|
DO queue2.rem
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ set $LatMin 24
|
|||||||
set $LatSec 0
|
set $LatSec 0
|
||||||
|
|
||||||
IF $PSCAL
|
IF $PSCAL
|
||||||
[trigger(moondate(0))] SPECIAL MOON 0 -1 -1 [moontime(0)]
|
REM [trigger(moondate(0))] SPECIAL MOON 0 -1 -1 [moontime(0)]
|
||||||
[trigger(moondate(1))] SPECIAL MOON 1 -1 -1 [moontime(1)]
|
REM [trigger(moondate(1))] SPECIAL MOON 1 -1 -1 [moontime(1)]
|
||||||
[trigger(moondate(2))] SPECIAL MOON 2 -1 -1 [moontime(2)]
|
REM [trigger(moondate(2))] SPECIAL MOON 2 -1 -1 [moontime(2)]
|
||||||
[trigger(moondate(3))] SPECIAL MOON 3 -1 -1 [moontime(3)]
|
REM [trigger(moondate(3))] SPECIAL MOON 3 -1 -1 [moontime(3)]
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
REM 4 PS (First-Bit-Of-PS)
|
REM 4 PS (First-Bit-Of-PS)
|
||||||
|
|||||||
7
tests/test-once.rem
Normal file
7
tests/test-once.rem
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
BANNER %
|
||||||
|
SET $OnceFile "../tests/once.timestamp"
|
||||||
|
|
||||||
|
REM ONCE MSG This should only be issued once per day.
|
||||||
|
|
||||||
|
SET $OnceFile "../tests/once.timestamp"
|
||||||
|
SET $OnceFile "../tests/once-again.timestamp"
|
||||||
148
tests/test-rem
148
tests/test-rem
@@ -176,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
|
||||||
@@ -452,10 +452,154 @@ rm -rf include_dir/ww
|
|||||||
# Test queueing. Because eventstart depends on the actual system
|
# Test queueing. Because eventstart depends on the actual system
|
||||||
# date, we have to convert it to some constant (in this case,
|
# date, we have to convert it to some constant (in this case,
|
||||||
# VOLATILE) so that tests are not dependent on the system date.
|
# 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' >> ../tests/test.out 2>&1
|
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
|
||||||
|
|
||||||
|
# Test ONCE with a timestamp file
|
||||||
|
rm -f ../tests/once.timestamp
|
||||||
|
../src/remind ../tests/test-once.rem >> ../tests/test.out 2>&1
|
||||||
|
../src/remind ../tests/test-once.rem >> ../tests/test.out 2>&1
|
||||||
|
../src/remind ../tests/test-once.rem >> ../tests/test.out 2>&1
|
||||||
|
tail +2 ../tests/once.timestamp >> ../tests/test.out 2>&1
|
||||||
|
rm -f ../tests/once.timestamp
|
||||||
|
|
||||||
|
../src/remind - < ../tests/test-once.rem >> ../tests/test.out 2>&1
|
||||||
|
../src/remind - < ../tests/test-once.rem >> ../tests/test.out 2>&1
|
||||||
|
../src/remind - < ../tests/test-once.rem >> ../tests/test.out 2>&1
|
||||||
|
tail +2 ../tests/once.timestamp >> ../tests/test.out 2>&1
|
||||||
|
rm -f ../tests/once.timestamp
|
||||||
|
|
||||||
|
# Newlines in calendar output
|
||||||
|
(echo 'REM 16 MSG foo%_bar%_baz wookie quux apple %_ %_ %_ blech'; echo "REM 16 MSG ANOTHER") | ../src/remind -c -w80 - 1 sep 1990 >> ../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
|
||||||
|
|
||||||
|
# If "man" accepts the --warnings flag, test all the man pages.
|
||||||
|
man man | grep -e --warnings > /dev/null 2>&1
|
||||||
|
if test $? = 0 ; then
|
||||||
|
for i in ../man/*.1 ; do
|
||||||
|
man --warnings=w $i 2>>../tests/test.out 1>/dev/null
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test --print-tokens long option
|
||||||
|
../src/remind --print-tokens < /dev/null >> ../tests/test.out 2>&1
|
||||||
|
|
||||||
cmp -s ../tests/test.out ../tests/test.cmp
|
cmp -s ../tests/test.out ../tests/test.cmp
|
||||||
if [ "$?" = "0" ]; then
|
if [ "$?" = "0" ]; then
|
||||||
echo "Remind: Acceptance test PASSED"
|
echo "Remind: Acceptance test PASSED"
|
||||||
|
|||||||
4225
tests/test.cmp
4225
tests/test.cmp
File diff suppressed because one or more lines are too long
299
tests/test.rem
299
tests/test.rem
@@ -33,7 +33,7 @@ fset _h(x, y) trigger(hebdate(x,y))
|
|||||||
|
|
||||||
# Test case from Remind mailing list
|
# Test case from Remind mailing list
|
||||||
set mltest "a b"
|
set mltest "a b"
|
||||||
INCLUDECMD printf 'REM %s\n' [mltest]
|
INCLUDECMD printf 'REM MSG %s\n' [mltest]
|
||||||
|
|
||||||
# Disabling RUN in an !includecmd
|
# Disabling RUN in an !includecmd
|
||||||
INCLUDECMD !echo MSG foo
|
INCLUDECMD !echo MSG foo
|
||||||
@@ -49,38 +49,38 @@ INCLUDECMD echo MSG foo
|
|||||||
RUN ON
|
RUN ON
|
||||||
INCLUDECMD echo MSG foo
|
INCLUDECMD echo MSG foo
|
||||||
|
|
||||||
[_h(1, "Tishrey")] MSG Rosh Hashana 1
|
REM [_h(1, "Tishrey")] MSG Rosh Hashana 1
|
||||||
[_h(2, "Tishrey")] MSG Rosh Hashana 2
|
REM [_h(2, "Tishrey")] MSG Rosh Hashana 2
|
||||||
[_h(3, "Tishrey")] MSG Tzom Gedalia
|
REM [_h(3, "Tishrey")] MSG Tzom Gedalia
|
||||||
[_h(10, "Tishrey")] MSG Yom Kippur
|
REM [_h(10, "Tishrey")] MSG Yom Kippur
|
||||||
[_h(15, "Tishrey")] MSG Sukkot 1
|
REM [_h(15, "Tishrey")] MSG Sukkot 1
|
||||||
[_h(25, "Kislev")] MSG Channuka
|
REM [_h(25, "Kislev")] MSG Channuka
|
||||||
[_h(10, "Tevet")] MSG Asara B'Tevet
|
REM [_h(10, "Tevet")] MSG Asara B'Tevet
|
||||||
[_h(15, "Shvat")] MSG Tu B'Shvat
|
REM [_h(15, "Shvat")] MSG Tu B'Shvat
|
||||||
[_h(15, "Adar A")] MSG Purim Katan
|
REM [_h(15, "Adar A")] MSG Purim Katan
|
||||||
[_h(14, "Adar")] MSG Purim
|
REM [_h(14, "Adar")] MSG Purim
|
||||||
[_h(15, "Nisan")] MSG Pesach
|
REM [_h(15, "Nisan")] MSG Pesach
|
||||||
[_h(27, "Nisan")] MSG Yom HaShoah
|
REM [_h(27, "Nisan")] MSG Yom HaShoah
|
||||||
[_h(4, "Iyar")] MSG Yom HaZikaron
|
REM [_h(4, "Iyar")] MSG Yom HaZikaron
|
||||||
[_h(5, "Iyar")] MSG Yom Ha'atzmaut
|
REM [_h(5, "Iyar")] MSG Yom Ha'atzmaut
|
||||||
[_h(28, "Iyar")] MSG Yom Yerushalayim
|
REM [_h(28, "Iyar")] MSG Yom Yerushalayim
|
||||||
[_h(6, "Sivan")] MSG Shavuot
|
REM [_h(6, "Sivan")] MSG Shavuot
|
||||||
[_h(9, "Av")] MSG Tish'a B'Av
|
REM [_h(9, "Av")] MSG Tish'a B'Av
|
||||||
|
|
||||||
# Test some jahrzeit cases
|
# Test some jahrzeit cases
|
||||||
fset _i(x,y,z,a) trigger(hebdate(x,y,z,a))
|
fset _i(x,y,z,a) trigger(hebdate(x,y,z,a))
|
||||||
[_i(30, "Heshvan", today(), 5759)] MSG Complete-Complete
|
REM [_i(30, "Heshvan", today(), 5759)] MSG Complete-Complete
|
||||||
[_i(30, "Heshvan", today(), 5760)] MSG Complete-Defective
|
REM [_i(30, "Heshvan", today(), 5760)] MSG Complete-Defective
|
||||||
[_i(30, "Heshvan", today(), 5761)] MSG Illegal
|
REM [_i(30, "Heshvan", today(), 5761)] MSG Illegal
|
||||||
|
|
||||||
[_i(30, "Kislev", today(), 5759)] MSG Complete-Complete
|
REM [_i(30, "Kislev", today(), 5759)] MSG Complete-Complete
|
||||||
[_i(30, "Kislev", today(), 5760)] MSG Complete-Defective
|
REM [_i(30, "Kislev", today(), 5760)] MSG Complete-Defective
|
||||||
[_i(30, "Kislev", today(), 5761)] MSG Illegal
|
REM [_i(30, "Kislev", today(), 5761)] MSG Illegal
|
||||||
|
|
||||||
[_i(30, "Adar A", today(), 5755)] MSG Leap
|
REM [_i(30, "Adar A", today(), 5755)] MSG Leap
|
||||||
[_i(30, "Adar A", today(), 5756)] MSG Illegal
|
REM [_i(30, "Adar A", today(), 5756)] MSG Illegal
|
||||||
[_i(29, "Adar A", today(), 5755)] MSG Leap
|
REM [_i(29, "Adar A", today(), 5755)] MSG Leap
|
||||||
[_i(29, "Adar A", today(), 5756)] MSG Illegal
|
REM [_i(29, "Adar A", today(), 5756)] MSG Illegal
|
||||||
|
|
||||||
# This causes a parse error on version 03.01.01
|
# This causes a parse error on version 03.01.01
|
||||||
REM 1990-01-01 SATISFY 1
|
REM 1990-01-01 SATISFY 1
|
||||||
@@ -238,8 +238,8 @@ CLEAR-OMIT-CONTEXT
|
|||||||
|
|
||||||
REM tag ill,egal MSG bad tag
|
REM tag ill,egal MSG bad tag
|
||||||
REM MSG The tags are: [trigtags()]
|
REM MSG The tags are: [trigtags()]
|
||||||
REM TAG foo The tags are: [trigtags()]
|
REM TAG foo MSG The tags are: [trigtags()]
|
||||||
REM TAG foo TAG bar TAG quux TAG znort TAG cabbage The tags are: [trigtags()]
|
REM TAG foo TAG bar TAG quux TAG znort TAG cabbage MSG The tags are: [trigtags()]
|
||||||
REM MSG The tags are: [trigtags()]
|
REM MSG The tags are: [trigtags()]
|
||||||
|
|
||||||
# Test ADDOMIT
|
# Test ADDOMIT
|
||||||
@@ -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)
|
||||||
@@ -447,7 +450,7 @@ set a125 trigduration()
|
|||||||
|
|
||||||
# Test adding TIME+TIME and DATETIME+TIME
|
# Test adding TIME+TIME and DATETIME+TIME
|
||||||
set a126 11:00 + 3:00
|
set a126 11:00 + 3:00
|
||||||
set a127 23:00 + 5:30
|
set a127 '23:00' + 5:30
|
||||||
set a128 '2018-02-03@10:00' + 6:45
|
set a128 '2018-02-03@10:00' + 6:45
|
||||||
set a129 23:30 + '2019-02-02@16:44'
|
set a129 23:30 + '2019-02-02@16:44'
|
||||||
|
|
||||||
@@ -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()
|
||||||
@@ -555,11 +559,11 @@ REM 1992-01-01 *1 UNTIL 1991-12-31 MSG Diagnosed
|
|||||||
set x '1992-01-01'
|
set x '1992-01-01'
|
||||||
REM [x] *1 UNTIL 1991-12-31 MSG Not diagnosed - nonconst expression
|
REM [x] *1 UNTIL 1991-12-31 MSG Not diagnosed - nonconst expression
|
||||||
|
|
||||||
REM MON FROM 1992-01-01 UNTIL 1991-12-31 Diagnosed
|
REM MON FROM 1992-01-01 UNTIL 1991-12-31 MSG Diagnosed
|
||||||
REM MON SCANFROM 1992-01-01 UNTIL 1991-12-31 Diagnosed
|
REM MON SCANFROM 1992-01-01 UNTIL 1991-12-31 MSG Diagnosed
|
||||||
|
|
||||||
REM MON FROM [x] UNTIL 1991-12-31 Not diagnosed
|
REM MON FROM [x] UNTIL 1991-12-31 MSG Not diagnosed
|
||||||
REM MON SCANFROM [x] UNTIL 1991-12-31 Not diagnosed
|
REM MON SCANFROM [x] UNTIL 1991-12-31 MSG Not diagnosed
|
||||||
|
|
||||||
REM 1992-01-01 UNTIL 1992-02-02 MSG Diagnosed
|
REM 1992-01-01 UNTIL 1992-02-02 MSG Diagnosed
|
||||||
REM [x] UNTIL 1992-02-02 MSG Diagnosed
|
REM [x] UNTIL 1992-02-02 MSG Diagnosed
|
||||||
@@ -571,7 +575,7 @@ OMIT December 25 MSG X
|
|||||||
OMIT 26 Dec 2010 THROUGH 27 Dec 2010 MSG This is not legal
|
OMIT 26 Dec 2010 THROUGH 27 Dec 2010 MSG This is not legal
|
||||||
OMIT DUMP
|
OMIT DUMP
|
||||||
# Regression test for bugfix in Hebrew calendar Adar jahrzeit
|
# Regression test for bugfix in Hebrew calendar Adar jahrzeit
|
||||||
[_i(14, "Adar", today(), 5761)] MSG Purim
|
REM [_i(14, "Adar", today(), 5761)] MSG Purim
|
||||||
|
|
||||||
# Regression test for bug found by Larry Hynes
|
# Regression test for bug found by Larry Hynes
|
||||||
REM SATISFY [day(trigdate()-25) == 14] MSG Foo
|
REM SATISFY [day(trigdate()-25) == 14] MSG Foo
|
||||||
@@ -704,6 +708,56 @@ set x ampm(21:12) + ""
|
|||||||
set x ampm(22:12) + ""
|
set x ampm(22:12) + ""
|
||||||
set x ampm(23:12) + ""
|
set x ampm(23:12) + ""
|
||||||
|
|
||||||
|
set x ampm(0:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(1:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(2:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(3:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(4:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(5:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(6:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(7:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(8:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(9:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(10:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(11:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(12:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(13:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(14:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(15:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(16:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(17:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(18:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(19:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(20:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(21:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(22:12,"AM", "PM", 1) + ""
|
||||||
|
set x ampm(23:12,"AM", "PM", 1) + ""
|
||||||
|
|
||||||
|
set x ampm(0:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(0:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(2:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(3:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(4:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(5:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(6:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(7:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(8:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(9:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(00:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(00:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(02:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(03:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(04:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(05:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(06:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(07:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(08:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(09:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(20:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(20:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(22:02,"AM", "PM", 0) + ""
|
||||||
|
set x ampm(23:02,"AM", "PM", 0) + ""
|
||||||
|
|
||||||
# Coerce with am/pm
|
# Coerce with am/pm
|
||||||
set x coerce("TIME", "12:45am")
|
set x coerce("TIME", "12:45am")
|
||||||
set x coerce("TIME", "12:45")
|
set x coerce("TIME", "12:45")
|
||||||
@@ -773,15 +827,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
|
||||||
@@ -856,6 +922,17 @@ REM MSG Here: %{custom}
|
|||||||
REM MSG There: %*{custom}
|
REM MSG There: %*{custom}
|
||||||
REM MSG Bad: %{custom
|
REM MSG Bad: %{custom
|
||||||
|
|
||||||
|
REM MSG Undefined: %{nopity_nope_nope}
|
||||||
|
|
||||||
|
# Bad substitution functions
|
||||||
|
FSET subst_bad() "foo"
|
||||||
|
REM MSG %{bad}
|
||||||
|
|
||||||
|
FSET subst_ampm(a, b, c, d, e, f, g) "wookie"
|
||||||
|
|
||||||
|
REM AT 11:00 MSG %2
|
||||||
|
FUNSET subst_ampm
|
||||||
|
|
||||||
# Test FUNSET
|
# Test FUNSET
|
||||||
FSET square(x) x*x
|
FSET square(x) x*x
|
||||||
SET a square(5)
|
SET a square(5)
|
||||||
@@ -908,6 +985,152 @@ set a 7 * "Cabbage! "
|
|||||||
# Should result in errors
|
# Should result in errors
|
||||||
set pqxya 1+2)
|
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("😆")]
|
||||||
|
|
||||||
|
This should be diagnosed as implicitly being REM
|
||||||
|
REM This should be diganosed as implicitly being MSG-type
|
||||||
|
|
||||||
|
# Check that user-defined functions with too many arguments are
|
||||||
|
# correctly diagnosed.
|
||||||
|
|
||||||
|
# This should be OK
|
||||||
|
FSET f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, a62, a63) 3
|
||||||
|
|
||||||
|
# This should give an error
|
||||||
|
FSET f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, a62, a63, a64) 3
|
||||||
|
|
||||||
|
# Check that SATISFY expressions that don't reference trigdate are diagnosed
|
||||||
|
|
||||||
|
# These should all NOT be diagnosed
|
||||||
|
set x 3
|
||||||
|
REM SATISFY 1
|
||||||
|
REM SATISFY trigdate() > '1990-01-01'
|
||||||
|
REM AT 23:59 SATISFY trigdatetime() > '1990-01-01@12:00'
|
||||||
|
REM SATISFY $T > '1990-01-01'
|
||||||
|
REM SATISFY $Ty > 1990
|
||||||
|
REM SATISFY $Tm > 0
|
||||||
|
REM SATISFY $Td > 0
|
||||||
|
REM SATISFY $Tw > -1
|
||||||
|
REM SATISFY [max(x, max(x, 1, 2, 3), 4, 5, 6) * max(5, $Td)]
|
||||||
|
|
||||||
|
FSET references_t(x) $T != x
|
||||||
|
REM SATISFY references_t($U)
|
||||||
|
|
||||||
|
FSET recursive_t(x) iif(x==0, recursive_t(1), references_t($U))
|
||||||
|
|
||||||
|
REM SATISFY recursive_t(0)
|
||||||
|
REM SATISFY recursive_t(2)
|
||||||
|
|
||||||
|
# These should be diagnosed
|
||||||
|
REM SATISFY 0
|
||||||
|
REM SATSIFY ""
|
||||||
|
REM SATISFY [version() > "01.00.00"]
|
||||||
|
REM SATISFY [max(x, max(x, 1, 2, 3), 4, 5, 6) * 5]
|
||||||
|
|
||||||
|
FSET gg(x) 0
|
||||||
|
REM WARN gg MSG Wookie
|
||||||
|
REM AT 11:00 SCHED gg MSG blork
|
||||||
|
REM OMITFUNC gg MSG hehe
|
||||||
|
|
||||||
|
FSET gg(x,y,z) 0
|
||||||
|
REM WARN gg MSG Wookie
|
||||||
|
REM AT 11:00 SCHED gg MSG blork
|
||||||
|
REM OMITFUNC gg MSG hehe
|
||||||
|
|
||||||
|
FSET gg() 0
|
||||||
|
REM WARN gg MSG Wookie
|
||||||
|
REM AT 11:00 SCHED gg MSG blork
|
||||||
|
REM OMITFUNC gg MSG hehe
|
||||||
|
|
||||||
|
FSET gg(x) x-x
|
||||||
|
REM WARN gg MSG Wookie
|
||||||
|
REM AT 11:00 SCHED gg MSG blork
|
||||||
|
REM OMITFUNC gg MSG hehe
|
||||||
|
|
||||||
|
REM WARN not_defined MSG Wookie
|
||||||
|
REM AT 11:00 SCHED not_defined MSG blork
|
||||||
|
REM OMITFUNC not_defined MSG hehe
|
||||||
|
|
||||||
|
### Strings in logical operators
|
||||||
|
SET logstr "" && 7
|
||||||
|
SET logstr "foo" && 7
|
||||||
|
SET logstr "" && ""
|
||||||
|
SET logstr "foo" && ""
|
||||||
|
SET logstr "" && "bar"
|
||||||
|
SET logstr "foo" && "bar"
|
||||||
|
SET logstr "" && '2023-02-01'
|
||||||
|
SET logstr "foo" && '2023-02-01'
|
||||||
|
|
||||||
|
SET logstr "" || 7
|
||||||
|
SET logstr "foo" || 7
|
||||||
|
SET logstr "" || ""
|
||||||
|
SET logstr "foo" || ""
|
||||||
|
SET logstr "" || "bar"
|
||||||
|
SET logstr "foo" || "bar"
|
||||||
|
SET logstr "" || '2023-02-01'
|
||||||
|
SET logstr "foo" || '2023-02-01'
|
||||||
|
|
||||||
|
set xyz ! 0
|
||||||
|
set xyz ! 1
|
||||||
|
set xyz ! 2
|
||||||
|
|
||||||
|
set xyz ! date(baseyr(), 1, 1)
|
||||||
|
set xyz ! date(baseyr(), 1, 2)
|
||||||
|
set xyz ! '2024-01-01'
|
||||||
|
|
||||||
|
set xyz ! datetime(baseyr(), 1, 1, 00:00)
|
||||||
|
set xyz ! datetime(baseyr(), 1, 1, 00:01)
|
||||||
|
set xyz ! datetime(baseyr(), 1, 2, 12:30)
|
||||||
|
set xyz ! '2024-01-01@11:47'
|
||||||
|
|
||||||
|
set xyz ! 00:00
|
||||||
|
set xyz ! 00:01
|
||||||
|
set xyz ! 23:59
|
||||||
|
|
||||||
|
set xyz ! ""
|
||||||
|
set xyz ! "foo"
|
||||||
|
set xyz ! "0"
|
||||||
|
|
||||||
|
# Test error messages for function calls with too many / too few args
|
||||||
|
|
||||||
|
set zxk version(1)
|
||||||
|
set zxk max()
|
||||||
|
|
||||||
|
fset dooby(x) 1
|
||||||
|
set zxk dooby()
|
||||||
|
set zxk dooby(1, 2)
|
||||||
|
set zxk dooby(1)
|
||||||
|
|
||||||
|
REM 1 Jan 1873 MSG This should fail
|
||||||
|
REM 1873-12-11 MSG Also bad.
|
||||||
|
|
||||||
|
# Test $SuppressImplicitWarnings
|
||||||
|
REM wookie
|
||||||
|
Barf
|
||||||
|
|
||||||
|
set $SuppressImplicitWarnings 1
|
||||||
|
REM wookie
|
||||||
|
Barf
|
||||||
|
|
||||||
# Don't want Remind to queue reminders
|
# Don't want Remind to queue reminders
|
||||||
EXIT
|
EXIT
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
MSG ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский
|
REM MSG ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский
|
||||||
MSG עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית
|
REM MSG עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית
|
||||||
|
|
||||||
Wed MSG With tabs and spaces
|
REM Wed MSG With tabs and spaces
|
||||||
|
|
||||||
REM [moondate(0)] MSG 🌑
|
REM [moondate(0)] MSG 🌑
|
||||||
REM [moondate(1)] MSG 🌓 woo
|
REM [moondate(1)] MSG 🌓 woo
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ CGIDIR = /cgi-bin
|
|||||||
# The complete path to the directory containing the HTML file "calendar.html".
|
# The complete path to the directory containing the HTML file "calendar.html".
|
||||||
# This is a sample file containing links to all the scripts. This path
|
# This is a sample file containing links to all the scripts. This path
|
||||||
# should be the path as seen by the UNIX operating system
|
# should be the path as seen by the UNIX operating system
|
||||||
HTMLDIR = /var/www/remind
|
HTMLDIR = /var/www/html/remind
|
||||||
|
|
||||||
# Where you stick images and CSS files, as seen by UNIX
|
# Where you stick images and CSS files, as seen by UNIX
|
||||||
IMAGEDIR = /var/www/remind/resources
|
IMAGEDIR = /var/www/html/remind/resources
|
||||||
|
|
||||||
# Where images and CSS files are, as seen by web browsers
|
# Where images and CSS files are, as seen by web browsers
|
||||||
IMAGEBASE = /remind/resources
|
IMAGEBASE = /remind/resources
|
||||||
@@ -32,6 +32,7 @@ datarootdir=@datarootdir@
|
|||||||
# Where do Remind and Rem2PS executables live?
|
# Where do Remind and Rem2PS executables live?
|
||||||
REMIND = $(bindir)/remind
|
REMIND = $(bindir)/remind
|
||||||
REM2PS = $(bindir)/rem2ps
|
REM2PS = $(bindir)/rem2ps
|
||||||
|
REM2PDF = $(bindir)/rem2pdf
|
||||||
REM2HTML = $(bindir)/rem2html
|
REM2HTML = $(bindir)/rem2html
|
||||||
# If your Web server requires CGI programs to have a .cgi suffix, use
|
# If your Web server requires CGI programs to have a .cgi suffix, use
|
||||||
# the next line. Otherwise, comment it out
|
# the next line. Otherwise, comment it out
|
||||||
@@ -46,6 +47,7 @@ SEDSCRIPT = -e 's@%CGIDIR%@$(CGIDIR)@g' \
|
|||||||
-e 's@%REMIND%@$(REMIND)@g' \
|
-e 's@%REMIND%@$(REMIND)@g' \
|
||||||
-e 's@%IMAGEBASE%@$(IMAGEBASE)@g' \
|
-e 's@%IMAGEBASE%@$(IMAGEBASE)@g' \
|
||||||
-e 's@%REM2PS%@$(REM2PS)@g' \
|
-e 's@%REM2PS%@$(REM2PS)@g' \
|
||||||
|
-e 's@%REM2PDF%@$(REM2PDF)@g' \
|
||||||
-e 's@%REM2HTML%@$(REM2HTML)@g' \
|
-e 's@%REM2HTML%@$(REM2HTML)@g' \
|
||||||
-e 's@cal_dispatch@cal_dispatch$(CGISUFFIX)@g' \
|
-e 's@cal_dispatch@cal_dispatch$(CGISUFFIX)@g' \
|
||||||
|
|
||||||
@@ -57,7 +59,8 @@ all:
|
|||||||
install:
|
install:
|
||||||
-mkdir -p $(DESTDIR)$(SCRIPTDIR)
|
-mkdir -p $(DESTDIR)$(SCRIPTDIR)
|
||||||
-mkdir -p $(DESTDIR)$(HTMLDIR)
|
-mkdir -p $(DESTDIR)$(HTMLDIR)
|
||||||
cp calps hebdate hebps hebhtml moon sunrise sunset $(DESTDIR)$(SCRIPTDIR)
|
cp calps calpdf hebps hebpdf hebhtml moon sunrise sunset $(DESTDIR)$(SCRIPTDIR)
|
||||||
|
sed $(SEDSCRIPT) < hebdate > $(DESTDIR)$(SCRIPTDIR)/hebdate
|
||||||
sed $(SEDSCRIPT) < cal_dispatch-DIST > $(DESTDIR)$(SCRIPTDIR)/cal_dispatch$(CGISUFFIX)
|
sed $(SEDSCRIPT) < cal_dispatch-DIST > $(DESTDIR)$(SCRIPTDIR)/cal_dispatch$(CGISUFFIX)
|
||||||
sed $(SEDSCRIPT) < hebdate.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/hebdate.rem
|
sed $(SEDSCRIPT) < hebdate.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/hebdate.rem
|
||||||
sed $(SEDSCRIPT) < moon.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/moon.rem
|
sed $(SEDSCRIPT) < moon.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/moon.rem
|
||||||
@@ -73,14 +76,14 @@ install:
|
|||||||
chmod 644 $(DESTDIR)$(SCRIPTDIR)/blank.rem
|
chmod 644 $(DESTDIR)$(SCRIPTDIR)/blank.rem
|
||||||
chmod 644 $(DESTDIR)$(HTMLDIR)/calendar.html
|
chmod 644 $(DESTDIR)$(HTMLDIR)/calendar.html
|
||||||
chmod 755 $(DESTDIR)$(SCRIPTDIR)/cal_dispatch$(CGISUFFIX)
|
chmod 755 $(DESTDIR)$(SCRIPTDIR)/cal_dispatch$(CGISUFFIX)
|
||||||
chmod 755 $(DESTDIR)$(SCRIPTDIR)/calps $(DESTDIR)$(SCRIPTDIR)/hebdate \
|
chmod 755 $(DESTDIR)$(SCRIPTDIR)/calpdf $(DESTDIR)$(SCRIPTDIR)/calps $(DESTDIR)$(SCRIPTDIR)/hebdate \
|
||||||
$(DESTDIR)$(SCRIPTDIR)/hebps $(DESTDIR)$(SCRIPTDIR)/moon \
|
$(DESTDIR)$(SCRIPTDIR)/hebps $(DESTDIR)$(SCRIPTDIR)/hebpdf $(DESTDIR)$(SCRIPTDIR)/moon \
|
||||||
$(DESTDIR)$(SCRIPTDIR)/sunrise $(DESTDIR)$(SCRIPTDIR)/sunset \
|
$(DESTDIR)$(SCRIPTDIR)/sunrise $(DESTDIR)$(SCRIPTDIR)/sunset \
|
||||||
$(DESTDIR)$(SCRIPTDIR)/hebhtml \
|
$(DESTDIR)$(SCRIPTDIR)/hebhtml \
|
||||||
|
|
||||||
-mkdir -p $(DESTDIR)$(IMAGEDIR)
|
-mkdir -p $(DESTDIR)$(IMAGEDIR)
|
||||||
cp rem-default.css *.png $(DESTDIR)$(IMAGEDIR)
|
cp calendar.css rem-default.css *.png $(DESTDIR)$(IMAGEDIR)
|
||||||
chmod 644 $(DESTDIR)$(IMAGEDIR)/rem-default.css $(DESTDIR)$(IMAGEDIR)/*.png
|
chmod 644 $(DESTDIR)$(IMAGEDIR)/calendar.css $(DESTDIR)$(IMAGEDIR)/rem-default.css $(DESTDIR)$(IMAGEDIR)/*.png
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[moondate(0)] SPECIAL MOON 0
|
REM [moondate(0)] SPECIAL MOON 0
|
||||||
[moondate(1)] SPECIAL MOON 1
|
REM [moondate(1)] SPECIAL MOON 1
|
||||||
[moondate(2)] SPECIAL MOON 2
|
REM [moondate(2)] SPECIAL MOON 2
|
||||||
[moondate(3)] SPECIAL MOON 3
|
REM [moondate(3)] SPECIAL MOON 3
|
||||||
REM Monday SPECIAL WEEK (W[weekno()])
|
REM Monday SPECIAL WEEK (W[weekno()])
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ export REMIND
|
|||||||
REM2PS=%REM2PS%
|
REM2PS=%REM2PS%
|
||||||
export REM2PS
|
export REM2PS
|
||||||
|
|
||||||
|
# Set REM2PDF to the full pathname of the rem2pdf executable
|
||||||
|
REM2PDF=%REM2PDF%
|
||||||
|
export REM2PDF
|
||||||
|
|
||||||
#########################
|
#########################
|
||||||
#
|
#
|
||||||
# Don't change anything after this.
|
# Don't change anything after this.
|
||||||
@@ -56,6 +60,10 @@ case "$1" in
|
|||||||
exec $DIR/calps
|
exec $DIR/calps
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
calpdf)
|
||||||
|
exec $DIR/calpdf
|
||||||
|
;;
|
||||||
|
|
||||||
moon)
|
moon)
|
||||||
exec $DIR/moon
|
exec $DIR/moon
|
||||||
;;
|
;;
|
||||||
@@ -64,6 +72,10 @@ case "$1" in
|
|||||||
exec $DIR/hebps
|
exec $DIR/hebps
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
hebpdf)
|
||||||
|
exec $DIR/hebpdf
|
||||||
|
;;
|
||||||
|
|
||||||
hebhtml)
|
hebhtml)
|
||||||
if [ "$2" = "" -o "$3" = "" ] ; then
|
if [ "$2" = "" -o "$3" = "" ] ; then
|
||||||
exec $DIR/hebhtml
|
exec $DIR/hebhtml
|
||||||
|
|||||||
41
www/calendar.css
Normal file
41
www/calendar.css
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
html, body {
|
||||||
|
padding: 0px;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
font-family: "Open Sans", Arial, sans-serif
|
||||||
|
background: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
font-family: inherit;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, .h1 {
|
||||||
|
font-size: 1.75rem; }
|
||||||
|
|
||||||
|
h2, .h2 {
|
||||||
|
font-size: 1.5rem; }
|
||||||
|
|
||||||
|
h3, .h3 {
|
||||||
|
font-size: 1.25rem; }
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #1a0dab;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #1a0dab;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #ff0000;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
<HTML>
|
<HTML>
|
||||||
<!-- Sample HTML file with links to the calendar stuff -->
|
<!-- Sample HTML file with links to the calendar stuff -->
|
||||||
<HEAD>
|
<HEAD>
|
||||||
<TITLE>Remind Calendar Server</TITLE>
|
<TITLE>Remind Calendar Server</TITLE>
|
||||||
|
<LINK rel="stylesheet" href="%IMAGEBASE%/calendar.css">
|
||||||
</HEAD>
|
</HEAD>
|
||||||
|
|
||||||
<BODY>
|
<BODY>
|
||||||
@@ -15,10 +16,14 @@ Sunset Information</a><P>
|
|||||||
Moon Phase Information</a><P>
|
Moon Phase Information</a><P>
|
||||||
<a HREF="%CGIDIR%/cal_dispatch?calps">
|
<a HREF="%CGIDIR%/cal_dispatch?calps">
|
||||||
Blank PostScript Calendar</a> (Approximately 20kB)<P>
|
Blank PostScript Calendar</a> (Approximately 20kB)<P>
|
||||||
|
<a HREF="%CGIDIR%/cal_dispatch?calpdf">
|
||||||
|
Blank PDF Calendar</a> (Approximately 15kB)<P>
|
||||||
<a HREF="%CGIDIR%/cal_dispatch?hebdate">
|
<a HREF="%CGIDIR%/cal_dispatch?hebdate">
|
||||||
Today's Hebrew Date</a><P>
|
Today's Hebrew Date</a><P>
|
||||||
<a HREF="%CGIDIR%/cal_dispatch?hebps">
|
<a HREF="%CGIDIR%/cal_dispatch?hebps">
|
||||||
PostScript Calendar with Jewish Holidays</a> (Approximately 35 kB)<P>
|
PostScript Calendar with Jewish Holidays</a> (Approximately 35 kB)<P>
|
||||||
|
<a HREF="%CGIDIR%/cal_dispatch?hebpdf">
|
||||||
|
PDF Calendar with Jewish Holidays</a> (Approximately 20 kB)<P>
|
||||||
<a HREF="%CGIDIR%/cal_dispatch?hebhtml">
|
<a HREF="%CGIDIR%/cal_dispatch?hebhtml">
|
||||||
HTML Calendar with Jewish Holidays</a>
|
HTML Calendar with Jewish Holidays</a>
|
||||||
<HR>
|
<HR>
|
||||||
|
|||||||
11
www/calpdf
Normal file
11
www/calpdf
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# PostScript calendar shell script
|
||||||
|
#
|
||||||
|
# This file is part of REMIND.
|
||||||
|
# Copyright (C) 1992-2018 by Dianne Skoll
|
||||||
|
|
||||||
|
echo "Content-type: application/pdf"
|
||||||
|
echo
|
||||||
|
|
||||||
|
$REMIND -p $DIR/blank.rem | $REM2PDF -e -c3 -l
|
||||||
|
exit 0
|
||||||
@@ -11,6 +11,7 @@ cat <<EOM
|
|||||||
<HTML>
|
<HTML>
|
||||||
<HEAD>
|
<HEAD>
|
||||||
<TITLE>Hebrew date</TITLE>
|
<TITLE>Hebrew date</TITLE>
|
||||||
|
<LINK rel="stylesheet" href="%IMAGEBASE%/calendar.css">
|
||||||
</HEAD>
|
</HEAD>
|
||||||
<BODY>
|
<BODY>
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ IF !$PSCAL
|
|||||||
|
|
||||||
FSET msgsuffix(x) "<P>"
|
FSET msgsuffix(x) "<P>"
|
||||||
|
|
||||||
MSG The Hebrew date for today, %d %m, %y, is [_hstr(today())]. %
|
REM MSG The Hebrew date for today, %d %m, %y, is [_hstr(today())]. %
|
||||||
MSG And the Hebrew date for tomorrow is [_hstr(today()+1)]. %
|
REM MSG And the Hebrew date for tomorrow is [_hstr(today()+1)]. %
|
||||||
|
|
||||||
fset msgprefix(x) iif($NumTrig==OldTrig, "<H2>Upcoming Holidays</H2>"+char(13,10),"")
|
fset msgprefix(x) iif($NumTrig==OldTrig, "<H2>Upcoming Holidays</H2>"+char(13,10),"")
|
||||||
set oldtrig $numtrig
|
set oldtrig $numtrig
|
||||||
@@ -51,40 +51,40 @@ FSET _PastSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, \
|
|||||||
SET InIsrael VALUE("InIsrael", 0)
|
SET InIsrael VALUE("InIsrael", 0)
|
||||||
SET Reform VALUE("Reform", 0)
|
SET Reform VALUE("Reform", 0)
|
||||||
|
|
||||||
[_h(1, "Tishrey")] ++12 MSG %"Rosh Hashana 1%" is %b.
|
REM [_h(1, "Tishrey")] ++12 MSG %"Rosh Hashana 1%" is %b.
|
||||||
|
|
||||||
# No RH-2 or Tzom Gedalia in Reform
|
# No RH-2 or Tzom Gedalia in Reform
|
||||||
IF !Reform
|
IF !Reform
|
||||||
[_h(2, "Tishrey")] ++12 MSG %"Rosh Hashana 2%" is %b.
|
REM [_h(2, "Tishrey")] ++12 MSG %"Rosh Hashana 2%" is %b.
|
||||||
[_PastSat(3, "Tishrey")] ++12 MSG %"Tzom Gedalia%" is %b.
|
REM [_PastSat(3, "Tishrey")] ++12 MSG %"Tzom Gedalia%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(10, "Tishrey")] ++12 MSG %"Yom Kippur%" is %b.
|
REM [_h(10, "Tishrey")] ++12 MSG %"Yom Kippur%" is %b.
|
||||||
[_h(15, "Tishrey")] ++12 MSG %"Sukkot 1%" is %b.
|
REM [_h(15, "Tishrey")] ++12 MSG %"Sukkot 1%" is %b.
|
||||||
|
|
||||||
IF !InIsrael
|
IF !InIsrael
|
||||||
[_h(16, "Tishrey")] MSG %"Sukkot 2%"
|
REM [_h(16, "Tishrey")] MSG %"Sukkot 2%"
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(21, "Tishrey")] ++12 MSG %"Hoshana Rabba%" is %b.
|
REM [_h(21, "Tishrey")] ++12 MSG %"Hoshana Rabba%" is %b.
|
||||||
[_h(22, "Tishrey")] ++12 MSG %"Shemini Atzeret%" is %b.
|
REM [_h(22, "Tishrey")] ++12 MSG %"Shemini Atzeret%" is %b.
|
||||||
|
|
||||||
IF InIsrael
|
IF InIsrael
|
||||||
[_h(22, "Tishrey")] ++12 MSG %"Simchat Torah%" is %b.
|
REM [_h(22, "Tishrey")] ++12 MSG %"Simchat Torah%" is %b.
|
||||||
ELSE
|
ELSE
|
||||||
[_h(23, "Tishrey")] ++12 MSG %"Simchat Torah%" is %b.
|
REM [_h(23, "Tishrey")] ++12 MSG %"Simchat Torah%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
# Because Kislev can change length, we must be more careful about Chanukah
|
# Because Kislev can change length, we must be more careful about Chanukah
|
||||||
FSET _chan(x) TRIGGER(HEBDATE(24, "Kislev", today()-9)+x)
|
FSET _chan(x) TRIGGER(HEBDATE(24, "Kislev", today()-9)+x)
|
||||||
[_chan(1)] ++12 MSG %"Chanukah 1%" is %b.
|
REM [_chan(1)] ++12 MSG %"Chanukah 1%" is %b.
|
||||||
[_chan(2)] MSG %"Chanukah 2%"
|
REM [_chan(2)] MSG %"Chanukah 2%"
|
||||||
[_chan(3)] MSG %"Chanukah 3%"
|
REM [_chan(3)] MSG %"Chanukah 3%"
|
||||||
[_chan(4)] MSG %"Chanukah 4%"
|
REM [_chan(4)] MSG %"Chanukah 4%"
|
||||||
[_chan(5)] MSG %"Chanukah 5%"
|
REM [_chan(5)] MSG %"Chanukah 5%"
|
||||||
[_chan(6)] MSG %"Chanukah 6%"
|
REM [_chan(6)] MSG %"Chanukah 6%"
|
||||||
[_chan(7)] MSG %"Chanukah 7%"
|
REM [_chan(7)] MSG %"Chanukah 7%"
|
||||||
[_chan(8)] MSG %"Chanukah 8%"
|
REM [_chan(8)] MSG %"Chanukah 8%"
|
||||||
|
|
||||||
# Not sure about Reform's position on the next one.
|
# Not sure about Reform's position on the next one.
|
||||||
IF !Reform
|
IF !Reform
|
||||||
@@ -92,8 +92,8 @@ IF !Reform
|
|||||||
REM [_PastSat(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
|
REM [_PastSat(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(15, "Shvat")] ++12 MSG %"Tu B'Shvat%" is %b.
|
REM [_h(15, "Shvat")] ++12 MSG %"Tu B'Shvat%" is %b.
|
||||||
[_h(15, "Adar A")] ++12 MSG %"Purim Katan%" is %b.
|
REM [_h(15, "Adar A")] ++12 MSG %"Purim Katan%" is %b.
|
||||||
|
|
||||||
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
|
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
|
||||||
IF WKDAYNUM(_h2(13, "Adar")) != 6
|
IF WKDAYNUM(_h2(13, "Adar")) != 6
|
||||||
@@ -101,41 +101,41 @@ IF WKDAYNUM(_h2(13, "Adar")) != 6
|
|||||||
ELSE
|
ELSE
|
||||||
REM [TRIGGER(_h2(11, "Adar"))] ++12 MSG %"Fast of Esther%" is %b.
|
REM [TRIGGER(_h2(11, "Adar"))] ++12 MSG %"Fast of Esther%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
[_h(14, "Adar")] ++12 MSG %"Purim%" is %b.
|
REM [_h(14, "Adar")] ++12 MSG %"Purim%" is %b.
|
||||||
[_h(15, "Nisan")] ++12 MSG %"Pesach%" is %b.
|
REM [_h(15, "Nisan")] ++12 MSG %"Pesach%" is %b.
|
||||||
|
|
||||||
IF !InIsrael
|
IF !InIsrael
|
||||||
[_h(16, "Nisan")] MSG %"Pesach 2%" is %b.
|
REM [_h(16, "Nisan")] MSG %"Pesach 2%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(21, "Nisan")] MSG %"Pesach 7%" is %b.
|
REM [_h(21, "Nisan")] MSG %"Pesach 7%" is %b.
|
||||||
|
|
||||||
IF !InIsrael && !Reform
|
IF !InIsrael && !Reform
|
||||||
[_h(22, "Nisan")] MSG %"Pesach 8%" is %b.
|
REM [_h(22, "Nisan")] MSG %"Pesach 8%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(27, "Nisan")] ++12 MSG %"Yom HaShoah%" is %b.
|
REM [_h(27, "Nisan")] ++12 MSG %"Yom HaShoah%" is %b.
|
||||||
[_h(4, "Iyar")] ++12 MSG %"Yom HaZikaron%" is %b.
|
REM [_h(4, "Iyar")] ++12 MSG %"Yom HaZikaron%" is %b.
|
||||||
[_h(5, "Iyar")] ++12 MSG %"Yom Ha'atzmaut%" is %b.
|
REM [_h(5, "Iyar")] ++12 MSG %"Yom Ha'atzmaut%" is %b.
|
||||||
|
|
||||||
# Not sure about Reform's position on Lag B'Omer
|
# Not sure about Reform's position on Lag B'Omer
|
||||||
IF !Reform
|
IF !Reform
|
||||||
[_h(18, "Iyar")] ++12 MSG %"Lag B'Omer%" is %b.
|
REM [_h(18, "Iyar")] ++12 MSG %"Lag B'Omer%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
[_h(28, "Iyar")] ++12 MSG %"Yom Yerushalayim%" is %b.
|
REM [_h(28, "Iyar")] ++12 MSG %"Yom Yerushalayim%" is %b.
|
||||||
[_h(6, "Sivan")] ++12 MSG %"Shavuot%" is %b.
|
REM [_h(6, "Sivan")] ++12 MSG %"Shavuot%" is %b.
|
||||||
|
|
||||||
IF !InIsrael && !Reform
|
IF !InIsrael && !Reform
|
||||||
[_h(7, "Sivan")] MSG %"Shavuot 2%" is %b.
|
REM [_h(7, "Sivan")] MSG %"Shavuot 2%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
# Fairly sure Reform Jews don't observe the next two
|
# Fairly sure Reform Jews don't observe the next two
|
||||||
IF !Reform
|
IF !Reform
|
||||||
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
|
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
|
||||||
# fall on a Saturday
|
# fall on a Saturday
|
||||||
[_PastSat(17, "Tamuz")] ++12 MSG %"Tzom Tammuz%" is %b.
|
REM [_PastSat(17, "Tamuz")] ++12 MSG %"Tzom Tammuz%" is %b.
|
||||||
[_PastSat(9, "Av")] ++12 MSG %"Tish'a B'Av%" is %b.
|
REM [_PastSat(9, "Av")] ++12 MSG %"Tish'a B'Av%" is %b.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
fset msgprefix(x) ""
|
fset msgprefix(x) ""
|
||||||
@@ -165,13 +165,15 @@ ENDIF
|
|||||||
IF !$PSCAL
|
IF !$PSCAL
|
||||||
REM 20 ++40 msg Also available: <a HREF="%CGIDIR%/cal_dispatch?hebps">a PostScript calendar</a> (about 35KB) for %m %y, complete with Hebrew dates, Jewish holidays, and moon phases for [$Location].
|
REM 20 ++40 msg Also available: <a HREF="%CGIDIR%/cal_dispatch?hebps">a PostScript calendar</a> (about 35KB) for %m %y, complete with Hebrew dates, Jewish holidays, and moon phases for [$Location].
|
||||||
REM 20 ++40 msg And: <a HREF="%CGIDIR%/cal_dispatch?hebhtml">an HTML version</a> of the above.
|
REM 20 ++40 msg And: <a HREF="%CGIDIR%/cal_dispatch?hebhtml">an HTML version</a> of the above.
|
||||||
|
REM 20 ++40 msg And: <a HREF="%CGIDIR%/cal_dispatch?hebpdf">a PDF version</a> of the above.
|
||||||
ELSE
|
ELSE
|
||||||
[trigger(moondate(0))] SPECIAL MOON 0
|
REM [moondate(0)] SPECIAL MOON 0
|
||||||
[trigger(moondate(1))] SPECIAL MOON 1
|
REM [moondate(1)] SPECIAL MOON 1
|
||||||
[trigger(moondate(2))] SPECIAL MOON 2
|
REM [moondate(2)] SPECIAL MOON 2
|
||||||
[trigger(moondate(3))] SPECIAL MOON 3
|
REM [moondate(3)] SPECIAL MOON 3
|
||||||
REM PS Border Border moveto /DayFont findfont 10 scalefont setfont ([hebday(today())] [hebmon(today())]) show
|
REM PS Border Border moveto /DayFont findfont 10 scalefont setfont ([hebday($U)] [hebmon($U)]) show
|
||||||
REM SPECIAL HTML <P>[hebday(today())] [hebmon(today())]</P>
|
REM SPECIAL HTML <P>[hebday($U)] [hebmon($U)]</P>
|
||||||
|
REM SPECIAL PANGO @4,-1 <span size="6400"><i>[hebday($U)] [hebmon($U)]</i></span>
|
||||||
|
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
|
|||||||
17
www/hebpdf
Normal file
17
www/hebpdf
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Hebrew PostScript calendar shell script
|
||||||
|
#
|
||||||
|
# This file is part of REMIND.
|
||||||
|
# Copyright (C) 1992-2018 by Dianne Skoll
|
||||||
|
|
||||||
|
# Figure out the month: If day <= 20, use this month; otherwise, use
|
||||||
|
# next month.
|
||||||
|
echo "Content-type: application/pdf"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
$REMIND - <<EOR
|
||||||
|
BANNER %
|
||||||
|
REM 20 ++40 RUN $REMIND -iHTML=0 -p $DIR/hebdate.rem %m %y | $REM2PDF -e -c3 -l
|
||||||
|
EOR
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -9,6 +9,7 @@ banner %
|
|||||||
|
|
||||||
MSG <HEAD>%
|
MSG <HEAD>%
|
||||||
MSG <TITLE>Moon over [$Location]</TITLE>%
|
MSG <TITLE>Moon over [$Location]</TITLE>%
|
||||||
|
MSG <LINK rel="stylesheet" href="%IMAGEBASE%/calendar.css">%
|
||||||
MSG </HEAD>%
|
MSG </HEAD>%
|
||||||
|
|
||||||
MSG <BODY>
|
MSG <BODY>
|
||||||
|
|||||||
@@ -1,341 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
class Remind
|
|
||||||
{
|
|
||||||
# For validating commands we send to popen
|
|
||||||
function is_valid_day($d) {
|
|
||||||
return (preg_match('/^\d+$/', $d)) &&
|
|
||||||
$d >= 1 && $d <= 31;
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_valid_month($m) {
|
|
||||||
return
|
|
||||||
($m == 'January') ||
|
|
||||||
($m == 'February') ||
|
|
||||||
($m == 'March') ||
|
|
||||||
($m == 'April') ||
|
|
||||||
($m == 'May') ||
|
|
||||||
($m == 'June') ||
|
|
||||||
($m == 'July') ||
|
|
||||||
($m == 'August') ||
|
|
||||||
($m == 'September') ||
|
|
||||||
($m == 'October') ||
|
|
||||||
($m == 'November') ||
|
|
||||||
($m == 'December');
|
|
||||||
}
|
|
||||||
|
|
||||||
function is_valid_year($y) {
|
|
||||||
return preg_match('/^\d\d\d\d$/', $y) &&
|
|
||||||
$y >= 1900;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function get_el(&$array, $i)
|
|
||||||
{
|
|
||||||
if (!array_key_exists($i, $array)) return null;
|
|
||||||
return $array[$i];
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_elem($array, $indexes)
|
|
||||||
{
|
|
||||||
foreach ($indexes as $i) {
|
|
||||||
if (!is_array($array)) return null;
|
|
||||||
if (!array_key_exists($i, $array)) return null;
|
|
||||||
$array = $array[$i];
|
|
||||||
}
|
|
||||||
return $array;
|
|
||||||
}
|
|
||||||
|
|
||||||
function munge_entry($day, &$results, &$specials, &$options, $str, &$e) {
|
|
||||||
return htmlspecialchars($str);
|
|
||||||
}
|
|
||||||
|
|
||||||
function format_entry($day, &$results, &$specials, &$options, &$e) {
|
|
||||||
$special = $this->get_el($e, 'special');
|
|
||||||
$body = $this->get_el($e, 'body');
|
|
||||||
|
|
||||||
if ($body === null) $body = '';
|
|
||||||
if ($special === null || $special == '*') {
|
|
||||||
return $this->munge_entry($day, $results, $specials, $options, $body, $e);
|
|
||||||
}
|
|
||||||
if ($special == 'COLOR' || $special == 'COLOUR') {
|
|
||||||
if (preg_match('/^(\d+)\s+(\d+)\s+(\d+)\s+(.*)/', $body, $matches)) {
|
|
||||||
return sprintf('<span style="color: #%02x%02x%02x">%s</span>',
|
|
||||||
$matches[1] % 255,
|
|
||||||
$matches[2] % 255,
|
|
||||||
$matches[3] % 255,
|
|
||||||
$this->munge_entry($day, $results, $specials, $options, $matches[4], $e));
|
|
||||||
}
|
|
||||||
return 'Bad COLOR spec: ' . htmlspecialchars($body);
|
|
||||||
}
|
|
||||||
|
|
||||||
# HTML is passed through un-munged.
|
|
||||||
if ($special == 'HTML') return $body;
|
|
||||||
|
|
||||||
# Ignore unknown specials
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function format_entries($day, &$results, &$specials, &$options, &$entries) {
|
|
||||||
$html = '';
|
|
||||||
foreach ($entries as $e) {
|
|
||||||
$html .= '<div class="rem-entry">' . $this->format_entry($day, $results, $specials, $options, $e) . '</div>';
|
|
||||||
}
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function do_one_day($day, &$results, &$specials, &$options) {
|
|
||||||
$class = $this->get_elem($specials, array('HTMLCLASS', $day, 0, 'body'));
|
|
||||||
$shade = $this->get_elem($specials, array('SHADE', $day, 0, 'body'));
|
|
||||||
$moon = $this->get_elem($specials, array('MOON', $day, 0, 'body'));
|
|
||||||
|
|
||||||
if ($class === null) $class = 'rem-cell';
|
|
||||||
$bg = '';
|
|
||||||
if ($shade !== null) {
|
|
||||||
if (preg_match('/(\d+)\s+(\d+)\s+(\d+)/', $shade, $matches)) {
|
|
||||||
if ($matches[1] <= 255 && $matches[2] <= 255 && $matches[3] <= 255) {
|
|
||||||
$bg = sprintf(' style="background: #%02x%02x%02x"',
|
|
||||||
$matches[1], $matches[2], $matches[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$html = "<td class=\"$class\"$bg>";
|
|
||||||
|
|
||||||
$week = $this->get_elem($specials, array('WEEK', $day, 0, 'body'));
|
|
||||||
if ($week === null) {
|
|
||||||
$week = '';
|
|
||||||
} else {
|
|
||||||
$week = ' ' . $week;
|
|
||||||
}
|
|
||||||
|
|
||||||
$moon_html = '';
|
|
||||||
if ($moon !== null) {
|
|
||||||
$phase = -1;
|
|
||||||
if (preg_match('/(\d+)\s+(\S+)\s+(\S+)\s+(.*)$/', $moon, $matches)) {
|
|
||||||
$phase = $matches[1];
|
|
||||||
$moonsize = $matches[2];
|
|
||||||
$fontsize = $matches[3];
|
|
||||||
$msg = $matches[4];
|
|
||||||
} elseif (preg_match('/(\d+)/', $moon, $matches)) {
|
|
||||||
$phase = $matches[1];
|
|
||||||
$msg = '';
|
|
||||||
}
|
|
||||||
if ($phase >= 0) {
|
|
||||||
if ($phase == 0) {
|
|
||||||
$img = 'newmoon.png';
|
|
||||||
$title = 'New Moon';
|
|
||||||
$alt = 'new';
|
|
||||||
} elseif ($phase == 1) {
|
|
||||||
$img = 'firstquarter.png';
|
|
||||||
$title = 'First Quarter';
|
|
||||||
$alt = '1st';
|
|
||||||
} elseif ($phase == 2) {
|
|
||||||
$img = 'fullmoon.png';
|
|
||||||
$alt = 'full';
|
|
||||||
$title = 'Full Moon';
|
|
||||||
} else {
|
|
||||||
$img = 'lastquarter.png';
|
|
||||||
$alt = 'last';
|
|
||||||
$title = 'Last Quarter';
|
|
||||||
}
|
|
||||||
$base = rtrim($this->get_el($options, 'imgbase'), '/');
|
|
||||||
if ($base !== null) {
|
|
||||||
$img = $base . '/' . $img;
|
|
||||||
}
|
|
||||||
$moon_html = '<div class="rem-moon">' . "<img width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">" . htmlspecialchars($msg) . '</div>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Day number
|
|
||||||
$html .= $moon_html . '<div class="rem-daynumber">' . $day . $week . '</div>';
|
|
||||||
|
|
||||||
# And the entries
|
|
||||||
$entries = $this->get_elem($results, array('entries', $day));
|
|
||||||
if (is_array($entries) && count($entries) > 0) {
|
|
||||||
$html .= '<div class="rem-entries">';
|
|
||||||
$html .= $this->format_entries($day, $results, $specials, $options, $entries);
|
|
||||||
$html .= '</div>';
|
|
||||||
}
|
|
||||||
$html .= "</td>\n";
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function small_calendar($results, $month, $monlen, $first_col, $which, &$options)
|
|
||||||
{
|
|
||||||
$monday_first = $results['monday_flag'];
|
|
||||||
if ($monday_first) {
|
|
||||||
$first_col--;
|
|
||||||
if ($first_col < 0) {
|
|
||||||
$first_col = 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$html = "<td class=\"rem-small-calendar\">\n<table class=\"rem-sc-table\">\n<caption class=\"rem-sc-caption\">";
|
|
||||||
# TODO: URL for small calendar
|
|
||||||
$html .= $month;
|
|
||||||
$html .= "</caption>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
function generate_html(&$results, &$specials, &$options)
|
|
||||||
{
|
|
||||||
$monday_first = $results['monday_flag'];
|
|
||||||
$first_col = $results['first_day'];
|
|
||||||
if ($monday_first) {
|
|
||||||
$first_col--;
|
|
||||||
if ($first_col < 0) $first_col = 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
$last_col = ($first_col + $results['days_in_mon'] -1) % 7;
|
|
||||||
|
|
||||||
$html = '<table class="rem-cal"><caption class="rem-cal-caption">' .
|
|
||||||
htmlspecialchars($results['month']) . ' ' . htmlspecialchars($results['year']) .
|
|
||||||
"</caption>\n";
|
|
||||||
|
|
||||||
$html .= '<tr class="rem-cal-hdr-row">';
|
|
||||||
if (!$monday_first) $html .= '<th class="rem-cal-hdr">' . htmlspecialchars($results['day_names'][0]) . '</th>';
|
|
||||||
for ($i=1; $i<7; $i++) $html .= '<th class="rem-cal-hdr">' . htmlspecialchars($results['day_names'][$i]) . '</th>';
|
|
||||||
if ($monday_first) $html .= '<th class="rem-cal-hdr">' . htmlspecialchars($results['day_names'][0]) . '</th>';
|
|
||||||
$html .= "</tr>\n";
|
|
||||||
|
|
||||||
# Do the leading empty columns
|
|
||||||
for ($col=0; $col < $first_col; $col++) {
|
|
||||||
if ($col == 0) $html .= '<tr class="rem-cal-body-row">';
|
|
||||||
$html .= '<td class="rem-empty"> </td>';
|
|
||||||
}
|
|
||||||
|
|
||||||
for ($day=1; $day <= $results['days_in_mon']; $day++) {
|
|
||||||
if ($col == 0) $html .= '<tr class="rem-cal-body-row">';
|
|
||||||
$col++;
|
|
||||||
$html .= $this->do_one_day($day, $results, $specials, $options);
|
|
||||||
if ($col == 7) {
|
|
||||||
$html .= "</tr>\n";
|
|
||||||
$col = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($col) {
|
|
||||||
while ($col++ < 7) {
|
|
||||||
$html .= '<td class="rem-empty"> </td>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$html .= "</tr>\n";
|
|
||||||
|
|
||||||
$html .= "</table>\n";
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
function parse_remind_output ($fp)
|
|
||||||
{
|
|
||||||
while(1) {
|
|
||||||
$line = fgets($fp);
|
|
||||||
if ($line === false) break;
|
|
||||||
$line = trim($line);
|
|
||||||
if ($line == '# rem2ps begin') break;
|
|
||||||
}
|
|
||||||
if ($line === false) {
|
|
||||||
return array('success' => 0,
|
|
||||||
'error' => 'Could not find any Rem2PS data');
|
|
||||||
}
|
|
||||||
|
|
||||||
$line = fgets($fp);
|
|
||||||
if ($line === false) {
|
|
||||||
return array('success' => 0,
|
|
||||||
'error' => 'Unexpected end-of-file');
|
|
||||||
}
|
|
||||||
|
|
||||||
$line = trim($line);
|
|
||||||
list($month, $year, $days_in_mon, $first_day, $monday_flag) = explode(' ', $line);
|
|
||||||
$retval = array('month' => $month,
|
|
||||||
'year' => $year,
|
|
||||||
'days_in_mon' => $days_in_mon,
|
|
||||||
'first_day' => $first_day,
|
|
||||||
'monday_flag' => $monday_flag);
|
|
||||||
|
|
||||||
$line = fgets($fp);
|
|
||||||
if ($line === false) {
|
|
||||||
return array('success' => 0,
|
|
||||||
'error' => 'Unexpected end-of-file');
|
|
||||||
}
|
|
||||||
|
|
||||||
$line = trim($line);
|
|
||||||
$retval['day_names'] = explode(' ', $line);
|
|
||||||
|
|
||||||
$line = fgets($fp);
|
|
||||||
if ($line === false) {
|
|
||||||
return array('success' => 0,
|
|
||||||
'error' => 'Unexpected end-of-file');
|
|
||||||
}
|
|
||||||
$line = trim($line);
|
|
||||||
|
|
||||||
list($m, $n) = explode(' ', $line);
|
|
||||||
$retval['prev'] = array('month' => $m, 'days' => $n);
|
|
||||||
|
|
||||||
$line = fgets($fp);
|
|
||||||
if ($line === false) {
|
|
||||||
return array('success' => 0,
|
|
||||||
'error' => 'Unexpected end-of-file');
|
|
||||||
}
|
|
||||||
$line = trim($line);
|
|
||||||
|
|
||||||
list($m, $n) = explode(' ', $line);
|
|
||||||
$retval['next'] = array('month' => $m, 'days' => $n);
|
|
||||||
|
|
||||||
$line_info = 0;
|
|
||||||
|
|
||||||
$entries = array();
|
|
||||||
$specials = array();
|
|
||||||
while (1) {
|
|
||||||
$line = fgets($fp);
|
|
||||||
if ($line === false) break;
|
|
||||||
$line = trim($line);
|
|
||||||
if ($line == '# rem2ps end') break;
|
|
||||||
if (strpos($line, '# fileinfo ') === 0) {
|
|
||||||
list($lno, $fname) = explode(' ', substr($line, 11), 2);
|
|
||||||
$lineinfo = array('file' => $fname, 'line' => $lno);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
list($date, $special, $tags, $duration, $time, $body) = explode(' ', $line, 6);
|
|
||||||
list($y, $m, $d) = explode('/', $date);
|
|
||||||
$d = preg_replace('/^0(.)/', '$1', $d);
|
|
||||||
$m = preg_replace('/^0(.)/', '$1', $m);
|
|
||||||
$entry = array('day' => $d,
|
|
||||||
'month' => $m,
|
|
||||||
'year' => $y,
|
|
||||||
'special' => $special,
|
|
||||||
'tags' => $tags,
|
|
||||||
'duration' => $duration,
|
|
||||||
'time' => $time,
|
|
||||||
'body' => $body);
|
|
||||||
if (is_array($lineinfo)) {
|
|
||||||
$entry['line'] = $lineinfo['line'];
|
|
||||||
$entry['file'] = $lineinfo['file'];
|
|
||||||
$lineinfo = 0;
|
|
||||||
}
|
|
||||||
if ($special != '*' && $special != 'COLOR' && $special != 'COLOUR' && $special != 'HTML') {
|
|
||||||
if (!array_key_exists($special, $specials)) {
|
|
||||||
$specials[$special] = array();
|
|
||||||
}
|
|
||||||
if (!array_key_exists($d, $specials[$special])) {
|
|
||||||
$specials[$special][$d] = array();
|
|
||||||
}
|
|
||||||
$specials[$special][$d][] = $entry;
|
|
||||||
} else {
|
|
||||||
if (!array_key_exists($d, $entries)) {
|
|
||||||
$entries[$d] = array();
|
|
||||||
}
|
|
||||||
$entries[$d][] = $entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
$retval['entries'] = $entries;
|
|
||||||
return array('success' => 1, 'results' => $retval, 'specials' => $specials);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$fp = popen('rem -p -l', 'r');
|
|
||||||
$r = new Remind;
|
|
||||||
$ans = $r->parse_remind_output($fp);
|
|
||||||
pclose($fp);
|
|
||||||
print_r($ans);
|
|
||||||
$options = array();
|
|
||||||
#print $r->generate_html($ans['results'], $ans['specials'], $options);
|
|
||||||
|
|
||||||
?>
|
|
||||||
@@ -8,6 +8,7 @@ set now now()
|
|||||||
banner %
|
banner %
|
||||||
MSG <HEAD>%
|
MSG <HEAD>%
|
||||||
MSG <TITLE>Sunrise in [$Location]</TITLE>%
|
MSG <TITLE>Sunrise in [$Location]</TITLE>%
|
||||||
|
MSG <LINK rel="stylesheet" href="%IMAGEBASE%/calendar.css">%
|
||||||
MSG </HEAD>%
|
MSG </HEAD>%
|
||||||
|
|
||||||
MSG <BODY>
|
MSG <BODY>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ banner %
|
|||||||
|
|
||||||
MSG <HEAD>%
|
MSG <HEAD>%
|
||||||
MSG <TITLE>Sunset in [$Location]</TITLE>%
|
MSG <TITLE>Sunset in [$Location]</TITLE>%
|
||||||
|
MSG <LINK rel="stylesheet" href="%IMAGEBASE%/calendar.css">%
|
||||||
MSG </HEAD>%
|
MSG </HEAD>%
|
||||||
|
|
||||||
MSG <BODY>
|
MSG <BODY>
|
||||||
|
|||||||
Reference in New Issue
Block a user