Compare commits

..

65 Commits

Author SHA1 Message Date
Dianne Skoll
e3297fe751 Prep for 3.3.9 release. 2021-10-14 21:20:05 -04:00
Dianne Skoll
58ca741a1c Update docs. 2021-10-14 10:38:11 -04:00
Dianne Skoll
14dbbc7bb4 Fix help text. 2021-10-14 10:24:58 -04:00
Dianne Skoll
df55c4032b Use external .png images for moon phases. 2021-10-14 10:23:58 -04:00
Dianne Skoll
3768155a20 Add "--pngs" option 2021-10-14 10:21:51 -04:00
Dianne Skoll
2f3b9cadf4 Add a generated file to unconfigure 2021-10-12 22:06:03 -04:00
Dianne Skoll
2c79a6531a Fix typo. 2021-10-12 22:05:12 -04:00
Dianne Skoll
be5c856f4b Remove "cm2rem". It's waaaay obsolete. 2021-10-12 22:04:00 -04:00
Dianne Skoll
712a333f08 Substitute full path to `rem2html' 2021-10-12 21:58:10 -04:00
Dianne Skoll
b753e84c8c Update README 2021-10-12 21:55:18 -04:00
Dianne Skoll
4b4acaadbb Don't install rem2html if we don't have Perl. 2021-10-12 21:54:38 -04:00
Dianne Skoll
8a52f9b67d Silence Perl warning. 2021-10-12 21:51:04 -04:00
Dianne Skoll
e372606281 Pass --stylesheet option 2021-10-12 21:46:03 -04:00
Dianne Skoll
c443d0a9da Make imgbase and stylesheet options behave rationally. 2021-10-12 21:44:25 -04:00
Dianne Skoll
42c9ae9ea8 Add generated file to .gitignore. 2021-10-12 21:33:06 -04:00
Dianne Skoll
dac9bb4187 Pass proper --imgbase argument 2021-10-12 21:32:46 -04:00
Dianne Skoll
812d926f66 Move rem2html into its own directory and install it by default. 2021-10-12 21:28:14 -04:00
Dianne Skoll
45831ea69f Fix error in man page courtesy of Richard Ulmer. 2021-10-11 19:54:38 -04:00
Dianne Skoll
354e1d236b Update test-for-backends.rem with comments. 2021-10-08 15:27:32 -04:00
Dianne Skoll
ac478039cf Remove unnecessary spaces from JSON output. 2021-10-06 17:47:31 -04:00
Dianne Skoll
96f5799e6f Fix typo 2021-10-06 17:41:15 -04:00
Dianne Skoll
e21479f696 Add test reminder file for seeing how back-ends handle SPECIALs 2021-10-06 09:39:52 -04:00
Dianne Skoll
25dc883e15 Fix bug in calendar display: Would sometimes highlight wrong day as "today" 2021-10-06 09:39:08 -04:00
Dianne Skoll
bfb1374ee3 Document that "-pp" is the preferred Remind output format. 2021-10-05 23:31:34 -04:00
Dianne Skoll
cacd8f9792 Tweak stylesheet 2021-10-05 23:13:22 -04:00
Dianne Skoll
3e9053a3c6 No need to install the .png images. 2021-10-05 23:10:34 -04:00
Dianne Skoll
5fa357fec2 Use data: URLs for the moon images. 2021-10-05 23:08:41 -04:00
Dianne Skoll
f109c3d696 Remove C99-ism. 2021-10-05 13:54:04 -04:00
Dianne Skoll
b097ce7279 Fix docs. 2021-10-05 12:18:50 -04:00
Dianne Skoll
1297854935 Allow "-u+whatever" to change users without disabling RUN. 2021-10-05 12:17:42 -04:00
Dianne Skoll
0a1d0011f6 Add "-+username" option to trust "username" for the purpose of allowing RUN. 2021-10-05 12:04:44 -04:00
Dianne Skoll
20db1be0a0 Add missing #ifdef...#endif courtesy of Nomen Nescio 2021-10-04 08:39:27 -04:00
Dianne Skoll
143f1d6144 Prep for 3.3.8 release. 2021-09-13 19:14:03 -04:00
Dianne Skoll
358f6c9497 Fix error in TkRemind reverse-engineering of Reminder. 2021-09-13 18:11:32 -04:00
Dianne Skoll
ca26544be8 Don't use YYYY-MM-DD form of full date.
We get better error messages from Remind this way.
2021-09-13 17:54:36 -04:00
Dianne Skoll
5ceffddd5b Add "shellescape" built-in function. 2021-09-08 09:33:47 -04:00
Dianne Skoll
8e3ddb96b3 Add another couple of tests. 2021-09-07 12:16:36 -04:00
Dianne Skoll
377de36b35 More doc about INCLUDECMD. 2021-09-07 10:06:20 -04:00
Dianne Skoll
4395e2f7ed Use "pclose" rather than "fclose" to close descriptors opened with "popen" 2021-09-05 11:45:55 -04:00
Dianne Skoll
1d0cc31b10 Clarify how we determine uniqueness of INCLUDECMD commands. 2021-09-05 11:38:13 -04:00
Dianne Skoll
4b4b2ddcd4 Add test case for line-continuation in INCLUDECMD lines. 2021-09-05 11:30:35 -04:00
Dianne Skoll
3c9b5b786e Convert \n from continuation lines in INCLUDECMD to ' ' to make it a little friendlier. 2021-09-05 11:28:54 -04:00
Dianne Skoll
08f1bea6ce Make TkRemind refuse to attempt to edit reminders issued by an INCLUDECMD 2021-09-05 11:13:11 -04:00
Dianne Skoll
a2cc5943e0 Fix test case 2021-09-05 10:54:56 -04:00
Dianne Skoll
895ac6f0f7 Fix bugs in INCLUDECMD. Improve INCLUDECMD documentation. Add ! feature
If you use:

    INCLUDECMD !some_command

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

19
.gitignore vendored
View File

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

View File

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

View File

@@ -18,7 +18,8 @@ install:
@echo "* *"
@echo "*********************"
@echo ""
@cd src && $(MAKE) install
@$(MAKE) -C src install
@$(MAKE) -C rem2html install
clean:
find . -name '*~' -exec rm {} \;

49
configure vendored
View File

@@ -626,6 +626,7 @@ VERSION
EGREP
GREP
CPP
PERL
SET_MAKE
LN_S
INSTALL_DATA
@@ -3274,6 +3275,46 @@ $as_echo "no" >&6; }
SET_MAKE="MAKE=${MAKE-make}"
fi
# Extract the first word of "perl", so it can be a program name with args.
set dummy perl; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_PERL+:} false; then :
$as_echo_n "(cached) " >&6
else
case $PERL in
[\\/]* | ?:[\\/]*)
ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
PERL=$ac_cv_path_PERL
if test -n "$PERL"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5
$as_echo "$PERL" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
@@ -3820,7 +3861,7 @@ _ACEOF
for ac_header in sys/file.h glob.h wctype.h locale.h
for ac_header in sys/types.h sys/file.h glob.h wctype.h locale.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -3991,9 +4032,10 @@ _ACEOF
fi
done
VERSION=03.03.06
VERSION=03.03.09
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h"
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h rem2html/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -4689,6 +4731,7 @@ do
"src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
"www/Makefile") CONFIG_FILES="$CONFIG_FILES www/Makefile" ;;
"src/version.h") CONFIG_FILES="$CONFIG_FILES src/version.h" ;;
"rem2html/Makefile") CONFIG_FILES="$CONFIG_FILES rem2html/Makefile" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac

View File

@@ -49,6 +49,7 @@ AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PATH_PROG([PERL], [perl])
dnl Checks for libraries.
dnl Replace `main' with a function in -lm:
@@ -61,7 +62,7 @@ AC_CHECK_SIZEOF(unsigned int)
AC_CHECK_SIZEOF(unsigned long)
dnl Checks for header files.
AC_CHECK_HEADERS(sys/file.h glob.h wctype.h locale.h)
AC_CHECK_HEADERS(sys/types.h sys/file.h glob.h wctype.h locale.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_STRUCT_TM
@@ -75,6 +76,7 @@ if test "$GCC" = yes; then
fi
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale)
VERSION=03.03.06
VERSION=03.03.09
AC_SUBST(VERSION)
AC_OUTPUT(src/Makefile www/Makefile src/version.h)
AC_SUBST(PERL)
AC_OUTPUT(src/Makefile www/Makefile src/version.h rem2html/Makefile)

View File

@@ -1,5 +1,64 @@
CHANGES TO REMIND
* VERSION 3.3 Patch 9 - 2021-10-14
- NEW FEATURE: Add "-+username" option to tell Remind to trust files owned by
"username" and allow RUN directives in them. Idea courtesy of Ian! D. Allen
- NEW FEATURE: Add "-u+username" variant to tell Remind to switch users to
"username" without disabling RUN directices. Idea courtesy of Ian! D. Allen
- CHANGE: rem2html: rem2html has been moved out of the www/ directory into
its own rem2html/ directory. If your system has the prerequisites
(namely Perl, Getopt::Long and JSON::Any) then rem2html will be installed
by "make install".
- CHANGE: Remove "cm2rem". It was about 20 years obsolete.
- CHANGE: rem2html: Use inline data: URL images for moon images by default,
thus producing a completely stand-alone HTML file.
- CHANGE: Remove unnecessary spaces from "remind -pp" JSON output.
- DOCUMENTATION FIX: Various man page fixes and tweaks.
- BUG FIX: rem2html: Tweak the default CSS stylesheet; more rational
handling of rem2html command-line options.
- BUG FIX: remind: "remind -c" would sometimes highlight *two* days as
"today"; this has been fixed.
- BUG FIX: Add a missing #ifdef...#endif and remove a C99-ism. This once again
allows Remind to be compiled with some very old C compilers.
* VERSION 3.3 Patch 8 - 2021-09-13
- NEW FEATURE: remind: Add INCLUDECMD command
- NEW FEATURE: remind: Add shellescape() built-in function
- BUG FIX: tkremind: TkRemind would sometimes fill in incorrect initial
values for the reminder-editing form if you clicked on a TkRemind-created
reminder to edit it. This has been fixed.
- BUG FIX: tkremind: Get back better error messages from Remind if you
try to create a reminder with an invalid date specification.
- BUG FIX: remind: Catch integer overflow if we try to evaluate $IntMin * -1
- DOC UPDATES: remind: Minor man page fixes
* VERSION 3.3 Patch 7 - 2021-05-10
- MINOR FIX: Refuse to run "make test" as root --- it would fail
anyway with an obscure message.
- BUG FIX: Remind would sometimes compute incorrect trigger date for:
REM Tue 29 Feb MSG ...
- BUG FIX: Remind would sometimes compute incorrect trigger date for
a date spec like: Tue 31 2021 MSG ...
* VERSION 3.3 Patch 6 - 2021-03-30
- test/test.rem: Change local to en_US.utf-8 only if current locale

View File

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

View File

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

View File

@@ -475,7 +475,7 @@ present and the value will be the type of SPECIAL (such as SHADE, COLOR,
MOON, etc.)
.TP
.B tags \fIdata\fR
If any TAG clauses are present, the \fBtag\fR key will be present and consist
If any TAG clauses are present, the \fBtags\fR key will be present and consist
of a comma-separated list of tags.
.TP
.B time \fIt\fR

View File

@@ -1,4 +1,4 @@
.TH REMIND 1 "1 January 2020"
.TH REMIND 1 "1 January 2021"
.UC 4
.SH NAME
remind \- a sophisticated reminder service
@@ -31,7 +31,8 @@ ignore them for now and skip to the section "REMINDER FILES".
.B \-n
The \fB\-n\fR option causes \fBRemind\fR to print the \fBnext\fR occurrence
of each reminder in a simple calendar format. You can sort this by
date by piping the output through \fBsort(1)\fR.
date by piping the output through \fBsort(1)\fR. Note that the \fB\-n\fR
option causes any \fB\-g\fR option to be \fIignored\fR.
.TP
.B \-j\fR[\fIn\fR]
Runs \fBRemind\fR in "purge" mode to get rid of expired reminders.
@@ -39,7 +40,7 @@ See the section PURGE MODE for details.
.TP
.B \-r
The \fB\-r\fR option disables \fBRUN\fR directives and the \fBshell()\fR
function. As of Remind 3.00.17, using \fB\-u\fR implies \fB\-r\fR.
function.
.TP
.B \-c\fI[flags]\fIn\fR
The \fB\-c\fR option causes \fBRemind\fR to produce a calendar that is
@@ -250,6 +251,7 @@ The optional \fBa\fR and \fBd\fR characters specify the sort order
(ascending or descending) for the date, time and priority fields. See
the section "SORTING REMINDERS" for more information.
Note that \fB\-g\fR is \fIignored\fR if you use the \fB\-n\fR option.
.TP
\fB\-b\fR[\fIn\fR]
Set the time format for the calendar and simple-calendar outputs. \fIN\fR
@@ -308,7 +310,11 @@ and user name, respectively, of the specified user. LOGNAME is also
set to the specified user name. This option is meant for
use in shell scripts that mail reminders to all users. Note that
as of Remind 3.00.17, using \fB\-u\fR implies \fB\-r\fR -- the RUN
directive and shell() functions are disabled.
directive and shell() functions are disabled. However, if you prefix
\fIname\fR with a \fB+\fR-sign, then RUN and shell() are \fInot\fR
disabled. That is, \fB\-uwhatever\fR switches the user to \fBwhatever\fR
and disables RUN, whereas \fB\-u+whatever\fR switches the user to
\fBwhatever\fR but leaves RUN enabled.
.PP
.RS
Non-root users can also use the \fB\-u\fR option. However, in this
@@ -316,6 +322,13 @@ case, it only changes the environment variables as described above.
It does not change the effective uid or gid.
.RE
.TP
\fB\-+\fIusername\fR
Causes \fBRemind\fR to trust files owned by the user \fIusername\fR.
Normally, if \fBRemind\fR reads a file that you do not own, it disables
RUN and the shell() function. This option causes it to also trust files
owned by \fIusername\fR. You can supply multiple \fB\-+\fR options
to trust multiple users, up to a limit of 20 trusted users.
.TP
\fB-y\fR
Causes \fBRemind\fR to synthesize a tag for any reminder that lacks a
TAG clause.
@@ -349,7 +362,7 @@ it as YYYY-MM-DD or YYYY/MM/DD. You can even supply a date and
time on the command line as one argument: YYYY-MM-DD@HH:MM.
.PP
In addition, you can supply a \fIrepeat\fR parameter, which has the
form *\fInum\fR. This causes \fBRemind\fR to be run \fInum\fR times,
form *\fIrep\fR. This causes \fBRemind\fR to be run \fIrep\fR times,
with the date incrementing on each iteration. You may have to enclose
the parameter in quotes to avoid shell expansion. See the subsection
"Repeated Execution" in the section "CALENDAR MODE" for more
@@ -618,7 +631,7 @@ present. Examples:
.nf
REM Sat 1 MSG First Saturday of every month
REM Mon Tue Wed Thu Fri 15 \\
MSG 1st working day after 15th of every month
MSG 1st working day on or after 15th of every month
.fi
.PP
11.
@@ -1579,6 +1592,53 @@ It will not run set-uid. If it reads a file you don't own, it will
disable RUN and the shell() function. And if it is run as \fIroot\fR,
it will only read files owned by \fIroot\fR.
.PP
Note that if \fBRemind\fR reads standard input, it does \fInot\fR
attempt to check the ownership of standard input, even if it is
coming from a file, and hence does \fInot\fR disable RUN and shell()
in this situation.
.SH THE INCLUDECMD COMMAND
.PP
\fBRemind\fR allows you to execute a shell command and evaluate the
output of that command as if it were an included file. For example,
you could have scripts that extract reminders out of a database and print
them on stdout as REM commands. Here is an example:
.PP
.nf
INCLUDECMD extract_reminders_for dfs
.fi
.PP
We assume that the command "extract_reminders_for" extracts reminders out
of a central database for the named user. Another use-case of INCLUDECMD
is if you have your reminders stored in a file in some non-Remind format;
you can write a command that transforms them to Remind format and then
Remind can "include" the file with an appropriate INCLUDECMD command.
.PP
Note that if RUN is disabled, then INCLUDECMD will fail with the error
message "RUN disabled"
.PP
INCLUDECMD passes the rest of the line to \fBpopen\fR(3), meaning that
the command is executed by the shell. As such, shell metacharacters
may need escaping or arguments quoting, depending on what you're trying
to do. Remind itself does not perform any modification of the command
line (apart from the normal [expr] expression-pasting mechanism).
.PP
If the command passed to INCLUDECMD begins with an exclamation mark "!",
then Remind disables \fBRUN\fR for the output of the command. If you are
running a command whose output you don't quite trust, you should
prefix it with "!" so that any RUN commands it emits fail.
.PP
An \fBINCLUDECMD\fR command counts towards the INCLUDE nesting depth.
For any given Remind run, a given INCLUDECMD command is only executed
once and the results are cached. For example, if you generate a
calendar, each unique INCLUDECMD command is run just once, not once
for each day of the produced calendar. "Uniqueness" is determined by
looking at the command that will be passed to the shell, so if (for example)
your INCLUDECMD uses expression-pasting that results in differences depending
on the value of \fBtoday()\fR, then each \fIunique\fR version of the
command will be executed once.
.PP
.SH THE BANNER COMMAND
.PP
When \fBRemind\fR first issues a reminder, it prints a message like this:
@@ -2851,6 +2911,23 @@ If \fImaxlen\fR is specified, then \fBshell()\fR returns the first
\fImaxlen\fR is specified as a negative number, then \fIall\fR the
output from \fIcmd\fR is returned.
.RE
.TP
.B shellescape(s_str)
Returns \fIstr\fR with all shell metacharacters such as " ", "*", etc
escaped with a backslash. For example:
.PP
.nf
SET a shellescape("a b*? c&d$e")
.fi
.RS
.PP
will set \fBa\fR to:
.RE
.PP
.nf
"a\\ b\\*\\?\\ c\\&d\\$e"
.fi
.TP
.B slide(d_start, i_amt [,s_wkday...])
This function is the inverse of \fBnonomitted\fR. It adds \fIamt\fR

29
rem2html/Makefile.in Normal file
View File

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

12
rem2html/README.rem2html Normal file
View File

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

View File

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

View File

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

View File

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

View File

@@ -1005,8 +1005,8 @@ proc FillCalWindow {} {
ConfigureCalWindow $monthName $year $firstWkday $daysInMonth
set offset [CalEntryOffset $firstWkday]
set fntag "x"
while { [gets $file line] >= 0 } {
set fntag "x"
# Ignore unless begins with left brace
if { ! [string match "\{*" $line]} {
continue
@@ -1017,7 +1017,11 @@ proc FillCalWindow {} {
}
if {[dict exists $obj filename]} {
set fntag [string cat "FILE_" [dict get $obj lineno] "_" [dict get $obj filename]]
set fname [dict get $obj filename]
# Don't make INCLUDECMD output editable
if {![string match "*|" $fname]} {
set fntag [string cat "FILE_" [dict get $obj lineno] "_" $fname]
}
}
set date [dict get $obj date]
@@ -1087,13 +1091,17 @@ proc FillCalWindow {} {
continue
}
.cal.t$n configure -state normal
if {[regexp {TKTAG([0-9]+)} $tag all tagno]} {
if {[regexp {TKTAG([0-9]+)} $tag all tagno] && "$fntag" != "x"} {
.cal.t$n insert end [string trim $stuff] [list REM TAGGED "TKTAG$tagno" "date_$date" $extratags $fntag]
.cal.t$n tag bind "TKTAG$tagno" <Enter> "TaggedEnter .cal.t$n"
.cal.t$n tag bind "TKTAG$tagno" <Leave> "TaggedLeave .cal.t$n"
set TagToObj(TKTAG$tagno) $obj
} else {
.cal.t$n insert end [string trim $stuff] [list REM $extratags $fntag]
if {"$fntag" == "x" } {
.cal.t$n insert end [string trim $stuff] [list REM $extratags]
} else {
.cal.t$n insert end [string trim $stuff] [list REM $extratags $fntag]
}
}
.cal.t$n insert end "\n"
.cal.t$n configure -state disabled
@@ -1837,6 +1845,7 @@ proc ModifyDay {d firstDay} {
set oldFocus [focus]
while {1} {
grab .mod
raise .mod
focus .mod.entry
set ModifyDialogResult -1
tkwait variable ModifyDialogResult
@@ -1983,7 +1992,7 @@ proc CreateReminder {w} {
# Check it out!
global Remind
set f [open "|$Remind -arq -e -" r+]
set f [open "|$Remind -arq -e - 2>&1" r+]
puts $f "BANNER %"
puts $f "$rem MSG %"
puts $f "MSG %_%_%_%_"
@@ -2001,13 +2010,17 @@ proc CreateReminder {w} {
return $rem
}
# We used to return YYYY-MM-DD, but reverted to
# day monthname year because this lets Remind produce
# much better error messages.
proc consolidate {y m d} {
global MonthNames
if {![regexp {^[0-9]+$} $m]} {
set m [lsearch -exact $MonthNames $m]
incr m
}
return [format "%04d-%02d-%02d" $y $m $d]
set mname [lindex $MonthNames [expr $m-1]]
return "$d $mname $y"
}
#---------------------------------------------------------------------------
@@ -2804,7 +2817,7 @@ proc ReadTaggedOptions { tag date } {
lappend ans -text-day2 $d
}
if {[dict exists $obj m]} {
set mm [dict get $obj m]
set m [dict get $obj m]
set mm [string trimleft $m 0]
lappend ans -text-mon1 [lindex $MonthNames [expr $mm -1]]
lappend ans -text-mon2 [lindex $MonthNames [expr $mm -1]]
@@ -3194,6 +3207,7 @@ proc EditTaggedReminder { w } {
tkwait visibility .mod
set oldFocus [focus]
while {1} {
raise .mod
grab .mod
focus .mod.entry
set ModifyDialogResult -1

View File

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

View File

@@ -5,7 +5,7 @@
/* The code for generating a calendar. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -268,7 +268,7 @@ void PrintJSONKeyPairInt(char const *name, int val)
{
printf("\"");
PrintJSONString(name);
printf("\":%d, ", val);
printf("\":%d,", val);
}
void PrintJSONKeyPairString(char const *name, char const *val)
@@ -282,7 +282,7 @@ void PrintJSONKeyPairString(char const *name, char const *val)
PrintJSONString(name);
printf("\":\"");
PrintJSONString(val);
printf("\", ");
printf("\",");
}
void PrintJSONKeyPairDate(char const *name, int jul)
@@ -295,7 +295,7 @@ void PrintJSONKeyPairDate(char const *name, int jul)
FromJulian(jul, &y, &m, &d);
printf("\"");
PrintJSONString(name);
printf("\":\"%04d-%02d-%02d\", ", y, m+1, d);
printf("\":\"%04d-%02d-%02d\",", y, m+1, d);
}
@@ -313,7 +313,7 @@ void PrintJSONKeyPairDateTime(char const *name, int dt)
i = k % 60;
printf("\"");
PrintJSONString(name);
printf("\":\"%04d-%02d-%02dT%02d:%02d\", ", y, m+1, d, h, i);
printf("\":\"%04d-%02d-%02dT%02d:%02d\",", y, m+1, d, h, i);
}
@@ -328,7 +328,7 @@ void PrintJSONKeyPairTime(char const *name, int t)
i = t % 60;
printf("\"");
PrintJSONString(name);
printf("\":\"%02d:%02d\", ", h, i);
printf("\":\"%02d:%02d\",", h, i);
}
@@ -797,7 +797,7 @@ static int WriteCalendarRow(void)
PrintLeft("", ColSpaces, ' ');
else {
sprintf(buf, "%d ", d+i-wd);
if (OrigJul+i == RealToday) {
if (Julian(y, m, d+i-wd) == RealToday) {
PrintLeft(buf, ColSpaces-1, '*');
PutChar(' ');
} else {
@@ -1239,6 +1239,7 @@ static void GenerateCalEntries(int col)
case T_Else: r=DoElse(&p); break;
case T_EndIf: r=DoEndif(&p); break;
case T_Include: r=DoInclude(&p); break;
case T_IncludeCmd: r=DoIncludeCmd(&p); break;
case T_Exit: DoExit(&p); break;
case T_Set: r=DoSet(&p); break;
case T_Fset: r=DoFset(&p); break;
@@ -1664,7 +1665,9 @@ static int DoCalRem(ParsePtr p, int col)
if(!e->filename) {
if (e->text) free(e->text);
if (e->raw_text) free(e->raw_text);
#ifdef REM_USE_WCHAR
if (e->wc_text) free(e->wc_text);
#endif
free(e);
return E_NO_MEM;
}
@@ -1753,7 +1756,7 @@ static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
printf("\"%s\"", EnglishDayName[i]);
}
}
printf("], ");
printf("],");
}
if (e->trig.d != NO_DAY) {
PrintJSONKeyPairInt("d", e->trig.d);
@@ -1806,7 +1809,7 @@ static void WriteSimpleEntryProtocol2(CalEntry *e, int today)
printf("\"%s\"", EnglishDayName[i]);
}
}
printf("], ");
printf("],");
}
PrintJSONKeyPairDate("until", e->trig.until);
if (e->trig.once != NO_ONCE) {
@@ -1875,7 +1878,7 @@ static void WriteSimpleEntries(int col, int jul)
}
}
DidADay = 1;
printf("{\"date\":\"%04d-%02d-%02d\", ", y, m+1, d);
printf("{\"date\":\"%04d-%02d-%02d\",", y, m+1, d);
WriteSimpleEntryProtocol2(e, jul);
printf("}");
if (PsCal != PSCAL_LEVEL3) {

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,7 @@
/* commands. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -24,10 +24,6 @@
#include "protos.h"
#include "expr.h"
/* Define the shell characters not to escape */
static char const DontEscapeMe[] =
"1234567890_-=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.,";
static int ParseTimeTrig (ParsePtr s, TimeTrig *tim, int save_in_globals);
static int ParseLocalOmit (ParsePtr s, Trigger *t);
static int ParseScanFrom (ParsePtr s, Trigger *t, int type);
@@ -1230,24 +1226,16 @@ int DoMsgCommand(char const *cmd, char const *msg)
DynamicBuffer execBuffer;
DynamicBuffer buf;
char const *s;
DBufInit(&buf);
DBufInit(&execBuffer);
/* Escape shell characters in msg INCLUDING WHITESPACE! */
for (s=msg; *s; s++) {
if (isspace(*s) || !strchr(DontEscapeMe, *s)) {
if (DBufPutc(&buf, '\\') != OK) {
r = E_NO_MEM;
goto finished;
}
}
if (DBufPutc(&buf, *s) != OK) {
r = E_NO_MEM;
goto finished;
}
/* Escape shell characters in msg */
if (ShellEscape(msg, &buf) != OK) {
r = E_NO_MEM;
goto finished;
}
msg = DBufValue(&buf);
/* Do "%s" substitution */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@
/* expressions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -151,6 +151,7 @@ static int FWeekno (func_info *);
static int FWkday (func_info *);
static int FWkdaynum (func_info *);
static int FYear (func_info *);
static int FShellescape (func_info *);
static int CleanUpAfterFunc (func_info *);
static int CheckArgs (BuiltinFunc *f, int nargs);
@@ -267,6 +268,7 @@ BuiltinFunc Func[] = {
{ "realtoday", 0, 0, 0, FRealtoday },
{ "sgn", 1, 1, 1, FSgn },
{ "shell", 1, 2, 0, FShell },
{ "shellescape", 1, 1, 1, FShellescape },
{ "slide", 2, NO_MAX, 0, FSlide },
{ "strlen", 1, 1, 1, FStrlen },
{ "substr", 2, 3, 1, FSubstr },
@@ -1072,6 +1074,28 @@ static int FOstype(func_info *info)
return RetStrVal("UNIX", info);
}
/***************************************************************/
/* */
/* FShellescape - escape shell meta-characters */
/* */
/***************************************************************/
static int FShellescape(func_info *info)
{
DynamicBuffer buf;
int r;
ASSERT_TYPE(0, STR_TYPE);
DBufInit (&buf);
if (ShellEscape(ARG(0).v.str, &buf) != OK) {
DBufFree(&buf);
return E_NO_MEM;
}
r = RetStrVal(DBufValue(&buf), info);
DBufFree(&buf);
return r;
}
/***************************************************************/
/* */
/* FUpper - convert string to upper-case */

View File

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

View File

@@ -7,7 +7,7 @@
/* MK_GLOBALS. Also contains useful macro definitions. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -21,6 +21,12 @@
#define INIT(var, val) var
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#define MAX_TRUSTED_USERS 20
#define MINUTES_PER_DAY 1440
#define DaysInYear(y) (((y) % 4) ? 365 : ((!((y) % 100) && ((y) % 400)) ? 365 : 366 ))
@@ -36,6 +42,9 @@ EXTERN int CurMon;
EXTERN int CurYear;
EXTERN int LineNo;
EXTERN int FreshLine;
EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
EXTERN INIT( int NumTrustedUsers, 0);
EXTERN INIT( char const *MsgCommand, NULL);
EXTERN INIT( int ShowAllErrors, 0);
EXTERN INIT( int DebugFlag, 0);

View File

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

View File

@@ -7,7 +7,7 @@
/* in normal mode. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -89,6 +89,7 @@ static void ChgUser(char const *u);
static void InitializeVar(char const *str);
static char const *BadDate = "Illegal date on command line\n";
static void AddTrustedUser(char const *username);
static DynamicBuffer default_filename_buf;
@@ -114,7 +115,7 @@ static char const *DefaultFilename(void)
s = getenv("HOME");
if (!s) {
fprintf(stderr, "HOME environment variable not set. Unable to determine reminder file.\n");
exit(1);
exit(EXIT_FAILURE);
}
DBufPuts(&default_filename_buf, s);
DBufPuts(&default_filename_buf, "/.reminders");
@@ -172,7 +173,7 @@ void InitRemind(int argc, char const *argv[])
if (getgid() != getegid() ||
getuid() != geteuid()) {
fprintf(ErrFp, "\nRemind should not be installed set-uid or set-gid.\nCHECK YOUR SYSTEM SECURITY.\n");
exit(1);
exit(EXIT_FAILURE);
}
y = NO_YR;
@@ -183,7 +184,7 @@ void InitRemind(int argc, char const *argv[])
RealToday = SystemDate(&CurYear, &CurMon, &CurDay);
if (RealToday < 0) {
fprintf(ErrFp, ErrMsg[M_BAD_SYS_DATE], BASE);
exit(1);
exit(EXIT_FAILURE);
}
JulianToday = RealToday;
FromJulian(JulianToday, &CurYear, &CurMon, &CurDay);
@@ -217,6 +218,10 @@ void InitRemind(int argc, char const *argv[])
}
while (*arg) {
switch(*arg++) {
case '+':
AddTrustedUser(arg);
while(*arg) arg++;
break;
case '@':
UseVTColors = 1;
@@ -330,8 +335,12 @@ void InitRemind(int argc, char const *argv[])
case 'u':
case 'U':
ChgUser(arg);
RunDisabled = RUN_CMDLINE;
if (*arg == '+') {
ChgUser(arg+1);
} else {
RunDisabled = RUN_CMDLINE;
ChgUser(arg);
}
while (*arg) arg++;
break;
case 'z':
@@ -535,7 +544,7 @@ void InitRemind(int argc, char const *argv[])
if (!InvokedAsRem) {
if (i >= argc) {
Usage();
exit(1);
exit(EXIT_FAILURE);
}
InitialFile = argv[i++];
} else {
@@ -649,7 +658,7 @@ void InitRemind(int argc, char const *argv[])
#ifndef L_USAGE_OVERRIDE
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2020 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
@@ -682,7 +691,7 @@ void Usage(void)
fprintf(ErrFp, " -m Start calendar with Monday rather than Sunday\n");
fprintf(ErrFp, " -y Synthesize tags for tagless reminders\n");
fprintf(ErrFp, " -j[n] Run in 'purge' mode. [n = INCLUDE depth]\n");
exit(1);
exit(EXIT_FAILURE);
}
#endif /* L_USAGE_OVERRIDE */
/***************************************************************/
@@ -711,23 +720,23 @@ static void ChgUser(char const *user)
if (!pwent) {
fprintf(ErrFp, ErrMsg[M_BAD_USER], user);
exit(1);
exit(EXIT_FAILURE);
}
if (!myuid && setgid(pwent->pw_gid)) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_GID], pwent->pw_gid);
exit(1);
exit(EXIT_FAILURE);
}
if (!myuid && setuid(pwent->pw_uid)) {
fprintf(ErrFp, ErrMsg[M_NO_CHG_UID], pwent->pw_uid);
exit(1);
exit(EXIT_FAILURE);
}
home = malloc(strlen(pwent->pw_dir) + 6);
if (!home) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(home, "HOME=%s", pwent->pw_dir);
putenv(home);
@@ -735,7 +744,7 @@ static void ChgUser(char const *user)
shell = malloc(strlen(pwent->pw_shell) + 7);
if (!shell) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(shell, "SHELL=%s", pwent->pw_shell);
putenv(shell);
@@ -744,14 +753,14 @@ static void ChgUser(char const *user)
username = malloc(strlen(pwent->pw_name) + 6);
if (!username) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(username, "USER=%s", pwent->pw_name);
putenv(username);
logname= malloc(strlen(pwent->pw_name) + 9);
if (!logname) {
fprintf(ErrFp, "%s", ErrMsg[M_NOMEM_ENV]);
exit(1);
exit(EXIT_FAILURE);
}
sprintf(logname, "LOGNAME=%s", pwent->pw_name);
putenv(logname);
@@ -838,6 +847,25 @@ static void InitializeVar(char const *str)
return;
}
static void
AddTrustedUser(char const *username)
{
struct passwd *pwent;
if (NumTrustedUsers >= MAX_TRUSTED_USERS) {
fprintf(stderr, "Too many trusted users (%d max)\n",
MAX_TRUSTED_USERS);
exit(EXIT_FAILURE);
}
pwent = getpwnam(username);
if (!pwent) {
fprintf(ErrFp, ErrMsg[M_BAD_USER], username);
exit(EXIT_FAILURE);
}
TrustedUsers[NumTrustedUsers] = pwent->pw_uid;
NumTrustedUsers++;
}
#if defined(__APPLE__) || defined(__CYGWIN__)
static char const pmsg1[] = {
0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20,

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,7 +11,7 @@
/* */
/* This file is part of REMIND. */
/* This file is Copyright (C) 1993-1998 by Mikko Silvonen. */
/* REMIND is Copyright (C) 1992-2020 by Dianne Skoll */
/* REMIND is Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -527,7 +527,7 @@ EXTERN char *ErrMsg[] =
#define L_USAGE_OVERRIDE 1
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2020 Dianne Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-2021 Dianne Skoll\n", VERSION, L_LANGNAME);
#ifdef BETA
fprintf(ErrFp, ">>>> BETAVERSIO <<<<\n");
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@
/* routines, etc. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -243,6 +243,15 @@ static void DoReminders(void)
r=DoInclude(&p);
purge_handled = 1;
break;
case T_IncludeCmd:
/* In purge mode, include closes file, so we
need to echo it here! */
if (PurgeMode) {
PurgeEchoLine("%s\n", CurLine);
}
r=DoIncludeCmd(&p);
purge_handled = 1;
break;
case T_Exit: DoExit(&p); break;
case T_Flush: r=DoFlush(&p); break;
case T_Set: r=DoSet(&p); break;

View File

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

View File

@@ -6,7 +6,7 @@
/* the data structures for OMITted dates. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

@@ -5,7 +5,7 @@
/* Function Prototypes. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -45,6 +45,7 @@ int CopyValue (Value *dest, const Value *src);
int ReadLine (void);
int OpenFile (char const *fname);
int DoInclude (ParsePtr p);
int DoIncludeCmd (ParsePtr p);
int IncludeFile (char const *fname);
int GetAccessDate (char const *file);
int SetAccessDate (char const *fname, int jul);
@@ -161,3 +162,4 @@ void PrintJSONKeyPairDate(char const *name, int jul);
void PrintJSONKeyPairDateTime(char const *name, int dt);
void PrintJSONKeyPairTime(char const *name, int t);
void System(char const *cmd);
int ShellEscape(char const *in, DynamicBuffer *out);

View File

@@ -5,7 +5,7 @@
/* Queue up reminders for subsequent execution. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/

View File

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

View File

@@ -6,7 +6,7 @@
/* classifying the tokens parsed. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -62,6 +62,7 @@ Token TokArray[] = {
{ "if", 2, T_If, 0 },
{ "iftrig", 6, T_IfTrig, 0 },
{ "include", 3, T_Include, 0 },
{ "includecmd", 10, T_IncludeCmd, 0 },
{ "january", 3, T_Month, 0 },
{ "july", 3, T_Month, 6 },
{ "june", 3, T_Month, 5 },
@@ -172,6 +173,10 @@ void FindToken(char const *s, Token *tok)
int top, bot, mid, r, max;
int l;
#if LANG != ENGLISH
size_t i;
#endif
tok->type = T_Illegal;
if (! *s) {
tok->type = T_Empty;
@@ -229,11 +234,11 @@ void FindToken(char const *s, Token *tok)
/* If language is other than English, search the DayNames[] and MonthNames[]
array. */
#if LANG != ENGLISH
for (size_t x=0; x<(sizeof(NonEnglishToks) / sizeof(Token)); x++) {
if (l >= NonEnglishToks[x].MinLen &&
!TokStrCmp(&NonEnglishToks[x], s)) {
tok->type = NonEnglishToks[x].type;
tok->val = NonEnglishToks[x].val;
for (i=0; i<(sizeof(NonEnglishToks) / sizeof(Token)); i++) {
if (l >= NonEnglishToks[i].MinLen &&
!TokStrCmp(&NonEnglishToks[i], s)) {
tok->type = NonEnglishToks[i].type;
tok->val = NonEnglishToks[i].val;
return;
}
}

View File

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

View File

@@ -5,7 +5,7 @@
/* Type definitions all dumped here. */
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-2020 by Dianne Skoll */
/* Copyright (C) 1992-2021 by Dianne Skoll */
/* */
/***************************************************************/
@@ -150,7 +150,7 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
enum TokTypes
{ T_Illegal,
/* Commands first */
T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_If, T_Else, T_EndIf,
T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_IncludeCmd, T_If, T_Else, T_EndIf,
T_IfTrig, T_ErrMsg,
T_Set, T_UnSet, T_Fset, T_Omit, T_Banner, T_Exit,
T_WkDay,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -15,9 +15,40 @@ REM Wed UNTIL 15 Feb 1991 SATISFY [trigdate() > '1990-01-01'] MSG wookie
# bad AT
REM AT 0:00 0:01 0:02 MSG foo
# Includecmd
INCLUDECMD echo REM 16 Feb 1991 MSG Blork
INCLUDECMD echo REM 18 Feb 1991 MSG Blork
# Includecmd with continuation line
INCLUDECMD echo REM 18 Feb 1991 MSG This line is \
continued so there
# This should work
INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo MSG Yippee
# This should fail
INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo MSG Yippee
REM MSG Today is [hebday(today())] [hebmon(today())] [hebyear(today())]
fset _h(x, y) trigger(hebdate(x,y))
# Test case from Remind mailing list
set mltest "a b"
INCLUDECMD printf 'REM %s\n' [mltest]
# Disabling RUN in an !includecmd
INCLUDECMD !echo MSG foo
INCLUDECMD !echo MSG foo
INCLUDECMD !echo INCLUDECMD echo MSG foo
INCLUDECMD !echo INCLUDECMD echo MSG foo
INCLUDECMD !echo MSG foo
INCLUDECMD !echo MSG foo
# INCLUDECMD with RUN disabled
RUN OFF
INCLUDECMD echo MSG foo
RUN ON
INCLUDECMD echo MSG foo
[_h(1, "Tishrey")] MSG Rosh Hashana 1
[_h(2, "Tishrey")] MSG Rosh Hashana 2
[_h(3, "Tishrey")] MSG Tzom Gedalia
@@ -551,8 +582,15 @@ set a $IntMin * 2
set a $IntMin * $IntMin
set a $IntMin * $IntMax
set a $IntMin / (-1)
set a $IntMin * (-1)
set a (-1) * $IntMin
set a abs($IntMin)
# Shellescape
set a shellescape(" !\"#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")
msg [a]
# Don't want Remind to queue reminders
EXIT

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -49,6 +49,10 @@ div.rem-daynumber {
font-size: 14pt;
}
p.rem-entry {
clear: both;
}
div.rem-moon {
float: left;
text-align: left;
@@ -66,4 +70,4 @@ td.rem-sc-empty-cell, td.rem-sc-cell {
caption.rem-sc-caption {
font-size: 12pt;
}
}