Compare commits
465 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
daf09d9d4e | ||
|
|
511cdb2784 | ||
|
|
a567a9b777 | ||
|
|
05bc3af03d | ||
|
|
7a048d1702 | ||
|
|
8d7f9bcb8b | ||
|
|
9fd8b0f890 | ||
|
|
86873d0725 | ||
|
|
b22438b489 | ||
|
|
683b38a7ab | ||
|
|
d6b4fdd6d3 | ||
|
|
c996649954 | ||
|
|
d59ad77893 | ||
|
|
e637c20dee | ||
|
|
19dc588319 | ||
|
|
dc53ef2e71 | ||
|
|
e51d7f3c6d | ||
|
|
5a7e86e443 | ||
|
|
7f4edae006 | ||
|
|
2f4e1462e3 | ||
|
|
54f5d81a8c | ||
|
|
d33c27289a | ||
|
|
1675fdb499 | ||
|
|
9321109691 | ||
|
|
e6a4f939a3 | ||
|
|
c7ae214853 | ||
|
|
68a9cc047e | ||
|
|
1f2b25f852 | ||
|
|
20040c8857 | ||
|
|
ac64b0c11f | ||
|
|
ba47ce7ca8 | ||
|
|
be1ab4ea36 | ||
|
|
13cd9f3d04 | ||
|
|
8e1f82de5f | ||
|
|
8631ad3122 | ||
|
|
90e6aef9d7 | ||
|
|
698190fb72 | ||
|
|
27cfaa9404 | ||
|
|
9f296fe76d | ||
|
|
d0112adb08 | ||
|
|
75f4fe3595 | ||
|
|
211bfbc1e2 | ||
|
|
afaa1841fc | ||
|
|
027662c9c3 | ||
|
|
43e652321b | ||
|
|
83a2216d19 | ||
|
|
82ae568add | ||
|
|
2573003034 | ||
|
|
c33e873577 | ||
|
|
a1d03b8159 | ||
|
|
762530f6ab | ||
|
|
f53a3ecc69 | ||
|
|
1ed60fecee | ||
|
|
c1a12ea4e9 | ||
|
|
0efd235e36 | ||
|
|
c7be8c59f3 | ||
|
|
20bb3eb674 | ||
|
|
cde0e5883e | ||
|
|
0b43099621 | ||
|
|
386f36c3ae | ||
|
|
b391b2129e | ||
|
|
5478673bda | ||
|
|
6295048b3e | ||
|
|
4fa956aa27 | ||
|
|
21cce0e104 | ||
|
|
b14e72ddf7 | ||
|
|
7a34b6e18d | ||
|
|
ddc0e8eb45 | ||
|
|
7648ee6e54 | ||
|
|
2b86c912e3 | ||
|
|
342acedbec | ||
|
|
a83bf495b1 | ||
|
|
899829f1ac | ||
|
|
408a62115e | ||
|
|
430d0990aa | ||
|
|
47d33e7aaf | ||
|
|
12f40cba6d | ||
|
|
ecc0e9609a | ||
|
|
eb35a843c1 | ||
|
|
79289fe6c4 | ||
|
|
cb841adf86 | ||
|
|
724d82e6d2 | ||
|
|
0532910604 | ||
|
|
f4f5552975 | ||
|
|
3e2794548b | ||
|
|
f7b8ee168f | ||
|
|
e3297fe751 | ||
|
|
58ca741a1c | ||
|
|
14dbbc7bb4 | ||
|
|
df55c4032b | ||
|
|
3768155a20 | ||
|
|
2f3b9cadf4 | ||
|
|
2c79a6531a | ||
|
|
be5c856f4b | ||
|
|
712a333f08 | ||
|
|
b753e84c8c | ||
|
|
4b4acaadbb | ||
|
|
8a52f9b67d | ||
|
|
e372606281 | ||
|
|
c443d0a9da | ||
|
|
42c9ae9ea8 | ||
|
|
dac9bb4187 | ||
|
|
812d926f66 | ||
|
|
45831ea69f | ||
|
|
354e1d236b | ||
|
|
ac478039cf | ||
|
|
96f5799e6f | ||
|
|
e21479f696 | ||
|
|
25dc883e15 | ||
|
|
bfb1374ee3 | ||
|
|
cacd8f9792 | ||
|
|
3e9053a3c6 | ||
|
|
5fa357fec2 | ||
|
|
f109c3d696 | ||
|
|
b097ce7279 | ||
|
|
1297854935 | ||
|
|
0a1d0011f6 | ||
|
|
20db1be0a0 | ||
|
|
143f1d6144 | ||
|
|
358f6c9497 | ||
|
|
ca26544be8 | ||
|
|
5ceffddd5b | ||
|
|
8e3ddb96b3 | ||
|
|
377de36b35 | ||
|
|
4395e2f7ed | ||
|
|
1d0cc31b10 | ||
|
|
4b4b2ddcd4 | ||
|
|
3c9b5b786e | ||
|
|
08f1bea6ce | ||
|
|
a2cc5943e0 | ||
|
|
895ac6f0f7 | ||
|
|
759ca0253e | ||
|
|
0ca368c8d9 | ||
|
|
a467cc1b84 | ||
|
|
c65fd826a5 | ||
|
|
bd6f4e1b43 | ||
|
|
169520914f | ||
|
|
a163a0c446 | ||
|
|
295aeb0ed8 | ||
|
|
9b2fdad56c | ||
|
|
7a1184d3c5 | ||
|
|
b036244316 | ||
|
|
5ad5366e8a | ||
|
|
244677e524 | ||
|
|
f5a094a973 | ||
|
|
5681ebdb12 | ||
|
|
664fa5f08f | ||
|
|
14edec5eae | ||
|
|
6adfd2e739 | ||
|
|
34409f7a7d | ||
|
|
7e13d1052c | ||
|
|
eb1998c888 | ||
|
|
543252cbaf | ||
|
|
6df7c59876 | ||
|
|
f780e0afc3 | ||
|
|
310e8d3287 | ||
|
|
ba51bdf258 | ||
|
|
ef88b844fb | ||
|
|
67b96b0a26 | ||
|
|
562da30fb5 | ||
|
|
21175e8cf6 | ||
|
|
80d01f7158 | ||
|
|
90cac447e4 | ||
|
|
04bf5b0a8b | ||
|
|
d667c15b25 | ||
|
|
2123bf4b18 | ||
|
|
429a64f29e | ||
|
|
f39381dd6c | ||
|
|
0a9eb07f6f | ||
|
|
9c287e3fd7 | ||
|
|
cce4b2cb14 | ||
|
|
e49d9f8ab6 | ||
|
|
48cbeb28f4 | ||
|
|
57d5c54559 | ||
|
|
3b2260f67e | ||
|
|
d423a62327 | ||
|
|
ac8da00030 | ||
|
|
77eb7fb99d | ||
|
|
a751149dd3 | ||
|
|
69d45618c6 | ||
|
|
22fa1a28e5 | ||
|
|
f4cc233009 | ||
|
|
1d6e4edd0f | ||
|
|
daffa8cba0 | ||
|
|
2e161a1bc1 | ||
|
|
204bb00060 | ||
|
|
d6029a54aa | ||
|
|
f99b5c5a66 | ||
|
|
2df4119c1a | ||
|
|
d06b4e5dcd | ||
|
|
bf8a25137d | ||
|
|
0f302ad0fc | ||
|
|
e3d6b283c5 | ||
|
|
2e3ed09039 | ||
|
|
37971a3f07 | ||
|
|
2a1960f257 | ||
|
|
350564c304 | ||
|
|
9e2a9fea37 | ||
|
|
3592b43629 | ||
|
|
becf1fc459 | ||
|
|
2bccd058ed | ||
|
|
12c6621051 | ||
|
|
504bc6a875 | ||
|
|
9cfdd0b53f | ||
|
|
d59024f399 | ||
|
|
24e0178d1a | ||
|
|
1ede5775f2 | ||
|
|
a5c9b07052 | ||
|
|
22353d4833 | ||
|
|
7499ada891 | ||
|
|
3f0a4e5c39 | ||
|
|
b8d6472974 | ||
|
|
6358297724 | ||
|
|
4f6dcde980 | ||
|
|
8a7985c48e | ||
|
|
4ddbe54e55 | ||
|
|
ef0bf73a29 | ||
|
|
beda9014d8 | ||
|
|
498a429b2c | ||
|
|
6aa2aa0fb3 | ||
|
|
1bef88fccd | ||
|
|
8308068067 | ||
|
|
8385c7f1b0 | ||
|
|
0537d02fef | ||
|
|
c33a1a3b0b | ||
|
|
fd39999128 | ||
|
|
0aa40094fa | ||
|
|
e3bbbe07be | ||
|
|
5633798d33 | ||
|
|
0e7e1b1b75 | ||
|
|
4d3790bc1a | ||
|
|
2002c7f1f8 | ||
|
|
1be14e99a2 | ||
|
|
78efdaf85f | ||
|
|
0e98a1c656 | ||
|
|
7aa483e201 | ||
|
|
a6dbf05af4 | ||
|
|
8ab78fd8be | ||
|
|
4f119031a4 | ||
|
|
19bdd6c2db | ||
|
|
f1557b8243 | ||
|
|
85f96e2e01 | ||
|
|
47331cd919 | ||
|
|
d9f18ed6a7 | ||
|
|
efa4816371 | ||
|
|
2dc8c63adb | ||
|
|
c3c1781021 | ||
|
|
cd39480a98 | ||
|
|
281a1a206e | ||
|
|
cbff2a7bf2 | ||
|
|
2a08be8fd0 | ||
|
|
0826678209 | ||
|
|
f2e421bfa5 | ||
|
|
ce53a9b91a | ||
|
|
b166b1cf82 | ||
|
|
d09fbb03b2 | ||
|
|
7a835f3b10 | ||
|
|
6b991cdf9c | ||
|
|
018e9d0323 | ||
|
|
f499ae096f | ||
|
|
725e046a15 | ||
|
|
275b1f62b6 | ||
|
|
6e58dea198 | ||
|
|
ad4e62c8c3 | ||
|
|
a5768d55d8 | ||
|
|
7db49971c8 | ||
|
|
45ca6631ac | ||
|
|
d51944f36c | ||
|
|
037c79fb0f | ||
|
|
993373414f | ||
|
|
38a0a9992a | ||
|
|
a82bbe3776 | ||
|
|
a32ba217ba | ||
|
|
d322cf54ac | ||
|
|
b1d07a231d | ||
|
|
97851a08e6 | ||
|
|
8547b30a8f | ||
|
|
405c7d9ed0 | ||
|
|
ac5b641d93 | ||
|
|
06a79989c0 | ||
|
|
671db64436 | ||
|
|
33344cefe6 | ||
|
|
5ef0341537 | ||
|
|
6abca08189 | ||
|
|
35670ce651 | ||
|
|
e230d53d84 | ||
|
|
88537a3471 | ||
|
|
7c9d74da73 | ||
|
|
3b582935ee | ||
|
|
508fafb875 | ||
|
|
6f718f0fe5 | ||
|
|
53acbf2052 | ||
|
|
1606dbbe77 | ||
|
|
adced3ac6c | ||
|
|
14f207140a | ||
|
|
d2da32de6c | ||
|
|
e5d6a36f05 | ||
|
|
68ecfcf876 | ||
|
|
fcb14b9dfe | ||
|
|
6a4b4257a6 | ||
|
|
385b57e269 | ||
|
|
a8e81e3984 | ||
|
|
46c5f0e752 | ||
|
|
454d859fdd | ||
|
|
57134a182c | ||
|
|
5801e143ea | ||
|
|
4e0d0ff98b | ||
|
|
d4ac1849ae | ||
|
|
c16ac1bd8c | ||
|
|
16222ac3bc | ||
|
|
8d88931fb1 | ||
|
|
63f0356e70 | ||
|
|
786b0dee6f | ||
|
|
e7ef9dc295 | ||
|
|
f59461b95d | ||
|
|
566a86b9fd | ||
|
|
8589a3730d | ||
|
|
c05fd366df | ||
|
|
fc9fd1e53c | ||
|
|
a5e6eb9f7c | ||
|
|
a9430fea5f | ||
|
|
828a0d6589 | ||
|
|
32601da748 | ||
|
|
ac50f119cf | ||
|
|
7622ebaa0a | ||
|
|
a586d5cd37 | ||
|
|
edbc88bd19 | ||
|
|
94f99f3414 | ||
|
|
fd4f84349e | ||
|
|
f86350b2ff | ||
|
|
564b72066a | ||
|
|
2890c52090 | ||
|
|
c1d45485c1 | ||
|
|
8b2a69cf8d | ||
|
|
034c1341b3 | ||
|
|
29bbf1a030 | ||
|
|
be6661d6be | ||
|
|
3f876e792c | ||
|
|
f2457b90ff | ||
|
|
e999e9009b | ||
|
|
46326c001b | ||
|
|
b84c2c403c | ||
|
|
861ad72187 | ||
|
|
7dbbc34ccc | ||
|
|
4ea45d1d14 | ||
|
|
c1b9243e2f | ||
|
|
a41c40c7a4 | ||
|
|
318d4547ef | ||
|
|
6f98b60a6a | ||
|
|
baa8f7f3c4 | ||
|
|
6297622072 | ||
|
|
9f3ba0bf2b | ||
|
|
9591dec708 | ||
|
|
ee2d0b7518 | ||
|
|
2d46749c58 | ||
|
|
494664d1b6 | ||
|
|
49686210ae | ||
|
|
ddfa44188b | ||
|
|
73cf93d27b | ||
|
|
60d1a34bf0 | ||
|
|
6f80986801 | ||
|
|
2078f087b2 | ||
|
|
68d110826e | ||
|
|
9fb04c54ae | ||
|
|
d82314594b | ||
|
|
ad169a5248 | ||
|
|
a9bab81226 | ||
|
|
fa63a9ba51 | ||
|
|
1e7a630737 | ||
|
|
de1afce8da | ||
|
|
ac3cb19c26 | ||
|
|
af0479d11d | ||
|
|
0d9c04707f | ||
|
|
c2218f133b | ||
|
|
1ad0645fab | ||
|
|
3c16f6839a | ||
|
|
e8bac1e469 | ||
|
|
b3b69596f4 | ||
|
|
6a7bcb0956 | ||
|
|
f18a0704c1 | ||
|
|
d6f24b7c1e | ||
|
|
e2c9bbf94c | ||
|
|
f53aa4f656 | ||
|
|
a7ab9b8bf8 | ||
|
|
4448271166 | ||
|
|
4861b535a2 | ||
|
|
167f0100c7 | ||
|
|
b0367c7a5c | ||
|
|
4ae8ad52f5 | ||
|
|
dbd64828ab | ||
|
|
158ca882ba | ||
|
|
623ed44608 | ||
|
|
f13b867626 | ||
|
|
ff85325886 | ||
|
|
aa830116ea | ||
|
|
1a4504ba28 | ||
|
|
20365c4627 | ||
|
|
fae8f89ed6 | ||
|
|
a0689999fe | ||
|
|
a42a0ab032 | ||
|
|
b66eb5d3ec | ||
|
|
8b4bc0f56e | ||
|
|
c9d984983f | ||
|
|
47125b051a | ||
|
|
e5e6ff6031 | ||
|
|
9f0aedb608 | ||
|
|
08af33ece5 | ||
|
|
9b421d0b94 | ||
|
|
7bd8d2dd25 | ||
|
|
a7c4879a0a | ||
|
|
8b3585a6b8 | ||
|
|
a223149aee | ||
|
|
9185341b0c | ||
|
|
bf2d707e13 | ||
|
|
f081e5c54d | ||
|
|
18a3db0f31 | ||
|
|
d2c115127d | ||
|
|
c12e7e1b8f | ||
|
|
d3495ab3aa | ||
|
|
b93a7a6195 | ||
|
|
e5519a8498 | ||
|
|
eb2256f873 | ||
|
|
637b137b1c | ||
|
|
e2d14e73bf | ||
|
|
fbbffb4672 | ||
|
|
422e098727 | ||
|
|
87347e30b2 | ||
|
|
3314ce9823 | ||
|
|
402c1fe614 | ||
|
|
1d57856aa8 | ||
|
|
c027c215d6 | ||
|
|
fa0428b9fe | ||
|
|
b01c499ce5 | ||
|
|
4e5033dd24 | ||
|
|
00863f3830 | ||
|
|
2d4b35e8b9 | ||
|
|
6e4f2b9466 | ||
|
|
9a6fc0253b | ||
|
|
3180c781ed | ||
|
|
632152e8b6 | ||
|
|
1048f7e98d | ||
|
|
3de265216e | ||
|
|
2bdcadc7ab | ||
|
|
421ddfc68e | ||
|
|
41594bc1ac | ||
|
|
e85199d464 | ||
|
|
a6ee3bc704 | ||
|
|
2909106f30 | ||
|
|
05b97aabb2 | ||
|
|
84af60d817 | ||
|
|
72403a2512 | ||
|
|
4ec619d646 | ||
|
|
6178a627a0 | ||
|
|
3095fd7e4a | ||
|
|
74a6041760 | ||
|
|
96127e37ff | ||
|
|
df5484ea35 | ||
|
|
0ae3dae030 | ||
|
|
e5979139ac | ||
|
|
f81f6deb20 | ||
|
|
f9951909d8 | ||
|
|
bbda972b05 | ||
|
|
4445e9c434 | ||
|
|
709adacac2 | ||
|
|
9841cdd355 |
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.gitignore export-ignore
|
||||
.gitattributes export-ignore
|
||||
remind.php export-ignore
|
||||
sync-to-dianne-git export-ignore
|
||||
18
.gitignore
vendored
@@ -1,15 +1,17 @@
|
||||
*.bak
|
||||
*.o
|
||||
*~
|
||||
.gitignore
|
||||
TAGS
|
||||
autom4te.cache
|
||||
config.log
|
||||
config.status
|
||||
src/Makefile
|
||||
www/Makefile
|
||||
*.o
|
||||
src/config.h
|
||||
src/remind
|
||||
rem2html/Makefile
|
||||
src/*.tar.gz*
|
||||
tests/test.out
|
||||
.gitignore
|
||||
*~
|
||||
src/Makefile
|
||||
src/config.h
|
||||
src/rem2ps
|
||||
src/remind
|
||||
src/version.h
|
||||
tests/test.out
|
||||
www/Makefile
|
||||
|
||||
@@ -3,7 +3,7 @@ THE REMIND COPYRIGHT
|
||||
1. REMIND refers to the entire set of files and documentation in the
|
||||
REMIND package.
|
||||
|
||||
2. REMIND is Copyright 1992-2018 Dianne Skoll, except where noted in
|
||||
2. REMIND is Copyright 1992-2021 Dianne Skoll, except where noted in
|
||||
individual files.
|
||||
|
||||
3. DISTRIBUTION AND USE
|
||||
|
||||
9
Makefile
@@ -8,7 +8,7 @@ all: src/Makefile
|
||||
@echo "* *"
|
||||
@echo "*******************"
|
||||
@echo ""
|
||||
@cd src; $(MAKE) all LANGDEF=$(LANGDEF)
|
||||
@cd src && $(MAKE) all LANGDEF=$(LANGDEF)
|
||||
|
||||
install:
|
||||
@echo ""
|
||||
@@ -18,14 +18,15 @@ install:
|
||||
@echo "* *"
|
||||
@echo "*********************"
|
||||
@echo ""
|
||||
cd src; $(MAKE) install
|
||||
@$(MAKE) -C src install
|
||||
@$(MAKE) -C rem2html install
|
||||
|
||||
clean:
|
||||
find . -name '*~' -exec rm {} \;
|
||||
cd src; $(MAKE) clean
|
||||
cd src && $(MAKE) clean
|
||||
|
||||
test:
|
||||
@cd src && $(MAKE) test
|
||||
@cd src && $(MAKE) -s test
|
||||
|
||||
distclean: clean
|
||||
rm -f config.cache config.log config.status src/Makefile src/config.h tests/test.out www/Makefile
|
||||
|
||||
83
configure
vendored
@@ -626,6 +626,7 @@ VERSION
|
||||
EGREP
|
||||
GREP
|
||||
CPP
|
||||
PERL
|
||||
SET_MAKE
|
||||
LN_S
|
||||
INSTALL_DATA
|
||||
@@ -2291,36 +2292,6 @@ EOF
|
||||
ac_config_headers="$ac_config_headers src/config.h"
|
||||
|
||||
|
||||
if test "`uname -s`" = "Darwin" ; then
|
||||
trap 'echo Be patient...' INT TERM
|
||||
cat <<'EOF'
|
||||
|
||||
Please don't use Apple products. This script will continue in 30 seconds
|
||||
if you insist on compiling Remind on Mac OS X.
|
||||
|
||||
EOF
|
||||
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
|
||||
sleep 1
|
||||
done
|
||||
trap - INT
|
||||
trap - TERM
|
||||
fi
|
||||
|
||||
if uname -s | grep -i -q 'cygwin' ; then
|
||||
trap 'echo Be patient...' INT TERM
|
||||
cat <<'EOF'
|
||||
|
||||
Please don't use Microsoft products. This script will continue in 30
|
||||
seconds if you insist on compiling Remind on Cygwin.
|
||||
|
||||
EOF
|
||||
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
|
||||
sleep 1
|
||||
done
|
||||
trap - INT
|
||||
trap - TERM
|
||||
fi
|
||||
|
||||
ac_ext=c
|
||||
ac_cpp='$CPP $CPPFLAGS'
|
||||
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
||||
@@ -3274,6 +3245,46 @@ $as_echo "no" >&6; }
|
||||
SET_MAKE="MAKE=${MAKE-make}"
|
||||
fi
|
||||
|
||||
# Extract the first word of "perl", so it can be a program name with args.
|
||||
set dummy perl; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_path_PERL+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
case $PERL in
|
||||
[\\/]* | ?:[\\/]*)
|
||||
ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
PERL=$ac_cv_path_PERL
|
||||
if test -n "$PERL"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5
|
||||
$as_echo "$PERL" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3820,7 +3831,7 @@ _ACEOF
|
||||
|
||||
|
||||
|
||||
for ac_header in sys/file.h glob.h wctype.h locale.h
|
||||
for ac_header in sys/types.h sys/file.h glob.h wctype.h locale.h
|
||||
do :
|
||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||
@@ -3976,10 +3987,10 @@ fi
|
||||
|
||||
|
||||
if test "$GCC" = yes; then
|
||||
CFLAGS="$CFLAGS -Wall -Wstrict-prototypes"
|
||||
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
|
||||
fi
|
||||
|
||||
for ac_func in setenv unsetenv glob mbstowcs setlocale
|
||||
for ac_func in setenv unsetenv glob mbstowcs setlocale initgroups
|
||||
do :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||
@@ -3991,9 +4002,10 @@ _ACEOF
|
||||
fi
|
||||
done
|
||||
|
||||
VERSION=03.01.16
|
||||
VERSION=03.03.12
|
||||
|
||||
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h"
|
||||
|
||||
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h rem2html/Makefile"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
@@ -4689,6 +4701,7 @@ do
|
||||
"src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
|
||||
"www/Makefile") CONFIG_FILES="$CONFIG_FILES www/Makefile" ;;
|
||||
"src/version.h") CONFIG_FILES="$CONFIG_FILES src/version.h" ;;
|
||||
"rem2html/Makefile") CONFIG_FILES="$CONFIG_FILES rem2html/Makefile" ;;
|
||||
|
||||
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
|
||||
esac
|
||||
|
||||
42
configure.in
@@ -14,41 +14,12 @@ EOF
|
||||
|
||||
AC_CONFIG_HEADER(src/config.h)
|
||||
|
||||
if test "`uname -s`" = "Darwin" ; then
|
||||
trap 'echo Be patient...' INT TERM
|
||||
cat <<'EOF'
|
||||
|
||||
Please don't use Apple products. This script will continue in 30 seconds
|
||||
if you insist on compiling Remind on Mac OS X.
|
||||
|
||||
EOF
|
||||
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
|
||||
sleep 1
|
||||
done
|
||||
trap - INT
|
||||
trap - TERM
|
||||
fi
|
||||
|
||||
if uname -s | grep -i -q 'cygwin' ; then
|
||||
trap 'echo Be patient...' INT TERM
|
||||
cat <<'EOF'
|
||||
|
||||
Please don't use Microsoft products. This script will continue in 30
|
||||
seconds if you insist on compiling Remind on Cygwin.
|
||||
|
||||
EOF
|
||||
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
|
||||
sleep 1
|
||||
done
|
||||
trap - INT
|
||||
trap - TERM
|
||||
fi
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PATH_PROG([PERL], [perl])
|
||||
|
||||
dnl Checks for libraries.
|
||||
dnl Replace `main' with a function in -lm:
|
||||
@@ -61,7 +32,7 @@ AC_CHECK_SIZEOF(unsigned int)
|
||||
AC_CHECK_SIZEOF(unsigned long)
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_CHECK_HEADERS(sys/file.h glob.h wctype.h locale.h)
|
||||
AC_CHECK_HEADERS(sys/types.h sys/file.h glob.h wctype.h locale.h)
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_STRUCT_TM
|
||||
@@ -71,10 +42,11 @@ AC_FUNC_UTIME_NULL
|
||||
AC_HEADER_TIME
|
||||
|
||||
if test "$GCC" = yes; then
|
||||
CFLAGS="$CFLAGS -Wall -Wstrict-prototypes"
|
||||
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale)
|
||||
VERSION=03.01.16
|
||||
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale initgroups)
|
||||
VERSION=03.03.12
|
||||
AC_SUBST(VERSION)
|
||||
AC_OUTPUT(src/Makefile www/Makefile src/version.h)
|
||||
AC_SUBST(PERL)
|
||||
AC_OUTPUT(src/Makefile www/Makefile src/version.h rem2html/Makefile)
|
||||
|
||||
13
contrib/remind-conf-mode/README
Normal file
@@ -0,0 +1,13 @@
|
||||
Remind-conf-mode is a configuration mode designed to make it a little easier to configure remind using emacs.
|
||||
|
||||
It offers a vibrant colour syntax highlighting for those who like lots of colour, simple indentation and some hopefully useful functions for entering times and dates. Those functions have been exposed in a special menu for remind for those who have not turned off the emacs menu system.
|
||||
|
||||
Just copy remind-conf-mode.el to your elisp folder (whatever it is called) make sure it is in your path so emacs know where to look for it, and put (require 'remind-conf-mode) in your dotemacs file.
|
||||
|
||||
There are some more complex instructions in the file itself.
|
||||
|
||||
Have fun and if you can think of any improvements let me know, or fork it to your own git repository and experiment away.
|
||||
|
||||
The faux-locale branch has code for choosing the language you use remind in. Please try it out and let me know if there are any problems with it.
|
||||
|
||||
Shelagh
|
||||
674
contrib/remind-conf-mode/gpl.txt
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
@@ -1,11 +1,11 @@
|
||||
;;; remind-conf-mode.el --- A mode to help configure remind.
|
||||
|
||||
;; Copyright (C) 2008 Shelagh Manton <shelagh.manton@gmail.com>
|
||||
;; Copyright (C) 2008 - 2011 Shelagh Manton <shelagh.manton@gmail.com>
|
||||
|
||||
;; Author: Shelagh Manton <shelagh.manton@gmail.com> with help from
|
||||
;; Dianne Skoll
|
||||
;; Keywords: remind configure mode
|
||||
;; Version: .04
|
||||
;; Keywords: remind configure convenience
|
||||
;; Version: 0.14
|
||||
|
||||
;; This program is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU General Public License
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
;; If you want to use the auto-complete stuff, you will need to download and install the
|
||||
;; auto-complete library from http://www.cx4a.org/pub/auto-complete.el and put
|
||||
;; (require 'auto-complete) in your emacs with
|
||||
;; (require 'auto-complete) in your Emacs with
|
||||
;; (add-hook 'remind-conf-mode-hook
|
||||
;; (lambda ()
|
||||
;; (make-local-variable 'ac-sources)
|
||||
@@ -42,10 +42,13 @@
|
||||
;; (auto-complete t)))
|
||||
;; in your .emacs file
|
||||
|
||||
;; PS. you could add ac-source-abbrev ac-source-words-in-buffer to have abbrevs and
|
||||
;; PS. you could add ac-source-abbrev ac-source-words-in-buffer to have abbrevs and
|
||||
;; other words in buffer auto-complete too
|
||||
|
||||
;;; History:
|
||||
;;Thu, Nov 26, 2009
|
||||
;; sorted out why the rem-save-file was not working. fixed.
|
||||
;;
|
||||
;; Thu, Feb 14, 2008
|
||||
;; Based mode on wpld-mode tutorial and sample-mode on emacs wiki.
|
||||
;; Ideas from mupad.el for font-lock styles.
|
||||
@@ -54,14 +57,14 @@
|
||||
;; Added a demo skeleton for people to copy for easy entry of coloured remind entries.
|
||||
;; tried to hook in the auto-complete library so that all known functions and keywords can be easily entered.
|
||||
;; EXPERIMENTAL, but seems to work well here (emacs cvs).
|
||||
;; Seems to work without case folding which is nice. wonder why it didn't yesterday?
|
||||
;; Seems to work without case folding which is nice.
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
||||
(require 'font-lock); this goes in the define-derived-mode part.
|
||||
(when (featurep 'xemacs)
|
||||
(require 'overlay)) ;I wonder if this will help with font-lock and xemacs?
|
||||
(require 'overlay)) ;supposed to make it compatible with Xemacs.
|
||||
|
||||
|
||||
(defgroup remind-conf nil
|
||||
@@ -80,12 +83,13 @@
|
||||
remind-conf-mode-map)
|
||||
"Keymap for `remind-conf-mode'.")
|
||||
|
||||
(define-key remind-conf-mode-map "\C-cr" 'rem-skel)
|
||||
(define-key remind-conf-mode-map "\C-ct" 'rem-today)
|
||||
(define-key remind-conf-mode-map "\C-cd" 'rem-today-skel)
|
||||
(define-key remind-conf-mode-map "\C-cw" 'rem-week-away)
|
||||
(define-key remind-conf-mode-map "\C-cx" 'rem-tomorrow)
|
||||
(define-key remind-conf-mode-map "\C-ca" 'rem-days-away)
|
||||
(define-key remind-conf-mode-map "\C-c\C-r" 'rem-skel)
|
||||
(define-key remind-conf-mode-map "\C-c\C-t" 'rem-today)
|
||||
(define-key remind-conf-mode-map "\C-c\C-d" 'rem-today-skel)
|
||||
(define-key remind-conf-mode-map "\C-c\C-w" 'rem-week-away)
|
||||
(define-key remind-conf-mode-map "\C-c\C-W" 'rem-weeks-away)
|
||||
(define-key remind-conf-mode-map "\C-c\C-x" 'rem-tomorrow)
|
||||
(define-key remind-conf-mode-map "\C-c\C-a" 'rem-days-away)
|
||||
(define-key remind-conf-mode-map "\M-j" 'remind-indent-line)
|
||||
(define-key remind-conf-mode-map (kbd "RET") 'remind-indent-line)
|
||||
(define-key remind-conf-mode-map "\C-c\C-c" 'rem-save-file)
|
||||
@@ -107,41 +111,51 @@
|
||||
|
||||
(defconst remind-keywords
|
||||
(sort
|
||||
(list "RUN" "REM" "ONCE" "SATISFY" "BEFORE" "UNSET" "OMIT"
|
||||
(list "RUN" "REM" "ONCE" "SATISFY" "BEFORE" "UNSET" "OMIT" "FIRST" "SATISFY"
|
||||
"OMIT" "DATE" "SKIP" "ONCE" "AFTER" "WARN" "PRIORITY" "AT" "SCHED" "IF" "ELSE" "ENDIF"
|
||||
"WARN" "UNTIL" "THROUGH" "SCANFROM" "DURATION" "TAG" "MSG" "MSF" "CAL" "SPECIAL" "IFTRIG"
|
||||
"PS" "PSFILE" "BANNER" "INCLUDE" "PUSH-OMIT-CONTEXT" "DEBUG" "DUMPVARS"
|
||||
"CLEAR-OMIT-CONTEXT" "POP-OMIT-CONTEXT" "SET" "ERRMSG" "FSET"
|
||||
"EXIT" "FLUSH" "PRESERVE" "MOON" "COLOR" "COLOUR")
|
||||
"PS" "PSFILE" "BANNER" "INCLUDE" "PUSH-OMIT-CONTEXT" "DEBUG" "DUMPVARS" "PUSH" "CLEAR" "POP"
|
||||
"CLEAR-OMIT-CONTEXT" "POP-OMIT-CONTEXT" "SET" "ERRMSG" "FSET" "DUMP" "BAN" "INC" "SCAN"
|
||||
"EXIT" "FLUSH" "PRESERVE" "MOON" "COLOR" "UNSET")
|
||||
#'(lambda (a b) (> (length a) (length b)))))
|
||||
|
||||
|
||||
(defconst remind-type-keywords
|
||||
(sort
|
||||
(list "INT" "STRING" "TIME" "DATE" "SHADE")
|
||||
(list "INT" "STRING" "TIME" "DATE" "SHADE" "DATETIME")
|
||||
#'(lambda (a b) (> (length a) (length b)))))
|
||||
|
||||
(defconst remind-builtin-variables
|
||||
(sort
|
||||
(list "$CalcUTC" "$CalMode" "$DefaultPrio" "$EndSent" "$EndSentIg" "$NumTrig"
|
||||
"$FirstIndent" "$FoldYear" "$FormWidth" "$MinsFromUTC" "$LatDeg" "$LatMin" "$LatSec"
|
||||
"$Location" "$LongDeg" "$LongMin" "$LongSec" "$MaxSatIter" "$SubsIndent")
|
||||
(list "$CalcUTC" "$CalMode" "$Daemon" "$DateSep" "$DefaultPrio" "$DontFork" "$DontTrigAts" "$DontQueue"
|
||||
"$EndSent" "$EndSentIg" "$NumTrig" "$FirstIndent" "$FoldYear" "$FormWidth" "$HushMode"
|
||||
"$IgnoreOnce" "$InfDelta" "$NextMode" "$NumQueued" "$NumTrig" "$PrefixLineNo" "$PSCal" "$RunOff"
|
||||
"$SimpleCal" "$SortByDate" "$SortByPrio" "$MinsFromUTC" "$LatDeg" "$LatMin" "$LatSec" "$EndSent"
|
||||
"$EndSentIg" "$Location" "$LongDeg" "$LongMin" "$LongSec" "$MaxSatIter" "$SubsIndent" "$T" "$Td"
|
||||
"$Tm" "$Tw" "$Ty" "$TimeSep" "$UntimedFirst" "$U" "$Ud" "$Um" "$Uw" "$Uy")
|
||||
#'(lambda (a b) (> (length a) (length b)))))
|
||||
|
||||
|
||||
(defconst remind-time-words
|
||||
(sort
|
||||
(list "Jan" "January" "Feb" "Mar" "Apr" "Jun" "Jul" "Aug" "Sept" "Sep" "Oct" "Nov" "Dec" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December" "Mon" "Monday" "Tue" "Tues" "Tuesday" "Wed" "Wednesday" "Thu" "Thursday" "Fri" "Friday" "Saturday" "Sat" "Sun" "Sunday")
|
||||
(list "Jan" "January" "Feb" "Mar" "Apr" "Jun" "Jul" "Aug" "Sept" "Sep" "Oct" "Nov" "Dec"
|
||||
"February" "March" "April" "May" "June" "July" "August" "September" "October"
|
||||
"November" "December" "Mon" "Monday" "Tue" "Tues" "Tuesday" "Wed" "Wednesday"
|
||||
"Thu" "Thursday" "Thurs" "Fri" "Friday" "Saturday" "Sat" "Sun" "Sunday")
|
||||
#'(lambda (a b) (> (length a) (length b)))))
|
||||
|
||||
|
||||
(defconst remind-builtin-functions
|
||||
(sort
|
||||
(list "abs" "access" "shell" "args" "asc" "baseyr" "char" "choose" "coerce" "date"
|
||||
"dawn" "today" "day" "daysinmon" "defined" "dosubst" "dusk" "easterdate" "easter"
|
||||
"filedir" "filename" "getenv" "hour" "iif" "trigger" "index" "isdst" "isleap"
|
||||
"isomitted" "hebdate" "hebday" "hebmon" "hebyear" "language" "ord" "thisyear"
|
||||
"sunrise" "sunset" "lower" "max" "min" "minute" "mon" "moondate" "moontime"
|
||||
"moonphase" "now" "ostype" "plural" "realnow" "realtoday" "sgn" "strlen" "psshade"
|
||||
"substr" "trigdate" "trigger" "trigtime" "trigvalid" "typeof" "upper" "psmoon"
|
||||
"value" "version" "wkday" "wkdaynum" "msgprefix" "msgsuffix" "year")
|
||||
(list "abs" "access" "args" "asc" "baseyr" "char" "choose" "coerce" "current" "date" "datetime" "datepart"
|
||||
"dawn" "day" "daysinmon" "defined" "dosubst" "dusk" "easter" "easterdate" "evaltrig" "filedate"
|
||||
"filedatetime" "filedir" "filename" "getenv" "hebdate" "hebday" "hebmon" "hebyear" "hour" "iif" "index" "isdst"
|
||||
"isleap" "isomitted" "language" "lower" "max" "min" "minute" "minsfromutc" "mon" "monnum" "moondate" "moondatetime"
|
||||
"moonphase" "moontime" "msgprefix" "msgsuffix" "nonomitted" "now" "ord" "ostype" "plural"
|
||||
"psmoon" "psshade" "realcurrent" "realnow" "realtoday" "sgn" "shell" "slide" "strlen" "substr" "sunrise" "sunset" "time" "timepart"
|
||||
"thisyear" "today" "trigdate" "trigdatetime" "trigger" "trigger" "trigtime" "trigvalid" "typeof" "tzconvert" "upper" "value"
|
||||
"version" "weekno" "wkday" "wkdaynum" "year"
|
||||
)
|
||||
#'(lambda (a b) (> (length a) (length b)))))
|
||||
|
||||
;;; faces
|
||||
@@ -225,10 +239,7 @@
|
||||
:group 'remind-conf)
|
||||
|
||||
(defcustom rem-post-save-function ""
|
||||
"Name of shell function that can be run when you save and close a remind file.
|
||||
|
||||
If you put a & after the name of the function, it will run asyncronously. This might
|
||||
be useful if the process takes a long time."
|
||||
"Name of shell function that can be run when you save and close a remind file."
|
||||
:type 'string
|
||||
:group 'remind-conf
|
||||
)
|
||||
@@ -258,18 +269,22 @@ be useful if the process takes a long time."
|
||||
(cons (regexp-opt remind-type-keywords 'words) remind-conf-type-face)
|
||||
'("\[[a-zA-Z]\\{3,6\\}\]" . remind-conf-color-face)
|
||||
'("\\s-+\\([12][0-9]\\|3[01]\\|0?[0-9]\\)\\s-+" . remind-conf-substitutes-face);better date regexp
|
||||
'("\\s-+\\([12][09][0-9][0-9][-/]\\(0[1-9]\\|1[0-2]\\)[-/]\\([12][0-9]\\|0[1-9]\\|3[01]\\)\\)\\s-+" . remind-time-face) ;; pseudo ISO 8601 date format.
|
||||
'("\\s-+\\([12][09][0-9][0-9][-/]\\(0[1-9]\\|1[0-2]\\)[-/]\\([12][0-9]\\|0[1-9]\\|3[01]\\)\\)@\\(2[0-4]\\|[01]?[0-9][.:][0-5][0-9]\\)\\s-+" . remind-time-face) ;;extended pseudo ISO time format
|
||||
'("\\s-+\\(\\(?:20\\|19\\)[0-9][0-9]\\)\\s-+" . remind-conf-substitutes-face);years
|
||||
'("\\s-+\\(2[0-4]\\|[01]?[0-9][.:][0-5][0-9]\\)\\s-+" . remind-conf-substitutes-face);24hour clock, more precise
|
||||
'("\\s-+\\([+-][+-]?[1-9][0-9]*\\)\\s-+" 1 remind-conf-delta-face prepend)
|
||||
(cons (regexp-opt remind-builtin-variables 'words) remind-conf-variable-face)))
|
||||
"The ultimate in highlighting experiences for `remind-conf-mode'.")
|
||||
|
||||
;;YYYY-MM-DD@hh:mm, YYYY-MM-DD@hh.mm, YYYY/MM/DD@hh:mm and YYYY/MM/DD@hh.mm
|
||||
|
||||
(defcustom remind-conf-font-lock-keywords 'remind-conf-font-lock-keywords-3
|
||||
"Font-lock highlighting level for `remind-conf-mode'."
|
||||
:group 'remind-conf
|
||||
:type '(choice (const :tag "Barest minimum of highlighting." remind-conf-font-lock-keywords-1)
|
||||
(const :tag "Medium highlighting." remind-conf-font-lock-keywords-2)
|
||||
(const :tag "Highlighting deluxe." remind-conf-font-lock-keywords-3)))
|
||||
(const :tag "Fruit salad." remind-conf-font-lock-keywords-3)))
|
||||
|
||||
;;; Indentation (I'm sure this could be made more simple. But at least it works.)
|
||||
|
||||
@@ -289,8 +304,8 @@ be useful if the process takes a long time."
|
||||
(if (looking-at "^[ \t]*\\<\\(ENDIF\\|POP\\(?:-OMIT-CONTEXT\\)?\\)\\>")
|
||||
(progn
|
||||
(save-excursion
|
||||
(forward-line -1)
|
||||
(setq cur-indent (- (current-indentation) remind-indent-level))) ;note that not-indented is still t
|
||||
(forward-line -1)
|
||||
(setq cur-indent (- (current-indentation) remind-indent-level))) ;note that not-indented is still t
|
||||
(if (< cur-indent 0) (setq cur-indent 0)))
|
||||
(save-excursion
|
||||
(while not-indented
|
||||
@@ -313,14 +328,17 @@ be useful if the process takes a long time."
|
||||
;;; Convenience functions
|
||||
|
||||
(define-skeleton rem-skel
|
||||
"Skeleton to insert a rem line in a remind configuration file."
|
||||
nil
|
||||
"REM "(skeleton-read "Date? " )
|
||||
("Optional: How many days ahead? " " +" str )
|
||||
"Skeleton to insert a rem line in a remind configuration file.
|
||||
|
||||
If you don't want an optional feature just RET and move on."
|
||||
nil
|
||||
'(setq v1 (skeleton-read "How many days in future?: "))
|
||||
"REM " (rem-days-away (string-to-number v1))
|
||||
("Optional: How many days warning? " " +" str )
|
||||
resume:
|
||||
("Optional: At what time? Format eg 13:00. " " AT " str)
|
||||
resume:
|
||||
("Optional: How many minutes ahead? " " +" str )
|
||||
("Optional: How many minutes warning? " " +" str )
|
||||
resume:
|
||||
("Optional: At what priority? eg 0-9999" " PRIORITY " str )
|
||||
resume:
|
||||
@@ -333,7 +351,7 @@ be useful if the process takes a long time."
|
||||
"REM " (format-time-string "%d %b %Y")
|
||||
("Optional: At what time? Format eg 13:20. " " AT " str)
|
||||
resume:
|
||||
("Optional: How many minutes ahead? " " +" str )
|
||||
("Optional: How many minutes warning? " " +" str )
|
||||
resume:
|
||||
("Optional: At what priority? eg 0-9999" " PRIORITY " str )
|
||||
resume:
|
||||
@@ -351,9 +369,7 @@ be useful if the process takes a long time."
|
||||
(insert (format-time-string "%e %b %Y" (time-add (current-time) (days-to-time 1)))))
|
||||
|
||||
(defun rem-days-away (arg)
|
||||
"Insert a day N number of days in the future.
|
||||
|
||||
Takes a prefix argument, but defaults to 4."
|
||||
"Insert a day ARG number of days in the future."
|
||||
(interactive "nHow many Days?: ")
|
||||
(insert (format-time-string "%e %b %Y" (time-add (current-time) (days-to-time arg)))))
|
||||
|
||||
@@ -362,11 +378,10 @@ Takes a prefix argument, but defaults to 4."
|
||||
(interactive)
|
||||
(insert (format-time-string "%e %b %Y" (time-add (current-time) (days-to-time 7)))))
|
||||
|
||||
(setq skeleton-end-hook nil) ; so the skeletons will not automatically go to a new line.
|
||||
|
||||
;;; private function
|
||||
;; could make it useful for others. Put somethin like the following in your .emacs
|
||||
;(setq rem-post-save-function "~/bin/dailypic &")
|
||||
(defun rem-weeks-away (arg)
|
||||
"Insert a day ARG many weeks in future."
|
||||
(interactive "nHow many weeks?: ")
|
||||
(insert (format-time-string "%e %b %Y" (time-add (current-time) (days-to-time (* 7 arg))))))
|
||||
|
||||
(defun rem-save-file ()
|
||||
"Save the file and start the shell function in one go.
|
||||
@@ -374,7 +389,7 @@ Takes a prefix argument, but defaults to 4."
|
||||
This function will close the window after running. It needs the
|
||||
variable `rem-post-save-function' to be set. It will be most
|
||||
useful to people who have some sort of function they run to use
|
||||
remind data ie procucing calendars."
|
||||
remind data ie producing calendars."
|
||||
(interactive)
|
||||
(if (boundp 'rem-post-save-function)
|
||||
(progn (save-buffer)
|
||||
@@ -383,7 +398,9 @@ remind data ie procucing calendars."
|
||||
(error "`rem-post-save-function' variable is not set")))
|
||||
|
||||
(defun rem-setup-colors ()
|
||||
"Insert set of variables for coloured output in remind messages."
|
||||
"Insert set of variables for coloured output in remind messages.
|
||||
|
||||
You would only need to do this once in your main reminders file."
|
||||
(interactive)
|
||||
(find-file (expand-file-name "~/.reminders"))
|
||||
(goto-char 0) ;we do want it somewhere near the top of the file.
|
||||
@@ -410,12 +427,38 @@ SET BrWht Esc + \"[37;1m\" \n \n")))
|
||||
|
||||
;; So now you can do things like:
|
||||
|
||||
(define-skeleton birthcol
|
||||
(define-skeleton rem-birthday
|
||||
"Make birthdays magenta.
|
||||
Acts on the region or places point where it needs to be."
|
||||
nil
|
||||
"[Mag]" _ " [Nrm]")
|
||||
|
||||
(define-skeleton rem-urgent
|
||||
"Colour urgent notices red.
|
||||
Acts on the region or places point where it needs to be."
|
||||
nil
|
||||
"[Red]" _ " [Nrm]")
|
||||
|
||||
;; menu anyone?
|
||||
|
||||
(easy-menu-define remind-menu
|
||||
remind-conf-mode-map
|
||||
"Menu used in remind-conf-mode."
|
||||
(append '("Remind")
|
||||
'([ "Insert a reminder" rem-skel t])
|
||||
'([ "Insert todays date" rem-today t])
|
||||
'([ "Insert tomorrows date" rem-tomorrow t])
|
||||
'([ "How many days away?" rem-days-away t])
|
||||
'([ "A week away" rem-week-away t])
|
||||
'([ "How many weeks away?" rem-weeks-away t])
|
||||
'([ "Birthday color" rem-birthday t])
|
||||
'([ "Urgent color" rem-urgent t])
|
||||
'([ "Save the file and run a script" rem-save-file t])
|
||||
'("-----")
|
||||
'([ "Setting up the colors - once-off" rem-setup-colors t])
|
||||
))
|
||||
|
||||
|
||||
;; finally the derived mode.
|
||||
|
||||
;;;###autoload
|
||||
@@ -429,6 +472,7 @@ Acts on the region or places point where it needs to be."
|
||||
(set (make-local-variable 'comment-start) ";")
|
||||
(set (make-local-variable 'comment-start) "#")
|
||||
(set (make-local-variable 'comment-end) "\n")
|
||||
(set (make-local-variable 'skeleton-end-hook) nil) ; so the skeletons will not automatically go to a new line.
|
||||
(set (make-local-variable 'fill-column) '100);cause I was having problems with autofill.
|
||||
(set (make-local-variable 'indent-line-function) 'remind-indent-line)
|
||||
(use-local-map remind-conf-mode-map)
|
||||
@@ -438,7 +482,5 @@ Acts on the region or places point where it needs to be."
|
||||
(provide 'remind-conf-mode)
|
||||
;;; remind-conf-mode.el ends here
|
||||
|
||||
;;; Indentation code
|
||||
;;; work out how to make the syntax highlighting work only before the (MSG|MSF)
|
||||
;;; keywords and not after.
|
||||
;;; for my own use. keymap to save file and do dailypic C-c C-c in time honoured tradition?
|
||||
;;; work out how to make the syntax highlighting work only before the
|
||||
;;; (MSG|MSF) keywords and not after.
|
||||
@@ -1,4 +1,4 @@
|
||||
REMIND version 3.1 for UNIX
|
||||
REMIND version 3.2 for UNIX
|
||||
|
||||
REMIND is a sophisticated alarm/calendar program. Details are given
|
||||
in the man page, "remind.1".
|
||||
@@ -6,16 +6,16 @@ in the man page, "remind.1".
|
||||
INSTALLING REMIND:
|
||||
-----------------
|
||||
|
||||
If you have Tcl/Tk (wish 4.1 or higher) installed and are running X Windows:
|
||||
--------------------------------------------------------------
|
||||
If you have Tcl/Tk (wish 4.1 or higher) installed and are running X11:
|
||||
----------------------------------------------------------------------
|
||||
|
||||
1) Type: wish ./build.tk from the top-level Remind directory.
|
||||
Fill in the various options and hit "Build Remind"
|
||||
|
||||
2) Type: "make install" -- you may need to be root to do this.
|
||||
|
||||
If you do NOT have Tcl/Tk or are NOT running X Windows:
|
||||
-------------------------------------------------------
|
||||
If you do NOT have Tcl/Tk or are NOT running X11:
|
||||
-------------------------------------------------
|
||||
|
||||
1) Edit the file "src/custom.h" according to your preferences.
|
||||
|
||||
@@ -73,12 +73,12 @@ RELEASE NOTES -- miscellaneous info that couldn't go anywhere else!
|
||||
|
||||
1. POPUP REMINDERS
|
||||
|
||||
If you're running under X-Windows and you have the TCL tools,
|
||||
you can create simple pop-up reminders by creating the following
|
||||
TCL script called 'popup'. It pops a message on to the screen and
|
||||
waits for you to press the 'OK' button. If you don't press the OK button
|
||||
within 15 seconds, it exits anyway. To use it, you can use the '-k' option
|
||||
for Remind as follows:
|
||||
If you're running under X11 and you have the Tcl tools, you can create
|
||||
simple pop-up reminders by creating the following Tcl script called
|
||||
'popup'. It pops a message on to the screen and waits for you to
|
||||
press the 'OK' button. If you don't press the OK button within 15
|
||||
seconds, it exits anyway. To use it, you can use the '-k' option for
|
||||
Remind as follows:
|
||||
|
||||
remind "-kpopup '%s'&" .reminders
|
||||
|
||||
@@ -93,7 +93,7 @@ Norman Walsh.
|
||||
#!/usr/local/bin/wish
|
||||
wm withdraw .
|
||||
after 15000 { destroy . ; exit }
|
||||
tk_dialog .d { Message } $argv warning 0 { OK }
|
||||
tk_dialog .d { Message } $argv warning 0 { OK }
|
||||
destroy .
|
||||
exit
|
||||
-------------- Cut Here ---------- Cut Here ---------- Cut Here -------------
|
||||
|
||||
370
docs/WHATSNEW
@@ -1,5 +1,367 @@
|
||||
CHANGES TO REMIND
|
||||
|
||||
* VERSION 3.3 Patch 12 - 2022-01-24
|
||||
|
||||
- UPDATE: rem2html: Use JSON::MaybeXS instead of JSON::Any, since JSON::Any
|
||||
is deprecated. NOTE INCOMPATIBILITY: If you don't have JSON::MaybeXS
|
||||
installed, you'll need to install it before trying to install or update
|
||||
rem2html
|
||||
|
||||
- NEW FEATURE: Add a DO command. This is just like INCLUDE, but relative
|
||||
paths are interpreted relative to the directory containing the current
|
||||
file. That is:
|
||||
|
||||
DO somefile.rem
|
||||
|
||||
is equivalent to:
|
||||
|
||||
INCLUDE [filedir()]/somefile.rem
|
||||
|
||||
- NEW FEATURE: Add the $DefaultTDelta system variable and associated
|
||||
-tt[N] command-line option to set a default time delta for timed
|
||||
reminder without an explicit +N delta.
|
||||
|
||||
- IMPROVEMENT: TkRemind: Store .tkremindrc in $XDG_CONFIG_HOME/tkremindrc
|
||||
or $HOME/.config/tkremindrc as per the XDG Base Directory Specification.
|
||||
|
||||
- BUG FIX: remind: Make the shell() built-in function respect
|
||||
$MaxStringLen
|
||||
|
||||
- BUG FIX: Use size_t to track the size of dynamic buffers rather than int.
|
||||
This permits Remind to read in files with lines longer than 1GB and to
|
||||
consume more than 1GB of output from the shell() command, both of which
|
||||
will surely be massively useful. (The old limit was 1GB rather than 2GB
|
||||
because of details of the dynamic buffer resizing algorithm.)
|
||||
|
||||
* VERSION 3.3 Patch 11 - 2021-12-30
|
||||
|
||||
- IMPROVEMENT: TkRemind: Save the print dialog settings so they persist.
|
||||
|
||||
- IMPROVEMENT: TkRemind: Show queue in sorted order.
|
||||
|
||||
- IMPROVEMENT: TkRemind: Pass "-r" flag to inotifywait
|
||||
|
||||
- IMPROVEMENT: TkRemind: Draw moon phases with Tk canvas items rather than
|
||||
using PNG images. This lets them change color along with other TkRemind
|
||||
preferences.
|
||||
|
||||
- IMPROVEMENT: TkRemind: Underline editable reminders when the pointer enters
|
||||
them; fire up the editor with either Button-1 or Button-3 for
|
||||
non-TkRemind-generated reminders.
|
||||
|
||||
- NEW FUNCTION: Remind: Add the isany() built-in function.
|
||||
|
||||
- IMPROVEMENT: rem2html: Add class names indicating number of rows in calendar
|
||||
|
||||
- IMPROVEMENT: remind: In -z0 mode, sleep with higher precision to ensure we
|
||||
wake as close to possible to each 1-minute boundary.
|
||||
|
||||
- IMPROVEMENT: rem2html: Coalesce table.rem-cal CSS into one block. Thanks
|
||||
to Ian! D. Allen for pointing this out.
|
||||
|
||||
- IMPROVEMENT: examples/defs.rem: Modernize the examples and get rid of some
|
||||
cruft.
|
||||
|
||||
- CHANGE: Add $Latitude and $Longitude system variables. Deprecate
|
||||
$LatDeg, $LatMin, $LatSec, $LongDeg, $LongMin and $LongSec.
|
||||
|
||||
- CHANGE: Test: Add "dump $" to test.rem.
|
||||
|
||||
* VERSION 3.3 Patch 10 - 2021-11-30
|
||||
|
||||
- IMPROVEMENT: TkRemind: Apply window and text colors to all GUI elements
|
||||
including buttons and status labels.
|
||||
|
||||
- NEW FEATURE: The new ADDOMIT keyword can shorten reminder files.
|
||||
The command:
|
||||
|
||||
REM ...whatever... ADDOMIT MSG Foo
|
||||
|
||||
behaves identically to:
|
||||
|
||||
REM ...whatever... SATISFY 1
|
||||
IF trigvalid()
|
||||
OMIT [trigdate()] MSG Foo
|
||||
ENDIF
|
||||
|
||||
For example, Labour Day can be displayed and omitted as follows:
|
||||
|
||||
REM Mon 1 Sep SCANFROM -7 ADDOMIT MSG Labour Day
|
||||
|
||||
- UPDATE: Update contrib/remind-conf-mode to latest release
|
||||
|
||||
- CHANGE: The parser does not auto-convert numbers 90-99 to 1990-1999. This
|
||||
was messing up things like "DURATION 90". It also means you can no longer
|
||||
abbreviate the years 1990-1999 as 90-99.
|
||||
|
||||
- BUG FIX: Various documentation fixes
|
||||
|
||||
- BUG FIX: When switching users with the "-u" option, call initgroups()
|
||||
to properly set group membership list.
|
||||
|
||||
* VERSION 3.3 Patch 9 - 2021-10-14
|
||||
|
||||
- NEW FEATURE: Add "-+username" option to tell Remind to trust files owned by
|
||||
"username" and allow RUN directives in them. Idea courtesy of Ian! D. Allen
|
||||
|
||||
- NEW FEATURE: Add "-u+username" variant to tell Remind to switch users to
|
||||
"username" without disabling RUN directives. Idea courtesy of Ian! D. Allen
|
||||
|
||||
- CHANGE: rem2html: rem2html has been moved out of the www/ directory into
|
||||
its own rem2html/ directory. If your system has the prerequisites
|
||||
(namely Perl, Getopt::Long and JSON::Any) then rem2html will be installed
|
||||
by "make install".
|
||||
|
||||
- CHANGE: Remove "cm2rem". It was about 20 years obsolete.
|
||||
|
||||
- CHANGE: rem2html: Use inline data: URL images for moon images by default,
|
||||
thus producing a completely stand-alone HTML file.
|
||||
|
||||
- CHANGE: Remove unnecessary spaces from "remind -pp" JSON output.
|
||||
|
||||
- DOCUMENTATION FIX: Various man page fixes and tweaks.
|
||||
|
||||
- BUG FIX: rem2html: Tweak the default CSS stylesheet; more rational
|
||||
handling of rem2html command-line options.
|
||||
|
||||
- BUG FIX: remind: "remind -c" would sometimes highlight *two* days as
|
||||
"today"; this has been fixed.
|
||||
|
||||
- BUG FIX: Add a missing #ifdef...#endif and remove a C99-ism. This once again
|
||||
allows Remind to be compiled with some very old C compilers.
|
||||
|
||||
* VERSION 3.3 Patch 8 - 2021-09-13
|
||||
|
||||
- NEW FEATURE: remind: Add INCLUDECMD command
|
||||
|
||||
- NEW FEATURE: remind: Add shellescape() built-in function
|
||||
|
||||
- BUG FIX: tkremind: TkRemind would sometimes fill in incorrect initial
|
||||
values for the reminder-editing form if you clicked on a TkRemind-created
|
||||
reminder to edit it. This has been fixed.
|
||||
|
||||
- BUG FIX: tkremind: Get back better error messages from Remind if you
|
||||
try to create a reminder with an invalid date specification.
|
||||
|
||||
- BUG FIX: remind: Catch integer overflow if we try to evaluate $IntMin * -1
|
||||
|
||||
- DOC UPDATES: remind: Minor man page fixes
|
||||
|
||||
* VERSION 3.3 Patch 7 - 2021-05-10
|
||||
|
||||
- MINOR FIX: Refuse to run "make test" as root --- it would fail
|
||||
anyway with an obscure message.
|
||||
|
||||
- BUG FIX: Remind would sometimes compute incorrect trigger date for:
|
||||
REM Tue 29 Feb MSG ...
|
||||
|
||||
- BUG FIX: Remind would sometimes compute incorrect trigger date for
|
||||
a date spec like: Tue 31 2021 MSG ...
|
||||
|
||||
* VERSION 3.3 Patch 6 - 2021-03-30
|
||||
|
||||
- test/test.rem: Change local to en_US.utf-8 only if current locale
|
||||
is not a UTF-8 locale.
|
||||
|
||||
- MINOR CHANGE: Remind's arithmetic operators (+, -, *, /) give errors
|
||||
on overflow rather than silently giving the wrong answer.
|
||||
|
||||
- MINOR CHANGE: Add $IntMin and $IntMax system variables.
|
||||
|
||||
- DOCUMENTATION FIX: Document that TkRemind now requires Tcl/Tk version
|
||||
8.5 or newer.
|
||||
|
||||
* VERSION 3.3 Patch 5 - 2021-01-21
|
||||
|
||||
- NEW FEATURE: tkremind: Add ability to change fonts and colors from
|
||||
within TkRemind "Options" dialog.
|
||||
|
||||
- CHANGE: tkremind: TkRemind now requires Tcl/Tk 8.5 or newer.
|
||||
|
||||
- CHANGE: tkremind: You can specify the location of the options
|
||||
file on the command-line if you want to use one other than ~/.tkremindrc
|
||||
|
||||
- CLEANUP: tkremind: Remove "Apply Options" from Options dialog; we only
|
||||
need "Save Options".
|
||||
|
||||
- DOC FIX: Add missing release note in 3.3.4 notes regarding
|
||||
setpagedevice patch
|
||||
|
||||
- DOC FIX: tkremind: Document shortcut keys.
|
||||
|
||||
* VERSION 3.3 Patch 4 - 2021-01-12
|
||||
|
||||
- NEW FEATURE: If "inotifywait" is installed, TkRemind uses it to refresh
|
||||
the calendar display right away when the reminders file/directory is updated.
|
||||
This makes TkRemind react almost instantly if external tools are editing
|
||||
or updating reminders.
|
||||
|
||||
- MINOR NEW FEATURE: rem2ps has a new '-x' option; this puts the day numbers
|
||||
on the top-left of the day's box instead of the top-right.
|
||||
|
||||
- MINOR FIXES: A typo in remind.1 was fixed; additional comments regarding
|
||||
UNTIL were added.
|
||||
|
||||
- BUG FIX: rem2ps: Call setpagedevice to set page size. Based on a patch
|
||||
from Jonathan Kamens.
|
||||
|
||||
* VERSION 3.3 Patch 3 - 2020-11-09
|
||||
|
||||
- BUG FIX: Fix startup crash in TkRemind if "Show Today's Reminders on
|
||||
Startup" is enabled (which, unfortunately, is the default.) Bug reported
|
||||
by Martin Ziemer.
|
||||
|
||||
* VERSION 3.3 Patch 2 - 2020-11-08
|
||||
|
||||
- MINOR NEW FEATURE: Add MAYBE-UNCOMPUTABLE keyword; see the man page
|
||||
and discussion at
|
||||
https://dianne.skoll.ca/pipermail/remind-fans/2020/003745.html
|
||||
|
||||
- CHANGE: TkRemind always invokes Remind with the "-itkremind=1" option,
|
||||
even when printing. NOTE INCOMPATIBILITY: This is a behavior change!
|
||||
When you print from TkRemind, we also invoke Remind with "-itkprint=1"
|
||||
so you can detect that PostScript is being generated.
|
||||
|
||||
- CHANGE: The maximum length of a variable name has been increased from
|
||||
16 characters to 64 characters. Modern computers have plenty of memory.
|
||||
|
||||
- BUG FIXES: Minor documentation updates, typo fixes, clarifications, etc.
|
||||
|
||||
- BUG FIX: Fix calendar-drawing alignment errors when displaying UTF-8
|
||||
strings with zero-width combining characters and strings with tabs.
|
||||
|
||||
- BUG FIX: TkRemind would mess up placement of the WEEK special if invoked
|
||||
with the "-m" option. This has been fixed.
|
||||
|
||||
- BUG FIX: TkRemind would sometimes fail with an error message when editing
|
||||
a reminder; this is because it was interpreting months 08 and 09 as
|
||||
illegal octal numbers. This has been fixed.
|
||||
|
||||
* VERSION 3.3 Patch 1 - 2020-03-20
|
||||
|
||||
- CHANGE: For overlapping multi-day events, issue a reminder for the
|
||||
most *recent* event rather than the earliest event. NOTE
|
||||
INCOMPATIBILITY: This is a behavior change!
|
||||
|
||||
- CHANGE: Do not convert 90-99 to 1990-1999 when parsing numbers to
|
||||
recognize years. NOTE INCOMPATIBILITY: This is a behavior change!
|
||||
|
||||
- CHANGE: Revert change to -y option that included filename and line
|
||||
number in the hash.
|
||||
|
||||
- CHANGE: Retain newlines (produced by %_) in JSON output.
|
||||
|
||||
- FIX: Document $FormWidth system variable
|
||||
|
||||
- FIX: Highlight today's date in "remind -c" output
|
||||
|
||||
- FIX: Eliminate compiler warnings on Ubuntu 18.04.
|
||||
|
||||
- IMPROVEMENT: Allow times to be specified either in 24-hour mode
|
||||
(HH:MM or HH.MM) or AM/PM mode (HH:MMam; HH:MMpm, etc.)
|
||||
|
||||
- IMPROVEMENT: Allow DURATION to be specified as a time (1:30) or a
|
||||
number of minutes (90).
|
||||
|
||||
- IMPROVEMENT: If terminal size can be determined, set $FormWidth to
|
||||
terminal width - 8; if not, set $FormWidth to 72.
|
||||
|
||||
- MINOR IMPROVEMENT: Add the "ampm()" built-in function.
|
||||
|
||||
* Version 3.3 Patch 0 - 2020-01-31
|
||||
|
||||
- FIX: rem2ps: Add a %%PageBoundingBox: document structuring convention
|
||||
comment.
|
||||
|
||||
- FIX: rem2ps: Ignore unknown SPECIAL-type reminders.
|
||||
|
||||
- IMPROVEMENT: In calendar mode ("-c" option), Remind automatically adjusts
|
||||
the width of the calendar to fit the terminal window if standard output
|
||||
is a TTY.
|
||||
|
||||
- IMPROVEMENT: Add JSON-based output with "remind -pp" and "remind -ppp"
|
||||
The JSON-based intermediate format preserves a lot more information
|
||||
about the original reminder, allowing back-ends more insight into
|
||||
the intent of the reminder, the recurrence used, etc. See the documentation
|
||||
in "man rem2ps"
|
||||
|
||||
- IMPROVEMENT: TkRemind can "reverse-engineer" reminders that it creates
|
||||
using the additional information in the "remind -pp" format, so it
|
||||
doesn't create or use ugly comment blocks to delimit the reminders
|
||||
it creates.
|
||||
|
||||
- IMPROVEMENT: TkRemind: Add popup help to most buttons and controls.
|
||||
|
||||
- NEW FEATURE: Add support for $DefaultColor system variable, suggested
|
||||
by Tim Chase.
|
||||
|
||||
- NEW FEATURE: The "-@[n][,m]" command-line option allows colored reminders
|
||||
in Agenda Mode as well as in Calendar Mode. It also adds support for
|
||||
terminal emulators that can handle the xterm 256-color escape sequences
|
||||
as well as the true 24-bit color escape sequences.
|
||||
|
||||
- CHANGE: SPECIALs are now case-insensitive. Before, only SPECIAL COLOR
|
||||
would work. Now you can use Special Color, special color, etc.
|
||||
|
||||
* Version 3.2 Patch 0 - 2020-01-03
|
||||
|
||||
- IMPROVEMENT: Add support for events spanning multiple days (with AT
|
||||
and DURATION). Add trigeventstart() and trigeventduration()
|
||||
introspection functions; see "MULTI-DAY EVENTS" in the man page.
|
||||
|
||||
- IMPROVEMENT: Add introspection functions trigback(), trigdelta(),
|
||||
trigduration(), trigfrom(), trigpriority(), trigrep(),
|
||||
trigscanfrom(), trigtimedelta(), trigtimerep(), and triguntil(). See
|
||||
man page for details; thanks to Tim Chase for the suggestion.
|
||||
|
||||
- IMPROVEMENT: TkRemind: Use PNG images for the next month / previous
|
||||
month buttons rather than -> and <-. Also use nice anti-aliased
|
||||
moon phase images instead of ugly blocky bitmaps.
|
||||
|
||||
- CHANGE: Modify addition so that previously-illegal combinations
|
||||
TIME + TIME, TIME + DATETIME and DATETIME + TIME are now allowed.
|
||||
Also allow DATETIME - TIME. If t1 and t2 are expressions of type TIME
|
||||
and dt is an expression of type DATETIME, then the following are now
|
||||
equivalent (before, the expressions on the left-hand side would fail
|
||||
with a "Type mismatch" error.)
|
||||
|
||||
t1 + t2 == t1 + coerce("INT", t2)
|
||||
dt + t2 == dt + coerce("INT", t2)
|
||||
t1 + dt == coerce("INT", t1) + dt
|
||||
dt - t2 == dt - coerce("INT", t2)
|
||||
|
||||
- DOC FIX: Document previously-undocumented $MaxStringLen system variable
|
||||
|
||||
- DOC FIX: Various minor documentation fixes.
|
||||
|
||||
- BUG FIX: Specifying a DURATION without an AT clause results in an error.
|
||||
Before, it would be accepted but not do anything useful.
|
||||
|
||||
- BUG FIX: Catch potential date overflow in slide() function
|
||||
|
||||
- BUG FIX: Fix compile error when compiling Romanian version; eliminate
|
||||
compiler warning when compiling non-English versions.
|
||||
|
||||
- BUG FIX: TkRemind: Fix startup failure of TkRemind if options are at
|
||||
default. :(
|
||||
|
||||
* Version 3.1 Patch 17 - 2019-11-15
|
||||
|
||||
- IMPROVEMENT: Add "Extra Remind Options" setting to TkRemind.
|
||||
|
||||
- IMPROVEMENT: Enable warning-free compilation even with gcc -Wextra flag.
|
||||
|
||||
- IMPROVEMENT: Warn if "OMIT a THROUGH b" has a > b.
|
||||
|
||||
- SYNTACTIC SUGAR: Make "SCANFROM -n" the same as "SCANFROM [today() - n]"
|
||||
|
||||
- BUG FIX: Don't dump expired reminders when dumping queue.
|
||||
|
||||
- BUG FIX: Fix failure when specifying a Jahrzeit in Adar. Fix
|
||||
courtesy of Dov Feldstern
|
||||
|
||||
- BUG FIX: Fix various documentation errors and update man page.
|
||||
|
||||
* Version 3.1 Patch 16 - 2018-11-09
|
||||
|
||||
- IMPROVEMENT: Add patch from Stephen Morgan to calculate astronomical and
|
||||
@@ -38,7 +400,7 @@ CHANGES TO REMIND
|
||||
|
||||
- BUG FIX: Make parser reject an AT followed by more than one time.
|
||||
|
||||
- BUG FIX: Make parser reject epeated delta or *repeat values.
|
||||
- BUG FIX: Make parser reject repeated delta or *repeat values.
|
||||
|
||||
* Version 3.1 Patch 14 - 2015-04-24
|
||||
|
||||
@@ -229,7 +591,7 @@ CHANGES TO REMIND
|
||||
|
||||
* Version 3.1 Patch 4 - 2008-02-03
|
||||
|
||||
- ENHANCMENT: 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.
|
||||
|
||||
- ENHANCEMENT: tkremind has been tweaked to look better with Tcl/Tk 8.5.
|
||||
@@ -368,7 +730,7 @@ CHANGES TO REMIND
|
||||
|
||||
- The SPECIAL COLOR reminder type has been hacked to behave more like
|
||||
a MSG type. It sorts properly and is emitted as a normal reminder
|
||||
in non-calendar mode. Simlarly, SPECIAL HTML sorts with -g as well.
|
||||
in non-calendar mode. Similarly, SPECIAL HTML sorts with -g as well.
|
||||
|
||||
+ MINOR ENHANCEMENTS
|
||||
|
||||
@@ -1304,7 +1666,7 @@ CHANGES TO REMIND
|
||||
|
||||
- Improved debugging of reminder scripts
|
||||
|
||||
- Took out the "purge" option - it is in general too dificult to tell when
|
||||
- Took out the "purge" option - it is in general too difficult to tell when
|
||||
a reminder has expired for good, so now it's up to you to do this
|
||||
by hand.
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
# "#USHOLS" for U.S. holidays #
|
||||
# "#JHOLS" for Jewish holidays #
|
||||
# "#PSSTUFF" for nifty PostScript examples #
|
||||
# "#COLORS" for examples of ANSI color escape sequences. #
|
||||
# #
|
||||
# This file is part of REMIND. #
|
||||
# Copyright (C) 1992-2018 Dianne Skoll #
|
||||
@@ -26,8 +25,8 @@ RUN OFF
|
||||
################################################
|
||||
# Ensure required version of remind is used... #
|
||||
################################################
|
||||
IF version() < "03.01.08"
|
||||
ERRMSG This file requires at least version 03.01.08 of Remind.%
|
||||
IF version() < "03.01.10"
|
||||
ERRMSG This file requires at least version 03.01.10 of Remind.%
|
||||
ERRMSG This version is version [version()].
|
||||
EXIT
|
||||
ENDIF
|
||||
@@ -84,7 +83,6 @@ SET December 12
|
||||
###########################################################
|
||||
# Other symbolic constants and functions for "pasting"... #
|
||||
###########################################################
|
||||
|
||||
SET Quote CHAR(34)
|
||||
|
||||
# Handy constants/function for specifing week of month...
|
||||
@@ -94,30 +92,15 @@ SET Week_3 15
|
||||
SET Week_4 22
|
||||
FSET _last(mo) "1 " + MON((mo%12)+1) + " --7"
|
||||
|
||||
# Handy function to provide SCANFROM dates...
|
||||
FSET _back(days) TODAY()-days
|
||||
|
||||
###########################################################
|
||||
# Function which returns a string in "am/pm" format based #
|
||||
# on the time. For example, set a am_pm(NOW())... #
|
||||
###########################################################
|
||||
|
||||
FSET _am_pm(tm) IIF(tm<01:00, tm+12*60+"am", \
|
||||
tm<12:00, tm+"am", \
|
||||
tm<13:00, tm+"pm", \
|
||||
tm-12*60+"pm")
|
||||
|
||||
#################################################################
|
||||
# Function which removes a single leading zero from a string... #
|
||||
# Function that removes a single leading zero from a string... #
|
||||
#################################################################
|
||||
|
||||
FSET _no_lz(s) IIF(SUBSTR(s, 1, 1)=="0", SUBSTR(s, 2), s)
|
||||
|
||||
#################################################################
|
||||
# Return the length of the daylight/night portion of a date, #
|
||||
# in minutes. #
|
||||
#################################################################
|
||||
|
||||
FSET _light_len(date) MAX(SUNSET(date)-SUNRISE(date), 0)
|
||||
FSET _dark_len(date) 1440-_light_len(date)
|
||||
|
||||
@@ -125,26 +108,12 @@ FSET _dark_len(date) 1440-_light_len(date)
|
||||
# Function to calculate number of years since a given year #
|
||||
# or number of months since a given month and year... #
|
||||
############################################################
|
||||
|
||||
FSET _yr_num(yr) ORD(YEAR(TRIGDATE()) - yr)
|
||||
FSET _mo_num(mo, yr) ORD(12 * (YEAR(TRIGDATE()) - yr) + \
|
||||
MONNUM(TRIGDATE()) - mo)
|
||||
FSET _yr_num(yr) ORD($Ty - yr)
|
||||
FSET _mo_num(mo, yr) ORD(12 * ($Ty - yr) + $Tm - mo)
|
||||
|
||||
# Here's an example of how to use them:
|
||||
REM 1 Nov ++12 MSG %"Dean's [_yr_num(1984)] birthday%" is %b.
|
||||
REM 1 MSG Dean's [_mo_num(11, 1984)] 'monthly' anniversary
|
||||
|
||||
###########################################################
|
||||
# Function to send mail via elm's "fastmail" (by GMS!)... #
|
||||
###########################################################
|
||||
|
||||
#FSET _mail(from, subj) "mailx -s " + \
|
||||
# Quote + from + " : " + subj + Quote \
|
||||
# GETENV("LOGNAME") + " < /dev/null 1>&0"
|
||||
FSET _mail(from, subj) "fastmail -f " + \
|
||||
Quote + from + Quote + \
|
||||
" -s " + Quote + subj + Quote + \
|
||||
" /dev/null " + GETENV("LOGNAME")
|
||||
REM 1 Nov ++12 MSG %"John's [_yr_num(1984)] birthday%" is %b.
|
||||
REM 1 MSG John's [_mo_num(11, 1984)] 'monthly' anniversary
|
||||
|
||||
#############################################################################
|
||||
# Here's a tricky problem: The 4th of July is a holiday in the U.S.
|
||||
@@ -158,29 +127,28 @@ FSET _mail(from, subj) "fastmail -f " + \
|
||||
# dependent upon the current date, it's tricky and results may not be
|
||||
# what you expect. You should try to make sure that the OMIT context
|
||||
# "near" any current reminders will not change during a calendar run.
|
||||
# The SCANFROM clause should help make these OMITs very safe.
|
||||
# The SCANFROM clause will make these OMITs safe.
|
||||
############################################################################
|
||||
|
||||
# Calculate the weekday of the holiday.
|
||||
REM 4 July SCANFROM [_back(7)] SATISFY 1
|
||||
REM 4 July SCANFROM -7 SATISFY 1
|
||||
|
||||
IF WKDAYNUM(TRIGDATE()) == Sat
|
||||
REM [TRIGDATE()] MSG Independence day (actual)
|
||||
OMIT [TRIGDATE()-1] MSG Independence day (observed)
|
||||
SET iday $T
|
||||
IF WKDAYNUM(iday) == Sat
|
||||
REM [iday] MSG Independence day (actual)
|
||||
OMIT [iday-1] MSG Independence day (observed)
|
||||
ELSE
|
||||
IF WKDAYNUM(TRIGDATE()) == Sun
|
||||
REM [TRIGDATE()] MSG Independence day (actual)
|
||||
OMIT [TRIGDATE()+1] MSG Independence day (observed)
|
||||
IF WKDAYNUM(iday) == Sun
|
||||
REM [iday] MSG Independence day (actual)
|
||||
OMIT [iday+1] MSG Independence day (observed)
|
||||
ELSE
|
||||
OMIT [TRIGDATE()] MSG Independence day
|
||||
OMIT [iday] MSG Independence day
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
############################################################################
|
||||
# #
|
||||
# A meeting on the first Monday of every month which is moved to the #
|
||||
# second Monday in the event of a holiday. #
|
||||
# #
|
||||
############################################################################
|
||||
|
||||
# First, the normal meeting. However, the SKIP keyword means this
|
||||
@@ -192,68 +160,21 @@ REM Mon 8 SATISFY 1
|
||||
|
||||
# But only actually trigger the delayed meeting if the previous
|
||||
# Monday was a holiday
|
||||
IF ISOMITTED(TRIGDATE()-7)
|
||||
REM [TRIGDATE()] MSG Delayed meeting
|
||||
IF ISOMITTED($T-7)
|
||||
REM [$T] MSG Delayed meeting
|
||||
ENDIF
|
||||
|
||||
############################################################################
|
||||
# #
|
||||
# A very complicated reminder sent in by a Remind user. #
|
||||
# This person gets paid every two weeks, starting from 8 January 1993. #
|
||||
# If a pay date occurs before the twelfth of a month, then that #
|
||||
# he pays his mortgage on that pay date. Otherwise, he pays the mortgage #
|
||||
# on the previous pay date. Furthermore, he has to schedule his #
|
||||
# mortgage payment six days before it is due. He wants to be reminded #
|
||||
# a further four days before the scheduling deadline. He also #
|
||||
# wants to be mailed a notice two weeks before the scheduling deadline. #
|
||||
# #
|
||||
# Here's the solution - if you can follow this, consider yourself a #
|
||||
# Remind programmer extraordinaire! #
|
||||
# #
|
||||
############################################################################
|
||||
|
||||
# A function to determine whether or not a pay-date is a mortgage-date.
|
||||
|
||||
FSET _IsMortDate(x) DAY(x) < 12 || (DAY(x+14) >= 12 && DAY(x+14) <= 14)
|
||||
|
||||
# Paydays - for reference
|
||||
|
||||
REM 8 Jan 1993 *14 MSG Payday
|
||||
|
||||
# Calculate the mortgage payment six days ahead of time. Note that this
|
||||
# is done "implicitly" by subtracting 6 from the starting date - we start
|
||||
# on 2 Jan rather than 8 Jan. We add 6 to TRIGDATE() in _IsMortDate to
|
||||
# compensate.
|
||||
|
||||
REM 2 Jan 1993 *14 ++4 SATISFY [_IsMortDate(TRIGDATE()+6)] \
|
||||
MSG %"Schedule mortgage payment%" for %a.
|
||||
|
||||
# Now the mail reminder two weeks before the payment date - because two
|
||||
# weeks before a payment date is also a payment date, no pre-compensation
|
||||
# in the starting date of 8 Jan is necessary - convince yourself of this!
|
||||
# This uses the _mail() function defined earlier.
|
||||
|
||||
REM ONCE 8 Jan 1993 *14 SATISFY [_IsMortDate(TRIGDATE()+14)] \
|
||||
RUN [_mail("Decatur Federal", \
|
||||
"Pay mortgage by the " + ORD(DAY(TRIGDATE()+14)))]
|
||||
|
||||
# Make an entry on the calendar when the mortgage should be paid
|
||||
|
||||
REM 8 Jan 1993 *14 SATISFY [_IsMortDate(TRIGDATE())] \
|
||||
CAL Mortgage payment
|
||||
|
||||
##########################################################################
|
||||
# #
|
||||
# On our UNIX system, I run a program which queries the university #
|
||||
# On our UNIX system, I run a program that queries the university #
|
||||
# library and creates a file called ".booksdue". This file is #
|
||||
# a REMIND script to tell me when my library books are due. Here's #
|
||||
# an example from my reminder file - it shows the use of filedate(). #
|
||||
# When the .booksdue file is at least 7 days old, I create a new version #
|
||||
# by querying the library computer. Note the use of realtoday() rather #
|
||||
# than today. #
|
||||
# than today(). #
|
||||
# #
|
||||
##########################################################################
|
||||
|
||||
IF !$RunOff && !$CalMode && !$SimpleCal
|
||||
IF REALTODAY()-FILEDATE("/home/dfs/.booksdue") >= 7
|
||||
REM RUN /home/dfs/bilge/library/getbooks
|
||||
@@ -283,7 +204,7 @@ REM Sat Sun SPECIAL SHADE 220
|
||||
#############################################################################
|
||||
|
||||
SET SaveTrig $NumTrig
|
||||
SET easter EASTERDATE(YEAR(TODAY()))
|
||||
SET easter EASTERDATE($Uy)
|
||||
REM [easter-46] MSG %"Ash Wednesday%"
|
||||
REM [easter-7] MSG %"Palm Sunday%"
|
||||
OMIT [easter-2] MSG %"Good Friday%"
|
||||
@@ -292,17 +213,15 @@ REM [easter+39] MSG %"Ascension Day%"
|
||||
REM [easter+49] MSG %"Pentecost%"
|
||||
|
||||
# Some holidays are omitted, some are not. You may want to change
|
||||
# which ones are omitted - use the general forms shown below.
|
||||
# You'll need the _back() function and the Week_n variables defined
|
||||
# way up in the file.
|
||||
# which ones are omitted - use the general forms shown below. You'll
|
||||
# need the Week_n variables defined way up in the file.
|
||||
|
||||
OMIT Jan 1 MSG %"New Year's%" Day
|
||||
REM Mon Jan [Week_3] MSG Martin Luther King - %"MLK Day%"
|
||||
REM Feb 2 MSG %"Ground Hog Day%"
|
||||
REM Feb 14 MSG %"Valentine's%" Day
|
||||
REM Mon Feb [Week_3] SCANFROM [_back(7)] SATISFY 1
|
||||
OMIT [trigdate()] MSG %"President's Day%"
|
||||
REM Mar 17 MSG %"St. Patrick's%" Day
|
||||
OMIT Jan 1 MSG %"New Year's%" Day
|
||||
REM Mon Jan [Week_3] MSG Martin Luther King - %"MLK Day%"
|
||||
REM Feb 2 MSG %"Ground Hog Day%"
|
||||
REM Feb 14 MSG %"Valentine's%" Day
|
||||
REM Mon Feb [Week_3] SCANFROM -7 ADDOMIT MSG %"President's Day%"
|
||||
REM Mar 17 MSG %"St. Patrick's%" Day
|
||||
|
||||
# The DST rules are accurate for most locations in
|
||||
# North America
|
||||
@@ -312,51 +231,37 @@ REM Sun Mar 8 ++2 FROM 1 Jan 2007 MSG Daylight Saving Time - %"DST starts%" %b
|
||||
REM Sun [_last(Oct)] ++2 UNTIL 1 Jan 2007 MSG Daylight Saving Time - %"DST ends%" %b
|
||||
REM Sun 1 Nov ++2 FROM 1 Jan 2007 MSG Daylight Saving Time - %"DST ends%" %b
|
||||
|
||||
REM Apr 1 MSG %"April Fool's%" Day
|
||||
REM Mon Tue Wed Thu Fri Sat 15 Apr MSG %"Income tax%" due
|
||||
REM May 5 MSG %"Cinco de Mayo%"
|
||||
REM Sat May [Week_1] MSG %"Kentucky Derby%"
|
||||
REM Sun May [Week_2] MSG %"Mother's Day%"
|
||||
REM Sat May [Week_3] MSG %"Armed Forces Day%"
|
||||
REM Mon [_last(May)] SCANFROM [_back(7)] SATISFY 1
|
||||
OMIT [trigdate()] MSG %"Memorial Day%"
|
||||
REM Jun 14 MSG %"Flag Day%"
|
||||
REM Sun Jun [Week_3] MSG %"Father's Day%"
|
||||
REM Mon Sep [Week_1] SCANFROM [_back(7)] SATISFY 1
|
||||
OMIT [trigdate()] MSG %"Labor Day%"
|
||||
REM Mon Oct [Week_2] MSG %"Columbus Day%"
|
||||
REM Nov 11 MSG %"Veterans Day%"
|
||||
REM Apr 1 MSG %"April Fool's%" Day
|
||||
REM Mon Tue Wed Thu Fri Sat 15 Apr MSG %"Income tax%" due
|
||||
REM May 5 MSG %"Cinco de Mayo%"
|
||||
REM Sat May [Week_1] MSG %"Kentucky Derby%"
|
||||
REM Sun May [Week_2] MSG %"Mother's Day%"
|
||||
REM Sat May [Week_3] MSG %"Armed Forces Day%"
|
||||
REM Mon [_last(May)] SCANFROM -7 ADDOMIT MSG %"Memorial Day%"
|
||||
REM Jun 14 MSG %"Flag Day%"
|
||||
REM Sun Jun [Week_3] MSG %"Father's Day%"
|
||||
REM Mon Sep [Week_1] SCANFROM -7 ADDOMIT MSG %"Labor Day%"
|
||||
REM Mon Oct [Week_2] MSG %"Columbus Day%"
|
||||
REM Nov 11 MSG %"Veterans Day%"
|
||||
|
||||
REM Oct 30 MSG %"Mischief Night%"
|
||||
REM Oct 31 MSG %"Halloween%"
|
||||
REM Tue Nov 2 SCANFROM [_back(7)] \
|
||||
SATISFY [(YEAR(TRIGDATE()) % 4) == 0] \
|
||||
MSG %"Election%" Day
|
||||
REM Thu Nov [Week_4] SCANFROM [_back(7)] SATISFY 1
|
||||
OMIT [trigdate()] MSG %"Thanksgiving%" Day
|
||||
REM Fri Nov [Week_4+1] SCANFROM [_back(7)] SATISFY 1
|
||||
OMIT [trigdate()] MSG %"Thanksgiving%" (cont.)
|
||||
OMIT Dec 24 MSG %"Christmas Eve%"
|
||||
OMIT Dec 25 MSG %"Christmas%" Day
|
||||
REM Oct 30 MSG %"Mischief Night%"
|
||||
REM Oct 31 MSG %"Halloween%"
|
||||
REM Tue Nov 2 SCANFROM -7 SATISFY [($Ty % 4) == 0] MSG %"Election Day%"
|
||||
REM Thu Nov [Week_4] SCANFROM -7 ADDOMIT MSG %"Thanksgiving Day%"
|
||||
REM Fri Nov [Week_4+1] SCANFROM -7 ADDOMIT MSG %"Thanksgiving (cont.)%"
|
||||
OMIT Dec 24 MSG %"Christmas Eve%"
|
||||
OMIT Dec 25 MSG %"Christmas%" Day
|
||||
|
||||
##########################################################################
|
||||
# #
|
||||
# If any US holidays were triggered above, shade in the calendar #
|
||||
# entry in PostScript. This is not quite correct, as it blots out any #
|
||||
# other PostScript stuff above. I was too lazy to do it properly :-) #
|
||||
# entry in PostScript. #
|
||||
# #
|
||||
##########################################################################
|
||||
if $NumTrig > SaveTrig
|
||||
REM SPECIAL SHADE 220
|
||||
endif
|
||||
|
||||
# Seasons (valid from 1992 to 2000)...
|
||||
REM Mar 20 MSG %"Spring%" begins
|
||||
REM Jun [IIF(YEAR(TODAY())%4, 21, 20)] MSG %"Summer%" begins
|
||||
REM Sep [CHOOSE(YEAR(TODAY())-1991, 22,22,23,23,22,22,22,23,22)] \
|
||||
MSG %"Fall%" begins
|
||||
REM Dec [IIF((YEAR(TODAY())+1)%4, 21, 22)] MSG %"Winter%" begins
|
||||
|
||||
#PSSTUFF2
|
||||
##########################################################################
|
||||
# #
|
||||
@@ -370,7 +275,7 @@ REM Dec [IIF((YEAR(TODAY())+1)%4, 21, 22)] MSG %"Winter%" begins
|
||||
# example, I recommend that you use the -sd 10 option for Rem2PS.
|
||||
REM PS Border Border moveto \
|
||||
/DayFont findfont DaySize scalefont setfont \
|
||||
([hebday(today())] [hebmon(today())]) show
|
||||
([hebday($U)] [hebmon($U)]) show
|
||||
|
||||
# Fill in the phases of the moon on the PostScript calendar
|
||||
[moondate(0)] SPECIAL MOON 0
|
||||
@@ -382,7 +287,7 @@ REM PS Border Border moveto \
|
||||
# calendar - the sizes are hard-coded, however, and work best in landscape.
|
||||
REM PS Border Border 5 sub moveto \
|
||||
/SmallFont findfont 4 scalefont setfont \
|
||||
(Sunrise: [sunrise(trigdate())] Sunset: [sunset(trigdate())]) show
|
||||
(Sunrise: [sunrise($T)] Sunset: [sunset($T)]) show
|
||||
|
||||
# The next one puts the day number (1-366) and days left in the year at the
|
||||
# bottom of the post-script calendar. Again, the hard-coded sizes work best
|
||||
@@ -390,7 +295,7 @@ REM PS Border Border 5 sub moveto \
|
||||
FSET _DayOfYear(x) x-(date(year(x),1,1) - 1)
|
||||
REM PS BoxWidth 3 mul 4 div Border 5 sub moveto \
|
||||
/SmallFont findfont 4 scalefont setfont \
|
||||
([_DayOfYear(today())]([365+isleap(today())-_DayOfYear(today())])) show
|
||||
([_DayOfYear($U)]([365+isleap($U)-_DayOfYear($U)])) show
|
||||
|
||||
#JHOLS
|
||||
##########################################################################
|
||||
@@ -430,7 +335,7 @@ SET Reform 0
|
||||
|
||||
# Convenient function definition to save typing
|
||||
FSET _h(x, y) HEBDATE(x,y)
|
||||
FSET _h2(x, y) HEBDATE(x, y, TODAY()-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 _PastSun(x, y) IIF(WKDAYNUM(_h2(x,y))!=0, _h2(x,y), _h2(x,y)+1)
|
||||
FSET _PastMon(x, y) IIF(WKDAYNUM(_h2(x,y))!=1, _h2(x,y), _h2(x,y)+1)
|
||||
@@ -464,7 +369,7 @@ ELSE
|
||||
ENDIF
|
||||
|
||||
# Because Kislev can change length, we must be more careful about Chanukah
|
||||
FSET _chan(x) HEBDATE(24, "Kislev", today()-9)+x
|
||||
FSET _chan(x) HEBDATE(24, "Kislev", $U-9)+x
|
||||
[_chan(1)] ++4 MSG %"Chanukah 1%" is %b.
|
||||
[_chan(2)] MSG %"Chanukah 2%"
|
||||
[_chan(3)] MSG %"Chanukah 3%"
|
||||
@@ -553,9 +458,9 @@ ENDIF
|
||||
# Counting the omer - do the whole spiel, i.e:
|
||||
# "This is the xth day of the omer, being y weeks and z days of the omer."
|
||||
# Nice Remind programming example here!
|
||||
SET ostart HEBDATE(16, "Nisan", TODAY()-50)
|
||||
IF ostart <= TODAY() && (TODAY() - ostart < 49)
|
||||
SET odays TODAY()-ostart+1
|
||||
SET ostart HEBDATE(16, "Nisan", $U-50)
|
||||
IF ostart <= $U && ($U - ostart < 49)
|
||||
SET odays $U-ostart+1
|
||||
IF odays < 7
|
||||
MSG %"%"Today is the [ORD(odays)] day of the Omer.
|
||||
ELSE
|
||||
@@ -573,52 +478,14 @@ ENDIF
|
||||
### for Friday and Saturday. Note: You must set your latitude, longitude
|
||||
### and possibly time zone for these to work properly!
|
||||
|
||||
REM Friday CAL Candle lighting at [sunset(trigdate())-18]
|
||||
REM Saturday CAL Havdalah at [sunset(trigdate())+42]
|
||||
REM Friday CAL Candle lighting at [sunset($T)-18]
|
||||
REM Saturday CAL Havdalah at [sunset($T)+42]
|
||||
|
||||
#COLORS
|
||||
##########################################################################
|
||||
# #
|
||||
# This contains sample ANSI escape sequences for coloring messages. #
|
||||
# It should work on an IBM PC with the ANSI.SYS driver, and on #
|
||||
# other terminals which use the ANSI sequences. #
|
||||
# #
|
||||
# This information was provided by Gail Gurman.
|
||||
# #
|
||||
##########################################################################
|
||||
# Colors - use Nrm to reset to normal text.
|
||||
SET Esc CHAR(27)
|
||||
|
||||
SET Nrm Esc + "[0m"
|
||||
SET Blk Esc + "[0;30m"
|
||||
SET Red Esc + "[0;31m"
|
||||
SET Grn Esc + "[0;32m"
|
||||
SET Ylw Esc + "[0;33m"
|
||||
SET Blu Esc + "[0;34m"
|
||||
SET Mag Esc + "[0;35m"
|
||||
SET Cyn Esc + "[0;36m"
|
||||
SET Wht Esc + "[0;37m"
|
||||
SET Gry Esc + "[30;1m"
|
||||
SET BrRed Esc + "[31;1m"
|
||||
SET BrGrn Esc + "[32;1m"
|
||||
SET BrYlw Esc + "[33;1m"
|
||||
SET BrBlu Esc + "[34;1m"
|
||||
SET BrMag Esc + "[35;1m"
|
||||
SET BrCyn Esc + "[36;1m"
|
||||
SET BrWht Esc + "[37;1m"
|
||||
|
||||
# Examples
|
||||
REM MSG A [Blu]blue[Nrm] reminder.
|
||||
REM MSG [Red]%"A red reminder%" safe to use in the calendar mode.[Nrm]
|
||||
|
||||
# Here is an example of how to use msgprefix() and msgsuffix(). These
|
||||
# will highlight priority-0 reminders in bright red,
|
||||
# priority-2500 in red, and priority-7500 in blue. All others
|
||||
# will be in the normal colors
|
||||
FSET msgprefix(x) iif(x==0, BrRed, x==2500, Red, x==7500, Blu, Nrm)
|
||||
|
||||
# Don't forget to return to normal color set at the end of reminder!
|
||||
FSET msgsuffix(x) Nrm
|
||||
REM 1 SPECIAL COLOR 0 0 255 A blue reminder.
|
||||
REM 2 SPECIAL COLOR 255 0 0 %"A red reminder%" safe to use in the calendar mode.
|
||||
|
||||
# The next examples are great for putting right at the end of the reminder
|
||||
# file. They make queued reminders more eye-catching when they pop up.
|
||||
|
||||
25
man/cm2rem.1
@@ -1,25 +0,0 @@
|
||||
.TH CM2REM 1 "18 October 1999"
|
||||
.UC 4
|
||||
.SH NAME
|
||||
cm2rem.tcl \- Convert Sun's "cm" input file to Remind format
|
||||
.SH SYNOPSIS
|
||||
.B cm2rem.tcl < cm_file > remind_file
|
||||
.SH DESCRIPTION
|
||||
\fBcm2rem.tcl\fR reads the Sun calendar manager data file and converts
|
||||
it into a \fBRemind\fR script. Note that \fBcm2rem.tcl\fR can convert
|
||||
\fIonly\fR version 3 calendar manager files. If you are using version 4
|
||||
files, there should be a system utility to convert them to version 3 files.
|
||||
.SH AUTHOR
|
||||
\fBcm2rem.tcl\fR was written by Dianne Skoll <dianne@skoll.ca>.
|
||||
.SH BUGS
|
||||
Not all of the Sun calendar manager options are respected. In particular,
|
||||
nothing is done for e-mail actions. Also, the resulting Remind script
|
||||
is not editable with \fBTkRemind\fR; you can only edit it with a text
|
||||
editor.
|
||||
.PP
|
||||
\fBcm2rem.tcl\fR requires Tcl/Tk version 8.0 or higher. The
|
||||
\fBtclsh\fR interpreter must be on your \fBpath\fR.
|
||||
|
||||
.SH SEE ALSO
|
||||
\fBremind(1)\fR, \fBtkremind(1)\fR
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH REM 1 "30 August 2007"
|
||||
.TH REM 1 "1 January 2021"
|
||||
.UC 4
|
||||
.SH NAME
|
||||
rem \- Invoke Remind with a default filename
|
||||
|
||||
267
man/rem2ps.1
@@ -1,13 +1,13 @@
|
||||
.TH REM2PS 1 "11 April 2005"
|
||||
.TH REM2PS 1 "5 January 2021"
|
||||
.UC 4
|
||||
.SH NAME
|
||||
rem2ps \- draw a PostScript calendar from Remind output
|
||||
.SH SYNOPSIS
|
||||
.B rem2ps [\fIoptions\fR]
|
||||
.SH DESCRIPTION
|
||||
\fBRem2ps\fR reads the standard input, which should be the results of running
|
||||
\fBRemind\fR with the \fB\-p\fR option. It emits PostScript code (which
|
||||
draws a calendar) to the standard output.
|
||||
\fBRem2ps\fR reads the standard input, which should be the results of
|
||||
running \fBRemind\fR with the \fB\-p\fR or \fB\-pp\fR option. It
|
||||
emits PostScript code (which draws a calendar) to the standard output.
|
||||
.PP
|
||||
See the section "Rem2PS Input Format" for details about the \fB\-p\fR
|
||||
data. This may be useful if you wish to create other \fBRemind\fR
|
||||
@@ -29,6 +29,11 @@ include any document structuring comments in your prologue.
|
||||
Produce the calendar in landscape mode rather than the default
|
||||
portrait mode.
|
||||
.TP
|
||||
.B \-x
|
||||
When printing the calendar, place the day numbers in the top-left of each
|
||||
day's box. If this option is omitted, the day numbers appear in the
|
||||
top-right.
|
||||
.TP
|
||||
\fB\-c\fR[\fIn\fR]
|
||||
If \fIn\fR is omitted, disables the small calendars for next and previous
|
||||
months which are normally generated. If \fIn\fR is supplied, it can range
|
||||
@@ -267,7 +272,7 @@ hold:
|
||||
.TP
|
||||
o
|
||||
The PostScript origin is at the bottom left-hand corner of the page, and
|
||||
PostScript units of 1/72" are in effect.
|
||||
PostScript units of 1/72 inch are in effect.
|
||||
.TP
|
||||
o
|
||||
The variables MinX, MinY, MaxX and MaxY define the bounding box within
|
||||
@@ -313,7 +318,13 @@ Use that file with the \fBRem2ps\fR \fB\-p\fR option to create calendars
|
||||
with the year and month in large grey letters in the background of the
|
||||
calendar.
|
||||
.PP
|
||||
.SH REM2PS INPUT FORMAT
|
||||
.SH REM2PS INPUT FORMAT (-P OPTION)
|
||||
The \fB\-p\fR option is an older, simpler interchange format used by
|
||||
\fBRemind\fR to communicate with back-ends. New back-ends are
|
||||
encoraged to support the new \fB\-pp\fR format preferably, though they
|
||||
are encouraged to support the older \fB\-p\fR format as well if the
|
||||
older format contains enough information for them to work properly.
|
||||
.PP
|
||||
\fBRemind \-p\fR sends the following lines to standard output.
|
||||
The information is designed to be easily parsed by back-end programs:
|
||||
.TP
|
||||
@@ -375,6 +386,9 @@ was provided.
|
||||
.PP
|
||||
\fIbody\fR is the body of the reminder.
|
||||
.PP
|
||||
Future versions of \fBRemind\fR may add additional keys to the JSON
|
||||
object. Back-ends \fImust\fR ignore keys they don't recognize.
|
||||
.PP
|
||||
After a month's worth of reminders have been emitted, \fBRemind\fR
|
||||
emits the line:
|
||||
.PP
|
||||
@@ -393,6 +407,247 @@ the line number and file name of the file containing the reminder. Back-ends
|
||||
that don't care about this information should ignore lines starting with
|
||||
"#" (except, of course, for the # rem2ps lines.)
|
||||
.PP
|
||||
.SH REM2PS PARTIAL JSON INPUT FORMAT (-PP OPTION)
|
||||
\fBRemind \-pp\fR sends the following lines to standard output. They
|
||||
are designed to be easily parsed, but contain much more information
|
||||
than the old-style \fBremind -p\fR output. The extra information
|
||||
contains a representation of the parsed "REM" statement, which could
|
||||
allow converters to better preserve semantics of a reminder. For
|
||||
example, this format passes enough information to allow a back-end to
|
||||
(in many cases) determine a reminder's recurrence rather than just treating
|
||||
each reminder as a one-off event.
|
||||
.PP
|
||||
The lines emitted by \fBremind \-pp\fR are as follows:
|
||||
.TP
|
||||
.B # rem2ps2 begin
|
||||
This line signifies the start of calendar data. Back-ends can search
|
||||
for it to verify they are being fed correct information. Note the
|
||||
"2" after "rem2ps", which distinguishes this format from the older \fB\-p\fR
|
||||
format.
|
||||
.TP
|
||||
\fImonth_name year num_days first_day monday_first\fR
|
||||
Same as the \fB\-p\fR format
|
||||
.TP
|
||||
\fIsun mon tue wed thu fri sat\fR
|
||||
Same as the \fB\-p\fR format
|
||||
.TP
|
||||
\fInext_mon next_days\fR
|
||||
Same as the \fB\-p\fR format
|
||||
.TP
|
||||
\fIprev_mon prev_days\fR
|
||||
Same as the \fB\-p\fR format
|
||||
.PP
|
||||
.B CALENDAR ENTRIES
|
||||
.PP
|
||||
The remaining data consists of calendar entries expressed as a JSON object
|
||||
on a single line. Each such line will begin with "{" and will be a well-formed
|
||||
JSON object. The keys that may be present in the JSON object are as
|
||||
follows:
|
||||
.TP
|
||||
.B date \fIYYYY-MM-DD\fR
|
||||
The \fbdate\fR key will \fIalways\fR be present; it is the trigger date
|
||||
of the reminder expressed as a string in the format \fIYYYY-MM-DD\fR
|
||||
.TP
|
||||
.B filename \fIf\fR
|
||||
The filename in which the reminder was found.
|
||||
.TP
|
||||
.B lineno \fIn\fR
|
||||
The line number within the file on which the reminder was found.
|
||||
.TP
|
||||
.B nonconst_expr 1
|
||||
If the reminder contained a non-constant expression that had to be evaluated
|
||||
to determine the trigger date, this key will be present with the value 1.
|
||||
If this key is present, then it is unsafe for a back-end to rely on
|
||||
recurrence semantics or even the semantics of any part of the parsed
|
||||
reminder, as they may have been computed in a way that cannot be expressed
|
||||
in JSON.
|
||||
.TP
|
||||
.B if_depth \fIn\fR
|
||||
If the reminder is inside one or more IF or ELSE statements, this key
|
||||
will be present and the value will be the number of nested IFs from
|
||||
the top-level to the reminder. Back-ends should be wary of
|
||||
interpreting recurrence semantics of reminders within an IF or ELSE
|
||||
block.
|
||||
.TP
|
||||
.B passthru \fIspecial\fR
|
||||
If the reminder was a SPECIAL reminder, the \fBpassthru\fR key will be
|
||||
present and the value will be the type of SPECIAL (such as SHADE, COLOR,
|
||||
MOON, etc.)
|
||||
.TP
|
||||
.B tags \fIdata\fR
|
||||
If any TAG clauses are present, the \fBtags\fR key will be present and consist
|
||||
of a comma-separated list of tags.
|
||||
.TP
|
||||
.B time \fIt\fR
|
||||
If an AT clause was present, this key will contain the time of the AT clause
|
||||
in minutes after midnight.
|
||||
.TP
|
||||
.B tdelta \fIn\fR
|
||||
If a time delta (+n after an AT clause) was present, this key contains the
|
||||
delta value in minutes.
|
||||
.TP
|
||||
.B trep \fIn\fR
|
||||
If a time repeat (*n after an AT clause) was present, this key contains the
|
||||
repeat value in minutes.
|
||||
.TP
|
||||
.B eventduration \fIn\fR
|
||||
If a DURATION clause was present, this key contains the event duration in
|
||||
minutes.
|
||||
.TP
|
||||
.B duration \fIn\fR
|
||||
If a DURATION clause was present, this key contains today's duration in
|
||||
minutes. See the \fBremind(1)\fR man page, "MULTI-DAY EVENTS", for a
|
||||
discussion of duration vs. event duration.
|
||||
.TP
|
||||
.B eventstart \fIdt\fR
|
||||
If an AT clause was present, this key contains the event start time in
|
||||
the format \fIYYYY-MM-DDTHH:MM\fR.
|
||||
.TP
|
||||
.B back \fIn\fR
|
||||
If the reminder contained a "back" clause (\-n or \-\-n), this key
|
||||
contains the back value. If the "back" value was \-n, the value will
|
||||
be positive; if it was \-\-n, the value will be negative.
|
||||
.TP
|
||||
.B delta \fIn\fR
|
||||
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
|
||||
be positive; if it was \+\+n, the value will be negative.
|
||||
.TP
|
||||
.B rep \fIn\fR
|
||||
If the reminder contained a "repeat" clause (*n), this key contains
|
||||
the repeat value.
|
||||
.TP
|
||||
.B skip \fItype\fR
|
||||
If the reminder contained a SKIP, BEFORE or AFTER keyword, then this
|
||||
key will contain that keyword.
|
||||
.TP
|
||||
.B localomit \fIarray\fR
|
||||
If the reminder contains a local OMIT keyword, this key will be present.
|
||||
Its value will be an array of English day names that are OMITted.
|
||||
.TP
|
||||
.B wd \fIarray\fR
|
||||
If the reminder contains one or more weekdays, this key will be present.
|
||||
Its value will be an array of English day names that are present.
|
||||
.TP
|
||||
.B d \fIn\fR
|
||||
If a day-of-month is present in the reminder specification, this key
|
||||
will be present and its value will be the day number.
|
||||
.TP
|
||||
.B m \fIn\fR
|
||||
If a month is present in the reminder specification, this key
|
||||
will be present and its value will be the month number.
|
||||
.TP
|
||||
.B y \fIn\fR
|
||||
If a year is present in the reminder specification, this key
|
||||
will be present and its value will be the year.
|
||||
.TP
|
||||
.B until \fIYYYY-MM-DD\fR
|
||||
If the reminder contains an UNTIL or THROUGH clause, this key
|
||||
will be present. Its value will be a string of the form YYYY-MM-DD.
|
||||
.TP
|
||||
.B once 1
|
||||
If the reminder contains a ONCE keyword, this key will be present
|
||||
with a value of 1.
|
||||
.TP
|
||||
.B scanfrom \fIYYYY-MM-DD\fR
|
||||
If the reminder contains a SCANFROM keyword, this key will be present
|
||||
and its value will be a string of the form YYYY-MM-DD.
|
||||
.TP
|
||||
.B from \fIYYYY-MM-DD\fR
|
||||
If the reminder contains a FROM keyword, this key will be present
|
||||
and its value will be a string of the form YYYY-MM-DD.
|
||||
.TP
|
||||
.B priority \fIn\fR
|
||||
The priority of the reminder. Always present; if no PRIORITY keyword
|
||||
is specified, then a reminder has a default priority of 5000.
|
||||
.TP
|
||||
.B r \fIn\fR
|
||||
For a SHADE or COLOR special, the red color component.
|
||||
.TP
|
||||
.B g \fIn\fR
|
||||
For a SHADE or COLOR special, the green color component.
|
||||
.TP
|
||||
.B b \fIn\fR
|
||||
For a SHADE or COLOR special, the blue color component.
|
||||
.TP
|
||||
.B body \fIbody\fR
|
||||
The body of the reminder to issue. Always present.
|
||||
.TP
|
||||
.B rawbody \fIraw\fR
|
||||
The "raw" body of the reminder, before any expression-pasting or
|
||||
substitution-sequence processing. If the raw body would be the same
|
||||
as the processed body, then this key is not present.
|
||||
.PP
|
||||
After a month's worth of reminders have been emitted, \fBRemind\fR
|
||||
emits the line:
|
||||
.PP
|
||||
\fB# rem2ps2 end
|
||||
.PP
|
||||
However, back-ends should keep reading until EOF in case more data for
|
||||
subsequent months is forthcoming.
|
||||
.PP
|
||||
|
||||
.SH REM2PS PURE JSON INPUT FORMAT (-PPP OPTION)
|
||||
\fBRemind \-ppp\fR emits \fIpure JSON\fR output. The format is
|
||||
as follows:
|
||||
.PP
|
||||
\fBRemind\fR outputs a JSON array. Each element of the array is a
|
||||
\fImonth descriptor\fR.
|
||||
.PP
|
||||
Each month descriptor is a JSON object with the following elements:
|
||||
.TP
|
||||
.B monthname \fIname\fR
|
||||
The name of the month.
|
||||
.TP
|
||||
.B year \fIyyyy\fR
|
||||
The year.
|
||||
.TP
|
||||
.B daysinmonnth \fIn\fR
|
||||
The number of days in the current month.
|
||||
.TP
|
||||
.B firstwkday \fIn\fR
|
||||
The weekday of the first day of the month (0 = Sunday, 1 = Monday, 6 = Saturday).
|
||||
.TP
|
||||
.B mondayfirst \fIn\fR
|
||||
An indicator of whether or not the calendar week should start with
|
||||
Sunday (n=0) or Monday (n=1).
|
||||
.TP
|
||||
.B daynames \fR[\fIdays\fR]
|
||||
A seven-element array of day names; each element is a string representing
|
||||
the names of the days from Sunday through Saturday.
|
||||
.TP
|
||||
.B prevmonthname \fIname\fR
|
||||
The name of the previous month.
|
||||
.TP
|
||||
.B daysinprevmonth \fIn\fR
|
||||
The number of days in the previous month.
|
||||
.TP
|
||||
.B prevmonthyear \fIyyyy\fR
|
||||
The year of the previous month. (The same as \fByear\fR unless the current
|
||||
month is January.)
|
||||
.TP
|
||||
.B nextmonthname \fIname\fR
|
||||
The name of the following month.
|
||||
.TP
|
||||
.B daysinnextmonth \fIn\fR
|
||||
The number of days in the following month.
|
||||
.TP
|
||||
.B nextmonthyear \fIyyyy\fR
|
||||
The year of the following month. (The same as \fByear\fR unless the
|
||||
current month is December.)
|
||||
.TP
|
||||
.B entries \fR[\fIarray\fR]
|
||||
The \fBentries\fR key consists of an array of calendar entries; each
|
||||
entry is a JSON object that has the same format as described in the
|
||||
\fBCALENDAR ENTRIES\fR section in the \fB\-PP FORMAT\fR section,
|
||||
\fIwith the following difference\fR: In \fB\-PP\fR mode, if a reminder
|
||||
has \fB%"\fR markers, only the text between the markers
|
||||
is included in the \fBbody\fR element. In \fB\-PPP\fR mode, the
|
||||
entire text \fIincluding\fR the \fB%"\fR markers is included and it's up to
|
||||
the back-end to extract the portion between the markers if that
|
||||
is desired.
|
||||
|
||||
|
||||
.SH AUTHOR
|
||||
Rem2PS was written by Dianne Skoll <dianne@skoll.ca>
|
||||
.SH BUGS
|
||||
|
||||
750
man/remind.1
@@ -1,9 +1,9 @@
|
||||
.TH TKREMIND 1 "15 February 1998"
|
||||
.TH TKREMIND 1 "15 January 2021"
|
||||
.UC 4
|
||||
.SH NAME
|
||||
tkremind \- graphical front-end to Remind calendar program
|
||||
.SH SYNOPSIS
|
||||
.B tkremind \fR[\fIoptions\fR] [\fIread_file\fR] [\fIwrite_file\fR]
|
||||
.B tkremind \fR[\fIoptions\fR] [\fIread_file\fR] [\fIwrite_file\fR] [\fIconfig_file\fR]
|
||||
.SH DESCRIPTION
|
||||
\fBTkRemind\fR is a graphical front-end to the \fBRemind\fR program.
|
||||
It provides a friendly graphical interface which allows you to view
|
||||
@@ -13,8 +13,10 @@ Although not all of \fBRemind\fR's features are available with \fBTkRemind\fR,
|
||||
it creates. This allows you to learn \fBRemind\fR's syntax and then add
|
||||
extra features as you become a more sophisticated \fBRemind\fR programmer.
|
||||
|
||||
\fBTkRemind\fR is written in Tcl, and requires version 8.0
|
||||
(or higher). It also requires a \fBwish\fR binary.
|
||||
\fBTkRemind\fR is written in Tcl, and requires version 8.5 (or higher)
|
||||
as well as the tcllib extension. It also requires a \fBwish\fR
|
||||
binary. If you are using Tcl/Tk 8.5, you may also need either the Img
|
||||
or the tkpng extension to handle PNG images.
|
||||
|
||||
.SH OPTIONS
|
||||
\fBTkRemind\fR itself has no options. However, it passes certain options
|
||||
@@ -41,6 +43,9 @@ include the line:
|
||||
.fi
|
||||
.PP
|
||||
|
||||
\fIConfig_file\fR is the file in which \fBTkRemind\fR stores
|
||||
its options. If it is omitted, it defaults to \fI$HOME/.tkremindrt\fR.
|
||||
|
||||
.SH THE CALENDAR WINDOW
|
||||
When you start \fBTkRemind\fR, it displays a calendar for the current
|
||||
month, with today's date highlighted. Reminders are filled into each
|
||||
@@ -51,11 +56,14 @@ notice that the box appears completely full.
|
||||
|
||||
.SH NAVIGATING
|
||||
To change to the previous or next month, click the \fB<\-\fR
|
||||
or \fB\->\fR button, respectively. To change back to
|
||||
the current month, click \fBToday\fR. To go to a specific month,
|
||||
click \fBGo To Date...\fR. This pops up a dialog box which allows you
|
||||
to select a month and enter a year. Once you've done this, click
|
||||
\fBGo\fR to go to the date, or \fBCancel\fR to cancel.
|
||||
or \fB\->\fR button, respectively. You can also use the left/right arrow
|
||||
keys or PageUp/PageDown to navigate.
|
||||
|
||||
To change back to the current month, click \fBToday\fR or press the
|
||||
Home key. To go to a specific month, click \fBGo To Date...\fR. This
|
||||
pops up a dialog box which allows you to select a month and enter a
|
||||
year. Once you've done this, click \fBGo\fR to go to the date, or
|
||||
\fBCancel\fR to cancel.
|
||||
|
||||
To exit \fBTkRemind\fR, click \fBQuit\fR.
|
||||
|
||||
@@ -104,7 +112,7 @@ edit the reminder, thereby gaining access to advanced features of
|
||||
\fBRemind\fR's idioms for expressing different types of reminders.
|
||||
|
||||
.SH PRINTING
|
||||
To print the current month's calender, click \fBPrint...\fR on the
|
||||
To print the current month's calendar, click \fBPrint...\fR on the
|
||||
main calendar window. This brings up the print dialog. Printing
|
||||
either produces a PostScript file or sends PostScript to a UNIX command.
|
||||
|
||||
@@ -125,10 +133,11 @@ Select the appropriate paper size and orientation. Activate
|
||||
be the normal case unless you have many reminders in a particular
|
||||
day. (See the \fBRem2PS\fR documentation.)
|
||||
|
||||
Finally, click \fBPrint\fR to print or \fBCancel\fR to cancel.
|
||||
Note that during printing, \fBRemind\fR is \fInot\fR called with
|
||||
the \fB-itkremind=1\fR option, because it is operated in normal
|
||||
PostScript-producing mode.
|
||||
Finally, click \fBPrint\fR to print or \fBCancel\fR to cancel. Note
|
||||
that during printing, \fBRemind\fR is called with the
|
||||
\fB-itkremind=1\fR option and also an additional \fB-itkprint=1\fR
|
||||
option.
|
||||
|
||||
|
||||
.SH EDITING REMINDERS
|
||||
|
||||
@@ -155,7 +164,11 @@ it with \fBTkRemind\fR.
|
||||
If you have set the "text editor" option correctly, right-clicking
|
||||
on a reminder will bring up a text editor on the file containing
|
||||
the reminder. The cursor will be positioned on the line that
|
||||
generated the reminder.
|
||||
generated the reminder. In addition, if you have a reminder that
|
||||
is editable with an editor but was not created using \fBTkRemind\fR,
|
||||
it will be underlined when you move the cursor over it, and
|
||||
you can edit it in a text editor by either left- or right-clicking
|
||||
on the reminder.
|
||||
|
||||
.SH BACKGROUND REMINDERS
|
||||
|
||||
@@ -210,7 +223,8 @@ background reminder pops up.
|
||||
.TP
|
||||
.B Feed popped-up reminder to command's standard input
|
||||
If selected, feeds the text of the reminder to the command described
|
||||
above.
|
||||
above. The text of the reminder is prefixed by "HH:MM ", where HH:MM
|
||||
is the time of the reminder.
|
||||
|
||||
.TP
|
||||
.B E-mail reminders here if popup not dismissed
|
||||
@@ -231,6 +245,22 @@ The characters "%d" are replaced with the lined number of the file
|
||||
containing the reminder, and "%s" are replaced with the file name.
|
||||
Useful strings might be "emacs +%d %s" or "gvim +%d %s"
|
||||
|
||||
.TP
|
||||
.B Extra Argument for Remind
|
||||
This specifies any extra arguments that should be passed to Remind
|
||||
when \BTkRemind\fR invokes \fBremind\fR. Unless you know what
|
||||
you are doing, leave this blank.
|
||||
|
||||
.TP
|
||||
.B Change entry font...
|
||||
This button pops up a font selection dialog that lets you change the
|
||||
font used to draw calendar items in the calendar boxes.
|
||||
|
||||
.TP
|
||||
.B Change heading font...
|
||||
Similar to Change entry font, but applies to calendar heading
|
||||
(the month and day names and the day numbers.)
|
||||
|
||||
.PP
|
||||
Once you've configured the options the way you like them,
|
||||
press \fBApply Options\fR to put them into effect, \fBSave Options\fR
|
||||
@@ -360,7 +390,7 @@ This line is emitted in response to a \fBSTATUS\fR command. The number
|
||||
.SH AUTHOR
|
||||
TkRemind was written by Dianne Skoll <dianne@skoll.ca>
|
||||
|
||||
\fBTkRemind\fR is Copyright 1996-2018 by Dianne Skoll.
|
||||
\fBTkRemind\fR is Copyright 1996-2020 by Dianne Skoll.
|
||||
|
||||
.SH FILES
|
||||
|
||||
|
||||
29
rem2html/Makefile.in
Normal file
@@ -0,0 +1,29 @@
|
||||
# Set by configure - don't touch.
|
||||
srcdir=@srcdir@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
mandir=@mandir@
|
||||
bindir=@bindir@
|
||||
datadir=@datadir@
|
||||
datarootdir=@datarootdir@
|
||||
PERL=@PERL@
|
||||
PERLMODS_NEEDED=JSON::MaybeXS Getopt::Long
|
||||
all:
|
||||
true
|
||||
|
||||
install:
|
||||
@if test "$(PERL)" = "" ; then \
|
||||
echo "Not installing rem2html; Perl is required"; exit 0; fi; \
|
||||
for m in $(PERLMODS_NEEDED) ; \
|
||||
do \
|
||||
$(PERL) -M$$m -e 1 > /dev/null 2>&1; \
|
||||
if test $$? != 0 ; then echo "Not installing rem2html; missing $$m"; exit 0; fi; \
|
||||
done; \
|
||||
echo "Installing rem2html in $(DESTDIR)$(bindir)"; \
|
||||
mkdir -p $(DESTDIR)$(bindir) && sed -e 's|^#!perl|#!$(PERL)|' < rem2html > $(DESTDIR)$(bindir)/rem2html && chmod 755 $(DESTDIR)$(bindir)/rem2html && exit 0; \
|
||||
exit 1;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
12
rem2html/README.rem2html
Normal file
@@ -0,0 +1,12 @@
|
||||
REM2HTML
|
||||
--------
|
||||
|
||||
rem2html is a Perl script that transforms the output of `remind -pp
|
||||
...' to HTML. Type `perl rem2html --help' for usage information.
|
||||
|
||||
rem2html requires the Perl modules `JSON::Any' and `Getopt::Long'. It
|
||||
will not be installed unless you have those modules as well as Perl
|
||||
itself.
|
||||
|
||||
--
|
||||
Dianne Skoll
|
||||
@@ -1,13 +1,14 @@
|
||||
#!/usr/bin/perl
|
||||
#!perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Getopt::Long;
|
||||
use JSON::MaybeXS;
|
||||
|
||||
my %Options;
|
||||
|
||||
my $rem2html_version = '2.0';
|
||||
my $rem2html_version = '2.1';
|
||||
|
||||
my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mondayfirst, $weeks,
|
||||
@Daynames, $Nextmon, $Nextlen, $Prevmon, $Prevlen);
|
||||
@@ -15,15 +16,20 @@ my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mond
|
||||
my $TIDY_PROGNAME = $0;
|
||||
$TIDY_PROGNAME =~ s|^.*/||;
|
||||
|
||||
# rem2html -- convert the output of "remind -p" to HTML
|
||||
# rem2html -- convert the output of "remind -pp" to HTML
|
||||
|
||||
=head1 NAME
|
||||
|
||||
rem2html - Convert the output of "remind -p" to HTML
|
||||
rem2html - Convert the output of "remind -pp" to HTML
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
remind -p ... | rem2html [options]
|
||||
remind -pp ... | rem2html [options]
|
||||
|
||||
You can also use the old interchange format as below, but the -pp
|
||||
version is preferred.
|
||||
|
||||
remind -p ... | rem2html [options]
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
@@ -49,13 +55,21 @@ month name a link to I<url>.
|
||||
|
||||
=item --imgbase I<url>
|
||||
|
||||
When creating URLs for images and the stylesheet, use
|
||||
I<url> as the base URL.
|
||||
When creating URLs for the stylesheet or external images, use I<url>
|
||||
as the base URL.
|
||||
|
||||
=item --pngs
|
||||
|
||||
Normally, rem2html uses inline "data:" URLs for the moon phase images,
|
||||
yielding a standalone HTML file. The C<--pngs> option makes it use
|
||||
external images named firstquarter.png, fullmoon.png, lastquarter.png
|
||||
and newmoon.png, which are expected to live in C<--imgbase>.
|
||||
|
||||
=item --stylesheet I<url.css>
|
||||
|
||||
Use I<url.css> as the stylesheet. If this option is used,
|
||||
I<url.css> is I<not> interpreted relative to B<imgbase>.
|
||||
I<url.css> is interpreted relative to B<imgbase> I<unless> it start
|
||||
with a "/".
|
||||
|
||||
=item --nostyle
|
||||
|
||||
@@ -96,9 +110,9 @@ sub usage
|
||||
$exit_status = 1;
|
||||
}
|
||||
print STDERR <<"EOM";
|
||||
$TIDY_PROGNAME: Produce an HTML calendar from the output of "remind -p"
|
||||
$TIDY_PROGNAME: Produce an HTML calendar from the output of "remind -pp"
|
||||
|
||||
Usage: remind -p ... | rem2html [options]
|
||||
Usage: remind -pp ... | rem2html [options]
|
||||
|
||||
Options:
|
||||
|
||||
@@ -109,6 +123,8 @@ Options:
|
||||
entry a link to <url>
|
||||
--forwurl url Same as --backurl, but for the next month's small calendar
|
||||
--imgbase url Base URL of images and default stylesheet file
|
||||
--pngs Use external .PNG images for moon phases rater than
|
||||
inline data: URLs
|
||||
--stylesheet url.css URL of CSS stylesheet. If specified, imgbase is NOT
|
||||
prepended to url.css
|
||||
--nostyle Produce basic HTML that does not use a CSS stylesheet
|
||||
@@ -120,11 +136,31 @@ EOM
|
||||
exit($exit_status);
|
||||
}
|
||||
|
||||
sub smoosh
|
||||
{
|
||||
my ($first, $second) = @_;
|
||||
return $second unless defined ($first);
|
||||
return $second if $first eq '';
|
||||
return $second if ($second =~ m|^/|); # Absolute path given for second
|
||||
|
||||
# Squash multiple slashes
|
||||
$first =~ s|/+|/|g;
|
||||
|
||||
# Special case
|
||||
return "/$second" if ($first eq '/');
|
||||
|
||||
# Delete trailing slash
|
||||
$first =~ s|/$||;
|
||||
|
||||
return "$first/$second";
|
||||
}
|
||||
|
||||
sub parse_options
|
||||
{
|
||||
local $SIG{__WARN__} = sub { print STDERR "$TIDY_PROGNAME: $_[0]\n"; };
|
||||
if (!GetOptions(\%Options, "help|h",
|
||||
"man",
|
||||
"pngs",
|
||||
"version",
|
||||
"stylesheet=s",
|
||||
"nostyle",
|
||||
@@ -137,45 +173,40 @@ sub parse_options
|
||||
"tableonly")) {
|
||||
usage(1);
|
||||
}
|
||||
$Options{'title'} ||= 'HTML Calendar';
|
||||
$Options{title} ||= 'HTML Calendar';
|
||||
|
||||
# Fix up imgbase
|
||||
my $imgbase = '%IMAGEBASE%';
|
||||
if ($imgbase ne '%' . 'IMAGEBASE' . '%') {
|
||||
$Options{'imgbase'} ||= $imgbase;
|
||||
} else {
|
||||
$Options{'imgbase'} ||= '';
|
||||
my $stylesheet = $Options{stylesheet};
|
||||
if ($stylesheet) {
|
||||
$Options{stylesheet} = smoosh($Options{imgbase}, $stylesheet);
|
||||
}
|
||||
|
||||
$Options{'imgbase'} =~ s|/+$||;
|
||||
my $stylesheet = $Options{'imgbase'};
|
||||
$stylesheet .= '/' if ($stylesheet ne '');
|
||||
$stylesheet .= 'rem-default.css';
|
||||
$Options{'stylesheet'} ||= $stylesheet;
|
||||
}
|
||||
|
||||
sub start_output
|
||||
{
|
||||
return if ($Options{'tableonly'});
|
||||
return if ($Options{tableonly});
|
||||
|
||||
print("<html>\n<head>\n<title>" . $Options{'title'} . "</title>\n");
|
||||
if (!$Options{'nostyle'}) {
|
||||
if ($Options{'stylesheet'}) {
|
||||
print('<link rel="stylesheet" type="text/css" href="' .
|
||||
$Options{'stylesheet'} . '">' . "\n");
|
||||
}
|
||||
print("<html>\n<head>\n<title>" . $Options{title} . "</title>\n");
|
||||
if (!$Options{nostyle}) {
|
||||
if ($Options{stylesheet}) {
|
||||
print('<link rel="stylesheet" type="text/css" href="' .
|
||||
$Options{stylesheet} . '">' . "\n");
|
||||
} else {
|
||||
print("<style>\n");
|
||||
print default_stylesheet();
|
||||
print("</style>\n");
|
||||
}
|
||||
}
|
||||
print("</head>\n<body>\n");
|
||||
if ($Options{'prologue'}) {
|
||||
print $Options{'prologue'} . "\n";
|
||||
if ($Options{prologue}) {
|
||||
print $Options{prologue} . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub end_output
|
||||
{
|
||||
return if ($Options{'tableonly'});
|
||||
if ($Options{'epilogue'}) {
|
||||
print $Options{'epilogue'} . "\n";
|
||||
return if ($Options{tableonly});
|
||||
if ($Options{epilogue}) {
|
||||
print $Options{epilogue} . "\n";
|
||||
}
|
||||
print("</body>\n</html>\n");
|
||||
}
|
||||
@@ -191,7 +222,7 @@ sub parse_input
|
||||
my $found_data = 0;
|
||||
while(<STDIN>) {
|
||||
chomp;
|
||||
last if /^\# rem2ps begin$/;
|
||||
last if /^\# rem2ps2? begin$/;
|
||||
}
|
||||
|
||||
my $line;
|
||||
@@ -221,20 +252,36 @@ sub parse_input
|
||||
|
||||
$found_data = 1;
|
||||
my $class;
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
$class = '';
|
||||
} else {
|
||||
$class = ' class="rem-entry"';
|
||||
}
|
||||
while(<STDIN>) {
|
||||
chomp;
|
||||
last if /^\# rem2ps end$/;
|
||||
last if /^\# rem2ps2? end$/;
|
||||
next if /^\#/;
|
||||
next unless m/^(\d*).(\d*).(\d*)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/;
|
||||
my ($y, $m, $d, $special, $tag, $duration, $time, $body) =
|
||||
($1, $2, $3, $4, $5, $6, $7, $8);
|
||||
my ($y, $m, $d, $special, $tag, $duration, $time, $body);
|
||||
if (m/^(\d*).(\d*).(\d*)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/) {
|
||||
($y, $m, $d, $special, $tag, $duration, $time, $body) =
|
||||
($1, $2, $3, $4, $5, $6, $7, $8);
|
||||
} elsif (/\{/) {
|
||||
my $obj = decode_json($_);
|
||||
next unless ($obj->{date} =~ /^(\d+)-(\d+)-(\d+)$/);
|
||||
$y = $1;
|
||||
$m = $2;
|
||||
$d = $3;
|
||||
$special = $obj->{passthru} || '*';
|
||||
$tag = $obj->{tags} || '*';
|
||||
$duration = $obj->{duration} || '*';
|
||||
$time = $obj->{time} || '*';
|
||||
$body = $obj->{body};
|
||||
} else {
|
||||
next;
|
||||
}
|
||||
my $d1 = $d;
|
||||
$d1 =~ s/^0+//;
|
||||
$special = uc($special);
|
||||
if ($special eq 'HTML') {
|
||||
push(@{$days->[$d]}, $body);
|
||||
} elsif ($special eq 'HTMLCLASS') {
|
||||
@@ -284,7 +331,7 @@ sub small_calendar
|
||||
}
|
||||
}
|
||||
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
print "<td width=\"14%\">\n";
|
||||
print "<table border=\"0\">\n";
|
||||
print "<caption>";
|
||||
@@ -299,7 +346,7 @@ sub small_calendar
|
||||
print "</caption>\n";
|
||||
|
||||
my $class;
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
print '<tr>';
|
||||
$class = ' align="right"';
|
||||
} else {
|
||||
@@ -321,7 +368,7 @@ sub small_calendar
|
||||
if ($col == 0) {
|
||||
print("<tr>\n");
|
||||
}
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
print("<td align=\"right\" width=\"14%\"> </td>");
|
||||
} else {
|
||||
print("<td class=\"rem-sc-empty-cell\"> </td>");
|
||||
@@ -333,7 +380,7 @@ sub small_calendar
|
||||
print("<tr>\n");
|
||||
}
|
||||
$col++;
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
print("<td align=\"right\" width=\"14%\">$day</td>");
|
||||
} else {
|
||||
print("<td class=\"rem-sc-cell\">$day</td>");
|
||||
@@ -345,7 +392,7 @@ sub small_calendar
|
||||
}
|
||||
if ($col) {
|
||||
while ($col < 7) {
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
print("<td align=\"right\" width=\"14%\"> </td>");
|
||||
} else {
|
||||
print("<td class=\"rem-sc-empty-cell\"> </td>");
|
||||
@@ -372,9 +419,17 @@ sub output_calendar
|
||||
# Last column
|
||||
my $last_col = ($first_col + $Numdays - 1) % 7;
|
||||
|
||||
# Figure out how many rows
|
||||
my $number_of_rows = int(($first_col + $Numdays ) / 7 + 0.999);
|
||||
|
||||
# Add a row for small calendars if necessary
|
||||
if ($first_col == 0 && $last_col == 6) {
|
||||
$number_of_rows++;
|
||||
}
|
||||
|
||||
# Start the table
|
||||
my $class;
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
print '<table width="100%" border="1" cellspacing=\"0\"><caption>' .
|
||||
$Month . ' ' . $Year . '</caption>' . "\n";
|
||||
print '<tr>';
|
||||
@@ -398,26 +453,26 @@ sub output_calendar
|
||||
|
||||
# Start the calendar rows
|
||||
my $col = 0;
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
print "<tr>\n";
|
||||
} else {
|
||||
print "<tr class=\"rem-cal-row\">\n";
|
||||
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
|
||||
}
|
||||
if ($first_col > 0) {
|
||||
small_calendar($Prevmon, $Prevlen, $Options{'backurl'},
|
||||
small_calendar($Prevmon, $Prevlen, $Options{backurl},
|
||||
($Firstwkday - $Prevlen + 35) % 7);
|
||||
$col++;
|
||||
}
|
||||
|
||||
if ($last_col == 6 && $first_col > 0) {
|
||||
small_calendar($Nextmon, $Nextlen, $Options{'forwurl'},
|
||||
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
|
||||
($Firstwkday + $Numdays) % 7);
|
||||
$col++;
|
||||
}
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
$class = ' width="14%"';
|
||||
} else {
|
||||
$class = ' class="rem-empty"';
|
||||
$class = ' class="rem-empty rem-empty-$number_of_rows-rows"';
|
||||
}
|
||||
while ($col < $first_col) {
|
||||
print("<td$class> </td>\n");
|
||||
@@ -425,16 +480,16 @@ sub output_calendar
|
||||
}
|
||||
|
||||
for (my $day=1; $day<=$Numdays; $day++) {
|
||||
draw_day_cell($day);
|
||||
draw_day_cell($day, $number_of_rows);
|
||||
$col++;
|
||||
if ($col == 7) {
|
||||
$col = 0;
|
||||
print "</tr>\n";
|
||||
if ($day < $Numdays) {
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
print "<tr>\n";
|
||||
} else {
|
||||
print "<tr class=\"rem-cal-row\">\n";
|
||||
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -444,13 +499,13 @@ sub output_calendar
|
||||
while ($col < 7) {
|
||||
if ($col == 5) {
|
||||
if ($first_col == 0) {
|
||||
small_calendar($Prevmon, $Prevlen, $Options{'backurl'},
|
||||
small_calendar($Prevmon, $Prevlen, $Options{backurl},
|
||||
($Firstwkday - $Prevlen + 35) % 7);
|
||||
} else {
|
||||
print("<td$class> </td>\n");
|
||||
}
|
||||
} elsif ($col == 6) {
|
||||
small_calendar($Nextmon, $Nextlen, $Options{'forwurl'},
|
||||
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
|
||||
($Firstwkday + $Numdays) % 7);
|
||||
} else {
|
||||
print("<td$class> </td>\n");
|
||||
@@ -462,17 +517,17 @@ sub output_calendar
|
||||
|
||||
# Add a row for small calendars if they were not yet done!
|
||||
if ($first_col == 0 && $last_col == 6) {
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
print "<tr>\n";
|
||||
} else {
|
||||
print "<tr class=\"rem-cal-row\">\n";
|
||||
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
|
||||
}
|
||||
small_calendar($Prevmon, $Prevlen, $Options{'backurl'},
|
||||
small_calendar($Prevmon, $Prevlen, $Options{backurl},
|
||||
($Firstwkday - $Prevlen + 35) % 7);
|
||||
for (my $i=0; $i<5; $i++) {
|
||||
print("<td$class> </td>\n");
|
||||
}
|
||||
small_calendar($Nextmon, $Nextlen, $Options{'forwurl'},
|
||||
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
|
||||
($Firstwkday + $Numdays) % 7);
|
||||
print("</tr>\n");
|
||||
}
|
||||
@@ -482,17 +537,17 @@ sub output_calendar
|
||||
|
||||
sub draw_day_cell
|
||||
{
|
||||
my($day) = @_;
|
||||
my($day, $number_of_rows) = @_;
|
||||
my $shade = $shades->[$day];
|
||||
my $week = '';
|
||||
if (exists($weeks->{$day})) {
|
||||
$week = ' ' . $weeks->{$day};
|
||||
}
|
||||
my $class;
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
$class = $classes->[$day] || '';
|
||||
} else {
|
||||
$class = $classes->[$day] || "rem-cell";
|
||||
$class = $classes->[$day] || "rem-cell rem-cell-$number_of_rows-rows";
|
||||
}
|
||||
if ($shade) {
|
||||
$shade = " style=\"background: $shade;\"";
|
||||
@@ -515,33 +570,46 @@ sub draw_day_cell
|
||||
my $alt;
|
||||
my $title;
|
||||
if ($phase == 0) {
|
||||
$img = 'newmoon.png';
|
||||
if ($Options{pngs}) {
|
||||
$img = smoosh($Options{imgbase}, 'newmoon.png');
|
||||
} else {
|
||||
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAC6SURBVDiNpdNNbsIwFATgL0HKolchHKBX6yFaBOEyoPYUabvOIVKJRaCL2JX5TRNGGvnJ8ozGz89cYoElPvET+BX2yivn/1Bggw5HHMKa1h2qcPZC/JEIhvh+brIZIY6sorhMYo9hh3KGFzzfa84NZNjDt9OG/ZcH1BlaPE1IAG0+URhxzNGESKPFaHJs9Q0Ziww7HnvGeXSrJhis0jiFfjwnj3I0WRv+TKtr4hQl3lDrZ6QN9Wt654hfWfGDmBpUwDkAAAAASUVORK5CYII=';
|
||||
}
|
||||
$title = 'New Moon';
|
||||
$alt = 'new';
|
||||
} elsif ($phase == 1) {
|
||||
$img = 'firstquarter.png';
|
||||
if ($Options{pngs}) {
|
||||
$img = smoosh($Options{imgbase}, 'firstquarter.png');
|
||||
} else {
|
||||
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADfSURBVDiNndM9TsNAFATgzy5yjZSAE85JBygETgENUPF3iBCitHAFQkcIhZ/Ryn9gRlrZmp2Z3ef3TBOHOMULPrDBMrhpi/4HI5xjix2+4nmJRbx/Yh7ahvkpRPVV4QDXwT3UQy46zGkAZDgK/iytefvHgCrkJsqZUH6cLnNbABSxd5Jhhf1IbkMXv8Qux7hH1Ic1xvk/jBWy6gavumvtwx7ectwZXkKh7MA95XgObeOtpI2U4zl0kGbpxgiPvwQUcXLrKFchc82f6Ur0PK49azOnmOI4TBu84zm4SV38DeIVYkrYJyNbAAAAAElFTkSuQmCC';
|
||||
}
|
||||
$title = 'First Quarter';
|
||||
$alt = '1st';
|
||||
} elsif ($phase == 2) {
|
||||
$img = 'fullmoon.png';
|
||||
if ($Options{pngs}) {
|
||||
$img = smoosh($Options{imgbase}, 'fullmoon.png');
|
||||
} else {
|
||||
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADlSURBVDiNrdNBUsJAEAXQlyw4hq4hwWPqTixET6ELkZ16CcAq7oFLqXExjaYgQVNlV/Viev7/6XT/4TjGuME7PiLXUatb8N8xwB12SFjiIXIZtU/MAntEfgvQE4YtHxhiHpjXQ5H7uLhEcaLLAleBvd0Xx9Ha/BdyU+Q5OBV5OKmj7a4YBWdSyNPe4aKHAHkzqcQZNj3JgnNexqE8heyIAulffuFF3kTfIVbBVeu/xoXGGsn2TLJJ/mqkafNiINszySYZdbS90GHlvcgsWktY4TFy7ecxTdvIzahxHQLbyFXUqkPwF2ASRNYgB/PXAAAAAElFTkSuQmCC';
|
||||
}
|
||||
$alt = 'full';
|
||||
$title = 'Full Moon';
|
||||
} else {
|
||||
$img = 'lastquarter.png';
|
||||
if ($Options{pngs}) {
|
||||
$img = smoosh($Options{imgbase}, 'lastquarter.png');
|
||||
} else {
|
||||
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADmSURBVDiNndMxTsNAEIXhzy5yCyQ6FAgcE7oQheQWUAAl5BIkREoZrgB0GFNkHBl7bURGsryaee/3jHeXdpxjghU+8InXyI0S+n0MMEeBEi+4jfV3vAvMQtsyL0J0j2GtViaeRRMyj8IlsgY8BSijE2Kur/hy09wHKMJrEolhwtwHKDHOsI4OLnoAXfl1jiNsOkR9keE4P8D4q4scbzg5xIxtjie709f1E7siC+9+Gx/8fxvPKtEsklcJSBdgWhcN8ByFR5z+AWgd5QpyE+OUWOJO+zJNU+Z6jHAdgHe7K73CuD5zFT9nCmRDIssCaAAAAABJRU5ErkJggg==';
|
||||
}
|
||||
$alt = 'last';
|
||||
$title = 'Last Quarter';
|
||||
}
|
||||
if ($Options{'imgbase'}) {
|
||||
$img = $Options{'imgbase'} . '/' . $img;
|
||||
}
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
print("<div style=\"float: left\"><img border=\"0\" width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">$msg</div>");
|
||||
} else {
|
||||
print("<div class=\"rem-moon\"><img width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">$msg</div>");
|
||||
}
|
||||
}
|
||||
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
print "<div style=\"float: right\">$day$week</div>\n";
|
||||
print "<p> </p>\n";
|
||||
} else {
|
||||
@@ -564,13 +632,13 @@ sub escape_html
|
||||
}
|
||||
|
||||
parse_options();
|
||||
if ($Options{'help'}) {
|
||||
if ($Options{help}) {
|
||||
usage(0);
|
||||
exit(0);
|
||||
} elsif ($Options{'man'}) {
|
||||
} elsif ($Options{man}) {
|
||||
system("perldoc $0");
|
||||
exit(0);
|
||||
} elsif ($Options{'version'}) {
|
||||
} elsif ($Options{version}) {
|
||||
print "rem2html version $rem2html_version.\n";
|
||||
exit(0);
|
||||
}
|
||||
@@ -595,3 +663,81 @@ if ($found_something) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sub default_stylesheet
|
||||
{
|
||||
return <<'EOF';
|
||||
table.rem-cal {
|
||||
font-family: helvetica, arial, sans-serif;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
table.rem-sc-table {
|
||||
font-family: helvetica, arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
width: 95%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
caption.rem-cal-caption {
|
||||
font-size: 14pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
th.rem-cal-hdr {
|
||||
width: 14%;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
vertical-align: top;
|
||||
}
|
||||
td.rem-empty, td.rem-cell, td.rem-small-calendar {
|
||||
width: 14%;
|
||||
height: 7em;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
vertical-align: top;
|
||||
}
|
||||
td.rem-today {
|
||||
width: 14%;
|
||||
height: 7em;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
border-color: #EE3333;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.rem-cal {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
div.rem-daynumber {
|
||||
float: right;
|
||||
text-align: right;
|
||||
vertical-align: top;
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
p.rem-entry {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
div.rem-moon {
|
||||
float: left;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
th.rem-sc-hdr {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
td.rem-sc-empty-cell, td.rem-sc-cell {
|
||||
text-align: right;
|
||||
width: 14%;
|
||||
}
|
||||
|
||||
caption.rem-sc-caption {
|
||||
font-size: 12pt;
|
||||
}
|
||||
EOF
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
Files in this directory:
|
||||
|
||||
tkremind -- Tcl/Tk graphical calendar using Remind as engine
|
||||
cm2rem.tcl -- Convert Sun's "cm" calendar manager files to Remind.
|
||||
|
||||
@@ -1,358 +0,0 @@
|
||||
#!/bin/sh
|
||||
# -*-Mode: TCL;-*-
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# cm2rem.tcl
|
||||
#
|
||||
# A cheesy Tcl script to convert Sun's "cm" calendar manager
|
||||
# files (version 3 only) to Remind format.
|
||||
#
|
||||
# This file is part of REMIND.
|
||||
# Copyright (C) 1992-2018 by Dianne Skoll
|
||||
#
|
||||
#--------------------------------------------------------------
|
||||
|
||||
# the next line restarts using tclsh \
|
||||
exec tclsh "$0" "$@"
|
||||
|
||||
set i 0
|
||||
foreach month {January February March April May June
|
||||
July August September October November December} {
|
||||
incr i
|
||||
set MonthNum($month) $i
|
||||
set FullMonth([string range $month 0 2]) $month
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: convertParens
|
||||
# %ARGUMENTS:
|
||||
# line -- a line read from a cm file
|
||||
# %RETURNS:
|
||||
# A new line with all ( and ) outside quotes converted to { and }.
|
||||
# This cheap trick allows us to use Tcl's built-in list manipulation
|
||||
# functions to munge the line.
|
||||
#***********************************************************************
|
||||
proc convertParens { line } {
|
||||
# Convert all ( and ) to { and } unless they are inside a quoted
|
||||
# string
|
||||
set out ""
|
||||
set len [string length $line]
|
||||
set inQuotes 0
|
||||
for {set i 0} {$i < $len} {incr i} {
|
||||
set char [string range $line $i $i]
|
||||
if {$char == "\\" && $inQuotes} {
|
||||
append out $char
|
||||
incr i
|
||||
set char [string range $line $i $i]
|
||||
append out $char
|
||||
continue
|
||||
}
|
||||
|
||||
if {$char == "(" && !$inQuotes} {
|
||||
set char \{
|
||||
}
|
||||
|
||||
if {$char == ")" && !$inQuotes} {
|
||||
set char \}
|
||||
}
|
||||
|
||||
if {$char == "\""} {
|
||||
set inQuotes [expr !$inQuotes]
|
||||
}
|
||||
|
||||
append out $char
|
||||
}
|
||||
return $out
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: processLine
|
||||
# %ARGUMENTS:
|
||||
# line -- a line read from a cm file
|
||||
# %RETURNS:
|
||||
# Nothing
|
||||
# %DESCRIPTION:
|
||||
# Processes a single line from the file, possibly writing a reminder
|
||||
# in Remind format to stdout
|
||||
#***********************************************************************
|
||||
proc processLine { line } {
|
||||
global Attributes
|
||||
global FullMonth
|
||||
|
||||
catch {unset Attributes}
|
||||
|
||||
# Only convert lines which start with "(add"
|
||||
if {[string range $line 0 3] != "(add"} {
|
||||
return
|
||||
}
|
||||
set line [convertParens $line]
|
||||
# Convert it to a list. CAREFUL: Potential security problem if
|
||||
# $line contains something nasty.
|
||||
|
||||
eval set line $line
|
||||
|
||||
set Attributes(body) ""
|
||||
foreach {key val} $line {
|
||||
switch -exact -- $key {
|
||||
"add" {
|
||||
set Attributes(date) $val
|
||||
}
|
||||
"what:" {
|
||||
append Attributes(body) $val
|
||||
}
|
||||
"details:" {
|
||||
append Attributes(body) $val
|
||||
}
|
||||
"duration:" {
|
||||
set Attributes(duration) $val
|
||||
}
|
||||
"period:" {
|
||||
set Attributes(period) $val
|
||||
}
|
||||
"ntimes:" {
|
||||
set Attributes(ntimes) $val
|
||||
}
|
||||
"attributes:" {
|
||||
set Attributes(action) $val
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if {[info exists Attributes(action)]} {
|
||||
# Nuke quotes and commas in action
|
||||
regsub -all {[,\"]} $Attributes(action) { } Attributes(action)
|
||||
|
||||
# Add spaces to pairs
|
||||
regsub -all \}\{ $Attributes(action) \}\ \{ Attributes(action)
|
||||
|
||||
# Add another pair of brackets to make a proper list
|
||||
set Attributes(action) "{$Attributes(action)}"
|
||||
|
||||
# Convert to a real Tcl list
|
||||
eval set Attributes(action) $Attributes(action)
|
||||
}
|
||||
# Split out date into month, day, year, time parts
|
||||
scan $Attributes(date) "%s%s%s%s%s" wkday month day time year
|
||||
set time [string range $time 0 4]
|
||||
set Attributes(wkday) $wkday
|
||||
set Attributes(month) $FullMonth($month)
|
||||
set Attributes(day) $day
|
||||
set Attributes(time) $time
|
||||
set Attributes(year) $year
|
||||
|
||||
# Convert newlines in body to spaces
|
||||
set body $Attributes(body)
|
||||
regsub -all "\n" $body " " body
|
||||
|
||||
# TODO: Escape BODY to get rid of [] chars.
|
||||
set Attributes(body) $body
|
||||
|
||||
# Convert to Reminder format
|
||||
convertReminder
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: convertReminder
|
||||
# %ARGUMENTS:
|
||||
# None -- uses global Attributes variable which must be filled in
|
||||
# %RETURNS:
|
||||
# Nothing
|
||||
# %DESCRIPTION:
|
||||
# Converts a reminder to Remind format.
|
||||
#***********************************************************************
|
||||
proc convertReminder {} {
|
||||
global Attributes
|
||||
switch -exact $Attributes(period) {
|
||||
single { convertSingleReminder }
|
||||
daily { convertDailyReminder }
|
||||
weekly { convertWeeklyReminder }
|
||||
monthly { convertMonthlyReminder }
|
||||
yearly { convertYearlyReminder }
|
||||
default {
|
||||
puts "\# Unable to convert reminder with period $Attributes(period)"
|
||||
puts "\# Body is: $Attributes(body)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: convertSingleReminder
|
||||
# %ARGUMENTS:
|
||||
# None -- uses global Attributes variable which must be filled in
|
||||
# %RETURNS:
|
||||
# Nothing
|
||||
# %DESCRIPTION:
|
||||
# Converts a reminder with "single" period to Remind format.
|
||||
#***********************************************************************
|
||||
proc convertSingleReminder {} {
|
||||
global Attributes
|
||||
puts "REM $Attributes(day) $Attributes(month) $Attributes(year) [at][duration]MSG $Attributes(body)"
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: convertDailyReminder
|
||||
# %ARGUMENTS:
|
||||
# None -- uses global Attributes variable which must be filled in
|
||||
# %RETURNS:
|
||||
# Nothing
|
||||
# %DESCRIPTION:
|
||||
# Converts a reminder with "daily" period to Remind format.
|
||||
#***********************************************************************
|
||||
proc convertDailyReminder {} {
|
||||
global Attributes
|
||||
set ntimes [expr $Attributes(ntimes) - 1]
|
||||
if {$ntimes <= 1} {
|
||||
convertSingleReminder
|
||||
return
|
||||
}
|
||||
set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) $ntimes]
|
||||
|
||||
puts "REM $Attributes(day) $Attributes(month) $Attributes(year) *1 [at][duration]UNTIL $until MSG $Attributes(body)"
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: convertWeeklyReminder
|
||||
# %ARGUMENTS:
|
||||
# None -- uses global Attributes variable which must be filled in
|
||||
# %RETURNS:
|
||||
# Nothing
|
||||
# %DESCRIPTION:
|
||||
# Converts a reminder with "daily" period to Remind format.
|
||||
#***********************************************************************
|
||||
proc convertWeeklyReminder {} {
|
||||
global Attributes
|
||||
set ntimes [expr $Attributes(ntimes) - 1]
|
||||
if {$ntimes <= 1} {
|
||||
convertSingleReminder
|
||||
return
|
||||
}
|
||||
set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) [expr $ntimes * 7]]
|
||||
|
||||
puts "REM $Attributes(day) $Attributes(month) $Attributes(year) *7 [at][duration]UNTIL $until MSG $Attributes(body)"
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: convertMonthlyReminder
|
||||
# %ARGUMENTS:
|
||||
# None -- uses global Attributes variable which must be filled in
|
||||
# %RETURNS:
|
||||
# Nothing
|
||||
# %DESCRIPTION:
|
||||
# Converts a reminder with "monthly" period to Remind format.
|
||||
#***********************************************************************
|
||||
proc convertMonthlyReminder {} {
|
||||
global Attributes
|
||||
set ntimes [expr $Attributes(ntimes) - 1]
|
||||
if {$ntimes <= 1} {
|
||||
convertSingleReminder
|
||||
return
|
||||
}
|
||||
|
||||
# If repetition > 1000, it's infinite
|
||||
if {$ntimes > 1000} {
|
||||
puts "REM $Attributes(day) [at][duration]MSG $Attributes(body)"
|
||||
return
|
||||
}
|
||||
|
||||
### UNTIL date is fudged!
|
||||
set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) [expr $ntimes * 30]]
|
||||
|
||||
puts "REM $Attributes(day) [at][duration]UNTIL $until MSG $Attributes(body)"
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: convertYearlyReminder
|
||||
# %ARGUMENTS:
|
||||
# None -- uses global Attributes variable which must be filled in
|
||||
# %RETURNS:
|
||||
# Nothing
|
||||
# %DESCRIPTION:
|
||||
# Converts a reminder with "yearly" period to Remind format.
|
||||
#***********************************************************************
|
||||
proc convertYearlyReminder {} {
|
||||
global Attributes
|
||||
|
||||
# No special handling of ntimes et al.
|
||||
puts "REM $Attributes(day) $Attributes(month) [at][duration]MSG $Attributes(body)"
|
||||
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: at
|
||||
# %ARGUMENTS:
|
||||
# None -- uses Attributes global variable
|
||||
# %RETURNS:
|
||||
# A string providing the correct AT clause for a timed reminder.
|
||||
#***********************************************************************
|
||||
proc at {} {
|
||||
global Attributes
|
||||
if {![info exists Attributes(time)]} {
|
||||
return ""
|
||||
}
|
||||
if {"$Attributes(time)" == ""} {
|
||||
return ""
|
||||
}
|
||||
|
||||
return "AT $Attributes(time) "
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: duration
|
||||
# %ARGUMENTS:
|
||||
# None -- uses Attributes global variable
|
||||
# %RETURNS:
|
||||
# A string providing the correct DURATION clause for a timed reminder.
|
||||
#***********************************************************************
|
||||
proc duration {} {
|
||||
global Attributes
|
||||
if {![info exists Attributes(duration)]} {
|
||||
return ""
|
||||
}
|
||||
if {"$Attributes(duration)" == ""} {
|
||||
return ""
|
||||
}
|
||||
set h [expr $Attributes(duration) / 3600]
|
||||
set remainder [expr $Attributes(duration) - $h*3600]
|
||||
set m [expr $remainder / 60]
|
||||
return "DURATION [format "%d:%02d " $h $m]"
|
||||
}
|
||||
|
||||
#***********************************************************************
|
||||
# %PROCEDURE: getUntilDate
|
||||
# %ARGUMENTS:
|
||||
# day, month, year -- a date
|
||||
# days -- number of days to add to date
|
||||
# %RETURNS:
|
||||
# The date which is "days" later than supplied date in a correct UNTIL
|
||||
# format.
|
||||
#***********************************************************************
|
||||
proc getUntilDate { day month year days } {
|
||||
global RemindPipe
|
||||
global MonthNum
|
||||
set date "'$year/$MonthNum($month)/$day'"
|
||||
puts $RemindPipe "MSG \[trigger($date + $days)\]%"
|
||||
puts $RemindPipe "flush"
|
||||
flush $RemindPipe
|
||||
gets $RemindPipe line
|
||||
return $line
|
||||
}
|
||||
|
||||
catch {wm withdraw .}
|
||||
# Start a Remind process to issue reminders
|
||||
if {[catch {set RemindPipe [open "|remind -" "r+"]} err]} {
|
||||
puts stderr "Error: Cannot run Remind: $err"
|
||||
exit 1
|
||||
}
|
||||
|
||||
puts $RemindPipe "banner %"
|
||||
flush $RemindPipe
|
||||
|
||||
# Write some blurb
|
||||
puts "\# Reminder file converted from \"cm\" data by cm2rem.tcl"
|
||||
puts ""
|
||||
|
||||
while {[gets stdin line] >= 0} {
|
||||
processLine $line
|
||||
}
|
||||
exit 0
|
||||
1483
scripts/tkremind
@@ -18,11 +18,10 @@ INSTALL_PROGRAM=@INSTALL_PROGRAM@
|
||||
INSTALL_DATA=@INSTALL_DATA@
|
||||
|
||||
PROGS= remind rem2ps
|
||||
SCRIPTS= $(srcdir)/../scripts/tkremind $(srcdir)/../scripts/cm2rem.tcl
|
||||
SCRIPTS= $(srcdir)/../scripts/tkremind
|
||||
|
||||
MANS= $(srcdir)/../man/rem2ps.1 $(srcdir)/../man/remind.1 \
|
||||
$(srcdir)/../man/tkremind.1 $(srcdir)/../man/cm2rem.1 \
|
||||
$(srcdir)/../man/rem.1
|
||||
$(srcdir)/../man/tkremind.1 $(srcdir)/../man/rem.1
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
@@ -43,8 +42,10 @@ test: remind
|
||||
.c.o:
|
||||
@CC@ -c @CPPFLAGS@ @CFLAGS@ @DEFS@ $(CEXTRA) $(LANGDEF) -I. -I$(srcdir) $<
|
||||
|
||||
rem2ps: rem2ps.o dynbuf.o
|
||||
@CC@ @LDFLAGS@ $(LDEXTRA) -o rem2ps rem2ps.o dynbuf.o
|
||||
$(REMINDOBJS): $(REMINDHDRS)
|
||||
|
||||
rem2ps: rem2ps.o dynbuf.o json.o
|
||||
@CC@ @LDFLAGS@ $(LDEXTRA) -o rem2ps rem2ps.o dynbuf.o json.o -lm
|
||||
|
||||
remind: $(REMINDOBJS)
|
||||
@CC@ @LDFLAGS@ $(LDEXTRA) -o remind $(REMINDOBJS) @LIBS@
|
||||
@@ -72,23 +73,21 @@ clobber:
|
||||
rm -f *.o *~ remind rem2ps test.out core *.bak
|
||||
|
||||
depend:
|
||||
gccmakedep @DEFS@ $(REMINDSRCS) rem2ps.c
|
||||
gccmakedep @DEFS@ $(REMINDSRCS) rem2ps.c json.c
|
||||
|
||||
# The next targets are not very useful to you. I use them to build
|
||||
# distributions, etc.
|
||||
|
||||
# Build a tar file based on all files checked into git.
|
||||
distro:
|
||||
ln -s . ../remind-$(VERSION)
|
||||
(cd ..; git ls-files | fgrep -v .gitignore | fgrep -v remind.php) | sed -e 's/^/remind-$(VERSION)\//' | xargs tar -C .. -cvf remind-$(VERSION).tar
|
||||
cd .. && git archive --worktree-attributes --format=tar --prefix=remind-$(VERSION)/ HEAD > src/remind-$(VERSION).tar
|
||||
gzip -f -v -9 remind-$(VERSION).tar
|
||||
rm -f ../remind-$(VERSION)
|
||||
gpg --detach-sign -u dianne@skoll.ca remind-$(VERSION).tar.gz
|
||||
|
||||
beta-tgz:
|
||||
ln -s . ../remind-$(VERSION)-BETA-$(BETA)
|
||||
(cd ..; git ls-files | fgrep -v .gitignore | fgrep -v remind.php) | sed -e 's/^/remind-$(VERSION)-BETA-$(BETA)\//' | xargs tar -C .. -cvf remind-$(VERSION)-BETA-$(BETA).tar
|
||||
cd .. && git archive --worktree-attributes --format=tar --prefix=remind-$(VERSION)-BETA-$(BETA)/ HEAD > src/remind-$(VERSION)-BETA-$(BETA).tar
|
||||
gzip -f -v -9 remind-$(VERSION)-BETA-$(BETA).tar
|
||||
rm -f ../remind-$(VERSION)-BETA-$(BETA)
|
||||
gpg --detach-sign -u dianne@skoll.ca remind-$(VERSION)-BETA-$(BETA).tar.gz
|
||||
|
||||
#---------------- Stuff after this added by "make depend" -----------------
|
||||
|
||||
|
||||
857
src/calendar.c
@@ -10,6 +10,9 @@
|
||||
/* Define if you have the <sys/file.h> header file. */
|
||||
#undef HAVE_SYS_FILE_H
|
||||
|
||||
/* Define if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define if you have the <glob.h> header file */
|
||||
#undef HAVE_GLOB_H
|
||||
|
||||
@@ -21,6 +24,8 @@
|
||||
|
||||
#undef HAVE_SETENV
|
||||
|
||||
#undef HAVE_INITGROUPS
|
||||
|
||||
#undef HAVE_UNSETENV
|
||||
|
||||
#undef HAVE_MBSTOWCS
|
||||
|
||||
15
src/custom.h
@@ -6,7 +6,7 @@
|
||||
/* which you can customize. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
/* The default values are initially set to Ottawa, Ontario, Canada. */
|
||||
/*---------------------------------------------------------------------*/
|
||||
#define LAT_DEG 45
|
||||
#define LAT_MIN 24
|
||||
#define LAT_SEC 0
|
||||
#define LAT_MIN 25
|
||||
#define LAT_SEC 30
|
||||
#define LON_DEG 75
|
||||
#define LON_MIN 39
|
||||
#define LON_SEC 0
|
||||
#define LON_MIN 41
|
||||
#define LON_SEC 59
|
||||
#define LOCATION "Ottawa"
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
@@ -146,7 +146,7 @@
|
||||
/* VAR_NAME_LEN: The maximum length of variable names. Don't make it */
|
||||
/* any less than 12. */
|
||||
/*---------------------------------------------------------------------*/
|
||||
#define VAR_NAME_LEN 16
|
||||
#define VAR_NAME_LEN 64
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* MAX_PRT_LEN: The maximum number of characters to print when */
|
||||
@@ -220,6 +220,9 @@
|
||||
#define PSBEGIN "# rem2ps begin"
|
||||
#define PSEND "# rem2ps end"
|
||||
|
||||
#define PSBEGIN2 "# rem2ps2 begin"
|
||||
#define PSEND2 "# rem2ps2 end"
|
||||
|
||||
#ifdef BROKEN_PUTC
|
||||
#define Putc SafePutc
|
||||
#define PutChar SafePutChar
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* which you can customize. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
/* The default values are initially set to Ottawa, Ontario, Canada. */
|
||||
/*---------------------------------------------------------------------*/
|
||||
#define LAT_DEG 45
|
||||
#define LAT_MIN 24
|
||||
#define LAT_SEC 0
|
||||
#define LAT_MIN 25
|
||||
#define LAT_SEC 30
|
||||
#define LON_DEG 75
|
||||
#define LON_MIN 39
|
||||
#define LON_SEC 0
|
||||
#define LON_MIN 41
|
||||
#define LON_SEC 59
|
||||
#define LOCATION "Ottawa"
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
@@ -146,7 +146,7 @@
|
||||
/* VAR_NAME_LEN: The maximum length of variable names. Don't make it */
|
||||
/* any less than 12. */
|
||||
/*---------------------------------------------------------------------*/
|
||||
#define VAR_NAME_LEN 16
|
||||
#define VAR_NAME_LEN 64
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* MAX_PRT_LEN: The maximum number of characters to print when */
|
||||
@@ -220,6 +220,9 @@
|
||||
#define PSBEGIN "# rem2ps begin"
|
||||
#define PSEND "# rem2ps end"
|
||||
|
||||
#define PSBEGIN2 "# rem2ps2 begin"
|
||||
#define PSEND2 "# rem2ps2 end"
|
||||
|
||||
#ifdef BROKEN_PUTC
|
||||
#define Putc SafePutc
|
||||
#define PutChar SafePutChar
|
||||
|
||||
227
src/dorem.c
@@ -7,7 +7,7 @@
|
||||
/* commands. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -18,22 +18,29 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "globals.h"
|
||||
#include "err.h"
|
||||
#include "types.h"
|
||||
#include "protos.h"
|
||||
#include "expr.h"
|
||||
|
||||
/* Define the shell characters not to escape */
|
||||
static char const DontEscapeMe[] =
|
||||
"1234567890_-=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.,";
|
||||
|
||||
static int ParseTimeTrig (ParsePtr s, TimeTrig *tim, int save_in_globals);
|
||||
static int ParseLocalOmit (ParsePtr s, Trigger *t);
|
||||
static int ParseScanFrom (ParsePtr s, Trigger *t, int type);
|
||||
static int ParsePriority (ParsePtr s, Trigger *t);
|
||||
static int ParseUntil (ParsePtr s, Trigger *t);
|
||||
static int ShouldTriggerBasedOnWarn (Trigger *t, int jul, int *err);
|
||||
static int ComputeTrigDuration(TimeTrig *t);
|
||||
|
||||
static int
|
||||
ComputeTrigDuration(TimeTrig *t)
|
||||
{
|
||||
if (t->ttime == NO_TIME ||
|
||||
t->duration == NO_TIME) {
|
||||
return 0;
|
||||
}
|
||||
return (t->ttime + t->duration - 1) / MINUTES_PER_DAY;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
@@ -70,6 +77,9 @@ int DoRem(ParsePtr p)
|
||||
PurgeEchoLine("%s\n", CurLine);
|
||||
r=DoSatRemind(&trig, &tim, p);
|
||||
if (r) {
|
||||
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
|
||||
r = OK;
|
||||
}
|
||||
FreeTrig(&trig);
|
||||
if (r == E_EXPIRED) return OK;
|
||||
return r;
|
||||
@@ -117,17 +127,28 @@ int DoRem(ParsePtr p)
|
||||
}
|
||||
} else {
|
||||
/* Calculate the trigger date */
|
||||
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1);
|
||||
jul = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
|
||||
if (r) {
|
||||
if (PurgeMode) {
|
||||
PurgeEchoLine("%s: %s\n", "#!P! Problem calculating trigger date", ErrMsg[r]);
|
||||
PurgeEchoLine("%s\n", CurLine);
|
||||
}
|
||||
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
|
||||
r = OK;
|
||||
}
|
||||
FreeTrig(&trig);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add to global OMITs if so indicated */
|
||||
if (trig.addomit) {
|
||||
r = AddGlobalOmit(jul);
|
||||
if (r) {
|
||||
FreeTrig(&trig);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
if (PurgeMode) {
|
||||
if (trig.expired || jul < JulianToday) {
|
||||
if (p->expr_happened) {
|
||||
@@ -198,16 +219,22 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
trig->localomit = NO_WD;
|
||||
trig->skip = NO_SKIP;
|
||||
trig->once = NO_ONCE;
|
||||
trig->addomit = 0;
|
||||
trig->typ = NO_TYPE;
|
||||
trig->scanfrom = NO_DATE;
|
||||
trig->from = NO_DATE;
|
||||
trig->priority = DefaultPrio;
|
||||
trig->sched[0] = 0;
|
||||
trig->warn[0] = 0;
|
||||
trig->omitfunc[0] = 0;
|
||||
trig->duration_days = 0;
|
||||
trig->eventstart = NO_TIME;
|
||||
trig->eventduration = NO_TIME;
|
||||
trig->maybe_uncomputable = 0;
|
||||
DBufInit(&(trig->tags));
|
||||
trig->passthru[0] = 0;
|
||||
tim->ttime = NO_TIME;
|
||||
tim->delta = NO_DELTA;
|
||||
tim->delta = DefaultTDelta;
|
||||
tim->rep = NO_REP;
|
||||
tim->duration = NO_TIME;
|
||||
if (save_in_globals) {
|
||||
@@ -245,6 +272,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
tim->ttime = (tok.val % MINUTES_PER_DAY);
|
||||
if (save_in_globals) {
|
||||
LastTriggerTime = tim->ttime;
|
||||
SaveLastTimeTrig(tim);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -260,6 +288,11 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
trig->m = tok.val;
|
||||
break;
|
||||
|
||||
case T_MaybeUncomputable:
|
||||
DBufFree(&buf);
|
||||
trig->maybe_uncomputable = 1;
|
||||
break;
|
||||
|
||||
case T_Skip:
|
||||
DBufFree(&buf);
|
||||
if (trig->skip != NO_SKIP) return E_SKIP_ERR;
|
||||
@@ -276,6 +309,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
DBufFree(&buf);
|
||||
r=ParseTimeTrig(s, tim, save_in_globals);
|
||||
if (r) return r;
|
||||
trig->duration_days = ComputeTrigDuration(tim);
|
||||
break;
|
||||
|
||||
case T_Scanfrom:
|
||||
@@ -350,6 +384,11 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
trig->once = ONCE_ONCE;
|
||||
break;
|
||||
|
||||
case T_AddOmit:
|
||||
DBufFree(&buf);
|
||||
trig->addomit = 1;
|
||||
break;
|
||||
|
||||
case T_Omit:
|
||||
DBufFree(&buf);
|
||||
if (trig->omitfunc[0]) {
|
||||
@@ -372,6 +411,10 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
r=ParseToken(s, &buf);
|
||||
if (r) return r;
|
||||
StrnCpy(trig->omitfunc, DBufValue(&buf), VAR_NAME_LEN);
|
||||
|
||||
/* An OMITFUNC counts as a nonconst_expr! */
|
||||
s->expr_happened = 1;
|
||||
s->nonconst_expr = 1;
|
||||
DBufFree(&buf);
|
||||
break;
|
||||
|
||||
@@ -396,7 +439,18 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
switch(tok.type) {
|
||||
case T_Time:
|
||||
case T_LongTime:
|
||||
tim->duration = tok.val;
|
||||
case T_Year:
|
||||
case T_Day:
|
||||
case T_Number:
|
||||
if (tok.val != 0) {
|
||||
tim->duration = tok.val;
|
||||
} else {
|
||||
tim->duration = NO_TIME;
|
||||
}
|
||||
if (save_in_globals) {
|
||||
SaveLastTimeTrig(tim);
|
||||
}
|
||||
trig->duration_days = ComputeTrigDuration(tim);
|
||||
break;
|
||||
default:
|
||||
return E_BAD_TIME;
|
||||
@@ -435,7 +489,7 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
|
||||
{
|
||||
Token tok;
|
||||
int r;
|
||||
|
||||
int seen_delta = 0;
|
||||
DynamicBuffer buf;
|
||||
DBufInit(&buf);
|
||||
|
||||
@@ -452,8 +506,9 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
|
||||
|
||||
case T_Delta:
|
||||
DBufFree(&buf);
|
||||
if (tim->delta != NO_DELTA) return E_DELTA_TWICE;
|
||||
tim->delta = (tok.val > 0) ? tok.val : -tok.val;
|
||||
if (seen_delta) return E_DELTA_TWICE;
|
||||
seen_delta = 1;
|
||||
tim->delta = (tok.val >= 0) ? tok.val : -tok.val;
|
||||
break;
|
||||
|
||||
case T_Rep:
|
||||
@@ -468,6 +523,7 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
|
||||
/* Save trigger time in global variable */
|
||||
if (save_in_globals) {
|
||||
LastTriggerTime = tim->ttime;
|
||||
SaveLastTimeTrig(tim);
|
||||
}
|
||||
PushToken(DBufValue(&buf), s);
|
||||
DBufFree(&buf);
|
||||
@@ -666,6 +722,30 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
|
||||
FromJulian(tok.val, &y, &m, &d);
|
||||
break;
|
||||
|
||||
case T_Back:
|
||||
DBufFree(&buf);
|
||||
if (type != SCANFROM_TYPE) {
|
||||
Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]);
|
||||
return E_INCOMPLETE;
|
||||
}
|
||||
if (y != NO_YR) {
|
||||
Eprint("%s: %s", word, ErrMsg[E_YR_TWICE]);
|
||||
return E_YR_TWICE;
|
||||
}
|
||||
if (m != NO_MON) {
|
||||
Eprint("%s: %s", word, ErrMsg[E_MON_TWICE]);
|
||||
return E_MON_TWICE;
|
||||
}
|
||||
if (d != NO_DAY) {
|
||||
Eprint("%s: %s", word, ErrMsg[E_DAY_TWICE]);
|
||||
return E_DAY_TWICE;
|
||||
}
|
||||
if (tok.val < 0) {
|
||||
tok.val = -tok.val;
|
||||
}
|
||||
FromJulian(JulianToday - tok.val, &y, &m, &d);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
|
||||
Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]);
|
||||
@@ -678,9 +758,12 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
|
||||
}
|
||||
t->scanfrom = Julian(y, m, d);
|
||||
if (type == FROM_TYPE) {
|
||||
t->from = t->scanfrom;
|
||||
if (t->scanfrom < JulianToday) {
|
||||
t->scanfrom = JulianToday;
|
||||
}
|
||||
} else {
|
||||
t->from = NO_DATE;
|
||||
}
|
||||
|
||||
PushToken(DBufValue(&buf), s);
|
||||
@@ -706,20 +789,24 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
|
||||
char const *s;
|
||||
Value v;
|
||||
|
||||
int red = -1, green = -1, blue = -1;
|
||||
int is_color = 0;
|
||||
|
||||
DBufInit(&buf);
|
||||
DBufInit(&calRow);
|
||||
DBufInit(&pre_buf);
|
||||
if (t->typ == RUN_TYPE && RunDisabled) return E_RUN_DISABLED;
|
||||
if ((t->typ == PASSTHRU_TYPE && strcmp(t->passthru, "COLOR") && strcmp(t->passthru, "COLOUR")) ||
|
||||
if ((t->typ == PASSTHRU_TYPE && StrCmpi(t->passthru, "COLOR") && StrCmpi(t->passthru, "COLOUR")) ||
|
||||
t->typ == CAL_TYPE ||
|
||||
t->typ == PS_TYPE ||
|
||||
t->typ == PSF_TYPE)
|
||||
return OK;
|
||||
|
||||
/* Handle COLOR types */
|
||||
if (t->typ == PASSTHRU_TYPE && (!strcmp(t->passthru, "COLOR") || !strcmp(t->passthru, "COLOUR"))) {
|
||||
if (t->typ == PASSTHRU_TYPE && (!StrCmpi(t->passthru, "COLOR") || !StrCmpi(t->passthru, "COLOUR"))) {
|
||||
/* Strip off three tokens */
|
||||
r = ParseToken(p, &buf);
|
||||
sscanf(DBufValue(&buf), "%d", &red);
|
||||
if (!NextMode) {
|
||||
DBufPuts(&pre_buf, DBufValue(&buf));
|
||||
DBufPutc(&pre_buf, ' ');
|
||||
@@ -727,6 +814,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
|
||||
DBufFree(&buf);
|
||||
if (r) return r;
|
||||
r = ParseToken(p, &buf);
|
||||
sscanf(DBufValue(&buf), "%d", &green);
|
||||
if (!NextMode) {
|
||||
DBufPuts(&pre_buf, DBufValue(&buf));
|
||||
DBufPutc(&pre_buf, ' ');
|
||||
@@ -734,6 +822,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
|
||||
DBufFree(&buf);
|
||||
if (r) return r;
|
||||
r = ParseToken(p, &buf);
|
||||
sscanf(DBufValue(&buf), "%d", &blue);
|
||||
if (!NextMode) {
|
||||
DBufPuts(&pre_buf, DBufValue(&buf));
|
||||
DBufPutc(&pre_buf, ' ');
|
||||
@@ -817,6 +906,23 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Correct colors */
|
||||
if (UseVTColors) {
|
||||
if (red == -1 && green == -1 && blue == -1) {
|
||||
if (DefaultColorR != -1 && DefaultColorG != -1 && DefaultColorB != -1) {
|
||||
red = DefaultColorR;
|
||||
green = DefaultColorG;
|
||||
blue = DefaultColorB;
|
||||
}
|
||||
}
|
||||
if (red >= 0 && green >= 0 && blue >= 0) {
|
||||
is_color = 1;
|
||||
if (red > 255) red = 255;
|
||||
if (green > 255) green = 255;
|
||||
if (blue > 255) blue = 255;
|
||||
}
|
||||
}
|
||||
|
||||
/* Put the substituted string into the substitution buffer */
|
||||
|
||||
/* Don't use msgprefix() on RUN-type reminders */
|
||||
@@ -827,6 +933,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
|
||||
r = EvalExpr(&s, &v, NULL);
|
||||
if (!r) {
|
||||
if (!DoCoerce(STR_TYPE, &v)) {
|
||||
if (is_color) {
|
||||
DBufPuts(&buf, Colorize(red, green, blue));
|
||||
}
|
||||
if (DBufPuts(&buf, v.v.str) != OK) {
|
||||
DBufFree(&buf);
|
||||
DestroyValue(v);
|
||||
@@ -838,6 +947,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
|
||||
}
|
||||
}
|
||||
|
||||
if (is_color) {
|
||||
DBufPuts(&buf, Colorize(red, green, blue));
|
||||
}
|
||||
if ( (r=DoSubst(p, &buf, t, tim, jul, NORMAL_MODE)) ) return r;
|
||||
if (t->typ != RUN_TYPE) {
|
||||
if (UserFuncExists("msgsuffix") == 1) {
|
||||
@@ -846,6 +958,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
|
||||
r = EvalExpr(&s, &v, NULL);
|
||||
if (!r) {
|
||||
if (!DoCoerce(STR_TYPE, &v)) {
|
||||
if (is_color) {
|
||||
DBufPuts(&buf, Colorize(red, green, blue));
|
||||
}
|
||||
if (DBufPuts(&buf, v.v.str) != OK) {
|
||||
DBufFree(&buf);
|
||||
DestroyValue(v);
|
||||
@@ -857,6 +972,10 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
|
||||
}
|
||||
}
|
||||
|
||||
if (is_color) {
|
||||
DBufPuts(&buf, Decolorize(red, green, blue));
|
||||
}
|
||||
|
||||
if ((!MsgCommand && t->typ == MSG_TYPE) || t->typ == MSF_TYPE) {
|
||||
if (DBufPutc(&buf, '\n') != OK) {
|
||||
DBufFree(&buf);
|
||||
@@ -891,7 +1010,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
|
||||
break;
|
||||
|
||||
case RUN_TYPE:
|
||||
system(DBufValue(&buf));
|
||||
System(DBufValue(&buf));
|
||||
break;
|
||||
|
||||
default: /* Unknown/illegal type? */
|
||||
@@ -995,21 +1114,35 @@ int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int jul, int *err)
|
||||
/* Do the "satisfying..." remind calculation. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int DoSatRemind(Trigger *trig, TimeTrig *tim, ParsePtr p)
|
||||
int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
|
||||
{
|
||||
int iter, jul, r;
|
||||
int iter, jul, r, start;
|
||||
Value v;
|
||||
char const *s;
|
||||
char const *t;
|
||||
|
||||
t = p->pos;
|
||||
iter = 0;
|
||||
jul = trig->scanfrom;
|
||||
start = trig->scanfrom;
|
||||
while (iter++ < MaxSatIter) {
|
||||
jul = ComputeTrigger(jul, trig, &r, 1);
|
||||
jul = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, 0);
|
||||
if (r) {
|
||||
if (r == E_CANT_TRIG) return OK; else return r;
|
||||
}
|
||||
if (jul != start && trig->duration_days) {
|
||||
jul = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, trig->duration_days);
|
||||
if (r) {
|
||||
if (r == E_CANT_TRIG) return OK; else return r;
|
||||
}
|
||||
} else if (jul == start) {
|
||||
if (tt->ttime != NO_TIME) {
|
||||
trig->eventstart = MINUTES_PER_DAY * r + tt->ttime;
|
||||
if (tt->duration != NO_TIME) {
|
||||
trig->eventduration = tt->duration;
|
||||
}
|
||||
}
|
||||
SaveAllTriggerInfo(trig, tt, jul, tt->ttime, 1);
|
||||
}
|
||||
if (jul == -1) {
|
||||
return E_EXPIRED;
|
||||
}
|
||||
@@ -1018,14 +1151,42 @@ int DoSatRemind(Trigger *trig, TimeTrig *tim, ParsePtr p)
|
||||
t = p->pos;
|
||||
if (r) return r;
|
||||
if (v.type != INT_TYPE && v.type != STR_TYPE) return E_BAD_TYPE;
|
||||
if (v.type == INT_TYPE && v.v.val) return OK;
|
||||
if (v.type == STR_TYPE && *v.v.str) return OK;
|
||||
if ((v.type == INT_TYPE && v.v.val) ||
|
||||
(v.type == STR_TYPE && *v.v.str)) {
|
||||
AdjustTriggerForDuration(trig->scanfrom, jul, trig, tt, 1);
|
||||
if (DebugFlag & DB_PRTTRIG) {
|
||||
int y, m, d;
|
||||
FromJulian(LastTriggerDate, &y, &m, &d);
|
||||
fprintf(ErrFp, "%s(%d): Trig(satisfied) = %s, %d %s, %d",
|
||||
FileName, LineNo,
|
||||
DayName[LastTriggerDate % 7],
|
||||
d,
|
||||
MonthName[m],
|
||||
y);
|
||||
if (tt->ttime != NO_TIME) {
|
||||
fprintf(ErrFp, " AT %02d:%02d",
|
||||
(tt->ttime / 60),
|
||||
(tt->ttime % 60));
|
||||
if (tt->duration != NO_TIME) {
|
||||
fprintf(ErrFp, " DURATION %02d:%02d",
|
||||
(tt->duration / 60),
|
||||
(tt->duration % 60));
|
||||
}
|
||||
}
|
||||
fprintf(ErrFp, "\n");
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
p->pos = s;
|
||||
jul++;
|
||||
if (jul+trig->duration_days < start) {
|
||||
start++;
|
||||
} else {
|
||||
start = jul+trig->duration_days+1;
|
||||
}
|
||||
}
|
||||
p->pos = t;
|
||||
LastTrigValid = 0;
|
||||
return OK;
|
||||
return E_CANT_TRIG;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
@@ -1081,24 +1242,16 @@ int DoMsgCommand(char const *cmd, char const *msg)
|
||||
DynamicBuffer execBuffer;
|
||||
|
||||
DynamicBuffer buf;
|
||||
char const *s;
|
||||
|
||||
DBufInit(&buf);
|
||||
DBufInit(&execBuffer);
|
||||
|
||||
/* Escape shell characters in msg INCLUDING WHITESPACE! */
|
||||
for (s=msg; *s; s++) {
|
||||
if (isspace(*s) || !strchr(DontEscapeMe, *s)) {
|
||||
if (DBufPutc(&buf, '\\') != OK) {
|
||||
r = E_NO_MEM;
|
||||
goto finished;
|
||||
}
|
||||
}
|
||||
if (DBufPutc(&buf, *s) != OK) {
|
||||
r = E_NO_MEM;
|
||||
goto finished;
|
||||
}
|
||||
/* Escape shell characters in msg */
|
||||
if (ShellEscape(msg, &buf) != OK) {
|
||||
r = E_NO_MEM;
|
||||
goto finished;
|
||||
}
|
||||
|
||||
msg = DBufValue(&buf);
|
||||
|
||||
/* Do "%s" substitution */
|
||||
@@ -1119,7 +1272,7 @@ int DoMsgCommand(char const *cmd, char const *msg)
|
||||
}
|
||||
r = OK;
|
||||
|
||||
system(DBufValue(&execBuffer));
|
||||
System(DBufValue(&execBuffer));
|
||||
|
||||
finished:
|
||||
DBufFree(&buf);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* reminders are triggered. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "globals.h"
|
||||
#include "err.h"
|
||||
#include "types.h"
|
||||
#include "protos.h"
|
||||
|
||||
#define UPPER(c) (islower(c) ? toupper(c) : (c))
|
||||
@@ -644,10 +644,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
|
||||
break;
|
||||
|
||||
case '_':
|
||||
if (mode != CAL_MODE && mode != ADVANCE_MODE && !MsgCommand)
|
||||
if (PsCal == PSCAL_LEVEL2 || PsCal == PSCAL_LEVEL3 || (mode != CAL_MODE && mode != ADVANCE_MODE && !MsgCommand)) {
|
||||
sprintf(s, "%s", NL);
|
||||
else
|
||||
} else {
|
||||
sprintf(s, " ");
|
||||
}
|
||||
SHIP_OUT(s);
|
||||
break;
|
||||
|
||||
@@ -656,8 +657,13 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
|
||||
break;
|
||||
|
||||
case '"':
|
||||
if (DBufPutc(dbuf, QUOTE_MARKER) != OK) return E_NO_MEM;
|
||||
has_quote = 1;
|
||||
if (PsCal != PSCAL_LEVEL3) {
|
||||
if (DBufPutc(dbuf, QUOTE_MARKER) != OK) return E_NO_MEM;
|
||||
has_quote = 1;
|
||||
} else {
|
||||
if (DBufPutc(dbuf, '%') != OK) return E_NO_MEM;
|
||||
if (DBufPutc(dbuf, c) != OK) return E_NO_MEM;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
12
src/dynbuf.c
@@ -6,7 +6,7 @@
|
||||
/* buffers. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -27,11 +27,11 @@
|
||||
Doubles the size of dynamic buffer until it has room for at least
|
||||
'n' characters, not including trailing '\0'
|
||||
**********************************************************************/
|
||||
static int DBufMakeRoom(DynamicBuffer *dbuf, int n)
|
||||
static int DBufMakeRoom(DynamicBuffer *dbuf, size_t n)
|
||||
{
|
||||
/* Double size until it's greater than n (strictly > to leave room
|
||||
for trailing '\0' */
|
||||
int size = dbuf->allocatedLen;
|
||||
size_t size = dbuf->allocatedLen;
|
||||
char *buf;
|
||||
|
||||
if (size > n) return OK;
|
||||
@@ -150,7 +150,9 @@ int DBufGets(DynamicBuffer *dbuf, FILE *fp)
|
||||
we can usually save some unnecessary copying */
|
||||
|
||||
*(dbuf->buffer) = 0;
|
||||
fgets(dbuf->buffer, dbuf->allocatedLen, fp);
|
||||
if (fgets(dbuf->buffer, dbuf->allocatedLen, fp) == NULL) {
|
||||
return OK;
|
||||
}
|
||||
if (!*(dbuf->buffer)) return OK;
|
||||
dbuf->len = strlen(dbuf->buffer);
|
||||
l = dbuf->len - 1;
|
||||
@@ -162,7 +164,7 @@ int DBufGets(DynamicBuffer *dbuf, FILE *fp)
|
||||
|
||||
while(busy) {
|
||||
*tmp = 0;
|
||||
fgets(tmp, 256, fp);
|
||||
if (fgets(tmp, 256, fp) == NULL) return OK;
|
||||
if (!*tmp) return OK;
|
||||
l = strlen(tmp) - 1;
|
||||
if (tmp[l] == '\n') {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/* Declaration of functions for manipulating dynamic buffers */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
#define DBUF_STATIC_SIZE 128
|
||||
typedef struct {
|
||||
char *buffer;
|
||||
int len;
|
||||
int allocatedLen;
|
||||
size_t len;
|
||||
size_t allocatedLen;
|
||||
char staticBuf[DBUF_STATIC_SIZE];
|
||||
} DynamicBuffer;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/* Error definitions. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
#define E_NO_MATCHING_REMS 100
|
||||
#define E_STRING_TOO_LONG 101
|
||||
#define E_TIME_TWICE 102
|
||||
#define E_DURATION_NO_AT 103
|
||||
#ifdef MK_GLOBALS
|
||||
#undef EXTERN
|
||||
#define EXTERN
|
||||
@@ -234,7 +235,8 @@ EXTERN char *ErrMsg[]
|
||||
"Can't convert between time zones",
|
||||
"No files matching *.rem",
|
||||
"String too long",
|
||||
"Time specified twice"
|
||||
"Time specified twice",
|
||||
"Cannot specify DURATION without specifying AT"
|
||||
}
|
||||
#endif /* MK_GLOBALS */
|
||||
;
|
||||
|
||||
186
src/expr.c
@@ -5,7 +5,7 @@
|
||||
/* This file contains routines to parse and evaluate */
|
||||
/* expressions. */
|
||||
/* */
|
||||
/* Copyright 1992-2018 by Dianne Skoll */
|
||||
/* Copyright 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -30,7 +31,6 @@
|
||||
#define LE 4
|
||||
#define NE 5
|
||||
|
||||
static char CoerceBuf[512];
|
||||
extern int NumFuncs;
|
||||
|
||||
static int Multiply(void), Divide(void), Mod(void), Add(void),
|
||||
@@ -493,6 +493,8 @@ static int MakeValue(char const *s, Value *v, Var *locals, ParsePtr p)
|
||||
{
|
||||
int len;
|
||||
int h, m, r;
|
||||
int ampm = 0;
|
||||
int prev_val;
|
||||
|
||||
if (*s == '\"') { /* It's a literal string "*/
|
||||
len = strlen(s)-1;
|
||||
@@ -519,9 +521,15 @@ static int MakeValue(char const *s, Value *v, Var *locals, ParsePtr p)
|
||||
return OK;
|
||||
} else if (isdigit(*s)) { /* It's a number - use len to hold it.*/
|
||||
len = 0;
|
||||
prev_val = 0;
|
||||
while (*s && isdigit(*s)) {
|
||||
len *= 10;
|
||||
len += (*s++ - '0');
|
||||
if (len < prev_val) {
|
||||
/* We overflowed */
|
||||
return E_2HIGH;
|
||||
}
|
||||
prev_val = len;
|
||||
}
|
||||
if (*s == ':' || *s == '.' || *s == TimeSep) { /* Must be a literal time */
|
||||
s++;
|
||||
@@ -533,7 +541,27 @@ static int MakeValue(char const *s, Value *v, Var *locals, ParsePtr p)
|
||||
m += *s - '0';
|
||||
s++;
|
||||
}
|
||||
/* Check for p[m] or a[m] */
|
||||
if (*s == 'A' || *s == 'a' || *s == 'P' || *s == 'p') {
|
||||
ampm = tolower(*s);
|
||||
s++;
|
||||
if (*s == 'm' || *s == 'M') {
|
||||
s++;
|
||||
}
|
||||
}
|
||||
if (*s || h>23 || m>59) return E_BAD_TIME;
|
||||
if (ampm) {
|
||||
if (h < 1 || h > 12) return E_BAD_TIME;
|
||||
if (ampm == 'a') {
|
||||
if (h == 12) {
|
||||
h = 0;
|
||||
}
|
||||
} else if (ampm == 'p') {
|
||||
if (h < 12) {
|
||||
h += 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
v->type = TIME_TYPE;
|
||||
v->v.val = h*60 + m;
|
||||
return OK;
|
||||
@@ -578,6 +606,8 @@ int DoCoerce(char type, Value *v)
|
||||
int h, d, m, y, i, k;
|
||||
char const *s;
|
||||
|
||||
char coerce_buf[128];
|
||||
|
||||
/* Do nothing if value is already the right type */
|
||||
if (type == v->type) return OK;
|
||||
|
||||
@@ -605,12 +635,12 @@ int DoCoerce(char type, Value *v)
|
||||
}
|
||||
case STR_TYPE:
|
||||
switch(v->type) {
|
||||
case INT_TYPE: sprintf(CoerceBuf, "%d", v->v.val); break;
|
||||
case TIME_TYPE: sprintf(CoerceBuf, "%02d%c%02d", v->v.val / 60,
|
||||
case INT_TYPE: sprintf(coerce_buf, "%d", v->v.val); break;
|
||||
case TIME_TYPE: sprintf(coerce_buf, "%02d%c%02d", v->v.val / 60,
|
||||
TimeSep, v->v.val % 60);
|
||||
break;
|
||||
case DATE_TYPE: FromJulian(v->v.val, &y, &m, &d);
|
||||
sprintf(CoerceBuf, "%04d%c%02d%c%02d",
|
||||
sprintf(coerce_buf, "%04d%c%02d%c%02d",
|
||||
y, DateSep, m+1, DateSep, d);
|
||||
break;
|
||||
case DATETIME_TYPE:
|
||||
@@ -619,13 +649,13 @@ int DoCoerce(char type, Value *v)
|
||||
k = v->v.val % MINUTES_PER_DAY;
|
||||
h = k / 60;
|
||||
i = k % 60;
|
||||
sprintf(CoerceBuf, "%04d%c%02d%c%02d%c%02d%c%02d",
|
||||
sprintf(coerce_buf, "%04d%c%02d%c%02d%c%02d%c%02d",
|
||||
y, DateSep, m+1, DateSep, d, DateTimeSep, h, TimeSep, i);
|
||||
break;
|
||||
default: return E_CANT_COERCE;
|
||||
}
|
||||
v->type = STR_TYPE;
|
||||
v->v.str = StrDup(CoerceBuf);
|
||||
v->v.str = StrDup(coerce_buf);
|
||||
if (!v->v.str) {
|
||||
v->type = ERR_TYPE;
|
||||
return E_NO_MEM;
|
||||
@@ -700,26 +730,12 @@ int DoCoerce(char type, Value *v)
|
||||
return OK;
|
||||
|
||||
case STR_TYPE:
|
||||
h = 0;
|
||||
m = 0;
|
||||
s = v->v.str;
|
||||
if (!isdigit(*s)) return E_CANT_COERCE;
|
||||
while (isdigit(*s)) {
|
||||
h *= 10;
|
||||
h += *s++ - '0';
|
||||
}
|
||||
if (*s != ':' && *s != '.' && *s != TimeSep)
|
||||
return E_CANT_COERCE;
|
||||
s++;
|
||||
if (!isdigit(*s)) return E_CANT_COERCE;
|
||||
while (isdigit(*s)) {
|
||||
m *= 10;
|
||||
m += *s++ - '0';
|
||||
}
|
||||
if (*s || h>23 || m>59) return E_CANT_COERCE;
|
||||
if (ParseLiteralTime(&s, &i)) return E_CANT_COERCE;
|
||||
if (*s) return E_CANT_COERCE;
|
||||
v->type = TIME_TYPE;
|
||||
free(v->v.str);
|
||||
v->v.val = h*60+m;
|
||||
v->v.val = i;
|
||||
return OK;
|
||||
|
||||
default: return E_CANT_COERCE;
|
||||
@@ -750,35 +766,49 @@ static int Add(void)
|
||||
|
||||
/* If both are ints, just add 'em */
|
||||
if (v2.type == INT_TYPE && v1.type == INT_TYPE) {
|
||||
v2.v.val += v1.v.val;
|
||||
PushValStack(v2);
|
||||
int old = v1.v.val;
|
||||
v1.v.val += v2.v.val;
|
||||
/* Check for overflow */
|
||||
if (_private_add_overflow(v1.v.val, v2.v.val, old)) {
|
||||
return E_2HIGH;
|
||||
}
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* If it's a date plus an int, add 'em */
|
||||
if ((v1.type == DATE_TYPE && v2.type == INT_TYPE) ||
|
||||
(v1.type == INT_TYPE && v2.type == DATE_TYPE)) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val += v2.v.val;
|
||||
if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
if (v1.v.val < 0) return E_DATE_OVER;
|
||||
v1.type = DATE_TYPE;
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* If it's a datetime plus an int, add 'em */
|
||||
if ((v1.type == DATETIME_TYPE && v2.type == INT_TYPE) ||
|
||||
(v1.type == INT_TYPE && v2.type == DATETIME_TYPE)) {
|
||||
/* If it's a datetime plus an int or a time, add 'em */
|
||||
if ((v1.type == DATETIME_TYPE && (v2.type == INT_TYPE || v2.type == TIME_TYPE)) ||
|
||||
((v1.type == INT_TYPE || v1.type == TIME_TYPE) && v2.type == DATETIME_TYPE)) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val += v2.v.val;
|
||||
if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
if (v1.v.val < 0) return E_DATE_OVER;
|
||||
v1.type = DATETIME_TYPE;
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* If it's a time plus an int, add 'em mod MINUTES_PER_DAY */
|
||||
/* If it's a time plus an int or a time plus a time,
|
||||
add 'em mod MINUTES_PER_DAY */
|
||||
if ((v1.type == TIME_TYPE && v2.type == INT_TYPE) ||
|
||||
(v1.type == INT_TYPE && v2.type == TIME_TYPE)) {
|
||||
v1.v.val = (v1.v.val + v2.v.val) % MINUTES_PER_DAY;
|
||||
(v1.type == INT_TYPE && v2.type == TIME_TYPE) ||
|
||||
(v1.type == TIME_TYPE && v2.type == TIME_TYPE)) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val += v2.v.val;
|
||||
if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
v1.v.val = v1.v.val % MINUTES_PER_DAY;
|
||||
if (v1.v.val < 0) v1.v.val += MINUTES_PER_DAY;
|
||||
v1.type = TIME_TYPE;
|
||||
PushValStack(v1);
|
||||
@@ -798,7 +828,7 @@ static int Add(void)
|
||||
v3.type = STR_TYPE;
|
||||
l1 = strlen(v1.v.str);
|
||||
l2 = strlen(v2.v.str);
|
||||
if (MaxStringLen && (l1 + l2 > MaxStringLen)) {
|
||||
if (MaxStringLen > 0 && (l1 + l2 > (size_t) MaxStringLen)) {
|
||||
DestroyValue(v1); DestroyValue(v2);
|
||||
return E_STRING_TOO_LONG;
|
||||
}
|
||||
@@ -808,7 +838,7 @@ static int Add(void)
|
||||
return E_NO_MEM;
|
||||
}
|
||||
strcpy(v3.v.str, v1.v.str);
|
||||
strcat(v3.v.str, v2.v.str);
|
||||
strcpy(v3.v.str+l1, v2.v.str);
|
||||
DestroyValue(v1); DestroyValue(v2);
|
||||
PushValStack(v3);
|
||||
return OK;
|
||||
@@ -838,22 +868,29 @@ static int Subtract(void)
|
||||
|
||||
/* If they're both INTs, do subtraction */
|
||||
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val -= v2.v.val;
|
||||
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_2HIGH;
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* If it's a date minus an int, do subtraction, checking for underflow */
|
||||
if (v1.type == DATE_TYPE && v2.type == INT_TYPE) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val -= v2.v.val;
|
||||
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
if (v1.v.val < 0) return E_DATE_OVER;
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* If it's a datetime minus an int, do subtraction, checking for underflow */
|
||||
if (v1.type == DATETIME_TYPE && v2.type == INT_TYPE) {
|
||||
/* If it's a datetime minus an int or a time, do subtraction,
|
||||
* checking for underflow */
|
||||
if (v1.type == DATETIME_TYPE && (v2.type == INT_TYPE || v2.type == TIME_TYPE)) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val -= v2.v.val;
|
||||
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
if (v1.v.val < 0) return E_DATE_OVER;
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
@@ -871,7 +908,9 @@ static int Subtract(void)
|
||||
if ((v1.type == TIME_TYPE && v2.type == TIME_TYPE) ||
|
||||
(v1.type == DATETIME_TYPE && v2.type == DATETIME_TYPE) ||
|
||||
(v1.type == DATE_TYPE && v2.type == DATE_TYPE)) {
|
||||
int old = v1.v.val;
|
||||
v1.v.val -= v2.v.val;
|
||||
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
|
||||
v1.type = INT_TYPE;
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
@@ -901,7 +940,16 @@ static int Multiply(void)
|
||||
}
|
||||
|
||||
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
|
||||
/* Prevent floating-point exception */
|
||||
if ((v2.v.val == -1 && v1.v.val == INT_MIN) ||
|
||||
(v1.v.val == -1 && v2.v.val == INT_MIN)) {
|
||||
return E_2HIGH;
|
||||
}
|
||||
int old = v1.v.val;
|
||||
v1.v.val *= v2.v.val;
|
||||
if (v2.v.val != 0) {
|
||||
if (_private_div(v1.v.val, v2.v.val) != old) return E_2HIGH;
|
||||
}
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
}
|
||||
@@ -929,6 +977,10 @@ static int Divide(void)
|
||||
|
||||
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
|
||||
if (v2.v.val == 0) return E_DIV_ZERO;
|
||||
/* This is the only way it can overflow */
|
||||
if (v2.v.val == -1 && v1.v.val == INT_MIN) {
|
||||
return E_2HIGH;
|
||||
}
|
||||
v1.v.val /= v2.v.val;
|
||||
PushValStack(v1);
|
||||
return OK;
|
||||
@@ -1103,7 +1155,9 @@ static int UnMinus(void)
|
||||
{
|
||||
Value *v = &ValStack[ValStackPtr-1];
|
||||
if (v->type != INT_TYPE) return E_BAD_TYPE;
|
||||
int old = v->v.val;
|
||||
v->v.val = -v->v.val;
|
||||
if (_private_unminus_overflow(old, v->v.val)) return E_2HIGH;
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -1218,6 +1272,48 @@ int CopyValue(Value *dest, const Value *src)
|
||||
return OK;
|
||||
}
|
||||
|
||||
int ParseLiteralTime(char const **s, int *tim)
|
||||
{
|
||||
int h=0;
|
||||
int m=0;
|
||||
int ampm=0;
|
||||
if (!isdigit(**s)) return E_BAD_TIME;
|
||||
while(isdigit(**s)) {
|
||||
h *= 10;
|
||||
h += *(*s)++ - '0';
|
||||
}
|
||||
if (**s != ':' && **s != '.' && **s != TimeSep) return E_BAD_TIME;
|
||||
(*s)++;
|
||||
if (!isdigit(**s)) return E_BAD_TIME;
|
||||
while(isdigit(**s)) {
|
||||
m *= 10;
|
||||
m += *(*s)++ - '0';
|
||||
}
|
||||
/* Check for p[m] or a[m] */
|
||||
if (**s == 'A' || **s == 'a' || **s == 'P' || **s == 'p') {
|
||||
ampm = tolower(**s);
|
||||
(*s)++;
|
||||
if (**s == 'm' || **s == 'M') {
|
||||
(*s)++;
|
||||
}
|
||||
}
|
||||
if (h>23 || m>59) return E_BAD_TIME;
|
||||
if (ampm) {
|
||||
if (h < 1 || h > 12) return E_BAD_TIME;
|
||||
if (ampm == 'a') {
|
||||
if (h == 12) {
|
||||
h = 0;
|
||||
}
|
||||
} else if (ampm == 'p') {
|
||||
if (h < 12) {
|
||||
h += 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
*tim = h * 60 + m;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* ParseLiteralDate */
|
||||
@@ -1229,10 +1325,9 @@ int CopyValue(Value *dest, const Value *src)
|
||||
int ParseLiteralDate(char const **s, int *jul, int *tim)
|
||||
{
|
||||
int y, m, d;
|
||||
int hour, min;
|
||||
int r;
|
||||
|
||||
y=0; m=0; d=0;
|
||||
hour=0; min=0;
|
||||
|
||||
*tim = NO_TIME;
|
||||
if (!isdigit(**s)) return E_BAD_DATE;
|
||||
@@ -1262,20 +1357,9 @@ int ParseLiteralDate(char const **s, int *jul, int *tim)
|
||||
/* Do we have a time part as well? */
|
||||
if (**s == ' ' || **s == '@' || **s == 'T' || **s == 't') {
|
||||
(*s)++;
|
||||
while(isdigit(**s)) {
|
||||
hour *= 10;
|
||||
hour += *(*s)++ - '0';
|
||||
}
|
||||
if (**s != ':' && **s != '.' && **s != TimeSep) return E_BAD_TIME;
|
||||
(*s)++;
|
||||
while(isdigit(**s)) {
|
||||
min *= 10;
|
||||
min += *(*s)++ - '0';
|
||||
}
|
||||
if (hour > 23 || min > 59) return E_BAD_TIME;
|
||||
*tim = hour * 60 + min;
|
||||
r = ParseLiteralTime(s, tim);
|
||||
if (r != OK) return r;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
11
src/expr.h
@@ -5,7 +5,7 @@
|
||||
/* Contains a few definitions used by expression evaluator. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -53,3 +53,12 @@ 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_div(int a, int b);
|
||||
extern int _private_add_overflow(int result, int b, int old);
|
||||
extern int _private_sub_overflow(int result, int b, int old);
|
||||
extern int _private_unminus_overflow(int a, int b);
|
||||
|
||||
336
src/files.c
@@ -7,7 +7,7 @@
|
||||
/* files. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -40,8 +40,9 @@
|
||||
#include "err.h"
|
||||
|
||||
|
||||
/* Convenient macro for closing files */
|
||||
/* Convenient macros for closing files */
|
||||
#define FCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL))
|
||||
#define PCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (pclose(fp),(fp)=NULL) : ((fp)=NULL))
|
||||
|
||||
/* Define the structures needed by the file caching system */
|
||||
typedef struct cache {
|
||||
@@ -91,12 +92,12 @@ static FILE *fp;
|
||||
static IncludeStruct IStack[INCLUDE_NEST];
|
||||
static int IStackPtr = 0;
|
||||
|
||||
static int ReadLineFromFile (void);
|
||||
static int CacheFile (char const *fname);
|
||||
static int ReadLineFromFile (int use_pclose);
|
||||
static int CacheFile (char const *fname, int use_pclose);
|
||||
static void DestroyCache (CachedFile *cf);
|
||||
static int CheckSafety (void);
|
||||
static int PopFile (void);
|
||||
|
||||
static int IncludeCmd(char const *);
|
||||
static void OpenPurgeFile(char const *fname, char const *mode)
|
||||
{
|
||||
DynamicBuffer fname_buf;
|
||||
@@ -167,7 +168,7 @@ int ReadLine(void)
|
||||
}
|
||||
|
||||
/* Not cached. Read from the file. */
|
||||
return ReadLineFromFile();
|
||||
return ReadLineFromFile(0);
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
@@ -177,7 +178,7 @@ int ReadLine(void)
|
||||
/* Read a line from the file pointed to by fp. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static int ReadLineFromFile(void)
|
||||
static int ReadLineFromFile(int use_pclose)
|
||||
{
|
||||
int l;
|
||||
char copy_buffer[4096];
|
||||
@@ -200,7 +201,11 @@ static int ReadLineFromFile(void)
|
||||
return E_IO_ERR;
|
||||
}
|
||||
if (feof(fp)) {
|
||||
FCLOSE(fp);
|
||||
if (use_pclose) {
|
||||
PCLOSE(fp);
|
||||
} else {
|
||||
FCLOSE(fp);
|
||||
}
|
||||
if ((DBufLen(&buf) == 0) &&
|
||||
(DBufLen(&LineBuffer) == 0) && PurgeMode) {
|
||||
if (PurgeFP != NULL && PurgeFP != stdout) fclose(PurgeFP);
|
||||
@@ -248,7 +253,11 @@ static int ReadLineFromFile(void)
|
||||
if (PurgeFP != stdout) fclose(PurgeFP);
|
||||
PurgeFP = NULL;
|
||||
}
|
||||
FCLOSE(fp);
|
||||
if (use_pclose) {
|
||||
PCLOSE(fp);
|
||||
} else {
|
||||
FCLOSE(fp);
|
||||
}
|
||||
DBufFree(&LineBuffer);
|
||||
CurLine = DBufValue(&LineBuffer);
|
||||
}
|
||||
@@ -282,9 +291,6 @@ int OpenFile(char const *fname)
|
||||
PurgeFP = NULL;
|
||||
}
|
||||
|
||||
/* Assume we own the file for now */
|
||||
RunDisabled &= ~RUN_NOTOWNER;
|
||||
|
||||
/* If it's in the cache, get it from there. */
|
||||
|
||||
while (h) {
|
||||
@@ -297,7 +303,9 @@ int OpenFile(char const *fname)
|
||||
LineNo = 0;
|
||||
if (!h->ownedByMe) {
|
||||
RunDisabled |= RUN_NOTOWNER;
|
||||
}
|
||||
} else {
|
||||
RunDisabled &= ~RUN_NOTOWNER;
|
||||
}
|
||||
if (FileName) return OK; else return E_NO_MEM;
|
||||
}
|
||||
h = h->next;
|
||||
@@ -306,6 +314,7 @@ int OpenFile(char const *fname)
|
||||
/* If it's a dash, then it's stdin */
|
||||
if (!strcmp(fname, "-")) {
|
||||
fp = stdin;
|
||||
RunDisabled &= ~RUN_NOTOWNER;
|
||||
if (PurgeMode) {
|
||||
PurgeFP = stdout;
|
||||
}
|
||||
@@ -325,7 +334,7 @@ int OpenFile(char const *fname)
|
||||
CLine = NULL;
|
||||
if (ShouldCache) {
|
||||
LineNo = 0;
|
||||
r = CacheFile(fname);
|
||||
r = CacheFile(fname, 0);
|
||||
if (r == OK) {
|
||||
fp = NULL;
|
||||
CLine = CachedFiles->cache;
|
||||
@@ -353,7 +362,7 @@ int OpenFile(char const *fname)
|
||||
/* Returns an indication of success or failure. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static int CacheFile(char const *fname)
|
||||
static int CacheFile(char const *fname, int use_pclose)
|
||||
{
|
||||
int r;
|
||||
CachedFile *cf;
|
||||
@@ -366,16 +375,24 @@ static int CacheFile(char const *fname)
|
||||
cl = NULL;
|
||||
/* Create a file header */
|
||||
cf = NEW(CachedFile);
|
||||
cf->cache = NULL;
|
||||
if (!cf) {
|
||||
ShouldCache = 0;
|
||||
FCLOSE(fp);
|
||||
if (use_pclose) {
|
||||
PCLOSE(fp);
|
||||
} else {
|
||||
FCLOSE(fp);
|
||||
}
|
||||
return E_NO_MEM;
|
||||
}
|
||||
cf->cache = NULL;
|
||||
cf->filename = StrDup(fname);
|
||||
if (!cf->filename) {
|
||||
ShouldCache = 0;
|
||||
FCLOSE(fp);
|
||||
if (use_pclose) {
|
||||
PCLOSE(fp);
|
||||
} else {
|
||||
FCLOSE(fp);
|
||||
}
|
||||
free(cf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
@@ -388,11 +405,15 @@ static int CacheFile(char const *fname)
|
||||
|
||||
/* Read the file */
|
||||
while(fp) {
|
||||
r = ReadLineFromFile();
|
||||
r = ReadLineFromFile(use_pclose);
|
||||
if (r) {
|
||||
DestroyCache(cf);
|
||||
ShouldCache = 0;
|
||||
FCLOSE(fp);
|
||||
if (use_pclose) {
|
||||
PCLOSE(fp);
|
||||
} else {
|
||||
FCLOSE(fp);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
/* Skip blank chars */
|
||||
@@ -406,7 +427,11 @@ static int CacheFile(char const *fname)
|
||||
DBufFree(&LineBuffer);
|
||||
DestroyCache(cf);
|
||||
ShouldCache = 0;
|
||||
FCLOSE(fp);
|
||||
if (use_pclose) {
|
||||
PCLOSE(fp);
|
||||
} else {
|
||||
FCLOSE(fp);
|
||||
}
|
||||
return E_NO_MEM;
|
||||
}
|
||||
cl = cf->cache;
|
||||
@@ -416,7 +441,11 @@ static int CacheFile(char const *fname)
|
||||
DBufFree(&LineBuffer);
|
||||
DestroyCache(cf);
|
||||
ShouldCache = 0;
|
||||
FCLOSE(fp);
|
||||
if (use_pclose) {
|
||||
PCLOSE(fp);
|
||||
} else {
|
||||
FCLOSE(fp);
|
||||
}
|
||||
return E_NO_MEM;
|
||||
}
|
||||
cl = cl->next;
|
||||
@@ -428,7 +457,11 @@ static int CacheFile(char const *fname)
|
||||
if (!cl->text) {
|
||||
DestroyCache(cf);
|
||||
ShouldCache = 0;
|
||||
FCLOSE(fp);
|
||||
if (use_pclose) {
|
||||
PCLOSE(fp);
|
||||
} else {
|
||||
FCLOSE(fp);
|
||||
}
|
||||
return E_NO_MEM;
|
||||
}
|
||||
}
|
||||
@@ -471,9 +504,6 @@ static int PopFile(void)
|
||||
{
|
||||
IncludeStruct *i;
|
||||
|
||||
/* Assume we own the file for now */
|
||||
RunDisabled &= ~RUN_NOTOWNER;
|
||||
|
||||
if (!Hush && NumIfs) Eprint("%s", ErrMsg[E_MISS_ENDIF]);
|
||||
if (!IStackPtr) return E_EOF;
|
||||
i = &IStack[IStackPtr-1];
|
||||
@@ -500,8 +530,10 @@ static int PopFile(void)
|
||||
STRSET(FileName, i->filename);
|
||||
if (!i->ownedByMe) {
|
||||
RunDisabled |= RUN_NOTOWNER;
|
||||
} else {
|
||||
RunDisabled &= ~RUN_NOTOWNER;
|
||||
}
|
||||
if (!CLine && (i->offset != -1L)) {
|
||||
if (!CLine && (i->offset != -1L || !strcmp(i->filename, "-"))) {
|
||||
/* We must open the file, then seek to specified position */
|
||||
if (strcmp(i->filename, "-")) {
|
||||
fp = fopen(i->filename, "r");
|
||||
@@ -525,16 +557,119 @@ static int PopFile(void)
|
||||
/* The INCLUDE command. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int DoInclude(ParsePtr p)
|
||||
int DoInclude(ParsePtr p, enum TokTypes tok)
|
||||
{
|
||||
DynamicBuffer buf;
|
||||
DynamicBuffer fullname;
|
||||
DynamicBuffer path;
|
||||
int r, e;
|
||||
|
||||
r = OK;
|
||||
char const *s;
|
||||
DBufInit(&buf);
|
||||
DBufInit(&fullname);
|
||||
DBufInit(&path);
|
||||
if ( (r=ParseToken(p, &buf)) ) return r;
|
||||
e = VerifyEoln(p);
|
||||
if (e) Eprint("%s", ErrMsg[e]);
|
||||
if ( (r=IncludeFile(DBufValue(&buf))) ) {
|
||||
|
||||
if (tok == T_IncludeR && *(DBufValue(&buf)) != '/') {
|
||||
/* Relative include: Include relative to dir
|
||||
containing current file */
|
||||
if (DBufPuts(&path, FileName) != OK) {
|
||||
r = E_NO_MEM;
|
||||
goto bailout;
|
||||
}
|
||||
if (DBufLen(&path) == 0) {
|
||||
s = DBufValue(&buf);
|
||||
} else {
|
||||
char *t = DBufValue(&path) + DBufLen(&path) - 1;
|
||||
while (t > DBufValue(&path) && *t != '/') t--;
|
||||
if (*t == '/') {
|
||||
*t = 0;
|
||||
if (DBufPuts(&fullname, DBufValue(&path)) != OK) {
|
||||
r = E_NO_MEM;
|
||||
goto bailout;
|
||||
}
|
||||
if (DBufPuts(&fullname, "/") != OK) {
|
||||
r = E_NO_MEM;
|
||||
goto bailout;
|
||||
}
|
||||
if (DBufPuts(&fullname, DBufValue(&buf)) != OK) {
|
||||
r = E_NO_MEM;
|
||||
goto bailout;
|
||||
}
|
||||
s = DBufValue(&fullname);
|
||||
} else {
|
||||
s = DBufValue(&buf);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s = DBufValue(&buf);
|
||||
}
|
||||
if ( (r=IncludeFile(s)) ) {
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
NumIfs = 0;
|
||||
IfFlags = 0;
|
||||
|
||||
bailout:
|
||||
DBufFree(&buf);
|
||||
DBufFree(&path);
|
||||
DBufFree(&fullname);
|
||||
return r;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* DoIncludeCmd */
|
||||
/* */
|
||||
/* The INCLUDECMD command. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int DoIncludeCmd(ParsePtr p)
|
||||
{
|
||||
DynamicBuffer buf;
|
||||
int r;
|
||||
int ch;
|
||||
char append_buf[2];
|
||||
int seen_nonspace = 0;
|
||||
|
||||
append_buf[1] = 0;
|
||||
|
||||
DBufInit(&buf);
|
||||
|
||||
while(1) {
|
||||
ch = ParseChar(p, &r, 0);
|
||||
if (r) {
|
||||
DBufFree(&buf);
|
||||
return r;
|
||||
}
|
||||
if (!ch) {
|
||||
break;
|
||||
}
|
||||
if (isspace(ch) && !seen_nonspace) {
|
||||
continue;
|
||||
}
|
||||
seen_nonspace = 1;
|
||||
/* Convert \n to ' ' to better handle line continuation */
|
||||
if (ch == '\n') {
|
||||
ch = ' ';
|
||||
}
|
||||
append_buf[0] = (char) ch;
|
||||
if (DBufPuts(&buf, append_buf) != OK) {
|
||||
DBufFree(&buf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (RunDisabled) {
|
||||
DBufFree(&buf);
|
||||
return E_RUN_DISABLED;
|
||||
}
|
||||
|
||||
if ( (r=IncludeCmd(DBufValue(&buf))) ) {
|
||||
DBufFree(&buf);
|
||||
return r;
|
||||
}
|
||||
@@ -664,6 +799,127 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* IncludeCmd */
|
||||
/* */
|
||||
/* Process the INCLUDECMD command - actually do the command */
|
||||
/* inclusion. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static int IncludeCmd(char const *cmd)
|
||||
{
|
||||
IncludeStruct *i;
|
||||
DynamicBuffer buf;
|
||||
FILE *fp2;
|
||||
int r;
|
||||
CachedFile *h;
|
||||
char const *fname;
|
||||
int old_flag;
|
||||
|
||||
FreshLine = 1;
|
||||
if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE;
|
||||
i = &IStack[IStackPtr];
|
||||
|
||||
/* Use "cmd|" as the filename */
|
||||
DBufInit(&buf);
|
||||
if (DBufPuts(&buf, cmd) != OK) {
|
||||
DBufFree(&buf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
if (DBufPuts(&buf, "|") != OK) {
|
||||
DBufFree(&buf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
fname = DBufValue(&buf);
|
||||
|
||||
if (FileName) {
|
||||
i->filename = StrDup(FileName);
|
||||
if (!i->filename) {
|
||||
DBufFree(&buf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
} else {
|
||||
i->filename = NULL;
|
||||
}
|
||||
i->ownedByMe = 1;
|
||||
i->LineNo = LineNo;
|
||||
i->NumIfs = NumIfs;
|
||||
i->IfFlags = IfFlags;
|
||||
i->CLine = CLine;
|
||||
i->offset = -1L;
|
||||
i->chain = NULL;
|
||||
if (fp) {
|
||||
i->offset = ftell(fp);
|
||||
FCLOSE(fp);
|
||||
}
|
||||
IStackPtr++;
|
||||
|
||||
/* If the file is cached, use it */
|
||||
h = CachedFiles;
|
||||
while(h) {
|
||||
if (!strcmp(fname, h->filename)) {
|
||||
if (DebugFlag & DB_TRACE_FILES) {
|
||||
fprintf(ErrFp, "Reading command `%s': Found in cache\n", fname);
|
||||
}
|
||||
CLine = h->cache;
|
||||
STRSET(FileName, fname);
|
||||
DBufFree(&buf);
|
||||
LineNo = 0;
|
||||
if (!h->ownedByMe) {
|
||||
RunDisabled |= RUN_NOTOWNER;
|
||||
} else {
|
||||
RunDisabled &= ~RUN_NOTOWNER;
|
||||
}
|
||||
if (FileName) return OK; else return E_NO_MEM;
|
||||
}
|
||||
h = h->next;
|
||||
}
|
||||
|
||||
if (DebugFlag & DB_TRACE_FILES) {
|
||||
fprintf(ErrFp, "Executing `%s' for INCLUDECMD and caching as `%s'\n",
|
||||
cmd, fname);
|
||||
}
|
||||
|
||||
/* Not found in cache */
|
||||
|
||||
/* If cmd starts with !, then disable RUN within the cmd output */
|
||||
if (cmd[0] == '!') {
|
||||
fp2 = popen(cmd+1, "r");
|
||||
} else {
|
||||
fp2 = popen(cmd, "r");
|
||||
}
|
||||
if (!fp2) {
|
||||
DBufFree(&buf);
|
||||
return E_CANT_OPEN;
|
||||
}
|
||||
fp = fp2;
|
||||
LineNo = 0;
|
||||
|
||||
/* Temporarily turn of file tracing */
|
||||
old_flag = DebugFlag;
|
||||
DebugFlag &= (~DB_TRACE_FILES);
|
||||
|
||||
if (cmd[0] == '!') {
|
||||
RunDisabled |= RUN_NOTOWNER;
|
||||
}
|
||||
r = CacheFile(fname, 1);
|
||||
|
||||
DebugFlag = old_flag;
|
||||
if (r == OK) {
|
||||
fp = NULL;
|
||||
CLine = CachedFiles->cache;
|
||||
LineNo = 0;
|
||||
STRSET(FileName, fname);
|
||||
DBufFree(&buf);
|
||||
return OK;
|
||||
}
|
||||
DBufFree(&buf);
|
||||
/* We failed */
|
||||
PopFile();
|
||||
return E_CANT_OPEN;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* IncludeFile */
|
||||
@@ -828,7 +1084,8 @@ int TopLevel(void)
|
||||
/* root, we refuse to open files not owned by root. */
|
||||
/* We also reject world-writable files, no matter */
|
||||
/* who we're running as. */
|
||||
/* As a side effect, if we don't own the file, we disable RUN */
|
||||
/* As a side effect, if we don't own the file, or it's not */
|
||||
/* owned by a trusted user, we disable RUN */
|
||||
/***************************************************************/
|
||||
static int CheckSafety(void)
|
||||
{
|
||||
@@ -866,9 +1123,22 @@ static int CheckSafety(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If file is not owned by me, disable RUN command */
|
||||
if (statbuf.st_uid != geteuid()) {
|
||||
RunDisabled |= RUN_NOTOWNER;
|
||||
/* If file is not owned by me or a trusted user, disable RUN command */
|
||||
|
||||
/* Assume unsafe */
|
||||
RunDisabled |= RUN_NOTOWNER;
|
||||
if (statbuf.st_uid == geteuid()) {
|
||||
/* Owned by me... safe */
|
||||
RunDisabled &= ~RUN_NOTOWNER;
|
||||
} else {
|
||||
int i;
|
||||
for (i=0; i<NumTrustedUsers; i++) {
|
||||
if (statbuf.st_uid == TrustedUsers[i]) {
|
||||
/* Owned by a trusted user... safe */
|
||||
RunDisabled &= ~RUN_NOTOWNER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
520
src/funcs.c
@@ -6,7 +6,7 @@
|
||||
/* expressions. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -53,94 +53,110 @@
|
||||
#define RetVal (info->retval)
|
||||
|
||||
/* Function prototypes */
|
||||
static int FCurrent (func_info *);
|
||||
static int FNonomitted (func_info *);
|
||||
static int FTimepart(func_info *);
|
||||
static int FDatepart(func_info *);
|
||||
static int FRealCurrent(func_info *);
|
||||
static int FAbs (func_info *);
|
||||
static int FAccess (func_info *);
|
||||
static int FArgs (func_info *);
|
||||
static int FAsc (func_info *);
|
||||
static int FBaseyr (func_info *);
|
||||
static int FChar (func_info *);
|
||||
static int FChoose (func_info *);
|
||||
static int FCoerce (func_info *);
|
||||
static int FDate (func_info *);
|
||||
static int FDateTime (func_info *);
|
||||
static int FDay (func_info *);
|
||||
static int FDaysinmon (func_info *);
|
||||
static int FDefined (func_info *);
|
||||
static int FDosubst (func_info *);
|
||||
static int FEasterdate (func_info *);
|
||||
static int FEvalTrig (func_info *);
|
||||
static int FFiledate (func_info *);
|
||||
static int FFiledatetime (func_info *);
|
||||
static int FFiledir (func_info *);
|
||||
static int FFilename (func_info *);
|
||||
static int FGetenv (func_info *);
|
||||
static int FHebdate (func_info *);
|
||||
static int FHebday (func_info *);
|
||||
static int FHebmon (func_info *);
|
||||
static int FHebyear (func_info *);
|
||||
static int FHour (func_info *);
|
||||
static int FIif (func_info *);
|
||||
static int FIndex (func_info *);
|
||||
static int FIsdst (func_info *);
|
||||
static int FIsomitted (func_info *);
|
||||
static int FSlide (func_info *);
|
||||
static int FLanguage (func_info *);
|
||||
static int FMax (func_info *);
|
||||
static int FMin (func_info *);
|
||||
static int FMinute (func_info *);
|
||||
static int FMinsfromutc (func_info *);
|
||||
static int FMoondate (func_info *);
|
||||
static int FMoondatetime (func_info *);
|
||||
static int FMoonphase (func_info *);
|
||||
static int FMoontime (func_info *);
|
||||
static int FMon (func_info *);
|
||||
static int FMonnum (func_info *);
|
||||
static int FOrd (func_info *);
|
||||
static int FOstype (func_info *);
|
||||
static int FPlural (func_info *);
|
||||
static int FSgn (func_info *);
|
||||
static int FPsmoon (func_info *);
|
||||
static int FPsshade (func_info *);
|
||||
static int FShell (func_info *);
|
||||
static int FStrlen (func_info *);
|
||||
static int FSubstr (func_info *);
|
||||
static int FADawn (func_info *);
|
||||
static int FADusk (func_info *);
|
||||
static int FNDawn (func_info *);
|
||||
static int FNDusk (func_info *);
|
||||
static int FDawn (func_info *);
|
||||
static int FDusk (func_info *);
|
||||
static int FSunset (func_info *);
|
||||
static int FSunrise (func_info *);
|
||||
static int FTime (func_info *);
|
||||
static int FTrigdate (func_info *);
|
||||
static int FTrigdatetime (func_info *);
|
||||
static int FTrigtime (func_info *);
|
||||
static int FTrigvalid (func_info *);
|
||||
static int FTypeof (func_info *);
|
||||
static int FUpper (func_info *);
|
||||
static int FValue (func_info *);
|
||||
static int FVersion (func_info *);
|
||||
static int FWkday (func_info *);
|
||||
static int FWkdaynum (func_info *);
|
||||
static int FYear (func_info *);
|
||||
static int FIsleap (func_info *);
|
||||
static int FLower (func_info *);
|
||||
static int FNow (func_info *);
|
||||
static int FRealnow (func_info *);
|
||||
static int FRealtoday (func_info *);
|
||||
static int FToday (func_info *);
|
||||
static int FTrigger (func_info *);
|
||||
static int FTzconvert (func_info *);
|
||||
static int FWeekno (func_info *);
|
||||
static int CheckArgs (BuiltinFunc *f, int nargs);
|
||||
static int CleanUpAfterFunc (func_info *);
|
||||
static int SunStuff (int rise, double cosz, int jul);
|
||||
static int FADawn (func_info *);
|
||||
static int FADusk (func_info *);
|
||||
static int FAbs (func_info *);
|
||||
static int FAccess (func_info *);
|
||||
static int FAmpm (func_info *);
|
||||
static int FIsAny (func_info *);
|
||||
static int FArgs (func_info *);
|
||||
static int FAsc (func_info *);
|
||||
static int FBaseyr (func_info *);
|
||||
static int FChar (func_info *);
|
||||
static int FChoose (func_info *);
|
||||
static int FCoerce (func_info *);
|
||||
static int FCurrent (func_info *);
|
||||
static int FDate (func_info *);
|
||||
static int FDateTime (func_info *);
|
||||
static int FDatepart (func_info *);
|
||||
static int FDawn (func_info *);
|
||||
static int FDay (func_info *);
|
||||
static int FDaysinmon (func_info *);
|
||||
static int FDefined (func_info *);
|
||||
static int FDosubst (func_info *);
|
||||
static int FDusk (func_info *);
|
||||
static int FEasterdate (func_info *);
|
||||
static int FEvalTrig (func_info *);
|
||||
static int FFiledate (func_info *);
|
||||
static int FFiledatetime (func_info *);
|
||||
static int FFiledir (func_info *);
|
||||
static int FFilename (func_info *);
|
||||
static int FGetenv (func_info *);
|
||||
static int FHebdate (func_info *);
|
||||
static int FHebday (func_info *);
|
||||
static int FHebmon (func_info *);
|
||||
static int FHebyear (func_info *);
|
||||
static int FHour (func_info *);
|
||||
static int FIif (func_info *);
|
||||
static int FIndex (func_info *);
|
||||
static int FIsdst (func_info *);
|
||||
static int FIsleap (func_info *);
|
||||
static int FIsomitted (func_info *);
|
||||
static int FLanguage (func_info *);
|
||||
static int FLower (func_info *);
|
||||
static int FMax (func_info *);
|
||||
static int FMin (func_info *);
|
||||
static int FMinsfromutc (func_info *);
|
||||
static int FMinute (func_info *);
|
||||
static int FMon (func_info *);
|
||||
static int FMonnum (func_info *);
|
||||
static int FMoondate (func_info *);
|
||||
static int FMoondatetime (func_info *);
|
||||
static int FMoonphase (func_info *);
|
||||
static int FMoontime (func_info *);
|
||||
static int FNDawn (func_info *);
|
||||
static int FNDusk (func_info *);
|
||||
static int FNonomitted (func_info *);
|
||||
static int FNow (func_info *);
|
||||
static int FOrd (func_info *);
|
||||
static int FOstype (func_info *);
|
||||
static int FPlural (func_info *);
|
||||
static int FPsmoon (func_info *);
|
||||
static int FPsshade (func_info *);
|
||||
static int FRealCurrent (func_info *);
|
||||
static int FRealnow (func_info *);
|
||||
static int FRealtoday (func_info *);
|
||||
static int FSgn (func_info *);
|
||||
static int FShell (func_info *);
|
||||
static int FSlide (func_info *);
|
||||
static int FStrlen (func_info *);
|
||||
static int FSubstr (func_info *);
|
||||
static int FSunrise (func_info *);
|
||||
static int FSunset (func_info *);
|
||||
static int FTime (func_info *);
|
||||
static int FTimepart (func_info *);
|
||||
static int FToday (func_info *);
|
||||
static int FTrigback (func_info *);
|
||||
static int FTrigdate (func_info *);
|
||||
static int FTrigdatetime (func_info *);
|
||||
static int FTrigdelta (func_info *);
|
||||
static int FTrigduration (func_info *);
|
||||
static int FTrigeventduration(func_info *);
|
||||
static int FTrigeventstart (func_info *);
|
||||
static int FTrigfrom (func_info *);
|
||||
static int FTrigger (func_info *);
|
||||
static int FTrigpriority (func_info *);
|
||||
static int FTrigrep (func_info *);
|
||||
static int FTrigscanfrom (func_info *);
|
||||
static int FTrigtime (func_info *);
|
||||
static int FTrigtimedelta (func_info *);
|
||||
static int FTrigtimerep (func_info *);
|
||||
static int FTriguntil (func_info *);
|
||||
static int FTrigvalid (func_info *);
|
||||
static int FTypeof (func_info *);
|
||||
static int FTzconvert (func_info *);
|
||||
static int FUpper (func_info *);
|
||||
static int FValue (func_info *);
|
||||
static int FVersion (func_info *);
|
||||
static int FWeekno (func_info *);
|
||||
static int FWkday (func_info *);
|
||||
static int FWkdaynum (func_info *);
|
||||
static int FYear (func_info *);
|
||||
static int FShellescape (func_info *);
|
||||
|
||||
static int CleanUpAfterFunc (func_info *);
|
||||
static int CheckArgs (BuiltinFunc *f, int nargs);
|
||||
static int SunStuff (int rise, double cosz, int jul);
|
||||
|
||||
/* "Overload" the struct Operator definition */
|
||||
#define NO_MAX 127
|
||||
@@ -193,6 +209,7 @@ BuiltinFunc Func[] = {
|
||||
{ "access", 2, 2, 0, FAccess },
|
||||
{ "adawn", 0, 1, 0, FADawn},
|
||||
{ "adusk", 0, 1, 0, FADusk},
|
||||
{ "ampm", 1, 3, 1, FAmpm },
|
||||
{ "args", 1, 1, 0, FArgs },
|
||||
{ "asc", 1, 1, 1, FAsc },
|
||||
{ "baseyr", 0, 0, 1, FBaseyr },
|
||||
@@ -223,6 +240,7 @@ BuiltinFunc Func[] = {
|
||||
{ "hour", 1, 1, 1, FHour },
|
||||
{ "iif", 1, NO_MAX, 1, FIif },
|
||||
{ "index", 2, 3, 1, FIndex },
|
||||
{ "isany", 1, NO_MAX, 1, FIsAny },
|
||||
{ "isdst", 0, 2, 0, FIsdst },
|
||||
{ "isleap", 1, 1, 1, FIsleap },
|
||||
{ "isomitted", 1, 1, 0, FIsomitted },
|
||||
@@ -252,6 +270,7 @@ BuiltinFunc Func[] = {
|
||||
{ "realtoday", 0, 0, 0, FRealtoday },
|
||||
{ "sgn", 1, 1, 1, FSgn },
|
||||
{ "shell", 1, 2, 0, FShell },
|
||||
{ "shellescape", 1, 1, 1, FShellescape },
|
||||
{ "slide", 2, NO_MAX, 0, FSlide },
|
||||
{ "strlen", 1, 1, 1, FStrlen },
|
||||
{ "substr", 2, 3, 1, FSubstr },
|
||||
@@ -260,10 +279,22 @@ BuiltinFunc Func[] = {
|
||||
{ "time", 2, 2, 1, FTime },
|
||||
{ "timepart", 1, 1, 1, FTimepart },
|
||||
{ "today", 0, 0, 0, FToday },
|
||||
{ "trigback", 0, 0, 0, FTrigback },
|
||||
{ "trigdate", 0, 0, 0, FTrigdate },
|
||||
{ "trigdatetime", 0, 0, 0, FTrigdatetime },
|
||||
{ "trigdelta", 0, 0, 0, FTrigdelta },
|
||||
{ "trigduration", 0, 0, 0, FTrigduration },
|
||||
{ "trigeventduration", 0, 0, 0, FTrigeventduration },
|
||||
{ "trigeventstart", 0, 0, 0, FTrigeventstart },
|
||||
{ "trigfrom", 0, 0, 0, FTrigfrom },
|
||||
{ "trigger", 1, 3, 0, FTrigger },
|
||||
{ "trigpriority", 0, 0, 0, FTrigpriority },
|
||||
{ "trigrep", 0, 0, 0, FTrigrep },
|
||||
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom },
|
||||
{ "trigtime", 0, 0, 0, FTrigtime },
|
||||
{ "trigtimedelta",0, 0, 0, FTrigtimedelta },
|
||||
{ "trigtimerep", 0, 0, 0, FTrigtimerep },
|
||||
{ "triguntil", 0, 0, 0, FTriguntil },
|
||||
{ "trigvalid", 0, 0, 0, FTrigvalid },
|
||||
{ "typeof", 1, 1, 1, FTypeof },
|
||||
{ "tzconvert", 2, 3, 0, FTzconvert },
|
||||
@@ -380,8 +411,9 @@ static int RetStrVal(char const *s, func_info *info)
|
||||
if (!s) {
|
||||
RetVal.v.str = malloc(1);
|
||||
if (RetVal.v.str) *RetVal.v.str = 0;
|
||||
} else
|
||||
} else {
|
||||
RetVal.v.str = StrDup(s);
|
||||
}
|
||||
|
||||
if (!RetVal.v.str) {
|
||||
RetVal.type = ERR_TYPE;
|
||||
@@ -401,7 +433,9 @@ static int FStrlen(func_info *info)
|
||||
Value *v = &ARG(0);
|
||||
if (v->type != STR_TYPE) return E_BAD_TYPE;
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = strlen(v->v.str);
|
||||
size_t l = strlen(v->v.str);
|
||||
if (l > INT_MAX) return E_2HIGH;
|
||||
RETVAL = (int) l;
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -839,12 +873,14 @@ static int FTime(func_info *info)
|
||||
/***************************************************************/
|
||||
static int FAbs(func_info *info)
|
||||
{
|
||||
int v;
|
||||
volatile int v;
|
||||
|
||||
ASSERT_TYPE(0, INT_TYPE);
|
||||
v = ARGV(0);
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = (v < 0) ? (-v) : v;
|
||||
v = RETVAL;
|
||||
if (v < 0) return E_2HIGH;
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -861,6 +897,76 @@ static int FSgn(func_info *info)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* FAmpm - return a time as a string with "AM" or "PM" suffix */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static int FAmpm(func_info *info)
|
||||
{
|
||||
int h, m;
|
||||
int yr=0, mo=0, da=0;
|
||||
|
||||
char const *am = "AM";
|
||||
char const *pm = "PM";
|
||||
char const *ampm = NULL;
|
||||
|
||||
char outbuf[128];
|
||||
|
||||
if (ARG(0).type != DATETIME_TYPE && ARG(0).type != TIME_TYPE) {
|
||||
return E_BAD_TYPE;
|
||||
}
|
||||
if (HASDATE(ARG(0))) {
|
||||
FromJulian(DATEPART(ARG(0)), &yr, &mo, &da);
|
||||
}
|
||||
if (Nargs >= 2) {
|
||||
ASSERT_TYPE(1, STR_TYPE);
|
||||
am = ARGSTR(1);
|
||||
if (Nargs >= 3) {
|
||||
ASSERT_TYPE(2, STR_TYPE);
|
||||
pm = ARGSTR(2);
|
||||
}
|
||||
}
|
||||
h = TIMEPART(ARG(0)) / 60;
|
||||
m = TIMEPART(ARG(0)) % 60;
|
||||
if (h <= 11) {
|
||||
/* AM */
|
||||
if (h == 0) {
|
||||
if (ARG(0).type == DATETIME_TYPE) {
|
||||
snprintf(outbuf, sizeof(outbuf), "%04d%c%02d%c%02d%c12%c%02d", yr, DateSep, mo+1, DateSep, da, DateTimeSep, TimeSep, m);
|
||||
} else {
|
||||
snprintf(outbuf, sizeof(outbuf), "12%c%02d", TimeSep, m);
|
||||
}
|
||||
} else {
|
||||
if (ARG(0).type == DATETIME_TYPE) {
|
||||
snprintf(outbuf, sizeof(outbuf), "%04d%c%02d%c%02d%c%d%c%02d", yr, DateSep, mo+1, DateSep, da, DateTimeSep, h, TimeSep, m);
|
||||
} else {
|
||||
snprintf(outbuf, sizeof(outbuf), "%d%c%02d", h, TimeSep, m);
|
||||
}
|
||||
}
|
||||
ampm = am;
|
||||
} else {
|
||||
if (h > 12) {
|
||||
h -= 12;
|
||||
}
|
||||
if (ARG(0).type == DATETIME_TYPE) {
|
||||
snprintf(outbuf, sizeof(outbuf), "%04d%c%02d%c%02d%c%d%c%02d", yr, DateSep, mo+1, DateSep, da, DateTimeSep, h, TimeSep, m);
|
||||
} else {
|
||||
snprintf(outbuf, sizeof(outbuf), "%d%c%02d", h, TimeSep, m);
|
||||
}
|
||||
ampm = pm;
|
||||
}
|
||||
RetVal.type = STR_TYPE;
|
||||
RetVal.v.str = malloc(strlen(outbuf) + strlen(ampm) + 1);
|
||||
if (!RetVal.v.str) {
|
||||
RetVal.type = ERR_TYPE;
|
||||
return E_NO_MEM;
|
||||
}
|
||||
strcpy(RetVal.v.str, outbuf);
|
||||
strcat(RetVal.v.str, ampm);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* FOrd - returns a string containing ordinal number. */
|
||||
@@ -932,6 +1038,36 @@ static int FPlural(func_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* FIsAny */
|
||||
/* Return 1 if the first arg equals any subsequent arg, 0 */
|
||||
/* otherwise. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static int FIsAny(func_info *info)
|
||||
{
|
||||
int i;
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = 0;
|
||||
for (i=1; i<Nargs; i++) {
|
||||
if (ARG(0).type == ARG(i).type) {
|
||||
if (ARG(0).type == STR_TYPE) {
|
||||
if (!strcmp(ARGSTR(0), ARGSTR(i))) {
|
||||
RETVAL = 1;
|
||||
return OK;
|
||||
}
|
||||
} else {
|
||||
if (ARGV(0) == ARGV(i)) {
|
||||
RETVAL = 1;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* FChoose */
|
||||
@@ -973,6 +1109,28 @@ static int FOstype(func_info *info)
|
||||
return RetStrVal("UNIX", info);
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* FShellescape - escape shell meta-characters */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static int FShellescape(func_info *info)
|
||||
{
|
||||
DynamicBuffer buf;
|
||||
int r;
|
||||
|
||||
ASSERT_TYPE(0, STR_TYPE);
|
||||
DBufInit (&buf);
|
||||
if (ShellEscape(ARG(0).v.str, &buf) != OK) {
|
||||
DBufFree(&buf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
|
||||
r = RetStrVal(DBufValue(&buf), info);
|
||||
DBufFree(&buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* FUpper - convert string to upper-case */
|
||||
@@ -1137,6 +1295,120 @@ static int FTrigdate(func_info *info)
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigback(func_info *info)
|
||||
{
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = LastTrigger.back;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigdelta(func_info *info)
|
||||
{
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = LastTrigger.delta;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigtimedelta(func_info *info)
|
||||
{
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = LastTimeTrig.delta;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigtimerep(func_info *info)
|
||||
{
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = LastTimeTrig.rep;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigeventduration(func_info *info)
|
||||
{
|
||||
if (LastTrigger.eventduration == NO_TIME) {
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = -1;
|
||||
} else {
|
||||
RetVal.type = TIME_TYPE;
|
||||
RETVAL = LastTrigger.eventduration;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigeventstart(func_info *info)
|
||||
{
|
||||
if (LastTrigger.eventstart == NO_TIME) {
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = -1;
|
||||
} else {
|
||||
RetVal.type = DATETIME_TYPE;
|
||||
RETVAL = LastTrigger.eventstart;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigduration(func_info *info)
|
||||
{
|
||||
if (LastTimeTrig.duration == NO_TIME) {
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = -1;
|
||||
} else {
|
||||
RetVal.type = TIME_TYPE;
|
||||
RETVAL = LastTimeTrig.duration;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigrep(func_info *info)
|
||||
{
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = LastTrigger.rep;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigpriority(func_info *info)
|
||||
{
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = LastTrigger.priority;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTriguntil(func_info *info)
|
||||
{
|
||||
if (LastTrigger.until == NO_UNTIL) {
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = -1;
|
||||
} else {
|
||||
RetVal.type = DATE_TYPE;
|
||||
RETVAL = LastTrigger.until;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigscanfrom(func_info *info)
|
||||
{
|
||||
if (LastTrigger.scanfrom == NO_DATE) {
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = -1;
|
||||
} else {
|
||||
RetVal.type = DATE_TYPE;
|
||||
RETVAL = LastTrigger.scanfrom;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigfrom(func_info *info)
|
||||
{
|
||||
if (LastTrigger.from == NO_DATE) {
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = -1;
|
||||
} else {
|
||||
RetVal.type = DATE_TYPE;
|
||||
RETVAL = LastTrigger.from;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int FTrigvalid(func_info *info)
|
||||
{
|
||||
RetVal.type = INT_TYPE;
|
||||
@@ -1302,6 +1574,15 @@ static int FShell(func_info *info)
|
||||
ASSERT_TYPE(1, INT_TYPE);
|
||||
maxlen = ARGV(1);
|
||||
}
|
||||
|
||||
/* Don't allow maxlen to exceed the maximum length of
|
||||
a string variable */
|
||||
if (MaxStringLen > 0) {
|
||||
if (maxlen <= 0 || maxlen > MaxStringLen) {
|
||||
maxlen = MaxStringLen;
|
||||
}
|
||||
}
|
||||
|
||||
fp = popen(ARGSTR(0), "r");
|
||||
if (!fp) return E_IO_ERR;
|
||||
while (1) {
|
||||
@@ -1315,7 +1596,7 @@ static int FShell(func_info *info)
|
||||
DBufFree(&buf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
if (maxlen > 0 && DBufLen(&buf) >= maxlen) {
|
||||
if (maxlen > 0 && DBufLen(&buf) >= (size_t) maxlen) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1876,12 +2157,8 @@ static int SunStuff(int rise, double cosz, int jul)
|
||||
} else mins = MinsFromUTC;
|
||||
|
||||
/* Get latitude and longitude */
|
||||
longdeg = (double) LongDeg + (double) LongMin / 60.0
|
||||
+ (double) LongSec / 3600.0;
|
||||
|
||||
latitude = DEGRAD * ((double) LatDeg + (double) LatMin / 60.0
|
||||
+ (double) LatSec / 3600.0);
|
||||
|
||||
longdeg = -Longitude;
|
||||
latitude = DEGRAD * Latitude;
|
||||
|
||||
FromJulian(jul, &year, &mon, &day);
|
||||
|
||||
@@ -1919,10 +2196,10 @@ static int SunStuff(int rise, double cosz, int jul)
|
||||
/* Sine of sun's declination */
|
||||
sinDelta = 0.39782 * sin(DEGRAD*L);
|
||||
cosDelta = sqrt(1 - sinDelta*sinDelta);
|
||||
|
||||
|
||||
/* Cosine of sun's local hour angle */
|
||||
cosH = (cosz - sinDelta * sin(latitude)) / (cosDelta * cos(latitude));
|
||||
|
||||
|
||||
if (cosH < -1.0) { /* Summer -- permanent daylight */
|
||||
if (rise) return NO_TIME;
|
||||
else return -NO_TIME;
|
||||
@@ -1940,9 +2217,9 @@ static int SunStuff(int rise, double cosz, int jul)
|
||||
|
||||
if (T >= 24.0) T -= 24.0;
|
||||
else if (T < 0.0) T+= 24.0;
|
||||
|
||||
|
||||
UT = T + longdeg / 15.0;
|
||||
|
||||
|
||||
|
||||
local = UT + (double) mins / 60.0;
|
||||
if (local < 0.0) local += 24.0;
|
||||
@@ -1953,7 +2230,7 @@ static int SunStuff(int rise, double cosz, int jul)
|
||||
|
||||
hours = (int) local;
|
||||
mins = (int) ((local - hours) * 60.0);
|
||||
|
||||
|
||||
/* Sometimes, we get roundoff error. Check for "reasonableness" of
|
||||
answer. */
|
||||
if (rise) {
|
||||
@@ -2135,6 +2412,7 @@ static int FPsshade(func_info *info)
|
||||
if (!psshade_warned) {
|
||||
psshade_warned = 1;
|
||||
Eprint("psshade() is deprecated; use SPECIAL SHADE instead.");
|
||||
FreshLine = 1;
|
||||
}
|
||||
|
||||
sprintf(s, "/_A LineWidth 2 div def ");
|
||||
@@ -2190,6 +2468,7 @@ static int FPsmoon(func_info *info)
|
||||
if (!psmoon_warned) {
|
||||
psmoon_warned = 1;
|
||||
Eprint("psmoon() is deprecated; use SPECIAL MOON instead.");
|
||||
FreshLine = 1;
|
||||
}
|
||||
if (size > 0) {
|
||||
sprintf(sizebuf, "%d", size);
|
||||
@@ -2422,16 +2701,16 @@ static int tz_set_tz(char const *tz)
|
||||
unsetenv("TZ");
|
||||
r = 0;
|
||||
} else {
|
||||
r = setenv("TZ", tz, 1);
|
||||
r = setenv("TZ", tz, 1);
|
||||
}
|
||||
tzset();
|
||||
return r;
|
||||
}
|
||||
|
||||
static int tz_convert(int year, int month, int day,
|
||||
int hour, int minute,
|
||||
char const *src_tz, char const *tgt_tz,
|
||||
struct tm *tm)
|
||||
int hour, int minute,
|
||||
char const *src_tz, char const *tgt_tz,
|
||||
struct tm *tm)
|
||||
{
|
||||
int r;
|
||||
time_t t;
|
||||
@@ -2452,28 +2731,28 @@ static int tz_convert(int year, int month, int day,
|
||||
/* backup old TZ env var */
|
||||
old_tz = getenv("TZ");
|
||||
if (tgt_tz == NULL) {
|
||||
tgt_tz = old_tz;
|
||||
tgt_tz = old_tz;
|
||||
}
|
||||
|
||||
/* set source TZ */
|
||||
r = tz_set_tz(src_tz);
|
||||
if (r == -1) {
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create timestamp in UTC */
|
||||
t = mktime(tm);
|
||||
|
||||
if (t == (time_t) -1) {
|
||||
tz_set_tz(old_tz);
|
||||
return -1;
|
||||
tz_set_tz(old_tz);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set target TZ */
|
||||
r = tz_set_tz(tgt_tz);
|
||||
if (r == -1) {
|
||||
tz_set_tz(old_tz);
|
||||
return -1;
|
||||
tz_set_tz(old_tz);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* convert to target TZ */
|
||||
@@ -2484,9 +2763,9 @@ static int tz_convert(int year, int month, int day,
|
||||
|
||||
/* return result */
|
||||
if (res == NULL) {
|
||||
return -1;
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2557,6 +2836,7 @@ FSlide(func_info *info)
|
||||
} else {
|
||||
while(amt) {
|
||||
d--;
|
||||
if (d < 0) return E_DATE_OVER;
|
||||
r = IsOmitted(d, localomit, NULL,&omit);
|
||||
if (r) return r;
|
||||
if (!omit) amt++;
|
||||
@@ -2697,13 +2977,17 @@ FEvalTrig(func_info *info)
|
||||
return E_PARSE_ERR;
|
||||
}
|
||||
if (scanfrom == NO_DATE) {
|
||||
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 0);
|
||||
jul = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
|
||||
} else {
|
||||
/* Hokey... */
|
||||
if (trig.scanfrom != JulianToday) {
|
||||
Eprint("Warning: SCANFROM is ignored in two-argument form of evaltrig()");
|
||||
}
|
||||
jul = ComputeTrigger(scanfrom, &trig, &r, 0);
|
||||
jul = ComputeTrigger(scanfrom, &trig, &tim, &r, 0);
|
||||
}
|
||||
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
|
||||
r = 0;
|
||||
jul = -1;
|
||||
}
|
||||
FreeTrig(&trig);
|
||||
if (r) return r;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
/* globals.h and err.h */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/* MK_GLOBALS. Also contains useful macro definitions. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
#define INIT(var, val) var
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#define MAX_TRUSTED_USERS 20
|
||||
|
||||
#define MINUTES_PER_DAY 1440
|
||||
|
||||
#define DaysInYear(y) (((y) % 4) ? 365 : ((!((y) % 100) && ((y) % 400)) ? 365 : 366 ))
|
||||
@@ -36,6 +42,9 @@ EXTERN int CurMon;
|
||||
EXTERN int CurYear;
|
||||
EXTERN int LineNo;
|
||||
EXTERN int FreshLine;
|
||||
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
|
||||
|
||||
EXTERN INIT( int NumTrustedUsers, 0);
|
||||
EXTERN INIT( char const *MsgCommand, NULL);
|
||||
EXTERN INIT( int ShowAllErrors, 0);
|
||||
EXTERN INIT( int DebugFlag, 0);
|
||||
@@ -46,12 +55,13 @@ EXTERN INIT( int DoPrefixLineNo, 0);
|
||||
EXTERN INIT( int MondayFirst, 0);
|
||||
EXTERN INIT( int Iterations, 1);
|
||||
EXTERN INIT( int PsCal, 0);
|
||||
EXTERN INIT( int CalWidth, 80);
|
||||
EXTERN INIT( int CalWidth, -1);
|
||||
EXTERN INIT( int CalWeeks, 0);
|
||||
EXTERN INIT( int CalMonths, 0);
|
||||
EXTERN INIT( int Hush, 0);
|
||||
EXTERN INIT( int NextMode, 0);
|
||||
EXTERN INIT( int InfiniteDelta, 0);
|
||||
EXTERN INIT( int DefaultTDelta, 0);
|
||||
EXTERN INIT( int DeltaOffset, 0);
|
||||
EXTERN INIT( int RunDisabled, 0);
|
||||
EXTERN INIT( int IgnoreOnce, 0);
|
||||
@@ -73,6 +83,9 @@ EXTERN INIT( int Daemon, 0);
|
||||
EXTERN INIT( char DateSep, DATESEP);
|
||||
EXTERN INIT( char TimeSep, TIMESEP);
|
||||
EXTERN INIT( char DateTimeSep, DATETIMESEP);
|
||||
EXTERN INIT( int DefaultColorR, -1);
|
||||
EXTERN INIT( int DefaultColorB, -1);
|
||||
EXTERN INIT( int DefaultColorG, -1);
|
||||
EXTERN INIT( int SynthesizeTags, 0);
|
||||
EXTERN INIT( int ScFormat, SC_AMPM);
|
||||
EXTERN INIT( int MaxSatIter, 150);
|
||||
@@ -85,8 +98,10 @@ EXTERN FILE *ErrFp;
|
||||
EXTERN INIT( FILE *PurgeFP, NULL);
|
||||
EXTERN INIT( int NumIfs, 0);
|
||||
EXTERN INIT( unsigned int IfFlags, 0);
|
||||
EXTERN INIT( int LastTriggerDate, 0);
|
||||
EXTERN INIT( int LastTrigValid, 0);
|
||||
EXTERN Trigger LastTrigger;
|
||||
EXTERN TimeTrig LastTimeTrig;
|
||||
EXTERN INIT( int LastTriggerDate, 0);
|
||||
EXTERN INIT( int LastTriggerTime, 0);
|
||||
EXTERN INIT( int ShouldCache, 0);
|
||||
EXTERN char const *CurLine;
|
||||
@@ -98,6 +113,9 @@ EXTERN INIT( int CalPad, 1);
|
||||
EXTERN INIT( int UseVTChars, 0);
|
||||
EXTERN INIT( int UseUTF8Chars, 0);
|
||||
EXTERN INIT( int UseVTColors, 0);
|
||||
EXTERN INIT( int Use256Colors, 0);
|
||||
EXTERN INIT( int UseTrueColors, 0);
|
||||
EXTERN INIT( int TerminalBackground, TERMINAL_BACKGROUND_UNKNOWN);
|
||||
|
||||
/* Latitude and longitude */
|
||||
EXTERN INIT( int LatDeg, LAT_DEG);
|
||||
@@ -106,6 +124,9 @@ EXTERN INIT( int LatSec, LAT_SEC);
|
||||
EXTERN INIT( int LongDeg, LON_DEG);
|
||||
EXTERN INIT( int LongMin, LON_MIN);
|
||||
EXTERN INIT( int LongSec, LON_SEC);
|
||||
EXTERN INIT( double Longitude, -999.0);
|
||||
EXTERN INIT( double Latitude, -999.0);
|
||||
|
||||
EXTERN INIT( char *Location, LOCATION);
|
||||
|
||||
/* UTC calculation stuff */
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/* Support for the Hebrew calendar */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/* Derived from code written by Amos Shapir in 1978; revised */
|
||||
/* 1985. */
|
||||
@@ -138,8 +138,8 @@ int DaysInHebYear(int y)
|
||||
/***************************************************************/
|
||||
char const *DaysInHebMonths(int ylen)
|
||||
{
|
||||
static char monlen[13] =
|
||||
{30, 29, 30, 29, 30, 0, 29, 30, 29, 30, 29, 30, 29};
|
||||
static char monlen[14] =
|
||||
{30, 29, 30, 29, 30, 0, 29, 30, 29, 30, 29, 30, 29, 29};
|
||||
|
||||
|
||||
if (ylen > 355) {
|
||||
|
||||
211
src/init.c
@@ -7,7 +7,7 @@
|
||||
/* in normal mode. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifdef HAVE_INITGROUPS
|
||||
#include <grp.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "protos.h"
|
||||
@@ -38,6 +43,7 @@
|
||||
* simple calendar format.
|
||||
* -r = Disallow RUN mode
|
||||
* -c[n] = Produce a calendar for n months (default = 1)
|
||||
* -@[n,m] = Colorize n=0 VT100 n=1 85 n=2 True m=0 dark terminal m=1 light
|
||||
* -w[n,n,n] = Specify output device width, padding and spacing
|
||||
* -s[n] = Produce calendar in "simple calendar" format
|
||||
* -p[n] = Produce calendar in format compatible with rem2ps
|
||||
@@ -70,9 +76,6 @@
|
||||
* A minus sign alone indicates to take input from stdin
|
||||
*
|
||||
**************************************************************/
|
||||
#if defined(__APPLE__) || defined(__CYGWIN__)
|
||||
static void rkrphgvba(int x);
|
||||
#endif
|
||||
|
||||
/* For parsing an integer */
|
||||
#define PARSENUM(var, s) \
|
||||
@@ -87,6 +90,7 @@ static void ChgUser(char const *u);
|
||||
static void InitializeVar(char const *str);
|
||||
|
||||
static char const *BadDate = "Illegal date on command line\n";
|
||||
static void AddTrustedUser(char const *username);
|
||||
|
||||
static DynamicBuffer default_filename_buf;
|
||||
|
||||
@@ -112,7 +116,7 @@ static char const *DefaultFilename(void)
|
||||
s = getenv("HOME");
|
||||
if (!s) {
|
||||
fprintf(stderr, "HOME environment variable not set. Unable to determine reminder file.\n");
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
DBufPuts(&default_filename_buf, s);
|
||||
DBufPuts(&default_filename_buf, "/.reminders");
|
||||
@@ -135,17 +139,22 @@ void InitRemind(int argc, char const *argv[])
|
||||
int InvokedAsRem = 0;
|
||||
char const *s;
|
||||
int weeks;
|
||||
|
||||
int x;
|
||||
int jul;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
rkrphgvba(0);
|
||||
#elif defined(__CYGWIN__)
|
||||
rkrphgvba(1);
|
||||
#endif
|
||||
|
||||
jul = NO_DATE;
|
||||
|
||||
/* If stdout is a terminal, initialize $FormWidth to terminal width-8,
|
||||
but clamp to [20, 500] */
|
||||
if (isatty(STDOUT_FILENO)) {
|
||||
struct winsize w;
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
|
||||
FormWidth = w.ws_col - 8;
|
||||
if (FormWidth < 20) FormWidth = 20;
|
||||
if (FormWidth > 500) FormWidth = 500;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize global dynamic buffers */
|
||||
DBufInit(&Banner);
|
||||
DBufInit(&LineBuffer);
|
||||
@@ -159,7 +168,7 @@ void InitRemind(int argc, char const *argv[])
|
||||
if (getgid() != getegid() ||
|
||||
getuid() != geteuid()) {
|
||||
fprintf(ErrFp, "\nRemind should not be installed set-uid or set-gid.\nCHECK YOUR SYSTEM SECURITY.\n");
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
y = NO_YR;
|
||||
@@ -170,11 +179,14 @@ void InitRemind(int argc, char const *argv[])
|
||||
RealToday = SystemDate(&CurYear, &CurMon, &CurDay);
|
||||
if (RealToday < 0) {
|
||||
fprintf(ErrFp, ErrMsg[M_BAD_SYS_DATE], BASE);
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
JulianToday = RealToday;
|
||||
FromJulian(JulianToday, &CurYear, &CurMon, &CurDay);
|
||||
|
||||
/* Initialize Latitude and Longitude */
|
||||
set_lat_and_long_from_components();
|
||||
|
||||
/* See if we were invoked as "rem" rather than "remind" */
|
||||
if (argv[0]) {
|
||||
s = strrchr(argv[0], '/');
|
||||
@@ -190,6 +202,7 @@ void InitRemind(int argc, char const *argv[])
|
||||
|
||||
/* Parse the command-line options */
|
||||
i = 1;
|
||||
|
||||
while (i < argc) {
|
||||
arg = argv[i];
|
||||
if (*arg != '-') break; /* Exit the loop if it's not an option */
|
||||
@@ -203,6 +216,31 @@ void InitRemind(int argc, char const *argv[])
|
||||
}
|
||||
while (*arg) {
|
||||
switch(*arg++) {
|
||||
case '+':
|
||||
AddTrustedUser(arg);
|
||||
while(*arg) arg++;
|
||||
break;
|
||||
|
||||
case '@':
|
||||
UseVTColors = 1;
|
||||
if (*arg) {
|
||||
PARSENUM(x, arg);
|
||||
if (x == 1) {
|
||||
Use256Colors = 1;
|
||||
} else if (x == 2) {
|
||||
UseTrueColors = 1;
|
||||
}
|
||||
}
|
||||
if (*arg == ',') {
|
||||
arg++;
|
||||
PARSENUM(x, arg);
|
||||
if (x == 0) {
|
||||
TerminalBackground = TERMINAL_BACKGROUND_DARK;
|
||||
} else if (x == 1) {
|
||||
TerminalBackground = TERMINAL_BACKGROUND_LIGHT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
case 'J':
|
||||
@@ -246,7 +284,19 @@ void InitRemind(int argc, char const *argv[])
|
||||
|
||||
case 't':
|
||||
case 'T':
|
||||
if (!*arg) {
|
||||
if (*arg == 'T' || *arg == 't') {
|
||||
arg++;
|
||||
if (!*arg) {
|
||||
DefaultTDelta = 5;
|
||||
} else {
|
||||
PARSENUM(DefaultTDelta, arg);
|
||||
if (DefaultTDelta < 0) {
|
||||
DefaultTDelta = 0;
|
||||
} else if (DefaultTDelta > 1440) {
|
||||
DefaultTDelta = 1440;
|
||||
}
|
||||
}
|
||||
} else if (!*arg) {
|
||||
InfiniteDelta = 1;
|
||||
} else {
|
||||
PARSENUM(DeltaOffset, arg);
|
||||
@@ -295,8 +345,12 @@ void InitRemind(int argc, char const *argv[])
|
||||
|
||||
case 'u':
|
||||
case 'U':
|
||||
ChgUser(arg);
|
||||
RunDisabled = RUN_CMDLINE;
|
||||
if (*arg == '+') {
|
||||
ChgUser(arg+1);
|
||||
} else {
|
||||
RunDisabled = RUN_CMDLINE;
|
||||
ChgUser(arg);
|
||||
}
|
||||
while (*arg) arg++;
|
||||
break;
|
||||
case 'z':
|
||||
@@ -400,9 +454,21 @@ void InitRemind(int argc, char const *argv[])
|
||||
case 'p':
|
||||
case 'P':
|
||||
DoSimpleCalendar = 1;
|
||||
PsCal = 1;
|
||||
if (*arg == 'a' || *arg == 'A') {
|
||||
DoSimpleCalDelta = 1;
|
||||
PsCal = PSCAL_LEVEL1;
|
||||
while (*arg == 'a' || *arg == 'A' ||
|
||||
*arg == 'p' || *arg == 'P') {
|
||||
if (*arg == 'a' || *arg == 'A') {
|
||||
DoSimpleCalDelta = 1;
|
||||
} else if (*arg == 'p' || *arg == 'P') {
|
||||
/* JSON interchange formats always include
|
||||
file and line number info */
|
||||
DoPrefixLineNo = 1;
|
||||
if (PsCal == PSCAL_LEVEL1) {
|
||||
PsCal = PSCAL_LEVEL2;
|
||||
} else {
|
||||
PsCal = PSCAL_LEVEL3;
|
||||
}
|
||||
}
|
||||
arg++;
|
||||
}
|
||||
PARSENUM(CalMonths, arg);
|
||||
@@ -418,7 +484,10 @@ void InitRemind(int argc, char const *argv[])
|
||||
case 'W':
|
||||
if (*arg != ',') {
|
||||
PARSENUM(CalWidth, arg);
|
||||
if (CalWidth < 71) CalWidth = 71;
|
||||
if (CalWidth != 0 && CalWidth < 71) CalWidth = 71;
|
||||
if (CalWidth == 0) {
|
||||
CalWidth = -1;
|
||||
}
|
||||
}
|
||||
if (*arg == ',') {
|
||||
arg++;
|
||||
@@ -485,7 +554,7 @@ void InitRemind(int argc, char const *argv[])
|
||||
if (!InvokedAsRem) {
|
||||
if (i >= argc) {
|
||||
Usage();
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
InitialFile = argv[i++];
|
||||
} else {
|
||||
@@ -583,6 +652,7 @@ void InitRemind(int argc, char const *argv[])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Figure out the offset from UTC */
|
||||
if (CalculateUTC)
|
||||
(void) CalcMinsFromUTC(JulianToday, SystemTime(0)/60,
|
||||
@@ -599,7 +669,7 @@ void InitRemind(int argc, char const *argv[])
|
||||
#ifndef L_USAGE_OVERRIDE
|
||||
void Usage(void)
|
||||
{
|
||||
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2018 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||
#ifdef BETA
|
||||
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
|
||||
#endif
|
||||
@@ -607,6 +677,7 @@ void Usage(void)
|
||||
fprintf(ErrFp, "Options:\n");
|
||||
fprintf(ErrFp, " -n Output next occurrence of reminders in simple format\n");
|
||||
fprintf(ErrFp, " -r Disable RUN directives\n");
|
||||
fprintf(ErrFp, " -@[n,m] Colorize COLOR reminders\n");
|
||||
fprintf(ErrFp, " -c[a][n] Produce a calendar for n (default 1) months\n");
|
||||
fprintf(ErrFp, " -c[a]+[n] Produce a calendar for n (default 1) weeks\n");
|
||||
fprintf(ErrFp, " -w[n[,p[,s]]] Specify width, padding and spacing of calendar\n");
|
||||
@@ -631,7 +702,7 @@ void Usage(void)
|
||||
fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n");
|
||||
fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n");
|
||||
fprintf(ErrFp, " -j[n] Run in 'purge' mode. [n = INCLUDE depth]\n");
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif /* L_USAGE_OVERRIDE */
|
||||
/***************************************************************/
|
||||
@@ -646,7 +717,7 @@ void Usage(void)
|
||||
/***************************************************************/
|
||||
static void ChgUser(char const *user)
|
||||
{
|
||||
uid_t myuid;
|
||||
uid_t myeuid;
|
||||
|
||||
struct passwd *pwent;
|
||||
static char *home;
|
||||
@@ -654,29 +725,38 @@ static void ChgUser(char const *user)
|
||||
static char *username;
|
||||
static char *logname;
|
||||
|
||||
myuid = getuid();
|
||||
myeuid = geteuid();
|
||||
|
||||
pwent = getpwnam(user);
|
||||
|
||||
if (!pwent) {
|
||||
fprintf(ErrFp, ErrMsg[M_BAD_USER], user);
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!myuid && setgid(pwent->pw_gid)) {
|
||||
fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
|
||||
exit(1);
|
||||
}
|
||||
if (!myeuid) {
|
||||
/* Started as root, so drop privileges */
|
||||
#ifdef HAVE_INITGROUPS
|
||||
if (initgroups(pwent->pw_name, pwent->pw_gid) < 0) {
|
||||
fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
|
||||
exit(EXIT_FAILURE);
|
||||
};
|
||||
#endif
|
||||
if (setgid(pwent->pw_gid) < 0) {
|
||||
fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!myuid && setuid(pwent->pw_uid)) {
|
||||
fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid);
|
||||
exit(1);
|
||||
if (setuid(pwent->pw_uid) < 0) {
|
||||
fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
home = malloc(strlen(pwent->pw_dir) + 6);
|
||||
if (!home) {
|
||||
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sprintf(home, "HOME=%s", pwent->pw_dir);
|
||||
putenv(home);
|
||||
@@ -684,7 +764,7 @@ static void ChgUser(char const *user)
|
||||
shell = malloc(strlen(pwent->pw_shell) + 7);
|
||||
if (!shell) {
|
||||
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sprintf(shell, "SHELL=%s", pwent->pw_shell);
|
||||
putenv(shell);
|
||||
@@ -693,14 +773,14 @@ static void ChgUser(char const *user)
|
||||
username = malloc(strlen(pwent->pw_name) + 6);
|
||||
if (!username) {
|
||||
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sprintf(username, "USER=%s", pwent->pw_name);
|
||||
putenv(username);
|
||||
logname= malloc(strlen(pwent->pw_name) + 9);
|
||||
if (!logname) {
|
||||
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sprintf(logname, "LOGNAME=%s", pwent->pw_name);
|
||||
putenv(logname);
|
||||
@@ -773,6 +853,7 @@ static void InitializeVar(char const *str)
|
||||
|
||||
if (*varname == '$') {
|
||||
r=SetSysVar(varname+1, &val);
|
||||
DestroyValue(val);
|
||||
if (r) fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
|
||||
return;
|
||||
}
|
||||
@@ -787,46 +868,22 @@ static void InitializeVar(char const *str)
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) || defined(__CYGWIN__)
|
||||
static char const pmsg1[] = {
|
||||
0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20,
|
||||
0x67, 0x62, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x68, 0x61, 0x61, 0x76,
|
||||
0x61, 0x74, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x62,
|
||||
0x61, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x63, 0x63, 0x79, 0x72, 0x20,
|
||||
0x63, 0x65, 0x62, 0x71, 0x68, 0x70, 0x67, 0x2e, 0x20, 0x20, 0x56,
|
||||
0x27, 0x71, 0x20, 0x65, 0x6e, 0x67, 0x75, 0x72, 0x65, 0x20, 0x67,
|
||||
0x75, 0x6e, 0x67, 0x0a, 0x6c, 0x62, 0x68, 0x20, 0x71, 0x76, 0x71,
|
||||
0x61, 0x27, 0x67, 0x2e, 0x20, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61,
|
||||
0x71, 0x20, 0x72, 0x6b, 0x72, 0x70, 0x68, 0x67, 0x76, 0x62, 0x61,
|
||||
0x20, 0x6a, 0x76, 0x79, 0x79, 0x20, 0x70, 0x62, 0x61, 0x67, 0x76,
|
||||
0x61, 0x68, 0x72, 0x20, 0x7a, 0x62, 0x7a, 0x72, 0x61, 0x67, 0x6e,
|
||||
0x65, 0x76, 0x79, 0x6c, 0x2e, 0x0a, 0x00
|
||||
};
|
||||
|
||||
static char const pmsg2[] = {
|
||||
0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20,
|
||||
0x67, 0x62, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x68, 0x61, 0x61, 0x76,
|
||||
0x61, 0x74, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x62,
|
||||
0x61, 0x20, 0x6e, 0x20, 0x5a, 0x76, 0x70, 0x65, 0x62, 0x66, 0x62,
|
||||
0x73, 0x67, 0x20, 0x66, 0x6c, 0x66, 0x67, 0x72, 0x7a, 0x2e, 0x20,
|
||||
0x20, 0x56, 0x27, 0x71, 0x20, 0x65, 0x6e, 0x67, 0x75, 0x72, 0x65,
|
||||
0x20, 0x67, 0x75, 0x6e, 0x67, 0x0a, 0x6c, 0x62, 0x68, 0x20, 0x71,
|
||||
0x76, 0x71, 0x61, 0x27, 0x67, 0x2e, 0x20, 0x20, 0x45, 0x72, 0x7a,
|
||||
0x76, 0x61, 0x71, 0x20, 0x72, 0x6b, 0x72, 0x70, 0x68, 0x67, 0x76,
|
||||
0x62, 0x61, 0x20, 0x6a, 0x76, 0x79, 0x79, 0x20, 0x70, 0x62, 0x61,
|
||||
0x67, 0x76, 0x61, 0x68, 0x72, 0x20, 0x7a, 0x62, 0x7a, 0x72, 0x61,
|
||||
0x67, 0x6e, 0x65, 0x76, 0x79, 0x6c, 0x2e, 0x0a, 0x00
|
||||
};
|
||||
|
||||
static void
|
||||
rkrphgvba(int x)
|
||||
AddTrustedUser(char const *username)
|
||||
{
|
||||
char const *s = (x ? pmsg2 : pmsg1);
|
||||
while(*s) {
|
||||
int c = (int) *s++;
|
||||
c=isalpha(c)?tolower(c)<0x6e?c+13:c-13:c;
|
||||
putchar(c);
|
||||
struct passwd *pwent;
|
||||
if (NumTrustedUsers >= MAX_TRUSTED_USERS) {
|
||||
fprintf(stderr, "Too many trusted users (%d max)\n",
|
||||
MAX_TRUSTED_USERS);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sleep(5);
|
||||
|
||||
pwent = getpwnam(username);
|
||||
if (!pwent) {
|
||||
fprintf(ErrFp, ErrMsg[M_BAD_USER], username);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
TrustedUsers[NumTrustedUsers] = pwent->pw_uid;
|
||||
NumTrustedUsers++;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
1045
src/json.c
Normal file
280
src/json.h
Normal file
@@ -0,0 +1,280 @@
|
||||
/* vim: set et ts=3 sw=3 sts=3 ft=c:
|
||||
*
|
||||
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
|
||||
* https://github.com/udp/json-parser
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _JSON_H
|
||||
#define _JSON_H
|
||||
|
||||
#ifndef json_char
|
||||
#define json_char char
|
||||
#endif
|
||||
|
||||
#ifndef json_int_t
|
||||
#ifndef _MSC_VER
|
||||
#include <inttypes.h>
|
||||
#define json_int_t int64_t
|
||||
#else
|
||||
#define json_int_t __int64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <string.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long max_memory;
|
||||
int settings;
|
||||
|
||||
/* Custom allocator support (leave null to use malloc/free)
|
||||
*/
|
||||
|
||||
void * (* mem_alloc) (size_t, int zero, void * user_data);
|
||||
void (* mem_free) (void *, void * user_data);
|
||||
|
||||
void * user_data; /* will be passed to mem_alloc and mem_free */
|
||||
|
||||
size_t value_extra; /* how much extra space to allocate for values? */
|
||||
|
||||
} json_settings;
|
||||
|
||||
#define json_enable_comments 0x01
|
||||
|
||||
typedef enum
|
||||
{
|
||||
json_none,
|
||||
json_object,
|
||||
json_array,
|
||||
json_integer,
|
||||
json_double,
|
||||
json_string,
|
||||
json_boolean,
|
||||
json_null
|
||||
|
||||
} json_type;
|
||||
|
||||
extern const struct _json_value json_value_none;
|
||||
|
||||
typedef struct _json_object_entry
|
||||
{
|
||||
json_char * name;
|
||||
unsigned int name_length;
|
||||
|
||||
struct _json_value * value;
|
||||
|
||||
} json_object_entry;
|
||||
|
||||
typedef struct _json_value
|
||||
{
|
||||
struct _json_value * parent;
|
||||
|
||||
json_type type;
|
||||
|
||||
union
|
||||
{
|
||||
int boolean;
|
||||
json_int_t integer;
|
||||
double dbl;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned int length;
|
||||
json_char * ptr; /* null terminated */
|
||||
|
||||
} string;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned int length;
|
||||
|
||||
json_object_entry * values;
|
||||
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||
decltype(values) begin () const
|
||||
{ return values;
|
||||
}
|
||||
decltype(values) end () const
|
||||
{ return values + length;
|
||||
}
|
||||
#endif
|
||||
|
||||
} object;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned int length;
|
||||
struct _json_value ** values;
|
||||
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||
decltype(values) begin () const
|
||||
{ return values;
|
||||
}
|
||||
decltype(values) end () const
|
||||
{ return values + length;
|
||||
}
|
||||
#endif
|
||||
|
||||
} array;
|
||||
|
||||
} u;
|
||||
|
||||
union
|
||||
{
|
||||
struct _json_value * next_alloc;
|
||||
void * object_mem;
|
||||
|
||||
} _reserved;
|
||||
|
||||
#ifdef JSON_TRACK_SOURCE
|
||||
|
||||
/* Location of the value in the source JSON
|
||||
*/
|
||||
unsigned int line, col;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Some C++ operator sugar */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
public:
|
||||
|
||||
inline _json_value ()
|
||||
{ memset (this, 0, sizeof (_json_value));
|
||||
}
|
||||
|
||||
inline const struct _json_value &operator [] (int index) const
|
||||
{
|
||||
if (type != json_array || index < 0
|
||||
|| ((unsigned int) index) >= u.array.length)
|
||||
{
|
||||
return json_value_none;
|
||||
}
|
||||
|
||||
return *u.array.values [index];
|
||||
}
|
||||
|
||||
inline const struct _json_value &operator [] (const char * index) const
|
||||
{
|
||||
if (type != json_object)
|
||||
return json_value_none;
|
||||
|
||||
for (unsigned int i = 0; i < u.object.length; ++ i)
|
||||
if (!strcmp (u.object.values [i].name, index))
|
||||
return *u.object.values [i].value;
|
||||
|
||||
return json_value_none;
|
||||
}
|
||||
|
||||
inline operator const char * () const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case json_string:
|
||||
return u.string.ptr;
|
||||
|
||||
default:
|
||||
return "";
|
||||
};
|
||||
}
|
||||
|
||||
inline operator json_int_t () const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case json_integer:
|
||||
return u.integer;
|
||||
|
||||
case json_double:
|
||||
return (json_int_t) u.dbl;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
inline operator bool () const
|
||||
{
|
||||
if (type != json_boolean)
|
||||
return false;
|
||||
|
||||
return u.boolean != 0;
|
||||
}
|
||||
|
||||
inline operator double () const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case json_integer:
|
||||
return (double) u.integer;
|
||||
|
||||
case json_double:
|
||||
return u.dbl;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} json_value;
|
||||
|
||||
json_value * json_parse (const json_char * json,
|
||||
size_t length);
|
||||
|
||||
#define json_error_max 128
|
||||
json_value * json_parse_ex (json_settings * settings,
|
||||
const json_char * json,
|
||||
size_t length,
|
||||
char * error);
|
||||
|
||||
void json_value_free (json_value *);
|
||||
|
||||
|
||||
/* Not usually necessary, unless you used a custom mem_alloc and now want to
|
||||
* use a custom mem_free.
|
||||
*/
|
||||
void json_value_free_ex (json_settings * settings,
|
||||
json_value *);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -5,7 +5,7 @@
|
||||
/* Header file for language support for various languages. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* */
|
||||
/* REMIND is Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* This file is Copyright (C) 1993 by Mogens Lynnerup. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
/* Further corrections by Erik-Jan Vens */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/* Support for the English language. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* This file is Copyright (C) 1993-1998 by Mikko Silvonen. */
|
||||
/* REMIND is Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -302,7 +302,8 @@ EXTERN char *ErrMsg[] =
|
||||
"Can't convert between time zones",
|
||||
"No files matching *.rem",
|
||||
"String too long",
|
||||
"Time specified twice"
|
||||
"Time specified twice",
|
||||
"Cannot specify DURATION without specifying AT"
|
||||
|
||||
#elif IBMEXTENDED
|
||||
"Ok",
|
||||
@@ -407,7 +408,8 @@ EXTERN char *ErrMsg[] =
|
||||
"Can't convert between time zones",
|
||||
"No files matching *.rem",
|
||||
"String too long",
|
||||
"Time specified twice"
|
||||
"Time specified twice",
|
||||
"Cannot specify DURATION without specifying AT"
|
||||
|
||||
#else
|
||||
"Ok",
|
||||
@@ -512,7 +514,8 @@ EXTERN char *ErrMsg[] =
|
||||
"Can't convert between time zones",
|
||||
"No files matching *.rem",
|
||||
"String too long",
|
||||
"Time specified twice"
|
||||
"Time specified twice",
|
||||
"Cannot specify DURATION without specifying AT"
|
||||
|
||||
|
||||
#endif
|
||||
@@ -524,7 +527,7 @@ EXTERN char *ErrMsg[] =
|
||||
#define L_USAGE_OVERRIDE 1
|
||||
void Usage(void)
|
||||
{
|
||||
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2018 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||
#ifdef BETA
|
||||
fprintf(ErrFp, ">>>> BETAVERSIO <<<<\n");
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* */
|
||||
/* REMIND is Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* This file is Copyright (C) 1993 by Laurent Duperval and */
|
||||
/* Dianne Skoll. */
|
||||
/* */
|
||||
@@ -242,7 +242,8 @@ EXTERN char *ErrMsg[] =
|
||||
"Can't convert between time zones",
|
||||
"No files matching *.rem",
|
||||
"String too long",
|
||||
"Time specified twice"
|
||||
"Time specified twice",
|
||||
"Cannot specify DURATION without specifying AT"
|
||||
|
||||
#else /* ISOLATIN1 */
|
||||
"Ok",
|
||||
@@ -347,7 +348,8 @@ EXTERN char *ErrMsg[] =
|
||||
"Can't convert between time zones",
|
||||
"No files matching *.rem",
|
||||
"String too long",
|
||||
"Time specified twice"
|
||||
"Time specified twice",
|
||||
"Cannot specify DURATION without specifying AT"
|
||||
#endif /* ISOLATIN1 */
|
||||
};
|
||||
#endif /* MK_GLOBALS */
|
||||
@@ -357,7 +359,7 @@ EXTERN char *ErrMsg[] =
|
||||
#define L_USAGE_OVERRIDE 1
|
||||
void Usage(void)
|
||||
{
|
||||
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2018 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||
#ifdef BETA
|
||||
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
|
||||
#endif
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/* I don't speak German. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/* Support for the Icelandic language. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* Translated by Björn Davíðsson (bjossi@snerpa.is) */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/* This file is part of REMIND. */
|
||||
/* It is Copyright (C) 1996 by Valerio Aimale */
|
||||
/* */
|
||||
/* Remind is copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Remind is copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* This file is Copyright (C) 1993 by Trygve Randen. */
|
||||
/* Remind is Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Remind is Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/* Polish. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -281,7 +281,8 @@ EXTERN char *ErrMsg[] =
|
||||
"Can't convert between time zones",
|
||||
"No files matching *.rem",
|
||||
"String too long",
|
||||
"Time specified twice"
|
||||
"Time specified twice",
|
||||
"Cannot specify DURATION without specifying AT"
|
||||
#else /* ISOLATIN1 */
|
||||
"OK",
|
||||
"Brakujacy ']'",
|
||||
@@ -385,7 +386,8 @@ EXTERN char *ErrMsg[] =
|
||||
"Can't convert between time zones",
|
||||
"No files matching *.rem",
|
||||
"String too long",
|
||||
"Time specified twice"
|
||||
"Time specified twice",
|
||||
"Cannot specify DURATION without specifying AT"
|
||||
#endif /* ISOLATIN1 */
|
||||
};
|
||||
#endif /* MK_GLOBALS */
|
||||
@@ -395,7 +397,7 @@ EXTERN char *ErrMsg[] =
|
||||
#define L_USAGE_OVERRIDE 1
|
||||
void Usage(void)
|
||||
{
|
||||
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2018 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||
#ifdef BETA
|
||||
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* */
|
||||
/* REMIND is Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* This file is Copyright (C) 1996 by Marco Paganini and */
|
||||
/* Dianne Skoll. */
|
||||
/* */
|
||||
@@ -247,7 +247,8 @@ EXTERN char *ErrMsg[] =
|
||||
"Can't convert between time zones",
|
||||
"No files matching *.rem",
|
||||
"String too long",
|
||||
"Time specified twice"
|
||||
"Time specified twice",
|
||||
"Cannot specify DURATION without specifying AT"
|
||||
};
|
||||
#endif /* MK_GLOBALS */
|
||||
|
||||
@@ -256,7 +257,7 @@ EXTERN char *ErrMsg[] =
|
||||
#define L_USAGE_OVERRIDE 1
|
||||
void Usage(void)
|
||||
{
|
||||
fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-2018 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||
fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
|
||||
#ifdef BETA
|
||||
fprintf(ErrFp, ">>>> VERSAO BETA <<<<\n");
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
!/***************************************************************/
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* ROMANIAN.H */
|
||||
/* */
|
||||
@@ -8,7 +8,7 @@
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* */
|
||||
/* REMIND is Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* This file is Copyright (C) 1996-1998 by Liviu Daia */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/* Author: Rafa Couto <rafacouto@biogate.com> */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
118
src/main.c
@@ -6,7 +6,7 @@
|
||||
/* routines, etc. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -63,14 +63,16 @@ int main(int argc, char *argv[])
|
||||
setlocale(LC_ALL, "");
|
||||
#endif
|
||||
|
||||
/* The very first thing to do is to set up ErrFp to be stderr */
|
||||
/* The very first thing to do is to set up ErrFp to be stderr */
|
||||
ErrFp = stderr;
|
||||
|
||||
/* Set up global vars */
|
||||
/* Set up global vars */
|
||||
ArgC = argc;
|
||||
ArgV = (char const **) argv;
|
||||
|
||||
InitRemind(argc, (char const **) argv);
|
||||
ClearLastTriggers();
|
||||
|
||||
if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) {
|
||||
ProduceCalendar();
|
||||
return 0;
|
||||
@@ -125,10 +127,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
if (Iterations) {
|
||||
ClearGlobalOmits();
|
||||
DestroyOmitContexts();
|
||||
DestroyVars(0);
|
||||
NumTriggered = 0;
|
||||
PerIterationInit();
|
||||
JulianToday++;
|
||||
}
|
||||
}
|
||||
@@ -146,6 +145,19 @@ void PurgeEchoLine(char const *fmt, ...)
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
PerIterationInit(void)
|
||||
{
|
||||
ClearGlobalOmits();
|
||||
DestroyOmitContexts();
|
||||
DestroyVars(0);
|
||||
DefaultColorR = -1;
|
||||
DefaultColorG = -1;
|
||||
DefaultColorB = -1;
|
||||
NumTriggered = 0;
|
||||
ClearLastTriggers();
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* DoReminders */
|
||||
@@ -223,12 +235,22 @@ static void DoReminders(void)
|
||||
case T_Else: r=DoElse(&p); break;
|
||||
case T_EndIf: r=DoEndif(&p); break;
|
||||
case T_Include:
|
||||
case T_IncludeR:
|
||||
/* In purge mode, include closes file, so we
|
||||
need to echo it here! */
|
||||
if (PurgeMode) {
|
||||
PurgeEchoLine("%s\n", CurLine);
|
||||
}
|
||||
r=DoInclude(&p);
|
||||
r=DoInclude(&p, tok.type);
|
||||
purge_handled = 1;
|
||||
break;
|
||||
case T_IncludeCmd:
|
||||
/* In purge mode, include closes file, so we
|
||||
need to echo it here! */
|
||||
if (PurgeMode) {
|
||||
PurgeEchoLine("%s\n", CurLine);
|
||||
}
|
||||
r=DoIncludeCmd(&p);
|
||||
purge_handled = 1;
|
||||
break;
|
||||
case T_Exit: DoExit(&p); break;
|
||||
@@ -713,7 +735,7 @@ int DoIf(ParsePtr p)
|
||||
int r;
|
||||
unsigned syndrome;
|
||||
|
||||
if (NumIfs >= IF_NEST) return E_NESTED_IF;
|
||||
if ((size_t) NumIfs >= IF_NEST) return E_NESTED_IF;
|
||||
|
||||
if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE;
|
||||
else {
|
||||
@@ -794,13 +816,20 @@ int DoIfTrig(ParsePtr p)
|
||||
int jul;
|
||||
|
||||
|
||||
if (NumIfs >= IF_NEST) return E_NESTED_IF;
|
||||
if ((size_t) NumIfs >= IF_NEST) return E_NESTED_IF;
|
||||
if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE;
|
||||
else {
|
||||
if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r;
|
||||
if (trig.typ != NO_TYPE) return E_PARSE_ERR;
|
||||
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1);
|
||||
if (r) syndrome = IF_TRUE | BEFORE_ELSE;
|
||||
jul = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
|
||||
if (r) {
|
||||
if (r != E_CANT_TRIG || !trig.maybe_uncomputable) {
|
||||
if (!Hush || r != E_RUN_DISABLED) {
|
||||
Eprint("%s", ErrMsg[r]);
|
||||
}
|
||||
}
|
||||
syndrome = IF_TRUE | BEFORE_ELSE;
|
||||
}
|
||||
else {
|
||||
if (ShouldTriggerReminder(&trig, &tim, jul, &err)) {
|
||||
syndrome = IF_TRUE | BEFORE_ELSE;
|
||||
@@ -1302,6 +1331,7 @@ void UTCToLocal(int utcdate, int utctime, int *locdate, int *loctime)
|
||||
|
||||
void SigIntHandler(int d)
|
||||
{
|
||||
UNUSED(d);
|
||||
signal(SIGINT, SigIntHandler);
|
||||
GotSigInt();
|
||||
exit(0);
|
||||
@@ -1321,3 +1351,67 @@ FreeTrig(Trigger *t)
|
||||
{
|
||||
DBufFree(&(t->tags));
|
||||
}
|
||||
|
||||
void
|
||||
ClearLastTriggers(void)
|
||||
{
|
||||
LastTrigger.expired = 0;
|
||||
LastTrigger.wd = NO_WD;
|
||||
LastTrigger.d = NO_DAY;
|
||||
LastTrigger.m = NO_MON;
|
||||
LastTrigger.y = NO_YR;
|
||||
LastTrigger.back = NO_BACK;
|
||||
LastTrigger.delta = NO_DELTA;
|
||||
LastTrigger.rep = NO_REP;
|
||||
LastTrigger.localomit = NO_WD;
|
||||
LastTrigger.skip = NO_SKIP;
|
||||
LastTrigger.until = NO_UNTIL;
|
||||
LastTrigger.typ = NO_TYPE;
|
||||
LastTrigger.once = NO_ONCE;
|
||||
LastTrigger.scanfrom = NO_DATE;
|
||||
LastTrigger.from = NO_DATE;
|
||||
LastTrigger.priority = DefaultPrio;
|
||||
LastTrigger.sched[0] = 0;
|
||||
LastTrigger.warn[0] = 0;
|
||||
LastTrigger.omitfunc[0] = 0;
|
||||
LastTrigger.passthru[0] = 0;
|
||||
|
||||
LastTimeTrig.ttime = NO_TIME;
|
||||
LastTimeTrig.delta = NO_DELTA;
|
||||
LastTimeTrig.rep = NO_REP;
|
||||
LastTimeTrig.duration = NO_TIME;
|
||||
}
|
||||
|
||||
void
|
||||
SaveAllTriggerInfo(Trigger const *t, TimeTrig const *tt, int trigdate, int trigtime, int valid)
|
||||
{
|
||||
SaveLastTrigger(t);
|
||||
SaveLastTimeTrig(tt);
|
||||
LastTriggerDate = trigdate;
|
||||
LastTriggerTime = trigtime;
|
||||
LastTrigValid = valid;
|
||||
}
|
||||
|
||||
void
|
||||
SaveLastTrigger(Trigger const *t)
|
||||
{
|
||||
memcpy(&LastTrigger, t, sizeof(LastTrigger));
|
||||
DBufInit(&(LastTrigger.tags));
|
||||
}
|
||||
|
||||
void
|
||||
SaveLastTimeTrig(TimeTrig const *t)
|
||||
{
|
||||
memcpy(&LastTimeTrig, t, sizeof(LastTimeTrig));
|
||||
}
|
||||
|
||||
/* Wrapper to ignore warnings about ignoring return value of system() */
|
||||
void
|
||||
System(char const *cmd)
|
||||
{
|
||||
int r;
|
||||
r = system(cmd);
|
||||
if (r == 0) {
|
||||
r = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/* Calculations for figuring out moon phases. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
23
src/omit.c
@@ -6,7 +6,7 @@
|
||||
/* the data structures for OMITted dates. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -370,20 +370,30 @@ int DoOmit(ParsePtr p)
|
||||
NumPartialOmits++;
|
||||
}
|
||||
} else {
|
||||
if (NumFullOmits == MAX_FULL_OMITS) return E_2MANY_FULL;
|
||||
|
||||
if (d > DaysInMonth(m, y)) return E_BAD_DATE;
|
||||
syndrome = Julian(y, m, d);
|
||||
if (!BexistsIntArray(FullOmitArray, NumFullOmits, syndrome)) {
|
||||
InsertIntoSortedArray(FullOmitArray, NumFullOmits, syndrome);
|
||||
NumFullOmits++;
|
||||
}
|
||||
r = AddGlobalOmit(syndrome);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
if (tok.type == T_Tag || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
|
||||
return OK;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
AddGlobalOmit(int jul)
|
||||
{
|
||||
if (NumFullOmits == MAX_FULL_OMITS) return E_2MANY_FULL;
|
||||
if (!BexistsIntArray(FullOmitArray, NumFullOmits, jul)) {
|
||||
InsertIntoSortedArray(FullOmitArray, NumFullOmits, jul);
|
||||
NumFullOmits++;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int
|
||||
DoThroughOmit(ParsePtr p, int ystart, int mstart, int dstart)
|
||||
{
|
||||
@@ -453,6 +463,7 @@ DoThroughOmit(ParsePtr p, int ystart, int mstart, int dstart)
|
||||
end = Julian(yend, mend, dend);
|
||||
|
||||
if (end < start) {
|
||||
Eprint("Warning: Swapping dates on OMIT ... THROUGH ... line");
|
||||
tmp = start;
|
||||
start = end;
|
||||
end = tmp;
|
||||
|
||||
35
src/protos.h
@@ -5,10 +5,13 @@
|
||||
/* Function Prototypes. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
/* Suppress unused variable warnings */
|
||||
#define UNUSED(x) (void) x
|
||||
|
||||
/* Define a string assignment macro - be careful!!! */
|
||||
#define STRSET(x, str) { if (x) free(x); (x) = StrDup(str); }
|
||||
|
||||
@@ -34,13 +37,15 @@ int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int jul, int *err);
|
||||
int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul, int mode);
|
||||
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int jul, int tim);
|
||||
int ParseLiteralDate (char const **s, int *jul, int *tim);
|
||||
int ParseLiteralTime (char const **s, int *tim);
|
||||
int EvalExpr (char const **e, Value *v, ParsePtr p);
|
||||
int DoCoerce (char type, Value *v);
|
||||
void PrintValue (Value *v, FILE *fp);
|
||||
int CopyValue (Value *dest, const Value *src);
|
||||
int ReadLine (void);
|
||||
int OpenFile (char const *fname);
|
||||
int DoInclude (ParsePtr p);
|
||||
int DoInclude (ParsePtr p, enum TokTypes tok);
|
||||
int DoIncludeCmd (ParsePtr p);
|
||||
int IncludeFile (char const *fname);
|
||||
int GetAccessDate (char const *file);
|
||||
int SetAccessDate (char const *fname, int jul);
|
||||
@@ -85,7 +90,10 @@ void HandleQueuedReminders (void);
|
||||
char const *FindInitialToken (Token *tok, char const *s);
|
||||
void FindToken (char const *s, Token *tok);
|
||||
void FindNumericToken (char const *s, Token *t);
|
||||
int ComputeTrigger (int today, Trigger *trig, int *err, int save_in_globals);
|
||||
int ComputeTrigger (int today, Trigger *trig, TimeTrig *tim, int *err, int save_in_globals);
|
||||
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 ComputeScanStart(int today, Trigger *trig, TimeTrig *tt);
|
||||
char *StrnCpy (char *dest, char const *source, int n);
|
||||
int StrMatch (char const *s1, char const *s2, int n);
|
||||
int StrinCmp (char const *s1, char const *s2, int n);
|
||||
@@ -102,7 +110,7 @@ void DumpVarTable (void);
|
||||
void DestroyVars (int all);
|
||||
int PreserveVar (char const *name);
|
||||
int DoPreserve (Parser *p);
|
||||
int DoSatRemind (Trigger *trig, TimeTrig *tim, ParsePtr p);
|
||||
int DoSatRemind (Trigger *trig, TimeTrig *tt, ParsePtr p);
|
||||
int DoMsgCommand (char const *cmd, char const *msg);
|
||||
int ParseNonSpaceChar (ParsePtr p, int *err, int peek);
|
||||
unsigned int HashVal (char const *str);
|
||||
@@ -139,3 +147,22 @@ void PurgeEchoLine(char const *fmt, ...);
|
||||
void FreeTrig(Trigger *t);
|
||||
void AppendTag(DynamicBuffer *buf, char const *s);
|
||||
char const *SynthesizeTag(void);
|
||||
void ClearLastTriggers(void);
|
||||
void SaveLastTrigger(Trigger const *t);
|
||||
void SaveLastTimeTrig(TimeTrig const *t);
|
||||
void SaveAllTriggerInfo(Trigger const *t, TimeTrig const *tt, int trigdate, int trigtime, int valid);
|
||||
|
||||
void PerIterationInit(void);
|
||||
char const *Decolorize(int r, int g, int b);
|
||||
char const *Colorize(int r, int g, int b);
|
||||
void PrintJSONString(char const *s);
|
||||
void PrintJSONKeyPairInt(char const *name, int val);
|
||||
void PrintJSONKeyPairString(char const *name, char const *val);
|
||||
void PrintJSONKeyPairDate(char const *name, int jul);
|
||||
void PrintJSONKeyPairDateTime(char const *name, int dt);
|
||||
void PrintJSONKeyPairTime(char const *name, int t);
|
||||
void System(char const *cmd);
|
||||
int ShellEscape(char const *in, DynamicBuffer *out);
|
||||
int AddGlobalOmit(int jul);
|
||||
void set_lat_and_long_from_components(void);
|
||||
void set_components_from_lat_and_long(void);
|
||||
|
||||
148
src/queue.c
@@ -5,7 +5,7 @@
|
||||
/* Queue up reminders for subsequent execution. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "globals.h"
|
||||
#include "err.h"
|
||||
#include "types.h"
|
||||
#include "protos.h"
|
||||
#include "expr.h"
|
||||
|
||||
@@ -43,6 +43,7 @@ typedef struct queuedrem {
|
||||
char passthru[PASSTHRU_LEN+1];
|
||||
char sched[VAR_NAME_LEN+1];
|
||||
DynamicBuffer tags;
|
||||
Trigger t;
|
||||
TimeTrig tt;
|
||||
} QueuedRem;
|
||||
|
||||
@@ -56,7 +57,7 @@ static void CheckInitialFile (void);
|
||||
static int CalculateNextTime (QueuedRem *q);
|
||||
static QueuedRem *FindNextReminder (void);
|
||||
static int CalculateNextTimeUsingSched (QueuedRem *q);
|
||||
static void DaemonWait (unsigned int sleeptime);
|
||||
static void DaemonWait (struct timeval *sleep_tv);
|
||||
static void reread (void);
|
||||
|
||||
/***************************************************************/
|
||||
@@ -91,6 +92,8 @@ int QueueReminder(ParsePtr p, Trigger *trig,
|
||||
qelem->typ = trig->typ;
|
||||
strcpy(qelem->passthru, trig->passthru);
|
||||
qelem->tt = *tim;
|
||||
qelem->t = *trig;
|
||||
DBufInit(&(qelem->t.tags));
|
||||
qelem->next = QueueHead;
|
||||
qelem->RunDisabled = RunDisabled;
|
||||
qelem->ntrig = 0;
|
||||
@@ -118,6 +121,8 @@ void HandleQueuedReminders(void)
|
||||
unsigned SleepTime;
|
||||
Parser p;
|
||||
Trigger trig;
|
||||
struct timeval tv;
|
||||
struct timeval sleep_tv;
|
||||
|
||||
/* Suppress the BANNER from being issued */
|
||||
NumTriggered = 1;
|
||||
@@ -179,20 +184,24 @@ void HandleQueuedReminders(void)
|
||||
while (TimeToSleep > 0L) {
|
||||
SleepTime = TimeToSleep;
|
||||
|
||||
if (Daemon > 0 && SleepTime > 60*Daemon) SleepTime = 60*Daemon;
|
||||
if (Daemon > 0 && SleepTime > (unsigned int) 60*Daemon) SleepTime = 60*Daemon;
|
||||
|
||||
/* Wake up once a minute to recalibrate sleep time in
|
||||
case of laptop hibernation */
|
||||
if (Daemon <= 0) {
|
||||
if (Daemon < 0) {
|
||||
/* Wake up on the next exact minute */
|
||||
SleepTime = 60 - (SystemTime(1)%60);
|
||||
}
|
||||
|
||||
if (Daemon >= 0) {
|
||||
sleep(SleepTime);
|
||||
gettimeofday(&tv, NULL);
|
||||
sleep_tv.tv_sec = 60 - (tv.tv_sec % 60);
|
||||
if (tv.tv_usec != 0 && sleep_tv.tv_sec != 0) {
|
||||
sleep_tv.tv_sec--;
|
||||
sleep_tv.tv_usec = 1000000 - tv.tv_usec;
|
||||
} else {
|
||||
sleep_tv.tv_usec = 0;
|
||||
}
|
||||
DaemonWait(&sleep_tv);
|
||||
} else {
|
||||
DaemonWait(SleepTime);
|
||||
}
|
||||
sleep(SleepTime);
|
||||
}
|
||||
|
||||
/* If not in daemon mode and day has rolled around,
|
||||
exit -- not much we can do. */
|
||||
@@ -243,9 +252,7 @@ void HandleQueuedReminders(void)
|
||||
|
||||
/* Set up global variables so some functions like trigdate()
|
||||
and trigtime() work correctly */
|
||||
LastTriggerDate = JulianToday;
|
||||
LastTriggerTime = q->tt.ttime;
|
||||
LastTrigValid = 1;
|
||||
SaveAllTriggerInfo(&(q->t), &(q->tt), JulianToday, q->tt.ttime, 1);
|
||||
(void) TriggerReminder(&p, &trig, &q->tt, JulianToday);
|
||||
if (Daemon < 0) {
|
||||
printf("NOTE endreminder\n");
|
||||
@@ -447,6 +454,70 @@ static int CalculateNextTimeUsingSched(QueuedRem *q)
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump the queue in JSON format */
|
||||
static void
|
||||
json_queue(QueuedRem const *q)
|
||||
{
|
||||
int done = 0;
|
||||
printf("[");
|
||||
while(q) {
|
||||
if (q->tt.nexttime == NO_TIME) {
|
||||
q = q->next;
|
||||
continue;
|
||||
}
|
||||
if (done) {
|
||||
printf(",");
|
||||
}
|
||||
done = 1;
|
||||
printf("{");
|
||||
switch(q->typ) {
|
||||
case NO_TYPE: PrintJSONKeyPairString("type", "NO_TYPE"); break;
|
||||
case MSG_TYPE: PrintJSONKeyPairString("type", "MSG_TYPE"); break;
|
||||
case RUN_TYPE: PrintJSONKeyPairString("type", "RUN_TYPE"); break;
|
||||
case CAL_TYPE: PrintJSONKeyPairString("type", "CAL_TYPE"); break;
|
||||
case SAT_TYPE: PrintJSONKeyPairString("type", "SAT_TYPE"); break;
|
||||
case PS_TYPE: PrintJSONKeyPairString("type", "PS_TYPE"); break;
|
||||
case PSF_TYPE: PrintJSONKeyPairString("type", "PSF_TYPE"); break;
|
||||
case MSF_TYPE: PrintJSONKeyPairString("type", "MSF_TYPE"); break;
|
||||
case PASSTHRU_TYPE: PrintJSONKeyPairString("type", "PASSTHRU_TYPE"); break;
|
||||
default: PrintJSONKeyPairString("type", "?"); break;
|
||||
}
|
||||
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
|
||||
PrintJSONKeyPairInt("ntrig", q->ntrig);
|
||||
PrintJSONKeyPairTime("ttime", q->tt.ttime);
|
||||
PrintJSONKeyPairTime("nextttime", q->tt.nexttime);
|
||||
PrintJSONKeyPairInt("delta", q->tt.delta);
|
||||
if (q->tt.rep != NO_TIME) {
|
||||
PrintJSONKeyPairInt("rep", q->tt.rep);
|
||||
}
|
||||
if (q->tt.duration != NO_TIME) {
|
||||
PrintJSONKeyPairInt("duration", q->tt.duration);
|
||||
}
|
||||
if (q->passthru[0]) {
|
||||
PrintJSONKeyPairString("passthru", q->passthru);
|
||||
}
|
||||
if (q->sched[0]) {
|
||||
PrintJSONKeyPairString("sched", q->sched);
|
||||
}
|
||||
if (DBufLen(&(q->tags))) {
|
||||
PrintJSONKeyPairString("tags", DBufValue(&(q->tags)));
|
||||
}
|
||||
|
||||
/* Last one is a special case - no trailing comma */
|
||||
printf("\"");
|
||||
PrintJSONString("body");
|
||||
printf("\":\"");
|
||||
if (q->text) {
|
||||
PrintJSONString(q->text);
|
||||
} else {
|
||||
PrintJSONString("");
|
||||
}
|
||||
printf("\"}");
|
||||
q = q->next;
|
||||
}
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* DaemonWait */
|
||||
@@ -454,19 +525,16 @@ static int CalculateNextTimeUsingSched(QueuedRem *q)
|
||||
/* Sleep or read command from stdin in "daemon -1" mode */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static void DaemonWait(unsigned int sleeptime)
|
||||
static void DaemonWait(struct timeval *sleep_tv)
|
||||
{
|
||||
fd_set readSet;
|
||||
struct timeval timeout;
|
||||
int retval;
|
||||
int y, m, d;
|
||||
char cmdLine[256];
|
||||
|
||||
FD_ZERO(&readSet);
|
||||
FD_SET(0, &readSet);
|
||||
timeout.tv_sec = sleeptime;
|
||||
timeout.tv_usec = 0;
|
||||
retval = select(1, &readSet, NULL, NULL, &timeout);
|
||||
retval = select(1, &readSet, NULL, NULL, sleep_tv);
|
||||
|
||||
/* If date has rolled around, restart */
|
||||
if (RealToday != SystemDate(&y, &m, &d)) {
|
||||
@@ -508,28 +576,34 @@ static void DaemonWait(unsigned int sleeptime)
|
||||
printf("NOTE queue\n");
|
||||
QueuedRem *q = QueueHead;
|
||||
while (q) {
|
||||
switch (q->typ) {
|
||||
case NO_TYPE: printf("NO_TYPE "); break;
|
||||
case MSG_TYPE: printf("MSG_TYPE "); break;
|
||||
case RUN_TYPE: printf("RUN_TYPE "); break;
|
||||
case CAL_TYPE: printf("CAL_TYPE "); break;
|
||||
case SAT_TYPE: printf("SAT_TYPE "); break;
|
||||
case PS_TYPE: printf("PS_TYPE "); break;
|
||||
case PSF_TYPE: printf("PSF_TYPE "); break;
|
||||
case MSF_TYPE: printf("MSF_TYPE "); break;
|
||||
case PASSTHRU_TYPE: printf("PASSTHRU_TYPE "); break;
|
||||
default: printf("? "); break;
|
||||
if (q->tt.nexttime != NO_TIME) {
|
||||
switch (q->typ) {
|
||||
case NO_TYPE: printf("NO_TYPE "); break;
|
||||
case MSG_TYPE: printf("MSG_TYPE "); break;
|
||||
case RUN_TYPE: printf("RUN_TYPE "); break;
|
||||
case CAL_TYPE: printf("CAL_TYPE "); break;
|
||||
case SAT_TYPE: printf("SAT_TYPE "); break;
|
||||
case PS_TYPE: printf("PS_TYPE "); break;
|
||||
case PSF_TYPE: printf("PSF_TYPE "); break;
|
||||
case MSF_TYPE: printf("MSF_TYPE "); break;
|
||||
case PASSTHRU_TYPE: printf("PASSTHRU_TYPE "); break;
|
||||
default: printf("? "); 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));
|
||||
printf("%s %s %s\n",
|
||||
(q->passthru[0] ? q->passthru : "*"),
|
||||
(q->sched[0] ? q->sched : "*"),
|
||||
q->text ? q->text : "NULL");
|
||||
}
|
||||
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));
|
||||
printf("%s %s %s\n",
|
||||
(q->passthru[0] ? q->passthru : "*"),
|
||||
(q->sched[0] ? q->sched : "*"),
|
||||
q->text ? q->text : "NULL");
|
||||
|
||||
q = q->next;
|
||||
}
|
||||
printf("NOTE endqueue\n");
|
||||
fflush(stdout);
|
||||
} else if (!strcmp(cmdLine, "JSONQUEUE\n")) {
|
||||
printf("NOTE JSONQUEUE\n");
|
||||
json_queue(QueueHead);
|
||||
printf("NOTE ENDJSONQUEUE\n");
|
||||
fflush(stdout);
|
||||
} else if (!strcmp(cmdLine, "REREAD\n")) {
|
||||
printf("NOTE reread\n");
|
||||
fflush(stdout);
|
||||
|
||||
415
src/rem2ps.c
@@ -5,7 +5,7 @@
|
||||
/* Print a PostScript calendar. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include "rem2ps.h"
|
||||
#include "json.h"
|
||||
|
||||
#define NEW(type) (malloc(sizeof(type)))
|
||||
|
||||
@@ -30,6 +31,7 @@
|
||||
#define SPECIAL_COLOR 4
|
||||
#define SPECIAL_WEEK 5
|
||||
#define SPECIAL_SHADE 6
|
||||
#define SPECIAL_UNKNOWN 7
|
||||
|
||||
/* Array holding how specials sort */
|
||||
static int SpecialSortOrder[] = {
|
||||
@@ -46,6 +48,7 @@ typedef struct calentry {
|
||||
struct calentry *next;
|
||||
int special;
|
||||
char *entry;
|
||||
int daynum;
|
||||
} CalEntry;
|
||||
|
||||
typedef struct {
|
||||
@@ -62,7 +65,7 @@ char const *SmallCalLoc[] = {
|
||||
"sbt",
|
||||
};
|
||||
|
||||
#define NUMSMALL (sizeof(SmallCalLoc)/sizeof(SmallCalLoc[0]))
|
||||
#define NUMSMALL ((int) (sizeof(SmallCalLoc)/sizeof(SmallCalLoc[0])))
|
||||
char const *SmallLocation;
|
||||
int SmallCol1, SmallCol2;
|
||||
|
||||
@@ -96,6 +99,7 @@ CalEntry *CurEntries = NULL;
|
||||
CalEntry *PsEntries[32];
|
||||
PageType *CurPage;
|
||||
char PortraitMode;
|
||||
char DaynumRight;
|
||||
char NoSmallCal;
|
||||
char UseISO;
|
||||
|
||||
@@ -137,6 +141,184 @@ void WriteOneEntry (CalEntry *c);
|
||||
void GetSmallLocations (void);
|
||||
char const *EatToken(char const *in, char *out, int maxlen);
|
||||
|
||||
static void
|
||||
put_escaped_string(char const *s)
|
||||
{
|
||||
while(*s) {
|
||||
if (*s == '\\' || *s == '(' || *s == ')') {
|
||||
PutChar('\\');
|
||||
}
|
||||
PutChar(*s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* StrCmpi */
|
||||
/* */
|
||||
/* Compare strings, case insensitive. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int StrCmpi(char const *s1, char const *s2)
|
||||
{
|
||||
int r;
|
||||
while (*s1 && *s2) {
|
||||
r = toupper(*s1) - toupper(*s2);
|
||||
if (r) return r;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
return toupper(*s1) - toupper(*s2);
|
||||
}
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* Parse the new-style JSON intermediate format */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static CalEntry *
|
||||
JSONToCalEntry(DynamicBuffer *buf)
|
||||
{
|
||||
CalEntry *c;
|
||||
json_value *val;
|
||||
|
||||
val = json_parse(DBufValue(buf), DBufLen(buf));
|
||||
if (!val) {
|
||||
fprintf(stderr, "Unable to parse JSON line `%s'\n", DBufValue(buf));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (val->type != json_object) {
|
||||
fprintf(stderr, "Expecting JSON object; found `%s'\n",
|
||||
DBufValue(buf));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
c = NEW(CalEntry);
|
||||
if (!c) {
|
||||
fprintf(stderr, "malloc failed - aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
c->next = NULL;
|
||||
c->special = SPECIAL_NORMAL;
|
||||
|
||||
int got_date = 0, got_body = 0;
|
||||
size_t i;
|
||||
for (i=0; i<val->u.object.length; i++) {
|
||||
char const *nm = val->u.object.values[i].name;
|
||||
json_value *v = val->u.object.values[i].value;
|
||||
char const *s;
|
||||
if (!strcmp(nm, "date")) {
|
||||
if (v->type == json_string) {
|
||||
s = v->u.string.ptr;
|
||||
c->daynum = (s[8] - '0') * 10 + s[9] - '0';
|
||||
got_date = 1;
|
||||
}
|
||||
} else if (!strcmp(nm, "body")) {
|
||||
if (v->type == json_string) {
|
||||
s = v->u.string.ptr;
|
||||
c->entry = malloc(strlen(s)+1);
|
||||
if (!c->entry) {
|
||||
fprintf(stderr, "malloc failed - aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
strcpy(c->entry, s);
|
||||
got_body = 1;
|
||||
}
|
||||
} else if (!strcmp(nm, "passthru")) {
|
||||
if (v->type == json_string) {
|
||||
s = v->u.string.ptr;
|
||||
if (!StrCmpi(s, "PostScript")) {
|
||||
c->special = SPECIAL_POSTSCRIPT;
|
||||
} else if (!StrCmpi(s, "SHADE")) {
|
||||
c->special = SPECIAL_SHADE;
|
||||
} else if (!StrCmpi(s, "MOON")) {
|
||||
c->special = SPECIAL_MOON;
|
||||
} else if (!StrCmpi(s, "WEEK")) {
|
||||
c->special = SPECIAL_WEEK;
|
||||
} else if (!StrCmpi(s, "PSFile")) {
|
||||
c->special = SPECIAL_PSFILE;
|
||||
} else if (!StrCmpi(s, "COLOUR") ||
|
||||
!StrCmpi(s, "COLOR")) {
|
||||
c->special = SPECIAL_COLOR;
|
||||
} else {
|
||||
c->special = SPECIAL_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
json_value_free(val);
|
||||
|
||||
if (!got_body || !got_date) {
|
||||
fprintf(stderr, "Could not parse line `%s'\n", DBufValue(buf));
|
||||
exit(1);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* Parse the old-style REM2PS intermediate format */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static CalEntry *
|
||||
TextToCalEntry(DynamicBuffer *buf)
|
||||
{
|
||||
char const *startOfBody;
|
||||
char passthru[PASSTHRU_LEN+1];
|
||||
|
||||
CalEntry *c = NEW(CalEntry);
|
||||
if (!c) {
|
||||
fprintf(stderr, "malloc failed - aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
c->next = NULL;
|
||||
c->special = SPECIAL_NORMAL;
|
||||
c->daynum = (DBufValue(buf)[8] - '0') * 10 + DBufValue(buf)[9] - '0';
|
||||
|
||||
/* Skip the tag, duration and time */
|
||||
startOfBody = DBufValue(buf)+10;
|
||||
|
||||
/* Eat the passthru */
|
||||
startOfBody = EatToken(startOfBody, passthru, PASSTHRU_LEN);
|
||||
|
||||
/* Eat the tag */
|
||||
startOfBody = EatToken(startOfBody, NULL, 0);
|
||||
|
||||
/* Eat the duration */
|
||||
startOfBody = EatToken(startOfBody, NULL, 0);
|
||||
|
||||
/* Eat the time */
|
||||
startOfBody = EatToken(startOfBody, NULL, 0);
|
||||
|
||||
c->entry = malloc(strlen(startOfBody) + 1);
|
||||
if (!c->entry) {
|
||||
fprintf(stderr, "malloc failed - aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
strcpy(c->entry, startOfBody);
|
||||
|
||||
/* Save the type of SPECIAL */
|
||||
if (!StrCmpi(passthru, "PostScript")) {
|
||||
c->special = SPECIAL_POSTSCRIPT;
|
||||
} else if (!StrCmpi(passthru, "SHADE")) {
|
||||
c->special = SPECIAL_SHADE;
|
||||
} else if (!StrCmpi(passthru, "MOON")) {
|
||||
c->special = SPECIAL_MOON;
|
||||
} else if (!StrCmpi(passthru, "WEEK")) {
|
||||
c->special = SPECIAL_WEEK;
|
||||
} else if (!StrCmpi(passthru, "PSFile")) {
|
||||
c->special = SPECIAL_PSFILE;
|
||||
} else if (!StrCmpi(passthru, "COLOUR") ||
|
||||
!StrCmpi(passthru, "COLOR")) {
|
||||
c->special = SPECIAL_COLOR;
|
||||
} else if (StrCmpi(passthru, "*")) {
|
||||
c->special = SPECIAL_UNKNOWN;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* MAIN PROGRAM */
|
||||
@@ -154,13 +336,20 @@ int main(int argc, char *argv[])
|
||||
Usage("Input should not come from a terminal");
|
||||
}
|
||||
|
||||
int first_line = 1;
|
||||
/* Search for a valid input file */
|
||||
while (!feof(stdin)) {
|
||||
DBufGets(&buf, stdin);
|
||||
if (!strcmp(DBufValue(&buf), PSBEGIN)) {
|
||||
if (first_line && (!strcmp(DBufValue(&buf), "["))) {
|
||||
fprintf(stderr, "Rem2PS: It appears that you have invoked Remind with the -ppp option.\n Please use either -p or -pp, but not -ppp.\n");
|
||||
exit(1);
|
||||
}
|
||||
first_line = 0;
|
||||
if (!strcmp(DBufValue(&buf), PSBEGIN) ||
|
||||
!strcmp(DBufValue(&buf), PSBEGIN2)) {
|
||||
if (!validfile) {
|
||||
if (Verbose) {
|
||||
fprintf(stderr, "Rem2PS: Version %s Copyright 1992-1998 by Dianne Skoll\n\n", VERSION);
|
||||
fprintf(stderr, "Rem2PS: Version %s Copyright 1992-2021 by Dianne Skoll\n\n", VERSION);
|
||||
fprintf(stderr, "Generating PostScript calendar\n");
|
||||
}
|
||||
}
|
||||
@@ -191,10 +380,7 @@ void DoPsCal(void)
|
||||
int days, wkday, prevdays, nextdays;
|
||||
int sfirst;
|
||||
int i;
|
||||
int is_ps;
|
||||
int firstcol;
|
||||
char const *startOfBody;
|
||||
char passthru[PASSTHRU_LEN+1];
|
||||
DynamicBuffer buf;
|
||||
CalEntry *c, *d, *p;
|
||||
|
||||
@@ -230,6 +416,7 @@ void DoPsCal(void)
|
||||
|
||||
printf("%%%%Page: %c%c%c%c%c %d\n", month[0], month[1], month[2],
|
||||
year[2], year[3], validfile);
|
||||
printf("%%%%PageBoundingBox: 0 0 %d %d\n", CurPage->xsize, CurPage->ysize);
|
||||
|
||||
/* Emit PostScript to do the heading */
|
||||
if (!PortraitMode) printf("90 rotate 0 XSIZE neg translate\n");
|
||||
@@ -272,80 +459,48 @@ void DoPsCal(void)
|
||||
}
|
||||
|
||||
DBufGets(&buf, stdin);
|
||||
if (!strcmp(DBufValue(&buf), PSEND)) {
|
||||
if (!strcmp(DBufValue(&buf), PSEND) ||
|
||||
!strcmp(DBufValue(&buf), PSEND2)) {
|
||||
DBufFree(&buf);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Ignore lines beginning with '#' */
|
||||
if (DBufValue(&buf)[0] == '#') {
|
||||
DBufFree(&buf);
|
||||
continue;
|
||||
}
|
||||
/* Read the day number - a bit of a hack! */
|
||||
DayNum = (DBufValue(&buf)[8] - '0') * 10 + DBufValue(&buf)[9] - '0';
|
||||
if (DayNum != CurDay) {
|
||||
for(; CurDay<DayNum; CurDay++) {
|
||||
|
||||
if (DBufValue(&buf)[0] == '{') {
|
||||
/* Starts with '{', so assume new-style JSON format */
|
||||
c = JSONToCalEntry(&buf);
|
||||
} else {
|
||||
/* Assume it's the old-style rem2ps intermediate format */
|
||||
c = TextToCalEntry(&buf);
|
||||
}
|
||||
|
||||
/* If it's an unknown special, ignore */
|
||||
if (c->special == SPECIAL_UNKNOWN) {
|
||||
DBufFree(&buf);
|
||||
free(c);
|
||||
c = NULL;
|
||||
continue;
|
||||
}
|
||||
if (c->daynum != CurDay) {
|
||||
for(; CurDay<c->daynum; CurDay++) {
|
||||
WriteCalEntry();
|
||||
WkDayNum = (WkDayNum + 1) % 7;
|
||||
}
|
||||
}
|
||||
/* Add the text */
|
||||
c = NEW(CalEntry);
|
||||
if (!c) {
|
||||
fprintf(stderr, "malloc failed - aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
c->next = NULL;
|
||||
c->special = SPECIAL_NORMAL;
|
||||
|
||||
/* Skip the tag, duration and time */
|
||||
startOfBody = DBufValue(&buf)+10;
|
||||
|
||||
/* Eat the passthru */
|
||||
startOfBody = EatToken(startOfBody, passthru, PASSTHRU_LEN);
|
||||
|
||||
/* Eat the tag */
|
||||
startOfBody = EatToken(startOfBody, NULL, 0);
|
||||
|
||||
/* Eat the duration */
|
||||
startOfBody = EatToken(startOfBody, NULL, 0);
|
||||
|
||||
/* Eat the time */
|
||||
startOfBody = EatToken(startOfBody, NULL, 0);
|
||||
|
||||
is_ps = 0;
|
||||
if (!strcmp(passthru, "PostScript") ||
|
||||
!strcmp(passthru, "PSFile") ||
|
||||
!strcmp(passthru, "MOON") ||
|
||||
!strcmp(passthru, "WEEK") ||
|
||||
!strcmp(passthru, "SHADE")) {
|
||||
is_ps = 1;
|
||||
}
|
||||
c->entry = malloc(strlen(startOfBody) + 1);
|
||||
if (!c->entry) {
|
||||
fprintf(stderr, "malloc failed - aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
strcpy(c->entry, startOfBody);
|
||||
|
||||
if (is_ps) {
|
||||
/* Save the type of SPECIAL */
|
||||
if (!strcmp(passthru, "PostScript")) {
|
||||
c->special = SPECIAL_POSTSCRIPT;
|
||||
} else if (!strcmp(passthru, "SHADE")) {
|
||||
c->special = SPECIAL_SHADE;
|
||||
} else if (!strcmp(passthru, "MOON")) {
|
||||
c->special = SPECIAL_MOON;
|
||||
} else if (!strcmp(passthru, "WEEK")) {
|
||||
c->special = SPECIAL_WEEK;
|
||||
if (c->special == SPECIAL_POSTSCRIPT ||
|
||||
c->special == SPECIAL_SHADE ||
|
||||
c->special == SPECIAL_MOON ||
|
||||
c->special == SPECIAL_WEEK ||
|
||||
c->special == SPECIAL_PSFILE) {
|
||||
if (!PsEntries[c->daynum]) {
|
||||
PsEntries[c->daynum] = c;
|
||||
} else {
|
||||
c->special = SPECIAL_PSFILE;
|
||||
}
|
||||
|
||||
if (!PsEntries[DayNum]) {
|
||||
PsEntries[DayNum] = c;
|
||||
} else {
|
||||
d = PsEntries[DayNum];
|
||||
d = PsEntries[c->daynum];
|
||||
p = NULL;
|
||||
/* Slot it into the right place */
|
||||
while (d->next && (SpecialSortOrder[c->special] <= SpecialSortOrder[d->special])) {
|
||||
@@ -359,14 +514,12 @@ void DoPsCal(void)
|
||||
if (p) {
|
||||
p->next = c;
|
||||
} else {
|
||||
PsEntries[DayNum] = c;
|
||||
PsEntries[c->daynum] = c;
|
||||
}
|
||||
c->next = d;
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(passthru, "*") ||
|
||||
!strcmp(passthru, "COLOUR") ||
|
||||
!strcmp(passthru, "COLOR")) {
|
||||
} else {
|
||||
/* Put on linked list */
|
||||
if (!CurEntries) {
|
||||
CurEntries = c;
|
||||
@@ -375,10 +528,6 @@ void DoPsCal(void)
|
||||
while(d->next) d = d->next;
|
||||
d->next = c;
|
||||
}
|
||||
if (!strcmp(passthru, "COLOR") ||
|
||||
!strcmp(passthru, "COLOUR")) {
|
||||
c->special = SPECIAL_COLOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(; CurDay<=days; CurDay++) {
|
||||
@@ -451,6 +600,12 @@ void WriteProlog(void)
|
||||
printf("%%%%Pages: (atend)\n");
|
||||
printf("%%%%Orientation: %s\n", PortraitMode ? "Portrait" : "Landscape");
|
||||
printf("%%%%EndComments\n");
|
||||
if (PortraitMode) {
|
||||
printf("<< /PageSize [%d %d] >> setpagedevice\n", x, y);
|
||||
} else {
|
||||
/* They were swapped up above, so swap them back or we'll get rotated output */
|
||||
printf("<< /PageSize [%d %d] >> setpagedevice\n", y, x);
|
||||
}
|
||||
|
||||
for (i=0; PSProlog1[i]; i++) puts(PSProlog1[i]);
|
||||
if (!MondayFirst)
|
||||
@@ -543,7 +698,7 @@ void WriteCalEntry(void)
|
||||
printf("]\n");
|
||||
|
||||
/* Print the day number */
|
||||
printf("(%d)\n", CurDay);
|
||||
printf("(%d) %d\n", CurDay, (int) DaynumRight);
|
||||
/* Do it! */
|
||||
printf("DoCalBox\n");
|
||||
|
||||
@@ -669,7 +824,8 @@ void Init(int argc, char *argv[])
|
||||
char const *s;
|
||||
char const *t;
|
||||
int i=1;
|
||||
int j;
|
||||
size_t j;
|
||||
int k;
|
||||
int offset;
|
||||
|
||||
PortraitMode = 1;
|
||||
@@ -682,6 +838,7 @@ void Init(int argc, char *argv[])
|
||||
FillPage = 0;
|
||||
MondayFirst = 0;
|
||||
SmallLocation = "bt";
|
||||
DaynumRight = 1;
|
||||
|
||||
for(j=0; j<32; j++) PsEntries[i] = NULL;
|
||||
|
||||
@@ -798,13 +955,14 @@ void Init(int argc, char *argv[])
|
||||
|
||||
case 'i': UseISO = 1; break;
|
||||
|
||||
case 'c': j=(*s);
|
||||
if (!j) {
|
||||
case 'x': DaynumRight = 0; break;
|
||||
case 'c': k=(*s);
|
||||
if (!k) {
|
||||
SmallLocation = SmallCalLoc[0];
|
||||
} else {
|
||||
j -= '0';
|
||||
if (j>=0 && j<NUMSMALL) {
|
||||
SmallLocation = SmallCalLoc[j];
|
||||
k -= '0';
|
||||
if (k>=0 && k<NUMSMALL) {
|
||||
SmallLocation = SmallCalLoc[k];
|
||||
} else {
|
||||
SmallLocation = SmallCalLoc[0];
|
||||
}
|
||||
@@ -842,6 +1000,7 @@ void Usage(char const *s)
|
||||
fprintf(stderr, "-b size Set border size for calendar entries\n");
|
||||
fprintf(stderr, "-t size Set line thickness\n");
|
||||
fprintf(stderr, "-e Make calendar fill entire page\n");
|
||||
fprintf(stderr, "-x Put day numbers on left instead of right\n");
|
||||
fprintf(stderr, "-o[lrtb] marg Specify left, right, top and bottom margins\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -917,10 +1076,10 @@ int DoQueuedPs(void)
|
||||
FILE *fp;
|
||||
int fnoff;
|
||||
char buffer[512];
|
||||
char const *size, *extra;
|
||||
char fbuffer[512];
|
||||
char const *size, *fsize, *extra;
|
||||
char const *s;
|
||||
int num, r, g, b, phase, fontsize, moonsize;
|
||||
unsigned char c;
|
||||
|
||||
if (!MondayFirst) begin = CurDay - WkDayNum;
|
||||
else begin = CurDay - (WkDayNum ? WkDayNum-1 : 6);
|
||||
@@ -992,19 +1151,28 @@ int DoQueuedPs(void)
|
||||
while(*s && isspace(*s)) {
|
||||
s++;
|
||||
}
|
||||
while(*s) {
|
||||
if (*s == '\\' || *s == '(' || *s == ')') {
|
||||
PutChar('\\');
|
||||
}
|
||||
PutChar(*s);
|
||||
s++;
|
||||
}
|
||||
put_escaped_string(s);
|
||||
printf(") show grestore\n");
|
||||
break;
|
||||
|
||||
case SPECIAL_MOON: /* Moon phase */
|
||||
num = sscanf(e->entry+fnoff, "%d %d %d", &phase, &moonsize,
|
||||
&fontsize);
|
||||
/* See if we have extra stuff */
|
||||
extra = e->entry+fnoff;
|
||||
|
||||
/* Skip phase */
|
||||
while(*extra && !isspace(*extra)) extra++;
|
||||
while(*extra && isspace(*extra)) extra++;
|
||||
|
||||
/* Skip moon size */
|
||||
while(*extra && !isspace(*extra)) extra++;
|
||||
while(*extra && isspace(*extra)) extra++;
|
||||
|
||||
/* Skip font size */
|
||||
while(*extra && !isspace(*extra)) extra++;
|
||||
while(*extra && isspace(*extra)) extra++;
|
||||
|
||||
if (num == 1) {
|
||||
moonsize = -1;
|
||||
fontsize = -1;
|
||||
@@ -1026,7 +1194,27 @@ int DoQueuedPs(void)
|
||||
size = buffer;
|
||||
}
|
||||
|
||||
printf("gsave 0 setgray newpath Border %s add BoxHeight Border sub %s sub\n", size, size);
|
||||
/* Store the starting X coordinate in "moonstartx" */
|
||||
if (DaynumRight) {
|
||||
printf("Border %s add /moonstartx exch def", size);
|
||||
} else {
|
||||
printf("xincr Border sub %s sub ", size);
|
||||
if (*extra) {
|
||||
if (fontsize < 0) {
|
||||
fsize = "EntrySize";
|
||||
} else {
|
||||
sprintf(fbuffer, "%d", fontsize);
|
||||
fsize = fbuffer;
|
||||
}
|
||||
printf("/EntryFont findfont %s scalefont setfont (",
|
||||
fsize);
|
||||
put_escaped_string(extra);
|
||||
printf(") stringwidth pop sub Border sub ");
|
||||
}
|
||||
printf("/moonstartx exch def\n");
|
||||
}
|
||||
printf(" gsave 0 setgray newpath ");
|
||||
printf("moonstartx BoxHeight Border sub %s sub\n", size);
|
||||
printf(" %s 0 360 arc closepath\n", size);
|
||||
switch(phase) {
|
||||
case 0:
|
||||
@@ -1037,49 +1225,28 @@ int DoQueuedPs(void)
|
||||
break;
|
||||
|
||||
case 1:
|
||||
printf("stroke\n");
|
||||
printf("newpath Border %s add BoxHeight Border sub %s sub\n",
|
||||
size, size);
|
||||
printf("stroke\nnewpath ");
|
||||
printf("moonstartx BoxHeight Border sub %s sub\n", size);
|
||||
printf("%s 90 270 arc closepath fill\n", size);
|
||||
break;
|
||||
default:
|
||||
printf("stroke\n");
|
||||
printf("newpath Border %s add BoxHeight Border sub %s sub\n",
|
||||
size, size);
|
||||
printf("stroke\nnewpath ");
|
||||
printf("moonstartx BoxHeight Border sub %s sub\n", size);
|
||||
printf("%s 270 90 arc closepath fill\n", size);
|
||||
break;
|
||||
}
|
||||
/* See if we have extra stuff */
|
||||
extra = e->entry+fnoff;
|
||||
|
||||
/* Skip phase */
|
||||
while(*extra && !isspace(*extra)) extra++;
|
||||
while(*extra && isspace(*extra)) extra++;
|
||||
|
||||
/* Skip moon size */
|
||||
while(*extra && !isspace(*extra)) extra++;
|
||||
while(*extra && isspace(*extra)) extra++;
|
||||
|
||||
/* Skip font size */
|
||||
while(*extra && !isspace(*extra)) extra++;
|
||||
while(*extra && isspace(*extra)) extra++;
|
||||
|
||||
/* Anything left? */
|
||||
if (*extra) {
|
||||
printf("Border %s add %s add Border add BoxHeight border sub %s sub %s sub moveto\n", size, size, size, size);
|
||||
printf("moonstartx %s add Border add BoxHeight border sub %s sub %s sub moveto\n", size, size, size);
|
||||
if (fontsize < 0) {
|
||||
size = "EntrySize";
|
||||
fsize = "EntrySize";
|
||||
} else {
|
||||
sprintf(buffer, "%d", fontsize);
|
||||
size = buffer;
|
||||
sprintf(fbuffer, "%d", fontsize);
|
||||
fsize = fbuffer;
|
||||
}
|
||||
printf("/EntryFont findfont %s scalefont setfont (",
|
||||
size);
|
||||
while(*extra) {
|
||||
c = (unsigned char) *extra++;
|
||||
if (c == '\\' || c == '(' || c == ')') PutChar('\\');
|
||||
PutChar(c);
|
||||
}
|
||||
fsize);
|
||||
put_escaped_string(extra);
|
||||
printf(") show\n");
|
||||
|
||||
}
|
||||
|
||||
13
src/rem2ps.h
@@ -5,7 +5,7 @@
|
||||
/* Define the PostScript prologue */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -13,7 +13,7 @@ char *PSProlog1[] =
|
||||
{
|
||||
"% This file was produced by Remind and Rem2PS, written by",
|
||||
"% Dianne Skoll.",
|
||||
"% Remind and Rem2PS are Copyright 1992-1997 Dianne Skoll.",
|
||||
"% Remind and Rem2PS are Copyright 1992-2021 Dianne Skoll.",
|
||||
"/ISOLatin1Encoding where { pop save true }{ false } ifelse",
|
||||
" /ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus",
|
||||
" StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute",
|
||||
@@ -196,9 +196,10 @@ char *PSProlog2[] =
|
||||
"% Variables for calendar boxes:",
|
||||
"% ytop - current top position",
|
||||
"% ymin - minimum y reached for current row",
|
||||
"% border ytop xleft width textarray daynum DoCalBox ybot",
|
||||
"% border ytop xleft width textarray daynum onright DoCalBox ybot",
|
||||
"% Do the entries for one calendar box. Returns lowest Y-coordinate reached",
|
||||
"/DoCalBox {",
|
||||
" /onright exch def",
|
||||
" /daynum exch def",
|
||||
" /textarr exch def",
|
||||
" /wid exch def",
|
||||
@@ -207,8 +208,10 @@ char *PSProlog2[] =
|
||||
" /border exch def",
|
||||
"% Do the day number",
|
||||
" /DayFont findfont DaySize scalefont setfont",
|
||||
" xl wid add border sub daynum stringwidth pop sub",
|
||||
" yt border sub DaySize sub moveto daynum show",
|
||||
" onright 1 eq",
|
||||
" {xl wid add border sub daynum stringwidth pop sub yt border sub DaySize sub moveto daynum show}",
|
||||
" {xl border add yt border sub DaySize sub moveto daynum show}",
|
||||
" ifelse",
|
||||
"% Do the text entries. Precharge the stack with current y pos.",
|
||||
" /ycur yt border sub DaySize sub DaySize sub 2 add def",
|
||||
" /EntryFont findfont EntrySize scalefont setfont",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/* Routines for sorting reminders by trigger date */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -150,7 +150,7 @@ void IssueSortedReminders(void)
|
||||
break;
|
||||
|
||||
case RUN_TYPE:
|
||||
system(cur->text);
|
||||
System(cur->text);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
53
src/token.c
@@ -6,7 +6,7 @@
|
||||
/* classifying the tokens parsed. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -37,7 +37,7 @@ while (isdigit(*(string))) { \
|
||||
Keep this array sorted, or software will not work. */
|
||||
Token TokArray[] = {
|
||||
/* NAME MINLEN TYPE VALUE */
|
||||
|
||||
{ "addomit", 7, T_AddOmit, 0 },
|
||||
{ "after", 3, T_Skip, AFTER_SKIP },
|
||||
{ "april", 3, T_Month, 3 },
|
||||
{ "at", 2, T_At, 0 },
|
||||
@@ -48,6 +48,7 @@ Token TokArray[] = {
|
||||
{ "clear-omit-context", 5, T_Clr, 0 },
|
||||
{ "debug", 5, T_Debug, 0 },
|
||||
{ "december", 3, T_Month, 11 },
|
||||
{ "do", 2, T_IncludeR, 0 },
|
||||
{ "dumpvars", 4, T_Dumpvars, 0 },
|
||||
{ "duration", 3, T_Duration, 0 },
|
||||
{ "else", 4, T_Else, 0 },
|
||||
@@ -62,11 +63,13 @@ Token TokArray[] = {
|
||||
{ "if", 2, T_If, 0 },
|
||||
{ "iftrig", 6, T_IfTrig, 0 },
|
||||
{ "include", 3, T_Include, 0 },
|
||||
{ "includecmd", 10, T_IncludeCmd, 0 },
|
||||
{ "january", 3, T_Month, 0 },
|
||||
{ "july", 3, T_Month, 6 },
|
||||
{ "june", 3, T_Month, 5 },
|
||||
{ "march", 3, T_Month, 2 },
|
||||
{ "may", 3, T_Month, 4 },
|
||||
{ "maybe-uncomputable", 5, T_MaybeUncomputable, 0},
|
||||
{ "monday", 3, T_WkDay, 0 },
|
||||
{ "msf", 3, T_RemType, MSF_TYPE },
|
||||
{ "msg", 3, T_RemType, MSG_TYPE },
|
||||
@@ -171,6 +174,10 @@ void FindToken(char const *s, Token *tok)
|
||||
int top, bot, mid, r, max;
|
||||
int l;
|
||||
|
||||
#if LANG != ENGLISH
|
||||
size_t i;
|
||||
#endif
|
||||
|
||||
tok->type = T_Illegal;
|
||||
if (! *s) {
|
||||
tok->type = T_Empty;
|
||||
@@ -228,11 +235,11 @@ void FindToken(char const *s, Token *tok)
|
||||
/* If language is other than English, search the DayNames[] and MonthNames[]
|
||||
array. */
|
||||
#if LANG != ENGLISH
|
||||
for (r=0; r<(sizeof(NonEnglishToks) / sizeof(Token)); r++) {
|
||||
if (l >= NonEnglishToks[r].MinLen &&
|
||||
!TokStrCmp(&NonEnglishToks[r], s)) {
|
||||
tok->type = NonEnglishToks[r].type;
|
||||
tok->val = NonEnglishToks[r].val;
|
||||
for (i=0; i<(sizeof(NonEnglishToks) / sizeof(Token)); i++) {
|
||||
if (l >= NonEnglishToks[i].MinLen &&
|
||||
!TokStrCmp(&NonEnglishToks[i], s)) {
|
||||
tok->type = NonEnglishToks[i].type;
|
||||
tok->val = NonEnglishToks[i].val;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -257,6 +264,7 @@ void FindNumericToken(char const *s, Token *t)
|
||||
{
|
||||
int mult = 1, hour, min;
|
||||
char const *s_orig = s;
|
||||
int ampm = 0;
|
||||
|
||||
t->type = T_Illegal;
|
||||
t->val = 0;
|
||||
@@ -284,10 +292,6 @@ void FindNumericToken(char const *s, Token *t)
|
||||
like Jan 6, 1998 */
|
||||
if (*s == ',') {
|
||||
s++;
|
||||
/* Special hack - convert years between 90 and
|
||||
99 to 1990 and 1999 */
|
||||
if (t->val >= 90 && t->val <= 99) t->val += 1900;
|
||||
|
||||
/* Classify the number we've got */
|
||||
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;
|
||||
@@ -299,7 +303,29 @@ void FindNumericToken(char const *s, Token *t)
|
||||
s++;
|
||||
hour = t->val;
|
||||
PARSENUM(min, s);
|
||||
if (*s || min > 59) return; /* Illegal time */
|
||||
if (min > 59) return; /* Illegal time */
|
||||
/* Check for p[m] or a[m] */
|
||||
if (*s == 'A' || *s == 'a' || *s == 'P' || *s == 'p') {
|
||||
ampm = tolower(*s);
|
||||
s++;
|
||||
if (*s == 'm' || *s == 'M') {
|
||||
s++;
|
||||
}
|
||||
}
|
||||
if (*s) return; /* Illegal time */
|
||||
if (ampm) {
|
||||
if (hour < 1 || hour > 12) return;
|
||||
if (ampm == 'a') {
|
||||
if (hour == 12) {
|
||||
hour = 0;
|
||||
}
|
||||
} else if (ampm == 'p') {
|
||||
if (hour < 12) {
|
||||
hour += 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t->val = hour*60 + min; /* Convert to minutes past midnight */
|
||||
if (hour <= 23) {
|
||||
t->type = T_Time;
|
||||
@@ -312,9 +338,6 @@ void FindNumericToken(char const *s, Token *t)
|
||||
/* If we hit a non-digit, error! */
|
||||
if (*s) return;
|
||||
|
||||
/* Special hack - convert years between 90 and 99 to 1990 and 1999 */
|
||||
if (t->val >= 90 && t->val <= 99) t->val += 1900;
|
||||
|
||||
/* Classify the number we've got */
|
||||
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;
|
||||
|
||||
217
src/trigger.c
@@ -5,7 +5,7 @@
|
||||
/* Routines for figuring out the trigger date of a reminder */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#define GOT_YR 4
|
||||
#define GOT_WD 8
|
||||
|
||||
#define ADVANCE_TO_WD(x, wd) while (! ((wd) & (1 << ((x)%7)))) (x)++
|
||||
|
||||
static int JYear(int jul);
|
||||
static int JMonth(int jul);
|
||||
static int NextSimpleTrig(int startdate, Trigger *trig, int *err);
|
||||
@@ -58,9 +60,10 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
||||
if (trig->wd != NO_WD) typ |= GOT_WD;
|
||||
switch(typ) {
|
||||
case 0:
|
||||
return startdate;
|
||||
|
||||
case GOT_WD:
|
||||
if (trig->wd != NO_WD)
|
||||
while(! (trig->wd & (1 << (startdate%7)))) startdate++;
|
||||
ADVANCE_TO_WD(startdate, trig->wd);
|
||||
return startdate;
|
||||
|
||||
case GOT_DAY:
|
||||
@@ -83,12 +86,12 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
||||
else return -1;
|
||||
|
||||
case GOT_DAY+GOT_MON:
|
||||
if (m > trig->m || (m == trig->m && d > trig->d)) y++;
|
||||
if (trig->d > MonthDays[trig->m]) {
|
||||
*err = E_BAD_DATE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (m > trig->m || (m == trig->m && d > trig->d)) y++;
|
||||
/* Take care of Feb. 29 */
|
||||
while (trig->d > DaysInMonth(trig->m, y)) y++;
|
||||
return Julian(y, trig->m, trig->d);
|
||||
@@ -121,19 +124,19 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
||||
if (y > trig->y) return -1;
|
||||
if (y < trig->y) j = Julian(trig->y, 0, 1);
|
||||
else j = startdate;
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
if (JYear(j) > trig->y) return -1;
|
||||
return j;
|
||||
|
||||
case GOT_MON+GOT_WD:
|
||||
if (m == trig->m) {
|
||||
j = startdate;
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
if (JMonth(j) == trig->m) return j;
|
||||
}
|
||||
if (m >= trig->m) j = Julian(y+1, trig->m, 1);
|
||||
else j = Julian(y, trig->m, 1);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
return j; /* Guaranteed to be within the month */
|
||||
|
||||
case GOT_DAY+GOT_WD:
|
||||
@@ -144,7 +147,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
||||
/* If there are fewer days in previous month, no match */
|
||||
if (trig->d <= DaysInMonth(m2, y2)) {
|
||||
j = Julian(y2, m2, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
if (j >= startdate) return j;
|
||||
|
||||
}
|
||||
@@ -153,7 +156,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
||||
/* Try this month */
|
||||
if (trig->d <= DaysInMonth(m, y)) {
|
||||
j = Julian(y, m, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
if (j >= startdate) return j;
|
||||
}
|
||||
|
||||
@@ -162,18 +165,18 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
||||
if (m2 > 11) { m2 = 0; y++; }
|
||||
while (trig->d > DaysInMonth(m2, y)) m2++;
|
||||
j = Julian(y, m2, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
return j;
|
||||
|
||||
case GOT_WD+GOT_YR+GOT_DAY:
|
||||
if (y > trig->y+1 || (y > trig->y && m>0)) return -1;
|
||||
if (y > trig->y) {
|
||||
j = Julian(trig->y, 11, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
if (j >= startdate) return j;
|
||||
} else if (y < trig->y) {
|
||||
j = Julian(trig->y, 0, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
return j;
|
||||
} else {
|
||||
/* Try last month */
|
||||
@@ -181,14 +184,16 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
||||
m2 = m-1;
|
||||
while (trig->d > DaysInMonth(m2, trig->y)) m2--;
|
||||
j = Julian(trig->y, m2, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
if (JYear(j) > trig->y) return -1;
|
||||
if (j >= startdate) return j;
|
||||
}
|
||||
}
|
||||
/* Try this month */
|
||||
if (trig->d <= DaysInMonth(m, trig->y)) {
|
||||
j = Julian(trig->y, m, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
if (JYear(j) > trig->y) return -1;
|
||||
if (j >= startdate) return j;
|
||||
}
|
||||
|
||||
@@ -197,7 +202,8 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
||||
m++;
|
||||
while (trig->d > DaysInMonth(m, trig->d)) m++;
|
||||
j = Julian(trig->y, m, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
if (JYear(j) > trig->y) return -1;
|
||||
return j;
|
||||
|
||||
case GOT_DAY+GOT_MON+GOT_WD:
|
||||
@@ -215,31 +221,32 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
||||
|
||||
/* Try last year */
|
||||
j = Julian(y, trig->m, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
if (j >= startdate) return j;
|
||||
|
||||
/* Try this year */
|
||||
y++;
|
||||
while (trig->d > DaysInMonth(trig->m, y)) y++;
|
||||
j = Julian(y, trig->m, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
if (j >= startdate) return j;
|
||||
|
||||
/* Must be next year */
|
||||
y++;
|
||||
while (trig->d > DaysInMonth(trig->m, y)) y++;
|
||||
j = Julian(y, trig->m, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
return j;
|
||||
|
||||
case GOT_WD+GOT_MON+GOT_YR:
|
||||
if (y > trig->y || (y == trig->y && m > trig->m)) return -1;
|
||||
if (trig->y > y || (trig->y == y && trig->m > m)) {
|
||||
j = Julian(trig->y, trig->m, 1);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
return j;
|
||||
} else {
|
||||
j = startdate;
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
FromJulian(j, &y2, &m2, &d2);
|
||||
if (m2 == trig->m) return j; else return -1;
|
||||
}
|
||||
@@ -250,7 +257,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
|
||||
return -1;
|
||||
}
|
||||
j = Julian(trig->y, trig->m, trig->d);
|
||||
while(! (trig->wd & (1 << (j%7)))) j++;
|
||||
ADVANCE_TO_WD(j, trig->wd);
|
||||
return j;
|
||||
|
||||
default:
|
||||
@@ -408,6 +415,57 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
|
||||
return simple;
|
||||
}
|
||||
|
||||
int
|
||||
AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
{
|
||||
int y, m, d;
|
||||
/* If we have an AT, save the original event start */
|
||||
if (tim->ttime != NO_TIME) {
|
||||
trig->eventstart = MINUTES_PER_DAY * r + tim->ttime;
|
||||
if (tim->duration != NO_TIME) {
|
||||
trig->eventduration = tim->duration;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now potentially adjust */
|
||||
if (r < today && r + trig->duration_days >= today) {
|
||||
/* Adjust duration down */
|
||||
tim->duration -= (today - r) * MINUTES_PER_DAY;
|
||||
tim->duration += tim->ttime;
|
||||
|
||||
/* Start at midnight */
|
||||
tim->ttime = 0;
|
||||
|
||||
/* Change trigger date to today */
|
||||
r = today;
|
||||
if (DebugFlag & DB_PRTTRIG) {
|
||||
FromJulian(r, &y, &m, &d);
|
||||
fprintf(ErrFp, "%s(%d): Trig(adj) = %s, %d %s, %d",
|
||||
FileName, LineNo,
|
||||
DayName[r % 7],
|
||||
d,
|
||||
MonthName[m],
|
||||
y);
|
||||
if (tim->ttime != NO_TIME) {
|
||||
fprintf(ErrFp, " AT %02d:%02d",
|
||||
(tim->ttime / 60),
|
||||
(tim->ttime % 60));
|
||||
if (tim->duration != NO_TIME) {
|
||||
fprintf(ErrFp, " DURATION %02d:%02d",
|
||||
(tim->duration / 60),
|
||||
(tim->duration % 60));
|
||||
}
|
||||
}
|
||||
fprintf(ErrFp, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
if (save_in_globals) {
|
||||
SaveAllTriggerInfo(trig, tim, r, tim->ttime, 1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* ComputeTrigger */
|
||||
@@ -416,10 +474,49 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
|
||||
/* today's date. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
|
||||
int ComputeTrigger(int today, Trigger *trig, TimeTrig *tim,
|
||||
int *err, int save_in_globals)
|
||||
{
|
||||
int r = ComputeTriggerNoAdjustDuration(today, trig, tim, err, save_in_globals, 0);
|
||||
if (*err != OK) {
|
||||
return r;
|
||||
}
|
||||
if (r == today) {
|
||||
if (tim->ttime != NO_TIME) {
|
||||
trig->eventstart = MINUTES_PER_DAY * r + tim->ttime;
|
||||
if (tim->duration != NO_TIME) {
|
||||
trig->eventduration = tim->duration;
|
||||
}
|
||||
}
|
||||
if (save_in_globals) {
|
||||
SaveAllTriggerInfo(trig, tim, r, tim->ttime, 1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
if (trig->duration_days) {
|
||||
r = ComputeTriggerNoAdjustDuration(today, trig, tim, err, save_in_globals, trig->duration_days);
|
||||
if (*err != OK) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
r = AdjustTriggerForDuration(today, r, trig, tim, save_in_globals);
|
||||
return r;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* ComputeTriggerNoAdjustDuration */
|
||||
/* */
|
||||
/* Compute a trigger, but do NOT adjust the time trigger */
|
||||
/* duration. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
|
||||
int *err, int save_in_globals, int duration_days)
|
||||
{
|
||||
int nattempts = 0,
|
||||
start = today,
|
||||
start = today - duration_days,
|
||||
nextstart = 0,
|
||||
y, m, d, omit,
|
||||
result;
|
||||
@@ -429,15 +526,25 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
|
||||
LastTrigValid = 0;
|
||||
}
|
||||
|
||||
/* Assume everything works */
|
||||
/* Assume everything works */
|
||||
*err = OK;
|
||||
|
||||
/* But check for obvious problems... */
|
||||
/* But check for obvious problems... */
|
||||
if (trig->localomit == 1 + 2 + 4 + 8 + 16 + 32 + 64) {
|
||||
*err = E_2MANY_LOCALOMIT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (start < 0) {
|
||||
*err = E_DATE_OVER;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tim->duration != NO_TIME && tim->ttime == NO_TIME) {
|
||||
*err = E_DURATION_NO_AT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (trig->rep != NO_REP &&
|
||||
(trig->d == NO_DAY ||
|
||||
trig->m == NO_MON ||
|
||||
@@ -448,6 +555,11 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
|
||||
}
|
||||
|
||||
|
||||
/* Save the trigger */
|
||||
if (save_in_globals) {
|
||||
SaveLastTrigger(trig);
|
||||
}
|
||||
|
||||
while (nattempts++ < TRIG_ATTEMPTS) {
|
||||
result = GetNextTriggerDate(trig, start, err, &nextstart);
|
||||
|
||||
@@ -469,7 +581,9 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
|
||||
} else {
|
||||
omit = 0;
|
||||
}
|
||||
if (result >= today &&
|
||||
|
||||
/** FIXME: Fix bad interaction with SATISFY... need to rethink!!! */
|
||||
if (result+duration_days >= today &&
|
||||
(trig->skip != SKIP_SKIP || !omit)) {
|
||||
if (save_in_globals) {
|
||||
LastTriggerDate = result; /* Save in global var */
|
||||
@@ -477,12 +591,23 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
|
||||
}
|
||||
if (DebugFlag & DB_PRTTRIG) {
|
||||
FromJulian(result, &y, &m, &d);
|
||||
fprintf(ErrFp, "%s(%d): Trig = %s, %d %s, %d\n",
|
||||
fprintf(ErrFp, "%s(%d): Trig = %s, %d %s, %d",
|
||||
FileName, LineNo,
|
||||
DayName[result % 7],
|
||||
d,
|
||||
MonthName[m],
|
||||
y);
|
||||
if (tim->ttime != NO_TIME) {
|
||||
fprintf(ErrFp, " AT %02d:%02d",
|
||||
(tim->ttime / 60),
|
||||
(tim->ttime % 60));
|
||||
if (tim->duration != NO_TIME) {
|
||||
fprintf(ErrFp, " DURATION %02d:%02d",
|
||||
(tim->duration / 60),
|
||||
(tim->duration % 60));
|
||||
}
|
||||
}
|
||||
fprintf(ErrFp, "\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -535,3 +660,41 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
|
||||
*err = E_CANT_TRIG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* ComputeScanStart */
|
||||
/* */
|
||||
/* Figure out where to start scan from by examining SCANFROM */
|
||||
/* and DURATION */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int
|
||||
ComputeScanStart(int today, Trigger *trig, TimeTrig *tt)
|
||||
{
|
||||
int minutes, days;
|
||||
|
||||
/* If we don't have a time/duration, just use scanfrom */
|
||||
if (tt->ttime == NO_TIME ||
|
||||
tt->duration == NO_TIME) {
|
||||
if (trig->scanfrom == NO_DATE) {
|
||||
return today;
|
||||
}
|
||||
return trig->scanfrom;
|
||||
}
|
||||
|
||||
/* Calculate time-based SCANFROM */
|
||||
minutes = tt->ttime + tt->duration - 1;
|
||||
|
||||
/* Figure out how many days to scan backwards from */
|
||||
days = minutes / MINUTES_PER_DAY;
|
||||
|
||||
if (trig->scanfrom != NO_DATE) {
|
||||
if (trig->scanfrom <= today - days) {
|
||||
return trig->scanfrom;
|
||||
} else {
|
||||
return today - days;
|
||||
}
|
||||
}
|
||||
return today - days;
|
||||
}
|
||||
|
||||
39
src/types.h
@@ -5,7 +5,7 @@
|
||||
/* Type definitions all dumped here. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -68,7 +68,13 @@ typedef struct {
|
||||
int typ;
|
||||
int once;
|
||||
int scanfrom;
|
||||
int from;
|
||||
int priority;
|
||||
int duration_days; /* Duration converted to days to search */
|
||||
int eventstart; /* Original event start (datetime) */
|
||||
int eventduration; /* Original event duration (minutes) */
|
||||
int maybe_uncomputable; /* Suppress "can't compute trigger" warnings */
|
||||
int addomit; /* Add trigger date to global OMITs */
|
||||
char sched[VAR_NAME_LEN+1]; /* Scheduling function */
|
||||
char warn[VAR_NAME_LEN+1]; /* Warning function */
|
||||
char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */
|
||||
@@ -87,16 +93,16 @@ typedef struct {
|
||||
|
||||
/* The parse pointer */
|
||||
typedef struct {
|
||||
char isnested; /* Is it a nested expression? */
|
||||
char allownested;
|
||||
DynamicBuffer pushedToken; /* Pushed-back token */
|
||||
char const *text; /* Start of text */
|
||||
char const *pos; /* Current position */
|
||||
char const *etext; /* Substituted text */
|
||||
char const *epos; /* Position in substituted text */
|
||||
DynamicBuffer pushedToken; /* Pushed-back token */
|
||||
char const *tokenPushed; /* NULL if no pushed-back token */
|
||||
char expr_happened; /* Did we encounter an [expression] ? */
|
||||
char nonconst_expr; /* Did we encounter a non-constant [expression] ? */
|
||||
unsigned char isnested; /* Is it a nested expression? */
|
||||
unsigned char allownested;
|
||||
unsigned char expr_happened; /* Did we encounter an [expression] ? */
|
||||
unsigned char nonconst_expr; /* Did we encounter a non-constant [expression] ? */
|
||||
} Parser;
|
||||
|
||||
typedef Parser *ParsePtr; /* Pointer to parser structure */
|
||||
@@ -145,9 +151,10 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
|
||||
enum TokTypes
|
||||
{ T_Illegal,
|
||||
/* Commands first */
|
||||
T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_If, T_Else, T_EndIf,
|
||||
T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_IncludeR, T_IncludeCmd, T_If, T_Else, T_EndIf,
|
||||
T_IfTrig, T_ErrMsg,
|
||||
T_Set, T_UnSet, T_Fset, T_Omit, T_Banner, T_Exit,
|
||||
T_AddOmit,
|
||||
T_WkDay,
|
||||
T_Month, T_Time, T_Date, T_DateTime,
|
||||
T_Skip, T_At, T_RemType, T_Until, T_Year, T_Day, T_Rep, T_Delta, T_Back,
|
||||
@@ -167,7 +174,8 @@ enum TokTypes
|
||||
T_Duration,
|
||||
T_LongTime,
|
||||
T_OmitFunc,
|
||||
T_Through
|
||||
T_Through,
|
||||
T_MaybeUncomputable
|
||||
};
|
||||
|
||||
/* The structure of a token */
|
||||
@@ -212,3 +220,18 @@ typedef struct {
|
||||
/* Flags for FROM / SCANFROM */
|
||||
#define SCANFROM_TYPE 0
|
||||
#define FROM_TYPE 1
|
||||
|
||||
/* PS Calendar levels */
|
||||
|
||||
/* Original interchange format */
|
||||
#define PSCAL_LEVEL1 1
|
||||
|
||||
/* Line-by-line JSON */
|
||||
#define PSCAL_LEVEL2 2
|
||||
|
||||
/* Pure JSON */
|
||||
#define PSCAL_LEVEL3 3
|
||||
|
||||
#define TERMINAL_BACKGROUND_UNKNOWN 0
|
||||
#define TERMINAL_BACKGROUND_DARK 1
|
||||
#define TERMINAL_BACKGROUND_LIGHT 2
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* functions. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -64,6 +64,7 @@ int DoFset(ParsePtr p)
|
||||
int c;
|
||||
UserFunc *func;
|
||||
Var *v;
|
||||
int orig_namelen;
|
||||
|
||||
DynamicBuffer buf;
|
||||
DBufInit(&buf);
|
||||
@@ -74,6 +75,7 @@ int DoFset(ParsePtr p)
|
||||
DBufFree(&buf);
|
||||
return E_BAD_ID;
|
||||
}
|
||||
orig_namelen = buf.len;
|
||||
|
||||
/* Should be followed by '(' */
|
||||
c = ParseNonSpaceChar(p, &r, 0);
|
||||
@@ -94,9 +96,8 @@ int DoFset(ParsePtr p)
|
||||
StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN);
|
||||
DBufFree(&buf);
|
||||
if (!Hush) {
|
||||
if (FindFunc(DBufValue(&buf), Func, NumFuncs)) {
|
||||
Eprint("%s: `%s'", ErrMsg[E_REDEF_FUNC],
|
||||
DBufValue(&buf));
|
||||
if (FindFunc(func->name, Func, NumFuncs)) {
|
||||
Eprint("%s: `%s'", ErrMsg[E_REDEF_FUNC], func->name);
|
||||
}
|
||||
}
|
||||
func->locals = NULL;
|
||||
@@ -118,6 +119,7 @@ int DoFset(ParsePtr p)
|
||||
if ( (r=ParseIdentifier(p, &buf)) ) return r;
|
||||
if (*DBufValue(&buf) == '$') {
|
||||
DBufFree(&buf);
|
||||
DestroyUserFunc(func);
|
||||
return E_BAD_ID;
|
||||
}
|
||||
v = NEW(Var);
|
||||
@@ -164,6 +166,10 @@ int DoFset(ParsePtr p)
|
||||
|
||||
/* Add the function definition */
|
||||
FSet(func);
|
||||
if (orig_namelen > VAR_NAME_LEN) {
|
||||
Eprint("Warning: Function name `%s...' truncated to `%s'",
|
||||
func->name, func->name);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -273,7 +279,7 @@ int CallUserFunc(char const *name, int nargs, ParsePtr p)
|
||||
}
|
||||
return E_RECURSIVE;
|
||||
}
|
||||
|
||||
|
||||
/* Check number of args */
|
||||
if (nargs != f->nargs) {
|
||||
if (DebugFlag &DB_PRTEXPR) {
|
||||
|
||||
41
src/utils.c
@@ -5,11 +5,15 @@
|
||||
/* Useful utility functions. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
static char const DontEscapeMe[] =
|
||||
"1234567890_-=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.,/";
|
||||
|
||||
#include "config.h"
|
||||
#include "err.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@@ -123,3 +127,38 @@ int DateOK(int y, int m, int d)
|
||||
d > DaysInMonth(m, y) ) return 0;
|
||||
else return 1;
|
||||
}
|
||||
|
||||
/* Functions designed to defeat gcc optimizer */
|
||||
|
||||
int _private_div(int a, int b) { return a/b; }
|
||||
int _private_add_overflow(int result, int b, int old)
|
||||
{
|
||||
if (b > 0 && result < old) return 1;
|
||||
if (b < 0 && result > old) return 1;
|
||||
return 0;
|
||||
}
|
||||
int _private_sub_overflow(int result, int b, int old)
|
||||
{
|
||||
if (b < 0 && result < old) return 1;
|
||||
if (b > 0 && result > old) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _private_unminus_overflow(int a, int b)
|
||||
{
|
||||
if (a > 0 && b > 0) return 1;
|
||||
if (a < 0 && b < 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ShellEscape(char const *in, DynamicBuffer *out)
|
||||
{
|
||||
while(*in) {
|
||||
if (!strchr(DontEscapeMe, *in)) {
|
||||
if (DBufPutc(out, '\\') != OK) return E_NO_MEM;
|
||||
}
|
||||
if (DBufPutc(out, *in++) != OK) return E_NO_MEM;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
239
src/var.c
@@ -6,7 +6,7 @@
|
||||
/* user- and system-defined variables. */
|
||||
/* */
|
||||
/* This file is part of REMIND. */
|
||||
/* Copyright (C) 1992-2018 by Dianne Skoll */
|
||||
/* Copyright (C) 1992-2021 by Dianne Skoll */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include "types.h"
|
||||
#include "expr.h"
|
||||
#include "globals.h"
|
||||
@@ -31,12 +33,109 @@
|
||||
#define VALUE ErrMsg[E_VAL]
|
||||
#define UNDEF ErrMsg[E_UNDEF]
|
||||
|
||||
static int IntMin = INT_MIN;
|
||||
static int IntMax = INT_MAX;
|
||||
|
||||
static Var *VHashTbl[VAR_HASH_SIZE];
|
||||
|
||||
typedef int (*SysVarFunc)(int, Value *);
|
||||
|
||||
static void deprecated_var(char const *var, char const *instead)
|
||||
{
|
||||
if (DebugFlag & DB_PRTLINE) {
|
||||
Eprint("%s is deprecated; use %s instead", var, instead);
|
||||
FreshLine = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int latlong_component_func(int do_set, Value *val, int *var, int min, int max, char const *varname, char const *newvarname)
|
||||
{
|
||||
if (!do_set) {
|
||||
val->type = INT_TYPE;
|
||||
val->v.val = *var;
|
||||
return OK;
|
||||
}
|
||||
deprecated_var(varname, newvarname);
|
||||
if (val->type != INT_TYPE) return E_BAD_TYPE;
|
||||
if (val->v.val < min) return E_2LOW;
|
||||
if (val->v.val > max) return E_2HIGH;
|
||||
*var = val->v.val;
|
||||
set_lat_and_long_from_components();
|
||||
return OK;
|
||||
}
|
||||
static int latdeg_func(int do_set, Value *val)
|
||||
{
|
||||
return latlong_component_func(do_set, val, &LatDeg, -90, 90, "$LatDeg", "$Latitude");
|
||||
}
|
||||
|
||||
static int latmin_func(int do_set, Value *val)
|
||||
{
|
||||
return latlong_component_func(do_set, val, &LatMin, -59, 59, "$LatMin", "$Latitude");
|
||||
}
|
||||
|
||||
static int latsec_func(int do_set, Value *val)
|
||||
{
|
||||
return latlong_component_func(do_set, val, &LatSec, -59, 59, "$LatSec", "$Latitude");
|
||||
}
|
||||
|
||||
static int longdeg_func(int do_set, Value *val)
|
||||
{
|
||||
return latlong_component_func(do_set, val, &LongDeg, -180, 180, "$LongDeg", "$Longitude");
|
||||
}
|
||||
|
||||
static int longmin_func(int do_set, Value *val)
|
||||
{
|
||||
return latlong_component_func(do_set, val, &LongMin, -59, 59, "$LongMin", "$Longitude");
|
||||
}
|
||||
|
||||
static int longsec_func(int do_set, Value *val)
|
||||
{
|
||||
return latlong_component_func(do_set, val, &LongSec, -59, 59, "$LongSec", "$Longitude");
|
||||
}
|
||||
|
||||
static int latitude_longitude_func(int do_set, Value *val, double *var, double min, double max) {
|
||||
char buf[64];
|
||||
double x;
|
||||
char *endptr;
|
||||
|
||||
if (!do_set) {
|
||||
snprintf(buf, sizeof(buf), "%f", *var);
|
||||
val->v.str = malloc(strlen(buf)+1);
|
||||
if (!val->v.str) return E_NO_MEM;
|
||||
strcpy(val->v.str, buf);
|
||||
val->type = STR_TYPE;
|
||||
return OK;
|
||||
}
|
||||
if (val->type == INT_TYPE) {
|
||||
x = (double) val->v.val;
|
||||
} else {
|
||||
if (val->type != STR_TYPE) return E_BAD_TYPE;
|
||||
errno = 0;
|
||||
x = strtod(val->v.str, &endptr);
|
||||
if (errno) return E_BAD_TYPE;
|
||||
if (*endptr) return E_BAD_TYPE;
|
||||
}
|
||||
if (x < min) return E_2LOW;
|
||||
if (x > max) return E_2HIGH;
|
||||
*var = x;
|
||||
set_components_from_lat_and_long();
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int longitude_func(int do_set, Value *val)
|
||||
{
|
||||
return latitude_longitude_func(do_set, val, &Longitude, -180.0, 180.0);
|
||||
}
|
||||
|
||||
static int latitude_func(int do_set, Value *val)
|
||||
{
|
||||
return latitude_longitude_func(do_set, val, &Latitude, -90.0, 90.0);
|
||||
}
|
||||
|
||||
|
||||
static int trig_date_func(int do_set, Value *val)
|
||||
{
|
||||
UNUSED(do_set);
|
||||
val->type = DATE_TYPE;
|
||||
if (!LastTrigValid) {
|
||||
val->v.val = 0;
|
||||
@@ -48,6 +147,7 @@ static int trig_date_func(int do_set, Value *val)
|
||||
static int trig_day_func(int do_set, Value *val)
|
||||
{
|
||||
int y, m, d;
|
||||
UNUSED(do_set);
|
||||
val->type = INT_TYPE;
|
||||
if (!LastTrigValid) {
|
||||
val->v.val = -1;
|
||||
@@ -62,6 +162,7 @@ static int trig_day_func(int do_set, Value *val)
|
||||
static int trig_mon_func(int do_set, Value *val)
|
||||
{
|
||||
int y, m, d;
|
||||
UNUSED(do_set);
|
||||
val->type = INT_TYPE;
|
||||
if (!LastTrigValid) {
|
||||
val->v.val = -1;
|
||||
@@ -76,6 +177,7 @@ static int trig_mon_func(int do_set, Value *val)
|
||||
static int trig_year_func(int do_set, Value *val)
|
||||
{
|
||||
int y, m, d;
|
||||
UNUSED(do_set);
|
||||
val->type = INT_TYPE;
|
||||
if (!LastTrigValid) {
|
||||
val->v.val = -1;
|
||||
@@ -90,6 +192,7 @@ static int trig_year_func(int do_set, Value *val)
|
||||
static int trig_wday_func(int do_set, Value *val)
|
||||
{
|
||||
val->type = INT_TYPE;
|
||||
UNUSED(do_set);
|
||||
if (!LastTrigValid) {
|
||||
val->v.val = -1;
|
||||
return OK;
|
||||
@@ -101,6 +204,7 @@ static int trig_wday_func(int do_set, Value *val)
|
||||
|
||||
static int today_date_func(int do_set, Value *val)
|
||||
{
|
||||
UNUSED(do_set);
|
||||
val->type = DATE_TYPE;
|
||||
val->v.val = JulianToday;
|
||||
return OK;
|
||||
@@ -108,6 +212,7 @@ static int today_date_func(int do_set, Value *val)
|
||||
static int today_day_func(int do_set, Value *val)
|
||||
{
|
||||
int y, m, d;
|
||||
UNUSED(do_set);
|
||||
val->type = INT_TYPE;
|
||||
FromJulian(JulianToday, &y, &m, &d);
|
||||
val->v.val = d;
|
||||
@@ -117,6 +222,7 @@ static int today_day_func(int do_set, Value *val)
|
||||
static int today_mon_func(int do_set, Value *val)
|
||||
{
|
||||
int y, m, d;
|
||||
UNUSED(do_set);
|
||||
val->type = INT_TYPE;
|
||||
FromJulian(JulianToday, &y, &m, &d);
|
||||
val->v.val = m+1;
|
||||
@@ -126,6 +232,7 @@ static int today_mon_func(int do_set, Value *val)
|
||||
static int today_year_func(int do_set, Value *val)
|
||||
{
|
||||
int y, m, d;
|
||||
UNUSED(do_set);
|
||||
val->type = INT_TYPE;
|
||||
FromJulian(JulianToday, &y, &m, &d);
|
||||
val->v.val = y;
|
||||
@@ -134,6 +241,7 @@ static int today_year_func(int do_set, Value *val)
|
||||
|
||||
static int today_wday_func(int do_set, Value *val)
|
||||
{
|
||||
UNUSED(do_set);
|
||||
val->type = INT_TYPE;
|
||||
val->v.val = (JulianToday + 1) % 7;
|
||||
return OK;
|
||||
@@ -158,6 +266,45 @@ static int datetime_sep_func(int do_set, Value *val)
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int default_color_func(int do_set, Value *val)
|
||||
{
|
||||
int col_r, col_g, col_b;
|
||||
if (!do_set) {
|
||||
/* 12 = strlen("255 255 255\0") */
|
||||
val->v.str = malloc(12);
|
||||
if (!val->v.str) return E_NO_MEM;
|
||||
snprintf(val->v.str, 12, "%d %d %d",
|
||||
DefaultColorR,
|
||||
DefaultColorG,
|
||||
DefaultColorB
|
||||
);
|
||||
val->type = STR_TYPE;
|
||||
return OK;
|
||||
}
|
||||
if (val->type != STR_TYPE) return E_BAD_TYPE;
|
||||
if (sscanf(val->v.str, "%d %d %d", &col_r, &col_g, &col_b) != 3) {
|
||||
return E_BAD_TYPE;
|
||||
}
|
||||
/* They either all have to be -1, or all between 0 and 255 */
|
||||
if (col_r == -1 && col_g == -1 && col_b == -1) {
|
||||
DefaultColorR = -1;
|
||||
DefaultColorG = -1;
|
||||
DefaultColorB = -1;
|
||||
return OK;
|
||||
}
|
||||
if (col_r < 0) return E_2LOW;
|
||||
if (col_r > 255) return E_2HIGH;
|
||||
if (col_g < 0) return E_2LOW;
|
||||
if (col_g > 255) return E_2HIGH;
|
||||
if (col_b < 0) return E_2LOW;
|
||||
if (col_b > 255) return E_2HIGH;
|
||||
|
||||
DefaultColorR = col_r;
|
||||
DefaultColorG = col_g;
|
||||
DefaultColorB = col_b;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int date_sep_func(int do_set, Value *val)
|
||||
{
|
||||
if (!do_set) {
|
||||
@@ -360,6 +507,10 @@ int DoSet (Parser *p)
|
||||
|
||||
if (*DBufValue(&buf) == '$') r = SetSysVar(DBufValue(&buf)+1, &v);
|
||||
else r = SetVar(DBufValue(&buf), &v);
|
||||
if (buf.len > VAR_NAME_LEN) {
|
||||
Eprint("Warning: Variable name `%.*s...' truncated to `%.*s'",
|
||||
VAR_NAME_LEN, DBufValue(&buf), VAR_NAME_LEN, DBufValue(&buf));
|
||||
}
|
||||
DBufFree(&buf);
|
||||
return r;
|
||||
}
|
||||
@@ -422,17 +573,17 @@ int DoDump(ParsePtr p)
|
||||
DumpVarTable();
|
||||
return OK;
|
||||
}
|
||||
fprintf(ErrFp, "%*s %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE);
|
||||
fprintf(ErrFp, "%s %s\n\n", VARIABLE, VALUE);
|
||||
while(1) {
|
||||
if (*DBufValue(&buf) == '$') {
|
||||
DumpSysVarByName(DBufValue(&buf)+1);
|
||||
} else {
|
||||
v = FindVar(DBufValue(&buf), 0);
|
||||
DBufValue(&buf)[VAR_NAME_LEN] = 0;
|
||||
if (!v) fprintf(ErrFp, "%*s %s\n", VAR_NAME_LEN,
|
||||
if (!v) fprintf(ErrFp, "%s %s\n",
|
||||
DBufValue(&buf), UNDEF);
|
||||
else {
|
||||
fprintf(ErrFp, "%*s ", VAR_NAME_LEN, v->name);
|
||||
fprintf(ErrFp, "%s ", v->name);
|
||||
PrintValue(&(v->v), ErrFp);
|
||||
fprintf(ErrFp, "\n");
|
||||
}
|
||||
@@ -460,12 +611,12 @@ void DumpVarTable(void)
|
||||
register Var *v;
|
||||
register int i;
|
||||
|
||||
fprintf(ErrFp, "%*s %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE);
|
||||
fprintf(ErrFp, "%s %s\n\n", VARIABLE, VALUE);
|
||||
|
||||
for (i=0; i<VAR_HASH_SIZE; i++) {
|
||||
v = VHashTbl[i];
|
||||
while(v) {
|
||||
fprintf(ErrFp, "%*s ", VAR_NAME_LEN, v->name);
|
||||
fprintf(ErrFp, "%s ", v->name);
|
||||
PrintValue(&(v->v), ErrFp);
|
||||
fprintf(ErrFp, "\n");
|
||||
v = v->next;
|
||||
@@ -594,7 +745,9 @@ static SysVar SysVarArr[] = {
|
||||
{"Daemon", 0, INT_TYPE, &Daemon, 0, 0 },
|
||||
{"DateSep", 1, SPECIAL_TYPE, date_sep_func, 0, 0 },
|
||||
{"DateTimeSep", 1, SPECIAL_TYPE, datetime_sep_func, 0, 0 },
|
||||
{"DefaultColor", 1, SPECIAL_TYPE, default_color_func, 0, 0 },
|
||||
{"DefaultPrio", 1, INT_TYPE, &DefaultPrio, 0, 9999},
|
||||
{"DefaultTDelta", 1, INT_TYPE, &DefaultTDelta, 0, 1440},
|
||||
{"DeltaOffset", 0, INT_TYPE, &DeltaOffset, 0, 0 },
|
||||
{"DontFork", 0, INT_TYPE, &DontFork, 0, 0 },
|
||||
{"DontQueue", 0, INT_TYPE, &DontQueue, 0, 0 },
|
||||
@@ -603,17 +756,21 @@ static SysVar SysVarArr[] = {
|
||||
{"EndSentIg", 1, STR_TYPE, &EndSentIg, 0, 0 },
|
||||
{"FirstIndent", 1, INT_TYPE, &FirstIndent, 0, 132 },
|
||||
{"FoldYear", 1, INT_TYPE, &FoldYear, 0, 1 },
|
||||
{"FormWidth", 1, INT_TYPE, &FormWidth, 20, 132 },
|
||||
{"FormWidth", 1, INT_TYPE, &FormWidth, 20, 500 },
|
||||
{"HushMode", 0, INT_TYPE, &Hush, 0, 0 },
|
||||
{"IgnoreOnce", 0, INT_TYPE, &IgnoreOnce, 0, 0 },
|
||||
{"InfDelta", 0, INT_TYPE, &InfiniteDelta, 0, 0 },
|
||||
{"LatDeg", 1, INT_TYPE, &LatDeg, -90, 90 },
|
||||
{"LatMin", 1, INT_TYPE, &LatMin, -59, 59 },
|
||||
{"LatSec", 1, INT_TYPE, &LatSec, -59, 59 },
|
||||
{"IntMax", 0, INT_TYPE, &IntMax, 0, 0 },
|
||||
{"IntMin", 0, INT_TYPE, &IntMin, 0, 0 },
|
||||
{"LatDeg", 1, SPECIAL_TYPE, latdeg_func, 0, 0 },
|
||||
{"Latitude", 1, SPECIAL_TYPE, latitude_func, 0, 0 },
|
||||
{"LatMin", 1, SPECIAL_TYPE, latmin_func, 0, 0 },
|
||||
{"LatSec", 1, SPECIAL_TYPE, latsec_func, 0, 0 },
|
||||
{"Location", 1, STR_TYPE, &Location, 0, 0 },
|
||||
{"LongDeg", 1, INT_TYPE, &LongDeg, -180, 180 },
|
||||
{"LongMin", 1, INT_TYPE, &LongMin, -59, 59 },
|
||||
{"LongSec", 1, INT_TYPE, &LongSec, -59, 59 },
|
||||
{"LongDeg", 1, SPECIAL_TYPE, longdeg_func, 0, 0 },
|
||||
{"Longitude", 1, SPECIAL_TYPE, longitude_func, 0, 0 },
|
||||
{"LongMin", 1, SPECIAL_TYPE, longmin_func, 0, 0 },
|
||||
{"LongSec", 1, SPECIAL_TYPE, longsec_func, 0, 0 },
|
||||
{"MaxSatIter", 1, INT_TYPE, &MaxSatIter, 10, ANY },
|
||||
{"MaxStringLen", 1, INT_TYPE, &MaxStringLen, -1, ANY },
|
||||
{"MinsFromUTC", 1, INT_TYPE, &MinsFromUTC, -780, 780 },
|
||||
@@ -654,6 +811,7 @@ static void DumpSysVar (char const *name, const SysVar *v);
|
||||
/***************************************************************/
|
||||
int SetSysVar(char const *name, Value *value)
|
||||
{
|
||||
int r;
|
||||
SysVar *v = FindSysVar(name);
|
||||
if (!v) return E_NOSUCH_VAR;
|
||||
if (v->type != SPECIAL_TYPE &&
|
||||
@@ -665,7 +823,9 @@ int SetSysVar(char const *name, Value *value)
|
||||
|
||||
if (v->type == SPECIAL_TYPE) {
|
||||
SysVarFunc f = (SysVarFunc) v->value;
|
||||
return f(1, value);
|
||||
r = f(1, value);
|
||||
DestroyValue(*value);
|
||||
return r;
|
||||
} else if (v->type == STR_TYPE) {
|
||||
/* If it's a string variable, special measures must be taken */
|
||||
if (v->been_malloced) free(*((char **)(v->value)));
|
||||
@@ -707,7 +867,7 @@ int GetSysVar(char const *name, Value *val)
|
||||
/* In "verbose" mode, print attempts to test $RunOff */
|
||||
if (DebugFlag & DB_PRTLINE) {
|
||||
if (v->value == (void *) &RunDisabled) {
|
||||
Eprint("(Security note: $RunOff variable tested.)\n");
|
||||
Eprint("(Security note: $RunOff variable tested.)");
|
||||
/* Allow further messages from this line */
|
||||
FreshLine = 1;
|
||||
}
|
||||
@@ -748,7 +908,7 @@ static SysVar *FindSysVar(char const *name)
|
||||
/***************************************************************/
|
||||
void DumpSysVarByName(char const *name)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
SysVar *v;
|
||||
|
||||
if (!name || !*name) {
|
||||
@@ -781,7 +941,7 @@ static void DumpSysVar(char const *name, const SysVar *v)
|
||||
return;
|
||||
}
|
||||
if (name) strcat(buffer, name); else strcat(buffer, v->name);
|
||||
fprintf(ErrFp, "%*s ", VAR_NAME_LEN+1, buffer);
|
||||
fprintf(ErrFp, "%16s ", buffer);
|
||||
if (v) {
|
||||
if (v->type == SPECIAL_TYPE) {
|
||||
Value val;
|
||||
@@ -825,3 +985,48 @@ static void DumpSysVar(char const *name, const SysVar *v)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
set_lat_and_long_from_components(void)
|
||||
{
|
||||
Latitude = (double) LatDeg + ((double) LatMin) / 60.0 + ((double) LatSec) / 3600.0;
|
||||
Longitude = - ( (double) LongDeg + ((double) LongMin) / 60.0 + ((double) LongSec) / 3600.0);
|
||||
}
|
||||
|
||||
void
|
||||
set_components_from_lat_and_long(void)
|
||||
{
|
||||
double x;
|
||||
|
||||
x = (Latitude < 0.0 ? -Latitude : Latitude);
|
||||
LatDeg = (int) x;
|
||||
x -= (double) LatDeg;
|
||||
x *= 60;
|
||||
LatMin = (int) x;
|
||||
x -= (double) LatMin;
|
||||
x *= 60;
|
||||
LatSec = (int) x;
|
||||
if (Latitude < 0.0) {
|
||||
LatDeg = -LatDeg;
|
||||
LatMin = -LatMin;
|
||||
LatSec = -LatSec;
|
||||
}
|
||||
|
||||
x = (Longitude < 0.0 ? -Longitude : Longitude);
|
||||
LongDeg = (int) x;
|
||||
x -= (double) LongDeg;
|
||||
x *= 60;
|
||||
LongMin = (int) x;
|
||||
x -= (double) LongMin;
|
||||
x *= 60;
|
||||
LongSec = (int) x;
|
||||
|
||||
/* Use STANDARD sign for $Longitude even if $LongDeg, $LongMin and
|
||||
* $LongSec are messed up */
|
||||
if (Longitude > 0.0) {
|
||||
LongDeg = -LongDeg;
|
||||
LongMin = -LongMin;
|
||||
LongSec = -LongSec;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
REM 15 MSG 02
|
||||
DO subdir/04.rem
|
||||
INCLUDE subdir/04.rem
|
||||
|
||||
1
tests/include_dir/subdir/04.rem
Normal file
@@ -0,0 +1 @@
|
||||
REM 16 MSG Should be included by 02.rem
|
||||
@@ -28,3 +28,5 @@ REM Fri SPECIAL SHADE 255 204 204
|
||||
REM Sat SPECIAL SHADE 204 255 204
|
||||
REM Sun SPECIAL SHADE 204 204 255
|
||||
|
||||
# This should be ignored by rem2ps
|
||||
REM SPECIAL HTML <b>FOO</b>
|
||||
|
||||
2
tests/test-addomit.rem
Normal file
@@ -0,0 +1,2 @@
|
||||
REM Mon 1 Sep SCANFROM -7 ADDOMIT MSG Labour Day
|
||||
REM 6 Sep 2021 AFTER MSG Should be bumped to Tuesday
|
||||
27
tests/test-for-backends.rem
Normal file
@@ -0,0 +1,27 @@
|
||||
# This file is designed for testing how back-ends
|
||||
# handle SPECIALs, including SPECIALS they don't understand
|
||||
# If you're writing a back-end, test it by feeding it the output
|
||||
# of: remind -pp test-for-backends.rem
|
||||
|
||||
# Color and shade
|
||||
REM 1 SPECIAL COLOR 128 0 0 Red
|
||||
REM 2 SPECIAL COLOUR 0 128 0 British Green
|
||||
REM 3 SPECIAL SHADE 192 192 255
|
||||
|
||||
# Moon
|
||||
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)]
|
||||
|
||||
# Week
|
||||
REM Monday SPECIAL WEEK (W[weekno()])
|
||||
|
||||
# PostScript
|
||||
REM Wed PS Border Border 2 div moveto /Helvetica-Oblique findfont 6 scalefont setfont (oof!) show
|
||||
|
||||
# A SPECIAL that should be ignored
|
||||
REM 15 SPECIAL RANDOM-STUFF ignore me and be happy
|
||||
|
||||
# A normal reminder
|
||||
REM 16 MSG A normal reminder
|
||||
229
tests/test-rem
@@ -7,13 +7,22 @@
|
||||
# in the build directory.
|
||||
#
|
||||
# This file is part of REMIND.
|
||||
# Copyright (C) 1992-2018 Dianne Skoll
|
||||
# Copyright (C) 1992-2021 Dianne Skoll
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
DIR=`dirname $0`
|
||||
cd $DIR
|
||||
if test $? != 0 ; then
|
||||
echo ""
|
||||
echo "Unable to cd $DIR" >&2
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test `id -u` = 0 ; then
|
||||
echo ""
|
||||
echo "*** Please do not run the test suite as root; it will fail."
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -56,6 +65,14 @@ echo "" >> ../tests/test.out
|
||||
|
||||
chmod 644 include_dir/04cantread.rem
|
||||
|
||||
# Feb 29 bug
|
||||
echo "Feb 29 Bug Test" >> ../tests/test.out
|
||||
echo 'REM Sun 29 Feb MSG [$T]' | ../src/remind -dt - 1 feb 2021 >> ../tests/test.out 2>&1
|
||||
|
||||
# Day Weekday Year out-of-year bug
|
||||
echo "Mon 31 Dec Bug Test" >> ../tests/test.out
|
||||
echo 'REM Mon 31 2021 MSG [$T]' | ../src/remind -dt - 31 dec 2021 >> ../tests/test.out 2>&1
|
||||
|
||||
echo "Color Test" >> ../tests/test.out
|
||||
../src/remind -ccl ../tests/colors.rem 1 aug 2007 >> ../tests/test.out 2>&1
|
||||
|
||||
@@ -79,6 +96,7 @@ rm -f ../tests/purge_dir/*.rem.purged >> ../tests/test.out 2>&1
|
||||
../src/remind ../tests/runtest.rem >> ../tests/test.out 2>&1
|
||||
|
||||
../src/remind -p ../tests/shade.rem 1 August 2009 | ../src/rem2ps -e -l -c3 >> ../tests/test.out 2>&1
|
||||
../src/remind -pp ../tests/shade.rem 1 August 2009 | ../src/rem2ps -e -l -c3 >> ../tests/test.out 2>&1
|
||||
|
||||
# The sun tests can fail due to math roundoff error changing the times
|
||||
# by a minute...
|
||||
@@ -99,6 +117,215 @@ REM 1 Jan 2012 AT 10:00 MSG 10am: Should show up
|
||||
MSG [$DontTrigAts]
|
||||
EOF
|
||||
|
||||
# An OMITFUNC should indicate nonconst_expr
|
||||
../src/remind -pp - 1 jan 2012 9:00 <<'EOF' >> ../tests/test.out 2>&1
|
||||
REM Mon OMITFUNC foo MSG bar
|
||||
EOF
|
||||
|
||||
# Test default color
|
||||
../src/remind -ppp - 1 Jan 2012 9:00 <<'EOF' >> ../tests/test.out 2>&1
|
||||
REM 2 MSG Normal
|
||||
SET $DefaultColor "255 0 0"
|
||||
REM 3 MSG Red
|
||||
SET $DefaultColor "-1 -1 -1"
|
||||
REM 4 MSG Normal
|
||||
# Should give an error
|
||||
SET $DefaultColor "256 0 0"
|
||||
EOF
|
||||
|
||||
# Test -@ option
|
||||
../src/remind -w,0,0 -@0 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
|
||||
rem 1 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 2 SPECIAL COLOR 0 0 65 BLUE
|
||||
rem 3 SPECIAL COLOR 0 65 0 GREEN
|
||||
rem 4 SPECIAL COLOR 0 65 65 CYAN
|
||||
rem 5 msg -@0
|
||||
rem 15 SPECIAL COLOR 65 0 0 RED
|
||||
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
|
||||
rem 17 SPECIAL COLOR 65 65 0 YELLOW
|
||||
rem 18 SPECIAL COLOR 65 65 65 WHITE
|
||||
rem 8 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
|
||||
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
|
||||
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
|
||||
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
|
||||
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
|
||||
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
|
||||
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
|
||||
EOF
|
||||
../src/remind -w,0,0 -@0,0 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
|
||||
rem 1 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 2 SPECIAL COLOR 0 0 65 BLUE
|
||||
rem 3 SPECIAL COLOR 0 65 0 GREEN
|
||||
rem 4 SPECIAL COLOR 0 65 65 CYAN
|
||||
rem 5 msg -@0,0
|
||||
rem 15 SPECIAL COLOR 65 0 0 RED
|
||||
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
|
||||
rem 17 SPECIAL COLOR 65 65 0 YELLOW
|
||||
rem 18 SPECIAL COLOR 65 65 65 WHITE
|
||||
rem 8 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
|
||||
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
|
||||
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
|
||||
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
|
||||
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
|
||||
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
|
||||
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
|
||||
EOF
|
||||
../src/remind -w,0,0 -@0,1 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
|
||||
rem 1 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 2 SPECIAL COLOR 0 0 65 BLUE
|
||||
rem 3 SPECIAL COLOR 0 65 0 GREEN
|
||||
rem 4 SPECIAL COLOR 0 65 65 CYAN
|
||||
rem 5 msg -@0,1
|
||||
rem 15 SPECIAL COLOR 65 0 0 RED
|
||||
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
|
||||
rem 17 SPECIAL COLOR 65 65 0 YELLOW
|
||||
rem 18 SPECIAL COLOR 65 65 65 WHITE
|
||||
rem 8 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
|
||||
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
|
||||
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
|
||||
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
|
||||
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
|
||||
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
|
||||
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
|
||||
EOF
|
||||
../src/remind -w,0,0 -@1 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
|
||||
rem 1 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 2 SPECIAL COLOR 0 0 65 BLUE
|
||||
rem 3 SPECIAL COLOR 0 65 0 GREEN
|
||||
rem 4 SPECIAL COLOR 0 65 65 CYAN
|
||||
rem 5 msg -@1
|
||||
rem 15 SPECIAL COLOR 65 0 0 RED
|
||||
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
|
||||
rem 17 SPECIAL COLOR 65 65 0 YELLOW
|
||||
rem 18 SPECIAL COLOR 65 65 65 WHITE
|
||||
rem 8 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
|
||||
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
|
||||
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
|
||||
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
|
||||
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
|
||||
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
|
||||
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
|
||||
EOF
|
||||
../src/remind -w,0,0 -@1,0 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
|
||||
rem 1 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 2 SPECIAL COLOR 0 0 65 BLUE
|
||||
rem 3 SPECIAL COLOR 0 65 0 GREEN
|
||||
rem 4 SPECIAL COLOR 0 65 65 CYAN
|
||||
rem 5 msg -@1,0
|
||||
rem 15 SPECIAL COLOR 65 0 0 RED
|
||||
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
|
||||
rem 17 SPECIAL COLOR 65 65 0 YELLOW
|
||||
rem 18 SPECIAL COLOR 65 65 65 WHITE
|
||||
rem 8 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
|
||||
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
|
||||
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
|
||||
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
|
||||
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
|
||||
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
|
||||
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
|
||||
EOF
|
||||
../src/remind -w,0,0 -@1,1 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
|
||||
rem 1 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 2 SPECIAL COLOR 0 0 65 BLUE
|
||||
rem 3 SPECIAL COLOR 0 65 0 GREEN
|
||||
rem 4 SPECIAL COLOR 0 65 65 CYAN
|
||||
rem 5 msg -@1,1
|
||||
rem 15 SPECIAL COLOR 65 0 0 RED
|
||||
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
|
||||
rem 17 SPECIAL COLOR 65 65 0 YELLOW
|
||||
rem 18 SPECIAL COLOR 65 65 65 WHITE
|
||||
rem 8 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
|
||||
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
|
||||
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
|
||||
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
|
||||
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
|
||||
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
|
||||
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
|
||||
EOF
|
||||
../src/remind -w,0,0 -@2 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
|
||||
rem 1 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 2 SPECIAL COLOR 0 0 65 BLUE
|
||||
rem 3 SPECIAL COLOR 0 65 0 GREEN
|
||||
rem 4 SPECIAL COLOR 0 65 65 CYAN
|
||||
rem 5 msg -@2
|
||||
rem 15 SPECIAL COLOR 65 0 0 RED
|
||||
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
|
||||
rem 17 SPECIAL COLOR 65 65 0 YELLOW
|
||||
rem 18 SPECIAL COLOR 65 65 65 WHITE
|
||||
rem 8 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
|
||||
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
|
||||
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
|
||||
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
|
||||
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
|
||||
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
|
||||
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
|
||||
EOF
|
||||
../src/remind -w,0,0 -@2,0 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
|
||||
rem 1 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 2 SPECIAL COLOR 0 0 65 BLUE
|
||||
rem 3 SPECIAL COLOR 0 65 0 GREEN
|
||||
rem 4 SPECIAL COLOR 0 65 65 CYAN
|
||||
rem 5 msg -@2,0
|
||||
rem 15 SPECIAL COLOR 65 0 0 RED
|
||||
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
|
||||
rem 17 SPECIAL COLOR 65 65 0 YELLOW
|
||||
rem 18 SPECIAL COLOR 65 65 65 WHITE
|
||||
rem 8 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
|
||||
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
|
||||
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
|
||||
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
|
||||
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
|
||||
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
|
||||
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
|
||||
EOF
|
||||
../src/remind -w,0,0 -@2,1 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
|
||||
rem 1 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 2 SPECIAL COLOR 0 0 65 BLUE
|
||||
rem 3 SPECIAL COLOR 0 65 0 GREEN
|
||||
rem 4 SPECIAL COLOR 0 65 65 CYAN
|
||||
rem 5 msg -@2,1
|
||||
rem 15 SPECIAL COLOR 65 0 0 RED
|
||||
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
|
||||
rem 17 SPECIAL COLOR 65 65 0 YELLOW
|
||||
rem 18 SPECIAL COLOR 65 65 65 WHITE
|
||||
rem 8 SPECIAL COLOR 0 0 0 BLACK
|
||||
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
|
||||
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
|
||||
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
|
||||
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
|
||||
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
|
||||
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
|
||||
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
|
||||
EOF
|
||||
|
||||
# If we're already in a utf-8 locale, do
|
||||
# nothing; otherwise, set LC_ALL
|
||||
OK=0
|
||||
if echo $LC_ALL | grep -i utf-8 > /dev/null 2>&1 ; then
|
||||
OK=1
|
||||
fi
|
||||
|
||||
if test -z "$LC_ALL" ; then
|
||||
if echo $LANG | grep -i utf-8 > /dev/null 2>&1 ; then
|
||||
export LC_ALL="$LANG"
|
||||
OK=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$OK" = 0 ; then
|
||||
export LC_ALL=en_US.utf-8
|
||||
fi
|
||||
|
||||
../src/remind -w128 -c ../tests/utf-8.rem 1 Nov 2019 >> ../tests/test.out
|
||||
../src/remind -c ../tests/test-addomit.rem 1 Sep 2021 >> ../tests/test.out
|
||||
|
||||
cmp -s ../tests/test.out ../tests/test.cmp
|
||||
if [ "$?" = "0" ]; then
|
||||
|
||||
4609
tests/test.cmp
328
tests/test.rem
@@ -5,6 +5,9 @@
|
||||
#
|
||||
# ./test-rem # From WITHIN Remind source directory!
|
||||
|
||||
# Should issue a warning
|
||||
fset year(x) 1
|
||||
|
||||
# Don't evaluate SATISFY expressions if reminder has expired
|
||||
|
||||
REM Wed UNTIL 15 Feb 1991 SATISFY [trigdate() > '1990-01-01'] MSG wookie
|
||||
@@ -12,9 +15,40 @@ REM Wed UNTIL 15 Feb 1991 SATISFY [trigdate() > '1990-01-01'] MSG wookie
|
||||
# bad AT
|
||||
REM AT 0:00 0:01 0:02 MSG foo
|
||||
|
||||
# Includecmd
|
||||
INCLUDECMD echo REM 16 Feb 1991 MSG Blork
|
||||
INCLUDECMD echo REM 18 Feb 1991 MSG Blork
|
||||
|
||||
# Includecmd with continuation line
|
||||
INCLUDECMD echo REM 18 Feb 1991 MSG This line is \
|
||||
continued so there
|
||||
|
||||
# This should work
|
||||
INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo MSG Yippee
|
||||
|
||||
# This should fail
|
||||
INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo MSG Yippee
|
||||
REM MSG Today is [hebday(today())] [hebmon(today())] [hebyear(today())]
|
||||
fset _h(x, y) trigger(hebdate(x,y))
|
||||
|
||||
# Test case from Remind mailing list
|
||||
set mltest "a b"
|
||||
INCLUDECMD printf 'REM %s\n' [mltest]
|
||||
|
||||
# Disabling RUN in an !includecmd
|
||||
INCLUDECMD !echo MSG foo
|
||||
INCLUDECMD !echo MSG foo
|
||||
INCLUDECMD !echo INCLUDECMD echo MSG foo
|
||||
INCLUDECMD !echo INCLUDECMD echo MSG foo
|
||||
INCLUDECMD !echo MSG foo
|
||||
INCLUDECMD !echo MSG foo
|
||||
|
||||
# INCLUDECMD with RUN disabled
|
||||
RUN OFF
|
||||
INCLUDECMD echo MSG foo
|
||||
RUN ON
|
||||
INCLUDECMD echo MSG foo
|
||||
|
||||
[_h(1, "Tishrey")] MSG Rosh Hashana 1
|
||||
[_h(2, "Tishrey")] MSG Rosh Hashana 2
|
||||
[_h(3, "Tishrey")] MSG Tzom Gedalia
|
||||
@@ -169,6 +203,10 @@ REM Fri SCANFROM [trigger(today()-7)] SATISFY 1
|
||||
OMIT [trigger(trigdate())]
|
||||
REM Fri after MSG 16 Feb 1991
|
||||
CLEAR-OMIT-CONTEXT
|
||||
REM Fri SCANFROM -7 SATISFY 1
|
||||
OMIT [trigger(trigdate())]
|
||||
REM Fri after MSG 16 Feb 1991
|
||||
CLEAR-OMIT-CONTEXT
|
||||
|
||||
# Test omitfunc
|
||||
fset _ofunc(x) (day(x) < 7 || day(x) % 2)
|
||||
@@ -188,6 +226,36 @@ REM 1991/02/28@14:45 MSG Feb 28
|
||||
REM Wed UNTIL 1991-01-01 MSG Expired
|
||||
REM Wed SCANFROM 1991-02-26 MSG SCANFROM
|
||||
|
||||
CLEAR-OMIT-CONTEXT
|
||||
# Test ADDOMIT
|
||||
|
||||
REM Mon 15 Feb ADDOMIT MSG Family Day
|
||||
REM Feb 18 AFTER MSG Should trigger on Feb 19
|
||||
OMIT DUMP
|
||||
|
||||
set $CalcUTC 0
|
||||
set $DateTimeSep "@"
|
||||
set $DefaultColor "-1 -1 -1"
|
||||
set $DefaultPrio 5000
|
||||
set $EndSent ".?!"
|
||||
set $EndSentIg "" + char(34) + "')]}>"
|
||||
set $FirstIndent 0
|
||||
set $FoldYear 0
|
||||
set $FormWidth 72
|
||||
set $Location "Ottawa"
|
||||
set $MaxSatIter 150
|
||||
set $MaxStringLen 65535
|
||||
set $MinsFromUTC -300
|
||||
set $SubsIndent 0
|
||||
set $TimeSep ":"
|
||||
|
||||
set $LatDeg 30
|
||||
set $LatMin 30
|
||||
set $LatSec 0
|
||||
set $LongDeg -25
|
||||
set $LongMin 15
|
||||
set $LongSec 0
|
||||
|
||||
set a000 abs(1)
|
||||
set a001 abs(-1)
|
||||
set a002 asc("foo")
|
||||
@@ -306,14 +374,274 @@ set a082 slide('1991-03-01', 7, "Sat", "Sun")
|
||||
set a083 slide('1991-04-01', -7, "Sat")
|
||||
set a084 nonomitted('1991-03-01', '1991-03-13', "Sat", "Sun")
|
||||
set a085 nonomitted('1991-03-24', '1991-04-01', "Sat")
|
||||
REM 2010-09-03 +3 -4 UNTIL 2012-01-01 PRIORITY 7 *14 MSG foo
|
||||
set a086 trigback()
|
||||
set a087 trigdelta()
|
||||
set a088 trigrep()
|
||||
set a089 triguntil()
|
||||
set a090 trigscanfrom()
|
||||
set a091 trigfrom()
|
||||
set a092 trigpriority()
|
||||
set a093 trigtimedelta()
|
||||
set a094 trigtimerep()
|
||||
set a095 trigduration()
|
||||
|
||||
REM Mon Wed FROM 2010-09-03 ++3 --4 MSG foo
|
||||
set a096 trigback()
|
||||
set a097 trigdelta()
|
||||
set a098 trigrep()
|
||||
set a099 triguntil()
|
||||
set a100 trigscanfrom()
|
||||
set a101 trigfrom()
|
||||
set a102 trigpriority()
|
||||
set a103 trigtimedelta()
|
||||
set a104 trigtimerep()
|
||||
set a105 trigduration()
|
||||
|
||||
REM 2010-09-03 +3 -4 UNTIL 2012-01-01 PRIORITY 7 *14 AT 14:41 +15 *2 DURATION 213 MSG foo
|
||||
set a106 trigback()
|
||||
set a107 trigdelta()
|
||||
set a108 trigrep()
|
||||
set a109 triguntil()
|
||||
set a110 trigscanfrom()
|
||||
set a111 trigfrom()
|
||||
set a112 trigpriority()
|
||||
set a113 trigtimedelta()
|
||||
set a114 trigtimerep()
|
||||
set a115 trigduration()
|
||||
|
||||
REM Mon Wed FROM 2010-09-03 ++3 --4 AT 14:44 MSG foo
|
||||
set a116 trigback()
|
||||
set a117 trigdelta()
|
||||
set a118 trigrep()
|
||||
set a119 triguntil()
|
||||
set a120 trigscanfrom()
|
||||
set a121 trigfrom()
|
||||
set a122 trigpriority()
|
||||
set a123 trigtimedelta()
|
||||
set a124 trigtimerep()
|
||||
set a125 trigduration()
|
||||
|
||||
# Test adding TIME+TIME and DATETIME+TIME
|
||||
set a126 11:00 + 3:00
|
||||
set a127 23:00 + 5:30
|
||||
set a128 '2018-02-03@10:00' + 6:45
|
||||
set a129 23:30 + '2019-02-02@16:44'
|
||||
|
||||
# Multi-day reminder
|
||||
REM 13 AT 16:00 DURATION 72:00 MSG 72-hour event
|
||||
set a130 trigdate()
|
||||
set a131 trigtime()
|
||||
set a132 trigdatetime()
|
||||
set a133 trigduration()
|
||||
set a134 trigeventstart()
|
||||
set a135 trigeventduration()
|
||||
|
||||
# These will issue errors
|
||||
REM Mon OMIT Mon SKIP MSG Never ever ever...
|
||||
REM Mon SATISFY [wkdaynum($T) == 3] MSG Nope nope...
|
||||
|
||||
# These will just silently not trigger
|
||||
REM MAYBE-UNCOMPUTABLE Mon OMIT Mon SKIP MSG Never ever ever...
|
||||
REM MAYBE-UNCOMPUTABLE Mon SATISFY [wkdaynum($T) == 3] MSG Nope nope...
|
||||
|
||||
dump
|
||||
dump $
|
||||
dump $aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
OMIT 2010-09-03 THROUGH 2010-09-15
|
||||
OMIT December 25 MSG X
|
||||
# Next should give a parse error
|
||||
OMIT 26 Dec 2010 THROUGH 27 Dec 2010 MSG This is not legal
|
||||
OMIT DUMP
|
||||
# Regression test for bugfix in Hebrew calendar Adar jahrzeit
|
||||
[_i(14, "Adar", today(), 5761)] MSG Purim
|
||||
|
||||
# Regression test for bug found by Larry Hynes
|
||||
REM SATISFY [day(trigdate()-25) == 14] MSG Foo
|
||||
|
||||
# Check combo of SATISFY and long-duration events
|
||||
REM 14 SATISFY [$Tw == 4] MSG Thursday, the 14th
|
||||
REM 14 AT 16:00 DURATION 8:00 SATISFY [$Tw == 4] MSG Thursday, the 14th
|
||||
REM 14 AT 16:00 DURATION 8:01 SATISFY [$Tw == 4] MSG Thursday, the 14th
|
||||
REM 14 AT 16:00 DURATION 32:00 SATISFY [$Tw == 4] MSG Thursday, the 14th
|
||||
REM 14 AT 16:00 DURATION 32:01 SATISFY [$Tw == 4] MSG Thursday, the 14th
|
||||
REM 14 AT 16:00 DURATION 40:00 SATISFY [$Tw == 4] MSG Thursday, the 14th
|
||||
|
||||
# This is now an error
|
||||
REM DURATION 15:00 MSG Should fail... need AT if you have DURATION.
|
||||
|
||||
# Parsing of AM/PM times
|
||||
REM AT 0:00am MSG foo 0a
|
||||
REM AT 1:00AM MSG foo 1a
|
||||
REM AT 2:00am MSG foo 2a
|
||||
REM AT 3:00AM MSG foo 3a
|
||||
REM AT 4:00am MSG foo 4a
|
||||
REM AT 5:00AM MSG foo 5a
|
||||
REM AT 6:00am MSG foo 6a
|
||||
REM AT 7:00AM MSG foo 7a
|
||||
REM AT 8:00am MSG foo 8a
|
||||
REM AT 9:00AM MSG foo 9a
|
||||
REM AT 10:00am MSG foo 10a
|
||||
REM AT 11:00AM MSG foo 11a
|
||||
REM AT 12:00am MSG foo 12a
|
||||
REM AT 13:00AM MSG foo 13a
|
||||
REM AT 0:00pm MSG foo 0p
|
||||
REM AT 1:00PM MSG foo 1p
|
||||
REM AT 2:00pm MSG foo 2p
|
||||
REM AT 3:00PM MSG foo 3p
|
||||
REM AT 4:00pm MSG foo 4p
|
||||
REM AT 5:00PM MSG foo 5p
|
||||
REM AT 6:00pm MSG foo 6p
|
||||
REM AT 7:00PM MSG foo 7p
|
||||
REM AT 8:00pm MSG foo 8p
|
||||
REM AT 9:00PM MSG foo 9p
|
||||
REM AT 10:00pm MSG foo 10p
|
||||
REM AT 11:00PM MSG foo 11p
|
||||
REM AT 12:00pm MSG foo 12p
|
||||
REM AT 13:00PM MSG foo 13p
|
||||
|
||||
DEBUG +x
|
||||
SET x 0:00am + 0
|
||||
SET x 1:00AM + 0
|
||||
SET x 2:00am + 0
|
||||
SET x 3:00AM + 0
|
||||
SET x 4:00am + 0
|
||||
SET x 5:00AM + 0
|
||||
SET x 6:00am + 0
|
||||
SET x 7:00AM + 0
|
||||
SET x 8:00am + 0
|
||||
SET x 9:00AM + 0
|
||||
SET x 10:00am + 0
|
||||
SET x 11:00AM + 0
|
||||
SET x 12:00am + 0
|
||||
SET x 13:00AM + 0
|
||||
|
||||
SET x 0:00pm + 0
|
||||
SET x 1:00PM + 0
|
||||
SET x 2:00pm + 0
|
||||
SET x 3:00PM + 0
|
||||
SET x 4:00pm + 0
|
||||
SET x 5:00PM + 0
|
||||
SET x 6:00pm + 0
|
||||
SET x 7:00PM + 0
|
||||
SET x 8:00pm + 0
|
||||
SET x 9:00PM + 0
|
||||
SET x 10:00pm + 0
|
||||
SET x 11:00PM + 0
|
||||
SET x 12:00pm + 0
|
||||
SET x 13:00PM + 0
|
||||
|
||||
SET x '2015-02-03@0:00am' + 0
|
||||
SET x '2015-02-03@1:00AM' + 0
|
||||
SET x '2015-02-03@2:00am' + 0
|
||||
SET x '2015-02-03@3:00AM' + 0
|
||||
SET x '2015-02-03@4:00am' + 0
|
||||
SET x '2015-02-03@5:00AM' + 0
|
||||
SET x '2015-02-03@6:00am' + 0
|
||||
SET x '2015-02-03@7:00AM' + 0
|
||||
SET x '2015-02-03@8:00am' + 0
|
||||
SET x '2015-02-03@9:00AM' + 0
|
||||
SET x '2015-02-03@10:00am' + 0
|
||||
SET x '2015-02-03@11:00AM' + 0
|
||||
SET x '2015-02-03@12:00am' + 0
|
||||
SET x '2015-02-03@13:00AM' + 0
|
||||
|
||||
SET x '2015-02-03@0:00pm' + 0
|
||||
SET x '2015-02-03@1:00PM' + 0
|
||||
SET x '2015-02-03@2:00pm' + 0
|
||||
SET x '2015-02-03@3:00PM' + 0
|
||||
SET x '2015-02-03@4:00pm' + 0
|
||||
SET x '2015-02-03@5:00PM' + 0
|
||||
SET x '2015-02-03@6:00pm' + 0
|
||||
SET x '2015-02-03@7:00PM' + 0
|
||||
SET x '2015-02-03@8:00pm' + 0
|
||||
SET x '2015-02-03@9:00PM' + 0
|
||||
SET x '2015-02-03@10:00pm' + 0
|
||||
SET x '2015-02-03@11:00PM' + 0
|
||||
SET x '2015-02-03@12:00pm' + 0
|
||||
SET x '2015-02-03@13:00PM' + 0
|
||||
|
||||
# Test the ampm function
|
||||
set x ampm(0:12) + ""
|
||||
set x ampm(1:12) + ""
|
||||
set x ampm(2:12) + ""
|
||||
set x ampm(3:12) + ""
|
||||
set x ampm(4:12) + ""
|
||||
set x ampm(5:12) + ""
|
||||
set x ampm(6:12) + ""
|
||||
set x ampm(7:12) + ""
|
||||
set x ampm(8:12) + ""
|
||||
set x ampm(9:12) + ""
|
||||
set x ampm(10:12) + ""
|
||||
set x ampm(11:12) + ""
|
||||
set x ampm(12:12) + ""
|
||||
set x ampm(13:12) + ""
|
||||
set x ampm(14:12) + ""
|
||||
set x ampm(15:12) + ""
|
||||
set x ampm(16:12) + ""
|
||||
set x ampm(17:12) + ""
|
||||
set x ampm(18:12) + ""
|
||||
set x ampm(19:12) + ""
|
||||
set x ampm(20:12) + ""
|
||||
set x ampm(21:12) + ""
|
||||
set x ampm(22:12) + ""
|
||||
set x ampm(23:12) + ""
|
||||
|
||||
# Coerce with am/pm
|
||||
set x coerce("TIME", "12:45am")
|
||||
set x coerce("TIME", "12:45")
|
||||
set x coerce("TIME", "1:45pm")
|
||||
set x coerce("DATETIME", "2020-05-05@12:45am")
|
||||
set x coerce("DATETIME", "2020-05-05@12:45")
|
||||
set x coerce("DATETIME", "2020-05-05@1:45pm")
|
||||
|
||||
# Overflow - these tests only work on machines with 32-bit
|
||||
# twos-complement signed integers. You may get test failures on
|
||||
# machines with different architectures.
|
||||
set a $IntMin - 1
|
||||
set a $IntMin - $IntMax
|
||||
set a $IntMax - $IntMin
|
||||
set a $IntMax - (-1)
|
||||
set a $IntMax + 1
|
||||
set a $IntMax + $IntMax
|
||||
set a $IntMin + (-1)
|
||||
set a $IntMin + $IntMin
|
||||
set a $IntMax * 2
|
||||
set a $IntMax * $IntMax
|
||||
set a $IntMax * $IntMin
|
||||
set a $IntMin * 2
|
||||
set a $IntMin * $IntMin
|
||||
set a $IntMin * $IntMax
|
||||
set a $IntMin / (-1)
|
||||
set a $IntMin * (-1)
|
||||
set a (-1) * $IntMin
|
||||
set a abs($IntMin)
|
||||
|
||||
# The "isany" function
|
||||
set a isany(1)
|
||||
set a isany("foo")
|
||||
set a isany(1:00)
|
||||
set a isany(1, 2)
|
||||
set a isany("foo", 2)
|
||||
set a isany(1:00, 2)
|
||||
set a isany(1, 2, 1, 3)
|
||||
set a isany("foo", 2, 3, "foo")
|
||||
set a isany(1:00, 2, "foo", 2:00, 1:00, 9:00)
|
||||
|
||||
# Shellescape
|
||||
set a shellescape(" !\"#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")
|
||||
|
||||
msg [a]
|
||||
|
||||
# Deprecated functions
|
||||
set x psshade(50)
|
||||
set x psmoon(0)
|
||||
|
||||
# Don't want Remind to queue reminders
|
||||
EXIT
|
||||
|
||||
__EOF__
|
||||
REM This line should not even be seen
|
||||
And you can put whatever you like here.
|
||||
[+f=asdfasdasde3ir0a]
|
||||
|
||||
|
||||
4
tests/utf-8.rem
Normal file
@@ -0,0 +1,4 @@
|
||||
MSG ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский
|
||||
MSG עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית
|
||||
|
||||
Wed MSG With tabs and spaces
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Unconfiguring Remind..."
|
||||
echo rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile
|
||||
rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile
|
||||
echo rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile rem2html/Makefile
|
||||
rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile rem2html/Makefile
|
||||
exit 0
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
# The complete path to where the scripts actually live, as seen by
|
||||
# the UNIX operating system.
|
||||
SCRIPTDIR = /var/www/cgi-bin
|
||||
SCRIPTDIR = /usr/lib/cgi-bin
|
||||
|
||||
# Where the scripts live as seen by the web browser.
|
||||
CGIDIR = /cgi-bin
|
||||
@@ -17,7 +17,7 @@ HTMLDIR = /var/www/remind
|
||||
# Where you stick images and CSS files, as seen by UNIX
|
||||
IMAGEDIR = /var/www/remind/resources
|
||||
|
||||
# Where images are, as seen by web browers
|
||||
# Where images and CSS fiels are, as seen by web browers
|
||||
IMAGEBASE = /remind/resources
|
||||
|
||||
# Set by configure - don't touch.
|
||||
@@ -32,7 +32,7 @@ datarootdir=@datarootdir@
|
||||
# Where do Remind and Rem2PS executables live?
|
||||
REMIND = $(bindir)/remind
|
||||
REM2PS = $(bindir)/rem2ps
|
||||
|
||||
REM2HTML = $(bindir)/rem2html
|
||||
# If your Web server requires CGI programs to have a .cgi suffix, use
|
||||
# the next line. Otherwise, comment it out
|
||||
CGISUFFIX=.cgi
|
||||
@@ -46,14 +46,8 @@ SEDSCRIPT = -e 's@%CGIDIR%@$(CGIDIR)@g' \
|
||||
-e 's@%REMIND%@$(REMIND)@g' \
|
||||
-e 's@%IMAGEBASE%@$(IMAGEBASE)@g' \
|
||||
-e 's@%REM2PS%@$(REM2PS)@g' \
|
||||
-e 's@%REM2HTML%@$(REM2HTML)@g' \
|
||||
-e 's@cal_dispatch@cal_dispatch$(CGISUFFIX)@g' \
|
||||
-e 's@rem2html@rem2html$(CGISUFFIX)@g'
|
||||
|
||||
SEDSCRIPT2 = -e 's@%CGIDIR%@$(CGIDIR)@g' \
|
||||
-e 's@%SCRIPTDIR%@$(SCRIPTDIR)@g' \
|
||||
-e 's@%REMIND%@$(REMIND)@g' \
|
||||
-e 's@%IMAGEBASE%@$(IMAGEBASE)@g' \
|
||||
-e 's@%REM2PS%@$(REM2PS)@g'
|
||||
|
||||
all:
|
||||
@echo "Edit the Makefile; then type 'make install' to install"
|
||||
@@ -69,29 +63,24 @@ install:
|
||||
sed $(SEDSCRIPT) < moon.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/moon.rem
|
||||
sed $(SEDSCRIPT) < sunrise.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/sunrise.rem
|
||||
sed $(SEDSCRIPT) < sunset.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/sunset.rem
|
||||
cp blank.rem $(DESTDIR)$(SCRIPTDIR)/blank.rem
|
||||
sed $(SEDSCRIPT) < calendar.html-DIST > $(DESTDIR)$(HTMLDIR)/calendar.html
|
||||
sed $(SEDSCRIPT) < hebhtml > $(DESTDIR)$(SCRIPTDIR)/hebhtml
|
||||
sed $(SEDSCRIPT2) < rem2html > $(DESTDIR)$(SCRIPTDIR)/rem2html$(CGISUFFIX)
|
||||
chmod 644 $(DESTDIR)$(SCRIPTDIR)/sunrise.rem
|
||||
chmod 644 $(DESTDIR)$(SCRIPTDIR)/moon.rem
|
||||
chmod 644 $(DESTDIR)$(SCRIPTDIR)/hebdate.rem
|
||||
chmod 644 $(DESTDIR)$(SCRIPTDIR)/sunset.rem
|
||||
chmod 644 $(DESTDIR)$(SCRIPTDIR)/blank.rem
|
||||
chmod 644 $(DESTDIR)$(HTMLDIR)/calendar.html
|
||||
chmod 755 $(DESTDIR)$(SCRIPTDIR)/cal_dispatch$(CGISUFFIX)
|
||||
chmod 755 $(DESTDIR)$(SCRIPTDIR)/rem2html$(CGISUFFIX)
|
||||
chmod 755 $(DESTDIR)$(SCRIPTDIR)/calps $(DESTDIR)$(SCRIPTDIR)/hebdate \
|
||||
$(DESTDIR)$(SCRIPTDIR)/hebps $(DESTDIR)$(SCRIPTDIR)/moon \
|
||||
$(DESTDIR)$(SCRIPTDIR)/sunrise $(DESTDIR)$(SCRIPTDIR)/sunset \
|
||||
$(DESTDIR)$(SCRIPTDIR)/hebhtml \
|
||||
$(DESTDIR)$(SCRIPTDIR)/rem2html$(CGISUFFIX)
|
||||
|
||||
-mkdir -p $(DESTDIR)$(IMAGEDIR)
|
||||
cp firstquarter.png fullmoon.png lastquarter.png newmoon.png rem-default.css $(DESTDIR)$(IMAGEDIR)
|
||||
chmod 644 $(DESTDIR)$(IMAGEDIR)/firstquarter.png \
|
||||
$(DESTDIR)$(IMAGEDIR)/fullmoon.png \
|
||||
$(DESTDIR)$(IMAGEDIR)/lastquarter.png \
|
||||
$(DESTDIR)$(IMAGEDIR)/newmoon.png \
|
||||
$(DESTDIR)$(IMAGEDIR)/rem-default.css
|
||||
cp rem-default.css *.png $(DESTDIR)$(IMAGEDIR)
|
||||
chmod 644 $(DESTDIR)$(IMAGEDIR)/rem-default.css $(DESTDIR)$(IMAGEDIR)/*.png
|
||||
|
||||
|
||||
|
||||
|
||||
10
www/README
@@ -9,7 +9,7 @@ only tested it with Linux running NCSA's httpd and Apache's httpd, but
|
||||
it should work on any UNIX web server.
|
||||
|
||||
To install it, you need the Remind package, available via ftp from
|
||||
ftp://ftp.doe.carleton.ca/pub/remind-3.0. You should install Remind,
|
||||
https://dianne.skoll.ca/projects/remind/ You should install Remind,
|
||||
setting the lattitude, longitude, location and time zone as appropriate
|
||||
for your machine.
|
||||
|
||||
@@ -19,9 +19,7 @@ server:
|
||||
1) Edit the Makefile in this directory. See the comments in the Makefile
|
||||
for details.
|
||||
|
||||
2) Edit the first line of "rem2html" to reflect the location of
|
||||
Perl on your system. (Oh yeah, you need Perl for the
|
||||
HTML Hebrew calendar...)
|
||||
2) Make sure "rem2html" is installed.
|
||||
|
||||
3) Type "make install"
|
||||
|
||||
@@ -38,12 +36,8 @@ where "what" is one of:
|
||||
hebps -- get a PostScript calendar with Jewish holidays.
|
||||
hebhtml -- get an HTML version of the above (requires Perl.)
|
||||
|
||||
(Visit http://www.doe.carleton.ca/~dfs/ for previews.)
|
||||
|
||||
All of these links will be set up in a sample HTML document
|
||||
called "calendar.html" and installed in the HTMLDIR you specified
|
||||
in the Makefile.
|
||||
|
||||
4) Enjoy!
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
REM2HTML
|
||||
--------
|
||||
|
||||
Rem2HTML is a Perl script that transforms the output of `remind -p
|
||||
...' to HTML. Type `perl rem2html --help' for usage information.
|
||||
|
||||
Typical usage: remind -p ~/.reminders | rem2html > file.html
|
||||
|
||||
You may have to edit the "#!/usr/bin/perl" line to reflect the
|
||||
location of your Perl interpreter.
|
||||
|
||||
--
|
||||
Dianne Skoll
|
||||
5
www/blank.rem
Normal file
@@ -0,0 +1,5 @@
|
||||
[moondate(0)] SPECIAL MOON 0
|
||||
[moondate(1)] SPECIAL MOON 1
|
||||
[moondate(2)] SPECIAL MOON 2
|
||||
[moondate(3)] SPECIAL MOON 3
|
||||
REM Monday SPECIAL WEEK (W[weekno()])
|
||||
@@ -7,5 +7,5 @@
|
||||
echo "Content-type: application/postscript"
|
||||
echo
|
||||
|
||||
$REMIND -p /dev/null | $REM2PS -e -c3 -l
|
||||
$REMIND -p $DIR/blank.rem | $REM2PS -e -c3 -l
|
||||
exit 0
|
||||
|
||||
|
Before Width: | Height: | Size: 379 B After Width: | Height: | Size: 354 B |
BIN
www/fullmoon.png
|
Before Width: | Height: | Size: 317 B After Width: | Height: | Size: 360 B |
@@ -29,6 +29,8 @@ ENDIF
|
||||
# #
|
||||
##########################################################################
|
||||
|
||||
SET n $NumTrig
|
||||
|
||||
# --- HERE ARE THE JEWISH HOLIDAYS ---
|
||||
# Set the variable InIsrael to 1 if you live in Israel. Otherwise,
|
||||
# you get the Diaspora versions of Jewish holidays
|
||||
@@ -138,6 +140,10 @@ ENDIF
|
||||
|
||||
fset msgprefix(x) ""
|
||||
|
||||
IF $NumTrig > n
|
||||
REM SPECIAL SHADE 224 224 255
|
||||
ENDIF
|
||||
|
||||
# Counting the omer - do the whole spiel, i.e:
|
||||
# "This is the xth day of the omer, being y weeks and z days of the omer."
|
||||
# Nice Remind programming example here!
|
||||
@@ -165,7 +171,7 @@ ELSE
|
||||
[trigger(moondate(2))] SPECIAL MOON 2
|
||||
[trigger(moondate(3))] SPECIAL MOON 3
|
||||
REM PS Border Border moveto /DayFont findfont 10 scalefont setfont ([hebday(today())] [hebmon(today())]) show
|
||||
REM SPECIAL HTML <P><FONT SIZE=-1>[hebday(today())] [hebmon(today())]</FONT></P>
|
||||
REM SPECIAL HTML <P>[hebday(today())] [hebmon(today())]</P>
|
||||
|
||||
ENDIF
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ set lastyear iif(lastmon==12, thisyear-1, thisyear)
|
||||
set nextmon mon(nextmon)
|
||||
set lastmon mon(lastmon)
|
||||
BANNER %
|
||||
REM RUN $REMIND -iHTML=1 -p $DIR/hebdate.rem %m %y | $DIR/rem2html --forwurl "cal_dispatch?hebhtml+[nextmon]+[nextyear]" --backurl "cal_dispatch?hebhtml+[lastmon]+[lastyear]"
|
||||
REM RUN $REMIND -iHTML=1 -p $DIR/hebdate.rem %m %y | %REM2HTML% --forwurl "cal_dispatch?hebhtml+[nextmon]+[nextyear]" --backurl "cal_dispatch?hebhtml+[lastmon]+[lastyear]" --imgbase "%IMAGEBASE%" --stylesheet rem-default.css --pngs
|
||||
EOR
|
||||
|
||||
else
|
||||
@@ -33,7 +33,7 @@ set lastyear iif(lastmon==12, thisyear-1, thisyear)
|
||||
set nextmon mon(nextmon)
|
||||
set lastmon mon(lastmon)
|
||||
BANNER %
|
||||
REM RUN $REMIND -iHTML=1 -p $DIR/hebdate.rem %m %y | $DIR/rem2html --forwurl "cal_dispatch?hebhtml+[nextmon]+[nextyear]" --backurl "cal_dispatch?hebhtml+[lastmon]+[lastyear]"
|
||||
REM RUN $REMIND -iHTML=1 -p $DIR/hebdate.rem %m %y | %REM2HTML% --forwurl "cal_dispatch?hebhtml+[nextmon]+[nextyear]" --backurl "cal_dispatch?hebhtml+[lastmon]+[lastyear]" --imgbase "%IMAGEBASE%" --stylesheet rem-default.css --pngs
|
||||
EOR
|
||||
|
||||
fi
|
||||
|
||||
|
Before Width: | Height: | Size: 367 B After Width: | Height: | Size: 361 B |
BIN
www/newmoon.png
|
Before Width: | Height: | Size: 362 B After Width: | Height: | Size: 317 B |
@@ -1,6 +1,8 @@
|
||||
table.rem-cal {
|
||||
font-family: helvetica, arial, sans-serif;
|
||||
font-size: 12pt;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.rem-sc-table {
|
||||
@@ -37,11 +39,6 @@ td.rem-today {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.rem-cal {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
div.rem-daynumber {
|
||||
float: right;
|
||||
text-align: right;
|
||||
@@ -49,6 +46,10 @@ div.rem-daynumber {
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
p.rem-entry {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
div.rem-moon {
|
||||
float: left;
|
||||
text-align: left;
|
||||
@@ -66,4 +67,4 @@ td.rem-sc-empty-cell, td.rem-sc-cell {
|
||||
|
||||
caption.rem-sc-caption {
|
||||
font-size: 12pt;
|
||||
}
|
||||
}
|
||||
|
||||