Compare commits

...

54 Commits

Author SHA1 Message Date
Dianne Skoll 739d285e36 Indent system variable dump better.
Remind unit tests / tests (push) Successful in 48s
2024-09-15 10:21:22 -04:00
Dianne Skoll ee1c931932 Add $SuppressImplicitWarnings system variable.
This suppresses warnings about missing REM or MSG tokens.
2024-09-15 09:39:15 -04:00
Dianne Skoll 0806b6738f Add test for time constants of the form '12:34'
Remind unit tests / tests (push) Successful in 41s
2024-09-13 13:07:49 -04:00
Dianne Skoll 020e82d575 Document that TIME constants may be surrounded by single quotes. 2024-09-13 13:06:57 -04:00
Dianne Skoll a20f2b588e Accept either 12:34 or '12:34' as a time constant. 2024-09-13 13:02:46 -04:00
Dianne Skoll 631e721a96 More helpful error if someone uses '...' around a TIME constant. 2024-09-13 12:46:38 -04:00
Dianne Skoll 8453e17c6c Add a guard to avoid calling free(NULL)
Remind unit tests / tests (push) Successful in 29s
2024-09-12 11:50:11 -04:00
Dianne Skoll 76c1e2abb3 Avoid unnecessary double-initialization. 2024-09-12 11:38:59 -04:00
Dianne Skoll 3389f1c91b Refactor init_token and token_error. 2024-09-12 10:58:35 -04:00
Dianne Skoll b2d47ae979 Initialize token.val in a few places. 2024-09-12 10:51:00 -04:00
Dianne Skoll e2c615f310 Fix comment. 2024-09-12 10:16:01 -04:00
Dianne Skoll e8492a4303 Add Chinese New Year file. 2024-09-11 12:09:57 -04:00
Dianne Skoll 4695efaabd Use DBG macro
Remind unit tests / tests (push) Failing after 28s
2024-09-11 11:53:07 -04:00
Dianne Skoll c433f42587 Get rid of useless function. 2024-09-11 11:49:04 -04:00
Dianne Skoll 4708e59a43 No need to munch following whitespace. 2024-09-11 11:46:40 -04:00
Dianne Skoll d56ac6332a Use switch rather than if...else chains
Remind unit tests / tests (push) Successful in 33s
2024-09-11 11:37:30 -04:00
Dianne Skoll b054baf590 Stricter tokenization of datetime 2024-09-11 09:01:52 -04:00
Dianne Skoll 42f5e3467d Better error messages for ill-formed time. 2024-09-11 08:52:06 -04:00
Dianne Skoll 97013ae89b Return T_Illegal with a negative tok.val if we can't parse a numeric token. 2024-09-11 08:45:31 -04:00
Dianne Skoll 2acead9118 Shorten error message.
Remind unit tests / tests (push) Successful in 29s
2024-09-10 16:25:00 -04:00
Dianne Skoll a53a80acb4 Make error message more explicit. 2024-09-10 16:23:52 -04:00
Dianne Skoll 56e62b1b4d More error checking of bad date specs. 2024-09-10 14:27:46 -04:00
Dianne Skoll c645db5ede Diagnose bad YYYY-MM-DD constants in REM command. 2024-09-10 14:09:52 -04:00
Dianne Skoll ef6b9c3783 Better error message when a number that isn't recognized as a day number or year is encountered. 2024-09-10 13:57:34 -04:00
Dianne Skoll 019bee26cb Start refactoring calendar code.
Remind unit tests / tests (push) Successful in 30s
2024-09-10 10:47:32 -04:00
Dianne Skoll 152cd4090b Better error message.
Remind unit tests / tests (push) Successful in 28s
2024-09-09 17:01:56 -04:00
Dianne Skoll b7fc2b5776 Tweak remind-conf-mode.el with new Remind keywords and better handling of comment lines. 2024-09-09 16:50:27 -04:00
Dianne Skoll 723aba9b7c Document and test --print-tokens
Remind unit tests / tests (push) Successful in 30s
2024-09-08 10:33:24 -04:00
Dianne Skoll 8a5b88338b Add --print-tokens long option to dump Remind tokens to stdout. 2024-09-08 10:29:49 -04:00
Dianne Skoll 7236441e02 Remove note saying REM can be omitted. 2024-09-08 10:26:07 -04:00
Dianne Skoll e4bab0dda4 Be more explicit. 2024-09-08 09:57:52 -04:00
Dianne Skoll 5b7d4a07ec More explicit error messages.
Remind unit tests / tests (push) Successful in 47s
2024-09-07 13:25:31 -04:00
Dianne Skoll 8c3d2c4003 More specific error message. 2024-09-07 13:14:31 -04:00
Dianne Skoll f485d607ff Fix error message. 2024-09-07 10:16:57 -04:00
Dianne Skoll a0effa5f0b Update keyword/variable/function list in remind-conf-mode.el. 2024-09-07 10:15:02 -04:00
Dianne Skoll 7d501cda6f Update to ical2rem version 0.7.
Remind unit tests / tests (push) Successful in 31s
2024-09-05 12:44:17 -04:00
Dianne Skoll 5d7f55c8d5 Make error messages more consistent.
Remind unit tests / tests (push) Successful in 28s
2024-09-03 10:53:45 -04:00
Dianne Skoll 097bf92bea Better error message. 2024-09-03 10:51:50 -04:00
Dianne Skoll b9dea59206 Update changelog.
Remind unit tests / tests (push) Successful in 39s
2024-09-02 14:46:58 -04:00
Dianne Skoll 46aa144b65 Bump version to 05.00.05 2024-09-02 10:15:56 -04:00
Dianne Skoll 914971308d Better error message.
Remind unit tests / tests (push) Successful in 30s
2024-09-01 23:42:29 -04:00
Dianne Skoll a22e81040f Check error return in a couple of spots. 2024-09-01 23:22:00 -04:00
Dianne Skoll 72f74f03cf Check for errors. 2024-09-01 23:18:09 -04:00
Dianne Skoll d0e45e727e Don't print closing ] in error indicator.
Remind unit tests / tests (push) Successful in 31s
2024-09-01 22:39:49 -04:00
Dianne Skoll ce2b2e80da Remove unnecessary _h() function definition.
Remind unit tests / tests (push) Successful in 28s
2024-09-01 11:31:28 -04:00
Dianne Skoll 11771b7d3d Better formatting of ^-- here message for expressions with embedded newlines 2024-09-01 11:27:34 -04:00
Dianne Skoll 01cb028532 Fix up tests to pass in September 2024. 2024-09-01 11:09:32 -04:00
Dianne Skoll 58b6f43b9c Better diagnosis of wrong #args for builtin functions. 2024-09-01 09:03:26 -04:00
Dianne Skoll 1dedb667e8 Prevent a couple of file descriptor leaks.
Remind unit tests / tests (push) Successful in 28s
2024-08-31 09:06:05 -04:00
Dianne Skoll 8a96236788 Avoid warnings if REM_USE_WCHAR is undefined.
Remind unit tests / tests (push) Successful in 28s
2024-08-30 20:44:08 -04:00
Dianne Skoll 2a13163659 Fix some weird edge cases in text-mode calendar formatting.
Remind unit tests / tests (push) Successful in 28s
2024-08-29 13:25:36 -04:00
Dianne Skoll 336a9684d4 In calendar mode, SHADE the entire calendar box including day number.
Remind unit tests / tests (push) Successful in 29s
2024-08-29 08:50:57 -04:00
Dianne Skoll 86945c6e18 Remove incorrect test obsoleted by changes in 05.00.04. 2024-08-29 08:39:55 -04:00
Dianne Skoll 684280db5e Remove "SCHED _sfun" and hard-code "+15" instead. 2024-08-29 08:15:10 -04:00
32 changed files with 1474 additions and 375 deletions
Vendored
+9 -9
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.00.04.
# Generated by GNU Autoconf 2.71 for remind 05.00.05.
#
#
# 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.00.04'
PACKAGE_STRING='remind 05.00.04'
PACKAGE_VERSION='05.00.05'
PACKAGE_STRING='remind 05.00.05'
PACKAGE_BUGREPORT=''
PACKAGE_URL='https://dianne.skoll.ca/projects/remind/'
@@ -1264,7 +1264,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.00.04 to adapt to many kinds of systems.
\`configure' configures remind 05.00.05 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1326,7 +1326,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of remind 05.00.04:";;
short | recursive ) echo "Configuration of remind 05.00.05:";;
esac
cat <<\_ACEOF
@@ -1414,7 +1414,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
remind configure 05.00.04
remind configure 05.00.05
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1864,7 +1864,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.00.04, which was
It was created by remind $as_me 05.00.05, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -4703,7 +4703,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.00.04, which was
This file was extended by remind $as_me 05.00.05, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -4768,7 +4768,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.00.04
remind config.status 05.00.05
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
+1 -1
View File
@@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(remind, 05.00.04, , , https://dianne.skoll.ca/projects/remind/)
AC_INIT(remind, 05.00.05, , , https://dianne.skoll.ca/projects/remind/)
AC_CONFIG_SRCDIR([src/queue.c])
cat <<'EOF'
+3
View File
@@ -0,0 +1,3 @@
The upstream GitHub project for ical2rem is:
https://github.com/jbalcorn/ical2rem
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Justin B. Alcorn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+103
View File
@@ -0,0 +1,103 @@
# ical2rem
The original iCal to Remind script, first released in 2005.
Reads iCal files and outputs remind-compatible files. Tested ONLY with
calendar files created by Mozilla Calendar/Sunbird. Use at your own risk.
## License
In 2005, this was released with the Gnu Public License V2. However, I am changing it to the MIT License, since that provides greater freedom to do with this code what you want.
Copyright (c) 2005, 2007, 2019 Justin B. Alcorn
## How I use Remind and Google Calendar together
- My family has a Google Email domain, and our email addresses all end in the same domain. We all use Google Calendars and I want to mail reminders to each of the family members containing both Google Calendar and .reminder information.
- Under my ~/.rem/ directory each family member has a directory. Each directory contains a standard remind file called 'reminders' that at the very least has the line "INCLUDE /home/jalcorn/.rem/<username>/ical2rem" and flag files indicating whether they want Daily or Weekly reminders. My reminders files references my standard .reminders file, and I also have a flag so if I run a Test run I'll get it. There's actually a lot more files (I have a big family).
````
./rem
./son1:
drwxrwxr-x 2 jalcorn jalcorn 4096 Dec 12 14:02 .
drwxr-xr-x 12 jalcorn jalcorn 4096 Dec 12 14:13 ..
-rw-rw-r-- 1 jalcorn jalcorn 51 Mar 3 06:10 ical2rem
lrwxrwxrwx 1 jalcorn jalcorn 33 Oct 27 2016 son1.ics -> /home/jalcorn/calendars/son1.ics
-rw-rw-r-- 1 jalcorn jalcorn 976 Dec 12 14:02 reminders
-rw-rw-r-- 1 jalcorn jalcorn 0 Oct 27 2016 Weekly
./justin:
drwxrwxr-x 2 jalcorn jalcorn 4096 Feb 27 08:29 .
drwxr-xr-x 12 jalcorn jalcorn 4096 Dec 12 14:13 ..
lrwxrwxrwx 1 jalcorn jalcorn 32 Oct 27 2016 son1.ics -> /home/jalcorn/calendars/son1.ics
-rw-rw-r-- 1 jalcorn jalcorn 0 Nov 7 2016 Daily
lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 family.ics -> /home/jalcorn/calendars/family.ics
-rw-rw-r-- 1 jalcorn jalcorn 37320 Mar 3 06:10 ical2rem
lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 justin.ics -> /home/jalcorn/calendars/justin.ics
lrwxrwxrwx 1 jalcorn jalcorn 24 Nov 7 2016 reminders -> /home/jalcorn/.reminders
lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 vmd.ics -> /home/jalcorn/calendars/vmd.ics
-rw-rw-r-- 1 jalcorn jalcorn 0 Oct 27 2016 Test
-rw-rw-r-- 1 jalcorn jalcorn 0 Nov 7 2016 Weekly
````
- bin/getgooglecals.sh runs out of crontab and downloads whatever calendars I want. Note that we can also download organization calendars, I've included a public one here (Cleveland Heights Vocal Music Department calendar).
- dailyreminders.sh is linked to weeklyreminders.sh and testreminders.sh so I can run it in different modes. The concatenate the various calendar outputs as a single remind file then send the reminders via email.
### Example: .rem/son1/reminders file:
````
INCLUDE /home/jalcorn/.rem/defs.rem
INCLUDE /home/jalcorn/.rem/float
INCLUDE /home/jalcorn/.rem/son1/ical2rem
fset _weeks() coerce("STRING", (trigdate()-today())/7) + plural((trigdate()-today())/7, " week")
FSET _sfun(x) choose(x, -60, 30, 5, 0)
FSET oldfloat(y,m,d) trigger(MAX(realtoday(), date(y,m,d)))
FSET due(y,m,d) "(" + (date(y,m,d)-trigdate()) + ")"
SET fullmoon moondate(2)
REM [trigger(realtoday())] SPECIAL SHADE 145 70 100 %
REM [float(2019,4,15,105)] MSG File tax return [due(2017,4,15)]%
REM PRIORITY 9999 MSG %"%"%
INCLUDE /home/jalcorn/.rem/bdays
SET $LongDeg 81
SET $LongMin 11
SET $LongSec 11
SET $LatDeg 41
SET $LatMin 11
SET $LatSec 11
REM [trigger(moondate(2))] +1 MSG %"Full Moon%" %b%
fset _srtd() coerce("STRING", _no_lz(_am_pm(sunrise(today()))))
fset _sstd() coerce("STRING", _no_lz(_am_pm(sunset(today()))))
MSG Sun is up today from [_srtd()] to [_sstd()].%"%"%
````
## Revision History
### Version 0.7 2024-09-04
- ISSUE 8: New version of remind complains if _sfun isn't defined. Output a header
to define a function that does nothing if the function doesn't exist.
### Version 0.6 2019-03-01
- Publish on GitHub and change license to MIT License
- Add supporting files and explanation of how I use it
### version 0.5.2 2007-03-23
- BUG: leadtime for recurring events had a max of 4 instead of DEFAULT_LEAD_TIME
- remove project-lead-time, since Category was a non-standard attribute
- NOTE: There is a bug in iCal::Parser v1.14 that causes multiple calendars to
fail if a calendar with recurring events is followed by a calendar with no
recurring events. This has been reported to the iCal::Parser author.
### version 0.5.1 2007-03-21
- BUG: Handle multiple calendars on STDIN
- add --heading option for priority on section headers
### version 0.5 2007-03-21
- Add more help options
- --project-lead-time option
- Supress printing of heading if there are no todos to print
### version 0.4
- Version 0.4 changes all written or inspired by, and thanks to Mark Stosberg
- Change to GetOptions
- Change to pipe
- Add --label, --help options
- Add Help Text
- Change to subroutines
- Efficiency and Cleanup
### version 0.3
- Convert to GPL (Thanks to Mark Stosberg)
- Add usage
### version 0.2
- add command line switches
- add debug code
- add SCHED _sfun keyword
- fix typos
### version 0.1 - ALPHA CODE.
+82
View File
@@ -0,0 +1,82 @@
#!/usr/bin/perl -w
#
# cal_futureonly.pl -
# Reads iCal files and outputs events between 1 month ago and 1 year from now.
# Copyright (c) 2005, 2007, 2019 Justin B. Alcorn
=head1 SYNOPSIS
cal_futureonly.pl --file=filname.ics > output.ics
--help Usage
--man Complete man page
--infile (REQUIRED) name of input calendar file
--file (REQUIRED) name of output calendar file
Expects an ICAL stream on STDIN. Converts it to the format
used by the C<remind> script and prints it to STDOUT.
=head2 --infile
Input file
=head2 --file
Output File
=cut
use strict;
use Data::ICal;
use Data::ICal::Entry;
use DateTime::Span;
use Data::ICal::DateTime;
use DateTime;
use Getopt::Long 2.24 qw':config auto_help';
use Pod::Usage;
use Data::Dumper;
use vars '$VERSION';
$VERSION = "0.1";
my $help;
my $man;
my $infile;
my $file;
my $debug = 0;
GetOptions (
"help|?" => \$help,
"man" => \$man,
"debug" => \$debug,
"infile=s" => \$infile,
"file=s" => \$file
);
pod2usage(1) if $help;
pod2usage(1) if (! $file);
pod2usage(-verbose => 2) if $man;
my $limit = DateTime->now();
$limit->subtract( months => 1);
my $endlimit = DateTime->now()->add(years =>1);
print STDERR "including events from: ",$limit->ymd," to: ".$endlimit->ymd,"\n" if $debug;
my $span = DateTime::Span->from_datetimes( start => $limit, end => $endlimit );
print STDERR "Parsing $infile\n" if $debug;
my $cal = Data::ICal->new(filename => $infile);
if (! $cal) {
die "Died Trying to read $infile :".$cal->error_message;
}
#my $archive = Data::ICal->new(filename => 'archive.ics');
print "Output = $file\n" if $debug;
my $new = Data::ICal->new();
if (! $new) {
die $new->error_message;
}
my @events = $cal->events($span);
$new->add_entries(@events);
open(NEW, ">$file");
print NEW $new->as_string;
close NEW;
exit 0;
#:vim set ft=perl ts=4 sts=4 expandtab :
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
r=`basename $0`
if [ $r == 'weeklyreminders.sh' ];
then
t=14;
w=Weekly;
elif [ $r == 'dailyreminders.sh' ];
then
t=3;
w=Daily;
else
t=5
w=Test;
fi
cd .rem
for d in * ;
do
if [ "$( ls -A $d/$w 2>/dev/null )" ];
then
echo "Sending a $w reminder to $d"
ft=/tmp/$d-t-$$.txt
f=/tmp/$d-$$.txt
echo "Reminders for next $t days:" >> $f
cat /dev/null > $d/ical2rem
for c in $d/*.ics
do
calname=`basename $c .ics | tr a-z A-Z`
cat $c 2>/dev/null | sed -e "s/^SUMMARY:/SUMMARY: {${calname}} /" \
| sed -e 's/DT\([A-Z]*\);TZID=UTC:\([0-9T]*\)/DT\1:\2Z/' >> $ft
done
cat $ft | ~/bin/ical2rem.pl --label "Online Calendar" --heading "PRIORITY 9999" --lead-time $t >> $d/ical2rem
if [ -e $d/reminders ];then r="${d}/reminders"; else r="${d}/ical2rem";fi
/usr/bin/remind -q -iplain=1 $r >> $f
echo "
All calendars can be accessed by logging into https://calendar.google.com/ as $d@jalcorn.net
" >> $f
cat $f | mail -s "$w Reminders for $d" $d@jalcorn.net;
cat $f
rm $f
rm $ft
fi;
done
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
#
# Get google calendars, fix issues caused by changes in Google calendars, and remove all past events.
#
# Obviously, I've removed the private hashes from private calendars.
#
cd ~/calendars
wget -q -O full/justin.ics --no-check-certificate https://www.google.com/calendar/ical/jbalcorn\%40gmail.com/private-aaaaaaaaaaaaaaaaaaaaaaaaaa/basic.ics
wget -q -O full/family.ics --no-check-certificate https://www.google.com/calendar/ical/jalcorn.net_aaaaaaaaaaaaaaaaaaaaaaaaaa\%40group.calendar.google.com/private-6c42a79dec0b3b3bb7b9b0ebf9776bc1/basic.ics
wget -q -O full/son1.ics --no-check-certificate https://www.google.com/calendar/ical/son1\%40jalcorn.net/private-aaaaaaaaaaaaaaaaaaaaaaaaaa/basic.ics
wget -q -O full/vmd.ics --no-check-certificate https://calendar.google.com/calendar/ical/chuh.org_0pmkefjkiqc4snoel7occlslh8%40group.calendar.google.com/public/basic.ics
for i in full/*.ics;do
cat $i 2>/dev/null | sed -e 's/DT\([A-Z]*\);TZID=UTC:\([0-9T]*\)/DT\1:\2Z/' > /tmp/temp.ics
cp /tmp/temp.ics $i
done
~/bin/cal_futureonly.pl --infile=full/justin.ics --file=justin.ics
~/bin/cal_futureonly.pl --infile=full/family.ics --file=family.ics
~/bin/cal_futureonly.pl --infile=full/son1.ics --file=son1.ics
~/bin/cal_futureonly.pl --infile=full/vmd.ics --file=vmd.ics
@@ -19,7 +19,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
# version 0.6 2019-03-01
# - Updates to put on GitHub
# version 0.5.2 2007-03-23
# - BUG: leadtime for recurring events had a max of 4 instead of DEFAULT_LEAD_TIME
# - remove project-lead-time, since Category was a non-standard attribute
@@ -32,7 +33,7 @@
# version 0.5 2007-03-21
# - Add more help options
# - --project-lead-time option
# - Suppress printing of heading if there are no todos to print
# - Supress printing of heading if there are no todos to print
# version 0.4
# - Version 0.4 changes all written or inspired by, and thanks to Mark Stosberg
# - Change to GetOptions
@@ -56,12 +57,19 @@
cat /path/to/file*.ics | ical2rem.pl > ~/.ical2rem
All options have reasonable defaults:
--label Calendar name (Default: Calendar)
--label Calendar name (Default: Calendar)
--start Start of time period to parse (parsed by str2time)
--end End of time period to parse
--lead-time Advance days to start reminders (Default: 3)
--todos, --no-todos Process Todos? (Default: Yes)
--heading Define a priority for static entries
--help Usage
--man Complete man page
--iso8601 Use YYYY-MM-DD date format
--locations, --no-locations Include location? (Default: Yes)
--end-times, --no-end-times Include event end times in reminder text
(Default: No)
--heading Define a priority for static entries
--help Usage
--debug Enable debug output
--man Complete man page
Expects an ICAL stream on STDIN. Converts it to the format
used by the C<remind> script and prints it to STDOUT.
@@ -74,6 +82,14 @@ The syntax generated includes a label for the calendar parsed.
By default this is "Calendar". You can customize this with
the "--label" option.
=head2 --iso8601
Use YYYY-MM-DD date format in output instead of Mmm DD YYYY
=head2 --locations, --no-locations
Whether or not to include locations in events
=head2 --lead-time
ical2rem.pl --lead-time 3
@@ -84,7 +100,7 @@ How may days in advance to start getting reminders about the events. Defaults to
ical2rem.pl --no-todos
If you don't care about the ToDos the calendar, this will suppress
If you don't care about the ToDos the calendar, this will surpress
printing of the ToDo heading, as well as skipping ToDo processing.
=head2 --heading
@@ -98,6 +114,7 @@ the calendar entries. See the file defs.rem from the remind distribution for mo
use strict;
use iCal::Parser;
use Date::Parse;
use DateTime;
use Getopt::Long 2.24 qw':config auto_help';
use Pod::Usage;
@@ -108,19 +125,31 @@ $VERSION = "0.5.2";
# Declare how many days in advance to remind
my $DEFAULT_LEAD_TIME = 3;
my $PROCESS_TODOS = 1;
my $HEADING = "";
my $HEADING = "";
my $help;
my $debug;
my $man;
my $iso8601;
my $do_location = 1;
my $do_end_times;
my $start;
my $end;
my $label = 'Calendar';
GetOptions (
"label=s" => \$label,
"start=s" => \$start,
"end=s" => \$end,
"lead-time=i" => \$DEFAULT_LEAD_TIME,
"todos!" => \$PROCESS_TODOS,
"iso8601!" => \$iso8601,
"locations!" => \$do_location,
"end-times!" => \$do_end_times,
"heading=s" => \$HEADING,
"help|?" => \$help,
"debug" => \$debug,
"man" => \$man
);
) or pod2usage(1);
pod2usage(1) if $help;
pod2usage(-verbose => 2) if $man;
@@ -136,8 +165,22 @@ while (<>) {
$in = "";
}
}
my $parser = iCal::Parser->new();
print STDERR "Read all calendars\n" if $debug;
my(%parser_opts) = ("debug" => $debug);
if ($start) {
my $t = str2time($start);
die "Invalid time $start\n" if (! $t);
$parser_opts{'start'} = DateTime->from_epoch(epoch => $t);
}
if ($end) {
my $t = str2time($end);
die "Invalid time $end\n" if (! $t);
$parser_opts{'end'} = DateTime->from_epoch(epoch => $t);
}
print STDERR "About to parse calendars\n" if $debug;
my $parser = iCal::Parser->new(%parser_opts);
my $hash = $parser->parse_strings(@calendars);
print STDERR "Calendars parsed\n" if $debug;
##############################################################
#
@@ -209,6 +252,13 @@ sub _process_todos {
#
######################################################################
# Issue 8 https://github.com/jbalcorn/ical2rem/issues/8
# Make sure there is a _sfun function declared in the reminder file. We'll just make it do nothing here.
print 'IF args("_sfun") < 1
FSET _sfun(x) choose(x,0)
ENDIF
';
print _process_todos($hash->{'todos'}) if $PROCESS_TODOS;
my ($leadtime, $yearkey, $monkey, $daykey,$uid,%eventsbyuid);
@@ -260,20 +310,67 @@ foreach $yearkey (sort keys %{$events} ) {
$leadtime = "+".$DEFAULT_LEAD_TIME;
}
my $start = $event->{'DTSTART'};
print "REM ".$start->month_abbr." ".$start->day." ".$start->year." $leadtime ";
if ($start->hour > 0) {
print " AT ";
print $start->strftime("%H:%M");
print " SCHED _sfun MSG %a %2 ";
} else {
print " MSG %a ";
my $end = $event->{'DTEND'};
my $duration = "";
if ($end and ($start->hour or $start->minute or $end->hour or $end->minute)) {
# We need both an HH:MM version of the delta, to put in the
# DURATION specifier, and a human-readable version of the
# delta, to put in the message if the user requested it.
my $seconds = $end->epoch - $start->epoch;
my $minutes = int($seconds / 60);
my $hours = int($minutes / 60);
$minutes -= $hours * 60;
$duration = sprintf("DURATION %d:%02d ", $hours, $minutes);
}
print "%\"$event->{'SUMMARY'}";
print " at $event->{'LOCATION'}" if $event->{'LOCATION'};
print "\%\"%\n";
print "REM ";
if ($iso8601) {
print $start->strftime("%F ");
} else {
print $start->month_abbr." ".$start->day." ".$start->year." ";
}
print "$leadtime ";
if ($duration or $start->hour > 0 or $start->minute > 0) {
print "AT ";
print $start->strftime("%H:%M");
print " SCHED _sfun ${duration}MSG %a %2 ";
} else {
print "MSG %a ";
}
print "%\"", &quote($event->{'SUMMARY'});
print(" at ", &quote($event->{'LOCATION'}))
if ($do_location and $event->{'LOCATION'});
print "\%\"";
if ($do_end_times and ($start->hour or $start->minute or
$end->hour or $end->minute)) {
my $start_date = $start->strftime("%F");
my $start_time = $start->strftime("%k:%M");
my $end_date = $end->strftime("%F");
my $end_time = $end->strftime("%k:%M");
# We don't want leading whitespace; some strftime's support
# disabling the pdding in the format string, but not all,
# so for maximum portability we do it ourselves.
$start_time =~ s/^\s+//;
$end_time =~ s/^\s+//;
my(@pieces);
if ($start_date ne $end_date) {
push(@pieces, $end_date);
}
if ($start_time ne $end_time) {
push(@pieces, $end_time);
}
print " (-", join(" ", @pieces), ")";
}
print "%\n";
}
}
}
}
sub quote {
local($_) = @_;
s/\[/["["]/g;
return $_;
}
exit 0;
#:vim set ft=perl ts=4 sts=4 expandtab :
+52 -48
View File
@@ -109,18 +109,15 @@
(defconst remind-keywords
(sort
(list "ADDOMIT" "AFTER" "AT" "BANNER" "BEFORE"
"CAL" "CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMPVARS"
"DURATION" "ELSE" "ENDIF" "ERRMSG" "EXIT" "FIRST"
"FLUSH" "FOURTH" "FROM" "FSET" "IF" "IFTRIG" "IN"
"INCLUDE" "INCLUDECMD" "LAST" "LASTDAY"
"LASTWORKDAY" "MAYBE-UNCOMPUTABLE" "MSF"
"MSG" "OMIT" "OMITFUNC" "ONCE"
"POP-OMIT-CONTEXT" "PRESERVE" "PRIORITY" "PS" "PSFILE"
"PUSH-OMIT-CONTEXT" "REM" "RUN" "SATISFY" "SCANFROM"
"SCHED" "SECOND" "SET" "SKIP" "SPECIAL"
"TAG" "THIRD" "THROUGH" "UNSET" "UNTIL"
"WARN")
(list "ADDOMIT" "AFTER" "AT" "BAN" "BANNER" "BEFORE" "CAL" "CLEAR"
"CLEAR-OMIT-CONTEXT" "DEBUG" "DO" "DUMP" "DUMPVARS" "DURATION" "ELSE"
"ENDIF" "ERRMSG" "EXIT" "EXPR" "FIRST" "FLUSH" "FOURTH" "FROM" "FSET"
"FUNSET" "IF" "IFTRIG" "IN" "INC" "INCLUDE" "INCLUDECMD" "LAST"
"LASTDAY" "LASTWORKDAY" "MAYBE" "MAYBE-UNCOMPUTABLE" "MSF" "MSG"
"NOQUEUE" "OMIT" "OMITFUNC" "ONCE" "POP" "POP-OMIT-CONTEXT" "PRESERVE"
"PRIORITY" "PS" "PSFILE" "PUSH" "PUSH-OMIT-CONTEXT" "REM" "RUN"
"SATISFY" "SCAN" "SCANFROM" "SCHED" "SECOND" "SET" "SKIP" "SPECIAL"
"TAG" "THIRD" "THROUGH" "UNSET" "UNTIL" "WARN")
#'(lambda (a b) (> (length a) (length b)))))
@@ -131,50 +128,57 @@
(defconst remind-builtin-variables
(sort
(list "$Ago" "$Am" "$And" "$April" "$At" "$August" "$CalcUTC" "$CalMode" "$Daemon" "$DateSep"
"$DateTimeSep" "$December" "$DefaultColor" "$DefaultPrio"
"$DefaultTDelta" "$DeltaOffset" "$DontFork" "$DontQueue"
"$DontTrigAts" "$EndSent" "$EndSentIg" "$February" "$FirstIndent"
"$FoldYear" "$FormWidth" "$Friday" "$Fromnow" "$Hour" "$Hplu" "$HushMode" "$IgnoreOnce"
"$InfDelta" "$IntMax" "$IntMin" "$Is" "$January" "$July" "$June" "$LatDeg"
"$Latitude" "$LatMin" "$LatSec" "$Location" "$LongDeg" "$Longitude"
"$LongMin" "$LongSec" "$March" "$MaxSatIter" "$MaxStringLen" "$May"
"$MinsFromUTC" "$Minute" "$Monday" "$Mplu" "$NextMode" "$November" "$Now" "$NumQueued"
"$NumTrig" "$October" "$On" "$Pm" "$PrefixLineNo" "$PSCal" "$RunOff" "$Saturday"
"$September" "$SimpleCal" "$SortByDate" "$SortByPrio" "$SortByTime"
"$SubsIndent" "$Sunday" "$SysInclude" "$T" "$Td" "$Thursday" "$TimeSep" "$Tm"
"$Today" "$Tomorrow" "$Tuesday" "$Tw" "$Ty" "$U" "$Ud" "$Um" "$UntimedFirst" "$Uw" "$Uy"
"$Was" "$Wednesday")
(list "$AddBlankLines" "$Ago" "$Am" "$And" "$April" "$At" "$August"
"$CalcUTC" "$CalMode" "$Daemon" "$DateSep" "$DateTimeSep" "$December"
"$DefaultColor" "$DefaultPrio" "$DefaultTDelta" "$DeltaOverride"
"$DontFork" "$DontQueue" "$DontTrigAts" "$EndSent" "$EndSentIg"
"$ExpressionTimeLimit" "$February" "$FirstIndent" "$FoldYear"
"$FormWidth" "$Friday" "$Fromnow" "$Hour" "$Hplu" "$HushMode"
"$IgnoreOnce" "$InfDelta" "$IntMax" "$IntMin" "$Is" "$January" "$July"
"$June" "$LatDeg" "$Latitude" "$LatMin" "$LatSec" "$Location"
"$LongDeg" "$Longitude" "$LongMin" "$LongSec" "$March" "$MaxFullOmits"
"$MaxLateMinutes" "$MaxPartialOmits" "$MaxSatIter" "$MaxStringLen"
"$May" "$MinsFromUTC" "$Minute" "$Monday" "$Mplu" "$NextMode"
"$November" "$Now" "$NumFullOmits" "$NumPartialOmits" "$NumQueued"
"$NumTrig" "$October" "$On" "$OnceFile" "$ParseUntriggered" "$Pm"
"$PrefixLineNo" "$PSCal" "$RunOff" "$Saturday" "$September"
"$SimpleCal" "$SortByDate" "$SortByPrio" "$SortByTime" "$SubsIndent"
"$Sunday" "$SuppressImplicitWarnings" "$SuppressLRM" "$SysInclude" "$T" "$Td"
"$TerminalBackground" "$Thursday" "$TimeSep" "$Tm" "$Today"
"$Tomorrow" "$Tt" "$Tuesday" "$Tw" "$Ty" "$U" "$Ud" "$Um"
"$UntimedFirst" "$Use256Colors" "$UseBGVTColors" "$UseTrueColors"
"$UseVTColors" "$Uw" "$Uy" "$Was" "$Wednesday")
#'(lambda (a b) (> (length a) (length b)))))
(defconst remind-time-words
(sort
(list "Jan" "January" "Feb" "Mar" "Apr" "Jun" "Jul" "Aug" "Sept" "Sep" "Oct" "Nov" "Dec"
"February" "March" "April" "May" "June" "July" "August" "September" "October"
"November" "December" "Mon" "Monday" "Tue" "Tues" "Tuesday" "Wed" "Wednesday"
"Thu" "Thursday" "Thurs" "Fri" "Friday" "Saturday" "Sat" "Sun" "Sunday")
(list "Apr" "April" "Aug" "August" "Dec" "December" "Feb" "February"
"Jan" "January" "Jul" "July" "Jun" "June" "Mar" "March" "May"
"Nov" "November" "Oct" "October" "Sep" "September" "Fri"
"Friday" "Mon" "Monday" "Sat" "Saturday" "Sun" "Sunday" "Thu"
"Thursday" "Tue" "Tuesday" "Wed" "Wednesday")
#'(lambda (a b) (> (length a) (length b)))))
(defconst remind-builtin-functions
(sort
(list "abs" "access" "adawn" "adusk" "ampm" "args" "asc" "baseyr" "char"
"choose" "coerce" "current" "date" "datepart" "datetime" "dawn" "day"
"daysinmon" "defined" "dosubst" "dusk" "easterdate" "evaltrig"
"filedate" "filedatetime" "filedir" "filename" "getenv" "hebdate"
"hebday" "hebmon" "hebyear" "hour" "iif" "index" "isany" "isdst"
"isleap" "isomitted" "language" "lower" "max" "min" "minsfromutc"
(list "abs" "access" "adawn" "adusk" "ampm" "ansicolor" "args" "asc"
"baseyr" "char" "choose" "coerce" "columns" "current" "date"
"datepart" "datetime" "dawn" "day" "daysinmon" "defined" "dosubst"
"dusk" "easterdate" "evaltrig" "filedate" "filedatetime" "filedir"
"filename" "getenv" "hebdate" "hebday" "hebmon" "hebyear" "hour"
"htmlescape" "htmlstriptags" "iif" "index" "isany" "isdst" "isleap"
"isomitted" "language" "localtoutc" "lower" "max" "min" "minsfromutc"
"minute" "mon" "monnum" "moondate" "moondatetime" "moonphase"
"moontime" "ndawn" "ndusk" "nonomitted" "now" "ord" "ostype" "pad" "plural"
"psmoon" "psshade" "realcurrent" "realnow" "realtoday" "sgn" "shell"
"shellescape" "slide" "strlen" "substr" "sunrise" "sunset" "time"
"timepart" "today" "trig" "trigback" "trigdate" "trigdatetime"
"trigdelta" "trigduration" "trigeventduration" "trigeventstart"
"trigfrom" "trigger" "trigpriority" "trigrep" "trigscanfrom"
"trigtime" "trigtimedelta" "trigtimerep" "triguntil" "trigvalid"
"typeof" "tzconvert" "upper" "value" "version" "weekno" "wkday"
"wkdaynum" "year")
"moontime" "multitrig" "ndawn" "ndusk" "nonomitted" "now" "ord"
"orthodoxeaster" "ostype" "pad" "plural" "psmoon" "psshade"
"realcurrent" "realnow" "realtoday" "rows" "sgn" "shell" "shellescape"
"slide" "soleq" "stdout" "strlen" "substr" "sunrise" "sunset" "time"
"timepart" "timezone" "today" "trig" "trigback" "trigdate"
"trigdatetime" "trigdelta" "trigduration" "trigeventduration"
"trigeventstart" "trigfrom" "trigger" "trigpriority" "trigrep"
"trigscanfrom" "trigtags" "trigtime" "trigtimedelta" "trigtimerep"
"triguntil" "trigvalid" "typeof" "tzconvert" "upper" "utctolocal"
"value" "version" "weekno" "wkday" "wkdaynum" "year")
#'(lambda (a b) (> (length a) (length b)))))
;;; faces
@@ -290,7 +294,7 @@
(defconst remind-conf-font-lock-keywords-1
(list
'("^[\;\#]\\s-+.*$" . remind-comment-face)
'("^\s*[\;\#].*$" . remind-comment-face)
'(remind-keywords-matcher . remind-conf-keyword-face)
'("%[\"_]" . font-lock-warning-face)
'("\\(%[a-mops-w]\\)" . remind-conf-substitutes-face)
+30
View File
@@ -1,5 +1,35 @@
CHANGES TO REMIND
* VERSION 5.0 Patch 5 - 2024-09-02
* CHANGE: remind: When using the "-c" option and with the SHADE special
enabled, shade the entire calendar box including the line containing the
day number.
* IMPROVEMENT: remind: Better error messages when diagnosing certain
errors in expressions.
* IMPROVEMENT: include/holidays/jewish.rem: Remove unnecessary _h()
function definition.
* BUG FIX: remind: In a couple of spots when we parsed a character, we did
not check for an error return. This has been fixed.
* BUG FIX: remind: Fix edge-case bugs in "remind -c" output formatting.
* BUG FIX: make test: Fix a test that was broken for all of September 2024.
* BUG FIX: remind: Fix a couple of potential file-descriptor leaks.
* BUG FIX: contrib/ical2rem.pl: Replace "SCHED _sfun" with "+15" to
hard-code 15-minutes advance warning rather than using an undefined
scheduling function. If this is not what you want, you should edit
ical2rem.pl to suit your taste; it's not officially part of Remind and
is meant more as a starting point for you to customize than a finished
product.
* DOCUMENTATION FIX: Remove obsolete info from Remind man page.
* VERSION 5.0 Patch 4 - 2024-08-29
* IMPROVEMENT: remind: When checking if a SATISFY expression refers to the
+1 -1
View File
@@ -32,7 +32,7 @@ RUN OFF
# Ensure required version of remind is used... #
################################################
IF version() < "03.04.02"
ERRMSG This file requires at least version 03.01.10 of Remind.%
ERRMSG This file requires at least version 03.04.02 of Remind.%
ERRMSG This version is version [version()].
EXIT
ENDIF
+29
View File
@@ -0,0 +1,29 @@
REM 1 Feb 2022 MSG Chinese New Year (Tiger)
REM 22 Jan 2023 MSG Chinese New Year (Rabbit)
REM 10 Feb 2024 MSG Chinese New Year (Dragon)
REM 29 Jan 2025 MSG Chinese New Year (Snake)
REM 17 Feb 2026 MSG Chinese New Year (Horse)
REM 6 Feb 2027 MSG Chinese New Year (Goat)
REM 26 Jan 2028 MSG Chinese New Year (Monkey)
REM 13 Feb 2029 MSG Chinese New Year (Rooster)
REM 3 Feb 2030 MSG Chinese New Year (Dog)
REM 23 Jan 2031 MSG Chinese New Year (Pig)
REM 11 Feb 2032 MSG Chinese New Year (Rat)
REM 31 Jan 2033 MSG Chinese New Year (Ox)
REM 19 Feb 2034 MSG Chinese New Year (Tiger)
REM 8 Feb 2035 MSG Chinese New Year (Rabbit)
REM 28 Jan 2036 MSG Chinese New Year (Dragon)
REM 15 Feb 2037 MSG Chinese New Year (Snake)
REM 4 Feb 2038 MSG Chinese New Year (Horse)
REM 24 Jan 2039 MSG Chinese New Year (Goat)
REM 12 Feb 2040 MSG Chinese New Year (Monkey)
REM 1 Feb 2041 MSG Chinese New Year (Rooster)
REM 22 Jan 2042 MSG Chinese New Year (Dog)
REM 10 Feb 2043 MSG Chinese New Year (Pig)
REM 30 Jan 2044 MSG Chinese New Year (Rat)
REM 17 Feb 2045 MSG Chinese New Year (Ox)
REM 6 Feb 2046 MSG Chinese New Year (Tiger)
REM 26 Jan 2047 MSG Chinese New Year (Rabbit)
REM 14 Feb 2048 MSG Chinese New Year (Dragon)
REM 2 Feb 2049 MSG Chinese New Year (Snake)
REM 23 Jan 2050 MSG Chinese New Year (Horse)
+22 -23
View File
@@ -10,7 +10,6 @@ SET InIsrael value("InIsrael", 0)
SET Reform value("Reform", 0)
# Convenient function definition to save typing
FSET _h(x, y) HEBDATE(x,y)
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)
@@ -19,28 +18,28 @@ FSET _BackTwoSat(x, y) IIF(WKDAYNUM(_h2(x,y))!=6, _h2(x,y), _h2(x,y)-2)
SET InIsrael VALUE("InIsrael", 0)
SET Reform VALUE("Reform", 0)
REM [_h(1, "Tishrey")] ++4 MSG %"Rosh Hashana 1%" is %b.
REM [hebdate(1, "Tishrey")] ++4 MSG %"Rosh Hashana 1%" is %b.
# No RH-2 or Tzom Gedalia in Reform
IF !Reform
REM [_h(2, "Tishrey")] ++4 MSG %"Rosh Hashana 2%" is %b.
REM [hebdate(2, "Tishrey")] ++4 MSG %"Rosh Hashana 2%" is %b.
REM [_PastSat(3, "Tishrey")] ++4 MSG %"Tzom Gedalia%" is %b.
ENDIF
REM [_h(10, "Tishrey")] ++4 MSG %"Yom Kippur%" is %b.
REM [_h(15, "Tishrey")] ++4 MSG %"Sukkot 1%" is %b.
REM [hebdate(10, "Tishrey")] ++4 MSG %"Yom Kippur%" is %b.
REM [hebdate(15, "Tishrey")] ++4 MSG %"Sukkot 1%" is %b.
IF !InIsrael
REM [_h(16, "Tishrey")] MSG %"Sukkot 2%"
REM [hebdate(16, "Tishrey")] MSG %"Sukkot 2%"
ENDIF
REM [_h(21, "Tishrey")] ++4 MSG %"Hoshana Rabba%" is %b.
REM [_h(22, "Tishrey")] ++4 MSG %"Shemini Atzeret%" is %b.
REM [hebdate(21, "Tishrey")] ++4 MSG %"Hoshana Rabba%" is %b.
REM [hebdate(22, "Tishrey")] ++4 MSG %"Shemini Atzeret%" is %b.
IF InIsrael
REM [_h(22, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
REM [hebdate(22, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
ELSE
REM [_h(23, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
REM [hebdate(23, "Tishrey")] ++4 MSG %"Simchat Torah%" is %b.
ENDIF
# Because Kislev can change length, we must be more careful about Chanukah
@@ -58,11 +57,11 @@ REM [_chan(8)] MSG %"Chanukah 8%"
IF !Reform
# 10 Tevet will never be a Saturday, so whether or not to
# move it is moot. (Thanks to Art Werschulz.)
REM [_h(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
REM [hebdate(10, "Tevet")] MSG %"Tzom Tevet%" is %b.
ENDIF
REM [_h(15, "Shvat")] ++4 MSG %"Tu B'Shvat%" is %b.
REM [_h(14, "Adar A")] ++4 MSG %"Purim Katan%" is %b.
REM [hebdate(15, "Shvat")] ++4 MSG %"Tu B'Shvat%" is %b.
REM [hebdate(14, "Adar A")] ++4 MSG %"Purim Katan%" is %b.
# If Purim is on Sunday, then Fast of Esther is 11 Adar.
IF WKDAYNUM(_h2(13, "Adar")) != 6
@@ -70,33 +69,33 @@ IF WKDAYNUM(_h2(13, "Adar")) != 6
ELSE
REM [_h2(11, "Adar")] ++4 MSG %"Fast of Esther%" is %b.
ENDIF
REM [_h(14, "Adar")] ++4 MSG %"Purim%" is %b.
REM [_h(15, "Nisan")] ++4 MSG %"Pesach%" is %b.
REM [hebdate(14, "Adar")] ++4 MSG %"Purim%" is %b.
REM [hebdate(15, "Nisan")] ++4 MSG %"Pesach%" is %b.
IF !InIsrael
REM [_h(16, "Nisan")] MSG %"Pesach 2%"
REM [hebdate(16, "Nisan")] MSG %"Pesach 2%"
ENDIF
REM [_h(21, "Nisan")] MSG %"Pesach 7%"
REM [hebdate(21, "Nisan")] MSG %"Pesach 7%"
IF !InIsrael && !Reform
REM [_h(22, "Nisan")] MSG %"Pesach 8%"
REM [hebdate(22, "Nisan")] MSG %"Pesach 8%"
ENDIF
REM [_h(27, "Nisan")] ++4 MSG %"Yom HaShoah%" is %b.
REM [hebdate(27, "Nisan")] ++4 MSG %"Yom HaShoah%" is %b.
REM [_BackTwoFri(4, "Iyar")] ++4 MSG %"Yom HaZikaron%" is %b.
REM [_BackTwoSat(5, "Iyar")] ++4 MSG %"Yom Ha'atzmaut%" is %b.
# Not sure about Reform's position on Lag B'Omer
IF !Reform
REM [_h(18, "Iyar")] ++4 MSG %"Lag B'Omer%" is %b.
REM [hebdate(18, "Iyar")] ++4 MSG %"Lag B'Omer%" is %b.
ENDIF
REM [_h(28, "Iyar")] ++4 MSG %"Yom Yerushalayim%" is %b.
REM [_h(6, "Sivan")] ++4 MSG %"Shavuot%" is %b.
REM [hebdate(28, "Iyar")] ++4 MSG %"Yom Yerushalayim%" is %b.
REM [hebdate(6, "Sivan")] ++4 MSG %"Shavuot%" is %b.
IF !InIsrael && !Reform
REM [_h(7, "Sivan")] MSG %"Shavuot 2%"
REM [hebdate(7, "Sivan")] MSG %"Shavuot 2%"
ENDIF
# Fairly sure Reform Jews don't observe the next two
+22 -9
View File
@@ -468,6 +468,14 @@ case-sensitive:
The \fB\-\-version\fR option causes \fBRemind\fR to print its version number
to standard output and then exit.
.TP
.B \-\-print-tokens
The \fB\-\-print-tokens\fR option causes \fBRemind\fR to print the tokens
used by the parser, built-in function names, and system variable names
to standard output and then exit. This output is designed to make it easy
to create a syntax-highlighting file for various text editors. The output
can be modified by hand or by a script into a syntax-highlighting file
with relative ease.
.TP
.B \-\-max-execution-time\fR=\fIn\fR
Limit the total execution time (as measured by the wall clock) to
\fIn\fR seconds. This is useful if \fBRemind\fR is invoked on
@@ -2181,6 +2189,11 @@ If the \fBTIME\fR is used where \fBRemind\fR expects a time-of-day
\fIpm\fR suffix and the hour can be as large as you want, so long
as the total number of minutes in the duration fits in a signed integer
variable.
.PP
For convenience, a \fBTIME\fR constant may be surrounded by single
quotes to match \fBDATE\fR and \fBDATETIME\fR constants, but these
quotes are optional. That is, 12:56 and '12:56' represent the same
\fBTIME\fR constant.
.RE
.TP
.B DATE constants
@@ -2812,8 +2825,15 @@ order, or 2 if sorting by time in descending order.
The number of spaces by which all lines (except the first) of an
\fBMSF\fR-type reminder should be indented. The default is 0.
.TP
.B $SuppressImplicitWarnings
Normally, \fBRemind\fR issues a warning if a line begins with an unknown
token and is treated as a \fBREM\fR command, or if a \fBREM\fR command
is missing a type and is treated as a \fBMSG\fR-type reminder. Setting
\fB$SuppressImplicitWarnings\fR to 1 suppresses these warnings. The default
is 0 and we do not recommend disabling the warnings.
.TP
.B $SuppressLRM
Normally, when Remind is run with the \fB\-c\fR option in a UTF-8 locale,
Normally, when \fBRemind\fR is run with the \fB\-c\fR option in a UTF-8 locale,
it emits a left-to-right mark sequence after printing day names or
reminders. Some terminals render this incorrectly, so you can use:
.RS
@@ -4706,10 +4726,7 @@ This is really useful only if \fIexpr\fR involves a call to the
\fIexpr\fR will not change as \fBRemind\fR iterates. In fact, if
\fIexpr\fR is not a constant and does not call \fBtrigdate()\fR or
related functions or system variables, then \fBRemind\fR will issue a
warning. If you have a user-defined function that calls
\fBtrigdate()\fR, this can result in an unwanted warning. In that
case, pass \fBtrigdate()\fR or some related function or system
variable into your user-defined function from the SATISFY expression.
warning.
.PP
An example of the usefulness of \fBSATISFY\fR: Suppose you wish to
be warned of every Friday the 13th. Your first attempt may be:
@@ -5840,10 +5857,6 @@ after the WEEK keyword.
The following tokens can be abbreviated:
.TP
o
\fBREM\fR can be omitted - it is implied if no other valid command
is present.
.TP
o
\fBCLEAR-OMIT-CONTEXT\fR --> \fBCLEAR\fR
.TP
o
+76 -30
View File
@@ -281,6 +281,7 @@ static void ColorizeEntry(CalEntry const *e, int clamp);
static void SortCol (CalEntry **col);
static void DoCalendarOneWeek (int nleft);
static void DoCalendarOneMonth (void);
static void DoSimpleCalendarOneMonth (void);
static int WriteCalendarRow (void);
static void WriteWeekHeaderLine (void);
static void WritePostHeaderLine (void);
@@ -338,6 +339,7 @@ UnBackgroundize(int d)
printf("%s", Decolorize());
}
#ifdef REM_USE_WCHAR
static void
send_lrm(void)
{
@@ -352,6 +354,7 @@ send_lrm(void)
printf("\xE2\x80\x8E");
}
}
#endif
static char const *
despace(char const *s)
@@ -526,9 +529,9 @@ get_month_abbrev(char const *mon)
#endif
}
#ifdef REM_USE_WCHAR
static int make_wchar_versions(CalEntry *e)
{
#ifdef REM_USE_WCHAR
size_t len;
wchar_t *buf;
len = mbstowcs(NULL, e->text, 0);
@@ -542,10 +545,8 @@ static int make_wchar_versions(CalEntry *e)
e->wc_text = buf;
e->wc_pos = buf;
return 1;
#else
return 1;
#endif
}
#endif
static void gon(void)
{
@@ -900,13 +901,17 @@ static void DoCalendarOneWeek(int nleft)
if (UseVTColors) {
printf("\x1B[1m"); /* Bold */
}
Backgroundize(d);
PrintLeft(buf, ColSpaces-1, '*');
putchar(' ');
UnBackgroundize(d);
if (UseVTColors) {
printf("\x1B[0m"); /* Normal */
}
putchar(' ');
} else {
Backgroundize(d);
PrintLeft(buf, ColSpaces, ' ');
UnBackgroundize(d);
}
gon();
DRAW(tb);
@@ -963,21 +968,20 @@ static void DoCalendarOneWeek(int nleft)
/***************************************************************/
/* */
/* DoCalendarOneMonth */
/* DoSimpleCalendarOneMonth */
/* */
/* Produce a calendar for the current month. */
/* Produce a "simple" calendar for the current month. */
/* */
/* A simple calendar is produced if the -s or -p option */
/* was used. */
/* */
/***************************************************************/
static void DoCalendarOneMonth(void)
static void DoSimpleCalendarOneMonth(void)
{
int y, m, d, mm, yy, i, j;
InitMoonsAndShades();
if (!DoSimpleCalendar) WriteCalHeader();
DidADay = 0;
if (PsCal) {
FromDSE(DSEToday, &y, &m, &d);
if (PsCal == PSCAL_LEVEL1) {
@@ -1050,7 +1054,29 @@ static void DoCalendarOneMonth(void)
}
printf("]\n}");
}
if (!DoSimpleCalendar) WriteCalTrailer();
}
/***************************************************************/
/* */
/* DoCalendarOneMonth */
/* */
/* Produce a calendar for the current month. */
/* */
/***************************************************************/
static void DoCalendarOneMonth(void)
{
InitMoonsAndShades();
if (DoSimpleCalendar) {
DoSimpleCalendarOneMonth();
return;
}
WriteCalHeader();
while (WriteCalendarRow()) /* continue */;
WriteCalTrailer();
}
/***************************************************************/
@@ -1122,13 +1148,17 @@ static int WriteCalendarRow(void)
if (UseVTColors) {
printf("\x1B[1m"); /* Bold */
}
Backgroundize(d+i-wd);
PrintLeft(buf, ColSpaces-1, '*');
putchar(' ');
if (UseVTColors) {
printf("\x1B[0m"); /* Normal */
}
putchar(' ');
UnBackgroundize(d+i-wd);
} else {
Backgroundize(d+i-wd);
PrintLeft(buf, ColSpaces, ' ');
UnBackgroundize(d+i-wd);
}
}
gon();
@@ -1196,15 +1226,17 @@ static void PrintLeft(char const *s, int width, char pad)
{
#ifndef REM_USE_WCHAR
int len = strlen(s);
printf("%s", s);
while (len++ < width) putchar(pad);
int i;
for (i=0; i<len && i<width; i++) {
fputc(*(s+i), stdout);
}
while (i++ < width) putchar(pad);
#else
size_t len = mbstowcs(NULL, s, 0);
int i;
wchar_t static_buf[128];
wchar_t *buf;
wchar_t *ws;
int display_len;
if (!len) {
for (i=0; i<width; i++) {
@@ -1223,13 +1255,16 @@ static void PrintLeft(char const *s, int width, char pad)
}
}
(void) mbstowcs(buf, s, len+1);
display_len = wcswidth(buf, len+1);
ws = buf;
for (i=0; i<width;) {
i=0;
while (i<width) {
if (*ws) {
if (i + wcwidth(*ws) > width) {
break;
}
i += wcwidth(*ws);
PutWideChar(*ws++, NULL);
i+= wcwidth(*ws);
} else {
break;
}
@@ -1242,7 +1277,10 @@ static void PrintLeft(char const *s, int width, char pad)
/* Possibly send lrm control sequence */
send_lrm();
for (i=display_len; i<width; i++) fputc(pad, stdout);
while (i<width) {
fputc(pad, stdout);
i++;
}
if (buf != static_buf) free(buf);
#endif
@@ -1263,7 +1301,7 @@ static void PrintCentered(char const *s, int width, char *pad)
int i;
for (i=0; i<d; i++) fputs(pad, stdout);
for (i=0; i<width; i++) {
for (i=0; i<width-d; i++) {
if (*s) {
if (isspace(*s)) {
putchar(' ');
@@ -1307,13 +1345,14 @@ static void PrintCentered(char const *s, int width, char *pad)
if (d < 0) d = 0;
ws = buf;
for (i=0; i<d; i++) fputs(pad, stdout);
for (i=0; i<width; i++) {
i=0;
while (i+d < width) {
if (*ws) {
PutWideChar(*ws++, NULL);
if (wcwidth(*ws) == 0) {
/* Don't count this character... it's zero-width */
i--;
if (i+d + wcwidth(*ws) > width) {
break;
}
i += wcwidth(*ws);
PutWideChar(*ws++, NULL);
} else {
break;
}
@@ -1325,7 +1364,10 @@ static void PrintCentered(char const *s, int width, char *pad)
/* Possibly send lrm control sequence */
send_lrm();
for (i=d+display_len; i<width; i++) fputs(pad, stdout);
while (i+d<width) {
fputs(pad, stdout);
i++;
}
if (buf != static_buf) free(buf);
#endif
}
@@ -1682,8 +1724,10 @@ static void GenerateCalEntries(int col)
/* need to destroy it here. */
default:
Wprint("Unrecognized command; interpreting as REM");
WarnedAboutImplicit = 1;
if (!SuppressImplicitRemWarnings) {
Wprint("Unrecognized command; interpreting as REM");
WarnedAboutImplicit = 1;
}
CreateParser(CurLine, &p);
r=DoCalRem(&p, col);
break;
@@ -2143,7 +2187,9 @@ static int DoCalRem(ParsePtr p, int col)
FreeTrig(&trig);
return E_NO_MEM;
}
#ifdef REM_USE_WCHAR
make_wchar_versions(e);
#endif
DBufInit(&(e->tags));
DBufPuts(&(e->tags), DBufValue(&(trig.tags)));
if (SynthesizeTags) {
+39 -6
View File
@@ -208,7 +208,7 @@ int DoRem(ParsePtr p)
DBufInit(&buf);
/* Parse the trigger date and time */
if ( (r=ParseRem(p, &trig, &tim)) ) {
if ( (r=ParseRem(p, &trig, &tim)) != OK ) {
FreeTrig(&trig);
return r;
}
@@ -437,10 +437,17 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
break;
case T_Date:
DBufFree(&buf);
if (trig->d != NO_DAY) return E_DAY_TWICE;
if (trig->m != NO_MON) return E_MON_TWICE;
if (trig->y != NO_YR) return E_YR_TWICE;
DBufFree(&buf);
if (trig->d != NO_DAY) {
return E_DAY_TWICE;
}
if (trig->m != NO_MON) {
return E_MON_TWICE;
}
if (trig->y != NO_YR) {
return E_YR_TWICE;
}
FromDSE(tok.val, &y, &m, &d);
trig->y = y;
trig->m = m;
@@ -542,6 +549,12 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
if (r) return r;
break;
case T_Number:
DBufFree(&buf);
Eprint("`%d' is not recognized as a year (%d-%d) or a day number (1-31)",
tok.val, BASE, BASE+YR_RANGE);
return E_PARSE_ERR;
case T_Year:
DBufFree(&buf);
if (trig->y != NO_YR) return E_YR_TWICE;
@@ -682,11 +695,16 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim)
break;
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
PushToken(DBufValue(&buf), s);
DBufFree(&buf);
trig->typ = MSG_TYPE;
if (s->isnested) return E_CANT_NEST_RTYPE;
if (!WarnedAboutImplicit) {
if (!WarnedAboutImplicit && !SuppressImplicitRemWarnings) {
Wprint("Missing REM type; assuming MSG");
WarnedAboutImplicit = 1;
}
@@ -787,6 +805,11 @@ static int ParseTimeTrig(ParsePtr s, TimeTrig *tim)
break;
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
if (tim->ttime == NO_TIME) return E_EXPECT_TIME;
PushToken(DBufValue(&buf), s);
@@ -904,6 +927,11 @@ static int ParseUntil(ParsePtr s, Trigger *t, int type)
break;
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
Eprint("%s: %s", which, ErrMsg[E_INCOMPLETE]);
DBufFree(&buf);
@@ -1023,6 +1051,11 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
break;
default:
if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
DBufFree(&buf);
return -tok.val;
}
if (y == NO_YR || m == NO_MON || d == NO_DAY) {
Eprint("%s: %s", word, ErrMsg[E_INCOMPLETE]);
DBufFree(&buf);
-1
View File
@@ -152,7 +152,6 @@ int DBufGets(DynamicBuffer *dbuf, FILE *fp)
/* Try reading the first few bytes right into the buffer --
we can usually save some unnecessary copying */
*(dbuf->buffer) = 0;
if (fgets(dbuf->buffer, dbuf->allocatedLen, fp) == NULL) {
return OK;
}
+75 -36
View File
@@ -685,16 +685,12 @@ eval_userfunc(expr_node *node, Value *locals, Value *ans, int *nonconst)
/* Add a call to the call stack for better error messages */
pushed = push_call(f->filename, f->name, f->lineno);
if (DebugFlag & DB_PRTEXPR) {
debug_enter_userfunc(node, new_locals, f->nargs);
}
DBG(debug_enter_userfunc(node, new_locals, f->nargs));
/* Evaluate the function's expr_node tree */
r = evaluate_expr_node(f->node, new_locals, ans, nonconst);
if (DebugFlag & DB_PRTEXPR) {
debug_exit_userfunc(node, ans, r, new_locals, f->nargs);
}
DBG(debug_exit_userfunc(node, ans, r, new_locals, f->nargs));
if (r != OK) {
/* We print the error here in order to get the call stack trace */
@@ -1506,18 +1502,7 @@ static int logical_and(expr_node *node, Value *locals, Value *ans, int *nonconst
/* Read a token. */
/* */
/***************************************************************/
static int parse_expr_token_aux(DynamicBuffer *buf, char const **in);
static int parse_expr_token(DynamicBuffer *buf, char const **in)
{
int r = parse_expr_token_aux(buf, in);
/* Munch any following whitespace */
while (**in && isempty(**in)) (*in)++;
return r;
}
static int parse_expr_token_aux(DynamicBuffer *buf, char const **in)
{
char c;
@@ -1555,9 +1540,11 @@ static int parse_expr_token_aux(DynamicBuffer *buf, char const **in)
return E_NO_MEM;
}
(*in)++;
}
return OK;
} else {
Eprint("%s `%c' (did you mean `%c%c'?)", ErrMsg[E_PARSE_ERR], c, c, c);
return E_PARSE_ERR;
}
return OK;
case '!':
case '>':
case '<':
@@ -1698,7 +1685,7 @@ static int parse_expr_token_aux(DynamicBuffer *buf, char const **in)
/***************************************************************/
static int peek_expr_token(DynamicBuffer *buf, char const *in)
{
return parse_expr_token_aux(buf, &in);
return parse_expr_token(buf, &in);
}
/***************************************************************/
@@ -1778,6 +1765,7 @@ static expr_node * parse_function_call(char const **e, int *r, Var *locals, int
expr_node *node;
expr_node *arg;
char *s;
char const *ptr;
CHECK_PARSE_LEVEL();
node = alloc_expr_node(r);
@@ -1850,6 +1838,7 @@ static expr_node * parse_function_call(char const **e, int *r, Var *locals, int
}
}
if (TOKEN_IS(")")) {
ptr = *e;
*r = GET_TOKEN();
if (*r != OK) {
return free_expr_tree(node);
@@ -1858,8 +1847,14 @@ static expr_node * parse_function_call(char const **e, int *r, Var *locals, int
/* Check args for builtin funcs */
if (node->type == N_BUILTIN_FUNC) {
f = node->u.builtin_func;
if (node->num_kids < f->minargs) *r = E_2FEW_ARGS;
if (node->num_kids > f->maxargs && f->maxargs != NO_MAX) *r = E_2MANY_ARGS;
if (node->num_kids < f->minargs) {
*e = ptr;
*r = E_2FEW_ARGS;
}
if (node->num_kids > f->maxargs && f->maxargs != NO_MAX) {
*e = ptr;
*r = E_2MANY_ARGS;
}
}
if (*r != OK) {
if (node->type == N_BUILTIN_FUNC) {
@@ -1909,11 +1904,25 @@ static int set_constant_value(expr_node *atom)
return OK;
} else if (*s == '\'') { /* It's a literal date */
s++;
if ((r=ParseLiteralDate(&s, &dse, &tim)) != 0) return r;
if (*s != '\'') return E_BAD_DATE;
if ((r=ParseLiteralDateOrTime(&s, &dse, &tim)) != 0) {
Eprint("%s: %s", ErrMsg[r], DBufValue(&ExprBuf));
return r;
}
if (*s != '\'') {
if (dse != NO_DATE) {
Eprint("%s: %s", ErrMsg[E_BAD_DATE], DBufValue(&ExprBuf));
return E_BAD_DATE;
} else {
Eprint("%s: %s", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
return E_BAD_TIME;
}
}
if (tim == NO_TIME) {
atom->u.value.type = DATE_TYPE;
atom->u.value.v.val = dse;
} else if (dse == NO_DATE) {
atom->u.value.type = TIME_TYPE;
atom->u.value.v.val = tim;
} else {
atom->u.value.type = DATETIME_TYPE;
atom->u.value.v.val = (dse * MINUTES_PER_DAY) + tim;
@@ -1934,7 +1943,10 @@ static int set_constant_value(expr_node *atom)
}
if (*s == ':' || *s == '.' || *s == TimeSep) { /* Must be a literal time */
s++;
if (!isdigit(*s)) return E_BAD_TIME;
if (!isdigit(*s)) {
Eprint("%s: `%s'", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
return E_BAD_TIME;
}
h = val;
m = 0;
while (isdigit(*s)) {
@@ -1950,9 +1962,15 @@ static int set_constant_value(expr_node *atom)
s++;
}
}
if (*s || h>23 || m>59) return E_BAD_TIME;
if (*s || h>23 || m>59) {
Eprint("%s: `%s'", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
return E_BAD_TIME;
}
if (ampm) {
if (h < 1 || h > 12) return E_BAD_TIME;
if (h < 1 || h > 12) {
Eprint("%s: `%s'", ErrMsg[E_BAD_TIME], DBufValue(&ExprBuf));
return E_BAD_TIME;
}
if (ampm == 'a') {
if (h == 12) {
h = 0;
@@ -1968,7 +1986,10 @@ static int set_constant_value(expr_node *atom)
return OK;
}
/* Not a time - must be a number */
if (*s) return E_BAD_NUMBER;
if (*s) {
Eprint("%s: `%s'", ErrMsg[E_BAD_NUMBER], DBufValue(&ExprBuf));
return E_BAD_NUMBER;
}
atom->u.value.type = INT_TYPE;
atom->u.value.v.val = val;
return OK;
@@ -2016,7 +2037,7 @@ static int make_atom(expr_node *atom, Var *locals)
/* System Variable */
if (*(s) == '$' && isalpha(*(s+1))) {
if (!FindSysVar(s+1)) {
Eprint("`%s': %s", s, ErrMsg[E_NOSUCH_VAR]);
Eprint("%s: `%s'", ErrMsg[E_NOSUCH_VAR], s);
return E_NOSUCH_VAR;
}
if (strlen(s+1) < SHORT_NAME_BUF) {
@@ -2502,15 +2523,23 @@ expr_node *parse_expression(char const **e, int *r, Var *locals)
}
}
if (*r == E_EXPECT_COMMA ||
*r == E_PARSE_ERR ||
*r == E_MISS_RIGHT_PAREN ||
*r == E_EXPECTING_EOL ||
*r == E_2MANY_ARGS ||
*r == E_2FEW_ARGS ||
*r == E_PARSE_ERR ||
*r == E_EOLN ||
*r == E_ILLEGAL_CHAR) {
orig = o2;
while (*orig) {
fprintf(ErrFp, "%c", *orig++);
if (*orig == '\n') {
fprintf(ErrFp, " ");
orig++;
} else if (*orig == ']' && ! *(orig+1)) {
break;
} else {
fprintf(ErrFp, "%c", *orig++);
}
}
fprintf(ErrFp, "\n");
orig = o2;
@@ -2843,25 +2872,32 @@ int ParseLiteralTime(char const **s, int *tim)
/***************************************************************/
/* */
/* ParseLiteralDate */
/* ParseLiteralDateOrTime */
/* */
/* Parse a literal date or datetime. Return result in dse */
/* and tim; update s. */
/* */
/***************************************************************/
int ParseLiteralDate(char const **s, int *dse, int *tim)
int ParseLiteralDateOrTime(char const **s, int *dse, int *tim)
{
int y, m, d;
int r;
char const *orig_s = *s;
y=0; m=0; d=0;
*tim = NO_TIME;
*dse = NO_DATE;
if (!isdigit(**s)) return E_BAD_DATE;
while (isdigit(**s)) {
y *= 10;
y += *(*s)++ - '0';
}
if (**s == ':' || **s == '.' || **s == TimeSep) {
*s = orig_s;
return ParseLiteralTime(s, tim);
}
if (**s != '/' && **s != '-' && **s != DateSep) return E_BAD_DATE;
(*s)++;
if (!isdigit(**s)) return E_BAD_DATE;
@@ -2917,7 +2953,8 @@ int DoCoerce(char type, Value *v)
return OK;
case STR_TYPE:
s = v->v.str;
if (ParseLiteralDate(&s, &i, &m)) return E_CANT_COERCE;
if (ParseLiteralDateOrTime(&s, &i, &m)) return E_CANT_COERCE;
if (i == NO_DATE) return E_CANT_COERCE;
if (*s) return E_CANT_COERCE;
v->type = DATETIME_TYPE;
free(v->v.str);
@@ -2999,7 +3036,8 @@ int DoCoerce(char type, Value *v)
case STR_TYPE:
s = v->v.str;
if (ParseLiteralDate(&s, &i, &m)) return E_CANT_COERCE;
if (ParseLiteralDateOrTime(&s, &i, &m)) return E_CANT_COERCE;
if (i == NO_DATE) return E_CANT_COERCE;
if (*s) return E_CANT_COERCE;
v->type = DATE_TYPE;
free(v->v.str);
@@ -3025,6 +3063,7 @@ int DoCoerce(char type, Value *v)
case STR_TYPE:
s = v->v.str;
i=0; /* Avoid compiler warning */
if (ParseLiteralTime(&s, &i)) return E_CANT_COERCE;
if (*s) return E_CANT_COERCE;
v->type = TIME_TYPE;
+10
View File
@@ -4005,3 +4005,13 @@ BuiltinFunc *FindBuiltinFunc(char const *name)
}
return NULL;
}
void
print_builtinfunc_tokens(void)
{
int i;
printf("\n# Built-in Functions\n\n");
for (i=0; i<NumFuncs; i++) {
printf("%s\n", Func[i].name);
}
}
+3
View File
@@ -171,6 +171,9 @@ EXTERN DynamicBuffer ExprBuf;
/* User-func recursion level */
EXTERN INIT( unsigned int FuncRecursionLevel, 0);
/* Suppress warnings about implicit REM and MSG */
EXTERN INIT( int SuppressImplicitRemWarnings, 0);
extern int NumFullOmits, NumPartialOmits;
/* List of months */
+13
View File
@@ -717,6 +717,10 @@ void InitRemind(int argc, char const *argv[])
break;
default:
if (tok.type == T_Illegal && tok.val < 0) {
fprintf(stderr, "%s: `%s'\n", ErrMsg[-tok.val], arg);
Usage();
}
Usage();
}
}
@@ -1067,6 +1071,12 @@ ProcessLongOption(char const *arg)
printf("%s\n", VERSION);
exit(EXIT_SUCCESS);
}
if (!strcmp(arg, "print-tokens")) {
print_remind_tokens();
print_builtinfunc_tokens();
print_sysvar_tokens();
exit(0);
}
if (sscanf(arg, "max-execution-time=%d", &t) == 1) {
if (t < 0) {
fprintf(ErrFp, "%s: --max-execution-time must be non-negative\n", ArgV[0]);
@@ -1119,6 +1129,8 @@ guess_terminal_background(int *r, int *g, int *b)
if (n != 8) {
/* write failed... WTF? Not much we can do */
tty_reset(ttyfd);
close(ttyfd);
return;
}
@@ -1142,6 +1154,7 @@ guess_terminal_background(int *r, int *g, int *b)
return;
}
tty_reset(ttyfd);
close(ttyfd);
buf[n+1] = 0;
if (n < 25) {
/* Too short */
+4 -2
View File
@@ -356,8 +356,10 @@ static void DoReminders(void)
/* If we don't recognize the command, do a REM by default, but warn */
default:
Wprint("Unrecognized command; interpreting as REM");
WarnedAboutImplicit = 1;
if (!SuppressImplicitRemWarnings) {
Wprint("Unrecognized command; interpreting as REM");
WarnedAboutImplicit = 1;
}
DestroyParser(&p);
CreateParser(CurLine, &p);
purge_handled = 1;
+1 -1
View File
@@ -129,7 +129,7 @@ static double phase (double, double *, double *, double *, double *, double *, d
/* */
/* jdate */
/* */
/* Convert a date and time to DSE day and fraction. */
/* Convert a date and time to Julian day and fraction. */
/* */
/***************************************************************/
static long jdate(int y, int mon, int day)
+5 -1
View File
@@ -145,7 +145,9 @@ int PushOmitContext(ParsePtr p)
context->partsave = malloc(NumPartialOmits * sizeof(int));
if (NumPartialOmits && !context->partsave) {
free(context->filename);
free(context->fullsave);
if (context->fullsave) {
free(context->fullsave);
}
free(context);
return E_NO_MEM;
}
@@ -399,6 +401,8 @@ int DoOmit(ParsePtr p)
default:
if (tok.type == T_Until) {
Eprint("OMIT: UNTIL not allowed; did you mean THROUGH?");
} else if (tok.type == T_Illegal && tok.val < 0) {
Eprint("%s: `%s'", ErrMsg[-tok.val], DBufValue(&buf));
} else {
Eprint("%s: `%s' (OMIT)", ErrMsg[E_UNKNOWN_TOKEN],
DBufValue(&buf));
+6 -1
View File
@@ -55,7 +55,7 @@ int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queu
int ShouldTriggerReminder (Trigger *t, TimeTrig *tim, int dse, int *err);
int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse, int mode);
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int dse, int tim);
int ParseLiteralDate (char const **s, int *dse, int *tim);
int ParseLiteralDateOrTime (char const **s, int *dse, int *tim);
int ParseLiteralTime (char const **s, int *tim);
expr_node *parse_expression(char const **e, int *r, Var *locals);
@@ -242,3 +242,8 @@ void PutWideChar(wchar_t const wc, DynamicBuffer *output);
extern int _private_mul_overflow(int a, int b);
extern int _private_add_overflow(int a, int b);
extern int _private_sub_overflow(int a, int b);
/* Utility functions for dumping tokens */
void print_sysvar_tokens(void);
void print_builtinfunc_tokens(void);
void print_remind_tokens(void);
+137 -28
View File
@@ -39,19 +39,19 @@ while (isdigit(*(string))) { \
Token TokArray[] = {
/* NAME MINLEN TYPE VALUE */
{ "addomit", 7, T_AddOmit, 0 },
{ "after", 3, T_Skip, AFTER_SKIP },
{ "after", 5, T_Skip, AFTER_SKIP },
{ "april", 3, T_Month, 3 },
{ "at", 2, T_At, 0 },
{ "august", 3, T_Month, 7 },
{ "banner", 3, T_Banner, 0 },
{ "before", 3, T_Skip, BEFORE_SKIP },
{ "before", 6, T_Skip, BEFORE_SKIP },
{ "cal", 3, T_RemType, CAL_TYPE },
{ "clear-omit-context", 5, T_Clr, 0 },
{ "debug", 5, T_Debug, 0 },
{ "december", 3, T_Month, 11 },
{ "do", 2, T_IncludeR, 0 },
{ "dumpvars", 4, T_Dumpvars, 0 },
{ "duration", 3, T_Duration, 0 },
{ "duration", 8, T_Duration, 0 },
{ "else", 4, T_Else, 0 },
{ "endif", 5, T_EndIf, 0 },
{ "errmsg", 6, T_ErrMsg, 0 },
@@ -85,9 +85,9 @@ Token TokArray[] = {
{ "noqueue", 7, T_NoQueue, 0 },
{ "november", 3, T_Month, 10 },
{ "october", 3, T_Month, 9 },
{ "omit", 3, T_Omit, 0 },
{ "omit", 4, T_Omit, 0 },
{ "omitfunc", 8, T_OmitFunc, 0 },
{ "once", 3, T_Once, 0 },
{ "once", 4, T_Once, 0 },
{ "pop-omit-context", 3, T_Pop, 0 },
{ "preserve", 8, T_Preserve, 0 },
{ "priority", 8, T_Priority, 0 },
@@ -103,7 +103,7 @@ Token TokArray[] = {
{ "second", 6, T_Ordinal, 1 },
{ "september", 3, T_Month, 8 },
{ "set", 3, T_Set, 0 },
{ "skip", 3, T_Skip, SKIP_SKIP },
{ "skip", 4, T_Skip, SKIP_SKIP },
{ "special", 7, T_RemType, PASSTHRU_TYPE },
{ "sunday", 3, T_WkDay, 6 },
{ "tag", 3, T_Tag, 0 },
@@ -112,13 +112,28 @@ Token TokArray[] = {
{ "thursday", 3, T_WkDay, 3 },
{ "tuesday", 3, T_WkDay, 1 },
{ "unset", 5, T_UnSet, 0 },
{ "until", 3, T_Until, 0 },
{ "until", 5, T_Until, 0 },
{ "warn", 4, T_Warn, 0 },
{ "wednesday", 3, T_WkDay, 2 }
};
static int TokStrCmp (Token const *t, char const *s);
static void
init_token(Token *t)
{
t->name = NULL;
t->type = T_Illegal;
t->val = 0;
}
static void
token_error(Token *t, int errcode)
{
t->type = T_Illegal;
t->val = -errcode;
}
/***************************************************************/
/* */
/* FindInitialToken */
@@ -132,7 +147,7 @@ char const *FindInitialToken(Token *tok, char const *s)
DynamicBuffer buf;
DBufInit(&buf);
tok->type = T_Illegal;
init_token(tok);
while (isempty(*s)) s++;
@@ -159,7 +174,7 @@ void FindToken(char const *s, Token *tok)
int top, bot, mid, r, max;
int l;
tok->type = T_Illegal;
init_token(tok);
if (! *s) {
tok->type = T_Empty;
return;
@@ -233,9 +248,9 @@ void FindNumericToken(char const *s, Token *t)
int mult = 1, hour, min;
char const *s_orig = s;
int ampm = 0;
int r;
t->type = T_Illegal;
t->val = 0;
init_token(t);
if (isdigit(*s)) {
PARSENUM(t->val, s);
@@ -243,22 +258,37 @@ void FindNumericToken(char const *s, Token *t)
if (*s == '-' || *s == '/') {
char const *p = s_orig;
int dse, tim;
if (ParseLiteralDate(&p, &dse, &tim) == OK) {
if (*p) return;
r = ParseLiteralDateOrTime(&p, &dse, &tim);
if (r == OK) {
if (*p) {
if (tim == NO_TIME) {
t->val = -E_BAD_DATE;
} else {
t->val = -E_BAD_TIME;
}
return;
}
if (tim == NO_TIME) {
t->type = T_Date;
t->val = dse;
return;
}
if (dse == NO_DATE) {
t->type = T_Time;
t->val = tim;
return;
}
t->type = T_DateTime;
t->val = MINUTES_PER_DAY * dse + tim;
}
} else {
token_error(t, r);
}
return;
}
/* If we hit a comma, swallow it. This allows stuff
like Jan 6, 1998 */
if (*s == ',') {
if (*s == ',' && *(s+1) == 0) {
/* Classify the number we've got */
if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
else if (t->val >= 1 && t->val <= 31) t->type = T_Day;
@@ -269,8 +299,16 @@ void FindNumericToken(char const *s, Token *t)
if (*s == ':' || *s == '.' || *s == TimeSep) {
s++;
hour = t->val;
if (!isdigit(*s)) {
token_error(t, E_BAD_TIME);
return;
}
PARSENUM(min, s);
if (min > 59) return; /* Illegal time */
if (min > 59) {
/* Illegal time */
token_error(t, E_BAD_TIME);
return;
}
/* Check for p[m] or a[m] */
if (*s == 'A' || *s == 'a' || *s == 'P' || *s == 'p') {
ampm = tolower(*s);
@@ -279,9 +317,15 @@ void FindNumericToken(char const *s, Token *t)
s++;
}
}
if (*s) return; /* Illegal time */
if (*s) {
token_error(t, E_BAD_TIME);
return;
}
if (ampm) {
if (hour < 1 || hour > 12) return;
if (hour < 1 || hour > 12) {
token_error(t, E_BAD_TIME);
return;
}
if (ampm == 'a') {
if (hour == 12) {
hour = 0;
@@ -303,45 +347,70 @@ void FindNumericToken(char const *s, Token *t)
}
/* If we hit a non-digit, error! */
if (*s) return;
if (*s) {
token_error(t, E_BAD_NUMBER);
return;
}
/* Classify the number we've got */
if (t->val >= BASE && t->val <= BASE+YR_RANGE) t->type = T_Year;
else if (t->val >= 1 && t->val <= 31) t->type = T_Day;
else t->type = T_Number;
return;
} else if (*s == '*') {
}
switch (*s) {
case '*':
s++;
PARSENUM(t->val, s);
if (*s) return; /* Illegal token if followed by non-numeric char */
if (*s) {
/* Illegal token if followed by non-numeric char */
token_error(t, E_BAD_NUMBER);
return;
}
t->type = T_Rep;
return;
} else if (*s == '+') {
case '+':
s++;
if (*s == '+') { mult = -1; s++; }
PARSENUM(t->val, s);
if (*s) return; /* Illegal token if followed by non-numeric char */
if (*s) {
/* Illegal token if followed by non-numeric char */
token_error(t, E_BAD_NUMBER);
return;
}
t->type = T_Delta;
t->val *= mult;
return;
} else if (*s == '-') {
case '-':
s++;
if (*s == '-') { mult = -1; s++; }
PARSENUM(t->val, s);
if (*s) return; /* Illegal token if followed by non-numeric char */
if (*s) {
/* Illegal token if followed by non-numeric char */
token_error(t, E_BAD_NUMBER);
return;
}
t->type = T_Back;
t->val *= mult;
return;
} else if (*s == '~') {
case '~':
s++;
if (*s == '~') { mult = -1; s++; }
PARSENUM(t->val, s);
if (*s) return; /* Illegal token if followed by non-numeric char */
if (*s) {
/* Illegal token if followed by non-numeric char */
token_error(t, E_BAD_NUMBER);
return;
}
t->type = T_BackAdj;
t->val *= mult;
return;
default: return;
}
return; /* Unknown token type */
}
@@ -368,3 +437,43 @@ static int TokStrCmp(Token const *t, char const *s)
if (!*s || (*s == ',' && !*(s+1))) return 0;
return (*tk - tolower(*s));
}
static void
print_token(Token *tok)
{
if (tok->MinLen < (int) strlen(tok->name)) {
printf("%.*s\n", tok->MinLen, tok->name);
}
printf("%s\n", tok->name);
}
void
print_remind_tokens(void)
{
int i;
Token *tok;
int num = (int) (sizeof(TokArray) / sizeof(TokArray[0]));
printf("# Remind Tokens\n\n");
for (i=0; i<num; i++) {
tok = &TokArray[i];
if (tok->type != T_Month && tok->type != T_WkDay) {
print_token(tok);
}
}
printf("\n# Month Names\n\n");
for (i=0; i<num; i++) {
tok = &TokArray[i];
if (tok->type == T_Month) {
print_token(tok);
}
}
printf("\n# Weekdays\n\n");
for (i=0; i<num; i++) {
tok = &TokArray[i];
if (tok->type == T_WkDay) {
print_token(tok);
}
}
}
+11 -1
View File
@@ -207,6 +207,11 @@ int DoFset(ParsePtr p)
local_array[i+1].next = NULL;
func->nargs++;
c = ParseNonSpaceChar(p, &r, 0);
if (r) {
DBufFree(&buf);
DestroyUserFunc(func);
return r;
}
if (c == ')') break;
else if (c != ',') {
DestroyUserFunc(func);
@@ -217,6 +222,10 @@ int DoFset(ParsePtr p)
/* Allow an optional = sign: FSET f(x) = x*x */
c = ParseNonSpaceChar(p, &r, 1);
if (r) {
DestroyUserFunc(func);
return r;
}
if (c == '=') {
(void) ParseNonSpaceChar(p, &r, 0);
}
@@ -241,8 +250,9 @@ int DoFset(ParsePtr p)
}
c = ParseNonSpaceChar(p, &r, 1);
if (c != 0) {
if (c != 0 || r != 0) {
DestroyUserFunc(func);
if (r != 0) return r;
return E_EXPECTING_EOL;
}
+17 -4
View File
@@ -572,7 +572,7 @@ int GetVarValue(char const *str, Value *val)
v=FindVar(str, 0);
if (!v) {
Eprint("%s: %s", ErrMsg[E_NOSUCH_VAR], str);
Eprint("%s: `%s'", ErrMsg[E_NOSUCH_VAR], str);
return E_NOSUCH_VAR;
}
return CopyValue(val, &v->v);
@@ -587,7 +587,7 @@ int DoSet (Parser *p)
{
Value v;
int r;
int ch;
DynamicBuffer buf;
DynamicBuffer buf2;
DBufInit(&buf);
@@ -597,8 +597,11 @@ int DoSet (Parser *p)
if (r) return r;
/* Allow optional equals-sign: SET var = value */
if (ParseNonSpaceChar(p, &r, 1) == '=') {
ch = ParseNonSpaceChar(p, &r, 1);
if (r) return r;
if (ch == '=') {
ParseNonSpaceChar(p, &r, 0);
if (r) return r;
}
if (p->isnested) {
@@ -931,6 +934,7 @@ static SysVar SysVarArr[] = {
{"SortByTime", 0, INT_TYPE, &SortByTime, 0, 0 },
{"SubsIndent", 1, INT_TYPE, &SubsIndent, 0, 132 },
{"Sunday", 1, STR_TYPE, &DynamicDayName[6], 0, 0 },
{"SuppressImplicitWarnings", 1, INT_TYPE, &SuppressImplicitRemWarnings, 0, 1},
{"SuppressLRM", 1, INT_TYPE, &SuppressLRM, 0, 1 },
{"SysInclude", 0, STR_TYPE, &SysDir, 0, 0 },
{"T", 0, SPECIAL_TYPE, trig_date_func, 0, 0 },
@@ -1116,7 +1120,7 @@ static void DumpSysVar(char const *name, const SysVar *v)
return;
}
if (name) strcat(buffer, name); else strcat(buffer, v->name);
fprintf(ErrFp, "%16s ", buffer);
fprintf(ErrFp, "%25s ", buffer);
if (v) {
if (v->type == CONST_INT_TYPE) {
fprintf(ErrFp, "%d\n", v->constval);
@@ -1195,3 +1199,12 @@ set_components_from_lat_and_long(void)
}
}
void
print_sysvar_tokens(void)
{
int i;
printf("\n# System Variables\n\n");
for (i=0; i< (int) NUMSYSVARS; i++) {
printf("$%s\n", SysVarArr[i].name);
}
}
+4 -1
View File
@@ -584,7 +584,7 @@ tail +2 ../tests/once.timestamp >> ../tests/test.out 2>&1
rm -f ../tests/once.timestamp
# Newlines in calendar output
(echo 'REM 16 MSG foo%_bar%_baz wookie quux apple %_ %_ %_ blech'; echo "REM 16 MSG ANOTHER") | ../src/remind -c -w80 - 1 sep 2024 >> ../tests/test.out 2>&1
(echo 'REM 16 MSG foo%_bar%_baz wookie quux apple %_ %_ %_ blech'; echo "REM 16 MSG ANOTHER") | ../src/remind -c -w80 - 1 sep 1990 >> ../tests/test.out 2>&1
# Remove references to SysInclude, which is build-specific
grep -F -v '$SysInclude' < ../tests/test.out > ../tests/test.out.1 && mv -f ../tests/test.out.1 ../tests/test.out
@@ -597,6 +597,9 @@ if test $? = 0 ; then
done
fi
# Test --print-tokens long option
../src/remind --print-tokens < /dev/null >> ../tests/test.out 2>&1
cmp -s ../tests/test.out ../tests/test.cmp
if [ "$?" = "0" ]; then
echo "Remind: Acceptance test PASSED"
+511 -151
View File
@@ -1007,7 +1007,7 @@ a049 => 21
substr(21, 2) => Type mismatch
../tests/test.rem(326): substr(): Type mismatch
set a051 substr(a050, 2, 6)
../tests/test.rem(327): Undefined variable: a050
../tests/test.rem(327): Undefined variable: `a050'
a050 => Undefined variable
set a052 time(1+2, 3+4)
1 + 2 => 3
@@ -1029,7 +1029,7 @@ set a057 value("a05"+"6")
"a05" + "6" => "a056"
value("a056") => "SDFJHSDF KSJDFH KJSDFH KSJDFH"
set a058 version()
version() => "05.00.04"
version() => "05.00.05"
set a059 wkday(today())
today() => 1991-02-16
wkday(1991-02-16) => "Saturday"
@@ -1334,7 +1334,7 @@ trigduration() => -1
# Test adding TIME+TIME and DATETIME+TIME
set a126 11:00 + 3:00
11:00 + 03:00 => 14:00
set a127 23:00 + 5:30
set a127 '23:00' + 5:30
23:00 + 05:30 => 04:30
set a128 '2018-02-03@10:00' + 6:45
2018-02-03@10:00 + 06:45 => 2018-02-03@16:45
@@ -2619,7 +2619,7 @@ a086 4
a109 2012-01-01
a128 2018-02-03@16:45
a039 "February"
a058 "05.00.04"
a058 "05.00.05"
a077 "1992 92\n"
a096 -4
a119 -1
@@ -2716,114 +2716,115 @@ a125 -1
dump $
Variable Value
$AddBlankLines 1 [0, 1]
$Ago "ago"
$Am "am"
$And "and"
$April "April"
$At "at"
$August "August"
$CalcUTC 0 [0, 1]
$CalMode 0
$Daemon 0
$DateSep "-"
$DateTimeSep "@"
$December "December"
$DefaultColor "-1 -1 -1"
$DefaultPrio 5000 [0, 9999]
$DefaultTDelta 0 [0, 1440]
$DeltaOverride 0
$DontFork 0
$DontQueue 1
$DontTrigAts 0
$EndSent ".?!"
$EndSentIg "\"')]}>"
$ExpressionTimeLimit 0
$February "February"
$FirstIndent 0 [0, 132]
$FoldYear 0 [0, 1]
$FormWidth 72 [20, 500]
$Friday "Friday"
$Fromnow "from now"
$Hour "hour"
$Hplu "s"
$HushMode 0
$IgnoreOnce 1
$InfDelta 0
$IntMax 2147483647
$IntMin -2147483648
$Is "is"
$January "January"
$July "July"
$June "June"
$LatDeg 30
$Latitude "30.500000"
$LatMin 30
$LatSec 0
$Location "Ottawa"
$LongDeg -25
$Longitude "24.750000"
$LongMin 15
$LongSec 0
$March "March"
$MaxFullOmits 1000
$MaxLateMinutes 0 [0, 1440]
$MaxPartialOmits 366
$MaxSatIter 150 [10, Inf)
$MaxStringLen 65535 [-1, Inf)
$May "May"
$MinsFromUTC -300 [-780, 780]
$Minute "minute"
$Monday "Monday"
$Mplu "s"
$NextMode 0
$November "November"
$Now "now"
$NumFullOmits 1
$NumPartialOmits 0
$NumQueued 0
$NumTrig 41
$October "October"
$On "on"
$OnceFile ""
$ParseUntriggered 1 [0, 1]
$Pm "pm"
$PrefixLineNo 0
$PSCal 0
$RunOff 0
$Saturday "Saturday"
$September "September"
$SimpleCal 0
$SortByDate 0
$SortByPrio 0
$SortByTime 0
$SubsIndent 0 [0, 132]
$Sunday "Sunday"
$SuppressLRM 0 [0, 1]
$T 0
$Td -1
$TerminalBackground -1
$Thursday "Thursday"
$TimeSep ":"
$Tm -1
$Today "today"
$Tomorrow "tomorrow"
$Tt 00:00
$Tuesday "Tuesday"
$Tw -1
$Ty -1
$U 1991-02-16
$Ud 16
$Um 2
$UntimedFirst 0
$Use256Colors 0
$UseBGVTColors 0
$UseTrueColors 0
$UseVTColors 0
$Uw 6
$Uy 1991
$Was "was"
$Wednesday "Wednesday"
$AddBlankLines 1 [0, 1]
$Ago "ago"
$Am "am"
$And "and"
$April "April"
$At "at"
$August "August"
$CalcUTC 0 [0, 1]
$CalMode 0
$Daemon 0
$DateSep "-"
$DateTimeSep "@"
$December "December"
$DefaultColor "-1 -1 -1"
$DefaultPrio 5000 [0, 9999]
$DefaultTDelta 0 [0, 1440]
$DeltaOverride 0
$DontFork 0
$DontQueue 1
$DontTrigAts 0
$EndSent ".?!"
$EndSentIg "\"')]}>"
$ExpressionTimeLimit 0
$February "February"
$FirstIndent 0 [0, 132]
$FoldYear 0 [0, 1]
$FormWidth 72 [20, 500]
$Friday "Friday"
$Fromnow "from now"
$Hour "hour"
$Hplu "s"
$HushMode 0
$IgnoreOnce 1
$InfDelta 0
$IntMax 2147483647
$IntMin -2147483648
$Is "is"
$January "January"
$July "July"
$June "June"
$LatDeg 30
$Latitude "30.500000"
$LatMin 30
$LatSec 0
$Location "Ottawa"
$LongDeg -25
$Longitude "24.750000"
$LongMin 15
$LongSec 0
$March "March"
$MaxFullOmits 1000
$MaxLateMinutes 0 [0, 1440]
$MaxPartialOmits 366
$MaxSatIter 150 [10, Inf)
$MaxStringLen 65535 [-1, Inf)
$May "May"
$MinsFromUTC -300 [-780, 780]
$Minute "minute"
$Monday "Monday"
$Mplu "s"
$NextMode 0
$November "November"
$Now "now"
$NumFullOmits 1
$NumPartialOmits 0
$NumQueued 0
$NumTrig 41
$October "October"
$On "on"
$OnceFile ""
$ParseUntriggered 1 [0, 1]
$Pm "pm"
$PrefixLineNo 0
$PSCal 0
$RunOff 0
$Saturday "Saturday"
$September "September"
$SimpleCal 0
$SortByDate 0
$SortByPrio 0
$SortByTime 0
$SubsIndent 0 [0, 132]
$Sunday "Sunday"
$SuppressImplicitWarnings 0 [0, 1]
$SuppressLRM 0 [0, 1]
$T 0
$Td -1
$TerminalBackground -1
$Thursday "Thursday"
$TimeSep ":"
$Tm -1
$Today "today"
$Tomorrow "tomorrow"
$Tt 00:00
$Tuesday "Tuesday"
$Tw -1
$Ty -1
$U 1991-02-16
$Ud 16
$Um 2
$UntimedFirst 0
$Use256Colors 0
$UseBGVTColors 0
$UseTrueColors 0
$UseVTColors 0
$Uw 6
$Uy 1991
$Was "was"
$Wednesday "Wednesday"
msg [$April]%
../tests/test.rem(478): Trig = Saturday, 16 February, 1991
$April => "April"
@@ -3380,7 +3381,7 @@ REM DURATION 15:00 MSG Should fail... need AT if you have DURATION.
# Parsing of AM/PM times
REM AT 0:00am MSG foo 0a
../tests/test.rem(595): Expecting time after AT
../tests/test.rem(595): Ill-formed time: `0:00am'
REM AT 1:00AM MSG foo 1a
../tests/test.rem(596): Trig = Saturday, 16 February, 1991 AT 01:00
foo 1a
@@ -3430,9 +3431,9 @@ REM AT 12:00am MSG foo 12a
foo 12a
REM AT 13:00AM MSG foo 13a
../tests/test.rem(608): Expecting time after AT
../tests/test.rem(608): Ill-formed time: `13:00AM'
REM AT 0:00pm MSG foo 0p
../tests/test.rem(609): Expecting time after AT
../tests/test.rem(609): Ill-formed time: `0:00pm'
REM AT 1:00PM MSG foo 1p
../tests/test.rem(610): Trig = Saturday, 16 February, 1991 AT 13:00
foo 1p
@@ -3482,11 +3483,11 @@ REM AT 12:00pm MSG foo 12p
foo 12p
REM AT 13:00PM MSG foo 13p
../tests/test.rem(622): Expecting time after AT
../tests/test.rem(622): Ill-formed time: `13:00PM'
DEBUG +x
SET x 0:00am + 0
../tests/test.rem(625): Ill-formed time
../tests/test.rem(625): Ill-formed time: `0:00am'
SET x 1:00AM + 0
01:00 + 0 => 01:00
SET x 2:00am + 0
@@ -3512,10 +3513,10 @@ SET x 11:00AM + 0
SET x 12:00am + 0
00:00 + 0 => 00:00
SET x 13:00AM + 0
../tests/test.rem(638): Ill-formed time
../tests/test.rem(638): Ill-formed time: `13:00AM'
SET x 0:00pm + 0
../tests/test.rem(640): Ill-formed time
../tests/test.rem(640): Ill-formed time: `0:00pm'
SET x 1:00PM + 0
13:00 + 0 => 13:00
SET x 2:00pm + 0
@@ -3541,10 +3542,10 @@ SET x 11:00PM + 0
SET x 12:00pm + 0
12:00 + 0 => 12:00
SET x 13:00PM + 0
../tests/test.rem(653): Ill-formed time
../tests/test.rem(653): Ill-formed time: `13:00PM'
SET x '2015-02-03@0:00am' + 0
../tests/test.rem(655): Ill-formed time
../tests/test.rem(655): Ill-formed time: '2015-02-03@0:00am'
SET x '2015-02-03@1:00AM' + 0
2015-02-03@01:00 + 0 => 2015-02-03@01:00
SET x '2015-02-03@2:00am' + 0
@@ -3570,10 +3571,10 @@ SET x '2015-02-03@11:00AM' + 0
SET x '2015-02-03@12:00am' + 0
2015-02-03@00:00 + 0 => 2015-02-03@00:00
SET x '2015-02-03@13:00AM' + 0
../tests/test.rem(668): Ill-formed time
../tests/test.rem(668): Ill-formed time: '2015-02-03@13:00AM'
SET x '2015-02-03@0:00pm' + 0
../tests/test.rem(670): Ill-formed time
../tests/test.rem(670): Ill-formed time: '2015-02-03@0:00pm'
SET x '2015-02-03@1:00PM' + 0
2015-02-03@13:00 + 0 => 2015-02-03@13:00
SET x '2015-02-03@2:00pm' + 0
@@ -3599,7 +3600,7 @@ SET x '2015-02-03@11:00PM' + 0
SET x '2015-02-03@12:00pm' + 0
2015-02-03@12:00 + 0 => 2015-02-03@12:00
SET x '2015-02-03@13:00PM' + 0
../tests/test.rem(683): Ill-formed time
../tests/test.rem(683): Ill-formed time: '2015-02-03@13:00PM'
# Test the ampm function
set x ampm(0:12) + ""
@@ -5459,8 +5460,8 @@ SATSIFY ""
REM SATISFY [version() > "01.00.00"]
../tests/test.rem(1045): SATISFY: expression has no reference to trigdate() or $T...
../tests/test.rem(1045): Trig = Saturday, 16 February, 1991
version() => "05.00.04"
"05.00.04" > "01.00.00" => 1
version() => "05.00.05"
"05.00.05" > "01.00.00" => 1
../tests/test.rem(1045): Trig(satisfied) = Saturday, 16 February, 1991
REM SATISFY [max(x, max(x, 1, 2, 3), 4, 5, 6) * 5]
../tests/test.rem(1046): SATISFY: expression has no reference to trigdate() or $T...
@@ -5681,8 +5682,12 @@ set xyz ! "0"
set zxk version(1)
../tests/test.rem(1114): version: Too many arguments
version(1)
^-- here
set zxk max()
../tests/test.rem(1115): max: Not enough arguments
max()
^-- here
fset dooby(x) 1
set zxk dooby()
@@ -5695,6 +5700,11 @@ set zxk dooby(1)
Entering UserFN dooby(1)
Leaving UserFN dooby(1) => 1
REM 1 Jan 1873 MSG This should fail
../tests/test.rem(1122): `1873' is not recognized as a year (1990-5990) or a day number (1-31)
REM 1873-12-11 MSG Also bad.
../tests/test.rem(1123): Bad date specification: `1873-12-11'
# Don't want Remind to queue reminders
EXIT
@@ -11848,7 +11858,7 @@ STDOUT is a: PIPE
| | | |1 |2 |3 |4 |
| | | |BLACK |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
|5 |6 |7 |8 |9 |10 |11 |
|5 |6 |7 |8 |9 |10 |11 |
|-@0 | | |BLACK |BRIGHT |BRIGHT |BRIGHT |
| | | | |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
@@ -11870,7 +11880,7 @@ STDOUT is a: PIPE
| | | |1 |2 |3 |4 |
| | | |BLACK |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
|5 |6 |7 |8 |9 |10 |11 |
|5 |6 |7 |8 |9 |10 |11 |
|-@0,0 | | |BLACK |BRIGHT |BRIGHT |BRIGHT |
| | | | |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
@@ -11892,7 +11902,7 @@ STDOUT is a: PIPE
| | | |1 |2 |3 |4 |
| | | |BLACK |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
|5 |6 |7 |8 |9 |10 |11 |
|5 |6 |7 |8 |9 |10 |11 |
|-@0,1 | | |BLACK |BRIGHT |BRIGHT |BRIGHT |
| | | | |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
@@ -11914,7 +11924,7 @@ STDOUT is a: PIPE
| | | |1 |2 |3 |4 |
| | | |BLACK |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
|5 |6 |7 |8 |9 |10 |11 |
|5 |6 |7 |8 |9 |10 |11 |
|-@1 | | |BLACK |BRIGHT |BRIGHT |BRIGHT |
| | | | |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
@@ -11936,7 +11946,7 @@ STDOUT is a: PIPE
| | | |1 |2 |3 |4 |
| | | |BLACK |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
|5 |6 |7 |8 |9 |10 |11 |
|5 |6 |7 |8 |9 |10 |11 |
|-@1,0 | | |BLACK |BRIGHT |BRIGHT |BRIGHT |
| | | | |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
@@ -11958,7 +11968,7 @@ STDOUT is a: PIPE
| | | |1 |2 |3 |4 |
| | | |BLACK |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
|5 |6 |7 |8 |9 |10 |11 |
|5 |6 |7 |8 |9 |10 |11 |
|-@1,1 | | |BLACK |BRIGHT |BRIGHT |BRIGHT |
| | | | |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
@@ -11980,7 +11990,7 @@ STDOUT is a: PIPE
| | | |1 |2 |3 |4 |
| | | |BLACK |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
|5 |6 |7 |8 |9 |10 |11 |
|5 |6 |7 |8 |9 |10 |11 |
|-@2 | | |BLACK |BRIGHT |BRIGHT |BRIGHT |
| | | | |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
@@ -12002,7 +12012,7 @@ STDOUT is a: PIPE
| | | |1 |2 |3 |4 |
| | | |BLACK |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
|5 |6 |7 |8 |9 |10 |11 |
|5 |6 |7 |8 |9 |10 |11 |
|-@2,0 | | |BLACK |BRIGHT |BRIGHT |BRIGHT |
| | | | |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
@@ -12024,7 +12034,7 @@ STDOUT is a: PIPE
| | | |1 |2 |3 |4 |
| | | |BLACK |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
|5 |6 |7 |8 |9 |10 |11 |
|5 |6 |7 |8 |9 |10 |11 |
|-@2,1 | | |BLACK |BRIGHT |BRIGHT |BRIGHT |
| | | | |BLUE |GREEN |CYAN |
+----------+----------+----------+----------+----------+----------+----------+
@@ -12592,7 +12602,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.00.04
05.00.05
NOTE JSONQUEUE
[{"priority":2,"eventstart":"VOLATILE","time":"23:59","nexttime":"23:59","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue2.rem","lineno":1,"type":"MSG_TYPE","body":"XXXX"},{"priority":999,"eventstart":"VOLATILE","time":"23:58","nexttime":"23:58","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":5,"type":"MSG_TYPE","body":"quux"},{"priority":42,"eventstart":"VOLATILE","time":"23:57","nexttime":"23:57","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":4,"type":"MSG_TYPE","body":"bar"},{"priority":5000,"eventstart":"VOLATILE","time":"23:56","nexttime":"23:56","tdelta":0,"trep":0,"rundisabled":0,"ntrig":1,"filename":"../tests/queue1.rem","lineno":3,"type":"MSG_TYPE","body":"foo"}]
NOTE ENDJSONQUEUE
@@ -13176,11 +13186,11 @@ No reminders.
# This is a timestamp file used by Remind to track ONCE reminders.
# Do not edit or delete it.
+----------------------------------------------------------------------------+
| September 2024 |
| September 1990 |
+----------+----------+----------+----------+----------+----------+----------+
| Sunday | Monday | Tuesday |Wednesday | Thursday | Friday | Saturday |
+----------+----------+----------+----------+----------+----------+----------+
|1 |2 |3 |4 |5 |6 |7 |
| | | | | | |1 |
| | | | | | | |
| | | | | | | |
| | | | | | | |
@@ -13188,7 +13198,7 @@ No reminders.
| | | | | | | |
| | | | | | | |
+----------+----------+----------+----------+----------+----------+----------+
|8 |9 |10 |11 |12 |13 |14 |
|2 |3 |4 |5 |6 |7 |8 |
| | | | | | | |
| | | | | | | |
| | | | | | | |
@@ -13196,17 +13206,7 @@ No reminders.
| | | | | | | |
| | | | | | | |
+----------+----------+----------+----------+----------+----------+----------+
|15 |16 |17 |18 |19 |20 |21 |
| | | | | | | |
| |foo | | | | | |
| |bar | | | | | |
| |baz wookie| | | | | |
| |quux apple| | | | | |
| |blech | | | | | |
| | | | | | | |
| |ANOTHER | | | | | |
+----------+----------+----------+----------+----------+----------+----------+
|22 |23 |24 |25 |26 |27 |28 |
|9 |10 |11 |12 |13 |14 |15 |
| | | | | | | |
| | | | | | | |
| | | | | | | |
@@ -13214,7 +13214,25 @@ No reminders.
| | | | | | | |
| | | | | | | |
+----------+----------+----------+----------+----------+----------+----------+
|29 |30 | | | | | |
|16 |17 |18 |19 |20 |21 |22 |
| | | | | | | |
|foo | | | | | | |
|bar | | | | | | |
|baz wookie| | | | | | |
|quux apple| | | | | | |
|blech | | | | | | |
| | | | | | | |
|ANOTHER | | | | | | |
+----------+----------+----------+----------+----------+----------+----------+
|23 |24 |25 |26 |27 |28 |29 |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
+----------+----------+----------+----------+----------+----------+----------+
|30 | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
@@ -13223,3 +13241,345 @@ No reminders.
| | | | | | | |
+----------+----------+----------+----------+----------+----------+----------+
# Remind Tokens
addomit
after
at
ban
banner
before
cal
clear
clear-omit-context
debug
do
dump
dumpvars
duration
else
endif
errmsg
exit
expr
first
flush
fourth
from
fset
funset
if
iftrig
in
inc
include
includecmd
last
lastday
lastworkday
maybe
maybe-uncomputable
msf
msg
noqueue
omit
omitfunc
once
pop
pop-omit-context
preserve
priority
ps
psfile
push
push-omit-context
rem
run
satisfy
scan
scanfrom
sched
second
set
skip
special
tag
third
through
unset
until
warn
# Month Names
apr
april
aug
august
dec
december
feb
february
jan
january
jul
july
jun
june
mar
march
may
nov
november
oct
october
sep
september
# Weekdays
fri
friday
mon
monday
sat
saturday
sun
sunday
thu
thursday
tue
tuesday
wed
wednesday
# Built-in Functions
abs
access
adawn
adusk
ampm
ansicolor
args
asc
baseyr
char
choose
coerce
columns
current
date
datepart
datetime
dawn
day
daysinmon
defined
dosubst
dusk
easterdate
evaltrig
filedate
filedatetime
filedir
filename
getenv
hebdate
hebday
hebmon
hebyear
hour
htmlescape
htmlstriptags
iif
index
isany
isdst
isleap
isomitted
language
localtoutc
lower
max
min
minsfromutc
minute
mon
monnum
moondate
moondatetime
moonphase
moontime
multitrig
ndawn
ndusk
nonomitted
now
ord
orthodoxeaster
ostype
pad
plural
psmoon
psshade
realcurrent
realnow
realtoday
rows
sgn
shell
shellescape
slide
soleq
stdout
strlen
substr
sunrise
sunset
time
timepart
timezone
today
trig
trigback
trigdate
trigdatetime
trigdelta
trigduration
trigeventduration
trigeventstart
trigfrom
trigger
trigpriority
trigrep
trigscanfrom
trigtags
trigtime
trigtimedelta
trigtimerep
triguntil
trigvalid
typeof
tzconvert
upper
utctolocal
value
version
weekno
wkday
wkdaynum
year
# System Variables
$AddBlankLines
$Ago
$Am
$And
$April
$At
$August
$CalcUTC
$CalMode
$Daemon
$DateSep
$DateTimeSep
$December
$DefaultColor
$DefaultPrio
$DefaultTDelta
$DeltaOverride
$DontFork
$DontQueue
$DontTrigAts
$EndSent
$EndSentIg
$ExpressionTimeLimit
$February
$FirstIndent
$FoldYear
$FormWidth
$Friday
$Fromnow
$Hour
$Hplu
$HushMode
$IgnoreOnce
$InfDelta
$IntMax
$IntMin
$Is
$January
$July
$June
$LatDeg
$Latitude
$LatMin
$LatSec
$Location
$LongDeg
$Longitude
$LongMin
$LongSec
$March
$MaxFullOmits
$MaxLateMinutes
$MaxPartialOmits
$MaxSatIter
$MaxStringLen
$May
$MinsFromUTC
$Minute
$Monday
$Mplu
$NextMode
$November
$Now
$NumFullOmits
$NumPartialOmits
$NumQueued
$NumTrig
$October
$On
$OnceFile
$ParseUntriggered
$Pm
$PrefixLineNo
$PSCal
$RunOff
$Saturday
$September
$SimpleCal
$SortByDate
$SortByPrio
$SortByTime
$SubsIndent
$Sunday
$SuppressImplicitWarnings
$SuppressLRM
$SysInclude
$T
$Td
$TerminalBackground
$Thursday
$TimeSep
$Tm
$Today
$Tomorrow
$Tt
$Tuesday
$Tw
$Ty
$U
$Ud
$Um
$UntimedFirst
$Use256Colors
$UseBGVTColors
$UseTrueColors
$UseVTColors
$Uw
$Uy
$Was
$Wednesday
+4 -1
View File
@@ -450,7 +450,7 @@ set a125 trigduration()
# Test adding TIME+TIME and DATETIME+TIME
set a126 11:00 + 3:00
set a127 23:00 + 5:30
set a127 '23:00' + 5:30
set a128 '2018-02-03@10:00' + 6:45
set a129 23:30 + '2019-02-02@16:44'
@@ -1119,6 +1119,9 @@ set zxk dooby()
set zxk dooby(1, 2)
set zxk dooby(1)
REM 1 Jan 1873 MSG This should fail
REM 1873-12-11 MSG Also bad.
# Don't want Remind to queue reminders
EXIT