mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-17 14:59:20 +02:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
143f1d6144 | ||
|
|
358f6c9497 | ||
|
|
ca26544be8 | ||
|
|
5ceffddd5b | ||
|
|
8e3ddb96b3 | ||
|
|
377de36b35 | ||
|
|
4395e2f7ed | ||
|
|
1d0cc31b10 | ||
|
|
4b4b2ddcd4 | ||
|
|
3c9b5b786e | ||
|
|
08f1bea6ce | ||
|
|
a2cc5943e0 | ||
|
|
895ac6f0f7 | ||
|
|
759ca0253e | ||
|
|
0ca368c8d9 | ||
|
|
a467cc1b84 | ||
|
|
c65fd826a5 | ||
|
|
bd6f4e1b43 | ||
|
|
169520914f | ||
|
|
a163a0c446 | ||
|
|
295aeb0ed8 | ||
|
|
9b2fdad56c | ||
|
|
7a1184d3c5 | ||
|
|
b036244316 | ||
|
|
5ad5366e8a |
2
configure
vendored
2
configure
vendored
@@ -3991,7 +3991,7 @@ _ACEOF
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
VERSION=03.03.07
|
VERSION=03.03.08
|
||||||
|
|
||||||
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h"
|
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h"
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,6 @@ if test "$GCC" = yes; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale)
|
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale)
|
||||||
VERSION=03.03.07
|
VERSION=03.03.08
|
||||||
AC_SUBST(VERSION)
|
AC_SUBST(VERSION)
|
||||||
AC_OUTPUT(src/Makefile www/Makefile src/version.h)
|
AC_OUTPUT(src/Makefile www/Makefile src/version.h)
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
CHANGES TO REMIND
|
CHANGES TO REMIND
|
||||||
|
|
||||||
|
* VERSION 3.3 Patch 8 - 2021-09-13
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: Add INCLUDECMD command
|
||||||
|
|
||||||
|
- NEW FEATURE: remind: Add shellescape() built-in function
|
||||||
|
|
||||||
|
- BUG FIX: tkremind: TkRemind would sometimes fill in incorrect initial
|
||||||
|
values for the reminder-editing form if you clicked on a TkRemind-created
|
||||||
|
reminder to edit it. This has been fixed.
|
||||||
|
|
||||||
|
- BUG FIX: tkremind: Get back better error messages from Remind if you
|
||||||
|
try to create a reminder with an invalid date specification.
|
||||||
|
|
||||||
|
- BUG FIX: remind: Catch integer overflow if we try to evaluate $IntMin * -1
|
||||||
|
|
||||||
|
- DOC UPDATES: remind: Minor man page fixes
|
||||||
|
|
||||||
* VERSION 3.3 Patch 7 - 2021-05-10
|
* VERSION 3.3 Patch 7 - 2021-05-10
|
||||||
|
|
||||||
- MINOR FIX: Refuse to run "make test" as root --- it would fail
|
- MINOR FIX: Refuse to run "make test" as root --- it would fail
|
||||||
|
|||||||
65
man/remind.1
65
man/remind.1
@@ -31,7 +31,8 @@ ignore them for now and skip to the section "REMINDER FILES".
|
|||||||
.B \-n
|
.B \-n
|
||||||
The \fB\-n\fR option causes \fBRemind\fR to print the \fBnext\fR occurrence
|
The \fB\-n\fR option causes \fBRemind\fR to print the \fBnext\fR occurrence
|
||||||
of each reminder in a simple calendar format. You can sort this by
|
of each reminder in a simple calendar format. You can sort this by
|
||||||
date by piping the output through \fBsort(1)\fR.
|
date by piping the output through \fBsort(1)\fR. Note that the \fB\-n\fR
|
||||||
|
option causes any \fB\-g\fR option to be \fIignored\fR.
|
||||||
.TP
|
.TP
|
||||||
.B \-j\fR[\fIn\fR]
|
.B \-j\fR[\fIn\fR]
|
||||||
Runs \fBRemind\fR in "purge" mode to get rid of expired reminders.
|
Runs \fBRemind\fR in "purge" mode to get rid of expired reminders.
|
||||||
@@ -250,6 +251,7 @@ The optional \fBa\fR and \fBd\fR characters specify the sort order
|
|||||||
(ascending or descending) for the date, time and priority fields. See
|
(ascending or descending) for the date, time and priority fields. See
|
||||||
the section "SORTING REMINDERS" for more information.
|
the section "SORTING REMINDERS" for more information.
|
||||||
|
|
||||||
|
Note that \fB\-g\fR is \fIignored\fR if you use the \fB\-n\fR option.
|
||||||
.TP
|
.TP
|
||||||
\fB\-b\fR[\fIn\fR]
|
\fB\-b\fR[\fIn\fR]
|
||||||
Set the time format for the calendar and simple-calendar outputs. \fIN\fR
|
Set the time format for the calendar and simple-calendar outputs. \fIN\fR
|
||||||
@@ -349,7 +351,7 @@ it as YYYY-MM-DD or YYYY/MM/DD. You can even supply a date and
|
|||||||
time on the command line as one argument: YYYY-MM-DD@HH:MM.
|
time on the command line as one argument: YYYY-MM-DD@HH:MM.
|
||||||
.PP
|
.PP
|
||||||
In addition, you can supply a \fIrepeat\fR parameter, which has the
|
In addition, you can supply a \fIrepeat\fR parameter, which has the
|
||||||
form *\fInum\fR. This causes \fBRemind\fR to be run \fInum\fR times,
|
form *\fIrep\fR. This causes \fBRemind\fR to be run \fIrep\fR times,
|
||||||
with the date incrementing on each iteration. You may have to enclose
|
with the date incrementing on each iteration. You may have to enclose
|
||||||
the parameter in quotes to avoid shell expansion. See the subsection
|
the parameter in quotes to avoid shell expansion. See the subsection
|
||||||
"Repeated Execution" in the section "CALENDAR MODE" for more
|
"Repeated Execution" in the section "CALENDAR MODE" for more
|
||||||
@@ -1578,7 +1580,49 @@ features. It will not read a file that is group- or world-writable.
|
|||||||
It will not run set-uid. If it reads a file you don't own, it will
|
It will not run set-uid. If it reads a file you don't own, it will
|
||||||
disable RUN and the shell() function. And if it is run as \fIroot\fR,
|
disable RUN and the shell() function. And if it is run as \fIroot\fR,
|
||||||
it will only read files owned by \fIroot\fR.
|
it will only read files owned by \fIroot\fR.
|
||||||
|
|
||||||
|
.SH THE INCLUDECMD COMMAND
|
||||||
.PP
|
.PP
|
||||||
|
\fBRemind\fR allows you to execute a shell command and evaluate the
|
||||||
|
output of that command as if it were an included file. For example,
|
||||||
|
you could have scripts that extract reminders out of a database and print
|
||||||
|
them on stdout as REM commands. Here is an example:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
INCLUDECMD extract_reminders_for dfs
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
We assume that the command "extract_reminders_for" extracts reminders out
|
||||||
|
of a central database for the named user. Another use-case of INCLUDECMD
|
||||||
|
is if you have your reminders stored in a file in some non-Remind format;
|
||||||
|
you can write a command that transforms them to Remind format and then
|
||||||
|
Remind can "include" the file with an appropriate INCLUDECMD command.
|
||||||
|
.PP
|
||||||
|
Note that if RUN is disabled, then INCLUDECMD will fail with the error
|
||||||
|
message "RUN disabled"
|
||||||
|
.PP
|
||||||
|
INCLUDECMD passes the rest of the line to \fBpopen\fR(3), meaning that
|
||||||
|
the command is executed by the shell. As such, shell metacharacters
|
||||||
|
may need escaping or arguments quoting, depending on what you're trying
|
||||||
|
to do. Remind itself does not perform any modification of the command
|
||||||
|
line (apart from the normal [expr] expression-pasting mechanism).
|
||||||
|
.PP
|
||||||
|
If the command passed to INCLUDECMD begins with an exclamation mark "!",
|
||||||
|
then Remind disables \fBRUN\fR for the output of the command. If you are
|
||||||
|
running a command whose output you don't quite trust, you should
|
||||||
|
prefix it with "!" so that any RUN commands it emits fail.
|
||||||
|
.PP
|
||||||
|
An \fBINCLUDECMD\fR command counts towards the INCLUDE nesting depth.
|
||||||
|
For any given Remind run, a given INCLUDECMD command is only executed
|
||||||
|
once and the results are cached. For example, if you generate a
|
||||||
|
calendar, each unique INCLUDECMD command is run just once, not once
|
||||||
|
for each day of the produced calendar. "Uniqueness" is determined by
|
||||||
|
looking at the command that will be passed to the shell, so if (for example)
|
||||||
|
your INCLUDECMD uses expression-pasting that results in differences depending
|
||||||
|
on the value of \fBtoday()\fR, then each \fIunique\fR version of the
|
||||||
|
command will be executed once.
|
||||||
|
.PP
|
||||||
|
|
||||||
.SH THE BANNER COMMAND
|
.SH THE BANNER COMMAND
|
||||||
.PP
|
.PP
|
||||||
When \fBRemind\fR first issues a reminder, it prints a message like this:
|
When \fBRemind\fR first issues a reminder, it prints a message like this:
|
||||||
@@ -2851,6 +2895,23 @@ If \fImaxlen\fR is specified, then \fBshell()\fR returns the first
|
|||||||
\fImaxlen\fR is specified as a negative number, then \fIall\fR the
|
\fImaxlen\fR is specified as a negative number, then \fIall\fR the
|
||||||
output from \fIcmd\fR is returned.
|
output from \fIcmd\fR is returned.
|
||||||
.RE
|
.RE
|
||||||
|
.TP
|
||||||
|
.B shellescape(s_str)
|
||||||
|
Returns \fIstr\fR with all shell metacharacters such as " ", "*", etc
|
||||||
|
escaped with a backslash. For example:
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
SET a shellescape("a b*? c&d$e")
|
||||||
|
.fi
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
will set \fBa\fR to:
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
.nf
|
||||||
|
"a\\ b\\*\\?\\ c\\&d\\$e"
|
||||||
|
.fi
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B slide(d_start, i_amt [,s_wkday...])
|
.B slide(d_start, i_amt [,s_wkday...])
|
||||||
This function is the inverse of \fBnonomitted\fR. It adds \fIamt\fR
|
This function is the inverse of \fBnonomitted\fR. It adds \fIamt\fR
|
||||||
|
|||||||
@@ -1005,8 +1005,8 @@ proc FillCalWindow {} {
|
|||||||
ConfigureCalWindow $monthName $year $firstWkday $daysInMonth
|
ConfigureCalWindow $monthName $year $firstWkday $daysInMonth
|
||||||
set offset [CalEntryOffset $firstWkday]
|
set offset [CalEntryOffset $firstWkday]
|
||||||
|
|
||||||
set fntag "x"
|
|
||||||
while { [gets $file line] >= 0 } {
|
while { [gets $file line] >= 0 } {
|
||||||
|
set fntag "x"
|
||||||
# Ignore unless begins with left brace
|
# Ignore unless begins with left brace
|
||||||
if { ! [string match "\{*" $line]} {
|
if { ! [string match "\{*" $line]} {
|
||||||
continue
|
continue
|
||||||
@@ -1017,7 +1017,11 @@ proc FillCalWindow {} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if {[dict exists $obj filename]} {
|
if {[dict exists $obj filename]} {
|
||||||
set fntag [string cat "FILE_" [dict get $obj lineno] "_" [dict get $obj filename]]
|
set fname [dict get $obj filename]
|
||||||
|
# Don't make INCLUDECMD output editable
|
||||||
|
if {![string match "*|" $fname]} {
|
||||||
|
set fntag [string cat "FILE_" [dict get $obj lineno] "_" $fname]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set date [dict get $obj date]
|
set date [dict get $obj date]
|
||||||
@@ -1087,13 +1091,17 @@ proc FillCalWindow {} {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
.cal.t$n configure -state normal
|
.cal.t$n configure -state normal
|
||||||
if {[regexp {TKTAG([0-9]+)} $tag all tagno]} {
|
if {[regexp {TKTAG([0-9]+)} $tag all tagno] && "$fntag" != "x"} {
|
||||||
.cal.t$n insert end [string trim $stuff] [list REM TAGGED "TKTAG$tagno" "date_$date" $extratags $fntag]
|
.cal.t$n insert end [string trim $stuff] [list REM TAGGED "TKTAG$tagno" "date_$date" $extratags $fntag]
|
||||||
.cal.t$n tag bind "TKTAG$tagno" <Enter> "TaggedEnter .cal.t$n"
|
.cal.t$n tag bind "TKTAG$tagno" <Enter> "TaggedEnter .cal.t$n"
|
||||||
.cal.t$n tag bind "TKTAG$tagno" <Leave> "TaggedLeave .cal.t$n"
|
.cal.t$n tag bind "TKTAG$tagno" <Leave> "TaggedLeave .cal.t$n"
|
||||||
set TagToObj(TKTAG$tagno) $obj
|
set TagToObj(TKTAG$tagno) $obj
|
||||||
} else {
|
} else {
|
||||||
.cal.t$n insert end [string trim $stuff] [list REM $extratags $fntag]
|
if {"$fntag" == "x" } {
|
||||||
|
.cal.t$n insert end [string trim $stuff] [list REM $extratags]
|
||||||
|
} else {
|
||||||
|
.cal.t$n insert end [string trim $stuff] [list REM $extratags $fntag]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.cal.t$n insert end "\n"
|
.cal.t$n insert end "\n"
|
||||||
.cal.t$n configure -state disabled
|
.cal.t$n configure -state disabled
|
||||||
@@ -1837,6 +1845,7 @@ proc ModifyDay {d firstDay} {
|
|||||||
set oldFocus [focus]
|
set oldFocus [focus]
|
||||||
while {1} {
|
while {1} {
|
||||||
grab .mod
|
grab .mod
|
||||||
|
raise .mod
|
||||||
focus .mod.entry
|
focus .mod.entry
|
||||||
set ModifyDialogResult -1
|
set ModifyDialogResult -1
|
||||||
tkwait variable ModifyDialogResult
|
tkwait variable ModifyDialogResult
|
||||||
@@ -1983,7 +1992,7 @@ proc CreateReminder {w} {
|
|||||||
|
|
||||||
# Check it out!
|
# Check it out!
|
||||||
global Remind
|
global Remind
|
||||||
set f [open "|$Remind -arq -e -" r+]
|
set f [open "|$Remind -arq -e - 2>&1" r+]
|
||||||
puts $f "BANNER %"
|
puts $f "BANNER %"
|
||||||
puts $f "$rem MSG %"
|
puts $f "$rem MSG %"
|
||||||
puts $f "MSG %_%_%_%_"
|
puts $f "MSG %_%_%_%_"
|
||||||
@@ -2001,13 +2010,17 @@ proc CreateReminder {w} {
|
|||||||
return $rem
|
return $rem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# We used to return YYYY-MM-DD, but reverted to
|
||||||
|
# day monthname year because this lets Remind produce
|
||||||
|
# much better error messages.
|
||||||
proc consolidate {y m d} {
|
proc consolidate {y m d} {
|
||||||
global MonthNames
|
global MonthNames
|
||||||
if {![regexp {^[0-9]+$} $m]} {
|
if {![regexp {^[0-9]+$} $m]} {
|
||||||
set m [lsearch -exact $MonthNames $m]
|
set m [lsearch -exact $MonthNames $m]
|
||||||
incr m
|
incr m
|
||||||
}
|
}
|
||||||
return [format "%04d-%02d-%02d" $y $m $d]
|
set mname [lindex $MonthNames [expr $m-1]]
|
||||||
|
return "$d $mname $y"
|
||||||
}
|
}
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@@ -2804,7 +2817,7 @@ proc ReadTaggedOptions { tag date } {
|
|||||||
lappend ans -text-day2 $d
|
lappend ans -text-day2 $d
|
||||||
}
|
}
|
||||||
if {[dict exists $obj m]} {
|
if {[dict exists $obj m]} {
|
||||||
set mm [dict get $obj m]
|
set m [dict get $obj m]
|
||||||
set mm [string trimleft $m 0]
|
set mm [string trimleft $m 0]
|
||||||
lappend ans -text-mon1 [lindex $MonthNames [expr $mm -1]]
|
lappend ans -text-mon1 [lindex $MonthNames [expr $mm -1]]
|
||||||
lappend ans -text-mon2 [lindex $MonthNames [expr $mm -1]]
|
lappend ans -text-mon2 [lindex $MonthNames [expr $mm -1]]
|
||||||
@@ -3194,6 +3207,7 @@ proc EditTaggedReminder { w } {
|
|||||||
tkwait visibility .mod
|
tkwait visibility .mod
|
||||||
set oldFocus [focus]
|
set oldFocus [focus]
|
||||||
while {1} {
|
while {1} {
|
||||||
|
raise .mod
|
||||||
grab .mod
|
grab .mod
|
||||||
focus .mod.entry
|
focus .mod.entry
|
||||||
set ModifyDialogResult -1
|
set ModifyDialogResult -1
|
||||||
|
|||||||
@@ -1239,6 +1239,7 @@ static void GenerateCalEntries(int col)
|
|||||||
case T_Else: r=DoElse(&p); break;
|
case T_Else: r=DoElse(&p); break;
|
||||||
case T_EndIf: r=DoEndif(&p); break;
|
case T_EndIf: r=DoEndif(&p); break;
|
||||||
case T_Include: r=DoInclude(&p); break;
|
case T_Include: r=DoInclude(&p); break;
|
||||||
|
case T_IncludeCmd: r=DoIncludeCmd(&p); break;
|
||||||
case T_Exit: DoExit(&p); break;
|
case T_Exit: DoExit(&p); break;
|
||||||
case T_Set: r=DoSet(&p); break;
|
case T_Set: r=DoSet(&p); break;
|
||||||
case T_Fset: r=DoFset(&p); break;
|
case T_Fset: r=DoFset(&p); break;
|
||||||
|
|||||||
22
src/dorem.c
22
src/dorem.c
@@ -24,10 +24,6 @@
|
|||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
|
||||||
/* Define the shell characters not to escape */
|
|
||||||
static char const DontEscapeMe[] =
|
|
||||||
"1234567890_-=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.,";
|
|
||||||
|
|
||||||
static int ParseTimeTrig (ParsePtr s, TimeTrig *tim, int save_in_globals);
|
static int ParseTimeTrig (ParsePtr s, TimeTrig *tim, int save_in_globals);
|
||||||
static int ParseLocalOmit (ParsePtr s, Trigger *t);
|
static int ParseLocalOmit (ParsePtr s, Trigger *t);
|
||||||
static int ParseScanFrom (ParsePtr s, Trigger *t, int type);
|
static int ParseScanFrom (ParsePtr s, Trigger *t, int type);
|
||||||
@@ -1230,24 +1226,16 @@ int DoMsgCommand(char const *cmd, char const *msg)
|
|||||||
DynamicBuffer execBuffer;
|
DynamicBuffer execBuffer;
|
||||||
|
|
||||||
DynamicBuffer buf;
|
DynamicBuffer buf;
|
||||||
char const *s;
|
|
||||||
|
|
||||||
DBufInit(&buf);
|
DBufInit(&buf);
|
||||||
DBufInit(&execBuffer);
|
DBufInit(&execBuffer);
|
||||||
|
|
||||||
/* Escape shell characters in msg INCLUDING WHITESPACE! */
|
/* Escape shell characters in msg */
|
||||||
for (s=msg; *s; s++) {
|
if (ShellEscape(msg, &buf) != OK) {
|
||||||
if (isspace(*s) || !strchr(DontEscapeMe, *s)) {
|
r = E_NO_MEM;
|
||||||
if (DBufPutc(&buf, '\\') != OK) {
|
goto finished;
|
||||||
r = E_NO_MEM;
|
|
||||||
goto finished;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (DBufPutc(&buf, *s) != OK) {
|
|
||||||
r = E_NO_MEM;
|
|
||||||
goto finished;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = DBufValue(&buf);
|
msg = DBufValue(&buf);
|
||||||
|
|
||||||
/* Do "%s" substitution */
|
/* Do "%s" substitution */
|
||||||
|
|||||||
@@ -940,6 +940,11 @@ static int Multiply(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
|
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
|
||||||
|
/* Prevent floating-point exception */
|
||||||
|
if ((v2.v.val == -1 && v1.v.val == INT_MIN) ||
|
||||||
|
(v1.v.val == -1 && v2.v.val == INT_MIN)) {
|
||||||
|
return E_2HIGH;
|
||||||
|
}
|
||||||
int old = v1.v.val;
|
int old = v1.v.val;
|
||||||
v1.v.val *= v2.v.val;
|
v1.v.val *= v2.v.val;
|
||||||
if (v2.v.val != 0) {
|
if (v2.v.val != 0) {
|
||||||
|
|||||||
263
src/files.c
263
src/files.c
@@ -40,8 +40,9 @@
|
|||||||
#include "err.h"
|
#include "err.h"
|
||||||
|
|
||||||
|
|
||||||
/* Convenient macro for closing files */
|
/* Convenient macros for closing files */
|
||||||
#define FCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL))
|
#define FCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (fclose(fp),(fp)=NULL) : ((fp)=NULL))
|
||||||
|
#define PCLOSE(fp) (((fp)&&((fp)!=stdin)) ? (pclose(fp),(fp)=NULL) : ((fp)=NULL))
|
||||||
|
|
||||||
/* Define the structures needed by the file caching system */
|
/* Define the structures needed by the file caching system */
|
||||||
typedef struct cache {
|
typedef struct cache {
|
||||||
@@ -91,12 +92,12 @@ static FILE *fp;
|
|||||||
static IncludeStruct IStack[INCLUDE_NEST];
|
static IncludeStruct IStack[INCLUDE_NEST];
|
||||||
static int IStackPtr = 0;
|
static int IStackPtr = 0;
|
||||||
|
|
||||||
static int ReadLineFromFile (void);
|
static int ReadLineFromFile (int use_pclose);
|
||||||
static int CacheFile (char const *fname);
|
static int CacheFile (char const *fname, int use_pclose);
|
||||||
static void DestroyCache (CachedFile *cf);
|
static void DestroyCache (CachedFile *cf);
|
||||||
static int CheckSafety (void);
|
static int CheckSafety (void);
|
||||||
static int PopFile (void);
|
static int PopFile (void);
|
||||||
|
static int IncludeCmd(char const *);
|
||||||
static void OpenPurgeFile(char const *fname, char const *mode)
|
static void OpenPurgeFile(char const *fname, char const *mode)
|
||||||
{
|
{
|
||||||
DynamicBuffer fname_buf;
|
DynamicBuffer fname_buf;
|
||||||
@@ -167,7 +168,7 @@ int ReadLine(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Not cached. Read from the file. */
|
/* Not cached. Read from the file. */
|
||||||
return ReadLineFromFile();
|
return ReadLineFromFile(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -177,7 +178,7 @@ int ReadLine(void)
|
|||||||
/* Read a line from the file pointed to by fp. */
|
/* Read a line from the file pointed to by fp. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static int ReadLineFromFile(void)
|
static int ReadLineFromFile(int use_pclose)
|
||||||
{
|
{
|
||||||
int l;
|
int l;
|
||||||
char copy_buffer[4096];
|
char copy_buffer[4096];
|
||||||
@@ -200,7 +201,11 @@ static int ReadLineFromFile(void)
|
|||||||
return E_IO_ERR;
|
return E_IO_ERR;
|
||||||
}
|
}
|
||||||
if (feof(fp)) {
|
if (feof(fp)) {
|
||||||
FCLOSE(fp);
|
if (use_pclose) {
|
||||||
|
PCLOSE(fp);
|
||||||
|
} else {
|
||||||
|
FCLOSE(fp);
|
||||||
|
}
|
||||||
if ((DBufLen(&buf) == 0) &&
|
if ((DBufLen(&buf) == 0) &&
|
||||||
(DBufLen(&LineBuffer) == 0) && PurgeMode) {
|
(DBufLen(&LineBuffer) == 0) && PurgeMode) {
|
||||||
if (PurgeFP != NULL && PurgeFP != stdout) fclose(PurgeFP);
|
if (PurgeFP != NULL && PurgeFP != stdout) fclose(PurgeFP);
|
||||||
@@ -248,7 +253,11 @@ static int ReadLineFromFile(void)
|
|||||||
if (PurgeFP != stdout) fclose(PurgeFP);
|
if (PurgeFP != stdout) fclose(PurgeFP);
|
||||||
PurgeFP = NULL;
|
PurgeFP = NULL;
|
||||||
}
|
}
|
||||||
FCLOSE(fp);
|
if (use_pclose) {
|
||||||
|
PCLOSE(fp);
|
||||||
|
} else {
|
||||||
|
FCLOSE(fp);
|
||||||
|
}
|
||||||
DBufFree(&LineBuffer);
|
DBufFree(&LineBuffer);
|
||||||
CurLine = DBufValue(&LineBuffer);
|
CurLine = DBufValue(&LineBuffer);
|
||||||
}
|
}
|
||||||
@@ -282,9 +291,6 @@ int OpenFile(char const *fname)
|
|||||||
PurgeFP = NULL;
|
PurgeFP = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assume we own the file for now */
|
|
||||||
RunDisabled &= ~RUN_NOTOWNER;
|
|
||||||
|
|
||||||
/* If it's in the cache, get it from there. */
|
/* If it's in the cache, get it from there. */
|
||||||
|
|
||||||
while (h) {
|
while (h) {
|
||||||
@@ -297,7 +303,9 @@ int OpenFile(char const *fname)
|
|||||||
LineNo = 0;
|
LineNo = 0;
|
||||||
if (!h->ownedByMe) {
|
if (!h->ownedByMe) {
|
||||||
RunDisabled |= RUN_NOTOWNER;
|
RunDisabled |= RUN_NOTOWNER;
|
||||||
}
|
} else {
|
||||||
|
RunDisabled &= ~RUN_NOTOWNER;
|
||||||
|
}
|
||||||
if (FileName) return OK; else return E_NO_MEM;
|
if (FileName) return OK; else return E_NO_MEM;
|
||||||
}
|
}
|
||||||
h = h->next;
|
h = h->next;
|
||||||
@@ -306,6 +314,7 @@ int OpenFile(char const *fname)
|
|||||||
/* If it's a dash, then it's stdin */
|
/* If it's a dash, then it's stdin */
|
||||||
if (!strcmp(fname, "-")) {
|
if (!strcmp(fname, "-")) {
|
||||||
fp = stdin;
|
fp = stdin;
|
||||||
|
RunDisabled &= ~RUN_NOTOWNER;
|
||||||
if (PurgeMode) {
|
if (PurgeMode) {
|
||||||
PurgeFP = stdout;
|
PurgeFP = stdout;
|
||||||
}
|
}
|
||||||
@@ -325,7 +334,7 @@ int OpenFile(char const *fname)
|
|||||||
CLine = NULL;
|
CLine = NULL;
|
||||||
if (ShouldCache) {
|
if (ShouldCache) {
|
||||||
LineNo = 0;
|
LineNo = 0;
|
||||||
r = CacheFile(fname);
|
r = CacheFile(fname, 0);
|
||||||
if (r == OK) {
|
if (r == OK) {
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
CLine = CachedFiles->cache;
|
CLine = CachedFiles->cache;
|
||||||
@@ -353,7 +362,7 @@ int OpenFile(char const *fname)
|
|||||||
/* Returns an indication of success or failure. */
|
/* Returns an indication of success or failure. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static int CacheFile(char const *fname)
|
static int CacheFile(char const *fname, int use_pclose)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
CachedFile *cf;
|
CachedFile *cf;
|
||||||
@@ -368,14 +377,22 @@ static int CacheFile(char const *fname)
|
|||||||
cf = NEW(CachedFile);
|
cf = NEW(CachedFile);
|
||||||
if (!cf) {
|
if (!cf) {
|
||||||
ShouldCache = 0;
|
ShouldCache = 0;
|
||||||
FCLOSE(fp);
|
if (use_pclose) {
|
||||||
|
PCLOSE(fp);
|
||||||
|
} else {
|
||||||
|
FCLOSE(fp);
|
||||||
|
}
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
cf->cache = NULL;
|
cf->cache = NULL;
|
||||||
cf->filename = StrDup(fname);
|
cf->filename = StrDup(fname);
|
||||||
if (!cf->filename) {
|
if (!cf->filename) {
|
||||||
ShouldCache = 0;
|
ShouldCache = 0;
|
||||||
FCLOSE(fp);
|
if (use_pclose) {
|
||||||
|
PCLOSE(fp);
|
||||||
|
} else {
|
||||||
|
FCLOSE(fp);
|
||||||
|
}
|
||||||
free(cf);
|
free(cf);
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
@@ -388,11 +405,15 @@ static int CacheFile(char const *fname)
|
|||||||
|
|
||||||
/* Read the file */
|
/* Read the file */
|
||||||
while(fp) {
|
while(fp) {
|
||||||
r = ReadLineFromFile();
|
r = ReadLineFromFile(use_pclose);
|
||||||
if (r) {
|
if (r) {
|
||||||
DestroyCache(cf);
|
DestroyCache(cf);
|
||||||
ShouldCache = 0;
|
ShouldCache = 0;
|
||||||
FCLOSE(fp);
|
if (use_pclose) {
|
||||||
|
PCLOSE(fp);
|
||||||
|
} else {
|
||||||
|
FCLOSE(fp);
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
/* Skip blank chars */
|
/* Skip blank chars */
|
||||||
@@ -406,7 +427,11 @@ static int CacheFile(char const *fname)
|
|||||||
DBufFree(&LineBuffer);
|
DBufFree(&LineBuffer);
|
||||||
DestroyCache(cf);
|
DestroyCache(cf);
|
||||||
ShouldCache = 0;
|
ShouldCache = 0;
|
||||||
FCLOSE(fp);
|
if (use_pclose) {
|
||||||
|
PCLOSE(fp);
|
||||||
|
} else {
|
||||||
|
FCLOSE(fp);
|
||||||
|
}
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
cl = cf->cache;
|
cl = cf->cache;
|
||||||
@@ -416,7 +441,11 @@ static int CacheFile(char const *fname)
|
|||||||
DBufFree(&LineBuffer);
|
DBufFree(&LineBuffer);
|
||||||
DestroyCache(cf);
|
DestroyCache(cf);
|
||||||
ShouldCache = 0;
|
ShouldCache = 0;
|
||||||
FCLOSE(fp);
|
if (use_pclose) {
|
||||||
|
PCLOSE(fp);
|
||||||
|
} else {
|
||||||
|
FCLOSE(fp);
|
||||||
|
}
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
cl = cl->next;
|
cl = cl->next;
|
||||||
@@ -428,7 +457,11 @@ static int CacheFile(char const *fname)
|
|||||||
if (!cl->text) {
|
if (!cl->text) {
|
||||||
DestroyCache(cf);
|
DestroyCache(cf);
|
||||||
ShouldCache = 0;
|
ShouldCache = 0;
|
||||||
FCLOSE(fp);
|
if (use_pclose) {
|
||||||
|
PCLOSE(fp);
|
||||||
|
} else {
|
||||||
|
FCLOSE(fp);
|
||||||
|
}
|
||||||
return E_NO_MEM;
|
return E_NO_MEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -471,9 +504,6 @@ static int PopFile(void)
|
|||||||
{
|
{
|
||||||
IncludeStruct *i;
|
IncludeStruct *i;
|
||||||
|
|
||||||
/* Assume we own the file for now */
|
|
||||||
RunDisabled &= ~RUN_NOTOWNER;
|
|
||||||
|
|
||||||
if (!Hush && NumIfs) Eprint("%s", ErrMsg[E_MISS_ENDIF]);
|
if (!Hush && NumIfs) Eprint("%s", ErrMsg[E_MISS_ENDIF]);
|
||||||
if (!IStackPtr) return E_EOF;
|
if (!IStackPtr) return E_EOF;
|
||||||
i = &IStack[IStackPtr-1];
|
i = &IStack[IStackPtr-1];
|
||||||
@@ -500,8 +530,10 @@ static int PopFile(void)
|
|||||||
STRSET(FileName, i->filename);
|
STRSET(FileName, i->filename);
|
||||||
if (!i->ownedByMe) {
|
if (!i->ownedByMe) {
|
||||||
RunDisabled |= RUN_NOTOWNER;
|
RunDisabled |= RUN_NOTOWNER;
|
||||||
|
} else {
|
||||||
|
RunDisabled &= ~RUN_NOTOWNER;
|
||||||
}
|
}
|
||||||
if (!CLine && (i->offset != -1L)) {
|
if (!CLine && (i->offset != -1L || !strcmp(i->filename, "-"))) {
|
||||||
/* We must open the file, then seek to specified position */
|
/* We must open the file, then seek to specified position */
|
||||||
if (strcmp(i->filename, "-")) {
|
if (strcmp(i->filename, "-")) {
|
||||||
fp = fopen(i->filename, "r");
|
fp = fopen(i->filename, "r");
|
||||||
@@ -544,6 +576,64 @@ int DoInclude(ParsePtr p)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* DoIncludeCmd */
|
||||||
|
/* */
|
||||||
|
/* The INCLUDECMD command. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
int DoIncludeCmd(ParsePtr p)
|
||||||
|
{
|
||||||
|
DynamicBuffer buf;
|
||||||
|
int r;
|
||||||
|
int ch;
|
||||||
|
char append_buf[2];
|
||||||
|
int seen_nonspace = 0;
|
||||||
|
|
||||||
|
append_buf[1] = 0;
|
||||||
|
|
||||||
|
DBufInit(&buf);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
ch = ParseChar(p, &r, 0);
|
||||||
|
if (r) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (!ch) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isspace(ch) && !seen_nonspace) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
seen_nonspace = 1;
|
||||||
|
/* Convert \n to ' ' to better handle line continuation */
|
||||||
|
if (ch == '\n') {
|
||||||
|
ch = ' ';
|
||||||
|
}
|
||||||
|
append_buf[0] = (char) ch;
|
||||||
|
if (DBufPuts(&buf, append_buf) != OK) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
return E_NO_MEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RunDisabled) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
return E_RUN_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (r=IncludeCmd(DBufValue(&buf))) ) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
DBufFree(&buf);
|
||||||
|
NumIfs = 0;
|
||||||
|
IfFlags = 0;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_GLOB
|
#ifdef HAVE_GLOB
|
||||||
static int SetupGlobChain(char const *dirname, IncludeStruct *i)
|
static int SetupGlobChain(char const *dirname, IncludeStruct *i)
|
||||||
{
|
{
|
||||||
@@ -664,6 +754,127 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* IncludeCmd */
|
||||||
|
/* */
|
||||||
|
/* Process the INCLUDECMD command - actually do the command */
|
||||||
|
/* inclusion. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
static int IncludeCmd(char const *cmd)
|
||||||
|
{
|
||||||
|
IncludeStruct *i;
|
||||||
|
DynamicBuffer buf;
|
||||||
|
FILE *fp2;
|
||||||
|
int r;
|
||||||
|
CachedFile *h;
|
||||||
|
char const *fname;
|
||||||
|
int old_flag;
|
||||||
|
|
||||||
|
FreshLine = 1;
|
||||||
|
if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE;
|
||||||
|
i = &IStack[IStackPtr];
|
||||||
|
|
||||||
|
/* Use "cmd|" as the filename */
|
||||||
|
DBufInit(&buf);
|
||||||
|
if (DBufPuts(&buf, cmd) != OK) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
return E_NO_MEM;
|
||||||
|
}
|
||||||
|
if (DBufPuts(&buf, "|") != OK) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
return E_NO_MEM;
|
||||||
|
}
|
||||||
|
fname = DBufValue(&buf);
|
||||||
|
|
||||||
|
if (FileName) {
|
||||||
|
i->filename = StrDup(FileName);
|
||||||
|
if (!i->filename) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
return E_NO_MEM;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i->filename = NULL;
|
||||||
|
}
|
||||||
|
i->ownedByMe = 1;
|
||||||
|
i->LineNo = LineNo;
|
||||||
|
i->NumIfs = NumIfs;
|
||||||
|
i->IfFlags = IfFlags;
|
||||||
|
i->CLine = CLine;
|
||||||
|
i->offset = -1L;
|
||||||
|
i->chain = NULL;
|
||||||
|
if (fp) {
|
||||||
|
i->offset = ftell(fp);
|
||||||
|
FCLOSE(fp);
|
||||||
|
}
|
||||||
|
IStackPtr++;
|
||||||
|
|
||||||
|
/* If the file is cached, use it */
|
||||||
|
h = CachedFiles;
|
||||||
|
while(h) {
|
||||||
|
if (!strcmp(fname, h->filename)) {
|
||||||
|
if (DebugFlag & DB_TRACE_FILES) {
|
||||||
|
fprintf(ErrFp, "Reading command `%s': Found in cache\n", fname);
|
||||||
|
}
|
||||||
|
CLine = h->cache;
|
||||||
|
STRSET(FileName, fname);
|
||||||
|
DBufFree(&buf);
|
||||||
|
LineNo = 0;
|
||||||
|
if (!h->ownedByMe) {
|
||||||
|
RunDisabled |= RUN_NOTOWNER;
|
||||||
|
} else {
|
||||||
|
RunDisabled &= ~RUN_NOTOWNER;
|
||||||
|
}
|
||||||
|
if (FileName) return OK; else return E_NO_MEM;
|
||||||
|
}
|
||||||
|
h = h->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DebugFlag & DB_TRACE_FILES) {
|
||||||
|
fprintf(ErrFp, "Executing `%s' for INCLUDECMD and caching as `%s'\n",
|
||||||
|
cmd, fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not found in cache */
|
||||||
|
|
||||||
|
/* If cmd starts with !, then disable RUN within the cmd output */
|
||||||
|
if (cmd[0] == '!') {
|
||||||
|
fp2 = popen(cmd+1, "r");
|
||||||
|
} else {
|
||||||
|
fp2 = popen(cmd, "r");
|
||||||
|
}
|
||||||
|
if (!fp2) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
return E_CANT_OPEN;
|
||||||
|
}
|
||||||
|
fp = fp2;
|
||||||
|
LineNo = 0;
|
||||||
|
|
||||||
|
/* Temporarily turn of file tracing */
|
||||||
|
old_flag = DebugFlag;
|
||||||
|
DebugFlag &= (~DB_TRACE_FILES);
|
||||||
|
|
||||||
|
if (cmd[0] == '!') {
|
||||||
|
RunDisabled |= RUN_NOTOWNER;
|
||||||
|
}
|
||||||
|
r = CacheFile(fname, 1);
|
||||||
|
|
||||||
|
DebugFlag = old_flag;
|
||||||
|
if (r == OK) {
|
||||||
|
fp = NULL;
|
||||||
|
CLine = CachedFiles->cache;
|
||||||
|
LineNo = 0;
|
||||||
|
STRSET(FileName, fname);
|
||||||
|
DBufFree(&buf);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
DBufFree(&buf);
|
||||||
|
/* We failed */
|
||||||
|
PopFile();
|
||||||
|
return E_CANT_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* IncludeFile */
|
/* IncludeFile */
|
||||||
@@ -869,6 +1080,8 @@ static int CheckSafety(void)
|
|||||||
/* If file is not owned by me, disable RUN command */
|
/* If file is not owned by me, disable RUN command */
|
||||||
if (statbuf.st_uid != geteuid()) {
|
if (statbuf.st_uid != geteuid()) {
|
||||||
RunDisabled |= RUN_NOTOWNER;
|
RunDisabled |= RUN_NOTOWNER;
|
||||||
|
} else {
|
||||||
|
RunDisabled &= ~RUN_NOTOWNER;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
24
src/funcs.c
24
src/funcs.c
@@ -151,6 +151,7 @@ static int FWeekno (func_info *);
|
|||||||
static int FWkday (func_info *);
|
static int FWkday (func_info *);
|
||||||
static int FWkdaynum (func_info *);
|
static int FWkdaynum (func_info *);
|
||||||
static int FYear (func_info *);
|
static int FYear (func_info *);
|
||||||
|
static int FShellescape (func_info *);
|
||||||
|
|
||||||
static int CleanUpAfterFunc (func_info *);
|
static int CleanUpAfterFunc (func_info *);
|
||||||
static int CheckArgs (BuiltinFunc *f, int nargs);
|
static int CheckArgs (BuiltinFunc *f, int nargs);
|
||||||
@@ -267,6 +268,7 @@ BuiltinFunc Func[] = {
|
|||||||
{ "realtoday", 0, 0, 0, FRealtoday },
|
{ "realtoday", 0, 0, 0, FRealtoday },
|
||||||
{ "sgn", 1, 1, 1, FSgn },
|
{ "sgn", 1, 1, 1, FSgn },
|
||||||
{ "shell", 1, 2, 0, FShell },
|
{ "shell", 1, 2, 0, FShell },
|
||||||
|
{ "shellescape", 1, 1, 1, FShellescape },
|
||||||
{ "slide", 2, NO_MAX, 0, FSlide },
|
{ "slide", 2, NO_MAX, 0, FSlide },
|
||||||
{ "strlen", 1, 1, 1, FStrlen },
|
{ "strlen", 1, 1, 1, FStrlen },
|
||||||
{ "substr", 2, 3, 1, FSubstr },
|
{ "substr", 2, 3, 1, FSubstr },
|
||||||
@@ -1072,6 +1074,28 @@ static int FOstype(func_info *info)
|
|||||||
return RetStrVal("UNIX", info);
|
return RetStrVal("UNIX", info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FShellescape - escape shell meta-characters */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
static int FShellescape(func_info *info)
|
||||||
|
{
|
||||||
|
DynamicBuffer buf;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
ASSERT_TYPE(0, STR_TYPE);
|
||||||
|
DBufInit (&buf);
|
||||||
|
if (ShellEscape(ARG(0).v.str, &buf) != OK) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
return E_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = RetStrVal(DBufValue(&buf), info);
|
||||||
|
DBufFree(&buf);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* FUpper - convert string to upper-case */
|
/* FUpper - convert string to upper-case */
|
||||||
|
|||||||
@@ -243,6 +243,15 @@ static void DoReminders(void)
|
|||||||
r=DoInclude(&p);
|
r=DoInclude(&p);
|
||||||
purge_handled = 1;
|
purge_handled = 1;
|
||||||
break;
|
break;
|
||||||
|
case T_IncludeCmd:
|
||||||
|
/* In purge mode, include closes file, so we
|
||||||
|
need to echo it here! */
|
||||||
|
if (PurgeMode) {
|
||||||
|
PurgeEchoLine("%s\n", CurLine);
|
||||||
|
}
|
||||||
|
r=DoIncludeCmd(&p);
|
||||||
|
purge_handled = 1;
|
||||||
|
break;
|
||||||
case T_Exit: DoExit(&p); break;
|
case T_Exit: DoExit(&p); break;
|
||||||
case T_Flush: r=DoFlush(&p); break;
|
case T_Flush: r=DoFlush(&p); break;
|
||||||
case T_Set: r=DoSet(&p); break;
|
case T_Set: r=DoSet(&p); break;
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ int CopyValue (Value *dest, const Value *src);
|
|||||||
int ReadLine (void);
|
int ReadLine (void);
|
||||||
int OpenFile (char const *fname);
|
int OpenFile (char const *fname);
|
||||||
int DoInclude (ParsePtr p);
|
int DoInclude (ParsePtr p);
|
||||||
|
int DoIncludeCmd (ParsePtr p);
|
||||||
int IncludeFile (char const *fname);
|
int IncludeFile (char const *fname);
|
||||||
int GetAccessDate (char const *file);
|
int GetAccessDate (char const *file);
|
||||||
int SetAccessDate (char const *fname, int jul);
|
int SetAccessDate (char const *fname, int jul);
|
||||||
@@ -161,3 +162,4 @@ void PrintJSONKeyPairDate(char const *name, int jul);
|
|||||||
void PrintJSONKeyPairDateTime(char const *name, int dt);
|
void PrintJSONKeyPairDateTime(char const *name, int dt);
|
||||||
void PrintJSONKeyPairTime(char const *name, int t);
|
void PrintJSONKeyPairTime(char const *name, int t);
|
||||||
void System(char const *cmd);
|
void System(char const *cmd);
|
||||||
|
int ShellEscape(char const *in, DynamicBuffer *out);
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ Token TokArray[] = {
|
|||||||
{ "if", 2, T_If, 0 },
|
{ "if", 2, T_If, 0 },
|
||||||
{ "iftrig", 6, T_IfTrig, 0 },
|
{ "iftrig", 6, T_IfTrig, 0 },
|
||||||
{ "include", 3, T_Include, 0 },
|
{ "include", 3, T_Include, 0 },
|
||||||
|
{ "includecmd", 10, T_IncludeCmd, 0 },
|
||||||
{ "january", 3, T_Month, 0 },
|
{ "january", 3, T_Month, 0 },
|
||||||
{ "july", 3, T_Month, 6 },
|
{ "july", 3, T_Month, 6 },
|
||||||
{ "june", 3, T_Month, 5 },
|
{ "june", 3, T_Month, 5 },
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
|
|||||||
enum TokTypes
|
enum TokTypes
|
||||||
{ T_Illegal,
|
{ T_Illegal,
|
||||||
/* Commands first */
|
/* Commands first */
|
||||||
T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_If, T_Else, T_EndIf,
|
T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_IncludeCmd, T_If, T_Else, T_EndIf,
|
||||||
T_IfTrig, T_ErrMsg,
|
T_IfTrig, T_ErrMsg,
|
||||||
T_Set, T_UnSet, T_Fset, T_Omit, T_Banner, T_Exit,
|
T_Set, T_UnSet, T_Fset, T_Omit, T_Banner, T_Exit,
|
||||||
T_WkDay,
|
T_WkDay,
|
||||||
|
|||||||
16
src/utils.c
16
src/utils.c
@@ -9,7 +9,11 @@
|
|||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
||||||
|
static char const DontEscapeMe[] =
|
||||||
|
"1234567890_-=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.,/";
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -146,3 +150,15 @@ int _private_unminus_overflow(int a, int b)
|
|||||||
if (a < 0 && b < 0) return 1;
|
if (a < 0 && b < 0) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ShellEscape(char const *in, DynamicBuffer *out)
|
||||||
|
{
|
||||||
|
while(*in) {
|
||||||
|
if (!strchr(DontEscapeMe, *in)) {
|
||||||
|
if (DBufPutc(out, '\\') != OK) return E_NO_MEM;
|
||||||
|
}
|
||||||
|
if (DBufPutc(out, *in++) != OK) return E_NO_MEM;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
cd /home/dfs/Software/Remind.git || exit 1
|
|
||||||
|
|
||||||
rm -f .git/COMMIT_EDITMSG .git/*~
|
|
||||||
|
|
||||||
git update-server-info && cd .git && rsync --exclude HEADER.html --archive --verbose --progress --delete ./ dianne.skoll.ca:web/projects/remind/git/Remind.git/
|
|
||||||
exit $?
|
|
||||||
|
|
||||||
@@ -307,14 +307,21 @@ rem 25 SPECIAL COLOR 200 200 200 BRIGHT WHITE
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
# If we're already in a utf-8 locale, do
|
# If we're already in a utf-8 locale, do
|
||||||
# nothing
|
# nothing; otherwise, set LC_ALL
|
||||||
|
OK=0
|
||||||
if ! echo $LC_ALL | grep -i utf-8 > /dev/null 2>&1 ; then
|
if echo $LC_ALL | grep -i utf-8 > /dev/null 2>&1 ; then
|
||||||
export LC_ALL=en_US.utf-8
|
OK=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! echo $LANG | grep -i utf-8 > /dev/null 2>&1 ; then
|
if test -z "$LC_ALL" ; then
|
||||||
export LANG=en_US.utf-8
|
if echo $LANG | grep -i utf-8 > /dev/null 2>&1 ; then
|
||||||
|
export LC_ALL="$LANG"
|
||||||
|
OK=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$OK" = 0 ; then
|
||||||
|
export LC_ALL=en_US.utf-8
|
||||||
fi
|
fi
|
||||||
|
|
||||||
../src/remind -w128 -c ../tests/utf-8.rem 1 Nov 2019 >> ../tests/test.out
|
../src/remind -w128 -c ../tests/utf-8.rem 1 Nov 2019 >> ../tests/test.out
|
||||||
|
|||||||
1231
tests/test.cmp
1231
tests/test.cmp
File diff suppressed because it is too large
Load Diff
@@ -15,9 +15,40 @@ REM Wed UNTIL 15 Feb 1991 SATISFY [trigdate() > '1990-01-01'] MSG wookie
|
|||||||
# bad AT
|
# bad AT
|
||||||
REM AT 0:00 0:01 0:02 MSG foo
|
REM AT 0:00 0:01 0:02 MSG foo
|
||||||
|
|
||||||
|
# Includecmd
|
||||||
|
INCLUDECMD echo REM 16 Feb 1991 MSG Blork
|
||||||
|
INCLUDECMD echo REM 18 Feb 1991 MSG Blork
|
||||||
|
|
||||||
|
# Includecmd with continuation line
|
||||||
|
INCLUDECMD echo REM 18 Feb 1991 MSG This line is \
|
||||||
|
continued so there
|
||||||
|
|
||||||
|
# This should work
|
||||||
|
INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo MSG Yippee
|
||||||
|
|
||||||
|
# This should fail
|
||||||
|
INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo INCLUDECMD echo MSG Yippee
|
||||||
REM MSG Today is [hebday(today())] [hebmon(today())] [hebyear(today())]
|
REM MSG Today is [hebday(today())] [hebmon(today())] [hebyear(today())]
|
||||||
fset _h(x, y) trigger(hebdate(x,y))
|
fset _h(x, y) trigger(hebdate(x,y))
|
||||||
|
|
||||||
|
# Test case from Remind mailing list
|
||||||
|
set mltest "a b"
|
||||||
|
INCLUDECMD printf 'REM %s\n' [mltest]
|
||||||
|
|
||||||
|
# Disabling RUN in an !includecmd
|
||||||
|
INCLUDECMD !echo MSG foo
|
||||||
|
INCLUDECMD !echo MSG foo
|
||||||
|
INCLUDECMD !echo INCLUDECMD echo MSG foo
|
||||||
|
INCLUDECMD !echo INCLUDECMD echo MSG foo
|
||||||
|
INCLUDECMD !echo MSG foo
|
||||||
|
INCLUDECMD !echo MSG foo
|
||||||
|
|
||||||
|
# INCLUDECMD with RUN disabled
|
||||||
|
RUN OFF
|
||||||
|
INCLUDECMD echo MSG foo
|
||||||
|
RUN ON
|
||||||
|
INCLUDECMD echo MSG foo
|
||||||
|
|
||||||
[_h(1, "Tishrey")] MSG Rosh Hashana 1
|
[_h(1, "Tishrey")] MSG Rosh Hashana 1
|
||||||
[_h(2, "Tishrey")] MSG Rosh Hashana 2
|
[_h(2, "Tishrey")] MSG Rosh Hashana 2
|
||||||
[_h(3, "Tishrey")] MSG Tzom Gedalia
|
[_h(3, "Tishrey")] MSG Tzom Gedalia
|
||||||
@@ -551,8 +582,15 @@ set a $IntMin * 2
|
|||||||
set a $IntMin * $IntMin
|
set a $IntMin * $IntMin
|
||||||
set a $IntMin * $IntMax
|
set a $IntMin * $IntMax
|
||||||
set a $IntMin / (-1)
|
set a $IntMin / (-1)
|
||||||
|
set a $IntMin * (-1)
|
||||||
|
set a (-1) * $IntMin
|
||||||
set a abs($IntMin)
|
set a abs($IntMin)
|
||||||
|
|
||||||
|
# Shellescape
|
||||||
|
set a shellescape(" !\"#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")
|
||||||
|
|
||||||
|
msg [a]
|
||||||
|
|
||||||
# Don't want Remind to queue reminders
|
# Don't want Remind to queue reminders
|
||||||
EXIT
|
EXIT
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user