Compare commits

...

20 Commits

Author SHA1 Message Date
Dianne Skoll
5258e98f54 Add translations for various astronomical events in German localization, courtesy of Gunther Reißig. 2022-10-12 08:39:02 -04:00
Dianne Skoll
af9d42721c Separate Sun from Moon output. 2022-10-11 15:44:19 -04:00
Dianne Skoll
8ed43f5c3e Update WHATSNEW 2022-10-11 14:19:32 -04:00
Dianne Skoll
ec02a87c2b Fix some bugs in US holidays. 2022-10-11 14:19:00 -04:00
Dianne Skoll
6c2ec04d40 Visual tweaks. 2022-10-11 13:57:00 -04:00
Dianne Skoll
9f91cdf0b9 Update WHATSNEW. 2022-10-11 13:23:55 -04:00
Dianne Skoll
8ada68ce54 Add the "columns(str)" variant. 2022-10-11 13:18:44 -04:00
Dianne Skoll
d7975634af Update WHATSNEW 2022-10-11 11:56:41 -04:00
Dianne Skoll
87be68fecf Document rows() and columns() 2022-10-11 11:54:52 -04:00
Dianne Skoll
b42d5fd412 Add rows() and columns() built-in function. 2022-10-11 11:52:35 -04:00
Dianne Skoll
603228b944 Update prerequisite list. 2022-10-11 10:41:57 -04:00
Dianne Skoll
c62f676813 Diagnose unterminated %{...} sequence 2022-10-11 10:35:31 -04:00
Dianne Skoll
c7654c27a6 Update WHATSNEW. 2022-10-11 09:16:04 -04:00
Dianne Skoll
b00bf05fea Add test for %{custom} substitution. 2022-10-11 09:14:47 -04:00
Dianne Skoll
29bd07d4ef Document %{name} substitution sequences. 2022-10-11 09:11:12 -04:00
Dianne Skoll
b7047da89e Allow user-defined substitutions of the form: %{name} or %*{name} that call subst_name. 2022-10-11 09:07:08 -04:00
Dianne Skoll
f26334e25f Add doc about %_ to insert a blank line if $AddBlankLines is 0. 2022-10-11 08:31:13 -04:00
Dianne Skoll
b80bc5f788 Test that ending a reminder with %_ does add a blank line. 2022-10-11 08:30:17 -04:00
Dianne Skoll
91549e18ce Make use of $AddBlankLines 2022-10-10 22:52:48 -04:00
Dianne Skoll
07fd975935 Add the $AddBlankLines system variable. 2022-10-10 22:49:28 -04:00
20 changed files with 442 additions and 38 deletions

21
README
View File

@@ -34,5 +34,26 @@ If you do NOT have Tcl/Tk or are NOT running X Windows:
5) Type: "make install" -- you may need to be root to do this.
PREREQUISITES:
--------------
Remind and rem2ps have no prerequisites beyond the standard C library and
the standard math library.
Rem2HTML requires the JSON::MaybeXS Perl module; on Debian-like
systems, you can install that with:
apt install libjson-maybexs-perl
Rem2PDF requires the JSON::MaybeXS, Pango and Cairo Perl modules. On
Debian-like systems, install with:
apt install libjson-maybexs-perl libpango-perl libcairo-perl
TkRemind requires Tcl/Tk and the tcllib library. On Debian-like systems
install with:
apt install tcl tk tcllib
Contact info: mailto:dianne@skoll.ca
Home page: https://dianne.skoll.ca/projects/remind/

View File

@@ -21,6 +21,20 @@ CHANGES TO REMIND
- NEW FEATURE: remind: Add trigtags() function per suggestion from Tim Chase.
- NEW FEATURE: remind: The $AddBlankLines system variable controls whether or
not a blank line is added after each reminder.
- NEW FEATURE: remind: The built-in functions columns() and rows() return the
width and height of the terminal (in character positions) respectively.
- NEW FEATURE: remind: The built-in function columns("string") returns the
number of columns occupied by "string" on the terminal, taking into account
double-width Unicode characters and zero-width ANSI escape sequences.
- NEW FEATURE: remind: You can add custom substitution sequences of the form
%{name} or %*{name} that end up calling the function subst_name and using
its return value as the replacement for the substitution sequence.
- BUG FIX: remind: Make MSF correctly format UTF-8 text and text with
embedded ANSI color-changing codes.
@@ -32,6 +46,9 @@ CHANGES TO REMIND
- BUG FIX: Fix tests in non-UTF-8 locales.
- BUG FIX: Fix a few problems with the include include/holidays/us.rem
file.
* VERSION 4.1 Patch 0 - 2022-09-25
- NEW FEATURE: remind: "remind -c" now supports the MOON special, printing

18
examples/alignment.rem Normal file
View File

@@ -0,0 +1,18 @@
# Demo the columns() function
#
# Run as: remind -@2 alignment.rem
SET $AddBlankLines 0
BANNER %
FSET center(x) pad("", " ", (columns() - columns(x))/2) + x
FSET right(x) pad("", " ", columns() - columns(x)) + x
MSG This is left-aligned.
MSG [ansicolor(0,255,0)]This is also left-aligned.[ansicolor("")]
MSG [center("This is centered.")]
MSG [ansicolor(255,255,0) + center("🌕 🌕 🌕 🌕 This is also centered. ") + ansicolor("")]
msg [right("This is right-aligned.")]
msg [ansicolor(255,0,0) + right("This is also right-aligned. 🌕 🌕 🌕") + ansicolor("")]

View File

@@ -9,24 +9,26 @@ remind -g -@2 - <<'EOF'
# it is light.
SET bg_dark 1
SET $AddBlankLines 0
BANNER %
IF bg_dark
SPECIAL COLOR 255 255 0 Sunrise: 🌅 [sunrise()] today and [sunrise(today()+1)] tomorrow%
SPECIAL COLOR 255 128 0 Sunset: 🌇 [sunset()] today and [sunset(today()+1)] tomorrow%
SPECIAL COLOR 255 255 0 Sunrise: 🌅 [sunrise()] today and [sunrise(today()+1)] tomorrow
SPECIAL COLOR 255 128 0 Sunset: 🌇 [sunset()] today and [sunset(today()+1)] tomorrow%_
REM [moondate(0)] +60 SPECIAL COLOR 255 255 0 New moon: 🌑 [moondate(0)] (%b)%
REM [moondate(1)] +60 SPECIAL COLOR 255 255 128 First Quarter: 🌓 [moondate(1)] (%b)%
REM [moondate(2)] +60 SPECIAL COLOR 255 255 255 Full moon: 🌕 [moondate(2)] (%b)%
REM [moondate(3)] +60 SPECIAL COLOR 255 255 128 Last Quarter: 🌗 [moondate(3)] (%b)%
REM [moondate(0)] +60 SPECIAL COLOR 255 255 0 New moon: 🌑 [moondate(0)] (%b)
REM [moondate(1)] +60 SPECIAL COLOR 255 255 128 First Quarter: 🌓 [moondate(1)] (%b)
REM [moondate(2)] +60 SPECIAL COLOR 255 255 255 Full moon: 🌕 [moondate(2)] (%b)
REM [moondate(3)] +60 SPECIAL COLOR 255 255 128 Last Quarter: 🌗 [moondate(3)] (%b)
ELSE
SPECIAL COLOR 128 128 0 Sunrise: 🌅 [sunrise()] today and [sunrise(today()+1)] tomorrow%
SPECIAL COLOR 128 32 0 Sunset: 🌇 [sunset()] today and [sunset(today()+1)] tomorrow%
SPECIAL COLOR 128 128 0 Sunrise: 🌅 [sunrise()] today and [sunrise(today()+1)] tomorrow
SPECIAL COLOR 128 32 0 Sunset: 🌇 [sunset()] today and [sunset(today()+1)] tomorrow%_
REM [moondate(0)] +60 SPECIAL COLOR 128 128 0 New moon: 🌑 [moondate(0)] (%b)%
REM [moondate(1)] +60 SPECIAL COLOR 128 128 64 First Quarter: 🌓 [moondate(1)] (%b)%
REM [moondate(2)] +60 SPECIAL COLOR 0 0 0 Full moon: 🌕 [moondate(2)] (%b)%
REM [moondate(3)] +60 SPECIAL COLOR 128 128 64 Last Quarter: 🌗 [moondate(3)] (%b)%
REM [moondate(0)] +60 SPECIAL COLOR 128 128 0 New moon: 🌑 [moondate(0)] (%b)
REM [moondate(1)] +60 SPECIAL COLOR 128 128 64 First Quarter: 🌓 [moondate(1)] (%b)
REM [moondate(2)] +60 SPECIAL COLOR 0 0 0 Full moon: 🌕 [moondate(2)] (%b)
REM [moondate(3)] +60 SPECIAL COLOR 128 128 64 Last Quarter: 🌗 [moondate(3)] (%b)
ENDIF
EOF

View File

@@ -19,13 +19,9 @@ REM Feb 14 MSG %"Valentine's Day%"
REM Third Monday in Feb SCANFROM -7 ADDOMIT MSG %"President's Day%"
REM Mar 17 MSG %"St. Patrick's Day%"
# The DST rules are accurate for most locations in
# North America
REM Sun Apr 1 ++2 UNTIL 1 Jan 2007 MSG Daylight Saving Time - %"DST starts%" %b
REM Sun Mar 8 ++2 FROM 1 Jan 2007 MSG Daylight Saving Time - %"DST starts%" %b
REM Last Sunday in October ++2 UNTIL 1 Jan 2007 MSG Daylight Saving Time - %"DST ends%" %b
REM First Sunday in November ++2 FROM 1 Jan 2007 MSG Daylight Saving Time - %"DST ends%" %b
# 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 Apr 1 MSG %"April Fool's%" Day
REM Mon Tue Wed Thu Fri Sat 15 Apr MSG %"Income tax%" due
@@ -35,15 +31,24 @@ REM Second Sun in May MSG %"Mother's Day%"
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%"
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 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%"
REM Second Mon in Oct MSG %"Columbus Day / Indigenous Peoples' Day%"
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 Fri Nov [Week_4+1] SCANFROM -7 ADDOMIT MSG %"Thanksgiving (cont.)%"
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

View File

@@ -61,3 +61,29 @@ FSET subst_gx(alt, d, t) iif(alt, subst_g_alt(d), $On + " " + subst_g_alt(d))
FSET subst_ux(alt, d, t) subst_ax(alt, d, t)
FSET subst_vx(alt, d, t) subst_gx(alt, d, t)
FSET subst_p(alt, d, t) iif(d == today()+1, "", "en")
# Localization of various astronomical events
# Perihelion
SET earthseasons_Perihelion_str "Perihel"
# Vernal equinox
SET earthseasons_EquinoxMar_str "Frühlingsanfang"
# Summer solstice
SET earthseasons_SolsticeJun_str "Sommeranfang"
# Aphelion
SET earthseasons_Aphelion_str "Aphel"
# Autumnal Equinox
SET earthseasons_EquinoxSep_str "Herbstanfang"
# Winter Solstice
SET earthseasons_SolsticeDec_str "Winteranfang"
# Daylight saving time starts
SET daylightST_starts_str "Beginn Sommerzeit"
# Daylight saving time ends
SET daylightST_ends_str "Ende Sommerzeit"

View File

@@ -1526,7 +1526,8 @@ Notes:
o
.B Remind
normally prints a blank line after each reminder; if the last character
of the body is "%", the blank line will not be printed.
of the body is "%", the blank line will not be printed. You can globally
suppress the extra blank lines by setting \fB$AddBlankLines\fR to 0.
.TP
o
Substitutions a, b, c, e, f, g, h, i, j, k, l, u and v all are replaced
@@ -2274,6 +2275,16 @@ The following system variables are defined. Those marked
"read-only" cannot be changed with the \fBSET\fR command.
All system variables hold values of type \fBINT\fR, unless otherwise
specified.
.TP
.B $AddBlankLines
If set to 1 (the default), then \fBRemind\fR normally prints a blank
line after the banner and each reminder. (This can be suppressed by
ending the reminder or banner with a single percent sign.) If
$AddBlankLines is set to 0, then Remind does not print the blank line.
In this case, ending a reminder with % has no effect. If you \fIdo\fR
want a blank line after a reminder, end it with \fB%_\fR to insert a
newline.
.TP
.B $CalcUTC
If 1 (the default), then \fBRemind\fR uses C library functions
@@ -2816,6 +2827,22 @@ arguments are converted using the reverse of procedures described
above. A \fBSTRING\fR \fIarg\fR is converted by parsing it as an
integer.
.RE
.TP
.B columns([s_arg])
If called with no arguments, \fBcolumns()\fR behaves as follows:
If standard output is a TTY, returns the width of the terminal in columns.
If standard output is not a TTY, attempts to open "/dev/tty" to obtain
the terminal size. If this fails, returns -1.
.RS
.PP
If called with a single string argument, \fBcolumns(str)\fR returns
the number of columns \fBstr\fR will occupy if printed to a terminal.
ANSI color-changing sequences occupy zero columns whereas some Unicode
characters occupy two columns. \fBcolumns(str)\fR takes all of that
into account. Note that if Remind was compiled without Unicode support,
\fBcolumns(str)\fR returns a type mismatch error.
.RE
.TP
.B current()
Returns the current date and time as a DATETIME object. This may be the
@@ -3338,6 +3365,11 @@ Returns the date as provided by the operating system. This is in contrast to
\fBRemind\fR's concept of "today", which may be changed if it is running
in calendar mode, or if a date has been supplied on the command line.
.TP
.B rows()
If standard output is a TTY, returns the height of the terminal in rows.
If standard output is not a TTY, attempts to open "/dev/tty" to obtain
the terminal size. If this fails, returns -1.
.TP
.B sgn(i_num)
Returns \-1 if \fInum\fR is negative, 1 if \fInum\fR is positive,
and 0 if \fInum\fR is zero.
@@ -3753,7 +3785,7 @@ defined, and the value of XY if it is defined.
.TP
.B version()
Returns a string specifying the version of \fBRemind\fR. For version
03.00.04, returns "03.00.04". It is guaranteed that as new versions of
@VERSION@, returns "@VERSION@". It is guaranteed that as new versions of
\fBRemind\fR are released, the value returned by \fBversion()\fR will
strictly increase, according to the rules for string ordering.
.TP
@@ -4086,13 +4118,13 @@ Notes:
.TP
o
If you access a variable in \fIexpr\fR that is not in the list of arguments,
the "global" value (if any) is used.
the global value (if any) is used.
.TP
o
Function and parameter names are significant only to 12 characters.
Function and parameter names are significant to 64 characters.
.TP
o
The \fBvalue()\fR function \fIalways\fR accesses the "global" value of a
The \fBvalue()\fR function \fIalways\fR accesses the global value of a
variable, even if it has the same name as an argument. For example:
.RS
.PP
@@ -5051,6 +5083,17 @@ as:
FSET subst_bx(a,d,t) iif(d==today()+2, "the day after tomorrow", 0)
.fi
.PP
You can define your own substitution sequences in addition to the built-in
ones as follows: If you define a function named \fBsubst_\fIname\fB(alt, date, time)\fR, then the sequence \fB%{name}\fR calls the function with \fBalt\fR
set to 0 and \fBdate\fR and \fRtime\fR to the trigger date and time,
respectively. The \fB%{name}\fR sequence is replaced with whatever the
function returns. The sequence \fB%*{name}\fR is similar, but calls
the function with \fBalt\fR set to 1.
.PP
If you use a \fB%{name}\fR sequence and the function \fBsubst_\fIname\fR is
not defined or returns an error, then \fB%{name}\fR is replaced with the
empty string.
.PP
.SH LANGUAGE PACKS
.PP
\fBRemind\fR ships with a number of language packs, which are simply reminder

View File

@@ -9,7 +9,7 @@
/* */
/***************************************************************/
#define _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#include "config.h"
#include "custom.h"

View File

@@ -945,8 +945,8 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig *tim, int jul)
if (!DoSubstFromString(DBufValue(&Banner), &buf,
JulianToday, NO_TIME) &&
DBufLen(&buf)) {
printf("%s\n", DBufValue(&buf));
}
printf("%s\n", DBufValue(&buf));
}
DBufFree(&buf);
}

View File

@@ -51,6 +51,7 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
int d, m, y;
int tim = tt->ttime;
int h, min, hh, ch, cmin, chh;
int i;
char const *pm, *cpm;
int tdiff, adiff, mdiff, hdiff;
char const *mplu, *hplu, *when, *plu;
@@ -190,8 +191,11 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
}
if (c == '\n') continue;
if (!c) {
if (mode != CAL_MODE && mode != ADVANCE_MODE &&
t->typ != RUN_TYPE && !MsgCommand) {
if (AddBlankLines &&
mode != CAL_MODE &&
mode != ADVANCE_MODE &&
t->typ != RUN_TYPE &&
!MsgCommand) {
if (DBufPutc(dbuf, '\n') != OK) return E_NO_MEM;
}
break;
@@ -221,6 +225,45 @@ int DoSubst(ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int jul,
break;
}
}
if (c == '{') {
i = 0;
ss = s + snprintf(s, sizeof(s), "subst_");
while (1) {
c = ParseChar(p, &err, 0);
if (err) {
DBufFree(dbuf);
return err;
}
if (c == '}' || !c) {
break;
}
if (i < 64) {
*ss++ = c;
*ss = 0;
i++;
}
}
if (!c) {
Wprint("Warning: Unterminated %{...} substitution sequence");
}
if (UserFuncExists(s) != 3) {
continue;
}
snprintf(ss, sizeof(s) - (ss-s), "(%d,'%04d-%02d-%02d',%02d:%02d)",
altmode ? 1 : 0, y, m+1, d, h, min);
expr = (char const *) s;
r = EvalExpr(&expr, &v, NULL);
if (r == OK) {
if (!DoCoerce(STR_TYPE, &v)) {
if (DBufPuts(dbuf, v.v.str) != OK) {
DestroyValue(v);
return E_NO_MEM;
}
}
DestroyValue(v);
}
continue;
}
done = 0;
snprintf(uf, sizeof(uf), "subst_%c", c);
if (UserFuncExists(uf) == 3) {

View File

@@ -13,12 +13,19 @@
#include "version.h"
#include "config.h"
#ifdef REM_USE_WCHAR
#define _XOPEN_SOURCE 600
#include <wctype.h>
#include <wchar.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <sys/ioctl.h>
#include <unistd.h>
@@ -67,6 +74,7 @@ static int FBaseyr (func_info *);
static int FChar (func_info *);
static int FChoose (func_info *);
static int FCoerce (func_info *);
static int FColumns (func_info *);
static int FCurrent (func_info *);
static int FDate (func_info *);
static int FDateTime (func_info *);
@@ -120,6 +128,7 @@ static int FPsshade (func_info *);
static int FRealCurrent (func_info *);
static int FRealnow (func_info *);
static int FRealtoday (func_info *);
static int FRows (func_info *);
static int FSgn (func_info *);
static int FShell (func_info *);
static int FSlide (func_info *);
@@ -227,6 +236,7 @@ BuiltinFunc Func[] = {
{ "char", 1, NO_MAX, 1, FChar },
{ "choose", 2, NO_MAX, 1, FChoose },
{ "coerce", 2, 2, 1, FCoerce },
{ "columns", 0, 1, 0, FColumns },
{ "current", 0, 0, 0, FCurrent },
{ "date", 3, 3, 1, FDate },
{ "datepart", 1, 1, 1, FDatepart },
@@ -281,6 +291,7 @@ BuiltinFunc Func[] = {
{ "realcurrent", 0, 0, 0, FRealCurrent},
{ "realnow", 0, 0, 0, FRealnow},
{ "realtoday", 0, 0, 0, FRealtoday },
{ "rows", 0, 0, 0, FRows },
{ "sgn", 1, 1, 1, FSgn },
{ "shell", 1, 2, 0, FShell },
{ "shellescape", 1, 1, 1, FShellescape },
@@ -3371,3 +3382,77 @@ FTrig(func_info *info)
}
return OK;
}
static int
rows_or_cols(func_info *info, int want_rows)
{
struct winsize w;
int fd = STDOUT_FILENO;
RetVal.type = INT_TYPE;
if (!isatty(fd)) {
fd = open("/dev/tty", O_RDONLY);
if (fd < 0) {
RETVAL = -1;
return OK;
}
}
if (ioctl(fd, TIOCGWINSZ, &w) == 0) {
if (want_rows) RETVAL = w.ws_row;
else RETVAL = w.ws_col;
} else {
RETVAL = -1;
}
if (fd != STDOUT_FILENO) {
close(fd);
}
return OK;
}
static int FRows(func_info *info)
{
return rows_or_cols(info, 1);
}
static int FColumns(func_info *info)
{
#ifdef REM_USE_WCHAR
size_t len;
wchar_t *buf, *s;
int width;
#endif
if (Nargs == 0) {
return rows_or_cols(info, 0);
}
ASSERT_TYPE(0, STR_TYPE);
#ifdef REM_USE_WCHAR
len = mbstowcs(NULL, ARGSTR(0), 0);
if (len == (size_t) -1) return E_NO_MEM;
buf = calloc(len+1, sizeof(wchar_t));
if (!buf) return E_NO_MEM;
(void) mbstowcs(buf, ARGSTR(0), len+1);
s = buf;
width = 0;
while (*s) {
if (*s == 0x1B && *(s+1) == '[') {
/* Skip escape sequences */
s += 2;
while (*s && (*s < 0x40 || *s > 0x7E)) {
s++;
}
if (*s) {
s++;
}
continue;
}
width += wcwidth(*s);
s++;
}
free(buf);
RetVal.type = INT_TYPE;
RETVAL = width;
return OK;
#else
return E_BAD_TYPE;
#endif
}

View File

@@ -58,6 +58,7 @@ EXTERN INIT( int DoSimpleCalendar, 0);
EXTERN INIT( int DoSimpleCalDelta, 0);
EXTERN INIT( int DoPrefixLineNo, 0);
EXTERN INIT( int MondayFirst, 0);
EXTERN INIT( int AddBlankLines, 1);
EXTERN INIT( int Iterations, 1);
EXTERN INIT( int PsCal, 0);
EXTERN INIT( int CalWidth, 80);

View File

@@ -10,7 +10,7 @@
/* */
/***************************************************************/
#define _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#include "config.h"
#include <errno.h>

View File

@@ -178,7 +178,7 @@ int have_callstack(void);
int print_callstack(FILE *fp);
void pop_call(void);
#ifdef REM_USE_WCHAR
#define _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#include <wctype.h>
#include <wchar.h>
void PutWideChar(wchar_t const wc);

View File

@@ -776,6 +776,7 @@ typedef struct {
/* All of the system variables sorted alphabetically */
static SysVar SysVarArr[] = {
/* name mod type value min/mal max validate*/
{"AddBlankLines", 1, INT_TYPE, &AddBlankLines, 0, 1, NULL },
{"Ago", 1, STR_TYPE, &DynamicAgo, 0, 0, NULL },
{"Am", 1, STR_TYPE, &DynamicAm, 0, 0, NULL },
{"And", 1, STR_TYPE, &DynamicAnd, 0, 0, NULL },

View File

@@ -42,3 +42,8 @@ set a ansicolor(128, 128, 128, -1)
set a ansicolor(128, 128, 128, 0, 2)
set a ansicolor(128, 128, 128, 0, -1)
set a ansicolor(128,0,0)
set str a + "foo: 🌅"
set w columns(str)
MSG Width of [str] is: [w]

5
tests/blanks.rem Normal file
View File

@@ -0,0 +1,5 @@
MSG $AddBlankLines=[$AddBlankLines]%_
MSG Hello
MSG Hi
MSF How are you?
MSG OK

View File

@@ -49,7 +49,7 @@ chmod 000 include_dir/04cantread.rem
TEST_GETENV="foo bar baz" ; export TEST_GETENV
echo "Test 1" > ../tests/test.out
echo "" >> ../tests/test.out
../src/remind -e -dxte ../tests/test.rem 16 feb 1991 >> ../tests/test.out 2>&1
../src/remind -e -dxte ../tests/test.rem 16 feb 1991 12:13 >> ../tests/test.out 2>&1
echo "" >> ../tests/test.out
echo "Test 2" >> ../tests/test.out
echo "" >> ../tests/test.out
@@ -116,6 +116,11 @@ echo "ANSI Color Test" >> ../tests/test.out
../src/remind -@1,1,1 ../tests/ansicolors.rem 1 Jan 2022 >> ../tests/test.out 2>&1
../src/remind -@2,1,1 ../tests/ansicolors.rem 1 Jan 2022 >> ../tests/test.out 2>&1
echo '$AddBlankLines test' >> ../tests/test.out
../src/remind ../tests/blanks.rem 1 Jan 2022 >> ../tests/test.out 2>&1
../src/remind '-i$AddBlankLines=1' ../tests/blanks.rem 1 Jan 2022 >> ../tests/test.out 2>&1
../src/remind '-i$AddBlankLines=0' ../tests/blanks.rem 1 Jan 2022 >> ../tests/test.out 2>&1
echo "MON WKDAY DAY across year test" >> ../tests/test.out
echo 'REM Mon 29 Dec MSG x' | ../src/remind -dt - 1 Jan 2000 >> ../tests/test.out 2>&1

View File

@@ -2723,6 +2723,7 @@ a125 -1
dump $
Variable Value
$AddBlankLines 1 [0, 1]
$Ago "ago"
$Am "am"
$And "and"
@@ -2740,7 +2741,7 @@ Variable Value
$DefaultTDelta 0 [0, 1440]
$DeltaOffset 0
$DontFork 0
$DontQueue 0
$DontQueue 1
$DontTrigAts 0
$EndSent ".?!"
$EndSentIg "\"')]}>"
@@ -2875,8 +2876,8 @@ $DontFork => 0
0
msg [$DontQueue]%
../tests/test.rem(479): Trig = Saturday, 16 February, 1991
$DontQueue => 0
0
$DontQueue => 1
1
msg [$DontTrigAts]%
../tests/test.rem(480): Trig = Saturday, 16 February, 1991
$DontTrigAts => 0
@@ -4118,6 +4119,53 @@ This is a very long reminder. It should be wrapped. Will it be
wrapped? I'm interested to see it it's wrapped. Please wrap this, ok?
# Custom substitution sequences
FSET subst_custom(a, d, t) "Custom: a=" + a + "; d=" + d + "; t=" + t
REM MSG Here: %{custom}
../tests/test.rem(844): Trig = Saturday, 16 February, 1991
Entering UserFN subst_custom(0, 1991-02-16, 12:13)
a => 0
"Custom: a=" + 0 => "Custom: a=0"
"Custom: a=0" + "; d=" => "Custom: a=0; d="
d => 1991-02-16
"Custom: a=0; d=" + 1991-02-16 => "Custom: a=0; d=1991-02-16"
"Custom: a=0; d=1991-02-16" + "; t=" => "Custom: a=0; d=1991-02-16; t="
t => 12:13
"Custom: a=0; d=1991-02-16; t=" + 12:13 => "Custom: a=0; d=1991-02-16; t=12:13"
Leaving UserFN subst_custom() => "Custom: a=0; d=1991-02-16; t=12:13"
Here: Custom: a=0; d=1991-02-16; t=12:13
REM MSG There: %*{custom}
../tests/test.rem(845): Trig = Saturday, 16 February, 1991
Entering UserFN subst_custom(1, 1991-02-16, 12:13)
a => 1
"Custom: a=" + 1 => "Custom: a=1"
"Custom: a=1" + "; d=" => "Custom: a=1; d="
d => 1991-02-16
"Custom: a=1; d=" + 1991-02-16 => "Custom: a=1; d=1991-02-16"
"Custom: a=1; d=1991-02-16" + "; t=" => "Custom: a=1; d=1991-02-16; t="
t => 12:13
"Custom: a=1; d=1991-02-16; t=" + 12:13 => "Custom: a=1; d=1991-02-16; t=12:13"
Leaving UserFN subst_custom() => "Custom: a=1; d=1991-02-16; t=12:13"
There: Custom: a=1; d=1991-02-16; t=12:13
REM MSG Bad: %{custom
../tests/test.rem(846): Trig = Saturday, 16 February, 1991
../tests/test.rem(846): Warning: Unterminated %{...} substitution sequence
Entering UserFN subst_custom(0, 1991-02-16, 12:13)
a => 0
"Custom: a=" + 0 => "Custom: a=0"
"Custom: a=0" + "; d=" => "Custom: a=0; d="
d => 1991-02-16
"Custom: a=0; d=" + 1991-02-16 => "Custom: a=0; d=1991-02-16"
"Custom: a=0; d=1991-02-16" + "; t=" => "Custom: a=0; d=1991-02-16; t="
t => 12:13
"Custom: a=0; d=1991-02-16; t=" + 12:13 => "Custom: a=0; d=1991-02-16; t=12:13"
Leaving UserFN subst_custom() => "Custom: a=0; d=1991-02-16; t=12:13"
Bad: Custom: a=0; d=1991-02-16; t=12:13
# Don't want Remind to queue reminders
EXIT
@@ -5520,6 +5568,8 @@ keyword will wrap it so it's pleasantly readable.
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: -1
UseVTColors is: 1
Use256Colors is: 0
@@ -5581,6 +5631,8 @@ keyword will wrap it so
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: -1
UseVTColors is: 1
Use256Colors is: 1
@@ -5642,6 +5694,8 @@ keyword will wrap it[
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: -1
UseVTColors is: 1
Use256Colors is: 0
@@ -5703,6 +5757,8 @@ keyword will[38;2;0
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 0
UseVTColors is: 1
Use256Colors is: 0
@@ -5764,6 +5820,8 @@ keyword will wrap it so
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 0
UseVTColors is: 1
Use256Colors is: 1
@@ -5825,6 +5883,8 @@ keyword will wrap it[
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 0
UseVTColors is: 1
Use256Colors is: 0
@@ -5886,6 +5946,8 @@ keyword will[38;2;0
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 1
UseVTColors is: 1
Use256Colors is: 0
@@ -5947,6 +6009,8 @@ keyword will wrap it so
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 1
UseVTColors is: 1
Use256Colors is: 1
@@ -6008,6 +6072,8 @@ keyword will wrap it[
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 1
UseVTColors is: 1
Use256Colors is: 0
@@ -6069,6 +6135,8 @@ keyword will[38;2;0
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: -1
UseVTColors is: 1
Use256Colors is: 0
@@ -6130,6 +6198,8 @@ keyword will wrap it so
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: -1
UseVTColors is: 1
Use256Colors is: 1
@@ -6191,6 +6261,8 @@ keyword will wrap it[
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: -1
UseVTColors is: 1
Use256Colors is: 0
@@ -6252,6 +6324,8 @@ keyword will[38;2;0
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 0
UseVTColors is: 1
Use256Colors is: 0
@@ -6313,6 +6387,8 @@ keyword will wrap it so
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 0
UseVTColors is: 1
Use256Colors is: 1
@@ -6374,6 +6450,8 @@ keyword will wrap it[
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 0
UseVTColors is: 1
Use256Colors is: 0
@@ -6435,6 +6513,8 @@ keyword will[38;2;0
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 1
UseVTColors is: 1
Use256Colors is: 0
@@ -6496,6 +6576,8 @@ keyword will wrap it so
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 1
UseVTColors is: 1
Use256Colors is: 1
@@ -6557,6 +6639,8 @@ keyword will wrap it[
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
TerminalBackground is: 1
UseVTColors is: 1
Use256Colors is: 0
@@ -6618,6 +6702,42 @@ keyword will[38;2;0
../tests/ansicolors.rem(41): ansicolor(): Number too low
../tests/ansicolors.rem(42): ansicolor(): Number too high
../tests/ansicolors.rem(43): ansicolor(): Number too low
Width of foo: 🌅 is: 7
$AddBlankLines test
Reminders for Saturday, 1st January, 2022:
$AddBlankLines=1
Hello
Hi
How are you?
OK
Reminders for Saturday, 1st January, 2022:
$AddBlankLines=1
Hello
Hi
How are you?
OK
Reminders for Saturday, 1st January, 2022:
$AddBlankLines=0
Hello
Hi
How are you?
OK
MON WKDAY DAY across year test
-(1): Trig = Monday, 3 January, 2000
No reminders.

View File

@@ -838,6 +838,13 @@ OMIT Dec 5 2029 through Dec 4 2029
REM MSF This is a very long reminder. It should be wrapped. Will it be wrapped? I'm interested to see it it's wrapped. Please wrap this, ok?
# Custom substitution sequences
FSET subst_custom(a, d, t) "Custom: a=" + a + "; d=" + d + "; t=" + t
REM MSG Here: %{custom}
REM MSG There: %*{custom}
REM MSG Bad: %{custom
# Don't want Remind to queue reminders
EXIT