Compare commits

..

42 Commits

Author SHA1 Message Date
Dianne Skoll
4ab8897577 Update WHATSNEW. 2025-07-16 11:07:43 -04:00
Dianne Skoll
9613417a2e Bump version to 05.04.02 2025-07-16 11:03:25 -04:00
Dianne Skoll
f808a2963d When using -dt, print the trigger date for a fully-specified but expired trigger. 2025-07-09 12:11:38 -04:00
Dianne Skoll
96a4dc3189 Make macro safer. 2025-07-07 22:21:53 -04:00
Dianne Skoll
3c60285466 Add Chinese new year dates 2051 through 2100. 2025-07-05 17:50:53 -04:00
Dianne Skoll
6fed350e1f Give better error messages thant "Type mismatch" for bad month or weekday names. 2025-07-05 09:52:30 -04:00
Dianne Skoll
9f220555af Exit early from FromDSE if all we need is the year. 2025-07-02 14:39:15 -04:00
Dianne Skoll
005ccef953 Pass NULLs in a bunch of places where FromDSE result is not needed. 2025-07-02 14:21:32 -04:00
Dianne Skoll
578c98c865 Pass NULLs to FromDSE for info we don't need. 2025-07-02 14:10:42 -04:00
Dianne Skoll
64bf3381c6 Document mon(STRING) 2025-07-02 14:02:42 -04:00
Dianne Skoll
02ade6fc58 Add tests. 2025-07-02 11:42:03 -04:00
Dianne Skoll
2954fca8d8 Allow month to be specified by name in all places where it can be specified by number. 2025-07-02 11:40:02 -04:00
Dianne Skoll
8356dacf2a Allow first argument of daysinmon to be a string. 2025-07-02 11:20:15 -04:00
Dianne Skoll
4fd145cf4e Allow daysinmon() to take a single DATE or DATETIME argument. 2025-07-02 10:14:48 -04:00
Dianne Skoll
1af2bdf8f1 Add test to ensure "unsatisfied" SATISFY clears trigvalid() 2025-07-01 16:51:16 -04:00
Dianne Skoll
9b98e65e01 Don't set trigvalid() for a reminder whose SATISFY clause is never satisfied. 2025-07-01 16:49:06 -04:00
Dianne Skoll
0f83b98698 Fix bug that didn't save trigger date for a fully-specified REM in the past. 2025-06-30 19:23:45 -04:00
Dianne Skoll
4fd62f9894 Move contents of NOTE-ABOUT-AI.txt into README.md 2025-06-26 10:51:34 -04:00
Dianne Skoll
cc06592fe0 Update documentation to reflect reality. 2025-06-18 11:02:37 -04:00
Dianne Skoll
21d28ebfc3 Bump version to 05.04.01. 2025-06-15 09:29:36 -04:00
Dianne Skoll
b300422cdb Update release notes. 2025-06-15 09:27:57 -04:00
Dianne Skoll
37e09f4671 Fix bug in processing UNTIL clause.
Bug found by Ian! D. Allen.
2025-06-15 09:15:48 -04:00
Dianne Skoll
b6e53341c8 Add utils/add-html-anchors.rem standard file. 2025-06-10 14:26:51 -04:00
Dianne Skoll
896fcf1d7f Yet more wording. 2025-06-07 23:05:34 -04:00
Dianne Skoll
72155329f2 Tweak wording, again. 2025-06-07 23:04:47 -04:00
Dianne Skoll
36c7db510a Tweak wording. 2025-06-07 23:03:46 -04:00
Dianne Skoll
d4aa73747d Add some comments. 2025-06-07 22:45:02 -04:00
Dianne Skoll
3ed657b708 Add a couple more SPECIALs to test. 2025-06-07 22:40:55 -04:00
Dianne Skoll
0441c0263b Make rem2pdf *ACTUALLY* support "special colour" 2025-06-07 22:38:19 -04:00
Dianne Skoll
c40d4ee672 Fix misleading comment. 2025-06-07 22:13:08 -04:00
Dianne Skoll
96f2d6537a Update the main README.md file. 2025-06-06 21:54:49 -04:00
Dianne Skoll
dc777c95df Fix cppcheck warning. 2025-06-03 16:54:47 -04:00
Dianne Skoll
3090d77346 Update WHATSNEW. 2025-06-03 12:34:08 -04:00
Dianne Skoll
157d2821f3 Don't Eprint errors if we're supposed to be ignoring lines. 2025-05-28 14:52:12 -04:00
Dianne Skoll
71d2da19a8 Introduce "FSET - f(args) expr" syntax to define a function and suppress any "redefined function" warnings. 2025-05-28 14:40:46 -04:00
Dianne Skoll
516b9c81b3 Get rid of ancient cruft. 2025-05-28 14:23:56 -04:00
Dianne Skoll
58d0e38f1a Remove superfluous assignments. 2025-05-28 14:17:21 -04:00
Dianne Skoll
68d487ade9 Make a macro DBGX to avoid typo-ing '&' as '&&' in future. :) 2025-05-26 22:44:28 -04:00
Dianne Skoll
9d42879170 Make "value" constant iff variable exists and is constant.
Otherwise, it's non-constant.
2025-05-26 22:22:49 -04:00
Dianne Skoll
db70aabc97 Use ParseIdentifier instead of ParseToken with "PRESERVE"
to avoid creating illegal variable names.
2025-05-26 22:09:21 -04:00
Dianne Skoll
c8f55ef60b Note that value evaluates its second argument lazily. 2025-05-26 21:59:24 -04:00
Dianne Skoll
44b50fc6be Make "value()" evaluate its second argument lazily.
If the variable whose name is the first argument exists, don't
bother evaluating the second argument.
2025-05-26 21:56:04 -04:00
26 changed files with 623 additions and 198 deletions

View File

@@ -55,6 +55,39 @@ edit custom.h on your behalf:
`wish ./build.tk`
## Usage
Remind is a large and complex program. You can read the full manual page
with:
`man remind`
after installation. However, the man page is long and detailed and is
more of a reference than an introduction. You can get an overview
with a [slide deck](https://dianne.skoll.ca/projects/remind/download/remind-oclug.pdf)
I made a while back. There's also a (long) [YouTube video](https://www.youtube.com/watch?v=0SNgvsDvx7M) that serves as an
introduction to Remind.
## A Note about AI
1. No part of Remind was written using AI of any type.<br><br>
I certify that all of the C, Perl and Tcl code in Remind was written
by a human being. I certify that all code in `.rem` files other than
ones under `include/holidays` was written by a human being. The code
under `include/holidays` was derived from the Python "holidays" library
and I have no direct knowledge of the provenance of that library,
though I suspect it's entirely or almost entirely human-written.
2. No AI-generated patches or other sorts of contributions to Remind
will be accepted.
3. Remind's source code may not be used to train an AI model,
including an LLM model, unless all of the output of said model is
released under the GNU General Public License, version 2. If you use
any of Remind's source code to train your model, then anything that
the model produces is a derived product of Remind and must be licensed
under the same terms as Remind.
---
Contact info: dianne@skoll.ca

18
configure vendored
View File

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

View File

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

View File

@@ -1,6 +1,41 @@
CHANGES TO REMIND
* VERSION 5.4 Patch 0 - 2025-??-??
* VERSION 5,4 Patch 2 - 2025-07-16
- MINOR CHANGE: remind: Allow daysinmon() to take a DATE or DATETIME
argument.
- MINOR CHANGE: remind: All functions that want an integer month number
will now also accept a string naming the month.
= UPDATE: include/holidays/chinese-new-year.rem: Add dates for Chinese
New Year for 2051 through 2100.
- BUG FIX: remind: Set trigdate() correctly for a fully-specified
date, even if it's in the past, as the manual documnented. Bug
found by Tim Chase.
- DOCUMENTATION FIX: rem2html: Document the correct Perl module
prerequisites.
- CODE FIXES: remind: Various minor improvements to the code with
no user-visible changes.
* VERSION 5.4 Patch 1 - 2025-06-15
- MAJOR BUG FIX: remind: In some circumstances, a REM command could
yield a trigger date after its UNTIL date, rather than recognizing it
as having expired. This has been fixed. Bug found by Ian! D. Allen.
- BUG FIX: rem2pdf: Support the COLOUR special (as well as COLOR).
- MINOR IMPROVEMENT: Add include/utils/add-html-anchors.rem. You can
INCLUDE this file to get HTML anchors added to every calendar day
by rem2html.
- DOCUMENTATION: Add NOTE-ABOUT-AI.txt
* VERSION 5.4 Patch 0 - 2025-06-03
- MAJOR IMPROVEMENT: remind: Track which expressions and variables
Remind can prove to its satisfaction are "constant" - that is, that
@@ -26,6 +61,20 @@ CHANGES TO REMIND
corresponding $Tb system variable. See the remind(1) man page for
details.
- MINOR IMPROVEMENT: remind: make value("var", default) evaluate the
second argument lazily: If "var" is defined, then the second
argument is never evaluated.
- MINOR IMPROVEMENT: remind: Add syntax for redefining a function without
issuing a warning. The syntax:
FSET - func(x) expr
is equivalent to:
FUNSET func
FSET func(x) expr
- MINOR IMPROVEMENT: include/holidays: Update a bunch of files to use
isany(n, a, b, c) rather than (n == a || n == b || n == c)
@@ -1500,10 +1549,10 @@ CHANGES TO REMIND
- NEW FEATURE: Add "-u+username" variant to tell Remind to switch users to
"username" without disabling RUN directives. Idea courtesy of Ian! D. Allen
- CHANGE: rem2html: rem2html has been moved out of the www/ directory into
its own rem2html/ directory. If your system has the prerequisites
(namely Perl, Getopt::Long and JSON::Any) then rem2html will be installed
by "make install".
- CHANGE: rem2html: rem2html has been moved out of the www/ directory
into its own rem2html/ directory. If your system has the
prerequisites (namely Perl, Getopt::Long and JSON::MaybeXS) then
rem2html will be installed by "make install".
- CHANGE: Remove "cm2rem". It was about 20 years obsolete.

View File

@@ -28,3 +28,53 @@ REM 26 Jan 2047 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %
REM 14 Feb 2048 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %(Chinese New Year) (%(Dragon))
REM 2 Feb 2049 INFO "Url: https://en.wikipedia.org/wiki/Snake_(zodiac)" MSG %(Chinese New Year) (%(Snake))
REM 23 Jan 2050 INFO "Url: https://en.wikipedia.org/wiki/Horse_(zodiac)" MSG %(Chinese New Year) (%(Horse))
REM 11 Feb 2051 INFO "Url: https://en.wikipedia.org/wiki/Goat_(zodiac)" MSG %(Chinese New Year) (%(Goat))
REM 1 Feb 2052 INFO "Url: https://en.wikipedia.org/wiki/Monkey_(zodiac)" MSG %(Chinese New Year) (%(Monkey))
REM 19 Feb 2053 INFO "Url: https://en.wikipedia.org/wiki/Rooster_(zodiac)" MSG %(Chinese New Year) (%(Rooster))
REM 8 Feb 2054 INFO "Url: https://en.wikipedia.org/wiki/Dog_(zodiac)" MSG %(Chinese New Year) (%(Dog))
REM 28 Jan 2055 INFO "Url: https://en.wikipedia.org/wiki/Pig_(zodiac)" MSG %(Chinese New Year) (%(Pig))
REM 15 Feb 2056 INFO "Url: https://en.wikipedia.org/wiki/Rat_(zodiac)" MSG %(Chinese New Year) (%(Rat))
REM 4 Feb 2057 INFO "Url: https://en.wikipedia.org/wiki/Ox_(zodiac)" MSG %(Chinese New Year) (%(Ox))
REM 24 Jan 2058 INFO "Url: https://en.wikipedia.org/wiki/Tiger_(zodiac)" MSG %(Chinese New Year) (%(Tiger))
REM 12 Feb 2059 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %(Chinese New Year) (%(Rabbit))
REM 2 Feb 2060 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %(Chinese New Year) (%(Dragon))
REM 21 Jan 2061 INFO "Url: https://en.wikipedia.org/wiki/Snake_(zodiac)" MSG %(Chinese New Year) (%(Snake))
REM 9 Feb 2062 INFO "Url: https://en.wikipedia.org/wiki/Horse_(zodiac)" MSG %(Chinese New Year) (%(Horse))
REM 29 Jan 2063 INFO "Url: https://en.wikipedia.org/wiki/Goat_(zodiac)" MSG %(Chinese New Year) (%(Goat))
REM 17 Feb 2064 INFO "Url: https://en.wikipedia.org/wiki/Monkey_(zodiac)" MSG %(Chinese New Year) (%(Monkey))
REM 5 Feb 2065 INFO "Url: https://en.wikipedia.org/wiki/Rooster_(zodiac)" MSG %(Chinese New Year) (%(Rooster))
REM 26 Jan 2066 INFO "Url: https://en.wikipedia.org/wiki/Dog_(zodiac)" MSG %(Chinese New Year) (%(Dog))
REM 14 Feb 2067 INFO "Url: https://en.wikipedia.org/wiki/Pig_(zodiac)" MSG %(Chinese New Year) (%(Pig))
REM 3 Feb 2068 INFO "Url: https://en.wikipedia.org/wiki/Rat_(zodiac)" MSG %(Chinese New Year) (%(Rat))
REM 23 Jan 2069 INFO "Url: https://en.wikipedia.org/wiki/Ox_(zodiac)" MSG %(Chinese New Year) (%(Ox))
REM 11 Feb 2070 INFO "Url: https://en.wikipedia.org/wiki/Tiger_(zodiac)" MSG %(Chinese New Year) (%(Tiger))
REM 31 Jan 2071 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %(Chinese New Year) (%(Rabbit))
REM 19 Feb 2072 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %(Chinese New Year) (%(Dragon))
REM 7 Feb 2073 INFO "Url: https://en.wikipedia.org/wiki/Snake_(zodiac)" MSG %(Chinese New Year) (%(Snake))
REM 27 Jan 2074 INFO "Url: https://en.wikipedia.org/wiki/Horse_(zodiac)" MSG %(Chinese New Year) (%(Horse))
REM 15 Feb 2075 INFO "Url: https://en.wikipedia.org/wiki/Goat_(zodiac)" MSG %(Chinese New Year) (%(Goat))
REM 5 Feb 2076 INFO "Url: https://en.wikipedia.org/wiki/Monkey_(zodiac)" MSG %(Chinese New Year) (%(Monkey))
REM 24 Jan 2077 INFO "Url: https://en.wikipedia.org/wiki/Rooster_(zodiac)" MSG %(Chinese New Year) (%(Rooster))
REM 12 Feb 2078 INFO "Url: https://en.wikipedia.org/wiki/Dog_(zodiac)" MSG %(Chinese New Year) (%(Dog))
REM 2 Feb 2079 INFO "Url: https://en.wikipedia.org/wiki/Pig_(zodiac)" MSG %(Chinese New Year) (%(Pig))
REM 22 Jan 2080 INFO "Url: https://en.wikipedia.org/wiki/Rat_(zodiac)" MSG %(Chinese New Year) (%(Rat))
REM 9 Feb 2081 INFO "Url: https://en.wikipedia.org/wiki/Ox_(zodiac)" MSG %(Chinese New Year) (%(Ox))
REM 29 Jan 2082 INFO "Url: https://en.wikipedia.org/wiki/Tiger_(zodiac)" MSG %(Chinese New Year) (%(Tiger))
REM 17 Feb 2083 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %(Chinese New Year) (%(Rabbit))
REM 6 Feb 2084 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %(Chinese New Year) (%(Dragon))
REM 26 Jan 2085 INFO "Url: https://en.wikipedia.org/wiki/Snake_(zodiac)" MSG %(Chinese New Year) (%(Snake))
REM 14 Feb 2086 INFO "Url: https://en.wikipedia.org/wiki/Horse_(zodiac)" MSG %(Chinese New Year) (%(Horse))
REM 3 Feb 2087 INFO "Url: https://en.wikipedia.org/wiki/Goat_(zodiac)" MSG %(Chinese New Year) (%(Goat))
REM 24 Jan 2088 INFO "Url: https://en.wikipedia.org/wiki/Monkey_(zodiac)" MSG %(Chinese New Year) (%(Monkey))
REM 10 Feb 2089 INFO "Url: https://en.wikipedia.org/wiki/Rooster_(zodiac)" MSG %(Chinese New Year) (%(Rooster))
REM 30 Jan 2090 INFO "Url: https://en.wikipedia.org/wiki/Dog_(zodiac)" MSG %(Chinese New Year) (%(Dog))
REM 18 Feb 2091 INFO "Url: https://en.wikipedia.org/wiki/Pig_(zodiac)" MSG %(Chinese New Year) (%(Pig))
REM 7 Feb 2092 INFO "Url: https://en.wikipedia.org/wiki/Rat_(zodiac)" MSG %(Chinese New Year) (%(Rat))
REM 27 Jan 2093 INFO "Url: https://en.wikipedia.org/wiki/Ox_(zodiac)" MSG %(Chinese New Year) (%(Ox))
REM 15 Feb 2094 INFO "Url: https://en.wikipedia.org/wiki/Tiger_(zodiac)" MSG %(Chinese New Year) (%(Tiger))
REM 5 Feb 2095 INFO "Url: https://en.wikipedia.org/wiki/Rabbit_(zodiac)" MSG %(Chinese New Year) (%(Rabbit))
REM 25 Jan 2096 INFO "Url: https://en.wikipedia.org/wiki/Dragon_(zodiac)" MSG %(Chinese New Year) (%(Dragon))
REM 12 Feb 2097 INFO "Url: https://en.wikipedia.org/wiki/Snake_(zodiac)" MSG %(Chinese New Year) (%(Snake))
REM 1 Feb 2098 INFO "Url: https://en.wikipedia.org/wiki/Horse_(zodiac)" MSG %(Chinese New Year) (%(Horse))
REM 21 Jan 2099 INFO "Url: https://en.wikipedia.org/wiki/Goat_(zodiac)" MSG %(Chinese New Year) (%(Goat))
REM 9 Feb 2100 INFO "Url: https://en.wikipedia.org/wiki/Monkey_(zodiac)" MSG %(Chinese New Year) (%(Monkey))

View File

@@ -14,9 +14,6 @@ FSET _h2(x, y) HEBDATE(x, y, $U-7)
FSET _PastSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)+1)
FSET _BackTwoFri(x, y) IIF(WKDAYNUM(_h2(x,y))!=5, _h2(x,y), _h2(x,y)-2)
FSET _BackTwoSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)-2)
# Default values in case InIsrael and Reform are not set
SET InIsrael VALUE("InIsrael", 0)
SET Reform VALUE("Reform", 0)
REM [hebdate(1, "Tishrey")] INFO "Url: https://en.wikipedia.org/wiki/Rosh_Hashanah" MSG Rosh Hashana 1

View File

@@ -0,0 +1,5 @@
# Add HTML anchors to each day box.
# This adds anchors: <a id="YYYY-MM-DD" name="YYYY-MM-DD"></a>
# to each calendar box in an HTML calendar.
REM SPECIAL HTML <a id="[$T]" name="[$T]"></a>

View File

@@ -3431,9 +3431,11 @@ in unwanted reminders being purged in Purge Mode. See also the section
Returns the current date and time as a DATETIME object. This may be the
actual date and time, or may be the date and time supplied on the command line.
.TP
.B date(i_y, i_m, i_d)
.B date(i_y, si_m, i_d)
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.
The month can be specified as an integer from 1 to 12, or a string
that is the name of a month.
.TP
.B datepart(dq_datetime)
Returns a \fBDATE\fR object representing the date portion of
@@ -3450,11 +3452,13 @@ If you supply three arguments, the first
must be a DATE and the second and third must be INTs. The second and
third arguments are interpreted as hours and minutes and converted to a TIME.
.PP
If you supply four arguments, the first three must be INTs, interpreted
as the year, month and day. The fourth argument must be a TIME.
If you supply four arguments, they are interpreted as year, month, day
and time. Year and day must be INTs. Month may be an INT from 0 to 12
or a string naming a month. Time must be a TIME.
.PP
Finally, if you supply five arguments, they must all be INTs and are
interpreted as year, month, day, hour and minute.
interpreted as year, month, day, hour and minute. (Actually, month
can also be a string that is the name of a month.)
.RE
.TP
.B dawn([dq_date])
@@ -3467,8 +3471,12 @@ This function takes a \fBDATE\fR or \fBDATETIME\fR as an argument, and
returns an \fBINT\fR that is the day-of-month component of
\fIdate\fR.
.TP
.B daysinmon(i_m, i_y)
Returns the number of days in month \fIm\fR (1-12) of the year \fIy\fR.
.B daysinmon(si_m, i_y)\fR or \fB daysinmon(dq_date)\fR
Returns the number of days in month \fIm\fR (1-12) of the year
\fIy\fR. The first argument can either be an integer from 1 to 12, or
a string that is the name of a month. If given a single DATE or
DATETIME argument, returns the number of days in the month containing
the argument.
.TP
.B defined(s_var)
Returns 1 if the variable named by \fIvar\fR is defined, or 0 if it is not.
@@ -3774,10 +3782,20 @@ functions. It is available starting with version 03.00.07 of \fBRemind\fR.
.B minute(tq_time)
Returns the minute component of \fItime\fR.
.TP
.B mon(dqi_arg)
.B mon(dqis_arg)
If \fIarg\fR is of \fBDATE\fR or \fBDATETIME\fR type, returns a string
that names the month component of the date. If \fIarg\fR is an
\fBINT\fR from 1 to 12, returns a string that names the month.
\fBINT\fR from 1 to 12, returns a string that names the month. If \fIarg\fR
is a \fBSTRING\fR, returns the name of the month. This last case might
sound silly, but for example:
.RS
.PP
.nf
mon("Mar")
.fi
.PP
will return "March", the full name of the month.
.RE
.TP
.B monnum(dq_date)\fR or \fBmonnum(s_str)\fR
Returns an \fBINT\fR from 1 to 12, representing the month component of
@@ -4595,7 +4613,9 @@ an error results.
.PP
However, if you supply a second argument, it is returned if the \fIvarname\fR
is not defined. The expression value("XY", 0) will return 0 if XY is not
defined, and the value of XY if it is defined.
defined, and the value of XY if it is defined. Note that \fBvalue\fR
evaluates the second argument lazily; it is \fInot\fR evaluated if
\fIvarname\fR is defined.
.RE
.TP
.B version()
@@ -5074,7 +5094,18 @@ function, the command fails with an error message and does nothing.
If you define a user-defined function and then later on redefine it,
\fBRemind\fR will issue a warning. If you do not want this warning,
then use \fBFUNSET\fR to remove the existing definition before you
redefine the function.
redefine the function. Alternatively, you can use a "-" token before
the function name to suppress "redefined function" warnings, as in the
following example:
.PP
.nf
FSET - f(x) 2*x
# You must have space before and after the "-"
# This will NOT work:
# FSET -f(x) 2*x
.fi
.PP
to define a function and suppress any "redefined function" warning.
.PP
.SH PRECISE SCHEDULING
.PP
@@ -6760,12 +6791,13 @@ date of the scanning\fR that
satisfies the trigger. In addition, there is one special case in which
\fBtrigvalid()\fR returns 1 and \fBtrigdate()\fR returns a meaningful result:
.PP
If the \fBREM\fR or \fBIFTRIG\fR command did not contain an \fBUNTIL\fR
clause, and contained all of the \fIday\fR, \fImonth\fR and \fIyear\fR
components, then \fBRemind\fR will correctly compute a trigger date, even
if it happens to be before the start of scanning.
Note that this behaviour is not true for
If the \fBREM\fR or \fBIFTRIG\fR command did not contain an
\fBUNTIL\fR or \fBSATISFY\fR clause, and contained all of the
\fIday\fR, \fImonth\fR and \fIyear\fR components, then \fBRemind\fR
will correctly compute a trigger date, even if it happens to be before
the start of scanning. Note that this behaviour is not true for
versions of \fBRemind\fR prior to 03.00.01.
.SH FILES
.PP
The traditional location of your reminders file or directory is:

View File

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

View File

@@ -265,6 +265,7 @@ while(1) {
}
my ($obj, $err) = Remind::PDF->create_from_stream(*STDIN,
{color => 1,
colour => 1,
shade => 1,
moon => 1,
pango => 1,

View File

@@ -757,7 +757,7 @@ InitMoonsAndShades(void)
static void
SetShadeEntry(int dse, char const *shade)
{
int y, m, d;
int d;
int r, g, b;
/* Don't bother if we're not doing SHADE specials */
if (!UseBGVTColors) {
@@ -774,7 +774,7 @@ SetShadeEntry(int dse, char const *shade)
if (r < 0 || g < 0 || b < 0 || r > 255 || g > 255 || b > 255) {
return;
}
FromDSE(dse, &y, &m, &d);
FromDSE(dse, NULL, NULL, &d);
bgcolor[d][0] = r;
bgcolor[d][1] = g;
bgcolor[d][2] = b;
@@ -784,7 +784,7 @@ static void
SetMoonEntry(int dse, char const *moon)
{
int phase;
int y, m, d;
int d;
char msg[28];
/* Don't bother unless it's utf-8 */
@@ -803,7 +803,7 @@ SetMoonEntry(int dse, char const *moon)
/* Bad phase */
return;
}
FromDSE(dse, &y, &m, &d);
FromDSE(dse, NULL, NULL, &d);
if (msg[0]) {
snprintf(moons[d], sizeof(moons[d]), "%s %s", moonphase_emojis[phase], msg);
} else {
@@ -1476,13 +1476,13 @@ static void PrintCentered(char const *s, int width, char *pad)
static int WriteOneCalLine(int start_dse, int wd)
{
int done = 1, i;
int y, m, d;
int d;
gon();
DRAW(tb);
goff();
for (i=0; i<7; i++) {
FromDSE(start_dse+i, &y, &m, &d);
FromDSE(start_dse+i, NULL, NULL, &d);
d -= wd;
if (CalColumn[i]) {
Backgroundize(ColToDay[i]);

View File

@@ -1554,6 +1554,8 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
}
if (dse == -1) {
free_expr_tree(sat_node);
LastTrigValid = 0;
LastTriggerDate = -1;
return E_EXPIRED;
}
r = evaluate_expression(sat_node, NULL, &v, &nonconst);

View File

@@ -23,11 +23,11 @@
#define E_MISS_END 1
#define E_MISS_QUOTE 2
#define E_OP_STK_OVER 3
/* #define E_VA_STK_OVER 4 */
#define E_CANT_PARSE_MONTH 4
#define E_MISS_RIGHT_PAREN 5
#define E_UNDEF_FUNC 6
#define E_ILLEGAL_CHAR 7
/* #define E_EXPECTING_BINOP 8 */
#define E_CANT_PARSE_WKDAY 8
#define E_NO_MEM 9
#define E_BAD_NUMBER 10
/* #define E_OP_STK_UNDER 11 */
@@ -151,11 +151,11 @@ EXTERN char *ErrMsg[]
/* E_MISS_END */ "Missing ']'",
/* E_MISS_QUOTE */ "Missing quote",
/* E_OP_STK_OVER */ "Expression too complex",
/* E_VA_STK_OVER */ "",
/* E_CANT_PARSE_MONTH */ "Invalid month name",
/* E_MISS_RIGHT_PAREN */ "Missing ')'",
/* E_UNDEF_FUNC */ "Undefined function",
/* E_ILLEGAL_CHAR */ "Illegal character",
/* E_EXPECTING_BINOP */ "Expecting binary operator",
/* E_CANT_PARSE_WKDAY*/ "Invalid weekday name",
/* E_NO_MEM */ "Out of memory",
/* E_BAD_NUMBER */ "Ill-formed number",
/* E_OP_STK_UNDER */ "",

View File

@@ -59,7 +59,9 @@
#define Nargs (info->nargs)
#define RetVal (info->retval)
#define DBG(x) do { if (DebugFlag & DB_PRTEXPR) { x; } } while(0)
#define DBGX (DebugFlag & DB_PRTEXPR)
#define DBG(x) do { if (DBGX) { x; } } while(0)
/* Debugging helpers for "choose()", "iif(), etc. */
#define PUT(x) DBufPuts(&DebugBuf, x)
#define OUT() do { fprintf(ErrFp, "%s\n", DBufValue(&DebugBuf)); DBufFree(&DebugBuf); } while(0)
@@ -193,7 +195,7 @@ static int FTypeof (func_info *);
static int FTzconvert (func_info *);
static int FUTCToLocal (func_info *);
static int FUpper (func_info *);
static int FValue (func_info *);
static int FValue (expr_node *, Value *, Value *, int *);
static int FVersion (func_info *);
static int FWeekno (func_info *);
static int FWkday (func_info *);
@@ -229,6 +231,8 @@ static int CacheHebYear, CacheHebMon, CacheHebDay;
#define HASDATE(x) ((x).type & DATE_TYPE)
#define HASTIME(x) ((x).type & TIME_TYPE)
#define GETMON(x) get_month(&(ARG(x)))
/* Macro for copying a value while destroying original copy */
#define DCOPYVAL(x, y) ( (x) = (y), (y).type = ERR_TYPE )
@@ -265,7 +269,7 @@ BuiltinFunc Func[] = {
{ "datetime", 2, 5, 1, FDateTime, NULL },
{ "dawn", 0, 1, 0, FDawn, NULL },
{ "day", 1, 1, 1, FDay, NULL },
{ "daysinmon", 2, 2, 1, FDaysinmon, NULL },
{ "daysinmon", 1, 2, 1, FDaysinmon, NULL },
{ "defined", 1, 1, 0, FDefined, NULL },
{ "dosubst", 1, 3, 0, FDosubst, NULL },
{ "dusk", 0, 1, 0, FDusk, NULL },
@@ -365,7 +369,7 @@ BuiltinFunc Func[] = {
{ "tzconvert", 2, 3, 0, FTzconvert, NULL },
{ "upper", 1, 1, 1, FUpper, NULL },
{ "utctolocal", 1, 1, 1, FUTCToLocal, NULL },
{ "value", 1, 2, 0, FValue, NULL },
{ "value", 1, 2, 1, NULL, FValue }, /* NEW-STYLE */
{ "version", 0, 0, 1, FVersion, NULL },
{ "weekno", 0, 3, 0, FWeekno, NULL },
{ "wkday", 1, 1, 1, FWkday, NULL },
@@ -376,6 +380,26 @@ BuiltinFunc Func[] = {
/* Need a variable here - Func[] array not really visible to outside. */
int NumFuncs = sizeof(Func) / sizeof(BuiltinFunc) ;
static int get_month(Value *v)
{
Token tok;
if (v->type == INT_TYPE) {
if (v->v.val < 1) return -E_2LOW;
if (v->v.val > 12) return -E_2HIGH;
return v->v.val - 1;
}
if (v->type == STR_TYPE) {
FindToken(v->v.str, &tok);
if (tok.type != T_Month) {
return -E_CANT_PARSE_MONTH;
}
return tok.val;
}
return -E_BAD_TYPE;
}
/***************************************************************/
/* */
/* RetStrVal */
@@ -461,29 +485,27 @@ static int FBaseyr(func_info *info)
static int FDate(func_info *info)
{
int y, m, d;
int ytemp, mtemp, dtemp;
/* Any arg can be a date (in which case we use the corresponding
component) or an integer */
if (HASDATE(ARG(0))) {
FromDSE(DATEPART(ARG(0)), &ytemp, &mtemp, &dtemp);
y = ytemp;
FromDSE(DATEPART(ARG(0)), &y, NULL, NULL);
} else {
ASSERT_TYPE(0, INT_TYPE);
y = ARGV(0);
}
if (HASDATE(ARG(1))) {
FromDSE(DATEPART(ARG(1)), &ytemp, &mtemp, &dtemp);
m = mtemp;
FromDSE(DATEPART(ARG(1)), NULL, &m, NULL);
} else {
ASSERT_TYPE(1, INT_TYPE);
m = ARGV(1) - 1;
m = GETMON(1);
if (m < 0) {
return -m;
}
}
if (HASDATE(ARG(2))) {
FromDSE(DATEPART(ARG(2)), &ytemp, &mtemp, &dtemp);
d = dtemp;
FromDSE(DATEPART(ARG(2)), NULL, NULL, &d);
} else {
ASSERT_TYPE(2, INT_TYPE);
d = ARGV(2);
@@ -528,11 +550,11 @@ static int FDateTime(func_info *info)
return OK;
case 4:
if (ARG(0).type != INT_TYPE ||
ARG(1).type != INT_TYPE ||
ARG(2).type != INT_TYPE ||
ARG(3).type != TIME_TYPE) return E_BAD_TYPE;
y = ARGV(0);
m = ARGV(1) - 1;
m = GETMON(1);
if (m < 0) return -m;
d = ARGV(2);
if (!DateOK(y, m, d)) return E_BAD_DATE;
@@ -540,13 +562,13 @@ static int FDateTime(func_info *info)
return OK;
case 5:
if (ARG(0).type != INT_TYPE ||
ARG(1).type != INT_TYPE ||
ARG(2).type != INT_TYPE ||
ARG(3).type != INT_TYPE ||
ARG(4).type != INT_TYPE) return E_BAD_TYPE;
y = ARGV(0);
m = ARGV(1) - 1;
m = GETMON(1);
if (m < 0) return -m;
d = ARGV(2);
if (!DateOK(y, m, d)) return E_BAD_DATE;
@@ -757,7 +779,7 @@ static int FMonnum(func_info *info)
/* Convert a month name to a month number */
FindToken(ARG(0).v.str, &tok);
if (tok.type != T_Month) {
return E_BAD_TYPE;
return E_CANT_PARSE_MONTH;
}
RetVal.type = INT_TYPE;
RETVAL = tok.val + 1;
@@ -809,7 +831,7 @@ static int FWkdaynum(func_info *info)
/* Convert a day name to a day number */
FindToken(ARG(0).v.str, &tok);
if (tok.type != T_WkDay) {
return E_BAD_TYPE;
return E_CANT_PARSE_WKDAY;
}
RetVal.type = INT_TYPE;
RETVAL = (tok.val + 1) % 7;
@@ -846,12 +868,11 @@ static int FMon(func_info *info)
char const *s;
int y, m, d, v;
if (!HASDATE(ARG(0)) && ARG(0).type != INT_TYPE) return E_BAD_TYPE;
if (!HASDATE(ARG(0)) && ARG(0).type != INT_TYPE && ARG(0).type != STR_TYPE) return E_BAD_TYPE;
if (ARG(0).type == INT_TYPE) {
m = ARGV(0) - 1;
if (m < 0) return E_2LOW;
if (m > 11) return E_2HIGH;
if (ARG(0).type == INT_TYPE || ARG(0).type == STR_TYPE) {
m = GETMON(0);
if (m < 0) return -m;
} else {
v = DATEPART(ARG(0));
if (v == CacheDse)
@@ -1299,7 +1320,7 @@ static int FIsconst(expr_node *node, Value *locals, Value *ans, int *nonconst)
ans->type = INT_TYPE;
ans->v.val = (my_nonconst ? 0 : 1);
DBG(PUT(PrintValue(&junk, NULL)));
if (DebugFlag & DB_PRTEXPR) {
if (DBGX) {
PUT(") => ");
PUT(PrintValue(ans, NULL));
OUT();
@@ -1366,7 +1387,7 @@ static int FIsAny(expr_node *node, Value *locals, Value *ans, int *nonconst)
break;
}
DestroyValue(v);
if (DebugFlag & DB_PRTEXPR) {
if (DBGX) {
while(cur->sibling) {
cur = cur->sibling;
PUT(", ?");
@@ -1403,7 +1424,7 @@ static int FCatch(expr_node *node, Value *locals, Value *ans, int *nonconst)
SuppressErrorOutputInCatch = old_suppress;
if (r == OK) {
if (DebugFlag & DB_PRTEXPR) {
if (DBGX) {
PUT(PrintValue(ans, NULL));
PUT(", ?) => ");
PUT(PrintValue(ans, NULL));
@@ -1414,14 +1435,14 @@ static int FCatch(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* Save the catch error */
LastCatchError = r;
if (DebugFlag & DB_PRTEXPR) {
if (DBGX) {
PUT("*");
PUT(GetErr(r));
PUT("*, ");
}
r = evaluate_expr_node(cur->sibling, locals, ans, nonconst);
if (r == OK) {
if (DebugFlag & DB_PRTEXPR) {
if (DBGX) {
PUT(PrintValue(ans, NULL));
PUT(") => ");
PUT(PrintValue(ans, NULL));
@@ -1429,7 +1450,7 @@ static int FCatch(expr_node *node, Value *locals, Value *ans, int *nonconst)
}
return r;
}
if (DebugFlag & DB_PRTEXPR) {
if (DBGX) {
PUT("*");
PUT(GetErr(r));
PUT("*) => ");
@@ -1478,7 +1499,7 @@ static int FChoose(expr_node *node, Value *locals, Value *ans, int *nonconst)
}
DBG(PUT(PrintValue(&v, NULL)));
if (v.type != INT_TYPE) {
if (DebugFlag & DB_PRTEXPR) {
if (DBGX) {
cur = cur->sibling;
while(cur) {
PUT(", ?");
@@ -1488,6 +1509,7 @@ static int FChoose(expr_node *node, Value *locals, Value *ans, int *nonconst)
PUT(GetErr(E_BAD_TYPE));
OUT();
}
DestroyValue(v);
Eprint("choose(): %s", GetErr(E_BAD_TYPE));
return E_BAD_TYPE;
}
@@ -1505,7 +1527,7 @@ static int FChoose(expr_node *node, Value *locals, Value *ans, int *nonconst)
DBG(DBufFree(&DebugBuf));
return r;
}
if (DebugFlag & DB_PRTEXPR) {
if (DBGX) {
PUT(", ");
PUT(PrintValue(ans, NULL));
cur = cur->sibling;
@@ -1695,26 +1717,92 @@ static int FGetenv(func_info *info)
/* it is returned if variable is undefined. */
/* */
/***************************************************************/
static int FValue(func_info *info)
static int FValue(expr_node *node, Value *locals, Value *ans, int *nonconst)
{
DynamicBuffer DebugBuf;
expr_node *cur;
int r;
Value varname;
Var *v;
ASSERT_TYPE(0, STR_TYPE);
switch(Nargs) {
case 1:
return GetVarValue(ARGSTR(0), &RetVal);
DBG(DBufInit(&DebugBuf));
case 2:
v = FindVar(ARGSTR(0), 0);
if (!v) {
DCOPYVAL(RetVal, ARG(1));
return OK;
} else {
v->used_since_set = 1;
return CopyValue(&RetVal, &v->v);
cur = node->child;
r = evaluate_expr_node(cur, locals, &varname, nonconst);
if (r != OK) {
DBG(DBufFree(&DebugBuf));
return r;
}
DBG(PUT("value("));
DBG(PUT(PrintValue(&varname, NULL)));
if (node->num_kids == 1) {
DBG(PUT(") => "));
} else {
DBG(PUT(", "));
}
if (varname.type != STR_TYPE) {
if (DBGX) {
if (node->num_kids == 2) {
PUT("?) => ");
}
PUT(GetErr(E_BAD_TYPE));
OUT();
}
DestroyValue(varname);
return E_BAD_TYPE;
}
v = FindVar(varname.v.str, 0);
if (!v) {
r = E_NOSUCH_VAR;
} else {
r = OK;
v->used_since_set = 1;
CopyValue(ans, &v->v);
if (!v->is_constant) {
nonconst_debug(*nonconst, tr("Global variable `%s' makes expression non-constant"), varname.v.str);
*nonconst = 1;
}
}
return OK;
if (r == OK || node->num_kids == 1) {
DestroyValue(varname);
if (DBGX) {
if (node->num_kids == 2) {
PUT("?) => ");
}
if (r != OK) {
PUT(GetErr(r));
} else {
PUT(PrintValue(ans, NULL));
}
OUT();
}
return r;
}
/* Variable does not exist. We have to mark the result of value()
as non-constant because the nonexistence of a variable may depend
on today's date (for example) */
nonconst_debug(*nonconst, tr("Nonexistence of global variable `%s' makes value() non-constant"), varname.v.str);
DestroyValue(varname);
*nonconst = 1;
r = evaluate_expr_node(cur->sibling, locals, ans, nonconst);
if (DBGX) {
if (node->num_kids == 2) {
if (r != OK) {
PUT(GetErr(r));
PUT(") => ");
PUT(GetErr(r));
} else {
PUT(PrintValue(ans, NULL));
PUT(") => ");
PUT(PrintValue(ans, NULL));
}
OUT();
}
}
return r;
}
/***************************************************************/
@@ -1939,19 +2027,29 @@ static int FTrigdatetime(func_info *info)
/* */
/* FDaysinmon */
/* */
/* Returns the number of days in mon,yr */
/* Returns the number of days in mon,yr OR month containing */
/* given date. */
/* */
/***************************************************************/
static int FDaysinmon(func_info *info)
{
if (ARG(0).type != INT_TYPE || ARG(1).type != INT_TYPE) return E_BAD_TYPE;
int y, m;
if (ARGV(0) > 12 || ARGV(0) < 1 ||
ARGV(1) < BASE || ARGV(1) > BASE+YR_RANGE)
return E_DOMAIN_ERR;
if (Nargs == 1) {
if (!HASDATE(ARG(0))) return E_BAD_TYPE;
FromDSE(DATEPART(ARG(0)), &y, &m, NULL);
} else {
if (ARG(1).type != INT_TYPE) return E_BAD_TYPE;
m = GETMON(0);
if (m < 0) return -m;
y = ARGV(1);
if (y < BASE) return E_2LOW;
if (y > BASE + YR_RANGE) return E_2HIGH;
}
RetVal.type = INT_TYPE;
RETVAL = DaysInMonth(ARGV(0)-1, ARGV(1));
RETVAL = DaysInMonth(m, y);
return OK;
}
@@ -1964,13 +2062,13 @@ static int FDaysinmon(func_info *info)
/***************************************************************/
static int FIsleap(func_info *info)
{
int y, m, d;
int y;
if (ARG(0).type != INT_TYPE && !HASDATE(ARG(0))) return E_BAD_TYPE;
/* If it's a date, extract the year */
if (HASDATE(ARG(0)))
FromDSE(DATEPART(ARG(0)), &y, &m, &d);
FromDSE(DATEPART(ARG(0)), &y, NULL, NULL);
else
y = ARGV(0);
@@ -2216,7 +2314,7 @@ static int FIif(expr_node *node, Value *locals, Value *ans, int *nonconst)
cur = node->child;
if (!(node->num_kids % 2)) {
if (DebugFlag & DB_PRTEXPR) {
if (DBGX) {
r = 0;
while(cur) {
if (r) PUT(", ");
@@ -2239,7 +2337,7 @@ static int FIif(expr_node *node, Value *locals, Value *ans, int *nonconst)
DBG(DBufFree(&DebugBuf));
return r;
}
if (DebugFlag & DB_PRTEXPR) {
if (DBGX) {
if (done) PUT(", ");
done = 1;
PUT(PrintValue(&v, NULL));
@@ -2247,7 +2345,7 @@ static int FIif(expr_node *node, Value *locals, Value *ans, int *nonconst)
if (truthy(&v)) {
r = evaluate_expr_node(cur->sibling, locals, ans, nonconst);
if (r == OK && (DebugFlag & DB_PRTEXPR)) {
if (r == OK && DBGX) {
PUT(", ");
PUT(PrintValue(ans, NULL));
cur = cur->sibling->sibling;
@@ -2268,7 +2366,7 @@ static int FIif(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* Return the last arg */
r = evaluate_expr_node(cur, locals, ans, nonconst);
if (DebugFlag & DB_PRTEXPR) {
if (DBGX) {
if (done) PUT(", ");
PUT(PrintValue(ans, NULL));
PUT(") => ");
@@ -2756,7 +2854,7 @@ static int FEasterdate(func_info *info)
int base;
if (Nargs == 0) {
base = DSEToday;
FromDSE(DSEToday, &y, &m, &d);
FromDSE(DSEToday, &y, NULL, NULL);
} else {
if (ARG(0).type == INT_TYPE) {
base = -1;
@@ -2765,7 +2863,7 @@ static int FEasterdate(func_info *info)
else if (y > BASE+YR_RANGE) return E_2HIGH;
} else if (HASDATE(ARG(0))) {
base = DATEPART(ARG(0));
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
FromDSE(DATEPART(ARG(0)), &y, NULL, NULL); /* We just want the year */
} else return E_BAD_TYPE;
}
@@ -2809,7 +2907,7 @@ static int FOrthodoxeaster(func_info *info)
int base = -1;
if (Nargs == 0) {
base = DSEToday;
FromDSE(DSEToday, &y, &m, &d);
FromDSE(DSEToday, &y, NULL, NULL);
} else {
if (ARG(0).type == INT_TYPE) {
y = ARGV(0);
@@ -2817,7 +2915,7 @@ static int FOrthodoxeaster(func_info *info)
else if (y > BASE+YR_RANGE) return E_2HIGH;
} else if (HASDATE(ARG(0))) {
base = DATEPART(ARG(0));
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
FromDSE(DATEPART(ARG(0)), &y, NULL, NULL); /* We just want the year */
} else return E_BAD_TYPE;
}
@@ -3845,7 +3943,7 @@ FSlide(func_info *info)
for (i=localargs; i<Nargs; i++) {
if (ARG(i).type != STR_TYPE) return E_BAD_TYPE;
FindToken(ARG(i).v.str, &tok);
if (tok.type != T_WkDay) return E_UNKNOWN_TOKEN;
if (tok.type != T_WkDay) return E_CANT_PARSE_WKDAY;
localomit |= (1 << tok.val);
}
@@ -3903,7 +4001,7 @@ FNonomitted(func_info *info)
for (i=localargs; i<Nargs; i++) {
if (ARG(i).type != STR_TYPE) return E_BAD_TYPE;
FindToken(ARG(i).v.str, &tok);
if (tok.type != T_WkDay) return E_UNKNOWN_TOKEN;
if (tok.type != T_WkDay) return E_CANT_PARSE_WKDAY;
localomit |= (1 << tok.val);
}

View File

@@ -1,6 +1,6 @@
/***************************************************************/
/* */
/* HASHTAB_STATS.C */
/* HASHTAB.C */
/* */
/* Implementation of hash table. */
/* */

View File

@@ -459,6 +459,15 @@ void FromDSE(int dse, int *y, int *m, int *d)
try_yr--;
try_dse -= DaysInYear(try_yr);
}
if (y) {
*y = try_yr;
}
/* If all we want is the year, we can quit here */
if (!d && !m) {
return;
}
dse -= try_dse;
t = DaysInMonth(try_mon, try_yr);
@@ -467,9 +476,6 @@ void FromDSE(int dse, int *y, int *m, int *d)
try_mon++;
t = DaysInMonth(try_mon, try_yr);
}
if (y) {
*y = try_yr;
}
if (m) {
*m = try_mon;
}
@@ -935,6 +941,10 @@ void Eprint(char const *fmt, ...)
return;
}
if (should_ignore_line()) {
return;
}
char const *fname = GetCurrentFilename();
if (!fname) {
return;
@@ -1990,9 +2000,11 @@ SaveAllTriggerInfo(Trigger const *t, TimeTrig const *tt, int trigdate, int trigt
{
SaveLastTrigger(t);
SaveLastTimeTrig(tt);
LastTriggerDate = trigdate;
if (trigdate != -1) {
LastTriggerDate = trigdate;
LastTrigValid = valid;
}
LastTriggerTime = trigtime;
LastTrigValid = valid;
}
void

View File

@@ -242,7 +242,7 @@ int IsOmitted(int dse, int localomit, char const *omitfunc, int *omit)
return OK;
}
FromDSE(dse, &y, &m, &d);
FromDSE(dse, NULL, &m, &d);
if (BexistsIntArray(PartialOmitArray, NumPartialOmits, (m << 5) + d)) {
*omit = 1;
return OK;

View File

@@ -12,12 +12,6 @@
#include "config.h"
/* Solaris needs this to get select() prototype */
#ifdef __sun__
#define __EXTENSIONS__ 1
#endif
/* We only want object code generated if we have queued reminders */
#include <stdio.h>
#include <string.h>
#include <signal.h>

View File

@@ -27,11 +27,11 @@
executes 'return' if an initial non-numeric char is found. */
#define PARSENUM(var, string) \
if (!isdigit(*(string))) return; \
var = 0; \
(var) = 0; \
while (isdigit(*(string))) { \
var *= 10; \
var += *(string) - '0'; \
string++; \
(var) *= 10; \
(var) += *(string) - '0'; \
(string)++; \
}
/* The big array holding all recognized (literal) tokens in reminder file.

View File

@@ -310,15 +310,15 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
{
int simple, mod, omit;
/* First: Have we passed the UNTIL date? */
/* First: Have we passed the UNTIL date? */
if (trig->until != NO_UNTIL &&
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 */
/* Next: If it's an "AFTER"-type skip, back up
until we're at the start of a block of holidays */
if (trig->skip == AFTER_SKIP) {
int iter = 0;
while (iter++ <= MaxSatIter) {
@@ -339,16 +339,16 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
}
}
/* Find the next simple trigger */
/* Find the next simple trigger */
simple = NextSimpleTrig(start, trig, err);
/* Problems? */
/* Problems? */
if (*err || (simple == -1)) return -1;
/* Suggested starting point for next attempt */
/* Suggested starting point for next attempt */
*nextstart = simple+1;
/* If there's a BACK, back up... */
/* If there's a BACK, back up... */
if (trig->back != NO_BACK) {
mod = trig->back;
if (mod < 0) {
@@ -376,7 +376,7 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
}
}
/* If there's a REP, calculate the next occurrence */
/* If there's a REP, calculate the next occurrence */
if (trig->rep != NO_REP) {
if (simple < start) {
mod = (start - simple) / trig->rep;
@@ -385,7 +385,7 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
}
}
/* If it's a "BEFORE"-type skip, back up */
/* If it's a "BEFORE"-type skip, back up */
if (trig->skip == BEFORE_SKIP) {
int iter = 0;
while(iter++ <= MaxSatIter) {
@@ -406,7 +406,7 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
}
}
/* If it's an "AFTER"-type skip, jump ahead */
/* If it's an "AFTER"-type skip, jump ahead */
if (trig->skip == AFTER_SKIP) {
int iter = 0;
while (iter++ <= MaxSatIter) {
@@ -423,7 +423,12 @@ static int GetNextTriggerDate(Trigger *trig, int start, int *err, int *nextstart
}
}
/* Return the date */
/* If we've passed the UNTIL, then it's expired */
if (trig->until != NO_UNTIL && simple > trig->until) {
return -1;
}
/* Return the date */
return simple;
}
@@ -536,6 +541,7 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
trig->expired = 0;
if (save_in_globals) {
LastTrigValid = 0;
LastTriggerDate = -1;
}
/* Assume everything works */
@@ -574,7 +580,6 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
while (nattempts++ < TRIG_ATTEMPTS) {
result = GetNextTriggerDate(trig, start, err, &nextstart);
/* If there's an error, die immediately */
if (*err) return -1;
if (result == -1) {
@@ -630,8 +635,9 @@ int ComputeTriggerNoAdjustDuration(int today, Trigger *trig, TimeTrig *tim,
trig->rep == NO_REP) {
trig->expired = 1;
if (DebugFlag & DB_PRTTRIG) {
fprintf(ErrFp, "%s(%s): %s\n",
GetCurrentFilename(), line_range(LineNoStart, LineNo), GetErr(E_EXPIRED));
FromDSE(result, &y, &m, &d);
fprintf(ErrFp, "%s(%s): %s: %04d-%02d-%02d\n",
GetCurrentFilename(), line_range(LineNoStart, LineNo), GetErr(E_EXPIRED), y, m+1, d);
}
if (save_in_globals) {
LastTriggerDate = result;

View File

@@ -181,12 +181,34 @@ int DoFset(ParsePtr p)
Var *locals = NULL;
Var local_array[MAX_FUNC_ARGS];
int orig_namelen;
int suppress_redefined_function_warning = 0;
int ch;
DynamicBuffer buf;
DBufInit(&buf);
ch = ParseNonSpaceChar(p, &r, 1);
if (r) {
return r;
}
if (ch == '-') {
r = ParseToken(p, &buf);
if (r) {
return r;
}
if (strcmp(DBufValue(&buf), "-")) {
DBufFree(&buf);
return E_PARSE_ERR;
}
suppress_redefined_function_warning = 1;
DBufFree(&buf);
}
/* Get the function name */
if ( (r=ParseIdentifier(p, &buf)) ) return r;
if ( (r=ParseIdentifier(p, &buf)) ) {
return r;
}
if (*DBufValue(&buf) == '$') {
DBufFree(&buf);
return E_BAD_ID;
@@ -222,8 +244,10 @@ int DoFset(ParsePtr p)
return OK;
}
/* Warn about redefinition */
Wprint(tr("Function `%s' redefined: previously defined at %s(%s)"),
existing->name, existing->filename, line_range(existing->lineno_start, existing->lineno));
if (!suppress_redefined_function_warning) {
Wprint(tr("Function `%s' redefined: previously defined at %s(%s)"),
existing->name, existing->filename, line_range(existing->lineno_start, existing->lineno));
}
}
/* Should be followed by '(' */

View File

@@ -285,7 +285,7 @@ static int trig_until_func(int do_set, Value *val)
static int trig_day_func(int do_set, Value *val)
{
int y, m, d;
int d;
UNUSED(do_set);
val->type = INT_TYPE;
if (!LastTrigValid) {
@@ -293,7 +293,7 @@ static int trig_day_func(int do_set, Value *val)
return OK;
}
FromDSE(LastTriggerDate, &y, &m, &d);
FromDSE(LastTriggerDate, NULL, NULL, &d);
val->v.val = d;
return OK;
}
@@ -312,7 +312,7 @@ static int timet_is_64_func(int do_set, Value *val)
static int trig_mon_func(int do_set, Value *val)
{
int y, m, d;
int m;
UNUSED(do_set);
val->type = INT_TYPE;
if (!LastTrigValid) {
@@ -320,14 +320,14 @@ static int trig_mon_func(int do_set, Value *val)
return OK;
}
FromDSE(LastTriggerDate, &y, &m, &d);
FromDSE(LastTriggerDate, NULL, &m, NULL);
val->v.val = m+1;
return OK;
}
static int trig_year_func(int do_set, Value *val)
{
int y, m, d;
int y;
UNUSED(do_set);
val->type = INT_TYPE;
if (!LastTrigValid) {
@@ -335,7 +335,7 @@ static int trig_year_func(int do_set, Value *val)
return OK;
}
FromDSE(LastTriggerDate, &y, &m, &d);
FromDSE(LastTriggerDate, &y, NULL, NULL);
val->v.val = y;
return OK;
}
@@ -362,30 +362,30 @@ static int today_date_func(int do_set, Value *val)
}
static int today_day_func(int do_set, Value *val)
{
int y, m, d;
int d;
UNUSED(do_set);
val->type = INT_TYPE;
FromDSE(DSEToday, &y, &m, &d);
FromDSE(DSEToday, NULL, NULL, &d);
val->v.val = d;
return OK;
}
static int today_mon_func(int do_set, Value *val)
{
int y, m, d;
int m;
UNUSED(do_set);
val->type = INT_TYPE;
FromDSE(DSEToday, &y, &m, &d);
FromDSE(DSEToday, NULL, &m, NULL);
val->v.val = m+1;
return OK;
}
static int today_year_func(int do_set, Value *val)
{
int y, m, d;
int y;
UNUSED(do_set);
val->type = INT_TYPE;
FromDSE(DSEToday, &y, &m, &d);
FromDSE(DSEToday, &y, NULL, NULL);
val->v.val = y;
return OK;
}
@@ -560,6 +560,7 @@ Var *FindVar(char const *str, int create)
v->v.type = INT_TYPE;
v->v.v.val = 0;
v->preserve = 0;
v->is_constant = 1;
v->filename = "";
v->lineno = 0;
StrnCpy(v->name, str, VAR_NAME_LEN);
@@ -660,7 +661,13 @@ int DoSet (Parser *p)
Var *var;
r = ParseIdentifier(p, &buf);
if (r) return r;
if (r) {
DBufFree(&buf);
if (ignoring) {
return OK;
}
return r;
}
if (ignoring) {
/* We're only here to mark a variable as non-const */
@@ -907,7 +914,6 @@ int PreserveVar(char const *name)
v = FindVar(name, 1);
if (!v) return E_NO_MEM;
v->preserve = 1;
/* Assume we're gonna use the variable */
v->used_since_set = 1;
return OK;
@@ -925,11 +931,10 @@ int DoPreserve (Parser *p)
DynamicBuffer buf;
DBufInit(&buf);
r = ParseToken(p, &buf);
if (r) return r;
if (!DBufLen(&buf)) {
r = ParseIdentifier(p, &buf);
if (r) {
DBufFree(&buf);
return E_EOLN;
return r;
}
r = PreserveVar(DBufValue(&buf));
@@ -938,12 +943,14 @@ int DoPreserve (Parser *p)
/* Keep going... */
while(1) {
r = ParseToken(p, &buf);
if (r) return r;
if (!DBufLen(&buf)) {
r = ParseIdentifier(p, &buf);
if (r == E_EOLN) {
DBufFree(&buf);
return OK;
}
if (r) {
return r;
}
r = PreserveVar(DBufValue(&buf));
DBufFree(&buf);
if (r) return r;

View File

@@ -65,8 +65,8 @@ FSET not_const(x) x+nonconst(a)
REM [const(5)] Jan 1992 MSG expired... should be commented out
REM [const(a)] Jan 1992 MSG expired... should be commented out
REM [not_const(5)] Jan 1992 MSG nonconstant expression
REM [value("a")] Jan 1992 MSG nonconstant expression
REM [value("a")] Jan 1992 MSG constant expression
REM [value("__cabbage", 1)] Jan 1992 MSG non-constant expression
IF 0
# A comment in a false IF block
#!P This should be nuked

View File

@@ -3,6 +3,9 @@
# If you're writing a back-end, test it by feeding it the output
# of: remind -pp test-for-backends.rem
# All back-ends should endeavour to support: WEEK, SHADE, MOON, and
# COLOR/COLOUR. They may support other back-end-specific SPECIALs.
# Color and shade
REM 1 SPECIAL COLOR 128 0 0 Red
REM 2 SPECIAL COLOUR 0 128 0 British Green
@@ -17,11 +20,18 @@ REM [moondate(3)] SPECIAL MOON 3 -1 -1 [moontime(3)]
# Week
REM Monday SPECIAL WEEK (W[weekno()])
# PostScript
REM Wed PS Border Border 2 div moveto /Helvetica-Oblique findfont 6 scalefont setfont (oof!) show
# A normal reminder
REM 16 MSG A normal reminder
# PostScript - currently only supported by rem2ps
REM Wed PS Border Border 2 div moveto /Helvetica-Oblique findfont 6 scalefont setfont (oof PostScript!) show
# A SPECIAL that should be ignored
REM 15 SPECIAL RANDOM-STUFF ignore me and be happy
# A normal reminder
REM 16 MSG A normal reminder
# HTML - currently only supported by rem2html
REM 17 SPECIAL HTML I am <b>bold</b> HTML
# Pango - currently only supported by rem2pdf
REM 18 SPECIAL PANGO I am <b>bold</b> PANGO

View File

@@ -428,7 +428,7 @@ Leaving UserFN _i(29, "Adar A", 1991-02-16, 5756) => Invalid Hebrew date
# This causes a parse error on version 03.01.01
REM 1990-01-01 SATISFY 1
../tests/test.rem(90): Expired
../tests/test.rem(90): Expired: 1990-01-01
# Test each possible case of the basic reminders.
@@ -494,7 +494,7 @@ REM May 1992 MSG May 1992
../tests/test.rem(121): Trig = Friday, 1 May, 1992
REM 1 Jan 1991 MSG 1 Jan 1991
../tests/test.rem(123): Expired
../tests/test.rem(123): Expired: 1991-01-01
REM 16 Feb 1991 MSG 16 Feb 1991
../tests/test.rem(124): Trig = Saturday, 16 February, 1991
16 Feb 1991
@@ -800,8 +800,7 @@ Leaving UserFN _ofunc(1991-02-28) => 0
../tests/test.rem(224): Trig = Thursday, 28 February, 1991
# omitfunc ignores local/global omits
fset _ofunc(x) 0
../tests/test.rem(227): Function `_ofunc' redefined: previously defined at ../tests/test.rem(222)
fset - _ofunc(x) 0
OMIT 1 March
OMIT 2 March 1991
REM 1 March OMIT Sun OMITFUNC _ofunc AFTER MSG Should trigger 1 March
@@ -1043,7 +1042,7 @@ set a057 value("a05"+"6")
"a05" + "6" => "a056"
value("a056") => "SDFJHSDF KSJDFH KJSDFH KSJDFH"
set a058 version()
version() => "05.04.00"
version() => "05.04.02"
set a059 wkday(today())
today() => 1991-02-16
wkday(1991-02-16) => "Saturday"
@@ -2606,7 +2605,7 @@ a056 "SDFJHSDF KSJDFH KJSDFH KSJDFH"
a007 "1991-02-16"
a057 "SDFJHSDF KSJDFH KJSDFH KSJDFH"
a008 "11:44"
a058 "05.04.00"
a058 "05.04.02"
a059 "Saturday"
a010 12
a060 6
@@ -3154,7 +3153,7 @@ REM Mon 1992 UNTIL 1991-01-01 MSG Not diagnosed - not fully-specified start
../tests/test.rem(561): Expired
REM 1992-01-01 *1 UNTIL 1991-12-31 MSG Diagnosed
../tests/test.rem(562): Warning: UNTIL/THROUGH date earlier than start date
../tests/test.rem(562): Trig = Wednesday, 1 January, 1992
../tests/test.rem(562): Expired
set x '1992-01-01'
MSG [isconst(x)]
../tests/test.rem(564): Trig = Saturday, 16 February, 1991
@@ -3165,7 +3164,7 @@ isconst(1992-01-01) => 1
REM [x] *1 UNTIL 1991-12-31 MSG Diagnosed
x => 1992-01-01
../tests/test.rem(565): Warning: UNTIL/THROUGH date earlier than start date
../tests/test.rem(565): Trig = Wednesday, 1 January, 1992
../tests/test.rem(565): Expired
set x nonconst('1992-01-01')
nonconst(1992-01-01) => 1992-01-01
@@ -3177,7 +3176,7 @@ isconst(1992-01-01) => 0
REM [x] *1 UNTIL 1991-12-31 MSG Not diagnosed - nonconst expression
x => 1992-01-01
../tests/test.rem(569): Trig = Wednesday, 1 January, 1992
../tests/test.rem(569): Expired
REM MON FROM 1992-01-01 UNTIL 1991-12-31 MSG Diagnosed
../tests/test.rem(571): Warning: UNTIL/THROUGH date earlier than FROM date
@@ -4116,7 +4115,7 @@ trig("Mon", "Tue", "Wed") => ../tests/test.rem(849): Trig = Monday, 18 February,
../tests/test.rem(849): Trig = Tuesday, 19 February, 1991
../tests/test.rem(849): Trig = Wednesday, 20 February, 1991
1990-01-01
../tests/test.rem(849): Expired
../tests/test.rem(849): Expired: 1990-01-01
# Multitrig
REM [multitrig("10", "17")] MSG multitrig-1
@@ -4152,7 +4151,7 @@ REM [multitrig("15 SCANFROM -7", "14 SCANFROM -7")] MSG multitrig-6
multitrig("15 SCANFROM -7", "14 SCANFROM -7") => ../tests/test.rem(857): Trig = Friday, 15 February, 1991
../tests/test.rem(857): Trig = Thursday, 14 February, 1991
1991-02-14
../tests/test.rem(857): Expired
../tests/test.rem(857): Expired: 1991-02-14
REM [multitrig("15 SCANFROM -7", "14 SCANFROM -7")] SCANFROM -7 MSG multitrig-7
multitrig("15 SCANFROM -7", "14 SCANFROM -7") => ../tests/test.rem(858): Trig = Friday, 15 February, 1991
../tests/test.rem(858): Trig = Thursday, 14 February, 1991
@@ -5076,12 +5075,12 @@ htmlstriptags("<img src=\"foo\">") => ""
# $ParseUntriggered
REM 2 Jan 1990 MSG ["bad_expr" / 2]
../tests/test.rem(971): Expired
../tests/test.rem(971): Expired: 1990-01-02
"bad_expr" / 2 => Type mismatch
../tests/test.rem(971): `/': Type mismatch
SET $ParseUntriggered 0
REM 2 Jan 1990 MSG ["bad_expr" / 2]
../tests/test.rem(973): Expired
../tests/test.rem(973): Expired: 1990-01-02
SET $ParseUntriggered 1
# String multiplication
@@ -5640,8 +5639,8 @@ REM SATISFY ""
REM SATISFY [version() > "01.00.00"]
../tests/test.rem(1055): SATISFY: expression has no reference to trigdate() or $T...
../tests/test.rem(1055): Trig = Saturday, 16 February, 1991
version() => "05.04.00"
"05.04.00" > "01.00.00" => 1
version() => "05.04.02"
"05.04.02" > "01.00.00" => 1
../tests/test.rem(1055): Trig(satisfied) = Saturday, 16 February, 1991
REM SATISFY [max(x, max(x, 1, 2, 3), 4, 5, 6) * 5]
../tests/test.rem(1056): SATISFY: expression has no reference to trigdate() or $T...
@@ -16363,8 +16362,8 @@ set a monnum("Dec")
monnum("Dec") => 12
set a monnum("not a month")
monnum("not a month") => Type mismatch
../tests/test.rem(1491): monnum(): Type mismatch
monnum("not a month") => Invalid month name
../tests/test.rem(1491): monnum(): Invalid month name
# Test wkdaynum("string")
set a wkdaynum("Sun")
@@ -16398,8 +16397,8 @@ set a wkdaynum("saturday")
wkdaynum("saturday") => 6
set a wkdaynum("cabbage")
wkdaynum("cabbage") => Type mismatch
../tests/test.rem(1510): wkdaynum(): Type mismatch
wkdaynum("cabbage") => Invalid weekday name
../tests/test.rem(1510): wkdaynum(): Invalid weekday name
# Test non-constant debugging
DEBUG +n
@@ -16554,12 +16553,59 @@ shell("ls") => RUN disabled
../tests/test.rem(1588): shell(): RUN disabled
RUN disabled
# "value" should use lazy evaluation
set a value(4:33)
value(04:33) => Type mismatch
../tests/test.rem(1591): Type mismatch
set a value('2020-01-01', 42)
value(2020-01-01, ?) => Type mismatch
../tests/test.rem(1592): Type mismatch
set a value("nosuchvar")
value("nosuchvar") => Undefined variable
../tests/test.rem(1593): Undefined variable
set a value("nosuchvar", 42)
value("nosuchvar", 42) => 42
set a value("a", 42)
value("a", ?) => 42
set a value("a")
value("a") => 42
DEBUG -x
DEBUG -e
../tests/test.rem(1596): eval(): Too many recursive function calls
../tests/test.rem(1603): eval(): Too many recursive function calls
Base: 1991-02-09
Base: 1991-02-09
../tests/test.rem(1611): Expired
../tests/test.rem(1612): Expired
trigvalid = 1; trigdate = 1991-01-14
trigvalid = 0; trigdate = 0
daysinmon(2, 2000) => 29
daysinmon(2, 2001) => 28
daysinmon(3, 2000) => 31
daysinmon(3, 2001) => 31
daysinmon("Feb", 2000) => 29
daysinmon("Feb", 2001) => 28
daysinmon("March", 2000) => 31
daysinmon("March", 2001) => 31
daysinmon("Cabbage", 2001) => Invalid month name
../tests/test.rem(1639): daysinmon(): Invalid month name
daysinmon(2000-02-14) => 29
daysinmon(2001-02-14) => 28
daysinmon(2000-04-14) => 30
daysinmon(2001-04-14) => 30
date(2020, "April", 15) => 2020-04-15
date(2020, "Carrot", 12) => Invalid month name
../tests/test.rem(1647): date(): Invalid month name
datetime(2020, "April", 13, 04:44) => 2020-04-13@04:44
datetime(2020, "April", 13, 4, 44) => 2020-04-13@04:44
datetime(2020, "Lettuce", 13, 04:44) => Invalid month name
../tests/test.rem(1650): datetime(): Invalid month name
datetime(2020, "Lettuce", 13, 4, 44) => Invalid month name
../tests/test.rem(1651): datetime(): Invalid month name
wkdaynum("Tue") => 2
wkdaynum("Wednesday") => 3
wkdaynum("telephone") => Invalid weekday name
../tests/test.rem(1655): wkdaynum(): Invalid weekday name
Variable hash table statistics:
Entries: 100143; Buckets: 87719; Non-empty Buckets: 66301
Maxlen: 5; Minlen: 0; Avglen: 1.142; Stddev: 0.878; Avg nonempty len: 1.510
@@ -20399,10 +20445,11 @@ FSET not_const(x) x+nonconst(a)
#!P: Next line may have expired, but contains non-constant expression
#!P: or a relative SCANFROM clause
REM [not_const(5)] Jan 1992 MSG nonconstant expression
#!P: Next line has expired, but contains expression... please verify
#!P: Expired: REM [value("a")] Jan 1992 MSG constant expression
#!P: Next line may have expired, but contains non-constant expression
#!P: or a relative SCANFROM clause
REM [value("a")] Jan 1992 MSG nonconstant expression
REM [value("__cabbage", 1)] Jan 1992 MSG non-constant expression
#!P: The next IF evaluated false...
#!P: REM statements in IF block not checked for purging.
IF 0
@@ -20516,8 +20563,8 @@ FSET not_const(x) x+nonconst(a)
#!P: Expired: REM [const(5)] Jan 1992 MSG expired... should be commented out
#!P: Expired: REM [const(a)] Jan 1992 MSG expired... should be commented out
REM [not_const(5)] Jan 1992 MSG nonconstant expression
REM [value("a")] Jan 1992 MSG nonconstant expression
#!P: Expired: REM [value("a")] Jan 1992 MSG constant expression
REM [value("__cabbage", 1)] Jan 1992 MSG non-constant expression
IF 0
# A comment in a false IF block
ENDIF
@@ -23621,7 +23668,7 @@ SECURITY: Won't read world-writable file or directory!
Error reading include_dir/ww: Can't open file
SECURITY: Won't read world-writable file or directory!
Error reading include_dir/ww: No files matching *.rem
05.04.00
05.04.02
Enabling test mode: This is meant for the acceptance test.
Do not use --test in production.
In test mode, the system time is fixed at 2025-01-06@19:00
@@ -23675,7 +23722,7 @@ REM 29 Feb MSG two
REM 29 2024 MSG three
-stdin-(4): Trig = Friday, 29 March, 2024
REM 29 Feb 2024 MSG four
-stdin-(5): Expired
-stdin-(5): Expired: 2024-02-29
REM Thursday 29 MSG One
-stdin-(6): Trig = Thursday, 4 April, 2024
REM Thursday 29 Feb MSG two
@@ -23683,7 +23730,7 @@ REM Thursday 29 Feb MSG two
REM Thursday 29 2024 MSG three
-stdin-(8): Trig = Thursday, 4 April, 2024
REM Thursday 29 Feb 2024 MSG four
-stdin-(9): Expired
-stdin-(9): Expired: 2024-02-29
REM Wednesday 29 MSG One
-stdin-(10): Trig = Wednesday, 6 March, 2024
REM Wednesday 29 Feb MSG two
@@ -24826,10 +24873,11 @@ TRANSLATE "Ok" ""
TRANSLATE "Missing ']'" ""
TRANSLATE "Missing quote" ""
TRANSLATE "Expression too complex" ""
TRANSLATE "Invalid month name" ""
TRANSLATE "Missing ')'" ""
TRANSLATE "Undefined function" ""
TRANSLATE "Illegal character" ""
TRANSLATE "Expecting binary operator" ""
TRANSLATE "Invalid weekday name" ""
TRANSLATE "Out of memory" ""
TRANSLATE "Ill-formed number" ""
TRANSLATE "Can't coerce" ""
@@ -24955,6 +25003,7 @@ TRANSLATE "No Adar A in %d" ""
TRANSLATE "No substition function `%s' defined" ""
TRANSLATE "Non-constant built-in function `%s' makes expression non-constant" ""
TRANSLATE "Non-constant expression converted to constant by `const' built-in function" ""
TRANSLATE "Nonexistence of global variable `%s' makes value() non-constant" ""
TRANSLATE "Not setting $OnceFile: Already processed a reminder with a ONCE clause" ""
TRANSLATE "OMIT: UNTIL not allowed; did you mean THROUGH?" ""
TRANSLATE "OMITFUNC counts as a non-constant expression" ""

View File

@@ -224,7 +224,7 @@ REM 1 March OMITFUNC _ofunc AFTER MSG OmitFunc Test
REM 8 March OMITFUNC _ofunc -1 MSG OmitFunc Test 2
# omitfunc ignores local/global omits
fset _ofunc(x) 0
fset - _ofunc(x) 0
OMIT 1 March
OMIT 2 March 1991
REM 1 March OMIT Sun OMITFUNC _ofunc AFTER MSG Should trigger 1 March
@@ -1587,6 +1587,13 @@ FUNSET i
set a "eval(\"1\")+ shell(\"ls\")"
set b eval(a)
# "value" should use lazy evaluation
set a value(4:33)
set a value('2020-01-01', 42)
set a value("nosuchvar")
set a value("nosuchvar", 42)
set a value("a", 42)
set a value("a")
DEBUG -x
DEBUG -e
@@ -1599,6 +1606,55 @@ set a eval(a)
REM 9 Feb 1991 *7 MSG Base: [trigbase()]
REM 9 Feb 1991 *1 MSG Base: [$Tb]
# The UNTIL bug
DEBUG +t
REM SECOND SATURDAY +300 UNTIL 1991-02-02 MSG [$T]
REM SECOND SATURDAY +300 UNTIL 1991-02-16 MSG [$T]
DEBUG -t
# Fully-specified trigger date in the past
REM 14 Jan 1991 MSG In the past
set a trigvalid()
set b trigdate()
REM MSG trigvalid = [a]; trigdate = [b]
# SATISFY clause that's never satisfied...
REM 14 Jan 1991 SATISFY [$Ty == 2022] MSG I can't get no satisfaction
set a trigvalid()
set b trigdate()
REM MSG trigvalid = [a]; trigdate = [b]
DEBUG +x
set a daysinmon(2, 2000)
set a daysinmon(2, 2001)
set a daysinmon(3, 2000)
set a daysinmon(3, 2001)
set a daysinmon("Feb", 2000)
set a daysinmon("Feb", 2001)
set a daysinmon("March", 2000)
set a daysinmon("March", 2001)
set a daysinmon("Cabbage", 2001)
set a daysinmon('2000-02-14')
set a daysinmon('2001-02-14')
set a daysinmon('2000-04-14')
set a daysinmon('2001-04-14')
set a date(2020, "April", 15)
set a date(2020, "Carrot", 12)
set a datetime(2020, "April", 13, 4:44)
set a datetime(2020, "April", 13, 4, 44)
set a datetime(2020, "Lettuce", 13, 4:44)
set a datetime(2020, "Lettuce", 13, 4, 44)
set a wkdaynum("Tue")
set a wkdaynum("Wednesday")
set a wkdaynum("telephone")
DEBUG -x
# Output expression-node stats
DEBUG +h