mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-16 14:28:40 +02:00
Compare commits
34 Commits
04.02.03-B
...
04.02.04
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fee354e6c | ||
|
|
ec76554d41 | ||
|
|
ddb0817c99 | ||
|
|
3d6ecd1f72 | ||
|
|
e3ec6565e9 | ||
|
|
8ed49ead7f | ||
|
|
49fbca416f | ||
|
|
82cd438fff | ||
|
|
946e1bca38 | ||
|
|
e40c81b5bf | ||
|
|
f23418480d | ||
|
|
bb4df39c50 | ||
|
|
5fec775863 | ||
|
|
a85980fec2 | ||
|
|
f3ea2962e6 | ||
|
|
3a5af23ab6 | ||
|
|
f9656edc51 | ||
|
|
5134b47d47 | ||
|
|
d4a183f3bf | ||
|
|
87e392de6c | ||
|
|
afc1667e64 | ||
|
|
8d25270c43 | ||
|
|
929866a770 | ||
|
|
395bad96a7 | ||
|
|
cd7be006c9 | ||
|
|
f658ba7ee7 | ||
|
|
7416f4c035 | ||
|
|
2860159ff7 | ||
|
|
64fa71ab09 | ||
|
|
ffbba7d4d1 | ||
|
|
fdcc2d8acf | ||
|
|
f1aa4d16af | ||
|
|
a55c5580f3 | ||
|
|
569e315306 |
2
configure
vendored
2
configure
vendored
@@ -4025,7 +4025,7 @@ _ACEOF
|
||||
fi
|
||||
done
|
||||
|
||||
VERSION=04.02.02
|
||||
VERSION=04.02.04
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ if test "$?" != 0 ; then
|
||||
exit 1
|
||||
fi
|
||||
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale initgroups)
|
||||
VERSION=04.02.02
|
||||
VERSION=04.02.04
|
||||
AC_SUBST(VERSION)
|
||||
AC_SUBST(PERL)
|
||||
AC_SUBST(PERLARTIFACTS)
|
||||
|
||||
@@ -1,6 +1,53 @@
|
||||
CHANGES TO REMIND
|
||||
|
||||
* VERSION 4.2 Patch 3 - 2023-??-??
|
||||
* VERSION 4.2 Patch 4 - 2023-03-15
|
||||
|
||||
- NEW FEATURE: Remind: Add "htmlescape" and "htmlstriptags" built-in
|
||||
functions.
|
||||
|
||||
- NEW FEATURE: Rem2PDF: Add the "--wrap, -y" option to ensure that no
|
||||
printed calendar takes up more than 5 rows. If a calendar would normally
|
||||
require 6 rows, wrap it so the last day or two appear on the first
|
||||
row instead of on a sixth row.
|
||||
|
||||
- NEW FEATURE: Remind: Improve the -k option to allow specification of
|
||||
separate commands for immediately-issued vs. queued reminders. For
|
||||
example:
|
||||
|
||||
remind '-kcmd1 %s' '-k:cmd2 %s' ...
|
||||
|
||||
will use "cmd1" for immediately-issued reminders and "cmd2" for queued
|
||||
ones. If you only use '-k:cmd2 %s' then immediately-issued reminders
|
||||
are simply printed as usual rather than being passed to a command.
|
||||
|
||||
- IMPROVEMENT: Remind: Make "SPECIAL MSG" the same as just "MSG" and
|
||||
the same for MSF, RUN, PS and PSFILE. This effectively lets you use
|
||||
expression-pasting to determine the type of a REM command; see the
|
||||
remind(1) man page for details.
|
||||
|
||||
- MINOR IMPROVEMENT: If "make test" fails, output up to 200 lines of diff
|
||||
so we can see immediately what failed.
|
||||
|
||||
- DOCUMENTATION FIX: Fix some typos; fix TkRemind syntax description.
|
||||
|
||||
- TEST FIX: Make tests run reliably regardless of local machine's time zone.
|
||||
|
||||
- BUG FIX: TkRemind: Don't crash if local installation of Tk lacks the
|
||||
-underlinefg configuration option.
|
||||
|
||||
- BUG FIX: examples/defs.rem: Fix up US Thanksgiving example.
|
||||
|
||||
- BUG FIX: include/holidays/us.rem: Add logic for US holidays that are
|
||||
observed on a Friday if the holiday is a Saturday, or on a Monday if the
|
||||
holiday is a Sunday.
|
||||
|
||||
- BUG FIX: TkRemind: Don't cut off MOON text at the first white-space
|
||||
character.
|
||||
|
||||
- BUG FIX: Remind: prevent functions defined on the command-line (as in
|
||||
remind '-if(x)=whatever') from segfaulting.
|
||||
|
||||
* VERSION 4.2 Patch 3 - 2023-02-10
|
||||
|
||||
- NEW FEATURE: Remind: add the orthodoxeaster() function to return the
|
||||
date of Orthodox Easter.
|
||||
@@ -9,6 +56,9 @@ CHANGES TO REMIND
|
||||
|
||||
- IMPROVEMENT: Add Greek holiday file courtesy of JeiEl.
|
||||
|
||||
- IMPROVEMENT: Fix the Perl code (rem2pdf, rem2html) to silence Perl::Critic
|
||||
warnings
|
||||
|
||||
- IMPROVEMENT: Many internal code tweaks to eliminate many cppcheck
|
||||
static analysis warnings.
|
||||
|
||||
@@ -23,6 +73,9 @@ CHANGES TO REMIND
|
||||
|
||||
- BUG FIX: Remind: Add missing #include <fcntl.h> to funcs.c
|
||||
|
||||
- BUG FIX: Remind: Fix undefined integer-overflow behavior in built-in abs()
|
||||
function. Pointed out on IRC by "ubitux".
|
||||
|
||||
* VERSION 4.2 Patch 2 - 2023-01-01
|
||||
|
||||
- NEW FEATURE: Remind: Add the NOQUEUE modifier to the REM statement for
|
||||
|
||||
@@ -42,7 +42,6 @@ SET Week_1 1
|
||||
SET Week_2 8
|
||||
SET Week_3 15
|
||||
SET Week_4 22
|
||||
FSET _last(mo) "1 " + MON((mo%12)+1) + " --7"
|
||||
|
||||
#################################################################
|
||||
# Function that removes a single leading zero from a string... #
|
||||
@@ -126,6 +125,8 @@ REM Sat Sun SPECIAL SHADE 220
|
||||
# The following holidays were provided by Dave Rickel #
|
||||
# Modified by D. Skoll to give safe OMITs for moveable holidays #
|
||||
# #
|
||||
# NOTE: See include/holidays/us.rem for more up-to-date definitions #
|
||||
# #
|
||||
#############################################################################
|
||||
|
||||
SET SaveTrig $NumTrig
|
||||
@@ -189,7 +190,7 @@ REM Nov 11 MSG %"Veterans Day%"
|
||||
REM Oct 30 MSG %"Mischief Night%"
|
||||
REM Oct 31 MSG %"Halloween%"
|
||||
REM Tue Nov 2 SCANFROM -7 SATISFY [($Ty % 4) == 0] MSG %"Election Day%"
|
||||
REM Last Thu in Nov SCANFROM -7 ADDOMIT MSG %"Thanksgiving Day%"
|
||||
REM Thu Nov [Week_4] SCANFROM -7 ADDOMIT MSG %"Thanksgiving Day%"
|
||||
REM Fri Nov [Week_4+1] SCANFROM -7 ADDOMIT MSG %"Thanksgiving (cont.)%"
|
||||
OMIT Dec 24 MSG %"Christmas Eve%"
|
||||
OMIT Dec 25 MSG %"Christmas%" Day
|
||||
|
||||
@@ -14,6 +14,9 @@ REM [easterdate($Uy)+49] MSG Pentecost
|
||||
# which ones are omitted.
|
||||
|
||||
OMIT Jan 1 MSG New Year's Day
|
||||
REM 31 Dec SCANFROM -7 ADDOMIT SATISFY [$Tw==5] MSG New Year's Day (observed)
|
||||
REM 2 Jan SCANFROM -7 ADDOMIT SATISFY [$Tw==1] MSG New Year's Day (observed)
|
||||
|
||||
REM Third Monday in Jan MSG Martin Luther King - %"MLK Day%"
|
||||
REM Feb 2 MSG Ground Hog Day
|
||||
REM Feb 14 MSG Valentine's Day
|
||||
@@ -21,8 +24,8 @@ REM Third Monday in Feb SCANFROM -7 ADDOMIT MSG President's Day
|
||||
REM Mar 17 MSG St. Patrick's Day
|
||||
|
||||
# These are accurate for most places in North America
|
||||
REM MAYBE-UNCOMPUTABLE Sun November SATISFY [isdst($T) != isdst($T+1)] MSG Daylight Saving Time Ends
|
||||
REM MAYBE-UNCOMPUTABLE Sun March SATISFY [isdst($T) != isdst($T+1)] MSG Daylight Saving Time Starts
|
||||
REM MAYBE-UNCOMPUTABLE Sun November SATISFY [isdst($T) && !isdst($T+1)] MSG Daylight Saving Time Ends
|
||||
REM MAYBE-UNCOMPUTABLE Sun March SATISFY [!isdst($T) && isdst($T+1)] MSG Daylight Saving Time Starts
|
||||
|
||||
REM Apr 1 MSG %"April Fool's%" Day
|
||||
|
||||
@@ -49,14 +52,21 @@ REM Third Sat in May MSG Armed Forces Day
|
||||
REM Last Monday in May SCANFROM -7 ADDOMIT MSG Memorial Day
|
||||
REM Jun 14 MSG Flag Day
|
||||
|
||||
OMIT 19 June MSG Juneteenth
|
||||
REM 18 June SCANFROM -7 ADDOMIT SATISFY [$Tw==5] MSG Juneteenth (observed)
|
||||
REM 20 June SCANFROM -7 ADDOMIT SATISFY [$Tw==1] MSG Juneteenth (observed)
|
||||
|
||||
REM July 4 SCANFROM -7 ADDOMIT MSG Independence Day
|
||||
REM July 3 SCANFROM -7 ADDOMIT SATISFY [$Tw == 5] MSG Independence Day (observed)
|
||||
REM July 5 SCANFROM -7 ADDOMIT SATISFY [$Tw == 1] MSG Independence Day (observed)
|
||||
REM July 3 SCANFROM -7 ADDOMIT SATISFY [$Tw==5] MSG Independence Day (observed)
|
||||
REM July 5 SCANFROM -7 ADDOMIT SATISFY [$Tw==1] MSG Independence Day (observed)
|
||||
|
||||
REM Third Sun in June MSG Father's Day
|
||||
REM First Mon in Sep SCANFROM -7 ADDOMIT MSG Labor Day
|
||||
REM Second Mon in Oct MSG Columbus Day / Indigenous Peoples' Day
|
||||
REM Nov 11 MSG Veterans Day
|
||||
|
||||
OMIT 11 Nov MSG Veterans Day
|
||||
REM 10 Nov SCANFROM -7 ADDOMIT SATISFY [$Tw==5] MSG Veterans Day (observed)
|
||||
REM 12 Nov SCANFROM -7 ADDOMIT SATISFY [$Tw==1] MSG Veterans Day (observed)
|
||||
|
||||
REM Oct 30 MSG Mischief Night
|
||||
REM Oct 31 MSG Halloween
|
||||
@@ -64,8 +74,9 @@ REM Oct 31 MSG Halloween
|
||||
REM Tue Nov 2 SCANFROM -7 SATISFY [($Ty % 4) == 0] MSG Election Day
|
||||
|
||||
REM Thu 22 Nov SCANFROM -7 ADDOMIT MSG Thanksgiving Day
|
||||
|
||||
REM Fri 23 Nov SCANFROM -7 ADDOMIT MSG Thanksgiving (cont.)
|
||||
|
||||
REM Dec 24 MSG Christmas Eve
|
||||
OMIT Dec 25 MSG %"Christmas%" Day
|
||||
REM 24 Dec SCANFROM -7 ADDOMIT SATISFY [$Tw==5] MSG Christmas (observed)
|
||||
REM 26 Dec SCANFROM -7 ADDOMIT SATISFY [$Tw==1] MSG Christmas (observed)
|
||||
|
||||
@@ -328,6 +328,18 @@ processes with the above technique. So be very careful. Because all
|
||||
shell and whitespace characters are escaped, the program you execute
|
||||
with the \fB\-k\fR option must be prepared to handle the entire
|
||||
message as a single argument.
|
||||
.PP
|
||||
If you follow the \fB\-k\fR option with a colon, then the command is applied
|
||||
only to queued timed reminders. Normal reminders are handled as usual.
|
||||
In the above example, if you want normal reminders to simply be displayed
|
||||
as usual, but queued reminders to be sent to notify-send, you could use:
|
||||
.PP
|
||||
.nf
|
||||
remind '\-k:notify-send %s &' ...
|
||||
.fi
|
||||
.PP
|
||||
You use both \fB\-k\fR\fIcmd1\fR and \fB\-k:\fR\fIcmd2\fR to use different
|
||||
commands for queued versus non-queued reminders.
|
||||
.RE
|
||||
.TP
|
||||
\fB\-z\fR[\fIn\fR] Runs \fBRemind\fR in the daemon mode. If \fIn\fR
|
||||
@@ -1006,7 +1018,7 @@ By comparison, if we had used "\-\-1", the reminder would be triggered on
|
||||
the last day of the month, regardless of the \fBOMIT\fR.
|
||||
.PP
|
||||
If you locally omit weekdays but also have globally-omitted weekdays, then
|
||||
the list of ommitted weekdays is the union of the two. Consider this
|
||||
the list of omitted weekdays is the union of the two. Consider this
|
||||
example:
|
||||
.PP
|
||||
.nf
|
||||
@@ -3074,6 +3086,16 @@ Support for Hebrew dates - see the section "THE HEBREW CALENDAR"
|
||||
.B hour(tq_time)
|
||||
Returns the hour component of \fItime\fR.
|
||||
.TP
|
||||
.B htmlescape(s_str)
|
||||
Returns a modified copy of \fIstr\fR where "<" is replaced with
|
||||
"<"; ">" is replaced with ">" and "&" is replaced with "&"
|
||||
.TP
|
||||
.B htmlstriptags(s_str)
|
||||
Returns a modified copy of \fIstr\fR where HTML tags are stripped
|
||||
out. The stripping algorithm is fairly naive; the function starts
|
||||
stripping characters when it encounters a "<" and it stops stripping
|
||||
when it encounters a ">".
|
||||
.TP
|
||||
.B iif(si_test1, x_arg1, [si_test2, x_arg2,...], x_default)
|
||||
If \fItest1\fR is not zero or the null string, returns \fIarg1\fR.
|
||||
Otherwise, if \fItest2\fR is not zero or the null string, returns
|
||||
@@ -4065,15 +4087,30 @@ You cannot use expression-pasting to determine the type (\fBMSG\fR,
|
||||
\fBCAL\fR, etc.) of a \fBREM\fR command. You can paste expressions
|
||||
before and after the \fBMSG\fR, etc. keywords, but cannot do something like
|
||||
this:
|
||||
.RS
|
||||
.PP
|
||||
.nf
|
||||
REM ["12 Nov 1993 AT 13:05 " + "MSG" + " BOO!"]
|
||||
REM ["12 Nov 1993 AT 13:05 " + "MSG" + " BOO!"]
|
||||
.fi
|
||||
.PP
|
||||
.B COMMON PITFALLS IN EXPRESSION PASTING
|
||||
However, as an escape hatch, the sequence \fBSPECIAL\fR \fItype\fR
|
||||
means the same thing as just \fItype\fR where \fItype\fR is one
|
||||
of MSG, MSF, RUN, CAL, PS and PSFILE. This lets you do something
|
||||
like this:
|
||||
.PP
|
||||
Remember, when pasting in expressions, that extra spaces are not
|
||||
inserted. Thus, something like:
|
||||
.nf
|
||||
SET type "MSG"
|
||||
REM 12 Nov 2024 SPECIAL [type] Hello
|
||||
.fi
|
||||
.PP
|
||||
You can use this to control the types of your reminders based on variables
|
||||
you set, how Remind is invoked, etc.
|
||||
.RE
|
||||
.PP
|
||||
.B COMMON PITFALLS WITH EXPRESSION PASTING
|
||||
.PP
|
||||
Remember that extra spaces are not inserted when an expression is
|
||||
pasted. Thus, something like:
|
||||
.PP
|
||||
.nf
|
||||
REM[expr]MSG[expr]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.SH NAME
|
||||
tkremind \- graphical front-end to Remind calendar program
|
||||
.SH SYNOPSIS
|
||||
.B tkremind \fR[\fIoptions\fR] [\fIread_file\fR] [\fIwrite_file\fR] [\fIconfig_file\fR]
|
||||
.B tkremind \fR[\fIoptions\fR] [\fIread_file\fR [\fIwrite_file\fR [\fIconfig_file\fR]]]
|
||||
.SH DESCRIPTION
|
||||
\fBTkRemind\fR is a graphical front-end to the \fBRemind\fR program.
|
||||
It provides a friendly graphical interface which allows you to view
|
||||
|
||||
@@ -687,7 +687,7 @@ if ($Options{help}) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (-t STDIN) {
|
||||
if (-t STDIN) { ## no critic
|
||||
print STDERR "$TIDY_PROGNAME: Input should not come from a terminal.\n\n";
|
||||
usage(1);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ my $settings = {
|
||||
numbers_on_left => 0,
|
||||
small_calendars => 0,
|
||||
fill_entire_page => 0,
|
||||
|
||||
wrap_calendar => 0,
|
||||
media => 'Letter',
|
||||
width => 0,
|
||||
height => 0,
|
||||
@@ -86,6 +86,7 @@ Options:
|
||||
--media=MEDIA, -mMEDIA Size for specified media
|
||||
--width=W, -wW Specify media width in 1/72nds of an inch
|
||||
--height=H, -hH Specify media height in 1/72nds of an inch
|
||||
--wrap, -y Make calendar fit in at most 5 rows
|
||||
--title-font=FONT Specify font for calendar title
|
||||
--header-font=FONT Specify font for weekday names
|
||||
--daynum-font=FONT Specify font for day numbers
|
||||
@@ -114,6 +115,7 @@ my $ret = GetOptions('landscape|l' => \$settings->{landscape},
|
||||
'fill-page|e' => \$settings->{fill_entire_page},
|
||||
'media|m=s' => \$settings->{media},
|
||||
'width|w=i' => \$settings->{width},
|
||||
'wrap|y' => \$settings->{wrap_calendar},
|
||||
'height|h=i' => \$settings->{height},
|
||||
'title-font=s' => \$settings->{title_font},
|
||||
'header-font=s' => \$settings->{header_font},
|
||||
@@ -175,7 +177,7 @@ if ($settings->{landscape}) {
|
||||
}
|
||||
|
||||
# Don't read from a terminal
|
||||
if (-t STDIN) {
|
||||
if (-t STDIN) { ## no critic
|
||||
print STDERR "I can't read data from a terminal. Please run like this:\n";
|
||||
print STDERR " remind -pp [options] filename | $me [options] > out.pdf\n";
|
||||
exit(1);
|
||||
@@ -249,20 +251,21 @@ sub set_media
|
||||
sub set_media_from_file
|
||||
{
|
||||
my ($fn) = @_;
|
||||
if (!open(IN, '<', $fn)) {
|
||||
my $IN;
|
||||
if (!open($IN, '<', $fn)) {
|
||||
return 0;
|
||||
}
|
||||
while(<IN>) {
|
||||
while(<$IN>) {
|
||||
chomp;
|
||||
s/^\s+//;
|
||||
s/\s+$//;
|
||||
next if ($_ eq '');
|
||||
next if ($_ =~ /^#/);
|
||||
my $m = $_;
|
||||
close(IN);
|
||||
close($IN);
|
||||
return set_media($m);
|
||||
}
|
||||
close(IN);
|
||||
close($IN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -430,6 +433,14 @@ The default is 36.
|
||||
The size of the margin at the right of the page in 1/72ths of an inch.
|
||||
The default is 36.
|
||||
|
||||
=item --wrap, -y
|
||||
|
||||
Modify the calendar so that if it would normally require 6 rows to print,
|
||||
then the last day (or last two days, as needed) are moved to the
|
||||
first row of the calendar, and adjust the small calendar positions
|
||||
as needed. This results in a calendar that only requires 5 rows, but
|
||||
with the last day or two appearing in the I<first> row.
|
||||
|
||||
=item --verbose, -v
|
||||
|
||||
Print (on STDERR) the name of the month and year for each month that
|
||||
|
||||
@@ -110,7 +110,6 @@ sub read_one_month
|
||||
$self->{daysinnextmonth} = 0;
|
||||
$self->{prevmonthyear} = 0;
|
||||
$self->{nextmonthyear} = 0;
|
||||
|
||||
for (my $i=0; $i<=31; $i++) {
|
||||
$self->{entries}->[$i] = [];
|
||||
}
|
||||
@@ -134,7 +133,7 @@ sub read_one_month
|
||||
$line = $in->getline();
|
||||
chomp($line);
|
||||
if ($line =~ /^\S+ \S+ \S+ \S+ \S+ \S+ \S+$/) {
|
||||
@{$self->{daynames}} = map { s/_/ /g; $_; } (split(/ /, $line));
|
||||
@{$self->{daynames}} = map { s/_/ /g; $_; } (split(/ /, $line)); ## no critic
|
||||
} else {
|
||||
return (undef, "Cannot interpret line: $line");
|
||||
}
|
||||
@@ -213,7 +212,7 @@ hash keys found in the newer "remind -pp" JSON output.
|
||||
sub parse_oldstyle_line
|
||||
{
|
||||
my ($self, $line) = @_;
|
||||
return undef unless $line =~ m|^(\d+)/(\d+)/(\d+) (\S+) (\S+) (\S+) (\S+) (.*)$|;
|
||||
return unless $line =~ m|^(\d+)/(\d+)/(\d+) (\S+) (\S+) (\S+) (\S+) (.*)$|;
|
||||
|
||||
my $hash = {
|
||||
date => "$1-$2-$3",
|
||||
@@ -244,6 +243,143 @@ sub parse_oldstyle_line
|
||||
return $hash;
|
||||
}
|
||||
|
||||
=head2 setup_daymap
|
||||
|
||||
Set up the array that maps ($row, $col) to day number (or -1
|
||||
for rows/cols out of range.)
|
||||
|
||||
=cut
|
||||
sub setup_daymap
|
||||
{
|
||||
my ($self, $settings) = @_;
|
||||
# First column
|
||||
my $first_col = $self->{firstwkday};
|
||||
if ($self->{mondayfirst}) {
|
||||
$first_col--;
|
||||
if ($first_col < 0) {
|
||||
$first_col = 6;
|
||||
}
|
||||
}
|
||||
|
||||
# Last column
|
||||
my $last_col = ($first_col + $self->{daysinmonth} - 1) % 7;
|
||||
|
||||
# Number of rows
|
||||
my $rows = 1;
|
||||
my $last_day_on_row = 7 - $first_col;
|
||||
while ($last_day_on_row < $self->{daysinmonth}) {
|
||||
$last_day_on_row += 7;
|
||||
$rows++;
|
||||
}
|
||||
|
||||
# Add a row for small calendars if necessary
|
||||
if (($settings->{small_calendars} != 0) && ($first_col == 0) && ($last_col == 6)) {
|
||||
$rows++;
|
||||
$self->{extra_row} = 1;
|
||||
} else {
|
||||
$self->{extra_row} = 0;
|
||||
}
|
||||
$self->{rows} = $rows;
|
||||
$self->{daymap} = [];
|
||||
$self->{first_col} = $first_col;
|
||||
$self->{last_col} = $last_col;
|
||||
for (my $row=0; $row<$rows; $row++) {
|
||||
for (my $col=0; $col < 7; $col++) {
|
||||
$self->{daymap}->[$row]->[$col] = -1;
|
||||
}
|
||||
}
|
||||
$self->{nextcal_row} = -1;
|
||||
$self->{prevcal_row} = -1;
|
||||
$self->{nextcal_col} = 6;
|
||||
$self->{prevcal_col} = 0;
|
||||
# Figure out where to draw the small calendars
|
||||
my $extra_row = $self->{extra_row};
|
||||
if ($settings->{small_calendars} == 1) {
|
||||
if ($last_col <= 4 || ($last_col == 6 && $extra_row)) {
|
||||
$self->{prevcal_row} = $rows-1;
|
||||
$self->{prevcal_col} = 5;
|
||||
$self->{nextcal_row} = $rows-1;
|
||||
$self->{nextcal_col} = 6;
|
||||
} else {
|
||||
$self->{prevcal_row} = 0;
|
||||
$self->{prevcal_col} = 0;
|
||||
$self->{nextcal_row} = 0;
|
||||
$self->{nextcal_col} = 1;
|
||||
}
|
||||
} elsif ($settings->{small_calendars} == 2) {
|
||||
if ($first_col >= 2) {
|
||||
$self->{prevcal_row} = 0;
|
||||
$self->{prevcal_col} = 0;
|
||||
$self->{nextcal_row} = 0;
|
||||
$self->{nextcal_col} = 1;
|
||||
} else {
|
||||
$self->{prevcal_row} = $rows-1;
|
||||
$self->{prevcal_col} = 5;
|
||||
$self->{nextcal_row} = $rows-1;
|
||||
$self->{nextcal_col} = 6;
|
||||
}
|
||||
} elsif ($settings->{small_calendars} == 3) {
|
||||
if ($first_col >= 1 && $last_col <= 5) {
|
||||
$self->{prevcal_row} = 0;
|
||||
$self->{prevcal_col} = 0;
|
||||
$self->{nextcal_row} = $rows-1;
|
||||
$self->{nextcal_col} = 6;
|
||||
} else {
|
||||
if ($last_col <= 4 || ($last_col == 6 && $extra_row)) {
|
||||
$self->{prevcal_row} = $rows-1;
|
||||
$self->{prevcal_col} = 5;
|
||||
$self->{nextcal_row} = $rows-1;
|
||||
$self->{nextcal_col} = 6;
|
||||
} else {
|
||||
$self->{prevcal_row} = 0;
|
||||
$self->{prevcal_col} = 0;
|
||||
$self->{nextcal_row} = 0;
|
||||
$self->{nextcal_col} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $col = $first_col;
|
||||
my $row = 0;
|
||||
my $day = 1;
|
||||
while ($day <= $self->{daysinmonth}) {
|
||||
$self->{daymap}->[$row]->[$col] = $day;
|
||||
$day++;
|
||||
$col++;
|
||||
if ($col > 6) {
|
||||
$row++;
|
||||
$col = 0;
|
||||
}
|
||||
}
|
||||
|
||||
# Check if we should wrap the calendar
|
||||
if ($self->{rows} == 6 && $settings->{wrap_calendar}) {
|
||||
# Move everything in the last row to the first row
|
||||
my $occupied_col = 0;
|
||||
for (my $col=0; $col<7; $col++) {
|
||||
if ($self->{daymap}->[5]->[$col] > 0) {
|
||||
$self->{daymap}->[0]->[$col] = $self->{daymap}->[5]->[$col];
|
||||
$occupied_col = $col;
|
||||
} else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ($settings->{small_calendars}) {
|
||||
$self->{prevcal_row} = 0;
|
||||
$self->{prevcal_col} = $occupied_col+1;
|
||||
$self->{nextcal_row} = 0;
|
||||
$self->{nextcal_col} = $occupied_col+2;
|
||||
for (my $col = 6; $col > 0; $col--) {
|
||||
if ($self->{daymap}->[0]->[$col] < 0) {
|
||||
$self->{nextcal_col} = $col;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
$self->{rows} = 5;
|
||||
}
|
||||
}
|
||||
|
||||
=head2 read_one_month_pp($in, $specials_accepted)
|
||||
|
||||
This function reads one month's worth of data from the file handle
|
||||
@@ -329,6 +465,7 @@ sub render
|
||||
{
|
||||
my ($self, $cr, $settings) = @_;
|
||||
|
||||
$self->setup_daymap($settings);
|
||||
$self->{horiz_lines} = [];
|
||||
$cr->set_line_cap('square');
|
||||
my $so_far = $self->draw_title($cr, $settings);
|
||||
@@ -347,111 +484,25 @@ sub render
|
||||
$self->{remaining_space} = $settings->{height} - $settings->{margin_bottom} - $so_far;
|
||||
|
||||
$self->{minimum_row_height} = $self->{remaining_space} / 9;
|
||||
# First column
|
||||
my $first_col = $self->{firstwkday};
|
||||
if ($self->{mondayfirst}) {
|
||||
$first_col--;
|
||||
if ($first_col < 0) {
|
||||
$first_col = 6;
|
||||
}
|
||||
}
|
||||
|
||||
# Last column
|
||||
my $last_col = ($first_col + $self->{daysinmonth} - 1) % 7;
|
||||
|
||||
# Number of rows
|
||||
my $rows = 1;
|
||||
my $last_day_on_row = 7 - $first_col;
|
||||
while ($last_day_on_row < $self->{daysinmonth}) {
|
||||
$last_day_on_row += 7;
|
||||
$rows++;
|
||||
}
|
||||
|
||||
my $extra_row = 0;
|
||||
# Add a row for small calendars if necessary
|
||||
if (($settings->{small_calendars} != 0) && ($first_col == 0) && ($last_col == 6)) {
|
||||
$rows++;
|
||||
$extra_row++;
|
||||
}
|
||||
|
||||
# Figure out where to draw the small calendars
|
||||
my $prevcal_top = 0;
|
||||
my $nextcal_top = 0;
|
||||
my $prevcal_bottom = 0;
|
||||
my $nextcal_bottom = 0;
|
||||
|
||||
if ($settings->{small_calendars} == 1) {
|
||||
if ($last_col <= 4 || ($last_col == 6 && $extra_row)) {
|
||||
$prevcal_bottom = 1;
|
||||
$nextcal_bottom = 1;
|
||||
} else {
|
||||
$prevcal_top = 1;
|
||||
$nextcal_top = 1;
|
||||
}
|
||||
} elsif ($settings->{small_calendars} == 2) {
|
||||
if ($first_col >= 2) {
|
||||
$prevcal_top = 1;
|
||||
$nextcal_top = 1;
|
||||
} else {
|
||||
$prevcal_bottom = 1;
|
||||
$nextcal_bottom = 1;
|
||||
}
|
||||
} elsif ($settings->{small_calendars} == 3) {
|
||||
if ($first_col >= 1 && $last_col <= 5) {
|
||||
$prevcal_top = 1;
|
||||
$nextcal_bottom = 1;
|
||||
} else {
|
||||
if ($last_col <= 4 || ($last_col == 6 && $extra_row)) {
|
||||
$prevcal_bottom = 1;
|
||||
$nextcal_bottom = 1;
|
||||
} else {
|
||||
$prevcal_top = 1;
|
||||
$nextcal_top = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Row height if we are filling the page
|
||||
$self->{row_height} = $self->{remaining_space} / $rows;
|
||||
$self->{row_height} = $self->{remaining_space} / $self->{rows};
|
||||
|
||||
my ($start_col, $start_day);
|
||||
for (my $row = 0; $row < $rows; $row++) {
|
||||
if ($row == 0) {
|
||||
$start_day = 1;
|
||||
$start_col = $first_col;
|
||||
} else {
|
||||
$start_col = 0;
|
||||
}
|
||||
for (my $row = 0; $row < $self->{rows}; $row++) {
|
||||
my $old_so_far = $so_far;
|
||||
$so_far = $self->draw_row($cr, $settings, $so_far, $row, $start_day, $start_col);
|
||||
$start_day += 7 - $start_col;
|
||||
$so_far = $self->draw_row($cr, $settings, $so_far, $row);
|
||||
push(@{$self->{horiz_lines}}, $so_far);
|
||||
if ($row == 0) {
|
||||
if ($prevcal_top) {
|
||||
my ($x1, $y1, $x2, $y2) = $self->col_box_coordinates($old_so_far, 0, $so_far - $old_so_far, $settings);
|
||||
$self->draw_small_calendar($cr, $x1 + $settings->{border_size}, $y1 + $settings->{border_size},
|
||||
$x2 - $x1 - 2*$settings->{border_size}, $y2 - $y1 - 2*$settings->{border_size},
|
||||
$settings, $self->{prevmonthname}, $self->{daysinprevmonth}, ($first_col + 35 - $self->{daysinprevmonth}) % 7);
|
||||
}
|
||||
if ($nextcal_top) {
|
||||
my ($x1, $y1, $x2, $y2) = $self->col_box_coordinates($old_so_far, 1, $so_far - $old_so_far, $settings);
|
||||
$self->draw_small_calendar($cr, $x1 + $settings->{border_size}, $y1 + $settings->{border_size},
|
||||
$x2 - $x1 - 2*$settings->{border_size}, $y2 - $y1 - 2*$settings->{border_size},
|
||||
$settings, $self->{nextmonthname}, $self->{daysinnextmonth}, ($last_col + 1) % 7);
|
||||
}
|
||||
} elsif ($row == $rows-1) {
|
||||
if ($prevcal_bottom) {
|
||||
my ($x1, $y1, $x2, $y2) = $self->col_box_coordinates($old_so_far, 5, $so_far - $old_so_far, $settings);
|
||||
$self->draw_small_calendar($cr, $x1 + $settings->{border_size}, $y1 + $settings->{border_size},
|
||||
$x2 - $x1 - 2*$settings->{border_size}, $y2 - $y1 - 2*$settings->{border_size},
|
||||
$settings, $self->{prevmonthname}, $self->{daysinprevmonth}, ($first_col + 35 - $self->{daysinprevmonth}) % 7);
|
||||
}
|
||||
if ($nextcal_bottom) {
|
||||
my ($x1, $y1, $x2, $y2) = $self->col_box_coordinates($old_so_far, 6, $so_far - $old_so_far, $settings);
|
||||
$self->draw_small_calendar($cr, $x1 + $settings->{border_size}, $y1 + $settings->{border_size},
|
||||
$x2 - $x1 - 2*$settings->{border_size}, $y2 - $y1 - 2*$settings->{border_size},
|
||||
$settings, $self->{nextmonthname}, $self->{daysinnextmonth}, ($last_col + 1) % 7);
|
||||
}
|
||||
if ($row == $self->{prevcal_row}) {
|
||||
my ($x1, $y1, $x2, $y2) = $self->col_box_coordinates($old_so_far, $self->{prevcal_col}, $so_far - $old_so_far, $settings);
|
||||
$self->draw_small_calendar($cr, $x1 + $settings->{border_size}, $y1 + $settings->{border_size},
|
||||
$x2 - $x1 - 2*$settings->{border_size}, $y2 - $y1 - 2*$settings->{border_size},
|
||||
$settings, $self->{prevmonthname}, $self->{daysinprevmonth}, ($self->{first_col} + 35 - $self->{daysinprevmonth}) % 7);
|
||||
}
|
||||
if ($row == $self->{nextcal_row}) {
|
||||
my ($x1, $y1, $x2, $y2) = $self->col_box_coordinates($old_so_far, $self->{nextcal_col}, $so_far - $old_so_far, $settings);
|
||||
$self->draw_small_calendar($cr, $x1 + $settings->{border_size}, $y1 + $settings->{border_size},
|
||||
$x2 - $x1 - 2*$settings->{border_size}, $y2 - $y1 - 2*$settings->{border_size},
|
||||
$settings, $self->{nextmonthname}, $self->{daysinnextmonth}, ($self->{last_col} + 1) % 7);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,23 +546,18 @@ calendar row.
|
||||
=cut
|
||||
sub draw_row
|
||||
{
|
||||
my ($self, $cr, $settings, $so_far, $row, $start_day, $start_col) = @_;
|
||||
my ($self, $cr, $settings, $so_far, $row) = @_;
|
||||
|
||||
my $col = $start_col;
|
||||
my $day = $start_day;
|
||||
my $height = 0;
|
||||
|
||||
# Preview them to figure out the row height...
|
||||
if (!$settings->{fill_entire_page}) {
|
||||
while ($col < 7) {
|
||||
for (my $col=0; $col<7; $col++) {
|
||||
my $day = $self->{daymap}->[$row]->[$col];
|
||||
next if ($day < 1);
|
||||
my $h = $self->draw_day($cr, $settings, $so_far, $day, $col, 0);
|
||||
$height = $h if ($h > $height);
|
||||
$day++;
|
||||
$col++;
|
||||
last if ($day > $self->{daysinmonth});
|
||||
}
|
||||
$col = $start_col;
|
||||
$day = $start_day;
|
||||
} else {
|
||||
$height = $self->{row_height} - $settings->{border_size} * 2;
|
||||
}
|
||||
@@ -520,10 +566,10 @@ sub draw_row
|
||||
$height = $self->{minimum_row_height};
|
||||
}
|
||||
# Now draw for real
|
||||
while ($col < 7 && $day <= $self->{daysinmonth}) {
|
||||
for (my $col=0; $col<7; $col++) {
|
||||
my $day = $self->{daymap}->[$row]->[$col];
|
||||
next if ($day < 1);
|
||||
$self->draw_day($cr, $settings, $so_far, $day, $col, $height);
|
||||
$day++;
|
||||
$col++;
|
||||
}
|
||||
|
||||
return $so_far + $height + $settings->{border_size};
|
||||
@@ -908,7 +954,7 @@ sub create_from_stream
|
||||
return(undef, 'Unable to parse JSON stream');
|
||||
}
|
||||
|
||||
=head2 Remind::PDF::Multi->create_from_stream($json, $specials_accepted)
|
||||
=head2 Remind::PDF::Multi->create_from_json($json, $specials_accepted)
|
||||
|
||||
This method takes data from a JSON string <$json>. C<$specials_accepted>
|
||||
is a hashref of SPECIAL reminder types to accept; the key is the name of the
|
||||
|
||||
@@ -240,6 +240,9 @@ set Option(PrintOrient) landscape
|
||||
set OptDescr(PrintFill) "(0/1) If 1, fill entire page when printing"
|
||||
set Option(PrintFill) 1
|
||||
|
||||
set OptDescr(WrapCal) "(0/1) If 1, make printed calendars occupy at most 5 rows"
|
||||
set Option(WrapCal) 0
|
||||
|
||||
set OptDescr(PrintDaysRight) "(0/1) If 1, put day numbers in the top-right of each calendar box"
|
||||
set Option(PrintDaysRight) 1
|
||||
|
||||
@@ -1290,6 +1293,7 @@ proc DoPrint {} {
|
||||
radiobutton .p.portrait -text "Portrait" -variable Option(PrintOrient) -value portrait
|
||||
|
||||
checkbutton .p.fill -text "Fill page" -variable Option(PrintFill)
|
||||
checkbutton .p.wrap -text "Use at most 5 rows (PDF only)" -variable Option(WrapCal)
|
||||
checkbutton .p.right -text "Day numbers at top-right" -variable Option(PrintDaysRight)
|
||||
checkbutton .p.encoding -text "ISO 8859-1 PostScript encoding" -variable Option(PrintEncoding)
|
||||
checkbutton .p.calendars -text "Print small calendars" -variable Option(PrintSmallCalendars)
|
||||
@@ -1300,12 +1304,14 @@ proc DoPrint {} {
|
||||
if {$HaveRem2PDF} {
|
||||
pack .p.f1 .p.ff .p.f2 .p.f2a .p.f3 .p.f3a \
|
||||
-side top -fill both -expand 1 -anchor w
|
||||
pack .p.fill .p.wrap .p.right .p.encoding .p.calendars -in .p.f3a \
|
||||
-side top -anchor w -fill none -expand 0
|
||||
} else {
|
||||
pack .p.f1 .p.f2 .p.f2a .p.f3 .p.f3a \
|
||||
-side top -fill both -expand 1 -anchor w
|
||||
}
|
||||
pack .p.fill .p.right .p.encoding .p.calendars -in .p.f3a \
|
||||
pack .p.fill .p.right .p.encoding .p.calendars -in .p.f3a \
|
||||
-side top -anchor w -fill none -expand 0
|
||||
}
|
||||
pack .p.f4 -side top -fill both -expand 1 -anchor w
|
||||
pack .p.f11 .p.f12 -in .p.f1 -side top -fill none -expand 0 -anchor w
|
||||
pack .p.tofile .p.filename .p.browse -in .p.f11 -side left -fill none -expand 0 -anchor w
|
||||
@@ -1398,6 +1404,11 @@ proc DoPrint {} {
|
||||
}
|
||||
}
|
||||
|
||||
if {$Option(WrapCal)} {
|
||||
if {$Option(PrintFormat) == "pdf"} {
|
||||
append cmd " --wrap"
|
||||
}
|
||||
}
|
||||
if {$Option(PrintOrient) == "landscape"} {
|
||||
append cmd " -l"
|
||||
}
|
||||
@@ -3326,7 +3337,9 @@ proc EditableEnter { w } {
|
||||
set c [$w tag cget $ctag -foreground]
|
||||
}
|
||||
if {"$c" != ""} {
|
||||
$w tag configure $tag -underline 1 -underlinefg $c
|
||||
$w tag configure $tag -underline 1
|
||||
# underlinefg not supported on older versions of Tk
|
||||
eval { $w tag configure $tag -underlinefg $c }
|
||||
} else {
|
||||
$w tag configure $tag -underline 1
|
||||
}
|
||||
@@ -3633,7 +3646,9 @@ proc DoShadeSpecial { n r g b } {
|
||||
#***********************************************************************
|
||||
proc DoMoonSpecial { n stuff fntag day } {
|
||||
set msg ""
|
||||
set num [scan $stuff "%d %d %d %s" phase junk1 junk2 msg]
|
||||
# Yes, this is gross, but the odds of ctrl-A appearing
|
||||
# in the text associated with a MOON are small.
|
||||
set num [scan $stuff {%d %d %d %[^]} phase junk1 junk2 msg]
|
||||
if {$num < 1} {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1830,6 +1830,10 @@ static int DoCalRem(ParsePtr p, int col)
|
||||
DBufFree(&buf);
|
||||
}
|
||||
trig.typ = tok.val;
|
||||
|
||||
/* Convert some SPECIALs back to plain types */
|
||||
FixSpecialType(&trig);
|
||||
|
||||
if (trig.typ == MSG_TYPE ||
|
||||
trig.typ == CAL_TYPE ||
|
||||
trig.typ == MSF_TYPE) {
|
||||
|
||||
56
src/dorem.c
56
src/dorem.c
@@ -123,8 +123,12 @@ int DoRem(ParsePtr p)
|
||||
}
|
||||
StrnCpy(trig.passthru, DBufValue(&buf), PASSTHRU_LEN);
|
||||
DBufFree(&buf);
|
||||
}
|
||||
trig.typ = tok.val;
|
||||
}
|
||||
trig.typ = tok.val;
|
||||
|
||||
/* Convert some SPECIALs back to plain types */
|
||||
FixSpecialType(&trig);
|
||||
|
||||
dse = LastTriggerDate;
|
||||
if (!LastTrigValid || PurgeMode) {
|
||||
FreeTrig(&trig);
|
||||
@@ -188,7 +192,7 @@ int DoRem(ParsePtr p)
|
||||
|
||||
r = OK;
|
||||
if (ShouldTriggerReminder(&trig, &tim, dse, &err)) {
|
||||
if ( (r=TriggerReminder(p, &trig, &tim, dse)) ) {
|
||||
if ( (r=TriggerReminder(p, &trig, &tim, dse, 0)) ) {
|
||||
FreeTrig(&trig);
|
||||
return r;
|
||||
}
|
||||
@@ -370,6 +374,7 @@ int ParseRem(ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals)
|
||||
}
|
||||
StrnCpy(trig->passthru, DBufValue(&buf), PASSTHRU_LEN);
|
||||
}
|
||||
FixSpecialType(trig);
|
||||
parsing = 0;
|
||||
break;
|
||||
|
||||
@@ -893,7 +898,7 @@ static int ParseScanFrom(ParsePtr s, Trigger *t, int type)
|
||||
/* Trigger the reminder if it's a RUN or MSG type. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse)
|
||||
int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued)
|
||||
{
|
||||
int r, y, m, d;
|
||||
char PrioExpr[VAR_NAME_LEN+25];
|
||||
@@ -901,8 +906,21 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse)
|
||||
DynamicBuffer buf, calRow;
|
||||
DynamicBuffer pre_buf;
|
||||
char const *s;
|
||||
char const *msg_command = NULL;
|
||||
Value v;
|
||||
|
||||
if (MsgCommand) {
|
||||
msg_command = MsgCommand;
|
||||
}
|
||||
if (is_queued && QueuedMsgCommand) {
|
||||
msg_command = QueuedMsgCommand;
|
||||
}
|
||||
|
||||
/* A null command is no command */
|
||||
if (msg_command && !*msg_command) {
|
||||
msg_command = NULL;
|
||||
}
|
||||
|
||||
int red = -1, green = -1, blue = -1;
|
||||
int is_color = 0;
|
||||
|
||||
@@ -947,7 +965,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse)
|
||||
}
|
||||
/* If it's a MSG-type reminder, and no -k option was used, issue the banner. */
|
||||
if ((t->typ == MSG_TYPE || t->typ == MSF_TYPE)
|
||||
&& !DidMsgReminder && !NextMode && !MsgCommand) {
|
||||
&& !DidMsgReminder && !NextMode && !msg_command) {
|
||||
DidMsgReminder = 1;
|
||||
if (!DoSubstFromString(DBufValue(&Banner), &buf,
|
||||
DSEToday, NO_TIME) &&
|
||||
@@ -1091,7 +1109,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse)
|
||||
DBufPuts(&buf, Decolorize());
|
||||
}
|
||||
|
||||
if ((!MsgCommand && t->typ == MSG_TYPE) || t->typ == MSF_TYPE) {
|
||||
if ((!msg_command && t->typ == MSG_TYPE) || t->typ == MSF_TYPE) {
|
||||
if (DBufPutc(&buf, '\n') != OK) {
|
||||
DBufFree(&buf);
|
||||
return E_NO_MEM;
|
||||
@@ -1113,8 +1131,8 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int dse)
|
||||
switch(t->typ) {
|
||||
case MSG_TYPE:
|
||||
case PASSTHRU_TYPE:
|
||||
if (MsgCommand) {
|
||||
DoMsgCommand(MsgCommand, DBufValue(&buf));
|
||||
if (msg_command) {
|
||||
DoMsgCommand(msg_command, DBufValue(&buf));
|
||||
} else {
|
||||
printf("%s", DBufValue(&buf));
|
||||
}
|
||||
@@ -1466,3 +1484,25 @@ static int ShouldTriggerBasedOnWarn(Trigger *t, int dse, int *err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FixSpecialType(Trigger *t)
|
||||
{
|
||||
if (t->typ != PASSTHRU_TYPE) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert SPECIAL MSG / MSF / RUN / CAL to just plain MSG / MSF / etc */
|
||||
if (!StrCmpi(t->passthru, "MSG")) {
|
||||
t->typ = MSG_TYPE;
|
||||
} else if (!StrCmpi(t->passthru, "MSF")) {
|
||||
t->typ = MSF_TYPE;
|
||||
} else if (!StrCmpi(t->passthru, "RUN")) {
|
||||
t->typ = RUN_TYPE;
|
||||
} else if (!StrCmpi(t->passthru, "CAL")) {
|
||||
t->typ = CAL_TYPE;
|
||||
} else if (!StrCmpi(t->passthru, "PS")) {
|
||||
t->typ = PS_TYPE;
|
||||
} else if (!StrCmpi(t->passthru, "PSFILE")) {
|
||||
t->typ = PSF_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
||||
mode != CAL_MODE &&
|
||||
mode != ADVANCE_MODE &&
|
||||
t->typ != RUN_TYPE &&
|
||||
!MsgCommand) {
|
||||
!(MsgCommand && *MsgCommand)) {
|
||||
if (DBufPutc(dbuf, '\n') != OK) return E_NO_MEM;
|
||||
}
|
||||
break;
|
||||
@@ -794,7 +794,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
||||
break;
|
||||
|
||||
case '_':
|
||||
if (PsCal == PSCAL_LEVEL2 || PsCal == PSCAL_LEVEL3 || (mode != CAL_MODE && mode != ADVANCE_MODE && !MsgCommand)) {
|
||||
if (PsCal == PSCAL_LEVEL2 || PsCal == PSCAL_LEVEL3 || (mode != CAL_MODE && mode != ADVANCE_MODE && !(MsgCommand && *MsgCommand))) {
|
||||
snprintf(s, sizeof(s), "%s", NL);
|
||||
} else {
|
||||
snprintf(s, sizeof(s), " ");
|
||||
|
||||
115
src/funcs.c
115
src/funcs.c
@@ -101,6 +101,8 @@ static int FHebday (func_info *);
|
||||
static int FHebmon (func_info *);
|
||||
static int FHebyear (func_info *);
|
||||
static int FHour (func_info *);
|
||||
static int FHtmlEscape (func_info *);
|
||||
static int FHtmlStriptags (func_info *);
|
||||
static int FIif (func_info *);
|
||||
static int FIndex (func_info *);
|
||||
static int FIsdst (func_info *);
|
||||
@@ -265,6 +267,8 @@ BuiltinFunc Func[] = {
|
||||
{ "hebmon", 1, 1, 0, FHebmon },
|
||||
{ "hebyear", 1, 1, 0, FHebyear },
|
||||
{ "hour", 1, 1, 1, FHour },
|
||||
{ "htmlescape", 1, 1, 1, FHtmlEscape },
|
||||
{ "htmlstriptags",1, 1, 1, FHtmlStriptags },
|
||||
{ "iif", 1, NO_MAX, 1, FIif },
|
||||
{ "index", 2, 3, 1, FIndex },
|
||||
{ "isany", 1, NO_MAX, 1, FIsAny },
|
||||
@@ -914,9 +918,14 @@ static int FAbs(func_info *info)
|
||||
|
||||
ASSERT_TYPE(0, INT_TYPE);
|
||||
v = ARGV(0);
|
||||
if (v == INT_MIN) return E_2HIGH;
|
||||
|
||||
RetVal.type = INT_TYPE;
|
||||
RETVAL = (v < 0) ? (-v) : v;
|
||||
v = RETVAL;
|
||||
|
||||
/* The following test is probably redundant given the test
|
||||
for v == INT_MIN above, but I'll leave it in just in case. */
|
||||
if (v < 0) return E_2HIGH;
|
||||
return OK;
|
||||
}
|
||||
@@ -1162,15 +1171,27 @@ static int FPad(func_info *info)
|
||||
if (Nargs < 4 || !ARGV(3)) {
|
||||
/* Pad on the LEFT */
|
||||
for (i=0; i<wantlen-len; i++) {
|
||||
DBufPutc(&dbuf, *s++);
|
||||
if (DBufPutc(&dbuf, *s++) != OK) {
|
||||
DBufFree(&dbuf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
if (!*s) s = ARGSTR(1);
|
||||
}
|
||||
DBufPuts(&dbuf, ARGSTR(0));
|
||||
if (DBufPuts(&dbuf, ARGSTR(0)) != OK) {
|
||||
DBufFree(&dbuf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
} else {
|
||||
/* Pad on the RIGHT */
|
||||
DBufPuts(&dbuf, ARGSTR(0));
|
||||
if (DBufPuts(&dbuf, ARGSTR(0)) != OK) {
|
||||
DBufFree(&dbuf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
for (i=0; i<wantlen-len; i++) {
|
||||
DBufPutc(&dbuf, *s++);
|
||||
if (DBufPutc(&dbuf, *s++) != OK) {
|
||||
DBufFree(&dbuf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
if (!*s) s = ARGSTR(1);
|
||||
}
|
||||
}
|
||||
@@ -2243,6 +2264,92 @@ static int FHebyear(func_info *info)
|
||||
RETVAL = y;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* htmlescape - replace <. > and & by < > and & */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
static int FHtmlEscape(func_info *info)
|
||||
{
|
||||
DynamicBuffer dbuf;
|
||||
char const *s;
|
||||
int r;
|
||||
|
||||
ASSERT_TYPE(0, STR_TYPE);
|
||||
|
||||
DBufInit(&dbuf);
|
||||
|
||||
s = ARGSTR(0);
|
||||
while(*s) {
|
||||
switch(*s) {
|
||||
case '<':
|
||||
r = DBufPuts(&dbuf, "<");
|
||||
break;
|
||||
|
||||
case '>':
|
||||
r = DBufPuts(&dbuf, ">");
|
||||
break;
|
||||
|
||||
case '&':
|
||||
r = DBufPuts(&dbuf, "&");
|
||||
break;
|
||||
|
||||
default:
|
||||
r = DBufPutc(&dbuf, *s);
|
||||
break;
|
||||
}
|
||||
if (r != OK) {
|
||||
DBufFree(&dbuf);
|
||||
return r;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
r = RetStrVal(DBufValue(&dbuf), info);
|
||||
DBufFree(&dbuf);
|
||||
return r;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* htmlstriptags - strip out HTML tags from a string */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
static int FHtmlStriptags(func_info *info)
|
||||
{
|
||||
DynamicBuffer dbuf;
|
||||
char const *s;
|
||||
int r = OK;
|
||||
|
||||
int in_tag = 0;
|
||||
ASSERT_TYPE(0, STR_TYPE);
|
||||
|
||||
DBufInit(&dbuf);
|
||||
|
||||
s = ARGSTR(0);
|
||||
while(*s) {
|
||||
if (!in_tag) {
|
||||
if (*s == '<') {
|
||||
in_tag = 1;
|
||||
} else {
|
||||
r = DBufPutc(&dbuf, *s);
|
||||
}
|
||||
} else {
|
||||
if (*s == '>') {
|
||||
in_tag = 0;
|
||||
}
|
||||
}
|
||||
if (r != OK) {
|
||||
DBufFree(&dbuf);
|
||||
return r;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
r = RetStrVal(DBufValue(&dbuf), info);
|
||||
DBufFree(&dbuf);
|
||||
return r;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* FEasterdate - calc. easter Sunday from a year. */
|
||||
|
||||
@@ -52,6 +52,7 @@ EXTERN uid_t TrustedUsers[MAX_TRUSTED_USERS];
|
||||
|
||||
EXTERN INIT( int NumTrustedUsers, 0);
|
||||
EXTERN INIT( char const *MsgCommand, NULL);
|
||||
EXTERN INIT( char const *QueuedMsgCommand, NULL);
|
||||
EXTERN INIT( int ShowAllErrors, 0);
|
||||
EXTERN INIT( int DebugFlag, 0);
|
||||
EXTERN INIT( int DoCalendar, 0);
|
||||
|
||||
@@ -600,7 +600,12 @@ void InitRemind(int argc, char const *argv[])
|
||||
|
||||
case 'k':
|
||||
case 'K':
|
||||
MsgCommand = arg;
|
||||
if (*arg == ':') {
|
||||
arg++;
|
||||
QueuedMsgCommand = arg;
|
||||
} else {
|
||||
MsgCommand = arg;
|
||||
}
|
||||
while (*arg) arg++; /* Chew up remaining chars in this arg */
|
||||
break;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ int DoRem (ParsePtr p);
|
||||
int DoFlush (ParsePtr p);
|
||||
void DoExit (ParsePtr p);
|
||||
int ParseRem (ParsePtr s, Trigger *trig, TimeTrig *tim, int save_in_globals);
|
||||
int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int dse);
|
||||
int TriggerReminder (ParsePtr p, Trigger *t, TimeTrig *tim, int dse, int is_queued);
|
||||
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);
|
||||
@@ -177,6 +177,7 @@ int push_call(char const *filename, char const *func, int lineno);
|
||||
void clear_callstack(void);
|
||||
int print_callstack(FILE *fp);
|
||||
void pop_call(void);
|
||||
void FixSpecialType(Trigger *trig);
|
||||
#ifdef REM_USE_WCHAR
|
||||
#define _XOPEN_SOURCE 600
|
||||
#include <wctype.h>
|
||||
|
||||
@@ -267,7 +267,7 @@ void HandleQueuedReminders(void)
|
||||
/* Set up global variables so some functions like trigdate()
|
||||
and trigtime() work correctly */
|
||||
SaveAllTriggerInfo(&(q->t), &(q->tt), DSEToday, q->tt.ttime, 1);
|
||||
(void) TriggerReminder(&p, &trig, &q->tt, DSEToday);
|
||||
(void) TriggerReminder(&p, &trig, &q->tt, DSEToday, 1);
|
||||
if (Daemon < 0) {
|
||||
printf("NOTE endreminder\n");
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ void IssueSortedReminders(void)
|
||||
next = cur->next;
|
||||
switch(cur->typ) {
|
||||
case MSG_TYPE:
|
||||
if (MsgCommand) {
|
||||
if (MsgCommand && *MsgCommand) {
|
||||
DoMsgCommand(MsgCommand, cur->text);
|
||||
} else {
|
||||
if (cur->trigdate != olddate) {
|
||||
|
||||
@@ -124,7 +124,11 @@ int DoFset(ParsePtr p)
|
||||
DBufFree(&buf);
|
||||
return E_NO_MEM;
|
||||
}
|
||||
func->filename = StrDup(FileName);
|
||||
if (FileName) {
|
||||
func->filename = StrDup(FileName);
|
||||
} else {
|
||||
func->filename = StrDup("[cmdline]");
|
||||
}
|
||||
if (!func->filename) {
|
||||
free(func);
|
||||
return E_NO_MEM;
|
||||
|
||||
@@ -27,6 +27,10 @@ if test `id -u` = 0 ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set a known timezone so moon phases show up in predictable places
|
||||
TZ=UTC
|
||||
export TZ
|
||||
|
||||
# If we're already in a utf-8 locale, do
|
||||
# nothing; otherwise, set LC_ALL
|
||||
OK=0
|
||||
@@ -418,6 +422,9 @@ chmod 0777 include_dir/ww
|
||||
../src/remind include_dir/ww >> ../tests/test.out 2>&1
|
||||
rm -rf include_dir/ww
|
||||
|
||||
# This segfaulted in 04.02.03
|
||||
../src/remind -h '-imsgprefix(x)="foo"' /dev/null >> ../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
|
||||
cmp -s ../tests/test.out ../tests/test.cmp
|
||||
@@ -428,7 +435,11 @@ else
|
||||
echo "Remind: Acceptance test FAILED"
|
||||
echo ""
|
||||
echo "Examine the file test.out to see where it differs from the"
|
||||
echo "reference file test.cmp."
|
||||
echo "reference file test.cmp. Here are the first 200 lines of"
|
||||
echo "diff -u test.out test.cmp"
|
||||
echo ""
|
||||
diff -u ../tests/test.out ../tests/test.cmp | head -n 200
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -1060,7 +1060,7 @@ set a057 value("a05"+"6")
|
||||
"a05" + "6" => "a056"
|
||||
value("a056") => "SDFJHSDF KSJDFH KJSDFH KSJDFH"
|
||||
set a058 version()
|
||||
version() => "04.02.02"
|
||||
version() => "04.02.04"
|
||||
set a059 wkday(today())
|
||||
today() => 1991-02-16
|
||||
wkday(1991-02-16) => "Saturday"
|
||||
@@ -2644,7 +2644,7 @@ a086 4
|
||||
a109 2012-01-01
|
||||
a128 2018-02-03@16:45
|
||||
a039 "February"
|
||||
a058 "04.02.02"
|
||||
a058 "04.02.04"
|
||||
a077 "1992 92\n"
|
||||
a096 -4
|
||||
a119 -1
|
||||
@@ -4786,6 +4786,41 @@ FUNSET circle square rectangle
|
||||
SET a square(5)
|
||||
../tests/test.rem(867): Undefined function: `square'
|
||||
|
||||
# htmlescape
|
||||
set a htmlescape("foo")
|
||||
htmlescape("foo") => "foo"
|
||||
REM MSG [a]
|
||||
../tests/test.rem(871): Trig = Saturday, 16 February, 1991
|
||||
a => "foo"
|
||||
foo
|
||||
|
||||
set a htmlescape("<&>")
|
||||
htmlescape("<&>") => "<&>"
|
||||
REM MSG [a]
|
||||
../tests/test.rem(873): Trig = Saturday, 16 February, 1991
|
||||
a => "<&>"
|
||||
<&>
|
||||
|
||||
set a htmlescape("@&^#*@&^##$*&@><><@#@#><@#>%%_#$foobarquux")
|
||||
htmlescape("@&^#*@&^##$*&@><><@#@#><@#>%%_#$foobarqu"...) => "@&^#*@&^##$*&@><>&l"...
|
||||
REM MSG [a]
|
||||
../tests/test.rem(875): Trig = Saturday, 16 February, 1991
|
||||
a => "@&^#*@&^##$*&@><>&l"...
|
||||
@&^#*@&^##$*&@><><@#@#><@#>%_#$foobarquux
|
||||
|
||||
|
||||
# htmlstriptags
|
||||
set a htmlstriptags("foobar")
|
||||
htmlstriptags("foobar") => "foobar"
|
||||
set a htmlstriptags("This is <b>bold</b>")
|
||||
htmlstriptags("This is <b>bold</b>") => "This is bold"
|
||||
set a htmlstriptags("This is <unclosed whut?")
|
||||
htmlstriptags("This is <unclosed whut?") => "This is "
|
||||
set a htmlstriptags("this is > whut <b>foo</b>")
|
||||
htmlstriptags("this is > whut <b>foo</b>") => "this is > whut foo"
|
||||
set a htmlstriptags("<img src=\"foo\">")
|
||||
htmlstriptags("<img src=\"foo\">") => ""
|
||||
|
||||
# Don't want Remind to queue reminders
|
||||
EXIT
|
||||
|
||||
|
||||
@@ -866,6 +866,21 @@ FUNSET circle square rectangle
|
||||
# Should fail
|
||||
SET a square(5)
|
||||
|
||||
# htmlescape
|
||||
set a htmlescape("foo")
|
||||
REM MSG [a]
|
||||
set a htmlescape("<&>")
|
||||
REM MSG [a]
|
||||
set a htmlescape("@&^#*@&^##$*&@><><@#@#><@#>%%_#$foobarquux")
|
||||
REM MSG [a]
|
||||
|
||||
# htmlstriptags
|
||||
set a htmlstriptags("foobar")
|
||||
set a htmlstriptags("This is <b>bold</b>")
|
||||
set a htmlstriptags("This is <unclosed whut?")
|
||||
set a htmlstriptags("this is > whut <b>foo</b>")
|
||||
set a htmlstriptags("<img src=\"foo\">")
|
||||
|
||||
# Don't want Remind to queue reminders
|
||||
EXIT
|
||||
|
||||
|
||||
Reference in New Issue
Block a user