Compare commits

...

60 Commits

Author SHA1 Message Date
David F. Skoll
de4ebb8be6 Update WHATSNEW. 2010-10-30 17:13:17 -04:00
David F. Skoll
11e2ce5093 Document multiple tag clauses. 2010-10-29 13:09:12 -04:00
David F. Skoll
2c560e6f2b Merge branches 'master' and 'master' of ssh://vanadium.roaringpenguin.com/home/dfs/personal-git-repos/Remind 2010-10-24 14:15:01 -04:00
David F. Skoll
643f394e6a Bug fix: If there are no tags, emit a "*" when doing NOTE reminder ... 2010-10-12 15:39:08 -04:00
David F. Skoll
6d047c2856 Use a dynamic buffer to accumulate tags instead of a special-purpose data structure. 2010-09-29 14:07:14 -04:00
David F. Skoll
be86746685 Support multiple TAGs in a single REM. 2010-09-23 15:47:22 -04:00
David F. Skoll
da429b9629 Avoid leaving running processes in the background when doing "make test" 2010-09-16 12:46:06 -04:00
David F. Skoll
b21a206c26 Fix token comparisons to be case-insensitive. 2010-09-13 20:17:02 -04:00
David F. Skoll
85bde8ba3a Make PrintCentered handle multi-byte characters. 2010-09-13 10:11:28 -04:00
David F. Skoll
f84e658e6b Update remind.vim to latest. 2010-09-12 12:48:39 -04:00
David F. Skoll
8f0eba8bcd Fix corner (UTF-8 had a typo.) 2010-09-10 17:37:49 -04:00
David F. Skoll
2faaaf78a8 Add support for UTF-8 line-drawing characters. 2010-09-10 10:18:22 -04:00
David F. Skoll
7f659dace2 Add support for multibyte chars in -c output. But that breaks line-drawing. :( 2010-09-09 17:17:18 -04:00
David F. Skoll
54cdd566c7 Shrink executable on non-Apple/non-MS platforms. 2010-09-02 15:30:56 -04:00
David F. Skoll
e212df87f9 Bump version to 03.01.10. 2010-09-01 17:15:37 -04:00
David F. Skoll
4fb4db15e8 Stricter syntax check - reject extra cruft afer "OMIT DUMP" 2010-09-01 17:12:55 -04:00
David F. Skoll
9a15a25a7b Don't hard-code text box background. 2010-09-01 12:07:41 -04:00
David F. Skoll
c02cfb9b17 Add THROUGH keyword to editor syntax files. 2010-08-31 16:57:27 -04:00
David F. Skoll
3e726f21f7 Improve error message. 2010-08-31 14:02:17 -04:00
David F. Skoll
21d4faa26f Allow OMIT ... THROUGH ... to be re-parsed as a REM command. 2010-08-31 13:51:13 -04:00
David F. Skoll
1d13d0ee07 Update tests to handle OMIT ... THROUGH ... 2010-08-31 13:44:57 -04:00
David F. Skoll
329d13e480 Fix typo 2010-08-31 13:34:55 -04:00
David F. Skoll
2161c09b1d Update man page. 2010-08-31 13:33:51 -04:00
David F. Skoll
3f2e396c3c Change "omit debug" to "omit dump" 2010-08-31 12:37:10 -04:00
David F. Skoll
412e242109 Don't create any OMITs with THROUGH if there would be too many.
Bump max full omits to 500 and partial omits to 366.
2010-08-31 12:27:23 -04:00
David F. Skoll
e827516b72 Add "OMIT start THROUGH end" syntax. Also add "OMIT DEBUG"
Add syntactic sugar:

REM start THROUGH end   is converted to REM start *1 UNTIL end
2010-08-31 12:19:08 -04:00
David F. Skoll
7f953e98d7 Clarify manual: Line continuations are processed before comments. 2010-08-20 13:47:51 -04:00
David F. Skoll
821d3fe783 Conform to older C spec that prohibits declaration of variables in the middle of a block. 2010-06-21 21:32:21 -04:00
David F. Skoll
fdb4b302ac Update WHATSNEW with release date. 2010-06-20 16:38:44 -04:00
David F. Skoll
760d5d4a09 Fix trap to reset signal disposition to default. 2010-06-02 09:05:11 -04:00
David F. Skoll
d561f98c42 Fix syntax error. 2010-05-18 20:45:36 -04:00
David F. Skoll
ea74f276dc Don't rkrphgvba more than once. 2010-05-18 12:46:34 -04:00
David F. Skoll
42cf82a5d5 More Apple / Cygwin detection. 2010-05-17 09:32:50 -04:00
David F. Skoll
825a6700da Make "trap" command follow POSIX standard. 2010-05-17 06:59:41 -04:00
David F. Skoll
2f27645dac Handle SPECIAL COLOR correctly with -n commandline option. 2010-05-01 20:52:25 -04:00
David F. Skoll
1e5b44d063 Make handling of continued lines same as in 3.1.8. 2010-04-25 10:07:12 -04:00
David F. Skoll
099ad9945d Fix huge bug in handling of continued lines. 2010-04-25 10:03:13 -04:00
David F. Skoll
540ce3d946 Allow "timepart" to take a TIME or DATETIME. Allow "datepart" to take a
DATE or DATETIME.  Update docs.
2010-04-25 09:50:39 -04:00
David F. Skoll
ac2efcc993 Document timepart() and datepart(). 2010-04-25 09:40:01 -04:00
David F. Skoll
b4bb1d9e37 Update copyright date. 2010-04-25 09:34:49 -04:00
David F. Skoll
9ec8b30934 Update copyright date. 2010-04-22 11:45:19 -04:00
David F. Skoll
fb38e5b35b Update WHATSNEW. 2010-04-21 16:01:04 -04:00
David F. Skoll
5fa10e9d84 Document Purge Mode. 2010-04-21 14:55:28 -04:00
David F. Skoll
3bc1b5bd46 Clean up tests; add test for non-parseable line in purge mode. 2010-04-21 13:30:10 -04:00
David F. Skoll
b266b399ba Test for fix of parse error.
Try REALLY hard to detect constant expressions...
2010-04-21 13:23:26 -04:00
David F. Skoll
0e827a457d Fix YomHashoah date and bug in DoSatReminder. 2010-04-21 09:49:33 -04:00
David F. Skoll
d05d85b243 More tests. 2010-04-21 09:04:48 -04:00
David F. Skoll
a1faa8d804 Finish up Purge Mode:
o Make it recognize constant expressions (yay!)
o Make it not add a blank line to end of *.purged files.
o Make it nuke #!P comments in the source files.
2010-04-21 09:02:25 -04:00
David F. Skoll
70adbf90c2 Add tests for purge mode. 2010-04-20 15:20:49 -04:00
David F. Skoll
501c04f4b6 More work on purge mode. 2010-04-20 14:01:54 -04:00
David F. Skoll
d294e62be1 More work on purge mode. 2010-04-20 11:34:07 -04:00
David F. Skoll
31f90b6c53 Add purge mode. 2010-04-20 10:59:57 -04:00
David F. Skoll
184d29c592 More work on -j ("Purge Mode") option. 2010-04-19 15:57:35 -04:00
David F. Skoll
2d798bc4ec Add support for DURATION in TkRemind. Patch from Marek Marczykowski. 2010-04-19 14:13:48 -04:00
David F. Skoll
bd9a3761a6 Sort PSFILE and PS reminders with same priority (Ticket #17581) 2010-04-19 13:17:00 -04:00
David F. Skoll
b1063b0a9e More purge-mode work. 2010-04-09 11:01:45 -04:00
David F. Skoll
cb2fffab92 Don't expire lines containing expressions. 2010-04-07 15:32:20 -04:00
David F. Skoll
55cca49428 Start implementing a "-j" mode to purge old reminders. 2010-04-07 15:30:29 -04:00
David F. Skoll
5a0ab9ed8a Fix shade.rem to be independent of location and time zone of test machine. 2010-03-10 11:14:36 -05:00
David F. Skoll
1f2cfdfd84 Bump version to 03.01.09. 2010-03-09 10:05:56 -05:00
48 changed files with 1802 additions and 538 deletions

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 1999-2008 Roaring Penguin Software Inc.,
2. REMIND is Copyright 1999-2010 Roaring Penguin Software Inc.,
except where noted in individual files.
3. DISTRIBUTION AND USE

View File

@@ -25,7 +25,7 @@ clean:
cd src; $(MAKE) clean
test:
cd src && $(MAKE) test
@cd src && $(MAKE) test
distclean: clean
rm -f config.cache config.log config.status src/Makefile src/config.h tests/test.out www/Makefile

18
configure vendored
View File

@@ -1702,8 +1702,8 @@ EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap INT
trap TERM
trap - INT
trap - TERM
fi
if uname -s | grep -i -q 'cygwin' ; then
@@ -1717,8 +1717,8 @@ EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap INT
trap TERM
trap - INT
trap - TERM
fi
ac_ext=c
@@ -4721,7 +4721,9 @@ _ACEOF
for ac_header in sys/file.h glob.h
for ac_header in sys/file.h glob.h wctype.h locale.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
@@ -5221,7 +5223,9 @@ fi
for ac_func in setenv unsetenv glob
for ac_func in setenv unsetenv glob mbstowcs setlocale
do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
{ echo "$as_me:$LINENO: checking for $ac_func" >&5
@@ -5314,7 +5318,7 @@ _ACEOF
fi
done
VERSION=03.01.08
VERSION=03.01.10
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h"

View File

@@ -25,8 +25,8 @@ EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap INT
trap TERM
trap - INT
trap - TERM
fi
if uname -s | grep -i -q 'cygwin' ; then
@@ -40,8 +40,8 @@ EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap INT
trap TERM
trap - INT
trap - TERM
fi
dnl Checks for programs.
@@ -61,7 +61,7 @@ AC_CHECK_SIZEOF(unsigned int)
AC_CHECK_SIZEOF(unsigned long)
dnl Checks for header files.
AC_CHECK_HEADERS(sys/file.h glob.h)
AC_CHECK_HEADERS(sys/file.h glob.h wctype.h locale.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_STRUCT_TM
@@ -74,7 +74,7 @@ if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wstrict-prototypes"
fi
AC_CHECK_FUNCS(setenv unsetenv glob)
VERSION=03.01.08
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale)
VERSION=03.01.10
AC_SUBST(VERSION)
AC_OUTPUT(src/Makefile www/Makefile src/version.h)

View File

@@ -109,7 +109,7 @@
(sort
(list "RUN" "REM" "ONCE" "SATISFY" "BEFORE" "UNSET" "OMIT"
"OMIT" "DATE" "SKIP" "ONCE" "AFTER" "WARN" "PRIORITY" "AT" "SCHED" "IF" "ELSE" "ENDIF"
"WARN" "UNTIL" "SCANFROM" "DURATION" "TAG" "MSG" "MSF" "CAL" "SPECIAL" "IFTRIG"
"WARN" "UNTIL" "THROUGH" "SCANFROM" "DURATION" "TAG" "MSG" "MSF" "CAL" "SPECIAL" "IFTRIG"
"PS" "PSFILE" "BANNER" "INCLUDE" "PUSH-OMIT-CONTEXT" "DEBUG" "DUMPVARS"
"CLEAR-OMIT-CONTEXT" "POP-OMIT-CONTEXT" "SET" "ERRMSG" "FSET"
"EXIT" "FLUSH" "PRESERVE" "MOON" "COLOR")

View File

@@ -1,5 +1,45 @@
CHANGES TO REMIND
* Version 3.1 Patch 10 - 2010-11-01
- NOTE: This is the 20th anniversary of Remind's first public release.
- ENHANCEMENT: Add the THROUGH keyword. You can omit blocks of dates with:
OMIT start THROUGH end
and the syntax REM start THROUGH end is equivalent to REM start *1 UNTIL end
- ENHANCEMENT: Add support for multibyte characters (eg, UTF-8) in calendar
output. Note that UTF-8 strings are still not supported in PostScript
output.
- ENHANCEMENT: Add support for UTF-8 line-drawing characters in calendar
output.
- ENHANCEMENT: You can have multiple TAG clauses in a REM statement.
- BUG FIX: Avoid spawning long-running background processes in "make test".
- BUG FIX: Don't declare variables in the middle of statements (old C
compilers choke.)
* Version 3.1 Patch 9 - 2010-06-20
- MAJOR ENHANCEMENT: New "purge mode" to delete expired reminders. See
the PURGE MODE section of the remind man page.
- ENHANCEMENT: Support DURATION in TkRemind. Thanks to Marek Marczykowski.
- BUG FIX: Don't change the order of PS and PSFILE reminders. Bug found
by John McGowan.
- BUG FIX: "REM 1990-01-01 SATISFY 1" would yield a spurious parse error
in earlier versions of Remind.
- BUG FIX: Yom HaShoah is moved to Thursday if it would normally fall on
a Friday. Thanks to Jonathan Kamens for pointing this out.
* Version 3.1 Patch 8 - 2010-03-09
- ENHANCEMENT: Include some useful scripts in contrib/

View File

@@ -508,7 +508,13 @@ IF !InIsrael && !Reform
[_h(22, "Nisan")] MSG %"Pesach 8%"
ENDIF
[_PastSun(27, "Nisan")] ++4 MSG %"Yom HaShoah%" is %b.
REM [_PastSun(27, "Nisan")] SATISFY 1
IF $Tw == 5
REM [_PastSun(26, "Nisan")] ++4 MSG %"Yom HaShoah%" is %b.
ELSE
REM [_PastSun(27, "Nisan")] ++4 MSG %"Yom HaShoah%" is %b.
ENDIF
# If 4 Iyar is a Friday, then Yom Hazikaron is
# the Wednesday before and Yom Ha'atzmaut is on

View File

@@ -1,53 +1,79 @@
" Vim syntax file
" Language: Remind
" Maintainer: Davide Alberani <alberanid@bigfoot.com>
" Last change: 03 Dec 1999
" Version: 0.1
" URL: http://members.xoom.com/alberanid/vim/syntax/remind.vim
" Maintainer: Davide Alberani <alberanid@libero.it>
" Last Change: 18 Sep 2009
" Version: 0.5
" URL: http://erlug.linux.it/~da/vim/syntax/remind.vim
"
" remind is a sophisticated reminder service
" you can download remind from ftp://ftp.doe.carleton.ca/pub/remind-3.0/
" you can download remind from:
" http://www.roaringpenguin.com/penguin/open_source_remind.php
" clear any unwanted syntax defs
syn clear
if version < 600
syntax clear
elseif exists("b:current_syntax")
finish
endif
" shut case off
" shut case off.
syn case ignore
syn keyword remindCommands REM OMIT SET FSET UNSET
syn keyword remindExpiry UNTIL SCANFROM SCAN WARN SCHED
syn keyword remindExpiry UNTIL FROM SCANFROM SCAN WARN SCHED
syn keyword remindTag PRIORITY TAG
syn keyword remindTimed AT DURATION
syn keyword remindMove ONCE SKIP BEFORE AFTER
syn keyword remindSpecial INCLUDE INC BANNER PUSH-OMIT-CONTEXT PUSH CLEAR-OMIT-CONTEXT CLEAR POP-OMIT-CONTEXT POP
syn keyword remindSpecial INCLUDE INC BANNER PUSH-OMIT-CONTEXT PUSH CLEAR-OMIT-CONTEXT CLEAR POP-OMIT-CONTEXT POP COLOR
syn keyword remindRun MSG MSF RUN CAL SATISFY SPECIAL PS PSFILE SHADE MOON
syn keyword remindConditional IF ELSE ENDIF IFTRIG
syn keyword remindDebug DEBUG DUMPVARS DUMP ERRMSG FLUSH PRESERVE
syn match remindComment "#.*$"
syn region remindString start=+'+ end=+'+ skip=+\\\\\|\\'+ oneline
syn region remindString start=+"+ end=+"+ skip=+\\\\\|\\"+ oneline
syn keyword remindDebug DEBUG DUMPVARS DUMP ERRMSG FLUSH PRESERVE
syn match remindVar "\$[_a-zA-Z][_a-zA-Z0-9]*"
syn match remindSubst "%[^ ]"
syn match remindAdvanceNumber "\(\*\|+\|-\|++\|--\)[0-9]\+"
" XXX: use different separators for dates and times?
syn match remindDateSeparators "[/:@\.-]" contained
syn match remindTimes "[0-9]\{1,2}[:\.][0-9]\{1,2}" contains=remindDateSeparators
" XXX: why not match only valid dates? Ok, checking for 'Feb the 30' would
" be impossible, but at least check for valid months and times.
syn match remindDates "'[0-9]\{4}[/-][0-9]\{1,2}[/-][0-9]\{1,2}\(@[0-9]\{1,2}[:\.][0-9]\{1,2}\)\?'" contains=remindDateSeparators
" This will match trailing whitespaces that seem to break rem2ps.
" Courtesy of Michael Dunn.
syn match remindWarning display excludenl "\S\s\+$"ms=s+1
if !exists("did_remind_syntax_inits")
let did_remind_syntax_inits = 1
hi link remindCommands Function
hi link remindExpiry Repeat
hi link remindTag Label
hi link remindTimed Statement
hi link remindMove Statement
hi link remindSpecial Include
hi link remindRun Function
hi link remindConditional Conditional
hi link remindComment Comment
hi link remindString String
hi link remindDebug Debug
hi link remindVar Identifier
hi link remindSubst Constant
hi link remindAdvanceNumber Number
if version >= 508 || !exists("did_remind_syn_inits")
if version < 508
let did_remind_syn_inits = 1
command -nargs=+ HiLink hi link <args>
else
command -nargs=+ HiLink hi def link <args>
endif
HiLink remindCommands Function
HiLink remindExpiry Repeat
HiLink remindTag Label
HiLink remindTimed Statement
HiLink remindMove Statement
HiLink remindSpecial Include
HiLink remindRun Function
HiLink remindConditional Conditional
HiLink remindComment Comment
HiLink remindTimes String
HiLink remindString String
HiLink remindDebug Debug
HiLink remindVar Identifier
HiLink remindSubst Constant
HiLink remindAdvanceNumber Number
HiLink remindDateSeparators Comment
HiLink remindDates String
HiLink remindWarning Error
delcommand HiLink
endif
let b:current_syntax = "remind"
"EOF vim: ts=8 noet tw=100 sw=8 sts=0
" vim: ts=8 sw=2

View File

@@ -362,7 +362,10 @@ Other back-ends may understand other specials. A back end should
\fIsilently ignore\fR a reminder with a special it doesn't understand.
.PP
\fItag\fR is whatever tag the user provided with the \fBTAG\fR clause,
or "*" if no tag was provided.
or "*" if no tag was provided. If there is more than one \fBTAG\fR clause,
the tags appear in a comma-separated list. For example, the command
\fBREM TAG foo TAG bar TAG quux\fR would result in \fBfoo,bar,quux\fR
in the \fItag\fR field.
.PP
\fIdur\fR is the \fBDURATION\fR value in minutes, or "*" if no duration
was provided.

View File

@@ -29,6 +29,10 @@ 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.
.TP
.B \-j\fR[\fIn\fR]
Runs \fBRemind\fR in "purge" mode to get rid of expired reminders.
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.
@@ -57,6 +61,11 @@ causes \fBRemind\fR to use VT100 line-drawing characters to draw
the calendar. The characters are hard-coded and will only work
on terminals that emulate the VT00 line-drawing character set.
.TP
.B 'u'
is similar to 'l', but causes \fBRemind\fR to use UNICODE line-drawing
characters to draw the calendar. The characters are hard-coded and will
only work on terminals that are set to UTF-8 character encoding.
.TP
.B 'c'
causes \fBRemind\fR to use VT100 escape sequences to approximate
SPECIAL COLOR reminders. The approximation is (of necessity) very
@@ -326,6 +335,16 @@ wish to pass a \fBRemind\fR script through the C pre-processor, which
interprets the '#' character as the start of a pre-processing
directive.
.PP
Note that \fBRemind\fR processes line continuations before anything else.
For example:
.PP
.nf
# This is a comment \\
This line is part of the comment because of line continuation \\
and so on.
REM MSG This line is not ignored (no \\ above)
.fi
.PP
\fBRemind\fR is not case sensitive; you can generally use any mixture of upper-
or lower-case for commands, parameters, invocation options, etc.
.SH THE REM COMMAND
@@ -346,7 +365,7 @@ Its syntax is:
[\fBAT\fR \fItime\fR [\fItdelta\fR] [\fItrepeat\fR]]
[\fBSCHED\fR \fIsched_function\fR]
[\fBWARN\fR \fIwarn_function\fR]
[\fBUNTIL\fR \fIexpiry_date\fR]
[\fBUNTIL\fR \fIexpiry_date\fR | \fBTHROUGH\fR \fIlast_date\fR]
[\fBSCANFROM\fR \fIscan_date\fR | \fBFROM\fR \fIstart_date\fR]
[\fBDURATION\fR \fIduration\fR]
[\fBTAG\fR \fItag\fR]
@@ -782,6 +801,15 @@ of your jury duty, as well as 2 days ahead of time:
Note that the \fIrepeat\fR of *1 is necessary; without it, the reminder
would be issued only on 30 November (and the two days preceding.)
.PP
As a special case, you can use the \fBTHROUGH\fR keyword instead of
*1 and \fBUNTIL\fR. The following two \fBREM\fR commands are equivalent:
.PP
.nf
REM 1992-11-30 *1 +2 UNTIL 1992-12-04 MSG Jury duty
REM 1992-11-30 +2 THROUGH 1992-12-04 MSG Jury duty
.fi
.PP
.B THE ONCE KEYWORD
.PP
Sometimes, it is necessary to ensure that reminders are run only once
@@ -985,11 +1013,11 @@ expressions and user-defined functions are explained. See the subsection
The \fBTAG\fR keyword lets you "tag" certain reminders. This facility
is used by certain back-ends or systems built around \fBRemind\fR,
such as \fBTkRemind\fR. These back-ends have specific rules about
tags; you should \fInot\fR use the \fBTAG\fR keyword yourself, or
your script will interact badly with back-ends.
tags; see their documentation for details.
.PP
The \fBTAG\fR keyword is followed by a tag consisting of up to
48 characters.
48 characters. You can have as many TAG clauses as you like in
a given REM statement.
.PP
If you supply the \fB\-y\fR option to \fBRemind\fR, then any
reminder that lacks a \fBTAG\fR will have one synthesized. The
@@ -1285,6 +1313,10 @@ In addition to being a keyword in the \fBREM\fR command,
.PP
.RS
\fBOMIT\fR \fIday\fR \fImonth\fR [\fIyear\fR]
.PP
or:
.PP
\fBOMIT\fR \fIday1\fR \fImonth1\fR \fIyear1\fR \fBTHROUGH\fR \fIday2\fR \fImonth2\fR \fIyear2\fR
.RE
.PP
The \fBOMIT\fR command is used to "globally" omit certain days
@@ -1312,7 +1344,7 @@ the following are equivalent:
.fi
.PP
For convenience, you can use a \fIdelta\fR and \fBMSG\fR or \fBRUN\fR
keyword in the \fBOMIT\fR command. The following sequences are exactly
keyword in the \fBOMIT\fR command. The following sequences are
equivalent:
.PP
.nf
@@ -1324,6 +1356,36 @@ equivalent:
OMIT 1 Jan +4 MSG New year's day is %b!
.fi
.PP
The \fBTHROUGH\fR keyword lets you conveniently OMIT a range of days.
The starting and ending points must be fully-specified (ie, they must
include day, month and year.). For example, the following sequences
are equivalent:
.PP
.nf
OMIT 3 Jan 2011
OMIT 4 Jan 2011
OMIT 5 Jan 2011
and
OMIT 3 Jan 2011 THROUGH 5 Jan 2011
.fi
.PP
You can make a THROUGH \fBOMIT\fR do double-duty as a \fBREM\fR command:
.PP
.nf
OMIT 6 Sep 2010 THROUGH 10 Sep 2010 MSG Vacation
.fi
.PP
You can debug your global OMITs with the following command:
.PP
.nf
OMIT DUMP
.fi
.PP
The OMIT DUMP command prints the current global omits to standard output.
.PP
.B THE BEFORE, AFTER AND SKIP KEYWORDS
.PP
Normally, days that are omitted, whether by a global \fBOMIT\fR
@@ -2148,6 +2210,10 @@ actual date and time, or may be the date and time supplied on the command line.
The \fBdate()\fR function returns a \fBDATE\fR object with the year,
month and day components specified by \fIy\fR, \fIm\fR and \fId\fR.
.TP
.B datepart(dq_datetime)
Returns a \fBDATE\fR object representing the date portion of
\fIdatetime\fR.
.TP
.B datetime(args)
The \fBdatetime()\fR function can take anywhere from two to five arguments.
It always returns a DATETIME generated from its arguments.
@@ -2295,6 +2361,18 @@ environment variable is not defined. Note that the names of environment
variables are generally case-sensitive; thus, getenv("HOME") is not
the same as getenv("home").
.TP
.B hebdate(i_day, s_hebmon [,idq_yrstart [,i_jahr [,i_aflag]]])
Support for Hebrew dates - see the section "The Hebrew Calendar"
.TP
.B hebday(dq_date)
Support for Hebrew dates - see the section "The Hebrew Calendar"
.TP
.B hebmon(dq_date)
Support for Hebrew dates - see the section "The Hebrew Calendar"
.TP
.B hebyear(dq_date)
Support for Hebrew dates - see the section "The Hebrew Calendar"
.TP
.B hour(tq_time)
Returns the hour component of \fItime\fR.
.TP
@@ -2338,18 +2416,6 @@ context. Returns 0 otherwise. (If a datetime is supplied, only the
date part is used.) Note that any local \fBOMIT\fR or \fBOMITFUNC\fR
clauses are \fInot\fR taken into account by this function.
.TP
.B hebdate(i_day, s_hebmon [,idq_yrstart [,i_jahr [,i_aflag]]])
Support for Hebrew dates - see the section "The Hebrew Calendar"
.TP
.B hebday(dq_date)
Support for Hebrew dates - see the section "The Hebrew Calendar"
.TP
.B hebmon(dq_date)
Support for Hebrew dates - see the section "The Hebrew Calendar"
.TP
.B hebyear(dq_date)
Support for Hebrew dates - see the section "The Hebrew Calendar"
.TP
.B language()
Returns a \fBSTRING\fR naming the language supported by \fBRemind\fR.
(See "Foreign Language Support.") By default, \fBRemind\fR is compiled
@@ -2680,6 +2746,10 @@ than 60 degrees. The functions are available starting from version
Creates a \fBTIME\fR with the hour and minute components specified by
\fIhr\fR and \fImin\fR.
.TP
.B timepart(tq_datetime)
Returns a \fBTIME\fR object representing the time portion of
\fIdatetime\fR.
.TP
.B today()
Returns \fBRemind\fR's notion of "today." This may be the actual system
date, or a date supplied on the command line, or the date of the
@@ -3626,7 +3696,68 @@ so to run in the daemon mode in the background, use:
.PP
If you use \fBsh\fR or \fBbash\fR, you may have to use the "nohup" command
to ensure that the daemon is not killed when you log out.
.PP
.SH PURGE MODE
.PP
If you supply the \fB\-j\fR command-line option, \fBRemind\fR runs
in \fIpurge mode\fR. In this mode, it tries to purge expired reminders
from your reminder files.
.PP
In purge mode, \fBRemind\fR reads your reminder file and creates a new
file by appending ".purged" to the original file name. Note that
\fBRemind\fR \fInever\fR edits your original file; it always creates
a new .purged file.
.PP
If you invoke \fBRemind\fR against a directory instead of a file, then
a .purged file is created for each *.rem file in the directory.
.PP
Normally, \fBRemind\fR does not create .purged files for INCLUDed files.
However, if you supply a numeric argument after \fB\-j\fR, then \fBRemind\fR
will create .purged files for the specified level of INCLUDE. For example,
if you invoke \fBRemind\fR with the argument \fB\-j2\fR, then .purged
files will be created for the file (or directory) specified on the command
line, any files included by them, and any files included by those files.
However, .purged files will not be created for third-or-higher level
INCLUDE files.
.PP
Determining which reminders have expired is extremely tricky. \fBRemind\fR
does its best, but you should always compare the .purged file to the
original file and hand-merge the changes back in.
.PP
Remind annotates the .purged file as follows:
.PP
An expired reminder is prefixed with: #!P: Expired:
.PP
In situations where \fBRemind\fR cannot reliably determine that
something was expired, you may see the following comments inserted
before the problematic line:
.PP
.nf
#!P: Cannot purge SATISFY-type reminders
#!P: The next IF evaluated false...
#!P: REM statements in IF block not checked for purging.
#!P: The previous IF evaluated true.
#!P: REM statements in ELSE block not checked for purging
#!P: The next IFTRIG did not trigger.
#!P: REM statements in IFTRIG block not checked for purging.
#!P: Next line has expired, but contains expression... please verify
#!P: Next line may have expired, but contains non-constant expression
#!P! Could not parse next line: Some-Error-Message-Here
.fi
.PP
\fBRemind\fR always annotates .purged files with lines beginning with
"#!P". If such lines are encountered in the \fIoriginal\fR file,
they are not copied to the .purged file.
.PP
.SH SORTING REMINDERS
.PP

View File

@@ -289,7 +289,9 @@ file to store additional state. You can certainly mix
if you are aware of the following rules and limitations:
.TP
o
Do not use the \fBTAG\fR keyword in hand-crafted reminders.
\fBTkRemind\fR uses \fBTAG\fRs of the form \fBTKTAG\fR\fInnn\fR
where \fInnn\fR is a number. You should not use such \fBTAG\fRs
in hand-crafted reminders.
.TP
o
Do not edit lines starting with "# TKTAGnnn", "# TKEND", or any

View File

@@ -8,7 +8,7 @@
#
# This file is part of REMIND.
# Copyright (C) 1992-1998 David F. Skoll
# Copyright (C) 1999-2009 Roaring Penguin Software Inc.
# Copyright (C) 1999-2010 Roaring Penguin Software Inc.
#
#--------------------------------------------------------------
@@ -392,11 +392,7 @@ proc ConfigureCalFrame { w firstDay numDays } {
set first [expr $offset+1]
set last [expr $offset+$numDays]
if {$tk_version >= 8.5} {
set bg "#d9d9d9"
} else {
set bg [lindex [$w.t0 configure -background] 3]
}
set bg [lindex [. configure -background] 3]
for {set i 0} {$i < $first} {incr i} {
grid $w.l$i $w.t$i
@@ -1155,12 +1151,13 @@ proc CreateModifyDialog {w day firstDay args} {
frame $w.exp -border 4
frame $w.adv -border 4
frame $w.weekend -border 4
frame $w.durationbox -border 4
frame $w.time -border 4
frame $w.hol -border 4
frame $w.msg
frame $w.buttons
pack $w.o1 $w.o2 $w.o3 -side top -anchor w -in $w.o
pack $w.o $w.exp $w.adv $w.weekend $w.time $w.hol $w.msg -side top -anchor w -pady 4 -expand 1 -fill both
pack $w.o $w.exp $w.adv $w.weekend $w.time $w.durationbox $w.hol $w.msg -side top -anchor w -pady 4 -expand 1 -fill both
pack $w.buttons -side top -anchor w -pady 4 -expand 1 -fill x
# TYPE 1 REMINDER
@@ -1301,6 +1298,22 @@ proc CreateModifyDialog {w day firstDay args} {
pack $w.timebut $w.timehour $w.timemin $w.ampm $w.timeadvbut $w.timeadv $w.timelab1 $w.timerepbut $w.timerep $w.timelab2 -side left -anchor w -in $w.time
}
# DURATION
checkbutton $w.durationbut -text "Duration"
$w.durationbut deselect
menubutton $w.durationh -text "1" -menu $w.durationh.menu -relief raised
menu $w.durationh.menu -tearoff 0
foreach i {0 1 2 3 4 5 6 7 8 9 10 11 12} {
$w.durationh.menu add command -label $i -command "$w.durationh configure -text $i"
}
label $w.durationcolon -text ":"
menubutton $w.durationm -text "00" -menu $w.durationm.menu -relief raised
menu $w.durationm.menu -tearoff 0
foreach i {00 15 30 45} {
$w.durationm.menu add command -label $i -command "$w.durationm configure -text $i"
}
pack $w.durationbut $w.durationh $w.durationcolon $w.durationm -side left -anchor w -in $w.durationbox
# SKIP TYPE
label $w.labhol -text "On holidays or weekends:"
radiobutton $w.issue -variable SkipType -value 1 -text "Issue reminder as usual"
@@ -1343,7 +1356,7 @@ proc CreateModifyDialog {w day firstDay args} {
#***********************************************************************
proc RemindDialogToOptions { w } {
global OptionType SkipType repbut expbut advbut advcount
global timebut timeadvbut timerepbut
global timebut timeadvbut timerepbut durationbut
global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday
set ans {}
lappend ans "-global-OptionType" $OptionType
@@ -1377,7 +1390,7 @@ proc RemindDialogToOptions { w } {
#***********************************************************************
proc OptionsToRemindDialog { w opts } {
global OptionType SkipType repbut expbut advbut advcount
global timebut timeadvbut timerepbut TwentyFourHourMode
global timebut timeadvbut timerepbut TwentyFourHourMode durationbut
global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday
set hour ""
set ampm ""
@@ -1589,7 +1602,7 @@ proc CreateReminder {w} {
# Delegate the first part to CreateReminder1, CreateReminder2, or
# CreateReminder3
global OptionType SkipType repbut expbut advbut advcount
global timebut timeadvbut timerepbut
global timebut timeadvbut timerepbut durationbut
set rem [CreateReminder$OptionType $w]
@@ -1631,6 +1644,9 @@ proc CreateReminder {w} {
if {$timerepbut} {
append rem " *[$w.timerep cget -text]"
}
if {$durationbut} {
append rem " DURATION [$w.durationh cget -text]:[$w.durationm cget -text]"
}
}
global SkipType
@@ -2303,7 +2319,7 @@ proc main {} {
global AppendFile HighestTagSoFar DayNames
catch {
puts "\nTkRemind Copyright (C) 1996-1998 David F. Skoll"
puts "Copyright (C) 1999-2009 Roaring Penguin Software Inc."
puts "Copyright (C) 1999-2010 Roaring Penguin Software Inc."
}
catch { SetFonts }
LoadOptions

View File

@@ -38,7 +38,7 @@ REMINDOBJS= $(REMINDSRCS:.c=.o)
all: remind rem2ps
test: remind
sh ../tests/test-rem
@sh ../tests/test-rem
.c.o:
@CC@ -c @CFLAGS@ @DEFS@ $(CEXTRA) $(LANGDEF) -I. -I$(srcdir) $<

View File

@@ -18,6 +18,10 @@
#include <stdlib.h>
#ifdef REM_USE_WCHAR
#include <wctype.h>
#endif
#include "types.h"
#include "protos.h"
#include "expr.h"
@@ -30,11 +34,15 @@ typedef struct cal_entry {
struct cal_entry *next;
char const *text;
char const *pos;
#ifdef REM_USE_WCHAR
wchar_t const *wc_text;
wchar_t const *wc_pos;
#endif
int is_color;
int r, g, b;
int time;
int priority;
char tag[TAG_LEN+1];
DynamicBuffer tags;
char passthru[PASSTHRU_LEN+1];
int duration;
char const *filename;
@@ -45,17 +53,32 @@ typedef struct cal_entry {
struct line_drawing {
char const *graphics_on;
char const *graphics_off;
char tlr, bl, tbl, blr, tblr, tr, tb, br, tbr, tl, lr;
char *tlr, *bl, *tbl, *blr, *tblr, *tr, *tb, *br, *tbr, *tl, *lr;
};
static struct line_drawing NormalDrawing = {
"", "", '+', '+', '+', '+', '+', '+', '|', '+', '+', '+', '-'
"", "", "+", "+", "+", "+", "+", "+", "|", "+", "+", "+", "-"
};
static struct line_drawing VT100Drawing = {
"\x1B(0", "\x1B(B",
'\x76', '\x6b', '\x75', '\x77', '\x6e', '\x6d', '\x78',
'\x6c', '\x74', '\x6a', '\x71'
"\x76", "\x6b", "\x75", "\x77", "\x6e", "\x6d", "\x78",
"\x6c", "\x74", "\x6a", "\x71"
};
static struct line_drawing UTF8Drawing = {
"", "",
"\xe2\x94\xb4",
"\xe2\x94\x90",
"\xe2\x94\xa4",
"\xe2\x94\xac",
"\xe2\x94\xbc",
"\xe2\x94\x94",
"\xe2\x94\x82",
"\xe2\x94\x8c",
"\xe2\x94\x9c",
"\xe2\x94\x98",
"\xe2\x94\x80"
};
static char *VT100Colors[2][2][2][2] /* [Br][R][G][B] */ = {
@@ -108,7 +131,7 @@ static char *VT100Colors[2][2][2][2] /* [Br][R][G][B] */ = {
};
static struct line_drawing *linestruct;
#define DRAW(x) putchar(linestruct->x)
#define DRAW(x) fputs(linestruct->x, stdout)
/* Global variables */
static CalEntry *CalColumn[7];
@@ -124,7 +147,7 @@ static int WriteCalendarRow (void);
static void WriteWeekHeaderLine (void);
static void WritePostHeaderLine (void);
static void PrintLeft (char const *s, int width, char pad);
static void PrintCentered (char const *s, int width, char pad);
static void PrintCentered (char const *s, int width, char *pad);
static int WriteOneCalLine (void);
static int WriteOneColLine (int col);
static void GenerateCalEntries (int col);
@@ -137,6 +160,40 @@ static void WriteBottomCalLine (void);
static void WriteIntermediateCalLine (void);
static void WriteCalDays (void);
#ifdef REM_USE_WCHAR
static void PutWideChar(wchar_t const wc)
{
char buf[MB_CUR_MAX+1];
int len;
len = wctomb(buf, wc);
if (len > 0) {
buf[len] = 0;
fputs(buf, stdout);
}
}
#endif
static int make_wchar_versions(CalEntry *e)
{
#ifdef REM_USE_WCHAR
size_t len;
wchar_t *buf;
len = mbstowcs(NULL, e->text, 0);
if (len == (size_t) -1) return 0;
buf = calloc(len+1, sizeof(wchar_t));
if (!buf) return 0;
(void) mbstowcs(buf, e->text, len+1);
e->wc_text = buf;
e->wc_pos = buf;
return 1;
#else
return 1;
#endif
}
static void gon(void)
{
printf("%s", linestruct->graphics_on);
@@ -179,7 +236,9 @@ void ProduceCalendar(void)
{
int y, m, d;
if (UseVTChars) {
if (UseUTF8Chars) {
linestruct = &UTF8Drawing;
} else if (UseVTChars) {
linestruct = &VT100Drawing;
} else {
linestruct = &NormalDrawing;
@@ -460,20 +519,55 @@ static void PrintLeft(char const *s, int width, char pad)
/* */
/* PrintCentered */
/* */
/* Center a piec of text */
/* Center a piece of text */
/* */
/***************************************************************/
static void PrintCentered(char const *s, int width, char pad)
static void PrintCentered(char const *s, int width, char *pad)
{
#ifndef REM_USE_WCHAR
int len = strlen(s);
int d = (width - len) / 2;
int i;
for (i=0; i<d; i++) PutChar(pad);
for (i=0; i<d; i++) fputs(pad, stdout);
for (i=0; i<width; i++) {
if (*s) PutChar(*s++); else break;
}
for (i=d+len; i<width; i++) PutChar(pad);
for (i=d+len; i<width; i++) fputs(pad, stdout);
#else
size_t len = mbstowcs(NULL, s, 0);
int i;
wchar_t static_buf[128];
wchar_t *buf;
wchar_t *ws;
int d;
if (!len) {
for (i=0; i<width; i++) {
fputs(pad, stdout);
}
return;
}
if (len + 1 <= 128) {
buf = static_buf;
} else {
buf = calloc(len+1, sizeof(wchar_t));
if (!buf) {
/* Uh-oh... cannot recover */
fprintf(stderr, "%s\n", ErrMsg[E_NO_MEM]);
exit(1);
}
}
(void) mbstowcs(buf, s, len+1);
d = (width - len) / 2;
ws = buf;
for (i=0; i<d; i++) fputs(pad, stdout);
for (i=0; i<width; i++) {
if (*ws) PutWideChar(*ws++); else break;
}
for (i=d+len; i<width; i++) fputs(pad, stdout);
if (buf != static_buf) free(buf);
#endif
}
/***************************************************************/
@@ -494,7 +588,7 @@ static int WriteOneCalLine(void)
if (CalColumn[i]) {
if (WriteOneColLine(i)) done = 0;
} else {
PrintCentered("", ColSpaces, ' ');
PrintCentered("", ColSpaces, " ");
}
gon();
DRAW(tb);
@@ -519,74 +613,158 @@ static int WriteOneColLine(int col)
CalEntry *e = CalColumn[col];
char const *s;
char const *space;
#ifdef REM_USE_WCHAR
wchar_t const *ws;
wchar_t const *wspace;
#endif
int numwritten = 0;
/* Print as many characters as possible within the column */
space = NULL;
s = e->pos;
/* Print as many characters as possible within the column */
#ifdef REM_USE_WCHAR
if (e->wc_text) {
wspace = NULL;
ws = e->wc_pos;
/* If we're at the end, and there's another entry, do a blank line and move
to next entry. */
if (!*s && e->next) {
PrintLeft("", ColSpaces, ' ');
CalColumn[col] = e->next;
free((char *) e->text);
free((char *) e->filename);
free(e);
return 1;
}
/* Find the last space char within the column. */
while (s - e->pos <= ColSpaces) {
if (!*s) {space = s; break;}
if (*s == ' ') space = s;
s++;
}
/* Colorize reminder if necessary */
if (UseVTColors && e->is_color) {
Colorize(e);
}
/* If we couldn't find a space char, print what we have. */
if (!space) {
for (s = e->pos; s - e->pos < ColSpaces; s++) {
if (!*s) break;
numwritten++;
PutChar(*s);
/* If we're at the end, and there's another entry, do a blank
line and move to next entry. */
if (!*ws && e->next) {
PrintLeft("", ColSpaces, ' ');
CalColumn[col] = e->next;
free((void *)e->text);
free((void *)e->filename);
if (e->wc_text) free((void *)e->wc_text);
free(e);
return 1;
}
e->pos = s;
} else {
/* We found a space - print everything before it. */
for (s = e->pos; s<space; s++) {
if (!*s) break;
numwritten++;
PutChar(*s);
/* Find the last space char within the column. */
while (ws - e->wc_pos <= ColSpaces) {
if (!*ws) {wspace = ws; break;}
if (iswspace(*ws)) wspace = ws;
ws++;
}
}
/* Decolorize reminder if necessary */
if (UseVTColors && e->is_color) {
Decolorize();
}
/* Colorize reminder if necessary */
if (UseVTColors && e->is_color) {
Colorize(e);
}
/* Flesh out the rest of the column */
while(numwritten++ < ColSpaces) PutChar(' ');
/* If we couldn't find a space char, print what we have. */
if (!wspace) {
for (ws = e->wc_pos; ws - e->wc_pos < ColSpaces; ws++) {
if (!*ws) break;
numwritten++;
PutWideChar(*ws);
}
e->wc_pos = ws;
} else {
/* We found a space - print everything before it. */
for (ws = e->wc_pos; ws<wspace; ws++) {
if (!*ws) break;
numwritten++;
PutWideChar(*ws);
}
}
/* Skip any spaces before next word */
while (*s == ' ') s++;
/* Decolorize reminder if necessary */
if (UseVTColors && e->is_color) {
Decolorize();
}
/* If done, free memory if no next entry. */
if (!*s && !e->next) {
CalColumn[col] = e->next;
free((char *) e->text);
free((char *) e->filename);
free(e);
/* Flesh out the rest of the column */
while(numwritten++ < ColSpaces) PutChar(' ');
/* Skip any spaces before next word */
while (iswspace(*ws)) ws++;
/* If done, free memory if no next entry. */
if (!*ws && !e->next) {
CalColumn[col] = e->next;
free((void *)e->text);
free((void *)e->filename);
if (e->wc_text) free((void *)e->wc_text);
free(e);
} else {
e->wc_pos = ws;
}
if (CalColumn[col]) return 1; else return 0;
} else {
e->pos = s;
#endif
space = NULL;
s = e->pos;
/* If we're at the end, and there's another entry, do a blank
line and move to next entry. */
if (!*s && e->next) {
PrintLeft("", ColSpaces, ' ');
CalColumn[col] = e->next;
free((void *)e->text);
free((void *)e->filename);
#ifdef REM_USE_WCHAR
if (e->wc_text) free((void *)e->wc_text);
#endif
free(e);
return 1;
}
/* Find the last space char within the column. */
while (s - e->pos <= ColSpaces) {
if (!*s) {space = s; break;}
if (*s == ' ') space = s;
s++;
}
/* Colorize reminder if necessary */
if (UseVTColors && e->is_color) {
Colorize(e);
}
/* If we couldn't find a space char, print what we have. */
if (!space) {
for (s = e->pos; s - e->pos < ColSpaces; s++) {
if (!*s) break;
numwritten++;
PutChar(*s);
}
e->pos = s;
} else {
/* We found a space - print everything before it. */
for (s = e->pos; s<space; s++) {
if (!*s) break;
numwritten++;
PutChar(*s);
}
}
/* Decolorize reminder if necessary */
if (UseVTColors && e->is_color) {
Decolorize();
}
/* Flesh out the rest of the column */
while(numwritten++ < ColSpaces) PutChar(' ');
/* Skip any spaces before next word */
while (*s == ' ') s++;
/* If done, free memory if no next entry. */
if (!*s && !e->next) {
CalColumn[col] = e->next;
free((void *)e->text);
free((void *)e->filename);
#ifdef REM_USE_WCHAR
if (e->wc_text) free((void *)e->wc_text);
#endif
free(e);
} else {
e->pos = s;
}
if (CalColumn[col]) return 1; else return 0;
#ifdef REM_USE_WCHAR
}
if (CalColumn[col]) return 1; else return 0;
#endif
}
/***************************************************************/
@@ -714,7 +892,7 @@ static void WriteCalHeader(void)
gon();
DRAW(tb);
goff();
PrintCentered(buf, CalWidth-2, ' ');
PrintCentered(buf, CalWidth-2, " ");
gon();
DRAW(tb);
goff();
@@ -763,26 +941,52 @@ static int DoCalRem(ParsePtr p, int col)
DBufInit(&pre_buf);
/* Parse the trigger date and time */
if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r;
if ( (r=ParseRem(p, &trig, &tim, 1)) ) {
FreeTrig(&trig);
return r;
}
/* Don't include timed reminders in calendar if -a option supplied. */
if (DontIssueAts && tim.ttime != NO_TIME) return OK;
if (trig.typ == NO_TYPE) return E_EOLN;
if (DontIssueAts && tim.ttime != NO_TIME) {
FreeTrig(&trig);
return OK;
}
if (trig.typ == NO_TYPE) {
FreeTrig(&trig);
return E_EOLN;
}
if (trig.typ == SAT_TYPE) {
r=DoSatRemind(&trig, &tim, p);
if (r) return r;
if (!LastTrigValid) return OK;
if (r) {
FreeTrig(&trig);
if (r == E_EXPIRED) return OK;
return r;
}
if (!LastTrigValid) {
FreeTrig(&trig);
return OK;
}
r=ParseToken(p, &buf);
if (r) return r;
if (r) {
FreeTrig(&trig);
return r;
}
FindToken(DBufValue(&buf), &tok);
DBufFree(&buf);
if (tok.type == T_Empty || tok.type == T_Comment) return OK;
if (tok.type != T_RemType || tok.val == SAT_TYPE) return E_PARSE_ERR;
if (tok.type == T_Empty || tok.type == T_Comment) {
FreeTrig(&trig);
return OK;
}
if (tok.type != T_RemType || tok.val == SAT_TYPE) {
FreeTrig(&trig);
return E_PARSE_ERR;
}
if (tok.val == PASSTHRU_TYPE) {
r=ParseToken(p, &buf);
if (r) return r;
if (!DBufLen(&buf)) {
DBufFree(&buf);
FreeTrig(&trig);
return E_EOLN;
}
StrnCpy(trig.passthru, DBufValue(&buf), PASSTHRU_LEN);
@@ -790,11 +994,17 @@ static int DoCalRem(ParsePtr p, int col)
}
trig.typ = tok.val;
jul = LastTriggerDate;
if (!LastTrigValid) return OK;
if (!LastTrigValid) {
FreeTrig(&trig);
return OK;
}
} else {
/* Calculate the trigger date */
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1);
if (r) return r;
if (r) {
FreeTrig(&trig);
return r;
}
}
/* Convert PS and PSF to PASSTHRU */
@@ -806,39 +1016,50 @@ static int DoCalRem(ParsePtr p, int col)
trig.typ = PASSTHRU_TYPE;
}
if (trig.typ == PASSTHRU_TYPE) {
if (!PsCal && strcmp(trig.passthru, "COLOR")) return OK;
if (!strcmp(trig.passthru, "COLOR")) {
is_color = 1;
/* Strip off the three color numbers */
DBufFree(&buf);
r=ParseToken(p, &buf);
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
DBufFree(&buf);
if (r) return r;
r=ParseToken(p, &buf);
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
DBufFree(&buf);
if (r) return r;
r=ParseToken(p, &buf);
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
DBufFree(&buf);
if (r) return r;
(void) sscanf(DBufValue(&pre_buf), "%d %d %d",
&col_r, &col_g, &col_b);
if (col_r < 0) col_r = 0;
else if (col_r > 255) col_r = 255;
if (col_g < 0) col_g = 0;
else if (col_g > 255) col_g = 255;
if (col_b < 0) col_b = 0;
else if (col_b > 255) col_b = 255;
if (!PsCal && !DoSimpleCalendar) {
DBufFree(&pre_buf);
}
}
if (!PsCal && strcmp(trig.passthru, "COLOR")) {
FreeTrig(&trig);
return OK;
}
if (!strcmp(trig.passthru, "COLOR")) {
is_color = 1;
/* Strip off the three color numbers */
DBufFree(&buf);
r=ParseToken(p, &buf);
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
DBufFree(&buf);
if (r) {
FreeTrig(&trig);
return r;
}
r=ParseToken(p, &buf);
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
DBufFree(&buf);
if (r) {
FreeTrig(&trig);
return r;
}
r=ParseToken(p, &buf);
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
DBufFree(&buf);
if (r) {
FreeTrig(&trig);
return r;
}
(void) sscanf(DBufValue(&pre_buf), "%d %d %d",
&col_r, &col_g, &col_b);
if (col_r < 0) col_r = 0;
else if (col_r > 255) col_r = 255;
if (col_g < 0) col_g = 0;
else if (col_g > 255) col_g = 255;
if (col_b < 0) col_b = 0;
else if (col_b > 255) col_b = 255;
if (!PsCal && !DoSimpleCalendar) {
DBufFree(&pre_buf);
}
}
}
/* If trigger date == today, add it to the current entry */
@@ -856,12 +1077,14 @@ static int DoCalRem(ParsePtr p, int col)
if (DBufPuts(&obuf, SimpleTime(NO_TIME)) != OK) {
DBufFree(&obuf);
DBufFree(&pre_buf);
FreeTrig(&trig);
return E_NO_MEM;
}
} else {
if (DBufPuts(&obuf, CalendarTime(tim.ttime, tim.duration)) != OK) {
DBufFree(&obuf);
DBufFree(&pre_buf);
FreeTrig(&trig);
return E_NO_MEM;
}
}
@@ -871,13 +1094,14 @@ static int DoCalRem(ParsePtr p, int col)
char evalBuf[64];
sprintf(evalBuf, "calprefix(%d)", trig.priority);
s2 = evalBuf;
r = EvalExpr(&s2, &v);
r = EvalExpr(&s2, &v, NULL);
if (!r) {
if (!DoCoerce(STR_TYPE, &v)) {
if (DBufPuts(&obuf, v.v.str) != OK) {
DestroyValue(v);
DBufFree(&obuf);
DBufFree(&pre_buf);
FreeTrig(&trig);
return E_NO_MEM;
}
}
@@ -896,11 +1120,13 @@ static int DoCalRem(ParsePtr p, int col)
if (r) {
DBufFree(&pre_buf);
DBufFree(&obuf);
FreeTrig(&trig);
return r;
}
if (DBufLen(&obuf) <= oldLen) {
DBufFree(&obuf);
DBufFree(&pre_buf);
FreeTrig(&trig);
return OK;
}
if (trig.typ != PASSTHRU_TYPE &&
@@ -908,13 +1134,14 @@ static int DoCalRem(ParsePtr p, int col)
char evalBuf[64];
sprintf(evalBuf, "calsuffix(%d)", trig.priority);
s2 = evalBuf;
r = EvalExpr(&s2, &v);
r = EvalExpr(&s2, &v, NULL);
if (!r) {
if (!DoCoerce(STR_TYPE, &v)) {
if (DBufPuts(&obuf, v.v.str) != OK) {
DestroyValue(v);
DBufFree(&obuf);
DBufFree(&pre_buf);
FreeTrig(&trig);
return E_NO_MEM;
}
}
@@ -922,34 +1149,41 @@ static int DoCalRem(ParsePtr p, int col)
}
}
s = DBufValue(&obuf);
if (!DoSimpleCalendar) while (isspace(*s)) s++;
if (!DoSimpleCalendar) while (isempty(*s)) s++;
DBufPuts(&pre_buf, s);
s = DBufValue(&pre_buf);
e = NEW(CalEntry);
if (!e) {
DBufFree(&obuf);
DBufFree(&pre_buf);
FreeTrig(&trig);
return E_NO_MEM;
}
#ifdef REM_USE_WCHAR
e->wc_pos = NULL;
e->wc_text = NULL;
#endif
e->is_color = is_color;
e->r = col_r;
e->g = col_g;
e->b = col_b;
if (!e) {
DBufFree(&obuf);
DBufFree(&pre_buf);
return E_NO_MEM;
}
e->text = StrDup(s);
DBufFree(&obuf);
DBufFree(&pre_buf);
if (!e->text) {
free(e);
FreeTrig(&trig);
return E_NO_MEM;
}
StrnCpy(e->tag, trig.tag, TAG_LEN);
if (!e->tag[0]) {
if (SynthesizeTags) {
SynthesizeTag(e->tag);
} else {
strcpy(e->tag, "*");
}
make_wchar_versions(e);
DBufInit(&(e->tags));
DBufPuts(&(e->tags), DBufValue(&(trig.tags)));
if (SynthesizeTags) {
AppendTag(&(e->tags), SynthesizeTag());
}
/* Don't need tags any more */
FreeTrig(&trig);
e->duration = tim.duration;
e->priority = trig.priority;
e->filename = StrDup(FileName);
@@ -999,7 +1233,11 @@ static void WriteSimpleEntries(int col, int jul)
} else {
printf(" *");
}
printf(" %s ", e->tag);
if (*DBufValue(&(e->tags))) {
printf(" %s ", DBufValue(&(e->tags)));
} else {
printf(" * ");
}
if (e->duration != NO_TIME) {
printf("%d ", e->duration);
} else {
@@ -1011,8 +1249,11 @@ static void WriteSimpleEntries(int col, int jul)
printf("* ");
}
printf("%s\n", e->text);
free((char *) e->text);
free((char *) e->filename);
free((void *)e->text);
free((void *)e->filename);
#ifdef REM_USE_WCHAR
if (e->wc_text) free((void *)e->wc_text);
#endif
n = e->next;
free(e);
e = n;
@@ -1112,9 +1353,9 @@ static void WriteCalDays(void)
goff();
for (i=0; i<7; i++) {
if (!MondayFirst)
PrintCentered(DayName[(i+6)%7], ColSpaces, ' ');
PrintCentered(DayName[(i+6)%7], ColSpaces, " ");
else
PrintCentered(DayName[i%7], ColSpaces, ' ');
PrintCentered(DayName[i%7], ColSpaces, " ");
gon();
DRAW(tb);
goff();
@@ -1282,10 +1523,11 @@ static void SortCol(CalEntry **col)
}
}
void SynthesizeTag(char *out)
char const *SynthesizeTag(void)
{
struct MD5Context ctx;
unsigned char buf[16];
static char out[128];
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) CurLine, strlen(CurLine));
MD5Final(buf, &ctx);
@@ -1298,5 +1540,6 @@ void SynthesizeTag(char *out)
(unsigned int) buf[10], (unsigned int) buf[11],
(unsigned int) buf[12], (unsigned int) buf[13],
(unsigned int) buf[14], (unsigned int) buf[15]);
return out;
}

View File

@@ -13,12 +13,20 @@
/* Define if you have the <glob.h> header file */
#undef HAVE_GLOB_H
#undef HAVE_WCTYPE_H
#undef HAVE_LOCALE_H
#undef HAVE_GLOB
#undef HAVE_SETENV
#undef HAVE_UNSETENV
#undef HAVE_MBSTOWCS
#undef HAVE_SETLOCALE
/* The number of bytes in a unsigned int. */
#undef SIZEOF_UNSIGNED_INT

View File

@@ -183,12 +183,12 @@
/*---------------------------------------------------------------------*/
/* How many global omits of the form YYYY MM DD do we handle? */
/*---------------------------------------------------------------------*/
#define MAX_FULL_OMITS 250
#define MAX_FULL_OMITS 500
/*---------------------------------------------------------------------*/
/* How many global omits of the form MM DD do we handle? */
/*---------------------------------------------------------------------*/
#define MAX_PARTIAL_OMITS 250
#define MAX_PARTIAL_OMITS 366
/*---------------------------------------------------------------------*/
/* A newline - some systems need "\n\r" */
@@ -221,3 +221,9 @@
#define Putc putc
#define PutChar putchar
#endif
#if defined(HAVE_MBSTOWCS) && defined(HAVE_WCTYPE_H)
#define REM_USE_WCHAR 1
#else
#undef REM_USE_WCHAR
#endif

View File

@@ -183,12 +183,12 @@
/*---------------------------------------------------------------------*/
/* How many global omits of the form YYYY MM DD do we handle? */
/*---------------------------------------------------------------------*/
#define MAX_FULL_OMITS 250
#define MAX_FULL_OMITS 500
/*---------------------------------------------------------------------*/
/* How many global omits of the form MM DD do we handle? */
/*---------------------------------------------------------------------*/
#define MAX_PARTIAL_OMITS 250
#define MAX_PARTIAL_OMITS 366
/*---------------------------------------------------------------------*/
/* A newline - some systems need "\n\r" */
@@ -221,3 +221,9 @@
#define Putc putc
#define PutChar putchar
#endif
#if defined(HAVE_MBSTOWCS) && defined(HAVE_WCTYPE_H)
#define REM_USE_WCHAR 1
#else
#undef REM_USE_WCHAR
#endif

View File

@@ -56,29 +56,54 @@ int DoRem(ParsePtr p)
DBufInit(&buf);
/* Parse the trigger date and time */
if ( (r=ParseRem(p, &trig, &tim, 1)) ) return r;
if ( (r=ParseRem(p, &trig, &tim, 1)) ) {
FreeTrig(&trig);
return r;
}
if (trig.typ == NO_TYPE) return E_EOLN;
if (trig.typ == NO_TYPE) {
PurgeEchoLine("%s\n%s\n", "#!P! Cannot parse next line", CurLine);
FreeTrig(&trig);
return E_EOLN;
}
if (trig.typ == SAT_TYPE) {
PurgeEchoLine("%s\n", "#!P: Cannot purge SATISFY-type reminders");
PurgeEchoLine("%s\n", CurLine);
r=DoSatRemind(&trig, &tim, p);
if (r) return r;
if (!LastTrigValid) return OK;
if (r) {
FreeTrig(&trig);
if (r == E_EXPIRED) return OK;
return r;
}
if (!LastTrigValid) {
FreeTrig(&trig);
return OK;
}
r=ParseToken(p, &buf);
if (r) return r;
if (r) {
FreeTrig(&trig);
return r;
}
FindToken(DBufValue(&buf), &tok);
DBufFree(&buf);
if (tok.type == T_Empty || tok.type == T_Comment) {
DBufFree(&buf);
FreeTrig(&trig);
return OK;
}
if (tok.type != T_RemType || tok.val == SAT_TYPE) {
DBufFree(&buf);
FreeTrig(&trig);
return E_PARSE_ERR;
}
if (tok.val == PASSTHRU_TYPE) {
r=ParseToken(p, &buf);
if (r) return r;
if (r) {
FreeTrig(&trig);
return r;
}
if (!DBufLen(&buf)) {
FreeTrig(&trig);
DBufFree(&buf);
return E_EOLN;
}
@@ -87,13 +112,42 @@ int DoRem(ParsePtr p)
}
trig.typ = tok.val;
jul = LastTriggerDate;
if (!LastTrigValid) return OK;
if (!LastTrigValid || PurgeMode) {
FreeTrig(&trig);
return OK;
}
} else {
/* Calculate the trigger date */
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1);
if (r) return r;
if (r) {
if (PurgeMode) {
PurgeEchoLine("%s: %s\n", "#!P! Problem calculating trigger date", ErrMsg[r]);
PurgeEchoLine("%s\n", CurLine);
}
FreeTrig(&trig);
return r;
}
}
if (PurgeMode) {
if (trig.expired || jul < JulianToday) {
if (p->expr_happened) {
if (p->nonconst_expr) {
PurgeEchoLine("%s\n", "#!P: Next line may have expired, but contains non-constant expression");
PurgeEchoLine("%s\n", CurLine);
} else {
PurgeEchoLine("%s\n", "#!P: Next line has expired, but contains expression... please verify");
PurgeEchoLine("#!P: Expired: %s\n", CurLine);
}
} else {
PurgeEchoLine("#!P: Expired: %s\n", CurLine);
}
} else {
PurgeEchoLine("%s\n", CurLine);
}
FreeTrig(&trig);
return OK;
}
/* Queue the reminder, if necessary */
if (jul == JulianToday &&
!(!IgnoreOnce &&
@@ -101,17 +155,21 @@ int DoRem(ParsePtr p)
FileAccessDate == JulianToday))
QueueReminder(p, &trig, &tim, trig.sched);
/* If we're in daemon mode, do nothing over here */
if (Daemon) return OK;
if (ShouldTriggerReminder(&trig, &tim, jul, &err)) {
if ( (r=TriggerReminder(p, &trig, &tim, jul)) )
{
return r;
}
if (Daemon) {
FreeTrig(&trig);
return OK;
}
if (ShouldTriggerReminder(&trig, &tim, jul, &err)) {
if ( (r=TriggerReminder(p, &trig, &tim, jul)) ) {
FreeTrig(&trig);
return r;
}
}
FreeTrig(&trig);
return OK;
}
}
/***************************************************************/
/* */
@@ -126,7 +184,6 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
register int r;
DynamicBuffer buf;
Token tok;
int y, m, d;
DBufInit(&buf);
@@ -148,7 +205,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
trig->sched[0] = 0;
trig->warn[0] = 0;
trig->omitfunc[0] = 0;
trig->tag[0] = 0;
DBufInit(&(trig->tags));
trig->passthru[0] = 0;
tim->ttime = NO_TIME;
tim->delta = NO_DELTA;
@@ -244,6 +301,14 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
}
return OK;
case T_Through:
DBufFree(&buf);
if (trig->rep != NO_REP) return E_REP_TWICE;
trig->rep = 1;
r = ParseUntil(s, trig);
if (r) return r;
break;
case T_Until:
DBufFree(&buf);
r=ParseUntil(s, trig);
@@ -321,7 +386,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
case T_Tag:
r = ParseToken(s, &buf);
if (r) return r;
StrnCpy(trig->tag, DBufValue(&buf), TAG_LEN);
AppendTag(&(trig->tags), DBufValue(&buf));
break;
case T_Duration:
@@ -653,18 +718,24 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
if (t->typ == PASSTHRU_TYPE && !strcmp(t->passthru, "COLOR")) {
/* Strip off three tokens */
r = ParseToken(p, &buf);
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
if (!NextMode) {
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
}
DBufFree(&buf);
if (r) return r;
r = ParseToken(p, &buf);
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
if (!NextMode) {
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
}
DBufFree(&buf);
if (r) return r;
r = ParseToken(p, &buf);
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
if (!NextMode) {
DBufPuts(&pre_buf, DBufValue(&buf));
DBufPutc(&pre_buf, ' ');
}
DBufFree(&buf);
if (r) return r;
t->typ = MSG_TYPE;
@@ -704,16 +775,12 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
DBufFree(&pre_buf);
return E_NO_MEM;
}
if (t->tag[0]) {
sprintf(tmpBuf, "%s ", t->tag);
} else {
sprintf(tmpBuf, "* ");
}
if (DBufPuts(&calRow, tmpBuf) != OK) {
DBufFree(&calRow);
DBufFree(&pre_buf);
return E_NO_MEM;
}
if (*DBufValue(&(t->tags))) {
DBufPuts(&calRow, DBufValue(&(t->tags)));
DBufPutc(&calRow, ' ');
} else {
DBufPuts(&calRow, "* ");
}
if (tim->duration != NO_TIME) {
sprintf(tmpBuf, "%d ", tim->duration);
} else {
@@ -755,7 +822,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
if (UserFuncExists("msgprefix") == 1) {
sprintf(PrioExpr, "msgprefix(%d)", t->priority);
s = PrioExpr;
r = EvalExpr(&s, &v);
r = EvalExpr(&s, &v, NULL);
if (!r) {
if (!DoCoerce(STR_TYPE, &v)) {
if (DBufPuts(&buf, v.v.str) != OK) {
@@ -774,7 +841,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
if (UserFuncExists("msgsuffix") == 1) {
sprintf(PrioExpr, "msgsuffix(%d)", t->priority);
s = PrioExpr;
r = EvalExpr(&s, &v);
r = EvalExpr(&s, &v, NULL);
if (!r) {
if (!DoCoerce(STR_TYPE, &v)) {
if (DBufPuts(&buf, v.v.str) != OK) {
@@ -884,9 +951,9 @@ int ShouldTriggerReminder(Trigger *t, TimeTrig *tim, int jul, int *err)
if (t->delta < 0)
jul = jul + t->delta;
else {
r = t->delta;
int iter = 0;
int max = MaxSatIter;
r = t->delta;
if (max < r*2) max = r*2;
while(iter++ < max) {
if (!r || (jul <= JulianToday)) {
@@ -932,7 +999,7 @@ int DoSatRemind(Trigger *trig, TimeTrig *tim, ParsePtr p)
if (r == E_CANT_TRIG) return OK; else return r;
}
if (jul == -1) {
return OK;
return E_EXPIRED;
}
s = p->pos;
r = EvaluateExpr(p, &v);
@@ -1073,7 +1140,7 @@ static int ShouldTriggerBasedOnWarn(Trigger *t, int jul, int *err)
for (i=1; ; i++) {
sprintf(buffer, "%s(%d)", t->warn, i);
s = buffer;
r = EvalExpr(&s, &v);
r = EvalExpr(&s, &v, NULL);
if (r) {
Eprint("%s: `%s': %s", ErrMsg[M_BAD_WARN_FUNC],
t->warn, ErrMsg[r]);

View File

@@ -205,7 +205,7 @@ EXTERN char *ErrMsg[]
"Back value specified twice",
"ONCE keyword used twice. (Hah.)",
"Expecting time after AT",
"UNTIL keyword used twice",
"THROUGH/UNTIL keyword used twice",
"Incomplete date specification",
"FROM/SCANFROM keyword used twice",
"Variable",

View File

@@ -41,7 +41,7 @@ static int Multiply(void), Divide(void), Mod(void), Add(void),
UnMinus(void), LogNot(void),
Compare(int);
static int MakeValue (char const *s, Value *v, Var *locals);
static int MakeValue (char const *s, Value *v, Var *locals, ParsePtr p);
/* Binary operators - all left-associative */
@@ -132,7 +132,7 @@ static void CleanStack(void)
static char PeekChar(char const **s)
{
char const *t = *s;
while (*t && isspace(*t)) t++;
while (*t && isempty(*t)) t++;
return *t;
}
@@ -150,7 +150,7 @@ static int ParseExprToken(DynamicBuffer *buf, char const **in)
DBufFree(buf);
/* Skip white space */
while (**in && isspace(**in)) (*in)++;
while (**in && isempty(**in)) (*in)++;
if (!**in) return OK;
@@ -283,7 +283,7 @@ static int ParseExprToken(DynamicBuffer *buf, char const **in)
(*in)++;
}
/* Chew up any remaining white space */
while (**in && isspace(**in)) (*in)++;
while (**in && isempty(**in)) (*in)++;
/* Peek ahead - is it '('? Then we have a function call */
if (**in == '(') {
@@ -303,14 +303,14 @@ static int ParseExprToken(DynamicBuffer *buf, char const **in)
/* Put the result into value pointed to by v. */
/* */
/***************************************************************/
int EvalExpr(char const **e, Value *v)
int EvalExpr(char const **e, Value *v, ParsePtr p)
{
int r;
OpStackPtr = 0;
ValStackPtr = 0;
r = Evaluate(e, NULL);
r = Evaluate(e, NULL, p);
/* Put last character parsed back onto input stream */
if (DBufLen(&ExprBuf)) (*e)--;
@@ -326,7 +326,7 @@ int EvalExpr(char const **e, Value *v)
}
/* Evaluate - do the actual work of evaluation. */
int Evaluate(char const **s, Var *locals)
int Evaluate(char const **s, Var *locals, ParsePtr p)
{
int OpBase, ValBase;
int r;
@@ -351,7 +351,7 @@ int Evaluate(char const **s, Var *locals)
if (*DBufValue(&ExprBuf) == '(') { /* Parenthesized expression */
DBufFree(&ExprBuf);
r = Evaluate(s, locals); /* Leaves the last parsed token in ExprBuf */
r = Evaluate(s, locals, p); /* Leaves the last parsed token in ExprBuf */
if (r) return r;
r = OK;
if (*DBufValue(&ExprBuf) != ')') {
@@ -374,9 +374,11 @@ int Evaluate(char const **s, Var *locals)
}
args = 0;
if (PeekChar(s) == ')') { /* Function has no arguments */
if (f) r = CallFunc(f, 0);
else {
r = CallUserFunc(ufname, 0);
if (f) {
if (!f->is_constant && (p != NULL)) p->nonconst_expr = 1;
r = CallFunc(f, 0);
} else {
r = CallUserFunc(ufname, 0, p);
free((char *) ufname);
}
if (r) return r;
@@ -385,7 +387,7 @@ int Evaluate(char const **s, Var *locals)
} else { /* Function has some arguments */
while(1) {
args++;
r = Evaluate(s, locals);
r = Evaluate(s, locals, p);
if (r) {
if (!f) free((char *) ufname);
return r;
@@ -399,9 +401,11 @@ int Evaluate(char const **s, Var *locals)
return E_EXPECT_COMMA;
}
}
if (f) r = CallFunc(f, args);
else {
r = CallUserFunc(ufname, args);
if (f) {
if (!f->is_constant && (p != NULL)) p->nonconst_expr = 1;
r = CallFunc(f, args);
} else {
r = CallUserFunc(ufname, args, p);
free((char *) ufname);
}
DBufFree(&ExprBuf);
@@ -422,7 +426,7 @@ int Evaluate(char const **s, Var *locals)
DBufFree(&ExprBuf);
return E_ILLEGAL_CHAR;
} else { /* Must be a literal value */
r = MakeValue(DBufValue(&ExprBuf), &va, locals);
r = MakeValue(DBufValue(&ExprBuf), &va, locals, p);
DBufFree(&ExprBuf);
if (r) return r;
PushValStack(va);
@@ -486,7 +490,7 @@ int Evaluate(char const **s, Var *locals)
/* a date or the value of a symbol. */
/* */
/***************************************************************/
static int MakeValue(char const *s, Value *v, Var *locals)
static int MakeValue(char const *s, Value *v, Var *locals, ParsePtr p)
{
int len;
int h, m, r;
@@ -541,6 +545,7 @@ static int MakeValue(char const *s, Value *v, Var *locals)
v->v.val = len;
return OK;
} else if (*s == '$') { /* A system variable */
if (p) p->nonconst_expr = 1;
if (DebugFlag & DB_PRTEXPR)
fprintf(ErrFp, "%s => ", s);
r = GetSysVar(s+1, v);
@@ -551,10 +556,11 @@ static int MakeValue(char const *s, Value *v, Var *locals)
Putc('\n', ErrFp);
}
return r;
} else /* Must be a symbol */
} else { /* Must be a symbol */
if (DebugFlag & DB_PRTEXPR)
fprintf(ErrFp, "%s => ", s);
r = GetVarValue(s, v, locals);
}
r = GetVarValue(s, v, locals, p);
if (! (DebugFlag & DB_PRTEXPR)) return r;
if (r == OK) {
PrintValue(v, ErrFp);

View File

@@ -17,6 +17,7 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <sys/stat.h>
@@ -97,6 +98,32 @@ static void DestroyCache (CachedFile *cf);
static int CheckSafety (void);
static int PopFile (void);
static void OpenPurgeFile(char const *fname, char const *mode)
{
DynamicBuffer fname_buf;
if (PurgeFP != NULL && PurgeFP != stdout) {
fclose(PurgeFP);
}
PurgeFP = NULL;
/* Do not open a purge file if we're below purge
include depth */
if (IStackPtr-2 >= PurgeIncludeDepth) {
PurgeFP = NULL;
return;
}
DBufInit(&fname_buf);
if (DBufPuts(&fname_buf, fname) != OK) return;
if (DBufPuts(&fname_buf, ".purged") != OK) return;
PurgeFP = fopen(DBufValue(&fname_buf), mode);
if (!PurgeFP) {
fprintf(ErrFp, "Cannot open `%s' for writing: %s\n", DBufValue(&fname_buf), strerror(errno));
}
DBufFree(&fname_buf);
}
static void FreeChainItem(FilenameChain *chain)
{
if (chain->filename) free((void *) chain->filename);
@@ -173,14 +200,32 @@ static int ReadLineFromFile(void)
}
if (feof(fp)) {
FCLOSE(fp);
if ((DBufLen(&buf) == 0) &&
(DBufLen(&LineBuffer) == 0) && PurgeMode) {
if (PurgeFP != NULL && PurgeFP != stdout) fclose(PurgeFP);
PurgeFP = NULL;
}
}
l = DBufLen(&buf);
if (l && (DBufValue(&buf)[l-1] == '\\')) {
DBufValue(&buf)[l-1] = '\n';
if (DBufPuts(&LineBuffer, DBufValue(&buf)) != OK) {
DBufFree(&buf);
DBufFree(&LineBuffer);
return E_NO_MEM;
if (PurgeMode) {
if (DBufPuts(&LineBuffer, DBufValue(&buf)) != OK) {
DBufFree(&buf);
DBufFree(&LineBuffer);
return E_NO_MEM;
}
if (DBufPutc(&LineBuffer, '\n') != OK) {
DBufFree(&buf);
DBufFree(&LineBuffer);
return E_NO_MEM;
}
} else {
DBufValue(&buf)[l-1] = '\n';
if (DBufPuts(&LineBuffer, DBufValue(&buf)) != OK) {
DBufFree(&buf);
DBufFree(&LineBuffer);
return E_NO_MEM;
}
}
continue;
}
@@ -212,6 +257,13 @@ int OpenFile(char const *fname)
CachedFile *h = CachedFiles;
int r;
if (PurgeMode) {
if (PurgeFP != NULL && PurgeFP != stdout) {
fclose(PurgeFP);
}
PurgeFP = NULL;
}
/* Assume we own the file for now */
RunDisabled &= ~RUN_NOTOWNER;
@@ -236,6 +288,9 @@ int OpenFile(char const *fname)
/* If it's a dash, then it's stdin */
if (!strcmp(fname, "-")) {
fp = stdin;
if (PurgeMode) {
PurgeFP = stdout;
}
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Reading `-': Reading stdin\n");
}
@@ -244,6 +299,9 @@ int OpenFile(char const *fname)
if (DebugFlag & DB_TRACE_FILES) {
fprintf(ErrFp, "Reading `%s': Opening file on disk\n", fname);
}
if (PurgeMode) {
OpenPurgeFile(fname, "w");
}
}
if (!fp || !CheckSafety()) return E_CANT_OPEN;
CLine = NULL;
@@ -257,8 +315,10 @@ int OpenFile(char const *fname)
if (strcmp(fname, "-")) {
fp = fopen(fname, "r");
if (!fp || !CheckSafety()) return E_CANT_OPEN;
if (PurgeMode) OpenPurgeFile(fname, "w");
} else {
fp = stdin;
if (PurgeMode) PurgeFP = stdout;
}
}
}
@@ -289,7 +349,11 @@ static int CacheFile(char const *fname)
/* Create a file header */
cf = NEW(CachedFile);
cf->cache = NULL;
if (!cf) { ShouldCache = 0; FCLOSE(fp); return E_NO_MEM; }
if (!cf) {
ShouldCache = 0;
FCLOSE(fp);
return E_NO_MEM;
}
cf->filename = StrDup(fname);
if (!cf->filename) {
ShouldCache = 0;
@@ -315,7 +379,7 @@ static int CacheFile(char const *fname)
}
/* Skip blank chars */
s = DBufValue(&LineBuffer);
while (isspace(*s)) s++;
while (isempty(*s)) s++;
if (*s && *s!=';' && *s!='#') {
/* Add the line to the cache */
if (!cl) {
@@ -424,8 +488,10 @@ static int PopFile(void)
if (strcmp(i->filename, "-")) {
fp = fopen(i->filename, "r");
if (!fp || !CheckSafety()) return E_CANT_OPEN;
if (PurgeMode) OpenPurgeFile(i->filename, "a");
} else {
fp = stdin;
if (PurgeMode) PurgeFP = stdout;
}
if (fp != stdin)
(void) fseek(fp, i->offset, 0); /* Trust that it works... */

View File

@@ -184,89 +184,89 @@ extern int ValStackPtr;
/* The array holding the built-in functions. */
BuiltinFunc Func[] = {
/* Name minargs maxargs func */
/* Name minargs maxargs is_constant func */
{ "abs", 1, 1, FAbs },
{ "access", 2, 2, FAccess },
{ "args", 1, 1, FArgs },
{ "asc", 1, 1, FAsc },
{ "baseyr", 0, 0, FBaseyr },
{ "char", 1, NO_MAX, FChar },
{ "choose", 2, NO_MAX, FChoose },
{ "coerce", 2, 2, FCoerce },
{ "current", 0, 0, FCurrent },
{ "date", 3, 3, FDate },
{ "datepart", 1, 1, FDatepart },
{ "datetime", 2, 5, FDateTime },
{ "dawn", 0, 1, FDawn},
{ "day", 1, 1, FDay },
{ "daysinmon", 2, 2, FDaysinmon },
{ "defined", 1, 1, FDefined },
{ "dosubst", 1, 3, FDosubst },
{ "dusk", 0, 1, FDusk },
{ "easterdate", 1, 1, FEasterdate },
{ "evaltrig", 1, 2, FEvalTrig },
{ "filedate", 1, 1, FFiledate },
{ "filedatetime", 1, 1, FFiledatetime },
{ "filedir", 0, 0, FFiledir },
{ "filename", 0, 0, FFilename },
{ "getenv", 1, 1, FGetenv },
{ "hebdate", 2, 5, FHebdate },
{ "hebday", 1, 1, FHebday },
{ "hebmon", 1, 1, FHebmon },
{ "hebyear", 1, 1, FHebyear },
{ "hour", 1, 1, FHour },
{ "iif", 1, NO_MAX, FIif },
{ "index", 2, 3, FIndex },
{ "isdst", 0, 2, FIsdst },
{ "isleap", 1, 1, FIsleap },
{ "isomitted", 1, 1, FIsomitted },
{ "language", 0, 0, FLanguage },
{ "lower", 1, 1, FLower },
{ "max", 1, NO_MAX, FMax },
{ "min", 1, NO_MAX, FMin },
{ "minsfromutc", 0, 2, FMinsfromutc },
{ "minute", 1, 1, FMinute },
{ "mon", 1, 1, FMon },
{ "monnum", 1, 1, FMonnum },
{ "moondate", 1, 3, FMoondate },
{ "moondatetime", 1, 3, FMoondatetime },
{ "moonphase", 0, 2, FMoonphase },
{ "moontime", 1, 3, FMoontime },
{ "nonomitted", 2, NO_MAX, FNonomitted },
{ "now", 0, 0, FNow },
{ "ord", 1, 1, FOrd },
{ "ostype", 0, 0, FOstype },
{ "plural", 1, 3, FPlural },
{ "psmoon", 1, 4, FPsmoon},
{ "psshade", 1, 3, FPsshade},
{ "realcurrent", 0, 0, FRealCurrent},
{ "realnow", 0, 0, FRealnow},
{ "realtoday", 0, 0, FRealtoday },
{ "sgn", 1, 1, FSgn },
{ "shell", 1, 2, FShell },
{ "slide", 2, NO_MAX, FSlide },
{ "strlen", 1, 1, FStrlen },
{ "substr", 2, 3, FSubstr },
{ "sunrise", 0, 1, FSunrise},
{ "sunset", 0, 1, FSunset },
{ "time", 2, 2, FTime },
{ "timepart", 1, 1, FTimepart },
{ "today", 0, 0, FToday },
{ "trigdate", 0, 0, FTrigdate },
{ "trigdatetime", 0, 0, FTrigdatetime },
{ "trigger", 1, 3, FTrigger },
{ "trigtime", 0, 0, FTrigtime },
{ "trigvalid", 0, 0, FTrigvalid },
{ "typeof", 1, 1, FTypeof },
{ "tzconvert", 2, 3, FTzconvert },
{ "upper", 1, 1, FUpper },
{ "value", 1, 2, FValue },
{ "version", 0, 0, FVersion },
{ "weekno", 0, 3, FWeekno },
{ "wkday", 1, 1, FWkday },
{ "wkdaynum", 1, 1, FWkdaynum },
{ "year", 1, 1, FYear }
{ "abs", 1, 1, 1, FAbs },
{ "access", 2, 2, 0, FAccess },
{ "args", 1, 1, 0, FArgs },
{ "asc", 1, 1, 1, FAsc },
{ "baseyr", 0, 0, 1, FBaseyr },
{ "char", 1, NO_MAX, 1, FChar },
{ "choose", 2, NO_MAX, 1, FChoose },
{ "coerce", 2, 2, 1, FCoerce },
{ "current", 0, 0, 0, FCurrent },
{ "date", 3, 3, 1, FDate },
{ "datepart", 1, 1, 1, FDatepart },
{ "datetime", 2, 5, 1, FDateTime },
{ "dawn", 0, 1, 0, FDawn},
{ "day", 1, 1, 1, FDay },
{ "daysinmon", 2, 2, 1, FDaysinmon },
{ "defined", 1, 1, 0, FDefined },
{ "dosubst", 1, 3, 0, FDosubst },
{ "dusk", 0, 1, 0, FDusk },
{ "easterdate", 1, 1, 0, FEasterdate },
{ "evaltrig", 1, 2, 0, FEvalTrig },
{ "filedate", 1, 1, 0, FFiledate },
{ "filedatetime", 1, 1, 0, FFiledatetime },
{ "filedir", 0, 0, 0, FFiledir },
{ "filename", 0, 0, 0, FFilename },
{ "getenv", 1, 1, 0, FGetenv },
{ "hebdate", 2, 5, 0, FHebdate },
{ "hebday", 1, 1, 0, FHebday },
{ "hebmon", 1, 1, 0, FHebmon },
{ "hebyear", 1, 1, 0, FHebyear },
{ "hour", 1, 1, 1, FHour },
{ "iif", 1, NO_MAX, 1, FIif },
{ "index", 2, 3, 1, FIndex },
{ "isdst", 0, 2, 0, FIsdst },
{ "isleap", 1, 1, 1, FIsleap },
{ "isomitted", 1, 1, 0, FIsomitted },
{ "language", 0, 0, 1, FLanguage },
{ "lower", 1, 1, 1, FLower },
{ "max", 1, NO_MAX, 1, FMax },
{ "min", 1, NO_MAX, 1, FMin },
{ "minsfromutc", 0, 2, 0, FMinsfromutc },
{ "minute", 1, 1, 1, FMinute },
{ "mon", 1, 1, 1, FMon },
{ "monnum", 1, 1, 1, FMonnum },
{ "moondate", 1, 3, 0, FMoondate },
{ "moondatetime", 1, 3, 0, FMoondatetime },
{ "moonphase", 0, 2, 0, FMoonphase },
{ "moontime", 1, 3, 0, FMoontime },
{ "nonomitted", 2, NO_MAX, 0, FNonomitted },
{ "now", 0, 0, 0, FNow },
{ "ord", 1, 1, 1, FOrd },
{ "ostype", 0, 0, 1, FOstype },
{ "plural", 1, 3, 1, FPlural },
{ "psmoon", 1, 4, 1, FPsmoon},
{ "psshade", 1, 3, 1, FPsshade},
{ "realcurrent", 0, 0, 0, FRealCurrent},
{ "realnow", 0, 0, 0, FRealnow},
{ "realtoday", 0, 0, 0, FRealtoday },
{ "sgn", 1, 1, 1, FSgn },
{ "shell", 1, 2, 0, FShell },
{ "slide", 2, NO_MAX, 0, FSlide },
{ "strlen", 1, 1, 1, FStrlen },
{ "substr", 2, 3, 1, FSubstr },
{ "sunrise", 0, 1, 0, FSunrise},
{ "sunset", 0, 1, 0, FSunset },
{ "time", 2, 2, 1, FTime },
{ "timepart", 1, 1, 1, FTimepart },
{ "today", 0, 0, 0, FToday },
{ "trigdate", 0, 0, 0, FTrigdate },
{ "trigdatetime", 0, 0, 0, FTrigdatetime },
{ "trigger", 1, 3, 0, FTrigger },
{ "trigtime", 0, 0, 0, FTrigtime },
{ "trigvalid", 0, 0, 0, FTrigvalid },
{ "typeof", 1, 1, 1, FTypeof },
{ "tzconvert", 2, 3, 0, FTzconvert },
{ "upper", 1, 1, 1, FUpper },
{ "value", 1, 2, 0, FValue },
{ "version", 0, 0, 1, FVersion },
{ "weekno", 0, 3, 1, FWeekno },
{ "wkday", 1, 1, 1, FWkday },
{ "wkdaynum", 1, 1, 1, FWkdaynum },
{ "year", 1, 1, 1, FYear }
};
/* Need a variable here - Func[] array not really visible to outside. */
@@ -1076,7 +1076,7 @@ static int FValue(func_info *info)
ASSERT_TYPE(0, STR_TYPE);
switch(Nargs) {
case 1:
return GetVarValue(ARGSTR(0), &RetVal, NULL);
return GetVarValue(ARGSTR(0), &RetVal, NULL, NULL);
case 2:
v = FindVar(ARGSTR(0), 0);
@@ -1335,10 +1335,11 @@ static int FShell(func_info *info)
/***************************************************************/
static int FIsomitted(func_info *info)
{
int r;
if (!HASDATE(ARG(0))) return E_BAD_TYPE;
RetVal.type = INT_TYPE;
int r = IsOmitted(DATEPART(ARG(0)), 0, NULL, &RETVAL);
r = IsOmitted(DATEPART(ARG(0)), 0, NULL, &RETVAL);
return r;
}
@@ -2324,7 +2325,7 @@ static int MoonStuff(int type_wanted, func_info *info)
static int FTimepart(func_info *info)
{
ASSERT_TYPE(0, DATETIME_TYPE);
if (!HASTIME(ARG(0))) return E_BAD_TYPE;
RetVal.type = TIME_TYPE;
RETVAL = TIMEPART(ARG(0));
return OK;
@@ -2332,7 +2333,7 @@ static int FTimepart(func_info *info)
static int FDatepart(func_info *info)
{
ASSERT_TYPE(0, DATETIME_TYPE);
if (!HASDATE(ARG(0))) return E_BAD_TYPE;
RetVal.type = DATE_TYPE;
RETVAL = DATEPART(ARG(0));
return OK;
@@ -2659,7 +2660,10 @@ FEvalTrig(func_info *info)
p.allownested = 0;
r = ParseRem(&p, &trig, &tim, 0);
if (r) return r;
if (trig.typ != NO_TYPE) return E_PARSE_ERR;
if (trig.typ != NO_TYPE) {
FreeTrig(&trig);
return E_PARSE_ERR;
}
if (scanfrom == NO_DATE) {
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 0);
} else {
@@ -2669,6 +2673,7 @@ FEvalTrig(func_info *info)
}
jul = ComputeTrigger(scanfrom, &trig, &r, 0);
}
FreeTrig(&trig);
if (r) return r;
if (jul < 0) {
RetVal.type = INT_TYPE;

View File

@@ -79,7 +79,10 @@ EXTERN INIT( int MaxSatIter, 150);
EXTERN INIT( int MaxStringLen, MAX_STR_LEN);
EXTERN INIT( char *FileName, NULL);
EXTERN INIT( int UseStdin, 0);
EXTERN INIT( int PurgeMode, 0);
EXTERN INIT( int PurgeIncludeDepth, 0);
EXTERN FILE *ErrFp;
EXTERN INIT( FILE *PurgeFP, NULL);
EXTERN INIT( int NumIfs, 0);
EXTERN INIT( unsigned int IfFlags, 0);
EXTERN INIT( int LastTriggerDate, 0);
@@ -93,6 +96,7 @@ EXTERN char const **ArgV;
EXTERN INIT( int CalLines, CAL_LINES);
EXTERN INIT( int CalPad, 1);
EXTERN INIT( int UseVTChars, 0);
EXTERN INIT( int UseUTF8Chars, 0);
EXTERN INIT( int UseVTColors, 0);
/* Latitude and longitude */

View File

@@ -8,7 +8,7 @@
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-1998 by David F. Skoll */
/* Copyright (C) 1999-2007 by Roaring Penguin Software Inc. */
/* Copyright (C) 1999-2010 by Roaring Penguin Software Inc. */
/* */
/***************************************************************/
@@ -67,9 +67,13 @@
* -kcmd = Run 'cmd' for MSG-type reminders instead of printing to stdout
* -iVAR=EXPR = Initialize and preserve VAR.
* -m = Start calendar with Monday instead of Sunday.
* -j[n] = Purge all junk from reminder files (n = INCLUDE depth)
* A minus sign alone indicates to take input from stdin
*
**************************************************************/
#if defined(__APPLE__) || defined(__CYGWIN__)
static void rkrphgvba(int x);
#endif
/* For parsing an integer */
#define PARSENUM(var, s) \
@@ -135,6 +139,12 @@ void InitRemind(int argc, char const *argv[])
int jul, tim;
#if defined(__APPLE__)
rkrphgvba(0);
#elif defined(__CYGWIN__)
rkrphgvba(1);
#endif
jul = NO_DATE;
tim = NO_TIME;
@@ -145,6 +155,8 @@ void InitRemind(int argc, char const *argv[])
DBufPuts(&Banner, L_BANNER);
PurgeFP = NULL;
/* Make sure remind is not installed set-uid or set-gid */
if (getgid() != getegid() ||
getuid() != geteuid()) {
@@ -194,6 +206,13 @@ void InitRemind(int argc, char const *argv[])
while (*arg) {
switch(*arg++) {
case 'j':
case 'J':
PurgeMode = 1;
if (*arg) {
PARSENUM(PurgeIncludeDepth, arg);
}
break;
case 'i':
case 'I':
InitializeVar(arg);
@@ -333,6 +352,11 @@ void InitRemind(int argc, char const *argv[])
arg++;
continue;
}
if (*arg == 'u' || *arg == 'U') {
UseUTF8Chars = 1;
arg++;
continue;
}
if (*arg == 'c' || *arg == 'C') {
UseVTColors = 1;
arg++;
@@ -578,7 +602,7 @@ void InitRemind(int argc, char const *argv[])
void Usage(void)
{
fprintf(ErrFp, "\nREMIND %s (%s version) Copyright 1992-1998 David F. Skoll\n", VERSION, L_LANGNAME);
fprintf(ErrFp, "Copyright 1999-2009 Roaring Penguin Software Inc.\n");
fprintf(ErrFp, "Copyright 1999-2010 Roaring Penguin Software Inc.\n");
#ifdef BETA
fprintf(ErrFp, ">>>> BETA VERSION <<<<\n");
#endif
@@ -609,6 +633,7 @@ void Usage(void)
fprintf(ErrFp, " -ivar=val Initialize var to val and preserve var\n");
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);
}
#endif /* L_USAGE_OVERRIDE */
@@ -743,7 +768,7 @@ static void InitializeVar(char const *str)
return;
}
r=EvalExpr(&expr, &val);
r=EvalExpr(&expr, &val, NULL);
if (r) {
fprintf(ErrFp, ErrMsg[M_I_OPTION], ErrMsg[r]);
return;
@@ -765,3 +790,46 @@ static void InitializeVar(char const *str)
return;
}
#if defined(__APPLE__) || defined(__CYGWIN__)
static char const pmsg1[] = {
0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20,
0x67, 0x62, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x68, 0x61, 0x61, 0x76,
0x61, 0x74, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x62,
0x61, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x63, 0x63, 0x79, 0x72, 0x20,
0x63, 0x65, 0x62, 0x71, 0x68, 0x70, 0x67, 0x2e, 0x20, 0x20, 0x56,
0x27, 0x71, 0x20, 0x65, 0x6e, 0x67, 0x75, 0x72, 0x65, 0x20, 0x67,
0x75, 0x6e, 0x67, 0x0a, 0x6c, 0x62, 0x68, 0x20, 0x71, 0x76, 0x71,
0x61, 0x27, 0x67, 0x2e, 0x20, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61,
0x71, 0x20, 0x72, 0x6b, 0x72, 0x70, 0x68, 0x67, 0x76, 0x62, 0x61,
0x20, 0x6a, 0x76, 0x79, 0x79, 0x20, 0x70, 0x62, 0x61, 0x67, 0x76,
0x61, 0x68, 0x72, 0x20, 0x7a, 0x62, 0x7a, 0x72, 0x61, 0x67, 0x6e,
0x65, 0x76, 0x79, 0x6c, 0x2e, 0x0a, 0x00
};
static char const pmsg2[] = {
0x4c, 0x62, 0x68, 0x20, 0x6e, 0x63, 0x63, 0x72, 0x6e, 0x65, 0x20,
0x67, 0x62, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x68, 0x61, 0x61, 0x76,
0x61, 0x74, 0x20, 0x45, 0x72, 0x7a, 0x76, 0x61, 0x71, 0x20, 0x62,
0x61, 0x20, 0x6e, 0x20, 0x5a, 0x76, 0x70, 0x65, 0x62, 0x66, 0x62,
0x73, 0x67, 0x20, 0x66, 0x6c, 0x66, 0x67, 0x72, 0x7a, 0x2e, 0x20,
0x20, 0x56, 0x27, 0x71, 0x20, 0x65, 0x6e, 0x67, 0x75, 0x72, 0x65,
0x20, 0x67, 0x75, 0x6e, 0x67, 0x0a, 0x6c, 0x62, 0x68, 0x20, 0x71,
0x76, 0x71, 0x61, 0x27, 0x67, 0x2e, 0x20, 0x20, 0x45, 0x72, 0x7a,
0x76, 0x61, 0x71, 0x20, 0x72, 0x6b, 0x72, 0x70, 0x68, 0x67, 0x76,
0x62, 0x61, 0x20, 0x6a, 0x76, 0x79, 0x79, 0x20, 0x70, 0x62, 0x61,
0x67, 0x76, 0x61, 0x68, 0x72, 0x20, 0x7a, 0x62, 0x7a, 0x72, 0x61,
0x67, 0x6e, 0x65, 0x76, 0x79, 0x6c, 0x2e, 0x0a, 0x00
};
static void
rkrphgvba(int x)
{
char const *s = (x ? pmsg2 : pmsg1);
while(*s) {
int c = (int) *s++;
c=isalpha(c)?tolower(c)<0x6e?c+13:c-13:c;
putchar(c);
}
sleep(5);
}
#endif

View File

@@ -280,7 +280,7 @@ EXTERN char *ErrMsg[] =
"Peruutusarvo annettu kahdesti",
"ONCE-avainsanaa k\xE4ytetty kahdesti. (Hah.)",
"AT-sanan per\xE4st\xE4 puuttuu aika",
"UNTIL-sanaa k\xE4ytetty kahdesti",
"THROUGH/UNTIL-sanaa k\xE4ytetty kahdesti",
"Ep\xE4t\xE4ydellinen p\xE4iv\xE4ys",
"FROM/SCANFROM-sanaa k\xE4ytetty kahdesti",
"Muuttuja",
@@ -384,7 +384,7 @@ EXTERN char *ErrMsg[] =
"Peruutusarvo annettu kahdesti",
"ONCE-avainsanaa k\x84ytetty kahdesti. (Hah.)",
"AT-sanan per\x84st\x84 puuttuu aika",
"UNTIL-sanaa k\x84ytetty kahdesti",
"THROUGH/UNTIL-sanaa k\x84ytetty kahdesti",
"Ep\x84t\x84ydellinen p\x84iv\x84ys",
"FROM/SCANFROM-sanaa k\x84ytetty kahdesti",
"Muuttuja",
@@ -488,7 +488,7 @@ EXTERN char *ErrMsg[] =
"Peruutusarvo annettu kahdesti",
"ONCE-avainsanaa k{ytetty kahdesti. (Hah.)",
"AT-sanan per{st{ puuttuu aika",
"UNTIL-sanaa k{ytetty kahdesti",
"THROUGH/UNTIL-sanaa k{ytetty kahdesti",
"Ep{t{ydellinen p{iv{ys",
"FROM/SCANFROM-sanaa k{ytetty kahdesti",
"Muuttuja",

View File

@@ -217,7 +217,7 @@ EXTERN char *ErrMsg[] =
"Valeur de retour sp\351cifi\351e deux fois",
"Mot-cl\351 ONCE utilis\351 deux fois. (Hah.)",
"Heure attendue apr\350s AT",
"Mot-cl\351 UNTIL utilis\351 deux fois",
"Mot-cl\351 THROUGH/UNTIL utilis\351 deux fois",
"Sp\351cification de date incompl\350te",
"Mot-cl\351 FROM/SCANFROM utilis\351 deux fois",
"Variable",
@@ -321,7 +321,7 @@ EXTERN char *ErrMsg[] =
"Valeur de retour specifiee deux fois",
"Mot-cle ONCE utilise deux fois. (Hah.)",
"Heure attendue apres AT",
"Mot-cle UNTIL utilise deux fois",
"Mot-cle THROUGH/UNTIL utilise deux fois",
"Specification de date incomplete",
"Mot-cle FROM/SCANFROM utilise deux fois",
"Variable",

View File

@@ -252,7 +252,7 @@ EXTERN char *ErrMsg[] =
"Warto\266\346 cofni\352cia podana dw\363krotnie",
"S\263owo ONCE u\277yte dw\363krotnie.",
"Po AT oczekiwany jest czas",
"S\263owo UNTIL u\277yte dw\363krotnie",
"S\263owo THROUGH/UNTIL u\277yte dw\363krotnie",
"Niekompletna specyfikacja daty",
"S\263owo FROM/SCANFROM u\277yte dw\363krotnie",
"Zmienna",
@@ -355,7 +355,7 @@ EXTERN char *ErrMsg[] =
"Wartosc cofniecia podana dwokrotnie",
"Slowo ONCE uzyte dwokrotnie.",
"Po AT oczekiwany jest czas",
"Slowo UNTIL uzyte dwokrotnie",
"Slowo THROUGH/UNTIL uzyte dwokrotnie",
"Niekompletna specyfikacja daty",
"Slowo FROM/SCANFROM uzyte dwokrotnie",
"Zmienna",

View File

@@ -218,7 +218,7 @@ EXTERN char *ErrMsg[] =
"Valor de Back especificado duas vezes",
"ONCE usado duas vezes (Eheheh)",
"Esperando hora apos AT",
"Keyword UNTIL usada duas vezes",
"Keyword THROUGH/UNTIL usada duas vezes",
"Especificacao de data incompleta",
"Keyword FROM/SCANFROM usada duas vezes",
"Variavel",

View File

@@ -7,7 +7,7 @@
/* */
/* This file is part of REMIND. */
/* Copyright (C) 1992-1998 by David F. Skoll */
/* Copyright (C) 1999-2009 by Roaring Penguin Software Inc. */
/* Copyright (C) 1999-2010 by Roaring Penguin Software Inc. */
/* */
/***************************************************************/
@@ -19,6 +19,9 @@
#include <signal.h>
#include <string.h>
#include <stdarg.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include <ctype.h>
#ifdef TIME_WITH_SYS_TIME
@@ -57,6 +60,10 @@ int main(int argc, char *argv[])
{
int pid;
#ifdef HAVE_SETLOCALE
setlocale(LC_ALL, "");
#endif
/* The very first thing to do is to set up ErrFp to be stderr */
ErrFp = stderr;
@@ -70,6 +77,12 @@ int main(int argc, char *argv[])
return 0;
}
/* Are we purging old reminders? Then just run through the loop once! */
if (PurgeMode) {
DoReminders();
return 0;
}
/* Not doing a calendar. Do the regular remind loop */
ShouldCache = (Iterations > 1);
@@ -123,6 +136,17 @@ int main(int argc, char *argv[])
return 0;
}
void PurgeEchoLine(char const *fmt, ...)
{
va_list argptr;
va_start(argptr, fmt);
if (PurgeFP != NULL) {
(void) vfprintf(PurgeFP, fmt, argptr);
}
va_end(argptr);
}
/***************************************************************/
/* */
/* DoReminders */
@@ -136,6 +160,7 @@ static void DoReminders(void)
Token tok;
char const *s;
Parser p;
int purge_handled;
if (!UseStdin) {
FileAccessDate = GetAccessDate(InitialFile);
@@ -173,23 +198,40 @@ static void DoReminders(void)
ShouldIgnoreLine())
{
/*** IGNORE THE LINE ***/
if (PurgeMode) {
if (strncmp(CurLine, "#!P", 3)) {
PurgeEchoLine("%s\n", CurLine);
}
}
}
else {
purge_handled = 0;
/* Create a parser to parse the line */
CreateParser(s, &p);
switch(tok.type) {
case T_Empty:
case T_Comment:
if (!strncmp(CurLine, "#!P", 3)) {
purge_handled = 1;
}
break;
case T_Rem: r=DoRem(&p); break;
case T_Rem: r=DoRem(&p); purge_handled = 1; break;
case T_ErrMsg: r=DoErrMsg(&p); break;
case T_If: r=DoIf(&p); break;
case T_IfTrig: r=DoIfTrig(&p); break;
case T_Else: r=DoElse(&p); break;
case T_EndIf: r=DoEndif(&p); break;
case T_Include: r=DoInclude(&p); break;
case T_Include:
/* In purge mode, include closes file, so we
need to echo it here! */
if (PurgeMode) {
PurgeEchoLine("%s\n", CurLine);
}
r=DoInclude(&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;
@@ -204,32 +246,42 @@ static void DoReminders(void)
DestroyParser(&p);
CreateParser(s, &p);
r=DoRem(&p);
purge_handled = 1;
}
break;
case T_Pop: r=PopOmitContext(&p); break;
case T_Preserve: r=DoPreserve(&p); break;
case T_Push: r=PushOmitContext(&p); break;
case T_RemType: if (tok.val == RUN_TYPE) {
r=DoRun(&p);
r=DoRun(&p);
} else {
CreateParser(CurLine, &p);
r=DoRem(&p);
purge_handled = 1;
}
break;
} else {
CreateParser(CurLine, &p);
r=DoRem(&p);
break;
}
/* If we don't recognize the command, do a REM by default */
/* Note: Since the parser hasn't been used yet, we don't */
/* need to destroy it here. */
default: CreateParser(CurLine, &p); r=DoRem(&p); break;
default: CreateParser(CurLine, &p); purge_handled = 1; r=DoRem(&p); break;
}
if (r && (!Hush || r != E_RUN_DISABLED)) {
Eprint("%s", ErrMsg[r]);
}
if (PurgeMode) {
if (!purge_handled) {
PurgeEchoLine("%s\n", CurLine);
} else {
if (r) {
PurgeEchoLine("#!P! Could not parse next line: %s\n", ErrMsg[r]);
PurgeEchoLine("%s\n", CurLine);
}
}
}
/* Destroy the parser - free up resources it may be tying up */
DestroyParser(&p);
}
@@ -347,7 +399,7 @@ int ParseChar(ParsePtr p, int *err, int peek)
}
p->expr_happened = 1;
p->pos++;
r = EvalExpr(&(p->pos), &val);
r = EvalExpr(&(p->pos), &val, p);
if (r) {
*err = r;
DestroyParser(p);
@@ -383,7 +435,7 @@ int ParseNonSpaceChar(ParsePtr p, int *err, int peek)
ch = ParseChar(p, err, 1);
if (*err) return 0;
while (isspace(ch)) {
while (isempty(ch)) {
ParseChar(p, err, 0); /* Guaranteed to work */
ch = ParseChar(p, err, 1);
if (*err) return 0;
@@ -407,12 +459,12 @@ int ParseToken(ParsePtr p, DynamicBuffer *dbuf)
c = ParseChar(p, &err, 0);
if (err) return err;
while (c && isspace(c)) {
while (c && isempty(c)) {
c = ParseChar(p, &err, 0);
if (err) return err;
}
if (!c) return OK;
while (c && !isspace(c)) {
while (c && !isempty(c)) {
if (DBufPutc(dbuf, c) != OK) {
DBufFree(dbuf);
return E_NO_MEM;
@@ -443,7 +495,7 @@ int ParseIdentifier(ParsePtr p, DynamicBuffer *dbuf)
c = ParseChar(p, &err, 0);
if (err) return err;
while (c && isspace(c)) {
while (c && isempty(c)) {
c = ParseChar(p, &err, 0);
if (err) return err;
}
@@ -484,13 +536,13 @@ int EvaluateExpr(ParsePtr p, Value *v)
int r;
if (p->isnested) return E_PARSE_ERR; /* Can't nest expressions */
while (isspace(*p->pos)) (p->pos)++;
while (isempty(*p->pos)) (p->pos)++;
if (!p->pos) return E_PARSE_ERR; /* Missing expression */
if (*p->pos == BEG_OF_EXPR) {
(p->pos)++;
bracketed = 1;
}
r = EvalExpr(&(p->pos), v);
r = EvalExpr(&(p->pos), v, p);
if (r) return r;
if (bracketed) {
if (*p->pos != END_OF_EXPR) return E_MISS_END;
@@ -567,6 +619,7 @@ void CreateParser(char const *s, ParsePtr p)
p->allownested = 1;
p->tokenPushed = NULL;
p->expr_happened = 0;
p->nonconst_expr = 0;
DBufInit(&p->pushedToken);
}
@@ -670,10 +723,15 @@ int DoIf(ParsePtr p)
Eprint("%s", ErrMsg[r]);
} else
if ( (v.type != STR_TYPE && v.v.val) ||
(v.type == STR_TYPE && strcmp(v.v.str, "")) )
(v.type == STR_TYPE && strcmp(v.v.str, "")) ) {
syndrome = IF_TRUE | BEFORE_ELSE;
else
} else {
syndrome = IF_FALSE | BEFORE_ELSE;
if (PurgeMode) {
PurgeEchoLine("%s\n", "#!P: The next IF evaluated false...");
PurgeEchoLine("%s\n", "#!P: REM statements in IF block not checked for purging.");
}
}
}
NumIfs++;
@@ -693,6 +751,8 @@ int DoElse(ParsePtr p)
{
unsigned syndrome;
int was_ignoring = ShouldIgnoreLine();
if (!NumIfs) return E_ELSE_NO_IF;
syndrome = IfFlags >> (2 * NumIfs - 2);
@@ -700,6 +760,10 @@ int DoElse(ParsePtr p)
if ((syndrome & IF_ELSE_MASK) == AFTER_ELSE) return E_ELSE_NO_IF;
IfFlags |= AFTER_ELSE << (2 * NumIfs - 2);
if (PurgeMode && ShouldIgnoreLine() && !was_ignoring) {
PurgeEchoLine("%s\n", "#!P: The previous IF evaluated true.");
PurgeEchoLine("%s\n", "#!P: REM statements in ELSE block not checked for purging");
}
return VerifyEoln(p);
}
@@ -739,11 +803,17 @@ int DoIfTrig(ParsePtr p)
jul = ComputeTrigger(trig.scanfrom, &trig, &r, 1);
if (r) syndrome = IF_TRUE | BEFORE_ELSE;
else {
if (ShouldTriggerReminder(&trig, &tim, jul, &err))
if (ShouldTriggerReminder(&trig, &tim, jul, &err)) {
syndrome = IF_TRUE | BEFORE_ELSE;
else
} else {
syndrome = IF_FALSE | BEFORE_ELSE;
if (PurgeMode) {
PurgeEchoLine("%s\n", "#!P: The next IFTRIG did not trigger.");
PurgeEchoLine("%s\n", "#!P: REM statements in IFTRIG block not checked for purging.");
}
}
}
FreeTrig(&trig);
}
NumIfs++;
IfFlags &= ~(IF_MASK << (2*NumIfs - 2));
@@ -889,7 +959,7 @@ int DoBanner(ParsePtr p)
DBufInit(&buf);
c = ParseChar(p, &err, 0);
if (err) return err;
while (isspace(c)) {
while (isempty(c)) {
c = ParseChar(p, &err, 0);
if (err) return err;
}
@@ -969,6 +1039,8 @@ void DoExit(ParsePtr p)
int r;
Value v;
if (PurgeMode) return;
r = EvaluateExpr(p, &v);
if (r || v.type != INT_TYPE) exit(99);
exit(v.v.val);
@@ -990,6 +1062,8 @@ int DoErrMsg(ParsePtr p)
DynamicBuffer buf;
if (PurgeMode) return OK;
DBufInit(&buf);
t.typ = MSG_TYPE;
tt.ttime = SystemTime(0) / 60;
@@ -997,7 +1071,7 @@ int DoErrMsg(ParsePtr p)
return r;
}
s = DBufValue(&buf);
while (isspace(*s)) s++;
while (isempty(*s)) s++;
fprintf(ErrFp, "%s\n", s);
DBufFree(&buf);
return OK;
@@ -1233,3 +1307,18 @@ void SigIntHandler(int d)
GotSigInt();
exit(0);
}
void
AppendTag(DynamicBuffer *buf, char const *s)
{
if (*(DBufValue(buf))) {
DBufPutc(buf, ',');
}
DBufPuts(buf, s);
}
void
FreeTrig(Trigger *t)
{
DBufFree(&(t->tags));
}

View File

@@ -125,7 +125,7 @@ int PushOmitContext(ParsePtr p)
free(context);
return E_NO_MEM;
}
/* Copy the context over */
for (i=0; i<NumFullOmits; i++)
*(context->fullsave + i) = FullOmitArray[i];
@@ -198,7 +198,7 @@ int IsOmitted(int jul, int localomit, char const *omitfunc, int *omit)
sprintf(expr, "%s('%04d-%02d-%02d')",
omitfunc, y, m+1, d);
s = expr;
r = EvalExpr(&s, &v);
r = EvalExpr(&s, &v, NULL);
if (r) return r;
if (v.type == INT_TYPE && v.v.val != 0) {
*omit = 1;
@@ -272,6 +272,9 @@ static void InsertIntoSortedArray(int *array, int num, int key)
*cur = key;
}
static int DoThroughOmit(ParsePtr p, int y, int m, int d);
static void DumpOmits(void);
/***************************************************************/
/* */
/* DoOmit */
@@ -285,15 +288,25 @@ int DoOmit(ParsePtr p)
Token tok;
int parsing=1;
int syndrome;
int not_first_token = -1;
DynamicBuffer buf;
DBufInit(&buf);
/* Parse the OMIT. We need a month and day; year is optional. */
while(parsing) {
not_first_token++;
if ( (r=ParseToken(p, &buf)) ) return r;
FindToken(DBufValue(&buf), &tok);
switch (tok.type) {
case T_Dumpvars:
if (not_first_token) return E_PARSE_ERR;
DBufFree(&buf);
r = VerifyEoln(p);
if (r != OK) return r;
DumpOmits();
return OK;
case T_Date:
DBufFree(&buf);
if (y != NO_YR) return E_YR_TWICE;
@@ -324,6 +337,11 @@ int DoOmit(ParsePtr p)
DBufFree(&buf);
break;
case T_Through:
DBufFree(&buf);
if (y == NO_YR || m == NO_MON || d == NO_DAY) return E_INCOMPLETE;
return DoThroughOmit(p, y, m, d);
case T_Empty:
case T_Comment:
case T_RemType:
@@ -362,7 +380,123 @@ int DoOmit(ParsePtr p)
NumFullOmits++;
}
}
if (tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
if (tok.type == T_Tag || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
return OK;
}
static int
DoThroughOmit(ParsePtr p, int ystart, int mstart, int dstart)
{
int yend = NO_YR, mend = NO_MON, dend = NO_DAY, r;
int start, end, tmp;
Token tok;
DynamicBuffer buf;
DBufInit(&buf);
int parsing = 1;
while(parsing) {
if ( (r=ParseToken(p, &buf)) ) return r;
FindToken(DBufValue(&buf), &tok);
switch(tok.type) {
case T_Date:
DBufFree(&buf);
if (yend != NO_YR) return E_YR_TWICE;
if (mend != NO_MON) return E_MON_TWICE;
if (dend != NO_DAY) return E_DAY_TWICE;
FromJulian(tok.val, &yend, &mend, &dend);
break;
case T_Year:
DBufFree(&buf);
if (yend != NO_YR) return E_YR_TWICE;
yend = tok.val;
break;
case T_Month:
DBufFree(&buf);
if (mend != NO_MON) return E_MON_TWICE;
mend = tok.val;
break;
case T_Day:
DBufFree(&buf);
if (dend != NO_DAY) return E_DAY_TWICE;
dend = tok.val;
break;
case T_Empty:
case T_Comment:
case T_RemType:
case T_Priority:
case T_Tag:
case T_Duration:
DBufFree(&buf);
parsing = 0;
break;
default:
Eprint("%s: `%s' (OMIT)", ErrMsg[E_UNKNOWN_TOKEN],
DBufValue(&buf));
DBufFree(&buf);
return E_UNKNOWN_TOKEN;
}
}
if (yend == NO_YR || mend == NO_MON || dend == NO_DAY) return E_INCOMPLETE;
if (dend > DaysInMonth(mend, yend)) return E_BAD_DATE;
if (dstart > DaysInMonth(mstart, ystart)) return E_BAD_DATE;
start = Julian(ystart, mstart, dstart);
end = Julian(yend, mend, dend);
if (end < start) {
tmp = start;
start = end;
end = tmp;
}
tmp = end - start + 1;
/* Don't create any OMITs if there would be too many. */
if (NumFullOmits + tmp >= MAX_FULL_OMITS) return E_2MANY_FULL;
for (tmp = start; tmp <= end; tmp++) {
if (!BexistsIntArray(FullOmitArray, NumFullOmits, tmp)) {
InsertIntoSortedArray(FullOmitArray, NumFullOmits, tmp);
NumFullOmits++;
}
}
if (tok.type == T_Tag || tok.type == T_Duration || tok.type == T_RemType || tok.type == T_Priority) return E_PARSE_AS_REM;
return OK;
}
void
DumpOmits(void)
{
int i;
int y, m, d;
printf("Global Full OMITs (%d of maximum allowed %d):\n", NumFullOmits, MAX_FULL_OMITS);
if (!NumFullOmits) {
printf("\tNone.\n");
} else {
for (i=0; i<NumFullOmits; i++) {
FromJulian(FullOmitArray[i], &y, &m, &d);
printf("\t%04d%c%02d%c%02d\n",
y, DateSep, m+1, DateSep, d);
}
}
printf("Global Partial OMITs (%d of maximum allowed %d):\n", NumPartialOmits, MAX_PARTIAL_OMITS);
if (!NumPartialOmits) {
printf("\tNone.\n");
} else {
for (i=0; i<NumPartialOmits; i++) {
m = PartialOmitArray[i] >> 5 & 0xf;
d = PartialOmitArray[i] & 0x1f;
printf("\t%02d%c%02d\n", m+1, DateSep, d);
}
}
}

View File

@@ -16,9 +16,12 @@
/* Define a general malloc routine for creating pointers to objects */
#define NEW(type) (malloc(sizeof(type)))
/* Characters to ignore */
#define isempty(c) (isspace(c) || ((c) == '\\'))
#include "dynbuf.h"
int CallUserFunc (char const *name, int nargs);
int CallUserFunc (char const *name, int nargs, ParsePtr p);
int DoFset (ParsePtr p);
void ProduceCalendar (void);
char const *SimpleTime (int tim);
@@ -32,7 +35,7 @@ int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int jul, int *err);
int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul, int mode);
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int jul, int tim);
int ParseLiteralDate (char const **s, int *jul, int *tim);
int EvalExpr (char const **e, Value *v);
int EvalExpr (char const **e, Value *v, ParsePtr p);
int DoCoerce (char type, Value *v);
void PrintValue (Value *v, FILE *fp);
int CopyValue (Value *dest, const Value *src);
@@ -52,7 +55,7 @@ int ParseChar (ParsePtr p, int *err, int peek);
int ParseToken (ParsePtr p, DynamicBuffer *dbuf);
int ParseIdentifier (ParsePtr p, DynamicBuffer *dbuf);
int EvaluateExpr (ParsePtr p, Value *v);
int Evaluate (char const **s, Var *locals);
int Evaluate (char const **s, Var *locals, ParsePtr p);
int FnPopValStack (Value *val);
void Eprint (char const *fmt, ...);
void OutputLine (FILE *fp);
@@ -92,7 +95,7 @@ int StrCmpi (char const *s1, char const *s2);
Var *FindVar (char const *str, int create);
int DeleteVar (char const *str);
int SetVar (char const *str, Value *val);
int GetVarValue (char const *str, Value *val, Var *locals);
int GetVarValue (char const *str, Value *val, Var *locals, ParsePtr p);
int DoSet (Parser *p);
int DoUnset (Parser *p);
int DoDump (ParsePtr p);
@@ -133,4 +136,7 @@ void HuntPhase (int startdate, int starttim, int phas, int *date, int *time);
int CompareRems (int dat1, int tim1, int prio1, int dat2, int tim2, int prio2, int bydate, int bytime, int byprio, int untimed_first);
void SigIntHandler (int d);
void GotSigInt (void);
void SynthesizeTag(char *);
void PurgeEchoLine(char const *fmt, ...);
void FreeTrig(Trigger *t);
void AppendTag(DynamicBuffer *buf, char const *s);
char const *SynthesizeTag(void);

View File

@@ -43,7 +43,7 @@ typedef struct queuedrem {
char const *text;
char passthru[PASSTHRU_LEN+1];
char sched[VAR_NAME_LEN+1];
char tag[TAG_LEN+1];
DynamicBuffer tags;
TimeTrig tt;
} QueuedRem;
@@ -96,9 +96,10 @@ int QueueReminder(ParsePtr p, Trigger *trig,
qelem->RunDisabled = RunDisabled;
qelem->ntrig = 0;
strcpy(qelem->sched, sched);
strcpy(qelem->tag, trig->tag);
if (! *qelem->tag && SynthesizeTags) {
SynthesizeTag(qelem->tag);
DBufInit(&(qelem->tags));
DBufPuts(&(qelem->tags), DBufValue(&(trig->tags)));
if (SynthesizeTags) {
AppendTag(&(qelem->tags), SynthesizeTag());
}
QueueHead = qelem;
return OK;
@@ -235,12 +236,11 @@ void HandleQueuedReminders(void)
printf("NOTE reminder %s",
SimpleTime(q->tt.ttime));
printf("%s", SimpleTime(SystemTime(0)/60));
if (!*q->tag) {
printf("*");
if (!*DBufValue(&q->tags)) {
printf("*\n");
} else {
printf("%s", q->tag);
printf("%s\n", DBufValue(&(q->tags)));
}
printf("\n");
}
/* Set up global variables so some functions like trigdate()
@@ -411,7 +411,7 @@ static int CalculateNextTimeUsingSched(QueuedRem *q)
char exprBuf[VAR_NAME_LEN+32];
sprintf(exprBuf, "%s(%d)", q->sched, q->ntrig);
s = exprBuf;
r = EvalExpr(&s, &v);
r = EvalExpr(&s, &v, NULL);
if (r) {
q->sched[0] = 0;
return NO_TIME;

View File

@@ -32,6 +32,17 @@
#define SPECIAL_WEEK 5
#define SPECIAL_SHADE 6
/* Array holding how specials sort */
static int SpecialSortOrder[] = {
0, /* NORMAL */
1, /* POSTSCRIPT */
1, /* PSFILE */
2, /* MOON */
0, /* COLOR */
4, /* WEEK */
5 /* SHADE */
};
typedef struct calentry {
struct calentry *next;
int special;
@@ -338,11 +349,11 @@ void DoPsCal(void)
d = PsEntries[DayNum];
p = NULL;
/* Slot it into the right place */
while (d->next && (c->special <= d->special)) {
while (d->next && (SpecialSortOrder[c->special] <= SpecialSortOrder[d->special])) {
p = d;
d = d->next;
}
if (c->special <= d->special) {
if (SpecialSortOrder[c->special] <= SpecialSortOrder[d->special]) {
c->next = d->next;
d->next = c;
} else {

View File

@@ -181,7 +181,7 @@ static void IssueSortBanner(int jul)
FromJulian(jul, &y, &m, &d);
sprintf(BanExpr, "sortbanner('%04d/%02d/%02d')", y, m+1, d);
y = EvalExpr(&s, &v);
y = EvalExpr(&s, &v, NULL);
if (y) return;
if (DoCoerce(STR_TYPE, &v)) return;
DBufInit(&buf);

View File

@@ -94,6 +94,7 @@ Token TokArray[] = {
{ "special", 7, T_RemType, PASSTHRU_TYPE },
{ "sunday", 3, T_WkDay, 6 },
{ "tag", 3, T_Tag, 0 },
{ "through", 7, T_Through, 0 },
{ "thursday", 3, T_WkDay, 3 },
{ "tuesday", 3, T_WkDay, 1 },
{ "unset", 5, T_UnSet, 0 },
@@ -146,9 +147,9 @@ char const *FindInitialToken(Token *tok, char const *s)
tok->type = T_Illegal;
while (isspace(*s)) s++;
while (isempty(*s)) s++;
while (*s && !isspace(*s)) {
while (*s && !isempty(*s)) {
if (DBufPutc(&buf, *s++) != OK) return s;
}
@@ -359,7 +360,7 @@ static int TokStrCmp(Token const *t, char const *s)
register int r;
char const *tk = t->name;
while(*tk && *s && !(*s == ',' && *(s+1) == 0)) {
r = *tk - tolower(*s);
r = tolower(*tk) - tolower(*s);
tk++;
s++;
if (r) return r;
@@ -367,5 +368,5 @@ static int TokStrCmp(Token const *t, char const *s)
/* Ignore trailing commas on s */
if (!*s || (*s == ',' && !*(s+1))) return 0;
return (*tk - *s);
return (tolower(*tk) - tolower(*s));
}

View File

@@ -301,7 +301,10 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
/* First: Have we passed the UNTIL date? */
if (trig->until != NO_UNTIL &&
trig->until < start) return -1; /* expired */
trig->until < start) {
trig->expired = 1;
return -1; /* expired */
}
/* Next: If it's an "AFTER"-type skip, back up
until we're at the start of a block of holidays */
@@ -422,6 +425,7 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
y, m, d, omit,
result;
trig->expired = 0;
if (save_in_globals) LastTrigValid = 0;
/* Assume everything works */
@@ -449,6 +453,7 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
/* If there's an error, die immediately */
if (*err) return -1;
if (result == -1) {
trig->expired = 1;
if (DebugFlag & DB_PRTTRIG) {
fprintf(ErrFp, "%s(%d): %s\n",
FileName, LineNo, ErrMsg[E_EXPIRED]);
@@ -485,6 +490,7 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
if (trig->back == NO_BACK &&
trig->skip == NO_SKIP &&
trig->rep == NO_REP) {
trig->expired = 1;
if (DebugFlag & DB_PRTTRIG) {
fprintf(ErrFp, "%s(%d): %s\n",
FileName, LineNo, ErrMsg[E_EXPIRED]);
@@ -513,6 +519,7 @@ int ComputeTrigger(int today, Trigger *trig, int *err, int save_in_globals)
LastTrigValid = 1;
}
}
trig->expired = 1;
if (DebugFlag & DB_PRTTRIG) {
fprintf(ErrFp, "%s(%d): %s\n",
FileName, LineNo, ErrMsg[E_EXPIRED]);

View File

@@ -41,6 +41,7 @@ typedef struct {
char const *name;
char minargs;
char maxargs;
char is_constant;
int (*func)(func_info *);
} BuiltinFunc;
@@ -54,6 +55,7 @@ typedef struct var {
/* A trigger */
typedef struct {
int expired;
int wd;
int d;
int m;
@@ -71,7 +73,7 @@ typedef struct {
char sched[VAR_NAME_LEN+1]; /* Scheduling function */
char warn[VAR_NAME_LEN+1]; /* Warning function */
char omitfunc[VAR_NAME_LEN+1]; /* OMITFUNC function */
char tag[TAG_LEN+1];
DynamicBuffer tags;
char passthru[PASSTHRU_LEN+1];
} Trigger;
@@ -95,6 +97,7 @@ typedef struct {
DynamicBuffer pushedToken; /* Pushed-back token */
char const *tokenPushed; /* NULL if no pushed-back token */
char expr_happened; /* Did we encounter an [expression] ? */
char nonconst_expr; /* Did we encounter a non-constant [expression] ? */
} Parser;
typedef Parser *ParsePtr; /* Pointer to parser structure */
@@ -164,7 +167,8 @@ enum TokTypes
T_Tag,
T_Duration,
T_LongTime,
T_OmitFunc
T_OmitFunc,
T_Through
};
/* The structure of a token */

View File

@@ -243,7 +243,7 @@ static void FSet(UserFunc *f)
/* Call a user-defined function. */
/* */
/***************************************************************/
int CallUserFunc(char const *name, int nargs)
int CallUserFunc(char const *name, int nargs, ParsePtr p)
{
UserFunc *f;
int h = HashVal(name) % FUNC_HASH_SIZE;
@@ -299,9 +299,9 @@ int CallUserFunc(char const *name, int nargs)
s = f->text;
/* Skip the opening bracket, if there's one */
while (isspace(*s)) s++;
while (isempty(*s)) s++;
if (*s == BEG_OF_EXPR) s++;
h = Evaluate(&s, f->locals);
h = Evaluate(&s, f->locals, p);
f->IsActive = 0;
DestroyLocalVals(f);
if (DebugFlag &DB_PRTEXPR) {

View File

@@ -290,7 +290,7 @@ int SetVar(char const *str, Value *val)
/* Get a copy of the value of the variable. */
/* */
/***************************************************************/
int GetVarValue(char const *str, Value *val, Var *locals)
int GetVarValue(char const *str, Value *val, Var *locals, ParsePtr p)
{
Var *v;
@@ -302,6 +302,8 @@ int GetVarValue(char const *str, Value *val, Var *locals)
v = v->next;
}
/* Global variable... mark expression as non-constant */
if (p) p->nonconst_expr = 1;
v=FindVar(str, 0);
if (!v) {
@@ -390,6 +392,8 @@ int DoDump(ParsePtr p)
Var *v;
DynamicBuffer buf;
if (PurgeMode) return OK;
DBufInit(&buf);
r = ParseToken(p, &buf);
if (r) return r;

1
tests/file.ps Normal file
View File

@@ -0,0 +1 @@
(Second-Bit-Of-PS)

1
tests/file2.ps Normal file
View File

@@ -0,0 +1 @@
(Fourth-Bit-Of-PS)

7
tests/purge_dir/f1.rem Normal file
View File

@@ -0,0 +1,7 @@
# This is f1.rem
INCLUDE [filedir()]/f2.rem
INCLUDE [filedir()]/f2.rem
REM 1 Oct 1991 MSG old1.
REM Monday UNTIL 1 Oct 1991 MSG old2.

6
tests/purge_dir/f2.rem Normal file
View File

@@ -0,0 +1,6 @@
# This is f2.rem
REM 3 feb 2012 MSG new
REM 3 1998 MSG old
INCLUDE [filedir()]/f3.rem

92
tests/purge_dir/f3.rem Normal file
View File

@@ -0,0 +1,92 @@
# This is f3.rem
REM Mon MSG repeat
REM Mon SATISFY [1] MSG repeat
IF 0
REM 1991 MSG wookie
ENDIF
IF 1
REM 1991 MSG wookie
ENDIF
IFTRIG 1991
REM MSG wookie
ENDIF
# More complex conditional statements
IF 1
IF 0
REM 1991 MSG wookie
ELSE
REM 1991 MSG wookie
ENDIF
ELSE
IF 1
REM 1991 MSG wookie
ELSE
REM 1991 MSG wookie
ENDIF
ENDIF
REM [1990+1] MSG old-with-constant-expression
REM [1990+1] \
MSG Continued line-old-with-constant-expression
REM 1990 \
MSG expired-continued-line
set y 1990
REM [y+1] MSG old-with-nonconstant-expression
# A comment that should be preserved
#!P A comment that should be nuked because it \
starts with #!P
REM [y+1] \
MSG Continued-line-old-with-nonconstant-expression
OMIT 25 Dec MSG woaaahh!
OMIT 24 Dec
OMIT 1 Jan 1992 MSG woaaahah... expired
OMIT 2 Jan 1992
# Complicated expressions
SET a 3
FSET const(x) x+3
FSET nonconst(x) x+a
REM [const(5)] Jan 1992 MSG expired... should be commented out
REM [const(a)] Jan 1992 MSG nonconstant expression
REM [nonconst(5)] Jan 1992 MSG nonconstant expression
REM [value("a")] Jan 1992 MSG nonconstant expression
IF 0
# A comment in a false IF block
#!P This should be nuked
ENDIF
# Busted line
REM [0/0] Jan 1992 MSG ouch
ERRMSG blorky
FLUSH
SET a 1
FSET a(x) x*x
UNSET a
CLEAR-OMIT-CONTEXT
PUSH-OMIT-CONTEXT
POP-OMIT-CONTEXT
BANNER wow
DEBUG +x
DEBUG -x
DUMP $
EXIT 0
PRESERVE i

View File

@@ -1,3 +1,13 @@
set $MinsFromUTC -240
set $CalcUTC 0
set $Location "Ottawa"
set $LongDeg 75
set $LongMin 39
set $LongSec 0
set $LatDeg 45
set $LatMin 24
set $LatSec 0
IF $PSCAL
[trigger(moondate(0))] SPECIAL MOON 0 -1 -1 [moontime(0)]
[trigger(moondate(1))] SPECIAL MOON 1 -1 -1 [moontime(1)]
@@ -5,6 +15,11 @@ IF $PSCAL
[trigger(moondate(3))] SPECIAL MOON 3 -1 -1 [moontime(3)]
ENDIF
REM 4 PS (First-Bit-Of-PS)
REM 4 PSFILE file.ps
REM 4 PS (Third-Bit-Of-PS)
REM 4 PSFILE file2.ps
REM Mon SPECIAL SHADE 255 255 255
REM Tue SPECIAL SHADE 255 255 204
REM Wed SPECIAL SHADE 255 204 255

View File

@@ -22,28 +22,28 @@ chmod 000 include_dir/04cantread.rem
TEST_GETENV="foo bar baz" ; export TEST_GETENV
echo "Test 1" > ../tests/test.out
echo "" >> ../tests/test.out
../src/remind -e -dxte ../tests/test.rem 16 feb 1991 >> ../tests/test.out
../src/remind -e -dxte ../tests/test.rem 16 feb 1991 >> ../tests/test.out 2>&1
echo "" >> ../tests/test.out
echo "Test 2" >> ../tests/test.out
echo "" >> ../tests/test.out
../src/remind -p -l ../tests/test2.rem 1 aug 2007 >> ../tests/test.out
../src/remind -p -l ../tests/test2.rem 1 aug 2007 >> ../tests/test.out 2>&1
echo "" >> ../tests/test.out
echo "Test 3" >> ../tests/test.out
echo "" >> ../tests/test.out
../src/remind -s ../tests/test2.rem 1 aug 2007 >> ../tests/test.out
../src/remind -s ../tests/test2.rem 1 aug 2007 >> ../tests/test.out 2>&1
echo "" >> ../tests/test.out
echo "Test 4" >> ../tests/test.out
echo "" >> ../tests/test.out
../src/remind -sa ../tests/test2.rem 1 aug 2007 >> ../tests/test.out
../src/remind -sa ../tests/test2.rem 1 aug 2007 >> ../tests/test.out 2>&1
echo "Test 5" >> ../tests/test.out
echo "" >> ../tests/test.out
../src/remind -p -l -b0 ../tests/test3.rem 1 aug 2007 >> ../tests/test.out
../src/remind -p -l -b0 ../tests/test3.rem 1 aug 2007 >> ../tests/test.out 2>&1
echo "Test 6" >> ../tests/test.out
echo "" >> ../tests/test.out
../src/remind -p -l -b1 ../tests/test3.rem 1 aug 2007 >> ../tests/test.out
../src/remind -p -l -b1 ../tests/test3.rem 1 aug 2007 >> ../tests/test.out 2>&1
echo "Test 7" >> ../tests/test.out
echo "" >> ../tests/test.out
../src/remind -p -l -b2 ../tests/test3.rem 1 aug 2007 >> ../tests/test.out
../src/remind -p -l -b2 ../tests/test3.rem 1 aug 2007 >> ../tests/test.out 2>&1
echo "Test 8" >> ../tests/test.out
echo "" >> ../tests/test.out
@@ -58,15 +58,25 @@ echo "" >> ../tests/test.out
chmod 644 include_dir/04cantread.rem
echo "Color Test" >> ../tests/test.out
../src/remind -ccl ../tests/colors.rem 1 aug 2007 >> ../tests/test.out
../src/remind -ccl ../tests/colors.rem 1 aug 2007 >> ../tests/test.out 2>&1
echo "MON WKDAY DAY across year test" >> ../tests/test.out
echo 'REM Mon 29 Dec MSG x' | ../src/remind -dt - 1 Jan 2000 >> ../tests/test.out 2>&1
echo "Sort Test" >> ../tests/test.out
(echo "REM AT 12:00 MSG Untimed"; echo "REM MSG Timed") | ../src/remind -gaaa - 1 Jan 2000 >> ../tests/test.out 2>&1
(echo "REM AT 12:00 MSG Untimed"; echo "REM MSG Timed") | ../src/remind -gaaad - 1 Jan 2000 >> ../tests/test.out 2>&1
(echo "REM AT 12:00 MSG Untimed"; echo "REM MSG Timed") | ../src/remind -q -gaaa - 1 Jan 2000 >> ../tests/test.out 2>&1
(echo "REM AT 12:00 MSG Untimed"; echo "REM MSG Timed") | ../src/remind -q -gaaad - 1 Jan 2000 >> ../tests/test.out 2>&1
echo "Purge Test" >> ../tests/test.out
../src/remind -j999 ../tests/purge_dir/f1.rem >> ../tests/test.out 2>&1
echo "F1" >> ../tests/test.out
cat ../tests/purge_dir/f1.rem.purged >> ../tests/test.out
echo "F2" >> ../tests/test.out
cat ../tests/purge_dir/f2.rem.purged >> ../tests/test.out
echo "F3" >> ../tests/test.out
cat ../tests/purge_dir/f3.rem.purged >> ../tests/test.out
rm -f ../tests/purge_dir/*.rem.purged >> ../tests/test.out 2>&1
../src/remind ../tests/runtest.rem >> ../tests/test.out 2>&1
../src/remind -p ../tests/shade.rem 1 August 2009 | ../src/rem2ps -e -l -c3 >> ../tests/test.out 2>&1

View File

@@ -274,217 +274,221 @@ hebdate(29, "Adar A", 1991-02-16, 5756) => ../tests/test.rem(46): No Adar A in 5
Invalid Hebrew date
Leaving UserFN _i() => Invalid Hebrew date
# This causes a parse error on version 03.01.01
REM 1990-01-01 SATISFY 1
../tests/test.rem(49): Expired
# Test each possible case of the basic reminders.
REM MSG Every Day
../tests/test.rem(50): Trig = Saturday, 16 February, 1991
../tests/test.rem(53): Trig = Saturday, 16 February, 1991
Every Day
REM 18 MSG Every 18th
../tests/test.rem(52): Trig = Monday, 18 February, 1991
../tests/test.rem(55): Trig = Monday, 18 February, 1991
REM 15 MSG Every 15th
../tests/test.rem(53): Trig = Friday, 15 March, 1991
../tests/test.rem(56): Trig = Friday, 15 March, 1991
REM Feb MSG February
../tests/test.rem(55): Trig = Saturday, 16 February, 1991
../tests/test.rem(58): Trig = Saturday, 16 February, 1991
February
REM Jan MSG January
../tests/test.rem(56): Trig = Wednesday, 1 January, 1992
../tests/test.rem(59): Trig = Wednesday, 1 January, 1992
REM March MSG March
../tests/test.rem(57): Trig = Friday, 1 March, 1991
../tests/test.rem(60): Trig = Friday, 1 March, 1991
REM 13 Jan MSG 13 Jan
../tests/test.rem(59): Trig = Monday, 13 January, 1992
../tests/test.rem(62): Trig = Monday, 13 January, 1992
REM 15 Feb MSG 15 Feb
../tests/test.rem(60): Trig = Saturday, 15 February, 1992
../tests/test.rem(63): Trig = Saturday, 15 February, 1992
REM 28 Feb MSG 28 Feb
../tests/test.rem(61): Trig = Thursday, 28 February, 1991
../tests/test.rem(64): Trig = Thursday, 28 February, 1991
REM 29 Feb MSG 29 Feb
../tests/test.rem(62): Trig = Saturday, 29 February, 1992
../tests/test.rem(65): Trig = Saturday, 29 February, 1992
REM 5 Mar MSG 5 Mar
../tests/test.rem(63): Trig = Tuesday, 5 March, 1991
../tests/test.rem(66): Trig = Tuesday, 5 March, 1991
REM 1990 MSG 1990
../tests/test.rem(65): Expired
../tests/test.rem(68): Expired
REM 1991 MSG 1991
../tests/test.rem(66): Trig = Saturday, 16 February, 1991
../tests/test.rem(69): Trig = Saturday, 16 February, 1991
1991
REM 1992 MSG 1991
../tests/test.rem(67): Trig = Wednesday, 1 January, 1992
../tests/test.rem(70): Trig = Wednesday, 1 January, 1992
REM 1 1990 MSG 1 1990
../tests/test.rem(69): Expired
../tests/test.rem(72): Expired
REM 29 1991 MSG 29 1991
../tests/test.rem(70): Trig = Friday, 29 March, 1991
../tests/test.rem(73): Trig = Friday, 29 March, 1991
REM 29 1992 MSG 29 1992
../tests/test.rem(71): Trig = Wednesday, 29 January, 1992
../tests/test.rem(74): Trig = Wednesday, 29 January, 1992
REM 16 1991 MSG 16 1991
../tests/test.rem(72): Trig = Saturday, 16 February, 1991
../tests/test.rem(75): Trig = Saturday, 16 February, 1991
16 1991
REM Jan 1990 MSG Jan 1990
../tests/test.rem(74): Expired
../tests/test.rem(77): Expired
REM Feb 1991 MSG Feb 1991
../tests/test.rem(75): Trig = Saturday, 16 February, 1991
../tests/test.rem(78): Trig = Saturday, 16 February, 1991
Feb 1991
REM Dec 1991 MSG Dec 1991
../tests/test.rem(76): Trig = Sunday, 1 December, 1991
../tests/test.rem(79): Trig = Sunday, 1 December, 1991
REM May 1992 MSG May 1992
../tests/test.rem(77): Trig = Friday, 1 May, 1992
../tests/test.rem(80): Trig = Friday, 1 May, 1992
REM 1 Jan 1991 MSG 1 Jan 1991
../tests/test.rem(79): Expired
../tests/test.rem(82): Expired
REM 16 Feb 1991 MSG 16 Feb 1991
../tests/test.rem(80): Trig = Saturday, 16 February, 1991
../tests/test.rem(83): Trig = Saturday, 16 February, 1991
16 Feb 1991
REM 29 Dec 1992 MSG 29 Dec 1992
../tests/test.rem(81): Trig = Tuesday, 29 December, 1992
../tests/test.rem(84): Trig = Tuesday, 29 December, 1992
REM Sun MSG Sun
../tests/test.rem(83): Trig = Sunday, 17 February, 1991
../tests/test.rem(86): Trig = Sunday, 17 February, 1991
REM Fri Sat Tue MSG Fri Sat Tue
../tests/test.rem(84): Trig = Saturday, 16 February, 1991
../tests/test.rem(87): Trig = Saturday, 16 February, 1991
Fri Sat Tue
REM Sun 16 MSG Sun 16
../tests/test.rem(86): Trig = Sunday, 17 February, 1991
../tests/test.rem(89): Trig = Sunday, 17 February, 1991
REM Mon Tue Wed Thu Fri 1 MSG Mon Tue Wed Thu Fri 1
../tests/test.rem(87): Trig = Friday, 1 March, 1991
../tests/test.rem(90): Trig = Friday, 1 March, 1991
REM Sun Feb MSG Sun Feb
../tests/test.rem(89): Trig = Sunday, 17 February, 1991
../tests/test.rem(92): Trig = Sunday, 17 February, 1991
REM Mon Tue March MSG Mon Tue March
../tests/test.rem(90): Trig = Monday, 4 March, 1991
../tests/test.rem(93): Trig = Monday, 4 March, 1991
REM Sun 16 Feb MSG Sun 16 Feb
../tests/test.rem(92): Trig = Sunday, 17 February, 1991
../tests/test.rem(95): Trig = Sunday, 17 February, 1991
REM Mon Tue 10 March MSG Mon Tue 10 March
../tests/test.rem(93): Trig = Monday, 11 March, 1991
../tests/test.rem(96): Trig = Monday, 11 March, 1991
REM Sat Sun 1991 MSG Sat Sun 1991
../tests/test.rem(95): Trig = Saturday, 16 February, 1991
../tests/test.rem(98): Trig = Saturday, 16 February, 1991
Sat Sun 1991
REM Mon Tue 1992 MSG Mon Tue 1992
../tests/test.rem(96): Trig = Monday, 6 January, 1992
../tests/test.rem(99): Trig = Monday, 6 January, 1992
REM Sun 16 1991 MSG Sun 16 1991
../tests/test.rem(98): Trig = Sunday, 17 February, 1991
../tests/test.rem(101): Trig = Sunday, 17 February, 1991
REM Mon Tue Wed Thu Fri 1 1992 MSG Mon Tue Wed Thu Fri 1 1992
../tests/test.rem(99): Trig = Wednesday, 1 January, 1992
../tests/test.rem(102): Trig = Wednesday, 1 January, 1992
REM Mon Feb 1991 MSG Mon Feb 1991
../tests/test.rem(101): Trig = Monday, 18 February, 1991
../tests/test.rem(104): Trig = Monday, 18 February, 1991
REM Tue Jan 1992 MSG Tue Jan 1992
../tests/test.rem(102): Trig = Tuesday, 7 January, 1992
../tests/test.rem(105): Trig = Tuesday, 7 January, 1992
REM Sun Mon 16 Feb 1991 MSG Sun Mon 16 Feb 1991
../tests/test.rem(104): Trig = Sunday, 17 February, 1991
../tests/test.rem(107): Trig = Sunday, 17 February, 1991
REM Tue 28 Jan 1992 MSG Tue 28 Jan 1992
../tests/test.rem(105): Trig = Tuesday, 28 January, 1992
../tests/test.rem(108): Trig = Tuesday, 28 January, 1992
# Try some Backs
CLEAR-OMIT-CONTEXT
REM 1 -1 OMIT sat sun MSG 1 -1 OMIT Sat Sun
../tests/test.rem(109): Trig = Thursday, 28 February, 1991
../tests/test.rem(112): Trig = Thursday, 28 February, 1991
REM 1 --1 OMIT sat sun MSG 1 --1 OMIT Sat Sun
../tests/test.rem(110): Trig = Thursday, 28 February, 1991
../tests/test.rem(113): Trig = Thursday, 28 February, 1991
OMIT 28 Feb
REM 1 -1 OMIT sat sun MSG 1 -1 OMIT Sat Sun (28 Feb omitted)
../tests/test.rem(113): Trig = Wednesday, 27 February, 1991
../tests/test.rem(116): Trig = Wednesday, 27 February, 1991
REM 1 --1 OMIT sat sun MSG 1 --1 OMIT Sat Sun (28 Feb omitted)
../tests/test.rem(114): Trig = Thursday, 28 February, 1991
../tests/test.rem(117): Trig = Thursday, 28 February, 1991
CLEAR-OMIT-CONTEXT
# Try out UNTIL
REM Wed UNTIL 21 Feb 1991 MSG Wed UNTIL 21 Feb 1991
../tests/test.rem(119): Trig = Wednesday, 20 February, 1991
../tests/test.rem(122): Trig = Wednesday, 20 February, 1991
# Try playing with the OMIT context
OMIT 28 Feb 1991
REM 1 Mar -1 MSG 1 mar -1 (28feb91 omitted)
../tests/test.rem(124): Trig = Wednesday, 27 February, 1991
../tests/test.rem(127): Trig = Wednesday, 27 February, 1991
REM 1 Mar --1 MSG 1 mar --1 (28Feb91 omitted)
../tests/test.rem(125): Trig = Thursday, 28 February, 1991
../tests/test.rem(128): Trig = Thursday, 28 February, 1991
REM 28 Feb BEFORE MSG 28 Feb BEFORE (28Feb91 omitted)
../tests/test.rem(126): Trig = Wednesday, 27 February, 1991
../tests/test.rem(129): Trig = Wednesday, 27 February, 1991
REM 28 Feb SKIP MSG 28 Feb SKIP (28Feb91 omitted)
../tests/test.rem(127): Trig = Friday, 28 February, 1992
../tests/test.rem(130): Trig = Friday, 28 February, 1992
REM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted)
../tests/test.rem(128): Trig = Friday, 1 March, 1991
../tests/test.rem(131): Trig = Friday, 1 March, 1991
PUSH-OMIT-CONTEXT
CLEAR-OMIT-CONTEXT
REM 1 Mar -1 MSG 1 mar -1
../tests/test.rem(132): Trig = Thursday, 28 February, 1991
REM 1 Mar --1 MSG 1 mar --1
../tests/test.rem(133): Trig = Thursday, 28 February, 1991
REM 28 Feb BEFORE MSG 28 Feb BEFORE
../tests/test.rem(134): Trig = Thursday, 28 February, 1991
REM 28 Feb SKIP MSG 28 Feb SKIP
../tests/test.rem(135): Trig = Thursday, 28 February, 1991
REM 28 Feb AFTER MSG 28 Feb AFTER
REM 1 Mar --1 MSG 1 mar --1
../tests/test.rem(136): Trig = Thursday, 28 February, 1991
REM 28 Feb BEFORE MSG 28 Feb BEFORE
../tests/test.rem(137): Trig = Thursday, 28 February, 1991
REM 28 Feb SKIP MSG 28 Feb SKIP
../tests/test.rem(138): Trig = Thursday, 28 February, 1991
REM 28 Feb AFTER MSG 28 Feb AFTER
../tests/test.rem(139): Trig = Thursday, 28 February, 1991
POP-OMIT-CONTEXT
REM 1 Mar -1 MSG 1 mar -1 (28feb91 omitted)
../tests/test.rem(139): Trig = Wednesday, 27 February, 1991
../tests/test.rem(142): Trig = Wednesday, 27 February, 1991
REM 1 Mar --1 MSG 1 mar --1 (28Feb91 omitted)
../tests/test.rem(140): Trig = Thursday, 28 February, 1991
../tests/test.rem(143): Trig = Thursday, 28 February, 1991
REM 28 Feb BEFORE MSG 28 Feb BEFORE (28Feb91 omitted)
../tests/test.rem(141): Trig = Wednesday, 27 February, 1991
../tests/test.rem(144): Trig = Wednesday, 27 February, 1991
REM 28 Feb SKIP MSG 28 Feb SKIP (28Feb91 omitted)
../tests/test.rem(142): Trig = Friday, 28 February, 1992
../tests/test.rem(145): Trig = Friday, 28 February, 1992
REM 28 Feb AFTER MSG 28 Feb AFTER (28Feb91 omitted)
../tests/test.rem(143): Trig = Friday, 1 March, 1991
../tests/test.rem(146): Trig = Friday, 1 March, 1991
REM 13 March 1991 *1 UNTIL 19 March 1991 MSG 13-19 Mar 91
../tests/test.rem(146): Trig = Wednesday, 13 March, 1991
../tests/test.rem(149): Trig = Wednesday, 13 March, 1991
# Test BACK
CLEAR-OMIT-CONTEXT
REM 18 Feb 1991 +1 MSG 18 Feb 1991 +1
../tests/test.rem(150): Trig = Monday, 18 February, 1991
../tests/test.rem(153): Trig = Monday, 18 February, 1991
OMIT 17 Feb 1991
REM 18 Feb 1991 +1 MSG 18 Feb 1991 +1 (17Feb91 omitted)
../tests/test.rem(153): Trig = Monday, 18 February, 1991
../tests/test.rem(156): Trig = Monday, 18 February, 1991
18 Feb 1991 +1 (17Feb91 omitted)
REM 18 Feb 1991 ++1 MSG 18 Feb 1991 ++1 (17Feb91 omitted)
../tests/test.rem(154): Trig = Monday, 18 February, 1991
../tests/test.rem(157): Trig = Monday, 18 February, 1991
CLEAR-OMIT-CONTEXT
# Test the scanfrom clause
REM Fri SATISFY 1
../tests/test.rem(158): Trig = Friday, 22 February, 1991
../tests/test.rem(161): Trig = Friday, 22 February, 1991
OMIT [trigger(trigdate())]
trigdate() => 1991-02-22
trigger(1991-02-22) => "22 February 1991"
REM Fri after MSG 23 Feb 1991
../tests/test.rem(160): Trig = Saturday, 23 February, 1991
../tests/test.rem(163): Trig = Saturday, 23 February, 1991
CLEAR-OMIT-CONTEXT
REM Fri SCANFROM [trigger(today()-7)] SATISFY 1
today() => 1991-02-16
1991-02-16 - 7 => 1991-02-09
trigger(1991-02-09) => "9 February 1991"
../tests/test.rem(162): Trig = Friday, 15 February, 1991
../tests/test.rem(165): Trig = Friday, 15 February, 1991
OMIT [trigger(trigdate())]
trigdate() => 1991-02-15
trigger(1991-02-15) => "15 February 1991"
REM Fri after MSG 16 Feb 1991
../tests/test.rem(164): Trig = Saturday, 16 February, 1991
../tests/test.rem(167): Trig = Saturday, 16 February, 1991
16 Feb 1991
CLEAR-OMIT-CONTEXT
@@ -582,7 +586,7 @@ day(1991-03-08) => 8
8 % 2 => 0
0 || 0 => 0
Leaving UserFN _ofunc() => 0
../tests/test.rem(169): Trig = Friday, 8 March, 1991
../tests/test.rem(172): Trig = Friday, 8 March, 1991
REM 8 March OMITFUNC _ofunc -1 MSG OmitFunc Test 2
Entering UserFN _ofunc(1991-03-07)
x => 1991-03-07
@@ -656,31 +660,31 @@ day(1991-02-28) => 28
28 % 2 => 0
0 || 0 => 0
Leaving UserFN _ofunc() => 0
../tests/test.rem(170): Trig = Thursday, 28 February, 1991
../tests/test.rem(173): Trig = Thursday, 28 February, 1991
# omitfunc ignores local/global omits
fset _ofunc(x) 0
OMIT 1 March
OMIT 2 March 1991
REM 1 March OMIT Sun OMITFUNC _ofunc AFTER MSG Should trigger 1 March
../tests/test.rem(176): Warning: OMIT is ignored if you use OMITFUNC
../tests/test.rem(179): Warning: OMIT is ignored if you use OMITFUNC
Entering UserFN _ofunc(1991-02-15)
Leaving UserFN _ofunc() => 0
Entering UserFN _ofunc(1991-03-01)
Leaving UserFN _ofunc() => 0
../tests/test.rem(176): Trig = Friday, 1 March, 1991
../tests/test.rem(179): Trig = Friday, 1 March, 1991
REM 1 March OMIT Sun AFTER MSG Should trigger 4 March
../tests/test.rem(177): Trig = Monday, 4 March, 1991
../tests/test.rem(180): Trig = Monday, 4 March, 1991
# Test shorthand reminders
REM 1991-02-28 MSG Feb 28
../tests/test.rem(180): Trig = Thursday, 28 February, 1991
../tests/test.rem(183): Trig = Thursday, 28 February, 1991
REM 1991/02/28@14:45 MSG Feb 28
../tests/test.rem(181): Trig = Thursday, 28 February, 1991
../tests/test.rem(184): Trig = Thursday, 28 February, 1991
REM Wed UNTIL 1991-01-01 MSG Expired
../tests/test.rem(182): Expired
../tests/test.rem(185): Expired
REM Wed SCANFROM 1991-02-26 MSG SCANFROM
../tests/test.rem(183): Trig = Wednesday, 27 February, 1991
../tests/test.rem(186): Trig = Wednesday, 27 February, 1991
set a000 abs(1)
abs(1) => 1
@@ -704,7 +708,7 @@ set a008 coerce("string", 11:44)
coerce("string", 11:44) => "11:44"
set a009 coerce("int", "badnews")
coerce("int", "badnews") => Can't coerce
../tests/test.rem(194): Can't coerce
../tests/test.rem(197): Can't coerce
set a010 coerce("int", "12")
coerce("int", "12") => 12
set a011 coerce("int", 11:44)
@@ -716,7 +720,7 @@ set a013 date(1992, 2, 2)
date(1992, 2, 2) => 1992-02-02
set a014 date(1993, 2, 29)
date(1993, 2, 29) => Bad date specification
../tests/test.rem(199): Bad date specification
../tests/test.rem(202): Bad date specification
set a015 day(today())
today() => 1991-02-16
day(1991-02-16) => 16
@@ -811,15 +815,15 @@ strlen("sadjflkhsldkfhsdlfjhk") => 21
set a050 substr(a049, 2)
a049 => 21
substr(21, 2) => Type mismatch
../tests/test.rem(237): Type mismatch
../tests/test.rem(240): Type mismatch
set a051 substr(a050, 2, 6)
a050 => ../tests/test.rem(238): Undefined variable: a050
a050 => ../tests/test.rem(241): Undefined variable: a050
set a052 time(1+2, 3+4)
1 + 2 => 3
3 + 4 => 7
time(3, 7) => 03:07
rem 10 jan 1992 AT 11:22 CAL
../tests/test.rem(240): Trig = Friday, 10 January, 1992
../tests/test.rem(243): Trig = Friday, 10 January, 1992
set a053 trigdate()
trigdate() => 1992-01-10
set a054 trigtime()
@@ -832,7 +836,7 @@ set a057 value("a05"+"6")
"a05" + "6" => "a056"
value("a056") => "SDFJHSDF KSJDFH KJSDFH KSJDFH"
set a058 version()
version() => "03.01.08"
version() => "03.01.10"
set a059 wkday(today())
today() => 1991-02-16
wkday(1991-02-16) => "Saturday"
@@ -911,31 +915,31 @@ y => 11:33
x => "foo"
y => 11:33
"foo" * 11:33 => Type mismatch
../tests/test.rem(263): `*': Type mismatch
../tests/test.rem(266): `*': Type mismatch
Leaving UserFN h() => Type mismatch
set a074 dosubst("%a %b %c %d %e %f %g %h", '1992/5/5')
dosubst("%a %b %c %d %e %f %g %h", 1992-05-05) => "on Tuesday, 5 May, 1992 in 444 days' tim"...
msg [a074]%
../tests/test.rem(265): Trig = Saturday, 16 February, 1991
../tests/test.rem(268): Trig = Saturday, 16 February, 1991
a074 => "on Tuesday, 5 May, 1992 in 444 days' tim"...
on Tuesday, 5 May, 1992 in 444 days' time on Tuesday 5 on 05-05-1992 on 05-05-1992 on Tuesday, 5 May on 05-05
set a075 dosubst("%i %j %k %l %m %n %o %p", '1992/5/5')
dosubst("%i %j %k %l %m %n %o %p", 1992-05-05) => "on 05-05 on Tuesday, May 5th, 1992 on Tu"...
msg [a075]%
../tests/test.rem(267): Trig = Saturday, 16 February, 1991
../tests/test.rem(270): Trig = Saturday, 16 February, 1991
a075 => "on 05-05 on Tuesday, May 5th, 1992 on Tu"...
on 05-05 on Tuesday, May 5th, 1992 on Tuesday, May 5th on 1992-05-05 May 5 s
set a076 dosubst("%q %r %s %t %u %v %w %x", '1992/5/5')
dosubst("%q %r %s %t %u %v %w %x", 1992-05-05) => "s' 05 th 05 on Tuesday, 5th May, 1992 on"...
msg [a076]%
../tests/test.rem(269): Trig = Saturday, 16 February, 1991
../tests/test.rem(272): Trig = Saturday, 16 February, 1991
a076 => "s' 05 th 05 on Tuesday, 5th May, 1992 on"...
s' 05 th 05 on Tuesday, 5th May, 1992 on Tuesday, 5th May Tuesday 444
set a077 dosubst("%y %z", '1992/5/5')
dosubst("%y %z", 1992-05-05) => "1992 92
"
msg [a077]%
../tests/test.rem(271): Trig = Saturday, 16 February, 1991
../tests/test.rem(274): Trig = Saturday, 16 February, 1991
a077 => "1992 92
"
1992 92
@@ -985,7 +989,7 @@ dump
a048 "foo"
a067 "INT"
a039 "February"
a058 "03.01.08"
a058 "03.01.10"
a077 "1992 92
"
a049 21
@@ -1042,6 +1046,32 @@ dump
a045 "iess"
a064 1
a083 1991-03-24
OMIT 2010-09-03 THROUGH 2010-09-15
OMIT December 25 MSG X
../tests/test.rem(286): Trig = Wednesday, 25 December, 1991
# Next should give a parse error
OMIT 26 Dec 2010 THROUGH 27 Dec 2010 MSG This is not legal
../tests/test.rem(288): Trig = Sunday, 26 December, 2010
OMIT DUMP
Global Full OMITs (16 of maximum allowed 500):
1991-03-11
2010-09-03
2010-09-04
2010-09-05
2010-09-06
2010-09-07
2010-09-08
2010-09-09
2010-09-10
2010-09-11
2010-09-12
2010-09-13
2010-09-14
2010-09-15
2010-12-26
2010-12-27
Global Partial OMITs (1 of maximum allowed 366):
12-25
Test 2
@@ -2150,6 +2180,134 @@ Timed
Untimed
Purge Test
../tests/purge_dir/f3.rem(76): `/': Division by zero
../tests/purge_dir/f3.rem(76): `/': Division by zero
F1
# This is f1.rem
INCLUDE [filedir()]/f2.rem
INCLUDE [filedir()]/f2.rem
#!P: Expired: REM 1 Oct 1991 MSG old1.
#!P: Expired: REM Monday UNTIL 1 Oct 1991 MSG old2.
F2
# This is f2.rem
REM 3 feb 2012 MSG new
#!P: Expired: REM 3 1998 MSG old
INCLUDE [filedir()]/f3.rem
F3
# This is f3.rem
REM Mon MSG repeat
#!P: Cannot purge SATISFY-type reminders
REM Mon SATISFY [1] MSG repeat
#!P: The next IF evaluated false...
#!P: REM statements in IF block not checked for purging.
IF 0
REM 1991 MSG wookie
ENDIF
IF 1
#!P: Expired: REM 1991 MSG wookie
ENDIF
#!P: The next IFTRIG did not trigger.
#!P: REM statements in IFTRIG block not checked for purging.
IFTRIG 1991
REM MSG wookie
ENDIF
# More complex conditional statements
IF 1
#!P: The next IF evaluated false...
#!P: REM statements in IF block not checked for purging.
IF 0
REM 1991 MSG wookie
ELSE
#!P: Expired: REM 1991 MSG wookie
ENDIF
#!P: The previous IF evaluated true.
#!P: REM statements in ELSE block not checked for purging
ELSE
IF 1
REM 1991 MSG wookie
ELSE
REM 1991 MSG wookie
ENDIF
ENDIF
#!P: Next line has expired, but contains expression... please verify
#!P: Expired: REM [1990+1] MSG old-with-constant-expression
#!P: Next line has expired, but contains expression... please verify
#!P: Expired: REM [1990+1] \
MSG Continued line-old-with-constant-expression
#!P: Expired: REM 1990 \
MSG expired-continued-line
set y 1990
#!P: Next line may have expired, but contains non-constant expression
REM [y+1] MSG old-with-nonconstant-expression
# A comment that should be preserved
#!P: Next line may have expired, but contains non-constant expression
REM [y+1] \
MSG Continued-line-old-with-nonconstant-expression
OMIT 25 Dec MSG woaaahh!
OMIT 24 Dec
#!P: Expired: OMIT 1 Jan 1992 MSG woaaahah... expired
OMIT 2 Jan 1992
# Complicated expressions
SET a 3
FSET const(x) x+3
FSET nonconst(x) x+a
#!P: Next line has expired, but contains expression... please verify
#!P: Expired: REM [const(5)] Jan 1992 MSG expired... should be commented out
#!P: Next line may have expired, but contains non-constant expression
REM [const(a)] Jan 1992 MSG nonconstant expression
#!P: Next line may have expired, but contains non-constant expression
REM [nonconst(5)] Jan 1992 MSG nonconstant expression
#!P: Next line may have expired, but contains non-constant expression
REM [value("a")] Jan 1992 MSG nonconstant expression
#!P: The next IF evaluated false...
#!P: REM statements in IF block not checked for purging.
IF 0
# A comment in a false IF block
ENDIF
# Busted line
#!P! Could not parse next line: Division by zero
REM [0/0] Jan 1992 MSG ouch
ERRMSG blorky
FLUSH
SET a 1
FSET a(x) x*x
UNSET a
CLEAR-OMIT-CONTEXT
PUSH-OMIT-CONTEXT
POP-OMIT-CONTEXT
BANNER wow
DEBUG +x
DEBUG -x
DUMP $
EXIT 0
PRESERVE i
../tests/runtest.rem(2): shell(): RUN disabled
../tests/runinc.rem(1): shell(): RUN disabled
../tests/runinc.rem(3): shell(): RUN disabled
@@ -2527,7 +2685,10 @@ _A BoxHeight _A sub lineto closepath
BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto
_A BoxHeight _A sub lineto closepath
1 1 0.8 setrgbcolor fill 0.0 setgray
(First-Bit-Of-PS)
(Second-Bit-Of-PS)
(Third-Bit-Of-PS)
(Fourth-Bit-Of-PS)
SAVESTATE restore
/SAVESTATE save def
3 xincr mul MinX add ytop translate

View File

@@ -45,6 +45,9 @@ fset _i(x,y,z,a) trigger(hebdate(x,y,z,a))
[_i(29, "Adar A", today(), 5755)] MSG Leap
[_i(29, "Adar A", today(), 5756)] MSG Illegal
# This causes a parse error on version 03.01.01
REM 1990-01-01 SATISFY 1
# Test each possible case of the basic reminders.
REM MSG Every Day
@@ -279,3 +282,8 @@ set a083 slide('1991-04-01', -7, "Sat")
set a084 nonomitted('1991-03-01', '1991-03-13', "Sat", "Sun")
set a085 nonomitted('1991-03-24', '1991-04-01', "Sat")
dump
OMIT 2010-09-03 THROUGH 2010-09-15
OMIT December 25 MSG X
# Next should give a parse error
OMIT 26 Dec 2010 THROUGH 27 Dec 2010 MSG This is not legal
OMIT DUMP