Blame agen5/functions.c

Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * @file functions.c
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  This module implements text functions.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * @addtogroup autogen
Packit Service 96b5d3
 * @{
Packit Service 96b5d3
 */
Packit Service 96b5d3
/*
Packit Service 96b5d3
 *  This file is part of AutoGen.
Packit Service 96b5d3
 *  AutoGen Copyright (C) 1992-2016 by Bruce Korb - all rights reserved
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * AutoGen is free software: you can redistribute it and/or modify it
Packit Service 96b5d3
 * under the terms of the GNU General Public License as published by the
Packit Service 96b5d3
 * Free Software Foundation, either version 3 of the License, or
Packit Service 96b5d3
 * (at your option) any later version.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * AutoGen is distributed in the hope that it will be useful, but
Packit Service 96b5d3
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 96b5d3
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Packit Service 96b5d3
 * See the GNU General Public License for more details.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * You should have received a copy of the GNU General Public License along
Packit Service 96b5d3
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service 96b5d3
 */
Packit Service 96b5d3
Packit Service 96b5d3
/*=macfunc CONTINUE
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  handler-proc:   Break
Packit Service 96b5d3
 *  load-proc:      Leave
Packit Service 96b5d3
 *  what:           Skip to end of a FOR or WHILE macro.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  desc:
Packit Service 96b5d3
 *  This will skip the remainder of the loop and start the next.
Packit Service 96b5d3
=*/
Packit Service 96b5d3
Packit Service 96b5d3
/*=macfunc BREAK
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  handler-proc:   Break
Packit Service 96b5d3
 *  load-proc:      Leave
Packit Service 96b5d3
 *  what:           Leave a FOR or WHILE macro
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  desc:
Packit Service 96b5d3
 *  This will unwind the loop context and resume after ENDFOR/ENDWHILE.
Packit Service 96b5d3
 *  Note that unless this happens to be the last iteration anyway,
Packit Service 96b5d3
 *  the (last-for?) function will never yield "#t".
Packit Service 96b5d3
=*/
Packit Service 96b5d3
macro_t *
Packit Service 96b5d3
mFunc_Break(templ_t * tpl, macro_t * mac)
Packit Service 96b5d3
{
Packit Service 96b5d3
    for_state_t * fst = curr_ivk_info->ii_for_data;
Packit Service 96b5d3
    int code = (mac->md_code == FTYP_BREAK) ? LOOP_JMP_BREAK : LOOP_JMP_NEXT;
Packit Service 96b5d3
    if (fst == NULL) {
Packit Service 96b5d3
        char const * which =
Packit Service 96b5d3
            (mac->md_code == FTYP_BREAK) ? BREAK_STR : CONTINUE_STR;
Packit Service 96b5d3
        AG_ABEND(aprf(BAD_BREAK_FMT, which));
Packit Service 96b5d3
    }
Packit Service 96b5d3
    fst += curr_ivk_info->ii_for_depth - 1;
Packit Service 96b5d3
Packit Service 96b5d3
    (void)tpl;
Packit Service 96b5d3
    (void)mac;
Packit Service 96b5d3
    longjmp(fst->for_env, code);
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * wrapper function for calling gen_block in a loop.
Packit Service 96b5d3
 * It sets up and handles the jump buffer, returning the jump result.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * @param[in,out] jbuf     the jump buffer
Packit Service 96b5d3
 * @param[in]     tpl      the new active template
Packit Service 96b5d3
 * @param[in]     mac      the looping macro
Packit Service 96b5d3
 * @param[in]     end_mac  pointer to the first macro after the block
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * @returns either LOOP_JMP_OKAY (0) or LOOP_JMP_BREAK (the caller should
Packit Service 96b5d3
 * exit the loop).
Packit Service 96b5d3
 */
Packit Service 96b5d3
LOCAL loop_jmp_type_t
Packit Service 96b5d3
call_gen_block(jmp_buf jbuf, templ_t * tpl, macro_t * mac, macro_t * end_mac)
Packit Service 96b5d3
{
Packit Service 96b5d3
    switch (setjmp(jbuf)) {
Packit Service 96b5d3
    case LOOP_JMP_OKAY: // 0
Packit Service 96b5d3
        gen_block(tpl, mac, end_mac);
Packit Service 96b5d3
        /* FALLTHROUGH */
Packit Service 96b5d3
Packit Service 96b5d3
    case LOOP_JMP_NEXT:
Packit Service 96b5d3
        return LOOP_JMP_OKAY;
Packit Service 96b5d3
Packit Service 96b5d3
    case LOOP_JMP_BREAK:
Packit Service 96b5d3
    default:
Packit Service 96b5d3
        return LOOP_JMP_BREAK;
Packit Service 96b5d3
    }
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/*=macfunc RETURN
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  handler-proc:
Packit Service 96b5d3
 *  load-proc:      Leave
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  what:           Leave an INVOKE-d (DEFINE) macro
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  desc:
Packit Service 96b5d3
 *  This will unwind looping constructs inside of a DEFINE-d macro and
Packit Service 96b5d3
 *  return to the invocation point.  The output files and diversions
Packit Service 96b5d3
 *  @i{are left alone}.  This means it is unwise to start diversions
Packit Service 96b5d3
 *  in a DEFINEd macro and RETURN from it before you have handled the
Packit Service 96b5d3
 *  diversion.  Unless you are careful.  Here is some rope for you.
Packit Service 96b5d3
 *  Please be careful using it.
Packit Service 96b5d3
=*/
Packit Service 96b5d3
macro_t *
Packit Service 96b5d3
mFunc_Return(templ_t * tpl, macro_t * mac)
Packit Service 96b5d3
{
Packit Service 96b5d3
    (void)tpl;
Packit Service 96b5d3
    (void)mac;
Packit Service 96b5d3
    free_for_context(INT_MAX);
Packit Service 96b5d3
    if (curr_ivk_info->ii_prev == NULL)
Packit Service 96b5d3
        AG_ABEND_IN(tpl, mac, RETURN_FROM_NOWHERE);
Packit Service 96b5d3
    longjmp(curr_ivk_info->ii_env, 1);
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * Generate a block with a new template context.  It may be either
Packit Service 96b5d3
 * an @code{INCLUDE}-d template or a user @code{DEFINE}-d macro.
Packit Service 96b5d3
 * If @code{gen_block} returns with a long jump, the long jump value
Packit Service 96b5d3
 * is ignored.  It was terminated early with a @code{RETURN}.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * @param[in] tpl new template block (included or invoked).
Packit Service 96b5d3
 */
Packit Service 96b5d3
LOCAL void
Packit Service 96b5d3
gen_new_block(templ_t * tpl)
Packit Service 96b5d3
{
Packit Service 96b5d3
    templ_t *   oldt = current_tpl;
Packit Service 96b5d3
    ivk_info_t    ii = IVK_INFO_INITIALIZER(curr_ivk_info);
Packit Service 96b5d3
Packit Service 96b5d3
    curr_ivk_info = ⅈ
Packit Service 96b5d3
Packit Service 96b5d3
    if (setjmp(ii.ii_env) == 0) {
Packit Service 96b5d3
        macro_t * m = tpl->td_macros;
Packit Service 96b5d3
        gen_block(tpl, m, m + tpl->td_mac_ct);
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    current_tpl   = oldt;
Packit Service 96b5d3
    curr_ivk_info = ii.ii_prev;
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * Validate the context for leaving early.  @code{FOR} and @code{WHILE} loops
Packit Service 96b5d3
 * may leave an interation early with @code{CONTINUE} or @code{BREAK}.
Packit Service 96b5d3
 * @code{DEFINE}-d macros and @code{INCLUDE}-d files may leave early with
Packit Service 96b5d3
 * @code{RETURN}.  Loops may not be left early from an @code{INVOKE}-d macro
Packit Service 96b5d3
 * or an @code{INCLUDE}-d template.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * This load function handles @code{BREAK}, @code{CONTINUE} and @code{RETURN}.
Packit Service 96b5d3
 * It is always defined, so it must check for itself whether the
Packit Service 96b5d3
 * context is correct or not.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  @param tpl     template being loaded
Packit Service 96b5d3
 *  @param mac     the macro descriptor
Packit Service 96b5d3
 *  @param p_scan  the input text scanning pointer
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  @returns the macro table entry after mac
Packit Service 96b5d3
 */
Packit Service 96b5d3
macro_t *
Packit Service 96b5d3
mLoad_Leave(templ_t * tpl, macro_t * mac, char const ** p_scan)
Packit Service 96b5d3
{
Packit Service 96b5d3
    (void) tpl;
Packit Service 96b5d3
Packit Service 96b5d3
    if (mac->md_code == FTYP_RETURN) {
Packit Service 96b5d3
        /*
Packit Service 96b5d3
         * Check returns at load time.  "break" and "continue" at
Packit Service 96b5d3
         * instantiation time.
Packit Service 96b5d3
         */
Packit Service 96b5d3
        if (! defining_macro && (include_depth == 0))
Packit Service 96b5d3
            (void)mLoad_Bogus(tpl, mac, p_scan);
Packit Service 96b5d3
    }
Packit Service 96b5d3
    return mac + 1;
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/*=macfunc INCLUDE
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  what:   Read in and emit a template block
Packit Service 96b5d3
 *  handler_proc:
Packit Service 96b5d3
 *  load_proc:    Expr
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  desc:
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  The entire contents of the named file is inserted at this point.
Packit Service 96b5d3
 *  The contents of the file are processed for macro expansion.  The
Packit Service 96b5d3
 *  arguments are eval-ed, so you may compute the name of the file to
Packit Service 96b5d3
 *  be included.  The included file must not contain any incomplete
Packit Service 96b5d3
 *  function blocks.  Function blocks are template text beginning with
Packit Service 96b5d3
 *  any of the macro functions @samp{CASE}, @samp{DEFINE}, @samp{FOR},
Packit Service 96b5d3
 *  @samp{IF} and @samp{WHILE}; extending through their respective
Packit Service 96b5d3
 *  terminating macro functions.
Packit Service 96b5d3
=*/
Packit Service 96b5d3
macro_t *
Packit Service 96b5d3
mFunc_Include(templ_t * tpl, macro_t * mac)
Packit Service 96b5d3
{
Packit Service 96b5d3
    bool         allocated_name;
Packit Service 96b5d3
    char const * fname = eval_mac_expr(&allocated_name);
Packit Service 96b5d3
Packit Service 96b5d3
    include_depth++;
Packit Service 96b5d3
    if (*fname != NUL) {
Packit Service 96b5d3
        templ_t * new_tpl  = tpl_load(fname, tpl->td_file);
Packit Service 96b5d3
        macro_t * last_mac = new_tpl->td_macros + (new_tpl->td_mac_ct - 1);
Packit Service 96b5d3
Packit Service 96b5d3
        if (last_mac->md_code == FTYP_TEXT) {
Packit Service 96b5d3
            /*
Packit Service 96b5d3
             *  Strip off trailing white space from included templates
Packit Service 96b5d3
             */
Packit Service 96b5d3
            char * pz = new_tpl->td_text + last_mac->md_txt_off;
Packit Service 96b5d3
            char * pe = SPN_WHITESPACE_BACK(pz, pz);
Packit Service 96b5d3
Packit Service 96b5d3
            /*
Packit Service 96b5d3
             *  IF there is no text left, remove the macro entirely
Packit Service 96b5d3
             */
Packit Service 96b5d3
            if (pe > pz) {
Packit Service 96b5d3
                *pe = NUL;
Packit Service 96b5d3
            } else {
Packit Service 96b5d3
                new_tpl->td_mac_ct--;
Packit Service 96b5d3
            }
Packit Service 96b5d3
        }
Packit Service 96b5d3
Packit Service 96b5d3
        if (OPT_VALUE_TRACE > TRACE_DEBUG_MESSAGE) {
Packit Service 96b5d3
            fprintf(trace_fp, TRACE_FN_INC_TPL, new_tpl->td_file);
Packit Service 96b5d3
            if (OPT_VALUE_TRACE == TRACE_EVERYTHING)
Packit Service 96b5d3
                fprintf(trace_fp, TRACE_FN_INC_LINE, current_tpl->td_file,
Packit Service 96b5d3
                        mac->md_line);
Packit Service 96b5d3
        }
Packit Service 96b5d3
Packit Service 96b5d3
        gen_new_block(new_tpl);
Packit Service 96b5d3
        tpl_unload(new_tpl);
Packit Service 96b5d3
        current_tpl = tpl;
Packit Service 96b5d3
    }
Packit Service 96b5d3
    include_depth--;
Packit Service 96b5d3
Packit Service 96b5d3
    if (allocated_name)
Packit Service 96b5d3
        AGFREE(fname);
Packit Service 96b5d3
Packit Service 96b5d3
    return mac + 1;
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/*=macfunc UNKNOWN
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  what:  Either a user macro or a value name.
Packit Service 96b5d3
 *  handler_proc:
Packit Service 96b5d3
 *  load_proc:
Packit Service 96b5d3
 *  unnamed:
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  desc:
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  The macro text has started with a name not known to AutoGen.  If, at run
Packit Service 96b5d3
 *  time, it turns out to be the name of a defined macro, then that macro is
Packit Service 96b5d3
 *  invoked.  If it is not, then it is a conditional expression that is
Packit Service 96b5d3
 *  evaluated only if the name is defined at the time the macro is invoked.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  You may not specify @code{UNKNOWN} explicitly.
Packit Service 96b5d3
=*/
Packit Service 96b5d3
macro_t *
Packit Service 96b5d3
mFunc_Unknown(templ_t * pT, macro_t * pMac)
Packit Service 96b5d3
{
Packit Service 96b5d3
    templ_t * pInv = find_tpl(pT->td_text + pMac->md_name_off);
Packit Service 96b5d3
    if (pInv != NULL) {
Packit Service 96b5d3
        if (OPT_VALUE_TRACE >= TRACE_EVERYTHING)
Packit Service 96b5d3
            fprintf(trace_fp, TRACE_FN_REMAPPED, TRACE_FN_REMAP_INVOKE,
Packit Service 96b5d3
                    pMac->md_code, pT->td_file, pMac->md_line);
Packit Service 96b5d3
        pMac->md_code    = FTYP_DEFINE;
Packit Service 96b5d3
        pMac->md_pvt = VOIDP(pInv);
Packit Service 96b5d3
        parse_mac_args(pT, pMac);
Packit Service 96b5d3
        return mFunc_Define(pT, pMac);
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    if (OPT_VALUE_TRACE >= TRACE_EVERYTHING) {
Packit Service 96b5d3
        fprintf(trace_fp, TRACE_FN_REMAPPED, TRACE_FN_REMAP_EXPR,
Packit Service 96b5d3
                pMac->md_code, pT->td_file, pMac->md_line);
Packit Service 96b5d3
        fprintf(trace_fp, TRACE_FN_REMAP_BASE,
Packit Service 96b5d3
                pT->td_text + pMac->md_name_off);
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    pMac->md_code = FTYP_EXPR;
Packit Service 96b5d3
    if (pMac->md_txt_off == 0) {
Packit Service 96b5d3
        pMac->md_res = EMIT_VALUE;
Packit Service 96b5d3
Packit Service 96b5d3
    } else {
Packit Service 96b5d3
        char * pzExpr = pT->td_text + pMac->md_txt_off;
Packit Service 96b5d3
        switch (*pzExpr) {
Packit Service 96b5d3
        case ';':
Packit Service 96b5d3
        case '(':
Packit Service 96b5d3
            pMac->md_res = EMIT_EXPRESSION;
Packit Service 96b5d3
            break;
Packit Service 96b5d3
Packit Service 96b5d3
        case '`':
Packit Service 96b5d3
            pMac->md_res = EMIT_SHELL;
Packit Service 96b5d3
            span_quote(pzExpr);
Packit Service 96b5d3
            break;
Packit Service 96b5d3
Packit Service 96b5d3
        case '"':
Packit Service 96b5d3
        case '\'':
Packit Service 96b5d3
            span_quote(pzExpr);
Packit Service 96b5d3
            /* FALLTHROUGH */
Packit Service 96b5d3
Packit Service 96b5d3
        default:
Packit Service 96b5d3
            pMac->md_res = EMIT_STRING;
Packit Service 96b5d3
        }
Packit Service 96b5d3
Packit Service 96b5d3
        if (OPT_VALUE_TRACE >= TRACE_EVERYTHING)
Packit Service 96b5d3
            fprintf(trace_fp, TRACE_UNKNOWN_FMT, pMac->md_res, pzExpr);
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    return mFunc_Expr(pT, pMac);
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
Packit Service 96b5d3
/*=macfunc BOGUS
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  what:  Out-of-context or unknown functions are bogus.
Packit Service 96b5d3
 *  handler_proc:
Packit Service 96b5d3
 *  load_proc:
Packit Service 96b5d3
 *  unnamed:
Packit Service 96b5d3
=*/
Packit Service 96b5d3
macro_t *
Packit Service 96b5d3
mFunc_Bogus(templ_t * pT, macro_t * pMac)
Packit Service 96b5d3
{
Packit Service 96b5d3
    char * pz = aprf(FN_BOGUS_FMT, pMac->md_code,
Packit Service 96b5d3
                     (pMac->md_code < FUNC_CT)
Packit Service 96b5d3
                     ? ag_fun_names[ pMac->md_code ]
Packit Service 96b5d3
                     : FN_BOGUS_HUH);
Packit Service 96b5d3
Packit Service 96b5d3
    AG_ABEND_IN(pT, pMac, pz);
Packit Service 96b5d3
    /* NOTREACHED */
Packit Service 96b5d3
    return pMac;
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
Packit Service 96b5d3
/*=macfunc TEXT
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  what:  A block of text to be emitted.
Packit Service 96b5d3
 *  handler_proc:
Packit Service 96b5d3
 *  unnamed:
Packit Service 96b5d3
=*/
Packit Service 96b5d3
macro_t *
Packit Service 96b5d3
mFunc_Text(templ_t * pT, macro_t * pMac)
Packit Service 96b5d3
{
Packit Service 96b5d3
    fputs(pT->td_text + pMac->md_txt_off, cur_fpstack->stk_fp);
Packit Service 96b5d3
    fflush(cur_fpstack->stk_fp);
Packit Service 96b5d3
    return pMac + 1;
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
Packit Service 96b5d3
/*=macfunc COMMENT
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  what:  A block of comment to be ignored
Packit Service 96b5d3
 *  load_proc:
Packit Service 96b5d3
 *  alias: "#"
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  desc:
Packit Service 96b5d3
 *    This function can be specified by the user, but there will
Packit Service 96b5d3
 *    never be a situation where it will be invoked at emit time.
Packit Service 96b5d3
 *    The macro is actually removed from the internal representation.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *    If the native macro name code is @code{#}, then the
Packit Service 96b5d3
 *    entire macro function is treated as a comment and ignored.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *    @example
Packit Service 96b5d3
 *    [+ # say what you want, but no '+' before any ']' chars +]
Packit Service 96b5d3
 *    @end example
Packit Service 96b5d3
=*/
Packit Service 96b5d3
macro_t *
Packit Service 96b5d3
mLoad_Comment(templ_t * tpl, macro_t * mac, char const ** p_scan)
Packit Service 96b5d3
{
Packit Service 96b5d3
    (void)tpl;
Packit Service 96b5d3
    (void)p_scan;
Packit Service 96b5d3
    memset(VOIDP(mac), 0, sizeof(*mac));
Packit Service 96b5d3
    return mac;
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 *  The default (unknown) load function.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  Move any text into the text offset field.  This macro will change to
Packit Service 96b5d3
 *  either INVOKE or an expression function, depending on whether or not a
Packit Service 96b5d3
 *  DEFINE macro corresponds to the name.  This is determined at instantiation
Packit Service 96b5d3
 *  time.  This is used as the default load mechanism.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  @param tpl     template being loaded
Packit Service 96b5d3
 *  @param mac     the macro descriptor
Packit Service 96b5d3
 *  @param p_scan  the input text scanning pointer
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  @returns the macro table entry after mac
Packit Service 96b5d3
 */
Packit Service 96b5d3
macro_t *
Packit Service 96b5d3
mLoad_Unknown(templ_t * tpl, macro_t * mac, char const ** unused)
Packit Service 96b5d3
{
Packit Service 96b5d3
    char const * scan;
Packit Service 96b5d3
    ssize_t      src_len = (ssize_t)mac->md_res; /* macro len  */
Packit Service 96b5d3
    (void)unused;
Packit Service 96b5d3
Packit Service 96b5d3
    if (src_len <= 0)
Packit Service 96b5d3
        goto return_emtpy_expr;
Packit Service 96b5d3
Packit Service 96b5d3
    scan = (char const *)mac->md_txt_off; /* macro text */
Packit Service 96b5d3
Packit Service 96b5d3
    switch (*scan) {
Packit Service 96b5d3
    case ';':
Packit Service 96b5d3
    {
Packit Service 96b5d3
        char const * start = scan;
Packit Service 96b5d3
Packit Service 96b5d3
        /*
Packit Service 96b5d3
         *  Strip off scheme comments
Packit Service 96b5d3
         */
Packit Service 96b5d3
        do  {
Packit Service 96b5d3
            scan = strchr(scan, NL);
Packit Service 96b5d3
            if (scan == NULL)
Packit Service 96b5d3
                goto return_emtpy_expr;
Packit Service 96b5d3
Packit Service 96b5d3
            scan = SPN_WHITESPACE_CHARS(scan);
Packit Service 96b5d3
            if (*scan == NUL)
Packit Service 96b5d3
                goto return_emtpy_expr;
Packit Service 96b5d3
Packit Service 96b5d3
            src_len -= scan - start;
Packit Service 96b5d3
            if (src_len <= 0)
Packit Service 96b5d3
                goto return_emtpy_expr;
Packit Service 96b5d3
Packit Service 96b5d3
            start = scan;
Packit Service 96b5d3
        } while (*scan == ';');
Packit Service 96b5d3
        break;
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    case '[':
Packit Service 96b5d3
    case '.':
Packit Service 96b5d3
    {
Packit Service 96b5d3
        /*
Packit Service 96b5d3
         *  We are going to recopy the definition name, this time as a
Packit Service 96b5d3
         *  canonical name (i.e. including '[', ']' and '.'  characters,
Packit Service 96b5d3
         *  but with all blanks squeezed out)
Packit Service 96b5d3
         */
Packit Service 96b5d3
        char * cname     = tpl->td_text + mac->md_name_off;
Packit Service 96b5d3
        size_t cname_len = strlen(cname);
Packit Service 96b5d3
Packit Service 96b5d3
        /*
Packit Service 96b5d3
         *  Move back the source pointer.  We may have skipped blanks,
Packit Service 96b5d3
         *  so skip over however many first, then back up over the name.
Packit Service 96b5d3
         *  We have found a name, so we won't back up past the start.
Packit Service 96b5d3
         */
Packit Service 96b5d3
        while (IS_WHITESPACE_CHAR(scan[-1])) scan--, src_len++;
Packit Service 96b5d3
        scan    -= cname_len;
Packit Service 96b5d3
        src_len += (ssize_t)cname_len;
Packit Service 96b5d3
Packit Service 96b5d3
        /*
Packit Service 96b5d3
         *  Now copy over the full canonical name.  Check for errors.
Packit Service 96b5d3
         *  Advance the scan pointer to just past the name we've copied.
Packit Service 96b5d3
         */
Packit Service 96b5d3
        {
Packit Service 96b5d3
            ssize_t rem_len = canonical_name(cname, scan, (int)src_len);
Packit Service 96b5d3
            if (rem_len > src_len)
Packit Service 96b5d3
                AG_ABEND_IN(tpl, mac, LD_UNKNOWN_INVAL_DEF);
Packit Service 96b5d3
Packit Service 96b5d3
            scan   += src_len - rem_len;
Packit Service 96b5d3
            src_len = (ssize_t)rem_len;
Packit Service 96b5d3
        }
Packit Service 96b5d3
Packit Service 96b5d3
        /*
Packit Service 96b5d3
         *  Where we are stashing text ("td_scan") gets set to just past the
Packit Service 96b5d3
         *  NUL byte terminating the name.  "cname" is now longer than before.
Packit Service 96b5d3
         */
Packit Service 96b5d3
        tpl->td_scan = cname + strlen(cname) + 1;
Packit Service 96b5d3
        if (src_len <= 0)
Packit Service 96b5d3
            goto return_emtpy_expr;
Packit Service 96b5d3
        break;
Packit Service 96b5d3
    }
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    /*
Packit Service 96b5d3
     *  Copy the expression (the remaining text)
Packit Service 96b5d3
     */
Packit Service 96b5d3
    {
Packit Service 96b5d3
        char * dest = tpl->td_scan; /* next text dest   */
Packit Service 96b5d3
        mac->md_txt_off = (uintptr_t)(dest - tpl->td_text);
Packit Service 96b5d3
        mac->md_res = 0;
Packit Service 96b5d3
        memcpy(dest, scan, (size_t)src_len);
Packit Service 96b5d3
        dest       += src_len;
Packit Service 96b5d3
        *(dest++)   = NUL;
Packit Service 96b5d3
        *dest       = NUL; /* double terminate */
Packit Service 96b5d3
        tpl->td_scan = dest;
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    return mac + 1;
Packit Service 96b5d3
Packit Service 96b5d3
 return_emtpy_expr:
Packit Service 96b5d3
    mac->md_txt_off = 0;
Packit Service 96b5d3
    mac->md_res     = 0;
Packit Service 96b5d3
    return mac + 1;
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 *  Some functions are known to AutoGen, but invalid out of context.
Packit Service 96b5d3
 *  For example, ELIF, ELSE and ENDIF are all known to AutoGen.
Packit Service 96b5d3
 *  However, the load function pointer for those functions points
Packit Service 96b5d3
 *  here, until an "IF" function is encountered.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  @param tpl     template being loaded
Packit Service 96b5d3
 *  @param mac     the macro descriptor
Packit Service 96b5d3
 *  @param p_scan  the input text scanning pointer
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  @returns the macro table entry after mac
Packit Service 96b5d3
 */
Packit Service 96b5d3
macro_t *
Packit Service 96b5d3
mLoad_Bogus(templ_t * tpl, macro_t * mac, char const ** p_scan)
Packit Service 96b5d3
{
Packit Service 96b5d3
    char const * pzSrc = (char const *)mac->md_txt_off; /* macro text */
Packit Service 96b5d3
    char const * pzMac;
Packit Service 96b5d3
Packit Service 96b5d3
    char z[ 64 ];
Packit Service 96b5d3
    (void)p_scan;
Packit Service 96b5d3
Packit Service 96b5d3
    if (pzSrc != NULL) {
Packit Service 96b5d3
        z[0] = ':';
Packit Service 96b5d3
        z[1] = z[2] = ' ';
Packit Service 96b5d3
        strncpy(z+3, pzSrc, (size_t)60);
Packit Service 96b5d3
        z[63] = NUL;
Packit Service 96b5d3
        pzSrc = z;
Packit Service 96b5d3
    }
Packit Service 96b5d3
    else
Packit Service 96b5d3
        pzSrc = zNil;
Packit Service 96b5d3
Packit Service 96b5d3
    {
Packit Service 96b5d3
        int ix = mac->md_code;
Packit Service 96b5d3
        if ((unsigned)ix >= FUNC_CT)
Packit Service 96b5d3
            ix = 0;
Packit Service 96b5d3
Packit Service 96b5d3
        pzMac = ag_fun_names[ ix ];
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    pzSrc = aprf(LD_BOGUS_UNKNOWN, tpl->td_file, mac->md_line, pzMac, pzSrc);
Packit Service 96b5d3
Packit Service 96b5d3
    AG_ABEND_IN(tpl, mac, pzSrc);
Packit Service 96b5d3
    /* NOTREACHED */
Packit Service 96b5d3
    return NULL;
Packit Service 96b5d3
}
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * @}
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * Local Variables:
Packit Service 96b5d3
 * mode: C
Packit Service 96b5d3
 * c-file-style: "stroustrup"
Packit Service 96b5d3
 * indent-tabs-mode: nil
Packit Service 96b5d3
 * End:
Packit Service 96b5d3
 * end of agen5/functions.c */