mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-16 06:18:47 +02:00
Completely revamp expression engine.
This commit is contained in:
@@ -166,6 +166,10 @@
|
|||||||
|
|
||||||
#define PASSTHRU_LEN 32
|
#define PASSTHRU_LEN 32
|
||||||
|
|
||||||
|
#define MAX_RECURSION_LEVEL 1000
|
||||||
|
|
||||||
|
#define MAX_FUNC_ARGS 64
|
||||||
|
|
||||||
#define PSBEGIN "# rem2ps begin"
|
#define PSBEGIN "# rem2ps begin"
|
||||||
#define PSEND "# rem2ps end"
|
#define PSEND "# rem2ps end"
|
||||||
|
|
||||||
|
|||||||
@@ -166,6 +166,10 @@
|
|||||||
|
|
||||||
#define PASSTHRU_LEN 32
|
#define PASSTHRU_LEN 32
|
||||||
|
|
||||||
|
#define MAX_RECURSION_LEVEL 1000
|
||||||
|
|
||||||
|
#define MAX_FUNC_ARGS 64
|
||||||
|
|
||||||
#define PSBEGIN "# rem2ps begin"
|
#define PSBEGIN "# rem2ps begin"
|
||||||
#define PSEND "# rem2ps end"
|
#define PSEND "# rem2ps end"
|
||||||
|
|
||||||
|
|||||||
33
src/dorem.c
33
src/dorem.c
@@ -1268,20 +1268,28 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
|
|||||||
{
|
{
|
||||||
int iter, dse, r, start;
|
int iter, dse, r, start;
|
||||||
Value v;
|
Value v;
|
||||||
char const *s;
|
expr_node *sat_node;
|
||||||
char const *t;
|
int nonconst = 0;
|
||||||
|
|
||||||
t = p->pos;
|
sat_node = ParseExpr(p, &r);
|
||||||
|
if (r != OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (!sat_node) {
|
||||||
|
return E_SWERR;
|
||||||
|
}
|
||||||
iter = 0;
|
iter = 0;
|
||||||
start = trig->scanfrom;
|
start = trig->scanfrom;
|
||||||
while (iter++ < MaxSatIter) {
|
while (iter++ < MaxSatIter) {
|
||||||
dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, 0);
|
dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, 0);
|
||||||
if (r) {
|
if (r) {
|
||||||
|
free_expr_tree(sat_node);
|
||||||
if (r == E_CANT_TRIG) return OK; else return r;
|
if (r == E_CANT_TRIG) return OK; else return r;
|
||||||
}
|
}
|
||||||
if (dse != start && trig->duration_days) {
|
if (dse != start && trig->duration_days) {
|
||||||
dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, trig->duration_days);
|
dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, trig->duration_days);
|
||||||
if (r) {
|
if (r) {
|
||||||
|
free_expr_tree(sat_node);
|
||||||
if (r == E_CANT_TRIG) return OK; else return r;
|
if (r == E_CANT_TRIG) return OK; else return r;
|
||||||
}
|
}
|
||||||
} else if (dse == start) {
|
} else if (dse == start) {
|
||||||
@@ -1294,13 +1302,18 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
|
|||||||
SaveAllTriggerInfo(trig, tt, dse, tt->ttime, 1);
|
SaveAllTriggerInfo(trig, tt, dse, tt->ttime, 1);
|
||||||
}
|
}
|
||||||
if (dse == -1) {
|
if (dse == -1) {
|
||||||
|
free_expr_tree(sat_node);
|
||||||
return E_EXPIRED;
|
return E_EXPIRED;
|
||||||
}
|
}
|
||||||
s = p->pos;
|
r = evaluate_expr_node(sat_node, NULL, &v, &nonconst);
|
||||||
r = EvaluateExpr(p, &v);
|
if (r) {
|
||||||
t = p->pos;
|
free_expr_tree(sat_node);
|
||||||
if (r) return r;
|
return r;
|
||||||
if (v.type != INT_TYPE && v.type != STR_TYPE) return E_BAD_TYPE;
|
}
|
||||||
|
if (v.type != INT_TYPE && v.type != STR_TYPE) {
|
||||||
|
free_expr_tree(sat_node);
|
||||||
|
return E_BAD_TYPE;
|
||||||
|
}
|
||||||
if ((v.type == INT_TYPE && v.v.val) ||
|
if ((v.type == INT_TYPE && v.v.val) ||
|
||||||
(v.type == STR_TYPE && *v.v.str)) {
|
(v.type == STR_TYPE && *v.v.str)) {
|
||||||
AdjustTriggerForDuration(trig->scanfrom, dse, trig, tt, 1);
|
AdjustTriggerForDuration(trig->scanfrom, dse, trig, tt, 1);
|
||||||
@@ -1325,17 +1338,17 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
|
|||||||
}
|
}
|
||||||
fprintf(ErrFp, "\n");
|
fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
|
free_expr_tree(sat_node);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
p->pos = s;
|
|
||||||
if (dse+trig->duration_days < start) {
|
if (dse+trig->duration_days < start) {
|
||||||
start++;
|
start++;
|
||||||
} else {
|
} else {
|
||||||
start = dse+trig->duration_days+1;
|
start = dse+trig->duration_days+1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p->pos = t;
|
|
||||||
LastTrigValid = 0;
|
LastTrigValid = 0;
|
||||||
|
free_expr_tree(sat_node);
|
||||||
return E_CANT_TRIG;
|
return E_CANT_TRIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "types.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#define L_IN_DOSUBST
|
#define L_IN_DOSUBST
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -20,7 +21,6 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "protos.h"
|
#include "protos.h"
|
||||||
|
|||||||
@@ -124,7 +124,9 @@ int DBufPuts(DynamicBuffer *dbuf, char const *str)
|
|||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
void DBufFree(DynamicBuffer *dbuf)
|
void DBufFree(DynamicBuffer *dbuf)
|
||||||
{
|
{
|
||||||
if (dbuf->buffer != dbuf->staticBuf) free(dbuf->buffer);
|
if (dbuf->buffer != NULL && dbuf->buffer != dbuf->staticBuf) {
|
||||||
|
free(dbuf->buffer);
|
||||||
|
}
|
||||||
DBufInit(dbuf);
|
DBufInit(dbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ EXTERN char *ErrMsg[]
|
|||||||
"RUN disabled",
|
"RUN disabled",
|
||||||
"Domain error",
|
"Domain error",
|
||||||
"Invalid identifier",
|
"Invalid identifier",
|
||||||
"Recursive function call detected",
|
"Too many recursive function calls",
|
||||||
"",
|
"",
|
||||||
"Cannot modify system variable",
|
"Cannot modify system variable",
|
||||||
"C library function can't represent date/time",
|
"C library function can't represent date/time",
|
||||||
|
|||||||
3140
src/expr.c
3140
src/expr.c
File diff suppressed because it is too large
Load Diff
46
src/expr.h
46
src/expr.h
@@ -1,15 +1,19 @@
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* EXPR.H */
|
/* EXPR_NEW.H */
|
||||||
/* */
|
/* */
|
||||||
/* Contains a few definitions used by expression evaluator. */
|
/* Contains a few definitions used by expression pareser and */
|
||||||
|
/* evaluator. */
|
||||||
/* */
|
/* */
|
||||||
/* This file is part of REMIND. */
|
/* This file is part of REMIND. */
|
||||||
/* Copyright (C) 1992-2024 by Dianne Skoll */
|
/* Copyright (C) 2022 by Dianne Skoll */
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
||||||
|
typedef struct udf_struct UserFunc;
|
||||||
|
|
||||||
|
expr_node *parse_expression(char const **e, int *r, Var *locals);
|
||||||
|
|
||||||
/* Define the types of values */
|
/* Define the types of values */
|
||||||
#define ERR_TYPE 0
|
#define ERR_TYPE 0
|
||||||
#define INT_TYPE 1
|
#define INT_TYPE 1
|
||||||
@@ -20,43 +24,10 @@
|
|||||||
#define SPECIAL_TYPE 6 /* Only for system variables */
|
#define SPECIAL_TYPE 6 /* Only for system variables */
|
||||||
#define CONST_INT_TYPE 7 /* Only for system variables */
|
#define CONST_INT_TYPE 7 /* Only for system variables */
|
||||||
|
|
||||||
/* Define stuff for parsing expressions */
|
|
||||||
#define BEG_OF_EXPR '['
|
#define BEG_OF_EXPR '['
|
||||||
#define END_OF_EXPR ']'
|
#define END_OF_EXPR ']'
|
||||||
#define COMMA ','
|
#define COMMA ','
|
||||||
|
|
||||||
#define UN_OP 0 /* Unary operator */
|
|
||||||
#define BIN_OP 1 /* Binary Operator */
|
|
||||||
#define FUNC 2 /* Function */
|
|
||||||
|
|
||||||
/* Make the pushing and popping of values and operators in-line code
|
|
||||||
for speed. BEWARE: These macros invoke return if an error happens ! */
|
|
||||||
|
|
||||||
#define PushOpStack(op) \
|
|
||||||
do { if (OpStackPtr >= OP_STACK_SIZE) return E_OP_STK_OVER; \
|
|
||||||
else { OpStack[OpStackPtr++] = (op); if (OpStackPtr > OpStackHiWater) OpStackHiWater = OpStackPtr; } } while(0)
|
|
||||||
|
|
||||||
#define PopOpStack(op) \
|
|
||||||
if (OpStackPtr <= 0) \
|
|
||||||
return E_OP_STK_UNDER; \
|
|
||||||
else \
|
|
||||||
(op) = OpStack[--OpStackPtr]
|
|
||||||
|
|
||||||
#define PushValStack(val) \
|
|
||||||
do { if (ValStackPtr >= VAL_STACK_SIZE) { \
|
|
||||||
DestroyValue(val); \
|
|
||||||
return E_VA_STK_OVER; \
|
|
||||||
} else { \
|
|
||||||
ValStack[ValStackPtr++] = (val); \
|
|
||||||
if (ValStackPtr > ValStackHiWater) ValStackHiWater = ValStackPtr; \
|
|
||||||
} } while (0);
|
|
||||||
|
|
||||||
#define PopValStack(val) \
|
|
||||||
if (ValStackPtr <= 0) \
|
|
||||||
return E_VA_STK_UNDER; \
|
|
||||||
else \
|
|
||||||
(val) = ValStack[--ValStackPtr]
|
|
||||||
|
|
||||||
/* These functions are in utils.c and are used to detect overflow
|
/* These functions are in utils.c and are used to detect overflow
|
||||||
in various arithmetic operators. They have to be in separate
|
in various arithmetic operators. They have to be in separate
|
||||||
functions with extern linkage to defeat compiler optimizations
|
functions with extern linkage to defeat compiler optimizations
|
||||||
@@ -64,4 +35,3 @@ else \
|
|||||||
extern int _private_mul_overflow(int a, int b);
|
extern int _private_mul_overflow(int a, int b);
|
||||||
extern int _private_add_overflow(int a, int b);
|
extern int _private_add_overflow(int a, int b);
|
||||||
extern int _private_sub_overflow(int a, int b);
|
extern int _private_sub_overflow(int a, int b);
|
||||||
|
|
||||||
|
|||||||
559
src/funcs.c
559
src/funcs.c
@@ -60,6 +60,8 @@
|
|||||||
#define Nargs (info->nargs)
|
#define Nargs (info->nargs)
|
||||||
#define RetVal (info->retval)
|
#define RetVal (info->retval)
|
||||||
|
|
||||||
|
#define DBG(x) do { if (DebugFlag & DB_PRTEXPR) { x; } } while(0)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
solstice_equinox_for_year(int y, int which);
|
solstice_equinox_for_year(int y, int which);
|
||||||
|
|
||||||
@@ -74,7 +76,7 @@ static int FArgs (func_info *);
|
|||||||
static int FAsc (func_info *);
|
static int FAsc (func_info *);
|
||||||
static int FBaseyr (func_info *);
|
static int FBaseyr (func_info *);
|
||||||
static int FChar (func_info *);
|
static int FChar (func_info *);
|
||||||
static int FChoose (func_info *);
|
static int FChoose (expr_node *, Value *, Value *, int *);
|
||||||
static int FCoerce (func_info *);
|
static int FCoerce (func_info *);
|
||||||
static int FColumns (func_info *);
|
static int FColumns (func_info *);
|
||||||
static int FCurrent (func_info *);
|
static int FCurrent (func_info *);
|
||||||
@@ -101,7 +103,7 @@ static int FHebyear (func_info *);
|
|||||||
static int FHour (func_info *);
|
static int FHour (func_info *);
|
||||||
static int FHtmlEscape (func_info *);
|
static int FHtmlEscape (func_info *);
|
||||||
static int FHtmlStriptags (func_info *);
|
static int FHtmlStriptags (func_info *);
|
||||||
static int FIif (func_info *);
|
static int FIif (expr_node *, Value *, Value *, int *);
|
||||||
static int FIndex (func_info *);
|
static int FIndex (func_info *);
|
||||||
static int FIsAny (func_info *);
|
static int FIsAny (func_info *);
|
||||||
static int FIsdst (func_info *);
|
static int FIsdst (func_info *);
|
||||||
@@ -180,14 +182,9 @@ 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 CleanUpAfterFunc (func_info *);
|
|
||||||
static int CheckArgs (BuiltinFunc *f, int nargs);
|
|
||||||
static int SunStuff (int rise, double cosz, int dse);
|
static int SunStuff (int rise, double cosz, int dse);
|
||||||
static int tz_set_tz (char const *tz);
|
static int tz_set_tz (char const *tz);
|
||||||
|
|
||||||
/* "Overload" the struct Operator definition */
|
|
||||||
#define NO_MAX 127
|
|
||||||
|
|
||||||
/* Caches for extracting months, days, years from dates - may
|
/* Caches for extracting months, days, years from dates - may
|
||||||
improve performance slightly. */
|
improve performance slightly. */
|
||||||
static int CacheDse = -1;
|
static int CacheDse = -1;
|
||||||
@@ -196,14 +193,9 @@ static int CacheYear, CacheMon, CacheDay;
|
|||||||
static int CacheHebDse = -1;
|
static int CacheHebDse = -1;
|
||||||
static int CacheHebYear, CacheHebMon, CacheHebDay;
|
static int CacheHebYear, CacheHebMon, CacheHebDay;
|
||||||
|
|
||||||
/* We need access to the value stack */
|
|
||||||
extern Value ValStack[];
|
|
||||||
extern int ValStackPtr;
|
|
||||||
extern int ValStackHiWater;
|
|
||||||
|
|
||||||
/* Macro for accessing arguments from the value stack - args are numbered
|
/* Macro for accessing arguments from the value stack - args are numbered
|
||||||
from 0 to (Nargs - 1) */
|
from 0 to (Nargs - 1) */
|
||||||
#define ARG(x) (ValStack[ValStackPtr - Nargs + (x)])
|
#define ARG(x) (info->args[x])
|
||||||
|
|
||||||
#define ARGV(x) ARG(x).v.val
|
#define ARGV(x) ARG(x).v.val
|
||||||
#define ARGSTR(x) ARG(x).v.str
|
#define ARGSTR(x) ARG(x).v.str
|
||||||
@@ -231,215 +223,127 @@ extern int ValStackHiWater;
|
|||||||
|
|
||||||
/* The array holding the built-in functions. */
|
/* The array holding the built-in functions. */
|
||||||
BuiltinFunc Func[] = {
|
BuiltinFunc Func[] = {
|
||||||
/* Name minargs maxargs is_constant func */
|
/* Name minargs maxargs is_constant func newfunc*/
|
||||||
|
|
||||||
{ "abs", 1, 1, 1, FAbs },
|
{ "abs", 1, 1, 1, FAbs, NULL },
|
||||||
{ "access", 2, 2, 0, FAccess },
|
{ "access", 2, 2, 0, FAccess, NULL },
|
||||||
{ "adawn", 0, 1, 0, FADawn},
|
{ "adawn", 0, 1, 0, FADawn, NULL},
|
||||||
{ "adusk", 0, 1, 0, FADusk},
|
{ "adusk", 0, 1, 0, FADusk, NULL},
|
||||||
{ "ampm", 1, 3, 1, FAmpm },
|
{ "ampm", 1, 3, 1, FAmpm, NULL },
|
||||||
{ "ansicolor", 1, 5, 1, FAnsicolor },
|
{ "ansicolor", 1, 5, 1, FAnsicolor, NULL },
|
||||||
{ "args", 1, 1, 0, FArgs },
|
{ "args", 1, 1, 0, FArgs, NULL },
|
||||||
{ "asc", 1, 1, 1, FAsc },
|
{ "asc", 1, 1, 1, FAsc, NULL },
|
||||||
{ "baseyr", 0, 0, 1, FBaseyr },
|
{ "baseyr", 0, 0, 1, FBaseyr, NULL },
|
||||||
{ "char", 1, NO_MAX, 1, FChar },
|
{ "char", 1, NO_MAX, 1, FChar, NULL },
|
||||||
{ "choose", 2, NO_MAX, 1, FChoose },
|
{ "choose", 2, NO_MAX, 1, NULL, FChoose }, /*NEW-STYLE*/
|
||||||
{ "coerce", 2, 2, 1, FCoerce },
|
{ "coerce", 2, 2, 1, FCoerce, NULL },
|
||||||
{ "columns", 0, 1, 0, FColumns },
|
{ "columns", 0, 1, 0, FColumns, NULL },
|
||||||
{ "current", 0, 0, 0, FCurrent },
|
{ "current", 0, 0, 0, FCurrent, NULL },
|
||||||
{ "date", 3, 3, 1, FDate },
|
{ "date", 3, 3, 1, FDate, NULL },
|
||||||
{ "datepart", 1, 1, 1, FDatepart },
|
{ "datepart", 1, 1, 1, FDatepart, NULL },
|
||||||
{ "datetime", 2, 5, 1, FDateTime },
|
{ "datetime", 2, 5, 1, FDateTime, NULL },
|
||||||
{ "dawn", 0, 1, 0, FDawn},
|
{ "dawn", 0, 1, 0, FDawn, NULL },
|
||||||
{ "day", 1, 1, 1, FDay },
|
{ "day", 1, 1, 1, FDay, NULL },
|
||||||
{ "daysinmon", 2, 2, 1, FDaysinmon },
|
{ "daysinmon", 2, 2, 1, FDaysinmon, NULL },
|
||||||
{ "defined", 1, 1, 0, FDefined },
|
{ "defined", 1, 1, 0, FDefined, NULL },
|
||||||
{ "dosubst", 1, 3, 0, FDosubst },
|
{ "dosubst", 1, 3, 0, FDosubst, NULL },
|
||||||
{ "dusk", 0, 1, 0, FDusk },
|
{ "dusk", 0, 1, 0, FDusk, NULL },
|
||||||
{ "easterdate", 0, 1, 0, FEasterdate },
|
{ "easterdate", 0, 1, 0, FEasterdate, NULL },
|
||||||
{ "evaltrig", 1, 2, 0, FEvalTrig },
|
{ "evaltrig", 1, 2, 0, FEvalTrig, NULL },
|
||||||
{ "filedate", 1, 1, 0, FFiledate },
|
{ "filedate", 1, 1, 0, FFiledate, NULL },
|
||||||
{ "filedatetime", 1, 1, 0, FFiledatetime },
|
{ "filedatetime", 1, 1, 0, FFiledatetime, NULL },
|
||||||
{ "filedir", 0, 0, 0, FFiledir },
|
{ "filedir", 0, 0, 0, FFiledir, NULL },
|
||||||
{ "filename", 0, 0, 0, FFilename },
|
{ "filename", 0, 0, 0, FFilename, NULL },
|
||||||
{ "getenv", 1, 1, 0, FGetenv },
|
{ "getenv", 1, 1, 0, FGetenv, NULL },
|
||||||
{ "hebdate", 2, 5, 0, FHebdate },
|
{ "hebdate", 2, 5, 0, FHebdate, NULL },
|
||||||
{ "hebday", 1, 1, 0, FHebday },
|
{ "hebday", 1, 1, 0, FHebday, NULL },
|
||||||
{ "hebmon", 1, 1, 0, FHebmon },
|
{ "hebmon", 1, 1, 0, FHebmon, NULL },
|
||||||
{ "hebyear", 1, 1, 0, FHebyear },
|
{ "hebyear", 1, 1, 0, FHebyear, NULL },
|
||||||
{ "hour", 1, 1, 1, FHour },
|
{ "hour", 1, 1, 1, FHour, NULL },
|
||||||
{ "htmlescape", 1, 1, 1, FHtmlEscape },
|
{ "htmlescape", 1, 1, 1, FHtmlEscape, NULL },
|
||||||
{ "htmlstriptags",1, 1, 1, FHtmlStriptags },
|
{ "htmlstriptags",1, 1, 1, FHtmlStriptags, NULL },
|
||||||
{ "iif", 1, NO_MAX, 1, FIif },
|
{ "iif", 1, NO_MAX, 1, NULL, FIif }, /*NEW-STYLE*/
|
||||||
{ "index", 2, 3, 1, FIndex },
|
{ "index", 2, 3, 1, FIndex, NULL },
|
||||||
{ "isany", 1, NO_MAX, 1, FIsAny },
|
{ "isany", 1, NO_MAX, 1, FIsAny, NULL },
|
||||||
{ "isdst", 0, 2, 0, FIsdst },
|
{ "isdst", 0, 2, 0, FIsdst, NULL },
|
||||||
{ "isleap", 1, 1, 1, FIsleap },
|
{ "isleap", 1, 1, 1, FIsleap, NULL },
|
||||||
{ "isomitted", 1, 1, 0, FIsomitted },
|
{ "isomitted", 1, 1, 0, FIsomitted, NULL },
|
||||||
{ "language", 0, 0, 1, FLanguage },
|
{ "language", 0, 0, 1, FLanguage, NULL },
|
||||||
{ "localtoutc", 1, 1, 1, FLocalToUTC },
|
{ "localtoutc", 1, 1, 1, FLocalToUTC, NULL },
|
||||||
{ "lower", 1, 1, 1, FLower },
|
{ "lower", 1, 1, 1, FLower, NULL },
|
||||||
{ "max", 1, NO_MAX, 1, FMax },
|
{ "max", 1, NO_MAX, 1, FMax, NULL },
|
||||||
{ "min", 1, NO_MAX, 1, FMin },
|
{ "min", 1, NO_MAX, 1, FMin, NULL },
|
||||||
{ "minsfromutc", 0, 2, 0, FMinsfromutc },
|
{ "minsfromutc", 0, 2, 0, FMinsfromutc, NULL },
|
||||||
{ "minute", 1, 1, 1, FMinute },
|
{ "minute", 1, 1, 1, FMinute, NULL },
|
||||||
{ "mon", 1, 1, 1, FMon },
|
{ "mon", 1, 1, 1, FMon, NULL },
|
||||||
{ "monnum", 1, 1, 1, FMonnum },
|
{ "monnum", 1, 1, 1, FMonnum, NULL },
|
||||||
{ "moondate", 1, 3, 0, FMoondate },
|
{ "moondate", 1, 3, 0, FMoondate, NULL },
|
||||||
{ "moondatetime", 1, 3, 0, FMoondatetime },
|
{ "moondatetime", 1, 3, 0, FMoondatetime, NULL },
|
||||||
{ "moonphase", 0, 2, 0, FMoonphase },
|
{ "moonphase", 0, 2, 0, FMoonphase, NULL },
|
||||||
{ "moontime", 1, 3, 0, FMoontime },
|
{ "moontime", 1, 3, 0, FMoontime, NULL },
|
||||||
{ "multitrig", 1, NO_MAX, 0, FMultiTrig },
|
{ "multitrig", 1, NO_MAX, 0, FMultiTrig, NULL },
|
||||||
{ "ndawn", 0, 1, 0, FNDawn},
|
{ "ndawn", 0, 1, 0, FNDawn, NULL },
|
||||||
{ "ndusk", 0, 1, 0, FNDusk},
|
{ "ndusk", 0, 1, 0, FNDusk, NULL },
|
||||||
{ "nonomitted", 2, NO_MAX, 0, FNonomitted },
|
{ "nonomitted", 2, NO_MAX, 0, FNonomitted, NULL },
|
||||||
{ "now", 0, 0, 0, FNow },
|
{ "now", 0, 0, 0, FNow, NULL },
|
||||||
{ "ord", 1, 1, 1, FOrd },
|
{ "ord", 1, 1, 1, FOrd, NULL },
|
||||||
{ "orthodoxeaster",0, 1, 0, FOrthodoxeaster },
|
{ "orthodoxeaster",0, 1, 0, FOrthodoxeaster, NULL },
|
||||||
{ "ostype", 0, 0, 1, FOstype },
|
{ "ostype", 0, 0, 1, FOstype, NULL },
|
||||||
{ "pad", 3, 4, 1, FPad },
|
{ "pad", 3, 4, 1, FPad, NULL },
|
||||||
{ "plural", 1, 3, 1, FPlural },
|
{ "plural", 1, 3, 1, FPlural, NULL },
|
||||||
{ "psmoon", 1, 4, 1, FPsmoon},
|
{ "psmoon", 1, 4, 1, FPsmoon, NULL },
|
||||||
{ "psshade", 1, 3, 1, FPsshade},
|
{ "psshade", 1, 3, 1, FPsshade, NULL },
|
||||||
{ "realcurrent", 0, 0, 0, FRealCurrent},
|
{ "realcurrent", 0, 0, 0, FRealCurrent, NULL },
|
||||||
{ "realnow", 0, 0, 0, FRealnow},
|
{ "realnow", 0, 0, 0, FRealnow, NULL },
|
||||||
{ "realtoday", 0, 0, 0, FRealtoday },
|
{ "realtoday", 0, 0, 0, FRealtoday, NULL },
|
||||||
{ "rows", 0, 0, 0, FRows },
|
{ "rows", 0, 0, 0, FRows, NULL },
|
||||||
{ "sgn", 1, 1, 1, FSgn },
|
{ "sgn", 1, 1, 1, FSgn, NULL },
|
||||||
{ "shell", 1, 2, 0, FShell },
|
{ "shell", 1, 2, 0, FShell, NULL },
|
||||||
{ "shellescape", 1, 1, 1, FShellescape },
|
{ "shellescape", 1, 1, 1, FShellescape, NULL },
|
||||||
{ "slide", 2, NO_MAX, 0, FSlide },
|
{ "slide", 2, NO_MAX, 0, FSlide, NULL },
|
||||||
{ "soleq", 1, 2, 0, FSoleq },
|
{ "soleq", 1, 2, 0, FSoleq, NULL },
|
||||||
{ "stdout", 0, 0, 1, FStdout },
|
{ "stdout", 0, 0, 1, FStdout, NULL },
|
||||||
{ "strlen", 1, 1, 1, FStrlen },
|
{ "strlen", 1, 1, 1, FStrlen, NULL },
|
||||||
{ "substr", 2, 3, 1, FSubstr },
|
{ "substr", 2, 3, 1, FSubstr, NULL },
|
||||||
{ "sunrise", 0, 1, 0, FSunrise},
|
{ "sunrise", 0, 1, 0, FSunrise, NULL },
|
||||||
{ "sunset", 0, 1, 0, FSunset },
|
{ "sunset", 0, 1, 0, FSunset, NULL },
|
||||||
{ "time", 2, 2, 1, FTime },
|
{ "time", 2, 2, 1, FTime, NULL },
|
||||||
{ "timepart", 1, 1, 1, FTimepart },
|
{ "timepart", 1, 1, 1, FTimepart, NULL },
|
||||||
{ "timezone", 0, 1, 1, FTimezone },
|
{ "timezone", 0, 1, 1, FTimezone, NULL },
|
||||||
{ "today", 0, 0, 0, FToday },
|
{ "today", 0, 0, 0, FToday, NULL },
|
||||||
{ "trig", 0, NO_MAX, 0, FTrig },
|
{ "trig", 0, NO_MAX, 0, FTrig, NULL },
|
||||||
{ "trigback", 0, 0, 0, FTrigback },
|
{ "trigback", 0, 0, 0, FTrigback, NULL },
|
||||||
{ "trigdate", 0, 0, 0, FTrigdate },
|
{ "trigdate", 0, 0, 0, FTrigdate, NULL },
|
||||||
{ "trigdatetime", 0, 0, 0, FTrigdatetime },
|
{ "trigdatetime", 0, 0, 0, FTrigdatetime, NULL },
|
||||||
{ "trigdelta", 0, 0, 0, FTrigdelta },
|
{ "trigdelta", 0, 0, 0, FTrigdelta, NULL },
|
||||||
{ "trigduration", 0, 0, 0, FTrigduration },
|
{ "trigduration", 0, 0, 0, FTrigduration, NULL },
|
||||||
{ "trigeventduration", 0, 0, 0, FTrigeventduration },
|
{ "trigeventduration", 0, 0, 0, FTrigeventduration, NULL },
|
||||||
{ "trigeventstart", 0, 0, 0, FTrigeventstart },
|
{ "trigeventstart", 0, 0, 0, FTrigeventstart, NULL },
|
||||||
{ "trigfrom", 0, 0, 0, FTrigfrom },
|
{ "trigfrom", 0, 0, 0, FTrigfrom, NULL },
|
||||||
{ "trigger", 1, 3, 0, FTrigger },
|
{ "trigger", 1, 3, 0, FTrigger, NULL },
|
||||||
{ "trigpriority", 0, 0, 0, FTrigpriority },
|
{ "trigpriority", 0, 0, 0, FTrigpriority, NULL },
|
||||||
{ "trigrep", 0, 0, 0, FTrigrep },
|
{ "trigrep", 0, 0, 0, FTrigrep, NULL },
|
||||||
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom },
|
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom, NULL },
|
||||||
{ "trigtags", 0, 0, 0, FTrigtags },
|
{ "trigtags", 0, 0, 0, FTrigtags, NULL },
|
||||||
{ "trigtime", 0, 0, 0, FTrigtime },
|
{ "trigtime", 0, 0, 0, FTrigtime, NULL },
|
||||||
{ "trigtimedelta",0, 0, 0, FTrigtimedelta },
|
{ "trigtimedelta",0, 0, 0, FTrigtimedelta, NULL },
|
||||||
{ "trigtimerep", 0, 0, 0, FTrigtimerep },
|
{ "trigtimerep", 0, 0, 0, FTrigtimerep, NULL },
|
||||||
{ "triguntil", 0, 0, 0, FTriguntil },
|
{ "triguntil", 0, 0, 0, FTriguntil, NULL },
|
||||||
{ "trigvalid", 0, 0, 0, FTrigvalid },
|
{ "trigvalid", 0, 0, 0, FTrigvalid, NULL },
|
||||||
{ "typeof", 1, 1, 1, FTypeof },
|
{ "typeof", 1, 1, 1, FTypeof, NULL },
|
||||||
{ "tzconvert", 2, 3, 0, FTzconvert },
|
{ "tzconvert", 2, 3, 0, FTzconvert, NULL },
|
||||||
{ "upper", 1, 1, 1, FUpper },
|
{ "upper", 1, 1, 1, FUpper, NULL },
|
||||||
{ "utctolocal", 1, 1, 1, FUTCToLocal },
|
{ "utctolocal", 1, 1, 1, FUTCToLocal, NULL },
|
||||||
{ "value", 1, 2, 0, FValue },
|
{ "value", 1, 2, 0, FValue, NULL },
|
||||||
{ "version", 0, 0, 1, FVersion },
|
{ "version", 0, 0, 1, FVersion, NULL },
|
||||||
{ "weekno", 0, 3, 1, FWeekno },
|
{ "weekno", 0, 3, 1, FWeekno, NULL },
|
||||||
{ "wkday", 1, 1, 1, FWkday },
|
{ "wkday", 1, 1, 1, FWkday, NULL },
|
||||||
{ "wkdaynum", 1, 1, 1, FWkdaynum },
|
{ "wkdaynum", 1, 1, 1, FWkdaynum, NULL },
|
||||||
{ "year", 1, 1, 1, FYear }
|
{ "year", 1, 1, 1, FYear, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Need a variable here - Func[] array not really visible to outside. */
|
/* Need a variable here - Func[] array not really visible to outside. */
|
||||||
int NumFuncs = sizeof(Func) / sizeof(Operator) ;
|
int NumFuncs = sizeof(Func) / sizeof(BuiltinFunc) ;
|
||||||
|
|
||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* CallFunc */
|
|
||||||
/* */
|
|
||||||
/* Call a function given a pointer to it, and the number */
|
|
||||||
/* of arguments supplied. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
int CallFunc(BuiltinFunc *f, int nargs)
|
|
||||||
{
|
|
||||||
register int r = CheckArgs(f, nargs);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
func_info info_obj;
|
|
||||||
func_info *info = &info_obj;
|
|
||||||
|
|
||||||
Nargs = nargs;
|
|
||||||
RetVal.type = ERR_TYPE;
|
|
||||||
|
|
||||||
if (DebugFlag & DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s(", f->name);
|
|
||||||
for (i=0; i<nargs; i++) {
|
|
||||||
PrintValue(&ARG(i), ErrFp);
|
|
||||||
if (i<nargs-1) fprintf(ErrFp, ", ");
|
|
||||||
}
|
|
||||||
fprintf(ErrFp, ") => ");
|
|
||||||
if (r) {
|
|
||||||
fprintf(ErrFp, "%s\n", ErrMsg[r]);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (r) {
|
|
||||||
Eprint("%s(): %s", f->name, ErrMsg[r]);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = (*(f->func))(info);
|
|
||||||
if (r) {
|
|
||||||
DestroyValue(RetVal);
|
|
||||||
if (DebugFlag & DB_PRTEXPR)
|
|
||||||
fprintf(ErrFp, "%s\n", ErrMsg[r]);
|
|
||||||
else
|
|
||||||
Eprint("%s(): %s", f->name, ErrMsg[r]);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
if (DebugFlag & DB_PRTEXPR) {
|
|
||||||
PrintValue(&RetVal, ErrFp);
|
|
||||||
fprintf(ErrFp, "\n");
|
|
||||||
}
|
|
||||||
r = CleanUpAfterFunc(info);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* CheckArgs */
|
|
||||||
/* */
|
|
||||||
/* Check that the right number of args have been supplied */
|
|
||||||
/* for a function. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
static int CheckArgs(BuiltinFunc *f, int nargs)
|
|
||||||
{
|
|
||||||
if (nargs < f->minargs) return E_2FEW_ARGS;
|
|
||||||
if (nargs > f->maxargs && f->maxargs != NO_MAX) return E_2MANY_ARGS;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* CleanUpAfterFunc */
|
|
||||||
/* */
|
|
||||||
/* Clean up the stack after a function call - remove */
|
|
||||||
/* args and push the new value. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
static int CleanUpAfterFunc(func_info *info)
|
|
||||||
{
|
|
||||||
Value v;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=0; i<Nargs; i++) {
|
|
||||||
PopValStack(v);
|
|
||||||
DestroyValue(v);
|
|
||||||
}
|
|
||||||
PushValStack(RetVal);
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
@@ -1279,6 +1183,9 @@ static int FIsAny(func_info *info)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Debugging helpers for "choose()" and "iif() */
|
||||||
|
#define PUT(x) DBufPuts(&DebugBuf, x)
|
||||||
|
#define OUT() do { fprintf(ErrFp, "%s\n", DBufValue(&DebugBuf)); DBufFree(&DebugBuf); } while(0)
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* FChoose */
|
/* FChoose */
|
||||||
@@ -1287,15 +1194,63 @@ static int FIsAny(func_info *info)
|
|||||||
/* from 1. */
|
/* from 1. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static int FChoose(func_info *info)
|
static int FChoose(expr_node *node, Value *locals, Value *ans, int *nonconst)
|
||||||
{
|
{
|
||||||
int v;
|
DynamicBuffer DebugBuf;
|
||||||
|
expr_node *cur;
|
||||||
|
int r;
|
||||||
|
int n;
|
||||||
|
int nargs = node->num_kids;
|
||||||
|
Value(v);
|
||||||
|
DBG(DBufInit(&DebugBuf));
|
||||||
|
PUT("choose(");
|
||||||
|
|
||||||
ASSERT_TYPE(0, INT_TYPE);
|
cur = node->child;
|
||||||
v = ARGV(0);
|
r = evaluate_expr_node(cur, locals, &v, nonconst);
|
||||||
if (v < 1) v = 1;
|
if (r != OK) {
|
||||||
if (v > Nargs-1) v = Nargs-1;
|
DBG(DBufFree(&DebugBuf));
|
||||||
DCOPYVAL(RetVal, ARG(v));
|
return r;
|
||||||
|
}
|
||||||
|
DBG(PUT(PrintValue(&v, NULL)));
|
||||||
|
if (v.type != INT_TYPE) {
|
||||||
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
|
cur = cur->sibling;
|
||||||
|
while(cur) {
|
||||||
|
PUT(", ?");
|
||||||
|
cur = cur->sibling;
|
||||||
|
}
|
||||||
|
PUT(") => ");
|
||||||
|
PUT(ErrMsg[E_BAD_TYPE]);
|
||||||
|
OUT();
|
||||||
|
}
|
||||||
|
return E_BAD_TYPE;
|
||||||
|
}
|
||||||
|
n = v.v.val;
|
||||||
|
if (n < 1) n = 1;
|
||||||
|
if (n > nargs-1) n = nargs-1;
|
||||||
|
|
||||||
|
while(n--) {
|
||||||
|
cur = cur->sibling;
|
||||||
|
DBG(if (n) { PUT(", ?"); });
|
||||||
|
if (!cur) return E_SWERR; /* Should not happen! */
|
||||||
|
}
|
||||||
|
r = evaluate_expr_node(cur, locals, ans, nonconst);
|
||||||
|
if (r != OK) {
|
||||||
|
DBG(DBufFree(&DebugBuf));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
|
PUT(", ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
cur = cur->sibling;
|
||||||
|
while(cur) {
|
||||||
|
PUT(", ?");
|
||||||
|
cur = cur->sibling;
|
||||||
|
}
|
||||||
|
PUT(") => ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
OUT();
|
||||||
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1481,7 +1436,7 @@ static int FValue(func_info *info)
|
|||||||
ASSERT_TYPE(0, STR_TYPE);
|
ASSERT_TYPE(0, STR_TYPE);
|
||||||
switch(Nargs) {
|
switch(Nargs) {
|
||||||
case 1:
|
case 1:
|
||||||
return GetVarValue(ARGSTR(0), &RetVal, NULL, NULL);
|
return GetVarValue(ARGSTR(0), &RetVal);
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
v = FindVar(ARGSTR(0), 0);
|
v = FindVar(ARGSTR(0), 0);
|
||||||
@@ -1953,33 +1908,101 @@ static int FIndex(func_info *info)
|
|||||||
/* */
|
/* */
|
||||||
/* FIif */
|
/* FIif */
|
||||||
/* */
|
/* */
|
||||||
/* The IIF function. */
|
/* The IIF function. Uses new-style evaluation */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static int FIif(func_info *info)
|
static int FIif(expr_node *node, Value *locals, Value *ans, int *nonconst)
|
||||||
{
|
{
|
||||||
int istrue;
|
int istrue;
|
||||||
int arg;
|
int r;
|
||||||
|
int done;
|
||||||
|
Value v;
|
||||||
|
expr_node *cur;
|
||||||
|
DynamicBuffer DebugBuf;
|
||||||
|
|
||||||
if (!(Nargs % 2)) return E_IIF_ODD;
|
DBG(DBufInit(&DebugBuf));
|
||||||
|
DBG(PUT("iif("));
|
||||||
|
cur = node->child;
|
||||||
|
|
||||||
for (arg=0; arg<Nargs-1; arg += 2) {
|
if (!(node->num_kids % 2)) {
|
||||||
if (ARG(arg).type != STR_TYPE && ARG(arg).type != INT_TYPE)
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
return E_BAD_TYPE;
|
r = 0;
|
||||||
|
while(cur) {
|
||||||
if (ARG(arg).type == INT_TYPE)
|
if (r) PUT(", ");
|
||||||
istrue = ARG(arg).v.val;
|
r=1;
|
||||||
else
|
PUT("?");
|
||||||
istrue = *(ARG(arg).v.str);
|
cur = cur->sibling;
|
||||||
|
}
|
||||||
if (istrue) {
|
PUT(") => ");
|
||||||
DCOPYVAL(RetVal, ARG(arg+1));
|
PUT(ErrMsg[E_IIF_ODD]);
|
||||||
return OK;
|
OUT();
|
||||||
}
|
}
|
||||||
|
return E_IIF_ODD;
|
||||||
}
|
}
|
||||||
|
|
||||||
DCOPYVAL(RetVal, ARG(Nargs-1));
|
|
||||||
return OK;
|
done = 0;
|
||||||
|
while(cur->sibling) {
|
||||||
|
r = evaluate_expr_node(cur, locals, &v, nonconst);
|
||||||
|
if (r != OK) {
|
||||||
|
DBG(DBufFree(&DebugBuf));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
|
if (done) PUT(", ");
|
||||||
|
done = 1;
|
||||||
|
PUT(PrintValue(&v, NULL));
|
||||||
|
}
|
||||||
|
if (v.type != STR_TYPE && v.type != INT_TYPE) {
|
||||||
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
|
cur = cur->sibling;
|
||||||
|
while(cur) {
|
||||||
|
PUT(", ?");
|
||||||
|
cur = cur->sibling;
|
||||||
|
}
|
||||||
|
PUT(") => ");
|
||||||
|
PUT(ErrMsg[E_BAD_TYPE]);
|
||||||
|
OUT();
|
||||||
|
}
|
||||||
|
return E_BAD_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v.type == INT_TYPE) {
|
||||||
|
istrue = v.v.val;
|
||||||
|
} else {
|
||||||
|
istrue = *(v.v.str);
|
||||||
|
}
|
||||||
|
if (istrue) {
|
||||||
|
r = evaluate_expr_node(cur->sibling, locals, ans, nonconst);
|
||||||
|
if (r == OK && (DebugFlag & DB_PRTEXPR)) {
|
||||||
|
PUT(", ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
cur = cur->sibling->sibling;
|
||||||
|
while(cur) {
|
||||||
|
PUT(", ?");
|
||||||
|
cur = cur->sibling;
|
||||||
|
}
|
||||||
|
PUT(") => ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
OUT();
|
||||||
|
}
|
||||||
|
DBG(DBufFree(&DebugBuf));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
DBG(PUT(", ?"));
|
||||||
|
cur = cur->sibling->sibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the last arg */
|
||||||
|
r = evaluate_expr_node(cur, locals, ans, nonconst);
|
||||||
|
if (DebugFlag & DB_PRTEXPR) {
|
||||||
|
if (done) PUT(", ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
PUT(") => ");
|
||||||
|
PUT(PrintValue(ans, NULL));
|
||||||
|
OUT();
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
@@ -2373,14 +2396,18 @@ static int FEasterdate(func_info *info)
|
|||||||
{
|
{
|
||||||
int y, m, d;
|
int y, m, d;
|
||||||
int g, c, x, z, e, n;
|
int g, c, x, z, e, n;
|
||||||
|
int base;
|
||||||
if (Nargs == 0) {
|
if (Nargs == 0) {
|
||||||
|
base = DSEToday;
|
||||||
FromDSE(DSEToday, &y, &m, &d);
|
FromDSE(DSEToday, &y, &m, &d);
|
||||||
} else {
|
} else {
|
||||||
if (ARG(0).type == INT_TYPE) {
|
if (ARG(0).type == INT_TYPE) {
|
||||||
|
base = -1;
|
||||||
y = ARGV(0);
|
y = ARGV(0);
|
||||||
if (y < BASE) return E_2LOW;
|
if (y < BASE) return E_2LOW;
|
||||||
else if (y > BASE+YR_RANGE) return E_2HIGH;
|
else if (y > BASE+YR_RANGE) return E_2HIGH;
|
||||||
} else if (HASDATE(ARG(0))) {
|
} else if (HASDATE(ARG(0))) {
|
||||||
|
base = DATEPART(ARG(0));
|
||||||
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
|
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
|
||||||
} else return E_BAD_TYPE;
|
} else return E_BAD_TYPE;
|
||||||
}
|
}
|
||||||
@@ -2406,7 +2433,7 @@ static int FEasterdate(func_info *info)
|
|||||||
|
|
||||||
RetVal.type = DATE_TYPE;
|
RetVal.type = DATE_TYPE;
|
||||||
RETVAL = DSE(y, m, d);
|
RETVAL = DSE(y, m, d);
|
||||||
y++; } while (HASDATE(ARG(0)) && RETVAL < DATEPART(ARG(0)));
|
y++; } while (base > -1 && RETVAL < base);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2449,9 @@ static int FOrthodoxeaster(func_info *info)
|
|||||||
{
|
{
|
||||||
int y, m, d;
|
int y, m, d;
|
||||||
int a, b, c, dd, e, f, dse;
|
int a, b, c, dd, e, f, dse;
|
||||||
|
int base = -1;
|
||||||
if (Nargs == 0) {
|
if (Nargs == 0) {
|
||||||
|
base = DSEToday;
|
||||||
FromDSE(DSEToday, &y, &m, &d);
|
FromDSE(DSEToday, &y, &m, &d);
|
||||||
} else {
|
} else {
|
||||||
if (ARG(0).type == INT_TYPE) {
|
if (ARG(0).type == INT_TYPE) {
|
||||||
@@ -2430,6 +2459,7 @@ static int FOrthodoxeaster(func_info *info)
|
|||||||
if (y < BASE) return E_2LOW;
|
if (y < BASE) return E_2LOW;
|
||||||
else if (y > BASE+YR_RANGE) return E_2HIGH;
|
else if (y > BASE+YR_RANGE) return E_2HIGH;
|
||||||
} else if (HASDATE(ARG(0))) {
|
} else if (HASDATE(ARG(0))) {
|
||||||
|
base = DATEPART(ARG(0));
|
||||||
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
|
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
|
||||||
} else return E_BAD_TYPE;
|
} else return E_BAD_TYPE;
|
||||||
}
|
}
|
||||||
@@ -2449,7 +2479,7 @@ static int FOrthodoxeaster(func_info *info)
|
|||||||
RetVal.type = DATE_TYPE;
|
RetVal.type = DATE_TYPE;
|
||||||
RETVAL = dse;
|
RETVAL = dse;
|
||||||
y++;
|
y++;
|
||||||
} while (HASDATE(ARG(0)) && RETVAL < DATEPART(ARG(0)));
|
} while (base > -1 && RETVAL < base);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -3896,3 +3926,38 @@ FSoleq(func_info *info)
|
|||||||
RETVAL = ret;
|
RETVAL = ret;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compare two strings case-insensitively, where we KNOW
|
||||||
|
that the second string is definitely lower-case */
|
||||||
|
static int strcmp_lcfirst(char const *s1, char const *s2)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
while (*s1 && *s2) {
|
||||||
|
r = tolower(*s1) - *s2;
|
||||||
|
if (r) return r;
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
return tolower(*s1) - *s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FindBuiltinFunc */
|
||||||
|
/* */
|
||||||
|
/* Find a built-in function. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
BuiltinFunc *FindBuiltinFunc(char const *name)
|
||||||
|
{
|
||||||
|
int top=NumFuncs-1, bot=0;
|
||||||
|
int mid, r;
|
||||||
|
while (top >= bot) {
|
||||||
|
mid = (top + bot) / 2;
|
||||||
|
r = strcmp_lcfirst(name, Func[mid].name);
|
||||||
|
if (!r) return &Func[mid];
|
||||||
|
else if (r > 0) bot = mid+1;
|
||||||
|
else top = mid-1;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|||||||
@@ -159,6 +159,9 @@ EXTERN DynamicBuffer Banner;
|
|||||||
EXTERN DynamicBuffer LineBuffer;
|
EXTERN DynamicBuffer LineBuffer;
|
||||||
EXTERN DynamicBuffer ExprBuf;
|
EXTERN DynamicBuffer ExprBuf;
|
||||||
|
|
||||||
|
/* User-func recursion level */
|
||||||
|
EXTERN INIT( unsigned int FuncRecursionLevel, 0);
|
||||||
|
|
||||||
extern int NumFullOmits, NumPartialOmits;
|
extern int NumFullOmits, NumPartialOmits;
|
||||||
|
|
||||||
/* List of months */
|
/* List of months */
|
||||||
|
|||||||
@@ -605,7 +605,7 @@ void InitRemind(int argc, char const *argv[])
|
|||||||
case 'D':
|
case 'D':
|
||||||
while (*arg) {
|
while (*arg) {
|
||||||
switch(*arg++) {
|
switch(*arg++) {
|
||||||
case 's': case 'S': DebugFlag |= DB_EXPR_STACKS; break;
|
case 's': case 'S': DebugFlag |= DB_PARSE_EXPR; break;
|
||||||
case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break;
|
case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break;
|
||||||
case 'x': case 'X': DebugFlag |= DB_PRTEXPR; break;
|
case 'x': case 'X': DebugFlag |= DB_PRTEXPR; break;
|
||||||
case 't': case 'T': DebugFlag |= DB_PRTTRIG; break;
|
case 't': case 'T': DebugFlag |= DB_PRTTRIG; break;
|
||||||
|
|||||||
@@ -246,7 +246,9 @@ EXTERN char *ErrMsg[] =
|
|||||||
"String too long",
|
"String too long",
|
||||||
"Time specified twice",
|
"Time specified twice",
|
||||||
"Cannot specify DURATION without specifying AT",
|
"Cannot specify DURATION without specifying AT",
|
||||||
"Odotettu viikonpäivän nimi"
|
"Odotettu viikonpäivän nimi",
|
||||||
|
"Päällekkäinen argumentin nimi"
|
||||||
|
|
||||||
};
|
};
|
||||||
#endif /* MK_GLOBALS */
|
#endif /* MK_GLOBALS */
|
||||||
|
|
||||||
|
|||||||
@@ -221,6 +221,7 @@ EXTERN char *ErrMsg[] =
|
|||||||
"Time specified twice",
|
"Time specified twice",
|
||||||
"Cannot specify DURATION without specifying AT",
|
"Cannot specify DURATION without specifying AT",
|
||||||
"Nom du jour de la semaine attendu",
|
"Nom du jour de la semaine attendu",
|
||||||
|
"Nom de l'argument en double",
|
||||||
};
|
};
|
||||||
#endif /* MK_GLOBALS */
|
#endif /* MK_GLOBALS */
|
||||||
|
|
||||||
|
|||||||
@@ -236,7 +236,8 @@ EXTERN char *ErrMsg[] =
|
|||||||
"String too long",
|
"String too long",
|
||||||
"Time specified twice",
|
"Time specified twice",
|
||||||
"Cannot specify DURATION without specifying AT",
|
"Cannot specify DURATION without specifying AT",
|
||||||
"Oczekiwana nazwa dnia tygodnia"
|
"Oczekiwana nazwa dnia tygodnia",
|
||||||
|
"Zduplikowana nazwa argumentu",
|
||||||
};
|
};
|
||||||
#endif /* MK_GLOBALS */
|
#endif /* MK_GLOBALS */
|
||||||
|
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ EXTERN char *ErrMsg[] =
|
|||||||
"Time specified twice",
|
"Time specified twice",
|
||||||
"Cannot specify DURATION without specifying AT",
|
"Cannot specify DURATION without specifying AT",
|
||||||
"Esperando nome do dia da semana",
|
"Esperando nome do dia da semana",
|
||||||
|
"Nome de argumento duplicado"
|
||||||
};
|
};
|
||||||
#endif /* MK_GLOBALS */
|
#endif /* MK_GLOBALS */
|
||||||
|
|
||||||
|
|||||||
113
src/main.c
113
src/main.c
@@ -55,6 +55,15 @@ static void DoReminders(void);
|
|||||||
/* Macro for simplifying common block so as not to litter code */
|
/* Macro for simplifying common block so as not to litter code */
|
||||||
#define OUTPUT(c) do { if (output) { DBufPutc(output, c); } else { putchar(c); } } while(0)
|
#define OUTPUT(c) do { if (output) { DBufPutc(output, c); } else { putchar(c); } } while(0)
|
||||||
|
|
||||||
|
void
|
||||||
|
exitfunc(void)
|
||||||
|
{
|
||||||
|
if (DebugFlag & DB_PARSE_EXPR) {
|
||||||
|
UnsetAllUserFuncs();
|
||||||
|
print_expr_nodes_stats();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/** **/
|
/** **/
|
||||||
@@ -81,7 +90,7 @@ int main(int argc, char *argv[])
|
|||||||
DBufInit(&(LastTrigger.tags));
|
DBufInit(&(LastTrigger.tags));
|
||||||
ClearLastTriggers();
|
ClearLastTriggers();
|
||||||
|
|
||||||
atexit(DebugExitFunc);
|
atexit(exitfunc);
|
||||||
|
|
||||||
if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) {
|
if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) {
|
||||||
ProduceCalendar();
|
ProduceCalendar();
|
||||||
@@ -289,6 +298,7 @@ static void DoReminders(void)
|
|||||||
case T_RemType: if (tok.val == RUN_TYPE) {
|
case T_RemType: if (tok.val == RUN_TYPE) {
|
||||||
r=DoRun(&p);
|
r=DoRun(&p);
|
||||||
} else {
|
} else {
|
||||||
|
DestroyParser(&p);
|
||||||
CreateParser(CurLine, &p);
|
CreateParser(CurLine, &p);
|
||||||
r=DoRem(&p);
|
r=DoRem(&p);
|
||||||
purge_handled = 1;
|
purge_handled = 1;
|
||||||
@@ -297,10 +307,8 @@ static void DoReminders(void)
|
|||||||
|
|
||||||
|
|
||||||
/* If we don't recognize the command, do a REM by default */
|
/* If we don't recognize the command, do a REM by default */
|
||||||
/* Note: Since the parser hasn't been used yet, we don't */
|
|
||||||
/* need to destroy it here. */
|
|
||||||
|
|
||||||
default: CreateParser(CurLine, &p); purge_handled = 1; r=DoRem(&p); break;
|
default: DestroyParser(&p); CreateParser(CurLine, &p); purge_handled = 1; r=DoRem(&p); break;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (r && (!Hush || r != E_RUN_DISABLED)) {
|
if (r && (!Hush || r != E_RUN_DISABLED)) {
|
||||||
@@ -582,6 +590,53 @@ int ParseIdentifier(ParsePtr p, DynamicBuffer *dbuf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* ParseExpr */
|
||||||
|
/* */
|
||||||
|
/* We are expecting an expression here. Parse it and return */
|
||||||
|
/* the value node tree. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
expr_node * ParseExpr(ParsePtr p, int *r)
|
||||||
|
{
|
||||||
|
|
||||||
|
int bracketed = 0;
|
||||||
|
expr_node *node;
|
||||||
|
|
||||||
|
if (p->isnested) {
|
||||||
|
*r = E_PARSE_ERR; /* Can't nest expressions */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!p->pos) {
|
||||||
|
*r = E_PARSE_ERR; /* Missing expression */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (isempty(*p->pos)) (p->pos)++;
|
||||||
|
if (!*(p->pos)) {
|
||||||
|
*r = E_EOLN;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (*p->pos == BEG_OF_EXPR) {
|
||||||
|
(p->pos)++;
|
||||||
|
bracketed = 1;
|
||||||
|
}
|
||||||
|
node = parse_expression(&(p->pos), r, NULL);
|
||||||
|
if (*r) {
|
||||||
|
return free_expr_tree(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bracketed) {
|
||||||
|
if (*p->pos != END_OF_EXPR) {
|
||||||
|
*r = E_MISS_END;
|
||||||
|
return free_expr_tree(node);
|
||||||
|
}
|
||||||
|
(p->pos)++;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* EvaluateExpr */
|
/* EvaluateExpr */
|
||||||
@@ -593,21 +648,22 @@ int ParseIdentifier(ParsePtr p, DynamicBuffer *dbuf)
|
|||||||
int EvaluateExpr(ParsePtr p, Value *v)
|
int EvaluateExpr(ParsePtr p, Value *v)
|
||||||
{
|
{
|
||||||
|
|
||||||
int bracketed = 0;
|
|
||||||
int r;
|
int r;
|
||||||
|
int nonconst = 0;
|
||||||
|
expr_node *node = ParseExpr(p, &r);
|
||||||
|
|
||||||
if (p->isnested) return E_PARSE_ERR; /* Can't nest expressions */
|
if (r != OK) {
|
||||||
if (!p->pos) return E_PARSE_ERR; /* Missing expression */
|
return r;
|
||||||
while (isempty(*p->pos)) (p->pos)++;
|
|
||||||
if (*p->pos == BEG_OF_EXPR) {
|
|
||||||
(p->pos)++;
|
|
||||||
bracketed = 1;
|
|
||||||
}
|
}
|
||||||
r = EvalExpr(&(p->pos), v, p);
|
if (!node) {
|
||||||
|
return E_SWERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = evaluate_expr_node(node, NULL, v, &nonconst);
|
||||||
|
free_expr_tree(node);
|
||||||
if (r) return r;
|
if (r) return r;
|
||||||
if (bracketed) {
|
if (nonconst) {
|
||||||
if (*p->pos != END_OF_EXPR) return E_MISS_END;
|
p->nonconst_expr = 1;
|
||||||
(p->pos)++;
|
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -651,27 +707,34 @@ void Eprint(char const *fmt, ...)
|
|||||||
FreshLine = 0;
|
FreshLine = 0;
|
||||||
if (strcmp(FileName, "-")) {
|
if (strcmp(FileName, "-")) {
|
||||||
(void) fprintf(ErrFp, "%s(%d): ", FileName, LineNo);
|
(void) fprintf(ErrFp, "%s(%d): ", FileName, LineNo);
|
||||||
|
va_start(argptr, fmt);
|
||||||
|
(void) vfprintf(ErrFp, fmt, argptr);
|
||||||
|
(void) fputc('\n', ErrFp);
|
||||||
|
va_end(argptr);
|
||||||
if (print_callstack(ErrFp)) {
|
if (print_callstack(ErrFp)) {
|
||||||
(void) fprintf(ErrFp, ": ");
|
(void) fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(void) fprintf(ErrFp, "-stdin-(%d): ", LineNo);
|
(void) fprintf(ErrFp, "-stdin-(%d): ", LineNo);
|
||||||
|
va_start(argptr, fmt);
|
||||||
|
(void) vfprintf(ErrFp, fmt, argptr);
|
||||||
|
(void) fputc('\n', ErrFp);
|
||||||
|
va_end(argptr);
|
||||||
if (print_callstack(ErrFp)) {
|
if (print_callstack(ErrFp)) {
|
||||||
(void) fprintf(ErrFp, ": ");
|
(void) fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DebugFlag & DB_PRTLINE) OutputLine(ErrFp);
|
if (DebugFlag & DB_PRTLINE) OutputLine(ErrFp);
|
||||||
} else if (FileName) {
|
} else if (FileName) {
|
||||||
fprintf(ErrFp, " ");
|
fprintf(ErrFp, " ");
|
||||||
|
va_start(argptr, fmt);
|
||||||
|
(void) vfprintf(ErrFp, fmt, argptr);
|
||||||
|
(void) fputc('\n', ErrFp);
|
||||||
|
va_end(argptr);
|
||||||
if (print_callstack(ErrFp)) {
|
if (print_callstack(ErrFp)) {
|
||||||
(void) fprintf(ErrFp, ": ");
|
(void) fprintf(ErrFp, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
va_start(argptr, fmt);
|
|
||||||
(void) vfprintf(ErrFp, fmt, argptr);
|
|
||||||
(void) fputc('\n', ErrFp);
|
|
||||||
va_end(argptr);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1025,8 +1088,8 @@ int DoDebug(ParsePtr p)
|
|||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
if (val) DebugFlag |= DB_EXPR_STACKS;
|
if (val) DebugFlag |= DB_PARSE_EXPR;
|
||||||
else DebugFlag &= ~DB_EXPR_STACKS;
|
else DebugFlag &= ~DB_PARSE_EXPR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'x':
|
case 'x':
|
||||||
|
|||||||
16
src/protos.h
16
src/protos.h
@@ -43,6 +43,7 @@
|
|||||||
int CallUserFunc (char const *name, int nargs, ParsePtr p);
|
int CallUserFunc (char const *name, int nargs, ParsePtr p);
|
||||||
int DoFset (ParsePtr p);
|
int DoFset (ParsePtr p);
|
||||||
int DoFunset (ParsePtr p);
|
int DoFunset (ParsePtr p);
|
||||||
|
void UnsetAllUserFuncs(void);
|
||||||
void ProduceCalendar (void);
|
void ProduceCalendar (void);
|
||||||
char const *SimpleTime (int tim);
|
char const *SimpleTime (int tim);
|
||||||
char const *CalendarTime (int tim, int duration);
|
char const *CalendarTime (int tim, int duration);
|
||||||
@@ -56,9 +57,12 @@ int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
|
|||||||
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int dse, int tim);
|
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int dse, int tim);
|
||||||
int ParseLiteralDate (char const **s, int *dse, int *tim);
|
int ParseLiteralDate (char const **s, int *dse, int *tim);
|
||||||
int ParseLiteralTime (char const **s, int *tim);
|
int ParseLiteralTime (char const **s, int *tim);
|
||||||
|
int evaluate_expr_node(expr_node *node, Value *locals, Value *ans, int *nonconst);
|
||||||
|
void print_expr_tree(expr_node *node, FILE *fp);
|
||||||
|
expr_node *free_expr_tree(expr_node *node);
|
||||||
int EvalExpr (char const **e, Value *v, ParsePtr p);
|
int EvalExpr (char const **e, Value *v, ParsePtr p);
|
||||||
int DoCoerce (char type, Value *v);
|
int DoCoerce (char type, Value *v);
|
||||||
void PrintValue (Value *v, FILE *fp);
|
char const *PrintValue (Value *v, FILE *fp);
|
||||||
int CopyValue (Value *dest, const Value *src);
|
int CopyValue (Value *dest, const Value *src);
|
||||||
int ReadLine (void);
|
int ReadLine (void);
|
||||||
int OpenFile (char const *fname);
|
int OpenFile (char const *fname);
|
||||||
@@ -77,8 +81,9 @@ int JulianToGregorianOffset(int y, int m);
|
|||||||
int ParseChar (ParsePtr p, int *err, int peek);
|
int ParseChar (ParsePtr p, int *err, int peek);
|
||||||
int ParseToken (ParsePtr p, DynamicBuffer *dbuf);
|
int ParseToken (ParsePtr p, DynamicBuffer *dbuf);
|
||||||
int ParseIdentifier (ParsePtr p, DynamicBuffer *dbuf);
|
int ParseIdentifier (ParsePtr p, DynamicBuffer *dbuf);
|
||||||
|
expr_node * ParseExpr(ParsePtr p, int *r);
|
||||||
|
void print_expr_nodes_stats(void);
|
||||||
int EvaluateExpr (ParsePtr p, Value *v);
|
int EvaluateExpr (ParsePtr p, Value *v);
|
||||||
int Evaluate (char const **s, Var *locals, ParsePtr p);
|
|
||||||
int FnPopValStack (Value *val);
|
int FnPopValStack (Value *val);
|
||||||
void Eprint (char const *fmt, ...);
|
void Eprint (char const *fmt, ...);
|
||||||
void Wprint (char const *fmt, ...);
|
void Wprint (char const *fmt, ...);
|
||||||
@@ -129,9 +134,10 @@ int StrCmpi (char const *s1, char const *s2);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
Var *FindVar (char const *str, int create);
|
Var *FindVar (char const *str, int create);
|
||||||
|
SysVar *FindSysVar (char const *name);
|
||||||
int DeleteVar (char const *str);
|
int DeleteVar (char const *str);
|
||||||
int SetVar (char const *str, Value const *val);
|
int SetVar (char const *str, Value const *val);
|
||||||
int GetVarValue (char const *str, Value *val, Var *locals, ParsePtr p);
|
int GetVarValue (char const *str, Value *val);
|
||||||
int DoSet (Parser *p);
|
int DoSet (Parser *p);
|
||||||
int DoUnset (Parser *p);
|
int DoUnset (Parser *p);
|
||||||
int DoDump (ParsePtr p);
|
int DoDump (ParsePtr p);
|
||||||
@@ -145,9 +151,10 @@ int ParseNonSpaceChar (ParsePtr p, int *err, int peek);
|
|||||||
unsigned int HashVal (char const *str);
|
unsigned int HashVal (char const *str);
|
||||||
int DateOK (int y, int m, int d);
|
int DateOK (int y, int m, int d);
|
||||||
Operator *FindOperator (char const *name, Operator where[], int num);
|
Operator *FindOperator (char const *name, Operator where[], int num);
|
||||||
BuiltinFunc *FindFunc (char const *name, BuiltinFunc where[], int num);
|
BuiltinFunc *FindBuiltinFunc (char const *name);
|
||||||
int InsertIntoSortBuffer (int dse, int tim, char const *body, int typ, int prio);
|
int InsertIntoSortBuffer (int dse, int tim, char const *body, int typ, int prio);
|
||||||
void IssueSortedReminders (void);
|
void IssueSortedReminders (void);
|
||||||
|
UserFunc *FindUserFunc(char const *name);
|
||||||
int UserFuncExists (char const *fn);
|
int UserFuncExists (char const *fn);
|
||||||
void DSEToHeb (int dse, int *hy, int *hm, int *hd);
|
void DSEToHeb (int dse, int *hy, int *hm, int *hd);
|
||||||
int HebNameToNum (char const *mname);
|
int HebNameToNum (char const *mname);
|
||||||
@@ -207,6 +214,7 @@ void set_cloexec(FILE *fp);
|
|||||||
int push_call(char const *filename, char const *func, int lineno);
|
int push_call(char const *filename, char const *func, int lineno);
|
||||||
void clear_callstack(void);
|
void clear_callstack(void);
|
||||||
int print_callstack(FILE *fp);
|
int print_callstack(FILE *fp);
|
||||||
|
int have_callstack(void);
|
||||||
void pop_call(void);
|
void pop_call(void);
|
||||||
void FixSpecialType(Trigger *trig);
|
void FixSpecialType(Trigger *trig);
|
||||||
void WriteJSONTrigger(Trigger const *t, int include_tags, int today);
|
void WriteJSONTrigger(Trigger const *t, int include_tags, int today);
|
||||||
|
|||||||
68
src/types.h
68
src/types.h
@@ -30,21 +30,62 @@ typedef struct {
|
|||||||
int (*func)(void);
|
int (*func)(void);
|
||||||
} Operator;
|
} Operator;
|
||||||
|
|
||||||
|
/* New-style expr_node structure and constants */
|
||||||
|
enum expr_node_type
|
||||||
|
{
|
||||||
|
N_FREE,
|
||||||
|
N_ERROR,
|
||||||
|
N_CONSTANT,
|
||||||
|
N_LOCAL_VAR,
|
||||||
|
N_SHORT_VAR,
|
||||||
|
N_VARIABLE,
|
||||||
|
N_SHORT_SYSVAR,
|
||||||
|
N_SYSVAR,
|
||||||
|
N_BUILTIN_FUNC,
|
||||||
|
N_SHORT_USER_FUNC,
|
||||||
|
N_USER_FUNC,
|
||||||
|
N_BINARY_OPERATOR,
|
||||||
|
N_UNARY_OPERATOR,
|
||||||
|
};
|
||||||
|
|
||||||
/* Structure for passing in Nargs and out RetVal from functions */
|
/* Structure for passing in Nargs and out RetVal from functions */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int nargs;
|
int nargs;
|
||||||
|
Value *args;
|
||||||
Value retval;
|
Value retval;
|
||||||
} func_info;
|
} func_info;
|
||||||
|
|
||||||
|
/* Forward reference */
|
||||||
|
typedef struct expr_node_struct expr_node;
|
||||||
|
|
||||||
/* Define the type of user-functions */
|
/* Define the type of user-functions */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char const *name;
|
char const *name;
|
||||||
char minargs;
|
char minargs;
|
||||||
char maxargs;
|
char maxargs;
|
||||||
char is_constant;
|
char is_constant;
|
||||||
|
/* Old-style function calling convention */
|
||||||
int (*func)(func_info *);
|
int (*func)(func_info *);
|
||||||
|
|
||||||
|
/* New-style function calling convention */
|
||||||
|
int (*newfunc)(expr_node *node, Value *locals, Value *ans, int *nonconst);
|
||||||
} BuiltinFunc;
|
} BuiltinFunc;
|
||||||
|
|
||||||
|
#define SHORT_NAME_BUF 16
|
||||||
|
typedef struct expr_node_struct {
|
||||||
|
struct expr_node_struct *child;
|
||||||
|
struct expr_node_struct *sibling;
|
||||||
|
enum expr_node_type type;
|
||||||
|
int num_kids;
|
||||||
|
union {
|
||||||
|
Value value;
|
||||||
|
int arg;
|
||||||
|
BuiltinFunc *builtin_func;
|
||||||
|
char name[SHORT_NAME_BUF];
|
||||||
|
int (*operator_func) (struct expr_node_struct *node, Value *locals, Value *ans, int *nonconst);
|
||||||
|
} u;
|
||||||
|
} expr_node;
|
||||||
|
|
||||||
/* Define the structure of a variable */
|
/* Define the structure of a variable */
|
||||||
typedef struct var {
|
typedef struct var {
|
||||||
struct var *next;
|
struct var *next;
|
||||||
@@ -142,6 +183,8 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
|
|||||||
#define MSF_TYPE 7
|
#define MSF_TYPE 7
|
||||||
#define PASSTHRU_TYPE 8
|
#define PASSTHRU_TYPE 8
|
||||||
|
|
||||||
|
/* For function arguments */
|
||||||
|
#define NO_MAX 127
|
||||||
|
|
||||||
/* DEFINES for debugging flags */
|
/* DEFINES for debugging flags */
|
||||||
#define DB_PRTLINE 1
|
#define DB_PRTLINE 1
|
||||||
@@ -150,7 +193,7 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
|
|||||||
#define DB_DUMP_VARS 8
|
#define DB_DUMP_VARS 8
|
||||||
#define DB_ECHO_LINE 16
|
#define DB_ECHO_LINE 16
|
||||||
#define DB_TRACE_FILES 32
|
#define DB_TRACE_FILES 32
|
||||||
#define DB_EXPR_STACKS 64
|
#define DB_PARSE_EXPR 64
|
||||||
|
|
||||||
/* Enumeration of the tokens */
|
/* Enumeration of the tokens */
|
||||||
enum TokTypes
|
enum TokTypes
|
||||||
@@ -244,3 +287,26 @@ typedef struct {
|
|||||||
#define TERMINAL_BACKGROUND_UNKNOWN -1
|
#define TERMINAL_BACKGROUND_UNKNOWN -1
|
||||||
#define TERMINAL_BACKGROUND_DARK 0
|
#define TERMINAL_BACKGROUND_DARK 0
|
||||||
#define TERMINAL_BACKGROUND_LIGHT 1
|
#define TERMINAL_BACKGROUND_LIGHT 1
|
||||||
|
|
||||||
|
typedef int (*SysVarFunc)(int, Value *);
|
||||||
|
/* The structure of a system variable */
|
||||||
|
typedef struct {
|
||||||
|
char const *name;
|
||||||
|
char modifiable;
|
||||||
|
int type;
|
||||||
|
void *value;
|
||||||
|
int min; /* Or const-value */
|
||||||
|
int max;
|
||||||
|
} SysVar;
|
||||||
|
|
||||||
|
/* Define the data structure used to hold a user-defined function */
|
||||||
|
typedef struct udf_struct {
|
||||||
|
struct udf_struct *next;
|
||||||
|
char name[VAR_NAME_LEN+1];
|
||||||
|
expr_node *node;
|
||||||
|
char **args;
|
||||||
|
int nargs;
|
||||||
|
char const *filename;
|
||||||
|
int lineno;
|
||||||
|
} UserFunc;
|
||||||
|
|
||||||
|
|||||||
280
src/userfns.c
280
src/userfns.c
@@ -30,34 +30,12 @@
|
|||||||
|
|
||||||
#define FUNC_HASH_SIZE 32 /* Size of User-defined function hash table */
|
#define FUNC_HASH_SIZE 32 /* Size of User-defined function hash table */
|
||||||
|
|
||||||
/* Define the data structure used to hold a user-defined function */
|
|
||||||
typedef struct udf_struct {
|
|
||||||
struct udf_struct *next;
|
|
||||||
char name[VAR_NAME_LEN+1];
|
|
||||||
char const *text;
|
|
||||||
Var *locals;
|
|
||||||
char IsActive;
|
|
||||||
int nargs;
|
|
||||||
char const *filename;
|
|
||||||
int lineno;
|
|
||||||
} UserFunc;
|
|
||||||
|
|
||||||
/* The hash table */
|
/* The hash table */
|
||||||
static UserFunc *FuncHash[FUNC_HASH_SIZE];
|
static UserFunc *FuncHash[FUNC_HASH_SIZE];
|
||||||
|
|
||||||
/* Access to built-in functions */
|
|
||||||
extern int NumFuncs;
|
|
||||||
extern BuiltinFunc Func[];
|
|
||||||
|
|
||||||
/* We need access to the expression evaluation stack */
|
|
||||||
extern Value ValStack[];
|
|
||||||
extern int ValStackPtr;
|
|
||||||
|
|
||||||
static void DestroyUserFunc (UserFunc *f);
|
static void DestroyUserFunc (UserFunc *f);
|
||||||
static void FUnset (char const *name);
|
static void FUnset (char const *name);
|
||||||
static void FSet (UserFunc *f);
|
static void FSet (UserFunc *f);
|
||||||
static int SetUpLocalVars (UserFunc *f);
|
|
||||||
static void DestroyLocalVals (UserFunc *f);
|
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
@@ -98,9 +76,11 @@ int DoFset(ParsePtr p)
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
int c;
|
int c;
|
||||||
|
int i;
|
||||||
UserFunc *func;
|
UserFunc *func;
|
||||||
Var *v;
|
UserFunc *existing;
|
||||||
Var *local;
|
Var *locals = NULL;
|
||||||
|
Var local_array[MAX_FUNC_ARGS];
|
||||||
int orig_namelen;
|
int orig_namelen;
|
||||||
|
|
||||||
DynamicBuffer buf;
|
DynamicBuffer buf;
|
||||||
@@ -125,6 +105,18 @@ int DoFset(ParsePtr p)
|
|||||||
return E_PARSE_ERR;
|
return E_PARSE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the function exists and was defined at the same line of the same
|
||||||
|
file, do nothing */
|
||||||
|
existing = FindUserFunc(DBufValue(&buf));
|
||||||
|
if (existing) {
|
||||||
|
if (!strcmp(existing->filename, FileName) &&
|
||||||
|
strcmp(existing->filename, "[cmdline]") &&
|
||||||
|
existing->lineno == LineNo) {
|
||||||
|
DBufFree(&buf);
|
||||||
|
/* We already have it! Our work here is done. */
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
func = NEW(UserFunc);
|
func = NEW(UserFunc);
|
||||||
if (!func) {
|
if (!func) {
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
@@ -143,25 +135,22 @@ int DoFset(ParsePtr p)
|
|||||||
StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN);
|
StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN);
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
if (!Hush) {
|
if (!Hush) {
|
||||||
if (FindFunc(func->name, Func, NumFuncs)) {
|
if (FindBuiltinFunc(func->name)) {
|
||||||
Eprint("%s: `%s'", ErrMsg[E_REDEF_FUNC], func->name);
|
Eprint("%s: `%s'", ErrMsg[E_REDEF_FUNC], func->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func->locals = NULL;
|
func->node = NULL;
|
||||||
func->text = NULL;
|
|
||||||
func->IsActive = 0;
|
|
||||||
func->nargs = 0;
|
func->nargs = 0;
|
||||||
|
func->args = NULL;
|
||||||
|
|
||||||
/* Get the local variables - we insert the local variables in REVERSE
|
/* Get the local variables */
|
||||||
order, but that's OK, because we pop them off the stack in reverse
|
|
||||||
order, too, so everything works out just fine. */
|
|
||||||
|
|
||||||
c=ParseNonSpaceChar(p, &r, 1);
|
c=ParseNonSpaceChar(p, &r, 1);
|
||||||
if (r) return r;
|
if (r) return r;
|
||||||
if (c == ')') {
|
if (c == ')') {
|
||||||
(void) ParseNonSpaceChar(p, &r, 0);
|
(void) ParseNonSpaceChar(p, &r, 0);
|
||||||
}
|
} else {
|
||||||
else {
|
locals = local_array;
|
||||||
while(1) {
|
while(1) {
|
||||||
if ( (r=ParseIdentifier(p, &buf)) ) return r;
|
if ( (r=ParseIdentifier(p, &buf)) ) return r;
|
||||||
if (*DBufValue(&buf) == '$') {
|
if (*DBufValue(&buf) == '$') {
|
||||||
@@ -170,27 +159,24 @@ int DoFset(ParsePtr p)
|
|||||||
return E_BAD_ID;
|
return E_BAD_ID;
|
||||||
}
|
}
|
||||||
/* If we've already seen this local variable, error */
|
/* If we've already seen this local variable, error */
|
||||||
local = func->locals;
|
for (i=0; i<func->nargs; i++) {
|
||||||
while(local) {
|
if (!StrinCmp(DBufValue(&buf), local_array[i].name, VAR_NAME_LEN)) {
|
||||||
if (!StrinCmp(DBufValue(&buf), local->name, VAR_NAME_LEN)) {
|
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
DestroyUserFunc(func);
|
DestroyUserFunc(func);
|
||||||
return E_REPEATED_ARG;
|
return E_REPEATED_ARG;
|
||||||
}
|
}
|
||||||
local = local->next;
|
|
||||||
}
|
}
|
||||||
v = NEW(Var);
|
i = func->nargs;
|
||||||
if (!v) {
|
if (i >= MAX_FUNC_ARGS-1) {
|
||||||
DBufFree(&buf);
|
DBufFree(&buf);
|
||||||
DestroyUserFunc(func);
|
DestroyUserFunc(func);
|
||||||
return E_NO_MEM;
|
return E_2MANY_ARGS;
|
||||||
}
|
}
|
||||||
|
local_array[i].v.type = ERR_TYPE;
|
||||||
|
StrnCpy(local_array[i].name, DBufValue(&buf), VAR_NAME_LEN);
|
||||||
|
local_array[i].next = &(local_array[i+1]);
|
||||||
|
local_array[i+1].next = NULL;
|
||||||
func->nargs++;
|
func->nargs++;
|
||||||
v->v.type = ERR_TYPE;
|
|
||||||
StrnCpy(v->name, DBufValue(&buf), VAR_NAME_LEN);
|
|
||||||
DBufFree(&buf);
|
|
||||||
v->next = func->locals;
|
|
||||||
func->locals = v;
|
|
||||||
c = ParseNonSpaceChar(p, &r, 0);
|
c = ParseNonSpaceChar(p, &r, 0);
|
||||||
if (c == ')') break;
|
if (c == ')') break;
|
||||||
else if (c != ',') {
|
else if (c != ',') {
|
||||||
@@ -205,7 +191,6 @@ int DoFset(ParsePtr p)
|
|||||||
if (c == '=') {
|
if (c == '=') {
|
||||||
(void) ParseNonSpaceChar(p, &r, 0);
|
(void) ParseNonSpaceChar(p, &r, 0);
|
||||||
}
|
}
|
||||||
/* Copy the text over */
|
|
||||||
if (p->isnested) {
|
if (p->isnested) {
|
||||||
Eprint("%s", ErrMsg[E_CANTNEST_FDEF]);
|
Eprint("%s", ErrMsg[E_CANTNEST_FDEF]);
|
||||||
DestroyUserFunc(func);
|
DestroyUserFunc(func);
|
||||||
@@ -219,10 +204,23 @@ int DoFset(ParsePtr p)
|
|||||||
DestroyUserFunc(func);
|
DestroyUserFunc(func);
|
||||||
return E_EOLN;
|
return E_EOLN;
|
||||||
}
|
}
|
||||||
func->text = StrDup(p->pos);
|
/* Parse the expression */
|
||||||
if (!func->text) {
|
func->node = parse_expression(&(p->pos), &r, locals);
|
||||||
DestroyUserFunc(func);
|
if (!func->node) {
|
||||||
return E_NO_MEM;
|
DestroyUserFunc(func);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the argument names */
|
||||||
|
if (func->nargs) {
|
||||||
|
func->args = calloc(sizeof(char *), func->nargs);
|
||||||
|
for (i=0; i<func->nargs; i++) {
|
||||||
|
func->args[i] = StrDup(local_array[i].name);
|
||||||
|
if (!func->args[i]) {
|
||||||
|
DestroyUserFunc(func);
|
||||||
|
return E_NO_MEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If an old definition of this function exists, destroy it */
|
/* If an old definition of this function exists, destroy it */
|
||||||
@@ -246,23 +244,22 @@ int DoFset(ParsePtr p)
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static void DestroyUserFunc(UserFunc *f)
|
static void DestroyUserFunc(UserFunc *f)
|
||||||
{
|
{
|
||||||
Var *v, *prev;
|
int i;
|
||||||
|
|
||||||
/* Free the local variables first */
|
|
||||||
v = f->locals;
|
|
||||||
while(v) {
|
|
||||||
DestroyValue(v->v);
|
|
||||||
prev = v;
|
|
||||||
v = v->next;
|
|
||||||
free(prev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free the function definition */
|
/* Free the function definition */
|
||||||
if (f->text) free( (char *) f->text);
|
if (f->node) free_expr_tree(f->node);
|
||||||
|
|
||||||
/* Free the filename */
|
/* Free the filename */
|
||||||
if (f->filename) free( (char *) f->filename);
|
if (f->filename) free( (char *) f->filename);
|
||||||
|
|
||||||
|
/* Free arg names */
|
||||||
|
if (f->args) {
|
||||||
|
for (i=0; i<f->nargs; i++) {
|
||||||
|
if (f->args[i]) free(f->args[i]);
|
||||||
|
}
|
||||||
|
free(f->args);
|
||||||
|
}
|
||||||
|
|
||||||
/* Free the data structure itself */
|
/* Free the data structure itself */
|
||||||
free(f);
|
free(f);
|
||||||
}
|
}
|
||||||
@@ -308,129 +305,17 @@ static void FSet(UserFunc *f)
|
|||||||
FuncHash[h] = f;
|
FuncHash[h] = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
UserFunc *FindUserFunc(char const *name)
|
||||||
/* */
|
|
||||||
/* CallUserFunc */
|
|
||||||
/* */
|
|
||||||
/* Call a user-defined function. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
int CallUserFunc(char const *name, int nargs, ParsePtr p)
|
|
||||||
{
|
{
|
||||||
UserFunc *f;
|
UserFunc *f;
|
||||||
int h = HashVal(name) % FUNC_HASH_SIZE;
|
int h = HashVal(name) % FUNC_HASH_SIZE;
|
||||||
int i;
|
|
||||||
char const *s;
|
|
||||||
|
|
||||||
/* Search for the function */
|
/* Search for the function */
|
||||||
f = FuncHash[h];
|
f = FuncHash[h];
|
||||||
while (f && StrinCmp(name, f->name, VAR_NAME_LEN)) f = f->next;
|
while (f && StrinCmp(name, f->name, VAR_NAME_LEN)) f = f->next;
|
||||||
if (!f) {
|
return f;
|
||||||
Eprint("%s: `%s'", ErrMsg[E_UNDEF_FUNC], name);
|
|
||||||
return E_UNDEF_FUNC;
|
|
||||||
}
|
|
||||||
/* Debugging stuff */
|
|
||||||
if (DebugFlag & DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s %s(", ErrMsg[E_ENTER_FUN], f->name);
|
|
||||||
for (i=0; i<nargs; i++) {
|
|
||||||
PrintValue(&ValStack[ValStackPtr - nargs + i], ErrFp);
|
|
||||||
if (i<nargs-1) fprintf(ErrFp, ", ");
|
|
||||||
}
|
|
||||||
fprintf(ErrFp, ")\n");
|
|
||||||
}
|
|
||||||
/* Detect illegal recursive call */
|
|
||||||
if (f->IsActive) {
|
|
||||||
if (DebugFlag &DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
|
|
||||||
fprintf(ErrFp, "%s\n", ErrMsg[E_RECURSIVE]);
|
|
||||||
}
|
|
||||||
return E_RECURSIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check number of args */
|
|
||||||
if (nargs != f->nargs) {
|
|
||||||
if (DebugFlag &DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
|
|
||||||
fprintf(ErrFp, "%s\n",
|
|
||||||
ErrMsg[(nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS]);
|
|
||||||
}
|
|
||||||
return (nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS;
|
|
||||||
}
|
|
||||||
/* Found the function - set up a local variable frame */
|
|
||||||
h = SetUpLocalVars(f);
|
|
||||||
if (h) {
|
|
||||||
if (DebugFlag &DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
|
|
||||||
fprintf(ErrFp, "%s\n", ErrMsg[h]);
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Evaluate the expression */
|
|
||||||
f->IsActive = 1;
|
|
||||||
s = f->text;
|
|
||||||
|
|
||||||
/* Skip the opening bracket, if there's one */
|
|
||||||
while (isempty(*s)) s++;
|
|
||||||
if (*s == BEG_OF_EXPR) {
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
push_call(f->filename, f->name, f->lineno);
|
|
||||||
h = Evaluate(&s, f->locals, p);
|
|
||||||
if (h == OK) {
|
|
||||||
pop_call();
|
|
||||||
}
|
|
||||||
f->IsActive = 0;
|
|
||||||
DestroyLocalVals(f);
|
|
||||||
if (DebugFlag &DB_PRTEXPR) {
|
|
||||||
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
|
|
||||||
if (h) fprintf(ErrFp, "%s\n", ErrMsg[h]);
|
|
||||||
else {
|
|
||||||
PrintValue(&ValStack[ValStackPtr-1], ErrFp);
|
|
||||||
fprintf(ErrFp, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* SetUpLocalVars */
|
|
||||||
/* */
|
|
||||||
/* Set up the local variables from the stack frame. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
static int SetUpLocalVars(UserFunc *f)
|
|
||||||
{
|
|
||||||
int i, r;
|
|
||||||
Var *var;
|
|
||||||
|
|
||||||
for (i=0, var=f->locals; var && i<f->nargs; var=var->next, i++) {
|
|
||||||
if ( (r=FnPopValStack(&(var->v))) ) {
|
|
||||||
DestroyLocalVals(f);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************/
|
|
||||||
/* */
|
|
||||||
/* DestroyLocalVals */
|
|
||||||
/* */
|
|
||||||
/* Destroy the values of all local variables after evaluating */
|
|
||||||
/* the function. */
|
|
||||||
/* */
|
|
||||||
/***************************************************************/
|
|
||||||
static void DestroyLocalVals(UserFunc *f)
|
|
||||||
{
|
|
||||||
Var *v = f->locals;
|
|
||||||
|
|
||||||
while(v) {
|
|
||||||
DestroyValue(v->v);
|
|
||||||
v = v->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* UserFuncExists */
|
/* UserFuncExists */
|
||||||
@@ -441,12 +326,33 @@ static void DestroyLocalVals(UserFunc *f)
|
|||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int UserFuncExists(char const *fn)
|
int UserFuncExists(char const *fn)
|
||||||
{
|
{
|
||||||
UserFunc *f;
|
UserFunc *f = FindUserFunc(fn);
|
||||||
int h = HashVal(fn) % FUNC_HASH_SIZE;
|
|
||||||
|
|
||||||
f = FuncHash[h];
|
|
||||||
while (f && StrinCmp(fn, f->name, VAR_NAME_LEN)) f = f->next;
|
|
||||||
if (!f) return -1;
|
if (!f) return -1;
|
||||||
else return f->nargs;
|
else return f->nargs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
/* */
|
||||||
|
/* UnsetAllUserFuncs */
|
||||||
|
/* */
|
||||||
|
/* Call FUNSET on all user funcs. Used with -ds flag to */
|
||||||
|
/* ensure no expr_node memory leaks. */
|
||||||
|
/* */
|
||||||
|
/***************************************************************/
|
||||||
|
void
|
||||||
|
UnsetAllUserFuncs(void)
|
||||||
|
{
|
||||||
|
UserFunc *f;
|
||||||
|
UserFunc *next;
|
||||||
|
int i;
|
||||||
|
for (i=0; i<FUNC_HASH_SIZE; i++) {
|
||||||
|
f = FuncHash[i];
|
||||||
|
while(f) {
|
||||||
|
next = f->next;
|
||||||
|
DestroyUserFunc(f);
|
||||||
|
f = next;
|
||||||
|
}
|
||||||
|
FuncHash[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
54
src/utils.c
54
src/utils.c
@@ -187,31 +187,33 @@ typedef struct cs_s {
|
|||||||
} cs;
|
} cs;
|
||||||
|
|
||||||
static cs *callstack = NULL;
|
static cs *callstack = NULL;
|
||||||
|
static cs *freecs = NULL;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
destroy_cs(cs *entry)
|
destroy_cs(cs *entry)
|
||||||
{
|
{
|
||||||
if (entry->filename) free( (void *) entry->filename);
|
entry->next = freecs;
|
||||||
if (entry->func) free( (void *) entry->func);
|
freecs = entry;
|
||||||
free( (void *) entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
push_call(char const *filename, char const *func, int lineno)
|
push_call(char const *filename, char const *func, int lineno)
|
||||||
{
|
{
|
||||||
cs *entry = NEW(cs);
|
cs *entry;
|
||||||
if (!entry) {
|
if (freecs) {
|
||||||
return E_NO_MEM;
|
entry = freecs;
|
||||||
|
freecs = freecs->next;
|
||||||
|
} else {
|
||||||
|
entry = NEW(cs);
|
||||||
|
if (!entry) {
|
||||||
|
return E_NO_MEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
entry->next = NULL;
|
entry->next = NULL;
|
||||||
entry->filename = StrDup(filename);
|
entry->filename = filename;
|
||||||
entry->func = StrDup(func);
|
entry->func = func;
|
||||||
entry->lineno = lineno;
|
entry->lineno = lineno;
|
||||||
if (!entry->filename || !entry->func) {
|
|
||||||
destroy_cs(entry);
|
|
||||||
return E_NO_MEM;
|
|
||||||
}
|
|
||||||
entry->next = callstack;
|
entry->next = callstack;
|
||||||
callstack = entry;
|
callstack = entry;
|
||||||
return OK;
|
return OK;
|
||||||
@@ -233,11 +235,31 @@ clear_callstack(void)
|
|||||||
static void
|
static void
|
||||||
print_callstack_aux(FILE *fp, cs *entry)
|
print_callstack_aux(FILE *fp, cs *entry)
|
||||||
{
|
{
|
||||||
if (entry) {
|
int i = 0;
|
||||||
print_callstack_aux(fp, entry->next);
|
char const *in = "In";
|
||||||
fprintf(fp, "\n");
|
cs *prev = NULL;
|
||||||
(void) fprintf(fp, "%s(%d): In function `%s'", entry->filename, entry->lineno, entry->func);
|
while(entry) {
|
||||||
|
if (prev) {
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
in = "Called from";
|
||||||
|
}
|
||||||
|
(void) fprintf(fp, " %s(%d): [#%d] %s function `%s'", entry->filename, entry->lineno, i, in, entry->func);
|
||||||
|
prev = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
i++;
|
||||||
|
if (i > 10) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (entry) {
|
||||||
|
(void) fprintf(fp, "\n [remaining call frames omitted]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
have_callstack(void)
|
||||||
|
{
|
||||||
|
return (callstack != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
27
src/var.c
27
src/var.c
@@ -39,8 +39,6 @@ static int IntMax = INT_MAX;
|
|||||||
|
|
||||||
static Var *VHashTbl[VAR_HASH_SIZE];
|
static Var *VHashTbl[VAR_HASH_SIZE];
|
||||||
|
|
||||||
typedef int (*SysVarFunc)(int, Value *);
|
|
||||||
|
|
||||||
static double
|
static double
|
||||||
strtod_in_c_locale(char const *str, char **endptr)
|
strtod_in_c_locale(char const *str, char **endptr)
|
||||||
{
|
{
|
||||||
@@ -511,20 +509,10 @@ int SetVar(char const *str, Value const *val)
|
|||||||
/* Get a copy of the value of the variable. */
|
/* Get a copy of the value of the variable. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
int GetVarValue(char const *str, Value *val, Var *locals, ParsePtr p)
|
int GetVarValue(char const *str, Value *val)
|
||||||
{
|
{
|
||||||
Var *v;
|
Var *v;
|
||||||
|
|
||||||
/* Try searching local variables first */
|
|
||||||
v = locals;
|
|
||||||
while (v) {
|
|
||||||
if (! StrinCmp(str, v->name, VAR_NAME_LEN))
|
|
||||||
return CopyValue(val, &v->v);
|
|
||||||
v = v->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Global variable... mark expression as non-constant */
|
|
||||||
if (p) p->nonconst_expr = 1;
|
|
||||||
v=FindVar(str, 0);
|
v=FindVar(str, 0);
|
||||||
|
|
||||||
if (!v) {
|
if (!v) {
|
||||||
@@ -785,16 +773,6 @@ int DoPreserve (Parser *p)
|
|||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
||||||
/* The structure of a system variable */
|
|
||||||
typedef struct {
|
|
||||||
char const *name;
|
|
||||||
char modifiable;
|
|
||||||
int type;
|
|
||||||
void *value;
|
|
||||||
int min; /* Or const-value */
|
|
||||||
int max;
|
|
||||||
} SysVar;
|
|
||||||
|
|
||||||
/* Macro to access "min" but as a constval. Just to make source more
|
/* Macro to access "min" but as a constval. Just to make source more
|
||||||
readable */
|
readable */
|
||||||
#define constval min
|
#define constval min
|
||||||
@@ -919,7 +897,6 @@ static SysVar SysVarArr[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define NUMSYSVARS ( sizeof(SysVarArr) / sizeof(SysVar) )
|
#define NUMSYSVARS ( sizeof(SysVarArr) / sizeof(SysVar) )
|
||||||
static SysVar *FindSysVar (char const *name);
|
|
||||||
static void DumpSysVar (char const *name, const SysVar *v);
|
static void DumpSysVar (char const *name, const SysVar *v);
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* */
|
/* */
|
||||||
@@ -1016,7 +993,7 @@ int GetSysVar(char const *name, Value *val)
|
|||||||
/* Find a system var with specified name. */
|
/* Find a system var with specified name. */
|
||||||
/* */
|
/* */
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
static SysVar *FindSysVar(char const *name)
|
SysVar *FindSysVar(char const *name)
|
||||||
{
|
{
|
||||||
int top=NUMSYSVARS-1, bottom=0;
|
int top=NUMSYSVARS-1, bottom=0;
|
||||||
int mid=(top + bottom) / 2;
|
int mid=(top + bottom) / 2;
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ set a ansicolor(-1, 0, 0)
|
|||||||
set a ansicolor(42, 42, 256)
|
set a ansicolor(42, 42, 256)
|
||||||
set a ansicolor("foo")
|
set a ansicolor("foo")
|
||||||
set a ansicolor("1 1")
|
set a ansicolor("1 1")
|
||||||
set a ansicolor("-1 -1 0");
|
set a ansicolor("-1 -1 0")
|
||||||
set a ansicolor("256 1 1");
|
set a ansicolor("256 1 1")
|
||||||
set a ansicolor(128, 128, 128, 2)
|
set a ansicolor(128, 128, 128, 2)
|
||||||
set a ansicolor(128, 128, 128, -1)
|
set a ansicolor(128, 128, 128, -1)
|
||||||
set a ansicolor(128, 128, 128, 0, 2)
|
set a ansicolor(128, 128, 128, 0, 2)
|
||||||
|
|||||||
Reference in New Issue
Block a user