Compare commits

...

162 Commits

Author SHA1 Message Date
Dianne Skoll
d5e38ee3b4 Fix typo in test.rem.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-10-18 11:26:41 -04:00
Dianne Skoll
11594aee2d Rename configure.in to configure.ac to avoid autoreconf warning. 2024-10-18 11:21:41 -04:00
Dianne Skoll
711f0b6c69 Rename contrib/ical2rem-0.7.1 to contrib/ical2rem-0.8
All checks were successful
Remind unit tests / tests (push) Successful in 29s
2024-10-17 15:29:15 -04:00
Dianne Skoll
87a8b9811d Update to upstream 0.8. 2024-10-17 15:28:42 -04:00
Dianne Skoll
689b1d0e13 Rebuild src/config.h.in with autoreconf
All checks were successful
Remind unit tests / tests (push) Successful in 30s
2024-10-17 13:19:53 -04:00
Dianne Skoll
a8650e888f Add comment to AC_DEFINE_UNQUOTED 2024-10-17 13:17:44 -04:00
Dianne Skoll
dea2aed628 Update release notes.
All checks were successful
Remind unit tests / tests (push) Successful in 32s
2024-10-16 13:23:04 -04:00
Dianne Skoll
5618b928e0 Add National Day for Truth and Reconciliation 2024-10-16 13:13:01 -04:00
Dianne Skoll
91187c4c60 Include Remind version in Options dialog. 2024-10-16 10:00:04 -04:00
Dianne Skoll
636ae8f21a Include TkRemind version in title bar.
All checks were successful
Remind unit tests / tests (push) Successful in 30s
2024-10-15 14:59:09 -04:00
Dianne Skoll
405398b226 Use % instead of @ for substitution to avoid possible autoconf conflicts. 2024-10-15 14:56:25 -04:00
Dianne Skoll
0df3a903b1 Remove useless comment. 2024-10-15 14:54:25 -04:00
Dianne Skoll
eac07d212c Bump version to 05.00.07
All checks were successful
Remind unit tests / tests (push) Successful in 29s
2024-10-15 11:55:40 -04:00
Dianne Skoll
96da3a6596 Add note about safety of eval remind --print-config-cmd 2024-10-15 11:22:42 -04:00
Dianne Skoll
94ef20d702 Make sure string is well-formed C 2024-10-15 11:18:16 -04:00
Dianne Skoll
c9c309e436 Document how to use --print-config-cmd 2024-10-15 10:36:55 -04:00
Dianne Skoll
52c973509b Add --print-config-cmd long option. 2024-10-15 10:32:01 -04:00
Dianne Skoll
c192c580da Fix permissions.
All checks were successful
Remind unit tests / tests (push) Successful in 27s
2024-10-14 08:41:00 -04:00
Dianne Skoll
235e5ec1c7 Make ./configure generate tkremind from tkremind.in. 2024-10-14 08:40:05 -04:00
Dianne Skoll
3d30173f9a Print version info in options window. 2024-10-14 08:36:44 -04:00
Dianne Skoll
8b0bbc9fb7 Remove obsolete comment.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-10-13 10:35:33 -04:00
Dianne Skoll
c57d2fd52a Tweak "astro" example. 2024-10-13 10:33:38 -04:00
Dianne Skoll
2970591187 Add a couple more examples.
All checks were successful
Remind unit tests / tests (push) Successful in 31s
2024-10-12 12:47:17 -04:00
Dianne Skoll
23ec559ddf Fix typo 2024-10-12 12:47:04 -04:00
Dianne Skoll
302bc5a5de Make hash table sizes prime numbers instead of powers of two. 2024-10-12 10:24:22 -04:00
Dianne Skoll
950c0b3747 Use HashPJW for hasing user-defined function names and variable names.
All checks were successful
Remind unit tests / tests (push) Successful in 26s
2024-10-12 10:17:50 -04:00
Dianne Skoll
ad382fea25 Print hash-table statistics with "-ds" debugging.
Some checks failed
Remind unit tests / tests (push) Failing after 29s
2024-10-11 16:34:11 -04:00
Dianne Skoll
a66e855ca7 Remove dead code; remove unnecessary catch { ... } 2024-10-11 16:00:47 -04:00
Dianne Skoll
a1b814d6b1 Allow "hostname" to fail.
All checks were successful
Remind unit tests / tests (push) Successful in 27s
2024-10-10 11:43:26 -04:00
Dianne Skoll
62030719bb Set app name to tkremind.
All checks were successful
Remind unit tests / tests (push) Successful in 30s
2024-10-02 11:08:17 -04:00
Dianne Skoll
985816dc32 Document that system notifications work if notify-send is installed. 2024-10-02 11:05:38 -04:00
Dianne Skoll
a131a53132 Fix typos. 2024-10-02 11:05:27 -04:00
Dianne Skoll
c5e723b6ac Use "notify-send" if Tk < 9.0 2024-10-02 11:00:28 -04:00
Dianne Skoll
3fe2b88e65 Document "Use system notifications when issuing a reminder" 2024-10-02 09:26:11 -04:00
Dianne Skoll
54603090ee Use "tk sysnotify" if we have it.
All checks were successful
Remind unit tests / tests (push) Successful in 39s
2024-10-01 11:02:32 -04:00
Dianne Skoll
2514b3681f Make tkremind work with Tcl/Tk 9.0.
All checks were successful
Remind unit tests / tests (push) Successful in 35s
2024-09-30 11:40:03 -04:00
Dianne Skoll
0b7b101814 Accept Tk >= 8.5 including 9.0 2024-09-30 11:26:30 -04:00
Dianne Skoll
3ac1c622fd Update ical2rem to upstream 0.7.1.
All checks were successful
Remind unit tests / tests (push) Successful in 30s
2024-09-19 16:14:23 -04:00
Dianne Skoll
7878f6623c Fix typo
All checks were successful
Remind unit tests / tests (push) Successful in 35s
2024-09-16 14:48:57 -04:00
Dianne Skoll
00ad38e5fe Put N_ERROR at the end. 2024-09-16 14:47:09 -04:00
Dianne Skoll
10ae0b0077 Add DEBUG +s test. 2024-09-16 14:43:37 -04:00
Dianne Skoll
e032f3315d Mark a freshly-allocated node of type N_ERROR rather than N_FREE. 2024-09-16 14:41:30 -04:00
Dianne Skoll
a38fd95a90 Add guard against double-free of expr_node. 2024-09-16 14:39:26 -04:00
Dianne Skoll
9f7609b2c6 Fix typo. Sigh. 2024-09-16 09:48:50 -04:00
Dianne Skoll
a6c166ae0c Update release notes.
All checks were successful
Remind unit tests / tests (push) Successful in 36s
2024-09-16 09:41:12 -04:00
Dianne Skoll
e9c89b770f Bump version to 05.00.06 2024-09-16 08:29:58 -04:00
Dianne Skoll
df6298bd63 Add test for $SuppressImplicitWarnings
All checks were successful
Remind unit tests / tests (push) Successful in 1m15s
2024-09-15 16:59:46 -04:00
Dianne Skoll
739d285e36 Indent system variable dump better.
All checks were successful
Remind unit tests / tests (push) Successful in 48s
2024-09-15 10:21:22 -04:00
Dianne Skoll
ee1c931932 Add $SuppressImplicitWarnings system variable.
This suppresses warnings about missing REM or MSG tokens.
2024-09-15 09:39:15 -04:00
Dianne Skoll
0806b6738f Add test for time constants of the form '12:34'
All checks were successful
Remind unit tests / tests (push) Successful in 41s
2024-09-13 13:07:49 -04:00
Dianne Skoll
020e82d575 Document that TIME constants may be surrounded by single quotes. 2024-09-13 13:06:57 -04:00
Dianne Skoll
a20f2b588e Accept either 12:34 or '12:34' as a time constant. 2024-09-13 13:02:46 -04:00
Dianne Skoll
631e721a96 More helpful error if someone uses '...' around a TIME constant. 2024-09-13 12:46:38 -04:00
Dianne Skoll
8453e17c6c Add a guard to avoid calling free(NULL)
All checks were successful
Remind unit tests / tests (push) Successful in 29s
2024-09-12 11:50:11 -04:00
Dianne Skoll
76c1e2abb3 Avoid unnecessary double-initialization. 2024-09-12 11:38:59 -04:00
Dianne Skoll
3389f1c91b Refactor init_token and token_error. 2024-09-12 10:58:35 -04:00
Dianne Skoll
b2d47ae979 Initialize token.val in a few places. 2024-09-12 10:51:00 -04:00
Dianne Skoll
e2c615f310 Fix comment. 2024-09-12 10:16:01 -04:00
Dianne Skoll
e8492a4303 Add Chinese New Year file. 2024-09-11 12:09:57 -04:00
Dianne Skoll
4695efaabd Use DBG macro
Some checks failed
Remind unit tests / tests (push) Failing after 28s
2024-09-11 11:53:07 -04:00
Dianne Skoll
c433f42587 Get rid of useless function. 2024-09-11 11:49:04 -04:00
Dianne Skoll
4708e59a43 No need to munch following whitespace. 2024-09-11 11:46:40 -04:00
Dianne Skoll
d56ac6332a Use switch rather than if...else chains
All checks were successful
Remind unit tests / tests (push) Successful in 33s
2024-09-11 11:37:30 -04:00
Dianne Skoll
b054baf590 Stricter tokenization of datetime 2024-09-11 09:01:52 -04:00
Dianne Skoll
42f5e3467d Better error messages for ill-formed time. 2024-09-11 08:52:06 -04:00
Dianne Skoll
97013ae89b Return T_Illegal with a negative tok.val if we can't parse a numeric token. 2024-09-11 08:45:31 -04:00
Dianne Skoll
2acead9118 Shorten error message.
All checks were successful
Remind unit tests / tests (push) Successful in 29s
2024-09-10 16:25:00 -04:00
Dianne Skoll
a53a80acb4 Make error message more explicit. 2024-09-10 16:23:52 -04:00
Dianne Skoll
56e62b1b4d More error checking of bad date specs. 2024-09-10 14:27:46 -04:00
Dianne Skoll
c645db5ede Diagnose bad YYYY-MM-DD constants in REM command. 2024-09-10 14:09:52 -04:00
Dianne Skoll
ef6b9c3783 Better error message when a number that isn't recognized as a day number or year is encountered. 2024-09-10 13:57:34 -04:00
Dianne Skoll
019bee26cb Start refactoring calendar code.
All checks were successful
Remind unit tests / tests (push) Successful in 30s
2024-09-10 10:47:32 -04:00
Dianne Skoll
152cd4090b Better error message.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-09-09 17:01:56 -04:00
Dianne Skoll
b7fc2b5776 Tweak remind-conf-mode.el with new Remind keywords and better handling of comment lines. 2024-09-09 16:50:27 -04:00
Dianne Skoll
723aba9b7c Document and test --print-tokens
All checks were successful
Remind unit tests / tests (push) Successful in 30s
2024-09-08 10:33:24 -04:00
Dianne Skoll
8a5b88338b Add --print-tokens long option to dump Remind tokens to stdout. 2024-09-08 10:29:49 -04:00
Dianne Skoll
7236441e02 Remove note saying REM can be omitted. 2024-09-08 10:26:07 -04:00
Dianne Skoll
e4bab0dda4 Be more explicit. 2024-09-08 09:57:52 -04:00
Dianne Skoll
5b7d4a07ec More explicit error messages.
All checks were successful
Remind unit tests / tests (push) Successful in 47s
2024-09-07 13:25:31 -04:00
Dianne Skoll
8c3d2c4003 More specific error message. 2024-09-07 13:14:31 -04:00
Dianne Skoll
f485d607ff Fix error message. 2024-09-07 10:16:57 -04:00
Dianne Skoll
a0effa5f0b Update keyword/variable/function list in remind-conf-mode.el. 2024-09-07 10:15:02 -04:00
Dianne Skoll
7d501cda6f Update to ical2rem version 0.7.
All checks were successful
Remind unit tests / tests (push) Successful in 31s
2024-09-05 12:44:17 -04:00
Dianne Skoll
5d7f55c8d5 Make error messages more consistent.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-09-03 10:53:45 -04:00
Dianne Skoll
097bf92bea Better error message. 2024-09-03 10:51:50 -04:00
Dianne Skoll
b9dea59206 Update changelog.
All checks were successful
Remind unit tests / tests (push) Successful in 39s
2024-09-02 14:46:58 -04:00
Dianne Skoll
46aa144b65 Bump version to 05.00.05 2024-09-02 10:15:56 -04:00
Dianne Skoll
914971308d Better error message.
All checks were successful
Remind unit tests / tests (push) Successful in 30s
2024-09-01 23:42:29 -04:00
Dianne Skoll
a22e81040f Check error return in a couple of spots. 2024-09-01 23:22:00 -04:00
Dianne Skoll
72f74f03cf Check for errors. 2024-09-01 23:18:09 -04:00
Dianne Skoll
d0e45e727e Don't print closing ] in error indicator.
All checks were successful
Remind unit tests / tests (push) Successful in 31s
2024-09-01 22:39:49 -04:00
Dianne Skoll
ce2b2e80da Remove unnecessary _h() function definition.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-09-01 11:31:28 -04:00
Dianne Skoll
11771b7d3d Better formatting of ^-- here message for expressions with embedded newlines 2024-09-01 11:27:34 -04:00
Dianne Skoll
01cb028532 Fix up tests to pass in September 2024. 2024-09-01 11:09:32 -04:00
Dianne Skoll
58b6f43b9c Better diagnosis of wrong #args for builtin functions. 2024-09-01 09:03:26 -04:00
Dianne Skoll
1dedb667e8 Prevent a couple of file descriptor leaks.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-08-31 09:06:05 -04:00
Dianne Skoll
8a96236788 Avoid warnings if REM_USE_WCHAR is undefined.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-08-30 20:44:08 -04:00
Dianne Skoll
2a13163659 Fix some weird edge cases in text-mode calendar formatting.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-08-29 13:25:36 -04:00
Dianne Skoll
336a9684d4 In calendar mode, SHADE the entire calendar box including day number.
All checks were successful
Remind unit tests / tests (push) Successful in 29s
2024-08-29 08:50:57 -04:00
Dianne Skoll
86945c6e18 Remove incorrect test obsoleted by changes in 05.00.04. 2024-08-29 08:39:55 -04:00
Dianne Skoll
684280db5e Remove "SCHED _sfun" and hard-code "+15" instead. 2024-08-29 08:15:10 -04:00
Dianne Skoll
d801408933 Update WHATSNEW. 2024-08-29 08:01:50 -04:00
Dianne Skoll
79b3da3820 Update man page.
All checks were successful
Remind unit tests / tests (push) Successful in 27s
2024-08-28 20:43:27 -04:00
Dianne Skoll
ed021d3f46 Let IIF's boolean arg be any type... we use truthy(). 2024-08-28 20:41:21 -04:00
Dianne Skoll
27d0fda280 Factor out truthy code from Fiif 2024-08-28 20:38:04 -04:00
Dianne Skoll
ef12da4ec6 Refactor out "truthy". 2024-08-28 20:36:30 -04:00
Dianne Skoll
7b098e95ad Make error messages more consistent. 2024-08-28 18:21:35 -04:00
Dianne Skoll
7d13f4b09e Better diagnostics when printing "Too many/few arguments" errors 2024-08-28 18:14:43 -04:00
Dianne Skoll
cecdfe6ade Bump version to 05.00.04. 2024-08-28 18:00:50 -04:00
Dianne Skoll
216bbd6378 Fix the logic that recurses into user-defined functions. 2024-08-28 17:56:47 -04:00
Dianne Skoll
30e2e9c633 When looking at SATISFY expressions to make sure they use the trigger date, look recursively into user-defined functions in the expression also. 2024-08-28 17:49:12 -04:00
Dianne Skoll
bf2aabd610 Update release notes. 2024-08-28 15:42:23 -04:00
Dianne Skoll
c019221d15 Add diagnostics for missing/bad subst_XXX functions. 2024-08-28 15:15:34 -04:00
Dianne Skoll
b7bd6faf07 Warn if SCHED/WARN/OMITFUNC functions take wrong number of args. 2024-08-28 15:02:22 -04:00
Dianne Skoll
80d58220fe In warnings, give file/lineno where function is defined. 2024-08-28 14:59:13 -04:00
Dianne Skoll
cd8624e176 Tweak diagnostic messages. 2024-08-28 14:35:49 -04:00
Dianne Skoll
8515fb7ddd Update / clarify manual. 2024-08-28 14:28:34 -04:00
Dianne Skoll
84f9f4ae0a Update tests. 2024-08-28 14:23:14 -04:00
Dianne Skoll
e201ebcfa4 Document that logical operators can take any type; add tests. 2024-08-28 14:22:07 -04:00
Dianne Skoll
4e15c3ec35 Remove an optimization that was interfering with expression debugging. 2024-08-28 14:21:44 -04:00
Dianne Skoll
1adccf9b1f Add tests for SCHED/WARN/OMITFUNC functions that don't use their argument. 2024-08-28 13:54:47 -04:00
Dianne Skoll
a1aa5c2ad9 Change wording of warning slightly. 2024-08-28 13:54:40 -04:00
Dianne Skoll
1e0d650737 Fix tests. 2024-08-28 13:49:34 -04:00
Dianne Skoll
553d092ca8 Diagnost if WARN/SCHED/OMITFUNC functions don't reference their argument. 2024-08-28 13:49:17 -04:00
Dianne Skoll
dc62841517 Fix accidental broken commit. :( 2024-08-28 13:45:42 -04:00
Dianne Skoll
326e7bfc53 Document calendar back-end handling of %_ 2024-08-28 13:23:54 -04:00
Dianne Skoll
b9dc7c16ad Use /s modifier on regex. 2024-08-28 13:09:18 -04:00
Dianne Skoll
abd54b016b Add tests for newlines in calendars. 2024-08-28 12:56:53 -04:00
Dianne Skoll
db02b54067 Collapse multiple whitespace; convert newlines to "<br />" in HTML output. 2024-08-28 12:52:39 -04:00
Dianne Skoll
40a78dfbbb Collapse multiple newlines after all other processing. 2024-08-28 12:52:29 -04:00
Dianne Skoll
c860b46baa Collapse multiple runs of whitespace 2024-08-28 12:52:07 -04:00
Dianne Skoll
1458ba8856 Clean up whitespace runs in rem2pdf.
All checks were successful
Remind unit tests / tests (push) Successful in 45s
2024-08-28 10:44:41 -04:00
Dianne Skoll
7b9b6ebc96 Preserve %_ newlines in "-C" mode. 2024-08-28 10:14:06 -04:00
Dianne Skoll
7ee4073c7a Document warning on function redefinitiion.
All checks were successful
Remind unit tests / tests (push) Successful in 26s
2024-08-27 21:43:46 -04:00
Dianne Skoll
8c072cd9b6 Add a warning if a function is redefined. 2024-08-27 21:41:45 -04:00
Dianne Skoll
b794a45c3f Add more SATISFY diagnostics.
All checks were successful
Remind unit tests / tests (push) Successful in 34s
2024-08-27 15:02:11 -04:00
Dianne Skoll
98e491ed1d Remove some left-over debugging code. 2024-08-27 15:01:59 -04:00
Dianne Skoll
c397cc06da Rewrite code to avoid need to pass address of "mentioned" variable.
All checks were successful
Remind unit tests / tests (push) Successful in 30s
2024-08-27 11:33:41 -04:00
Dianne Skoll
8616236b3c Document that SATISFY clauses that don't mention trigdate are diagnosed. 2024-08-27 11:26:13 -04:00
Dianne Skoll
702704af1a Make sure SATISFY expressions are either constant or mention trigdate. 2024-08-27 11:22:42 -04:00
Dianne Skoll
a0d1b19050 Fix typo in comment.
All checks were successful
Remind unit tests / tests (push) Successful in 39s
2024-08-23 15:08:35 -04:00
Dianne Skoll
a5c8ae491c Add test for diagnosing function definitions with too many arguments. 2024-08-23 15:05:24 -04:00
Dianne Skoll
b3cf741d15 Suppress warning in GCC 14.2.1. Patch courtesy of Emanuele Torre
All checks were successful
Remind unit tests / tests (push) Successful in 38s
2024-08-23 07:44:36 -04:00
Dianne Skoll
0b28dde9c7 Add optional argument to ampm() to specify that hour should be zero-padded to two digits.
All checks were successful
Remind unit tests / tests (push) Successful in 46s
2024-08-22 17:38:54 -04:00
Dianne Skoll
5a3980b5b8 Make note about intended use of defs.rem 2024-08-22 12:51:58 -04:00
Dianne Skoll
a8e33118d6 Suppress warnings. 2024-08-22 10:32:27 -04:00
Dianne Skoll
2223277f64 Fix many warnings. 2024-08-22 10:26:48 -04:00
Dianne Skoll
c72413e3c1 Fix up tests for previous commit.
All checks were successful
Remind unit tests / tests (push) Successful in 29s
2024-08-21 15:10:28 -04:00
Dianne Skoll
fa1033db6f Don't warn about assuming REM type if we've already warned about assuming "REM" 2024-08-21 15:09:41 -04:00
Dianne Skoll
61e3edd2ac Add tests for new diagnostics. 2024-08-21 12:57:04 -04:00
Dianne Skoll
093c97ff91 Add tests for missing REM or missing MSG being diagnosed. 2024-08-21 12:50:51 -04:00
Dianne Skoll
6e64b175aa Diagnose lines that are implicitly treated as REM lines.
Diagnose REM commands that are implicitly treated as having MSG type.

Properly start all lines that should start with REM, with REM.
2024-08-21 12:45:30 -04:00
Dianne Skoll
09dba4bc94 Clarify caching of INCLUDECMD output.
All checks were successful
Remind unit tests / tests (push) Successful in 27s
2024-08-07 13:26:00 -04:00
Dianne Skoll
2e443ac5b7 Properly handle landscape mode in PostScript output.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-08-04 08:04:56 -04:00
Dianne Skoll
59a8c88178 Use %%PageOrientation, not %%Orientation in DSC comments. 2024-08-04 07:55:55 -04:00
Dianne Skoll
40eab03d84 Add two ways to produce PostScript code: Using rem2ps or rem2pdf
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-08-01 12:27:33 -04:00
Dianne Skoll
e993bf59cf Add support for Encapsulated PostScript to rem2pdf. 2024-08-01 09:57:16 -04:00
Dianne Skoll
c6de5a2c8f Add support for producing PostScript to rem2pdf. 2024-08-01 09:40:29 -04:00
Dianne Skoll
51cc939d0c Suppress a couple of cppcheck warnings.
All checks were successful
Remind unit tests / tests (push) Successful in 30s
2024-07-30 15:17:13 -04:00
Dianne Skoll
c857192e6d Change the man page to remove statements that are no longer true (since the new expression-evaluation code in 05.00.00.)
All checks were successful
Remind unit tests / tests (push) Successful in 27s
2024-07-27 08:51:00 -04:00
Dianne Skoll
4591c2b181 Bump version number; fix a bunch of man page warnings; make "make test" fail if there are any man page warnings iff the "man" command accepts --warning
All checks were successful
Remind unit tests / tests (push) Successful in 6m7s
2024-07-26 09:59:46 -04:00
Dianne Skoll
7843a1b2ba Fix typo: .RP should be .PP 2024-07-26 08:18:33 -04:00
55 changed files with 4396 additions and 1409 deletions

1
.gitignore vendored
View File

@@ -22,6 +22,7 @@ rem2pdf/Makefile.PL
rem2pdf/Makefile.old
rem2pdf/Makefile.top
rem2pdf/bin/rem2pdf
scripts/tkremind
set-irc-topic
src/*.tar.gz*
src/Makefile

View File

@@ -24,7 +24,7 @@ install:
@$(MAKE) -C rem2pdf -f Makefile.top install INSTALL_BASE=$(INSTALL_BASE)
clean:
find . -name '*~' -exec rm {} \;
-rm man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1
-rm man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1 scripts/tkremind
-$(MAKE) -C src clean
-$(MAKE) -C rem2pdf clean

29
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for remind 05.00.02.
# Generated by GNU Autoconf 2.71 for remind 05.00.07.
#
#
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -608,8 +608,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='remind'
PACKAGE_TARNAME='remind'
PACKAGE_VERSION='05.00.02'
PACKAGE_STRING='remind 05.00.02'
PACKAGE_VERSION='05.00.07'
PACKAGE_STRING='remind 05.00.07'
PACKAGE_BUGREPORT=''
PACKAGE_URL='https://dianne.skoll.ca/projects/remind/'
@@ -651,6 +651,7 @@ LIBOBJS
RELEASE_DATE
PERLARTIFACTS
VERSION
CONFIG_CMD
PERL
SET_MAKE
LN_S
@@ -1264,7 +1265,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures remind 05.00.02 to adapt to many kinds of systems.
\`configure' configures remind 05.00.07 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1326,7 +1327,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of remind 05.00.02:";;
short | recursive ) echo "Configuration of remind 05.00.07:";;
esac
cat <<\_ACEOF
@@ -1414,7 +1415,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
remind configure 05.00.02
remind configure 05.00.07
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1864,7 +1865,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by remind $as_me 05.00.02, which was
It was created by remind $as_me 05.00.07, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -4198,11 +4199,17 @@ fi
VERSION=$PACKAGE_VERSION
CONFIG_CMD="$0$ac_configure_args_raw"
CONFIG_CMD=`echo "$CONFIG_CMD" | sed -e 's/"/\\\\"/g'`
printf "%s\n" "#define CONFIG_CMD \"$CONFIG_CMD\"" >>confdefs.h
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h rem2html/Makefile rem2html/rem2html rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1"
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h rem2html/Makefile rem2html/rem2html rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1 scripts/tkremind"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -4703,7 +4710,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by remind $as_me 05.00.02, which was
This file was extended by remind $as_me 05.00.07, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -4768,7 +4775,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
remind config.status 05.00.02
remind config.status 05.00.07
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
@@ -4903,6 +4910,7 @@ do
"man/rem2ps.1") CONFIG_FILES="$CONFIG_FILES man/rem2ps.1" ;;
"man/remind.1") CONFIG_FILES="$CONFIG_FILES man/remind.1" ;;
"man/tkremind.1") CONFIG_FILES="$CONFIG_FILES man/tkremind.1" ;;
"scripts/tkremind") CONFIG_FILES="$CONFIG_FILES scripts/tkremind" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac
@@ -5490,4 +5498,5 @@ printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2
fi
chmod a+x rem2pdf/bin/rem2pdf
chmod a+x scripts/tkremind

View File

@@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(remind, 05.00.02, , , https://dianne.skoll.ca/projects/remind/)
AC_INIT(remind, 05.00.07, , , https://dianne.skoll.ca/projects/remind/)
AC_CONFIG_SRCDIR([src/queue.c])
cat <<'EOF'
@@ -87,10 +87,15 @@ fi
AC_CHECK_FUNCS(strdup strcasecmp strncasecmp setenv unsetenv glob mbstowcs setlocale initgroups inotify_init1)
VERSION=$PACKAGE_VERSION
CONFIG_CMD="$0$ac_configure_args_raw"
CONFIG_CMD=`echo "$CONFIG_CMD" | sed -e 's/"/\\\\"/g'`
AC_DEFINE_UNQUOTED([CONFIG_CMD], ["$CONFIG_CMD"], [Configuration command used to build Remind])
AC_SUBST(CONFIG_CMD)
AC_SUBST(VERSION)
AC_SUBST(PERL)
AC_SUBST(PERLARTIFACTS)
AC_SUBST(RELEASE_DATE)
AC_CONFIG_FILES([src/Makefile www/Makefile src/version.h rem2html/Makefile rem2html/rem2html rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1])
AC_CONFIG_FILES([src/Makefile www/Makefile src/version.h rem2html/Makefile rem2html/rem2html rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1 scripts/tkremind])
AC_OUTPUT
chmod a+x rem2pdf/bin/rem2pdf
chmod a+x scripts/tkremind

View File

@@ -0,0 +1,3 @@
The upstream GitHub project for ical2rem is:
https://github.com/jbalcorn/ical2rem

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2005, 2007, 2019 Justin B. Alcorn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,103 @@
# ical2rem
The original iCal to Remind script, first released in 2005.
Reads iCal files and outputs remind-compatible files. Tested ONLY with
calendar files created by Mozilla Calendar/Sunbird. Use at your own risk.
## License
In 2005, this was released with the Gnu Public License V2. However, I am changing it to the MIT License, since that provides greater freedom to do with this code what you want.
Copyright (c) 2005, 2007, 2019 Justin B. Alcorn
## How I use Remind and Google Calendar together
- My family has a Google Email domain, and our email addresses all end in the same domain. We all use Google Calendars and I want to mail reminders to each of the family members containing both Google Calendar and .reminder information.
- Under my ~/.rem/ directory each family member has a directory. Each directory contains a standard remind file called 'reminders' that at the very least has the line "INCLUDE /home/jalcorn/.rem/<username>/ical2rem" and flag files indicating whether they want Daily or Weekly reminders. My reminders files references my standard .reminders file, and I also have a flag so if I run a Test run I'll get it. There's actually a lot more files (I have a big family).
````
./rem
./son1:
drwxrwxr-x 2 jalcorn jalcorn 4096 Dec 12 14:02 .
drwxr-xr-x 12 jalcorn jalcorn 4096 Dec 12 14:13 ..
-rw-rw-r-- 1 jalcorn jalcorn 51 Mar 3 06:10 ical2rem
lrwxrwxrwx 1 jalcorn jalcorn 33 Oct 27 2016 son1.ics -> /home/jalcorn/calendars/son1.ics
-rw-rw-r-- 1 jalcorn jalcorn 976 Dec 12 14:02 reminders
-rw-rw-r-- 1 jalcorn jalcorn 0 Oct 27 2016 Weekly
./justin:
drwxrwxr-x 2 jalcorn jalcorn 4096 Feb 27 08:29 .
drwxr-xr-x 12 jalcorn jalcorn 4096 Dec 12 14:13 ..
lrwxrwxrwx 1 jalcorn jalcorn 32 Oct 27 2016 son1.ics -> /home/jalcorn/calendars/son1.ics
-rw-rw-r-- 1 jalcorn jalcorn 0 Nov 7 2016 Daily
lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 family.ics -> /home/jalcorn/calendars/family.ics
-rw-rw-r-- 1 jalcorn jalcorn 37320 Mar 3 06:10 ical2rem
lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 justin.ics -> /home/jalcorn/calendars/justin.ics
lrwxrwxrwx 1 jalcorn jalcorn 24 Nov 7 2016 reminders -> /home/jalcorn/.reminders
lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 vmd.ics -> /home/jalcorn/calendars/vmd.ics
-rw-rw-r-- 1 jalcorn jalcorn 0 Oct 27 2016 Test
-rw-rw-r-- 1 jalcorn jalcorn 0 Nov 7 2016 Weekly
````
- bin/getgooglecals.sh runs out of crontab and downloads whatever calendars I want. Note that we can also download organization calendars, I've included a public one here (Cleveland Heights Vocal Music Department calendar).
- dailyreminders.sh is linked to weeklyreminders.sh and testreminders.sh so I can run it in different modes. The concatenate the various calendar outputs as a single remind file then send the reminders via email.
### Example: .rem/son1/reminders file:
````
INCLUDE /home/jalcorn/.rem/defs.rem
INCLUDE /home/jalcorn/.rem/float
INCLUDE /home/jalcorn/.rem/son1/ical2rem
fset _weeks() coerce("STRING", (trigdate()-today())/7) + plural((trigdate()-today())/7, " week")
FSET _sfun(x) choose(x, -60, 30, 5, 0)
FSET oldfloat(y,m,d) trigger(MAX(realtoday(), date(y,m,d)))
FSET due(y,m,d) "(" + (date(y,m,d)-trigdate()) + ")"
SET fullmoon moondate(2)
REM [trigger(realtoday())] SPECIAL SHADE 145 70 100 %
REM [float(2019,4,15,105)] MSG File tax return [due(2017,4,15)]%
REM PRIORITY 9999 MSG %"%"%
INCLUDE /home/jalcorn/.rem/bdays
SET $LongDeg 81
SET $LongMin 11
SET $LongSec 11
SET $LatDeg 41
SET $LatMin 11
SET $LatSec 11
REM [trigger(moondate(2))] +1 MSG %"Full Moon%" %b%
fset _srtd() coerce("STRING", _no_lz(_am_pm(sunrise(today()))))
fset _sstd() coerce("STRING", _no_lz(_am_pm(sunset(today()))))
MSG Sun is up today from [_srtd()] to [_sstd()].%"%"%
````
## Revision History
### Version 0.7 2024-09-04
- ISSUE 8: New version of remind complains if _sfun isn't defined. Output a header
to define a function that does nothing if the function doesn't exist.
### Version 0.6 2019-03-01
- Publish on GitHub and change license to MIT License
- Add supporting files and explanation of how I use it
### version 0.5.2 2007-03-23
- BUG: leadtime for recurring events had a max of 4 instead of DEFAULT_LEAD_TIME
- remove project-lead-time, since Category was a non-standard attribute
- NOTE: There is a bug in iCal::Parser v1.14 that causes multiple calendars to
fail if a calendar with recurring events is followed by a calendar with no
recurring events. This has been reported to the iCal::Parser author.
### version 0.5.1 2007-03-21
- BUG: Handle multiple calendars on STDIN
- add --heading option for priority on section headers
### version 0.5 2007-03-21
- Add more help options
- --project-lead-time option
- Supress printing of heading if there are no todos to print
### version 0.4
- Version 0.4 changes all written or inspired by, and thanks to Mark Stosberg
- Change to GetOptions
- Change to pipe
- Add --label, --help options
- Add Help Text
- Change to subroutines
- Efficiency and Cleanup
### version 0.3
- Convert to GPL (Thanks to Mark Stosberg)
- Add usage
### version 0.2
- add command line switches
- add debug code
- add SCHED _sfun keyword
- fix typos
### version 0.1 - ALPHA CODE.

View File

@@ -0,0 +1,82 @@
#!/usr/bin/perl -w
#
# cal_futureonly.pl -
# Reads iCal files and outputs events between 1 month ago and 1 year from now.
# Copyright (c) 2005, 2007, 2019 Justin B. Alcorn
=head1 SYNOPSIS
cal_futureonly.pl --file=filname.ics > output.ics
--help Usage
--man Complete man page
--infile (REQUIRED) name of input calendar file
--file (REQUIRED) name of output calendar file
Expects an ICAL stream on STDIN. Converts it to the format
used by the C<remind> script and prints it to STDOUT.
=head2 --infile
Input file
=head2 --file
Output File
=cut
use strict;
use Data::ICal;
use Data::ICal::Entry;
use DateTime::Span;
use Data::ICal::DateTime;
use DateTime;
use Getopt::Long 2.24 qw':config auto_help';
use Pod::Usage;
use Data::Dumper;
use vars '$VERSION';
$VERSION = "0.1";
my $help;
my $man;
my $infile;
my $file;
my $debug = 0;
GetOptions (
"help|?" => \$help,
"man" => \$man,
"debug" => \$debug,
"infile=s" => \$infile,
"file=s" => \$file
);
pod2usage(1) if $help;
pod2usage(1) if (! $file);
pod2usage(-verbose => 2) if $man;
my $limit = DateTime->now();
$limit->subtract( months => 1);
my $endlimit = DateTime->now()->add(years =>1);
print STDERR "including events from: ",$limit->ymd," to: ".$endlimit->ymd,"\n" if $debug;
my $span = DateTime::Span->from_datetimes( start => $limit, end => $endlimit );
print STDERR "Parsing $infile\n" if $debug;
my $cal = Data::ICal->new(filename => $infile);
if (! $cal) {
die "Died Trying to read $infile :".$cal->error_message;
}
#my $archive = Data::ICal->new(filename => 'archive.ics');
print "Output = $file\n" if $debug;
my $new = Data::ICal->new();
if (! $new) {
die $new->error_message;
}
my @events = $cal->events($span);
$new->add_entries(@events);
open(NEW, ">$file");
print NEW $new->as_string;
close NEW;
exit 0;
#:vim set ft=perl ts=4 sts=4 expandtab :

View File

@@ -0,0 +1,45 @@
#!/bin/bash
r=`basename $0`
if [ $r == 'weeklyreminders.sh' ];
then
t=14;
w=Weekly;
elif [ $r == 'dailyreminders.sh' ];
then
t=3;
w=Daily;
else
t=5
w=Test;
fi
cd .rem
for d in * ;
do
if [ "$( ls -A $d/$w 2>/dev/null )" ];
then
echo "Sending a $w reminder to $d"
ft=/tmp/$d-t-$$.txt
f=/tmp/$d-$$.txt
echo "Reminders for next $t days:" >> $f
cat /dev/null > $d/ical2rem
for c in $d/*.ics
do
calname=`basename $c .ics | tr a-z A-Z`
cat $c 2>/dev/null | sed -e "s/^SUMMARY:/SUMMARY: {${calname}} /" \
| sed -e 's/DT\([A-Z]*\);TZID=UTC:\([0-9T]*\)/DT\1:\2Z/' >> $ft
done
cat $ft | ~/bin/ical2rem.pl --label "Online Calendar" --heading "PRIORITY 9999" --lead-time $t >> $d/ical2rem
if [ -e $d/reminders ];then r="${d}/reminders"; else r="${d}/ical2rem";fi
/usr/bin/remind -q -iplain=1 $r >> $f
echo "
All calendars can be accessed by logging into https://calendar.google.com/ as $d@jalcorn.net
" >> $f
cat $f | mail -s "$w Reminders for $d" $d@jalcorn.net;
cat $f
rm $f
rm $ft
fi;
done

View File

@@ -0,0 +1,21 @@
#!/bin/sh
#
# Get google calendars, fix issues caused by changes in Google calendars, and remove all past events.
#
# Obviously, I've removed the private hashes from private calendars.
#
cd ~/calendars
wget -q -O full/justin.ics --no-check-certificate https://www.google.com/calendar/ical/jbalcorn\%40gmail.com/private-aaaaaaaaaaaaaaaaaaaaaaaaaa/basic.ics
wget -q -O full/family.ics --no-check-certificate https://www.google.com/calendar/ical/jalcorn.net_aaaaaaaaaaaaaaaaaaaaaaaaaa\%40group.calendar.google.com/private-6c42a79dec0b3b3bb7b9b0ebf9776bc1/basic.ics
wget -q -O full/son1.ics --no-check-certificate https://www.google.com/calendar/ical/son1\%40jalcorn.net/private-aaaaaaaaaaaaaaaaaaaaaaaaaa/basic.ics
wget -q -O full/vmd.ics --no-check-certificate https://calendar.google.com/calendar/ical/chuh.org_0pmkefjkiqc4snoel7occlslh8%40group.calendar.google.com/public/basic.ics
for i in full/*.ics;do
cat $i 2>/dev/null | sed -e 's/DT\([A-Z]*\);TZID=UTC:\([0-9T]*\)/DT\1:\2Z/' > /tmp/temp.ics
cp /tmp/temp.ics $i
done
~/bin/cal_futureonly.pl --infile=full/justin.ics --file=justin.ics
~/bin/cal_futureonly.pl --infile=full/family.ics --file=family.ics
~/bin/cal_futureonly.pl --infile=full/son1.ics --file=son1.ics
~/bin/cal_futureonly.pl --infile=full/vmd.ics --file=vmd.ics

396
contrib/ical2rem-0.8/ical2rem.pl Executable file
View File

@@ -0,0 +1,396 @@
#!/usr/bin/perl -w
#
# ical2rem.pl -
# Reads iCal files and outputs remind-compatible files. Tested ONLY with
# calendar files created by Mozilla Calendar/Sunbird. Use at your own risk.
# MIT License
#
# Copyright (c) 2005, 2007, 2019 Justin B. Alcorn
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# version 0.8 2024-10-16
# - Issue 9. Remove extra day notation on all day events.
# version 0.7.1 2024-09-19
# - Made sure license statements were consistent
# version 0.7 2024-09-04
# - Added dummy _sfun to resolve Issue #8
# version 0.6 2019-03-01
# - Updates to put on GitHub
# version 0.5.2 2007-03-23
# - BUG: leadtime for recurring events had a max of 4 instead of DEFAULT_LEAD_TIME
# - remove project-lead-time, since Category was a non-standard attribute
# - NOTE: There is a bug in iCal::Parser v1.14 that causes multiple calendars to
# fail if a calendar with recurring events is followed by a calendar with no
# recurring events. This has been reported to the iCal::Parser author.
# version 0.5.1 2007-03-21
# - BUG: Handle multiple calendars on STDIN
# - add --heading option for priority on section headers
# version 0.5 2007-03-21
# - Add more help options
# - --project-lead-time option
# - Supress printing of heading if there are no todos to print
# version 0.4
# - Version 0.4 changes all written or inspired by, and thanks to Mark Stosberg
# - Change to GetOptions
# - Change to pipe
# - Add --label, --help options
# - Add Help Text
# - Change to subroutines
# - Efficiency and Cleanup
# version 0.3
# - Convert to GPL (Thanks to Mark Stosberg)
# - Add usage
# version 0.2
# - add command line switches
# - add debug code
# - add SCHED _sfun keyword
# - fix typos
# version 0.1 - ALPHA CODE.
=head1 SYNOPSIS
cat /path/to/file*.ics | ical2rem.pl > ~/.ical2rem
All options have reasonable defaults:
--label Calendar name (Default: Calendar)
--start Start of time period to parse (parsed by str2time)
--end End of time period to parse
--lead-time Advance days to start reminders (Default: 3)
--todos, --no-todos Process Todos? (Default: Yes)
--iso8601 Use YYYY-MM-DD date format
--locations, --no-locations Include location? (Default: Yes)
--end-times, --no-end-times Include event end times in reminder text
(Default: No)
--heading Define a priority for static entries
--help Usage
--debug Enable debug output
--man Complete man page
Expects an ICAL stream on STDIN. Converts it to the format
used by the C<remind> script and prints it to STDOUT.
=head2 --label
ical2rem.pl --label "Bob's Calendar"
The syntax generated includes a label for the calendar parsed.
By default this is "Calendar". You can customize this with
the "--label" option.
=head2 --iso8601
Use YYYY-MM-DD date format in output instead of Mmm DD YYYY
=head2 --locations, --no-locations
Whether or not to include locations in events
=head2 --lead-time
ical2rem.pl --lead-time 3
How may days in advance to start getting reminders about the events. Defaults to 3.
=head2 --no-todos
ical2rem.pl --no-todos
If you don't care about the ToDos the calendar, this will surpress
printing of the ToDo heading, as well as skipping ToDo processing.
=head2 --heading
ical2rem.pl --heading "PRIORITY 9999"
Set an option on static messages output. Using priorities can made the static messages look different from
the calendar entries. See the file defs.rem from the remind distribution for more information.
=cut
use strict;
use iCal::Parser;
use Date::Parse;
use DateTime;
use Getopt::Long 2.24 qw':config auto_help';
use Pod::Usage;
use Data::Dumper;
use vars '$VERSION';
$VERSION = "0.5.2";
# Declare how many days in advance to remind
my $DEFAULT_LEAD_TIME = 3;
my $PROCESS_TODOS = 1;
my $HEADING = "";
my $help;
my $debug;
my $man;
my $iso8601;
my $do_location = 1;
my $do_end_times;
my $start;
my $end;
my $label = 'Calendar';
GetOptions (
"label=s" => \$label,
"start=s" => \$start,
"end=s" => \$end,
"lead-time=i" => \$DEFAULT_LEAD_TIME,
"todos!" => \$PROCESS_TODOS,
"iso8601!" => \$iso8601,
"locations!" => \$do_location,
"end-times!" => \$do_end_times,
"heading=s" => \$HEADING,
"help|?" => \$help,
"debug" => \$debug,
"man" => \$man
) or pod2usage(1);
pod2usage(1) if $help;
pod2usage(-verbose => 2) if $man;
my $month = ['None','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
my @calendars;
my $in;
while (<>) {
$in .= $_;
if (/END:VCALENDAR/) {
push(@calendars,$in);
$in = "";
}
}
print STDERR "Read all calendars\n" if $debug;
my(%parser_opts) = ("debug" => $debug);
if ($start) {
my $t = str2time($start);
die "Invalid time $start\n" if (! $t);
$parser_opts{'start'} = DateTime->from_epoch(epoch => $t);
}
if ($end) {
my $t = str2time($end);
die "Invalid time $end\n" if (! $t);
$parser_opts{'end'} = DateTime->from_epoch(epoch => $t);
}
print STDERR "About to parse calendars\n" if $debug;
my $parser = iCal::Parser->new(%parser_opts);
my $hash = $parser->parse_strings(@calendars);
print STDERR "Calendars parsed\n" if $debug;
##############################################################
#
# Subroutines
#
#############################################################
#
# _process_todos()
# expects 'todos' hashref from iCal::Parser is input
# returns String to output
sub _process_todos {
my $todos = shift;
my ($todo, @newtodos, $leadtime);
my $output = "";
$output .= 'REM '.$HEADING.' MSG '.$label.' ToDos:%"%"%'."\n";
# For sorting, make sure everything's got something
# To sort on.
my $now = DateTime->now;
for $todo (@{$todos}) {
# remove completed items
if ($todo->{'STATUS'} && $todo->{'STATUS'} eq 'COMPLETED') {
next;
} elsif ($todo->{'DUE'}) {
# All we need is a due date, everything else is sugar
$todo->{'SORT'} = $todo->{'DUE'}->clone;
} elsif ($todo->{'DTSTART'}) {
# for sorting, sort on start date if there's no due date
$todo->{'SORT'} = $todo->{'DTSTART'}->clone;
} else {
# if there's no due or start date, just make it now.
$todo->{'SORT'} = $now;
}
push(@newtodos,$todo);
}
if (! (scalar @newtodos)) {
return "";
}
# Now sort on the new Due dates and print them out.
for $todo (sort { DateTime->compare($a->{'SORT'}, $b->{'SORT'}) } @newtodos) {
my $due = $todo->{'SORT'}->clone();
my $priority = "";
if (defined($todo->{'PRIORITY'})) {
if ($todo->{'PRIORITY'} == 1) {
$priority = "PRIORITY 1000";
} elsif ($todo->{'PRIORITY'} == 3) {
$priority = "PRIORITY 7500";
}
}
if (defined($todo->{'DTSTART'}) && defined($todo->{'DUE'})) {
# Lead time is duration of task + lead time
my $diff = ($todo->{'DUE'}->delta_days($todo->{'DTSTART'})->days())+$DEFAULT_LEAD_TIME;
$leadtime = "+".$diff;
} else {
$leadtime = "+".$DEFAULT_LEAD_TIME;
}
$output .= "REM ".$due->month_abbr." ".$due->day." ".$due->year." $leadtime $priority MSG \%a $todo->{'SUMMARY'}\%\"\%\"\%\n";
}
$output .= 'REM '.$HEADING.' MSG %"%"%'."\n";
return $output;
}
#######################################################################
#
# Main Program
#
######################################################################
# Issue 8 https://github.com/jbalcorn/ical2rem/issues/8
# Make sure there is a _sfun function declared in the reminder file. We'll just make it do nothing here.
print 'IF args("_sfun") < 1
FSET _sfun(x) choose(x,0)
ENDIF
';
print _process_todos($hash->{'todos'}) if $PROCESS_TODOS;
my ($leadtime, $yearkey, $monkey, $daykey,$uid,%eventsbyuid);
print 'REM '.$HEADING.' MSG '.$label.' Events:%"%"%'."\n";
my $events = $hash->{'events'};
foreach $yearkey (sort keys %{$events} ) {
my $yearevents = $events->{$yearkey};
foreach $monkey (sort {$a <=> $b} keys %{$yearevents}){
my $monevents = $yearevents->{$monkey};
foreach $daykey (sort {$a <=> $b} keys %{$monevents} ) {
my $dayevents = $monevents->{$daykey};
foreach $uid (sort {
DateTime->compare($dayevents->{$a}->{'DTSTART'}, $dayevents->{$b}->{'DTSTART'})
} keys %{$dayevents}) {
my $event = $dayevents->{$uid};
if ($eventsbyuid{$uid}) {
my $curreventday = $event->{'DTSTART'}->clone;
$curreventday->truncate( to => 'day' );
$eventsbyuid{$uid}{$curreventday->epoch()} =1;
for (my $i = 0;$i < $DEFAULT_LEAD_TIME && !defined($event->{'LEADTIME'});$i++) {
if ($eventsbyuid{$uid}{$curreventday->subtract( days => $i+1 )->epoch() }) {
$event->{'LEADTIME'} = $i;
}
}
# Issue 9. Multi-day events have extra day with zero time. Mark this as the date not needed in reminders file so we can skip later
# Repeating multi-day events have the same uid so we need to mark each one.
if ($event->{'DTSTART'} eq $event->{'DTEND'} and $event->{'DTEND'}->hour eq 0 and $event->{'DTEND'}->minute eq 0 and $event->{'DTEND'}->second eq 0) {
$eventsbyuid{$uid}{$event->{'DTSTART'}->ymd} = 'rm';
}
} else {
$eventsbyuid{$uid} = $event;
my $curreventday = $event->{'DTSTART'}->clone;
$curreventday->truncate( to => 'day' );
$eventsbyuid{$uid}{$curreventday->epoch()} =1;
}
}
}
}
}
foreach $yearkey (sort keys %{$events} ) {
my $yearevents = $events->{$yearkey};
foreach $monkey (sort {$a <=> $b} keys %{$yearevents}){
my $monevents = $yearevents->{$monkey};
foreach $daykey (sort {$a <=> $b} keys %{$monevents} ) {
my $dayevents = $monevents->{$daykey};
foreach $uid (sort {
DateTime->compare($dayevents->{$a}->{'DTSTART'}, $dayevents->{$b}->{'DTSTART'})
} keys %{$dayevents}) {
my $event = $dayevents->{$uid};
if (exists($event->{'LEADTIME'})) {
$leadtime = "+".$event->{'LEADTIME'};
} else {
$leadtime = "+".$DEFAULT_LEAD_TIME;
}
my $start = $event->{'DTSTART'};
my $end = $event->{'DTEND'};
my $duration = "";
# Issue 9. All Day events create an event that has zero length and DTSTART and DTEND at 00:00 on last day. Marked while handling multi-day events. Ignore these
if ($start eq $end and $eventsbyuid{$uid}{$start->ymd} and $eventsbyuid{$uid}{$start->ymd} eq 'rm') {
next;
}
if ($end and ($start->hour or $start->minute or $end->hour or $end->minute)) {
# We need both an HH:MM version of the delta, to put in the
# DURATION specifier, and a human-readable version of the
# delta, to put in the message if the user requested it.
my $seconds = $end->epoch - $start->epoch;
my $minutes = int($seconds / 60);
my $hours = int($minutes / 60);
$minutes -= $hours * 60;
$duration = sprintf("DURATION %d:%02d ", $hours, $minutes);
}
print "REM ";
if ($iso8601) {
print $start->strftime("%F ");
} else {
print $start->month_abbr." ".$start->day." ".$start->year." ";
}
print "$leadtime ";
if ($duration or $start->hour > 0 or $start->minute > 0) {
print "AT ";
print $start->strftime("%H:%M");
print " SCHED _sfun ${duration}MSG %a %2 ";
} else {
print "MSG %a ";
}
print "%\"", &quote($event->{'SUMMARY'});
print(" at ", &quote($event->{'LOCATION'}))
if ($do_location and $event->{'LOCATION'});
print "\%\"";
if ($do_end_times and ($start->hour or $start->minute or
$end->hour or $end->minute)) {
my $start_date = $start->strftime("%F");
my $start_time = $start->strftime("%k:%M");
my $end_date = $end->strftime("%F");
my $end_time = $end->strftime("%k:%M");
# We don't want leading whitespace; some strftime's support
# disabling the pdding in the format string, but not all,
# so for maximum portability we do it ourselves.
$start_time =~ s/^\s+//;
$end_time =~ s/^\s+//;
my(@pieces);
if ($start_date ne $end_date) {
push(@pieces, $end_date);
}
if ($start_time ne $end_time) {
push(@pieces, $end_time);
}
print " (-", join(" ", @pieces), ")";
}
print "%\n";
}
}
}
}
sub quote {
local($_) = @_;
s/\[/["["]/g;
return $_;
}
exit 0;
#:vim set ft=perl ts=4 sts=4 tabstop=4 expandtab :

View File

@@ -1,279 +0,0 @@
#!/usr/bin/perl -w
#
# ical2rem.pl -
# Reads iCal files and outputs remind-compatible files. Tested ONLY with
# calendar files created by Mozilla Calendar/Sunbird. Use at your own risk.
# Copyright (c) 2005, 2007, Justin B. Alcorn
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
# version 0.5.2 2007-03-23
# - BUG: leadtime for recurring events had a max of 4 instead of DEFAULT_LEAD_TIME
# - remove project-lead-time, since Category was a non-standard attribute
# - NOTE: There is a bug in iCal::Parser v1.14 that causes multiple calendars to
# fail if a calendar with recurring events is followed by a calendar with no
# recurring events. This has been reported to the iCal::Parser author.
# version 0.5.1 2007-03-21
# - BUG: Handle multiple calendars on STDIN
# - add --heading option for priority on section headers
# version 0.5 2007-03-21
# - Add more help options
# - --project-lead-time option
# - Suppress printing of heading if there are no todos to print
# version 0.4
# - Version 0.4 changes all written or inspired by, and thanks to Mark Stosberg
# - Change to GetOptions
# - Change to pipe
# - Add --label, --help options
# - Add Help Text
# - Change to subroutines
# - Efficiency and Cleanup
# version 0.3
# - Convert to GPL (Thanks to Mark Stosberg)
# - Add usage
# version 0.2
# - add command line switches
# - add debug code
# - add SCHED _sfun keyword
# - fix typos
# version 0.1 - ALPHA CODE.
=head1 SYNOPSIS
cat /path/to/file*.ics | ical2rem.pl > ~/.ical2rem
All options have reasonable defaults:
--label Calendar name (Default: Calendar)
--lead-time Advance days to start reminders (Default: 3)
--todos, --no-todos Process Todos? (Default: Yes)
--heading Define a priority for static entries
--help Usage
--man Complete man page
Expects an ICAL stream on STDIN. Converts it to the format
used by the C<remind> script and prints it to STDOUT.
=head2 --label
ical2rem.pl --label "Bob's Calendar"
The syntax generated includes a label for the calendar parsed.
By default this is "Calendar". You can customize this with
the "--label" option.
=head2 --lead-time
ical2rem.pl --lead-time 3
How may days in advance to start getting reminders about the events. Defaults to 3.
=head2 --no-todos
ical2rem.pl --no-todos
If you don't care about the ToDos the calendar, this will suppress
printing of the ToDo heading, as well as skipping ToDo processing.
=head2 --heading
ical2rem.pl --heading "PRIORITY 9999"
Set an option on static messages output. Using priorities can made the static messages look different from
the calendar entries. See the file defs.rem from the remind distribution for more information.
=cut
use strict;
use iCal::Parser;
use DateTime;
use Getopt::Long 2.24 qw':config auto_help';
use Pod::Usage;
use Data::Dumper;
use vars '$VERSION';
$VERSION = "0.5.2";
# Declare how many days in advance to remind
my $DEFAULT_LEAD_TIME = 3;
my $PROCESS_TODOS = 1;
my $HEADING = "";
my $help;
my $man;
my $label = 'Calendar';
GetOptions (
"label=s" => \$label,
"lead-time=i" => \$DEFAULT_LEAD_TIME,
"todos!" => \$PROCESS_TODOS,
"heading=s" => \$HEADING,
"help|?" => \$help,
"man" => \$man
);
pod2usage(1) if $help;
pod2usage(-verbose => 2) if $man;
my $month = ['None','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
my @calendars;
my $in;
while (<>) {
$in .= $_;
if (/END:VCALENDAR/) {
push(@calendars,$in);
$in = "";
}
}
my $parser = iCal::Parser->new();
my $hash = $parser->parse_strings(@calendars);
##############################################################
#
# Subroutines
#
#############################################################
#
# _process_todos()
# expects 'todos' hashref from iCal::Parser is input
# returns String to output
sub _process_todos {
my $todos = shift;
my ($todo, @newtodos, $leadtime);
my $output = "";
$output .= 'REM '.$HEADING.' MSG '.$label.' ToDos:%"%"%'."\n";
# For sorting, make sure everything's got something
# To sort on.
my $now = DateTime->now;
for $todo (@{$todos}) {
# remove completed items
if ($todo->{'STATUS'} && $todo->{'STATUS'} eq 'COMPLETED') {
next;
} elsif ($todo->{'DUE'}) {
# All we need is a due date, everything else is sugar
$todo->{'SORT'} = $todo->{'DUE'}->clone;
} elsif ($todo->{'DTSTART'}) {
# for sorting, sort on start date if there's no due date
$todo->{'SORT'} = $todo->{'DTSTART'}->clone;
} else {
# if there's no due or start date, just make it now.
$todo->{'SORT'} = $now;
}
push(@newtodos,$todo);
}
if (! (scalar @newtodos)) {
return "";
}
# Now sort on the new Due dates and print them out.
for $todo (sort { DateTime->compare($a->{'SORT'}, $b->{'SORT'}) } @newtodos) {
my $due = $todo->{'SORT'}->clone();
my $priority = "";
if (defined($todo->{'PRIORITY'})) {
if ($todo->{'PRIORITY'} == 1) {
$priority = "PRIORITY 1000";
} elsif ($todo->{'PRIORITY'} == 3) {
$priority = "PRIORITY 7500";
}
}
if (defined($todo->{'DTSTART'}) && defined($todo->{'DUE'})) {
# Lead time is duration of task + lead time
my $diff = ($todo->{'DUE'}->delta_days($todo->{'DTSTART'})->days())+$DEFAULT_LEAD_TIME;
$leadtime = "+".$diff;
} else {
$leadtime = "+".$DEFAULT_LEAD_TIME;
}
$output .= "REM ".$due->month_abbr." ".$due->day." ".$due->year." $leadtime $priority MSG \%a $todo->{'SUMMARY'}\%\"\%\"\%\n";
}
$output .= 'REM '.$HEADING.' MSG %"%"%'."\n";
return $output;
}
#######################################################################
#
# Main Program
#
######################################################################
print _process_todos($hash->{'todos'}) if $PROCESS_TODOS;
my ($leadtime, $yearkey, $monkey, $daykey,$uid,%eventsbyuid);
print 'REM '.$HEADING.' MSG '.$label.' Events:%"%"%'."\n";
my $events = $hash->{'events'};
foreach $yearkey (sort keys %{$events} ) {
my $yearevents = $events->{$yearkey};
foreach $monkey (sort {$a <=> $b} keys %{$yearevents}){
my $monevents = $yearevents->{$monkey};
foreach $daykey (sort {$a <=> $b} keys %{$monevents} ) {
my $dayevents = $monevents->{$daykey};
foreach $uid (sort {
DateTime->compare($dayevents->{$a}->{'DTSTART'}, $dayevents->{$b}->{'DTSTART'})
} keys %{$dayevents}) {
my $event = $dayevents->{$uid};
if ($eventsbyuid{$uid}) {
my $curreventday = $event->{'DTSTART'}->clone;
$curreventday->truncate( to => 'day' );
$eventsbyuid{$uid}{$curreventday->epoch()} =1;
for (my $i = 0;$i < $DEFAULT_LEAD_TIME && !defined($event->{'LEADTIME'});$i++) {
if ($eventsbyuid{$uid}{$curreventday->subtract( days => $i+1 )->epoch() }) {
$event->{'LEADTIME'} = $i;
}
}
} else {
$eventsbyuid{$uid} = $event;
my $curreventday = $event->{'DTSTART'}->clone;
$curreventday->truncate( to => 'day' );
$eventsbyuid{$uid}{$curreventday->epoch()} =1;
}
}
}
}
}
foreach $yearkey (sort keys %{$events} ) {
my $yearevents = $events->{$yearkey};
foreach $monkey (sort {$a <=> $b} keys %{$yearevents}){
my $monevents = $yearevents->{$monkey};
foreach $daykey (sort {$a <=> $b} keys %{$monevents} ) {
my $dayevents = $monevents->{$daykey};
foreach $uid (sort {
DateTime->compare($dayevents->{$a}->{'DTSTART'}, $dayevents->{$b}->{'DTSTART'})
} keys %{$dayevents}) {
my $event = $dayevents->{$uid};
if (exists($event->{'LEADTIME'})) {
$leadtime = "+".$event->{'LEADTIME'};
} else {
$leadtime = "+".$DEFAULT_LEAD_TIME;
}
my $start = $event->{'DTSTART'};
print "REM ".$start->month_abbr." ".$start->day." ".$start->year." $leadtime ";
if ($start->hour > 0) {
print " AT ";
print $start->strftime("%H:%M");
print " SCHED _sfun MSG %a %2 ";
} else {
print " MSG %a ";
}
print "%\"$event->{'SUMMARY'}";
print " at $event->{'LOCATION'}" if $event->{'LOCATION'};
print "\%\"%\n";
}
}
}
}
exit 0;
#:vim set ft=perl ts=4 sts=4 expandtab :

View File

@@ -109,18 +109,15 @@
(defconst remind-keywords
(sort
(list "ADDOMIT" "AFTER" "AT" "BANNER" "BEFORE"
"CAL" "CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMPVARS"
"DURATION" "ELSE" "ENDIF" "ERRMSG" "EXIT" "FIRST"
"FLUSH" "FOURTH" "FROM" "FSET" "IF" "IFTRIG" "IN"
"INCLUDE" "INCLUDECMD" "LAST" "LASTDAY"
"LASTWORKDAY" "MAYBE-UNCOMPUTABLE" "MSF"
"MSG" "OMIT" "OMITFUNC" "ONCE"
"POP-OMIT-CONTEXT" "PRESERVE" "PRIORITY" "PS" "PSFILE"
"PUSH-OMIT-CONTEXT" "REM" "RUN" "SATISFY" "SCANFROM"
"SCHED" "SECOND" "SET" "SKIP" "SPECIAL"
"TAG" "THIRD" "THROUGH" "UNSET" "UNTIL"
"WARN")
(list "ADDOMIT" "AFTER" "AT" "BAN" "BANNER" "BEFORE" "CAL" "CLEAR"
"CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMP" "DUMPVARS" "DURATION" "ELSE"
"ENDIF" "ERRMSG" "EXIT" "EXPR" "FIRST" "FLUSH" "FOURTH" "FROM" "FSET"
"FUNSET" "IF" "IFTRIG" "IN" "INC" "INCLUDE" "INCLUDECMD" "LAST"
"LASTDAY" "LASTWORKDAY" "MAYBE" "MAYBE-UNCOMPUTABLE" "MSF" "MSG"
"NOQUEUE" "OMIT" "OMITFUNC" "ONCE" "POP" "POP-OMIT-CONTEXT" "PRESERVE"
"PRIORITY" "PS" "PSFILE" "PUSH" "PUSH-OMIT-CONTEXT" "REM" "RUN"
"SATISFY" "SCAN" "SCANFROM" "SCHED" "SECOND" "SET" "SKIP" "SPECIAL"
"TAG" "THIRD" "THROUGH" "UNSET" "UNTIL" "WARN")
#'(lambda (a b) (> (length a) (length b)))))
@@ -131,50 +128,57 @@
(defconst remind-builtin-variables
(sort
(list "$Ago" "$Am" "$And" "$April" "$At" "$August" "$CalcUTC" "$CalMode" "$Daemon" "$DateSep"
"$DateTimeSep" "$December" "$DefaultColor" "$DefaultPrio"
"$DefaultTDelta" "$DeltaOffset" "$DontFork" "$DontQueue"
"$DontTrigAts" "$EndSent" "$EndSentIg" "$February" "$FirstIndent"
"$FoldYear" "$FormWidth" "$Friday" "$Fromnow" "$Hour" "$Hplu" "$HushMode" "$IgnoreOnce"
"$InfDelta" "$IntMax" "$IntMin" "$Is" "$January" "$July" "$June" "$LatDeg"
"$Latitude" "$LatMin" "$LatSec" "$Location" "$LongDeg" "$Longitude"
"$LongMin" "$LongSec" "$March" "$MaxSatIter" "$MaxStringLen" "$May"
"$MinsFromUTC" "$Minute" "$Monday" "$Mplu" "$NextMode" "$November" "$Now" "$NumQueued"
"$NumTrig" "$October" "$On" "$Pm" "$PrefixLineNo" "$PSCal" "$RunOff" "$Saturday"
"$September" "$SimpleCal" "$SortByDate" "$SortByPrio" "$SortByTime"
"$SubsIndent" "$Sunday" "$SysInclude" "$T" "$Td" "$Thursday" "$TimeSep" "$Tm"
"$Today" "$Tomorrow" "$Tuesday" "$Tw" "$Ty" "$U" "$Ud" "$Um" "$UntimedFirst" "$Uw" "$Uy"
"$Was" "$Wednesday")
(list "$AddBlankLines" "$Ago" "$Am" "$And" "$April" "$At" "$August"
"$CalcUTC" "$CalMode" "$Daemon" "$DateSep" "$DateTimeSep" "$December"
"$DefaultColor" "$DefaultPrio" "$DefaultTDelta" "$DeltaOverride"
"$DontFork" "$DontQueue" "$DontTrigAts" "$EndSent" "$EndSentIg"
"$ExpressionTimeLimit" "$February" "$FirstIndent" "$FoldYear"
"$FormWidth" "$Friday" "$Fromnow" "$Hour" "$Hplu" "$HushMode"
"$IgnoreOnce" "$InfDelta" "$IntMax" "$IntMin" "$Is" "$January" "$July"
"$June" "$LatDeg" "$Latitude" "$LatMin" "$LatSec" "$Location"
"$LongDeg" "$Longitude" "$LongMin" "$LongSec" "$March" "$MaxFullOmits"
"$MaxLateMinutes" "$MaxPartialOmits" "$MaxSatIter" "$MaxStringLen"
"$May" "$MinsFromUTC" "$Minute" "$Monday" "$Mplu" "$NextMode"
"$November" "$Now" "$NumFullOmits" "$NumPartialOmits" "$NumQueued"
"$NumTrig" "$October" "$On" "$OnceFile" "$ParseUntriggered" "$Pm"
"$PrefixLineNo" "$PSCal" "$RunOff" "$Saturday" "$September"
"$SimpleCal" "$SortByDate" "$SortByPrio" "$SortByTime" "$SubsIndent"
"$Sunday" "$SuppressImplicitWarnings" "$SuppressLRM" "$SysInclude" "$T" "$Td"
"$TerminalBackground" "$Thursday" "$TimeSep" "$Tm" "$Today"
"$Tomorrow" "$Tt" "$Tuesday" "$Tw" "$Ty" "$U" "$Ud" "$Um"
"$UntimedFirst" "$Use256Colors" "$UseBGVTColors" "$UseTrueColors"
"$UseVTColors" "$Uw" "$Uy" "$Was" "$Wednesday")
#'(lambda (a b) (> (length a) (length b)))))
(defconst remind-time-words
(sort
(list "Jan" "January" "Feb" "Mar" "Apr" "Jun" "Jul" "Aug" "Sept" "Sep" "Oct" "Nov" "Dec"
"February" "March" "April" "May" "June" "July" "August" "September" "October"
"November" "December" "Mon" "Monday" "Tue" "Tues" "Tuesday" "Wed" "Wednesday"
"Thu" "Thursday" "Thurs" "Fri" "Friday" "Saturday" "Sat" "Sun" "Sunday")
(list "Apr" "April" "Aug" "August" "Dec" "December" "Feb" "February"
"Jan" "January" "Jul" "July" "Jun" "June" "Mar" "March" "May"
"Nov" "November" "Oct" "October" "Sep" "September" "Fri"
"Friday" "Mon" "Monday" "Sat" "Saturday" "Sun" "Sunday" "Thu"
"Thursday" "Tue" "Tuesday" "Wed" "Wednesday")
#'(lambda (a b) (> (length a) (length b)))))
(defconst remind-builtin-functions
(sort
(list "abs" "access" "adawn" "adusk" "ampm" "args" "asc" "baseyr" "char"
"choose" "coerce" "current" "date" "datepart" "datetime" "dawn" "day"
"daysinmon" "defined" "dosubst" "dusk" "easterdate" "evaltrig"
"filedate" "filedatetime" "filedir" "filename" "getenv" "hebdate"
"hebday" "hebmon" "hebyear" "hour" "iif" "index" "isany" "isdst"
"isleap" "isomitted" "language" "lower" "max" "min" "minsfromutc"
(list "abs" "access" "adawn" "adusk" "ampm" "ansicolor" "args" "asc"
"baseyr" "char" "choose" "coerce" "columns" "current" "date"
"datepart" "datetime" "dawn" "day" "daysinmon" "defined" "dosubst"
"dusk" "easterdate" "evaltrig" "filedate" "filedatetime" "filedir"
"filename" "getenv" "hebdate" "hebday" "hebmon" "hebyear" "hour"
"htmlescape" "htmlstriptags" "iif" "index" "isany" "isdst" "isleap"
"isomitted" "language" "localtoutc" "lower" "max" "min" "minsfromutc"
"minute" "mon" "monnum" "moondate" "moondatetime" "moonphase"
"moontime" "ndawn" "ndusk" "nonomitted" "now" "ord" "ostype" "pad" "plural"
"psmoon" "psshade" "realcurrent" "realnow" "realtoday" "sgn" "shell"
"shellescape" "slide" "strlen" "substr" "sunrise" "sunset" "time"
"timepart" "today" "trig" "trigback" "trigdate" "trigdatetime"
"trigdelta" "trigduration" "trigeventduration" "trigeventstart"
"trigfrom" "trigger" "trigpriority" "trigrep" "trigscanfrom"
"trigtime" "trigtimedelta" "trigtimerep" "triguntil" "trigvalid"
"typeof" "tzconvert" "upper" "value" "version" "weekno" "wkday"
"wkdaynum" "year")
"moontime" "multitrig" "ndawn" "ndusk" "nonomitted" "now" "ord"
"orthodoxeaster" "ostype" "pad" "plural" "psmoon" "psshade"
"realcurrent" "realnow" "realtoday" "rows" "sgn" "shell" "shellescape"
"slide" "soleq" "stdout" "strlen" "substr" "sunrise" "sunset" "time"
"timepart" "timezone" "today" "trig" "trigback" "trigdate"
"trigdatetime" "trigdelta" "trigduration" "trigeventduration"
"trigeventstart" "trigfrom" "trigger" "trigpriority" "trigrep"
"trigscanfrom" "trigtags" "trigtime" "trigtimedelta" "trigtimerep"
"triguntil" "trigvalid" "typeof" "tzconvert" "upper" "utctolocal"
"value" "version" "weekno" "wkday" "wkdaynum" "year")
#'(lambda (a b) (> (length a) (length b)))))
;;; faces
@@ -290,7 +294,7 @@
(defconst remind-conf-font-lock-keywords-1
(list
'("^[\;\#]\\s-+.*$" . remind-comment-face)
'("^\s*[\;\#].*$" . remind-comment-face)
'(remind-keywords-matcher . remind-conf-keyword-face)
'("%[\"_]" . font-lock-warning-face)
'("\\(%[a-mops-w]\\)" . remind-conf-substitutes-face)

View File

@@ -1,8 +1,147 @@
CHANGES TO REMIND
* VERSION 5.0 Patch 7 - 2024-10-16
- NEW FEATURE: tkremind: Add option to create a desktop notification when
a queued reminder is triggered. For Tcl/Tk 9.0 or later, uses the native
"tk sysnotify" facility. For earlier versions of Tcl/Tk, executes the
"notify-send" program if possible.
- NEW FEATURE: remind: Add --print-config-cmd option which prints the
exact ./configure command used to build Remind. This will let you
configure future Remind releases exactly the same way an installed
version was configured.
- UPDATE: include/holidays/ca.rem: Add National Day for Truth and
Reconciliation to Canadian holiday list.
- MINOR IMPROVEMENTS: Update examples/ansitext and examples/astro
- MINOR IMPROVEMENT: remind: Use HashPJW to hash variable and function
names; make the hash table size a prime rather than a power of two.
This seems to improve hash performance ever so slightly in most cases.
- UPDATE: Update contrib/ical2rem to upstream version 0.7.1
- FIX: tkremind: Make tkremind work with Tcl/Tk 8.5 or higher, including
Tcl/Tk 9.0
- MINOR CHANGE: remind: Add hash table statistics to "-ds" debugging
output. This is probably of no use to anyone except the author of
Remind.
* VERSION 5.0 Patch 6 - 2024-09-16
- NEW FEATURE: remind: Include a file containing the dates of Chinese
New Year through 2050.
- NEW FEATURE: remind: Add $SuppressImplicitWarnings system variable.
Setting this to 1 suppresses the warnings "Unrecognized command;
interpreting as REM" and "Missing REM type; assuming MSG"
- NEW FEATURE: remind: Add --print-tokens command-line argument. This
simply prints all of Remind's built-in tokens, functions, and system
variables. It's designed to help people who are writing editor
add-ons for syntax highlighting.
- CHANGE: remind: allow '12:34' to be parsed as a TIME constant. This
matches DATEs and DATETIMEs which are enclosed in single-quotes.
(The quotes are optional for TIME constants, however.)
- IMPROVEMENT: Improve many error messages and warnings.
- UPDATE: contrib/ical2rem: Update to upstream version 0.7
- IMPROVEMENT: contrib/remind-conf-mode: Improve the Emacs
remind-conf-mode package. Add new keywords and make comment
highlighting correct.
- FIX: remind man page: Remove note saying REM can be omitted.
* VERSION 5.0 Patch 5 - 2024-09-02
- CHANGE: remind: When using the "-c" option and with the SHADE special
enabled, shade the entire calendar box including the line containing the
day number.
- IMPROVEMENT: remind: Better error messages when diagnosing certain
errors in expressions.
- IMPROVEMENT: include/holidays/jewish.rem: Remove unnecessary _h()
function definition.
- BUG FIX: remind: In a couple of spots when we parsed a character, we did
not check for an error return. This has been fixed.
- BUG FIX: remind: Fix edge-case bugs in "remind -c" output formatting.
- BUG FIX: make test: Fix a test that was broken for all of September 2024.
- BUG FIX: remind: Fix a couple of potential file-descriptor leaks.
- BUG FIX: contrib/ical2rem.pl: Replace "SCHED _sfun" with "+15" to
hard-code 15-minutes advance warning rather than using an undefined
scheduling function. If this is not what you want, you should edit
ical2rem.pl to suit your taste; it's not officially part of Remind and
is meant more as a starting point for you to customize than a finished
product.
- DOCUMENTATION FIX: Remove obsolete info from Remind man page.
* VERSION 5.0 Patch 4 - 2024-08-29
- IMPROVEMENT: remind: When checking if a SATISFY expression refers to the
trigger date, look recursively at any user-defined functions it calls.
This reduces spurious warnings.
- CHANGE: remind: Allow any type to be used as the test argument for IIF.
- IMPROVEMENT: remind man page: Clarify how various types are treated
in boolean context.
* VERSION 5.0 Patch 3 - 2024-08-28
- IMPROVEMENT: remind: Preserve newlines ("%_" sequences) in calendar
mode in most cases. See the remind man page for details.
- IMPROVEMENT: rem2pdf: rem2pdf can now produce PostScript and
Encapsulated PostScript output in addition to PDF and SVG.
- IMPROVEMENT: remind: Emit warnings if a subst_XXX function takes the
wrong number of arguments, or for custom sequences, if the function
is not defined.
- IMPROVEMENT: remind: Emit warnings if WARN/SCHED/OMITFUNC functions
do not reference their argument.
- IMPROVEMENT: remind: Allow strings to be used with logical
operators. The empty string "" is considered false and all other
strings are considered true.
- IMPROVEMENT: remind: Emit warnings for lines that are implicitly
treated as REM commands; add warnings for REM commands that are
implicitly treated as MSG-type reminders.
- IMPROVEMENT: remind: Add an optional fourth argument to the built-in
ampm() function that specifies not to suppress a leading zero in the
hour component.
- IMPROVEMENT: remind: If a SATISFY expression is not constant and
doesn't reference the trigger date somehow, issue a warning.
- IMPROVEMENT: remind: Add a warning if a user-defined function is
redefined. If you do have a use-case that requires you to redefine
a function, simply FUNSET it first before FSETting it for the second
time.
- DOCUMENTATION FIX: Clarify man pages and remove some information that
has become incorrect as Remind has evolved.
- BUG FIX: Fix typos in man pages
* VERSION 5.0 Patch 2 - 2024-07-26
* IMPROVEMENT: Remind: Revamp how ONCE works. You can now set a
- IMPROVEMENT: Remind: Revamp how ONCE works. You can now set a
special variable $OnceFile to be the path to a timestamp file. The
ONCE directive uses this timestamp file to track when it was last
run rather than the access date of the main reminder script. This
@@ -10,38 +149,38 @@ CHANGES TO REMIND
(which might not be maintained accurately) and is not affected if
you edit your reminder script.
* CHANGE: Taking input from stdin no longer implies the "-o" option; ONCE can
- CHANGE: Taking input from stdin no longer implies the "-o" option; ONCE can
work if you set $OnceFile
* CHANGE: Any of the -c, -n, -p and -s options implicitly enable the
- CHANGE: Any of the -c, -n, -p and -s options implicitly enable the
-o option. As before, specifying a repeat factor *N or a date that
is not today on the command-line also implies -o.
* MINOR NEW FEATURE: Rem2PDF: Add the "--svg" command-line option to produce
- MINOR NEW FEATURE: Rem2PDF: Add the "--svg" command-line option to produce
SVG output rather than PDF.
* MINOR IMPROVEMENT: Remind: Improve the storage efficiency of short
- MINOR IMPROVEMENT: Remind: Improve the storage efficiency of short
string constants in compiled expression trees.
* MINOR IMPROVEMENT: Remind: Remove some obsolete macro definitions
- MINOR IMPROVEMENT: Remind: Remove some obsolete macro definitions
* VERSION 5.0 Patch 1 - 2024-06-08
* MINOR IMPROVEMENT: Add short-circuit evaluation to the isany() function,
- MINOR IMPROVEMENT: Add short-circuit evaluation to the isany() function,
which now only evaluates those arguments absolutely necessary to determine
the result.
* BUG FIX: Mark weekno() as a non-constant function (the zero-argument form
- BUG FIX: Mark weekno() as a non-constant function (the zero-argument form
depends on external conditions.)
* BUG FIX: Fix a couple of memory leaks.
- BUG FIX: Fix a couple of memory leaks.
* BUG FIX: Don't rely on support for unnamed function parameters; this caused
- BUG FIX: Don't rely on support for unnamed function parameters; this caused
compilation failures with older versions of gcc.
* VERSION 5.0 Patch 0 - 2024-06-06
* MAJOR CHANGE: The expression evaluation engine has been completely replaced
- MAJOR CHANGE: The expression evaluation engine has been completely replaced
with a new one that splits parsing and evaluating into two separate steps.
It also features short-circuit evaluation of &&, ||, iif() and choose().
This should speed up expression-heavy reminder files.
@@ -72,56 +211,56 @@ CHANGES TO REMIND
and it will work for values of n that don't cause integer overflow.
* IMPROVEMENT: If there's an unmatched PUSH-OMIT-CONTEXT, print the
- IMPROVEMENT: If there's an unmatched PUSH-OMIT-CONTEXT, print the
filename and line number containing it.
* IMPROVEMENT: If there's an IF with a missing ENDIF, print the filename
- IMPROVEMENT: If there's an IF with a missing ENDIF, print the filename
and line number of the IF statement.
* NEW FEATURE: Add EXPR OFF command to completely disable expression
- NEW FEATURE: Add EXPR OFF command to completely disable expression
evaluation. Useful if you INCLUDE files that you don't expect to
contain expressions and may come from slightly untrustworthy sources.
* NEW FEATURE: Add $ExpressionTimeLimit system variable to enforce a
- NEW FEATURE: Add $ExpressionTimeLimit system variable to enforce a
maximum limit on how long evaluating an expression is allowed to take.
* NEW FEATURE: Add --max-execution-time=n command-line option to terminate
- NEW FEATURE: Add --max-execution-time=n command-line option to terminate
Remind if it runs for more than n seconds.
* CHANGE: Make the command-line option "-ifoo" equivalent to "-ifoo=0"
- CHANGE: Make the command-line option "-ifoo" equivalent to "-ifoo=0"
* CHANGE: Permit a literal [ in a reminder by using the sequence [[
- CHANGE: Permit a literal [ in a reminder by using the sequence [[
The old ["["] still works.
* BUG FIX: In "purge" mode, Remind would sometimes purge reminders with
- BUG FIX: In "purge" mode, Remind would sometimes purge reminders with
a relative "SCANFROM" which haven't actually expired. This has been fixed.
* BUG FIX: Disallow something like: FSET func(x, x) expr
- BUG FIX: Disallow something like: FSET func(x, x) expr
which shouldn't have been allowed in the first place.
* BUG FIX: Replace leading spaces with tabs in Makefiles (per Emanuele Torre
- BUG FIX: Replace leading spaces with tabs in Makefiles (per Emanuele Torre
and Tim Chase)
* VERSION 4.3 Patch 7 - 2024-04-29
* IMPROVEMENT: build.tk: Add a note if build.tk obtains default settings
- IMPROVEMENT: build.tk: Add a note if build.tk obtains default settings
from an existing Remind installation.
* IMPROVEMENT: configure: Pass all args to AC_INIT including the Remind
- IMPROVEMENT: configure: Pass all args to AC_INIT including the Remind
home page. Remove some unused autoconf cruft.
* IMPROVEMENT: Use standard C library versions of strdup, strcasecmp and
- IMPROVEMENT: Use standard C library versions of strdup, strcasecmp and
strncasecmp where available, rather than using our own versions.
* MINOR FEATURE: remind: Make $Tt a synonym for trigtime().
- MINOR FEATURE: remind: Make $Tt a synonym for trigtime().
* BUG FIX: remind: Make sure shellescape() doesn't mangle UTF-8 characters
- BUG FIX: remind: Make sure shellescape() doesn't mangle UTF-8 characters
with high-bits set.
* BUG FIX: remind: Don't rely on undefined behavior of "%" operator in
- BUG FIX: remind: Don't rely on undefined behavior of "%" operator in
the ord() built-in function.
* BUG FIX: remind: Do not clear out trigtime() unnecessarily. Before,
- BUG FIX: remind: Do not clear out trigtime() unnecessarily. Before,
you could not write things like the following; now you can:
REM Tue AT 11:30 DURATION 0:30 MSG Thing 1
@@ -131,90 +270,90 @@ CHANGES TO REMIND
for successive reminders that should be moved as a block if the time of
the first one changes.
* BUG FIX: Don't update trigdate() or trigtime() while parsing a REM
- BUG FIX: Don't update trigdate() or trigtime() while parsing a REM
statement... only when actually computing the trigger.
* VERSION 4.3 Patch 6 - 2024-04-02
* NEW FILE: Add [$SysInclude]/holidays/pt.rem - Portuguese holidays, courtesy
- NEW FILE: Add [$SysInclude]/holidays/pt.rem - Portuguese holidays, courtesy
of Joop Kiefte.
* BUG FIX: remind: Fix compile error on systems that don't support inotify(7).
- BUG FIX: remind: Fix compile error on systems that don't support inotify(7).
* BUG FIX: remind: Fix test failures on FreeBSD. On FreeBSD, you have to copy
- BUG FIX: remind: Fix test failures on FreeBSD. On FreeBSD, you have to copy
the result of getenv() or else a subsequent setenv() can change the stored
value.
* VERSION 4.3 Patch 5 - 2024-04-01
* IMPROVEMENT: remind: Use inotify to detect reminder file changes
- IMPROVEMENT: remind: Use inotify to detect reminder file changes
even in regular daemon mode (-zn where n>0).
* INTERNAL IMPROVEMENTS: Rearrange and refactor some code.
- INTERNAL IMPROVEMENTS: Rearrange and refactor some code.
* FIXES: Various fixes and improvements to man pages.
- FIXES: Various fixes and improvements to man pages.
* BUG FIX: remind: Handle queued "SPECIAL COLOR" reminders correctly.
- BUG FIX: remind: Handle queued "SPECIAL COLOR" reminders correctly.
* BUG FIX: remind: Preserve the value of $DefaultColor that was in effect
- BUG FIX: remind: Preserve the value of $DefaultColor that was in effect
when a reminder was queued; restore it before issuing the queued reminder.
* VERSION 4.3 Patch 4 - 2024-03-25
* NEW FEATURE: remind: Add the new "multitrig" function, which is how "trig"
- NEW FEATURE: remind: Add the new "multitrig" function, which is how "trig"
should have worked in the first place. See man page for details.
* IMPROVEMENT: tkremind: Make errors in your reminders file stand out more
- IMPROVEMENT: tkremind: Make errors in your reminders file stand out more
prominently.
* IMPROVEMENT: tkremind: If you click on an error in the "Errors..." popup,
- IMPROVEMENT: tkremind: If you click on an error in the "Errors..." popup,
tkremind will open a text editor on the offending file and line.
* IMPROVEMENT: tkremind: Format the "Queue..." output better and make queue
- IMPROVEMENT: tkremind: Format the "Queue..." output better and make queue
items clickable; clicking on a queue item opens a text editor on the
corresponding file and line.
* IMPROVEMENT: Add a standard [$SysInclude]/moonphases.rem file to display
- IMPROVEMENT: Add a standard [$SysInclude]/moonphases.rem file to display
moon phases on your calendar.
* IMPROVEMENT: Clean up the demo code in www/ and add PDF output.
- IMPROVEMENT: Clean up the demo code in www/ and add PDF output.
* BUG FIX: tkremind: Correctly handle filenames containing spaces and other
- BUG FIX: tkremind: Correctly handle filenames containing spaces and other
characters that tend to confuse the shell.
* BUG FIX: tkremind: Raise dialog boxes after errors so that they
- BUG FIX: tkremind: Raise dialog boxes after errors so that they
remain visible.
* CLEANUP: tkremind: Remove some dead code.
- CLEANUP: tkremind: Remove some dead code.
* VERSION 4.3 Patch 3 - 2024-03-18
* IMPROVEMENT: tkremind: Update icon to include a white border so it shows
- IMPROVEMENT: tkremind: Update icon to include a white border so it shows
up better on dark backgrounds.
* IMPROVEMENT: C code: Fix a number of cppcheck static-analysis warnings.
- IMPROVEMENT: C code: Fix a number of cppcheck static-analysis warnings.
* IMPROVEMENT: remind: Update the "-zj" protocol to include a queue-id for
- IMPROVEMENT: remind: Update the "-zj" protocol to include a queue-id for
each queued reminder and add the DEL client command to delete a specific
item from the queue. Used by tkremind to implement "don't remind me about
this again today."
* MINOR NEW FEATURE: Add a "-ds" debugging flag to print out expression-parsing
- MINOR NEW FEATURE: Add a "-ds" debugging flag to print out expression-parsing
stack high-water marks on exit. This esoteric feature is of no use to
anyone but the Remind author.
* IMPROVEMENT: tkremind: Stop using the deprecated tk_dialog command in favor
- IMPROVEMENT: tkremind: Stop using the deprecated tk_dialog command in favor
of the newer tk_messageBox command.
* IMPROVEMENT: remind: In server mode, try to minimize redraws by
- IMPROVEMENT: remind: In server mode, try to minimize redraws by
consuming inotify events until at least 0.2s elapses without an
event appearing.
* BUG FIX: tkremind: The "Don't remind me about this again today" feature
- BUG FIX: tkremind: The "Don't remind me about this again today" feature
was unreliable and only worked for reminders created with TkRemind itself.
It has been made more reliable and works with any reminder.
* BUG FIX: remind: Make it a syntax error if a local OMIT in a REM statement
- BUG FIX: remind: Make it a syntax error if a local OMIT in a REM statement
is not followed by at least one weekday name.
* VERSION 4.3 Patch 2 - 2024-03-01
@@ -1187,7 +1326,7 @@ CHANGES TO REMIND
- MINOR IMPROVEMENT: Add the "ampm()" built-in function.
* Version 3.3 Patch 0 - 2020-01-31
* VERSION 3.3 Patch 0 - 2020-01-31
- FIX: rem2ps: Add a %%PageBoundingBox: document structuring convention
comment.
@@ -1222,7 +1361,7 @@ CHANGES TO REMIND
- 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
* VERSION 3.2 Patch 0 - 2020-01-03
- IMPROVEMENT: Add support for events spanning multiple days (with AT
and DURATION). Add trigeventstart() and trigeventduration()
@@ -1264,7 +1403,7 @@ CHANGES TO REMIND
- BUG FIX: TkRemind: Fix startup failure of TkRemind if options are at
default. :(
* Version 3.1 Patch 17 - 2019-11-15
* VERSION 3.1 Patch 17 - 2019-11-15
- IMPROVEMENT: Add "Extra Remind Options" setting to TkRemind.
@@ -1281,7 +1420,7 @@ CHANGES TO REMIND
- BUG FIX: Fix various documentation errors and update man page.
* Version 3.1 Patch 16 - 2018-11-09
* VERSION 3.1 Patch 16 - 2018-11-09
- IMPROVEMENT: Add patch from Stephen Morgan to calculate astronomical and
nautical twilight in addition to civil twilight.
@@ -1311,7 +1450,7 @@ CHANGES TO REMIND
- BUG FIX: In "remind -z0" mode, remind wakes up exactly on the minute instead
of sleeping for 60 seconds each time, which could cause it to fall behind.
* Version 3.1 Patch 15 - 2015-07-27
* VERSION 3.1 Patch 15 - 2015-07-27
- BUG FIX: Fix a buffer overflow found by Alexander Keller
@@ -1321,7 +1460,7 @@ CHANGES TO REMIND
- BUG FIX: Make parser reject repeated delta or *repeat values.
* Version 3.1 Patch 14 - 2015-04-24
* VERSION 3.1 Patch 14 - 2015-04-24
- NEW FEATURE: Putting the line __EOF__ in a .rem file causes Remind
to treat it as end-of-file.
@@ -1338,7 +1477,7 @@ CHANGES TO REMIND
- BUG FIX: Typo in Spanish translation was fixed.
* Version 3.1 Patch 13 - 2013-03-22
* VERSION 3.1 Patch 13 - 2013-03-22
- BUG FIX: Sunrise/Sunset calculations greatly improved thanks to John
McGowan. Accuracy should now be within a couple of minutes in most
@@ -1355,7 +1494,7 @@ CHANGES TO REMIND
- BUG FIX: Spurious test harness failure was fixed.
* Version 3.1 Patch 12 - 2012-01-23
* VERSION 3.1 Patch 12 - 2012-01-23
- NEW FEATURE: Many substitution sequences "%x" have an alternate mode
denoted by "%*x". This alternate mode leaves out prepositions. For
@@ -1367,7 +1506,7 @@ CHANGES TO REMIND
so the results may be off by a minute or two compared to previous versions
of Remind.
* Version 3.1 Patch 11 - 2011-12-16
* VERSION 3.1 Patch 11 - 2011-12-16
- BUG FIX: For some inexplicable reason, dawn was considered to happen when
the sun was 14 degrees below the horizon instead of the standard 6
@@ -1381,7 +1520,7 @@ CHANGES TO REMIND
- BUG FIX: Apply minor Debian cleanups reported by Kurt B. Kaiser.
* Version 3.1 Patch 10 - 2010-11-01
* VERSION 3.1 Patch 10 - 2010-11-01
- NOTE: This is the 20th anniversary of Remind's first public release.
@@ -1405,7 +1544,7 @@ CHANGES TO REMIND
- BUG FIX: Don't declare variables in the middle of statements (old C
compilers choke.)
* Version 3.1 Patch 9 - 2010-06-20
* VERSION 3.1 Patch 9 - 2010-06-20
- MAJOR ENHANCEMENT: New "purge mode" to delete expired reminders. See
the PURGE MODE section of the remind man page.
@@ -1421,7 +1560,7 @@ CHANGES TO REMIND
- BUG FIX: Yom HaShoah is moved to Thursday if it would normally fall on
a Friday. Thanks to Jonathan Kamens for pointing this out.
* Version 3.1 Patch 8 - 2010-03-09
* VERSION 3.1 Patch 8 - 2010-03-09
- ENHANCEMENT: Include some useful scripts in contrib/
@@ -1441,7 +1580,7 @@ CHANGES TO REMIND
- BUG FIX: Fix bug in SCHED calculations if Remind is started in the middle
of a SCHED interval.
* Version 3.1 Patch 7 - 2009-05-31
* VERSION 3.1 Patch 7 - 2009-05-31
- ENHANCEMENT: Wherever you could write "day Mon year", the parser now
accepts "YYYY-MM-DD". This applies on the command-line and to the
@@ -1450,7 +1589,7 @@ CHANGES TO REMIND
- ENHANCEMENT: New slide() built-in function eases some complicated reminders.
* Version 3.1 Patch 6 - 2008-11-16
* VERSION 3.1 Patch 6 - 2008-11-16
- MAJOR ENHANCEMENT: A new OMITFUNC clause gives you additional
control and flexibility over "omitted days" calculations. This is
@@ -1478,7 +1617,7 @@ CHANGES TO REMIND
weekday would fail if it needed to cross a year boundary. This has
been fixed.
* Version 3.1 Patch 5 - 2008-04-15
* VERSION 3.1 Patch 5 - 2008-04-15
- MAJOR ENHANCEMENT: If you supply a directory name on the command line
or for an INCLUDE command, then Remind reads all *.rem file in that
@@ -1508,7 +1647,7 @@ CHANGES TO REMIND
- BUG FIX: Parse error in calendar mode was fixed.
* Version 3.1 Patch 4 - 2008-02-03
* VERSION 3.1 Patch 4 - 2008-02-03
- ENHANCEMENT: tkremind respects the "-b1" option and operates in 24-hour
clock mode if the option is supplied.
@@ -1530,7 +1669,7 @@ CHANGES TO REMIND
- BUG FIX: The "-ivar=value" command-line option failed if Remind re-execed
itself because we overwrote argv[]. This has been fixed.
* Version 3.1 Patch 3 - 2007-10-15
* VERSION 3.1 Patch 3 - 2007-10-15
+ MINOR ENHANCEMENTS
@@ -1549,7 +1688,7 @@ CHANGES TO REMIND
is not evaluated. This helps avoid spurious error messages in some
reminders.
* Version 3.1 Patch 2 - 2007-09-12
* VERSION 3.1 Patch 2 - 2007-09-12
+ MINOR ENHANCEMENTS
@@ -1603,7 +1742,7 @@ CHANGES TO REMIND
- Using the psshade() or psmoon() functions emits a warning on stderr. You
should use SPECIAL SHADE or SPECIAL MOON instead.
* Version 3.1 Patch 1 - 2007-08-23
* VERSION 3.1 Patch 1 - 2007-08-23
+ MAJOR ENHANCEMENTS
@@ -1633,7 +1772,7 @@ CHANGES TO REMIND
- Various man-page fixes.
* Version 3.1 Patch 0 - 2007-07-14
* VERSION 3.1 Patch 0 - 2007-07-14
+ MAJOR ENHANCEMENTS
@@ -1696,7 +1835,7 @@ CHANGES TO REMIND
- rem2ps would produce invalid PostScript in some rare cases
(eg, for February 2007). This has been fixed.
* Version 3.0 Patch 24 - 2005-11-19
* VERSION 3.0 Patch 24 - 2005-11-19
+ MINOR ENHANCEMENTS
@@ -1719,7 +1858,7 @@ CHANGES TO REMIND
- Fixed a bug in the tokenizer that could make Remind segfault. Fix courtesy
of Stan Tobias.
* Version 3.0 Patch 23 - 2005-04-14
* VERSION 3.0 Patch 23 - 2005-04-14
+ MINOR ENHANCEMENTS
@@ -1743,7 +1882,7 @@ CHANGES TO REMIND
- Fixed parser error for unterminated date constant: '2005/01/01
* Version 3.0 Patch 22 - 2000-06-16
* VERSION 3.0 Patch 22 - 2000-06-16
+ MINOR ENHANCEMENTS
@@ -1765,7 +1904,7 @@ CHANGES TO REMIND
- Fixed serious bug in which background queued reminders were ignored and
Remind simply exited. Doh! Sorry about that.
* Version 3.0 Patch 21 - 2000-03-15
* VERSION 3.0 Patch 21 - 2000-03-15
+ MINOR ENHANCEMENTS
@@ -1796,7 +1935,7 @@ CHANGES TO REMIND
- Fixed compilation problem on FreeBSD, IRIX, Tru64 and other UNIXes.
* Version 3.0 Patch 20 - 1999-04-12
* VERSION 3.0 Patch 20 - 1999-04-12
+ LICENSE CHANGE
@@ -1818,7 +1957,7 @@ CHANGES TO REMIND
- Fixed a typo in danish.h, courtesy of Niels Kristian Bech Jensen.
* Version 3.0 Patch 19 - 1998-05-09
* VERSION 3.0 Patch 19 - 1998-05-09
+ MAJOR ENHANCEMENTS
@@ -1860,7 +1999,7 @@ CHANGES TO REMIND
- Lots more silly little bugs squashed -- too many to go into in
detail.
* Version 3.0 Patch 18 - 1998-02-15
* VERSION 3.0 Patch 18 - 1998-02-15
+ MAJOR ENHANCEMENTS
@@ -1924,7 +2063,7 @@ CHANGES TO REMIND
- Getting rid of fixed-sized buffers meant lots of changes to code.
No doubt, I missed a few regression tests.
* Version 3.0 Patch 17 - 1997-09-07
* VERSION 3.0 Patch 17 - 1997-09-07
+ MINOR ENHANCEMENTS
@@ -1965,7 +2104,7 @@ CHANGES TO REMIND
library. All three of these fixes are courtesy of Christopher
J. Madsen <madsen@iglobal.net>. Thanks, Christopher.
* Version 3.0 Patch 16 - 1997-02-11
* VERSION 3.0 Patch 16 - 1997-02-11
+ MINOR ENHANCEMENTS
@@ -1993,7 +2132,7 @@ CHANGES TO REMIND
- Fixed a problem under Solaris 2.5 whereby rem2ps was skipping some
latin1 characters which it interpreted as white space.
* Version 3.0 Patch 15 - 1996-10-27
* VERSION 3.0 Patch 15 - 1996-10-27
+ IMPORTANT NOTES
@@ -2023,7 +2162,7 @@ CHANGES TO REMIND
- Fixed bug in TkRemind which caused a crash if the "-m" option was used
for a month beginning on Sunday. Doh!!!
* Version 3.0 Patch 14 - 1996-05-25
* VERSION 3.0 Patch 14 - 1996-05-25
+ CHANGE IN COPYING POLICY
@@ -2082,7 +2221,7 @@ CHANGES TO REMIND
_not_ support MS Windows, and in fact do not allow Remind to run
under Windows (see COPYRIGHT).
* Version 3.0 Patch 13 - 1994-05-06
* VERSION 3.0 Patch 13 - 1994-05-06
+ MINOR ENHANCEMENTS
@@ -2117,7 +2256,7 @@ CHANGES TO REMIND
- Updated the copyright notices everywhere.
* Version 3.0 Patch 12 - 1994-02-01
* VERSION 3.0 Patch 12 - 1994-02-01
+ MINOR ENHANCEMENTS
@@ -2136,7 +2275,7 @@ CHANGES TO REMIND
- Fixed a problem with the '-k' option which resulted in a newline being
placed after the message text. This was giving sh(1) heartburn...
* Version 3.0 Patch 11 - 1993-11-26
* VERSION 3.0 Patch 11 - 1993-11-26
+ MINOR ENHANCEMENTS
@@ -2168,7 +2307,7 @@ CHANGES TO REMIND
- Fixed typos in french.h
* Version 3.0 Patch 10
* VERSION 3.0 Patch 10
+ MAJOR ENHANCEMENT
@@ -2216,7 +2355,7 @@ CHANGES TO REMIND
- Fixed the Finnish language support which was missing a few newlines.
* Version 3.0 Patch 9 - 1993-10-04
* VERSION 3.0 Patch 9 - 1993-10-04
+ NOTES
@@ -2273,7 +2412,7 @@ CHANGES TO REMIND
so that newlines in the body start new paragraphs, rather than being
swallowed as white-space.
* Version 3.0 Patch 8 - 1993-09-08
* VERSION 3.0 Patch 8 - 1993-09-08
+ MAJOR ENHANCEMENTS
@@ -2325,7 +2464,7 @@ CHANGES TO REMIND
range [-128, 255] (but not 0) so that char(asc(s)) works even
on machines with signed char types.
* Version 3.0 Patch 7 - 1993-07-22
* VERSION 3.0 Patch 7 - 1993-07-22
+ MAJOR ENHANCEMENTS
@@ -2368,7 +2507,7 @@ CHANGES TO REMIND
- Changed kall so that "kall sh" doesn't commit suicide - patch courtesy
of Michael Salmon.
* Version 3.0 Patch 6 - 1993-05-05
* VERSION 3.0 Patch 6 - 1993-05-05
+ MINOR ENHANCEMENTS
@@ -2391,7 +2530,7 @@ CHANGES TO REMIND
- Fixed a bug in the -u option which sometimes caused a core dump
(embarrassed grin!) The fix is due to Tina Hoeltig. Thanks, Tina!
* Version 3.0 Patch 5 - 1993-04-27
* VERSION 3.0 Patch 5 - 1993-04-27
+ MAJOR ENHANCEMENTS:
@@ -2426,7 +2565,7 @@ CHANGES TO REMIND
- Fixed a bug in the man page - thanks to Ed Oskiewicz.
* Version 3.0 Patch 4 - 1993-03-08
* VERSION 3.0 Patch 4 - 1993-03-08
- Added the -g option - this sorts reminders by date/time before
issuing them. (You can see I'm running out of letters to
@@ -2485,13 +2624,13 @@ CHANGES TO REMIND
- Put my new mailing address in the README files.
* Version 3.0 Patch 3 - 1993-02-21
* VERSION 3.0 Patch 3 - 1993-02-21
- Corrected bugs in Remind and Rem2PS. No new features added. You
should NOT use patch level 2 - either stick to 3.0.1 or upgrade to
3.0.3.
* Version 3.0 Patch 2 - 1993-02-04
* VERSION 3.0 Patch 2 - 1993-02-04
- Added the -u option to Remind so that root can run it as any user.
This simplifies the remind-all scripts, and makes them more efficient.
@@ -2531,7 +2670,7 @@ CHANGES TO REMIND
- Changed Remind so that supplying the -a option causes timed reminders
not to be placed into the calendar in calendar mode.
* Version 3.0 Patch 1 - 1992-12-18
* VERSION 3.0 Patch 1 - 1992-12-18
- Wrote the Rem2ps program to produce PostScript calendars
@@ -2571,7 +2710,7 @@ CHANGES TO REMIND
- Re-formatted the WHATSNEW.30 file.
* Version 3.0 - 1992-11-09
* VERSION 3.0 - 1992-11-09
- Total rewrite from previous versions
@@ -2592,23 +2731,23 @@ CHANGES TO REMIND
- Fixed a lurking bug in trigger date calculation which, amazingly, had not
been caught in the couple of years that Remind has been out!
* Version 2.3 Patch 5 - 1992-04-11
* VERSION 2.3 Patch 5 - 1992-04-11
- Added the "c+n" option for printing a calendar by
weeks instead of months, courtesy Dennis Cottel (dennis@peanuts.nosc.mil).
* Version 2.3 Patch 4 - 1991-11-06
* VERSION 2.3 Patch 4 - 1991-11-06
- Made the init.c file nicer. Made the Makefile
prettier. Added "make test", "make tar" and "make shar" Makefile targets.
* Version 2.3 Patch 3 - 1991-09-11
* VERSION 2.3 Patch 3 - 1991-09-11
- Added a command-line option for Remind to process
queued reminders in the foreground. This makes automatic termination
of Remind processes from within X-Windows and Sunview easier.
* Version 2.3 Patch 2 - 1991-07-19
* VERSION 2.3 Patch 2 - 1991-07-19
- Fixed up a problem with timed reminders which resulted
in cursor not starting from left side of screen on some systems.
@@ -2625,7 +2764,7 @@ CHANGES TO REMIND
- Made the Makefile more portable
* Version 2.3 Patch 1 - 1991-03-08
* VERSION 2.3 Patch 1 - 1991-03-08
- Added the "-t" command-line option to get Remind
to trigger all non-expired reminders.
@@ -2639,7 +2778,7 @@ CHANGES TO REMIND
- Added manual pages for "kall" and "rem".
* Version 2.3 - 1991-02-20
* VERSION 2.3 - 1991-02-20
- Added the UNTIL keyword for forcing reminders to expire.
@@ -2661,32 +2800,32 @@ CHANGES TO REMIND
- Modified the calendar and SimpleCalendar formats so that the % escape
substitutions ARE performed.
* Version 2.2 - Patch 5 - 1990-12-03
* VERSION 2.2 - Patch 5 - 1990-12-03
- Added the BEFORE, AFTER and SKIP tokens to make the
handling of holidays more sensible. Also corrected a few more bugs.
* Version 2.2 - Patch 3 - 1990-11-28
* VERSION 2.2 - Patch 3 - 1990-11-28
- Added the MSG or RUN tokens in an OMIT command; also
allowed RUN-type reminders to be explicitly included in the calendar by
using the %" escape sequence.
* Version 2.2 - 1990-11-16
* VERSION 2.2 - 1990-11-16
- Added the AT keyword, the timed reminders daemon, and the
calendar facility.
* Version 2.1 - 1990-11-06
* VERSION 2.1 - 1990-11-06
- Added the "repeat" token for repeating reminders with a period
other than 7 days. Also fixed some bugs from version 2.0
* Version 2.0 - 1990-11-01
* VERSION 2.0 - 1990-11-01
- first public release. Included advanced date specifications,
character substitution, and the RUN keyword.
* Version 1.0
* VERSION 1.0
- never publicly released.

View File

@@ -26,7 +26,10 @@ MSG This is [ansicolor(0,255,0)]green.[ansicolor("")]
MSG This is [ansicolor(0,0,255)]blue.[ansicolor("")]
MSG This is [ansicolor(255,255,0)]yellow.[ansicolor("")]
MSG This is [ansicolor(255,0,255)]magenta.[ansicolor("")]
MSG This is [ansicolor(0,255,255)]cyan.[ansicolor("")]%_
MSG This is [ansicolor(0,255,255)]cyan.[ansicolor("")]
MSG This is [ansi_bold][ansicolor(255,255,255)][ansicolor(0,0,0,1)]white on black[ansicolor("")][ansi_normal]
MSG This is [ansi_bold][ansicolor(0,0,0)][ansicolor(255,255,255,1)]black on white[ansicolor("")][ansi_normal]
MSG %_
# You can combine attributes
MSG This is [ansicolor(0,255,0)][ansicolor(0,0,96,1)][ansi_italic][ansi_bold]Green-Bold-Italic-on-Blue[ansi_normal][ansicolor("")]

View File

@@ -5,9 +5,6 @@
# Best used in a UTF-8 environment.
# SPDX-License-Identifier: GPL-2.0-only
# Set this variable to 1 if your terminal has a dark background or 0 if
# it: light.
# Set your latitude and longitude correctly for Sunrise/Sunset/Equinox/Solstice
#
# The values below are for Ottawa, Ontario, Canada
@@ -20,7 +17,8 @@ BANNER %
INCLUDE [$SysInclude]/ansitext.rem
MSG Today is [ansi_bold][$T][ansi_normal], being the [ord($T-date(year($T),1,1)+1)] day of [year($T)].%_
MSG Today is [ansi_bold][$T][ansi_normal], being the [ord($T-date(year($T),1,1)+1)] day of [year($T)].
MSG Not including today, the year [year($T)] has [date(year($T)+1, 1, 1)-$T-1] more [plural(date(year($T)+1, 1, 1)-$T-1, "day")] left.%_
IF $TerminalBackground == 0
SPECIAL COLOR 255 255 0 Sunrise: 🌅 [sunrise()] today and [sunrise($T+1)] tomorrow

View File

@@ -6,6 +6,11 @@
# Cut and paste as desired! Also, near the end, there are a bunch of #
# holiday definitions for the U.S. #
# #
# *** NOTE *** #
# #
# This file is simply a grab-bag of examples. It is NOT meant to be #
# included as-is in a live reminder file. #
# #
# Some examples provided by George M. Sipe <gsipe@pyratl.ga.pyramid.com> #
# #
# U.S. holidays provided by Dave Rickel <drickel@sjc.mentorg.com> #
@@ -27,7 +32,7 @@ RUN OFF
# Ensure required version of remind is used... #
################################################
IF version() < "03.04.02"
ERRMSG This file requires at least version 03.01.10 of Remind.%
ERRMSG This file requires at least version 03.04.02 of Remind.%
ERRMSG This version is version [version()].
EXIT
ENDIF
@@ -305,51 +310,51 @@ FSET _PastMon(x, y) IIF(WKDAYNUM(_h2(x,y))!=1, _h2(x,y), _h2(x,y)+1)
SET InIsrael VALUE("InIsrael", 0)
SET Reform VALUE("Reform", 0)
[_h(1, "Tishrey")] ++4 MSG %"Rosh Hashana 1%" is %b.
REM [_h(1, "Tishrey")] ++4 MSG %"Rosh Hashana 1%" is %b.
# No RH-2 or Tzom Gedalia in Reform
IF !Reform
[_h(2, "Tishrey")] ++4 MSG %"Rosh Hashana 2%" is %b.
[_PastSat(3, "Tishrey")] ++4 MSG %"Tzom Gedalia%" is %b.
REM [_h(2, "Tishrey")] ++4 MSG %"Rosh Hashana 2%" is %b.
REM [_PastSat(3, "Tishrey")] ++4 MSG %"Tzom Gedalia%" is %b.
ENDIF
[_h(10, "Tishrey")] ++4 MSG %"Yom Kippur%" is %b.
[_h(15, "Tishrey")] ++4 MSG %"Sukkot 1%" is %b.
REM [_h(10, "Tishrey")] ++4 MSG %"Yom Kippur%" is %b.
REM [_h(15, "Tishrey")] ++4 MSG %"Sukkot 1%" is %b.
IF !InIsrael
[_h(16, "Tishrey")] MSG %"Sukkot 2%"
REM [_h(16, "Tishrey")] MSG %"Sukkot 2%"
ENDIF
[_h(21, "Tishrey")] ++4 MSG %"Hoshana Rabba%" is %b.
[_h(22, "Tishrey")] ++4 MSG %"Shemini Atzeret%" is %b.
REM [_h(21, "Tishrey")] ++4 MSG %"Hoshana Rabba%" is %b.
REM [_h(22, "Tishrey")] ++4 MSG %"Shemini Atzeret%" is %b.
IF InIsrael
[_h(22, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
REM [_h(22, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
ELSE
[_h(23, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
REM [_h(23, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
ENDIF
# Because Kislev can change length, we must be more careful about Chanukah
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%"
[_chan(4)] MSG %"Chanukah 4%"
[_chan(5)] MSG %"Chanukah 5%"
[_chan(6)] MSG %"Chanukah 6%"
[_chan(7)] MSG %"Chanukah 7%"
[_chan(8)] MSG %"Chanukah 8%"
REM [_chan(1)] ++4 MSG %"Chanukah 1%" is %b.
REM [_chan(2)] MSG %"Chanukah 2%"
REM [_chan(3)] MSG %"Chanukah 3%"
REM [_chan(4)] MSG %"Chanukah 4%"
REM [_chan(5)] MSG %"Chanukah 5%"
REM [_chan(6)] MSG %"Chanukah 6%"
REM [_chan(7)] MSG %"Chanukah 7%"
REM [_chan(8)] MSG %"Chanukah 8%"
# Not sure about Reform's position on the next one.
IF !Reform
# 10 Tevet will never be a Saturday, so whether or not to
# move it is moot. (Thanks to Art Werschulz.)
[_h(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
REM [_h(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
ENDIF
[_h(15, "Shvat")] ++4 MSG %"Tu B'Shvat%" is %b.
[_h(14, "Adar A")] ++4 MSG %"Purim Katan%" is %b.
[_h(15, "Adar A")] ++4 MSG %"Shushan Purim Katan%" is %b.
REM [_h(15, "Shvat")] ++4 MSG %"Tu B'Shvat%" is %b.
REM [_h(14, "Adar A")] ++4 MSG %"Purim Katan%" is %b.
REM [_h(15, "Adar A")] ++4 MSG %"Shushan Purim Katan%" is %b.
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
IF WKDAYNUM(_h2(13, "Adar")) != 6
@@ -357,18 +362,18 @@ IF WKDAYNUM(_h2(13, "Adar")) != 6
ELSE
REM [_h2(11, "Adar")] ++4 MSG %"Fast of Esther%" is %b.
ENDIF
[_h(14, "Adar")] ++4 MSG %"Purim%" is %b.
[_h(15, "Adar")] ++4 MSG %"Shushan Purim%" is %b.
[_h(15, "Nisan")] ++4 MSG %"Pesach%" is %b.
REM [_h(14, "Adar")] ++4 MSG %"Purim%" is %b.
REM [_h(15, "Adar")] ++4 MSG %"Shushan Purim%" is %b.
REM [_h(15, "Nisan")] ++4 MSG %"Pesach%" is %b.
IF !InIsrael
[_h(16, "Nisan")] MSG %"Pesach 2%"
REM [_h(16, "Nisan")] MSG %"Pesach 2%"
ENDIF
[_h(21, "Nisan")] MSG %"Pesach 7%"
REM [_h(21, "Nisan")] MSG %"Pesach 7%"
IF !InIsrael && !Reform
[_h(22, "Nisan")] MSG %"Pesach 8%"
REM [_h(22, "Nisan")] MSG %"Pesach 8%"
ENDIF
REM [_PastSun(27, "Nisan")] SATISFY 1
@@ -384,36 +389,36 @@ ENDIF
# Thursday. If 4 Iyar is a Sunday, then Yom Hazikaron
# moves to 5 Iyar and Yom Ha'atzmaut to 6 Iyar.
IF WKDAYNUM(_h2(4, "Iyar")) == 4 || WKDAYNUM(_h2(4, "Iyar")) == 5
[_h(2, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
[_h(3, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
REM [_h(2, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
REM [_h(3, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
ELSE
IF WKDAYNUM(_h2(4, "Iyar")) == 0
[_h(5, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
[_h(6, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
REM [_h(5, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
REM [_h(6, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
ELSE
[_h(4, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
[_h(5, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
REM [_h(4, "Iyar")] ++4 MSG %"Yom Hazikaron%" is %b.
REM [_h(5, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
ENDIF
ENDIF
# Not sure about Reform's position on Lag B'Omer
IF !Reform
[_h(18, "Iyar")] ++4 MSG %"Lag B'Omer%" is %b.
REM [_h(18, "Iyar")] ++4 MSG %"Lag B'Omer%" is %b.
ENDIF
[_h(28, "Iyar")] ++4 MSG %"Yom Yerushalayim%" is %b.
[_h(6, "Sivan")] ++4 MSG %"Shavuot%" is %b.
REM [_h(28, "Iyar")] ++4 MSG %"Yom Yerushalayim%" is %b.
REM [_h(6, "Sivan")] ++4 MSG %"Shavuot%" is %b.
IF !InIsrael && !Reform
[_h(7, "Sivan")] MSG %"Shavuot 2%"
REM [_h(7, "Sivan")] MSG %"Shavuot 2%"
ENDIF
# Fairly sure Reform Jews don't observe the next two
IF !Reform
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
# fall on a Saturday
[_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b.
[_PastSat(9, "Av")] ++4 MSG %"Tish'a B'Av%" is %b.
REM [_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b.
REM [_PastSat(9, "Av")] ++4 MSG %"Tish'a B'Av%" is %b.
ENDIF
# Counting the omer - do the whole spiel, i.e:

View File

@@ -20,6 +20,8 @@ REM First Monday in Aug SCANFROM -7 ADDOMIT MSG Civic Holiday
REM First Monday in Sep SCANFROM -7 ADDOMIT MSG Labour Day
REM 30 Sep MSG National Day for Truth and Reconciliation
REM Second Monday in Oct SCANFROM -7 ADDOMIT MSG Thanksgiving Day
REM 11 November MSG Remembrance Day

View File

@@ -0,0 +1,29 @@
REM 1 Feb 2022 MSG Chinese New Year (Tiger)
REM 22 Jan 2023 MSG Chinese New Year (Rabbit)
REM 10 Feb 2024 MSG Chinese New Year (Dragon)
REM 29 Jan 2025 MSG Chinese New Year (Snake)
REM 17 Feb 2026 MSG Chinese New Year (Horse)
REM 6 Feb 2027 MSG Chinese New Year (Goat)
REM 26 Jan 2028 MSG Chinese New Year (Monkey)
REM 13 Feb 2029 MSG Chinese New Year (Rooster)
REM 3 Feb 2030 MSG Chinese New Year (Dog)
REM 23 Jan 2031 MSG Chinese New Year (Pig)
REM 11 Feb 2032 MSG Chinese New Year (Rat)
REM 31 Jan 2033 MSG Chinese New Year (Ox)
REM 19 Feb 2034 MSG Chinese New Year (Tiger)
REM 8 Feb 2035 MSG Chinese New Year (Rabbit)
REM 28 Jan 2036 MSG Chinese New Year (Dragon)
REM 15 Feb 2037 MSG Chinese New Year (Snake)
REM 4 Feb 2038 MSG Chinese New Year (Horse)
REM 24 Jan 2039 MSG Chinese New Year (Goat)
REM 12 Feb 2040 MSG Chinese New Year (Monkey)
REM 1 Feb 2041 MSG Chinese New Year (Rooster)
REM 22 Jan 2042 MSG Chinese New Year (Dog)
REM 10 Feb 2043 MSG Chinese New Year (Pig)
REM 30 Jan 2044 MSG Chinese New Year (Rat)
REM 17 Feb 2045 MSG Chinese New Year (Ox)
REM 6 Feb 2046 MSG Chinese New Year (Tiger)
REM 26 Jan 2047 MSG Chinese New Year (Rabbit)
REM 14 Feb 2048 MSG Chinese New Year (Dragon)
REM 2 Feb 2049 MSG Chinese New Year (Snake)
REM 23 Jan 2050 MSG Chinese New Year (Horse)

View File

@@ -10,7 +10,7 @@ REM 28 Oct MSG ΟΧΙ
REM 25 Dec MSG ΧΡΙΣΤΟΥΓΕΝΝΑ
REM 26 Dec MSG ΧΡΙΣΤΟΥΓΕΝΝΑ2
REM [orthodoxeaster($Uy)+1] ΔΕΥΤΕΡΑ ΤΟΥ ΠΑΣΧΑ
REM [orthodoxeaster($Uy)+1] MSG ΔΕΥΤΕΡΑ ΤΟΥ ΠΑΣΧΑ
# May first is a national holiday except if Sunday, day of great week (week before easter) or Monday after easter, then

View File

@@ -10,7 +10,6 @@ SET InIsrael value("InIsrael", 0)
SET Reform value("Reform", 0)
# Convenient function definition to save typing
FSET _h(x, y) HEBDATE(x,y)
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 _BackTwoFri(x, y) IIF(WKDAYNUM(_h2(x,y))!=5, _h2(x,y), _h2(x,y)-2)
@@ -19,50 +18,50 @@ FSET _BackTwoSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)-2)
SET InIsrael VALUE("InIsrael", 0)
SET Reform VALUE("Reform", 0)
[_h(1, "Tishrey")] ++4 MSG %"Rosh Hashana 1%" is %b.
REM [hebdate(1, "Tishrey")] ++4 MSG %"Rosh Hashana 1%" is %b.
# No RH-2 or Tzom Gedalia in Reform
IF !Reform
[_h(2, "Tishrey")] ++4 MSG %"Rosh Hashana 2%" is %b.
[_PastSat(3, "Tishrey")] ++4 MSG %"Tzom Gedalia%" is %b.
REM [hebdate(2, "Tishrey")] ++4 MSG %"Rosh Hashana 2%" is %b.
REM [_PastSat(3, "Tishrey")] ++4 MSG %"Tzom Gedalia%" is %b.
ENDIF
[_h(10, "Tishrey")] ++4 MSG %"Yom Kippur%" is %b.
[_h(15, "Tishrey")] ++4 MSG %"Sukkot 1%" is %b.
REM [hebdate(10, "Tishrey")] ++4 MSG %"Yom Kippur%" is %b.
REM [hebdate(15, "Tishrey")] ++4 MSG %"Sukkot 1%" is %b.
IF !InIsrael
[_h(16, "Tishrey")] MSG %"Sukkot 2%"
REM [hebdate(16, "Tishrey")] MSG %"Sukkot 2%"
ENDIF
[_h(21, "Tishrey")] ++4 MSG %"Hoshana Rabba%" is %b.
[_h(22, "Tishrey")] ++4 MSG %"Shemini Atzeret%" is %b.
REM [hebdate(21, "Tishrey")] ++4 MSG %"Hoshana Rabba%" is %b.
REM [hebdate(22, "Tishrey")] ++4 MSG %"Shemini Atzeret%" is %b.
IF InIsrael
[_h(22, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
REM [hebdate(22, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
ELSE
[_h(23, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
REM [hebdate(23, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
ENDIF
# Because Kislev can change length, we must be more careful about Chanukah
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%"
[_chan(4)] MSG %"Chanukah 4%"
[_chan(5)] MSG %"Chanukah 5%"
[_chan(6)] MSG %"Chanukah 6%"
[_chan(7)] MSG %"Chanukah 7%"
[_chan(8)] MSG %"Chanukah 8%"
REM [_chan(1)] ++4 MSG %"Chanukah 1%" is %b.
REM [_chan(2)] MSG %"Chanukah 2%"
REM [_chan(3)] MSG %"Chanukah 3%"
REM [_chan(4)] MSG %"Chanukah 4%"
REM [_chan(5)] MSG %"Chanukah 5%"
REM [_chan(6)] MSG %"Chanukah 6%"
REM [_chan(7)] MSG %"Chanukah 7%"
REM [_chan(8)] MSG %"Chanukah 8%"
# Not sure about Reform's position on the next one.
IF !Reform
# 10 Tevet will never be a Saturday, so whether or not to
# move it is moot. (Thanks to Art Werschulz.)
[_h(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
REM [hebdate(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
ENDIF
[_h(15, "Shvat")] ++4 MSG %"Tu B'Shvat%" is %b.
[_h(14, "Adar A")] ++4 MSG %"Purim Katan%" is %b.
REM [hebdate(15, "Shvat")] ++4 MSG %"Tu B'Shvat%" is %b.
REM [hebdate(14, "Adar A")] ++4 MSG %"Purim Katan%" is %b.
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
IF WKDAYNUM(_h2(13, "Adar")) != 6
@@ -70,39 +69,39 @@ IF WKDAYNUM(_h2(13, "Adar")) != 6
ELSE
REM [_h2(11, "Adar")] ++4 MSG %"Fast of Esther%" is %b.
ENDIF
[_h(14, "Adar")] ++4 MSG %"Purim%" is %b.
[_h(15, "Nisan")] ++4 MSG %"Pesach%" is %b.
REM [hebdate(14, "Adar")] ++4 MSG %"Purim%" is %b.
REM [hebdate(15, "Nisan")] ++4 MSG %"Pesach%" is %b.
IF !InIsrael
[_h(16, "Nisan")] MSG %"Pesach 2%"
REM [hebdate(16, "Nisan")] MSG %"Pesach 2%"
ENDIF
[_h(21, "Nisan")] MSG %"Pesach 7%"
REM [hebdate(21, "Nisan")] MSG %"Pesach 7%"
IF !InIsrael && !Reform
[_h(22, "Nisan")] MSG %"Pesach 8%"
REM [hebdate(22, "Nisan")] MSG %"Pesach 8%"
ENDIF
[_h(27, "Nisan")] ++4 MSG %"Yom HaShoah%" is %b.
[_BackTwoFri(4, "Iyar")] ++4 MSG %"Yom HaZikaron%" is %b.
[_BackTwoSat(5, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
REM [hebdate(27, "Nisan")] ++4 MSG %"Yom HaShoah%" is %b.
REM [_BackTwoFri(4, "Iyar")] ++4 MSG %"Yom HaZikaron%" is %b.
REM [_BackTwoSat(5, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
# Not sure about Reform's position on Lag B'Omer
IF !Reform
[_h(18, "Iyar")] ++4 MSG %"Lag B'Omer%" is %b.
REM [hebdate(18, "Iyar")] ++4 MSG %"Lag B'Omer%" is %b.
ENDIF
[_h(28, "Iyar")] ++4 MSG %"Yom Yerushalayim%" is %b.
[_h(6, "Sivan")] ++4 MSG %"Shavuot%" is %b.
REM [hebdate(28, "Iyar")] ++4 MSG %"Yom Yerushalayim%" is %b.
REM [hebdate(6, "Sivan")] ++4 MSG %"Shavuot%" is %b.
IF !InIsrael && !Reform
[_h(7, "Sivan")] MSG %"Shavuot 2%"
REM [hebdate(7, "Sivan")] MSG %"Shavuot 2%"
ENDIF
# Fairly sure Reform Jews don't observe the next two
IF !Reform
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
# fall on a Saturday
[_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b.
[_PastSat(9, "Av")] ++4 MSG %"Tish'a B'Av%" is %b.
REM [_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b.
REM [_PastSat(9, "Av")] ++4 MSG %"Tish'a B'Av%" is %b.
ENDIF

View File

@@ -525,9 +525,9 @@ contains the back value. If the "back" value was \-n, the value will
be positive; if it was \-\-n, the value will be negative.
.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.
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

View File

@@ -240,13 +240,13 @@ regardless of the \fIdelta\fR supplied for each reminder.
.B \-t\fR\fIn\fR
If you supply a number \fIn\fR after the \fB\-t\fR option, then
\fBRemind\fR pretends that echo \fBREM\fR command has a delta
of \+\+\fIn\fR, regardless of any existing delta.
of ++\fIn\fR, regardless of any existing delta.
.TP
.B \-tz\fR
If you supply the letter \fBz\fR after the \fB\-t\fR option, then
\fBRemind\fR sets all REM statements' deltas to zero, regardless of the
value supplied in the REM statement itself. In effect, this disables
all deltas of the form \fB\+\fIn\fR and \fB\+\+\fIn\fR.
all deltas of the form \fB+\fIn\fR and \fB++\fIn\fR.
.TP
.B \-tt\fR[\fIn\fR]
The \fB-tt\fR option causes \fBRemind\fR to assume a default delta of
@@ -463,11 +463,36 @@ information.
\fBRemind\fR supports the following long options, which \fIare\fR
case-sensitive:
.RP
.PP
.B \-\-version
The \fB\-\-version\fR option causes \fBRemind\fR to print its version number
to standard output and then exit.
.TP
.B \-\-print-config-cmd
This option causes \fBRemind\fR to print the exact \fB./configure\fR
command that was used when \fBRemind\fR was built. You can use this
to build a new version of \fBRemind\fR using the same configuration
as an existing one by running:
.RS
.PP
.nf
eval `remind --print-config-cmd`
.fi
.PP
from the top-level \fBRemind\fR source directory. (However, it's safer
to simply run \fBremind --print-config-cmd\fR and then type in the
command once you've verified that it looks OK.)
.RE
.TP
.B \-\-print-tokens
The \fB\-\-print-tokens\fR option causes \fBRemind\fR to print the tokens
used by the parser, built-in function names, and system variable names
to standard output and then exit. This output is designed to make it easy
to create a syntax-highlighting file for various text editors. The output
can be modified by hand or by a script into a syntax-highlighting file
with relative ease.
.TP
.B \-\-max-execution-time\fR=\fIn\fR
Limit the total execution time (as measured by the wall clock) to
\fIn\fR seconds. This is useful if \fBRemind\fR is invoked on
@@ -555,12 +580,15 @@ Its syntax is:
The parts of the \fBREM\fR command can be specified in any order, except
that the \fIbody\fR must come immediately after the \fBMSG\fR,
\fBRUN\fR, \fBCAL\fR, \fBPS\fR, \fBPSFILE\fR or \fBSATISFY\fR keyword.
The portion of the \fBREM\fR command before the \fBMSG\fR, \fBMSF\fR
\fBRUN\fR, \fBCAL\fR or \fBSATISFY\fR clause is called a
\fItrigger\fR.
.PP
The \fBREM\fR token is optional, providing that the remainder
of the command cannot be mistaken for another \fBRemind\fR command
such as \fBOMIT\fR or \fBRUN\fR. The portion of the \fBREM\fR command
before the \fBMSG\fR, \fBMSF\fR \fBRUN\fR, \fBCAL\fR or \fBSATISFY\fR clause
is called a \fItrigger\fR.
In earlier versions of \fBRemind\fR, the \fBREM\fR token was optional
providing that the remainder of the command cannot be mistaken for
another \fBRemind\fR command. However, this use is deprecated and will
now cause a warning to be issued. All of your reminder lines should
be written to start with the REM command.
.PP
.B "MSG, MSF, RUN, CAL, SPECIAL, PS and PSFILE"
.PP
@@ -573,14 +601,16 @@ used the \fB\-k\fR command-line option, then \fBMSG\fR-type reminders are
passed to the appropriate program. Note that the options \fB\-c\fR,
\fB\-s\fR, \fB\-p\fR and \fB\-n\fR disable the \fB\-k\fR option.
.PP
Note that you can omit the reminder type, in which case it
defaults to \fBMSG\fR. So you can write:
Earlier versions of \fBRemind\fR let you omit the reminder type,
in which case it defaulted to \fBMSG\fR. However, this usage is
deprecated and will cause a warning. Something like:
.PP
.nf
6 January Dianne's Birthday
REM 6 January Dianne's Birthday
.fi
.PP
although this is not recommended.
will issue the warning "Missing REM type; assuming MSG"
.PP
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
@@ -1051,7 +1081,7 @@ will be updated, and the \fBONCE\fR keyword will not operate properly.
You can fix this by setting a timestamp file for \fBRemind\fR to track
the last-run date; see the documentation of \fB$OnceFile\fR in the
\fBSYSTEM VARIABLES\fR section. If you use standard input as your
\fBRemind\fR input file, then you \fImust\fR use \B$OnceFile\fR for the
\fBRemind\fR input file, then you \fImust\fR use \fB$OnceFile\fR for the
\fBONCE\fR keyword to work properly.
.PP
If you start \fBRemind\fR with the \fB\-o\fR option, then the \fBONCE\fR
@@ -1565,7 +1595,35 @@ is replaced with "\fIyy\fR", the last two digits of the year.
.TP
.B %_
(percent-underscore) is replaced with a newline. You can use this to
achieve multi-line reminders.
achieve multi-line reminders. Note that calendar back-ends vary in
how they handle multi-line reminders:
.RS
.TP
.B o
Running \fBremind -c\fR preserves newlines in the terminal calendar output.
.TP
.B o
\fBrem2pdf\fR preserves newlines if \fBremind\fR is invoked with the \fB\-pp\fR
or \fB\-ppp\fR option.
.TP
.B o
\fBrem2html\fR preserves newlines if \fBremind\fR is invoked with the
\fB\-pp\fR option.
.TP
.B o
\fBtkremind\fR preserves newlines.\fR
.TP
.B o
\fBrem2ps\fR converts newlines to spaces. But \fBrem2ps\fR is deprecated;
use \fBrem2pdf\fR instead.
.TP
.B o
The "simple calendar" formats (ie, \fBremind\fR's \fB\-s\fR, \fB\-n\fR and
\fB\-p\fR options) convert newlines to spaces.
.PP
All calendar back-ends collapse multiple spaces to a single space and
multiple newlines to a single newline.
.RE
.TP
.B %1
is replaced with "now", "\fIm\fR minutes from now", "\fIm\fR minutes ago",
@@ -1699,7 +1757,7 @@ or:
The \fBOMIT\fR command is used to "globally" omit certain days
(usually holidays). These globally-omitted days are skipped by the
"\-" and "+" forms of \fIback\fR and \fIdelta\fR, but not by the
"\-\-" and "\+\+" forms. Some examples:
"\-\-" and "++" forms. Some examples:
.PP
.nf
OMIT Saturday Sunday
@@ -1995,6 +2053,10 @@ 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
If a given reminder file contains more than one identical
\fBINCLUDECMD\fR, only the first one will actually be executed. All
subsequent identical ones will use the cached output from the first one.
.PP
.SH THE BANNER COMMAND
.PP
@@ -2144,6 +2206,11 @@ If the \fBTIME\fR is used where \fBRemind\fR expects a time-of-day
\fIpm\fR suffix and the hour can be as large as you want, so long
as the total number of minutes in the duration fits in a signed integer
variable.
.PP
For convenience, a \fBTIME\fR constant may be surrounded by single
quotes to match \fBDATE\fR and \fBDATETIME\fR constants, but these
quotes are optional. That is, 12:56 and '12:56' represent the same
\fBTIME\fR constant.
.RE
.TP
.B DATE constants
@@ -2178,11 +2245,11 @@ and time separator characters for \fBDATE\fR and \fBTIME\fR constants apply
also to \fBDATETIME\fR constants.
.RE
.PP
.B ZERO VALUES
.B ZERO VALUES AND TRUE/FALSE
.PP
The non-string types all have an associated \fIzero\fR value, which is
treated as "false" by the IF command and the logical operators. The
zero values are:
All types have an associated \fIzero value\fR, which is treated as
\fIfalse\fR by the IF command, the IIF function, and the logical
operators. The zero values are:
.PP
.RS
.PP
@@ -2193,10 +2260,11 @@ zero values are:
\fBTIME\fR - 00:00
.PP
\fBDATETIME\fR - '1990-01-01@00:00'
.PP
\fBSTRING\fR - "" (the empty string)
.RE
.PP
Additionally, for the purpose of the IF command (but \fInot\fR the
logical operators) the empty string "" is considered a false value.
Any value other than the \fIzero value\fR is treated as \fItrue\fR.
.PP
.B OPERATORS
.PP
@@ -2219,8 +2287,8 @@ C operators.
.PP
.TP
.B !
Logical negation. Can be applied to an \fBINT\fR type. If the operand
is non-zero, returns zero. Otherwise, returns 1.
Logical negation. Can be applied to any type. If the operand
is non-zero, returns 0. Otherwise, returns 1.
.TP
.B \-
Unary minus. Can be applied to an \fBINT\fR. Returns the negative
@@ -2324,15 +2392,16 @@ If the operands are not of the same type, == returns 0 and != returns
.RE
.TP
.B &&
This is the logical AND operator. Neither of its operands can be
\fBSTRING\fR type. Returns the second operand if both operands are
non-zero. Otherwise, returns whichever operand is zero.
This is the logical AND operator. Returns the second operand if both
operands are non-zero. Otherwise, returns whichever operand is zero.
Operands can be any type and "zero" is interpreted as appropriate for
each operand's type.
.TP
.B ||
This is the logical OR operator. Neither of its operands can be
\fBSTRING\fR type. It returns the first operand that is non-zero; if
both operands are zero, then returns the second operand.
This is the logical OR operator. It returns the first operand that is
non-zero; if both operands are zero, then returns the second operand.
Operands can be any type and "zero" is interpreted as appropriate for
each operand's type.
.PP
.B NOTES
.PP
@@ -2773,8 +2842,15 @@ order, or 2 if sorting by time in descending order.
The number of spaces by which all lines (except the first) of an
\fBMSF\fR-type reminder should be indented. The default is 0.
.TP
.B $SuppressImplicitWarnings
Normally, \fBRemind\fR issues a warning if a line begins with an unknown
token and is treated as a \fBREM\fR command, or if a \fBREM\fR command
is missing a type and is treated as a \fBMSG\fR-type reminder. Setting
\fB$SuppressImplicitWarnings\fR to 1 suppresses these warnings. The default
is 0 and we do not recommend disabling the warnings.
.TP
.B $SuppressLRM
Normally, when Remind is run with the \fB\-c\fR option in a UTF-8 locale,
Normally, when \fBRemind\fR is run with the \fB\-c\fR option in a UTF-8 locale,
it emits a left-to-right mark sequence after printing day names or
reminders. Some terminals render this incorrectly, so you can use:
.RS
@@ -2900,18 +2976,25 @@ 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]])
.B ampm(tq_time [,s_am [,s_pm [,i_lz]]])
Returns a \fBSTRING\fR that is the result of converting \fItime\fR
(which is either a \fBTIME\fR or a \fBDATETIME\fR object) to "AM/PM"
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:
and "PM". The optional argument \fIlz\fR specifies whether or not
the hour should be padded to two digits with a leading zero. If \fIlz\fR is
zero, then a leading 0 is not added; otherwise, the hour is padded out to
two digits with a leading zero. If not supplied, \fIlz\fR defaults to zero.
.RS
.PP
The function obeys the system variables $DateSep, $TimeSep and
$DateTimeSep when formatting its output. Here are some examples of
its output:
.PP
.nf
ampm(0:22) returns "12:22AM"
ampm(17:45, "am", "pm") returns "5:45pm"
ampm(17:45, "am", "pm", 1) returns "05:45pm"
ampm('2020-03-14@21:34') returns "2020-03-14@9:34PM"
.fi
.PP
@@ -3271,14 +3354,14 @@ out. The stripping algorithm is fairly naive; the function starts
stripping characters when it encounters a "<" and it stops stripping
when it encounters a ">".
.TP
.B iif(si_test1, x_arg1, [si_test2, x_arg2,...], x_default)
If \fItest1\fR is not zero or the null string, returns \fIarg1\fR.
Otherwise, if \fItest2\fR is not zero or the null string, returns
\fIarg2\fR, and so on. If all of the \fItest\fR arguments are false,
returns \fIdefault\fR. Note that all arguments are \fIalways\fR evaluated.
This function accepts an odd number of arguments - note that prior to version
03.00.05 of \fBRemind\fR, it accepted 3 arguments only. The 3-argument
version of \fBiif()\fR is compatible with previous versions of \fBRemind\fR.
.B iif(x_test1, x_arg1, [x_test2, x_arg2,...], x_default)
If \fItest1\fR is true, returns \fIarg1\fR. Otherwise, if \fItest2\fR
is true, returns \fIarg2\fR, and so on. If all of the \fItest\fR
arguments are false, returns \fIdefault\fR. Note that all arguments
are \fIalways\fR evaluated. This function accepts an odd number of
arguments - note that prior to version 03.00.05 of \fBRemind\fR, it
accepted 3 arguments only. The 3-argument version of \fBiif()\fR is
compatible with previous versions of \fBRemind\fR.
.TP
.B index(s_search, s_target [,i_start)
Returns an \fBINT\fR that is the location of \fItarget\fR in the
@@ -4493,11 +4576,10 @@ The above sequence sets y to 1, which is the global value of x.
.TP
o
User-defined functions may call other functions, including other user-defined
functions. However, recursive calls are not allowed.
.TP
o
User-defined functions are not syntax-checked when they are defined; parsing
occurs only when they are called.
functions. Recursive calls are allowed, but they must terminate (for
example, by using a short-circuit operator or function that breaks the
recursion) or an error will result after a certain maximum number of
recursive calls (by default, 1000.)
.TP
o
If a user-defined function has the same name as a built-in function,
@@ -4519,6 +4601,11 @@ or thirdfunc will exist. \fBRemind\fR does not issue an error if you
try to \fBFUNSET\fR a nonexistent user-defined function; it simply
does nothing in that case.
.PP
If you define a user-defined function and then later on redefine it,
\fBRemind\fR will issue a warning. If you do not want this warning,
then use \fBFUNSET\fR to remove the existing definition before you
redefine the function.
.PP
.SH PRECISE SCHEDULING
.PP
The \fBWARN\fR keyword allows precise control over advance warning in
@@ -4652,8 +4739,11 @@ 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 or related functions; otherwise, \fIexpr\fR will not change as
\fBRemind\fR iterates.
\fBtrigdate()\fR or related functions or system variables; otherwise,
\fIexpr\fR will not change as \fBRemind\fR iterates. In fact, if
\fIexpr\fR is not a constant and does not call \fBtrigdate()\fR or
related functions or system variables, then \fBRemind\fR will issue a
warning.
.PP
An example of the usefulness of \fBSATISFY\fR: Suppose you wish to
be warned of every Friday the 13th. Your first attempt may be:
@@ -5784,10 +5874,6 @@ after the WEEK keyword.
The following tokens can be abbreviated:
.TP
o
\fBREM\fR can be omitted - it is implied if no other valid command
is present.
.TP
o
\fBCLEAR-OMIT-CONTEXT\fR --> \fBCLEAR\fR
.TP
o

View File

@@ -224,6 +224,14 @@ If this is selected, pop-up reminder boxes will be closed after one minute
has elapsed. Otherwise, they remain on your screen forever until you
explicitly dismiss them.
.TP
.B Use system notifications when issuing a reminder
This option is available only for Tcl/Tk version 9.0 or later, or if
you have the \fBnotify-send\fR program installed; it will be greyed
out if neither condition is true. If selected, then when a reminder
is popped up, it will also be sent to the desktop notification system,
causing a notification to appear.
.TP
.B Beep terminal when popping up a reminder
If selected, \fBTkRemind\fR beeps the terminal bell when a queued reminder
@@ -266,7 +274,7 @@ 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
when \fBTkRemind\fR invokes \fBremind\fR. Unless you know what
you are doing, leave this blank.
.TP

View File

@@ -374,19 +374,37 @@ sub parse_input
($1 % 256), ($1 % 256), ($1 % 256));
}
} elsif ($special eq 'COLOR' || $special eq 'COLOUR') {
if ($body =~ /(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/) {
if ($body =~ /(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/s) {
my($r, $g, $b, $text) = ($1, $2, $3, $4);
my $color = sprintf("style=\"color: #%02X%02X%02X;\"",
$r % 256, $g % 256, $b % 256);
push(@{$days->[$d]}, "<p$class $color>" . escape_html($text) . '</p>');
push(@{$days->[$d]}, "<p$class $color>" . fix_whitespace(escape_html($text)) . '</p>');
}
} elsif ($special eq '*') {
push(@{$days->[$d]}, "<p$class>" . escape_html($body) . '</p>');
push(@{$days->[$d]}, "<p$class>" . fix_whitespace(escape_html($body)) . '</p>');
}
}
return $found_data;
}
sub fix_whitespace
{
my ($text) = @_;
# Collapse multiple spaces/tabs to a single space
$text =~ s/[ \t]+/ /gs;
# Remove whitespace before/after newlines
$text =~ s/\s+\n/\n/gs;
$text =~ s/\n\s+/\n/gs;
# Collapse multiple newlines to a single newline
$text =~ s/\n+/\n/gs;
# Convert newlines to <br />
$text =~ s|\n|<br />|g;
return $text;
}
sub small_calendar
{
my($month, $monlen, $url, $first_col) = @_;

View File

@@ -61,6 +61,8 @@ my $settings = {
margin_left => 36,
margin_right => 36,
svg => 0,
ps => 0,
eps => 0,
verbose => 0,
};
@@ -81,6 +83,8 @@ Options:
--landscape, -l Print in landscape orientation
--small-calendars=N Choose location for small calendars
--svg Output SVG instead of PDF
--ps Output PostScript instead of PDF
--eps Output encapsulated PostScript instead of PDF
-cN Synonym for --small-calendars=N
--left-numbers, -x Print day numbers on the left
--fill-page, -e Fill the entire page
@@ -114,6 +118,8 @@ my $ret = GetOptions('landscape|l' => \$settings->{landscape},
'small-calendars|c=i' => \$settings->{small_calendars},
'left-numbers|x' => \$settings->{numbers_on_left},
'svg' => \$settings->{svg},
'ps' => \$settings->{ps},
'eps' => \$settings->{eps},
'fill-page|e' => \$settings->{fill_entire_page},
'media|m=s' => \$settings->{media},
'width|w=i' => \$settings->{width},
@@ -178,6 +184,17 @@ if ($settings->{landscape}) {
$settings->{height} = $tmp;
}
if ($settings->{svg} && $settings->{ps} ||
$settings->{svg} && $settings->{eps} ||
$settings->{eps} && $settings->{ps}) {
print STDERR "Only one of --eps, --ps or --svg may be used.\n";
exit(1);
}
if ($settings->{eps}) {
$settings->{ps} = 1;
}
# Don't read from a terminal
if (-t STDIN) { ## no critic
print STDERR "I can't read data from a terminal. Please run like this:\n";
@@ -193,6 +210,17 @@ my $surface;
if ($settings->{svg}) {
$surface = Cairo::SvgSurface->create_for_stream(sub { print $_[1] unless $errored_out; }, undef,
$settings->{width}, $settings->{height});
} elsif ($settings->{ps}) {
if ($settings->{landscape}) {
$surface = Cairo::PsSurface->create_for_stream(sub { print $_[1] unless $errored_out; }, undef,
$settings->{height}, $settings->{width});
} else {
$surface = Cairo::PsSurface->create_for_stream(sub { print $_[1] unless $errored_out; }, undef,
$settings->{width}, $settings->{height});
}
if ($settings->{eps}) {
$surface->set_eps(1);
}
} else {
$surface = Cairo::PdfSurface->create_for_stream(sub { print $_[1] unless $errored_out; }, undef,
$settings->{width}, $settings->{height});
@@ -204,11 +232,26 @@ eval { $surface->set_metadata('author', 'Remind (https://dianne.skoll.ca/project
eval { $surface->set_metadata('creator', 'rem2pdf (https://dianne.skoll.ca/projects/remind/)'); };
eval { $surface->set_metadata('subject', 'Calendar'); };
if ($settings->{ps}) {
$surface->dsc_comment('%%Title: Calendar');
$surface->dsc_comment('%%Producer: rem2pdf (https://dianne.skoll.ca/projects/remind/)');
$surface->dsc_comment('%%PageOrientation: ' . (($settings->{landscape}) ? 'Landscape' : 'Portrait'));
$surface->dsc_begin_setup();
}
my $cr = Cairo::Context->create($surface);
$cr->set_line_width($settings->{line_thickness});
if ($settings->{ps} && $settings->{landscape}) {
$cr->translate(0, $settings->{width});
$cr->rotate(-1.5707963267949); # Rotate -90 degrees
}
my $warned = 0;
while(1) {
if ($settings->{ps}) {
$surface->dsc_begin_page_setup();
$surface->dsc_comment('%%PageOrientation: ' . (($settings->{landscape}) ? 'Landscape' : 'Portrait'));
}
my ($obj, $err) = Remind::PDF->create_from_stream(*STDIN,
{color => 1,
shade => 1,
@@ -224,9 +267,9 @@ while(1) {
}
last;
}
if ($settings->{svg} && $done_one) {
if (($settings->{eps} || $settings->{svg}) && $done_one) {
if (!$warned) {
print STDERR "WARNING: --svg can only output one page; ignoring subsequent\nmonths in a multi-month calendar.\n";
print STDERR "WARNING: --eps and --svg can only output one page; ignoring subsequent\nmonths in a multi-month calendar.\n";
$warned = 1;
}
next;
@@ -289,18 +332,22 @@ __END__
=head1 NAME
rem2pdf - draw a PDF or SVG calendar from Remind output
rem2pdf - draw a PDF, SVG or PostScript calendar from Remind output
=head1 SYNOPSIS
remind -pp [options] file | rem2pdf [options] > output.pdf
remind -pp [options] file | rem2pdf --svg [options] > output.svg
remind -pp [options] file | rem2pdf --ps [options] > output.ps
remind -pp [options] file | rem2pdf --eps [options] > output.eps
=head1 DESCRIPTION
B<rem2pdf> reads the standard input, which should be the results of
running B<remind> with the B<-p>, B<-pp> or B<-ppp> options. It emits
PDF or SVG code that draws a calendar to standard output.
PDF, SVG or PostScript code that draws a calendar to standard output. (The
addition of support for SVG and PostScript means that rem2pdf is increasingly
misnamed...)
B<rem2pdf> uses the Pango text formatting library (L<https://pango.gnome.org/>)
and the Cairo graphics library (L<https://www.cairographics.org/>) to produce
@@ -315,6 +362,16 @@ output at all.
=over
=item --ps
Output PostScript instead of PDF.
=item --eps
Output Encapsulated PostScript instead of PDF. In this case, you
should feed C<rem2pdf> only one month's worth of calendar data,
because it cannot create a multi-page encapsulated PostScript file.
=item --svg
Output SVG instead of PDF. In this case, you should feed C<rem2pdf>

View File

@@ -85,6 +85,18 @@ sub render
} else {
$body = $self->{body};
}
# Clean up the body:
# Collapse multiple spaces/tabs to a single space
$body =~ s/[ \t]+/ /gs;
# Remove whitespace before/after newlines
$body =~ s/\s+\n/\n/gs;
$body =~ s/\n\s+/\n/gs;
# Collapse multiple newlines to a single newline
$body =~ s/\n+/\n/gs;
$layout->set_text(Encode::decode('UTF-8', $body));
my $desc = Pango::FontDescription->from_string($settings->{entry_font} . ' ' . $settings->{entry_size} . 'px');
$layout->set_font_description($desc);

124
scripts/tkremind → scripts/tkremind.in Executable file → Normal file
View File

@@ -15,8 +15,10 @@
# the next line restarts using wish \
exec wish "$0" "$@"
tk appname tkremind
# We need at least version 8.5 because of {*} list expansion operator
if {[catch {package require Tcl 8.5}]} {
if {[catch {package require Tcl 8.5-}]} {
puts stderr "This program requires Tcl 8.5 or higher."
puts stderr "You have version [info tclversion]"
exit 1
@@ -24,7 +26,33 @@ if {[catch {package require Tcl 8.5}]} {
wm withdraw .
set Hostname [exec hostname]
catch {
set Hostname [exec hostname]
}
global env
set HOME $env(HOME)
# Check if we have "tk sysnotify"
set HAVE_SYSNOTIFY 0
set NOTIFY_SEND_PATH ""
catch { tk sysnotify } err opt
if { [dict get $opt -errorcode] == "TCL WRONGARGS" } {
set HAVE_SYSNOTIFY 1
} else {
set path [split $env(PATH) :]
foreach d $path {
if { [file executable [file join $d "notify-send"]] } {
set NOTIFY_SEND_PATH [file join $d "notify-send"]
break
}
}
}
proc home { f } {
global HOME
return [string cat $HOME $f]
}
# Our icon photo
catch {
@@ -166,6 +194,9 @@ set OptDescr(Deiconify) "(0/1) If 1, TkRemind deiconifies the calendar window wh
set Option(ShowTodaysReminders) 1
set OptDescr(ShowTodaysReminders) "(0/1) If 1, TkRemind shows all of today's non-timed reminders in a window at startup and when the date changes"
set Option(SysNotify) 0
set OptDescr(SysNotify) "(0/1) If 1, TkRemind uses the system notification mechanism when a reminder pops up (Tcl 9.0 or newer)"
set Option(RunCmd) ""
set OptDescr(RunCmd) "(String) If non-blank, run specified command when a pop-up reminder appears"
set Option(FeedReminder) 0
@@ -231,8 +262,7 @@ if {[string match "rem2pdf:*" "$a"]} {
}
# Reminder file to source -- default
set ReminderFile {NOSUCHFILE}
set ReminderFile [file nativename "~/.reminders"]
set ReminderFile [file nativename [home "/.reminders"]]
# Default options file
set ConfigFile ""
@@ -243,8 +273,7 @@ set EditorPid -1
set RemindErrors ""
# Reminder file to append to -- default
set AppendFile {NOSUCHFILE}
catch {set AppendFile $ReminderFile}
set AppendFile $ReminderFile
# Array of tags -> JSON dicts
array unset TagToObj
@@ -319,7 +348,7 @@ set Option(PrintMargins) 36pt
set OptDescr(PrintSmallCalendars) "(0/1) If 1, print small calendars in PostScript output"
set Option(PrintSmallCalendars) 1
set OptDescr(PrintFormat) "Print format: pdf or ps"
set OptDescr(PrintFormat) "Print format: pdf, ps or ps1 - ps1 means PostScript using rem2pdf"
set Option(PrintFormat) ps
set WarningHeaders [list "# Lines starting with REM TAG TKTAGnnn ... were created by tkremind" "# Do not edit them by hand or results may be unpredictable."]
@@ -400,8 +429,8 @@ proc Initialize {} {
set TodayYear [clock format $now -format %Y]
set TodayDay [string trim [clock format $now -format %e]]
set CommandLine "$Remind -itkremind=1 -pp -y -l @EXTRA@"
set PSCmd "$Remind -itkremind=1 -itkprint=1 -pp -l @EXTRA@"
set CommandLine "$Remind -itkremind=1 -pp -y -l %EXTRA%"
set PSCmd "$Remind -itkremind=1 -itkprint=1 -pp -l %EXTRA%"
set i 0
while {$i < $argc} {
if {[regexp -- {-[bgxim].*} [lindex $argv $i]]} {
@@ -478,7 +507,7 @@ proc Initialize {} {
append PSCmd " "
append PSCmd [posix_escape $ReminderFile]
set CommandLine "|/bin/sh -c \"$CommandLine @MONTH@ @YEAR@\""
set CommandLine "|/bin/sh -c \"$CommandLine %MONTH% %YEAR%\""
}
#***********************************************************************
@@ -734,7 +763,7 @@ proc CreateCalWindow { dayNames } {
# Lets user edit options
#***********************************************************************
proc EditOptions {} {
global Option tmpOpt
global Option tmpOpt HAVE_SYSNOTIFY NOTIFY_SEND_PATH ver
# Make a working copy of current option set
foreach name [array names Option] {
@@ -751,6 +780,8 @@ proc EditOptions {} {
pack $w.f -side top -expand 1 -fill both
pack $w.b -side top -expand 0 -fill x
label $w.ver -text "TkRemind version @VERSION@ on Tcl/Tk version [info tclversion] with Remind version $ver"
pack $w.ver -in $w.f -side top -expand 0 -fill x
# Start iconified
checkbutton $w.startIconified -text "Start up Iconified" \
-anchor w -justify left \
@@ -770,6 +801,16 @@ proc EditOptions {} {
-text "Automatically close pop-up reminders after a minute" \
-anchor w -justify left -variable tmpOpt(AutoClose)
checkbutton $w.sysNotify \
-text "Use system notifications when issuing a reminder" \
-anchor w -justify left -variable tmpOpt(SysNotify)
if { ! $HAVE_SYSNOTIFY } {
if { "$NOTIFY_SEND_PATH" == "" } {
$w.sysNotify configure -state disabled -takefocus 0
}
}
# Ring bell when popping up reminder
checkbutton $w.ring -text "Beep terminal when popping up a reminder" \
-anchor w -justify left -variable tmpOpt(RingBell)
@@ -873,6 +914,7 @@ proc EditOptions {} {
pack $w.showTodays -in $w.f -side top -expand 0 -fill x
pack $w.confirmQuit -in $w.f -side top -expand 0 -fill x
pack $w.bringDown -in $w.f -side top -expand 0 -fill x
pack $w.sysNotify -in $w.f -side top -expand 0 -fill x
pack $w.ring -in $w.f -side top -expand 0 -fill x
pack $w.deic -in $w.f -side top -expand 0 -fill x
pack $w.ancFrame -in $w.f -side top -expand 0 -fill x
@@ -1063,7 +1105,11 @@ proc LoadOptions {} {
proc ConfigureCalWindow { month year firstDay numDays } {
global Hostname
.h.title configure -text "$month $year"
wm title . "$month $year - TkRemind on $Hostname"
if {[info exists Hostname]} {
wm title . "$month $year - TkRemind @VERSION@ on $Hostname"
} else {
wm title . "$month $year - TkRemind @VERSION@"
}
wm iconname . "$month $year"
ConfigureCalFrame .cal $firstDay $numDays
}
@@ -1082,9 +1128,9 @@ proc FillCalWindow {} {
set_button_to_queue
set month [lindex $MonthNames $CurMonth]
set cmd [regsub @EXTRA@ $CommandLine $Option(ExtraRemindArgs)]
set cmd [regsub @MONTH@ $cmd $month]
set cmd [regsub @YEAR@ $cmd $CurYear]
set cmd [regsub %EXTRA% $CommandLine $Option(ExtraRemindArgs)]
set cmd [regsub %MONTH% $cmd $month]
set cmd [regsub %YEAR% $cmd $CurYear]
set file [open $cmd r]
# Look for # rem2ps2 begin line
@@ -1217,6 +1263,13 @@ proc FillCalWindow {} {
continue
}
.cal.t$n configure -state normal
# Canonicalize spaces and newlines
set stuff [regsub -all {[ \t]+} $stuff " "]
set stuff [regsub -all {[ \t]+\n} $stuff "\n"]
set stuff [regsub -all {\n[ \t]} $stuff "\n"]
set stuff [regsub -all {\n+} $stuff "\n"]
if {[regexp {TKTAG([0-9]+)} $tag all tagno] && "$fntag" != "x"} {
.cal.t$n insert end [string trim $stuff] [list REM TAGGED "TKTAG$tagno" "date_$date" $extratags $fntag]
.cal.t$n tag bind "TKTAG$tagno" <Enter> "TaggedEnter .cal.t$n"
@@ -1333,7 +1386,8 @@ proc DoPrint {} {
frame .p.ff -relief sunken -bd 2
label .p.format -text "Output Format:"
radiobutton .p.pdf -text "PDF" -variable Option(PrintFormat) -value pdf
radiobutton .p.ps -text "PostScript" -variable Option(PrintFormat) -value ps
radiobutton .p.ps -text "PostScript (using rem2ps)" -variable Option(PrintFormat) -value ps
radiobutton .p.ps1 -text "PostScript (using rem2pdf)" -variable Option(PrintFormat) -value ps1
}
label .p.size -text "Paper Size:"
@@ -1350,7 +1404,7 @@ proc DoPrint {} {
radiobutton .p.portrait -text "Portrait" -variable Option(PrintOrient) -value portrait
checkbutton .p.fill -text "Fill page" -variable Option(PrintFill)
checkbutton .p.wrap -text "Use at most 5 rows (PDF only)" -variable Option(WrapCal)
checkbutton .p.wrap -text "Use at most 5 rows (rem2pdf only)" -variable Option(WrapCal)
checkbutton .p.right -text "Day numbers at top-right" -variable Option(PrintDaysRight)
checkbutton .p.encoding -text "ISO 8859-1 PostScript encoding" -variable Option(PrintEncoding)
checkbutton .p.calendars -text "Print small calendars" -variable Option(PrintSmallCalendars)
@@ -1374,7 +1428,7 @@ proc DoPrint {} {
pack .p.tofile .p.filename .p.browse -in .p.f11 -side left -fill none -expand 0 -anchor w
pack .p.tocmd .p.command -in .p.f12 -side left -fill none -expand 0 -anchor w
if { $HaveRem2PDF } {
pack .p.format .p.pdf .p.ps -in .p.ff -side top -fill none -expand 0 -anchor w
pack .p.format .p.pdf .p.ps .p.ps1 -in .p.ff -side top -fill none -expand 0 -anchor w
}
pack .p.size .p.letter .p.a4 -in .p.f2 -side top -fill none -expand 0 -anchor w
pack .p.margin .p.24pt .p.36pt .p.48pt -in .p.f2a -side top -anchor w -fill none -expand 0
@@ -1420,10 +1474,13 @@ proc DoPrint {} {
}
if {$HaveRem2PDF && $Option(PrintFormat) == "pdf"} {
set p [regsub @EXTRA@ $PSCmd "-itkpdf=1 $Option(ExtraRemindArgs)"]
set p [regsub %EXTRA% $PSCmd "-itkpdf=1 $Option(ExtraRemindArgs)"]
set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PDF"
} elseif {$HaveRem2PDF && $Option(PrintFormat) == "ps1"} {
set p [regsub %EXTRA% $PSCmd "-itkpdf=1 $Option(ExtraRemindArgs)"]
set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PDF --ps"
} else {
set p [regsub @EXTRA@ $PSCmd $Option(ExtraRemindArgs)]
set p [regsub %EXTRA% $PSCmd $Option(ExtraRemindArgs)]
set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PS"
set Option(PrintFormat) ps
}
@@ -1463,7 +1520,7 @@ proc DoPrint {} {
}
if {$Option(WrapCal)} {
if {$Option(PrintFormat) == "pdf"} {
if {$Option(PrintFormat) == "pdf" || $Option(PrintFormat) == "ps1"} {
append cmd " --wrap"
}
}
@@ -2857,7 +2914,7 @@ proc DaemonReadable { file } {
# Reads a background reminder from daemon and pops up window.
#---------------------------------------------------------------------------
proc IssueBackgroundReminder { body time now tag qid } {
global BgCounter Option Ignore DaemonFile
global BgCounter Option Ignore DaemonFile HAVE_SYSNOTIFY NOTIFY_SEND_PATH
if {$Option(Deiconify)} {
wm deiconify .
}
@@ -2917,6 +2974,15 @@ proc IssueBackgroundReminder { body time now tag qid } {
if {$Option(RingBell)} {
bell
}
if {$Option(SysNotify)} {
if {$HAVE_SYSNOTIFY} {
tk sysnotify "Reminder for $time" $body
} elseif {"$NOTIFY_SEND_PATH" != "" } {
catch {
exec $NOTIFY_SEND_PATH -a tkremind -i dialog-information "Reminder for $time" "$body"
}
}
}
if {$Option(RunCmd) != ""} {
if {$Option(FeedReminder)} {
FeedReminderToCommand $Option(RunCmd) "$time: $body"
@@ -4214,7 +4280,7 @@ proc FindConfigFile {} {
set confighome $env(XDG_CONFIG_HOME)
}
if {"$confighome" == ""} {
set confighome "~/.config"
set confighome [home "/.config"]
}
# If $confighome does not exist, attempt to
@@ -4225,15 +4291,15 @@ proc FindConfigFile {} {
if {[file isdirectory $confighome]} {
# Migrate .tkremindrc to $confighome/tkremindrc
if {[file exists "~/.tkremindrc"]} {
if {[file exists [home "/.tkremindrc"]]} {
if {![file exists "$confighome/tkreminderc"]} {
puts "Migrating ~/.tkremindrc to $confighome/tkremindrc"
if {[catch { file copy "~/.tkremindrc" "$confighome/tkremindrc"}]} {
if {[catch { file copy [home "/.tkremindrc"] "$confighome/tkremindrc"}]} {
puts "FAILED!\n"
set ConfigFile "~/.tkremindrc"
set ConfigFile [home "/.tkremindrc"]
return
}
catch { file delete "~/.tkremindrc" }
catch { file delete [home "/.tkremindrc"] }
}
set ConfigFile "$confighome/tkremindrc"
return
@@ -4241,7 +4307,7 @@ proc FindConfigFile {} {
set ConfigFile "$confighome/tkremindrc"
return
}
set ConfigFile "~/.tkremindrc"
set ConfigFile [home "/.tkremindrc"]
}
proc set_default_colors { w } {
@@ -4331,6 +4397,4 @@ proc DoneShowingErrors {} {
destroy .errors
}
# Rem2PS program to execute -- supply full path if you want
main

View File

@@ -281,6 +281,7 @@ static void ColorizeEntry(CalEntry const *e, int clamp);
static void SortCol (CalEntry **col);
static void DoCalendarOneWeek (int nleft);
static void DoCalendarOneMonth (void);
static void DoSimpleCalendarOneMonth (void);
static int WriteCalendarRow (void);
static void WriteWeekHeaderLine (void);
static void WritePostHeaderLine (void);
@@ -338,6 +339,7 @@ UnBackgroundize(int d)
printf("%s", Decolorize());
}
#ifdef REM_USE_WCHAR
static void
send_lrm(void)
{
@@ -352,6 +354,7 @@ send_lrm(void)
printf("\xE2\x80\x8E");
}
}
#endif
static char const *
despace(char const *s)
@@ -526,9 +529,9 @@ get_month_abbrev(char const *mon)
#endif
}
#ifdef REM_USE_WCHAR
static int make_wchar_versions(CalEntry *e)
{
#ifdef REM_USE_WCHAR
size_t len;
wchar_t *buf;
len = mbstowcs(NULL, e->text, 0);
@@ -542,10 +545,8 @@ static int make_wchar_versions(CalEntry *e)
e->wc_text = buf;
e->wc_pos = buf;
return 1;
#else
return 1;
#endif
}
#endif
static void gon(void)
{
@@ -758,13 +759,11 @@ SetMoonEntry(int dse, char const *moon)
if (sscanf(moon, "%d %*d %*d %27[^\x01]", &phase, msg) < 4) {
if (sscanf(moon, "%d", &phase) != 1) {
/* Malformed MOON special; ignore */
fprintf(stderr, "Oops 1\n");
return;
}
}
if (phase < 0 || phase > 3) {
/* Bad phase */
fprintf(stderr, "Oops 2\n");
return;
}
FromDSE(dse, &y, &m, &d);
@@ -902,13 +901,17 @@ static void DoCalendarOneWeek(int nleft)
if (UseVTColors) {
printf("\x1B[1m"); /* Bold */
}
Backgroundize(d);
PrintLeft(buf, ColSpaces-1, '*');
putchar(' ');
UnBackgroundize(d);
if (UseVTColors) {
printf("\x1B[0m"); /* Normal */
}
putchar(' ');
} else {
Backgroundize(d);
PrintLeft(buf, ColSpaces, ' ');
UnBackgroundize(d);
}
gon();
DRAW(tb);
@@ -965,21 +968,20 @@ static void DoCalendarOneWeek(int nleft)
/***************************************************************/
/* */
/* DoCalendarOneMonth */
/* DoSimpleCalendarOneMonth */
/* */
/* Produce a calendar for the current month. */
/* Produce a "simple" calendar for the current month. */
/* */
/* A simple calendar is produced if the -s or -p option */
/* was used. */
/* */
/***************************************************************/
static void DoCalendarOneMonth(void)
static void DoSimpleCalendarOneMonth(void)
{
int y, m, d, mm, yy, i, j;
InitMoonsAndShades();
if (!DoSimpleCalendar) WriteCalHeader();
DidADay = 0;
if (PsCal) {
FromDSE(DSEToday, &y, &m, &d);
if (PsCal == PSCAL_LEVEL1) {
@@ -1052,7 +1054,29 @@ static void DoCalendarOneMonth(void)
}
printf("]\n}");
}
if (!DoSimpleCalendar) WriteCalTrailer();
}
/***************************************************************/
/* */
/* DoCalendarOneMonth */
/* */
/* Produce a calendar for the current month. */
/* */
/***************************************************************/
static void DoCalendarOneMonth(void)
{
InitMoonsAndShades();
if (DoSimpleCalendar) {
DoSimpleCalendarOneMonth();
return;
}
WriteCalHeader();
while (WriteCalendarRow()) /* continue */;
WriteCalTrailer();
}
/***************************************************************/
@@ -1124,13 +1148,17 @@ static int WriteCalendarRow(void)
if (UseVTColors) {
printf("\x1B[1m"); /* Bold */
}
Backgroundize(d+i-wd);
PrintLeft(buf, ColSpaces-1, '*');
putchar(' ');
if (UseVTColors) {
printf("\x1B[0m"); /* Normal */
}
putchar(' ');
UnBackgroundize(d+i-wd);
} else {
Backgroundize(d+i-wd);
PrintLeft(buf, ColSpaces, ' ');
UnBackgroundize(d+i-wd);
}
}
gon();
@@ -1198,15 +1226,17 @@ static void PrintLeft(char const *s, int width, char pad)
{
#ifndef REM_USE_WCHAR
int len = strlen(s);
printf("%s", s);
while (len++ < width) putchar(pad);
int i;
for (i=0; i<len && i<width; i++) {
fputc(*(s+i), stdout);
}
while (i++ < width) putchar(pad);
#else
size_t len = mbstowcs(NULL, s, 0);
int i;
wchar_t static_buf[128];
wchar_t *buf;
wchar_t *ws;
int display_len;
if (!len) {
for (i=0; i<width; i++) {
@@ -1225,13 +1255,16 @@ static void PrintLeft(char const *s, int width, char pad)
}
}
(void) mbstowcs(buf, s, len+1);
display_len = wcswidth(buf, len+1);
ws = buf;
for (i=0; i<width;) {
i=0;
while (i<width) {
if (*ws) {
if (i + wcwidth(*ws) > width) {
break;
}
i += wcwidth(*ws);
PutWideChar(*ws++, NULL);
i+= wcwidth(*ws);
} else {
break;
}
@@ -1244,7 +1277,10 @@ static void PrintLeft(char const *s, int width, char pad)
/* Possibly send lrm control sequence */
send_lrm();
for (i=display_len; i<width; i++) fputc(pad, stdout);
while (i<width) {
fputc(pad, stdout);
i++;
}
if (buf != static_buf) free(buf);
#endif
@@ -1265,7 +1301,7 @@ static void PrintCentered(char const *s, int width, char *pad)
int i;
for (i=0; i<d; i++) fputs(pad, stdout);
for (i=0; i<width; i++) {
for (i=0; i<width-d; i++) {
if (*s) {
if (isspace(*s)) {
putchar(' ');
@@ -1309,13 +1345,14 @@ static void PrintCentered(char const *s, int width, char *pad)
if (d < 0) d = 0;
ws = buf;
for (i=0; i<d; i++) fputs(pad, stdout);
for (i=0; i<width; i++) {
i=0;
while (i+d < width) {
if (*ws) {
PutWideChar(*ws++, NULL);
if (wcwidth(*ws) == 0) {
/* Don't count this character... it's zero-width */
i--;
if (i+d + wcwidth(*ws) > width) {
break;
}
i += wcwidth(*ws);
PutWideChar(*ws++, NULL);
} else {
break;
}
@@ -1327,7 +1364,10 @@ static void PrintCentered(char const *s, int width, char *pad)
/* Possibly send lrm control sequence */
send_lrm();
for (i=d+display_len; i<width; i++) fputs(pad, stdout);
while (i+d<width) {
fputs(pad, stdout);
i++;
}
if (buf != static_buf) free(buf);
#endif
}
@@ -1414,7 +1454,7 @@ static int WriteOneColLine(int col)
/* Find the last space char within the column. */
width = 0;
while (width <= ColSpaces) {
if (!*ws) {
if (!*ws || *ws == '\n') {
wspace = ws;
break;
}
@@ -1520,7 +1560,7 @@ static int WriteOneColLine(int col)
/* Find the last space char within the column. */
while (s - e->pos <= ColSpaces) {
if (!*s) {space = s; break;}
if (!*s || *s == '\n') {space = s; break;}
if (isspace(*s)) space = s;
s++;
}
@@ -1683,7 +1723,12 @@ static void GenerateCalEntries(int col)
/* Note: Since the parser hasn't been used yet, we don't */
/* need to destroy it here. */
default: CreateParser(CurLine, &p);
default:
if (!SuppressImplicitRemWarnings) {
Wprint("Unrecognized command; interpreting as REM");
WarnedAboutImplicit = 1;
}
CreateParser(CurLine, &p);
r=DoCalRem(&p, col);
break;
}
@@ -2142,7 +2187,9 @@ static int DoCalRem(ParsePtr p, int col)
FreeTrig(&trig);
return E_NO_MEM;
}
#ifdef REM_USE_WCHAR
make_wchar_versions(e);
#endif
DBufInit(&(e->tags));
DBufPuts(&(e->tags), DBufValue(&(trig.tags)));
if (SynthesizeTags) {

View File

@@ -1,52 +1,119 @@
/* Define if your <sys/time.h> declares struct tm. */
#undef TM_IN_SYS_TIME
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Define if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define if you have the <sys/inotify.h> header file. */
#undef HAVE_SYS_INOTIFY_H
/* Define if you have the <glob.h> header file */
#undef HAVE_GLOB_H
/* Define if you have <stdint.h> */
#undef HAVE_STDINT_H
#undef HAVE_STRINGS_H
#undef HAVE_STRDUP
#undef HAVE_STRCASECMP
#undef HAVE_STRNCASECMP
#undef HAVE_WCTYPE_H
#undef HAVE_LOCALE_H
#undef HAVE_INOTIFY_INIT1
#undef HAVE_LANGINFO_H
/* Configuration command used to build Remind */
#undef CONFIG_CMD
/* Define to 1 if you have the `glob' function. */
#undef HAVE_GLOB
#undef HAVE_SETENV
/* Define to 1 if you have the <glob.h> header file. */
#undef HAVE_GLOB_H
/* Define to 1 if you have the `initgroups' function. */
#undef HAVE_INITGROUPS
#undef HAVE_UNSETENV
/* Define to 1 if you have the `inotify_init1' function. */
#undef HAVE_INOTIFY_INIT1
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <langinfo.h> header file. */
#undef HAVE_LANGINFO_H
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
/* Define to 1 if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
/* Define to 1 if you have the `mbstowcs' function. */
#undef HAVE_MBSTOWCS
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
/* Define to 1 if you have the `setlocale' function. */
#undef HAVE_SETLOCALE
/* The number of bytes in a unsigned int. */
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdio.h> header file. */
#undef HAVE_STDIO_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strcasecmp' function. */
#undef HAVE_STRCASECMP
/* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strncasecmp' function. */
#undef HAVE_STRNCASECMP
/* Define to 1 if you have the <sys/inotify.h> header file. */
#undef HAVE_SYS_INOTIFY_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `unsetenv' function. */
#undef HAVE_UNSETENV
/* Define to 1 if you have the <wctype.h> header file. */
#undef HAVE_WCTYPE_H
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* The size of `time_t', as computed by sizeof. */
#undef SIZEOF_TIME_T
/* The size of `unsigned int', as computed by sizeof. */
#undef SIZEOF_UNSIGNED_INT
/* The number of bytes in a unsigned long. */
/* The size of `unsigned long', as computed by sizeof. */
#undef SIZEOF_UNSIGNED_LONG
#define PACKAGE_NAME "@PACKAGE_NAME@"
#define PACKAGE_URL "@PACKAGE_URL@"
/* Define to 1 if all of the C90 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#undef STDC_HEADERS
#include "custom.h"
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
#include <custom.h>

View File

@@ -32,6 +32,152 @@ static int ParseUntil (ParsePtr s, Trigger *t, int type);
static int ShouldTriggerBasedOnWarn (Trigger *t, int dse, int *err);
static int ComputeTrigDuration(TimeTrig *t);
static int
ensure_expr_references_first_local_arg(expr_node *node)
{
expr_node *other;
if (!node) {
return 0;
}
if (node->type == N_LOCAL_VAR && node->u.arg == 0) {
return 1;
}
if (ensure_expr_references_first_local_arg(node->child)) {
return 1;
}
other = node->sibling;
while (other) {
if (ensure_expr_references_first_local_arg(other)) {
return 1;
}
other = other->sibling;
}
return 0;
}
static void
check_trigger_function(char const *fname, char const *type)
{
UserFunc *f;
if (!*fname) {
return;
}
f = FindUserFunc(fname);
if (!f) {
if (strcmp(type, "WARN")) {
/* Undefined WARN functions are diagnosed elsewhere... */
Wprint("Undefined %s function: `%s'", type, fname);
}
return;
}
if (f->nargs != 1) {
Wprint("%s function `%s' defined at %s:%d should take 1 argument but actually takes %d", type, fname, f->filename, f->lineno, f->nargs);
return;
}
if (ensure_expr_references_first_local_arg(f->node)) {
return;
}
Wprint("%s function `%s' defined at %s:%d does not use its argument", type, fname, f->filename, f->lineno);
}
static void
ensure_satnode_mentions_trigdate_aux(expr_node *node, int *mentioned)
{
char const *name;
expr_node *other;
UserFunc *f;
if (!node) {
return;
}
if (*mentioned) {
return;
}
if (node->type == N_BUILTIN_FUNC) {
name = node->u.builtin_func->name;
if (!strcmp(name, "trigdate") ||
!strcmp(name, "trigdatetime")) {
*mentioned = 1;
return;
}
} else if (node->type == N_SHORT_SYSVAR || node->type == N_SYSVAR) {
if (node->type == N_SHORT_SYSVAR) {
name = node->u.name;
} else {
name = node->u.value.v.str;
}
if (!StrCmpi(name, "T") ||
!StrCmpi(name, "Td") ||
!StrCmpi(name, "Tm") ||
!StrCmpi(name, "Tw") ||
!StrCmpi(name, "Ty")) {
*mentioned = 1;
return;
}
} else if (node->type == N_SHORT_USER_FUNC || node->type == N_USER_FUNC) {
if (node->type == N_SHORT_USER_FUNC) {
name = node->u.name;
} else {
name = node->u.value.v.str;
}
f = FindUserFunc(name);
if (f && !f->recurse_flag) {
f->recurse_flag = 1;
ensure_satnode_mentions_trigdate_aux(f->node, mentioned);
f->recurse_flag = 0;
if (*mentioned) {
return;
}
}
}
ensure_satnode_mentions_trigdate_aux(node->child, mentioned);
if (*mentioned) {
return;
}
other = node->sibling;
while (other) {
ensure_satnode_mentions_trigdate_aux(other, mentioned);
if (*mentioned) {
return;
}
other = other->sibling;
}
}
static void ensure_satnode_mentions_trigdate(expr_node *node)
{
int mentioned = 0;
char const *str;
if (node->type == N_CONSTANT || node->type == N_SHORT_STR) {
if (node->type == N_CONSTANT) {
if (node->u.value.type == INT_TYPE) {
if (node->u.value.v.val == 0) {
Wprint("SATISFY: constant 0 will never be true");
}
return;
}
if (node->u.value.type != STR_TYPE) {
return;
}
str = node->u.value.v.str;
} else {
str = node->u.name;
}
if (!*str) {
Wprint("SATISFY: constant \"\" will never be true");
}
return;
}
ensure_satnode_mentions_trigdate_aux(node, &mentioned);
if (!mentioned) {
Wprint("SATISFY: expression has no reference to trigdate() or $T...");
}
}
static int
ComputeTrigDuration(TimeTrig *t)
{
@@ -62,7 +208,7 @@ int DoRem(ParsePtr p)
DBufInit(&buf);
/* Parse the trigger date and time */
if ( (r=ParseRem(p, &trig, &tim)) ) {
if ( (r=ParseRem(p, &trig, &tim)) != OK ) {
FreeTrig(&trig);
return r;
}
@@ -291,10 +437,17 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
break;
case T_Date:
DBufFree(&buf);
if (trig->d != NO_DAY) return E_DAY_TWICE;
if (trig->m != NO_MON) return E_MON_TWICE;
if (trig->y != NO_YR) return E_YR_TWICE;
DBufFree(&buf);
if (trig->d != NO_DAY) {
return E_DAY_TWICE;
}
if (trig->m != NO_MON) {
return E_MON_TWICE;
}
if (trig->y != NO_YR) {
return E_YR_TWICE;
}
FromDSE(tok.val, &y, &m, &d);
trig->y = y;
trig->m = m;
@@ -396,6 +549,12 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
if (r) return r;
break;
case T_Number:
DBufFree(&buf);
Eprint("`%d' is not recognized as a year (%d-%d) or a day number (1-31)",
tok.val, BASE, BASE+YR_RANGE);
return E_PARSE_ERR;
case T_Year:
DBufFree(&buf);
if (trig->y != NO_YR) return E_YR_TWICE;
@@ -536,10 +695,19 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
break;
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
PushToken(DBufValue(&buf), s);
DBufFree(&buf);
trig->typ = MSG_TYPE;
if (s->isnested) return E_CANT_NEST_RTYPE;
if (!WarnedAboutImplicit && !SuppressImplicitRemWarnings) {
Wprint("Missing REM type; assuming MSG");
WarnedAboutImplicit = 1;
}
parsing = 0;
break;
}
@@ -591,6 +759,11 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
trig->scanfrom = DSEToday;
}
/* Check that any SCHED / WARN / OMITFUNC functions refer to
their arguments */
check_trigger_function(trig->sched, "SCHED");
check_trigger_function(trig->warn, "WARN");
check_trigger_function(trig->omitfunc, "OMITFUNC");
return OK;
}
@@ -632,6 +805,11 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim)
break;
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
if (tim->ttime == NO_TIME) return E_EXPECT_TIME;
PushToken(DBufValue(&buf), s);
@@ -749,6 +927,11 @@ static int ParseUntil(ParsePtr s, Trigger *t, int type)
break;
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
Eprint("%s: %s", which, ErrMsg[E_INCOMPLETE]);
DBufFree(&buf);
@@ -868,6 +1051,11 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
break;
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]);
DBufFree(&buf);
@@ -1283,6 +1471,10 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
if (!sat_node) {
return E_SWERR;
}
/* Diagnose if SAT_NODE does not reference trigdate */
ensure_satnode_mentions_trigdate(sat_node);
iter = 0;
start = trig->scanfrom;
while (iter++ < MaxSatIter) {

View File

@@ -31,6 +31,19 @@
#define SHIP_OUT(s) if(DBufPuts(dbuf, s) != OK) return E_NO_MEM
static int
check_subst_args(UserFunc *f, int n)
{
if (!f) {
return 0;
}
if (f->nargs == n) {
return 1;
}
Wprint("Function `%s' defined at %s:%d should take %d argument%s, but actually takes %d",
f->name, f->filename, f->lineno, n, (n == 1 ? "" : "s"), f->nargs);
return 0;
}
/***************************************************************/
/* */
/* DoSubst */
@@ -67,6 +80,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
int altmode;
int r;
Value v;
UserFunc *func;
FromDSE(dse, &y, &m, &d);
@@ -100,7 +114,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
L_AMPM_OVERRIDE (pm, h)
#else
r = -1;
if (UserFuncExists("subst_ampm") == 1) {
func = FindUserFunc("subst_ampm");
if (func && check_subst_args(func, 1)) {
snprintf(s, sizeof(s), "subst_ampm(%d)", h);
expr = (char const *) s;
r = EvalExpr(&expr, &v, NULL);
@@ -129,7 +144,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
L_AMPM_OVERRIDE (cpm, ch)
#else
r = -1;
if (UserFuncExists("subst_ampm") == 1) {
func = FindUserFunc("subst_ampm");
if (func && check_subst_args(func, 1)) {
snprintf(s, sizeof(s), "subst_ampm(%d)", ch);
expr = (char const *) s;
r = EvalExpr(&expr, &v, NULL);
@@ -154,7 +170,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
#ifdef L_ORDINAL_OVERRIDE
L_ORDINAL_OVERRIDE;
#else
if (UserFuncExists("subst_ordinal") == 1) {
func = FindUserFunc("subst_ordinal");
if (func && check_subst_args(func, 1)) {
snprintf(s, sizeof(s), "subst_ordinal(%d)", d);
expr = (char const *) s;
r = EvalExpr(&expr, &v, NULL);
@@ -250,7 +267,13 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
if (!c) {
Wprint("Warning: Unterminated %%{...} substitution sequence");
}
if (UserFuncExists(s) != 3) {
func = FindUserFunc(s);
if (!func) {
Wprint("No substition function `%s' defined", s);
continue;
}
if (!check_subst_args(func, 3)) {
continue;
}
snprintf(ss, sizeof(s) - (ss-s), "(%d,'%04d-%02d-%02d',%02d:%02d)",
@@ -270,7 +293,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
}
done = 0;
snprintf(uf, sizeof(uf), "subst_%c", tolower(c));
if (UserFuncExists(uf) == 3) {
func = FindUserFunc(uf);
if (func && check_subst_args(func, 3)) {
snprintf(s, sizeof(s), "subst_%c(%d,'%04d-%02d-%02d',%02d:%02d)",
tolower(c), altmode ? 1 : 0, y, m+1, d, h, min);
expr = (char const *) s;
@@ -345,7 +369,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
if (!done) {
snprintf(uf, sizeof(uf), "subst_%cx", tolower(c));
if (UserFuncExists(uf) == 3) {
func = FindUserFunc(uf);
if (func && check_subst_args(func, 3)) {
snprintf(s, sizeof(s), "subst_%cx(%d,'%04d-%02d-%02d',%02d:%02d)",
tolower(c), altmode ? 1 : 0, y, m+1, d, h, min);
expr = (char const *) s;
@@ -797,7 +822,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
break;
case '_':
if (PsCal == PSCAL_LEVEL2 || PsCal == PSCAL_LEVEL3 || (mode != CAL_MODE && mode != ADVANCE_MODE && !(MsgCommand && *MsgCommand))) {
if (PsCal == PSCAL_LEVEL2 || PsCal == PSCAL_LEVEL3 || DoCalendar || (mode != CAL_MODE && mode != ADVANCE_MODE && !(MsgCommand && *MsgCommand))) {
snprintf(s, sizeof(s), "%s", NL);
} else {
snprintf(s, sizeof(s), " ");

View File

@@ -152,7 +152,6 @@ int DBufGets(DynamicBuffer *dbuf, FILE *fp)
/* Try reading the first few bytes right into the buffer --
we can usually save some unnecessary copying */
*(dbuf->buffer) = 0;
if (fgets(dbuf->buffer, dbuf->allocatedLen, fp) == NULL) {
return OK;
}

View File

@@ -204,7 +204,7 @@ EXTERN char *ErrMsg[]
/* E_ERR_READING */ "Error reading",
/* E_EXPECTING_EOL */ "Expecting end-of-line",
/* E_BAD_HEBDATE */ "Invalid Hebrew date",
/* E_IIF_ODD */ "IIF needs odd number of arguments",
/* E_IIF_ODD */ "iif(): odd number of arguments required",
/* E_MISS_ENDIF */ "Warning: Missing ENDIF",
/* E_EXPECT_COMMA */ "Expecting comma",
/* E_WD_TWICE */ "Weekday specified twice",
@@ -241,7 +241,7 @@ EXTERN char *ErrMsg[]
/* E_NOREMINDERS */ "No reminders.",
/* M_QUEUED */ "%d reminder(s) queued for later today.\n",
/* E_EXPECTING_NUMBER */ "Expecting number",
/* M_BAD_WARN_FUNC */ "Bad function in WARN clause",
/* M_BAD_WARN_FUNC */ "Undefined WARN function",
/* E_CANT_CONVERT_TZ */ "Can't convert between time zones",
/* E_NO_MATCHING_REMS */ "No files matching *.rem",
/* E_STRING_TOO_LONG */ "String too long",

View File

@@ -38,8 +38,8 @@
5) N_BUILTIN_FUNC: A reference to a built-in function
6) N_USER_FUNC: A reference to a user-defined function
7) N_OPERATOR: A reference to an operator such as "+" or "&&"
8) N_ERROR: A node resulting from a parse error
9) N_SHORT_STR: A string constant short enough to store in u.name
8) N_SHORT_STR: A string constant short enough to store in u.name
9) N_ERROR: An uninitialized node, or a parse error
Additional types are N_SHORT_VAR, N_SHORT_SYSVAR, and N_SHORT_USER_FUNC
which behave identically to N_VARIABLE, N_SYSVAR and N_USER_FUNC
@@ -97,7 +97,7 @@
1) For N_CONSTANT nodes: The constant
2) For N_VARIABLE nodes: The value of the variable
3) For N_SYSVAR nodes: The value of the system variable
4) For N_LOCAL_VAR nodes: The value of the user-defined functions argument
4) For N_LOCAL_VAR nodes: The value of the user-defined function's argument
User-defined functions contain their own expr_node tree. This is
evaluated with the "locals" parameter set to the values of all
@@ -156,7 +156,7 @@
/* Constants for the "how" arg to compare() */
enum { EQ, GT, LT, GE, LE, NE };
/* Our pool of free expr_node objext, as a linked list, linked by child ptr */
/* Our pool of free expr_node objects, as a linked list, linked by child ptr */
static expr_node *expr_node_free_list = NULL;
#define TOKEN_IS(x) (!strcmp(DBufValue(&ExprBuf), x))
@@ -231,7 +231,7 @@ alloc_expr_node(int *r)
if (ExprNodesUsed > ExprNodesHighWater) ExprNodesHighWater = ExprNodesUsed;
node = expr_node_free_list;
expr_node_free_list = node->child;
node->type = N_FREE;
node->type = N_ERROR;
node->child = NULL;
node->sibling = NULL;
node->num_kids = 0;
@@ -425,8 +425,14 @@ eval_builtin(expr_node *node, Value *locals, Value *ans, int *nonconst)
Value stack_args[STACK_ARGS_MAX];
/* Check that we have the right number of argumens */
if (node->num_kids < f->minargs) return E_2FEW_ARGS;
if (node->num_kids > f->maxargs && f->maxargs != NO_MAX) return E_2MANY_ARGS;
if (node->num_kids < f->minargs) {
Eprint("%s(): %s", f->name, ErrMsg[E_2FEW_ARGS]);
return E_2FEW_ARGS;
}
if (node->num_kids > f->maxargs && f->maxargs != NO_MAX) {
Eprint("%s(): %s", f->name, ErrMsg[E_2MANY_ARGS]);
return E_2MANY_ARGS;
}
/* If this is a new-style function that knows about expr_nodes,
let it evaluate itself */
@@ -622,10 +628,12 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* Make sure we have the right number of arguments */
if (node->num_kids < f->nargs) {
DBG(fprintf(ErrFp, "%s(...) => %s\n", fname, ErrMsg[E_2FEW_ARGS]));
Eprint("%s(): %s", f->name, ErrMsg[E_2FEW_ARGS]);
return E_2FEW_ARGS;
}
if (node->num_kids > f->nargs) {
DBG(fprintf(ErrFp, "%s(...) => %s\n", fname, ErrMsg[E_2MANY_ARGS]));
Eprint("%s(): %s", f->name, ErrMsg[E_2MANY_ARGS]);
return E_2MANY_ARGS;
}
@@ -677,16 +685,12 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* Add a call to the call stack for better error messages */
pushed = push_call(f->filename, f->name, f->lineno);
if (DebugFlag & DB_PRTEXPR) {
debug_enter_userfunc(node, new_locals, f->nargs);
}
DBG(debug_enter_userfunc(node, new_locals, f->nargs));
/* Evaluate the function's expr_node tree */
r = evaluate_expr_node(f->node, new_locals, ans, nonconst);
if (DebugFlag & DB_PRTEXPR) {
debug_exit_userfunc(node, ans, r, new_locals, f->nargs);
}
DBG(debug_exit_userfunc(node, ans, r, new_locals, f->nargs));
if (r != OK) {
/* We print the error here in order to get the call stack trace */
@@ -1367,7 +1371,7 @@ static int divide_or_mod(expr_node *node, Value *locals, Value *ans, int *noncon
/***************************************************************/
/* */
/* domod - evaluate the "%" operator */
/* do_mod - evaluate the "%" operator */
/* */
/***************************************************************/
static int do_mod(expr_node *node, Value *locals, Value *ans, int *nonconst)
@@ -1397,14 +1401,10 @@ static int logical_not(expr_node *node, Value *locals, Value *ans, int *nonconst
r = evaluate_expr_node(node->child, locals, &v1, nonconst);
if (r != OK) return r;
if (v1.type != INT_TYPE) {
DBG(debug_evaluation_unop(ans, E_BAD_TYPE, &v1, "!"));
DestroyValue(v1);
return E_BAD_TYPE;
}
ans->type = INT_TYPE;
ans->v.val = !(v1.v.val);
ans->v.val = !truthy(&v1);
DBG(debug_evaluation_unop(ans, OK, &v1, "!"));
DestroyValue(v1);
return OK;
}
@@ -1452,22 +1452,16 @@ static int logical_binop(expr_node *node, Value *locals, Value *ans, int *noncon
/* Bail on error */
if (r != OK) return r;
if (v.type == STR_TYPE) {
DBG(debug_evaluation_binop(ans, E_BAD_TYPE, &v, NULL, opname));
DestroyValue(v);
return E_BAD_TYPE;
}
if (is_and) {
/* If first arg is false, return it */
if (!v.v.val) {
if (!truthy(&v)) {
*ans = v;
DBG(debug_evaluation_binop(ans, OK, &v, NULL, opname));
return OK;
}
} else {
/* If first arg is true, return it */
if (v.v.val) {
if (truthy(&v)) {
*ans = v;
DBG(debug_evaluation_binop(ans, OK, &v, NULL, opname));
return OK;
@@ -1476,12 +1470,8 @@ static int logical_binop(expr_node *node, Value *locals, Value *ans, int *noncon
/* Otherwise, evaluate and return second arg */
r = evaluate_expr_node(node->child->sibling, locals, ans, nonconst);
if (r == OK && ans->type == STR_TYPE) {
DBG(debug_evaluation_binop(ans, E_BAD_TYPE, &v, ans, opname));
DestroyValue(*ans);
return E_BAD_TYPE;
}
DBG(debug_evaluation_binop(ans, r, &v, ans, opname));
DestroyValue(v);
return r;
}
@@ -1512,18 +1502,7 @@ static int logical_and(expr_node *node, Value *locals, Value *ans, int *nonconst
/* Read a token. */
/* */
/***************************************************************/
static int parse_expr_token_aux(DynamicBuffer *buf, char const **in);
static int parse_expr_token(DynamicBuffer *buf, char const **in)
{
int r = parse_expr_token_aux(buf, in);
/* Munch any following whitespace */
while (**in && isempty(**in)) (*in)++;
return r;
}
static int parse_expr_token_aux(DynamicBuffer *buf, char const **in)
{
char c;
@@ -1561,9 +1540,11 @@ static int parse_expr_token_aux(DynamicBuffer *buf, char const **in)
return E_NO_MEM;
}
(*in)++;
}
return OK;
} else {
Eprint("%s `%c' (did you mean `%c%c'?)", ErrMsg[E_PARSE_ERR], c, c, c);
return E_PARSE_ERR;
}
return OK;
case '!':
case '>':
case '<':
@@ -1704,7 +1685,7 @@ static int parse_expr_token_aux(DynamicBuffer *buf, char const **in)
/***************************************************************/
static int peek_expr_token(DynamicBuffer *buf, char const *in)
{
return parse_expr_token_aux(buf, &in);
return parse_expr_token(buf, &in);
}
/***************************************************************/
@@ -1717,7 +1698,7 @@ static int peek_expr_token(DynamicBuffer *buf, char const *in)
/***************************************************************/
expr_node * free_expr_tree(expr_node *node)
{
if (node) {
if (node && (node->type != N_FREE)) {
ExprNodesUsed--;
if (node->type == N_CONSTANT ||
node->type == N_VARIABLE ||
@@ -1784,6 +1765,7 @@ static expr_node * parse_function_call(char const **e, int *r, Var *locals, int
expr_node *node;
expr_node *arg;
char *s;
char const *ptr;
CHECK_PARSE_LEVEL();
node = alloc_expr_node(r);
@@ -1856,6 +1838,7 @@ static expr_node * parse_function_call(char const **e, int *r, Var *locals, int
}
}
if (TOKEN_IS(")")) {
ptr = *e;
*r = GET_TOKEN();
if (*r != OK) {
return free_expr_tree(node);
@@ -1864,8 +1847,14 @@ static expr_node * parse_function_call(char const **e, int *r, Var *locals, int
/* Check args for builtin funcs */
if (node->type == N_BUILTIN_FUNC) {
f = node->u.builtin_func;
if (node->num_kids < f->minargs) *r = E_2FEW_ARGS;
if (node->num_kids > f->maxargs && f->maxargs != NO_MAX) *r = E_2MANY_ARGS;
if (node->num_kids < f->minargs) {
*e = ptr;
*r = E_2FEW_ARGS;
}
if (node->num_kids > f->maxargs && f->maxargs != NO_MAX) {
*e = ptr;
*r = E_2MANY_ARGS;
}
}
if (*r != OK) {
if (node->type == N_BUILTIN_FUNC) {
@@ -1915,11 +1904,25 @@ static int set_constant_value(expr_node *atom)
return OK;
} else if (*s == '\'') { /* It's a literal date */
s++;
if ((r=ParseLiteralDate(&s, &dse, &tim)) != 0) return r;
if (*s != '\'') return E_BAD_DATE;
if ((r=ParseLiteralDateOrTime(&s, &dse, &tim)) != 0) {
Eprint("%s: %s", ErrMsg[r], DBufValue(&ExprBuf));
return r;
}
if (*s != '\'') {
if (dse != NO_DATE) {
Eprint("%s: %s", ErrMsg[E_BAD_DATE], DBufValue(&ExprBuf));
return E_BAD_DATE;
} else {
Eprint("%s: %s", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
return E_BAD_TIME;
}
}
if (tim == NO_TIME) {
atom->u.value.type = DATE_TYPE;
atom->u.value.v.val = dse;
} else if (dse == NO_DATE) {
atom->u.value.type = TIME_TYPE;
atom->u.value.v.val = tim;
} else {
atom->u.value.type = DATETIME_TYPE;
atom->u.value.v.val = (dse * MINUTES_PER_DAY) + tim;
@@ -1940,7 +1943,10 @@ static int set_constant_value(expr_node *atom)
}
if (*s == ':' || *s == '.' || *s == TimeSep) { /* Must be a literal time */
s++;
if (!isdigit(*s)) return E_BAD_TIME;
if (!isdigit(*s)) {
Eprint("%s: `%s'", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
return E_BAD_TIME;
}
h = val;
m = 0;
while (isdigit(*s)) {
@@ -1956,9 +1962,15 @@ static int set_constant_value(expr_node *atom)
s++;
}
}
if (*s || h>23 || m>59) return E_BAD_TIME;
if (*s || h>23 || m>59) {
Eprint("%s: `%s'", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
return E_BAD_TIME;
}
if (ampm) {
if (h < 1 || h > 12) return E_BAD_TIME;
if (h < 1 || h > 12) {
Eprint("%s: `%s'", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
return E_BAD_TIME;
}
if (ampm == 'a') {
if (h == 12) {
h = 0;
@@ -1974,7 +1986,10 @@ static int set_constant_value(expr_node *atom)
return OK;
}
/* Not a time - must be a number */
if (*s) return E_BAD_NUMBER;
if (*s) {
Eprint("%s: `%s'", ErrMsg[E_BAD_NUMBER], DBufValue(&ExprBuf));
return E_BAD_NUMBER;
}
atom->u.value.type = INT_TYPE;
atom->u.value.v.val = val;
return OK;
@@ -2022,7 +2037,7 @@ static int make_atom(expr_node *atom, Var *locals)
/* System Variable */
if (*(s) == '$' && isalpha(*(s+1))) {
if (!FindSysVar(s+1)) {
Eprint("`%s': %s", s, ErrMsg[E_NOSUCH_VAR]);
Eprint("%s: `%s'", ErrMsg[E_NOSUCH_VAR], s);
return E_NOSUCH_VAR;
}
if (strlen(s+1) < SHORT_NAME_BUF) {
@@ -2167,22 +2182,6 @@ static expr_node *parse_factor(char const **e, int *r, Var *locals, int level)
return NULL;
}
/* If the child is a constant int, optimize! */
if (node->type == N_CONSTANT &&
node->u.value.type == INT_TYPE) {
if (op == '-') {
if (node->u.value.v.val == INT_MIN) {
*r = E_2LOW;
return free_expr_tree(node);
}
node->u.value.v.val = -node->u.value.v.val;
} else {
node->u.value.v.val = !node->u.value.v.val;
}
return node;
}
/* Not a constant int; we need to add a node */
factor_node = alloc_expr_node(r);
if (!factor_node) {
free_expr_tree(node);
@@ -2524,15 +2523,23 @@ expr_node *parse_expression(char const **e, int *r, Var *locals)
}
}
if (*r == E_EXPECT_COMMA ||
*r == E_PARSE_ERR ||
*r == E_MISS_RIGHT_PAREN ||
*r == E_EXPECTING_EOL ||
*r == E_2MANY_ARGS ||
*r == E_2FEW_ARGS ||
*r == E_PARSE_ERR ||
*r == E_EOLN ||
*r == E_ILLEGAL_CHAR) {
orig = o2;
while (*orig) {
fprintf(ErrFp, "%c", *orig++);
if (*orig == '\n') {
fprintf(ErrFp, " ");
orig++;
} else if (*orig == ']' && ! *(orig+1)) {
break;
} else {
fprintf(ErrFp, "%c", *orig++);
}
}
fprintf(ErrFp, "\n");
orig = o2;
@@ -2865,25 +2872,32 @@ int ParseLiteralTime(char const **s, int *tim)
/***************************************************************/
/* */
/* ParseLiteralDate */
/* ParseLiteralDateOrTime */
/* */
/* Parse a literal date or datetime. Return result in dse */
/* and tim; update s. */
/* */
/***************************************************************/
int ParseLiteralDate(char const **s, int *dse, int *tim)
int ParseLiteralDateOrTime(char const **s, int *dse, int *tim)
{
int y, m, d;
int r;
char const *orig_s = *s;
y=0; m=0; d=0;
*tim = NO_TIME;
*dse = NO_DATE;
if (!isdigit(**s)) return E_BAD_DATE;
while (isdigit(**s)) {
y *= 10;
y += *(*s)++ - '0';
}
if (**s == ':' || **s == '.' || **s == TimeSep) {
*s = orig_s;
return ParseLiteralTime(s, tim);
}
if (**s != '/' && **s != '-' && **s != DateSep) return E_BAD_DATE;
(*s)++;
if (!isdigit(**s)) return E_BAD_DATE;
@@ -2939,7 +2953,8 @@ int DoCoerce(char type, Value *v)
return OK;
case STR_TYPE:
s = v->v.str;
if (ParseLiteralDate(&s, &i, &m)) return E_CANT_COERCE;
if (ParseLiteralDateOrTime(&s, &i, &m)) return E_CANT_COERCE;
if (i == NO_DATE) return E_CANT_COERCE;
if (*s) return E_CANT_COERCE;
v->type = DATETIME_TYPE;
free(v->v.str);
@@ -3021,7 +3036,8 @@ int DoCoerce(char type, Value *v)
case STR_TYPE:
s = v->v.str;
if (ParseLiteralDate(&s, &i, &m)) return E_CANT_COERCE;
if (ParseLiteralDateOrTime(&s, &i, &m)) return E_CANT_COERCE;
if (i == NO_DATE) return E_CANT_COERCE;
if (*s) return E_CANT_COERCE;
v->type = DATE_TYPE;
free(v->v.str);
@@ -3047,6 +3063,7 @@ int DoCoerce(char type, Value *v)
case STR_TYPE:
s = v->v.str;
i=0; /* Avoid compiler warning */
if (ParseLiteralTime(&s, &i)) return E_CANT_COERCE;
if (*s) return E_CANT_COERCE;
v->type = TIME_TYPE;
@@ -3076,3 +3093,17 @@ void print_expr_nodes_stats(void)
fprintf(stderr, " Expression nodes leaked: %d\n", ExprNodesUsed);
fprintf(stderr, " Parse level high-water: %d\n", parse_level_high_water);
}
/* Return 1 if a value is "true" for its type, 0 if "false" */
int truthy(Value const *v)
{
if (v->type == STR_TYPE) {
if (v->v.str && *(v->v.str)) {
return 1;
} else {
return 0;
}
}
return (v->v.val != 0);
}

View File

@@ -102,6 +102,13 @@ static int CheckSafetyAux (struct stat *statbuf);
static int PopFile (void);
static int IncludeCmd(char const *);
static void
got_a_fresh_line(void)
{
FreshLine = 1;
WarnedAboutImplicit = 0;
}
void set_cloexec(FILE *fp)
{
int flags;
@@ -182,7 +189,7 @@ int ReadLine(void)
CurLine = CLine->text;
LineNo = CLine->LineNo;
CLine = CLine->next;
FreshLine = 1;
got_a_fresh_line();
clear_callstack();
if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp);
return OK;
@@ -283,7 +290,7 @@ static int ReadLineFromFile(int use_pclose)
CurLine = DBufValue(&LineBuffer);
}
FreshLine = 1;
got_a_fresh_line();
clear_callstack();
if (DebugFlag & DB_ECHO_LINE) OutputLine(ErrFp);
return OK;
@@ -849,7 +856,7 @@ static int IncludeCmd(char const *cmd)
char const *fname;
int old_flag;
FreshLine = 1;
got_a_fresh_line();
clear_callstack();
if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE;
i = &IStack[IStackPtr];
@@ -968,7 +975,7 @@ int IncludeFile(char const *fname)
int oldRunDisabled;
struct stat statbuf;
FreshLine = 1;
got_a_fresh_line();
clear_callstack();
if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE;
i = &IStack[IStackPtr];

View File

@@ -231,7 +231,7 @@ BuiltinFunc Func[] = {
{ "access", 2, 2, 0, FAccess, NULL },
{ "adawn", 0, 1, 0, FADawn, NULL},
{ "adusk", 0, 1, 0, FADusk, NULL},
{ "ampm", 1, 3, 1, FAmpm, NULL },
{ "ampm", 1, 4, 1, FAmpm, NULL },
{ "ansicolor", 1, 5, 1, FAnsicolor, NULL },
{ "args", 1, 1, 0, FArgs, NULL },
{ "asc", 1, 1, 1, FAsc, NULL },
@@ -945,6 +945,8 @@ static int FAmpm(func_info *info)
char const *pm = "PM";
char const *ampm = NULL;
int include_leading_zero = 0;
char outbuf[128];
if (ARG(0).type != DATETIME_TYPE && ARG(0).type != TIME_TYPE) {
@@ -959,6 +961,10 @@ static int FAmpm(func_info *info)
if (Nargs >= 3) {
ASSERT_TYPE(2, STR_TYPE);
pm = ARGSTR(2);
if (Nargs >= 4) {
ASSERT_TYPE(3, INT_TYPE);
include_leading_zero = ARGV(3);
}
}
}
h = TIMEPART(ARG(0)) / 60;
@@ -973,9 +979,17 @@ static int FAmpm(func_info *info)
}
} 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);
if (include_leading_zero) {
snprintf(outbuf, sizeof(outbuf), "%04d%c%02d%c%02d%c%02d%c%02d", yr, DateSep, mo+1, DateSep, da, DateTimeSep, h, TimeSep, m);
} else {
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);
if (include_leading_zero) {
snprintf(outbuf, sizeof(outbuf), "%02d%c%02d", h, TimeSep, m);
} else {
snprintf(outbuf, sizeof(outbuf), "%d%c%02d", h, TimeSep, m);
}
}
}
ampm = am;
@@ -984,9 +998,17 @@ static int FAmpm(func_info *info)
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);
if (include_leading_zero) {
snprintf(outbuf, sizeof(outbuf), "%04d%c%02d%c%02d%c%02d%c%02d", yr, DateSep, mo+1, DateSep, da, DateTimeSep, h, TimeSep, m);
} else {
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);
if (include_leading_zero) {
snprintf(outbuf, sizeof(outbuf), "%02d%c%02d", h, TimeSep, m);
} else {
snprintf(outbuf, sizeof(outbuf), "%d%c%02d", h, TimeSep, m);
}
}
ampm = pm;
}
@@ -1262,6 +1284,7 @@ static int FChoose(expr_node *node, Value *locals, Value *ans, int *nonconst)
PUT(ErrMsg[E_BAD_TYPE]);
OUT();
}
Eprint("choose(): %s", ErrMsg[E_BAD_TYPE]);
return E_BAD_TYPE;
}
n = v.v.val;
@@ -1952,7 +1975,6 @@ static int FIndex(func_info *info)
/***************************************************************/
static int FIif(expr_node *node, Value *locals, Value *ans, int *nonconst)
{
int istrue;
int r;
int done;
Value v;
@@ -1992,26 +2014,8 @@ static int FIif(expr_node *node, Value *locals, Value *ans, int *nonconst)
done = 1;
PUT(PrintValue(&v, NULL));
}
if (v.type != STR_TYPE && v.type != INT_TYPE) {
if (DebugFlag & DB_PRTEXPR) {
cur = cur->sibling;
while(cur) {
PUT(", ?");
cur = cur->sibling;
}
PUT(") => ");
PUT(ErrMsg[E_BAD_TYPE]);
OUT();
}
return E_BAD_TYPE;
}
if (v.type == INT_TYPE) {
istrue = v.v.val;
} else {
istrue = *(v.v.str);
}
if (istrue) {
if (truthy(&v)) {
r = evaluate_expr_node(cur->sibling, locals, ans, nonconst);
if (r == OK && (DebugFlag & DB_PRTEXPR)) {
PUT(", ");
@@ -4001,3 +4005,13 @@ BuiltinFunc *FindBuiltinFunc(char const *name)
}
return NULL;
}
void
print_builtinfunc_tokens(void)
{
int i;
printf("\n# Built-in Functions\n\n");
for (i=0; i<NumFuncs; i++) {
printf("%s\n", Func[i].name);
}
}

View File

@@ -49,6 +49,7 @@ EXTERN int CurMon;
EXTERN int CurYear;
EXTERN int LineNo;
EXTERN int FreshLine;
EXTERN int WarnedAboutImplicit;
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
EXTERN INIT( int MaxLateMinutes, 0);
@@ -170,6 +171,9 @@ EXTERN DynamicBuffer ExprBuf;
/* User-func recursion level */
EXTERN INIT( unsigned int FuncRecursionLevel, 0);
/* Suppress warnings about implicit REM and MSG */
EXTERN INIT( int SuppressImplicitRemWarnings, 0);
extern int NumFullOmits, NumPartialOmits;
/* List of months */

View File

@@ -717,6 +717,10 @@ void InitRemind(int argc, char const *argv[])
break;
default:
if (tok.type == T_Illegal && tok.val < 0) {
fprintf(stderr, "%s: `%s'\n", ErrMsg[-tok.val], arg);
Usage();
}
Usage();
}
}
@@ -1067,6 +1071,16 @@ ProcessLongOption(char const *arg)
printf("%s\n", VERSION);
exit(EXIT_SUCCESS);
}
if (!strcmp(arg, "print-config-cmd")) {
printf("%s\n", CONFIG_CMD);
exit(EXIT_SUCCESS);
}
if (!strcmp(arg, "print-tokens")) {
print_remind_tokens();
print_builtinfunc_tokens();
print_sysvar_tokens();
exit(0);
}
if (sscanf(arg, "max-execution-time=%d", &t) == 1) {
if (t < 0) {
fprintf(ErrFp, "%s: --max-execution-time must be non-negative\n", ArgV[0]);
@@ -1119,6 +1133,8 @@ guess_terminal_background(int *r, int *g, int *b)
if (n != 8) {
/* write failed... WTF? Not much we can do */
tty_reset(ttyfd);
close(ttyfd);
return;
}
@@ -1142,6 +1158,7 @@ guess_terminal_background(int *r, int *g, int *b)
return;
}
tty_reset(ttyfd);
close(ttyfd);
buf[n+1] = 0;
if (n < 25) {
/* Too short */

View File

@@ -60,9 +60,15 @@ exitfunc(void)
/* Kill any execution-time-limiter process */
unlimit_execution_time();
int maxlen, total;
double avglen;
if (DebugFlag & DB_PARSE_EXPR) {
fflush(stdout);
fflush(stderr);
get_var_hash_stats(&total, &maxlen, &avglen);
fprintf(stderr, " Var hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
get_userfunc_hash_stats(&total, &maxlen, &avglen);
fprintf(stderr, "Func hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
UnsetAllUserFuncs();
print_expr_nodes_stats();
}
@@ -83,6 +89,8 @@ static void sigxcpu(int sig)
int r = write(STDERR_FILENO, "\n\nmax-execution-time exceeded.\n\n", 32);
/* Pretend to use r to avoid compiler warning */
/* cppcheck-suppress duplicateExpression */
/* cppcheck-suppress knownArgument */
_exit(1 + (r-r));
}
@@ -351,9 +359,18 @@ static void DoReminders(void)
break;
/* If we don't recognize the command, do a REM by default */
/* If we don't recognize the command, do a REM by default, but warn */
default: DestroyParser(&p); CreateParser(CurLine, &p); purge_handled = 1; r=DoRem(&p); break;
default:
if (!SuppressImplicitRemWarnings) {
Wprint("Unrecognized command; interpreting as REM");
WarnedAboutImplicit = 1;
}
DestroyParser(&p);
CreateParser(CurLine, &p);
purge_handled = 1;
r=DoRem(&p);
break;
}
if (r && (!Hush || r != E_RUN_DISABLED)) {

View File

@@ -129,7 +129,7 @@ static double phase (double, double *, double *, double *, double *, double *, d
/* */
/* jdate */
/* */
/* Convert a date and time to DSE day and fraction. */
/* Convert a date and time to Julian day and fraction. */
/* */
/***************************************************************/
static long jdate(int y, int mon, int day)

View File

@@ -145,7 +145,9 @@ int PushOmitContext(ParsePtr p)
context->partsave = malloc(NumPartialOmits * sizeof(int));
if (NumPartialOmits && !context->partsave) {
free(context->filename);
free(context->fullsave);
if (context->fullsave) {
free(context->fullsave);
}
free(context);
return E_NO_MEM;
}
@@ -399,6 +401,8 @@ int DoOmit(ParsePtr p)
default:
if (tok.type == T_Until) {
Eprint("OMIT: UNTIL not allowed; did you mean THROUGH?");
} else if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
} else {
Eprint("%s: `%s' (OMIT)", ErrMsg[E_UNKNOWN_TOKEN],
DBufValue(&buf));

View File

@@ -55,12 +55,14 @@ int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queu
int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int dse, int *err);
int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse, int mode);
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int dse, int tim);
int ParseLiteralDate (char const **s, int *dse, int *tim);
int ParseLiteralDateOrTime (char const **s, int *dse, int *tim);
int ParseLiteralTime (char const **s, int *tim);
expr_node *parse_expression(char const **e, int *r, Var *locals);
int evaluate_expression(expr_node *node, Value *locals, Value *ans, int *nonconst);
int evaluate_expr_node(expr_node *node, Value *locals, Value *ans, int *nonconst);
int truthy(Value const *v);
void print_expr_tree(expr_node *node, FILE *fp);
void unlimit_execution_time(void);
expr_node *free_expr_tree(expr_node *node);
@@ -240,3 +242,11 @@ void PutWideChar(wchar_t const wc, DynamicBuffer *output);
extern int _private_mul_overflow(int a, int b);
extern int _private_add_overflow(int a, int b);
extern int _private_sub_overflow(int a, int b);
/* Utility functions for dumping tokens */
void print_sysvar_tokens(void);
void print_builtinfunc_tokens(void);
void print_remind_tokens(void);
void get_var_hash_stats(int *total, int *maxlen, double *avglen);
void get_userfunc_hash_stats(int *total, int *maxlen, double *avglen);

View File

@@ -39,19 +39,19 @@ while (isdigit(*(string))) { \
Token TokArray[] = {
/* NAME MINLEN TYPE VALUE */
{ "addomit", 7, T_AddOmit, 0 },
{ "after", 3, T_Skip, AFTER_SKIP },
{ "after", 5, T_Skip, AFTER_SKIP },
{ "april", 3, T_Month, 3 },
{ "at", 2, T_At, 0 },
{ "august", 3, T_Month, 7 },
{ "banner", 3, T_Banner, 0 },
{ "before", 3, T_Skip, BEFORE_SKIP },
{ "before", 6, T_Skip, BEFORE_SKIP },
{ "cal", 3, T_RemType, CAL_TYPE },
{ "clear-omit-context", 5, T_Clr, 0 },
{ "debug", 5, T_Debug, 0 },
{ "december", 3, T_Month, 11 },
{ "do", 2, T_IncludeR, 0 },
{ "dumpvars", 4, T_Dumpvars, 0 },
{ "duration", 3, T_Duration, 0 },
{ "duration", 8, T_Duration, 0 },
{ "else", 4, T_Else, 0 },
{ "endif", 5, T_EndIf, 0 },
{ "errmsg", 6, T_ErrMsg, 0 },
@@ -85,9 +85,9 @@ Token TokArray[] = {
{ "noqueue", 7, T_NoQueue, 0 },
{ "november", 3, T_Month, 10 },
{ "october", 3, T_Month, 9 },
{ "omit", 3, T_Omit, 0 },
{ "omit", 4, T_Omit, 0 },
{ "omitfunc", 8, T_OmitFunc, 0 },
{ "once", 3, T_Once, 0 },
{ "once", 4, T_Once, 0 },
{ "pop-omit-context", 3, T_Pop, 0 },
{ "preserve", 8, T_Preserve, 0 },
{ "priority", 8, T_Priority, 0 },
@@ -103,7 +103,7 @@ Token TokArray[] = {
{ "second", 6, T_Ordinal, 1 },
{ "september", 3, T_Month, 8 },
{ "set", 3, T_Set, 0 },
{ "skip", 3, T_Skip, SKIP_SKIP },
{ "skip", 4, T_Skip, SKIP_SKIP },
{ "special", 7, T_RemType, PASSTHRU_TYPE },
{ "sunday", 3, T_WkDay, 6 },
{ "tag", 3, T_Tag, 0 },
@@ -112,13 +112,28 @@ Token TokArray[] = {
{ "thursday", 3, T_WkDay, 3 },
{ "tuesday", 3, T_WkDay, 1 },
{ "unset", 5, T_UnSet, 0 },
{ "until", 3, T_Until, 0 },
{ "until", 5, T_Until, 0 },
{ "warn", 4, T_Warn, 0 },
{ "wednesday", 3, T_WkDay, 2 }
};
static int TokStrCmp (Token const *t, char const *s);
static void
init_token(Token *t)
{
t->name = NULL;
t->type = T_Illegal;
t->val = 0;
}
static void
token_error(Token *t, int errcode)
{
t->type = T_Illegal;
t->val = -errcode;
}
/***************************************************************/
/* */
/* FindInitialToken */
@@ -132,7 +147,7 @@ char const *FindInitialToken(Token *tok, char const *s)
DynamicBuffer buf;
DBufInit(&buf);
tok->type = T_Illegal;
init_token(tok);
while (isempty(*s)) s++;
@@ -159,7 +174,7 @@ void FindToken(char const *s, Token *tok)
int top, bot, mid, r, max;
int l;
tok->type = T_Illegal;
init_token(tok);
if (! *s) {
tok->type = T_Empty;
return;
@@ -233,9 +248,9 @@ void FindNumericToken(char const *s, Token *t)
int mult = 1, hour, min;
char const *s_orig = s;
int ampm = 0;
int r;
t->type = T_Illegal;
t->val = 0;
init_token(t);
if (isdigit(*s)) {
PARSENUM(t->val, s);
@@ -243,22 +258,37 @@ void FindNumericToken(char const *s, Token *t)
if (*s == '-' || *s == '/') {
char const *p = s_orig;
int dse, tim;
if (ParseLiteralDate(&p, &dse, &tim) == OK) {
if (*p) return;
r = ParseLiteralDateOrTime(&p, &dse, &tim);
if (r == OK) {
if (*p) {
if (tim == NO_TIME) {
t->val = -E_BAD_DATE;
} else {
t->val = -E_BAD_TIME;
}
return;
}
if (tim == NO_TIME) {
t->type = T_Date;
t->val = dse;
return;
}
if (dse == NO_DATE) {
t->type = T_Time;
t->val = tim;
return;
}
t->type = T_DateTime;
t->val = MINUTES_PER_DAY * dse + tim;
}
} else {
token_error(t, r);
}
return;
}
/* If we hit a comma, swallow it. This allows stuff
like Jan 6, 1998 */
if (*s == ',') {
if (*s == ',' && *(s+1) == 0) {
/* 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;
@@ -269,8 +299,16 @@ void FindNumericToken(char const *s, Token *t)
if (*s == ':' || *s == '.' || *s == TimeSep) {
s++;
hour = t->val;
if (!isdigit(*s)) {
token_error(t, E_BAD_TIME);
return;
}
PARSENUM(min, s);
if (min > 59) return; /* Illegal time */
if (min > 59) {
/* Illegal time */
token_error(t, E_BAD_TIME);
return;
}
/* Check for p[m] or a[m] */
if (*s == 'A' || *s == 'a' || *s == 'P' || *s == 'p') {
ampm = tolower(*s);
@@ -279,9 +317,15 @@ void FindNumericToken(char const *s, Token *t)
s++;
}
}
if (*s) return; /* Illegal time */
if (*s) {
token_error(t, E_BAD_TIME);
return;
}
if (ampm) {
if (hour < 1 || hour > 12) return;
if (hour < 1 || hour > 12) {
token_error(t, E_BAD_TIME);
return;
}
if (ampm == 'a') {
if (hour == 12) {
hour = 0;
@@ -303,45 +347,70 @@ void FindNumericToken(char const *s, Token *t)
}
/* If we hit a non-digit, error! */
if (*s) return;
if (*s) {
token_error(t, E_BAD_NUMBER);
return;
}
/* Classify the number we've got */
if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
else if (t->val >= 1 && t->val <= 31) t->type = T_Day;
else t->type = T_Number;
return;
} else if (*s == '*') {
}
switch (*s) {
case '*':
s++;
PARSENUM(t->val, s);
if (*s) return; /* Illegal token if followed by non-numeric char */
if (*s) {
/* Illegal token if followed by non-numeric char */
token_error(t, E_BAD_NUMBER);
return;
}
t->type = T_Rep;
return;
} else if (*s == '+') {
case '+':
s++;
if (*s == '+') { mult = -1; s++; }
PARSENUM(t->val, s);
if (*s) return; /* Illegal token if followed by non-numeric char */
if (*s) {
/* Illegal token if followed by non-numeric char */
token_error(t, E_BAD_NUMBER);
return;
}
t->type = T_Delta;
t->val *= mult;
return;
} else if (*s == '-') {
case '-':
s++;
if (*s == '-') { mult = -1; s++; }
PARSENUM(t->val, s);
if (*s) return; /* Illegal token if followed by non-numeric char */
if (*s) {
/* Illegal token if followed by non-numeric char */
token_error(t, E_BAD_NUMBER);
return;
}
t->type = T_Back;
t->val *= mult;
return;
} else if (*s == '~') {
case '~':
s++;
if (*s == '~') { mult = -1; s++; }
PARSENUM(t->val, s);
if (*s) return; /* Illegal token if followed by non-numeric char */
if (*s) {
/* Illegal token if followed by non-numeric char */
token_error(t, E_BAD_NUMBER);
return;
}
t->type = T_BackAdj;
t->val *= mult;
return;
default: return;
}
return; /* Unknown token type */
}
@@ -368,3 +437,43 @@ static int TokStrCmp(Token const *t, char const *s)
if (!*s || (*s == ',' && !*(s+1))) return 0;
return (*tk - tolower(*s));
}
static void
print_token(Token *tok)
{
if (tok->MinLen < (int) strlen(tok->name)) {
printf("%.*s\n", tok->MinLen, tok->name);
}
printf("%s\n", tok->name);
}
void
print_remind_tokens(void)
{
int i;
Token *tok;
int num = (int) (sizeof(TokArray) / sizeof(TokArray[0]));
printf("# Remind Tokens\n\n");
for (i=0; i<num; i++) {
tok = &TokArray[i];
if (tok->type != T_Month && tok->type != T_WkDay) {
print_token(tok);
}
}
printf("\n# Month Names\n\n");
for (i=0; i<num; i++) {
tok = &TokArray[i];
if (tok->type == T_Month) {
print_token(tok);
}
}
printf("\n# Weekdays\n\n");
for (i=0; i<num; i++) {
tok = &TokArray[i];
if (tok->type == T_WkDay) {
print_token(tok);
}
}
}

View File

@@ -41,8 +41,7 @@ typedef struct {
/* New-style expr_node structure and constants */
enum expr_node_type
{
N_FREE,
N_ERROR,
N_FREE = 0,
N_CONSTANT,
N_SHORT_STR,
N_LOCAL_VAR,
@@ -54,6 +53,7 @@ enum expr_node_type
N_SHORT_USER_FUNC,
N_USER_FUNC,
N_OPERATOR,
N_ERROR = 32767,
};
/* Structure for passing in Nargs and out RetVal from functions */
@@ -317,5 +317,6 @@ typedef struct udf_struct {
int nargs;
char const *filename;
int lineno;
int recurse_flag;
} UserFunc;

View File

@@ -27,7 +27,7 @@
#include "protos.h"
#include "err.h"
#define FUNC_HASH_SIZE 32 /* Size of User-defined function hash table */
#define FUNC_HASH_SIZE 31 /* Size of User-defined function hash table */
/* The hash table */
static UserFunc *FuncHash[FUNC_HASH_SIZE];
@@ -44,17 +44,17 @@ static void FSet (UserFunc *f);
/***************************************************************/
unsigned int HashVal_nocase(char const *str)
{
register unsigned int i=0;
register unsigned int j=1;
register unsigned int len=0;
while(*str && len < VAR_NAME_LEN) {
i += j * (*str);
str++;
len++;
j = 3-j;
unsigned int h = 0, high;
while(*str) {
h = (h << 4) + (unsigned int) *str;
str++;
high = h & 0xF0000000;
if (high) {
h ^= (high >> 24);
}
h &= ~high;
}
return i;
return h;
}
/***************************************************************/
@@ -129,6 +129,9 @@ int DoFset(ParsePtr p)
/* We already have it! Our work here is done. */
return OK;
}
/* Warn about redefinition */
Wprint("Function %s redefined (previously defined at %s:%d)",
existing->name, existing->filename, existing->lineno);
}
/* Should be followed by '(' */
@@ -157,6 +160,7 @@ int DoFset(ParsePtr p)
return E_NO_MEM;
}
func->lineno = LineNo;
func->recurse_flag = 0;
StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN);
DBufFree(&buf);
if (!Hush) {
@@ -203,6 +207,11 @@ int DoFset(ParsePtr p)
local_array[i+1].next = NULL;
func->nargs++;
c = ParseNonSpaceChar(p, &r, 0);
if (r) {
DBufFree(&buf);
DestroyUserFunc(func);
return r;
}
if (c == ')') break;
else if (c != ',') {
DestroyUserFunc(func);
@@ -213,6 +222,10 @@ int DoFset(ParsePtr p)
/* Allow an optional = sign: FSET f(x) = x*x */
c = ParseNonSpaceChar(p, &r, 1);
if (r) {
DestroyUserFunc(func);
return r;
}
if (c == '=') {
(void) ParseNonSpaceChar(p, &r, 0);
}
@@ -237,14 +250,15 @@ int DoFset(ParsePtr p)
}
c = ParseNonSpaceChar(p, &r, 1);
if (c != 0) {
if (c != 0 || r != 0) {
DestroyUserFunc(func);
if (r != 0) return r;
return E_EXPECTING_EOL;
}
/* Save the argument names */
if (func->nargs) {
func->args = calloc(sizeof(char *), func->nargs);
func->args = calloc(func->nargs, sizeof(char *));
for (i=0; i<func->nargs; i++) {
func->args[i] = StrDup(local_array[i].name);
if (!func->args[i]) {
@@ -387,3 +401,28 @@ UnsetAllUserFuncs(void)
FuncHash[i] = NULL;
}
}
void
get_userfunc_hash_stats(int *total, int *maxlen, double *avglen)
{
int len;
int i;
UserFunc *f;
*maxlen = 0;
*total = 0;
for (i=0; i<FUNC_HASH_SIZE; i++) {
len = 0;
f = FuncHash[i];
while(f) {
len++;
(*total)++;
f = f->next;
}
if (len > *maxlen) {
*maxlen = len;
}
}
*avglen = (double) *total / (double) FUNC_HASH_SIZE;
}

View File

@@ -28,7 +28,7 @@
#define UPPER(c) (islower(c) ? toupper(c) : c)
/* The variable hash table */
#define VAR_HASH_SIZE 64
#define VAR_HASH_SIZE 67
#define VARIABLE ErrMsg[E_VAR]
#define VALUE ErrMsg[E_VAL]
#define UNDEF ErrMsg[E_UNDEF]
@@ -461,17 +461,17 @@ static int time_sep_func(int do_set, Value *val)
/***************************************************************/
unsigned int HashVal(char const *str)
{
register unsigned int i=0;
register unsigned int j=1;
register unsigned int len=0;
while(*str && len < VAR_NAME_LEN) {
i += j * (unsigned int) UPPER(*str);
str++;
len++;
j = 3-j;
unsigned int h = 0, high;
while(*str) {
h = (h << 4) + (unsigned int) UPPER(*str);
str++;
high = h & 0xF0000000;
if (high) {
h ^= (high >> 24);
}
h &= ~high;
}
return i;
return h;
}
/***************************************************************/
@@ -572,7 +572,7 @@ int GetVarValue(char const *str, Value *val)
v=FindVar(str, 0);
if (!v) {
Eprint("%s: %s", ErrMsg[E_NOSUCH_VAR], str);
Eprint("%s: `%s'", ErrMsg[E_NOSUCH_VAR], str);
return E_NOSUCH_VAR;
}
return CopyValue(val, &v->v);
@@ -587,7 +587,7 @@ int DoSet (Parser *p)
{
Value v;
int r;
int ch;
DynamicBuffer buf;
DynamicBuffer buf2;
DBufInit(&buf);
@@ -597,8 +597,11 @@ int DoSet (Parser *p)
if (r) return r;
/* Allow optional equals-sign: SET var = value */
if (ParseNonSpaceChar(p, &r, 1) == '=') {
ch = ParseNonSpaceChar(p, &r, 1);
if (r) return r;
if (ch == '=') {
ParseNonSpaceChar(p, &r, 0);
if (r) return r;
}
if (p->isnested) {
@@ -931,6 +934,7 @@ static SysVar SysVarArr[] = {
{"SortByTime", 0, INT_TYPE, &SortByTime, 0, 0 },
{"SubsIndent", 1, INT_TYPE, &SubsIndent, 0, 132 },
{"Sunday", 1, STR_TYPE, &DynamicDayName[6], 0, 0 },
{"SuppressImplicitWarnings", 1, INT_TYPE, &SuppressImplicitRemWarnings, 0, 1},
{"SuppressLRM", 1, INT_TYPE, &SuppressLRM, 0, 1 },
{"SysInclude", 0, STR_TYPE, &SysDir, 0, 0 },
{"T", 0, SPECIAL_TYPE, trig_date_func, 0, 0 },
@@ -1116,7 +1120,7 @@ static void DumpSysVar(char const *name, const SysVar *v)
return;
}
if (name) strcat(buffer, name); else strcat(buffer, v->name);
fprintf(ErrFp, "%16s ", buffer);
fprintf(ErrFp, "%25s ", buffer);
if (v) {
if (v->type == CONST_INT_TYPE) {
fprintf(ErrFp, "%d\n", v->constval);
@@ -1195,3 +1199,37 @@ set_components_from_lat_and_long(void)
}
}
void
print_sysvar_tokens(void)
{
int i;
printf("\n# System Variables\n\n");
for (i=0; i< (int) NUMSYSVARS; i++) {
printf("$%s\n", SysVarArr[i].name);
}
}
void
get_var_hash_stats(int *total, int *maxlen, double *avglen)
{
int len;
int i;
Var *v;
*maxlen = 0;
*total = 0;
for (i=0; i<VAR_HASH_SIZE; i++) {
len = 0;
v = VHashTbl[i];
while(v) {
len++;
(*total)++;
v = v->next;
}
if (len > *maxlen) {
*maxlen = len;
}
}
*avglen = (double) *total / (double) VAR_HASH_SIZE;
}

View File

@@ -2,5 +2,5 @@ FSET msgprefix(x) "Priority: " + x + "; Filename: " + filename() + ": "
REM at 23:56 MSG foo
REM PRIORITY 42 at 23:57 MSG bar
REM PRIORITY 999 at 23:58 MSQ quux
REM PRIORITY 999 at 23:58 MSG quux
DO queue2.rem

View File

@@ -9,10 +9,10 @@ set $LatMin 24
set $LatSec 0
IF $PSCAL
[trigger(moondate(0))] SPECIAL MOON 0 -1 -1 [moontime(0)]
[trigger(moondate(1))] SPECIAL MOON 1 -1 -1 [moontime(1)]
[trigger(moondate(2))] SPECIAL MOON 2 -1 -1 [moontime(2)]
[trigger(moondate(3))] SPECIAL MOON 3 -1 -1 [moontime(3)]
REM [trigger(moondate(0))] SPECIAL MOON 0 -1 -1 [moontime(0)]
REM [trigger(moondate(1))] SPECIAL MOON 1 -1 -1 [moontime(1)]
REM [trigger(moondate(2))] SPECIAL MOON 2 -1 -1 [moontime(2)]
REM [trigger(moondate(3))] SPECIAL MOON 3 -1 -1 [moontime(3)]
ENDIF
REM 4 PS (First-Bit-Of-PS)

View File

@@ -583,8 +583,23 @@ rm -f ../tests/once.timestamp
tail +2 ../tests/once.timestamp >> ../tests/test.out 2>&1
rm -f ../tests/once.timestamp
# Newlines in calendar output
(echo 'REM 16 MSG foo%_bar%_baz wookie quux apple %_ %_ %_ blech'; echo "REM 16 MSG ANOTHER") | ../src/remind -c -w80 - 1 sep 1990 >> ../tests/test.out 2>&1
# Remove references to SysInclude, which is build-specific
grep -F -v '$SysInclude' < ../tests/test.out > ../tests/test.out.1 && mv -f ../tests/test.out.1 ../tests/test.out
# If "man" accepts the --warnings flag, test all the man pages.
man man | grep -e --warnings > /dev/null 2>&1
if test $? = 0 ; then
for i in ../man/*.1 ; do
man --warnings=w $i 2>>../tests/test.out 1>/dev/null
done
fi
# Test --print-tokens long option
../src/remind --print-tokens < /dev/null >> ../tests/test.out 2>&1
cmp -s ../tests/test.out ../tests/test.cmp
if [ "$?" = "0" ]; then
echo "Remind: Acceptance test PASSED"

File diff suppressed because one or more lines are too long

View File

@@ -33,7 +33,7 @@ fset _h(x, y) trigger(hebdate(x,y))
# Test case from Remind mailing list
set mltest "a b"
INCLUDECMD printf 'REM %s\n' [mltest]
INCLUDECMD printf 'REM MSG %s\n' [mltest]
# Disabling RUN in an !includecmd
INCLUDECMD !echo MSG foo
@@ -49,38 +49,38 @@ 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
[_h(10, "Tishrey")] MSG Yom Kippur
[_h(15, "Tishrey")] MSG Sukkot 1
[_h(25, "Kislev")] MSG Channuka
[_h(10, "Tevet")] MSG Asara B'Tevet
[_h(15, "Shvat")] MSG Tu B'Shvat
[_h(15, "Adar A")] MSG Purim Katan
[_h(14, "Adar")] MSG Purim
[_h(15, "Nisan")] MSG Pesach
[_h(27, "Nisan")] MSG Yom HaShoah
[_h(4, "Iyar")] MSG Yom HaZikaron
[_h(5, "Iyar")] MSG Yom Ha'atzmaut
[_h(28, "Iyar")] MSG Yom Yerushalayim
[_h(6, "Sivan")] MSG Shavuot
[_h(9, "Av")] MSG Tish'a B'Av
REM [_h(1, "Tishrey")] MSG Rosh Hashana 1
REM [_h(2, "Tishrey")] MSG Rosh Hashana 2
REM [_h(3, "Tishrey")] MSG Tzom Gedalia
REM [_h(10, "Tishrey")] MSG Yom Kippur
REM [_h(15, "Tishrey")] MSG Sukkot 1
REM [_h(25, "Kislev")] MSG Channuka
REM [_h(10, "Tevet")] MSG Asara B'Tevet
REM [_h(15, "Shvat")] MSG Tu B'Shvat
REM [_h(15, "Adar A")] MSG Purim Katan
REM [_h(14, "Adar")] MSG Purim
REM [_h(15, "Nisan")] MSG Pesach
REM [_h(27, "Nisan")] MSG Yom HaShoah
REM [_h(4, "Iyar")] MSG Yom HaZikaron
REM [_h(5, "Iyar")] MSG Yom Ha'atzmaut
REM [_h(28, "Iyar")] MSG Yom Yerushalayim
REM [_h(6, "Sivan")] MSG Shavuot
REM [_h(9, "Av")] MSG Tish'a B'Av
# Test some jahrzeit cases
fset _i(x,y,z,a) trigger(hebdate(x,y,z,a))
[_i(30, "Heshvan", today(), 5759)] MSG Complete-Complete
[_i(30, "Heshvan", today(), 5760)] MSG Complete-Defective
[_i(30, "Heshvan", today(), 5761)] MSG Illegal
REM [_i(30, "Heshvan", today(), 5759)] MSG Complete-Complete
REM [_i(30, "Heshvan", today(), 5760)] MSG Complete-Defective
REM [_i(30, "Heshvan", today(), 5761)] MSG Illegal
[_i(30, "Kislev", today(), 5759)] MSG Complete-Complete
[_i(30, "Kislev", today(), 5760)] MSG Complete-Defective
[_i(30, "Kislev", today(), 5761)] MSG Illegal
REM [_i(30, "Kislev", today(), 5759)] MSG Complete-Complete
REM [_i(30, "Kislev", today(), 5760)] MSG Complete-Defective
REM [_i(30, "Kislev", today(), 5761)] MSG Illegal
[_i(30, "Adar A", today(), 5755)] MSG Leap
[_i(30, "Adar A", today(), 5756)] MSG Illegal
[_i(29, "Adar A", today(), 5755)] MSG Leap
[_i(29, "Adar A", today(), 5756)] MSG Illegal
REM [_i(30, "Adar A", today(), 5755)] MSG Leap
REM [_i(30, "Adar A", today(), 5756)] MSG Illegal
REM [_i(29, "Adar A", today(), 5755)] MSG Leap
REM [_i(29, "Adar A", today(), 5756)] MSG Illegal
# This causes a parse error on version 03.01.01
REM 1990-01-01 SATISFY 1
@@ -238,8 +238,8 @@ CLEAR-OMIT-CONTEXT
REM tag ill,egal MSG bad tag
REM MSG The tags are: [trigtags()]
REM TAG foo The tags are: [trigtags()]
REM TAG foo TAG bar TAG quux TAG znort TAG cabbage The tags are: [trigtags()]
REM TAG foo MSG The tags are: [trigtags()]
REM TAG foo TAG bar TAG quux TAG znort TAG cabbage MSG The tags are: [trigtags()]
REM MSG The tags are: [trigtags()]
# Test ADDOMIT
@@ -450,7 +450,7 @@ set a125 trigduration()
# Test adding TIME+TIME and DATETIME+TIME
set a126 11:00 + 3:00
set a127 23:00 + 5:30
set a127 '23:00' + 5:30
set a128 '2018-02-03@10:00' + 6:45
set a129 23:30 + '2019-02-02@16:44'
@@ -559,11 +559,11 @@ REM 1992-01-01 *1 UNTIL 1991-12-31 MSG Diagnosed
set x '1992-01-01'
REM [x] *1 UNTIL 1991-12-31 MSG Not diagnosed - nonconst expression
REM MON FROM 1992-01-01 UNTIL 1991-12-31 Diagnosed
REM MON SCANFROM 1992-01-01 UNTIL 1991-12-31 Diagnosed
REM MON FROM 1992-01-01 UNTIL 1991-12-31 MSG Diagnosed
REM MON SCANFROM 1992-01-01 UNTIL 1991-12-31 MSG Diagnosed
REM MON FROM [x] UNTIL 1991-12-31 Not diagnosed
REM MON SCANFROM [x] UNTIL 1991-12-31 Not diagnosed
REM MON FROM [x] UNTIL 1991-12-31 MSG Not diagnosed
REM MON SCANFROM [x] UNTIL 1991-12-31 MSG Not diagnosed
REM 1992-01-01 UNTIL 1992-02-02 MSG Diagnosed
REM [x] UNTIL 1992-02-02 MSG Diagnosed
@@ -575,7 +575,7 @@ OMIT December 25 MSG X
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
REM [_i(14, "Adar", today(), 5761)] MSG Purim
# Regression test for bug found by Larry Hynes
REM SATISFY [day(trigdate()-25) == 14] MSG Foo
@@ -708,6 +708,56 @@ set x ampm(21:12) + ""
set x ampm(22:12) + ""
set x ampm(23:12) + ""
set x ampm(0:12,"AM", "PM", 1) + ""
set x ampm(1:12,"AM", "PM", 1) + ""
set x ampm(2:12,"AM", "PM", 1) + ""
set x ampm(3:12,"AM", "PM", 1) + ""
set x ampm(4:12,"AM", "PM", 1) + ""
set x ampm(5:12,"AM", "PM", 1) + ""
set x ampm(6:12,"AM", "PM", 1) + ""
set x ampm(7:12,"AM", "PM", 1) + ""
set x ampm(8:12,"AM", "PM", 1) + ""
set x ampm(9:12,"AM", "PM", 1) + ""
set x ampm(10:12,"AM", "PM", 1) + ""
set x ampm(11:12,"AM", "PM", 1) + ""
set x ampm(12:12,"AM", "PM", 1) + ""
set x ampm(13:12,"AM", "PM", 1) + ""
set x ampm(14:12,"AM", "PM", 1) + ""
set x ampm(15:12,"AM", "PM", 1) + ""
set x ampm(16:12,"AM", "PM", 1) + ""
set x ampm(17:12,"AM", "PM", 1) + ""
set x ampm(18:12,"AM", "PM", 1) + ""
set x ampm(19:12,"AM", "PM", 1) + ""
set x ampm(20:12,"AM", "PM", 1) + ""
set x ampm(21:12,"AM", "PM", 1) + ""
set x ampm(22:12,"AM", "PM", 1) + ""
set x ampm(23:12,"AM", "PM", 1) + ""
set x ampm(0:02,"AM", "PM", 0) + ""
set x ampm(0:02,"AM", "PM", 0) + ""
set x ampm(2:02,"AM", "PM", 0) + ""
set x ampm(3:02,"AM", "PM", 0) + ""
set x ampm(4:02,"AM", "PM", 0) + ""
set x ampm(5:02,"AM", "PM", 0) + ""
set x ampm(6:02,"AM", "PM", 0) + ""
set x ampm(7:02,"AM", "PM", 0) + ""
set x ampm(8:02,"AM", "PM", 0) + ""
set x ampm(9:02,"AM", "PM", 0) + ""
set x ampm(00:02,"AM", "PM", 0) + ""
set x ampm(00:02,"AM", "PM", 0) + ""
set x ampm(02:02,"AM", "PM", 0) + ""
set x ampm(03:02,"AM", "PM", 0) + ""
set x ampm(04:02,"AM", "PM", 0) + ""
set x ampm(05:02,"AM", "PM", 0) + ""
set x ampm(06:02,"AM", "PM", 0) + ""
set x ampm(07:02,"AM", "PM", 0) + ""
set x ampm(08:02,"AM", "PM", 0) + ""
set x ampm(09:02,"AM", "PM", 0) + ""
set x ampm(20:02,"AM", "PM", 0) + ""
set x ampm(20:02,"AM", "PM", 0) + ""
set x ampm(22:02,"AM", "PM", 0) + ""
set x ampm(23:02,"AM", "PM", 0) + ""
# Coerce with am/pm
set x coerce("TIME", "12:45am")
set x coerce("TIME", "12:45")
@@ -777,7 +827,7 @@ ENDIF
# Trig with a good warnfunc
FSET w(x) choose(x, 5, 3, 1, 0)
Short-circuit operators
# Short-circuit operators
IF trig("sun warn w") || trig("thu warn w")
REM [trig()] +5 MSG Foo %b
ENDIF
@@ -872,6 +922,17 @@ REM MSG Here: %{custom}
REM MSG There: %*{custom}
REM MSG Bad: %{custom
REM MSG Undefined: %{nopity_nope_nope}
# Bad substitution functions
FSET subst_bad() "foo"
REM MSG %{bad}
FSET subst_ampm(a, b, c, d, e, f, g) "wookie"
REM AT 11:00 MSG %2
FUNSET subst_ampm
# Test FUNSET
FSET square(x) x*x
SET a square(5)
@@ -945,6 +1006,133 @@ REM Tue AT 10:00 DURATION [trigtime()] MSG blort
# Make sure shellescape does not mangle UTF-8 characters
msg [shellescape("😆")]
This should be diagnosed as implicitly being REM
REM This should be diganosed as implicitly being MSG-type
# Check that user-defined functions with too many arguments are
# correctly diagnosed.
# This should be OK
FSET f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, a62, a63) 3
# This should give an error
FSET f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, a62, a63, a64) 3
# Check that SATISFY expressions that don't reference trigdate are diagnosed
# These should all NOT be diagnosed
set x 3
REM SATISFY 1
REM SATISFY trigdate() > '1990-01-01'
REM AT 23:59 SATISFY trigdatetime() > '1990-01-01@12:00'
REM SATISFY $T > '1990-01-01'
REM SATISFY $Ty > 1990
REM SATISFY $Tm > 0
REM SATISFY $Td > 0
REM SATISFY $Tw > -1
REM SATISFY [max(x, max(x, 1, 2, 3), 4, 5, 6) * max(5, $Td)]
FSET references_t(x) $T != x
REM SATISFY references_t($U)
FSET recursive_t(x) iif(x==0, recursive_t(1), references_t($U))
REM SATISFY recursive_t(0)
REM SATISFY recursive_t(2)
# These should be diagnosed
REM SATISFY 0
REM SATISFY ""
REM SATISFY [version() > "01.00.00"]
REM SATISFY [max(x, max(x, 1, 2, 3), 4, 5, 6) * 5]
FSET gg(x) 0
REM WARN gg MSG Wookie
REM AT 11:00 SCHED gg MSG blork
REM OMITFUNC gg MSG hehe
FSET gg(x,y,z) 0
REM WARN gg MSG Wookie
REM AT 11:00 SCHED gg MSG blork
REM OMITFUNC gg MSG hehe
FSET gg() 0
REM WARN gg MSG Wookie
REM AT 11:00 SCHED gg MSG blork
REM OMITFUNC gg MSG hehe
FSET gg(x) x-x
REM WARN gg MSG Wookie
REM AT 11:00 SCHED gg MSG blork
REM OMITFUNC gg MSG hehe
REM WARN not_defined MSG Wookie
REM AT 11:00 SCHED not_defined MSG blork
REM OMITFUNC not_defined MSG hehe
### Strings in logical operators
SET logstr "" && 7
SET logstr "foo" && 7
SET logstr "" && ""
SET logstr "foo" && ""
SET logstr "" && "bar"
SET logstr "foo" && "bar"
SET logstr "" && '2023-02-01'
SET logstr "foo" && '2023-02-01'
SET logstr "" || 7
SET logstr "foo" || 7
SET logstr "" || ""
SET logstr "foo" || ""
SET logstr "" || "bar"
SET logstr "foo" || "bar"
SET logstr "" || '2023-02-01'
SET logstr "foo" || '2023-02-01'
set xyz ! 0
set xyz ! 1
set xyz ! 2
set xyz ! date(baseyr(), 1, 1)
set xyz ! date(baseyr(), 1, 2)
set xyz ! '2024-01-01'
set xyz ! datetime(baseyr(), 1, 1, 00:00)
set xyz ! datetime(baseyr(), 1, 1, 00:01)
set xyz ! datetime(baseyr(), 1, 2, 12:30)
set xyz ! '2024-01-01@11:47'
set xyz ! 00:00
set xyz ! 00:01
set xyz ! 23:59
set xyz ! ""
set xyz ! "foo"
set xyz ! "0"
# Test error messages for function calls with too many / too few args
set zxk version(1)
set zxk max()
fset dooby(x) 1
set zxk dooby()
set zxk dooby(1, 2)
set zxk dooby(1)
REM 1 Jan 1873 MSG This should fail
REM 1873-12-11 MSG Also bad.
# Test $SuppressImplicitWarnings
REM wookie
Barf
set $SuppressImplicitWarnings 1
REM wookie
Barf
# Output expression-node stats
DEBUG +s
# Don't want Remind to queue reminders
EXIT

View File

@@ -1,7 +1,7 @@
MSG ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский
MSG עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית
REM MSG ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский
REM MSG עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית
Wed MSG With tabs and spaces
REM Wed MSG With tabs and spaces
REM [moondate(0)] MSG 🌑
REM [moondate(1)] MSG 🌓 woo

View File

@@ -1,5 +1,5 @@
[moondate(0)] SPECIAL MOON 0
[moondate(1)] SPECIAL MOON 1
[moondate(2)] SPECIAL MOON 2
[moondate(3)] SPECIAL MOON 3
REM [moondate(0)] SPECIAL MOON 0
REM [moondate(1)] SPECIAL MOON 1
REM [moondate(2)] SPECIAL MOON 2
REM [moondate(3)] SPECIAL MOON 3
REM Monday SPECIAL WEEK (W[weekno()])

View File

@@ -9,8 +9,8 @@ IF !$PSCAL
FSET msgsuffix(x) "<P>"
MSG The Hebrew date for today, %d %m, %y, is [_hstr(today())]. %
MSG And the Hebrew date for tomorrow is [_hstr(today()+1)]. %
REM MSG The Hebrew date for today, %d %m, %y, is [_hstr(today())]. %
REM MSG And the Hebrew date for tomorrow is [_hstr(today()+1)]. %
fset msgprefix(x) iif($NumTrig==OldTrig, "<H2>Upcoming Holidays</H2>"+char(13,10),"")
set oldtrig $numtrig
@@ -51,40 +51,40 @@ FSET _PastSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, \
SET InIsrael VALUE("InIsrael", 0)
SET Reform VALUE("Reform", 0)
[_h(1, "Tishrey")] ++12 MSG %"Rosh Hashana 1%" is %b.
REM [_h(1, "Tishrey")] ++12 MSG %"Rosh Hashana 1%" is %b.
# No RH-2 or Tzom Gedalia in Reform
IF !Reform
[_h(2, "Tishrey")] ++12 MSG %"Rosh Hashana 2%" is %b.
[_PastSat(3, "Tishrey")] ++12 MSG %"Tzom Gedalia%" is %b.
REM [_h(2, "Tishrey")] ++12 MSG %"Rosh Hashana 2%" is %b.
REM [_PastSat(3, "Tishrey")] ++12 MSG %"Tzom Gedalia%" is %b.
ENDIF
[_h(10, "Tishrey")] ++12 MSG %"Yom Kippur%" is %b.
[_h(15, "Tishrey")] ++12 MSG %"Sukkot 1%" is %b.
REM [_h(10, "Tishrey")] ++12 MSG %"Yom Kippur%" is %b.
REM [_h(15, "Tishrey")] ++12 MSG %"Sukkot 1%" is %b.
IF !InIsrael
[_h(16, "Tishrey")] MSG %"Sukkot 2%"
REM [_h(16, "Tishrey")] MSG %"Sukkot 2%"
ENDIF
[_h(21, "Tishrey")] ++12 MSG %"Hoshana Rabba%" is %b.
[_h(22, "Tishrey")] ++12 MSG %"Shemini Atzeret%" is %b.
REM [_h(21, "Tishrey")] ++12 MSG %"Hoshana Rabba%" is %b.
REM [_h(22, "Tishrey")] ++12 MSG %"Shemini Atzeret%" is %b.
IF InIsrael
[_h(22, "Tishrey")] ++12 MSG %"Simchat Torah%" is %b.
REM [_h(22, "Tishrey")] ++12 MSG %"Simchat Torah%" is %b.
ELSE
[_h(23, "Tishrey")] ++12 MSG %"Simchat Torah%" is %b.
REM [_h(23, "Tishrey")] ++12 MSG %"Simchat Torah%" is %b.
ENDIF
# Because Kislev can change length, we must be more careful about Chanukah
FSET _chan(x) TRIGGER(HEBDATE(24, "Kislev", today()-9)+x)
[_chan(1)] ++12 MSG %"Chanukah 1%" is %b.
[_chan(2)] MSG %"Chanukah 2%"
[_chan(3)] MSG %"Chanukah 3%"
[_chan(4)] MSG %"Chanukah 4%"
[_chan(5)] MSG %"Chanukah 5%"
[_chan(6)] MSG %"Chanukah 6%"
[_chan(7)] MSG %"Chanukah 7%"
[_chan(8)] MSG %"Chanukah 8%"
REM [_chan(1)] ++12 MSG %"Chanukah 1%" is %b.
REM [_chan(2)] MSG %"Chanukah 2%"
REM [_chan(3)] MSG %"Chanukah 3%"
REM [_chan(4)] MSG %"Chanukah 4%"
REM [_chan(5)] MSG %"Chanukah 5%"
REM [_chan(6)] MSG %"Chanukah 6%"
REM [_chan(7)] MSG %"Chanukah 7%"
REM [_chan(8)] MSG %"Chanukah 8%"
# Not sure about Reform's position on the next one.
IF !Reform
@@ -92,8 +92,8 @@ IF !Reform
REM [_PastSat(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
ENDIF
[_h(15, "Shvat")] ++12 MSG %"Tu B'Shvat%" is %b.
[_h(15, "Adar A")] ++12 MSG %"Purim Katan%" is %b.
REM [_h(15, "Shvat")] ++12 MSG %"Tu B'Shvat%" is %b.
REM [_h(15, "Adar A")] ++12 MSG %"Purim Katan%" is %b.
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
IF WKDAYNUM(_h2(13, "Adar")) != 6
@@ -101,41 +101,41 @@ IF WKDAYNUM(_h2(13, "Adar")) != 6
ELSE
REM [TRIGGER(_h2(11, "Adar"))] ++12 MSG %"Fast of Esther%" is %b.
ENDIF
[_h(14, "Adar")] ++12 MSG %"Purim%" is %b.
[_h(15, "Nisan")] ++12 MSG %"Pesach%" is %b.
REM [_h(14, "Adar")] ++12 MSG %"Purim%" is %b.
REM [_h(15, "Nisan")] ++12 MSG %"Pesach%" is %b.
IF !InIsrael
[_h(16, "Nisan")] MSG %"Pesach 2%" is %b.
REM [_h(16, "Nisan")] MSG %"Pesach 2%" is %b.
ENDIF
[_h(21, "Nisan")] MSG %"Pesach 7%" is %b.
REM [_h(21, "Nisan")] MSG %"Pesach 7%" is %b.
IF !InIsrael && !Reform
[_h(22, "Nisan")] MSG %"Pesach 8%" is %b.
REM [_h(22, "Nisan")] MSG %"Pesach 8%" is %b.
ENDIF
[_h(27, "Nisan")] ++12 MSG %"Yom HaShoah%" is %b.
[_h(4, "Iyar")] ++12 MSG %"Yom HaZikaron%" is %b.
[_h(5, "Iyar")] ++12 MSG %"Yom Ha'atzmaut%" is %b.
REM [_h(27, "Nisan")] ++12 MSG %"Yom HaShoah%" is %b.
REM [_h(4, "Iyar")] ++12 MSG %"Yom HaZikaron%" is %b.
REM [_h(5, "Iyar")] ++12 MSG %"Yom Ha'atzmaut%" is %b.
# Not sure about Reform's position on Lag B'Omer
IF !Reform
[_h(18, "Iyar")] ++12 MSG %"Lag B'Omer%" is %b.
REM [_h(18, "Iyar")] ++12 MSG %"Lag B'Omer%" is %b.
ENDIF
[_h(28, "Iyar")] ++12 MSG %"Yom Yerushalayim%" is %b.
[_h(6, "Sivan")] ++12 MSG %"Shavuot%" is %b.
REM [_h(28, "Iyar")] ++12 MSG %"Yom Yerushalayim%" is %b.
REM [_h(6, "Sivan")] ++12 MSG %"Shavuot%" is %b.
IF !InIsrael && !Reform
[_h(7, "Sivan")] MSG %"Shavuot 2%" is %b.
REM [_h(7, "Sivan")] MSG %"Shavuot 2%" is %b.
ENDIF
# Fairly sure Reform Jews don't observe the next two
IF !Reform
# Tzom Tamuz and Tish'a B'Av are moved to Sunday if they normally
# fall on a Saturday
[_PastSat(17, "Tamuz")] ++12 MSG %"Tzom Tammuz%" is %b.
[_PastSat(9, "Av")] ++12 MSG %"Tish'a B'Av%" is %b.
REM [_PastSat(17, "Tamuz")] ++12 MSG %"Tzom Tammuz%" is %b.
REM [_PastSat(9, "Av")] ++12 MSG %"Tish'a B'Av%" is %b.
ENDIF
fset msgprefix(x) ""