Compare commits
379 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
||||
|
||||
51
configure
vendored
@@ -626,6 +626,7 @@ VERSION
|
||||
EGREP
|
||||
GREP
|
||||
CPP
|
||||
PERL
|
||||
SET_MAKE
|
||||
LN_S
|
||||
INSTALL_DATA
|
||||
@@ -3274,6 +3275,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 +3861,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,7 +4017,7 @@ 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
|
||||
@@ -3991,9 +4032,10 @@ _ACEOF
|
||||
fi
|
||||
done
|
||||
|
||||
VERSION=03.01.16
|
||||
VERSION=03.03.09
|
||||
|
||||
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 +4731,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
|
||||
|
||||
10
configure.in
@@ -49,6 +49,7 @@ 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 +62,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 +72,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
|
||||
VERSION=03.03.09
|
||||
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)
|
||||
|
||||
@@ -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 -------------
|
||||
|
||||
263
docs/WHATSNEW
@@ -1,5 +1,268 @@
|
||||
CHANGES TO REMIND
|
||||
|
||||
* 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 directices. 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 arithemtic 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 maxmimum 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
|
||||
|
||||
@@ -26,8 +26,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.09"
|
||||
ERRMSG This file requires at least version 03.01.09 of Remind.%
|
||||
ERRMSG This version is version [version()].
|
||||
EXIT
|
||||
ENDIF
|
||||
@@ -84,7 +84,6 @@ SET December 12
|
||||
###########################################################
|
||||
# Other symbolic constants and functions for "pasting"... #
|
||||
###########################################################
|
||||
|
||||
SET Quote CHAR(34)
|
||||
|
||||
# Handy constants/function for specifing week of month...
|
||||
@@ -95,29 +94,17 @@ 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")
|
||||
FSET _back(days) $U-days
|
||||
|
||||
#################################################################
|
||||
# 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 +112,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 +131,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
|
||||
|
||||
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 +164,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 +208,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%"
|
||||
@@ -301,7 +226,7 @@ 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%"
|
||||
OMIT [$T] MSG %"President's Day%"
|
||||
REM Mar 17 MSG %"St. Patrick's%" Day
|
||||
|
||||
# The DST rules are accurate for most locations in
|
||||
@@ -319,23 +244,23 @@ 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%"
|
||||
OMIT [$T] 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%"
|
||||
OMIT [$T] 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] \
|
||||
SATISFY [($Ty % 4) == 0] \
|
||||
MSG %"Election%" Day
|
||||
REM Thu Nov [Week_4] SCANFROM [_back(7)] SATISFY 1
|
||||
OMIT [trigdate()] MSG %"Thanksgiving%" Day
|
||||
OMIT [$T] MSG %"Thanksgiving%" Day
|
||||
REM Fri Nov [Week_4+1] SCANFROM [_back(7)] SATISFY 1
|
||||
OMIT [trigdate()] MSG %"Thanksgiving%" (cont.)
|
||||
OMIT [$T] MSG %"Thanksgiving%" (cont.)
|
||||
OMIT Dec 24 MSG %"Christmas Eve%"
|
||||
OMIT Dec 25 MSG %"Christmas%" Day
|
||||
|
||||
@@ -350,13 +275,6 @@ 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 +288,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 +300,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 +308,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 +348,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 +382,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 +471,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,8 +491,8 @@ 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
|
||||
##########################################################################
|
||||
|
||||
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
|
||||
|
||||
611
man/remind.1
@@ -1,4 +1,4 @@
|
||||
.TH REMIND 1 "31 August 2008"
|
||||
.TH REMIND 1 "1 January 2021"
|
||||
.UC 4
|
||||
.SH NAME
|
||||
remind \- a sophisticated reminder service
|
||||
@@ -26,12 +26,13 @@ Anything after the __EOF__ marker is completely ignored.
|
||||
|
||||
.SH OPTIONS
|
||||
\fBRemind\fR has a slew of options. If you're new to the program,
|
||||
ignore them for now and skip to the section "Reminder Files".
|
||||
ignore them for now and skip to the section "REMINDER FILES".
|
||||
.TP
|
||||
.B \-n
|
||||
The \fB\-n\fR option causes \fBRemind\fR to print the \fBnext\fR occurrence
|
||||
of each reminder in a simple calendar format. You can sort this by
|
||||
date by piping the output through \fBsort(1)\fR.
|
||||
date by piping the output through \fBsort(1)\fR. Note that the \fB\-n\fR
|
||||
option causes any \fB\-g\fR option to be \fIignored\fR.
|
||||
.TP
|
||||
.B \-j\fR[\fIn\fR]
|
||||
Runs \fBRemind\fR in "purge" mode to get rid of expired reminders.
|
||||
@@ -39,14 +40,15 @@ See the section PURGE MODE for details.
|
||||
.TP
|
||||
.B \-r
|
||||
The \fB\-r\fR option disables \fBRUN\fR directives and the \fBshell()\fR
|
||||
function. As of Remind 3.00.17, using \fB\-u\fR implies \fB\-r\fR.
|
||||
function.
|
||||
.TP
|
||||
.B \-c\fI[flags]\fIn\fR
|
||||
The \fB\-c\fR option causes \fBRemind\fR to produce a calendar that is
|
||||
sent to standard output. If you supply a number \fIn\fR, then a
|
||||
calendar will be generated for \fIn\fR months, starting with the
|
||||
current month. By default, a calendar for only the current month is
|
||||
produced.
|
||||
produced.
|
||||
.RS
|
||||
.PP
|
||||
You can precede \fIn\fR (if any) with a set of flags. The flags
|
||||
are as follows:
|
||||
@@ -72,24 +74,54 @@ only work on terminals that are set to UTF-8 character encoding.
|
||||
.TP
|
||||
.B 'c'
|
||||
causes \fBRemind\fR to use VT100 escape sequences to approximate
|
||||
SPECIAL COLOR reminders. The approximation is (of necessity) very
|
||||
SPECIAL COLOR reminders. Note that this flag is kept for
|
||||
backwards-compatibility; you should use the \fB\-@\fI[n][,m]\fR
|
||||
command-line option instead.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B \-@\fR[\fIn\fR][,\fIm\fR]
|
||||
Tells \fBRemind\fR to approximate SPECIAL COLOR reminders using VT100
|
||||
escape sequences. The approximation is (of necessity) very
|
||||
coarse, because the VT100 only has eight different color sequences,
|
||||
each with one of two brightnesses. A color component greater than
|
||||
64 is considered "on", and if any of the three color components is
|
||||
greater than 128, the color is considered "bright".
|
||||
|
||||
.RS
|
||||
.PP
|
||||
If you supply the optional numeric parameters, the have the following
|
||||
meanings: \fIn\fR=0 tells \fBRemind\fR to use the standard 16 VT100
|
||||
colors. \fIn\fR=1 tells it to use an extended 256-color palette supported
|
||||
by many terminal emulators such as xterm. And \fIn\fR=2 tells it to
|
||||
use escape sequences that support true 24-bit colors, again supported
|
||||
by many terminal emulators such as xterm.
|
||||
.PP
|
||||
If the optional \fIm\fR parameter is supplied following a comma,
|
||||
then \fIm\fR=0 tells \fBRemind\fR that the terminal background is dark,
|
||||
and \fBRemind\fR will brighten up dark colors to make them visible. If
|
||||
\fIm\fR=1, then \fBRemind\fR assumes the terminal background is light
|
||||
and it will darken bright colors to make them visible. If no \fIm\fR
|
||||
is supplied, then \fBRemind\fR does not perform any adjustments, and
|
||||
some reminders may be hard or impossible to see if the color is too close
|
||||
to the terminal background color.
|
||||
.RE
|
||||
.TP
|
||||
.B \-w\fR\fIcol\fR[,\fIpad\fR[,\fIspc\fR]]]
|
||||
The \fB\-w\fR option specifies the output width, padding and spacing
|
||||
of the formatted calendar output. \fICol\fR specifies the number of
|
||||
columns in the output device, and defaults to 80. \fIPad\fR specifies
|
||||
how many lines to use to "pad" empty calendar boxes. This defaults to
|
||||
5. If you have many reminders on certain days that make your calendar
|
||||
too large to fit on a page, you can try reducing \fIpad\fR to make the
|
||||
empty boxes smaller. \fISpc\fR specifies how many blank lines to leave
|
||||
between the day number and the first reminder entry. It defaults to 1.
|
||||
columns in the output device. If not specified, or specified as 0,
|
||||
it defaults to the larger of 71 or the actual width of your terminal,
|
||||
or to 80 if standard output is not a terminal.
|
||||
.RS
|
||||
.PP
|
||||
\fIPad\fR specifies how many lines
|
||||
to use to "pad" empty calendar boxes. This defaults to 5. If you
|
||||
have many reminders on certain days that make your calendar too large
|
||||
to fit on a page, you can try reducing \fIpad\fR to make the empty
|
||||
boxes smaller. \fISpc\fR specifies how many blank lines to leave
|
||||
between the day number and the first reminder entry. It defaults to
|
||||
1.
|
||||
.PP
|
||||
Any of \fIcol\fR, \fIpad\fR or \fIspc\fR can be omitted, providing you
|
||||
provide the correct number of commas. Don't use any spaces in the option.
|
||||
.RE
|
||||
@@ -106,17 +138,27 @@ If you immediately follow the \fBs\fR with the letter
|
||||
day they actually occur \fIas well as\fR on any preceding days specified
|
||||
by the reminder's \fIdelta\fR.
|
||||
.TP
|
||||
.B \-p\fR[\fBa\fR]\fIn\fR
|
||||
.B \-p\fR[\fBa\fR][\fBp\fR][\fBp\fR]\fIn\fR
|
||||
The \fB\-p\fR option is very similar to the \fB\-s\fR option, except
|
||||
that the output contains additional information for use by the
|
||||
\fBRem2PS\fR program, which creates a PostScript calendar. For this
|
||||
\fBRem2PS\fR program, which creates a PostScript calendar, and various
|
||||
other back-end programs. For this
|
||||
option, \fIn\fR cannot start with "+"; it must specify a number of months.
|
||||
The format of the \fB\-p\fR output is described in the \fBrem2ps(1)\fR
|
||||
man page. If you immediately follow the \fBp\fR with the letter
|
||||
\fBa\fR, then \fBRemind\fR displays reminders on the calendar on the
|
||||
day they actually occur \fIas well as\fR on any preceding days specified
|
||||
by the reminder's \fIdelta\fR.
|
||||
|
||||
by the reminder's \fIdelta\fR. If you follow the \fBp\fR with another
|
||||
\fBp\fR, then \fBRemind\fR uses a more comprehensive JSON-based
|
||||
format rather than the "simple calendar" format. This format is
|
||||
also documented in the \fBrem2ps(1)\fR man page. Finally, if you use
|
||||
three p's, as in \fB\-ppp\fR, then \fBRemind\fR uses a pure JSON
|
||||
format, again documented in \fBrem2ps(1)\fR.
|
||||
.RS
|
||||
.PP
|
||||
Note that the \fB\-pp\fR or \fB\-ppp\fR options also enable the \fB\-l\fR
|
||||
option.
|
||||
.RE
|
||||
.TP
|
||||
.B \-l
|
||||
If you use the \-l option in conjunction with the \-p option, then
|
||||
@@ -207,8 +249,9 @@ encountered in the reminder script. The \fB\-g\fR option cause
|
||||
\fBRemind\fR to sort reminders by date and time prior to issuing them.
|
||||
The optional \fBa\fR and \fBd\fR characters specify the sort order
|
||||
(ascending or descending) for the date, time and priority fields. See
|
||||
the section "Sorting Reminders" for more information.
|
||||
the section "SORTING REMINDERS" for more information.
|
||||
|
||||
Note that \fB\-g\fR is \fIignored\fR if you use the \fB\-n\fR option.
|
||||
.TP
|
||||
\fB\-b\fR[\fIn\fR]
|
||||
Set the time format for the calendar and simple-calendar outputs. \fIN\fR
|
||||
@@ -267,7 +310,11 @@ and user name, respectively, of the specified user. LOGNAME is also
|
||||
set to the specified user name. This option is meant for
|
||||
use in shell scripts that mail reminders to all users. Note that
|
||||
as of Remind 3.00.17, using \fB\-u\fR implies \fB\-r\fR -- the RUN
|
||||
directive and shell() functions are disabled.
|
||||
directive and shell() functions are disabled. However, if you prefix
|
||||
\fIname\fR with a \fB+\fR-sign, then RUN and shell() are \fInot\fR
|
||||
disabled. That is, \fB\-uwhatever\fR switches the user to \fBwhatever\fR
|
||||
and disables RUN, whereas \fB\-u+whatever\fR switches the user to
|
||||
\fBwhatever\fR but leaves RUN enabled.
|
||||
.PP
|
||||
.RS
|
||||
Non-root users can also use the \fB\-u\fR option. However, in this
|
||||
@@ -275,6 +322,13 @@ case, it only changes the environment variables as described above.
|
||||
It does not change the effective uid or gid.
|
||||
.RE
|
||||
.TP
|
||||
\fB\-+\fIusername\fR
|
||||
Causes \fBRemind\fR to trust files owned by the user \fIusername\fR.
|
||||
Normally, if \fBRemind\fR reads a file that you do not own, it disables
|
||||
RUN and the shell() function. This option causes it to also trust files
|
||||
owned by \fIusername\fR. You can supply multiple \fB\-+\fR options
|
||||
to trust multiple users, up to a limit of 20 trusted users.
|
||||
.TP
|
||||
\fB-y\fR
|
||||
Causes \fBRemind\fR to synthesize a tag for any reminder that lacks a
|
||||
TAG clause.
|
||||
@@ -282,7 +336,7 @@ TAG clause.
|
||||
\fB\-i\fR\fIvar\fR\fB=\fR\fIexpr\fR
|
||||
Sets the value of the specified \fIvar\fR to \fIexpr\fR, and \fBpreserves\fR
|
||||
\fIvar\fR. \fIExpr\fR can be any valid \fBRemind\fR expression. See the
|
||||
section "Initializing Variables on the Command Line" for more details.
|
||||
section "INITIALIZING VARIABLES ON THE COMMAND LINE" for more details.
|
||||
.TP
|
||||
\fB\-i\fR\fIfunc\fR(\fIargs\fR)=\fIdefinition\fR
|
||||
Allows you to define a function on the command line.
|
||||
@@ -293,24 +347,25 @@ If you supply a \fIdate\fR on the command line, it must consist of
|
||||
of the month, and \fIyear\fR is a year (all 4 digits) from 1990 to
|
||||
about 2075. You can leave out the \fIday\fR, which then defaults to 1.
|
||||
.PP
|
||||
If you do supply a \fIdate\fR on the command line, then \fBRemind\fR uses
|
||||
it, rather than the actual system date, as its notion of "today."
|
||||
This lets you create calendars for future months, or test to see
|
||||
how your reminders will be triggered in the future. Similarly,
|
||||
you can supply a \fItime\fR (in 24-hour format -- for example, 17:15) to
|
||||
set \fBRemind\fR's notion of "now" to a particular time. Supplying
|
||||
a \fItime\fR on the command line also implicitly enables the \fB\-q\fR
|
||||
option and disables the \fB\-z\fR option.
|
||||
If you do supply a \fIdate\fR on the command line, then \fBRemind\fR
|
||||
uses it, rather than the actual system date, as its notion of "today."
|
||||
This lets you create calendars for future months, or test to see how
|
||||
your reminders will be triggered in the future. Similarly, you can
|
||||
supply a \fItime\fR to set \fBRemind\fR's notion of "now" to a
|
||||
particular time. Supplying a \fItime\fR on the command line also
|
||||
implicitly enables the \fB\-q\fR option and disables the \fB\-z\fR
|
||||
option. The \fItime\fR may be specified in 24-hour format (eg, 13:20)
|
||||
or common "AM/PM" format (1:20pm).
|
||||
.PP
|
||||
If you would rather specify the date more succinctly, you can supply
|
||||
it as YYYY-MM-DD or YYYY/MM/DD. You can even supply a date and
|
||||
time on the command line as one argument: YYYY-MM-DD@HH:MM.
|
||||
.PP
|
||||
In addition, you can supply a \fIrepeat\fR parameter, which has the
|
||||
form *\fInum\fR. This causes \fBRemind\fR to be run \fInum\fR times,
|
||||
form *\fIrep\fR. This causes \fBRemind\fR to be run \fIrep\fR times,
|
||||
with the date incrementing on each iteration. You may have to enclose
|
||||
the parameter in quotes to avoid shell expansion. See the subsection
|
||||
"Repeated Execution" in the section "Calendar Mode" for more
|
||||
"Repeated Execution" in the section "CALENDAR MODE" for more
|
||||
information.
|
||||
.SH REMINDER FILES
|
||||
.PP
|
||||
@@ -397,7 +452,7 @@ These keywords denote the \fItype\fR
|
||||
of the reminder. (\fBSATISFY\fR is more complicated and will be explained
|
||||
later.) A \fBMSG\fR-type reminder normally prints a message to the standard
|
||||
output, after passing the \fIbody\fR through a special substitution filter,
|
||||
described in the section "The Substitution Filter." However, if you have
|
||||
described in the section "THE SUBSTITUTION FILTER." However, if you have
|
||||
used the \fB\-k\fR command-line option, then \fBMSG\fR-type reminders are
|
||||
passed to the appropriate program. Note that the options \fB\-c\fR,
|
||||
\fB\-s\fR, \fB\-p\fR and \fB\-n\fR disable the \fB\-k\fR option.
|
||||
@@ -415,7 +470,7 @@ The \fBMSF\fR keyword is almost the same as the \fBMSG\fR keyword,
|
||||
except that the reminder is formatted to fit into a paragraph-like
|
||||
format. Three system variables control the formatting of \fBMSF\fR-type
|
||||
reminders - they are \fB$FirstIndent\fR, \fB$SubsIndent\fR and
|
||||
\fB$FormWidth\fR. They are discussed in the section "System Variables."
|
||||
\fB$FormWidth\fR. They are discussed in the section "SYSTEM VARIABLES."
|
||||
The \fBMSF\fR keyword causes the spacing of your reminder to be altered -
|
||||
extra spaces are discarded, and two spaces are placed after periods and
|
||||
other characters, as specified by the system variables \fB$EndSent\fR and
|
||||
@@ -448,7 +503,8 @@ of a special reminder depends on the back-end. For the \fBRem2PS\fR
|
||||
back-end, \fBSPECIAL PostScript\fR is equivalent to a \fBPS\fR-type
|
||||
reminder, and \fBSPECIAL PSFile\fR is equivalent to a \fBPSFILE\fR-type
|
||||
reminder. The body of a \fBSPECIAL\fR reminder is obviously dependent
|
||||
upon the back-end.
|
||||
upon the back-end. A back-end \fImust\fR ignore a \fBSPECIAL\fR that
|
||||
it does not recognize.
|
||||
.PP
|
||||
.B DATE SPECIFICATIONS
|
||||
.PP
|
||||
@@ -475,7 +531,7 @@ characters must be used. The following are examples of the various parts of a
|
||||
JANUARY, feb, March, ApR, may, Aug
|
||||
.TP
|
||||
.I year:
|
||||
1990, 1993, 2030, 95 (interpreted as 1995). The year can range
|
||||
1990, 1993, 2030. The year can range
|
||||
from 1990 to 2075.
|
||||
.TP
|
||||
.I weekday:
|
||||
@@ -575,7 +631,7 @@ present. Examples:
|
||||
.nf
|
||||
REM Sat 1 MSG First Saturday of every month
|
||||
REM Mon Tue Wed Thu Fri 15 \\
|
||||
MSG 1st working day after 15th of every month
|
||||
MSG 1st working day on or after 15th of every month
|
||||
.fi
|
||||
.PP
|
||||
11.
|
||||
@@ -772,7 +828,7 @@ the initial date, and does not affect the repetition period.
|
||||
.B SCANFROM \fRand\fB FROM
|
||||
.PP
|
||||
The \fBSCANFROM\fR and \fBFROM\fR keywords are for advanced \fBRemind\fR programmers
|
||||
only, and will be explained in the section "Details about Trigger Computation"
|
||||
only, and will be explained in the section "DETAILS ABOUT TRIGGER COMPUTATION"
|
||||
near the end of this manual. Note that \fBSCANFROM\fR is available only
|
||||
in versions of \fBRemind\fR from 03.00.04 up. \fBFROM\fR is available only
|
||||
from 03.01.00 and later.
|
||||
@@ -784,7 +840,7 @@ It is used in calendar mode and when sorting reminders. If two reminders
|
||||
have the same trigger date and time, then they are sorted by priority.
|
||||
If the \fBPRIORITY\fR keyword is not supplied, a default priority of 5000
|
||||
is used. (This default can be changed by adjusting the system variable
|
||||
\fB$DefaultPrio\fR. See the section "System Variables" for more
|
||||
\fB$DefaultPrio\fR. See the section "SYSTEM VARIABLES" for more
|
||||
information.)
|
||||
.PP
|
||||
.B EXPIRY DATES
|
||||
@@ -817,6 +873,20 @@ As a special case, you can use the \fBTHROUGH\fR keyword instead of
|
||||
REM 1992-11-30 +2 THROUGH 1992-12-04 MSG Jury duty
|
||||
.fi
|
||||
.PP
|
||||
If you have an expiry date via the use of \fBTHROUGH\fR or \fBUNTIL\fR,
|
||||
then Remind will \fInever\fR trigger the reminder after the expiry
|
||||
date. For example, if you have this:
|
||||
.PP
|
||||
.nf
|
||||
OMIT 2021-01-08
|
||||
REM 2021-01-01 THROUGH 2021-01-08 AFTER MSG Test
|
||||
.fi
|
||||
.PP
|
||||
the reminder will not be triggered on 2021-01-08, and nor will it be
|
||||
triggered on 2021-01-09; even though the AFTER keyword would normally
|
||||
move the 8th's reminder to the 9th, the expiry date of 2021-01-08
|
||||
overrides that.
|
||||
.PP
|
||||
.B THE ONCE KEYWORD
|
||||
.PP
|
||||
Sometimes, it is necessary to ensure that reminders are run only once
|
||||
@@ -925,8 +995,13 @@ it terminates the search after the \fBSATISFY\fR iteration limit
|
||||
.PP
|
||||
Timed reminders are those that have an \fBAT\fR keyword followed
|
||||
by a \fItime\fR and optional \fItdelta\fR and \fItrepeat\fR. The \fItime\fR
|
||||
must be specified in 24-hour format, with 0:00 representing midnight,
|
||||
may be specified in 24-hour format, with 0:00 representing midnight,
|
||||
12:00 representing noon, and 23:59 representing one minute to midnight.
|
||||
Alternatively, it may be specified in common "AM/PM" format; in this case,
|
||||
the hour must range from 1 to 12. 12:00am represents midnight, 12:00pm
|
||||
represents noon, and 11:59pm represents one minute to midnight. The "am"
|
||||
and "pm" portions are case-insensitive and the "m" is optional.
|
||||
.PP
|
||||
You can use either a colon or a period to separate the hours from the
|
||||
minutes. That is, 13:39 and 13.39 are equivalent.
|
||||
.PP
|
||||
@@ -953,7 +1028,7 @@ The following reminder will be triggered on Thursdays and Fridays,
|
||||
but will only be queued on Fridays:
|
||||
.PP
|
||||
.nf
|
||||
REM Fri ++1 AT 13:00 MSG Lunch at 1pm Friday.
|
||||
REM Fri ++1 AT 1:00PM MSG Lunch at 1pm Friday.
|
||||
.fi
|
||||
.PP
|
||||
The \fItdelta\fR and \fItrepeat\fR have the same form as a \fIrepeat\fR
|
||||
@@ -1013,7 +1088,7 @@ of timed reminders, and the \fBWARN\fR keyword allows precise control
|
||||
over the advance triggering of all types of reminders.
|
||||
However, discussion must be deferred until after
|
||||
expressions and user-defined functions are explained. See the subsection
|
||||
"Precise Scheduling" further on.
|
||||
"PRECISE SCHEDULING" further on.
|
||||
.PP
|
||||
.B TAG AND DURATION
|
||||
.PP
|
||||
@@ -1033,17 +1108,23 @@ by the hexadecimal representation of the MD5 sum of the REM
|
||||
command line. This lets you give a more-or-less unique identifier
|
||||
to each distinct REM command.
|
||||
.PP
|
||||
The \fBDURATION\fR keyword makes sense only for timed reminders;
|
||||
it specifies the duration of an event. Currently, this is not
|
||||
used, but it may be used in future by back-ends or scheduling
|
||||
systems built around \fBRemind\fR. For example, if you have
|
||||
a 90-minute meeting starting at 1:00pm, you could use:
|
||||
The \fBDURATION\fR keyword makes sense only for timed reminders; it
|
||||
specifies the duration of an event. For example, if you have a
|
||||
90-minute meeting starting at 1:00pm, you could use any of the following:
|
||||
.PP
|
||||
.nf
|
||||
REM 5 March 1999 AT 13:00 DURATION 1:30 MSG Meeting
|
||||
REM 5 March 2021 AT 13:00 DURATION 1:30 MSG Meeting
|
||||
REM 5 March 2021 AT 13:00 DURATION 90 MSG Meeting
|
||||
REM 5 March 2021 AT 1:00pm DURATION 1:30 MSG Meeting
|
||||
REM 5 March 2021 AT 1:00pm DURATION 90 MSG Meeting
|
||||
.fi
|
||||
.PP
|
||||
Note that \fIduration\fR is specified in hours and minutes.
|
||||
|
||||
Note that \fIduration\fR is specified either in hours and minutes as a
|
||||
\fItime\fR, or in minutes as an \fIinteger\fR. If you specify a
|
||||
duration of 00:00 or 0, then \fBRemind\fR behaves exactly as if no
|
||||
\fBDURATION\fR at all had been present.
|
||||
|
||||
.PP
|
||||
.SH THE SUBSTITUTION FILTER
|
||||
.PP
|
||||
@@ -1269,7 +1350,7 @@ is similar to \fB%3\fR but displays the current time.
|
||||
used by the substitution filter,
|
||||
but is used to tell \fBRemind\fR which text to include in a calendar
|
||||
entry when the \fB\-c\fR, \fB\-s\fR or \fB\-p\fR option is chosen.
|
||||
See "Calendar Mode"
|
||||
See "CALENDAR MODE"
|
||||
.PP
|
||||
Notes:
|
||||
.TP
|
||||
@@ -1511,6 +1592,53 @@ It will not run set-uid. If it reads a file you don't own, it will
|
||||
disable RUN and the shell() function. And if it is run as \fIroot\fR,
|
||||
it will only read files owned by \fIroot\fR.
|
||||
.PP
|
||||
Note that if \fBRemind\fR reads standard input, it does \fInot\fR
|
||||
attempt to check the ownership of standard input, even if it is
|
||||
coming from a file, and hence does \fInot\fR disable RUN and shell()
|
||||
in this situation.
|
||||
|
||||
.SH THE INCLUDECMD COMMAND
|
||||
.PP
|
||||
\fBRemind\fR allows you to execute a shell command and evaluate the
|
||||
output of that command as if it were an included file. For example,
|
||||
you could have scripts that extract reminders out of a database and print
|
||||
them on stdout as REM commands. Here is an example:
|
||||
.PP
|
||||
.nf
|
||||
INCLUDECMD extract_reminders_for dfs
|
||||
.fi
|
||||
.PP
|
||||
We assume that the command "extract_reminders_for" extracts reminders out
|
||||
of a central database for the named user. Another use-case of INCLUDECMD
|
||||
is if you have your reminders stored in a file in some non-Remind format;
|
||||
you can write a command that transforms them to Remind format and then
|
||||
Remind can "include" the file with an appropriate INCLUDECMD command.
|
||||
.PP
|
||||
Note that if RUN is disabled, then INCLUDECMD will fail with the error
|
||||
message "RUN disabled"
|
||||
.PP
|
||||
INCLUDECMD passes the rest of the line to \fBpopen\fR(3), meaning that
|
||||
the command is executed by the shell. As such, shell metacharacters
|
||||
may need escaping or arguments quoting, depending on what you're trying
|
||||
to do. Remind itself does not perform any modification of the command
|
||||
line (apart from the normal [expr] expression-pasting mechanism).
|
||||
.PP
|
||||
If the command passed to INCLUDECMD begins with an exclamation mark "!",
|
||||
then Remind disables \fBRUN\fR for the output of the command. If you are
|
||||
running a command whose output you don't quite trust, you should
|
||||
prefix it with "!" so that any RUN commands it emits fail.
|
||||
.PP
|
||||
An \fBINCLUDECMD\fR command counts towards the INCLUDE nesting depth.
|
||||
For any given Remind run, a given INCLUDECMD command is only executed
|
||||
once and the results are cached. For example, if you generate a
|
||||
calendar, each unique INCLUDECMD command is run just once, not once
|
||||
for each day of the produced calendar. "Uniqueness" is determined by
|
||||
looking at the command that will be passed to the shell, so if (for example)
|
||||
your INCLUDECMD uses expression-pasting that results in differences depending
|
||||
on the value of \fBtoday()\fR, then each \fIunique\fR version of the
|
||||
command will be executed once.
|
||||
.PP
|
||||
|
||||
.SH THE BANNER COMMAND
|
||||
.PP
|
||||
When \fBRemind\fR first issues a reminder, it prints a message like this:
|
||||
@@ -1623,13 +1751,15 @@ in C.
|
||||
.RE
|
||||
.TP
|
||||
.B TIME constants
|
||||
12:33, 0:01, 14:15, 16:42, 12.16, 13.00, 1.11
|
||||
12:33, 0:01, 14:15, 16:42, 12.16, 13.00, 1.11, 4:30PM, 12:20am
|
||||
.PP
|
||||
.RS
|
||||
Note that \fBTIME\fR constants are written in 24-hour format. Either the
|
||||
period or colon can be used to separate the minutes from the hours.
|
||||
However, Remind will consistently output times using only one separator
|
||||
character. (The output separator character is chosen at compile-time.)
|
||||
Note that \fBTIME\fR constants may be written in 24-hour format or in
|
||||
common "AM/PM" format. If you use "AM/PM" format, then the hour can
|
||||
range from 1 to 12. Either a period or colon can be used to separate
|
||||
the minutes from the hours. However, Remind will consistently output
|
||||
times in 24-hour format using only one separator character. (The
|
||||
output separator character is chosen at compile-time.)
|
||||
.RE
|
||||
.TP
|
||||
.B DATE constants
|
||||
@@ -1652,11 +1782,12 @@ versions prior to 03.00.02 did not support the '-' date separator.
|
||||
.RE
|
||||
.TP
|
||||
.B DATETIME constants
|
||||
\fBDATETIME\fR constants are expressed similarly to \fBDATE\fR constants
|
||||
with the addition of an "@HH:MM" part. For example:
|
||||
\fBDATETIME\fR constants are expressed similarly to \fBDATE\fR
|
||||
constants with the addition of an "@HH:MM" part, optionally followed
|
||||
by "am" or "pm". For example:
|
||||
.PP
|
||||
.RS
|
||||
\'2008-04-05@23:11', '1999/02/03@14:06', '2001-04-07@08:30'
|
||||
\'2008-04-05@23:11', '1999/02/03@14:06', '2001-04-07@08:30', '2020-01-01@3:20pm'
|
||||
.PP
|
||||
\fBDATETIME\fR values are printed without the quotes. Notes about date
|
||||
and time separator characters for \fBDATE\fR and \fBTIME\fR constants apply
|
||||
@@ -1709,7 +1840,12 @@ Has several uses. These are:
|
||||
.PP
|
||||
\fBINT\fR + \fBTIME\fR or \fBTIME\fR + \fBINT\fR - returns a \fBTIME\fR
|
||||
obtained by adding
|
||||
\fBINT\fR minutes to the original \fBTIME\fR.
|
||||
\fBINT\fR minutes to the original \fBTIME\fR. The result will always
|
||||
range from 00:00 through 23:59.
|
||||
.PP
|
||||
\fBTIME\fR + \fBTIME\fR treats the second \fBTIME\fR parameter as a
|
||||
duration, converting it to an integer number of minutes past midnight,
|
||||
and then performs addition as with \fBTIME\fR + \fBINT\fR.
|
||||
.PP
|
||||
\fBINT\fR + \fBDATE\fR or \fBDATE\fR + \fBINT\fR - returns a \fBDATE\fR
|
||||
obtained by adding \fBINT\fR days to the original \fBDATE\fR.
|
||||
@@ -1718,6 +1854,11 @@ obtained by adding \fBINT\fR days to the original \fBDATE\fR.
|
||||
\fBDATETIME\fR obtained by adding \fBINT\fR minutes to the original
|
||||
\fBDATETIME\fR.
|
||||
.PP
|
||||
\fBDATETIME\fR + \fBTIME\fR or \fBTIME\fR + \fBDATETIME\fR
|
||||
treats the \fBTIME\fR parameter as a
|
||||
duration, converting it to an integer number of minutes past midnight,
|
||||
and then performs addition as with \fBDATETIME\fR + \fBINT\fR.
|
||||
.PP
|
||||
\fBSTRING\fR + \fBSTRING\fR - returns a \fBSTRING\fR that is the
|
||||
concatenation of the two original
|
||||
\fBSTRING\fRs.
|
||||
@@ -1751,9 +1892,11 @@ the original \fBDATE\fR.
|
||||
earlier
|
||||
than the original \fBTIME\fR.
|
||||
.PP
|
||||
\fBDATETIME\fR - \fBINT\fR - returns a \fBDATETIME\fR that is \fBINT\fR minutes
|
||||
earlier
|
||||
than the original \fBDATETIME\fR.
|
||||
\fBDATETIME\fR - \fBINT\fR - returns a \fBDATETIME\fR that is
|
||||
\fBINT\fR minutes earlier than the original \fBDATETIME\fR.
|
||||
.PP
|
||||
\fBDATETIME\fR - \fBTIME\fR - coerces the \fBTIME\fR to an \fBINT\fR
|
||||
and then performs subtraction as above.
|
||||
.RE
|
||||
.TP
|
||||
.B <, <=, >, and >=
|
||||
@@ -1785,6 +1928,11 @@ otherwise.
|
||||
.PP
|
||||
.B NOTES
|
||||
.PP
|
||||
If the result of an addition, subtraction or multiplication operation
|
||||
would not fit in a C "int" type, \fBRemind\fR issues a "Number too
|
||||
high" error. Unlike C, integer operations will not simply give the
|
||||
wrong answer in case of overflow.
|
||||
.PP
|
||||
Operators of equal precedence are \fIalways\fR evaluated from left
|
||||
to right, except where parentheses dictate otherwise. This is important,
|
||||
because the enhanced "+" operator is not necessarily associative.
|
||||
@@ -1831,6 +1979,9 @@ variable. Examples:
|
||||
Note that variables themselves have no type. They take on the type of
|
||||
whatever you store in them.
|
||||
.PP
|
||||
Variables set with SET or on the command-line with \fB\-i\fR\fIvar\fB=\fR\fIexpr\fR
|
||||
have global scope.
|
||||
.PP
|
||||
To delete a variable, use the \fBUNSET\fR command:
|
||||
.PP
|
||||
\fBUNSET\fR \fIvar\fR [\fIvar\fR...]
|
||||
@@ -1883,6 +2034,22 @@ This variable can be set only to "/" or "-". It holds the character
|
||||
used to separate portions of a date when \fBRemind\fR prints a DATE or
|
||||
DATETIME value.
|
||||
.TP
|
||||
.B $DefaultColor
|
||||
This variable can be set to a string that has the form of three
|
||||
space-separated numbers. Each number must be an integer from 0 to
|
||||
255, or all three numbers must be -1. The default value of
|
||||
\fB$DefaultColor\fR is "-1 -1 -1", which suppresses default coloring
|
||||
of MSG-type reminders. If you set \fB$DefaultColor\fR to any other
|
||||
value, then all MSG-, MSF- and CAL-type reminders are effectively
|
||||
converted into SPECIAL COLOR reminders whose color value is specified
|
||||
by \fB$DefaultColor\fR.
|
||||
.RS
|
||||
.PP
|
||||
Unlike other system variables, the value of \fB$DefaultColor\fR is
|
||||
\fInot\fR preserved between calendar iterations; rather, it is reset
|
||||
to "-1 -1 -1" at the start of each iteration.
|
||||
.RE
|
||||
.TP
|
||||
.B $DefaultPrio
|
||||
The default priority assigned to reminders without a \fBPRIORITY\fR
|
||||
clause. You can set this as required to adjust the priorities of
|
||||
@@ -1941,9 +2108,11 @@ for years greater than 2037.
|
||||
.TP
|
||||
.B $FormWidth
|
||||
The maximum width of each line of text for formatting \fBMSF\fR-type
|
||||
reminders. The default is 72. If an \fBMSF\fR-type reminder contains
|
||||
a word too long to fit in this width, it will not be truncated - the
|
||||
width limit will be ignored.
|
||||
reminders. The default is the width of the terminal in columns, minus
|
||||
8, but clamped at a minimum of 20 and a maximum of 500. If standard
|
||||
output is not a terminal, then the default is 72.If an \fBMSF\fR-type
|
||||
reminder contains a word too long to fit in this width, it will not be
|
||||
truncated - the width limit will be ignored.
|
||||
.TP
|
||||
.B $HushMode (read-only)
|
||||
If non-zero, then the \fB\-h\fR option was supplied on the command line.
|
||||
@@ -1956,6 +2125,14 @@ then \fBONCE\fR directives will be ignored.
|
||||
.B $InfDelta (read-only)
|
||||
If non-zero, then the \fB\-t\fR option was supplied on the command line.
|
||||
.TP
|
||||
.B $IntMax (read-only)
|
||||
The largest representable \fBINT\fR. On a machine with 32-bit signed integers
|
||||
using twos-complement representation, this will be 2147483647.
|
||||
.TP
|
||||
.B $IntMin (read-only)
|
||||
The smallest representable \fBINT\fR. On a machine with 32-bit signed integers
|
||||
using twos-complement representation, this will be -2147483648.
|
||||
.TP
|
||||
.B $LatDeg, $LatMin, $LatSec
|
||||
These specify the latitude of your location. \fB$LatDeg\fR can
|
||||
range from \-90 to 90, and the others from \-59 to 59. Northern latitudes
|
||||
@@ -1972,8 +2149,13 @@ the latitude and longitude system variables.
|
||||
These specify the longitude of your location. \fB$LongDeg\fR can
|
||||
range from \-180 to 180. Western longitudes are positive; eastern
|
||||
ones are negative. Note that all three components should have the
|
||||
same sign: All positive for Western longitudes and all negative
|
||||
for Eastern longitudes.
|
||||
same sign: All positive for Western longitudes and all negative for
|
||||
Eastern longitudes. Note that for historical reasons, the sign for
|
||||
longitude is \fIdifferent\fR from the usual convention! If you find
|
||||
the longitude of your location from a search engine, you will most
|
||||
likely \fIneed to invert the sign to have it work correctly with
|
||||
Remind.\fR
|
||||
|
||||
.RS
|
||||
.PP
|
||||
The latitude and longitude information is required for the functions
|
||||
@@ -1986,6 +2168,10 @@ start of your reminder scripts.
|
||||
The maximum number of iterations for the \fBSATISFY\fR clause
|
||||
(described later.) Must be at least 10.
|
||||
.TP
|
||||
.B $MaxStringLen
|
||||
A limit on the longest string that \fBRemind\fR will allow you
|
||||
to create. The default is 65535.
|
||||
.TP
|
||||
.B $MinsFromUTC
|
||||
The number of minutes between Universal Time Coordinated and local time. If
|
||||
\fB$CalcUTC\fR is non-zero, this is calculated upon startup of \fBRemind\fR.
|
||||
@@ -2132,6 +2318,23 @@ is supplied, only the date component is used.
|
||||
Returns the time of "astronomical twilight" on the specified \fIdate\fR. If
|
||||
\fIdate\fR is omitted, defaults to \fBtoday()\fR.
|
||||
.TP
|
||||
.B ampm(tq_time [,s_am [,s_pm]])
|
||||
Returns a \fBSTRING\fR that is the result of converting \fItime\fR
|
||||
(which is either a \fBTIME\R or a \fBDATETIME\fR object) to "AM/PM"
|
||||
format. The optional arguments \fIam\fR and \fIpm\fR are the strings
|
||||
to append in the AM and PM case, respectively; they default to "AM"
|
||||
and "PM". The function obeys the system variables $DateSep,
|
||||
$TimeSep and $DateTimeSep when formatting its output. For example:
|
||||
.RS
|
||||
.PP
|
||||
.nf
|
||||
ampm(0:22) returns "12:22AM"
|
||||
ampm(17:45, "am", "pm") returns "5:45pm"
|
||||
ampm('2020-03-14@21:34') returns "2020-03-14@9:34PM"
|
||||
.fi
|
||||
.PP
|
||||
.RE
|
||||
.TP
|
||||
.B args(s_fname)
|
||||
Returns the number of arguments expected by the user-defined function
|
||||
\fIfname\fR, or \-1 if no such user-defined function exists. Note that
|
||||
@@ -2378,16 +2581,16 @@ variables are generally case-sensitive; thus, getenv("HOME") is not
|
||||
the same as getenv("home").
|
||||
.TP
|
||||
.B hebdate(i_day, s_hebmon [,idq_yrstart [,i_jahr [,i_aflag]]])
|
||||
Support for Hebrew dates - see the section "The Hebrew Calendar"
|
||||
Support for Hebrew dates - see the section "THE HEBREW CALENDAR"
|
||||
.TP
|
||||
.B hebday(dq_date)
|
||||
Support for Hebrew dates - see the section "The Hebrew Calendar"
|
||||
Support for Hebrew dates - see the section "THE HEBREW CALENDAR"
|
||||
.TP
|
||||
.B hebmon(dq_date)
|
||||
Support for Hebrew dates - see the section "The Hebrew Calendar"
|
||||
Support for Hebrew dates - see the section "THE HEBREW CALENDAR"
|
||||
.TP
|
||||
.B hebyear(dq_date)
|
||||
Support for Hebrew dates - see the section "The Hebrew Calendar"
|
||||
Support for Hebrew dates - see the section "THE HEBREW CALENDAR"
|
||||
.TP
|
||||
.B hour(tq_time)
|
||||
Returns the hour component of \fItime\fR.
|
||||
@@ -2708,6 +2911,23 @@ If \fImaxlen\fR is specified, then \fBshell()\fR returns the first
|
||||
\fImaxlen\fR is specified as a negative number, then \fIall\fR the
|
||||
output from \fIcmd\fR is returned.
|
||||
.RE
|
||||
.TP
|
||||
.B shellescape(s_str)
|
||||
Returns \fIstr\fR with all shell metacharacters such as " ", "*", etc
|
||||
escaped with a backslash. For example:
|
||||
.PP
|
||||
.nf
|
||||
SET a shellescape("a b*? c&d$e")
|
||||
.fi
|
||||
.RS
|
||||
.PP
|
||||
will set \fBa\fR to:
|
||||
.RE
|
||||
.PP
|
||||
.nf
|
||||
"a\\ b\\*\\?\\ c\\&d\\$e"
|
||||
.fi
|
||||
|
||||
.TP
|
||||
.B slide(d_start, i_amt [,s_wkday...])
|
||||
This function is the inverse of \fBnonomitted\fR. It adds \fIamt\fR
|
||||
@@ -2791,10 +3011,77 @@ date, returns the integer 0.
|
||||
Similar to trigdate(), but returns a \fBDATETIME\fR if the most recent
|
||||
triggerable \fBREM\fR command had an \fBAT\fR clause. If there was no
|
||||
\fBAT\fR clause, returns a \fBDATE\fR. If no trigger could be computed,
|
||||
returns the integer 0.
|
||||
returns the integer 0. See "MULTI-DAY EVENTS" for more information.
|
||||
.TP
|
||||
.B trigeventstart()
|
||||
Returns a \fBDATETIME\fR representing the start of the most recent
|
||||
triggerable \fBREM\fR command that had an \fBAT\fR clause. For events
|
||||
without a \fBDURATION\fR or that do not span multiple days, returns
|
||||
the same as \fBtrigdatetime()\fR. If the \fBREM\fR command did not
|
||||
have an \fBAT\fR clause, returns the integer -1 (and differs from
|
||||
\fBtrigdatetime()\fR in this respect.) See "MULTI-DAY EVENTS" for more
|
||||
information.
|
||||
.TP
|
||||
.B trigeventduration()
|
||||
Returns a \fBTIME\fR representing the duration of the most recent
|
||||
triggerable \fBREM\fR command that had an \fBAT\fR and a
|
||||
\fBDURATION\fR clause. If the event does not span multiple days,
|
||||
returns the same thing as \fBtrigduration()\fR. If the \fBREM\fR
|
||||
command lacked an \fBAT\fR or \fBDURATION\fR clause, returns -1. See
|
||||
"MULTI-DAY EVENTS" for more information.
|
||||
.TP
|
||||
.B trigback()
|
||||
Returns the "back" amount of the last \fBREM\fR or \fBIFTRIG\fR command.
|
||||
Returns a positive integer N if the "back" is of the form -N, or a negative
|
||||
integer if it is of the form --N. If there is no "back", then returns 0.
|
||||
.TP
|
||||
.B trigdelta()
|
||||
Returns the "delta" amount of the last \fBREM\fR or \fBIFTRIG\fR command.
|
||||
Returns a positive integer N if the "delta" is of the form +N, or a negative
|
||||
integer if it is of the form ++N. If there is no "delta", then returns 0.
|
||||
.TP
|
||||
.B trigtimedelta()
|
||||
Similar to \fBtrigdelta()\fR, but returns the delta used in the
|
||||
\fBAT\fR clause of a timed reminder.
|
||||
.TP
|
||||
.B trigrep()
|
||||
Returns the "repeat" amount of the last \fBREM\fR or \fBIFTRIG\fR
|
||||
command. Returns a positive integer N if the "repeat" is of the form
|
||||
*N. If there is no "repeat", then returns 0.
|
||||
.TP
|
||||
.B trigtimerep()
|
||||
Similar to \fBtrigrep()\fR, but returns the repeat used in the \fBAT\fR clause
|
||||
of a timed reminder.
|
||||
.TP
|
||||
.B trigduration()
|
||||
Returns (as a TIME type) the \fBDURATION\fR parameter of a timed
|
||||
reminder. If there is no \fBDURATION\fR parameter, returns the
|
||||
integer -1. See "MULTI-DAY EVENTS" for more information.
|
||||
.TP
|
||||
.B trigpriority()
|
||||
Returns the \fBPRIORITY\fR of the last \fBREM\fR or \fBIFTRIG\fR command.
|
||||
.TP
|
||||
.B triguntil()
|
||||
Returns (as a \fBDATE\fR type) the \fBUNTIL\fR parameter of the last
|
||||
\fBREM\fR or \fBIFTRIG\fR command. If there was no \fBUNTIL\fR
|
||||
parameter, returns the integer -1. If there is a \fBTHROUGH\fR parameter,
|
||||
that will be returned by \fBtriguntil()\fR since "THROUGH yyyy-mm-dd" is simply
|
||||
syntactic sugar for "*1 UNTIL yyyy-mm-dd".
|
||||
.TP
|
||||
.B trigscanfrom()
|
||||
Returns (as a \fBDATE\fR type) the \fBSCANFROM\fR parameter of the last \fBREM\fR
|
||||
or \fBIFTRIG\fR command. If there was no \fBSCANFROM\fR parameter, returns
|
||||
the integer -1. Note that \fBFROM\fR and \fBSCANFROM\fR interact; a reminder that
|
||||
has a "FROM yyyy-mm-dd" parameter will act as if it has a \fBSCANFROM\fR parameter
|
||||
whose value is the maximum of "yyyy-mm-dd" and today.
|
||||
.TP
|
||||
.B trigfrom()
|
||||
Returns (as a \fBDATE\fR type) the \fBFROM\fR parameter of the last \fBREM\fR or
|
||||
\fBIFTRIG\fR command. If there was no \fBFROM\fR parameter, returns the integer -1.
|
||||
|
||||
.TP
|
||||
.B trigger(d_date [,t_time [,i_utcflag]]) \fRor\fB trigger(q_datetime [,i_utcflag])
|
||||
Returns a string suitable for use in a \fBREM\fR command or a SCANFROM
|
||||
Returns a string suitable for use in a \fBREM\fR command or a \fBSCANFROM\fR
|
||||
or UNTIL clause, allowing you to calculate trigger dates in advance.
|
||||
Note that in earlier versions of \fBRemind\fR, \fBtrigger\fR was
|
||||
required to convert a date into something the \fBREM\fR command could
|
||||
@@ -2827,9 +3114,11 @@ The value for your time zone may differ.
|
||||
.RE
|
||||
.TP
|
||||
.B trigtime()
|
||||
Returns the time of the last \fBREM\fR command with an \fBAT\fR clause.
|
||||
If the last \fBREM\fR did not have an \fBAT\fR clause, returns the integer
|
||||
0.
|
||||
Returns the time of the last \fBREM\fR command with an \fBAT\fR
|
||||
clause. If the last \fBREM\fR did not have an \fBAT\fR clause,
|
||||
returns the integer 0. If a \fBREM\fR command has an \fBAT\fR clause
|
||||
with a \fBDURATION\fR, then you can compute the end time as
|
||||
\fBtrigtime() + trigduration()\fR.
|
||||
.TP
|
||||
.B trigvalid()
|
||||
Returns 1 if the value returned by \fBtrigdate()\fR is valid for the most
|
||||
@@ -2909,6 +3198,98 @@ Returns a number from 0 to 6 representing the day-of-week of the specified
|
||||
.TP
|
||||
.B year(dq_date)
|
||||
Returns a \fBINT\fR that is the year component of \fIdate\fR.
|
||||
|
||||
.SH MULTI-DAY EVENTS
|
||||
|
||||
If you specify a start time with \fBAT\fR and a duration with
|
||||
\fBDURATION\fR, you can create events that span multiple days.
|
||||
Consider these two REM statements:
|
||||
.PP
|
||||
.nf
|
||||
REM 1991-02-13 AT 16:00 DURATION 72:00 MSG 72-hour event
|
||||
REM 1991-02-13 THROUGH 1991-02-16 AT 16:00 MSG Four events
|
||||
.fi
|
||||
.PP
|
||||
The first statement creates a \fIsingle\fR event that starts on
|
||||
13 February 1991 at 16:00 and runs through 16 February 1991 at 16:00
|
||||
.PP
|
||||
The second statements creates \fIfour separate\fR events that start
|
||||
at 16:00 on 13, 14, 15 and 16 February 1991 and have indefinite duration.
|
||||
.PP
|
||||
Remind handles multi-day events specially. These are the rules:
|
||||
.PP
|
||||
On the \fIfirst\fR day of a multi-day event, \fBtrigdatetime()\fR will
|
||||
return the starting date and time of the event, and \fBtrigduration()\fR
|
||||
will return the original DURATION.
|
||||
.PP
|
||||
On each \fIsubsequent\fR day of a multi-day event, \fBtrigdatetime()\fR
|
||||
will return midnight on the day in question, and \fBtrigduration()\fR
|
||||
will return the \fIremaining\fR duration. Consider this example:
|
||||
.PP
|
||||
.nf
|
||||
#!/bin/sh
|
||||
remind - 12 feb 1991 '*6' <<'EOF'
|
||||
BANNER %
|
||||
REM 1991-02-13 AT 16:00 DURATION 72:00 SATISFY 1
|
||||
set a trigdatetime()
|
||||
set b trigduration()
|
||||
set c trigeventstart()
|
||||
set d trigeventduration()
|
||||
MSG now=[today()] dt=[a] dur=[b] estart=[c] edur=[d]%
|
||||
EOF
|
||||
.fi
|
||||
.PP
|
||||
The output is:
|
||||
.PP
|
||||
.nf
|
||||
now=1991-02-12 dt=1991-02-13@16:00 dur=72:00 estart=1991-02-13@16:00 edur=72:00
|
||||
now=1991-02-13 dt=1991-02-13@16:00 dur=72:00 estart=1991-02-13@16:00 edur=72:00
|
||||
now=1991-02-14 dt=1991-02-14@00:00 dur=64:00 estart=1991-02-13@16:00 edur=72:00
|
||||
now=1991-02-15 dt=1991-02-15@00:00 dur=40:00 estart=1991-02-13@16:00 edur=72:00
|
||||
now=1991-02-16 dt=1991-02-16@00:00 dur=16:00 estart=1991-02-13@16:00 edur=72:00
|
||||
now=1991-02-17 dt=1991-02-13@16:00 dur=72:00 estart=-1 edur=-1
|
||||
.fi
|
||||
.PP
|
||||
As you see, the \fBtrigdatetime()\fR and \fBtrigduration()\fR functions
|
||||
return the start time and duration of the \fIremaining\fR portion of
|
||||
a multi-day event, whereas \fBtrigeventstart\fR and \fBtrigeventduration\fR
|
||||
always return the original start and duration of the multi-day event. Note also
|
||||
that the return value for expired reminders is not reliable; the fact
|
||||
that \fBtrigeventstart\fR and \fBtrigeventduration\fR return -1 in that case
|
||||
is an implementation artifact.
|
||||
.PP
|
||||
.B SELF-OVERLAPPING EVENTS
|
||||
.PP
|
||||
A multi-day event has the possibility of "overlapping itself". When this
|
||||
happens, \fBRemind\fR prefers the \fIlater\fR event (only one copy of
|
||||
an event is ever triggered for a given date.) Consider this example:
|
||||
.PP
|
||||
.nf
|
||||
#!/bin/sh
|
||||
remind - '*5' 10 Feb 1991 <<'EOF'
|
||||
|
||||
BANNER %
|
||||
REM MON at 0:00 DURATION 192:0 MSG [today()] [trigeventstart()] [trigduration()]%
|
||||
|
||||
EOF
|
||||
.fi
|
||||
.PP
|
||||
The output is:
|
||||
.PP
|
||||
.nf
|
||||
1991-02-10 1991-02-04@00:00 48:00
|
||||
1991-02-11 1991-02-11@00:00 192:00
|
||||
1991-02-12 1991-02-11@00:00 168:00
|
||||
1991-02-13 1991-02-11@00:00 144:00
|
||||
1991-02-14 1991-02-11@00:00 120:00
|
||||
.fi
|
||||
.PP
|
||||
Although the event from 1991-02-04 still has 24 hours left on 1991-02-11,
|
||||
the fresh occurrence on 1991-02-11 takes precedences and is the one that
|
||||
is triggered.
|
||||
.PP
|
||||
I do not recommend constructing self-overlapping multi-day events.
|
||||
.PP
|
||||
.SH EXPRESSION PASTING
|
||||
.PP
|
||||
An extremely powerful feature of \fBRemind\fR is its macro capability,
|
||||
@@ -2984,7 +3365,7 @@ three commands are equivalent:
|
||||
o
|
||||
You cannot use expression-pasting to determine the type (\fBMSG\fR,
|
||||
\fBCAL\fR, etc.) of a \fBREM\fR command. You can paste expressions
|
||||
before and after the \fBMSG\fR, etc keywords, but cannot do something like
|
||||
before and after the \fBMSG\fR, etc. keywords, but cannot do something like
|
||||
this:
|
||||
.PP
|
||||
.nf
|
||||
@@ -3080,8 +3461,10 @@ to true if a corresponding \fBREM\fR command would trigger. Examples:
|
||||
.PP
|
||||
Note that the \fBIFTRIG\fR command computes a trigger date, which can
|
||||
be retrieved with the \fBtrigdate()\fR function. You can use all of
|
||||
the normal trigger components, such as \fBUNTIL\fR, \fIdelta\fR, etc in the
|
||||
\fBIFTRIG\fR command.
|
||||
the normal trigger components, such as \fBUNTIL\fR, \fIdelta\fR, etc. in the
|
||||
\fBIFTRIG\fR command. However, you cannot use a type specifier such
|
||||
as \fBCAL\fR, \fBMSG\fR or \fBSATISFY\fR; attempting to do so
|
||||
yields a parse error.
|
||||
.PP
|
||||
.SH USER-DEFINED FUNCTIONS
|
||||
.PP
|
||||
@@ -3279,12 +3662,12 @@ ends. Otherwise, \fBRemind\fR computes the next trigger date, and re-tests
|
||||
or non-null, or until the iteration limit specified with the \fB\-x\fR
|
||||
command-line option is reached.
|
||||
.PP
|
||||
If \fIexpr\fR is not satisfied, then \fBtrigvalid()\fR is set to 0.
|
||||
Otherwise, \fBtrigvalid()\fR is set to 1. In any event, no error message
|
||||
is issued.
|
||||
If \fIexpr\fR is not satisfied, then \fBtrigvalid()\fR is set to 0 and
|
||||
the error message "Can't compute trigger" is issued. Otherwise,
|
||||
\fBtrigvalid()\fR is set to 1.
|
||||
.PP
|
||||
This is really useful only if \fIexpr\fR involves a call to the
|
||||
\fBtrigdate()\fR function; otherwise, \fIexpr\fR will not change as
|
||||
\fBtrigdate()\fR or related functions; otherwise, \fIexpr\fR will not change as
|
||||
\fBRemind\fR iterates.
|
||||
.PP
|
||||
An example of the usefulness of \fBSATISFY\fR: Suppose you wish to
|
||||
@@ -3307,6 +3690,12 @@ more complicated sequence:
|
||||
ENDIF
|
||||
.fi
|
||||
.PP
|
||||
You can write the REM statement a little more concisely:
|
||||
.PP
|
||||
.nf
|
||||
REM 13 SATISFY $Tw == 5
|
||||
.fi
|
||||
.PP
|
||||
Let's see how this works. The \fBSATISFY\fR clause iterates through
|
||||
all the 13ths of successive months, until a trigger date is found whose
|
||||
day-of-week is Friday (== 5). If a valid date was found, we use the
|
||||
@@ -3347,7 +3736,7 @@ However, when \fBRemind\fR gets around to calculating the trigger
|
||||
for Tuesday, 8 September, 1992, the \fBOMIT\fR command will now be
|
||||
omitting Labour Day for 1993, and the "Mon AFTER" command
|
||||
will not be triggered. (But see the description of \fBSCANFROM\fR
|
||||
in the section "Details about Trigger Computation.")
|
||||
in the section "DETAILS ABOUT TRIGGER COMPUTATION.")
|
||||
.PP
|
||||
It is probably best to stay away from computing \fBOMIT\fR
|
||||
trigger dates unless you keep these pitfalls in mind.
|
||||
@@ -3361,7 +3750,7 @@ follows:
|
||||
.fi
|
||||
.PP
|
||||
Note that for this case only, the \fIexpr\fR after \fBSATISFY\fR
|
||||
\fImust\fR be enclosed in braces. It must come after all the other
|
||||
\fImust\fR be enclosed in square brackets. It must come after all the other
|
||||
components of the trigger, and immediately before the \fBMSG\fR,
|
||||
\fBRUN\fR, etc. keyword. If \fIexpr\fR cannot be satisfied, then
|
||||
the reminder is not triggered.
|
||||
@@ -3369,22 +3758,49 @@ the reminder is not triggered.
|
||||
Thus, the "Friday the 13th" example can be expressed more compactly as:
|
||||
.PP
|
||||
.nf
|
||||
REM 13 +2 SATISFY [wkdaynum(trigdate()) == 5] \\
|
||||
MSG Friday the 13th is %b.
|
||||
REM 13 +2 SATISFY [$Tw == 5] MSG Friday the 13th is %b.
|
||||
.fi
|
||||
.PP
|
||||
And you can trigger a reminder on Mondays, Wednesdays and Thursdays
|
||||
occurring on odd-numbered days of the month with the following:
|
||||
.PP
|
||||
.nf
|
||||
REM Mon Wed Thu SATISFY [day(trigdate())%2] \\
|
||||
MSG Here it is!!!
|
||||
REM Mon Wed Thu SATISFY [$Td %2 ] MSG Here it is!!!
|
||||
.fi
|
||||
.PP
|
||||
Note that \fBSATISFY\fR and \fBOMITFUNC\fR can often be used to solve the
|
||||
same problem, though in different ways. Sometimes a \fBSATISFY\fR is cleaner
|
||||
and sometimes an \fBOMITFUNC\fR; experiment and use whichever seems clearer.
|
||||
.PP
|
||||
.SH POSSIBLY-UNCOMPUTABLE TRIGGERS
|
||||
.PP
|
||||
Occasionally, you may wish to suppress the "Can't compute trigger" warnings
|
||||
for reminders for which a trigger date cannot be computed. For example,
|
||||
the following reminder is triggered on a Monday that is not a holiday
|
||||
if the following Tuesday is a holiday:
|
||||
.PP
|
||||
.nf
|
||||
REM Mon SKIP SATISFY [isomitted($T+1)] MSG Work between holidays
|
||||
.fi
|
||||
.PP
|
||||
However, if there are no Mondays after today's date that satisfy the
|
||||
condition, Remind will print the "Can't compute trigger" error. To
|
||||
suppress this, use the \fBMAYBE-UNCOMPUTABLE\fR keyword:
|
||||
.PP
|
||||
.nf
|
||||
REM MAYBE-UNCOMPUTABLE Mon SKIP SATISFY [isomitted($T+1)] MSG Work between holidays
|
||||
.fi
|
||||
.PP
|
||||
It's almost never appropriate to use \fBMAYBE-UNCOMPUTABLE\fR, but it is
|
||||
provided for those rare occasions when it makes sense. If you use
|
||||
\fBMAYBE-UNCOMPUTABLE\fR inside the \fBevaltrig()\fR function, then
|
||||
untriggerable triggers return -1. For example:
|
||||
.PP
|
||||
.nf
|
||||
SET a evaltrig("MAYBE-UNCOMPUTABLE Mon SKIP OMIT Mon")
|
||||
.fi
|
||||
.PP
|
||||
will set a to -1.
|
||||
.SH DEBUGGING REMINDER SCRIPTS
|
||||
.PP
|
||||
Although the command-line \fB\-d\fR option is useful for debugging, it
|
||||
@@ -3547,7 +3963,7 @@ iterations. On the next iteration, the commands are skipped, since
|
||||
initialized has remained defined. Thus, time-consuming operations that
|
||||
do not depend on the value of \fBtoday()\fR are done only once.
|
||||
.PP
|
||||
System variables (those whose names start with '$') are automatically
|
||||
Most system variables (those whose names start with '$') are automatically
|
||||
preserved between calendar iterations.
|
||||
.PP
|
||||
Note that for efficiency, \fBRemind\fR caches the reminder script
|
||||
@@ -4136,7 +4552,7 @@ They are used only when piping data from a \fBremind \-p\fR line.
|
||||
equivalent of MSG in \fBremind's\fR normal mode of operation.)
|
||||
.PP
|
||||
The various \fBSPECIAL\fRs recognized are particular for each
|
||||
backend; however, there are three \fBSPECIAL\fRs that all backends
|
||||
backend; however, there are four \fBSPECIAL\fRs that all backends
|
||||
should attempt to support. They are currently supported by
|
||||
\fBRem2PS\fR, \fBtkremind\fR and \fBrem2html\fR.
|
||||
.PP
|
||||
@@ -4199,9 +4615,12 @@ The rest of the line is the text to put in the calendar.
|
||||
.PP
|
||||
The COLOR special is "doubly special", because in its normal operating
|
||||
mode, \fBremind\fR treats a COLOR special just like a MSG-type reminder.
|
||||
Also, if you invoke \fBRemind\fR with \fB\-cc\fR..., then it approximates
|
||||
Also, if you invoke \fBRemind\fR with \fB\-@\fR[\fIn\fR], then it approximates
|
||||
SPECIAL COLOR reminders on your terminal.
|
||||
.PP
|
||||
See also the documentation of the \fB$DefaultColor\fR system variable
|
||||
in the section "SYSTEM VARIABLES".
|
||||
.PP
|
||||
The \fBWEEK\fR special lets you place annotations such as the week
|
||||
number in the calendar. For example, this would number each Monday
|
||||
with the ISO 8601 week number. The week number is shown like this:
|
||||
@@ -4354,6 +4773,18 @@ from 7 days before the current date. This ensures that Labour Day for
|
||||
the current year will continue to be triggered until 7 days after it has
|
||||
occurred. This allows you to safely use the AFTER keyword as shown.
|
||||
.PP
|
||||
As a special case, you can simply use a negative number after SCANFROM;
|
||||
a negative numbner \-N is interpreted as N days before today. Thus,
|
||||
the previous example could also be written like this:
|
||||
.PP
|
||||
.nf
|
||||
# This form of SCANFROM requires Remind 03.01.17 or later.
|
||||
REM Mon 1 Sept SCANFROM \-7 SATISFY 1
|
||||
OMIT [trigdate()]
|
||||
|
||||
REM Mon AFTER MSG Hello
|
||||
.fi
|
||||
.PP
|
||||
In general, use \fBSCANFROM\fR as shown for safe movable \fBOMITs\fR. The
|
||||
amount you should scan back by (7 days in the example above) depends on
|
||||
the number of possible consecutive \fBOMITted\fR days that may occur, and
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -210,7 +219,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 +241,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 +386,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::Any 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::Any;
|
||||
|
||||
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 = JSON::Any->jsonToObj($_);
|
||||
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>");
|
||||
@@ -374,7 +421,7 @@ sub output_calendar
|
||||
|
||||
# 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,23 +445,23 @@ 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";
|
||||
}
|
||||
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"';
|
||||
@@ -431,7 +478,7 @@ sub output_calendar
|
||||
$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";
|
||||
@@ -444,13 +491,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 +509,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";
|
||||
}
|
||||
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");
|
||||
}
|
||||
@@ -489,7 +536,7 @@ sub draw_day_cell
|
||||
$week = ' ' . $weeks->{$day};
|
||||
}
|
||||
my $class;
|
||||
if ($Options{'nostyle'}) {
|
||||
if ($Options{nostyle}) {
|
||||
$class = $classes->[$day] || '';
|
||||
} else {
|
||||
$class = $classes->[$day] || "rem-cell";
|
||||
@@ -515,33 +562,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 +624,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 +655,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
|
||||
1242
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" -----------------
|
||||
|
||||
|
||||
832
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
|
||||
|
||||
|
||||
@@ -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 */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -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 */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -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
|
||||
|
||||
203
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,12 +127,15 @@ 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;
|
||||
}
|
||||
@@ -200,10 +213,15 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
trig->once = NO_ONCE;
|
||||
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;
|
||||
@@ -245,6 +263,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 +279,10 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
trig->m = tok.val;
|
||||
break;
|
||||
|
||||
case T_MaybeUncomputable:
|
||||
trig->maybe_uncomputable = 1;
|
||||
break;
|
||||
|
||||
case T_Skip:
|
||||
DBufFree(&buf);
|
||||
if (trig->skip != NO_SKIP) return E_SKIP_ERR;
|
||||
@@ -276,6 +299,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:
|
||||
@@ -372,6 +396,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 +424,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;
|
||||
@@ -468,6 +507,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 +706,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 +742,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 +773,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 +798,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 +806,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 +890,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 +917,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 +931,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 +942,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 +956,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 +994,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 +1098,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 +1135,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 +1226,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 +1256,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:
|
||||
|
||||
@@ -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 */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -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 */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
@@ -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 && (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);
|
||||
|
||||
287
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");
|
||||
@@ -544,6 +576,64 @@ int DoInclude(ParsePtr p)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* 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;
|
||||
}
|
||||
DBufFree(&buf);
|
||||
NumIfs = 0;
|
||||
IfFlags = 0;
|
||||
return OK;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GLOB
|
||||
static int SetupGlobChain(char const *dirname, IncludeStruct *i)
|
||||
{
|
||||
@@ -664,6 +754,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 +1039,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 +1078,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;
|
||||
|
||||
462
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,109 @@
|
||||
#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 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 +208,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 },
|
||||
@@ -252,6 +268,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 +277,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 },
|
||||
@@ -839,12 +868,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 +892,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. */
|
||||
@@ -973,6 +1074,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 +1260,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;
|
||||
@@ -1880,7 +2117,7 @@ static int SunStuff(int rise, double cosz, int jul)
|
||||
+ (double) LongSec / 3600.0;
|
||||
|
||||
latitude = DEGRAD * ((double) LatDeg + (double) LatMin / 60.0
|
||||
+ (double) LatSec / 3600.0);
|
||||
+ (double) LatSec / 3600.0);
|
||||
|
||||
|
||||
FromJulian(jul, &year, &mon, &day);
|
||||
@@ -1919,10 +2156,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 +2177,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 +2190,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) {
|
||||
@@ -2422,16 +2659,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 +2689,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 +2721,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 +2794,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 +2935,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,7 +55,7 @@ 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);
|
||||
@@ -73,6 +82,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 +97,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 +112,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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
121
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,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "protos.h"
|
||||
@@ -38,6 +39,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
|
||||
@@ -87,6 +89,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 +115,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,7 +138,7 @@ void InitRemind(int argc, char const *argv[])
|
||||
int InvokedAsRem = 0;
|
||||
char const *s;
|
||||
int weeks;
|
||||
|
||||
int x;
|
||||
int jul;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@@ -146,6 +149,17 @@ void InitRemind(int argc, char const *argv[])
|
||||
|
||||
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 +173,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,7 +184,7 @@ 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);
|
||||
@@ -190,6 +204,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 +218,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':
|
||||
@@ -295,8 +335,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 +444,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 +474,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 +544,7 @@ void InitRemind(int argc, char const *argv[])
|
||||
if (!InvokedAsRem) {
|
||||
if (i >= argc) {
|
||||
Usage();
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
InitialFile = argv[i++];
|
||||
} else {
|
||||
@@ -599,7 +658,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 +666,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 +691,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 */
|
||||
/***************************************************************/
|
||||
@@ -660,23 +720,23 @@ static void ChgUser(char const *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);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!myuid && setuid(pwent->pw_uid)) {
|
||||
fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid);
|
||||
exit(1);
|
||||
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 +744,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 +753,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);
|
||||
@@ -787,6 +847,25 @@ static void InitializeVar(char const *str)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
AddTrustedUser(char const *username)
|
||||
{
|
||||
struct passwd *pwent;
|
||||
if (NumTrustedUsers >= MAX_TRUSTED_USERS) {
|
||||
fprintf(stderr, "Too many trusted users (%d max)\n",
|
||||
MAX_TRUSTED_USERS);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pwent = getpwnam(username);
|
||||
if (!pwent) {
|
||||
fprintf(ErrFp, ErrMsg[M_BAD_USER], username);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
TrustedUsers[NumTrustedUsers] = pwent->pw_uid;
|
||||
NumTrustedUsers++;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) || defined(__CYGWIN__)
|
||||
static char const pmsg1[] = {
|
||||
0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20,
|
||||
|
||||
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 */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
115
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 */
|
||||
@@ -231,6 +243,15 @@ static void DoReminders(void)
|
||||
r=DoInclude(&p);
|
||||
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;
|
||||
case T_Flush: r=DoFlush(&p); break;
|
||||
case T_Set: r=DoSet(&p); break;
|
||||
@@ -713,7 +734,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 +815,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 +1330,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 +1350,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 */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
|
||||
@@ -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 */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -453,6 +453,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;
|
||||
|
||||
30
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,6 +37,7 @@ 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);
|
||||
@@ -41,6 +45,7 @@ int CopyValue (Value *dest, const Value *src);
|
||||
int ReadLine (void);
|
||||
int OpenFile (char const *fname);
|
||||
int DoInclude (ParsePtr p);
|
||||
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,19 @@ 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);
|
||||
|
||||
117
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;
|
||||
|
||||
@@ -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;
|
||||
@@ -179,7 +182,7 @@ 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 */
|
||||
@@ -243,9 +246,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 +448,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 */
|
||||
@@ -508,28 +573,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;
|
||||
}
|
||||
|
||||
|
||||
47
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 */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
|
||||
@@ -62,11 +62,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 +173,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 +234,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 +263,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 +291,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 +302,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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
37
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,12 @@ 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 */
|
||||
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 +92,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,7 +150,7 @@ 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_IncludeCmd, T_If, T_Else, T_EndIf,
|
||||
T_IfTrig, T_ErrMsg,
|
||||
T_Set, T_UnSet, T_Fset, T_Omit, T_Banner, T_Exit,
|
||||
T_WkDay,
|
||||
@@ -167,7 +172,8 @@ enum TokTypes
|
||||
T_Duration,
|
||||
T_LongTime,
|
||||
T_OmitFunc,
|
||||
T_Through
|
||||
T_Through,
|
||||
T_MaybeUncomputable
|
||||
};
|
||||
|
||||
/* The structure of a token */
|
||||
@@ -212,3 +218,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;
|
||||
}
|
||||
|
||||
78
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,7 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "types.h"
|
||||
#include "expr.h"
|
||||
#include "globals.h"
|
||||
@@ -31,12 +32,16 @@
|
||||
#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 int trig_date_func(int do_set, Value *val)
|
||||
{
|
||||
UNUSED(do_set);
|
||||
val->type = DATE_TYPE;
|
||||
if (!LastTrigValid) {
|
||||
val->v.val = 0;
|
||||
@@ -48,6 +53,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 +68,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 +83,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 +98,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 +110,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 +118,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 +128,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 +138,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 +147,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 +172,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 +413,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 +479,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 +517,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,6 +651,7 @@ 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},
|
||||
{"DeltaOffset", 0, INT_TYPE, &DeltaOffset, 0, 0 },
|
||||
{"DontFork", 0, INT_TYPE, &DontFork, 0, 0 },
|
||||
@@ -603,10 +661,12 @@ 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 },
|
||||
{"IntMax", 0, INT_TYPE, &IntMax, 0, 0 },
|
||||
{"IntMin", 0, INT_TYPE, &IntMin, 0, 0 },
|
||||
{"LatDeg", 1, INT_TYPE, &LatDeg, -90, 90 },
|
||||
{"LatMin", 1, INT_TYPE, &LatMin, -59, 59 },
|
||||
{"LatSec", 1, INT_TYPE, &LatSec, -59, 59 },
|
||||
@@ -748,7 +808,7 @@ static SysVar *FindSysVar(char const *name)
|
||||
/***************************************************************/
|
||||
void DumpSysVarByName(char const *name)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
SysVar *v;
|
||||
|
||||
if (!name || !*name) {
|
||||
@@ -781,7 +841,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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
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
|
||||
227
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,7 +117,214 @@ 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
|
||||
cmp -s ../tests/test.out ../tests/test.cmp
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "Remind: Acceptance test PASSED"
|
||||
|
||||
4181
tests/test.cmp
282
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)
|
||||
@@ -306,6 +344,77 @@ 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 $aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
OMIT 2010-09-03 THROUGH 2010-09-15
|
||||
@@ -313,7 +422,180 @@ 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)
|
||||
|
||||
# Shellescape
|
||||
set a shellescape(" !\"#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")
|
||||
|
||||
msg [a]
|
||||
|
||||
# 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 |
@@ -49,6 +49,10 @@ div.rem-daynumber {
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
p.rem-entry {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
div.rem-moon {
|
||||
float: left;
|
||||
text-align: left;
|
||||
@@ -66,4 +70,4 @@ td.rem-sc-empty-cell, td.rem-sc-cell {
|
||||
|
||||
caption.rem-sc-caption {
|
||||
font-size: 12pt;
|
||||
}
|
||||
}
|
||||
|
||||