Compare commits

...

186 Commits

Author SHA1 Message Date
Dianne Skoll
34f8486c10 Update docs.
All checks were successful
Remind unit tests / tests (push) Successful in 42s
2025-02-02 11:21:38 -05:00
Dianne Skoll
5adb5d893e Final (??) tweaks of popup appearance. :)
All checks were successful
Remind unit tests / tests (push) Successful in 34s
2025-02-01 15:58:51 -05:00
Dianne Skoll
2f11b6fdc8 Tweak appearance of popups and background reminders. 2025-02-01 15:52:13 -05:00
Dianne Skoll
49d46c1397 Improve reminder popups. 2025-02-01 15:38:13 -05:00
Dianne Skoll
1641f99f97 Include the "info" element in pop-up reminders. 2025-02-01 15:02:54 -05:00
Dianne Skoll
f9f9552850 Avoid segfault if we call dosubst("%<foo>") 2025-02-01 14:50:49 -05:00
Dianne Skoll
3b43222585 Add the triginfo("header") function and corresponding %<...> substitution sequence. 2025-02-01 14:39:06 -05:00
Dianne Skoll
231d9d77e7 Save the info chain when saving the last trigger. 2025-02-01 14:16:17 -05:00
Dianne Skoll
6140221bf3 Make a function static. 2025-02-01 11:15:52 -05:00
Dianne Skoll
51b831fb6a Check for proper escaping in JSON and TRANSLATE DUMP. 2025-02-01 11:15:25 -05:00
Dianne Skoll
35a4994b3e Document changes. 2025-02-01 10:59:04 -05:00
Dianne Skoll
0ebaaa4097 Add optional add_quote argument to escape() 2025-02-01 10:58:55 -05:00
Dianne Skoll
2f43aca21c Update version to 05.03.00 2025-02-01 10:58:34 -05:00
Dianne Skoll
930bab0fde Add more tests. 2025-02-01 10:45:34 -05:00
Dianne Skoll
694c4099d1 Add \xAA sequence for parsing quoted strings; add the escape() built-in function; update docs. 2025-02-01 10:36:38 -05:00
Dianne Skoll
ca56b4c90e Disallow "\x00" 2025-02-01 10:12:51 -05:00
Dianne Skoll
5c965e2083 Add "\xAB" escapes to string parser.
\x followed by one or two hex digits gets converted to that character.
2025-02-01 10:08:12 -05:00
Dianne Skoll
d58ccbef69 Improve how add/edit reminder dialog resizes.
All checks were successful
Remind unit tests / tests (push) Successful in 37s
2025-01-31 21:31:47 -05:00
Dianne Skoll
17ad03be69 Add a bit of space after labels. 2025-01-31 21:22:48 -05:00
Dianne Skoll
75a4e98de2 Call the reminder body the "Summary" rather than "Subject" to be consistent with ical. 2025-01-31 21:21:30 -05:00
Dianne Skoll
1408f77303 Use concat instead of list to flatten lists.
Bug report: https://dianne.skoll.ca/pipermail/remind-fans/2025/004986.html
2025-01-31 19:36:41 -05:00
Dianne Skoll
af76dd67fb Remove dead code; count lines better. 2025-01-31 17:02:03 -05:00
Dianne Skoll
f7a19d1570 Change "Body:" to "Subject:" and update man page. 2025-01-31 16:48:48 -05:00
Dianne Skoll
e7ec975ff0 Support location and description fields in tkremind. 2025-01-31 16:30:07 -05:00
Dianne Skoll
8c4ca12ca7 When creating the "info" JSON hash, make the keys lower-case instead of upper-case.
All checks were successful
Remind unit tests / tests (push) Successful in 46s
2025-01-31 08:07:53 -05:00
Dianne Skoll
e832eb868c Make INFO require "Header: Value" strings; make the "info" element in the JSON output a hash instead of an array.
All checks were successful
Remind unit tests / tests (push) Successful in 36s
2025-01-30 16:58:56 -05:00
Dianne Skoll
cb0acb3077 Document INFO
All checks were successful
Remind unit tests / tests (push) Successful in 54s
2025-01-29 19:07:26 -05:00
Dianne Skoll
9376c7a36d Add INFO keyword. 2025-01-29 18:55:22 -05:00
Dianne Skoll
e6ceeee2ec Add the "INFO" clause to the REM command.
All checks were successful
Remind unit tests / tests (push) Successful in 33s
Intended to pass additional information to a back-end to use as it wishes.
One example is to add extra info such as locaiton, description, etc. to ical
files.
2025-01-28 15:51:28 -05:00
Dianne Skoll
bbeece644e Use "custom.h" rather than <custom.h> for our header file. 2025-01-24 08:10:06 -05:00
Dianne Skoll
8d09abc363 Use snprintf in favor of sprintf almost everywhere.
All checks were successful
Remind unit tests / tests (push) Successful in 35s
2025-01-22 11:11:08 -05:00
Dianne Skoll
3dcd353fb5 Update release notes. 2025-01-22 10:56:05 -05:00
Dianne Skoll
124c5c4e7e Make test mode warning more verbose.
All checks were successful
Remind unit tests / tests (push) Successful in 35s
2025-01-21 11:54:24 -05:00
Dianne Skoll
77024562b3 Fix SystemDate to always return 2025-01-06 in --test mode.
All checks were successful
Remind unit tests / tests (push) Successful in 38s
2025-01-21 11:52:20 -05:00
Dianne Skoll
35c33ae915 Prevent infinite test loop. 2025-01-21 11:48:56 -05:00
Dianne Skoll
901831ff75 Add --test long option to make the test suite repeatable.
Some checks failed
Remind unit tests / tests (push) Failing after 3h14m50s
2025-01-20 13:33:00 -05:00
Dianne Skoll
e0c5e878a8 Explicitly unset REMIND_RUNNING_TEST at the start. 2025-01-20 11:35:32 -05:00
Dianne Skoll
ffba7fcb03 Make queue tests work at any time of the day.
All checks were successful
Remind unit tests / tests (push) Successful in 33s
If the REMIND_RUNNING_TEST environment variable is set to 1, then
SystemTime adjusts times near midnight so the queue tests pass.

Remind prints a warning if it is set so you don't accidentally
set it in normal use.
2025-01-20 10:15:19 -05:00
Dianne Skoll
b3f3cb9ce0 Add test for previous change
All checks were successful
Remind unit tests / tests (push) Successful in 31s
2025-01-19 22:05:25 -05:00
Dianne Skoll
6f11e727f8 Truncate any absurdly-long translations of "am" or "pm" rather than letting a buffer overflow. 2025-01-19 22:01:45 -05:00
Dianne Skoll
9f7ea96e87 Make it a bit easier to read
All checks were successful
Remind unit tests / tests (push) Successful in 41s
2025-01-18 10:45:35 -05:00
Dianne Skoll
d650b8564c Update release notes
All checks were successful
Remind unit tests / tests (push) Successful in 33s
2025-01-17 13:26:06 -05:00
Dianne Skoll
4f2e4030eb Bump version go 05.02.03. 2025-01-17 13:21:11 -05:00
Dianne Skoll
447bda5c91 Warn if given a bad debug flag. 2025-01-17 10:22:22 -05:00
Dianne Skoll
4f351c089e Add the "-dq" debugging flag, for outputing TRANSLATE commands needed by a reminder script.
All checks were successful
Remind unit tests / tests (push) Successful in 44s
2025-01-17 08:46:29 -05:00
Dianne Skoll
6b31778973 Better error message.
All checks were successful
Remind unit tests / tests (push) Successful in 32s
2025-01-16 19:24:57 -05:00
Dianne Skoll
dcf8b46beb Skip queueing tests between 23:55 and 00:00 UTC. 2025-01-16 19:23:49 -05:00
Dianne Skoll
0f582ccb60 Sleep until midnight if test starts after 23:55 UTC
All checks were successful
Remind unit tests / tests (push) Successful in 35s
2025-01-16 13:52:34 -05:00
Dianne Skoll
8d0743dd3e Don't allow a translation entry if printf-style formatters differ. 2025-01-16 12:53:23 -05:00
Dianne Skoll
436526c27d Fix -Wformat-security warnings. 2025-01-16 12:37:13 -05:00
Dianne Skoll
5f3f3b410f Fix tests for previous commit.
All checks were successful
Remind unit tests / tests (push) Successful in 52s
2025-01-15 11:02:30 -05:00
Dianne Skoll
4f79b0d42a Remove leading space from translatable. 2025-01-15 11:02:06 -05:00
Dianne Skoll
c96f9f21ed Properly print already-translated TRANS-type system variables in TRANSLATE GENERATE output.
All checks were successful
Remind unit tests / tests (push) Successful in 36s
2025-01-14 15:02:08 -05:00
Dianne Skoll
dc192f2a69 Final good version of TRANSLATE GENERATE. 2025-01-14 14:59:01 -05:00
Dianne Skoll
ac3dd1ec7c Better translation template 2025-01-14 14:54:26 -05:00
Dianne Skoll
b5717828f0 Make "TRANSLATE GENERATE" emit a BANNER command. 2025-01-14 14:08:46 -05:00
Dianne Skoll
c0d73fb9d1 Use @ to suppress echoing, not -. 2025-01-14 13:55:47 -05:00
Dianne Skoll
3a2ac067b0 Fix tests. 2025-01-14 13:49:13 -05:00
Dianne Skoll
1d467ab9ed Remove trailing \n from translation strings. 2025-01-14 13:48:45 -05:00
Dianne Skoll
c2ec4e9d29 Don't require any translation strings to include a trailing "\n" 2025-01-14 13:46:23 -05:00
Dianne Skoll
96c11e89eb Add the TRANSLATE GENERATE command to generate a skeleton .rem file for localization. 2025-01-14 13:27:04 -05:00
Dianne Skoll
a35920f28e Put quotes around function name when issuing "redefined" warning. 2025-01-14 11:30:06 -05:00
Dianne Skoll
17ccf5d2b4 Make more messages translatable. 2025-01-14 11:27:47 -05:00
Dianne Skoll
788a09b2cd Properly fix printing of ^-- here in error diagnosis.
All checks were successful
Remind unit tests / tests (push) Successful in 1m36s
2025-01-13 12:55:14 -05:00
Dianne Skoll
9f0e23a307 More localization. 2025-01-13 11:58:42 -05:00
Dianne Skoll
542620c188 Allow "did you mean" to be localized. 2025-01-13 11:56:43 -05:00
Dianne Skoll
50419bd83a Translate "here" to French. 2025-01-13 11:55:32 -05:00
Dianne Skoll
2b7c582392 Let "here" be localized. 2025-01-13 11:54:14 -05:00
Dianne Skoll
812a2af64b Better location of the ^-- here marker. 2025-01-13 11:52:55 -05:00
Dianne Skoll
17d7abd4a4 Add country-specific LGBTQ holidays.
All checks were successful
Remind unit tests / tests (push) Successful in 34s
2025-01-11 14:12:56 -05:00
Dianne Skoll
098e98c59e Add holidays/lgbtq.rem
All checks were successful
Remind unit tests / tests (push) Successful in 37s
2025-01-10 20:34:37 -05:00
Dianne Skoll
c5e0dbf2e5 Add license identifier. 2025-01-10 20:34:29 -05:00
Dianne Skoll
18c8bc719f Update tests to match commit 195ed15167
All checks were successful
Remind unit tests / tests (push) Successful in 35s
2025-01-07 17:59:06 -05:00
Dianne Skoll
195ed15167 Print ^-- here for a few more error types. 2025-01-07 17:58:03 -05:00
Dianne Skoll
51677cd7b5 Use "info patchlevel" to display detailed Tcl/Tk version. 2025-01-07 15:57:07 -05:00
Dianne Skoll
aef5b353cd Add a missing update.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2025-01-06 10:40:25 -05:00
Dianne Skoll
8a99c29533 Update WHATSNEW in preparation for release.
All checks were successful
Remind unit tests / tests (push) Successful in 33s
2025-01-05 12:14:04 -05:00
Dianne Skoll
0bf2b0772a Bump version to 05.02.02.
All checks were successful
Remind unit tests / tests (push) Successful in 1m41s
2025-01-05 10:34:28 -05:00
Dianne Skoll
a033a48acd Make rem2html support weekly calendars.
All checks were successful
Remind unit tests / tests (push) Successful in 1m29s
rem2html is a mess and needs refactoring, but oh well... it works.
2025-01-04 18:10:34 -05:00
Dianne Skoll
0feb81c8cc Make "rem2html" accept "remind -ppp" as input (as well as -p and -pp) 2025-01-04 17:07:06 -05:00
Dianne Skoll
1850607542 Use hex constants for flags that are bitmasks.
All checks were successful
Remind unit tests / tests (push) Successful in 37s
2024-12-31 15:26:18 -05:00
Dianne Skoll
213138a7b7 Split the "-ds" debug flag into "-ds" and "-dh"
-ds prints parsed expressions
   -dh dumps hash-table statistics on exit.
2024-12-31 12:50:15 -05:00
Dianne Skoll
562cec3dc8 Mass-update copyright date to 2025. 2024-12-29 13:47:07 -05:00
Dianne Skoll
18b57d26b4 Properly detect and handle requests for multi-page --svg or --eps output.
All checks were successful
Remind unit tests / tests (push) Successful in 42s
2024-12-26 09:38:05 -05:00
Dianne Skoll
c80d72f623 Add --weeks-per-page option.
All checks were successful
Remind unit tests / tests (push) Successful in 44s
2024-12-25 13:29:51 -05:00
Dianne Skoll
2739a41651 If we ask for multiple weekly calendars, render then two weeks to a page. 2024-12-25 10:37:18 -05:00
Dianne Skoll
5a56f4c61b Pass in index and total number of calendars to "render". 2024-12-25 10:00:21 -05:00
Dianne Skoll
77080ff600 Make copyright notices consistent.
All checks were successful
Remind unit tests / tests (push) Successful in 37s
2024-12-24 20:02:08 -05:00
Dianne Skoll
c4aa21ff51 Remove unused functions. 2024-12-24 15:05:15 -05:00
Dianne Skoll
34c513ba3b Add $CalType system variable. 2024-12-24 14:45:57 -05:00
Dianne Skoll
35c16a060a Fix typo again.
All checks were successful
Remind unit tests / tests (push) Successful in 1m26s
2024-12-24 13:20:19 -05:00
Dianne Skoll
69dedc577f Fix typo 2024-12-24 13:19:28 -05:00
Dianne Skoll
a7d8f3c887 Support --verbose in weekly calendars 2024-12-24 13:18:19 -05:00
Dianne Skoll
800a4b15b2 Add support for weekly PDF calendars with "-p+n" Remind option. 2024-12-24 13:07:45 -05:00
Dianne Skoll
3e981fd8be Convert README file to Markdown. That is what all the cool kids use.
All checks were successful
Remind unit tests / tests (push) Successful in 33s
2024-12-19 10:20:35 -05:00
Dianne Skoll
7c530d3068 Remove unnecesary .gitignore entry
All checks were successful
Remind unit tests / tests (push) Successful in 1m27s
2024-12-18 11:19:45 -05:00
Dianne Skoll
58f9cf641b Remove some truly ancient docs. 2024-12-18 11:19:04 -05:00
Dianne Skoll
53906035fe Warn if a POP-OMIT-CONTEXT matches a PUSH-OMIT-CONTEXT in a different file.
All checks were successful
Remind unit tests / tests (push) Successful in 37s
2024-12-17 17:26:51 -05:00
Dianne Skoll
4804325863 Merge branch 'fix_typo' into 'master'
Fix typo

See merge request dskoll/remind!9
2024-12-17 15:29:09 +00:00
Jochen Sprickerhof
5f5e7054f4 Fix typo 2024-12-17 09:22:42 +01:00
Dianne Skoll
078dba1e98 Prepare for 05.02.01 release.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-12-16 19:37:31 -05:00
Dianne Skoll
8ebec9584c Fix incorrect comparison code. 2024-12-16 19:33:41 -05:00
Dianne Skoll
2504b39be2 Remove const qualifier.
All checks were successful
Remind unit tests / tests (push) Successful in 32s
2024-12-16 17:10:45 -05:00
Dianne Skoll
e394f402f8 Set release date.
All checks were successful
Remind unit tests / tests (push) Successful in 32s
2024-12-16 09:31:02 -05:00
Dianne Skoll
5a2914f6c7 Start hash tables with 7 buckets instead of 17; print more detailed hash stats with -ds; consistently use ErrFp instead of stderr
All checks were successful
Remind unit tests / tests (push) Successful in 32s
2024-12-14 11:52:16 -05:00
Dianne Skoll
a19b009f7c Fix man page typo and cppcheck warnings.
All checks were successful
Remind unit tests / tests (push) Successful in 32s
2024-12-13 15:22:46 -05:00
Dianne Skoll
6373ae8ca5 Update release notes. 2024-12-13 15:08:54 -05:00
Dianne Skoll
b8c4786b33 Allow INCLUDE/DO/SYSINCLUDE to take a QuotedString argument. This allows for filenames with spaces in them. 2024-12-13 10:38:34 -05:00
Dianne Skoll
4e7cfc20ce Make use of SYSINCLUDE.
All checks were successful
Remind unit tests / tests (push) Successful in 32s
2024-12-13 08:28:14 -05:00
Dianne Skoll
0c9a35a584 Add SYSINCLUDE to release notes. 2024-12-13 08:22:43 -05:00
Dianne Skoll
5e333f6162 Add the SYSINCLUDE directive. 2024-12-13 08:18:22 -05:00
Dianne Skoll
af8b4e6df1 Add const qualifier on Sysvar.value.
All checks were successful
Remind unit tests / tests (push) Successful in 44s
2024-12-12 20:27:54 -05:00
Dianne Skoll
3fa798523a Document the difference between %(foo) and [_("foo")] 2024-12-12 16:56:38 -05:00
Dianne Skoll
53001f9fbc Update WHATSNEW 2024-12-12 16:48:53 -05:00
Dianne Skoll
9cd76eae84 Fix typo 2024-12-12 16:47:34 -05:00
Dianne Skoll
c8295b6251 Convert files we ship to use %(foo) in place of [_("foo")] 2024-12-12 16:43:30 -05:00
Dianne Skoll
3c95245407 In the substitution filter, make %(foo) equivalent to [_("foo")] 2024-12-12 16:35:31 -05:00
Dianne Skoll
3362c7226c Add regression test for commit 356b562d75
All checks were successful
Remind unit tests / tests (push) Successful in 31s
2024-12-12 12:17:15 -05:00
Dianne Skoll
356b562d75 Fix logic error in resetting IF flags and Popfile interaction. 2024-12-12 12:14:29 -05:00
Dianne Skoll
6eebcdc39d Handle error return from GetSysVar. 2024-12-12 11:58:27 -05:00
Dianne Skoll
5a80d63060 Add localization tests. 2024-12-12 11:55:07 -05:00
Dianne Skoll
c7ca1b4baa Get rid of the DyamicFoo hacks and make most translatable variables live in the translation table. 2024-12-12 11:43:03 -05:00
Dianne Skoll
dc89a6fba9 Eliminate unnecessary test. 2024-12-12 10:12:50 -05:00
Dianne Skoll
f83fec5563 Add missing three Chinese New Year animals. 2024-12-12 09:55:30 -05:00
Dianne Skoll
9c38161430 Merge branch 'translation_de' into 'master'
Add German translations

See merge request dskoll/remind!8
2024-12-12 14:53:21 +00:00
Jochen Sprickerhof
68f5fe1d10 Add German translations
Based on nl.rem
2024-12-12 12:51:38 +01:00
Dianne Skoll
bc7c57e53b Add another translation-propagation test.
All checks were successful
Remind unit tests / tests (push) Successful in 27s
2024-12-11 20:10:11 -05:00
Dianne Skoll
88aacb3905 Get two-way propagation working properly. 2024-12-11 20:08:09 -05:00
Dianne Skoll
a894076bfc Verify two-way correspondence between translation table and system variables. 2024-12-11 19:48:19 -05:00
Dianne Skoll
82e068fcca Refactor SetSysVar. 2024-12-11 19:22:30 -05:00
Dianne Skoll
a119d97539 Make mapping between translatable system variables and TRANSLATE table table-driven. 2024-12-11 19:15:44 -05:00
Dianne Skoll
01afb63a3d Sent translations with only the first month, in a multi-month (-pN) output. 2024-12-11 18:07:48 -05:00
Dianne Skoll
54fccabdfe Escape the result of translation, in case a bad translation file includes HTML special characters. 2024-12-11 17:15:01 -05:00
Dianne Skoll
ba4d44664f Clarify docs.
All checks were successful
Remind unit tests / tests (push) Successful in 34s
2024-12-11 15:36:17 -05:00
Dianne Skoll
d76c5499b5 Document how translation table is passed to back-ends. 2024-12-11 15:35:31 -05:00
Dianne Skoll
84e8244e48 Use localized names for "Full Moon", etc. 2024-12-11 15:35:23 -05:00
Dianne Skoll
92a6115a5c Send the translation table to back-ends. 2024-12-11 15:24:37 -05:00
Dianne Skoll
b98e336e9e Tweak release notes. 2024-12-11 14:02:30 -05:00
Dianne Skoll
ffcd21446e Update WHATSNEW 2024-12-11 13:55:23 -05:00
Dianne Skoll
af9ca68d99 Document the need for %-style escape sequences in translations to match those in the original message. 2024-12-11 13:42:49 -05:00
Dianne Skoll
71db7168a1 Increase update-for-changes delay to 250ms 2024-12-11 10:25:45 -05:00
Dianne Skoll
54f284c43f Note that strlen returns number of bytes, not characters. 2024-12-11 09:45:40 -05:00
Dianne Skoll
0ab93f2dea Guard against printf-style formatting attacks by malicious translation files. 2024-12-11 09:43:04 -05:00
Dianne Skoll
3d97f87bcd Remove obsolet error messages 2024-12-11 09:33:31 -05:00
Dianne Skoll
dcfa6d8ef8 Add translation for No reminders.
All checks were successful
Remind unit tests / tests (push) Successful in 33s
2024-12-10 19:59:00 -05:00
Dianne Skoll
52dd5332f4 Fix banner for Dutch translation. 2024-12-10 19:57:08 -05:00
Dianne Skoll
7b5fafe1ab Document how _() looks for translations. 2024-12-10 19:48:26 -05:00
Dianne Skoll
929af71a10 Fix test. 2024-12-10 18:21:24 -05:00
Dianne Skoll
abf7c74ff2 When dumping translation table NOT to JSON, always start with LANGID 2024-12-10 18:20:48 -05:00
Dianne Skoll
5b9d9a67b2 Make daemon not respond at all to a TRANSLATE for which there is no entry. 2024-12-10 17:16:25 -05:00
Dianne Skoll
16ca2ade23 Clear out translations when we prepare to ask for new ones. 2024-12-10 17:09:25 -05:00
Dianne Skoll
d3e6c81a3a Synthesize mixed-case translations. 2024-12-10 17:02:41 -05:00
Dianne Skoll
13ae49d3cd Put LANGID near the top. 2024-12-10 15:35:53 -05:00
Dianne Skoll
78adc9f61d Document how translators should use LANGID. 2024-12-10 15:33:22 -05:00
Dianne Skoll
a622d4fad4 Add LANGID translations to all language packs. 2024-12-10 15:27:41 -05:00
Dianne Skoll
6c0e7b4ff5 Add a second torture test to test hash-table resizing.
All checks were successful
Remind unit tests / tests (push) Successful in 31s
2024-12-10 15:12:24 -05:00
Dianne Skoll
28e0599380 Get new translations if inotify says something has changed. 2024-12-10 15:05:48 -05:00
Dianne Skoll
87445f639c Don't print the "" error message for translators. 2024-12-10 14:09:02 -05:00
Dianne Skoll
af6e159eaa Refresh translations if they seem to have changed. :) 2024-12-10 13:32:50 -05:00
Dianne Skoll
bffa28e258 Implement the "TRANSLATE" command to translate just one string;
rename "JSONTRANSLATE" to "TRANSLATE_DUMP"
2024-12-10 13:06:12 -05:00
Dianne Skoll
1781f84d84 Merely schedule an update when we get the translation table. 2024-12-10 12:24:53 -05:00
Dianne Skoll
ed6e65182e Document JSONTRANSLATE daemon command. 2024-12-10 12:21:06 -05:00
Dianne Skoll
f5cc0ec686 Get translation table; translate moon phases in TkRemind. 2024-12-10 12:16:27 -05:00
Dianne Skoll
a2c818f96c Fully implement JSONTRANSLATE daemon command. 2024-12-10 11:57:52 -05:00
Dianne Skoll
0bbbaaf3d9 Implement JSONTRANSLATE -zj command. 2024-12-10 11:48:01 -05:00
Dianne Skoll
1c81d4cae3 Add sunrise/sunset standard include file. 2024-12-10 11:38:57 -05:00
Dianne Skoll
56c684087b Add Sunrise and Sunset translations. 2024-12-10 11:34:44 -05:00
Dianne Skoll
9500a929ea Fix indentation. 2024-12-10 11:00:13 -05:00
Dianne Skoll
585d45e4a1 Completely remove support for compile-time localization.
All localization is now done at run-time.
2024-12-10 10:58:09 -05:00
Dianne Skoll
67d1d1366d Add error message translations. 2024-12-10 10:39:13 -05:00
Dianne Skoll
f4018892e8 Be pickier about syntax. 2024-12-10 10:25:38 -05:00
Dianne Skoll
ffd309f89d Add missing translations. 2024-12-09 23:28:10 -05:00
Dianne Skoll
286babc1bf Avoid memory leak. 2024-12-09 23:23:39 -05:00
Dianne Skoll
cc3c0040e9 Fix comment.
All checks were successful
Remind unit tests / tests (push) Successful in 28s
2024-12-09 23:21:53 -05:00
Dianne Skoll
b33a1ee98b Better error message if we hit EOLN after TRANSLATE. 2024-12-09 23:19:48 -05:00
Dianne Skoll
99706741bb Translate error messages in pl.rem 2024-12-09 23:04:52 -05:00
Dianne Skoll
df73a74503 Better colors (for me, at any rate...)
All checks were successful
Remind unit tests / tests (push) Successful in 34s
2024-12-09 21:11:01 -05:00
Dianne Skoll
c747ebebb4 Don't escape high chars. :) 2024-12-09 20:55:26 -05:00
Dianne Skoll
6b412062c2 Dump translation table in a way that it can be re-ingested. 2024-12-09 20:53:44 -05:00
Dianne Skoll
27b688f82c Highlight strings first. 2024-12-09 20:46:44 -05:00
Dianne Skoll
4c314ff81c Add --print-errs and localize error messages in lang/fr.rem. 2024-12-09 20:40:41 -05:00
Dianne Skoll
d2955ec733 Fix solstice translation. 2024-12-09 20:15:37 -05:00
Dianne Skoll
480216db9e Update test file 2024-12-09 20:08:46 -05:00
Dianne Skoll
9dbb0de7e6 Fix bug in ParseQuotedString 2024-12-09 20:07:29 -05:00
Dianne Skoll
9f9ae77895 Bound-check GetErr 2024-12-09 20:03:15 -05:00
Dianne Skoll
d9796e72e5 Allow error messages to be localized. 2024-12-09 19:55:23 -05:00
131 changed files with 618744 additions and 3984 deletions

2
.gitignore vendored
View File

@@ -23,7 +23,6 @@ rem2pdf/Makefile.old
rem2pdf/Makefile.top
rem2pdf/bin/rem2pdf
scripts/tkremind
set-irc-topic
src/*.tar.gz*
src/Makefile
src/config.h
@@ -35,3 +34,4 @@ tests/test.out
www/Makefile
gmon.out
tests/once.timestamp
src/xlat.c

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-2024 Dianne Skoll, except where noted in
2. REMIND is Copyright (C) 1992-2025 Dianne Skoll, except where noted in
individual files.
3. DISTRIBUTION AND USE

View File

@@ -23,8 +23,7 @@ install:
@$(MAKE) -C rem2html install
@$(MAKE) -C rem2pdf -f Makefile.top install INSTALL_BASE=$(INSTALL_BASE)
clean:
find . -name '*~' -exec rm {} \;
-rm man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1 scripts/tkremind
-find . -name '*~' -exec rm {} \;
-$(MAKE) -C src clean
-$(MAKE) -C rem2pdf clean
@@ -44,7 +43,8 @@ test:
@$(MAKE) -C src -s test
distclean: clean
rm -f config.cache config.log config.status src/Makefile src/config.h tests/test.out www/Makefile rem2pdf/Makefile.top rem2pdf/Makefile.old rem2pdf/Makefile rem2pdf/Makefile.PL rem2pdf/bin/rem2pdf rem2html/rem2html
-rm -f config.cache config.log config.status src/Makefile src/config.h tests/test.out www/Makefile rem2pdf/Makefile.top rem2pdf/Makefile.old rem2pdf/Makefile rem2pdf/Makefile.PL rem2pdf/bin/rem2pdf rem2html/rem2html
-rm -f man/rem.1 man/rem2ps.1 man/remind.1 man/tkremind.1 scripts/tkremind
src/Makefile: src/Makefile.in
./configure

78
README
View File

@@ -1,78 +0,0 @@
REMIND
Remind is a full-featured calendar/alarm program. Copying policy is
in the file "COPYRIGHT" in this directory.
Installation notes for various operating systems are in "docs". See
the appropriate README file for installation on your system.
Manual pages are in "man".
-----------------------------------------------------------------------------
Quick UNIX installation instructions for the very impatient:
If you have Tcl/Tk (wish 4.1 or higher) installed and are running X Windows:
--------------------------------------------------------------
1) Type: wish ./build.tk from this directory. Fill in the various
options and hit "Build Remind"
2) Type: "make install" -- you may need to be root to do this.
If you do NOT have Tcl/Tk or are NOT running X Windows:
-------------------------------------------------------
1) Edit the file "src/custom.h" according to your preferences.
2) Edit the file "src/lang.h" to choose a language.
3) Type: "./configure" (You can supply options; type "./configure --help"
for details.)
4) Type: "make"
5) Type: "make install" -- you may need to be root to do this.
PREREQUISITES:
--------------
Remind and rem2ps have no prerequisites beyond the standard C library and
the standard math library.
Rem2HTML requires the JSON::MaybeXS Perl module.
Rem2PDF requires the JSON::MaybeXS, Pango and Cairo Perl modules.
- On Debian-like systems, these prerequisites may be installed with:
apt install libjson-maybexs-perl libpango-perl libcairo-perl
- On RPM-based systems, you need perl-Pango, perl-Cairo and perl-JSON-MaybeXS
- On Gentoo, you need dev-perl/Pango, dev-perl/Cairo and dev-perl/JSON-MaybeXS.
- On Arch linux, you need pango-perl, cairo-perl and perl-json-maybexs
TkRemind requires Tcl/Tk and the tcllib library.
- On Debian-like systems, install with:
apt install tcl tk tcllib
- On RPM-based systems, you need tcl, tk and tcllib
- On Arch Linux, you need tk and tcllib. The latter is available at
https://aur.archlinux.org/packages/tcllib
If the little arrows for "Previous Month" and "Next Month" do not display
correctly in TkRemind, you may need to install the Noto Fonts. Install
all of your distribution's Nonto Font-related packages.
- On Debian-like systems, install with:
apt install fonts-noto-core fonts-noto-color-emoji \
fonts-noto-extra fonts-noto-ui-core fonts-noto-ui-extra
==========================================================================
Contact info: mailto:dianne@skoll.ca
Home page: https://dianne.skoll.ca/projects/remind/

63
README.md Normal file
View File

@@ -0,0 +1,63 @@
# REMIND
Remind is a full-featured calendar/alarm program. Copying policy is
in the file "COPYRIGHT" included with the source; Remind is licensed under
the GNU General Public License, Vesion 2.
## Prerequisites:
remind and rem2ps have no prerequisites beyond the standard C library and
the standard math library.
rem2html requires the JSON::MaybeXS Perl module and rem2pdf
requires the JSON::MaybeXS, Pango and Cairo Perl modules.
- On Debian-like systems, these prerequisites may be installed with:
`apt install libjson-maybexs-perl libpango-perl libcairo-perl`
- On RPM-based systems, you need `perl-Pango`, `perl-Cairo` and
`perl-JSON-MaybeXS`
- On Gentoo, you need `dev-perl/Pango`, `dev-perl/Cairo` and
`dev-perl/JSON-MaybeXS`.
- On Arch linux, you need `pango-perl`, `cairo-perl` and `perl-json-maybexs`
TkRemind requires Tcl/Tk and the tcllib library.
- On Debian-like systems, install with:
`apt install tcl tk tcllib`
- On RPM-based systems, you need `tcl`, `tk` and `tcllib`
- On Arch Linux, you need `tk` and `tcllib`. The latter is available at
https://aur.archlinux.org/packages/tcllib
If the little arrows for "Previous Month" and "Next Month" do not display
correctly in TkRemind, you may need to install the Noto Fonts. Install
all of your distribution's Nonto Font-related packages.
- On Debian-like systems, install with:
`apt install fonts-noto-core fonts-noto-color-emoji fonts-noto-extra fonts-noto-ui-core fonts-noto-ui-extra`
## Installation
Remind can be installed with the usual:
`./configure && make && make test && sudo make install`
You can edit custom.h to configure some aspects of Remind. Or, if
you have Tcl/Tk installed, you can use the graphical build tool to
edit custom.h on your behalf:
`wish ./build.tk`
---
Contact info: dianne@skoll.ca
Home page: [https://dianne.skoll.ca/projects/remind/](https://dianne.skoll.ca/projects/remind/)

View File

@@ -8,7 +8,7 @@
# A cheesy graphical front-end for building and installing REMIND.
#
# This file is part of REMIND.
# Copyright (C) 1992-2018 Dianne Skoll
# Copyright (C) 1992-2025 Dianne Skoll
#
#--------------------------------------------------------------
@@ -40,7 +40,6 @@ proc SetConfigDefaults {} {
set Config(TIMESEP) ":"
set Config(NORTHERN_HEMISPHERE) 1
set Config(WESTERN_HEMISPHERE) 1
set Config(LANGUAGE) "English"
set Config(INST_DIR) "/usr/local/bin"
set Config(MAN_DIR) "/usr/local/share/man"
}
@@ -242,32 +241,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.langlabel -text "Language: "
menubutton $w.lang -text $Config(LANGUAGE) -indicatoron 1 -relief raised \
-menu $w.lang.menu
menu $w.lang.menu -tearoff 0
foreach lang {
"Brazilian Portuguese"
"Danish"
"Dutch"
"English"
"Finnish"
"French"
"German"
"Italian"
"Norwegian"
"Polish"
"Romanian"
"Spanish"
"Icelandic"
} {
$w.lang.menu add command -label $lang -command [list $w.lang configure -text $lang]
}
grid configure $w.langlabel -row 3 -column 0 -sticky e
grid configure $w.lang -row 3 -column 1 -sticky nsew
}
#***********************************************************************
@@ -491,32 +464,16 @@ proc CreateCustomH {} {
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Runs "make" with appropriate language definitions
# Runs "make"
#***********************************************************************
proc CallMake {} {
global Options
set lang [$Options.lang cget -text]
switch -- $lang {
"German" { set lang GERMAN }
"Dutch" { set lang DUTCH }
"Finnish" { set lang FINNISH }
"French" { set lang FRENCH }
"Norwegian" { set lang NORWEGIAN }
"Danish" { set lang DANISH }
"Polish" { set lang POLISH }
"Brazilian Portuguese" { set lang BRAZPORT }
"Italian" { set lang ITALIAN }
"Romanian" { set lang ROMANIAN }
"Spanish" { set lang SPANISH }
"Icelandic" { set lang ICELANDIC }
default { set lang ENGLISH }
}
set nproc 0
catch { set nproc [exec nproc] }
if { $nproc != 0 } {
RunCommand "make -j $nproc \"LANGDEF=-DLANG=$lang\""
RunCommand "make -j $nproc"
} else {
RunCommand "make \"LANGDEF=-DLANG=$lang\""
RunCommand "make"
}
}
@@ -530,7 +487,7 @@ proc CallMake {} {
# Michael McLennan, Bell Labs Innovations for Lucent Technologies
# Addison-Wesley Professional Computing Series
# ======================================================================
# Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison
# Copyright (C) 1996-1997 Lucent Technologies Inc. and Mark Harrison
# ======================================================================
option add *Tabnotebook.tabs.background #666666 widgetDefault
@@ -644,7 +601,7 @@ proc tabnotebook_display {win name} {
# Michael McLennan, Bell Labs Innovations for Lucent Technologies
# Addison-Wesley Professional Computing Series
# ======================================================================
# Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison
# Copyright (C) 1996-1997 Lucent Technologies Inc. and Mark Harrison
# ======================================================================
option add *Notebook.borderWidth 2 widgetDefault
@@ -786,7 +743,6 @@ proc SetConfigFromRemind {} {
QueryRemind $rem LOCATION {$Location}
QueryRemind $rem DATESEP {$DateSep}
QueryRemind $rem TIMESEP {$TimeSep}
QueryRemind $rem LANGUAGE {language()}
set $Config(LAT_MIN) [expr abs($Config(LAT_MIN))]
set $Config(LAT_SEC) [expr abs($Config(LAT_SEC))]

18
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for remind 05.02.00.
# Generated by GNU Autoconf 2.71 for remind 05.03.00.
#
#
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -608,8 +608,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='remind'
PACKAGE_TARNAME='remind'
PACKAGE_VERSION='05.02.00'
PACKAGE_STRING='remind 05.02.00'
PACKAGE_VERSION='05.03.00'
PACKAGE_STRING='remind 05.03.00'
PACKAGE_BUGREPORT=''
PACKAGE_URL='https://dianne.skoll.ca/projects/remind/'
@@ -1265,7 +1265,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures remind 05.02.00 to adapt to many kinds of systems.
\`configure' configures remind 05.03.00 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1327,7 +1327,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of remind 05.02.00:";;
short | recursive ) echo "Configuration of remind 05.03.00:";;
esac
cat <<\_ACEOF
@@ -1415,7 +1415,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
remind configure 05.02.00
remind configure 05.03.00
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1865,7 +1865,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by remind $as_me 05.02.00, which was
It was created by remind $as_me 05.03.00, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -4710,7 +4710,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by remind $as_me 05.02.00, which was
This file was extended by remind $as_me 05.03.00, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -4775,7 +4775,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
remind config.status 05.02.00
remind config.status 05.03.00
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"

View File

@@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(remind, 05.02.00, , , https://dianne.skoll.ca/projects/remind/)
AC_INIT(remind, 05.03.00, , , https://dianne.skoll.ca/projects/remind/)
AC_CONFIG_SRCDIR([src/queue.c])
cat <<'EOF'

View File

@@ -112,12 +112,13 @@
(list "ADDOMIT" "AFTER" "AT" "BAN" "BANNER" "BEFORE" "CAL" "CLEAR"
"CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMP" "DUMPVARS" "DURATION" "ELSE"
"ENDIF" "ERRMSG" "EXIT" "EXPR" "FIRST" "FLUSH" "FOURTH" "FRENAME" "FROM" "FSET"
"FUNSET" "IF" "IFTRIG" "IN" "INC" "INCLUDE" "INCLUDECMD" "LAST"
"FUNSET" "IF" "IFTRIG" "IN" "INC" "INCLUDE" "INCLUDECMD" "INFO" "LAST"
"LASTDAY" "LASTWORKDAY" "MAYBE" "MAYBE-UNCOMPUTABLE" "MSF" "MSG"
"NOQUEUE" "OMIT" "OMITFUNC" "ONCE" "POP" "POP-OMIT-CONTEXT" "PRESERVE"
"PRIORITY" "PS" "PSFILE" "PUSH" "PUSH-OMIT-CONTEXT" "REM" "RUN"
"SATISFY" "SCAN" "SCANFROM" "SCHED" "SECOND" "SET" "SKIP" "SPECIAL"
"TAG" "THIRD" "THROUGH" "TRANSLATE" "TRANS" "UNSET" "UNTIL" "WARN")
"SYSINCLUDE" "TAG" "THIRD" "THROUGH" "TRANSLATE" "TRANS" "UNSET"
"UNTIL" "WARN")
#'(lambda (a b) (> (length a) (length b)))))
@@ -129,8 +130,8 @@
(defconst remind-builtin-variables
(sort
(list " $AddBlankLines" "$Ago" "$Am" "$And" "$April" "$At" "$August"
"$CalcUTC" "$CalMode" "$Daemon" "$DateSep" "$DateTimeSep" "$December"
"$DedupeReminders" "$DefaultColor" "$DefaultDelta"
"$CalcUTC" "$CalMode" "$CalType" "$Daemon" "$DateSep" "$DateTimeSep"
"$December" "$DedupeReminders" "$DefaultColor" "$DefaultDelta"
"$DefaultPrio" "$DefaultTDelta" "$DeltaOverride"
"$DontFork" "$DontQueue" "$DontTrigAts" "$EndSent" "$EndSentIg"
"$ExpressionTimeLimit" "$February" "$FirstIndent" "$FoldYear"
@@ -165,7 +166,7 @@
(list "_" "abs" "access" "adawn" "adusk" "ampm" "ansicolor" "args" "asc"
"baseyr" "char" "choose" "coerce" "columns" "current" "date"
"datepart" "datetime" "dawn" "day" "daysinmon" "defined" "dosubst"
"dusk" "easterdate" "evaltrig" "filedate" "filedatetime" "filedir"
"dusk" "easterdate" "escape" "evaltrig" "filedate" "filedatetime" "filedir"
"filename" "getenv" "hebdate" "hebday" "hebmon" "hebyear" "hour"
"htmlescape" "htmlstriptags" "iif" "index" "isany" "isdst" "isleap"
"isomitted" "language" "localtoutc" "lower" "max" "min" "minsfromutc"
@@ -176,7 +177,7 @@
"slide" "soleq" "stdout" "strlen" "substr" "sunrise" "sunset" "time"
"timepart" "timezone" "today" "trig" "trigback" "trigdate"
"trigdatetime" "trigdelta" "trigduration" "trigeventduration"
"trigeventstart" "trigfrom" "trigger" "trigpriority" "trigrep"
"trigeventstart" "trigfrom" "trigger" "triginfo" "trigpriority" "trigrep"
"trigscanfrom" "trigtags" "trigtime" "trigtimedelta" "trigtimerep"
"triguntil" "trigvalid" "typeof" "tzconvert" "upper" "utctolocal"
"value" "version" "weekno" "wkday" "wkdaynum" "year")
@@ -188,21 +189,21 @@
(defvar remind-conf-command-face 'remind-conf-command-face
"Remind commands.")
(defface remind-conf-command-face
'((t :foreground "SeaGreen4" :bold t))
'((t :foreground "#FF8080"))
"Font Lock mode face used to highlight commands."
:group 'remind-conf)
(defvar remind-conf-keyword-face 'remind-conf-keyword-face
"Remind keywords.")
(defface remind-conf-keyword-face
'((t :foreground "blue violet"))
'((t :foreground "#FFFF80"))
"Font Lock mode face used to highlight keywords."
:group 'remind-conf)
(defvar remind-conf-substitutes-face 'remind-conf-substitutes-face
"Remind substitutes.")
(defface remind-conf-substitutes-face
'((t :foreground "blue2"))
'((t :foreground "#8080FF"))
"Font Lock mode face used to highlight substitutes."
:group 'remind-conf)
@@ -216,7 +217,7 @@
(defvar remind-conf-variable-face 'remind-conf-variable-face
"Remind variable.")
(defface remind-conf-variable-face
'((t :foreground "DeepPink2" :bold t))
'((t :foreground "#FF8080" :bold t))
"Font Lock mode face used to highlight commands."
:group 'remind-conf)
@@ -237,14 +238,14 @@
(defvar remind-comment-face 'remind-comment-face
"Remind comments.")
(defface remind-comment-face
'((t :foreground "brown"))
'((t :foreground "#FF7F24"))
"Font-lock face for highlighting comments."
:group 'remind-conf)
(defvar remind-string-face 'remind-string-face
"Remind strings.")
(defface remind-string-face
'((t :foreground "tomato"))
'((t :foreground "#FF7FE0"))
"Font lock mode face used to highlight strings."
:group 'remind-conf)
@@ -296,11 +297,11 @@
(defconst remind-conf-font-lock-keywords-1
(list
'("^\s*[\;\#].*$" . remind-comment-face)
'("\"[^\"]*\"" . remind-string-face)
'(remind-keywords-matcher . remind-conf-keyword-face)
'("%[\"_]" . font-lock-warning-face)
'("\\(%[a-mops-w]\\)" . remind-conf-substitutes-face)
'("\"[^\"]*\"" . remind-string-face))
"Minimal font-locking for `remind-conf-mode'.")
'("\\(%[a-z]\\)" . remind-conf-substitutes-face)
"Minimal font-locking for `remind-conf-mode'."))
(defconst remind-conf-font-lock-keywords-2
(append remind-conf-font-lock-keywords-1

View File

@@ -1,6 +1,6 @@
REMIND version 3.2 for UNIX
Remind for UNIX and Linux
REMIND is a sophisticated alarm/calendar program. Details are given
Remind is a sophisticated alarm/calendar program. Details are given
in the man page, "remind.1".
INSTALLING REMIND:
@@ -19,88 +19,13 @@ If you do NOT have Tcl/Tk or are NOT running X11:
1) Edit the file "src/custom.h" according to your preferences.
2) Edit the file "src/lang.h" to choose a language.
2) Type: "make"
3) Type: "make"
4) Type: "make install" -- you may need to be root to do this.
3) Type: "make install" -- you may need to be root to do this.
The subdirectory "www" contains scripts for making a nice calendar
web server. See the files README and Makefile in that directory.
The file "examples/defs.rem" has some sample Remind definitions and
commands, as well as U.S. and Jewish holidays.
OTHER LANGUAGE SUPPORT
Remind has support for languages other than English. See the file
"src/lang.h" for details. The language support may vary - you can change
only the substitution filter, or you can translate all of the usage
instructions and error messages as well. See "src/langs/french.h" for an
example of the latter.
To compile Remind for a non-english language, look at the constants
defined in "src/lang.h". Then, to compile Remind for Italian (as an
example), type:
make "LANGDEF=-DLANG=ITALIAN"
If you add support for a non-English language, Remind will accept both the
English and non-English names of months and weekdays in an input script.
However, you should not rely on this feature if you want to write portable
Remind scripts.
At a minimum, you should support month and day names in the foreign
language, and should modify the substitution filter appropriately.
If you are truly diligent, you can translate usage and error messages
too.
Take a look at the files "src/langs/english.h" and
"src/langs/german.h" if you want to add support for your favourite
language. If you do add another language to Remind, please let me
know! Here are the basic guidelines:
- Your language file should be called "src/langs/lxxx.h", where lxxx
is the first 8 characters of the ENGLISH name of your language.
- Your language file should define L_LANGNAME to be the full English
name of your language, with the first letter capitalized and the rest
lower-case.
- 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
If you're running under X11 and you have the Tcl tools, you can create
simple pop-up reminders by creating the following Tcl script called
'popup'. It pops a message on to the screen and waits for you to
press the 'OK' button. If you don't press the OK button within 15
seconds, it exits anyway. To use it, you can use the '-k' option for
Remind as follows:
remind "-kpopup '%s'&" .reminders
Or use the following in your Remind script:
REM AT 17:00 RUN popup 'Time to go home.' &
This Tcl script is a slightly modified version of one submitted by
Norman Walsh.
-------------- Cut Here ---------- Cut Here ---------- Cut Here -------------
#!/usr/local/bin/wish
wm withdraw .
after 15000 { destroy . ; exit }
tk_messageBox -message Message -detail $argv -icon info -type ok
destroy .
exit
-------------- Cut Here ---------- Cut Here ---------- Cut Here -------------
--
Dianne Skoll <dianne@skoll.ca>
https://dianne.skoll.ca/projects/remind/

View File

@@ -1,26 +1,134 @@
CHANGES TO REMIND
* VERSION 5.2 Patch 0 - ????-??=??
* VERSION 5.3 Patch 0 - 2025-02-??
- MAJOR NEW FEATURE: remind: Add the TRANSLATE command and the _()
built-in function. This allows you to localize your reminder files
more easily.
- NEW FEATURE: remind: Add the "INFO" clause to the REM command. This
is intended for storing additional metadata about an event, such as
the location and a longer description. The intention is to make
Remind <-> iCal conversions preserve as much information as possible.
- NEW FEATURE: remind: Add the triginfo() built-in function so a reminder
body can refer to INFO data. Add the %<...> substitution filter as a
shorthand for [triginfo("...")]
- NEW FEATURE: TkRemind: Add "Location" and "Description" fields when
creating a reminder; these are converted to INFO clauses. Also support
a popup window with the extra information when hovering over a reminder
in the calendar display.
- IMPROVEMENT: remind: Add the "\xAB" escape sequence for parsing quoted
strings, where "AB" is a pair of hex digits.
- NEW FUNCTION: remind: Add the escape() built-in function that converts
problematic characters within a string to the \-escaped versions.
It's essentially the inverse of how Remind parses a quoted string.
* VERSION 5.2 Patch 3 - 2025-01-22
- NEW FEATURE: remind: Add "TRANSLATE GENERATE" command for generating
a skeleton set of TRANSLATE commands to make it easier to localize
Remind.
- NEW FEATURE: remind: Add "q" debug flag for tracing calls to _()
or %(...) in the substitution filter; this will help with localizing
reminder files.
- NEW FILES: remind: Add holidays/lgbtq.rem for LGBTQ holidays. Add
country-specific files in holidays/lgbtq/*.rem
- IMPROVEMENT: TkRemind: use "info patchlevel" to display full Tcl/Tk
version.
- IMPROVEMENT: remind: The DEBUG command issues a warning if given an
unknown debug flag.
- BUG FIX: remind: "make test" will now succeed even if run between
23:55 and 00:00 UTC. This is done with a new --test flag for remind.
- BUG FIX: remind: Avoid potential buffer overflow if someone supplies
ridiculously-long translations for "am" or "pm".
* VERSION 5.2 Patch 2 - 2025-01-06
- NEW FEATURE: remind: The "-p+" option lets you produce weekly calendars;
so far, the rem2pdf and rem2html back-ends support rendering of weekly
calendars.
- NEW FEATURE: remind: The $CalType system variable indicates the type of
calendar being produced; its value is one of "monthly", "weekly",
or "none". "none" signifies agenda mode rather than calendar mode.
- IMPROVEMENT: remind: Warn if a POP-OMIT-CONTEXT matches a
PUSH-OMIT-CONTEXT that is in a different file.
- CHANGE: remind: Split the "-ds" debug option into two separate options:
"-ds" for debugging expression-parsing and "-dh" for printing hash
table statistics on exit.
* VERSION 5.2 Patch 1 - 2024-12-16
- BUG FIX: remind: Fix a logic error that only showed itself on big-endian
architectures. Found thanks to Debian testing and a notification from
Jochen Sprickerhof.
* VERSION 5.2 Patch 0 - 2024-12-16
- MAJOR NEW FEATURE: remind: Add the TRANSLATE command, the _()
built-in function and the %(...) substitution sequence. These allow
you to localize your reminder files more easily. The translation table
is also made available to back-ends like rem2pdf and tkremind,
which they can use as they see fit.
- MINOR FEATURE: tkremind, rem2html: Localize the names of the moon
phases.
- MAJOR CHANGE: remind: Remind used to support compile-time localization
into different languages (French, English, etc.) That compile-time
support has been removed and all localization is now done at run-time.
- NEW FEATURE: remind: In JSON daemon mode (-zj), the front-end can
request translation table entries from the Remind daemon, allowing the
front-end to localize messages.
- UPDATE: Update national holidays following update to upstream Python
library.
- MINOR FEATURE: Add standard include/sun.rem file for sunrise/sunset.
- MINOR FEATURE: The SYSINCLUDE command has been added. The command:
SYSINCLUDE foo/bar.rem
is equivalent to:
INCLUDE [$SysInclude]/foo/bar.rem
- MINOR IMPROVEMENT: Allow INCLUDE, DO and SYSINCLUDE to include files with
spaces in their names; in this case, you have to put the filename inside
double-quotes.
- IMPROVEMENT: remind: Refuse to open subdirectories named "*.rem"
under a top-level directory rather than trying and failing with a
confusing error.
- IMPROVEMENT: contrib/remind-conf-mode: Fix a few bugs and choose colors
that are easier on the eyes.
- IMPROVEMENT: remind: Remind used to have three completely separate
hash table implementations. Replace them all with one piece of code.
hash table implementations. They have all been replaced with a single
implementation; this new implementation adapts the hash table size based
on the number of entries and is dramatically faster than the old code
when there are a large number of entries.
- MINOR FIXES: remind: Fix typos in comments; use memcpy to copy OMIT
contexts internally.
- BUG FIX: Actually allow the documented 9 levels of INCLUDE rather than
8.
- BUG FIX: remind: Actually allow the documented 9 levels of INCLUDE
rather than 8.
- BUG FIX: remind: If an INCLUDE statement failed inside an IF statement,
Remind would print spurious errors about unmatched IF/ENDIF. This has
been fixed.
* VERSION 5.1 Patch 1 - 2024-11-18

View File

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

View File

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

View File

@@ -54,8 +54,8 @@ advance warning of holidays:
FSET msgsuffix(x) char(8) + dosubst(" is %b.%", $T)
# Include your holiday files here...
INCLUDE [$SysInclude]/holidays/us.rem
INCLUDE [$SysInclude]/holidays/us/ny.rem
SYSINCLUDE holidays/us.rem
SYSINCLUDE holidays/us/ny.rem
# Restore old version of msgsuffix and $DefaultDelta
FRENAME saved_msgsuffix msgsuffix

View File

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

View File

@@ -0,0 +1,34 @@
# List of LGBTQ awareness days
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
# These are the internationally-recognized days.
#
# SPDX-License-Identifier: GPL-2.0-only
REM Sun 14 Feb MSG Start of Aromantic Spectrum Awareness Week
REM 1 Mar MSG Zero Discrimination Day
REM 31 Mar MSG Trans Day of Visibility
REM 6 Apr MSG International Asexuality Day
REM Wed 8 Apr MSG International Day of Pink
REM 26 Apr MSG Lesbian Visibility Day
REM 17 May MSG International Day Against Homophobia, Biphobia and Transphobia
REM 19 May MSG Agender Pride Day
REM 24 May MSG Pansexual & Panromantic Awareness Day
REM 1 Jun MSG Start of LGBT Pride Month
REM 5 Jun MSG Aromantic Visibility Day
REM Mon 8 Jul MSG Start of Non-Binary Awareness Week
REM 14 Jul MSG Non-Binary People's Day
REM 16 Jul MSG Drag Day
REM 9 Aug MSG Start of Dyke Week
REM 16 Sep MSG Start of Bisexual Awareness Week
REM 23 Sep MSG Celebrate Bisexuality Day
REM 8 Oct MSG Lesbian Day
REM 11 Oct MSG National Coming Out Day
REM Wed 15 Oct MSG Pronouns Day
REM 17 Oct MSG Start of Genderfluid Visibility Week
REM Sun 19 Oct MSG Start of Ace Week
REM 26 Oct MSG Intersex Awareness Day
REM 8 Nov MSG Intersex Day of Remembrance
REM 1 Nov MSG Start of Trans Awareness Month
REM Sun 1 Nov MSG Trans Parent Day
REM 13 Nov MSG Start of Trans Awareness Week
REM 20 Nov MSG Transgender Day of Remembrance

View File

@@ -0,0 +1,8 @@
# List of LGBTQ awareness days
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
# These are the holidays recognized in Australia
#
# SPDX-License-Identifier: GPL-2.0-only
REM Sat 1 Mar MSG Mardi Gras Parade
REM Fri 1 Sep --7 MSG Wear it Purple Day
REM 1 Oct MSG Start of LGBT History Month

View File

@@ -0,0 +1,10 @@
# List of LGBTQ awareness days
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
# These are the holidays recognized in Brazil
#
# SPDX-License-Identifier: GPL-2.0-only
REM 29 Jan MSG National Day of Transgender Visibility
REM 20 Feb MSG Trans Men and Transmasculine Day
REM 25 Mar MSG National Gay Pride Day
REM 29 Aug MSG National Day of Lesbian Visibility

View File

@@ -0,0 +1,7 @@
# List of LGBTQ awareness days
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
# These are the holidays recognized in Canada
#
# SPDX-License-Identifier: GPL-2.0-only
REM 1 Oct MSG Start of LGBT History Month

View File

@@ -0,0 +1,7 @@
# List of LGBTQ awareness days
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
# These are the holidays recognized in Chile
#
# SPDX-License-Identifier: GPL-2.0-only
REM 9 Jul MSG Lesbian Visibility Day

View File

@@ -0,0 +1,7 @@
# List of LGBTQ awareness days
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
# These are the holidays recognized in Ireland
#
# SPDX-License-Identifier: GPL-2.0-only
REM 22 May MSG Irish Marriage Referendum Day

View File

@@ -0,0 +1,7 @@
# List of LGBTQ awareness days
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
# These are the holidays recognized in India
#
# SPDX-License-Identifier: GPL-2.0-only
REM 2 Jul MSG Indian Coming Out Day

View File

@@ -0,0 +1,7 @@
# List of LGBTQ awareness days
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
# These are the holidays recognized in the Netherlands
#
# SPDX-License-Identifier: GPL-2.0-only
REM Fri 8 Dec MSG Purple Friday

View File

@@ -0,0 +1,7 @@
# List of LGBTQ awareness days
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
# These are the holidays recognized in Ukraine
#
# SPDX-License-Identifier: GPL-2.0-only
REM 12 Dec MSG Day of Remembrance of Homosexuals in Ukraine (victims of the totalitarian Soviet regime)

View File

@@ -0,0 +1,8 @@
# List of LGBTQ awareness days
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
# These are the holidays recognized in the United Kingdom
#
# SPDX-License-Identifier: GPL-2.0-only
REM 1 Feb MSG Start of LGBT History Month
REM 6 May MSG Start of Trans+ History Week

View File

@@ -0,0 +1,16 @@
# List of LGBTQ awareness days
# Sourced from https://en.wikipedia.org/wiki/List_of_LGBTQ_awareness_periods
# These are the holidays recognized in the United States of America
#
# SPDX-License-Identifier: GPL-2.0-only
REM 1 Mar MSG Start of Bisexual Health Awareness Month
REM Fri 8 Apr MSG Day of Silence
REM 9 Apr MSG Sapphic Visibility Day
REM 22 May MSG Harvey Milk Day
REM 5 Jun MSG HIV Long-Term Survivors Awareness Day
REM 12 Jun MSG Pulse Night of Remembrance
REM 28 Jun MSG Stonewall Riots Anniversary
REM 1 Aug MSG Start of Transgender History Month (CA)
REM 1 Oct MSG Start of LGBT History Month
REM Thu 15 Oct MSG Spirit Day

View File

@@ -16,10 +16,10 @@ if !defined("__autolang__")
IF autolang != ""
IF access($SysInclude + "/lang/" + lower(substr(autolang, 1, 5)) + ".rem", "r") == 0
INCLUDE [$SysInclude]/lang/[lower(substr(autolang, 1, 5))].rem
SYSINCLUDE lang/[lower(substr(autolang, 1, 5))].rem
ELSE
IF access($SysInclude + "/lang/" + lower(substr(autolang, 1, 2)) + ".rem", "r") == 0
INCLUDE [$SysInclude]/lang/[lower(substr(autolang, 1, 2))].rem
SYSINCLUDE lang/[lower(substr(autolang, 1, 2))].rem
ENDIF
ENDIF
ENDIF

View File

@@ -1,8 +1,10 @@
# Support for the Catalan language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file was created by Eloi Torrents <eloitor@disroot.org>
TRANSLATE "LANGID" "ca"
SET $Monday "dilluns"
SET $Tuesday "dimarts"
SET $Wednesday "dimecres"

View File

@@ -1,8 +1,10 @@
# Support for the Danish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Mogens Lynnerup.
TRANSLATE "LANGID" "da"
SET $Sunday "Søndag"
SET $Monday "Mandag"
SET $Tuesday "Tirsdag"

View File

@@ -1,8 +1,10 @@
# Support for the German language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Wolfgang Thronicke
TRANSLATE "LANGID" "de"
# Day names
SET $Sunday "Sonntag"
SET $Monday "Montag"
@@ -64,28 +66,35 @@ FSET subst_p(alt, d, t) iif(d == today()+1, "", "en")
# Localization of various astronomical events
# Perihelion
SET earthseasons_Perihelion_str "Perihel"
TRANSLATE "Perihelion" "Perihel"
TRANSLATE "Vernal Equinox" "Frühlingsanfang"
TRANSLATE "Summer Solstice" "Sommeranfang"
TRANSLATE "Aphelion" "Aphel"
TRANSLATE "Autumnal Equinox" "Herbstanfang"
TRANSLATE "Winter Solstice" "Winteranfang"
TRANSLATE "Daylight Saving Time Starts" "Beginn Sommerzeit"
TRANSLATE "Daylight Saving Time Ends" "Ende Sommerzeit"
# Vernal equinox
SET earthseasons_EquinoxMar_str "Frühlingsanfang"
TRANSLATE "New Moon" "Neumond"
TRANSLATE "First Quarter" "zunehmender Halbmond"
TRANSLATE "Full Moon" "Vollmond"
TRANSLATE "Last Quarter" "abnehmender Halbmond"
# Summer solstice
SET earthseasons_SolsticeJun_str "Sommeranfang"
TRANSLATE "Chinese New Year" "Chinesisches Neujahr"
TRANSLATE "Snake" "Schlange"
TRANSLATE "Horse" "Pferd"
TRANSLATE "Goat" "Ziege"
TRANSLATE "Monkey" "Affe"
TRANSLATE "Rooster" "Hahn"
TRANSLATE "Dog" "Hund"
TRANSLATE "Pig" "Schwein"
TRANSLATE "Rat" "Ratte"
TRANSLATE "Ox" "Ochse"
TRANSLATE "Tiger" "Tiger"
TRANSLATE "Rabbit" "Kaninchen"
TRANSLATE "Dragon" "Drachen"
# Aphelion
SET earthseasons_Aphelion_str "Aphel"
TRANSLATE "Sunrise" "Sonnenaufgang"
TRANSLATE "Sunset" "Sonnenuntergang"
# Autumnal Equinox
SET earthseasons_EquinoxSep_str "Herbstanfang"
# Winter Solstice
SET earthseasons_SolsticeDec_str "Winteranfang"
# Daylight saving time starts
SET daylightST_starts_str "Beginn Sommerzeit"
# Daylight saving time ends
SET daylightST_ends_str "Ende Sommerzeit"
PRESERVE earthseasons_Perihelion_str earthseasons_EquinoxMar_str earthseasons_SolsticeJun_str earthseasons_Aphelion_str earthseasons_EquinoxSep_str earthseasons_SolsticeDec_str daylightST_starts_str daylightST_ends_str
TRANSLATE "No reminders." "Keine Termine."

View File

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

View File

@@ -1,8 +1,10 @@
# Support for the Spanish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Rafa Couto <rafacouto@biogate.com>
TRANSLATE "LANGID" "es"
SET $Sunday "Domingo"
SET $Monday "Lunes"
SET $Tuesday "Martes"

View File

@@ -1,8 +1,10 @@
# Support for the Finnish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Mikko Silvonen
TRANSLATE "LANGID" "fi"
SET $Sunday "sunnuntai"
SET $Monday "maanantai"
SET $Tuesday "tiistai"
@@ -92,3 +94,103 @@ FSET subst_hour_past(h) iif(h==0, "", h + " " + $Hour + iif(h==1, " ", $Hplu + "
FSET subst_min_past(m) iif(m==0, "", m + " " + $Minute + iif(m==1, " ", $Mplu + " "))
FSET subst_hour_future(h) iif(h==0, "", h + " tunnin ")
FSET subst_min_future(m) iif(m==0, "", m + " minuutin ")
TRANSLATE "Missing ']'" "Puuttuva ']'"
TRANSLATE "Missing quote" "Puuttuva lainausmerkki"
TRANSLATE "Expression too complex" "Liian monimutkainen lauseke"
TRANSLATE "Missing ')'" "Puuttuva ')'"
TRANSLATE "Undefined function" "Määrittelemätön funktio"
TRANSLATE "Illegal character" "Virheellinen merkki"
TRANSLATE "Expecting binary operator" "Kaksipaikkainen operaattori puuttuu"
TRANSLATE "Out of memory" "Muisti loppui"
TRANSLATE "Ill-formed number" "Virheellinen luku"
TRANSLATE "Can't coerce" "Tyyppimuunnos ei onnistu"
TRANSLATE "Type mismatch" "Virheellinen tyyppi"
TRANSLATE "Date overflow" "Liian suuri päiväys"
TRANSLATE "Division by zero" "Jako nollalla"
TRANSLATE "Undefined variable" "Määrittelemätön funktio"
TRANSLATE "Unexpected end of line" "Odottamaton rivin loppu"
TRANSLATE "Unexpected end of file" "Odottamaton tiedoston loppu"
TRANSLATE "I/O error" "Syöttö- tai tulostusvirhe"
TRANSLATE "Internal error" "Sisäinen virhe"
TRANSLATE "Bad date specification" "Virheellinen päiväys"
TRANSLATE "Not enough arguments" "Liian vähän argumentteja"
TRANSLATE "Too many arguments" "Liian paljon argumentteja"
TRANSLATE "Ill-formed time" "Virheellinen aika"
TRANSLATE "Number too high" "Liian suuri luku"
TRANSLATE "Number too low" "Liian pieni luku"
TRANSLATE "Can't open file" "Tiedoston avaus ei onnistu"
TRANSLATE "INCLUDE nested too deeply (max. 9)" "Liian monta sisäkkäistä INCLUDEa"
TRANSLATE "Parse error" "Jäsennysvirhe"
TRANSLATE "Can't compute trigger" "Laukaisuhetken laskenta ei onnistu"
TRANSLATE "Too many nested IFs" "Liian monta sisäkkäistä IF-lausetta"
TRANSLATE "ELSE with no matching IF" "ELSE ilman IF-lausetta"
TRANSLATE "ENDIF with no matching IF" "ENDIF ilman IF-lausetta"
TRANSLATE "Can't OMIT every weekday" "Kaikkia viikonpäiviä ei voi jättää pois"
TRANSLATE "Extraneous token(s) on line" "Ylimääräisiä merkkejä rivillä"
TRANSLATE "POP-OMIT-CONTEXT without matching PUSH-OMIT-CONTEXT" "POP-OMIT-CONTEXT ilman PUSH-OMIT-CONTEXTia"
TRANSLATE "RUN disabled" "RUN-lauseen käyttö estetty"
TRANSLATE "Domain error" "Arvoaluevirhe"
TRANSLATE "Invalid identifier" "Virheellinen tunniste"
TRANSLATE "Too many recursive function calls" "Liian monta rekursiivista toimintopuhelua"
TRANSLATE "Cannot modify system variable" "Järjestelmämuuttujan muuttaminen ei onnistu"
TRANSLATE "C library function can't represent date/time" "C-kirjastofunktio ei pysty esittämään päiväystä tai aikaa"
TRANSLATE "Attempt to redefine built-in function" "Sisäisen funktion määritelmää yritettiin muuttaa"
TRANSLATE "Can't nest function definition in expression" "Lausekkeessa ei voi olla sisäkkäisiä funktiomääritelmiä"
TRANSLATE "Must fully specify date to use repeat factor" "Päiväyksen täytyy olla täydellinen toistokertoimessa"
TRANSLATE "Year specified twice" "Vuosi annettu kahdesti"
TRANSLATE "Month specified twice" "Kuukausi annettu kahdesti"
TRANSLATE "Day specified twice" "Päivä annettu kahdesti"
TRANSLATE "Unknown token" "Tuntematon sana tai merkki"
TRANSLATE "Must specify month in OMIT command" "OMIT-komennossa on annettava kuukausi"
TRANSLATE "Too many full OMITs (max. 1000)" "Liian monta täydellistä OMIT-komentoa"
TRANSLATE "Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT" "Varoitus: PUSH-OMIT-CONTEXT ilman POP-OMIT-CONTEXTia"
TRANSLATE "Error reading" "Virhe tiedoston luvussa"
TRANSLATE "Expecting end-of-line" "Pilkku puuttuu"
TRANSLATE "Invalid Hebrew date" "Virheellinen juutalainen päiväys"
TRANSLATE "iif(): odd number of arguments required" "IIF vaatii parittoman määrän argumentteja"
TRANSLATE "Warning: Missing ENDIF" "Varoitus: puuttuva ENDIF"
TRANSLATE "Expecting comma" "Pilkku puuttuu"
TRANSLATE "Weekday specified twice" "Viikonpäivä annettu kahdesti"
TRANSLATE "Only use one of BEFORE, AFTER or SKIP" "Käytä vain yhtä komennoista BEFORE, AFTER ja SKIP"
TRANSLATE "Can't nest MSG, MSF, RUN, etc. in expression" "Sisäkkäisiä MSG-, MSF- ja RUN-lauseita ei voi käyttää lausekkeessa"
TRANSLATE "Repeat value specified twice" "Toistokerroin annettu kahdesti"
TRANSLATE "Delta value specified twice" "Delta-arvo annettu kahdesti"
TRANSLATE "Back value specified twice" "Peruutusarvo annettu kahdesti"
TRANSLATE "ONCE keyword used twice. (Hah.)" "ONCE-avainsanaa käytetty kahdesti. (Hah.)"
TRANSLATE "Expecting time after AT" "AT-sanan perästä puuttuu aika"
TRANSLATE "THROUGH/UNTIL keyword used twice" "THROUGH/UNTIL-sanaa käytetty kahdesti"
TRANSLATE "Incomplete date specification" "Epätäydellinen päiväys"
TRANSLATE "FROM/SCANFROM keyword used twice" "FROM/SCANFROM-sanaa käytetty kahdesti"
TRANSLATE "Variable" "Muuttuja"
TRANSLATE "Value" "Arvo"
TRANSLATE "*UNDEFINED*" "*MÄÄRITTELEMÄTÖN*"
TRANSLATE "Entering UserFN" "Siirrytään funktioon"
TRANSLATE "Leaving UserFN" "Poistutaan funktiosta"
TRANSLATE "Expired" "Vanhentunut"
TRANSLATE "fork() failed - can't do queued reminders" "fork() epäonnistui - jonomuistutukset eivät toimi"
TRANSLATE "Can't access file" "Tiedoston avaus ei onnistu"
TRANSLATE "Illegal system date: Year is less than %d" "Virheellinen järjestelmäpäiväys: vuosi on vähemmän kuin %d"
TRANSLATE "Unknown debug flag '%c'" "Tuntematon virheenetsintätarkenne '%c'"
TRANSLATE "Unknown option '%c'" "Tuntematon tarkenne '%c'"
TRANSLATE "Unknown user '%s'" "Tuntematon käyttäjä '%s'"
TRANSLATE "Could not change gid to %d" "Ryhmänumeron vaihto %d:ksi ei onnistunut"
TRANSLATE "Could not change uid to %d" "Käyttäjänumeron vaihto %d:ksi ei onnistunut"
TRANSLATE "Out of memory for environment" "Muisti ei riitä ympäristölle"
TRANSLATE "Missing '=' sign" "Puuttuva '='-merkki"
TRANSLATE "Missing variable name" "Puuttuva muuttujanimi"
TRANSLATE "Missing expression" "Puuttuva lauseke"
TRANSLATE "Remind: '-i' option: %s" "Remind: tarkenne '-i': %s"
TRANSLATE "No reminders." "Ei viestejä."
TRANSLATE "%d reminder(s) queued for later today." "%d viesti(ä) tämän päivän jonossa."
TRANSLATE "Expecting number" "Numero puuttuu"
TRANSLATE "Undefined WARN function" "Virheellinen funktio WARN-lausekkeessa"
TRANSLATE "Can't convert between time zones" "Aikavyöhykkeiden välillä ei voi muuntaa"
TRANSLATE "No files matching *.rem" "Ei tiedostoja, jotka vastaavat *.rem"
TRANSLATE "String too long" "Merkkijono liian kauan"
TRANSLATE "Time specified twice" "Aika määritetty kahdesti"
TRANSLATE "Cannot specify DURATION without specifying AT" "Ei voi määrittää DURATION määrittelemättä AT"
TRANSLATE "Expecting weekday name" "Odotettu viikonpäivän nimi"
TRANSLATE "Duplicate argument name" "Päällekkäinen argumentin nimi"
TRANSLATE "Expression evaluation is disabled" "Lausekkeiden arviointi on poistettu käytöstä"
TRANSLATE "Time limit for expression evaluation exceeded" "Ilmaisun arvioinnin aikaraja ylitti"

View File

@@ -1,8 +1,10 @@
# Support for the French language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Laurent Duperval
TRANSLATE "LANGID" "fr"
SET $Sunday "dimanche"
SET $Monday "lundi"
SET $Tuesday "mardi"
@@ -60,3 +62,103 @@ FSET subst_jx(alt, date, time) iif(alt, subst_j_alt(date), $On + " " + subst_j_a
FSET subst_k_alt(date) wkday(date) + ", " + day(date) + subst_ordinal(day(date)) + " " + mon(date)
FSET subst_kx(alt, date, time) iif(alt, subst_k_alt(date), $On + " " + subst_k_alt(date))
TRANSLATE "Missing ']'" "']' manquant"
TRANSLATE "Missing quote" "Apostrophe manquant"
TRANSLATE "Expression too complex" "Expression trop complexe"
TRANSLATE "Missing ')'" "')' manquante"
TRANSLATE "Undefined function" "Fonction non-définie"
TRANSLATE "Illegal character" "Caractère illégal"
TRANSLATE "Expecting binary operator" "Opérateur binaire attendu"
TRANSLATE "Out of memory" "Manque de mémoire"
TRANSLATE "Ill-formed number" "Nombre mal formé"
TRANSLATE "Can't coerce" "Impossible de convertir"
TRANSLATE "Type mismatch" "Types non-équivalents"
TRANSLATE "Date overflow" "Débordement de date"
TRANSLATE "Division by zero" "Division par zéro"
TRANSLATE "Undefined variable" "Variable non définie"
TRANSLATE "Unexpected end of line" "Fin de ligne non attendue"
TRANSLATE "Unexpected end of file" "Fin de fichier non attendue"
TRANSLATE "I/O error" "Erreur I/O"
TRANSLATE "Internal error" "Erreur interne"
TRANSLATE "Bad date specification" "Mauvaise date spécifiée"
TRANSLATE "Not enough arguments" "Pas assez d'arguments"
TRANSLATE "Too many arguments" "Trop d'arguments"
TRANSLATE "Ill-formed time" "Heure mal formée"
TRANSLATE "Number too high" "Nombre trop élevé"
TRANSLATE "Number too low" "Nombre trop bas"
TRANSLATE "Can't open file" "Impossible d'ouvrir le fichier"
TRANSLATE "INCLUDE nested too deeply (max. 9)" "Trop d'INCLUDE imbriqués"
TRANSLATE "Parse error" "Erreur d'analyse"
TRANSLATE "Can't compute trigger" "Impossible de calculer le déclenchement"
TRANSLATE "Too many nested IFs" "Trop de IF imbriqués"
TRANSLATE "ELSE with no matching IF" "ELSE sans IF correspondant"
TRANSLATE "ENDIF with no matching IF" "ENDIF sans IF correspondant"
TRANSLATE "Can't OMIT every weekday" "Impossible d'omettre (OMIT) tous les jours"
TRANSLATE "Extraneous token(s) on line" "Elément(s) étranger(s) sur la ligne"
TRANSLATE "POP-OMIT-CONTEXT without matching PUSH-OMIT-CONTEXT" "POP-OMIT-CONTEXT sans PUSH-OMIT-CONTEXT correspondant"
TRANSLATE "RUN disabled" "RUN déactivé"
TRANSLATE "Domain error" "Erreur de domaine"
TRANSLATE "Invalid identifier" "Identificateur invalide"
TRANSLATE "Too many recursive function calls" "Trop d'appels de fonctions récursives"
TRANSLATE "Cannot modify system variable" "Impossible de modifier une variable système"
TRANSLATE "C library function can't represent date/time" "Fonction de la librairie C ne peut représenter la date/l'heure"
TRANSLATE "Attempt to redefine built-in function" "Tentative de redéfinition d'une fonction intrinsèque"
TRANSLATE "Can't nest function definition in expression" "Impossible d'imbriquer une définition de fonction dans une expression"
TRANSLATE "Must fully specify date to use repeat factor" "Pour utiliser le facteur de répétition la date doit être spécifiée au complet"
TRANSLATE "Year specified twice" "Année spécifiée deux fois"
TRANSLATE "Month specified twice" "Mois spécifié deux fois"
TRANSLATE "Day specified twice" "Jour spécifié deux fois"
TRANSLATE "Unknown token" "Elément inconnu"
TRANSLATE "Must specify month in OMIT command" "Mois doit être spécifiés dans commande OMIT"
TRANSLATE "Too many full OMITs (max. 1000)" "Trop de OMITs complets"
TRANSLATE "Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT" "Attention: PUSH-OMIT-CONTEXT sans POP-OMIT-CONTEXT correspondant"
TRANSLATE "Error reading" "Erreur à la lecture du fichier"
TRANSLATE "Expecting end-of-line" "Fin de ligne attendue"
TRANSLATE "Invalid Hebrew date" "Date hébreuse invalide"
TRANSLATE "iif(): odd number of arguments required" "IIF demande nombre d'arguments impair"
TRANSLATE "Warning: Missing ENDIF" "Attention: ENDIF manquant"
TRANSLATE "Expecting comma" "Virgule attendue"
TRANSLATE "Weekday specified twice" "Jour de la semaine spécifié deux fois"
TRANSLATE "Only use one of BEFORE, AFTER or SKIP" "Utiliser un seul parmi BEFORE, AFTER ou SKIP"
TRANSLATE "Can't nest MSG, MSF, RUN, etc. in expression" "Impossible d'imbriquer MSG, MSF, RUN, etc. dans une expression"
TRANSLATE "Repeat value specified twice" "Valeur de répétition spécifiée deux fois"
TRANSLATE "Delta value specified twice" "Valeur delta spécifiée deux fois"
TRANSLATE "Back value specified twice" "Valeur de retour spécifiée deux fois"
TRANSLATE "ONCE keyword used twice. (Hah.)" "Mot-clé ONCE utilisé deux fois. (Hah.)"
TRANSLATE "Expecting time after AT" "Heure attendue après AT"
TRANSLATE "THROUGH/UNTIL keyword used twice" "Mot-clé THROUGH/UNTIL utilisé deux fois"
TRANSLATE "Incomplete date specification" "Spécification de date incomplète"
TRANSLATE "FROM/SCANFROM keyword used twice" "Mot-clé FROM/SCANFROM utilisé deux fois"
TRANSLATE "Variable" "Variable"
TRANSLATE "Value" "Valeur"
TRANSLATE "*UNDEFINED*" "*NON-DEFINI*"
TRANSLATE "Entering UserFN" "Entrée dans UserFN"
TRANSLATE "Leaving UserFN" "Sortie de UserFN"
TRANSLATE "Expired" "Expiré"
TRANSLATE "fork() failed - can't do queued reminders" "fork() échoué - impossible de faire les appels en queue"
TRANSLATE "Can't access file" "Impossible d'accéder au fichier"
TRANSLATE "Illegal system date: Year is less than %d" "Date système illégale: Année est inférieure à %d"
TRANSLATE "Unknown debug flag '%c'" "Option de déverminage inconnue '%c'"
TRANSLATE "Unknown option '%c'" "Option inconnue '%c'"
TRANSLATE "Unknown user '%s'" "Usager inconnu '%s'"
TRANSLATE "Could not change gid to %d" "Impossible de changer gid pour %d"
TRANSLATE "Could not change uid to %d" "Impossible de changer uid pour %d"
TRANSLATE "Out of memory for environment" "Manque de mémoire pour environnement"
TRANSLATE "Missing '=' sign" "Signe '=' manquant"
TRANSLATE "Missing variable name" "Nom de variable absent"
TRANSLATE "Missing expression" "Expression absente"
TRANSLATE "%d reminder(s) queued for later today." "%d rappel(s) en file pour aujourd'hui."
TRANSLATE "Expecting number" "Nombre attendu"
TRANSLATE "Undefined WARN function" "Fonction illégale après WARN"
TRANSLATE "Can't convert between time zones" "Impossible de convertir entre les fuseaux horaires"
TRANSLATE "No files matching *.rem" "Aucun fichier correspondant à *.rem"
TRANSLATE "String too long" "Chaîne trop longue"
TRANSLATE "Time specified twice" "Heure spécifiée deux fois"
TRANSLATE "Cannot specify DURATION without specifying AT" "Impossible de spécifier DURATION sans spécifier AT"
TRANSLATE "Expecting weekday name" "Nom du jour de la semaine attendu"
TRANSLATE "Duplicate argument name" "Nom de l'argument en double"
TRANSLATE "Expression evaluation is disabled" "L'évaluation de l'expression est désactivée"
TRANSLATE "Time limit for expression evaluation exceeded" "Délai d'évaluation de l'expression dépassé"
TRANSLATE "here" "ici"
TRANSLATE "did you mean" "voulais-vous dire"

View File

@@ -1,8 +1,10 @@
# Support for the Hellenic (Greek) language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by jarlaxl lamat (jarlaxl@freemail.gr)
TRANSLATE "LANGID" "gr"
SET $Sunday "Κυριακή"
SET $Monday "Δευτέρα"
SET $Tuesday "Τρίτη"
@@ -56,30 +58,11 @@ FSET subst_gx(alt, d, t) iif(alt, subst_g_alt(d), $On + " " + subst_g_alt(d))
FSET subst_ux(alt, d, t) subst_ax(alt, d, t)
FSET subst_vx(alt, d, t) subst_gx(alt, d, t)
# Localization of various astronomical events
# Perihelion
SET earthseasons_Perihelion_str "Περιήλιον"
# Vernal equinox
SET earthseasons_EquinoxMar_str "Εαρινή ισημερία"
# Summer solstice
SET earthseasons_SolsticeJun_str "Θερινό ηλιοστάσιο"
# Aphelion
SET earthseasons_Aphelion_str "Αφήλιον"
# Autumnal Equinox
SET earthseasons_EquinoxSep_str "Φθινοπωρινή ισημερία"
# Winter Solstice
SET earthseasons_SolsticeDec_str "Χειμερινό ηλιοστάσιο"
# Daylight saving time starts
SET daylightST_starts_str "Έναρξη θέρους"
# Daylight saving time ends
SET daylightST_ends_str "Τέλος θέρους"
PRESERVE earthseasons_Perihelion_str earthseasons_EquinoxMar_str earthseasons_SolsticeJun_str earthseasons_Aphelion_str earthseasons_EquinoxSep_str earthseasons_SolsticeDec_str daylightST_starts_str daylightST_ends_str
TRANSLATE "Perihelion" "Περιήλιον"
TRANSLATE "Vernal Equinox" "Εαρινή ισημερία"
TRANSLATE "Summer Solstice" "Θερινό ηλιοστάσιο"
TRANSLATE "Aphelion" "Αφήλιον"
TRANSLATE "Autumnal Equinox" "Φθινοπωρινή ισημερία"
TRANSLATE "Winter Solstice" "Χειμερινό ηλιοστάσιο"
TRANSLATE "Daylight Saving Time Starts" "Έναρξη θέρους"
TRANSLATE "Daylight Saving Time Ends" "Τέλος θέρους"

View File

@@ -1,8 +1,10 @@
# Support for the Icelanding language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Björn Davíðsson (bjossi@snerpa.is)
TRANSLATE "LANGID" "is"
SET $Sunday "sunnudagur"
SET $Monday "mánudagur"
SET $Tuesday "þriðjudagur"

View File

@@ -1,8 +1,10 @@
# Support for the Italian language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Valerio Aimale
TRANSLATE "LANGID" "it"
SET $Sunday "Domenica"
SET $Monday "Lunedì"
SET $Tuesday "Martedì"

View File

@@ -1,8 +1,10 @@
# Support for the Dutch language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Willem Kasdorp and Erik-Jan Vens
TRANSLATE "LANGID" "nl"
SET $Sunday "zondag"
SET $Monday "maandag"
SET $Tuesday "dinsdag"
@@ -27,7 +29,7 @@ SET $December "december"
SET $Today "vandaag"
SET $Tomorrow "morgen"
BANNER Herinneringen voor %w, %d%s %m, %y%o:
BANNER Herinneringen voor %w, %d %m, %y%o:
SET $Am "am"
SET $Pm "pm"
@@ -55,15 +57,16 @@ FSET subst_hours(h) iif(h==1, "1 uur", h + " uren")
FSET subst_bx(a, d, t) "over " + (d-today()) + " dagen"
FSET subst_s(a, d, t) iif(day(d) == 1 || day(d) == 8, "e", day(d) < 20, "de", "te")
TRANSLATE "New Moon" "Nieuwe maan"
TRANSLATE "First Quarter" "Eerste kwartier"
TRANSLATE "Full Moon" "Volle maan"
TRANSLATE "Last Quarter" "Laatste kwartier"
TRANSLATE "Vernal Equiniox" "Lente-equinox"
TRANSLATE "Summer Solstice" "Zomerzonnewend"
TRANSLATE "Vernal Equinox" "Lente-equinox"
TRANSLATE "Summer Solstice" "Zomerzonnewende"
TRANSLATE "Autumnal Equinox" "Herfst-equinox"
TRANSLATE "Winter Solstice" "Winterzonnewend"
TRANSLATE "Winter Solstice" "Winterzonnewende"
TRANSLATE "Chinese New Year" "Chinees Nieuwjaar"
TRANSLATE "Snake" "Slang"
@@ -75,3 +78,11 @@ TRANSLATE "Dog" "Hond"
TRANSLATE "Pig" "Varken"
TRANSLATE "Rat" "Rat"
TRANSLATE "Ox" "Os"
TRANSLATE "Tiger" "Tijger"
TRANSLATE "Rabbit" "Konijn"
TRANSLATE "Dragon" "Draak"
TRANSLATE "Sunrise" "Zonsopgang"
TRANSLATE "Sunset" "Zonsondergang"
TRANSLATE "No reminders." "Geen herinneringen."

View File

@@ -1,8 +1,10 @@
# Support for the Norwegian language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Trygve Randen
TRANSLATE "LANGID" "no"
SET $Sunday "Søndag"
SET $Monday "Mandag"
SET $Tuesday "Tirsdag"

View File

@@ -1,8 +1,10 @@
# Support for the Polish language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Jerzy Sobczyk
TRANSLATE "LANGID" "pl"
SET $Sunday "Niedziela"
SET $Monday "Poniedziałek"
SET $Tuesday "Wtorek"
@@ -67,3 +69,104 @@ FSET subst_1past(diff) iif(diff/60==0, subst_1min(diff%60), diff%60==0, subst_1h
FSET subst_1min(m) m + " " + $Minute + subst_pl_plu(m)
FSET subst_1h(h) h + " " + $Hour + subst_pl_plu(h)
TRANSLATE "Ok" "OK"
TRANSLATE "Missing ']'" "Brakujący ']'"
TRANSLATE "Missing quote" "Brakujący nawias"
TRANSLATE "Expression too complex" "Zbyt skomplikowane wyrażenie"
TRANSLATE "Missing ')'" "Brakujący ')'"
TRANSLATE "Undefined function" "Nie zdefiniowana funkcja"
TRANSLATE "Illegal character" "Nielegalny znak"
TRANSLATE "Expecting binary operator" "Spodziewany operator binarny"
TRANSLATE "Out of memory" "Brak pamięci"
TRANSLATE "Ill-formed number" "Niepoprawny numer"
TRANSLATE "Can't coerce" "Niemożliwa konwersja"
TRANSLATE "Type mismatch" "Błąd typu"
TRANSLATE "Date overflow" "Nadmiar daty"
TRANSLATE "Division by zero" "Dzielenie przez zero"
TRANSLATE "Undefined variable" "Niezdefiniowana zmienna"
TRANSLATE "Unexpected end of line" "Niespodziewany koniec linii"
TRANSLATE "Unexpected end of file" "Niespodziewany koniec pliku"
TRANSLATE "I/O error" "Błąd wejscia/wyjscia"
TRANSLATE "Internal error" "Błąd wewnętrzny"
TRANSLATE "Bad date specification" "Zła specyfikacja daty"
TRANSLATE "Not enough arguments" "Za mało argumentów"
TRANSLATE "Too many arguments" "Za dużo argumentów"
TRANSLATE "Ill-formed time" "Nieprawidłowy czas"
TRANSLATE "Number too high" "Liczba za duża"
TRANSLATE "Number too low" "Liczba za mała"
TRANSLATE "Can't open file" "Nie mogę otworzyć pliku"
TRANSLATE "INCLUDE nested too deeply (max. 9)" "Zbyt zagnieżdżone INCLUDE"
TRANSLATE "Parse error" "Błąd składniowy"
TRANSLATE "Can't compute trigger" "Nie mogę obliczyć przypomnienia"
TRANSLATE "Too many nested IFs" "Zbyt zagnieżdżone IF"
TRANSLATE "ELSE with no matching IF" "ELSE bez IF do pary"
TRANSLATE "ENDIF with no matching IF" "ENDIF bez IF do pary"
TRANSLATE "Can't OMIT every weekday" "Nie mogę ominąć (OMIT) wszystkich dni"
TRANSLATE "Extraneous token(s) on line" "Niespodziewany wyraz w lini"
TRANSLATE "POP-OMIT-CONTEXT without matching PUSH-OMIT-CONTEXT" "POP-OMIT-CONTEXT bez PUSH-OMIT-CONTEXT"
TRANSLATE "RUN disabled" "Komenda RUN zablokowana"
TRANSLATE "Domain error" "Błąd dziedziny"
TRANSLATE "Invalid identifier" "Niepoprawny identyfikator"
TRANSLATE "Too many recursive function calls" "Wykryto rekursywne wywołanie funkcji"
TRANSLATE "Cannot modify system variable" "Nie mogę zmienić zmiennej systemowej"
TRANSLATE "C library function can't represent date/time" "Funkcja biblioteki C nie może reprezentowac daty/czasu"
TRANSLATE "Attempt to redefine built-in function" "Próba redefinicji funkcji wbudowanej"
TRANSLATE "Can't nest function definition in expression" "Nie wolno zagnieżdżać definicji funkcji w wyrażeniu"
TRANSLATE "Must fully specify date to use repeat factor" "Aby użyc powtórzenia trzeba w pełni wyspecyfikować datę"
TRANSLATE "Year specified twice" "Rok podany dwókrotnie"
TRANSLATE "Month specified twice" "Miesiąc podany dwókrotnie"
TRANSLATE "Day specified twice" "Dzień podany dwókrotnie"
TRANSLATE "Unknown token" "Nieznane słowo"
TRANSLATE "Must specify month in OMIT command" "W komendzie OMIT trzeba podać miesiąc"
TRANSLATE "Too many full OMITs (max. 1000)" "Za dużo pełnych komend OMIT"
TRANSLATE "Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT" "Ostrzeżenie: PUSH-OMIT-CONTEXT bez POP-OMIT-CONTEXT"
TRANSLATE "Error reading" "Błąd odczytu pliku"
TRANSLATE "Expecting end-of-line" "Oczekiwany koniec linii"
TRANSLATE "Invalid Hebrew date" "Błędna data hebrajska"
TRANSLATE "iif(): odd number of arguments required" "IIF wymaga nieparzystej liczby argumentów"
TRANSLATE "Warning: Missing ENDIF" "Ostrzeżenie: Brakujacy ENDIF"
TRANSLATE "Expecting comma" "Oczekiwany przecinek"
TRANSLATE "Weekday specified twice" "Dzień tygodnia podany dwókrotnie"
TRANSLATE "Only use one of BEFORE, AFTER or SKIP" "Dozwolone tylko jedno z: BEFORE, AFTER i SKIP"
TRANSLATE "Can't nest MSG, MSF, RUN, etc. in expression" "Nie można zagnieżdżać MSG, MSF, RUN, itp. w wyrażeniu"
TRANSLATE "Repeat value specified twice" "Wartość powtorzenia podana dwókrotnie"
TRANSLATE "Delta value specified twice" "Wartość różnicy podana dwókrotnie"
TRANSLATE "Back value specified twice" "Wartość cofnięcia podana dwókrotnie"
TRANSLATE "ONCE keyword used twice. (Hah.)" "Słowo ONCE użyte dwókrotnie."
TRANSLATE "Expecting time after AT" "Po AT oczekiwany jest czas"
TRANSLATE "THROUGH/UNTIL keyword used twice" "Słowo THROUGH/UNTIL użyte dwókrotnie"
TRANSLATE "Incomplete date specification" "Niekompletna specyfikacja daty"
TRANSLATE "FROM/SCANFROM keyword used twice" "Słowo FROM/SCANFROM użyte dwókrotnie"
TRANSLATE "Variable" "Zmienna"
TRANSLATE "Value" "Wartość"
TRANSLATE "*UNDEFINED*" "*NIE ZDEFINIOWANE*"
TRANSLATE "Entering UserFN" "Początek UserFN"
TRANSLATE "Leaving UserFN" "Koniec UserFN"
TRANSLATE "Expired" "Przemineło"
TRANSLATE "fork() failed - can't do queued reminders" "Niepowodzenie w funkcji fork() - nie mogę kolejkować przypomnień"
TRANSLATE "Can't access file" "Nie ma dostępu do pliku"
TRANSLATE "Illegal system date: Year is less than %d" "Błędna data systemowa: Rok mniejszy niż %d"
TRANSLATE "Unknown debug flag '%c'" "Nieznana flaga odpluskwiania '%c'"
TRANSLATE "Unknown option '%c'" "Nieznana opcja '%c'"
TRANSLATE "Unknown user '%s'" "Nieznany użytkownik '%s'"
TRANSLATE "Could not change gid to %d" "Nie mogę zmienić gid na %d"
TRANSLATE "Could not change uid to %d" "Nie mogę zmienić uid na %d"
TRANSLATE "Out of memory for environment" "Brak pamięci na zmienne środowiska"
TRANSLATE "Missing '=' sign" "Brak znaku '='"
TRANSLATE "Missing variable name" "Brak nazwy zmiennej"
TRANSLATE "Missing expression" "Brak wyrażenia"
TRANSLATE "Remind: '-i' option: %s" "Remind: '-i' option: %s"
TRANSLATE "No reminders." "Brak przypomnień."
TRANSLATE "%d reminder(s) queued for later today." "%d Przypomnienia zakolejkowane na później."
TRANSLATE "Expecting number" "Spodziewana liczba"
TRANSLATE "Undefined WARN function" "Nielegalna funkcja w klauzuli WARN:"
TRANSLATE "Can't convert between time zones" "Nie można konwertować między strefami czasowymi"
TRANSLATE "No files matching *.rem" "Brak dopasowania plików *.rem"
TRANSLATE "String too long" "Ciąg za długo:"
TRANSLATE "Time specified twice" "Czas określony dwukrotnie:"
TRANSLATE "Cannot specify DURATION without specifying AT" "Nie można określić DURATION bez AT"
TRANSLATE "Expecting weekday name" "Oczekiwana nazwa dnia tygodnia"
TRANSLATE "Duplicate argument name" "Zduplikowana nazwa argumentu"
TRANSLATE "Expression evaluation is disabled" "Ocena wyrażeń jest wyłączona"
TRANSLATE "Time limit for expression evaluation exceeded" "Przekroczono limit czasu na ocenę wyrażenia"

View File

@@ -1,8 +1,10 @@
# Support for the (Brazilian) Portuguese language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Marco Paganini
TRANSLATE "LANGID" "pt"
SET $Sunday "domingo"
SET $Monday "segunda"
SET $Tuesday "terça"
@@ -67,3 +69,103 @@ FSET subst_1(a, d, t) iif(t==now(), $Now, t>now(), "em " + subst_1help(t-now()),
FSET subst_1help(diff) iif(diff/60==0, subst_mplu(diff%60), diff%60==0, subst_hplu(diff/60), subst_hplu(diff/60) + " " + $And + " " + subst_mplu(diff%60))
FSET subst_mplu(m) iif(m==1, "1 " + $Minute, m + " " + $Minute + $Mplu)
FSET subst_hplu(h) iif(h==1, "1 " + $Hour, h + " " + $Hour + $Hplu)
TRANSLATE "Missing ']'" "Falta um ']'"
TRANSLATE "Missing quote" "Falta uma aspa"
TRANSLATE "Expression too complex" "Expressao muito complexa"
TRANSLATE "Missing ')'" "Falta um ')'"
TRANSLATE "Undefined function" "Funcao nao definida"
TRANSLATE "Illegal character" "Caracter ilegal"
TRANSLATE "Expecting binary operator" "Esperando operador binario"
TRANSLATE "Out of memory" "Sem memoria"
TRANSLATE "Ill-formed number" "Numero mal-formado"
TRANSLATE "Can't coerce" "Nao consigo fazer 'coerce'"
TRANSLATE "Type mismatch" "Type mismatch"
TRANSLATE "Date overflow" "Overflow na data"
TRANSLATE "Division by zero" "Divisao por zero"
TRANSLATE "Undefined variable" "Variavel nao definida"
TRANSLATE "Unexpected end of line" "Fim da linha nao esperado"
TRANSLATE "Unexpected end of file" "Fim de arquivo nao esperado"
TRANSLATE "I/O error" "Erro de I/O"
TRANSLATE "Internal error" "Erro interno"
TRANSLATE "Bad date specification" "Especificacao de data invalida"
TRANSLATE "Not enough arguments" "Argumentos insuficientes"
TRANSLATE "Too many arguments" "Argumentos em excesso"
TRANSLATE "Ill-formed time" "Hora mal-formada"
TRANSLATE "Number too high" "Numero muito grande"
TRANSLATE "Number too low" "Numero muito pequeno"
TRANSLATE "Can't open file" "Nao consigo abrir o arquivo"
TRANSLATE "INCLUDE nested too deeply (max. 9)" "Ninho de INCLUDEs muito profundo"
TRANSLATE "Parse error" "Erro de parsing"
TRANSLATE "Can't compute trigger" "Nao consigo computar o 'trigger'"
TRANSLATE "Too many nested IFs" "Muitos IFs aninhados"
TRANSLATE "ELSE with no matching IF" "ELSE sem o IF correspondente"
TRANSLATE "ENDIF with no matching IF" "ENDIF sem o IF correspondente"
TRANSLATE "Can't OMIT every weekday" "Nao se pode usar OMIT para todos os dias da semana"
TRANSLATE "Extraneous token(s) on line" "Token nao reconhecido na linha"
TRANSLATE "POP-OMIT-CONTEXT without matching PUSH-OMIT-CONTEXT" "POP-OMIT-CONTEXT sem PUSH-OMIT-CONTEXT correspondente"
TRANSLATE "RUN disabled" "RUN desabilitado"
TRANSLATE "Domain error" "Erro de dominio"
TRANSLATE "Invalid identifier" "Identificados invalido"
TRANSLATE "Too many recursive function calls" "Muitas chamadas de função recursiva"
TRANSLATE "Cannot modify system variable" "Nao posso modificar variavel de sistema"
TRANSLATE "C library function can't represent date/time" "Funcao da biblioteca C nao pode representar data/hora"
TRANSLATE "Attempt to redefine built-in function" "Tentativa de redefinir funcao interna"
TRANSLATE "Can't nest function definition in expression" "Nao e' possivel aninhar definicao de funcao em expressao"
TRANSLATE "Must fully specify date to use repeat factor" "Data deve ser completamente especificada para usar o fator de REPEAT"
TRANSLATE "Year specified twice" "Ano especificado duas vezes"
TRANSLATE "Month specified twice" "Mes especificado duas vezes"
TRANSLATE "Day specified twice" "Dia especificado duas vezes"
TRANSLATE "Unknown token" "Token desconhecido"
TRANSLATE "Must specify month in OMIT command" "O mes deve ser especificados no comando OMIT"
TRANSLATE "Too many full OMITs (max. 1000)" "Muitos OMITs full"
TRANSLATE "Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT" "Aviso: PUSH-OMIT-CONTEXT sem POP-OMIT-CONTEXT correspondente"
TRANSLATE "Error reading" "Erro na leitura do arquivo"
TRANSLATE "Expecting end-of-line" "Aguardando fim do arquivo"
TRANSLATE "Invalid Hebrew date" "Data hebraica invalida"
TRANSLATE "iif(): odd number of arguments required" "IIF necessita de numero impar de argumentos"
TRANSLATE "Warning: Missing ENDIF" "Warning: ENDIF faltando"
TRANSLATE "Expecting comma" "Esperando virgula"
TRANSLATE "Weekday specified twice" "Dia da semana especificado duas vezes"
TRANSLATE "Only use one of BEFORE, AFTER or SKIP" "Use apenas um de BEFORE, AFTER ou SKIP"
TRANSLATE "Can't nest MSG, MSF, RUN, etc. in expression" "Nao e possivel aninhar MSG, MSF, RUN, etc. em expressoes"
TRANSLATE "Repeat value specified twice" "Valor de Repeat especificado duas vezes"
TRANSLATE "Delta value specified twice" "Valor de Delta especificado duas vezes"
TRANSLATE "Back value specified twice" "Valor de Back especificado duas vezes"
TRANSLATE "ONCE keyword used twice. (Hah.)" "ONCE usado duas vezes (Eheheh)"
TRANSLATE "Expecting time after AT" "Esperando hora apos AT"
TRANSLATE "THROUGH/UNTIL keyword used twice" "Keyword THROUGH/UNTIL usada duas vezes"
TRANSLATE "Incomplete date specification" "Especificacao de data incompleta"
TRANSLATE "FROM/SCANFROM keyword used twice" "Keyword FROM/SCANFROM usada duas vezes"
TRANSLATE "Variable" "Variavel"
TRANSLATE "Value" "Valor"
TRANSLATE "*UNDEFINED*" "*INDEFINIDO*"
TRANSLATE "Entering UserFN" "Entrando UserFN"
TRANSLATE "Leaving UserFN" "Saindo UserFN"
TRANSLATE "Expired" "Expirou"
TRANSLATE "fork() failed - can't do queued reminders" "fork() falhou - Nao posso processar compromissos na fila"
TRANSLATE "Can't access file" "Nao consigo acessar o arquivo"
TRANSLATE "Illegal system date: Year is less than %d" "Data do sistema ilegal: Ano e menor que %d"
TRANSLATE "Unknown debug flag '%c'" "Flag de debug desconhecido '%c'"
TRANSLATE "Unknown option '%c'" "Opcao desconhecida '%c'"
TRANSLATE "Unknown user '%s'" "Usuario desconhecido '%s'"
TRANSLATE "Could not change gid to %d" "Nao consigo mudar gid para %d"
TRANSLATE "Could not change uid to %d" "Nao consigo mudar uid para %d"
TRANSLATE "Out of memory for environment" "Sem memoria para o environment"
TRANSLATE "Missing '=' sign" "Falta o sinal de '='"
TRANSLATE "Missing variable name" "Falta o nome da variavel"
TRANSLATE "Missing expression" "Falta a expressao"
TRANSLATE "Remind: '-i' option: %s" "Remind: '-i' opcao: %s"
TRANSLATE "No reminders." "Sem compromissos."
TRANSLATE "%d reminder(s) queued for later today." "%d compromisso(s) colocados na fila para mais tarde."
TRANSLATE "Expecting number" "Esperando numero"
TRANSLATE "Undefined WARN function" "Funcao ilegal na clausula WARN"
TRANSLATE "Can't convert between time zones" "Não consigo converter entre fusos horários"
TRANSLATE "No files matching *.rem" "Nenhum arquivo correspondente *.rem"
TRANSLATE "String too long" "String muito longa"
TRANSLATE "Time specified twice" "Tempo especificado duas vezes"
TRANSLATE "Cannot specify DURATION without specifying AT" "Não é possível especificar DURATION sem especificar AT"
TRANSLATE "Expecting weekday name" "Esperando nome do dia da semana"
TRANSLATE "Duplicate argument name" "Nome de argumento duplicado"
TRANSLATE "Expression evaluation is disabled" "A avaliação da expressão está desabilitada"
TRANSLATE "Time limit for expression evaluation exceeded" "Limite de tempo para avaliação de expressão excedido"

View File

@@ -1,8 +1,10 @@
# Support for the Romanian language.
# This file is part of REMIND.
# REMIND is Copyright (C) 1992-2024 by Dianne Skoll
# REMIND is Copyright (C) 1992-2025 by Dianne Skoll
# This file is derived from a translation by Liviu Daia
TRANSLATE "LANGID" "ro"
SET $Sunday "Duminică"
SET $Monday "Luni"
SET $Tuesday "Marți"

View File

@@ -7,8 +7,8 @@ IF $CalMode || $PsCal
REM [moondate(2)] SPECIAL MOON 2 -1 -1 [moontime(2)]
REM [moondate(3)] SPECIAL MOON 3 -1 -1 [moontime(3)]
ELSE
REM NOQUEUE [moondatetime(0)] MSG [_("New Moon")] (%2)
REM NOQUEUE [moondatetime(1)] MSG [_("First Quarter")] (%2)
REM NOQUEUE [moondatetime(2)] MSG [_("Full Moon")] (%2)
REM NOQUEUE [moondatetime(3)] MSG [_("Last Quarter")] (%2)
REM NOQUEUE [moondatetime(0)] MSG %(New Moon) (%2)
REM NOQUEUE [moondatetime(1)] MSG %(First Quarter) (%2)
REM NOQUEUE [moondatetime(2)] MSG %(Full Moon) (%2)
REM NOQUEUE [moondatetime(3)] MSG %(Last Quarter) (%2)
ENDIF

View File

@@ -3,14 +3,14 @@
IF $LatDeg >= 0
# Northern Hemisphere
REM NOQUEUE [soleq(0)] MSG %"[_("Vernal Equinox")]%" [$Is] %3.
REM NOQUEUE [soleq(1)] MSG %"[_("Summer Solstice")]%" [$Is] %3.
REM NOQUEUE [soleq(2)] MSG %"[_("Autumnal Equinox")]%" [$Is] %3.
REM NOQUEUE [soleq(3)] MSG %"[_("Winter Solstice")]%" [$Is] %3.
REM NOQUEUE [soleq(0)] MSG %"%(Vernal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(1)] MSG %"%(Summer Solstice)%" [$Is] %3.
REM NOQUEUE [soleq(2)] MSG %"%(Autumnal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(3)] MSG %"%(Winter Solstice)%" [$Is] %3.
ELSE
# Southern Hemisphere
REM NOQUEUE [soleq(0)] MSG %"[_("Autumnal Equinox")]%" [$Is] %3.
REM NOQUEUE [soleq(1)] MSG %"[_("Winter Solstice")]%" [$Is] %3.
REM NOQUEUE [soleq(2)] MSG %"[_("Vernal Equinox")]%" [$Is] %3.
REM NOQUEUE [soleq(3)] MSG %"[_("Summer Solstice")]%" [$Is] %3.
REM NOQUEUE [soleq(0)] MSG %"%(Autumnal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(1)] MSG %"%(Winter Solstice)%" [$Is] %3.
REM NOQUEUE [soleq(2)] MSG %"%(Vernal Equinox)%" [$Is] %3.
REM NOQUEUE [soleq(3)] MSG %"%(Summer Solstice)%" [$Is] %3.
ENDIF

7
include/sun.rem Normal file
View File

@@ -0,0 +1,7 @@
# Sunrise and sunset
# SPDX-License-Identifier: GPL-2.0-only
IF !$CalMode && !$PsCal
REM NOQUEUE AT [sunrise()] MSG %"%"%(Sunrise) %! %2.
REM NOQUEUE AT [sunset()] MSG %"%"%(Sunset) %! %2.
ENDIF

View File

@@ -336,6 +336,18 @@ older format contains enough information for them to work properly.
.PP
\fBRemind \-p\fR sends the following lines to standard output.
The information is designed to be easily parsed by back-end programs:
.TP
.B # translations
This line signifies that the next line will be the translation table.
The line following \fB# translations\fR is a JSON object (on a single
line) containing all of the entries of the translation table. Back-ends that
are not interested in the translation table can simply read and discard
the next line.
.RS
If \fBRemind\fR sends data for multiple months, then only the first month
will include the translation table.
.RE
.TP
.B # rem2ps begin
This line signifies the start of calendar data. Back-ends can search
@@ -435,6 +447,16 @@ each reminder as a one-off event.
.PP
The lines emitted by \fBremind \-pp\fR are as follows:
.TP
.B # translations
This line signifies that the next line will be the translation table.
The line following \fB# translations\fR is a JSON object (on a single
line) containing all of the entries of the translation table. Back-ends that
are not interested in the translation table can simply read and discard
.RS
If \fBRemind\fR sends data for multiple months, then only the first month
will include the translation table.
.RE
.TP
.B # rem2ps2 begin
This line signifies the start of calendar data. Back-ends can search
for it to verify they are being fed correct information. Note the
@@ -494,6 +516,29 @@ MOON, etc.)
If any TAG clauses are present, the \fBtags\fR key will be present and consist
of a comma-separated list of tags.
.TP
.B info \fR{ \fIhash\fR }
If any INFO clauses are present, the \fBinfo\fR key will be present. Its
value will be a hash of info key-value pairs. Each key is the header
from an INFO string, \fIconverted to all lower-case\fR. The value is the
value from the INFO string.
.RS
.PP
For example, the following REM command:
.PP
.nf
REM INFO "Location: Boardroom" INFO "Summary: None" MSG whatever
.fi
.PP
will produce the following \fBinfo\fR hash:
.PP
.nf
"info" : {
"location" : "Boardroom",
"summary" : "None"
},
.fi
.RE
.TP
.B time \fIt\fR
If an AT clause was present, this key will contain the time of the AT clause
in minutes after midnight.
@@ -615,66 +660,100 @@ However, back-ends should keep reading until EOF in case more data for
subsequent months is forthcoming.
.PP
.SH REM2PS PURE JSON INPUT FORMAT (-PPP OPTION)
\fBRemind \-ppp\fR emits \fIpure JSON\fR output. The format is
as follows:
.SH REM2PS PURE JSON INPUT FORMAT (-PPP OR -P+ OPTION)
\fBRemind \-ppp\fR and \fBremind \-p+\fR emit \fIpure JSON\fR output.
The format is as follows:
.PP
\fBRemind\fR outputs a JSON array. Each element of the array is a
\fImonth descriptor\fR.
\fImonth descriptor\fR or a \fIweek descriptor\fR in the case of
\fBremind \-p+\fR.
.PP
Each month descriptor is a JSON object with the following elements:
Each descriptor is a JSON object with the following elements:
.TP
.B caltype \fItype\fR
The calendar type, either \fBmonthly\fR or \fBweekly\fR. Older versions
of \fBRemind\fR did not include a \fBcaltype\fR element, so a missing
\fBcaltype\fR should be treated as \fBmonthly\fR.
.TP
.B monthname \fIname\fR
The name of the month.
The name of the month. Present in monthly calendar types only.
.TP
.B year \fIyyyy\fR
The year.
The year. Present in monthly calendar types only.
.TP
.B daysinmonnth \fIn\fR
The number of days in the current month.
The number of days in the current month. Present in monthly calendar types only.
.TP
.B firstwkday \fIn\fR
The weekday of the first day of the month (0 = Sunday, 1 = Monday, 6 = Saturday).
The weekday of the first day of the month (0 = Sunday, 1 = Monday, 6 = Saturday). Present in monthly calendar types only.
.TP
.B mondayfirst \fIn\fR
An indicator of whether or not the calendar week should start with
Sunday (n=0) or Monday (n=1).
Sunday (n=0) or Monday (n=1). Present in monthly calendar types only.
.TP
.B daynames \fR[\fIdays\fR]
A seven-element array of day names; each element is a string representing
the names of the days from Sunday through Saturday.
the names of the days from Sunday through Saturday. Present in monthly calendar types only.
.TP
.B prevmonthname \fIname\fR
The name of the previous month.
The name of the previous month. Present in monthly calendar types only.
.TP
.B daysinprevmonth \fIn\fR
The number of days in the previous month.
The number of days in the previous month. Present in monthly calendar types only.
.TP
.B prevmonthyear \fIyyyy\fR
The year of the previous month. (The same as \fByear\fR unless the current
month is January.)
month is January.) Present in monthly calendar types only.
.TP
.B nextmonthname \fIname\fR
The name of the following month.
The name of the following month. Present in monthly calendar types only.
.TP
.B daysinnextmonth \fIn\fR
The number of days in the following month.
The number of days in the following month. Present in monthly calendar types only.
.TP
.B nextmonthyear \fIyyyy\fR
The year of the following month. (The same as \fByear\fR unless the
current month is December.)
current month is December.) Present in monthly calendar types only.
.TP
.B translations \fR{\fIobject\fR}
A complete dump of the Remind translation table. In output for multiple
months or weeks, the translation table is included only with the first month
or week. Present in both weekly and monthly calendar types.
.TP
.B entries \fR[\fIarray\fR]
The \fBentries\fR key consists of an array of calendar entries; each
entry is a JSON object that has the same format as described in the
\fBCALENDAR ENTRIES\fR section in the \fB\-PP FORMAT\fR section,
\fIwith the following difference\fR: In \fB\-PP\fR mode, if a reminder
has \fB%"\fR markers, only the text between the markers
is included in the \fBbody\fR element. In \fB\-PPP\fR mode, the
entire text \fIincluding\fR the \fB%"\fR markers is included and it's up to
the back-end to extract the portion between the markers if that
is desired.
The \fBentries\fR key, present in both weekly and monthly calendar
types, consists of an array of calendar entries; each entry is a JSON
object that has the same format as described in the \fBCALENDAR
ENTRIES\fR section in the \fB\-PP FORMAT\fR section, \fIwith the
following difference\fR: In \fB\-PP\fR mode, if a reminder has
\fB%"\fR markers, only the text between the markers is included in the
\fBbody\fR element. In \fB\-PPP\fR mode, the entire text
\fIincluding\fR the \fB%"\fR markers is included and it's up to the
back-end to extract the portion between the markers if that is
desired.
.TP
.B dates \fR[\fIarray\fR]
The \fBdates\fR key, present in weekly calendar types only,
contains seven entries; one for each column in the weekly
calendar. Each entry is a JSON object containing the following
key/value pairs:
.RS
.TP
.B date \fR\fIYYYY-MM-DD\fR
The date of the column.
.TP
.B day \fR\fIDD\fR
The day number of the column.
.TP
.B dayname \fR\fIweekday_name\fR
The name of the weekday (possibly localized).
.TP
.B month \fR\fImonth_name\fR
The name of the month (possibly localized).
.TP
.B year \fR\fIYYYY\fR
The year.
.RE
.SH AUTHOR
rem2ps was written by Dianne Skoll <dianne@skoll.ca>

View File

@@ -182,12 +182,18 @@ If you immediately follow the \fBs\fR with the letter
day they actually occur \fIas well as\fR on any preceding days specified
by the reminder's \fIdelta\fR.
.TP
.B \-p\fR[\fBa\fR][\fBp\fR][\fBp\fR][\fBq\fR]\fIn\fR
.B \-p\fR[\fBa\fR][\fBp\fR][\fBp\fR][\fBq\fR][+]\fIn\fR
The \fB\-p\fR option is very similar to the \fB\-s\fR option, except
that the output contains additional information for use by the
that the output contains additional information for use by a back-end such as the
\fBRem2PS\fR program, which creates a PostScript calendar, and various
other back-end programs. For this
option, \fIn\fR cannot start with "+"; it must specify a number of months.
other back-end programs. If \fIn\fR starts with "+", then it specifies
a number of weeks rather than a number of months, and back-ends are expected
to produce weekly calendars. Note that not all back-ends support
weekly calendars; currently, only \fBrem2pdf\fR does. Specifying a weekly
calendar implicitly enables the pure JSON interchange format, similar
to \fB\-ppp\fR.
.RS
.PP
The format of the \fB\-p\fR output is described in the \fBrem2ps(1)\fR
man page. If you immediately follow the \fBp\fR with the letter
\fBa\fR, then \fBRemind\fR displays reminders on the calendar on the
@@ -200,7 +206,6 @@ three p's, as in \fB\-ppp\fR, then \fBRemind\fR uses a pure JSON
format, again documented in \fBrem2ps(1)\fR. If you include a \fBq\fR
letter with this option, then the normal calendar-mode substitution filter
is disabled and the %"...%" sequences are preserved in the output.
.RS
.PP
The \fB\-p\fR, \fB\-pp\fR and \fB\-ppp\fR options implicitly enable
the \fB\-o\fR option.
@@ -310,6 +315,13 @@ Trace the reading of reminder files
Trace expression parsing and display the internal expression node
tree. This is unlikely to be useful unless you are working on
\fBRemind\fR's expression evaluation engine.
.TP
.B h
Dump hash-table statistics on exit.
.TP
.B q
Output a TRANSLATE command each time the \fB_()\fR built-in function
is called or the \fB%(...)\fR substitution sequence is encountered.
.RE
.TP
\fB\-g\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR]]]]
@@ -469,6 +481,22 @@ case-sensitive:
The \fB\-\-version\fR option causes \fBRemind\fR to print its version number
to standard output and then exit.
.TP
.B \-\-print-errs
The \fB\-\-print-errs\fR option causes \fBRemind\fR to print all
possible error messages to standard output and then exit. The
messages are printed in a format suitable for the first argument of a
TRANSLATE command. If you TRANSLATE the error messages, then
\fBRemind\fR will use the translated versions when outputting error
and warning messages. See also TRANSLATE GENERATE in the section
"THE TRANSLATION TABLE".
.RS
.PP
Note that if an untranslated message contains printf-style formatting
sequences like "%s" or "%d", then the translated message \fImust\fR
contain the same sequences in the same order, or \fBRemind\fR will
ignore it and use the original untranslated message.
.RE
.TP
.B \-\-print-config-cmd
This option causes \fBRemind\fR to print the exact \fB./configure\fR
command that was used when \fBRemind\fR was built. You can use this
@@ -502,11 +530,16 @@ resources. Note that the limit \fIn\fR is approximate and
\fBRemind\fR might execute for one or two more seconds before it is
killed. If \fIn\fR is specified as zero, then no limit is applied, just
as if the option had not been used at all.
.RS
.PP
If a limit is applied, it applies only to the foreground run of \fBRemind\fR.
If \fBRemind\fR finishes processing the script and then starts handling
queued reminders, the time limit is reset to no limit.
.PP
.RE
.TP
.B \-\-test
The \fB\-\-test\fR long option is only for use by the acceptance tests
run by "make test". Do not use this option in production.
.SH REMINDER FILES
.PP
\fBRemind\fR uses scripts to control its operation. You can use any
@@ -573,8 +606,9 @@ Its syntax is:
[\fBSCANFROM\fR \fIscan_date\fR | \fBFROM\fR \fIstart_date\fR]
[\fBDURATION\fR \fIduration\fR]
[\fBTAG\fR \fItag\fR]
<\fBMSG\fR | \fBMSF\fR | \fBRUN\fR | \fBCAL\fR | \fBSATISFY\fR |
\fBSPECIAL\fR \fIspecial\fR | \fBPS\fR | \fBPSFILE\fR>
[\fBINFO\fR "\fIinfo_string\fR"]
\fBMSG\fR | \fBMSF\fR | \fBRUN\fR | \fBCAL\fR | \fBSATISFY\fR |
\fBSPECIAL\fR \fIspecial\fR | \fBPS\fR | \fBPSFILE\fR
.I body
.RE
.PP
@@ -1310,7 +1344,7 @@ However, discussion must be deferred until after
expressions and user-defined functions are explained. See the subsection
"PRECISE SCHEDULING" further on.
.PP
.B TAG AND DURATION
.B TAG, INFO AND DURATION
.PP
The \fBTAG\fR keyword lets you "tag" certain reminders. This facility
is used by certain back-ends or systems built around \fBRemind\fR,
@@ -1329,15 +1363,40 @@ by the hexadecimal representation of the MD5 sum of the REM
command line. This lets you give a more-or-less unique identifier
to each distinct REM command.
.PP
The \fBINFO\fR keyword is similar to \fBTAG\fR but is intended to convey
metadata about an event, such as its location. Back-ends will have their
own rules about which \fIinfo_string\fRs they recognize, and must ignore
\fIinfo_string\fRs they don't recognize. Note that \fBINFO\fR must
be followed by a quoted string; you can include newlines in the string
by supplying them as "\\n".
.PP
An INFO string \fImust\fR be of the form "Header: Value". The header
can consist of any printable character, but cannot contain whitespace.
The value can consist of any characters you like. Space may not
appear before the colon, but can appear afterwards; such space is not
considered to be part of the value. If there is more than one INFO
string for a given reminder, there cannot be any duplicate headers.
Case is ignored when determining if a header is a duplicate of an
existing one.
.PP
For example, a hypothetical back-end might let you set the location
and description of a reminder like this:
.PP
.nf
REM 26 Feb 2025 INFO "Location: Boardroom #2" \\
INFO "Description: Go over latest pull requests" \\
MSG Engineering meeting
.fi
.PP
The \fBDURATION\fR keyword makes sense only for timed reminders; it
specifies the duration of an event. For example, if you have a
90-minute meeting starting at 1:00pm, you could use any of the following:
.PP
.nf
REM 5 March 2021 AT 13:00 DURATION 1:30 MSG Meeting
REM 5 March 2021 AT 13:00 DURATION 90 MSG Meeting
REM 5 March 2021 AT 1:00pm DURATION 1:30 MSG Meeting
REM 5 March 2021 AT 1:00pm DURATION 90 MSG Meeting
REM 5 March 2021 AT 13:00 DURATION 1:30 MSG Meeting
REM 5 March 2021 AT 13:00 DURATION 90 MSG Meeting
REM 5 March 2021 AT 1:00pm DURATION 1:30 MSG Meeting
REM 5 March 2021 AT 1:00pm DURATION 90 MSG Meeting
.fi
.PP
For long-duration reminders, it is convenient to use expressions
@@ -1367,26 +1426,26 @@ The REM command has syntactic sugar to let you express common
reminders. The following pairs of reminders are equivalent:
.PP
.nf
REM First Monday April MSG Foo
REM Mon 1 April MSG Foo
REM First Monday April MSG Foo
REM Mon 1 April MSG Foo
REM Second Monday May MSG Bar
REM Mon 8 May MSG Bar
REM Second Monday May MSG Bar
REM Mon 8 May MSG Bar
REM Third Monday MSG Third Monday of every month
REM Mon 15 MSG Third Monday of every month
REM Third Monday MSG Third Monday of every month
REM Mon 15 MSG Third Monday of every month
REM Fourth Sunday June 2025 MSG Fourth Sunday in June 2025
REM Sun 22 June 2025 MSG Fourth Sunday in June 2025
REM Fourth Sunday June 2025 MSG Fourth Sunday in June 2025
REM Sun 22 June 2025 MSG Fourth Sunday in June 2025
REM Last Monday MSG Last Monday of every month
REM Mon 1 --7 MSG Last Monday of every month
REM Last Monday MSG Last Monday of every month
REM Mon 1 --7 MSG Last Monday of every month
REM Last Monday April MSG Last Monday of every April
REM Mon 1 May --7 MSG Last Monday of every April
REM Last Monday April MSG Last Monday of every April
REM Mon 1 May --7 MSG Last Monday of every April
REM Last Monday December 2025 MSG Last Monday of Dec 2025
REM Monday 1 Jan 2026 --7 MSG Last Monday of Dec 2025
REM Last Monday December 2025 MSG Last Monday of Dec 2025
REM Monday 1 Jan 2026 --7 MSG Last Monday of Dec 2025
.fi
.PP
Note that \fBLast\fR effectively adjusts the month and year, if necessary, to
@@ -1395,35 +1454,35 @@ make the reminder trigger on the correct date.
The keyword \fBIN\fR is completely ignored, so you can write (for example):
.PP
.nf
REM Second Monday in May MSG foo
REM Last Monday in December 2025 MSG Bar
REM Second Monday in May MSG foo
REM Last Monday in December 2025 MSG Bar
.fi
.PP
An alternate form of \fIback\fR makes writing reminders easier.
The following groups of reminders are equivalent:
.PP
.nf
REM ~~1 MSG Last day of every month
REM Lastday MSG Last day of every month
REM 1 --1 MSG Last day of every month
REM ~~1 MSG Last day of every month
REM Lastday MSG Last day of every month
REM 1 --1 MSG Last day of every month
REM May ~~1 MSG Last day of May
REM Lastday May MSG Last day of May
REM 1 June --1 MSG Last day of May
REM May ~~1 MSG Last day of May
REM Lastday May MSG Last day of May
REM 1 June --1 MSG Last day of May
REM Dec 2025 ~~1 MSG Last day of December 2025
REM Lastday Dec 2025 MSG Last day of December 2025
REM 1 Jan 2026 --1 MSG Last day of December 2025
REM Dec 2025 ~~1 MSG Last day of December 2025
REM Lastday Dec 2025 MSG Last day of December 2025
REM 1 Jan 2026 --1 MSG Last day of December 2025
REM Apr ~1 OMIT SAT SUN MSG Last workday of April
REM Lastworkday April OMIT SAT SUN MSG Last workday of April
REM 1 May -1 OMIT SAT SUN MSG Last workday of April
REM Apr ~1 OMIT SAT SUN MSG Last workday of April
REM Lastworkday April OMIT SAT SUN MSG Last workday of April
REM 1 May -1 OMIT SAT SUN MSG Last workday of April
REM Apr ~~7 MSG Seventh-last day of April
REM 1 May --7 MSG Seventh-last day of April
REM Apr ~~7 MSG Seventh-last day of April
REM 1 May --7 MSG Seventh-last day of April
REM Apr ~2 OMIT SAT SUN MSG Second-last workday of April
REM 1 May -2 OMIT SAT SUN MSG Second-last workday of April
REM Apr ~2 OMIT SAT SUN MSG Second-last workday of April
REM 1 May -2 OMIT SAT SUN MSG Second-last workday of April
.fi
.PP
As we see, "Lastday" is equivalent to ~~1 and "Lastworkday" to ~1.
@@ -1434,9 +1493,9 @@ be combined with a day. Additionally, First/Second/Third/Fourth/Last
must have at least one weekday name. The following are illegal:
.PP
.nf
REM First Monday 3 June MSG Huh?
REM April 3 ~~1 MSG What?
REM Second June MSG Where's the weekday???
REM First Monday 3 June MSG Huh?
REM April 3 ~~1 MSG What?
REM Second June MSG Where's the weekday???
.fi
.PP
.SH THE SUBSTITUTION FILTER
@@ -1598,6 +1657,15 @@ is replaced with "\fIyear\fR", the year of the trigger date.
.B %z
is replaced with "\fIyy\fR", the last two digits of the year.
.TP
.B %(\fIany_text\fR\fB)
is replaced with the lookup of \fIany_text\fR in the translation table.
It is the equivalent of [_("any_text")] but is more convenient to type.
.TP
.B %<\fIany_text\fR\fB>
is replaced with the INFO value associated with the header \fIany_text\fR
or the empty string if no such INFO value exists. It is the
equivalent of [triginfo("any_text")] but is more convenient to type.
.TP
.B %_
(percent-underscore) is replaced with a newline. You can use this to
achieve multi-line reminders. Note that calendar back-ends vary in
@@ -1906,22 +1974,21 @@ 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 DO AND INCLUDE COMMANDS
.SH THE DO, INCLUDE AND SYSINCLUDE COMMANDS
.PP
\fBRemind\fR allows you to include other files in your reminder script,
similar to the C preprocessor #include directive. For example, your
system administrator may maintain a file of holidays or system-wide
reminders. You can include these in your reminder script as follows:
similar to the C preprocessor #include directive. For example, you
might organize different reminders into different files like this:
.PP
.nf
INCLUDE /usr/share/remind/holidays
INCLUDE /usr/share/remind/reminders
INCLUDE holidays.rem
INCLUDE birthdays.rem
INCLUDE "quote files with spaces.rem"
.fi
.PP
(The actual pathnames vary from system to system - ask your system
administrator.)
.PP
\fBINCLUDE\fR files can be nested up to a depth of 8.
\fBINCLUDE\fR files can be nested up to a depth of 8. As shown above, if a
filename has spaces in it (not recommended!) you can use double-quotes
around the filename.
.PP
If you specify a filename of "-" in the \fBINCLUDE\fR command, \fBRemind\fR
will begin reading from standard input.
@@ -1963,6 +2030,11 @@ symbolic link itself, \fBDO\fR will fail. \fBRemind\fR does \fInot\fR
resolve the real path of symbolic links, so you should avoid using
symbolic links to files.
.PP
The \fBSYSINCLUDE\fR command is similar to \fBDO\fR, but it looks for
relative pathnames under the system directory containing standard reminder
scripts. For this version of \fBRemind\fR, the system directory is
"@prefix@/share/remind".
.PP
.SH THE RUN COMMAND
.PP
If you include other files in your reminder script, you may not always
@@ -2187,6 +2259,10 @@ The following examples illustrate constants in \fBRemind\fR expressions:
Note that the empty string is represented by "". Remind supports
the escape sequences "\\a", "\\b", "\\f", "\\n", "\\r", "\\t"
and "\\v" which have the same meanings as their counterparts in C.
It also supports "\\xAB" where A and B are hexadecimal digits;
this operates just as in C. The "\\x" must be followed by one or
two hex digits; the escape sequence "\\x00" is not permitted.
.PP
To include a quote in a string, use "\\"". Any other character
preceded by a backslash is inserted into the string as-is, but the
backslash itself is removed. To include a backslash in a string,
@@ -2491,7 +2567,7 @@ The following system variables are defined. Those marked
All system variables hold values of type \fBINT\fR, unless otherwise
specified.
.TP
.B $AddBlankLines
.B $AddBlankLines
If set to 1 (the default), then \fBRemind\fR normally prints a blank
line after the banner and each reminder. (This can be suppressed by
ending the reminder or banner with a single percent sign.) If
@@ -2512,12 +2588,17 @@ Universal Time Coordinated in the \fB$MinsFromUTC\fR system variable.
.B $CalMode (read-only)
If non-zero, then the \fB\-c\fR option was supplied on the command line.
.TP
.B $CalType (read-only, STRING type)
If the \fB\-c\fR, \fB\-s\fR or \fB\-p\fR command-line options were
used, then this variable has the value "monthly". If \fB\-c+\fR,
\fB\-s+\fR or \fB\-p+\fR were used, then "weekly". Otherwise, "none".
.TP
.B $Daemon (read-only)
If "daemon mode" \fB\-z\fR was invoked, contains the number of
minutes between wakeups. If not running in daemon mode, contains
0. In server mode (either \fB-z0\fR or \fB-zj\fR), contains -1.
.TP
.B $DateSep
.B $DateSep (STRING type)
This variable can be set only to "/" or "-". It holds the character
used to separate portions of a date when \fBRemind\fR prints a DATE or
DATETIME value.
@@ -2572,7 +2653,7 @@ print "bar". The third will not trigger because it's a duplicate of the
first "foo".
.RE
.TP
.B $DefaultColor
.B $DefaultColor (STRING type)
This variable can be set to a string that has the form of three
space-separated numbers. Each number must be an integer from 0 to
255, or all three numbers must be -1. The default value of
@@ -2949,7 +3030,7 @@ Equivalent to \fByear(trigdate())\fR.
.B $Tt (read-only, TIME type)
Equivalent to \fBtrigtime()\fR.
.TP
.B $TimeSep
.B $TimeSep (STRING type)
This variable can be set only to ":" or ".". It holds the character
used to separate portions of a time when \fBRemind\fR prints a TIME or
DATETIME value.
@@ -3032,6 +3113,25 @@ For example, consider this sequence:
After those two lines have been executed, the variable \fBa\fR will be
set to "Tot ziens". See the section THE TRANSLATION TABLE for more
information.
.PP
In the body of a reminder, the substitution sequence
\fB%(\fItext\fR\fB)\fR is (almost) the equivalent of
\fB[_("\fItext\fR\fB")]\fR. Therefore, the following reminders are
almost equivalent:
.PP
.nf
REM MSG %(Goodbye)
REM MSG [_("Goodbye")]
.fi
.PP
The only difference is that if _("Goodbye") contains a \fB%\fR sign,
then that result will be run through the substitution filter, whereas
in the first reminder, it will not. That is because the second
\fBREM\fR command performs expression pasting followed by a
substitution filter pass, while the first one performs the translation
as part of the substitution filter (and does not make a second
substitution filter pass.)
.RE
.TP
.B abs(i_num)
@@ -3331,6 +3431,25 @@ Note that \fBeasterdate\fR computes the Western Easter. For the Orthodox
Easter date, see \fBorthodoxeaster\fR.
.RE
.TP
.B escape(s_string [,i_add_quotes])
Returns a \fBSTRING\fR that is the same as the input string, but with
all special characters backslashed-escaped. For example, the following
command:
.RS
.PP
.nf
set a escape("foo" + char(10) + "bar")
.fi
.PP
will set a to "foo\\nbar" where "\\n" is the literal sequence "\\" followed
by "n". This is useful if you want to compute a string in a pasted-in
expression that \fBRemind\fR will then parse as a quoted string again,
such as in a TRANSLATE command or an INFO clause.
.PP
If the optional \fIadd_quotes\fR argument is supplied and is non-zero, then
the return value from \fBescape\fR will include surrounding double-quotes.
.RE
.TP
.B evaltrig(s_trigger [,dq_start])
Evaluates \fItrigger\fR as if it were a REM or IFTRIG trigger specification
and returns the trigger date as a \fBDATE\fR (or as a \fBDATETIME\fR if
@@ -3490,12 +3609,13 @@ date part is used.) Note that any local \fBOMIT\fR or \fBOMITFUNC\fR
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 "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
in versions of \fBRemind\fR prior to 03.00.02.
Returns a \fBSTRING\fR naming the compiled-in language supported by
\fBRemind\fR. Remind used to support compiled-in support for other
languages, but now all localization is done at run-time. As such,
this function always returns "English". However, the expression
\fB_("LANGID")\fR returns the two-character ISO 639 language code
of any language pack in effect, assuming the language pack author has
written the localization correctly!
.TP
.B localtoutc(q_datetime)
Given a \fBDATETIME\fR object interpreted in the local time zone, return
@@ -3624,18 +3744,18 @@ In general, \fBmultitrig\fR works better with the Remind algorithm than
reminder is issued at the end of each quarter:
.PP
.nf
REM [multitrig("Mar 31", "Jun 30", "Sep 30", "Dec 31")] +7 MSG \\
%"End of [ord($Tm/3)] quarter%" is %b.
REM [multitrig("Mar 31", "Jun 30", "Sep 30", "Dec 31")] +7 MSG \\
%"End of [ord($Tm/3)] quarter%" is %b.
.fi
.PP
If you want the last working day of each quarter, you could use:
.PP
.nf
PUSH-OMIT-CONTEXT
OMIT Sat Sun
REM [multitrig("Mar ~1", "Jun ~1", "Sep ~1", "Dec ~1")] +7 MSG \\
%"Last working day of [ord($Tm/3)] quarter%" is %b.
POP-OMIT-CONTEXT
PUSH-OMIT-CONTEXT
OMIT Sat Sun
REM [multitrig("Mar ~1", "Jun ~1", "Sep ~1", "Dec ~1")] +7 MSG \\
%"Last working day of [ord($Tm/3)] quarter%" is %b.
POP-OMIT-CONTEXT
.fi
.PP
Note that unlike \fBevaltrig\fR, \fBmultitrig\fR always returns a \fBDATE\fR
@@ -3985,7 +4105,10 @@ output is not going to a TTY.
.TP
.B strlen(s_str)
Returns the length of \fIstr\fR. If the length of \fIstr\fR is too large
to represent as an integer, emits a "Number too high" error.
to represent as an integer, emits a "Number too high" error. Note that
\fBstrlen\fR returns the number of \fIbytes\fR in the string, not the
number of \fIcharacters\fR. These numbers are the same for ASCII strings,
but may be different for UTF-8 strings.
.TP
.B substr(s_str, i_start [,i_end])
Returns a \fBSTRING\fR consisting of all characters in \fIstr\fR from
@@ -4174,7 +4297,23 @@ whose value is the maximum of "yyyy-mm-dd" and today.
.B trigfrom()
Returns (as a \fBDATE\fR type) the \fBFROM\fR parameter of the last \fBREM\fR or
\fBIFTRIG\fR command. If there was no \fBFROM\fR parameter, returns the integer -1.
.TP
.B triginfo(s_header)
Returns a \fBSTRING\fR that is the INFO item associated with the header
\fIheader\fR. The header should \fInot\fR contain a colon. Header name
comparisons are case-insensitive.
.RS
.PP
For example, the following will assign "At home" to the variable a and
the empty string to variable b:
.PP
.nf
REM INFO "Location: At home" MSG test
SET a triginfo("location")
SET b triginfo("no_such_header")
.fi
.PP
.RE
.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
@@ -5222,55 +5361,6 @@ You can also define a function on the command line by using:
\fB\-i\fR\fIfunc\fR(\fIargs\fR)=\fIdefinition\fR
.PP
Be sure to protect special characters from shell interpretation.
.SH THE TRANSLATION TABLE
.PP
To assist with localizing reminder files, \fBRemind\fR maintains a
table of translations. This is simple a lookup table that maps one
string (the original string) to a new string (the translated string.)
When \fBRemind\fR starts executing, the translation table is empty.
.PP
To add a message to the translation table, use the \fBTRANSLATE\fR
command (which may be abbreviated to \fBTRANS\fR.) The \fBTRANSLATE\fR
command must be followed by two quoted strings, separated from each
other and from the command by whitespace. For example, a Dutch
language file might contain something like this:
.PP
.nf
TRANSLATE "New Moon" "Nieuwe maan"
TRANSLATE "First Quarter" "Eerste kwartier"
TRANSLATE "Full Moon" "Volle maan"
TRANSLATE "Last Quarter" "Laatste kwartier"
.fi
.PP
To actually use the translation table, make use of the \fB_\fR built-in
function, as follows:
.PP
.nf
REM NOQUEUE [moondatetime(0)] MSG [_("New Moon")] (%2)
REM NOQUEUE [moondatetime(1)] MSG [_("First Quarter")] (%2)
REM NOQUEUE [moondatetime(2)] MSG [_("Full Moon")] (%2)
REM NOQUEUE [moondatetime(3)] MSG [_("Last Quarter")] (%2)
.fi
.PP
By using \fBTRANSLATE\fR and \fB_\fR judiciously, you can make your
reminder files easy to translate.
.PP
\fBTRANSLATE\fR has three additional forms: If it is followed
by \fIone\fR quoted string instead of two, then \fBRemind\fR deletes the
translation table entry for that string. If it is followed by
the keyword \fBDUMP\fR, then \fBRemind\fR dumps all translation table entries
to standard output. And if it is followed by \fBCLEAR\fR, then
\fBRemind\fR deletes all of the translation table entries.
.PP
Note that if you \fBSET\fR various translation-related system
variables such as \fB$Monday\fR, \fB$December\fR, \fB$Ago\fR, etc,
then \fBRemind\fR \fIalso\fR makes a corresponding translation
table entry automatically. This is done for all of the translation-related
system variables \fIexcept for\fR \fB$Hplu\fR and \fB$Mplu\fR.
.PP
The converse does not apply; creating a translation table entry for
"December" does not automatically set \fB$December\fR.
.SH MORE ABOUT POSTSCRIPT
.PP
The \fBPS\fR and \fBPSFILE\fR reminders pass PostScript code directly
@@ -5588,22 +5678,13 @@ error messages. For an example of this, define the following:
.PP
.SH COMPILE-TIME 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, 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
selected language rather than for English.
.PP
Note that a non-English version of \fBRemind\fR will accept \fIonly\fR
English names of weekdays and months in a reminder script.
Remind used to support compile-time localization to other languages,
but no longer does. All localization is now done at run-time.
.PP
.SH RUN-TIME SUPPORT FOR OTHER LANGUAGES
.PP
\fBRemind\fR has run-time support for other languages, and it is
expected that compile-time support will be deprecated in favour of
run-time support.
\fBRemind\fR has run-time support for other languages, and
compile-time support has been removed in favour of run-time support.
.PP
A number of system variables let you translate various phrases
to other languages. These system variables are:
@@ -5721,6 +5802,127 @@ If you use a \fB%{name}\fR sequence and the function \fBsubst_\fIname\fR is
not defined or returns an error, then \fB%{name}\fR is replaced with the
empty string.
.PP
.SH THE TRANSLATION TABLE
.PP
To assist with localizing reminder files, \fBRemind\fR maintains a
table of translations. This is simple a lookup table that maps one
string (the original string) to a new string (the translated string.)
When \fBRemind\fR starts executing, the translation table is empty.
.PP
To add a message to the translation table, use the \fBTRANSLATE\fR
command (which may be abbreviated to \fBTRANS\fR.) The \fBTRANSLATE\fR
command must be followed by two quoted strings, separated from each
other and from the command by whitespace. For example, a Dutch
language file might contain something like this:
.PP
.nf
TRANSLATE "New Moon" "Nieuwe maan"
TRANSLATE "First Quarter" "Eerste kwartier"
TRANSLATE "Full Moon" "Volle maan"
TRANSLATE "Last Quarter" "Laatste kwartier"
.fi
.PP
To actually use the translation table, make use of the \fB_\fR built-in
function, as follows:
.PP
.nf
REM NOQUEUE [moondatetime(0)] MSG [_("New Moon")] (%2)
REM NOQUEUE [moondatetime(1)] MSG [_("First Quarter")] (%2)
REM NOQUEUE [moondatetime(2)] MSG [_("Full Moon")] (%2)
REM NOQUEUE [moondatetime(3)] MSG [_("Last Quarter")] (%2)
.fi
.PP
By using \fBTRANSLATE\fR and \fB_\fR judiciously, you can make your
reminder files easy to translate.
.PP
\fBTRANSLATE\fR has four additional forms: If it is followed
by \fIone\fR quoted string instead of two, then \fBRemind\fR deletes the
translation table entry for that string. If it is followed by
the keyword \fBDUMP\fR, then \fBRemind\fR dumps all translation table entries
to standard output. And if it is followed by \fBCLEAR\fR, then
\fBRemind\fR deletes all of the translation table entries.
.PP
The fourth form, \fBTRANSLATE GENERATE\fR, dumps all of the
strings that can be localized (as a series of TRANSLATE commands) to
standard output. Strings that are already localized are output
with their localization; strings that are not localized are
output as:
.PP
.nf
TRANSLATE "untranslated" ""
.nf
.PP
If you want to add a new language, you can obtain a skeleton translation
file by running:
.PP
.nf
echo "TRANSLATE GENERATE" | remind -h - > /tmp/skeleton.rem
.fi
.PP
If you have an existing language file that is missing some translations,
you can update it by running:
.PP
.nf
(echo INCLUDE mylang.rem; echo TRANSLATE GENERATE) | \\
remind -h - > /tmp/mylang-update.rem
.fi
.PP
and then editing \fBmylang-update.rem\fR to add in the missing translations.
.PP
If you have some reminder scripts that use the \fB_()\fR built-in function
or \fB%(...)\fR substitution sequence, you can generate a list of needed
TRANSLATE commands by running:
.PP
.nf
remind -q -n -dq myscript.rem 2>&1 | grep ^TRANSLATE | sort | uniq
.fi
.PP
Note that if you \fBSET\fR various translation-related system
variables such as \fB$Monday\fR, \fB$December\fR, \fB$Ago\fR, etc,
then \fBRemind\fR \fIalso\fR makes a corresponding translation
table entry automatically. This is done for all of the translation-related
system variables \fIexcept for\fR \fB$Hplu\fR and \fB$Mplu\fR.
.PP
The converse applies too; creating a translation table for
"December" automatically sets \fB$December\fR. And if you invoke
\fBTRANSLATE CLEAR\fR, then all translation-related system variables
are set to their default values as well.
.PP
The translation table always contains a special entry \fBLANGID\fR whose
default value is \fBen\fR. Translators are encouraged to add a \fBLANGID\fR
entry in their language files; the value should be the two-characters
ISO 639 language code.
.PP
For example, if you write a translation file for the Dutch language,
add this line:
.PP
.nf
TRANSLATE "LANGID" "nl"
.fi
.PP
Scripts can use \fB_("LANGID")\fR to query the translation language that is
in effect.
.PP
The \fB_()\fR function uses the following procedure to obtain the translation
for a string:
.RS
.TP
1
Look for an exact match. If found, return.
.TP
2
If the original string had an upper-case letter, search for the
all-lower-case equivalent. If found, make the first letter of the
result upper-case and return.
.TP
3
If the original string started with a lower-case letter, search
for an equivalent whose first letter is upper-case and the rest lower-case.
If found, make the first letter of the result lower-case and return.
.TP
4
No translation was found. Return the original string.
.RE
.SH LANGUAGE PACKS
.PP
\fBRemind\fR ships with a number of language packs, which are simply reminder
@@ -5735,14 +5937,14 @@ To use a language pack (in this example, de.rem), simply place this at
the top of your reminders file:
.PP
.nf
INCLUDE [$SysInclude]/lang/de.rem
SYSINCLUDE lang/de.rem
.fi
.PP
If you want \fBRemind\fR to try to find the language pack appropriate
for your locale settings, use:
.PP
.nf
INCLUDE [$SysInclude]/lang/auto.rem
SYSINCLUDE lang/auto.rem
.fi
.PP
You are encouraged to study the language packs to see how to translate
@@ -6254,16 +6456,15 @@ Do not hard-code the above directory in your reminder files. Instead,
use the value of the $SysInclude system variable.
.SH AUTHOR
.PP
Dianne Skoll <dianne@skoll.ca> wrote \fBRemind\fR. The moon code
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
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
and month/day names.
Dianne Skoll <dianne@skoll.ca> wrote \fBRemind\fR. The moon code 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 languages and their
translators are listed below. Languages marked "complete" support
error messages in that language; all others only support the
substitution filter mechanism and month/day names.
.PP
\fBGerman\fR --
Wolfgang Thronicke

View File

@@ -102,7 +102,10 @@ You can also specify advance notice, possibly repeating.
The sixth control specifies what \fBRemind\fR should do if a reminder
falls on a holiday or weekend.
Enter the body of the reminder into the \fBBody:\fR text entry.
Enter the body of the reminder into the \fBSummary:\fR text entry. If
you want, you can enter a location and longer description in the
\fBLocation:\fR and \fBDescription:\fR boxes. If you enter anything
here, they will be added as \fBINFO\fR items to the reminder.
To add the reminder to the reminder file, click \fBAdd to reminder file\fR.
To close the dialog without adding the reminder to the file, click
@@ -178,6 +181,10 @@ 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.
.PP
If a reminder has location or description \fBINFO\fR items, then
hovering over the reminder will pop up a window containing the
location and/or description information.
.SH ERRORS
@@ -413,6 +420,39 @@ like this:
The value of the \fBqueue\fR key is an array of JSON objects, each
representing a queued reminder.
.TP
TRANSLATE Any string goes here
Returns the translation of "Any string goes here" according to \fBRemind\fR's
translation table. Note that there must be exactly one space after
TRANSLATE and before the string you wish to translate. The JSON object
that results from "TRANSLATE New Moon" might look like this:
.nf
{"response":"translate","translation":{"New Moon":"Nieuwe maan"},"command":"TRANSLATE"}
.fi
As you see, the value of the \fBtranslation\fR key is an object whose
key is the original text and value is the translated text. A
front-end can use TRANSLATE do its own localization; for example,
TkRemind uses it to localize the moon phase popup window for the
SPECIAL MOON display.
.RS
.PP
If the argument to TRANSLATE is not in the translation table, then
\fBRemind\fR \fIwill not issue any response at all\fR to the TRANSLATE command.
.RE
.TP
TRANSLATE_DUMP
Returns the contents of the translation table. The JSON object looks
like this:
.nf
{"response":"translate_dump","table":{...},"command":"TRANSLATE_DUMP"}
.fi
The value of the \fBtable\fR key is a dictionary of original-to-translated
strings.
.TP
DEL \fIqid\fR
Delete the reminder with queue-id \fIqid\fR from the queue.
@@ -479,7 +519,7 @@ asynchronous status messages.
.SH AUTHOR
TkRemind was written by Dianne Skoll <dianne@skoll.ca>
\fBTkRemind\fR is Copyright 1996-2024 by Dianne Skoll.
\fBTkRemind\fR is Copyright (C) 1996-2025 by Dianne Skoll.
.SH FILES

View File

@@ -10,6 +10,8 @@ use Encode;
my %Options;
my $Translations = {};
my $rem2html_version = '@VERSION@';
my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mondayfirst, $weeks,
@@ -18,18 +20,20 @@ my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mond
my $TIDY_PROGNAME = $0;
$TIDY_PROGNAME =~ s|^.*/||;
# rem2html -- convert the output of "remind -pp" to HTML
# rem2html -- convert the output of "remind -pp" or "remind -ppp" to HTML
=head1 NAME
rem2html - Convert the output of "remind -pp" to HTML
rem2html - Convert the output of "remind -pp" or "remind -ppp" to HTML
=head1 SYNOPSIS
remind -ppp [remind_options] file | rem2html [options]
remind -pp [remind_options] file | rem2html [options]
You can also use the old interchange format as below, but the -pp
version is preferred.
or -ppp versions are preferred.
remind -p [remind_options] file | rem2html [options]
@@ -153,9 +157,10 @@ sub usage
$exit_status = 1;
}
print STDERR <<"EOM";
$TIDY_PROGNAME: Produce an HTML calendar from the output of "remind -pp"
$TIDY_PROGNAME: Produce an HTML calendar from the output of "remind -pp[p]"
Usage: remind -pp [remind_options] file | rem2html [options]
or: remind -ppp [remind_options] file | rem2html [options]
Options:
@@ -265,6 +270,31 @@ sub end_output
print("</body>\n</html>\n");
}
sub slurp_translations
{
my $line;
$line = <STDIN>;
chomp $line;
eval {
if ($Options{utf8}) {
$Translations = decode_json(encode('UTF-8', $line, Encode::FB_DEFAULT));
} else {
$Translations = decode_json($line);
}
};
if ($@) {
$Translations = {};
}
}
sub t
{
my ($str) = @_;
return $Translations->{$str} if exists($Translations->{$str});
return $str;
}
sub parse_input
{
undef $days;
@@ -275,8 +305,15 @@ sub parse_input
my $found_data = 0;
while(<STDIN>) {
chomp;
last if /^\# rem2ps2? begin$/;
chomp;
if ($_ eq '[') {
return parse_input_ppp();
}
if (/# translations/) {
slurp_translations();
next;
}
last if /^\# rem2ps2? begin$/;
}
my $line;
@@ -387,6 +424,159 @@ sub parse_input
return $found_data;
}
sub parse_input_ppp
{
my $json = "[\n";
my $curlies = 0;
my $did_a_calendar = 0;
while(<STDIN>) {
$json .= $_;
$curlies++ if ($_ eq "{\n");
$curlies-- if ($_ eq "}\n");
$curlies-- if ($_ eq "},\n");
if ($_ eq "]\n" && !$curlies) {
my $array;
eval {
if ($Options{utf8}) {
$array = decode_json(encode('UTF-8', $json, Encode::FB_DEFAULT));
} else {
$array = decode_json($json);
}
};
if (!$array) {
print STDERR "Could not decode JSON.\n";
exit(1);
}
if (!$did_a_calendar) {
start_output();
$did_a_calendar = 1;
}
if (exists($array->[0]{caltype}) &&
$array->[0]{caltype} eq 'weekly') {
emit_ppp_calendars($array, 'weekly');
} else {
emit_ppp_calendars($array, 'monthly');
}
$json = '';
}
}
if (!$did_a_calendar) {
print STDERR "$TIDY_PROGNAME: Could not find any calendar data on STDIN.\n";
exit(1);
} else {
end_output();
exit(0);
}
}
sub emit_ppp_calendars
{
my ($array, $type) = @_;
foreach my $cal (@$array) {
emit_one_ppp_calendar($cal, $type);
}
}
sub emit_one_ppp_calendar
{
my ($c, $type) = @_;
undef $days;
undef $shades;
undef $moons;
undef $classes;
undef $weeks;
my $dates_to_day_index;
my $cols_to_date_info;
if (exists($c->{translations})) {
$Translations = $c->{translations};
}
if ($type eq 'monthly') {
$Month = $c->{monthname};
$Year = $c->{year};
$Numdays = $c->{daysinmonth};
$Firstwkday = $c->{firstwkday};
$Mondayfirst = $c->{mondayfirst};
@Daynames = @{$c->{daynames}};
$Prevmon = $c->{prevmonthname};
$Prevlen = $c->{daysinprevmonth};
$Nextmon = $c->{nextmonthname};
$Nextlen = $c->{daysinnextmonth};
} else {
my $idx = 0;
$Numdays = 7;
foreach my $date (@{$c->{dates}}) {
$Daynames[$idx] = $date->{dayname};
$dates_to_day_index->{$date->{date}} = $idx;
$cols_to_date_info->[$idx] = $date;
$idx++;
}
}
my $class;
if ($Options{nostyle}) {
$class = '';
} else {
$class = ' class="rem-entry"';
}
foreach my $obj (@{$c->{entries}}) {
next unless ($obj->{date} =~ /^(\d+)-(\d+)-(\d+)$/);
my $y = $1;
my $m = $2;
my $d = $3;
my $col;
if ($type eq 'weekly') {
$col = $dates_to_day_index->{$obj->{date}};
} else {
$col = $d;
$col =~ s/^0+//;
}
my $special = $obj->{passthru} || '*';
my $tag = $obj->{tags} || '*';
my $duration = $obj->{duration} || '*';
my $time = $obj->{time} || '*';
my $body = $obj->{body};
$special = uc($special);
if ($special eq 'HTML') {
push(@{$days->[$col]}, $body);
} elsif ($special eq 'HTMLCLASS') {
$classes->[$col] = $body;
} elsif ($special eq 'WEEK') {
$body =~ s/^\s+//;
$body =~ s/\s+$//;
$weeks->{$col} = $body;
} elsif ($special eq 'MOON') {
if ($body =~ /(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) {
my ($phase, $moonsize, $fontsize, $msg) = ($1, $2, $3, $4);
$moons->[$col]->{'phase'} = $phase;
$moons->[$col]->{'msg'} = $msg;
} elsif ($body =~ /(\S+)/) {
$moons->[$col]->{'phase'} = $1;
$moons->[$col]->{'msg'} = '';
}
} elsif ($special eq 'SHADE') {
if ($body =~ /(\d+)\s+(\d+)\s+(\d+)/) {
$shades->[$col] = sprintf("#%02X%02X%02X",
($1 % 256), ($2 % 256), ($3 % 256));
} elsif ($body =~ /(\d+)/) {
$shades->[$col] = sprintf("#%02X%02X%02X",
($1 % 256), ($1 % 256), ($1 % 256));
}
} elsif ($special eq 'COLOR' || $special eq 'COLOUR') {
if ($body =~ /(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/s) {
my($r, $g, $b, $text) = ($1, $2, $3, $4);
my $color = sprintf("style=\"color: #%02X%02X%02X;\"",
$r % 256, $g % 256, $b % 256);
push(@{$days->[$col]}, "<p$class $color>" . fix_whitespace(escape_html($text)) . '</p>');
}
} elsif ($special eq '*') {
push(@{$days->[$col]}, "<p$class>" . fix_whitespace(escape_html($body)) . '</p>');
}
}
output_calendar($type, $cols_to_date_info);
}
sub fix_whitespace
{
my ($text) = @_;
@@ -492,23 +682,33 @@ sub small_calendar
sub output_calendar
{
# Which column is 1st of month in?
my $first_col = $Firstwkday;
if ($Mondayfirst) {
$first_col--;
if ($first_col < 0) {
$first_col = 6;
}
}
my ($type, $date_info) = @_;
# Last column
my $last_col = ($first_col + $Numdays - 1) % 7;
my ($first_col, $last_col, $number_of_rows);
# Figure out how many rows
my $number_of_rows = int(($first_col + $Numdays ) / 7 + 0.999);
if ($type eq 'monthly') {
$first_col = $Firstwkday;
if ($Mondayfirst) {
$first_col--;
if ($first_col < 0) {
$first_col = 6;
}
}
# Add a row for small calendars if necessary
if ($first_col == 0 && $last_col == 6) {
# Last column
$last_col = ($first_col + $Numdays - 1) % 7;
# Figure out how many rows
$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++;
}
} else {
$first_col = 0;
$last_col = 6;
$number_of_rows = 1;
}
# Start the table
@@ -519,22 +719,36 @@ sub output_calendar
print '<tr>';
$class = ' width="14%"';
} else {
print '<table class="rem-cal"><caption class="rem-cal-caption">' .
$Month . ' ' . $Year . '</caption>' . "\n";
if ($type eq 'monthly') {
print '<table class="rem-cal"><caption class="rem-cal-caption">' .
$Month . ' ' . $Year . '</caption>' . "\n";
} else {
print '<table class="rem-cal">' . "\n";
}
print '<tr class="rem-cal-hdr-row">';
$class = ' class="rem-cal-hdr"';
}
if (!$Mondayfirst) {
print "<th$class>" . $Daynames[0] . '</th>';
if ($type eq 'monthly') {
if (!$Mondayfirst) {
print "<th$class>" . $Daynames[0] . '</th>';
}
for (my $i=1; $i<7; $i++) {
print "<th$class>" . $Daynames[$i] . '</th>';
}
if ($Mondayfirst) {
print "<th$class>" . $Daynames[0] . '</th>';
}
} else {
for (my $i=0; $i<7; $i++) {
my $inf = $date_info->[$i];
print "<th$class>" . $inf->{dayname} . "<br>" .
$inf->{day} . '&nbsp;' .
$inf->{month} . '&nbsp;' .
$inf->{year} . '</th>';
}
}
for (my $i=1; $i<7; $i++) {
print "<th$class>" . $Daynames[$i] . '</th>';
}
if ($Mondayfirst) {
print "<th$class>" . $Daynames[0] . '</th>';
}
print "</tr>\n";
print "</tr>\n";
# Start the calendar rows
my $col = 0;
if ($Options{nostyle}) {
@@ -542,16 +756,18 @@ sub output_calendar
} else {
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
}
if ($first_col > 0) {
small_calendar($Prevmon, $Prevlen, $Options{backurl},
($Firstwkday - $Prevlen + 35) % 7);
$col++;
}
if ($type eq 'monthly') {
if ($first_col > 0) {
small_calendar($Prevmon, $Prevlen, $Options{backurl},
($Firstwkday - $Prevlen + 35) % 7);
$col++;
}
if ($last_col == 6 && $first_col > 0) {
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
($Firstwkday + $Numdays) % 7);
$col++;
if ($last_col == 6 && $first_col > 0) {
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
($Firstwkday + $Numdays) % 7);
$col++;
}
}
if ($Options{nostyle}) {
$class = ' width="14%"';
@@ -564,7 +780,7 @@ sub output_calendar
}
for (my $day=1; $day<=$Numdays; $day++) {
draw_day_cell($day, $number_of_rows);
draw_day_cell($day, $number_of_rows, $type);
$col++;
if ($col == 7) {
$col = 0;
@@ -579,32 +795,33 @@ sub output_calendar
}
}
if ($col) {
while ($col < 7) {
if ($col == 5) {
if ($first_col == 0) {
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},
($Firstwkday + $Numdays) % 7);
} else {
print("<td$class>&nbsp;</td>\n");
}
$col++;
}
print "</tr>\n";
}
if ($type eq 'monthly') {
if ($col) {
while ($col < 7) {
if ($col == 5) {
if ($first_col == 0) {
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},
($Firstwkday + $Numdays) % 7);
} else {
print("<td$class>&nbsp;</td>\n");
}
$col++;
}
print "</tr>\n";
}
# Add a row for small calendars if they were not yet done!
if ($first_col == 0 && $last_col == 6) {
# Add a row for small calendars if they were not yet done!
if ($first_col == 0 && $last_col == 6) {
if ($Options{nostyle}) {
print "<tr>\n";
print "<tr>\n";
} else {
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n";
}
small_calendar($Prevmon, $Prevlen, $Options{backurl},
($Firstwkday - $Prevlen + 35) % 7);
@@ -614,14 +831,18 @@ sub output_calendar
small_calendar($Nextmon, $Nextlen, $Options{forwurl},
($Firstwkday + $Numdays) % 7);
print("</tr>\n");
}
}
# End the table
print "</table>\n";
if ($type eq 'weekly') {
print "&nbsp;<br />\n";
}
}
sub draw_day_cell
{
my($day, $number_of_rows) = @_;
my($day, $number_of_rows, $type) = @_;
my $shade = $shades->[$day];
my $week = '';
if (exists($weeks->{$day})) {
@@ -659,7 +880,7 @@ sub draw_day_cell
} else {
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAC6SURBVDiNpdNNbsIwFATgL0HKolchHKBX6yFaBOEyoPYUabvOIVKJRaCL2JX5TRNGGvnJ8ozGz89cYoElPvET+BX2yivn/1Bggw5HHMKa1h2qcPZC/JEIhvh+brIZIY6sorhMYo9hh3KGFzzfa84NZNjDt9OG/ZcH1BlaPE1IAG0+URhxzNGESKPFaHJs9Q0Ziww7HnvGeXSrJhis0jiFfjwnj3I0WRv+TKtr4hQl3lDrZ6QN9Wt654hfWfGDmBpUwDkAAAAASUVORK5CYII=';
}
$title = 'New Moon';
$title = escape_html(t('New Moon'));
$alt = 'new';
} elsif ($phase == 1) {
if ($Options{pngs}) {
@@ -667,7 +888,7 @@ sub draw_day_cell
} else {
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADfSURBVDiNndM9TsNAFATgzy5yjZSAE85JBygETgENUPF3iBCitHAFQkcIhZ/Ryn9gRlrZmp2Z3ef3TBOHOMULPrDBMrhpi/4HI5xjix2+4nmJRbx/Yh7ahvkpRPVV4QDXwT3UQy46zGkAZDgK/iytefvHgCrkJsqZUH6cLnNbABSxd5Jhhf1IbkMXv8Qux7hH1Ic1xvk/jBWy6gavumvtwx7ectwZXkKh7MA95XgObeOtpI2U4zl0kGbpxgiPvwQUcXLrKFchc82f6Ur0PK49azOnmOI4TBu84zm4SV38DeIVYkrYJyNbAAAAAElFTkSuQmCC';
}
$title = 'First Quarter';
$title = escape_html(t('First Quarter'));
$alt = '1st';
} elsif ($phase == 2) {
if ($Options{pngs}) {
@@ -676,7 +897,7 @@ sub draw_day_cell
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADlSURBVDiNrdNBUsJAEAXQlyw4hq4hwWPqTixET6ELkZ16CcAq7oFLqXExjaYgQVNlV/Viev7/6XT/4TjGuME7PiLXUatb8N8xwB12SFjiIXIZtU/MAntEfgvQE4YtHxhiHpjXQ5H7uLhEcaLLAleBvd0Xx9Ha/BdyU+Q5OBV5OKmj7a4YBWdSyNPe4aKHAHkzqcQZNj3JgnNexqE8heyIAulffuFF3kTfIVbBVeu/xoXGGsn2TLJJ/mqkafNiINszySYZdbS90GHlvcgsWktY4TFy7ecxTdvIzahxHQLbyFXUqkPwF2ASRNYgB/PXAAAAAElFTkSuQmCC';
}
$alt = 'full';
$title = 'Full Moon';
$title = escape_html(t('Full Moon'));
} else {
if ($Options{pngs}) {
$img = smoosh($Options{imgbase}, 'lastquarter.png');
@@ -684,7 +905,7 @@ sub draw_day_cell
$img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADmSURBVDiNndMxTsNAEIXhzy5yCyQ6FAgcE7oQheQWUAAl5BIkREoZrgB0GFNkHBl7bURGsryaee/3jHeXdpxjghU+8InXyI0S+n0MMEeBEi+4jfV3vAvMQtsyL0J0j2GtViaeRRMyj8IlsgY8BSijE2Kur/hy09wHKMJrEolhwtwHKDHOsI4OLnoAXfl1jiNsOkR9keE4P8D4q4scbzg5xIxtjie709f1E7siC+9+Gx/8fxvPKtEsklcJSBdgWhcN8ByFR5z+AWgd5QpyE+OUWOJO+zJNU+Z6jHAdgHe7K73CuD5zFT9nCmRDIssCaAAAAABJRU5ErkJggg==';
}
$alt = 'last';
$title = 'Last Quarter';
$title = escape_html(t('Last Quarter'));
}
if ($Options{nostyle}) {
print("<div style=\"float: left\"><img border=\"0\" width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">$msg</div>");
@@ -693,11 +914,20 @@ sub draw_day_cell
}
}
if ($Options{nostyle}) {
print "<div style=\"float: right\">$day$week</div>\n";
print "<p>&nbsp;</p>\n";
if ($type eq 'monthly') {
if ($Options{nostyle}) {
print "<div style=\"float: right\">$day$week</div>\n";
print "<p>&nbsp;</p>\n";
} else {
print "<div class=\"rem-daynumber\">$day$week</div>\n";
}
} else {
print "<div class=\"rem-daynumber\">$day$week</div>\n";
if ($Options{nostyle}) {
print "<div style=\"float: right\">$week</div>\n";
print "<p>&nbsp;</p>\n";
} else {
print "<div class=\"rem-daynumber\">$week</div>\n";
}
}
if ($days->[$day]) {
print(join("\n", @{$days->[$day]}));
@@ -737,7 +967,7 @@ while(1) {
last if (!parse_input());
start_output() unless $found_something;
$found_something = 1;
output_calendar();
output_calendar('monthly', undef);
}
if ($found_something) {
end_output();

View File

@@ -64,6 +64,8 @@ my $settings = {
ps => 0,
eps => 0,
verbose => 0,
weeks_per_page => 1,
};
my $me = $0;
@@ -81,17 +83,18 @@ Usage: remind -pp [options] filename | $me [options] > out.pdf
Options:
--landscape, -l Print in landscape orientation
--small-calendars=N Choose location for small calendars
--small-calendars=N Location for small calendars (monthly calendars only)
--svg Output SVG instead of PDF
--ps Output PostScript instead of PDF
--eps Output encapsulated PostScript instead of PDF
-cN Synonym for --small-calendars=N
--left-numbers, -x Print day numbers on the left
--fill-page, -e Fill the entire page
--left-numbers, -x Print day numbers on the left (monthly calendars only)
--fill-page, -e Fill the entire page (monthly calendars only)
--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
--wrap, -y Make calendar fit in at most 5 rows
--wrap, -y Make calendar fit in 5 rows (monthly calendars only)
--weeks-per-page=N, -pN Number of weeks per page (weekly calendars only)
--title-font=FONT Specify font for calendar title
--header-font=FONT Specify font for weekday names
--daynum-font=FONT Specify font for day numbers
@@ -121,6 +124,7 @@ my $ret = GetOptions('landscape|l' => \$settings->{landscape},
'ps' => \$settings->{ps},
'eps' => \$settings->{eps},
'fill-page|e' => \$settings->{fill_entire_page},
'weeks-per-page|p=i' => \$settings->{weeks_per_page},
'media|m=s' => \$settings->{media},
'width|w=i' => \$settings->{width},
'wrap|y' => \$settings->{wrap_calendar},
@@ -153,6 +157,12 @@ if ($help) {
exit(0);
}
if ($settings->{weeks_per_page} < 1) {
$settings->{weeks_per_page} = 1;}
elsif ($settings->{weeks_per_page} > 4) {
$settings->{weeks_per_page} = 4;
}
if ($settings->{width} <= 0 ||
$settings->{height} <= 0) {
my $size = $media_to_size->{ucfirst($settings->{media})};
@@ -247,6 +257,7 @@ if ($settings->{ps} && $settings->{landscape}) {
}
my $warned = 0;
my $index = 0;
while(1) {
if ($settings->{ps}) {
$surface->dsc_begin_page_setup();
@@ -267,14 +278,8 @@ while(1) {
}
last;
}
if (($settings->{eps} || $settings->{svg}) && $done_one) {
if (!$warned) {
print STDERR "WARNING: --eps and --svg can only output one page; ignoring subsequent\nmonths in a multi-month calendar.\n";
$warned = 1;
}
next;
}
$obj->render($cr, $settings);
$index++;
$obj->render($cr, $settings, $index, -1);
$done_one = 1;
}
@@ -392,7 +397,7 @@ month. Possible values for I<n> are:
=item Z<>0
Do not draw any small calendares
Do not draw any small calendars
=item Z<>1
@@ -521,6 +526,11 @@ first row of the calendar, and adjust the small calendar positions
as needed. This results in a calendar that only requires 5 rows, but
with the last day or two appearing in the I<first> row.
=item --weeks-per-page=I<n>, -pI<n>.
This option is only used for weekly calendars. I<n> is the number of weeks
to print per page; it is an integer that can range from 1 to 4.
=item --verbose, -v
Print (on STDERR) the name of the month and year for each month that
@@ -563,6 +573,12 @@ 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 WEEKLY CALENDARS
B<rem2pdf> will produce weekly calendars if you invoke B<remind> with the
B<-p+> option. the B<--weeks-per-page> option specifies how many
weeks' worth of reminders to print per page, and can range from 1 to 4.
=head1 ABSOLUTELY-POSITIONED TEXT
If your B<PANGO> special reminder starts with C<@I<x>,I<y>> where I<x>

View File

@@ -62,6 +62,9 @@ sub create_from_hash
{
my ($class, $hash, $specials_accepted) = @_;
if (exists($hash->{caltype}) && ($hash->{caltype} eq 'weekly')) {
return Remind::PDF::Weekly->create_from_hash($hash, $specials_accepted);
}
bless $hash, $class;
my $filtered_entries = [];
@@ -463,8 +466,16 @@ C<rem2pdf> for the contents of C<$settings>
=cut
sub render
{
my ($self, $cr, $settings) = @_;
my ($self, $cr, $settings, $index, $total) = @_;
if ($settings->{svg} || $settings->{eps}) {
if ($index > 1) {
if ($index == 2) {
print STDERR "WARNING: --svg/--eps can only output one page; ignoring subsequent\nmonths in a multi-month calendar.\n";
}
return;
}
}
$self->setup_daymap($settings);
$self->{horiz_lines} = [];
$cr->set_line_cap('square');
@@ -525,7 +536,7 @@ sub render
}
if ($settings->{verbose}) {
print STDERR "remdp2f: Rendered " . $self->{monthname} . ' ' . $self->{year} . "\n";
print STDERR "rem2pdf: Rendered " . $self->{monthname} . ' ' . $self->{year} . "\n";
}
# Done this page
$cr->show_page();
@@ -1008,20 +1019,260 @@ as were read from the C<remind -ppp> stream
sub render
{
my ($self, $cr, $settings) = @_;
my $done = 0;
my $warned = 0;
my $index = 0;
my $total = scalar(@{$self->{entries}});
foreach my $e (@{$self->{entries}}) {
if ($settings->{svg} && $done) {
if (!$warned) {
print STDERR "WARNING: --svg can only output one page; ignoring subsequent\nmonths in a multi-month calendar.\n";
$warned = 1;
$index++;
$e->render($cr, $settings, $index, $total);
}
}
package Remind::PDF::Weekly;
use base qw(Remind::PDF);
=head1 NAME
Remind::PDF::Weekly - render a weekly calendar
=cut
sub render
{
my ($self, $cr, $settings, $index, $total) = @_;
if ($settings->{svg} || $settings->{eps}) {
if ($index > $settings->{weeks_per_page}) {
if ($index == $settings->{weeks_per_page}+1) {
print STDERR "WARNING: --svg/--eps can only output one page; ignoring subsequent pages.\n";
}
return;
}
}
$settings->{numbers_on_left} = 1;
# Set up bounding box
if ($settings->{weeks_per_page} == 1) {
$self->{bounding_box} = [
$settings->{margin_left},
$settings->{margin_top},
$settings->{width} - $settings->{margin_right},
$settings->{height} - $settings->{margin_bottom}]
} else {
my $total_height = $settings->{height} - $settings->{margin_top} - $settings->{margin_bottom};
my $week_height = $total_height / $settings->{weeks_per_page};
my $top_offset = (($index-1) % $settings->{weeks_per_page}) * $week_height;
my $bot_offset = $top_offset + $week_height;
$self->{bounding_box} =
$self->{bounding_box} = [
$settings->{margin_left},
$settings->{margin_top} + $top_offset,
$settings->{width} - $settings->{margin_right},
$settings->{margin_top} + $bot_offset];
if ($index != 1) {
$self->{bounding_box}[1] += 0.25 * $settings->{margin_top};
}
if ($index != $settings->{weeks_per_page}) {
$self->{bounding_box}[3] -= 0.25 * $settings->{margin_top};
}
}
$self->draw_headings($cr, $settings);
for (my $i=0; $i<7; $i++) {
$self->draw_entries($cr, $settings, $i);
}
$self->draw_lines($cr, $settings);
if ($index == $total || ($index % $settings->{weeks_per_page}) == 0) {
$cr->show_page();
}
if ($settings->{verbose}) {
print STDERR "rem2pdf: Rendered " . $self->{dates}->[0]->{date} . " to " . $self->{dates}->[6]->{date} . "\n";
}
}
sub draw_headings
{
my ($self, $cr, $settings) = @_;
my $ymax = 0;
my $cell = ($settings->{width} - $settings->{margin_left} - $settings->{margin_right})/7;
for (my $i=0; $i<7; $i++) {
my $date = $self->{dates}[$i];
my $month = $date->{month};
my $year = $date->{year};
my $day = $date->{day};
my $dayname = $date->{dayname};
my $layout = Pango::Cairo::create_layout($cr);
$layout->set_text(Encode::decode('UTF-8', $dayname));
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, $self->{bounding_box}[1]);
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
$layout = Pango::Cairo::create_layout($cr);
$layout->set_text(Encode::decode('UTF-8', $day . " " . $month . " " . $year));
my $es = $settings->{entry_size};
if ($es > 8) {
$es = 8;
}
$desc = Pango::FontDescription->from_string($settings->{entry_font} . ' ' . $es . 'px');
$layout->set_font_description($desc);
my ($wid2, $h2) = $layout->get_pixel_size();
$cr->save;
$cr->move_to($settings->{margin_left} + $i * $cell + $cell/2 - $wid2/2, $self->{bounding_box}[1] + $h);
Pango::Cairo::show_layout($cr, $layout);
$cr->restore();
if ($h + $h2 > $ymax) {
$ymax = $h + $h2;
}
}
$self->{heading_bottom_y} = $ymax + $self->{bounding_box}[1];
}
sub draw_entries
{
my ($self, $cr, $settings, $i) = @_;
my $cell = ($settings->{width} - $settings->{margin_left} - $settings->{margin_right})/7;
# Coordinates of box from line-to-line
my $l2l_box = [$i * $cell + $settings->{margin_left},
$self->{heading_bottom_y},
($i+1) * $cell + $settings->{margin_left},
$self->{bounding_box}[3]];
# Coordinates of drawing-space box
my $box = [$l2l_box->[0] + $settings->{border_size},
$l2l_box->[1] + $settings->{border_size},
$l2l_box->[2] - $settings->{border_size},
$l2l_box->[3] - $settings->{border_size}];
$self->{l2l_box} = $l2l_box;
$self->{box} = $box;
# Do shading, if any
my $shade = $self->find_last_special('shade', $self->{entries}->[$i]);
if ($shade) {
$cr->save;
$cr->set_source_rgb($shade->{r} / 255,
$shade->{g} / 255,
$shade->{b} / 255);
$cr->rectangle($l2l_box->[0], $l2l_box->[1],
$l2l_box->[2] - $l2l_box->[0],
$l2l_box->[3] - $l2l_box->[1]);
$cr->fill();
$cr->restore;
}
# Get the "day number" size to leave room for moon and week specials
my $layout = Pango::Cairo::create_layout($cr);
$layout->set_text("31");
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();
my $so_far = $box->[1] + $h + $settings->{border_size};
my $box_height = $box->[3] - $box->[1];
my $done = 0;
foreach my $entry (@{$self->{entries}->[$i]}) {
# 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, $box->[1], $i, $i, $box_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, $box->[1], $i, $i, $box_height);
next;
}
# Shade is done already
if ($entry->isa('Remind::PDF::Entry::shade')) {
next;
}
if ($done) {
$so_far += $settings->{border_size};
}
$done = 1;
$e->render($cr, $settings);
my $h2 = $entry->render($self, $cr, $settings, $so_far, $i, $i, $box_height);
$so_far += $h2;
}
}
sub col_box_coordinates
{
my ($self, $so_far, $col, $height, $settings) = @_;
return (@{$self->{l2l_box}});
}
sub draw_lines
{
my ($self, $cr, $settings) = @_;
# Top horizonal line
$cr->move_to($self->{bounding_box}[0], $self->{bounding_box}[1]);
$cr->line_to($self->{bounding_box}[2], $self->{bounding_box}[1]);
$cr->stroke();
# Horizontal line below headings
$cr->move_to($self->{bounding_box}[0], $self->{heading_bottom_y});
$cr->line_to($self->{bounding_box}[2], $self->{heading_bottom_y});
$cr->stroke();
# Bottom horizontal line
$cr->move_to($self->{bounding_box}[0], $self->{bounding_box}[3]);
$cr->line_to($self->{bounding_box}[2], $self->{bounding_box}[3]);
$cr->stroke();
# Vertical lines
my $w = ($settings->{width} - $settings->{margin_left} - $settings->{margin_right})/7;
for (my $i=0; $i<=7; $i++) {
my $x = $settings->{margin_left} + ($i * $w);
$cr->move_to($x, $self->{bounding_box}[1]);
$cr->line_to($x, $self->{bounding_box}[3]);
$cr->stroke();
}
}
sub create_from_hash
{
my ($class, $hash, $specials_accepted) = @_;
bless $hash, $class;
my $filtered_entries = [];
my $date_to_index;
for (my $i=0; $i<7; $i++) {
$date_to_index->{$hash->{dates}[$i]->{date}} = $i;
}
for (my $i=0; $i<7; $i++) {
$filtered_entries->[$i] = [];
}
foreach my $e (@{$hash->{entries}}) {
if ($hash->accept_special($e, $specials_accepted)) {
my $index = $date_to_index->{$e->{date}};
push(@{$filtered_entries->[$index]}, Remind::PDF::Entry->new_from_hash($e));
}
}
$hash->{entries} = $filtered_entries;
return $hash;
}
1;

View File

@@ -8,7 +8,7 @@
# A cheesy graphical front/back end for Remind using Tcl/Tk
#
# This file is part of REMIND.
# Copyright (C) 1992-2024 Dianne Skoll
# Copyright (C) 1992-2025 Dianne Skoll
#
#--------------------------------------------------------------
@@ -30,6 +30,8 @@ catch {
set Hostname [exec hostname]
}
set Translations [dict create]
global env
set HOME $env(HOME)
@@ -278,6 +280,9 @@ set AppendFile $ReminderFile
# Array of tags -> JSON dicts
array unset TagToObj
# Array of __syn__ tags -> JSON dicts
array unset SynToObj
set SetFontsWorked 0
#---------------- DON'T CHANGE STUFF BELOW HERE ------------------
@@ -696,6 +701,21 @@ proc DoQueue {} {
flush $DaemonFile
}
proc DoTranslate {} {
global DaemonFile
global Translations
# Clear out any existing translations
set Translations [dict create]
# Get just the translations we can use
puts $DaemonFile "TRANSLATE New Moon"
puts $DaemonFile "TRANSLATE Full Moon"
puts $DaemonFile "TRANSLATE First Quarter"
puts $DaemonFile "TRANSLATE Last Quarter"
flush $DaemonFile
}
#---------------------------------------------------------------------------
# CreateCalWindow -- create the calendar window.
# Arguments:
@@ -703,6 +723,7 @@ proc DoQueue {} {
#---------------------------------------------------------------------------
proc CreateCalWindow { dayNames } {
global Option
frame .h -background $Option(LineColor)
label .h.title -text "" -justify center -pady 2 -bd 0 -relief flat -font HeadingFont -background $Option(WinBackground) -foreground $Option(LabelColor)
pack .h.title -side top -fill x -pady 1 -padx 1
@@ -780,7 +801,7 @@ proc EditOptions {} {
pack $w.f -side top -expand 1 -fill both
pack $w.b -side top -expand 0 -fill x
label $w.ver -text "TkRemind version @VERSION@ on Tcl/Tk version [info tclversion] with Remind version $ver"
label $w.ver -text "TkRemind version @VERSION@ on Tcl/Tk version [info patchlevel] with Remind version $ver"
pack $w.ver -in $w.f -side top -expand 0 -fill x
# Start iconified
checkbutton $w.startIconified -text "Start up Iconified" \
@@ -1120,9 +1141,10 @@ proc ConfigureCalWindow { month year firstDay numDays } {
proc FillCalWindow {} {
set FileName ""
set LineNo 0
global DayNames CurYear CurMonth MonthNames CommandLine Option TagToObj RemindErrors MondayFirst
global DayNames CurYear CurMonth MonthNames CommandLine Option TagToObj SynToObj RemindErrors MondayFirst
array unset TagToObj
array unset SynToObj
Status "Firing off Remind..."
set_button_to_queue
@@ -1212,7 +1234,7 @@ proc FillCalWindow {} {
set day [string trimleft $day 0]
set n [expr $day+$offset]
set month [string trimleft $month 0]
set extratags ""
set extratags {}
switch -nocase -- $type {
"WEEK" {
set stuff [string trimleft $stuff]
@@ -1251,9 +1273,9 @@ proc FillCalWindow {} {
set b 0
}
set color [format "%02X%02X%02X" $r $g $b]
set extratags "clr$color"
lappend extratags "clr$color"
.cal.t$n configure -state normal
.cal.t$n tag configure $extratags -foreground "#$color"
.cal.t$n tag configure "clr$color" -foreground "#$color"
.cal.t$n configure -state disabled -takefocus 0
set stuff $stuff
set type "COLOR"
@@ -1270,18 +1292,27 @@ proc FillCalWindow {} {
set stuff [regsub -all {\n[ \t]} $stuff "\n"]
set stuff [regsub -all {\n+} $stuff "\n"]
if {[regexp {__syn__([0-9a-f]+)} $tag syntag]} {
set SynToObj($syntag) $obj
lappend extratags $syntag
.cal.t$n tag bind $syntag <Enter> [list details_enter .cal.t$n]
.cal.t$n tag bind $syntag <Leave> [list details_leave .cal.t$n]
} else {
set syntag ""
}
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
.cal.t$n insert end [string trim $stuff] [concat REM TAGGED "TKTAG$tagno" "date_$date" $extratags $fntag]
.cal.t$n tag bind "TKTAG$tagno" <Enter> [list TaggedEnter .cal.t$n]
.cal.t$n tag bind "TKTAG$tagno" <Leave> [list TaggedLeave .cal.t$n]
set TagToObj($all) $obj
} else {
if {"$fntag" == "x" } {
.cal.t$n insert end [string trim $stuff] [list REM $extratags]
.cal.t$n insert end [string trim $stuff] [concat 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 insert end [string trim $stuff] [concat REM $extratags $fntag]
.cal.t$n tag bind $fntag <Enter> [list EditableEnter .cal.t$n]
.cal.t$n tag bind $fntag <Leave> [list EditableLeave .cal.t$n]
.cal.t$n tag bind $fntag <ButtonPress-1> "FireEditor .cal.t$n"
}
}
@@ -1689,8 +1720,9 @@ proc CreateModifyDialog {w day firstDay args} {
frame $w.msg
frame $w.buttons
pack $w.o1 $w.o2 $w.o3 -side top -anchor w -in $w.o
pack $w.o $w.exp $w.adv $w.weekend $w.time $w.durationbox $w.hol $w.msg -side top -anchor w -pady 4 -expand 1 -fill both
pack $w.buttons -side top -anchor w -pady 4 -expand 1 -fill x
pack $w.o $w.exp $w.adv $w.weekend $w.time $w.durationbox $w.hol $w.msg -side top -anchor w -pady 4 -expand 0 -fill both
pack $w.msg -side top -anchor w -pady 4 -padx 4 -expand true -fill both
pack $w.buttons -side top -anchor w -pady 4 -expand 0 -fill x
# TYPE 1 REMINDER
radiobutton $w.type1 -variable OptionType -value 1
@@ -1887,12 +1919,30 @@ proc CreateModifyDialog {w day firstDay args} {
pack $w.labhol $w.issue $w.skip $w.before $w.after -side top -anchor w -in $w.hol
# TEXT ENTRY
label $w.msglab -text "Body:"
label $w.msglab -text "Summary: "
entry $w.entry
balloon_add_help $w.entry "Enter the text of the reminder"
pack $w.msglab -side left -anchor w -in $w.msg
pack $w.entry -side left -anchor w -expand 1 -fill x -in $w.msg
grid $w.msglab -row 0 -column 0 -in $w.msg -sticky e
grid $w.entry -row 0 -column 1 -in $w.msg -sticky nsew
# LOCATION and DESCRIPTION
label $w.loclab -text "Location: "
entry $w.location
balloon_add_help $w.location "Enter the location, if any"
grid $w.loclab -row 1 -column 0 -in $w.msg -sticky e
grid $w.location -row 1 -column 1 -in $w.msg -sticky nsew
label $w.desclab -text "Description: "
text $w.description -width 80 -height 5
balloon_add_help $w.description "Enter a detailed description, if any"
grid $w.desclab -row 2 -column 0 -in $w.msg -sticky e
grid $w.description -row 2 -column 1 -in $w.msg -sticky nsew
grid columnconfigure $w.msg 0 -weight 0
grid columnconfigure $w.msg 1 -weight 1
grid rowconfigure $w.msg 0 -weight 0
grid rowconfigure $w.msg 1 -weight 0
grid rowconfigure $w.msg 2 -weight 1
# BUTTONS
set nbut 0
foreach but $args {
@@ -1970,6 +2020,11 @@ proc OptionsToRemindDialog { w opts } {
set hour $value
}
}
"-txtentry-*" {
set win [string range $flag 10 end]
$w.$win delete 1.0 end
$w.$win insert end $value
}
"-global-*" {
set win [string range $flag 8 end]
set $win $value
@@ -2152,6 +2207,13 @@ proc CenterWindow {w {parent {}}} {
wm deiconify $w
}
#---------------------------------------------------------------------------
# RemQuotedString - return a quoted string with difficult characters escaped
#---------------------------------------------------------------------------
proc RemQuotedString { str } {
set str [string map {"\n" "\\n" "\"" "\\\"" "[" "[\"[\"]"} $str]
return "\"$str\""
}
#---------------------------------------------------------------------------
# CreateReminder -- create the reminder
# Arguments:
@@ -2237,7 +2299,16 @@ proc CreateReminder {w} {
append rem " OMIT [GetWeekend $w 1]"
}
set location [string trim [$w.location get]]
if {$location != ""} {
set location "Location: $location"
append rem " INFO [RemQuotedString $location]"
}
set description [string trim [$w.description get 1.0 end]]
if {$description != ""} {
set description "Description: $description"
append rem " INFO [RemQuotedString $description]"
}
# Check it out!
global Remind
set f [open "|$Remind -arq -e - 2>@1" r+]
@@ -2702,7 +2773,8 @@ proc StartBackgroundRemindDaemon {} {
} else {
fileevent $DaemonFile readable "DaemonReadable $DaemonFile"
puts $DaemonFile "STATUS"
flush $DaemonFile
DoTranslate
ScheduleUpdateForChanges
}
}
@@ -2826,6 +2898,33 @@ proc sort_q { a b } {
return 0
}
#---------------------------------------------------------------------------
# AddTranslation
# Arguments:
# obj - a dictionary of the form old:new
# Returns:
# nothing
# Description:
# Updates the Translations dict object
#---------------------------------------------------------------------------
proc AddTranslation { obj } {
global Translations
set Translations [dict merge $Translations $obj]
ScheduleUpdateForChanges
}
proc t { str } {
global Translations
set trans ""
catch {
set trans [dict get $Translations $str]
}
if {"$trans" == ""} {
return $str
}
return $trans
}
#---------------------------------------------------------------------------
# DaemonReadable
# Arguments:
@@ -2851,6 +2950,9 @@ proc DaemonReadable { file } {
}
set response [dict get $obj response]
switch -- $response {
"translate" {
AddTranslation [dict get $obj translation]
}
"queued" {
set n [dict get $obj nqueued]
if {$n == 1} {
@@ -2867,11 +2969,16 @@ proc DaemonReadable { file } {
set tag [dict get $obj tags]
}
set body [dict get $obj body]
if {[dict exists $obj info]} {
set info [dict get $obj info]
} else {
set info [dict create]
}
set qid "*"
if {[dict exists $obj qid]} {
set qid [dict get $obj qid]
}
IssueBackgroundReminder $body $time $now $tag $qid
IssueBackgroundReminder $body $time $now $tag $qid $info
}
"queue" {
set queue [dict get $obj queue]
@@ -2888,7 +2995,9 @@ proc DaemonReadable { file } {
if {[dict exists $obj command]} {
set cmd [dict get $obj command]
if {"$cmd" == "inotify"} {
FillCalWindow
# Update our translations if file has changed
DoTranslate
ScheduleUpdateForChanges
}
}
puts $file "STATUS"
@@ -2913,7 +3022,7 @@ proc DaemonReadable { file } {
# Description:
# Reads a background reminder from daemon and pops up window.
#---------------------------------------------------------------------------
proc IssueBackgroundReminder { body time now tag qid } {
proc IssueBackgroundReminder { body time now tag qid info } {
global BgCounter Option Ignore DaemonFile HAVE_SYSNOTIFY NOTIFY_SEND_PATH
if {$Option(Deiconify)} {
wm deiconify .
@@ -2942,7 +3051,7 @@ proc IssueBackgroundReminder { body time now tag qid } {
wm iconname $w "Reminder"
wm title $w "Timed reminder ($time)"
label $w.l -text "Reminder for $time issued at $now"
message $w.msg -width 6i -text $body
message $w.msg -aspect 2000 -text $body -justify left -anchor w -font {-weight bold} -relief groove -bd 2
frame $w.b
# Automatically shut down window after a minute if option says so
@@ -2958,7 +3067,24 @@ proc IssueBackgroundReminder { body time now tag qid } {
button $w.nomore -text "Don't remind me again today" -command [list ClosePopup $w $after_token "" 1 "ignore" $tag $body $time $qid]
}
pack $w.l -side top
pack $w.msg -side top -expand 1 -fill both
pack $w.msg -side top -expand 1 -fill both -anchor w
frame $w.f
pack $w.f -side top -expand 1 -fill both
set row 0
if {[dict exists $info location]} {
label $w.f.l1 -text "Location: " -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight bold}
message $w.f.l2 -text [dict get $info location] -justify left -anchor w -aspect 2000 -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight normal}
grid $w.f.l1 -row $row -column 0 -sticky nw
grid $w.f.l2 -row $row -column 1 -sticky new
incr row
}
if {[dict exists $info description]} {
label $w.f.m1 -text "Description: " -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight bold}
message $w.f.m2 -text [dict get $info description] -justify left -anchor w -aspect 2000 -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -font {-weight normal}
grid $w.f.m1 -row $row -column 0 -sticky nw
grid $w.f.m2 -row $row -column 1 -sticky new
incr row
}
pack $w.b -side top
pack $w.ok -in $w.b -side left
if {$qid != "*"} {
@@ -3035,7 +3161,7 @@ proc main {} {
global AppendFile HighestTagSoFar DayNames
catch {
puts "\nTkRemind Copyright (C) 1996-2024 Dianne Skoll"
puts "\nTkRemind Copyright (C) 1996-2025 Dianne Skoll"
}
catch { SetFonts }
Initialize
@@ -3392,6 +3518,16 @@ proc ReadTaggedOptions { tag date } {
lappend ans -text-year3 $y
}
}
if {[dict exists $obj info]} {
set info [dict get $obj info]
if {[dict exists $info location]} {
lappend ans -entry-location [dict get $info location]
}
if {[dict exists $info description]} {
lappend ans -txtentry-description [dict get $info description]
}
}
return $ans
}
@@ -3522,6 +3658,67 @@ proc EditableLeave { w } {
set tag [lindex $tags $index]
$w tag configure $tag -underline 0
}
proc details_enter { w } {
global SynToObj Balloon
set tags [$w tag names current]
set index [lsearch -glob $tags "__syn__*"]
if {$index < 0} {
return
}
set syntag [lindex $tags $index]
if {![info exists SynToObj($syntag)]} {
return
}
set obj $SynToObj($syntag)
set lines {}
if {![dict exists $obj info]} {
return;
}
set info [dict get $obj info]
set llen 0
if {[dict exists $info location]} {
lappend lines [list "Location:" [dict get $info location]]
}
if {[dict exists $info description]} {
lappend lines [list "Description:" [dict get $info description]]
}
if {[llength $lines] < 1} {
return;
}
balloon_cancel_timer
set Balloon(HelpId) [after $Balloon(HelpTime) [list details_popup $lines]]
}
proc details_leave { w } {
balloon_cancel_timer
catch { destroy .balloonhelp }
}
proc details_popup { pairs } {
global Balloon
set maxwid 80
set h .balloonhelp
set c 0
toplevel $h -bg #000000
frame $h.l -padx 0 -pady 0 -highlightthickness 0 -relief flat -bd 0 -bg #FFFFC0
pack $h.l -side top -padx 1 -pady 1 -ipadx 2 -ipady 1
foreach pair $pairs {
label $h.lab$c -text "[lindex $pair 0] " -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -bg #FFFFC0 -font {-weight bold}
message $h.m$c -text "[lindex $pair 1] " -justify left -anchor w -aspect 2000 -padx 1 -pady 1 -highlightthickness 0 -relief flat -bd 0 -bg #FFFFC0 -font {-weight normal}
grid $h.lab$c -in $h.l -row $c -column 0 -sticky nw
grid $h.m$c -in $h.l -row $c -column 1 -sticky new
incr c
}
wm overrideredirect $h 1
set geom [balloon_calculate_geometry $h]
wm geometry $h $geom
set Balloon(HelpId) [after 10000 "catch { destroy $h }"]
set Balloon(MustLeave) 1
}
#***********************************************************************
# %PROCEDURE: EditTaggedReminder
# %ARGUMENTS:
@@ -3617,14 +3814,14 @@ proc UpdateForChanges {} {
RestartBackgroundRemindDaemon
}
# Schedule an update for 100ms in the future.
# Schedule an update for 250ms in the future.
# That way, if we get a rapid succession of
# change notifications, we (probably) only
# end up doing one call to UpdateForChanges
proc ScheduleUpdateForChanges {} {
global TimerUpdateForChanges
catch { after cancel $TimerUpdateForChanges }
set TimerUpdateForChanges [after 100 UpdateForChanges]
set TimerUpdateForChanges [after 250 UpdateForChanges]
}
#***********************************************************************
@@ -3929,27 +4126,27 @@ proc CreateMoonWindows {} {
foreach win {.moon_new .moon_new2 } {
canvas $win -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0
$win create oval $extra $extra $w $w -outline $Option(TextColor) -width 1
balloon_add_help $win "New Moon"
balloon_add_help $win [t "New Moon"]
}
foreach win {.moon_first .moon_first2 } {
canvas $win -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0
$win create oval $extra $extra $w $w -outline $Option(TextColor) -width 1
$win create arc $extra $extra $w $w -outline $Option(TextColor) -fill $Option(TextColor) -start 90 -extent 180 -outline {}
balloon_add_help $win "First Quarter"
balloon_add_help $win [t "First Quarter"]
}
foreach win {.moon_full .moon_full2 } {
canvas $win -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0
$win create oval $extra $extra $w $w -outline $Option(TextColor) -fill $Option(TextColor) -width 1
balloon_add_help $win "Full Moon"
balloon_add_help $win [t "Full Moon"]
}
foreach win {.moon_last .moon_last2 } {
canvas $win -background $Option(BackgroundColor) -width $wid -height $wid -borderwidth 0 -highlightthickness 0
$win create oval $extra $extra $w $w -outline $Option(TextColor) -width 1
$win create arc $extra $extra $w $w -outline $Option(TextColor) -fill $Option(TextColor) -start 270 -extent 180 -outline {}
balloon_add_help $win "Last Quarter"
balloon_add_help $win [t "Last Quarter"]
}
}

View File

@@ -31,9 +31,11 @@ REMINDSRCS= calendar.c dedupe.c dynbuf.c dorem.c dosubst.c expr.c \
hbcal.c init.c main.c md5.c moon.c omit.c queue.c \
sort.c token.c trans.c trigger.c userfns.c utils.c var.c
XLATSRC= xlat.c
REMINDHDRS=config.h custom.h dynbuf.h err.h globals.h hashtab.h \
lang.h md5.h protos.h rem2ps.h types.h version.h
REMINDOBJS= $(REMINDSRCS:.c=.o)
md5.h protos.h rem2ps.h types.h version.h
REMINDOBJS= $(REMINDSRCS:.c=.o) $(XLATSRC:.c=.o)
all: remind rem2ps
@@ -41,7 +43,14 @@ test: all
@sh ../tests/test-rem
.c.o:
@CC@ -c @CPPFLAGS@ @CFLAGS@ @DEFS@ $(CEXTRA) $(LANGDEF) -DSYSDIR=$(datarootdir)/remind -I. -I$(srcdir) $<
@CC@ -c @CPPFLAGS@ @CFLAGS@ @DEFS@ $(CEXTRA) -DSYSDIR=$(datarootdir)/remind -I. -I$(srcdir) $<
xlat.c: $(REMINDSRCS)
@echo "#include <stddef.h>" > xlat.c
@echo "char const *translatables[] = {" >> xlat.c
@cat $(REMINDSRCS) | grep 'tr(".*")' | sed -e 's/.*tr."/"/' -e 's/").*/"/' | sort | uniq | grep -E -v '^"(am|at|from now|hour|minute|now|on|pm|today|tomorrow|was)"$$' | sed -e 's/^/ /' -e 's/$$/,/' >> xlat.c
@echo " NULL" >> xlat.c
@echo "};" >> xlat.c
$(REMINDOBJS): $(REMINDHDRS)
@@ -80,7 +89,7 @@ install-stripped: install
strip $(DESTDIR)$(bindir)/rem2ps || true
clean:
rm -f *.o *~ core *.bak $(PROGS)
rm -f *.o *~ core *.bak $(PROGS) $(XLATSRC)
clobber:
rm -f *.o *~ remind rem2ps test.out core *.bak

View File

@@ -5,7 +5,7 @@
/* The code for generating a calendar. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -32,7 +32,6 @@
#include <langinfo.h>
#endif
#include "lang.h"
#include "types.h"
#include "protos.h"
#include "globals.h"
@@ -62,6 +61,7 @@ typedef struct cal_entry {
TimeTrig tt;
int nonconst_expr;
int if_depth;
TrigInfo *infos;
} CalEntry;
/* Line-drawing sequences */
@@ -275,6 +275,7 @@ static int ColToDay[7];
static int ColSpaces;
static int DidAMonth;
static int DidAWeek;
static int DidADay;
static void ColorizeEntry(CalEntry const *e, int clamp);
@@ -387,7 +388,13 @@ void PrintJSONChar(char c) {
case '\t': printf("\\t"); break;
case '"': printf("\\\""); break;
case '\\': printf("\\\\"); break;
default: printf("%c", c);
default:
if ((c > 0 && c < 32) || c == 0x7f) {
printf("\\u%04x", (unsigned int) c);
} else {
printf("%c", c);
}
break;
}
}
@@ -402,7 +409,36 @@ void PrintJSONString(char const *s)
case '\t': printf("\\t"); break;
case '"': printf("\\\""); break;
case '\\': printf("\\\\"); break;
default: printf("%c", *s);
default:
if ((*s > 0 && *s < 32) || *s == 0x7f) {
printf("\\u%04x", (unsigned int) *s);
} else {
printf("%c", *s);
}
break;
}
s++;
}
}
void PrintJSONStringLC(char const *s)
{
while (*s) {
switch(*s) {
case '\b': printf("\\b"); break;
case '\f': printf("\\f"); break;
case '\n': printf("\\n"); break;
case '\r': printf("\\r"); break;
case '\t': printf("\\t"); break;
case '"': printf("\\\""); break;
case '\\': printf("\\\\"); break;
default:
if ((*s > 0 && *s < 32) || *s == 0x7f) {
printf("\\u%04x", (unsigned int) *s);
} else {
printf("%c", tolower(*s));
}
break;
}
s++;
}
@@ -499,7 +535,7 @@ get_month_abbrev(char const *mon)
{
static char buf[80];
#ifndef REM_USE_WCHAR
sprintf(buf, "%.3s", mon);
snprintf(buf, sizeof(buf), "%.3s", mon);
return buf;
#else
char *s;
@@ -626,9 +662,9 @@ Colorize256(int r, int g, int b, int bg, int clamp)
}
}
if (bg) {
sprintf(buf, "\x1B[48;5;%dm", best);
snprintf(buf, sizeof(buf), "\x1B[48;5;%dm", best);
} else {
sprintf(buf, "\x1B[38;5;%dm", best);
snprintf(buf, sizeof(buf), "\x1B[38;5;%dm", best);
}
return buf;
}
@@ -641,9 +677,9 @@ ColorizeTrue(int r, int g, int b, int bg, int clamp)
ClampColor(&r, &g, &b);
}
if (bg) {
sprintf(buf, "\x1B[48;2;%d;%d;%dm", r, g, b);
snprintf(buf, sizeof(buf), "\x1B[48;2;%d;%d;%dm", r, g, b);
} else {
sprintf(buf, "\x1B[38;2;%d;%d;%dm", r, g, b);
snprintf(buf, sizeof(buf), "\x1B[38;2;%d;%d;%dm", r, g, b);
}
return buf;
}
@@ -835,12 +871,33 @@ void ProduceCalendar(void)
WriteIntermediateCalLine();
}
while (CalWeeks--)
DidAWeek = 0;
if (PsCal == PSCAL_LEVEL3) {
printf("[\n");
}
while (CalWeeks--) {
DoCalendarOneWeek(CalWeeks);
DidAWeek = 1;
}
if (PsCal == PSCAL_LEVEL3) {
printf("\n]\n");
}
return;
}
}
static void
SendTranslationTable(int pslevel)
{
if (pslevel < PSCAL_LEVEL3) {
printf("# translations\n");
}
DumpTranslationTable(stdout, 1);
if (pslevel < PSCAL_LEVEL3) {
printf("\n");
}
}
/***************************************************************/
/* */
/* DoCalendarOneWeek */
@@ -871,9 +928,33 @@ static void DoCalendarOneWeek(int nleft)
/* Output the entries */
/* If it's "Simple Calendar" format, do it simply... */
if (DoSimpleCalendar) {
if (PsCal == PSCAL_LEVEL3) {
if (DidAWeek) {
printf(",\n");
}
printf("{\n\"caltype\":\"weekly\",");
if (!DidAWeek) {
printf("\"translations\":");
SendTranslationTable(PsCal);
printf(",");
}
printf("\"dates\":[");
for (i=0; i<7; i++) {
if (i != 0) {
printf(",");
}
FromDSE(OrigDse+i-wd, &y, &m, &d);
printf("{\"dayname\":\"%s\",\"date\":\"%04d-%02d-%02d\",\"year\":%d,\"month\":\"%s\",\"day\":%d}", get_day_name((OrigDse+i-wd)%7),y, m+1, d, y, get_month_name(m), d);
}
printf("],\"entries\":[");
}
DidADay = 0;
for (i=0; i<7; i++) {
WriteSimpleEntries(i, OrigDse+i-wd);
}
if (PsCal == PSCAL_LEVEL3) {
printf("\n]\n}");
}
return;
}
@@ -985,14 +1066,25 @@ static void DoSimpleCalendarOneMonth(void)
if (PsCal) {
FromDSE(DSEToday, &y, &m, &d);
if (PsCal == PSCAL_LEVEL1) {
if (!DidAMonth) {
SendTranslationTable(PsCal);
}
printf("%s\n", PSBEGIN);
} else if (PsCal == PSCAL_LEVEL2) {
if (!DidAMonth) {
SendTranslationTable(PsCal);
}
printf("%s\n", PSBEGIN2);
} else {
if (DidAMonth) {
printf(",\n");
}
printf("{\n");
if (!DidAMonth) {
printf("\"translations\":");
SendTranslationTable(PsCal);
printf(",");
}
}
if (PsCal < PSCAL_LEVEL3) {
printf("%s %d %d %d %d\n",
@@ -1008,6 +1100,7 @@ static void DoSimpleCalendarOneMonth(void)
}
printf("\n");
} else {
PrintJSONKeyPairString("caltype", "monthly");
PrintJSONKeyPairString("monthname", get_month_name(m));
PrintJSONKeyPairInt("year", y);
PrintJSONKeyPairInt("daysinmonth", DaysInMonth(m, y));
@@ -1250,7 +1343,7 @@ static void PrintLeft(char const *s, int width, char pad)
buf = calloc(len+1, sizeof(wchar_t));
if (!buf) {
/* Uh-oh... cannot recover */
fprintf(stderr, "%s\n", ErrMsg[E_NO_MEM]);
fprintf(ErrFp, "%s\n", GetErr(E_NO_MEM));
exit(EXIT_FAILURE);
}
}
@@ -1335,7 +1428,7 @@ static void PrintCentered(char const *s, int width, char *pad)
buf = calloc(len+1, sizeof(wchar_t));
if (!buf) {
/* Uh-oh... cannot recover */
fprintf(stderr, "%s\n", ErrMsg[E_NO_MEM]);
fprintf(ErrFp, "%s\n", GetErr(E_NO_MEM));
exit(EXIT_FAILURE);
}
}
@@ -1447,6 +1540,7 @@ static int WriteOneColLine(int col)
free(e->raw_text);
free(e->filename);
if (e->wc_text) free(e->wc_text);
FreeTrigInfoChain(e->infos);
free(e);
return 1;
}
@@ -1533,6 +1627,7 @@ static int WriteOneColLine(int col)
free(e->raw_text);
free(e->filename);
if (e->wc_text) free(e->wc_text);
FreeTrigInfoChain(e->infos);
free(e);
} else {
e->wc_pos = ws;
@@ -1554,6 +1649,7 @@ static int WriteOneColLine(int col)
if (e->wc_text) free(e->wc_text);
#endif
free(e->raw_text);
FreeTrigInfoChain(e->infos);
free(e);
return 1;
}
@@ -1616,6 +1712,7 @@ static int WriteOneColLine(int col)
if (e->wc_text) free(e->wc_text);
#endif
free(e->raw_text);
FreeTrigInfoChain(e->infos);
free(e);
} else {
e->pos = s;
@@ -1645,7 +1742,7 @@ static void GenerateCalEntries(int col)
r=IncludeFile(InitialFile);
if (r) {
fprintf(ErrFp, "%s %s: %s\n", ErrMsg[E_ERR_READING], InitialFile, ErrMsg[r]);
fprintf(ErrFp, "%s %s: %s\n", GetErr(E_ERR_READING), InitialFile, GetErr(r));
exit(EXIT_FAILURE);
}
@@ -1653,7 +1750,7 @@ static void GenerateCalEntries(int col)
r = ReadLine();
if (r == E_EOF) return;
if (r) {
Eprint("%s: %s", ErrMsg[E_ERR_READING], ErrMsg[r]);
Eprint("%s: %s", GetErr(E_ERR_READING), GetErr(r));
exit(EXIT_FAILURE);
}
s = FindInitialToken(&tok, CurLine);
@@ -1686,6 +1783,7 @@ static void GenerateCalEntries(int col)
case T_EndIf: r=DoEndif(&p); break;
case T_Include:
case T_IncludeSys:
case T_IncludeR: r=DoInclude(&p, tok.type); break;
case T_IncludeCmd: r=DoIncludeCmd(&p); break;
@@ -1734,7 +1832,7 @@ static void GenerateCalEntries(int col)
r=DoCalRem(&p, col);
break;
}
if (r && (!Hush || r != E_RUN_DISABLED)) Eprint("%s", ErrMsg[r]);
if (r && (!Hush || r != E_RUN_DISABLED)) Eprint("%s", GetErr(r));
/* Destroy the parser - free up resources it may be tying up */
DestroyParser(&p);
@@ -1754,7 +1852,7 @@ static void WriteCalHeader(void)
int y, m, d;
FromDSE(DSEToday, &y, &m, &d);
sprintf(buf, "%s %d", get_month_name(m), y);
snprintf(buf, sizeof(buf), "%s %d", get_month_name(m), y);
WriteTopCalLine();
@@ -1958,7 +2056,7 @@ static int DoCalRem(ParsePtr p, int col)
trig.typ == MSF_TYPE) {
if (PsCal && is_color) {
char cbuf[24];
sprintf(cbuf, "%d %d %d ", col_r, col_g, col_b);
snprintf(cbuf, sizeof(cbuf), "%d %d %d ", col_r, col_g, col_b);
DBufPuts(&pre_buf, cbuf);
strcpy(trig.passthru, "COLOR");
/* Don't change trig.typ or next if() will trigger! */
@@ -2091,7 +2189,7 @@ static int DoCalRem(ParsePtr p, int col)
if (trig.typ != PASSTHRU_TYPE &&
UserFuncExists("calprefix")==1) {
char evalBuf[64];
sprintf(evalBuf, "calprefix(%d)", trig.priority);
snprintf(evalBuf, sizeof(evalBuf), "calprefix(%d)", trig.priority);
s2 = evalBuf;
r = EvalExpr(&s2, &v, NULL);
if (!r) {
@@ -2134,7 +2232,7 @@ static int DoCalRem(ParsePtr p, int col)
if (trig.typ != PASSTHRU_TYPE &&
UserFuncExists("calsuffix")==1) {
char evalBuf[64];
sprintf(evalBuf, "calsuffix(%d)", trig.priority);
snprintf(evalBuf, sizeof(evalBuf), "calsuffix(%d)", trig.priority);
s2 = evalBuf;
r = EvalExpr(&s2, &v, NULL);
if (!r) {
@@ -2174,6 +2272,7 @@ static int DoCalRem(ParsePtr p, int col)
FreeTrig(&trig);
return E_NO_MEM;
}
e->infos = NULL;
e->nonconst_expr = nonconst_expr;
e->if_depth = NumIfs;
e->trig = trig;
@@ -2194,6 +2293,7 @@ static int DoCalRem(ParsePtr p, int col)
if (!e->text || !e->raw_text) {
if (e->text) free(e->text);
if (e->raw_text) free(e->raw_text);
FreeTrigInfoChain(e->infos);
free(e);
FreeTrig(&trig);
return E_NO_MEM;
@@ -2207,12 +2307,17 @@ static int DoCalRem(ParsePtr p, int col)
AppendTag(&(e->tags), SynthesizeTag());
}
/* Take over any TrigInfo! */
e->infos = trig.infos;
trig.infos = NULL;
/* Don't need tags any more */
FreeTrig(&trig);
e->duration = tim.duration;
e->priority = trig.priority;
e->filename = StrDup(FileName);
if(!e->filename) {
FreeTrigInfoChain(e->infos);
if (e->text) free(e->text);
if (e->raw_text) free(e->raw_text);
#ifdef REM_USE_WCHAR
@@ -2284,6 +2389,41 @@ void WriteJSONTimeTrigger(TimeTrig const *tt)
}
}
void
WriteJSONInfoChain(TrigInfo *ti)
{
printf("\"info\":{");
while (ti) {
/* Skanky... */
char *colon = (char *) strchr(ti->info, ':');
char const *value;
if (!colon) {
/* Should be impossible... */
ti = ti->next;
continue;
}
/* Terminate the string at the colon */
*colon = 0;
value = colon+1;
while(*value && isspace(*value)) {
value++;
}
printf("\"");
PrintJSONStringLC(ti->info);
printf("\":\"");
PrintJSONString(value);
printf("\"");
/* Restore the value of the colon */
*colon = ':';
if (ti->next) {
printf(",");
}
ti = ti->next;
}
printf("},");
}
void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
{
/* wd is an array of days from 0=monday to 6=sunday.
@@ -2298,7 +2438,7 @@ void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
printf(",");
}
done = 1;
printf("\"%s\"", EnglishDayName[i]);
printf("\"%s\"", DayName[i]);
}
}
printf("],");
@@ -2333,7 +2473,7 @@ void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
printf(",");
}
done = 1;
printf("\"%s\"", EnglishDayName[i]);
printf("\"%s\"", DayName[i]);
}
}
printf("],");
@@ -2375,6 +2515,9 @@ void WriteJSONTrigger(Trigger const *t, int include_tags, int today)
PrintJSONKeyPairInt("addomit", 1);
}
if (include_tags) {
if (t->infos) {
WriteJSONInfoChain(t->infos);
}
PrintJSONKeyPairString("tags", DBufValue(&(t->tags)));
}
}
@@ -2388,6 +2531,9 @@ static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
}
PrintJSONKeyPairString("passthru", e->passthru);
PrintJSONKeyPairString("tags", DBufValue(&(e->tags)));
if (e->infos) {
WriteJSONInfoChain(e->infos);
}
if (e->duration != NO_TIME) {
PrintJSONKeyPairInt("duration", e->duration);
}
@@ -2518,6 +2664,7 @@ static void WriteSimpleEntries(int col, int dse)
free(e->text);
free(e->raw_text);
free(e->filename);
FreeTrigInfoChain(e->infos);
#ifdef REM_USE_WCHAR
if (e->wc_text) free(e->wc_text);
#endif
@@ -2678,20 +2825,20 @@ CalendarTime(int tim, int duration)
else hh2 = h2;
if (days) {
sprintf(daybuf, "+%d", days);
snprintf(daybuf, sizeof(daybuf), "+%d", days);
} else {
daybuf[0] = 0;
}
if (h >= 12) {
ampm1 = DynamicPm;
ampm1 = tr("pm");
} else {
ampm1 = DynamicAm;
ampm1 = tr("am");
}
if (h2 >= 12) {
ampm2 = DynamicPm;
ampm2 = tr("pm");
} else {
ampm2 = DynamicAm;
ampm2 = tr("am");
}
if (!days) {
if (!strcmp(ampm1, ampm2)) {
@@ -2701,12 +2848,12 @@ CalendarTime(int tim, int duration)
switch(ScFormat) {
case SC_AMPM:
sprintf(buf, "%d%c%02d%s-%d%c%02d%s%s ",
snprintf(buf, sizeof(buf), "%d%c%02d%s-%d%c%02d%s%s ",
hh, TimeSep, min, ampm1, hh2, TimeSep, min2, ampm2, daybuf);
break;
case SC_MIL:
sprintf(buf, "%02d%c%02d-%02d%c%02d%s ",
snprintf(buf, sizeof(buf), "%02d%c%02d-%02d%c%02d%s ",
h, TimeSep, min, h2, TimeSep, min2, daybuf);
break;
}
@@ -2724,7 +2871,7 @@ CalendarTime(int tim, int duration)
/***************************************************************/
char const *SimpleTime(int tim)
{
static char buf[32];
static char buf[128];
int h, min, hh;
buf[0] = 0;
@@ -2738,7 +2885,7 @@ char const *SimpleTime(int tim)
if (h == 0) hh=12;
else if (h > 12) hh=h-12;
else hh=h;
sprintf(buf, "%d%c%02d%s ", hh, TimeSep, min, (h>=12) ? DynamicPm : DynamicAm);
snprintf(buf, sizeof(buf), "%d%c%02d%.64s ", hh, TimeSep, min, (h>=12) ? tr("pm") : tr("am"));
}
break;
@@ -2746,7 +2893,7 @@ char const *SimpleTime(int tim)
if (tim != NO_TIME) {
h = tim / 60;
min = tim % 60;
sprintf(buf, "%02d%c%02d ", h, TimeSep, min);
snprintf(buf, sizeof(buf), "%02d%c%02d ", h, TimeSep, min);
}
break;
}
@@ -2797,8 +2944,11 @@ char const *SynthesizeTag(void)
static char out[128];
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) CurLine, strlen(CurLine));
MD5Update(&ctx, (unsigned char *) FileName, strlen(FileName));
snprintf((char *) buf, sizeof(buf), "%d", LineNo);
MD5Update(&ctx, buf, strlen( (char *) buf));
MD5Final(buf, &ctx);
sprintf(out, "__syn__%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
snprintf(out, sizeof(out), "__syn__%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
(unsigned int) buf[0], (unsigned int) buf[1],
(unsigned int) buf[2], (unsigned int) buf[3],
(unsigned int) buf[4], (unsigned int) buf[5],

View File

@@ -1,73 +0,0 @@
#!/usr/bin/perl
use strict;
use warnings;
my $language_map = {
en => 'ENGLISH',
de => 'GERMAN',
nl => 'DUTCH',
fi => 'FINNISH',
fr => 'FRENCH',
'no' => 'NORWEGIAN',
da => 'DANISH',
pl => 'POLISH',
is => 'ICELANDIC',
pt => 'BRAZPORT',
it => 'ITALIAN',
ro => 'ROMANIAN',
es => 'SPANISH',
};
if (!$ARGV[0]) {
print STDERR "Usage: $0 lang_code\n";
exit(1);
}
my $lang = $ARGV[0];
my $rc = 0;
if ($lang eq 'all') {
foreach my $l (sort(keys(%$language_map))) {
if (check($l)) {
$rc = 1;
}
}
} else {
$rc = check($lang);
}
exit($rc);
sub check
{
my ($lang) = @_;
if (!exists($language_map->{$lang})) {
print STDERR "$lang is not a valid language.\n";
return 1;
}
my $flag = $language_map->{$lang};
print STDERR "Testing for: $lang - $flag.\n";
my_sys("make clean > /dev/null 2>&1") && die("make clean failed");
my_sys("make -j18 all LANGDEF=-DLANG=$flag > /dev/null 2>&1") && die("make all failed");
my_sys("./remind -q -r ../tests/tstlang.rem 2022-03-23 11:44 > test-$lang-compiled.out 2>&1");
my_sys("make clean > /dev/null 2>&1") && die("make clean failed");
my_sys("make -j18 all > /dev/null 2>&1") && die("make all failed");
my_sys("./remind -q -r -ii=\\\"../include/lang/$lang.rem\\\" ../tests/tstlang.rem 2022-03-23 11:44 > test-$lang-runtime.out 2>&1");
my $rc = my_sys("cmp test-$lang-compiled.out test-$lang-runtime.out > /dev/null 2>&1");
if ($rc == 0) {
print STDERR "Congrats! Compiled and runtime language output matches for $lang.\n";
} else {
print STDERR "Whoops. Compiled and runtime language output differs for $lang.\n"
}
return $rc;
}
exit(0);
sub my_sys
{
#print STDERR "Running: " . join(' ', @_) . "\n";
return system(@_);
}

View File

@@ -116,4 +116,4 @@
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
#include <custom.h>
#include "custom.h"

View File

@@ -6,7 +6,7 @@
/* which you can customize. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -22,8 +22,8 @@
/* The default values are initially set to the city hall in Ottawa, */
/* Ontario, Canada. */
/*---------------------------------------------------------------------*/
#define DEFAULT_LATITUDE 45.420556
#define DEFAULT_LONGITUDE -75.689722
#define DEFAULT_LATITUDE 45.42055555555555
#define DEFAULT_LONGITUDE -75.68944444444445
#define LOCATION "Ottawa"
/*---------------------------------------------------------------------*/

View File

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

View File

@@ -5,7 +5,7 @@
/* Code to suppress duplicate reminders */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -167,17 +167,13 @@ InitDedupeTable(void)
if (hash_table_init(&DedupeTable,
offsetof(DedupeEntry, link),
DedupeHashFunc, CompareDedupes) < 0) {
fprintf(stderr, "Unable to initialize function hash table: Out of memory. Exiting.\n");
fprintf(ErrFp, "Unable to initialize function hash table: Out of memory. Exiting.\n");
exit(1);
}
}
void
get_dedupe_hash_stats(int *total, int *maxlen, double *avglen)
dump_dedupe_hash_stats(void)
{
struct hash_table_stats s;
hash_table_get_stats(&DedupeTable, &s);
*total = s.num_entries;
*maxlen = s.max_len;
*avglen = s.avg_len;
hash_table_dump_stats(&DedupeTable, ErrFp);
}

View File

@@ -7,7 +7,7 @@
/* commands. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -67,18 +67,18 @@ check_trigger_function(char const *fname, char const *type)
if (!f) {
if (strcmp(type, "WARN")) {
/* Undefined WARN functions are diagnosed elsewhere... */
Wprint("Undefined %s function: `%s'", type, fname);
Wprint(tr("Undefined %s function: `%s'"), type, fname);
}
return;
}
if (f->nargs != 1) {
Wprint("%s function `%s' defined at %s:%d should take 1 argument but actually takes %d", type, fname, f->filename, f->lineno, f->nargs);
Wprint(tr("%s function `%s' defined at %s:%d should take 1 argument but actually takes %d"), type, fname, f->filename, f->lineno, f->nargs);
return;
}
if (ensure_expr_references_first_local_arg(f->node)) {
return;
}
Wprint("%s function `%s' defined at %s:%d does not use its argument", type, fname, f->filename, f->lineno);
Wprint(tr("%s function `%s' defined at %s:%d does not use its argument"), type, fname, f->filename, f->lineno);
}
static void
@@ -154,7 +154,7 @@ static void ensure_satnode_mentions_trigdate(expr_node *node)
if (node->type == N_CONSTANT) {
if (node->u.value.type == INT_TYPE) {
if (node->u.value.v.val == 0) {
Wprint("SATISFY: constant 0 will never be true");
Wprint(tr("SATISFY: constant 0 will never be true"));
}
return;
}
@@ -166,14 +166,14 @@ static void ensure_satnode_mentions_trigdate(expr_node *node)
str = node->u.name;
}
if (!*str) {
Wprint("SATISFY: constant \"\" will never be true");
Wprint(tr("SATISFY: constant \"\" will never be true"));
}
return;
}
ensure_satnode_mentions_trigdate_aux(node, &mentioned);
if (!mentioned) {
Wprint("SATISFY: expression has no reference to trigdate() or $T...");
Wprint(tr("SATISFY: expression has no reference to trigdate() or $T..."));
}
}
@@ -284,7 +284,7 @@ int DoRem(ParsePtr p)
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
if (r) {
if (PurgeMode) {
PurgeEchoLine("%s: %s\n", "#!P! Problem calculating trigger date", ErrMsg[r]);
PurgeEchoLine("%s: %s\n", "#!P! Problem calculating trigger date", GetErr(r));
PurgeEchoLine("%s\n", CurLine);
}
if (r == E_CANT_TRIG && trig.maybe_uncomputable) {
@@ -408,6 +408,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
tim->duration = NO_TIME;
trig->need_wkday = 0;
trig->adj_for_last = 0;
trig->infos = NULL;
int parsing = 1;
while(parsing) {
@@ -615,7 +616,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
case T_Omit:
DBufFree(&buf);
if (trig->omitfunc[0]) {
Wprint("Warning: OMIT is ignored if you use OMITFUNC");
Wprint(tr("Warning: OMIT is ignored if you use OMITFUNC"));
}
r = ParseLocalOmit(s, trig);
@@ -629,7 +630,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
case T_OmitFunc:
if (trig->localomit) {
Wprint("Warning: OMIT is ignored if you use OMITFUNC");
Wprint(tr("Warning: OMIT is ignored if you use OMITFUNC"));
}
r=ParseToken(s, &buf);
if (r) return r;
@@ -649,6 +650,15 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
DBufFree(&buf);
break;
case T_Info:
r = ParseQuotedString(s, &buf);
if (r != OK) {
return r;
}
r = AppendTrigInfo(trig, DBufValue(&buf));
DBufFree(&buf);
if (r) return r;
break;
case T_Tag:
r = ParseToken(s, &buf);
if (r) return r;
@@ -698,7 +708,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
Eprint("%s: `%s'", GetErr(-tok.val), DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
@@ -707,7 +717,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
trig->typ = MSG_TYPE;
if (s->isnested) return E_CANT_NEST_RTYPE;
if (!WarnedAboutImplicit && !SuppressImplicitRemWarnings) {
Wprint("Missing REM type; assuming MSG");
Wprint(tr("Missing REM type; assuming MSG"));
WarnedAboutImplicit = 1;
}
parsing = 0;
@@ -738,22 +748,22 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
if (!s->nonconst_expr) {
if (trig->y != NO_YR && trig->m != NO_MON && trig->d != NO_DAY && trig->until != NO_UNTIL) {
if (DSE(trig->y, trig->m, trig->d) > trig->until) {
Wprint("Warning: UNTIL/THROUGH date earlier than start date");
Wprint(tr("Warning: UNTIL/THROUGH date earlier than start date"));
}
}
if (trig->from != NO_DATE) {
if (trig->until != NO_UNTIL && trig->until < trig->from) {
Wprint("Warning: UNTIL/THROUGH date earlier than FROM date");
Wprint(tr("Warning: UNTIL/THROUGH date earlier than FROM date"));
}
} else if (trig->scanfrom != NO_DATE) {
if (trig->until != NO_UNTIL && trig->until < trig->scanfrom) {
Wprint("Warning: UNTIL/THROUGH date earlier than SCANFROM date");
Wprint(tr("Warning: UNTIL/THROUGH date earlier than SCANFROM date"));
}
}
}
if (trig->y != NO_YR && trig->m != NO_MON && trig->d != NO_DAY && trig->until != NO_UNTIL && trig->rep == NO_REP) {
Wprint("Warning: Useless use of UNTIL with fully-specified date and no *rep");
Wprint(tr("Warning: Useless use of UNTIL with fully-specified date and no *rep"));
}
/* Set scanfrom to default if not set explicitly */
@@ -808,7 +818,7 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim)
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
Eprint("%s: `%s'", GetErr(-tok.val), DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
@@ -887,7 +897,7 @@ static int ParseUntil(ParsePtr s, Trigger *t, int type)
case T_Year:
DBufFree(&buf);
if (y != NO_YR) {
Eprint("%s: %s", which, ErrMsg[E_YR_TWICE]);
Eprint("%s: %s", which, GetErr(E_YR_TWICE));
return E_YR_TWICE;
}
y = tok.val;
@@ -896,7 +906,7 @@ static int ParseUntil(ParsePtr s, Trigger *t, int type)
case T_Month:
DBufFree(&buf);
if (m != NO_MON) {
Eprint("%s: %s", which, ErrMsg[E_MON_TWICE]);
Eprint("%s: %s", which, GetErr(E_MON_TWICE));
return E_MON_TWICE;
}
m = tok.val;
@@ -905,7 +915,7 @@ static int ParseUntil(ParsePtr s, Trigger *t, int type)
case T_Day:
DBufFree(&buf);
if (d != NO_DAY) {
Eprint("%s: %s", which, ErrMsg[E_DAY_TWICE]);
Eprint("%s: %s", which, GetErr(E_DAY_TWICE));
return E_DAY_TWICE;
}
d = tok.val;
@@ -914,15 +924,15 @@ static int ParseUntil(ParsePtr s, Trigger *t, int type)
case T_Date:
DBufFree(&buf);
if (y != NO_YR) {
Eprint("%s: %s", which, ErrMsg[E_YR_TWICE]);
Eprint("%s: %s", which, GetErr(E_YR_TWICE));
return E_YR_TWICE;
}
if (m != NO_MON) {
Eprint("%s: %s", which, ErrMsg[E_MON_TWICE]);
Eprint("%s: %s", which, GetErr(E_MON_TWICE));
return E_MON_TWICE;
}
if (d != NO_DAY) {
Eprint("%s: %s", which, ErrMsg[E_DAY_TWICE]);
Eprint("%s: %s", which, GetErr(E_DAY_TWICE));
return E_DAY_TWICE;
}
FromDSE(tok.val, &y, &m, &d);
@@ -930,12 +940,12 @@ static int ParseUntil(ParsePtr s, Trigger *t, int type)
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
Eprint("%s: `%s'", GetErr(-tok.val), DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
Eprint("%s: %s", which, ErrMsg[E_INCOMPLETE]);
Eprint("%s: %s", which, GetErr(E_INCOMPLETE));
DBufFree(&buf);
return E_INCOMPLETE;
}
@@ -984,7 +994,7 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
case T_Year:
DBufFree(&buf);
if (y != NO_YR) {
Eprint("%s: %s", word, ErrMsg[E_YR_TWICE]);
Eprint("%s: %s", word, GetErr(E_YR_TWICE));
return E_YR_TWICE;
}
y = tok.val;
@@ -993,7 +1003,7 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
case T_Month:
DBufFree(&buf);
if (m != NO_MON) {
Eprint("%s: %s", word, ErrMsg[E_MON_TWICE]);
Eprint("%s: %s", word, GetErr(E_MON_TWICE));
return E_MON_TWICE;
}
m = tok.val;
@@ -1002,7 +1012,7 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
case T_Day:
DBufFree(&buf);
if (d != NO_DAY) {
Eprint("%s: %s", word, ErrMsg[E_DAY_TWICE]);
Eprint("%s: %s", word, GetErr(E_DAY_TWICE));
return E_DAY_TWICE;
}
d = tok.val;
@@ -1011,15 +1021,15 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
case T_Date:
DBufFree(&buf);
if (y != NO_YR) {
Eprint("%s: %s", word, ErrMsg[E_YR_TWICE]);
Eprint("%s: %s", word, GetErr(E_YR_TWICE));
return E_YR_TWICE;
}
if (m != NO_MON) {
Eprint("%s: %s", word, ErrMsg[E_MON_TWICE]);
Eprint("%s: %s", word, GetErr(E_MON_TWICE));
return E_MON_TWICE;
}
if (d != NO_DAY) {
Eprint("%s: %s", word, ErrMsg[E_DAY_TWICE]);
Eprint("%s: %s", word, GetErr(E_DAY_TWICE));
return E_DAY_TWICE;
}
FromDSE(tok.val, &y, &m, &d);
@@ -1028,19 +1038,19 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
case T_Back:
DBufFree(&buf);
if (type != SCANFROM_TYPE) {
Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]);
Eprint("%s: %s", word, GetErr(E_INCOMPLETE));
return E_INCOMPLETE;
}
if (y != NO_YR) {
Eprint("%s: %s", word, ErrMsg[E_YR_TWICE]);
Eprint("%s: %s", word, GetErr(E_YR_TWICE));
return E_YR_TWICE;
}
if (m != NO_MON) {
Eprint("%s: %s", word, ErrMsg[E_MON_TWICE]);
Eprint("%s: %s", word, GetErr(E_MON_TWICE));
return E_MON_TWICE;
}
if (d != NO_DAY) {
Eprint("%s: %s", word, ErrMsg[E_DAY_TWICE]);
Eprint("%s: %s", word, GetErr(E_DAY_TWICE));
return E_DAY_TWICE;
}
if (tok.val < 0) {
@@ -1054,12 +1064,12 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
Eprint("%s: `%s'", GetErr(-tok.val), DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]);
Eprint("%s: %s", word, GetErr(E_INCOMPLETE));
DBufFree(&buf);
return E_INCOMPLETE;
}
@@ -1180,7 +1190,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
return OK;
}
FromDSE(dse, &y, &m, &d);
sprintf(tmpBuf, "%04d/%02d/%02d ", y, m+1, d);
snprintf(tmpBuf, sizeof(tmpBuf), "%04d/%02d/%02d ", y, m+1, d);
if (DBufPuts(&calRow, tmpBuf) != OK) {
DBufFree(&calRow);
DBufFree(&pre_buf);
@@ -1201,9 +1211,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
DBufPuts(&calRow, "* ");
}
if (tim->duration != NO_TIME) {
sprintf(tmpBuf, "%d ", tim->duration);
snprintf(tmpBuf, sizeof(tmpBuf), "%d ", tim->duration);
} else {
sprintf(tmpBuf, "* ");
snprintf(tmpBuf, sizeof(tmpBuf), "* ");
}
if (DBufPuts(&calRow, tmpBuf) != OK) {
DBufFree(&calRow);
@@ -1211,9 +1221,9 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
return E_NO_MEM;
}
if (tim->ttime != NO_TIME) {
sprintf(tmpBuf, "%d ", tim->ttime);
snprintf(tmpBuf, sizeof(tmpBuf), "%d ", tim->ttime);
} else {
sprintf(tmpBuf, "* ");
snprintf(tmpBuf, sizeof(tmpBuf), "* ");
}
if (DBufPuts(&calRow, tmpBuf) != OK) {
DBufFree(&calRow);
@@ -1263,7 +1273,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
/* Don't use msgprefix() on RUN-type reminders */
if (t->typ != RUN_TYPE) {
if (UserFuncExists("msgprefix") == 1) {
sprintf(PrioExpr, "msgprefix(%d)", t->priority);
snprintf(PrioExpr, sizeof(PrioExpr), "msgprefix(%d)", t->priority);
s = PrioExpr;
r = EvalExpr(&s, &v, NULL);
if (!r) {
@@ -1289,7 +1299,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queue
if (t->typ != RUN_TYPE) {
if (UserFuncExists("msgsuffix") == 1) {
sprintf(PrioExpr, "msgsuffix(%d)", t->priority);
snprintf(PrioExpr, sizeof(PrioExpr), "msgsuffix(%d)", t->priority);
s = PrioExpr;
r = EvalExpr(&s, &v, NULL);
if (!r) {
@@ -1471,7 +1481,7 @@ int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int dse, int *err)
}
if (iter > max) {
*err = E_CANT_TRIG;
Eprint("Delta: Bad OMITFUNC? %s", ErrMsg[E_CANT_TRIG]);
Eprint("Delta: Bad OMITFUNC? %s", GetErr(E_CANT_TRIG));
return 0;
}
}
@@ -1690,22 +1700,22 @@ static int ShouldTriggerBasedOnWarn(Trigger *t, int dse, int *err)
/* If no proper function exists, barf... */
if (UserFuncExists(t->warn) != 1) {
Eprint("%s: `%s'", ErrMsg[M_BAD_WARN_FUNC], t->warn);
Eprint("%s: `%s'", GetErr(M_BAD_WARN_FUNC), t->warn);
return (dse == DSEToday);
}
for (i=1; ; i++) {
sprintf(buffer, "%s(%d)", t->warn, i);
snprintf(buffer, sizeof(buffer), "%s(%d)", t->warn, i);
s = buffer;
r = EvalExpr(&s, &v, NULL);
if (r) {
Eprint("%s: `%s': %s", ErrMsg[M_BAD_WARN_FUNC],
t->warn, ErrMsg[r]);
Eprint("%s: `%s': %s", GetErr(M_BAD_WARN_FUNC),
t->warn, GetErr(r));
return (dse == DSEToday);
}
if (v.type != INT_TYPE) {
DestroyValue(v);
Eprint("%s: `%s': %s", ErrMsg[M_BAD_WARN_FUNC],
t->warn, ErrMsg[E_BAD_TYPE]);
Eprint("%s: `%s': %s", GetErr(M_BAD_WARN_FUNC),
t->warn, GetErr(E_BAD_TYPE));
return (dse == DSEToday);
}
@@ -1735,7 +1745,7 @@ static int ShouldTriggerBasedOnWarn(Trigger *t, int dse, int *err)
}
}
if (iter > max) {
Eprint("Delta: Bad OMITFUNC? %s", ErrMsg[E_CANT_TRIG]);
Eprint("Delta: Bad OMITFUNC? %s", GetErr(E_CANT_TRIG));
return 0;
}
if (j == DSEToday) return 1;

View File

@@ -6,7 +6,7 @@
/* reminders are triggered. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -40,7 +40,7 @@ check_subst_args(UserFunc *f, int n)
if (f->nargs == n) {
return 1;
}
Wprint("Function `%s' defined at %s:%d should take %d argument%s, but actually takes %d",
Wprint(tr("Function `%s' defined at %s:%d should take %d argument%s, but actually takes %d"),
f->name, f->filename, f->lineno, n, (n == 1 ? "" : "s"), f->nargs);
return 0;
}
@@ -93,26 +93,14 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
mdiff = adiff % 60;
hdiff = adiff / 60;
#ifdef L_MPLU_OVER
L_MPLU_OVER
#else /* L_MPLU_OVER */
mplu = (mdiff == 1 ? "" : DynamicMplu);
#endif /* L_MPLU_OVER */
#ifdef L_HPLU_OVER
L_HPLU_OVER
#else /* L_HPLU_OVER */
hplu = (hdiff == 1 ? "" : DynamicHplu);
#endif /* L_HPLU_OVER */
when = (tdiff < 0) ? DynamicAgo : DynamicFromnow;
when = (tdiff < 0) ? tr("ago") : tr("from now");
h = tim / 60;
min = tim % 60;
#ifdef L_AMPM_OVERRIDE
L_AMPM_OVERRIDE (pm, h)
#else
r = -1;
func = FindUserFunc("subst_ampm");
if (func && check_subst_args(func, 1)) {
@@ -128,21 +116,18 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
}
DestroyValue(v);
} else {
Eprint("%s", ErrMsg[r]);
Eprint("%s", GetErr(r));
}
}
if (r != OK) {
pm = (h < 12) ? DynamicAm : DynamicPm;
pm = (h < 12) ? tr("am") : tr("pm");
}
#endif
hh = (h == 12) ? 12 : h % 12;
ch = curtime / 60;
cmin = curtime % 60;
#ifdef L_AMPM_OVERRIDE
L_AMPM_OVERRIDE (cpm, ch)
#else
r = -1;
func = FindUserFunc("subst_ampm");
if (func && check_subst_args(func, 1)) {
@@ -158,18 +143,14 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
}
DestroyValue(v);
} else {
Eprint("%s", ErrMsg[r]);
Eprint("%s", GetErr(r));
}
}
if (r != OK) {
cpm = (h < 12) ? DynamicAm : DynamicPm;
cpm = (h < 12) ? tr("am") : tr("pm");
}
#endif
chh = (ch == 12) ? 12 : ch % 12;
#ifdef L_ORDINAL_OVERRIDE
L_ORDINAL_OVERRIDE;
#else
func = FindUserFunc("subst_ordinal");
if (func && check_subst_args(func, 1)) {
snprintf(s, sizeof(s), "subst_ordinal(%d)", d);
@@ -184,7 +165,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
}
DestroyValue(v);
} else {
Eprint("%s", ErrMsg[r]);
Eprint("%s", GetErr(r));
}
}
if (r != OK) {
@@ -202,7 +183,6 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
default: plu = "th"; break;
}
}
#endif
while(1) {
c = ParseChar(p, &err, 0);
@@ -235,6 +215,66 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
if (!c) {
break;
}
if (c == '<') {
DynamicBuffer header;
char const *val;
DBufInit(&header);
while(1) {
c = ParseChar(p, &err, 0);
if (err) {
DBufFree(&header);
return err;
}
if (!c || c == '>') {
break;
}
DBufPutc(&header, c);
}
if (!c) {
Wprint(tr("Warning: Unterminated %%<...> substitution sequence"));
}
err = OK;
val = FindTrigInfo(t, DBufValue(&header));
DBufFree(&header);
if (val) {
SHIP_OUT(val);
}
continue;
}
if (c == '(') {
DynamicBuffer orig;
DynamicBuffer translated;
DBufInit(&orig);
DBufInit(&translated);
while(1) {
c = ParseChar(p, &err, 0);
if (err) {
DBufFree(&orig);
return err;
}
if (!c || c == ')') {
break;
}
DBufPutc(&orig, c);
}
if (!c) {
Wprint(tr("Warning: Unterminated %%(...) substitution sequence"));
}
err = OK;
if (GetTranslatedStringTryingVariants(DBufValue(&orig), &translated)) {
err = DBufPuts(dbuf, DBufValue(&translated));
} else {
err = DBufPuts(dbuf, DBufValue(&orig));
}
if (DebugFlag & DB_TRANSLATE) {
TranslationTemplate(DBufValue(&orig));
}
DBufFree(&orig);
DBufFree(&translated);
if (err) return err;
continue;
}
if (c == '*') {
altmode = c;
c = ParseChar(p, &err, 0);
@@ -265,11 +305,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
}
}
if (!c) {
Wprint("Warning: Unterminated %%{...} substitution sequence");
Wprint(tr("Warning: Unterminated %%{...} substitution sequence"));
}
func = FindUserFunc(s);
if (!func) {
Wprint("No substition function `%s' defined", s);
Wprint(tr("No substition function `%s' defined"), s);
continue;
}
@@ -312,52 +352,26 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
}
DestroyValue(v);
} else {
Eprint("%s", ErrMsg[r]);
Eprint("%s", GetErr(r));
}
}
if (diff <= 1) {
switch(UPPER(c)) {
#ifndef L_NOTOMORROW_A
case 'A':
#endif
#ifndef L_NOTOMORROW_B
case 'B':
#endif
#ifndef L_NOTOMORROW_C
case 'C':
#endif
#ifndef L_NOTOMORROW_E
case 'E':
#endif
#ifndef L_NOTOMORROW_F
case 'F':
#endif
#ifndef L_NOTOMORROW_G
case 'G':
#endif
#ifndef L_NOTOMORROW_H
case 'H':
#endif
#ifndef L_NOTOMORROW_I
case 'I':
#endif
#ifndef L_NOTOMORROW_J
case 'J':
#endif
#ifndef L_NOTOMORROW_K
case 'K':
#endif
#ifndef L_NOTOMORROW_L
case 'L':
#endif
#ifndef L_NOTOMORROW_U
case 'U':
#endif
#ifndef L_NOTOMORROW_V
case 'V':
#endif
snprintf(s, sizeof(s), "%s", (diff ? DynamicTomorrow: DynamicToday));
snprintf(s, sizeof(s), "%s", (diff ? tr("tomorrow") : tr("today")));
SHIP_OUT(s);
done = 1;
break;
@@ -388,436 +402,279 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
}
DestroyValue(v);
} else {
Eprint("%s", ErrMsg[r]);
Eprint("%s", GetErr(r));
}
}
switch(UPPER(c)) {
case 'A':
#ifdef L_A_OVER
L_A_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%s, %d %s, %d", get_day_name(dse%7), d,
get_month_name(m), y);
} else {
snprintf(s, sizeof(s), "%s %s, %d %s, %d", DynamicOn, get_day_name(dse%7), d,
get_month_name(m), y);
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%s, %d %s, %d", get_day_name(dse%7), d,
get_month_name(m), y);
} else {
snprintf(s, sizeof(s), "%s %s, %d %s, %d", tr("on"), get_day_name(dse%7), d,
get_month_name(m), y);
}
SHIP_OUT(s);
break;
case 'B':
#ifdef L_B_OVER
L_B_OVER
#else
snprintf(s, sizeof(s), L_INXDAYS, diff);
#endif
snprintf(s, sizeof(s), "in %d days' time", diff);
SHIP_OUT(s);
break;
case 'C':
#ifdef L_C_OVER
L_C_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%s", get_day_name(dse%7));
} else {
snprintf(s, sizeof(s), "%s %s", DynamicOn, get_day_name(dse%7));
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%s", get_day_name(dse%7));
} else {
snprintf(s, sizeof(s), "%s %s", tr("on"), get_day_name(dse%7));
}
SHIP_OUT(s);
break;
case 'D':
#ifdef L_D_OVER
L_D_OVER
#else
snprintf(s, sizeof(s), "%d", d);
#endif
snprintf(s, sizeof(s), "%d", d);
SHIP_OUT(s);
break;
case 'E':
#ifdef L_E_OVER
L_E_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%02d%c%02d%c%04d", d, DateSep,
m+1, DateSep, y);
} else {
snprintf(s, sizeof(s), "%s %02d%c%02d%c%04d", DynamicOn, d, DateSep,
m+1, DateSep, y);
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%02d%c%02d%c%04d", d, DateSep,
m+1, DateSep, y);
} else {
snprintf(s, sizeof(s), "%s %02d%c%02d%c%04d", tr("on"), d, DateSep,
m+1, DateSep, y);
}
SHIP_OUT(s);
break;
case 'F':
#ifdef L_F_OVER
L_F_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%02d%c%02d%c%04d", m+1, DateSep, d, DateSep, y);
} else {
snprintf(s, sizeof(s), "%s %02d%c%02d%c%04d", DynamicOn, m+1, DateSep, d, DateSep, y);
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%02d%c%02d%c%04d", m+1, DateSep, d, DateSep, y);
} else {
snprintf(s, sizeof(s), "%s %02d%c%02d%c%04d", tr("on"), m+1, DateSep, d, DateSep, y);
}
SHIP_OUT(s);
break;
case 'G':
#ifdef L_G_OVER
L_G_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%s, %d %s", get_day_name(dse%7), d, get_month_name(m));
} else {
snprintf(s, sizeof(s), "%s %s, %d %s", DynamicOn, get_day_name(dse%7), d, get_month_name(m));
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%s, %d %s", get_day_name(dse%7), d, get_month_name(m));
} else {
snprintf(s, sizeof(s), "%s %s, %d %s", tr("on"), get_day_name(dse%7), d, get_month_name(m));
}
SHIP_OUT(s);
break;
case 'H':
#ifdef L_H_OVER
L_H_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%02d%c%02d", d, DateSep, m+1);
} else {
snprintf(s, sizeof(s), "%s %02d%c%02d", DynamicOn, d, DateSep, m+1);
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%02d%c%02d", d, DateSep, m+1);
} else {
snprintf(s, sizeof(s), "%s %02d%c%02d", tr("on"), d, DateSep, m+1);
}
SHIP_OUT(s);
break;
case 'I':
#ifdef L_I_OVER
L_I_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%02d%c%02d", m+1, DateSep, d);
} else {
snprintf(s, sizeof(s), "%s %02d%c%02d", DynamicOn, m+1, DateSep, d);
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%02d%c%02d", m+1, DateSep, d);
} else {
snprintf(s, sizeof(s), "%s %02d%c%02d", tr("on"), m+1, DateSep, d);
}
SHIP_OUT(s);
break;
case 'J':
#ifdef L_J_OVER
L_J_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%s, %s %d%s, %d", get_day_name(dse%7),
get_month_name(m), d, plu, y);
} else {
snprintf(s, sizeof(s), "%s %s, %s %d%s, %d", DynamicOn, get_day_name(dse%7),
get_month_name(m), d, plu, y);
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%s, %s %d%s, %d", get_day_name(dse%7),
get_month_name(m), d, plu, y);
} else {
snprintf(s, sizeof(s), "%s %s, %s %d%s, %d", tr("on"), get_day_name(dse%7),
get_month_name(m), d, plu, y);
}
SHIP_OUT(s);
break;
case 'K':
#ifdef L_K_OVER
L_K_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%s, %s %d%s", get_day_name(dse%7),
get_month_name(m), d, plu);
} else {
snprintf(s, sizeof(s), "%s %s, %s %d%s", DynamicOn, get_day_name(dse%7),
get_month_name(m), d, plu);
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%s, %s %d%s", get_day_name(dse%7),
get_month_name(m), d, plu);
} else {
snprintf(s, sizeof(s), "%s %s, %s %d%s", tr("on"), get_day_name(dse%7),
get_month_name(m), d, plu);
}
SHIP_OUT(s);
break;
case 'L':
#ifdef L_L_OVER
L_L_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d);
} else {
snprintf(s, sizeof(s), "%s %04d%c%02d%c%02d", DynamicOn, y, DateSep, m+1, DateSep, d);
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d);
} else {
snprintf(s, sizeof(s), "%s %04d%c%02d%c%02d", tr("on"), y, DateSep, m+1, DateSep, d);
}
SHIP_OUT(s);
break;
case 'M':
#ifdef L_M_OVER
L_M_OVER
#else
snprintf(s, sizeof(s), "%s", get_month_name(m));
#endif
snprintf(s, sizeof(s), "%s", get_month_name(m));
SHIP_OUT(s);
break;
case 'N':
#ifdef L_N_OVER
L_N_OVER
#else
snprintf(s, sizeof(s), "%d", m+1);
#endif
snprintf(s, sizeof(s), "%d", m+1);
SHIP_OUT(s);
break;
case 'O':
#ifdef L_O_OVER
L_O_OVER
#else
if (RealToday == DSEToday) snprintf(s, sizeof(s), " (%s)", DynamicToday);
else *s = 0;
#endif
if (RealToday == DSEToday) snprintf(s, sizeof(s), " (%s)", tr("today"));
else *s = 0;
SHIP_OUT(s);
break;
case 'P':
#ifdef L_P_OVER
L_P_OVER
#else
snprintf(s, sizeof(s), "%s", (diff == 1 ? "" : L_PLURAL));
#endif
snprintf(s, sizeof(s), "%s", (diff == 1 ? "" : "s"));
SHIP_OUT(s);
break;
case 'Q':
#ifdef L_Q_OVER
L_Q_OVER
#else
snprintf(s, sizeof(s), "%s", (diff == 1 ? "'s" : "s'"));
#endif
snprintf(s, sizeof(s), "%s", (diff == 1 ? "'s" : "s'"));
SHIP_OUT(s);
break;
case 'R':
#ifdef L_R_OVER
L_R_OVER
#else
snprintf(s, sizeof(s), "%02d", d);
#endif
snprintf(s, sizeof(s), "%02d", d);
SHIP_OUT(s);
break;
case 'S':
#ifdef L_S_OVER
L_S_OVER
#else
snprintf(s, sizeof(s), "%s", plu);
#endif
snprintf(s, sizeof(s), "%s", plu);
SHIP_OUT(s);
break;
case 'T':
#ifdef L_T_OVER
L_T_OVER
#else
snprintf(s, sizeof(s), "%02d", m+1);
#endif
snprintf(s, sizeof(s), "%02d", m+1);
SHIP_OUT(s);
break;
case 'U':
#ifdef L_U_OVER
L_U_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%s, %d%s %s, %d", get_day_name(dse%7), d,
plu, get_month_name(m), y);
} else {
snprintf(s, sizeof(s), "%s %s, %d%s %s, %d", DynamicOn, get_day_name(dse%7), d,
plu, get_month_name(m), y);
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%s, %d%s %s, %d", get_day_name(dse%7), d,
plu, get_month_name(m), y);
} else {
snprintf(s, sizeof(s), "%s %s, %d%s %s, %d", tr("on"), get_day_name(dse%7), d,
plu, get_month_name(m), y);
}
SHIP_OUT(s);
break;
case 'V':
#ifdef L_V_OVER
L_V_OVER
#else
if (altmode == '*' || !strcmp(DynamicOn, "")) {
snprintf(s, sizeof(s), "%s, %d%s %s", get_day_name(dse%7), d, plu,
get_month_name(m));
} else {
snprintf(s, sizeof(s), "%s %s, %d%s %s", DynamicOn, get_day_name(dse%7), d, plu,
get_month_name(m));
}
#endif
if (altmode == '*' || !strcmp(tr("on"), "")) {
snprintf(s, sizeof(s), "%s, %d%s %s", get_day_name(dse%7), d, plu,
get_month_name(m));
} else {
snprintf(s, sizeof(s), "%s %s, %d%s %s", tr("on"), get_day_name(dse%7), d, plu,
get_month_name(m));
}
SHIP_OUT(s);
break;
case 'W':
#ifdef L_W_OVER
L_W_OVER
#else
snprintf(s, sizeof(s), "%s", get_day_name(dse%7));
#endif
snprintf(s, sizeof(s), "%s", get_day_name(dse%7));
SHIP_OUT(s);
break;
case 'X':
#ifdef L_X_OVER
L_X_OVER
#else
snprintf(s, sizeof(s), "%d", diff);
#endif
snprintf(s, sizeof(s), "%d", diff);
SHIP_OUT(s);
break;
case 'Y':
#ifdef L_Y_OVER
L_Y_OVER
#else
snprintf(s, sizeof(s), "%d", y);
#endif
snprintf(s, sizeof(s), "%d", y);
SHIP_OUT(s);
break;
case 'Z':
#ifdef L_Z_OVER
L_Z_OVER
#else
snprintf(s, sizeof(s), "%d", y % 100);
#endif
snprintf(s, sizeof(s), "%d", y % 100);
SHIP_OUT(s);
break;
case '1':
#ifdef L_1_OVER
L_1_OVER
#else
if (tdiff == 0)
snprintf(s, sizeof(s), "%s", DynamicNow);
else if (hdiff == 0)
snprintf(s, sizeof(s), "%d %s%s %s", mdiff, DynamicMinute, mplu, when);
else if (mdiff == 0)
snprintf(s, sizeof(s), "%d %s%s %s", hdiff, DynamicHour, hplu, when);
else
snprintf(s, sizeof(s), "%d %s%s %s %d %s%s %s", hdiff, DynamicHour, hplu,
DynamicAnd, mdiff, DynamicMinute, mplu, when);
#endif
if (tdiff == 0)
snprintf(s, sizeof(s), "%s", tr("now"));
else if (hdiff == 0)
snprintf(s, sizeof(s), "%d %s%s %s", mdiff, tr("minute"), mplu, when);
else if (mdiff == 0)
snprintf(s, sizeof(s), "%d %s%s %s", hdiff, tr("hour"), hplu, when);
else
snprintf(s, sizeof(s), "%d %s%s %s %d %s%s %s", hdiff, tr("hour"), hplu,
tr("and"), mdiff, tr("minute"), mplu, when);
SHIP_OUT(s);
break;
case '2':
#ifdef L_2_OVER
L_2_OVER
#else
if (altmode == '*') {
snprintf(s, sizeof(s), "%d%c%02d%s", hh, TimeSep, min, pm);
} else {
snprintf(s, sizeof(s), "%s %d%c%02d%s", DynamicAt, hh, TimeSep, min, pm);
}
#endif
if (altmode == '*') {
snprintf(s, sizeof(s), "%d%c%02d%s", hh, TimeSep, min, pm);
} else {
snprintf(s, sizeof(s), "%s %d%c%02d%s", tr("at"), hh, TimeSep, min, pm);
}
SHIP_OUT(s);
break;
case '3':
#ifdef L_3_OVER
L_3_OVER
#else
if (altmode == '*') {
snprintf(s, sizeof(s), "%02d%c%02d", h, TimeSep, min);
} else {
snprintf(s, sizeof(s), "%s %02d%c%02d", DynamicAt, h, TimeSep, min);
}
#endif
if (altmode == '*') {
snprintf(s, sizeof(s), "%02d%c%02d", h, TimeSep, min);
} else {
snprintf(s, sizeof(s), "%s %02d%c%02d", tr("at"), h, TimeSep, min);
}
SHIP_OUT(s);
break;
case '4':
#ifdef L_4_OVER
L_4_OVER
#else
snprintf(s, sizeof(s), "%d", tdiff);
#endif
snprintf(s, sizeof(s), "%d", tdiff);
SHIP_OUT(s);
break;
case '5':
#ifdef L_5_OVER
L_5_OVER
#else
snprintf(s, sizeof(s), "%d", adiff);
#endif
snprintf(s, sizeof(s), "%d", adiff);
SHIP_OUT(s);
break;
case '6':
#ifdef L_6_OVER
L_6_OVER
#else
snprintf(s, sizeof(s), "%s", when);
#endif
snprintf(s, sizeof(s), "%s", when);
SHIP_OUT(s);
break;
case '7':
#ifdef L_7_OVER
L_7_OVER
#else
snprintf(s, sizeof(s), "%d", hdiff);
#endif
snprintf(s, sizeof(s), "%d", hdiff);
SHIP_OUT(s);
break;
case '8':
#ifdef L_8_OVER
L_8_OVER
#else
snprintf(s, sizeof(s), "%d", mdiff);
#endif
snprintf(s, sizeof(s), "%d", mdiff);
SHIP_OUT(s);
break;
case '9':
#ifdef L_9_OVER
L_9_OVER
#else
snprintf(s, sizeof(s), "%s", mplu);
#endif
snprintf(s, sizeof(s), "%s", mplu);
SHIP_OUT(s);
break;
case '0':
#ifdef L_0_OVER
L_0_OVER
#else
snprintf(s, sizeof(s), "%s", hplu);
#endif
snprintf(s, sizeof(s), "%s", hplu);
SHIP_OUT(s);
break;
case '!':
#ifdef L_BANG_OVER
L_BANG_OVER
#else
snprintf(s, sizeof(s), "%s", (tdiff >= 0 ? DynamicIs : DynamicWas));
#endif
snprintf(s, sizeof(s), "%s", (tdiff >= 0 ? tr("is") : tr("was")));
SHIP_OUT(s);
break;
case '@':
#ifdef L_AT_OVER
L_AT_OVER
#else
snprintf(s, sizeof(s), "%d%c%02d%s", chh, TimeSep, cmin, cpm);
#endif
snprintf(s, sizeof(s), "%d%c%02d%s", chh, TimeSep, cmin, cpm);
SHIP_OUT(s);
break;
case '#':
#ifdef L_HASH_OVER
L_HASH_OVER
#else
snprintf(s, sizeof(s), "%02d%c%02d", ch, TimeSep, cmin);
#endif
snprintf(s, sizeof(s), "%02d%c%02d", ch, TimeSep, cmin);
SHIP_OUT(s);
break;
@@ -914,7 +771,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
/* */
/***************************************************************/
int DoSubstFromString(char const *source, DynamicBuffer *dbuf,
int dse, int tim)
int dse, int tim)
{
Trigger tempTrig;
TimeTrig tempTime;
@@ -925,6 +782,8 @@ int DoSubstFromString(char const *source, DynamicBuffer *dbuf,
if (tim == NO_TIME) tim=MinutesPastMidnight(0);
CreateParser(source, &tempP);
tempP.allownested = 0;
tempTrig.infos = NULL;
DBufInit(&tempTrig.tags);
tempTrig.typ = MSG_TYPE;
tempTime.ttime = tim;

View File

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

View File

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

View File

@@ -5,7 +5,7 @@
/* Error definitions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -13,31 +13,35 @@
/* Note that not all of the "errors" are really errors - some are just
messages for information purposes. Constants beginning with M_ should
never be returned as error indicators - they should only be used to
index the ErrMsg array. */
index the ErrMsg array.
Some #defines are commented out; these are former error codes that are
no longer used. They are left as placeholders because renumbering
everything wouild be too tedious */
#define OK 0
#define E_MISS_END 1
#define E_MISS_QUOTE 2
#define E_OP_STK_OVER 3
#define E_VA_STK_OVER 4
/* #define E_VA_STK_OVER 4 */
#define E_MISS_RIGHT_PAREN 5
#define E_UNDEF_FUNC 6
#define E_ILLEGAL_CHAR 7
#define E_EXPECTING_BINOP 8
/* #define E_EXPECTING_BINOP 8 */
#define E_NO_MEM 9
#define E_BAD_NUMBER 10
#define E_OP_STK_UNDER 11
#define E_VA_STK_UNDER 12
/* #define E_OP_STK_UNDER 11 */
/* #define E_VA_STK_UNDER 12 */
#define E_CANT_COERCE 13
#define E_BAD_TYPE 14
#define E_DATE_OVER 15
#define E_STACK_ERR 16
/* #define E_STACK_ERR 16 */
#define E_DIV_ZERO 17
#define E_NOSUCH_VAR 18
#define E_EOLN 19
#define E_EOF 20
#define E_IO_ERR 21
#define E_LINE_2_LONG 22
/* #define E_LINE_2_LONG 22 */
#define E_SWERR 23
#define E_BAD_DATE 24
#define E_2FEW_ARGS 25
@@ -72,7 +76,7 @@
#define E_DAY_TWICE 52
#define E_UNKNOWN_TOKEN 53
#define E_SPEC_MON 54
#define E_2MANY_PART 55
/* #define E_2MANY_PART 55 */
#define E_2MANY_FULL 56
#define E_PUSH_NOPOP 57
#define E_ERR_READING 58
@@ -110,7 +114,7 @@
#define E_MISS_EQ 90
#define E_MISS_VAR 91
#define E_MISS_EXPR 92
#define M_CANTSET_ACCESS 93
/* #define M_CANTSET_ACCESS 93 */
#define M_I_OPTION 94
#define E_NOREMINDERS 95
#define M_QUEUED 96
@@ -147,25 +151,25 @@ EXTERN char *ErrMsg[]
/* E_MISS_END */ "Missing ']'",
/* E_MISS_QUOTE */ "Missing quote",
/* E_OP_STK_OVER */ "Expression too complex",
/* E_VA_STK_OVER */ "Expression too complex - too many operands",
/* E_VA_STK_OVER */ "",
/* E_MISS_RIGHT_PAREN */ "Missing ')'",
/* E_UNDEF_FUNC */ "Undefined function",
/* E_ILLEGAL_CHAR */ "Illegal character",
/* E_EXPECTING_BINOP */ "Expecting binary operator",
/* E_NO_MEM */ "Out of memory",
/* E_BAD_NUMBER */ "Ill-formed number",
/* E_OP_STK_UNDER */ "Op stack underflow - internal error",
/* E_VA_STK_UNDER */ "Va stack underflow - internal error",
/* E_OP_STK_UNDER */ "",
/* E_VA_STK_UNDER */ "",
/* E_CANT_COERCE */ "Can't coerce",
/* E_BAD_TYPE */ "Type mismatch",
/* E_DATE_OVER */ "Date overflow",
/* E_STACK_ERR */ "Stack error - internal error",
/* E_STACK_ERR */ "",
/* E_DIV_ZERO */ "Division by zero",
/* E_NOSUCH_VAR */ "Undefined variable",
/* E_EOLN */ "Unexpected end of line",
/* E_EOF */ "Unexpected end of file",
/* E_IO_ERR */ "I/O error",
/* E_LINE_2_LONG */ "Line too long",
/* E_LINE_2_LONG */ "",
/* E_SWERR */ "Internal error",
/* E_BAD_DATE */ "Bad date specification",
/* E_2FEW_ARGS */ "Not enough arguments",
@@ -198,7 +202,7 @@ EXTERN char *ErrMsg[]
/* E_DAY_TWICE */ "Day specified twice",
/* E_UNKNOWN_TOKEN */ "Unknown token",
/* E_SPEC_MON */ "Must specify month in OMIT command",
/* E_2MANY_PART */ "Too many partial OMITs (max. " STR(MAX_PARTIAL_OMITS) ")",
/* E_2MANY_PART */ "",
/* E_2MANY_FULL */ "Too many full OMITs (max. " STR(MAX_FULL_OMITS) ")",
/* E_PUSH_NOPOP */ "Warning: PUSH-OMIT-CONTEXT without matching POP-OMIT-CONTEXT",
/* E_ERR_READING */ "Error reading",
@@ -226,20 +230,20 @@ EXTERN char *ErrMsg[]
/* E_EXPIRED */ "Expired",
/* E_CANTFORK */ "fork() failed - can't do queued reminders",
/* E_CANTACCESS */ "Can't access file",
/* M_BAD_SYS_DATE */ "Illegal system date: Year is less than %d\n",
/* M_BAD_DB_FLAG */ "Unknown debug flag '%c'\n",
/* M_BAD_OPTION */ "Unknown option '%c'\n",
/* M_BAD_USER */ "Unknown user '%s'\n",
/* M_NO_CHG_GID */ "Could not change gid to %d\n",
/* M_NO_CHG_UID */ "Could not change uid to %d\n",
/* M_NOMEM_ENV */ "Out of memory for environment\n",
/* M_BAD_SYS_DATE */ "Illegal system date: Year is less than %d",
/* M_BAD_DB_FLAG */ "Unknown debug flag '%c'",
/* M_BAD_OPTION */ "Unknown option '%c'",
/* M_BAD_USER */ "Unknown user '%s'",
/* M_NO_CHG_GID */ "Could not change gid to %d",
/* M_NO_CHG_UID */ "Could not change uid to %d",
/* M_NOMEM_ENV */ "Out of memory for environment",
/* E_MISS_EQ */ "Missing '=' sign",
/* E_MISS_VAR */ "Missing variable name",
/* E_MISS_EXPR */ "Missing expression",
/* M_CANTSET_ACCESS */ "Can't reset access date of %s\n",
/* M_I_OPTION */ "Remind: '-i' option: %s\n",
/* M_CANTSET_ACCESS */ "",
/* M_I_OPTION */ "Remind: '-i' option: %s",
/* E_NOREMINDERS */ "No reminders.",
/* M_QUEUED */ "%d reminder(s) queued for later today.\n",
/* M_QUEUED */ "%d reminder(s) queued for later today.",
/* E_EXPECTING_NUMBER */ "Expecting number",
/* M_BAD_WARN_FUNC */ "Undefined WARN function",
/* E_CANT_CONVERT_TZ */ "Can't convert between time zones",
@@ -255,3 +259,9 @@ EXTERN char *ErrMsg[]
#endif /* MK_GLOBALS */
;
#endif /* L_ERR_OVERRIDE */
EXTERN int NumErrs
#ifdef MK_GLOBALS
= sizeof(ErrMsg) / sizeof(ErrMsg[0])
#endif
;

View File

@@ -12,7 +12,7 @@
/* evaluated. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -199,6 +199,46 @@ static UserFunc *CurrentUserFunc = NULL;
/* How many expr_node objects to allocate at a time */
#define ALLOC_CHUNK 64
static char const *
find_end_of_expr(char const *s)
{
char const *e = s;
int in_quoted_string = 0;
int escaped = 0;
while(*e) {
if (in_quoted_string) {
if (escaped) {
escaped = 0;
e++;
continue;
}
if (*e == '\\') {
escaped = 1;
e++;
continue;
}
if (*e == '"') {
in_quoted_string = 0;
e++;
continue;
}
e++;
continue;
}
if (*e == '"') {
in_quoted_string = 1;
e++;
continue;
}
if (*e == ']') {
break;
}
e++;
}
return e;
}
/***************************************************************/
/* */
/* alloc_expr_node - allocate an expr_node object */
@@ -282,7 +322,7 @@ debug_evaluation(Value *ans, int r, char const *fmt, ...)
vfprintf(ErrFp, fmt, argptr);
fprintf(ErrFp, " => ");
if (r != OK) {
fprintf(ErrFp, "%s\n", ErrMsg[r]);
fprintf(ErrFp, "%s\n", GetErr(r));
} else {
PrintValue(ans, ErrFp);
fprintf(ErrFp, "\n");
@@ -321,7 +361,7 @@ debug_evaluation_binop(Value *ans, int r, Value *v1, Value *v2, char const *fmt,
}
fprintf(ErrFp, " => ");
if (r != OK) {
fprintf(ErrFp, "%s\n", ErrMsg[r]);
fprintf(ErrFp, "%s\n", GetErr(r));
} else {
PrintValue(ans, ErrFp);
fprintf(ErrFp, "\n");
@@ -353,7 +393,7 @@ debug_evaluation_unop(Value *ans, int r, Value *v1, char const *fmt, ...)
}
fprintf(ErrFp, " => ");
if (r != OK) {
fprintf(ErrFp, "%s\n", ErrMsg[r]);
fprintf(ErrFp, "%s\n", GetErr(r));
} else {
PrintValue(ans, ErrFp);
fprintf(ErrFp, "\n");
@@ -426,11 +466,11 @@ eval_builtin(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* Check that we have the right number of argumens */
if (node->num_kids < f->minargs) {
Eprint("%s(): %s", f->name, ErrMsg[E_2FEW_ARGS]);
Eprint("%s(): %s", f->name, GetErr(E_2FEW_ARGS));
return E_2FEW_ARGS;
}
if (node->num_kids > f->maxargs && f->maxargs != NO_MAX) {
Eprint("%s(): %s", f->name, ErrMsg[E_2MANY_ARGS]);
Eprint("%s(): %s", f->name, GetErr(E_2MANY_ARGS));
return E_2MANY_ARGS;
}
@@ -506,14 +546,14 @@ eval_builtin(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* Debug */
if (DebugFlag & DB_PRTEXPR) {
if (r) {
fprintf(ErrFp, "%s", ErrMsg[r]);
fprintf(ErrFp, "%s", GetErr(r));
} else {
PrintValue(ans, ErrFp);
}
fprintf(ErrFp, "\n");
}
if (r != OK) {
Eprint("%s(): %s", f->name, ErrMsg[r]);
Eprint("%s(): %s", f->name, GetErr(r));
}
/* Clean up */
if (info.args) {
@@ -546,7 +586,7 @@ debug_enter_userfunc(expr_node *node, Value *locals, int nargs)
} else {
fname = node->u.value.v.str;
}
fprintf(ErrFp, "%s %s(", ErrMsg[E_ENTER_FUN], fname);
fprintf(ErrFp, "%s %s(", GetErr(E_ENTER_FUN), fname);
for (i=0; i<nargs; i++) {
if (i) fprintf(ErrFp, ", ");
PrintValue(&(locals[i]), ErrFp);
@@ -572,7 +612,7 @@ debug_exit_userfunc(expr_node *node, Value *ans, int r, Value *locals, int nargs
} else {
fname = node->u.value.v.str;
}
fprintf(ErrFp, "%s %s(", ErrMsg[E_LEAVE_FUN], fname);
fprintf(ErrFp, "%s %s(", GetErr(E_LEAVE_FUN), fname);
for (i=0; i<nargs; i++) {
if (i) fprintf(ErrFp, ", ");
PrintValue(&(locals[i]), ErrFp);
@@ -581,7 +621,7 @@ debug_exit_userfunc(expr_node *node, Value *ans, int r, Value *locals, int nargs
if (r == OK) {
PrintValue(ans, ErrFp);
} else {
fprintf(ErrFp, "%s", ErrMsg[r]);
fprintf(ErrFp, "%s", GetErr(r));
}
fprintf(ErrFp, "\n");
}
@@ -621,19 +661,19 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* Bail if function does not exist */
if (!f) {
Eprint("%s: `%s'", ErrMsg[E_UNDEF_FUNC], fname);
Eprint("%s: `%s'", GetErr(E_UNDEF_FUNC), fname);
return E_UNDEF_FUNC;
}
/* Make sure we have the right number of arguments */
if (node->num_kids < f->nargs) {
DBG(fprintf(ErrFp, "%s(...) => %s\n", fname, ErrMsg[E_2FEW_ARGS]));
Eprint("%s(): %s", f->name, ErrMsg[E_2FEW_ARGS]);
DBG(fprintf(ErrFp, "%s(...) => %s\n", fname, GetErr(E_2FEW_ARGS)));
Eprint("%s(): %s", f->name, GetErr(E_2FEW_ARGS));
return E_2FEW_ARGS;
}
if (node->num_kids > f->nargs) {
DBG(fprintf(ErrFp, "%s(...) => %s\n", fname, ErrMsg[E_2MANY_ARGS]));
Eprint("%s(): %s", f->name, ErrMsg[E_2MANY_ARGS]);
DBG(fprintf(ErrFp, "%s(...) => %s\n", fname, GetErr(E_2MANY_ARGS)));
Eprint("%s(): %s", f->name, GetErr(E_2MANY_ARGS));
return E_2MANY_ARGS;
}
@@ -643,7 +683,7 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* Too many args to fit on stack; put on heap */
new_locals = malloc(node->num_kids * sizeof(Value));
if (!new_locals) {
DBG(fprintf(ErrFp, "%s(...) => %s\n", fname, ErrMsg[E_NO_MEM]));
DBG(fprintf(ErrFp, "%s(...) => %s\n", fname, GetErr(E_NO_MEM)));
return E_NO_MEM;
}
} else {
@@ -694,7 +734,7 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
if (r != OK) {
/* We print the error here in order to get the call stack trace */
Eprint("%s", ErrMsg[r]);
Eprint("%s", GetErr(r));
}
if (pushed == OK) pop_call();
@@ -850,7 +890,7 @@ evaluate_expr_node(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* Operator? Evaluate it */
r = node->u.operator_func(node, locals, ans, nonconst);
if (r != OK) {
Eprint("`%s': %s", get_operator_name(node), ErrMsg[r]);
Eprint("`%s': %s", get_operator_name(node), GetErr(r));
}
return r;
}
@@ -1506,6 +1546,8 @@ static int parse_expr_token(DynamicBuffer *buf, char const **in)
{
char c;
char c2;
char hexbuf[3];
DBufFree(buf);
@@ -1541,7 +1583,7 @@ static int parse_expr_token(DynamicBuffer *buf, char const **in)
}
(*in)++;
} else {
Eprint("%s `%c' (did you mean `%c%c'?)", ErrMsg[E_PARSE_ERR], c, c, c);
Eprint("%s `%c' (%s `%c%c'?)", GetErr(E_PARSE_ERR), c, tr("did you mean"), c, c);
return E_PARSE_ERR;
}
return OK;
@@ -1593,8 +1635,32 @@ static int parse_expr_token(DynamicBuffer *buf, char const **in)
case 'v':
r = DBufPutc(buf, '\v');
break;
case 'x':
c2 = *(*in + 1);
if (!isxdigit(c2)) {
r = DBufPutc(buf, **in);
break;
}
hexbuf[0] = c2;
hexbuf[1] = 0;
(*in)++;
c2 = *(*in + 1);
if (isxdigit(c2)) {
hexbuf[1] = c2;
hexbuf[2] = 0;
(*in)++;
}
c2 = (int) strtol(hexbuf, NULL, 16);
if (!c2) {
Eprint(tr("\\x00 is not a valid escape sequence"));
r = E_PARSE_ERR;
} else {
r = DBufPutc(buf, c2);
}
break;
default:
r = DBufPutc(buf, **in);
break;
}
(*in)++;
if (r != OK) {
@@ -1633,10 +1699,10 @@ static int parse_expr_token(DynamicBuffer *buf, char const **in)
if (!ISID(c) && c != '$') {
if (!c) {
Eprint("%s", ErrMsg[E_EOLN]);
Eprint("%s", GetErr(E_EOLN));
return E_EOLN;
}
Eprint("%s `%c'", ErrMsg[E_ILLEGAL_CHAR], c);
Eprint("%s `%c'", GetErr(E_ILLEGAL_CHAR), c);
return E_ILLEGAL_CHAR;
}
@@ -1831,14 +1897,14 @@ static expr_node * parse_function_call(char const **e, int *r, Var *locals, int
return free_expr_tree(node);
}
if (TOKEN_IS(")")) {
Eprint("%s `)'", ErrMsg[E_PARSE_ERR]);
Eprint("%s `)'", GetErr(E_PARSE_ERR));
*r = E_PARSE_ERR;
return free_expr_tree(node);
}
}
}
ptr = *e;
if (TOKEN_IS(")")) {
ptr = *e;
*r = GET_TOKEN();
if (*r != OK) {
return free_expr_tree(node);
@@ -1859,7 +1925,7 @@ static expr_node * parse_function_call(char const **e, int *r, Var *locals, int
if (*r != OK) {
if (node->type == N_BUILTIN_FUNC) {
f = node->u.builtin_func;
Eprint("%s: %s", f->name, ErrMsg[*r]);
Eprint("%s: %s", f->name, GetErr(*r));
}
return free_expr_tree(node);
}
@@ -1881,7 +1947,7 @@ static int set_constant_value(expr_node *atom)
atom->type = N_CONSTANT;
if (!*s) {
Eprint("%s", ErrMsg[E_EOLN]);
Eprint("%s", GetErr(E_EOLN));
return E_EOLN;
}
ampm = 0;
@@ -1905,15 +1971,15 @@ static int set_constant_value(expr_node *atom)
} else if (*s == '\'') { /* It's a literal date */
s++;
if ((r=ParseLiteralDateOrTime(&s, &dse, &tim)) != 0) {
Eprint("%s: %s", ErrMsg[r], DBufValue(&ExprBuf));
Eprint("%s: %s", GetErr(r), DBufValue(&ExprBuf));
return r;
}
if (*s != '\'') {
if (dse != NO_DATE) {
Eprint("%s: %s", ErrMsg[E_BAD_DATE], DBufValue(&ExprBuf));
Eprint("%s: %s", GetErr(E_BAD_DATE), DBufValue(&ExprBuf));
return E_BAD_DATE;
} else {
Eprint("%s: %s", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
Eprint("%s: %s", GetErr(E_BAD_TIME), DBufValue(&ExprBuf));
return E_BAD_TIME;
}
}
@@ -1944,7 +2010,7 @@ static int set_constant_value(expr_node *atom)
if (*s == ':' || *s == '.' || *s == TimeSep) { /* Must be a literal time */
s++;
if (!isdigit(*s)) {
Eprint("%s: `%s'", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
Eprint("%s: `%s'", GetErr(E_BAD_TIME), DBufValue(&ExprBuf));
return E_BAD_TIME;
}
h = val;
@@ -1963,12 +2029,12 @@ static int set_constant_value(expr_node *atom)
}
}
if (*s || h>23 || m>59) {
Eprint("%s: `%s'", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
Eprint("%s: `%s'", GetErr(E_BAD_TIME), DBufValue(&ExprBuf));
return E_BAD_TIME;
}
if (ampm) {
if (h < 1 || h > 12) {
Eprint("%s: `%s'", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
Eprint("%s: `%s'", GetErr(E_BAD_TIME), DBufValue(&ExprBuf));
return E_BAD_TIME;
}
if (ampm == 'a') {
@@ -1987,7 +2053,7 @@ static int set_constant_value(expr_node *atom)
}
/* Not a time - must be a number */
if (*s) {
Eprint("%s: `%s'", ErrMsg[E_BAD_NUMBER], DBufValue(&ExprBuf));
Eprint("%s: `%s'", GetErr(E_BAD_NUMBER), DBufValue(&ExprBuf));
return E_BAD_NUMBER;
}
atom->u.value.type = INT_TYPE;
@@ -1995,7 +2061,7 @@ static int set_constant_value(expr_node *atom)
return OK;
}
atom->u.value.type = ERR_TYPE;
Eprint("`%s': %s", DBufValue(&ExprBuf), ErrMsg[E_ILLEGAL_CHAR]);
Eprint("`%s': %s", DBufValue(&ExprBuf), GetErr(E_ILLEGAL_CHAR));
return E_ILLEGAL_CHAR;
}
@@ -2037,7 +2103,7 @@ static int make_atom(expr_node *atom, Var *locals)
/* System Variable */
if (*(s) == '$' && isalpha(*(s+1))) {
if (!FindSysVar(s+1)) {
Eprint("%s: `%s'", ErrMsg[E_NOSUCH_VAR], s);
Eprint("%s: `%s'", GetErr(E_NOSUCH_VAR), s);
return E_NOSUCH_VAR;
}
if (strlen(s+1) < SHORT_NAME_BUF) {
@@ -2117,7 +2183,7 @@ static expr_node *parse_atom(char const **e, int *r, Var *locals, int level)
/* Check that it's a valid ID or constant */
s = DBufValue(&ExprBuf);
if (!*s) {
Eprint("%s", ErrMsg[E_EOLN]);
Eprint("%s", GetErr(E_EOLN));
*r = E_EOLN;
return NULL;
}
@@ -2126,7 +2192,7 @@ static expr_node *parse_atom(char const **e, int *r, Var *locals, int level)
*s != '$' &&
*s != '"' &&
*s != '\'') {
Eprint("%s `%c'", ErrMsg[E_ILLEGAL_CHAR], *s);
Eprint("%s `%c'", GetErr(E_ILLEGAL_CHAR), *s);
*r = E_ILLEGAL_CHAR;
return NULL;
}
@@ -2137,6 +2203,7 @@ static expr_node *parse_atom(char const **e, int *r, Var *locals, int level)
}
/* It's a constant or a variable reference */
char const *olds = *e;
*r = GET_TOKEN();
if (*r != OK) return NULL;
node = alloc_expr_node(r);
@@ -2145,6 +2212,8 @@ static expr_node *parse_atom(char const **e, int *r, Var *locals, int level)
}
*r = make_atom(node, locals);
if (*r != OK) {
/* Preserve location for error position when we print ^-- here */
*e = olds;
return free_expr_tree(node);
}
return node;
@@ -2498,6 +2567,7 @@ expr_node *parse_expression(char const **e, int *r, Var *locals)
{
char const *orig = *e;
char const *o2 = *e;
char const *end_of_expr;
if (ExpressionEvaluationDisabled) {
*r = E_EXPR_DISABLED;
return NULL;
@@ -2512,7 +2582,7 @@ expr_node *parse_expression(char const **e, int *r, Var *locals)
}
putc('\n', ErrFp);
if (*r != OK) {
fprintf(ErrFp, " => Error: %s\n", ErrMsg[*r]);
fprintf(ErrFp, " => Error: %s\n", GetErr(*r));
} else {
fprintf(ErrFp, " => ");
print_expr_tree(node, ErrFp);
@@ -2529,25 +2599,29 @@ expr_node *parse_expression(char const **e, int *r, Var *locals)
*r == E_2FEW_ARGS ||
*r == E_PARSE_ERR ||
*r == E_EOLN ||
*r == E_BAD_NUMBER ||
*r == E_BAD_DATE ||
*r == E_BAD_TIME ||
*r == E_ILLEGAL_CHAR) {
orig = o2;
while (*orig) {
end_of_expr = find_end_of_expr(orig);
while (**e && isempty(**e)) {
(*e)++;
}
while (*orig && ((orig < end_of_expr) || (orig <= *e))) {
if (*orig == '\n') {
fprintf(ErrFp, " ");
orig++;
} else if (*orig == ']' && ! *(orig+1)) {
break;
} else {
fprintf(ErrFp, "%c", *orig++);
fprintf(ErrFp, "%c", *orig);
}
orig++;
}
fprintf(ErrFp, "\n");
orig = o2;
while ((orig < *e) && *orig) {
while (*orig && (orig < *e || isspace(*orig))) {
orig++;
fprintf(ErrFp, " ");
}
fprintf(ErrFp, "^-- here\n");
fprintf(ErrFp, "^-- %s\n", tr("here"));
}
return node;
}
@@ -2966,12 +3040,12 @@ int DoCoerce(char type, Value *v)
}
case STR_TYPE:
switch(v->type) {
case INT_TYPE: sprintf(coerce_buf, "%d", v->v.val); break;
case TIME_TYPE: sprintf(coerce_buf, "%02d%c%02d", v->v.val / 60,
case INT_TYPE: snprintf(coerce_buf, sizeof(coerce_buf), "%d", v->v.val); break;
case TIME_TYPE: snprintf(coerce_buf, sizeof(coerce_buf), "%02d%c%02d", v->v.val / 60,
TimeSep, v->v.val % 60);
break;
case DATE_TYPE: FromDSE(v->v.val, &y, &m, &d);
sprintf(coerce_buf, "%04d%c%02d%c%02d",
snprintf(coerce_buf, sizeof(coerce_buf), "%04d%c%02d%c%02d",
y, DateSep, m+1, DateSep, d);
break;
case DATETIME_TYPE:
@@ -2980,7 +3054,7 @@ int DoCoerce(char type, Value *v)
k = v->v.val % MINUTES_PER_DAY;
h = k / 60;
i = k % 60;
sprintf(coerce_buf, "%04d%c%02d%c%02d%c%02d%c%02d",
snprintf(coerce_buf, sizeof(coerce_buf), "%04d%c%02d%c%02d%c%02d%c%02d",
y, DateSep, m+1, DateSep, d, DateTimeSep, h, TimeSep, i);
break;
default: return E_CANT_COERCE;
@@ -3088,10 +3162,10 @@ int DoCoerce(char type, Value *v)
/***************************************************************/
void print_expr_nodes_stats(void)
{
fprintf(stderr, " Expression nodes allocated: %d\n", ExprNodesAllocated);
fprintf(stderr, "Expression nodes high-water: %d\n", ExprNodesHighWater);
fprintf(stderr, " Expression nodes leaked: %d\n", ExprNodesUsed);
fprintf(stderr, " Parse level high-water: %d\n", parse_level_high_water);
fprintf(ErrFp, " Expression nodes allocated: %d\n", ExprNodesAllocated);
fprintf(ErrFp, "Expression nodes high-water: %d\n", ExprNodesHighWater);
fprintf(ErrFp, " Expression nodes leaked: %d\n", ExprNodesUsed);
fprintf(ErrFp, " Parse level high-water: %d\n", parse_level_high_water);
}
/* Return 1 if a value is "true" for its type, 0 if "false" */

View File

@@ -7,7 +7,7 @@
/* files. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -145,7 +145,8 @@ static void OpenPurgeFile(char const *fname, char const *mode)
if (DBufPuts(&fname_buf, ".purged") != OK) return;
PurgeFP = fopen(DBufValue(&fname_buf), mode);
if (!PurgeFP) {
fprintf(ErrFp, "Cannot open `%s' for writing: %s\n", DBufValue(&fname_buf), strerror(errno));
fprintf(ErrFp, tr("Cannot open `%s' for writing: %s"), DBufValue(&fname_buf), strerror(errno));
fprintf(ErrFp, "\n");
}
set_cloexec(PurgeFP);
DBufFree(&fname_buf);
@@ -325,7 +326,8 @@ int OpenFile(char const *fname)
while (h) {
if (!strcmp(fname, h->filename)) {
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Reading `%s': Found in cache\n", fname);
fprintf(ErrFp, tr("Reading `%s': Found in cache"), fname);
fprintf(ErrFp, "\n");
}
CLine = h->cache;
STRSET(FileName, fname);
@@ -348,13 +350,14 @@ int OpenFile(char const *fname)
PurgeFP = stdout;
}
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Reading `-': Reading stdin\n");
fprintf(ErrFp, "%s\n", tr("Reading `-': Reading stdin"));
}
} else {
fp = fopen(fname, "r");
set_cloexec(fp);
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Reading `%s': Opening file on disk\n", fname);
fprintf(ErrFp, tr("Reading `%s': Opening file on disk"), fname);
fprintf(ErrFp, "\n");
}
if (PurgeMode) {
OpenPurgeFile(fname, "w");
@@ -401,7 +404,8 @@ static int CacheFile(char const *fname, int use_pclose)
char const *s;
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Caching file `%s' in memory\n", fname);
fprintf(ErrFp, tr("Caching file `%s' in memory"), fname);
fprintf(ErrFp, "\n");
}
cl = NULL;
/* Create a file header */
@@ -519,7 +523,7 @@ static int NextChainedFile(IncludeStruct *i)
if (OpenFile(cur->filename) == OK) {
return OK;
} else {
Eprint("%s: %s", ErrMsg[E_CANT_OPEN], cur->filename);
Eprint("%s: %s", GetErr(E_CANT_OPEN), cur->filename);
}
}
return E_EOF;
@@ -537,9 +541,10 @@ static int PopFile(void)
int j;
if (!Hush && NumIfs) {
Eprint("%s", ErrMsg[E_MISS_ENDIF]);
Eprint("%s", GetErr(E_MISS_ENDIF));
for (j=NumIfs-1; j >=0; j--) {
fprintf(ErrFp, "%s(%d): IF without ENDIF\n", FileName, IfLinenos[j]);
fprintf(ErrFp, tr("%s(%d): IF without ENDIF"), FileName, IfLinenos[j]);
fprintf(ErrFp, "\n");
}
}
if (!IStackPtr) return E_EOF;
@@ -608,16 +613,25 @@ int DoInclude(ParsePtr p, enum TokTypes tok)
DBufInit(&buf);
DBufInit(&fullname);
DBufInit(&path);
if ( (r=ParseToken(p, &buf)) ) return r;
if ( (r=ParseTokenOrQuotedString(p, &buf)) ) return r;
e = VerifyEoln(p);
if (e) Eprint("%s", ErrMsg[e]);
if (e) Eprint("%s", GetErr(e));
if (tok == T_IncludeR && *(DBufValue(&buf)) != '/') {
if ((tok == T_IncludeR || tok == T_IncludeSys) &&
*(DBufValue(&buf)) != '/') {
/* Relative include: Include relative to dir
containing current file */
if (DBufPuts(&path, FileName) != OK) {
r = E_NO_MEM;
goto bailout;
if (tok == T_IncludeR) {
if (DBufPuts(&path, FileName) != OK) {
r = E_NO_MEM;
goto bailout;
}
} else {
if (DBufPuts(&path, SysDir) != OK ||
DBufPutc(&path, '/') != OK) {
r = E_NO_MEM;
goto bailout;
}
}
if (DBufLen(&path) == 0) {
s = DBufValue(&buf);
@@ -650,9 +664,6 @@ int DoInclude(ParsePtr p, enum TokTypes tok)
goto bailout;
}
NumIfs = 0;
IfFlags = 0;
bailout:
DBufFree(&buf);
DBufFree(&path);
@@ -713,8 +724,6 @@ int DoIncludeCmd(ParsePtr p)
return r;
}
DBufFree(&buf);
NumIfs = 0;
IfFlags = 0;
return OK;
}
@@ -756,8 +765,9 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
while(dc) {
if (!strcmp(dc->dirname, dir)) {
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Found cached directory listing for `%s'\n",
fprintf(ErrFp, tr("Found cached directory listing for `%s'"),
dir);
fprintf(ErrFp, "\n");
}
free(dir);
i->chain = dc->chain;
@@ -767,7 +777,8 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
}
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Scanning directory `%s' for *.rem files\n", dir);
fprintf(ErrFp, tr("Scanning directory `%s' for *.rem files"), dir);
fprintf(ErrFp, "\n");
}
if (ShouldCache) {
@@ -781,7 +792,8 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
}
if (dc) {
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Caching directory `%s' listing\n", dir);
fprintf(ErrFp, tr("Caching directory `%s' listing"), dir);
fprintf(ErrFp, "\n");
}
dc->chain = NULL;
@@ -905,13 +917,16 @@ static int IncludeCmd(char const *cmd)
FCLOSE(fp);
}
IStackPtr++;
NumIfs = 0;
IfFlags = 0;
/* 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);
fprintf(ErrFp, tr("Reading command `%s': Found in cache"), fname);
fprintf(ErrFp, "\n");
}
CLine = h->cache;
STRSET(FileName, fname);
@@ -928,8 +943,9 @@ static int IncludeCmd(char const *cmd)
}
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Executing `%s' for INCLUDECMD and caching as `%s'\n",
fprintf(ErrFp, tr("Executing `%s' for INCLUDECMD and caching as `%s'"),
cmd, fname);
fprintf(ErrFp, "\n");
}
/* Not found in cache */
@@ -941,6 +957,7 @@ static int IncludeCmd(char const *cmd)
fp2 = popen(cmd, "r");
}
if (!fp2) {
PopFile();
DBufFree(&buf);
return E_CANT_OPEN;
}
@@ -1014,6 +1031,8 @@ int IncludeFile(char const *fname)
}
IStackPtr++;
NumIfs = 0;
IfFlags = 0;
#ifdef HAVE_GLOB
/* If it's a directory, set up the glob chain here. */
@@ -1028,7 +1047,7 @@ int IncludeFile(char const *fname)
if (SetupGlobChain(fname, i) == OK) { /* Glob succeeded */
if (!i->chain) { /* Oops... no matching files */
if (!Hush) {
Eprint("%s: %s", fname, ErrMsg[E_NO_MATCHING_REMS]);
Eprint("%s: %s", fname, GetErr(E_NO_MATCHING_REMS));
}
PopFile();
return E_NO_MATCHING_REMS;
@@ -1042,14 +1061,14 @@ int IncludeFile(char const *fname)
if (!OpenFile(fc->filename)) {
return OK;
}
Eprint("%s: %s", ErrMsg[E_CANT_OPEN], fc->filename);
Eprint("%s: %s", GetErr(E_CANT_OPEN), fc->filename);
RunDisabled = oldRunDisabled;
}
/* Couldn't open anything... bail */
return PopFile();
} else {
if (!Hush) {
Eprint("%s: %s", fname, ErrMsg[E_NO_MATCHING_REMS]);
Eprint("%s: %s", fname, GetErr(E_NO_MATCHING_REMS));
}
}
return E_NO_MATCHING_REMS;
@@ -1063,7 +1082,7 @@ int IncludeFile(char const *fname)
return OK;
}
RunDisabled = oldRunDisabled;
Eprint("%s: %s", ErrMsg[E_CANT_OPEN], fname);
Eprint("%s: %s", GetErr(E_CANT_OPEN), fname);
/* Ugh! We failed! */
PopFile();
return E_CANT_OPEN;
@@ -1192,7 +1211,7 @@ static int CheckSafetyAux(struct stat *statbuf)
if (!geteuid()) {
/* Reject files not owned by root or group/world writable */
if (statbuf->st_uid != 0) {
fprintf(ErrFp, "SECURITY: Won't read non-root-owned file or directory when running as root!\n");
fprintf(ErrFp, "%s\n", tr("SECURITY: Won't read non-root-owned file or directory when running as root!"));
return 0;
}
}
@@ -1202,7 +1221,7 @@ static int CheckSafetyAux(struct stat *statbuf)
return 1;
}
if ((statbuf->st_mode & S_IWOTH)) {
fprintf(ErrFp, "SECURITY: Won't read world-writable file or directory!\n");
fprintf(ErrFp, "%s\n", tr("SECURITY: Won't read world-writable file or directory!"));
return 0;
}

View File

@@ -6,7 +6,7 @@
/* expressions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -93,6 +93,7 @@ static int FDefined (func_info *);
static int FDosubst (func_info *);
static int FDusk (func_info *);
static int FEasterdate (func_info *);
static int FEscape (func_info *);
static int FEvalTrig (func_info *);
static int FFiledate (func_info *);
static int FFiledatetime (func_info *);
@@ -161,6 +162,7 @@ static int FTrigdate (func_info *);
static int FTrigdatetime (func_info *);
static int FTrigdelta (func_info *);
static int FTrigduration (func_info *);
static int FTriginfo (func_info *);
static int FTrigeventduration(func_info *);
static int FTrigeventstart (func_info *);
static int FTrigfrom (func_info *);
@@ -252,6 +254,7 @@ BuiltinFunc Func[] = {
{ "dosubst", 1, 3, 0, FDosubst, NULL },
{ "dusk", 0, 1, 0, FDusk, NULL },
{ "easterdate", 0, 1, 0, FEasterdate, NULL },
{ "escape", 1, 2, 1, FEscape, NULL },
{ "evaltrig", 1, 2, 0, FEvalTrig, NULL },
{ "filedate", 1, 1, 0, FFiledate, NULL },
{ "filedatetime", 1, 1, 0, FFiledatetime, NULL },
@@ -324,6 +327,7 @@ BuiltinFunc Func[] = {
{ "trigeventstart", 0, 0, 0, FTrigeventstart, NULL },
{ "trigfrom", 0, 0, 0, FTrigfrom, NULL },
{ "trigger", 1, 3, 0, FTrigger, NULL },
{ "triginfo", 1, 1, 1, FTriginfo, NULL },
{ "trigpriority", 0, 0, 0, FTrigpriority, NULL },
{ "trigrep", 0, 0, 0, FTrigrep, NULL },
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom, NULL },
@@ -380,14 +384,22 @@ static int RetStrVal(char const *s, func_info *info)
/***************************************************************/
static int F_(func_info *info)
{
char const *translated;
DynamicBuffer translated;
int r;
DBufInit(&translated);
ASSERT_TYPE(0, STR_TYPE);
translated = GetTranslatedString(ARGSTR(0));
if (!translated) {
r = GetTranslatedStringTryingVariants(ARGSTR(0), &translated);
if (!r) {
DCOPYVAL(RetVal, ARG(0));
return OK;
}
return RetStrVal(translated, info);
r = RetStrVal(DBufValue(&translated), info);
DBufFree(&translated);
if (DebugFlag & DB_TRANSLATE) {
TranslationTemplate(ARGSTR(0));
}
return r;
}
/***************************************************************/
@@ -1068,7 +1080,7 @@ static int FOrd(func_info *info)
if (u == 1 && t != 11) s = "st";
if (u == 2 && t != 12) s = "nd";
if (u == 3 && t != 13) s = "rd";
sprintf(buf, "%d%s", v, s);
snprintf(buf, sizeof(buf), "%d%s", v, s);
return RetStrVal(buf, info);
}
@@ -1299,10 +1311,10 @@ static int FChoose(expr_node *node, Value *locals, Value *ans, int *nonconst)
cur = cur->sibling;
}
PUT(") => ");
PUT(ErrMsg[E_BAD_TYPE]);
PUT(GetErr(E_BAD_TYPE));
OUT();
}
Eprint("choose(): %s", ErrMsg[E_BAD_TYPE]);
Eprint("choose(): %s", GetErr(E_BAD_TYPE));
return E_BAD_TYPE;
}
n = v.v.val;
@@ -1610,6 +1622,17 @@ static int FTrigeventduration(func_info *info)
return OK;
}
static int FTriginfo(func_info *info)
{
char const *s;
ASSERT_TYPE(0, STR_TYPE);
s = FindTrigInfo(&LastTrigger, ARGSTR(0));
if (!s) {
return RetStrVal("", info);
}
return RetStrVal(s, info);
}
static int FTrigeventstart(func_info *info)
{
if (LastTrigger.eventstart == NO_TIME) {
@@ -1820,10 +1843,10 @@ static int FTrigger(func_info *info)
FromDSE(date, &y, &m, &d);
if (tim != NO_TIME) {
sprintf(buf, "%d %s %d AT %02d:%02d", d, EnglishMonthName[m], y,
snprintf(buf, sizeof(buf), "%d %s %d AT %02d:%02d", d, MonthName[m], y,
tim/60, tim%60);
} else {
sprintf(buf, "%d %s %d", d, EnglishMonthName[m], y);
snprintf(buf, sizeof(buf), "%d %s %d", d, MonthName[m], y);
}
return RetStrVal(buf, info);
}
@@ -2013,7 +2036,7 @@ static int FIif(expr_node *node, Value *locals, Value *ans, int *nonconst)
cur = cur->sibling;
}
PUT(") => ");
PUT(ErrMsg[E_IIF_ODD]);
PUT(GetErr(E_IIF_ODD));
OUT();
}
return E_IIF_ODD;
@@ -2171,7 +2194,7 @@ static int FTypeof(func_info *info)
/***************************************************************/
static int FLanguage(func_info *info)
{
return RetStrVal(L_LANGNAME, info);
return RetStrVal("English", info);
}
/***************************************************************/
@@ -2355,6 +2378,89 @@ static int FHebyear(func_info *info)
return OK;
}
/****************************************************************/
/* */
/* escape - escape special characters with "\xx" sequences */
/* */
/****************************************************************/
static int FEscape(func_info *info)
{
DynamicBuffer dbuf;
char const *s;
char hexbuf[16];
int r;
int include_quotes = 0;
ASSERT_TYPE(0, STR_TYPE);
if (Nargs >= 2) {
ASSERT_TYPE(1, INT_TYPE);
include_quotes = ARGV(1);
}
DBufInit(&dbuf);
if (include_quotes) {
r = DBufPutc(&dbuf, '"');
if (r != OK) {
DBufFree(&dbuf);
return r;
}
}
s = ARGSTR(0);
while(*s) {
switch(*s) {
case '\a':
r = DBufPuts(&dbuf, "\\a");
break;
case '\b':
r = DBufPuts(&dbuf, "\\b");
break;
case '\f':
r = DBufPuts(&dbuf, "\\f");
break;
case '\n':
r = DBufPuts(&dbuf, "\\n");
break;
case '\r':
r = DBufPuts(&dbuf, "\\r");
break;
case '\t':
r = DBufPuts(&dbuf, "\\t");
break;
case '\v':
r = DBufPuts(&dbuf, "\\v");
break;
case '\\':
r = DBufPuts(&dbuf, "\\\\");
break;
case '"':
r = DBufPuts(&dbuf, "\\\"");
break;
default:
if ((*s > 0 && *s < ' ') || *s == 0x7f) {
snprintf(hexbuf, sizeof(hexbuf), "\\x%02x", (unsigned int) *s);
r = DBufPuts(&dbuf, hexbuf);
} else {
r = DBufPutc(&dbuf, *s);
}
break;
}
if (r != OK) {
DBufFree(&dbuf);
return r;
}
s++;
}
if (include_quotes) {
r = DBufPutc(&dbuf, '"');
if (r != OK) {
DBufFree(&dbuf);
return r;
}
}
r = RetStrVal(DBufValue(&dbuf), info);
DBufFree(&dbuf);
return r;
}
/****************************************************************/
/* */
/* htmlescape - replace <. > and & by &lt; &gt; and &amp; */
@@ -2752,7 +2858,7 @@ static int SunStuff(int rise, double cosz, int dse)
/* Get offset from UTC */
if (CalculateUTC) {
if (CalcMinsFromUTC(dse, 12*60, &mins, NULL)) {
Eprint(ErrMsg[E_MKTIME_PROBLEM]);
Eprint(GetErr(E_MKTIME_PROBLEM));
return NO_TIME;
}
} else mins = MinsFromUTC;
@@ -3004,6 +3110,7 @@ static int FPsshade(func_info *info)
char psbuff[256];
char *s = psbuff;
int i;
size_t len = sizeof(psbuff);
/* 1 or 3 args */
if (Nargs != 1 && Nargs != 3) return E_2MANY_ARGS;
@@ -3016,19 +3123,22 @@ static int FPsshade(func_info *info)
if (!psshade_warned) {
psshade_warned = 1;
Wprint("psshade() is deprecated; use SPECIAL SHADE instead.");
Wprint(tr("psshade() is deprecated; use SPECIAL SHADE instead."));
}
sprintf(s, "/_A LineWidth 2 div def ");
snprintf(s, len, "/_A LineWidth 2 div def ");
len -= strlen(s);
s += strlen(s);
sprintf(s, "_A _A moveto ");
snprintf(s, len, "_A _A moveto ");
len -= strlen(s);
s += strlen(s);
sprintf(s, "BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto ");
snprintf(s, len, "BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto ");
len -= strlen(s);
s += strlen(s);
if (Nargs == 1) {
sprintf(s, "_A BoxHeight _A sub lineto closepath %d 100 div setgray fill 0.0 setgray", ARGV(0));
snprintf(s, len, "_A BoxHeight _A sub lineto closepath %d 100 div setgray fill 0.0 setgray", ARGV(0));
} else {
sprintf(s, "_A BoxHeight _A sub lineto closepath %d 100 div %d 100 div %d 100 div setrgbcolor fill 0.0 setgray", ARGV(0), ARGV(1), ARGV(2));
snprintf(s, len, "_A BoxHeight _A sub lineto closepath %d 100 div %d 100 div %d 100 div setrgbcolor fill 0.0 setgray", ARGV(0), ARGV(1), ARGV(2));
}
return RetStrVal(psbuff, info);
}
@@ -3051,6 +3161,7 @@ static int FPsmoon(func_info *info)
char const *extra = NULL;
int size = -1;
int fontsize = -1;
size_t len = sizeof(psbuff);
ASSERT_TYPE(0, INT_TYPE);
if (ARGV(0) < 0) return E_2LOW;
@@ -3071,63 +3182,74 @@ static int FPsmoon(func_info *info)
}
if (!psmoon_warned) {
psmoon_warned = 1;
Wprint("psmoon() is deprecated; use SPECIAL MOON instead.");
Wprint(tr("psmoon() is deprecated; use SPECIAL MOON instead."));
}
if (size > 0) {
sprintf(sizebuf, "%d", size);
snprintf(sizebuf, sizeof(sizebuf), "%d", size);
} else {
strcpy(sizebuf, "DaySize 2 div");
}
if (fontsize > 0) {
sprintf(fontsizebuf, "%d", fontsize);
snprintf(fontsizebuf, sizeof(fontsizebuf), "%d", fontsize);
} else {
strcpy(fontsizebuf, "EntrySize");
}
sprintf(s, "gsave 0 setgray newpath Border %s add BoxHeight Border sub %s sub",
snprintf(s, len, "gsave 0 setgray newpath Border %s add BoxHeight Border sub %s sub",
sizebuf, sizebuf);
len -= strlen(s);
s += strlen(s);
sprintf(s, " %s 0 360 arc closepath", sizebuf);
snprintf(s, len, " %s 0 360 arc closepath", sizebuf);
len -= strlen(s);
s += strlen(s);
switch(ARGV(0)) {
case 0:
sprintf(s, " fill");
snprintf(s, len, " fill");
len -= strlen(s);
s += strlen(s);
break;
case 2:
sprintf(s, " stroke");
snprintf(s, len, " stroke");
len -= strlen(s);
s += strlen(s);
break;
case 1:
sprintf(s, " stroke");
snprintf(s, len, " stroke");
len -= strlen(s);
s += strlen(s);
sprintf(s, " newpath Border %s add BoxHeight Border sub %s sub",
snprintf(s, len, " newpath Border %s add BoxHeight Border sub %s sub",
sizebuf, sizebuf);
len -= strlen(s);
s += strlen(s);
sprintf(s, " %s 90 270 arc closepath fill", sizebuf);
snprintf(s, len, " %s 90 270 arc closepath fill", sizebuf);
len -= strlen(s);
s += strlen(s);
break;
default:
sprintf(s, " stroke");
snprintf(s, len, " stroke");
len -= strlen(s);
s += strlen(s);
sprintf(s, " newpath Border %s add BoxHeight Border sub %s sub",
snprintf(s, len, " newpath Border %s add BoxHeight Border sub %s sub",
sizebuf, sizebuf);
len -= strlen(s);
s += strlen(s);
sprintf(s, " %s 270 90 arc closepath fill", sizebuf);
snprintf(s, len, " %s 270 90 arc closepath fill", sizebuf);
len -= strlen(s);
s += strlen(s);
break;
}
if (extra) {
sprintf(s, " Border %s add %s add Border add BoxHeight border sub %s sub %s sub moveto /EntryFont findfont %s scalefont setfont (%s) show",
snprintf(s, len, " Border %s add %s add Border add BoxHeight border sub %s sub %s sub moveto /EntryFont findfont %s scalefont setfont (%s) show",
sizebuf, sizebuf, sizebuf, sizebuf, fontsizebuf, extra);
len -= strlen(s);
s += strlen(s);
}
sprintf(s, " grestore");
snprintf(s, len, " grestore");
return RetStrVal(psbuff, info);
}
@@ -3258,20 +3380,20 @@ static int FDatepart(func_info *info)
* used for the timezone stuff! */
static int setenv(char const *varname, char const *val, int overwrite)
{
static char tzbuf[256];
static char tzbuf[128];
if (strcmp(varname, "TZ")) {
fprintf(stderr, "built-in setenv can only be used with TZ\n");
fprintf(ErrFp, "built-in setenv can only be used with TZ\n");
abort();
}
if (!overwrite) {
fprintf(stderr, "built-in setenv must have overwrite=1\n");
fprintf(ErrFp, "built-in setenv must have overwrite=1\n");
abort();
}
if (strlen(val) > 250) {
return -1;
}
sprintf(tzbuf, "%s=%s", varname, val);
snprintf(tzbuf, sizeof(tzbuf), "%s=%s", varname, val);
return(putenv(tzbuf));
}
#endif
@@ -3280,12 +3402,12 @@ static int setenv(char const *varname, char const *val, int overwrite)
* used for the timezone stuff! */
static void unsetenv(char const *varname)
{
static char tzbuf[8];
static char tzbuf[128];
if (strcmp(varname, "TZ")) {
fprintf(stderr, "built-in unsetenv can only be used with TZ\n");
fprintf(ErrFp, "built-in unsetenv can only be used with TZ\n");
abort();
}
sprintf(tzbuf, "%s", varname);
snprintf(tzbuf, sizeof(tzbuf), "%s", varname);
putenv(tzbuf);
}
#endif
@@ -3617,7 +3739,7 @@ FEvalTrig(func_info *info)
} else {
/* Hokey... */
if (trig.scanfrom != DSEToday) {
Wprint("Warning: SCANFROM is ignored in two-argument form of evaltrig()");
Wprint(tr("Warning: SCANFROM is ignored in two-argument form of evaltrig()"));
}
dse = ComputeTrigger(scanfrom, &trig, &tim, &r, 0);
}
@@ -3672,7 +3794,7 @@ FMultiTrig(func_info *info)
return E_PARSE_ERR;
}
if (tim.ttime != NO_TIME) {
Eprint("Cannot use AT clause in multitrig() function");
Eprint(tr("Cannot use AT clause in multitrig() function"));
return E_PARSE_ERR;
}
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);

View File

@@ -8,7 +8,7 @@
/* globals.h and err.h */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -18,7 +18,6 @@
#include <stdio.h> /* For definition of FILE - sigh! */
#include "types.h"
#include "custom.h"
#include "lang.h"
#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-2021 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -30,7 +30,6 @@
EXTERN FILE *ErrFp;
#include "dynbuf.h"
#include "lang.h"
#define MAX_TRUSTED_USERS 20
@@ -69,6 +68,7 @@ EXTERN INIT( int PsCal, 0);
EXTERN INIT( int CalWidth, 80);
EXTERN INIT( int CalWeeks, 0);
EXTERN INIT( int CalMonths, 0);
EXTERN INIT( char const *CalType, "none");
EXTERN INIT( int Hush, 0);
EXTERN INIT( int NextMode, 0);
EXTERN INIT( int InfiniteDelta, 0);
@@ -176,65 +176,23 @@ EXTERN INIT( unsigned int FuncRecursionLevel, 0);
/* Suppress warnings about implicit REM and MSG */
EXTERN INIT( int SuppressImplicitRemWarnings, 0);
/* Test mode - used by the acceptance tests */
EXTERN INIT( int TestMode, 0);
extern int NumFullOmits, NumPartialOmits;
/* List of months */
EXTERN char *EnglishMonthName[]
#ifdef MK_GLOBALS
= {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"}
#endif
;
#if LANG == ENGLISH
#define MonthName EnglishMonthName
#else
EXTERN char *MonthName[]
#ifdef MK_GLOBALS
= {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 *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",
"Saturday", "Sunday"}
#endif
;
#if LANG == ENGLISH
#define DayName EnglishDayName
#else
EXTERN char *DayName[]
#ifdef MK_GLOBALS
= {L_MONDAY, L_TUESDAY, L_WEDNESDAY, L_THURSDAY, L_FRIDAY,
L_SATURDAY, L_SUNDAY}
#endif
;
#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
;
@@ -256,84 +214,15 @@ EXTERN int MonthIndex[2][12]
#endif
;
EXTERN char *DynamicAgo
#ifdef MK_GLOBALS
= L_AGO
#endif
;
EXTERN char *DynamicAm
#ifdef MK_GLOBALS
= L_AM
#endif
;
EXTERN char *DynamicAnd
#ifdef MK_GLOBALS
= L_AND
#endif
;
EXTERN char *DynamicAt
#ifdef MK_GLOBALS
= L_AT
#endif
;
EXTERN char *DynamicFromnow
#ifdef MK_GLOBALS
= L_FROMNOW
#endif
;
EXTERN char *DynamicHour
#ifdef MK_GLOBALS
= L_HOUR
#endif
;
EXTERN char *DynamicHplu
#ifdef MK_GLOBALS
= L_HPLU
#endif
;
EXTERN char *DynamicIs
#ifdef MK_GLOBALS
= L_IS
#endif
;
EXTERN char *DynamicMinute
#ifdef MK_GLOBALS
= L_MINUTE
= "s"
#endif
;
EXTERN char *DynamicMplu
#ifdef MK_GLOBALS
= L_MPLU
#endif
;
EXTERN char *DynamicNow
#ifdef MK_GLOBALS
= L_NOW
#endif
;
EXTERN char *DynamicOn
#ifdef MK_GLOBALS
= L_ON
#endif
;
EXTERN char *DynamicPm
#ifdef MK_GLOBALS
= L_PM
#endif
;
EXTERN char *DynamicToday
#ifdef MK_GLOBALS
= L_TODAY
#endif
;
EXTERN char *DynamicTomorrow
#ifdef MK_GLOBALS
= L_TOMORROW
#endif
;
EXTERN char *DynamicWas
#ifdef MK_GLOBALS
= L_WAS
= "s"
#endif
;
@@ -351,3 +240,6 @@ EXTERN int SuppressLRM
= 0
#endif
;
/* Translatable messages */
extern char const *translatables[];

View File

@@ -5,7 +5,7 @@
/* Implementation of hash table. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -63,7 +63,7 @@
* These are used as choices for the number of hash buckets in the table
*/
static size_t bucket_choices[] = {
17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911, 43853, 87719,
7, 17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911, 43853, 87719,
175447, 350899, 701819, 1403641, 2807303, 5614657, 11229331, 22458671,
44917381, 89834777, 179669557, 359339171, 718678369, 1437356741 };
@@ -108,6 +108,8 @@ hash_table_init(hash_table *t,
t->hashfunc = hashfunc;
t->compare = compare;
t->buckets = malloc(sizeof(void *) * bucket_choices[0]);
t->num_growths = 0;
t->num_shrinks = 0;
if (!t->buckets) {
return -1;
}
@@ -216,15 +218,17 @@ hash_table_resize(hash_table *t, int dir)
/* Out of memory... just don't resize? */
return 0;
}
if (dir == 1) {
t->num_growths++;
} else {
t->num_shrinks++;
}
for (size_t j=0; j<num_new_buckets; j++) {
new_buckets[j] = NULL;
}
/* Move everything from the old buckets into the new */
for (size_t i=0; i<num_old_buckets; i++) {
if (!t->buckets[i]) {
continue;
}
void *p = t->buckets[i];
while(p) {
struct hash_link *l = LINK(t, p);
@@ -308,32 +312,6 @@ hash_table_find(hash_table *t, void *candidate)
return NULL;
}
/**
* \brief Find the next item in a hash table
*
* \param t Pointer to a hash table object
* \param obj Pointer to an object that was perviously returned by
* hash_table_find() or hash_table_find_next().
*
* \return A pointer to the next object matching obj, or NULL if
* no more exist
*/
void *
hash_table_find_next(hash_table *t, void *obj)
{
if (!obj) {
return NULL;
}
void *ptr = LINK(t, obj)->next;
while(ptr) {
if (!t->compare(obj, ptr)) {
return ptr;
}
ptr = LINK(t, ptr)->next;
}
return NULL;
}
/**
* \brief Delete an item from a hash table
*

View File

@@ -5,7 +5,7 @@
/* Header file for hash-table related functions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -29,6 +29,8 @@ struct hash_link {
*/
typedef struct {
unsigned int bucket_choice_index; /**< Index into array of possible bucket counts */
size_t num_growths; /**< How many times have we grown the hash table? */
size_t num_shrinks; /**< How many times have we grown the hash table? */
size_t num_entries; /**< Number of entries in the hash table */
size_t hash_link_offset; /**< Offset of the struct hash_link in the container */
void **buckets; /**< Array of buckets */
@@ -45,6 +47,8 @@ struct hash_table_stats {
size_t num_nonempty_buckets; /**< Number of non-emptry buckets */
size_t max_len; /**< Length of longest chain in the hash table */
size_t min_len; /**< Length of the shortest chain in the hash table */
size_t num_growths; /**< How many times have we grown the hash table? */
size_t num_shrinks; /**< How many times have we grown the hash table? */
double avg_len; /**< Average chain length */
double avg_nonempty_len; /**< Average chain length of non-empty bucket */
double stddev; /**< Standard deviation of chain lengths */
@@ -60,7 +64,6 @@ size_t hash_table_num_buckets(hash_table *t);
size_t hash_table_chain_len(hash_table *t, size_t i);
int hash_table_insert(hash_table *t, void *item);
void *hash_table_find(hash_table *t, void *candidate);
void *hash_table_find_next(hash_table *t, void *obj);
int hash_table_delete(hash_table *t, void *item);
int hash_table_delete_no_resize(hash_table *t, void *item);
void *hash_table_next(hash_table *t, void *cur);
@@ -84,29 +87,3 @@ void hash_table_get_stats(hash_table *t, struct hash_table_stats *stat);
(item); \
(item) = hash_table_next((t), (item)))
/**
* \brief Iterate over all items in a hash table that match a candidate
*
* This macro iterates over all items in a hash table that match a
* candidate object. (In general, a hash table may contain multiple
* objects with the same key.) Here is an example assuming that the hash
* table holds objects of type struct int_object:
*
* struct int_object {
* int value;
* struct hash_link link;
* }
*
* hash_table tab;
* int_object candidate;
*
* candidate.value = 7;
* int_object *item;
* hash_table_for_each_matching(item, &candidate, &tab) {
* // Do something with item, which will match "7"
* }
*/
#define hash_table_for_each_matching(item, candidate, t) \
for ((item) = hash_table_find((t), (candidate)); \
(item); \
(item) = hash_table_find_next((t), (item)))

View File

@@ -5,7 +5,7 @@
/* Utility function to print hash table stats. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -33,14 +33,15 @@ hash_table_dump_stats(hash_table *t, FILE *fp)
{
struct hash_table_stats stat;
hash_table_get_stats(t, &stat);
fprintf(fp, "#Entries: %lu\n#Buckets: %lu\n#Non-empty Buckets: %lu\n",
fprintf(fp, " Entries: %lu; Buckets: %lu; Non-empty Buckets: %lu\n",
(unsigned long) stat.num_entries,
(unsigned long) stat.num_buckets,
(unsigned long) stat.num_nonempty_buckets);
fprintf(fp, "Max len: %lu\nMin len: %lu\nAvg len: %.4f\nStd dev: %.4f\nAvg nonempty len: %.4f\n",
fprintf(fp, " Maxlen: %lu; Minlen: %lu; Avglen: %.3f; Stddev: %.3f; Avg nonempty len: %.3f\n",
(unsigned long) stat.max_len,
(unsigned long) stat.min_len,
stat.avg_len, stat.stddev, stat.avg_nonempty_len);
fprintf(fp, " Growths: %lu; Shrinks: %lu\n", (unsigned long) stat.num_growths, (unsigned long) stat.num_shrinks);
}
/**
@@ -67,6 +68,8 @@ hash_table_get_stats(hash_table *t, struct hash_table_stats *stat)
stat->stddev = 0.0;
stat->num_nonempty_buckets = 0;
stat->avg_nonempty_len = 0.0;
stat->num_growths = t->num_growths;
stat->num_shrinks = t->num_shrinks;
double sum = 0.0;
double sumsq = 0.0;

View File

@@ -5,7 +5,7 @@
/* Support for the Hebrew calendar */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/* Derived from code written by Amos Shapir in 1978; revised */
@@ -324,7 +324,7 @@ int GetValidHebDate(int yin, int min, int din, int adarbehave,
case ADAR2ADARB: *mout = min = ADARB; break;
default:
Eprint("GetValidHebDate: Bad adarbehave value %d", adarbehave);
Eprint(tr("GetValidHebDate: Bad adarbehave value %d"), adarbehave);
return E_SWERR;
}
}
@@ -464,7 +464,7 @@ int ComputeJahr(int y, int m, int d, int *ans)
/* Check for Adar A */
if (m == ADARA && monlen[m] == 0) {
Eprint("No Adar A in %d", y);
Eprint(tr("No Adar A in %d"), y);
return E_BAD_HEBDATE;
}
@@ -474,7 +474,7 @@ int ComputeJahr(int y, int m, int d, int *ans)
}
if (d > monlen[m]) {
Eprint("%d %s %d: %s", d, HebMonthNames[m], y, ErrMsg[E_BAD_HEBDATE]);
Eprint("%d %s %d: %s", d, HebMonthNames[m], y, GetErr(E_BAD_HEBDATE));
return E_BAD_HEBDATE;
}

View File

@@ -7,7 +7,7 @@
/* in normal mode. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -149,7 +149,7 @@ static char const *DefaultFilename(void)
s = getenv("HOME");
if (!s) {
fprintf(stderr, "HOME environment variable not set. Unable to determine reminder file.\n");
fprintf(ErrFp, "HOME environment variable not set. Unable to determine reminder file.\n");
exit(EXIT_FAILURE);
}
DBufPuts(&default_filename_buf, s);
@@ -196,7 +196,7 @@ void InitRemind(int argc, char const *argv[])
DBufInit(&LineBuffer);
DBufInit(&ExprBuf);
DBufPuts(&Banner, L_BANNER);
DBufPuts(&Banner, "Reminders for %w, %d%s %m, %y%o:");
PurgeFP = NULL;
@@ -216,7 +216,8 @@ void InitRemind(int argc, char const *argv[])
RealToday = SystemDate(&CurYear, &CurMon, &CurDay);
if (RealToday < 0) {
fprintf(ErrFp, ErrMsg[M_BAD_SYS_DATE], BASE);
fprintf(ErrFp, GetErr(M_BAD_SYS_DATE), BASE);
fprintf(ErrFp, "\n");
exit(EXIT_FAILURE);
}
DSEToday = RealToday;
@@ -237,7 +238,7 @@ void InitRemind(int argc, char const *argv[])
InvokedAsRem = 1;
}
} else {
fprintf(stderr, "Invoked with a NULL argv[0]; bailing because that's just plain bizarre.\n");
fprintf(ErrFp, "Invoked with a NULL argv[0]; bailing because that's just plain bizarre.\n");
exit(EXIT_FAILURE);
}
@@ -501,9 +502,11 @@ void InitRemind(int argc, char const *argv[])
break;
}
if (weeks) {
CalType = "weekly";
PARSENUM(CalWeeks, arg);
if (!CalWeeks) CalWeeks = 1;
} else {
CalType = "monthly";
PARSENUM(CalMonths, arg);
if (!CalMonths) CalMonths = 1;
}
@@ -528,9 +531,11 @@ void InitRemind(int argc, char const *argv[])
break;
}
if (weeks) {
CalType = "weekly";
PARSENUM(CalWeeks, arg);
if (!CalWeeks) CalWeeks = 1;
} else {
CalType = "monthly";
PARSENUM(CalMonths, arg);
if (!CalMonths) CalMonths = 1;
}
@@ -541,10 +546,14 @@ void InitRemind(int argc, char const *argv[])
DoSimpleCalendar = 1;
IgnoreOnce = 1;
PsCal = PSCAL_LEVEL1;
weeks = 0;
while (*arg == 'a' || *arg == 'A' ||
*arg == 'q' || *arg == 'Q' ||
*arg == '+' ||
*arg == 'p' || *arg == 'P') {
if (*arg == 'a' || *arg == 'A') {
if (*arg == '+') {
weeks = 1;
} else if (*arg == 'a' || *arg == 'A') {
DoSimpleCalDelta = 1;
} else if (*arg == 'p' || *arg == 'P') {
/* JSON interchange formats always include
@@ -560,8 +569,16 @@ void InitRemind(int argc, char const *argv[])
}
arg++;
}
PARSENUM(CalMonths, arg);
if (!CalMonths) CalMonths = 1;
if (weeks) {
CalType = "weekly";
PARSENUM(CalWeeks, arg);
if (!CalWeeks) CalWeeks = 1;
PsCal = PSCAL_LEVEL3;
} else {
CalType = "monthly";
PARSENUM(CalMonths, arg);
if (!CalMonths) CalMonths = 1;
}
break;
case 'l':
@@ -577,7 +594,7 @@ void InitRemind(int argc, char const *argv[])
/* -wt means get width from /dev/tty */
ttyfd = open("/dev/tty", O_RDONLY);
if (ttyfd < 0) {
fprintf(stderr, "%s: `-wt': Cannot open /dev/tty: %s\n",
fprintf(ErrFp, "%s: `-wt': Cannot open /dev/tty: %s\n",
argv[0], strerror(errno));
} else {
InitCalWidthAndFormWidth(ttyfd);
@@ -618,14 +635,17 @@ void InitRemind(int argc, char const *argv[])
while (*arg) {
switch(*arg++) {
case 's': case 'S': DebugFlag |= DB_PARSE_EXPR; break;
case 'h': case 'H': DebugFlag |= DB_HASHSTATS; break;
case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break;
case 'x': case 'X': DebugFlag |= DB_PRTEXPR; break;
case 't': case 'T': DebugFlag |= DB_PRTTRIG; break;
case 'v': case 'V': DebugFlag |= DB_DUMP_VARS; break;
case 'l': case 'L': DebugFlag |= DB_PRTLINE; break;
case 'f': case 'F': DebugFlag |= DB_TRACE_FILES; break;
case 'q': case 'Q': DebugFlag |= DB_TRANSLATE; break;
default:
fprintf(ErrFp, ErrMsg[M_BAD_DB_FLAG], *(arg-1));
fprintf(ErrFp, GetErr(M_BAD_DB_FLAG), *(arg-1));
fprintf(ErrFp, "\n");
}
}
break;
@@ -660,7 +680,8 @@ void InitRemind(int argc, char const *argv[])
break;
default:
fprintf(ErrFp, ErrMsg[M_BAD_OPTION], *(arg-1));
fprintf(ErrFp, GetErr(M_BAD_OPTION), *(arg-1));
fprintf(ErrFp, "\n");
}
}
@@ -728,7 +749,7 @@ void InitRemind(int argc, char const *argv[])
default:
if (tok.type == T_Illegal && tok.val < 0) {
fprintf(stderr, "%s: `%s'\n", ErrMsg[-tok.val], arg);
fprintf(ErrFp, "%s: `%s'\n", GetErr(-tok.val), arg);
Usage();
}
Usage();
@@ -774,10 +795,11 @@ void InitRemind(int argc, char const *argv[])
}
/* Figure out the offset from UTC */
if (CalculateUTC)
/* Figure out the offset from UTC */
if (CalculateUTC) {
(void) CalcMinsFromUTC(DSEToday, MinutesPastMidnight(0),
&MinsFromUTC, NULL);
}
}
/***************************************************************/
@@ -790,7 +812,7 @@ void InitRemind(int argc, char const *argv[])
#ifndef L_USAGE_OVERRIDE
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s Copyright (C) 1992-2025 Dianne Skoll\n", VERSION);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
@@ -852,7 +874,8 @@ static void ChgUser(char const *user)
pwent = getpwnam(user);
if (!pwent) {
fprintf(ErrFp, ErrMsg[M_BAD_USER], user);
fprintf(ErrFp, GetErr(M_BAD_USER), user);
fprintf(ErrFp, "\n");
exit(EXIT_FAILURE);
}
@@ -860,24 +883,28 @@ static void ChgUser(char const *user)
/* 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);
fprintf(ErrFp, GetErr(M_NO_CHG_GID), pwent->pw_gid);
fprintf(ErrFp, "\n");
exit(EXIT_FAILURE);
};
#endif
if (setgid(pwent->pw_gid) < 0) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
fprintf(ErrFp, GetErr(M_NO_CHG_GID), pwent->pw_gid);
fprintf(ErrFp, "\n");
exit(EXIT_FAILURE);
}
if (setuid(pwent->pw_uid) < 0) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid);
fprintf(ErrFp, GetErr(M_NO_CHG_UID), pwent->pw_uid);
fprintf(ErrFp, "\n");
exit(EXIT_FAILURE);
}
}
home = malloc(strlen(pwent->pw_dir) + 6);
if (!home) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
fprintf(ErrFp, "\n");
exit(EXIT_FAILURE);
}
sprintf(home, "HOME=%s", pwent->pw_dir);
@@ -885,7 +912,8 @@ static void ChgUser(char const *user)
shell = malloc(strlen(pwent->pw_shell) + 7);
if (!shell) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
fprintf(ErrFp, "\n");
exit(EXIT_FAILURE);
}
sprintf(shell, "SHELL=%s", pwent->pw_shell);
@@ -894,14 +922,16 @@ static void ChgUser(char const *user)
if (pwent->pw_uid) {
username = malloc(strlen(pwent->pw_name) + 6);
if (!username) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
fprintf(ErrFp, "\n");
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]);
fprintf(ErrFp, "%s", GetErr(M_NOMEM_ENV));
fprintf(ErrFp, "\n");
exit(EXIT_FAILURE);
}
sprintf(logname, "LOGNAME=%s", pwent->pw_name);
@@ -919,7 +949,7 @@ DefineFunction(char const *str)
r = DoFset(&p);
DestroyParser(&p);
if (r != OK) {
fprintf(ErrFp, "-i option: %s: %s\n", str, ErrMsg[r]);
fprintf(ErrFp, "-i option: %s: %s\n", str, GetErr(r));
}
}
/***************************************************************/
@@ -946,7 +976,8 @@ static void InitializeVar(char const *str)
if (isalpha(*str) || *str == '_' || (r > 0 && *str == '(') || (r == 0 && *str == '$') || (r > 0 && isdigit(*str))) {
varname[r++] = *str;
} else {
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_ILLEGAL_CHAR]);
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_ILLEGAL_CHAR));
fprintf(ErrFp, "\n");
return;
}
}
@@ -959,13 +990,15 @@ static void InitializeVar(char const *str)
}
varname[r] = 0;
if (!*varname) {
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_VAR]);
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_VAR));
fprintf(ErrFp, "\n");
return;
}
if (!*str) {
/* Setting a system var does require =expr on the commandline */
if (*varname == '$') {
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_EQ]);
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_EQ));
fprintf(ErrFp, "\n");
return;
}
val.type = INT_TYPE;
@@ -975,41 +1008,52 @@ static void InitializeVar(char const *str)
r = PreserveVar(varname);
}
if (r) {
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
fprintf(ErrFp, "\n");
}
return;
}
if (!*varname) {
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_VAR]);
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_VAR));
fprintf(ErrFp, "\n");
return;
}
expr = str+1;
if (!*expr) {
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[E_MISS_EXPR]);
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(E_MISS_EXPR));
fprintf(ErrFp, "\n");
return;
}
r=EvalExpr(&expr, &val, NULL);
if (r) {
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
fprintf(ErrFp, "\n");
return;
}
if (*varname == '$') {
r=SetSysVar(varname+1, &val);
DestroyValue(val);
if (r) fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
if (r) {
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
fprintf(ErrFp, "\n");
}
return;
}
r=SetVar(varname, &val);
if (r) {
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
fprintf(ErrFp, "\n");
return;
}
r=PreserveVar(varname);
if (r) fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
if (r) {
fprintf(ErrFp, GetErr(M_I_OPTION), GetErr(r));
fprintf(ErrFp, "\n");
}
return;
}
@@ -1018,14 +1062,15 @@ AddTrustedUser(char const *username)
{
struct passwd *pwent;
if (NumTrustedUsers >= MAX_TRUSTED_USERS) {
fprintf(stderr, "Too many trusted users (%d max)\n",
fprintf(ErrFp, "Too many trusted users (%d max)\n",
MAX_TRUSTED_USERS);
exit(EXIT_FAILURE);
}
pwent = getpwnam(username);
if (!pwent) {
fprintf(ErrFp, ErrMsg[M_BAD_USER], username);
fprintf(ErrFp, GetErr(M_BAD_USER), username);
fprintf(ErrFp, "\n");
exit(EXIT_FAILURE);
}
TrustedUsers[NumTrustedUsers] = pwent->pw_uid;
@@ -1077,6 +1122,17 @@ static void
ProcessLongOption(char const *arg)
{
int t;
if (!strcmp(arg, "test")) {
fprintf(stderr, "Enabling test mode: This is meant for the acceptance test.\nDo not use --test in production.\nIn test mode, the system time is fixed at 2025-01-06@19:00\n");
TestMode = 1;
/* Update RealToday because of TestMode */
RealToday = SystemDate(&CurYear, &CurMon, &CurDay);
DSEToday = RealToday;
FromDSE(DSEToday, &CurYear, &CurMon, &CurDay);
return;
}
if (!strcmp(arg, "version")) {
printf("%s\n", VERSION);
exit(EXIT_SUCCESS);
@@ -1085,6 +1141,16 @@ ProcessLongOption(char const *arg)
printf("%s\n", CONFIG_CMD);
exit(EXIT_SUCCESS);
}
if (!strcmp(arg, "print-errs")) {
for (t=0; t<NumErrs; t++) {
if (*ErrMsg[t]) {
print_escaped_string(stdout, ErrMsg[t]);
printf("\n");
}
}
exit(EXIT_SUCCESS);
}
if (!strcmp(arg, "print-tokens")) {
print_remind_tokens();
print_builtinfunc_tokens();

View File

@@ -299,7 +299,7 @@ json_value * json_parse_ex (json_settings * settings,
if (flags & flag_string)
{
if (!b)
{ sprintf (error, "Unexpected EOF in string (at %u:%u)", line_and_col);
{ snprintf (error, sizeof(error), "Unexpected EOF in string (at %u:%u)", line_and_col);
goto e_failed;
}
@@ -325,7 +325,7 @@ json_value * json_parse_ex (json_settings * settings,
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
(uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
{
sprintf (error, "Invalid character value `%c` (at %u:%u)", b, line_and_col);
snprintf (error, sizeof(error), "Invalid character value `%c` (at %u:%u)", b, line_and_col);
goto e_failed;
}
@@ -342,7 +342,7 @@ json_value * json_parse_ex (json_settings * settings,
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
(uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
{
sprintf (error, "Invalid character value `%c` (at %u:%u)", b, line_and_col);
snprintf (error, sizeof(error), "Invalid character value `%c` (at %u:%u)", b, line_and_col);
goto e_failed;
}
@@ -472,7 +472,7 @@ json_value * json_parse_ex (json_settings * settings,
if (flags & flag_block_comment)
{
if (!b)
{ sprintf (error, "%u:%u: Unexpected EOF in block comment", line_and_col);
{ snprintf (error, sizeof(error), "%u:%u: Unexpected EOF in block comment", line_and_col);
goto e_failed;
}
@@ -488,12 +488,12 @@ json_value * json_parse_ex (json_settings * settings,
else if (b == '/')
{
if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object)
{ sprintf (error, "%u:%u: Comment not allowed here", line_and_col);
{ snprintf (error, sizeof(error), "%u:%u: Comment not allowed here", line_and_col);
goto e_failed;
}
if (++ state.ptr == end)
{ sprintf (error, "%u:%u: EOF unexpected", line_and_col);
{ snprintf (error, sizeof(error), "%u:%u: EOF unexpected", line_and_col);
goto e_failed;
}
@@ -508,7 +508,7 @@ json_value * json_parse_ex (json_settings * settings,
continue;
default:
sprintf (error, "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b);
snprintf (error, sizeof(error), "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b);
goto e_failed;
};
}
@@ -526,7 +526,7 @@ json_value * json_parse_ex (json_settings * settings,
default:
sprintf (error, "%u:%u: Trailing garbage: `%c`",
snprintf (error, sizeof(error), "%u:%u: Trailing garbage: `%c`",
state.cur_line, state.cur_col, b);
goto e_failed;
@@ -545,7 +545,7 @@ json_value * json_parse_ex (json_settings * settings,
if (top && top->type == json_array)
flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next;
else
{ sprintf (error, "%u:%u: Unexpected ]", line_and_col);
{ snprintf (error, sizeof(error), "%u:%u: Unexpected ]", line_and_col);
goto e_failed;
}
@@ -561,7 +561,7 @@ json_value * json_parse_ex (json_settings * settings,
}
else
{
sprintf (error, "%u:%u: Expected , before %c",
snprintf (error, sizeof(error), "%u:%u: Expected , before %c",
state.cur_line, state.cur_col, b);
goto e_failed;
@@ -576,7 +576,7 @@ json_value * json_parse_ex (json_settings * settings,
}
else
{
sprintf (error, "%u:%u: Expected : before %c",
snprintf (error, sizeof(error), "%u:%u: Expected : before %c",
state.cur_line, state.cur_col, b);
goto e_failed;
@@ -702,7 +702,7 @@ json_value * json_parse_ex (json_settings * settings,
continue;
}
else
{ sprintf (error, "%u:%u: Unexpected %c when seeking value", line_and_col, b);
{ snprintf (error, sizeof(error), "%u:%u: Unexpected %c when seeking value", line_and_col, b);
goto e_failed;
}
};
@@ -722,7 +722,7 @@ json_value * json_parse_ex (json_settings * settings,
case '"':
if (flags & flag_need_comma)
{ sprintf (error, "%u:%u: Expected , before \"", line_and_col);
{ snprintf (error, sizeof(error), "%u:%u: Expected , before \"", line_and_col);
goto e_failed;
}
@@ -747,7 +747,7 @@ json_value * json_parse_ex (json_settings * settings,
}
/* FALLTHROUGH */
default:
sprintf (error, "%u:%u: Unexpected `%c` in object", line_and_col, b);
snprintf (error, sizeof(error), "%u:%u: Unexpected `%c` in object", line_and_col, b);
goto e_failed;
};
@@ -765,7 +765,7 @@ json_value * json_parse_ex (json_settings * settings,
if (! (flags & flag_num_e))
{
if (flags & flag_num_zero)
{ sprintf (error, "%u:%u: Unexpected `0` before `%c`", line_and_col, b);
{ snprintf (error, sizeof(error), "%u:%u: Unexpected `0` before `%c`", line_and_col, b);
goto e_failed;
}
@@ -814,7 +814,7 @@ json_value * json_parse_ex (json_settings * settings,
else if (b == '.' && top->type == json_integer)
{
if (!num_digits)
{ sprintf (error, "%u:%u: Expected digit before `.`", line_and_col);
{ snprintf (error, sizeof(error), "%u:%u: Expected digit before `.`", line_and_col);
goto e_failed;
}
@@ -831,7 +831,7 @@ json_value * json_parse_ex (json_settings * settings,
if (top->type == json_double)
{
if (!num_digits)
{ sprintf (error, "%u:%u: Expected digit after `.`", line_and_col);
{ snprintf (error, sizeof(error), "%u:%u: Expected digit after `.`", line_and_col);
goto e_failed;
}
@@ -857,7 +857,7 @@ json_value * json_parse_ex (json_settings * settings,
else
{
if (!num_digits)
{ sprintf (error, "%u:%u: Expected digit after `e`", line_and_col);
{ snprintf (error, sizeof(error), "%u:%u: Expected digit after `e`", line_and_col);
goto e_failed;
}
@@ -942,7 +942,7 @@ json_value * json_parse_ex (json_settings * settings,
e_unknown_value:
sprintf (error, "%u:%u: Unknown value", line_and_col);
snprintf (error, sizeof(error), "%u:%u: Unknown value", line_and_col);
goto e_failed;
e_alloc_failure:
@@ -952,7 +952,7 @@ e_alloc_failure:
e_overflow:
sprintf (error, "%u:%u: Too long (caught overflow)", line_and_col);
snprintf (error, sizeof(error), "%u:%u: Too long (caught overflow)", line_and_col);
goto e_failed;
e_failed:

View File

@@ -1,78 +0,0 @@
/***************************************************************/
/* */
/* LANG.H */
/* */
/* Header file for language support for various languages. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* I'm chauvinistic and name each language with its English name... */
#define ENGLISH 0 /* original by Dianne Skoll */
#define GERMAN 1 /* translated by Wolfgang Thronicke */
#define DUTCH 2 /* translated by Willem Kasdorp and Erik-Jan Vens */
#define FINNISH 3 /* translated by Mikko Silvonen */
#define FRENCH 4 /* translated by Laurent Duperval */
#define NORWEGIAN 5 /* translated by Trygve Randen */
#define DANISH 6 /* translated by Mogens Lynnerup */
#define POLISH 7 /* translated by Jerzy Sobczyk */
#define BRAZPORT 8 /* Brazilian Portuguese by Marco Paganini */
#define ITALIAN 9 /* translated by Valerio Aimale */
#define ROMANIAN 10 /* translated by Liviu Daia */
#define SPANISH 11 /* translated by Rafa Couto */
#define ICELANDIC 12 /* translated by Björn Davíðsson */
/* Add more languages here - but please e-mail dianne@skoll.ca
to have your favorite language assigned a number. If you add a
language, please send me the header file, and permission to include
it in future releases of Remind. Note that you'll get no remuneration
for this service - just everlasting fame. :-)
Use the file tstlang.rem to test your new language file. */
/************************************************************************
* *
* Define the language you want to use here *
* *
************************************************************************/
#ifndef LANG /* Allow for definition on compiler command line */
#define LANG ENGLISH
#endif
/* Pick up the appropriate header file */
#if LANG == ENGLISH
#include "langs/english.h"
#elif LANG == GERMAN
#include "langs/german.h"
#elif LANG == DUTCH
#include "langs/dutch.h"
#elif LANG == FINNISH
#include "langs/finnish.h"
#elif LANG == FRENCH
#include "langs/french.h"
#elif LANG == NORWEGIAN
#include "langs/norwgian.h"
#elif LANG == DANISH
#include "langs/danish.h"
#elif LANG == POLISH
#include "langs/polish.h"
#elif LANG == BRAZPORT
#include "langs/portbr.h"
#elif LANG == ITALIAN
#include "langs/italian.h"
#elif LANG == ROMANIAN
#include "langs/romanian.h"
#elif LANG == SPANISH
#include "langs/spanish.h"
#elif LANG == ICELANDIC
#include "langs/icelandic.h"
/* If no sensible language, choose English. I intended to use
the #error directive here, but some C compilers barf. */
#else
#include "langs/english.h"
#endif

View File

@@ -1,91 +0,0 @@
/***************************************************************/
/* */
/* DANISH.H */
/* */
/* Support for the Danish language. */
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
/* This file is Copyright (C) 1993 by Mogens Lynnerup. */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "Danish"
/* Day names */
#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"
#define L_SATURDAY "Lørdag"
/* Month names */
#define L_JAN "Januar"
#define L_FEB "Februar"
#define L_MAR "Marts"
#define L_APR "April"
#define L_MAY "Maj"
#define L_JUN "Juni"
#define L_JUL "Juli"
#define L_AUG "August"
#define L_SEP "September"
#define L_OCT "Oktober"
#define L_NOV "November"
#define L_DEC "December"
/* Today and tomorrow */
#define L_TODAY "i dag"
#define L_TOMORROW "i morgen"
/* The default banner */
#define L_BANNER "Påmindelse for %w, %d. %m, %y%o:"
/* "am" and "pm" */
#define L_AM "am"
#define L_PM "pm"
/* Ago and from now */
#define L_AGO "siden"
#define L_FROMNOW "fra nu"
/* "in %d days' time" */
#define L_INXDAYS "om %d dage"
/* "on" as in "on date..." */
#define L_ON "på"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
#define L_PLURAL "e"
/* Minutes, hours, at, etc */
#define L_NOW "nu"
#define L_AT "kl."
#define L_MINUTE "minut"
#define L_HOUR "time"
#define L_IS "er"
#define L_WAS "var"
#define L_AND "og"
/* What to add to make "hour" plural */
#define L_HPLU "r"
/* What to add to make "minute" plural */
#define L_MPLU "ter"
/* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc.
See the file dosubst.c for more info. */
#define L_AMPM_OVERRIDE(ampm, hour) ampm = (hour < 12) ? (hour<5) ? " om natten" : " om formiddagen" : (hour > 17) ? " om aftenen" : " om eftermiddagen";
#define L_ORDINAL_OVERRIDE plu = ".";
#define L_A_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s %d", DayName[dse%7], d, MonthName[m], y); } else { sprintf(s, "%s %s, den %d. %s %d", L_ON, DayName[dse%7], d, MonthName[m], y); }
#define L_E_OVER sprintf(s, "den %02d%c%02d%c%04d", d, DateSep, m+1, DateSep, y);
#define L_F_OVER sprintf(s, "den %02d%c%02d%c%04d", m+1, DateSep, d, DateSep, y);
#define L_G_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s", DayName[dse%7], d, MonthName[m]); } else { sprintf(s, "%s %s, den %d. %s", L_ON, DayName[dse%7], d, MonthName[m]); }
#define L_H_OVER sprintf(s, "den %02d%c%02d", d, DateSep, m+1);
#define L_I_OVER sprintf(s, "den %02d%c%02d", m+1, DateSep, d);
#define L_U_OVER L_A_OVER
#define L_V_OVER L_G_OVER

View File

@@ -1,102 +0,0 @@
/***************************************************************/
/* */
/* DUTCH.H */
/* */
/* Support for the DUTCH language. */
/* */
/* Author: Willem Kasdorp */
/* */
/* Modified slightly by Dianne Skoll */
/* */
/* Further corrections by Erik-Jan Vens */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "Dutch"
/* Day names */
#define L_SUNDAY "zondag"
#define L_MONDAY "maandag"
#define L_TUESDAY "dinsdag"
#define L_WEDNESDAY "woensdag"
#define L_THURSDAY "donderdag"
#define L_FRIDAY "vrijdag"
#define L_SATURDAY "zaterdag"
/* Month names */
#define L_JAN "januari"
#define L_FEB "februari"
#define L_MAR "maart"
#define L_APR "april"
#define L_MAY "mei"
#define L_JUN "juni"
#define L_JUL "juli"
#define L_AUG "augustus"
#define L_SEP "september"
#define L_OCT "oktober"
#define L_NOV "november"
#define L_DEC "december"
/* Today and tomorrow */
#define L_TODAY "vandaag"
#define L_TOMORROW "morgen"
/* The default banner */
#define L_BANNER "Herinneringen voor %w, %d%s %m, %y%o:"
/* "am" and "pm" */
#define L_AM "am"
#define L_PM "pm"
/* Ago and from now */
#define L_AGO "geleden"
#define L_FROMNOW "vanaf nu"
/* "in %d days' time" */
#define L_INXDAYS "over %d dagen"
/* "on" as in "on date..." */
#define L_ON "op"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix. (Indeed..., wkasdo) */
#define L_PLURAL "s"
/* Minutes, hours, at, etc */
#define L_NOW "nu"
#define L_AT "op"
#define L_MINUTE "minuut"
#define L_HOUR "uur"
#define L_IS "is"
#define L_WAS "was"
#define L_AND "en"
/* What to add to make "hour" plural (should result in uren, not uuren (wkasdo) */
#define L_HPLU "en"
/* What to add to make "minute" plural (should be minuten, not minuuten) */
#define L_MPLU "en"
/* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc.
See the file dosubst.c for more info. */
/* Willem - I fixed the uren/uuren problem here */
#define L_1_OVER \
if (tdiff == 0) \
sprintf(s, L_NOW); \
else if (hdiff == 0) \
sprintf(s, "%d %s %s", mdiff, \
((mdiff == 1) ? "minuut" : "minuten"), when); \
else if (mdiff == 0) \
sprintf(s, "%d %s %s", hdiff, \
((hdiff == 1) ? "uur" : "uren"), when); \
else sprintf(s, "%d %s %s %d %s %s", hdiff, \
(hdiff == 1 ? "uur" : "uren"), \
L_AND, mdiff, \
(mdiff == 1 ? "minuut" : "minuten"), \
when);

View File

@@ -1,78 +0,0 @@
/***************************************************************/
/* */
/* ENGLISH.H */
/* */
/* Support for the English language. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "English"
/* Day names */
#define L_SUNDAY "Sunday"
#define L_MONDAY "Monday"
#define L_TUESDAY "Tuesday"
#define L_WEDNESDAY "Wednesday"
#define L_THURSDAY "Thursday"
#define L_FRIDAY "Friday"
#define L_SATURDAY "Saturday"
/* Month names */
#define L_JAN "January"
#define L_FEB "February"
#define L_MAR "March"
#define L_APR "April"
#define L_MAY "May"
#define L_JUN "June"
#define L_JUL "July"
#define L_AUG "August"
#define L_SEP "September"
#define L_OCT "October"
#define L_NOV "November"
#define L_DEC "December"
/* Today and tomorrow */
#define L_TODAY "today"
#define L_TOMORROW "tomorrow"
/* The default banner */
#define L_BANNER "Reminders for %w, %d%s %m, %y%o:"
/* "am" and "pm" */
#define L_AM "am"
#define L_PM "pm"
/* Ago and from now */
#define L_AGO "ago"
#define L_FROMNOW "from now"
/* "in %d days' time" */
#define L_INXDAYS "in %d days' time"
/* "on" as in "on date..." */
#define L_ON "on"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
#define L_PLURAL "s"
/* Minutes, hours, at, etc */
#define L_NOW "now"
#define L_AT "at"
#define L_MINUTE "minute"
#define L_HOUR "hour"
#define L_IS "is"
#define L_WAS "was"
#define L_AND "and"
/* What to add to make "hour" plural */
#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. */

View File

@@ -1,292 +0,0 @@
/***************************************************************/
/* */
/* FINNISH.H */
/* */
/* Support for the Finnish language. */
/* */
/* Author: Mikko Silvonen <silvonen@iki.fi> */
/* */
/* See http://www.iki.fi/silvonen/remind/ for a list of */
/* Finnish holidays. */
/* */
/* This file is part of REMIND. */
/* This file is Copyright (C) 1993-1998 by Mikko Silvonen. */
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "Finnish"
/* Day names */
#define L_SUNDAY "sunnuntai"
#define L_MONDAY "maanantai"
#define L_TUESDAY "tiistai"
#define L_WEDNESDAY "keskiviikko"
#define L_THURSDAY "torstai"
#define L_FRIDAY "perjantai"
#define L_SATURDAY "lauantai"
/* Month names */
#define L_JAN "tammikuu"
#define L_FEB "helmikuu"
#define L_MAR "maaliskuu"
#define L_APR "huhtikuu"
#define L_MAY "toukokuu"
#define L_JUN "kesäkuu"
#define L_JUL "heinäkuu"
#define L_AUG "elokuu"
#define L_SEP "syyskuu"
#define L_OCT "lokakuu"
#define L_NOV "marraskuu"
#define L_DEC "joulukuu"
/* Today and tomorrow */
#define L_TODAY "tänään"
#define L_TOMORROW "huomenna"
/* The default banner */
#define L_BANNER "Viestit %wna %d. %mta %y%o:"
/* "am" and "pm" */
#define L_AM " ap."
#define L_PM " ip."
/* Ago and from now */
#define L_AGO "sitten"
#define L_FROMNOW "kuluttua"
/* "in %d days' time" */
#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 */
#define L_ON "na"
#define L_PARTIT "ta"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
/* The partitive ending of "day" */
#define L_PLURAL "ä"
/* Minutes, hours, at, etc */
#define L_NOW "nyt"
#define L_AT "klo"
#define L_MINUTE "minuutti"
#define L_HOUR "tunti"
#define L_IS "on"
#define L_WAS "oli"
#define L_AND "ja"
/* What to add to make "hour" plural (or actually partitive) */
#define L_HPLU "a"
/* What to add to make "minute" plural (or actually partitive) */
#define L_MPLU "a"
/* Genitive form of "hour" */
#define L_HGEN "tunnin"
/* Genitive form of "minute" */
#define L_MGEN "minuutin"
/* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc.
See the file dosubst.c for more info. */
#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; \
} \
}
#define L_A_OVER if (altmode == '*') { sprintf(s, "%s %d. %s %d", DayName[dse%7], d, MonthName[m], y); } else { sprintf(s, "%s%s %d. %s%s %d", DayName[dse%7], L_ON, d, MonthName[m], L_PARTIT, y); }
#define L_C_OVER if (altmode == '*') { sprintf(s, "%s", DayName[dse%7]); } else { sprintf(s, "%s%s", DayName[dse%7], L_ON); }
#define L_E_OVER sprintf(s, "%02d%c%02d%c%04d", d, DateSep, m+1, DateSep, y);
#define L_F_OVER sprintf(s, "%02d%c%02d%c%04d", m+1, DateSep, d, DateSep, y);
#define L_G_OVER if (altmode == '*') { sprintf(s, "%s %d. %s", DayName[dse%7], d, MonthName[m]); } else { sprintf(s, "%s%s %d. %s%s", DayName[dse%7], L_ON, d, MonthName[m], L_PARTIT); }
#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_J_OVER if (altmode == '*') { sprintf(s, "%s %sn %d%s %d", DayName[dse%7], MonthName[m], d, plu, y); } else { sprintf(s, "%s%s %sn %d%s %d", DayName[dse%7], L_ON, MonthName[m], d, plu, y); }
#define L_K_OVER if (altmode == '*') { sprintf(s, "%s %sn %d%s", DayName[dse%7], MonthName[m], d, plu); } else { sprintf(s, "%s%s %sn %d%s", DayName[dse%7], L_ON, MonthName[m], d, plu); }
#define L_L_OVER sprintf(s, "%04d%c%02d%c%02d", y, DateSep, m+1, DateSep, d);
#define L_Q_OVER sprintf(s, "n");
#define L_U_OVER if (altmode == '*') { sprintf(s, "%s %d%s %s %d", DayName[dse%7], d, plu, MonthName[m], y); } else { sprintf(s, "%s%s %d%s %s%s %d", DayName[dse%7], L_ON, d, plu, MonthName[m], L_PARTIT, y); }
#define L_V_OVER if (altmode == '*') { sprintf(s, "%s %d%s %s", DayName[dse%7], d, plu, MonthName[m]); } else { sprintf(s, "%s%s %d%s %s%s", DayName[dse%7], L_ON, d, plu, MonthName[m], L_PARTIT); }
#define L_1_OVER \
if (tdiff == 0) \
sprintf(s, "%s", L_NOW); \
else { \
s[0] = '\0'; \
if (hdiff != 0) { \
if (tdiff < 0) \
sprintf(s, "%d %s%s ", hdiff, L_HOUR, hplu); \
else \
sprintf(s, "%d %s ", hdiff, L_HGEN); \
} \
if (mdiff != 0) { \
if (tdiff < 0) \
sprintf(s + strlen(s), "%d %s%s ", mdiff, L_MINUTE, mplu); \
else \
sprintf(s + strlen(s), "%d %s ", mdiff, L_MGEN); \
} \
sprintf(s + strlen(s), when); \
}
/* The next ones are used only when MK_GLOBALS is set */
#ifdef MK_GLOBALS
#define L_ERR_OVERRIDE 1
EXTERN char *ErrMsg[] =
{
"Ok",
"Puuttuva ']'",
"Puuttuva lainausmerkki",
"Liian monimutkainen lauseke",
"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",
"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",
"Odotettu viikonpäivän nimi",
"Päällekkäinen argumentin nimi",
"Lausekkeiden arviointi on poistettu käytöstä",
};
#endif /* MK_GLOBALS */
/* The following is only used in init.c */
#ifdef L_IN_INIT
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETAVERSIO <<<<\n");
#endif
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");
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");
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 1000)\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 /* L_IN_INIT */

View File

@@ -1,266 +0,0 @@
/***************************************************************/
/* */
/* FRENCH.H */
/* */
/* Support for the French language. */
/* */
/* Contributed by Laurent Duperval. */
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
/* This file is Copyright (C) 1993 by Laurent Duperval and */
/* Dianne Skoll. */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "French"
/* Day names */
#define L_SUNDAY "dimanche"
#define L_MONDAY "lundi"
#define L_TUESDAY "mardi"
#define L_WEDNESDAY "mercredi"
#define L_THURSDAY "jeudi"
#define L_FRIDAY "vendredi"
#define L_SATURDAY "samedi"
/* Month names */
#define L_JAN "janvier"
#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"
#define L_AUG "août"
#define L_SEP "septembre"
#define L_OCT "octobre"
#define L_NOV "novembre"
#define L_DEC "décembre"
/* Today and tomorrow */
#define L_TODAY "aujourd'hui"
#define L_TOMORROW "demain"
/* The default banner */
#define L_BANNER "Rappels pour %w, %d%s %m, %y%o:"
/* "am" and "pm" */
#define L_AM "am"
#define L_PM "pm"
/* Ago and from now */
#define L_AGO "il y a"
#define L_FROMNOW "dans"
/* "in %d days' time" */
#define L_INXDAYS "dans %d jours"
/* "on" as in "on date..." */
#define L_ON "le"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
#define L_PLURAL "s"
/* Minutes, hours, at, etc */
#define L_NOW "maintenant"
#define L_AT "à"
#define L_MINUTE "minute"
#define L_HOUR "heure"
#define L_IS "est"
#define L_WAS "était"
#define L_AND "et"
/* What to add to make "hour" plural */
#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_ORDINAL_OVERRIDE \
switch(d) { \
case 1: plu = "er"; break; \
default: plu = ""; break; \
}
#define L_1_OVER \
if (tdiff == 0) \
sprintf(s, L_NOW); \
else if (tdiff < 0) { \
if (mdiff == 0) \
sprintf(s, "il y a %d heure%s", hdiff, hplu); \
else if (hdiff == 0) \
sprintf(s, "il y a %d minute%s", mdiff, mplu); \
else \
sprintf(s, "il y a %d heure%s et %d minute%s", hdiff, hplu, mdiff, mplu); \
} else { \
if (mdiff == 0) \
sprintf(s, "dans %d heure%s", hdiff, hplu); \
else if (hdiff == 0) \
sprintf(s, "dans %d minute%s", mdiff, mplu); \
else \
sprintf(s, "dans %d heure%s et %d minute%s", hdiff, hplu, mdiff, mplu); \
}
#define L_J_OVER if (altmode == '*') { sprintf(s, "%s, %d%s %s, %d", DayName[dse%7], d, plu, MonthName[m], y); } else { sprintf(s, "%s %s, %d%s %s, %d", L_ON, DayName[dse%7], d, plu, MonthName[m], y); }
#define L_K_OVER if (altmode == '*') { sprintf(s, "%s, %d%s %s", DayName[dse%7], d, plu, MonthName[m]); } else { sprintf(s, "%s %s, %d%s %s", L_ON, DayName[dse%7], d, plu, MonthName[m]); }
/* The next ones are used only when MK_GLOBALS is set */
#ifdef MK_GLOBALS
#define L_ERR_OVERRIDE 1
EXTERN char *ErrMsg[] =
{
"Ok",
"']' manquant",
"Apostrophe manquant",
"Expression trop complexe",
"Expression trop complexe - trop d'opérandes",
"')' manquante",
"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-équivalents",
"Débordement de date",
"Erreur interne - erreur de pile",
"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écifiée",
"Pas assez d'arguments",
"Trop d'arguments",
"Heure mal formée",
"Nombre trop élevé",
"Nombre trop bas",
"Impossible d'ouvrir le fichier",
"Trop d'INCLUDE imbriqués",
"Erreur d'analyse",
"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ément(s) étranger(s) sur la ligne",
"POP-OMIT-CONTEXT sans PUSH-OMIT-CONTEXT correspondant",
"RUN déactivé",
"Erreur de domaine",
"Identificateur invalide",
"Appel récursif détecté",
"",
"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 à la lecture du fichier",
"Fin de ligne attendue",
"Date hébreuse invalide",
"IIF demande nombre d'arguments impair",
"Attention: ENDIF manquant",
"Virgule attendue",
"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é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ée dans UserFN",
"Sortie de UserFN",
"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émoire pour environnement\n",
"Signe '=' manquant",
"Nom de variable absent",
"Expression absente",
"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é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",
"Nom du jour de la semaine attendu",
"Nom de l'argument en double",
"L'évaluation de l'expression est désactivée",
};
#endif /* MK_GLOBALS */
/* The following is only used in init.c */
#ifdef L_IN_INIT
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
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é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ée compatible avec rem2ps\n");
fprintf(ErrFp, " -v Mode verbeux\n");
fprintf(ErrFp, " -o Ignorer instructions ONCE\n");
fprintf(ErrFp, " -t Déclencher tous les rappels peu importe le delta\n");
fprintf(ErrFp, " -h Mode silencieux\n");
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");
fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
fprintf(ErrFp, " -e Envoyer les messages de stderr à stdout\n");
fprintf(ErrFp, " -b[n] Formats de l'heure pour le calendrier: 0=am/pm, 1=24hr, 2=aucun\n");
fprintf(ErrFp, " -x[n] Limite d'itérations pour la clause SATISFY (def=1000)\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

@@ -1,88 +0,0 @@
/***************************************************************/
/* */
/* GERMAN.H */
/* */
/* Support for the German language. */
/* */
/* This file was derived from a patch submitted by Wolfgang */
/* Thronicke. I don't guarantee that there are no mistakes - */
/* I don't speak German. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "German"
/* Day names */
#define L_SUNDAY "Sonntag"
#define L_MONDAY "Montag"
#define L_TUESDAY "Dienstag"
#define L_WEDNESDAY "Mittwoch"
#define L_THURSDAY "Donnerstag"
#define L_FRIDAY "Freitag"
#define L_SATURDAY "Samstag"
/* Month names */
#define L_JAN "Januar"
#define L_FEB "Februar"
#define L_MAR "März"
#define L_APR "April"
#define L_MAY "Mai"
#define L_JUN "Juni"
#define L_JUL "Juli"
#define L_AUG "August"
#define L_SEP "September"
#define L_OCT "Oktober"
#define L_NOV "November"
#define L_DEC "Dezember"
/* Today and tomorrow */
#define L_TODAY "heute"
#define L_TOMORROW "morgen"
/* The default banner */
#define L_BANNER "Termine für %w, den %d. %m %y%o:"
/* "am" and "pm" */
#define L_AM "am"
#define L_PM "pm"
/* Ago and from now */
#define L_AGO "vorher"
#define L_FROMNOW "von heute"
/* "in %d days' time" */
#define L_INXDAYS "in %d Tagen"
/* "on" as in "on date..." */
#define L_ON "am"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
#define L_PLURAL "en"
/* Minutes, hours, at, etc */
#define L_NOW "jetzt"
#define L_AT "um"
#define L_MINUTE "Minute"
#define L_HOUR "Stunde"
#define L_IS "ist"
#define L_WAS "war"
#define L_AND "und"
/* What to add to make "hour" plural */
#define L_HPLU "n"
/* What to add to make "minute" plural */
#define L_MPLU "n"
/* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc.
See the file dosubst.c for more info. */
#define L_AMPM_OVERRIDE(ampm, hour) ampm = (hour < 12) ? (hour<5) ? " nachts" : " vormittags" : (hour > 17) ? " abends" : " nachmittags";
#define L_ORDINAL_OVERRIDE plu = ".";
#define L_A_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s %d", DayName[dse%7], d, MonthName[m], y); } else { sprintf(s, "%s %s, den %d. %s %d", L_ON, DayName[dse%7], d, MonthName[m], y); }
#define L_G_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s", DayName[dse%7], d, MonthName[m]); } else { sprintf(s, "%s %s, den %d. %s", L_ON, DayName[dse%7], d, MonthName[m]); }
#define L_U_OVER L_A_OVER
#define L_V_OVER L_G_OVER

View File

@@ -1,79 +0,0 @@
/***************************************************************/
/* */
/* ICELANDIC.H */
/* */
/* Support for the Icelandic language. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Translated by Björn Davíðsson (bjossi@snerpa.is) */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "Icelandic"
/* Day names */
#define L_SUNDAY "sunnudagur"
#define L_MONDAY "mánudagur"
#define L_TUESDAY "þriðjudagur"
#define L_WEDNESDAY "miðvikudagur"
#define L_THURSDAY "fimmtudagur"
#define L_FRIDAY "föstudagur"
#define L_SATURDAY "laugardagur"
/* Month names */
#define L_JAN "janúar"
#define L_FEB "febrúar"
#define L_MAR "mars"
#define L_APR "apríl"
#define L_MAY "maí"
#define L_JUN "júní"
#define L_JUL "júlí"
#define L_AUG "ágúst"
#define L_SEP "september"
#define L_OCT "október"
#define L_NOV "nóvember"
#define L_DEC "desember"
/* Today and tomorrow */
#define L_TODAY "í dag"
#define L_TOMORROW "á morgun"
/* The default banner */
#define L_BANNER "Minnisatriði: %w, %d%s %m, %y%o:"
/* "am" and "pm" */
#define L_AM "fh"
#define L_PM "eh"
/* Ago and from now */
#define L_AGO "síðan"
#define L_FROMNOW "frá því nú"
/* "in %d days' time" */
#define L_INXDAYS "eftir %d daga"
/* "on" as in "on date..." */
#define L_ON "þann"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
#define L_PLURAL "a"
/* Minutes, hours, at, etc */
#define L_NOW "núna"
#define L_AT "kl."
#define L_MINUTE "mínútu"
#define L_HOUR "klukkustund"
#define L_IS "er"
#define L_WAS "var"
#define L_AND "og"
/* What to add to make "hour" plural */
#define L_HPLU "ir"
/* What to add to make "minute" plural */
#define L_MPLU "r"
/* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc.
See the file dosubst.c for more info. */

View File

@@ -1,114 +0,0 @@
/***************************************************************/
/* */
/* ITALIAN.H */
/* */
/* Support for the Italian language. */
/* */
/* This file is part of REMIND. */
/* It is Copyright (C) 1996 by Valerio Aimale */
/* */
/* Remind is copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "Italian"
/* Day names */
#define L_SUNDAY "Domenica"
#define L_MONDAY "Lunedì"
#define L_TUESDAY "Martedì"
#define L_WEDNESDAY "Mercoledì"
#define L_THURSDAY "Giovedì"
#define L_FRIDAY "Venerdì"
#define L_SATURDAY "Sabato"
/* Month names */
#define L_JAN "Gennaio"
#define L_FEB "Febbraio"
#define L_MAR "Marzo"
#define L_APR "Aprile"
#define L_MAY "Maggio"
#define L_JUN "Giugno"
#define L_JUL "Luglio"
#define L_AUG "Agosto"
#define L_SEP "Settembre"
#define L_OCT "Ottobre"
#define L_NOV "Novembre"
#define L_DEC "Dicembre"
/* Today and tomorrow */
#define L_TODAY "oggi"
#define L_TOMORROW "domani"
/* The default banner */
#define L_BANNER "Promemoria per %w, %d %m %y%o:"
/* "am" and "pm" */
#define L_AM "am"
#define L_PM "pm"
/* Ago and from now */
#define L_AGO "fa"
#define L_FROMNOW "da oggi"
/* "in %d days' time" */
#define L_INXDAYS "fra %d giorni"
/* "on" as in "on date..." */
#define L_ON ""
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
/* Minutes, hours, at, etc */
#define L_NOW "ora"
#define L_AT "alle"
#define L_MINUTE "minut"
#define L_HOUR "or"
#define L_IS "è"
#define L_WAS "era"
#define L_AND "e"
/* What to add to make "hour" plural */
#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_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[dse%7], d,\
MonthName[m], y);
#define L_C_OVER sprintf(s, "%s", DayName[dse%7]);
#define L_E_OVER sprintf(s, "%02d%c%02d%c%04d", d, DateSep,\
m+1, 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[dse%7], d, MonthName[m]);
#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_J_OVER sprintf(s, "%s, %d %s %d", DayName[dse%7], d, \
MonthName[m], y);
#define L_K_OVER sprintf(s, "%s, %d %s", DayName[dse%7], 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[dse%7], d, \
MonthName[m], y);
#define L_V_OVER sprintf(s, "%s, %d %s", DayName[dse%7], d, \
MonthName[m]);

View File

@@ -1,84 +0,0 @@
/***************************************************************/
/* */
/* NORWGIAN.H */
/* */
/* Support for the Norwegian language. */
/* */
/* This file is part of REMIND. */
/* This file is Copyright (C) 1993 by Trygve Randen. */
/* Remind is Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "Norwegian"
/* Day names */
#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"
#define L_SATURDAY "Lørdag"
/* Month names */
#define L_JAN "Januar"
#define L_FEB "Februar"
#define L_MAR "Mars"
#define L_APR "April"
#define L_MAY "Mai"
#define L_JUN "Juni"
#define L_JUL "Juli"
#define L_AUG "August"
#define L_SEP "September"
#define L_OCT "Oktober"
#define L_NOV "November"
#define L_DEC "Desember"
/* Today and tomorrow */
#define L_TODAY "i dag"
#define L_TOMORROW "i morgen"
/* The default banner */
#define L_BANNER "Påminnelse for %w, %d. %m, %y%o:"
/* "am" and "pm" */
#define L_AM "am"
#define L_PM "pm"
/* Ago and from now */
#define L_AGO "siden"
#define L_FROMNOW "fra nå"
/* "in %d days' time" */
#define L_INXDAYS "om %d dager"
/* "on" as in "on date..." */
#define L_ON "den"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
#define L_PLURAL "er"
/* Minutes, hours, at, etc */
#define L_NOW "nå"
#define L_AT "kl."
#define L_MINUTE "minutt"
#define L_HOUR "time"
#define L_IS "er"
#define L_WAS "var"
#define L_AND "og"
/* What to add to make "hour" plural */
#define L_HPLU "r"
/* What to add to make "minute" plural */
#define L_MPLU "er"
/* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc.
See the file dosubst.c for more info. */
#define L_ORDINAL_OVERRIDE plu = ".";
#define L_A_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s %d", DayName[dse%7], d, MonthName[m], y); } else { sprintf(s, "%s %s, den %d. %s %d", L_ON, DayName[dse%7], d, MonthName[m], y); }
#define L_G_OVER if (altmode == '*') { sprintf(s, "%s, den %d. %s", DayName[dse%7], d, MonthName[m]); } else { sprintf(s, "%s %s, den %d. %s", L_ON, DayName[dse%7], d, MonthName[m]); }
#define L_U_OVER L_A_OVER
#define L_V_OVER L_G_OVER

View File

@@ -1,281 +0,0 @@
/***************************************************************/
/* */
/* POLISH.H */
/* */
/* Support for the Polish language. */
/* */
/* This file was submitted by Jerzy Sobczyk. I don't */
/* guarantee that there are no mistakes - I don't speak */
/* Polish. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "Polish"
/* Day names */
# define L_SUNDAY "Niedziela"
# define L_MONDAY "Poniedziałek"
# define L_TUESDAY "Wtorek"
# define L_WEDNESDAY "Środa"
# define L_THURSDAY "Czwartek"
# define L_FRIDAY "Piątek"
# define L_SATURDAY "Sobota"
/* Month names */
# define L_JAN "Styczeń"
# define L_FEB "Luty"
# define L_MAR "Marzec"
# define L_APR "Kwiecień"
# define L_MAY "Maj"
# define L_JUN "Czerwiec"
# define L_JUL "Lipiec"
# define L_AUG "Sierpień"
# define L_SEP "Wrzesień"
# define L_OCT "Październik"
# define L_NOV "Listopad"
# define L_DEC "Grudzień"
/* Today and tomorrow */
#define L_TODAY "dzisiaj"
#define L_TOMORROW "jutro"
/* The default banner */
#define L_BANNER "Terminarz na %w, %d. %m %y%o:"
/* "am" and "pm" */
#define L_AM "am"
#define L_PM "pm"
/* Ago and from now */
#define L_AGO "temu"
#define L_FROMNOW "od teraz"
/* "in %d days' time" */
#define L_INXDAYS "za %d dni"
/* "on" as in "on date..." */
#define L_ON "-"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
#define L_PLURAL ""
/* Minutes, hours, at, etc */
#define L_NOW "teraz"
#define L_AT "o"
#define L_MINUTE "minut"
#define L_HOUR "godzin"
# define L_IS "będzie"
# define L_WAS "było"
#define L_AND "i"
#define L_HPLU ""
#define L_MPLU ""
/* What to add to make "hour" or "minute" plural */
#define L_NPLU( N ) ((N == 1) ? "ę" : ((N==12) || (N==13) || (N==14)) ? "" : \
((N%10==2) || (N%10==3) || (N%10==4)) ? "y" : "" )
/* What to add to make "hour" plural */
#define L_HPLU_OVER hplu = L_NPLU( hdiff );
/* What to add to make "minute" plural */
#define L_MPLU_OVER mplu = L_NPLU( mdiff );
/* Define any overrides here, such as L_ORDINAL_OVERRIDE, L_A_OVER, etc.
See the file dosubst.c for more info. */
#define L_AMPM_OVERRIDE(ampm, hour) \
ampm = (hour<12) ? \
(hour<5) ? " w nocy" \
: (hour<10) ? " rano" \
: " przed południem" \
: (hour<18) ? " po południu" \
: (hour<22) ? " wieczorem" \
: " w nocy";
#define L_ORDINAL_OVERRIDE plu = "";
#define L_A_OVER if (altmode == '*') { sprintf(s, "%s, %d. %s %d", DayName[dse%7], d, MonthName[m], y); } else { sprintf(s, "%s %s, %d. %s %d", L_ON, DayName[dse%7], d, MonthName[m], y); }
#define L_G_OVER if (altmode == '*') { sprintf(s, "%s, %d. %s", DayName[dse%7], d, MonthName[m]); } else { sprintf(s, "%s %s, %d. %s", L_ON, DayName[dse%7], d, MonthName[m]); }
#define L_U_OVER L_A_OVER
#define L_V_OVER L_G_OVER
#define L_0_OVER sprintf(s, L_NPLU(hdiff));
#define L_9_OVER sprintf(s, L_NPLU(mdiff));
#define L_1_OVER \
if (tdiff == 0) \
sprintf(s, L_NOW); \
else if (tdiff > 0) \
{ \
if (hdiff == 0) \
sprintf(s, "za %d %s%s", mdiff, L_MINUTE, L_NPLU(mdiff)); \
else if (mdiff == 0) \
sprintf(s, "za %d %s%s", hdiff, L_HOUR, L_NPLU(hdiff)); \
else \
sprintf(s, "za %d %s%s %s %d %s%s", hdiff, L_HOUR, L_NPLU(hdiff), \
L_AND, mdiff, L_MINUTE, L_NPLU(mdiff)); \
} \
else \
{ \
if (hdiff == 0) \
sprintf(s, "%d %s%s temu", mdiff, L_MINUTE, L_NPLU(mdiff)); \
else if (mdiff == 0) \
sprintf(s, "%d %s%s temu", hdiff, L_HOUR, L_NPLU(hdiff)); \
else \
sprintf(s, "%d %s%s %s %d %s%s temu", hdiff, L_HOUR, L_NPLU(hdiff), \
L_AND, mdiff, L_MINUTE, L_NPLU(mdiff)); \
}
/* The next ones are used only when MK_GLOBALS is set */
#ifdef MK_GLOBALS
#define L_ERR_OVERRIDE 1
EXTERN char *ErrMsg[] =
{
"OK",
"Brakujący ']'",
"Brakujący nawias",
"Zbyt skomplikowane wyrażenie",
"Zbyt skomplikowane wyrażenie - za dużo argumentów",
"Brakujący ')'",
"Nie zdefiniowana funkcja",
"Nielegalny znak",
"Spodziewany operator binarny",
"Brak pamięci",
"Niepoprawny numer",
"Pusty stos operatorów - błąd wewnętrzny",
"Pusty stos zmiennych - błąd wewnętrzny",
"Niemożliwa konwersja",
"Błąd typu",
"Nadmiar daty",
"Błąd stosu - błąd wewnętrzny",
"Dzielenie przez zero",
"Niezdefiniowana zmienna",
"Niespodziewany koniec linii",
"Niespodziewany koniec pliku",
"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ę ominąć (OMIT) wszystkich dni",
"Niespodziewany wyraz w lini",
"POP-OMIT-CONTEXT bez PUSH-OMIT-CONTEXT",
"Komenda RUN zablokowana",
"Błąd dziedziny",
"Niepoprawny identyfikator",
"Wykryto rekursywne wywołanie funkcji",
"",
"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",
"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łędna data hebrajska",
"IIF wymaga nieparzystej liczby argumentów",
"Ostrzeżenie: Brakujacy ENDIF",
"Oczekiwany przecinek",
"Dzień tygodnia podany dwókrotnie",
"Dozwolone tylko jedno z: BEFORE, AFTER i SKIP",
"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łowo THROUGH/UNTIL użyte dwókrotnie",
"Niekompletna specyfikacja daty",
"Słowo FROM/SCANFROM użyte dwókrotnie",
"Zmienna",
"Wartość",
"*NIE ZDEFINIOWANE*",
"Początek UserFN",
"Koniec UserFN",
"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ż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żenia",
"Nie mogę zmienić daty dostępu pliku %s\n",
"Remind: '-i' option: %s\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",
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT",
"Oczekiwana nazwa dnia tygodnia",
"Zduplikowana nazwa argumentu",
"Ocena wyrażeń jest wyłączona",
};
#endif /* MK_GLOBALS */
/* The following is only used in init.c */
#ifdef L_IN_INIT
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
fprintf(ErrFp, "\nSposób użycia: remind [opcje] plik [data] [czas] [*powtórzenie]\n");
fprintf(ErrFp, "Opcje:\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ś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łe przypomnienia niezależnie od delty\n");
fprintf(ErrFp, " -h Praca bezszmerowa\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");
fprintf(ErrFp, " -d... Odpluskwianie: e=echo x=expr-eval t=trig v=dumpvars l=showline\n");
fprintf(ErrFp, " -e Komunikaty o błędach skieruj na stdout\n");
fprintf(ErrFp, " -b[n] Format czasu: 0=am/pm, 1=24godz., 2=żaden\n");
fprintf(ErrFp, " -x[n] Limit powtórzeń klauzuli SATISFY (domyślnie=1000)\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

@@ -1,290 +0,0 @@
/***************************************************************/
/* */
/* PORTBR.H */
/* */
/* Support for the Brazilian Portuguese Language. */
/* */
/* Contributed by Marco Paganini (paganini@ism.com.br). */
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
/* This file is Copyright (C) 1996 by Marco Paganini and */
/* Dianne Skoll. */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "Brazilian Portuguese"
/* Day names */
#define L_SUNDAY "domingo"
#define L_MONDAY "segunda"
#define L_TUESDAY "terca"
#define L_WEDNESDAY "quarta"
#define L_THURSDAY "quinta"
#define L_FRIDAY "sexta"
#define L_SATURDAY "sabado"
/* Month names */
#define L_JAN "janeiro"
#define L_FEB "fevereiro"
#define L_MAR "marco"
#define L_APR "abril"
#define L_MAY "maio"
#define L_JUN "junho"
#define L_JUL "julho"
#define L_AUG "agosto"
#define L_SEP "setembro"
#define L_OCT "outubro"
#define L_NOV "novembro"
#define L_DEC "dezembro"
/* Today and tomorrow */
#define L_TODAY "hoje"
#define L_TOMORROW "amanha"
/* The default banner */
#define L_BANNER "Avisos para %w, %d de %m de %y%o:"
/* "am" and "pm" */
#define L_AM "am"
#define L_PM "pm"
/* Ago and from now */
#define L_AGO "atras"
#define L_FROMNOW "adiante"
/* "in %d days' time" */
#define L_INXDAYS "em %d dias"
/* "on" as in "on date..." */
#define L_ON "em"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
#define L_PLURAL "s"
/* Minutes, hours, at, etc */
#define L_NOW "agora"
#define L_AT "as"
#define L_MINUTE "minuto"
#define L_HOUR "hora"
#define L_IS "sao"
#define L_WAS "eram"
#define L_AND "e"
/* What to add to make "hour" plural */
#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_ORDINAL_OVERRIDE plu = "";
/* Portuguese weekdays must be treated separately */
#define _ON_WEEKDAY(x) ((x % 7) < 2) ? "no" : "na"
#define L_A_OVER \
sprintf(s, "%s %s, %d de %s de %d", _ON_WEEKDAY(dse), DayName[dse%7], d, MonthName[m], y);
#define L_C_OVER \
sprintf(s, "%s %s", _ON_WEEKDAY(dse), DayName[dse%7]);
#define L_G_OVER \
sprintf(s, "%s %s, %d %s", _ON_WEEKDAY(dse), DayName[dse%7], d, MonthName[m]);
#define L_J_OVER \
sprintf(s, "%s %s, %d de %s de %d", _ON_WEEKDAY(dse), DayName[dse%7], d, MonthName[m], y);
#define L_K_OVER \
sprintf(s, "%s %s, %d de %s", _ON_WEEKDAY(dse), DayName[dse%7], d, MonthName[m]);
/* Portuguese does not use some suffixes, some some %u and %j are the same */
#define L_U_OVER \
sprintf(s, "%s %s, %d de %s de %d", _ON_WEEKDAY(dse), DayName[dse%7], d, MonthName[m], y);
#define L_V_OVER \
sprintf(s, "%s %s, %d de %s", _ON_WEEKDAY(dse), DayName[dse%7], d, MonthName[m]);
#define L_1_OVER \
{ \
if (tdiff == 0) \
sprintf(s, L_NOW); \
else \
if (hdiff == 0) \
{ \
if (mdiff > 0) \
sprintf(s, "em %d %s%s", mdiff, L_MINUTE, mplu); \
else \
sprintf(s, "%d %s%s atras", mdiff, L_MINUTE, mplu); \
} \
else if (mdiff == 0) \
{ \
if (hdiff > 0) \
sprintf(s, "em %d %s%s", hdiff, L_HOUR, hplu); \
else \
sprintf(s, "%d %s%s atras", hdiff, L_HOUR, hplu); \
} else { \
if (tdiff > 0) \
sprintf(s, "em %d %s%s %s %d %s%s", hdiff, L_HOUR, hplu, L_AND, mdiff, L_MINUTE, mplu); \
else \
sprintf(s, "%d %s%s %s %d %s%s atras", hdiff, L_HOUR, hplu, L_AND, mdiff, L_MINUTE, mplu); \
} \
}
/* The next ones are used only when MK_GLOBALS is set */
#ifdef MK_GLOBALS
#define L_ERR_OVERRIDE 1
EXTERN char *ErrMsg[] =
{
"Ok",
"Falta um ']'",
"Falta uma aspa",
"Expressao muito complexa",
"Expressao muito complexa - muitos operandos",
"Falta um ')'",
"Funcao nao definida",
"Caracter ilegal",
"Esperando operador binario",
"Sem memoria",
"Numero mal-formado",
"Op stack underflow - erro interno",
"Va stack underflow - erro interno",
"Nao consigo fazer 'coerce'",
"Type mismatch",
"Overflow na data",
"Erro de stack - erro interno",
"Divisao por zero",
"Variavel nao definida",
"Fim da linha nao esperado",
"Fim de arquivo nao esperado",
"Erro de I/O",
"Linha muito longa",
"Erro interno",
"Especificacao de data invalida",
"Argumentos insuficientes",
"Argumentos em excesso",
"Hora mal-formada",
"Numero muito grande",
"Numero muito pequeno",
"Nao consigo abrir o arquivo",
"Ninho de INCLUDEs muito profundo",
"Erro de parsing",
"Nao consigo computar o 'trigger'",
"Muitos IFs aninhados",
"ELSE sem o IF correspondente",
"ENDIF sem o IF correspondente",
"Nao se pode usar OMIT para todos os dias da semana",
"Token nao reconhecido na linha",
"POP-OMIT-CONTEXT sem PUSH-OMIT-CONTEXT correspondente",
"RUN desabilitado",
"Erro de dominio",
"Identificados invalido",
"Chamada de funcao recursiva detectada",
"",
"Nao posso modificar variavel de sistema",
"Funcao da biblioteca C nao pode representar data/hora",
"Tentativa de redefinir funcao interna",
"Nao e' possivel aninhar definicao de funcao em expressao",
"Data deve ser completamente especificada para usar o fator de REPEAT",
"Ano especificado duas vezes",
"Mes especificado duas vezes",
"Dia especificado duas vezes",
"Token desconhecido",
"O mes deve ser especificados no comando OMIT",
"Muitos OMITs parciais",
"Muitos OMITs full",
"Aviso: PUSH-OMIT-CONTEXT sem POP-OMIT-CONTEXT correspondente",
"Erro na leitura do arquivo",
"Aguardando fim do arquivo",
"Data hebraica invalida",
"IIF necessita de numero impar de argumentos",
"Warning: ENDIF faltando",
"Esperando virgula",
"Dia da semana especificado duas vezes",
"Use apenas um de BEFORE, AFTER ou SKIP",
"Nao e possivel aninhar MSG, MSF, RUN, etc. em expressoes",
"Valor de Repeat especificado duas vezes",
"Valor de Delta especificado duas vezes",
"Valor de Back especificado duas vezes",
"ONCE usado duas vezes (Eheheh)",
"Esperando hora apos AT",
"Keyword THROUGH/UNTIL usada duas vezes",
"Especificacao de data incompleta",
"Keyword FROM/SCANFROM usada duas vezes",
"Variavel",
"Valor",
"*INDEFINIDO*",
"Entrando UserFN",
"Saindo UserFN",
"Expirou",
"fork() falhou - Nao posso processar compromissos na fila",
"Nao consigo acessar o arquivo",
"Data do sistema ilegal: Ano e menor que %d\n",
"Flag de debug desconhecido '%c'\n",
"Opcao desconhecida '%c'\n",
"Usuario desconhecido '%s'\n",
"Nao consigo mudar gid para %d\n",
"Nao consigo mudar uid para %d\n",
"Sem memoria para o environment\n",
"Falta o sinal de '='",
"Falta o nome da variavel",
"Falta a expressao",
"Nao consigo resetar a data de acesso de %s\n",
"Remind: '-i' opcao: %s\n",
"Sem compromissos.",
"%d compromisso(s) colocados na fila para mais tarde.\n",
"Esperando numero",
"Funcao ilegal na clausula WARN",
"Can't convert between time zones",
"No files matching *.rem",
"String too long",
"Time specified twice",
"Cannot specify DURATION without specifying AT",
"Esperando nome do dia da semana",
"Nome de argumento duplicado",
"A avaliação da expressão está desabilitada",
};
#endif /* MK_GLOBALS */
/* The following is only used in init.c */
#ifdef L_IN_INIT
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (versao %s) (C) 1992-2024 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> VERSAO BETA <<<<\n");
#endif
fprintf(ErrFp, "Uso: remind [opcoes] arquivo [data] [hora] [*rep]\n");
fprintf(ErrFp, "Opcoes:\n");
fprintf(ErrFp, " -n Imprime a proxima ocorrencia em formato simples\n");
fprintf(ErrFp, " -r Desabilita a diretiva RUN\n");
fprintf(ErrFp, " -c[n] Produz calendario para n (default 1) meses\n");
fprintf(ErrFp, " -c+[n] Produz calendario para n (default 1) semanas\n");
fprintf(ErrFp, " -w[n[,p[,s]]] Especifica largura, preenchimento e espacejamento do calendario\n");
fprintf(ErrFp, " -s[+][n] Produz um `calendario simples' para n (1) meses (semanas)\n");
fprintf(ErrFp, " -p[n] Identico a -s, porem com saida compativel com rem2ps\n");
fprintf(ErrFp, " -v Modo verbose\n");
fprintf(ErrFp, " -o Ignora diretivas ONCE\n");
fprintf(ErrFp, " -t Aciona todos os compromissos futuros, sem considerar o delta\n");
fprintf(ErrFp, " -h Modo `Hush' - quieto\n");
fprintf(ErrFp, " -a Nao aciona compromissos com hora imediatamente - apenas coloca na fila\n");
fprintf(ErrFp, " -q Nao coloca compromissos com hora na fila\n");
fprintf(ErrFp, " -f Aciona compromissos com hora em modo foreground\n");
fprintf(ErrFp, " -z[n] Modo `daemon', acordando a cada n (5) minutos.\n");
fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trigger v=dumpvars l=showline\n");
fprintf(ErrFp, " -e Desvia mensagens normalmente enviadas a stderr para stdout\n");
fprintf(ErrFp, " -b[n] Formato da hora para o cal: 0=am/pm, 1=24hr, 2=nenhum\n");
fprintf(ErrFp, " -x[n] Limite de iteracoes para a clausula SATISFY (default=1000)\n");
fprintf(ErrFp, " -kcmd Executa `cmd' para os compromissos com MSG\n");
fprintf(ErrFp, " -g[ddd] Classifica compromissos por data, hora e prioridade antes de exibir\n");
fprintf(ErrFp, " -ivar=val Inicializa (e preserva) variavel var com val\n");
fprintf(ErrFp, " -m Inicia o calendario na segunda, ao inves de domingo\n");
exit(1);
}
#endif /* L_IN_INIT */

View File

@@ -1,105 +0,0 @@
/***************************************************************/
/* */
/* ROMANIAN.H */
/* */
/* Support for the Romanian language. */
/* */
/* Contributed by Liviu Daia <daia@stoilow.imar.ro> */
/* */
/* This file is part of REMIND. */
/* */
/* REMIND is Copyright (C) 1992-2024 by Dianne Skoll */
/* This file is Copyright (C) 1996-1998 by Liviu Daia */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
/* The very first define in a language support file must be L_LANGNAME: */
#define L_LANGNAME "Romanian"
/* Day names */
# define L_SUNDAY "Duminică"
# define L_MONDAY "Luni"
# define L_TUESDAY "Marți"
# define L_WEDNESDAY "Miercuri"
# define L_THURSDAY "Joi"
# define L_FRIDAY "Vineri"
# define L_SATURDAY "Sâmbătă"
/* Month names */
#define L_JAN "Ianuarie"
#define L_FEB "Februarie"
#define L_MAR "Martie"
#define L_APR "Aprilie"
#define L_MAY "Mai"
#define L_JUN "Iunie"
#define L_JUL "Iulie"
#define L_AUG "August"
#define L_SEP "Septembrie"
#define L_OCT "Octombrie"
#define L_NOV "Noiembrie"
#define L_DEC "Decembrie"
/* Today and tomorrow */
# define L_TODAY "astăzi"
# define L_TOMORROW "mâine"
/* The default banner */
#define L_BANNER "Reamintiri pentru %w, %d %m %y%o:"
/* "am" and "pm" */
#define L_AM "am"
#define L_PM "pm"
/* Ago and from now */
#define L_AGO "acum"
#define L_FROMNOW "peste"
/* "in %d days' time" */
#define L_INXDAYS "peste %d zile"
/* "on" as in "on date..." */
#define L_ON "pe"
/* Pluralizing - this is a problem for many languages and may require
a more drastic fix */
#define L_PLURAL "le"
/* Minutes, hours, at, etc */
#define L_NOW "acum"
#define L_AT "la ora"
#define L_MINUTE "minut"
#define L_HOUR "or"
#define L_IS "este"
#define L_WAS "a fost"
/* What to add to make "minute" plural */
#define L_MPLU "e"
#define L_HPLU "e"
/* 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. */
#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[dse%7], d, MonthName[m], y);
#define L_C_OVER sprintf(s, "%s", DayName[dse%7]);
#define L_G_OVER sprintf(s, "%s, %d %s", DayName[dse%7], d, MonthName[m]);
#define L_J_OVER sprintf(s, "%s, %s %d, %d", DayName[dse%7], MonthName[m], d, y);
#define L_K_OVER sprintf(s, "%s, %s %d", DayName[dse%7], MonthName[m], d);
#define L_S_OVER
#define L_U_OVER sprintf(s, "%s, %d %s %d", DayName[dse%7], d, MonthName[m], y);
#define L_V_OVER sprintf(s, "%s, %d %s", DayName[dse%7], d, MonthName[m]);
#define L_1_OVER \
if (tdiff == 0) \
sprintf(s, L_NOW); \
else if (hdiff == 0) \
sprintf(s, "%s %d %s%s", when, mdiff, L_MINUTE, mplu); \
else if (mdiff == 0) \
sprintf(s, "%s %d %s%s", when, hdiff, L_HOUR, hplu); \
else \
sprintf(s, "%s %d %s%s %s %d %s%s", when, hdiff, \
L_HOUR, hplu, L_AND, mdiff, L_MINUTE, mplu);

View File

@@ -1,74 +0,0 @@
/***************************************************************/
/* */
/* SPANISH.H */
/* */
/* Support for the Spanish language. */
/* */
/* Author: Rafa Couto <rafacouto@biogate.com> */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
#define L_LANGNAME "Spanish"
/* Nombres de los di'as de la semana */
#define L_SUNDAY "Domingo"
#define L_MONDAY "Lunes"
#define L_TUESDAY "Martes"
#define L_WEDNESDAY "Miércoles"
#define L_THURSDAY "Jueves"
#define L_FRIDAY "Viernes"
#define L_SATURDAY "Sábado"
/* Nombres de los meses */
#define L_JAN "Enero"
#define L_FEB "Febrero"
#define L_MAR "Marzo"
#define L_APR "Abril"
#define L_MAY "Mayo"
#define L_JUN "Junio"
#define L_JUL "Julio"
#define L_AUG "Agosto"
#define L_SEP "Septiembre"
#define L_OCT "Octubre"
#define L_NOV "Noviembre"
#define L_DEC "Diciembre"
/* Hoy y man~ana */
#define L_TODAY "hoy"
#define L_TOMORROW "mañana"
/* El titular habitual */
#define L_BANNER "Agenda para el %w, %d%s %m, %y%o:"
/* "am" and "pm" */
#define L_AM "am"
#define L_PM "pm"
/* Hace y desde hoy */
#define L_AGO "hace"
#define L_FROMNOW "desde hoy"
/* "dentro de %d di'as" */
#define L_INXDAYS "dentro de %d días"
#define L_ON "el día"
/* "el di'a..." */
/* plurales */
#define L_PLURAL "s"
/* Minutos, horas, a las, etc */
#define L_NOW "ahora"
#define L_AT "a las"
#define L_MINUTE "minuto"
#define L_HOUR "hora"
#define L_IS "es"
#define L_WAS "fue"
#define L_AND "y"
#define L_HPLU "s"
#define L_MPLU "s"

View File

@@ -6,7 +6,7 @@
/* routines, etc. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -60,19 +60,21 @@ exitfunc(void)
/* Kill any execution-time-limiter process */
unlimit_execution_time();
int maxlen, total;
double avglen;
if (DebugFlag & DB_PARSE_EXPR) {
if (DebugFlag & DB_HASHSTATS) {
fflush(stdout);
fflush(stderr);
get_var_hash_stats(&total, &maxlen, &avglen);
fprintf(stderr, " Var hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
get_userfunc_hash_stats(&total, &maxlen, &avglen);
fprintf(stderr, " Func hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
get_dedupe_hash_stats(&total, &maxlen, &avglen);
fprintf(stderr, "Dedup hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
get_translation_hash_stats(&total, &maxlen, &avglen);
fprintf(stderr, "Trans hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
fflush(ErrFp);
fprintf(ErrFp, "Variable hash table statistics:\n");
dump_var_hash_stats();
fprintf(ErrFp, "Function hash table statistics:\n");
dump_userfunc_hash_stats();
fprintf(ErrFp, "Dedupe hash table statistics:\n");
dump_dedupe_hash_stats();
fprintf(ErrFp, "Translation hash table statistics:\n");
dump_translation_hash_stats();
UnsetAllUserFuncs();
print_expr_nodes_stats();
}
@@ -128,7 +130,7 @@ int main(int argc, char *argv[])
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
if (sigaction(SIGALRM, &act, NULL) < 0) {
fprintf(stderr, "%s: sigaction() failed: %s\n",
fprintf(ErrFp, "%s: sigaction() failed: %s\n",
argv[0], strerror(errno));
exit(1);
}
@@ -137,12 +139,13 @@ int main(int argc, char *argv[])
act.sa_flags = SA_RESTART;
sigemptyset(&act.sa_mask);
if (sigaction(SIGXCPU, &act, NULL) < 0) {
fprintf(stderr, "%s: sigaction() failed: %s\n",
fprintf(ErrFp, "%s: sigaction() failed: %s\n",
argv[0], strerror(errno));
exit(1);
}
DBufInit(&(LastTrigger.tags));
LastTrigger.infos = NULL;
ClearLastTriggers();
atexit(exitfunc);
@@ -172,11 +175,12 @@ int main(int argc, char *argv[])
if (!Hush) {
if (DestroyOmitContexts(1))
Eprint("%s", ErrMsg[E_PUSH_NOPOP]);
Eprint("%s", GetErr(E_PUSH_NOPOP));
if (!Daemon && !NextMode && !NumTriggered && !NumQueued) {
printf("%s\n", ErrMsg[E_NOREMINDERS]);
printf("%s\n", GetErr(E_NOREMINDERS));
} else if (!Daemon && !NextMode && !NumTriggered) {
printf(ErrMsg[M_QUEUED], NumQueued);
printf(GetErr(M_QUEUED), NumQueued);
printf("\n");
}
}
@@ -196,7 +200,7 @@ int main(int argc, char *argv[])
return 0;
}
if (pid == -1) {
fprintf(ErrFp, "%s", ErrMsg[E_CANTFORK]);
fprintf(ErrFp, "%s", GetErr(E_CANTFORK));
return 1;
}
}
@@ -258,14 +262,14 @@ static void DoReminders(void)
}
if (FileAccessDate < 0) {
fprintf(ErrFp, "%s: `%s': %s.\n", ErrMsg[E_CANTACCESS], InitialFile, strerror(errno));
fprintf(ErrFp, "%s: `%s': %s.\n", GetErr(E_CANTACCESS), InitialFile, strerror(errno));
exit(EXIT_FAILURE);
}
r=IncludeFile(InitialFile);
if (r) {
fprintf(ErrFp, "%s %s: %s\n", ErrMsg[E_ERR_READING],
InitialFile, ErrMsg[r]);
fprintf(ErrFp, "%s %s: %s\n", GetErr(E_ERR_READING),
InitialFile, GetErr(r));
exit(EXIT_FAILURE);
}
@@ -273,7 +277,7 @@ static void DoReminders(void)
r = ReadLine();
if (r == E_EOF) return;
if (r) {
Eprint("%s: %s", ErrMsg[E_ERR_READING], ErrMsg[r]);
Eprint("%s: %s", GetErr(E_ERR_READING), GetErr(r));
exit(EXIT_FAILURE);
}
s = FindInitialToken(&tok, CurLine);
@@ -314,6 +318,7 @@ static void DoReminders(void)
case T_EndIf: r=DoEndif(&p); break;
case T_Include:
case T_IncludeR:
case T_IncludeSys:
/* In purge mode, include closes file, so we
need to echo it here! */
if (PurgeMode) {
@@ -370,7 +375,7 @@ static void DoReminders(void)
default:
if (!SuppressImplicitRemWarnings) {
Wprint("Unrecognized command; interpreting as REM");
Wprint(tr("Unrecognized command; interpreting as REM"));
WarnedAboutImplicit = 1;
}
DestroyParser(&p);
@@ -381,14 +386,14 @@ static void DoReminders(void)
}
if (r && (!Hush || r != E_RUN_DISABLED)) {
Eprint("%s", ErrMsg[r]);
Eprint("%s", GetErr(r));
}
if (PurgeMode) {
if (!purge_handled) {
PurgeEchoLine("%s\n", CurLine);
} else {
if (r) {
PurgeEchoLine("#!P! Could not parse next line: %s\n", ErrMsg[r]);
PurgeEchoLine("#!P! Could not parse next line: %s\n", GetErr(r));
PurgeEchoLine("%s\n", CurLine);
}
}
@@ -599,6 +604,24 @@ int ParseNonSpaceChar(ParsePtr p, int *err, int peek)
return ch;
}
/***************************************************************/
/* */
/* ParseTokenOrQuotedString */
/* */
/* Parse either a token or a double-quote-delimited string. */
/* */
/***************************************************************/
int ParseTokenOrQuotedString(ParsePtr p, DynamicBuffer *dbuf)
{
int c, err;
c = ParseNonSpaceChar(p, &err, 1);
if (err) return err;
if (c != '"') {
return ParseToken(p, dbuf);
}
return ParseQuotedString(p, dbuf);
}
/***************************************************************/
/* */
/* ParseQuotedString */
@@ -608,7 +631,9 @@ int ParseNonSpaceChar(ParsePtr p, int *err, int peek)
/***************************************************************/
int ParseQuotedString(ParsePtr p, DynamicBuffer *dbuf)
{
int c, err;
int c, err, c2;
char hexbuf[3];
DBufFree(dbuf);
c = ParseNonSpaceChar(p, &err, 0);
if (err) return err;
@@ -623,7 +648,7 @@ int ParseQuotedString(ParsePtr p, DynamicBuffer *dbuf)
DBufFree(dbuf);
return err;
}
while (c != '"') {
while (c != 0 && c != '"') {
if (c == '\\') {
c = ParseChar(p, &err, 0);
if (err) {
@@ -652,6 +677,34 @@ int ParseQuotedString(ParsePtr p, DynamicBuffer *dbuf)
case 'v':
err = DBufPutc(dbuf, '\v');
break;
case 'x':
/* \x Followed by one or two hex digits */
c2 = ParseChar(p, &err, 1);
if (err) break;
if (!isxdigit(c2)) {
err = DBufPutc(dbuf, c);
break;
}
hexbuf[0] = c2;
hexbuf[1] = 0;
c2 = ParseChar(p, &err, 0);
if (err) break;
c2 = ParseChar(p, &err, 1);
if (err) break;
if (isxdigit(c2)) {
hexbuf[1] = c2;
hexbuf[2] = 0;
c2 = ParseChar(p, &err, 0);
if (err) break;
}
c2 = (int) strtol(hexbuf, NULL, 16);
if (!c2) {
Eprint(tr("\\x00 is not a valid escape sequence"));
err = E_PARSE_ERR;
} else {
err = DBufPutc(dbuf, c2);
}
break;
default:
err = DBufPutc(dbuf, c);
}
@@ -668,6 +721,10 @@ int ParseQuotedString(ParsePtr p, DynamicBuffer *dbuf)
return err;
}
}
if (c != '"') {
DBufFree(dbuf);
return E_MISS_QUOTE;
}
return OK;
}
@@ -984,6 +1041,11 @@ int SystemTime(int realtime)
if (!realtime && (SysTime != -1)) return SysTime;
if (TestMode) {
/* Pretend it's 7:00PM in test mode */
return 19 * 3600;
}
now = time(NULL);
t = localtime(&now);
return t->tm_hour * 3600L + t->tm_min * 60L +
@@ -1017,6 +1079,14 @@ int SystemDate(int *y, int *m, int *d)
time_t now;
struct tm *t;
/* In test mode, always return 6 January 2025 */
if (TestMode) {
*y = 2025;
*m = 0;
*d = 6;
return 12789; /* 2025-01-06 */
}
now = time(NULL);
t = localtime(&now);
@@ -1045,7 +1115,7 @@ int DoIf(ParsePtr p)
else {
if ( (r = EvaluateExpr(p, &v)) ) {
syndrome = IF_TRUE | BEFORE_ELSE;
Eprint("%s", ErrMsg[r]);
Eprint("%s", GetErr(r));
} else
if ( (v.type != STR_TYPE && v.v.val) ||
(v.type == STR_TYPE && strcmp(v.v.str, "")) ) {
@@ -1130,7 +1200,7 @@ int DoIfTrig(ParsePtr p)
if (r) {
if (r != E_CANT_TRIG || !trig.maybe_uncomputable) {
if (!Hush || r != E_RUN_DISABLED) {
Eprint("%s", ErrMsg[r]);
Eprint("%s", GetErr(r));
}
}
syndrome = IF_FALSE | BEFORE_ELSE;
@@ -1194,7 +1264,7 @@ int VerifyEoln(ParsePtr p)
if (*DBufValue(&buf) &&
(*DBufValue(&buf) != '#') &&
(*DBufValue(&buf) != ';')) {
Eprint("%s: `%s'", ErrMsg[E_EXPECTING_EOL], DBufValue(&buf));
Eprint("%s: `%s'", GetErr(E_EXPECTING_EOL), DBufValue(&buf));
DBufFree(&buf);
return E_EXTRANEOUS_TOKEN;
}
@@ -1242,12 +1312,24 @@ int DoDebug(ParsePtr p)
else DebugFlag &= ~DB_ECHO_LINE;
break;
case 'q':
case 'Q':
if (val) DebugFlag |= DB_TRANSLATE;
else DebugFlag &= ~DB_TRANSLATE;
break;
case 's':
case 'S':
if (val) DebugFlag |= DB_PARSE_EXPR;
else DebugFlag &= ~DB_PARSE_EXPR;
break;
case 'h':
case 'H':
if (val) DebugFlag |= DB_HASHSTATS;
else DebugFlag &= ~DB_HASHSTATS;
break;
case 'x':
case 'X':
if (val) DebugFlag |= DB_PRTEXPR;
@@ -1277,6 +1359,9 @@ int DoDebug(ParsePtr p)
if (val) DebugFlag |= DB_TRACE_FILES;
else DebugFlag &= ~DB_TRACE_FILES;
break;
default:
Wprint(GetErr(M_BAD_DB_FLAG), ch);
break;
}
}
}
@@ -1861,6 +1946,10 @@ void
FreeTrig(Trigger *t)
{
DBufFree(&(t->tags));
if (t->infos) {
FreeTrigInfoChain(t->infos);
}
t->infos = NULL;
}
void
@@ -1886,8 +1975,7 @@ ClearLastTriggers(void)
LastTrigger.warn[0] = 0;
LastTrigger.omitfunc[0] = 0;
LastTrigger.passthru[0] = 0;
DBufFree(&(LastTrigger.tags));
FreeTrig(&LastTrigger);
LastTimeTrig.ttime = NO_TIME;
LastTimeTrig.delta = NO_DELTA;
LastTimeTrig.rep = NO_REP;
@@ -1907,10 +1995,19 @@ SaveAllTriggerInfo(Trigger const *t, TimeTrig const *tt, int trigdate, int trigt
void
SaveLastTrigger(Trigger const *t)
{
DBufFree(&(LastTrigger.tags));
FreeTrig(&LastTrigger);
memcpy(&LastTrigger, t, sizeof(LastTrigger));
/* DON'T hang on to the invalid info chain! */
LastTrigger.infos = NULL;
DBufInit(&(LastTrigger.tags));
DBufPuts(&(LastTrigger.tags), DBufValue(&(t->tags)));
TrigInfo *cur = t->infos;
while(cur) {
AppendTrigInfo(&LastTrigger, cur->info);
cur = cur->next;
}
}
void
@@ -1975,8 +2072,7 @@ get_day_name(int wkday)
if (wkday < 0 || wkday > 6) {
return "INVALID_WKDAY";
}
if (DynamicDayName[wkday]) return DynamicDayName[wkday];
return DayName[wkday];
return tr(DayName[wkday]);
}
char const *
@@ -1985,8 +2081,7 @@ get_month_name(int mon)
if (mon < 0 || mon > 11) {
return "INVALID_MON";
}
if (DynamicMonthName[mon]) return DynamicMonthName[mon];
return MonthName[mon];
return tr(MonthName[mon]);
}
static int GetOnceDateFromFile(void)
@@ -2005,7 +2100,7 @@ static int GetOnceDateFromFile(void)
/* Save today to file */
fp = fopen(OnceFile, "w");
if (!fp) {
Wprint("Warning: Unable to save ONCE timestamp to %s: %s",
Wprint(tr("Warning: Unable to save ONCE timestamp to %s: %s"),
OnceFile, strerror(errno));
return once_date;
}
@@ -2025,3 +2120,19 @@ int GetOnceDate(void)
}
return OnceDate;
}
char const *GetErr(int r)
{
char const *msg;
if (r < 0 || r >= NumErrs) {
r = E_SWERR;
}
msg = GetTranslatedString(ErrMsg[r]);
if (!msg) {
return ErrMsg[r];
}
return msg;
}

View File

@@ -5,7 +5,7 @@
/* Calculations for figuring out moon phases. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/

View File

@@ -6,7 +6,7 @@
/* the data structures for OMITted dates. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -92,7 +92,7 @@ int DestroyOmitContexts(int print_unmatched)
while (c) {
if (print_unmatched) {
Wprint("Unmatched PUSH-OMIT-CONTEXT at %s(%d)",
Wprint(tr("Unmatched PUSH-OMIT-CONTEXT at %s(%d)"),
c->filename, c->lineno);
}
num++;
@@ -185,6 +185,9 @@ int PopOmitContext(ParsePtr p)
/* Remove the context from the stack */
SavedOmitContexts = c->next;
if (c->filename && FileName && strcmp(c->filename, FileName)) {
Wprint(tr("POP-OMIT-CONTEXT at %s:%d matches PUSH-OMIT-CONTEXT in different file: %s:%d"), FileName, LineNo, c->filename, c->lineno);
}
/* Free memory used by the saved context */
if (c->partsave) free(c->partsave);
if (c->fullsave) free(c->fullsave);
@@ -215,7 +218,7 @@ int IsOmitted(int dse, int localomit, char const *omitfunc, int *omit)
Value v;
FromDSE(dse, &y, &m, &d);
sprintf(expr, "%s('%04d-%02d-%02d')",
snprintf(expr, sizeof(expr), "%s('%04d-%02d-%02d')",
omitfunc, y, m+1, d);
s = expr;
r = EvalExpr(&s, &v, NULL);
@@ -385,6 +388,7 @@ int DoOmit(ParsePtr p)
case T_RemType:
case T_Priority:
case T_Tag:
case T_Info:
case T_Duration:
DBufFree(&buf);
parsing = 0;
@@ -392,11 +396,11 @@ int DoOmit(ParsePtr p)
default:
if (tok.type == T_Until) {
Eprint("OMIT: UNTIL not allowed; did you mean THROUGH?");
Eprint(tr("OMIT: UNTIL not allowed; did you mean THROUGH?"));
} else if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
Eprint("%s: `%s'", GetErr(-tok.val), DBufValue(&buf));
} else {
Eprint("%s: `%s' (OMIT)", ErrMsg[E_UNKNOWN_TOKEN],
Eprint("%s: `%s' (OMIT)", GetErr(E_UNKNOWN_TOKEN),
DBufValue(&buf));
}
DBufFree(&buf);
@@ -412,7 +416,7 @@ int DoOmit(ParsePtr p)
return E_2MANY_LOCALOMIT;
}
WeekdayOmits |= wd;
if (tok.type == T_Tag || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
if (tok.type == T_Tag || tok.type == T_Info || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
return OK;
}
@@ -462,7 +466,7 @@ int DoOmit(ParsePtr p)
InsertIntoSortedArray(PartialOmitArray, NumPartialOmits, syndrome);
NumPartialOmits++;
if (NumPartialOmits == 366) {
Wprint("You have OMITted everything! The space-time continuum is at risk.");
Wprint(tr("You have OMITted everything! The space-time continuum is at risk."));
}
}
if (mc == m[1] && dc == d[1]) {
@@ -484,7 +488,7 @@ int DoOmit(ParsePtr p)
start = DSE(y[0], m[0], d[0]);
end = DSE(y[1], m[1], d[1]);
if (end < start) {
Eprint("Error: THROUGH date earlier than start date");
Eprint(tr("Error: THROUGH date earlier than start date"));
return E_BAD_DATE;
}
@@ -497,7 +501,7 @@ int DoOmit(ParsePtr p)
}
}
if (tok.type == T_Tag || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
if (tok.type == T_Tag || tok.type == T_Info || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
return OK;
}
@@ -544,7 +548,7 @@ DumpOmits(void)
} else {
for (i=0; i<7; i++) {
if (WeekdayOmits & (1<<i)) {
printf("\t%s\n", EnglishDayName[i]);
printf("\t%s\n", DayName[i]);
}
}
}

View File

@@ -5,7 +5,7 @@
/* Function Prototypes. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -88,6 +88,7 @@ int JulianToGregorianOffset(int y, int m);
int ParseChar (ParsePtr p, int *err, int peek);
int ParseToken (ParsePtr p, DynamicBuffer *dbuf);
int ParseQuotedString (ParsePtr p, DynamicBuffer *dbuf);
int ParseTokenOrQuotedString (ParsePtr p, DynamicBuffer *dbuf);
int ParseIdentifier (ParsePtr p, DynamicBuffer *dbuf);
expr_node * ParseExpr(ParsePtr p, int *r);
void print_expr_nodes_stats(void);
@@ -114,6 +115,7 @@ int DoRun (ParsePtr p);
int DoExpr (ParsePtr p);
int DoTranslate (ParsePtr p);
int InsertTranslation(char const *orig, char const *translated);
void DumpTranslationTable(FILE *fp, int json);
int DoErrMsg (ParsePtr p);
int ClearGlobalOmits (void);
int DoClear (ParsePtr p);
@@ -227,7 +229,6 @@ void set_cloexec(FILE *fp);
int push_call(char const *filename, char const *func, int lineno);
void clear_callstack(void);
int print_callstack(FILE *fp);
int have_callstack(void);
void pop_call(void);
void FixSpecialType(Trigger *trig);
void WriteJSONTrigger(Trigger const *t, int include_tags, int today);
@@ -254,10 +255,10 @@ void print_builtinfunc_tokens(void);
void print_remind_tokens(void);
/* Stats for -ds output */
void get_var_hash_stats(int *total, int *maxlen, double *avglen);
void get_userfunc_hash_stats(int *total, int *maxlen, double *avglen);
void get_dedupe_hash_stats(int *total, int *maxlen, double *avglen);
void get_translation_hash_stats(int *total, int *maxlen, double *avglen);
void dump_var_hash_stats(void);
void dump_userfunc_hash_stats(void);
void dump_dedupe_hash_stats(void);
void dump_translation_hash_stats(void);
/* Dedupe code */
int ShouldDedupe(int trigger_date, int trigger_time, char const *body);
@@ -268,3 +269,18 @@ void InitVars(void);
void InitUserFunctions(void);
void InitTranslationTable(void);
char const *GetTranslatedString(char const *orig);
int GetTranslatedStringTryingVariants(char const *orig, DynamicBuffer *out);
char const *GetErr(int r);
char const *tr(char const *s);
void print_escaped_string(FILE *fp, char const *s);
void print_escaped_string_helper(FILE *fp, char const *s, int esc_for_remind, int json);
void GenerateSysvarTranslationTemplates(void);
void TranslationTemplate(char const *msg);
TrigInfo *NewTrigInfo(char const *i);
void FreeTrigInfo(TrigInfo *ti);
void FreeTrigInfoChain(TrigInfo *ti);
int AppendTrigInfo(Trigger *t, char const *info);
int TrigInfoHeadersAreTheSame(char const *i1, char const *i2);
int TrigInfoIsValid(char const *info);
char const *FindTrigInfo(Trigger *t, char const *header);
void WriteJSONInfoChain(TrigInfo *ti);

View File

@@ -5,7 +5,7 @@
/* Queue up reminders for subsequent execution. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -163,6 +163,7 @@ static void del_reminder(QueuedRem *qid)
if (q == qid) {
QueueHead = q->next;
if (q->text) free((void *) q->text);
FreeTrig(&(q->t));
free(q);
return;
}
@@ -171,6 +172,7 @@ static void del_reminder(QueuedRem *qid)
if (q->next == qid) {
q->next = q->next->next;
if (next->text) free((void *) next->text);
FreeTrig(&(next->t));
free(next);
return;
}
@@ -227,6 +229,10 @@ int QueueReminder(ParsePtr p, Trigger *trig,
strcpy(qelem->passthru, trig->passthru);
qelem->tt = *tim;
qelem->t = *trig;
/* Take over infos */
trig->infos = NULL;
DBufInit(&(qelem->t.tags));
DBufPuts(&(qelem->t.tags), DBufValue(&(trig->tags)));
if (SynthesizeTags) {
@@ -346,8 +352,9 @@ void HandleQueuedReminders(void)
/* If we're a daemon, get the mod time of initial file */
if (Daemon > 0) {
if (stat(InitialFile, &StatBuf)) {
fprintf(ErrFp, "Cannot stat %s - not running as daemon!\n",
fprintf(ErrFp, tr("Cannot stat %s - not running as daemon!"),
InitialFile);
fprintf(ErrFp, "\n");
Daemon = 0;
} else FileModTime = StatBuf.st_mtime;
}
@@ -459,10 +466,17 @@ void HandleQueuedReminders(void)
if (IsServerMode() && q->typ != RUN_TYPE) {
if (DaemonJSON) {
printf("{\"response\":\"reminder\",");
snprintf(qid, sizeof(qid), "%lx", (unsigned long) q);
if (TestMode) {
snprintf(qid, sizeof(qid), "42424242");
} else {
snprintf(qid, sizeof(qid), "%lx", (unsigned long) q);
}
PrintJSONKeyPairString("qid", qid);
PrintJSONKeyPairString("ttime", SimpleTimeNoSpace(q->tt.ttime));
PrintJSONKeyPairString("now", SimpleTimeNoSpace(MinutesPastMidnight(1)));
if (q->t.infos) {
WriteJSONInfoChain(q->t.infos);
}
PrintJSONKeyPairString("tags", DBufValue(&q->t.tags));
} else {
printf("NOTE reminder %s",
@@ -485,6 +499,7 @@ void HandleQueuedReminders(void)
DefaultColorB = q->blue;
/* Make a COPY of q->t because TriggerReminder can change q->t.typ */
Trigger tcopy = q->t;
if (DaemonJSON) {
DynamicBuffer out;
DBufInit(&out);
@@ -697,7 +712,7 @@ static int CalculateNextTimeUsingSched(QueuedRem *q)
to be a security hole! */
while(1) {
char exprBuf[VAR_NAME_LEN+32];
sprintf(exprBuf, "%s(%d)", q->sched, q->ntrig);
snprintf(exprBuf, sizeof(exprBuf), "%s(%d)", q->sched, q->ntrig);
s = exprBuf;
r = EvalExpr(&s, &v, NULL);
if (r) {
@@ -759,7 +774,11 @@ json_queue(QueuedRem const *q)
printf("{");
WriteJSONTrigger(&(q->t), 1, DSEToday);
WriteJSONTimeTrigger(&(q->tt));
snprintf(idbuf, sizeof(idbuf), "%lx", (unsigned long) q);
if (TestMode) {
snprintf(idbuf, sizeof(idbuf), "42424242");
} else {
snprintf(idbuf, sizeof(idbuf), "%lx", (unsigned long) q);
}
PrintJSONKeyPairString("qid", idbuf);
PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
PrintJSONKeyPairInt("ntrig", q->ntrig);
@@ -815,6 +834,11 @@ static void ServerWait(struct timeval *sleep_tv)
int y, m, d;
int max = 1;
char cmdLine[256];
char *s;
int r;
DynamicBuffer tx;
DBufInit(&tx);
FD_ZERO(&readSet);
FD_SET(0, &readSet);
@@ -868,9 +892,32 @@ static void ServerWait(struct timeval *sleep_tv)
exit(EXIT_SUCCESS);
}
/* Read a line from stdin and interpret it */
if (!fgets(cmdLine, sizeof(cmdLine), stdin)) {
exit(EXIT_SUCCESS);
/* Read a line using read() one char at a time to avoid resetting
* readability if we get two commands quickly */
s = cmdLine;
*s = 0;
while (1) {
r = read(fileno(stdin), s, 1);
if (r == 0) {
/* EOF */
exit(EXIT_SUCCESS);
}
if (r != 1) {
/* Error? */
if (errno == EINTR) {
continue;
}
exit(EXIT_FAILURE);
}
*(s+1) = 0;
if (*s == '\n') {
break;
}
if ((size_t) (s - cmdLine) >= sizeof(cmdLine)-1) {
break;
}
s++;
}
if (!strcmp(cmdLine, "EXIT\n")) {
@@ -917,6 +964,42 @@ static void ServerWait(struct timeval *sleep_tv)
printf("NOTE ENDJSONQUEUE\n");
}
fflush(stdout);
} else if (DaemonJSON && !strncmp(cmdLine, "TRANSLATE ", 10)) {
/* Cut off the trailing "\n" */
if (*(cmdLine + strlen(cmdLine)-1) == '\n') {
*(cmdLine + strlen(cmdLine)-1) = 0;
}
r = GetTranslatedStringTryingVariants(cmdLine+10, &tx);
/* Output NOTHING if there's no translation */
if (r) {
printf("{");
PrintJSONKeyPairString("response", "translate");
printf("\"translation\":{\"");
PrintJSONString(cmdLine+10);
printf("\":\"");
PrintJSONString(DBufValue(&tx));
DBufFree(&tx);
printf("\"},");
printf("\"command\":\"TRANSLATE\"}\n");
fflush(stdout);
}
} else if (!strcmp(cmdLine, "TRANSLATE_DUMP\n")) {
if (!DaemonJSON) {
printf("NOTE TRANSLATE_DUMP\n");
} else {
printf("{");
PrintJSONKeyPairString("response", "translate_dump");
printf("\"table\":");
}
DumpTranslationTable(stdout, 1);
if (!DaemonJSON) {
printf("\nNOTE ENDTRANSLATE_DUMP\n");
} else {
printf(",\"command\":\"TRANSLATE_DUMP\"}\n");
}
fflush(stdout);
} else if (!strcmp(cmdLine, "REREAD\n")) {
if (DaemonJSON) {
printf("{\"response\":\"reread\",\"command\":\"REREAD\"}\n");

View File

@@ -5,7 +5,7 @@
/* Print a PostScript calendar. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -350,13 +350,14 @@ int main(int argc, char *argv[])
!strcmp(DBufValue(&buf), PSBEGIN2)) {
if (!validfile) {
if (Verbose) {
fprintf(stderr, "Rem2PS: Version %s Copyright 1992-2024 by Dianne Skoll\n\n", VERSION);
fprintf(stderr, "Rem2PS: Version %s Copyright (C) 1992-2025 by Dianne Skoll\n\n", VERSION);
fprintf(stderr, "Generating PostScript calendar\n");
}
}
validfile++;
DoPsCal();
}
DBufFree(&buf);
}
if (!validfile) {
fprintf(stderr, "Rem2PS: Couldn't find any calendar data - are you\n");
@@ -1221,7 +1222,7 @@ int DoQueuedPs(void)
if (moonsize < 0) {
size = "DaySize 2 div";
} else {
sprintf(buffer, "%d", moonsize);
snprintf(buffer, sizeof(buffer), "%d", moonsize);
size = buffer;
}
@@ -1234,7 +1235,7 @@ int DoQueuedPs(void)
if (fontsize < 0) {
fsize = "EntrySize";
} else {
sprintf(fbuffer, "%d", fontsize);
snprintf(fbuffer, sizeof(fbuffer), "%d", fontsize);
fsize = fbuffer;
}
printf("/EntryFont findfont %s scalefont setfont (",
@@ -1272,7 +1273,7 @@ int DoQueuedPs(void)
if (fontsize < 0) {
fsize = "EntrySize";
} else {
sprintf(fbuffer, "%d", fontsize);
snprintf(fbuffer, sizeof(fbuffer), "%d", fontsize);
fsize = fbuffer;
}
printf("/EntryFont findfont %s scalefont setfont (",

View File

@@ -5,7 +5,7 @@
/* Define the PostScript prologue */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -14,7 +14,7 @@ char *PSProlog1[] =
{
"% This file was produced by Remind and Rem2PS, written by",
"% Dianne Skoll.",
"% Remind and Rem2PS are Copyright 1992-2024 Dianne Skoll.",
"% Remind and Rem2PS are Copyright (C) 1992-2025 Dianne Skoll.",
"/ISOLatin1Encoding where { pop save true }{ false } ifelse",
" /ISOLatin1Encoding [ StandardEncoding 0 45 getinterval aload pop /minus",
" StandardEncoding 46 98 getinterval aload pop /dotlessi /grave /acute",

View File

@@ -5,7 +5,7 @@
/* Routines for sorting reminders by trigger date */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -77,7 +77,7 @@ int InsertIntoSortBuffer(int dse, int tim, char const *body, int typ, int prio)
int ShouldGoAfter;
if (!new) {
Eprint("%s", ErrMsg[E_NO_MEM]);
Eprint("%s", GetErr(E_NO_MEM));
IssueSortedReminders();
SortByDate = 0;
SortByTime = 0;
@@ -183,7 +183,7 @@ static void IssueSortBanner(int dse)
if (UserFuncExists("sortbanner") != 1) return;
FromDSE(dse, &y, &m, &d);
sprintf(BanExpr, "sortbanner('%04d/%02d/%02d')", y, m+1, d);
snprintf(BanExpr, sizeof(BanExpr), "sortbanner('%04d/%02d/%02d')", y, m+1, d);
y = EvalExpr(&s, &v, NULL);
if (y) return;
if (DoCoerce(STR_TYPE, &v)) return;

View File

@@ -1,26 +0,0 @@
#!/bin/sh
# Make sure Remind compiles with all supported languages; show
# tstlang.rem output for each language.
ALL=`grep ^#define lang.h | grep -v '#define LANG' | awk '{print $2}'`
OUTPUT_COMPILED=lang-compiled.out
OUTPUT_RUNTIME=lang-runtime.out
cat /dev/null > $OUTPUT_COMPILED
cat /dev/null > $OUTPUT_RUNTIME
for i in $ALL ; do
make clean
make -j`nproc` all LANGDEF=-DLANG=$i || exit 1
./remind -q -r ../tests/tstlang.rem >> $OUTPUT_COMPILED 2>&1
done
# Rebuild English version
make clean
make -j`nproc` all || exit 1
ALL=`ls ../include/lang/*.rem`
for i in $ALL; do
./remind -q -r "-ii=\"$i\"" ../tests/tstlang.rem >> $OUTPUT_RUNTIME 2>&1
done
exit 0

View File

@@ -6,7 +6,7 @@
/* classifying the tokens parsed. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -71,6 +71,7 @@ Token TokArray[] = {
{ "in", 2, T_In, 0 },
{ "include", 3, T_Include, 0 },
{ "includecmd", 10, T_IncludeCmd, 0 },
{ "info", 4, T_Info, 0 },
{ "january", 3, T_Month, 0 },
{ "july", 3, T_Month, 6 },
{ "june", 3, T_Month, 5 },
@@ -107,6 +108,7 @@ Token TokArray[] = {
{ "skip", 4, T_Skip, SKIP_SKIP },
{ "special", 7, T_RemType, PASSTHRU_TYPE },
{ "sunday", 3, T_WkDay, 6 },
{ "sysinclude", 10, T_IncludeSys, 0 },
{ "tag", 3, T_Tag, 0 },
{ "third", 5, T_Ordinal, 2 },
{ "through", 7, T_Through, 0 },

View File

@@ -6,7 +6,7 @@
/* the TRANSLATE keyword. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */
/* Copyright (C) 1992-2025 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */
/***************************************************************/
@@ -34,6 +34,71 @@ typedef struct xlat {
hash_table TranslationTable;
static XlateItem *FindTranslation(char const *orig);
static int printf_formatters_are_safe(char const *orig, char const *translated);
void
TranslationTemplate(char const *in)
{
if (!*in) {
return;
}
if (!strcmp(in, "LANGID")) {
return;
}
printf("TRANSLATE ");
print_escaped_string_helper(stdout, in, 1, 0);
if (FindTranslation(in)) {
printf(" ");
print_escaped_string_helper(stdout, tr(in), 1, 0);
printf("\n");
} else {
printf(" \"\"\n");
}
}
static void
GenerateTranslationTemplate(void)
{
int i;
printf("# Translation table template\n\n");
printf("TRANSLATE \"LANGID\" ");
print_escaped_string_helper(stdout, tr("LANGID"), 1, 0);
printf("\n\n");
printf("BANNER %s\n", DBufValue(&Banner));
printf("\n# Weekday Names\n");
for (i=0; i<7; i++) {
printf("SET $%s ", DayName[i]);
print_escaped_string_helper(stdout, tr(DayName[i]), 1, 0);
printf("\n");
}
printf("\n# Month Names\n");
for (i=0; i<12; i++) {
printf("SET $%s ", MonthName[i]);
print_escaped_string_helper(stdout, tr(MonthName[i]), 1, 0);
printf("\n");
}
printf("\n# Other Translation-related System Variables\n");
GenerateSysvarTranslationTemplates();
printf("\n# Error Messages\n");
for (i=0; i<NumErrs; i++) {
TranslationTemplate(ErrMsg[i]);
}
printf("\n# Other Messages\n");
for (i=0; translatables[i] != NULL; i++) {
TranslationTemplate(translatables[i]);
}
}
/***************************************************************/
/* */
/* AllocateXlateItem - Allocate a new translation item */
@@ -47,6 +112,7 @@ AllocateXlateItem(char const *orig, char const *translated)
size_t s3 = strlen(translated)+1;
XlateItem *item;
/* Allocate the string space in ONE go! */
char *blob = malloc(s1+s2+s3);
if (!blob) {
return NULL;
@@ -54,7 +120,6 @@ AllocateXlateItem(char const *orig, char const *translated)
item = (XlateItem *) blob;
/* Allocate the string space in ONE go! */
item->orig = blob + s1;
item->translated = item->orig + s2;
strcpy(item->orig, orig);
@@ -77,6 +142,13 @@ FreeXlateItem(XlateItem *item)
static void
RemoveTranslation(XlateItem *item)
{
hash_table_delete(&TranslationTable, item);
FreeXlateItem(item);
}
static void
RemoveTranslationNoResize(XlateItem *item)
{
hash_table_delete_no_resize(&TranslationTable, item);
FreeXlateItem(item);
@@ -96,16 +168,27 @@ ClearTranslationTable(void)
item = hash_table_next(&TranslationTable, NULL);
while(item) {
next = hash_table_next(&TranslationTable, item);
RemoveTranslation(item);
RemoveTranslationNoResize(item);
item = next;
}
hash_table_free(&TranslationTable);
InitTranslationTable();
}
static void
void
print_escaped_string(FILE *fp, char const *s)
{
print_escaped_string_helper(fp, s, 0, 0);
}
static void
print_escaped_string_json(FILE *fp, char const *s)
{
print_escaped_string_helper(fp, s, 0, 1);
}
void
print_escaped_string_helper(FILE *fp, char const *s, int esc_for_remind, int json) {
putc('"', fp);
while(*s) {
switch(*s) {
@@ -119,11 +202,20 @@ print_escaped_string(FILE *fp, char const *s)
case '"': putc('\\', fp); putc('"', fp); break;
case '\\': putc('\\', fp); putc('\\', fp); break;
default:
if (*s < 32) {
fprintf(fp, "\\x%02x", (unsigned int) *s);
if ((*s > 0 && *s < 32) || *s == 0x7f) {
if (json) {
fprintf(fp, "\\u%04x", (unsigned int) *s);
} else {
fprintf(fp, "\\x%02x", (unsigned int) *s);
}
} else {
putc(*s, fp); break;
if (esc_for_remind && *s == '[') {
fprintf(fp, "[\"[\"]");
} else {
putc(*s, fp);
}
}
break;
}
s++;
}
@@ -135,19 +227,48 @@ print_escaped_string(FILE *fp, char const *s)
/* DumpTranslationTable - Dump the table to a file descriptor */
/* */
/***************************************************************/
static void
DumpTranslationTable(FILE *fp)
void
DumpTranslationTable(FILE *fp, int json)
{
XlateItem *item;
int done = 0;
char const *t;
if (!json) {
fprintf(fp, "# Translation table\n");
/* Always to LANGID first */
t = GetTranslatedString("LANGID");
if (t) {
fprintf(fp, "TRANSLATE \"LANGID\" ");
print_escaped_string(fp, t);
fprintf(fp, "\n");
}
} else {
fprintf(fp, "{");
}
item = hash_table_next(&TranslationTable, NULL);
while(item) {
print_escaped_string(fp, item->orig);
fprintf(fp, " ");
print_escaped_string(fp, item->translated);
fprintf(fp, "\n");
if (!json) {
if (strcmp(item->orig, "LANGID")) {
fprintf(fp, "TRANSLATE ");
print_escaped_string(fp, item->orig);
fprintf(fp, " ");
print_escaped_string(fp, item->translated);
fprintf(fp, "\n");
}
} else {
if (done) {
fprintf(fp, ",");
}
done=1;
print_escaped_string_json(fp, item->orig);
fprintf(fp, ":");
print_escaped_string_json(fp, item->translated);
}
item = hash_table_next(&TranslationTable, item);
}
if (json) {
fprintf(fp, "}");
}
}
static unsigned int
@@ -170,9 +291,10 @@ InitTranslationTable(void)
{
if (hash_table_init(&TranslationTable, offsetof(XlateItem, link),
HashXlateItem, CompareXlateItems) < 0) {
fprintf(stderr, "Unable to initialize translation hash table: Out of memory. Exiting.\n");
fprintf(ErrFp, "Unable to initialize translation hash table: Out of memory. Exiting.\n");
exit(1);
}
InsertTranslation("LANGID", "en");
}
static XlateItem *
@@ -188,7 +310,13 @@ FindTranslation(char const *orig)
int
InsertTranslation(char const *orig, char const *translated)
{
XlateItem *item = FindTranslation(orig);
XlateItem *item;
if (!printf_formatters_are_safe(orig, translated)) {
Eprint(tr("Invalid translation: Both original and translated must have the same printf-style formatting sequences in the same order."));
return E_PARSE_ERR;
}
item = FindTranslation(orig);
if (item) {
if (!strcmp(item->translated, translated)) {
/* Translation is the same; do nothing */
@@ -196,6 +324,10 @@ InsertTranslation(char const *orig, char const *translated)
}
RemoveTranslation(item);
}
if (strcmp(orig, "LANGID") && (!strcmp(orig, translated))) {
return OK;
}
item = AllocateXlateItem(orig, translated);
if (!item) {
return E_NO_MEM;
@@ -212,6 +344,78 @@ GetTranslatedString(char const *orig)
return item->translated;
}
int
GetTranslatedStringTryingVariants(char const *orig, DynamicBuffer *out)
{
DynamicBuffer in;
char const *s;
int first_lower = 0;
int has_upper = 0;
DBufInit(&in);
/* Try exact match first */
s = GetTranslatedString(orig);
if (s) {
DBufPuts(out, s);
return 1;
}
/* Classify orig */
s = orig;
while (*s) {
if (isupper(*s)) {
has_upper = 1;
break;
}
s++;
}
if (islower(*orig)) {
first_lower = 1;
}
if (has_upper) {
/* Try all lower-case version */
DBufPuts(&in, orig);
strtolower(DBufValue(&in));
s = GetTranslatedString(DBufValue(&in));
if (s) {
DBufPuts(out, s);
strtolower(DBufValue(out));
*(DBufValue(out)) = toupper(*DBufValue(out));
DBufFree(&in);
return 1;
}
}
if (first_lower) {
/* Try ucfirst version */
DBufFree(&in);
DBufPuts(&in, orig);
strtolower(DBufValue(&in));
*(DBufValue(&in)) = toupper(*(DBufValue(&in)));
s = GetTranslatedString(DBufValue(&in));
if (s) {
DBufPuts(out, s);
strtolower(DBufValue(out));
DBufFree(&in);
return 1;
}
}
DBufFree(&in);
return 0;
}
char const *tr(char const *orig)
{
char const *n = GetTranslatedString(orig);
if (n) {
return n;
}
return orig;
}
int
DoTranslate(ParsePtr p)
{
@@ -223,17 +427,32 @@ DoTranslate(ParsePtr p)
c = ParseNonSpaceChar(p, &r, 1);
if (r) return r;
if (c == 0) {
return E_EOLN;
}
if (c != '"') {
r = ParseToken(p, &orig);
if (r) return r;
r = VerifyEoln(p);
if (!StrCmpi(DBufValue(&orig), "dump")) {
DumpTranslationTable(stdout);
DBufFree(&orig);
if (r) return r;
DumpTranslationTable(stdout, 0);
return OK;
}
if (!StrCmpi(DBufValue(&orig), "clear")) {
DBufFree(&orig);
if (r) return r;
ClearTranslationTable();
return OK;
}
if (!StrCmpi(DBufValue(&orig), "generate")) {
DBufFree(&orig);
if (r) return r;
GenerateTranslationTemplate();
return OK;
}
return E_PARSE_ERR;
}
@@ -246,6 +465,9 @@ DoTranslate(ParsePtr p)
if (item) {
RemoveTranslation(item);
}
if (!strcmp(DBufValue(&orig), "LANGID")) {
InsertTranslation("LANGID", "en");
}
r = OK;
}
DBufFree(&orig);
@@ -264,11 +486,51 @@ DoTranslate(ParsePtr p)
}
void
get_translation_hash_stats(int *total, int *maxlen, double *avglen)
dump_translation_hash_stats(void)
{
struct hash_table_stats s;
hash_table_get_stats(&TranslationTable, &s);
*total = s.num_entries;
*maxlen = s.max_len;
*avglen = s.avg_len;
hash_table_dump_stats(&TranslationTable, ErrFp);
}
static void
get_printf_escapes(char const *str, DynamicBuffer *out)
{
char const *s = str;
while(*s) {
if (*s == '%' && *(s+1) != 0) {
/* %% is safe and does not need to be replicated in translation */
if (*(s+1) == '%') {
s += 2;
continue;
}
s++;
DBufPutc(out, *s);
while (*s && *(s+1) && strchr("#0- +'I%123456789.hlqLjzZt", *s)) {
s++;
DBufPutc(out, *s);
}
}
s++;
}
}
static int
printf_formatters_are_safe(char const *orig, char const *translated)
{
DynamicBuffer origEscapes;
DynamicBuffer translatedEscapes;
int dangerous;
DBufInit(&origEscapes);
DBufInit(&translatedEscapes);
get_printf_escapes(orig, &origEscapes);
get_printf_escapes(translated, &translatedEscapes);
dangerous = strcmp(DBufValue(&origEscapes), DBufValue(&translatedEscapes));
if (dangerous) {
return 0;
}
return 1;
}

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