/* * Invoke a function and return the result. The function is * assumed to not be a special built-in (eg, "@if"). */ char * _tmpl_invoke(struct tmpl_ctx *ctx, char **errmsgp, const struct func_call *call) { char **args_copy = NULL; char **args = NULL; char *r = NULL; int i; /* Evaluate arguments; first function argument is the function name */ if ((args = MALLOC(ctx->mtype, (1 + call->nargs) * sizeof(*args))) == NULL) return (NULL); memset(args, 0, (1 + call->nargs) * sizeof(*args)); if ((args[0] = STRDUP(ctx->mtype, call->funcname)) == NULL) goto fail; for (i = 0; i < call->nargs; i++) { if ((args[i + 1] = evaluate_arg(ctx, errmsgp, &call->args[i])) == NULL) goto fail; } /* Save a copy of argument pointers so handlers can modify them */ if ((args_copy = MALLOC(ctx->mtype, (1 + call->nargs) * sizeof(*args))) == NULL) return (NULL); memcpy(args_copy, args, (1 + call->nargs) * sizeof(*args)); /* Invoke function, either run-time defined, built-in, or user */ assert(call->type == TY_NORMAL); if ((i = _tmpl_find_func(ctx, call->funcname)) != -1) { r = tmpl_invoke_defined(ctx, &ctx->funcs[i], errmsgp, 1 + call->nargs, args_copy); } else if (call->handler != NULL) r = (*call->handler)(ctx, errmsgp, 1 + call->nargs, args_copy); else r = (*ctx->handler)(ctx, errmsgp, 1 + call->nargs, args_copy); fail: for (i = 0; i < 1 + call->nargs; i++) FREE(ctx->mtype, args[i]); FREE(ctx->mtype, args); FREE(ctx->mtype, args_copy); return (r); }
/* * Execute elements. */ enum exec_rtn _tmpl_execute_elems(struct tmpl_ctx *ctx, struct tmpl_elem *const elems, int first_elem, int nelems) { #if TMPL_DEBUG char indent[80]; #endif enum exec_rtn rtn; int i; /* Increase nesting */ ctx->depth++; /* Check for infinite loop */ if (ctx->depth >= INFINITE_LOOP) { pr_err(ctx, 0, "too much recursion in template execution"); rtn = RTN_NORMAL; goto done; } /* Debug */ #if TMPL_DEBUG *indent = '\0'; for (i = 1; i < ctx->depth; i++) strlcat(indent, " ", sizeof(indent)); TDBG("%sExecuting %d elems starting at %d\n", indent _ nelems _ first_elem); #endif /* Execute elements in order */ for (i = first_elem; i < first_elem + nelems; i++) { struct tmpl_elem *const elem = &elems[i]; TDBG("%s%4d: %s\n", indent _ i _ _tmpl_elemstr(&elems[i] _ i)); /* Handle normal text */ if (elem->text != NULL) { /* Optionally skip initial NL + whitespace */ if (((elem->flags & TMPL_ELEM_NL_WHITE) != 0 && ctx->flags & TMPL_SKIP_NL_WHITE) != 0) continue; /* Output text */ fwrite(elem->text, 1, elem->len, ctx->output); continue; } /* Handle function call */ switch (elem->call.type) { case TY_NORMAL: { char *errmsg = NULL; char *result; if ((result = _tmpl_invoke(ctx, &errmsg, &elem->call)) == NULL) { pr_err(ctx, errno, errmsg); FREE(ctx->mtype, errmsg); break; } TDBG("%s --> \"%s\"\n", indent _ result); (void)fputs(result, ctx->output); FREE(ctx->mtype, result); break; } case TY_LOOP: { struct loop_ctx this; char *errmsg = NULL; long count; char *eptr; char *x; if (!(x = evaluate_arg(ctx, &errmsg, &elem->call.args[0]))) { pr_err(ctx, errno, errmsg); FREE(ctx->mtype, errmsg); i += elem->u.u_loop.endloop; break; } count = strtoul(x, &eptr, 10); if (*x == '\0' || *eptr != '\0' || count < 0 || count == LONG_MAX) { char buf[32]; snprintf(buf, sizeof(buf), "invalid loop count \"%s\"", x); pr_err(ctx, 0, buf); FREE(ctx->mtype, x); i += elem->u.u_loop.endloop; break; } FREE(ctx->mtype, x); this.outer = ctx->loop; ctx->loop = &this; for (this.index = 0; this.index < count; this.index++) { rtn = _tmpl_execute_elems(ctx, elems, i + 1, elem->u.u_loop.endloop - 1); if (rtn == RTN_BREAK) break; if (rtn == RTN_RETURN) { ctx->loop = this.outer; goto done; } } ctx->loop = this.outer; i += elem->u.u_loop.endloop; break; } case TY_WHILE: while (1) { char *errmsg = NULL; int truth; char *x; if (!(x = evaluate_arg(ctx, &errmsg, &elem->call.args[0]))) { pr_err(ctx, errno, errmsg); FREE(ctx->mtype, errmsg); i += elem->u.u_while.endwhile; break; } truth = _tmpl_true(x); FREE(ctx->mtype, x); if (!truth) break; rtn = _tmpl_execute_elems(ctx, elems, i + 1, elem->u.u_while.endwhile - 1); if (rtn == RTN_BREAK) break; if (rtn == RTN_RETURN) goto done; } i += elem->u.u_while.endwhile; break; case TY_IF: case TY_ELIF: { char *errmsg = NULL; int first = -1; int num = 0; int truth; char *x; if (!(x = evaluate_arg(ctx, &errmsg, &elem->call.args[0]))) { pr_err(ctx, errno, errmsg); FREE(ctx->mtype, errmsg); i += elem->u.u_if.endif; break; } truth = _tmpl_true(x); FREE(ctx->mtype, x); if (truth) { first = i + 1; num = (elem->u.u_if.elsie != -1) ? elem->u.u_if.elsie - 1 : elem->u.u_if.endif - 1; } else if (elem->u.u_if.elsie != -1) { first = i + elem->u.u_if.elsie; num = elem->u.u_if.endif - elem->u.u_if.elsie; } if (first != -1) { rtn = _tmpl_execute_elems(ctx, elems, first, num); if (rtn == RTN_BREAK || rtn == RTN_RETURN || rtn == RTN_CONTINUE) goto done; } i += elem->u.u_if.endif; break; } case TY_DEFINE: { char *errmsg = NULL; char *name; if (!(name = evaluate_arg(ctx, &errmsg, &elem->call.args[0]))) { pr_err(ctx, errno, errmsg); FREE(ctx->mtype, errmsg); i += elem->u.u_define.enddef; break; } #ifdef TMPL_DEBUG TDBG("%s%6sDefining function \"%s\" as %d elems" " starting at %d\n", indent _ "" _ name _ elem->u.u_define.enddef - 1 _ i + 1); #endif if (_tmpl_set_func(ctx, name, elems + i + 1, elem->u.u_define.enddef - 1) == -1) { pr_err(ctx, errno, NULL); FREE(ctx->mtype, name); i += elem->u.u_define.enddef; break; } FREE(ctx->mtype, name); i += elem->u.u_define.enddef; break; } case TY_ENDLOOP: case TY_ENDWHILE: case TY_ELSE: case TY_ENDIF: case TY_ENDDEF: break; case TY_BREAK: rtn = RTN_BREAK; goto done; case TY_CONTINUE: rtn = RTN_CONTINUE; goto done; case TY_RETURN: rtn = RTN_RETURN; goto done; default: assert(0); } } /* If we finished all the elements, that's a normal return */ rtn = RTN_NORMAL; done: /* Debug */ #if TMPL_DEBUG TDBG("%sDone, return is %s\n", indent _ tmpl_rtnstr(rtn)); #endif /* Decrease nesting */ ctx->depth--; /* Done */ return (rtn); }
tree evaluate_impl (tree t) { //cout << "Really evaluate " << t << LF; switch (L(t)) { /* Typesetting primitives with side effects */ case DATOMS: return evaluate_formatting (t, ATOM_DECORATIONS); case DLINES: return evaluate_formatting (t, LINE_DECORATIONS); case DPAGES: return evaluate_formatting (t, PAGE_DECORATIONS); case TFORMAT: return evaluate_formatting (t, CELL_FORMAT); case TABLE: return evaluate_table (t); /* Primitives for macro expansion */ case ASSIGN: return evaluate_assign (t); case WITH: return evaluate_with (t); case PROVIDES: return evaluate_provides (t); case VALUE: return evaluate_value (t); case QUOTE_VALUE: return evaluate_quote_value (t); case MACRO: return copy (t); case DRD_PROPS: return evaluate_drd_props (t); #ifdef CLASSICAL_MACRO_EXPANSION case ARG: return evaluate_arg (t); case QUOTE_ARG: return evaluate_quote_arg (t); #endif case COMPOUND: return evaluate_compound (t); case XMACRO: return copy (t); case GET_LABEL: return evaluate_get_label (t); case GET_ARITY: return evaluate_get_arity (t); /* Primitives for quoting and evaluation */ case MAP_ARGS: return evaluate_rewrite (t); case EVAL_ARGS: return evaluate_eval_args (t); case MARK: return tree (MARK, copy (t[0]), evaluate (t[1])); case EXPAND_AS: return evaluate (t[1]); case EVAL: return evaluate (evaluate (t[0])); case QUOTE: return t[0]; case QUASI: return evaluate (evaluate_quasiquote (t[0])); case QUASIQUOTE: return evaluate_quasiquote (t[0]); case UNQUOTE: case VAR_UNQUOTE: return evaluate (t[0]); case COPY: return copy (evaluate (t[0])); /* Control structures */ case IF: case VAR_IF: return evaluate_if (t); case CASE: return evaluate_case (t); case WHILE: return evaluate_while (t); case FOR_EACH: return evaluate_for_each (t); case EXTERN: return evaluate_rewrite (t); case VAR_INCLUDE: return evaluate_include (t); case WITH_PACKAGE: return evaluate_rewrite (t); case USE_PACKAGE: return evaluate_use_package (t); case USE_MODULE: return evaluate_use_module (t); /* Computational markup */ case OR: return evaluate_or (t); case XOR: return evaluate_xor (t); case AND: return evaluate_and (t); case NOT: return evaluate_not (t); case PLUS: case MINUS: return evaluate_plus_minus (t); case TIMES: case OVER: return evaluate_times_over (t); case DIV: return evaluate_divide (t); case MOD: return evaluate_modulo (t); case MATH_SQRT: return evaluate_math_sqrt (t); case EXP: return evaluate_exp (t); case LOG: return evaluate_log (t); case POW: return evaluate_pow (t); case COS: return evaluate_cos (t); case SIN: return evaluate_sin (t); case TAN: return evaluate_tan (t); case MERGE: return evaluate_merge (t); case LENGTH: return evaluate_length (t); case RANGE: return evaluate_range (t); case NUMBER: return evaluate_number (t); case _DATE: return evaluate_date (t); case TRANSLATE: return evaluate_translate (t); case CHANGE_CASE: return evaluate_change_case (t); case FIND_FILE: return evaluate_find_file (t); case IS_TUPLE: return evaluate_is_tuple (t); case LOOK_UP: return evaluate_lookup (t); case EQUAL: return evaluate_equal (t); case UNEQUAL: return evaluate_unequal (t); case LESS: return evaluate_less (t); case LESSEQ: return evaluate_lesseq (t); case GREATER: return evaluate_greater (t); case GREATEREQ: return evaluate_greatereq (t); case BLEND: return evaluate_blend (t); /* Length units */ case CM_LENGTH: return evaluate_cm_length (); case MM_LENGTH: return evaluate_mm_length (); case IN_LENGTH: return evaluate_in_length (); case PT_LENGTH: return evaluate_pt_length (); case BP_LENGTH: return evaluate_bp_length (); case DD_LENGTH: return evaluate_dd_length (); case PC_LENGTH: return evaluate_pc_length (); case CC_LENGTH: return evaluate_cc_length (); case FS_LENGTH: return evaluate_fs_length (); case FBS_LENGTH: return evaluate_fbs_length (); case EM_LENGTH: return evaluate_em_length (); case LN_LENGTH: return evaluate_ln_length (); case SEP_LENGTH: return evaluate_sep_length (); case YFRAC_LENGTH: return evaluate_yfrac_length (); case EX_LENGTH: return evaluate_ex_length (); case FN_LENGTH: return evaluate_fn_length (); case FNS_LENGTH: return evaluate_fns_length (); case BLS_LENGTH: return evaluate_bls_length (); case FNBOT_LENGTH: return evaluate_fnbot_length (); case FNTOP_LENGTH: return evaluate_fntop_length (); case SPC_LENGTH: return evaluate_spc_length (); case XSPC_LENGTH: return evaluate_xspc_length (); case PAR_LENGTH: return evaluate_par_length (); case PAG_LENGTH: return evaluate_pag_length (); case GW_LENGTH: return evaluate_gw_length (); case GH_LENGTH: return evaluate_gh_length (); case GU_LENGTH: return evaluate_gu_length (); case TMPT_LENGTH: return evaluate_tmpt_length (); case PX_LENGTH: return evaluate_px_length (); case MSEC_LENGTH: return evaluate_msec_length (); case SEC_LENGTH: return evaluate_sec_length (); case MIN_LENGTH: return evaluate_min_length (); case HR_LENGTH: return evaluate_hr_length (); /* Primitives for stylesheet editing */ case STYLE_WITH: case VAR_STYLE_WITH: return evaluate (t[N(t)-1]); case STYLE_ONLY: case VAR_STYLE_ONLY: case ACTIVE: case VAR_ACTIVE: case INACTIVE: case VAR_INACTIVE: return evaluate_compound (t); case REWRITE_INACTIVE: return evaluate_rewrite (t); /* Linking primitives */ case HARD_ID: return evaluate_hard_id (t[0]); case SCRIPT: return evaluate_script (t); case HLINK: case ACTION: return evaluate_compound (t); case SET_BINDING: return evaluate_set_binding (t); case GET_BINDING: return evaluate_get_binding (t); /* Graphical primitives */ case PATTERN: return evaluate_pattern (t); case _POINT: return evaluate_point (t); /* case BOX_INFO: return evaluate_box_info (t); case FRAME_DIRECT: return evaluate_frame_direct (t); case FRAME_INVERSE: return evaluate_frame_inverse (t); */ /* User extensions */ default: if (L(t) < START_EXTENSIONS) { int i, n= N(t); tree r (t, n); for (i=0; i<n; i++) r[i]= evaluate (t[i]); transfer_ip (t, r); return r; } else { tree r= evaluate_compound (t); return r; } } }