Compare commits

...

236 Commits

Author SHA1 Message Date
Dianne Skoll
c16f93effd Update WHATSNEW. 2024-04-01 09:14:25 -04:00
Dianne Skoll
61b27c02b5 Be a little more aggressive. 2024-04-01 09:07:13 -04:00
Dianne Skoll
ba28eaad53 Fix typo. 2024-04-01 08:42:48 -04:00
Dianne Skoll
92c2d0cc9f Remove obsolete #ifdef tests 2024-04-01 08:41:29 -04:00
Dianne Skoll
21d5e8a095 Tweak daemon mode documentation. 2024-04-01 08:39:24 -04:00
Dianne Skoll
60417d68a7 Bump version to 04.03.05 2024-04-01 08:31:59 -04:00
Dianne Skoll
7d25387403 Remove the MICROSOFT-AND-APPLE file. I think I've made my point. 2024-03-31 12:07:11 -04:00
Dianne Skoll
b454cf5b20 Refactor set_cloexec to make it more convenient to call. 2024-03-31 09:49:32 -04:00
Dianne Skoll
9ea6385b72 Tweak whitespace. 2024-03-31 09:42:13 -04:00
Dianne Skoll
55b7908444 Add International Transgender Day of Visibility to man page
Done to annoy the anti-LGBT crowd.
2024-03-31 09:40:58 -04:00
Dianne Skoll
e9ff66478b Document that we use inotify, where possible, to detect changes to reminder scripts / directories. 2024-03-30 13:25:57 -04:00
Dianne Skoll
d3240d711d Rename DaemonWait to ServerWait. 2024-03-29 19:57:47 -04:00
Dianne Skoll
a8d63a4199 Use inotfy even in normal daemon mode (-zn where n>0) to detect file changes. 2024-03-29 08:28:41 -04:00
Dianne Skoll
a4807a21c3 Save the value of $DefaultColor that was in effect at the time a reminder was queued. Restore this value when triggering the reminder. 2024-03-26 11:44:42 -04:00
Dianne Skoll
a394ef53a0 Print the "passthru" field for PASSTHRU_TYPE reminders when listing the queue. 2024-03-26 11:29:37 -04:00
Dianne Skoll
eb8243743a Prevent mishandling of SPECIAL COLOR reminders when pulling them from the queue.
Bug reported by Damien Tardy-Panis.
2024-03-26 11:21:17 -04:00
Dianne Skoll
8444bb15c5 Fix typo. 2024-03-26 09:54:31 -04:00
Dianne Skoll
b86245c4c6 Fix wording. 2024-03-25 10:24:39 -04:00
Dianne Skoll
499fcfad41 Fix typo 2024-03-25 10:24:20 -04:00
Dianne Skoll
bddbbf061b Update changelog. 2024-03-25 10:21:05 -04:00
Dianne Skoll
05136f4cf0 Add a basic CSS file for the demo WWW stuff. 2024-03-25 10:12:46 -04:00
Dianne Skoll
e62e3d5d03 More multitrig examples. 2024-03-24 11:05:15 -04:00
Dianne Skoll
595fdaa4a4 Increment version to 04.03.04. 2024-03-24 10:54:44 -04:00
Dianne Skoll
133febc2c1 Document that you can't have an AT clause in a multitrig trigger. 2024-03-24 10:50:21 -04:00
Dianne Skoll
f8c6d7ff6c Document multitrig. 2024-03-24 10:46:53 -04:00
Dianne Skoll
db3341db91 Fix bug in code that stripes the Queue... output grey and white. 2024-03-23 10:57:56 -04:00
Dianne Skoll
8cbcd3ec01 Show Hebrew dates on PDF version of Jewish holiday calendar. 2024-03-22 17:38:30 -04:00
Dianne Skoll
4c6512e9b6 Update the HTML remind demo. 2024-03-22 17:26:23 -04:00
Dianne Skoll
4769789a8f More common HTML path. 2024-03-22 17:14:13 -04:00
Dianne Skoll
b4a8cb085c Add "blank PDF calendar" to www choices. 2024-03-22 17:13:21 -04:00
Dianne Skoll
4f816d52fd Another test for multitrig / scanfrom interaction. 2024-03-22 12:40:50 -04:00
Dianne Skoll
94b3a0248d Add tests for multitrig 2024-03-22 12:39:58 -04:00
Dianne Skoll
5fbf1d82e4 Remove duplicated line. 2024-03-22 11:23:04 -04:00
Dianne Skoll
55eb3ebe95 Add multitrig built-in function which is how trig() should originally have been done. 2024-03-22 11:21:26 -04:00
Dianne Skoll
2afa3c5558 Raise windows after errors so they remain visible. 2024-03-21 16:08:18 -04:00
Dianne Skoll
30d9a42db2 Remove debugging statement. 2024-03-21 12:39:48 -04:00
Dianne Skoll
74d357b84d Use placeholders that are less likely to be used as filenames. :) 2024-03-21 12:22:43 -04:00
Dianne Skoll
09c98a93ec Fix month navigation. 2024-03-21 12:19:39 -04:00
Dianne Skoll
ed89ab7c04 Remove unnecessary code and variable. 2024-03-21 12:13:32 -04:00
Dianne Skoll
27c74be02b Don't need to monitor reminder file for changes; reap zombies. 2024-03-21 12:11:39 -04:00
Dianne Skoll
8f22ab39dc Apply POSIX-escaping to filenames. 2024-03-21 11:46:29 -04:00
Dianne Skoll
795c53f4ce Format queue items better; make them clickable to open an editor. 2024-03-21 11:02:07 -04:00
Dianne Skoll
3fd18a9cc0 Document clickable errors. 2024-03-21 10:45:32 -04:00
Dianne Skoll
a5afb4a87e In the "show errors" text box, fire up the editor when you click on an error if we can figure out the filename and line number. 2024-03-20 20:53:19 -04:00
Dianne Skoll
379fc4542d Make errors stand out more obviously. 2024-03-20 20:33:46 -04:00
Dianne Skoll
538ef6c8ce Check for both $CalMode and $PsCal 2024-03-20 16:32:02 -04:00
Dianne Skoll
95c7e8856c Add standard "moonphases.rem" file with moon phases. 2024-03-20 16:28:50 -04:00
Dianne Skoll
95523c8f10 Convert cosd() function into a macro. 2024-03-19 16:26:07 -04:00
Dianne Skoll
97b53d5e40 Fix typo 2024-03-18 11:18:46 -04:00
Dianne Skoll
fb688850b1 Update release notes. 2024-03-18 11:11:16 -04:00
Dianne Skoll
5b1bad2650 Document DEL server command and qid value. 2024-03-16 15:50:58 -04:00
Dianne Skoll
e5ff132c5e Remove all traces of tk_dialog 2024-03-16 15:45:29 -04:00
Dianne Skoll
a0830ad23c Bump version to 04.03.03 2024-03-16 15:27:34 -04:00
Dianne Skoll
9290f53466 Fix typo 2024-03-16 15:24:11 -04:00
Dianne Skoll
e5711032bd Keep reading inotify events until 0.2 seconds elapses between successive events. 2024-03-16 15:22:48 -04:00
Dianne Skoll
08e3c1d5a2 Use tk_messageBox instead of tk_dialog. 2024-03-16 15:22:36 -04:00
Dianne Skoll
29c579a301 Refactor some code. 2024-03-16 14:01:21 -04:00
Dianne Skoll
61f55bceee Fix "Delete this reminder completely" functionality. 2024-03-16 13:56:28 -04:00
Dianne Skoll
6586fae3eb Fix logic bug that would sometimes fail to send a queue update message to controlling process. 2024-03-16 13:36:24 -04:00
Dianne Skoll
d5a86f3e4f Actually de-queue and free reminders that expire out of the queue. 2024-03-16 13:29:59 -04:00
Dianne Skoll
96551ccaa4 Make TkRemind use the "DEL qid" facility to ignore reminders. Fix potential use of freed memory in queue.c 2024-03-16 13:25:47 -04:00
Dianne Skoll
c83ee86d10 Implement DEL command to removed a queued reminder from the queue in -zj mode. 2024-03-16 12:54:30 -04:00
Dianne Skoll
c913306cbd Add "qid" member to JSONQUEUE. 2024-03-16 11:17:28 -04:00
Dianne Skoll
03d385df97 Add a test for the "-ds" debugging flag. 2024-03-13 12:17:49 -04:00
Dianne Skoll
61fcc1b275 Add "s" debugging flag to see expression-parsing stack high-water marks.
Reduce default value stack size from 1000 to 100.
2024-03-13 12:06:55 -04:00
Dianne Skoll
26977a4ac0 Fix a bunch of cppcheck complaints and also update the cppcheck Makefile target. 2024-03-11 12:10:03 -04:00
Dianne Skoll
28acd05215 Better icon. 2024-03-08 14:28:19 -05:00
Dianne Skoll
be4eed8b20 Update TkRemind logo to include a white outline. 2024-03-07 15:36:31 -05:00
Dianne Skoll
cdb0850373 Add a comment to the troff source so it doesn't confuse Emacs syntax highlighting. 2024-03-03 14:55:40 -05:00
Dianne Skoll
0d55e04284 Make a local OMIT that doesn't specify a weekday name into a syntax error. 2024-03-03 14:51:53 -05:00
Dianne Skoll
f4cce54b70 Warn if a local OMIT doesn't actually omit any weekdays. 2024-03-03 11:00:35 -05:00
Dianne Skoll
2dc6ca44f1 Fix typo 2024-03-01 09:10:26 -05:00
Dianne Skoll
d1d833f0f3 Document fix in commit 1d44577ce9 2024-03-01 09:04:09 -05:00
Dianne Skoll
1d44577ce9 Exit rather than return if we forked in System(). 2024-03-01 09:00:36 -05:00
Dianne Skoll
1be7c2d6d7 Bump version to 04.03.02 and document fix to install: target. 2024-03-01 08:50:00 -05:00
Dianne Skoll
b1f418ee42 Install desktop and icon file in correct paths: $prefix/share/applications and $prefix/share/pixmaps 2024-03-01 08:45:43 -05:00
Dianne Skoll
72b0bf96fe Update release notes. 2024-02-29 20:28:09 -05:00
Dianne Skoll
3388849fa5 Fix test bug. 2024-02-29 20:27:19 -05:00
Dianne Skoll
dc9650d5fa Fix test bug. SIGH. 2024-02-29 20:25:13 -05:00
Dianne Skoll
8eb40ae748 Note the bug fix. 2024-02-29 15:53:31 -05:00
Dianne Skoll
89184f1d0f Update release notes. 2024-02-29 15:52:43 -05:00
Dianne Skoll
e899c790b9 Add Catalan translation file, courtesy of Eloi Torrents 2024-02-29 15:29:24 -05:00
Dianne Skoll
bd6d695020 Add some more test cases. 2024-02-29 15:27:55 -05:00
Dianne Skoll
20d4626a71 Bump version to 04.03.00 2024-02-29 13:48:15 -05:00
Dianne Skoll
8ff94c5031 Install the .desktop and icon files; add to menu. 2024-02-29 13:19:00 -05:00
Dianne Skoll
ee185a0eeb Desktop file should be executable. 2024-02-29 13:08:49 -05:00
Dianne Skoll
06f8932efd Add .desktop file and icon for TkRemind, courtesy of Eloi Torrents 2024-02-29 13:04:19 -05:00
Dianne Skoll
1dc627148c Fix tests so they don't depend on current date; add more tests for Feb 29 edge cases. 2024-02-29 12:44:59 -05:00
Dianne Skoll
3cdde5351f Issue "NOTE newdate" in legacy mode in response to an inotify event. 2024-02-29 11:28:05 -05:00
Dianne Skoll
6e93b8a73d Update TkRemind man page to properly reflect inotify support. 2024-02-29 11:26:07 -05:00
Dianne Skoll
267e8533cf Fix stupid bug. 2024-02-29 11:14:05 -05:00
Dianne Skoll
d3bfb0a28f Let Remind handle the inotify stuff. 2024-02-29 11:07:32 -05:00
Dianne Skoll
5a31bc7058 Integrate inotify support directly into Remind for server mode. 2024-02-29 11:03:28 -05:00
Dianne Skoll
746bde71bd Check for inotify_init1 2024-02-29 10:41:49 -05:00
Dianne Skoll
b274ac635c Clarify comment. 2024-02-29 09:46:56 -05:00
Dianne Skoll
9e0a74e583 Don't spit anything out to client for RUN-type reminders in server mode. 2024-02-29 09:31:37 -05:00
Dianne Skoll
0f782f7697 Set CLOEXEC flag on files we open.
When running programs in server mode, connect stdin and stdout to /dev/null
2024-02-29 09:22:15 -05:00
Dianne Skoll
8efde3e9af Fix typo 2024-02-28 10:59:51 -05:00
Dianne Skoll
3bf3137dc4 Check for existence of tags key. 2024-02-28 10:58:46 -05:00
Dianne Skoll
63ec32d28d Add missing $Sunday to man page. 2024-02-27 18:40:35 -05:00
Dianne Skoll
d2f4177cdb Update man pages. 2024-02-27 11:11:21 -05:00
Dianne Skoll
1d958fb7a8 Use JSON server mode from TkRemind. 2024-02-27 10:55:26 -05:00
Dianne Skoll
fcd580d42e Add a test for -zj 2024-02-27 10:28:08 -05:00
Dianne Skoll
34dab68805 Finish implementing "-zj" mode - Daemon mode with JSON responses. 2024-02-27 10:18:18 -05:00
Dianne Skoll
216dd03922 Start adding support for JSON-formatted daemon responses. 2024-02-27 09:54:35 -05:00
Dianne Skoll
5eef9ac621 Add test for zero-arg forms of easterdate() and orthodoxeaster() 2024-02-26 17:21:12 -05:00
Dianne Skoll
6b798d5f7c Allow arg to easterdate() and orthodoxeaster() to be omitted, defaulting it to today(). 2024-02-26 17:19:22 -05:00
Dianne Skoll
22ccce0934 Lay groundwork for having TriggerReminder put the results in a DynamicBuffer rather than sending to stdout
Eventually should allow us to make a JSON-based daemon mode.
2024-02-25 09:17:54 -05:00
Dianne Skoll
fe2af14952 Remove obsolete file 2024-02-24 09:46:56 -05:00
Dianne Skoll
8e99ed27e7 Take is_queued into account when deciding to issue banner. 2024-02-24 09:33:59 -05:00
Dianne Skoll
bb12362cc8 Make "Go To Date..." dialog non-modal. 2024-02-14 11:16:24 -05:00
Dianne Skoll
1bfc630a64 Uneascape JSON properly. 2024-02-07 10:27:38 -05:00
Dianne Skoll
987983f8ae Add empty line between queue items. 2024-02-05 13:49:11 -05:00
Dianne Skoll
657a6118aa Set -selectbackground 2024-02-05 13:46:28 -05:00
Dianne Skoll
43e7e6ec7f Alternate queue item background colors. 2024-02-05 10:10:52 -05:00
Dianne Skoll
b8b3c19fbf *sigh* A JSON key was changed. :( 2024-02-05 09:56:47 -05:00
Dianne Skoll
69298c96a5 Make the version of rem2html track the version of Remind. 2024-02-04 21:23:57 -05:00
Dianne Skoll
7356138872 Update release date. 2024-02-04 13:10:19 -05:00
Dianne Skoll
616966f5df Fix spelling in comment 2024-02-04 13:01:45 -05:00
Dianne Skoll
a59e277c21 Fix a couple of typos 2024-02-04 12:59:25 -05:00
Dianne Skoll
740ae2c3e9 Fix some spelling inconsistencies 2024-02-04 12:54:52 -05:00
Dianne Skoll
25b7a40f2b Try hard to avoid integer overflow. 2024-02-03 16:30:39 -05:00
Dianne Skoll
2beaab1a2f More checks on INT * STRING plus a man page note. 2024-02-03 16:29:05 -05:00
Dianne Skoll
60793d53c6 Don't use O(N^2) algorithm for STR * INT 2024-02-03 16:12:54 -05:00
Dianne Skoll
4f869c8c81 Update WHATSNEW 2024-02-03 16:06:13 -05:00
Dianne Skoll
8955180a35 Document INT * STRING and STRING * INT 2024-02-03 16:03:26 -05:00
Dianne Skoll
a30cbf5797 Fix tests. 2024-02-03 16:01:26 -05:00
Dianne Skoll
b2bd6109dc Allow STRING * INT or INT * STRING, which repeats STRING that many times. 2024-02-03 16:00:23 -05:00
Dianne Skoll
9455ec48d7 Include lineno element in JSONQUEUE 2024-02-03 11:06:33 -05:00
Dianne Skoll
f751f5defa Fix up tests for commit 994edbebbe 2024-02-03 11:01:10 -05:00
Dianne Skoll
994edbebbe Proper keys for tdelta, etc. 2024-02-03 11:00:27 -05:00
Dianne Skoll
70959b791c Fix typo 2024-02-03 09:44:30 -05:00
Dianne Skoll
524ece5119 Update WHATSNEW 2024-02-03 09:40:28 -05:00
Dianne Skoll
6334bd61b6 Bump version to 04.02.09 2024-02-03 09:26:42 -05:00
Dianne Skoll
2e56edd557 SystemTime can be int... no need for it to be long. 2024-02-03 09:26:30 -05:00
Dianne Skoll
8cae1d21cd Set time zone. 2024-02-02 22:20:45 -05:00
Dianne Skoll
1de6ed16eb Add check that we don't run the test suite in the failure window. :) 2024-02-02 22:18:53 -05:00
Dianne Skoll
860cb94f41 Add comment 2024-02-02 22:12:45 -05:00
Dianne Skoll
6b505704e9 Fix test failures caused by output that changes based on date. 2024-02-02 22:10:21 -05:00
Dianne Skoll
167631451d Don't alloc/free FileName unnecessarily. 2024-02-02 18:45:31 -05:00
Dianne Skoll
fa5180b94d Refactor JSON output routines. 2024-02-02 16:08:17 -05:00
Dianne Skoll
ae01d7be43 Add a test for queued reminders. 2024-02-02 15:17:01 -05:00
Dianne Skoll
d5ce39ade1 Make a note about OMIT context and queued reminders. 2024-02-02 14:51:55 -05:00
Dianne Skoll
a043dfe8b9 Optimize the search for a queued filename by assuming we're still in the same file as before.
This is very likely to be true and should avoid traversing the list of
filenames in most cases.
2024-02-02 14:25:34 -05:00
Dianne Skoll
7cfb75e3b3 Save filename when queueing reminders. Also, use original trigger structure when triggering.
Before, we'd lose the priority and msgprefix() would mess up.
2024-02-02 14:18:55 -05:00
Dianne Skoll
a18f0d982f Update rem2ps man page. Indicate that no new features will be added; all new development will be on rem2pdf. 2024-01-11 15:48:10 -05:00
Dianne Skoll
0e2dc805c2 Fix some typos; run "make" with -jnproc if possible. 2024-01-09 21:35:31 -05:00
Dianne Skoll
4c1e11df2c Make build.tk executable; update lat/long for Ottawa. 2024-01-09 21:24:55 -05:00
Dianne Skoll
76776d054a Fix typo in build.tk 2024-01-09 21:20:43 -05:00
Dianne Skoll
45ebd05cb6 Minor tweaks. 2024-01-09 21:16:32 -05:00
Dianne Skoll
0203ce3979 Correct the mailing address of the FSF (pointed out by Neil Hanlon) 2024-01-09 16:32:53 -05:00
Dianne Skoll
72d10178bf Mass-update copyright year to 2024. 2023-12-31 12:05:03 -05:00
Dianne Skoll
96f4e26d53 Add "constval" alias for "min" structure field. 2023-12-30 11:33:01 -05:00
Dianne Skoll
4fd86f1b6a Add an entry to BIBLIOGRAPHY 2023-12-29 17:34:29 -05:00
Dianne Skoll
2f3ee0aec3 Clarify limits on full OMITs; document new system variables. 2023-12-28 19:32:53 -05:00
Dianne Skoll
a5dde31160 Update test file for new system vars. 2023-12-28 19:23:27 -05:00
Dianne Skoll
b45428df05 Add system variables: $NumFullOmits, $MaxFullOmits, $NumPartialOmits, $MaxPartialOmits 2023-12-28 19:22:48 -05:00
Dianne Skoll
d938763643 Update test file for new error messages 2023-12-28 19:08:51 -05:00
Dianne Skoll
e4e2157622 Include limits in "too many XXX" error messages. 2023-12-28 19:08:15 -05:00
Dianne Skoll
04b349c6c7 Check write() call for failures. 2023-12-28 18:23:13 -05:00
Dianne Skoll
7fe3eb7391 Avoid warning about ignoring return value. *SIGH* 2023-12-28 18:20:59 -05:00
Dianne Skoll
c1992b577a Check of (very unlikely and probably harmless) integer underflow. 2023-12-27 20:28:46 -05:00
Dianne Skoll
632283d47f Issue a warning if someone OMITs every possible date. 2023-12-27 20:27:26 -05:00
Dianne Skoll
1d9e46997c Don't attempt to obtain terminal background color at startup. Instead, only obtain it if and when it is needed. 2023-12-26 10:08:00 -05:00
Dianne Skoll
861ce34022 Clarify logic. 2023-12-25 10:16:59 -05:00
Dianne Skoll
32e8db322d Stricter parsing of SET command expressions. 2023-12-22 14:22:54 -05:00
Dianne Skoll
3df2b72175 Simplify logic for updating of number of queued reminders. 2023-12-18 14:48:49 -05:00
Dianne Skoll
e7ac4f95be Issue a spontaneous NOTE queued response only if we actually de-queue a reminder. 2023-12-18 14:44:41 -05:00
Dianne Skoll
e7ed69287b Fix existing typo'd line in reminders file. 2023-12-16 13:25:30 -05:00
Dianne Skoll
2e80417f53 Fix silly typo, found by Lorenzo Bazzanini. 2023-12-16 09:35:45 -05:00
Dianne Skoll
ee435d2bb9 Clarify that in server mode, status output can happen at any time and not just in response to a stdin command. 2023-12-15 14:51:21 -05:00
Dianne Skoll
bb516946be If we de-queue a reminder without issuing it, send a NOTE queued %d message in server mode. 2023-12-15 14:16:26 -05:00
Dianne Skoll
81157e1cb5 Update queue status once a minute. 2023-12-15 12:33:41 -05:00
Dianne Skoll
51dfd707a2 One more release note 2023-12-14 16:08:46 -05:00
Dianne Skoll
7c3bf8601b Update WHATSNEW. 2023-12-14 16:05:40 -05:00
Dianne Skoll
714195efe5 Bump version to 04.02.08 2023-12-14 15:58:20 -05:00
Dianne Skoll
eaeca2d09b Minor tweak. 2023-12-12 11:52:27 -05:00
Dianne Skoll
ffa3b13437 Better method to detect if compiler supports -ffat-lto-objects
clang does not support this option, but the configure script was
supplying it anyway, causing warnings.
2023-12-12 09:23:26 -05:00
Dianne Skoll
2551e98d11 Use "now = time(NULL)" rather than (void) time(&now)" 2023-12-11 15:56:42 -05:00
Dianne Skoll
1bfd7761bc Use EXIT_FAILURE / EXIT_SUCCESS consistently. 2023-12-10 10:42:26 -05:00
Dianne Skoll
de9cb1d0a3 Use symbols STDIN_FILENO, etc. 2023-12-10 10:38:42 -05:00
Dianne Skoll
b2d32b514a Catch SIGCONT to force it to interrupt the select() system call. 2023-12-09 19:12:27 -05:00
Dianne Skoll
6e53fd6924 Refactor code: Replace SystemTime(x)/60 with MinutesPastMidnight(x) 2023-12-09 10:41:03 -05:00
Dianne Skoll
8296d2b962 Display "(Queue is empty)" if queue is empty. 2023-12-09 10:30:18 -05:00
Dianne Skoll
d6e66ee1e6 Tighten test for removing very old reminders from queue. 2023-12-09 10:25:50 -05:00
Dianne Skoll
a49532b9c5 Remove non-triggered but expired reminders from the queue. 2023-12-08 14:02:29 -05:00
Dianne Skoll
57d87f4caf Better logic for closing stdin/stdout/stderr if we fork. 2023-12-06 16:39:13 -05:00
Dianne Skoll
ec9b30c616 Don't let "REM ... MSG NOTE endreminder" mess with daemon protocol.
Pad with a leading space. :)
2023-12-06 13:28:17 -05:00
Dianne Skoll
27d8a62ab6 Update SERVER MODE documentation. 2023-12-06 13:17:53 -05:00
Dianne Skoll
5077814c4a Clarify when $MaxLateMinutes is read. 2023-12-06 13:11:28 -05:00
Dianne Skoll
ca795a352a Add the $MaxLateMinutes system variable.
Don't trigger a timed reminder if it's more than $MaxLateMinutes past
the trigger time (for example, if the computer has hibernated and then
been awoken.)
2023-12-03 17:16:48 -05:00
Dianne Skoll
e59fc36458 Use <meta charset="UTF-8"> instead of http-equiv. 2023-10-15 11:25:06 -04:00
Dianne Skoll
39e3657539 Add --utf8 flag to rem2html. 2023-10-15 10:10:27 -04:00
Dianne Skoll
6031f70701 Update the balloon help when we toggle between Queue... and Errors... 2023-10-11 17:20:41 -04:00
Dianne Skoll
3567c9e55f If errors occur during printing, set the "Errors..." button rather than popping up a dialog. 2023-10-11 17:16:27 -04:00
Dianne Skoll
26de4e3fd3 Use bold rather than italice. 2023-10-09 10:39:18 -04:00
Dianne Skoll
cd65c6144d Merge branch 'fix_man' into 'master'
Fix manpage formatting

See merge request dskoll/remind!5
2023-10-09 14:38:07 +00:00
Dianne Skoll
d32edbbb1f Fix release date. 2023-10-09 10:21:33 -04:00
Dianne Skoll
eae48a5538 Update release notes. 2023-10-08 18:17:28 -04:00
Dianne Skoll
63eba104d9 Reinstate tests that only work with 64-bit time_t 2023-10-08 18:09:34 -04:00
Dianne Skoll
ae64961735 Try to use 64-bit time_t on 32-bit systems. 2023-10-08 18:07:14 -04:00
Dianne Skoll
f7bb91320c Return an error rather than (DATETIME) -1 if soleq fails 2023-10-08 11:58:28 -04:00
Dianne Skoll
c11071a859 Undo fixes - the problem is with mktime on 32-bit systems.
Remove tests that break on 32-bit systems.
2023-10-08 11:49:44 -04:00
Dianne Skoll
53cbcc22db Fix typo 2023-10-08 11:35:06 -04:00
Dianne Skoll
af9dcec3e9 Use "long long" for 32-bit systems. 2023-10-08 11:34:10 -04:00
Dianne Skoll
d5a4b0d235 Allow specification of terminal-background mode as 't'
This forces Remind to try to guess the terminal background
even if stdout is not a tty.
2023-10-08 11:19:17 -04:00
Dianne Skoll
3b870403d9 Don't use UTF-8 input. 2023-10-08 11:08:58 -04:00
Dianne Skoll
284d822884 Fix a number of typos. 2023-10-08 10:55:48 -04:00
Dianne Skoll
d881a26ad0 Don't attempt to guess terminal background if supplied in an -@,n option. 2023-10-05 09:52:43 -04:00
Dianne Skoll
8519edde29 Fix logic error. 2023-10-04 10:11:49 -04:00
Dianne Skoll
a30c467c48 Revert "Guess terminal background even if stdout is not a tty"
This reverts commit 887cd83ebe.
2023-10-04 09:36:25 -04:00
Dianne Skoll
887cd83ebe Guess terminal background even if stdout is not a tty 2023-10-04 09:33:54 -04:00
Dianne Skoll
242d787ca2 Update release notes 2023-10-04 09:32:44 -04:00
Dianne Skoll
5dd2cf7356 Update version to 04.02.07 2023-10-04 09:32:38 -04:00
Dianne Skoll
5efb70909d Make -w0 obtain width from STDOUT_FILENO 2023-10-04 09:32:06 -04:00
Dianne Skoll
a60d466774 Document that Remind attempts to figure out terminal background lightness. 2023-10-03 18:59:51 -04:00
Dianne Skoll
1c01f36271 Fix typo 2023-10-03 09:25:45 -04:00
Dianne Skoll
3718632551 Let Remind guess if terminal is dark or light. 2023-10-03 00:09:59 -04:00
Dianne Skoll
e8f3d5ff9f Tweak the terminal background-color guessing code. 2023-10-03 00:04:01 -04:00
Dianne Skoll
d77e27942d Try to guess the terminal background color. 2023-10-03 00:00:59 -04:00
Dianne Skoll
734cc61489 Better logic for checking if we should close TTY fd. 2023-10-02 23:07:34 -04:00
Dianne Skoll
44d489d3d2 Make -w0 behave the same as -wt instead of causing an infinite loop. 2023-10-02 23:03:30 -04:00
Dianne Skoll
3e36ffa9ff Rename function. 2023-10-01 13:56:24 -04:00
Dianne Skoll
12104a96b1 Improve icon. 2023-09-29 18:06:18 -04:00
Dianne Skoll
8ab8d65a15 Document $DeltaOverride 2023-09-27 11:01:28 -04:00
Dianne Skoll
f7a8122cef Document --version 2023-09-25 12:41:57 -04:00
Dianne Skoll
77d9bbb7d6 Add FILES section to man page. 2023-09-25 09:43:06 -04:00
Dianne Skoll
623def52fd Add MAILING LIST section. 2023-09-25 09:38:07 -04:00
Dianne Skoll
d088e35142 Add bug-reporting email address. 2023-09-25 09:37:12 -04:00
Dianne Skoll
5821e55eb8 Add (1) to remind(1) in SEE ALSO section. 2023-09-25 08:28:24 -04:00
Dianne Skoll
1ee989c65d Add example for null date specification. 2023-09-25 08:27:22 -04:00
Dianne Skoll
62388fb21f Add "--version" long option. 2023-09-25 08:23:28 -04:00
Dianne Skoll
13571f84af Fix typo in man page source (found by Dan Jacobson) 2023-09-25 08:15:14 -04:00
Dianne Skoll
03fdc06b65 Make AT optional: If we encounter a TIME, then implicitly start an AT clause. 2023-09-18 12:59:00 -04:00
Dianne Skoll
4bce675ae6 Update remind-conf-mode.el per Bill Benedetto 2023-09-13 18:40:13 -04:00
Jochen Sprickerhof
7b64623115 Fix manpage formatting 2023-09-12 21:08:44 +02:00
106 changed files with 3644 additions and 1881 deletions

1
.gitignore vendored
View File

@@ -16,6 +16,7 @@ man/remind.1
man/tkremind.1
pm_to_blib
rem2html/Makefile
rem2html/rem2html
rem2html/rem2html.1
rem2pdf/Makefile.PL
rem2pdf/Makefile.old

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-2023 Dianne Skoll, except where noted in
2. REMIND is Copyright 1992-2024 Dianne Skoll, except where noted in
individual files.
3. DISTRIBUTION AND USE
@@ -16,7 +16,7 @@ individual files.
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

View File

@@ -1,30 +0,0 @@
MICROSOFT WINDOWS
=================
I used to prohibit porting Remind to Microsoft Windows. However, this
may cause problems with the GPL, so I have removed that restriction.
Although I cannot prevent you from porting Remind to Windows, I appeal
to you not to do it. I am trying to encourage the growth of free
software, not proprietary software.
If you port Remind to Windows, I will not provide support or answers to
questions -- you're on your own. On the other hand, I will feel no guilt
in taking enhancements and merging them into the UNIX stream.
APPLE
=====
I can't prevent you from using Remind on Apple's products, but I hope
you don't. Apple's corporate culture is the very antithesis of Free
Software. Rather than using Mac OS X, I encourage you to switch to
Linux or FreeBSD, two Free Software operating systems that are every
bit as capable as Mac OS X and which are unencumbered by Apple's
arbitrary restrictions.
And if you're looking to port Remind to other Apple products like the
iPhone or iPad, please don't. Those products enforce Apple's rigorous
controls much more stringently than Mac OS X on an Apple PC.
--
Dianne Skoll

View File

@@ -44,7 +44,7 @@ test:
@$(MAKE) -C src -s test
distclean: clean
rm -f config.cache config.log config.status src/Makefile src/config.h tests/test.out www/Makefile rem2pdf/Makefile.top rem2pdf/Makefile.old rem2pdf/Makefile rem2pdf/Makefile.PL rem2pdf/bin/rem2pdf
rm -f config.cache config.log config.status src/Makefile src/config.h tests/test.out www/Makefile rem2pdf/Makefile.top rem2pdf/Makefile.old rem2pdf/Makefile rem2pdf/Makefile.PL rem2pdf/bin/rem2pdf rem2html/rem2html
src/Makefile: src/Makefile.in
./configure

26
build.tk Normal file → Executable file
View File

@@ -27,10 +27,10 @@ exec wish "$0" "$@"
proc SetConfigDefaults {} {
global Config
set Config(LAT_DEG) 45
set Config(LAT_MIN) 24
set Config(LAT_MIN) 25
set Config(LAT_SEC) 14
set Config(LON_DEG) 75
set Config(LON_MIN) 39
set Config(LON_MIN) 41
set Config(LON_SEC) 23
set Config(LOCATION) "Ottawa"
set Config(DEFAULT_PAGE) "Letter"
@@ -53,7 +53,7 @@ proc SetConfigDefaults {} {
# Pops up an error dialog; then calls exit.
#***********************************************************************
proc Bail { msg } {
tk_dialog .err "Remind Configuration Error" $msg error 0 "Bummer"
tk_messageBox -message "Remind Build Error" -detail $msg -icon error -type ok
exit 1
}
@@ -190,8 +190,8 @@ proc CreateLocationDialog { w } {
grid $w.north $w.west
grid $w.south $w.east
grid $w.loclab -sticky e
grid $w.location -sticky nsew -row 6 -column 1
grid $w.loclab -sticky e
grid $w.location -sticky nsew -row 8 -column 1
}
#***********************************************************************
@@ -293,9 +293,9 @@ proc BuildRemind {} {
.msgs insert end "\n>>> Creating src/custom.h...\n\n" green
CreateCustomH
.msgs insert end ">>> Calling `./configure'...\n\n" green
.msgs insert end "\n>>> Calling `./configure'...\n\n" green
CallConfigure
.msgs insert end ">>> Calling `make'...\n\n" green
.msgs insert end "\n>>> Calling `make'...\n\n" green
CallMake
.msgs insert end "\n----------------------------------------------\n\n"
.msgs insert end "Remind" red
@@ -447,12 +447,12 @@ proc CreateCustomH {} {
"#define DEFAULT_LATITUDE *" {
set lat [expr $LAT_DEG + ($LAT_MIN/60.0) + ($LAT_SEC/3600.0)];
puts $out "#define DEFAULT_LATITUDE $lat"
.msgs insert end "#define DEFAULT_LATITUDE $lat"
.msgs insert end "#define DEFAULT_LATITUDE $lat\n"
}
"#define DEFAULT_LONGITUDE *" {
set lon [expr -1.0 * ($LON_DEG + ($LON_MIN/60.0) + ($LON_SEC/3600.0))]
puts $out "#define DEFAULT_LONGITUDE $lon"
.msgs insert end "#define DEFAULT_LONGITUDE $lon"
.msgs insert end "#define DEFAULT_LONGITUDE $lon\n"
}
"#define LOCATION *" {
puts $out "#define LOCATION \"$Config(LOCATION)\""
@@ -506,7 +506,13 @@ proc CallMake {} {
"Icelandic" { set lang ICELANDIC }
default { set lang ENGLISH }
}
RunCommand "make \"LANGDEF=-DLANG=$lang\""
set nproc 0
catch { set nproc [exec nproc] }
if { $nproc != 0 } {
RunCommand "make -j $nproc \"LANGDEF=-DLANG=$lang\""
} else {
RunCommand "make \"LANGDEF=-DLANG=$lang\""
}
}

136
configure vendored
View File

@@ -1511,6 +1511,39 @@ fi
} # ac_fn_c_try_link
# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists and can be compiled using the include files in
# INCLUDES, setting the cache variable VAR accordingly.
ac_fn_c_check_header_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
printf %s "checking for $2... " >&6; }
if eval test \${$3+y}
then :
printf %s "(cached) " >&6
else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
eval "$3=yes"
else $as_nop
eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
eval ac_res=\$$3
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_header_compile
# ac_fn_c_try_run LINENO
# ----------------------
# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that
@@ -1743,39 +1776,6 @@ rm -f conftest.val
} # ac_fn_c_compute_int
# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists and can be compiled using the include files in
# INCLUDES, setting the cache variable VAR accordingly.
ac_fn_c_check_header_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
printf %s "checking for $2... " >&6; }
if eval test \${$3+y}
then :
printf %s "(cached) " >&6
else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
eval "$3=yes"
else $as_nop
eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
eval ac_res=\$$3
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_header_compile
# ac_fn_c_check_func LINENO FUNC VAR
# ----------------------------------
# Tests whether FUNC exists, setting the cache variable VAR accordingly
@@ -2449,8 +2449,8 @@ as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H"
as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
as_fn_append ac_header_c_list " utime.h utime_h HAVE_UTIME_H"
as_fn_append ac_header_c_list " sys/time.h sys_time_h HAVE_SYS_TIME_H"
as_fn_append ac_header_c_list " utime.h utime_h HAVE_UTIME_H"
# Auxiliary files required by this configure script.
ac_aux_files="install-sh"
@@ -3872,7 +3872,6 @@ then :
fi
ac_header= ac_cache=
for ac_item in $ac_header_c_list
do
@@ -3902,6 +3901,9 @@ then :
printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
fi
# The cast to long int works around a bug in the HP C Compiler
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
@@ -3968,6 +3970,39 @@ printf "%s\n" "$ac_cv_sizeof_unsigned_long" >&6; }
printf "%s\n" "#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long" >>confdefs.h
# The cast to long int works around a bug in the HP C Compiler
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
# This bug is HP SR number 8606223364.
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5
printf %s "checking size of time_t... " >&6; }
if test ${ac_cv_sizeof_time_t+y}
then :
printf %s "(cached) " >&6
else $as_nop
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" "$ac_includes_default"
then :
else $as_nop
if test "$ac_cv_type_time_t" = yes; then
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (time_t)
See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_sizeof_time_t=0
fi
fi
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5
printf "%s\n" "$ac_cv_sizeof_time_t" >&6; }
printf "%s\n" "#define SIZEOF_TIME_T $ac_cv_sizeof_time_t" >>confdefs.h
ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_types_h" = xyes
@@ -3999,6 +4034,12 @@ then :
printf "%s\n" "#define HAVE_LANGINFO_H 1" >>confdefs.h
fi
ac_fn_c_check_header_compile "$LINENO" "sys/inotify.h" "ac_cv_header_sys_inotify_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_inotify_h" = xyes
then :
printf "%s\n" "#define HAVE_SYS_INOTIFY_H 1" >>confdefs.h
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
@@ -4093,23 +4134,20 @@ printf "%s\n" "#define HAVE_UTIME_NULL 1" >>confdefs.h
fi
rm -f conftest.data
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
# Check for link-time optimization support
f=-flto=auto
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $f" >&5
printf %s "checking whether $CC supports $f... " >&6; }
if $CC -E $f /dev/null > /dev/null 2>&1 ; then
if $CC -Werror -E $f - < /dev/null > /dev/null 2>&1 ; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
CFLAGS="$CFLAGS $f"
f=-ffat-lto-objects
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $f" >&5
printf %s "checking whether $CC supports $f... " >&6; }
if $CC -E $f /dev/null > /dev/null 2>&1 ; then
if $CC -Werror -E $f - < /dev/null > /dev/null 2>&1 ; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
CFLAGS="$CFLAGS $f"
@@ -4123,6 +4161,12 @@ printf "%s\n" "no" >&6; }
fi
fi
if test "$ac_cv_sizeof_time_t" = "4" ; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: time_t is 32-bits on this system; attempting to use 64-bit time_t" >&5
printf "%s\n" "$as_me: time_t is 32-bits on this system; attempting to use 64-bit time_t" >&6;}
CFLAGS="$CFLAGS -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64"
fi
if test "$ac_cv_perlartifacts" = "yes" ; then
PERLARTIFACTS=
else
@@ -4173,13 +4217,20 @@ then :
printf "%s\n" "#define HAVE_INITGROUPS 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "inotify_init1" "ac_cv_func_inotify_init1"
if test "x$ac_cv_func_inotify_init1" = xyes
then :
printf "%s\n" "#define HAVE_INOTIFY_INIT1 1" >>confdefs.h
VERSION=04.02.06
fi
VERSION=04.03.05
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h rem2html/Makefile rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1"
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h rem2html/Makefile rem2html/rem2html rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -4871,6 +4922,7 @@ do
"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" ;;
"rem2html/rem2html") CONFIG_FILES="$CONFIG_FILES rem2html/rem2html" ;;
"rem2pdf/Makefile.PL") CONFIG_FILES="$CONFIG_FILES rem2pdf/Makefile.PL" ;;
"rem2pdf/Makefile.top") CONFIG_FILES="$CONFIG_FILES rem2pdf/Makefile.top" ;;
"rem2pdf/bin/rem2pdf") CONFIG_FILES="$CONFIG_FILES rem2pdf/bin/rem2pdf" ;;

View File

@@ -30,32 +30,32 @@ AC_PATH_PROG([PERL], [perl])
dnl Checks for libraries.
AC_CHECK_LIB(m, sqrt)
AC_CHECK_HEADERS_ONCE([sys/time.h])
dnl Integer sizes
AC_CHECK_SIZEOF(unsigned int)
AC_CHECK_SIZEOF(unsigned long)
AC_CHECK_SIZEOF(time_t)
dnl Checks for header files.
AC_CHECK_HEADERS(sys/types.h glob.h wctype.h locale.h langinfo.h)
AC_CHECK_HEADERS(sys/types.h glob.h wctype.h locale.h langinfo.h sys/inotify.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_STRUCT_TM
dnl Checks for library functions.
AC_FUNC_UTIME_NULL
AC_CHECK_HEADERS_ONCE([sys/time.h])
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
# Check for link-time optimization support
f=-flto=auto
AC_MSG_CHECKING([whether $CC supports $f])
if $CC -E $f /dev/null > /dev/null 2>&1 ; then
if $CC -Werror -E $f - < /dev/null > /dev/null 2>&1 ; then
AC_MSG_RESULT([yes])
CFLAGS="$CFLAGS $f"
f=-ffat-lto-objects
AC_MSG_CHECKING([whether $CC supports $f])
if $CC -E $f /dev/null > /dev/null 2>&1 ; then
if $CC -Werror -E $f - < /dev/null > /dev/null 2>&1 ; then
AC_MSG_RESULT([yes])
CFLAGS="$CFLAGS $f"
else
@@ -66,6 +66,12 @@ if test "$GCC" = yes; then
fi
fi
dnl If sizeof(time_t) is 4, try to get 64-bit time_t
if test "$ac_cv_sizeof_time_t" = "4" ; then
AC_MSG_NOTICE([time_t is 32-bits on this system; attempting to use 64-bit time_t])
CFLAGS="$CFLAGS -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64"
fi
if test "$ac_cv_perlartifacts" = "yes" ; then
PERLARTIFACTS=
else
@@ -80,12 +86,13 @@ if test "$?" != 0 ; then
echo "*** COULD NOT DETERMINE RELEASE DATE: docs/WHATSNEW is incorrect!"
exit 1
fi
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale initgroups)
VERSION=04.02.06
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale initgroups inotify_init1)
VERSION=04.03.05
AC_SUBST(VERSION)
AC_SUBST(PERL)
AC_SUBST(PERLARTIFACTS)
AC_SUBST(RELEASE_DATE)
AC_CONFIG_FILES([src/Makefile www/Makefile src/version.h rem2html/Makefile rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1])
AC_CONFIG_FILES([src/Makefile www/Makefile src/version.h rem2html/Makefile rem2html/rem2html rem2pdf/Makefile.PL rem2pdf/Makefile.top rem2pdf/bin/rem2pdf man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1])
AC_OUTPUT
chmod a+x rem2pdf/bin/rem2pdf

View File

@@ -19,8 +19,7 @@
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
;; 02111-1307, USA.
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
;;; Commentary:
@@ -514,6 +513,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 'comment-end-skip) "[ \t]*\\(\\s>\\||#\\)")
(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)

View File

@@ -95,7 +95,7 @@ Norman Walsh.
#!/usr/local/bin/wish
wm withdraw .
after 15000 { destroy . ; exit }
tk_dialog .d { Message } $argv warning 0 { OK }
tk_messageBox -message Message -detail $argv -icon info -type ok
destroy .
exit
-------------- Cut Here ---------- Cut Here ---------- Cut Here -------------

View File

@@ -1,5 +1,237 @@
CHANGES TO REMIND
* VERSION 4.3 Patch 5 - 2024-04-01
* IMPROVEMENT: remind: Use inotify to detect reminder file changes
even in regular daemon mode (-zn where n>0).
* INTERNAL IMPROVEMENTS: Rearrange and refactor some code.
* FIXES: Various fixes and improvements to man pages.
* BUG FIX: remind: Handle queued "SPECIAL COLOR" reminders correctly.
* BUG FIX: remind: Preserve the value of $DefaultColor that was in effect
when a reminder was queued; restore it before issuing the queued reminder.
* VERSION 4.3 Patch 4 - 2024-03-25
* NEW FEATURE: remind: Add the new "multitrig" function, which is how "trig"
should have worked in the first place. See man page for details.
* IMPROVEMENT: tkremind: Make errors in your reminders file stand out more
prominently.
* IMPROVEMENT: tkremind: If you click on an error in the "Errors..." popup,
tkremind will open a text editor on the offending file and line.
* IMPROVEMENT: tkremind: Format the "Queue..." output better and make queue
items clickable; clicking on a queue item opens a text editor on the
corresponding file and line.
* IMPROVEMENT: Add a standard [$SysInclude]/moonphases.rem file to display
moon phases on your calendar.
* IMPROVEMENT: Clean up the demo code in www/ and add PDF output.
* BUG FIX: tkremind: Correctly handle filenames containing spaces and other
characters that tend to confuse the shell.
* BUG FIX: tkremind: Raise dialog boxes after errors so that they
remain visible.
* CLEANUP: tkremind: Remove some dead code.
* VERSION 4.3 Patch 3 - 2024-03-18
* IMPROVEMENT: tkremind: Update icon to include a white border so it shows
up better on dark backgrounds.
* IMPROVEMENT: C code: Fix a number of cppcheck static-analysis warnings.
* IMPROVEMENT: remind: Update the "-zj" protocol to include a queue-id for
each queued reminder and add the DEL client command to delete a specific
item from the queue. Used by tkremind to implement "don't remind me about
this again today."
* MINOR NEW FEATURE: Add a "-ds" debugging flag to print out expression-parsing
stack high-water marks on exit. This esoteric feature is of no use to
anyone but the Remind author.
* IMPROVEMENT: tkremind: Stop using the deprecated tk_dialog command in favor
of the newer tk_messageBox command.
* IMPROVEMENT: remind: In server mode, try to minimize redraws by
consuming inotify events until at least 0.2s elapses without an
event appearing.
* BUG FIX: tkremind: The "Don't remind me about this again today" feature
was unreliable and only worked for reminders created with TkRemind itself.
It has been made more reliable and works with any reminder.
* BUG FIX: remind: Make it a syntax error if a local OMIT in a REM statement
is not followed by at least one weekday name.
* VERSION 4.3 Patch 2 - 2024-03-01
- BUG FIX: remind: Fix a logic error when implementing the RUN command in
server mode. As it turns out, the error is harmless, but it's best to do
things correctly.
- BUG FIX: The Makefile would install the tkremind.png and tkremind.desktop
files in the wrong location. This has been fixed.
* VERSION 4.3 Patch 1 - 2024-02-29
- BUG FIX: tests: "make test" could fail because of a bad test. This
has been fixed. There are no actual code changes to any of the programs
in Remind compared to 04.03.00.
* VERSION 4.3 Patch 0 - 2024-02-29
- IMPROVEMENT: remind: If Remind is compiled on a system that supports
inotify, then in server mode (-z0 or -zj) it monitors the reminders file
and restarts itself if it detects a change, and also notifies the client.
Moving inotify support directly into Remind means that tkremind no longer
has to invoke a separate inotifywait process.
- IMPROVEMENT: remind: Set the CLOEXEC flag on files we open so we
don't leak file descriptors to programs that we run. While I don't
think there's a security issue here (any program you run can do
anything as your userid anyway) it's best to be clean and tidy.
- IMPROVEMENT: remind: Add localization for the Catalan language, courtesy
of Eloi Torrents.
- IMPROVEMENT: tkremind: Add a .desktop file and icon so TkRemind can be
integrated into the desktop menu system, courtesy of Eloi Torrents.
- CHANGE: Add a new server mode with the "-zj" flag. This is just
like "-z0" except it uses JSON messages to communicate with the
client rather than an ad-hoc protocol. The "-z0" mode is still
supported, but is deprecated.
- CHANGE: In server mode (-z0 or -zj) any RUN-type reminders, or message
commands of the "-kcommand" type are run with standard input and standard
output connected to /dev/null. NOTE INCOMPATIBILITY: If you previously
relied on RUN-type reminders to pop up reminders in TkRemind, they no
longer do. If you want this, you'll have to get the command that you
run to pop up its own window with "xmessage" or something similar.
- IMPROVEMENT: tkremind: Make the "Go to date..." dialog non-modal.
- CHANGE: remind: Allow the argument to easterdate() and
orthodoxeaster() to be omitted, in which case it defaults to
today().
- BUG FIX: Miscellaneous man page fixes.
- BUG FIX: Fix a leap-year edge-case. The reminder: REM 29 MSG whatever
was not triggered on Feb 29 of leap years.
- BUG FIX: rem2html: Make the version of rem2html track the version of
Remind. Noted by Ian! D. Allen.
* VERSION 4.2 Patch 9 - 2024-02-04
- CHANGE: remind: Do not attempt to guess terminal background color on
startup. Only obtain it as needed. This can prevent mojibake from
appearing on terminals that don't support the color query escape
sequence.
- IMPROVEMENT: remind: Add new system variables $NumFullOmits,
$MaxFullOmits, $NumPartialOmits and $MaxPartialOmits.
- IMPROVEMENT: remind: Issue a warning if someone OMITs every possible date.
- IMPROVEMENT: remind: In several error messages complaining about limits
being exceeded, include the actual limit in the error message. Clarify
the man page regarding limits on the number of OMITs.
- MINOR NEW FEATURE: remind: The expression STRING * INT or INT * STRING
is now accepted and yields a string that is INT concatenations of the
original STRING. In this case, INT must be non-negative and the total
string length can't exceed $MaxStringLen.
- DOCUMENTATION: Add "Astronomical Algorithms" by Jean Meeus to bibliography.
- DOCUMENTATION FIX: Update address of the Free Software Foundation in the
license file.
- DOCUMENTATION: Note that rem2ps is deprecated and will not received any
new features. Further development will happen on rem2pdf.
- BUG FIX: Preserve the filename() and priority context for queued reminders.
Previously, the filename information was lost and the priority was
coming from uninitialized memory (yikes!). bug found by Alexander
Möller.
- BUG FIX: build.tk: Various minor improvements.
- BUG FIX: remind: In server mode, if we de-queue a reminder without
triggering it, issue a "NOTE queued %d" message to update the
client's notion of the queue size.
- BUG FIX: tkremind: Fix typo found by Lorenzo Bazzanini.
* VERSION 4.2 Patch 8 - 2023-12-14
- NEW FEATURE: Add the $MaxLateMinutes system variable. This suppresses
a queued time reminder if the current time is more than $MaxLateMinutes
past the trigger time. (This typically only occurs if the computer
has been suspended/hibernated and then resumed.)
- IMPROVEMENT: tkremind: If an error occurs during printing, catch it
and change the Queue... button to Errors... (the same way errors in
reminder files are handled.)
- IMPROVEMENT: rem2html: add the --utf8 flag to set the HTML charset to
UTF-8.
- MINOR IMPROVEMENTS: Refactor some of the C code; use symbolic exit
statuses and file descriptors for stdin/stdout/stderr where possible.
- BUG FIX: configure.in: Use better option detection so we don't use the
unsupported option -ffat-lto-objects if compiling with clang instead of gcc.
- BUG FIXES: Many fixes to man pages, some by Jochen Sprickerhof
- MINOR BUG FIX: If Remind puts itself in the background, only close
stdout/stderr if they are not associated with a terminal. If
we close a descriptor, dup /dev/null onto it.
- MINOR BUG FIX: Catch SIGCONT when running in daemon/background mode.
This forces the select() call to be interrupted so we can update the
sleep time. This really only matters if the computer or the background
Remind process is suspended and then resumed.
* VERSION 4.2 Patch 7 - 2023-10-09
- IMPROVEMENT: remind: On 32-bit systems, attempt to use a 64-bit time_t
if the C library supports that. This lets Remind work properly with
dates after 2038 in the few cases it has to call mktime() internally.
- MINOR NEW FEATURE: remind: Attempt to obtain the terminal background
color using an OSC sequence. This normally only happens if standard
output is a terminal, but can be forced with the '-@..,t' option.
- MINOR NEW FEATURE: remind: Add "--version" long option to print out
Remind's version and exit.
- MINOR IMPROVEMENT: tkremind: Use a higher-resolution PNG image for
the icon.
- MINOR IMPROVEMENT: remind-conf-mode.el: Update highlighting rules
courtesy of Bill Benedetto
- MINOR CHANGE: Make AT optional. If we encounter a TIME in a REM
command, implicitly begin an AT clause.
- DOCUMENTATION: Many minor fixes and improvements courtesy of Dan Jacobson.
- BUG FIX: Make "-w0" set the calendar width based on standard output
rather than setting it to zero and causing an infinite loop.
* VERSION 4.2 Patch 6 - 2023-09-12
- NEW FEATURE: remind: The "nonomitted()" function takes an optional

View File

@@ -10,7 +10,7 @@ FSET center(x) pad("", " ", (columns() - columns(x))/2) + x
FSET right(x) pad("", " ", columns() - columns(x)) + x
MSG This is left-aligned.
MSG [ansicolor(0,255,0)]This is also left-aligned.[ansicolor("")]
MSG [ansicolor(0,255,0)]🌕 🌕 🌕 🌕 This is also left-aligned.[ansicolor("")]
MSG [center("This is centered.")]
MSG [ansicolor(255,255,0) + center("🌕 🌕 🌕 🌕 This is also centered. ") + ansicolor("")]

View File

@@ -8,15 +8,13 @@
# Set this variable to 1 if your terminal has a dark background or 0 if
# it: light.
bg_dark=1
# Set your latitude and longitude correctly for Sunrise/Sunset/Equinox/Solstice
#
# The values below are for Ottawa, Ontario, Canada
latitude="45.420556"
longitude="-75.689722"
remind -g -ibg_dark="$bg_dark" "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
remind -g "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
SET $AddBlankLines 0
BANNER %
@@ -24,24 +22,25 @@ INCLUDE [$SysInclude]/ansitext.rem
MSG Today is [ansi_bold][$T][ansi_normal], being the [ord($T-date(year($T),1,1)+1)] day of [year($T)].%_
IF bg_dark
IF $TerminalBackground == 0
SPECIAL COLOR 255 255 0 Sunrise: 🌅 [sunrise()] today and [sunrise($T+1)] tomorrow
SPECIAL COLOR 255 128 0 Sunset: 🌇 [sunset()] today and [sunset($T+1)] tomorrow%_
ELSE
SPECIAL COLOR 128 128 0 Sunrise: 🌅 [sunrise()] today and [sunrise($T+1)] tomorrow
SPECIAL COLOR 128 32 0 Sunset: 🌇 [sunset()] today and [sunset($T+1)] tomorrow%_
ENDIF
EOF
remind -g -ibg_dark="$bg_dark" "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
remind -g "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
SET $AddBlankLines 0
BANNER %
IF bg_dark
IF $TerminalBackground == 0
REM [moondatetime(0)] +60 SPECIAL COLOR 255 255 0 New moon: 🌑 [$T] %3 (%b)
REM [moondatetime(1)] +60 SPECIAL COLOR 255 255 128 First Quarter: 🌓 [$T] %3 (%b)
REM [moondatetime(2)] +60 SPECIAL COLOR 255 255 255 Full moon: 🌕 [$T] %3 (%b)
REM [moondatetime(3)] +60 SPECIAL COLOR 255 255 128 Last Quarter: 🌗 [$T] %3 (%b)
ELSE
SPECIAL COLOR 128 128 0 Sunrise: 🌅 [sunrise()] today and [sunrise($T+1)] tomorrow
SPECIAL COLOR 128 32 0 Sunset: 🌇 [sunset()] today and [sunset($T+1)] tomorrow%_
REM [moondatetime(0)] +60 SPECIAL COLOR 128 128 0 New moon: 🌑 [$T] %3 (%b)
REM [moondatetime(1)] +60 SPECIAL COLOR 128 128 64 First Quarter: 🌓 [$T] %3 (%b)
REM [moondatetime(2)] +60 SPECIAL COLOR 0 0 0 Full moon: 🌕 [$T] %3 (%b)
@@ -51,7 +50,7 @@ EOF
echo ""
remind -g -ibg_dark="$bg_dark" "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
remind -g "-i\$Latitude=\"$latitude\"" "-i\$Longitude=\"$longitude\"" -q -@2 - "$@" <<'EOF'
SET $AddBlankLines 0
BANNER %

View File

@@ -16,7 +16,7 @@
# "#PSSTUFF" for nifty PostScript examples #
# #
# This file is part of REMIND. #
# Copyright (C) 1992-2023 Dianne Skoll #
# Copyright (C) 1992-2024 Dianne Skoll #
# SPDX-License-Identifier: GPL-2.0-only
# #
#############################################################################

View File

@@ -2,7 +2,7 @@
# Not all sequences are supported by all terminals.
# This file is part of REMIND
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# SPDX-License-Identifier: GPL-2.0-only
if !defined("ansi_bold")

View File

@@ -1,6 +1,6 @@
# US holidays
# This file is part of REMIND.
# Copyright (C) 1992-2023 Dianne Skoll
# Copyright (C) 1992-2024 Dianne Skoll
# SPDX-License-Identifier: GPL-2.0-only
REM [easterdate($Uy)-46] MSG Ash Wednesday

53
include/lang/ca.rem Normal file
View File

@@ -0,0 +1,53 @@
# Support for the Catalan language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file was created by Eloi Torrents <eloitor@disroot.org>
SET $Monday "dilluns"
SET $Tuesday "dimarts"
SET $Wednesday "dimecres"
SET $Thursday "dijous"
SET $Friday "divendres"
SET $Saturday "dissabte"
SET $Sunday "diumenge"
SET $January "gener"
SET $February "febrer"
SET $March "març"
SET $April "abril"
SET $May "maig"
SET $June "juny"
SET $July "juliol"
SET $August "agost"
SET $September "setembre"
SET $October "octubre"
SET $November "novembre"
SET $December "desembre"
SET $Today "avui"
SET $Tomorrow "demà"
FSET subst_bx(a,d,t) iif(d==today()+2, "demà passat", "d'aquí " + (d-today()) + " dies")
# 1 d'abril vs 1 de maig.
FSET subst_sx(a,d,t) iif(isany(substr(mon(d), 1, 1), "a", "o") , "d'", "de")
FSET subst_ordinal(d) ""
BANNER Agenda pel %w, %d %s %m de %y%o:
SET $Am "am"
SET $Pm "pm"
SET $Ago "fa"
SET $Fromnow "des d'avui"
SET $On "el dia"
SET $Now "ara"
SET $At "a les"
SET $Minute "minut"
SET $Mplu "s"
SET $Hour "hora"
FSET subst_hours(h) iif(h==1, "1 hora", h + " hores")
SET $Is "és"
SET $Was "va ser"
SET $And "i"

View File

@@ -1,6 +1,6 @@
# Support for the Danish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Mogens Lynnerup.
SET $Sunday "Søndag"

View File

@@ -1,6 +1,6 @@
# Support for the German language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Wolfgang Thronicke
# Day names

View File

@@ -1,4 +1,4 @@
# Support for the English language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# Nothing to do for English since it is the default.

View File

@@ -1,6 +1,6 @@
# Support for the Spanish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Rafa Couto <rafacouto@biogate.com>
SET $Sunday "Domingo"

View File

@@ -1,6 +1,6 @@
# Support for the Finnish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Mikko Silvonen
SET $Sunday "sunnuntai"

View File

@@ -1,6 +1,6 @@
# Support for the French language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Laurent Duperval
SET $Sunday "dimanche"

View File

@@ -1,6 +1,6 @@
# Support for the Hellenic (Greek) language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by jarlaxl lamat (jarlaxl@freemail.gr)
SET $Sunday "Κυριακή"

View File

@@ -1,6 +1,6 @@
# Support for the Icelanding language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Björn Davíðsson (bjossi@snerpa.is)
SET $Sunday "sunnudagur"

View File

@@ -1,6 +1,6 @@
# Support for the Italian language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Valerio Aimale
SET $Sunday "Domenica"

View File

@@ -1,6 +1,6 @@
# Support for the Dutch language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Willem Kasdorp and Erik-Jan Vens
SET $Sunday "zondag"

View File

@@ -1,6 +1,6 @@
# Support for the Norwegian language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Trygve Randen
SET $Sunday "Søndag"

View File

@@ -1,6 +1,6 @@
# Support for the Polish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Jerzy Sobczyk
SET $Sunday "Niedziela"

View File

@@ -1,6 +1,6 @@
# Support for the (Brazilian) Portuguese language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Marco Paganini
SET $Sunday "domingo"

View File

@@ -1,6 +1,6 @@
# Support for the Romanian language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2023 by Dianne Skoll
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# This file is derived from a translation by Liviu Daia
SET $Sunday "Duminică"

14
include/moonphases.rem Normal file
View File

@@ -0,0 +1,14 @@
# Moon phases
# SPDX-License-Identifier: GPL-2.0-only
IF $CalMode || $PsCal
REM [moondate(0)] SPECIAL MOON 0 -1 -1 [moontime(0)]
REM [moondate(1)] SPECIAL MOON 1 -1 -1 [moontime(1)]
REM [moondate(2)] SPECIAL MOON 2 -1 -1 [moontime(2)]
REM [moondate(3)] SPECIAL MOON 3 -1 -1 [moontime(3)]
ELSE
REM NOQUEUE [moondatetime(0)] MSG New Moon (%2)
REM NOQUEUE [moondatetime(1)] MSG First Quarter (%2)
REM NOQUEUE [moondatetime(2)] MSG Full Moon (%2)
REM NOQUEUE [moondatetime(3)] MSG Last Quarter (%2)
ENDIF

View File

@@ -19,4 +19,4 @@ Remind was written by Dianne Skoll <dianne@skoll.ca>
.SH HOME PAGE
https://dianne.skoll.ca/projects/remind/
.SH SEE ALSO
\fBremind\fR
\fBremind\fR(1)

View File

@@ -5,22 +5,25 @@ 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
\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
Although \fBrem2ps\fR will be maintained, no new features will be added
to it. Instead, all new development will continue on \fBrem2pdf\fR.
.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
back-ends.
.PP
Note that \fBRem2PS\fR does not handle UTF-8 input. If you need to
Note that \fBrem2ps\fR does not handle UTF-8 input. If you need to
render characters outside the ASCII character set, see
\fBrem2pdf\fR instead.
.SH OPTIONS
.TP
.B \-v
Be more verbose. This causes \fBRem2ps\fR to print progress messages
Be more verbose. This causes \fBrem2ps\fR to print progress messages
to the standard error stream. Normally, it is silent.
.TP
.B \-p file
@@ -133,7 +136,7 @@ numbers.
.PP
Type "rem2ps \-m help" for a list of available media. Note that the media
type (and all \fBRem2ps\fR options) are case-sensitive. If you don't use
type (and all \fBrem2ps\fR options) are case-sensitive. If you don't use
the \fB\-m\fR option, the media defaults to a compiled-in default - this
is usually Letter for North America and A4 for Europe. The "\-m help"
option will display the compiled-in default.
@@ -193,8 +196,8 @@ for good output:
rem2ps \-ol 72 \-sh 12
.fi
.SH USAGE
To use \fBRem2ps\fR, you should pipe the output of \fBRemind\fR with the \fB\-p\fR
option to \fBRem2ps\fR, and then send the result to a printer. This is most easily
To use \fBrem2ps\fR, you should pipe the output of \fBRemind\fR with the \fB\-p\fR
option to \fBrem2ps\fR, and then send the result to a printer. This is most easily
illustrated with examples:
.PP
.nf
@@ -228,10 +231,10 @@ calendar entries. This border is normally blank space.
.TP
BoxWidth and BoxHeight
The width and height of the calendar box, from center-to-center of the
black gridlines.
black grid lines.
.TP
InBoxHeight
The height from the center of the bottom black gridline to the top
The height from the center of the bottom black grid line to the top
of the regular calendar entry area. The space from here to the top
of the box is used only to draw the day number.
.TP
@@ -260,7 +263,7 @@ PostScript files. Always test your PostScript thoroughly with a PostScript
viewer before sending it to the printer. You should not use any document
structuring comments in your PostScript code.
.PP
In addition, prior to drawing a calendar page, \fBRem2ps\fR emits
In addition, prior to drawing a calendar page, \fBrem2ps\fR emits
the following PostScript code:
.PP
.nf
@@ -320,14 +323,14 @@ For an example, create a file called "myprolog" whose contents are:
} bind def
.fi
.PP
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
Use that file with the \fBrem2ps\fR \fB\-p\fR option to create calendars
with the year and month in large gray letters in the background of the
calendar.
.PP
.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
encouraged 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
@@ -380,7 +383,7 @@ been set to "-". The consistent use of "/" is designed to ease parsing.
.PP
\fIspecial\fR is a string used
for "out-of-band" communication with back-ends. If the reminder
is a normal reminder, \fIspecial\fR is "*". The \fBRem2PS\fR
is a normal reminder, \fIspecial\fR is "*". The \fBrem2ps\fR
back-end understands the specials \fBPostScript\fR and \fBPSFile\fR.
Other back-ends may understand other specials. A back end should
\fIsilently ignore\fR a reminder with a special it doesn't understand.
@@ -458,7 +461,7 @@ 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
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
@@ -674,17 +677,17 @@ is desired.
.SH AUTHOR
Rem2PS was written by Dianne Skoll <dianne@skoll.ca>
rem2ps was written by Dianne Skoll <dianne@skoll.ca>
.SH BUGS
All \fBRem2ps\fR options are case-sensitive, unlike \fBRemind\fR.
All \fBrem2ps\fR options are case-sensitive, unlike \fBRemind\fR.
Any time you supply
a font name or size, line thickness, or border width, it is treated as a
string and sent straight to the PostScript interpreter. Thus, if you
supply invalid fonts or sizes, \fBRem2ps\fR will not complain, but the
supply invalid fonts or sizes, \fBrem2ps\fR will not complain, but the
resulting PostScript output will probably not work.
.PP
You should ensure that the values you supply for margin widths are sensible.
If they are too big for the media size, \fBRem2ps\fR will not complain,
If they are too big for the media size, \fBrem2ps\fR will not complain,
but again, the PostScript output will probably not work.
.SH HOME PAGE
https://dianne.skoll.ca/projects/remind/

View File

@@ -28,6 +28,10 @@ Anything after the __EOF__ marker is completely ignored.
\fBRemind\fR has a slew of options. If you're new to the program,
ignore them for now and skip to the section "REMINDER FILES".
.TP
.B \-\-version
The \fB\-\-version\fR option causes \fBRemind\fR to print its version number
to standard output and then exit.
.TP
.B \-n
The \fB\-n\fR option causes \fBRemind\fR to print the \fBnext\fR occurrence
of each reminder in a simple calendar format. You can sort this by
@@ -62,7 +66,7 @@ causes \fBRemind\fR to display reminders on the calendar on the
day they actually occur \fIas well as\fR on any preceding days
specified by the reminder's \fIdelta\fR. This \fIalso\fR causes
\fBRemind\fR to include text outside %"...%" sequences that would
otherwise be removed (though the actual %" markers themseves are removed.)
otherwise be removed (though the actual %" markers themselves are removed.) \"" Add comment to avoid Emacs highlighting problems
.TP
.B 'l'
causes \fBRemind\fR to use VT100 line-drawing characters to draw
@@ -105,11 +109,18 @@ If the optional \fIm\fR parameter is supplied following a comma, then
\fIm\fR=0 tells \fBRemind\fR that the terminal background is dark, and
\fBRemind\fR will brighten up dark colors to make them visible. If
\fIm\fR=1, then \fBRemind\fR assumes the terminal background is light
and it will darken bright colors to make them visible. If no \fIm\fR
is supplied, or it is supplied as \fIm\fR=2, then \fBRemind\fR does
not perform any adjustments, and some reminders may be hard or
impossible to see if the color is too close to the terminal background
color.
and it will darken bright colors to make them visible. If \fIm\fR is
specified as 2, then \fBRemind\fR does not perform any adjustments,
and some reminders may be hard or impossible to see if the color is
too close to the terminal background color. If you supply the letter
\fBt\fR rather than a number, then Remind attempts to guess the background
color of the terminal, \fIeven if\fR stdout is not a terminal.
.PP
On startup, if the standard output is a terminal, \fBRemind\fR
attempts to determine if the terminal background is dark or light by
sending a special escape sequence to determine the background color.
The \fIm\fR parameter can override this check (or force it if
\fIm\fR is given as \fBt\fR.)
.PP
If the optional \fIb\fR parameter is supplied following a comma, then
\fIb=0\fR tells \fBRemind\fR to ignore SPECIAL SHADE reminders (the
@@ -225,7 +236,7 @@ regardless of the \fIdelta\fR supplied for each reminder.
.B \-t\fR\fIn\fR
If you supply a number \fIn\fR after the \fB\-t\fR option, then
\fBRemind\fR pretends that echo \fBREM\fR command has a delta
of \+\+\fIn\fR, regardles of any existing delta.
of \+\+\fIn\fR, regardless of any existing delta.
.TP
.B \-tz\fR
If you supply the letter \fBz\fR after the \fB\-t\fR option, then
@@ -289,6 +300,11 @@ Echo lines when displaying error messages
.TP
.B f
Trace the reading of reminder files
.TP
.B s
Upon exit, print the high-water mark of the operator and value stacks
used for expression-parsing. This is unlikely to be useful unless
you're intimately familiar with Remind's source code.
.RE
.TP
\fB\-g\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR]]]]
@@ -350,16 +366,24 @@ You use both \fB\-k\fR\fIcmd1\fR and \fB\-k:\fR\fIcmd2\fR to use different
commands for queued versus non-queued reminders.
.RE
.TP
\fB\-z\fR[\fIn\fR] Runs \fBRemind\fR in the daemon mode. If \fIn\fR
\fB\-z\fR[\fIn\fR] Runs \fBRemind\fR in "daemon mode". If \fIn\fR
is supplied, it specifies how often (in minutes) \fBRemind\fR should
wake up to check if the reminder script has been changed. \fIN\fR
defaults to 1, and can range from 1 to 60. Note that the use of the
\fB\-z\fR option also enables the \fB\-f\fR option.
.PP
.RS
If you supply the option \fB\-z0\fR, \fBRemind\fR runs in a
If \fBRemind\fR is compiled on a system that supports
\fBinotify\fR(7), then if the reminder script supplied on the
command-line is actually a directory, \fBRemind\fR additionally checks
if all files within that directory have been modified since startup.
.PP
If you supply the option \fB\-zj\fR, \fBRemind\fR runs in a
special mode called \fBserver mode\fR. This is documented
in the tkremind man page; see tkremind(1).
in the tkremind man page; see tkremind(1). The older server mode
option \fB\-z0\fR still works, but is deprecated; it uses an ad-hoc
method to communicate with the client rather than using JSON to communicate
with the client.
.RE
.TP
\fB\-u\fR\fIname\fR
@@ -435,14 +459,14 @@ text editor capable of creating plain-text files to create a
very simple and almost immediately understandable:
.PP
.nf
REM 6 Jan MSG Dianne's birthday
REM Mar 31 MSG International Transgender Day of Visibility
.fi
.PP
to the baroque and obscure:
.PP
.nf
REM [date(thisyear, 1, 1) + 180] ++5 OMIT \\
sat sun BEFORE MSG [ord(thisyear-1980)] payment due %b!
REM [date(thisyear, 1, 1) + 180] ++5 OMIT \\
sat sun BEFORE MSG [ord(thisyear-1980)] payment due %b!
.fi
.PP
A reminder file consists of commands, with one command per line. Several
@@ -610,6 +634,11 @@ The following examples show how date specifications are interpreted.
.PP
1. Null date specification - the reminder is triggered every day.
The trigger date for a specific run is simply the current system date.
For example:
.PP
.nf
REM MSG This is triggered every time Remind runs
.fi
.PP
2. Only
.I day
@@ -1122,7 +1151,7 @@ reminder is queued for later activation. When \fBRemind\fR has
finished processing the reminder file, it puts itself in the
background, and activates timed reminders when the system time reached
the specified time. Note that if you use the \fBNOQUEUE\fR modifier
in the \fBREM\fR command, then this queueing and background activation
in the \fBREM\fR command, then this queuing and background activation
is \fInot\fR performed. \fBNOQUEUE\fR is useful if you want a time
to be associated with a reminder (eg, in the calendar) but are not
interested in a popup reminder happening at the specified time.
@@ -1194,7 +1223,9 @@ in the bodies of timed reminders, then when the timed reminders are
activated, the variables and functions have the definitions that were
in effect at the end of the reminder script. These definitions may
\fInot\fR necessarily be those that were in effect at the time the reminder
was queued.
was queued. In addition, the OMIT context is whatever was in effect at
the end of the reminder script, which may not necessarily be the same
as when the \fBREM\fR command was first processed.
.PP
.B THE SCHED AND WARN KEYWORDS
.PP
@@ -1688,6 +1719,11 @@ For example, the following sequences are equivalent:
OMIT 3 Jan 2011 THROUGH 5 Jan 2011
.fi
.PP
Note that \fBRemind\fR has a compiled-in limit to the number of full
OMITs. If you omit a range of \fIN\fR fully-specified (ie, year
included) days, then \fIN\fR full OMITs are used up. Trying to omit a
very large range may result in the error "Too many full OMITs"
.PP
You can make a THROUGH \fBOMIT\fR do double-duty as a \fBREM\fR command as
long as both dates are fully specified
.PP
@@ -1790,7 +1826,7 @@ will begin reading from standard input.
.PP
If you specify a \fIdirectory\fR as the argument to \fBINCLUDE\fR, then
\fBRemind\fR will process all files in that directory that match the shell
patterm "*.rem". The files are processed in sorted order; the sort order
pattern "*.rem". The files are processed in sorted order; the sort order
matches that used by the shell when it expands "*.rem".
.PP
Note that the file specified by an \fBINCLUDE\fR command is interpreted
@@ -2146,7 +2182,10 @@ Unary minus. Can be applied to an \fBINT\fR. Returns the negative
of the operand.
.TP
.B *
Multiplication. Returns the product of two \fBINT\fRs.
Multiplication. Returns the product of two \fBINT\fRs. Alternatively, if
one argument is a \fBSTRING\fR and the other an \fBINT\fR, returns a
\fBSTRING\fR consisting of the INT number of repeats of the original STRING.
In this case, the INT argument cannot be negative.
.TP
.B /
Integer division. Returns the quotient of two \fBINT\fRs, discarding the
@@ -2360,9 +2399,9 @@ Universal Time Coordinated in the \fB$MinsFromUTC\fR system variable.
If non-zero, then the \fB\-c\fR option was supplied on the command line.
.TP
.B $Daemon (read-only)
If the daemon mode \fB\-z\fR was invoked, contains the number of
If "daemon mode" \fB\-z\fR was invoked, contains the number of
minutes between wakeups. If not running in daemon mode, contains
0.
0. In server mode (either \fB-z0\fR or \fB-zj\fR), contains -1.
.TP
.B $DateSep
This variable can be set only to "/" or "-". It holds the character
@@ -2398,6 +2437,10 @@ is normally 0, but can be set with the \fB\-tt\fR option or explicitly
set in your script. If \fB$DefaultDelta\fR is non-zero, you can use an
explicit delta of +0 in an AT clause to countermand the default delta.
.TP
.B $DeltaOverride (read-only)
If non-zero, corresponds to the \fIn\fR argument given to a
\fB\-t\fR\fIn\fR command-line option.
.TP
.B $DontFork (read-only)
If non-zero, then the \fB\-c\fR option was supplied on the command line.
.TP
@@ -2464,7 +2507,8 @@ or a date different from today's true date was supplied. If non-zero,
then \fBONCE\fR directives will be ignored.
.TP
.B $InfDelta (read-only)
If non-zero, then the \fB\-t\fR option was supplied on the command line.
If non-zero, then the \fB\-t\fR option was supplied on the command line,
with no \fIn\fR argument.
.TP
.B $IntMax (read-only)
The largest representable \fBINT\fR. On a machine with 32-bit signed integers
@@ -2541,6 +2585,24 @@ updates \fB$LongDeg\fR, \fB$LongMin\fR and \fB$LongSec\fR. Similar
rules apply to \fB$Latitude\fR, \fB$LatDeg\fR, \fB$LatMin\fR and \fB$LatSec\fR.
.RE
.TP
.B $MaxLateMinutes
This variable controls how \fBRemind\fR reacts to a computer being suspended
and then woken. Normally, if a timed reminder is queued and then the
computer suspended, and then the computer is woken \fIafter\fR the
timed reminder's trigger time, \fBRemind\fR will triger the timer anyway,
despite the fact that the trigger time has already passed.
.RS
.PP
If you set \fB$MaxLateMinutes\fR to a non-zero integer between 1 and 1440,
then \fBRemind\fR will \fInot\fR trigger a timed reminder whose trigger
time is more than \fB$MaxLateMinutes\fR minutes in the past.
.PP
Note that \fBRemind\fR uses the value of \fB$MaxLateMinutes\fR that is in
effect when it has finished reading the reminder file and puts itself in
the background. Generally, you should set \fB$MaxLateMinutes\fR once
near the beginning of the file and not change it after that.
.RE
.TP
.B $MaxSatIter
The maximum number of iterations for the \fBSATISFY\fR clause
(described later.) Must be at least 10.
@@ -2549,7 +2611,9 @@ The maximum number of iterations for the \fBSATISFY\fR clause
A limit on the longest string that \fBRemind\fR will allow you
to create. The default is 65535. If you set \fB$MaxStringLen\fR to 0
or to -1, then \fBremind\fR will allow you to create arbitrarily-long
strings, at least until it runs out of memory.
strings, at least until it runs out of memory. We do not recommend
setting \fB$MaxStringLen\fR to 0 or -1 because it is very easy to write
code that DOSes \fBRemind\fR in that case.
.TP
.B $MinsFromUTC
The number of minutes between Universal Time Coordinated and local time. If
@@ -2564,6 +2628,18 @@ must also set \fB$CalcUTC\fR to 0 with the \fB\-i\fR option.
.B $NextMode (read-only)
If non-zero, then the \fB\-n\fR option was supplied on the command line.
.TP
.B $MaxFullOmits (read-only)
The maximum number of full OMITs allowed (a compiled-in constant.)
.TP
.B $MaxPartialOmits (read-only)
The maximum number of partial OMITs allowed (a compiled-in constant.)
.TP
.B $NumFullOmits (read-only)
The number of full OMITs in the current OMIT context.
.TP
.B $NumPartialOmits (read-only)
The number of partial OMITs in the current OMIT context.
.TP
.B $NumQueued (read-only)
Contains the number of reminders queued so far for background
timed triggering.
@@ -2708,9 +2784,13 @@ Set to 1 if the \fB\-@1\fR option was used; 0 otherwise.
Set to 1 if the \fB\-@2\fR option was used; 0 otherwise.
.TP
.B $TerminalBackground (read-only)
Returns -1 if the terminal background color was not specified,
0 if it was specified as dark with the \fB\-@,0\fR option or
1 if it was specified as light with the \fB\-@,1\fR option.
Returns -1 if the terminal background color could not be determined, 0
if it was found to be dark (or was specified as dark with the
\fB\-@,0\fR option) or 1 if it was found to be light (or specified as
light with the \fB\-@,1\fR option.) The terminal background is considered
to be "dark" if the average of the red, green and blue components is
at most 85 out of 255, and if the maximum of any component is at most
128 out of 255.
.PP
Note: If any of the calendar modes are in effect, then the
values of $Daemon, $DontFork, $DontTrigAts, $DontQueue, $HushMode,
@@ -3013,11 +3093,12 @@ will produce undefined results.
Returns the time of "civil twilight" on the specified \fIdate\fR. If
\fIdate\fR is omitted, defaults to \fBtoday()\fR.
.TP
.B easterdate(dqi_arg)
.B easterdate([dqi_arg])
If \fIarg\fR is an \fBINT\fR, then returns the date of Easter Sunday
for the specified year. If \fIarg\fR is a \fBDATE\fR or
\fBDATETIME\fR, then returns the date of the next Easter Sunday on or
after \fIarg\fR. (The time component of a datetime is ignored.)
after \fIarg\fR. (The time component of a datetime is ignored.) If \fIarg\fR
is omitted, then it defaults to \fBtoday()\fR.
.RS
.P
Note that \fBeasterdate\fR computes the Western Easter. For the Orthodox
@@ -3279,6 +3360,62 @@ which default to \fBtoday()\fR and midnight, respectively. The returned
value is an integer from 0 to 359, representing the phase of the moon
in degrees. 0 is a new moon, 180 is a full moon, 90 is first-quarter, etc.
.TP
.B multitrig(s_trig1 [,s_trig2, [... s_trigN]])
\fBmultitrig\fR evaluates each string as a trigger, similar to \fBevaltrig\fR,
and returns the \fIearliest\fR trigger date that is on or after \fBtoday()\fR.
\fBmultitrig\fR is similar to \fBtrig\fR but has the following difference:
.RS
.PP
\fBtrig\fR returns the \fIfirst\fR trigger date that would have triggered today,
whereas \fBmultitrig\fR returns the \fIearliest\fR trigger date later than
today, regardless of whether it would have triggered today.
.PP
If no trigger can be computed that is later than \fBtoday()\fR, then
\fBmultitrig\fR returns 1990-01-01.
.PP
Consider the following examples, assuming that today is Sunday, 24 March 2024:
.PP
.nf
# Returns 1990-01-01 because neither would trigger today
SET a trig("Mon", "Wed")
# Returns 2024-03-25 because it's the earlier trigger date
SET a multitrig("Mon", "Wed")
# Returns 2024-03-27 because it's the first that would trigger today
SET a trig("Wed +3", "Mon +3")
# Returns 2024-03-25 because it's the earlier trigger date
SET a multitrig("Wed +3", "Mon +3")
# Returns 1990-01-01 because all triggers have expired
SET a multitrig("2000", "2022", "1998", "2023")
.fi
.PP
In general, \fBmultitrig\fR works better with the Remind algorithm than
\fBtrig\fR and should be used most of the time. As an example, this
reminder is issued at the end of each quarter:
.PP
.nf
REM [multitrig("Mar 31", "Jun 30", "Sep 30", "Dec 31")] +7 MSG \\
%"End of [ord($Tm/3)] quarter%" is %b.
.fi
.PP
If you want the last working day of each quarter, you could use:
.PP
.nf
PUSH-OMIT-CONTEXT
OMIT Sat Sun
REM [multitrig("Mar ~1", "Jun ~1", "Sep ~1", "Dec ~1")] +7 MSG \\
%"Last working day of [ord($Tm/3)] quarter%" is %b.
POP-OMIT-CONTEXT
.fi
.PP
Note that unlike \fBevaltrig\fR, \fBmultitrig\fR always returns a \fBDATE\fR
and never a \fBDATETIME\fR. Including an \fBAT\fR clause in a trigger
supplied to \fBmultitrig\fR will result in an error.
.RE
.TP
.B ndawn([dq_date])
Returns the time of "nautical dawn" on the specified \fIdate\fR. If
\fIdate\fR is omitted, defaults to \fBtoday()\fR. If a \fIdatetime\fR object
@@ -3294,7 +3431,7 @@ This function returns the number of \fInon-\fRomitted days between
counted. \fIend\fR is never counted.
.RS
.PP
Note that if \fIend\fR is less than \ffIstart\fR, the arguments
Note that if \fIend\fR is less than \fIstart\fR, the arguments
are effectively swapped, so counting always begins from the older
date.
.PP
@@ -3339,7 +3476,7 @@ reminder will label day numbers in a calendar:
.fi
.PP
Obviously, the answer you get from \fBnonomitted\fR depends on the global
OMIT context. If you use moveable OMITs, you may get inconsistent results.
OMIT context. If you use movable OMITs, you may get inconsistent results.
.PP
Here is a more complex use for \fBnonomitted\fR. My garbage collection
follows two interleaved 14-day cycles: One Friday, garbage and paper
@@ -3372,11 +3509,12 @@ the actual time, or a time supplied on the command line.
Returns a string that is the ordinal number \fInum\fR. For example,
\fBord(2)\fR returns "2nd", and \fBord(213)\fR returns "213th".
.TP
.B orthodoxeaster(dqi_arg)
.B orthodoxeaster([dqi_arg])
If \fIarg\fR is an \fBINT\fR, then returns the date of Orthodox Easter Sunday
for the specified year. If \fIarg\fR is a \fBDATE\fR or
\fBDATETIME\fR, then returns the date of the next Orthodox Easter Sunday on or
after \fIarg\fR. (The time component of a datetime is ignored.)
after \fIarg\fR. (The time component of a datetime is ignored.) If \fIarg\fR
is omitted, then it defaults to \fBtoday()\fR.
.RS
.P
Note that \fBorthodoxeaster\fR computes the Orthodox Easter. For the Western
@@ -3597,7 +3735,7 @@ not supplied, then it defaults to \fBtoday()\fR.
.PP
The return value of \fBsoleq()\fR is a \fBDATETIME\fR object specifying
the date and time of the solstice or equinox in the local time zone. It
should be accurate to within 3 minues or so in the worst case.
should be accurate to within 3 minutes or so in the worst case.
.PP
See the included file \fB$SysInclude/seasons.rem\fR for examples of how
to use \fBsoleq()\fR.
@@ -4304,7 +4442,7 @@ Dean was born in 1984. The above example, on 1 November 1992, would print:
Similarly, the function is useful in anniversary reminders. For example:
.PP
.nf
REM 4 June MSG [since(1989)] anniversary of the Tiananmen Square massacre
REM 4 June MSG [since(1989)] anniversary of the Tienanmen Square massacre
.fi
.PP
Notes:
@@ -4947,21 +5085,25 @@ structuring comments in your PostScript code.
.PP
.SH DAEMON MODE
.PP
If you use the \fB\-z\fR command-line option, \fBRemind\fR runs in the
"daemon" mode. In this mode, no "normal" reminders are issued.
If you use the \fB\-z\fR command-line option, \fBRemind\fR runs in
"daemon mode". In this mode, no "normal" reminders are issued.
Instead, only timed reminders are collected and queued, and are then
issued whenever they reach their trigger time.
.PP
In addition, \fBRemind\fR wakes up every few minutes to check the modification
date on the reminder script (the filename supplied on the command line.)
If \fBRemind\fR detects that the script has changed, it re-executes itself
in daemon mode, and interprets the changed script.
In addition, \fBRemind\fR wakes up every few minutes to check the
modification date on the reminder script (the filename supplied on the
command line.) If \fBRemind\fR detects that the script has changed,
it re-executes itself in daemon mode, and interprets the changed
script. If \fBRemind\fR was compiled with support for
\fBinotify\fR(7), then if the command-line reminder script is really a
directory, \fBRemind\fR also re-executes itself if any of the files in
the directory is changed.
.PP
In daemon mode, \fBRemind\fR also re-reads the remind script when it
detects that the system date has changed.
.PP
In daemon mode, \fBRemind\fR acts as if the \fB\-f\fR option had been used,
so to run in the daemon mode in the background, use:
so to run in daemon mode in the background, use:
.PP
.nf
remind \-z .reminders &
@@ -5188,7 +5330,7 @@ A number of system variables let you translate various phrases
to other languages. These system variables are:
.PP
.TP
.B $Monday, $Tuesday, $Wednesday, $Thursday, $Friday, $Saturday
.B $Monday, $Tuesday, $Wednesday, $Thursday, $Friday, $Saturday, $Sunday
Set each of these system variables to a string representing the corresponding
day's name in your language. Strings must be valid UTF-8 strings.
.TP
@@ -5291,7 +5433,7 @@ as:
.PP
You can define your own substitution sequences in addition to the built-in
ones as follows: If you define a function named \fBsubst_\fIname\fB(alt, date, time)\fR, then the sequence \fB%{name}\fR calls the function with \fBalt\fR
set to 0 and \fBdate\fR and \fRtime\fR to the trigger date and time,
set to 0 and \fBdate\fR and \fBtime\fR to the trigger date and time,
respectively. The \fB%{name}\fR sequence is replaced with whatever the
function returns. The sequence \fB%*{name}\fR is similar, but calls
the function with \fBalt\fR set to 1.
@@ -5494,13 +5636,13 @@ the anniversary of a death is. The following rules are used:
o
If the death occurred on 30 Heshvan, and Heshvan in the year after the
death is \fIchaser\fR, then the jahrzeit is observed on 29 Heshvan in years
when Heshvan is \fIchaser\fR. Otherwise, the yahrzeit is observed on 1
when Heshvan is \fIchaser\fR. Otherwise, the jahrzeit is observed on 1
Kislev when Heshvan is \fIchaser\fR.
.TP
o
If the death occurred on 30 Kislev, and Kislev in the year after the
death is \fIchaser\fR, then the jahrzeit is observed on 29 Kislev in years
when Kislev is \fIchaser\fR. Otherwise, the yahrzeit is observed on 1
when Kislev is \fIchaser\fR. Otherwise, the jahrzeit is observed on 1
Tevet when Kislev is \fIchaser\fR.
.TP
o
@@ -5525,7 +5667,7 @@ The \fBSPECIAL\fR keyword is used to transmit "out-of-band" information
to \fBRemind\fR backends, such as \fBtkremind\fR or \fBRem2PS\fR.
They are used only when piping data from a \fBremind \-p\fR line.
(Note that the COLOR special is an exception; it downgrades to the
equivalent of MSG in \fBremind's\fR normal mode of operation.)
equivalent of MSG in \fBRemind's\fR normal mode of operation.)
.PP
The various \fBSPECIAL\fRs recognized are particular for each
backend; however, there are four \fBSPECIAL\fRs that all backends
@@ -5816,6 +5958,25 @@ components, then \fBRemind\fR will correctly compute a trigger date, even
if it happens to be before the start of scanning.
Note that this behaviour is not true for
versions of \fBRemind\fR prior to 03.00.01.
.SH FILES
.PP
The traditional location of your reminders file or directory is:
.PP
.nf
$HOME/.reminders
.fi
.PP
where \fB$HOME\fR is your home directory.
.PP
Remind ships with some preinstalled files for holidays and language
packs. These are located in the following directory:
.PP
.nf
@prefix@/share/remind/
.fi
.PP
Do not hard-code the above directory in your reminder files. Instead,
use the value of the $SysInclude system variable.
.SH AUTHOR
.PP
Dianne Skoll <dianne@skoll.ca> wrote \fBRemind\fR. The moon code
@@ -5863,9 +6024,11 @@ Liviu Daia
Rafa Couto
.PP
\fBIcelandic\fR --
Bj\(:orn Dav\('i\[Sd]sson
Bj\[:o]rn Daví\[Sd]sson
.SH BUGS
.PP
If you find a bug in Remind, please report it to: dianne@skoll.ca
.PP
There's no good reason why read-only system variables are not
implemented as functions, or why functions like \fBversion()\fR, etc.
are not implemented as read-only system variables.
@@ -5886,8 +6049,13 @@ Almanac Office, USNO.
.PP
Richard Siegel and Michael and Sharon Strassfeld, \fIThe First Jewish
Catalog\fR, Jewish Publication Society of America.
.PP
Jean Meeus, \fIAstronomical Algorithms, Second Edition\fR, Willmann-Bell, Inc.
.SH HOME PAGE
https://dianne.skoll.ca/projects/remind/
.SH MAILING LIST
https://dianne.skoll.ca/mailman/listinfo/remind-fans
.SH SEE ALSO
.PP
\fBrem\fR(1), \fBrem2ps\fR(1), \fBrem2pdf\fR(1), \fBtkremind\fR(1), \fBrem2html\fR(1)

View File

@@ -184,7 +184,9 @@ on the reminder.
If there are any errors in your reminder file, the "Queue..." button
changes to "Errors...". Click on "Errors..." to see the Remind error
output. Click "OK" to close the error window; this makes the button
in the main TkRemind window to revert to "Queue..."
in the main TkRemind window to revert to "Queue..." You can click on
any error message to open an editor on the file and line number that
caused the error.
.SH BACKGROUND REMINDERS
@@ -192,7 +194,7 @@ If you create "timed" reminders, \fBTkRemind\fR will queue them in
the background and pop up boxes as they are triggered. Additionally,
if you created the reminder using \fBTkRemind\fR, you will be given the
option of "turning off" the reminder for the rest of the day.
\fBTkRemind\fR achieves queueing of background reminders by running
\fBTkRemind\fR achieves queuing of background reminders by running
\fBRemind\fR in \fIserver mode\fR, described later.
.SH OPTIONS
@@ -301,11 +303,11 @@ Today
.SH IMMEDIATE UPDATES
If you are running \fBTkRemind\fR on Linux and have the
\fBinotifywait\fR program installed (part of the \fBinotify-tools\fR
or similar package), then \fBTkRemind\fR redraws the calendar window
\fIimmediately\fR if \fB$HOME/.reminders\fR changes (or, if it is a
directory, any files in that directory change.)
If you are running \fBTkRemind\fR on Linux and \fBRemind\fR has been
compiled with \fBinotify\fR(7) support, then \fBTkRemind\fR redraws
the calendar window \fIimmediately\fR if \fB$HOME/.reminders\fR
changes (or, if it is a directory, any files in that directory
change.)
.PP
This lets \fBTkRemind\fR react immediately to hand-edited reminders or
to reminder files that are imported from another calendar system (for example,
@@ -366,60 +368,110 @@ your hand-edited files in a separate \fB*.rem\fR file than \fBTkRemind\fR's
\fBRemind\fR has a special mode for interacting with programs like
\fBTkRemind\fR. This mode is called \fIserver mode\fR and is
selected by supplying the \fB\-z0\fR option to \fBRemind\fR.
selected by supplying the \fB\-zj\fR option to \fBRemind\fR.
In server mode, \fBRemind\fR operates similar to daemon mode, except
it reads commands (one per line)
from standard input and writes status lines to standard output.
it reads commands (one per line) from standard input and writes status
lines to standard output. Each status line is a JSON object.
The commands accepted in server mode are:
.TP
EXIT
Terminate the \fBRemind\fR process. EOF on standard input does the
same thing.
same thing. \fBRemind\fR exits immediately without printing
a JSON status line.
.TP
STATUS
Return the number of queued reminders.
Return the number of queued reminders. The JSON object looks
something like this:
.nf
{"response":"queued","nqueued":n,"command":"STATUS"}
.fi
where \fIn\fR is the number of reminders queued.
.TP
QUEUE or JSONQUEUE
Returns the contents of the queue. The JSON object looks something
like this:
.nf
{"response":"queue","queue":[ ... ],"command":"QUEUE"}
.fi
The value of the \fBqueue\fR key is an array of JSON objects, each
representing a queued reminder.
.TP
DEL \fIqid\fR
Delete the reminder with queue-id \fIqid\fR from the queue.
.TP
REREAD
Re-read the reminder file
Re-read the reminder file. Returns the following status line:
.nf
{"response":"reread","command":"REREAD"}
.fi
.PP
The status lines written are as follows:
Additional status lines written are as follows:
.TP
NOTE reminder \fItime\fR \fItag\fR
Signifies the beginning of a timed reminder whose trigger time is
\fItime\fR with tag \fItag\fR. If the reminder has no tag, an
asterisk is supplied for \fItag\fR. All lines following this line
are the body of the reminder, until the line \fBNOTE endreminder\fR
is transmitted.
.nf
{"response":"reminder","ttime":tt,"now":now,"tags":tags,"qid":qid,"body":body}
.fi
In this line, \fItt\fR is the trigger time of the reminder (expressed
as a string), \fInow\fR is the current time, \fItags\fR (if present)
is the tag or tags associated with the reminder, and \fIbody\fR is the
body of the reminder. This response causes \fBTkRemind\fR to pop up a
reminder notification. \fIqid\fR is a unique identifier for this
reminder. You may delete it from the queue by sending a \fBDEL\fR
\fIqid\fR command to the server. Note that \fIqid\fRs are not stable
across re-reads; if \fBRemind\fR restarts itself to re-read the reminder
file, then the \fIqid\fR values are likely to change, and any reminder
deleted with a \fBDEL\fR \fIqid\fR command is likely to be re-queued.
.TP
NOTE newdate
.nf
{"response":"newdate"}
.fi
This line is emitted whenever \fBRemind\fR has detected a rollover of
the system date. The front-end program should redraw its calendar
or take whatever other action is needed.
.TP
NOTE reread
This line is emitted whenever the number of reminders in \fBRemind\fR's
queue changes because of a date rollover or a \fBREREAD\fR command.
The front-end should issue a \fBSTATUS\fR command in response to this
message.
.nf
.TP
NOTE queued \fIn\fR
This line is emitted in response to a \fBSTATUS\fR command. The number
\fIn\fR is the number of reminders in the queue.
{"response":"reread","command":"inotify"}
.fi
If \fBRemind\fR was compiled with support for \fBinotify\fR(7), then
if it detects a change to the top-level reminder file or directory,
it issues the above response. The front-end should redraw its
calendar since this response indicates that a change has been made
to the reminder file or directory.
.PP
Please note that \fBRemind\fR can write a status message \fIat any time\fR
and not just in response to a command sent to its standard input. Therefore,
a program that runs \fBRemind\fR in server mode must be prepared to handle
asynchronous status messages.
.SH AUTHOR
TkRemind was written by Dianne Skoll <dianne@skoll.ca>
\fBTkRemind\fR is Copyright 1996-2023 by Dianne Skoll.
\fBTkRemind\fR is Copyright 1996-2024 by Dianne Skoll.
.SH FILES

View File

@@ -6,10 +6,11 @@ use warnings;
use Getopt::Long;
use JSON::MaybeXS;
use Encode;
my %Options;
my $rem2html_version = '2.1';
my $rem2html_version = '@VERSION@';
my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mondayfirst, $weeks,
@Daynames, $Nextmon, $Nextlen, $Prevmon, $Prevlen);
@@ -44,6 +45,11 @@ Print usage information
Print version
=item --utf8
Assume standard input is encoded in UTF-8; write UTF-8 data to standard
output.
=item --backurl I<url>
When producing the small calendar for the previous month, make the
@@ -154,6 +160,7 @@ Usage: remind -pp ... | rem2html [options]
Options:
--help, -h Print usage information
--utf8 Assume UTF-8 input and write UTF-8 output
--man Show man page (requires "perldoc")
--version Print version
--backurl url Make the title on the previous month's small calendar
@@ -197,6 +204,7 @@ sub parse_options
local $SIG{__WARN__} = sub { print STDERR "$TIDY_PROGNAME: $_[0]\n"; };
if (!GetOptions(\%Options, "help|h",
"man",
"utf8",
"pngs",
"version",
"stylesheet=s",
@@ -216,13 +224,22 @@ sub parse_options
if ($stylesheet) {
$Options{stylesheet} = smoosh($Options{imgbase}, $stylesheet);
}
if ($Options{utf8}) {
binmode(STDIN, ':encoding(UTF-8)');
binmode(STDOUT, ':encoding(UTF-8)');
}
}
sub start_output
{
return if ($Options{tableonly});
print("<html>\n<head>\n<title>" . $Options{title} . "</title>\n");
print("<html>\n<head>\n");
if ($Options{utf8}) {
print '<meta charset="UTF-8">' . "\n";
}
print("<title>" . $Options{title} . "</title>\n");
if (!$Options{nostyle}) {
if ($Options{stylesheet}) {
print('<link rel="stylesheet" type="text/css" href="' .
@@ -310,7 +327,12 @@ sub parse_input
($y, $m, $d, $special, $tag, $duration, $time, $body) =
($1, $2, $3, $4, $5, $6, $7, $8);
} elsif (/\{/) {
my $obj = decode_json($_);
my $obj;
if ($Options{utf8}) {
$obj = decode_json(encode('UTF-8', $_, Encode::FB_DEFAULT));
} else {
$obj = decode_json($_);
}
next unless ($obj->{date} =~ /^(\d+)-(\d+)-(\d+)$/);
$y = $1;
$m = $2;

View File

@@ -486,7 +486,7 @@ output for the invalid reminder.
=head1 ABSOLUTELY-POSITIONED TEXT
If your B<PANGO> special reminder starts with C<@I<x>,I<y>> where I<x>
and I<y> are floating-point numbers, then the Pango marked-up test is
and I<y> are floating-point numbers, then the Pango marked-up text is
positioned absolutely with respect to the day's box (and is not
counted when calculating the box's height.)

15
resources/tkremind.desktop Executable file
View File

@@ -0,0 +1,15 @@
[Desktop Entry]
Type=Application
Exec=tkremind
StartupNotify=true
Icon=tkremind
Terminal=false
Name=tkremind
Comment=TkRemind Calendar Program
Categories=Office;Calendar;
Keywords=Calendar;remind;
Keywords[ca]=Calendari;remind;
Keywords[de]=Kalender;remind;
Keywords[en_GB]=Calendar;remind;
Keywords[es]=Calendario;remind;

BIN
resources/tkremind.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -63,6 +63,15 @@ install: all
done
-mkdir -p $(DESTDIR)$(datarootdir)/remind || true
cp -R ../include/* $(DESTDIR)$(datarootdir)/remind
-mkdir -p $(DESTDIR)$(prefix)/share/pixmaps
-mkdir -p $(DESTDIR)$(prefix)/share/applications
$(INSTALL_DATA) $(srcdir)/../resources/tkremind.png $(DESTDIR)$(prefix)/share/pixmaps
$(INSTALL_PROGRAM) $(srcdir)/../resources/tkremind.desktop $(DESTDIR)$(prefix)/share/applications
-if test "$(DESTDIR)" = ""; then \
update-desktop-database < /dev/null > /dev/null 2>&1 ; \
xdg-icon-resource install --novendor --size 64 $(DESTDIR)$(prefix)/share/pixmaps/tkremind.png < /dev/null > /dev/null 2>&1; \
xdg-desktop-menu install --novendor $(DESTDIR)$(prefix)/share/applications/tkremind.desktop < /dev/null > /dev/null 2>&1 ; \
fi
install-stripped: install
strip $(DESTDIR)$(bindir)/remind || true
@@ -71,9 +80,6 @@ install-stripped: install
clean:
rm -f *.o *~ core *.bak $(PROGS)
cppcheck:
cppcheck --force --enable=all --suppress=variableScope --suppress=ConfigurationNotChecked *.c
clobber:
rm -f *.o *~ remind rem2ps test.out core *.bak
@@ -83,6 +89,9 @@ depend:
# The next targets are not very useful to you. I use them to build
# distributions, etc.
cppcheck:
cppcheck -j`nproc` --force --enable=all --suppress=ConfigurationNotChecked --suppress=unmatchedSuppression --suppress=variableScope --inline-suppr .
# Build a tar file based on all files checked into git.
distro:
cd .. && git archive --worktree-attributes --format=tar --prefix=remind-$(VERSION)/ HEAD > src/remind-$(VERSION).tar

View File

@@ -5,7 +5,7 @@
/* The code for generating a calendar. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -475,7 +475,7 @@ void PrintJSONKeyPairTime(char const *name, int t)
}
#ifdef REM_USE_WCHAR
void PutWideChar(wchar_t const wc)
void PutWideChar(wchar_t const wc, DynamicBuffer *output)
{
char buf[MB_CUR_MAX+1];
int len;
@@ -483,7 +483,11 @@ void PutWideChar(wchar_t const wc)
len = wctomb(buf, wc);
if (len > 0) {
buf[len] = 0;
fputs(buf, stdout);
if (output) {
DBufPuts(output, buf);
} else {
fputs(buf, stdout);
}
}
}
#endif
@@ -556,11 +560,11 @@ static void goff(void)
static void
ClampColor(int *r, int *g, int *b)
{
if (TerminalBackground == TERMINAL_BACKGROUND_UNKNOWN) {
if (GetTerminalBackground() == TERMINAL_BACKGROUND_UNKNOWN) {
/* No special clamping if terminal background is unknown */
return;
}
if (TerminalBackground == TERMINAL_BACKGROUND_DARK) {
if (GetTerminalBackground() == TERMINAL_BACKGROUND_DARK) {
if (*r <= 64 && *g <= 64 && *b <= 64) {
int max = *r;
double factor;
@@ -579,7 +583,7 @@ ClampColor(int *r, int *g, int *b)
}
return;
}
if (TerminalBackground == TERMINAL_BACKGROUND_LIGHT) {
if (GetTerminalBackground() == TERMINAL_BACKGROUND_LIGHT) {
if (*r > 191 && *g > 191 && *b > 191) {
int min = *r;
if (*g < min) min = *g;
@@ -667,11 +671,11 @@ Colorize(int r, int g, int b, int bg, int clamp)
if (b > 64) b = 1;
else b = 0;
if (clamp && TerminalBackground == TERMINAL_BACKGROUND_DARK && !bg) {
if (clamp && GetTerminalBackground() == TERMINAL_BACKGROUND_DARK && !bg) {
/* Convert black-on-black to grey */
if (!r && !g && !b) return VT100Colors[1][0][0][0];
}
if (clamp && TerminalBackground == TERMINAL_BACKGROUND_LIGHT && !bg) {
if (clamp && GetTerminalBackground() == TERMINAL_BACKGROUND_LIGHT && !bg) {
/* Convert white-on-white to grey */
if (r && g && b) return VT100Colors[1][0][0][0];
}
@@ -1037,7 +1041,7 @@ static void DoCalendarOneMonth(void)
printf("\"entries\":[\n");
}
}
while (WriteCalendarRow()) continue;
while (WriteCalendarRow()) /* continue */;
if (PsCal == PSCAL_LEVEL1) {
printf("%s\n", PSEND);
@@ -1218,7 +1222,7 @@ static void PrintLeft(char const *s, int width, char pad)
if (!buf) {
/* Uh-oh... cannot recover */
fprintf(stderr, "%s\n", ErrMsg[E_NO_MEM]);
exit(1);
exit(EXIT_FAILURE);
}
}
(void) mbstowcs(buf, s, len+1);
@@ -1227,7 +1231,7 @@ static void PrintLeft(char const *s, int width, char pad)
ws = buf;
for (i=0; i<width;) {
if (*ws) {
PutWideChar(*ws++);
PutWideChar(*ws++, NULL);
i+= wcwidth(*ws);
} else {
break;
@@ -1235,7 +1239,7 @@ static void PrintLeft(char const *s, int width, char pad)
}
/* Mop up any potential combining characters */
while (*ws && wcwidth(*ws) == 0) {
PutWideChar(*ws++);
PutWideChar(*ws++, NULL);
}
/* Possibly send lrm control sequence */
@@ -1297,7 +1301,7 @@ static void PrintCentered(char const *s, int width, char *pad)
if (!buf) {
/* Uh-oh... cannot recover */
fprintf(stderr, "%s\n", ErrMsg[E_NO_MEM]);
exit(1);
exit(EXIT_FAILURE);
}
}
(void) mbstowcs(buf, s, len+1);
@@ -1308,7 +1312,7 @@ static void PrintCentered(char const *s, int width, char *pad)
for (i=0; i<d; i++) fputs(pad, stdout);
for (i=0; i<width; i++) {
if (*ws) {
PutWideChar(*ws++);
PutWideChar(*ws++, NULL);
if (wcwidth(*ws) == 0) {
/* Don't count this character... it's zero-width */
i--;
@@ -1319,7 +1323,7 @@ static void PrintCentered(char const *s, int width, char *pad)
}
/* Mop up any potential combining characters */
while (*ws && wcwidth(*ws) == 0) {
PutWideChar(*ws++);
PutWideChar(*ws++, NULL);
}
/* Possibly send lrm control sequence */
send_lrm();
@@ -1448,7 +1452,7 @@ static int WriteOneColLine(int col)
}
numwritten += wcwidth(*ws);
}
PutWideChar(*ws);
PutWideChar(*ws, NULL);
}
}
e->wc_pos = ws;
@@ -1463,7 +1467,7 @@ static int WriteOneColLine(int col)
if (wcwidth(*ws) > 0) {
numwritten += wcwidth(*ws);
}
PutWideChar(*ws);
PutWideChar(*ws, NULL);
}
}
}
@@ -1603,7 +1607,7 @@ static void GenerateCalEntries(int col)
r=IncludeFile(InitialFile);
if (r) {
fprintf(ErrFp, "%s %s: %s\n", ErrMsg[E_ERR_READING], InitialFile, ErrMsg[r]);
exit(1);
exit(EXIT_FAILURE);
}
while(1) {
@@ -1611,7 +1615,7 @@ static void GenerateCalEntries(int col)
if (r == E_EOF) return;
if (r) {
Eprint("%s: %s", ErrMsg[E_ERR_READING], ErrMsg[r]);
exit(1);
exit(EXIT_FAILURE);
}
s = FindInitialToken(&tok, CurLine);
@@ -2211,10 +2215,114 @@ static void WriteSimpleEntryProtocol1(CalEntry *e)
printf("%s\n", e->text);
}
void WriteJSONTimeTrigger(TimeTrig const *tt)
{
PrintJSONKeyPairTime("time", tt->ttime);
PrintJSONKeyPairTime("nexttime", tt->nexttime);
PrintJSONKeyPairInt("tdelta", tt->delta);
PrintJSONKeyPairInt("trep", tt->rep);
if (tt->duration != NO_TIME) {
PrintJSONKeyPairInt("duration", tt->duration);
}
}
void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
{
/* wd is an array of days from 0=monday to 6=sunday.
We convert to array of strings */
if (t->wd != NO_WD) {
printf("\"wd\":[");
int done = 0;
int i;
for (i=0; i<7; i++) {
if (t->wd & (1 << i)) {
if (done) {
printf(",");
}
done = 1;
printf("\"%s\"", EnglishDayName[i]);
}
}
printf("],");
}
if (t->d != NO_DAY) {
PrintJSONKeyPairInt("d", t->d);
}
if (t->m != NO_MON) {
PrintJSONKeyPairInt("m", t->m+1);
}
if (t->y != NO_YR) {
PrintJSONKeyPairInt("y", t->y);
}
if (t->back) {
PrintJSONKeyPairInt("back", t->back);
}
if (t->delta) {
PrintJSONKeyPairInt("delta", t->delta);
}
if (t->rep) {
PrintJSONKeyPairInt("rep", t->rep);
}
/* Local omit is an array of days from 0=monday to 6=sunday.
We convert to array of strings */
if (t->localomit != NO_WD) {
printf("\"localomit\":[");
int done = 0;
int i;
for (i=0; i<7; i++) {
if (t->localomit & (1 << i)) {
if (done) {
printf(",");
}
done = 1;
printf("\"%s\"", EnglishDayName[i]);
}
}
printf("],");
}
switch(t->skip) {
case SKIP_SKIP:
PrintJSONKeyPairString("skip", "SKIP");
break;
case BEFORE_SKIP:
PrintJSONKeyPairString("skip", "BEFORE");
break;
case AFTER_SKIP:
PrintJSONKeyPairString("skip", "AFTER");
break;
}
PrintJSONKeyPairDate("until", t->until);
if (t->once != NO_ONCE) {
PrintJSONKeyPairInt("once", t->once);
}
if (t->scanfrom != today) {
PrintJSONKeyPairDate("scanfrom", t->scanfrom);
}
PrintJSONKeyPairDate("from", t->from);
PrintJSONKeyPairInt("priority", t->priority);
PrintJSONKeyPairDateTime("eventstart", t->eventstart);
if (t->eventduration != NO_TIME) {
PrintJSONKeyPairInt("eventduration", t->eventduration);
}
if (t->maybe_uncomputable) {
PrintJSONKeyPairInt("maybe_uncomputable", 1);
}
if (t->noqueue) {
PrintJSONKeyPairInt("noqueue", 1);
}
PrintJSONKeyPairString("sched", t->sched);
PrintJSONKeyPairString("warn", t->warn);
PrintJSONKeyPairString("omitfunc", t->omitfunc);
if (t->addomit) {
PrintJSONKeyPairInt("addomit", 1);
}
if (include_tags) {
PrintJSONKeyPairString("tags", DBufValue(&(t->tags)));
}
}
static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
{
int done = 0;
char const *s;
if (DoPrefixLineNo) {
PrintJSONKeyPairString("filename", e->filename);
@@ -2234,88 +2342,13 @@ static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
PrintJSONKeyPairInt("trep", e->tt.rep);
}
}
if (e->trig.eventduration != NO_TIME) {
PrintJSONKeyPairInt("eventduration", e->trig.eventduration);
}
/* wd is an array of days from 0=monday to 6=sunday.
We convert to array of strings */
if (e->trig.wd != NO_WD) {
printf("\"wd\":[");
done = 0;
int i;
for (i=0; i<7; i++) {
if (e->trig.wd & (1 << i)) {
if (done) {
printf(",");
}
done = 1;
printf("\"%s\"", EnglishDayName[i]);
}
}
printf("],");
}
if (e->trig.d != NO_DAY) {
PrintJSONKeyPairInt("d", e->trig.d);
}
if (e->trig.m != NO_MON) {
PrintJSONKeyPairInt("m", e->trig.m+1);
}
if (e->trig.y != NO_YR) {
PrintJSONKeyPairInt("y", e->trig.y);
}
PrintJSONKeyPairDateTime("eventstart", e->trig.eventstart);
if (e->trig.back) {
PrintJSONKeyPairInt("back", e->trig.back);
}
if (e->trig.delta) {
PrintJSONKeyPairInt("delta", e->trig.delta);
}
if (e->trig.rep) {
PrintJSONKeyPairInt("rep", e->trig.rep);
}
WriteJSONTrigger(&e->trig, 0, today);
if (e->nonconst_expr) {
PrintJSONKeyPairInt("nonconst_expr", e->nonconst_expr);
}
if (e->if_depth) {
PrintJSONKeyPairInt("if_depth", e->if_depth);
}
switch(e->trig.skip) {
case SKIP_SKIP:
PrintJSONKeyPairString("skip", "SKIP");
break;
case BEFORE_SKIP:
PrintJSONKeyPairString("skip", "BEFORE");
break;
case AFTER_SKIP:
PrintJSONKeyPairString("skip", "AFTER");
break;
}
/* Local omit is an array of days from 0=monday to 6=sunday.
We convert to array of strings */
if (e->trig.localomit != NO_WD) {
printf("\"localomit\":[");
done = 0;
int i;
for (i=0; i<7; i++) {
if (e->trig.localomit & (1 << i)) {
if (done) {
printf(",");
}
done = 1;
printf("\"%s\"", EnglishDayName[i]);
}
}
printf("],");
}
PrintJSONKeyPairDate("until", e->trig.until);
if (e->trig.once != NO_ONCE) {
PrintJSONKeyPairInt("once", e->trig.once);
}
if (e->trig.scanfrom != today) {
PrintJSONKeyPairDate("scanfrom", e->trig.scanfrom);
}
PrintJSONKeyPairDate("from", e->trig.from);
PrintJSONKeyPairInt("priority", e->trig.priority);
if (e->is_color) {
PrintJSONKeyPairInt("r", e->r);

View File

@@ -32,11 +32,11 @@ if (!exists($language_map->{$lang})) {
my $flag = $language_map->{$lang};
print STDERR "Testing for: $lang - $flag.\n";
my_sys("make clean > /dev/null 2>&1") && die("make clean failed");
my_sys("make -j6 all LANGDEF=-DLANG=$flag > /dev/null 2>&1") && die("make all failed");
my_sys("make -j18 all LANGDEF=-DLANG=$flag > /dev/null 2>&1") && die("make all failed");
my_sys("./remind -q -r ../tests/tstlang.rem 2022-03-23 11:44 > test-$lang-compiled.out 2>&1");
my_sys("make clean > /dev/null 2>&1") && die("make clean failed");
my_sys("make -j6 all > /dev/null 2>&1") && die("make all failed");
my_sys("make -j18 all > /dev/null 2>&1") && die("make all failed");
my_sys("./remind -q -r -ii=\\\"../include/lang/$lang.rem\\\" ../tests/tstlang.rem 2022-03-23 11:44 > test-$lang-runtime.out 2>&1");
my $rc = my_sys("cmp test-$lang-compiled.out test-$lang-runtime.out > /dev/null 2>&1");

View File

@@ -10,6 +10,9 @@
/* Define if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define if you have the <sys/inotify.h> header file. */
#undef HAVE_SYS_INOTIFY_H
/* Define if you have the <glob.h> header file */
#undef HAVE_GLOB_H
@@ -17,6 +20,8 @@
#undef HAVE_LOCALE_H
#undef HAVE_INOTIFY_INIT1
#undef HAVE_LANGINFO_H
#undef HAVE_GLOB

View File

@@ -6,7 +6,7 @@
/* which you can customize. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -117,7 +117,7 @@
/*---------------------------------------------------------------------*/
/* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */
/*---------------------------------------------------------------------*/
#define VAL_STACK_SIZE 1000
#define VAL_STACK_SIZE 100
/*---------------------------------------------------------------------*/
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */

View File

@@ -6,7 +6,7 @@
/* which you can customize. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -117,7 +117,7 @@
/*---------------------------------------------------------------------*/
/* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */
/*---------------------------------------------------------------------*/
#define VAL_STACK_SIZE 1000
#define VAL_STACK_SIZE 100
/*---------------------------------------------------------------------*/
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */

View File

@@ -7,7 +7,7 @@
/* commands. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -192,7 +192,7 @@ int DoRem(ParsePtr p)
r = OK;
if (ShouldTriggerReminder(&trig, &tim, dse, &err)) {
if ( (r=TriggerReminder(p, &trig, &tim, dse, 0)) ) {
if ( (r=TriggerReminder(p, &trig, &tim, dse, 0, NULL)) ) {
FreeTrig(&trig);
return r;
}
@@ -350,6 +350,16 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
if (r) return r;
break;
/* A time implicitly introduces an AT if AT is not explicit */
case T_Time:
DBufFree(&buf);
if (tim->ttime != NO_TIME) return E_TIME_TWICE;
tim->ttime = tok.val;
r = ParseTimeTrig(s, tim, save_in_globals);
if (r) return r;
trig->duration_days = ComputeTrigDuration(tim);
break;
case T_At:
DBufFree(&buf);
r=ParseTimeTrig(s, tim, save_in_globals);
@@ -669,6 +679,9 @@ static int ParseLocalOmit(ParsePtr s, Trigger *t)
break;
default:
if (t->localomit == NO_WD) {
return E_EXPECTING_WEEKDAY;
}
PushToken(DBufValue(&buf), s);
DBufFree(&buf);
return OK;
@@ -900,7 +913,7 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
/* Trigger the reminder if it's a RUN or MSG type. */
/* */
/***************************************************************/
int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued)
int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued, DynamicBuffer *output)
{
int r, y, m, d;
char PrioExpr[VAR_NAME_LEN+25];
@@ -967,7 +980,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
}
/* If it's a MSG-type reminder, and no -k option was used, issue the banner. */
if ((t->typ == MSG_TYPE || t->typ == MSF_TYPE)
&& !DidMsgReminder && !NextMode && !msg_command) {
&& !DidMsgReminder && !NextMode && !msg_command && !is_queued) {
DidMsgReminder = 1;
if (!DoSubstFromString(DBufValue(&Banner), &buf,
DSEToday, NO_TIME) &&
@@ -1034,11 +1047,18 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
return E_NO_MEM;
}
printf("%s%s%s\n", DBufValue(&calRow), DBufValue(&pre_buf), DBufValue(&buf));
r = OK;
if (output) {
if (DBufPuts(output, DBufValue(&calRow)) != OK) r = E_NO_MEM;
if (DBufPuts(output, DBufValue(&pre_buf)) != OK) r = E_NO_MEM;
if (DBufPuts(output, DBufValue(&buf)) != OK) r = E_NO_MEM;
} else {
printf("%s%s%s\n", DBufValue(&calRow), DBufValue(&pre_buf), DBufValue(&buf));
}
DBufFree(&buf);
DBufFree(&pre_buf);
DBufFree(&calRow);
return OK;
return r;
}
/* Correct colors */
@@ -1134,18 +1154,27 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
case MSG_TYPE:
case PASSTHRU_TYPE:
if (msg_command) {
DoMsgCommand(msg_command, DBufValue(&buf));
DoMsgCommand(msg_command, DBufValue(&buf), is_queued);
} else {
printf("%s", DBufValue(&buf));
if (output) {
DBufPuts(output, DBufValue(&buf));
} else {
/* Add a space before "NOTE endreminder" */
if (IsServerMode() && !strncmp(DBufValue(&buf), "NOTE endreminder", 16)) {
printf(" %s", DBufValue(&buf));
} else {
printf("%s", DBufValue(&buf));
}
}
}
break;
case MSF_TYPE:
FillParagraph(DBufValue(&buf));
FillParagraph(DBufValue(&buf), output);
break;
case RUN_TYPE:
System(DBufValue(&buf));
System(DBufValue(&buf), is_queued);
break;
default: /* Unknown/illegal type? */
@@ -1184,7 +1213,7 @@ int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int dse, int *err)
if (DontIssueAts > 1) {
/* If two or more -a options, then *DO* issue ats that are in the
future */
if (tim->ttime < SystemTime(0) / 60) {
if (tim->ttime < MinutesPastMidnight(0)) {
return 0;
}
} else {
@@ -1192,13 +1221,6 @@ int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int dse, int *err)
}
}
/* Don't trigger "old" timed reminders */
/*** REMOVED...
if (dse == DSEToday &&
tim->ttime != NO_TIME &&
tim->ttime < SystemTime(0) / 60) return 0;
*** ...UNTIL HERE */
/* If "infinite delta" option is chosen, always trigger future reminders */
if (InfiniteDelta || NextMode) return 1;
@@ -1379,7 +1401,7 @@ static int ParsePriority(ParsePtr s, Trigger *t)
/* Execute the '-k' command, escaping shell chars in message. */
/* */
/***************************************************************/
int DoMsgCommand(char const *cmd, char const *msg)
int DoMsgCommand(char const *cmd, char const *msg, int is_queued)
{
int r;
int i, l;
@@ -1416,7 +1438,7 @@ int DoMsgCommand(char const *cmd, char const *msg)
}
r = OK;
System(DBufValue(&execBuffer));
System(DBufValue(&execBuffer), is_queued);
finished:
DBufFree(&buf);

View File

@@ -6,7 +6,7 @@
/* reminders are triggered. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -46,11 +46,11 @@
int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse, int mode)
{
int diff = dse - DSEToday;
int curtime = SystemTime(0) / 60;
int curtime = MinutesPastMidnight(0);
int err, done;
int c;
int d, m, y;
int tim = tt->ttime;
int tim = NO_TIME;
int h, min, hh, ch, cmin, chh;
int i;
char const *pm, *cpm;
@@ -72,6 +72,9 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
FromDSE(dse, &y, &m, &d);
if (tt) {
tim = tt->ttime;
}
if (tim == NO_TIME) tim = curtime;
tdiff = tim - curtime;
adiff = ABS(tdiff);
@@ -894,7 +897,7 @@ int DoSubstFromString(char const *source, DynamicBuffer *dbuf,
int r;
if (dse == NO_DATE) dse=DSEToday;
if (tim == NO_TIME) tim=SystemTime(0)/60;
if (tim == NO_TIME) tim=MinutesPastMidnight(0);
CreateParser(source, &tempP);
tempP.allownested = 0;
tempTrig.typ = MSG_TYPE;

View File

@@ -6,7 +6,7 @@
/* buffers. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Declaration of functions for manipulating dynamic buffers */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Error definitions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -121,6 +121,8 @@
#define E_STRING_TOO_LONG 101
#define E_TIME_TWICE 102
#define E_DURATION_NO_AT 103
#define E_EXPECTING_WEEKDAY 104
#ifdef MK_GLOBALS
#undef EXTERN
#define EXTERN
@@ -129,6 +131,10 @@
#define EXTERN extern
#endif
#define STR(X) STR2(X)
#define STR2(X) #X
#ifndef L_ERR_OVERRIDE
EXTERN char *ErrMsg[]
@@ -165,7 +171,7 @@ EXTERN char *ErrMsg[]
"Number too high",
"Number too low",
"Can't open file",
"INCLUDE nested too deeply",
"INCLUDE nested too deeply (max. " STR(INCLUDE_NEST) ")",
"Parse error",
"Can't compute trigger",
"Too many nested IFs",
@@ -189,8 +195,8 @@ EXTERN char *ErrMsg[]
"Day specified twice",
"Unknown token",
"Must specify month in OMIT command",
"Too many partial OMITs",
"Too many full OMITs",
"Too many partial OMITs (max. " STR(MAX_PARTIAL_OMITS) ")",
"Too many full OMITs (max. " STR(MAX_FULL_OMITS) ")",
"Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT",
"Error reading",
"Expecting end-of-line",
@@ -237,7 +243,8 @@ EXTERN char *ErrMsg[]
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
"Cannot specify DURATION without specifying AT",
"Expecting weekday name"
}
#endif /* MK_GLOBALS */
;

View File

@@ -5,7 +5,7 @@
/* This file contains routines to parse and evaluate */
/* expressions. */
/* */
/* Copyright 1992-2023 by Dianne Skoll */
/* Copyright 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -87,10 +87,11 @@ extern BuiltinFunc Func[];
static Operator OpStack[OP_STACK_SIZE];
static int OpStackPtr = 0;
static int OpStackHiWater = 0;
/* ValStack can't be static - needed by funcs.c */
Value ValStack[VAL_STACK_SIZE];
int ValStackPtr = 0;
Value ValStack[VAL_STACK_SIZE];
int ValStackPtr = 0;
int ValStackHiWater = 0;
/***************************************************************/
/* */
@@ -944,7 +945,8 @@ static int Subtract(void)
/***************************************************************/
static int Multiply(void)
{
Value v1, v2;
Value v1, v2, v3;
char *ptr;
int r;
PopValStack(v2);
@@ -964,6 +966,61 @@ static int Multiply(void)
PushValStack(v1);
return OK;
}
/* String times int means repeat the string that many times */
if ((v1.type == INT_TYPE && v2.type == STR_TYPE) ||
(v1.type == STR_TYPE && v2.type == INT_TYPE)) {
int rep = (v1.type == INT_TYPE ? v1.v.val : v2.v.val);
char const *str = (v1.type == INT_TYPE ? v2.v.str : v1.v.str);
int l;
/* Can't multiply by a negative number */
if (rep < 0) {
return E_2LOW;
}
if (rep == 0 || !str || !*str) {
/* Empty string */
DestroyValue(v1); DestroyValue(v2);
v3.type = STR_TYPE;
v3.v.str = malloc(1);
if (!v3.v.str) {
return E_NO_MEM;
}
*v3.v.str = 0;
PushValStack(v3);
return OK;
}
/* Create the new value */
l = (int) strlen(str);
if (l * rep < 0) {
DestroyValue(v1); DestroyValue(v2);
return E_STRING_TOO_LONG;
}
if ((unsigned long) l * (unsigned long) rep >= (unsigned long) INT_MAX) {
DestroyValue(v1); DestroyValue(v2);
return E_STRING_TOO_LONG;
}
if (MaxStringLen > 0 && ((unsigned long) l * (unsigned long) rep) > (unsigned long)MaxStringLen) {
DestroyValue(v1); DestroyValue(v2);
return E_STRING_TOO_LONG;
}
v3.type = STR_TYPE;
v3.v.str = malloc(l * rep + 1);
if (!v3.v.str) {
DestroyValue(v1); DestroyValue(v2);
return E_NO_MEM;
}
*v3.v.str = 0;
ptr = v3.v.str;
for (int i=0; i<rep; i++) {
strcat(ptr, str);
ptr += l;
}
DestroyValue(v1); DestroyValue(v2);
PushValStack(v3);
return OK;
}
DestroyValue(v1); DestroyValue(v2);
return E_BAD_TYPE;
}
@@ -1429,3 +1486,11 @@ int FnPopValStack(Value *val)
return OK;
}
}
void DebugExitFunc(void)
{
if (DebugFlag & DB_EXPR_STACKS) {
fprintf(stderr, "Operator stack high water: %d\n", OpStackHiWater);
fprintf(stderr, " Value stack high water: %d\n", ValStackHiWater);
}
}

View File

@@ -5,19 +5,20 @@
/* Contains a few definitions used by expression evaluator. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* Define the types of values */
#define ERR_TYPE 0
#define INT_TYPE 1
#define TIME_TYPE 2
#define DATE_TYPE 3
#define STR_TYPE 4
#define DATETIME_TYPE 5
#define SPECIAL_TYPE 6 /* Only for system variables */
#define ERR_TYPE 0
#define INT_TYPE 1
#define TIME_TYPE 2
#define DATE_TYPE 3
#define STR_TYPE 4
#define DATETIME_TYPE 5
#define SPECIAL_TYPE 6 /* Only for system variables */
#define CONST_INT_TYPE 7 /* Only for system variables */
/* Define stuff for parsing expressions */
#define BEG_OF_EXPR '['
@@ -32,10 +33,8 @@
for speed. BEWARE: These macros invoke return if an error happens ! */
#define PushOpStack(op) \
if (OpStackPtr >= OP_STACK_SIZE) \
return E_OP_STK_OVER; \
else \
OpStack[OpStackPtr++] = (op)
do { if (OpStackPtr >= OP_STACK_SIZE) return E_OP_STK_OVER; \
else { OpStack[OpStackPtr++] = (op); if (OpStackPtr > OpStackHiWater) OpStackHiWater = OpStackPtr; } } while(0)
#define PopOpStack(op) \
if (OpStackPtr <= 0) \
@@ -44,10 +43,13 @@ else \
(op) = OpStack[--OpStackPtr]
#define PushValStack(val) \
if (ValStackPtr >= VAL_STACK_SIZE) \
return E_VA_STK_OVER; \
else \
ValStack[ValStackPtr++] = (val)
do { if (ValStackPtr >= VAL_STACK_SIZE) { \
DestroyValue(val); \
return E_VA_STK_OVER; \
} else { \
ValStack[ValStackPtr++] = (val); \
if (ValStackPtr > ValStackHiWater) ValStackHiWater = ValStackPtr; \
} } while (0);
#define PopValStack(val) \
if (ValStackPtr <= 0) \

View File

@@ -7,7 +7,7 @@
/* files. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -15,7 +15,7 @@
#include "config.h"
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
@@ -42,8 +42,8 @@
/* 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 FCLOSE(fp) ((((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL))
#define PCLOSE(fp) ((((fp)!=stdin)) ? (pclose(fp),(fp)=NULL) : ((fp)=NULL))
/* Define the structures needed by the file caching system */
typedef struct cache {
@@ -100,6 +100,22 @@ static int CheckSafety (void);
static int CheckSafetyAux (struct stat *statbuf);
static int PopFile (void);
static int IncludeCmd(char const *);
void set_cloexec(FILE *fp)
{
int flags;
int fd;
if (fp) {
fd = fileno(fp);
flags = fcntl(fd, F_GETFD);
if (flags >= 0) {
flags |= FD_CLOEXEC;
fcntl(fd, F_SETFD, flags);
}
}
}
static void OpenPurgeFile(char const *fname, char const *mode)
{
DynamicBuffer fname_buf;
@@ -123,6 +139,7 @@ static void OpenPurgeFile(char const *fname, char const *mode)
if (!PurgeFP) {
fprintf(ErrFp, "Cannot open `%s' for writing: %s\n", DBufValue(&fname_buf), strerror(errno));
}
set_cloexec(PurgeFP);
DBufFree(&fname_buf);
}
@@ -327,6 +344,7 @@ int OpenFile(char const *fname)
}
} else {
fp = fopen(fname, "r");
set_cloexec(fp);
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Reading `%s': Opening file on disk\n", fname);
}
@@ -346,6 +364,7 @@ int OpenFile(char const *fname)
if (strcmp(fname, "-")) {
fp = fopen(fname, "r");
if (!fp || !CheckSafety()) return E_CANT_OPEN;
set_cloexec(fp);
if (PurgeMode) OpenPurgeFile(fname, "w");
} else {
fp = stdin;
@@ -542,6 +561,7 @@ static int PopFile(void)
if (strcmp(i->filename, "-")) {
fp = fopen(i->filename, "r");
if (!fp || !CheckSafety()) return E_CANT_OPEN;
set_cloexec(fp);
if (PurgeMode) OpenPurgeFile(i->filename, "a");
} else {
fp = stdin;

View File

@@ -6,11 +6,10 @@
/* expressions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
#include "version.h"
#include "config.h"
@@ -66,8 +65,6 @@ static int FAbs (func_info *);
static int FAccess (func_info *);
static int FAmpm (func_info *);
static int FAnsicolor (func_info *);
static int FTrig (func_info *);
static int FIsAny (func_info *);
static int FArgs (func_info *);
static int FAsc (func_info *);
static int FBaseyr (func_info *);
@@ -101,6 +98,7 @@ static int FHtmlEscape (func_info *);
static int FHtmlStriptags (func_info *);
static int FIif (func_info *);
static int FIndex (func_info *);
static int FIsAny (func_info *);
static int FIsdst (func_info *);
static int FIsleap (func_info *);
static int FIsomitted (func_info *);
@@ -117,6 +115,7 @@ static int FMoondate (func_info *);
static int FMoondatetime (func_info *);
static int FMoonphase (func_info *);
static int FMoontime (func_info *);
static int FMultiTrig (func_info *);
static int FNDawn (func_info *);
static int FNDusk (func_info *);
static int FNonomitted (func_info *);
@@ -134,6 +133,7 @@ static int FRealtoday (func_info *);
static int FRows (func_info *);
static int FSgn (func_info *);
static int FShell (func_info *);
static int FShellescape (func_info *);
static int FSlide (func_info *);
static int FSoleq (func_info *);
static int FStdout (func_info *);
@@ -156,9 +156,9 @@ static int FTrigeventstart (func_info *);
static int FTrigfrom (func_info *);
static int FTrigger (func_info *);
static int FTrigpriority (func_info *);
static int FTrigtags (func_info *);
static int FTrigrep (func_info *);
static int FTrigscanfrom (func_info *);
static int FTrigtags (func_info *);
static int FTrigtime (func_info *);
static int FTrigtimedelta (func_info *);
static int FTrigtimerep (func_info *);
@@ -166,15 +166,14 @@ 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 FUTCToLocal (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);
@@ -195,6 +194,7 @@ static int CacheHebYear, CacheHebMon, CacheHebDay;
/* We need access to the value stack */
extern Value ValStack[];
extern int ValStackPtr;
extern int ValStackHiWater;
/* Macro for accessing arguments from the value stack - args are numbered
from 0 to (Nargs - 1) */
@@ -251,7 +251,7 @@ BuiltinFunc Func[] = {
{ "defined", 1, 1, 0, FDefined },
{ "dosubst", 1, 3, 0, FDosubst },
{ "dusk", 0, 1, 0, FDusk },
{ "easterdate", 1, 1, 0, FEasterdate },
{ "easterdate", 0, 1, 0, FEasterdate },
{ "evaltrig", 1, 2, 0, FEvalTrig },
{ "filedate", 1, 1, 0, FFiledate },
{ "filedatetime", 1, 1, 0, FFiledatetime },
@@ -284,12 +284,13 @@ BuiltinFunc Func[] = {
{ "moondatetime", 1, 3, 0, FMoondatetime },
{ "moonphase", 0, 2, 0, FMoonphase },
{ "moontime", 1, 3, 0, FMoontime },
{ "multitrig", 1, NO_MAX, 0, FMultiTrig },
{ "ndawn", 0, 1, 0, FNDawn},
{ "ndusk", 0, 1, 0, FNDusk},
{ "nonomitted", 2, NO_MAX, 0, FNonomitted },
{ "now", 0, 0, 0, FNow },
{ "ord", 1, 1, 1, FOrd },
{ "orthodoxeaster",1, 1, 0, FOrthodoxeaster },
{ "orthodoxeaster",0, 1, 0, FOrthodoxeaster },
{ "ostype", 0, 0, 1, FOstype },
{ "pad", 3, 4, 1, FPad },
{ "plural", 1, 3, 1, FPlural },
@@ -1421,28 +1422,28 @@ static int FRealtoday(func_info *info)
static int FNow(func_info *info)
{
RetVal.type = TIME_TYPE;
RETVAL = (int) ( SystemTime(0) / 60L );
RETVAL = MinutesPastMidnight(0);
return OK;
}
static int FRealnow(func_info *info)
{
RetVal.type = TIME_TYPE;
RETVAL = (int) ( SystemTime(1) / 60L );
RETVAL = MinutesPastMidnight(1);
return OK;
}
static int FCurrent(func_info *info)
{
RetVal.type = DATETIME_TYPE;
RETVAL = DSEToday * MINUTES_PER_DAY + (SystemTime(0) / 60);
RETVAL = DSEToday * MINUTES_PER_DAY + MinutesPastMidnight(0);
return OK;
}
static int FRealCurrent(func_info *info)
{
RetVal.type = DATETIME_TYPE;
RETVAL = RealToday * MINUTES_PER_DAY + (SystemTime(1) / 60);
RETVAL = RealToday * MINUTES_PER_DAY + MinutesPastMidnight(1);
return OK;
}
@@ -2364,13 +2365,17 @@ static int FEasterdate(func_info *info)
{
int y, m, d;
int g, c, x, z, e, n;
if (ARG(0).type == INT_TYPE) {
y = ARGV(0);
if (y < BASE) return E_2LOW;
else if (y > BASE+YR_RANGE) return E_2HIGH;
} else if (HASDATE(ARG(0))) {
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
} else return E_BAD_TYPE;
if (Nargs == 0) {
FromDSE(DSEToday, &y, &m, &d);
} else {
if (ARG(0).type == INT_TYPE) {
y = ARGV(0);
if (y < BASE) return E_2LOW;
else if (y > BASE+YR_RANGE) return E_2HIGH;
} else if (HASDATE(ARG(0))) {
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
} else return E_BAD_TYPE;
}
do {
g = (y % 19) + 1; /* golden number */
@@ -2409,13 +2414,17 @@ static int FOrthodoxeaster(func_info *info)
{
int y, m, d;
int a, b, c, dd, e, f, dse;
if (ARG(0).type == INT_TYPE) {
y = ARGV(0);
if (y < BASE) return E_2LOW;
else if (y > BASE+YR_RANGE) return E_2HIGH;
} else if (HASDATE(ARG(0))) {
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
} else return E_BAD_TYPE;
if (Nargs == 0) {
FromDSE(DSEToday, &y, &m, &d);
} else {
if (ARG(0).type == INT_TYPE) {
y = ARGV(0);
if (y < BASE) return E_2LOW;
else if (y > BASE+YR_RANGE) return E_2HIGH;
} else if (HASDATE(ARG(0))) {
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
} else return E_BAD_TYPE;
}
do {
a = y % 4;
@@ -2492,7 +2501,7 @@ static int FTimezone(func_info *info)
if (Nargs == 0) {
dse = DSEToday;
now = (SystemTime(0) / 60);
now = MinutesPastMidnight(0);
} else {
if (!HASDATE(ARG(0))) return E_BAD_TYPE;
dse = DATEPART(ARG(0));
@@ -3512,6 +3521,57 @@ FEvalTrig(func_info *info)
return OK;
}
static int
FMultiTrig(func_info *info)
{
Parser p;
Trigger trig;
TimeTrig tim;
int dse;
int r;
int i;
int earliest = -1;
RetVal.type = DATE_TYPE;
RETVAL = 0;
for (i=0; i<Nargs; i++) {
ASSERT_TYPE(i, STR_TYPE);
}
for (i=0; i<Nargs; i++) {
CreateParser(ARGSTR(i), &p);
p.allownested = 0;
r = ParseRem(&p, &trig, &tim, 0);
if (r) {
DestroyParser(&p);
return r;
}
if (trig.typ != NO_TYPE) {
DestroyParser(&p);
FreeTrig(&trig);
return E_PARSE_ERR;
}
if (tim.ttime != NO_TIME) {
Eprint("Cannot use AT clause in multitrig() function");
return E_PARSE_ERR;
}
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
DestroyParser(&p);
if (r != E_CANT_TRIG) {
if (dse < earliest || earliest < 0) {
earliest = dse;
}
}
FreeTrig(&trig);
}
if (earliest >= 0) {
RETVAL = earliest;
}
return OK;
}
static int LastTrig = 0;
static int
FTrig(func_info *info)
@@ -3549,20 +3609,18 @@ FTrig(func_info *info)
return E_PARSE_ERR;
}
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
DestroyParser(&p);
if (r == E_CANT_TRIG) {
DestroyParser(&p);
FreeTrig(&trig);
continue;
}
if (ShouldTriggerReminder(&trig, &tim, dse, &r)) {
LastTrig = dse;
RETVAL = dse;
DestroyParser(&p);
FreeTrig(&trig);
return OK;
}
DestroyParser(&p);
FreeTrig(&trig);
}
return OK;
@@ -3574,6 +3632,8 @@ rows_or_cols(func_info *info, int want_rows)
struct winsize w;
int fd = STDOUT_FILENO;
int opened = 0;
RetVal.type = INT_TYPE;
if (!isatty(fd)) {
fd = open("/dev/tty", O_RDONLY);
@@ -3581,6 +3641,7 @@ rows_or_cols(func_info *info, int want_rows)
RETVAL = -1;
return OK;
}
opened = 1;
}
if (ioctl(fd, TIOCGWINSZ, &w) == 0) {
if (want_rows) RETVAL = w.ws_row;
@@ -3588,7 +3649,7 @@ rows_or_cols(func_info *info, int want_rows)
} else {
RETVAL = -1;
}
if (fd != STDOUT_FILENO) {
if (opened) {
close(fd);
}
return OK;
@@ -3672,11 +3733,8 @@ mean_december_solstice(double y)
}
/* Cosine of an angle specified in degrees */
static double
cosd(double degrees)
{
return cos((degrees / 180.0) * 3.14159265358979);
}
#define PI_BY_180 0.01745329251994329576923690768
#define cosd(theta) cos( (theta) * PI_BY_180)
/* Astronomical Algorithms by Meeus, p. 179
These weird periodic components refine the mean solstice/equinox dates
@@ -3757,7 +3815,7 @@ solstice_equinox_for_year(int y, int which)
j -= 2447892.50000; /* This is the Julian date of midnight, 1 Jan 1990 UTC */
int dse = (int) j;
int min = floor((j - (double) dse) * MINUTES_PER_DAY);
int min = (int) floor((j - (double) dse) * MINUTES_PER_DAY);
int ret;
/* Convert from UTC to local time */
@@ -3805,8 +3863,10 @@ FSoleq(func_info *info)
}
ret = solstice_equinox_for_year(y, which);
if (ret < 0) return E_MKTIME_PROBLEM;
if (dse != NO_DATE && (ret / MINUTES_PER_DAY) < dse) {
ret = solstice_equinox_for_year(y+1, which);
if (ret < 0) return E_MKTIME_PROBLEM;
}
RetVal.type = DATETIME_TYPE;
RETVAL = ret;

View File

@@ -8,7 +8,7 @@
/* globals.h and err.h */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -39,7 +39,7 @@ EXTERN FILE *ErrFp;
#define IsLeapYear(y) (((y) % 4) ? 0 : ((!((y) % 100) && ((y) % 400)) ? 0 : 1 ))
#define DaysInMonth(m, y) ((m) != 1 ? MonthDays[m] : 28 + IsLeapYear(y))
#define DestroyValue(x) (void) (((x).type == STR_TYPE && (x).v.str) ? (free((x).v.str),(x).v.str = NULL,(x).type = ERR_TYPE) : 0)
#define DestroyValue(x) do { if ((x).type == STR_TYPE && (x).v.str) { free((x).v.str); (x).v.str = NULL; } (x).type = ERR_TYPE; } while (0)
EXTERN int DSEToday;
EXTERN int RealToday;
@@ -50,6 +50,7 @@ EXTERN int LineNo;
EXTERN int FreshLine;
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
EXTERN INIT( int MaxLateMinutes, 0);
EXTERN INIT( int NumTrustedUsers, 0);
EXTERN INIT( char const *MsgCommand, NULL);
EXTERN INIT( char const *QueuedMsgCommand, NULL);
@@ -78,7 +79,7 @@ EXTERN INIT( int SortByDate, 0);
EXTERN INIT( int SortByPrio, 0);
EXTERN INIT( int UntimedBeforeTimed, 0);
EXTERN INIT( int DefaultPrio, NO_PRIORITY);
EXTERN INIT( long SysTime, -1L);
EXTERN INIT( int SysTime, -1);
EXTERN INIT( int ParseUntriggered, 1);
EXTERN char const *InitialFile;
@@ -91,6 +92,7 @@ EXTERN INIT( int DontQueue, 0);
EXTERN INIT( int NumQueued, 0);
EXTERN INIT( int DontIssueAts, 0);
EXTERN INIT( int Daemon, 0);
EXTERN INIT( int DaemonJSON, 0);
EXTERN INIT( char DateSep, DATESEP);
EXTERN INIT( char TimeSep, TIMESEP);
EXTERN INIT( char DateTimeSep, DATETIMESEP);
@@ -101,7 +103,7 @@ EXTERN INIT( int SynthesizeTags, 0);
EXTERN INIT( int ScFormat, SC_AMPM);
EXTERN INIT( int MaxSatIter, 1000);
EXTERN INIT( int MaxStringLen, MAX_STR_LEN);
EXTERN INIT( char *FileName, NULL);
EXTERN INIT( char *FileName, NULL);
EXTERN INIT( int UseStdin, 0);
EXTERN INIT( int PurgeMode, 0);
EXTERN INIT( int PurgeIncludeDepth, 0);
@@ -156,6 +158,9 @@ EXTERN INIT( char *EndSentIg, "\"')]}>");
EXTERN DynamicBuffer Banner;
EXTERN DynamicBuffer LineBuffer;
EXTERN DynamicBuffer ExprBuf;
extern int NumFullOmits, NumPartialOmits;
/* List of months */
EXTERN char *EnglishMonthName[]
#ifdef MK_GLOBALS

View File

@@ -5,7 +5,7 @@
/* Support for the Hebrew calendar */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/* Derived from code written by Amos Shapir in 1978; revised */

View File

@@ -7,7 +7,7 @@
/* in normal mode. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -25,10 +25,11 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <poll.h>
#include <pwd.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#ifdef HAVE_INITGROUPS
#include <grp.h>
@@ -40,6 +41,14 @@
#include "expr.h"
#include "err.h"
static int should_guess_terminal_background = 1;
static void guess_terminal_background(int *r, int *g, int *b);
static int tty_init(int fd);
static void tty_raw(int fd);
static void tty_reset(int fd);
static void ProcessLongOption(char const *arg);
/***************************************************************
*
* Command line options recognized:
@@ -69,6 +78,7 @@
* t = Display trigger dates
* v = Dump variables at end
* l = Display entire line in error messages
* s = Display expression-parsing stack usage before exit
* -e = Send messages normally sent to stderr to stdout instead
* -z[n] = Daemon mode waking up every n (def 1) minutes.
* -bn = Time format for cal (0, 1, or 2)
@@ -219,7 +229,7 @@ void InitRemind(int argc, char const *argv[])
}
} else {
fprintf(stderr, "Invoked with a NULL argv[0]; bailing because that's just plain bizarre.\n");
exit(1);
exit(EXIT_FAILURE);
}
/* Parse the command-line options */
@@ -243,6 +253,11 @@ void InitRemind(int argc, char const *argv[])
while(*arg) arg++;
break;
case '-':
ProcessLongOption(arg);
while(*arg) arg++;
break;
case '@':
UseVTColors = 1;
if (*arg) {
@@ -259,16 +274,24 @@ void InitRemind(int argc, char const *argv[])
if (*arg == ',') {
arg++;
if (*arg != ',') {
PARSENUM(x, arg);
if (x == 0) {
TerminalBackground = TERMINAL_BACKGROUND_DARK;
} else if (x == 1) {
TerminalBackground = TERMINAL_BACKGROUND_LIGHT;
} else if (x == 2) {
TerminalBackground = TERMINAL_BACKGROUND_UNKNOWN;
if (*arg == 't') {
arg++;
should_guess_terminal_background = 2;
} else {
fprintf(ErrFp, "%s: -@n,m,b: m must be 0, 1 or 2 (assuming 2)\n",
argv[0]);
PARSENUM(x, arg);
if (x == 0) {
should_guess_terminal_background = 0;
TerminalBackground = TERMINAL_BACKGROUND_DARK;
} else if (x == 1) {
should_guess_terminal_background = 0;
TerminalBackground = TERMINAL_BACKGROUND_LIGHT;
} else if (x == 2) {
should_guess_terminal_background = 0;
TerminalBackground = TERMINAL_BACKGROUND_UNKNOWN;
} else {
fprintf(ErrFp, "%s: -@n,m,b: m must be t, 0, 1 or 2 (assuming 2)\n",
argv[0]);
}
}
}
}
@@ -403,7 +426,11 @@ void InitRemind(int argc, char const *argv[])
case 'z':
case 'Z':
DontFork = 1;
if (*arg == '0') {
if (*arg == 'j' || *arg == 'J') {
while (*arg) arg++;
Daemon = -1;
DaemonJSON = 1;
} else if (*arg == '0') {
PARSENUM(Daemon, arg);
if (Daemon == 0) Daemon = -1;
else if (Daemon < 1) Daemon = 1;
@@ -537,7 +564,7 @@ void InitRemind(int argc, char const *argv[])
arg++;
/* -wt means get width from /dev/tty */
ttyfd = open("/dev/tty", O_RDONLY);
if (!ttyfd) {
if (ttyfd < 0) {
fprintf(stderr, "%s: `-wt': Cannot open /dev/tty: %s\n",
argv[0], strerror(errno));
} else {
@@ -548,7 +575,12 @@ void InitRemind(int argc, char const *argv[])
PARSENUM(CalWidth, arg);
if (CalWidth != 0 && CalWidth < 71) CalWidth = 71;
if (CalWidth == 0) {
CalWidth = -1;
/* Cal width of 0 means obtain from stdout */
if (isatty(STDOUT_FILENO)) {
InitCalWidthAndFormWidth(STDOUT_FILENO);
} else {
CalWidth = 80;
}
}
FormWidth = CalWidth - 8;
if (FormWidth < 20) FormWidth = 20;
@@ -573,6 +605,7 @@ void InitRemind(int argc, char const *argv[])
case 'D':
while (*arg) {
switch(*arg++) {
case 's': case 'S': DebugFlag |= DB_EXPR_STACKS; break;
case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break;
case 'x': case 'X': DebugFlag |= DB_PRTEXPR; break;
case 't': case 'T': DebugFlag |= DB_PRTTRIG; break;
@@ -726,7 +759,7 @@ void InitRemind(int argc, char const *argv[])
/* Figure out the offset from UTC */
if (CalculateUTC)
(void) CalcMinsFromUTC(DSEToday, SystemTime(0)/60,
(void) CalcMinsFromUTC(DSEToday, MinutesPastMidnight(0),
&MinsFromUTC, NULL);
}
@@ -740,7 +773,7 @@ void InitRemind(int argc, char const *argv[])
#ifndef L_USAGE_OVERRIDE
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2023 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
@@ -958,3 +991,139 @@ AddTrustedUser(char const *username)
NumTrustedUsers++;
}
static void
ProcessLongOption(char const *arg)
{
if (!strcmp(arg, "version")) {
printf("%s\n", VERSION);
exit(EXIT_SUCCESS);
}
fprintf(ErrFp, "%s: Unknown long option --%s\n", ArgV[0], arg);
}
static void
guess_terminal_background(int *r, int *g, int *b)
{
int ttyfd;
struct pollfd p;
unsigned int rr, gg, bb;
char buf[128];
int n;
*r = -1;
*g = -1;
*b = -1;
/* Don't guess if stdout not a terminal unless asked to by @,t */
if (should_guess_terminal_background != 2) {
if (!isatty(STDOUT_FILENO)) {
return;
}
}
ttyfd = open("/dev/tty", O_RDWR);
if (ttyfd < 0) {
return;
}
if (!isatty(ttyfd)) {
/* Not a TTY: Can't guess the color */
close(ttyfd);
return;
}
if (!tty_init(ttyfd)) {
return;
}
tty_raw(ttyfd);
n = write(ttyfd, "\033]11;?\033\\", 8);
if (n != 8) {
/* write failed... WTF? Not much we can do */
return;
}
/* Wait up to 0.1s for terminal to respond */
p.fd = ttyfd;
p.events = POLLIN;
if (poll(&p, 1, 100) < 0) {
tty_reset(ttyfd);
close(ttyfd);
return;
}
if (!(p.revents & POLLIN)) {
tty_reset(ttyfd);
close(ttyfd);
return;
}
n = read(ttyfd, buf, 127);
if (n <= 0) {
tty_reset(ttyfd);
close(ttyfd);
return;
}
tty_reset(ttyfd);
buf[n+1] = 0;
if (n < 25) {
/* Too short */
return;
}
if (sscanf(buf+5, "rgb:%x/%x/%x", &rr, &gg, &bb) != 3) {
/* Couldn't scan color codes */
return;
}
*r = (int) ((rr >> 8) & 255);
*g = (int) ((gg >> 8) & 255);
*b = (int) ((bb >> 8) & 255);
}
static struct termios orig_termios;
static int
tty_init(int fd)
{
if (tcgetattr(fd, &orig_termios) < 0) {
return 0;
}
return 1;
}
static void
tty_raw(int fd)
{
struct termios raw;
raw = orig_termios;
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
raw.c_oflag &= ~(OPOST);
raw.c_cflag |= (CS8);
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
/* put terminal in raw mode after flushing */
tcsetattr(fd,TCSAFLUSH,&raw);
}
static void
tty_reset(int fd)
{
tcsetattr(fd, TCSAFLUSH, &orig_termios);
}
int
GetTerminalBackground(void)
{
int r, g, b;
if (should_guess_terminal_background) {
guess_terminal_background(&r, &g, &b);
if (r >= 0 && g >= 0 && b >= 0) {
if (r+g+b <= 85*3 && r <= 128 && g <= 128 && b <= 128) {
TerminalBackground = TERMINAL_BACKGROUND_DARK;
} else {
TerminalBackground = TERMINAL_BACKGROUND_LIGHT;
}
}
should_guess_terminal_background = 0;
}
return TerminalBackground;
}

View File

@@ -5,7 +5,7 @@
/* Header file for language support for various languages. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -6,7 +6,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2023 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
/* This file is Copyright (C) 1993 by Mogens Lynnerup. */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */

View File

@@ -11,7 +11,7 @@
/* Further corrections by Erik-Jan Vens */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Support for the English language. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

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-2023 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -245,7 +245,8 @@ EXTERN char *ErrMsg[] =
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
"Cannot specify DURATION without specifying AT",
"Odotettu viikonpäivän nimi"
};
#endif /* MK_GLOBALS */
@@ -254,7 +255,7 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2023 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETAVERSIO <<<<\n");
#endif
@@ -271,12 +272,10 @@ void Usage(void)
fprintf(ErrFp, " -o Älä noudata ONCE-lauseita\n");
fprintf(ErrFp, " -t Laukaise kaikki viestit deltan arvosta välittämättä\n");
fprintf(ErrFp, " -h Suppeat tulostukset\n");
#ifdef HAVE_QUEUED
fprintf(ErrFp, " -a Älä laukaise viestejä heti - lisää ne jonoon\n");
fprintf(ErrFp, " -q Älä lisää viestejä jonoon\n");
fprintf(ErrFp, " -f Laukaise viestit, pysy etualalla\n");
fprintf(ErrFp, " -z[n] Käynnisty demonina, herätys n:n (5:n) minuutin välein\n");
#endif
fprintf(ErrFp, " -d... Virheenetsintä: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
fprintf(ErrFp, " -e Ohjaa virhetulostus stdout-vuohon\n");
fprintf(ErrFp, " -b[n] Ajan ilmaisu: 0=ap/ip, 1=24 tuntia, 2=ei aikoja\n");

View File

@@ -8,7 +8,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2023 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
/* This file is Copyright (C) 1993 by Laurent Duperval and */
/* Dianne Skoll. */
/* SPDX-License-Identifier: GPL-2.0-only */
@@ -219,7 +219,8 @@ EXTERN char *ErrMsg[] =
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
"Cannot specify DURATION without specifying AT",
"Nom du jour de la semaine attendu",
};
#endif /* MK_GLOBALS */
@@ -228,7 +229,7 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2023 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
@@ -245,12 +246,10 @@ void Usage(void)
fprintf(ErrFp, " -o Ignorer instructions ONCE\n");
fprintf(ErrFp, " -t Déclencher tous les rappels peu importe le delta\n");
fprintf(ErrFp, " -h Mode silencieux\n");
#ifdef HAVE_QUEUED
fprintf(ErrFp, " -a Ne pas déclencher les rappels minutés immédiatement - les mettre en file\n");
fprintf(ErrFp, " -q Ne pas mettre les rappels minutés en file\n");
fprintf(ErrFp, " -f Déclencher les rappels minutés immédiatement en restant en avant-plan\n");
fprintf(ErrFp, " -z[n] Entrer en mode 'daemon', réveil chaque n (5) minutes\n");
#endif
fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
fprintf(ErrFp, " -e Envoyer les messages de stderr à stdout\n");
fprintf(ErrFp, " -b[n] Formats de l'heure pour le calendrier: 0=am/pm, 1=24hr, 2=aucun\n");

View File

@@ -9,7 +9,7 @@
/* I don't speak German. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Support for the Icelandic language. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Translated by Björn Davíðsson (bjossi@snerpa.is) */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */

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-2023 by Dianne Skoll */
/* Remind is copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

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-2023 by Dianne Skoll */
/* Remind is Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -9,7 +9,7 @@
/* Polish. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -235,7 +235,8 @@ EXTERN char *ErrMsg[] =
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
"Cannot specify DURATION without specifying AT",
"Oczekiwana nazwa dnia tygodnia"
};
#endif /* MK_GLOBALS */
@@ -244,7 +245,7 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2023 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
@@ -261,12 +262,10 @@ void Usage(void)
fprintf(ErrFp, " -o Ignoruj instrukcje ONCE\n");
fprintf(ErrFp, " -t Odpal wszystkie przyszłe przypomnienia niezależnie od delty\n");
fprintf(ErrFp, " -h Praca bezszmerowa\n");
#ifdef HAVE_QUEUED
fprintf(ErrFp, " -a Nie odpalaj przyponień czasowych - kolejkuj je\n");
fprintf(ErrFp, " -q Nie kolejkuj przyponień czasowych\n");
fprintf(ErrFp, " -f Nie przechodź do pracy w tle\n");
fprintf(ErrFp, " -z[n] Pracuj jako demon, budząc się co n (5) minut\n");
#endif
fprintf(ErrFp, " -d... Odpluskwianie: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
fprintf(ErrFp, " -e Komunikaty o błędach skieruj na stdout\n");
fprintf(ErrFp, " -b[n] Format czasu: 0=am/pm, 1=24godz., 2=żaden\n");

View File

@@ -8,7 +8,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2023 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
/* This file is Copyright (C) 1996 by Marco Paganini and */
/* Dianne Skoll. */
/* SPDX-License-Identifier: GPL-2.0-only */
@@ -244,7 +244,8 @@ EXTERN char *ErrMsg[] =
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
"Cannot specify DURATION without specifying AT",
"Esperando nome do dia da semana",
};
#endif /* MK_GLOBALS */
@@ -253,7 +254,7 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-2023 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> VERSAO BETA <<<<\n");
#endif
@@ -270,12 +271,10 @@ void Usage(void)
fprintf(ErrFp, " -o Ignora diretivas ONCE\n");
fprintf(ErrFp, " -t Aciona todos os compromissos futuros, sem considerar o delta\n");
fprintf(ErrFp, " -h Modo `Hush' - quieto\n");
#ifdef HAVE_QUEUED
fprintf(ErrFp, " -a Nao aciona compromissos com hora imediatamente - apenas coloca na fila\n");
fprintf(ErrFp, " -q Nao coloca compromissos com hora na fila\n");
fprintf(ErrFp, " -f Aciona compromissos com hora em modo foreground\n");
fprintf(ErrFp, " -z[n] Modo `daemon', acordando a cada n (5) minutos.\n");
#endif
fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trigger v=dumpvars l=showline\n");
fprintf(ErrFp, " -e Desvia mensagens normalmente enviadas a stderr para stdout\n");
fprintf(ErrFp, " -b[n] Formato da hora para o cal: 0=am/pm, 1=24hr, 2=nenhum\n");

View File

@@ -8,7 +8,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2023 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
/* This file is Copyright (C) 1996-1998 by Liviu Daia */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */

View File

@@ -7,7 +7,7 @@
/* Author: Rafa Couto <rafacouto@biogate.com> */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -6,7 +6,7 @@
/* routines, etc. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -14,6 +14,8 @@
#define _XOPEN_SOURCE 600
#include "config.h"
#include <fcntl.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
@@ -45,6 +47,9 @@
static void DoReminders(void);
/* Macro for simplifying common block so as not to litter code */
#define OUTPUT(c) do { if (output) { DBufPutc(output, c); } else { putchar(c); } } while(0)
/***************************************************************/
/***************************************************************/
/** **/
@@ -71,6 +76,8 @@ int main(int argc, char *argv[])
DBufInit(&(LastTrigger.tags));
ClearLastTriggers();
atexit(DebugExitFunc);
if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) {
ProduceCalendar();
return 0;
@@ -181,14 +188,14 @@ static void DoReminders(void)
if (FileAccessDate < 0) {
fprintf(ErrFp, "%s: `%s': %s.\n", ErrMsg[E_CANTACCESS], InitialFile, strerror(errno));
exit(1);
exit(EXIT_FAILURE);
}
r=IncludeFile(InitialFile);
if (r) {
fprintf(ErrFp, "%s %s: %s\n", ErrMsg[E_ERR_READING],
InitialFile, ErrMsg[r]);
exit(1);
exit(EXIT_FAILURE);
}
while(1) {
@@ -196,7 +203,7 @@ static void DoReminders(void)
if (r == E_EOF) return;
if (r) {
Eprint("%s: %s", ErrMsg[E_ERR_READING], ErrMsg[r]);
exit(1);
exit(EXIT_FAILURE);
}
s = FindInitialToken(&tok, CurLine);
@@ -585,8 +592,8 @@ int EvaluateExpr(ParsePtr p, Value *v)
int r;
if (p->isnested) return E_PARSE_ERR; /* Can't nest expressions */
while (isempty(*p->pos)) (p->pos)++;
if (!p->pos) return E_PARSE_ERR; /* Missing expression */
while (isempty(*p->pos)) (p->pos)++;
if (*p->pos == BEG_OF_EXPR) {
(p->pos)++;
bracketed = 1;
@@ -747,19 +754,32 @@ int PushToken(char const *tok, ParsePtr p)
/* Return the system time in seconds past midnight */
/* */
/***************************************************************/
long SystemTime(int realtime)
int SystemTime(int realtime)
{
time_t tloc;
time_t now;
struct tm *t;
if (!realtime && (SysTime != -1L)) return SysTime;
if (!realtime && (SysTime != -1)) return SysTime;
(void) time(&tloc);
t = localtime(&tloc);
return (long) t->tm_hour * 3600L + (long) t->tm_min * 60L +
(long) t->tm_sec;
now = time(NULL);
t = localtime(&now);
return t->tm_hour * 3600L + t->tm_min * 60L +
t->tm_sec;
}
/***************************************************************/
/* */
/* MinutesPastMidnight */
/* */
/* Return the system time in minutes past midnight */
/* */
/***************************************************************/
int MinutesPastMidnight(int realtime)
{
return (SystemTime(realtime) / 60);
}
/***************************************************************/
/* */
/* SystemDate */
@@ -771,11 +791,11 @@ long SystemTime(int realtime)
/***************************************************************/
int SystemDate(int *y, int *m, int *d)
{
time_t tloc;
time_t now;
struct tm *t;
(void) time(&tloc);
t = localtime(&tloc);
now = time(NULL);
t = localtime(&now);
*d = t->tm_mday;
*m = t->tm_mon;
@@ -998,6 +1018,12 @@ int DoDebug(ParsePtr p)
else DebugFlag &= ~DB_ECHO_LINE;
break;
case 's':
case 'S':
if (val) DebugFlag |= DB_EXPR_STACKS;
else DebugFlag &= ~DB_EXPR_STACKS;
break;
case 'x':
case 'X':
if (val) DebugFlag |= DB_PRTEXPR;
@@ -1238,19 +1264,19 @@ int CalcMinsFromUTC(int dse, int tim, int *mins, int *isdst)
return 0;
}
static char const *OutputEscapeSequences(char const *s, int print)
static char const *OutputEscapeSequences(char const *s, int print, DynamicBuffer *output)
{
while (*s == 0x1B && *(s+1) == '[') {
if (print) putchar(*s);
if (print) OUTPUT(*s);
s++;
if (print) putchar(*s);
if (print) OUTPUT(*s);
s++;
while (*s && (*s < 0x40 || *s > 0x7E)) {
if (print) putchar(*s);
if (print) OUTPUT(*s);
s++;
}
if (*s) {
if (print) putchar(*s);
if (print) OUTPUT(*s);
s++;
}
}
@@ -1259,19 +1285,19 @@ static char const *OutputEscapeSequences(char const *s, int print)
#ifdef REM_USE_WCHAR
#define ISWBLANK(c) (iswspace(c) && (c) != '\n')
static wchar_t const *OutputEscapeSequencesWS(wchar_t const *s, int print)
static wchar_t const *OutputEscapeSequencesWS(wchar_t const *s, int print, DynamicBuffer *output)
{
while (*s == 0x1B && *(s+1) == '[') {
if (print) PutWideChar(*s);
if (print) PutWideChar(*s, output);
s++;
if (print) PutWideChar(*s);
if (print) PutWideChar(*s, output);
s++;
while (*s && (*s < 0x40 || *s > 0x7E)) {
if (print) PutWideChar(*s);
if (print) PutWideChar(*s, output);
s++;
}
if (*s) {
if (print) PutWideChar(*s);
if (print) PutWideChar(*s, output);
s++;
}
}
@@ -1280,7 +1306,7 @@ static wchar_t const *OutputEscapeSequencesWS(wchar_t const *s, int print)
static void
FillParagraphWCAux(wchar_t const *s)
FillParagraphWCAux(wchar_t const *s, DynamicBuffer *output)
{
int line = 0;
int i, j;
@@ -1295,7 +1321,7 @@ FillParagraphWCAux(wchar_t const *s)
/* If it's a carriage return, output it and start new paragraph */
if (*s == '\n') {
putchar('\n');
OUTPUT('\n');
s++;
line = 0;
while(ISWBLANK(*s)) s++;
@@ -1308,7 +1334,7 @@ FillParagraphWCAux(wchar_t const *s)
number of spaces */
j = line ? SubsIndent : FirstIndent;
for (i=0; i<j; i++) {
putchar(' ');
OUTPUT(' ');
}
/* Calculate the amount of room left on this line */
@@ -1321,7 +1347,7 @@ FillParagraphWCAux(wchar_t const *s)
if (*s == '\n') break;
while(1) {
t = s;
s = OutputEscapeSequencesWS(s, 1);
s = OutputEscapeSequencesWS(s, 1, output);
if (s == t) break;
while(ISWBLANK(*s)) s++;
}
@@ -1329,7 +1355,7 @@ FillParagraphWCAux(wchar_t const *s)
len = 0;
while(*s && !iswspace(*s)) {
if (*s == 0x1B && *(s+1) == '[') {
s = OutputEscapeSequencesWS(s, 0);
s = OutputEscapeSequencesWS(s, 0, output);
continue;
}
len += wcwidth(*s);
@@ -1340,17 +1366,17 @@ FillParagraphWCAux(wchar_t const *s)
}
if (!pendspace || len+pendspace <= roomleft) {
for (i=0; i<pendspace; i++) {
putchar(' ');
OUTPUT(' ');
}
while(t < s) {
PutWideChar(*t);
PutWideChar(*t, output);
if (strchr(EndSent, *t)) doublespace = 2;
else if (!strchr(EndSentIg, *t)) doublespace = 1;
t++;
}
} else {
s = t;
putchar('\n');
OUTPUT('\n');
line++;
break;
}
@@ -1361,7 +1387,7 @@ FillParagraphWCAux(wchar_t const *s)
}
static int
FillParagraphWC(char const *s)
FillParagraphWC(char const *s, DynamicBuffer *output)
{
size_t len;
wchar_t *buf;
@@ -1371,7 +1397,7 @@ FillParagraphWC(char const *s)
buf = calloc(len+1, sizeof(wchar_t));
if (!buf) return E_NO_MEM;
(void) mbstowcs(buf, s, len+1);
FillParagraphWCAux(buf);
FillParagraphWCAux(buf, output);
free(buf);
return OK;
}
@@ -1391,7 +1417,7 @@ FillParagraphWC(char const *s)
/* A macro safe ONLY if used with arg with no side effects! */
#define ISBLANK(c) (isspace(c) && (c) != '\n')
void FillParagraph(char const *s)
void FillParagraph(char const *s, DynamicBuffer *output)
{
int line = 0;
@@ -1409,7 +1435,7 @@ void FillParagraph(char const *s)
if (!*s) return;
#ifdef REM_USE_WCHAR
if (FillParagraphWC(s) == OK) {
if (FillParagraphWC(s, output) == OK) {
return;
}
#endif
@@ -1419,7 +1445,7 @@ void FillParagraph(char const *s)
/* If it's a carriage return, output it and start new paragraph */
if (*s == '\n') {
putchar('\n');
OUTPUT('\n');
s++;
line = 0;
while(ISBLANK(*s)) s++;
@@ -1432,7 +1458,7 @@ void FillParagraph(char const *s)
number of spaces */
j = line ? SubsIndent : FirstIndent;
for (i=0; i<j; i++) {
putchar(' ');
OUTPUT(' ');
}
/* Calculate the amount of room left on this line */
@@ -1445,7 +1471,7 @@ void FillParagraph(char const *s)
if (*s == '\n') break;
while(1) {
t = s;
s = OutputEscapeSequences(s, 1);
s = OutputEscapeSequences(s, 1, output);
if (s == t) break;
while(ISBLANK(*s)) s++;
}
@@ -1453,7 +1479,7 @@ void FillParagraph(char const *s)
len = 0;
while(*s && !isspace(*s)) {
if (*s == 0x1B && *(s+1) == '[') {
s = OutputEscapeSequences(s, 0);
s = OutputEscapeSequences(s, 0, output);
continue;
}
s++;
@@ -1464,17 +1490,17 @@ void FillParagraph(char const *s)
}
if (!pendspace || len+pendspace <= roomleft) {
for (i=0; i<pendspace; i++) {
putchar(' ');
OUTPUT(' ');
}
while(t < s) {
putchar(*t);
OUTPUT(*t);
if (strchr(EndSent, *t)) doublespace = 2;
else if (!strchr(EndSentIg, *t)) doublespace = 1;
t++;
}
} else {
s = t;
putchar('\n');
OUTPUT('\n');
line++;
break;
}
@@ -1638,12 +1664,51 @@ SaveLastTimeTrig(TimeTrig const *t)
memcpy(&LastTimeTrig, t, sizeof(LastTimeTrig));
}
/* Wrapper to ignore warnings about ignoring return value of system() */
/* Wrapper to ignore warnings about ignoring return value of system()
Also redirects stdin and stdout to /dev/null for queued reminders */
void
System(char const *cmd)
System(char const *cmd, int is_queued)
{
int r;
pid_t kid;
int fd;
int status;
int do_exit = 0;
if (is_queued && IsServerMode()) {
do_exit = 1;
/* Server mode... redirect stdin and stdout to /dev/null */
kid = fork();
if (kid == (pid_t) -1) {
/* Fork failed... nothing we can do */
return;
} else if (kid == 0) {
/* In the child */
(void) close(STDIN_FILENO);
(void) close(STDOUT_FILENO);
fd = open("/dev/null", O_RDONLY);
if (fd >= 0 && fd != STDIN_FILENO) {
dup2(fd, STDIN_FILENO);
close(STDIN_FILENO);
}
fd = open("/dev/null", O_WRONLY);
if (fd >= 0 && fd != STDOUT_FILENO) {
dup2(fd, STDOUT_FILENO);
close(STDOUT_FILENO);
}
} else {
/* In the parent */
while (waitpid(kid, &status, 0) != kid) /* continue */ ;
return;
}
}
/* This is the child process or original if we never forked */
r = system(cmd);
if (do_exit) {
/* In the child process, so exit! */
exit(0);
}
if (r == 0) {
return;
}

View File

@@ -5,7 +5,7 @@
/* Calculations for figuring out moon phases. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -412,7 +412,7 @@ static double phase(double pdate,
Day = pdate - epoch; /* Date within epoch */
N = fixangle((360 / 365.2422) * Day); /* Mean anomaly of the Sun */
M = fixangle(N + elonge - elongp); /* Convert from perigee
co-ordinates to epoch 1980.0 */
coordinates to epoch 1980.0 */
Ec = kepler(M, eccent); /* Solve equation of Kepler */
Ec = sqrt((1 + eccent) / (1 - eccent)) * tan(Ec / 2);
Ec = 2 * todeg(atan(Ec)); /* 1 anomaly */

View File

@@ -6,7 +6,7 @@
/* the data structures for OMITted dates. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -22,7 +22,7 @@
#include "err.h"
#include "expr.h"
static int BexistsIntArray (int array[], int num, int key);
static int BexistsIntArray (int const array[], int num, int key);
static void InsertIntoSortedArray (int *array, int num, int key);
/* Arrays for the global omits */
@@ -32,7 +32,7 @@ static int PartialOmitArray[MAX_PARTIAL_OMITS];
/* WeekdayOmits is declared in global.h */
/* How many of each omit types do we have? */
static int NumFullOmits, NumPartialOmits;
int NumFullOmits, NumPartialOmits;
/* The structure for saving and restoring OMIT contexts */
typedef struct omitcontext {
@@ -251,7 +251,7 @@ int IsOmitted(int dse, int localomit, char const *omitfunc, int *omit)
/* element is found, 0 otherwise. */
/* */
/***************************************************************/
static int BexistsIntArray(int array[], int num, int key)
static int BexistsIntArray(int const array[], int num, int key)
{
int top=num-1, bot=0, mid;
@@ -445,6 +445,9 @@ int DoOmit(ParsePtr p)
if (!BexistsIntArray(PartialOmitArray, NumPartialOmits, syndrome)) {
InsertIntoSortedArray(PartialOmitArray, NumPartialOmits, syndrome);
NumPartialOmits++;
if (NumPartialOmits == 366) {
Wprint("You have OMITted everything! The space-time continuum is at risk.");
}
}
if (mc == m[1] && dc == d[1]) {
break;

View File

@@ -5,7 +5,7 @@
/* Function Prototypes. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -22,6 +22,9 @@
/* Characters to ignore */
#define isempty(c) (isspace(c) || ((c) == '\\'))
#define IsServerMode() (Daemon < 0)
#define ShouldFork (!DontFork)
#include "dynbuf.h"
#include <ctype.h>
@@ -35,7 +38,7 @@ int DoRem (ParsePtr p);
int DoFlush (ParsePtr p);
void DoExit (ParsePtr p);
int ParseRem (ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals);
int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued);
int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued, DynamicBuffer *output);
int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int dse, int *err);
int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse, int mode);
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int dse, int tim);
@@ -71,7 +74,8 @@ void OutputLine (FILE *fp);
void CreateParser (char const *s, ParsePtr p);
void DestroyParser (ParsePtr p);
int PushToken (char const *tok, ParsePtr p);
long SystemTime (int realtime);
int SystemTime (int realtime);
int MinutesPastMidnight (int realtime);
int SystemDate (int *y, int *m, int *d);
int DoIf (ParsePtr p);
int DoElse (ParsePtr p);
@@ -104,7 +108,7 @@ char *StrDup (char const *s);
int StrCmpi (char const *s1, char const *s2);
Var *FindVar (char const *str, int create);
int DeleteVar (char const *str);
int SetVar (char const *str, Value *val);
int SetVar (char const *str, Value const *val);
int GetVarValue (char const *str, Value *val, Var *locals, ParsePtr p);
int DoSet (Parser *p);
int DoUnset (Parser *p);
@@ -114,7 +118,7 @@ void DestroyVars (int all);
int PreserveVar (char const *name);
int DoPreserve (Parser *p);
int DoSatRemind (Trigger *trig, TimeTrig *tt, ParsePtr p);
int DoMsgCommand (char const *cmd, char const *msg);
int DoMsgCommand (char const *cmd, char const *msg, int is_queued);
int ParseNonSpaceChar (ParsePtr p, int *err, int peek);
unsigned int HashVal (char const *str);
int DateOK (int y, int m, int d);
@@ -138,7 +142,7 @@ int GetSysVar (char const *name, Value *val);
int SetSysVar (char const *name, Value *val);
void DumpSysVarByName (char const *name);
int CalcMinsFromUTC (int dse, int tim, int *mins, int *isdst);
void FillParagraph (char const *s);
void FillParagraph (char const *s, DynamicBuffer *output);
void LocalToUTC (int locdate, int loctime, int *utcdate, int *utctime);
void UTCToLocal (int utcdate, int utctime, int *locdate, int *loctime);
int MoonPhase (int date, int time);
@@ -164,23 +168,30 @@ void PrintJSONKeyPairString(char const *name, char const *val);
void PrintJSONKeyPairDate(char const *name, int dse);
void PrintJSONKeyPairDateTime(char const *name, int dt);
void PrintJSONKeyPairTime(char const *name, int t);
void System(char const *cmd);
void System(char const *cmd, int queued);
int ShellEscape(char const *in, DynamicBuffer *out);
int AddGlobalOmit(int dse);
void set_lat_and_long_from_components(void);
void set_components_from_lat_and_long(void);
void DebugExitFunc(void);
int GetTerminalBackground(void);
char const *get_day_name(int wkday);
char const *get_month_name(int mon);
void set_cloexec(FILE *fp);
int push_call(char const *filename, char const *func, int lineno);
void clear_callstack(void);
int print_callstack(FILE *fp);
void pop_call(void);
void FixSpecialType(Trigger *trig);
void WriteJSONTrigger(Trigger const *t, int include_tags, int today);
void WriteJSONTimeTrigger(TimeTrig const *tt);
#ifdef REM_USE_WCHAR
#define _XOPEN_SOURCE 600
#include <wctype.h>
#include <wchar.h>
void PutWideChar(wchar_t const wc);
void PutWideChar(wchar_t const wc, DynamicBuffer *output);
#endif

View File

@@ -5,7 +5,7 @@
/* Queue up reminders for subsequent execution. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -24,16 +24,35 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <sys/select.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "types.h"
#include "globals.h"
#include "err.h"
#include "protos.h"
#include "expr.h"
#undef USE_INOTIFY
#if defined(HAVE_SYS_INOTIFY_H) && defined(HAVE_INOTIFY_INIT1)
#define USE_INOTIFY 1
#include <sys/inotify.h>
int watch_fd = -1;
static void consume_inotify_events(int fd);
static int setup_inotify_watch(void);
#endif
/* A list of filenames associated with queued reminders */
typedef struct queuedfname {
struct queuedfname *next;
char const *fname;
} QueuedFilename;
/* List structure for holding queued reminders */
typedef struct queuedrem {
struct queuedrem *next;
@@ -41,16 +60,19 @@ typedef struct queuedrem {
int RunDisabled;
int ntrig;
char const *text;
char const *fname;
int lineno;
char passthru[PASSTHRU_LEN+1];
char sched[VAR_NAME_LEN+1];
DynamicBuffer tags;
Trigger t;
TimeTrig tt;
int red, green, blue;
} QueuedRem;
/* Global variables */
static QueuedRem *QueueHead;
static QueuedRem *QueueHead = NULL;
static QueuedFilename *Files = NULL;
static time_t FileModTime;
static struct stat StatBuf;
@@ -58,9 +80,108 @@ static void CheckInitialFile (void);
static int CalculateNextTime (QueuedRem *q);
static QueuedRem *FindNextReminder (void);
static int CalculateNextTimeUsingSched (QueuedRem *q);
static void DaemonWait (struct timeval *sleep_tv);
static void ServerWait (struct timeval *sleep_tv);
static void reread (void);
static void PrintQueue(void);
static char const *QueueFilename(char const *fname);
static void chomp(DynamicBuffer *buf)
{
char *s = DBufValue(buf);
int l = DBufLen(buf);
while (l) {
if (s[l-1] == '\n') {
s[l-1] = 0;
DBufLen(buf)--;
l--;
} else {
break;
}
}
}
char const *SimpleTimeNoSpace(int tim)
{
char *s = (char *) SimpleTime(tim);
if (s && *s) {
size_t l = strlen(s);
if (l > 0 && s[l-1] == ' ') {
s[l-1] = 0;
}
}
return s;
}
/***************************************************************/
/* */
/* QueueFilename */
/* */
/* Add fname to the list of queued filenames if it's not */
/* already present. Either way, return a pointer to the */
/* filename. Returns NULL if out of memory */
/* */
/***************************************************************/
static QueuedFilename *last_file_found = NULL;
static char const *QueueFilename(char const *fname)
{
QueuedFilename *elem = Files;
/* Optimization: We are very likely in the same file as
before... */
if (last_file_found && !strcmp(fname, last_file_found->fname)) {
return last_file_found->fname;
}
/* No such luck; search the list */
while(elem) {
if (!strcmp(elem->fname, fname)) {
last_file_found = elem;
return elem->fname;
}
elem = elem->next;
}
/* Not found... queue it */
elem = NEW(QueuedFilename);
if (!elem) return NULL;
elem->fname = StrDup(fname);
if (!elem->fname) {
free(elem);
return NULL;
}
elem->next = Files;
Files = elem;
last_file_found = elem;
return elem->fname;
}
static void del_reminder(QueuedRem *qid)
{
QueuedRem *q = QueueHead;
QueuedRem *next;
if (!q) {
return;
}
if (q == qid) {
QueueHead = q->next;
if (q->text) free((void *) q->text);
free(q);
return;
}
while(q->next) {
next = q->next;
if (q->next == qid) {
q->next = q->next->next;
if (next->text) free((void *) next->text);
free(next);
return;
}
q = q->next;
}
}
static void del_reminder_ul(unsigned long qid) {
del_reminder((QueuedRem *) qid);
}
/***************************************************************/
/* */
@@ -71,7 +192,7 @@ static void PrintQueue(void);
/* */
/***************************************************************/
int QueueReminder(ParsePtr p, Trigger *trig,
TimeTrig *tim, char const *sched)
TimeTrig *tim, char const *sched)
{
QueuedRem *qelem;
@@ -79,37 +200,99 @@ int QueueReminder(ParsePtr p, Trigger *trig,
trig->noqueue ||
tim->ttime == NO_TIME ||
trig->typ == CAL_TYPE ||
tim->ttime < SystemTime(0) / 60 ||
tim->ttime < MinutesPastMidnight(0) ||
((trig->typ == RUN_TYPE) && RunDisabled)) return OK;
qelem = NEW(QueuedRem);
if (!qelem) {
return E_NO_MEM;
}
qelem->red = DefaultColorR;
qelem->green = DefaultColorG;
qelem->blue = DefaultColorB;
qelem->text = StrDup(p->pos); /* Guaranteed that parser is not nested. */
if (!qelem->text) {
free(qelem);
return E_NO_MEM;
}
qelem->fname = QueueFilename(FileName);
if (!qelem->fname) {
free((void *) qelem->text);
free(qelem);
return E_NO_MEM;
}
qelem->lineno = LineNo;
NumQueued++;
qelem->typ = trig->typ;
strcpy(qelem->passthru, trig->passthru);
qelem->tt = *tim;
qelem->t = *trig;
DBufInit(&(qelem->t.tags));
DBufPuts(&(qelem->t.tags), DBufValue(&(trig->tags)));
if (SynthesizeTags) {
AppendTag(&(qelem->t.tags), SynthesizeTag());
}
qelem->next = QueueHead;
qelem->RunDisabled = RunDisabled;
qelem->ntrig = 0;
strcpy(qelem->sched, sched);
DBufInit(&(qelem->tags));
DBufPuts(&(qelem->tags), DBufValue(&(trig->tags)));
if (SynthesizeTags) {
AppendTag(&(qelem->tags), SynthesizeTag());
}
QueueHead = qelem;
return OK;
}
static void
maybe_close(int fd)
{
int new_fd;
/* Don't close descriptors connected to a TTY, except for stdin */
if (fd && isatty(fd)) return;
(void) close(fd);
if (fd != STDIN_FILENO) {
new_fd = open("/dev/null", O_WRONLY);
} else {
new_fd = open("/dev/null", O_RDONLY);
}
/* If the open failed... well... not much we can do */
if (new_fd < 0) return;
/* If we got back the same fd as what we just closed, aces! */
if (fd == new_fd) return;
(void) dup2(new_fd, fd);
(void) close(new_fd);
}
void
SigContHandler(int d)
{
UNUSED(d);
}
static void
print_num_queued(void)
{
int nqueued = 0;
QueuedRem *q = QueueHead;
while(q) {
if (q->tt.nexttime != NO_TIME) {
nqueued++;
}
q = q->next;
}
if (DaemonJSON) {
printf("{");
PrintJSONKeyPairString("response", "queued");
PrintJSONKeyPairInt("nqueued", nqueued);
printf("\"command\":\"STATUS\"}\n");
} else {
printf("NOTE queued %d\n", nqueued);
}
fflush(stdout);
}
/***************************************************************/
/* */
/* HandleQueuedReminders */
@@ -123,17 +306,20 @@ void HandleQueuedReminders(void)
int TimeToSleep;
unsigned SleepTime;
Parser p;
Trigger trig;
struct timeval tv;
struct timeval sleep_tv;
struct sigaction sa;
/* Suppress the BANNER from being issued */
DidMsgReminder = 1;
char qid[64];
/* Turn off sorting -- otherwise, TriggerReminder has no effect! */
SortByDate = 0;
/* Free FileName if necessary */
if (FileName) {
free(FileName);
FileName = NULL;
}
/* If we are not connected to a tty, then we must close the
* standard file descriptors. This is to prevent someone
* doing:
@@ -143,9 +329,10 @@ void HandleQueuedReminders(void)
* processed correctly are RUN commands, provided they mail
* the result back or use their own resource (as a window).
*/
if (!DontFork && (!isatty(1) || !isatty(2))) {
close(1);
close(2);
if (ShouldFork) {
maybe_close(STDIN_FILENO);
maybe_close(STDOUT_FILENO);
maybe_close(STDERR_FILENO);
}
/* If we're a daemon, get the mod time of initial file */
@@ -160,17 +347,22 @@ void HandleQueuedReminders(void)
/* Initialize the queue - initialize all the entries time of issue */
while (q) {
q->tt.nexttime = (int) (SystemTime(1)/60 - 1);
q->tt.nexttime = MinutesPastMidnight(1) - 1;
q->tt.nexttime = CalculateNextTime(q);
q = q->next;
}
if (!DontFork || Daemon) {
if (ShouldFork || Daemon) {
sa.sa_handler = SigIntHandler;
sa.sa_flags = 0;
(void) sigaction(SIGINT, &sa, NULL);
sa.sa_handler = SigContHandler;
(void) sigaction(SIGCONT, &sa, NULL);
}
#ifdef USE_INOTIFY
watch_fd = setup_inotify_watch();
#endif
/* Sit in a loop, issuing reminders when necessary */
while(1) {
q = FindNextReminder();
@@ -179,7 +371,7 @@ void HandleQueuedReminders(void)
if (!q && !Daemon) break;
if (Daemon && !q) {
if (Daemon < 0) {
if (IsServerMode()) {
/* Sleep until midnight */
TimeToSleep = MINUTES_PER_DAY*60 - SystemTime(1);
} else {
@@ -196,9 +388,7 @@ void HandleQueuedReminders(void)
SleepTime = 60*Daemon;
}
/* Wake up once a minute to recalibrate sleep time in
case of laptop hibernation */
if (Daemon < 0) {
if (IsServerMode()) {
/* Wake up on the next exact minute */
gettimeofday(&tv, NULL);
sleep_tv.tv_sec = 60 - (tv.tv_sec % 60);
@@ -208,7 +398,9 @@ void HandleQueuedReminders(void)
} else {
sleep_tv.tv_usec = 0;
}
DaemonWait(&sleep_tv);
ServerWait(&sleep_tv);
/* A DEL command might have deleted our queued reminder! */
q = FindNextReminder();
} else {
sleep(SleepTime);
}
@@ -222,14 +414,16 @@ void HandleQueuedReminders(void)
if (!Daemon) {
int y, m, d;
if (RealToday != SystemDate(&y, &m, &d)) {
exit(0);
exit(EXIT_SUCCESS);
}
}
if (Daemon > 0 && SleepTime) CheckInitialFile();
if (Daemon > 0 && SleepTime) {
CheckInitialFile();
}
if (Daemon && !q) {
if (Daemon < 0) {
if (IsServerMode()) {
/* Sleep until midnight */
TimeToSleep = MINUTES_PER_DAY*60 - SystemTime(1);
} else {
@@ -244,31 +438,60 @@ void HandleQueuedReminders(void)
/* Do NOT trigger the reminder if tt.nexttime is more than a
minute in the past. This can happen if the clock is
changed or a laptop awakes from hibernation.
However, DO trigger if tt.nexttime == tt.ttime so all
However, DO trigger if tt.nexttime == tt.ttime and we're
within MaxLateTrigger minutes so all
queued reminders are triggered at least once. */
if ((SystemTime(1) - (q->tt.nexttime * 60) <= 60) ||
(q->tt.nexttime == q->tt.ttime)) {
(q->tt.nexttime == q->tt.ttime &&
(MaxLateMinutes == 0 || SystemTime(1) - (q->tt.nexttime * 60) <= 60 * MaxLateMinutes))) {
/* Trigger the reminder */
CreateParser(q->text, &p);
trig.typ = q->typ;
strcpy(trig.passthru, q->passthru);
RunDisabled = q->RunDisabled;
if (Daemon < 0) {
printf("NOTE reminder %s",
SimpleTime(q->tt.ttime));
printf("%s", SimpleTime(SystemTime(1)/60));
if (!*DBufValue(&q->tags)) {
printf("*\n");
} else {
printf("%s\n", DBufValue(&(q->tags)));
}
if (IsServerMode() && q->typ != RUN_TYPE) {
if (DaemonJSON) {
printf("{\"response\":\"reminder\",");
snprintf(qid, sizeof(qid), "%lx", (unsigned long) q);
PrintJSONKeyPairString("qid", qid);
PrintJSONKeyPairString("ttime", SimpleTimeNoSpace(q->tt.ttime));
PrintJSONKeyPairString("now", SimpleTimeNoSpace(MinutesPastMidnight(1)));
PrintJSONKeyPairString("tags", DBufValue(&q->t.tags));
} else {
printf("NOTE reminder %s",
SimpleTime(q->tt.ttime));
printf("%s", SimpleTime(MinutesPastMidnight(1)));
if (!*DBufValue(&q->t.tags)) {
printf("*\n");
} else {
printf("%s\n", DBufValue(&(q->t.tags)));
}
}
}
/* Set up global variables so some functions like trigdate()
and trigtime() work correctly */
SaveAllTriggerInfo(&(q->t), &(q->tt), DSEToday, q->tt.ttime, 1);
(void) TriggerReminder(&p, &trig, &q->tt, DSEToday, 1);
if (Daemon < 0) {
FileName = (char *) q->fname;
DefaultColorR = q->red;
DefaultColorG = q->green;
DefaultColorB = q->blue;
/* Make a COPY of q->t because TriggerReminder can change q->t.typ */
Trigger tcopy = q->t;
if (DaemonJSON) {
DynamicBuffer out;
DBufInit(&out);
(void) TriggerReminder(&p, &tcopy, &q->tt, DSEToday, 1, &out);
if (q->typ != RUN_TYPE) {
printf("\"body\":\"");
chomp(&out);
PrintJSONString(DBufValue(&out));
printf("\"}\n");
}
DBufFree(&out);
} else {
(void) TriggerReminder(&p, &tcopy, &q->tt, DSEToday, 1, NULL);
}
FileName = NULL;
if (IsServerMode() && !DaemonJSON && q->typ != RUN_TYPE) {
printf("NOTE endreminder\n");
}
fflush(stdout);
@@ -277,8 +500,26 @@ void HandleQueuedReminders(void)
/* Calculate the next trigger time */
q->tt.nexttime = CalculateNextTime(q);
if (q->tt.nexttime != NO_TIME) {
/* If trigger time is way in the past because computer has been
suspended or hibernated, remove from queue */
if (q->tt.ttime < MinutesPastMidnight(1) - MaxLateMinutes &&
q->tt.nexttime < MinutesPastMidnight(1) - MaxLateMinutes) {
q->tt.nexttime = NO_TIME;
}
}
/* If queued reminder has expired, actually remove it from queue
and update status */
if (q->tt.nexttime == NO_TIME) {
del_reminder(q);
if (IsServerMode()) {
print_num_queued();
}
}
}
exit(0);
exit(EXIT_SUCCESS);
}
@@ -396,7 +637,23 @@ static void CheckInitialFile(void)
/* If date has rolled around, or file has changed, spawn a new version. */
time_t tim = FileModTime;
int y, m, d;
char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
int n;
#ifdef USE_INOTIFY
/* If there are any inotify events, reread */
if (watch_fd >= 0) {
while(1) {
n = read(watch_fd, buf, sizeof(buf));
if (n < 0 && errno == EINTR) continue;
if (n > 0) {
close(watch_fd);
reread();
}
break;
}
}
#endif
if (stat(InitialFile, &StatBuf) == 0) tim = StatBuf.st_mtime;
if (tim != FileModTime ||
RealToday != SystemDate(&y, &m, &d)) {
@@ -474,7 +731,11 @@ static void
json_queue(QueuedRem const *q)
{
int done = 0;
if (DaemonJSON) {
printf("{\"response\":\"queue\",\"queue\":");
}
printf("[");
char idbuf[64];
while(q) {
if (q->tt.nexttime == NO_TIME) {
q = q->next;
@@ -485,6 +746,14 @@ json_queue(QueuedRem const *q)
}
done = 1;
printf("{");
WriteJSONTrigger(&(q->t), 1, DSEToday);
WriteJSONTimeTrigger(&(q->tt));
snprintf(idbuf, sizeof(idbuf), "%lx", (unsigned long) q);
PrintJSONKeyPairString("qid", idbuf);
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
PrintJSONKeyPairInt("ntrig", q->ntrig);
PrintJSONKeyPairString("filename", q->fname);
PrintJSONKeyPairInt("lineno", q->lineno);
switch(q->typ) {
case NO_TYPE: PrintJSONKeyPairString("type", "NO_TYPE"); break;
case MSG_TYPE: PrintJSONKeyPairString("type", "MSG_TYPE"); break;
@@ -494,29 +763,12 @@ json_queue(QueuedRem const *q)
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;
case PASSTHRU_TYPE:
PrintJSONKeyPairString("type", "PASSTHRU_TYPE");
PrintJSONKeyPairString("passthru", q->passthru);
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("\"");
@@ -530,30 +782,48 @@ json_queue(QueuedRem const *q)
printf("\"}");
q = q->next;
}
printf("]\n");
printf("]");
if (DaemonJSON) {
printf(",\"command\":\"QUEUE\"}\n");
} else {
printf("\n");
}
}
/***************************************************************/
/* */
/* DaemonWait */
/* ServerWait */
/* */
/* Sleep or read command from stdin in "daemon -1" mode */
/* Sleep or read command from stdin in server mode */
/* */
/***************************************************************/
static void DaemonWait(struct timeval *sleep_tv)
static void ServerWait(struct timeval *sleep_tv)
{
fd_set readSet;
int retval;
int y, m, d;
int max = 1;
char cmdLine[256];
FD_ZERO(&readSet);
FD_SET(0, &readSet);
retval = select(1, &readSet, NULL, NULL, sleep_tv);
#ifdef USE_INOTIFY
if (watch_fd >= 0) {
FD_SET(watch_fd, &readSet);
if (watch_fd > max-1)
max = watch_fd+1;
}
#endif
retval = select(max, &readSet, NULL, NULL, sleep_tv);
/* If date has rolled around, restart */
if (RealToday != SystemDate(&y, &m, &d)) {
printf("NOTE newdate\nNOTE reread\n");
if (DaemonJSON) {
printf("{\"response\":\"newdate\"}\n{\"response\":\"reread\",\"command\":\"newdate\"}\n");
} else {
printf("NOTE newdate\nNOTE reread\n");
}
fflush(stdout);
reread();
}
@@ -561,70 +831,108 @@ static void DaemonWait(struct timeval *sleep_tv)
/* If nothing readable or interrupted system call, return */
if (retval <= 0) return;
/* If inotify watch descriptor is readable, handle it */
#ifdef USE_INOTIFY
if (watch_fd >= 0) {
if (FD_ISSET(watch_fd, &readSet)) {
consume_inotify_events(watch_fd);
if (DaemonJSON) {
printf("{\"response\":\"reread\",\"command\":\"inotify\"}\n");
} else {
/* In deprecated server mode, we need to spit out
a NOTE newdate to force the front-end to redraw
the calendar */
printf("NOTE newdate\nNOTE reread\n");
}
fflush(stdout);
reread();
}
}
#endif
/* If stdin not readable, return */
if (!FD_ISSET(0, &readSet)) return;
/* If EOF on stdin, exit */
if (feof(stdin)) {
exit(0);
exit(EXIT_SUCCESS);
}
/* Read a line from stdin and interpret it */
if (!fgets(cmdLine, sizeof(cmdLine), stdin)) {
exit(0);
exit(EXIT_SUCCESS);
}
if (!strcmp(cmdLine, "EXIT\n")) {
exit(0);
exit(EXIT_SUCCESS);
} else if (!strcmp(cmdLine, "STATUS\n")) {
int nqueued = 0;
QueuedRem *q = QueueHead;
while(q) {
if (q->tt.nexttime != NO_TIME) {
nqueued++;
}
q = q->next;
}
printf("NOTE queued %d\n", nqueued);
fflush(stdout);
print_num_queued();
} else if (!strcmp(cmdLine, "QUEUE\n")) {
printf("NOTE queue\n");
QueuedRem *q = QueueHead;
while (q) {
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");
if (DaemonJSON) {
json_queue(QueueHead);
} else {
printf("NOTE queue\n");
QueuedRem *q = QueueHead;
while (q) {
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");
}
q = q->next;
}
q = q->next;
printf("NOTE endqueue\n");
}
printf("NOTE endqueue\n");
fflush(stdout);
} else if (!strcmp(cmdLine, "JSONQUEUE\n")) {
printf("NOTE JSONQUEUE\n");
if (!DaemonJSON) {
printf("NOTE JSONQUEUE\n");
}
json_queue(QueueHead);
printf("NOTE ENDJSONQUEUE\n");
if (!DaemonJSON) {
printf("NOTE ENDJSONQUEUE\n");
}
fflush(stdout);
} else if (!strcmp(cmdLine, "REREAD\n")) {
printf("NOTE reread\n");
if (DaemonJSON) {
printf("{\"response\":\"reread\",\"command\":\"REREAD\"}\n");
} else {
printf("NOTE reread\n");
}
fflush(stdout);
reread();
} else if (!strncmp(cmdLine, "DEL ", 4)) {
unsigned long qid;
if (sscanf(cmdLine, "DEL %lx", &qid) == 1) {
del_reminder_ul(qid);
}
print_num_queued();
fflush(stdout);
} else {
printf("ERR Invalid daemon command: %s", cmdLine);
if (DaemonJSON) {
size_t l = strlen(cmdLine);
if (l && cmdLine[l-1] == '\n') {
cmdLine[l-1] = 0;
}
printf("{\"response\":\"error\",\"error\":\"Unknown command\",\"command\":\"");
PrintJSONString(cmdLine);
printf("\"}\n");
} else {
printf("ERR Invalid daemon command: %s", cmdLine);
}
fflush(stdout);
}
}
@@ -641,3 +949,56 @@ static void reread(void)
execvp(ArgV[0], (char **) ArgV);
}
#ifdef USE_INOTIFY
static void consume_inotify_events(int fd)
{
char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
int n;
struct timespec sleeptime;
int slept = 0;
/* Consume all the inotify events */
while(1) {
n = read(fd, buf, sizeof(buf));
if (n > 0) {
/* Something new since we slept */
slept = 0;
}
if (n < 0) {
if (errno == EINTR) continue;
if (slept) {
/* Nothing new since we slept */
return;
}
slept = 1;
/* HACK: sleep for 0.2 seconds to let multiple events queue up so we
only do a single reread */
sleeptime.tv_sec = 0;
sleeptime.tv_nsec = 200000000;
nanosleep(&sleeptime, NULL);
}
}
}
static int setup_inotify_watch(void)
{
int fd;
/* Don't inotify_watch stdin */
if (!strcmp(InitialFile, "-")) {
return -1;
}
fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (fd < 0) {
return fd;
}
if (inotify_add_watch(fd, InitialFile, IN_CLOSE_WRITE | IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO) < 0) {
close(fd);
return -1;
}
return fd;
}
#endif

View File

@@ -5,7 +5,7 @@
/* Print a PostScript calendar. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -186,19 +186,19 @@ JSONToCalEntry(DynamicBuffer *buf)
val = json_parse(DBufValue(buf), DBufLen(buf));
if (!val) {
fprintf(stderr, "Unable to parse JSON line `%s'\n", DBufValue(buf));
exit(1);
exit(EXIT_FAILURE);
}
if (val->type != json_object) {
fprintf(stderr, "Expecting JSON object; found `%s'\n",
DBufValue(buf));
exit(1);
exit(EXIT_FAILURE);
}
c = NEW(CalEntry);
if (!c) {
fprintf(stderr, "malloc failed - aborting.\n");
exit(1);
exit(EXIT_FAILURE);
}
c->next = NULL;
c->special = SPECIAL_NORMAL;
@@ -221,7 +221,7 @@ JSONToCalEntry(DynamicBuffer *buf)
c->entry = malloc(strlen(s)+1);
if (!c->entry) {
fprintf(stderr, "malloc failed - aborting.\n");
exit(1);
exit(EXIT_FAILURE);
}
strcpy(c->entry, s);
got_body = 1;
@@ -253,7 +253,7 @@ JSONToCalEntry(DynamicBuffer *buf)
if (!got_body || !got_date) {
fprintf(stderr, "Could not parse line `%s'\n", DBufValue(buf));
exit(1);
exit(EXIT_FAILURE);
}
return c;
}
@@ -272,7 +272,7 @@ TextToCalEntry(DynamicBuffer *buf)
CalEntry *c = NEW(CalEntry);
if (!c) {
fprintf(stderr, "malloc failed - aborting.\n");
exit(1);
exit(EXIT_FAILURE);
}
c->next = NULL;
c->special = SPECIAL_NORMAL;
@@ -296,7 +296,7 @@ TextToCalEntry(DynamicBuffer *buf)
c->entry = malloc(strlen(startOfBody) + 1);
if (!c->entry) {
fprintf(stderr, "malloc failed - aborting.\n");
exit(1);
exit(EXIT_FAILURE);
}
strcpy(c->entry, startOfBody);
@@ -343,14 +343,14 @@ int main(int argc, char *argv[])
DBufGets(&buf, stdin);
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);
exit(EXIT_FAILURE);
}
first_line = 0;
if (!strcmp(DBufValue(&buf), PSBEGIN) ||
!strcmp(DBufValue(&buf), PSBEGIN2)) {
if (!validfile) {
if (Verbose) {
fprintf(stderr, "Rem2PS: Version %s Copyright 1992-2023 by Dianne Skoll\n\n", VERSION);
fprintf(stderr, "Rem2PS: Version %s Copyright 1992-2024 by Dianne Skoll\n\n", VERSION);
fprintf(stderr, "Generating PostScript calendar\n");
}
}
@@ -361,7 +361,7 @@ int main(int argc, char *argv[])
if (!validfile) {
fprintf(stderr, "Rem2PS: Couldn't find any calendar data - are you\n");
fprintf(stderr, " sure you fed me input produced by remind -p ...?\n");
exit(1);
exit(EXIT_FAILURE);
}
printf("%%%%Trailer\n");
printf("%%%%Pages: %d\n", validfile);
@@ -486,7 +486,7 @@ void DoPsCal(void)
while(1) {
if (feof(stdin)) {
fprintf(stderr, "Input from REMIND is corrupt!\n");
exit(1);
exit(EXIT_FAILURE);
}
DBufGets(&buf, stdin);
@@ -952,7 +952,7 @@ void Init(int argc, char *argv[])
fprintf(stderr, " WxHin Specify size in inches (W and H are decimal numbers)\n");
fprintf(stderr, " WxHcm Specify size in centimetres (W and H are decimal numbers)\n");
fprintf(stderr, "Default media type is %s\n", DefaultPage[0].name);
exit(1);
exit(EXIT_FAILURE);
}
break;
@@ -1033,7 +1033,7 @@ void Usage(char const *s)
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);
exit(EXIT_FAILURE);
}
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Define the PostScript prologue */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -14,7 +14,7 @@ char *PSProlog1[] =
{
"% This file was produced by Remind and Rem2PS, written by",
"% Dianne Skoll.",
"% Remind and Rem2PS are Copyright 1992-2023 Dianne Skoll.",
"% Remind and Rem2PS are Copyright 1992-2024 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",

View File

@@ -5,7 +5,7 @@
/* Routines for sorting reminders by trigger date */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -136,7 +136,7 @@ void IssueSortedReminders(void)
switch(cur->typ) {
case MSG_TYPE:
if (MsgCommand && *MsgCommand) {
DoMsgCommand(MsgCommand, cur->text);
DoMsgCommand(MsgCommand, cur->text, 0);
} else {
if (cur->trigdate != olddate) {
IssueSortBanner(cur->trigdate);
@@ -151,11 +151,11 @@ void IssueSortedReminders(void)
IssueSortBanner(cur->trigdate);
olddate = cur->trigdate;
}
FillParagraph(cur->text);
FillParagraph(cur->text, NULL);
break;
case RUN_TYPE:
System(cur->text);
System(cur->text, 0);
break;
}

View File

@@ -6,7 +6,7 @@
/* classifying the tokens parsed. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

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-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -72,7 +72,10 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
m++;
if (m == 12) { m = 0; y++; }
}
while (trig->d > DaysInMonth(m, trig->y)) m++;
while (trig->d > DaysInMonth(m, y)) {
m++;
if (m == 12) { m = 0; y++; }
}
j = DSE(y, m, trig->d);
return j;
@@ -241,6 +244,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
case GOT_WD+GOT_MON+GOT_YR:
if (y > trig->y || (y == trig->y && m > trig->m)) return -1;
/* cppcheck-suppress knownConditionTrueFalse */
if (trig->y > y || (trig->y == y && trig->m > m)) {
j = DSE(trig->y, trig->m, 1);
ADVANCE_TO_WD(j, trig->wd);
@@ -324,8 +328,11 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
break;
}
start--;
if (start < 0) {
break;
}
}
if (iter > MaxSatIter) {
if (start < 0 || iter > MaxSatIter) {
/* omitfunc must have returned "true" too often */
*err = E_CANT_TRIG;
return -2;
@@ -388,6 +395,10 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
break;
}
simple--;
if (simple < 0) {
*err = E_CANT_TRIG;
return -2;
}
}
if (iter > MaxSatIter) {
*err = E_CANT_TRIG;

View File

@@ -5,7 +5,7 @@
/* Type definitions all dumped here. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -150,6 +150,7 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
#define DB_DUMP_VARS 8
#define DB_ECHO_LINE 16
#define DB_TRACE_FILES 32
#define DB_EXPR_STACKS 64
/* Enumeration of the tokens */
enum TokTypes

View File

@@ -6,7 +6,7 @@
/* functions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -349,7 +349,9 @@ int CallUserFunc(char const *name, int nargs, ParsePtr p)
/* Skip the opening bracket, if there's one */
while (isempty(*s)) s++;
if (*s == BEG_OF_EXPR) s++;
if (*s == BEG_OF_EXPR) {
s++;
}
push_call(f->filename, f->name, f->lineno);
h = Evaluate(&s, f->locals, p);
if (h == OK) {

View File

@@ -5,7 +5,7 @@
/* Useful utility functions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -36,6 +36,11 @@ char *StrnCpy(char *dest, char const *source, int n)
{
char *odest = dest;
if (n <= 0) {
*dest = 0;
return dest;
}
while (n-- && (*dest++ = *source++)) ;
if (*(dest-1)) *dest = 0;
return odest;
@@ -108,7 +113,7 @@ int DateOK(int y, int m, int d)
m > 11 ||
y > BASE + YR_RANGE ||
d > DaysInMonth(m, y) ) return 0;
else return 1;
return 1;
}
/* Functions designed to defeat gcc optimizer */

View File

@@ -6,7 +6,7 @@
/* user- and system-defined variables. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2023 by Dianne Skoll */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -167,6 +167,13 @@ static int latitude_func(int do_set, Value *val)
return latitude_longitude_func(do_set, val, &Latitude, -90.0, 90.0);
}
static int terminal_bg_func(int do_set, Value *val)
{
UNUSED(do_set);
val->type = INT_TYPE;
val->v.val = GetTerminalBackground();
return OK;
}
static int trig_date_func(int do_set, Value *val)
{
@@ -473,7 +480,7 @@ int DeleteVar(char const *str)
/* Set the indicate variable to the specified value. */
/* */
/***************************************************************/
int SetVar(char const *str, Value *val)
int SetVar(char const *str, Value const *val)
{
Var *v = FindVar(str, 1);
@@ -525,7 +532,9 @@ int DoSet (Parser *p)
int r;
DynamicBuffer buf;
DynamicBuffer buf2;
DBufInit(&buf);
DBufInit(&buf2);
r = ParseIdentifier(p, &buf);
if (r) return r;
@@ -541,6 +550,13 @@ int DoSet (Parser *p)
return r;
}
r = ParseToken(p, &buf2);
if (r) return r;
if (DBufLen(&buf2)) {
DBufFree(&buf2);
return E_EXPECTING_EOL;
}
DBufFree(&buf2);
if (*DBufValue(&buf) == '$') r = SetSysVar(DBufValue(&buf)+1, &v);
else r = SetVar(DBufValue(&buf), &v);
if (buf.len > VAR_NAME_LEN) {
@@ -762,10 +778,14 @@ typedef struct {
char modifiable;
int type;
void *value;
int min;
int min; /* Or const-value */
int max;
} SysVar;
/* Macro to access "min" but as a constval. Just to make source more
readable */
#define constval min
/* If the type of a sys variable is STR_TYPE, then min is redefined
to be a flag indicating whether or not the value has been malloc'd. */
#define been_malloced min
@@ -825,6 +845,9 @@ static SysVar SysVarArr[] = {
{"LongMin", 1, SPECIAL_TYPE, longmin_func, 0, 0 },
{"LongSec", 1, SPECIAL_TYPE, longsec_func, 0, 0 },
{"March", 1, STR_TYPE, &DynamicMonthName[2], 0, 0 },
{"MaxFullOmits", 0, CONST_INT_TYPE, NULL, MAX_FULL_OMITS, 0},
{"MaxLateMinutes", 1, INT_TYPE, &MaxLateMinutes, 0, 1440 },
{"MaxPartialOmits",0, CONST_INT_TYPE, NULL, MAX_PARTIAL_OMITS, 0},
{"MaxSatIter", 1, INT_TYPE, &MaxSatIter, 10, ANY },
{"MaxStringLen", 1, INT_TYPE, &MaxStringLen, -1, ANY },
{"May", 1, STR_TYPE, &DynamicMonthName[4], 0, 0 },
@@ -835,6 +858,8 @@ static SysVar SysVarArr[] = {
{"NextMode", 0, INT_TYPE, &NextMode, 0, 0 },
{"November", 1, STR_TYPE, &DynamicMonthName[10],0, 0 },
{"Now", 1, STR_TYPE, &DynamicNow, 0, 0 },
{"NumFullOmits", 0, INT_TYPE, &NumFullOmits, 0, 0 },
{"NumPartialOmits",0, INT_TYPE, &NumPartialOmits, 0, 0 },
{"NumQueued", 0, INT_TYPE, &NumQueued, 0, 0 },
{"NumTrig", 0, INT_TYPE, &NumTriggered, 0, 0 },
{"October", 1, STR_TYPE, &DynamicMonthName[9], 0, 0 },
@@ -856,7 +881,7 @@ static SysVar SysVarArr[] = {
{"SysInclude", 0, STR_TYPE, &SysDir, 0, 0 },
{"T", 0, SPECIAL_TYPE, trig_date_func, 0, 0 },
{"Td", 0, SPECIAL_TYPE, trig_day_func, 0, 0 },
{"TerminalBackground", 0, INT_TYPE, &TerminalBackground, 0, 0 },
{"TerminalBackground", 0, SPECIAL_TYPE, terminal_bg_func, 0, 0 },
{"Thursday", 1, STR_TYPE, &DynamicDayName[3], 0, 0 },
{"TimeSep", 1, SPECIAL_TYPE, time_sep_func, 0, 0 },
{"Tm", 0, SPECIAL_TYPE, trig_mon_func, 0, 0 },
@@ -894,13 +919,13 @@ int SetSysVar(char const *name, Value *value)
int r;
SysVar *v = FindSysVar(name);
if (!v) return E_NOSUCH_VAR;
if (v->type != SPECIAL_TYPE &&
v->type != value->type) return E_BAD_TYPE;
if (!v->modifiable) {
Eprint("%s: `$%s'", ErrMsg[E_CANT_MODIFY], name);
return E_CANT_MODIFY;
}
if (v->type != SPECIAL_TYPE &&
v->type != value->type) return E_BAD_TYPE;
if (v->type == SPECIAL_TYPE) {
SysVarFunc f = (SysVarFunc) v->value;
r = f(1, value);
@@ -941,6 +966,11 @@ int GetSysVar(char const *name, Value *val)
val->type = ERR_TYPE;
if (!v) return E_NOSUCH_VAR;
if (v->type == CONST_INT_TYPE) {
val->v.val = v->constval;
val->type = INT_TYPE;
return OK;
}
if (v->type == SPECIAL_TYPE) {
SysVarFunc f = (SysVarFunc) v->value;
return f(0, val);
@@ -1034,7 +1064,9 @@ static void DumpSysVar(char const *name, const SysVar *v)
if (name) strcat(buffer, name); else strcat(buffer, v->name);
fprintf(ErrFp, "%16s ", buffer);
if (v) {
if (v->type == SPECIAL_TYPE) {
if (v->type == CONST_INT_TYPE) {
fprintf(ErrFp, "%d\n", v->constval);
} else if (v->type == SPECIAL_TYPE) {
SysVarFunc f = (SysVarFunc) v->value;
f(0, &vtmp);
PrintValue(&vtmp, ErrFp);

View File

@@ -4,7 +4,7 @@ MSG UseVTColors is: [$UseVTColors]%
MSG Use256Colors is: [$Use256Colors]%
MSG UseTrueColors is: [$UseTrueColors]%
MSG UseBGVTColors is: [$UseBGVTColors]%
set n ansicolor("")]
set n ansicolor("")
MSG This is [ansicolor(0,255,0)]green[n], [ansicolor("255 0 0")]red[n] and [ansicolor("0 0 255")]blue[n] text.%
MSG This is [ansicolor(0,0,0)][ansicolor(0,255,0,1)]black text on a green background[n]%
MSG This is [ansicolor(0,0,0,0,1)]clamped black text[n]%

6
tests/queue1.rem Normal file
View File

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

1
tests/queue2.rem Normal file
View File

@@ -0,0 +1 @@
REM at 23:59 PRIORITY 2 MSG XXXX

View File

@@ -7,7 +7,7 @@
# in the build directory.
#
# This file is part of REMIND.
# Copyright (C) 1992-2023 Dianne Skoll
# Copyright (C) 1992-2024 Dianne Skoll
# SPDX-License-Identifier: GPL-2.0-only
# ---------------------------------------------------------------------------
@@ -31,6 +31,15 @@ fi
TZ=UTC
export TZ
RESULT=`(echo 'BANNER %'; echo 'IF now() > 23:55'; echo 'MSG late%'; echo 'ENDIF') | ../src/remind -h -`
if test "$RESULT" = "late" ; then
echo ""
echo "*** Please do not run the test suite between 23:55 and 00:00 UTC; it will fail."
echo ""
exit 1
fi
# If we're already in a utf-8 locale, do
# nothing; otherwise, set LC_ALL
OK=0
@@ -56,6 +65,8 @@ echo "Test 1" > ../tests/test.out
echo "" >> ../tests/test.out
../src/remind -e -dxte ../tests/test.rem 16 feb 1991 12:13 >> ../tests/test.out 2>&1
echo "" >> ../tests/test.out
echo 'set a 1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+2*3))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))' | ../src/remind -ds - 16 feb 1991 12:13 >> ../tests/test.out 2>&1
echo "" >> ../tests/test.out
echo "Test 2" >> ../tests/test.out
echo "" >> ../tests/test.out
../src/remind -p -l ../tests/test2.rem 1 aug 2007 >> ../tests/test.out 2>&1
@@ -437,6 +448,99 @@ rm -rf include_dir/ww
# This segfaulted in 04.02.03
../src/remind -h '-imsgprefix(x)="foo"' /dev/null >> ../tests/test.out 2>&1
# Test --version long option
../src/remind --version >> ../tests/test.out 2>&1
# Test queueing. Because eventstart depends on the actual system
# date, we have to convert it to some constant (in this case,
# VOLATILE) so that tests are not dependent on the system date.
echo JSONQUEUE | ../src/remind -z0 ../tests/queue1.rem 2>&1 | sed -e 's/"eventstart":"................"/"eventstart":"VOLATILE"/g' | sed -e 's/"qid":"[0-9a-f]*",//g' >> ../tests/test.out 2>&1
echo QUEUE | ../src/remind -zj ../tests/queue1.rem 2>&1 | sed -e 's/"eventstart":"................"/"eventstart":"VOLATILE"/g' | sed -e 's/"qid":"[0-9a-f]*",//g' >> ../tests/test.out 2>&1
# Test for leap year bug that was fixed
../src/remind -dte - 28 Feb 2024 <<'EOF' >> ../tests/test.out 2>&1
BANNER %
REM 29 MSG One
REM 29 Feb MSG two
REM 29 2024 MSG three
REM 29 Feb 2024 MSG four
REM Thursday 29 MSG One
REM Thursday 29 Feb MSG two
REM Thursday 29 2024 MSG three
REM Thursday 29 Feb 2024 MSG four
REM Wednesday 29 MSG One
REM Wednesday 29 Feb MSG two
REM Wednesday 29 2024 MSG three
REM Wednesday 29 Feb 2024 MSG four
REM Friday 29 MSG One
REM Friday 29 Feb MSG two
REM Friday 29 2024 MSG three
REM Friday 29 Feb 2024 MSG four
EOF
../src/remind -dte - 1 Mar 2024 <<'EOF' >> ../tests/test.out 2>&1
BANNER %
REM 29 MSG One
REM 29 Feb MSG two
REM 29 2024 MSG three
REM 29 Feb 2024 MSG four
REM Thursday 29 MSG One
REM Thursday 29 Feb MSG two
REM Thursday 29 2024 MSG three
REM Thursday 29 Feb 2024 MSG four
REM Wednesday 29 MSG One
REM Wednesday 29 Feb MSG two
REM Wednesday 29 2024 MSG three
REM Wednesday 29 Feb 2024 MSG four
REM Friday 29 MSG One
REM Friday 29 Feb MSG two
REM Friday 29 2024 MSG three
REM Friday 29 Feb 2024 MSG four
EOF
../src/remind -dte - 28 Feb 2025 <<'EOF' >> ../tests/test.out 2>&1
BANNER %
REM 29 MSG One
REM 29 Feb MSG two
REM 29 2025 MSG three
REM 29 Feb 2025 MSG four
REM Thursday 29 MSG One
REM Thursday 29 Feb MSG two
REM Thursday 29 2025 MSG three
REM Thursday 29 Feb 2025 MSG four
REM Wednesday 29 MSG One
REM Wednesday 29 Feb MSG two
REM Wednesday 29 2025 MSG three
REM Wednesday 29 Feb 2025 MSG four
REM Friday 29 MSG One
REM Friday 29 Feb MSG two
REM Friday 29 2025 MSG three
REM Friday 29 Feb 2025 MSG four
EOF
../src/remind -dte - 1 Mar 2025 <<'EOF' >> ../tests/test.out 2>&1
BANNER %
REM 29 MSG One
REM 29 Feb MSG two
REM 29 2025 MSG three
REM 29 Feb 2025 MSG four
REM Thursday 29 MSG One
REM Thursday 29 Feb MSG two
REM Thursday 29 2025 MSG three
REM Thursday 29 Feb 2025 MSG four
REM Wednesday 29 MSG One
REM Wednesday 29 Feb MSG two
REM Wednesday 29 2025 MSG three
REM Wednesday 29 Feb 2025 MSG four
REM Friday 29 MSG One
REM Friday 29 Feb MSG two
REM Friday 29 2025 MSG three
REM Friday 29 Feb 2025 MSG four
EOF
(echo 'BANNER %'; echo 'REM 29 MSG No bug') | ../src/remind -dt - 29 Feb 2024 >> ../tests/test.out 2>&1
# Remove references to SysInclude, which is build-specific
grep -F -v '$SysInclude' < ../tests/test.out > ../tests/test.out.1 && mv -f ../tests/test.out.1 ../tests/test.out
cmp -s ../tests/test.out ../tests/test.cmp

File diff suppressed because one or more lines are too long

View File

@@ -381,9 +381,11 @@ msg [a076]%
set a077 dosubst("%*Y %*Z", '1992/5/5')
msg [a077]%
set a078 easterdate(today())
set a078 easterdate()
set a079 easterdate(1992)
set a080 easterdate(1995)
set a078 orthodoxeaster(today())
set a078 orthodoxeaster()
set a079 orthodoxeaster(1992)
set a080 orthodoxeaster(1995)
set a080 orthodoxeaster(2023)
@@ -782,6 +784,15 @@ ENDIF
REM [trig("Mon", "Tue", "Wed", "Sat")] MSG foo
REM [trig("Mon", "Tue", "Wed")] MSG bar
# Multitrig
REM [multitrig("10", "17")] MSG multitrig-1
REM [multitrig("Feb 15", "Mar 20")] MSG multitrig-2
REM [multitrig("Oct 7 1992", "1991")] MSG multitrig-3
REM [multitrig("16 Feb AFTER OMIT Sat Sun", "29 March")] MSG multitrig-4
REM [multitrig("2", "3", "5", "7")] MSG multitrig-5
REM [multitrig("15 SCANFROM -7", "14 SCANFROM -7")] MSG multitrig-6
REM [multitrig("15 SCANFROM -7", "14 SCANFROM -7")] SCANFROM -7 MSG multitrig-7
# The new syntactic sugar
REM First Monday January MSG x
REM Second Tuesday in April MSG x
@@ -882,11 +893,38 @@ set a htmlstriptags("this is > whut <b>foo</b>")
set a htmlstriptags("<img src=\"foo\">")
# $ParseUntriggered
REM 2 Jan 1990 MSG ["bad_expr" * 2]
REM 2 Jan 1990 MSG ["bad_expr" / 2]
SET $ParseUntriggered 0
REM 2 Jan 1990 MSG ["bad_expr" * 2]
REM 2 Jan 1990 MSG ["bad_expr" / 2]
SET $ParseUntriggered 1
# String multiplication
set a "low" * (-1)
set a (-1) * "low"
set a "zero" * 0
set a 0 * "zero"
set a "" * 10000000
set a 10000000 * ""
# Too long for default limits
set a "wookie" * 1000000
set a 1000000 * "wookie"
set a "Cabbage! " * 7
set a 7 * "Cabbage! "
# Should result in errors
set pqxya 1+2)
# Should result in an error
REM Tue OMIT 2024-01-01 MSG Wookie
# No error
REM Tue OMIT Wed 2024-01-01 MSG Blort
# Don't want Remind to queue reminders
EXIT

View File

@@ -11,7 +11,7 @@
# Use the output to verify your translations.
#
# This file is part of REMIND.
# Copyright (C) 1992-2023 Dianne Skoll
# Copyright (C) 1992-2024 Dianne Skoll
# SPDX-License-Identifier: GPL-2.0-only
#
# ---------------------------------------------------------------------------

View File

@@ -12,10 +12,10 @@ CGIDIR = /cgi-bin
# The complete path to the directory containing the HTML file "calendar.html".
# This is a sample file containing links to all the scripts. This path
# should be the path as seen by the UNIX operating system
HTMLDIR = /var/www/remind
HTMLDIR = /var/www/html/remind
# Where you stick images and CSS files, as seen by UNIX
IMAGEDIR = /var/www/remind/resources
IMAGEDIR = /var/www/html/remind/resources
# Where images and CSS files are, as seen by web browsers
IMAGEBASE = /remind/resources
@@ -32,6 +32,7 @@ datarootdir=@datarootdir@
# Where do Remind and Rem2PS executables live?
REMIND = $(bindir)/remind
REM2PS = $(bindir)/rem2ps
REM2PDF = $(bindir)/rem2pdf
REM2HTML = $(bindir)/rem2html
# If your Web server requires CGI programs to have a .cgi suffix, use
# the next line. Otherwise, comment it out
@@ -46,6 +47,7 @@ SEDSCRIPT = -e 's@%CGIDIR%@$(CGIDIR)@g' \
-e 's@%REMIND%@$(REMIND)@g' \
-e 's@%IMAGEBASE%@$(IMAGEBASE)@g' \
-e 's@%REM2PS%@$(REM2PS)@g' \
-e 's@%REM2PDF%@$(REM2PDF)@g' \
-e 's@%REM2HTML%@$(REM2HTML)@g' \
-e 's@cal_dispatch@cal_dispatch$(CGISUFFIX)@g' \
@@ -57,7 +59,8 @@ all:
install:
-mkdir -p $(DESTDIR)$(SCRIPTDIR)
-mkdir -p $(DESTDIR)$(HTMLDIR)
cp calps hebdate hebps hebhtml moon sunrise sunset $(DESTDIR)$(SCRIPTDIR)
cp calps calpdf hebps hebpdf hebhtml moon sunrise sunset $(DESTDIR)$(SCRIPTDIR)
sed $(SEDSCRIPT) < hebdate > $(DESTDIR)$(SCRIPTDIR)/hebdate
sed $(SEDSCRIPT) < cal_dispatch-DIST > $(DESTDIR)$(SCRIPTDIR)/cal_dispatch$(CGISUFFIX)
sed $(SEDSCRIPT) < hebdate.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/hebdate.rem
sed $(SEDSCRIPT) < moon.rem-DIST > $(DESTDIR)$(SCRIPTDIR)/moon.rem
@@ -73,14 +76,14 @@ install:
chmod 644 $(DESTDIR)$(SCRIPTDIR)/blank.rem
chmod 644 $(DESTDIR)$(HTMLDIR)/calendar.html
chmod 755 $(DESTDIR)$(SCRIPTDIR)/cal_dispatch$(CGISUFFIX)
chmod 755 $(DESTDIR)$(SCRIPTDIR)/calps $(DESTDIR)$(SCRIPTDIR)/hebdate \
$(DESTDIR)$(SCRIPTDIR)/hebps $(DESTDIR)$(SCRIPTDIR)/moon \
chmod 755 $(DESTDIR)$(SCRIPTDIR)/calpdf $(DESTDIR)$(SCRIPTDIR)/calps $(DESTDIR)$(SCRIPTDIR)/hebdate \
$(DESTDIR)$(SCRIPTDIR)/hebps $(DESTDIR)$(SCRIPTDIR)/hebpdf $(DESTDIR)$(SCRIPTDIR)/moon \
$(DESTDIR)$(SCRIPTDIR)/sunrise $(DESTDIR)$(SCRIPTDIR)/sunset \
$(DESTDIR)$(SCRIPTDIR)/hebhtml \
-mkdir -p $(DESTDIR)$(IMAGEDIR)
cp rem-default.css *.png $(DESTDIR)$(IMAGEDIR)
chmod 644 $(DESTDIR)$(IMAGEDIR)/rem-default.css $(DESTDIR)$(IMAGEDIR)/*.png
cp calendar.css rem-default.css *.png $(DESTDIR)$(IMAGEDIR)
chmod 644 $(DESTDIR)$(IMAGEDIR)/calendar.css $(DESTDIR)$(IMAGEDIR)/rem-default.css $(DESTDIR)$(IMAGEDIR)/*.png

View File

@@ -28,6 +28,10 @@ export REMIND
REM2PS=%REM2PS%
export REM2PS
# Set REM2PDF to the full pathname of the rem2pdf executable
REM2PDF=%REM2PDF%
export REM2PDF
#########################
#
# Don't change anything after this.
@@ -56,6 +60,10 @@ case "$1" in
exec $DIR/calps
;;
calpdf)
exec $DIR/calpdf
;;
moon)
exec $DIR/moon
;;
@@ -64,6 +72,10 @@ case "$1" in
exec $DIR/hebps
;;
hebpdf)
exec $DIR/hebpdf
;;
hebhtml)
if [ "$2" = "" -o "$3" = "" ] ; then
exec $DIR/hebhtml

41
www/calendar.css Normal file
View File

@@ -0,0 +1,41 @@
html, body {
padding: 0px;
margin-left: 10px;
margin-right: 10px;
font-family: "Open Sans", Arial, sans-serif
background: #FFFFFF;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 5px;
margin-bottom: 5px;
padding-top: 0px;
padding-bottom: 0px;
font-family: inherit;
font-weight: 600;
}
h1, .h1 {
font-size: 1.75rem; }
h2, .h2 {
font-size: 1.5rem; }
h3, .h3 {
font-size: 1.25rem; }
a {
text-decoration: none;
color: #1a0dab;
}
a:visited {
text-decoration: none;
color: #1a0dab;
}
a:hover {
text-decoration: none;
color: #ff0000;
}

View File

@@ -1,7 +1,8 @@
<HTML>
<!-- Sample HTML file with links to the calendar stuff -->
<HEAD>
<TITLE>Remind Calendar Server</TITLE>
<TITLE>Remind Calendar Server</TITLE>
<LINK rel="stylesheet" href="%IMAGEBASE%/calendar.css">
</HEAD>
<BODY>
@@ -15,10 +16,14 @@ Sunset Information</a><P>
Moon Phase Information</a><P>
<a HREF="%CGIDIR%/cal_dispatch?calps">
Blank PostScript Calendar</a> (Approximately 20kB)<P>
<a HREF="%CGIDIR%/cal_dispatch?calpdf">
Blank PDF Calendar</a> (Approximately 15kB)<P>
<a HREF="%CGIDIR%/cal_dispatch?hebdate">
Today's Hebrew Date</a><P>
<a HREF="%CGIDIR%/cal_dispatch?hebps">
PostScript Calendar with Jewish Holidays</a> (Approximately 35 kB)<P>
<a HREF="%CGIDIR%/cal_dispatch?hebpdf">
PDF Calendar with Jewish Holidays</a> (Approximately 20 kB)<P>
<a HREF="%CGIDIR%/cal_dispatch?hebhtml">
HTML Calendar with Jewish Holidays</a>
<HR>

11
www/calpdf Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
# PostScript calendar shell script
#
# This file is part of REMIND.
# Copyright (C) 1992-2018 by Dianne Skoll
echo "Content-type: application/pdf"
echo
$REMIND -p $DIR/blank.rem | $REM2PDF -e -c3 -l
exit 0

View File

@@ -11,6 +11,7 @@ cat <<EOM
<HTML>
<HEAD>
<TITLE>Hebrew date</TITLE>
<LINK rel="stylesheet" href="%IMAGEBASE%/calendar.css">
</HEAD>
<BODY>

Some files were not shown because too many files have changed in this diff Show More