/*
 * 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);
}
示例#3
0
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;
    }      
  }
}