diff --git a/docs/WHATSNEW b/docs/WHATSNEW index f96ab643..b63cb1d9 100644 --- a/docs/WHATSNEW +++ b/docs/WHATSNEW @@ -35,6 +35,9 @@ CHANGES TO REMIND %{name} or %*{name} that end up calling the function subst_name and using its return value as the replacement for the substitution sequence. +- NEW FEATURE: remind: Add the FUNSET command to undefine a user-defined + function. + - BUG FIX: remind: Make MSF correctly format UTF-8 text and text with embedded ANSI color-changing codes. diff --git a/include/holidays/jewish.rem b/include/holidays/jewish.rem index 99866f77..b5206ab3 100644 --- a/include/holidays/jewish.rem +++ b/include/holidays/jewish.rem @@ -105,3 +105,7 @@ IF !Reform [_PastSat(17, "Tamuz")] ++4 MSG %"Tzom Tammuz%" is %b. [_PastSat(9, "Av")] ++4 MSG %"Tish'a B'Av%" is %b. ENDIF + +# Clean up +FUNSET _h _h2 _PastSat _BackTwoFri _BackTwoSat _chan + diff --git a/man/remind.1.in b/man/remind.1.in index 96d215f2..78d51951 100644 --- a/man/remind.1.in +++ b/man/remind.1.in @@ -4152,6 +4152,19 @@ with future versions of \fBRemind\fR (which may define more built-in functions), you may wish to name all user-defined functions beginning with an underscore. .PP +To delete a user-defined function, use \fBFUNSET\fR. This takes a +space-separated list of user-defined functions to delete. For +example, after the command: +.PP +.nf + FUNSET myfunc1 otherfunc thirdfunc +.fi +.PP +it is guaranteed that no user-defined functions named myfunc1, otherfunc +or thirdfunc will exist. \fBRemind\fR does not issue an error if you +try to \fBFUNSET\fR a nonexistent user-defined function; it simply +does nothing in that case. +.PP .SH PRECISE SCHEDULING .PP The \fBWARN\fR keyword allows precise control over advance warning in diff --git a/src/calendar.c b/src/calendar.c index c12692ad..3ff90144 100644 --- a/src/calendar.c +++ b/src/calendar.c @@ -1649,6 +1649,7 @@ static void GenerateCalEntries(int col) case T_Exit: DoExit(&p); break; case T_Set: r=DoSet(&p); break; case T_Fset: r=DoFset(&p); break; + case T_Funset: r=DoFunset(&p); break; case T_UnSet: r=DoUnset(&p); break; case T_Clr: r=DoClear(&p); break; case T_Flush: r=DoFlush(&p); break; diff --git a/src/main.c b/src/main.c index 65fae32a..47d01b5c 100644 --- a/src/main.c +++ b/src/main.c @@ -260,6 +260,7 @@ static void DoReminders(void) case T_Flush: r=DoFlush(&p); break; case T_Set: r=DoSet(&p); break; case T_Fset: r=DoFset(&p); break; + case T_Funset: r=DoFunset(&p); break; case T_UnSet: r=DoUnset(&p); break; case T_Clr: r=DoClear(&p); break; case T_Debug: r=DoDebug(&p); break; diff --git a/src/protos.h b/src/protos.h index 1e39923f..7dda3d6a 100644 --- a/src/protos.h +++ b/src/protos.h @@ -26,6 +26,7 @@ int CallUserFunc (char const *name, int nargs, ParsePtr p); int DoFset (ParsePtr p); +int DoFunset (ParsePtr p); void ProduceCalendar (void); char const *SimpleTime (int tim); char const *CalendarTime (int tim, int duration); diff --git a/src/token.c b/src/token.c index c0013837..e47398ac 100644 --- a/src/token.c +++ b/src/token.c @@ -62,6 +62,7 @@ Token TokArray[] = { { "friday", 3, T_WkDay, 4 }, { "from", 4, T_Scanfrom, FROM_TYPE }, { "fset", 4, T_Fset, 0 }, + { "funset", 6, T_Funset, 0 }, { "if", 2, T_If, 0 }, { "iftrig", 6, T_IfTrig, 0 }, { "in", 2, T_In, 0 }, diff --git a/src/types.h b/src/types.h index 40765139..1904e527 100644 --- a/src/types.h +++ b/src/types.h @@ -155,7 +155,7 @@ enum TokTypes /* Commands first */ T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_IncludeR, T_IncludeCmd, T_If, T_Else, T_EndIf, T_IfTrig, T_ErrMsg, - T_Set, T_UnSet, T_Fset, T_Omit, T_Banner, T_Exit, + T_Set, T_UnSet, T_Fset, T_Funset, T_Omit, T_Banner, T_Exit, T_AddOmit, T_WkDay, T_Month, T_Time, T_Date, T_DateTime, diff --git a/src/userfns.c b/src/userfns.c index c4f79bab..8adc8e70 100644 --- a/src/userfns.c +++ b/src/userfns.c @@ -53,6 +53,34 @@ static void FSet (UserFunc *f); static int SetUpLocalVars (UserFunc *f); static void DestroyLocalVals (UserFunc *f); +/***************************************************************/ +/* */ +/* DoFset */ +/* */ +/* Undefine a user-defined function - the FUNSET command. */ +/* */ +/***************************************************************/ +int DoFunset(ParsePtr p) +{ + int r; + int seen_one = 0; + DynamicBuffer buf; + DBufInit(&buf); + + while(1) { + r = ParseIdentifier(p, &buf); + if (r == E_EOLN) { + DBufFree(&buf); + break; + } + seen_one = 1; + FUnset(DBufValue(&buf)); + DBufFree(&buf); + } + if (seen_one) return OK; + return E_PARSE_ERR; +} + /***************************************************************/ /* */ /* DoFset */ diff --git a/tests/test.cmp b/tests/test.cmp index 3c184034..03d78710 100644 --- a/tests/test.cmp +++ b/tests/test.cmp @@ -4166,6 +4166,22 @@ 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 +# Test FUNSET +FSET square(x) x*x +SET a square(5) +Entering UserFN square(5) +x => 5 +x => 5 +5 * 5 => 25 +Leaving UserFN square() => 25 + +# FUNSET doesn't give an error if we funset nonexistent functions +FUNSET circle square rectangle + +# Should fail +SET a square(5) +../tests/test.rem(856): Undefined function: `square' + # Don't want Remind to queue reminders EXIT diff --git a/tests/test.rem b/tests/test.rem index bf1cda96..f97a084f 100644 --- a/tests/test.rem +++ b/tests/test.rem @@ -845,6 +845,16 @@ REM MSG Here: %{custom} REM MSG There: %*{custom} REM MSG Bad: %{custom +# Test FUNSET +FSET square(x) x*x +SET a square(5) + +# FUNSET doesn't give an error if we funset nonexistent functions +FUNSET circle square rectangle + +# Should fail +SET a square(5) + # Don't want Remind to queue reminders EXIT