| 86 | } |
| 87 | |
| 88 | static const char *ap_expr_eval_word(ap_expr_eval_ctx_t *ctx, |
| 89 | const ap_expr_t *node) |
| 90 | { |
| 91 | const char *result = ""; |
| 92 | if (inc_rec(ctx)) |
| 93 | return result; |
| 94 | switch (node->node_op) { |
| 95 | case op_Digit: |
| 96 | case op_String: |
| 97 | result = node->node_arg1; |
| 98 | break; |
| 99 | case op_Var: |
| 100 | result = ap_expr_eval_var(ctx, (ap_expr_var_func_t *)node->node_arg1, |
| 101 | node->node_arg2); |
| 102 | break; |
| 103 | case op_Concat: |
| 104 | if (((ap_expr_t *)node->node_arg2)->node_op != op_Concat && |
| 105 | ((ap_expr_t *)node->node_arg1)->node_op != op_Concat) { |
| 106 | const char *s1 = ap_expr_eval_word(ctx, node->node_arg1); |
| 107 | const char *s2 = ap_expr_eval_word(ctx, node->node_arg2); |
| 108 | if (!*s1) |
| 109 | result = s2; |
| 110 | else if (!*s2) |
| 111 | result = s1; |
| 112 | else |
| 113 | result = apr_pstrcat(ctx->p, s1, s2, NULL); |
| 114 | } |
| 115 | else if (((ap_expr_t *)node->node_arg1)->node_op == op_Concat) { |
| 116 | const ap_expr_t *nodep = node; |
| 117 | int n; |
| 118 | int i = 1; |
| 119 | struct iovec *vec; |
| 120 | do { |
| 121 | nodep = nodep->node_arg1; |
| 122 | i++; |
| 123 | } while (nodep->node_op == op_Concat); |
| 124 | vec = apr_palloc(ctx->p, i * sizeof(struct iovec)); |
| 125 | n = i; |
| 126 | nodep = node; |
| 127 | i--; |
| 128 | do { |
| 129 | vec[i].iov_base = (void *)ap_expr_eval_word(ctx, |
| 130 | nodep->node_arg2); |
| 131 | vec[i].iov_len = strlen(vec[i].iov_base); |
| 132 | i--; |
| 133 | nodep = nodep->node_arg1; |
| 134 | } while (nodep->node_op == op_Concat); |
| 135 | vec[i].iov_base = (void *)ap_expr_eval_word(ctx, nodep); |
| 136 | vec[i].iov_len = strlen(vec[i].iov_base); |
| 137 | result = apr_pstrcatv(ctx->p, vec, n, NULL); |
| 138 | } |
| 139 | else { |
| 140 | const ap_expr_t *nodep = node; |
| 141 | int i = 1; |
| 142 | struct iovec *vec; |
| 143 | do { |
| 144 | nodep = nodep->node_arg2; |
| 145 | i++; |
no test coverage detected