Annotation of embedaddon/libpdel/tmpl/tmpl_exec.c, revision 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>