Compare commits

...

457 Commits

Author SHA1 Message Date
Dianne Skoll
b22438b489 Bump version to 03.03.12. 2022-01-22 09:21:02 -05:00
Dianne Skoll
683b38a7ab 3.3.12 will go out in 2022, not 2021. 2022-01-22 09:19:14 -05:00
Dianne Skoll
d6b4fdd6d3 Always clean up. 2022-01-20 20:10:39 -05:00
Dianne Skoll
c996649954 Update docs. 2022-01-20 19:52:29 -05:00
Dianne Skoll
d59ad77893 Document DO better. 2022-01-20 19:48:49 -05:00
Dianne Skoll
e637c20dee Don't try to do filedir() shenanigans for "DO /absolute/path" 2022-01-20 19:47:04 -05:00
Dianne Skoll
19dc588319 Update regression test file 2022-01-20 19:39:26 -05:00
Dianne Skoll
dc53ef2e71 Document DO 2022-01-20 19:39:12 -05:00
Dianne Skoll
e51d7f3c6d Add "DO file" command which is equivalent to "INCLUDE [filedir()]/file" 2022-01-20 19:30:10 -05:00
Dianne Skoll
5a7e86e443 Update WHATSNEW 2022-01-20 12:41:58 -05:00
Dianne Skoll
7f4edae006 Update test output comparison file. 2022-01-20 09:53:08 -05:00
Dianne Skoll
2f4e1462e3 Document -tt[N] and $DefaultTDelta 2022-01-20 09:52:57 -05:00
Dianne Skoll
54f5d81a8c Properly check for repeated tdelta 2022-01-20 09:52:46 -05:00
Dianne Skoll
d33c27289a Implement $DefaultTDelta system variable and -tt[N] command-line option. 2022-01-20 09:44:17 -05:00
Dianne Skoll
1675fdb499 Keep config file in $XDG_CONFIG_HOME/tkremindrc in preference to ~/.tkremindrc 2021-12-31 16:16:16 -05:00
Dianne Skoll
9321109691 Remove code that annoyed people on Windows or Mac OS X.
I think I've made my point, and the MICROSOFT-AND-APPLE file still exists.
2021-12-31 15:33:43 -05:00
Dianne Skoll
e6a4f939a3 Add brackets. 2021-12-29 20:51:01 -05:00
Dianne Skoll
c7ae214853 Remove comment. 2021-12-29 20:44:46 -05:00
Dianne Skoll
68a9cc047e Add tests for deprecation messages. 2021-12-29 10:42:30 -05:00
Dianne Skoll
1f2b25f852 Write options to a temporary file and then rename 2021-12-28 21:14:33 -05:00
Dianne Skoll
20040c8857 Update WHATSNEW 2021-12-28 21:05:13 -05:00
Dianne Skoll
ac64b0c11f Fix option descriptor. 2021-12-28 21:03:30 -05:00
Dianne Skoll
ba47ce7ca8 Make TkRemind remember printer settings. 2021-12-28 21:02:33 -05:00
Dianne Skoll
be1ab4ea36 Properly support '-i$Latitude="x.yyy"' 2021-12-28 17:56:31 -05:00
Dianne Skoll
13cd9f3d04 Fix memory leak. 2021-12-28 17:53:41 -05:00
Dianne Skoll
8e1f82de5f Get rid of _back function definition (not needed) 2021-12-28 16:59:19 -05:00
Dianne Skoll
8631ad3122 Sort function names alphabetically. 2021-12-28 15:31:03 -05:00
Dianne Skoll
90e6aef9d7 Set default location in custom.h 2021-12-28 15:26:59 -05:00
Dianne Skoll
698190fb72 Set default location right on Parliament Hill. 2021-12-28 15:25:32 -05:00
Dianne Skoll
27cfaa9404 Refactor common code in setting latitude/longitude vars 2021-12-28 14:02:07 -05:00
Dianne Skoll
9f296fe76d Update docs 2021-12-28 10:47:21 -05:00
Dianne Skoll
d0112adb08 Sleep with higher precision in -z0 mode. 2021-12-28 10:32:06 -05:00
Dianne Skoll
75f4fe3595 Update docs. 2021-12-27 15:47:42 -05:00
Dianne Skoll
211bfbc1e2 Bump version to 03.03.11 2021-12-27 15:42:19 -05:00
Dianne Skoll
afaa1841fc Add deprecation notice in verbose mode. 2021-12-27 15:37:32 -05:00
Dianne Skoll
027662c9c3 Add "DUMP $" to test. 2021-12-27 15:28:30 -05:00
Dianne Skoll
43e652321b Document $Latitude and $Longitude system variables. 2021-12-27 15:20:42 -05:00
Dianne Skoll
83a2216d19 Add $Latitude and $Longitude system variables. 2021-12-27 15:08:12 -05:00
Dianne Skoll
82ae568add Make underline the same color as text in TkRemind. 2021-12-27 11:53:02 -05:00
Dianne Skoll
2573003034 Modernize examples 2021-12-27 11:28:51 -05:00
Dianne Skoll
c33e873577 Add balloon help to moon windows 2021-12-26 13:08:49 -05:00
Dianne Skoll
a1d03b8159 Make moon icons respond to mouse clicks to edit reminders. 2021-12-26 13:04:35 -05:00
Dianne Skoll
762530f6ab Document underlining of editable reminders 2021-12-26 12:20:53 -05:00
Dianne Skoll
f53a3ecc69 Underline editable reminders when we enter them. 2021-12-26 12:19:05 -05:00
Dianne Skoll
1ed60fecee Make moon messages right-clickable. 2021-12-26 11:59:59 -05:00
Dianne Skoll
c1a12ea4e9 Don't outline the arcs used to make first/last quarter. 2021-12-25 18:27:56 -05:00
Dianne Skoll
0efd235e36 Use Tk oval and arc items to draw moons rather than PNG images.
This makes the moon images work even if the text and window colors
have been changed.
2021-12-25 17:27:50 -05:00
Dianne Skoll
c7be8c59f3 Redirect inotifywait's stdin and stderr from/to /dev/null 2021-12-22 10:15:34 -05:00
Dianne Skoll
20bb3eb674 Pass '-r' flag to inotifywait 2021-12-22 10:11:21 -05:00
Dianne Skoll
cde0e5883e Rename "any" to "isany" 2021-12-20 17:32:14 -05:00
Dianne Skoll
0b43099621 Coalesce all of the CSS for table.rem-cal into one block
Reported by Ian! D. Allen
2021-12-15 12:05:53 -05:00
Dianne Skoll
386f36c3ae Add class names indicating number of rows. 2021-12-14 10:53:01 -05:00
Dianne Skoll
b391b2129e More explanation of any 2021-12-07 11:57:14 -05:00
Dianne Skoll
5478673bda Add an example that uses "any" 2021-12-07 09:58:51 -05:00
Dianne Skoll
6295048b3e Add the "any" built-in function. 2021-12-07 09:28:49 -05:00
Dianne Skoll
4fa956aa27 Show queue in sorted order 2021-12-02 11:17:48 -05:00
Dianne Skoll
21cce0e104 Update WHATSNEW 2021-11-30 09:37:04 -05:00
Dianne Skoll
b14e72ddf7 Cosmetic tweaks 2021-11-28 20:32:30 -05:00
Dianne Skoll
7a34b6e18d Better arrowheads 2021-11-28 20:31:42 -05:00
Dianne Skoll
ddc0e8eb45 Use Unicode arrows instead of PNGs; make buttons follow global color scheme. 2021-11-28 20:23:50 -05:00
Dianne Skoll
7648ee6e54 Make queued and status windows obey window color 2021-11-22 14:39:29 -05:00
Dianne Skoll
2b86c912e3 Minor wording tweak 2021-11-21 17:51:33 -05:00
Dianne Skoll
342acedbec Correct documentation of variable name length. 2021-11-21 10:35:24 -05:00
Dianne Skoll
a83bf495b1 Don't convert 90-99 to 1900-1999 2021-11-21 10:17:06 -05:00
Dianne Skoll
899829f1ac Handle ADDOMIT in calendar mode before checking if we should not trigger timed reminders. 2021-11-21 10:10:08 -05:00
Dianne Skoll
408a62115e Add regression test for ADDOMIT in calendar mode. 2021-11-20 20:09:04 -05:00
Dianne Skoll
430d0990aa Obey ADDOMIT in calendar mode as well as command-line mode. 2021-11-20 20:05:00 -05:00
Dianne Skoll
47d33e7aaf Fix docs 2021-11-19 12:12:52 -05:00
Dianne Skoll
12f40cba6d Give a concrete example. 2021-11-19 12:08:15 -05:00
Dianne Skoll
ecc0e9609a Update WHATSNEW 2021-11-19 12:01:52 -05:00
Dianne Skoll
eb35a843c1 Add more explanation of ADDOMIT 2021-11-18 15:23:44 -05:00
Dianne Skoll
79289fe6c4 Add ADDMOMIT keyword; bump version to 03.03.10 2021-11-18 15:13:12 -05:00
Dianne Skoll
cb841adf86 Fix typo 2021-11-17 10:23:10 -05:00
Dianne Skoll
724d82e6d2 Fix typo 2021-10-24 10:07:09 -04:00
Dianne Skoll
0532910604 Update to latest remind-conf-mode 2021-10-24 10:00:07 -04:00
Dianne Skoll
f4f5552975 Make decision to drop privileges based on euid instead of uid 2021-10-15 20:36:58 -04:00
Dianne Skoll
3e2794548b Call initgroups when switching users. 2021-10-15 10:51:01 -04:00
Dianne Skoll
f7b8ee168f Fix typo 2021-10-14 21:30:42 -04:00
Dianne Skoll
e3297fe751 Prep for 3.3.9 release. 2021-10-14 21:20:05 -04:00
Dianne Skoll
58ca741a1c Update docs. 2021-10-14 10:38:11 -04:00
Dianne Skoll
14dbbc7bb4 Fix help text. 2021-10-14 10:24:58 -04:00
Dianne Skoll
df55c4032b Use external .png images for moon phases. 2021-10-14 10:23:58 -04:00
Dianne Skoll
3768155a20 Add "--pngs" option 2021-10-14 10:21:51 -04:00
Dianne Skoll
2f3b9cadf4 Add a generated file to unconfigure 2021-10-12 22:06:03 -04:00
Dianne Skoll
2c79a6531a Fix typo. 2021-10-12 22:05:12 -04:00
Dianne Skoll
be5c856f4b Remove "cm2rem". It's waaaay obsolete. 2021-10-12 22:04:00 -04:00
Dianne Skoll
712a333f08 Substitute full path to `rem2html' 2021-10-12 21:58:10 -04:00
Dianne Skoll
b753e84c8c Update README 2021-10-12 21:55:18 -04:00
Dianne Skoll
4b4acaadbb Don't install rem2html if we don't have Perl. 2021-10-12 21:54:38 -04:00
Dianne Skoll
8a52f9b67d Silence Perl warning. 2021-10-12 21:51:04 -04:00
Dianne Skoll
e372606281 Pass --stylesheet option 2021-10-12 21:46:03 -04:00
Dianne Skoll
c443d0a9da Make imgbase and stylesheet options behave rationally. 2021-10-12 21:44:25 -04:00
Dianne Skoll
42c9ae9ea8 Add generated file to .gitignore. 2021-10-12 21:33:06 -04:00
Dianne Skoll
dac9bb4187 Pass proper --imgbase argument 2021-10-12 21:32:46 -04:00
Dianne Skoll
812d926f66 Move rem2html into its own directory and install it by default. 2021-10-12 21:28:14 -04:00
Dianne Skoll
45831ea69f Fix error in man page courtesy of Richard Ulmer. 2021-10-11 19:54:38 -04:00
Dianne Skoll
354e1d236b Update test-for-backends.rem with comments. 2021-10-08 15:27:32 -04:00
Dianne Skoll
ac478039cf Remove unnecessary spaces from JSON output. 2021-10-06 17:47:31 -04:00
Dianne Skoll
96f5799e6f Fix typo 2021-10-06 17:41:15 -04:00
Dianne Skoll
e21479f696 Add test reminder file for seeing how back-ends handle SPECIALs 2021-10-06 09:39:52 -04:00
Dianne Skoll
25dc883e15 Fix bug in calendar display: Would sometimes highlight wrong day as "today" 2021-10-06 09:39:08 -04:00
Dianne Skoll
bfb1374ee3 Document that "-pp" is the preferred Remind output format. 2021-10-05 23:31:34 -04:00
Dianne Skoll
cacd8f9792 Tweak stylesheet 2021-10-05 23:13:22 -04:00
Dianne Skoll
3e9053a3c6 No need to install the .png images. 2021-10-05 23:10:34 -04:00
Dianne Skoll
5fa357fec2 Use data: URLs for the moon images. 2021-10-05 23:08:41 -04:00
Dianne Skoll
f109c3d696 Remove C99-ism. 2021-10-05 13:54:04 -04:00
Dianne Skoll
b097ce7279 Fix docs. 2021-10-05 12:18:50 -04:00
Dianne Skoll
1297854935 Allow "-u+whatever" to change users without disabling RUN. 2021-10-05 12:17:42 -04:00
Dianne Skoll
0a1d0011f6 Add "-+username" option to trust "username" for the purpose of allowing RUN. 2021-10-05 12:04:44 -04:00
Dianne Skoll
20db1be0a0 Add missing #ifdef...#endif courtesy of Nomen Nescio 2021-10-04 08:39:27 -04:00
Dianne Skoll
143f1d6144 Prep for 3.3.8 release. 2021-09-13 19:14:03 -04:00
Dianne Skoll
358f6c9497 Fix error in TkRemind reverse-engineering of Reminder. 2021-09-13 18:11:32 -04:00
Dianne Skoll
ca26544be8 Don't use YYYY-MM-DD form of full date.
We get better error messages from Remind this way.
2021-09-13 17:54:36 -04:00
Dianne Skoll
5ceffddd5b Add "shellescape" built-in function. 2021-09-08 09:33:47 -04:00
Dianne Skoll
8e3ddb96b3 Add another couple of tests. 2021-09-07 12:16:36 -04:00
Dianne Skoll
377de36b35 More doc about INCLUDECMD. 2021-09-07 10:06:20 -04:00
Dianne Skoll
4395e2f7ed Use "pclose" rather than "fclose" to close descriptors opened with "popen" 2021-09-05 11:45:55 -04:00
Dianne Skoll
1d0cc31b10 Clarify how we determine uniqueness of INCLUDECMD commands. 2021-09-05 11:38:13 -04:00
Dianne Skoll
4b4b2ddcd4 Add test case for line-continuation in INCLUDECMD lines. 2021-09-05 11:30:35 -04:00
Dianne Skoll
3c9b5b786e Convert \n from continuation lines in INCLUDECMD to ' ' to make it a little friendlier. 2021-09-05 11:28:54 -04:00
Dianne Skoll
08f1bea6ce Make TkRemind refuse to attempt to edit reminders issued by an INCLUDECMD 2021-09-05 11:13:11 -04:00
Dianne Skoll
a2cc5943e0 Fix test case 2021-09-05 10:54:56 -04:00
Dianne Skoll
895ac6f0f7 Fix bugs in INCLUDECMD. Improve INCLUDECMD documentation. Add ! feature
If you use:

    INCLUDECMD !some_command

then RUN is disabled for the outptu of some_command.
2021-09-05 10:49:04 -04:00
Dianne Skoll
759ca0253e Strip leading spaces from arg to INCLUDECMD. 2021-09-05 10:05:18 -04:00
Dianne Skoll
0ca368c8d9 Parse arg to INCLUDECMD as a character string, not a sequence of tokens. 2021-09-05 10:02:59 -04:00
Dianne Skoll
a467cc1b84 Document that results of INCLUDECMD commands are cached. 2021-09-04 23:27:17 -04:00
Dianne Skoll
c65fd826a5 Use cached results of commands. 2021-09-04 23:25:37 -04:00
Dianne Skoll
bd6f4e1b43 Add test for includecmd 2021-09-04 23:11:46 -04:00
Dianne Skoll
169520914f Document INCLUDECMD 2021-09-04 23:06:59 -04:00
Dianne Skoll
a163a0c446 Add INCLUDECMD command
Executes a shell command and reads the resulting output as a Remind script.
2021-09-04 23:00:03 -04:00
Dianne Skoll
295aeb0ed8 Prevent floating-point exception if we evaluate $IntMin * (-1) 2021-08-30 12:31:43 -04:00
Dianne Skoll
9b2fdad56c Remove obsolete script. 2021-07-12 13:14:44 -04:00
Dianne Skoll
7a1184d3c5 Don't set LC_ALL to en_US.utf-8 if it's already set to a UTF-8 locale 2021-06-27 13:03:59 -04:00
Dianne Skoll
b036244316 Document that -n causes -g to be ignored. 2021-06-01 14:29:48 -04:00
Dianne Skoll
5ad5366e8a Doc fix: *num should be *rep 2021-05-25 10:24:21 -04:00
Dianne Skoll
244677e524 Prep for 3.3.7 release. 2021-05-10 16:53:16 -04:00
Dianne Skoll
f5a094a973 Fix bug in handling of WKDAY DAY YEAR date specification. 2021-04-15 12:29:30 -04:00
Dianne Skoll
5681ebdb12 Simplify "REM MSG ..." case. 2021-04-13 20:54:54 -04:00
Dianne Skoll
664fa5f08f Fix bug: Remind would sometimes compute incorrect trigger date for:
REM 29 Feb SOME_WEEKDAY MSG ...
2021-04-13 12:21:37 -04:00
Dianne Skoll
14edec5eae Pass in wd to macro explicitly. 2021-04-13 12:11:13 -04:00
Dianne Skoll
6adfd2e739 Wrap code to advance to next specified weekday in a macro. 2021-04-13 12:08:20 -04:00
Dianne Skoll
34409f7a7d Update copyright year. 2021-04-02 10:43:54 -04:00
Dianne Skoll
7e13d1052c Don't run test suite as "root". 2021-04-01 19:41:19 -04:00
Dianne Skoll
eb1998c888 Update version 2021-03-30 16:34:24 -04:00
Dianne Skoll
543252cbaf Update docs. 2021-03-30 16:28:54 -04:00
Dianne Skoll
6df7c59876 Don't change locale to en_US.utf-8 if it is already a UTF-8 locale. 2021-03-25 09:43:42 -04:00
Dianne Skoll
f780e0afc3 Fix typo. 2021-02-28 10:03:05 -05:00
Dianne Skoll
310e8d3287 Clarify comment. 2021-02-15 16:37:20 -05:00
Dianne Skoll
ba51bdf258 Add tests for arithmetic overflow. 2021-02-15 16:35:23 -05:00
Dianne Skoll
ef88b844fb Catch integer overflow with "/". 2021-02-15 10:50:56 -05:00
Dianne Skoll
67b96b0a26 Send error messages to stderr 2021-02-09 12:13:21 -05:00
Dianne Skoll
562da30fb5 Update TkRemind requirements. 2021-02-09 12:08:43 -05:00
Dianne Skoll
21175e8cf6 Add $IntMax and $IntMin special variables. 2021-02-02 17:10:17 -05:00
Dianne Skoll
80d01f7158 Check for overflow in abs() 2021-02-02 17:04:14 -05:00
Dianne Skoll
90cac447e4 Document how Remind handles overflow. 2021-02-01 19:54:31 -05:00
Dianne Skoll
04bf5b0a8b Add explanatory comments about overflow-checking functions 2021-01-30 21:04:44 -05:00
Dianne Skoll
d667c15b25 Add overflow checks for unary minus. 2021-01-30 21:02:56 -05:00
Dianne Skoll
2123bf4b18 Check all Subtract implementations for overflow. 2021-01-30 15:15:02 -05:00
Dianne Skoll
429a64f29e Make all + implementations consistent 2021-01-30 15:12:46 -05:00
Dianne Skoll
f39381dd6c Check for overflow on addition of all integer types. 2021-01-30 15:07:55 -05:00
Dianne Skoll
0a9eb07f6f Check for overflow on addition, subtraction, multiplication of integers 2021-01-30 12:56:37 -05:00
Dianne Skoll
9c287e3fd7 Check for overflow when parsing integer constant. 2021-01-29 18:09:35 -05:00
Dianne Skoll
cce4b2cb14 Update docs. 2021-01-21 15:48:26 -05:00
Dianne Skoll
e49d9f8ab6 Bump version to 03.03.05 2021-01-21 15:44:18 -05:00
Dianne Skoll
48cbeb28f4 Make options file configurable. 2021-01-16 09:49:44 -05:00
Dianne Skoll
57d5c54559 Tidy up color options. 2021-01-15 21:16:44 -05:00
Dianne Skoll
3b2260f67e Tweak appearance 2021-01-15 19:19:13 -05:00
Dianne Skoll
d423a62327 Add ability to change fg/bg colors. 2021-01-15 18:55:38 -05:00
Dianne Skoll
ac8da00030 Update man page for new font-change options; document keyboard shortcuts for navigating. 2021-01-15 09:52:40 -05:00
Dianne Skoll
77eb7fb99d Update copyright date. 2021-01-15 09:46:55 -05:00
Dianne Skoll
a751149dd3 Fix typo. 2021-01-15 08:15:58 -05:00
Dianne Skoll
69d45618c6 Ensure we have Tcl/Tk 8.5 or newer. 2021-01-13 19:56:23 -05:00
Dianne Skoll
22fa1a28e5 Get rid of "Apply Options". "Save Options" is all that's needed. 2021-01-13 19:49:33 -05:00
Dianne Skoll
f4cc233009 Make the month heading also use HeadingFont. 2021-01-13 13:57:55 -05:00
Dianne Skoll
1d6e4edd0f Add dialog box for changing calendar fonts. 2021-01-13 13:08:31 -05:00
Dianne Skoll
daffa8cba0 Add missing release note. 2021-01-12 10:47:30 -05:00
Dianne Skoll
2e161a1bc1 Rebuild configure from configure.in 2021-01-12 10:13:13 -05:00
Dianne Skoll
204bb00060 Update docs; prep 3.3.4 release. 2021-01-12 10:13:00 -05:00
Dianne Skoll
d6029a54aa Remove unnecessary line of code; add space after "sub" operator. 2021-01-10 17:38:25 -05:00
Dianne Skoll
f99b5c5a66 Update man page date. 2021-01-05 21:30:21 -05:00
Dianne Skoll
2df4119c1a Fix test. 2021-01-05 19:14:16 -05:00
Dianne Skoll
d06b4e5dcd Update copyright date 2021-01-05 19:13:11 -05:00
Dianne Skoll
bf8a25137d Right-align moon indicators when day numbers are left-aligned. 2021-01-05 19:08:10 -05:00
Dianne Skoll
0f302ad0fc Add clarifying comment. 2021-01-05 17:38:33 -05:00
Dianne Skoll
e3d6b283c5 Fix setpagedevice for landscape mode. 2021-01-05 17:23:47 -05:00
Dianne Skoll
2e3ed09039 Update test for setpagedevice patch. 2021-01-05 17:20:27 -05:00
Dianne Skoll
37971a3f07 Set page size (patch from Jonathan Kamens) 2021-01-05 17:19:20 -05:00
Dianne Skoll
2a1960f257 Add TkRemind option for drawing day numbers on left. 2021-01-05 16:39:57 -05:00
Dianne Skoll
350564c304 Add "-x" option to rem2ps to put day numbers at the top-left of each box.
By default, day numbers are placed at the top-right.
2021-01-05 16:32:20 -05:00
Dianne Skoll
9e2a9fea37 Use "-q" option with inotifywait 2020-12-30 11:01:25 -05:00
Dianne Skoll
3592b43629 If inotifywait is available, use it to react instantly to changes to reminder file/dir. 2020-12-30 10:59:00 -05:00
Dianne Skoll
becf1fc459 Wait 100ms to update after changes. 2020-12-29 12:48:24 -05:00
Dianne Skoll
2bccd058ed Refactor code in TkRemind to prepare for possibly using inotify to react to changes. 2020-12-29 12:46:23 -05:00
Dianne Skoll
12c6621051 Fix typo 2020-11-09 17:32:16 -05:00
Dianne Skoll
504bc6a875 Update docs 2020-11-09 08:25:28 -05:00
Dianne Skoll
9cfdd0b53f Bump version to 3.3.3. 2020-11-09 07:26:14 -05:00
Dianne Skoll
d59024f399 Fix startup crash if ShowTodaysReminders option is set. 2020-11-09 07:23:19 -05:00
Dianne Skoll
24e0178d1a Fix tests for 3.3.2 release. 2020-11-08 16:01:57 -05:00
Dianne Skoll
1ede5775f2 Prep for 3.3.2 release. 2020-11-08 16:01:39 -05:00
Dianne Skoll
a5c9b07052 Fix for calendar alignment for reminders with embedded tabs.
Convert all whitespace chars to space in calendar mode.
2020-11-03 08:41:24 -05:00
Dianne Skoll
22353d4833 Fix typo (patch from Yigit Sever) 2020-11-02 08:31:28 -05:00
Dianne Skoll
7499ada891 Properly fix combining-char-word-wrapping. 2020-11-01 12:05:21 -05:00
Dianne Skoll
3f0a4e5c39 Fix another instance of mis-counting display width. 2020-11-01 10:13:51 -05:00
Dianne Skoll
b8d6472974 Add UTF-8 test. 2020-11-01 10:06:48 -05:00
Dianne Skoll
6358297724 Fix column misalignment with UTF-8 text. 2020-11-01 10:03:32 -05:00
Dianne Skoll
4f6dcde980 Upper-case section references.
Prevent potential null pointer dereference.
2020-10-31 16:57:13 -04:00
Dianne Skoll
8a7985c48e Highlight that longitude sign is opposite from the usual convention. 2020-10-12 18:54:26 -04:00
Dianne Skoll
4ddbe54e55 Fix typo 2020-09-25 22:27:48 -04:00
Dianne Skoll
ef0bf73a29 Document MAYBE-UNCOMPUTABLE. 2020-09-25 22:20:16 -04:00
Dianne Skoll
beda9014d8 Add test for MAYBE-UNCOMPUTABLE 2020-09-25 22:11:56 -04:00
Dianne Skoll
498a429b2c Add MAYBE-UNCOMPUTABLE modifier to trigger. 2020-09-25 22:08:49 -04:00
Dianne Skoll
6aa2aa0fb3 Align system vars in output. 2020-09-20 17:43:51 -04:00
Dianne Skoll
1bef88fccd Update released notes. 2020-09-20 17:40:58 -04:00
Dianne Skoll
8308068067 Don't bother aligning "DUMP" output.
It looks ridiculous with 64-char long variable names.
2020-09-20 17:39:33 -04:00
Dianne Skoll
8385c7f1b0 Update custom.h 2020-09-20 17:35:24 -04:00
Dianne Skoll
0537d02fef Increase max variable length from 16 to 64 characters.
Modern computers have plenty of memory, so meh.
2020-09-20 17:32:22 -04:00
Dianne Skoll
c33a1a3b0b Mention that variables are global. 2020-09-20 12:45:29 -04:00
Dianne Skoll
fd39999128 Fix bugs where month numbers with leading zeros are misinterpreted as octal instead of decimal.
Reported by Peter Geddes.
2020-09-13 12:34:27 -04:00
Dianne Skoll
0aa40094fa Make TwentyFourHourMode global. 2020-08-18 15:24:19 -04:00
Dianne Skoll
e3bbbe07be Respect 24-hour mode option. 2020-08-18 15:24:13 -04:00
Dianne Skoll
5633798d33 Document that time is fed to reminder command. 2020-08-18 15:24:09 -04:00
Dianne Skoll
0e7e1b1b75 When feeding reminder on stdin, prefix with "$time: " 2020-08-18 15:24:04 -04:00
Dianne Skoll
4d3790bc1a More tweaking of defs.rem to remove cruft and modernize usage. 2020-08-18 15:24:00 -04:00
Dianne Skoll
2002c7f1f8 Fix up defs.rem. 2020-08-18 15:23:51 -04:00
Dianne Skoll
1be14e99a2 Update docs for -itkremind=1 and -itkprint=1 options in TkRemind. 2020-06-11 15:06:09 -04:00
Dianne Skoll
78efdaf85f Fix bug that broke printing by putting cmdline options in wrong spot. 2020-06-10 10:26:06 -04:00
Dianne Skoll
0e98a1c656 Always set tkremind=1; set tkprint=1 if we're printing. 2020-06-10 10:22:46 -04:00
Dianne Skoll
7aa483e201 Fix bug reported by Jurgen Bollerhey
I have a
"REM Mon SPECIAL WEEK (W[weekno()])"
in my reminders file.
With tkremind -m the week number is displayed on the 2nd column which is
Tuesday and the date of this Tuesday is taken from the monday of the
next week, sometimes of Monday the same week.
2020-03-30 11:29:19 -04:00
Dianne Skoll
a6dbf05af4 Update WHATSNEW. 2020-03-20 09:18:48 -04:00
Dianne Skoll
8ab78fd8be Suppress compile warnings on Ubuntu 18.04 2020-03-19 20:27:45 -04:00
Dianne Skoll
4f119031a4 One more warning to suppress. 2020-03-19 20:24:53 -04:00
Dianne Skoll
19bdd6c2db Avoid warning about ignoring return value of fgets. 2020-03-19 20:24:01 -04:00
Dianne Skoll
f1557b8243 Try to suppress fallthrough warning. 2020-03-19 20:21:29 -04:00
Dianne Skoll
85f96e2e01 Update man page. 2020-03-14 11:37:11 -04:00
Dianne Skoll
47331cd919 Make ampm() function accept a DATETIME and obey $TimeSep, $DateSep and $DateTimeSep 2020-03-14 11:32:35 -04:00
Dianne Skoll
d9f18ed6a7 Don't use many-json2dict 2020-03-03 11:43:54 -05:00
Dianne Skoll
efa4816371 Properly-form JSON output. 2020-03-03 10:36:01 -05:00
Dianne Skoll
2dc8c63adb Proper prefix for beta versions. 2020-02-29 09:38:51 -05:00
Dianne Skoll
c3c1781021 Update COPYRIGHT date. 2020-02-28 08:56:49 -05:00
Dianne Skoll
cd39480a98 Remove extraneous spaces. 2020-02-27 16:50:44 -05:00
Dianne Skoll
281a1a206e Implement JSONQUEUE daemon command. 2020-02-27 15:18:23 -05:00
Dianne Skoll
cbff2a7bf2 Document ampm() 2020-02-27 08:39:21 -05:00
Dianne Skoll
2a08be8fd0 Fix up unit tests. 2020-02-26 17:43:47 -05:00
Dianne Skoll
0826678209 Make coerce from string to time and datetime accept ampm 2020-02-26 17:41:51 -05:00
Dianne Skoll
f2e421bfa5 Add acceptance tests for ampm() function. 2020-02-26 17:25:09 -05:00
Dianne Skoll
ce53a9b91a Add "ampm" built-in function. 2020-02-26 17:21:34 -05:00
Dianne Skoll
b166b1cf82 Fix up test file. 2020-02-24 15:17:07 -05:00
Dianne Skoll
d09fbb03b2 Bump version to 3.3.1. 2020-02-24 15:16:20 -05:00
Dianne Skoll
7a835f3b10 Update docs. 2020-02-23 16:02:59 -05:00
Dianne Skoll
6b991cdf9c Refactor saving of trigger info. 2020-02-23 11:38:17 -05:00
Dianne Skoll
018e9d0323 JSON can handle newlines (the literal newlines will be escaped to "\n" by the JSON writer.) 2020-02-23 11:17:59 -05:00
Dianne Skoll
f499ae096f Don't include filename or line number in synthesized tag. 2020-02-23 11:15:38 -05:00
Dianne Skoll
725e046a15 Fix bug in recording trigdate() for SATISFY-type reminders. :( 2020-02-22 19:15:24 -05:00
Dianne Skoll
275b1f62b6 For overlapping reminders, prefer the *later* version. 2020-02-22 16:50:42 -05:00
Dianne Skoll
6e58dea198 Handle overlapping events better. 2020-02-22 16:30:08 -05:00
Dianne Skoll
ad4e62c8c3 Test specifying DURATION as an integer. 2020-02-22 12:48:07 -05:00
Dianne Skoll
a5768d55d8 Update man page to document integer form of DURATION. 2020-02-22 12:46:57 -05:00
Dianne Skoll
7db49971c8 Update man page. 2020-02-22 12:40:32 -05:00
Dianne Skoll
45ca6631ac Make sure AM/PM is case-insensitive. 2020-02-22 12:32:52 -05:00
Dianne Skoll
d51944f36c Allow duration to be specified as a single number, meaning minutes.
Don't convert 90-99 to 1990-1999 when parsing numbers.
2020-02-22 12:31:17 -05:00
Dianne Skoll
037c79fb0f Allow times to have am/pm specifications. 2020-02-22 12:24:37 -05:00
Dianne Skoll
993373414f Parse times and datetimes with trailing am/pm 2020-02-22 12:14:18 -05:00
Dianne Skoll
38a0a9992a Leave a space after the asterisk row. 2020-02-12 11:19:30 -05:00
Dianne Skoll
a82bbe3776 Highlight today in month mode also. 2020-02-12 11:17:21 -05:00
Dianne Skoll
a32ba217ba Update man page. 2020-02-08 15:11:15 -05:00
Dianne Skoll
d322cf54ac Allow $FormWidth to be as large as 500. 2020-02-08 15:10:48 -05:00
Dianne Skoll
b1d07a231d Document $FormWidth. 2020-02-08 15:06:09 -05:00
Dianne Skoll
97851a08e6 Clamp min cal width at 72 2020-02-08 15:04:59 -05:00
Dianne Skoll
8547b30a8f Set $FormWidth to terminal width - 8 on startup. 2020-02-08 15:04:48 -05:00
Dianne Skoll
405c7d9ed0 Set release date. 2020-01-31 11:17:55 -05:00
Dianne Skoll
ac5b641d93 Note that back-ends MUST ignore unknown SPECIALs. 2020-01-30 16:07:57 -05:00
Dianne Skoll
06a79989c0 Minor tweaks. 2020-01-28 15:16:41 -05:00
Dianne Skoll
671db64436 Fix various typos. 2020-01-28 09:51:12 -05:00
Dianne Skoll
33344cefe6 Fix typo 2020-01-28 09:47:06 -05:00
Dianne Skoll
5ef0341537 Avoid memory leak. 2020-01-28 09:43:42 -05:00
Dianne Skoll
6abca08189 Add test to ensure rem2ps ignores unknown SPECIALs. 2020-01-28 09:42:13 -05:00
Dianne Skoll
35670ce651 Update docs 2020-01-28 09:38:06 -05:00
Dianne Skoll
e230d53d84 Ignore unknown SPECIALs in rem2ps. 2020-01-28 09:37:35 -05:00
Dianne Skoll
88537a3471 Remove ancient pointer to doe.carleton.ca 2020-01-28 09:29:42 -05:00
Dianne Skoll
7c9d74da73 Fix typo 2020-01-27 16:46:57 -05:00
Dianne Skoll
3b582935ee Sign beta tarballs too. 2020-01-27 16:46:07 -05:00
Dianne Skoll
508fafb875 Update WHATSNEW. 2020-01-27 16:28:57 -05:00
Dianne Skoll
6f718f0fe5 Update rem2ps man page. 2020-01-27 13:29:33 -05:00
Dianne Skoll
53acbf2052 Don't swallow %" %" markers in -ppp mode. 2020-01-27 13:21:48 -05:00
Dianne Skoll
1606dbbe77 Rework -@ option and tests. 2020-01-27 11:49:41 -05:00
Dianne Skoll
adced3ac6c Rework -@ option to be n,m 2020-01-27 11:44:16 -05:00
Dianne Skoll
14f207140a Better clamping algorithm for true colors 2020-01-27 11:31:57 -05:00
Dianne Skoll
d2da32de6c Don't hard-code number. 2020-01-26 18:26:03 -05:00
Dianne Skoll
e5d6a36f05 Update WHATSNEW 2020-01-26 18:10:11 -05:00
Dianne Skoll
68ecfcf876 Update test for change to rem2ps 2020-01-26 18:09:27 -05:00
Dianne Skoll
fcb14b9dfe Add PageBoundingBox comment. 2020-01-26 18:09:06 -05:00
Dianne Skoll
6a4b4257a6 Fix compilation failure on pre-C99 compilers. 2020-01-26 17:47:00 -05:00
Dianne Skoll
385b57e269 Update whatsnew 2020-01-25 17:43:10 -05:00
Dianne Skoll
a8e81e3984 Update WHATSNEW. 2020-01-25 17:41:47 -05:00
Dianne Skoll
46c5f0e752 Update man page for exact color setting. 2020-01-25 16:18:09 -05:00
Dianne Skoll
454d859fdd Support true RGB coloring. 2020-01-25 16:16:51 -05:00
Dianne Skoll
57134a182c Make SPECIALs case-insensitive. 2020-01-25 16:07:18 -05:00
Dianne Skoll
5801e143ea Make specials case-insensitive. 2020-01-25 16:04:53 -05:00
Dianne Skoll
4e0d0ff98b Test Xterm 256-color mode. 2020-01-25 15:16:30 -05:00
Dianne Skoll
d4ac1849ae Add comment for Xterm 256 colors. 2020-01-25 15:12:13 -05:00
Dianne Skoll
c16ac1bd8c Support 256-color mode on XTerm and other terminals. 2020-01-25 15:06:43 -05:00
Dianne Skoll
16222ac3bc Fix to man page. 2020-01-25 14:35:20 -05:00
Dianne Skoll
8d88931fb1 Fix indentation. 2020-01-25 14:27:25 -05:00
Dianne Skoll
63f0356e70 Fix man page wording. 2020-01-25 14:26:32 -05:00
Dianne Skoll
786b0dee6f Add test for =@ 2020-01-25 14:23:52 -05:00
Dianne Skoll
e7ef9dc295 Document -@ 2020-01-25 14:12:56 -05:00
Dianne Skoll
f59461b95d Convert black-on-black or white-on-white to grey. 2020-01-25 14:00:28 -05:00
Dianne Skoll
566a86b9fd Obey default color settings. 2020-01-25 11:29:06 -05:00
Dianne Skoll
8589a3730d Put -@[n] in help. 2020-01-25 11:13:50 -05:00
Dianne Skoll
c05fd366df Implement -@, -@0 and -@1 options to colorize reminders. 2020-01-25 11:12:10 -05:00
Dianne Skoll
fc9fd1e53c Start adding support for colored reminders in Agenda Mode. 2020-01-24 16:31:01 -05:00
Dianne Skoll
a5e6eb9f7c Add -@ commandline option. Yuck. 2020-01-24 16:26:55 -05:00
Dianne Skoll
a9430fea5f Make Remind adjust calendar to fit terminal. 2020-01-18 15:11:28 -05:00
Dianne Skoll
828a0d6589 Emit prevmonthyear and nextmonthyear items in -ppp format. 2020-01-18 14:52:17 -05:00
Dianne Skoll
32601da748 Update tests. 2020-01-18 14:48:27 -05:00
Dianne Skoll
ac50f119cf Document that -pp and -ppp enable -l 2020-01-18 14:45:23 -05:00
Dianne Skoll
7622ebaa0a Document remind -ppp format. 2020-01-18 14:43:21 -05:00
Dianne Skoll
a586d5cd37 Fix bug that incorrectly printed # fileinfo lines for -ppp format. 2020-01-18 14:43:04 -05:00
Dianne Skoll
edbc88bd19 Reformat error message. 2020-01-16 20:00:38 -05:00
Dianne Skoll
94f99f3414 Make rem2ps bail out if fed "-ppp"-format. 2020-01-16 19:59:30 -05:00
Dianne Skoll
fd4f84349e Include filename and lineno in tag synthesis. 2020-01-16 19:19:13 -05:00
Dianne Skoll
f86350b2ff More man page tweakage. 2020-01-16 18:56:28 -05:00
Dianne Skoll
564b72066a Document $DefaultColor 2020-01-16 18:53:30 -05:00
Dianne Skoll
2890c52090 Fix typo in man page 2020-01-15 11:27:43 -05:00
Dianne Skoll
c1d45485c1 Update test suite. 2020-01-15 09:20:31 -05:00
Dianne Skoll
8b2a69cf8d Do a small bit of refactoring to get rid of some copy/paste code. 2020-01-15 09:18:32 -05:00
Dianne Skoll
034c1341b3 Fix typos. 2020-01-14 21:47:26 -05:00
Dianne Skoll
29bbf1a030 Be strict in what we accept for SET $DefaultColor "r g b" 2020-01-14 21:44:08 -05:00
Dianne Skoll
be6661d6be Don't assume a potentially-colored reminder unless it's MSG/MSF/CAL type. 2020-01-14 21:43:46 -05:00
Dianne Skoll
3f876e792c Reset $DefaultColor each time we iterate. 2020-01-14 21:15:27 -05:00
Dianne Skoll
f2457b90ff Add patch for $DefaultColor, courtesy of Tim Chase. 2020-01-14 21:07:20 -05:00
Dianne Skoll
e999e9009b Minor formatting tweak. 2020-01-14 20:17:38 -05:00
Dianne Skoll
46326c001b Output true JSON if you invoke as "remind -ppp" 2020-01-14 20:09:24 -05:00
Dianne Skoll
b84c2c403c Add more balloon help. 2020-01-13 21:19:45 -05:00
Dianne Skoll
861ad72187 Add popup help. 2020-01-13 18:26:40 -05:00
Dianne Skoll
7dbbc34ccc Make Remind compile on older gcc that doesn't allow declarations in for(...) 2020-01-13 10:00:25 -05:00
Dianne Skoll
4ea45d1d14 Update rem2ps man page. 2020-01-12 20:03:43 -05:00
Dianne Skoll
c1b9243e2f Document new REM2PS format. 2020-01-12 19:56:45 -05:00
Dianne Skoll
a41c40c7a4 Document -pp option. 2020-01-12 19:24:21 -05:00
Dianne Skoll
318d4547ef Use r, g, b settings from SHADE special. 2020-01-12 18:11:35 -05:00
Dianne Skoll
6f98b60a6a Output "r", "g", "b" for shade-style reminders. 2020-01-12 18:09:41 -05:00
Dianne Skoll
baa8f7f3c4 Add test that OMITFUNC raises nonconst_expr indicator. 2020-01-12 17:51:06 -05:00
Dianne Skoll
6297622072 Write JSON using English day names. 2020-01-12 17:47:41 -05:00
Dianne Skoll
9f3ba0bf2b More intelligent filling out of GUI. 2020-01-12 17:27:50 -05:00
Dianne Skoll
9591dec708 Write out fully-specified dates in Reminders more compactly. 2020-01-12 17:15:38 -05:00
Dianne Skoll
ee2d0b7518 Production file location! 2020-01-12 14:05:55 -05:00
Dianne Skoll
2d46749c58 Add blank line when *first* creating AppendFile. 2020-01-12 14:01:20 -05:00
Dianne Skoll
494664d1b6 Take out blank line from warning header lines. 2020-01-12 14:00:04 -05:00
Dianne Skoll
49686210ae Better reverse-engineering of ordinal. 2020-01-12 13:57:25 -05:00
Dianne Skoll
ddfa44188b Reset HighestTagSoFar when we rewrite the appendfile after deletion. 2020-01-12 13:52:17 -05:00
Dianne Skoll
73cf93d27b Renumber tags when we delete a tagged reminder. 2020-01-12 13:34:22 -05:00
Dianne Skoll
60d1a34bf0 Fix up AM/PM handling; delete old comment lines. 2020-01-12 13:28:45 -05:00
Dianne Skoll
6f80986801 New version of tkremind seems to be decent... 2020-01-12 13:14:32 -05:00
Dianne Skoll
2078f087b2 An OMITFUNC should set the nonconst_expr flag. 2020-01-12 13:06:55 -05:00
Dianne Skoll
68d110826e First version of TkRemind that can reverse-engineer reminder without needing comments to set up GUI. 2020-01-12 12:45:34 -05:00
Dianne Skoll
9fb04c54ae Start work on reverse-engineering reminder dialog from JSON instead of relying on comments. 2020-01-11 19:08:35 -05:00
Dianne Skoll
d82314594b Make rem2html understand JSON interchange format. 2020-01-10 15:06:59 -05:00
Dianne Skoll
ad169a5248 Eliminate compiler warnings. 2020-01-10 13:57:13 -05:00
Dianne Skoll
a9bab81226 Test that rem2ps can parse "remind -pp" output. 2020-01-10 13:48:58 -05:00
Dianne Skoll
fa63a9ba51 Add comments. 2020-01-10 13:46:20 -05:00
Dianne Skoll
1e7a630737 rem2ps can read the new-style JSON output of "remind -pp" 2020-01-10 13:41:27 -05:00
Dianne Skoll
de1afce8da Suppress unused param warnings. 2020-01-09 18:53:00 -05:00
Dianne Skoll
ac3cb19c26 Simplify code. 2020-01-09 18:42:14 -05:00
Dianne Skoll
af0479d11d Start preparing rem2ps for parsing JSON input. 2020-01-09 18:38:08 -05:00
Dianne Skoll
0d9c04707f Output nonconst_expr and if_depth indicators in JSON mode. 2020-01-08 08:42:23 -05:00
Dianne Skoll
c2218f133b Preserve RGB info for a COLOR reminder. 2020-01-07 13:27:22 -05:00
Dianne Skoll
1ad0645fab Only print rawbody if it differs from body. 2020-01-06 22:25:49 -05:00
Dianne Skoll
3c16f6839a Pass raw body through to back-end in JSON mode. 2020-01-06 22:19:22 -05:00
Dianne Skoll
e8bac1e469 More info over JSON via -pp commandline switch. 2020-01-05 17:15:37 -05:00
Dianne Skoll
b3b69596f4 Output SKIP value in JSON. 2020-01-05 12:18:10 -05:00
Dianne Skoll
6a7bcb0956 Print the "wd" entry as array of weekday names. 2020-01-05 12:15:20 -05:00
Dianne Skoll
f18a0704c1 More work on emitting JSON. 2020-01-05 12:10:05 -05:00
Dianne Skoll
d6f24b7c1e rem2ps will only support "remind -p" protocol and not "remind -pp" 2020-01-03 18:00:21 -05:00
Dianne Skoll
e2c9bbf94c Start working on JSON-based alternate "remind -p" protocol. 2020-01-03 17:24:01 -05:00
Dianne Skoll
f53aa4f656 Start working on Version 2 of Rem2PS protocol. 2020-01-03 16:51:47 -05:00
Dianne Skoll
a7ab9b8bf8 Update release date. :( 2020-01-03 13:14:53 -05:00
Dianne Skoll
4448271166 Update WHATSNEW. 2020-01-03 13:05:33 -05:00
Dianne Skoll
4861b535a2 Use nicer moon graphics. 2020-01-03 13:02:16 -05:00
Dianne Skoll
167f0100c7 Minor tweaks. 2020-01-03 12:43:22 -05:00
Dianne Skoll
b0367c7a5c Update README.UNIX. 2020-01-02 14:45:31 -05:00
Dianne Skoll
4ae8ad52f5 Update WHATSNEW. 2020-01-02 14:42:46 -05:00
Dianne Skoll
dbd64828ab Use nicer moon images. 2020-01-02 11:39:29 -05:00
Dianne Skoll
158ca882ba Fix typo 2020-01-01 18:32:24 -05:00
Dianne Skoll
623ed44608 Update man page. 2020-01-01 18:30:46 -05:00
Dianne Skoll
f13b867626 Update WHATSNEW 2020-01-01 18:04:20 -05:00
Dianne Skoll
ff85325886 Support DATETIME - TIME 2020-01-01 18:00:22 -05:00
Dianne Skoll
aa830116ea Update copyright dates, etc. 2020-01-01 10:13:50 -05:00
Dianne Skoll
1a4504ba28 Catch date overflow if we use a crazy-long DURATION. 2020-01-01 10:01:02 -05:00
Dianne Skoll
20365c4627 Document DURATION 00:00 2020-01-01 09:50:13 -05:00
Dianne Skoll
fae8f89ed6 Handle self-overlapping events correctly; avoid 0-duration events; document
self-overlapping behaviour.
2020-01-01 09:45:28 -05:00
Dianne Skoll
a0689999fe Adjust duration_days to not include zero-duration tails. 2020-01-01 09:31:55 -05:00
Dianne Skoll
a42a0ab032 Update WHATSNEW. 2019-12-31 23:32:18 -05:00
Dianne Skoll
b66eb5d3ec Suppress printing subdirectory entry for "make test" 2019-12-31 23:11:55 -05:00
Dianne Skoll
8b4bc0f56e Print warning if we truncate a function name. 2019-12-31 22:54:22 -05:00
Dianne Skoll
c9d984983f Add a warning if we truncate variable names. 2019-12-31 22:50:42 -05:00
Dianne Skoll
47125b051a Clarify that IFTRIG can't take SATISFY 2019-12-31 22:41:34 -05:00
Dianne Skoll
e5e6ff6031 Return "Can't compute trigger" if SATISFY uses up too many iterations. 2019-12-31 22:26:23 -05:00
Dianne Skoll
9f0aedb608 Don't suppress errors in trigger computation. 2019-12-31 22:13:53 -05:00
Dianne Skoll
08af33ece5 Don't allow DURATION without an AT. 2019-12-31 21:51:34 -05:00
Dianne Skoll
9b421d0b94 Fix typo 2019-12-31 21:44:49 -05:00
Dianne Skoll
7bd8d2dd25 Tweak formatting. 2019-12-31 21:40:32 -05:00
Dianne Skoll
a7c4879a0a Update man page and WHATSNEW. 2019-12-31 21:38:18 -05:00
Dianne Skoll
8b3585a6b8 Add test for trigeventstart() and trigeventduration() 2019-12-31 21:12:44 -05:00
Dianne Skoll
a223149aee Add trigeventstart() and trigeventduration() functions. 2019-12-31 21:09:21 -05:00
Dianne Skoll
9185341b0c Add a test. 2019-12-31 19:14:15 -05:00
Dianne Skoll
bf2d707e13 Skip duration_days at least in each SATISFY loop. 2019-12-31 18:51:22 -05:00
Dianne Skoll
f081e5c54d Update test. 2019-12-31 18:42:10 -05:00
Dianne Skoll
18a3db0f31 Fix interation between multi-day events and SATISFY. 2019-12-31 18:41:25 -05:00
Dianne Skoll
d2c115127d Add a FIXME. 2019-12-31 18:02:49 -05:00
Dianne Skoll
c12e7e1b8f Update tests with new version. 2019-12-31 17:47:40 -05:00
Dianne Skoll
d3495ab3aa Update version to 3.2.0. Events spanning >1 day are a major new feature. 2019-12-31 17:46:40 -05:00
Dianne Skoll
b93a7a6195 Update tests. 2019-12-31 17:43:46 -05:00
Dianne Skoll
e5519a8498 Handle events that span >1 day. 2019-12-31 17:39:26 -05:00
Dianne Skoll
eb2256f873 Use proper arrow icons instead of text <- and -> 2019-12-30 20:51:37 -05:00
Dianne Skoll
637b137b1c Use open |foo rather than exec to handle cmdline option parsing more uniformly. 2019-12-30 20:27:12 -05:00
Dianne Skoll
e2d14e73bf Update copyright date. 2019-12-30 11:18:01 -05:00
Dianne Skoll
fbbffb4672 Bump version to 3.1.18 and copyright year to 2020. 2019-12-30 11:15:00 -05:00
Dianne Skoll
422e098727 Don't use a static coerce_buf 2019-12-30 11:02:09 -05:00
Dianne Skoll
87347e30b2 Make string concatenation more efficient. 2019-12-30 10:59:32 -05:00
Dianne Skoll
3314ce9823 Update WHATSNEW 2019-12-30 10:42:17 -05:00
Dianne Skoll
402c1fe614 Proper fix. 2019-12-30 10:37:30 -05:00
Dianne Skoll
1d57856aa8 Avoid startup error if ShowTodaysReminders is true and ExtraRemindArgs is empty. 2019-12-30 10:34:37 -05:00
Dianne Skoll
c027c215d6 Update WHATSNEW 2019-12-29 21:03:27 -05:00
Dianne Skoll
fa0428b9fe Fix compile error for Romanian language; avoid compiler warning for non-English languages. 2019-12-29 19:08:48 -05:00
Dianne Skoll
b01c499ce5 Tweak man page. 2019-12-29 18:53:29 -05:00
Dianne Skoll
4e5033dd24 Implement adding DATETIME+TIME, TIME+DATETIME and TIME+TIME 2019-12-29 18:46:10 -05:00
Dianne Skoll
00863f3830 Add header file dependency. 2019-12-28 17:46:17 -05:00
Dianne Skoll
2d4b35e8b9 Add tests for introspection functions. 2019-12-28 17:28:31 -05:00
Dianne Skoll
6e4f2b9466 Implement remaining trigger introspection functions. 2019-12-28 17:09:05 -05:00
Dianne Skoll
9a6fc0253b Clear last triggers in all necessary spots. 2019-12-28 16:42:10 -05:00
Dianne Skoll
3180c781ed Start working on making bits of the trigger and time trigger introspectable. 2019-12-28 16:37:47 -05:00
Dianne Skoll
632152e8b6 Remember the last trigger and time trigger. 2019-12-28 16:24:16 -05:00
Dianne Skoll
1048f7e98d Add TAGS to omitted files. 2019-12-28 16:17:32 -05:00
Dianne Skoll
3de265216e Document $MaxStringLen 2019-11-21 11:41:25 -05:00
Dianne Skoll
2bdcadc7ab Minor cleanups. 2019-11-21 11:36:49 -05:00
Dianne Skoll
421ddfc68e Catch date overflow in slide() function. 2019-11-21 11:06:00 -05:00
Dianne Skoll
41594bc1ac Update release notes. 2019-11-15 11:14:23 -05:00
Dianne Skoll
e85199d464 Remove obsolete line. 2019-11-15 11:08:04 -05:00
Dianne Skoll
a6ee3bc704 Use git-archive to create tarball. 2019-11-15 11:06:19 -05:00
Dianne Skoll
2909106f30 Update copyright date. 2019-11-15 10:57:01 -05:00
Dianne Skoll
05b97aabb2 Sign releases. 2019-11-15 10:56:40 -05:00
Dianne Skoll
84af60d817 Delete COMMIT_EDITMSG when syncing to public git repo. 2019-11-14 17:04:43 -05:00
Dianne Skoll
72403a2512 Warn if "OMIT a THROUGH b" has a > b 2019-11-14 11:09:51 -05:00
Dianne Skoll
4ec619d646 Update copyright date. 2019-11-07 20:52:38 -05:00
Dianne Skoll
6178a627a0 Fix bug that prevented warning if we redefine a built-in function. 2019-11-07 20:50:35 -05:00
Dianne Skoll
3095fd7e4a Enable warning-free compilation even with -Wextra. 2019-11-04 16:35:14 -05:00
Dianne Skoll
74a6041760 Update version to 03.01.17. 2019-11-04 16:18:56 -05:00
Dianne Skoll
96127e37ff Update man page. 2019-11-04 16:16:15 -05:00
Dianne Skoll
df5484ea35 Add test for "SCANFROM -n" form. 2019-11-04 16:10:53 -05:00
Dianne Skoll
0ae3dae030 Allow shortand: SCANFROM -n meaning SCANFROM [today() - n] 2019-11-04 16:08:44 -05:00
Dianne Skoll
e5979139ac Fix typo. 2019-02-13 11:04:20 -05:00
Dianne Skoll
f81f6deb20 Apply patch from Dov Feldstern to fix Adar behaviour. 2018-12-11 10:05:11 -05:00
Dianne Skoll
f9951909d8 First part of patch to fix ADAR behaviour 2018-12-11 10:04:05 -05:00
Dianne Skoll
bbda972b05 Properly react to changes in extra remind args. 2018-12-07 14:54:02 -05:00
Dianne Skoll
4445e9c434 Add "Extra remind options" option. 2018-12-07 14:47:47 -05:00
Dianne Skoll
709adacac2 Add helper script to sync to dianne.skoll.ca git repo 2018-11-29 11:18:35 -05:00
Dianne Skoll
9841cdd355 When dumping queue contents, omit expired reminders. 2018-11-28 14:27:40 -05:00
94 changed files with 13074 additions and 2346 deletions

4
.gitattributes vendored Normal file
View File

@@ -0,0 +1,4 @@
.gitignore export-ignore
.gitattributes export-ignore
remind.php export-ignore
sync-to-dianne-git export-ignore

18
.gitignore vendored
View File

@@ -1,15 +1,17 @@
*.bak
*.o
*~
.gitignore
TAGS
autom4te.cache
config.log
config.status
src/Makefile
www/Makefile
*.o
src/config.h
src/remind
rem2html/Makefile
src/*.tar.gz*
tests/test.out
.gitignore
*~
src/Makefile
src/config.h
src/rem2ps
src/remind
src/version.h
tests/test.out
www/Makefile

View File

@@ -3,7 +3,7 @@ THE REMIND COPYRIGHT
1. REMIND refers to the entire set of files and documentation in the
REMIND package.
2. REMIND is Copyright 1992-2018 Dianne Skoll, except where noted in
2. REMIND is Copyright 1992-2021 Dianne Skoll, except where noted in
individual files.
3. DISTRIBUTION AND USE

View File

@@ -8,7 +8,7 @@ all: src/Makefile
@echo "* *"
@echo "*******************"
@echo ""
@cd src; $(MAKE) all LANGDEF=$(LANGDEF)
@cd src && $(MAKE) all LANGDEF=$(LANGDEF)
install:
@echo ""
@@ -18,14 +18,15 @@ install:
@echo "* *"
@echo "*********************"
@echo ""
cd src; $(MAKE) install
@$(MAKE) -C src install
@$(MAKE) -C rem2html install
clean:
find . -name '*~' -exec rm {} \;
cd src; $(MAKE) clean
cd src && $(MAKE) clean
test:
@cd src && $(MAKE) test
@cd src && $(MAKE) -s test
distclean: clean
rm -f config.cache config.log config.status src/Makefile src/config.h tests/test.out www/Makefile

83
configure vendored
View File

@@ -626,6 +626,7 @@ VERSION
EGREP
GREP
CPP
PERL
SET_MAKE
LN_S
INSTALL_DATA
@@ -2291,36 +2292,6 @@ EOF
ac_config_headers="$ac_config_headers src/config.h"
if test "`uname -s`" = "Darwin" ; then
trap 'echo Be patient...' INT TERM
cat <<'EOF'
Please don't use Apple products. This script will continue in 30 seconds
if you insist on compiling Remind on Mac OS X.
EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap - INT
trap - TERM
fi
if uname -s | grep -i -q 'cygwin' ; then
trap 'echo Be patient...' INT TERM
cat <<'EOF'
Please don't use Microsoft products. This script will continue in 30
seconds if you insist on compiling Remind on Cygwin.
EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap - INT
trap - TERM
fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -3274,6 +3245,46 @@ $as_echo "no" >&6; }
SET_MAKE="MAKE=${MAKE-make}"
fi
# Extract the first word of "perl", so it can be a program name with args.
set dummy perl; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_PERL+:} false; then :
$as_echo_n "(cached) " >&6
else
case $PERL in
[\\/]* | ?:[\\/]*)
ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
PERL=$ac_cv_path_PERL
if test -n "$PERL"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5
$as_echo "$PERL" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
@@ -3820,7 +3831,7 @@ _ACEOF
for ac_header in sys/file.h glob.h wctype.h locale.h
for ac_header in sys/types.h sys/file.h glob.h wctype.h locale.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -3976,10 +3987,10 @@ fi
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wstrict-prototypes"
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
fi
for ac_func in setenv unsetenv glob mbstowcs setlocale
for ac_func in setenv unsetenv glob mbstowcs setlocale initgroups
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -3991,9 +4002,10 @@ _ACEOF
fi
done
VERSION=03.01.16
VERSION=03.03.12
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h"
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h rem2html/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -4689,6 +4701,7 @@ do
"src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
"www/Makefile") CONFIG_FILES="$CONFIG_FILES www/Makefile" ;;
"src/version.h") CONFIG_FILES="$CONFIG_FILES src/version.h" ;;
"rem2html/Makefile") CONFIG_FILES="$CONFIG_FILES rem2html/Makefile" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac

View File

@@ -14,41 +14,12 @@ EOF
AC_CONFIG_HEADER(src/config.h)
if test "`uname -s`" = "Darwin" ; then
trap 'echo Be patient...' INT TERM
cat <<'EOF'
Please don't use Apple products. This script will continue in 30 seconds
if you insist on compiling Remind on Mac OS X.
EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap - INT
trap - TERM
fi
if uname -s | grep -i -q 'cygwin' ; then
trap 'echo Be patient...' INT TERM
cat <<'EOF'
Please don't use Microsoft products. This script will continue in 30
seconds if you insist on compiling Remind on Cygwin.
EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap - INT
trap - TERM
fi
dnl Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PATH_PROG([PERL], [perl])
dnl Checks for libraries.
dnl Replace `main' with a function in -lm:
@@ -61,7 +32,7 @@ AC_CHECK_SIZEOF(unsigned int)
AC_CHECK_SIZEOF(unsigned long)
dnl Checks for header files.
AC_CHECK_HEADERS(sys/file.h glob.h wctype.h locale.h)
AC_CHECK_HEADERS(sys/types.h sys/file.h glob.h wctype.h locale.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_STRUCT_TM
@@ -71,10 +42,11 @@ AC_FUNC_UTIME_NULL
AC_HEADER_TIME
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wstrict-prototypes"
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
fi
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale)
VERSION=03.01.16
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale initgroups)
VERSION=03.03.12
AC_SUBST(VERSION)
AC_OUTPUT(src/Makefile www/Makefile src/version.h)
AC_SUBST(PERL)
AC_OUTPUT(src/Makefile www/Makefile src/version.h rem2html/Makefile)

View File

@@ -0,0 +1,13 @@
Remind-conf-mode is a configuration mode designed to make it a little easier to configure remind using emacs.
It offers a vibrant colour syntax highlighting for those who like lots of colour, simple indentation and some hopefully useful functions for entering times and dates. Those functions have been exposed in a special menu for remind for those who have not turned off the emacs menu system.
Just copy remind-conf-mode.el to your elisp folder (whatever it is called) make sure it is in your path so emacs know where to look for it, and put (require 'remind-conf-mode) in your dotemacs file.
There are some more complex instructions in the file itself.
Have fun and if you can think of any improvements let me know, or fork it to your own git repository and experiment away.
The faux-locale branch has code for choosing the language you use remind in. Please try it out and let me know if there are any problems with it.
Shelagh

View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@@ -1,11 +1,11 @@
;;; remind-conf-mode.el --- A mode to help configure remind.
;; Copyright (C) 2008 Shelagh Manton <shelagh.manton@gmail.com>
;; Copyright (C) 2008 - 2011 Shelagh Manton <shelagh.manton@gmail.com>
;; Author: Shelagh Manton <shelagh.manton@gmail.com> with help from
;; Dianne Skoll
;; Keywords: remind configure mode
;; Version: .04
;; Keywords: remind configure convenience
;; Version: 0.14
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
@@ -34,7 +34,7 @@
;; If you want to use the auto-complete stuff, you will need to download and install the
;; auto-complete library from http://www.cx4a.org/pub/auto-complete.el and put
;; (require 'auto-complete) in your emacs with
;; (require 'auto-complete) in your Emacs with
;; (add-hook 'remind-conf-mode-hook
;; (lambda ()
;; (make-local-variable 'ac-sources)
@@ -42,10 +42,13 @@
;; (auto-complete t)))
;; in your .emacs file
;; PS. you could add ac-source-abbrev ac-source-words-in-buffer to have abbrevs and
;; PS. you could add ac-source-abbrev ac-source-words-in-buffer to have abbrevs and
;; other words in buffer auto-complete too
;;; History:
;;Thu, Nov 26, 2009
;; sorted out why the rem-save-file was not working. fixed.
;;
;; Thu, Feb 14, 2008
;; Based mode on wpld-mode tutorial and sample-mode on emacs wiki.
;; Ideas from mupad.el for font-lock styles.
@@ -54,14 +57,14 @@
;; Added a demo skeleton for people to copy for easy entry of coloured remind entries.
;; tried to hook in the auto-complete library so that all known functions and keywords can be easily entered.
;; EXPERIMENTAL, but seems to work well here (emacs cvs).
;; Seems to work without case folding which is nice. wonder why it didn't yesterday?
;; Seems to work without case folding which is nice.
;;; Code:
(require 'font-lock); this goes in the define-derived-mode part.
(when (featurep 'xemacs)
(require 'overlay)) ;I wonder if this will help with font-lock and xemacs?
(require 'overlay)) ;supposed to make it compatible with Xemacs.
(defgroup remind-conf nil
@@ -80,12 +83,13 @@
remind-conf-mode-map)
"Keymap for `remind-conf-mode'.")
(define-key remind-conf-mode-map "\C-cr" 'rem-skel)
(define-key remind-conf-mode-map "\C-ct" 'rem-today)
(define-key remind-conf-mode-map "\C-cd" 'rem-today-skel)
(define-key remind-conf-mode-map "\C-cw" 'rem-week-away)
(define-key remind-conf-mode-map "\C-cx" 'rem-tomorrow)
(define-key remind-conf-mode-map "\C-ca" 'rem-days-away)
(define-key remind-conf-mode-map "\C-c\C-r" 'rem-skel)
(define-key remind-conf-mode-map "\C-c\C-t" 'rem-today)
(define-key remind-conf-mode-map "\C-c\C-d" 'rem-today-skel)
(define-key remind-conf-mode-map "\C-c\C-w" 'rem-week-away)
(define-key remind-conf-mode-map "\C-c\C-W" 'rem-weeks-away)
(define-key remind-conf-mode-map "\C-c\C-x" 'rem-tomorrow)
(define-key remind-conf-mode-map "\C-c\C-a" 'rem-days-away)
(define-key remind-conf-mode-map "\M-j" 'remind-indent-line)
(define-key remind-conf-mode-map (kbd "RET") 'remind-indent-line)
(define-key remind-conf-mode-map "\C-c\C-c" 'rem-save-file)
@@ -107,41 +111,51 @@
(defconst remind-keywords
(sort
(list "RUN" "REM" "ONCE" "SATISFY" "BEFORE" "UNSET" "OMIT"
(list "RUN" "REM" "ONCE" "SATISFY" "BEFORE" "UNSET" "OMIT" "FIRST" "SATISFY"
"OMIT" "DATE" "SKIP" "ONCE" "AFTER" "WARN" "PRIORITY" "AT" "SCHED" "IF" "ELSE" "ENDIF"
"WARN" "UNTIL" "THROUGH" "SCANFROM" "DURATION" "TAG" "MSG" "MSF" "CAL" "SPECIAL" "IFTRIG"
"PS" "PSFILE" "BANNER" "INCLUDE" "PUSH-OMIT-CONTEXT" "DEBUG" "DUMPVARS"
"CLEAR-OMIT-CONTEXT" "POP-OMIT-CONTEXT" "SET" "ERRMSG" "FSET"
"EXIT" "FLUSH" "PRESERVE" "MOON" "COLOR" "COLOUR")
"PS" "PSFILE" "BANNER" "INCLUDE" "PUSH-OMIT-CONTEXT" "DEBUG" "DUMPVARS" "PUSH" "CLEAR" "POP"
"CLEAR-OMIT-CONTEXT" "POP-OMIT-CONTEXT" "SET" "ERRMSG" "FSET" "DUMP" "BAN" "INC" "SCAN"
"EXIT" "FLUSH" "PRESERVE" "MOON" "COLOR" "UNSET")
#'(lambda (a b) (> (length a) (length b)))))
(defconst remind-type-keywords
(sort
(list "INT" "STRING" "TIME" "DATE" "SHADE")
(list "INT" "STRING" "TIME" "DATE" "SHADE" "DATETIME")
#'(lambda (a b) (> (length a) (length b)))))
(defconst remind-builtin-variables
(sort
(list "$CalcUTC" "$CalMode" "$DefaultPrio" "$EndSent" "$EndSentIg" "$NumTrig"
"$FirstIndent" "$FoldYear" "$FormWidth" "$MinsFromUTC" "$LatDeg" "$LatMin" "$LatSec"
"$Location" "$LongDeg" "$LongMin" "$LongSec" "$MaxSatIter" "$SubsIndent")
(list "$CalcUTC" "$CalMode" "$Daemon" "$DateSep" "$DefaultPrio" "$DontFork" "$DontTrigAts" "$DontQueue"
"$EndSent" "$EndSentIg" "$NumTrig" "$FirstIndent" "$FoldYear" "$FormWidth" "$HushMode"
"$IgnoreOnce" "$InfDelta" "$NextMode" "$NumQueued" "$NumTrig" "$PrefixLineNo" "$PSCal" "$RunOff"
"$SimpleCal" "$SortByDate" "$SortByPrio" "$MinsFromUTC" "$LatDeg" "$LatMin" "$LatSec" "$EndSent"
"$EndSentIg" "$Location" "$LongDeg" "$LongMin" "$LongSec" "$MaxSatIter" "$SubsIndent" "$T" "$Td"
"$Tm" "$Tw" "$Ty" "$TimeSep" "$UntimedFirst" "$U" "$Ud" "$Um" "$Uw" "$Uy")
#'(lambda (a b) (> (length a) (length b)))))
(defconst remind-time-words
(sort
(list "Jan" "January" "Feb" "Mar" "Apr" "Jun" "Jul" "Aug" "Sept" "Sep" "Oct" "Nov" "Dec" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December" "Mon" "Monday" "Tue" "Tues" "Tuesday" "Wed" "Wednesday" "Thu" "Thursday" "Fri" "Friday" "Saturday" "Sat" "Sun" "Sunday")
(list "Jan" "January" "Feb" "Mar" "Apr" "Jun" "Jul" "Aug" "Sept" "Sep" "Oct" "Nov" "Dec"
"February" "March" "April" "May" "June" "July" "August" "September" "October"
"November" "December" "Mon" "Monday" "Tue" "Tues" "Tuesday" "Wed" "Wednesday"
"Thu" "Thursday" "Thurs" "Fri" "Friday" "Saturday" "Sat" "Sun" "Sunday")
#'(lambda (a b) (> (length a) (length b)))))
(defconst remind-builtin-functions
(sort
(list "abs" "access" "shell" "args" "asc" "baseyr" "char" "choose" "coerce" "date"
"dawn" "today" "day" "daysinmon" "defined" "dosubst" "dusk" "easterdate" "easter"
"filedir" "filename" "getenv" "hour" "iif" "trigger" "index" "isdst" "isleap"
"isomitted" "hebdate" "hebday" "hebmon" "hebyear" "language" "ord" "thisyear"
"sunrise" "sunset" "lower" "max" "min" "minute" "mon" "moondate" "moontime"
"moonphase" "now" "ostype" "plural" "realnow" "realtoday" "sgn" "strlen" "psshade"
"substr" "trigdate" "trigger" "trigtime" "trigvalid" "typeof" "upper" "psmoon"
"value" "version" "wkday" "wkdaynum" "msgprefix" "msgsuffix" "year")
(list "abs" "access" "args" "asc" "baseyr" "char" "choose" "coerce" "current" "date" "datetime" "datepart"
"dawn" "day" "daysinmon" "defined" "dosubst" "dusk" "easter" "easterdate" "evaltrig" "filedate"
"filedatetime" "filedir" "filename" "getenv" "hebdate" "hebday" "hebmon" "hebyear" "hour" "iif" "index" "isdst"
"isleap" "isomitted" "language" "lower" "max" "min" "minute" "minsfromutc" "mon" "monnum" "moondate" "moondatetime"
"moonphase" "moontime" "msgprefix" "msgsuffix" "nonomitted" "now" "ord" "ostype" "plural"
"psmoon" "psshade" "realcurrent" "realnow" "realtoday" "sgn" "shell" "slide" "strlen" "substr" "sunrise" "sunset" "time" "timepart"
"thisyear" "today" "trigdate" "trigdatetime" "trigger" "trigger" "trigtime" "trigvalid" "typeof" "tzconvert" "upper" "value"
"version" "weekno" "wkday" "wkdaynum" "year"
)
#'(lambda (a b) (> (length a) (length b)))))
;;; faces
@@ -225,10 +239,7 @@
:group 'remind-conf)
(defcustom rem-post-save-function ""
"Name of shell function that can be run when you save and close a remind file.
If you put a & after the name of the function, it will run asyncronously. This might
be useful if the process takes a long time."
"Name of shell function that can be run when you save and close a remind file."
:type 'string
:group 'remind-conf
)
@@ -258,18 +269,22 @@ be useful if the process takes a long time."
(cons (regexp-opt remind-type-keywords 'words) remind-conf-type-face)
'("\[[a-zA-Z]\\{3,6\\}\]" . remind-conf-color-face)
'("\\s-+\\([12][0-9]\\|3[01]\\|0?[0-9]\\)\\s-+" . remind-conf-substitutes-face);better date regexp
'("\\s-+\\([12][09][0-9][0-9][-/]\\(0[1-9]\\|1[0-2]\\)[-/]\\([12][0-9]\\|0[1-9]\\|3[01]\\)\\)\\s-+" . remind-time-face) ;; pseudo ISO 8601 date format.
'("\\s-+\\([12][09][0-9][0-9][-/]\\(0[1-9]\\|1[0-2]\\)[-/]\\([12][0-9]\\|0[1-9]\\|3[01]\\)\\)@\\(2[0-4]\\|[01]?[0-9][.:][0-5][0-9]\\)\\s-+" . remind-time-face) ;;extended pseudo ISO time format
'("\\s-+\\(\\(?:20\\|19\\)[0-9][0-9]\\)\\s-+" . remind-conf-substitutes-face);years
'("\\s-+\\(2[0-4]\\|[01]?[0-9][.:][0-5][0-9]\\)\\s-+" . remind-conf-substitutes-face);24hour clock, more precise
'("\\s-+\\([+-][+-]?[1-9][0-9]*\\)\\s-+" 1 remind-conf-delta-face prepend)
(cons (regexp-opt remind-builtin-variables 'words) remind-conf-variable-face)))
"The ultimate in highlighting experiences for `remind-conf-mode'.")
;;YYYY-MM-DD@hh:mm, YYYY-MM-DD@hh.mm, YYYY/MM/DD@hh:mm and YYYY/MM/DD@hh.mm
(defcustom remind-conf-font-lock-keywords 'remind-conf-font-lock-keywords-3
"Font-lock highlighting level for `remind-conf-mode'."
:group 'remind-conf
:type '(choice (const :tag "Barest minimum of highlighting." remind-conf-font-lock-keywords-1)
(const :tag "Medium highlighting." remind-conf-font-lock-keywords-2)
(const :tag "Highlighting deluxe." remind-conf-font-lock-keywords-3)))
(const :tag "Fruit salad." remind-conf-font-lock-keywords-3)))
;;; Indentation (I'm sure this could be made more simple. But at least it works.)
@@ -289,8 +304,8 @@ be useful if the process takes a long time."
(if (looking-at "^[ \t]*\\<\\(ENDIF\\|POP\\(?:-OMIT-CONTEXT\\)?\\)\\>")
(progn
(save-excursion
(forward-line -1)
(setq cur-indent (- (current-indentation) remind-indent-level))) ;note that not-indented is still t
(forward-line -1)
(setq cur-indent (- (current-indentation) remind-indent-level))) ;note that not-indented is still t
(if (< cur-indent 0) (setq cur-indent 0)))
(save-excursion
(while not-indented
@@ -313,14 +328,17 @@ be useful if the process takes a long time."
;;; Convenience functions
(define-skeleton rem-skel
"Skeleton to insert a rem line in a remind configuration file."
nil
"REM "(skeleton-read "Date? " )
("Optional: How many days ahead? " " +" str )
"Skeleton to insert a rem line in a remind configuration file.
If you don't want an optional feature just RET and move on."
nil
'(setq v1 (skeleton-read "How many days in future?: "))
"REM " (rem-days-away (string-to-number v1))
("Optional: How many days warning? " " +" str )
resume:
("Optional: At what time? Format eg 13:00. " " AT " str)
resume:
("Optional: How many minutes ahead? " " +" str )
("Optional: How many minutes warning? " " +" str )
resume:
("Optional: At what priority? eg 0-9999" " PRIORITY " str )
resume:
@@ -333,7 +351,7 @@ be useful if the process takes a long time."
"REM " (format-time-string "%d %b %Y")
("Optional: At what time? Format eg 13:20. " " AT " str)
resume:
("Optional: How many minutes ahead? " " +" str )
("Optional: How many minutes warning? " " +" str )
resume:
("Optional: At what priority? eg 0-9999" " PRIORITY " str )
resume:
@@ -351,9 +369,7 @@ be useful if the process takes a long time."
(insert (format-time-string "%e %b %Y" (time-add (current-time) (days-to-time 1)))))
(defun rem-days-away (arg)
"Insert a day N number of days in the future.
Takes a prefix argument, but defaults to 4."
"Insert a day ARG number of days in the future."
(interactive "nHow many Days?: ")
(insert (format-time-string "%e %b %Y" (time-add (current-time) (days-to-time arg)))))
@@ -362,11 +378,10 @@ Takes a prefix argument, but defaults to 4."
(interactive)
(insert (format-time-string "%e %b %Y" (time-add (current-time) (days-to-time 7)))))
(setq skeleton-end-hook nil) ; so the skeletons will not automatically go to a new line.
;;; private function
;; could make it useful for others. Put somethin like the following in your .emacs
;(setq rem-post-save-function "~/bin/dailypic &")
(defun rem-weeks-away (arg)
"Insert a day ARG many weeks in future."
(interactive "nHow many weeks?: ")
(insert (format-time-string "%e %b %Y" (time-add (current-time) (days-to-time (* 7 arg))))))
(defun rem-save-file ()
"Save the file and start the shell function in one go.
@@ -374,7 +389,7 @@ Takes a prefix argument, but defaults to 4."
This function will close the window after running. It needs the
variable `rem-post-save-function' to be set. It will be most
useful to people who have some sort of function they run to use
remind data ie procucing calendars."
remind data ie producing calendars."
(interactive)
(if (boundp 'rem-post-save-function)
(progn (save-buffer)
@@ -383,7 +398,9 @@ remind data ie procucing calendars."
(error "`rem-post-save-function' variable is not set")))
(defun rem-setup-colors ()
"Insert set of variables for coloured output in remind messages."
"Insert set of variables for coloured output in remind messages.
You would only need to do this once in your main reminders file."
(interactive)
(find-file (expand-file-name "~/.reminders"))
(goto-char 0) ;we do want it somewhere near the top of the file.
@@ -410,12 +427,38 @@ SET BrWht Esc + \"[37;1m\" \n \n")))
;; So now you can do things like:
(define-skeleton birthcol
(define-skeleton rem-birthday
"Make birthdays magenta.
Acts on the region or places point where it needs to be."
nil
"[Mag]" _ " [Nrm]")
(define-skeleton rem-urgent
"Colour urgent notices red.
Acts on the region or places point where it needs to be."
nil
"[Red]" _ " [Nrm]")
;; menu anyone?
(easy-menu-define remind-menu
remind-conf-mode-map
"Menu used in remind-conf-mode."
(append '("Remind")
'([ "Insert a reminder" rem-skel t])
'([ "Insert todays date" rem-today t])
'([ "Insert tomorrows date" rem-tomorrow t])
'([ "How many days away?" rem-days-away t])
'([ "A week away" rem-week-away t])
'([ "How many weeks away?" rem-weeks-away t])
'([ "Birthday color" rem-birthday t])
'([ "Urgent color" rem-urgent t])
'([ "Save the file and run a script" rem-save-file t])
'("-----")
'([ "Setting up the colors - once-off" rem-setup-colors t])
))
;; finally the derived mode.
;;;###autoload
@@ -429,6 +472,7 @@ Acts on the region or places point where it needs to be."
(set (make-local-variable 'comment-start) ";")
(set (make-local-variable 'comment-start) "#")
(set (make-local-variable 'comment-end) "\n")
(set (make-local-variable 'skeleton-end-hook) nil) ; so the skeletons will not automatically go to a new line.
(set (make-local-variable 'fill-column) '100);cause I was having problems with autofill.
(set (make-local-variable 'indent-line-function) 'remind-indent-line)
(use-local-map remind-conf-mode-map)
@@ -438,7 +482,5 @@ Acts on the region or places point where it needs to be."
(provide 'remind-conf-mode)
;;; remind-conf-mode.el ends here
;;; Indentation code
;;; work out how to make the syntax highlighting work only before the (MSG|MSF)
;;; keywords and not after.
;;; for my own use. keymap to save file and do dailypic C-c C-c in time honoured tradition?
;;; work out how to make the syntax highlighting work only before the
;;; (MSG|MSF) keywords and not after.

View File

@@ -1,4 +1,4 @@
REMIND version 3.1 for UNIX
REMIND version 3.2 for UNIX
REMIND is a sophisticated alarm/calendar program. Details are given
in the man page, "remind.1".
@@ -6,16 +6,16 @@ in the man page, "remind.1".
INSTALLING REMIND:
-----------------
If you have Tcl/Tk (wish 4.1 or higher) installed and are running X Windows:
--------------------------------------------------------------
If you have Tcl/Tk (wish 4.1 or higher) installed and are running X11:
----------------------------------------------------------------------
1) Type: wish ./build.tk from the top-level Remind directory.
Fill in the various options and hit "Build Remind"
2) Type: "make install" -- you may need to be root to do this.
If you do NOT have Tcl/Tk or are NOT running X Windows:
-------------------------------------------------------
If you do NOT have Tcl/Tk or are NOT running X11:
-------------------------------------------------
1) Edit the file "src/custom.h" according to your preferences.
@@ -73,12 +73,12 @@ RELEASE NOTES -- miscellaneous info that couldn't go anywhere else!
1. POPUP REMINDERS
If you're running under X-Windows and you have the TCL tools,
you can create simple pop-up reminders by creating the following
TCL script called 'popup'. It pops a message on to the screen and
waits for you to press the 'OK' button. If you don't press the OK button
within 15 seconds, it exits anyway. To use it, you can use the '-k' option
for Remind as follows:
If you're running under X11 and you have the Tcl tools, you can create
simple pop-up reminders by creating the following Tcl script called
'popup'. It pops a message on to the screen and waits for you to
press the 'OK' button. If you don't press the OK button within 15
seconds, it exits anyway. To use it, you can use the '-k' option for
Remind as follows:
remind "-kpopup '%s'&" .reminders
@@ -93,7 +93,7 @@ Norman Walsh.
#!/usr/local/bin/wish
wm withdraw .
after 15000 { destroy . ; exit }
tk_dialog .d { Message } $argv warning 0 { OK }
tk_dialog .d { Message } $argv warning 0 { OK }
destroy .
exit
-------------- Cut Here ---------- Cut Here ---------- Cut Here -------------

View File

@@ -1,5 +1,353 @@
CHANGES TO REMIND
* VERSION 3.3 Patch 12 - 2022-??-??
- NEW FEATURE: Add a DO command. This is just like INCLUDE, but relative
paths are interpreted relative to the directory containing the current
file. That is:
DO somefile.rem
is equivalent to:
INCLUDE [filedir()]/somefile.rem
- NEW FEATURE: Add the $DefaultTDelta system variable and associated
-tt[N] command-line option to set a default time delta for timed
reminder without an explicit +N delta.
- IMPROVEMENT: TkRemind: Store .tkremindrc in $XDG_CONFIG_HOME/tkremindrc
or $HOME/.config/tkremindrc as per the XDG Base Directory Specification.
* VERSION 3.3 Patch 11 - 2021-12-30
- IMPROVEMENT: TkRemind: Save the print dialog settings so they persist.
- IMPROVEMENT: TkRemind: Show queue in sorted order.
- IMPROVEMENT: TkRemind: Pass "-r" flag to inotifywait
- IMPROVEMENT: TkRemind: Draw moon phases with Tk canvas items rather than
using PNG images. This lets them change color along with other TkRemind
preferences.
- IMPROVEMENT: TkRemind: Underline editable reminders when the pointer enters
them; fire up the editor with either Button-1 or Button-3 for
non-TkRemind-generated reminders.
- NEW FUNCTION: Remind: Add the isany() built-in function.
- IMPROVEMENT: rem2html: Add class names indicating number of rows in calendar
- IMPROVEMENT: remind: In -z0 mode, sleep with higher precision to ensure we
wake as close to possible to each 1-minute boundary.
- IMPROVEMENT: rem2html: Coalesce table.rem-cal CSS into one block. Thanks
to Ian! D. Allen for pointing this out.
- IMPROVEMENT: examples/defs.rem: Modernize the examples and get rid of some
cruft.
- CHANGE: Add $Latitude and $Longitude system variables. Deprecate
$LatDeg, $LatMin, $LatSec, $LongDeg, $LongMin and $LongSec.
- CHANGE: Test: Add "dump $" to test.rem.
* VERSION 3.3 Patch 10 - 2021-11-30
- IMPROVEMENT: TkRemind: Apply window and text colors to all GUI elements
including buttons and status labels.
- NEW FEATURE: The new ADDOMIT keyword can shorten reminder files.
The command:
REM ...whatever... ADDOMIT MSG Foo
behaves identically to:
REM ...whatever... SATISFY 1
IF trigvalid()
OMIT [trigdate()] MSG Foo
ENDIF
For example, Labour Day can be displayed and omitted as follows:
REM Mon 1 Sep SCANFROM -7 ADDOMIT MSG Labour Day
- UPDATE: Update contrib/remind-conf-mode to latest release
- CHANGE: The parser does not auto-convert numbers 90-99 to 1990-1999. This
was messing up things like "DURATION 90". It also means you can no longer
abbreviate the years 1990-1999 as 90-99.
- BUG FIX: Various documentation fixes
- BUG FIX: When switching users with the "-u" option, call initgroups()
to properly set group membership list.
* VERSION 3.3 Patch 9 - 2021-10-14
- NEW FEATURE: Add "-+username" option to tell Remind to trust files owned by
"username" and allow RUN directives in them. Idea courtesy of Ian! D. Allen
- NEW FEATURE: Add "-u+username" variant to tell Remind to switch users to
"username" without disabling RUN directives. Idea courtesy of Ian! D. Allen
- CHANGE: rem2html: rem2html has been moved out of the www/ directory into
its own rem2html/ directory. If your system has the prerequisites
(namely Perl, Getopt::Long and JSON::Any) then rem2html will be installed
by "make install".
- CHANGE: Remove "cm2rem". It was about 20 years obsolete.
- CHANGE: rem2html: Use inline data: URL images for moon images by default,
thus producing a completely stand-alone HTML file.
- CHANGE: Remove unnecessary spaces from "remind -pp" JSON output.
- DOCUMENTATION FIX: Various man page fixes and tweaks.
- BUG FIX: rem2html: Tweak the default CSS stylesheet; more rational
handling of rem2html command-line options.
- BUG FIX: remind: "remind -c" would sometimes highlight *two* days as
"today"; this has been fixed.
- BUG FIX: Add a missing #ifdef...#endif and remove a C99-ism. This once again
allows Remind to be compiled with some very old C compilers.
* VERSION 3.3 Patch 8 - 2021-09-13
- NEW FEATURE: remind: Add INCLUDECMD command
- NEW FEATURE: remind: Add shellescape() built-in function
- BUG FIX: tkremind: TkRemind would sometimes fill in incorrect initial
values for the reminder-editing form if you clicked on a TkRemind-created
reminder to edit it. This has been fixed.
- BUG FIX: tkremind: Get back better error messages from Remind if you
try to create a reminder with an invalid date specification.
- BUG FIX: remind: Catch integer overflow if we try to evaluate $IntMin * -1
- DOC UPDATES: remind: Minor man page fixes
* VERSION 3.3 Patch 7 - 2021-05-10
- MINOR FIX: Refuse to run "make test" as root --- it would fail
anyway with an obscure message.
- BUG FIX: Remind would sometimes compute incorrect trigger date for:
REM Tue 29 Feb MSG ...
- BUG FIX: Remind would sometimes compute incorrect trigger date for
a date spec like: Tue 31 2021 MSG ...
* VERSION 3.3 Patch 6 - 2021-03-30
- test/test.rem: Change local to en_US.utf-8 only if current locale
is not a UTF-8 locale.
- MINOR CHANGE: Remind's arithmetic operators (+, -, *, /) give errors
on overflow rather than silently giving the wrong answer.
- MINOR CHANGE: Add $IntMin and $IntMax system variables.
- DOCUMENTATION FIX: Document that TkRemind now requires Tcl/Tk version
8.5 or newer.
* VERSION 3.3 Patch 5 - 2021-01-21
- NEW FEATURE: tkremind: Add ability to change fonts and colors from
within TkRemind "Options" dialog.
- CHANGE: tkremind: TkRemind now requires Tcl/Tk 8.5 or newer.
- CHANGE: tkremind: You can specify the location of the options
file on the command-line if you want to use one other than ~/.tkremindrc
- CLEANUP: tkremind: Remove "Apply Options" from Options dialog; we only
need "Save Options".
- DOC FIX: Add missing release note in 3.3.4 notes regarding
setpagedevice patch
- DOC FIX: tkremind: Document shortcut keys.
* VERSION 3.3 Patch 4 - 2021-01-12
- NEW FEATURE: If "inotifywait" is installed, TkRemind uses it to refresh
the calendar display right away when the reminders file/directory is updated.
This makes TkRemind react almost instantly if external tools are editing
or updating reminders.
- MINOR NEW FEATURE: rem2ps has a new '-x' option; this puts the day numbers
on the top-left of the day's box instead of the top-right.
- MINOR FIXES: A typo in remind.1 was fixed; additional comments regarding
UNTIL were added.
- BUG FIX: rem2ps: Call setpagedevice to set page size. Based on a patch
from Jonathan Kamens.
* VERSION 3.3 Patch 3 - 2020-11-09
- BUG FIX: Fix startup crash in TkRemind if "Show Today's Reminders on
Startup" is enabled (which, unfortunately, is the default.) Bug reported
by Martin Ziemer.
* VERSION 3.3 Patch 2 - 2020-11-08
- MINOR NEW FEATURE: Add MAYBE-UNCOMPUTABLE keyword; see the man page
and discussion at
https://dianne.skoll.ca/pipermail/remind-fans/2020/003745.html
- CHANGE: TkRemind always invokes Remind with the "-itkremind=1" option,
even when printing. NOTE INCOMPATIBILITY: This is a behavior change!
When you print from TkRemind, we also invoke Remind with "-itkprint=1"
so you can detect that PostScript is being generated.
- CHANGE: The maximum length of a variable name has been increased from
16 characters to 64 characters. Modern computers have plenty of memory.
- BUG FIXES: Minor documentation updates, typo fixes, clarifications, etc.
- BUG FIX: Fix calendar-drawing alignment errors when displaying UTF-8
strings with zero-width combining characters and strings with tabs.
- BUG FIX: TkRemind would mess up placement of the WEEK special if invoked
with the "-m" option. This has been fixed.
- BUG FIX: TkRemind would sometimes fail with an error message when editing
a reminder; this is because it was interpreting months 08 and 09 as
illegal octal numbers. This has been fixed.
* VERSION 3.3 Patch 1 - 2020-03-20
- CHANGE: For overlapping multi-day events, issue a reminder for the
most *recent* event rather than the earliest event. NOTE
INCOMPATIBILITY: This is a behavior change!
- CHANGE: Do not convert 90-99 to 1990-1999 when parsing numbers to
recognize years. NOTE INCOMPATIBILITY: This is a behavior change!
- CHANGE: Revert change to -y option that included filename and line
number in the hash.
- CHANGE: Retain newlines (produced by %_) in JSON output.
- FIX: Document $FormWidth system variable
- FIX: Highlight today's date in "remind -c" output
- FIX: Eliminate compiler warnings on Ubuntu 18.04.
- IMPROVEMENT: Allow times to be specified either in 24-hour mode
(HH:MM or HH.MM) or AM/PM mode (HH:MMam; HH:MMpm, etc.)
- IMPROVEMENT: Allow DURATION to be specified as a time (1:30) or a
number of minutes (90).
- IMPROVEMENT: If terminal size can be determined, set $FormWidth to
terminal width - 8; if not, set $FormWidth to 72.
- MINOR IMPROVEMENT: Add the "ampm()" built-in function.
* Version 3.3 Patch 0 - 2020-01-31
- FIX: rem2ps: Add a %%PageBoundingBox: document structuring convention
comment.
- FIX: rem2ps: Ignore unknown SPECIAL-type reminders.
- IMPROVEMENT: In calendar mode ("-c" option), Remind automatically adjusts
the width of the calendar to fit the terminal window if standard output
is a TTY.
- IMPROVEMENT: Add JSON-based output with "remind -pp" and "remind -ppp"
The JSON-based intermediate format preserves a lot more information
about the original reminder, allowing back-ends more insight into
the intent of the reminder, the recurrence used, etc. See the documentation
in "man rem2ps"
- IMPROVEMENT: TkRemind can "reverse-engineer" reminders that it creates
using the additional information in the "remind -pp" format, so it
doesn't create or use ugly comment blocks to delimit the reminders
it creates.
- IMPROVEMENT: TkRemind: Add popup help to most buttons and controls.
- NEW FEATURE: Add support for $DefaultColor system variable, suggested
by Tim Chase.
- NEW FEATURE: The "-@[n][,m]" command-line option allows colored reminders
in Agenda Mode as well as in Calendar Mode. It also adds support for
terminal emulators that can handle the xterm 256-color escape sequences
as well as the true 24-bit color escape sequences.
- CHANGE: SPECIALs are now case-insensitive. Before, only SPECIAL COLOR
would work. Now you can use Special Color, special color, etc.
* Version 3.2 Patch 0 - 2020-01-03
- IMPROVEMENT: Add support for events spanning multiple days (with AT
and DURATION). Add trigeventstart() and trigeventduration()
introspection functions; see "MULTI-DAY EVENTS" in the man page.
- IMPROVEMENT: Add introspection functions trigback(), trigdelta(),
trigduration(), trigfrom(), trigpriority(), trigrep(),
trigscanfrom(), trigtimedelta(), trigtimerep(), and triguntil(). See
man page for details; thanks to Tim Chase for the suggestion.
- IMPROVEMENT: TkRemind: Use PNG images for the next month / previous
month buttons rather than -> and <-. Also use nice anti-aliased
moon phase images instead of ugly blocky bitmaps.
- CHANGE: Modify addition so that previously-illegal combinations
TIME + TIME, TIME + DATETIME and DATETIME + TIME are now allowed.
Also allow DATETIME - TIME. If t1 and t2 are expressions of type TIME
and dt is an expression of type DATETIME, then the following are now
equivalent (before, the expressions on the left-hand side would fail
with a "Type mismatch" error.)
t1 + t2 == t1 + coerce("INT", t2)
dt + t2 == dt + coerce("INT", t2)
t1 + dt == coerce("INT", t1) + dt
dt - t2 == dt - coerce("INT", t2)
- DOC FIX: Document previously-undocumented $MaxStringLen system variable
- DOC FIX: Various minor documentation fixes.
- BUG FIX: Specifying a DURATION without an AT clause results in an error.
Before, it would be accepted but not do anything useful.
- BUG FIX: Catch potential date overflow in slide() function
- BUG FIX: Fix compile error when compiling Romanian version; eliminate
compiler warning when compiling non-English versions.
- BUG FIX: TkRemind: Fix startup failure of TkRemind if options are at
default. :(
* Version 3.1 Patch 17 - 2019-11-15
- IMPROVEMENT: Add "Extra Remind Options" setting to TkRemind.
- IMPROVEMENT: Enable warning-free compilation even with gcc -Wextra flag.
- IMPROVEMENT: Warn if "OMIT a THROUGH b" has a > b.
- SYNTACTIC SUGAR: Make "SCANFROM -n" the same as "SCANFROM [today() - n]"
- BUG FIX: Don't dump expired reminders when dumping queue.
- BUG FIX: Fix failure when specifying a Jahrzeit in Adar. Fix
courtesy of Dov Feldstern
- BUG FIX: Fix various documentation errors and update man page.
* Version 3.1 Patch 16 - 2018-11-09
- IMPROVEMENT: Add patch from Stephen Morgan to calculate astronomical and
@@ -38,7 +386,7 @@ CHANGES TO REMIND
- BUG FIX: Make parser reject an AT followed by more than one time.
- BUG FIX: Make parser reject epeated delta or *repeat values.
- BUG FIX: Make parser reject repeated delta or *repeat values.
* Version 3.1 Patch 14 - 2015-04-24
@@ -229,7 +577,7 @@ CHANGES TO REMIND
* Version 3.1 Patch 4 - 2008-02-03
- ENHANCMENT: tkremind respects the "-b1" option and operates in 24-hour
- ENHANCEMENT: tkremind respects the "-b1" option and operates in 24-hour
clock mode if the option is supplied.
- ENHANCEMENT: tkremind has been tweaked to look better with Tcl/Tk 8.5.
@@ -368,7 +716,7 @@ CHANGES TO REMIND
- The SPECIAL COLOR reminder type has been hacked to behave more like
a MSG type. It sorts properly and is emitted as a normal reminder
in non-calendar mode. Simlarly, SPECIAL HTML sorts with -g as well.
in non-calendar mode. Similarly, SPECIAL HTML sorts with -g as well.
+ MINOR ENHANCEMENTS
@@ -1304,7 +1652,7 @@ CHANGES TO REMIND
- Improved debugging of reminder scripts
- Took out the "purge" option - it is in general too dificult to tell when
- Took out the "purge" option - it is in general too difficult to tell when
a reminder has expired for good, so now it's up to you to do this
by hand.

View File

@@ -14,7 +14,6 @@
# "#USHOLS" for U.S. holidays #
# "#JHOLS" for Jewish holidays #
# "#PSSTUFF" for nifty PostScript examples #
# "#COLORS" for examples of ANSI color escape sequences. #
# #
# This file is part of REMIND. #
# Copyright (C) 1992-2018 Dianne Skoll #
@@ -26,8 +25,8 @@ RUN OFF
################################################
# Ensure required version of remind is used... #
################################################
IF version() < "03.01.08"
ERRMSG This file requires at least version 03.01.08 of Remind.%
IF version() < "03.01.10"
ERRMSG This file requires at least version 03.01.10 of Remind.%
ERRMSG This version is version [version()].
EXIT
ENDIF
@@ -84,7 +83,6 @@ SET December 12
###########################################################
# Other symbolic constants and functions for "pasting"... #
###########################################################
SET Quote CHAR(34)
# Handy constants/function for specifing week of month...
@@ -94,30 +92,15 @@ SET Week_3 15
SET Week_4 22
FSET _last(mo) "1 " + MON((mo%12)+1) + " --7"
# Handy function to provide SCANFROM dates...
FSET _back(days) TODAY()-days
###########################################################
# Function which returns a string in "am/pm" format based #
# on the time. For example, set a am_pm(NOW())... #
###########################################################
FSET _am_pm(tm) IIF(tm<01:00, tm+12*60+"am", \
tm<12:00, tm+"am", \
tm<13:00, tm+"pm", \
tm-12*60+"pm")
#################################################################
# Function which removes a single leading zero from a string... #
# Function that removes a single leading zero from a string... #
#################################################################
FSET _no_lz(s) IIF(SUBSTR(s, 1, 1)=="0", SUBSTR(s, 2), s)
#################################################################
# Return the length of the daylight/night portion of a date, #
# in minutes. #
#################################################################
FSET _light_len(date) MAX(SUNSET(date)-SUNRISE(date), 0)
FSET _dark_len(date) 1440-_light_len(date)
@@ -125,26 +108,12 @@ FSET _dark_len(date) 1440-_light_len(date)
# Function to calculate number of years since a given year #
# or number of months since a given month and year... #
############################################################
FSET _yr_num(yr) ORD(YEAR(TRIGDATE()) - yr)
FSET _mo_num(mo, yr) ORD(12 * (YEAR(TRIGDATE()) - yr) + \
MONNUM(TRIGDATE()) - mo)
FSET _yr_num(yr) ORD($Ty - yr)
FSET _mo_num(mo, yr) ORD(12 * ($Ty - yr) + $Tm - mo)
# Here's an example of how to use them:
REM 1 Nov ++12 MSG %"Dean's [_yr_num(1984)] birthday%" is %b.
REM 1 MSG Dean's [_mo_num(11, 1984)] 'monthly' anniversary
###########################################################
# Function to send mail via elm's "fastmail" (by GMS!)... #
###########################################################
#FSET _mail(from, subj) "mailx -s " + \
# Quote + from + " : " + subj + Quote \
# GETENV("LOGNAME") + " < /dev/null 1>&0"
FSET _mail(from, subj) "fastmail -f " + \
Quote + from + Quote + \
" -s " + Quote + subj + Quote + \
" /dev/null " + GETENV("LOGNAME")
REM 1 Nov ++12 MSG %"John's [_yr_num(1984)] birthday%" is %b.
REM 1 MSG John's [_mo_num(11, 1984)] 'monthly' anniversary
#############################################################################
# Here's a tricky problem: The 4th of July is a holiday in the U.S.
@@ -158,29 +127,28 @@ FSET _mail(from, subj) "fastmail -f " + \
# dependent upon the current date, it's tricky and results may not be
# what you expect. You should try to make sure that the OMIT context
# "near" any current reminders will not change during a calendar run.
# The SCANFROM clause should help make these OMITs very safe.
# The SCANFROM clause will make these OMITs safe.
############################################################################
# Calculate the weekday of the holiday.
REM 4 July SCANFROM [_back(7)] SATISFY 1
REM 4 July SCANFROM -7 SATISFY 1
IF WKDAYNUM(TRIGDATE()) == Sat
REM [TRIGDATE()] MSG Independence day (actual)
OMIT [TRIGDATE()-1] MSG Independence day (observed)
SET iday $T
IF WKDAYNUM(iday) == Sat
REM [iday] MSG Independence day (actual)
OMIT [iday-1] MSG Independence day (observed)
ELSE
IF WKDAYNUM(TRIGDATE()) == Sun
REM [TRIGDATE()] MSG Independence day (actual)
OMIT [TRIGDATE()+1] MSG Independence day (observed)
IF WKDAYNUM(iday) == Sun
REM [iday] MSG Independence day (actual)
OMIT [iday+1] MSG Independence day (observed)
ELSE
OMIT [TRIGDATE()] MSG Independence day
OMIT [iday] MSG Independence day
ENDIF
ENDIF
############################################################################
# #
# A meeting on the first Monday of every month which is moved to the #
# second Monday in the event of a holiday. #
# #
############################################################################
# First, the normal meeting. However, the SKIP keyword means this
@@ -192,68 +160,21 @@ REM Mon 8 SATISFY 1
# But only actually trigger the delayed meeting if the previous
# Monday was a holiday
IF ISOMITTED(TRIGDATE()-7)
REM [TRIGDATE()] MSG Delayed meeting
IF ISOMITTED($T-7)
REM [$T] MSG Delayed meeting
ENDIF
############################################################################
# #
# A very complicated reminder sent in by a Remind user. #
# This person gets paid every two weeks, starting from 8 January 1993. #
# If a pay date occurs before the twelfth of a month, then that #
# he pays his mortgage on that pay date. Otherwise, he pays the mortgage #
# on the previous pay date. Furthermore, he has to schedule his #
# mortgage payment six days before it is due. He wants to be reminded #
# a further four days before the scheduling deadline. He also #
# wants to be mailed a notice two weeks before the scheduling deadline. #
# #
# Here's the solution - if you can follow this, consider yourself a #
# Remind programmer extraordinaire! #
# #
############################################################################
# A function to determine whether or not a pay-date is a mortgage-date.
FSET _IsMortDate(x) DAY(x) < 12 || (DAY(x+14) >= 12 && DAY(x+14) <= 14)
# Paydays - for reference
REM 8 Jan 1993 *14 MSG Payday
# Calculate the mortgage payment six days ahead of time. Note that this
# is done "implicitly" by subtracting 6 from the starting date - we start
# on 2 Jan rather than 8 Jan. We add 6 to TRIGDATE() in _IsMortDate to
# compensate.
REM 2 Jan 1993 *14 ++4 SATISFY [_IsMortDate(TRIGDATE()+6)] \
MSG %"Schedule mortgage payment%" for %a.
# Now the mail reminder two weeks before the payment date - because two
# weeks before a payment date is also a payment date, no pre-compensation
# in the starting date of 8 Jan is necessary - convince yourself of this!
# This uses the _mail() function defined earlier.
REM ONCE 8 Jan 1993 *14 SATISFY [_IsMortDate(TRIGDATE()+14)] \
RUN [_mail("Decatur Federal", \
"Pay mortgage by the " + ORD(DAY(TRIGDATE()+14)))]
# Make an entry on the calendar when the mortgage should be paid
REM 8 Jan 1993 *14 SATISFY [_IsMortDate(TRIGDATE())] \
CAL Mortgage payment
##########################################################################
# #
# On our UNIX system, I run a program which queries the university #
# On our UNIX system, I run a program that queries the university #
# library and creates a file called ".booksdue". This file is #
# a REMIND script to tell me when my library books are due. Here's #
# an example from my reminder file - it shows the use of filedate(). #
# When the .booksdue file is at least 7 days old, I create a new version #
# by querying the library computer. Note the use of realtoday() rather #
# than today. #
# than today(). #
# #
##########################################################################
IF !$RunOff && !$CalMode && !$SimpleCal
IF REALTODAY()-FILEDATE("/home/dfs/.booksdue") >= 7
REM RUN /home/dfs/bilge/library/getbooks
@@ -283,7 +204,7 @@ REM Sat Sun SPECIAL SHADE 220
#############################################################################
SET SaveTrig $NumTrig
SET easter EASTERDATE(YEAR(TODAY()))
SET easter EASTERDATE($Uy)
REM [easter-46] MSG %"Ash Wednesday%"
REM [easter-7] MSG %"Palm Sunday%"
OMIT [easter-2] MSG %"Good Friday%"
@@ -292,17 +213,15 @@ REM [easter+39] MSG %"Ascension Day%"
REM [easter+49] MSG %"Pentecost%"
# Some holidays are omitted, some are not. You may want to change
# which ones are omitted - use the general forms shown below.
# You'll need the _back() function and the Week_n variables defined
# way up in the file.
# which ones are omitted - use the general forms shown below. You'll
# need the Week_n variables defined way up in the file.
OMIT Jan 1 MSG %"New Year's%" Day
REM Mon Jan [Week_3] MSG Martin Luther King - %"MLK Day%"
REM Feb 2 MSG %"Ground Hog Day%"
REM Feb 14 MSG %"Valentine's%" Day
REM Mon Feb [Week_3] SCANFROM [_back(7)] SATISFY 1
OMIT [trigdate()] MSG %"President's Day%"
REM Mar 17 MSG %"St. Patrick's%" Day
OMIT Jan 1 MSG %"New Year's%" Day
REM Mon Jan [Week_3] MSG Martin Luther King - %"MLK Day%"
REM Feb 2 MSG %"Ground Hog Day%"
REM Feb 14 MSG %"Valentine's%" Day
REM Mon Feb [Week_3] SCANFROM -7 ADDOMIT MSG %"President's Day%"
REM Mar 17 MSG %"St. Patrick's%" Day
# The DST rules are accurate for most locations in
# North America
@@ -312,51 +231,37 @@ REM Sun Mar 8 ++2 FROM 1 Jan 2007 MSG Daylight Saving Time - %"DST starts%" %b
REM Sun [_last(Oct)] ++2 UNTIL 1 Jan 2007 MSG Daylight Saving Time - %"DST ends%" %b
REM Sun 1 Nov ++2 FROM 1 Jan 2007 MSG Daylight Saving Time - %"DST ends%" %b
REM Apr 1 MSG %"April Fool's%" Day
REM Mon Tue Wed Thu Fri Sat 15 Apr MSG %"Income tax%" due
REM May 5 MSG %"Cinco de Mayo%"
REM Sat May [Week_1] MSG %"Kentucky Derby%"
REM Sun May [Week_2] MSG %"Mother's Day%"
REM Sat May [Week_3] MSG %"Armed Forces Day%"
REM Mon [_last(May)] SCANFROM [_back(7)] SATISFY 1
OMIT [trigdate()] MSG %"Memorial Day%"
REM Jun 14 MSG %"Flag Day%"
REM Sun Jun [Week_3] MSG %"Father's Day%"
REM Mon Sep [Week_1] SCANFROM [_back(7)] SATISFY 1
OMIT [trigdate()] MSG %"Labor Day%"
REM Mon Oct [Week_2] MSG %"Columbus Day%"
REM Nov 11 MSG %"Veterans Day%"
REM Apr 1 MSG %"April Fool's%" Day
REM Mon Tue Wed Thu Fri Sat 15 Apr MSG %"Income tax%" due
REM May 5 MSG %"Cinco de Mayo%"
REM Sat May [Week_1] MSG %"Kentucky Derby%"
REM Sun May [Week_2] MSG %"Mother's Day%"
REM Sat May [Week_3] MSG %"Armed Forces Day%"
REM Mon [_last(May)] SCANFROM -7 ADDOMIT MSG %"Memorial Day%"
REM Jun 14 MSG %"Flag Day%"
REM Sun Jun [Week_3] MSG %"Father's Day%"
REM Mon Sep [Week_1] SCANFROM -7 ADDOMIT MSG %"Labor Day%"
REM Mon Oct [Week_2] MSG %"Columbus Day%"
REM Nov 11 MSG %"Veterans Day%"
REM Oct 30 MSG %"Mischief Night%"
REM Oct 31 MSG %"Halloween%"
REM Tue Nov 2 SCANFROM [_back(7)] \
SATISFY [(YEAR(TRIGDATE()) % 4) == 0] \
MSG %"Election%" Day
REM Thu Nov [Week_4] SCANFROM [_back(7)] SATISFY 1
OMIT [trigdate()] MSG %"Thanksgiving%" Day
REM Fri Nov [Week_4+1] SCANFROM [_back(7)] SATISFY 1
OMIT [trigdate()] MSG %"Thanksgiving%" (cont.)
OMIT Dec 24 MSG %"Christmas Eve%"
OMIT Dec 25 MSG %"Christmas%" Day
REM Oct 30 MSG %"Mischief Night%"
REM Oct 31 MSG %"Halloween%"
REM Tue Nov 2 SCANFROM -7 SATISFY [($Ty % 4) == 0] MSG %"Election Day%"
REM Thu Nov [Week_4] SCANFROM -7 ADDOMIT MSG %"Thanksgiving Day%"
REM Fri Nov [Week_4+1] SCANFROM -7 ADDOMIT MSG %"Thanksgiving (cont.)%"
OMIT Dec 24 MSG %"Christmas Eve%"
OMIT Dec 25 MSG %"Christmas%" Day
##########################################################################
# #
# If any US holidays were triggered above, shade in the calendar #
# entry in PostScript. This is not quite correct, as it blots out any #
# other PostScript stuff above. I was too lazy to do it properly :-) #
# entry in PostScript. #
# #
##########################################################################
if $NumTrig > SaveTrig
REM SPECIAL SHADE 220
endif
# Seasons (valid from 1992 to 2000)...
REM Mar 20 MSG %"Spring%" begins
REM Jun [IIF(YEAR(TODAY())%4, 21, 20)] MSG %"Summer%" begins
REM Sep [CHOOSE(YEAR(TODAY())-1991, 22,22,23,23,22,22,22,23,22)] \
MSG %"Fall%" begins
REM Dec [IIF((YEAR(TODAY())+1)%4, 21, 22)] MSG %"Winter%" begins
#PSSTUFF2
##########################################################################
# #
@@ -370,7 +275,7 @@ REM Dec [IIF((YEAR(TODAY())+1)%4, 21, 22)] MSG %"Winter%" begins
# example, I recommend that you use the -sd 10 option for Rem2PS.
REM PS Border Border moveto \
/DayFont findfont DaySize scalefont setfont \
([hebday(today())] [hebmon(today())]) show
([hebday($U)] [hebmon($U)]) show
# Fill in the phases of the moon on the PostScript calendar
[moondate(0)] SPECIAL MOON 0
@@ -382,7 +287,7 @@ REM PS Border Border moveto \
# calendar - the sizes are hard-coded, however, and work best in landscape.
REM PS Border Border 5 sub moveto \
/SmallFont findfont 4 scalefont setfont \
(Sunrise: [sunrise(trigdate())] Sunset: [sunset(trigdate())]) show
(Sunrise: [sunrise($T)] Sunset: [sunset($T)]) show
# The next one puts the day number (1-366) and days left in the year at the
# bottom of the post-script calendar. Again, the hard-coded sizes work best
@@ -390,7 +295,7 @@ REM PS Border Border 5 sub moveto \
FSET _DayOfYear(x) x-(date(year(x),1,1) - 1)
REM PS BoxWidth 3 mul 4 div Border 5 sub moveto \
/SmallFont findfont 4 scalefont setfont \
([_DayOfYear(today())]([365+isleap(today())-_DayOfYear(today())])) show
([_DayOfYear($U)]([365+isleap($U)-_DayOfYear($U)])) show
#JHOLS
##########################################################################
@@ -430,7 +335,7 @@ SET Reform 0
# Convenient function definition to save typing
FSET _h(x, y) HEBDATE(x,y)
FSET _h2(x, y) HEBDATE(x, y, TODAY()-7)
FSET _h2(x, y) HEBDATE(x, y, $U-7)
FSET _PastSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)+1)
FSET _PastSun(x, y) IIF(WKDAYNUM(_h2(x,y))!=0, _h2(x,y), _h2(x,y)+1)
FSET _PastMon(x, y) IIF(WKDAYNUM(_h2(x,y))!=1, _h2(x,y), _h2(x,y)+1)
@@ -464,7 +369,7 @@ ELSE
ENDIF
# Because Kislev can change length, we must be more careful about Chanukah
FSET _chan(x) HEBDATE(24, "Kislev", today()-9)+x
FSET _chan(x) HEBDATE(24, "Kislev", $U-9)+x
[_chan(1)] ++4 MSG %"Chanukah 1%" is %b.
[_chan(2)] MSG %"Chanukah 2%"
[_chan(3)] MSG %"Chanukah 3%"
@@ -553,9 +458,9 @@ ENDIF
# Counting the omer - do the whole spiel, i.e:
# "This is the xth day of the omer, being y weeks and z days of the omer."
# Nice Remind programming example here!
SET ostart HEBDATE(16, "Nisan", TODAY()-50)
IF ostart <= TODAY() && (TODAY() - ostart < 49)
SET odays TODAY()-ostart+1
SET ostart HEBDATE(16, "Nisan", $U-50)
IF ostart <= $U && ($U - ostart < 49)
SET odays $U-ostart+1
IF odays < 7
MSG %"%"Today is the [ORD(odays)] day of the Omer.
ELSE
@@ -573,52 +478,14 @@ ENDIF
### for Friday and Saturday. Note: You must set your latitude, longitude
### and possibly time zone for these to work properly!
REM Friday CAL Candle lighting at [sunset(trigdate())-18]
REM Saturday CAL Havdalah at [sunset(trigdate())+42]
REM Friday CAL Candle lighting at [sunset($T)-18]
REM Saturday CAL Havdalah at [sunset($T)+42]
#COLORS
##########################################################################
# #
# This contains sample ANSI escape sequences for coloring messages. #
# It should work on an IBM PC with the ANSI.SYS driver, and on #
# other terminals which use the ANSI sequences. #
# #
# This information was provided by Gail Gurman.
# #
##########################################################################
# Colors - use Nrm to reset to normal text.
SET Esc CHAR(27)
SET Nrm Esc + "[0m"
SET Blk Esc + "[0;30m"
SET Red Esc + "[0;31m"
SET Grn Esc + "[0;32m"
SET Ylw Esc + "[0;33m"
SET Blu Esc + "[0;34m"
SET Mag Esc + "[0;35m"
SET Cyn Esc + "[0;36m"
SET Wht Esc + "[0;37m"
SET Gry Esc + "[30;1m"
SET BrRed Esc + "[31;1m"
SET BrGrn Esc + "[32;1m"
SET BrYlw Esc + "[33;1m"
SET BrBlu Esc + "[34;1m"
SET BrMag Esc + "[35;1m"
SET BrCyn Esc + "[36;1m"
SET BrWht Esc + "[37;1m"
# Examples
REM MSG A [Blu]blue[Nrm] reminder.
REM MSG [Red]%"A red reminder%" safe to use in the calendar mode.[Nrm]
# Here is an example of how to use msgprefix() and msgsuffix(). These
# will highlight priority-0 reminders in bright red,
# priority-2500 in red, and priority-7500 in blue. All others
# will be in the normal colors
FSET msgprefix(x) iif(x==0, BrRed, x==2500, Red, x==7500, Blu, Nrm)
# Don't forget to return to normal color set at the end of reminder!
FSET msgsuffix(x) Nrm
REM 1 SPECIAL COLOR 0 0 255 A blue reminder.
REM 2 SPECIAL COLOR 255 0 0 %"A red reminder%" safe to use in the calendar mode.
# The next examples are great for putting right at the end of the reminder
# file. They make queued reminders more eye-catching when they pop up.

View File

@@ -1,25 +0,0 @@
.TH CM2REM 1 "18 October 1999"
.UC 4
.SH NAME
cm2rem.tcl \- Convert Sun's "cm" input file to Remind format
.SH SYNOPSIS
.B cm2rem.tcl < cm_file > remind_file
.SH DESCRIPTION
\fBcm2rem.tcl\fR reads the Sun calendar manager data file and converts
it into a \fBRemind\fR script. Note that \fBcm2rem.tcl\fR can convert
\fIonly\fR version 3 calendar manager files. If you are using version 4
files, there should be a system utility to convert them to version 3 files.
.SH AUTHOR
\fBcm2rem.tcl\fR was written by Dianne Skoll <dianne@skoll.ca>.
.SH BUGS
Not all of the Sun calendar manager options are respected. In particular,
nothing is done for e-mail actions. Also, the resulting Remind script
is not editable with \fBTkRemind\fR; you can only edit it with a text
editor.
.PP
\fBcm2rem.tcl\fR requires Tcl/Tk version 8.0 or higher. The
\fBtclsh\fR interpreter must be on your \fBpath\fR.
.SH SEE ALSO
\fBremind(1)\fR, \fBtkremind(1)\fR

View File

@@ -1,4 +1,4 @@
.TH REM 1 "30 August 2007"
.TH REM 1 "1 January 2021"
.UC 4
.SH NAME
rem \- Invoke Remind with a default filename

View File

@@ -1,13 +1,13 @@
.TH REM2PS 1 "11 April 2005"
.TH REM2PS 1 "5 January 2021"
.UC 4
.SH NAME
rem2ps \- draw a PostScript calendar from Remind output
.SH SYNOPSIS
.B rem2ps [\fIoptions\fR]
.SH DESCRIPTION
\fBRem2ps\fR reads the standard input, which should be the results of running
\fBRemind\fR with the \fB\-p\fR option. It emits PostScript code (which
draws a calendar) to the standard output.
\fBRem2ps\fR reads the standard input, which should be the results of
running \fBRemind\fR with the \fB\-p\fR or \fB\-pp\fR option. It
emits PostScript code (which draws a calendar) to the standard output.
.PP
See the section "Rem2PS Input Format" for details about the \fB\-p\fR
data. This may be useful if you wish to create other \fBRemind\fR
@@ -29,6 +29,11 @@ include any document structuring comments in your prologue.
Produce the calendar in landscape mode rather than the default
portrait mode.
.TP
.B \-x
When printing the calendar, place the day numbers in the top-left of each
day's box. If this option is omitted, the day numbers appear in the
top-right.
.TP
\fB\-c\fR[\fIn\fR]
If \fIn\fR is omitted, disables the small calendars for next and previous
months which are normally generated. If \fIn\fR is supplied, it can range
@@ -267,7 +272,7 @@ hold:
.TP
o
The PostScript origin is at the bottom left-hand corner of the page, and
PostScript units of 1/72" are in effect.
PostScript units of 1/72 inch are in effect.
.TP
o
The variables MinX, MinY, MaxX and MaxY define the bounding box within
@@ -313,7 +318,13 @@ Use that file with the \fBRem2ps\fR \fB\-p\fR option to create calendars
with the year and month in large grey letters in the background of the
calendar.
.PP
.SH REM2PS INPUT FORMAT
.SH REM2PS INPUT FORMAT (-P OPTION)
The \fB\-p\fR option is an older, simpler interchange format used by
\fBRemind\fR to communicate with back-ends. New back-ends are
encoraged to support the new \fB\-pp\fR format preferably, though they
are encouraged to support the older \fB\-p\fR format as well if the
older format contains enough information for them to work properly.
.PP
\fBRemind \-p\fR sends the following lines to standard output.
The information is designed to be easily parsed by back-end programs:
.TP
@@ -375,6 +386,9 @@ was provided.
.PP
\fIbody\fR is the body of the reminder.
.PP
Future versions of \fBRemind\fR may add additional keys to the JSON
object. Back-ends \fImust\fR ignore keys they don't recognize.
.PP
After a month's worth of reminders have been emitted, \fBRemind\fR
emits the line:
.PP
@@ -393,6 +407,247 @@ the line number and file name of the file containing the reminder. Back-ends
that don't care about this information should ignore lines starting with
"#" (except, of course, for the # rem2ps lines.)
.PP
.SH REM2PS PARTIAL JSON INPUT FORMAT (-PP OPTION)
\fBRemind \-pp\fR sends the following lines to standard output. They
are designed to be easily parsed, but contain much more information
than the old-style \fBremind -p\fR output. The extra information
contains a representation of the parsed "REM" statement, which could
allow converters to better preserve semantics of a reminder. For
example, this format passes enough information to allow a back-end to
(in many cases) determine a reminder's recurrence rather than just treating
each reminder as a one-off event.
.PP
The lines emitted by \fBremind \-pp\fR are as follows:
.TP
.B # rem2ps2 begin
This line signifies the start of calendar data. Back-ends can search
for it to verify they are being fed correct information. Note the
"2" after "rem2ps", which distinguishes this format from the older \fB\-p\fR
format.
.TP
\fImonth_name year num_days first_day monday_first\fR
Same as the \fB\-p\fR format
.TP
\fIsun mon tue wed thu fri sat\fR
Same as the \fB\-p\fR format
.TP
\fInext_mon next_days\fR
Same as the \fB\-p\fR format
.TP
\fIprev_mon prev_days\fR
Same as the \fB\-p\fR format
.PP
.B CALENDAR ENTRIES
.PP
The remaining data consists of calendar entries expressed as a JSON object
on a single line. Each such line will begin with "{" and will be a well-formed
JSON object. The keys that may be present in the JSON object are as
follows:
.TP
.B date \fIYYYY-MM-DD\fR
The \fbdate\fR key will \fIalways\fR be present; it is the trigger date
of the reminder expressed as a string in the format \fIYYYY-MM-DD\fR
.TP
.B filename \fIf\fR
The filename in which the reminder was found.
.TP
.B lineno \fIn\fR
The line number within the file on which the reminder was found.
.TP
.B nonconst_expr 1
If the reminder contained a non-constant expression that had to be evaluated
to determine the trigger date, this key will be present with the value 1.
If this key is present, then it is unsafe for a back-end to rely on
recurrence semantics or even the semantics of any part of the parsed
reminder, as they may have been computed in a way that cannot be expressed
in JSON.
.TP
.B if_depth \fIn\fR
If the reminder is inside one or more IF or ELSE statements, this key
will be present and the value will be the number of nested IFs from
the top-level to the reminder. Back-ends should be wary of
interpreting recurrence semantics of reminders within an IF or ELSE
block.
.TP
.B passthru \fIspecial\fR
If the reminder was a SPECIAL reminder, the \fBpassthru\fR key will be
present and the value will be the type of SPECIAL (such as SHADE, COLOR,
MOON, etc.)
.TP
.B tags \fIdata\fR
If any TAG clauses are present, the \fBtags\fR key will be present and consist
of a comma-separated list of tags.
.TP
.B time \fIt\fR
If an AT clause was present, this key will contain the time of the AT clause
in minutes after midnight.
.TP
.B tdelta \fIn\fR
If a time delta (+n after an AT clause) was present, this key contains the
delta value in minutes.
.TP
.B trep \fIn\fR
If a time repeat (*n after an AT clause) was present, this key contains the
repeat value in minutes.
.TP
.B eventduration \fIn\fR
If a DURATION clause was present, this key contains the event duration in
minutes.
.TP
.B duration \fIn\fR
If a DURATION clause was present, this key contains today's duration in
minutes. See the \fBremind(1)\fR man page, "MULTI-DAY EVENTS", for a
discussion of duration vs. event duration.
.TP
.B eventstart \fIdt\fR
If an AT clause was present, this key contains the event start time in
the format \fIYYYY-MM-DDTHH:MM\fR.
.TP
.B back \fIn\fR
If the reminder contained a "back" clause (\-n or \-\-n), this key
contains the back value. If the "back" value was \-n, the value will
be positive; if it was \-\-n, the value will be negative.
.TP
.B delta \fIn\fR
If the reminder contained a "delta" clause (\+n or \+\+n), this key
contains the delta value. If the "delta" value was \+n, the value will
be positive; if it was \+\+n, the value will be negative.
.TP
.B rep \fIn\fR
If the reminder contained a "repeat" clause (*n), this key contains
the repeat value.
.TP
.B skip \fItype\fR
If the reminder contained a SKIP, BEFORE or AFTER keyword, then this
key will contain that keyword.
.TP
.B localomit \fIarray\fR
If the reminder contains a local OMIT keyword, this key will be present.
Its value will be an array of English day names that are OMITted.
.TP
.B wd \fIarray\fR
If the reminder contains one or more weekdays, this key will be present.
Its value will be an array of English day names that are present.
.TP
.B d \fIn\fR
If a day-of-month is present in the reminder specification, this key
will be present and its value will be the day number.
.TP
.B m \fIn\fR
If a month is present in the reminder specification, this key
will be present and its value will be the month number.
.TP
.B y \fIn\fR
If a year is present in the reminder specification, this key
will be present and its value will be the year.
.TP
.B until \fIYYYY-MM-DD\fR
If the reminder contains an UNTIL or THROUGH clause, this key
will be present. Its value will be a string of the form YYYY-MM-DD.
.TP
.B once 1
If the reminder contains a ONCE keyword, this key will be present
with a value of 1.
.TP
.B scanfrom \fIYYYY-MM-DD\fR
If the reminder contains a SCANFROM keyword, this key will be present
and its value will be a string of the form YYYY-MM-DD.
.TP
.B from \fIYYYY-MM-DD\fR
If the reminder contains a FROM keyword, this key will be present
and its value will be a string of the form YYYY-MM-DD.
.TP
.B priority \fIn\fR
The priority of the reminder. Always present; if no PRIORITY keyword
is specified, then a reminder has a default priority of 5000.
.TP
.B r \fIn\fR
For a SHADE or COLOR special, the red color component.
.TP
.B g \fIn\fR
For a SHADE or COLOR special, the green color component.
.TP
.B b \fIn\fR
For a SHADE or COLOR special, the blue color component.
.TP
.B body \fIbody\fR
The body of the reminder to issue. Always present.
.TP
.B rawbody \fIraw\fR
The "raw" body of the reminder, before any expression-pasting or
substitution-sequence processing. If the raw body would be the same
as the processed body, then this key is not present.
.PP
After a month's worth of reminders have been emitted, \fBRemind\fR
emits the line:
.PP
\fB# rem2ps2 end
.PP
However, back-ends should keep reading until EOF in case more data for
subsequent months is forthcoming.
.PP
.SH REM2PS PURE JSON INPUT FORMAT (-PPP OPTION)
\fBRemind \-ppp\fR emits \fIpure JSON\fR output. The format is
as follows:
.PP
\fBRemind\fR outputs a JSON array. Each element of the array is a
\fImonth descriptor\fR.
.PP
Each month descriptor is a JSON object with the following elements:
.TP
.B monthname \fIname\fR
The name of the month.
.TP
.B year \fIyyyy\fR
The year.
.TP
.B daysinmonnth \fIn\fR
The number of days in the current month.
.TP
.B firstwkday \fIn\fR
The weekday of the first day of the month (0 = Sunday, 1 = Monday, 6 = Saturday).
.TP
.B mondayfirst \fIn\fR
An indicator of whether or not the calendar week should start with
Sunday (n=0) or Monday (n=1).
.TP
.B daynames \fR[\fIdays\fR]
A seven-element array of day names; each element is a string representing
the names of the days from Sunday through Saturday.
.TP
.B prevmonthname \fIname\fR
The name of the previous month.
.TP
.B daysinprevmonth \fIn\fR
The number of days in the previous month.
.TP
.B prevmonthyear \fIyyyy\fR
The year of the previous month. (The same as \fByear\fR unless the current
month is January.)
.TP
.B nextmonthname \fIname\fR
The name of the following month.
.TP
.B daysinnextmonth \fIn\fR
The number of days in the following month.
.TP
.B nextmonthyear \fIyyyy\fR
The year of the following month. (The same as \fByear\fR unless the
current month is December.)
.TP
.B entries \fR[\fIarray\fR]
The \fBentries\fR key consists of an array of calendar entries; each
entry is a JSON object that has the same format as described in the
\fBCALENDAR ENTRIES\fR section in the \fB\-PP FORMAT\fR section,
\fIwith the following difference\fR: In \fB\-PP\fR mode, if a reminder
has \fB%"\fR markers, only the text between the markers
is included in the \fBbody\fR element. In \fB\-PPP\fR mode, the
entire text \fIincluding\fR the \fB%"\fR markers is included and it's up to
the back-end to extract the portion between the markers if that
is desired.
.SH AUTHOR
Rem2PS was written by Dianne Skoll <dianne@skoll.ca>
.SH BUGS

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
.TH TKREMIND 1 "15 February 1998"
.TH TKREMIND 1 "15 January 2021"
.UC 4
.SH NAME
tkremind \- graphical front-end to Remind calendar program
.SH SYNOPSIS
.B tkremind \fR[\fIoptions\fR] [\fIread_file\fR] [\fIwrite_file\fR]
.B tkremind \fR[\fIoptions\fR] [\fIread_file\fR] [\fIwrite_file\fR] [\fIconfig_file\fR]
.SH DESCRIPTION
\fBTkRemind\fR is a graphical front-end to the \fBRemind\fR program.
It provides a friendly graphical interface which allows you to view
@@ -13,8 +13,10 @@ Although not all of \fBRemind\fR's features are available with \fBTkRemind\fR,
it creates. This allows you to learn \fBRemind\fR's syntax and then add
extra features as you become a more sophisticated \fBRemind\fR programmer.
\fBTkRemind\fR is written in Tcl, and requires version 8.0
(or higher). It also requires a \fBwish\fR binary.
\fBTkRemind\fR is written in Tcl, and requires version 8.5 (or higher)
as well as the tcllib extension. It also requires a \fBwish\fR
binary. If you are using Tcl/Tk 8.5, you may also need either the Img
or the tkpng extension to handle PNG images.
.SH OPTIONS
\fBTkRemind\fR itself has no options. However, it passes certain options
@@ -41,6 +43,9 @@ include the line:
.fi
.PP
\fIConfig_file\fR is the file in which \fBTkRemind\fR stores
its options. If it is omitted, it defaults to \fI$HOME/.tkremindrt\fR.
.SH THE CALENDAR WINDOW
When you start \fBTkRemind\fR, it displays a calendar for the current
month, with today's date highlighted. Reminders are filled into each
@@ -51,11 +56,14 @@ notice that the box appears completely full.
.SH NAVIGATING
To change to the previous or next month, click the \fB<\-\fR
or \fB\->\fR button, respectively. To change back to
the current month, click \fBToday\fR. To go to a specific month,
click \fBGo To Date...\fR. This pops up a dialog box which allows you
to select a month and enter a year. Once you've done this, click
\fBGo\fR to go to the date, or \fBCancel\fR to cancel.
or \fB\->\fR button, respectively. You can also use the left/right arrow
keys or PageUp/PageDown to navigate.
To change back to the current month, click \fBToday\fR or press the
Home key. To go to a specific month, click \fBGo To Date...\fR. This
pops up a dialog box which allows you to select a month and enter a
year. Once you've done this, click \fBGo\fR to go to the date, or
\fBCancel\fR to cancel.
To exit \fBTkRemind\fR, click \fBQuit\fR.
@@ -104,7 +112,7 @@ edit the reminder, thereby gaining access to advanced features of
\fBRemind\fR's idioms for expressing different types of reminders.
.SH PRINTING
To print the current month's calender, click \fBPrint...\fR on the
To print the current month's calendar, click \fBPrint...\fR on the
main calendar window. This brings up the print dialog. Printing
either produces a PostScript file or sends PostScript to a UNIX command.
@@ -125,10 +133,11 @@ Select the appropriate paper size and orientation. Activate
be the normal case unless you have many reminders in a particular
day. (See the \fBRem2PS\fR documentation.)
Finally, click \fBPrint\fR to print or \fBCancel\fR to cancel.
Note that during printing, \fBRemind\fR is \fInot\fR called with
the \fB-itkremind=1\fR option, because it is operated in normal
PostScript-producing mode.
Finally, click \fBPrint\fR to print or \fBCancel\fR to cancel. Note
that during printing, \fBRemind\fR is called with the
\fB-itkremind=1\fR option and also an additional \fB-itkprint=1\fR
option.
.SH EDITING REMINDERS
@@ -155,7 +164,11 @@ it with \fBTkRemind\fR.
If you have set the "text editor" option correctly, right-clicking
on a reminder will bring up a text editor on the file containing
the reminder. The cursor will be positioned on the line that
generated the reminder.
generated the reminder. In addition, if you have a reminder that
is editable with an editor but was not created using \fBTkRemind\fR,
it will be underlined when you move the cursor over it, and
you can edit it in a text editor by either left- or right-clicking
on the reminder.
.SH BACKGROUND REMINDERS
@@ -210,7 +223,8 @@ background reminder pops up.
.TP
.B Feed popped-up reminder to command's standard input
If selected, feeds the text of the reminder to the command described
above.
above. The text of the reminder is prefixed by "HH:MM ", where HH:MM
is the time of the reminder.
.TP
.B E-mail reminders here if popup not dismissed
@@ -231,6 +245,22 @@ The characters "%d" are replaced with the lined number of the file
containing the reminder, and "%s" are replaced with the file name.
Useful strings might be "emacs +%d %s" or "gvim +%d %s"
.TP
.B Extra Argument for Remind
This specifies any extra arguments that should be passed to Remind
when \BTkRemind\fR invokes \fBremind\fR. Unless you know what
you are doing, leave this blank.
.TP
.B Change entry font...
This button pops up a font selection dialog that lets you change the
font used to draw calendar items in the calendar boxes.
.TP
.B Change heading font...
Similar to Change entry font, but applies to calendar heading
(the month and day names and the day numbers.)
.PP
Once you've configured the options the way you like them,
press \fBApply Options\fR to put them into effect, \fBSave Options\fR
@@ -360,7 +390,7 @@ This line is emitted in response to a \fBSTATUS\fR command. The number
.SH AUTHOR
TkRemind was written by Dianne Skoll <dianne@skoll.ca>
\fBTkRemind\fR is Copyright 1996-2018 by Dianne Skoll.
\fBTkRemind\fR is Copyright 1996-2020 by Dianne Skoll.
.SH FILES

29
rem2html/Makefile.in Normal file
View File

@@ -0,0 +1,29 @@
# Set by configure - don't touch.
srcdir=@srcdir@
prefix=@prefix@
exec_prefix=@exec_prefix@
mandir=@mandir@
bindir=@bindir@
datadir=@datadir@
datarootdir=@datarootdir@
PERL=@PERL@
PERLMODS_NEEDED=JSON::Any Getopt::Long
all:
true
install:
@if test "$(PERL)" = "" ; then \
echo "Not installing rem2html; Perl is required"; exit 0; fi; \
for m in $(PERLMODS_NEEDED) ; \
do \
$(PERL) -M$$m -e 1 > /dev/null 2>&1; \
if test $$? != 0 ; then echo "Not installing rem2html; missing $$m"; exit 0; fi; \
done; \
echo "Installing rem2html in $(DESTDIR)$(bindir)"; \
mkdir -p $(DESTDIR)$(bindir) && sed -e 's|^#!perl|#!$(PERL)|' < rem2html > $(DESTDIR)$(bindir)/rem2html && chmod 755 $(DESTDIR)$(bindir)/rem2html && exit 0; \
exit 1;

12
rem2html/README.rem2html Normal file
View File

@@ -0,0 +1,12 @@
REM2HTML
--------
rem2html is a Perl script that transforms the output of `remind -pp
...' to HTML. Type `perl rem2html --help' for usage information.
rem2html requires the Perl modules `JSON::Any' and `Getopt::Long'. It
will not be installed unless you have those modules as well as Perl
itself.
--
Dianne Skoll

View File

@@ -1,13 +1,14 @@
#!/usr/bin/perl
#!perl
use strict;
use warnings;
use Getopt::Long;
use JSON::Any;
my %Options;
my $rem2html_version = '2.0';
my $rem2html_version = '2.1';
my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mondayfirst, $weeks,
@Daynames, $Nextmon, $Nextlen, $Prevmon, $Prevlen);
@@ -15,15 +16,20 @@ my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mond
my $TIDY_PROGNAME = $0;
$TIDY_PROGNAME =~ s|^.*/||;
# rem2html -- convert the output of "remind -p" to HTML
# rem2html -- convert the output of "remind -pp" to HTML
=head1 NAME
rem2html - Convert the output of "remind -p" to HTML
rem2html - Convert the output of "remind -pp" to HTML
=head1 SYNOPSIS
remind -p ... | rem2html [options]
remind -pp ... | rem2html [options]
You can also use the old interchange format as below, but the -pp
version is preferred.
remind -p ... | rem2html [options]
=head1 OPTIONS
@@ -49,13 +55,21 @@ month name a link to I<url>.
=item --imgbase I<url>
When creating URLs for images and the stylesheet, use
I<url> as the base URL.
When creating URLs for the stylesheet or external images, use I<url>
as the base URL.
=item --pngs
Normally, rem2html uses inline "data:" URLs for the moon phase images,
yielding a standalone HTML file. The C<--pngs> option makes it use
external images named firstquarter.png, fullmoon.png, lastquarter.png
and newmoon.png, which are expected to live in C<--imgbase>.
=item --stylesheet I<url.css>
Use I<url.css> as the stylesheet. If this option is used,
I<url.css> is I<not> interpreted relative to B<imgbase>.
I<url.css> is interpreted relative to B<imgbase> I<unless> it start
with a "/".
=item --nostyle
@@ -96,9 +110,9 @@ sub usage
$exit_status = 1;
}
print STDERR <<"EOM";
$TIDY_PROGNAME: Produce an HTML calendar from the output of "remind -p"
$TIDY_PROGNAME: Produce an HTML calendar from the output of "remind -pp"
Usage: remind -p ... | rem2html [options]
Usage: remind -pp ... | rem2html [options]
Options:
@@ -109,6 +123,8 @@ Options:
entry a link to <url>
--forwurl url Same as --backurl, but for the next month's small calendar
--imgbase url Base URL of images and default stylesheet file
--pngs Use external .PNG images for moon phases rater than
inline data: URLs
--stylesheet url.css URL of CSS stylesheet. If specified, imgbase is NOT
prepended to url.css
--nostyle Produce basic HTML that does not use a CSS stylesheet
@@ -120,11 +136,31 @@ EOM
exit($exit_status);
}
sub smoosh
{
my ($first, $second) = @_;
return $second unless defined ($first);
return $second if $first eq '';
return $second if ($second =~ m|^/|); # Absolute path given for second
# Squash multiple slashes
$first =~ s|/+|/|g;
# Special case
return "/$second" if ($first eq '/');
# Delete trailing slash
$first =~ s|/$||;
return "$first/$second";
}
sub parse_options
{
local $SIG{__WARN__} = sub { print STDERR "$TIDY_PROGNAME: $_[0]\n"; };
if (!GetOptions(\%Options, "help|h",
"man",
"pngs",
"version",
"stylesheet=s",
"nostyle",
@@ -137,45 +173,40 @@ sub parse_options
"tableonly")) {
usage(1);
}
$Options{'title'} ||= 'HTML Calendar';
$Options{title} ||= 'HTML Calendar';
# Fix up imgbase
my $imgbase = '%IMAGEBASE%';
if ($imgbase ne '%' . 'IMAGEBASE' . '%') {
$Options{'imgbase'} ||= $imgbase;
} else {
$Options{'imgbase'} ||= '';
my $stylesheet = $Options{stylesheet};
if ($stylesheet) {
$Options{stylesheet} = smoosh($Options{imgbase}, $stylesheet);
}
$Options{'imgbase'} =~ s|/+$||;
my $stylesheet = $Options{'imgbase'};
$stylesheet .= '/' if ($stylesheet ne '');
$stylesheet .= 'rem-default.css';
$Options{'stylesheet'} ||= $stylesheet;
}
sub start_output
{
return if ($Options{'tableonly'});
return if ($Options{tableonly});
print("<html>\n<head>\n<title>" . $Options{'title'} . "</title>\n");
if (!$Options{'nostyle'}) {
if ($Options{'stylesheet'}) {
print('<link rel="stylesheet" type="text/css" href="' .
$Options{'stylesheet'} . '">' . "\n");
}
print("<html>\n<head>\n<title>" . $Options{title} . "</title>\n");
if (!$Options{nostyle}) {
if ($Options{stylesheet}) {
print('<link rel="stylesheet" type="text/css" href="' .
$Options{stylesheet} . '">' . "\n");
} else {
print("<style>\n");
print default_stylesheet();
print("</style>\n");
}
}
print("</head>\n<body>\n");
if ($Options{'prologue'}) {
print $Options{'prologue'} . "\n";
if ($Options{prologue}) {
print $Options{prologue} . "\n";
}
}
sub end_output
{
return if ($Options{'tableonly'});
if ($Options{'epilogue'}) {
print $Options{'epilogue'} . "\n";
return if ($Options{tableonly});
if ($Options{epilogue}) {
print $Options{epilogue} . "\n";
}
print("</body>\n</html>\n");
}
@@ -191,7 +222,7 @@ sub parse_input
my $found_data = 0;
while(<STDIN>) {
chomp;
last if /^\# rem2ps begin$/;
last if /^\# rem2ps2? begin$/;
}
my $line;
@@ -221,20 +252,36 @@ sub parse_input
$found_data = 1;
my $class;
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
$class = '';
} else {
$class = ' class="rem-entry"';
}
while(<STDIN>) {
chomp;
last if /^\# rem2ps end$/;
last if /^\# rem2ps2? end$/;
next if /^\#/;
next unless m/^(\d*).(\d*).(\d*)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/;
my ($y, $m, $d, $special, $tag, $duration, $time, $body) =
($1, $2, $3, $4, $5, $6, $7, $8);
my ($y, $m, $d, $special, $tag, $duration, $time, $body);
if (m/^(\d*).(\d*).(\d*)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/) {
($y, $m, $d, $special, $tag, $duration, $time, $body) =
($1, $2, $3, $4, $5, $6, $7, $8);
} elsif (/\{/) {
my $obj = JSON::Any->jsonToObj($_);
next unless ($obj->{date} =~ /^(\d+)-(\d+)-(\d+)$/);
$y = $1;
$m = $2;
$d = $3;
$special = $obj->{passthru} || '*';
$tag = $obj->{tags} || '*';
$duration = $obj->{duration} || '*';
$time = $obj->{time} || '*';
$body = $obj->{body};
} else {
next;
}
my $d1 = $d;
$d1 =~ s/^0+//;
$special = uc($special);
if ($special eq 'HTML') {
push(@{$days->[$d]}, $body);
} elsif ($special eq 'HTMLCLASS') {
@@ -284,7 +331,7 @@ sub small_calendar
}
}
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
print "<td width=\"14%\">\n";
print "<table border=\"0\">\n";
print "<caption>";
@@ -299,7 +346,7 @@ sub small_calendar
print "</caption>\n";
my $class;
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
print '<tr>';
$class = ' align="right"';
} else {
@@ -321,7 +368,7 @@ sub small_calendar
if ($col == 0) {
print("<tr>\n");
}
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
print("<td align=\"right\" width=\"14%\">&nbsp;</td>");
} else {
print("<td class=\"rem-sc-empty-cell\">&nbsp;</td>");
@@ -333,7 +380,7 @@ sub small_calendar
print("<tr>\n");
}
$col++;
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
print("<td align=\"right\" width=\"14%\">$day</td>");
} else {
print("<td class=\"rem-sc-cell\">$day</td>");
@@ -345,7 +392,7 @@ sub small_calendar
}
if ($col) {
while ($col < 7) {
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
print("<td align=\"right\" width=\"14%\">&nbsp;</td>");
} else {
print("<td class=\"rem-sc-empty-cell\">&nbsp;</td>");
@@ -372,9 +419,17 @@ sub output_calendar
# Last column
my $last_col = ($first_col + $Numdays - 1) % 7;
# Figure out how many rows
my $number_of_rows = int(($first_col + $Numdays ) / 7 + 0.999);
# Add a row for small calendars if necessary
if ($first_col == 0 && $last_col == 6) {
$number_of_rows++;
}
# Start the table
my $class;
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
print '<table width="100%" border="1" cellspacing=\"0\"><caption>' .
$Month . ' ' . $Year . '</caption>' . "\n";
print '<tr>';
@@ -398,26 +453,26 @@ sub output_calendar
# Start the calendar rows
my $col = 0;
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
print "<tr>\n";
} else {
print "<tr class=\"rem-cal-row\">\n";
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
}
if ($first_col > 0) {
small_calendar($Prevmon, $Prevlen, $Options{'backurl'},
small_calendar($Prevmon, $Prevlen, $Options{backurl},
($Firstwkday - $Prevlen + 35) % 7);
$col++;
}
if ($last_col == 6 && $first_col > 0) {
small_calendar($Nextmon, $Nextlen, $Options{'forwurl'},
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
($Firstwkday + $Numdays) % 7);
$col++;
}
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
$class = ' width="14%"';
} else {
$class = ' class="rem-empty"';
$class = ' class="rem-empty rem-empty-$number_of_rows-rows"';
}
while ($col < $first_col) {
print("<td$class>&nbsp;</td>\n");
@@ -425,16 +480,16 @@ sub output_calendar
}
for (my $day=1; $day<=$Numdays; $day++) {
draw_day_cell($day);
draw_day_cell($day, $number_of_rows);
$col++;
if ($col == 7) {
$col = 0;
print "</tr>\n";
if ($day < $Numdays) {
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
print "<tr>\n";
} else {
print "<tr class=\"rem-cal-row\">\n";
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
}
}
}
@@ -444,13 +499,13 @@ sub output_calendar
while ($col < 7) {
if ($col == 5) {
if ($first_col == 0) {
small_calendar($Prevmon, $Prevlen, $Options{'backurl'},
small_calendar($Prevmon, $Prevlen, $Options{backurl},
($Firstwkday - $Prevlen + 35) % 7);
} else {
print("<td$class>&nbsp;</td>\n");
}
} elsif ($col == 6) {
small_calendar($Nextmon, $Nextlen, $Options{'forwurl'},
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
($Firstwkday + $Numdays) % 7);
} else {
print("<td$class>&nbsp;</td>\n");
@@ -462,17 +517,17 @@ sub output_calendar
# Add a row for small calendars if they were not yet done!
if ($first_col == 0 && $last_col == 6) {
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
print "<tr>\n";
} else {
print "<tr class=\"rem-cal-row\">\n";
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
}
small_calendar($Prevmon, $Prevlen, $Options{'backurl'},
small_calendar($Prevmon, $Prevlen, $Options{backurl},
($Firstwkday - $Prevlen + 35) % 7);
for (my $i=0; $i<5; $i++) {
print("<td$class>&nbsp;</td>\n");
}
small_calendar($Nextmon, $Nextlen, $Options{'forwurl'},
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
($Firstwkday + $Numdays) % 7);
print("</tr>\n");
}
@@ -482,17 +537,17 @@ sub output_calendar
sub draw_day_cell
{
my($day) = @_;
my($day, $number_of_rows) = @_;
my $shade = $shades->[$day];
my $week = '';
if (exists($weeks->{$day})) {
$week = ' ' . $weeks->{$day};
}
my $class;
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
$class = $classes->[$day] || '';
} else {
$class = $classes->[$day] || "rem-cell";
$class = $classes->[$day] || "rem-cell rem-cell-$number_of_rows-rows";
}
if ($shade) {
$shade = " style=\"background: $shade;\"";
@@ -515,33 +570,46 @@ sub draw_day_cell
my $alt;
my $title;
if ($phase == 0) {
$img = 'newmoon.png';
if ($Options{pngs}) {
$img = smoosh($Options{imgbase}, 'newmoon.png');
} else {
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAC6SURBVDiNpdNNbsIwFATgL0HKolchHKBX6yFaBOEyoPYUabvOIVKJRaCL2JX5TRNGGvnJ8ozGz89cYoElPvET+BX2yivn/1Bggw5HHMKa1h2qcPZC/JEIhvh+brIZIY6sorhMYo9hh3KGFzzfa84NZNjDt9OG/ZcH1BlaPE1IAG0+URhxzNGESKPFaHJs9Q0Ziww7HnvGeXSrJhis0jiFfjwnj3I0WRv+TKtr4hQl3lDrZ6QN9Wt654hfWfGDmBpUwDkAAAAASUVORK5CYII=';
}
$title = 'New Moon';
$alt = 'new';
} elsif ($phase == 1) {
$img = 'firstquarter.png';
if ($Options{pngs}) {
$img = smoosh($Options{imgbase}, 'firstquarter.png');
} else {
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADfSURBVDiNndM9TsNAFATgzy5yjZSAE85JBygETgENUPF3iBCitHAFQkcIhZ/Ryn9gRlrZmp2Z3ef3TBOHOMULPrDBMrhpi/4HI5xjix2+4nmJRbx/Yh7ahvkpRPVV4QDXwT3UQy46zGkAZDgK/iytefvHgCrkJsqZUH6cLnNbABSxd5Jhhf1IbkMXv8Qux7hH1Ic1xvk/jBWy6gavumvtwx7ectwZXkKh7MA95XgObeOtpI2U4zl0kGbpxgiPvwQUcXLrKFchc82f6Ur0PK49azOnmOI4TBu84zm4SV38DeIVYkrYJyNbAAAAAElFTkSuQmCC';
}
$title = 'First Quarter';
$alt = '1st';
} elsif ($phase == 2) {
$img = 'fullmoon.png';
if ($Options{pngs}) {
$img = smoosh($Options{imgbase}, 'fullmoon.png');
} else {
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADlSURBVDiNrdNBUsJAEAXQlyw4hq4hwWPqTixET6ELkZ16CcAq7oFLqXExjaYgQVNlV/Viev7/6XT/4TjGuME7PiLXUatb8N8xwB12SFjiIXIZtU/MAntEfgvQE4YtHxhiHpjXQ5H7uLhEcaLLAleBvd0Xx9Ha/BdyU+Q5OBV5OKmj7a4YBWdSyNPe4aKHAHkzqcQZNj3JgnNexqE8heyIAulffuFF3kTfIVbBVeu/xoXGGsn2TLJJ/mqkafNiINszySYZdbS90GHlvcgsWktY4TFy7ecxTdvIzahxHQLbyFXUqkPwF2ASRNYgB/PXAAAAAElFTkSuQmCC';
}
$alt = 'full';
$title = 'Full Moon';
} else {
$img = 'lastquarter.png';
if ($Options{pngs}) {
$img = smoosh($Options{imgbase}, 'lastquarter.png');
} else {
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADmSURBVDiNndMxTsNAEIXhzy5yCyQ6FAgcE7oQheQWUAAl5BIkREoZrgB0GFNkHBl7bURGsryaee/3jHeXdpxjghU+8InXyI0S+n0MMEeBEi+4jfV3vAvMQtsyL0J0j2GtViaeRRMyj8IlsgY8BSijE2Kur/hy09wHKMJrEolhwtwHKDHOsI4OLnoAXfl1jiNsOkR9keE4P8D4q4scbzg5xIxtjie709f1E7siC+9+Gx/8fxvPKtEsklcJSBdgWhcN8ByFR5z+AWgd5QpyE+OUWOJO+zJNU+Z6jHAdgHe7K73CuD5zFT9nCmRDIssCaAAAAABJRU5ErkJggg==';
}
$alt = 'last';
$title = 'Last Quarter';
}
if ($Options{'imgbase'}) {
$img = $Options{'imgbase'} . '/' . $img;
}
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
print("<div style=\"float: left\"><img border=\"0\" width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">$msg</div>");
} else {
print("<div class=\"rem-moon\"><img width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">$msg</div>");
}
}
if ($Options{'nostyle'}) {
if ($Options{nostyle}) {
print "<div style=\"float: right\">$day$week</div>\n";
print "<p>&nbsp;</p>\n";
} else {
@@ -564,13 +632,13 @@ sub escape_html
}
parse_options();
if ($Options{'help'}) {
if ($Options{help}) {
usage(0);
exit(0);
} elsif ($Options{'man'}) {
} elsif ($Options{man}) {
system("perldoc $0");
exit(0);
} elsif ($Options{'version'}) {
} elsif ($Options{version}) {
print "rem2html version $rem2html_version.\n";
exit(0);
}
@@ -595,3 +663,81 @@ if ($found_something) {
exit(1);
}
sub default_stylesheet
{
return <<'EOF';
table.rem-cal {
font-family: helvetica, arial, sans-serif;
font-size: 12pt;
}
table.rem-sc-table {
font-family: helvetica, arial, sans-serif;
font-size: 10pt;
width: 95%;
float: left;
}
caption.rem-cal-caption {
font-size: 14pt;
font-weight: bold;
}
th.rem-cal-hdr {
width: 14%;
border-style: solid;
border-width: 1px;
vertical-align: top;
}
td.rem-empty, td.rem-cell, td.rem-small-calendar {
width: 14%;
height: 7em;
border-style: solid;
border-width: 1px;
vertical-align: top;
}
td.rem-today {
width: 14%;
height: 7em;
border-style: solid;
border-width: 2px;
border-color: #EE3333;
vertical-align: top;
}
table.rem-cal {
width: 100%;
border-collapse: collapse;
}
div.rem-daynumber {
float: right;
text-align: right;
vertical-align: top;
font-size: 14pt;
}
p.rem-entry {
clear: both;
}
div.rem-moon {
float: left;
text-align: left;
vertical-align: top;
}
th.rem-sc-hdr {
text-align: right;
}
td.rem-sc-empty-cell, td.rem-sc-cell {
text-align: right;
width: 14%;
}
caption.rem-sc-caption {
font-size: 12pt;
}
EOF
}

View File

@@ -1,4 +1,3 @@
Files in this directory:
tkremind -- Tcl/Tk graphical calendar using Remind as engine
cm2rem.tcl -- Convert Sun's "cm" calendar manager files to Remind.

View File

@@ -1,358 +0,0 @@
#!/bin/sh
# -*-Mode: TCL;-*-
#--------------------------------------------------------------
# cm2rem.tcl
#
# A cheesy Tcl script to convert Sun's "cm" calendar manager
# files (version 3 only) to Remind format.
#
# This file is part of REMIND.
# Copyright (C) 1992-2018 by Dianne Skoll
#
#--------------------------------------------------------------
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
set i 0
foreach month {January February March April May June
July August September October November December} {
incr i
set MonthNum($month) $i
set FullMonth([string range $month 0 2]) $month
}
#***********************************************************************
# %PROCEDURE: convertParens
# %ARGUMENTS:
# line -- a line read from a cm file
# %RETURNS:
# A new line with all ( and ) outside quotes converted to { and }.
# This cheap trick allows us to use Tcl's built-in list manipulation
# functions to munge the line.
#***********************************************************************
proc convertParens { line } {
# Convert all ( and ) to { and } unless they are inside a quoted
# string
set out ""
set len [string length $line]
set inQuotes 0
for {set i 0} {$i < $len} {incr i} {
set char [string range $line $i $i]
if {$char == "\\" && $inQuotes} {
append out $char
incr i
set char [string range $line $i $i]
append out $char
continue
}
if {$char == "(" && !$inQuotes} {
set char \{
}
if {$char == ")" && !$inQuotes} {
set char \}
}
if {$char == "\""} {
set inQuotes [expr !$inQuotes]
}
append out $char
}
return $out
}
#***********************************************************************
# %PROCEDURE: processLine
# %ARGUMENTS:
# line -- a line read from a cm file
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Processes a single line from the file, possibly writing a reminder
# in Remind format to stdout
#***********************************************************************
proc processLine { line } {
global Attributes
global FullMonth
catch {unset Attributes}
# Only convert lines which start with "(add"
if {[string range $line 0 3] != "(add"} {
return
}
set line [convertParens $line]
# Convert it to a list. CAREFUL: Potential security problem if
# $line contains something nasty.
eval set line $line
set Attributes(body) ""
foreach {key val} $line {
switch -exact -- $key {
"add" {
set Attributes(date) $val
}
"what:" {
append Attributes(body) $val
}
"details:" {
append Attributes(body) $val
}
"duration:" {
set Attributes(duration) $val
}
"period:" {
set Attributes(period) $val
}
"ntimes:" {
set Attributes(ntimes) $val
}
"attributes:" {
set Attributes(action) $val
}
}
}
if {[info exists Attributes(action)]} {
# Nuke quotes and commas in action
regsub -all {[,\"]} $Attributes(action) { } Attributes(action)
# Add spaces to pairs
regsub -all \}\{ $Attributes(action) \}\ \{ Attributes(action)
# Add another pair of brackets to make a proper list
set Attributes(action) "{$Attributes(action)}"
# Convert to a real Tcl list
eval set Attributes(action) $Attributes(action)
}
# Split out date into month, day, year, time parts
scan $Attributes(date) "%s%s%s%s%s" wkday month day time year
set time [string range $time 0 4]
set Attributes(wkday) $wkday
set Attributes(month) $FullMonth($month)
set Attributes(day) $day
set Attributes(time) $time
set Attributes(year) $year
# Convert newlines in body to spaces
set body $Attributes(body)
regsub -all "\n" $body " " body
# TODO: Escape BODY to get rid of [] chars.
set Attributes(body) $body
# Convert to Reminder format
convertReminder
}
#***********************************************************************
# %PROCEDURE: convertReminder
# %ARGUMENTS:
# None -- uses global Attributes variable which must be filled in
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Converts a reminder to Remind format.
#***********************************************************************
proc convertReminder {} {
global Attributes
switch -exact $Attributes(period) {
single { convertSingleReminder }
daily { convertDailyReminder }
weekly { convertWeeklyReminder }
monthly { convertMonthlyReminder }
yearly { convertYearlyReminder }
default {
puts "\# Unable to convert reminder with period $Attributes(period)"
puts "\# Body is: $Attributes(body)"
}
}
}
#***********************************************************************
# %PROCEDURE: convertSingleReminder
# %ARGUMENTS:
# None -- uses global Attributes variable which must be filled in
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Converts a reminder with "single" period to Remind format.
#***********************************************************************
proc convertSingleReminder {} {
global Attributes
puts "REM $Attributes(day) $Attributes(month) $Attributes(year) [at][duration]MSG $Attributes(body)"
}
#***********************************************************************
# %PROCEDURE: convertDailyReminder
# %ARGUMENTS:
# None -- uses global Attributes variable which must be filled in
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Converts a reminder with "daily" period to Remind format.
#***********************************************************************
proc convertDailyReminder {} {
global Attributes
set ntimes [expr $Attributes(ntimes) - 1]
if {$ntimes <= 1} {
convertSingleReminder
return
}
set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) $ntimes]
puts "REM $Attributes(day) $Attributes(month) $Attributes(year) *1 [at][duration]UNTIL $until MSG $Attributes(body)"
}
#***********************************************************************
# %PROCEDURE: convertWeeklyReminder
# %ARGUMENTS:
# None -- uses global Attributes variable which must be filled in
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Converts a reminder with "daily" period to Remind format.
#***********************************************************************
proc convertWeeklyReminder {} {
global Attributes
set ntimes [expr $Attributes(ntimes) - 1]
if {$ntimes <= 1} {
convertSingleReminder
return
}
set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) [expr $ntimes * 7]]
puts "REM $Attributes(day) $Attributes(month) $Attributes(year) *7 [at][duration]UNTIL $until MSG $Attributes(body)"
}
#***********************************************************************
# %PROCEDURE: convertMonthlyReminder
# %ARGUMENTS:
# None -- uses global Attributes variable which must be filled in
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Converts a reminder with "monthly" period to Remind format.
#***********************************************************************
proc convertMonthlyReminder {} {
global Attributes
set ntimes [expr $Attributes(ntimes) - 1]
if {$ntimes <= 1} {
convertSingleReminder
return
}
# If repetition > 1000, it's infinite
if {$ntimes > 1000} {
puts "REM $Attributes(day) [at][duration]MSG $Attributes(body)"
return
}
### UNTIL date is fudged!
set until [getUntilDate $Attributes(day) $Attributes(month) $Attributes(year) [expr $ntimes * 30]]
puts "REM $Attributes(day) [at][duration]UNTIL $until MSG $Attributes(body)"
}
#***********************************************************************
# %PROCEDURE: convertYearlyReminder
# %ARGUMENTS:
# None -- uses global Attributes variable which must be filled in
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Converts a reminder with "yearly" period to Remind format.
#***********************************************************************
proc convertYearlyReminder {} {
global Attributes
# No special handling of ntimes et al.
puts "REM $Attributes(day) $Attributes(month) [at][duration]MSG $Attributes(body)"
}
#***********************************************************************
# %PROCEDURE: at
# %ARGUMENTS:
# None -- uses Attributes global variable
# %RETURNS:
# A string providing the correct AT clause for a timed reminder.
#***********************************************************************
proc at {} {
global Attributes
if {![info exists Attributes(time)]} {
return ""
}
if {"$Attributes(time)" == ""} {
return ""
}
return "AT $Attributes(time) "
}
#***********************************************************************
# %PROCEDURE: duration
# %ARGUMENTS:
# None -- uses Attributes global variable
# %RETURNS:
# A string providing the correct DURATION clause for a timed reminder.
#***********************************************************************
proc duration {} {
global Attributes
if {![info exists Attributes(duration)]} {
return ""
}
if {"$Attributes(duration)" == ""} {
return ""
}
set h [expr $Attributes(duration) / 3600]
set remainder [expr $Attributes(duration) - $h*3600]
set m [expr $remainder / 60]
return "DURATION [format "%d:%02d " $h $m]"
}
#***********************************************************************
# %PROCEDURE: getUntilDate
# %ARGUMENTS:
# day, month, year -- a date
# days -- number of days to add to date
# %RETURNS:
# The date which is "days" later than supplied date in a correct UNTIL
# format.
#***********************************************************************
proc getUntilDate { day month year days } {
global RemindPipe
global MonthNum
set date "'$year/$MonthNum($month)/$day'"
puts $RemindPipe "MSG \[trigger($date + $days)\]%"
puts $RemindPipe "flush"
flush $RemindPipe
gets $RemindPipe line
return $line
}
catch {wm withdraw .}
# Start a Remind process to issue reminders
if {[catch {set RemindPipe [open "|remind -" "r+"]} err]} {
puts stderr "Error: Cannot run Remind: $err"
exit 1
}
puts $RemindPipe "banner %"
flush $RemindPipe
# Write some blurb
puts "\# Reminder file converted from \"cm\" data by cm2rem.tcl"
puts ""
while {[gets stdin line] >= 0} {
processLine $line
}
exit 0

File diff suppressed because it is too large Load Diff

View File

@@ -18,11 +18,10 @@ INSTALL_PROGRAM=@INSTALL_PROGRAM@
INSTALL_DATA=@INSTALL_DATA@
PROGS= remind rem2ps
SCRIPTS= $(srcdir)/../scripts/tkremind $(srcdir)/../scripts/cm2rem.tcl
SCRIPTS= $(srcdir)/../scripts/tkremind
MANS= $(srcdir)/../man/rem2ps.1 $(srcdir)/../man/remind.1 \
$(srcdir)/../man/tkremind.1 $(srcdir)/../man/cm2rem.1 \
$(srcdir)/../man/rem.1
$(srcdir)/../man/tkremind.1 $(srcdir)/../man/rem.1
.SUFFIXES:
.SUFFIXES: .c .o
@@ -43,8 +42,10 @@ test: remind
.c.o:
@CC@ -c @CPPFLAGS@ @CFLAGS@ @DEFS@ $(CEXTRA) $(LANGDEF) -I. -I$(srcdir) $<
rem2ps: rem2ps.o dynbuf.o
@CC@ @LDFLAGS@ $(LDEXTRA) -o rem2ps rem2ps.o dynbuf.o
$(REMINDOBJS): $(REMINDHDRS)
rem2ps: rem2ps.o dynbuf.o json.o
@CC@ @LDFLAGS@ $(LDEXTRA) -o rem2ps rem2ps.o dynbuf.o json.o -lm
remind: $(REMINDOBJS)
@CC@ @LDFLAGS@ $(LDEXTRA) -o remind $(REMINDOBJS) @LIBS@
@@ -72,23 +73,21 @@ clobber:
rm -f *.o *~ remind rem2ps test.out core *.bak
depend:
gccmakedep @DEFS@ $(REMINDSRCS) rem2ps.c
gccmakedep @DEFS@ $(REMINDSRCS) rem2ps.c json.c
# The next targets are not very useful to you. I use them to build
# distributions, etc.
# Build a tar file based on all files checked into git.
distro:
ln -s . ../remind-$(VERSION)
(cd ..; git ls-files | fgrep -v .gitignore | fgrep -v remind.php) | sed -e 's/^/remind-$(VERSION)\//' | xargs tar -C .. -cvf remind-$(VERSION).tar
cd .. && git archive --worktree-attributes --format=tar --prefix=remind-$(VERSION)/ HEAD > src/remind-$(VERSION).tar
gzip -f -v -9 remind-$(VERSION).tar
rm -f ../remind-$(VERSION)
gpg --detach-sign -u dianne@skoll.ca remind-$(VERSION).tar.gz
beta-tgz:
ln -s . ../remind-$(VERSION)-BETA-$(BETA)
(cd ..; git ls-files | fgrep -v .gitignore | fgrep -v remind.php) | sed -e 's/^/remind-$(VERSION)-BETA-$(BETA)\//' | xargs tar -C .. -cvf remind-$(VERSION)-BETA-$(BETA).tar
cd .. && git archive --worktree-attributes --format=tar --prefix=remind-$(VERSION)-BETA-$(BETA)/ HEAD > src/remind-$(VERSION)-BETA-$(BETA).tar
gzip -f -v -9 remind-$(VERSION)-BETA-$(BETA).tar
rm -f ../remind-$(VERSION)-BETA-$(BETA)
gpg --detach-sign -u dianne@skoll.ca remind-$(VERSION)-BETA-$(BETA).tar.gz
#---------------- Stuff after this added by "make depend" -----------------

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,9 @@
/* Define if you have the <sys/file.h> header file. */
#undef HAVE_SYS_FILE_H
/* Define if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define if you have the <glob.h> header file */
#undef HAVE_GLOB_H
@@ -21,6 +24,8 @@
#undef HAVE_SETENV
#undef HAVE_INITGROUPS
#undef HAVE_UNSETENV
#undef HAVE_MBSTOWCS

View File

@@ -6,7 +6,7 @@
/* which you can customize. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -22,11 +22,11 @@
/* The default values are initially set to Ottawa, Ontario, Canada. */
/*---------------------------------------------------------------------*/
#define LAT_DEG 45
#define LAT_MIN 24
#define LAT_SEC 0
#define LAT_MIN 25
#define LAT_SEC 30
#define LON_DEG 75
#define LON_MIN 39
#define LON_SEC 0
#define LON_MIN 41
#define LON_SEC 59
#define LOCATION "Ottawa"
/*---------------------------------------------------------------------*/
@@ -146,7 +146,7 @@
/* VAR_NAME_LEN: The maximum length of variable names. Don't make it */
/* any less than 12. */
/*---------------------------------------------------------------------*/
#define VAR_NAME_LEN 16
#define VAR_NAME_LEN 64
/*---------------------------------------------------------------------*/
/* MAX_PRT_LEN: The maximum number of characters to print when */
@@ -220,6 +220,9 @@
#define PSBEGIN "# rem2ps begin"
#define PSEND "# rem2ps end"
#define PSBEGIN2 "# rem2ps2 begin"
#define PSEND2 "# rem2ps2 end"
#ifdef BROKEN_PUTC
#define Putc SafePutc
#define PutChar SafePutChar

View File

@@ -6,7 +6,7 @@
/* which you can customize. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -22,11 +22,11 @@
/* The default values are initially set to Ottawa, Ontario, Canada. */
/*---------------------------------------------------------------------*/
#define LAT_DEG 45
#define LAT_MIN 24
#define LAT_SEC 0
#define LAT_MIN 25
#define LAT_SEC 30
#define LON_DEG 75
#define LON_MIN 39
#define LON_SEC 0
#define LON_MIN 41
#define LON_SEC 59
#define LOCATION "Ottawa"
/*---------------------------------------------------------------------*/
@@ -146,7 +146,7 @@
/* VAR_NAME_LEN: The maximum length of variable names. Don't make it */
/* any less than 12. */
/*---------------------------------------------------------------------*/
#define VAR_NAME_LEN 16
#define VAR_NAME_LEN 64
/*---------------------------------------------------------------------*/
/* MAX_PRT_LEN: The maximum number of characters to print when */
@@ -220,6 +220,9 @@
#define PSBEGIN "# rem2ps begin"
#define PSEND "# rem2ps end"
#define PSBEGIN2 "# rem2ps2 begin"
#define PSEND2 "# rem2ps2 end"
#ifdef BROKEN_PUTC
#define Putc SafePutc
#define PutChar SafePutChar

View File

@@ -7,7 +7,7 @@
/* commands. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -18,22 +18,29 @@
#include <stdlib.h>
#include "types.h"
#include "globals.h"
#include "err.h"
#include "types.h"
#include "protos.h"
#include "expr.h"
/* Define the shell characters not to escape */
static char const DontEscapeMe[] =
"1234567890_-=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.,";
static int ParseTimeTrig (ParsePtr s, TimeTrig *tim, int save_in_globals);
static int ParseLocalOmit (ParsePtr s, Trigger *t);
static int ParseScanFrom (ParsePtr s, Trigger *t, int type);
static int ParsePriority (ParsePtr s, Trigger *t);
static int ParseUntil (ParsePtr s, Trigger *t);
static int ShouldTriggerBasedOnWarn (Trigger *t, int jul, int *err);
static int ComputeTrigDuration(TimeTrig *t);
static int
ComputeTrigDuration(TimeTrig *t)
{
if (t->ttime == NO_TIME ||
t->duration == NO_TIME) {
return 0;
}
return (t->ttime + t->duration - 1) / MINUTES_PER_DAY;
}
/***************************************************************/
/* */
@@ -70,6 +77,9 @@ int DoRem(ParsePtr p)
PurgeEchoLine("%s\n", CurLine);
r=DoSatRemind(&trig, &tim, p);
if (r) {
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
r = OK;
}
FreeTrig(&trig);
if (r == E_EXPIRED) return OK;
return r;
@@ -117,17 +127,28 @@ int DoRem(ParsePtr p)
}
} else {
/* Calculate the trigger date */
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1);
jul = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
if (r) {
if (PurgeMode) {
PurgeEchoLine("%s: %s\n", "#!P! Problem calculating trigger date", ErrMsg[r]);
PurgeEchoLine("%s\n", CurLine);
}
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
r = OK;
}
FreeTrig(&trig);
return r;
}
}
/* Add to global OMITs if so indicated */
if (trig.addomit) {
r = AddGlobalOmit(jul);
if (r) {
FreeTrig(&trig);
return r;
}
}
if (PurgeMode) {
if (trig.expired || jul < JulianToday) {
if (p->expr_happened) {
@@ -198,16 +219,22 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
trig->localomit = NO_WD;
trig->skip = NO_SKIP;
trig->once = NO_ONCE;
trig->addomit = 0;
trig->typ = NO_TYPE;
trig->scanfrom = NO_DATE;
trig->from = NO_DATE;
trig->priority = DefaultPrio;
trig->sched[0] = 0;
trig->warn[0] = 0;
trig->omitfunc[0] = 0;
trig->duration_days = 0;
trig->eventstart = NO_TIME;
trig->eventduration = NO_TIME;
trig->maybe_uncomputable = 0;
DBufInit(&(trig->tags));
trig->passthru[0] = 0;
tim->ttime = NO_TIME;
tim->delta = NO_DELTA;
tim->delta = DefaultTDelta;
tim->rep = NO_REP;
tim->duration = NO_TIME;
if (save_in_globals) {
@@ -245,6 +272,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
tim->ttime = (tok.val % MINUTES_PER_DAY);
if (save_in_globals) {
LastTriggerTime = tim->ttime;
SaveLastTimeTrig(tim);
}
break;
@@ -260,6 +288,11 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
trig->m = tok.val;
break;
case T_MaybeUncomputable:
DBufFree(&buf);
trig->maybe_uncomputable = 1;
break;
case T_Skip:
DBufFree(&buf);
if (trig->skip != NO_SKIP) return E_SKIP_ERR;
@@ -276,6 +309,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
DBufFree(&buf);
r=ParseTimeTrig(s, tim, save_in_globals);
if (r) return r;
trig->duration_days = ComputeTrigDuration(tim);
break;
case T_Scanfrom:
@@ -350,6 +384,11 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
trig->once = ONCE_ONCE;
break;
case T_AddOmit:
DBufFree(&buf);
trig->addomit = 1;
break;
case T_Omit:
DBufFree(&buf);
if (trig->omitfunc[0]) {
@@ -372,6 +411,10 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
r=ParseToken(s, &buf);
if (r) return r;
StrnCpy(trig->omitfunc, DBufValue(&buf), VAR_NAME_LEN);
/* An OMITFUNC counts as a nonconst_expr! */
s->expr_happened = 1;
s->nonconst_expr = 1;
DBufFree(&buf);
break;
@@ -396,7 +439,18 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
switch(tok.type) {
case T_Time:
case T_LongTime:
tim->duration = tok.val;
case T_Year:
case T_Day:
case T_Number:
if (tok.val != 0) {
tim->duration = tok.val;
} else {
tim->duration = NO_TIME;
}
if (save_in_globals) {
SaveLastTimeTrig(tim);
}
trig->duration_days = ComputeTrigDuration(tim);
break;
default:
return E_BAD_TIME;
@@ -435,7 +489,7 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
{
Token tok;
int r;
int seen_delta = 0;
DynamicBuffer buf;
DBufInit(&buf);
@@ -452,8 +506,9 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
case T_Delta:
DBufFree(&buf);
if (tim->delta != NO_DELTA) return E_DELTA_TWICE;
tim->delta = (tok.val > 0) ? tok.val : -tok.val;
if (seen_delta) return E_DELTA_TWICE;
seen_delta = 1;
tim->delta = (tok.val >= 0) ? tok.val : -tok.val;
break;
case T_Rep:
@@ -468,6 +523,7 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
/* Save trigger time in global variable */
if (save_in_globals) {
LastTriggerTime = tim->ttime;
SaveLastTimeTrig(tim);
}
PushToken(DBufValue(&buf), s);
DBufFree(&buf);
@@ -666,6 +722,30 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
FromJulian(tok.val, &y, &m, &d);
break;
case T_Back:
DBufFree(&buf);
if (type != SCANFROM_TYPE) {
Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]);
return E_INCOMPLETE;
}
if (y != NO_YR) {
Eprint("%s: %s", word, ErrMsg[E_YR_TWICE]);
return E_YR_TWICE;
}
if (m != NO_MON) {
Eprint("%s: %s", word, ErrMsg[E_MON_TWICE]);
return E_MON_TWICE;
}
if (d != NO_DAY) {
Eprint("%s: %s", word, ErrMsg[E_DAY_TWICE]);
return E_DAY_TWICE;
}
if (tok.val < 0) {
tok.val = -tok.val;
}
FromJulian(JulianToday - tok.val, &y, &m, &d);
break;
default:
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]);
@@ -678,9 +758,12 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
}
t->scanfrom = Julian(y, m, d);
if (type == FROM_TYPE) {
t->from = t->scanfrom;
if (t->scanfrom < JulianToday) {
t->scanfrom = JulianToday;
}
} else {
t->from = NO_DATE;
}
PushToken(DBufValue(&buf), s);
@@ -706,20 +789,24 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
char const *s;
Value v;
int red = -1, green = -1, blue = -1;
int is_color = 0;
DBufInit(&buf);
DBufInit(&calRow);
DBufInit(&pre_buf);
if (t->typ == RUN_TYPE && RunDisabled) return E_RUN_DISABLED;
if ((t->typ == PASSTHRU_TYPE && strcmp(t->passthru, "COLOR") && strcmp(t->passthru, "COLOUR")) ||
if ((t->typ == PASSTHRU_TYPE && StrCmpi(t->passthru, "COLOR") && StrCmpi(t->passthru, "COLOUR")) ||
t->typ == CAL_TYPE ||
t->typ == PS_TYPE ||
t->typ == PSF_TYPE)
return OK;
/* Handle COLOR types */
if (t->typ == PASSTHRU_TYPE && (!strcmp(t->passthru, "COLOR") || !strcmp(t->passthru, "COLOUR"))) {
if (t->typ == PASSTHRU_TYPE && (!StrCmpi(t->passthru, "COLOR") || !StrCmpi(t->passthru, "COLOUR"))) {
/* Strip off three tokens */
r = ParseToken(p, &buf);
sscanf(DBufValue(&buf), "%d", &red);
if (!NextMode) {
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
@@ -727,6 +814,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
DBufFree(&buf);
if (r) return r;
r = ParseToken(p, &buf);
sscanf(DBufValue(&buf), "%d", &green);
if (!NextMode) {
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
@@ -734,6 +822,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
DBufFree(&buf);
if (r) return r;
r = ParseToken(p, &buf);
sscanf(DBufValue(&buf), "%d", &blue);
if (!NextMode) {
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
@@ -817,6 +906,23 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
return OK;
}
/* Correct colors */
if (UseVTColors) {
if (red == -1 && green == -1 && blue == -1) {
if (DefaultColorR != -1 && DefaultColorG != -1 && DefaultColorB != -1) {
red = DefaultColorR;
green = DefaultColorG;
blue = DefaultColorB;
}
}
if (red >= 0 && green >= 0 && blue >= 0) {
is_color = 1;
if (red > 255) red = 255;
if (green > 255) green = 255;
if (blue > 255) blue = 255;
}
}
/* Put the substituted string into the substitution buffer */
/* Don't use msgprefix() on RUN-type reminders */
@@ -827,6 +933,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
r = EvalExpr(&s, &v, NULL);
if (!r) {
if (!DoCoerce(STR_TYPE, &v)) {
if (is_color) {
DBufPuts(&buf, Colorize(red, green, blue));
}
if (DBufPuts(&buf, v.v.str) != OK) {
DBufFree(&buf);
DestroyValue(v);
@@ -838,6 +947,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
}
}
if (is_color) {
DBufPuts(&buf, Colorize(red, green, blue));
}
if ( (r=DoSubst(p, &buf, t, tim, jul, NORMAL_MODE)) ) return r;
if (t->typ != RUN_TYPE) {
if (UserFuncExists("msgsuffix") == 1) {
@@ -846,6 +958,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
r = EvalExpr(&s, &v, NULL);
if (!r) {
if (!DoCoerce(STR_TYPE, &v)) {
if (is_color) {
DBufPuts(&buf, Colorize(red, green, blue));
}
if (DBufPuts(&buf, v.v.str) != OK) {
DBufFree(&buf);
DestroyValue(v);
@@ -857,6 +972,10 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
}
}
if (is_color) {
DBufPuts(&buf, Decolorize(red, green, blue));
}
if ((!MsgCommand && t->typ == MSG_TYPE) || t->typ == MSF_TYPE) {
if (DBufPutc(&buf, '\n') != OK) {
DBufFree(&buf);
@@ -891,7 +1010,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
break;
case RUN_TYPE:
system(DBufValue(&buf));
System(DBufValue(&buf));
break;
default: /* Unknown/illegal type? */
@@ -995,21 +1114,35 @@ int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int jul, int *err)
/* Do the "satisfying..." remind calculation. */
/* */
/***************************************************************/
int DoSatRemind(Trigger *trig, TimeTrig *tim, ParsePtr p)
int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
{
int iter, jul, r;
int iter, jul, r, start;
Value v;
char const *s;
char const *t;
t = p->pos;
iter = 0;
jul = trig->scanfrom;
start = trig->scanfrom;
while (iter++ < MaxSatIter) {
jul = ComputeTrigger(jul, trig, &r, 1);
jul = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, 0);
if (r) {
if (r == E_CANT_TRIG) return OK; else return r;
}
if (jul != start && trig->duration_days) {
jul = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, trig->duration_days);
if (r) {
if (r == E_CANT_TRIG) return OK; else return r;
}
} else if (jul == start) {
if (tt->ttime != NO_TIME) {
trig->eventstart = MINUTES_PER_DAY * r + tt->ttime;
if (tt->duration != NO_TIME) {
trig->eventduration = tt->duration;
}
}
SaveAllTriggerInfo(trig, tt, jul, tt->ttime, 1);
}
if (jul == -1) {
return E_EXPIRED;
}
@@ -1018,14 +1151,42 @@ int DoSatRemind(Trigger *trig, TimeTrig *tim, ParsePtr p)
t = p->pos;
if (r) return r;
if (v.type != INT_TYPE && v.type != STR_TYPE) return E_BAD_TYPE;
if (v.type == INT_TYPE && v.v.val) return OK;
if (v.type == STR_TYPE && *v.v.str) return OK;
if ((v.type == INT_TYPE && v.v.val) ||
(v.type == STR_TYPE && *v.v.str)) {
AdjustTriggerForDuration(trig->scanfrom, jul, trig, tt, 1);
if (DebugFlag & DB_PRTTRIG) {
int y, m, d;
FromJulian(LastTriggerDate, &y, &m, &d);
fprintf(ErrFp, "%s(%d): Trig(satisfied) = %s, %d %s, %d",
FileName, LineNo,
DayName[LastTriggerDate % 7],
d,
MonthName[m],
y);
if (tt->ttime != NO_TIME) {
fprintf(ErrFp, " AT %02d:%02d",
(tt->ttime / 60),
(tt->ttime % 60));
if (tt->duration != NO_TIME) {
fprintf(ErrFp, " DURATION %02d:%02d",
(tt->duration / 60),
(tt->duration % 60));
}
}
fprintf(ErrFp, "\n");
}
return OK;
}
p->pos = s;
jul++;
if (jul+trig->duration_days < start) {
start++;
} else {
start = jul+trig->duration_days+1;
}
}
p->pos = t;
LastTrigValid = 0;
return OK;
return E_CANT_TRIG;
}
/***************************************************************/
@@ -1081,24 +1242,16 @@ int DoMsgCommand(char const *cmd, char const *msg)
DynamicBuffer execBuffer;
DynamicBuffer buf;
char const *s;
DBufInit(&buf);
DBufInit(&execBuffer);
/* Escape shell characters in msg INCLUDING WHITESPACE! */
for (s=msg; *s; s++) {
if (isspace(*s) || !strchr(DontEscapeMe, *s)) {
if (DBufPutc(&buf, '\\') != OK) {
r = E_NO_MEM;
goto finished;
}
}
if (DBufPutc(&buf, *s) != OK) {
r = E_NO_MEM;
goto finished;
}
/* Escape shell characters in msg */
if (ShellEscape(msg, &buf) != OK) {
r = E_NO_MEM;
goto finished;
}
msg = DBufValue(&buf);
/* Do "%s" substitution */
@@ -1119,7 +1272,7 @@ int DoMsgCommand(char const *cmd, char const *msg)
}
r = OK;
system(DBufValue(&execBuffer));
System(DBufValue(&execBuffer));
finished:
DBufFree(&buf);

View File

@@ -6,7 +6,7 @@
/* reminders are triggered. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -18,9 +18,9 @@
#include <stdlib.h>
#include "types.h"
#include "globals.h"
#include "err.h"
#include "types.h"
#include "protos.h"
#define UPPER(c) (islower(c) ? toupper(c) : (c))
@@ -644,10 +644,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
break;
case '_':
if (mode != CAL_MODE && mode != ADVANCE_MODE && !MsgCommand)
if (PsCal == PSCAL_LEVEL2 || PsCal == PSCAL_LEVEL3 || (mode != CAL_MODE && mode != ADVANCE_MODE && !MsgCommand)) {
sprintf(s, "%s", NL);
else
} else {
sprintf(s, " ");
}
SHIP_OUT(s);
break;
@@ -656,8 +657,13 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
break;
case '"':
if (DBufPutc(dbuf, QUOTE_MARKER) != OK) return E_NO_MEM;
has_quote = 1;
if (PsCal != PSCAL_LEVEL3) {
if (DBufPutc(dbuf, QUOTE_MARKER) != OK) return E_NO_MEM;
has_quote = 1;
} else {
if (DBufPutc(dbuf, '%') != OK) return E_NO_MEM;
if (DBufPutc(dbuf, c) != OK) return E_NO_MEM;
}
break;
default:

View File

@@ -6,7 +6,7 @@
/* buffers. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -150,7 +150,9 @@ int DBufGets(DynamicBuffer *dbuf, FILE *fp)
we can usually save some unnecessary copying */
*(dbuf->buffer) = 0;
fgets(dbuf->buffer, dbuf->allocatedLen, fp);
if (fgets(dbuf->buffer, dbuf->allocatedLen, fp) == NULL) {
return OK;
}
if (!*(dbuf->buffer)) return OK;
dbuf->len = strlen(dbuf->buffer);
l = dbuf->len - 1;
@@ -162,7 +164,7 @@ int DBufGets(DynamicBuffer *dbuf, FILE *fp)
while(busy) {
*tmp = 0;
fgets(tmp, 256, fp);
if (fgets(tmp, 256, fp) == NULL) return OK;
if (!*tmp) return OK;
l = strlen(tmp) - 1;
if (tmp[l] == '\n') {

View File

@@ -5,7 +5,7 @@
/* Declaration of functions for manipulating dynamic buffers */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Error definitions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -119,6 +119,7 @@
#define E_NO_MATCHING_REMS 100
#define E_STRING_TOO_LONG 101
#define E_TIME_TWICE 102
#define E_DURATION_NO_AT 103
#ifdef MK_GLOBALS
#undef EXTERN
#define EXTERN
@@ -234,7 +235,8 @@ EXTERN char *ErrMsg[]
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice"
"Time specified twice",
"Cannot specify DURATION without specifying AT"
}
#endif /* MK_GLOBALS */
;

View File

@@ -5,7 +5,7 @@
/* This file contains routines to parse and evaluate */
/* expressions. */
/* */
/* Copyright 1992-2018 by Dianne Skoll */
/* Copyright 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -13,6 +13,7 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
@@ -30,7 +31,6 @@
#define LE 4
#define NE 5
static char CoerceBuf[512];
extern int NumFuncs;
static int Multiply(void), Divide(void), Mod(void), Add(void),
@@ -493,6 +493,8 @@ static int MakeValue(char const *s, Value *v, Var *locals, ParsePtr p)
{
int len;
int h, m, r;
int ampm = 0;
int prev_val;
if (*s == '\"') { /* It's a literal string "*/
len = strlen(s)-1;
@@ -519,9 +521,15 @@ static int MakeValue(char const *s, Value *v, Var *locals, ParsePtr p)
return OK;
} else if (isdigit(*s)) { /* It's a number - use len to hold it.*/
len = 0;
prev_val = 0;
while (*s && isdigit(*s)) {
len *= 10;
len += (*s++ - '0');
if (len < prev_val) {
/* We overflowed */
return E_2HIGH;
}
prev_val = len;
}
if (*s == ':' || *s == '.' || *s == TimeSep) { /* Must be a literal time */
s++;
@@ -533,7 +541,27 @@ static int MakeValue(char const *s, Value *v, Var *locals, ParsePtr p)
m += *s - '0';
s++;
}
/* Check for p[m] or a[m] */
if (*s == 'A' || *s == 'a' || *s == 'P' || *s == 'p') {
ampm = tolower(*s);
s++;
if (*s == 'm' || *s == 'M') {
s++;
}
}
if (*s || h>23 || m>59) return E_BAD_TIME;
if (ampm) {
if (h < 1 || h > 12) return E_BAD_TIME;
if (ampm == 'a') {
if (h == 12) {
h = 0;
}
} else if (ampm == 'p') {
if (h < 12) {
h += 12;
}
}
}
v->type = TIME_TYPE;
v->v.val = h*60 + m;
return OK;
@@ -578,6 +606,8 @@ int DoCoerce(char type, Value *v)
int h, d, m, y, i, k;
char const *s;
char coerce_buf[128];
/* Do nothing if value is already the right type */
if (type == v->type) return OK;
@@ -605,12 +635,12 @@ int DoCoerce(char type, Value *v)
}
case STR_TYPE:
switch(v->type) {
case INT_TYPE: sprintf(CoerceBuf, "%d", v->v.val); break;
case TIME_TYPE: sprintf(CoerceBuf, "%02d%c%02d", v->v.val / 60,
case INT_TYPE: sprintf(coerce_buf, "%d", v->v.val); break;
case TIME_TYPE: sprintf(coerce_buf, "%02d%c%02d", v->v.val / 60,
TimeSep, v->v.val % 60);
break;
case DATE_TYPE: FromJulian(v->v.val, &y, &m, &d);
sprintf(CoerceBuf, "%04d%c%02d%c%02d",
sprintf(coerce_buf, "%04d%c%02d%c%02d",
y, DateSep, m+1, DateSep, d);
break;
case DATETIME_TYPE:
@@ -619,13 +649,13 @@ int DoCoerce(char type, Value *v)
k = v->v.val % MINUTES_PER_DAY;
h = k / 60;
i = k % 60;
sprintf(CoerceBuf, "%04d%c%02d%c%02d%c%02d%c%02d",
sprintf(coerce_buf, "%04d%c%02d%c%02d%c%02d%c%02d",
y, DateSep, m+1, DateSep, d, DateTimeSep, h, TimeSep, i);
break;
default: return E_CANT_COERCE;
}
v->type = STR_TYPE;
v->v.str = StrDup(CoerceBuf);
v->v.str = StrDup(coerce_buf);
if (!v->v.str) {
v->type = ERR_TYPE;
return E_NO_MEM;
@@ -700,26 +730,12 @@ int DoCoerce(char type, Value *v)
return OK;
case STR_TYPE:
h = 0;
m = 0;
s = v->v.str;
if (!isdigit(*s)) return E_CANT_COERCE;
while (isdigit(*s)) {
h *= 10;
h += *s++ - '0';
}
if (*s != ':' && *s != '.' && *s != TimeSep)
return E_CANT_COERCE;
s++;
if (!isdigit(*s)) return E_CANT_COERCE;
while (isdigit(*s)) {
m *= 10;
m += *s++ - '0';
}
if (*s || h>23 || m>59) return E_CANT_COERCE;
if (ParseLiteralTime(&s, &i)) return E_CANT_COERCE;
if (*s) return E_CANT_COERCE;
v->type = TIME_TYPE;
free(v->v.str);
v->v.val = h*60+m;
v->v.val = i;
return OK;
default: return E_CANT_COERCE;
@@ -750,35 +766,49 @@ static int Add(void)
/* If both are ints, just add 'em */
if (v2.type == INT_TYPE && v1.type == INT_TYPE) {
v2.v.val += v1.v.val;
PushValStack(v2);
int old = v1.v.val;
v1.v.val += v2.v.val;
/* Check for overflow */
if (_private_add_overflow(v1.v.val, v2.v.val, old)) {
return E_2HIGH;
}
PushValStack(v1);
return OK;
}
/* If it's a date plus an int, add 'em */
if ((v1.type == DATE_TYPE && v2.type == INT_TYPE) ||
(v1.type == INT_TYPE && v2.type == DATE_TYPE)) {
int old = v1.v.val;
v1.v.val += v2.v.val;
if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
if (v1.v.val < 0) return E_DATE_OVER;
v1.type = DATE_TYPE;
PushValStack(v1);
return OK;
}
/* If it's a datetime plus an int, add 'em */
if ((v1.type == DATETIME_TYPE && v2.type == INT_TYPE) ||
(v1.type == INT_TYPE && v2.type == DATETIME_TYPE)) {
/* If it's a datetime plus an int or a time, add 'em */
if ((v1.type == DATETIME_TYPE && (v2.type == INT_TYPE || v2.type == TIME_TYPE)) ||
((v1.type == INT_TYPE || v1.type == TIME_TYPE) && v2.type == DATETIME_TYPE)) {
int old = v1.v.val;
v1.v.val += v2.v.val;
if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
if (v1.v.val < 0) return E_DATE_OVER;
v1.type = DATETIME_TYPE;
PushValStack(v1);
return OK;
}
/* If it's a time plus an int, add 'em mod MINUTES_PER_DAY */
/* If it's a time plus an int or a time plus a time,
add 'em mod MINUTES_PER_DAY */
if ((v1.type == TIME_TYPE && v2.type == INT_TYPE) ||
(v1.type == INT_TYPE && v2.type == TIME_TYPE)) {
v1.v.val = (v1.v.val + v2.v.val) % MINUTES_PER_DAY;
(v1.type == INT_TYPE && v2.type == TIME_TYPE) ||
(v1.type == TIME_TYPE && v2.type == TIME_TYPE)) {
int old = v1.v.val;
v1.v.val += v2.v.val;
if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
v1.v.val = v1.v.val % MINUTES_PER_DAY;
if (v1.v.val < 0) v1.v.val += MINUTES_PER_DAY;
v1.type = TIME_TYPE;
PushValStack(v1);
@@ -798,7 +828,7 @@ static int Add(void)
v3.type = STR_TYPE;
l1 = strlen(v1.v.str);
l2 = strlen(v2.v.str);
if (MaxStringLen && (l1 + l2 > MaxStringLen)) {
if (MaxStringLen && (l1 + l2 > (size_t) MaxStringLen)) {
DestroyValue(v1); DestroyValue(v2);
return E_STRING_TOO_LONG;
}
@@ -808,7 +838,7 @@ static int Add(void)
return E_NO_MEM;
}
strcpy(v3.v.str, v1.v.str);
strcat(v3.v.str, v2.v.str);
strcpy(v3.v.str+l1, v2.v.str);
DestroyValue(v1); DestroyValue(v2);
PushValStack(v3);
return OK;
@@ -838,22 +868,29 @@ static int Subtract(void)
/* If they're both INTs, do subtraction */
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
int old = v1.v.val;
v1.v.val -= v2.v.val;
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_2HIGH;
PushValStack(v1);
return OK;
}
/* If it's a date minus an int, do subtraction, checking for underflow */
if (v1.type == DATE_TYPE && v2.type == INT_TYPE) {
int old = v1.v.val;
v1.v.val -= v2.v.val;
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
if (v1.v.val < 0) return E_DATE_OVER;
PushValStack(v1);
return OK;
}
/* If it's a datetime minus an int, do subtraction, checking for underflow */
if (v1.type == DATETIME_TYPE && v2.type == INT_TYPE) {
/* If it's a datetime minus an int or a time, do subtraction,
* checking for underflow */
if (v1.type == DATETIME_TYPE && (v2.type == INT_TYPE || v2.type == TIME_TYPE)) {
int old = v1.v.val;
v1.v.val -= v2.v.val;
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
if (v1.v.val < 0) return E_DATE_OVER;
PushValStack(v1);
return OK;
@@ -871,7 +908,9 @@ static int Subtract(void)
if ((v1.type == TIME_TYPE && v2.type == TIME_TYPE) ||
(v1.type == DATETIME_TYPE && v2.type == DATETIME_TYPE) ||
(v1.type == DATE_TYPE && v2.type == DATE_TYPE)) {
int old = v1.v.val;
v1.v.val -= v2.v.val;
if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER;
v1.type = INT_TYPE;
PushValStack(v1);
return OK;
@@ -901,7 +940,16 @@ static int Multiply(void)
}
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
/* Prevent floating-point exception */
if ((v2.v.val == -1 && v1.v.val == INT_MIN) ||
(v1.v.val == -1 && v2.v.val == INT_MIN)) {
return E_2HIGH;
}
int old = v1.v.val;
v1.v.val *= v2.v.val;
if (v2.v.val != 0) {
if (_private_div(v1.v.val, v2.v.val) != old) return E_2HIGH;
}
PushValStack(v1);
return OK;
}
@@ -929,6 +977,10 @@ static int Divide(void)
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
if (v2.v.val == 0) return E_DIV_ZERO;
/* This is the only way it can overflow */
if (v2.v.val == -1 && v1.v.val == INT_MIN) {
return E_2HIGH;
}
v1.v.val /= v2.v.val;
PushValStack(v1);
return OK;
@@ -1103,7 +1155,9 @@ static int UnMinus(void)
{
Value *v = &ValStack[ValStackPtr-1];
if (v->type != INT_TYPE) return E_BAD_TYPE;
int old = v->v.val;
v->v.val = -v->v.val;
if (_private_unminus_overflow(old, v->v.val)) return E_2HIGH;
return OK;
}
@@ -1218,6 +1272,48 @@ int CopyValue(Value *dest, const Value *src)
return OK;
}
int ParseLiteralTime(char const **s, int *tim)
{
int h=0;
int m=0;
int ampm=0;
if (!isdigit(**s)) return E_BAD_TIME;
while(isdigit(**s)) {
h *= 10;
h += *(*s)++ - '0';
}
if (**s != ':' && **s != '.' && **s != TimeSep) return E_BAD_TIME;
(*s)++;
if (!isdigit(**s)) return E_BAD_TIME;
while(isdigit(**s)) {
m *= 10;
m += *(*s)++ - '0';
}
/* Check for p[m] or a[m] */
if (**s == 'A' || **s == 'a' || **s == 'P' || **s == 'p') {
ampm = tolower(**s);
(*s)++;
if (**s == 'm' || **s == 'M') {
(*s)++;
}
}
if (h>23 || m>59) return E_BAD_TIME;
if (ampm) {
if (h < 1 || h > 12) return E_BAD_TIME;
if (ampm == 'a') {
if (h == 12) {
h = 0;
}
} else if (ampm == 'p') {
if (h < 12) {
h += 12;
}
}
}
*tim = h * 60 + m;
return OK;
}
/***************************************************************/
/* */
/* ParseLiteralDate */
@@ -1229,10 +1325,9 @@ int CopyValue(Value *dest, const Value *src)
int ParseLiteralDate(char const **s, int *jul, int *tim)
{
int y, m, d;
int hour, min;
int r;
y=0; m=0; d=0;
hour=0; min=0;
*tim = NO_TIME;
if (!isdigit(**s)) return E_BAD_DATE;
@@ -1262,20 +1357,9 @@ int ParseLiteralDate(char const **s, int *jul, int *tim)
/* Do we have a time part as well? */
if (**s == ' ' || **s == '@' || **s == 'T' || **s == 't') {
(*s)++;
while(isdigit(**s)) {
hour *= 10;
hour += *(*s)++ - '0';
}
if (**s != ':' && **s != '.' && **s != TimeSep) return E_BAD_TIME;
(*s)++;
while(isdigit(**s)) {
min *= 10;
min += *(*s)++ - '0';
}
if (hour > 23 || min > 59) return E_BAD_TIME;
*tim = hour * 60 + min;
r = ParseLiteralTime(s, tim);
if (r != OK) return r;
}
return OK;
}

View File

@@ -5,7 +5,7 @@
/* Contains a few definitions used by expression evaluator. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -53,3 +53,12 @@ if (ValStackPtr <= 0) \
return E_VA_STK_UNDER; \
else \
(val) = ValStack[--ValStackPtr]
/* These functions are in utils.c and are used to detect overflow
in various arithmetic operators. They have to be in separate
functions with extern linkage to defeat compiler optimizations
that would otherwise break the overflow checks. */
extern int _private_div(int a, int b);
extern int _private_add_overflow(int result, int b, int old);
extern int _private_sub_overflow(int result, int b, int old);
extern int _private_unminus_overflow(int a, int b);

View File

@@ -7,7 +7,7 @@
/* files. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -40,8 +40,9 @@
#include "err.h"
/* Convenient macro for closing files */
/* Convenient macros for closing files */
#define FCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL))
#define PCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (pclose(fp),(fp)=NULL) : ((fp)=NULL))
/* Define the structures needed by the file caching system */
typedef struct cache {
@@ -91,12 +92,12 @@ static FILE *fp;
static IncludeStruct IStack[INCLUDE_NEST];
static int IStackPtr = 0;
static int ReadLineFromFile (void);
static int CacheFile (char const *fname);
static int ReadLineFromFile (int use_pclose);
static int CacheFile (char const *fname, int use_pclose);
static void DestroyCache (CachedFile *cf);
static int CheckSafety (void);
static int PopFile (void);
static int IncludeCmd(char const *);
static void OpenPurgeFile(char const *fname, char const *mode)
{
DynamicBuffer fname_buf;
@@ -167,7 +168,7 @@ int ReadLine(void)
}
/* Not cached. Read from the file. */
return ReadLineFromFile();
return ReadLineFromFile(0);
}
/***************************************************************/
@@ -177,7 +178,7 @@ int ReadLine(void)
/* Read a line from the file pointed to by fp. */
/* */
/***************************************************************/
static int ReadLineFromFile(void)
static int ReadLineFromFile(int use_pclose)
{
int l;
char copy_buffer[4096];
@@ -200,7 +201,11 @@ static int ReadLineFromFile(void)
return E_IO_ERR;
}
if (feof(fp)) {
FCLOSE(fp);
if (use_pclose) {
PCLOSE(fp);
} else {
FCLOSE(fp);
}
if ((DBufLen(&buf) == 0) &&
(DBufLen(&LineBuffer) == 0) && PurgeMode) {
if (PurgeFP != NULL && PurgeFP != stdout) fclose(PurgeFP);
@@ -248,7 +253,11 @@ static int ReadLineFromFile(void)
if (PurgeFP != stdout) fclose(PurgeFP);
PurgeFP = NULL;
}
FCLOSE(fp);
if (use_pclose) {
PCLOSE(fp);
} else {
FCLOSE(fp);
}
DBufFree(&LineBuffer);
CurLine = DBufValue(&LineBuffer);
}
@@ -282,9 +291,6 @@ int OpenFile(char const *fname)
PurgeFP = NULL;
}
/* Assume we own the file for now */
RunDisabled &= ~RUN_NOTOWNER;
/* If it's in the cache, get it from there. */
while (h) {
@@ -297,7 +303,9 @@ int OpenFile(char const *fname)
LineNo = 0;
if (!h->ownedByMe) {
RunDisabled |= RUN_NOTOWNER;
}
} else {
RunDisabled &= ~RUN_NOTOWNER;
}
if (FileName) return OK; else return E_NO_MEM;
}
h = h->next;
@@ -306,6 +314,7 @@ int OpenFile(char const *fname)
/* If it's a dash, then it's stdin */
if (!strcmp(fname, "-")) {
fp = stdin;
RunDisabled &= ~RUN_NOTOWNER;
if (PurgeMode) {
PurgeFP = stdout;
}
@@ -325,7 +334,7 @@ int OpenFile(char const *fname)
CLine = NULL;
if (ShouldCache) {
LineNo = 0;
r = CacheFile(fname);
r = CacheFile(fname, 0);
if (r == OK) {
fp = NULL;
CLine = CachedFiles->cache;
@@ -353,7 +362,7 @@ int OpenFile(char const *fname)
/* Returns an indication of success or failure. */
/* */
/***************************************************************/
static int CacheFile(char const *fname)
static int CacheFile(char const *fname, int use_pclose)
{
int r;
CachedFile *cf;
@@ -366,16 +375,24 @@ static int CacheFile(char const *fname)
cl = NULL;
/* Create a file header */
cf = NEW(CachedFile);
cf->cache = NULL;
if (!cf) {
ShouldCache = 0;
FCLOSE(fp);
if (use_pclose) {
PCLOSE(fp);
} else {
FCLOSE(fp);
}
return E_NO_MEM;
}
cf->cache = NULL;
cf->filename = StrDup(fname);
if (!cf->filename) {
ShouldCache = 0;
FCLOSE(fp);
if (use_pclose) {
PCLOSE(fp);
} else {
FCLOSE(fp);
}
free(cf);
return E_NO_MEM;
}
@@ -388,11 +405,15 @@ static int CacheFile(char const *fname)
/* Read the file */
while(fp) {
r = ReadLineFromFile();
r = ReadLineFromFile(use_pclose);
if (r) {
DestroyCache(cf);
ShouldCache = 0;
FCLOSE(fp);
if (use_pclose) {
PCLOSE(fp);
} else {
FCLOSE(fp);
}
return r;
}
/* Skip blank chars */
@@ -406,7 +427,11 @@ static int CacheFile(char const *fname)
DBufFree(&LineBuffer);
DestroyCache(cf);
ShouldCache = 0;
FCLOSE(fp);
if (use_pclose) {
PCLOSE(fp);
} else {
FCLOSE(fp);
}
return E_NO_MEM;
}
cl = cf->cache;
@@ -416,7 +441,11 @@ static int CacheFile(char const *fname)
DBufFree(&LineBuffer);
DestroyCache(cf);
ShouldCache = 0;
FCLOSE(fp);
if (use_pclose) {
PCLOSE(fp);
} else {
FCLOSE(fp);
}
return E_NO_MEM;
}
cl = cl->next;
@@ -428,7 +457,11 @@ static int CacheFile(char const *fname)
if (!cl->text) {
DestroyCache(cf);
ShouldCache = 0;
FCLOSE(fp);
if (use_pclose) {
PCLOSE(fp);
} else {
FCLOSE(fp);
}
return E_NO_MEM;
}
}
@@ -471,9 +504,6 @@ static int PopFile(void)
{
IncludeStruct *i;
/* Assume we own the file for now */
RunDisabled &= ~RUN_NOTOWNER;
if (!Hush && NumIfs) Eprint("%s", ErrMsg[E_MISS_ENDIF]);
if (!IStackPtr) return E_EOF;
i = &IStack[IStackPtr-1];
@@ -500,8 +530,10 @@ static int PopFile(void)
STRSET(FileName, i->filename);
if (!i->ownedByMe) {
RunDisabled |= RUN_NOTOWNER;
} else {
RunDisabled &= ~RUN_NOTOWNER;
}
if (!CLine && (i->offset != -1L)) {
if (!CLine && (i->offset != -1L || !strcmp(i->filename, "-"))) {
/* We must open the file, then seek to specified position */
if (strcmp(i->filename, "-")) {
fp = fopen(i->filename, "r");
@@ -525,16 +557,119 @@ static int PopFile(void)
/* The INCLUDE command. */
/* */
/***************************************************************/
int DoInclude(ParsePtr p)
int DoInclude(ParsePtr p, enum TokTypes tok)
{
DynamicBuffer buf;
DynamicBuffer fullname;
DynamicBuffer path;
int r, e;
r = OK;
char const *s;
DBufInit(&buf);
DBufInit(&fullname);
DBufInit(&path);
if ( (r=ParseToken(p, &buf)) ) return r;
e = VerifyEoln(p);
if (e) Eprint("%s", ErrMsg[e]);
if ( (r=IncludeFile(DBufValue(&buf))) ) {
if (tok == T_IncludeR && *(DBufValue(&buf)) != '/') {
/* Relative include: Include relative to dir
containing current file */
if (DBufPuts(&path, FileName) != OK) {
r = E_NO_MEM;
goto bailout;
}
if (DBufLen(&path) == 0) {
s = DBufValue(&buf);
} else {
char *t = DBufValue(&path) + DBufLen(&path) - 1;
while (t > DBufValue(&path) && *t != '/') t--;
if (*t == '/') {
*t = 0;
if (DBufPuts(&fullname, DBufValue(&path)) != OK) {
r = E_NO_MEM;
goto bailout;
}
if (DBufPuts(&fullname, "/") != OK) {
r = E_NO_MEM;
goto bailout;
}
if (DBufPuts(&fullname, DBufValue(&buf)) != OK) {
r = E_NO_MEM;
goto bailout;
}
s = DBufValue(&fullname);
} else {
s = DBufValue(&buf);
}
}
} else {
s = DBufValue(&buf);
}
if ( (r=IncludeFile(s)) ) {
goto bailout;
}
NumIfs = 0;
IfFlags = 0;
bailout:
DBufFree(&buf);
DBufFree(&path);
DBufFree(&fullname);
return r;
}
/***************************************************************/
/* */
/* DoIncludeCmd */
/* */
/* The INCLUDECMD command. */
/* */
/***************************************************************/
int DoIncludeCmd(ParsePtr p)
{
DynamicBuffer buf;
int r;
int ch;
char append_buf[2];
int seen_nonspace = 0;
append_buf[1] = 0;
DBufInit(&buf);
while(1) {
ch = ParseChar(p, &r, 0);
if (r) {
DBufFree(&buf);
return r;
}
if (!ch) {
break;
}
if (isspace(ch) && !seen_nonspace) {
continue;
}
seen_nonspace = 1;
/* Convert \n to ' ' to better handle line continuation */
if (ch == '\n') {
ch = ' ';
}
append_buf[0] = (char) ch;
if (DBufPuts(&buf, append_buf) != OK) {
DBufFree(&buf);
return E_NO_MEM;
}
}
if (RunDisabled) {
DBufFree(&buf);
return E_RUN_DISABLED;
}
if ( (r=IncludeCmd(DBufValue(&buf))) ) {
DBufFree(&buf);
return r;
}
@@ -664,6 +799,127 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
}
#endif
/***************************************************************/
/* */
/* IncludeCmd */
/* */
/* Process the INCLUDECMD command - actually do the command */
/* inclusion. */
/* */
/***************************************************************/
static int IncludeCmd(char const *cmd)
{
IncludeStruct *i;
DynamicBuffer buf;
FILE *fp2;
int r;
CachedFile *h;
char const *fname;
int old_flag;
FreshLine = 1;
if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE;
i = &IStack[IStackPtr];
/* Use "cmd|" as the filename */
DBufInit(&buf);
if (DBufPuts(&buf, cmd) != OK) {
DBufFree(&buf);
return E_NO_MEM;
}
if (DBufPuts(&buf, "|") != OK) {
DBufFree(&buf);
return E_NO_MEM;
}
fname = DBufValue(&buf);
if (FileName) {
i->filename = StrDup(FileName);
if (!i->filename) {
DBufFree(&buf);
return E_NO_MEM;
}
} else {
i->filename = NULL;
}
i->ownedByMe = 1;
i->LineNo = LineNo;
i->NumIfs = NumIfs;
i->IfFlags = IfFlags;
i->CLine = CLine;
i->offset = -1L;
i->chain = NULL;
if (fp) {
i->offset = ftell(fp);
FCLOSE(fp);
}
IStackPtr++;
/* If the file is cached, use it */
h = CachedFiles;
while(h) {
if (!strcmp(fname, h->filename)) {
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Reading command `%s': Found in cache\n", fname);
}
CLine = h->cache;
STRSET(FileName, fname);
DBufFree(&buf);
LineNo = 0;
if (!h->ownedByMe) {
RunDisabled |= RUN_NOTOWNER;
} else {
RunDisabled &= ~RUN_NOTOWNER;
}
if (FileName) return OK; else return E_NO_MEM;
}
h = h->next;
}
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Executing `%s' for INCLUDECMD and caching as `%s'\n",
cmd, fname);
}
/* Not found in cache */
/* If cmd starts with !, then disable RUN within the cmd output */
if (cmd[0] == '!') {
fp2 = popen(cmd+1, "r");
} else {
fp2 = popen(cmd, "r");
}
if (!fp2) {
DBufFree(&buf);
return E_CANT_OPEN;
}
fp = fp2;
LineNo = 0;
/* Temporarily turn of file tracing */
old_flag = DebugFlag;
DebugFlag &= (~DB_TRACE_FILES);
if (cmd[0] == '!') {
RunDisabled |= RUN_NOTOWNER;
}
r = CacheFile(fname, 1);
DebugFlag = old_flag;
if (r == OK) {
fp = NULL;
CLine = CachedFiles->cache;
LineNo = 0;
STRSET(FileName, fname);
DBufFree(&buf);
return OK;
}
DBufFree(&buf);
/* We failed */
PopFile();
return E_CANT_OPEN;
}
/***************************************************************/
/* */
/* IncludeFile */
@@ -828,7 +1084,8 @@ int TopLevel(void)
/* root, we refuse to open files not owned by root. */
/* We also reject world-writable files, no matter */
/* who we're running as. */
/* As a side effect, if we don't own the file, we disable RUN */
/* As a side effect, if we don't own the file, or it's not */
/* owned by a trusted user, we disable RUN */
/***************************************************************/
static int CheckSafety(void)
{
@@ -866,9 +1123,22 @@ static int CheckSafety(void)
return 0;
}
/* If file is not owned by me, disable RUN command */
if (statbuf.st_uid != geteuid()) {
RunDisabled |= RUN_NOTOWNER;
/* If file is not owned by me or a trusted user, disable RUN command */
/* Assume unsafe */
RunDisabled |= RUN_NOTOWNER;
if (statbuf.st_uid == geteuid()) {
/* Owned by me... safe */
RunDisabled &= ~RUN_NOTOWNER;
} else {
int i;
for (i=0; i<NumTrustedUsers; i++) {
if (statbuf.st_uid == TrustedUsers[i]) {
/* Owned by a trusted user... safe */
RunDisabled &= ~RUN_NOTOWNER;
break;
}
}
}
return 1;

View File

@@ -6,7 +6,7 @@
/* expressions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -53,94 +53,110 @@
#define RetVal (info->retval)
/* Function prototypes */
static int FCurrent (func_info *);
static int FNonomitted (func_info *);
static int FTimepart(func_info *);
static int FDatepart(func_info *);
static int FRealCurrent(func_info *);
static int FAbs (func_info *);
static int FAccess (func_info *);
static int FArgs (func_info *);
static int FAsc (func_info *);
static int FBaseyr (func_info *);
static int FChar (func_info *);
static int FChoose (func_info *);
static int FCoerce (func_info *);
static int FDate (func_info *);
static int FDateTime (func_info *);
static int FDay (func_info *);
static int FDaysinmon (func_info *);
static int FDefined (func_info *);
static int FDosubst (func_info *);
static int FEasterdate (func_info *);
static int FEvalTrig (func_info *);
static int FFiledate (func_info *);
static int FFiledatetime (func_info *);
static int FFiledir (func_info *);
static int FFilename (func_info *);
static int FGetenv (func_info *);
static int FHebdate (func_info *);
static int FHebday (func_info *);
static int FHebmon (func_info *);
static int FHebyear (func_info *);
static int FHour (func_info *);
static int FIif (func_info *);
static int FIndex (func_info *);
static int FIsdst (func_info *);
static int FIsomitted (func_info *);
static int FSlide (func_info *);
static int FLanguage (func_info *);
static int FMax (func_info *);
static int FMin (func_info *);
static int FMinute (func_info *);
static int FMinsfromutc (func_info *);
static int FMoondate (func_info *);
static int FMoondatetime (func_info *);
static int FMoonphase (func_info *);
static int FMoontime (func_info *);
static int FMon (func_info *);
static int FMonnum (func_info *);
static int FOrd (func_info *);
static int FOstype (func_info *);
static int FPlural (func_info *);
static int FSgn (func_info *);
static int FPsmoon (func_info *);
static int FPsshade (func_info *);
static int FShell (func_info *);
static int FStrlen (func_info *);
static int FSubstr (func_info *);
static int FADawn (func_info *);
static int FADusk (func_info *);
static int FNDawn (func_info *);
static int FNDusk (func_info *);
static int FDawn (func_info *);
static int FDusk (func_info *);
static int FSunset (func_info *);
static int FSunrise (func_info *);
static int FTime (func_info *);
static int FTrigdate (func_info *);
static int FTrigdatetime (func_info *);
static int FTrigtime (func_info *);
static int FTrigvalid (func_info *);
static int FTypeof (func_info *);
static int FUpper (func_info *);
static int FValue (func_info *);
static int FVersion (func_info *);
static int FWkday (func_info *);
static int FWkdaynum (func_info *);
static int FYear (func_info *);
static int FIsleap (func_info *);
static int FLower (func_info *);
static int FNow (func_info *);
static int FRealnow (func_info *);
static int FRealtoday (func_info *);
static int FToday (func_info *);
static int FTrigger (func_info *);
static int FTzconvert (func_info *);
static int FWeekno (func_info *);
static int CheckArgs (BuiltinFunc *f, int nargs);
static int CleanUpAfterFunc (func_info *);
static int SunStuff (int rise, double cosz, int jul);
static int FADawn (func_info *);
static int FADusk (func_info *);
static int FAbs (func_info *);
static int FAccess (func_info *);
static int FAmpm (func_info *);
static int FIsAny (func_info *);
static int FArgs (func_info *);
static int FAsc (func_info *);
static int FBaseyr (func_info *);
static int FChar (func_info *);
static int FChoose (func_info *);
static int FCoerce (func_info *);
static int FCurrent (func_info *);
static int FDate (func_info *);
static int FDateTime (func_info *);
static int FDatepart (func_info *);
static int FDawn (func_info *);
static int FDay (func_info *);
static int FDaysinmon (func_info *);
static int FDefined (func_info *);
static int FDosubst (func_info *);
static int FDusk (func_info *);
static int FEasterdate (func_info *);
static int FEvalTrig (func_info *);
static int FFiledate (func_info *);
static int FFiledatetime (func_info *);
static int FFiledir (func_info *);
static int FFilename (func_info *);
static int FGetenv (func_info *);
static int FHebdate (func_info *);
static int FHebday (func_info *);
static int FHebmon (func_info *);
static int FHebyear (func_info *);
static int FHour (func_info *);
static int FIif (func_info *);
static int FIndex (func_info *);
static int FIsdst (func_info *);
static int FIsleap (func_info *);
static int FIsomitted (func_info *);
static int FLanguage (func_info *);
static int FLower (func_info *);
static int FMax (func_info *);
static int FMin (func_info *);
static int FMinsfromutc (func_info *);
static int FMinute (func_info *);
static int FMon (func_info *);
static int FMonnum (func_info *);
static int FMoondate (func_info *);
static int FMoondatetime (func_info *);
static int FMoonphase (func_info *);
static int FMoontime (func_info *);
static int FNDawn (func_info *);
static int FNDusk (func_info *);
static int FNonomitted (func_info *);
static int FNow (func_info *);
static int FOrd (func_info *);
static int FOstype (func_info *);
static int FPlural (func_info *);
static int FPsmoon (func_info *);
static int FPsshade (func_info *);
static int FRealCurrent (func_info *);
static int FRealnow (func_info *);
static int FRealtoday (func_info *);
static int FSgn (func_info *);
static int FShell (func_info *);
static int FSlide (func_info *);
static int FStrlen (func_info *);
static int FSubstr (func_info *);
static int FSunrise (func_info *);
static int FSunset (func_info *);
static int FTime (func_info *);
static int FTimepart (func_info *);
static int FToday (func_info *);
static int FTrigback (func_info *);
static int FTrigdate (func_info *);
static int FTrigdatetime (func_info *);
static int FTrigdelta (func_info *);
static int FTrigduration (func_info *);
static int FTrigeventduration(func_info *);
static int FTrigeventstart (func_info *);
static int FTrigfrom (func_info *);
static int FTrigger (func_info *);
static int FTrigpriority (func_info *);
static int FTrigrep (func_info *);
static int FTrigscanfrom (func_info *);
static int FTrigtime (func_info *);
static int FTrigtimedelta (func_info *);
static int FTrigtimerep (func_info *);
static int FTriguntil (func_info *);
static int FTrigvalid (func_info *);
static int FTypeof (func_info *);
static int FTzconvert (func_info *);
static int FUpper (func_info *);
static int FValue (func_info *);
static int FVersion (func_info *);
static int FWeekno (func_info *);
static int FWkday (func_info *);
static int FWkdaynum (func_info *);
static int FYear (func_info *);
static int FShellescape (func_info *);
static int CleanUpAfterFunc (func_info *);
static int CheckArgs (BuiltinFunc *f, int nargs);
static int SunStuff (int rise, double cosz, int jul);
/* "Overload" the struct Operator definition */
#define NO_MAX 127
@@ -193,6 +209,7 @@ BuiltinFunc Func[] = {
{ "access", 2, 2, 0, FAccess },
{ "adawn", 0, 1, 0, FADawn},
{ "adusk", 0, 1, 0, FADusk},
{ "ampm", 1, 3, 1, FAmpm },
{ "args", 1, 1, 0, FArgs },
{ "asc", 1, 1, 1, FAsc },
{ "baseyr", 0, 0, 1, FBaseyr },
@@ -223,6 +240,7 @@ BuiltinFunc Func[] = {
{ "hour", 1, 1, 1, FHour },
{ "iif", 1, NO_MAX, 1, FIif },
{ "index", 2, 3, 1, FIndex },
{ "isany", 1, NO_MAX, 1, FIsAny },
{ "isdst", 0, 2, 0, FIsdst },
{ "isleap", 1, 1, 1, FIsleap },
{ "isomitted", 1, 1, 0, FIsomitted },
@@ -252,6 +270,7 @@ BuiltinFunc Func[] = {
{ "realtoday", 0, 0, 0, FRealtoday },
{ "sgn", 1, 1, 1, FSgn },
{ "shell", 1, 2, 0, FShell },
{ "shellescape", 1, 1, 1, FShellescape },
{ "slide", 2, NO_MAX, 0, FSlide },
{ "strlen", 1, 1, 1, FStrlen },
{ "substr", 2, 3, 1, FSubstr },
@@ -260,10 +279,22 @@ BuiltinFunc Func[] = {
{ "time", 2, 2, 1, FTime },
{ "timepart", 1, 1, 1, FTimepart },
{ "today", 0, 0, 0, FToday },
{ "trigback", 0, 0, 0, FTrigback },
{ "trigdate", 0, 0, 0, FTrigdate },
{ "trigdatetime", 0, 0, 0, FTrigdatetime },
{ "trigdelta", 0, 0, 0, FTrigdelta },
{ "trigduration", 0, 0, 0, FTrigduration },
{ "trigeventduration", 0, 0, 0, FTrigeventduration },
{ "trigeventstart", 0, 0, 0, FTrigeventstart },
{ "trigfrom", 0, 0, 0, FTrigfrom },
{ "trigger", 1, 3, 0, FTrigger },
{ "trigpriority", 0, 0, 0, FTrigpriority },
{ "trigrep", 0, 0, 0, FTrigrep },
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom },
{ "trigtime", 0, 0, 0, FTrigtime },
{ "trigtimedelta",0, 0, 0, FTrigtimedelta },
{ "trigtimerep", 0, 0, 0, FTrigtimerep },
{ "triguntil", 0, 0, 0, FTriguntil },
{ "trigvalid", 0, 0, 0, FTrigvalid },
{ "typeof", 1, 1, 1, FTypeof },
{ "tzconvert", 2, 3, 0, FTzconvert },
@@ -380,8 +411,9 @@ static int RetStrVal(char const *s, func_info *info)
if (!s) {
RetVal.v.str = malloc(1);
if (RetVal.v.str) *RetVal.v.str = 0;
} else
} else {
RetVal.v.str = StrDup(s);
}
if (!RetVal.v.str) {
RetVal.type = ERR_TYPE;
@@ -839,12 +871,14 @@ static int FTime(func_info *info)
/***************************************************************/
static int FAbs(func_info *info)
{
int v;
volatile int v;
ASSERT_TYPE(0, INT_TYPE);
v = ARGV(0);
RetVal.type = INT_TYPE;
RETVAL = (v < 0) ? (-v) : v;
v = RETVAL;
if (v < 0) return E_2HIGH;
return OK;
}
@@ -861,6 +895,76 @@ static int FSgn(func_info *info)
return OK;
}
/***************************************************************/
/* */
/* FAmpm - return a time as a string with "AM" or "PM" suffix */
/* */
/***************************************************************/
static int FAmpm(func_info *info)
{
int h, m;
int yr=0, mo=0, da=0;
char const *am = "AM";
char const *pm = "PM";
char const *ampm = NULL;
char outbuf[128];
if (ARG(0).type != DATETIME_TYPE && ARG(0).type != TIME_TYPE) {
return E_BAD_TYPE;
}
if (HASDATE(ARG(0))) {
FromJulian(DATEPART(ARG(0)), &yr, &mo, &da);
}
if (Nargs >= 2) {
ASSERT_TYPE(1, STR_TYPE);
am = ARGSTR(1);
if (Nargs >= 3) {
ASSERT_TYPE(2, STR_TYPE);
pm = ARGSTR(2);
}
}
h = TIMEPART(ARG(0)) / 60;
m = TIMEPART(ARG(0)) % 60;
if (h <= 11) {
/* AM */
if (h == 0) {
if (ARG(0).type == DATETIME_TYPE) {
snprintf(outbuf, sizeof(outbuf), "%04d%c%02d%c%02d%c12%c%02d", yr, DateSep, mo+1, DateSep, da, DateTimeSep, TimeSep, m);
} else {
snprintf(outbuf, sizeof(outbuf), "12%c%02d", TimeSep, m);
}
} else {
if (ARG(0).type == DATETIME_TYPE) {
snprintf(outbuf, sizeof(outbuf), "%04d%c%02d%c%02d%c%d%c%02d", yr, DateSep, mo+1, DateSep, da, DateTimeSep, h, TimeSep, m);
} else {
snprintf(outbuf, sizeof(outbuf), "%d%c%02d", h, TimeSep, m);
}
}
ampm = am;
} else {
if (h > 12) {
h -= 12;
}
if (ARG(0).type == DATETIME_TYPE) {
snprintf(outbuf, sizeof(outbuf), "%04d%c%02d%c%02d%c%d%c%02d", yr, DateSep, mo+1, DateSep, da, DateTimeSep, h, TimeSep, m);
} else {
snprintf(outbuf, sizeof(outbuf), "%d%c%02d", h, TimeSep, m);
}
ampm = pm;
}
RetVal.type = STR_TYPE;
RetVal.v.str = malloc(strlen(outbuf) + strlen(ampm) + 1);
if (!RetVal.v.str) {
RetVal.type = ERR_TYPE;
return E_NO_MEM;
}
strcpy(RetVal.v.str, outbuf);
strcat(RetVal.v.str, ampm);
return OK;
}
/***************************************************************/
/* */
/* FOrd - returns a string containing ordinal number. */
@@ -932,6 +1036,36 @@ static int FPlural(func_info *info)
}
}
/***************************************************************/
/* */
/* FIsAny */
/* Return 1 if the first arg equals any subsequent arg, 0 */
/* otherwise. */
/* */
/***************************************************************/
static int FIsAny(func_info *info)
{
int i;
RetVal.type = INT_TYPE;
RETVAL = 0;
for (i=1; i<Nargs; i++) {
if (ARG(0).type == ARG(i).type) {
if (ARG(0).type == STR_TYPE) {
if (!strcmp(ARGSTR(0), ARGSTR(i))) {
RETVAL = 1;
return OK;
}
} else {
if (ARGV(0) == ARGV(i)) {
RETVAL = 1;
return OK;
}
}
}
}
return OK;
}
/***************************************************************/
/* */
/* FChoose */
@@ -973,6 +1107,28 @@ static int FOstype(func_info *info)
return RetStrVal("UNIX", info);
}
/***************************************************************/
/* */
/* FShellescape - escape shell meta-characters */
/* */
/***************************************************************/
static int FShellescape(func_info *info)
{
DynamicBuffer buf;
int r;
ASSERT_TYPE(0, STR_TYPE);
DBufInit (&buf);
if (ShellEscape(ARG(0).v.str, &buf) != OK) {
DBufFree(&buf);
return E_NO_MEM;
}
r = RetStrVal(DBufValue(&buf), info);
DBufFree(&buf);
return r;
}
/***************************************************************/
/* */
/* FUpper - convert string to upper-case */
@@ -1137,6 +1293,120 @@ static int FTrigdate(func_info *info)
return OK;
}
static int FTrigback(func_info *info)
{
RetVal.type = INT_TYPE;
RETVAL = LastTrigger.back;
return OK;
}
static int FTrigdelta(func_info *info)
{
RetVal.type = INT_TYPE;
RETVAL = LastTrigger.delta;
return OK;
}
static int FTrigtimedelta(func_info *info)
{
RetVal.type = INT_TYPE;
RETVAL = LastTimeTrig.delta;
return OK;
}
static int FTrigtimerep(func_info *info)
{
RetVal.type = INT_TYPE;
RETVAL = LastTimeTrig.rep;
return OK;
}
static int FTrigeventduration(func_info *info)
{
if (LastTrigger.eventduration == NO_TIME) {
RetVal.type = INT_TYPE;
RETVAL = -1;
} else {
RetVal.type = TIME_TYPE;
RETVAL = LastTrigger.eventduration;
}
return OK;
}
static int FTrigeventstart(func_info *info)
{
if (LastTrigger.eventstart == NO_TIME) {
RetVal.type = INT_TYPE;
RETVAL = -1;
} else {
RetVal.type = DATETIME_TYPE;
RETVAL = LastTrigger.eventstart;
}
return OK;
}
static int FTrigduration(func_info *info)
{
if (LastTimeTrig.duration == NO_TIME) {
RetVal.type = INT_TYPE;
RETVAL = -1;
} else {
RetVal.type = TIME_TYPE;
RETVAL = LastTimeTrig.duration;
}
return OK;
}
static int FTrigrep(func_info *info)
{
RetVal.type = INT_TYPE;
RETVAL = LastTrigger.rep;
return OK;
}
static int FTrigpriority(func_info *info)
{
RetVal.type = INT_TYPE;
RETVAL = LastTrigger.priority;
return OK;
}
static int FTriguntil(func_info *info)
{
if (LastTrigger.until == NO_UNTIL) {
RetVal.type = INT_TYPE;
RETVAL = -1;
} else {
RetVal.type = DATE_TYPE;
RETVAL = LastTrigger.until;
}
return OK;
}
static int FTrigscanfrom(func_info *info)
{
if (LastTrigger.scanfrom == NO_DATE) {
RetVal.type = INT_TYPE;
RETVAL = -1;
} else {
RetVal.type = DATE_TYPE;
RETVAL = LastTrigger.scanfrom;
}
return OK;
}
static int FTrigfrom(func_info *info)
{
if (LastTrigger.from == NO_DATE) {
RetVal.type = INT_TYPE;
RETVAL = -1;
} else {
RetVal.type = DATE_TYPE;
RETVAL = LastTrigger.from;
}
return OK;
}
static int FTrigvalid(func_info *info)
{
RetVal.type = INT_TYPE;
@@ -1876,12 +2146,8 @@ static int SunStuff(int rise, double cosz, int jul)
} else mins = MinsFromUTC;
/* Get latitude and longitude */
longdeg = (double) LongDeg + (double) LongMin / 60.0
+ (double) LongSec / 3600.0;
latitude = DEGRAD * ((double) LatDeg + (double) LatMin / 60.0
+ (double) LatSec / 3600.0);
longdeg = -Longitude;
latitude = DEGRAD * Latitude;
FromJulian(jul, &year, &mon, &day);
@@ -1919,10 +2185,10 @@ static int SunStuff(int rise, double cosz, int jul)
/* Sine of sun's declination */
sinDelta = 0.39782 * sin(DEGRAD*L);
cosDelta = sqrt(1 - sinDelta*sinDelta);
/* Cosine of sun's local hour angle */
cosH = (cosz - sinDelta * sin(latitude)) / (cosDelta * cos(latitude));
if (cosH < -1.0) { /* Summer -- permanent daylight */
if (rise) return NO_TIME;
else return -NO_TIME;
@@ -1940,9 +2206,9 @@ static int SunStuff(int rise, double cosz, int jul)
if (T >= 24.0) T -= 24.0;
else if (T < 0.0) T+= 24.0;
UT = T + longdeg / 15.0;
local = UT + (double) mins / 60.0;
if (local < 0.0) local += 24.0;
@@ -1953,7 +2219,7 @@ static int SunStuff(int rise, double cosz, int jul)
hours = (int) local;
mins = (int) ((local - hours) * 60.0);
/* Sometimes, we get roundoff error. Check for "reasonableness" of
answer. */
if (rise) {
@@ -2135,6 +2401,7 @@ static int FPsshade(func_info *info)
if (!psshade_warned) {
psshade_warned = 1;
Eprint("psshade() is deprecated; use SPECIAL SHADE instead.");
FreshLine = 1;
}
sprintf(s, "/_A LineWidth 2 div def ");
@@ -2190,6 +2457,7 @@ static int FPsmoon(func_info *info)
if (!psmoon_warned) {
psmoon_warned = 1;
Eprint("psmoon() is deprecated; use SPECIAL MOON instead.");
FreshLine = 1;
}
if (size > 0) {
sprintf(sizebuf, "%d", size);
@@ -2422,16 +2690,16 @@ static int tz_set_tz(char const *tz)
unsetenv("TZ");
r = 0;
} else {
r = setenv("TZ", tz, 1);
r = setenv("TZ", tz, 1);
}
tzset();
return r;
}
static int tz_convert(int year, int month, int day,
int hour, int minute,
char const *src_tz, char const *tgt_tz,
struct tm *tm)
int hour, int minute,
char const *src_tz, char const *tgt_tz,
struct tm *tm)
{
int r;
time_t t;
@@ -2452,28 +2720,28 @@ static int tz_convert(int year, int month, int day,
/* backup old TZ env var */
old_tz = getenv("TZ");
if (tgt_tz == NULL) {
tgt_tz = old_tz;
tgt_tz = old_tz;
}
/* set source TZ */
r = tz_set_tz(src_tz);
if (r == -1) {
return -1;
return -1;
}
/* create timestamp in UTC */
t = mktime(tm);
if (t == (time_t) -1) {
tz_set_tz(old_tz);
return -1;
tz_set_tz(old_tz);
return -1;
}
/* set target TZ */
r = tz_set_tz(tgt_tz);
if (r == -1) {
tz_set_tz(old_tz);
return -1;
tz_set_tz(old_tz);
return -1;
}
/* convert to target TZ */
@@ -2484,9 +2752,9 @@ static int tz_convert(int year, int month, int day,
/* return result */
if (res == NULL) {
return -1;
return -1;
} else {
return 1;
return 1;
}
}
@@ -2557,6 +2825,7 @@ FSlide(func_info *info)
} else {
while(amt) {
d--;
if (d < 0) return E_DATE_OVER;
r = IsOmitted(d, localomit, NULL,&omit);
if (r) return r;
if (!omit) amt++;
@@ -2697,13 +2966,17 @@ FEvalTrig(func_info *info)
return E_PARSE_ERR;
}
if (scanfrom == NO_DATE) {
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 0);
jul = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
} else {
/* Hokey... */
if (trig.scanfrom != JulianToday) {
Eprint("Warning: SCANFROM is ignored in two-argument form of evaltrig()");
}
jul = ComputeTrigger(scanfrom, &trig, &r, 0);
jul = ComputeTrigger(scanfrom, &trig, &tim, &r, 0);
}
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
r = 0;
jul = -1;
}
FreeTrig(&trig);
if (r) return r;

View File

@@ -8,7 +8,7 @@
/* globals.h and err.h */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -7,7 +7,7 @@
/* MK_GLOBALS. Also contains useful macro definitions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -21,6 +21,12 @@
#define INIT(var, val) var
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#define MAX_TRUSTED_USERS 20
#define MINUTES_PER_DAY 1440
#define DaysInYear(y) (((y) % 4) ? 365 : ((!((y) % 100) && ((y) % 400)) ? 365 : 366 ))
@@ -36,6 +42,9 @@ EXTERN int CurMon;
EXTERN int CurYear;
EXTERN int LineNo;
EXTERN int FreshLine;
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
EXTERN INIT( int NumTrustedUsers, 0);
EXTERN INIT( char const *MsgCommand, NULL);
EXTERN INIT( int ShowAllErrors, 0);
EXTERN INIT( int DebugFlag, 0);
@@ -46,12 +55,13 @@ EXTERN INIT( int DoPrefixLineNo, 0);
EXTERN INIT( int MondayFirst, 0);
EXTERN INIT( int Iterations, 1);
EXTERN INIT( int PsCal, 0);
EXTERN INIT( int CalWidth, 80);
EXTERN INIT( int CalWidth, -1);
EXTERN INIT( int CalWeeks, 0);
EXTERN INIT( int CalMonths, 0);
EXTERN INIT( int Hush, 0);
EXTERN INIT( int NextMode, 0);
EXTERN INIT( int InfiniteDelta, 0);
EXTERN INIT( int DefaultTDelta, 0);
EXTERN INIT( int DeltaOffset, 0);
EXTERN INIT( int RunDisabled, 0);
EXTERN INIT( int IgnoreOnce, 0);
@@ -73,6 +83,9 @@ EXTERN INIT( int Daemon, 0);
EXTERN INIT( char DateSep, DATESEP);
EXTERN INIT( char TimeSep, TIMESEP);
EXTERN INIT( char DateTimeSep, DATETIMESEP);
EXTERN INIT( int DefaultColorR, -1);
EXTERN INIT( int DefaultColorB, -1);
EXTERN INIT( int DefaultColorG, -1);
EXTERN INIT( int SynthesizeTags, 0);
EXTERN INIT( int ScFormat, SC_AMPM);
EXTERN INIT( int MaxSatIter, 150);
@@ -85,8 +98,10 @@ EXTERN FILE *ErrFp;
EXTERN INIT( FILE *PurgeFP, NULL);
EXTERN INIT( int NumIfs, 0);
EXTERN INIT( unsigned int IfFlags, 0);
EXTERN INIT( int LastTriggerDate, 0);
EXTERN INIT( int LastTrigValid, 0);
EXTERN Trigger LastTrigger;
EXTERN TimeTrig LastTimeTrig;
EXTERN INIT( int LastTriggerDate, 0);
EXTERN INIT( int LastTriggerTime, 0);
EXTERN INIT( int ShouldCache, 0);
EXTERN char const *CurLine;
@@ -98,6 +113,9 @@ EXTERN INIT( int CalPad, 1);
EXTERN INIT( int UseVTChars, 0);
EXTERN INIT( int UseUTF8Chars, 0);
EXTERN INIT( int UseVTColors, 0);
EXTERN INIT( int Use256Colors, 0);
EXTERN INIT( int UseTrueColors, 0);
EXTERN INIT( int TerminalBackground, TERMINAL_BACKGROUND_UNKNOWN);
/* Latitude and longitude */
EXTERN INIT( int LatDeg, LAT_DEG);
@@ -106,6 +124,9 @@ EXTERN INIT( int LatSec, LAT_SEC);
EXTERN INIT( int LongDeg, LON_DEG);
EXTERN INIT( int LongMin, LON_MIN);
EXTERN INIT( int LongSec, LON_SEC);
EXTERN INIT( double Longitude, -999.0);
EXTERN INIT( double Latitude, -999.0);
EXTERN INIT( char *Location, LOCATION);
/* UTC calculation stuff */

View File

@@ -5,7 +5,7 @@
/* Support for the Hebrew calendar */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/* Derived from code written by Amos Shapir in 1978; revised */
/* 1985. */
@@ -138,8 +138,8 @@ int DaysInHebYear(int y)
/***************************************************************/
char const *DaysInHebMonths(int ylen)
{
static char monlen[13] =
{30, 29, 30, 29, 30, 0, 29, 30, 29, 30, 29, 30, 29};
static char monlen[14] =
{30, 29, 30, 29, 30, 0, 29, 30, 29, 30, 29, 30, 29, 29};
if (ylen > 355) {

View File

@@ -7,7 +7,7 @@
/* in normal mode. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -23,6 +23,11 @@
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#include <sys/ioctl.h>
#ifdef HAVE_INITGROUPS
#include <grp.h>
#endif
#include "types.h"
#include "protos.h"
@@ -38,6 +43,7 @@
* simple calendar format.
* -r = Disallow RUN mode
* -c[n] = Produce a calendar for n months (default = 1)
* -@[n,m] = Colorize n=0 VT100 n=1 85 n=2 True m=0 dark terminal m=1 light
* -w[n,n,n] = Specify output device width, padding and spacing
* -s[n] = Produce calendar in "simple calendar" format
* -p[n] = Produce calendar in format compatible with rem2ps
@@ -70,9 +76,6 @@
* A minus sign alone indicates to take input from stdin
*
**************************************************************/
#if defined(__APPLE__) || defined(__CYGWIN__)
static void rkrphgvba(int x);
#endif
/* For parsing an integer */
#define PARSENUM(var, s) \
@@ -87,6 +90,7 @@ static void ChgUser(char const *u);
static void InitializeVar(char const *str);
static char const *BadDate = "Illegal date on command line\n";
static void AddTrustedUser(char const *username);
static DynamicBuffer default_filename_buf;
@@ -112,7 +116,7 @@ static char const *DefaultFilename(void)
s = getenv("HOME");
if (!s) {
fprintf(stderr, "HOME environment variable not set. Unable to determine reminder file.\n");
exit(1);
exit(EXIT_FAILURE);
}
DBufPuts(&default_filename_buf, s);
DBufPuts(&default_filename_buf, "/.reminders");
@@ -135,17 +139,22 @@ void InitRemind(int argc, char const *argv[])
int InvokedAsRem = 0;
char const *s;
int weeks;
int x;
int jul;
#if defined(__APPLE__)
rkrphgvba(0);
#elif defined(__CYGWIN__)
rkrphgvba(1);
#endif
jul = NO_DATE;
/* If stdout is a terminal, initialize $FormWidth to terminal width-8,
but clamp to [20, 500] */
if (isatty(STDOUT_FILENO)) {
struct winsize w;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
FormWidth = w.ws_col - 8;
if (FormWidth < 20) FormWidth = 20;
if (FormWidth > 500) FormWidth = 500;
}
}
/* Initialize global dynamic buffers */
DBufInit(&Banner);
DBufInit(&LineBuffer);
@@ -159,7 +168,7 @@ void InitRemind(int argc, char const *argv[])
if (getgid() != getegid() ||
getuid() != geteuid()) {
fprintf(ErrFp, "\nRemind should not be installed set-uid or set-gid.\nCHECK YOUR SYSTEM SECURITY.\n");
exit(1);
exit(EXIT_FAILURE);
}
y = NO_YR;
@@ -170,11 +179,14 @@ void InitRemind(int argc, char const *argv[])
RealToday = SystemDate(&CurYear, &CurMon, &CurDay);
if (RealToday < 0) {
fprintf(ErrFp, ErrMsg[M_BAD_SYS_DATE], BASE);
exit(1);
exit(EXIT_FAILURE);
}
JulianToday = RealToday;
FromJulian(JulianToday, &CurYear, &CurMon, &CurDay);
/* Initialize Latitude and Longitude */
set_lat_and_long_from_components();
/* See if we were invoked as "rem" rather than "remind" */
if (argv[0]) {
s = strrchr(argv[0], '/');
@@ -190,6 +202,7 @@ void InitRemind(int argc, char const *argv[])
/* Parse the command-line options */
i = 1;
while (i < argc) {
arg = argv[i];
if (*arg != '-') break; /* Exit the loop if it's not an option */
@@ -203,6 +216,31 @@ void InitRemind(int argc, char const *argv[])
}
while (*arg) {
switch(*arg++) {
case '+':
AddTrustedUser(arg);
while(*arg) arg++;
break;
case '@':
UseVTColors = 1;
if (*arg) {
PARSENUM(x, arg);
if (x == 1) {
Use256Colors = 1;
} else if (x == 2) {
UseTrueColors = 1;
}
}
if (*arg == ',') {
arg++;
PARSENUM(x, arg);
if (x == 0) {
TerminalBackground = TERMINAL_BACKGROUND_DARK;
} else if (x == 1) {
TerminalBackground = TERMINAL_BACKGROUND_LIGHT;
}
}
break;
case 'j':
case 'J':
@@ -246,7 +284,19 @@ void InitRemind(int argc, char const *argv[])
case 't':
case 'T':
if (!*arg) {
if (*arg == 'T' || *arg == 't') {
arg++;
if (!*arg) {
DefaultTDelta = 5;
} else {
PARSENUM(DefaultTDelta, arg);
if (DefaultTDelta < 0) {
DefaultTDelta = 0;
} else if (DefaultTDelta > 1440) {
DefaultTDelta = 1440;
}
}
} else if (!*arg) {
InfiniteDelta = 1;
} else {
PARSENUM(DeltaOffset, arg);
@@ -295,8 +345,12 @@ void InitRemind(int argc, char const *argv[])
case 'u':
case 'U':
ChgUser(arg);
RunDisabled = RUN_CMDLINE;
if (*arg == '+') {
ChgUser(arg+1);
} else {
RunDisabled = RUN_CMDLINE;
ChgUser(arg);
}
while (*arg) arg++;
break;
case 'z':
@@ -400,9 +454,21 @@ void InitRemind(int argc, char const *argv[])
case 'p':
case 'P':
DoSimpleCalendar = 1;
PsCal = 1;
if (*arg == 'a' || *arg == 'A') {
DoSimpleCalDelta = 1;
PsCal = PSCAL_LEVEL1;
while (*arg == 'a' || *arg == 'A' ||
*arg == 'p' || *arg == 'P') {
if (*arg == 'a' || *arg == 'A') {
DoSimpleCalDelta = 1;
} else if (*arg == 'p' || *arg == 'P') {
/* JSON interchange formats always include
file and line number info */
DoPrefixLineNo = 1;
if (PsCal == PSCAL_LEVEL1) {
PsCal = PSCAL_LEVEL2;
} else {
PsCal = PSCAL_LEVEL3;
}
}
arg++;
}
PARSENUM(CalMonths, arg);
@@ -418,7 +484,10 @@ void InitRemind(int argc, char const *argv[])
case 'W':
if (*arg != ',') {
PARSENUM(CalWidth, arg);
if (CalWidth < 71) CalWidth = 71;
if (CalWidth != 0 && CalWidth < 71) CalWidth = 71;
if (CalWidth == 0) {
CalWidth = -1;
}
}
if (*arg == ',') {
arg++;
@@ -485,7 +554,7 @@ void InitRemind(int argc, char const *argv[])
if (!InvokedAsRem) {
if (i >= argc) {
Usage();
exit(1);
exit(EXIT_FAILURE);
}
InitialFile = argv[i++];
} else {
@@ -583,6 +652,7 @@ void InitRemind(int argc, char const *argv[])
}
}
/* Figure out the offset from UTC */
if (CalculateUTC)
(void) CalcMinsFromUTC(JulianToday, SystemTime(0)/60,
@@ -599,7 +669,7 @@ void InitRemind(int argc, char const *argv[])
#ifndef L_USAGE_OVERRIDE
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2018 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
@@ -607,6 +677,7 @@ void Usage(void)
fprintf(ErrFp, "Options:\n");
fprintf(ErrFp, " -n Output next occurrence of reminders in simple format\n");
fprintf(ErrFp, " -r Disable RUN directives\n");
fprintf(ErrFp, " -@[n,m] Colorize COLOR reminders\n");
fprintf(ErrFp, " -c[a][n] Produce a calendar for n (default 1) months\n");
fprintf(ErrFp, " -c[a]+[n] Produce a calendar for n (default 1) weeks\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Specify width, padding and spacing of calendar\n");
@@ -631,7 +702,7 @@ void Usage(void)
fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n");
fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n");
fprintf(ErrFp, " -j[n] Run in 'purge' mode. [n = INCLUDE depth]\n");
exit(1);
exit(EXIT_FAILURE);
}
#endif /* L_USAGE_OVERRIDE */
/***************************************************************/
@@ -646,7 +717,7 @@ void Usage(void)
/***************************************************************/
static void ChgUser(char const *user)
{
uid_t myuid;
uid_t myeuid;
struct passwd *pwent;
static char *home;
@@ -654,29 +725,38 @@ static void ChgUser(char const *user)
static char *username;
static char *logname;
myuid = getuid();
myeuid = geteuid();
pwent = getpwnam(user);
if (!pwent) {
fprintf(ErrFp, ErrMsg[M_BAD_USER], user);
exit(1);
exit(EXIT_FAILURE);
}
if (!myuid && setgid(pwent->pw_gid)) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
exit(1);
}
if (!myeuid) {
/* Started as root, so drop privileges */
#ifdef HAVE_INITGROUPS
if (initgroups(pwent->pw_name, pwent->pw_gid) < 0) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
exit(EXIT_FAILURE);
};
#endif
if (setgid(pwent->pw_gid) < 0) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
exit(EXIT_FAILURE);
}
if (!myuid && setuid(pwent->pw_uid)) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid);
exit(1);
if (setuid(pwent->pw_uid) < 0) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid);
exit(EXIT_FAILURE);
}
}
home = malloc(strlen(pwent->pw_dir) + 6);
if (!home) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(home, "HOME=%s", pwent->pw_dir);
putenv(home);
@@ -684,7 +764,7 @@ static void ChgUser(char const *user)
shell = malloc(strlen(pwent->pw_shell) + 7);
if (!shell) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(shell, "SHELL=%s", pwent->pw_shell);
putenv(shell);
@@ -693,14 +773,14 @@ static void ChgUser(char const *user)
username = malloc(strlen(pwent->pw_name) + 6);
if (!username) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(username, "USER=%s", pwent->pw_name);
putenv(username);
logname= malloc(strlen(pwent->pw_name) + 9);
if (!logname) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(logname, "LOGNAME=%s", pwent->pw_name);
putenv(logname);
@@ -773,6 +853,7 @@ static void InitializeVar(char const *str)
if (*varname == '$') {
r=SetSysVar(varname+1, &val);
DestroyValue(val);
if (r) fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
return;
}
@@ -787,46 +868,22 @@ static void InitializeVar(char const *str)
return;
}
#if defined(__APPLE__) || defined(__CYGWIN__)
static char const pmsg1[] = {
0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20,
0x67, 0x62, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x68, 0x61, 0x61, 0x76,
0x61, 0x74, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x62,
0x61, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x63, 0x63, 0x79, 0x72, 0x20,
0x63, 0x65, 0x62, 0x71, 0x68, 0x70, 0x67, 0x2e, 0x20, 0x20, 0x56,
0x27, 0x71, 0x20, 0x65, 0x6e, 0x67, 0x75, 0x72, 0x65, 0x20, 0x67,
0x75, 0x6e, 0x67, 0x0a, 0x6c, 0x62, 0x68, 0x20, 0x71, 0x76, 0x71,
0x61, 0x27, 0x67, 0x2e, 0x20, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61,
0x71, 0x20, 0x72, 0x6b, 0x72, 0x70, 0x68, 0x67, 0x76, 0x62, 0x61,
0x20, 0x6a, 0x76, 0x79, 0x79, 0x20, 0x70, 0x62, 0x61, 0x67, 0x76,
0x61, 0x68, 0x72, 0x20, 0x7a, 0x62, 0x7a, 0x72, 0x61, 0x67, 0x6e,
0x65, 0x76, 0x79, 0x6c, 0x2e, 0x0a, 0x00
};
static char const pmsg2[] = {
0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20,
0x67, 0x62, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x68, 0x61, 0x61, 0x76,
0x61, 0x74, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x62,
0x61, 0x20, 0x6e, 0x20, 0x5a, 0x76, 0x70, 0x65, 0x62, 0x66, 0x62,
0x73, 0x67, 0x20, 0x66, 0x6c, 0x66, 0x67, 0x72, 0x7a, 0x2e, 0x20,
0x20, 0x56, 0x27, 0x71, 0x20, 0x65, 0x6e, 0x67, 0x75, 0x72, 0x65,
0x20, 0x67, 0x75, 0x6e, 0x67, 0x0a, 0x6c, 0x62, 0x68, 0x20, 0x71,
0x76, 0x71, 0x61, 0x27, 0x67, 0x2e, 0x20, 0x20, 0x45, 0x72, 0x7a,
0x76, 0x61, 0x71, 0x20, 0x72, 0x6b, 0x72, 0x70, 0x68, 0x67, 0x76,
0x62, 0x61, 0x20, 0x6a, 0x76, 0x79, 0x79, 0x20, 0x70, 0x62, 0x61,
0x67, 0x76, 0x61, 0x68, 0x72, 0x20, 0x7a, 0x62, 0x7a, 0x72, 0x61,
0x67, 0x6e, 0x65, 0x76, 0x79, 0x6c, 0x2e, 0x0a, 0x00
};
static void
rkrphgvba(int x)
AddTrustedUser(char const *username)
{
char const *s = (x ? pmsg2 : pmsg1);
while(*s) {
int c = (int) *s++;
c=isalpha(c)?tolower(c)<0x6e?c+13:c-13:c;
putchar(c);
struct passwd *pwent;
if (NumTrustedUsers >= MAX_TRUSTED_USERS) {
fprintf(stderr, "Too many trusted users (%d max)\n",
MAX_TRUSTED_USERS);
exit(EXIT_FAILURE);
}
sleep(5);
pwent = getpwnam(username);
if (!pwent) {
fprintf(ErrFp, ErrMsg[M_BAD_USER], username);
exit(EXIT_FAILURE);
}
TrustedUsers[NumTrustedUsers] = pwent->pw_uid;
NumTrustedUsers++;
}
#endif

1045
src/json.c Normal file

File diff suppressed because it is too large Load Diff

280
src/json.h Normal file
View File

@@ -0,0 +1,280 @@
/* vim: set et ts=3 sw=3 sts=3 ft=c:
*
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
* https://github.com/udp/json-parser
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _JSON_H
#define _JSON_H
#ifndef json_char
#define json_char char
#endif
#ifndef json_int_t
#ifndef _MSC_VER
#include <inttypes.h>
#define json_int_t int64_t
#else
#define json_int_t __int64
#endif
#endif
#include <stdlib.h>
#ifdef __cplusplus
#include <string.h>
extern "C"
{
#endif
typedef struct
{
unsigned long max_memory;
int settings;
/* Custom allocator support (leave null to use malloc/free)
*/
void * (* mem_alloc) (size_t, int zero, void * user_data);
void (* mem_free) (void *, void * user_data);
void * user_data; /* will be passed to mem_alloc and mem_free */
size_t value_extra; /* how much extra space to allocate for values? */
} json_settings;
#define json_enable_comments 0x01
typedef enum
{
json_none,
json_object,
json_array,
json_integer,
json_double,
json_string,
json_boolean,
json_null
} json_type;
extern const struct _json_value json_value_none;
typedef struct _json_object_entry
{
json_char * name;
unsigned int name_length;
struct _json_value * value;
} json_object_entry;
typedef struct _json_value
{
struct _json_value * parent;
json_type type;
union
{
int boolean;
json_int_t integer;
double dbl;
struct
{
unsigned int length;
json_char * ptr; /* null terminated */
} string;
struct
{
unsigned int length;
json_object_entry * values;
#if defined(__cplusplus) && __cplusplus >= 201103L
decltype(values) begin () const
{ return values;
}
decltype(values) end () const
{ return values + length;
}
#endif
} object;
struct
{
unsigned int length;
struct _json_value ** values;
#if defined(__cplusplus) && __cplusplus >= 201103L
decltype(values) begin () const
{ return values;
}
decltype(values) end () const
{ return values + length;
}
#endif
} array;
} u;
union
{
struct _json_value * next_alloc;
void * object_mem;
} _reserved;
#ifdef JSON_TRACK_SOURCE
/* Location of the value in the source JSON
*/
unsigned int line, col;
#endif
/* Some C++ operator sugar */
#ifdef __cplusplus
public:
inline _json_value ()
{ memset (this, 0, sizeof (_json_value));
}
inline const struct _json_value &operator [] (int index) const
{
if (type != json_array || index < 0
|| ((unsigned int) index) >= u.array.length)
{
return json_value_none;
}
return *u.array.values [index];
}
inline const struct _json_value &operator [] (const char * index) const
{
if (type != json_object)
return json_value_none;
for (unsigned int i = 0; i < u.object.length; ++ i)
if (!strcmp (u.object.values [i].name, index))
return *u.object.values [i].value;
return json_value_none;
}
inline operator const char * () const
{
switch (type)
{
case json_string:
return u.string.ptr;
default:
return "";
};
}
inline operator json_int_t () const
{
switch (type)
{
case json_integer:
return u.integer;
case json_double:
return (json_int_t) u.dbl;
default:
return 0;
};
}
inline operator bool () const
{
if (type != json_boolean)
return false;
return u.boolean != 0;
}
inline operator double () const
{
switch (type)
{
case json_integer:
return (double) u.integer;
case json_double:
return u.dbl;
default:
return 0;
};
}
#endif
} json_value;
json_value * json_parse (const json_char * json,
size_t length);
#define json_error_max 128
json_value * json_parse_ex (json_settings * settings,
const json_char * json,
size_t length,
char * error);
void json_value_free (json_value *);
/* Not usually necessary, unless you used a custom mem_alloc and now want to
* use a custom mem_free.
*/
void json_value_free_ex (json_settings * settings,
json_value *);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -5,7 +5,7 @@
/* Header file for language support for various languages. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -6,7 +6,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2018 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
/* This file is Copyright (C) 1993 by Mogens Lynnerup. */
/* */
/***************************************************************/

View File

@@ -11,7 +11,7 @@
/* Further corrections by Erik-Jan Vens */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Support for the English language. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -11,7 +11,7 @@
/* */
/* This file is part of REMIND. */
/* This file is Copyright (C) 1993-1998 by Mikko Silvonen. */
/* REMIND is Copyright (C) 1992-2018 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -302,7 +302,8 @@ EXTERN char *ErrMsg[] =
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice"
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#elif IBMEXTENDED
"Ok",
@@ -407,7 +408,8 @@ EXTERN char *ErrMsg[] =
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice"
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#else
"Ok",
@@ -512,7 +514,8 @@ EXTERN char *ErrMsg[] =
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice"
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#endif
@@ -524,7 +527,7 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2018 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETAVERSIO <<<<\n");
#endif

View File

@@ -8,7 +8,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2018 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
/* This file is Copyright (C) 1993 by Laurent Duperval and */
/* Dianne Skoll. */
/* */
@@ -242,7 +242,8 @@ EXTERN char *ErrMsg[] =
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice"
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#else /* ISOLATIN1 */
"Ok",
@@ -347,7 +348,8 @@ EXTERN char *ErrMsg[] =
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice"
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#endif /* ISOLATIN1 */
};
#endif /* MK_GLOBALS */
@@ -357,7 +359,7 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2018 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif

View File

@@ -9,7 +9,7 @@
/* I don't speak German. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Support for the Icelandic language. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* Translated by Björn Davíðsson (bjossi@snerpa.is) */
/* */
/***************************************************************/

View File

@@ -7,7 +7,7 @@
/* This file is part of REMIND. */
/* It is Copyright (C) 1996 by Valerio Aimale */
/* */
/* Remind is copyright (C) 1992-2018 by Dianne Skoll */
/* Remind is copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -6,7 +6,7 @@
/* */
/* This file is part of REMIND. */
/* This file is Copyright (C) 1993 by Trygve Randen. */
/* Remind is Copyright (C) 1992-2018 by Dianne Skoll */
/* Remind is Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -9,7 +9,7 @@
/* Polish. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -281,7 +281,8 @@ EXTERN char *ErrMsg[] =
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice"
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#else /* ISOLATIN1 */
"OK",
"Brakujacy ']'",
@@ -385,7 +386,8 @@ EXTERN char *ErrMsg[] =
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice"
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#endif /* ISOLATIN1 */
};
#endif /* MK_GLOBALS */
@@ -395,7 +397,7 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2018 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif

View File

@@ -8,7 +8,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2018 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
/* This file is Copyright (C) 1996 by Marco Paganini and */
/* Dianne Skoll. */
/* */
@@ -247,7 +247,8 @@ EXTERN char *ErrMsg[] =
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice"
"Time specified twice",
"Cannot specify DURATION without specifying AT"
};
#endif /* MK_GLOBALS */
@@ -256,7 +257,7 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-2018 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> VERSAO BETA <<<<\n");
#endif

View File

@@ -1,4 +1,4 @@
!/***************************************************************/
/***************************************************************/
/* */
/* ROMANIAN.H */
/* */
@@ -8,7 +8,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2018 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
/* This file is Copyright (C) 1996-1998 by Liviu Daia */
/* */
/***************************************************************/

View File

@@ -7,7 +7,7 @@
/* Author: Rafa Couto <rafacouto@biogate.com> */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -6,7 +6,7 @@
/* routines, etc. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -63,14 +63,16 @@ int main(int argc, char *argv[])
setlocale(LC_ALL, "");
#endif
/* The very first thing to do is to set up ErrFp to be stderr */
/* The very first thing to do is to set up ErrFp to be stderr */
ErrFp = stderr;
/* Set up global vars */
/* Set up global vars */
ArgC = argc;
ArgV = (char const **) argv;
InitRemind(argc, (char const **) argv);
ClearLastTriggers();
if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) {
ProduceCalendar();
return 0;
@@ -125,10 +127,7 @@ int main(int argc, char *argv[])
}
}
if (Iterations) {
ClearGlobalOmits();
DestroyOmitContexts();
DestroyVars(0);
NumTriggered = 0;
PerIterationInit();
JulianToday++;
}
}
@@ -146,6 +145,19 @@ void PurgeEchoLine(char const *fmt, ...)
}
void
PerIterationInit(void)
{
ClearGlobalOmits();
DestroyOmitContexts();
DestroyVars(0);
DefaultColorR = -1;
DefaultColorG = -1;
DefaultColorB = -1;
NumTriggered = 0;
ClearLastTriggers();
}
/***************************************************************/
/* */
/* DoReminders */
@@ -223,12 +235,22 @@ static void DoReminders(void)
case T_Else: r=DoElse(&p); break;
case T_EndIf: r=DoEndif(&p); break;
case T_Include:
case T_IncludeR:
/* In purge mode, include closes file, so we
need to echo it here! */
if (PurgeMode) {
PurgeEchoLine("%s\n", CurLine);
}
r=DoInclude(&p);
r=DoInclude(&p, tok.type);
purge_handled = 1;
break;
case T_IncludeCmd:
/* In purge mode, include closes file, so we
need to echo it here! */
if (PurgeMode) {
PurgeEchoLine("%s\n", CurLine);
}
r=DoIncludeCmd(&p);
purge_handled = 1;
break;
case T_Exit: DoExit(&p); break;
@@ -713,7 +735,7 @@ int DoIf(ParsePtr p)
int r;
unsigned syndrome;
if (NumIfs >= IF_NEST) return E_NESTED_IF;
if ((size_t) NumIfs >= IF_NEST) return E_NESTED_IF;
if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE;
else {
@@ -794,13 +816,20 @@ int DoIfTrig(ParsePtr p)
int jul;
if (NumIfs >= IF_NEST) return E_NESTED_IF;
if ((size_t) NumIfs >= IF_NEST) return E_NESTED_IF;
if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE;
else {
if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r;
if (trig.typ != NO_TYPE) return E_PARSE_ERR;
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1);
if (r) syndrome = IF_TRUE | BEFORE_ELSE;
jul = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
if (r) {
if (r != E_CANT_TRIG || !trig.maybe_uncomputable) {
if (!Hush || r != E_RUN_DISABLED) {
Eprint("%s", ErrMsg[r]);
}
}
syndrome = IF_TRUE | BEFORE_ELSE;
}
else {
if (ShouldTriggerReminder(&trig, &tim, jul, &err)) {
syndrome = IF_TRUE | BEFORE_ELSE;
@@ -1302,6 +1331,7 @@ void UTCToLocal(int utcdate, int utctime, int *locdate, int *loctime)
void SigIntHandler(int d)
{
UNUSED(d);
signal(SIGINT, SigIntHandler);
GotSigInt();
exit(0);
@@ -1321,3 +1351,67 @@ FreeTrig(Trigger *t)
{
DBufFree(&(t->tags));
}
void
ClearLastTriggers(void)
{
LastTrigger.expired = 0;
LastTrigger.wd = NO_WD;
LastTrigger.d = NO_DAY;
LastTrigger.m = NO_MON;
LastTrigger.y = NO_YR;
LastTrigger.back = NO_BACK;
LastTrigger.delta = NO_DELTA;
LastTrigger.rep = NO_REP;
LastTrigger.localomit = NO_WD;
LastTrigger.skip = NO_SKIP;
LastTrigger.until = NO_UNTIL;
LastTrigger.typ = NO_TYPE;
LastTrigger.once = NO_ONCE;
LastTrigger.scanfrom = NO_DATE;
LastTrigger.from = NO_DATE;
LastTrigger.priority = DefaultPrio;
LastTrigger.sched[0] = 0;
LastTrigger.warn[0] = 0;
LastTrigger.omitfunc[0] = 0;
LastTrigger.passthru[0] = 0;
LastTimeTrig.ttime = NO_TIME;
LastTimeTrig.delta = NO_DELTA;
LastTimeTrig.rep = NO_REP;
LastTimeTrig.duration = NO_TIME;
}
void
SaveAllTriggerInfo(Trigger const *t, TimeTrig const *tt, int trigdate, int trigtime, int valid)
{
SaveLastTrigger(t);
SaveLastTimeTrig(tt);
LastTriggerDate = trigdate;
LastTriggerTime = trigtime;
LastTrigValid = valid;
}
void
SaveLastTrigger(Trigger const *t)
{
memcpy(&LastTrigger, t, sizeof(LastTrigger));
DBufInit(&(LastTrigger.tags));
}
void
SaveLastTimeTrig(TimeTrig const *t)
{
memcpy(&LastTimeTrig, t, sizeof(LastTimeTrig));
}
/* Wrapper to ignore warnings about ignoring return value of system() */
void
System(char const *cmd)
{
int r;
r = system(cmd);
if (r == 0) {
r = 1;
}
}

View File

@@ -5,7 +5,7 @@
/* Calculations for figuring out moon phases. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -6,7 +6,7 @@
/* the data structures for OMITted dates. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -370,20 +370,30 @@ int DoOmit(ParsePtr p)
NumPartialOmits++;
}
} else {
if (NumFullOmits == MAX_FULL_OMITS) return E_2MANY_FULL;
if (d > DaysInMonth(m, y)) return E_BAD_DATE;
syndrome = Julian(y, m, d);
if (!BexistsIntArray(FullOmitArray, NumFullOmits, syndrome)) {
InsertIntoSortedArray(FullOmitArray, NumFullOmits, syndrome);
NumFullOmits++;
}
r = AddGlobalOmit(syndrome);
if (r) {
return r;
}
}
if (tok.type == T_Tag || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
return OK;
}
int
AddGlobalOmit(int jul)
{
if (NumFullOmits == MAX_FULL_OMITS) return E_2MANY_FULL;
if (!BexistsIntArray(FullOmitArray, NumFullOmits, jul)) {
InsertIntoSortedArray(FullOmitArray, NumFullOmits, jul);
NumFullOmits++;
}
return OK;
}
static int
DoThroughOmit(ParsePtr p, int ystart, int mstart, int dstart)
{
@@ -453,6 +463,7 @@ DoThroughOmit(ParsePtr p, int ystart, int mstart, int dstart)
end = Julian(yend, mend, dend);
if (end < start) {
Eprint("Warning: Swapping dates on OMIT ... THROUGH ... line");
tmp = start;
start = end;
end = tmp;

View File

@@ -5,10 +5,13 @@
/* Function Prototypes. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
/* Suppress unused variable warnings */
#define UNUSED(x) (void) x
/* Define a string assignment macro - be careful!!! */
#define STRSET(x, str) { if (x) free(x); (x) = StrDup(str); }
@@ -34,13 +37,15 @@ int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int jul, int *err);
int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul, int mode);
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int jul, int tim);
int ParseLiteralDate (char const **s, int *jul, int *tim);
int ParseLiteralTime (char const **s, int *tim);
int EvalExpr (char const **e, Value *v, ParsePtr p);
int DoCoerce (char type, Value *v);
void PrintValue (Value *v, FILE *fp);
int CopyValue (Value *dest, const Value *src);
int ReadLine (void);
int OpenFile (char const *fname);
int DoInclude (ParsePtr p);
int DoInclude (ParsePtr p, enum TokTypes tok);
int DoIncludeCmd (ParsePtr p);
int IncludeFile (char const *fname);
int GetAccessDate (char const *file);
int SetAccessDate (char const *fname, int jul);
@@ -85,7 +90,10 @@ void HandleQueuedReminders (void);
char const *FindInitialToken (Token *tok, char const *s);
void FindToken (char const *s, Token *tok);
void FindNumericToken (char const *s, Token *t);
int ComputeTrigger (int today, Trigger *trig, int *err, int save_in_globals);
int ComputeTrigger (int today, Trigger *trig, TimeTrig *tim, int *err, int save_in_globals);
int ComputeTriggerNoAdjustDuration (int today, Trigger *trig, TimeTrig *tim, int *err, int save_in_globals, int duration_days);
int AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int save_in_globals);
int ComputeScanStart(int today, Trigger *trig, TimeTrig *tt);
char *StrnCpy (char *dest, char const *source, int n);
int StrMatch (char const *s1, char const *s2, int n);
int StrinCmp (char const *s1, char const *s2, int n);
@@ -102,7 +110,7 @@ void DumpVarTable (void);
void DestroyVars (int all);
int PreserveVar (char const *name);
int DoPreserve (Parser *p);
int DoSatRemind (Trigger *trig, TimeTrig *tim, ParsePtr p);
int DoSatRemind (Trigger *trig, TimeTrig *tt, ParsePtr p);
int DoMsgCommand (char const *cmd, char const *msg);
int ParseNonSpaceChar (ParsePtr p, int *err, int peek);
unsigned int HashVal (char const *str);
@@ -139,3 +147,22 @@ void PurgeEchoLine(char const *fmt, ...);
void FreeTrig(Trigger *t);
void AppendTag(DynamicBuffer *buf, char const *s);
char const *SynthesizeTag(void);
void ClearLastTriggers(void);
void SaveLastTrigger(Trigger const *t);
void SaveLastTimeTrig(TimeTrig const *t);
void SaveAllTriggerInfo(Trigger const *t, TimeTrig const *tt, int trigdate, int trigtime, int valid);
void PerIterationInit(void);
char const *Decolorize(int r, int g, int b);
char const *Colorize(int r, int g, int b);
void PrintJSONString(char const *s);
void PrintJSONKeyPairInt(char const *name, int val);
void PrintJSONKeyPairString(char const *name, char const *val);
void PrintJSONKeyPairDate(char const *name, int jul);
void PrintJSONKeyPairDateTime(char const *name, int dt);
void PrintJSONKeyPairTime(char const *name, int t);
void System(char const *cmd);
int ShellEscape(char const *in, DynamicBuffer *out);
int AddGlobalOmit(int jul);
void set_lat_and_long_from_components(void);
void set_components_from_lat_and_long(void);

View File

@@ -5,7 +5,7 @@
/* Queue up reminders for subsequent execution. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -27,9 +27,9 @@
#include <stdlib.h>
#include <unistd.h>
#include "types.h"
#include "globals.h"
#include "err.h"
#include "types.h"
#include "protos.h"
#include "expr.h"
@@ -43,6 +43,7 @@ typedef struct queuedrem {
char passthru[PASSTHRU_LEN+1];
char sched[VAR_NAME_LEN+1];
DynamicBuffer tags;
Trigger t;
TimeTrig tt;
} QueuedRem;
@@ -56,7 +57,7 @@ static void CheckInitialFile (void);
static int CalculateNextTime (QueuedRem *q);
static QueuedRem *FindNextReminder (void);
static int CalculateNextTimeUsingSched (QueuedRem *q);
static void DaemonWait (unsigned int sleeptime);
static void DaemonWait (struct timeval *sleep_tv);
static void reread (void);
/***************************************************************/
@@ -91,6 +92,8 @@ int QueueReminder(ParsePtr p, Trigger *trig,
qelem->typ = trig->typ;
strcpy(qelem->passthru, trig->passthru);
qelem->tt = *tim;
qelem->t = *trig;
DBufInit(&(qelem->t.tags));
qelem->next = QueueHead;
qelem->RunDisabled = RunDisabled;
qelem->ntrig = 0;
@@ -118,6 +121,8 @@ void HandleQueuedReminders(void)
unsigned SleepTime;
Parser p;
Trigger trig;
struct timeval tv;
struct timeval sleep_tv;
/* Suppress the BANNER from being issued */
NumTriggered = 1;
@@ -179,20 +184,24 @@ void HandleQueuedReminders(void)
while (TimeToSleep > 0L) {
SleepTime = TimeToSleep;
if (Daemon > 0 && SleepTime > 60*Daemon) SleepTime = 60*Daemon;
if (Daemon > 0 && SleepTime > (unsigned int) 60*Daemon) SleepTime = 60*Daemon;
/* Wake up once a minute to recalibrate sleep time in
case of laptop hibernation */
if (Daemon <= 0) {
if (Daemon < 0) {
/* Wake up on the next exact minute */
SleepTime = 60 - (SystemTime(1)%60);
}
if (Daemon >= 0) {
sleep(SleepTime);
gettimeofday(&tv, NULL);
sleep_tv.tv_sec = 60 - (tv.tv_sec % 60);
if (tv.tv_usec != 0 && sleep_tv.tv_sec != 0) {
sleep_tv.tv_sec--;
sleep_tv.tv_usec = 1000000 - tv.tv_usec;
} else {
sleep_tv.tv_usec = 0;
}
DaemonWait(&sleep_tv);
} else {
DaemonWait(SleepTime);
}
sleep(SleepTime);
}
/* If not in daemon mode and day has rolled around,
exit -- not much we can do. */
@@ -243,9 +252,7 @@ void HandleQueuedReminders(void)
/* Set up global variables so some functions like trigdate()
and trigtime() work correctly */
LastTriggerDate = JulianToday;
LastTriggerTime = q->tt.ttime;
LastTrigValid = 1;
SaveAllTriggerInfo(&(q->t), &(q->tt), JulianToday, q->tt.ttime, 1);
(void) TriggerReminder(&p, &trig, &q->tt, JulianToday);
if (Daemon < 0) {
printf("NOTE endreminder\n");
@@ -447,6 +454,70 @@ static int CalculateNextTimeUsingSched(QueuedRem *q)
}
}
/* Dump the queue in JSON format */
static void
json_queue(QueuedRem const *q)
{
int done = 0;
printf("[");
while(q) {
if (q->tt.nexttime == NO_TIME) {
q = q->next;
continue;
}
if (done) {
printf(",");
}
done = 1;
printf("{");
switch(q->typ) {
case NO_TYPE: PrintJSONKeyPairString("type", "NO_TYPE"); break;
case MSG_TYPE: PrintJSONKeyPairString("type", "MSG_TYPE"); break;
case RUN_TYPE: PrintJSONKeyPairString("type", "RUN_TYPE"); break;
case CAL_TYPE: PrintJSONKeyPairString("type", "CAL_TYPE"); break;
case SAT_TYPE: PrintJSONKeyPairString("type", "SAT_TYPE"); break;
case PS_TYPE: PrintJSONKeyPairString("type", "PS_TYPE"); break;
case PSF_TYPE: PrintJSONKeyPairString("type", "PSF_TYPE"); break;
case MSF_TYPE: PrintJSONKeyPairString("type", "MSF_TYPE"); break;
case PASSTHRU_TYPE: PrintJSONKeyPairString("type", "PASSTHRU_TYPE"); break;
default: PrintJSONKeyPairString("type", "?"); break;
}
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
PrintJSONKeyPairInt("ntrig", q->ntrig);
PrintJSONKeyPairTime("ttime", q->tt.ttime);
PrintJSONKeyPairTime("nextttime", q->tt.nexttime);
PrintJSONKeyPairInt("delta", q->tt.delta);
if (q->tt.rep != NO_TIME) {
PrintJSONKeyPairInt("rep", q->tt.rep);
}
if (q->tt.duration != NO_TIME) {
PrintJSONKeyPairInt("duration", q->tt.duration);
}
if (q->passthru[0]) {
PrintJSONKeyPairString("passthru", q->passthru);
}
if (q->sched[0]) {
PrintJSONKeyPairString("sched", q->sched);
}
if (DBufLen(&(q->tags))) {
PrintJSONKeyPairString("tags", DBufValue(&(q->tags)));
}
/* Last one is a special case - no trailing comma */
printf("\"");
PrintJSONString("body");
printf("\":\"");
if (q->text) {
PrintJSONString(q->text);
} else {
PrintJSONString("");
}
printf("\"}");
q = q->next;
}
printf("]\n");
}
/***************************************************************/
/* */
/* DaemonWait */
@@ -454,19 +525,16 @@ static int CalculateNextTimeUsingSched(QueuedRem *q)
/* Sleep or read command from stdin in "daemon -1" mode */
/* */
/***************************************************************/
static void DaemonWait(unsigned int sleeptime)
static void DaemonWait(struct timeval *sleep_tv)
{
fd_set readSet;
struct timeval timeout;
int retval;
int y, m, d;
char cmdLine[256];
FD_ZERO(&readSet);
FD_SET(0, &readSet);
timeout.tv_sec = sleeptime;
timeout.tv_usec = 0;
retval = select(1, &readSet, NULL, NULL, &timeout);
retval = select(1, &readSet, NULL, NULL, sleep_tv);
/* If date has rolled around, restart */
if (RealToday != SystemDate(&y, &m, &d)) {
@@ -508,28 +576,34 @@ static void DaemonWait(unsigned int sleeptime)
printf("NOTE queue\n");
QueuedRem *q = QueueHead;
while (q) {
switch (q->typ) {
case NO_TYPE: printf("NO_TYPE "); break;
case MSG_TYPE: printf("MSG_TYPE "); break;
case RUN_TYPE: printf("RUN_TYPE "); break;
case CAL_TYPE: printf("CAL_TYPE "); break;
case SAT_TYPE: printf("SAT_TYPE "); break;
case PS_TYPE: printf("PS_TYPE "); break;
case PSF_TYPE: printf("PSF_TYPE "); break;
case MSF_TYPE: printf("MSF_TYPE "); break;
case PASSTHRU_TYPE: printf("PASSTHRU_TYPE "); break;
default: printf("? "); break;
if (q->tt.nexttime != NO_TIME) {
switch (q->typ) {
case NO_TYPE: printf("NO_TYPE "); break;
case MSG_TYPE: printf("MSG_TYPE "); break;
case RUN_TYPE: printf("RUN_TYPE "); break;
case CAL_TYPE: printf("CAL_TYPE "); break;
case SAT_TYPE: printf("SAT_TYPE "); break;
case PS_TYPE: printf("PS_TYPE "); break;
case PSF_TYPE: printf("PSF_TYPE "); break;
case MSF_TYPE: printf("MSF_TYPE "); break;
case PASSTHRU_TYPE: printf("PASSTHRU_TYPE "); break;
default: printf("? "); break;
}
printf("RunDisabled=%d ntrig=%d ttime=%02d:%02d nexttime=%02d:%02d delta=%d rep=%d duration=%d ", q->RunDisabled, q->ntrig, q->tt.ttime/60, q->tt.ttime % 60, q->tt.nexttime / 60, q->tt.nexttime % 60, q->tt.delta, (q->tt.rep != NO_TIME ? q->tt.rep : -1), (q->tt.duration != NO_TIME ? q->tt.duration : -1));
printf("%s %s %s\n",
(q->passthru[0] ? q->passthru : "*"),
(q->sched[0] ? q->sched : "*"),
q->text ? q->text : "NULL");
}
printf("RunDisabled=%d ntrig=%d ttime=%02d:%02d nexttime=%02d:%02d delta=%d rep=%d duration=%d ", q->RunDisabled, q->ntrig, q->tt.ttime/60, q->tt.ttime % 60, q->tt.nexttime / 60, q->tt.nexttime % 60, q->tt.delta, (q->tt.rep != NO_TIME ? q->tt.rep : -1), (q->tt.duration != NO_TIME ? q->tt.duration : -1));
printf("%s %s %s\n",
(q->passthru[0] ? q->passthru : "*"),
(q->sched[0] ? q->sched : "*"),
q->text ? q->text : "NULL");
q = q->next;
}
printf("NOTE endqueue\n");
fflush(stdout);
} else if (!strcmp(cmdLine, "JSONQUEUE\n")) {
printf("NOTE JSONQUEUE\n");
json_queue(QueueHead);
printf("NOTE ENDJSONQUEUE\n");
fflush(stdout);
} else if (!strcmp(cmdLine, "REREAD\n")) {
printf("NOTE reread\n");
fflush(stdout);

View File

@@ -5,7 +5,7 @@
/* Print a PostScript calendar. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -20,6 +20,7 @@
#include <unistd.h>
#include <stdlib.h>
#include "rem2ps.h"
#include "json.h"
#define NEW(type) (malloc(sizeof(type)))
@@ -30,6 +31,7 @@
#define SPECIAL_COLOR 4
#define SPECIAL_WEEK 5
#define SPECIAL_SHADE 6
#define SPECIAL_UNKNOWN 7
/* Array holding how specials sort */
static int SpecialSortOrder[] = {
@@ -46,6 +48,7 @@ typedef struct calentry {
struct calentry *next;
int special;
char *entry;
int daynum;
} CalEntry;
typedef struct {
@@ -62,7 +65,7 @@ char const *SmallCalLoc[] = {
"sbt",
};
#define NUMSMALL (sizeof(SmallCalLoc)/sizeof(SmallCalLoc[0]))
#define NUMSMALL ((int) (sizeof(SmallCalLoc)/sizeof(SmallCalLoc[0])))
char const *SmallLocation;
int SmallCol1, SmallCol2;
@@ -96,6 +99,7 @@ CalEntry *CurEntries = NULL;
CalEntry *PsEntries[32];
PageType *CurPage;
char PortraitMode;
char DaynumRight;
char NoSmallCal;
char UseISO;
@@ -137,6 +141,184 @@ void WriteOneEntry (CalEntry *c);
void GetSmallLocations (void);
char const *EatToken(char const *in, char *out, int maxlen);
static void
put_escaped_string(char const *s)
{
while(*s) {
if (*s == '\\' || *s == '(' || *s == ')') {
PutChar('\\');
}
PutChar(*s);
s++;
}
}
/***************************************************************/
/* */
/* StrCmpi */
/* */
/* Compare strings, case insensitive. */
/* */
/***************************************************************/
int StrCmpi(char const *s1, char const *s2)
{
int r;
while (*s1 && *s2) {
r = toupper(*s1) - toupper(*s2);
if (r) return r;
s1++;
s2++;
}
return toupper(*s1) - toupper(*s2);
}
/***************************************************************/
/* */
/* Parse the new-style JSON intermediate format */
/* */
/***************************************************************/
static CalEntry *
JSONToCalEntry(DynamicBuffer *buf)
{
CalEntry *c;
json_value *val;
val = json_parse(DBufValue(buf), DBufLen(buf));
if (!val) {
fprintf(stderr, "Unable to parse JSON line `%s'\n", DBufValue(buf));
exit(1);
}
if (val->type != json_object) {
fprintf(stderr, "Expecting JSON object; found `%s'\n",
DBufValue(buf));
exit(1);
}
c = NEW(CalEntry);
if (!c) {
fprintf(stderr, "malloc failed - aborting.\n");
exit(1);
}
c->next = NULL;
c->special = SPECIAL_NORMAL;
int got_date = 0, got_body = 0;
size_t i;
for (i=0; i<val->u.object.length; i++) {
char const *nm = val->u.object.values[i].name;
json_value *v = val->u.object.values[i].value;
char const *s;
if (!strcmp(nm, "date")) {
if (v->type == json_string) {
s = v->u.string.ptr;
c->daynum = (s[8] - '0') * 10 + s[9] - '0';
got_date = 1;
}
} else if (!strcmp(nm, "body")) {
if (v->type == json_string) {
s = v->u.string.ptr;
c->entry = malloc(strlen(s)+1);
if (!c->entry) {
fprintf(stderr, "malloc failed - aborting.\n");
exit(1);
}
strcpy(c->entry, s);
got_body = 1;
}
} else if (!strcmp(nm, "passthru")) {
if (v->type == json_string) {
s = v->u.string.ptr;
if (!StrCmpi(s, "PostScript")) {
c->special = SPECIAL_POSTSCRIPT;
} else if (!StrCmpi(s, "SHADE")) {
c->special = SPECIAL_SHADE;
} else if (!StrCmpi(s, "MOON")) {
c->special = SPECIAL_MOON;
} else if (!StrCmpi(s, "WEEK")) {
c->special = SPECIAL_WEEK;
} else if (!StrCmpi(s, "PSFile")) {
c->special = SPECIAL_PSFILE;
} else if (!StrCmpi(s, "COLOUR") ||
!StrCmpi(s, "COLOR")) {
c->special = SPECIAL_COLOR;
} else {
c->special = SPECIAL_UNKNOWN;
}
}
}
}
json_value_free(val);
if (!got_body || !got_date) {
fprintf(stderr, "Could not parse line `%s'\n", DBufValue(buf));
exit(1);
}
return c;
}
/***************************************************************/
/* */
/* Parse the old-style REM2PS intermediate format */
/* */
/***************************************************************/
static CalEntry *
TextToCalEntry(DynamicBuffer *buf)
{
char const *startOfBody;
char passthru[PASSTHRU_LEN+1];
CalEntry *c = NEW(CalEntry);
if (!c) {
fprintf(stderr, "malloc failed - aborting.\n");
exit(1);
}
c->next = NULL;
c->special = SPECIAL_NORMAL;
c->daynum = (DBufValue(buf)[8] - '0') * 10 + DBufValue(buf)[9] - '0';
/* Skip the tag, duration and time */
startOfBody = DBufValue(buf)+10;
/* Eat the passthru */
startOfBody = EatToken(startOfBody, passthru, PASSTHRU_LEN);
/* Eat the tag */
startOfBody = EatToken(startOfBody, NULL, 0);
/* Eat the duration */
startOfBody = EatToken(startOfBody, NULL, 0);
/* Eat the time */
startOfBody = EatToken(startOfBody, NULL, 0);
c->entry = malloc(strlen(startOfBody) + 1);
if (!c->entry) {
fprintf(stderr, "malloc failed - aborting.\n");
exit(1);
}
strcpy(c->entry, startOfBody);
/* Save the type of SPECIAL */
if (!StrCmpi(passthru, "PostScript")) {
c->special = SPECIAL_POSTSCRIPT;
} else if (!StrCmpi(passthru, "SHADE")) {
c->special = SPECIAL_SHADE;
} else if (!StrCmpi(passthru, "MOON")) {
c->special = SPECIAL_MOON;
} else if (!StrCmpi(passthru, "WEEK")) {
c->special = SPECIAL_WEEK;
} else if (!StrCmpi(passthru, "PSFile")) {
c->special = SPECIAL_PSFILE;
} else if (!StrCmpi(passthru, "COLOUR") ||
!StrCmpi(passthru, "COLOR")) {
c->special = SPECIAL_COLOR;
} else if (StrCmpi(passthru, "*")) {
c->special = SPECIAL_UNKNOWN;
}
return c;
}
/***************************************************************/
/* */
/* MAIN PROGRAM */
@@ -154,13 +336,20 @@ int main(int argc, char *argv[])
Usage("Input should not come from a terminal");
}
int first_line = 1;
/* Search for a valid input file */
while (!feof(stdin)) {
DBufGets(&buf, stdin);
if (!strcmp(DBufValue(&buf), PSBEGIN)) {
if (first_line && (!strcmp(DBufValue(&buf), "["))) {
fprintf(stderr, "Rem2PS: It appears that you have invoked Remind with the -ppp option.\n Please use either -p or -pp, but not -ppp.\n");
exit(1);
}
first_line = 0;
if (!strcmp(DBufValue(&buf), PSBEGIN) ||
!strcmp(DBufValue(&buf), PSBEGIN2)) {
if (!validfile) {
if (Verbose) {
fprintf(stderr, "Rem2PS: Version %s Copyright 1992-1998 by Dianne Skoll\n\n", VERSION);
fprintf(stderr, "Rem2PS: Version %s Copyright 1992-2021 by Dianne Skoll\n\n", VERSION);
fprintf(stderr, "Generating PostScript calendar\n");
}
}
@@ -191,10 +380,7 @@ void DoPsCal(void)
int days, wkday, prevdays, nextdays;
int sfirst;
int i;
int is_ps;
int firstcol;
char const *startOfBody;
char passthru[PASSTHRU_LEN+1];
DynamicBuffer buf;
CalEntry *c, *d, *p;
@@ -230,6 +416,7 @@ void DoPsCal(void)
printf("%%%%Page: %c%c%c%c%c %d\n", month[0], month[1], month[2],
year[2], year[3], validfile);
printf("%%%%PageBoundingBox: 0 0 %d %d\n", CurPage->xsize, CurPage->ysize);
/* Emit PostScript to do the heading */
if (!PortraitMode) printf("90 rotate 0 XSIZE neg translate\n");
@@ -272,80 +459,48 @@ void DoPsCal(void)
}
DBufGets(&buf, stdin);
if (!strcmp(DBufValue(&buf), PSEND)) {
if (!strcmp(DBufValue(&buf), PSEND) ||
!strcmp(DBufValue(&buf), PSEND2)) {
DBufFree(&buf);
break;
}
/* Ignore lines beginning with '#' */
if (DBufValue(&buf)[0] == '#') {
DBufFree(&buf);
continue;
}
/* Read the day number - a bit of a hack! */
DayNum = (DBufValue(&buf)[8] - '0') * 10 + DBufValue(&buf)[9] - '0';
if (DayNum != CurDay) {
for(; CurDay<DayNum; CurDay++) {
if (DBufValue(&buf)[0] == '{') {
/* Starts with '{', so assume new-style JSON format */
c = JSONToCalEntry(&buf);
} else {
/* Assume it's the old-style rem2ps intermediate format */
c = TextToCalEntry(&buf);
}
/* If it's an unknown special, ignore */
if (c->special == SPECIAL_UNKNOWN) {
DBufFree(&buf);
free(c);
c = NULL;
continue;
}
if (c->daynum != CurDay) {
for(; CurDay<c->daynum; CurDay++) {
WriteCalEntry();
WkDayNum = (WkDayNum + 1) % 7;
}
}
/* Add the text */
c = NEW(CalEntry);
if (!c) {
fprintf(stderr, "malloc failed - aborting.\n");
exit(1);
}
c->next = NULL;
c->special = SPECIAL_NORMAL;
/* Skip the tag, duration and time */
startOfBody = DBufValue(&buf)+10;
/* Eat the passthru */
startOfBody = EatToken(startOfBody, passthru, PASSTHRU_LEN);
/* Eat the tag */
startOfBody = EatToken(startOfBody, NULL, 0);
/* Eat the duration */
startOfBody = EatToken(startOfBody, NULL, 0);
/* Eat the time */
startOfBody = EatToken(startOfBody, NULL, 0);
is_ps = 0;
if (!strcmp(passthru, "PostScript") ||
!strcmp(passthru, "PSFile") ||
!strcmp(passthru, "MOON") ||
!strcmp(passthru, "WEEK") ||
!strcmp(passthru, "SHADE")) {
is_ps = 1;
}
c->entry = malloc(strlen(startOfBody) + 1);
if (!c->entry) {
fprintf(stderr, "malloc failed - aborting.\n");
exit(1);
}
strcpy(c->entry, startOfBody);
if (is_ps) {
/* Save the type of SPECIAL */
if (!strcmp(passthru, "PostScript")) {
c->special = SPECIAL_POSTSCRIPT;
} else if (!strcmp(passthru, "SHADE")) {
c->special = SPECIAL_SHADE;
} else if (!strcmp(passthru, "MOON")) {
c->special = SPECIAL_MOON;
} else if (!strcmp(passthru, "WEEK")) {
c->special = SPECIAL_WEEK;
if (c->special == SPECIAL_POSTSCRIPT ||
c->special == SPECIAL_SHADE ||
c->special == SPECIAL_MOON ||
c->special == SPECIAL_WEEK ||
c->special == SPECIAL_PSFILE) {
if (!PsEntries[c->daynum]) {
PsEntries[c->daynum] = c;
} else {
c->special = SPECIAL_PSFILE;
}
if (!PsEntries[DayNum]) {
PsEntries[DayNum] = c;
} else {
d = PsEntries[DayNum];
d = PsEntries[c->daynum];
p = NULL;
/* Slot it into the right place */
while (d->next && (SpecialSortOrder[c->special] <= SpecialSortOrder[d->special])) {
@@ -359,14 +514,12 @@ void DoPsCal(void)
if (p) {
p->next = c;
} else {
PsEntries[DayNum] = c;
PsEntries[c->daynum] = c;
}
c->next = d;
}
}
} else if (!strcmp(passthru, "*") ||
!strcmp(passthru, "COLOUR") ||
!strcmp(passthru, "COLOR")) {
} else {
/* Put on linked list */
if (!CurEntries) {
CurEntries = c;
@@ -375,10 +528,6 @@ void DoPsCal(void)
while(d->next) d = d->next;
d->next = c;
}
if (!strcmp(passthru, "COLOR") ||
!strcmp(passthru, "COLOUR")) {
c->special = SPECIAL_COLOR;
}
}
}
for(; CurDay<=days; CurDay++) {
@@ -451,6 +600,12 @@ void WriteProlog(void)
printf("%%%%Pages: (atend)\n");
printf("%%%%Orientation: %s\n", PortraitMode ? "Portrait" : "Landscape");
printf("%%%%EndComments\n");
if (PortraitMode) {
printf("<< /PageSize [%d %d] >> setpagedevice\n", x, y);
} else {
/* They were swapped up above, so swap them back or we'll get rotated output */
printf("<< /PageSize [%d %d] >> setpagedevice\n", y, x);
}
for (i=0; PSProlog1[i]; i++) puts(PSProlog1[i]);
if (!MondayFirst)
@@ -543,7 +698,7 @@ void WriteCalEntry(void)
printf("]\n");
/* Print the day number */
printf("(%d)\n", CurDay);
printf("(%d) %d\n", CurDay, (int) DaynumRight);
/* Do it! */
printf("DoCalBox\n");
@@ -669,7 +824,8 @@ void Init(int argc, char *argv[])
char const *s;
char const *t;
int i=1;
int j;
size_t j;
int k;
int offset;
PortraitMode = 1;
@@ -682,6 +838,7 @@ void Init(int argc, char *argv[])
FillPage = 0;
MondayFirst = 0;
SmallLocation = "bt";
DaynumRight = 1;
for(j=0; j<32; j++) PsEntries[i] = NULL;
@@ -798,13 +955,14 @@ void Init(int argc, char *argv[])
case 'i': UseISO = 1; break;
case 'c': j=(*s);
if (!j) {
case 'x': DaynumRight = 0; break;
case 'c': k=(*s);
if (!k) {
SmallLocation = SmallCalLoc[0];
} else {
j -= '0';
if (j>=0 && j<NUMSMALL) {
SmallLocation = SmallCalLoc[j];
k -= '0';
if (k>=0 && k<NUMSMALL) {
SmallLocation = SmallCalLoc[k];
} else {
SmallLocation = SmallCalLoc[0];
}
@@ -842,6 +1000,7 @@ void Usage(char const *s)
fprintf(stderr, "-b size Set border size for calendar entries\n");
fprintf(stderr, "-t size Set line thickness\n");
fprintf(stderr, "-e Make calendar fill entire page\n");
fprintf(stderr, "-x Put day numbers on left instead of right\n");
fprintf(stderr, "-o[lrtb] marg Specify left, right, top and bottom margins\n");
exit(1);
}
@@ -917,10 +1076,10 @@ int DoQueuedPs(void)
FILE *fp;
int fnoff;
char buffer[512];
char const *size, *extra;
char fbuffer[512];
char const *size, *fsize, *extra;
char const *s;
int num, r, g, b, phase, fontsize, moonsize;
unsigned char c;
if (!MondayFirst) begin = CurDay - WkDayNum;
else begin = CurDay - (WkDayNum ? WkDayNum-1 : 6);
@@ -992,19 +1151,28 @@ int DoQueuedPs(void)
while(*s && isspace(*s)) {
s++;
}
while(*s) {
if (*s == '\\' || *s == '(' || *s == ')') {
PutChar('\\');
}
PutChar(*s);
s++;
}
put_escaped_string(s);
printf(") show grestore\n");
break;
case SPECIAL_MOON: /* Moon phase */
num = sscanf(e->entry+fnoff, "%d %d %d", &phase, &moonsize,
&fontsize);
/* See if we have extra stuff */
extra = e->entry+fnoff;
/* Skip phase */
while(*extra && !isspace(*extra)) extra++;
while(*extra && isspace(*extra)) extra++;
/* Skip moon size */
while(*extra && !isspace(*extra)) extra++;
while(*extra && isspace(*extra)) extra++;
/* Skip font size */
while(*extra && !isspace(*extra)) extra++;
while(*extra && isspace(*extra)) extra++;
if (num == 1) {
moonsize = -1;
fontsize = -1;
@@ -1026,7 +1194,27 @@ int DoQueuedPs(void)
size = buffer;
}
printf("gsave 0 setgray newpath Border %s add BoxHeight Border sub %s sub\n", size, size);
/* Store the starting X coordinate in "moonstartx" */
if (DaynumRight) {
printf("Border %s add /moonstartx exch def", size);
} else {
printf("xincr Border sub %s sub ", size);
if (*extra) {
if (fontsize < 0) {
fsize = "EntrySize";
} else {
sprintf(fbuffer, "%d", fontsize);
fsize = fbuffer;
}
printf("/EntryFont findfont %s scalefont setfont (",
fsize);
put_escaped_string(extra);
printf(") stringwidth pop sub Border sub ");
}
printf("/moonstartx exch def\n");
}
printf(" gsave 0 setgray newpath ");
printf("moonstartx BoxHeight Border sub %s sub\n", size);
printf(" %s 0 360 arc closepath\n", size);
switch(phase) {
case 0:
@@ -1037,49 +1225,28 @@ int DoQueuedPs(void)
break;
case 1:
printf("stroke\n");
printf("newpath Border %s add BoxHeight Border sub %s sub\n",
size, size);
printf("stroke\nnewpath ");
printf("moonstartx BoxHeight Border sub %s sub\n", size);
printf("%s 90 270 arc closepath fill\n", size);
break;
default:
printf("stroke\n");
printf("newpath Border %s add BoxHeight Border sub %s sub\n",
size, size);
printf("stroke\nnewpath ");
printf("moonstartx BoxHeight Border sub %s sub\n", size);
printf("%s 270 90 arc closepath fill\n", size);
break;
}
/* See if we have extra stuff */
extra = e->entry+fnoff;
/* Skip phase */
while(*extra && !isspace(*extra)) extra++;
while(*extra && isspace(*extra)) extra++;
/* Skip moon size */
while(*extra && !isspace(*extra)) extra++;
while(*extra && isspace(*extra)) extra++;
/* Skip font size */
while(*extra && !isspace(*extra)) extra++;
while(*extra && isspace(*extra)) extra++;
/* Anything left? */
if (*extra) {
printf("Border %s add %s add Border add BoxHeight border sub %s sub %s sub moveto\n", size, size, size, size);
printf("moonstartx %s add Border add BoxHeight border sub %s sub %s sub moveto\n", size, size, size);
if (fontsize < 0) {
size = "EntrySize";
fsize = "EntrySize";
} else {
sprintf(buffer, "%d", fontsize);
size = buffer;
sprintf(fbuffer, "%d", fontsize);
fsize = fbuffer;
}
printf("/EntryFont findfont %s scalefont setfont (",
size);
while(*extra) {
c = (unsigned char) *extra++;
if (c == '\\' || c == '(' || c == ')') PutChar('\\');
PutChar(c);
}
fsize);
put_escaped_string(extra);
printf(") show\n");
}

View File

@@ -5,7 +5,7 @@
/* Define the PostScript prologue */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -13,7 +13,7 @@ char *PSProlog1[] =
{
"% This file was produced by Remind and Rem2PS, written by",
"% Dianne Skoll.",
"% Remind and Rem2PS are Copyright 1992-1997 Dianne Skoll.",
"% Remind and Rem2PS are Copyright 1992-2021 Dianne Skoll.",
"/ISOLatin1Encoding where { pop save true }{ false } ifelse",
" /ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus",
" StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute",
@@ -196,9 +196,10 @@ char *PSProlog2[] =
"% Variables for calendar boxes:",
"% ytop - current top position",
"% ymin - minimum y reached for current row",
"% border ytop xleft width textarray daynum DoCalBox ybot",
"% border ytop xleft width textarray daynum onright DoCalBox ybot",
"% Do the entries for one calendar box. Returns lowest Y-coordinate reached",
"/DoCalBox {",
" /onright exch def",
" /daynum exch def",
" /textarr exch def",
" /wid exch def",
@@ -207,8 +208,10 @@ char *PSProlog2[] =
" /border exch def",
"% Do the day number",
" /DayFont findfont DaySize scalefont setfont",
" xl wid add border sub daynum stringwidth pop sub",
" yt border sub DaySize sub moveto daynum show",
" onright 1 eq",
" {xl wid add border sub daynum stringwidth pop sub yt border sub DaySize sub moveto daynum show}",
" {xl border add yt border sub DaySize sub moveto daynum show}",
" ifelse",
"% Do the text entries. Precharge the stack with current y pos.",
" /ycur yt border sub DaySize sub DaySize sub 2 add def",
" /EntryFont findfont EntrySize scalefont setfont",

View File

@@ -5,7 +5,7 @@
/* Routines for sorting reminders by trigger date */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -150,7 +150,7 @@ void IssueSortedReminders(void)
break;
case RUN_TYPE:
system(cur->text);
System(cur->text);
break;
}

View File

@@ -6,7 +6,7 @@
/* classifying the tokens parsed. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -37,7 +37,7 @@ while (isdigit(*(string))) { \
Keep this array sorted, or software will not work. */
Token TokArray[] = {
/* NAME MINLEN TYPE VALUE */
{ "addomit", 7, T_AddOmit, 0 },
{ "after", 3, T_Skip, AFTER_SKIP },
{ "april", 3, T_Month, 3 },
{ "at", 2, T_At, 0 },
@@ -48,6 +48,7 @@ Token TokArray[] = {
{ "clear-omit-context", 5, T_Clr, 0 },
{ "debug", 5, T_Debug, 0 },
{ "december", 3, T_Month, 11 },
{ "do", 2, T_IncludeR, 0 },
{ "dumpvars", 4, T_Dumpvars, 0 },
{ "duration", 3, T_Duration, 0 },
{ "else", 4, T_Else, 0 },
@@ -62,11 +63,13 @@ Token TokArray[] = {
{ "if", 2, T_If, 0 },
{ "iftrig", 6, T_IfTrig, 0 },
{ "include", 3, T_Include, 0 },
{ "includecmd", 10, T_IncludeCmd, 0 },
{ "january", 3, T_Month, 0 },
{ "july", 3, T_Month, 6 },
{ "june", 3, T_Month, 5 },
{ "march", 3, T_Month, 2 },
{ "may", 3, T_Month, 4 },
{ "maybe-uncomputable", 5, T_MaybeUncomputable, 0},
{ "monday", 3, T_WkDay, 0 },
{ "msf", 3, T_RemType, MSF_TYPE },
{ "msg", 3, T_RemType, MSG_TYPE },
@@ -171,6 +174,10 @@ void FindToken(char const *s, Token *tok)
int top, bot, mid, r, max;
int l;
#if LANG != ENGLISH
size_t i;
#endif
tok->type = T_Illegal;
if (! *s) {
tok->type = T_Empty;
@@ -228,11 +235,11 @@ void FindToken(char const *s, Token *tok)
/* If language is other than English, search the DayNames[] and MonthNames[]
array. */
#if LANG != ENGLISH
for (r=0; r<(sizeof(NonEnglishToks) / sizeof(Token)); r++) {
if (l >= NonEnglishToks[r].MinLen &&
!TokStrCmp(&NonEnglishToks[r], s)) {
tok->type = NonEnglishToks[r].type;
tok->val = NonEnglishToks[r].val;
for (i=0; i<(sizeof(NonEnglishToks) / sizeof(Token)); i++) {
if (l >= NonEnglishToks[i].MinLen &&
!TokStrCmp(&NonEnglishToks[i], s)) {
tok->type = NonEnglishToks[i].type;
tok->val = NonEnglishToks[i].val;
return;
}
}
@@ -257,6 +264,7 @@ void FindNumericToken(char const *s, Token *t)
{
int mult = 1, hour, min;
char const *s_orig = s;
int ampm = 0;
t->type = T_Illegal;
t->val = 0;
@@ -284,10 +292,6 @@ void FindNumericToken(char const *s, Token *t)
like Jan 6, 1998 */
if (*s == ',') {
s++;
/* Special hack - convert years between 90 and
99 to 1990 and 1999 */
if (t->val >= 90 && t->val <= 99) t->val += 1900;
/* Classify the number we've got */
if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
else if (t->val >= 1 && t->val <= 31) t->type = T_Day;
@@ -299,7 +303,29 @@ void FindNumericToken(char const *s, Token *t)
s++;
hour = t->val;
PARSENUM(min, s);
if (*s || min > 59) return; /* Illegal time */
if (min > 59) return; /* Illegal time */
/* Check for p[m] or a[m] */
if (*s == 'A' || *s == 'a' || *s == 'P' || *s == 'p') {
ampm = tolower(*s);
s++;
if (*s == 'm' || *s == 'M') {
s++;
}
}
if (*s) return; /* Illegal time */
if (ampm) {
if (hour < 1 || hour > 12) return;
if (ampm == 'a') {
if (hour == 12) {
hour = 0;
}
} else if (ampm == 'p') {
if (hour < 12) {
hour += 12;
}
}
}
t->val = hour*60 + min; /* Convert to minutes past midnight */
if (hour <= 23) {
t->type = T_Time;
@@ -312,9 +338,6 @@ void FindNumericToken(char const *s, Token *t)
/* If we hit a non-digit, error! */
if (*s) return;
/* Special hack - convert years between 90 and 99 to 1990 and 1999 */
if (t->val >= 90 && t->val <= 99) t->val += 1900;
/* Classify the number we've got */
if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
else if (t->val >= 1 && t->val <= 31) t->type = T_Day;

View File

@@ -5,7 +5,7 @@
/* Routines for figuring out the trigger date of a reminder */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -24,6 +24,8 @@
#define GOT_YR 4
#define GOT_WD 8
#define ADVANCE_TO_WD(x, wd) while (! ((wd) & (1 << ((x)%7)))) (x)++
static int JYear(int jul);
static int JMonth(int jul);
static int NextSimpleTrig(int startdate, Trigger *trig, int *err);
@@ -58,9 +60,10 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
if (trig->wd != NO_WD) typ |= GOT_WD;
switch(typ) {
case 0:
return startdate;
case GOT_WD:
if (trig->wd != NO_WD)
while(! (trig->wd & (1 << (startdate%7)))) startdate++;
ADVANCE_TO_WD(startdate, trig->wd);
return startdate;
case GOT_DAY:
@@ -83,12 +86,12 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
else return -1;
case GOT_DAY+GOT_MON:
if (m > trig->m || (m == trig->m && d > trig->d)) y++;
if (trig->d > MonthDays[trig->m]) {
*err = E_BAD_DATE;
return -1;
}
if (m > trig->m || (m == trig->m && d > trig->d)) y++;
/* Take care of Feb. 29 */
while (trig->d > DaysInMonth(trig->m, y)) y++;
return Julian(y, trig->m, trig->d);
@@ -121,19 +124,19 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
if (y > trig->y) return -1;
if (y < trig->y) j = Julian(trig->y, 0, 1);
else j = startdate;
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (JYear(j) > trig->y) return -1;
return j;
case GOT_MON+GOT_WD:
if (m == trig->m) {
j = startdate;
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (JMonth(j) == trig->m) return j;
}
if (m >= trig->m) j = Julian(y+1, trig->m, 1);
else j = Julian(y, trig->m, 1);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j; /* Guaranteed to be within the month */
case GOT_DAY+GOT_WD:
@@ -144,7 +147,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
/* If there are fewer days in previous month, no match */
if (trig->d <= DaysInMonth(m2, y2)) {
j = Julian(y2, m2, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (j >= startdate) return j;
}
@@ -153,7 +156,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
/* Try this month */
if (trig->d <= DaysInMonth(m, y)) {
j = Julian(y, m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (j >= startdate) return j;
}
@@ -162,18 +165,18 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
if (m2 > 11) { m2 = 0; y++; }
while (trig->d > DaysInMonth(m2, y)) m2++;
j = Julian(y, m2, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j;
case GOT_WD+GOT_YR+GOT_DAY:
if (y > trig->y+1 || (y > trig->y && m>0)) return -1;
if (y > trig->y) {
j = Julian(trig->y, 11, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (j >= startdate) return j;
} else if (y < trig->y) {
j = Julian(trig->y, 0, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j;
} else {
/* Try last month */
@@ -181,14 +184,16 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
m2 = m-1;
while (trig->d > DaysInMonth(m2, trig->y)) m2--;
j = Julian(trig->y, m2, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (JYear(j) > trig->y) return -1;
if (j >= startdate) return j;
}
}
/* Try this month */
if (trig->d <= DaysInMonth(m, trig->y)) {
j = Julian(trig->y, m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (JYear(j) > trig->y) return -1;
if (j >= startdate) return j;
}
@@ -197,7 +202,8 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
m++;
while (trig->d > DaysInMonth(m, trig->d)) m++;
j = Julian(trig->y, m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (JYear(j) > trig->y) return -1;
return j;
case GOT_DAY+GOT_MON+GOT_WD:
@@ -215,31 +221,32 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
/* Try last year */
j = Julian(y, trig->m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (j >= startdate) return j;
/* Try this year */
y++;
while (trig->d > DaysInMonth(trig->m, y)) y++;
j = Julian(y, trig->m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (j >= startdate) return j;
/* Must be next year */
y++;
while (trig->d > DaysInMonth(trig->m, y)) y++;
j = Julian(y, trig->m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j;
case GOT_WD+GOT_MON+GOT_YR:
if (y > trig->y || (y == trig->y && m > trig->m)) return -1;
if (trig->y > y || (trig->y == y && trig->m > m)) {
j = Julian(trig->y, trig->m, 1);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j;
} else {
j = startdate;
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
FromJulian(j, &y2, &m2, &d2);
if (m2 == trig->m) return j; else return -1;
}
@@ -250,7 +257,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
return -1;
}
j = Julian(trig->y, trig->m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j;
default:
@@ -408,6 +415,57 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
return simple;
}
int
AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int save_in_globals)
{
int y, m, d;
/* If we have an AT, save the original event start */
if (tim->ttime != NO_TIME) {
trig->eventstart = MINUTES_PER_DAY * r + tim->ttime;
if (tim->duration != NO_TIME) {
trig->eventduration = tim->duration;
}
}
/* Now potentially adjust */
if (r < today && r + trig->duration_days >= today) {
/* Adjust duration down */
tim->duration -= (today - r) * MINUTES_PER_DAY;
tim->duration += tim->ttime;
/* Start at midnight */
tim->ttime = 0;
/* Change trigger date to today */
r = today;
if (DebugFlag & DB_PRTTRIG) {
FromJulian(r, &y, &m, &d);
fprintf(ErrFp, "%s(%d): Trig(adj) = %s, %d %s, %d",
FileName, LineNo,
DayName[r % 7],
d,
MonthName[m],
y);
if (tim->ttime != NO_TIME) {
fprintf(ErrFp, " AT %02d:%02d",
(tim->ttime / 60),
(tim->ttime % 60));
if (tim->duration != NO_TIME) {
fprintf(ErrFp, " DURATION %02d:%02d",
(tim->duration / 60),
(tim->duration % 60));
}
}
fprintf(ErrFp, "\n");
}
}
if (save_in_globals) {
SaveAllTriggerInfo(trig, tim, r, tim->ttime, 1);
}
return r;
}
/***************************************************************/
/* */
/* ComputeTrigger */
@@ -416,10 +474,49 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
/* today's date. */
/* */
/***************************************************************/
int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
int ComputeTrigger(int today, Trigger *trig, TimeTrig *tim,
int *err, int save_in_globals)
{
int r = ComputeTriggerNoAdjustDuration(today, trig, tim, err, save_in_globals, 0);
if (*err != OK) {
return r;
}
if (r == today) {
if (tim->ttime != NO_TIME) {
trig->eventstart = MINUTES_PER_DAY * r + tim->ttime;
if (tim->duration != NO_TIME) {
trig->eventduration = tim->duration;
}
}
if (save_in_globals) {
SaveAllTriggerInfo(trig, tim, r, tim->ttime, 1);
}
return r;
}
if (trig->duration_days) {
r = ComputeTriggerNoAdjustDuration(today, trig, tim, err, save_in_globals, trig->duration_days);
if (*err != OK) {
return r;
}
}
r = AdjustTriggerForDuration(today, r, trig, tim, save_in_globals);
return r;
}
/***************************************************************/
/* */
/* ComputeTriggerNoAdjustDuration */
/* */
/* Compute a trigger, but do NOT adjust the time trigger */
/* duration. */
/* */
/***************************************************************/
int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
int *err, int save_in_globals, int duration_days)
{
int nattempts = 0,
start = today,
start = today - duration_days,
nextstart = 0,
y, m, d, omit,
result;
@@ -429,15 +526,25 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
LastTrigValid = 0;
}
/* Assume everything works */
/* Assume everything works */
*err = OK;
/* But check for obvious problems... */
/* But check for obvious problems... */
if (trig->localomit == 1 + 2 + 4 + 8 + 16 + 32 + 64) {
*err = E_2MANY_LOCALOMIT;
return -1;
}
if (start < 0) {
*err = E_DATE_OVER;
return -1;
}
if (tim->duration != NO_TIME && tim->ttime == NO_TIME) {
*err = E_DURATION_NO_AT;
return -1;
}
if (trig->rep != NO_REP &&
(trig->d == NO_DAY ||
trig->m == NO_MON ||
@@ -448,6 +555,11 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
}
/* Save the trigger */
if (save_in_globals) {
SaveLastTrigger(trig);
}
while (nattempts++ < TRIG_ATTEMPTS) {
result = GetNextTriggerDate(trig, start, err, &nextstart);
@@ -469,7 +581,9 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
} else {
omit = 0;
}
if (result >= today &&
/** FIXME: Fix bad interaction with SATISFY... need to rethink!!! */
if (result+duration_days >= today &&
(trig->skip != SKIP_SKIP || !omit)) {
if (save_in_globals) {
LastTriggerDate = result; /* Save in global var */
@@ -477,12 +591,23 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
}
if (DebugFlag & DB_PRTTRIG) {
FromJulian(result, &y, &m, &d);
fprintf(ErrFp, "%s(%d): Trig = %s, %d %s, %d\n",
fprintf(ErrFp, "%s(%d): Trig = %s, %d %s, %d",
FileName, LineNo,
DayName[result % 7],
d,
MonthName[m],
y);
if (tim->ttime != NO_TIME) {
fprintf(ErrFp, " AT %02d:%02d",
(tim->ttime / 60),
(tim->ttime % 60));
if (tim->duration != NO_TIME) {
fprintf(ErrFp, " DURATION %02d:%02d",
(tim->duration / 60),
(tim->duration % 60));
}
}
fprintf(ErrFp, "\n");
}
return result;
}
@@ -535,3 +660,41 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
*err = E_CANT_TRIG;
return -1;
}
/***************************************************************/
/* */
/* ComputeScanStart */
/* */
/* Figure out where to start scan from by examining SCANFROM */
/* and DURATION */
/* */
/***************************************************************/
int
ComputeScanStart(int today, Trigger *trig, TimeTrig *tt)
{
int minutes, days;
/* If we don't have a time/duration, just use scanfrom */
if (tt->ttime == NO_TIME ||
tt->duration == NO_TIME) {
if (trig->scanfrom == NO_DATE) {
return today;
}
return trig->scanfrom;
}
/* Calculate time-based SCANFROM */
minutes = tt->ttime + tt->duration - 1;
/* Figure out how many days to scan backwards from */
days = minutes / MINUTES_PER_DAY;
if (trig->scanfrom != NO_DATE) {
if (trig->scanfrom <= today - days) {
return trig->scanfrom;
} else {
return today - days;
}
}
return today - days;
}

View File

@@ -5,7 +5,7 @@
/* Type definitions all dumped here. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -68,7 +68,13 @@ typedef struct {
int typ;
int once;
int scanfrom;
int from;
int priority;
int duration_days; /* Duration converted to days to search */
int eventstart; /* Original event start (datetime) */
int eventduration; /* Original event duration (minutes) */
int maybe_uncomputable; /* Suppress "can't compute trigger" warnings */
int addomit; /* Add trigger date to global OMITs */
char sched[VAR_NAME_LEN+1]; /* Scheduling function */
char warn[VAR_NAME_LEN+1]; /* Warning function */
char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */
@@ -87,16 +93,16 @@ typedef struct {
/* The parse pointer */
typedef struct {
char isnested; /* Is it a nested expression? */
char allownested;
DynamicBuffer pushedToken; /* Pushed-back token */
char const *text; /* Start of text */
char const *pos; /* Current position */
char const *etext; /* Substituted text */
char const *epos; /* Position in substituted text */
DynamicBuffer pushedToken; /* Pushed-back token */
char const *tokenPushed; /* NULL if no pushed-back token */
char expr_happened; /* Did we encounter an [expression] ? */
char nonconst_expr; /* Did we encounter a non-constant [expression] ? */
unsigned char isnested; /* Is it a nested expression? */
unsigned char allownested;
unsigned char expr_happened; /* Did we encounter an [expression] ? */
unsigned char nonconst_expr; /* Did we encounter a non-constant [expression] ? */
} Parser;
typedef Parser *ParsePtr; /* Pointer to parser structure */
@@ -145,9 +151,10 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
enum TokTypes
{ T_Illegal,
/* Commands first */
T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_If, T_Else, T_EndIf,
T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_IncludeR, T_IncludeCmd, T_If, T_Else, T_EndIf,
T_IfTrig, T_ErrMsg,
T_Set, T_UnSet, T_Fset, T_Omit, T_Banner, T_Exit,
T_AddOmit,
T_WkDay,
T_Month, T_Time, T_Date, T_DateTime,
T_Skip, T_At, T_RemType, T_Until, T_Year, T_Day, T_Rep, T_Delta, T_Back,
@@ -167,7 +174,8 @@ enum TokTypes
T_Duration,
T_LongTime,
T_OmitFunc,
T_Through
T_Through,
T_MaybeUncomputable
};
/* The structure of a token */
@@ -212,3 +220,18 @@ typedef struct {
/* Flags for FROM / SCANFROM */
#define SCANFROM_TYPE 0
#define FROM_TYPE 1
/* PS Calendar levels */
/* Original interchange format */
#define PSCAL_LEVEL1 1
/* Line-by-line JSON */
#define PSCAL_LEVEL2 2
/* Pure JSON */
#define PSCAL_LEVEL3 3
#define TERMINAL_BACKGROUND_UNKNOWN 0
#define TERMINAL_BACKGROUND_DARK 1
#define TERMINAL_BACKGROUND_LIGHT 2

View File

@@ -6,7 +6,7 @@
/* functions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -64,6 +64,7 @@ int DoFset(ParsePtr p)
int c;
UserFunc *func;
Var *v;
int orig_namelen;
DynamicBuffer buf;
DBufInit(&buf);
@@ -74,6 +75,7 @@ int DoFset(ParsePtr p)
DBufFree(&buf);
return E_BAD_ID;
}
orig_namelen = buf.len;
/* Should be followed by '(' */
c = ParseNonSpaceChar(p, &r, 0);
@@ -94,9 +96,8 @@ int DoFset(ParsePtr p)
StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN);
DBufFree(&buf);
if (!Hush) {
if (FindFunc(DBufValue(&buf), Func, NumFuncs)) {
Eprint("%s: `%s'", ErrMsg[E_REDEF_FUNC],
DBufValue(&buf));
if (FindFunc(func->name, Func, NumFuncs)) {
Eprint("%s: `%s'", ErrMsg[E_REDEF_FUNC], func->name);
}
}
func->locals = NULL;
@@ -118,6 +119,7 @@ int DoFset(ParsePtr p)
if ( (r=ParseIdentifier(p, &buf)) ) return r;
if (*DBufValue(&buf) == '$') {
DBufFree(&buf);
DestroyUserFunc(func);
return E_BAD_ID;
}
v = NEW(Var);
@@ -164,6 +166,10 @@ int DoFset(ParsePtr p)
/* Add the function definition */
FSet(func);
if (orig_namelen > VAR_NAME_LEN) {
Eprint("Warning: Function name `%s...' truncated to `%s'",
func->name, func->name);
}
return OK;
}
@@ -273,7 +279,7 @@ int CallUserFunc(char const *name, int nargs, ParsePtr p)
}
return E_RECURSIVE;
}
/* Check number of args */
if (nargs != f->nargs) {
if (DebugFlag &DB_PRTEXPR) {

View File

@@ -5,11 +5,15 @@
/* Useful utility functions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
static char const DontEscapeMe[] =
"1234567890_-=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.,/";
#include "config.h"
#include "err.h"
#include <string.h>
#include <stdio.h>
@@ -123,3 +127,38 @@ int DateOK(int y, int m, int d)
d > DaysInMonth(m, y) ) return 0;
else return 1;
}
/* Functions designed to defeat gcc optimizer */
int _private_div(int a, int b) { return a/b; }
int _private_add_overflow(int result, int b, int old)
{
if (b > 0 && result < old) return 1;
if (b < 0 && result > old) return 1;
return 0;
}
int _private_sub_overflow(int result, int b, int old)
{
if (b < 0 && result < old) return 1;
if (b > 0 && result > old) return 1;
return 0;
}
int _private_unminus_overflow(int a, int b)
{
if (a > 0 && b > 0) return 1;
if (a < 0 && b < 0) return 1;
return 0;
}
int
ShellEscape(char const *in, DynamicBuffer *out)
{
while(*in) {
if (!strchr(DontEscapeMe, *in)) {
if (DBufPutc(out, '\\') != OK) return E_NO_MEM;
}
if (DBufPutc(out, *in++) != OK) return E_NO_MEM;
}
return OK;
}

239
src/var.c
View File

@@ -6,7 +6,7 @@
/* user- and system-defined variables. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2018 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -17,6 +17,8 @@
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include "types.h"
#include "expr.h"
#include "globals.h"
@@ -31,12 +33,109 @@
#define VALUE ErrMsg[E_VAL]
#define UNDEF ErrMsg[E_UNDEF]
static int IntMin = INT_MIN;
static int IntMax = INT_MAX;
static Var *VHashTbl[VAR_HASH_SIZE];
typedef int (*SysVarFunc)(int, Value *);
static void deprecated_var(char const *var, char const *instead)
{
if (DebugFlag & DB_PRTLINE) {
Eprint("%s is deprecated; use %s instead", var, instead);
FreshLine = 1;
}
}
static int latlong_component_func(int do_set, Value *val, int *var, int min, int max, char const *varname, char const *newvarname)
{
if (!do_set) {
val->type = INT_TYPE;
val->v.val = *var;
return OK;
}
deprecated_var(varname, newvarname);
if (val->type != INT_TYPE) return E_BAD_TYPE;
if (val->v.val < min) return E_2LOW;
if (val->v.val > max) return E_2HIGH;
*var = val->v.val;
set_lat_and_long_from_components();
return OK;
}
static int latdeg_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LatDeg, -90, 90, "$LatDeg", "$Latitude");
}
static int latmin_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LatMin, -59, 59, "$LatMin", "$Latitude");
}
static int latsec_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LatSec, -59, 59, "$LatSec", "$Latitude");
}
static int longdeg_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LongDeg, -180, 180, "$LongDeg", "$Longitude");
}
static int longmin_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LongMin, -59, 59, "$LongMin", "$Longitude");
}
static int longsec_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LongSec, -59, 59, "$LongSec", "$Longitude");
}
static int latitude_longitude_func(int do_set, Value *val, double *var, double min, double max) {
char buf[64];
double x;
char *endptr;
if (!do_set) {
snprintf(buf, sizeof(buf), "%f", *var);
val->v.str = malloc(strlen(buf)+1);
if (!val->v.str) return E_NO_MEM;
strcpy(val->v.str, buf);
val->type = STR_TYPE;
return OK;
}
if (val->type == INT_TYPE) {
x = (double) val->v.val;
} else {
if (val->type != STR_TYPE) return E_BAD_TYPE;
errno = 0;
x = strtod(val->v.str, &endptr);
if (errno) return E_BAD_TYPE;
if (*endptr) return E_BAD_TYPE;
}
if (x < min) return E_2LOW;
if (x > max) return E_2HIGH;
*var = x;
set_components_from_lat_and_long();
return OK;
}
static int longitude_func(int do_set, Value *val)
{
return latitude_longitude_func(do_set, val, &Longitude, -180.0, 180.0);
}
static int latitude_func(int do_set, Value *val)
{
return latitude_longitude_func(do_set, val, &Latitude, -90.0, 90.0);
}
static int trig_date_func(int do_set, Value *val)
{
UNUSED(do_set);
val->type = DATE_TYPE;
if (!LastTrigValid) {
val->v.val = 0;
@@ -48,6 +147,7 @@ static int trig_date_func(int do_set, Value *val)
static int trig_day_func(int do_set, Value *val)
{
int y, m, d;
UNUSED(do_set);
val->type = INT_TYPE;
if (!LastTrigValid) {
val->v.val = -1;
@@ -62,6 +162,7 @@ static int trig_day_func(int do_set, Value *val)
static int trig_mon_func(int do_set, Value *val)
{
int y, m, d;
UNUSED(do_set);
val->type = INT_TYPE;
if (!LastTrigValid) {
val->v.val = -1;
@@ -76,6 +177,7 @@ static int trig_mon_func(int do_set, Value *val)
static int trig_year_func(int do_set, Value *val)
{
int y, m, d;
UNUSED(do_set);
val->type = INT_TYPE;
if (!LastTrigValid) {
val->v.val = -1;
@@ -90,6 +192,7 @@ static int trig_year_func(int do_set, Value *val)
static int trig_wday_func(int do_set, Value *val)
{
val->type = INT_TYPE;
UNUSED(do_set);
if (!LastTrigValid) {
val->v.val = -1;
return OK;
@@ -101,6 +204,7 @@ static int trig_wday_func(int do_set, Value *val)
static int today_date_func(int do_set, Value *val)
{
UNUSED(do_set);
val->type = DATE_TYPE;
val->v.val = JulianToday;
return OK;
@@ -108,6 +212,7 @@ static int today_date_func(int do_set, Value *val)
static int today_day_func(int do_set, Value *val)
{
int y, m, d;
UNUSED(do_set);
val->type = INT_TYPE;
FromJulian(JulianToday, &y, &m, &d);
val->v.val = d;
@@ -117,6 +222,7 @@ static int today_day_func(int do_set, Value *val)
static int today_mon_func(int do_set, Value *val)
{
int y, m, d;
UNUSED(do_set);
val->type = INT_TYPE;
FromJulian(JulianToday, &y, &m, &d);
val->v.val = m+1;
@@ -126,6 +232,7 @@ static int today_mon_func(int do_set, Value *val)
static int today_year_func(int do_set, Value *val)
{
int y, m, d;
UNUSED(do_set);
val->type = INT_TYPE;
FromJulian(JulianToday, &y, &m, &d);
val->v.val = y;
@@ -134,6 +241,7 @@ static int today_year_func(int do_set, Value *val)
static int today_wday_func(int do_set, Value *val)
{
UNUSED(do_set);
val->type = INT_TYPE;
val->v.val = (JulianToday + 1) % 7;
return OK;
@@ -158,6 +266,45 @@ static int datetime_sep_func(int do_set, Value *val)
return OK;
}
static int default_color_func(int do_set, Value *val)
{
int col_r, col_g, col_b;
if (!do_set) {
/* 12 = strlen("255 255 255\0") */
val->v.str = malloc(12);
if (!val->v.str) return E_NO_MEM;
snprintf(val->v.str, 12, "%d %d %d",
DefaultColorR,
DefaultColorG,
DefaultColorB
);
val->type = STR_TYPE;
return OK;
}
if (val->type != STR_TYPE) return E_BAD_TYPE;
if (sscanf(val->v.str, "%d %d %d", &col_r, &col_g, &col_b) != 3) {
return E_BAD_TYPE;
}
/* They either all have to be -1, or all between 0 and 255 */
if (col_r == -1 && col_g == -1 && col_b == -1) {
DefaultColorR = -1;
DefaultColorG = -1;
DefaultColorB = -1;
return OK;
}
if (col_r < 0) return E_2LOW;
if (col_r > 255) return E_2HIGH;
if (col_g < 0) return E_2LOW;
if (col_g > 255) return E_2HIGH;
if (col_b < 0) return E_2LOW;
if (col_b > 255) return E_2HIGH;
DefaultColorR = col_r;
DefaultColorG = col_g;
DefaultColorB = col_b;
return OK;
}
static int date_sep_func(int do_set, Value *val)
{
if (!do_set) {
@@ -360,6 +507,10 @@ int DoSet (Parser *p)
if (*DBufValue(&buf) == '$') r = SetSysVar(DBufValue(&buf)+1, &v);
else r = SetVar(DBufValue(&buf), &v);
if (buf.len > VAR_NAME_LEN) {
Eprint("Warning: Variable name `%.*s...' truncated to `%.*s'",
VAR_NAME_LEN, DBufValue(&buf), VAR_NAME_LEN, DBufValue(&buf));
}
DBufFree(&buf);
return r;
}
@@ -422,17 +573,17 @@ int DoDump(ParsePtr p)
DumpVarTable();
return OK;
}
fprintf(ErrFp, "%*s %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE);
fprintf(ErrFp, "%s %s\n\n", VARIABLE, VALUE);
while(1) {
if (*DBufValue(&buf) == '$') {
DumpSysVarByName(DBufValue(&buf)+1);
} else {
v = FindVar(DBufValue(&buf), 0);
DBufValue(&buf)[VAR_NAME_LEN] = 0;
if (!v) fprintf(ErrFp, "%*s %s\n", VAR_NAME_LEN,
if (!v) fprintf(ErrFp, "%s %s\n",
DBufValue(&buf), UNDEF);
else {
fprintf(ErrFp, "%*s ", VAR_NAME_LEN, v->name);
fprintf(ErrFp, "%s ", v->name);
PrintValue(&(v->v), ErrFp);
fprintf(ErrFp, "\n");
}
@@ -460,12 +611,12 @@ void DumpVarTable(void)
register Var *v;
register int i;
fprintf(ErrFp, "%*s %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE);
fprintf(ErrFp, "%s %s\n\n", VARIABLE, VALUE);
for (i=0; i<VAR_HASH_SIZE; i++) {
v = VHashTbl[i];
while(v) {
fprintf(ErrFp, "%*s ", VAR_NAME_LEN, v->name);
fprintf(ErrFp, "%s ", v->name);
PrintValue(&(v->v), ErrFp);
fprintf(ErrFp, "\n");
v = v->next;
@@ -594,7 +745,9 @@ static SysVar SysVarArr[] = {
{"Daemon", 0, INT_TYPE, &Daemon, 0, 0 },
{"DateSep", 1, SPECIAL_TYPE, date_sep_func, 0, 0 },
{"DateTimeSep", 1, SPECIAL_TYPE, datetime_sep_func, 0, 0 },
{"DefaultColor", 1, SPECIAL_TYPE, default_color_func, 0, 0 },
{"DefaultPrio", 1, INT_TYPE, &DefaultPrio, 0, 9999},
{"DefaultTDelta", 1, INT_TYPE, &DefaultTDelta, 0, 1440},
{"DeltaOffset", 0, INT_TYPE, &DeltaOffset, 0, 0 },
{"DontFork", 0, INT_TYPE, &DontFork, 0, 0 },
{"DontQueue", 0, INT_TYPE, &DontQueue, 0, 0 },
@@ -603,17 +756,21 @@ static SysVar SysVarArr[] = {
{"EndSentIg", 1, STR_TYPE, &EndSentIg, 0, 0 },
{"FirstIndent", 1, INT_TYPE, &FirstIndent, 0, 132 },
{"FoldYear", 1, INT_TYPE, &FoldYear, 0, 1 },
{"FormWidth", 1, INT_TYPE, &FormWidth, 20, 132 },
{"FormWidth", 1, INT_TYPE, &FormWidth, 20, 500 },
{"HushMode", 0, INT_TYPE, &Hush, 0, 0 },
{"IgnoreOnce", 0, INT_TYPE, &IgnoreOnce, 0, 0 },
{"InfDelta", 0, INT_TYPE, &InfiniteDelta, 0, 0 },
{"LatDeg", 1, INT_TYPE, &LatDeg, -90, 90 },
{"LatMin", 1, INT_TYPE, &LatMin, -59, 59 },
{"LatSec", 1, INT_TYPE, &LatSec, -59, 59 },
{"IntMax", 0, INT_TYPE, &IntMax, 0, 0 },
{"IntMin", 0, INT_TYPE, &IntMin, 0, 0 },
{"LatDeg", 1, SPECIAL_TYPE, latdeg_func, 0, 0 },
{"Latitude", 1, SPECIAL_TYPE, latitude_func, 0, 0 },
{"LatMin", 1, SPECIAL_TYPE, latmin_func, 0, 0 },
{"LatSec", 1, SPECIAL_TYPE, latsec_func, 0, 0 },
{"Location", 1, STR_TYPE, &Location, 0, 0 },
{"LongDeg", 1, INT_TYPE, &LongDeg, -180, 180 },
{"LongMin", 1, INT_TYPE, &LongMin, -59, 59 },
{"LongSec", 1, INT_TYPE, &LongSec, -59, 59 },
{"LongDeg", 1, SPECIAL_TYPE, longdeg_func, 0, 0 },
{"Longitude", 1, SPECIAL_TYPE, longitude_func, 0, 0 },
{"LongMin", 1, SPECIAL_TYPE, longmin_func, 0, 0 },
{"LongSec", 1, SPECIAL_TYPE, longsec_func, 0, 0 },
{"MaxSatIter", 1, INT_TYPE, &MaxSatIter, 10, ANY },
{"MaxStringLen", 1, INT_TYPE, &MaxStringLen, -1, ANY },
{"MinsFromUTC", 1, INT_TYPE, &MinsFromUTC, -780, 780 },
@@ -654,6 +811,7 @@ static void DumpSysVar (char const *name, const SysVar *v);
/***************************************************************/
int SetSysVar(char const *name, Value *value)
{
int r;
SysVar *v = FindSysVar(name);
if (!v) return E_NOSUCH_VAR;
if (v->type != SPECIAL_TYPE &&
@@ -665,7 +823,9 @@ int SetSysVar(char const *name, Value *value)
if (v->type == SPECIAL_TYPE) {
SysVarFunc f = (SysVarFunc) v->value;
return f(1, value);
r = f(1, value);
DestroyValue(*value);
return r;
} else if (v->type == STR_TYPE) {
/* If it's a string variable, special measures must be taken */
if (v->been_malloced) free(*((char **)(v->value)));
@@ -707,7 +867,7 @@ int GetSysVar(char const *name, Value *val)
/* In "verbose" mode, print attempts to test $RunOff */
if (DebugFlag & DB_PRTLINE) {
if (v->value == (void *) &RunDisabled) {
Eprint("(Security note: $RunOff variable tested.)\n");
Eprint("(Security note: $RunOff variable tested.)");
/* Allow further messages from this line */
FreshLine = 1;
}
@@ -748,7 +908,7 @@ static SysVar *FindSysVar(char const *name)
/***************************************************************/
void DumpSysVarByName(char const *name)
{
int i;
size_t i;
SysVar *v;
if (!name || !*name) {
@@ -781,7 +941,7 @@ static void DumpSysVar(char const *name, const SysVar *v)
return;
}
if (name) strcat(buffer, name); else strcat(buffer, v->name);
fprintf(ErrFp, "%*s ", VAR_NAME_LEN+1, buffer);
fprintf(ErrFp, "%16s ", buffer);
if (v) {
if (v->type == SPECIAL_TYPE) {
Value val;
@@ -825,3 +985,48 @@ static void DumpSysVar(char const *name, const SysVar *v)
return;
}
void
set_lat_and_long_from_components(void)
{
Latitude = (double) LatDeg + ((double) LatMin) / 60.0 + ((double) LatSec) / 3600.0;
Longitude = - ( (double) LongDeg + ((double) LongMin) / 60.0 + ((double) LongSec) / 3600.0);
}
void
set_components_from_lat_and_long(void)
{
double x;
x = (Latitude < 0.0 ? -Latitude : Latitude);
LatDeg = (int) x;
x -= (double) LatDeg;
x *= 60;
LatMin = (int) x;
x -= (double) LatMin;
x *= 60;
LatSec = (int) x;
if (Latitude < 0.0) {
LatDeg = -LatDeg;
LatMin = -LatMin;
LatSec = -LatSec;
}
x = (Longitude < 0.0 ? -Longitude : Longitude);
LongDeg = (int) x;
x -= (double) LongDeg;
x *= 60;
LongMin = (int) x;
x -= (double) LongMin;
x *= 60;
LongSec = (int) x;
/* Use STANDARD sign for $Longitude even if $LongDeg, $LongMin and
* $LongSec are messed up */
if (Longitude > 0.0) {
LongDeg = -LongDeg;
LongMin = -LongMin;
LongSec = -LongSec;
}
}

View File

@@ -1 +1,3 @@
REM 15 MSG 02
DO subdir/04.rem
INCLUDE subdir/04.rem

View File

@@ -0,0 +1 @@
REM 16 MSG Should be included by 02.rem

View File

@@ -28,3 +28,5 @@ REM Fri SPECIAL SHADE 255 204 204
REM Sat SPECIAL SHADE 204 255 204
REM Sun SPECIAL SHADE 204 204 255
# This should be ignored by rem2ps
REM SPECIAL HTML <b>FOO</b>

2
tests/test-addomit.rem Normal file
View File

@@ -0,0 +1,2 @@
REM Mon 1 Sep SCANFROM -7 ADDOMIT MSG Labour Day
REM 6 Sep 2021 AFTER MSG Should be bumped to Tuesday

View File

@@ -0,0 +1,27 @@
# This file is designed for testing how back-ends
# handle SPECIALs, including SPECIALS they don't understand
# If you're writing a back-end, test it by feeding it the output
# of: remind -pp test-for-backends.rem
# Color and shade
REM 1 SPECIAL COLOR 128 0 0 Red
REM 2 SPECIAL COLOUR 0 128 0 British Green
REM 3 SPECIAL SHADE 192 192 255
# Moon
REM [moondate(0)] SPECIAL MOON 0 -1 -1 [moontime(0)]
REM [moondate(1)] SPECIAL MOON 1 -1 -1 [moontime(1)]
REM [moondate(2)] SPECIAL MOON 2 -1 -1 [moontime(2)]
REM [moondate(3)] SPECIAL MOON 3 -1 -1 [moontime(3)]
# Week
REM Monday SPECIAL WEEK (W[weekno()])
# PostScript
REM Wed PS Border Border 2 div moveto /Helvetica-Oblique findfont 6 scalefont setfont (oof!) show
# A SPECIAL that should be ignored
REM 15 SPECIAL RANDOM-STUFF ignore me and be happy
# A normal reminder
REM 16 MSG A normal reminder

View File

@@ -7,13 +7,22 @@
# in the build directory.
#
# This file is part of REMIND.
# Copyright (C) 1992-2018 Dianne Skoll
# Copyright (C) 1992-2021 Dianne Skoll
# ---------------------------------------------------------------------------
DIR=`dirname $0`
cd $DIR
if test $? != 0 ; then
echo ""
echo "Unable to cd $DIR" >&2
echo ""
exit 1
fi
if test `id -u` = 0 ; then
echo ""
echo "*** Please do not run the test suite as root; it will fail."
echo ""
exit 1
fi
@@ -56,6 +65,14 @@ echo "" >> ../tests/test.out
chmod 644 include_dir/04cantread.rem
# Feb 29 bug
echo "Feb 29 Bug Test" >> ../tests/test.out
echo 'REM Sun 29 Feb MSG [$T]' | ../src/remind -dt - 1 feb 2021 >> ../tests/test.out 2>&1
# Day Weekday Year out-of-year bug
echo "Mon 31 Dec Bug Test" >> ../tests/test.out
echo 'REM Mon 31 2021 MSG [$T]' | ../src/remind -dt - 31 dec 2021 >> ../tests/test.out 2>&1
echo "Color Test" >> ../tests/test.out
../src/remind -ccl ../tests/colors.rem 1 aug 2007 >> ../tests/test.out 2>&1
@@ -79,6 +96,7 @@ rm -f ../tests/purge_dir/*.rem.purged >> ../tests/test.out 2>&1
../src/remind ../tests/runtest.rem >> ../tests/test.out 2>&1
../src/remind -p ../tests/shade.rem 1 August 2009 | ../src/rem2ps -e -l -c3 >> ../tests/test.out 2>&1
../src/remind -pp ../tests/shade.rem 1 August 2009 | ../src/rem2ps -e -l -c3 >> ../tests/test.out 2>&1
# The sun tests can fail due to math roundoff error changing the times
# by a minute...
@@ -99,6 +117,215 @@ REM 1 Jan 2012 AT 10:00 MSG 10am: Should show up
MSG [$DontTrigAts]
EOF
# An OMITFUNC should indicate nonconst_expr
../src/remind -pp - 1 jan 2012 9:00 <<'EOF' >> ../tests/test.out 2>&1
REM Mon OMITFUNC foo MSG bar
EOF
# Test default color
../src/remind -ppp - 1 Jan 2012 9:00 <<'EOF' >> ../tests/test.out 2>&1
REM 2 MSG Normal
SET $DefaultColor "255 0 0"
REM 3 MSG Red
SET $DefaultColor "-1 -1 -1"
REM 4 MSG Normal
# Should give an error
SET $DefaultColor "256 0 0"
EOF
# Test -@ option
../src/remind -w,0,0 -@0 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
rem 1 SPECIAL COLOR 0 0 0 BLACK
rem 2 SPECIAL COLOR 0 0 65 BLUE
rem 3 SPECIAL COLOR 0 65 0 GREEN
rem 4 SPECIAL COLOR 0 65 65 CYAN
rem 5 msg -@0
rem 15 SPECIAL COLOR 65 0 0 RED
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
rem 17 SPECIAL COLOR 65 65 0 YELLOW
rem 18 SPECIAL COLOR 65 65 65 WHITE
rem 8 SPECIAL COLOR 0 0 0 BLACK
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
EOF
../src/remind -w,0,0 -@0,0 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
rem 1 SPECIAL COLOR 0 0 0 BLACK
rem 2 SPECIAL COLOR 0 0 65 BLUE
rem 3 SPECIAL COLOR 0 65 0 GREEN
rem 4 SPECIAL COLOR 0 65 65 CYAN
rem 5 msg -@0,0
rem 15 SPECIAL COLOR 65 0 0 RED
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
rem 17 SPECIAL COLOR 65 65 0 YELLOW
rem 18 SPECIAL COLOR 65 65 65 WHITE
rem 8 SPECIAL COLOR 0 0 0 BLACK
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
EOF
../src/remind -w,0,0 -@0,1 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
rem 1 SPECIAL COLOR 0 0 0 BLACK
rem 2 SPECIAL COLOR 0 0 65 BLUE
rem 3 SPECIAL COLOR 0 65 0 GREEN
rem 4 SPECIAL COLOR 0 65 65 CYAN
rem 5 msg -@0,1
rem 15 SPECIAL COLOR 65 0 0 RED
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
rem 17 SPECIAL COLOR 65 65 0 YELLOW
rem 18 SPECIAL COLOR 65 65 65 WHITE
rem 8 SPECIAL COLOR 0 0 0 BLACK
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
EOF
../src/remind -w,0,0 -@1 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
rem 1 SPECIAL COLOR 0 0 0 BLACK
rem 2 SPECIAL COLOR 0 0 65 BLUE
rem 3 SPECIAL COLOR 0 65 0 GREEN
rem 4 SPECIAL COLOR 0 65 65 CYAN
rem 5 msg -@1
rem 15 SPECIAL COLOR 65 0 0 RED
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
rem 17 SPECIAL COLOR 65 65 0 YELLOW
rem 18 SPECIAL COLOR 65 65 65 WHITE
rem 8 SPECIAL COLOR 0 0 0 BLACK
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
EOF
../src/remind -w,0,0 -@1,0 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
rem 1 SPECIAL COLOR 0 0 0 BLACK
rem 2 SPECIAL COLOR 0 0 65 BLUE
rem 3 SPECIAL COLOR 0 65 0 GREEN
rem 4 SPECIAL COLOR 0 65 65 CYAN
rem 5 msg -@1,0
rem 15 SPECIAL COLOR 65 0 0 RED
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
rem 17 SPECIAL COLOR 65 65 0 YELLOW
rem 18 SPECIAL COLOR 65 65 65 WHITE
rem 8 SPECIAL COLOR 0 0 0 BLACK
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
EOF
../src/remind -w,0,0 -@1,1 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
rem 1 SPECIAL COLOR 0 0 0 BLACK
rem 2 SPECIAL COLOR 0 0 65 BLUE
rem 3 SPECIAL COLOR 0 65 0 GREEN
rem 4 SPECIAL COLOR 0 65 65 CYAN
rem 5 msg -@1,1
rem 15 SPECIAL COLOR 65 0 0 RED
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
rem 17 SPECIAL COLOR 65 65 0 YELLOW
rem 18 SPECIAL COLOR 65 65 65 WHITE
rem 8 SPECIAL COLOR 0 0 0 BLACK
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
EOF
../src/remind -w,0,0 -@2 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
rem 1 SPECIAL COLOR 0 0 0 BLACK
rem 2 SPECIAL COLOR 0 0 65 BLUE
rem 3 SPECIAL COLOR 0 65 0 GREEN
rem 4 SPECIAL COLOR 0 65 65 CYAN
rem 5 msg -@2
rem 15 SPECIAL COLOR 65 0 0 RED
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
rem 17 SPECIAL COLOR 65 65 0 YELLOW
rem 18 SPECIAL COLOR 65 65 65 WHITE
rem 8 SPECIAL COLOR 0 0 0 BLACK
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
EOF
../src/remind -w,0,0 -@2,0 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
rem 1 SPECIAL COLOR 0 0 0 BLACK
rem 2 SPECIAL COLOR 0 0 65 BLUE
rem 3 SPECIAL COLOR 0 65 0 GREEN
rem 4 SPECIAL COLOR 0 65 65 CYAN
rem 5 msg -@2,0
rem 15 SPECIAL COLOR 65 0 0 RED
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
rem 17 SPECIAL COLOR 65 65 0 YELLOW
rem 18 SPECIAL COLOR 65 65 65 WHITE
rem 8 SPECIAL COLOR 0 0 0 BLACK
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
EOF
../src/remind -w,0,0 -@2,1 -c - 1 Jan 2020 <<'EOF' >> ../tests/test.out 2>&1
rem 1 SPECIAL COLOR 0 0 0 BLACK
rem 2 SPECIAL COLOR 0 0 65 BLUE
rem 3 SPECIAL COLOR 0 65 0 GREEN
rem 4 SPECIAL COLOR 0 65 65 CYAN
rem 5 msg -@2,1
rem 15 SPECIAL COLOR 65 0 0 RED
rem 16 SPECIAL COLOR 65 0 65 MAGENTA
rem 17 SPECIAL COLOR 65 65 0 YELLOW
rem 18 SPECIAL COLOR 65 65 65 WHITE
rem 8 SPECIAL COLOR 0 0 0 BLACK
rem 9 SPECIAL COLOR 0 0 200 BRIGHT BLUE
rem 10 SPECIAL COLOR 0 200 0 BRIGHT GREEN
rem 11 SPECIAL COLOR 0 200 200 BRIGHT CYAN
rem 22 SPECIAL COLOR 200 0 0 BRIGHT RED
rem 23 SPECIAL COLOR 200 0 200 BRIGHT MAGENTA
rem 24 SPECIAL COLOR 200 200 0 BRIGHT YELLOW
rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
EOF
# If we're already in a utf-8 locale, do
# nothing; otherwise, set LC_ALL
OK=0
if echo $LC_ALL | grep -i utf-8 > /dev/null 2>&1 ; then
OK=1
fi
if test -z "$LC_ALL" ; then
if echo $LANG | grep -i utf-8 > /dev/null 2>&1 ; then
export LC_ALL="$LANG"
OK=1
fi
fi
if test "$OK" = 0 ; then
export LC_ALL=en_US.utf-8
fi
../src/remind -w128 -c ../tests/utf-8.rem 1 Nov 2019 >> ../tests/test.out
../src/remind -c ../tests/test-addomit.rem 1 Sep 2021 >> ../tests/test.out
cmp -s ../tests/test.out ../tests/test.cmp
if [ "$?" = "0" ]; then

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,9 @@
#
# ./test-rem # From WITHIN Remind source directory!
# Should issue a warning
fset year(x) 1
# Don't evaluate SATISFY expressions if reminder has expired
REM Wed UNTIL 15 Feb 1991 SATISFY [trigdate() > '1990-01-01'] MSG wookie
@@ -12,9 +15,40 @@ REM Wed UNTIL 15 Feb 1991 SATISFY [trigdate() > '1990-01-01'] MSG wookie
# bad AT
REM AT 0:00 0:01 0:02 MSG foo
# Includecmd
INCLUDECMD echo REM 16 Feb 1991 MSG Blork
INCLUDECMD echo REM 18 Feb 1991 MSG Blork
# Includecmd with continuation line
INCLUDECMD echo REM 18 Feb 1991 MSG This line is \
continued so there
# This should work
INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo MSG Yippee
# This should fail
INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo MSG Yippee
REM MSG Today is [hebday(today())] [hebmon(today())] [hebyear(today())]
fset _h(x, y) trigger(hebdate(x,y))
# Test case from Remind mailing list
set mltest "a b"
INCLUDECMD printf 'REM %s\n' [mltest]
# Disabling RUN in an !includecmd
INCLUDECMD !echo MSG foo
INCLUDECMD !echo MSG foo
INCLUDECMD !echo INCLUDECMD echo MSG foo
INCLUDECMD !echo INCLUDECMD echo MSG foo
INCLUDECMD !echo MSG foo
INCLUDECMD !echo MSG foo
# INCLUDECMD with RUN disabled
RUN OFF
INCLUDECMD echo MSG foo
RUN ON
INCLUDECMD echo MSG foo
[_h(1, "Tishrey")] MSG Rosh Hashana 1
[_h(2, "Tishrey")] MSG Rosh Hashana 2
[_h(3, "Tishrey")] MSG Tzom Gedalia
@@ -169,6 +203,10 @@ REM Fri SCANFROM [trigger(today()-7)] SATISFY 1
OMIT [trigger(trigdate())]
REM Fri after MSG 16 Feb 1991
CLEAR-OMIT-CONTEXT
REM Fri SCANFROM -7 SATISFY 1
OMIT [trigger(trigdate())]
REM Fri after MSG 16 Feb 1991
CLEAR-OMIT-CONTEXT
# Test omitfunc
fset _ofunc(x) (day(x) < 7 || day(x) % 2)
@@ -188,6 +226,36 @@ REM 1991/02/28@14:45 MSG Feb 28
REM Wed UNTIL 1991-01-01 MSG Expired
REM Wed SCANFROM 1991-02-26 MSG SCANFROM
CLEAR-OMIT-CONTEXT
# Test ADDOMIT
REM Mon 15 Feb ADDOMIT MSG Family Day
REM Feb 18 AFTER MSG Should trigger on Feb 19
OMIT DUMP
set $CalcUTC 0
set $DateTimeSep "@"
set $DefaultColor "-1 -1 -1"
set $DefaultPrio 5000
set $EndSent ".?!"
set $EndSentIg "" + char(34) + "')]}>"
set $FirstIndent 0
set $FoldYear 0
set $FormWidth 72
set $Location "Ottawa"
set $MaxSatIter 150
set $MaxStringLen 65535
set $MinsFromUTC -300
set $SubsIndent 0
set $TimeSep ":"
set $LatDeg 30
set $LatMin 30
set $LatSec 0
set $LongDeg -25
set $LongMin 15
set $LongSec 0
set a000 abs(1)
set a001 abs(-1)
set a002 asc("foo")
@@ -306,14 +374,274 @@ set a082 slide('1991-03-01', 7, "Sat", "Sun")
set a083 slide('1991-04-01', -7, "Sat")
set a084 nonomitted('1991-03-01', '1991-03-13', "Sat", "Sun")
set a085 nonomitted('1991-03-24', '1991-04-01', "Sat")
REM 2010-09-03 +3 -4 UNTIL 2012-01-01 PRIORITY 7 *14 MSG foo
set a086 trigback()
set a087 trigdelta()
set a088 trigrep()
set a089 triguntil()
set a090 trigscanfrom()
set a091 trigfrom()
set a092 trigpriority()
set a093 trigtimedelta()
set a094 trigtimerep()
set a095 trigduration()
REM Mon Wed FROM 2010-09-03 ++3 --4 MSG foo
set a096 trigback()
set a097 trigdelta()
set a098 trigrep()
set a099 triguntil()
set a100 trigscanfrom()
set a101 trigfrom()
set a102 trigpriority()
set a103 trigtimedelta()
set a104 trigtimerep()
set a105 trigduration()
REM 2010-09-03 +3 -4 UNTIL 2012-01-01 PRIORITY 7 *14 AT 14:41 +15 *2 DURATION 213 MSG foo
set a106 trigback()
set a107 trigdelta()
set a108 trigrep()
set a109 triguntil()
set a110 trigscanfrom()
set a111 trigfrom()
set a112 trigpriority()
set a113 trigtimedelta()
set a114 trigtimerep()
set a115 trigduration()
REM Mon Wed FROM 2010-09-03 ++3 --4 AT 14:44 MSG foo
set a116 trigback()
set a117 trigdelta()
set a118 trigrep()
set a119 triguntil()
set a120 trigscanfrom()
set a121 trigfrom()
set a122 trigpriority()
set a123 trigtimedelta()
set a124 trigtimerep()
set a125 trigduration()
# Test adding TIME+TIME and DATETIME+TIME
set a126 11:00 + 3:00
set a127 23:00 + 5:30
set a128 '2018-02-03@10:00' + 6:45
set a129 23:30 + '2019-02-02@16:44'
# Multi-day reminder
REM 13 AT 16:00 DURATION 72:00 MSG 72-hour event
set a130 trigdate()
set a131 trigtime()
set a132 trigdatetime()
set a133 trigduration()
set a134 trigeventstart()
set a135 trigeventduration()
# These will issue errors
REM Mon OMIT Mon SKIP MSG Never ever ever...
REM Mon SATISFY [wkdaynum($T) == 3] MSG Nope nope...
# These will just silently not trigger
REM MAYBE-UNCOMPUTABLE Mon OMIT Mon SKIP MSG Never ever ever...
REM MAYBE-UNCOMPUTABLE Mon SATISFY [wkdaynum($T) == 3] MSG Nope nope...
dump
dump $
dump $aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
OMIT 2010-09-03 THROUGH 2010-09-15
OMIT December 25 MSG X
# Next should give a parse error
OMIT 26 Dec 2010 THROUGH 27 Dec 2010 MSG This is not legal
OMIT DUMP
# Regression test for bugfix in Hebrew calendar Adar jahrzeit
[_i(14, "Adar", today(), 5761)] MSG Purim
# Regression test for bug found by Larry Hynes
REM SATISFY [day(trigdate()-25) == 14] MSG Foo
# Check combo of SATISFY and long-duration events
REM 14 SATISFY [$Tw == 4] MSG Thursday, the 14th
REM 14 AT 16:00 DURATION 8:00 SATISFY [$Tw == 4] MSG Thursday, the 14th
REM 14 AT 16:00 DURATION 8:01 SATISFY [$Tw == 4] MSG Thursday, the 14th
REM 14 AT 16:00 DURATION 32:00 SATISFY [$Tw == 4] MSG Thursday, the 14th
REM 14 AT 16:00 DURATION 32:01 SATISFY [$Tw == 4] MSG Thursday, the 14th
REM 14 AT 16:00 DURATION 40:00 SATISFY [$Tw == 4] MSG Thursday, the 14th
# This is now an error
REM DURATION 15:00 MSG Should fail... need AT if you have DURATION.
# Parsing of AM/PM times
REM AT 0:00am MSG foo 0a
REM AT 1:00AM MSG foo 1a
REM AT 2:00am MSG foo 2a
REM AT 3:00AM MSG foo 3a
REM AT 4:00am MSG foo 4a
REM AT 5:00AM MSG foo 5a
REM AT 6:00am MSG foo 6a
REM AT 7:00AM MSG foo 7a
REM AT 8:00am MSG foo 8a
REM AT 9:00AM MSG foo 9a
REM AT 10:00am MSG foo 10a
REM AT 11:00AM MSG foo 11a
REM AT 12:00am MSG foo 12a
REM AT 13:00AM MSG foo 13a
REM AT 0:00pm MSG foo 0p
REM AT 1:00PM MSG foo 1p
REM AT 2:00pm MSG foo 2p
REM AT 3:00PM MSG foo 3p
REM AT 4:00pm MSG foo 4p
REM AT 5:00PM MSG foo 5p
REM AT 6:00pm MSG foo 6p
REM AT 7:00PM MSG foo 7p
REM AT 8:00pm MSG foo 8p
REM AT 9:00PM MSG foo 9p
REM AT 10:00pm MSG foo 10p
REM AT 11:00PM MSG foo 11p
REM AT 12:00pm MSG foo 12p
REM AT 13:00PM MSG foo 13p
DEBUG +x
SET x 0:00am + 0
SET x 1:00AM + 0
SET x 2:00am + 0
SET x 3:00AM + 0
SET x 4:00am + 0
SET x 5:00AM + 0
SET x 6:00am + 0
SET x 7:00AM + 0
SET x 8:00am + 0
SET x 9:00AM + 0
SET x 10:00am + 0
SET x 11:00AM + 0
SET x 12:00am + 0
SET x 13:00AM + 0
SET x 0:00pm + 0
SET x 1:00PM + 0
SET x 2:00pm + 0
SET x 3:00PM + 0
SET x 4:00pm + 0
SET x 5:00PM + 0
SET x 6:00pm + 0
SET x 7:00PM + 0
SET x 8:00pm + 0
SET x 9:00PM + 0
SET x 10:00pm + 0
SET x 11:00PM + 0
SET x 12:00pm + 0
SET x 13:00PM + 0
SET x '2015-02-03@0:00am' + 0
SET x '2015-02-03@1:00AM' + 0
SET x '2015-02-03@2:00am' + 0
SET x '2015-02-03@3:00AM' + 0
SET x '2015-02-03@4:00am' + 0
SET x '2015-02-03@5:00AM' + 0
SET x '2015-02-03@6:00am' + 0
SET x '2015-02-03@7:00AM' + 0
SET x '2015-02-03@8:00am' + 0
SET x '2015-02-03@9:00AM' + 0
SET x '2015-02-03@10:00am' + 0
SET x '2015-02-03@11:00AM' + 0
SET x '2015-02-03@12:00am' + 0
SET x '2015-02-03@13:00AM' + 0
SET x '2015-02-03@0:00pm' + 0
SET x '2015-02-03@1:00PM' + 0
SET x '2015-02-03@2:00pm' + 0
SET x '2015-02-03@3:00PM' + 0
SET x '2015-02-03@4:00pm' + 0
SET x '2015-02-03@5:00PM' + 0
SET x '2015-02-03@6:00pm' + 0
SET x '2015-02-03@7:00PM' + 0
SET x '2015-02-03@8:00pm' + 0
SET x '2015-02-03@9:00PM' + 0
SET x '2015-02-03@10:00pm' + 0
SET x '2015-02-03@11:00PM' + 0
SET x '2015-02-03@12:00pm' + 0
SET x '2015-02-03@13:00PM' + 0
# Test the ampm function
set x ampm(0:12) + ""
set x ampm(1:12) + ""
set x ampm(2:12) + ""
set x ampm(3:12) + ""
set x ampm(4:12) + ""
set x ampm(5:12) + ""
set x ampm(6:12) + ""
set x ampm(7:12) + ""
set x ampm(8:12) + ""
set x ampm(9:12) + ""
set x ampm(10:12) + ""
set x ampm(11:12) + ""
set x ampm(12:12) + ""
set x ampm(13:12) + ""
set x ampm(14:12) + ""
set x ampm(15:12) + ""
set x ampm(16:12) + ""
set x ampm(17:12) + ""
set x ampm(18:12) + ""
set x ampm(19:12) + ""
set x ampm(20:12) + ""
set x ampm(21:12) + ""
set x ampm(22:12) + ""
set x ampm(23:12) + ""
# Coerce with am/pm
set x coerce("TIME", "12:45am")
set x coerce("TIME", "12:45")
set x coerce("TIME", "1:45pm")
set x coerce("DATETIME", "2020-05-05@12:45am")
set x coerce("DATETIME", "2020-05-05@12:45")
set x coerce("DATETIME", "2020-05-05@1:45pm")
# Overflow - these tests only work on machines with 32-bit
# twos-complement signed integers. You may get test failures on
# machines with different architectures.
set a $IntMin - 1
set a $IntMin - $IntMax
set a $IntMax - $IntMin
set a $IntMax - (-1)
set a $IntMax + 1
set a $IntMax + $IntMax
set a $IntMin + (-1)
set a $IntMin + $IntMin
set a $IntMax * 2
set a $IntMax * $IntMax
set a $IntMax * $IntMin
set a $IntMin * 2
set a $IntMin * $IntMin
set a $IntMin * $IntMax
set a $IntMin / (-1)
set a $IntMin * (-1)
set a (-1) * $IntMin
set a abs($IntMin)
# The "isany" function
set a isany(1)
set a isany("foo")
set a isany(1:00)
set a isany(1, 2)
set a isany("foo", 2)
set a isany(1:00, 2)
set a isany(1, 2, 1, 3)
set a isany("foo", 2, 3, "foo")
set a isany(1:00, 2, "foo", 2:00, 1:00, 9:00)
# Shellescape
set a shellescape(" !\"#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")
msg [a]
# Deprecated functions
set x psshade(50)
set x psmoon(0)
# Don't want Remind to queue reminders
EXIT
__EOF__
REM This line should not even be seen
And you can put whatever you like here.
[+f=asdfasdasde3ir0a]

4
tests/utf-8.rem Normal file
View File

@@ -0,0 +1,4 @@
MSG ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский ру́сский
MSG עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית עִבְרִית
Wed MSG With tabs and spaces

View File

@@ -1,6 +1,6 @@
#!/bin/sh
echo "Unconfiguring Remind..."
echo rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile
rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile
echo rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile rem2html/Makefile
rm -f config.cache config.log config.status src/Makefile src/config.h src/version.h www/Makefile rem2html/Makefile
exit 0

View File

@@ -4,7 +4,7 @@
# The complete path to where the scripts actually live, as seen by
# the UNIX operating system.
SCRIPTDIR = /var/www/cgi-bin
SCRIPTDIR = /usr/lib/cgi-bin
# Where the scripts live as seen by the web browser.
CGIDIR = /cgi-bin
@@ -17,7 +17,7 @@ HTMLDIR = /var/www/remind
# Where you stick images and CSS files, as seen by UNIX
IMAGEDIR = /var/www/remind/resources
# Where images are, as seen by web browers
# Where images and CSS fiels are, as seen by web browers
IMAGEBASE = /remind/resources
# Set by configure - don't touch.
@@ -32,7 +32,7 @@ datarootdir=@datarootdir@
# Where do Remind and Rem2PS executables live?
REMIND = $(bindir)/remind
REM2PS = $(bindir)/rem2ps
REM2HTML = $(bindir)/rem2html
# If your Web server requires CGI programs to have a .cgi suffix, use
# the next line. Otherwise, comment it out
CGISUFFIX=.cgi
@@ -46,14 +46,8 @@ SEDSCRIPT = -e 's@%CGIDIR%@$(CGIDIR)@g' \
-e 's@%REMIND%@$(REMIND)@g' \
-e 's@%IMAGEBASE%@$(IMAGEBASE)@g' \
-e 's@%REM2PS%@$(REM2PS)@g' \
-e 's@%REM2HTML%@$(REM2HTML)@g' \
-e 's@cal_dispatch@cal_dispatch$(CGISUFFIX)@g' \
-e 's@rem2html@rem2html$(CGISUFFIX)@g'
SEDSCRIPT2 = -e 's@%CGIDIR%@$(CGIDIR)@g' \
-e 's@%SCRIPTDIR%@$(SCRIPTDIR)@g' \
-e 's@%REMIND%@$(REMIND)@g' \
-e 's@%IMAGEBASE%@$(IMAGEBASE)@g' \
-e 's@%REM2PS%@$(REM2PS)@g'
all:
@echo "Edit the Makefile; then type 'make install' to install"
@@ -69,29 +63,24 @@ install:
sed $(SEDSCRIPT) < moon.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/moon.rem
sed $(SEDSCRIPT) < sunrise.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/sunrise.rem
sed $(SEDSCRIPT) < sunset.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/sunset.rem
cp blank.rem $(DESTDIR)$(SCRIPTDIR)/blank.rem
sed $(SEDSCRIPT) < calendar.html-DIST > $(DESTDIR)$(HTMLDIR)/calendar.html
sed $(SEDSCRIPT) < hebhtml > $(DESTDIR)$(SCRIPTDIR)/hebhtml
sed $(SEDSCRIPT2) < rem2html > $(DESTDIR)$(SCRIPTDIR)/rem2html$(CGISUFFIX)
chmod 644 $(DESTDIR)$(SCRIPTDIR)/sunrise.rem
chmod 644 $(DESTDIR)$(SCRIPTDIR)/moon.rem
chmod 644 $(DESTDIR)$(SCRIPTDIR)/hebdate.rem
chmod 644 $(DESTDIR)$(SCRIPTDIR)/sunset.rem
chmod 644 $(DESTDIR)$(SCRIPTDIR)/blank.rem
chmod 644 $(DESTDIR)$(HTMLDIR)/calendar.html
chmod 755 $(DESTDIR)$(SCRIPTDIR)/cal_dispatch$(CGISUFFIX)
chmod 755 $(DESTDIR)$(SCRIPTDIR)/rem2html$(CGISUFFIX)
chmod 755 $(DESTDIR)$(SCRIPTDIR)/calps $(DESTDIR)$(SCRIPTDIR)/hebdate \
$(DESTDIR)$(SCRIPTDIR)/hebps $(DESTDIR)$(SCRIPTDIR)/moon \
$(DESTDIR)$(SCRIPTDIR)/sunrise $(DESTDIR)$(SCRIPTDIR)/sunset \
$(DESTDIR)$(SCRIPTDIR)/hebhtml \
$(DESTDIR)$(SCRIPTDIR)/rem2html$(CGISUFFIX)
-mkdir -p $(DESTDIR)$(IMAGEDIR)
cp firstquarter.png fullmoon.png lastquarter.png newmoon.png rem-default.css $(DESTDIR)$(IMAGEDIR)
chmod 644 $(DESTDIR)$(IMAGEDIR)/firstquarter.png \
$(DESTDIR)$(IMAGEDIR)/fullmoon.png \
$(DESTDIR)$(IMAGEDIR)/lastquarter.png \
$(DESTDIR)$(IMAGEDIR)/newmoon.png \
$(DESTDIR)$(IMAGEDIR)/rem-default.css
cp rem-default.css *.png $(DESTDIR)$(IMAGEDIR)
chmod 644 $(DESTDIR)$(IMAGEDIR)/rem-default.css $(DESTDIR)$(IMAGEDIR)/*.png

View File

@@ -9,7 +9,7 @@ only tested it with Linux running NCSA's httpd and Apache's httpd, but
it should work on any UNIX web server.
To install it, you need the Remind package, available via ftp from
ftp://ftp.doe.carleton.ca/pub/remind-3.0. You should install Remind,
https://dianne.skoll.ca/projects/remind/ You should install Remind,
setting the lattitude, longitude, location and time zone as appropriate
for your machine.
@@ -19,9 +19,7 @@ server:
1) Edit the Makefile in this directory. See the comments in the Makefile
for details.
2) Edit the first line of "rem2html" to reflect the location of
Perl on your system. (Oh yeah, you need Perl for the
HTML Hebrew calendar...)
2) Make sure "rem2html" is installed.
3) Type "make install"
@@ -38,12 +36,8 @@ where "what" is one of:
hebps -- get a PostScript calendar with Jewish holidays.
hebhtml -- get an HTML version of the above (requires Perl.)
(Visit http://www.doe.carleton.ca/~dfs/ for previews.)
All of these links will be set up in a sample HTML document
called "calendar.html" and installed in the HTMLDIR you specified
in the Makefile.
4) Enjoy!

View File

@@ -1,13 +0,0 @@
REM2HTML
--------
Rem2HTML is a Perl script that transforms the output of `remind -p
...' to HTML. Type `perl rem2html --help' for usage information.
Typical usage: remind -p ~/.reminders | rem2html > file.html
You may have to edit the "#!/usr/bin/perl" line to reflect the
location of your Perl interpreter.
--
Dianne Skoll

5
www/blank.rem Normal file
View File

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

View File

@@ -7,5 +7,5 @@
echo "Content-type: application/postscript"
echo
$REMIND -p /dev/null | $REM2PS -e -c3 -l
$REMIND -p $DIR/blank.rem | $REM2PS -e -c3 -l
exit 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 B

After

Width:  |  Height:  |  Size: 360 B

View File

@@ -29,6 +29,8 @@ ENDIF
# #
##########################################################################
SET n $NumTrig
# --- HERE ARE THE JEWISH HOLIDAYS ---
# Set the variable InIsrael to 1 if you live in Israel. Otherwise,
# you get the Diaspora versions of Jewish holidays
@@ -138,6 +140,10 @@ ENDIF
fset msgprefix(x) ""
IF $NumTrig > n
REM SPECIAL SHADE 224 224 255
ENDIF
# Counting the omer - do the whole spiel, i.e:
# "This is the xth day of the omer, being y weeks and z days of the omer."
# Nice Remind programming example here!
@@ -165,7 +171,7 @@ ELSE
[trigger(moondate(2))] SPECIAL MOON 2
[trigger(moondate(3))] SPECIAL MOON 3
REM PS Border Border moveto /DayFont findfont 10 scalefont setfont ([hebday(today())] [hebmon(today())]) show
REM SPECIAL HTML <P><FONT SIZE=-1>[hebday(today())] [hebmon(today())]</FONT></P>
REM SPECIAL HTML <P>[hebday(today())] [hebmon(today())]</P>
ENDIF

View File

@@ -18,7 +18,7 @@ set lastyear iif(lastmon==12, thisyear-1, thisyear)
set nextmon mon(nextmon)
set lastmon mon(lastmon)
BANNER %
REM RUN $REMIND -iHTML=1 -p $DIR/hebdate.rem %m %y | $DIR/rem2html --forwurl "cal_dispatch?hebhtml+[nextmon]+[nextyear]" --backurl "cal_dispatch?hebhtml+[lastmon]+[lastyear]"
REM RUN $REMIND -iHTML=1 -p $DIR/hebdate.rem %m %y | %REM2HTML% --forwurl "cal_dispatch?hebhtml+[nextmon]+[nextyear]" --backurl "cal_dispatch?hebhtml+[lastmon]+[lastyear]" --imgbase "%IMAGEBASE%" --stylesheet rem-default.css --pngs
EOR
else
@@ -33,7 +33,7 @@ set lastyear iif(lastmon==12, thisyear-1, thisyear)
set nextmon mon(nextmon)
set lastmon mon(lastmon)
BANNER %
REM RUN $REMIND -iHTML=1 -p $DIR/hebdate.rem %m %y | $DIR/rem2html --forwurl "cal_dispatch?hebhtml+[nextmon]+[nextyear]" --backurl "cal_dispatch?hebhtml+[lastmon]+[lastyear]"
REM RUN $REMIND -iHTML=1 -p $DIR/hebdate.rem %m %y | %REM2HTML% --forwurl "cal_dispatch?hebhtml+[nextmon]+[nextyear]" --backurl "cal_dispatch?hebhtml+[lastmon]+[lastyear]" --imgbase "%IMAGEBASE%" --stylesheet rem-default.css --pngs
EOR
fi

Binary file not shown.

Before

Width:  |  Height:  |  Size: 367 B

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 B

After

Width:  |  Height:  |  Size: 317 B

View File

@@ -1,6 +1,8 @@
table.rem-cal {
font-family: helvetica, arial, sans-serif;
font-size: 12pt;
width: 100%;
border-collapse: collapse;
}
table.rem-sc-table {
@@ -37,11 +39,6 @@ td.rem-today {
vertical-align: top;
}
table.rem-cal {
width: 100%;
border-collapse: collapse;
}
div.rem-daynumber {
float: right;
text-align: right;
@@ -49,6 +46,10 @@ div.rem-daynumber {
font-size: 14pt;
}
p.rem-entry {
clear: both;
}
div.rem-moon {
float: left;
text-align: left;
@@ -66,4 +67,4 @@ td.rem-sc-empty-cell, td.rem-sc-cell {
caption.rem-sc-caption {
font-size: 12pt;
}
}