Compare commits

...

230 Commits

Author SHA1 Message Date
Dianne Skoll
15a778075d Update whatsnew. 2022-01-30 14:36:07 -05:00
Dianne Skoll
2502191982 Fix up display_len vs len 2022-01-30 14:22:52 -05:00
Dianne Skoll
47af91d136 Fix PrintCentered. 2022-01-30 14:19:36 -05:00
Dianne Skoll
e249fe3a17 Bump version to 03.04.00. 2022-01-30 14:03:48 -05:00
Dianne Skoll
72838a07f3 Make rem2pdf take a -v option. 2022-01-30 14:02:34 -05:00
Dianne Skoll
c098acc659 Update man pages. 2022-01-30 13:58:33 -05:00
Dianne Skoll
15ee32b5bd Update rem2ps man page. 2022-01-30 13:43:36 -05:00
Dianne Skoll
5a059d9b09 Missed one 2022-01-30 12:35:05 -05:00
Dianne Skoll
77516dbdff Remove a few more files in "make distclean" 2022-01-30 12:34:36 -05:00
Dianne Skoll
835af9ad6a Fix various UTF-8 handling bugs; properly re-space month and day names. 2022-01-30 12:31:38 -05:00
Dianne Skoll
4c30db06c0 Allow spaces in month and day names 2022-01-30 12:02:08 -05:00
Dianne Skoll
3aee12073e Start allowing spaces in month and day names (convert to _ on -p output) 2022-01-30 12:00:57 -05:00
Dianne Skoll
654fd78ee7 Replace spaces in day names with '_' 2022-01-30 11:54:13 -05:00
Dianne Skoll
b8126d3a85 Add POD to Entry.pm 2022-01-30 11:06:50 -05:00
Dianne Skoll
3054091688 Add POD to PDF.pm 2022-01-30 11:00:36 -05:00
Dianne Skoll
6e0fd7ea5f Fix manpage cross-references. 2022-01-30 10:13:10 -05:00
Dianne Skoll
bbb82029d2 Make TkRemind support PDF output iff rem2pdf is installed. 2022-01-29 23:02:06 -05:00
Dianne Skoll
716d7bcc92 Tweak test file. 2022-01-29 22:29:34 -05:00
Dianne Skoll
e7a6bf0e19 Avoid "wide char" error. 2022-01-29 22:29:28 -05:00
Dianne Skoll
27c17252e7 Tweak 2022-01-29 22:23:43 -05:00
Dianne Skoll
940254bec6 Add another feature demo 2022-01-29 22:23:16 -05:00
Dianne Skoll
79952d52f1 Add note about invalid markup 2022-01-29 22:22:09 -05:00
Dianne Skoll
e58545d3f6 Finish rem2pdf man page. 2022-01-29 22:20:01 -05:00
Dianne Skoll
b7c9643a05 Also handle -ppp output. 2022-01-29 21:32:44 -05:00
Dianne Skoll
c2be6c348a Fix incorrect logic. 2022-01-29 21:30:32 -05:00
Dianne Skoll
0161f81389 Support old-style -p format as well. 2022-01-29 16:03:56 -05:00
Dianne Skoll
2a2df322dc More consistent error messages. 2022-01-28 18:30:01 -05:00
Dianne Skoll
b276b5fdce Start on man page. 2022-01-28 17:11:28 -05:00
Dianne Skoll
b5f7dabf10 Set default paper size correctly. 2022-01-28 16:42:58 -05:00
Dianne Skoll
307f8a07e0 Don't bother doing work if we set a system variable to the same as existing. 2022-01-28 13:14:14 -05:00
Dianne Skoll
3fe5e2becd More pango test tweaks. 2022-01-28 12:09:47 -05:00
Dianne Skoll
e8a4acf517 Fix height calculation. 2022-01-28 11:51:26 -05:00
Dianne Skoll
9ba28c01e7 Tweak test file to exercise dayname display. 2022-01-28 11:33:58 -05:00
Dianne Skoll
ff3b04f46d Add --help; properly grab first char of day name 2022-01-28 11:25:58 -05:00
Dianne Skoll
9f6f452b18 Don't make rem2pdf.in executable 2022-01-28 11:20:00 -05:00
Dianne Skoll
9b4e35841e Make rem2pdf executable 2022-01-28 11:16:36 -05:00
Dianne Skoll
927e260f5b Generate rem2pdf/bin/rem2pdf so we can embed VERSION 2022-01-28 11:15:07 -05:00
Dianne Skoll
949156f77c Add usage() 2022-01-28 10:40:56 -05:00
Dianne Skoll
cc59fcac58 Fix edge-case with small calendar placement. 2022-01-27 21:51:15 -05:00
Dianne Skoll
db624d8a8a Better error messages. 2022-01-27 21:41:12 -05:00
Dianne Skoll
ae90243352 Don't emit bogus PDF if there's an input error. 2022-01-27 21:37:33 -05:00
Dianne Skoll
ff58c7f699 Don't rebuild Makefile from Makefile.PL unnecessarily 2022-01-27 21:32:36 -05:00
Dianne Skoll
bd9738f6f4 Update test file. 2022-01-27 20:17:13 -05:00
Dianne Skoll
47e5c63290 Obey --small-cal-font option 2022-01-27 18:47:25 -05:00
Dianne Skoll
2abdcac15c Fix scaling of small calendars 2022-01-27 18:46:16 -05:00
Dianne Skoll
f0f12e4099 Refuse to read from a tty 2022-01-27 18:01:22 -05:00
Dianne Skoll
b1720317a4 Revert accidental deletion of lines from .gitignore. 2022-01-27 17:57:28 -05:00
Dianne Skoll
d90f466b53 Proper installation; 2022-01-27 17:56:33 -05:00
Dianne Skoll
fec84a5efc Ignore a generated file. 2022-01-27 17:47:26 -05:00
Dianne Skoll
1f3f869983 Fix up class names 2022-01-27 17:47:06 -05:00
Dianne Skoll
a6bd6f44bf Remove unneeded file. 2022-01-27 17:44:45 -05:00
Dianne Skoll
78aac61fe1 Ignore generated file 2022-01-27 17:42:50 -05:00
Dianne Skoll
8d735f0410 Build/install rem2pdf if prereqs are present 2022-01-27 17:42:22 -05:00
Dianne Skoll
de014732c6 Add more stuff to the script-testing. 2022-01-27 17:22:23 -05:00
Dianne Skoll
aae6511394 More-or-less working version of rem2pdf 2022-01-27 17:10:06 -05:00
Dianne Skoll
d973439b4f More pango-ization. 2022-01-27 15:12:24 -05:00
Dianne Skoll
32adce2de8 Support Pango markup with PANGO special. 2022-01-27 13:29:20 -05:00
Dianne Skoll
2ac6378fea More work on PDF rendering. 2022-01-27 12:41:24 -05:00
Dianne Skoll
153b7df5fc Get moons working. 2022-01-27 11:39:33 -05:00
Dianne Skoll
9d9bdabf79 More work 2022-01-27 10:23:30 -05:00
Dianne Skoll
2f8eaeacf0 More updates. 2022-01-27 09:18:41 -05:00
Dianne Skoll
dc07a3cf32 More work on Pango-ized rem2pdf 2022-01-26 21:11:48 -05:00
Dianne Skoll
b775e60d1b Start on rem2pdf via Cairo/Pango 2022-01-26 20:59:27 -05:00
Dianne Skoll
7290bccfd7 Start working on Remind -> PDF converter using Pango and Cairo 2022-01-26 16:38:49 -05:00
Dianne Skoll
a1d884ec3f Convert finnish.h and german.h to UTF-8 2022-01-26 10:16:23 -05:00
Dianne Skoll
cc05d88618 Convert danish.h to UTF-8 2022-01-26 10:09:48 -05:00
Dianne Skoll
2675fa53df Convert norwgian.h to UTF-8 2022-01-26 10:07:35 -05:00
Dianne Skoll
59ee9198e2 Convert polish.h to UTF-8 2022-01-26 10:01:05 -05:00
Dianne Skoll
5235936e7b Convert French file to UTF-8 2022-01-26 09:49:42 -05:00
Dianne Skoll
03ab44ea10 Don't allow $MonthName or $DayName system variables to be set to a value containing a space. 2022-01-25 22:35:21 -05:00
Dianne Skoll
b8c2d2b39b Bail if argv[0] == NULL. 2022-01-25 22:21:20 -05:00
Dianne Skoll
6ae7e71fbf Document the alternate %*-form of substitutions 2022-01-25 22:13:11 -05:00
Dianne Skoll
c49740ed81 Remove support for character sets other than UTF-8. 2022-01-25 22:08:20 -05:00
Dianne Skoll
16c0a819a9 Fix to language code. 2022-01-25 22:03:34 -05:00
Dianne Skoll
4a61fe73de Convert Italian to UTF-8 2022-01-25 21:55:13 -05:00
Dianne Skoll
a76feebe45 Convert languages to UTF-8 2022-01-25 21:52:09 -05:00
Dianne Skoll
3a52eadeb1 Handle custom day names in calendars. 2022-01-25 21:34:11 -05:00
Dianne Skoll
dd56b7c385 Add system variables for dynamically changing day and month names. 2022-01-25 19:18:59 -05:00
Dianne Skoll
f6f201085c Start adding support for dynamic month and day names. 2022-01-25 18:47:25 -05:00
Dianne Skoll
daf09d9d4e Fix doc bug. 2022-01-24 17:49:00 -05:00
Dianne Skoll
511cdb2784 Document changes to dynamic buffers. 2022-01-24 10:23:49 -05:00
Dianne Skoll
a567a9b777 Document that strlen() can return E_2HIGH 2022-01-22 18:42:11 -05:00
Dianne Skoll
05bc3af03d Use size_t rather than int to track dynamic buffer size.
This lets use create dynamic buffers larger than 2GB.
2022-01-22 18:40:27 -05:00
Dianne Skoll
7a048d1702 Document update to shell() 2022-01-22 18:26:22 -05:00
Dianne Skoll
8d7f9bcb8b Make shell() obey MaxStringLen 2022-01-22 18:24:38 -05:00
Dianne Skoll
9fd8b0f890 Update change to rem2html 2022-01-22 18:11:50 -05:00
Dianne Skoll
86873d0725 Use JSON::MaybeXS instead of JSON (courtesy of Ethan Rooke) 2022-01-22 18:09:02 -05:00
Dianne Skoll
b22438b489 Bump version to 03.03.12. 2022-01-22 09:21:02 -05:00
Dianne Skoll
683b38a7ab 3.3.12 will go out in 2022, not 2021. 2022-01-22 09:19:14 -05:00
Dianne Skoll
d6b4fdd6d3 Always clean up. 2022-01-20 20:10:39 -05:00
Dianne Skoll
c996649954 Update docs. 2022-01-20 19:52:29 -05:00
Dianne Skoll
d59ad77893 Document DO better. 2022-01-20 19:48:49 -05:00
Dianne Skoll
e637c20dee Don't try to do filedir() shenanigans for "DO /absolute/path" 2022-01-20 19:47:04 -05:00
Dianne Skoll
19dc588319 Update regression test file 2022-01-20 19:39:26 -05:00
Dianne Skoll
dc53ef2e71 Document DO 2022-01-20 19:39:12 -05:00
Dianne Skoll
e51d7f3c6d Add "DO file" command which is equivalent to "INCLUDE [filedir()]/file" 2022-01-20 19:30:10 -05:00
Dianne Skoll
5a7e86e443 Update WHATSNEW 2022-01-20 12:41:58 -05:00
Dianne Skoll
7f4edae006 Update test output comparison file. 2022-01-20 09:53:08 -05:00
Dianne Skoll
2f4e1462e3 Document -tt[N] and $DefaultTDelta 2022-01-20 09:52:57 -05:00
Dianne Skoll
54f5d81a8c Properly check for repeated tdelta 2022-01-20 09:52:46 -05:00
Dianne Skoll
d33c27289a Implement $DefaultTDelta system variable and -tt[N] command-line option. 2022-01-20 09:44:17 -05:00
Dianne Skoll
1675fdb499 Keep config file in $XDG_CONFIG_HOME/tkremindrc in preference to ~/.tkremindrc 2021-12-31 16:16:16 -05:00
Dianne Skoll
9321109691 Remove code that annoyed people on Windows or Mac OS X.
I think I've made my point, and the MICROSOFT-AND-APPLE file still exists.
2021-12-31 15:33:43 -05:00
Dianne Skoll
e6a4f939a3 Add brackets. 2021-12-29 20:51:01 -05:00
Dianne Skoll
c7ae214853 Remove comment. 2021-12-29 20:44:46 -05:00
Dianne Skoll
68a9cc047e Add tests for deprecation messages. 2021-12-29 10:42:30 -05:00
Dianne Skoll
1f2b25f852 Write options to a temporary file and then rename 2021-12-28 21:14:33 -05:00
Dianne Skoll
20040c8857 Update WHATSNEW 2021-12-28 21:05:13 -05:00
Dianne Skoll
ac64b0c11f Fix option descriptor. 2021-12-28 21:03:30 -05:00
Dianne Skoll
ba47ce7ca8 Make TkRemind remember printer settings. 2021-12-28 21:02:33 -05:00
Dianne Skoll
be1ab4ea36 Properly support '-i$Latitude="x.yyy"' 2021-12-28 17:56:31 -05:00
Dianne Skoll
13cd9f3d04 Fix memory leak. 2021-12-28 17:53:41 -05:00
Dianne Skoll
8e1f82de5f Get rid of _back function definition (not needed) 2021-12-28 16:59:19 -05:00
Dianne Skoll
8631ad3122 Sort function names alphabetically. 2021-12-28 15:31:03 -05:00
Dianne Skoll
90e6aef9d7 Set default location in custom.h 2021-12-28 15:26:59 -05:00
Dianne Skoll
698190fb72 Set default location right on Parliament Hill. 2021-12-28 15:25:32 -05:00
Dianne Skoll
27cfaa9404 Refactor common code in setting latitude/longitude vars 2021-12-28 14:02:07 -05:00
Dianne Skoll
9f296fe76d Update docs 2021-12-28 10:47:21 -05:00
Dianne Skoll
d0112adb08 Sleep with higher precision in -z0 mode. 2021-12-28 10:32:06 -05:00
Dianne Skoll
75f4fe3595 Update docs. 2021-12-27 15:47:42 -05:00
Dianne Skoll
211bfbc1e2 Bump version to 03.03.11 2021-12-27 15:42:19 -05:00
Dianne Skoll
afaa1841fc Add deprecation notice in verbose mode. 2021-12-27 15:37:32 -05:00
Dianne Skoll
027662c9c3 Add "DUMP $" to test. 2021-12-27 15:28:30 -05:00
Dianne Skoll
43e652321b Document $Latitude and $Longitude system variables. 2021-12-27 15:20:42 -05:00
Dianne Skoll
83a2216d19 Add $Latitude and $Longitude system variables. 2021-12-27 15:08:12 -05:00
Dianne Skoll
82ae568add Make underline the same color as text in TkRemind. 2021-12-27 11:53:02 -05:00
Dianne Skoll
2573003034 Modernize examples 2021-12-27 11:28:51 -05:00
Dianne Skoll
c33e873577 Add balloon help to moon windows 2021-12-26 13:08:49 -05:00
Dianne Skoll
a1d03b8159 Make moon icons respond to mouse clicks to edit reminders. 2021-12-26 13:04:35 -05:00
Dianne Skoll
762530f6ab Document underlining of editable reminders 2021-12-26 12:20:53 -05:00
Dianne Skoll
f53a3ecc69 Underline editable reminders when we enter them. 2021-12-26 12:19:05 -05:00
Dianne Skoll
1ed60fecee Make moon messages right-clickable. 2021-12-26 11:59:59 -05:00
Dianne Skoll
c1a12ea4e9 Don't outline the arcs used to make first/last quarter. 2021-12-25 18:27:56 -05:00
Dianne Skoll
0efd235e36 Use Tk oval and arc items to draw moons rather than PNG images.
This makes the moon images work even if the text and window colors
have been changed.
2021-12-25 17:27:50 -05:00
Dianne Skoll
c7be8c59f3 Redirect inotifywait's stdin and stderr from/to /dev/null 2021-12-22 10:15:34 -05:00
Dianne Skoll
20bb3eb674 Pass '-r' flag to inotifywait 2021-12-22 10:11:21 -05:00
Dianne Skoll
cde0e5883e Rename "any" to "isany" 2021-12-20 17:32:14 -05:00
Dianne Skoll
0b43099621 Coalesce all of the CSS for table.rem-cal into one block
Reported by Ian! D. Allen
2021-12-15 12:05:53 -05:00
Dianne Skoll
386f36c3ae Add class names indicating number of rows. 2021-12-14 10:53:01 -05:00
Dianne Skoll
b391b2129e More explanation of any 2021-12-07 11:57:14 -05:00
Dianne Skoll
5478673bda Add an example that uses "any" 2021-12-07 09:58:51 -05:00
Dianne Skoll
6295048b3e Add the "any" built-in function. 2021-12-07 09:28:49 -05:00
Dianne Skoll
4fa956aa27 Show queue in sorted order 2021-12-02 11:17:48 -05:00
Dianne Skoll
21cce0e104 Update WHATSNEW 2021-11-30 09:37:04 -05:00
Dianne Skoll
b14e72ddf7 Cosmetic tweaks 2021-11-28 20:32:30 -05:00
Dianne Skoll
7a34b6e18d Better arrowheads 2021-11-28 20:31:42 -05:00
Dianne Skoll
ddc0e8eb45 Use Unicode arrows instead of PNGs; make buttons follow global color scheme. 2021-11-28 20:23:50 -05:00
Dianne Skoll
7648ee6e54 Make queued and status windows obey window color 2021-11-22 14:39:29 -05:00
Dianne Skoll
2b86c912e3 Minor wording tweak 2021-11-21 17:51:33 -05:00
Dianne Skoll
342acedbec Correct documentation of variable name length. 2021-11-21 10:35:24 -05:00
Dianne Skoll
a83bf495b1 Don't convert 90-99 to 1900-1999 2021-11-21 10:17:06 -05:00
Dianne Skoll
899829f1ac Handle ADDOMIT in calendar mode before checking if we should not trigger timed reminders. 2021-11-21 10:10:08 -05:00
Dianne Skoll
408a62115e Add regression test for ADDOMIT in calendar mode. 2021-11-20 20:09:04 -05:00
Dianne Skoll
430d0990aa Obey ADDOMIT in calendar mode as well as command-line mode. 2021-11-20 20:05:00 -05:00
Dianne Skoll
47d33e7aaf Fix docs 2021-11-19 12:12:52 -05:00
Dianne Skoll
12f40cba6d Give a concrete example. 2021-11-19 12:08:15 -05:00
Dianne Skoll
ecc0e9609a Update WHATSNEW 2021-11-19 12:01:52 -05:00
Dianne Skoll
eb35a843c1 Add more explanation of ADDOMIT 2021-11-18 15:23:44 -05:00
Dianne Skoll
79289fe6c4 Add ADDMOMIT keyword; bump version to 03.03.10 2021-11-18 15:13:12 -05:00
Dianne Skoll
cb841adf86 Fix typo 2021-11-17 10:23:10 -05:00
Dianne Skoll
724d82e6d2 Fix typo 2021-10-24 10:07:09 -04:00
Dianne Skoll
0532910604 Update to latest remind-conf-mode 2021-10-24 10:00:07 -04:00
Dianne Skoll
f4f5552975 Make decision to drop privileges based on euid instead of uid 2021-10-15 20:36:58 -04:00
Dianne Skoll
3e2794548b Call initgroups when switching users. 2021-10-15 10:51:01 -04:00
Dianne Skoll
f7b8ee168f Fix typo 2021-10-14 21:30:42 -04:00
Dianne Skoll
e3297fe751 Prep for 3.3.9 release. 2021-10-14 21:20:05 -04:00
Dianne Skoll
58ca741a1c Update docs. 2021-10-14 10:38:11 -04:00
Dianne Skoll
14dbbc7bb4 Fix help text. 2021-10-14 10:24:58 -04:00
Dianne Skoll
df55c4032b Use external .png images for moon phases. 2021-10-14 10:23:58 -04:00
Dianne Skoll
3768155a20 Add "--pngs" option 2021-10-14 10:21:51 -04:00
Dianne Skoll
2f3b9cadf4 Add a generated file to unconfigure 2021-10-12 22:06:03 -04:00
Dianne Skoll
2c79a6531a Fix typo. 2021-10-12 22:05:12 -04:00
Dianne Skoll
be5c856f4b Remove "cm2rem". It's waaaay obsolete. 2021-10-12 22:04:00 -04:00
Dianne Skoll
712a333f08 Substitute full path to `rem2html' 2021-10-12 21:58:10 -04:00
Dianne Skoll
b753e84c8c Update README 2021-10-12 21:55:18 -04:00
Dianne Skoll
4b4acaadbb Don't install rem2html if we don't have Perl. 2021-10-12 21:54:38 -04:00
Dianne Skoll
8a52f9b67d Silence Perl warning. 2021-10-12 21:51:04 -04:00
Dianne Skoll
e372606281 Pass --stylesheet option 2021-10-12 21:46:03 -04:00
Dianne Skoll
c443d0a9da Make imgbase and stylesheet options behave rationally. 2021-10-12 21:44:25 -04:00
Dianne Skoll
42c9ae9ea8 Add generated file to .gitignore. 2021-10-12 21:33:06 -04:00
Dianne Skoll
dac9bb4187 Pass proper --imgbase argument 2021-10-12 21:32:46 -04:00
Dianne Skoll
812d926f66 Move rem2html into its own directory and install it by default. 2021-10-12 21:28:14 -04:00
Dianne Skoll
45831ea69f Fix error in man page courtesy of Richard Ulmer. 2021-10-11 19:54:38 -04:00
Dianne Skoll
354e1d236b Update test-for-backends.rem with comments. 2021-10-08 15:27:32 -04:00
Dianne Skoll
ac478039cf Remove unnecessary spaces from JSON output. 2021-10-06 17:47:31 -04:00
Dianne Skoll
96f5799e6f Fix typo 2021-10-06 17:41:15 -04:00
Dianne Skoll
e21479f696 Add test reminder file for seeing how back-ends handle SPECIALs 2021-10-06 09:39:52 -04:00
Dianne Skoll
25dc883e15 Fix bug in calendar display: Would sometimes highlight wrong day as "today" 2021-10-06 09:39:08 -04:00
Dianne Skoll
bfb1374ee3 Document that "-pp" is the preferred Remind output format. 2021-10-05 23:31:34 -04:00
Dianne Skoll
cacd8f9792 Tweak stylesheet 2021-10-05 23:13:22 -04:00
Dianne Skoll
3e9053a3c6 No need to install the .png images. 2021-10-05 23:10:34 -04:00
Dianne Skoll
5fa357fec2 Use data: URLs for the moon images. 2021-10-05 23:08:41 -04:00
Dianne Skoll
f109c3d696 Remove C99-ism. 2021-10-05 13:54:04 -04:00
Dianne Skoll
b097ce7279 Fix docs. 2021-10-05 12:18:50 -04:00
Dianne Skoll
1297854935 Allow "-u+whatever" to change users without disabling RUN. 2021-10-05 12:17:42 -04:00
Dianne Skoll
0a1d0011f6 Add "-+username" option to trust "username" for the purpose of allowing RUN. 2021-10-05 12:04:44 -04:00
Dianne Skoll
20db1be0a0 Add missing #ifdef...#endif courtesy of Nomen Nescio 2021-10-04 08:39:27 -04:00
Dianne Skoll
143f1d6144 Prep for 3.3.8 release. 2021-09-13 19:14:03 -04:00
Dianne Skoll
358f6c9497 Fix error in TkRemind reverse-engineering of Reminder. 2021-09-13 18:11:32 -04:00
Dianne Skoll
ca26544be8 Don't use YYYY-MM-DD form of full date.
We get better error messages from Remind this way.
2021-09-13 17:54:36 -04:00
Dianne Skoll
5ceffddd5b Add "shellescape" built-in function. 2021-09-08 09:33:47 -04:00
Dianne Skoll
8e3ddb96b3 Add another couple of tests. 2021-09-07 12:16:36 -04:00
Dianne Skoll
377de36b35 More doc about INCLUDECMD. 2021-09-07 10:06:20 -04:00
Dianne Skoll
4395e2f7ed Use "pclose" rather than "fclose" to close descriptors opened with "popen" 2021-09-05 11:45:55 -04:00
Dianne Skoll
1d0cc31b10 Clarify how we determine uniqueness of INCLUDECMD commands. 2021-09-05 11:38:13 -04:00
Dianne Skoll
4b4b2ddcd4 Add test case for line-continuation in INCLUDECMD lines. 2021-09-05 11:30:35 -04:00
Dianne Skoll
3c9b5b786e Convert \n from continuation lines in INCLUDECMD to ' ' to make it a little friendlier. 2021-09-05 11:28:54 -04:00
Dianne Skoll
08f1bea6ce Make TkRemind refuse to attempt to edit reminders issued by an INCLUDECMD 2021-09-05 11:13:11 -04:00
Dianne Skoll
a2cc5943e0 Fix test case 2021-09-05 10:54:56 -04:00
Dianne Skoll
895ac6f0f7 Fix bugs in INCLUDECMD. Improve INCLUDECMD documentation. Add ! feature
If you use:

    INCLUDECMD !some_command

then RUN is disabled for the outptu of some_command.
2021-09-05 10:49:04 -04:00
Dianne Skoll
759ca0253e Strip leading spaces from arg to INCLUDECMD. 2021-09-05 10:05:18 -04:00
Dianne Skoll
0ca368c8d9 Parse arg to INCLUDECMD as a character string, not a sequence of tokens. 2021-09-05 10:02:59 -04:00
Dianne Skoll
a467cc1b84 Document that results of INCLUDECMD commands are cached. 2021-09-04 23:27:17 -04:00
Dianne Skoll
c65fd826a5 Use cached results of commands. 2021-09-04 23:25:37 -04:00
Dianne Skoll
bd6f4e1b43 Add test for includecmd 2021-09-04 23:11:46 -04:00
Dianne Skoll
169520914f Document INCLUDECMD 2021-09-04 23:06:59 -04:00
Dianne Skoll
a163a0c446 Add INCLUDECMD command
Executes a shell command and reads the resulting output as a Remind script.
2021-09-04 23:00:03 -04:00
Dianne Skoll
295aeb0ed8 Prevent floating-point exception if we evaluate $IntMin * (-1) 2021-08-30 12:31:43 -04:00
Dianne Skoll
9b2fdad56c Remove obsolete script. 2021-07-12 13:14:44 -04:00
Dianne Skoll
7a1184d3c5 Don't set LC_ALL to en_US.utf-8 if it's already set to a UTF-8 locale 2021-06-27 13:03:59 -04:00
Dianne Skoll
b036244316 Document that -n causes -g to be ignored. 2021-06-01 14:29:48 -04:00
Dianne Skoll
5ad5366e8a Doc fix: *num should be *rep 2021-05-25 10:24:21 -04:00
Dianne Skoll
244677e524 Prep for 3.3.7 release. 2021-05-10 16:53:16 -04:00
Dianne Skoll
f5a094a973 Fix bug in handling of WKDAY DAY YEAR date specification. 2021-04-15 12:29:30 -04:00
Dianne Skoll
5681ebdb12 Simplify "REM MSG ..." case. 2021-04-13 20:54:54 -04:00
Dianne Skoll
664fa5f08f Fix bug: Remind would sometimes compute incorrect trigger date for:
REM 29 Feb SOME_WEEKDAY MSG ...
2021-04-13 12:21:37 -04:00
Dianne Skoll
14edec5eae Pass in wd to macro explicitly. 2021-04-13 12:11:13 -04:00
Dianne Skoll
6adfd2e739 Wrap code to advance to next specified weekday in a macro. 2021-04-13 12:08:20 -04:00
Dianne Skoll
34409f7a7d Update copyright year. 2021-04-02 10:43:54 -04:00
Dianne Skoll
7e13d1052c Don't run test suite as "root". 2021-04-01 19:41:19 -04:00
90 changed files with 6701 additions and 3262 deletions

28
.gitignore vendored
View File

@@ -1,16 +1,26 @@
rem2pdf/Makefile.old
*.bak
*.o
*~
.gitignore
TAGS
autom4te.cache
config.log
config.status
src/Makefile
www/Makefile
*.o
src/config.h
src/remind
rem2html/Makefile
src/*.tar.gz*
tests/test.out
.gitignore
*~
src/Makefile
src/config.h
src/rem2ps
src/remind
src/version.h
TAGS
tests/test.out
www/Makefile
rem2pdf/Makefile.PL
MYMETA.json
MYMETA.yml
Makefile
blib/
pm_to_blib
rem2pdf/Makefile.top
rem2pdf/bin/rem2pdf

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-2020 Dianne Skoll, except where noted in
2. REMIND is Copyright 1992-2021 Dianne Skoll, except where noted in
individual files.
3. DISTRIBUTION AND USE

View File

@@ -9,7 +9,7 @@ all: src/Makefile
@echo "*******************"
@echo ""
@cd src && $(MAKE) all LANGDEF=$(LANGDEF)
@$(MAKE) -C rem2pdf -f Makefile.top
install:
@echo ""
@echo "*********************"
@@ -18,17 +18,19 @@ install:
@echo "* *"
@echo "*********************"
@echo ""
@cd src && $(MAKE) install
@$(MAKE) -C src install
@$(MAKE) -C rem2html install
@$(MAKE) -C rem2pdf -f Makefile.top install
clean:
find . -name '*~' -exec rm {} \;
cd src && $(MAKE) clean
$(MAKE) -C src clean
-$(MAKE) -C rem2pdf clean
test:
@cd src && $(MAKE) -s 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
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
src/Makefile: src/Makefile.in
./configure

View File

@@ -33,10 +33,6 @@ proc SetConfigDefaults {} {
set Config(DEFAULT_PAGE) "Letter"
set Config(DATESEP) "-"
set Config(TIMESEP) ":"
set Config(ISOLATIN1) 0
set Config(IBMEXTENDED) 0
set Config(ISOLATIN2) 0
set Config(IBM852) 0
set Config(NORTHERN_HEMISPHERE) 1
set Config(WESTERN_HEMISPHERE) 1
set Config(LANGUAGE) "English"
@@ -233,19 +229,6 @@ proc CreateOptionsDialog { w } {
grid configure $w.timelabel -row 2 -column 0 -sticky e
grid configure $w.time -row 2 -column 1 -sticky nsew
label $w.charlabel -text "Character set: "
menubutton $w.char -text "ISO 8859-1" -indicatoron 1 -relief raised \
-menu $w.char.menu
menu $w.char.menu -tearoff 0
$w.char.menu add command -label "ISO 8859-1" -command "$w.char configure -text {ISO 8859-1}"
$w.char.menu add command -label "ISO 8859-2" -command "$w.char configure -text {ISO 8859-2}"
$w.char.menu add command -label "IBM Extended" -command "$w.char configure -text {IBM Extended}"
$w.char.menu add command -label "IBM CPI-852" -command "$w.char configure -text {ISO 8859-2}"
$w.char.menu add command -label "Plain ASCII" -command "$w.char configure -text {Plain ASCII}"
grid configure $w.charlabel -row 3 -column 0 -sticky e
grid configure $w.char -row 3 -column 1 -sticky nsew
label $w.langlabel -text "Language: "
menubutton $w.lang -text $Config(LANGUAGE) -indicatoron 1 -relief raised \
-menu $w.lang.menu
@@ -268,8 +251,8 @@ proc CreateOptionsDialog { w } {
$w.lang.menu add command -label $lang -command [list $w.lang configure -text $lang]
}
grid configure $w.langlabel -row 4 -column 0 -sticky e
grid configure $w.lang -row 4 -column 1 -sticky nsew
grid configure $w.langlabel -row 3 -column 0 -sticky e
grid configure $w.lang -row 3 -column 1 -sticky nsew
}
@@ -446,21 +429,6 @@ proc CreateCustomH {} {
set Config(DATESEP) [$Options.date cget -text]
set Config(TIMESEP) [$Options.time cget -text]
switch -- [$Options.char cget -text] {
"ISO 8859-1" {
set Config(ISOLATIN1) 1
}
"ISO 8859-2" {
set Config(ISOLATIN2) 1
}
"IBM CPI-852" {
set Config(IBM852) 1
}
"IBM Extended" {
set Config(IBMEXTENDED) 1
}
}
while {[gets $in line] != -1} {
switch -glob -- $line {
"#define LAT_DEG *" {
@@ -495,22 +463,6 @@ proc CreateCustomH {} {
puts $out "#define TIMESEP '$Config(TIMESEP)'"
.msgs insert end "#define TIMESEP '$Config(TIMESEP)'\n"
}
"#define ISOLATIN1 *" {
puts $out "#define ISOLATIN1 $Config(ISOLATIN1)"
.msgs insert end "#define ISOLATIN1 $Config(ISOLATIN1)\n"
}
"#define ISOLATIN2 *" {
puts $out "#define ISOLATIN2 $Config(ISOLATIN2)"
.msgs insert end "#define ISOLATIN2 $Config(ISOLATIN2)\n"
}
"#define IBM852 *" {
puts $out "#define IBM852 $Config(IBM852)"
.msgs insert end "#define IBM852 $Config(IBM852)\n"
}
"#define IBMEXTENDED *" {
puts $out "#define IBMEXTENDED $Config(IBMEXTENDED)"
.msgs insert end "#define IBMEXTENDED $Config(IBMEXTENDED)\n"
}
default {
puts $out $line
}

85
configure vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -69,6 +69,8 @@ know! Here are the basic guidelines:
- You can test your language file with the script "tests/tstlang.rem"
- Your localized strings must be encoded using UTF-8.
RELEASE NOTES -- miscellaneous info that couldn't go anywhere else!
1. POPUP REMINDERS

View File

@@ -1,11 +1,203 @@
CHANGES TO REMIND
* VERSION 3.4 Patch 0 - 2022-??-??
- MAJOR CHANGE: Remind and its helpers (except for rem2ps) fully support
UTF-8. If your system locale is a UTF-8 locale and your terminal
can handle UTF-8 encoding, you can enjoy full Unicode support in Remind.
- NEW FEATURE: Added a rem2pdf Remind-to-PDF converter. It can handle
the full UTF-8 character set and features a new PANGO special reminder
type that lets you format the text in the PDF calendar (by changing the
font size, color, underlining, etc.)
rem2pdf requires the Pango and Cairo Perl modules.
- NEW FEATURE: remind: New system variables $Sunday through $Saturday
and $January through $December let you set weekday and month names
to whatever you like, permitting you to produce calendars in your
local language, even if it's not one of the languages Remind supports
by default.
- NEW FEATURE: tkremind: If rem2pdf installed, TkRemind offers you the
choice of PDF or PostScript output in the Print dialog.
- BUG FIX: Properly support formatting of double-wide characters in the
terminal mode "remind -c" calendar.
- IMPROVEMENT: All localized languages now use UTF-8 exclusively.
Support for old character encodings like ISO-8859-1 and ISO-8859-2
has been dropped since modern UNIXes have pretty much standardized
on UTF-8.
- CHANGE: remind: Non-English versions of remind *no longer* accept
non-English month- and weekday-names in trigger specifications. This
was a misfeature. NOTE INCOMPATIBILITY.
* VERSION 3.3 Patch 12 - 2022-01-24
- UPDATE: rem2html: Use JSON::MaybeXS instead of JSON::Any, since JSON::Any
is deprecated. NOTE INCOMPATIBILITY: If you don't have JSON::MaybeXS
installed, you'll need to install it before trying to install or update
rem2html
- NEW FEATURE: Add a DO command. This is just like INCLUDE, but relative
paths are interpreted relative to the directory containing the current
file. That is:
DO somefile.rem
is equivalent to:
INCLUDE [filedir()]/somefile.rem
- NEW FEATURE: Add the $DefaultTDelta system variable and associated
-tt[N] command-line option to set a default time delta for timed
reminder without an explicit +N delta.
- IMPROVEMENT: TkRemind: Store .tkremindrc in $XDG_CONFIG_HOME/tkremindrc
or $HOME/.config/tkremindrc as per the XDG Base Directory Specification.
- BUG FIX: remind: Make the shell() built-in function respect
$MaxStringLen
- BUG FIX: Use size_t to track the size of dynamic buffers rather than int.
This permits Remind to read in files with lines longer than 1GB and to
consume more than 1GB of output from the shell() command, both of which
will surely be massively useful. (The old limit was 1GB rather than 2GB
because of details of the dynamic buffer resizing algorithm.)
* VERSION 3.3 Patch 11 - 2021-12-30
- IMPROVEMENT: TkRemind: Save the print dialog settings so they persist.
- IMPROVEMENT: TkRemind: Show queue in sorted order.
- IMPROVEMENT: TkRemind: Pass "-r" flag to inotifywait
- IMPROVEMENT: TkRemind: Draw moon phases with Tk canvas items rather than
using PNG images. This lets them change color along with other TkRemind
preferences.
- IMPROVEMENT: TkRemind: Underline editable reminders when the pointer enters
them; fire up the editor with either Button-1 or Button-3 for
non-TkRemind-generated reminders.
- NEW FUNCTION: Remind: Add the isany() built-in function.
- IMPROVEMENT: rem2html: Add class names indicating number of rows in calendar
- IMPROVEMENT: remind: In -z0 mode, sleep with higher precision to ensure we
wake as close to possible to each 1-minute boundary.
- IMPROVEMENT: rem2html: Coalesce table.rem-cal CSS into one block. Thanks
to Ian! D. Allen for pointing this out.
- IMPROVEMENT: examples/defs.rem: Modernize the examples and get rid of some
cruft.
- CHANGE: Add $Latitude and $Longitude system variables. Deprecate
$LatDeg, $LatMin, $LatSec, $LongDeg, $LongMin and $LongSec.
- CHANGE: Test: Add "dump $" to test.rem.
* VERSION 3.3 Patch 10 - 2021-11-30
- IMPROVEMENT: TkRemind: Apply window and text colors to all GUI elements
including buttons and status labels.
- NEW FEATURE: The new ADDOMIT keyword can shorten reminder files.
The command:
REM ...whatever... ADDOMIT MSG Foo
behaves identically to:
REM ...whatever... SATISFY 1
IF trigvalid()
OMIT [trigdate()] MSG Foo
ENDIF
For example, Labour Day can be displayed and omitted as follows:
REM Mon 1 Sep SCANFROM -7 ADDOMIT MSG Labour Day
- UPDATE: Update contrib/remind-conf-mode to latest release
- CHANGE: The parser does not auto-convert numbers 90-99 to 1990-1999. This
was messing up things like "DURATION 90". It also means you can no longer
abbreviate the years 1990-1999 as 90-99.
- BUG FIX: Various documentation fixes
- BUG FIX: When switching users with the "-u" option, call initgroups()
to properly set group membership list.
* VERSION 3.3 Patch 9 - 2021-10-14
- NEW FEATURE: Add "-+username" option to tell Remind to trust files owned by
"username" and allow RUN directives in them. Idea courtesy of Ian! D. Allen
- NEW FEATURE: Add "-u+username" variant to tell Remind to switch users to
"username" without disabling RUN directives. Idea courtesy of Ian! D. Allen
- CHANGE: rem2html: rem2html has been moved out of the www/ directory into
its own rem2html/ directory. If your system has the prerequisites
(namely Perl, Getopt::Long and JSON::Any) then rem2html will be installed
by "make install".
- CHANGE: Remove "cm2rem". It was about 20 years obsolete.
- CHANGE: rem2html: Use inline data: URL images for moon images by default,
thus producing a completely stand-alone HTML file.
- CHANGE: Remove unnecessary spaces from "remind -pp" JSON output.
- DOCUMENTATION FIX: Various man page fixes and tweaks.
- BUG FIX: rem2html: Tweak the default CSS stylesheet; more rational
handling of rem2html command-line options.
- BUG FIX: remind: "remind -c" would sometimes highlight *two* days as
"today"; this has been fixed.
- BUG FIX: Add a missing #ifdef...#endif and remove a C99-ism. This once again
allows Remind to be compiled with some very old C compilers.
* VERSION 3.3 Patch 8 - 2021-09-13
- NEW FEATURE: remind: Add INCLUDECMD command
- NEW FEATURE: remind: Add shellescape() built-in function
- BUG FIX: tkremind: TkRemind would sometimes fill in incorrect initial
values for the reminder-editing form if you clicked on a TkRemind-created
reminder to edit it. This has been fixed.
- BUG FIX: tkremind: Get back better error messages from Remind if you
try to create a reminder with an invalid date specification.
- BUG FIX: remind: Catch integer overflow if we try to evaluate $IntMin * -1
- DOC UPDATES: remind: Minor man page fixes
* VERSION 3.3 Patch 7 - 2021-05-10
- MINOR FIX: Refuse to run "make test" as root --- it would fail
anyway with an obscure message.
- BUG FIX: Remind would sometimes compute incorrect trigger date for:
REM Tue 29 Feb MSG ...
- BUG FIX: Remind would sometimes compute incorrect trigger date for
a date spec like: Tue 31 2021 MSG ...
* VERSION 3.3 Patch 6 - 2021-03-30
- test/test.rem: Change local to en_US.utf-8 only if current locale
is not a UTF-8 locale.
- MINOR CHANGE: Remind's arithemtic operators (+, -, *, /) give errors
- MINOR CHANGE: Remind's arithmetic operators (+, -, *, /) give errors
on overflow rather than silently giving the wrong answer.
- MINOR CHANGE: Add $IntMin and $IntMax system variables.
@@ -64,7 +256,7 @@ CHANGES TO REMIND
When you print from TkRemind, we also invoke Remind with "-itkprint=1"
so you can detect that PostScript is being generated.
- CHANGE: The maxmimum length of a variable name has been increased from
- CHANGE: The maximum length of a variable name has been increased from
16 characters to 64 characters. Modern computers have plenty of memory.
- BUG FIXES: Minor documentation updates, typo fixes, clarifications, etc.
@@ -242,7 +434,7 @@ CHANGES TO REMIND
- BUG FIX: Make parser reject an AT followed by more than one time.
- BUG FIX: Make parser reject epeated delta or *repeat values.
- BUG FIX: Make parser reject repeated delta or *repeat values.
* Version 3.1 Patch 14 - 2015-04-24
@@ -433,7 +625,7 @@ CHANGES TO REMIND
* Version 3.1 Patch 4 - 2008-02-03
- ENHANCMENT: tkremind respects the "-b1" option and operates in 24-hour
- ENHANCEMENT: tkremind respects the "-b1" option and operates in 24-hour
clock mode if the option is supplied.
- ENHANCEMENT: tkremind has been tweaked to look better with Tcl/Tk 8.5.
@@ -572,7 +764,7 @@ CHANGES TO REMIND
- The SPECIAL COLOR reminder type has been hacked to behave more like
a MSG type. It sorts properly and is emitted as a normal reminder
in non-calendar mode. Simlarly, SPECIAL HTML sorts with -g as well.
in non-calendar mode. Similarly, SPECIAL HTML sorts with -g as well.
+ MINOR ENHANCEMENTS
@@ -1508,7 +1700,7 @@ CHANGES TO REMIND
- Improved debugging of reminder scripts
- Took out the "purge" option - it is in general too dificult to tell when
- Took out the "purge" option - it is in general too difficult to tell when
a reminder has expired for good, so now it's up to you to do this
by hand.

View File

@@ -14,7 +14,6 @@
# "#USHOLS" for U.S. holidays #
# "#JHOLS" for Jewish holidays #
# "#PSSTUFF" for nifty PostScript examples #
# "#COLORS" for examples of ANSI color escape sequences. #
# #
# This file is part of REMIND. #
# Copyright (C) 1992-2018 Dianne Skoll #
@@ -26,8 +25,8 @@ RUN OFF
################################################
# Ensure required version of remind is used... #
################################################
IF version() < "03.01.09"
ERRMSG This file requires at least version 03.01.09 of Remind.%
IF version() < "03.01.10"
ERRMSG This file requires at least version 03.01.10 of Remind.%
ERRMSG This version is version [version()].
EXIT
ENDIF
@@ -93,9 +92,6 @@ SET Week_3 15
SET Week_4 22
FSET _last(mo) "1 " + MON((mo%12)+1) + " --7"
# Handy function to provide SCANFROM dates...
FSET _back(days) $U-days
#################################################################
# Function that removes a single leading zero from a string... #
#################################################################
@@ -135,7 +131,7 @@ REM 1 MSG John's [_mo_num(11, 1984)] 'monthly' anniversary
############################################################################
# Calculate the weekday of the holiday.
REM 4 July SCANFROM [_back(7)] SATISFY 1
REM 4 July SCANFROM -7 SATISFY 1
SET iday $T
IF WKDAYNUM(iday) == Sat
@@ -217,17 +213,15 @@ REM [easter+39] MSG %"Ascension Day%"
REM [easter+49] MSG %"Pentecost%"
# Some holidays are omitted, some are not. You may want to change
# which ones are omitted - use the general forms shown below.
# You'll need the _back() function and the Week_n variables defined
# way up in the file.
# which ones are omitted - use the general forms shown below. You'll
# need the Week_n variables defined way up in the file.
OMIT Jan 1 MSG %"New Year's%" Day
REM Mon Jan [Week_3] MSG Martin Luther King - %"MLK Day%"
REM Feb 2 MSG %"Ground Hog Day%"
REM Feb 14 MSG %"Valentine's%" Day
REM Mon Feb [Week_3] SCANFROM [_back(7)] SATISFY 1
OMIT [$T] MSG %"President's Day%"
REM Mar 17 MSG %"St. Patrick's%" Day
OMIT Jan 1 MSG %"New Year's%" Day
REM Mon Jan [Week_3] MSG Martin Luther King - %"MLK Day%"
REM Feb 2 MSG %"Ground Hog Day%"
REM Feb 14 MSG %"Valentine's%" Day
REM Mon Feb [Week_3] SCANFROM -7 ADDOMIT MSG %"President's Day%"
REM Mar 17 MSG %"St. Patrick's%" Day
# The DST rules are accurate for most locations in
# North America
@@ -237,38 +231,31 @@ REM Sun Mar 8 ++2 FROM 1 Jan 2007 MSG Daylight Saving Time - %"DST starts%" %b
REM Sun [_last(Oct)] ++2 UNTIL 1 Jan 2007 MSG Daylight Saving Time - %"DST ends%" %b
REM Sun 1 Nov ++2 FROM 1 Jan 2007 MSG Daylight Saving Time - %"DST ends%" %b
REM Apr 1 MSG %"April Fool's%" Day
REM Mon Tue Wed Thu Fri Sat 15 Apr MSG %"Income tax%" due
REM May 5 MSG %"Cinco de Mayo%"
REM Sat May [Week_1] MSG %"Kentucky Derby%"
REM Sun May [Week_2] MSG %"Mother's Day%"
REM Sat May [Week_3] MSG %"Armed Forces Day%"
REM Mon [_last(May)] SCANFROM [_back(7)] SATISFY 1
OMIT [$T] MSG %"Memorial Day%"
REM Jun 14 MSG %"Flag Day%"
REM Sun Jun [Week_3] MSG %"Father's Day%"
REM Mon Sep [Week_1] SCANFROM [_back(7)] SATISFY 1
OMIT [$T] MSG %"Labor Day%"
REM Mon Oct [Week_2] MSG %"Columbus Day%"
REM Nov 11 MSG %"Veterans Day%"
REM Apr 1 MSG %"April Fool's%" Day
REM Mon Tue Wed Thu Fri Sat 15 Apr MSG %"Income tax%" due
REM May 5 MSG %"Cinco de Mayo%"
REM Sat May [Week_1] MSG %"Kentucky Derby%"
REM Sun May [Week_2] MSG %"Mother's Day%"
REM Sat May [Week_3] MSG %"Armed Forces Day%"
REM Mon [_last(May)] SCANFROM -7 ADDOMIT MSG %"Memorial Day%"
REM Jun 14 MSG %"Flag Day%"
REM Sun Jun [Week_3] MSG %"Father's Day%"
REM Mon Sep [Week_1] SCANFROM -7 ADDOMIT MSG %"Labor Day%"
REM Mon Oct [Week_2] MSG %"Columbus Day%"
REM Nov 11 MSG %"Veterans Day%"
REM Oct 30 MSG %"Mischief Night%"
REM Oct 31 MSG %"Halloween%"
REM Tue Nov 2 SCANFROM [_back(7)] \
SATISFY [($Ty % 4) == 0] \
MSG %"Election%" Day
REM Thu Nov [Week_4] SCANFROM [_back(7)] SATISFY 1
OMIT [$T] MSG %"Thanksgiving%" Day
REM Fri Nov [Week_4+1] SCANFROM [_back(7)] SATISFY 1
OMIT [$T] MSG %"Thanksgiving%" (cont.)
OMIT Dec 24 MSG %"Christmas Eve%"
OMIT Dec 25 MSG %"Christmas%" Day
REM Oct 30 MSG %"Mischief Night%"
REM Oct 31 MSG %"Halloween%"
REM Tue Nov 2 SCANFROM -7 SATISFY [($Ty % 4) == 0] MSG %"Election Day%"
REM Thu Nov [Week_4] SCANFROM -7 ADDOMIT MSG %"Thanksgiving Day%"
REM Fri Nov [Week_4+1] SCANFROM -7 ADDOMIT MSG %"Thanksgiving (cont.)%"
OMIT Dec 24 MSG %"Christmas Eve%"
OMIT Dec 25 MSG %"Christmas%" Day
##########################################################################
# #
# If any US holidays were triggered above, shade in the calendar #
# entry in PostScript. This is not quite correct, as it blots out any #
# other PostScript stuff above. I was too lazy to do it properly :-) #
# entry in PostScript. #
# #
##########################################################################
if $NumTrig > SaveTrig
@@ -495,48 +482,10 @@ REM Friday CAL Candle lighting at [sunset($T)-18]
REM Saturday CAL Havdalah at [sunset($T)+42]
#COLORS
##########################################################################
# #
# This contains sample ANSI escape sequences for coloring messages. #
# It should work on an IBM PC with the ANSI.SYS driver, and on #
# other terminals which use the ANSI sequences. #
# #
# This information was provided by Gail Gurman.
# #
##########################################################################
# Colors - use Nrm to reset to normal text.
SET Esc CHAR(27)
SET Nrm Esc + "[0m"
SET Blk Esc + "[0;30m"
SET Red Esc + "[0;31m"
SET Grn Esc + "[0;32m"
SET Ylw Esc + "[0;33m"
SET Blu Esc + "[0;34m"
SET Mag Esc + "[0;35m"
SET Cyn Esc + "[0;36m"
SET Wht Esc + "[0;37m"
SET Gry Esc + "[30;1m"
SET BrRed Esc + "[31;1m"
SET BrGrn Esc + "[32;1m"
SET BrYlw Esc + "[33;1m"
SET BrBlu Esc + "[34;1m"
SET BrMag Esc + "[35;1m"
SET BrCyn Esc + "[36;1m"
SET BrWht Esc + "[37;1m"
# Examples
REM MSG A [Blu]blue[Nrm] reminder.
REM MSG [Red]%"A red reminder%" safe to use in the calendar mode.[Nrm]
# Here is an example of how to use msgprefix() and msgsuffix(). These
# will highlight priority-0 reminders in bright red,
# priority-2500 in red, and priority-7500 in blue. All others
# will be in the normal colors
FSET msgprefix(x) iif(x==0, BrRed, x==2500, Red, x==7500, Blu, Nrm)
# Don't forget to return to normal color set at the end of reminder!
FSET msgsuffix(x) Nrm
REM 1 SPECIAL COLOR 0 0 255 A blue reminder.
REM 2 SPECIAL COLOR 255 0 0 %"A red reminder%" safe to use in the calendar mode.
# The next examples are great for putting right at the end of the reminder
# file. They make queued reminders more eye-catching when they pop up.

View File

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

View File

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

View File

@@ -12,6 +12,10 @@ emits PostScript code (which draws a calendar) to the standard output.
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
render characters outside the ASCII character set, see
\fBrem2pdf\fR instead.
.SH OPTIONS
.TP
@@ -61,7 +65,9 @@ there is room and otherwise follows \fIn\fR=2 yields the same results as
.TP
.B \-i
Use ISO 8859-1 standard encoding for the PostScript fonts. If you do
not use this option, the default encoding is used.
not use this option, the default encoding is used. If you use this option,
you probably also need to convert Remind's output (typically UTF-8)
to ISO-8859-1 using \fBiconv\fR(1).
.TP
.B \-e
Make the calendar fill the entire page. By default, the calendar is
@@ -340,6 +346,10 @@ month (0 = Sunday, 1 = Monday, 6 = Saturday.) And \fImonday_first\fR is
1 if the \fB\-m\fR flag was supplied to \fBRemind\fR, or 0 if it was not.
All this information is supplied so back-ends don't need any date calculation
facilities.
Note that all spaces in \fImonth_name\fR will be replaced with
underscores. Back-ends should undo this replacement.
.TP
\fIsun mon tue wed thu fri sat\fR
This line consists of
@@ -347,6 +357,9 @@ space-separated names of days in whatever language \fBRemind\fR was
compiled for. This information can be used by back-ends to annotate
calendars, and means they don't have to be created for a specific
language.
Note that all spaces in day names will be replaced with
underscores. Back-ends should undo this replacement.
.TP
\fInext_mon next_days\fR
The name of the next month and the number of days in it.
@@ -475,7 +488,7 @@ present and the value will be the type of SPECIAL (such as SHADE, COLOR,
MOON, etc.)
.TP
.B tags \fIdata\fR
If any TAG clauses are present, the \fBtag\fR key will be present and consist
If any TAG clauses are present, the \fBtags\fR key will be present and consist
of a comma-separated list of tags.
.TP
.B time \fIt\fR
@@ -662,4 +675,4 @@ 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,
but again, the PostScript output will probably not work.
.SH SEE ALSO
\fBremind\fR
\fBremind\fR, \fBrem2pdf\fR

View File

@@ -1,4 +1,4 @@
.TH REMIND 1 "1 January 2020"
.TH REMIND 1 "1 January 2021"
.UC 4
.SH NAME
remind \- a sophisticated reminder service
@@ -31,7 +31,8 @@ ignore them for now and skip to the section "REMINDER FILES".
.B \-n
The \fB\-n\fR option causes \fBRemind\fR to print the \fBnext\fR occurrence
of each reminder in a simple calendar format. You can sort this by
date by piping the output through \fBsort(1)\fR.
date by piping the output through \fBsort(1)\fR. Note that the \fB\-n\fR
option causes any \fB\-g\fR option to be \fIignored\fR.
.TP
.B \-j\fR[\fIn\fR]
Runs \fBRemind\fR in "purge" mode to get rid of expired reminders.
@@ -39,7 +40,7 @@ See the section PURGE MODE for details.
.TP
.B \-r
The \fB\-r\fR option disables \fBRUN\fR directives and the \fBshell()\fR
function. As of Remind 3.00.17, using \fB\-u\fR implies \fB\-r\fR.
function.
.TP
.B \-c\fI[flags]\fIn\fR
The \fB\-c\fR option causes \fBRemind\fR to produce a calendar that is
@@ -189,6 +190,11 @@ If you supply a number \fIn\fR after the \fB\-t\fR option, then
\fBRemind\fR pretends that each non-expired reminder has a \fIdelta\fR
of \fIn\fR days and triggers reminders accordingly.
.TP
.B \-tt\fR[\fIn\fR]
The \fB-tt\fR option causes \fBRemind\fR to assume a default delta of
\fIn\fR minutes for all timed reminders. If \fB\-tt\fR is given with
no \fIn\fR, a default delta of 5 minutes is used.
.TP
.B \-h
The \fB\-h\fR option ("hush...") suppresses certain warning and information
messages. In particular, if no reminders are triggered, this mode
@@ -250,6 +256,7 @@ The optional \fBa\fR and \fBd\fR characters specify the sort order
(ascending or descending) for the date, time and priority fields. See
the section "SORTING REMINDERS" for more information.
Note that \fB\-g\fR is \fIignored\fR if you use the \fB\-n\fR option.
.TP
\fB\-b\fR[\fIn\fR]
Set the time format for the calendar and simple-calendar outputs. \fIN\fR
@@ -308,7 +315,11 @@ and user name, respectively, of the specified user. LOGNAME is also
set to the specified user name. This option is meant for
use in shell scripts that mail reminders to all users. Note that
as of Remind 3.00.17, using \fB\-u\fR implies \fB\-r\fR -- the RUN
directive and shell() functions are disabled.
directive and shell() functions are disabled. However, if you prefix
\fIname\fR with a \fB+\fR-sign, then RUN and shell() are \fInot\fR
disabled. That is, \fB\-uwhatever\fR switches the user to \fBwhatever\fR
and disables RUN, whereas \fB\-u+whatever\fR switches the user to
\fBwhatever\fR but leaves RUN enabled.
.PP
.RS
Non-root users can also use the \fB\-u\fR option. However, in this
@@ -316,6 +327,13 @@ case, it only changes the environment variables as described above.
It does not change the effective uid or gid.
.RE
.TP
\fB\-+\fIusername\fR
Causes \fBRemind\fR to trust files owned by the user \fIusername\fR.
Normally, if \fBRemind\fR reads a file that you do not own, it disables
RUN and the shell() function. This option causes it to also trust files
owned by \fIusername\fR. You can supply multiple \fB\-+\fR options
to trust multiple users, up to a limit of 20 trusted users.
.TP
\fB-y\fR
Causes \fBRemind\fR to synthesize a tag for any reminder that lacks a
TAG clause.
@@ -349,7 +367,7 @@ it as YYYY-MM-DD or YYYY/MM/DD. You can even supply a date and
time on the command line as one argument: YYYY-MM-DD@HH:MM.
.PP
In addition, you can supply a \fIrepeat\fR parameter, which has the
form *\fInum\fR. This causes \fBRemind\fR to be run \fInum\fR times,
form *\fIrep\fR. This causes \fBRemind\fR to be run \fIrep\fR times,
with the date incrementing on each iteration. You may have to enclose
the parameter in quotes to avoid shell expansion. See the subsection
"Repeated Execution" in the section "CALENDAR MODE" for more
@@ -410,6 +428,7 @@ Its syntax is:
[\fBPRIORITY\fR \fIprio\fR]
[\fBSKIP\fR | \fBBEFORE\fR | \fBAFTER\fR]
[\fBOMIT\fR \fIomit_list\fR]
[\fBADDOMIT\fR]
[\fBOMITFUNC\fR \fIomit_function\fR]
[\fBAT\fR \fItime\fR [\fItdelta\fR] [\fItrepeat\fR]]
[\fBSCHED\fR \fIsched_function\fR]
@@ -618,7 +637,7 @@ present. Examples:
.nf
REM Sat 1 MSG First Saturday of every month
REM Mon Tue Wed Thu Fri 15 \\
MSG 1st working day after 15th of every month
MSG 1st working day on or after 15th of every month
.fi
.PP
11.
@@ -978,6 +997,27 @@ omitted. For that reason, when \fBRemind\fR searches through omitted days,
it terminates the search after the \fBSATISFY\fR iteration limit
(command-line option \fB\-x\fR.)
.PP
.B ADDING TRIGGER DATES TO THE OMIT CONTEXT
.PP
If the \fBADDOMIT\fR keyword appears in a \fBREM\fR command, then
the trigger date (if one could be calculated) is automatically
added to the list of global OMITs.
.PP
The command:
.PP
.nf
REM ... whatever ... ADDOMIT MSG Foo
.fi
.PP
is identical in behaviour to the sequence:
.PP
.nf
REM ... whatever ... SATISFY 1
IF trigvalid()
OMIT [trigdate()] MSG Foo
ENDIF
.fi
.PP
.B TIMED REMINDERS
.PP
Timed reminders are those that have an \fBAT\fR keyword followed
@@ -1355,6 +1395,12 @@ the same as substitutions built up from the simpler %w, %y, etc.
sequences.
.TP
o
The a, c, e, f, g, h, i, j, k, l, u, v, 2, and 3 substitutions may
be preceded by an asterisk (for example, %*c) which causes the word
"at" or "on" that would normally be included in the output to be
omitted.
.TP
o
Any of the substitutions dealing with time (0 through 9 and '!')
produce undefined results if used in a reminder that does not have
an \fBAT\fR keyword. Also, if a reminder has a \fIdelta\fR and may
@@ -1396,7 +1442,8 @@ or:
.PP
The \fBOMIT\fR command is used to "globally" omit certain days
(usually holidays). These globally-omitted days are skipped by the
"\-" and "+" forms of \fIback\fR and \fIdelta\fR. Some examples:
"\-" and "+" forms of \fIback\fR and \fIdelta\fR, but not by the
"\-\-" and "\+\+" forms. Some examples:
.PP
.nf
OMIT 1 Jan
@@ -1510,7 +1557,7 @@ the first day of the month. The local \fBOMIT\fR keyword causes the
Finally, the \fBAFTER\fR keyword will keep moving the reminder forward
until it has passed any holidays specified with global \fBOMIT\fR
commands.
.SH THE INCLUDE COMMAND
.SH THE DO AND INCLUDE COMMANDS
.PP
\fBRemind\fR allows you to include other files in your reminder script,
similar to the C preprocessor #include directive. For example, your
@@ -1534,7 +1581,32 @@ 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
matches that used by the shell when it expands "*.rem".
.PP
Note that the file specified by an \fBINCLUDE\fR command is interpreted
relative to the \fIcurrent working directory of the Remind process\fR.
If you want to include a file relative to the directory containing the
currently-processing file, use \fBDO\fR instead. For example,
if the current file is \fB/home/user/.reminders/foo.rem\fR and Remind's
working directory is \fB/home/user\fR, then:
.PP
.nf
# Read /home/user/.reminders/bar.rem
DO bar.rem
# Read /usr/share/bar.rem - absolute path
DO /usr/share/bar.rem
# Read /home/user/bar.rem
INCLUDE bar.rem
# Read /usr/share/bar.rem - absolute path
INCLUDE /usr/share/bar.rem
.fi
.PP
Arguably, the \fBINCLUDE\fR command should have worked the way \fBDO\fR
does right from the start, but changing it would have broken
backward-compatibility, hence the introduction of \fBDO\fR.
.PP
.SH THE RUN COMMAND
.PP
If you include other files in your reminder script, you may not always
@@ -1579,6 +1651,53 @@ It will not run set-uid. If it reads a file you don't own, it will
disable RUN and the shell() function. And if it is run as \fIroot\fR,
it will only read files owned by \fIroot\fR.
.PP
Note that if \fBRemind\fR reads standard input, it does \fInot\fR
attempt to check the ownership of standard input, even if it is
coming from a file, and hence does \fInot\fR disable RUN and shell()
in this situation.
.SH THE INCLUDECMD COMMAND
.PP
\fBRemind\fR allows you to execute a shell command and evaluate the
output of that command as if it were an included file. For example,
you could have scripts that extract reminders out of a database and print
them on stdout as REM commands. Here is an example:
.PP
.nf
INCLUDECMD extract_reminders_for dfs
.fi
.PP
We assume that the command "extract_reminders_for" extracts reminders out
of a central database for the named user. Another use-case of INCLUDECMD
is if you have your reminders stored in a file in some non-Remind format;
you can write a command that transforms them to Remind format and then
Remind can "include" the file with an appropriate INCLUDECMD command.
.PP
Note that if RUN is disabled, then INCLUDECMD will fail with the error
message "RUN disabled"
.PP
INCLUDECMD passes the rest of the line to \fBpopen\fR(3), meaning that
the command is executed by the shell. As such, shell metacharacters
may need escaping or arguments quoting, depending on what you're trying
to do. Remind itself does not perform any modification of the command
line (apart from the normal [expr] expression-pasting mechanism).
.PP
If the command passed to INCLUDECMD begins with an exclamation mark "!",
then Remind disables \fBRUN\fR for the output of the command. If you are
running a command whose output you don't quite trust, you should
prefix it with "!" so that any RUN commands it emits fail.
.PP
An \fBINCLUDECMD\fR command counts towards the INCLUDE nesting depth.
For any given Remind run, a given INCLUDECMD command is only executed
once and the results are cached. For example, if you generate a
calendar, each unique INCLUDECMD command is run just once, not once
for each day of the produced calendar. "Uniqueness" is determined by
looking at the command that will be passed to the shell, so if (for example)
your INCLUDECMD uses expression-pasting that results in differences depending
on the value of \fBtoday()\fR, then each \fIunique\fR version of the
command will be executed once.
.PP
.SH THE BANNER COMMAND
.PP
When \fBRemind\fR first issues a reminder, it prints a message like this:
@@ -1904,7 +2023,7 @@ command is used as follows:
.PP
\fIVar\fR is the name of a variable. It must start with a letter or
underscore, and consist only of letters, digits and underscores. Only
the first 12 characters of a variable name are significant. Variable
the first 64 characters of a variable name are significant. Variable
names are \fInot\fR case sensitive; thus, "Afoo" and "afOo" are the same
variable. Examples:
.PP
@@ -1997,6 +2116,12 @@ blocks of reminders without having to type priorities for individual
reminders. At startup, \fB$DefaultPrio\fR is set to 5000; it can range
from 0 to 9999.
.TP
.B $DefaultTDelta
The default time delta used if no +N is given in an AT clause. This
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 $DontFork (read-only)
If non-zero, then the \fB\-c\fR option was supplied on the command line.
.TP
@@ -2073,11 +2198,35 @@ using twos-complement representation, this will be 2147483647.
The smallest representable \fBINT\fR. On a machine with 32-bit signed integers
using twos-complement representation, this will be -2147483648.
.TP
.B $LatDeg, $LatMin, $LatSec
.B $Latitude (STRING type)
The latitude of your location, expressed as a string that is a floating-point
number. Because \fBRemind\fR does not have a native floating-point type,
we need to express it as a string. $Latitude can range from "-90.0" to
"90.0", with positive numbers representing points north of the equator
and negative numbers representing south.
.TP
.B $Longitude (STRING type)
The longitude of your location, expressed as a string that is a floating-point
number. Because \fBRemind\fR does not have a native floating-point type,
we need to express it as a string. $Longitude can range from "-180.0" to
"180.0", with positive numbers representing points east of the Greenwich
Meridian and negative numbers representing west.
.RS
.PP
For example, the coordinates of the Statue of Liberty in New York City
are approximately set by:
.nf
SET $Latitude "40.68933"
SET $Longitude "-74.04454"
.fi
.RE
.TP
.B $LatDeg, $LatMin, $LatSec (DEPRECATED)
These specify the latitude of your location. \fB$LatDeg\fR can
range from \-90 to 90, and the others from \-59 to 59. Northern latitudes
are positive; southern ones are negative. For southern latitudes, all
three components should be negative.
three components should be negative. These three variables
are deprecated; you should use \fB$Latitude\fR instead.
.TP
.B $Location (STRING type)
This is a string specifying the name of your location. It is usually
@@ -2085,23 +2234,30 @@ the name of your town or city. It can be set to whatever you like,
but good style indicates that it should be kept consistent with
the latitude and longitude system variables.
.TP
.B $LongDeg, $LongMin, $LongSec
.B $LongDeg, $LongMin, $LongSec (DEPRECATED)
These specify the longitude of your location. \fB$LongDeg\fR can
range from \-180 to 180. Western longitudes are positive; eastern
ones are negative. Note that all three components should have the
same sign: All positive for Western longitudes and all negative for
Eastern longitudes. Note that for historical reasons, the sign for
same sign: All positive for western longitudes and all negative for
eastern longitudes. Note that for historical reasons, the sign for
longitude is \fIdifferent\fR from the usual convention! If you find
the longitude of your location from a search engine, you will most
likely \fIneed to invert the sign to have it work correctly with
Remind.\fR
Remind.\fR These three variables are deprecated; you should use
\fB$Longitude\fR instead. Note also that \fB$Longitude\fR uses the
standard convention of negative for western longitudes and positive
for eastern ones.
.RS
.PP
The latitude and longitude information is required for the functions
\fBsunrise()\fR and \fBsunset()\fR. Default values can be compiled
into \fBRemind\fR, or you can \fBSET\fR the correct values at the
start of your reminder scripts.
.PP
Note that setting any of \fB$LongDec\fR, \fB$LongMin\fR and \fB$LongSec\fR
updates \fB$Longitude\fR correspondingly, and setting \fB$Longitude\fR
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 $MaxSatIter
@@ -2110,7 +2266,9 @@ The maximum number of iterations for the \fBSATISFY\fR clause
.TP
.B $MaxStringLen
A limit on the longest string that \fBRemind\fR will allow you
to create. The default is 65535.
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.
.TP
.B $MinsFromUTC
The number of minutes between Universal Time Coordinated and local time. If
@@ -2505,7 +2663,9 @@ follows:
.PP
.RS
This includes the file "stuff" in the same directory as the
current file being processed.
current file being processed. Note that this workaround is
no longer necessary because \fBDO stuff\fR will achieve the
same goal.
.RE
.TP
.B filename()
@@ -2554,6 +2714,21 @@ The optional parameter \fIstart\fR specifies the position in
\fIsearch\fR at which to start looking for \fItarget\fR.
.RE
.TP
.B isany(arg1 [,arg2, ..., argN]);
Returns 1 if the first argument \fIarg1\fR is equal to any of the
subsequent arguments \fIarg2\fR through \fIargN\fR; returns 0 otherwise.
Also returns 0 if called with only one argument.
.RS
.PP
As an example, the following two expressions are equivalent:
.PP
.nf
(a == b) || (a == c) || (a == d) || (a == e)
isany(a, b, c, d, e)
.fi
.RE
.TP
.B isdst([d_date [,t_time]]) \fRor\fB isdst(q_datetime)
Returns a positive number if daylight saving time is in
effect on the specified date and time. \fIDate\fR
@@ -2577,7 +2752,7 @@ clauses are \fInot\fR taken into account by this function.
.TP
.B language()
Returns a \fBSTRING\fR naming the language supported by \fBRemind\fR.
(See "Foreign Language Support.") By default, \fBRemind\fR is compiled
(See "SUPPORT FOR OTHER LANGUAGES") By default, \fBRemind\fR is compiled
to support English messages, so this function returns "English". For
other languages, this function will return the English name of the
language (e.g. "German") Note that \fBlanguage()\fR is not available
@@ -2848,9 +3023,26 @@ not be executed.
.PP
If \fImaxlen\fR is specified, then \fBshell()\fR returns the first
\fImaxlen\fR characters of output (rather than the first 511). If
\fImaxlen\fR is specified as a negative number, then \fIall\fR the
output from \fIcmd\fR is returned.
\fImaxlen\fR is specified as a negative number, then it defaults to
the value of the system variable \fB$MaxStringLen\fR.
.RE
.TP
.B shellescape(s_str)
Returns \fIstr\fR with all shell metacharacters such as " ", "*", etc
escaped with a backslash. For example:
.PP
.nf
SET a shellescape("a b*? c&d$e")
.fi
.RS
.PP
will set \fBa\fR to:
.RE
.PP
.nf
"a\\ b\\*\\?\\ c\\&d\\$e"
.fi
.TP
.B slide(d_start, i_amt [,s_wkday...])
This function is the inverse of \fBnonomitted\fR. It adds \fIamt\fR
@@ -2878,7 +3070,8 @@ takes \fIa\fR back to 2009-05-13.
.RE
.TP
.B strlen(s_str)
Returns the length of \fIstr\fR.
Returns the length of \fIstr\fR. If the length of \fIstr\fR is too large
to represent as an integers, emits a "Number too high" error.
.TP
.B substr(s_str, i_start [,i_end])
Returns a \fBSTRING\fR consisting of all characters in \fIstr\fR from
@@ -3004,18 +3197,17 @@ Returns (as a \fBDATE\fR type) the \fBFROM\fR parameter of the last \fBREM\fR or
.TP
.B trigger(d_date [,t_time [,i_utcflag]]) \fRor\fB trigger(q_datetime [,i_utcflag])
Returns a string suitable for use in a \fBREM\fR command or a \fBSCANFROM\fR
or UNTIL clause, allowing you to calculate trigger dates in advance.
Note that in earlier versions of \fBRemind\fR, \fBtrigger\fR was
required to convert a date into something the \fBREM\fR command could
consume. However, in this version of \fBRemind\fR, you can omit it.
Note that \fBtrigger()\fR \fIalways\fR returns its result in English,
even for foreign-language versions of \fBRemind\fR. This is to avoid
problems with certain C libraries that do not handle accented
characters properly. Normally, the \fIdate\fR and \fItime\fR are the
local date and time; however, if \fIutcflag\fR is non-zero, the
\fIdate\fR and \fItime\fR are interpreted as UTC times, and are
converted to local time. Examples:
Returns a string suitable for use in a \fBREM\fR command or a
\fBSCANFROM\fR or UNTIL clause, allowing you to calculate trigger
dates in advance. Note that in earlier versions of \fBRemind\fR,
\fBtrigger\fR was required to convert a date into something the
\fBREM\fR command could consume. However, in this version of
\fBRemind\fR, you can omit it. Note that \fBtrigger()\fR \fIalways\fR
returns its result in English, even for non-English versions of
\fBRemind\fR. Normally, the \fIdate\fR and \fItime\fR are the local
date and time; however, if \fIutcflag\fR is non-zero, the \fIdate\fR
and \fItime\fR are interpreted as UTC times, and are converted to
local time. Examples:
.RS
.PP
trigger('1993/04/01')
@@ -3633,6 +3825,14 @@ We could also have written:
but this would result in more iterations, since "Fridays" occur more
often than "13ths of the month."
.PP
Here is another example: Suppose you want to be reminded of something
on the 15th of January, April, July, and October. You could make
four separate reminders, or you could use:
.PP
.nf
REM 15 SATISFY [isany($Tm, 1, 4, 7, 10)] MSG 15th Reminder!
.fi
.PP
This technique of using one \fBREM\fR command to calculate a trigger date
to be used by another command is quite powerful. For example, suppose
you wanted to OMIT Labour day, which is the first Monday in September. You
@@ -4256,23 +4456,42 @@ error messages. For an example of this, define the following:
fset msgprefix(x) x/0
.fi
.PP
.SH FOREIGN LANGUAGE SUPPORT
.SH SUPPORT FOR OTHER LANGUAGES
.PP
Your version of \fBRemind\fR may have been compiled to support a
language other than English. This support may or may not be complete -
for example, all error and usage messages may still be in English.
However, at a minimum, foreign-language versions of \fBRemind\fR will
output names of months and weekdays in the foreign language. Also,
However, at a minimum, non-English versions of \fBRemind\fR will
output names of months and weekdays in the selected language. Also,
the substitution mechanism will substitute constructs suitable for the
foreign language rather than for English.
selected language rather than for English.
.PP
A foreign-language version of \fBRemind\fR will accept either the English
or foreign-language names of weekdays and months in a reminder script.
However, for compatibility between versions of \fBRemind\fR, you should
use only the English names in your scripts. Also, if your C compiler or
run-time libraries are not "8-bit clean" or don't understand the ISO-Latin
character set, month or day names with accented letters may not be
recognized.
Note that a non-English version of \fBRemind\fR will accept \fIonly\fR
English names of weekdays and months in a reminder script.
.PP
If there is no support for your particular language, you can set
\fBRemind\fR system variables so that calendars are printed using
your language's day and month names. The system variables that you
can set are:
.PP
.TP
.B $Monday, $Tuesday, $Wednesday, $Thursday, $Friday, $Saturday
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
.B $January, $February, $March, $April, $May, $June, $July, $August, $September, $October, $November, $December
Set each of these system variables to a string representing the corresponding
month's name in your language. Strings must be valid UTF-8 strings.
.PP
Note that if you set the day- or month-name system variables, they
should be set in a section of your script that always is evaluated.
If you set them inside an \fBIF\fR statement, for example, results
are unpredictable.
.PP
Note also that the \fBRem2PS\fR back-end does not support the full
range of UTF-8 characters. The \fBTkRemind\fR, \fBrem2html\fR and
\fBrem2pdf\fR back-ends all do support the full UTF-8 range.
.PP
.SH THE HEBREW CALENDAR
.PP
@@ -4685,9 +4904,7 @@ in September. It can move over a range of 7 days. Consider the
following sequence:
.PP
.nf
REM Mon 1 Sept SCANFROM [today()\-7] SATISFY 1
OMIT [trigdate()]
REM Mon 1 Sept SCANFROM [today()\-7] ADDOMIT MSG Labour Day
REM Mon AFTER MSG Hello
.fi
.PP
@@ -4697,14 +4914,11 @@ the current year will continue to be triggered until 7 days after it has
occurred. This allows you to safely use the AFTER keyword as shown.
.PP
As a special case, you can simply use a negative number after SCANFROM;
a negative numbner \-N is interpreted as N days before today. Thus,
a negative number \-N is interpreted as N days before today. Thus,
the previous example could also be written like this:
.PP
.nf
# This form of SCANFROM requires Remind 03.01.17 or later.
REM Mon 1 Sept SCANFROM \-7 SATISFY 1
OMIT [trigdate()]
REM Mon 1 Sept SCANFROM \-7 ADDOMIT MSG Labour Day
REM Mon AFTER MSG Hello
.fi
.PP
@@ -4767,7 +4981,7 @@ was copied largely unmodified from "moontool" by John Walker. The
sunrise and sunset functions use ideas from programs by Michael
Schwartz and Marc T. Kaufman. The Hebrew calendar support was taken
from "hdate" by Amos Shapir. OS/2 support was done by Darrel
Hankerson, Russ Herman, and Norman Walsh. The supported foreign
Hankerson, Russ Herman, and Norman Walsh. The supported
languages and their translators are listed below. Languages marked
"complete" support error messages and usage instructions in that
language; all others only support the substitution filter mechanism
@@ -4836,4 +5050,4 @@ Catalog\fR, Jewish Publication Society of America.
.PP
.SH SEE ALSO
.PP
rem, rem2ps, tkremind
\fBrem\fR(1), \fBrem2ps\fR(1), \fBrem2pdf\fR(1), \fBtkremind\fR(1)

View File

@@ -115,6 +115,8 @@ edit the reminder, thereby gaining access to advanced features of
To print the current month's calendar, click \fBPrint...\fR on the
main calendar window. This brings up the print dialog. Printing
either produces a PostScript file or sends PostScript to a UNIX command.
(If you have \fBrem2pdf\fR installed, you can choose to produce
PDF output rather than PostScript.)
Select the print destination by choosing either \fBTo file:\fR or
\fBTo command:\fR in the print dialog. Press \fBBrowse...\fR to bring
@@ -131,12 +133,13 @@ the directory.
Select the appropriate paper size and orientation. Activate
\fBFill page\fR if you want the calendar to fill the page. This should
be the normal case unless you have many reminders in a particular
day. (See the \fBRem2PS\fR documentation.)
day. (See the \fBRem2PS\fR or \fBrem2pdf\fR documentation.)
Finally, click \fBPrint\fR to print or \fBCancel\fR to cancel. Note
that during printing, \fBRemind\fR is called with the
\fB-itkremind=1\fR option and also an additional \fB-itkprint=1\fR
option.
option. If you are producing PDF output, then the option \fB-itkpdf=1\fR
is also supplied to \fBRemind\fR.
.SH EDITING REMINDERS
@@ -164,7 +167,11 @@ it with \fBTkRemind\fR.
If you have set the "text editor" option correctly, right-clicking
on a reminder will bring up a text editor on the file containing
the reminder. The cursor will be positioned on the line that
generated the reminder.
generated the reminder. In addition, if you have a reminder that
is editable with an editor but was not created using \fBTkRemind\fR,
it will be underlined when you move the cursor over it, and
you can edit it in a text editor by either left- or right-clicking
on the reminder.
.SH BACKGROUND REMINDERS

29
rem2html/Makefile.in Normal file
View File

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

12
rem2html/README.rem2html Normal file
View File

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

View File

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

12
rem2pdf/Makefile.PL.in Normal file
View File

@@ -0,0 +1,12 @@
use ExtUtils::MakeMaker;
WriteMakefile(
NAME => 'Remind::PDF',
AUTHOR => q{Dianne Skoll <dianne@skoll.ca>},
VERSION => '@VERSION@',
PREREQ_PM => {
'Getopt::Long' => 0,
'Cairo' => 0,
'Pango' => 0,
},
EXE_FILES => [ 'bin/rem2pdf' ]
);

43
rem2pdf/Makefile.top.in Normal file
View File

@@ -0,0 +1,43 @@
# Set by configure - don't touch.
srcdir=@srcdir@
prefix=@prefix@
exec_prefix=@exec_prefix@
mandir=@mandir@
bindir=@bindir@
datadir=@datadir@
datarootdir=@datarootdir@
PERL=@PERL@
PERLMODS_NEEDED=Getopt::Long Cairo Pango
all: Makefile
@if test "$(PERL)" = "" ; then \
echo "Not building rem2pdf; Perl is required"; exit 0; fi; \
for m in $(PERLMODS_NEEDED) ; \
do \
$(PERL) -M$$m -e 1 > /dev/null 2>&1; \
if test $$? != 0 ; then echo "Not building rem2pdf; missing $$m"; exit 0; fi; \
done; \
$(MAKE) all && exit 0; \
exit 1;
install:
@if test "$(PERL)" = "" ; then \
echo "Not installing rem2pdf; Perl is required"; exit 0; fi; \
for m in $(PERLMODS_NEEDED) ; \
do \
$(PERL) -M$$m -e 1 > /dev/null 2>&1; \
if test $$? != 0 ; then echo "Not installing rem2pdf; missing $$m"; exit 0; fi; \
done; \
echo "Installing rem2pdf"; \
if test "$(prefix)" = "/usr" ; then \
$(MAKE) install DESTDIR=$(DESTDIR) INSTALLDIRS=vendor && exit 0; \
else \
$(MAKE) install DESTDIR=$(DESTDIR) && exit 0; \
fi; \
exit 1;
Makefile: Makefile.PL
$(PERL) Makefile.PL || true

22
rem2pdf/README Normal file
View File

@@ -0,0 +1,22 @@
rem2pdf is a Perl program that takes the output of "remind -p" and
produces a PDF calendar. See "man rem2pdf" for details.
rem2pdf has the following Perl modules as prerequisites:
Pango - https://metacpan.org/pod/Pango
Cairo - https://metacpan.org/pod/Cairo
On Debian or Debian-derived systems, these can be installed with:
apt install libpango-perl libcairo-perl
On Red Hat or Red Hat-derived systems, you need to install the perl-Pango
and perl-Cairo RPMs, which may require adding other repos to your list of
RPM sources.
rem2pdf is built and installed in the usual Perl program way:
perl Makefile.PL && make && sudo make install
--
Dianne Skoll - <dianne@skoll.ca>

507
rem2pdf/bin/rem2pdf.in Normal file
View File

@@ -0,0 +1,507 @@
#!@PERL@
use strict;
use warnings;
use Encode;
use Cairo;
use Pango;
use Getopt::Long;
my $VERSION = '@VERSION@';
use Remind::PDF;
my $media_to_size = {
"Letter" => [ 612, 792],
"Tabloid" => [ 792, 1224],
"Ledger" => [1224, 792],
"Legal" => [ 612, 1008],
"Statement" => [ 396, 612],
"Executive" => [ 540, 720],
"A3" => [ 842, 1190],
"A4" => [ 595, 842],
"A5" => [ 420, 595],
"B4" => [ 729, 1032],
"B5" => [ 519, 729],
"Folio" => [ 612, 936],
"Quarto" => [ 612, 780],
"10x14" => [ 720, 1008],
};
my $help = 0;
my $settings = {
landscape => 0,
numbers_on_left => 0,
small_calendars => 0,
fill_entire_page => 0,
media => 'Letter',
width => 0,
height => 0,
title_font => 'Helvetica',
header_font => 'Helvetica',
daynum_font => 'Helvetica Bold Oblique',
entry_font => 'Helvetica',
small_cal_font => 'Helvetica',
title_size => 14,
header_size => 14,
daynum_size => 14,
entry_size => 8,
border_size => 4,
line_thickness => 1,
margin_top => 36,
margin_bottom => 36,
margin_left => 36,
margin_right => 36,
verbose => 0,
};
my $me = $0;
$me =~ s/^.*\///;
set_default_media();
sub usage
{
print <<"EOF";
$me (version $VERSION): Convert Remind -pp output to a PDF calendar.
Usage: remind -pp [options] filename | $me [options] > out.pdf
Options:
--landscape, -l Print in landscape orientation
--small-calendars=N Choose location for small calendars
-cN Synonym for --small-calendars=N
--left-numbers, -x Print day numbers on the left
--fill-page, -e Fill the entire page
--media=MEDIA, -mMEDIA Size for specified media
--width=W, -wW Specify media width in 1/72nds of an inch
--height=H, -hH Specify media height in 1/72nds of an inch
--title-font=FONT Specify font for calendar title
--header-font=FONT Specify font for weekday names
--daynum-font=FONT Specify font for day numbers
--entry-font=FONT Specify font for calendar entries
--small-cal-font=FONT Specify font for small calendars
--title-size=S Specify size of font for calendar title in points
--header-size=S Specify size of font for weekday names
--daynum-size=S Specify size of font for day numbers
--entry-size=S Specify size of font for calendar entries
--border-size=S Specify size of gaps between items in 1/72nds of an inch
--line-thickness=S Specify line thickness in 1/72nds of an inch
--margin-top=S Specify top margin size in 1/72nds of an inch
--margin-bottom=S Specify bottom margin size in 1/72nds of an inch
--margin-left=S Specify left margin size in 1/72nds of an inch
--margin-right=S Specify right margin size in 1/72nds of an inch
--verbose, -v Print progress messages
--help Display this help
EOF
}
Getopt::Long::Configure('bundling_values');
my $ret = GetOptions('landscape|l' => \$settings->{landscape},
'small-calendars|c=i' => \$settings->{small_calendars},
'left-numbers|x' => \$settings->{numbers_on_left},
'fill-page|e' => \$settings->{fill_entire_page},
'media|m=s' => \$settings->{media},
'width|w=i' => \$settings->{width},
'height|h=i' => \$settings->{height},
'title-font=s' => \$settings->{title_font},
'header-font=s' => \$settings->{header_font},
'daynum-font=s' => \$settings->{daynum_font},
'entry-font=s' => \$settings->{entry_font},
'small-cal-font=s' => \$settings->{small_cal_font},
'title-size=f' => \$settings->{title_size},
'header-size=f' => \$settings->{header_size},
'daynum-size=f' => \$settings->{daynum_size},
'entry-size=f' => \$settings->{entry_size},
'border-size=f' => \$settings->{border_size},
'line-thickness=f' => \$settings->{line_thickness},
'margin-top=f' => \$settings->{margin_top},
'margin-bottom=f' => \$settings->{margin_bottom},
'margin-left=f' => \$settings->{margin_left},
'margin-right=f' => \$settings->{margin_right},
'verbose|v' => \$settings->{verbose},
'help' => \$help
);
if (!$ret) {
usage();
exit(1);
}
if ($help) {
usage();
exit(0);
}
if ($settings->{width} <= 0 ||
$settings->{height} <= 0) {
my $size = $media_to_size->{ucfirst($settings->{media})};
if (!$size) {
if (lc($settings->{media}) ne 'help') {
print STDERR "Unknown media " . $settings->{media} . "\n";
}
set_default_media();
printf("%-12s Size in 1/72 in\n", "Valid media:");
foreach my $m (sort { $a cmp $b } (keys(%$media_to_size))) {
if ($m eq $settings->{media}) {
print "* ";
} else {
print " ";
}
printf("%-12s %4d x %4d\n", $m,
$media_to_size->{$m}->[0],
$media_to_size->{$m}->[1]);
}
exit(1);
}
$settings->{width} = $size->[0];
$settings->{height} = $size->[1];
}
if ($settings->{landscape}) {
my $tmp = $settings->{width};
$settings->{width} = $settings->{height};
$settings->{height} = $tmp;
}
# Don't read from a terminal
if (-t STDIN) {
print STDERR "I can't read data from a terminal. Please run like this:\n";
print STDERR " remind -pp [options] filename | $me [options] > out.pdf\n";
exit(1);
}
my $done_one = 0;
my $errored_out = 0;
my $surface = Cairo::PdfSurface->create_for_stream(sub { print $_[1] unless $errored_out; }, undef,
$settings->{width}, $settings->{height});
$surface->set_metadata('title', 'Calendar');
$surface->set_metadata('author', 'Remind (https://dianne.skoll.ca/projects/remind/)');
$surface->set_metadata('creator', 'rem2pdf (https://dianne.skoll.ca/projects/remind/)');
$surface->set_metadata('subject', 'Calendar');
my $cr = Cairo::Context->create($surface);
$cr->set_line_width($settings->{line_thickness});
while(1) {
my ($obj, $err) = Remind::PDF->create_from_stream(*STDIN,
{color => 1,
shade => 1,
moon => 1,
pango => 1,
week => 1,});
if (!$obj) {
if (!$done_one) {
$errored_out = 1;
print STDERR "$me: $err\n";
exit(1);
}
last;
}
$done_one = 1;
$obj->render($cr, $settings);
}
$surface->finish();
sub set_default_media
{
my $paper;
$paper = $ENV{PAPERSIZE};
if ($paper && set_media(ucfirst($paper))) {
return 1;
}
if ($ENV{PAPERCONF}) {
if (set_media_from_file($ENV{PAPERCONF})) {
return 1;
}
}
if (set_media_from_file('/etc/papersize')) {
return 1;
}
return set_media('Letter');
}
sub set_media
{
my ($m) = @_;
return 0 unless $media_to_size->{$m};
$settings->{media} = $m;
return 1;
}
sub set_media_from_file
{
my ($fn) = @_;
if (!open(IN, '<', $fn)) {
return 0;
}
while(<IN>) {
chomp;
s/^\s+//;
s/\s+$//;
next if ($_ eq '');
next if ($_ =~ /^#/);
my $m = $_;
close(IN);
return set_media($m);
}
close(IN);
return 0;
}
__END__
=head1 NAME
rem2pdf - draw a PDF calendar from Remind output
=head1 SYNOPSIS
remind -pp [options] file | rem2pdf [options] > output.pdf
=head1 DESCRIPTION
B<rem2pdf> reads the standard input, which should be the results of
running B<remind> with the B<-p>, B<-pp> or B<-ppp> options. It emits
PDF code that draws a calendar to standard output.
B<rem2pdf> uses the Pango text formatting library (L<https://pango.gnome.org/>)
and the Cairo graphics library (L<https://www.cairographics.org/>) to produce
its output. The CPAN modules Pango (L<https://metacpan.org/pod/Pango>)
and Cairo (L<https://metacpan.org/pod/Cairo>) are prerequisites.
B<rem2pdf> assumes that its input stream is valid UTF-8. If this is not
the case, it may render output incorrectly or even fail to render
output at all.
=head1 OPTIONS
=over
=item --landscape, -l
Print the calendar in landscape orientation. Essentially, this swaps
the width and height of the output media.
=item --small-calendars=I<n>, -cI<n>
Control the inclusion of small calendars for the previous and next
month. Possible values for I<n> are:
=over
=item Z<>0
Do not draw any small calendares
=item Z<>1
Place the small calendars at the bottom-right if there is room;
otherwise, place them at the top-left.
=item Z<>2
Place the small calendars at the top-left if there is room; otherwise,
place them at the bottom-right.
=item Z<>3
Place the previous month's small calendar at the top-left and the next
month's at the bottom-right if there is room; otherwise, follow
I<n>=1. A moment's thought reveals that an option which splits the
calendars if there is room and otherwise follows I<n>=2 yields the
same results.
=back
=item --left-numbers, -x
Draw the day numbers in the top-left corner of each day's box rather than
the default top-right.
=item --fill-page, -e
Make the calendar fill the available space on the page.
=item --media=I<media>, -mI<media>
Specify the paper size (Letter, A4, etc.) For a list of valid media sizes,
run:
rem2pdf --media=help
The default media size will be marked with an asterisk.
=item --width=I<n>, -wI<n>, --height=I<m>, -hI<m>
Rather than specifying a named media size, directly specify the width
and height of the output in 1/72ths of an inch. You must specify both
width and height for the options to be respected.
=item --title-font=I<font>
Specify the font used for the calendar title. It can be any font that
the Pango library on your system can use. The default is Helvetica. If
you choose a font with spaces in its name, you may need to quote this
argument.
=item --header-font=I<font>
Specify the font used for the weekday names. The default is Helvetica.
=item --daynum-font=I<font>
Specify the font used for the day numbers. The default is
Helvetica Bold Oblique.
=item --entry-font=I<font>
Specify the font used for calendar entries. The default is Helvetica.
=item --small-cal-font=I<font>
Specify the font used for the small next- and previous-month
calendars. The default is Helvetica.
=item --title-size=I<n>
Specify the size of the title font in 1/72ths of an inch. The default
is 14. This size, and indeed all following sizes, may be specified as
floating-point numbers.
=item --header-size=I<n>
Specify the size of the header font in 1/72ths of an inch. The default is 14.
=item --daynum-size=I<n>
Specify the size of the day number font in 1/72ths of an inch. The
default is 14.
=item --entry-size=I<n>
Specify the size of the calendar entry font in 1/72ths of an inch.
The default is 8.
=item --border-size=I<n>
Specify the size of the blank border between the contents of a calendar
box and the centre of the lines surrounding it, in 1/72ths of an inch.
The default is 4.
=item --line-thickness=I<n>
Specify the thickness of the lines drawn on the calendar. The default is 1.
=item --margin-top=I<n>
The size of the margin at the top of the page in 1/72ths of an inch.
The default is 36.
=item --margin-bottom=I<n>
The size of the margin at the bottom of the page in 1/72ths of an inch.
The default is 36.
=item --margin-left=I<n>
The size of the margin at the left of the page in 1/72ths of an inch.
The default is 36.
=item --margin-right=I<n>
The size of the margin at the right of the page in 1/72ths of an inch.
The default is 36.
=item --verbose, -v
Print (on STDERR) the name of the month and year for each month that
is rendered.
=back
=head1 USAGE
To use B<rem2df>, pipe the output of B<remind> with one of the
B<-p>, B<-pp> or B<-ppp> options into B<rem2pdf>. The PDF output
will be sent to standard output. So for example, to print a 12-month
calendar for the year 2030, use:
remind -pp12 /dev/null Jan 2030 | rem2pdf -e -l -c=3 | lpr
You can concatenate multiple B<remind> runs. For example, the following
will produce a PDF calendar for January through March of 2023, and
June of 2023 (for a total of four pages);
(remind -pp3 Jan 2023 /dev/null ; \
remind -p June 2023 /dev/null) | rem2pdf -e -l -c=3 > cal.pdf
=head1 FORMATTED TEXT
B<rem2pdf> supports a B<SPECIAL> reminder type called B<PANGO>. This
lets you format text using the Pango markup language, described at
L<https://docs.gtk.org/Pango/pango_markup.html>. Here are some
examples:
REM Mon SPECIAL PANGO <b>Bold</b> and <i>italic</i>
REM Tue SPECIAL PANGO <span face="zapf chancery">Fancy</span>
REM Wed SPECIAL PANGO <span foreground="red"><b>Bold red</b></span>
Other back-ends such as B<rem2ps> and B<rem2html> will ignore PANGO
special reminders.
Neither B<remind> nor B<rem2pdf> will check the markup to ensure
it is syntactically correct. If you use invalid Pango markup, the
Pango library will print a warning and B<rem2pdf> will not render any
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
positioned absolutely with respect to the day's box (and is not
counted when calculating the box's height.)
A positive I<x> value positions the left edge of the text I<x> points
to the right of the left side of the calender box, while a negative
I<x> value positions the right edge of the text I<x> points to the left
of the right side of the calender box.
A positive I<y> value positions the top edge of the text I<y> points
below the top of the calender box, while a negative I<y> value
positions the bottom edge of the text I<y> points above the bottom of
the calender box.
If you use absolutely-positioned text, it's up to you to make sure it
doesn't overlap other text; B<rem2pdf> takes no special precautions to
prevent this.
As an example, this places Sunrise and Sunset times at the bottom left
of each calendar box:
REM SPECIAL PANGO @1,-1 <span size="4800"><i>Rise [sunrise($U)] Set [sunset($U)]</i></span>
(Note that Pango expresses font sizes in 1024's of a point, so a size of
4800 works out to about 4.6 points.)
=head1 AUTHOR
B<Rem2PDF> was written by Dianne Skoll <dianne@skoll.ca>
=head1 SEE ALSO
B<remind>, B<rem2ps>

937
rem2pdf/lib/Remind/PDF.pm Normal file
View File

@@ -0,0 +1,937 @@
package Remind::PDF;
use strict;
use warnings;
use Cairo;
use Pango;
use Remind::PDF::Entry;
use Encode;
use JSON::MaybeXS;
=head1 NAME
Remind::PDF - Render a month's worth of Remind data to PDF
=head1 CLASS METHODS
=head2 Remind::PDF->create_from_stream($in, $specials_accepted)
This method reads data from an open file handle C<$in>. C<$specials_accepted>
is a hashref of SPECIAL reminder types to accept; the key is the name of the
SPECIAL (all lower-case) and the value should be 1. Any SPECIAL reminders
not in the hash are ignored.
This function returns a two-element array: C<($obj, $err)>. On success,
C<$obj> will be a C<Remind::PDF> object and C<$err> will be undef. On
failure, C<$obj> will be undef and C<$err> will be an error message.
=cut
sub create_from_stream
{
my ($class, $in, $specials_accepted) = @_;
while (<$in>) {
chomp;
if ($_ eq '# rem2ps begin' ||
$_ eq '# rem2ps2 begin') {
my $self = bless {}, $class;
return $self->read_one_month($in, $_, $specials_accepted);
} elsif ($_ eq '[') {
return Remind::PDF::Multi->create_from_stream($in, $specials_accepted);
}
}
return (undef, "Could not find any remind -p output anywhere");
}
=head2 Remind::PDF->create_from_hash($hash, $specials_accepted)
This method takes data from a hash C<$hash>, which must be one month's
worth of data from C<remind -ppp> output. C<$specials_accepted> is a
hashref of SPECIAL reminder types to accept; the key is the name of
the SPECIAL (all lower-case) and the value should be 1. Any SPECIAL
reminders not in the hash are ignored.
This function returns a two-element array: C<($obj, $err)>. On success,
C<$obj> will be a C<Remind::PDF> object and C<$err> will be undef. On
failure, C<$obj> will be undef and C<$err> will be an error message.
=cut
sub create_from_hash
{
my ($class, $hash, $specials_accepted) = @_;
bless $hash, $class;
my $filtered_entries = [];
for (my $i=0; $i<=31; $i++) {
$filtered_entries->[$i] = [];
}
foreach my $e (@{$hash->{entries}}) {
if ($hash->accept_special($e, $specials_accepted)) {
my $day = $e->{date};
$day =~ s/^\d\d\d\d-\d\d-//;
$day =~ s/^0//;
push(@{$filtered_entries->[$day]}, Remind::PDF::Entry->new_from_hash($e));
}
}
$hash->{entries} = $filtered_entries;
return $hash;
}
=head1 INSTANCE METHODS
=head2 read_one_month($in, $first_line, $specials_accepted)
This function reads one month's worth of data from the file handle
C<$in>. C<$first_line> is the line that was read from C<$in>
just before calling this function. C<$specials_accepted> is a
hashref as documented above.
The return value is the same C<($obj, $err)> two-element array
as C<create_from_stream> returns.
=cut
sub read_one_month
{
my ($self, $in, $first_line, $specials_accepted) = @_;
$self->{entries} = [];
$self->{daynames} = [];
$self->{monthname} = '';
$self->{year} = '';
$self->{daysinmonth} = 0;
$self->{firstwkday} = 0;
$self->{mondayfirst} = 0;
$self->{prevmonthname} = '';
$self->{nextmonthname} = '';
$self->{daysinprevmonth} = 0;
$self->{daysinnextmonth} = 0;
$self->{prevmonthyear} = 0;
$self->{nextmonthyear} = 0;
for (my $i=0; $i<=31; $i++) {
$self->{entries}->[$i] = [];
}
my $line = $in->getline();
chomp($line);
# Month Year Days FirstWkday MondayFirst
if ($line =~ /^(\S+) (\d+) (\d+) (\d+) (\d+)/) {
$self->{monthname} = $1;
$self->{year} = $2;
$self->{daysinmonth} = $3;
$self->{firstwkday} = $4;
$self->{mondayfirst} = $5;
} else {
return (undef, "Cannot interpret line: $line");
}
$self->{monthname} =~ s/_/ /g;
# Day names
$line = $in->getline();
chomp($line);
if ($line =~ /^\S+ \S+ \S+ \S+ \S+ \S+ \S+$/) {
@{$self->{daynames}} = map { s/_/ /g; $_; } (split(/ /, $line));
} else {
return (undef, "Cannot interpret line: $line");
}
# Prev month, num days
$line = $in->getline();
chomp($line);
if ($line =~ /^\S+ \d+$/) {
($self->{prevmonthname}, $self->{daysinprevmonth}) = split(/ /, $line);
} else {
return (undef, "Cannot interpret line: $line");
}
# Next month, num days
$line = $in->getline();
chomp($line);
if ($line =~ /^\S+ \d+$/) {
($self->{nextmonthname}, $self->{daysinnextmonth}) = split(/ /, $line);
} else {
return (undef, "Cannot interpret line: $line");
}
$self->{prevmonthname} =~ s/_/ /g;
$self->{nextmonthname} =~ s/_/ /g;
if ($first_line eq '# rem2ps2 begin') {
# remind -pp format
return $self->read_one_month_pp($in, $specials_accepted);
}
# Old-style "remind -p"
# TODO: Eventually support this?
return $self->read_one_month_p($in, $specials_accepted);
}
=head2 read_one_month_p($in, $specials_accepted)
This function reads one month's worth of data from the file handle
C<$in>, assuming the original "remind -p" format.
C<$specials_accepted> is a hashref as documented above.
The return value is the same C<($obj, $err)> two-element array
as C<create_from_stream> returns.
=cut
sub read_one_month_p
{
my ($self, $in, $specials_accepted) = @_;
my $line;
while ($line = $in->getline()) {
chomp($line);
if ($line eq '# rem2ps end') {
return ($self, undef);
}
# Ignore comments
next if $line =~ /^#/;
my $hash = $self->parse_oldstyle_line($line);
next unless $hash;
my $day = $hash->{date};
$day =~ s/^\d\d\d\d-\d\d-//;
$day =~ s/^0//;
if ($self->accept_special($hash, $specials_accepted)) {
push(@{$self->{entries}->[$day]}, Remind::PDF::Entry->new_from_hash($hash));
}
}
return (undef, "Missing # rem2ps end marker");
}
=head2 parse_oldstyle_line ($line)
This method parses an old-style "remind -p" line
and returns a hashref containing some or all of the
hash keys found in the newer "remind -pp" JSON output.
=cut
sub parse_oldstyle_line
{
my ($self, $line) = @_;
return undef unless $line =~ m|^(\d+)/(\d+)/(\d+) (\S+) (\S+) (\S+) (\S+) (.*)$|;
my $hash = {
date => "$1-$2-$3",
passthru => $4,
tags => $5,
duration => $6,
time => $7,
body => $8};
foreach my $key (qw(passthru tags time duration)) {
delete $hash->{$key} if $hash->{$key} eq '*';
}
if ($hash->{passthru}) {
if ($hash->{passthru} =~ /^(shade|color|colour)$/i) {
if ($hash->{body} =~ /^\s*(\d+)\s+(\d+)\s+(\d+)/) {
$hash->{r} = $1;
$hash->{g} = $2;
$hash->{b} = $3;
}
}
}
return $hash;
}
=head2 read_one_month_pp($in, $specials_accepted)
This function reads one month's worth of data from the file handle
C<$in>, assuming the "remind -pp" partial-JSON format.
C<$specials_accepted> is a hashref as documented above.
The return value is the same C<($obj, $err)> two-element array
as C<create_from_stream> returns.
=cut
sub read_one_month_pp
{
my ($self, $in, $specials_accepted) = @_;
my $json = JSON::MaybeXS->new(utf8 => 0);
my $line;
while ($line = $in->getline()) {
chomp($line);
if ($line eq '# rem2ps2 end') {
return ($self, undef);
}
my $hash;
eval {
$hash = $json->decode($line);
};
if (!$hash) {
return (undef, "Unable to decode JSON: $@");
}
my $day = $hash->{date};
$day =~ s/^\d\d\d\d-\d\d-//;
$day =~ s/^0//;
if ($self->accept_special($hash, $specials_accepted)) {
push(@{$self->{entries}->[$day]}, Remind::PDF::Entry->new_from_hash($hash));
}
}
return (undef, "Missing # rem2ps2 end marker");
}
=head2 accept_special($hash, $specials_accepted)
Given a hashref C<$hash> consisting of one entry parsed
from the "remind -p" stream and a C<$specials_accepted> hash,
return 1 if we should include this entry in the calendar or
0 if mot.
=cut
sub accept_special
{
my ($self, $hash, $specials_accepted) = @_;
return 1 unless exists($hash->{passthru});
return 1 if $specials_accepted->{lc($hash->{passthru})};
return 0;
}
=head2 find_last_special($special, $entries)
Given an array of Reminder entries, find the last
C<$special>-type SPECIAL in the array. Return
the entry if one was found or undef if not.
=cut
sub find_last_special
{
my ($self, $special, $entries) = @_;
my $class = "Remind::PDF::Entry::$special";
my $found = undef;
foreach my $e (@$entries) {
$found = $e if ($e->isa($class));
}
return $found;
}
=head2 render($cr, $settings)
Render a calendar for one month. C<$cr> is a Cairo
drawing context, and C<$settings> is a settings hash
passed in by the caller. See the source code of
C<rem2pdf> for the contents of C<$settings>
=cut
sub render
{
my ($self, $cr, $settings) = @_;
$self->{horiz_lines} = [];
$cr->set_line_cap('square');
my $so_far = $self->draw_title($cr, $settings);
# Top line
push(@{$self->{horiz_lines}}, $so_far);
my $top_line = $so_far;
$so_far = $self->draw_daynames($cr, $settings, $so_far);
# Line under the days
push(@{$self->{horiz_lines}}, $so_far);
# Remaining space on page
$self->{remaining_space} = $settings->{height} - $settings->{margin_bottom} - $so_far;
$self->{minimum_row_height} = $self->{remaining_space} / 9;
# First column
my $first_col = $self->{firstwkday};
if ($self->{mondayfirst}) {
$first_col--;
if ($first_col < 0) {
$first_col = 6;
}
}
# Last column
my $last_col = ($first_col + $self->{daysinmonth} - 1) % 7;
# Number of rows
my $rows = 1;
my $last_day_on_row = 7 - $first_col;
while ($last_day_on_row < $self->{daysinmonth}) {
$last_day_on_row += 7;
$rows++;
}
my $extra_row = 0;
# Add a row for small calendars if necessary
if (($settings->{small_calendars} != 0) && ($first_col == 0) && ($last_col == 6)) {
$rows++;
$extra_row++;
}
# Figure out where to draw the small calendars
my $prevcal_top = 0;
my $nextcal_top = 0;
my $prevcal_bottom = 0;
my $nextcal_bottom = 0;
if ($settings->{small_calendars} == 1) {
if ($last_col <= 4 || ($last_col == 6 && $extra_row)) {
$prevcal_bottom = 1;
$nextcal_bottom = 1;
} else {
$prevcal_top = 1;
$nextcal_top = 1;
}
} elsif ($settings->{small_calendars} == 2) {
if ($first_col >= 2) {
$prevcal_top = 1;
$nextcal_top = 1;
} else {
$prevcal_bottom = 1;
$nextcal_bottom = 1;
}
} elsif ($settings->{small_calendars} == 3) {
if ($first_col >= 1 && $last_col <= 5) {
$prevcal_top = 1;
$nextcal_bottom = 1;
} else {
if ($last_col <= 4 || ($last_col == 6 && $extra_row)) {
$prevcal_bottom = 1;
$nextcal_bottom = 1;
} else {
$prevcal_top = 1;
$nextcal_top = 1;
}
}
}
# Row height if we are filling the page
$self->{row_height} = $self->{remaining_space} / $rows;
my ($start_col, $start_day);
for (my $row = 0; $row < $rows; $row++) {
if ($row == 0) {
$start_day = 1;
$start_col = $first_col;
} else {
$start_col = 0;
}
my $old_so_far = $so_far;
$so_far = $self->draw_row($cr, $settings, $so_far, $row, $start_day, $start_col);
$start_day += 7 - $start_col;
push(@{$self->{horiz_lines}}, $so_far);
if ($row == 0) {
if ($prevcal_top) {
my ($x1, $y1, $x2, $y2) = $self->col_box_coordinates($old_so_far, 0, $so_far - $old_so_far, $settings);
$self->draw_small_calendar($cr, $x1 + $settings->{border_size}, $y1 + $settings->{border_size},
$x2 - $x1 - 2*$settings->{border_size}, $y2 - $y1 - 2*$settings->{border_size},
$settings, $self->{prevmonthname}, $self->{daysinprevmonth}, ($first_col + 35 - $self->{daysinprevmonth}) % 7);
}
if ($nextcal_top) {
my ($x1, $y1, $x2, $y2) = $self->col_box_coordinates($old_so_far, 1, $so_far - $old_so_far, $settings);
$self->draw_small_calendar($cr, $x1 + $settings->{border_size}, $y1 + $settings->{border_size},
$x2 - $x1 - 2*$settings->{border_size}, $y2 - $y1 - 2*$settings->{border_size},
$settings, $self->{nextmonthname}, $self->{daysinnextmonth}, ($last_col + 1) % 7);
}
} elsif ($row == $rows-1) {
if ($prevcal_bottom) {
my ($x1, $y1, $x2, $y2) = $self->col_box_coordinates($old_so_far, 5, $so_far - $old_so_far, $settings);
$self->draw_small_calendar($cr, $x1 + $settings->{border_size}, $y1 + $settings->{border_size},
$x2 - $x1 - 2*$settings->{border_size}, $y2 - $y1 - 2*$settings->{border_size},
$settings, $self->{prevmonthname}, $self->{daysinprevmonth}, ($first_col + 35 - $self->{daysinprevmonth}) % 7);
}
if ($nextcal_bottom) {
my ($x1, $y1, $x2, $y2) = $self->col_box_coordinates($old_so_far, 6, $so_far - $old_so_far, $settings);
$self->draw_small_calendar($cr, $x1 + $settings->{border_size}, $y1 + $settings->{border_size},
$x2 - $x1 - 2*$settings->{border_size}, $y2 - $y1 - 2*$settings->{border_size},
$settings, $self->{nextmonthname}, $self->{daysinnextmonth}, ($last_col + 1) % 7);
}
}
}
if ($so_far > $settings->{height} - $settings->{margin_bottom}) {
print STDERR "WARNING: overfull calendar box\n";
}
# The vertical lines
my $cell = ($settings->{width} - $settings->{margin_left} - $settings->{margin_right}) / 7;
for (my $i=0; $i<=7; $i++) {
$cr->move_to($settings->{margin_left} + $i * $cell, $top_line);
$cr->line_to($settings->{margin_left} + $i * $cell, $so_far);
$cr->stroke();
}
# And the horizontal lines
foreach my $y (@{$self->{horiz_lines}}) {
$cr->move_to($settings->{margin_left}, $y);
$cr->line_to($settings->{width} - $settings->{margin_right}, $y);
$cr->stroke();
}
if ($settings->{verbose}) {
print STDERR "remdp2f: Rendered " . $self->{monthname} . ' ' . $self->{year} . "\n";
}
# Done this page
$cr->show_page();
}
=head2 draw_row($cr, $settings, $so_far, $row, $start_day, $start_col)
Draw a single row in the calendar. C<$cr> is a Cairo drawing context
and C<$settings> is the settings hash passed to C<render>. C<$so_far>
is the Y-coordinate of the top of the row; drawing starts at this
coordinate. C<$start_day> is the day of the month at which the
row starts and C<$start> col is the column number (0-6) at which
to start drawing from C<$start_day>
Returns the Y coordinate at which to start drawing the I<next>
calendar row.
=cut
sub draw_row
{
my ($self, $cr, $settings, $so_far, $row, $start_day, $start_col) = @_;
my $col = $start_col;
my $day = $start_day;
my $height = 0;
# Preview them to figure out the row height...
if (!$settings->{fill_entire_page}) {
while ($col < 7) {
my $h = $self->draw_day($cr, $settings, $so_far, $day, $col, 0);
$height = $h if ($h > $height);
$day++;
$col++;
last if ($day > $self->{daysinmonth});
}
$col = $start_col;
$day = $start_day;
} else {
$height = $self->{row_height} - $settings->{border_size} * 2;
}
if (!$settings->{fill_entire_page} && $height < $self->{minimum_row_height}) {
$height = $self->{minimum_row_height};
}
# Now draw for real
while ($col < 7 && $day <= $self->{daysinmonth}) {
$self->draw_day($cr, $settings, $so_far, $day, $col, $height);
$day++;
$col++;
}
return $so_far + $height + $settings->{border_size};
}
=head2 col_box_coordinates($so_far, $col, $height, $settings)
Returns a four-element array C<($x1, $y1, $x2, $y2)> representing
the bounding box of the calendar box at column C<$col> (0-6). C<$height>
is the height of the box and C<$settings> is the settings hashref
passed to C<render>.
=cut
sub col_box_coordinates
{
my ($self, $so_far, $col, $height, $settings) = @_;
my $cell = ($settings->{width} - $settings->{margin_left} - $settings->{margin_right}) / 7;
return (
$settings->{margin_left} + $cell * $col,
$so_far,
$settings->{margin_left} + $cell * ($col + 1),
$so_far + $height + $settings->{border_size},
);
}
=head2 draw_day($cr, $settings, $so_far, $day, $col, $height)
Renders a single day's worth of reminders. C<$cr> is a Cairo
drawing context and C<$settings> is the settings hash passed
to C<render>. C<$so_far> is the Y-coordinate of the top
of the box and C<$col> is the column number.
C<$height> is the height of the box. If C<$height> is passed
in as zero, then do not actually render anything... instead,
compute how high the box should be. If C<$height> is non-zero,
then it is the height of the box.
Returns the height required for the calendar box.
=cut
sub draw_day
{
my ($self, $cr, $settings, $so_far, $day, $col, $height) = @_;
my $top = $so_far;
my ($x1, $y1, $x2, $y2) = $self->col_box_coordinates($so_far, $col, $height, $settings);
# Do shading if we're in "for real" mode
if ($height) {
my $shade = $self->find_last_special('shade', $self->{entries}->[$day]);
if ($shade) {
$cr->save;
$cr->set_source_rgb($shade->{r} / 255,
$shade->{g} / 255,
$shade->{b} / 255);
$cr->rectangle($x1, $y1, $x2 - $x1, $y2 - $y1);
$cr->fill();
$cr->restore;
}
}
# Draw the day number
my $layout = Pango::Cairo::create_layout($cr);
$layout->set_text($day);
my $desc = Pango::FontDescription->from_string($settings->{daynum_font} . ' ' . $settings->{daynum_size} . 'px');
$layout->set_font_description($desc);
my ($wid, $h) = $layout->get_pixel_size();
# Don't actually draw if we're just previewing to get the cell height
if ($height) {
$cr->save;
if ($settings->{numbers_on_left}) {
$cr->move_to($x1 + $settings->{border_size}, $so_far + $settings->{border_size});
} else {
$cr->move_to($x2 - $settings->{border_size} - $wid, $so_far + $settings->{border_size});
}
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
}
$so_far += $h + 2 * $settings->{border_size};
my $entry_height = 0;
my $done = 0;
foreach my $entry (@{$self->{entries}->[$day]}) {
# Moon and week should not adjust height
if ($entry->isa('Remind::PDF::Entry::moon') ||
$entry->isa('Remind::PDF::Entry::week')) {
$entry->render($self, $cr, $settings, $top, $day, $col, $height);
next;
}
# An absolutely-positioned Pango markup should not adjust height
# either
if ($entry->isa('Remind::PDF::Entry::pango') &&
defined($entry->{atx}) && defined($entry->{aty})) {
$entry->render($self, $cr, $settings, $top, $day, $col, $height);
next;
}
# Shade is done already
if ($entry->isa('Remind::PDF::Entry::shade')) {
next;
}
if ($done) {
$so_far += $settings->{border_size};
$entry_height += $settings->{border_size};
}
$done = 1;
my $h2 = $entry->render($self, $cr, $settings, $so_far, $day, $col, $height);
$entry_height += $h2;
$so_far += $h2;
}
if ($height) {
if ($entry_height > $height) {
print STDERR "WARNING: overfull box at $day " . $self->{monthname} . ' ' . $self->{year} . "\n";
$entry_height = $height;
}
}
return $h + $entry_height + 2 * $settings->{border_size};
}
=head2 draw_daynames($cr, $settings, $so_far)
Draw the weekday names heading. C<$cr> is a Cairo drawing context
and C<$settings> is the settings hash passed to C<render>. C<$so_far>
is the Y-coordinate of the top of the row; drawing starts at this
coordinate.
Returns the Y coordinate at which to start drawing the first
calendar row.
=cut
sub draw_daynames
{
my ($self, $cr, $settings, $so_far) = @_;
my $w = $settings->{width} - $settings->{margin_left} - $settings->{margin_right};
my $cell = $w/7;
$so_far += $settings->{border_size};
my $height = 0;
for (my $i=0; $i<7; $i++) {
my $j;
if ($self->{mondayfirst}) {
$j = ($i + 1) % 7;
} else {
$j = $i;
}
my $layout = Pango::Cairo::create_layout($cr);
$layout->set_text(Encode::decode('UTF-8', $self->{daynames}->[$j]));
my $desc = Pango::FontDescription->from_string($settings->{header_font} . ' ' . $settings->{header_size} . 'px');
$layout->set_font_description($desc);
my ($wid, $h) = $layout->get_pixel_size();
$cr->save;
$cr->move_to($settings->{margin_left} + $i * $cell + $cell/2 - $wid/2, $so_far);
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
if ($h > $height) {
$height = $h;
}
}
return $so_far + $height + $settings->{border_size} * .75;
}
=head2 draw_title($cr, $settings)
Draw the title ("Monthname Year") at the top of the calendar.
C<$cr> is a Cairo drawing context
and C<$settings> is the settings hash passed to C<render>.
Returns the Y coordinate at which to start drawing the row
containing the weekday names.
=cut
sub draw_title
{
my ($self, $cr, $settings) = @_;
my $title = $self->{monthname} . ' ' . $self->{year};
$cr->get_target()->set_page_label($title);
my $layout = Pango::Cairo::create_layout($cr);
$layout->set_text(Encode::decode('UTF-8', $title));
my $desc = Pango::FontDescription->from_string($settings->{title_font} . ' ' . $settings->{title_size} . 'px');
$layout->set_font_description($desc);
my ($w, $h) = $layout->get_pixel_size();
$cr->save();
$cr->move_to($settings->{width}/2 - $w/2, $settings->{margin_top});
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
return $h + $settings->{margin_top} + $settings->{border_size};
}
=head2 draw_small_calendar($cr, $x, $y, $width, $height, $settings, $month, $days, $start_wkday)
Draw a small calendar on the Cairo context C<$cr>. The top left-hand
corner of the box is at C<($x, $y)> and the size of the box is
C<($width, $height>). $settings is the settings hashref passed to
C<render>. C<$month> is the name of the month to draw and C<$days> is
the number of days in the month. Finally, C<$start_wkday> is the
weekday (0=Sunday, 6=Saturday) on which the month starts
=cut
sub draw_small_calendar
{
my ($self, $cr, $x, $y, $width, $height, $settings, $month, $days, $start_wkday) = @_;
my $first_col = $start_wkday;
if ($self->{mondayfirst}) {
$first_col--;
if ($first_col < 0) {
$first_col = 6;
}
}
# Last column
my $last_col = ($first_col + $days - 1) % 7;
# Number of rows
my $rows = 1;
my $last_day_on_row = 7 - $first_col;
while ($last_day_on_row < $days) {
$last_day_on_row += 7;
$rows++;
}
my $layout = Pango::Cairo::create_layout($cr);
my $desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . '10px');
$layout->set_font_description($desc);
$layout->set_text('88 88 88 88 88 88 88');
my ($wid, $h) = $layout->get_pixel_size();
$h += 1;
$h *= ($rows + 2); # row for month name; row for day names
my $scale = $width / $wid;
if (($height / $h) < $scale) {
$scale = $height / $h;
}
my $font_size = int($scale * 10);
$layout = Pango::Cairo::create_layout($cr);
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
$layout->set_font_description($desc);
$layout->set_text('88 ');
($wid, $h) = $layout->get_pixel_size();
$h += 1;
# Month name
$layout = Pango::Cairo::create_layout($cr);
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
$layout->set_font_description($desc);
$layout->set_text(Encode::decode('UTF-8', $month));
my ($mw, $mh) = $layout->get_pixel_size();
$cr->save();
$cr->move_to($x + $width/2 - $mw/2, $y);
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
$y += $h;
# Day names
for (my $col=0; $col <7; $col++) {
my $j;
if ($self->{mondayfirst}) {
$j = ($col + 1) % 7;
} else {
$j = $col;
}
my $day = $self->{daynames}->[$j];
my $l = substr(Encode::decode('UTF-8', $day), 0, 1);
$layout = Pango::Cairo::create_layout($cr);
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
$layout->set_font_description($desc);
$layout->set_text($l);
$cr->save();
$cr->move_to($x + $col*$wid, $y);
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
}
$y += $h;
my $col = $start_wkday;
for (my $d=1; $d <= $days; $d++) {
$desc = Pango::FontDescription->from_string($settings->{small_cal_font} . ' ' . $font_size . 'px');
$layout->set_font_description($desc);
$layout->set_text($d);
$cr->save();
$cr->move_to($x + $col*$wid, $y);
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
$col++;
if ($col > 6) {
$col = 0;
$y += $h;
}
}
}
package Remind::PDF::Multi;
=head1 NAME
Remind::PDF::Multi - A container for multiple months' worth of calendar data
=head1 DESCRIPTION
The C<remind -ppp> output consists of a JSON array with each element
representing one month's worth of reminders. C<Remind::PDF::Multi>
reads this output and returns an instance of itself containing
an array of C<Remind::PDF> objects, one object for each month.
=head1 CLASS METHODS
=head2 Remind::PDF::Multi->create_from_stream($in, $specials_accepted)
This method reads data from an open file handle C<$in>. C<$specials_accepted>
is a hashref of SPECIAL reminder types to accept; the key is the name of the
SPECIAL (all lower-case) and the value should be 1. Any SPECIAL reminders
not in the hash are ignored.
This function returns a two-element array: C<($obj, $err)>. On
success, C<$obj> will be a C<Remind::PDF::Multi> object and C<$err>
will be undef. On failure, C<$obj> will be undef and C<$err> will be
an error message.
=cut
sub create_from_stream
{
my ($class, $in, $specials_accepted) = @_;
my $json = "[\n";
my $right_bracket = 0;
my $right_curly = 0;
while(<$in>) {
$json .= $_;
chomp;
if ($_ eq ']') {
$right_bracket++;
if ($right_bracket == 2 && $right_curly == 1) {
return $class->create_from_json($json, $specials_accepted);
}
} elsif($_ eq '}') {
$right_curly++;
} else {
$right_bracket = 0;
$right_curly = 0;
}
}
return(undef, 'Unable to parse JSON stream');
}
=head2 Remind::PDF::Multi->create_from_stream($json, $specials_accepted)
This method takes data from a JSON string <$json>. C<$specials_accepted>
is a hashref of SPECIAL reminder types to accept; the key is the name of the
SPECIAL (all lower-case) and the value should be 1. Any SPECIAL reminders
not in the hash are ignored.
This function returns a two-element array: C<($obj, $err)>. On
success, C<$obj> will be a C<Remind::PDF::Multi> object and C<$err>
will be undef. On failure, C<$obj> will be undef and C<$err> will be
an error message.
=cut
sub create_from_json
{
my ($class, $json, $specials_accepted) = @_;
my $parser = JSON::MaybeXS->new(utf8 => 0);
my $array;
eval {
$array = $parser->decode($json);
};
if (!$array) {
return (undef, "Unable to decode JSON: $@");
}
if (ref($array) ne 'ARRAY') {
return (undef, "Expecting array; found " . ref($array));
}
my $self = bless { months => []}, $class;
foreach my $m (@$array) {
my ($e, $error) = Remind::PDF->create_from_hash($m, $specials_accepted);
if (!$e) {
return (undef, $error);
}
push(@{$self->{entries}}, $e);
}
return ($self, undef);
}
=head1 INSTANCE METHODS
=head2 render($cr, $settings)
Iterate through all the C<Remind::PDF> objects
and call their C<render> methods. This method
renders as many months worth of calendar data
as were read from the C<remind -ppp> stream
=cut
sub render
{
my ($self, $cr, $settings) = @_;
foreach my $e (@{$self->{entries}}) {
$e->render($cr, $settings);
}
}
1;

View File

@@ -0,0 +1,311 @@
package Remind::PDF::Entry;
use strict;
use warnings;
use Cairo;
use Pango;
use Encode;
=head1 NAME
Remind::PDF::Entry - Representation of one calendar entry
=head1 DESCRIPTION
C<Remind::PDF::Entry> and its subclasses represent one calendar
entry. They can be normal reminder-type entries or SPECIAL reminders.
=head1 CLASS METHODS
=head2 Remind::PDF::Entry->new_from_hash($hash)
Create and return a new C<Remind::PDF::Entry> based on one reminder's
worth of data from C<remind -p>. Returns a C<Remind::PDF::Entry> object,
or in the case of SPECIAL reminders, a subclass of C<Remind::PDF::Entry>.
=cut
sub new_from_hash
{
my ($class, $hash) = @_;
if (exists($hash->{passthru})) {
my $special = lc($hash->{passthru});
if ($special =~ /^(html|htmlclass|week|moon|shade|color|colour|postscript|psfile|pango)$/) {
$special = 'color' if $special eq 'colour';
$class = 'Remind::PDF::Entry::' . $special;
} else {
$class = 'Remind::PDF::Entry::UNKNOWN';
}
}
bless $hash, $class;
$hash->_adjust();
return $hash;
}
# Base class: Set the color to black
sub _adjust
{
my ($self) = @_;
$self->{r} = 0;
$self->{g} = 0;
$self->{b} = 0;
}
=head1 INSTANCE METHODS
=head2 render($pdf, $cr, $settings, $so_far, $day, $col, $height)
Render a single entry. C<$pdf> is the parent C<Remind::PDF>
object. C<$cr> is a Cairo drawing context and C<$settings> is the
usual settings hash. C<$so_far> is the Y-coordinate at which
to start drawing. C<$day> is the month day and C<$col> is
the calendar column. C<$height> is the height of the calendar
box.
If C<$height> is zero, then nothing should actually be drawn,
but the height of the calendar entry should be computed.
Returns the height of the calendar entry.
=cut
sub render
{
my ($self, $pdf, $cr, $settings, $so_far, $day, $col, $height) = @_;
my ($x1, $y1, $x2, $y2) = $pdf->col_box_coordinates($so_far, $col, $height, $settings);
my $layout = Pango::Cairo::create_layout($cr);
$layout->set_width(1024 * ($x2 - $x1 - 2 * $settings->{border_size}));
$layout->set_wrap('word-char');
$layout->set_text(Encode::decode('UTF-8', $self->{body}));
my $desc = Pango::FontDescription->from_string($settings->{entry_font} . ' ' . $settings->{entry_size} . 'px');
$layout->set_font_description($desc);
my ($wid, $h) = $layout->get_pixel_size();
if ($height) {
$cr->save();
$cr->set_source_rgb($self->{r} / 255,
$self->{g} / 255,
$self->{b} / 255);
$cr->move_to($x1 + $settings->{border_size}, $so_far);
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
}
return $h;
}
package Remind::PDF::Entry::html;
use base 'Remind::PDF::Entry';
sub render {}
package Remind::PDF::Entry::htmlclass;
use base 'Remind::PDF::Entry';
sub render {}
package Remind::PDF::Entry::week;
use base 'Remind::PDF::Entry';
sub render
{
my ($self, $pdf, $cr, $settings, $so_far, $day, $col, $height) = @_;
# Do nothing in pre-render mode
return 0 unless $height;
# Render in small text at bottom-right
my ($x1, $y1, $x2, $y2) = $pdf->col_box_coordinates($so_far, $col, $height, $settings);
my $layout = Pango::Cairo::create_layout($cr);
$layout->set_text(Encode::decode('UTF-8', $self->{body}));
my $desc = Pango::FontDescription->from_string($settings->{entry_font} . ' ' . int(0.75 * $settings->{entry_size}) . 'px');
$layout->set_font_description($desc);
my ($wid, $h) = $layout->get_pixel_size();
$cr->save();
$cr->move_to($x2 - $settings->{border_size}/4 - $wid, $y2 - $settings->{border_size}/4 - $h);
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
return 0;
}
package Remind::PDF::Entry::moon;
use base 'Remind::PDF::Entry';
sub _adjust {
my ($self) = @_;
my ($phase, $size, $fontsize, $msg) = split(/\s+/, $self->{body}, 4);
$phase = '' unless defined($phase);
$size = -1 unless defined($size);
$fontsize = -1 unless defined($fontsize);
$msg = '' unless defined($msg);
$self->{phase} = $phase;
$self->{size} = $size;
$self->{fontsize} = $fontsize;
$self->{body} = $msg;
}
sub render
{
my ($self, $pdf, $cr, $settings, $so_far, $day, $col, $height) = @_;
# Do nothing in pre-render mode
return 0 unless $height;
my ($x1, $y1, $x2, $y2) = $pdf->col_box_coordinates($so_far, $col, $height, $settings);
my $layout;
my $bodywidth = 0;
if ($self->{fontsize} <= 0) {
$self->{fontsize} = $settings->{entry_size};
}
if ($self->{size} <= 0) {
$self->{size} = $settings->{daynum_size};
}
if ($self->{phase} !~ /^[0123]$/) {
# Invalid phase
return 0;
}
if ($self->{body} ne '') {
$layout = Pango::Cairo::create_layout($cr);
$layout->set_text(Encode::decode('UTF-8', $self->{body}));
my $desc = Pango::FontDescription->from_string($settings->{entry_font} . ' ' . $self->{fontsize} . 'px');
$layout->set_font_description($desc);
($bodywidth, undef) = $layout->get_pixel_size();
}
my ($xc, $yc);
if ($settings->{numbers_on_left}) {
$yc = $so_far + $settings->{border_size} + ($self->{size} / 2);
$xc = $x2 - $settings->{border_size} - ($self->{size} / 2);
if ($bodywidth) {
$xc -= ($bodywidth + $settings->{border_size});
}
} else {
$xc = $x1 + $settings->{border_size} + ($self->{size} / 2);
$yc = $so_far + $settings->{border_size} + ($self->{size} / 2);
}
$self->draw_moon($xc, $yc, $cr);
if ($layout) {
$cr->save();
$cr->move_to ($xc + ($self->{size}/2) + $settings->{border_size},
$yc + ($self->{size}/2) - $self->{fontsize} );
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
}
}
sub draw_moon
{
my ($self, $xc, $yc, $cr) = @_;
$cr->save();
$cr->new_path();
$cr->arc($xc, $yc, $self->{size}/2, 0, 2*3.1415926535);
if ($self->{phase} == 0) {
$cr->stroke_preserve();
$cr->fill();
} elsif ($self->{phase} == 1) {
$cr->stroke();
$cr->arc($xc, $yc, $self->{size}/2, 3.1415926535/2, 3 * 3.1415926535/2);
$cr->stroke_preserve();
$cr->fill();
} elsif ($self->{phase} == 2) {
$cr->stroke();
} elsif ($self->{phase} == 3) {
$cr->stroke();
$cr->arc($xc, $yc, $self->{size}/2, 3 * 3.1415926535/2, 3.1415926535/2);
$cr->stroke_preserve();
$cr->fill();
}
$cr->restore();
}
package Remind::PDF::Entry::shade;
use base 'Remind::PDF::Entry';
sub _adjust
{
my ($self) = @_;
if ($self->{body} =~ /^(\d+)\s+(\d+)\s+(\d+)/) {
$self->{r} = $1;
$self->{g} = $2;
$self->{b} = $3;
}
}
package Remind::PDF::Entry::color;
use base 'Remind::PDF::Entry';
# Strip the RGB prefix from body
sub _adjust
{
my ($self) = @_;
$self->{body} =~ s/^\d+\s+\d+\s+\d+\s+//;
}
package Remind::PDF::Entry::postscript;
use base 'Remind::PDF::Entry';
sub render {}
package Remind::PDF::Entry::psfile;
use base 'Remind::PDF::Entry';
sub render {}
package Remind::PDF::Entry::pango;
use base 'Remind::PDF::Entry';
sub _adjust
{
my ($self) = @_;
if ($self->{body} =~ /^@([-0-9.]+),\s*([-0-9.]+)\s*(.*)/) {
$self->{atx} = $1;
$self->{aty} = $2;
$self->{body} = $3;
}
}
sub render
{
my ($self, $pdf, $cr, $settings, $so_far, $day, $col, $height) = @_;
my ($x1, $y1, $x2, $y2) = $pdf->col_box_coordinates($so_far, $col, $height, $settings);
my $layout = Pango::Cairo::create_layout($cr);
$layout->set_width(1024 * ($x2 - $x1 - 2 * $settings->{border_size}));
$layout->set_wrap('word-char');
$layout->set_markup(Encode::decode('UTF-8', $self->{body}));
if (($layout->get_text() // '') eq '') {
# Invalid markup
return 0;
}
my $desc = Pango::FontDescription->from_string($settings->{entry_font} . ' ' . $settings->{entry_size} . 'px');
$layout->set_font_description($desc);
my ($wid, $h) = $layout->get_pixel_size();
if ($height) {
$cr->save();
if (defined($self->{atx}) && defined($self->{aty})) {
my ($x, $y);
if ($self->{atx} < 0) {
$x = $x2 + $self->{atx} - $wid;
} else {
$x = $x1 + $self->{atx};
}
if ($self->{aty} < 0) {
$y = $y2 + $self->{aty} - $h;
} else {
$y = $y1 + $self->{aty};
}
$cr->move_to($x, $y);
} else {
$cr->move_to($x1 + $settings->{border_size}, $so_far);
}
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
}
return $h;
}
package Remind::PDF::Entry::UNKNOWN;
use base 'Remind::PDF::Entry';
sub render {}
1;

View File

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

View File

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

View File

@@ -21,17 +21,6 @@ if {[catch {package require Tcl 8.5}]} {
exit 1
}
# If it's 8.5, try using the Img or the TkPNG package to
# get PNG support
if {[info tclversion] == 8.5} {
if {[catch {package require Img}]} {
if {[catch {package require tkpng}]} {
puts stderr "Tcl/Tk version 8.5 might require either the Img or tkpng"
puts stderr "package to handle PNG images correctly. TkRemind may"
puts stderr "crash because neither of these packages was found."
}
}
}
wm withdraw .
set Hostname [exec hostname]
@@ -68,46 +57,6 @@ QWsg5AAzDZSMbIBeaoHwAUwSDAI2XMAENA8ThAPEBvAStEkc3yonrOW0aUMk
wm iconphoto . -default rpicon
}
# Left and right arrows
image create photo leftarrow -data {
iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAC3XpUWHRSYXcgcHJvZmlsZSB0eXBl
IGV4aWYAAHja7ZdRkuMoDIbfOcUeAUkIieNgA1Vzgz3+/mDa6aR7pmpn52EfYioGK+IX6BNOd+h/
/xjhL1xUJIak5rnkHHGlkgpXDDxe19VTTOt+Xefu6dke7i8YJkEv12Pu27/Cro8Jlrb9eLYH20Ls
W+gj8haUGZkfK/EtJHzZaT+HsufV9Gk7+3O0bdOre31OhmQ0hZ5w4C4kEXefUQQrkCIVd8ZdZDnB
WiUtC4l+n7twD1+Sd49echfrtstzKkLM2yG/5GjbSb/P3crQ5xXRI/LTFyZ3iC+5G6P5GP3aXU0Z
mcphb+pjK2sExwOplDUtoxk+irGtVtAcWzxBrIHmgXYGKsTI9qBEjSoN6qs/6cQSE3c29Mwny7K5
GBc+F5Q0Gw024GlBHDROUJPJ5V4LrbhlxTvJEbkRPJkgNol+aeE74++0W2iMWbpE0e9cYV08axrL
mOTmHV4AQmPnVFd+Vwuf6iZ+AisgqCvNjg3WeFwSh9KjtmRxFvhpTCFeR4OsbQGkCLEViyEBgZhR
zJQpGrMRIY8OPhUrZ0l8gACpcqMwwEYkA47zjI05RsuXlS8zXi0AoZLFgAYHCLBSUtSPJUcNVRVN
QVWzmroWrVlyyppztjzfUdXEkqllM3MrVl08uXp2c/fitXARvMK05GKheCmlVgStkK6YXeFR68GH
HOnQIx92+FGOeqJ8znTqmU87/Sxnbdyk4fi33Cw0b6XVTh2l1FPXnrt176XXgVobMtLQkYcNH2XU
m9qm+kyNXsj9mhptapNYWn72oAaz2YcEzdeJTmYgxolA3CYBFDRPZtEpJZ7kJrNYGIdCGdRIJ5xG
kxgIpk6sg252D3K/5BY0/Stu/DNyYaL7E+TCRLfJfeX2DbVW1y+KLEDzFM6cRhl4scGhe2Wv8zfp
t/vwXwXeQm+ht9Bb6C30FnoL/X+EBv54wL+a4R9jg5HlHbplXQAAAAZiS0dEAP8A/wD/oL2nkwAA
AAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB+MMHwEqD2+Y0soAAABKSURBVCjPY2DADuoZSAC1
DAwM/0lVjFMDI5riJiR+Gz71yCYTwgx1JCj+z8TAwPCRgQyQT6wNjGiaJqDx8QUShk0kO48kUIhL
AgCfBSz4satMtQAAAABJRU5ErkJggg==
}
image create photo rightarrow -data {
iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAC3HpUWHRSYXcgcHJvZmlsZSB0eXBl
IGV4aWYAAHja7ZdRkuMoDIbfOcUeAUkIieNgA1Vzgz3+/mDa6aR7pmpn52EfYipgK7IE/ydId+h/
/xjhL1xUJIak5rnkHHGlkgpX3Hi8rmukmFZ/Xece6dke7i8YJsEo12Pu27/Cro8XLG378WwPtgOx
70AfmXdAmZn5MRPfgYQvO+3nUPZ7NX1azv4cbdv0Gl6fk0GMpognHLgLSUTvM4tgBlKkomf0IssJ
1ippW+R77cJ9+yLeffeiXazbLs9ShJi3Q37RaNtJv9duKfR5RvTI/PSFyZ3ii3ZjNB+jX6urKUOp
HPaiPpay7uB4QMpLjYxm+CjubbWC5ljiCWINNA+0M1AhhtqDEjWqNKiv8aQTU0zc2TAynyzL5mJc
+FxQ0mw02ICnBXHQOEFNJpd7LrTylpXvJEfmRvBkQrBJ9EsL3xl/p92BxpilSxT91grz4lnTmMYk
N3t4AQiNrakufVcLn+omfgIrIKhLZscCazyuEIfSo7ZkcRb4aUwhXluDrO0AkAi5FZMhAYGYSZQy
RWM2Iujo4FMxc5bEBwiQKjcKA2xEMuA4z9x4x2j5svJlxtECECpZDGiwgQArJUX9WHLUUFXRFFQ1
q6lr0Zolp6w5Z8vzjKomlkwtm5lbseriydWzm7sXr4WL4AjTkouF4qWUWpG0InTF2xUetR58yJEO
PfJhhx/lqCfK50ynnvm0089y1sZNGrZ/y81C81Za7dRRSj117blb9156Hai1ISMNHXnY8FFGvalt
qs/U6IXcr6nRpjaJpeVnD2owm32EoHmc6GQGYpwIxG0SQEHzZBadUuJJbjKLhbEplEGNdMJpNImB
YOrEOuhm9yD3S25B07/ixj8jFya6P0EuTHSb3Fdu31Brdf2iyAI0d+HUNMrAwQaH7pW9zt+k3x7D
fw3wDvQO9A70DvQO9A70DvT/CTTwxwP+1Qz/AGOHkeWpKJljAAAABmJLR0QA/wD/AP+gvaeTAAAA
CXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH4wwfASohs07fBQAAAFhJREFUKM9jYMAN6hlIBP8Z
GBhqSdWAoYmFgYGhDSqBCzRB6WZ0kwjhWpgNxIImBgYGRiYSA+IjKU7KZ2BgYGCEMrB5eiISuwCN
jzdY80mJh3xSPFiITRAA3qskpC7RIkIAAAAASUVORK5CYII=
}
proc missing_tcllib { pkg } {
catch { puts stderr "Could not find the '$pkg' package -- you must install tcllib.\nPlease see http://tcllib.sourceforge.net/" }
tk_dialog .err "Error: tcllib not installed" "Could not find the '$pkg' package -- you must install tcllib. Please see http://tcllib.sourceforge.net/" error 0 OK
@@ -188,17 +137,28 @@ set TimerUpdateForChanges ""
# Remind program to execute -- supply full path if you want
set Remind "remind"
#set Remind "/home/dfs/Remind/src/remind"
# Rem2PS program to execute -- supply full path if you want
set Rem2PS "rem2ps"
# Rem2PDF program to execute -- supply full path if you want
set Rem2PDF "rem2pdf"
# Check if we have Rem2PDF
set HaveRem2PDF 0
set a [exec sh -c "$Rem2PDF < /dev/null 2>&1 || true"]
if {[string match "rem2pdf:*" "$a"]} {
set HaveRem2PDF 1
}
# Reminder file to source -- default
set ReminderFile {NOSUCHFILE}
set ReminderFile [file nativename "~/.reminders"]
# Default options file
set ConfigFile ~/.tkremindrc
set ConfigFile ""
set EditorPid -1
@@ -224,12 +184,12 @@ set MondayFirst 0
# Month names in English
set MonthNames {January February March April May June July August September October November December}
# Day names in Remind's pre-selected language
set DayNames {}
# Day name in English
set EnglishDayNames {Sunday Monday Tuesday Wednesday Thursday Friday Saturday}
# Day names in Remind's pre-selected language - will be overwritten
set DayNames $EnglishDayNames
# Current month and year -- will be set by Initialize procedure
set CurMonth -1
set CurYear -1
@@ -238,9 +198,13 @@ set CurYear -1
set BgCounter 0
# Absolutely today -- unlike the CurMonth and CurYear, these won't change
set TodayMonth -1
set TodayYear -1
set TodayDay -1
set now [clock seconds]
set TodayMonth [expr [string trim [clock format $now -format %N]] - 1]
set TodayYear [clock format $now -format %Y]
set TodayDay [string trim [clock format $now -format %e]]
set CurMonth $TodayMonth
set CurYear $TodayYear
# Reminder option types and skip types
set OptionType 1
@@ -251,14 +215,32 @@ set PSCmd {}
# Print options -- destination file; letter-size; landscape; fill page; default
# encoding; 36pt margins; print small calendars
set PrintDest file
set PrintSize letter
set PrintOrient landscape
set PrintFill 1
set PrintDaysRight 1
set PrintEncoding 0
set PrintMargins 36pt
set PrintSmallCalendars 1
set OptDescr(PrintDest) "Print destination: file or command"
set Option(PrintDest) file
set OptDescr(PrintSize) "Page size: a4 or letter"
set Option(PrintSize) letter
set OptDescr(PrintOrient) "Page orientation: portrait or landscape"
set Option(PrintOrient) landscape
set OptDescr(PrintFill) "(0/1) If 1, fill entire page when printing"
set Option(PrintFill) 1
set OptDescr(PrintDaysRight) "(0/1) If 1, put day numbers in the top-right of each calendar box"
set Option(PrintDaysRight) 1
set OptDescr(PrintEncoding) "(0/1) If 1, apply ISO-8859-1 encoding to PostScript output"
set Option(PrintEncoding) 0
set OptDescr(PrintMargins) "Print margins: One of 24pt, 36pt or 48pt"
set Option(PrintMargins) 36pt
set OptDescr(PrintSmallCalendars) "(0/1) If 1, print small calendars in PostScript output"
set Option(PrintSmallCalendars) 1
set OptDescr(PrintFormat) "Print format: pdf or ps"
set Option(PrintFormat) ps
set WarningHeaders [list "# Lines staring with REM TAG TKTAGnnn ... were created by tkremind" "# Do not edit them by hand or results may be unpredictable."]
@@ -298,7 +280,6 @@ proc is_warning_header { line } {
# MondayFirst flag, current date, etc.
#***********************************************************************
proc Initialize {} {
global DayNames argc argv CommandLine ReminderFile AppendFile Remind PSCmd
global MondayFirst TwentyFourHourMode ReminderFileModTime
global Option ConfigFile
@@ -377,7 +358,6 @@ proc Initialize {} {
append CommandLine " $ReminderFile"
append PSCmd " $ReminderFile"
set DayNames [GetWeekdayNames]
# Get modification time of ReminderFile
set ReminderFileModTime -1
@@ -420,40 +400,6 @@ proc MonitorReminderFile {} {
ScheduleUpdateForChanges
}
}
#---------------------------------------------------------------------------
# GetWeekdayNames - Spawn a remind process and get the names of the weekdays
# Also sets CurMonth and CurYear.
#---------------------------------------------------------------------------
proc GetWeekdayNames {} {
global CurMonth CurYear TodayYear TodayMonth TodayDay Remind
set f [open "|$Remind - 2>/dev/null" r+]
puts $f "banner %"
set i 0
while { $i < 7 } {
puts $f "msg \[wkday($i)\]%"
incr i
}
# Get current month and year as long as we're running Remind
puts $f "msg %n%"
puts $f "msg %y%"
puts $f "msg %d%"
puts $f "FLUSH"
flush $f
set ans {}
set i 0
while { $i < 7 } {
lappend ans [gets $f]
incr i
}
set CurMonth [expr [gets $f] - 1]
set CurYear [gets $f]
set TodayDay [gets $f]
set TodayMonth $CurMonth
set TodayYear $CurYear
close $f
return $ans
}
#***********************************************************************
# %PROCEDURE: CalEntryOffset
@@ -524,7 +470,6 @@ proc CreateCalFrame { w dayNames } {
-state disabled -takefocus 0 -cursor {} -font CalboxFont -foreground $Option(TextColor) -background $Option(BackgroundColor)
$w.t$f tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$f"
$w.t$f tag bind REM <ButtonPress-3> "FireEditor $w.t$f"
grid configure $w.l$f -row [expr $i*2+1] -column $j -sticky ew
grid configure $w.t$f -row [expr $i*2+2] -column $j -sticky nsew
}
@@ -552,6 +497,8 @@ proc CreateCalFrame { w dayNames } {
proc ConfigureCalFrame { w firstDay numDays } {
global CurMonth CurYear TodayMonth TodayYear TodayDay
global tk_version Option
CreateMoonWindows
set offset [CalEntryOffset $firstDay]
set first [expr $offset+1]
set last [expr $offset+$numDays]
@@ -638,27 +585,27 @@ proc CreateCalWindow { dayNames } {
CreateCalFrame .cal $dayNames
frame .b -background $Option(WinBackground);
button .b.prev -image leftarrow -width 24 -command {MoveMonth -1} -border 1
button .b.prev -text "\u2b9c" -command {MoveMonth -1} -border 1 -foreground $Option(LabelColor) -background $Option(WinBackground)
balloon_add_help .b.prev "Go to previous month"
button .b.this -text {Today} -command {ThisMonth} -border 1
button .b.this -text {Today} -command {ThisMonth} -border 1 -foreground $Option(LabelColor) -background $Option(WinBackground)
balloon_add_help .b.this "Go to this month"
button .b.next -image rightarrow -width 24 -command {MoveMonth 1} -border 1
button .b.next -text "\u2b9e" -command {MoveMonth 1} -border 1 -foreground $Option(LabelColor) -background $Option(WinBackground)
balloon_add_help .b.next "Go to next month"
button .b.goto -text {Go To Date...} -command {GotoDialog} -border 1
button .b.goto -text {Go To Date...} -command {GotoDialog} -border 1 -foreground $Option(LabelColor) -background $Option(WinBackground)
balloon_add_help .b.goto "Go to a specific date"
button .b.print -text {Print...} -command {DoPrint} -border 1
button .b.print -text {Print...} -command {DoPrint} -border 1 -foreground $Option(LabelColor) -background $Option(WinBackground)
balloon_add_help .b.print "Print a PostScript calendar"
button .b.queue -text {Queue...} -command {DoQueue} -border 1
button .b.queue -text {Queue...} -command {DoQueue} -border 1 -foreground $Option(LabelColor) -background $Option(WinBackground)
balloon_add_help .b.queue "See the queue of pending reminders (debugging purposes only)"
button .b.quit -text {Quit} -command {Quit} -border 1
button .b.quit -text {Quit} -command {Quit} -border 1 -foreground $Option(LabelColor) -background $Option(WinBackground)
balloon_add_help .b.quit "Quit TkRemind"
button .b.options -text {Options...} -command EditOptions -border 1
button .b.options -text {Options...} -command EditOptions -border 1 -foreground $Option(LabelColor) -background $Option(WinBackground)
balloon_add_help .b.options "Set TkRemind options"
label .b.status -text "" -width 25 -relief sunken -border 1
label .b.nqueued -text "" -width 20 -relief sunken -border 1
label .b.status -text "" -width 25 -relief sunken -border 1 -foreground $Option(LabelColor) -background $Option(WinBackground)
label .b.nqueued -text "" -width 20 -relief sunken -border 1 -foreground $Option(LabelColor) -background $Option(WinBackground)
pack .b.prev .b.this .b.next .b.goto .b.print .b.options .b.queue .b.quit -side left -fill both
pack .b.status -side left -fill x -expand 1
pack .b.nqueued -side left -fill x
pack .b.status -side left -fill both -expand 1
pack .b.nqueued -side left -fill both
pack .b -side bottom -fill x -expand 0
pack .cal -side top -fill both -expand 1
wm title . "TkRemind"
@@ -879,12 +826,33 @@ proc ApplyOptions { w } {
# Saves options in specified config file
#***********************************************************************
proc SaveOptions { w } {
global Option OptDescr ConfigFile
global Option OptDescr
ApplyOptions $w
WriteOptionsToFile
FillCalWindow
.h.title configure -background $Option(WinBackground) -foreground $Option(LabelColor)
for {set i 0} {$i < 7} {incr i} {
.cal.day$i configure -foreground $Option(LabelColor) -background $Option(WinBackground)
}
.b.status configure -foreground $Option(LabelColor) -background $Option(WinBackground)
.b.nqueued configure -foreground $Option(LabelColor) -background $Option(WinBackground)
.b configure -background $Option(WinBackground)
.b.prev configure -foreground $Option(LabelColor) -background $Option(WinBackground)
.b.this configure -foreground $Option(LabelColor) -background $Option(WinBackground)
.b.next configure -foreground $Option(LabelColor) -background $Option(WinBackground)
.b.goto configure -foreground $Option(LabelColor) -background $Option(WinBackground)
.b.print configure -foreground $Option(LabelColor) -background $Option(WinBackground)
.b.queue configure -foreground $Option(LabelColor) -background $Option(WinBackground)
.b.quit configure -foreground $Option(LabelColor) -background $Option(WinBackground)
.b.options configure -foreground $Option(LabelColor) -background $Option(WinBackground)
}
set problem [catch {set f [open $ConfigFile "w"]} err]
proc WriteOptionsToFile {} {
global ConfigFile
global Option OptDescr
set problem [catch {set f [open "$ConfigFile.tmp" "w"]} err]
if {$problem} {
tk_dialog .error Error "Can't write $ConfigFile: $err" 0 OK
tk_dialog .error Error "Can't write $ConfigFile.tmp: $err" 0 OK
return
}
@@ -900,11 +868,7 @@ proc SaveOptions { w } {
}
puts $f ""
close $f
FillCalWindow
.h.title configure -background $Option(WinBackground) -foreground $Option(LabelColor)
for {set i 0} {$i < 7} {incr i} {
.cal.day$i configure -foreground $Option(LabelColor) -background $Option(WinBackground)
}
file rename -force "$ConfigFile.tmp" $ConfigFile
}
#***********************************************************************
@@ -1000,13 +964,25 @@ proc FillCalWindow {} {
gets $file line
regexp {^([^ ]*) ([0-9][0-9][0-9][0-9]) ([0-9][0-9]?) ([0-9]) ([0-9])} $line dummy monthName year daysInMonth firstWkday mondayFirst
# Skip day names -- we already have them
set monthName [regsub -all {_} $monthName " "]
# Get the day names
gets $file line
set DayNames {}
foreach day $line {
set day [regsub -all {_} $day " "];
lappend DayNames $day
}
ConfigureCalWindow $monthName $year $firstWkday $daysInMonth
# Update the day names in the calendar window
for {set i 0} {$i < 7} {incr i} {
.cal.day$i configure -text [lindex $DayNames $i]
}
set offset [CalEntryOffset $firstWkday]
set fntag "x"
while { [gets $file line] >= 0 } {
set fntag "x"
# Ignore unless begins with left brace
if { ! [string match "\{*" $line]} {
continue
@@ -1017,7 +993,11 @@ proc FillCalWindow {} {
}
if {[dict exists $obj filename]} {
set fntag [string cat "FILE_" [dict get $obj lineno] "_" [dict get $obj filename]]
set fname [dict get $obj filename]
# Don't make INCLUDECMD output editable
if {![string match "*|" $fname]} {
set fntag [string cat "FILE_" [dict get $obj lineno] "_" $fname]
}
}
set date [dict get $obj date]
@@ -1052,7 +1032,7 @@ proc FillCalWindow {} {
continue
}
"MOON" {
DoMoonSpecial $n $stuff
DoMoonSpecial $n $stuff $fntag
continue
}
"COLOUR" -
@@ -1087,13 +1067,20 @@ proc FillCalWindow {} {
continue
}
.cal.t$n configure -state normal
if {[regexp {TKTAG([0-9]+)} $tag all tagno]} {
if {[regexp {TKTAG([0-9]+)} $tag all tagno] && "$fntag" != "x"} {
.cal.t$n insert end [string trim $stuff] [list REM TAGGED "TKTAG$tagno" "date_$date" $extratags $fntag]
.cal.t$n tag bind "TKTAG$tagno" <Enter> "TaggedEnter .cal.t$n"
.cal.t$n tag bind "TKTAG$tagno" <Leave> "TaggedLeave .cal.t$n"
set TagToObj(TKTAG$tagno) $obj
} else {
.cal.t$n insert end [string trim $stuff] [list REM $extratags $fntag]
if {"$fntag" == "x" } {
.cal.t$n insert end [string trim $stuff] [list REM $extratags]
} else {
.cal.t$n insert end [string trim $stuff] [list REM $extratags $fntag]
.cal.t$n tag bind $fntag <Enter> "EditableEnter .cal.t$n"
.cal.t$n tag bind $fntag <Leave> "EditableLeave .cal.t$n"
.cal.t$n tag bind $fntag <ButtonPress-1> "FireEditor .cal.t$n"
}
}
.cal.t$n insert end "\n"
.cal.t$n configure -state disabled
@@ -1158,8 +1145,9 @@ proc Status { stuff } {
# None
#---------------------------------------------------------------------------
proc DoPrint {} {
global PrintDest PrintSize PrintMargins PrintOrient PrintFill PrintDaysRight PrintEncoding PrintSmallCalendars PrintStatus Rem2PS PSCmd Option
global Rem2PS Rem2PDF HaveRem2PDF PSCmd Option PrintStatus
global CurMonth CurYear MonthNames
catch {destroy .p}
toplevel .p
wm title .p "TkRemind Print..."
@@ -1173,42 +1161,57 @@ proc DoPrint {} {
frame .p.f3a -relief sunken -border 2
frame .p.f4
radiobutton .p.tofile -text "To file: " -variable PrintDest -value file
radiobutton .p.tofile -text "To file: " -variable Option(PrintDest) -value file
entry .p.filename
button .p.browse -text "Browse..." -command PrintFileBrowse
radiobutton .p.tocmd -text "To command: " -variable PrintDest -value command
radiobutton .p.tocmd -text "To command: " -variable Option(PrintDest) -value command
entry .p.command
.p.command insert end "lpr"
if { $HaveRem2PDF } {
frame .p.ff -relief sunken -border 2
label .p.format -text "Output Format:"
radiobutton .p.pdf -text "PDF" -variable Option(PrintFormat) -value pdf
radiobutton .p.ps -text "PostScript" -variable Option(PrintFormat) -value ps
}
label .p.size -text "Paper Size:"
radiobutton .p.letter -text "Letter" -variable PrintSize -value letter
radiobutton .p.a4 -text "A4" -variable PrintSize -value a4
radiobutton .p.letter -text "Letter" -variable Option(PrintSize) -value letter
radiobutton .p.a4 -text "A4" -variable Option(PrintSize) -value a4
label .p.margin -text "Margins:"
radiobutton .p.24pt -text "24pt margins" -variable PrintMargins -value 24pt
radiobutton .p.36pt -text "36pt margins" -variable PrintMargins -value 36pt
radiobutton .p.48pt -text "48pt margins" -variable PrintMargins -value 48pt
radiobutton .p.24pt -text "24pt margins" -variable Option(PrintMargins) -value 24pt
radiobutton .p.36pt -text "36pt margins" -variable Option(PrintMargins) -value 36pt
radiobutton .p.48pt -text "48pt margins" -variable Option(PrintMargins) -value 48pt
label .p.orient -text "Orientation:"
radiobutton .p.landscape -text "Landscape" -variable PrintOrient -value landscape
radiobutton .p.portrait -text "Portrait" -variable PrintOrient -value portrait
radiobutton .p.landscape -text "Landscape" -variable Option(PrintOrient) -value landscape
radiobutton .p.portrait -text "Portrait" -variable Option(PrintOrient) -value portrait
checkbutton .p.fill -text "Fill page" -variable PrintFill
checkbutton .p.right -text "Day numbers at top-right" -variable PrintDaysRight
checkbutton .p.encoding -text "ISO 8859-1 PostScript encoding" -variable PrintEncoding
checkbutton .p.calendars -text "Print small calendars" -variable PrintSmallCalendars
checkbutton .p.fill -text "Fill page" -variable Option(PrintFill)
checkbutton .p.right -text "Day numbers at top-right" -variable Option(PrintDaysRight)
checkbutton .p.encoding -text "ISO 8859-1 PostScript encoding" -variable Option(PrintEncoding)
checkbutton .p.calendars -text "Print small calendars" -variable Option(PrintSmallCalendars)
button .p.print -text "Print" -command {set PrintStatus print}
button .p.cancel -text "Cancel" -command {set PrintStatus cancel}
pack .p.f1 .p.f2 .p.f2a .p.f3 .p.f3a \
-side top -fill both -expand 1 -anchor w
if {$HaveRem2PDF} {
pack .p.f1 .p.ff .p.f2 .p.f2a .p.f3 .p.f3a \
-side top -fill both -expand 1 -anchor w
} else {
pack .p.f1 .p.f2 .p.f2a .p.f3 .p.f3a \
-side top -fill both -expand 1 -anchor w
}
pack .p.fill .p.right .p.encoding .p.calendars -in .p.f3a \
-side top -anchor w -fill none -expand 0
pack .p.f4 -side top -fill both -expand 1 -anchor w
pack .p.f11 .p.f12 -in .p.f1 -side top -fill none -expand 0 -anchor w
pack .p.tofile .p.filename .p.browse -in .p.f11 -side left -fill none -expand 0 -anchor w
pack .p.tocmd .p.command -in .p.f12 -side left -fill none -expand 0 -anchor w
if { $HaveRem2PDF } {
pack .p.format .p.pdf .p.ps -in .p.ff -side top -fill none -expand 0 -anchor w
}
pack .p.size .p.letter .p.a4 -in .p.f2 -side top -fill none -expand 0 -anchor w
pack .p.margin .p.24pt .p.36pt .p.48pt -in .p.f2a -side top -anchor w -fill none -expand 0
pack .p.orient .p.landscape .p.portrait -in .p.f3 -side top -fill none -expand 0 -anchor w
@@ -1230,7 +1233,8 @@ proc DoPrint {} {
if {$PrintStatus == "cancel"} {
return
}
if {$PrintDest == "file"} {
WriteOptionsToFile
if {$Option(PrintDest) == "file"} {
if {$fname == ""} {
tk_dialog .error Error "No filename specified" error 0 Ok
return
@@ -1250,39 +1254,67 @@ proc DoPrint {} {
set fname "| $cmd"
}
# Build the command line
set p [regsub EXTRA $PSCmd $Option(ExtraRemindArgs)]
set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PS"
if {$PrintSize == "letter"} {
append cmd " -m Letter"
if {$HaveRem2PDF && $Option(PrintFormat) == "pdf"} {
set p [regsub EXTRA $PSCmd "-itkpdf=1 $Option(ExtraRemindArgs)"]
set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PDF"
} else {
append cmd " -m A4"
set p [regsub EXTRA $PSCmd $Option(ExtraRemindArgs)]
set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PS"
set Option(PrintFormat) ps
}
if {$PrintMargins == "24pt"} {
append cmd " -or 24 -ol 24 -ot 24 -ob 24"
} elseif {$PrintMargins == "36pt"} {
append cmd " -or 36 -ol 36 -ot 36 -ob 36"
if {$Option(PrintSize) == "letter"} {
if {$Option(PrintFormat) == "ps"} {
append cmd " -m Letter"
} else {
append cmd " --media=Letter"
}
} else {
append cmd " -or 48 -ol 48 -ot 48 -ob 48"
if {$Option(PrintFormat) == "ps"} {
append cmd " -m A4"
} else {
append cmd " --media=A4"
}
}
if {$PrintOrient == "landscape"} {
if {$Option(PrintMargins) == "24pt"} {
if {$Option(PrintFormat) == "ps"} {
append cmd " -or 24 -ol 24 -ot 24 -ob 24"
} else {
append cmd " --margin-right=24 --margin-left=24 --margin-top=24 --margin-bottom=24"
}
} elseif {$Option(PrintMargins) == "36pt"} {
if {$Option(PrintFormat) == "ps"} {
append cmd " -or 36 -ol 36 -ot 36 -ob 36"
} else {
append cmd " --margin-right=36 --margin-left=36 --margin-top=36 --margin-bottom=36"
}
} else {
if {$Option(PrintFormat) == "ps"} {
append cmd " -or 48 -ol 48 -ot 48 -ob 48"
} else {
append cmd " --margin-right=48 --margin-left=48 --margin-top=48 --margin-bottom=48"
}
}
if {$Option(PrintOrient) == "landscape"} {
append cmd " -l"
}
if {$PrintFill} {
if {$Option(PrintFill)} {
append cmd " -e"
}
if {!$PrintDaysRight} {
if {!$Option(PrintDaysRight)} {
append cmd " -x"
}
if {$PrintEncoding} {
append cmd " -i"
if {$Option(PrintEncoding)} {
if {$Option(PrintFormat) == "ps"} {
append cmd " -i"
}
}
if {$PrintSmallCalendars} {
if {$Option(PrintSmallCalendars)} {
append cmd " -c3"
} else {
append cmd " -c0"
@@ -1837,6 +1869,7 @@ proc ModifyDay {d firstDay} {
set oldFocus [focus]
while {1} {
grab .mod
raise .mod
focus .mod.entry
set ModifyDialogResult -1
tkwait variable ModifyDialogResult
@@ -1983,7 +2016,7 @@ proc CreateReminder {w} {
# Check it out!
global Remind
set f [open "|$Remind -arq -e -" r+]
set f [open "|$Remind -arq -e - 2>&1" r+]
puts $f "BANNER %"
puts $f "$rem MSG %"
puts $f "MSG %_%_%_%_"
@@ -2001,13 +2034,17 @@ proc CreateReminder {w} {
return $rem
}
# We used to return YYYY-MM-DD, but reverted to
# day monthname year because this lets Remind produce
# much better error messages.
proc consolidate {y m d} {
global MonthNames
if {![regexp {^[0-9]+$} $m]} {
set m [lsearch -exact $MonthNames $m]
incr m
}
return [format "%04d-%02d-%02d" $y $m $d]
set mname [lindex $MonthNames [expr $m-1]]
return "$d $mname $y"
}
#---------------------------------------------------------------------------
@@ -2521,6 +2558,7 @@ proc ShowQueue { file } {
if {[catch {set obj [::json::json2dict $line]}]} {
continue;
}
set obj [lsort -command sort_q $obj]
foreach q $obj {
$w.t insert end "$q\n"
}
@@ -2528,6 +2566,18 @@ proc ShowQueue { file } {
$w.t configure -state disabled
}
proc sort_q { a b } {
set a_ttime [dict get $a nextttime]
set b_ttime [dict get $b nextttime]
if {$a_ttime < $b_ttime} {
return -1
}
if {$a_ttime > $b_ttime} {
return 1
}
return 0
}
#---------------------------------------------------------------------------
# DaemonReadable
# Arguments:
@@ -2720,8 +2770,8 @@ proc main {} {
close $f
}
}
FindConfigFile
LoadOptions
CreateMoonImages
ShowTodaysReminders
ScanForTags $AppendFile
CreateCalWindow $DayNames
@@ -2804,7 +2854,7 @@ proc ReadTaggedOptions { tag date } {
lappend ans -text-day2 $d
}
if {[dict exists $obj m]} {
set mm [dict get $obj m]
set m [dict get $obj m]
set mm [string trimleft $m 0]
lappend ans -text-mon1 [lindex $MonthNames [expr $mm -1]]
lappend ans -text-mon2 [lindex $MonthNames [expr $mm -1]]
@@ -3069,17 +3119,19 @@ proc ReadTaggedOptions { tag date } {
}
return $ans
}
proc FireEditor { w } {
proc FireEditor { w {fntag ""}} {
global Option
global EditorPid
set tags [$w tag names current]
set index [lsearch -glob $tags "FILE_*"]
if {$index < 0} {
return
if {"$fntag" == ""} {
set tags [$w tag names current]
set index [lsearch -glob $tags "FILE_*"]
if {$index < 0} {
return
}
set fntag [lindex $tags $index]
}
set tag [lindex $tags $index]
if {![regexp {^FILE_([0-9]+)_(.*)} $tag all line file]} {
return
if {![regexp {^FILE_([0-9]+)_(.*)} $fntag all line file]} {
return
}
set editor $Option(Editor)
regsub -all "%s" $editor $file editor
@@ -3132,6 +3184,7 @@ proc TaggedEnter { w } {
$w tag configure $tag -foreground #FF0000
}
}
#***********************************************************************
# %PROCEDURE: TaggedLeave
# %ARGUMENTS:
@@ -3157,6 +3210,35 @@ proc TaggedLeave { w } {
}
}
proc EditableEnter { w } {
set tags [$w tag names current]
set index [lsearch -glob $tags "FILE_*"]
if {$index < 0} {
return
}
set tag [lindex $tags $index]
set c ""
set index [lsearch -glob $tags "clr*"]
if {$index >= 0} {
set ctag [lindex $tags $index]
set c [$w tag cget $ctag -foreground]
}
if {"$c" != ""} {
$w tag configure $tag -underline 1 -underlinefg $c
} else {
$w tag configure $tag -underline 1
}
}
proc EditableLeave { w } {
set tags [$w tag names current]
set index [lsearch -glob $tags "FILE_*"]
if {$index < 0} {
return
}
set tag [lindex $tags $index]
$w tag configure $tag -underline 0
}
#***********************************************************************
# %PROCEDURE: EditTaggedReminder
# %ARGUMENTS:
@@ -3194,6 +3276,7 @@ proc EditTaggedReminder { w } {
tkwait visibility .mod
set oldFocus [focus]
while {1} {
raise .mod
grab .mod
focus .mod.entry
set ModifyDialogResult -1
@@ -3441,12 +3524,13 @@ proc DoShadeSpecial { n r g b } {
# %ARGUMENTS:
# n -- calendar box for moon
# stuff -- Remind command line
# fntag - filename tag, if any
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Handles the "MOON" special -- draws a moon symbol
#***********************************************************************
proc DoMoonSpecial { n stuff } {
proc DoMoonSpecial { n stuff fntag } {
set msg ""
set num [scan $stuff "%d %d %d %s" phase junk1 junk2 msg]
if {$num < 1} {
@@ -3456,18 +3540,34 @@ proc DoMoonSpecial { n stuff } {
return
}
switch -exact -- $phase {
0 { set image new }
1 { set image first }
2 { set image full }
3 { set image last }
0 { set win .moon_new }
1 { set win .moon_first }
2 { set win .moon_full }
3 { set win .moon_last }
}
.cal.t$n configure -state normal
.cal.t$n image create 1.0 -image $image
.cal.t$n window create 1.0 -window $win
if {$msg != ""} {
.cal.t$n insert 1.1 " $msg\n"
if {"$fntag" == "x"} {
.cal.t$n insert 1.1 " $msg\n"
} else {
.cal.t$n insert 1.1 " $msg\n" [list REM $fntag]
.cal.t$n tag bind $fntag <Enter> "EditableEnter .cal.t$n"
.cal.t$n tag bind $fntag <Leave> "EditableLeave .cal.t$n"
.cal.t$n tag bind $fntag <ButtonPress-1> "FireEditor .cal.t$n $fntag"
bind $win <ButtonPress-1> "FireEditor .cal.t$n $fntag"
bind $win <ButtonPress-3> "FireEditor .cal.t$n $fntag"
}
} else {
.cal.t$n insert 1.1 "\n"
if {"$fntag" == "x"} {
.cal.t$n insert 1.1 "\n"
} else {
.cal.t$n insert 1.1 "\n" [list REM $fntag]
.cal.t$n tag bind $fntag <Enter> "EditableEnter .cal.t$n"
.cal.t$n tag bind $fntag <Leave> "EditableLeave .cal.t$n"
.cal.t$n tag bind $fntag <ButtonPress-1> "FireEditor .cal.t$n $fntag"
}
}
.cal.t$n configure -state disabled
}
@@ -3491,19 +3591,52 @@ proc DisplayTime {} {
}
#***********************************************************************
# %PROCEDURE: CreateMoonImages
# %PROCEDURE: CreateMoonWindows
# %ARGUMENTS:
# None
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Creates the moon images "new", "first", "full" and "last"
# Creates the moon windows .moon_new, .moon_first, .moon_full and
# .moon_last
#***********************************************************************
proc CreateMoonImages {} {
image create photo full -data "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADlSURBVDiNrdNBUsJAEAXQlyw4hq4hwWPqTixET6ELkZ16CcAq7oFLqXExjaYgQVNlV/Viev7/6XT/4TjGuME7PiLXUatb8N8xwB12SFjiIXIZtU/MAntEfgvQE4YtHxhiHpjXQ5H7uLhEcaLLAleBvd0Xx9Ha/BdyU+Q5OBV5OKmj7a4YBWdSyNPe4aKHAHkzqcQZNj3JgnNexqE8heyIAulffuFF3kTfIVbBVeu/xoXGGsn2TLJJ/mqkafNiINszySYZdbS90GHlvcgsWktY4TFy7ecxTdvIzahxHQLbyFXUqkPwF2ASRNYgB/PXAAAAAElFTkSuQmCC"
image create photo first -data "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADfSURBVDiNndM9TsNAFATgzy5yjZSAE85JBygETgENUPF3iBCitHAFQkcIhZ/Ryn9gRlrZmp2Z3ef3TBOHOMULPrDBMrhpi/4HI5xjix2+4nmJRbx/Yh7ahvkpRPVV4QDXwT3UQy46zGkAZDgK/iytefvHgCrkJsqZUH6cLnNbABSxd5Jhhf1IbkMXv8Qux7hH1Ic1xvk/jBWy6gavumvtwx7ectwZXkKh7MA95XgObeOtpI2U4zl0kGbpxgiPvwQUcXLrKFchc82f6Ur0PK49azOnmOI4TBu84zm4SV38DeIVYkrYJyNbAAAAAElFTkSuQmCC"
image create photo new -data "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAC6SURBVDiNpdNNbsIwFATgL0HKolchHKBX6yFaBOEyoPYUabvOIVKJRaCL2JX5TRNGGvnJ8ozGz89cYoElPvET+BX2yivn/1Bggw5HHMKa1h2qcPZC/JEIhvh+brIZIY6sorhMYo9hh3KGFzzfa84NZNjDt9OG/ZcH1BlaPE1IAG0+URhxzNGESKPFaHJs9Q0Ziww7HnvGeXSrJhis0jiFfjwnj3I0WRv+TKtr4hQl3lDrZ6QN9Wt654hfWfGDmBpUwDkAAAAASUVORK5CYII="
image create photo last -data "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADmSURBVDiNndMxTsNAEIXhzy5yCyQ6FAgcE7oQheQWUAAl5BIkREoZrgB0GFNkHBl7bURGsryaee/3jHeXdpxjghU+8InXyI0S+n0MMEeBEi+4jfV3vAvMQtsyL0J0j2GtViaeRRMyj8IlsgY8BSijE2Kur/hy09wHKMJrEolhwtwHKDHOsI4OLnoAXfl1jiNsOkR9keE4P8D4q4scbzg5xIxtjie709f1E7siC+9+Gx/8fxvPKtEsklcJSBdgWhcN8ByFR5z+AWgd5QpyE+OUWOJO+zJNU+Z6jHAdgHe7K73CuD5zFT9nCmRDIssCaAAAAABJRU5ErkJggg=="
proc CreateMoonWindows {} {
global Option;
catch { destroy .moon_new }
catch { destroy .moon_first }
catch { destroy .moon_full }
catch { destroy .moon_last }
set extra 1
#set wid [font measure CalboxFont 0]
set wid [font metrics CalboxFont -ascent]
set orig_wid $wid
incr wid $extra
incr wid $extra
incr wid $extra
incr wid $extra
incr orig_wid $extra
incr orig_wid $extra
set w [expr $extra+$orig_wid]
canvas .moon_new -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0
.moon_new create oval $extra $extra $w $w -outline $Option(TextColor) -width 1
canvas .moon_first -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0
.moon_first create oval $extra $extra $w $w -outline $Option(TextColor) -width 1
.moon_first create arc $extra $extra $w $w -outline $Option(TextColor) -fill $Option(TextColor) -start 90 -extent 180 -outline {}
canvas .moon_full -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0
.moon_full create oval $extra $extra $w $w -outline $Option(TextColor) -fill $Option(TextColor) -width 1
canvas .moon_last -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0
.moon_last create oval $extra $extra $w $w -outline $Option(TextColor) -width 1
.moon_last create arc $extra $extra $w $w -outline $Option(TextColor) -fill $Option(TextColor) -start 270 -extent 180 -outline {}
balloon_add_help .moon_new "New Moon"
balloon_add_help .moon_first "First Quarter"
balloon_add_help .moon_full "Full Moon"
balloon_add_help .moon_last "Last Quarter"
}
#***********************************************************************
@@ -3646,7 +3779,7 @@ proc SetFonts {} {
proc SetupInotify {} {
global InotifyFP
global ReminderFile
set failed [catch {set InotifyFP [open "|inotifywait -q -m -e close_write -e move -e create -e delete $ReminderFile" "r"] } ]
set failed [catch {set InotifyFP [open "|inotifywait -r -q -m -e close_write -e move -e create -e delete $ReminderFile < /dev/null 2>/dev/null" "r"] } ]
if {$failed} {
# inotifywait probably not available... meh.
return
@@ -3820,4 +3953,47 @@ proc PickColor {index button} {
raise .opt
}
proc FindConfigFile {} {
global ConfigFile
# If it was set on the command line, use that
if {"$ConfigFile" != ""} {
return
}
set confighome ""
if {[info exists env(XDG_CONFIG_HOME)]} {
set confighome $env(XDG_CONFIG_HOME)
}
if {"$confighome" == ""} {
set confighome "~/.config"
}
# If $confighome does not exist, attempt to
# create it
if {![file exists $confighome]} {
catch { file mkdir $confighome }
}
if {[file isdirectory $confighome]} {
# Migrate .tkremindrc to $confighome/tkremindrc
if {[file exists "~/.tkremindrc"]} {
if {![file exists "$confighome/tkreminderc"]} {
puts "Migrating ~/.tkremindrc to $confighome/tkremindrc"
if {[catch { file copy "~/.tkremindrc" "$confighome/tkremindrc"}]} {
puts "FAILED!\n"
set ConfigFile "~/.tkremindrc"
return
}
catch { file delete "~/.tkremindrc" }
}
set ConfigFile "$confighome/tkremindrc"
return
}
set ConfigFile "$confighome/tkremindrc"
return
}
set ConfigFile "~/.tkremindrc"
}
main

View File

@@ -18,11 +18,10 @@ INSTALL_PROGRAM=@INSTALL_PROGRAM@
INSTALL_DATA=@INSTALL_DATA@
PROGS= remind rem2ps
SCRIPTS= $(srcdir)/../scripts/tkremind $(srcdir)/../scripts/cm2rem.tcl
SCRIPTS= $(srcdir)/../scripts/tkremind
MANS= $(srcdir)/../man/rem2ps.1 $(srcdir)/../man/remind.1 \
$(srcdir)/../man/tkremind.1 $(srcdir)/../man/cm2rem.1 \
$(srcdir)/../man/rem.1
$(srcdir)/../man/tkremind.1 $(srcdir)/../man/rem.1
.SUFFIXES:
.SUFFIXES: .c .o

View File

@@ -5,12 +5,13 @@
/* The code for generating a calendar. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
#define _XOPEN_SOURCE
#include "config.h"
#include "custom.h"
#include <stdio.h>
#include <string.h>
@@ -247,6 +248,28 @@ static void WriteBottomCalLine (void);
static void WriteIntermediateCalLine (void);
static void WriteCalDays (void);
static char const *
despace(char const *s)
{
static char buf[256];
char *t = buf;
if (strlen(s) > sizeof(buf)-1) {
/* Punt. :( */
return s;
}
while (*s) {
if (isspace(*s)) {
*t++ = '_';
} else {
*t++ = *s;
}
s++;
}
*t = 0;
return buf;
}
void PrintJSONString(char const *s)
{
while (*s) {
@@ -268,7 +291,7 @@ void PrintJSONKeyPairInt(char const *name, int val)
{
printf("\"");
PrintJSONString(name);
printf("\":%d, ", val);
printf("\":%d,", val);
}
void PrintJSONKeyPairString(char const *name, char const *val)
@@ -282,7 +305,7 @@ void PrintJSONKeyPairString(char const *name, char const *val)
PrintJSONString(name);
printf("\":\"");
PrintJSONString(val);
printf("\", ");
printf("\",");
}
void PrintJSONKeyPairDate(char const *name, int jul)
@@ -295,7 +318,7 @@ void PrintJSONKeyPairDate(char const *name, int jul)
FromJulian(jul, &y, &m, &d);
printf("\"");
PrintJSONString(name);
printf("\":\"%04d-%02d-%02d\", ", y, m+1, d);
printf("\":\"%04d-%02d-%02d\",", y, m+1, d);
}
@@ -313,7 +336,7 @@ void PrintJSONKeyPairDateTime(char const *name, int dt)
i = k % 60;
printf("\"");
PrintJSONString(name);
printf("\":\"%04d-%02d-%02dT%02d:%02d\", ", y, m+1, d, h, i);
printf("\":\"%04d-%02d-%02dT%02d:%02d\",", y, m+1, d, h, i);
}
@@ -328,7 +351,7 @@ void PrintJSONKeyPairTime(char const *name, int t)
i = t % 60;
printf("\"");
PrintJSONString(name);
printf("\":\"%02d:%02d\", ", h, i);
printf("\":\"%02d:%02d\",", h, i);
}
@@ -346,6 +369,41 @@ static void PutWideChar(wchar_t const wc)
}
#endif
static char const *
get_month_abbrev(char const *mon)
{
static char buf[80];
#ifndef REM_USE_WCHAR
sprintf(buf, "%.3s", mon);
return buf;
#else
char *s;
wchar_t tmp_buf[128];
wchar_t *ws;
int i;
int len;
*buf = 0;
(void) mbstowcs(tmp_buf, mon, 127);
ws = tmp_buf;
s = buf;
for (i=0; i<3; i++) {
if (*ws) {
len = wctomb(s, *ws);
s += len;
if (wcwidth(*ws) == 0) {
i--;
}
ws++;
} else {
break;
}
}
*s = 0;
return buf;
#endif
}
static int make_wchar_versions(CalEntry *e)
{
#ifdef REM_USE_WCHAR
@@ -543,9 +601,11 @@ void ProduceCalendar(void)
ColSpaces = (CalWidth - 9) / 7;
CalWidth = 7*ColSpaces + 8;
/* Run the file once to get potentially-overridden day names */
if (CalMonths) {
FromJulian(JulianToday, &y, &m, &d);
JulianToday = Julian(y, m, 1);
FromJulian(JulianToday, &y, &m, &d);
JulianToday = Julian(y, m, 1);
GenerateCalEntries(-1);
DidAMonth = 0;
if (PsCal == PSCAL_LEVEL3) {
printf("[\n");
@@ -562,6 +622,8 @@ void ProduceCalendar(void)
if (MondayFirst) JulianToday -= (JulianToday%7);
else JulianToday -= ((JulianToday+1)%7);
GenerateCalEntries(-1);
if (!DoSimpleCalendar) {
WriteWeekHeaderLine();
WriteCalDays();
@@ -584,7 +646,7 @@ void ProduceCalendar(void)
static void DoCalendarOneWeek(int nleft)
{
int y, m, d, done, i, l, wd;
char buf[81];
char buf[128];
int LinesWritten = 0;
int OrigJul = JulianToday;
@@ -612,8 +674,8 @@ static void DoCalendarOneWeek(int nleft)
goff();
for (i=0; i<7; i++) {
FromJulian(OrigJul+i, &y, &m, &d);
sprintf(buf, "%d %c%c%c ", d, MonthName[m][0], MonthName[m][1],
MonthName[m][2]);
char const *mon = get_month_name(m);
snprintf(buf, sizeof(buf), "%d %s ", d, get_month_abbrev(mon));
if (OrigJul+i == RealToday)
PrintLeft(buf, ColSpaces, '*');
else
@@ -674,7 +736,7 @@ static void DoCalendarOneWeek(int nleft)
/***************************************************************/
static void DoCalendarOneMonth(void)
{
int y, m, d, mm, yy;
int y, m, d, mm, yy, i, j;
if (!DoSimpleCalendar) WriteCalHeader();
@@ -694,20 +756,26 @@ static void DoCalendarOneMonth(void)
}
if (PsCal < PSCAL_LEVEL3) {
printf("%s %d %d %d %d\n",
MonthName[m], y, DaysInMonth(m, y), (JulianToday+1) % 7,
despace(get_month_name(m)), y, DaysInMonth(m, y), (JulianToday+1) % 7,
MondayFirst);
printf("%s %s %s %s %s %s %s\n",
DayName[6], DayName[0], DayName[1], DayName[2],
DayName[3], DayName[4], DayName[5]);
for (i=0; i<7; i++) {
j=(i+6)%7;
if (i) {
printf(" %s", despace(get_day_name(j)));
} else {
printf("%s", despace(get_day_name(j)));
}
}
printf("\n");
} else {
PrintJSONKeyPairString("monthname", MonthName[m]);
PrintJSONKeyPairString("monthname", get_month_name(m));
PrintJSONKeyPairInt("year", y);
PrintJSONKeyPairInt("daysinmonth", DaysInMonth(m, y));
PrintJSONKeyPairInt("firstwkday", (JulianToday+1) % 7);
PrintJSONKeyPairInt("mondayfirst", MondayFirst);
printf("\"daynames\":[\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"],",
DayName[6], DayName[0], DayName[1], DayName[2],
DayName[3], DayName[4], DayName[5]);
get_day_name(6), get_day_name(0), get_day_name(1), get_day_name(2),
get_day_name(3), get_day_name(4), get_day_name(5));
}
mm = m-1;
if (mm<0) {
@@ -715,9 +783,9 @@ static void DoCalendarOneMonth(void)
} else yy=y;
if (PsCal < PSCAL_LEVEL3) {
printf("%s %d\n", MonthName[mm], DaysInMonth(mm,yy));
printf("%s %d\n", despace(get_month_name(mm)), DaysInMonth(mm,yy));
} else {
PrintJSONKeyPairString("prevmonthname", MonthName[mm]);
PrintJSONKeyPairString("prevmonthname", get_month_name(mm));
PrintJSONKeyPairInt("daysinprevmonth", DaysInMonth(mm, yy));
PrintJSONKeyPairInt("prevmonthyear", yy);
}
@@ -726,9 +794,9 @@ static void DoCalendarOneMonth(void)
mm = 0; yy = y+1;
} else yy=y;
if (PsCal < PSCAL_LEVEL3) {
printf("%s %d\n", MonthName[mm], DaysInMonth(mm,yy));
printf("%s %d\n", despace(get_month_name(mm)), DaysInMonth(mm,yy));
} else {
PrintJSONKeyPairString("nextmonthname", MonthName[mm]);
PrintJSONKeyPairString("nextmonthname", get_month_name(mm));
PrintJSONKeyPairInt("daysinnextmonth", DaysInMonth(mm, yy));
PrintJSONKeyPairInt("nextmonthyear", yy);
printf("\"entries\":[\n");
@@ -797,7 +865,7 @@ static int WriteCalendarRow(void)
PrintLeft("", ColSpaces, ' ');
else {
sprintf(buf, "%d ", d+i-wd);
if (OrigJul+i == RealToday) {
if (Julian(y, m, d+i-wd) == RealToday) {
PrintLeft(buf, ColSpaces-1, '*');
PutChar(' ');
} else {
@@ -863,9 +931,54 @@ static int WriteCalendarRow(void)
/***************************************************************/
static void PrintLeft(char const *s, int width, char pad)
{
#ifndef REM_USE_WCHAR
int len = strlen(s);
printf("%s", s);
while (len++ < width) PutChar(pad);
#else
size_t len = mbstowcs(NULL, s, 0);
int i;
wchar_t static_buf[128];
wchar_t *buf;
wchar_t *ws;
int display_len;
if (!len) {
for (i=0; i<width; i++) {
fputc(pad, stdout);
}
return;
}
if (len + 1 <= 128) {
buf = static_buf;
} else {
buf = calloc(len+1, sizeof(wchar_t));
if (!buf) {
/* Uh-oh... cannot recover */
fprintf(stderr, "%s\n", ErrMsg[E_NO_MEM]);
exit(1);
}
}
(void) mbstowcs(buf, s, len+1);
display_len = wcswidth(buf, len+1);
ws = buf;
for (i=0; i<width;) {
if (*ws) {
PutWideChar(*ws++);
i+= wcwidth(*ws);
} else {
break;
}
}
/* Mop up any potential combining characters */
while (*ws && wcwidth(*ws) == 0) {
PutWideChar(*ws++);
}
for (i=display_len; i<width; i++) fputc(pad, stdout);
if (buf != static_buf) free(buf);
#endif
}
/***************************************************************/
@@ -942,7 +1055,7 @@ static void PrintCentered(char const *s, int width, char *pad)
while (*ws && wcwidth(*ws) == 0) {
PutWideChar(*ws++);
}
for (i=d+len; i<width; i++) fputs(pad, stdout);
for (i=d+display_len; i<width; i++) fputs(pad, stdout);
if (buf != static_buf) free(buf);
#endif
}
@@ -1238,7 +1351,11 @@ static void GenerateCalEntries(int col)
case T_IfTrig: r=DoIfTrig(&p); break;
case T_Else: r=DoElse(&p); break;
case T_EndIf: r=DoEndif(&p); break;
case T_Include: r=DoInclude(&p); break;
case T_Include:
case T_IncludeR: r=DoInclude(&p, tok.type); break;
case T_IncludeCmd: r=DoIncludeCmd(&p); break;
case T_Exit: DoExit(&p); break;
case T_Set: r=DoSet(&p); break;
case T_Fset: r=DoFset(&p); break;
@@ -1295,7 +1412,7 @@ static void WriteCalHeader(void)
int y, m, d;
FromJulian(JulianToday, &y, &m, &d);
sprintf(buf, "%s %d", MonthName[m], y);
sprintf(buf, "%s %d", get_month_name(m), y);
WriteTopCalLine();
@@ -1332,13 +1449,13 @@ static void WriteCalTrailer(void)
/***************************************************************/
static int DoCalRem(ParsePtr p, int col)
{
int oldLen;
size_t oldLen;
Trigger trig;
TimeTrig tim;
Value v;
int r, err;
int jul;
CalEntry *CurCol = CalColumn[col];
CalEntry *CurCol;
CalEntry *e;
char const *s, *s2;
DynamicBuffer buf, obuf, pre_buf, raw_buf;
@@ -1347,6 +1464,11 @@ static int DoCalRem(ParsePtr p, int col)
int is_color, col_r, col_g, col_b;
if (col >= 0) {
CurCol = CalColumn[col];
} else {
CurCol = NULL;
}
is_color = 0;
DBufInit(&buf);
DBufInit(&pre_buf);
@@ -1372,11 +1494,6 @@ static int DoCalRem(ParsePtr p, int col)
}
}
/* Don't include timed reminders in calendar if -a option supplied. */
if (DontIssueAts && tim.ttime != NO_TIME) {
FreeTrig(&trig);
return OK;
}
if (trig.typ == NO_TYPE) {
FreeTrig(&trig);
return E_EOLN;
@@ -1439,6 +1556,27 @@ static int DoCalRem(ParsePtr p, int col)
}
}
/* Add to global OMITs if so indicated */
if (trig.addomit) {
r = AddGlobalOmit(jul);
if (r) {
FreeTrig(&trig);
return r;
}
}
/* If we're not actually generating any calendar entries, we're done */
if (col < 0) {
FreeTrig(&trig);
return OK;
}
/* Don't include timed reminders in calendar if -a option supplied. */
if (DontIssueAts && tim.ttime != NO_TIME) {
FreeTrig(&trig);
return OK;
}
/* Save nonconst_expr flag */
nonconst_expr = p->nonconst_expr;
/* Convert PS and PSF to PASSTHRU */
@@ -1664,7 +1802,9 @@ static int DoCalRem(ParsePtr p, int col)
if(!e->filename) {
if (e->text) free(e->text);
if (e->raw_text) free(e->raw_text);
#ifdef REM_USE_WCHAR
if (e->wc_text) free(e->wc_text);
#endif
free(e);
return E_NO_MEM;
}
@@ -1753,7 +1893,7 @@ static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
printf("\"%s\"", EnglishDayName[i]);
}
}
printf("], ");
printf("],");
}
if (e->trig.d != NO_DAY) {
PrintJSONKeyPairInt("d", e->trig.d);
@@ -1806,7 +1946,7 @@ static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
printf("\"%s\"", EnglishDayName[i]);
}
}
printf("], ");
printf("],");
}
PrintJSONKeyPairDate("until", e->trig.until);
if (e->trig.once != NO_ONCE) {
@@ -1875,7 +2015,7 @@ static void WriteSimpleEntries(int col, int jul)
}
}
DidADay = 1;
printf("{\"date\":\"%04d-%02d-%02d\", ", y, m+1, d);
printf("{\"date\":\"%04d-%02d-%02d\",", y, m+1, d);
WriteSimpleEntryProtocol2(e, jul);
printf("}");
if (PsCal != PSCAL_LEVEL3) {
@@ -1991,9 +2131,9 @@ static void WriteCalDays(void)
goff();
for (i=0; i<7; i++) {
if (!MondayFirst)
PrintCentered(DayName[(i+6)%7], ColSpaces, " ");
PrintCentered(get_day_name((i+6)%7), ColSpaces, " ");
else
PrintCentered(DayName[i%7], ColSpaces, " ");
PrintCentered(get_day_name(i%7), ColSpaces, " ");
gon();
DRAW(tb);
goff();

View File

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

View File

@@ -6,7 +6,7 @@
/* which you can customize. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -22,11 +22,11 @@
/* The default values are initially set to Ottawa, Ontario, Canada. */
/*---------------------------------------------------------------------*/
#define LAT_DEG 45
#define LAT_MIN 24
#define LAT_SEC 0
#define LAT_MIN 25
#define LAT_SEC 30
#define LON_DEG 75
#define LON_MIN 39
#define LON_SEC 0
#define LON_MIN 41
#define LON_SEC 59
#define LOCATION "Ottawa"
/*---------------------------------------------------------------------*/
@@ -58,39 +58,6 @@
#define DATETIMESEP '@'
/* #define DATETIMESEP '/' */
/*---------------------------------------------------------------------*/
/* ISOLATIN1: define it to 1 if you use the */
/* ISO 8859-1 character set instead of ASCII. */
/*---------------------------------------------------------------------*/
#define ISOLATIN1 1
/*---------------------------------------------------------------------*/
/* ISOLATIN2: define it to 1 if you use the */
/* ISO 8859-2 character set instead of ASCII. */
/* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */
/* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */
/* then one are defined as 1, the results are unspecified. */
/*---------------------------------------------------------------------*/
#define ISOLATIN2 0
/*---------------------------------------------------------------------*/
/* IBMEXTENDED: define as 1 if your system uses the IBM extended */
/* character set. */
/* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */
/* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */
/* then one are defined as 1, the results are unspecified. */
/*---------------------------------------------------------------------*/
#define IBMEXTENDED 0
/*---------------------------------------------------------------------*/
/* IBM852: define as 1 if your system uses the IBM CPI-852 extended */
/* character set. */
/* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */
/* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */
/* then one are defined as 1, the results are unspecified. */
/*---------------------------------------------------------------------*/
#define IBM852 0
/*---------------------------------------------------------------------*/
/* WANT_U_OPTION: Comment out the next define to permanently disable */
/* the -u option. */

View File

@@ -6,7 +6,7 @@
/* which you can customize. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -22,11 +22,11 @@
/* The default values are initially set to Ottawa, Ontario, Canada. */
/*---------------------------------------------------------------------*/
#define LAT_DEG 45
#define LAT_MIN 24
#define LAT_SEC 0
#define LAT_MIN 25
#define LAT_SEC 30
#define LON_DEG 75
#define LON_MIN 39
#define LON_SEC 0
#define LON_MIN 41
#define LON_SEC 59
#define LOCATION "Ottawa"
/*---------------------------------------------------------------------*/
@@ -58,39 +58,6 @@
#define DATETIMESEP '@'
/* #define DATETIMESEP '/' */
/*---------------------------------------------------------------------*/
/* ISOLATIN1: define it to 1 if you use the */
/* ISO 8859-1 character set instead of ASCII. */
/*---------------------------------------------------------------------*/
#define ISOLATIN1 1
/*---------------------------------------------------------------------*/
/* ISOLATIN2: define it to 1 if you use the */
/* ISO 8859-2 character set instead of ASCII. */
/* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */
/* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */
/* then one are defined as 1, the results are unspecified. */
/*---------------------------------------------------------------------*/
#define ISOLATIN2 0
/*---------------------------------------------------------------------*/
/* IBMEXTENDED: define as 1 if your system uses the IBM extended */
/* character set. */
/* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */
/* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */
/* then one are defined as 1, the results are unspecified. */
/*---------------------------------------------------------------------*/
#define IBMEXTENDED 0
/*---------------------------------------------------------------------*/
/* IBM852: define as 1 if your system uses the IBM CPI-852 extended */
/* character set. */
/* NOT ALL LANGUAGE MODULES SUPPORT THIS. Note that at most one of */
/* ISOLATIN1, ISOLATIN2, IBMEXTENDED and IBM852 should be 1; if more */
/* then one are defined as 1, the results are unspecified. */
/*---------------------------------------------------------------------*/
#define IBM852 0
/*---------------------------------------------------------------------*/
/* WANT_U_OPTION: Comment out the next define to permanently disable */
/* the -u option. */

View File

@@ -7,7 +7,7 @@
/* commands. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -24,10 +24,6 @@
#include "protos.h"
#include "expr.h"
/* Define the shell characters not to escape */
static char const DontEscapeMe[] =
"1234567890_-=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.,";
static int ParseTimeTrig (ParsePtr s, TimeTrig *tim, int save_in_globals);
static int ParseLocalOmit (ParsePtr s, Trigger *t);
static int ParseScanFrom (ParsePtr s, Trigger *t, int type);
@@ -145,6 +141,14 @@ int DoRem(ParsePtr p)
}
}
/* Add to global OMITs if so indicated */
if (trig.addomit) {
r = AddGlobalOmit(jul);
if (r) {
FreeTrig(&trig);
return r;
}
}
if (PurgeMode) {
if (trig.expired || jul < JulianToday) {
if (p->expr_happened) {
@@ -215,6 +219,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
trig->localomit = NO_WD;
trig->skip = NO_SKIP;
trig->once = NO_ONCE;
trig->addomit = 0;
trig->typ = NO_TYPE;
trig->scanfrom = NO_DATE;
trig->from = NO_DATE;
@@ -229,7 +234,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
DBufInit(&(trig->tags));
trig->passthru[0] = 0;
tim->ttime = NO_TIME;
tim->delta = NO_DELTA;
tim->delta = DefaultTDelta;
tim->rep = NO_REP;
tim->duration = NO_TIME;
if (save_in_globals) {
@@ -284,6 +289,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
break;
case T_MaybeUncomputable:
DBufFree(&buf);
trig->maybe_uncomputable = 1;
break;
@@ -378,6 +384,11 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
trig->once = ONCE_ONCE;
break;
case T_AddOmit:
DBufFree(&buf);
trig->addomit = 1;
break;
case T_Omit:
DBufFree(&buf);
if (trig->omitfunc[0]) {
@@ -478,7 +489,7 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
{
Token tok;
int r;
int seen_delta = 0;
DynamicBuffer buf;
DBufInit(&buf);
@@ -495,8 +506,9 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
case T_Delta:
DBufFree(&buf);
if (tim->delta != NO_DELTA) return E_DELTA_TWICE;
tim->delta = (tok.val > 0) ? tok.val : -tok.val;
if (seen_delta) return E_DELTA_TWICE;
seen_delta = 1;
tim->delta = (tok.val >= 0) ? tok.val : -tok.val;
break;
case T_Rep:
@@ -1147,9 +1159,9 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
FromJulian(LastTriggerDate, &y, &m, &d);
fprintf(ErrFp, "%s(%d): Trig(satisfied) = %s, %d %s, %d",
FileName, LineNo,
DayName[LastTriggerDate % 7],
get_day_name(LastTriggerDate % 7),
d,
MonthName[m],
get_month_name(m),
y);
if (tt->ttime != NO_TIME) {
fprintf(ErrFp, " AT %02d:%02d",
@@ -1230,24 +1242,16 @@ int DoMsgCommand(char const *cmd, char const *msg)
DynamicBuffer execBuffer;
DynamicBuffer buf;
char const *s;
DBufInit(&buf);
DBufInit(&execBuffer);
/* Escape shell characters in msg INCLUDING WHITESPACE! */
for (s=msg; *s; s++) {
if (isspace(*s) || !strchr(DontEscapeMe, *s)) {
if (DBufPutc(&buf, '\\') != OK) {
r = E_NO_MEM;
goto finished;
}
}
if (DBufPutc(&buf, *s) != OK) {
r = E_NO_MEM;
goto finished;
}
/* Escape shell characters in msg */
if (ShellEscape(msg, &buf) != OK) {
r = E_NO_MEM;
goto finished;
}
msg = DBufValue(&buf);
/* Do "%s" substitution */

View File

@@ -6,7 +6,7 @@
/* reminders are triggered. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -219,11 +219,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
L_A_OVER
#else
if (altmode == '*') {
sprintf(s, "%s, %d %s, %d", DayName[jul%7], d,
MonthName[m], y);
sprintf(s, "%s, %d %s, %d", get_day_name(jul%7), d,
get_month_name(m), y);
} else {
sprintf(s, "%s %s, %d %s, %d", L_ON, DayName[jul%7], d,
MonthName[m], y);
sprintf(s, "%s %s, %d %s, %d", L_ON, get_day_name(jul%7), d,
get_month_name(m), y);
}
#endif
SHIP_OUT(s);
@@ -243,9 +243,9 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
L_C_OVER
#else
if (altmode == '*') {
sprintf(s, "%s", DayName[jul%7]);
sprintf(s, "%s", get_day_name(jul%7));
} else {
sprintf(s, "%s %s", L_ON, DayName[jul%7]);
sprintf(s, "%s %s", L_ON, get_day_name(jul%7));
}
#endif
SHIP_OUT(s);
@@ -293,9 +293,9 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
L_G_OVER
#else
if (altmode == '*') {
sprintf(s, "%s, %d %s", DayName[jul%7], d, MonthName[m]);
sprintf(s, "%s, %d %s", get_day_name(jul%7), d, get_month_name(m));
} else {
sprintf(s, "%s %s, %d %s", L_ON, DayName[jul%7], d, MonthName[m]);
sprintf(s, "%s %s, %d %s", L_ON, get_day_name(jul%7), d, get_month_name(m));
}
#endif
SHIP_OUT(s);
@@ -332,11 +332,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
L_J_OVER
#else
if (altmode == '*') {
sprintf(s, "%s, %s %d%s, %d", DayName[jul%7],
MonthName[m], d, plu, y);
sprintf(s, "%s, %s %d%s, %d", get_day_name(jul%7),
get_month_name(m), d, plu, y);
} else {
sprintf(s, "%s %s, %s %d%s, %d", L_ON, DayName[jul%7],
MonthName[m], d, plu, y);
sprintf(s, "%s %s, %s %d%s, %d", L_ON, get_day_name(jul%7),
get_month_name(m), d, plu, y);
}
#endif
SHIP_OUT(s);
@@ -347,11 +347,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
L_K_OVER
#else
if (altmode == '*') {
sprintf(s, "%s, %s %d%s", DayName[jul%7],
MonthName[m], d, plu);
sprintf(s, "%s, %s %d%s", get_day_name(jul%7),
get_month_name(m), d, plu);
} else {
sprintf(s, "%s %s, %s %d%s", L_ON, DayName[jul%7],
MonthName[m], d, plu);
sprintf(s, "%s %s, %s %d%s", L_ON, get_day_name(jul%7),
get_month_name(m), d, plu);
}
#endif
SHIP_OUT(s);
@@ -374,7 +374,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
#ifdef L_M_OVER
L_M_OVER
#else
sprintf(s, "%s", MonthName[m]);
sprintf(s, "%s", get_month_name(m));
#endif
SHIP_OUT(s);
break;
@@ -448,11 +448,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
L_U_OVER
#else
if (altmode == '*') {
sprintf(s, "%s, %d%s %s, %d", DayName[jul%7], d,
plu, MonthName[m], y);
sprintf(s, "%s, %d%s %s, %d", get_day_name(jul%7), d,
plu, get_month_name(m), y);
} else {
sprintf(s, "%s %s, %d%s %s, %d", L_ON, DayName[jul%7], d,
plu, MonthName[m], y);
sprintf(s, "%s %s, %d%s %s, %d", L_ON, get_day_name(jul%7), d,
plu, get_month_name(m), y);
}
#endif
SHIP_OUT(s);
@@ -463,11 +463,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
L_V_OVER
#else
if (altmode == '*') {
sprintf(s, "%s, %d%s %s", DayName[jul%7], d, plu,
MonthName[m]);
sprintf(s, "%s, %d%s %s", get_day_name(jul%7), d, plu,
get_month_name(m));
} else {
sprintf(s, "%s %s, %d%s %s", L_ON, DayName[jul%7], d, plu,
MonthName[m]);
sprintf(s, "%s %s, %d%s %s", L_ON, get_day_name(jul%7), d, plu,
get_month_name(m));
}
#endif
SHIP_OUT(s);
@@ -477,7 +477,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
#ifdef L_W_OVER
L_W_OVER
#else
sprintf(s, "%s", DayName[jul%7]);
sprintf(s, "%s", get_day_name(jul%7));
#endif
SHIP_OUT(s);
break;
@@ -657,13 +657,8 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
break;
case '"':
if (PsCal != PSCAL_LEVEL3) {
if (DBufPutc(dbuf, QUOTE_MARKER) != OK) return E_NO_MEM;
has_quote = 1;
} else {
if (DBufPutc(dbuf, '%') != OK) return E_NO_MEM;
if (DBufPutc(dbuf, c) != OK) return E_NO_MEM;
}
if (DBufPutc(dbuf, QUOTE_MARKER) != OK) return E_NO_MEM;
has_quote = 1;
break;
default:

View File

@@ -6,7 +6,7 @@
/* buffers. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -27,11 +27,11 @@
Doubles the size of dynamic buffer until it has room for at least
'n' characters, not including trailing '\0'
**********************************************************************/
static int DBufMakeRoom(DynamicBuffer *dbuf, int n)
static int DBufMakeRoom(DynamicBuffer *dbuf, size_t n)
{
/* Double size until it's greater than n (strictly > to leave room
for trailing '\0' */
int size = dbuf->allocatedLen;
size_t size = dbuf->allocatedLen;
char *buf;
if (size > n) return OK;

View File

@@ -5,7 +5,7 @@
/* Declaration of functions for manipulating dynamic buffers */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -17,8 +17,8 @@
#define DBUF_STATIC_SIZE 128
typedef struct {
char *buffer;
int len;
int allocatedLen;
size_t len;
size_t allocatedLen;
char staticBuf[DBUF_STATIC_SIZE];
} DynamicBuffer;

View File

@@ -5,7 +5,7 @@
/* Error definitions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* This file contains routines to parse and evaluate */
/* expressions. */
/* */
/* Copyright 1992-2020 by Dianne Skoll */
/* Copyright 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -828,7 +828,7 @@ static int Add(void)
v3.type = STR_TYPE;
l1 = strlen(v1.v.str);
l2 = strlen(v2.v.str);
if (MaxStringLen && (l1 + l2 > (size_t) MaxStringLen)) {
if (MaxStringLen > 0 && (l1 + l2 > (size_t) MaxStringLen)) {
DestroyValue(v1); DestroyValue(v2);
return E_STRING_TOO_LONG;
}
@@ -940,6 +940,11 @@ static int Multiply(void)
}
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
/* Prevent floating-point exception */
if ((v2.v.val == -1 && v1.v.val == INT_MIN) ||
(v1.v.val == -1 && v2.v.val == INT_MIN)) {
return E_2HIGH;
}
int old = v1.v.val;
v1.v.val *= v2.v.val;
if (v2.v.val != 0) {

View File

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

View File

@@ -6,7 +6,7 @@
/* expressions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -58,6 +58,7 @@ static int FADusk (func_info *);
static int FAbs (func_info *);
static int FAccess (func_info *);
static int FAmpm (func_info *);
static int FIsAny (func_info *);
static int FArgs (func_info *);
static int FAsc (func_info *);
static int FBaseyr (func_info *);
@@ -151,6 +152,7 @@ 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);
@@ -238,6 +240,7 @@ BuiltinFunc Func[] = {
{ "hour", 1, 1, 1, FHour },
{ "iif", 1, NO_MAX, 1, FIif },
{ "index", 2, 3, 1, FIndex },
{ "isany", 1, NO_MAX, 1, FIsAny },
{ "isdst", 0, 2, 0, FIsdst },
{ "isleap", 1, 1, 1, FIsleap },
{ "isomitted", 1, 1, 0, FIsomitted },
@@ -267,6 +270,7 @@ BuiltinFunc Func[] = {
{ "realtoday", 0, 0, 0, FRealtoday },
{ "sgn", 1, 1, 1, FSgn },
{ "shell", 1, 2, 0, FShell },
{ "shellescape", 1, 1, 1, FShellescape },
{ "slide", 2, NO_MAX, 0, FSlide },
{ "strlen", 1, 1, 1, FStrlen },
{ "substr", 2, 3, 1, FSubstr },
@@ -407,8 +411,9 @@ static int RetStrVal(char const *s, func_info *info)
if (!s) {
RetVal.v.str = malloc(1);
if (RetVal.v.str) *RetVal.v.str = 0;
} else
} else {
RetVal.v.str = StrDup(s);
}
if (!RetVal.v.str) {
RetVal.type = ERR_TYPE;
@@ -428,7 +433,9 @@ static int FStrlen(func_info *info)
Value *v = &ARG(0);
if (v->type != STR_TYPE) return E_BAD_TYPE;
RetVal.type = INT_TYPE;
RETVAL = strlen(v->v.str);
size_t l = strlen(v->v.str);
if (l > INT_MAX) return E_2HIGH;
RETVAL = (int) l;
return OK;
}
@@ -784,8 +791,8 @@ static int FWkday(func_info *info)
/* Convert 0=Sun to 0=Mon */
ARGV(0)--;
if (ARGV(0) < 0) ARGV(0) = 6;
s = DayName[ARGV(0)];
} else s = DayName[DATEPART(ARG(0)) % 7];
s = get_day_name(ARGV(0));
} else s = get_day_name(DATEPART(ARG(0)) % 7);
return RetStrVal(s, info);
}
@@ -812,7 +819,7 @@ static int FMon(func_info *info)
CacheDay = d;
}
}
s = MonthName[m];
s = get_month_name(m);
return RetStrVal(s, info);
}
@@ -1031,6 +1038,36 @@ static int FPlural(func_info *info)
}
}
/***************************************************************/
/* */
/* FIsAny */
/* Return 1 if the first arg equals any subsequent arg, 0 */
/* otherwise. */
/* */
/***************************************************************/
static int FIsAny(func_info *info)
{
int i;
RetVal.type = INT_TYPE;
RETVAL = 0;
for (i=1; i<Nargs; i++) {
if (ARG(0).type == ARG(i).type) {
if (ARG(0).type == STR_TYPE) {
if (!strcmp(ARGSTR(0), ARGSTR(i))) {
RETVAL = 1;
return OK;
}
} else {
if (ARGV(0) == ARGV(i)) {
RETVAL = 1;
return OK;
}
}
}
}
return OK;
}
/***************************************************************/
/* */
/* FChoose */
@@ -1072,6 +1109,28 @@ static int FOstype(func_info *info)
return RetStrVal("UNIX", info);
}
/***************************************************************/
/* */
/* FShellescape - escape shell meta-characters */
/* */
/***************************************************************/
static int FShellescape(func_info *info)
{
DynamicBuffer buf;
int r;
ASSERT_TYPE(0, STR_TYPE);
DBufInit (&buf);
if (ShellEscape(ARG(0).v.str, &buf) != OK) {
DBufFree(&buf);
return E_NO_MEM;
}
r = RetStrVal(DBufValue(&buf), info);
DBufFree(&buf);
return r;
}
/***************************************************************/
/* */
/* FUpper - convert string to upper-case */
@@ -1515,6 +1574,15 @@ static int FShell(func_info *info)
ASSERT_TYPE(1, INT_TYPE);
maxlen = ARGV(1);
}
/* Don't allow maxlen to exceed the maximum length of
a string variable */
if (MaxStringLen > 0) {
if (maxlen <= 0 || maxlen > MaxStringLen) {
maxlen = MaxStringLen;
}
}
fp = popen(ARGSTR(0), "r");
if (!fp) return E_IO_ERR;
while (1) {
@@ -1528,7 +1596,7 @@ static int FShell(func_info *info)
DBufFree(&buf);
return E_NO_MEM;
}
if (maxlen > 0 && DBufLen(&buf) >= maxlen) {
if (maxlen > 0 && DBufLen(&buf) >= (size_t) maxlen) {
break;
}
}
@@ -2089,12 +2157,8 @@ static int SunStuff(int rise, double cosz, int jul)
} else mins = MinsFromUTC;
/* Get latitude and longitude */
longdeg = (double) LongDeg + (double) LongMin / 60.0
+ (double) LongSec / 3600.0;
latitude = DEGRAD * ((double) LatDeg + (double) LatMin / 60.0
+ (double) LatSec / 3600.0);
longdeg = -Longitude;
latitude = DEGRAD * Latitude;
FromJulian(jul, &year, &mon, &day);
@@ -2348,6 +2412,7 @@ static int FPsshade(func_info *info)
if (!psshade_warned) {
psshade_warned = 1;
Eprint("psshade() is deprecated; use SPECIAL SHADE instead.");
FreshLine = 1;
}
sprintf(s, "/_A LineWidth 2 div def ");
@@ -2403,6 +2468,7 @@ static int FPsmoon(func_info *info)
if (!psmoon_warned) {
psmoon_warned = 1;
Eprint("psmoon() is deprecated; use SPECIAL MOON instead.");
FreshLine = 1;
}
if (size > 0) {
sprintf(sizebuf, "%d", size);

View File

@@ -8,7 +8,7 @@
/* globals.h and err.h */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -17,6 +17,6 @@
#include <stdio.h> /* For defintion of FILE - sigh! */
#include "types.h"
#include "custom.h"
#define MK_GLOBALS
#define MK_GLOBALS 1
#include "globals.h"
#include "err.h"

View File

@@ -7,7 +7,7 @@
/* MK_GLOBALS. Also contains useful macro definitions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -21,6 +21,12 @@
#define INIT(var, val) var
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#define MAX_TRUSTED_USERS 20
#define MINUTES_PER_DAY 1440
#define DaysInYear(y) (((y) % 4) ? 365 : ((!((y) % 100) && ((y) % 400)) ? 365 : 366 ))
@@ -36,6 +42,9 @@ EXTERN int CurMon;
EXTERN int CurYear;
EXTERN int LineNo;
EXTERN int FreshLine;
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
EXTERN INIT( int NumTrustedUsers, 0);
EXTERN INIT( char const *MsgCommand, NULL);
EXTERN INIT( int ShowAllErrors, 0);
EXTERN INIT( int DebugFlag, 0);
@@ -52,6 +61,7 @@ EXTERN INIT( int CalMonths, 0);
EXTERN INIT( int Hush, 0);
EXTERN INIT( int NextMode, 0);
EXTERN INIT( int InfiniteDelta, 0);
EXTERN INIT( int DefaultTDelta, 0);
EXTERN INIT( int DeltaOffset, 0);
EXTERN INIT( int RunDisabled, 0);
EXTERN INIT( int IgnoreOnce, 0);
@@ -114,6 +124,9 @@ EXTERN INIT( int LatSec, LAT_SEC);
EXTERN INIT( int LongDeg, LON_DEG);
EXTERN INIT( int LongMin, LON_MIN);
EXTERN INIT( int LongSec, LON_SEC);
EXTERN INIT( double Longitude, -999.0);
EXTERN INIT( double Latitude, -999.0);
EXTERN INIT( char *Location, LOCATION);
/* UTC calculation stuff */
@@ -155,6 +168,17 @@ EXTERN char *MonthName[]
;
#endif
EXTERN char *DynamicMonthName[]
#ifdef MK_GLOBALS
#if LANG == ENGLISH
= {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"}
#else
= {L_JAN, L_FEB, L_MAR, L_APR, L_MAY, L_JUN,
L_JUL, L_AUG, L_SEP, L_OCT, L_NOV, L_DEC}
#endif
#endif
;
EXTERN char *EnglishDayName[]
#ifdef MK_GLOBALS
= {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
@@ -173,6 +197,18 @@ EXTERN char *DayName[]
;
#endif
EXTERN char *DynamicDayName []
#ifdef MK_GLOBALS
#if LANG == ENGLISH
= {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday", "Sunday"}
#else
= {L_MONDAY, L_TUESDAY, L_WEDNESDAY, L_THURSDAY, L_FRIDAY,
L_SATURDAY, L_SUNDAY}
#endif
#endif
;
EXTERN int MonthDays[]
#ifdef MK_GLOBALS
= {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}

View File

@@ -5,7 +5,7 @@
/* Support for the Hebrew calendar */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/* Derived from code written by Amos Shapir in 1978; revised */
/* 1985. */

View File

@@ -7,7 +7,7 @@
/* in normal mode. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -25,6 +25,10 @@
#include <unistd.h>
#include <sys/ioctl.h>
#ifdef HAVE_INITGROUPS
#include <grp.h>
#endif
#include "types.h"
#include "protos.h"
#include "expr.h"
@@ -72,9 +76,6 @@
* A minus sign alone indicates to take input from stdin
*
**************************************************************/
#if defined(__APPLE__) || defined(__CYGWIN__)
static void rkrphgvba(int x);
#endif
/* For parsing an integer */
#define PARSENUM(var, s) \
@@ -89,6 +90,7 @@ static void ChgUser(char const *u);
static void InitializeVar(char const *str);
static char const *BadDate = "Illegal date on command line\n";
static void AddTrustedUser(char const *username);
static DynamicBuffer default_filename_buf;
@@ -114,7 +116,7 @@ static char const *DefaultFilename(void)
s = getenv("HOME");
if (!s) {
fprintf(stderr, "HOME environment variable not set. Unable to determine reminder file.\n");
exit(1);
exit(EXIT_FAILURE);
}
DBufPuts(&default_filename_buf, s);
DBufPuts(&default_filename_buf, "/.reminders");
@@ -140,12 +142,6 @@ void InitRemind(int argc, char const *argv[])
int x;
int jul;
#if defined(__APPLE__)
rkrphgvba(0);
#elif defined(__CYGWIN__)
rkrphgvba(1);
#endif
jul = NO_DATE;
/* If stdout is a terminal, initialize $FormWidth to terminal width-8,
@@ -172,7 +168,7 @@ void InitRemind(int argc, char const *argv[])
if (getgid() != getegid() ||
getuid() != geteuid()) {
fprintf(ErrFp, "\nRemind should not be installed set-uid or set-gid.\nCHECK YOUR SYSTEM SECURITY.\n");
exit(1);
exit(EXIT_FAILURE);
}
y = NO_YR;
@@ -183,11 +179,14 @@ void InitRemind(int argc, char const *argv[])
RealToday = SystemDate(&CurYear, &CurMon, &CurDay);
if (RealToday < 0) {
fprintf(ErrFp, ErrMsg[M_BAD_SYS_DATE], BASE);
exit(1);
exit(EXIT_FAILURE);
}
JulianToday = RealToday;
FromJulian(JulianToday, &CurYear, &CurMon, &CurDay);
/* Initialize Latitude and Longitude */
set_lat_and_long_from_components();
/* See if we were invoked as "rem" rather than "remind" */
if (argv[0]) {
s = strrchr(argv[0], '/');
@@ -199,6 +198,9 @@ void InitRemind(int argc, char const *argv[])
if (!strcmp(s, "rem")) {
InvokedAsRem = 1;
}
} else {
fprintf(stderr, "Invoked with a NULL argv[0]; bailing because that's just plain bizarre.\n");
exit(1);
}
/* Parse the command-line options */
@@ -217,6 +219,10 @@ void InitRemind(int argc, char const *argv[])
}
while (*arg) {
switch(*arg++) {
case '+':
AddTrustedUser(arg);
while(*arg) arg++;
break;
case '@':
UseVTColors = 1;
@@ -281,7 +287,19 @@ void InitRemind(int argc, char const *argv[])
case 't':
case 'T':
if (!*arg) {
if (*arg == 'T' || *arg == 't') {
arg++;
if (!*arg) {
DefaultTDelta = 5;
} else {
PARSENUM(DefaultTDelta, arg);
if (DefaultTDelta < 0) {
DefaultTDelta = 0;
} else if (DefaultTDelta > 1440) {
DefaultTDelta = 1440;
}
}
} else if (!*arg) {
InfiniteDelta = 1;
} else {
PARSENUM(DeltaOffset, arg);
@@ -330,8 +348,12 @@ void InitRemind(int argc, char const *argv[])
case 'u':
case 'U':
ChgUser(arg);
RunDisabled = RUN_CMDLINE;
if (*arg == '+') {
ChgUser(arg+1);
} else {
RunDisabled = RUN_CMDLINE;
ChgUser(arg);
}
while (*arg) arg++;
break;
case 'z':
@@ -535,7 +557,7 @@ void InitRemind(int argc, char const *argv[])
if (!InvokedAsRem) {
if (i >= argc) {
Usage();
exit(1);
exit(EXIT_FAILURE);
}
InitialFile = argv[i++];
} else {
@@ -633,6 +655,7 @@ void InitRemind(int argc, char const *argv[])
}
}
/* Figure out the offset from UTC */
if (CalculateUTC)
(void) CalcMinsFromUTC(JulianToday, SystemTime(0)/60,
@@ -649,7 +672,7 @@ void InitRemind(int argc, char const *argv[])
#ifndef L_USAGE_OVERRIDE
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2020 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
@@ -682,7 +705,7 @@ void Usage(void)
fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n");
fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n");
fprintf(ErrFp, " -j[n] Run in 'purge' mode. [n = INCLUDE depth]\n");
exit(1);
exit(EXIT_FAILURE);
}
#endif /* L_USAGE_OVERRIDE */
/***************************************************************/
@@ -697,7 +720,7 @@ void Usage(void)
/***************************************************************/
static void ChgUser(char const *user)
{
uid_t myuid;
uid_t myeuid;
struct passwd *pwent;
static char *home;
@@ -705,29 +728,38 @@ static void ChgUser(char const *user)
static char *username;
static char *logname;
myuid = getuid();
myeuid = geteuid();
pwent = getpwnam(user);
if (!pwent) {
fprintf(ErrFp, ErrMsg[M_BAD_USER], user);
exit(1);
exit(EXIT_FAILURE);
}
if (!myuid && setgid(pwent->pw_gid)) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
exit(1);
}
if (!myeuid) {
/* Started as root, so drop privileges */
#ifdef HAVE_INITGROUPS
if (initgroups(pwent->pw_name, pwent->pw_gid) < 0) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
exit(EXIT_FAILURE);
};
#endif
if (setgid(pwent->pw_gid) < 0) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
exit(EXIT_FAILURE);
}
if (!myuid && setuid(pwent->pw_uid)) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid);
exit(1);
if (setuid(pwent->pw_uid) < 0) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid);
exit(EXIT_FAILURE);
}
}
home = malloc(strlen(pwent->pw_dir) + 6);
if (!home) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(home, "HOME=%s", pwent->pw_dir);
putenv(home);
@@ -735,7 +767,7 @@ static void ChgUser(char const *user)
shell = malloc(strlen(pwent->pw_shell) + 7);
if (!shell) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(shell, "SHELL=%s", pwent->pw_shell);
putenv(shell);
@@ -744,14 +776,14 @@ static void ChgUser(char const *user)
username = malloc(strlen(pwent->pw_name) + 6);
if (!username) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(username, "USER=%s", pwent->pw_name);
putenv(username);
logname= malloc(strlen(pwent->pw_name) + 9);
if (!logname) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(logname, "LOGNAME=%s", pwent->pw_name);
putenv(logname);
@@ -824,6 +856,7 @@ static void InitializeVar(char const *str)
if (*varname == '$') {
r=SetSysVar(varname+1, &val);
DestroyValue(val);
if (r) fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
return;
}
@@ -838,46 +871,22 @@ static void InitializeVar(char const *str)
return;
}
#if defined(__APPLE__) || defined(__CYGWIN__)
static char const pmsg1[] = {
0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20,
0x67, 0x62, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x68, 0x61, 0x61, 0x76,
0x61, 0x74, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x62,
0x61, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x63, 0x63, 0x79, 0x72, 0x20,
0x63, 0x65, 0x62, 0x71, 0x68, 0x70, 0x67, 0x2e, 0x20, 0x20, 0x56,
0x27, 0x71, 0x20, 0x65, 0x6e, 0x67, 0x75, 0x72, 0x65, 0x20, 0x67,
0x75, 0x6e, 0x67, 0x0a, 0x6c, 0x62, 0x68, 0x20, 0x71, 0x76, 0x71,
0x61, 0x27, 0x67, 0x2e, 0x20, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61,
0x71, 0x20, 0x72, 0x6b, 0x72, 0x70, 0x68, 0x67, 0x76, 0x62, 0x61,
0x20, 0x6a, 0x76, 0x79, 0x79, 0x20, 0x70, 0x62, 0x61, 0x67, 0x76,
0x61, 0x68, 0x72, 0x20, 0x7a, 0x62, 0x7a, 0x72, 0x61, 0x67, 0x6e,
0x65, 0x76, 0x79, 0x6c, 0x2e, 0x0a, 0x00
};
static char const pmsg2[] = {
0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20,
0x67, 0x62, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x68, 0x61, 0x61, 0x76,
0x61, 0x74, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x62,
0x61, 0x20, 0x6e, 0x20, 0x5a, 0x76, 0x70, 0x65, 0x62, 0x66, 0x62,
0x73, 0x67, 0x20, 0x66, 0x6c, 0x66, 0x67, 0x72, 0x7a, 0x2e, 0x20,
0x20, 0x56, 0x27, 0x71, 0x20, 0x65, 0x6e, 0x67, 0x75, 0x72, 0x65,
0x20, 0x67, 0x75, 0x6e, 0x67, 0x0a, 0x6c, 0x62, 0x68, 0x20, 0x71,
0x76, 0x71, 0x61, 0x27, 0x67, 0x2e, 0x20, 0x20, 0x45, 0x72, 0x7a,
0x76, 0x61, 0x71, 0x20, 0x72, 0x6b, 0x72, 0x70, 0x68, 0x67, 0x76,
0x62, 0x61, 0x20, 0x6a, 0x76, 0x79, 0x79, 0x20, 0x70, 0x62, 0x61,
0x67, 0x76, 0x61, 0x68, 0x72, 0x20, 0x7a, 0x62, 0x7a, 0x72, 0x61,
0x67, 0x6e, 0x65, 0x76, 0x79, 0x6c, 0x2e, 0x0a, 0x00
};
static void
rkrphgvba(int x)
AddTrustedUser(char const *username)
{
char const *s = (x ? pmsg2 : pmsg1);
while(*s) {
int c = (int) *s++;
c=isalpha(c)?tolower(c)<0x6e?c+13:c-13:c;
putchar(c);
struct passwd *pwent;
if (NumTrustedUsers >= MAX_TRUSTED_USERS) {
fprintf(stderr, "Too many trusted users (%d max)\n",
MAX_TRUSTED_USERS);
exit(EXIT_FAILURE);
}
sleep(5);
pwent = getpwnam(username);
if (!pwent) {
fprintf(ErrFp, ErrMsg[M_BAD_USER], username);
exit(EXIT_FAILURE);
}
TrustedUsers[NumTrustedUsers] = pwent->pw_uid;
NumTrustedUsers++;
}
#endif

View File

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

View File

@@ -6,7 +6,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2020 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
/* This file is Copyright (C) 1993 by Mogens Lynnerup. */
/* */
/***************************************************************/
@@ -15,21 +15,13 @@
#define L_LANGNAME "Danish"
/* Day names */
#if ISOLATIN1
# define L_SUNDAY "S\370ndag"
#else
# define L_SUNDAY "Soendag"
#endif
#define L_SUNDAY "Søndag"
#define L_MONDAY "Mandag"
#define L_TUESDAY "Tirsdag"
#define L_WEDNESDAY "Onsdag"
#define L_THURSDAY "Torsdag"
#define L_FRIDAY "Fredag"
#if ISOLATIN1
# define L_SATURDAY "L\370rdag"
#else
# define L_SATURDAY "Loerdag"
#endif
#define L_SATURDAY "Lørdag"
/* Month names */
#define L_JAN "Januar"
@@ -50,11 +42,7 @@
#define L_TOMORROW "i morgen"
/* The default banner */
#if ISOLATIN1
# define L_BANNER "P\345mindelse for %w, %d. %m, %y%o:"
#else
# define L_BANNER "Paamindelse for %w, %d. %m, %y%o:"
#endif
#define L_BANNER "Påmindelse for %w, %d. %m, %y%o:"
/* "am" and "pm" */
#define L_AM "am"
@@ -71,11 +59,7 @@
#define L_INXDAYS "om %d dage"
/* "on" as in "on date..." */
#if ISOLATIN1
# define L_ON "p\345"
#else
# define L_ON "paa"
#endif
#define L_ON "på"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */

View File

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

View File

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

View File

@@ -11,7 +11,7 @@
/* */
/* This file is part of REMIND. */
/* This file is Copyright (C) 1993-1998 by Mikko Silvonen. */
/* REMIND is Copyright (C) 1992-2020 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -33,16 +33,8 @@
#define L_MAR "maaliskuu"
#define L_APR "huhtikuu"
#define L_MAY "toukokuu"
#if ISOLATIN1
#define L_JUN "kes\xE4kuu"
#define L_JUL "hein\xE4kuu"
#elif IBMEXTENDED
#define L_JUN "kes\x84kuu"
#define L_JUL "hein\x84kuu"
#else
#define L_JUN "kes{kuu"
#define L_JUL "hein{kuu"
#endif
#define L_JUN "kesäkuu"
#define L_JUL "heinäkuu"
#define L_AUG "elokuu"
#define L_SEP "syyskuu"
#define L_OCT "lokakuu"
@@ -50,13 +42,7 @@
#define L_DEC "joulukuu"
/* Today and tomorrow */
#if ISOLATIN1
#define L_TODAY "t\xE4n\xE4\xE4n"
#elif IBMEXTENDED
#define L_TODAY "t\x84n\x84\x84n"
#else
#define L_TODAY "t{n{{n"
#endif
#define L_TODAY "tänään"
#define L_TOMORROW "huomenna"
/* The default banner */
@@ -74,13 +60,7 @@
#define L_FROMNOW "kuluttua"
/* "in %d days' time" */
#if ISOLATIN1
#define L_INXDAYS "%d p\xE4iv\xE4n kuluttua"
#elif IBMEXTENDED
#define L_INXDAYS "%d p\x84iv\x84n kuluttua"
#else
#define L_INXDAYS "%d p{iv{n kuluttua"
#endif
#define L_INXDAYS "%d päivän kuluttua"
/* "on" as in "on date...", but in Finnish it is a case ending;
L_PARTIT is the partitive ending appended to -kuu and -tai */
@@ -90,13 +70,7 @@
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
/* The partitive ending of "day" */
#if ISOLATIN1
#define L_PLURAL "\xE4"
#elif IBMEXTENDED
#define L_PLURAL "\x84"
#else
#define L_PLURAL "{"
#endif
#define L_PLURAL "ä"
/* Minutes, hours, at, etc */
#define L_NOW "nyt"
@@ -120,9 +94,8 @@
/* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc.
See the file dosubst.c for more info. */
#if ISOLATIN1
#define L_ORDINAL_OVERRIDE switch(d) { \
case 1: plu = ":sen\xE4"; break; \
case 1: plu = ":senä"; break; \
case 2: plu = ":sena"; break; \
default: \
switch(d%10) { \
@@ -130,36 +103,9 @@
case 3: \
case 6: \
case 8: plu = ":ntena"; break; \
default: plu = ":nten\xE4"; break; \
default: plu = ":ntenä"; break; \
} \
}
#elif IBMEXTENDED
#define L_ORDINAL_OVERRIDE switch(d) { \
case 1: plu = ":sen\x84"; break; \
case 2: plu = ":sena"; break; \
default: \
switch(d%10) { \
case 2: \
case 3: \
case 6: \
case 8: plu = ":ntena"; break; \
default: plu = ":nten\x84"; break; \
} \
}
#else
#define L_ORDINAL_OVERRIDE switch(d) { \
case 1: plu = ":sen{"; break; \
case 2: plu = ":sena"; break; \
default: \
switch(d%10) { \
case 2: \
case 3: \
case 6: \
case 8: plu = ":ntena"; break; \
default: plu = ":nten{"; break; \
} \
}
#endif
#define L_A_OVER if (altmode == '*') { sprintf(s, "%s %d. %s %d", DayName[jul%7], d, MonthName[m], y); } else { sprintf(s, "%s%s %d. %s%s %d", DayName[jul%7], L_ON, d, MonthName[m], L_PARTIT, y); }
#define L_C_OVER if (altmode == '*') { sprintf(s, "%s", DayName[jul%7]); } else { sprintf(s, "%s%s", DayName[jul%7], L_ON); }
#define L_E_OVER sprintf(s, "%02d%c%02d%c%04d", d, DateSep, m+1, DateSep, y);
@@ -199,104 +145,103 @@ else { \
#define L_ERR_OVERRIDE 1
EXTERN char *ErrMsg[] =
{
#if ISOLATIN1
"Ok",
"Puuttuva ']'",
"Puuttuva lainausmerkki",
"Liian monimutkainen lauseke - liikaa operaattoreita",
"Liian monimutkainen lauseke - liikaa operandeja",
"Puuttuva ')'",
"M\xE4\xE4rittelem\xE4t\xF6n funktio",
"Määrittelemätön funktio",
"Virheellinen merkki",
"Kaksipaikkainen operaattori puuttuu",
"Muisti loppui",
"Virheellinen luku",
"Operaattoripino tyhj\xE4 - sis\xE4inen virhe",
"Muuttujapino tyhj\xE4 - sis\xE4inen virhe",
"Operaattoripino tyhjä - sisäinen virhe",
"Muuttujapino tyhjä - sisäinen virhe",
"Tyyppimuunnos ei onnistu",
"Virheellinen tyyppi",
"Liian suuri p\xE4iv\xE4ys",
"Pinovirhe - sis\xE4inen virhe",
"Liian suuri päiväys",
"Pinovirhe - sisäinen virhe",
"Jako nollalla",
"M\xE4\xE4rittelem\xE4t\xF6n funktio",
"Määrittelemätön funktio",
"Odottamaton rivin loppu",
"Odottamaton tiedoston loppu",
"Sy\xF6tt\xF6- tai tulostusvirhe",
"Liian pitk\xE4 rivi",
"Sis\xE4inen virhe",
"Virheellinen p\xE4iv\xE4ys",
"Liian v\xE4h\xE4n argumentteja",
"Syöttö- tai tulostusvirhe",
"Liian pitkä rivi",
"Sisäinen virhe",
"Virheellinen päiväys",
"Liian vähän argumentteja",
"Liian paljon argumentteja",
"Virheellinen aika",
"Liian suuri luku",
"Liian pieni luku",
"Tiedoston avaus ei onnistu",
"Liian monta sis\xE4kk\xE4ist\xE4 INCLUDEa",
"J\xE4sennysvirhe",
"Liian monta sisäkkäistä INCLUDEa",
"Jäsennysvirhe",
"Laukaisuhetken laskenta ei onnistu",
"Liian monta sis\xE4kk\xE4ist\xE4 IF-lausetta",
"Liian monta sisäkkäistä IF-lausetta",
"ELSE ilman IF-lausetta",
"ENDIF ilman IF-lausetta",
"Kaikkia viikonp\xE4ivi\xE4 ei voi j\xE4tt\xE4\xE4 pois",
"Ylim\xE4\xE4r\xE4isi\xE4 merkkej\xE4 rivill\xE4",
"Kaikkia viikonpäiviä ei voi jättää pois",
"Ylimääräisiä merkkejä rivillä",
"POP-OMIT-CONTEXT ilman PUSH-OMIT-CONTEXTia",
"RUN-lauseen k\xE4ytt\xF6 estetty",
"RUN-lauseen käyttö estetty",
"Arvoaluevirhe",
"Virheellinen tunniste",
"Rekursiivinen funktiokutsu havaittu",
"",
"J\xE4rjestelm\xE4muuttujan muuttaminen ei onnistu",
"C-kirjastofunktio ei pysty esitt\xE4m\xE4\xE4n p\xE4iv\xE4yst\xE4 tai aikaa",
"Sis\xE4isen funktion m\xE4\xE4ritelm\xE4\xE4 yritettiin muuttaa",
"Lausekkeessa ei voi olla sis\xE4kk\xE4isi\xE4 funktiom\xE4\xE4ritelmi\xE4",
"P\xE4iv\xE4yksen t\xE4ytyy olla t\xE4ydellinen toistokertoimessa",
"Järjestelmämuuttujan muuttaminen ei onnistu",
"C-kirjastofunktio ei pysty esittämään päiväystä tai aikaa",
"Sisäisen funktion määritelmää yritettiin muuttaa",
"Lausekkeessa ei voi olla sisäkkäisiä funktiomääritelmiä",
"Päiväyksen täytyy olla täydellinen toistokertoimessa",
"Vuosi annettu kahdesti",
"Kuukausi annettu kahdesti",
"P\xE4iv\xE4 annettu kahdesti",
"Päivä annettu kahdesti",
"Tuntematon sana tai merkki",
"OMIT-komennossa on annettava kuukausi ja p\xE4iv\xE4",
"OMIT-komennossa on annettava kuukausi ja päivä",
"Liian monta osittaista OMIT-komentoa",
"Liian monta t\xE4ydellist\xE4 OMIT-komentoa",
"Liian monta täydellistä OMIT-komentoa",
"Varoitus: PUSH-OMIT-CONTEXT ilman POP-OMIT-CONTEXTia",
"Virhe tiedoston luvussa",
"Pilkku puuttuu",
"Virheellinen juutalainen p\xE4iv\xE4ys",
"IIF vaatii parittoman m\xE4\xE4r\xE4n argumentteja",
"Virheellinen juutalainen päiväys",
"IIF vaatii parittoman määrän argumentteja",
"Varoitus: puuttuva ENDIF",
"Pilkku puuttuu",
"Viikonp\xE4iv\xE4 annettu kahdesti",
"K\xE4yt\xE4 vain yht\xE4 komennoista BEFORE, AFTER ja SKIP",
"Sis\xE4kk\xE4isi\xE4 MSG-, MSF- ja RUN-lauseita ei voi k\xE4ytt\xE4\xE4 lausekkeessa",
"Viikonpäivä annettu kahdesti",
"Käytä vain yhtä komennoista BEFORE, AFTER ja SKIP",
"Sisäkkäisiä MSG-, MSF- ja RUN-lauseita ei voi käyttää lausekkeessa",
"Toistokerroin annettu kahdesti",
"Delta-arvo annettu kahdesti",
"Peruutusarvo annettu kahdesti",
"ONCE-avainsanaa k\xE4ytetty kahdesti. (Hah.)",
"AT-sanan per\xE4st\xE4 puuttuu aika",
"THROUGH/UNTIL-sanaa k\xE4ytetty kahdesti",
"Ep\xE4t\xE4ydellinen p\xE4iv\xE4ys",
"FROM/SCANFROM-sanaa k\xE4ytetty kahdesti",
"ONCE-avainsanaa käytetty kahdesti. (Hah.)",
"AT-sanan perästä puuttuu aika",
"THROUGH/UNTIL-sanaa käytetty kahdesti",
"Epätäydellinen päiväys",
"FROM/SCANFROM-sanaa käytetty kahdesti",
"Muuttuja",
"Arvo",
"*M\xC4\xC4RITTELEM\xC4T\xD6N*",
"Siirryt\xE4\xE4n funktioon",
"*MÄÄRITTELEMÄTÖN*",
"Siirrytään funktioon",
"Poistutaan funktiosta",
"Vanhentunut",
"fork() ep\xE4onnistui - jonomuistutukset eiv\xE4t toimi",
"fork() epäonnistui - jonomuistutukset eivät toimi",
"Tiedoston avaus ei onnistu",
"Virheellinen j\xE4rjestelm\xE4p\xE4iv\xE4ys: vuosi on v\xE4hemm\xE4n kuin %d\n",
"Tuntematon virheenetsint\xE4tarkenne '%c'\n",
"Virheellinen järjestelmäpäiväys: vuosi on vähemmän kuin %d\n",
"Tuntematon virheenetsintätarkenne '%c'\n",
"Tuntematon tarkenne '%c'\n",
"Tuntematon k\xE4ytt\xE4j\xE4 '%s'\n",
"Ryhm\xE4numeron vaihto %d:ksi ei onnistunut\n",
"K\xE4ytt\xE4j\xE4numeron vaihto %d:ksi ei onnistunut\n",
"Muisti ei riit\xE4 ymp\xE4rist\xF6lle\n",
"Tuntematon käyttäjä '%s'\n",
"Ryhmänumeron vaihto %d:ksi ei onnistunut\n",
"Käyttäjänumeron vaihto %d:ksi ei onnistunut\n",
"Muisti ei riitä ympäristölle\n",
"Puuttuva '='-merkki",
"Puuttuva muuttujanimi",
"Puuttuva lauseke",
"P\xE4iv\xE4n asetus %s:ksi ei onnitus\n",
"Päivän asetus %s:ksi ei onnitus\n",
"Remind: tarkenne '-i': %s\n",
"Ei viestej\xE4.",
"%d viesti(\xE4) t\xE4m\xE4n p\xE4iv\xE4n jonossa.\n",
"Ei viestejä.",
"%d viesti(ä) tämän päivän jonossa.\n",
"Numero puuttuu",
"Virheellinen funktio WARN-lausekkeessa",
"Can't convert between time zones",
@@ -304,221 +249,6 @@ EXTERN char *ErrMsg[] =
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#elif IBMEXTENDED
"Ok",
"Puuttuva ']'",
"Puuttuva lainausmerkki",
"Liian monimutkainen lauseke - liikaa operaattoreita",
"Liian monimutkainen lauseke - liikaa operandeja",
"Puuttuva ')'",
"M\x84\x84rittelem\x84t\x94n funktio",
"Virheellinen merkki",
"Kaksipaikkainen operaattori puuttuu",
"Muisti loppui",
"Virheellinen luku",
"Operaattoripino tyhj\x84 - sis\x84inen virhe",
"Muuttujapino tyhj\x84 - sis\x84inen virhe",
"Tyyppimuunnos ei onnistu",
"Virheellinen tyyppi",
"Liian suuri p\x84iv\x84ys",
"Pinovirhe - sis\x84inen virhe",
"Jako nollalla",
"M\x84\x84rittelem\x84t\x94n funktio",
"Odottamaton rivin loppu",
"Odottamaton tiedoston loppu",
"Sy\x94tt\x94- tai tulostusvirhe",
"Liian pitk\x84 rivi",
"Sis\x84inen virhe",
"Virheellinen p\x84iv\x84ys",
"Liian v\x84h\x84n argumentteja",
"Liian paljon argumentteja",
"Virheellinen aika",
"Liian suuri luku",
"Liian pieni luku",
"Tiedoston avaus ei onnistu",
"Liian monta sis\x84kk\x84ist\x84 INCLUDEa",
"J\x84sennysvirhe",
"Laukaisuhetken laskenta ei onnistu",
"Liian monta sis\x84kk\x84ist\x84 IF-lausetta",
"ELSE ilman IF-lausetta",
"ENDIF ilman IF-lausetta",
"Kaikkia viikonp\x84ivi\x84 ei voi j\x84tt\x84\x84 pois",
"Ylim\x84\x84r\x84isi\x84 merkkej\x84 rivill\x84",
"POP-OMIT-CONTEXT ilman PUSH-OMIT-CONTEXTia",
"RUN-lauseen k\x84ytt\x94 estetty",
"Arvoaluevirhe",
"Virheellinen tunniste",
"Rekursiivinen funktiokutsu havaittu",
"",
"J\x84rjestelm\x84muuttujan muuttaminen ei onnistu",
"C-kirjastofunktio ei pysty esitt\x84m\x84\x84n p\x84iv\x84yst\x84 tai aikaa",
"Sis\x84isen funktion m\x84\x84ritelm\x84\x84 yritettiin muuttaa",
"Lausekkeessa ei voi olla sis\x84kk\x84isi\x84 funktiom\x84\x84ritelmi\x84",
"P\x84iv\x84yksen t\x84ytyy olla t\x84ydellinen toistokertoimessa",
"Vuosi annettu kahdesti",
"Kuukausi annettu kahdesti",
"P\x84iv\x84 annettu kahdesti",
"Tuntematon sana tai merkki",
"OMIT-komennossa on annettava kuukausi ja p\x84iv\x84",
"Liian monta osittaista OMIT-komentoa",
"Liian monta t\x84ydellist\x84 OMIT-komentoa",
"Varoitus: PUSH-OMIT-CONTEXT ilman POP-OMIT-CONTEXTia",
"Virhe tiedoston luvussa",
"Pilkku puuttuu",
"Virheellinen juutalainen p\x84iv\x84ys",
"IIF vaatii parittoman m\x84\x84r\x84n argumentteja",
"Varoitus: puuttuva ENDIF",
"Pilkku puuttuu",
"Viikonp\x84iv\x84 annettu kahdesti",
"K\x84yt\x84 vain yht\x84 komennoista BEFORE, AFTER ja SKIP",
"Sis\x84kk\x84isi\x84 MSG-, MSF- ja RUN-lauseita ei voi k\x84ytt\x84\x84 lausekkeessa",
"Toistokerroin annettu kahdesti",
"Delta-arvo annettu kahdesti",
"Peruutusarvo annettu kahdesti",
"ONCE-avainsanaa k\x84ytetty kahdesti. (Hah.)",
"AT-sanan per\x84st\x84 puuttuu aika",
"THROUGH/UNTIL-sanaa k\x84ytetty kahdesti",
"Ep\x84t\x84ydellinen p\x84iv\x84ys",
"FROM/SCANFROM-sanaa k\x84ytetty kahdesti",
"Muuttuja",
"Arvo",
"*M\x8E\x8ERITTELEM\x8ET\x99N*",
"Siirryt\x84\x84n funktioon",
"Poistutaan funktiosta",
"Vanhentunut",
"fork() ep\x84onnistui - jonomuistutukset eiv\x84t toimi",
"Tiedoston avaus ei onnistu",
"Virheellinen j\x84rjestelm\x84p\x84iv\x84ys: vuosi on v\x84hemm\x84n kuin %d\n",
"Tuntematon virheenetsint\x84tarkenne '%c'\n",
"Tuntematon tarkenne '%c'\n",
"Tuntematon k\x84ytt\x84j\x84 '%s'\n",
"Ryhm\x84numeron vaihto %d:ksi ei onnistunut\n",
"K\x84ytt\x84j\x84numeron vaihto %d:ksi ei onnistunut\n",
"Muisti ei riit\x84 ymp\x84rist\x94lle\n",
"Puuttuva '='-merkki",
"Puuttuva muuttujanimi",
"Puuttuva lauseke",
"P\x84iv\x84n asetus %s:ksi ei onnitus\n",
"Remind: tarkenne '-i': %s\n",
"Ei viestej\x84.",
"%d viesti(\x84) t\x84m\x84n p\x84iv\x84n jonossa.\n",
"Numero puuttuu"
"Virheellinen funktio WARN-lausekkeessa",
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#else
"Ok",
"Puuttuva ']'",
"Puuttuva lainausmerkki",
"Liian monimutkainen lauseke - liikaa operaattoreita",
"Liian monimutkainen lauseke - liikaa operandeja",
"Puuttuva ')'",
"M{{rittelem{t|n funktio",
"Virheellinen merkki",
"Kaksipaikkainen operaattori puuttuu",
"Muisti loppui",
"Virheellinen luku",
"Operaattoripino tyhj{ - sis{inen virhe",
"Muuttujapino tyhj{ - sis{inen virhe",
"Tyyppimuunnos ei onnistu",
"Virheellinen tyyppi",
"Liian suuri p{iv{ys",
"Pinovirhe - sis{inen virhe",
"Jako nollalla",
"M{{rittelem{t|n funktio",
"Odottamaton rivin loppu",
"Odottamaton tiedoston loppu",
"Sy|tt|- tai tulostusvirhe",
"Liian pitk{ rivi",
"Sis{inen virhe",
"Virheellinen p{iv{ys",
"Liian v{h{n argumentteja",
"Liian paljon argumentteja",
"Virheellinen aika",
"Liian suuri luku",
"Liian pieni luku",
"Tiedoston avaus ei onnistu",
"Liian monta sis{kk{ist{ INCLUDEa",
"J{sennysvirhe",
"Laukaisuhetken laskenta ei onnistu",
"Liian monta sis{kk{ist{ IF-lausetta",
"ELSE ilman IF-lausetta",
"ENDIF ilman IF-lausetta",
"Kaikkia viikonp{ivi{ ei voi j{tt{{ pois",
"Ylim{{r{isi{ merkkej{ rivill{",
"POP-OMIT-CONTEXT ilman PUSH-OMIT-CONTEXTia",
"RUN-lauseen k{ytt| estetty",
"Arvoaluevirhe",
"Virheellinen tunniste",
"Rekursiivinen funktiokutsu havaittu",
"",
"J{rjestelm{muuttujan muuttaminen ei onnistu",
"C-kirjastofunktio ei pysty esitt{m{{n p{iv{yst{ tai aikaa",
"Sis{isen funktion m{{ritelm{{ yritettiin muuttaa",
"Lausekkeessa ei voi olla sis{kk{isi{ funktiom{{ritelmi{",
"P{iv{yksen t{ytyy olla t{ydellinen toistokertoimessa",
"Vuosi annettu kahdesti",
"Kuukausi annettu kahdesti",
"P{iv{ annettu kahdesti",
"Tuntematon sana tai merkki",
"OMIT-komennossa on annettava kuukausi ja p{iv{",
"Liian monta osittaista OMIT-komentoa",
"Liian monta t{ydellist{ OMIT-komentoa",
"Varoitus: PUSH-OMIT-CONTEXT ilman POP-OMIT-CONTEXTia",
"Virhe tiedoston luvussa",
"Pilkku puuttuu",
"Virheellinen juutalainen p{iv{ys",
"IIF vaatii parittoman m{{r{n argumentteja",
"Varoitus: puuttuva ENDIF",
"Pilkku puuttuu",
"Viikonp{iv{ annettu kahdesti",
"K{yt{ vain yht{ komennoista BEFORE, AFTER ja SKIP",
"Sis{kk{isi{ MSG-, MSF- ja RUN-lauseita ei voi k{ytt{{ lausekkeessa",
"Toistokerroin annettu kahdesti",
"Delta-arvo annettu kahdesti",
"Peruutusarvo annettu kahdesti",
"ONCE-avainsanaa k{ytetty kahdesti. (Hah.)",
"AT-sanan per{st{ puuttuu aika",
"THROUGH/UNTIL-sanaa k{ytetty kahdesti",
"Ep{t{ydellinen p{iv{ys",
"FROM/SCANFROM-sanaa k{ytetty kahdesti",
"Muuttuja",
"Arvo",
"*M[[RITTELEM[T\\N*",
"Siirryt{{n funktioon",
"Poistutaan funktiosta",
"Vanhentunut",
"fork() ep{onnistui - jonomuistutukset eiv{t toimi",
"Tiedoston avaus ei onnistu",
"Virheellinen j{rjestelm{p{iv{ys: vuosi on v{hemm{n kuin %d\n",
"Tuntematon virheenetsint{tarkenne '%c'\n",
"Tuntematon tarkenne '%c'\n",
"Tuntematon k{ytt{j{ '%s'\n",
"Ryhm{numeron vaihto %d:ksi ei onnistunut\n",
"K{ytt{j{numeron vaihto %d:ksi ei onnistunut\n",
"Muisti ei riit{ ymp{rist|lle\n",
"Puuttuva '='-merkki",
"Puuttuva muuttujanimi",
"Puuttuva lauseke",
"P{iv{n asetus %s:ksi ei onnitus\n",
"Remind: tarkenne '-i': %s\n",
"Ei viestej{.",
"%d viesti({) t{m{n p{iv{n jonossa.\n",
"Numero puuttuu",
"Virheellinen funktio WARN-lausekkeessa",
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#endif
};
#endif /* MK_GLOBALS */
@@ -527,97 +257,37 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2020 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETAVERSIO <<<<\n");
#endif
#if ISOLATIN1
fprintf(ErrFp, "K\xE4ytt\xF6: remind [tarkenteet] tiedosto [p\xE4iv\xE4ys] [aika] [*toisto]\n");
fprintf(ErrFp, "Käyttö: remind [tarkenteet] tiedosto [päiväys] [aika] [*toisto]\n");
fprintf(ErrFp, "Tarkenteet:\n");
fprintf(ErrFp, " -n Tulosta viestien seuraavat esiintymiskerrat yksink. muodossa\n");
fprintf(ErrFp, " -r Est\xE4 RUN-lauseiden k\xE4ytt\xF6\n");
fprintf(ErrFp, " -r Estä RUN-lauseiden käyttö\n");
fprintf(ErrFp, " -c[n] Tulosta n:n kuukauden kalenteri (oletus 1)\n");
fprintf(ErrFp, " -c+[n] Tulosta n:n viikon kalenteri (oletus 1)\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Aseta kalenterin leveys, tasaus ja v\xE4lit\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Aseta kalenterin leveys, tasaus ja välit\n");
fprintf(ErrFp, " -s[+][n] Tulosta n:n kuukauden (viikon) 'yksink. kalenteri' (oletus 1)\n");
fprintf(ErrFp, " -p[n] Kuten -s, mutta tulosta rem2ps:lle sopivassa muodossa\n");
fprintf(ErrFp, " -v Laveat tulostukset\n");
fprintf(ErrFp, " -o \xC4l\xE4 noudata ONCE-lauseita\n");
fprintf(ErrFp, " -t Laukaise kaikki viestit deltan arvosta v\xE4litt\xE4m\xE4tt\xE4\n");
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 \xC4l\xE4 laukaise viestej\xE4 heti - lis\xE4\xE4 ne jonoon\n");
fprintf(ErrFp, " -q \xC4l\xE4 lis\xE4\xE4 viestej\xE4 jonoon\n");
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\xE4ynnisty demonina, her\xE4tys n:n (5:n) minuutin v\xE4lein\n");
fprintf(ErrFp, " -z[n] Käynnisty demonina, herätys n:n (5:n) minuutin välein\n");
#endif
fprintf(ErrFp, " -d... Virheenetsint\xE4: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
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");
fprintf(ErrFp, " -x[n] SATISFY-lauseen toistoraja (oletus 150)\n");
fprintf(ErrFp, " -kcmd Suorita 'cmd' MSG-tyyppisille viesteille\n");
fprintf(ErrFp, " -g[ddd] Lajittele viestit p\xE4iv\xE4yksen, ajan ja t\xE4rkeyden mukaan\n");
fprintf(ErrFp, " -ivar=val Alusta muuttuja var arvolla val ja s\xE4ilyt\xE4 var\n");
fprintf(ErrFp, " -m Aloita kalenteri maanantaista eik\xE4 sunnuntaista\n");
fprintf(ErrFp, " -g[ddd] Lajittele viestit päiväyksen, ajan ja tärkeyden mukaan\n");
fprintf(ErrFp, " -ivar=val Alusta muuttuja var arvolla val ja säilytä var\n");
fprintf(ErrFp, " -m Aloita kalenteri maanantaista eikä sunnuntaista\n");
exit(1);
#elif IBMEXTENDED
fprintf(ErrFp, "K\x84ytt\x94: remind [tarkenteet] tiedosto [p\x84iv\x84ys] [aika] [*toisto]\n");
fprintf(ErrFp, "Tarkenteet:\n");
fprintf(ErrFp, " -n Tulosta viestien seuraavat esiintymiskerrat yksink. muodossa\n");
fprintf(ErrFp, " -r Est\x84 RUN-lauseiden k\x84ytt\x94\n");
fprintf(ErrFp, " -c[n] Tulosta n:n kuukauden kalenteri (oletus 1)\n");
fprintf(ErrFp, " -c+[n] Tulosta n:n viikon kalenteri (oletus 1)\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Aseta kalenterin leveys, tasaus ja v\x84lit\n");
fprintf(ErrFp, " -s[+][n] Tulosta n:n kuukauden (viikon) 'yksink. kalenteri' (oletus 1)\n");
fprintf(ErrFp, " -p[n] Kuten -s, mutta tulosta rem2ps:lle sopivassa muodossa\n");
fprintf(ErrFp, " -v Laveat tulostukset\n");
fprintf(ErrFp, " -o \x8El\x84 noudata ONCE-lauseita\n");
fprintf(ErrFp, " -t Laukaise kaikki viestit deltan arvosta v\x84litt\x84m\x84tt\x84\n");
fprintf(ErrFp, " -h Suppeat tulostukset\n");
#ifdef HAVE_QUEUED
fprintf(ErrFp, " -a \x8El\x84 laukaise viestej\x84 heti - lis\x84\x84 ne jonoon\n");
fprintf(ErrFp, " -q \x8El\x84 lis\x84\x84 viestej\x84 jonoon\n");
fprintf(ErrFp, " -f Laukaise viestit, pysy etualalla\n");
fprintf(ErrFp, " -z[n] K\x84ynnisty demonina, her\x84tys n:n (5:n) minuutin v\x84lein\n");
#endif
fprintf(ErrFp, " -d... Virheenetsint\x84: 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");
fprintf(ErrFp, " -x[n] SATISFY-lauseen toistoraja (oletus 150)\n");
fprintf(ErrFp, " -kcmd Suorita 'cmd' MSG-tyyppisille viesteille\n");
fprintf(ErrFp, " -g[ddd] Lajittele viestit p\x84iv\x84yksen, ajan ja t\x84rkeyden mukaan\n");
fprintf(ErrFp, " -ivar=val Alusta muuttuja var arvolla val ja s\x84ilyt\x84 var\n");
fprintf(ErrFp, " -m Aloita kalenteri maanantaista eik\x84 sunnuntaista\n");
exit(1);
#else
fprintf(ErrFp, "K{ytt|: remind [tarkenteet] tiedosto [p{iv{ys] [aika] [*toisto]\n");
fprintf(ErrFp, "Tarkenteet:\n");
fprintf(ErrFp, " -n Tulosta viestien seuraavat esiintymiskerrat yksink. muodossa\n");
fprintf(ErrFp, " -r Est{ RUN-lauseiden k{ytt|\n");
fprintf(ErrFp, " -c[n] Tulosta n:n kuukauden kalenteri (oletus 1)\n");
fprintf(ErrFp, " -c+[n] Tulosta n:n viikon kalenteri (oletus 1)\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Aseta kalenterin leveys, tasaus ja v{lit\n");
fprintf(ErrFp, " -s[+][n] Tulosta n:n kuukauden (viikon) 'yksink. kalenteri' (oletus 1)\n");
fprintf(ErrFp, " -p[n] Kuten -s, mutta tulosta rem2ps:lle sopivassa muodossa\n");
fprintf(ErrFp, " -v Laveat tulostukset\n");
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");
fprintf(ErrFp, " -x[n] SATISFY-lauseen toistoraja (oletus 150)\n");
fprintf(ErrFp, " -kcmd Suorita 'cmd' MSG-tyyppisille viesteille\n");
fprintf(ErrFp, " -g[ddd] Lajittele viestit p{iv{yksen, ajan ja t{rkeyden mukaan\n");
fprintf(ErrFp, " -ivar=val Alusta muuttuja var arvolla val ja s{ilyt{ var\n");
fprintf(ErrFp, " -m Aloita kalenteri maanantaista eik{ sunnuntaista\n");
exit(1);
#endif
}
#endif /* L_IN_INIT */

View File

@@ -8,7 +8,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2020 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
/* This file is Copyright (C) 1993 by Laurent Duperval and */
/* Dianne Skoll. */
/* */
@@ -28,29 +28,18 @@
/* Month names */
#define L_JAN "janvier"
#if ISOLATIN1
#define L_FEB "f\351vrier"
#else
#define L_FEB "fevrier"
#endif
#define L_FEB "février"
#define L_MAR "mars"
#define L_APR "avril"
#define L_MAY "mai"
#define L_JUN "juin"
#define L_JUL "juillet"
#if ISOLATIN1
#define L_AUG "ao\373t"
#else
#define L_AUG "aout"
#endif
#define L_AUG "août"
#define L_SEP "septembre"
#define L_OCT "octobre"
#define L_NOV "novembre"
#if ISOLATIN1
#define L_DEC "d\351cembre"
#else
#define L_DEC "decembre"
#endif
#define L_DEC "décembre"
/* Today and tomorrow */
#define L_TODAY "aujourd'hui"
#define L_TOMORROW "demain"
@@ -81,22 +70,14 @@
/* Minutes, hours, at, etc */
#define L_NOW "maintenant"
#if ISOLATIN1
#define L_AT "\340"
#else
#define L_AT "a"
#endif
#define L_AT "à"
#define L_MINUTE "minute"
#define L_HOUR "heure"
#define L_IS "est"
#if ISOLATIN1
#define L_WAS "\351tait"
#else
#define L_WAS "etait"
#endif
#define L_WAS "était"
#define L_AND "et"
/* What to add to make "hour" plural */
#define L_HPLU "s"
#define L_HPLU "s"
/* What to add to make "minute" plural */
#define L_MPLU "s"
@@ -139,218 +120,110 @@ else if (tdiff < 0) { \
#define L_ERR_OVERRIDE 1
EXTERN char *ErrMsg[] =
{
#if ISOLATIN1
"Ok",
"']' manquant",
"Apostrophe manquant",
"Expression trop complexe - trop d'op\351rateurs",
"Expression trop complexe - trop d'op\351randes",
"Expression trop complexe - trop d'opérateurs",
"Expression trop complexe - trop d'opérandes",
"')' manquante",
"Fonction non-d\351finie",
"Caract\350re ill\351gal",
"Op\351rateur binaire attendu",
"Manque de m\351moire",
"Nombre mal form\351",
"Erreur interne - 'underflow' de la pile d'op\351rateurs",
"Fonction non-définie",
"Caractère illégal",
"Opérateur binaire attendu",
"Manque de mémoire",
"Nombre mal formé",
"Erreur interne - 'underflow' de la pile d'opérateurs",
"Erreur interne - 'underflow' de la pile de variables",
"Impossible de convertir",
"Types non-\351quivalents",
"D\351bordement de date",
"Types non-équivalents",
"Débordement de date",
"Erreur interne - erreur de pile",
"Division par z\351ro",
"Variable non d\351finie",
"Division par zéro",
"Variable non définie",
"Fin de ligne non attendue",
"Fin de fichier non attendue",
"Erreur I/O",
"Ligne trop longue",
"Erreur interne",
"Mauvaise date sp\351cifi\351e",
"Mauvaise date spécifiée",
"Pas assez d'arguments",
"Trop d'arguments",
"Heure mal form\351e",
"Nombre trop \351lev\351",
"Heure mal formée",
"Nombre trop élevé",
"Nombre trop bas",
"Impossible d'ouvrir le fichier",
"Trop d'INCLUDE imbriqu\351s",
"Trop d'INCLUDE imbriqués",
"Erreur d'analyse",
"Impossible de calculer le d\351clenchement",
"Trop de IF imbriqu\351s",
"Impossible de calculer le déclenchement",
"Trop de IF imbriqués",
"ELSE sans IF correspondant",
"ENDIF sans IF correspondant",
"Impossible d'omettre (OMIT) tous les jours",
"El\351ment(s) \351tranger(s) sur la ligne",
"Elément(s) étranger(s) sur la ligne",
"POP-OMIT-CONTEXT sans PUSH-OMIT-CONTEXT correspondant",
"RUN d\351activ\351",
"RUN déactivé",
"Erreur de domaine",
"Identificateur invalide",
"Appel r\351cursif d\351tect\351",
"Appel récursif détecté",
"",
"Impossible de modifier une variable syst\350me",
"Fonction de la librairie C ne peut repr\351senter la date/l'heure",
"Tentative de red\351finition d'une fonction intrins\350que",
"Impossible d'imbriquer une d\351finition de fonction dans une expression",
"Pour utiliser le facteur de r\351p\351tition la date doit \352tre sp\351cifi\351e au complet",
"Ann\351e sp\351cifi\351e deux fois",
"Mois sp\351cifi\351 deux fois",
"Jour sp\351cifi\351 deux fois",
"El\351ment inconnu",
"Mois et jour doivent \352tre sp\351cifi\351s dans commande OMIT",
"Impossible de modifier une variable système",
"Fonction de la librairie C ne peut représenter la date/l'heure",
"Tentative de redéfinition d'une fonction intrinsèque",
"Impossible d'imbriquer une définition de fonction dans une expression",
"Pour utiliser le facteur de répétition la date doit être spécifiée au complet",
"Année spécifiée deux fois",
"Mois spécifié deux fois",
"Jour spécifié deux fois",
"Elément inconnu",
"Mois et jour doivent être spécifiés dans commande OMIT",
"Trop de OMITs partiels",
"Trop de OMITs complets",
"Attention: PUSH-OMIT-CONTEXT sans POP-OMIT-CONTEXT correspondant",
"Erreur \340 la lecture du fichier",
"Erreur à la lecture du fichier",
"Fin de ligne attendue",
"Date h\351breuse invalide",
"Date hébreuse invalide",
"IIF demande nombre d'arguments impair",
"Attention: ENDIF manquant",
"Virgule attendue",
"Jour de la semaine sp\351cifi\351 deux fois",
"Jour de la semaine spécifié deux fois",
"Utiliser un seul parmi BEFORE, AFTER ou SKIP",
"Impossible d'imbriquer MSG, MSF, RUN, etc. dans une expression",
"Valeur de r\351p\351tition sp\351cifi\351e deux fois",
"Valeur delta sp\351cifi\351e deux fois",
"Valeur de retour sp\351cifi\351e deux fois",
"Mot-cl\351 ONCE utilis\351 deux fois. (Hah.)",
"Heure attendue apr\350s AT",
"Mot-cl\351 THROUGH/UNTIL utilis\351 deux fois",
"Sp\351cification de date incompl\350te",
"Mot-cl\351 FROM/SCANFROM utilis\351 deux fois",
"Valeur de répétition spécifiée deux fois",
"Valeur delta spécifiée deux fois",
"Valeur de retour spécifiée deux fois",
"Mot-clé ONCE utilisé deux fois. (Hah.)",
"Heure attendue après AT",
"Mot-clé THROUGH/UNTIL utilisé deux fois",
"Spécification de date incomplète",
"Mot-clé FROM/SCANFROM utilisé deux fois",
"Variable",
"Valeur",
"*NON-DEFINI*",
"Entr\351e dans UserFN",
"Entrée dans UserFN",
"Sortie de UserFN",
"Expir\351",
"fork() \351chou\351 - impossible de faire les appels en queue",
"Impossible d'acc\351der au fichier",
"Date syst\350me ill\351gale: Ann\351e est inf\351rieure \340 %d\n",
"Option de d\351verminage inconnue '%c'\n",
"Expiré",
"fork() échoué - impossible de faire les appels en queue",
"Impossible d'accéder au fichier",
"Date système illégale: Année est inférieure à %d\n",
"Option de déverminage inconnue '%c'\n",
"Option inconnue '%c'\n",
"Usager inconnu '%s'\n",
"Impossible de changer gid pour %d\n",
"Impossible de changer uid pour %d\n",
"Manque de m\351moire pour environnement\n",
"Manque de mémoire pour environnement\n",
"Signe '=' manquant",
"Nom de variable absent",
"Expression absente",
"Impossible de changer la date d'acc\350s de %s\n",
"Impossible de changer la date d'accès de %s\n",
"Remind: '-i' option: %s\n",
"Pas de rappels.",
"%d rappel(s) en file pour aujourd'hui.\n",
"Nombre attendu",
"Fonction ill\351gale apr\350s WARN",
"Fonction illégale après WARN",
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#else /* ISOLATIN1 */
"Ok",
"']' manquant",
"Apostrophe manquant",
"Expression trop complexe - trop d'operateurs",
"Expression trop complexe - trop d'operandes",
"')' manquante",
"Fonction non-definie",
"Caractere illegal",
"Operateur binaire attendu",
"Manque de memoire",
"Nombre mal forme",
"Erreur interne - 'underflow' de la pile d'operateurs",
"Erreur interne - 'underflow' de la pile de variables",
"Impossible de convertir",
"Types non-equivalents",
"Debordement de date",
"Erreur interne - erreur de pile",
"Division par zero",
"Variable non definie",
"Fin de ligne non attendue",
"Fin de fichier non attendue",
"Erreur I/O",
"Ligne trop longue",
"Erreur interne",
"Mauvaise date specifiee",
"Pas assez d'arguments",
"Trop d'arguments",
"Heure mal formee",
"Nombre trop eleve",
"Nombre trop bas",
"Impossible d'ouvrir le fichier",
"Trop d'INCLUDE imbriques",
"erreur d'analyse",
"Impossible de calculer le declenchement",
"Trop de IF imbriques",
"ELSE sans IF correspondant",
"ENDIF sans IF correspondant",
"Impossible d'omettre (OMIT) tous les jours",
"Element(s) etranger(s) sur la ligne",
"POP-OMIT-CONTEXT sans PUSH-OMIT-CONTEXT correspondant",
"RUN desactive",
"Erreur de domaine",
"Identificateur invalide",
"Appel recursif detecte",
"",
"Impossible de modifier une variable systeme",
"Fonction de la librairie C ne peut representer la date/l'heure",
"Tentative de redefinition d'une fonction intrinseque",
"Impossible d'imbriquer une definition de fonction dans une expression",
"Pour utiliser le facteur de repetition la date doit etre specifiee au complet",
"Annee specifiee deux fois",
"Mois specifie deux fois",
"Jour specifie deux fois",
"Element inconnu",
"Mois et jour doivent etre specifies dans commande OMIT",
"Trop de OMITs partiels",
"Trop de OMITs complets",
"Attention: PUSH-OMIT-CONTEXT sans POP-OMIT-CONTEXT correspondant",
"Erreur a la lecture du fichier",
"Fin de ligne attendue",
"Date hebreuse invalide",
"IIF demande nombre d'arguments impair",
"Attention: ENDIF manquant",
"Virgule attendue",
"Jour de la semaine specifie deux fois",
"Utiliser un seul parmi BEFORE, AFTER ou SKIP",
"Impossible d'imbriquer MSG, MSF, RUN, etc. dans une expression",
"Valeur de repetition specifiee deux fois",
"Valeur delta specifiee deux fois",
"Valeur de retour specifiee deux fois",
"Mot-cle ONCE utilise deux fois. (Hah.)",
"Heure attendue apres AT",
"Mot-cle THROUGH/UNTIL utilise deux fois",
"Specification de date incomplete",
"Mot-cle FROM/SCANFROM utilise deux fois",
"Variable",
"Valeur",
"*NON-DEFINI*",
"Entree dans UserFN",
"Sortie de UserFN",
"Expire",
"fork() echoue - impossible de faire les appels en queue",
"Impossible d'acceder au fichier",
"Date systeme illegale: Annee est inferieure a %d\n",
"Option de deverminage inconnue '%c'\n",
"Option inconnue '%c'\n",
"Usager inconnu '%s'\n",
"Impossible de changer gid pour %d\n",
"Impossible de changer uid pour %d\n",
"Manque de memoire pour environnement\n",
"Signe '=' manquant",
"Nom de variable absent",
"Expression absente",
"Impossible de changer la date d'acces de %s\n",
"Remind: '-i' option: %s\n",
"Pas de rappels.",
"%d rappel(s) en file pour aujourd'hui.\n",
"Nombre attendu",
"Fonction illegale apres WARN",
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#endif /* ISOLATIN1 */
};
#endif /* MK_GLOBALS */
@@ -359,67 +232,37 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2020 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
#if ISOLATIN1
fprintf(ErrFp, "\nUtilisation: remind [options] fichier [date] [heure] [*r\351p\351tition]\n");
fprintf(ErrFp, "\nUtilisation: remind [options] fichier [date] [heure] [*répétition]\n");
fprintf(ErrFp, "Options:\n");
fprintf(ErrFp, " -n Afficher la prochaine occurence des rappels en format simple\n");
fprintf(ErrFp, " -r D\351sactiver les instructions RUN\n");
fprintf(ErrFp, " -c[n] Produire un calendrier pour n (d\351faut 1) mois\n");
fprintf(ErrFp, " -c+[n] Produire un calendrier pour n (d\351faut 1) semaines\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Sp\351cifier largeur, remplissage et espacement du calendrier\n");
fprintf(ErrFp, " -r Désactiver les instructions RUN\n");
fprintf(ErrFp, " -c[n] Produire un calendrier pour n (défaut 1) mois\n");
fprintf(ErrFp, " -c+[n] Produire un calendrier pour n (défaut 1) semaines\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Spécifier largeur, remplissage et espacement du calendrier\n");
fprintf(ErrFp, " -s[+][n] Produire un 'calendrier simple' pour n (1) mois (semaines)\n");
fprintf(ErrFp, " -p[n] Comme -s, mais avec entr\351e compatible avec rem2ps\n");
fprintf(ErrFp, " -p[n] Comme -s, mais avec entrée compatible avec rem2ps\n");
fprintf(ErrFp, " -v Mode verbeux\n");
fprintf(ErrFp, " -o Ignorer instructions ONCE\n");
fprintf(ErrFp, " -t D\351clencher tous les rappels peu importe le delta\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\351clencher les rappels minut\351s imm\351diatement - les mettre en file\n");
fprintf(ErrFp, " -q Ne pas mettre les rappels minut\351s en file\n");
fprintf(ErrFp, " -f D\351clencher les rappels minut\351s imm\351diatement en restant en avant-plan\n");
fprintf(ErrFp, " -z[n] Entrer en mode 'daemon', r\351veil chaque n (5) minutes\n");
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 \340 stdout\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");
fprintf(ErrFp, " -x[n] Limite d'it\351rations pour la clause SATISFY (def=150)\n");
fprintf(ErrFp, " -kcmd Ex\351cuter 'cmd' pour les rappels de type MSG\n");
fprintf(ErrFp, " -g[ddd] Trier les rappels par date, heure et priorit\351 avant d'\351mettre\n");
fprintf(ErrFp, " -ivar=val Initialiser var \340 val et conserver var\n");
fprintf(ErrFp, " -m Commencer le calendrier avec lundi plut\364t que dimanche\n");
#else /* ISOLATIN1 */
fprintf(ErrFp, "\nUtilisation: remind [options] fichier [date] [heure] [*repetition]\n");
fprintf(ErrFp, "Options:\n");
fprintf(ErrFp, " -n Afficher la prochaine occurence des rappels en format simple\n");
fprintf(ErrFp, " -r Desactiver les instructions RUN\n");
fprintf(ErrFp, " -c[n] Produire un calendrier pour n (defaut 1) mois\n");
fprintf(ErrFp, " -c+[n] Produire un calendrier pour n (defaut 1) semaines\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Specifier largeur, remplissage et espacement du calendrier\n");
fprintf(ErrFp, " -s[+][n] Produire un 'calendrier simple' pour n (1) mois (semaines)\n");
fprintf(ErrFp, " -p[n] Comme -s, mais avec entree compatible avec rem2ps\n");
fprintf(ErrFp, " -v Mode verbeux\n");
fprintf(ErrFp, " -o Ignorer instructions ONCE\n");
fprintf(ErrFp, " -t Declencher tous les rappels peu importe le delta\n");
fprintf(ErrFp, " -h Mode silencieux\n");
#ifdef HAVE_QUEUED
fprintf(ErrFp, " -a Ne pas declencher les rappels minutes immediatement - les mettre en file\n");
fprintf(ErrFp, " -q Ne pas mettre les rappels minutes en file\n");
fprintf(ErrFp, " -f Declencher les rappels minutes immediatement en restant en avant-plan\n");
fprintf(ErrFp, " -z[n] Entrer en mode 'daemon', reveil 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 a stdout\n");
fprintf(ErrFp, " -b[n] Formats de l'heure pour le calendrier: 0=am/pm, 1=24hr, 2=aucun\n");
fprintf(ErrFp, " -x[n] Limite d'iterations pour la clause SATISFY (def=150)\n");
fprintf(ErrFp, " -kcmd Executer 'cmd' pour les rappels de type MSG\n");
fprintf(ErrFp, " -g[ddd] Trier les rappels par date, heure et priorite avant d'emettre\n");
fprintf(ErrFp, " -ivar=val Initialiser var a val et conserver var\n");
fprintf(ErrFp, " -m Commencer le calendrier avec lundi plutot que dimanche\n");
#endif /* ISOLATIN1 */
fprintf(ErrFp, " -x[n] Limite d'itérations pour la clause SATISFY (def=150)\n");
fprintf(ErrFp, " -kcmd Exécuter 'cmd' pour les rappels de type MSG\n");
fprintf(ErrFp, " -g[ddd] Trier les rappels par date, heure et priorité avant d'émettre\n");
fprintf(ErrFp, " -ivar=val Initialiser var à val et conserver var\n");
fprintf(ErrFp, " -m Commencer le calendrier avec lundi plutôt que dimanche\n");
exit(1);
}
#endif /* L_IN_INIT */

View File

@@ -9,7 +9,7 @@
/* I don't speak German. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -28,11 +28,7 @@
/* Month names */
#define L_JAN "Januar"
#define L_FEB "Februar"
#if ISOLATIN1
# define L_MAR "M\344rz"
#else
# define L_MAR "Maerz"
#endif
#define L_MAR "März"
#define L_APR "April"
#define L_MAY "Mai"
#define L_JUN "Juni"
@@ -48,11 +44,7 @@
#define L_TOMORROW "morgen"
/* The default banner */
#if ISOLATIN1
# define L_BANNER "Termine f\374r %w, den %d. %m %y%o:"
#else
# define L_BANNER "Termine fuer %w, den %d. %m %y%o:"
#endif
#define L_BANNER "Termine für %w, den %d. %m %y%o:"
/* "am" and "pm" */
#define L_AM "am"

View File

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

View File

@@ -7,7 +7,7 @@
/* This file is part of REMIND. */
/* It is Copyright (C) 1996 by Valerio Aimale */
/* */
/* Remind is copyright (C) 1992-2020 by Dianne Skoll */
/* Remind is copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -15,23 +15,13 @@
#define L_LANGNAME "Italian"
/* Day names */
#if ISOLATIN1
#define L_SUNDAY "Domenica"
#define L_MONDAY "Luned\354"
#define L_TUESDAY "Marted\354"
#define L_WEDNESDAY "Mercoled\354"
#define L_THURSDAY "Gioved\354"
#define L_FRIDAY "Venerd\354"
#define L_MONDAY "Lunedí"
#define L_TUESDAY "Martedí"
#define L_WEDNESDAY "Mercoledí"
#define L_THURSDAY "Giovedí"
#define L_FRIDAY "Venerdí"
#define L_SATURDAY "Sabato"
#else /* ISOLATIN1 */
#define L_SUNDAY "Domenica"
#define L_MONDAY "Lunedi`"
#define L_TUESDAY "Martedi`"
#define L_WEDNESDAY "Mercoledi`"
#define L_THURSDAY "Giovedi`"
#define L_FRIDAY "Venerdi`"
#define L_SATURDAY "Sabato"
#endif /* ISOLATIN */
/* Month names */
#define L_JAN "Gennaio"
@@ -76,58 +66,54 @@
a more drastic fix */
/* Minutes, hours, at, etc */
#define L_NOW "ora"
#define L_NOW "ora"
#define L_AT "alle"
#define L_MINUTE "minut"
#define L_HOUR "or"
#if ISOLATIN1
#define L_IS "\350"
#else /* ISOLATIN1 */
#define L_IS "e`"
#endif/* ISOLATIN1 */
#define L_IS "é"
#define L_WAS "era"
#define L_AND "e"
/* What to add to make "hour" plural */
#define L_HPLU "s"
#define L_HPLU "s"
/* What to add to make "minute" plural */
#define L_MPLU "s"
/* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc.
See the file dosubst.c for more info. */
#define L_P_OVER sprintf(s, (diff == 1 ? "o" : "i"));
#define L_Q_OVER sprintf(s, (diff == 1 ? "a" : "e"));
#define L_P_OVER sprintf(s, (diff == 1 ? "o" : "i"));
#define L_Q_OVER sprintf(s, (diff == 1 ? "a" : "e"));
#define L_HPLU_OVER hplu = (hdiff == 1 ? "a" : "e");
#define L_MPLU_OVER mplu = (mdiff == 1 ? "o" : "i");
#define L_A_OVER sprintf(s, "%s, %d %s %d", DayName[jul%7], d,\
MonthName[m], y);
#define L_C_OVER sprintf(s, "%s", DayName[jul%7]);
MonthName[m], y);
#define L_C_OVER sprintf(s, "%s", DayName[jul%7]);
#define L_E_OVER sprintf(s, "%02d%c%02d%c%04d", d, DateSep,\
m+1, DateSep, y);
m+1, DateSep, y);
#define L_F_OVER sprintf(s, "%02d%c%02d%c%04d", m+1, DateSep, d, DateSep, y);
#define L_F_OVER sprintf(s, "%02d%c%02d%c%04d", m+1, DateSep, d, DateSep, y);
#define L_G_OVER sprintf(s, "%s, %d %s", DayName[jul%7], d, MonthName[m]);
#define L_G_OVER sprintf(s, "%s, %d %s", DayName[jul%7], d, MonthName[m]);
#define L_H_OVER sprintf(s, "%02d%c%02d", d, DateSep, m+1);
#define L_H_OVER sprintf(s, "%02d%c%02d", d, DateSep, m+1);
#define L_I_OVER sprintf(s, "%02d%c%02d", m+1, DateSep, d);
#define L_I_OVER sprintf(s, "%02d%c%02d", m+1, DateSep, d);
#define L_J_OVER sprintf(s, "%s, %d %s %d", DayName[jul%7], d, \
MonthName[m], y);
MonthName[m], y);
#define L_K_OVER sprintf(s, "%s, %d %s", DayName[jul%7], d, \
MonthName[m]);
#define L_L_OVER sprintf(s, "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d);
MonthName[m]);
#define L_L_OVER sprintf(s, "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d);
#define L_U_OVER sprintf(s, "%s, %d %s %d", DayName[jul%7], d, \
MonthName[m], y);
MonthName[m], y);
#define L_V_OVER sprintf(s, "%s, %d %s", DayName[jul%7], d, \
MonthName[m]);
MonthName[m]);
#endif /* L_IN_DOSUBST */

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-2020 by Dianne Skoll */
/* Remind is Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -14,21 +14,13 @@
#define L_LANGNAME "Norwegian"
/* Day names */
#if ISOLATIN1
# define L_SUNDAY "S\370ndag"
#else
# define L_SUNDAY "Soendag"
#endif
#define L_SUNDAY "Søndag"
#define L_MONDAY "Mandag"
#define L_TUESDAY "Tirsdag"
#define L_WEDNESDAY "Onsdag"
#define L_THURSDAY "Torsdag"
#define L_FRIDAY "Fredag"
#if ISOLATIN1
# define L_SATURDAY "L\370rdag"
#else
# define L_SATURDAY "Loerdag"
#endif
#define L_SATURDAY "Lørdag"
/* Month names */
#define L_JAN "Januar"
@@ -49,11 +41,7 @@
#define L_TOMORROW "i morgen"
/* The default banner */
#if ISOLATIN1
# define L_BANNER "P\345minnelse for %w, %d. %m, %y%o:"
#else
# define L_BANNER "Paaminnelse for %w, %d. %m, %y%o:"
#endif
#define L_BANNER "Påminnelse for %w, %d. %m, %y%o:"
/* "am" and "pm" */
#define L_AM "am"
@@ -64,11 +52,7 @@
/* Ago and from now */
#define L_AGO "siden"
#if ISOLATIN1
# define L_FROMNOW "fra n\345"
#else
# define L_FROMNOW "fra naa"
#endif
#define L_FROMNOW "fra nå"
/* "in %d days' time" */
#define L_INXDAYS "om %d dager"
@@ -81,11 +65,7 @@
#define L_PLURAL "er"
/* Minutes, hours, at, etc */
#if ISOLATIN1
# define L_NOW "n\345"
#else
# define L_NOW "naa"
#endif
#define L_NOW "nå"
#define L_AT "kl."
#define L_MINUTE "minutt"
#define L_HOUR "time"
@@ -93,7 +73,7 @@
#define L_WAS "var"
#define L_AND "og"
/* What to add to make "hour" plural */
#define L_HPLU "r"
#define L_HPLU "r"
/* What to add to make "minute" plural */
#define L_MPLU "er"

View File

@@ -9,7 +9,7 @@
/* Polish. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -17,52 +17,27 @@
#define L_LANGNAME "Polish"
/* Day names */
#if ISOLATIN1
# define L_SUNDAY "Niedziela"
# define L_MONDAY "Poniedzia\263ek"
# define L_MONDAY "Poniedziałek"
# define L_TUESDAY "Wtorek"
# define L_WEDNESDAY "\246roda"
# define L_WEDNESDAY "Środa"
# define L_THURSDAY "Czwartek"
# define L_FRIDAY "Pi\261tek"
# define L_FRIDAY "Piątek"
# define L_SATURDAY "Sobota"
#else
# define L_SUNDAY "Niedziela"
# define L_MONDAY "Poniedzialek"
# define L_TUESDAY "Wtorek"
# define L_WEDNESDAY "Sroda"
# define L_THURSDAY "Czwartek"
# define L_FRIDAY "Piatek"
# define L_SATURDAY "Sobota"
#endif
/* Month names */
#if ISOLATIN1
# define L_JAN "Stycze\361"
# define L_JAN "Styczeń"
# define L_FEB "Luty"
# define L_MAR "Marzec"
# define L_APR "Kwiecie\361"
# define L_APR "Kwiecień"
# define L_MAY "Maj"
# define L_JUN "Czerwiec"
# define L_JUL "Lipiec"
# define L_AUG "Sierpie\361"
# define L_SEP "Wrzesie\361"
# define L_OCT "Pa\274dziernik"
# define L_AUG "Sierpień"
# define L_SEP "Wrzesień"
# define L_OCT "Październik"
# define L_NOV "Listopad"
# define L_DEC "Grudzie\361"
#else
# define L_JAN "Styczen"
# define L_FEB "Luty"
# define L_MAR "Marzec"
# define L_APR "Kwiecien"
# define L_MAY "Maj"
# define L_JUN "Czerwiec"
# define L_JUL "Lipiec"
# define L_AUG "Sierpien"
# define L_SEP "Wrzesien"
# define L_OCT "Pazdziernik"
# define L_NOV "Listopad"
# define L_DEC "Grudzien"
#endif
# define L_DEC "Grudzień"
/* Today and tomorrow */
#define L_TODAY "dzisiaj"
@@ -97,22 +72,12 @@
#define L_AT "o"
#define L_MINUTE "minut"
#define L_HOUR "godzin"
#if ISOLATIN1
# define L_IS "b\352dzie"
# define L_WAS "by\263o"
#else
# define L_IS "bedzie"
# define L_WAS "bylo"
#endif
# define L_IS "będzie"
# define L_WAS "było"
#define L_AND "i"
/* What to add to make "hour" or "minute" plural */
#if ISOLATIN1
#define L_NPLU( N ) ((N == 1) ? "\352" : ((N==12) || (N==13) || (N==14)) ? "" : \
#define L_NPLU( N ) ((N == 1) ? "ę" : ((N==12) || (N==13) || (N==14)) ? "" : \
((N%10==2) || (N%10==3) || (N%10==4)) ? "y" : "" )
#else
#define L_NPLU( N ) ((N == 1) ? "e" : ((N==12) || (N==13) || (N==14)) ? "" : \
((N%10==2) || (N%10==3) || (N%10==4)) ? "y" : "" )
#endif
/* What to add to make "hour" plural */
#define L_HPLU L_NPLU( hdiff )
/* What to add to make "minute" plural */
@@ -120,25 +85,14 @@
/* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc.
See the file dosubst.c for more info. */
#if ISOLATIN1
#define L_AMPM_OVERRIDE(ampm, hour) \
ampm = (hour<12) ? \
(hour<5) ? " w nocy" \
: (hour<10) ? " rano" \
: " przed po\263udniem" \
: (hour<18) ? " po po\263udniu" \
: " przed południem" \
: (hour<18) ? " po południu" \
: (hour<22) ? " wieczorem" \
: " w nocy";
#else
#define L_AMPM_OVERRIDE(ampm, hour) \
ampm = (hour<12) ? \
(hour<5) ? " w nocy" \
: (hour<10) ? " rano" \
: " przed poludniem" \
: (hour<18) ? " po poludniu" \
: (hour<22) ? " wieczorem" \
: " w nocy";
#endif
#define L_ORDINAL_OVERRIDE plu = "";
#define L_A_OVER if (altmode == '*') { sprintf(s, "%s, %d. %s %d", DayName[jul%7], d, MonthName[m], y); } else { sprintf(s, "%s %s, %d. %s %d", L_ON, DayName[jul%7], d, MonthName[m], y); }
#define L_G_OVER if (altmode == '*') { sprintf(s, "%s, %d. %s", DayName[jul%7], d, MonthName[m]); } else { sprintf(s, "%s %s, %d. %s", L_ON, DayName[jul%7], d, MonthName[m]); }
@@ -178,104 +132,103 @@ else \
#define L_ERR_OVERRIDE 1
EXTERN char *ErrMsg[] =
{
#if ISOLATIN1
"OK",
"Brakuj\261cy ']'",
"Brakuj\261cy nawias",
"Zbyt skomplikowane wyra\277enie - za du\277o operator\363w",
"Zbyt skomplikowane wyra\277enie - za du\277o argument\363w",
"Brakuj\261cy ')'",
"Brakujący ']'",
"Brakujący nawias",
"Zbyt skomplikowane wyrażenie - za dużo operatorów",
"Zbyt skomplikowane wyrażenie - za dużo argumentów",
"Brakujący ')'",
"Nie zdefiniowana funkcja",
"Nielegalny znak",
"Spodziewany operator binarny",
"Brak pami\352ci",
"Brak pamięci",
"Niepoprawny numer",
"Pusty stos operator\363w - b\263\261d wewn\352trzny",
"Pusty stos zmiennych - b\263\261d wewn\352trzny",
"Niemo\277liwa konwersja",
"B\263\261d typu",
"Pusty stos operatorów - błąd wewnętrzny",
"Pusty stos zmiennych - błąd wewnętrzny",
"Niemożliwa konwersja",
"Błąd typu",
"Nadmiar daty",
"B\263\261d stosu - b\263\261d wewn\352trzny",
"Błąd stosu - błąd wewnętrzny",
"Dzielenie przez zero",
"Niezdefiniowana zmienna",
"Niespodziewany koniec linii",
"Niespodziewany koniec pliku",
"B\263\261d wejscia/wyjscia",
"Za d\263uga linia",
"B\263\261d wewn\352trzny",
"Z\263a specyfikacja daty",
"Za ma\263o argument\363w",
"Za du\277o argument\363w",
"Nieprawid\263owy czas",
"Liczba za du\277a",
"Liczba za ma\263a",
"Nie mog\352 otworzy\346 pliku",
"Zbyt zagnie\277d\277one INCLUDE",
"B\263\261d sk\263adniowy",
"Nie mog\352 obliczy\346 przypomnienia",
"Zbyt zagnie\277d\277one IF",
"Błąd wejscia/wyjscia",
"Za długa linia",
"Błąd wewnętrzny",
"Zła specyfikacja daty",
"Za mało argumentów",
"Za dużo argumentów",
"Nieprawidłowy czas",
"Liczba za duża",
"Liczba za mała",
"Nie mogę otworzyć pliku",
"Zbyt zagnieżdżone INCLUDE",
"Błąd składniowy",
"Nie mogę obliczyć przypomnienia",
"Zbyt zagnieżdżone IF",
"ELSE bez IF do pary",
"ENDIF bez IF do pary",
"Nie mog\352 omin\261\346 (OMIT) wszystkich dni",
"Nie mogę ominąć (OMIT) wszystkich dni",
"Niespodziewany wyraz w lini",
"POP-OMIT-CONTEXT bez PUSH-OMIT-CONTEXT",
"Komenda RUN zablokowana",
"B\263\261d dziedziny",
"Błąd dziedziny",
"Niepoprawny identyfikator",
"Wykryto rekursywne wywo\263anie funkcji",
"Wykryto rekursywne wywołanie funkcji",
"",
"Nie mog\352 zmieni\346 zmiennej systemowej",
"Funkcja biblioteki C nie mo\277e reprezentowac daty/czasu",
"Pr\363ba redefinicji funkcji wbudowanej",
"Nie wolno zagnie\277d\277a\346 definicji funkcji w wyra\277eniu",
"Aby u\277yc powt\363rzenia trzeba w pe\263ni wyspecyfikowa\346 dat\352",
"Rok podany dw\363krotnie",
"Miesi\261c podany dw\363krotnie",
"Dzie\361 podany dw\363krotnie",
"Nieznane s\263owo",
"W komendzie OMIT trzeba poda\346 miesi\261c i dzie\361",
"Za du\277o cz\352\266ciowych komend OMIT",
"Za du\277o pe\263nych komend OMIT",
"Ostrze\277enie: PUSH-OMIT-CONTEXT bez POP-OMIT-CONTEXT",
"B\263\261d odczytu pliku",
"Nie mogę zmienić zmiennej systemowej",
"Funkcja biblioteki C nie może reprezentowac daty/czasu",
"Próba redefinicji funkcji wbudowanej",
"Nie wolno zagnieżdżać definicji funkcji w wyrażeniu",
"Aby użyc powtórzenia trzeba w pełni wyspecyfikować datę",
"Rok podany dwókrotnie",
"Miesiąc podany dwókrotnie",
"Dzień podany dwókrotnie",
"Nieznane słowo",
"W komendzie OMIT trzeba podać miesiąc i dzień",
"Za dużo częściowych komend OMIT",
"Za dużo pełnych komend OMIT",
"Ostrzeżenie: PUSH-OMIT-CONTEXT bez POP-OMIT-CONTEXT",
"Błąd odczytu pliku",
"Oczekiwany koniec linii",
"B\263\352dna data hebrajska",
"IIF wymaga nieparzystej liczby argument\363w",
"Ostrze\277enie: Brakujacy ENDIF",
"Błędna data hebrajska",
"IIF wymaga nieparzystej liczby argumentów",
"Ostrzeżenie: Brakujacy ENDIF",
"Oczekiwany przecinek",
"Dzie\361 tygodnia podany dw\363krotnie",
"Dzień tygodnia podany dwókrotnie",
"Dozwolone tylko jedno z: BEFORE, AFTER i SKIP",
"Nie mo\277na zagnie\277d\277a\346 MSG, MSF, RUN, itp. w wyra\277eniu",
"Warto\266\346 powtorzenia podana dw\363krotnie",
"Warto\266\346 r\363\277nicy podana dw\363krotnie",
"Warto\266\346 cofni\352cia podana dw\363krotnie",
"S\263owo ONCE u\277yte dw\363krotnie.",
"Nie można zagnieżdżać MSG, MSF, RUN, itp. w wyrażeniu",
"Wartość powtorzenia podana dwókrotnie",
"Wartość różnicy podana dwókrotnie",
"Wartość cofnięcia podana dwókrotnie",
"Słowo ONCE użyte dwókrotnie.",
"Po AT oczekiwany jest czas",
"S\263owo THROUGH/UNTIL u\277yte dw\363krotnie",
"Słowo THROUGH/UNTIL użyte dwókrotnie",
"Niekompletna specyfikacja daty",
"S\263owo FROM/SCANFROM u\277yte dw\363krotnie",
"Słowo FROM/SCANFROM użyte dwókrotnie",
"Zmienna",
"Warto\266\346",
"Wartość",
"*NIE ZDEFINIOWANE*",
"Pocz\261tek UserFN",
"Początek UserFN",
"Koniec UserFN",
"Przemine\263o",
"Niepowodzenie w funkcji fork() - nie mog\352 kolejkowa\346 przypomnie\361",
"Nie ma dost\352pu do pliku",
"B\263\352dna data systemowa: Rok mniejszy ni\277 %d\n",
"Przemineło",
"Niepowodzenie w funkcji fork() - nie mogę kolejkować przypomnień",
"Nie ma dostępu do pliku",
"Błędna data systemowa: Rok mniejszy niż %d\n",
"Nieznana flaga odpluskwiania '%c'\n",
"Nieznana opcja '%c'\n",
"Nieznany u\277ytkownik '%s'\n",
"Nie mog\352 zmieni\346 gid na %d\n",
"Nie mog\352 zmieni\346 uid na %d\n",
"Brak pami\352ci na zmienne \266rodowiska\n",
"Nieznany użytkownik '%s'\n",
"Nie mogę zmienić gid na %d\n",
"Nie mogę zmienić uid na %d\n",
"Brak pamięci na zmienne środowiska\n",
"Brak znaku '='",
"Brak nazwy zmiennej",
"Brak wyra\277enia",
"Nie mog\352 zmieni\346 daty dost\352pu pliku %s\n",
"Brak wyrażenia",
"Nie mogę zmienić daty dostępu pliku %s\n",
"Remind: '-i' option: %s\n",
"Brak przypomnie\361.",
"%d Przypomnienia zakolejkowane na p\363\274niej.\n",
"Brak przypomnień.",
"%d Przypomnienia zakolejkowane na później.\n",
"Spodziewana liczba",
"Illegal function in WARN clause (NEEDS TRANSLATION TO POLISH)",
"Can't convert between time zones",
@@ -283,112 +236,6 @@ EXTERN char *ErrMsg[] =
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#else /* ISOLATIN1 */
"OK",
"Brakujacy ']'",
"Brakujacy nawias",
"Zbyt skomplikowane wyrazenie - za duzo operatorow",
"Zbyt skomplikowane wyrazenie - za duzo argumentow",
"Brakujacy ')'",
"Niezdefiniowana funkcja",
"Nielegalny znak",
"Spodziewany operator binarny",
"Brak pamieci",
"Niepoprawny numer",
"Pusty stos operatorow - blad wewnetrzny",
"Pusty stos zmiennych - blad wewnetrzny",
"Niemozliwa konwersja",
"Blad typu",
"Nadmiar daty",
"Blad stosu - blad wewnetrzny",
"Dzielenie przez zero",
"Niezdefiniowana zmienna",
"Niespodziewany koniec linii",
"Niespodziewany koniec pliku",
"Blad wejscia/wyjscia",
"Za dluga linia",
"Blad wewnetrzny",
"Zla specyfikacja daty",
"Za malo argumentow",
"Za duzo argumentow",
"Nieprawidlowy czas",
"Liczba za duza",
"Liczba za mala",
"Nie moge otworzyc pliku",
"INCLUDE zbyt zagniezdzone",
"Blad skladniowy",
"Nie moge obliczyc przypomnienia",
"Zbyt zagniezdzone IF",
"ELSE bez IF do pary",
"ENDIF bez IF do pary",
"Nie moge ominac (OMIT) wszystkich dni",
"Niespodziewany wyraz w lini",
"POP-OMIT-CONTEXT bez PUSH-OMIT-CONTEXT",
"Komenda RUN zablokowana",
"Blad dziedziny",
"Niepoprawny identyfikator",
"Wykryto rekursywne wywolanie funkcji",
"",
"Nie moga zmienic zmiennej systemowej",
"Funkcja biblioteki C nie moze reprezentowac daty/czasu",
"Proba redefinicji funkcji wbudowanej",
"Nie wolno zagniezdzac definicji funkcji w wyrazeniu",
"Aby uzyc powtorzenia trzeba w pelni wyspecyfikowac date",
"Rok podany dwokrotnie",
"Miesiac podany dwokrotnie",
"Dzien podany dwokrotnie",
"Nieznane slowo",
"W komendzie OMIT trzeba podac miesiac i dzien",
"Za duzo czesciowych komend OMIT",
"Za duzo pelnych komend OMIT",
"ostrzezenie: PUSH-OMIT-CONTEXT bez POP-OMIT-CONTEXT",
"Blad odczytu pliku",
"Oczekiwany koniec linii",
"Bledna data hebrajska",
"IIF wymaga nieparzystej liczby argumentow",
"Ostrzezenie: Brakujacy ENDIF",
"Oczekiwany przecinek",
"Dzien tygodnia podany dwokrotnie",
"Dozwolone tylko jedno z: BEFORE, AFTER i SKIP",
"Nie mozna zagniezdzac MSG, MSF, RUN, itp. w wyrazeniu",
"Wartosc powtorzenia podana dwokrotnie",
"Wartosc roznicy podana dwokrotnie",
"Wartosc cofniecia podana dwokrotnie",
"Slowo ONCE uzyte dwokrotnie.",
"Po AT oczekiwany jest czas",
"Slowo THROUGH/UNTIL uzyte dwokrotnie",
"Niekompletna specyfikacja daty",
"Slowo FROM/SCANFROM uzyte dwokrotnie",
"Zmienna",
"Wartosc",
"*UNDEFINED*",
"Poczatek UserFN",
"Koniec UserFN",
"Przeminelo",
"niepowodzenie w funkcji fork() - nie moge kolejkowac przypomnien",
"Nie ma dostepu do pliku",
"Bledna data systemowa: Rok mniejszy niz %d\n",
"Nieznana flaga odpluskwiania '%c'\n",
"Nieznana opcja '%c'\n",
"Nieznany uzytkownik '%s'\n",
"Nie moge zmienic gid na %d\n",
"Nie moge zmienic uid na %d\n",
"Brak pamieci na zmienne srodowiska\n",
"Brak znaku '='",
"Brak nazwy zmiennej",
"Brak wyrazenia",
"Nie moge zmienic daty dostepu pliku %s\n",
"Remind: '-i' option: %s\n",
"Brak przypomnien.",
"%d Przypomnienia zakolejkowane na pozniej.\n",
"Spodziewana liczba",
"Illegal function in WARN clause (NEEDS TRANSLATION TO POLISH)",
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT"
#endif /* ISOLATIN1 */
};
#endif /* MK_GLOBALS */
@@ -397,67 +244,37 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2020 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
#if ISOLATIN1
fprintf(ErrFp, "\nSpos\363b u\277ycia: remind [opcje] plik [data] [czas] [*powt\363rzenie]\n");
fprintf(ErrFp, "\nSposób użycia: remind [opcje] plik [data] [czas] [*powtórzenie]\n");
fprintf(ErrFp, "Opcje:\n");
fprintf(ErrFp, " -n Wypisz nast\352pne przypomnienia w prostym formacie\n");
fprintf(ErrFp, " -n Wypisz następne przypomnienia w prostym formacie\n");
fprintf(ErrFp, " -r Zablokuj dyrektywy RUN\n");
fprintf(ErrFp, " -c[n] Wypisz kalendarz na n (domy\266lnie 1) miesi\352cy\n");
fprintf(ErrFp, " -c+[n] Wypisz kalendarz na n (domy\266lnie 1) tygodni\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Ustaw szeroko\266\346, wype\263nienie i odst\352py w kalendarzu\n");
fprintf(ErrFp, " -s[+][n] Wypisz uproszczony kalendarz na n (1) miesi\352cy (tygodni)\n");
fprintf(ErrFp, " -c[n] Wypisz kalendarz na n (domyślnie 1) miesięcy\n");
fprintf(ErrFp, " -c+[n] Wypisz kalendarz na n (domyślnie 1) tygodni\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Ustaw szerokość, wypełnienie i odstępy w kalendarzu\n");
fprintf(ErrFp, " -s[+][n] Wypisz uproszczony kalendarz na n (1) miesięcy (tygodni)\n");
fprintf(ErrFp, " -p[n] To samo co -s, ale kompatybilne z rem2ps\n");
fprintf(ErrFp, " -v Obszerniejsze komentarze\n");
fprintf(ErrFp, " -o Ignoruj instrukcje ONCE\n");
fprintf(ErrFp, " -t Odpal wszystkie przysz\263e przypomnienia niezale\277nie od delty\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\361 czasowych - kolejkuj je\n");
fprintf(ErrFp, " -q Nie kolejkuj przyponie\361 czasowych\n");
fprintf(ErrFp, " -f Nie przechod\274 do pracy w tle\n");
fprintf(ErrFp, " -z[n] Pracuj jako demon, budz\261c si\352 co n (5) minut\n");
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\263\352dach skieruj na stdout\n");
fprintf(ErrFp, " -b[n] Format czasu: 0=am/pm, 1=24godz., 2=\277aden\n");
fprintf(ErrFp, " -x[n] Limit powt\363rze\361 klauzuli SATISFY (domy\266lnie=150)\n");
fprintf(ErrFp, " -kcmd Wywo\263aj 'cmd' dla przypomnie\361 typu MSG\n");
fprintf(ErrFp, " -g[ddd] Sortuj przypomnienia wed\263ug daty, czasu i priorytetu\n");
fprintf(ErrFp, " -ivar=val Zainicjuj zmienn\261 var warto\266cia val i zachowaj ja\n");
fprintf(ErrFp, " -m Rozpocznij kalendarz od poniedzia\263ku zamiast od niedzieli\n");
#else /* ISOLATIN1 */
fprintf(ErrFp, "\nSposob uzycia: remind [opcje] plik [data] [czas] [*powtorzenie]\n");
fprintf(ErrFp, "Opcje:\n");
fprintf(ErrFp, " -n Wypisz nastepne przypomnienia w prostym formacie\n");
fprintf(ErrFp, " -r Zablokuj dyrektywy RUN\n");
fprintf(ErrFp, " -c[n] Wypisz kalendarz na n (domyslnie 1) miesiecy\n");
fprintf(ErrFp, " -c+[n] Wypisz kalendarz na n (domyslnie 1) tygodni\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Ustaw szerokosc, wypelnienie i odstepy w kalendarzu\n");
fprintf(ErrFp, " -s[+][n] Wypisz uproszczony kalendarz na n (1) miesiecy (tygodni)\n");
fprintf(ErrFp, " -p[n] To samo co -s, ale kompatybilne z rem2ps\n");
fprintf(ErrFp, " -v Obszerniejsze komentarze\n");
fprintf(ErrFp, " -o Ignoruj instrukcje ONCE\n");
fprintf(ErrFp, " -t Odpal wszystkie przyszle przypomnienia niezaleznie od delty\n");
fprintf(ErrFp, " -h Praca bezszmerowa\n");
#ifdef HAVE_QUEUED
fprintf(ErrFp, " -a Nie odpalaj przyponien czasowych - kolejkuj je\n");
fprintf(ErrFp, " -q Nie kolejkuj przyponien czasowych\n");
fprintf(ErrFp, " -f Nie przechodz do pracy w tle\n");
fprintf(ErrFp, " -z[n] Pracuj jako demon, budzac sie 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 bledach skieruj na stdout\n");
fprintf(ErrFp, " -b[n] Format czasu: 0=am/pm, 1=24godz., 2=zaden\n");
fprintf(ErrFp, " -x[n] Limit powtorzen klauzuli SATISFY (domyslnie=150)\n");
fprintf(ErrFp, " -kcmd Wywolaj 'cmd' dla przypomnien typu MSG\n");
fprintf(ErrFp, " -g[ddd] Sortuj przypomnienia wedlug daty, czasu i priorytetu\n");
fprintf(ErrFp, " -ivar=val Zainicjuj zmienna var wartoscia val i zachowaj ja\n");
fprintf(ErrFp, " -m Rozpocznij kalendarz od poniedzialku zamiast od niedzieli\n");
#endif /* ISOLATIN1 */
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");
fprintf(ErrFp, " -x[n] Limit powtórzeń klauzuli SATISFY (domyślnie=150)\n");
fprintf(ErrFp, " -kcmd Wywołaj 'cmd' dla przypomnień typu MSG\n");
fprintf(ErrFp, " -g[ddd] Sortuj przypomnienia według daty, czasu i priorytetu\n");
fprintf(ErrFp, " -ivar=val Zainicjuj zmienną var wartościa val i zachowaj ja\n");
fprintf(ErrFp, " -m Rozpocznij kalendarz od poniedziałku zamiast od niedzieli\n");
exit(1);
}
#endif /* L_IN_INIT */

View File

@@ -8,7 +8,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2020 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
/* This file is Copyright (C) 1996 by Marco Paganini and */
/* Dianne Skoll. */
/* */
@@ -257,7 +257,7 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-2020 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> VERSAO BETA <<<<\n");
#endif

View File

@@ -8,7 +8,7 @@
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2020 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
/* This file is Copyright (C) 1996-1998 by Liviu Daia */
/* */
/***************************************************************/
@@ -17,39 +17,13 @@
#define L_LANGNAME "Romanian"
/* Day names */
#if ISOLATIN1
# define L_SUNDAY "Duminica"
# define L_SUNDAY "Duminică"
# define L_MONDAY "Luni"
# define L_TUESDAY "Marti"
# define L_TUESDAY "Marți"
# define L_WEDNESDAY "Miercuri"
# define L_THURSDAY "Joi"
# define L_FRIDAY "Vineri"
# define L_SATURDAY "S\342mbata"
#elif ISOLATIN2
# define L_SUNDAY "Duminic\343"
# define L_MONDAY "Luni"
# define L_TUESDAY "Mar\376i"
# define L_WEDNESDAY "Miercuri"
# define L_THURSDAY "Joi"
# define L_FRIDAY "Vineri"
# define L_SATURDAY "S\342mb\343t\343"
#elif IBM852
# define L_SUNDAY "Duminic\307"
# define L_MONDAY "Luni"
# define L_TUESDAY "Mar\316i"
# define L_WEDNESDAY "Miercuri"
# define L_THURSDAY "Joi"
# define L_FRIDAY "Vineri"
# define L_SATURDAY "S\203mb\307t\307"
#else
# define L_SUNDAY "Duminica"
# define L_MONDAY "Luni"
# define L_TUESDAY "Marti"
# define L_WEDNESDAY "Miercuri"
# define L_THURSDAY "Joi"
# define L_FRIDAY "Vineri"
# define L_SATURDAY "Sambata"
#endif
# define L_SATURDAY "Sâmbătă"
/* Month names */
#define L_JAN "Ianuarie"
@@ -66,19 +40,8 @@
#define L_DEC "Decembrie"
/* Today and tomorrow */
#if ISOLATIN1
# define L_TODAY "astazi"
# define L_TOMORROW "m\342ine"
#elif ISOLATIN2
# define L_TODAY "ast\343zi"
# define L_TOMORROW "m\342ine"
#elif IBM852
# define L_TODAY "ast\307zi"
# define L_TOMORROW "m\203ine"
#else
# define L_TODAY "astazi"
# define L_TOMORROW "maine"
#endif
# define L_TODAY "astăzi"
# define L_TOMORROW "mâine"
/* The default banner */
#define L_BANNER "Reamintiri pentru %w, %d %m %y%o:"
@@ -114,30 +77,13 @@
/* What to add to make "minute" plural */
#define L_MPLU "e"
#if ISOLATIN2
/* What to add to make "hour" plural */
# define L_HPLU_OVER hplu = (hdiff == 1 ? "\343" : "e");
# define L_AND "\272i"
#elif IBM852
/* What to add to make "hour" plural */
# define L_HPLU_OVER hplu = (hdiff == 1 ? "\307" : "e");
# define L_AND "\255i"
#else
/* What to add to make "hour" plural */
# define L_HPLU_OVER hplu = (hdiff == 1 ? "a" : "e");
# define L_AND "si"
#endif
/* What to add to make "hour" plural */
#define L_HPLU_OVER hplu = (hdiff == 1 ? "ă" : "e");
#define L_AND "şi"
/* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc.
See the file dosubst.c for more info. */
#if ISOLATIN2
# define L_AMPM_OVERRIDE(ampm, hour) ampm = (hour < 12) ? (hour<4) ? " noaptea" : " diminea\376a" : (hour > 17) ? " seara" : " dup\343-amiaza";
#elif IBM852
# define L_AMPM_OVERRIDE(ampm, hour) ampm = (hour < 12) ? (hour<4) ? " noaptea" : " diminea\316a" : (hour > 17) ? " seara" : " dup\307-amiaza";
#else
# define L_AMPM_OVERRIDE(ampm, hour) ampm = (hour < 12) ? (hour<4) ? " noaptea" : " dimineata" : (hour > 17) ? " seara" : " dupa-amiaza";
#endif
#define L_AMPM_OVERRIDE(ampm, hour) ampm = (hour < 12) ? (hour<4) ? " noaptea" : " dimineaţa" : (hour > 17) ? " seara" : " după-amiaza";
#define L_ORDINAL_OVERRIDE plu = "";
#define L_A_OVER sprintf(s, "%s, %d %s %d", DayName[jul%7], d, MonthName[m], y);

View File

@@ -7,7 +7,7 @@
/* Author: Rafa Couto <rafacouto@biogate.com> */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -17,19 +17,10 @@
#define L_SUNDAY "Domingo"
#define L_MONDAY "Lunes"
#define L_TUESDAY "Martes"
#if ISOLATIN1
#define L_WEDNESDAY "Mi\351rcoles"
#else
#define L_WEDNESDAY "Miercoles"
#endif
#define L_WEDNESDAY "Miércoles"
#define L_THURSDAY "Jueves"
#define L_FRIDAY "Viernes"
#if ISOLATIN1
#define L_SATURDAY "S\341bado"
#else
#define L_SATURDAY "Sabado"
#endif
#define L_SATURDAY "Sábado"
/* Nombres de los meses */
#define L_JAN "Enero"
@@ -47,11 +38,7 @@
/* Hoy y man~ana */
#define L_TODAY "hoy"
#if ISOLATIN1
#define L_TOMORROW "ma\361ana"
#else
#define L_TOMORROW "manana"
#endif
#define L_TOMORROW "mañana"
/* El titular habitual */
#define L_BANNER "Agenda para el %w, %d%s %m, %y%o:"
@@ -68,13 +55,8 @@
#define L_FROMNOW "desde hoy"
/* "dentro de %d di'as" */
#if ISOLATIN1
#define L_INXDAYS "dentro de %d d\355as"
#define L_ON "el d\355a"
#else
#define L_INXDAYS "dentro de %d di'as"
#define L_ON "el di'a"
#endif
#define L_INXDAYS "dentro de %d días"
#define L_ON "el día"
/* "el di'a..." */

View File

@@ -6,7 +6,7 @@
/* routines, etc. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -235,12 +235,22 @@ static void DoReminders(void)
case T_Else: r=DoElse(&p); break;
case T_EndIf: r=DoEndif(&p); break;
case T_Include:
case T_IncludeR:
/* In purge mode, include closes file, so we
need to echo it here! */
if (PurgeMode) {
PurgeEchoLine("%s\n", CurLine);
}
r=DoInclude(&p);
r=DoInclude(&p, tok.type);
purge_handled = 1;
break;
case T_IncludeCmd:
/* In purge mode, include closes file, so we
need to echo it here! */
if (PurgeMode) {
PurgeEchoLine("%s\n", CurLine);
}
r=DoIncludeCmd(&p);
purge_handled = 1;
break;
case T_Exit: DoExit(&p); break;
@@ -1405,3 +1415,23 @@ System(char const *cmd)
r = 1;
}
}
char const *
get_day_name(int wkday)
{
if (wkday < 0 || wkday > 6) {
return "INVALID_WKDAY";
}
if (DynamicDayName[wkday]) return DynamicDayName[wkday];
return DayName[wkday];
}
char const *
get_month_name(int mon)
{
if (mon < 0 || mon > 11) {
return "INVALID_MON";
}
if (DynamicMonthName[mon]) return DynamicMonthName[mon];
return MonthName[mon];
}

View File

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

View File

@@ -6,7 +6,7 @@
/* the data structures for OMITted dates. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -370,20 +370,30 @@ int DoOmit(ParsePtr p)
NumPartialOmits++;
}
} else {
if (NumFullOmits == MAX_FULL_OMITS) return E_2MANY_FULL;
if (d > DaysInMonth(m, y)) return E_BAD_DATE;
syndrome = Julian(y, m, d);
if (!BexistsIntArray(FullOmitArray, NumFullOmits, syndrome)) {
InsertIntoSortedArray(FullOmitArray, NumFullOmits, syndrome);
NumFullOmits++;
}
r = AddGlobalOmit(syndrome);
if (r) {
return r;
}
}
if (tok.type == T_Tag || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
return OK;
}
int
AddGlobalOmit(int jul)
{
if (NumFullOmits == MAX_FULL_OMITS) return E_2MANY_FULL;
if (!BexistsIntArray(FullOmitArray, NumFullOmits, jul)) {
InsertIntoSortedArray(FullOmitArray, NumFullOmits, jul);
NumFullOmits++;
}
return OK;
}
static int
DoThroughOmit(ParsePtr p, int ystart, int mstart, int dstart)
{

View File

@@ -5,7 +5,7 @@
/* Function Prototypes. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -44,7 +44,8 @@ void PrintValue (Value *v, FILE *fp);
int CopyValue (Value *dest, const Value *src);
int ReadLine (void);
int OpenFile (char const *fname);
int DoInclude (ParsePtr p);
int DoInclude (ParsePtr p, enum TokTypes tok);
int DoIncludeCmd (ParsePtr p);
int IncludeFile (char const *fname);
int GetAccessDate (char const *file);
int SetAccessDate (char const *fname, int jul);
@@ -161,3 +162,10 @@ void PrintJSONKeyPairDate(char const *name, int jul);
void PrintJSONKeyPairDateTime(char const *name, int dt);
void PrintJSONKeyPairTime(char const *name, int t);
void System(char const *cmd);
int ShellEscape(char const *in, DynamicBuffer *out);
int AddGlobalOmit(int jul);
void set_lat_and_long_from_components(void);
void set_components_from_lat_and_long(void);
char const *get_day_name(int wkday);
char const *get_month_name(int mon);

View File

@@ -5,7 +5,7 @@
/* Queue up reminders for subsequent execution. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -57,7 +57,7 @@ static void CheckInitialFile (void);
static int CalculateNextTime (QueuedRem *q);
static QueuedRem *FindNextReminder (void);
static int CalculateNextTimeUsingSched (QueuedRem *q);
static void DaemonWait (unsigned int sleeptime);
static void DaemonWait (struct timeval *sleep_tv);
static void reread (void);
/***************************************************************/
@@ -121,6 +121,8 @@ void HandleQueuedReminders(void)
unsigned SleepTime;
Parser p;
Trigger trig;
struct timeval tv;
struct timeval sleep_tv;
/* Suppress the BANNER from being issued */
NumTriggered = 1;
@@ -186,16 +188,20 @@ void HandleQueuedReminders(void)
/* Wake up once a minute to recalibrate sleep time in
case of laptop hibernation */
if (Daemon <= 0) {
if (Daemon < 0) {
/* Wake up on the next exact minute */
SleepTime = 60 - (SystemTime(1)%60);
}
if (Daemon >= 0) {
sleep(SleepTime);
gettimeofday(&tv, NULL);
sleep_tv.tv_sec = 60 - (tv.tv_sec % 60);
if (tv.tv_usec != 0 && sleep_tv.tv_sec != 0) {
sleep_tv.tv_sec--;
sleep_tv.tv_usec = 1000000 - tv.tv_usec;
} else {
sleep_tv.tv_usec = 0;
}
DaemonWait(&sleep_tv);
} else {
DaemonWait(SleepTime);
}
sleep(SleepTime);
}
/* If not in daemon mode and day has rolled around,
exit -- not much we can do. */
@@ -519,19 +525,16 @@ json_queue(QueuedRem const *q)
/* Sleep or read command from stdin in "daemon -1" mode */
/* */
/***************************************************************/
static void DaemonWait(unsigned int sleeptime)
static void DaemonWait(struct timeval *sleep_tv)
{
fd_set readSet;
struct timeval timeout;
int retval;
int y, m, d;
char cmdLine[256];
FD_ZERO(&readSet);
FD_SET(0, &readSet);
timeout.tv_sec = sleeptime;
timeout.tv_usec = 0;
retval = select(1, &readSet, NULL, NULL, &timeout);
retval = select(1, &readSet, NULL, NULL, sleep_tv);
/* If date has rolled around, restart */
if (RealToday != SystemDate(&y, &m, &d)) {

View File

@@ -383,6 +383,7 @@ void DoPsCal(void)
int firstcol;
DynamicBuffer buf;
CalEntry *c, *d, *p;
char *s;
/* Read the month and year name, followed by # days in month and 1st day of
month */
@@ -391,12 +392,28 @@ void DoPsCal(void)
sscanf(DBufValue(&buf), "%s %s %d %d %d", month, year, &days, &wkday,
&MondayFirst);
/* Replace underscores in month name with spaces */
s = month;
while(*s) {
if (*s == '_') *s = ' ';
s++;
}
/* Get day names */
DBufGets(&buf, stdin);
sscanf(DBufValue(&buf), "%32s %32s %32s %32s %32s %32s %32s",
DayName[0], DayName[1], DayName[2], DayName[3],
DayName[4], DayName[5], DayName[6]);
/* Replace underscores in day names with spaces */
for (i=0; i<7; i++) {
s = DayName[i];
while(*s) {
if (*s == '_') *s = ' ';
s++;
}
}
/* We write the prolog here because it's only at this point that
MondayFirst is set correctly. */
if (validfile == 1) {
@@ -407,6 +424,19 @@ void DoPsCal(void)
sscanf(DBufValue(&buf), "%s %d", prevm, &prevdays);
DBufGets(&buf, stdin);
sscanf(DBufValue(&buf), "%s %d", nextm, &nextdays);
/* Replace underscores with spaces in names of next/prev month */
s = prevm;
while(*s) {
if (*s == '_') *s = ' ';
s++;
}
s = nextm;
while(*s) {
if (*s == '_') *s = ' ';
s++;
}
DBufFree(&buf);
MaxDay = days;
FirstWkDay = wkday;

View File

@@ -5,7 +5,7 @@
/* Routines for sorting reminders by trigger date */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -5,7 +5,8 @@
ALL=`grep ^#define lang.h | grep -v '#define LANG' | awk '{print $2}'`
for i in $ALL ; do
make clean all LANGDEF=-DLANG=$i || exit 1
make clean
make -j`nproc` all LANGDEF=-DLANG=$i || exit 1
./remind -q -r ../tests/tstlang.rem
done
exit 0

View File

@@ -6,7 +6,7 @@
/* classifying the tokens parsed. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -37,7 +37,7 @@ while (isdigit(*(string))) { \
Keep this array sorted, or software will not work. */
Token TokArray[] = {
/* NAME MINLEN TYPE VALUE */
{ "addomit", 7, T_AddOmit, 0 },
{ "after", 3, T_Skip, AFTER_SKIP },
{ "april", 3, T_Month, 3 },
{ "at", 2, T_At, 0 },
@@ -48,6 +48,7 @@ Token TokArray[] = {
{ "clear-omit-context", 5, T_Clr, 0 },
{ "debug", 5, T_Debug, 0 },
{ "december", 3, T_Month, 11 },
{ "do", 2, T_IncludeR, 0 },
{ "dumpvars", 4, T_Dumpvars, 0 },
{ "duration", 3, T_Duration, 0 },
{ "else", 4, T_Else, 0 },
@@ -62,6 +63,7 @@ Token TokArray[] = {
{ "if", 2, T_If, 0 },
{ "iftrig", 6, T_IfTrig, 0 },
{ "include", 3, T_Include, 0 },
{ "includecmd", 10, T_IncludeCmd, 0 },
{ "january", 3, T_Month, 0 },
{ "july", 3, T_Month, 6 },
{ "june", 3, T_Month, 5 },
@@ -103,33 +105,6 @@ Token TokArray[] = {
{ "wednesday", 3, T_WkDay, 2 }
};
/* If language != English, we must also search the following... */
#if LANG != ENGLISH
Token NonEnglishToks[] = {
/* NAME MINLEN TYPE VALUE */
{ L_MONDAY, 3, T_WkDay, 0 },
{ L_TUESDAY, 3, T_WkDay, 1 },
{ L_WEDNESDAY, 3, T_WkDay, 2 },
{ L_THURSDAY, 3, T_WkDay, 3 },
{ L_FRIDAY, 3, T_WkDay, 4 },
{ L_SATURDAY, 3, T_WkDay, 5 },
{ L_SUNDAY, 3, T_WkDay, 6 },
{ L_JAN, 3, T_Month, 0 },
{ L_FEB, 3, T_Month, 1 },
{ L_MAR, 3, T_Month, 2 },
{ L_APR, 3, T_Month, 3 },
{ L_MAY, 3, T_Month, 4 },
{ L_JUN, 3, T_Month, 5 },
{ L_JUL, 3, T_Month, 6 },
{ L_AUG, 3, T_Month, 7 },
{ L_SEP, 3, T_Month, 8 },
{ L_OCT, 3, T_Month, 9 },
{ L_NOV, 3, T_Month, 10 },
{ L_DEC, 3, T_Month, 11 }
};
#endif
static int TokStrCmp (Token const *t, char const *s);
/***************************************************************/
@@ -172,6 +147,10 @@ void FindToken(char const *s, Token *tok)
int top, bot, mid, r, max;
int l;
#if LANG != ENGLISH
size_t i;
#endif
tok->type = T_Illegal;
if (! *s) {
tok->type = T_Empty;
@@ -226,19 +205,6 @@ void FindToken(char const *s, Token *tok)
if (r > 0) top = mid-1; else bot=mid+1;
}
/* If language is other than English, search the DayNames[] and MonthNames[]
array. */
#if LANG != ENGLISH
for (size_t x=0; x<(sizeof(NonEnglishToks) / sizeof(Token)); x++) {
if (l >= NonEnglishToks[x].MinLen &&
!TokStrCmp(&NonEnglishToks[x], s)) {
tok->type = NonEnglishToks[x].type;
tok->val = NonEnglishToks[x].val;
return;
}
}
#endif
return;
}
@@ -332,9 +298,6 @@ void FindNumericToken(char const *s, Token *t)
/* If we hit a non-digit, error! */
if (*s) return;
/* Special hack - convert years between 90 and 99 to 1990 and 1999 */
if (t->val >= 90 && t->val <= 99) t->val += 1900;
/* Classify the number we've got */
if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
else if (t->val >= 1 && t->val <= 31) t->type = T_Day;

View File

@@ -5,7 +5,7 @@
/* Routines for figuring out the trigger date of a reminder */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -24,6 +24,8 @@
#define GOT_YR 4
#define GOT_WD 8
#define ADVANCE_TO_WD(x, wd) while (! ((wd) & (1 << ((x)%7)))) (x)++
static int JYear(int jul);
static int JMonth(int jul);
static int NextSimpleTrig(int startdate, Trigger *trig, int *err);
@@ -58,9 +60,10 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
if (trig->wd != NO_WD) typ |= GOT_WD;
switch(typ) {
case 0:
return startdate;
case GOT_WD:
if (trig->wd != NO_WD)
while(! (trig->wd & (1 << (startdate%7)))) startdate++;
ADVANCE_TO_WD(startdate, trig->wd);
return startdate;
case GOT_DAY:
@@ -83,12 +86,12 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
else return -1;
case GOT_DAY+GOT_MON:
if (m > trig->m || (m == trig->m && d > trig->d)) y++;
if (trig->d > MonthDays[trig->m]) {
*err = E_BAD_DATE;
return -1;
}
if (m > trig->m || (m == trig->m && d > trig->d)) y++;
/* Take care of Feb. 29 */
while (trig->d > DaysInMonth(trig->m, y)) y++;
return Julian(y, trig->m, trig->d);
@@ -121,19 +124,19 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
if (y > trig->y) return -1;
if (y < trig->y) j = Julian(trig->y, 0, 1);
else j = startdate;
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (JYear(j) > trig->y) return -1;
return j;
case GOT_MON+GOT_WD:
if (m == trig->m) {
j = startdate;
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (JMonth(j) == trig->m) return j;
}
if (m >= trig->m) j = Julian(y+1, trig->m, 1);
else j = Julian(y, trig->m, 1);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j; /* Guaranteed to be within the month */
case GOT_DAY+GOT_WD:
@@ -144,7 +147,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
/* If there are fewer days in previous month, no match */
if (trig->d <= DaysInMonth(m2, y2)) {
j = Julian(y2, m2, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (j >= startdate) return j;
}
@@ -153,7 +156,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
/* Try this month */
if (trig->d <= DaysInMonth(m, y)) {
j = Julian(y, m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (j >= startdate) return j;
}
@@ -162,18 +165,18 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
if (m2 > 11) { m2 = 0; y++; }
while (trig->d > DaysInMonth(m2, y)) m2++;
j = Julian(y, m2, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j;
case GOT_WD+GOT_YR+GOT_DAY:
if (y > trig->y+1 || (y > trig->y && m>0)) return -1;
if (y > trig->y) {
j = Julian(trig->y, 11, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (j >= startdate) return j;
} else if (y < trig->y) {
j = Julian(trig->y, 0, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j;
} else {
/* Try last month */
@@ -181,14 +184,16 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
m2 = m-1;
while (trig->d > DaysInMonth(m2, trig->y)) m2--;
j = Julian(trig->y, m2, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (JYear(j) > trig->y) return -1;
if (j >= startdate) return j;
}
}
/* Try this month */
if (trig->d <= DaysInMonth(m, trig->y)) {
j = Julian(trig->y, m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (JYear(j) > trig->y) return -1;
if (j >= startdate) return j;
}
@@ -197,7 +202,8 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
m++;
while (trig->d > DaysInMonth(m, trig->d)) m++;
j = Julian(trig->y, m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (JYear(j) > trig->y) return -1;
return j;
case GOT_DAY+GOT_MON+GOT_WD:
@@ -215,31 +221,32 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
/* Try last year */
j = Julian(y, trig->m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (j >= startdate) return j;
/* Try this year */
y++;
while (trig->d > DaysInMonth(trig->m, y)) y++;
j = Julian(y, trig->m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
if (j >= startdate) return j;
/* Must be next year */
y++;
while (trig->d > DaysInMonth(trig->m, y)) y++;
j = Julian(y, trig->m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j;
case GOT_WD+GOT_MON+GOT_YR:
if (y > trig->y || (y == trig->y && m > trig->m)) return -1;
if (trig->y > y || (trig->y == y && trig->m > m)) {
j = Julian(trig->y, trig->m, 1);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j;
} else {
j = startdate;
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
FromJulian(j, &y2, &m2, &d2);
if (m2 == trig->m) return j; else return -1;
}
@@ -250,7 +257,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
return -1;
}
j = Julian(trig->y, trig->m, trig->d);
while(! (trig->wd & (1 << (j%7)))) j++;
ADVANCE_TO_WD(j, trig->wd);
return j;
default:
@@ -435,9 +442,9 @@ AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int sav
FromJulian(r, &y, &m, &d);
fprintf(ErrFp, "%s(%d): Trig(adj) = %s, %d %s, %d",
FileName, LineNo,
DayName[r % 7],
get_day_name(r % 7),
d,
MonthName[m],
get_month_name(m),
y);
if (tim->ttime != NO_TIME) {
fprintf(ErrFp, " AT %02d:%02d",
@@ -586,9 +593,9 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
FromJulian(result, &y, &m, &d);
fprintf(ErrFp, "%s(%d): Trig = %s, %d %s, %d",
FileName, LineNo,
DayName[result % 7],
get_day_name(result % 7),
d,
MonthName[m],
get_month_name(m),
y);
if (tim->ttime != NO_TIME) {
fprintf(ErrFp, " AT %02d:%02d",

View File

@@ -5,7 +5,7 @@
/* Type definitions all dumped here. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -74,6 +74,7 @@ typedef struct {
int eventstart; /* Original event start (datetime) */
int eventduration; /* Original event duration (minutes) */
int maybe_uncomputable; /* Suppress "can't compute trigger" warnings */
int addomit; /* Add trigger date to global OMITs */
char sched[VAR_NAME_LEN+1]; /* Scheduling function */
char warn[VAR_NAME_LEN+1]; /* Warning function */
char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */
@@ -150,9 +151,10 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
enum TokTypes
{ T_Illegal,
/* Commands first */
T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_If, T_Else, T_EndIf,
T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_IncludeR, T_IncludeCmd, T_If, T_Else, T_EndIf,
T_IfTrig, T_ErrMsg,
T_Set, T_UnSet, T_Fset, T_Omit, T_Banner, T_Exit,
T_AddOmit,
T_WkDay,
T_Month, T_Time, T_Date, T_DateTime,
T_Skip, T_At, T_RemType, T_Until, T_Year, T_Day, T_Rep, T_Delta, T_Back,

View File

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

View File

@@ -5,11 +5,15 @@
/* Useful utility functions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
static char const DontEscapeMe[] =
"1234567890_-=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.,/";
#include "config.h"
#include "err.h"
#include <string.h>
#include <stdio.h>
@@ -146,3 +150,15 @@ int _private_unminus_overflow(int a, int b)
if (a < 0 && b < 0) return 1;
return 0;
}
int
ShellEscape(char const *in, DynamicBuffer *out)
{
while(*in) {
if (!strchr(DontEscapeMe, *in)) {
if (DBufPutc(out, '\\') != OK) return E_NO_MEM;
}
if (DBufPutc(out, *in++) != OK) return E_NO_MEM;
}
return OK;
}

324
src/var.c
View File

@@ -6,7 +6,7 @@
/* user- and system-defined variables. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include "types.h"
#include "expr.h"
#include "globals.h"
@@ -39,6 +40,99 @@ static Var *VHashTbl[VAR_HASH_SIZE];
typedef int (*SysVarFunc)(int, Value *);
static void deprecated_var(char const *var, char const *instead)
{
if (DebugFlag & DB_PRTLINE) {
Eprint("%s is deprecated; use %s instead", var, instead);
FreshLine = 1;
}
}
static int latlong_component_func(int do_set, Value *val, int *var, int min, int max, char const *varname, char const *newvarname)
{
if (!do_set) {
val->type = INT_TYPE;
val->v.val = *var;
return OK;
}
deprecated_var(varname, newvarname);
if (val->type != INT_TYPE) return E_BAD_TYPE;
if (val->v.val < min) return E_2LOW;
if (val->v.val > max) return E_2HIGH;
*var = val->v.val;
set_lat_and_long_from_components();
return OK;
}
static int latdeg_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LatDeg, -90, 90, "$LatDeg", "$Latitude");
}
static int latmin_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LatMin, -59, 59, "$LatMin", "$Latitude");
}
static int latsec_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LatSec, -59, 59, "$LatSec", "$Latitude");
}
static int longdeg_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LongDeg, -180, 180, "$LongDeg", "$Longitude");
}
static int longmin_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LongMin, -59, 59, "$LongMin", "$Longitude");
}
static int longsec_func(int do_set, Value *val)
{
return latlong_component_func(do_set, val, &LongSec, -59, 59, "$LongSec", "$Longitude");
}
static int latitude_longitude_func(int do_set, Value *val, double *var, double min, double max) {
char buf[64];
double x;
char *endptr;
if (!do_set) {
snprintf(buf, sizeof(buf), "%f", *var);
val->v.str = malloc(strlen(buf)+1);
if (!val->v.str) return E_NO_MEM;
strcpy(val->v.str, buf);
val->type = STR_TYPE;
return OK;
}
if (val->type == INT_TYPE) {
x = (double) val->v.val;
} else {
if (val->type != STR_TYPE) return E_BAD_TYPE;
errno = 0;
x = strtod(val->v.str, &endptr);
if (errno) return E_BAD_TYPE;
if (*endptr) return E_BAD_TYPE;
}
if (x < min) return E_2LOW;
if (x > max) return E_2HIGH;
*var = x;
set_components_from_lat_and_long();
return OK;
}
static int longitude_func(int do_set, Value *val)
{
return latitude_longitude_func(do_set, val, &Longitude, -180.0, 180.0);
}
static int latitude_func(int do_set, Value *val)
{
return latitude_longitude_func(do_set, val, &Latitude, -90.0, 90.0);
}
static int trig_date_func(int do_set, Value *val)
{
UNUSED(do_set);
@@ -177,15 +271,15 @@ static int default_color_func(int do_set, Value *val)
int col_r, col_g, col_b;
if (!do_set) {
/* 12 = strlen("255 255 255\0") */
val->v.str = malloc(12);
if (!val->v.str) return E_NO_MEM;
snprintf(val->v.str, 12, "%d %d %d",
DefaultColorR,
DefaultColorG,
DefaultColorB
);
val->type = STR_TYPE;
return OK;
val->v.str = malloc(12);
if (!val->v.str) return E_NO_MEM;
snprintf(val->v.str, 12, "%d %d %d",
DefaultColorR,
DefaultColorG,
DefaultColorB
);
val->type = STR_TYPE;
return OK;
}
if (val->type != STR_TYPE) return E_BAD_TYPE;
if (sscanf(val->v.str, "%d %d %d", &col_r, &col_g, &col_b) != 3) {
@@ -634,6 +728,7 @@ typedef struct {
void *value;
int min;
int max;
int (*validate)(void const *newvalue);
} SysVar;
/* If the type of a sys variable is STR_TYPE, then min is redefined
@@ -645,61 +740,83 @@ typedef struct {
/* All of the system variables sorted alphabetically */
static SysVar SysVarArr[] = {
/* name mod type value min/mal max */
{"CalcUTC", 1, INT_TYPE, &CalculateUTC, 0, 1 },
{"CalMode", 0, INT_TYPE, &DoCalendar, 0, 0 },
{"Daemon", 0, INT_TYPE, &Daemon, 0, 0 },
{"DateSep", 1, SPECIAL_TYPE, date_sep_func, 0, 0 },
{"DateTimeSep", 1, SPECIAL_TYPE, datetime_sep_func, 0, 0 },
{"DefaultColor", 1, SPECIAL_TYPE, default_color_func, 0, 0 },
{"DefaultPrio", 1, INT_TYPE, &DefaultPrio, 0, 9999},
{"DeltaOffset", 0, INT_TYPE, &DeltaOffset, 0, 0 },
{"DontFork", 0, INT_TYPE, &DontFork, 0, 0 },
{"DontQueue", 0, INT_TYPE, &DontQueue, 0, 0 },
{"DontTrigAts", 0, INT_TYPE, &DontIssueAts, 0, 0 },
{"EndSent", 1, STR_TYPE, &EndSent, 0, 0 },
{"EndSentIg", 1, STR_TYPE, &EndSentIg, 0, 0 },
{"FirstIndent", 1, INT_TYPE, &FirstIndent, 0, 132 },
{"FoldYear", 1, INT_TYPE, &FoldYear, 0, 1 },
{"FormWidth", 1, INT_TYPE, &FormWidth, 20, 500 },
{"HushMode", 0, INT_TYPE, &Hush, 0, 0 },
{"IgnoreOnce", 0, INT_TYPE, &IgnoreOnce, 0, 0 },
{"InfDelta", 0, INT_TYPE, &InfiniteDelta, 0, 0 },
{"IntMax", 0, INT_TYPE, &IntMax, 0, 0 },
{"IntMin", 0, INT_TYPE, &IntMin, 0, 0 },
{"LatDeg", 1, INT_TYPE, &LatDeg, -90, 90 },
{"LatMin", 1, INT_TYPE, &LatMin, -59, 59 },
{"LatSec", 1, INT_TYPE, &LatSec, -59, 59 },
{"Location", 1, STR_TYPE, &Location, 0, 0 },
{"LongDeg", 1, INT_TYPE, &LongDeg, -180, 180 },
{"LongMin", 1, INT_TYPE, &LongMin, -59, 59 },
{"LongSec", 1, INT_TYPE, &LongSec, -59, 59 },
{"MaxSatIter", 1, INT_TYPE, &MaxSatIter, 10, ANY },
{"MaxStringLen", 1, INT_TYPE, &MaxStringLen, -1, ANY },
{"MinsFromUTC", 1, INT_TYPE, &MinsFromUTC, -780, 780 },
{"NextMode", 0, INT_TYPE, &NextMode, 0, 0 },
{"NumQueued", 0, INT_TYPE, &NumQueued, 0, 0 },
{"NumTrig", 0, INT_TYPE, &NumTriggered, 0, 0 },
{"PrefixLineNo", 0, INT_TYPE, &DoPrefixLineNo, 0, 0 },
{"PSCal", 0, INT_TYPE, &PsCal, 0, 0 },
{"RunOff", 0, INT_TYPE, &RunDisabled, 0, 0 },
{"SimpleCal", 0, INT_TYPE, &DoSimpleCalendar, 0, 0 },
{"SortByDate", 0, INT_TYPE, &SortByDate, 0, 0 },
{"SortByPrio", 0, INT_TYPE, &SortByPrio, 0, 0 },
{"SortByTime", 0, INT_TYPE, &SortByTime, 0, 0 },
{"SubsIndent", 1, INT_TYPE, &SubsIndent, 0, 132 },
{"T", 0, SPECIAL_TYPE, trig_date_func, 0, 0 },
{"Td", 0, SPECIAL_TYPE, trig_day_func, 0, 0 },
{"TimeSep", 1, SPECIAL_TYPE, time_sep_func, 0, 0 },
{"Tm", 0, SPECIAL_TYPE, trig_mon_func, 0, 0 },
{"Tw", 0, SPECIAL_TYPE, trig_wday_func, 0, 0 },
{"Ty", 0, SPECIAL_TYPE, trig_year_func, 0, 0 },
{"U", 0, SPECIAL_TYPE, today_date_func, 0, 0 },
{"Ud", 0, SPECIAL_TYPE, today_day_func, 0, 0 },
{"Um", 0, SPECIAL_TYPE, today_mon_func, 0, 0 },
{"UntimedFirst", 0, INT_TYPE, &UntimedBeforeTimed, 0, 0 },
{"Uw", 0, SPECIAL_TYPE, today_wday_func, 0, 0 },
{"Uy", 0, SPECIAL_TYPE, today_year_func, 0, 0 }
/* name mod type value min/mal max validate*/
{"April", 1, STR_TYPE, &DynamicMonthName[3], 0, 0, NULL },
{"August", 1, STR_TYPE, &DynamicMonthName[7], 0, 0, NULL },
{"CalMode", 0, INT_TYPE, &DoCalendar, 0, 0, NULL },
{"CalcUTC", 1, INT_TYPE, &CalculateUTC, 0, 1, NULL },
{"Daemon", 0, INT_TYPE, &Daemon, 0, 0, NULL },
{"DateSep", 1, SPECIAL_TYPE, date_sep_func, 0, 0, NULL },
{"DateTimeSep", 1, SPECIAL_TYPE, datetime_sep_func, 0, 0, NULL },
{"December", 1, STR_TYPE, &DynamicMonthName[11],0, 0, NULL },
{"DefaultColor", 1, SPECIAL_TYPE, default_color_func, 0, 0, NULL },
{"DefaultPrio", 1, INT_TYPE, &DefaultPrio, 0, 9999, NULL },
{"DefaultTDelta", 1, INT_TYPE, &DefaultTDelta, 0, 1440, NULL },
{"DeltaOffset", 0, INT_TYPE, &DeltaOffset, 0, 0, NULL },
{"DontFork", 0, INT_TYPE, &DontFork, 0, 0, NULL },
{"DontQueue", 0, INT_TYPE, &DontQueue, 0, 0, NULL },
{"DontTrigAts", 0, INT_TYPE, &DontIssueAts, 0, 0, NULL },
{"EndSent", 1, STR_TYPE, &EndSent, 0, 0, NULL },
{"EndSentIg", 1, STR_TYPE, &EndSentIg, 0, 0, NULL },
{"February", 1, STR_TYPE, &DynamicMonthName[1], 0, 0, NULL },
{"FirstIndent", 1, INT_TYPE, &FirstIndent, 0, 132, NULL },
{"FoldYear", 1, INT_TYPE, &FoldYear, 0, 1, NULL },
{"FormWidth", 1, INT_TYPE, &FormWidth, 20, 500, NULL },
{"Friday", 1, STR_TYPE, &DynamicDayName[4], 0, 0, NULL },
{"HushMode", 0, INT_TYPE, &Hush, 0, 0, NULL },
{"IgnoreOnce", 0, INT_TYPE, &IgnoreOnce, 0, 0, NULL },
{"InfDelta", 0, INT_TYPE, &InfiniteDelta, 0, 0, NULL },
{"IntMax", 0, INT_TYPE, &IntMax, 0, 0, NULL },
{"IntMin", 0, INT_TYPE, &IntMin, 0, 0, NULL },
{"January", 1, STR_TYPE, &DynamicMonthName[0], 0, 0, NULL },
{"July", 1, STR_TYPE, &DynamicMonthName[6], 0, 0, NULL },
{"June", 1, STR_TYPE, &DynamicMonthName[5], 0, 0, NULL },
{"LatDeg", 1, SPECIAL_TYPE, latdeg_func, 0, 0, NULL },
{"Latitude", 1, SPECIAL_TYPE, latitude_func, 0, 0, NULL },
{"LatMin", 1, SPECIAL_TYPE, latmin_func, 0, 0, NULL },
{"LatSec", 1, SPECIAL_TYPE, latsec_func, 0, 0, NULL },
{"Location", 1, STR_TYPE, &Location, 0, 0, NULL },
{"LongDeg", 1, SPECIAL_TYPE, longdeg_func, 0, 0, NULL },
{"Longitude", 1, SPECIAL_TYPE, longitude_func, 0, 0, NULL },
{"LongMin", 1, SPECIAL_TYPE, longmin_func, 0, 0, NULL },
{"LongSec", 1, SPECIAL_TYPE, longsec_func, 0, 0, NULL },
{"March", 1, STR_TYPE, &DynamicMonthName[2], 0, 0, NULL },
{"MaxSatIter", 1, INT_TYPE, &MaxSatIter, 10, ANY, NULL },
{"MaxStringLen", 1, INT_TYPE, &MaxStringLen, -1, ANY, NULL },
{"May", 1, STR_TYPE, &DynamicMonthName[4], 0, 0, NULL },
{"MinsFromUTC", 1, INT_TYPE, &MinsFromUTC, -780, 780, NULL },
{"Monday", 1, STR_TYPE, &DynamicDayName[0], 0, 0, NULL },
{"NextMode", 0, INT_TYPE, &NextMode, 0, 0, NULL },
{"November", 1, STR_TYPE, &DynamicMonthName[10],0, 0, NULL },
{"NumQueued", 0, INT_TYPE, &NumQueued, 0, 0, NULL },
{"NumTrig", 0, INT_TYPE, &NumTriggered, 0, 0, NULL },
{"October", 1, STR_TYPE, &DynamicMonthName[9], 0, 0, NULL },
{"PrefixLineNo", 0, INT_TYPE, &DoPrefixLineNo, 0, 0, NULL },
{"PSCal", 0, INT_TYPE, &PsCal, 0, 0, NULL },
{"RunOff", 0, INT_TYPE, &RunDisabled, 0, 0, NULL },
{"Saturday", 1, STR_TYPE, &DynamicDayName[5], 0, 0, NULL },
{"September", 1, STR_TYPE, &DynamicMonthName[8], 0, 0, NULL },
{"SimpleCal", 0, INT_TYPE, &DoSimpleCalendar, 0, 0, NULL },
{"SortByDate", 0, INT_TYPE, &SortByDate, 0, 0, NULL },
{"SortByPrio", 0, INT_TYPE, &SortByPrio, 0, 0, NULL },
{"SortByTime", 0, INT_TYPE, &SortByTime, 0, 0, NULL },
{"SubsIndent", 1, INT_TYPE, &SubsIndent, 0, 132, NULL },
{"Sunday", 1, STR_TYPE, &DynamicDayName[6], 0, 0, NULL },
{"T", 0, SPECIAL_TYPE, trig_date_func, 0, 0, NULL },
{"Td", 0, SPECIAL_TYPE, trig_day_func, 0, 0, NULL },
{"Thursday", 1, STR_TYPE, &DynamicDayName[3], 0, 0, NULL },
{"TimeSep", 1, SPECIAL_TYPE, time_sep_func, 0, 0, NULL },
{"Tm", 0, SPECIAL_TYPE, trig_mon_func, 0, 0, NULL },
{"Tuesday", 1, STR_TYPE, &DynamicDayName[1], 0, 0, NULL },
{"Tw", 0, SPECIAL_TYPE, trig_wday_func, 0, 0, NULL },
{"Ty", 0, SPECIAL_TYPE, trig_year_func, 0, 0, NULL },
{"U", 0, SPECIAL_TYPE, today_date_func, 0, 0, NULL },
{"Ud", 0, SPECIAL_TYPE, today_day_func, 0, 0, NULL },
{"Um", 0, SPECIAL_TYPE, today_mon_func, 0, 0, NULL },
{"UntimedFirst", 0, INT_TYPE, &UntimedBeforeTimed, 0, 0, NULL },
{"Uw", 0, SPECIAL_TYPE, today_wday_func, 0, 0, NULL },
{"Uy", 0, SPECIAL_TYPE, today_year_func, 0, 0, NULL },
{"Wednesday", 1, STR_TYPE, &DynamicDayName[2], 0, 0, NULL }
};
#define NUMSYSVARS ( sizeof(SysVarArr) / sizeof(SysVar) )
@@ -714,6 +831,7 @@ static void DumpSysVar (char const *name, const SysVar *v);
/***************************************************************/
int SetSysVar(char const *name, Value *value)
{
int r;
SysVar *v = FindSysVar(name);
if (!v) return E_NOSUCH_VAR;
if (v->type != SPECIAL_TYPE &&
@@ -725,8 +843,27 @@ int SetSysVar(char const *name, Value *value)
if (v->type == SPECIAL_TYPE) {
SysVarFunc f = (SysVarFunc) v->value;
return f(1, value);
} else if (v->type == STR_TYPE) {
r = f(1, value);
DestroyValue(*value);
return r;
}
if (v->validate) {
if (v->type == STR_TYPE) {
r = (v->validate)((void *) value->v.str);
} else {
r = (v->validate)((void *) &(value->v.val));
}
if (r != OK) {
return r;
}
}
if (v->type == STR_TYPE) {
/* If it's already the same, don't bother doing anything */
if (!strcmp(value->v.str, (char const *) v->value)) {
DestroyValue(*value);
return OK;
}
/* If it's a string variable, special measures must be taken */
if (v->been_malloced) free(*((char **)(v->value)));
v->been_malloced = 1;
@@ -757,7 +894,11 @@ int GetSysVar(char const *name, Value *val)
SysVarFunc f = (SysVarFunc) v->value;
return f(0, val);
} else if (v->type == STR_TYPE) {
val->v.str = StrDup(*((char **) v->value));
if (! * (char **) v->value) {
val->v.str = StrDup("");
} else {
val->v.str = StrDup(*((char **) v->value));
}
if (!val->v.str) return E_NO_MEM;
} else {
val->v.val = *((int *) v->value);
@@ -767,7 +908,7 @@ int GetSysVar(char const *name, Value *val)
/* In "verbose" mode, print attempts to test $RunOff */
if (DebugFlag & DB_PRTLINE) {
if (v->value == (void *) &RunDisabled) {
Eprint("(Security note: $RunOff variable tested.)\n");
Eprint("(Security note: $RunOff variable tested.)");
/* Allow further messages from this line */
FreshLine = 1;
}
@@ -885,3 +1026,48 @@ static void DumpSysVar(char const *name, const SysVar *v)
return;
}
void
set_lat_and_long_from_components(void)
{
Latitude = (double) LatDeg + ((double) LatMin) / 60.0 + ((double) LatSec) / 3600.0;
Longitude = - ( (double) LongDeg + ((double) LongMin) / 60.0 + ((double) LongSec) / 3600.0);
}
void
set_components_from_lat_and_long(void)
{
double x;
x = (Latitude < 0.0 ? -Latitude : Latitude);
LatDeg = (int) x;
x -= (double) LatDeg;
x *= 60;
LatMin = (int) x;
x -= (double) LatMin;
x *= 60;
LatSec = (int) x;
if (Latitude < 0.0) {
LatDeg = -LatDeg;
LatMin = -LatMin;
LatSec = -LatSec;
}
x = (Longitude < 0.0 ? -Longitude : Longitude);
LongDeg = (int) x;
x -= (double) LongDeg;
x *= 60;
LongMin = (int) x;
x -= (double) LongMin;
x *= 60;
LongSec = (int) x;
/* Use STANDARD sign for $Longitude even if $LongDeg, $LongMin and
* $LongSec are messed up */
if (Longitude > 0.0) {
LongDeg = -LongDeg;
LongMin = -LongMin;
LongSec = -LongSec;
}
}

View File

@@ -1,8 +0,0 @@
#!/bin/sh
cd /home/dfs/Software/Remind.git || exit 1
rm -f .git/COMMIT_EDITMSG .git/*~
git update-server-info && cd .git && rsync --exclude HEADER.html --archive --verbose --progress --delete ./ dianne.skoll.ca:web/projects/remind/git/Remind.git/
exit $?

View File

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

View File

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

70
tests/scripts.rem Normal file
View File

@@ -0,0 +1,70 @@
# This is a test file that tests the
# rendering of various Unicode characters.
# It also tests some of the features of
# the Pango/Cairo-based rem2pdf program.
SET $Sunday "እሁድ"
SET $Monday "一"
SET $Tuesday "mardi"
SET $Wednesday "水曜日"
SET $Thursday "четвер"
SET $Friday "piątek"
SET $Saturday "יום שבת"
SET $January "January"
SET $February "février"
SET $March "März"
SET $April "אַפּרִיל"
SET $May "ግንቦት"
SET $June "Чэрвень"
SET $July "تموز"
SET $August "Наймдугаар сар"
SET $September "Вересень"
SET $October "październik"
SET $November "נאוועמבער"
SET $December "दिसंबर"
REM 1 MSG Përkujtues
REM 2 SPECIAL SHADE 192 192 255
REM 2 MSG تذكير
REM 3 MSG 提醒
REM 4 MSG રીમાઇન્ડર
REM 5 MSG Emlékeztető
REM 6 MSG Áminning
REM 7 SPECIAL PANGO <u>תִזכּוֹרֶת</u>
REM 8 MSG अनुस्मारक
REM 9 SPECIAL COLOR 0 0 192 Эскертүү
REM 10 SPECIAL COLOR 0 192 0 Напоминание
REM 11 SPECIAL COLOR 192 0 0 Υπενθύμιση
REM 12 SPECIAL PANGO <b>Bold</b> <small>and</small> <i>Italic</i> <big>and</big> <span bgcolor="#C0C0C0" foreground="red"><u>underline</u></span>
REM 12 MSG Hello
REM 28 SPECIAL PANGO <span face="zapf chancery" size="10000">Very Fancy</span>
REM 13 SPECIAL PANGO <bad>Invalid
REM 13 MSG Hello Again
REM 15 SPECIAL PANGO @1,-1 <small><small>[hebday($U)] [hebmon($U)] Rise [sunrise($U)] Set [sunset($U)]</small></small>
REM 16 MSG یادآور
REM 17 MSG Lời nhắc nhở
REM 18 MSG Påminnelse
REM 19 MSG דערמאָנונג
REM 20 MSG Hatırlatma
REM 21 SPECIAL PANGO <big><big> Нагадування</big></big>
REM 22 MSG შეხსენება
REM 23 MSG เตือนความจำ
REM 24 MSG リマインダー
REM 25 MSG Искә төшерү
REM 26 MSG Напомняне
REM 27 MSG ഓർമ്മപ്പെടുത്തൽ
REM 1 SPECIAL SHADE 192 255 192
REM 14 SPECIAL SHADE 255 192 192
REM 14 SPECIAL PANGO <span face="Zapf Chancery" size="15000">This is so <span foreground="blue">fancy</span></span>
REM [moondate(0)] SPECIAL MOON 0
REM [moondate(1)] SPECIAL MOON 1
REM [moondate(2)] SPECIAL MOON 2 -1 -1 [moontime(2)]
REM [moondate(3)] SPECIAL MOON 3 -1 -1 [moontime(3)]
REM Mon SPECIAL WEEK (W[weekno(today())])
REM SATISFY [$Td != 15] SPECIAL PANGO @1,-1 <span size="4800"><i>Rise [sunrise($U)] Set [sunset($U)]</i></span>

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

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

View File

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

View File

@@ -7,13 +7,22 @@
# in the build directory.
#
# This file is part of REMIND.
# Copyright (C) 1992-2018 Dianne Skoll
# Copyright (C) 1992-2021 Dianne Skoll
# ---------------------------------------------------------------------------
DIR=`dirname $0`
cd $DIR
if test $? != 0 ; then
echo ""
echo "Unable to cd $DIR" >&2
echo ""
exit 1
fi
if test `id -u` = 0 ; then
echo ""
echo "*** Please do not run the test suite as root; it will fail."
echo ""
exit 1
fi
@@ -56,6 +65,14 @@ echo "" >> ../tests/test.out
chmod 644 include_dir/04cantread.rem
# Feb 29 bug
echo "Feb 29 Bug Test" >> ../tests/test.out
echo 'REM Sun 29 Feb MSG [$T]' | ../src/remind -dt - 1 feb 2021 >> ../tests/test.out 2>&1
# Day Weekday Year out-of-year bug
echo "Mon 31 Dec Bug Test" >> ../tests/test.out
echo 'REM Mon 31 2021 MSG [$T]' | ../src/remind -dt - 31 dec 2021 >> ../tests/test.out 2>&1
echo "Color Test" >> ../tests/test.out
../src/remind -ccl ../tests/colors.rem 1 aug 2007 >> ../tests/test.out 2>&1
@@ -290,17 +307,26 @@ rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
EOF
# If we're already in a utf-8 locale, do
# nothing
# nothing; otherwise, set LC_ALL
OK=0
if echo $LC_ALL | grep -i utf-8 > /dev/null 2>&1 ; then
OK=1
fi
if ! echo $LC_ALL | grep -i utf-8 > /dev/null 2>&1 ; then
if test -z "$LC_ALL" ; then
if echo $LANG | grep -i utf-8 > /dev/null 2>&1 ; then
export LC_ALL="$LANG"
OK=1
fi
fi
if test "$OK" = 0 ; then
export LC_ALL=en_US.utf-8
fi
if ! echo $LANG | grep -i utf-8 > /dev/null 2>&1 ; then
export LANG=en_US.utf-8
fi
../src/remind -w128 -c ../tests/utf-8.rem 1 Nov 2019 >> ../tests/test.out
../src/remind -c ../tests/test-addomit.rem 1 Sep 2021 >> ../tests/test.out
cmp -s ../tests/test.out ../tests/test.cmp
if [ "$?" = "0" ]; then
echo "Remind: Acceptance test PASSED"

File diff suppressed because it is too large Load Diff

View File

@@ -15,9 +15,40 @@ REM Wed UNTIL 15 Feb 1991 SATISFY [trigdate() > '1990-01-01'] MSG wookie
# bad AT
REM AT 0:00 0:01 0:02 MSG foo
# Includecmd
INCLUDECMD echo REM 16 Feb 1991 MSG Blork
INCLUDECMD echo REM 18 Feb 1991 MSG Blork
# Includecmd with continuation line
INCLUDECMD echo REM 18 Feb 1991 MSG This line is \
continued so there
# This should work
INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo MSG Yippee
# This should fail
INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo MSG Yippee
REM MSG Today is [hebday(today())] [hebmon(today())] [hebyear(today())]
fset _h(x, y) trigger(hebdate(x,y))
# Test case from Remind mailing list
set mltest "a b"
INCLUDECMD printf 'REM %s\n' [mltest]
# Disabling RUN in an !includecmd
INCLUDECMD !echo MSG foo
INCLUDECMD !echo MSG foo
INCLUDECMD !echo INCLUDECMD echo MSG foo
INCLUDECMD !echo INCLUDECMD echo MSG foo
INCLUDECMD !echo MSG foo
INCLUDECMD !echo MSG foo
# INCLUDECMD with RUN disabled
RUN OFF
INCLUDECMD echo MSG foo
RUN ON
INCLUDECMD echo MSG foo
[_h(1, "Tishrey")] MSG Rosh Hashana 1
[_h(2, "Tishrey")] MSG Rosh Hashana 2
[_h(3, "Tishrey")] MSG Tzom Gedalia
@@ -195,6 +226,36 @@ REM 1991/02/28@14:45 MSG Feb 28
REM Wed UNTIL 1991-01-01 MSG Expired
REM Wed SCANFROM 1991-02-26 MSG SCANFROM
CLEAR-OMIT-CONTEXT
# Test ADDOMIT
REM Mon 15 Feb ADDOMIT MSG Family Day
REM Feb 18 AFTER MSG Should trigger on Feb 19
OMIT DUMP
set $CalcUTC 0
set $DateTimeSep "@"
set $DefaultColor "-1 -1 -1"
set $DefaultPrio 5000
set $EndSent ".?!"
set $EndSentIg "" + char(34) + "')]}>"
set $FirstIndent 0
set $FoldYear 0
set $FormWidth 72
set $Location "Ottawa"
set $MaxSatIter 150
set $MaxStringLen 65535
set $MinsFromUTC -300
set $SubsIndent 0
set $TimeSep ":"
set $LatDeg 30
set $LatMin 30
set $LatSec 0
set $LongDeg -25
set $LongMin 15
set $LongSec 0
set a000 abs(1)
set a001 abs(-1)
set a002 asc("foo")
@@ -385,6 +446,7 @@ REM MAYBE-UNCOMPUTABLE Mon OMIT Mon SKIP MSG Never ever ever...
REM MAYBE-UNCOMPUTABLE Mon SATISFY [wkdaynum($T) == 3] MSG Nope nope...
dump
dump $
dump $aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
OMIT 2010-09-03 THROUGH 2010-09-15
OMIT December 25 MSG X
@@ -551,8 +613,30 @@ set a $IntMin * 2
set a $IntMin * $IntMin
set a $IntMin * $IntMax
set a $IntMin / (-1)
set a $IntMin * (-1)
set a (-1) * $IntMin
set a abs($IntMin)
# The "isany" function
set a isany(1)
set a isany("foo")
set a isany(1:00)
set a isany(1, 2)
set a isany("foo", 2)
set a isany(1:00, 2)
set a isany(1, 2, 1, 3)
set a isany("foo", 2, 3, "foo")
set a isany(1:00, 2, "foo", 2:00, 1:00, 9:00)
# Shellescape
set a shellescape(" !\"#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")
msg [a]
# Deprecated functions
set x psshade(50)
set x psmoon(0)
# Don't want Remind to queue reminders
EXIT

View File

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

View File

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

View File

@@ -19,9 +19,7 @@ server:
1) Edit the Makefile in this directory. See the comments in the Makefile
for details.
2) Edit the first line of "rem2html" to reflect the location of
Perl on your system. (Oh yeah, you need Perl for the
HTML Hebrew calendar...)
2) Make sure "rem2html" is installed.
3) Type "make install"

View File

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

View File

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

View File

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