Annotation of embedaddon/libpdel/tmpl/tmpl_exec.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (c) 2001-2002 Packet Design, LLC.
                      4:  * All rights reserved.
                      5:  * 
                      6:  * Subject to the following obligations and disclaimer of warranty,
                      7:  * use and redistribution of this software, in source or object code
                      8:  * forms, with or without modifications are expressly permitted by
                      9:  * Packet Design; provided, however, that:
                     10:  * 
                     11:  *    (i)  Any and all reproductions of the source or object code
                     12:  *         must include the copyright notice above and the following
                     13:  *         disclaimer of warranties; and
                     14:  *    (ii) No rights are granted, in any manner or form, to use
                     15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
                     16:  *         on advertising, endorsements, or otherwise except as such
                     17:  *         appears in the above copyright notice or in the software.
                     18:  * 
                     19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
                     20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
                     21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
                     22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
                     23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
                     24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
                     25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
                     26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
                     27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
                     28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
                     29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
                     30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
                     31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
                     32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
                     33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
                     35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
                     36:  * THE POSSIBILITY OF SUCH DAMAGE.
                     37:  *
                     38:  * Author: Archie Cobbs <archie@freebsd.org>
                     39:  */
                     40: 
                     41: #include "tmpl_internal.h"
                     42: 
                     43: /*
                     44:  * Internal functions
                     45:  */
                     46: static char    *tmpl_invoke_defined(struct tmpl_ctx *ctx,
                     47:                        struct exec_func *func, char **errmsgp,
                     48:                        int argc, char **argv);
                     49: static int     tmpl_invoke_defined2(struct tmpl_ctx *ctx,
                     50:                        struct exec_func *func, char **errmsgp,
                     51:                        int argc, char **argv);
                     52: static void    tmpl_exec_cleanup(void *arg);
                     53: static char    *evaluate_arg(struct tmpl_ctx *ctx,
                     54:                        char **errmsgp, const struct func_arg *arg);
                     55: static void    pr_err(struct tmpl_ctx *ctx, int errnum, const char *msg);
                     56: #if TMPL_DEBUG
                     57: static const   char *tmpl_rtnstr(enum exec_rtn rtn);
                     58: #endif
                     59: 
                     60: /*
                     61:  * Execute a template.
                     62:  */
                     63: int
                     64: tmpl_execute(struct tmpl *tmpl, struct tmpl_ctx *ctx, FILE *output, int flags)
                     65: {
                     66:        /* Avoid reentrant execution with the same context */
                     67:        if (ctx->output != NULL) {
                     68:                errno = EBUSY;
                     69:                return (-1);
                     70:        }
                     71: 
                     72:        /* Allow output to be NULL */
                     73:        if (output == NULL) {
                     74:                if ((output = fopen(_PATH_DEVNULL, "w")) == NULL)
                     75:                        return (-1);
                     76:                ctx->close_output = 1;
                     77:        } else
                     78:                ctx->close_output = 0;
                     79: 
                     80:        /* Push cleanup hook */
                     81:        pthread_cleanup_push(tmpl_exec_cleanup, ctx);
                     82: 
                     83:        /* Set up context info for this run */
                     84:        ctx->output = output;
                     85:        ctx->orig_output = output;
                     86:        ctx->flags = flags;
                     87: 
                     88:        /* Execute template */
                     89:        _tmpl_execute_elems(ctx, tmpl->elems, 0, tmpl->num_elems);
                     90: 
                     91:        /* Finish up */
                     92:        pthread_cleanup_pop(1);
                     93: 
                     94:        /* Done */
                     95:        return (0);
                     96: }
                     97: 
                     98: /*
                     99:  * Clean up a context after execution.
                    100:  */
                    101: static void
                    102: tmpl_exec_cleanup(void *arg)
                    103: {
                    104:        struct tmpl_ctx *const ctx = arg;
                    105: 
                    106:        /* Close output if needed */
                    107:        if (ctx->close_output)
                    108:                fclose(ctx->output);
                    109:        ctx->output = NULL;
                    110:        ctx->orig_output = NULL;
                    111:        ctx->flags = 0;
                    112: }
                    113: 
                    114: /*
                    115:  * Invoke a single template function.
                    116:  */
                    117: int
                    118: tmpl_execute_func(struct tmpl_ctx *ctx, FILE *output,
                    119:        char **errmsgp, int argc, char **argv, int flags)
                    120: {
                    121:        struct tmpl *t;
                    122:        char *input;
                    123:        FILE *sbuf;
                    124:        int rtn;
                    125:        int i;
                    126: 
                    127:        /* Avoid reentrant execution with the same context */
                    128:        if (ctx->output != NULL) {
                    129:                errno = EBUSY;
                    130:                return (-1);
                    131:        }
                    132: 
                    133:        /* Initialize error string */
                    134:        *errmsgp = NULL;
                    135: 
                    136:        /* Sanity */
                    137:        if (argc < 1) {
                    138:                errno = EINVAL;
                    139:                return (-1);
                    140:        }
                    141: 
                    142:        /* Create template input containing the function call */
                    143:        if ((sbuf = string_buf_output(TYPED_MEM_TEMP)) == NULL)
                    144:                return (-1);
                    145:        fprintf(sbuf, "@%s(", argv[0]);
                    146:        for (i = 1; i < argc; i++) {
                    147:                char *qarg;
                    148: 
                    149:                /* Enquote and add argument */
                    150:                if ((qarg = string_enquote(argv[i], TYPED_MEM_TEMP)) == NULL) {
                    151:                        fclose(sbuf);
                    152:                        return (-1);
                    153:                }
                    154:                fprintf(sbuf, "%s%s", i > 1 ? "," : "", qarg);
                    155:                FREE(TYPED_MEM_TEMP, qarg);
                    156:        }
                    157:        fprintf(sbuf, ")");
                    158:        if ((input = string_buf_content(sbuf, 1)) == NULL) {
                    159:                fclose(sbuf);
                    160:                return (-1);
                    161:        }
                    162:        fclose(sbuf);
                    163: 
                    164:        /* Create a new template from the input string */
                    165:        if ((sbuf = string_buf_input(input, strlen(input), 0)) == NULL) {
                    166:                FREE(TYPED_MEM_TEMP, input);
                    167:                return (-1);
                    168:        }
                    169:        t = tmpl_create(sbuf, NULL, TYPED_MEM_TEMP);
                    170:        fclose(sbuf);
                    171:        FREE(TYPED_MEM_TEMP, input);
                    172:        if (t == NULL)
                    173:                return (-1);
                    174: 
                    175:        /* Execute template */
                    176:        rtn = tmpl_execute(t, ctx, output, flags);
                    177: 
                    178:        /* Clean up */
                    179:        tmpl_destroy(&t);
                    180:        return (rtn);
                    181: }
                    182: 
                    183: /*
                    184:  * Execute elements.
                    185:  */
                    186: enum exec_rtn
                    187: _tmpl_execute_elems(struct tmpl_ctx *ctx,
                    188:        struct tmpl_elem *const elems, int first_elem, int nelems)
                    189: {
                    190: #if TMPL_DEBUG
                    191:        char indent[80];
                    192: #endif
                    193:        enum exec_rtn rtn;
                    194:        int i;
                    195: 
                    196:        /* Increase nesting */
                    197:        ctx->depth++;
                    198: 
                    199:        /* Check for infinite loop */
                    200:        if (ctx->depth >= INFINITE_LOOP) {
                    201:                pr_err(ctx, 0, "too much recursion in template execution");
                    202:                rtn = RTN_NORMAL;
                    203:                goto done;
                    204:        }
                    205: 
                    206:        /* Debug */
                    207: #if TMPL_DEBUG
                    208:        *indent = '\0';
                    209:        for (i = 1; i < ctx->depth; i++)
                    210:                strlcat(indent, "  ", sizeof(indent));
                    211:        DBG("%sExecuting %d elems starting at %d\n",
                    212:            indent, nelems, first_elem);
                    213: #endif
                    214: 
                    215:        /* Execute elements in order */
                    216:        for (i = first_elem; i < first_elem + nelems; i++) {
                    217:                struct tmpl_elem *const elem = &elems[i];
                    218: 
                    219:                DBG("%s%4d: %s\n", indent, i, _tmpl_elemstr(&elems[i], i));
                    220: 
                    221:                /* Handle normal text */
                    222:                if (elem->text != NULL) {
                    223: 
                    224:                        /* Optionally skip initial NL + whitespace */
                    225:                        if (((elem->flags & TMPL_ELEM_NL_WHITE) != 0
                    226:                            && ctx->flags & TMPL_SKIP_NL_WHITE) != 0)
                    227:                                continue;
                    228: 
                    229:                        /* Output text */
                    230:                        fwrite(elem->text, 1, elem->len, ctx->output);
                    231:                        continue;
                    232:                }
                    233: 
                    234:                /* Handle function call */
                    235:                switch (elem->call.type) {
                    236:                case TY_NORMAL:
                    237:                    {
                    238:                        char *errmsg = NULL;
                    239:                        char *result;
                    240: 
                    241:                        if ((result = _tmpl_invoke(ctx,
                    242:                            &errmsg, &elem->call)) == NULL) {
                    243:                                pr_err(ctx, errno, errmsg);
                    244:                                FREE(ctx->mtype, errmsg);
                    245:                                break;
                    246:                        }
                    247:                        DBG("%s      --> \"%s\"\n", indent, result);
                    248:                        (void)fputs(result, ctx->output);
                    249:                        FREE(ctx->mtype, result);
                    250:                        break;
                    251:                    }
                    252: 
                    253:                case TY_LOOP:
                    254:                    {
                    255:                        struct loop_ctx this;
                    256:                        char *errmsg = NULL;
                    257:                        long count;
                    258:                        char *eptr;
                    259:                        char *x;
                    260: 
                    261:                        if (!(x = evaluate_arg(ctx,
                    262:                            &errmsg, &elem->call.args[0]))) {
                    263:                                pr_err(ctx, errno, errmsg);
                    264:                                FREE(ctx->mtype, errmsg);
                    265:                                i += elem->u.u_loop.endloop;
                    266:                                break;
                    267:                        }
                    268:                        count = strtoul(x, &eptr, 10);
                    269:                        if (*x == '\0' || *eptr != '\0'
                    270:                            || count < 0 || count == LONG_MAX) {
                    271:                                char buf[32];
                    272: 
                    273:                                snprintf(buf, sizeof(buf),
                    274:                                    "invalid loop count \"%s\"", x);
                    275:                                pr_err(ctx, 0, buf);
                    276:                                FREE(ctx->mtype, x);
                    277:                                i += elem->u.u_loop.endloop;
                    278:                                break;
                    279:                        }
                    280:                        FREE(ctx->mtype, x);
                    281:                        this.outer = ctx->loop;
                    282:                        ctx->loop = &this;
                    283:                        for (this.index = 0; this.index < count; this.index++) {
                    284:                                rtn = _tmpl_execute_elems(ctx, elems,
                    285:                                    i + 1, elem->u.u_loop.endloop - 1);
                    286:                                if (rtn == RTN_BREAK)
                    287:                                        break;
                    288:                                if (rtn == RTN_RETURN) {
                    289:                                        ctx->loop = this.outer;
                    290:                                        goto done;
                    291:                                }
                    292:                        }
                    293:                        ctx->loop = this.outer;
                    294:                        i += elem->u.u_loop.endloop;
                    295:                        break;
                    296:                    }
                    297: 
                    298:                case TY_WHILE:
                    299:                        while (1) {
                    300:                                char *errmsg = NULL;
                    301:                                int truth;
                    302:                                char *x;
                    303: 
                    304:                                if (!(x = evaluate_arg(ctx,
                    305:                                    &errmsg, &elem->call.args[0]))) {
                    306:                                        pr_err(ctx, errno, errmsg);
                    307:                                        FREE(ctx->mtype, errmsg);
                    308:                                        i += elem->u.u_while.endwhile;
                    309:                                        break;
                    310:                                }
                    311:                                truth = _tmpl_true(x);
                    312:                                FREE(ctx->mtype, x);
                    313:                                if (!truth)
                    314:                                        break;
                    315:                                rtn = _tmpl_execute_elems(ctx, elems, i + 1,
                    316:                                    elem->u.u_while.endwhile - 1);
                    317:                                if (rtn == RTN_BREAK)
                    318:                                        break;
                    319:                                if (rtn == RTN_RETURN)
                    320:                                        goto done;
                    321:                        }
                    322:                        i += elem->u.u_while.endwhile;
                    323:                        break;
                    324: 
                    325:                case TY_IF:
                    326:                case TY_ELIF:
                    327:                    {
                    328:                        char *errmsg = NULL;
                    329:                        int first = -1;
                    330:                        int num = 0;
                    331:                        int truth;
                    332:                        char *x;
                    333: 
                    334:                        if (!(x = evaluate_arg(ctx,
                    335:                            &errmsg, &elem->call.args[0]))) {
                    336:                                pr_err(ctx, errno, errmsg);
                    337:                                FREE(ctx->mtype, errmsg);
                    338:                                i += elem->u.u_if.endif;
                    339:                                break;
                    340:                        }
                    341:                        truth = _tmpl_true(x);
                    342:                        FREE(ctx->mtype, x);
                    343:                        if (truth) {
                    344:                                first = i + 1;
                    345:                                num = (elem->u.u_if.elsie != -1) ?
                    346:                                    elem->u.u_if.elsie - 1 :
                    347:                                    elem->u.u_if.endif - 1;
                    348:                        } else if (elem->u.u_if.elsie != -1) {
                    349:                                first = i + elem->u.u_if.elsie;
                    350:                                num = elem->u.u_if.endif - elem->u.u_if.elsie;
                    351:                        }
                    352:                        if (first != -1) {
                    353:                                rtn = _tmpl_execute_elems(ctx,
                    354:                                    elems, first, num);
                    355:                                if (rtn == RTN_BREAK
                    356:                                    || rtn == RTN_RETURN
                    357:                                    || rtn == RTN_CONTINUE)
                    358:                                        goto done;
                    359:                        }
                    360:                        i += elem->u.u_if.endif;
                    361:                        break;
                    362:                    }
                    363: 
                    364:                case TY_DEFINE:
                    365:                    {
                    366:                        char *errmsg = NULL;
                    367:                        char *name;
                    368: 
                    369:                        if (!(name = evaluate_arg(ctx,
                    370:                            &errmsg, &elem->call.args[0]))) {
                    371:                                pr_err(ctx, errno, errmsg);
                    372:                                FREE(ctx->mtype, errmsg);
                    373:                                i += elem->u.u_define.enddef;
                    374:                                break;
                    375:                        }
                    376: #ifdef TMPL_DEBUG
                    377:                        DBG("%s%6sDefining function \"%s\" as %d elems"
                    378:                            " starting at %d\n", indent, "", name,
                    379:                            elem->u.u_define.enddef - 1, i + 1);
                    380: #endif
                    381:                        if (_tmpl_set_func(ctx, name, elems + i + 1,
                    382:                            elem->u.u_define.enddef - 1) == -1) {
                    383:                                pr_err(ctx, errno, NULL);
                    384:                                FREE(ctx->mtype, name);
                    385:                                i += elem->u.u_define.enddef;
                    386:                                break;
                    387:                        }
                    388:                        FREE(ctx->mtype, name);
                    389:                        i += elem->u.u_define.enddef;
                    390:                        break;
                    391:                    }
                    392: 
                    393:                case TY_ENDLOOP:
                    394:                case TY_ENDWHILE:
                    395:                case TY_ELSE:
                    396:                case TY_ENDIF:
                    397:                case TY_ENDDEF:
                    398:                        break;
                    399: 
                    400:                case TY_BREAK:
                    401:                        rtn = RTN_BREAK;
                    402:                        goto done;
                    403: 
                    404:                case TY_CONTINUE:
                    405:                        rtn = RTN_CONTINUE;
                    406:                        goto done;
                    407: 
                    408:                case TY_RETURN:
                    409:                        rtn = RTN_RETURN;
                    410:                        goto done;
                    411: 
                    412:                default:
                    413:                        assert(0);
                    414:                }
                    415:        }
                    416: 
                    417:        /* If we finished all the elements, that's a normal return */
                    418:        rtn = RTN_NORMAL;
                    419: 
                    420: done:
                    421:        /* Debug */
                    422: #if TMPL_DEBUG
                    423:        DBG("%sDone, return is %s\n", indent, tmpl_rtnstr(rtn));
                    424: #endif
                    425: 
                    426:        /* Decrease nesting */
                    427:        ctx->depth--;
                    428: 
                    429:        /* Done */
                    430:        return (rtn);
                    431: }
                    432: 
                    433: /*
                    434:  * Invoke a function and return the result. The function is
                    435:  * assumed to not be a special built-in (eg, "@if").
                    436:  */
                    437: char *
                    438: _tmpl_invoke(struct tmpl_ctx *ctx, char **errmsgp, const struct func_call *call)
                    439: {
                    440:        char **args_copy = NULL;
                    441:        char **args = NULL;
                    442:        char *r = NULL;
                    443:        int i;
                    444: 
                    445:        /* Evaluate arguments; first function argument is the function name */
                    446:        if ((args = MALLOC(ctx->mtype,
                    447:            (1 + call->nargs) * sizeof(*args))) == NULL)
                    448:                return (NULL);
                    449:        memset(args, 0, (1 + call->nargs) * sizeof(*args));
                    450:        if ((args[0] = STRDUP(ctx->mtype, call->funcname)) == NULL)
                    451:                goto fail;
                    452:        for (i = 0; i < call->nargs; i++) {
                    453:                if ((args[i + 1] = evaluate_arg(ctx,
                    454:                    errmsgp, &call->args[i])) == NULL)
                    455:                        goto fail;
                    456:        }
                    457: 
                    458:        /* Save a copy of argument pointers so handlers can modify them */
                    459:        if ((args_copy = MALLOC(ctx->mtype,
                    460:            (1 + call->nargs) * sizeof(*args))) == NULL)
                    461:                return (NULL);
                    462:        memcpy(args_copy, args, (1 + call->nargs) * sizeof(*args));
                    463: 
                    464:        /* Invoke function, either run-time defined, built-in, or user */
                    465:        assert(call->type == TY_NORMAL);
                    466:        if ((i = _tmpl_find_func(ctx, call->funcname)) != -1) {
                    467:                r = tmpl_invoke_defined(ctx, &ctx->funcs[i],
                    468:                    errmsgp, 1 + call->nargs, args_copy);
                    469:        } else if (call->handler != NULL)
                    470:                r = (*call->handler)(ctx, errmsgp, 1 + call->nargs, args_copy);
                    471:        else
                    472:                r = (*ctx->handler)(ctx, errmsgp, 1 + call->nargs, args_copy);
                    473: 
                    474: fail:
                    475:        for (i = 0; i < 1 + call->nargs; i++)
                    476:                FREE(ctx->mtype, args[i]);
                    477:        FREE(ctx->mtype, args);
                    478:        FREE(ctx->mtype, args_copy);
                    479:        return (r);
                    480: }
                    481: 
                    482: /*
                    483:  * Invoke a run-time defined function and return the resulting
                    484:  * output as a string.
                    485:  */
                    486: static char *
                    487: tmpl_invoke_defined(struct tmpl_ctx *ctx, struct exec_func *func,
                    488:        char **errmsgp, int argc, char **argv)
                    489: {
                    490:        FILE *const output_save = ctx->output;
                    491:        char *rtn = NULL;
                    492:        int esave;
                    493: 
                    494:        /* Create string output buffer to capture output */
                    495:        if ((ctx->output = string_buf_output(ctx->mtype)) == NULL)
                    496:                goto fail;
                    497: 
                    498:        /* Invoke function using existing context */
                    499:        if (tmpl_invoke_defined2(ctx, func, errmsgp, argc, argv) == -1)
                    500:                goto fail;
                    501: 
                    502:        /* Return the resulting output as a string */
                    503:        rtn = string_buf_content(ctx->output, 1);
                    504: 
                    505: fail:
                    506:        /* Clean up and return */
                    507:        esave = errno;
                    508:        if (ctx->output != NULL)
                    509:                fclose(ctx->output);
                    510:        ctx->output = output_save;
                    511:        errno = esave;
                    512:        return (rtn);
                    513: }
                    514: 
                    515: /*
                    516:  * Invoke a runtime-defined function.
                    517:  */
                    518: static int
                    519: tmpl_invoke_defined2(struct tmpl_ctx *ctx,
                    520:        struct exec_func *func, char **errmsgp, int argc, char **argv)
                    521: {
                    522:        char **saved_vars;
                    523:        int rtn = 0;
                    524:        int i;
                    525: 
                    526:        /* Save variables argc and arg0, arg1, ... */
                    527:        if ((saved_vars = MALLOC(ctx->mtype,
                    528:            (argc + 1) * sizeof(*saved_vars))) == NULL)
                    529:                return (-1);
                    530:        memset(saved_vars, 0, (argc + 1) * sizeof(*saved_vars));
                    531:        for (i = 0; i <= argc; i++) {
                    532:                char namebuf[32];
                    533:                int j;
                    534: 
                    535:                if (i == argc)
                    536:                        strlcpy(namebuf, "argc", sizeof(namebuf));
                    537:                else
                    538:                        snprintf(namebuf, sizeof(namebuf), "arg%u", i);
                    539:                if ((j = _tmpl_find_var(ctx, namebuf)) != -1) {
                    540:                        if ((saved_vars[i] = STRDUP(ctx->mtype,
                    541:                            ctx->vars[j].value)) == NULL) {
                    542:                                while (--i >= 0)
                    543:                                        FREE(ctx->mtype, saved_vars[i]);
                    544:                                FREE(ctx->mtype, saved_vars);
                    545:                                return (-1);
                    546:                        }
                    547:                }
                    548:        }
                    549: 
                    550:        /* Set new values for those variables */
                    551:        for (i = 0; i <= argc; i++) {
                    552:                char namebuf[32], valbuf[32];
                    553:                char *argval;
                    554: 
                    555:                if (i == argc) {
                    556:                        strlcpy(namebuf, "argc", sizeof(namebuf));
                    557:                        snprintf(valbuf, sizeof(valbuf), "%u", argc);
                    558:                        argval = valbuf;
                    559:                } else {
                    560:                        snprintf(namebuf, sizeof(namebuf), "arg%u", i);
                    561:                        argval = argv[i];
                    562:                }
                    563:                if (tmpl_ctx_set_var(ctx, namebuf, argval) == -1) {
                    564:                        rtn = -1;
                    565:                        goto fail;
                    566:                }
                    567:        }
                    568: 
                    569:        /* Execute function elements */
                    570:        _tmpl_execute_elems(ctx, func->elems, 0, func->num_elems);
                    571: 
                    572: fail:
                    573:        /* Restore saved variables */
                    574:        for (i = 0; i <= argc; i++) {
                    575:                char argname[32];
                    576:                int j;
                    577: 
                    578:                if (i == argc)
                    579:                        strlcpy(argname, "argc", sizeof(argname));
                    580:                else
                    581:                        snprintf(argname, sizeof(argname), "arg%u", i);
                    582:                if ((j = _tmpl_find_var(ctx, argname)) == -1) {
                    583:                        FREE(ctx->mtype, saved_vars[i]);
                    584:                        continue; /* we get here only in the 'goto fail' case */
                    585:                }
                    586:                if (saved_vars[i] != NULL) {
                    587:                        FREE(ctx->mtype, ctx->vars[j].value);
                    588:                        ctx->vars[j].value = saved_vars[i];
                    589:                } else {
                    590:                        FREE(ctx->mtype, ctx->vars[j].name);
                    591:                        FREE(ctx->mtype, ctx->vars[j].value);
                    592:                        memmove(ctx->vars + j, ctx->vars + j + 1,
                    593:                            (--ctx->num_vars - j) * sizeof(*ctx->vars));
                    594:                }
                    595:        }
                    596:        FREE(ctx->mtype, saved_vars);
                    597:        return (rtn);
                    598: }
                    599: 
                    600: /*
                    601:  * Evaluate a function argument.
                    602:  */
                    603: static char *
                    604: evaluate_arg(struct tmpl_ctx *ctx, char **errmsgp, const struct func_arg *arg)
                    605: {
                    606:        if (arg->is_literal)
                    607:                return (STRDUP(ctx->mtype, arg->u.literal));
                    608:        else
                    609:                return (_tmpl_invoke(ctx, errmsgp, &arg->u.call));
                    610: }
                    611: 
                    612: /*
                    613:  * Output an error string.
                    614:  *
                    615:  * If "msg" is not NULL, use that, otherwise use strerror(error).
                    616:  */
                    617: static void
                    618: pr_err(struct tmpl_ctx *ctx, int error, const char *msg)
                    619: {
                    620:        const int errno_save = errno;
                    621:        char *cooked;
                    622: 
                    623:        /* Use strerror() error string if none more specific provided */
                    624:        if (msg == NULL)
                    625:                msg = strerror(errno);
                    626: 
                    627:        /* Format error string (if possible) and output it */
                    628:        if (ctx->errfmtr != NULL
                    629:            && (cooked = (*ctx->errfmtr)(ctx, msg)) != NULL) {
                    630:                (void)fputs(cooked, ctx->output);
                    631:                FREE(ctx->mtype, cooked);
                    632:        } else
                    633:                (void)fputs(msg, ctx->output);
                    634:        errno = errno_save;
                    635: }
                    636: 
                    637: /*
                    638:  * Determine truth of a string.
                    639:  */
                    640: int
                    641: _tmpl_true(const char *s)
                    642: {
                    643:        char *eptr;
                    644:        u_long val;
                    645: 
                    646:        val = strtol(s, &eptr, 0);
                    647:        return (*s != '\0' && *eptr == '\0' && val != 0);
                    648: }
                    649: 
                    650: #if TMPL_DEBUG
                    651: static const char *
                    652: tmpl_rtnstr(enum exec_rtn rtn)
                    653: {
                    654:        switch (rtn) {
                    655:        case RTN_NORMAL:
                    656:                return ("NORMAL");
                    657:        case RTN_BREAK:
                    658:                return ("BREAK");
                    659:        case RTN_CONTINUE:
                    660:                return ("CONTINUE");
                    661:        case RTN_RETURN:
                    662:                return ("RETURN");
                    663:        default:
                    664:                assert(0);
                    665:        }
                    666:        return (NULL);
                    667: }
                    668: #endif
                    669: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>