Compare commits

...

107 Commits

Author SHA1 Message Date
Dianne Skoll
4d45925758 Fix typo 2024-04-29 16:18:49 -04:00
Dianne Skoll
8cadb23f48 Update release notes. 2024-04-29 16:16:42 -04:00
Dianne Skoll
63211b65c2 Bump version to 04.03.07 2024-04-22 14:55:47 -04:00
Dianne Skoll
1be84525b1 Don't rely on behavior of "%" with negative args. 2024-04-22 09:57:32 -04:00
Dianne Skoll
67ae95a464 Make sure shellescape() does not mangle UTF-8 characters. 2024-04-22 09:50:17 -04:00
Dianne Skoll
c03a95ad94 Use built-in versions of strdup, strcasecmp and strncasecmp instead of writing our own. 2024-04-21 14:44:24 -04:00
Dianne Skoll
51aa7aecb9 Make $Tt a synonym for trigtime() 2024-04-20 11:50:39 -04:00
Dianne Skoll
592cfe5a20 Use "uint32_t" if we have <stdint.h> for MD5 code. 2024-04-20 10:50:44 -04:00
Dianne Skoll
b4cf15e73e Remove some unused autoconf cruft. 2024-04-20 10:45:22 -04:00
Dianne Skoll
862e143372 Ugh, forgot to regen ./configure. 2024-04-20 10:40:06 -04:00
Dianne Skoll
1f10ca49ad Pass proper args to AC_INIT; include Remind home page in usage output. 2024-04-20 10:39:12 -04:00
Dianne Skoll
4a0c4ffdca Add a test to ensure we don't save trigger time while parsing. 2024-04-18 23:48:30 -04:00
Dianne Skoll
27c8737f3a Only save trigger date when computing it, not while parsing. 2024-04-18 23:41:47 -04:00
Dianne Skoll
ecf45fc453 Add tests for commit 0a1178cfd7: Don't clear out last trigger time unnecessarily. 2024-04-18 18:32:38 -04:00
Dianne Skoll
0a1178cfd7 Don't clear out last trigger time unnecessarily. 2024-04-18 17:56:49 -04:00
Dianne Skoll
20a35dc627 Put the tabbed notebook blurb after the blurb about obtaining default settings. 2024-04-10 09:44:40 -04:00
Dianne Skoll
79887c06f0 Tweak wording. 2024-04-10 09:43:13 -04:00
Dianne Skoll
f7ff424904 Remove debugging line. 2024-04-04 13:43:44 -04:00
Dianne Skoll
6678721fe3 Make build.tk add a little note if it obtained default settings from an existing Remind installation. 2024-04-04 13:42:31 -04:00
Dianne Skoll
496302097b Add a missing release note... sigh. 2024-04-02 09:13:59 -04:00
Dianne Skoll
fe3e2b9a20 Install include files with proper permissions. 2024-04-02 09:05:25 -04:00
Dianne Skoll
400a6b066f Add Portuguese holidays, courtesy of Joop Kiefte. 2024-04-02 09:01:45 -04:00
Dianne Skoll
76d181e7fc Update docs 2024-04-02 08:56:27 -04:00
Dianne Skoll
77373eed2d Fix tests on FreeBSD. We need to copy the results of getenv or when we change it, it will be overwritten. 2024-04-02 08:54:40 -04:00
Dianne Skoll
6b52be388f Update docs. 2024-04-02 08:23:21 -04:00
Dianne Skoll
0518a12a91 Don't fail make install if we can't jigger desktop icons. 2024-04-01 14:42:17 -04:00
Dianne Skoll
362a02c4b8 Don't include inotify-related code if we don't have inotify.
Fixes bug that broke compilation on FreeBSD.
2024-04-01 14:24:00 -04:00
Dianne Skoll
3e3a0cde47 Add "all" option to compare-language-mods.pl 2024-04-01 12:03:34 -04:00
Dianne Skoll
c16f93effd Update WHATSNEW. 2024-04-01 09:14:25 -04:00
Dianne Skoll
61b27c02b5 Be a little more aggressive. 2024-04-01 09:07:13 -04:00
Dianne Skoll
ba28eaad53 Fix typo. 2024-04-01 08:42:48 -04:00
Dianne Skoll
92c2d0cc9f Remove obsolete #ifdef tests 2024-04-01 08:41:29 -04:00
Dianne Skoll
21d5e8a095 Tweak daemon mode documentation. 2024-04-01 08:39:24 -04:00
Dianne Skoll
60417d68a7 Bump version to 04.03.05 2024-04-01 08:31:59 -04:00
Dianne Skoll
7d25387403 Remove the MICROSOFT-AND-APPLE file. I think I've made my point. 2024-03-31 12:07:11 -04:00
Dianne Skoll
b454cf5b20 Refactor set_cloexec to make it more convenient to call. 2024-03-31 09:49:32 -04:00
Dianne Skoll
9ea6385b72 Tweak whitespace. 2024-03-31 09:42:13 -04:00
Dianne Skoll
55b7908444 Add International Transgender Day of Visibility to man page
Done to annoy the anti-LGBT crowd.
2024-03-31 09:40:58 -04:00
Dianne Skoll
e9ff66478b Document that we use inotify, where possible, to detect changes to reminder scripts / directories. 2024-03-30 13:25:57 -04:00
Dianne Skoll
d3240d711d Rename DaemonWait to ServerWait. 2024-03-29 19:57:47 -04:00
Dianne Skoll
a8d63a4199 Use inotfy even in normal daemon mode (-zn where n>0) to detect file changes. 2024-03-29 08:28:41 -04:00
Dianne Skoll
a4807a21c3 Save the value of $DefaultColor that was in effect at the time a reminder was queued. Restore this value when triggering the reminder. 2024-03-26 11:44:42 -04:00
Dianne Skoll
a394ef53a0 Print the "passthru" field for PASSTHRU_TYPE reminders when listing the queue. 2024-03-26 11:29:37 -04:00
Dianne Skoll
eb8243743a Prevent mishandling of SPECIAL COLOR reminders when pulling them from the queue.
Bug reported by Damien Tardy-Panis.
2024-03-26 11:21:17 -04:00
Dianne Skoll
8444bb15c5 Fix typo. 2024-03-26 09:54:31 -04:00
Dianne Skoll
b86245c4c6 Fix wording. 2024-03-25 10:24:39 -04:00
Dianne Skoll
499fcfad41 Fix typo 2024-03-25 10:24:20 -04:00
Dianne Skoll
bddbbf061b Update changelog. 2024-03-25 10:21:05 -04:00
Dianne Skoll
05136f4cf0 Add a basic CSS file for the demo WWW stuff. 2024-03-25 10:12:46 -04:00
Dianne Skoll
e62e3d5d03 More multitrig examples. 2024-03-24 11:05:15 -04:00
Dianne Skoll
595fdaa4a4 Increment version to 04.03.04. 2024-03-24 10:54:44 -04:00
Dianne Skoll
133febc2c1 Document that you can't have an AT clause in a multitrig trigger. 2024-03-24 10:50:21 -04:00
Dianne Skoll
f8c6d7ff6c Document multitrig. 2024-03-24 10:46:53 -04:00
Dianne Skoll
db3341db91 Fix bug in code that stripes the Queue... output grey and white. 2024-03-23 10:57:56 -04:00
Dianne Skoll
8cbcd3ec01 Show Hebrew dates on PDF version of Jewish holiday calendar. 2024-03-22 17:38:30 -04:00
Dianne Skoll
4c6512e9b6 Update the HTML remind demo. 2024-03-22 17:26:23 -04:00
Dianne Skoll
4769789a8f More common HTML path. 2024-03-22 17:14:13 -04:00
Dianne Skoll
b4a8cb085c Add "blank PDF calendar" to www choices. 2024-03-22 17:13:21 -04:00
Dianne Skoll
4f816d52fd Another test for multitrig / scanfrom interaction. 2024-03-22 12:40:50 -04:00
Dianne Skoll
94b3a0248d Add tests for multitrig 2024-03-22 12:39:58 -04:00
Dianne Skoll
5fbf1d82e4 Remove duplicated line. 2024-03-22 11:23:04 -04:00
Dianne Skoll
55eb3ebe95 Add multitrig built-in function which is how trig() should originally have been done. 2024-03-22 11:21:26 -04:00
Dianne Skoll
2afa3c5558 Raise windows after errors so they remain visible. 2024-03-21 16:08:18 -04:00
Dianne Skoll
30d9a42db2 Remove debugging statement. 2024-03-21 12:39:48 -04:00
Dianne Skoll
74d357b84d Use placeholders that are less likely to be used as filenames. :) 2024-03-21 12:22:43 -04:00
Dianne Skoll
09c98a93ec Fix month navigation. 2024-03-21 12:19:39 -04:00
Dianne Skoll
ed89ab7c04 Remove unnecessary code and variable. 2024-03-21 12:13:32 -04:00
Dianne Skoll
27c74be02b Don't need to monitor reminder file for changes; reap zombies. 2024-03-21 12:11:39 -04:00
Dianne Skoll
8f22ab39dc Apply POSIX-escaping to filenames. 2024-03-21 11:46:29 -04:00
Dianne Skoll
795c53f4ce Format queue items better; make them clickable to open an editor. 2024-03-21 11:02:07 -04:00
Dianne Skoll
3fd18a9cc0 Document clickable errors. 2024-03-21 10:45:32 -04:00
Dianne Skoll
a5afb4a87e In the "show errors" text box, fire up the editor when you click on an error if we can figure out the filename and line number. 2024-03-20 20:53:19 -04:00
Dianne Skoll
379fc4542d Make errors stand out more obviously. 2024-03-20 20:33:46 -04:00
Dianne Skoll
538ef6c8ce Check for both $CalMode and $PsCal 2024-03-20 16:32:02 -04:00
Dianne Skoll
95c7e8856c Add standard "moonphases.rem" file with moon phases. 2024-03-20 16:28:50 -04:00
Dianne Skoll
95523c8f10 Convert cosd() function into a macro. 2024-03-19 16:26:07 -04:00
Dianne Skoll
97b53d5e40 Fix typo 2024-03-18 11:18:46 -04:00
Dianne Skoll
fb688850b1 Update release notes. 2024-03-18 11:11:16 -04:00
Dianne Skoll
5b1bad2650 Document DEL server command and qid value. 2024-03-16 15:50:58 -04:00
Dianne Skoll
e5ff132c5e Remove all traces of tk_dialog 2024-03-16 15:45:29 -04:00
Dianne Skoll
a0830ad23c Bump version to 04.03.03 2024-03-16 15:27:34 -04:00
Dianne Skoll
9290f53466 Fix typo 2024-03-16 15:24:11 -04:00
Dianne Skoll
e5711032bd Keep reading inotify events until 0.2 seconds elapses between successive events. 2024-03-16 15:22:48 -04:00
Dianne Skoll
08e3c1d5a2 Use tk_messageBox instead of tk_dialog. 2024-03-16 15:22:36 -04:00
Dianne Skoll
29c579a301 Refactor some code. 2024-03-16 14:01:21 -04:00
Dianne Skoll
61f55bceee Fix "Delete this reminder completely" functionality. 2024-03-16 13:56:28 -04:00
Dianne Skoll
6586fae3eb Fix logic bug that would sometimes fail to send a queue update message to controlling process. 2024-03-16 13:36:24 -04:00
Dianne Skoll
d5a86f3e4f Actually de-queue and free reminders that expire out of the queue. 2024-03-16 13:29:59 -04:00
Dianne Skoll
96551ccaa4 Make TkRemind use the "DEL qid" facility to ignore reminders. Fix potential use of freed memory in queue.c 2024-03-16 13:25:47 -04:00
Dianne Skoll
c83ee86d10 Implement DEL command to removed a queued reminder from the queue in -zj mode. 2024-03-16 12:54:30 -04:00
Dianne Skoll
c913306cbd Add "qid" member to JSONQUEUE. 2024-03-16 11:17:28 -04:00
Dianne Skoll
03d385df97 Add a test for the "-ds" debugging flag. 2024-03-13 12:17:49 -04:00
Dianne Skoll
61fcc1b275 Add "s" debugging flag to see expression-parsing stack high-water marks.
Reduce default value stack size from 1000 to 100.
2024-03-13 12:06:55 -04:00
Dianne Skoll
26977a4ac0 Fix a bunch of cppcheck complaints and also update the cppcheck Makefile target. 2024-03-11 12:10:03 -04:00
Dianne Skoll
28acd05215 Better icon. 2024-03-08 14:28:19 -05:00
Dianne Skoll
be4eed8b20 Update TkRemind logo to include a white outline. 2024-03-07 15:36:31 -05:00
Dianne Skoll
cdb0850373 Add a comment to the troff source so it doesn't confuse Emacs syntax highlighting. 2024-03-03 14:55:40 -05:00
Dianne Skoll
0d55e04284 Make a local OMIT that doesn't specify a weekday name into a syntax error. 2024-03-03 14:51:53 -05:00
Dianne Skoll
f4cce54b70 Warn if a local OMIT doesn't actually omit any weekdays. 2024-03-03 11:00:35 -05:00
Dianne Skoll
2dc6ca44f1 Fix typo 2024-03-01 09:10:26 -05:00
Dianne Skoll
d1d833f0f3 Document fix in commit 1d44577ce9 2024-03-01 09:04:09 -05:00
Dianne Skoll
1d44577ce9 Exit rather than return if we forked in System(). 2024-03-01 09:00:36 -05:00
Dianne Skoll
1be7c2d6d7 Bump version to 04.03.02 and document fix to install: target. 2024-03-01 08:50:00 -05:00
Dianne Skoll
b1f418ee42 Install desktop and icon file in correct paths: $prefix/share/applications and $prefix/share/pixmaps 2024-03-01 08:45:43 -05:00
Dianne Skoll
72b0bf96fe Update release notes. 2024-02-29 20:28:09 -05:00
Dianne Skoll
3388849fa5 Fix test bug. 2024-02-29 20:27:19 -05:00
Dianne Skoll
dc9650d5fa Fix test bug. SIGH. 2024-02-29 20:25:13 -05:00
57 changed files with 1890 additions and 1105 deletions

View File

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

View File

@@ -15,6 +15,8 @@
# the next line restarts using wish \ # the next line restarts using wish \
exec wish "$0" "$@" exec wish "$0" "$@"
global RemindExecutable
#*********************************************************************** #***********************************************************************
# %PROCEDURE: SetConfigDefaults # %PROCEDURE: SetConfigDefaults
# %ARGUMENTS: # %ARGUMENTS:
@@ -40,7 +42,7 @@ proc SetConfigDefaults {} {
set Config(WESTERN_HEMISPHERE) 1 set Config(WESTERN_HEMISPHERE) 1
set Config(LANGUAGE) "English" set Config(LANGUAGE) "English"
set Config(INST_DIR) "/usr/local/bin" set Config(INST_DIR) "/usr/local/bin"
set Config(MAN_DIR) "/usr/local/man" set Config(MAN_DIR) "/usr/local/share/man"
} }
#*********************************************************************** #***********************************************************************
@@ -53,7 +55,7 @@ proc SetConfigDefaults {} {
# Pops up an error dialog; then calls exit. # Pops up an error dialog; then calls exit.
#*********************************************************************** #***********************************************************************
proc Bail { msg } { proc Bail { msg } {
tk_dialog .err "Remind Configuration Error" $msg error 0 "Bummer" tk_messageBox -message "Remind Build Error" -detail $msg -icon error -type ok
exit 1 exit 1
} }
@@ -124,7 +126,7 @@ proc CreateMainDialog {} {
# Creates the "installation directories" dialog. # Creates the "installation directories" dialog.
#*********************************************************************** #***********************************************************************
proc CreateInstallDirDialog { w } { proc CreateInstallDirDialog { w } {
global Config global Config RemindExecutable
label $w.binlabel -text "Location for programs: " label $w.binlabel -text "Location for programs: "
entry $w.bin -width 30 entry $w.bin -width 30
$w.bin insert end $Config(INST_DIR) $w.bin insert end $Config(INST_DIR)
@@ -133,16 +135,19 @@ proc CreateInstallDirDialog { w } {
entry $w.man -width 30 entry $w.man -width 30
$w.man insert end $Config(MAN_DIR) $w.man insert end $Config(MAN_DIR)
text $w.blurb -width 1 -height 5 -wrap word -relief flat -takefocus 0 text $w.blurb -width 1 -height 20 -wrap word -relief flat -takefocus 0
$w.blurb insert end "\n(Tabbed-notebook Tcl code taken from \"Effective Tcl/Tk Programming\" by Mark Harrison and Michael McLennan, Addison-Wesley Professional Computing Series.)" if { "$RemindExecutable" != "" } {
$w.blurb configure -state disabled $w.blurb insert end "Note: Default settings were obtained by querying the existing installed version of Remind found at: $RemindExecutable\n"
# Disable all text-window behaviour }
bindtags $w.blurb {NoSuchTag} $w.blurb insert end "\n(Tabbed-notebook Tcl code taken from \"Effective Tcl/Tk Programming\" by Mark Harrison and Michael McLennan, Addison-Wesley Professional Computing Series.)\n"
grid $w.binlabel -row 0 -column 0 -sticky e grid $w.binlabel -row 0 -column 0 -sticky e
grid $w.bin -row 0 -column 1 -sticky nsew grid $w.bin -row 0 -column 1 -sticky nsew
grid $w.manlabel -row 1 -column 0 -sticky e grid $w.manlabel -row 1 -column 0 -sticky e
grid $w.man -row 1 -column 1 -sticky nsew grid $w.man -row 1 -column 1 -sticky nsew
grid $w.blurb - -sticky nsew grid $w.blurb - -sticky nsew
# Disable all text-window behaviour
bindtags $w.blurb {NoSuchTag}
$w.blurb configure -state disabled
} }
#*********************************************************************** #***********************************************************************
@@ -727,7 +732,7 @@ proc notebook_fix_size {win} {
#*********************************************************************** #***********************************************************************
proc FindRemind {} { proc FindRemind {} {
global env global env
set path [concat [split $env(PATH) ":"] "/bin" "/usr/bin" "/usr/local/bin"] set path [concat [split $env(PATH) ":"] "/usr/local/bin" "/bin" "/usr/bin" ]
foreach thing $path { foreach thing $path {
if [file executable [file join $thing "remind"]] { if [file executable [file join $thing "remind"]] {
return [file join $thing "remind"] return [file join $thing "remind"]
@@ -745,16 +750,17 @@ proc FindRemind {} {
# sensible defaults. # sensible defaults.
#*********************************************************************** #***********************************************************************
proc SetConfigFromRemind {} { proc SetConfigFromRemind {} {
global Config global Config RemindExecutable
SetConfigDefaults SetConfigDefaults
set rem [FindRemind] set rem [FindRemind]
set RemindExecutable $rem
if {"$rem" == ""} { if {"$rem" == ""} {
return return
} }
set dir [file dirname $rem] set dir [file dirname $rem]
set Config(INST_DIR) $dir set Config(INST_DIR) $dir
if {"$dir" == "/usr/local/bin"} { if {"$dir" == "/usr/local/bin"} {
set Config(MAN_DIR) "/usr/local/man" set Config(MAN_DIR) "/usr/local/share/man"
} elseif {$dir == "/usr/bin"} { } elseif {$dir == "/usr/bin"} {
set Config(MAN_DIR) "/usr/share/man" set Config(MAN_DIR) "/usr/share/man"
} }
@@ -764,6 +770,8 @@ proc SetConfigFromRemind {} {
set Config(MAN_DIR) "/usr/share/man" set Config(MAN_DIR) "/usr/share/man"
} elseif {[file readable "/usr/man/man1/remind.1"]} { } elseif {[file readable "/usr/man/man1/remind.1"]} {
set Config(MAN_DIR) "/usr/man" set Config(MAN_DIR) "/usr/man"
} elseif {[file readable "/usr/local/share/man/man1/remind.1"]} {
set Config(MAN_DIR) "/usr/local/share/man"
} elseif {[file readable "/usr/local/man/man1/remind.1"]} { } elseif {[file readable "/usr/local/man/man1/remind.1"]} {
set Config(MAN_DIR) "/usr/local/man" set Config(MAN_DIR) "/usr/local/man"
} }

115
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71. # Generated by GNU Autoconf 2.71 for remind 04.03.07.
# #
# #
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -606,12 +606,12 @@ MFLAGS=
MAKEFLAGS= MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='' PACKAGE_NAME='remind'
PACKAGE_TARNAME='' PACKAGE_TARNAME='remind'
PACKAGE_VERSION='' PACKAGE_VERSION='04.03.07'
PACKAGE_STRING='' PACKAGE_STRING='remind 04.03.07'
PACKAGE_BUGREPORT='' PACKAGE_BUGREPORT=''
PACKAGE_URL='' PACKAGE_URL='https://dianne.skoll.ca/projects/remind/'
ac_unique_file="src/queue.c" ac_unique_file="src/queue.c"
# Factoring default headers for most tests. # Factoring default headers for most tests.
@@ -757,7 +757,7 @@ localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run' runstatedir='${localstatedir}/run'
includedir='${prefix}/include' includedir='${prefix}/include'
oldincludedir='/usr/include' oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
infodir='${datarootdir}/info' infodir='${datarootdir}/info'
htmldir='${docdir}' htmldir='${docdir}'
dvidir='${docdir}' dvidir='${docdir}'
@@ -1264,7 +1264,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures this package to adapt to many kinds of systems. \`configure' configures remind 04.03.07 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1313,7 +1313,7 @@ Fine tuning of the installation directories:
--infodir=DIR info documentation [DATAROOTDIR/info] --infodir=DIR info documentation [DATAROOTDIR/info]
--localedir=DIR locale-dependent data [DATAROOTDIR/locale] --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
--mandir=DIR man documentation [DATAROOTDIR/man] --mandir=DIR man documentation [DATAROOTDIR/man]
--docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --docdir=DIR documentation root [DATAROOTDIR/doc/remind]
--htmldir=DIR html documentation [DOCDIR] --htmldir=DIR html documentation [DOCDIR]
--dvidir=DIR dvi documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR]
--pdfdir=DIR pdf documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR]
@@ -1325,7 +1325,9 @@ _ACEOF
fi fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of remind 04.03.07:";;
esac
cat <<\_ACEOF cat <<\_ACEOF
Optional Features: Optional Features:
@@ -1348,6 +1350,7 @@ Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations. it to find libraries and programs with nonstandard names/locations.
Report bugs to the package provider. Report bugs to the package provider.
remind home page: <https://dianne.skoll.ca/projects/remind/>.
_ACEOF _ACEOF
ac_status=$? ac_status=$?
fi fi
@@ -1411,7 +1414,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
configure remind configure 04.03.07
generated by GNU Autoconf 2.71 generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc. Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1861,7 +1864,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by $as_me, which was It was created by remind $as_me 04.03.07, which was
generated by GNU Autoconf 2.71. Invocation command line was generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw $ $0$ac_configure_args_raw
@@ -2450,7 +2453,6 @@ as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
as_fn_append ac_header_c_list " sys/time.h sys_time_h HAVE_SYS_TIME_H" as_fn_append ac_header_c_list " sys/time.h sys_time_h HAVE_SYS_TIME_H"
as_fn_append ac_header_c_list " utime.h utime_h HAVE_UTIME_H"
# Auxiliary files required by this configure script. # Auxiliary files required by this configure script.
ac_aux_files="install-sh" ac_aux_files="install-sh"
@@ -4004,6 +4006,12 @@ printf "%s\n" "#define SIZEOF_TIME_T $ac_cv_sizeof_time_t" >>confdefs.h
ac_fn_c_check_header_compile "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default"
if test "x$ac_cv_header_strings_h" = xyes
then :
printf "%s\n" "#define HAVE_STRINGS_H 1" >>confdefs.h
fi
ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_types_h" = xyes if test "x$ac_cv_header_sys_types_h" = xyes
then : then :
@@ -4080,60 +4088,6 @@ printf "%s\n" "#define TM_IN_SYS_TIME 1" >>confdefs.h
fi fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether utime accepts a null argument" >&5
printf %s "checking whether utime accepts a null argument... " >&6; }
if test ${ac_cv_func_utime_null+y}
then :
printf %s "(cached) " >&6
else $as_nop
rm -f conftest.data; >conftest.data
# Sequent interprets utime(file, 0) to mean use start of epoch. Wrong.
if test "$cross_compiling" = yes
then :
ac_cv_func_utime_null='guessing yes'
else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$ac_includes_default
#ifdef HAVE_UTIME_H
# include <utime.h>
#endif
int
main (void)
{
struct stat s, t;
return ! (stat ("conftest.data", &s) == 0
&& utime ("conftest.data", 0) == 0
&& stat ("conftest.data", &t) == 0
&& t.st_mtime >= s.st_mtime
&& t.st_mtime - s.st_mtime < 120);
;
return 0;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"
then :
ac_cv_func_utime_null=yes
else $as_nop
ac_cv_func_utime_null=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_utime_null" >&5
printf "%s\n" "$ac_cv_func_utime_null" >&6; }
if test "x$ac_cv_func_utime_null" != xno; then
ac_cv_func_utime_null=yes
printf "%s\n" "#define HAVE_UTIME_NULL 1" >>confdefs.h
fi
rm -f conftest.data
if test "$GCC" = yes; then if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes" CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
# Check for link-time optimization support # Check for link-time optimization support
@@ -4181,6 +4135,24 @@ if test "$?" != 0 ; then
echo "*** COULD NOT DETERMINE RELEASE DATE: docs/WHATSNEW is incorrect!" echo "*** COULD NOT DETERMINE RELEASE DATE: docs/WHATSNEW is incorrect!"
exit 1 exit 1
fi fi
ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup"
if test "x$ac_cv_func_strdup" = xyes
then :
printf "%s\n" "#define HAVE_STRDUP 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp"
if test "x$ac_cv_func_strcasecmp" = xyes
then :
printf "%s\n" "#define HAVE_STRCASECMP 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "strncasecmp" "ac_cv_func_strncasecmp"
if test "x$ac_cv_func_strncasecmp" = xyes
then :
printf "%s\n" "#define HAVE_STRNCASECMP 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "setenv" "ac_cv_func_setenv" ac_fn_c_check_func "$LINENO" "setenv" "ac_cv_func_setenv"
if test "x$ac_cv_func_setenv" = xyes if test "x$ac_cv_func_setenv" = xyes
then : then :
@@ -4225,7 +4197,7 @@ then :
fi fi
VERSION=04.03.00 VERSION=$PACKAGE_VERSION
@@ -4731,7 +4703,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by $as_me, which was This file was extended by remind $as_me 04.03.07, which was
generated by GNU Autoconf 2.71. Invocation command line was generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -4787,7 +4759,8 @@ $config_files
Configuration headers: Configuration headers:
$config_headers $config_headers
Report bugs to the package provider." Report bugs to the package provider.
remind home page: <https://dianne.skoll.ca/projects/remind/>."
_ACEOF _ACEOF
ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
@@ -4795,7 +4768,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped' ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\ ac_cs_version="\\
config.status remind config.status 04.03.07
configured by $0, generated by GNU Autoconf 2.71, configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
AC_INIT AC_INIT(remind, 04.03.07, , , https://dianne.skoll.ca/projects/remind/)
AC_CONFIG_SRCDIR([src/queue.c]) AC_CONFIG_SRCDIR([src/queue.c])
cat <<'EOF' cat <<'EOF'
@@ -30,7 +30,7 @@ AC_PATH_PROG([PERL], [perl])
dnl Checks for libraries. dnl Checks for libraries.
AC_CHECK_LIB(m, sqrt) AC_CHECK_LIB(m, sqrt)
AC_CHECK_HEADERS_ONCE([sys/time.h]) AC_CHECK_HEADERS_ONCE([sys/time.h stdint.h])
dnl Integer sizes dnl Integer sizes
AC_CHECK_SIZEOF(unsigned int) AC_CHECK_SIZEOF(unsigned int)
@@ -38,13 +38,11 @@ AC_CHECK_SIZEOF(unsigned long)
AC_CHECK_SIZEOF(time_t) AC_CHECK_SIZEOF(time_t)
dnl Checks for header files. dnl Checks for header files.
AC_CHECK_HEADERS(sys/types.h glob.h wctype.h locale.h langinfo.h sys/inotify.h) AC_CHECK_HEADERS(strings.h sys/types.h glob.h wctype.h locale.h langinfo.h sys/inotify.h)
dnl Checks for typedefs, structures, and compiler characteristics. dnl Checks for typedefs, structures, and compiler characteristics.
AC_STRUCT_TM AC_STRUCT_TM
dnl Checks for library functions.
AC_FUNC_UTIME_NULL
if test "$GCC" = yes; then if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes" CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes"
# Check for link-time optimization support # Check for link-time optimization support
@@ -86,9 +84,9 @@ if test "$?" != 0 ; then
echo "*** COULD NOT DETERMINE RELEASE DATE: docs/WHATSNEW is incorrect!" echo "*** COULD NOT DETERMINE RELEASE DATE: docs/WHATSNEW is incorrect!"
exit 1 exit 1
fi fi
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale initgroups inotify_init1) AC_CHECK_FUNCS(strdup strcasecmp strncasecmp setenv unsetenv glob mbstowcs setlocale initgroups inotify_init1)
VERSION=04.03.00 VERSION=$PACKAGE_VERSION
AC_SUBST(VERSION) AC_SUBST(VERSION)
AC_SUBST(PERL) AC_SUBST(PERL)
AC_SUBST(PERLARTIFACTS) AC_SUBST(PERLARTIFACTS)

View File

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

View File

@@ -1,5 +1,135 @@
CHANGES TO REMIND CHANGES TO REMIND
* VERSION 4.3 Patch 7 - 2024-04-29
* IMPROVEMENT: build.tk: Add a note if build.tk obtains default settings
from an existing Remind installation.
* IMPROVEMENT: configure: Pass all args to AC_INIT including the Remind
home page. Remove some unused autoconf cruft.
* IMPROVEMENT: Use standard C library versions of strdup, strcasemp and
strncasecmp where available, rather than using our own versions.
* MINOR FEATURE: remind: Make $Tt a synonym for trigtime().
* BUG FIX: remind: Make sure shellescape() doesn't mangle UTF-8 characters
with high-bits set.
* BUG FIX: remind: Don't rely on undefined behavior of "%" operator in
the ord() built-in function.
* BUG FIX: remind: Do not clear out trigtime() unnecessarily. Before,
you could not write things like the following; now you can:
REM Tue AT 11:30 DURATION 0:30 MSG Thing 1
REM Tue AT [trigtime()+trigduration()] DURATION 1:00 MSG Thing 2
REM Tue AT [trigtime()+trigduration()] DURATION 0:45 MSG Thing 3
for successive reminders that should be moved as a block if the time of
the first one changes.
* BUG FIX: Don't update trigdate() or trigtime() while parsing a REM
statement... only when actually computing the trigger.
* VERSION 4.3 Patch 6 - 2024-04-02
* NEW FILE: Add [$SysInclude]/holidays/pt.rem - Portuguese holidays, courtesy
of Joop Kiefte.
* BUG FIX: remind: Fix compile error on systems that don't support inotify(7).
* BUG FIX: remind: Fix test failures on FreeBSD. On FreeBSD, you have to copy
the result of getenv() or else a subsequent setenv() can change the stored
value.
* VERSION 4.3 Patch 5 - 2024-04-01
* IMPROVEMENT: remind: Use inotify to detect reminder file changes
even in regular daemon mode (-zn where n>0).
* INTERNAL IMPROVEMENTS: Rearrange and refactor some code.
* FIXES: Various fixes and improvements to man pages.
* BUG FIX: remind: Handle queued "SPECIAL COLOR" reminders correctly.
* BUG FIX: remind: Preserve the value of $DefaultColor that was in effect
when a reminder was queued; restore it before issuing the queued reminder.
* VERSION 4.3 Patch 4 - 2024-03-25
* NEW FEATURE: remind: Add the new "multitrig" function, which is how "trig"
should have worked in the first place. See man page for details.
* IMPROVEMENT: tkremind: Make errors in your reminders file stand out more
prominently.
* IMPROVEMENT: tkremind: If you click on an error in the "Errors..." popup,
tkremind will open a text editor on the offending file and line.
* IMPROVEMENT: tkremind: Format the "Queue..." output better and make queue
items clickable; clicking on a queue item opens a text editor on the
corresponding file and line.
* IMPROVEMENT: Add a standard [$SysInclude]/moonphases.rem file to display
moon phases on your calendar.
* IMPROVEMENT: Clean up the demo code in www/ and add PDF output.
* BUG FIX: tkremind: Correctly handle filenames containing spaces and other
characters that tend to confuse the shell.
* BUG FIX: tkremind: Raise dialog boxes after errors so that they
remain visible.
* CLEANUP: tkremind: Remove some dead code.
* VERSION 4.3 Patch 3 - 2024-03-18
* IMPROVEMENT: tkremind: Update icon to include a white border so it shows
up better on dark backgrounds.
* IMPROVEMENT: C code: Fix a number of cppcheck static-analysis warnings.
* IMPROVEMENT: remind: Update the "-zj" protocol to include a queue-id for
each queued reminder and add the DEL client command to delete a specific
item from the queue. Used by tkremind to implement "don't remind me about
this again today."
* MINOR NEW FEATURE: Add a "-ds" debugging flag to print out expression-parsing
stack high-water marks on exit. This esoteric feature is of no use to
anyone but the Remind author.
* IMPROVEMENT: tkremind: Stop using the deprecated tk_dialog command in favor
of the newer tk_messageBox command.
* IMPROVEMENT: remind: In server mode, try to minimize redraws by
consuming inotify events until at least 0.2s elapses without an
event appearing.
* BUG FIX: tkremind: The "Don't remind me about this again today" feature
was unreliable and only worked for reminders created with TkRemind itself.
It has been made more reliable and works with any reminder.
* BUG FIX: remind: Make it a syntax error if a local OMIT in a REM statement
is not followed by at least one weekday name.
* VERSION 4.3 Patch 2 - 2024-03-01
- BUG FIX: remind: Fix a logic error when implementing the RUN command in
server mode. As it turns out, the error is harmless, but it's best to do
things correctly.
- BUG FIX: The Makefile would install the tkremind.png and tkremind.desktop
files in the wrong location. This has been fixed.
* VERSION 4.3 Patch 1 - 2024-02-29
- BUG FIX: tests: "make test" could fail because of a bad test. This
has been fixed. There are no actual code changes to any of the programs
in Remind compared to 04.03.00.
* VERSION 4.3 Patch 0 - 2024-02-29 * VERSION 4.3 Patch 0 - 2024-02-29
- IMPROVEMENT: remind: If Remind is compiled on a system that supports - IMPROVEMENT: remind: If Remind is compiled on a system that supports

17
include/holidays/pt.rem Normal file
View File

@@ -0,0 +1,17 @@
# Portuguese holidays
# Courtesy of Joop Kiefte
OMIT 1 Jan MSG Ano Novo
OMIT [easterdate()-47] MSG Carnaval
OMIT [easterdate()-2] MSG Sexta-feira Santa
OMIT [easterdate()] MSG Domingo de Páscoa
OMIT 25 Apr MSG Dia da Liberdade
OMIT 1 May MSG Dia do Trabalhador
OMIT [easterdate()+60] MSG Corpo de Deus
OMIT 10 Jun MSG Dia de Portugal, de Camões e das Comunidades Portuguesas
OMIT 15 Aug MSG Assunção de Nossa Senhora
OMIT 5 Oct MSG Implantação da República
OMIT 1 Nov MSG Dia de Todos os Santos
OMIT 1 Dec MSG Restauração da Independência
OMIT 8 Dec MSG Imaculada Conceição
OMIT 25 Dec MSG Natal

14
include/moonphases.rem Normal file
View File

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

View File

@@ -66,7 +66,7 @@ causes \fBRemind\fR to display reminders on the calendar on the
day they actually occur \fIas well as\fR on any preceding days day they actually occur \fIas well as\fR on any preceding days
specified by the reminder's \fIdelta\fR. This \fIalso\fR causes specified by the reminder's \fIdelta\fR. This \fIalso\fR causes
\fBRemind\fR to include text outside %"...%" sequences that would \fBRemind\fR to include text outside %"...%" sequences that would
otherwise be removed (though the actual %" markers themselves are removed.) otherwise be removed (though the actual %" markers themselves are removed.) \"" Add comment to avoid Emacs highlighting problems
.TP .TP
.B 'l' .B 'l'
causes \fBRemind\fR to use VT100 line-drawing characters to draw causes \fBRemind\fR to use VT100 line-drawing characters to draw
@@ -300,6 +300,11 @@ Echo lines when displaying error messages
.TP .TP
.B f .B f
Trace the reading of reminder files Trace the reading of reminder files
.TP
.B s
Upon exit, print the high-water mark of the operator and value stacks
used for expression-parsing. This is unlikely to be useful unless
you're intimately familiar with Remind's source code.
.RE .RE
.TP .TP
\fB\-g\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR]]]] \fB\-g\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR[\fBa|d\fR]]]]
@@ -361,13 +366,18 @@ You use both \fB\-k\fR\fIcmd1\fR and \fB\-k:\fR\fIcmd2\fR to use different
commands for queued versus non-queued reminders. commands for queued versus non-queued reminders.
.RE .RE
.TP .TP
\fB\-z\fR[\fIn\fR] Runs \fBRemind\fR in the daemon mode. If \fIn\fR \fB\-z\fR[\fIn\fR] Runs \fBRemind\fR in "daemon mode". If \fIn\fR
is supplied, it specifies how often (in minutes) \fBRemind\fR should is supplied, it specifies how often (in minutes) \fBRemind\fR should
wake up to check if the reminder script has been changed. \fIN\fR wake up to check if the reminder script has been changed. \fIN\fR
defaults to 1, and can range from 1 to 60. Note that the use of the defaults to 1, and can range from 1 to 60. Note that the use of the
\fB\-z\fR option also enables the \fB\-f\fR option. \fB\-z\fR option also enables the \fB\-f\fR option.
.PP .PP
.RS .RS
If \fBRemind\fR is compiled on a system that supports
\fBinotify\fR(7), then if the reminder script supplied on the
command-line is actually a directory, \fBRemind\fR additionally checks
if all files within that directory have been modified since startup.
.PP
If you supply the option \fB\-zj\fR, \fBRemind\fR runs in a If you supply the option \fB\-zj\fR, \fBRemind\fR runs in a
special mode called \fBserver mode\fR. This is documented special mode called \fBserver mode\fR. This is documented
in the tkremind man page; see tkremind(1). The older server mode in the tkremind man page; see tkremind(1). The older server mode
@@ -449,14 +459,14 @@ text editor capable of creating plain-text files to create a
very simple and almost immediately understandable: very simple and almost immediately understandable:
.PP .PP
.nf .nf
REM 6 Jan MSG Dianne's birthday REM Mar 31 MSG International Transgender Day of Visibility
.fi .fi
.PP .PP
to the baroque and obscure: to the baroque and obscure:
.PP .PP
.nf .nf
REM [date(thisyear, 1, 1) + 180] ++5 OMIT \\ REM [date(thisyear, 1, 1) + 180] ++5 OMIT \\
sat sun BEFORE MSG [ord(thisyear-1980)] payment due %b! sat sun BEFORE MSG [ord(thisyear-1980)] payment due %b!
.fi .fi
.PP .PP
A reminder file consists of commands, with one command per line. Several A reminder file consists of commands, with one command per line. Several
@@ -2389,9 +2399,9 @@ Universal Time Coordinated in the \fB$MinsFromUTC\fR system variable.
If non-zero, then the \fB\-c\fR option was supplied on the command line. If non-zero, then the \fB\-c\fR option was supplied on the command line.
.TP .TP
.B $Daemon (read-only) .B $Daemon (read-only)
If the daemon mode \fB\-z\fR was invoked, contains the number of If "daemon mode" \fB\-z\fR was invoked, contains the number of
minutes between wakeups. If not running in daemon mode, contains minutes between wakeups. If not running in daemon mode, contains
0. 0. In server mode (either \fB-z0\fR or \fB-zj\fR), contains -1.
.TP .TP
.B $DateSep .B $DateSep
This variable can be set only to "/" or "-". It holds the character This variable can be set only to "/" or "-". It holds the character
@@ -2737,6 +2747,9 @@ Equivalent to \fBwkdaynum(trigdate())\fR.
.B $Ty (read-only) .B $Ty (read-only)
Equivalent to \fByear(trigdate())\fR. Equivalent to \fByear(trigdate())\fR.
.TP .TP
.B $Tt (read-only, TIME type)
Equivalent to \fBtrigtime()\fR.
.TP
.B $TimeSep .B $TimeSep
This variable can be set only to ":" or ".". It holds the character 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 used to separate portions of a time when \fBRemind\fR prints a TIME or
@@ -3350,6 +3363,62 @@ which default to \fBtoday()\fR and midnight, respectively. The returned
value is an integer from 0 to 359, representing the phase of the moon value is an integer from 0 to 359, representing the phase of the moon
in degrees. 0 is a new moon, 180 is a full moon, 90 is first-quarter, etc. in degrees. 0 is a new moon, 180 is a full moon, 90 is first-quarter, etc.
.TP .TP
.B multitrig(s_trig1 [,s_trig2, [... s_trigN]])
\fBmultitrig\fR evaluates each string as a trigger, similar to \fBevaltrig\fR,
and returns the \fIearliest\fR trigger date that is on or after \fBtoday()\fR.
\fBmultitrig\fR is similar to \fBtrig\fR but has the following difference:
.RS
.PP
\fBtrig\fR returns the \fIfirst\fR trigger date that would have triggered today,
whereas \fBmultitrig\fR returns the \fIearliest\fR trigger date later than
today, regardless of whether it would have triggered today.
.PP
If no trigger can be computed that is later than \fBtoday()\fR, then
\fBmultitrig\fR returns 1990-01-01.
.PP
Consider the following examples, assuming that today is Sunday, 24 March 2024:
.PP
.nf
# Returns 1990-01-01 because neither would trigger today
SET a trig("Mon", "Wed")
# Returns 2024-03-25 because it's the earlier trigger date
SET a multitrig("Mon", "Wed")
# Returns 2024-03-27 because it's the first that would trigger today
SET a trig("Wed +3", "Mon +3")
# Returns 2024-03-25 because it's the earlier trigger date
SET a multitrig("Wed +3", "Mon +3")
# Returns 1990-01-01 because all triggers have expired
SET a multitrig("2000", "2022", "1998", "2023")
.fi
.PP
In general, \fBmultitrig\fR works better with the Remind algorithm than
\fBtrig\fR and should be used most of the time. As an example, this
reminder is issued at the end of each quarter:
.PP
.nf
REM [multitrig("Mar 31", "Jun 30", "Sep 30", "Dec 31")] +7 MSG \\
%"End of [ord($Tm/3)] quarter%" is %b.
.fi
.PP
If you want the last working day of each quarter, you could use:
.PP
.nf
PUSH-OMIT-CONTEXT
OMIT Sat Sun
REM [multitrig("Mar ~1", "Jun ~1", "Sep ~1", "Dec ~1")] +7 MSG \\
%"Last working day of [ord($Tm/3)] quarter%" is %b.
POP-OMIT-CONTEXT
.fi
.PP
Note that unlike \fBevaltrig\fR, \fBmultitrig\fR always returns a \fBDATE\fR
and never a \fBDATETIME\fR. Including an \fBAT\fR clause in a trigger
supplied to \fBmultitrig\fR will result in an error.
.RE
.TP
.B ndawn([dq_date]) .B ndawn([dq_date])
Returns the time of "nautical dawn" on the specified \fIdate\fR. If Returns the time of "nautical dawn" on the specified \fIdate\fR. If
\fIdate\fR is omitted, defaults to \fBtoday()\fR. If a \fIdatetime\fR object \fIdate\fR is omitted, defaults to \fBtoday()\fR. If a \fIdatetime\fR object
@@ -5019,21 +5088,25 @@ structuring comments in your PostScript code.
.PP .PP
.SH DAEMON MODE .SH DAEMON MODE
.PP .PP
If you use the \fB\-z\fR command-line option, \fBRemind\fR runs in the If you use the \fB\-z\fR command-line option, \fBRemind\fR runs in
"daemon" mode. In this mode, no "normal" reminders are issued. "daemon mode". In this mode, no "normal" reminders are issued.
Instead, only timed reminders are collected and queued, and are then Instead, only timed reminders are collected and queued, and are then
issued whenever they reach their trigger time. issued whenever they reach their trigger time.
.PP .PP
In addition, \fBRemind\fR wakes up every few minutes to check the modification In addition, \fBRemind\fR wakes up every few minutes to check the
date on the reminder script (the filename supplied on the command line.) modification date on the reminder script (the filename supplied on the
If \fBRemind\fR detects that the script has changed, it re-executes itself command line.) If \fBRemind\fR detects that the script has changed,
in daemon mode, and interprets the changed script. it re-executes itself in daemon mode, and interprets the changed
script. If \fBRemind\fR was compiled with support for
\fBinotify\fR(7), then if the command-line reminder script is really a
directory, \fBRemind\fR also re-executes itself if any of the files in
the directory is changed.
.PP .PP
In daemon mode, \fBRemind\fR also re-reads the remind script when it In daemon mode, \fBRemind\fR also re-reads the remind script when it
detects that the system date has changed. detects that the system date has changed.
.PP .PP
In daemon mode, \fBRemind\fR acts as if the \fB\-f\fR option had been used, In daemon mode, \fBRemind\fR acts as if the \fB\-f\fR option had been used,
so to run in the daemon mode in the background, use: so to run in daemon mode in the background, use:
.PP .PP
.nf .nf
remind \-z .reminders & remind \-z .reminders &
@@ -5363,7 +5436,7 @@ as:
.PP .PP
You can define your own substitution sequences in addition to the built-in You can define your own substitution sequences in addition to the built-in
ones as follows: If you define a function named \fBsubst_\fIname\fB(alt, date, time)\fR, then the sequence \fB%{name}\fR calls the function with \fBalt\fR ones as follows: If you define a function named \fBsubst_\fIname\fB(alt, date, time)\fR, then the sequence \fB%{name}\fR calls the function with \fBalt\fR
set to 0 and \fBdate\fR and \fRtime\fR to the trigger date and time, set to 0 and \fBdate\fR and \fBtime\fR to the trigger date and time,
respectively. The \fB%{name}\fR sequence is replaced with whatever the respectively. The \fB%{name}\fR sequence is replaced with whatever the
function returns. The sequence \fB%*{name}\fR is similar, but calls function returns. The sequence \fB%*{name}\fR is similar, but calls
the function with \fBalt\fR set to 1. the function with \fBalt\fR set to 1.

View File

@@ -184,7 +184,9 @@ on the reminder.
If there are any errors in your reminder file, the "Queue..." button If there are any errors in your reminder file, the "Queue..." button
changes to "Errors...". Click on "Errors..." to see the Remind error changes to "Errors...". Click on "Errors..." to see the Remind error
output. Click "OK" to close the error window; this makes the button output. Click "OK" to close the error window; this makes the button
in the main TkRemind window to revert to "Queue..." in the main TkRemind window to revert to "Queue..." You can click on
any error message to open an editor on the file and line number that
caused the error.
.SH BACKGROUND REMINDERS .SH BACKGROUND REMINDERS
@@ -403,6 +405,10 @@ like this:
The value of the \fBqueue\fR key is an array of JSON objects, each The value of the \fBqueue\fR key is an array of JSON objects, each
representing a queued reminder. representing a queued reminder.
.TP
DEL \fIqid\fR
Delete the reminder with queue-id \fIqid\fR from the queue.
.TP .TP
REREAD REREAD
Re-read the reminder file. Returns the following status line: Re-read the reminder file. Returns the following status line:
@@ -419,15 +425,19 @@ Additional status lines written are as follows:
.TP .TP
.nf .nf
{"response":"reminder","ttime":tt,"now":now,"tags":tags,"body":body} {"response":"reminder","ttime":tt,"now":now,"tags":tags,"qid":qid,"body":body}
.fi .fi
In this line, \fItt\fR is the trigger time of the reminder (expressed In this line, \fItt\fR is the trigger time of the reminder (expressed
as a string), \fInow\fR is the current time, \fItags\fR (if present) as a string), \fInow\fR is the current time, \fItags\fR (if present)
is the tag or tags associated with the reminder, and \fIbody\fR is is the tag or tags associated with the reminder, and \fIbody\fR is the
the body of the reminder. This response causes \fBTkRemind\fR to body of the reminder. This response causes \fBTkRemind\fR to pop up a
pop up a reminder notification. reminder notification. \fIqid\fR is a unique identifier for this
reminder. You may delete it from the queue by sending a \fBDEL\fR
\fIqid\fR command to the server. Note that \fIqid\fRs are not stable
across re-reads; if \fBRemind\fR restarts itself to re-read the reminder
file, then the \fIqid\fR values are likely to change, and any reminder
deleted with a \fBDEL\fR \fIqid\fR command is likely to be re-queued.
.TP .TP
.nf .nf

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -29,69 +29,92 @@ set Hostname [exec hostname]
# Our icon photo # Our icon photo
catch { catch {
image create photo rpicon -data { image create photo rpicon -data {
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 } Go0Ghw8fHmH/5+OJJ57gm7YEwdkneROgfG2NgwAzIWVlZX5fd1m1atVQq/X19VFKSopojzl//rzP
1m9oaCC9Xk8A+NdiPlDaA4QeLPnyyy/9JmDChAnU2NhIREQHDhwQjZufn++z8kREn376KQGeN8Z4
H0TJUkqA0CSYKvXisxicTieKi4vR09ODQ4cOicaVehJ04cIFAJ69wqCmyQAQNir4gNAcEPegnV4p
zGYzGIYRtPwCnm3vxo0bJaXHjX+erUCZtjYIIQJipF5O8IVz587B147ymWeegVrt2zx5+fLlISJ5
BFzwp3xCuUYFioCBgQHRmX/y5MnYsWOHpLROnToFlmVhMBj4dweO+VM+IQIiA0WAL2zZsoW/nRXF
6dOnAXhelRm0OBEA4V2VBAgREMa7dTVqCAsLwwsvvCApbnt7+9AxGa/7t8KzDVYMIQJCHgYBmzZt
8nnyw8FsNoOzTvMIUKb+8iBIwGgPAZ1Oh127dkmOX1ZWBgAYN24c31r0V78L4kU5mE5EvdHR0QG/
CM13mzZtkqT4EBH19PQQ90ZaVlYW/1GIUgXImyK0HB67+s2uri79aA4BlUqF5557TnL848ePD5nP
582bxwXfByD+UTEJ4PSAvW63e98nn3yCkpIS3Lx5M6AvNj2IvLw8LF++XHJ8vvU4O3voEyCyDaBe
QURzmpub2UWLFo1ql+e74uJiyd2fYRhKTEwkABQcHEx2u517tNXf7k+Dm6H7e/fufWiVnzNnDg0M
DEiqPMuydPTo0SHZnJycoUfk/ZtBiuwBf9q3b99HRqNR88EHH4ja6gOBHTt2DFN7+/v7UVVVhdra
WtTX16OhoWHYL/+NtPnz53N/bfBsgvzHIBPJRGTv6uqigwcP0uOPP07BwcEBb/0JEybQ66+/Ts8+
+ywtX76cHn30UVH7IOdCQ0Np2rRpQ1+PIKL/CkTrE438gsRLAP4ZgNFms6GsrAzXrl3DrVu3UF1d
jZqaGlF7nhyo1WpEREQgIiICkZGRiIiIQFRUFKKiohAbG4vo6GiYTCYkJiYiKSkJQUHDPhCxBkBA
XlkR+oRGGoB/BLAEgAmDClN3dzeuXLkCh8OBjo4OdHZ2orOzc8Q9fz5CQ0Oh1+sxfvx4GAwGhIaG
Ijg4GImJiTAaRV/vGYDnwkMHgHsA6uExfd0E8J/yq+odUr8hkgTPm9nZAGbC84amAZ6vNI+D8LYa
8HTjAQBueMatG57bnF3wrOX34DnVqYOngjXwfAPULx1fKv4X5zAnLNolSeQAAAAASUVORK5CYII=}
wm iconphoto . -default rpicon wm iconphoto . -default rpicon
} }
proc die_with_error { msg } {
tk_messageBox -message "Fatal Error" -detail $msg -icon error -type ok
exit 1
}
proc show_error { msg } {
tk_messageBox -message "Error" -detail $msg -icon error -type ok
}
proc missing_tcllib { pkg } { proc missing_tcllib { pkg } {
catch { puts stderr "Could not find the '$pkg' package -- you must install tcllib.\nPlease see http://tcllib.sourceforge.net/" } catch { puts stderr "Could not find the '$pkg' package -- you must install tcllib.\nPlease see http://tcllib.sourceforge.net/" }
tk_dialog .err "Error: tcllib not installed" "Could not find the '$pkg' package -- you must install tcllib. Please see http://tcllib.sourceforge.net/" error 0 OK tk_messageBox -message "Error: tcllib not installed" -detail "Could not find the '$pkg' package -- you must install tcllib. Please see http://tcllib.sourceforge.net/" -icon error -type ok
exit 1 exit 1
} }
if {[catch {package require mime}]} { if {[catch {package require mime}]} {
@@ -106,7 +129,7 @@ if {[catch {package require json}]} {
} }
if {$tcl_platform(platform) == "windows"} { if {$tcl_platform(platform) == "windows"} {
tk_dialog .error Error "Please do not port Remind to Windows" error 0 OK tk_messageBox -message "Please do not port Remind to Windows" -icon error -type ok
exit 1 exit 1
} }
@@ -301,14 +324,14 @@ set Option(PrintFormat) ps
set WarningHeaders [list "# Lines starting with REM TAG TKTAGnnn ... were created by tkremind" "# Do not edit them by hand or results may be unpredictable."] set WarningHeaders [list "# Lines starting with REM TAG TKTAGnnn ... were created by tkremind" "# Do not edit them by hand or results may be unpredictable."]
# Highest tag seen so far. Array of tags is stored in ReminderTags() # Highest tag seen so far.
set HighestTagSoFar 0 set HighestTagSoFar 0
# Check Remind version # Check Remind version
set ver [GetRemindVersion] set ver [GetRemindVersion]
if {"$ver" < "04.03.00"} { if {"$ver" < "04.03.03"} {
tk_dialog .error Error "This version of TkRemind requires Remind version 04.03.00 or newer; you have version $ver" error 0 OK tk_messageBox -message "This version of TkRemind requires Remind version 04.03.03 or newer; you have version $ver" -icon error -type ok
exit 1 exit 1
} }
@@ -338,6 +361,21 @@ proc is_warning_header { line } {
return 0 return 0
} }
proc extract_tag { regex tag } {
if {[regexp $regex $tag extracted]} {
return $extracted
}
return "*"
}
proc extract_tktag { tag } {
extract_tag {TKTAG[0-9]+} $tag
}
proc extract_syntag { tag } {
extract_tag {__syn__[0-9a-f]+} $tag
}
#*********************************************************************** #***********************************************************************
# %PROCEDURE: Initialize # %PROCEDURE: Initialize
# %ARGUMENTS: # %ARGUMENTS:
@@ -350,7 +388,7 @@ proc is_warning_header { line } {
#*********************************************************************** #***********************************************************************
proc Initialize {} { proc Initialize {} {
global DayNames argc argv CommandLine ReminderFile AppendFile Remind PSCmd global DayNames argc argv CommandLine ReminderFile AppendFile Remind PSCmd
global MondayFirst TwentyFourHourMode ReminderFileModTime global MondayFirst TwentyFourHourMode
global TodayDay TodayMonth TodayYear global TodayDay TodayMonth TodayYear
global Option ConfigFile global Option ConfigFile
@@ -362,8 +400,8 @@ proc Initialize {} {
set TodayYear [clock format $now -format %Y] set TodayYear [clock format $now -format %Y]
set TodayDay [string trim [clock format $now -format %e]] set TodayDay [string trim [clock format $now -format %e]]
set CommandLine "|$Remind -itkremind=1 -pp -y -l EXTRA" set CommandLine "$Remind -itkremind=1 -pp -y -l @EXTRA@"
set PSCmd "$Remind -itkremind=1 -itkprint=1 -pp -l EXTRA" set PSCmd "$Remind -itkremind=1 -itkprint=1 -pp -l @EXTRA@"
set i 0 set i 0
while {$i < $argc} { while {$i < $argc} {
if {[regexp -- {-[bgxim].*} [lindex $argv $i]]} { if {[regexp -- {-[bgxim].*} [lindex $argv $i]]} {
@@ -404,8 +442,8 @@ proc Initialize {} {
# Check system sanity # Check system sanity
if {! [file readable $ReminderFile]} { if {! [file readable $ReminderFile]} {
set ans [tk_dialog .error "TkRemind: Warning" "Can't read reminder file `$ReminderFile'" warning 0 "Create it and continue" "Exit"] set ans [tk_messageBox -message "Can't read reminder file `$ReminderFile'. Create it and continue?" -type yesno -icon question]
if {$ans != 0} { if {$ans != "yes"} {
exit 1 exit 1
} }
catch { catch {
@@ -416,7 +454,7 @@ proc Initialize {} {
} }
} }
if {! [file readable $ReminderFile]} { if {! [file readable $ReminderFile]} {
tk_dialog .error "TkRemind: Error" "Could not create reminder file `$ReminderFile'" error 0 "Exit" die_with_error "Could not create reminder file `$ReminderFile'"
exit 1 exit 1
} }
@@ -426,58 +464,21 @@ proc Initialize {} {
write_warning_headers $out write_warning_headers $out
puts $out "" puts $out ""
close $out}]} { close $out}]} {
tk_dialog .error "Created File" "Created blank file `$AppendFile'" info 0 "OK" tk_messageBox -message "Created File" -detail "Created blank file `$AppendFile'" -icon info -type ok
} }
} }
if {! [file writable $AppendFile]} { if {! [file writable $AppendFile]} {
tk_dialog .error Error "Can't write reminder file `$AppendFile'" error 0 Ok die_with_error "Can't write reminder file `$AppendFile'"
exit 1 exit 1
} }
append CommandLine " $ReminderFile" append CommandLine " "
append PSCmd " $ReminderFile" append CommandLine [posix_escape $ReminderFile]
append PSCmd " "
append PSCmd [posix_escape $ReminderFile]
# Get modification time of ReminderFile set CommandLine "|/bin/sh -c \"$CommandLine @MONTH@ @YEAR@\""
set ReminderFileModTime -1
catch {
set ReminderFileModTime [file mtime $ReminderFile]
}
MonitorReminderFile
# puts "CommandLine: $CommandLine"
}
#---------------------------------------------------------------------------
# MonitorReminderFile
# If Reminder File modtime changes, restart daemon
#---------------------------------------------------------------------------
proc MonitorReminderFile {} {
global ReminderFileModTime ReminderFile
if {$ReminderFileModTime < 0} {
# Could not stat file
return
}
set mtime -1
catch {
set mtime [file mtime $ReminderFile]
}
if {$mtime < 0} {
# Doh!
return
}
# Run ourselves again
after 60000 MonitorReminderFile
# Redraw calendar and restart daemon if needed
if {$ReminderFileModTime < $mtime} {
set ReminderFileModTime $mtime
ScheduleUpdateForChanges
}
} }
#*********************************************************************** #***********************************************************************
@@ -982,7 +983,7 @@ proc WriteOptionsToFile {} {
global Option OptDescr global Option OptDescr
set problem [catch {set f [open "$ConfigFile.tmp" "w"]} err] set problem [catch {set f [open "$ConfigFile.tmp" "w"]} err]
if {$problem} { if {$problem} {
tk_dialog .error Error "Can't write $ConfigFile.tmp: $err" 0 OK show_error "Can't write $ConfigFile.tmp: $err"
return return
} }
@@ -1081,8 +1082,11 @@ proc FillCalWindow {} {
set_button_to_queue set_button_to_queue
set month [lindex $MonthNames $CurMonth] set month [lindex $MonthNames $CurMonth]
set cmd [regsub EXTRA $CommandLine $Option(ExtraRemindArgs)] set cmd [regsub @EXTRA@ $CommandLine $Option(ExtraRemindArgs)]
set file [open "$cmd $month $CurYear" r] set cmd [regsub @MONTH@ $cmd $month]
set cmd [regsub @YEAR@ $cmd $CurYear]
set file [open $cmd r]
# Look for # rem2ps2 begin line # Look for # rem2ps2 begin line
while { [gets $file line] >= 0 } { while { [gets $file line] >= 0 } {
if { [string compare "$line" "# rem2ps2 begin"] == 0 } { break } if { [string compare "$line" "# rem2ps2 begin"] == 0 } { break }
@@ -1396,29 +1400,30 @@ proc DoPrint {} {
WriteOptionsToFile WriteOptionsToFile
if {$Option(PrintDest) == "file"} { if {$Option(PrintDest) == "file"} {
if {$fname == ""} { if {$fname == ""} {
tk_dialog .error Error "No filename specified" error 0 Ok show_error "No filename specified"
return return
} }
if {[file isdirectory $fname]} { if {[file isdirectory $fname]} {
tk_dialog .error Error "$fname is a directory" error 0 Ok show_error "$fname is a directory"
return return
} }
if {[file readable $fname]} { if {[file readable $fname]} {
set ans [tk_dialog .error Overwrite? "Overwrite $fname?" question 0 No Yes] set ans [tk_messageBox -message "Overwrite?" -detail "Overwrite $fname?" -icon question -type yesno]
if {$ans == 0} { if {$ans == no} {
return return
} }
} }
set fname [posix_escape $fname]
set fname "> $fname" set fname "> $fname"
} else { } else {
set fname "| $cmd" set fname "| $cmd"
} }
if {$HaveRem2PDF && $Option(PrintFormat) == "pdf"} { if {$HaveRem2PDF && $Option(PrintFormat) == "pdf"} {
set p [regsub EXTRA $PSCmd "-itkpdf=1 $Option(ExtraRemindArgs)"] set p [regsub @EXTRA@ $PSCmd "-itkpdf=1 $Option(ExtraRemindArgs)"]
set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PDF" set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PDF"
} else { } else {
set p [regsub EXTRA $PSCmd $Option(ExtraRemindArgs)] set p [regsub @EXTRA@ $PSCmd $Option(ExtraRemindArgs)]
set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PS" set cmd "$p 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PS"
set Option(PrintFormat) ps set Option(PrintFormat) ps
} }
@@ -1487,7 +1492,7 @@ proc DoPrint {} {
append cmd " $fname" append cmd " $fname"
Status "Printing..." Status "Printing..."
if {[catch {eval "exec $cmd"} err]} { if {[catch {exec /bin/sh "-c" $cmd} err]} {
set RemindErrors [unique_lines $err] set RemindErrors [unique_lines $err]
set_button_to_errors set_button_to_errors
} }
@@ -1506,6 +1511,7 @@ proc PrintFileBrowse {} {
.p.filename icursor end .p.filename icursor end
.p.filename xview end .p.filename xview end
} }
raise .p
} }
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@@ -1557,11 +1563,13 @@ proc DoGoto {} {
global CurYear CurMonth MonthNames global CurYear CurMonth MonthNames
set year [.g.y.e get] set year [.g.y.e get]
if { ! [regexp {^[0-9]+$} $year] } { if { ! [regexp {^[0-9]+$} $year] } {
tk_dialog .error Error {Illegal year specified (1990-5990)} error 0 Ok show_error {Illegal year specified (1990-5990)}
raise .g
return return
} }
if { $year < 1990 || $year > 5990 } { if { $year < 1990 || $year > 5990 } {
tk_dialog .error Error {Illegal year specified (1990-5990)} error 0 Ok show_error {Illegal year specified (1990-5990)}
raise .g
return return
} }
set month [lsearch -exact $MonthNames [.g.mon cget -text]] set month [lsearch -exact $MonthNames [.g.mon cget -text]]
@@ -1581,7 +1589,8 @@ proc Quit {} {
StopBackgroundRemindDaemon StopBackgroundRemindDaemon
exit 0 exit 0
} }
if { [tk_dialog .question "Confirm..." {Really quit?} question 0 No Yes] } { set ans [tk_messageBox -message "Really quit?" -icon question -type yesno]
if { $ans == "yes" } {
destroy . destroy .
StopBackgroundRemindDaemon StopBackgroundRemindDaemon
exit 0 exit 0
@@ -2018,7 +2027,7 @@ proc CreateYearMenu {w {every 1}} {
# firstDay -- first weekday in month (0-6) # firstDay -- first weekday in month (0-6)
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
proc ModifyDay {d firstDay} { proc ModifyDay {d firstDay} {
global ModifyDialogResult AppendFile HighestTagSoFar ReminderTags global ModifyDialogResult AppendFile HighestTagSoFar
catch {destroy .mod} catch {destroy .mod}
toplevel .mod toplevel .mod
CreateModifyDialog .mod $d $firstDay "Cancel" "Add to reminder file" "Preview reminder" CreateModifyDialog .mod $d $firstDay "Cancel" "Add to reminder file" "Preview reminder"
@@ -2039,7 +2048,8 @@ proc ModifyDay {d firstDay} {
} }
set problem [catch {set rem [CreateReminder .mod]} err] set problem [catch {set rem [CreateReminder .mod]} err]
if {$problem} { if {$problem} {
tk_dialog .error Error "$err" error 0 Ok show_error $err
raise .mod
} else { } else {
if {$ModifyDialogResult == 3} { if {$ModifyDialogResult == 3} {
set rem [EditReminder $rem Cancel "Add reminder"] set rem [EditReminder $rem Cancel "Add reminder"]
@@ -2053,7 +2063,6 @@ proc ModifyDay {d firstDay} {
Status "Writing reminder..." Status "Writing reminder..."
set f [open $AppendFile a] set f [open $AppendFile a]
incr HighestTagSoFar incr HighestTagSoFar
set ReminderTags($HighestTagSoFar) 1
WriteReminder $f TKTAG$HighestTagSoFar $rem $opts WriteReminder $f TKTAG$HighestTagSoFar $rem $opts
close $f close $f
@@ -2066,7 +2075,6 @@ proc ModifyDay {d firstDay} {
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# CenterWindow -- center a window on the screen or over a parent. # CenterWindow -- center a window on the screen or over a parent.
# Stolen from tk_dialog code
# Arguments: # Arguments:
# w -- window to center # w -- window to center
# parent -- window over which to center. Defaults to screen if not supplied. # parent -- window over which to center. Defaults to screen if not supplied.
@@ -2581,8 +2589,9 @@ proc BrowseForFileRead {w {dir ""}} {
if {$dir == ""} { if {$dir == ""} {
set dir [$w.cwd cget -text] set dir [$w.cwd cget -text]
} }
if {[catch "cd $dir" err]} { if {[catch {cd $dir} err]} {
tk_dialog .error Error "$err" error 0 Ok show_error "$err"
raise $w
return return
} }
$w.cwd configure -text [pwd] $w.cwd configure -text [pwd]
@@ -2625,13 +2634,14 @@ proc BrowseForFileRead {w {dir ""}} {
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
proc StartBackgroundRemindDaemon {} { proc StartBackgroundRemindDaemon {} {
global Remind DaemonFile ReminderFile Option TwentyFourHourMode global Remind DaemonFile ReminderFile Option TwentyFourHourMode
set fname [posix_escape $ReminderFile]
if {$TwentyFourHourMode} { if {$TwentyFourHourMode} {
set problem [catch { set DaemonFile [open "|$Remind -b1 -zj -itkremind=1 $Option(ExtraRemindArgs) $ReminderFile" "r+"] } err] set problem [catch { set DaemonFile [open "|/bin/sh -c \"$Remind -b1 -zj -y -itkremind=1 $Option(ExtraRemindArgs) $fname\"" "r+"] } err]
} else { } else {
set problem [catch { set DaemonFile [open "|$Remind -zj -itkremind=1 $Option(ExtraRemindArgs) $ReminderFile" "r+"] } err] set problem [catch { set DaemonFile [open "|/bin/sh -c \"$Remind -zj -y -itkremind=1 $Option(ExtraRemindArgs) $fname\"" "r+"] } err]
} }
if {$problem} { if {$problem} {
tk_dialog .error Error "Can't start Remind daemon in background: $err" error 0 OK show_error "Can't start Remind daemon in background: $err"
} else { } else {
fileevent $DaemonFile readable "DaemonReadable $DaemonFile" fileevent $DaemonFile readable "DaemonReadable $DaemonFile"
puts $DaemonFile "STATUS" puts $DaemonFile "STATUS"
@@ -2667,13 +2677,7 @@ proc StopBackgroundRemindDaemon {} {
# Restarts the background Remind daemon # Restarts the background Remind daemon
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
proc RestartBackgroundRemindDaemon {} { proc RestartBackgroundRemindDaemon {} {
global DaemonFile ReminderFile ReminderFileModTime global DaemonFile ReminderFile
# Don't let the background handler trigger another reread
catch {
set mtime [file mtime $ReminderFile]
set ReminderFileModTime $mtime
}
catch { catch {
puts $DaemonFile "REREAD" puts $DaemonFile "REREAD"
@@ -2715,11 +2719,30 @@ proc ShowQueue { queue } {
if { $did > 0 } { if { $did > 0 } {
$w.t insert end "\n" $w.t insert end "\n"
} }
foreach r $q { set fntag ""
catch {
set fname [dict get $q filename]
set lineno [dict get $q lineno]
set fntag [string cat "FILE_" $lineno "_" $fname]
}
if { "$fntag" != "" } {
$w.t tag bind $fntag <Enter> [list $w.t tag configure $fntag -underline 1]
$w.t tag bind $fntag <Leave> [list $w.t tag configure $fntag -underline 0]
$w.t tag bind $fntag <ButtonPress-1> [list FireEditor $w.t $fntag]
$w.t tag bind $fntag <ButtonPress-3> [list FireEditor $w.t $fntag]
}
foreach key [list time nexttime body] {
set r [dict get $q $key]
if { $toggle != 0 } { if { $toggle != 0 } {
$w.t insert end "$r " grey $w.t insert end "$key=$r" [list grey $fntag]
if {"$key" != "body"} {
$w.t insert end "; " [list grey $fntag]
}
} else { } else {
$w.t insert end "$r " $w.t insert end "$key=$r" [list $fntag]
if {"$key" != "body"} {
$w.t insert end "; " [list $fntag]
}
} }
} }
$w.t insert end "\n" $w.t insert end "\n"
@@ -2728,6 +2751,8 @@ proc ShowQueue { queue } {
} }
if { $did == 0 } { if { $did == 0 } {
$w.t insert end "(Queue is empty)\n" $w.t insert end "(Queue is empty)\n"
} else {
$w.t insert end "\n\nClick on a queue item to open an editor on the corresponding REM command.\n"
} }
$w.t configure -state disabled $w.t configure -state disabled
} }
@@ -2764,7 +2789,7 @@ proc DaemonReadable { file } {
if {[catch {set obj [::json::json2dict $line]}]} { if {[catch {set obj [::json::json2dict $line]}]} {
return; return;
} }
if (![dict exists $obj response]) { if {![dict exists $obj response]} {
return; return;
} }
set response [dict get $obj response] set response [dict get $obj response]
@@ -2785,7 +2810,11 @@ proc DaemonReadable { file } {
set tag [dict get $obj tags] set tag [dict get $obj tags]
} }
set body [dict get $obj body] set body [dict get $obj body]
IssueBackgroundReminder $body $time $now $tag set qid "*"
if {[dict exists $obj qid]} {
set qid [dict get $obj qid]
}
IssueBackgroundReminder $body $time $now $tag $qid
} }
"queue" { "queue" {
set queue [dict get $obj queue] set queue [dict get $obj queue]
@@ -2793,7 +2822,7 @@ proc DaemonReadable { file } {
} }
"newdate" { "newdate" {
# Date has rolled over -- clear "ignore" list # Date has rolled over -- clear "ignore" list
catch { unset Ignore} catch { unset Ignore }
Initialize Initialize
FillCalWindow FillCalWindow
ShowTodaysReminders ShowTodaysReminders
@@ -2821,13 +2850,14 @@ proc DaemonReadable { file } {
# time -- time of reminder # time -- time of reminder
# now -- current time according to Remind daemon # now -- current time according to Remind daemon
# tag -- tag for reminder, or "*" if no tag # tag -- tag for reminder, or "*" if no tag
# qid -- Queue-ID for reminder, or "*" if no qid
# Returns: # Returns:
# nothing # nothing
# Description: # Description:
# Reads a background reminder from daemon and pops up window. # Reads a background reminder from daemon and pops up window.
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
proc IssueBackgroundReminder { body time now tag } { proc IssueBackgroundReminder { body time now tag qid } {
global BgCounter Option Ignore global BgCounter Option Ignore DaemonFile
if {$Option(Deiconify)} { if {$Option(Deiconify)} {
wm deiconify . wm deiconify .
} }
@@ -2837,9 +2867,16 @@ proc IssueBackgroundReminder { body time now tag } {
return return
} }
# Do nothing if user told us to ignore this reminder # If we're ignoring it because of tag, ignore and delete
if {[info exists Ignore($tag)]} { set syntag [extract_syntag $tag]
return if {$syntag != "*"} {
if {[info exists Ignore($syntag)]} {
if {$qid != "*"} {
puts $DaemonFile "DEL $qid"
flush $DaemonFile
}
return
}
} }
incr BgCounter incr BgCounter
@@ -2852,20 +2889,26 @@ proc IssueBackgroundReminder { body time now tag } {
frame $w.b frame $w.b
# Automatically shut down window after a minute if option says so # Automatically shut down window after a minute if option says so
set after_token [after 60000 [list ClosePopup $w "" $Option(MailAddr) $Option(AutoClose) "" $tag $body $time]] set after_token [after 60000 [list ClosePopup $w "" $Option(MailAddr) $Option(AutoClose) "" $tag $body $time $qid]]
wm protocol $w WM_DELETE_WINDOW [list ClosePopup $w $after_token "" 1 "" $tag $body $time] wm protocol $w WM_DELETE_WINDOW [list ClosePopup $w $after_token "" 1 "" $tag $body $time $qid]
button $w.ok -text "OK" -command [list ClosePopup $w $after_token "" 1 "" $tag $body $time] button $w.ok -text "OK" -command [list ClosePopup $w $after_token "" 1 "" $tag $body $time $qid]
if {$tag != "*"} { set tktag [extract_tktag $tag]
button $w.nomore -text "Don't remind me again today" -command [list ClosePopup $w $after_token "" 1 "ignore" $tag $body $time] if {$tktag != "*"} {
button $w.kill -text "Delete this reminder completely" -command [list ClosePopup $w $after_token "" 1 "kill" $tag $body $time] button $w.kill -text "Delete this reminder completely" -command [list ClosePopup $w $after_token "" 1 "kill" $tag $body $time $qid]
}
if {$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.l -side top
pack $w.msg -side top -expand 1 -fill both pack $w.msg -side top -expand 1 -fill both
pack $w.b -side top pack $w.b -side top
pack $w.ok -in $w.b -side left pack $w.ok -in $w.b -side left
if {$tag != "*"} { if {$qid != "*"} {
pack $w.nomore $w.kill -in $w.b -side left pack $w.nomore -in $w.b -side left
}
if {$tktag != "*"} {
pack $w.kill -in $w.b -side left
} }
CenterWindow $w . CenterWindow $w .
@@ -2959,7 +3002,7 @@ proc main {} {
# the tag array. Also adjusts HighestTagSoFar # the tag array. Also adjusts HighestTagSoFar
#*********************************************************************** #***********************************************************************
proc ScanForTags { fname } { proc ScanForTags { fname } {
global HighestTagSoFar ReminderTags global HighestTagSoFar
if {[catch { set f [open $fname "r"]}]} { if {[catch { set f [open $fname "r"]}]} {
return return
} }
@@ -2970,7 +3013,6 @@ proc ScanForTags { fname } {
if {$tagno > $HighestTagSoFar} { if {$tagno > $HighestTagSoFar} {
set HighestTagSoFar $tagno set HighestTagSoFar $tagno
} }
set ReminderTags($tagno) 1
} }
} }
} }
@@ -3286,6 +3328,12 @@ proc ReadTaggedOptions { tag date } {
} }
return $ans return $ans
} }
# Make a string safe for passing to shell.
proc posix_escape { str } {
return [string cat "'" [string map [list {'} {'\''}] $str] "'"]
}
proc FireEditor { w {fntag ""}} { proc FireEditor { w {fntag ""}} {
global Option global Option
global EditorPid global EditorPid
@@ -3301,7 +3349,7 @@ proc FireEditor { w {fntag ""}} {
return return
} }
set editor $Option(Editor) set editor $Option(Editor)
regsub -all "%s" $editor $file editor regsub -all "%s" $editor [posix_escape $file] editor
regsub -all "%d" $editor $line editor regsub -all "%d" $editor $line editor
# Don't fire up a second editor if first is running # Don't fire up a second editor if first is running
@@ -3457,7 +3505,7 @@ proc EditTaggedReminder { w } {
} }
set problem [catch {set rem [CreateReminder .mod]} err] set problem [catch {set rem [CreateReminder .mod]} err]
if {$problem} { if {$problem} {
tk_dialog .error Error "$err" error 0 Ok show_error "$err"
continue continue
} }
if {$ModifyDialogResult == 4} { if {$ModifyDialogResult == 4} {
@@ -3477,7 +3525,7 @@ proc EditTaggedReminder { w } {
} }
} err] } err]
if {$problem} { if {$problem} {
tk_dialog .error Error "Error: $err" error 0 Ok show_error $err
return 1 return 1
} }
@@ -3540,7 +3588,7 @@ proc UniqueFileName { stem } {
#*********************************************************************** #***********************************************************************
proc DeleteTaggedReminder { tag } { proc DeleteTaggedReminder { tag } {
global AppendFile global AppendFile
global HighestTagSoFar global HighestTagSoFar Ignore
set tmpfile [UniqueFileName $AppendFile] set tmpfile [UniqueFileName $AppendFile]
set out [open $tmpfile "w"] set out [open $tmpfile "w"]
@@ -3549,12 +3597,14 @@ proc DeleteTaggedReminder { tag } {
set found 0 set found 0
set tagno 0 set tktag [extract_tktag $tag]
set syntag [extract_syntag $tag]
set h 0
while {[gets $in line] >= 0} { while {[gets $in line] >= 0} {
if {[is_warning_header $line]} { if {[is_warning_header $line]} {
continue continue
} }
if {[string match "REM TAG $tag *" $line]} { if {[string match "REM TAG $tktag *" $line]} {
set found 1 set found 1
continue continue
} }
@@ -3569,13 +3619,12 @@ proc DeleteTaggedReminder { tag } {
continue continue
} }
# Renumber tags if {[regexp {^REM TAG TKTAG([0-9]+)} $line all tagno]} {
if {[regexp {^REM TAG TKTAG([0-9]+) (.*)$} $line all oldtag rest]} { if {$tagno > $h} {
incr tagno set h $tagno
puts $out "REM TAG TKTAG$tagno $rest" }
} else { }
puts $out $line puts $out $line
}
} }
if {! $found } { if {! $found } {
@@ -3585,9 +3634,13 @@ proc DeleteTaggedReminder { tag } {
error "Did not find reminder with tag $tag" error "Did not find reminder with tag $tag"
} }
set HighestTagSoFar $tagno if {$syntag != "*"} {
catch { unset Ignore($syntag) }
}
close $in close $in
close $out close $out
set HighestTagSoFar $h
file rename -force -- $tmpfile $AppendFile file rename -force -- $tmpfile $AppendFile
} }
@@ -3846,6 +3899,10 @@ proc CreateMoonWindows {} {
#*********************************************************************** #***********************************************************************
proc DisplayTimeContinuously {} { proc DisplayTimeContinuously {} {
DisplayTime DisplayTime
# Reap any zombies
eval { exec true }
set secs [clock format [clock seconds] -format "%S"] set secs [clock format [clock seconds] -format "%S"]
# Doh -- don't interpret as an octal number if leading zero # Doh -- don't interpret as an octal number if leading zero
scan $secs "%d" decSecs scan $secs "%d" decSecs
@@ -3920,8 +3977,8 @@ proc ShowTodaysReminders {} {
# Prompts for confirmation; then deletes reminder # Prompts for confirmation; then deletes reminder
#*********************************************************************** #***********************************************************************
proc InteractiveDeleteReminder { tag } { proc InteractiveDeleteReminder { tag } {
set ans [tk_dialog .error "Really Delete" "Really delete reminder?" warning 0 No Yes] set ans [tk_messageBox -message "Really Delete" -detail "Really delete reminder?" -icon question -type yesno]
if {$ans == 1} { if {$ans == yes} {
DeleteTaggedReminder $tag DeleteTaggedReminder $tag
ScheduleUpdateForChanges ScheduleUpdateForChanges
} }
@@ -3943,8 +4000,8 @@ proc SendMail { recipient subject body } {
} }
} }
proc ClosePopup { w after_token mail_addr close_win ignore_or_kill tag reminder rem_time } { proc ClosePopup { w after_token mail_addr close_win ignore_or_kill tag reminder rem_time qid } {
global Ignore global DaemonFile Ignore
if {"$after_token" != ""} { if {"$after_token" != ""} {
catch { after cancel $after_token } catch { after cancel $after_token }
} }
@@ -3957,10 +4014,20 @@ proc ClosePopup { w after_token mail_addr close_win ignore_or_kill tag reminder
SendMail $mail_addr "Reminder for $rem_time" "Hello,\n\nThe following reminder is scheduled for $rem_time:\n\n$reminder\nRegards,\n\nTkRemind\n" SendMail $mail_addr "Reminder for $rem_time" "Hello,\n\nThe following reminder is scheduled for $rem_time:\n\n$reminder\nRegards,\n\nTkRemind\n"
} }
if {"$ignore_or_kill" == "ignore"} { if {"$ignore_or_kill" == "ignore"} {
set Ignore($tag) 1 if {$qid != "*"} {
set syntag [extract_syntag $tag]
if {$syntag != "*"} {
set Ignore($syntag) 1
}
puts $DaemonFile "DEL $qid"
flush $DaemonFile
}
} }
if {"$ignore_or_kill" == "kill"} { if {"$ignore_or_kill" == "kill"} {
InteractiveDeleteReminder $tag set tktag [extract_tktag $tag]
if {$tktag != "*"} {
InteractiveDeleteReminder $tag
}
} }
} }
@@ -4210,12 +4277,13 @@ proc update_color_buttons { w } {
} }
proc set_button_to_queue {} { proc set_button_to_queue {} {
global Option
balloon_set_help .b.queue "See the queue of pending reminders (debugging purposes only)" balloon_set_help .b.queue "See the queue of pending reminders (debugging purposes only)"
.b.queue configure -text {Queue...} -command {DoQueue} .b.queue configure -text {Queue...} -command {DoQueue} -foreground $Option(LabelColor) -background $Option(WinBackground)
} }
proc set_button_to_errors {} { proc set_button_to_errors {} {
balloon_set_help .b.queue "See the list of errors from the most recent operation" balloon_set_help .b.queue "See the list of errors from the most recent operation"
.b.queue configure -text {Errors...} -command {ShowErrors} .b.queue configure -text {Errors...} -command {ShowErrors} -bg #FF5555 -fg black
} }
proc ShowErrors {} { proc ShowErrors {} {
@@ -4233,7 +4301,25 @@ proc ShowErrors {} {
grid columnconfigure $w 1 -weight 0 grid columnconfigure $w 1 -weight 0
grid rowconfigure $w 0 -weight 1 grid rowconfigure $w 0 -weight 1
grid rowconfigure $w 1 -weight 0 grid rowconfigure $w 1 -weight 0
$w.t insert end $RemindErrors set l [split $RemindErrors "\n"]
set i 0
foreach line $l {
if {[regexp {^(.*)\(([0-9]+)\)} $line dummy fname lineno]} {
incr i
set fntag [string cat "FILE_" $lineno "_" $fname]
$w.t insert end $line [list ERR "ERR$i" $fntag]
$w.t tag bind "ERR$i" <ButtonPress-1> [list FireEditor $w.t $fntag]
$w.t tag bind "ERR$i" <ButtonPress-3> [list FireEditor $w.t $fntag]
$w.t tag bind "ERR$i" <Enter> "$w.t tag configure ERR$i -underline 1"
$w.t tag bind "ERR$i" <Leave> "$w.t tag configure ERR$i -underline 0"
} else {
$w.t insert end $line
}
$w.t insert end "\n"
}
if {$i > 0} {
$w.t insert end "\nIf an error message is underlined when you hover over it, click button-1 to edit the offending file at the line number of the error.\n"
}
$w.t configure -state disabled $w.t configure -state disabled
CenterWindow $w . CenterWindow $w .
} }

View File

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

View File

@@ -1041,7 +1041,7 @@ static void DoCalendarOneMonth(void)
printf("\"entries\":[\n"); printf("\"entries\":[\n");
} }
} }
while (WriteCalendarRow()) continue; while (WriteCalendarRow()) /* continue */;
if (PsCal == PSCAL_LEVEL1) { if (PsCal == PSCAL_LEVEL1) {
printf("%s\n", PSEND); printf("%s\n", PSEND);
@@ -1770,7 +1770,7 @@ static int DoCalRem(ParsePtr p, int col)
DBufInit(&raw_buf); DBufInit(&raw_buf);
/* Parse the trigger date and time */ /* Parse the trigger date and time */
if ( (r=ParseRem(p, &trig, &tim, 1)) ) { if ( (r=ParseRem(p, &trig, &tim)) ) {
FreeTrig(&trig); FreeTrig(&trig);
return r; return r;
} }

View File

@@ -24,27 +24,46 @@ if (!$ARGV[0]) {
} }
my $lang = $ARGV[0]; my $lang = $ARGV[0];
if (!exists($language_map->{$lang})) { my $rc = 0;
print STDERR "$lang is not a valid language.\n"; if ($lang eq 'all') {
exit(1); foreach my $l (sort(keys(%$language_map))) {
} if (check($l)) {
$rc = 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 -j6 all LANGDEF=-DLANG=$flag > /dev/null 2>&1") && die("make all failed");
my_sys("./remind -q -r ../tests/tstlang.rem 2022-03-23 11:44 > test-$lang-compiled.out 2>&1");
my_sys("make clean > /dev/null 2>&1") && die("make clean failed");
my_sys("make -j6 all > /dev/null 2>&1") && die("make all failed");
my_sys("./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 { } else {
print STDERR "Whoops. Compiled and runtime language output differs for $lang.\n" $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); exit(0);
sub my_sys sub my_sys

View File

@@ -1,9 +1,3 @@
/* Define if utime(file, NULL) sets file's timestamp to the present. */
#undef HAVE_UTIME_NULL
/* Define if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Define if your <sys/time.h> declares struct tm. */ /* Define if your <sys/time.h> declares struct tm. */
#undef TM_IN_SYS_TIME #undef TM_IN_SYS_TIME
@@ -16,6 +10,15 @@
/* Define if you have the <glob.h> header file */ /* Define if you have the <glob.h> header file */
#undef HAVE_GLOB_H #undef HAVE_GLOB_H
/* Define if you have <stdint.h> */
#undef HAVE_STDINT_H
#undef HAVE_STRINGS_H
#undef HAVE_STRDUP
#undef HAVE_STRCASECMP
#undef HAVE_STRNCASECMP
#undef HAVE_WCTYPE_H #undef HAVE_WCTYPE_H
#undef HAVE_LOCALE_H #undef HAVE_LOCALE_H
@@ -42,4 +45,8 @@
/* The number of bytes in a unsigned long. */ /* The number of bytes in a unsigned long. */
#undef SIZEOF_UNSIGNED_LONG #undef SIZEOF_UNSIGNED_LONG
#define PACKAGE_NAME "@PACKAGE_NAME@"
#define PACKAGE_URL "@PACKAGE_URL@"
#include "custom.h" #include "custom.h"

View File

@@ -117,7 +117,7 @@
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
/* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */ /* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
#define VAL_STACK_SIZE 1000 #define VAL_STACK_SIZE 100
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */ /* INCLUDE_NEST: How many nested INCLUDES do we handle? */

View File

@@ -117,7 +117,7 @@
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
/* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */ /* VAL_STACK_SIZE: The size of the operand stack for expr. parsing */
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
#define VAL_STACK_SIZE 1000 #define VAL_STACK_SIZE 100
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
/* INCLUDE_NEST: How many nested INCLUDES do we handle? */ /* INCLUDE_NEST: How many nested INCLUDES do we handle? */

View File

@@ -25,7 +25,7 @@
#include "protos.h" #include "protos.h"
#include "expr.h" #include "expr.h"
static int ParseTimeTrig (ParsePtr s, TimeTrig *tim, int save_in_globals); static int ParseTimeTrig (ParsePtr s, TimeTrig *tim);
static int ParseLocalOmit (ParsePtr s, Trigger *t); static int ParseLocalOmit (ParsePtr s, Trigger *t);
static int ParseScanFrom (ParsePtr s, Trigger *t, int type); static int ParseScanFrom (ParsePtr s, Trigger *t, int type);
static int ParsePriority (ParsePtr s, Trigger *t); static int ParsePriority (ParsePtr s, Trigger *t);
@@ -63,7 +63,7 @@ int DoRem(ParsePtr p)
DBufInit(&buf); DBufInit(&buf);
/* Parse the trigger date and time */ /* Parse the trigger date and time */
if ( (r=ParseRem(p, &trig, &tim, 1)) ) { if ( (r=ParseRem(p, &trig, &tim)) ) {
FreeTrig(&trig); FreeTrig(&trig);
return r; return r;
} }
@@ -220,7 +220,7 @@ int DoRem(ParsePtr p)
/* trigger structure. */ /* trigger structure. */
/* */ /* */
/***************************************************************/ /***************************************************************/
int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals) int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
{ {
register int r; register int r;
DynamicBuffer buf; DynamicBuffer buf;
@@ -262,10 +262,6 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
trig->need_wkday = 0; trig->need_wkday = 0;
trig->adj_for_last = 0; trig->adj_for_last = 0;
if (save_in_globals) {
LastTriggerTime = NO_TIME;
}
int parsing = 1; int parsing = 1;
while(parsing) { while(parsing) {
/* Read space-delimited string */ /* Read space-delimited string */
@@ -315,10 +311,6 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
trig->m = m; trig->m = m;
trig->d = d; trig->d = d;
tim->ttime = (tok.val % MINUTES_PER_DAY); tim->ttime = (tok.val % MINUTES_PER_DAY);
if (save_in_globals) {
LastTriggerTime = tim->ttime;
SaveLastTimeTrig(tim);
}
break; break;
case T_WkDay: case T_WkDay:
@@ -355,14 +347,14 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
DBufFree(&buf); DBufFree(&buf);
if (tim->ttime != NO_TIME) return E_TIME_TWICE; if (tim->ttime != NO_TIME) return E_TIME_TWICE;
tim->ttime = tok.val; tim->ttime = tok.val;
r = ParseTimeTrig(s, tim, save_in_globals); r = ParseTimeTrig(s, tim);
if (r) return r; if (r) return r;
trig->duration_days = ComputeTrigDuration(tim); trig->duration_days = ComputeTrigDuration(tim);
break; break;
case T_At: case T_At:
DBufFree(&buf); DBufFree(&buf);
r=ParseTimeTrig(s, tim, save_in_globals); r=ParseTimeTrig(s, tim);
if (r) return r; if (r) return r;
trig->duration_days = ComputeTrigDuration(tim); trig->duration_days = ComputeTrigDuration(tim);
break; break;
@@ -522,9 +514,6 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
} else { } else {
tim->duration = NO_TIME; tim->duration = NO_TIME;
} }
if (save_in_globals) {
SaveLastTimeTrig(tim);
}
trig->duration_days = ComputeTrigDuration(tim); trig->duration_days = ComputeTrigDuration(tim);
break; break;
default: default:
@@ -608,7 +597,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
/* ParseTimeTrig - parse the AT part of a timed reminder */ /* ParseTimeTrig - parse the AT part of a timed reminder */
/* */ /* */
/***************************************************************/ /***************************************************************/
static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals) static int ParseTimeTrig(ParsePtr s, TimeTrig *tim)
{ {
Token tok; Token tok;
int r; int r;
@@ -643,11 +632,6 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim, int save_in_globals)
default: default:
if (tim->ttime == NO_TIME) return E_EXPECT_TIME; if (tim->ttime == NO_TIME) return E_EXPECT_TIME;
/* Save trigger time in global variable */
if (save_in_globals) {
LastTriggerTime = tim->ttime;
SaveLastTimeTrig(tim);
}
PushToken(DBufValue(&buf), s); PushToken(DBufValue(&buf), s);
DBufFree(&buf); DBufFree(&buf);
return OK; return OK;
@@ -679,6 +663,9 @@ static int ParseLocalOmit(ParsePtr s, Trigger *t)
break; break;
default: default:
if (t->localomit == NO_WD) {
return E_EXPECTING_WEEKDAY;
}
PushToken(DBufValue(&buf), s); PushToken(DBufValue(&buf), s);
DBufFree(&buf); DBufFree(&buf);
return OK; return OK;

View File

@@ -50,7 +50,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
int err, done; int err, done;
int c; int c;
int d, m, y; int d, m, y;
int tim = tt->ttime; int tim = NO_TIME;
int h, min, hh, ch, cmin, chh; int h, min, hh, ch, cmin, chh;
int i; int i;
char const *pm, *cpm; char const *pm, *cpm;
@@ -72,6 +72,9 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
FromDSE(dse, &y, &m, &d); FromDSE(dse, &y, &m, &d);
if (tt) {
tim = tt->ttime;
}
if (tim == NO_TIME) tim = curtime; if (tim == NO_TIME) tim = curtime;
tdiff = tim - curtime; tdiff = tim - curtime;
adiff = ABS(tdiff); adiff = ABS(tdiff);

View File

@@ -121,6 +121,8 @@
#define E_STRING_TOO_LONG 101 #define E_STRING_TOO_LONG 101
#define E_TIME_TWICE 102 #define E_TIME_TWICE 102
#define E_DURATION_NO_AT 103 #define E_DURATION_NO_AT 103
#define E_EXPECTING_WEEKDAY 104
#ifdef MK_GLOBALS #ifdef MK_GLOBALS
#undef EXTERN #undef EXTERN
#define EXTERN #define EXTERN
@@ -241,7 +243,8 @@ EXTERN char *ErrMsg[]
"No files matching *.rem", "No files matching *.rem",
"String too long", "String too long",
"Time specified twice", "Time specified twice",
"Cannot specify DURATION without specifying AT" "Cannot specify DURATION without specifying AT",
"Expecting weekday name"
} }
#endif /* MK_GLOBALS */ #endif /* MK_GLOBALS */
; ;

View File

@@ -87,10 +87,11 @@ extern BuiltinFunc Func[];
static Operator OpStack[OP_STACK_SIZE]; static Operator OpStack[OP_STACK_SIZE];
static int OpStackPtr = 0; static int OpStackPtr = 0;
static int OpStackHiWater = 0;
/* ValStack can't be static - needed by funcs.c */ /* ValStack can't be static - needed by funcs.c */
Value ValStack[VAL_STACK_SIZE]; Value ValStack[VAL_STACK_SIZE];
int ValStackPtr = 0; int ValStackPtr = 0;
int ValStackHiWater = 0;
/***************************************************************/ /***************************************************************/
/* */ /* */
@@ -1485,3 +1486,11 @@ int FnPopValStack(Value *val)
return OK; return OK;
} }
} }
void DebugExitFunc(void)
{
if (DebugFlag & DB_EXPR_STACKS) {
fprintf(stderr, "Operator stack high water: %d\n", OpStackHiWater);
fprintf(stderr, " Value stack high water: %d\n", ValStackHiWater);
}
}

View File

@@ -33,10 +33,8 @@
for speed. BEWARE: These macros invoke return if an error happens ! */ for speed. BEWARE: These macros invoke return if an error happens ! */
#define PushOpStack(op) \ #define PushOpStack(op) \
if (OpStackPtr >= OP_STACK_SIZE) \ do { if (OpStackPtr >= OP_STACK_SIZE) return E_OP_STK_OVER; \
return E_OP_STK_OVER; \ else { OpStack[OpStackPtr++] = (op); if (OpStackPtr > OpStackHiWater) OpStackHiWater = OpStackPtr; } } while(0)
else \
OpStack[OpStackPtr++] = (op)
#define PopOpStack(op) \ #define PopOpStack(op) \
if (OpStackPtr <= 0) \ if (OpStackPtr <= 0) \
@@ -45,10 +43,13 @@ else \
(op) = OpStack[--OpStackPtr] (op) = OpStack[--OpStackPtr]
#define PushValStack(val) \ #define PushValStack(val) \
if (ValStackPtr >= VAL_STACK_SIZE) \ do { if (ValStackPtr >= VAL_STACK_SIZE) { \
return E_VA_STK_OVER; \ DestroyValue(val); \
else \ return E_VA_STK_OVER; \
ValStack[ValStackPtr++] = (val) } else { \
ValStack[ValStackPtr++] = (val); \
if (ValStackPtr > ValStackHiWater) ValStackHiWater = ValStackPtr; \
} } while (0);
#define PopValStack(val) \ #define PopValStack(val) \
if (ValStackPtr <= 0) \ if (ValStackPtr <= 0) \

View File

@@ -42,8 +42,8 @@
/* Convenient macros for closing files */ /* Convenient macros for closing files */
#define FCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL)) #define FCLOSE(fp) ((((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL))
#define PCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (pclose(fp),(fp)=NULL) : ((fp)=NULL)) #define PCLOSE(fp) ((((fp)!=stdin)) ? (pclose(fp),(fp)=NULL) : ((fp)=NULL))
/* Define the structures needed by the file caching system */ /* Define the structures needed by the file caching system */
typedef struct cache { typedef struct cache {
@@ -101,13 +101,17 @@ static int CheckSafetyAux (struct stat *statbuf);
static int PopFile (void); static int PopFile (void);
static int IncludeCmd(char const *); static int IncludeCmd(char const *);
void set_cloexec(int fd) void set_cloexec(FILE *fp)
{ {
int flags; int flags;
flags = fcntl(fd, F_GETFD); int fd;
if (flags >= 0) { if (fp) {
flags |= FD_CLOEXEC; fd = fileno(fp);
fcntl(fd, F_SETFD, flags); flags = fcntl(fd, F_GETFD);
if (flags >= 0) {
flags |= FD_CLOEXEC;
fcntl(fd, F_SETFD, flags);
}
} }
} }
@@ -135,7 +139,7 @@ static void OpenPurgeFile(char const *fname, char const *mode)
if (!PurgeFP) { if (!PurgeFP) {
fprintf(ErrFp, "Cannot open `%s' for writing: %s\n", DBufValue(&fname_buf), strerror(errno)); fprintf(ErrFp, "Cannot open `%s' for writing: %s\n", DBufValue(&fname_buf), strerror(errno));
} }
set_cloexec(fileno(PurgeFP)); set_cloexec(PurgeFP);
DBufFree(&fname_buf); DBufFree(&fname_buf);
} }
@@ -340,7 +344,7 @@ int OpenFile(char const *fname)
} }
} else { } else {
fp = fopen(fname, "r"); fp = fopen(fname, "r");
if (fp) set_cloexec(fileno(fp)); set_cloexec(fp);
if (DebugFlag & DB_TRACE_FILES) { if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Reading `%s': Opening file on disk\n", fname); fprintf(ErrFp, "Reading `%s': Opening file on disk\n", fname);
} }
@@ -360,7 +364,7 @@ int OpenFile(char const *fname)
if (strcmp(fname, "-")) { if (strcmp(fname, "-")) {
fp = fopen(fname, "r"); fp = fopen(fname, "r");
if (!fp || !CheckSafety()) return E_CANT_OPEN; if (!fp || !CheckSafety()) return E_CANT_OPEN;
set_cloexec(fileno(fp)); set_cloexec(fp);
if (PurgeMode) OpenPurgeFile(fname, "w"); if (PurgeMode) OpenPurgeFile(fname, "w");
} else { } else {
fp = stdin; fp = stdin;
@@ -557,7 +561,7 @@ static int PopFile(void)
if (strcmp(i->filename, "-")) { if (strcmp(i->filename, "-")) {
fp = fopen(i->filename, "r"); fp = fopen(i->filename, "r");
if (!fp || !CheckSafety()) return E_CANT_OPEN; if (!fp || !CheckSafety()) return E_CANT_OPEN;
set_cloexec(fileno(fp)); set_cloexec(fp);
if (PurgeMode) OpenPurgeFile(i->filename, "a"); if (PurgeMode) OpenPurgeFile(i->filename, "a");
} else { } else {
fp = stdin; fp = stdin;

View File

@@ -10,7 +10,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* */ /* */
/***************************************************************/ /***************************************************************/
#include "version.h" #include "version.h"
#include "config.h" #include "config.h"
@@ -24,6 +23,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@@ -66,8 +70,6 @@ static int FAbs (func_info *);
static int FAccess (func_info *); static int FAccess (func_info *);
static int FAmpm (func_info *); static int FAmpm (func_info *);
static int FAnsicolor (func_info *); static int FAnsicolor (func_info *);
static int FTrig (func_info *);
static int FIsAny (func_info *);
static int FArgs (func_info *); static int FArgs (func_info *);
static int FAsc (func_info *); static int FAsc (func_info *);
static int FBaseyr (func_info *); static int FBaseyr (func_info *);
@@ -101,6 +103,7 @@ static int FHtmlEscape (func_info *);
static int FHtmlStriptags (func_info *); static int FHtmlStriptags (func_info *);
static int FIif (func_info *); static int FIif (func_info *);
static int FIndex (func_info *); static int FIndex (func_info *);
static int FIsAny (func_info *);
static int FIsdst (func_info *); static int FIsdst (func_info *);
static int FIsleap (func_info *); static int FIsleap (func_info *);
static int FIsomitted (func_info *); static int FIsomitted (func_info *);
@@ -117,6 +120,7 @@ static int FMoondate (func_info *);
static int FMoondatetime (func_info *); static int FMoondatetime (func_info *);
static int FMoonphase (func_info *); static int FMoonphase (func_info *);
static int FMoontime (func_info *); static int FMoontime (func_info *);
static int FMultiTrig (func_info *);
static int FNDawn (func_info *); static int FNDawn (func_info *);
static int FNDusk (func_info *); static int FNDusk (func_info *);
static int FNonomitted (func_info *); static int FNonomitted (func_info *);
@@ -134,6 +138,7 @@ static int FRealtoday (func_info *);
static int FRows (func_info *); static int FRows (func_info *);
static int FSgn (func_info *); static int FSgn (func_info *);
static int FShell (func_info *); static int FShell (func_info *);
static int FShellescape (func_info *);
static int FSlide (func_info *); static int FSlide (func_info *);
static int FSoleq (func_info *); static int FSoleq (func_info *);
static int FStdout (func_info *); static int FStdout (func_info *);
@@ -156,9 +161,9 @@ static int FTrigeventstart (func_info *);
static int FTrigfrom (func_info *); static int FTrigfrom (func_info *);
static int FTrigger (func_info *); static int FTrigger (func_info *);
static int FTrigpriority (func_info *); static int FTrigpriority (func_info *);
static int FTrigtags (func_info *);
static int FTrigrep (func_info *); static int FTrigrep (func_info *);
static int FTrigscanfrom (func_info *); static int FTrigscanfrom (func_info *);
static int FTrigtags (func_info *);
static int FTrigtime (func_info *); static int FTrigtime (func_info *);
static int FTrigtimedelta (func_info *); static int FTrigtimedelta (func_info *);
static int FTrigtimerep (func_info *); static int FTrigtimerep (func_info *);
@@ -166,15 +171,14 @@ static int FTriguntil (func_info *);
static int FTrigvalid (func_info *); static int FTrigvalid (func_info *);
static int FTypeof (func_info *); static int FTypeof (func_info *);
static int FTzconvert (func_info *); static int FTzconvert (func_info *);
static int FUpper (func_info *);
static int FUTCToLocal (func_info *); static int FUTCToLocal (func_info *);
static int FUpper (func_info *);
static int FValue (func_info *); static int FValue (func_info *);
static int FVersion (func_info *); static int FVersion (func_info *);
static int FWeekno (func_info *); static int FWeekno (func_info *);
static int FWkday (func_info *); static int FWkday (func_info *);
static int FWkdaynum (func_info *); static int FWkdaynum (func_info *);
static int FYear (func_info *); static int FYear (func_info *);
static int FShellescape (func_info *);
static int CleanUpAfterFunc (func_info *); static int CleanUpAfterFunc (func_info *);
static int CheckArgs (BuiltinFunc *f, int nargs); static int CheckArgs (BuiltinFunc *f, int nargs);
@@ -195,6 +199,7 @@ static int CacheHebYear, CacheHebMon, CacheHebDay;
/* We need access to the value stack */ /* We need access to the value stack */
extern Value ValStack[]; extern Value ValStack[];
extern int ValStackPtr; extern int ValStackPtr;
extern int ValStackHiWater;
/* Macro for accessing arguments from the value stack - args are numbered /* Macro for accessing arguments from the value stack - args are numbered
from 0 to (Nargs - 1) */ from 0 to (Nargs - 1) */
@@ -284,6 +289,7 @@ BuiltinFunc Func[] = {
{ "moondatetime", 1, 3, 0, FMoondatetime }, { "moondatetime", 1, 3, 0, FMoondatetime },
{ "moonphase", 0, 2, 0, FMoonphase }, { "moonphase", 0, 2, 0, FMoonphase },
{ "moontime", 1, 3, 0, FMoontime }, { "moontime", 1, 3, 0, FMoontime },
{ "multitrig", 1, NO_MAX, 0, FMultiTrig },
{ "ndawn", 0, 1, 0, FNDawn}, { "ndawn", 0, 1, 0, FNDawn},
{ "ndusk", 0, 1, 0, FNDusk}, { "ndusk", 0, 1, 0, FNDusk},
{ "nonomitted", 2, NO_MAX, 0, FNonomitted }, { "nonomitted", 2, NO_MAX, 0, FNonomitted },
@@ -1107,8 +1113,11 @@ static int FOrd(func_info *info)
ASSERT_TYPE(0, INT_TYPE); ASSERT_TYPE(0, INT_TYPE);
v = ARGV(0); v = ARGV(0);
t = v % 100; if (v < 0) {
if (t < 0) t = -t; t = (-v) % 100;
} else {
t = v % 100;
}
u = t % 10; u = t % 10;
s = "th"; s = "th";
if (u == 1 && t != 11) s = "st"; if (u == 1 && t != 11) s = "st";
@@ -2574,6 +2583,10 @@ static int UTCToLocalHelper(int datetime, int *ret)
min = (datetime % MINUTES_PER_DAY) % 60; min = (datetime % MINUTES_PER_DAY) % 60;
old_tz = getenv("TZ"); old_tz = getenv("TZ");
if (old_tz) {
old_tz = StrDup(old_tz);
if (!old_tz) return E_NO_MEM;
}
tz_set_tz("UTC"); tz_set_tz("UTC");
@@ -2587,6 +2600,9 @@ static int UTCToLocalHelper(int datetime, int *ret)
utc.tm_isdst = 0; utc.tm_isdst = 0;
utc_t = mktime(&utc); utc_t = mktime(&utc);
tz_set_tz(old_tz); tz_set_tz(old_tz);
if (old_tz) {
free( (void *) old_tz);
}
if (utc_t == -1) { if (utc_t == -1) {
return E_MKTIME_PROBLEM; return E_MKTIME_PROBLEM;
@@ -3221,6 +3237,10 @@ static int tz_convert(int year, int month, int day,
/* backup old TZ env var */ /* backup old TZ env var */
old_tz = getenv("TZ"); old_tz = getenv("TZ");
if (old_tz) {
old_tz = StrDup(old_tz);
if (!old_tz) return E_NO_MEM;
}
if (tgt_tz == NULL) { if (tgt_tz == NULL) {
tgt_tz = old_tz; tgt_tz = old_tz;
} }
@@ -3228,6 +3248,8 @@ static int tz_convert(int year, int month, int day,
/* set source TZ */ /* set source TZ */
r = tz_set_tz(src_tz); r = tz_set_tz(src_tz);
if (r == -1) { if (r == -1) {
tz_set_tz(old_tz);
if (old_tz) free((void *) old_tz);
return -1; return -1;
} }
@@ -3235,14 +3257,16 @@ static int tz_convert(int year, int month, int day,
t = mktime(tm); t = mktime(tm);
if (t == (time_t) -1) { if (t == (time_t) -1) {
tz_set_tz(old_tz); tz_set_tz(old_tz);
if (old_tz) free((void *) old_tz);
return -1; return -1;
} }
/* set target TZ */ /* set target TZ */
r = tz_set_tz(tgt_tz); r = tz_set_tz(tgt_tz);
if (r == -1) { if (r == -1) {
tz_set_tz(old_tz); tz_set_tz(old_tz);
if (old_tz) free((void *) old_tz);
return -1; return -1;
} }
@@ -3251,6 +3275,7 @@ static int tz_convert(int year, int month, int day,
/* restore old TZ */ /* restore old TZ */
tz_set_tz(old_tz); tz_set_tz(old_tz);
if (old_tz) free((void *) old_tz);
/* return result */ /* return result */
if (res == NULL) { if (res == NULL) {
@@ -3481,7 +3506,7 @@ FEvalTrig(func_info *info)
CreateParser(ARGSTR(0), &p); CreateParser(ARGSTR(0), &p);
p.allownested = 0; p.allownested = 0;
r = ParseRem(&p, &trig, &tim, 0); r = ParseRem(&p, &trig, &tim);
if (r) { if (r) {
DestroyParser(&p); DestroyParser(&p);
return r; return r;
@@ -3520,6 +3545,57 @@ FEvalTrig(func_info *info)
return OK; return OK;
} }
static int
FMultiTrig(func_info *info)
{
Parser p;
Trigger trig;
TimeTrig tim;
int dse;
int r;
int i;
int earliest = -1;
RetVal.type = DATE_TYPE;
RETVAL = 0;
for (i=0; i<Nargs; i++) {
ASSERT_TYPE(i, STR_TYPE);
}
for (i=0; i<Nargs; i++) {
CreateParser(ARGSTR(i), &p);
p.allownested = 0;
r = ParseRem(&p, &trig, &tim);
if (r) {
DestroyParser(&p);
return r;
}
if (trig.typ != NO_TYPE) {
DestroyParser(&p);
FreeTrig(&trig);
return E_PARSE_ERR;
}
if (tim.ttime != NO_TIME) {
Eprint("Cannot use AT clause in multitrig() function");
return E_PARSE_ERR;
}
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
DestroyParser(&p);
if (r != E_CANT_TRIG) {
if (dse < earliest || earliest < 0) {
earliest = dse;
}
}
FreeTrig(&trig);
}
if (earliest >= 0) {
RETVAL = earliest;
}
return OK;
}
static int LastTrig = 0; static int LastTrig = 0;
static int static int
FTrig(func_info *info) FTrig(func_info *info)
@@ -3546,7 +3622,7 @@ FTrig(func_info *info)
for (i=0; i<Nargs; i++) { for (i=0; i<Nargs; i++) {
CreateParser(ARGSTR(i), &p); CreateParser(ARGSTR(i), &p);
p.allownested = 0; p.allownested = 0;
r = ParseRem(&p, &trig, &tim, 0); r = ParseRem(&p, &trig, &tim);
if (r) { if (r) {
DestroyParser(&p); DestroyParser(&p);
return r; return r;
@@ -3557,20 +3633,18 @@ FTrig(func_info *info)
return E_PARSE_ERR; return E_PARSE_ERR;
} }
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0); dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 0);
DestroyParser(&p);
if (r == E_CANT_TRIG) { if (r == E_CANT_TRIG) {
DestroyParser(&p);
FreeTrig(&trig); FreeTrig(&trig);
continue; continue;
} }
if (ShouldTriggerReminder(&trig, &tim, dse, &r)) { if (ShouldTriggerReminder(&trig, &tim, dse, &r)) {
LastTrig = dse; LastTrig = dse;
RETVAL = dse; RETVAL = dse;
DestroyParser(&p);
FreeTrig(&trig); FreeTrig(&trig);
return OK; return OK;
} }
DestroyParser(&p);
FreeTrig(&trig); FreeTrig(&trig);
} }
return OK; return OK;
@@ -3683,11 +3757,8 @@ mean_december_solstice(double y)
} }
/* Cosine of an angle specified in degrees */ /* Cosine of an angle specified in degrees */
static double #define PI_BY_180 0.01745329251994329576923690768
cosd(double degrees) #define cosd(theta) cos( (theta) * PI_BY_180)
{
return cos((degrees / 180.0) * 3.14159265358979);
}
/* Astronomical Algorithms by Meeus, p. 179 /* Astronomical Algorithms by Meeus, p. 179
These weird periodic components refine the mean solstice/equinox dates These weird periodic components refine the mean solstice/equinox dates

View File

@@ -39,7 +39,7 @@ EXTERN FILE *ErrFp;
#define IsLeapYear(y) (((y) % 4) ? 0 : ((!((y) % 100) && ((y) % 400)) ? 0 : 1 )) #define IsLeapYear(y) (((y) % 4) ? 0 : ((!((y) % 100) && ((y) % 400)) ? 0 : 1 ))
#define DaysInMonth(m, y) ((m) != 1 ? MonthDays[m] : 28 + IsLeapYear(y)) #define DaysInMonth(m, y) ((m) != 1 ? MonthDays[m] : 28 + IsLeapYear(y))
#define DestroyValue(x) (void) (((x).type == STR_TYPE && (x).v.str) ? (free((x).v.str),(x).v.str = NULL,(x).type = ERR_TYPE) : 0) #define DestroyValue(x) do { if ((x).type == STR_TYPE && (x).v.str) { free((x).v.str); (x).v.str = NULL; } (x).type = ERR_TYPE; } while (0)
EXTERN int DSEToday; EXTERN int DSEToday;
EXTERN int RealToday; EXTERN int RealToday;
@@ -114,7 +114,7 @@ EXTERN INIT( int LastTrigValid, 0);
EXTERN Trigger LastTrigger; EXTERN Trigger LastTrigger;
EXTERN TimeTrig LastTimeTrig; EXTERN TimeTrig LastTimeTrig;
EXTERN INIT( int LastTriggerDate, 0); EXTERN INIT( int LastTriggerDate, 0);
EXTERN INIT( int LastTriggerTime, 0); EXTERN INIT( int LastTriggerTime, NO_TIME);
EXTERN INIT( int ShouldCache, 0); EXTERN INIT( int ShouldCache, 0);
EXTERN char const *CurLine; EXTERN char const *CurLine;
EXTERN INIT( int NumTriggered, 0); EXTERN INIT( int NumTriggered, 0);

View File

@@ -20,6 +20,12 @@
#include "protos.h" #include "protos.h"
#include "globals.h" #include "globals.h"
#include "err.h" #include "err.h"
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#define HOUR 1080L #define HOUR 1080L
#define DAY (24L*HOUR) #define DAY (24L*HOUR)
#define WEEK (7L*DAY) #define WEEK (7L*DAY)

View File

@@ -78,6 +78,7 @@ static void ProcessLongOption(char const *arg);
* t = Display trigger dates * t = Display trigger dates
* v = Dump variables at end * v = Dump variables at end
* l = Display entire line in error messages * l = Display entire line in error messages
* s = Display expression-parsing stack usage before exit
* -e = Send messages normally sent to stderr to stdout instead * -e = Send messages normally sent to stderr to stdout instead
* -z[n] = Daemon mode waking up every n (def 1) minutes. * -z[n] = Daemon mode waking up every n (def 1) minutes.
* -bn = Time format for cal (0, 1, or 2) * -bn = Time format for cal (0, 1, or 2)
@@ -604,6 +605,7 @@ void InitRemind(int argc, char const *argv[])
case 'D': case 'D':
while (*arg) { while (*arg) {
switch(*arg++) { switch(*arg++) {
case 's': case 'S': DebugFlag |= DB_EXPR_STACKS; break;
case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break; case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break;
case 'x': case 'X': DebugFlag |= DB_PRTEXPR; break; case 'x': case 'X': DebugFlag |= DB_PRTEXPR; break;
case 't': case 'T': DebugFlag |= DB_PRTTRIG; break; case 't': case 'T': DebugFlag |= DB_PRTTRIG; break;
@@ -804,6 +806,7 @@ void Usage(void)
fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n"); fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n");
fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n"); fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n");
fprintf(ErrFp, " -j[n] Run in 'purge' mode. [n = INCLUDE depth]\n"); fprintf(ErrFp, " -j[n] Run in 'purge' mode. [n = INCLUDE depth]\n");
fprintf(ErrFp, "\nRemind home page: %s\n", PACKAGE_URL);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#endif /* L_USAGE_OVERRIDE */ #endif /* L_USAGE_OVERRIDE */
@@ -1004,7 +1007,7 @@ guess_terminal_background(int *r, int *g, int *b)
{ {
int ttyfd; int ttyfd;
struct pollfd p; struct pollfd p;
int rr, gg, bb; unsigned int rr, gg, bb;
char buf[128]; char buf[128];
int n; int n;
@@ -1070,9 +1073,9 @@ guess_terminal_background(int *r, int *g, int *b)
/* Couldn't scan color codes */ /* Couldn't scan color codes */
return; return;
} }
*r = (rr >> 8) & 255; *r = (int) ((rr >> 8) & 255);
*g = (gg >> 8) & 255; *g = (int) ((gg >> 8) & 255);
*b = (bb >> 8) & 255; *b = (int) ((bb >> 8) & 255);
} }
static struct termios orig_termios; static struct termios orig_termios;

View File

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

View File

@@ -219,7 +219,8 @@ EXTERN char *ErrMsg[] =
"No files matching *.rem", "No files matching *.rem",
"String too long", "String too long",
"Time specified twice", "Time specified twice",
"Cannot specify DURATION without specifying AT" "Cannot specify DURATION without specifying AT",
"Nom du jour de la semaine attendu",
}; };
#endif /* MK_GLOBALS */ #endif /* MK_GLOBALS */
@@ -245,12 +246,10 @@ void Usage(void)
fprintf(ErrFp, " -o Ignorer instructions ONCE\n"); fprintf(ErrFp, " -o Ignorer instructions ONCE\n");
fprintf(ErrFp, " -t Déclencher tous les rappels peu importe le delta\n"); fprintf(ErrFp, " -t Déclencher tous les rappels peu importe le delta\n");
fprintf(ErrFp, " -h Mode silencieux\n"); fprintf(ErrFp, " -h Mode silencieux\n");
#ifdef HAVE_QUEUED
fprintf(ErrFp, " -a Ne pas déclencher les rappels minutés immédiatement - les mettre en file\n"); fprintf(ErrFp, " -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, " -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, " -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, " -z[n] Entrer en mode 'daemon', réveil chaque n (5) minutes\n");
#endif
fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trig v=dumpvars l=showline\n"); fprintf(ErrFp, " -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, " -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, " -b[n] Formats de l'heure pour le calendrier: 0=am/pm, 1=24hr, 2=aucun\n");

View File

@@ -235,7 +235,8 @@ EXTERN char *ErrMsg[] =
"No files matching *.rem", "No files matching *.rem",
"String too long", "String too long",
"Time specified twice", "Time specified twice",
"Cannot specify DURATION without specifying AT" "Cannot specify DURATION without specifying AT",
"Oczekiwana nazwa dnia tygodnia"
}; };
#endif /* MK_GLOBALS */ #endif /* MK_GLOBALS */
@@ -261,12 +262,10 @@ void Usage(void)
fprintf(ErrFp, " -o Ignoruj instrukcje ONCE\n"); fprintf(ErrFp, " -o Ignoruj instrukcje ONCE\n");
fprintf(ErrFp, " -t Odpal wszystkie przyszłe przypomnienia niezależnie od delty\n"); fprintf(ErrFp, " -t Odpal wszystkie przyszłe przypomnienia niezależnie od delty\n");
fprintf(ErrFp, " -h Praca bezszmerowa\n"); fprintf(ErrFp, " -h Praca bezszmerowa\n");
#ifdef HAVE_QUEUED
fprintf(ErrFp, " -a Nie odpalaj przyponień czasowych - kolejkuj je\n"); fprintf(ErrFp, " -a Nie odpalaj przyponień czasowych - kolejkuj je\n");
fprintf(ErrFp, " -q Nie kolejkuj przyponień czasowych\n"); fprintf(ErrFp, " -q Nie kolejkuj przyponień czasowych\n");
fprintf(ErrFp, " -f Nie przechodź do pracy w tle\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, " -z[n] Pracuj jako demon, budząc się co n (5) minut\n");
#endif
fprintf(ErrFp, " -d... Odpluskwianie: e=echo x=expr-eval t=trig v=dumpvars l=showline\n"); fprintf(ErrFp, " -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, " -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, " -b[n] Format czasu: 0=am/pm, 1=24godz., 2=żaden\n");

View File

@@ -244,7 +244,8 @@ EXTERN char *ErrMsg[] =
"No files matching *.rem", "No files matching *.rem",
"String too long", "String too long",
"Time specified twice", "Time specified twice",
"Cannot specify DURATION without specifying AT" "Cannot specify DURATION without specifying AT",
"Esperando nome do dia da semana",
}; };
#endif /* MK_GLOBALS */ #endif /* MK_GLOBALS */
@@ -270,12 +271,10 @@ void Usage(void)
fprintf(ErrFp, " -o Ignora diretivas ONCE\n"); fprintf(ErrFp, " -o Ignora diretivas ONCE\n");
fprintf(ErrFp, " -t Aciona todos os compromissos futuros, sem considerar o delta\n"); fprintf(ErrFp, " -t Aciona todos os compromissos futuros, sem considerar o delta\n");
fprintf(ErrFp, " -h Modo `Hush' - quieto\n"); fprintf(ErrFp, " -h Modo `Hush' - quieto\n");
#ifdef HAVE_QUEUED
fprintf(ErrFp, " -a Nao aciona compromissos com hora imediatamente - apenas coloca na fila\n"); fprintf(ErrFp, " -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, " -q Nao coloca compromissos com hora na fila\n");
fprintf(ErrFp, " -f Aciona compromissos com hora em modo foreground\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, " -z[n] Modo `daemon', acordando a cada n (5) minutos.\n");
#endif
fprintf(ErrFp, " -d... Debug: e=echo x=expr-eval t=trigger v=dumpvars l=showline\n"); fprintf(ErrFp, " -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, " -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, " -b[n] Formato da hora para o cal: 0=am/pm, 1=24hr, 2=nenhum\n");

View File

@@ -22,6 +22,11 @@
#include <stdio.h> #include <stdio.h>
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <stdarg.h> #include <stdarg.h>
#ifdef HAVE_LOCALE_H #ifdef HAVE_LOCALE_H
#include <locale.h> #include <locale.h>
@@ -76,6 +81,8 @@ int main(int argc, char *argv[])
DBufInit(&(LastTrigger.tags)); DBufInit(&(LastTrigger.tags));
ClearLastTriggers(); ClearLastTriggers();
atexit(DebugExitFunc);
if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) { if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) {
ProduceCalendar(); ProduceCalendar();
return 0; return 0;
@@ -590,8 +597,8 @@ int EvaluateExpr(ParsePtr p, Value *v)
int r; int r;
if (p->isnested) return E_PARSE_ERR; /* Can't nest expressions */ if (p->isnested) return E_PARSE_ERR; /* Can't nest expressions */
while (isempty(*p->pos)) (p->pos)++;
if (!p->pos) return E_PARSE_ERR; /* Missing expression */ if (!p->pos) return E_PARSE_ERR; /* Missing expression */
while (isempty(*p->pos)) (p->pos)++;
if (*p->pos == BEG_OF_EXPR) { if (*p->pos == BEG_OF_EXPR) {
(p->pos)++; (p->pos)++;
bracketed = 1; bracketed = 1;
@@ -898,7 +905,7 @@ int DoIfTrig(ParsePtr p)
if ((size_t) NumIfs >= IF_NEST) return E_NESTED_IF; if ((size_t) NumIfs >= IF_NEST) return E_NESTED_IF;
if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE; if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE;
else { else {
if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r; if ( (r=ParseRem(p, &trig, &tim)) ) return r;
if (trig.typ != NO_TYPE) return E_PARSE_ERR; if (trig.typ != NO_TYPE) return E_PARSE_ERR;
dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1); dse = ComputeTrigger(trig.scanfrom, &trig, &tim, &r, 1);
if (r) { if (r) {
@@ -1016,6 +1023,12 @@ int DoDebug(ParsePtr p)
else DebugFlag &= ~DB_ECHO_LINE; else DebugFlag &= ~DB_ECHO_LINE;
break; break;
case 's':
case 'S':
if (val) DebugFlag |= DB_EXPR_STACKS;
else DebugFlag &= ~DB_EXPR_STACKS;
break;
case 'x': case 'x':
case 'X': case 'X':
if (val) DebugFlag |= DB_PRTEXPR; if (val) DebugFlag |= DB_PRTEXPR;
@@ -1666,7 +1679,9 @@ System(char const *cmd, int is_queued)
pid_t kid; pid_t kid;
int fd; int fd;
int status; int status;
int do_exit = 0;
if (is_queued && IsServerMode()) { if (is_queued && IsServerMode()) {
do_exit = 1;
/* Server mode... redirect stdin and stdout to /dev/null */ /* Server mode... redirect stdin and stdout to /dev/null */
kid = fork(); kid = fork();
if (kid == (pid_t) -1) { if (kid == (pid_t) -1) {
@@ -1688,14 +1703,17 @@ System(char const *cmd, int is_queued)
} }
} else { } else {
/* In the parent */ /* In the parent */
while (waitpid(kid, &status, 0) != kid) { while (waitpid(kid, &status, 0) != kid) /* continue */ ;
continue;
}
return; return;
} }
} }
/* This is the child process or original if we never forked */ /* This is the child process or original if we never forked */
r = system(cmd); r = system(cmd);
if (do_exit) {
/* In the child process, so exit! */
exit(0);
}
if (r == 0) { if (r == 0) {
return; return;
} }

View File

@@ -6,6 +6,10 @@
#include "config.h" #include "config.h"
#ifdef HAVE_STDINT_H
#include <stdint.h>
typedef uint32_t uint32;
#else
#if SIZEOF_UNSIGNED_INT == 4 #if SIZEOF_UNSIGNED_INT == 4
typedef unsigned int uint32; typedef unsigned int uint32;
#elif SIZEOF_UNSIGNED_LONG == 4 #elif SIZEOF_UNSIGNED_LONG == 4
@@ -13,6 +17,7 @@ typedef unsigned long uint32;
#else #else
# error Could not find a 32-bit integer type # error Could not find a 32-bit integer type
#endif #endif
#endif
struct MD5Context { struct MD5Context {
uint32 buf[4]; uint32 buf[4];
@@ -26,9 +31,4 @@ void MD5Update(struct MD5Context *context, unsigned char const *buf,
void MD5Final(unsigned char digest[16], struct MD5Context *context); void MD5Final(unsigned char digest[16], struct MD5Context *context);
void MD5Transform(uint32 buf[4], uint32 const in[16]); void MD5Transform(uint32 buf[4], uint32 const in[16]);
/*
* This is needed to make RSAREF happy on some MS-DOS compilers.
*/
typedef struct MD5Context MD5_CTX;
#endif /* !MD5_H */ #endif /* !MD5_H */

View File

@@ -22,7 +22,7 @@
#include "err.h" #include "err.h"
#include "expr.h" #include "expr.h"
static int BexistsIntArray (int array[], int num, int key); static int BexistsIntArray (int const array[], int num, int key);
static void InsertIntoSortedArray (int *array, int num, int key); static void InsertIntoSortedArray (int *array, int num, int key);
/* Arrays for the global omits */ /* Arrays for the global omits */
@@ -251,7 +251,7 @@ int IsOmitted(int dse, int localomit, char const *omitfunc, int *omit)
/* element is found, 0 otherwise. */ /* element is found, 0 otherwise. */
/* */ /* */
/***************************************************************/ /***************************************************************/
static int BexistsIntArray(int array[], int num, int key) static int BexistsIntArray(int const array[], int num, int key)
{ {
int top=num-1, bot=0, mid; int top=num-1, bot=0, mid;

View File

@@ -13,6 +13,18 @@
/* Suppress unused variable warnings */ /* Suppress unused variable warnings */
#define UNUSED(x) (void) x #define UNUSED(x) (void) x
#ifdef HAVE_STRDUP
#define StrDup strdup
#endif
#ifdef HAVE_STRNCASECMP
#define StrinCmp strncasecmp
#endif
#ifdef HAVE_STRCASECMP
#define StrCmpi strcasecmp
#endif
/* Define a string assignment macro - be careful!!! */ /* Define a string assignment macro - be careful!!! */
#define STRSET(x, str) { if (x) free(x); (x) = StrDup(str); } #define STRSET(x, str) { if (x) free(x); (x) = StrDup(str); }
@@ -37,7 +49,7 @@ char const *CalendarTime (int tim, int duration);
int DoRem (ParsePtr p); int DoRem (ParsePtr p);
int DoFlush (ParsePtr p); int DoFlush (ParsePtr p);
void DoExit (ParsePtr p); void DoExit (ParsePtr p);
int ParseRem (ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals); int ParseRem (ParsePtr s, Trigger *trig, TimeTrig *tim);
int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued, DynamicBuffer *output); int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued, DynamicBuffer *output);
int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int dse, int *err); int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int dse, int *err);
int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse, int mode); int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse, int mode);
@@ -103,12 +115,22 @@ int ComputeTrigger (int today, Trigger *trig, TimeTrig *tim, int *err, int save_
int ComputeTriggerNoAdjustDuration (int today, Trigger *trig, TimeTrig *tim, int *err, int save_in_globals, int duration_days); int ComputeTriggerNoAdjustDuration (int today, Trigger *trig, TimeTrig *tim, int *err, int save_in_globals, int duration_days);
int AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int save_in_globals); int AdjustTriggerForDuration(int today, int r, Trigger *trig, TimeTrig *tim, int save_in_globals);
char *StrnCpy (char *dest, char const *source, int n); char *StrnCpy (char *dest, char const *source, int n);
#ifndef HAVE_STRNCASECMP
int StrinCmp (char const *s1, char const *s2, int n); int StrinCmp (char const *s1, char const *s2, int n);
#endif
#ifndef HAVE_STRDUP
char *StrDup (char const *s); char *StrDup (char const *s);
#endif
#ifndef HAVE_STRCASECMP
int StrCmpi (char const *s1, char const *s2); int StrCmpi (char const *s1, char const *s2);
#endif
Var *FindVar (char const *str, int create); Var *FindVar (char const *str, int create);
int DeleteVar (char const *str); int DeleteVar (char const *str);
int SetVar (char const *str, Value *val); int SetVar (char const *str, Value const *val);
int GetVarValue (char const *str, Value *val, Var *locals, ParsePtr p); int GetVarValue (char const *str, Value *val, Var *locals, ParsePtr p);
int DoSet (Parser *p); int DoSet (Parser *p);
int DoUnset (Parser *p); int DoUnset (Parser *p);
@@ -174,12 +196,14 @@ int AddGlobalOmit(int dse);
void set_lat_and_long_from_components(void); void set_lat_and_long_from_components(void);
void set_components_from_lat_and_long(void); void set_components_from_lat_and_long(void);
void DebugExitFunc(void);
int GetTerminalBackground(void); int GetTerminalBackground(void);
char const *get_day_name(int wkday); char const *get_day_name(int wkday);
char const *get_month_name(int mon); char const *get_month_name(int mon);
void set_cloexec(int fd); void set_cloexec(FILE *fp);
int push_call(char const *filename, char const *func, int lineno); int push_call(char const *filename, char const *func, int lineno);
void clear_callstack(void); void clear_callstack(void);
int print_callstack(FILE *fp); int print_callstack(FILE *fp);

View File

@@ -66,6 +66,7 @@ typedef struct queuedrem {
char sched[VAR_NAME_LEN+1]; char sched[VAR_NAME_LEN+1];
Trigger t; Trigger t;
TimeTrig tt; TimeTrig tt;
int red, green, blue;
} QueuedRem; } QueuedRem;
/* Global variables */ /* Global variables */
@@ -79,7 +80,7 @@ static void CheckInitialFile (void);
static int CalculateNextTime (QueuedRem *q); static int CalculateNextTime (QueuedRem *q);
static QueuedRem *FindNextReminder (void); static QueuedRem *FindNextReminder (void);
static int CalculateNextTimeUsingSched (QueuedRem *q); static int CalculateNextTimeUsingSched (QueuedRem *q);
static void DaemonWait (struct timeval *sleep_tv); static void ServerWait (struct timeval *sleep_tv);
static void reread (void); static void reread (void);
static void PrintQueue(void); static void PrintQueue(void);
static char const *QueueFilename(char const *fname); static char const *QueueFilename(char const *fname);
@@ -153,6 +154,34 @@ static char const *QueueFilename(char const *fname)
return elem->fname; return elem->fname;
} }
static void del_reminder(QueuedRem *qid)
{
QueuedRem *q = QueueHead;
QueuedRem *next;
if (!q) {
return;
}
if (q == qid) {
QueueHead = q->next;
if (q->text) free((void *) q->text);
free(q);
return;
}
while(q->next) {
next = q->next;
if (q->next == qid) {
q->next = q->next->next;
if (next->text) free((void *) next->text);
free(next);
return;
}
q = q->next;
}
}
static void del_reminder_ul(unsigned long qid) {
del_reminder((QueuedRem *) qid);
}
/***************************************************************/ /***************************************************************/
/* */ /* */
@@ -178,6 +207,9 @@ int QueueReminder(ParsePtr p, Trigger *trig,
if (!qelem) { if (!qelem) {
return E_NO_MEM; return E_NO_MEM;
} }
qelem->red = DefaultColorR;
qelem->green = DefaultColorG;
qelem->blue = DefaultColorB;
qelem->text = StrDup(p->pos); /* Guaranteed that parser is not nested. */ qelem->text = StrDup(p->pos); /* Guaranteed that parser is not nested. */
if (!qelem->text) { if (!qelem->text) {
free(qelem); free(qelem);
@@ -277,6 +309,7 @@ void HandleQueuedReminders(void)
struct timeval tv; struct timeval tv;
struct timeval sleep_tv; struct timeval sleep_tv;
struct sigaction sa; struct sigaction sa;
char qid[64];
/* Turn off sorting -- otherwise, TriggerReminder has no effect! */ /* Turn off sorting -- otherwise, TriggerReminder has no effect! */
SortByDate = 0; SortByDate = 0;
@@ -328,9 +361,7 @@ void HandleQueuedReminders(void)
} }
#ifdef USE_INOTIFY #ifdef USE_INOTIFY
if (IsServerMode()) { watch_fd = setup_inotify_watch();
watch_fd = setup_inotify_watch();
}
#endif #endif
/* Sit in a loop, issuing reminders when necessary */ /* Sit in a loop, issuing reminders when necessary */
while(1) { while(1) {
@@ -357,8 +388,6 @@ void HandleQueuedReminders(void)
SleepTime = 60*Daemon; SleepTime = 60*Daemon;
} }
/* Wake up once a minute to recalibrate sleep time in
case of laptop hibernation */
if (IsServerMode()) { if (IsServerMode()) {
/* Wake up on the next exact minute */ /* Wake up on the next exact minute */
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
@@ -369,7 +398,9 @@ void HandleQueuedReminders(void)
} else { } else {
sleep_tv.tv_usec = 0; sleep_tv.tv_usec = 0;
} }
DaemonWait(&sleep_tv); ServerWait(&sleep_tv);
/* A DEL command might have deleted our queued reminder! */
q = FindNextReminder();
} else { } else {
sleep(SleepTime); sleep(SleepTime);
} }
@@ -387,7 +418,9 @@ void HandleQueuedReminders(void)
} }
} }
if (Daemon > 0 && SleepTime) CheckInitialFile(); if (Daemon > 0 && SleepTime) {
CheckInitialFile();
}
if (Daemon && !q) { if (Daemon && !q) {
if (IsServerMode()) { if (IsServerMode()) {
@@ -417,6 +450,8 @@ void HandleQueuedReminders(void)
if (IsServerMode() && q->typ != RUN_TYPE) { if (IsServerMode() && q->typ != RUN_TYPE) {
if (DaemonJSON) { if (DaemonJSON) {
printf("{\"response\":\"reminder\","); printf("{\"response\":\"reminder\",");
snprintf(qid, sizeof(qid), "%lx", (unsigned long) q);
PrintJSONKeyPairString("qid", qid);
PrintJSONKeyPairString("ttime", SimpleTimeNoSpace(q->tt.ttime)); PrintJSONKeyPairString("ttime", SimpleTimeNoSpace(q->tt.ttime));
PrintJSONKeyPairString("now", SimpleTimeNoSpace(MinutesPastMidnight(1))); PrintJSONKeyPairString("now", SimpleTimeNoSpace(MinutesPastMidnight(1)));
PrintJSONKeyPairString("tags", DBufValue(&q->t.tags)); PrintJSONKeyPairString("tags", DBufValue(&q->t.tags));
@@ -436,10 +471,15 @@ void HandleQueuedReminders(void)
and trigtime() work correctly */ and trigtime() work correctly */
SaveAllTriggerInfo(&(q->t), &(q->tt), DSEToday, q->tt.ttime, 1); SaveAllTriggerInfo(&(q->t), &(q->tt), DSEToday, q->tt.ttime, 1);
FileName = (char *) q->fname; FileName = (char *) q->fname;
DefaultColorR = q->red;
DefaultColorG = q->green;
DefaultColorB = q->blue;
/* Make a COPY of q->t because TriggerReminder can change q->t.typ */
Trigger tcopy = q->t;
if (DaemonJSON) { if (DaemonJSON) {
DynamicBuffer out; DynamicBuffer out;
DBufInit(&out); DBufInit(&out);
(void) TriggerReminder(&p, &q->t, &q->tt, DSEToday, 1, &out); (void) TriggerReminder(&p, &tcopy, &q->tt, DSEToday, 1, &out);
if (q->typ != RUN_TYPE) { if (q->typ != RUN_TYPE) {
printf("\"body\":\""); printf("\"body\":\"");
chomp(&out); chomp(&out);
@@ -448,7 +488,7 @@ void HandleQueuedReminders(void)
} }
DBufFree(&out); DBufFree(&out);
} else { } else {
(void) TriggerReminder(&p, &q->t, &q->tt, DSEToday, 1, NULL); (void) TriggerReminder(&p, &tcopy, &q->tt, DSEToday, 1, NULL);
} }
FileName = NULL; FileName = NULL;
if (IsServerMode() && !DaemonJSON && q->typ != RUN_TYPE) { if (IsServerMode() && !DaemonJSON && q->typ != RUN_TYPE) {
@@ -461,7 +501,6 @@ void HandleQueuedReminders(void)
/* Calculate the next trigger time */ /* Calculate the next trigger time */
q->tt.nexttime = CalculateNextTime(q); q->tt.nexttime = CalculateNextTime(q);
/* If it's dequeued, update num_queued */
if (q->tt.nexttime != NO_TIME) { if (q->tt.nexttime != NO_TIME) {
/* If trigger time is way in the past because computer has been /* If trigger time is way in the past because computer has been
suspended or hibernated, remove from queue */ suspended or hibernated, remove from queue */
@@ -471,9 +510,13 @@ void HandleQueuedReminders(void)
} }
} }
/* If we have dequeued a reminder, update controlling process */ /* If queued reminder has expired, actually remove it from queue
if (q->tt.nexttime == NO_TIME && IsServerMode()) { and update status */
print_num_queued(); if (q->tt.nexttime == NO_TIME) {
del_reminder(q);
if (IsServerMode()) {
print_num_queued();
}
} }
} }
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
@@ -594,7 +637,25 @@ static void CheckInitialFile(void)
/* If date has rolled around, or file has changed, spawn a new version. */ /* If date has rolled around, or file has changed, spawn a new version. */
time_t tim = FileModTime; time_t tim = FileModTime;
int y, m, d; int y, m, d;
#ifdef USE_INOTIFY
char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
int n;
#endif
#ifdef USE_INOTIFY
/* If there are any inotify events, reread */
if (watch_fd >= 0) {
while(1) {
n = read(watch_fd, buf, sizeof(buf));
if (n < 0 && errno == EINTR) continue;
if (n > 0) {
close(watch_fd);
reread();
}
break;
}
}
#endif
if (stat(InitialFile, &StatBuf) == 0) tim = StatBuf.st_mtime; if (stat(InitialFile, &StatBuf) == 0) tim = StatBuf.st_mtime;
if (tim != FileModTime || if (tim != FileModTime ||
RealToday != SystemDate(&y, &m, &d)) { RealToday != SystemDate(&y, &m, &d)) {
@@ -676,6 +737,7 @@ json_queue(QueuedRem const *q)
printf("{\"response\":\"queue\",\"queue\":"); printf("{\"response\":\"queue\",\"queue\":");
} }
printf("["); printf("[");
char idbuf[64];
while(q) { while(q) {
if (q->tt.nexttime == NO_TIME) { if (q->tt.nexttime == NO_TIME) {
q = q->next; q = q->next;
@@ -688,6 +750,8 @@ json_queue(QueuedRem const *q)
printf("{"); printf("{");
WriteJSONTrigger(&(q->t), 1, DSEToday); WriteJSONTrigger(&(q->t), 1, DSEToday);
WriteJSONTimeTrigger(&(q->tt)); WriteJSONTimeTrigger(&(q->tt));
snprintf(idbuf, sizeof(idbuf), "%lx", (unsigned long) q);
PrintJSONKeyPairString("qid", idbuf);
PrintJSONKeyPairInt("rundisabled", q->RunDisabled); PrintJSONKeyPairInt("rundisabled", q->RunDisabled);
PrintJSONKeyPairInt("ntrig", q->ntrig); PrintJSONKeyPairInt("ntrig", q->ntrig);
PrintJSONKeyPairString("filename", q->fname); PrintJSONKeyPairString("filename", q->fname);
@@ -701,7 +765,10 @@ json_queue(QueuedRem const *q)
case PS_TYPE: PrintJSONKeyPairString("type", "PS_TYPE"); break; case PS_TYPE: PrintJSONKeyPairString("type", "PS_TYPE"); break;
case PSF_TYPE: PrintJSONKeyPairString("type", "PSF_TYPE"); break; case PSF_TYPE: PrintJSONKeyPairString("type", "PSF_TYPE"); break;
case MSF_TYPE: PrintJSONKeyPairString("type", "MSF_TYPE"); break; case MSF_TYPE: PrintJSONKeyPairString("type", "MSF_TYPE"); break;
case PASSTHRU_TYPE: PrintJSONKeyPairString("type", "PASSTHRU_TYPE"); break; case PASSTHRU_TYPE:
PrintJSONKeyPairString("type", "PASSTHRU_TYPE");
PrintJSONKeyPairString("passthru", q->passthru);
break;
default: PrintJSONKeyPairString("type", "?"); break; default: PrintJSONKeyPairString("type", "?"); break;
} }
@@ -727,12 +794,12 @@ json_queue(QueuedRem const *q)
/***************************************************************/ /***************************************************************/
/* */ /* */
/* DaemonWait */ /* ServerWait */
/* */ /* */
/* Sleep or read command from stdin in "daemon -1" mode */ /* Sleep or read command from stdin in server mode */
/* */ /* */
/***************************************************************/ /***************************************************************/
static void DaemonWait(struct timeval *sleep_tv) static void ServerWait(struct timeval *sleep_tv)
{ {
fd_set readSet; fd_set readSet;
int retval; int retval;
@@ -849,6 +916,13 @@ static void DaemonWait(struct timeval *sleep_tv)
} }
fflush(stdout); fflush(stdout);
reread(); reread();
} else if (!strncmp(cmdLine, "DEL ", 4)) {
unsigned long qid;
if (sscanf(cmdLine, "DEL %lx", &qid) == 1) {
del_reminder_ul(qid);
}
print_num_queued();
fflush(stdout);
} else { } else {
if (DaemonJSON) { if (DaemonJSON) {
size_t l = strlen(cmdLine); size_t l = strlen(cmdLine);
@@ -884,18 +958,27 @@ static void consume_inotify_events(int fd)
int n; int n;
struct timespec sleeptime; struct timespec sleeptime;
/* HACK: sleep for 0.2 seconds to let multiple events queue up so we
only do a single reread */
sleeptime.tv_sec = 0;
sleeptime.tv_nsec = 200000000;
nanosleep(&sleeptime, NULL);
int slept = 0;
/* Consume all the inotify events */ /* Consume all the inotify events */
while(1) { while(1) {
n = read(fd, buf, sizeof(buf)); n = read(fd, buf, sizeof(buf));
if (n > 0) {
/* Something new since we slept */
slept = 0;
}
if (n < 0) { if (n < 0) {
if (errno == EINTR) continue; if (errno == EINTR) continue;
return; if (slept) {
/* Nothing new since we slept */
return;
}
slept = 1;
/* HACK: sleep for 0.2 seconds to let multiple events queue up so we
only do a single reread */
sleeptime.tv_sec = 0;
sleeptime.tv_nsec = 200000000;
nanosleep(&sleeptime, NULL);
} }
} }
} }

View File

@@ -244,6 +244,7 @@ static int NextSimpleTrig(int startdate, Trigger *trig, int *err)
case GOT_WD+GOT_MON+GOT_YR: case GOT_WD+GOT_MON+GOT_YR:
if (y > trig->y || (y == trig->y && m > trig->m)) return -1; if (y > trig->y || (y == trig->y && m > trig->m)) return -1;
/* cppcheck-suppress knownConditionTrueFalse */
if (trig->y > y || (trig->y == y && trig->m > m)) { if (trig->y > y || (trig->y == y && trig->m > m)) {
j = DSE(trig->y, trig->m, 1); j = DSE(trig->y, trig->m, 1);
ADVANCE_TO_WD(j, trig->wd); ADVANCE_TO_WD(j, trig->wd);

View File

@@ -150,6 +150,7 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
#define DB_DUMP_VARS 8 #define DB_DUMP_VARS 8
#define DB_ECHO_LINE 16 #define DB_ECHO_LINE 16
#define DB_TRACE_FILES 32 #define DB_TRACE_FILES 32
#define DB_EXPR_STACKS 64
/* Enumeration of the tokens */ /* Enumeration of the tokens */
enum TokTypes enum TokTypes

View File

@@ -16,6 +16,11 @@
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "types.h" #include "types.h"
#include "globals.h" #include "globals.h"

View File

@@ -17,6 +17,11 @@ static char const DontEscapeMe[] =
#include "err.h" #include "err.h"
#include <string.h> #include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
@@ -46,6 +51,7 @@ char *StrnCpy(char *dest, char const *source, int n)
return odest; return odest;
} }
#ifndef HAVE_STRNCASECMP
/***************************************************************/ /***************************************************************/
/* */ /* */
/* StrinCmp - compare strings, case-insensitive */ /* StrinCmp - compare strings, case-insensitive */
@@ -64,6 +70,9 @@ int StrinCmp(char const *s1, char const *s2, int n)
if (n) return (toupper(*s1) - toupper(*s2)); else return 0; if (n) return (toupper(*s1) - toupper(*s2)); else return 0;
} }
#endif
#ifndef HAVE_STRDUP
/***************************************************************/ /***************************************************************/
/* */ /* */
/* StrDup */ /* StrDup */
@@ -79,6 +88,9 @@ char *StrDup(char const *s)
return ret; return ret;
} }
#endif
#ifndef HAVE_STRCASECMP
/***************************************************************/ /***************************************************************/
/* */ /* */
/* StrCmpi */ /* StrCmpi */
@@ -98,6 +110,8 @@ int StrCmpi(char const *s1, char const *s2)
return toupper(*s1) - toupper(*s2); return toupper(*s1) - toupper(*s2);
} }
#endif
/***************************************************************/ /***************************************************************/
/* */ /* */
/* DateOK */ /* DateOK */
@@ -151,11 +165,15 @@ int _private_sub_overflow(int a, int b)
int int
ShellEscape(char const *in, DynamicBuffer *out) ShellEscape(char const *in, DynamicBuffer *out)
{ {
while(*in) { unsigned char const *i = (unsigned char const *) in;
if (!strchr(DontEscapeMe, *in)) { while(*i) {
if (DBufPutc(out, '\\') != OK) return E_NO_MEM; /* Don't escape chars with high bit set. That will mangle UTF-8 */
if (! (*i & 0x80) ) {
if (!strchr(DontEscapeMe, *i)) {
if (DBufPutc(out, '\\') != OK) return E_NO_MEM;
}
} }
if (DBufPutc(out, *in++) != OK) return E_NO_MEM; if (DBufPutc(out, *i++) != OK) return E_NO_MEM;
} }
return OK; return OK;
} }

View File

@@ -175,6 +175,19 @@ static int terminal_bg_func(int do_set, Value *val)
return OK; return OK;
} }
static int trig_time_func(int do_set, Value *val)
{
UNUSED(do_set);
if (LastTriggerTime != NO_TIME) {
val->type = TIME_TYPE;
val->v.val = LastTriggerTime;
} else {
val->type = INT_TYPE;
val->v.val = 0;
}
return OK;
}
static int trig_date_func(int do_set, Value *val) static int trig_date_func(int do_set, Value *val)
{ {
UNUSED(do_set); UNUSED(do_set);
@@ -480,7 +493,7 @@ int DeleteVar(char const *str)
/* Set the indicate variable to the specified value. */ /* Set the indicate variable to the specified value. */
/* */ /* */
/***************************************************************/ /***************************************************************/
int SetVar(char const *str, Value *val) int SetVar(char const *str, Value const *val)
{ {
Var *v = FindVar(str, 1); Var *v = FindVar(str, 1);
@@ -887,6 +900,7 @@ static SysVar SysVarArr[] = {
{"Tm", 0, SPECIAL_TYPE, trig_mon_func, 0, 0 }, {"Tm", 0, SPECIAL_TYPE, trig_mon_func, 0, 0 },
{"Today", 1, STR_TYPE, &DynamicToday, 0, 0 }, {"Today", 1, STR_TYPE, &DynamicToday, 0, 0 },
{"Tomorrow", 1, STR_TYPE, &DynamicTomorrow, 0, 0 }, {"Tomorrow", 1, STR_TYPE, &DynamicTomorrow, 0, 0 },
{"Tt", 0, SPECIAL_TYPE, trig_time_func, 0, 0 },
{"Tuesday", 1, STR_TYPE, &DynamicDayName[1], 0, 0 }, {"Tuesday", 1, STR_TYPE, &DynamicDayName[1], 0, 0 },
{"Tw", 0, SPECIAL_TYPE, trig_wday_func, 0, 0 }, {"Tw", 0, SPECIAL_TYPE, trig_wday_func, 0, 0 },
{"Ty", 0, SPECIAL_TYPE, trig_year_func, 0, 0 }, {"Ty", 0, SPECIAL_TYPE, trig_year_func, 0, 0 },

View File

@@ -65,6 +65,8 @@ echo "Test 1" > ../tests/test.out
echo "" >> ../tests/test.out echo "" >> ../tests/test.out
../src/remind -e -dxte ../tests/test.rem 16 feb 1991 12:13 >> ../tests/test.out 2>&1 ../src/remind -e -dxte ../tests/test.rem 16 feb 1991 12:13 >> ../tests/test.out 2>&1
echo "" >> ../tests/test.out echo "" >> ../tests/test.out
echo 'set a 1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+2*3))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))' | ../src/remind -ds - 16 feb 1991 12:13 >> ../tests/test.out 2>&1
echo "" >> ../tests/test.out
echo "Test 2" >> ../tests/test.out echo "Test 2" >> ../tests/test.out
echo "" >> ../tests/test.out echo "" >> ../tests/test.out
../src/remind -p -l ../tests/test2.rem 1 aug 2007 >> ../tests/test.out 2>&1 ../src/remind -p -l ../tests/test2.rem 1 aug 2007 >> ../tests/test.out 2>&1
@@ -452,8 +454,8 @@ rm -rf include_dir/ww
# Test queueing. Because eventstart depends on the actual system # Test queueing. Because eventstart depends on the actual system
# date, we have to convert it to some constant (in this case, # date, we have to convert it to some constant (in this case,
# VOLATILE) so that tests are not dependent on the system date. # VOLATILE) so that tests are not dependent on the system date.
echo JSONQUEUE | ../src/remind -z0 ../tests/queue1.rem 2>&1 | sed -e 's/"eventstart":"................"/"eventstart":"VOLATILE"/g' >> ../tests/test.out 2>&1 echo JSONQUEUE | ../src/remind -z0 ../tests/queue1.rem 2>&1 | sed -e 's/"eventstart":"................"/"eventstart":"VOLATILE"/g' | sed -e 's/"qid":"[0-9a-f]*",//g' >> ../tests/test.out 2>&1
echo QUEUE | ../src/remind -zj ../tests/queue1.rem 2>&1 | sed -e 's/"eventstart":"................"/"eventstart":"VOLATILE"/g' >> ../tests/test.out 2>&1 echo QUEUE | ../src/remind -zj ../tests/queue1.rem 2>&1 | sed -e 's/"eventstart":"................"/"eventstart":"VOLATILE"/g' | sed -e 's/"qid":"[0-9a-f]*",//g' >> ../tests/test.out 2>&1
# Test for leap year bug that was fixed # Test for leap year bug that was fixed
../src/remind -dte - 28 Feb 2024 <<'EOF' >> ../tests/test.out 2>&1 ../src/remind -dte - 28 Feb 2024 <<'EOF' >> ../tests/test.out 2>&1
@@ -537,7 +539,7 @@ REM Friday 29 Feb 2025 MSG four
EOF EOF
(echo 'BANNER %'; echo 'REM 29 MSG No bug') | ../src/remind -dt - >> ../tests/test.out 2>&1 (echo 'BANNER %'; echo 'REM 29 MSG No bug') | ../src/remind -dt - 29 Feb 2024 >> ../tests/test.out 2>&1
# Remove references to SysInclude, which is build-specific # Remove references to SysInclude, which is build-specific
grep -F -v '$SysInclude' < ../tests/test.out > ../tests/test.out.1 && mv -f ../tests/test.out.1 ../tests/test.out grep -F -v '$SysInclude' < ../tests/test.out > ../tests/test.out.1 && mv -f ../tests/test.out.1 ../tests/test.out

File diff suppressed because one or more lines are too long

View File

@@ -329,6 +329,7 @@ set a052 time(1+2, 3+4)
rem 10 jan 1992 AT 11:22 CAL rem 10 jan 1992 AT 11:22 CAL
set a053 trigdate() set a053 trigdate()
set a054 trigtime() set a054 trigtime()
set a054b $Tt
set a055 trigvalid() set a055 trigvalid()
set a056 upper("sdfjhsdf ksjdfh kjsdfh ksjdfh") set a056 upper("sdfjhsdf ksjdfh kjsdfh ksjdfh")
set a057 value("a05"+"6") set a057 value("a05"+"6")
@@ -457,6 +458,7 @@ set a129 23:30 + '2019-02-02@16:44'
REM 13 AT 16:00 DURATION 72:00 MSG 72-hour event REM 13 AT 16:00 DURATION 72:00 MSG 72-hour event
set a130 trigdate() set a130 trigdate()
set a131 trigtime() set a131 trigtime()
set a131b $Tt
set a132 trigdatetime() set a132 trigdatetime()
set a133 trigduration() set a133 trigduration()
set a134 trigeventstart() set a134 trigeventstart()
@@ -784,6 +786,15 @@ ENDIF
REM [trig("Mon", "Tue", "Wed", "Sat")] MSG foo REM [trig("Mon", "Tue", "Wed", "Sat")] MSG foo
REM [trig("Mon", "Tue", "Wed")] MSG bar REM [trig("Mon", "Tue", "Wed")] MSG bar
# Multitrig
REM [multitrig("10", "17")] MSG multitrig-1
REM [multitrig("Feb 15", "Mar 20")] MSG multitrig-2
REM [multitrig("Oct 7 1992", "1991")] MSG multitrig-3
REM [multitrig("16 Feb AFTER OMIT Sat Sun", "29 March")] MSG multitrig-4
REM [multitrig("2", "3", "5", "7")] MSG multitrig-5
REM [multitrig("15 SCANFROM -7", "14 SCANFROM -7")] MSG multitrig-6
REM [multitrig("15 SCANFROM -7", "14 SCANFROM -7")] SCANFROM -7 MSG multitrig-7
# The new syntactic sugar # The new syntactic sugar
REM First Monday January MSG x REM First Monday January MSG x
REM Second Tuesday in April MSG x REM Second Tuesday in April MSG x
@@ -910,6 +921,27 @@ set a 7 * "Cabbage! "
# Should result in errors # Should result in errors
set pqxya 1+2) set pqxya 1+2)
# Should result in an error
REM Tue OMIT 2024-01-01 MSG Wookie
# No error
REM Tue OMIT Wed 2024-01-01 MSG Blort
# Make sure trigtime() is not reset between invocations
REM Tue AT 16:00 DURATION 30 MSG Thing One
REM [$T] AT [trigtime()+trigduration()] DURATION 15 MSG Thing Two
REM [$T] AT [$Tt+trigduration()] DURATION 30 MSG Thing Three
REM [$T] AT [trigtime()+trigduration()] DURATION 10 MSG Last Thing
# Make sure trigtime is not reset during parsing
REM Tue AT 16:00 MSG blort
REM Tue AT 10:00 DURATION [$Tt] MSG blort
REM Tue AT 16:00 MSG blort
REM Tue AT 10:00 DURATION [trigtime()] MSG blort
# Make sure shellescape does not mangle UTF-8 characters
msg [shellescape("😆")]
# Don't want Remind to queue reminders # Don't want Remind to queue reminders
EXIT EXIT

View File

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

View File

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

41
www/calendar.css Normal file
View File

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

View File

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

11
www/calpdf Normal file
View File

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

View File

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

View File

@@ -165,13 +165,15 @@ ENDIF
IF !$PSCAL IF !$PSCAL
REM 20 ++40 msg Also available: <a HREF="%CGIDIR%/cal_dispatch?hebps">a PostScript calendar</a> (about 35KB) for %m %y, complete with Hebrew dates, Jewish holidays, and moon phases for [$Location]. REM 20 ++40 msg Also available: <a HREF="%CGIDIR%/cal_dispatch?hebps">a PostScript calendar</a> (about 35KB) for %m %y, complete with Hebrew dates, Jewish holidays, and moon phases for [$Location].
REM 20 ++40 msg And: <a HREF="%CGIDIR%/cal_dispatch?hebhtml">an HTML version</a> of the above. REM 20 ++40 msg And: <a HREF="%CGIDIR%/cal_dispatch?hebhtml">an HTML version</a> of the above.
REM 20 ++40 msg And: <a HREF="%CGIDIR%/cal_dispatch?hebpdf">a PDF version</a> of the above.
ELSE ELSE
[trigger(moondate(0))] SPECIAL MOON 0 REM [moondate(0)] SPECIAL MOON 0
[trigger(moondate(1))] SPECIAL MOON 1 REM [moondate(1)] SPECIAL MOON 1
[trigger(moondate(2))] SPECIAL MOON 2 REM [moondate(2)] SPECIAL MOON 2
[trigger(moondate(3))] SPECIAL MOON 3 REM [moondate(3)] SPECIAL MOON 3
REM PS Border Border moveto /DayFont findfont 10 scalefont setfont ([hebday(today())] [hebmon(today())]) show REM PS Border Border moveto /DayFont findfont 10 scalefont setfont ([hebday($U)] [hebmon($U)]) show
REM SPECIAL HTML <P>[hebday(today())] [hebmon(today())]</P> REM SPECIAL HTML <P>[hebday($U)] [hebmon($U)]</P>
REM SPECIAL PANGO @4,-1 <span size="6400"><i>[hebday($U)] [hebmon($U)]</i></span>
ENDIF ENDIF

17
www/hebpdf Normal file
View File

@@ -0,0 +1,17 @@
#!/bin/sh
# Hebrew PostScript calendar shell script
#
# This file is part of REMIND.
# Copyright (C) 1992-2018 by Dianne Skoll
# Figure out the month: If day <= 20, use this month; otherwise, use
# next month.
echo "Content-type: application/pdf"
echo ""
$REMIND - <<EOR
BANNER %
REM 20 ++40 RUN $REMIND -iHTML=0 -p $DIR/hebdate.rem %m %y | $REM2PDF -e -c3 -l
EOR
exit 0

View File

@@ -9,6 +9,7 @@ banner %
MSG <HEAD>% MSG <HEAD>%
MSG <TITLE>Moon over [$Location]</TITLE>% MSG <TITLE>Moon over [$Location]</TITLE>%
MSG <LINK rel="stylesheet" href="%IMAGEBASE%/calendar.css">%
MSG </HEAD>% MSG </HEAD>%
MSG <BODY> MSG <BODY>

View File

@@ -8,6 +8,7 @@ set now now()
banner % banner %
MSG <HEAD>% MSG <HEAD>%
MSG <TITLE>Sunrise in [$Location]</TITLE>% MSG <TITLE>Sunrise in [$Location]</TITLE>%
MSG <LINK rel="stylesheet" href="%IMAGEBASE%/calendar.css">%
MSG </HEAD>% MSG </HEAD>%
MSG <BODY> MSG <BODY>

View File

@@ -10,6 +10,7 @@ banner %
MSG <HEAD>% MSG <HEAD>%
MSG <TITLE>Sunset in [$Location]</TITLE>% MSG <TITLE>Sunset in [$Location]</TITLE>%
MSG <LINK rel="stylesheet" href="%IMAGEBASE%/calendar.css">%
MSG </HEAD>% MSG </HEAD>%
MSG <BODY> MSG <BODY>