+/*
+ * Default operations and functions
+ */
+
+static int
+isVariable(VariableValue value) {
+ if ( value == NULL )
+ return 0;
+
+ if ( (value->flags & TND_DEFINED) == 0 ) {
+ return 0;
+ } else {
+ switch (value->type) {
+ case valueInt:
+ return value->value.intValue;
+ case valueString:
+ if ( value->value.stringValue == NULL || *value->value.stringValue == '\0' )
+ return 0;
+ return 1;
+ case valueTime:
+ return ( value->value.timeValue > 0 ) ? 1 : 0;
+ case valueBool:
+ return value->value.boolValue;
+ case valueDouble:
+ return (value->value.doubleValue == 0) ? 0 : 1;
+ case valuePointer:
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static VariableValue
+makeBoolValue(Template tmpl, int v) {
+ VariableValue outvalue = mcalloc(tmpl->templateContext, sizeof(VariableValueData));
+
+ outvalue->type = valueBool;
+ outvalue->flags= TND_DEFINED;
+ outvalue->value.boolValue = (v) ? 1 : 0;
+ return outvalue;
+}
+
+static VariableValue
+copyValue(Template tmpl, VariableValue in) {
+ VariableValue out= mcalloc(tmpl->templateContext, sizeof(VariableValueData));
+
+ if (in)
+ memcpy(out, in, sizeof(VariableValueData));
+ else {
+ out->type = valueBool; /* something */
+ out->flags = 0;
+ }
+ return out;
+}
+
+static VariableValue
+isDefinedFn(Template tmpl, int n, VariableValue *vals) {
+ return makeBoolValue(tmpl, vals[0]->flags & TND_DEFINED );
+}
+
+static int
+strmblen(char *str) {
+ int len = strlen(str);
+ int totlen = 0, clen;
+
+ mblen(NULL,0); /* reset internal state */
+ while( len > 0 ) {
+ clen = mblen( str, len );
+ str += clen;
+ len -= clen;
+ totlen++;
+ }
+
+ return totlen;
+}
+
+static VariableValue
+LengthFn(Template tmpl, int n, VariableValue *vals) {
+ VariableValue outvalue = NULL;
+
+ outvalue = copyValue( tmpl, NULL );
+ outvalue->type = valueInt;
+
+ if ( vals[0]->type == valueString && vals[0]->value.stringValue &&
+ (vals[0]->flags & TND_DEFINED) ) {
+ outvalue->flags |= TND_DEFINED;
+ outvalue->value.intValue = strmblen( vals[0]->value.stringValue );
+ } else
+ outvalue->flags &= ~TND_DEFINED;
+
+ return outvalue;
+}
+
+static VariableValue
+NotFn(Template tmpl, int n, VariableValue *vals) {
+ return makeBoolValue(tmpl, !isVariable(vals[0]));
+}
+
+static VariableValue
+AndFn(Template tmpl, int n, VariableValue *vals) {
+ return makeBoolValue(tmpl, isVariable(vals[0]) && isVariable(vals[1]) );
+}
+
+static VariableValue
+OrFn(Template tmpl, int n, VariableValue *vals) {
+ return makeBoolValue(tmpl, isVariable(vals[0]) || isVariable(vals[1]) );
+}
+
+static VariableValue
+CondFn(Template tmpl, int n, VariableValue *vals) {
+ return isVariable(vals[0]) ? vals[1] : vals[2];
+}
+
+static VariableValue
+ModFn(Template tmpl, int n, VariableValue *vals) {
+ VariableValue outvalue = copyValue( tmpl, NULL );
+
+ outvalue->type = valueInt;
+
+ if ( (vals[0]->flags & vals[1]->flags & TND_DEFINED) &&
+ vals[0]->type == valueInt && vals[1]->type == valueInt) {
+
+ outvalue->flags |= TND_DEFINED;
+ outvalue->value.intValue = vals[0]->value.intValue % vals[1]->value.intValue;
+ } else
+ outvalue->flags &= ~TND_DEFINED;
+
+ return outvalue;
+}
+
+static VariableValue
+UnaryMinesFn(Template tmpl, int n, VariableValue *vals) {
+ VariableValue outvalue = copyValue( tmpl, vals[0] );
+
+ if (outvalue->type == valueInt)
+ outvalue->value.intValue = -outvalue->value.intValue;
+ else if (outvalue->type == valueDouble)
+ outvalue->value.doubleValue = -outvalue->value.doubleValue;
+ else
+ outvalue->flags &= ~TND_DEFINED;
+
+ return outvalue;
+}
+
+#define ISNUM(v) ( ((v)->type == valueDouble || (v)->type == valueInt) && ((v)->flags & TND_DEFINED) )
+
+#define ARIPHACT(OP) \
+ VariableValue outvalue = copyValue( tmpl, NULL ); \
+ if ( !(ISNUM(vals[0]) && ISNUM(vals[1])) ) { \
+ outvalue->flags &= ~TND_DEFINED; \
+ } else if ( vals[0]->type == valueDouble || vals[1]->type == valueDouble ) { \
+ outvalue->flags |= TND_DEFINED; \
+ outvalue->type = valueDouble; \
+ if ( vals[0]->type == valueDouble ) \
+ outvalue->value.doubleValue = vals[0]->value.doubleValue; \
+ else \
+ outvalue->value.doubleValue = vals[0]->value.intValue; \
+ if ( vals[1]->type == valueDouble ) \
+ outvalue->value.doubleValue OP##= vals[1]->value.doubleValue; \
+ else \
+ outvalue->value.doubleValue OP##= vals[1]->value.intValue; \
+ } else { \
+ outvalue->flags |= TND_DEFINED; \
+ outvalue->type = valueInt; \
+ outvalue->value.intValue = vals[0]->value.intValue OP vals[1]->value.intValue; \
+ }
+
+static VariableValue
+PlusFn(Template tmpl, int n, VariableValue *vals) {
+ ARIPHACT(+)
+ return outvalue;
+}
+
+static VariableValue
+MinesFn(Template tmpl, int n, VariableValue *vals) {
+ ARIPHACT(-)
+ return outvalue;
+}
+
+static VariableValue
+MulFn(Template tmpl, int n, VariableValue *vals) {
+ ARIPHACT(*)
+ return outvalue;
+}
+
+static VariableValue
+DivFn(Template tmpl, int n, VariableValue *vals) {
+ ARIPHACT(/)
+ return outvalue;
+}
+
+#define CMPACT(OP) \
+ VariableValue outvalue = copyValue( tmpl, NULL ); \
+ outvalue->type = valueBool; \
+ if ( !(ISNUM(vals[0]) && ISNUM(vals[1])) ) { \
+ outvalue->flags &= ~TND_DEFINED; \
+ } else if ( vals[0]->type == valueDouble || vals[1]->type == valueDouble ) { \
+ outvalue->flags |= TND_DEFINED; \
+ if ( vals[0]->type == valueDouble && vals[1]->type == valueDouble ) \
+ outvalue->value.boolValue = (vals[0]->value.doubleValue OP vals[1]->value.doubleValue) \
+ ? 1 : 0; \
+ else if ( vals[0]->type == valueDouble ) \
+ outvalue->value.boolValue = (vals[0]->value.doubleValue OP vals[1]->value.intValue) \
+ ? 1 : 0; \
+ else \
+ outvalue->value.boolValue = (vals[0]->value.intValue OP vals[1]->value.doubleValue) \
+ ? 1 : 0; \
+ } else { \
+ outvalue->flags |= TND_DEFINED; \
+ outvalue->value.boolValue = (vals[0]->value.intValue OP vals[1]->value.intValue) ? 1 : 0; \
+ }
+
+static VariableValue
+LtFn(Template tmpl, int n, VariableValue *vals) {
+ CMPACT(<)
+ return outvalue;
+}
+
+static VariableValue
+LeFn(Template tmpl, int n, VariableValue *vals) {
+ CMPACT(<=)
+ return outvalue;
+}
+
+static VariableValue
+EqFn(Template tmpl, int n, VariableValue *vals) {
+ CMPACT(==)
+ return outvalue;
+}
+
+static VariableValue
+GeFn(Template tmpl, int n, VariableValue *vals) {
+ CMPACT(>=)
+ return outvalue;
+}
+
+static VariableValue
+GtFn(Template tmpl, int n, VariableValue *vals) {
+ CMPACT(>)
+ return outvalue;
+}
+
+static VariableValue
+NeFn(Template tmpl, int n, VariableValue *vals) {
+ CMPACT(!=)
+ return outvalue;
+}
+
+static executeFunctionDescData Functions[] = {
+ {"defined", 1, isDefinedFn},
+ {"length", 1, LengthFn},
+ {"+", 2, PlusFn},
+ {"-", 2, MinesFn},
+ {"*", 2, MulFn},
+ {"/", 2, DivFn},
+ {"%", 2, ModFn},
+ {"-", 1, UnaryMinesFn},
+ {"?", 3, CondFn},
+ {"||", 2, OrFn},
+ {"&&", 2, AndFn},
+ {"!", 1, NotFn},
+ {"<", 2, LtFn},
+ {"<=", 2, LeFn},
+ {"==", 2, EqFn},
+ {">=", 2, GeFn},
+ {">", 2, GtFn},
+ {"!=", 2, NeFn},
+ {"<>", 2, NeFn},
+ {NULL, -1, NULL}
+};
+
+
+/*
+ * Initialize functions
+ */
+