/**
* @file funcDef.c
*
* This module implements the DEFINE text function.
*
* @addtogroup autogen
* @{
*/
/*
* This file is part of AutoGen.
* AutoGen Copyright (C) 1992-2016 by Bruce Korb - all rights reserved
*
* AutoGen is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AutoGen is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
typedef int (tCmpProc)(const void *, const void *);
typedef struct def_list def_list_t;
struct def_list {
def_ent_t de;
char * pzExpr;
};
/* = = = START-STATIC-FORWARD = = = */
static int
order_def_list(const void * p1, const void * p2);
static def_list_t *
link_twins(def_list_t * pDL, def_list_t * pNext, int * pCt);
static uint_t
count_named_values(templ_t * pT, macro_t * mac);
static char *
gather_assigned_value(char * pzScan, def_list_t * pDL);
static void
fill_in_values(def_list_t * pDL, char * pzScan, templ_t * pT, macro_t * mac);
static void
prep_invoke_args(macro_t * mac);
static void
build_defs(int def_ct, def_list_t * def_list);
static templ_t *
new_template(templ_t * base_tpl, macro_t * mac, char const * scan);
static void
load_define_tpl(templ_t * tpl, char const ** ppzScan);
/* = = = END-STATIC-FORWARD = = = */
static int
order_def_list(const void * p1, const void * p2)
{
def_ent_t * pDL1 = (def_ent_t *)p1;
def_ent_t * pDL2 = (def_ent_t *)p2;
int cmp = streqvcmp(pDL1->de_name, pDL2->de_name);
/*
* IF the names are the same, then we order them based on which name
* appears first. Do not reorder entries with the same name.
*/
if (cmp == 0)
cmp = (int)(pDL1->de_name - pDL2->de_name);
return cmp;
}
static def_list_t *
link_twins(def_list_t * pDL, def_list_t * pNext, int * pCt)
{
def_list_t * pN;
int ct = *pCt;
int idx = 1;
pDL->de.de_twin = &(pNext->de);
pNext->de.de_ptwin = &(pDL->de);
for (;;) {
pNext->de.de_index = idx++;
pN = pNext + 1; /* We return this, valid or not */
if (--ct <= 0) /* count each successive twin */
break;
if (streqvcmp(pNext->de.de_name, pN->de.de_name) != 0)
break;
/*
* We have found another twin. Link it in and advance
*/
pNext->de.de_twin = &(pN->de);
pN->de.de_ptwin = &(pNext->de);
pNext = pN;
}
pDL->de.de_etwin = &(pNext->de);
pNext->de.de_twin = NULL; /* NULL terminated list */
pDL->de.de_ptwin = NULL; /* NULL terminated list */
*pCt = ct;
pDL->de.de_next = NULL; /* in case ct == 0 */
return pN; /* If ct is zero, then this is invalid */
}
static uint_t
count_named_values(templ_t * pT, macro_t * mac)
{
char * pzScan = pT->td_text + mac->md_txt_off;
uint_t ct = 0;
while (*pzScan != NUL) {
ct++;
if (! IS_VAR_FIRST_CHAR(*pzScan)) {
fprintf(stderr, NAMED_VALUES_WHERE, ct, pzScan);
AG_ABEND_IN(pT, mac, NAMED_VALUES_NO_NAME);
}
pzScan = SPN_VALUE_NAME_CHARS(pzScan);
pzScan = SPN_WHITESPACE_CHARS(pzScan);
if (*pzScan != '=')
continue;
pzScan = SPN_WHITESPACE_CHARS(pzScan+1);
pzScan = (char *)skip_expr(pzScan, strlen(pzScan));
pzScan = SPN_WHITESPACE_CHARS(pzScan);
}
return ct;
}
static char *
gather_assigned_value(char * pzScan, def_list_t * pDL)
{
pzScan = SPN_WHITESPACE_CHARS(pzScan);
strtransform(pDL->de.de_name, pDL->de.de_name);
pDL->pzExpr = pzScan;
pDL->de.de_type = VALTYP_TEXT;
pzScan = (char *)skip_expr(pzScan, strlen(pzScan));
/*
* Figure out what kind of expression we have
*/
switch (*pDL->pzExpr) {
case ';':
case '(':
/*
* These expressions will need evaluation
*/
break;
case '`':
{
char * pz;
/*
* Process the quoted string, but leave a '`' marker, too
*/
AGDUPSTR(pz, pDL->pzExpr, "macro arg expr");
span_quote(pz);
strcpy(pDL->pzExpr+1, pz);
AGFREE(pz);
break;
}
case '"':
case '\'':
/*
* Process the quoted strings now
*/
if ((pzScan - pDL->pzExpr) < 24) {
char * pz = (char *)AGALOC(24, "quoted string");
memcpy(VOIDP(pz), pDL->pzExpr, (size_t)(pzScan - pDL->pzExpr));
pDL->pzExpr = pz;
}
span_quote(pDL->pzExpr);
/* FALLTHROUGH */
default:
/*
* Default: the raw sequence of characters is the value
*/
pDL->de.de_val.dvu_text = pDL->pzExpr;
pDL->pzExpr = NULL;
}
return pzScan;
}
static void
fill_in_values(def_list_t * pDL, char * pzScan, templ_t * pT, macro_t * mac)
{
for (;; pDL++ ) {
pDL->de.de_name = pzScan;
pzScan = SPN_VALUE_NAME_CHARS(pzScan);
switch (*pzScan) {
case NUL:
pDL->de.de_val.dvu_text = (char *)zNil;
return;
default:
AG_ABEND_IN(pT, mac, FILL_IN_VAL_NO_ASSIGN);
case ' ': case TAB: case NL: case '\f':
*(pzScan++) = NUL;
pzScan = SPN_WHITESPACE_CHARS(pzScan);
/*
* The name was separated by space, but has no value
*/
if (*pzScan != '=') {
pDL->de.de_val.dvu_text = (char *)zNil;
if (*pzScan == NUL)
return;
continue;
}
/* FALLTHROUGH */
case '=':
*(pzScan++) = NUL;
}
/*
* When we arrive here, we have just clobbered a '=' char.
* Now we have gather up the assigned value.
*/
pzScan = gather_assigned_value(pzScan, pDL);
/*
* IF the next char is NUL, we are done.
* OTHERWISE, the next character must be a space
*/
if (*pzScan == NUL)
break;
if (! IS_WHITESPACE_CHAR(*pzScan))
AG_ABEND_IN(pT, mac, FILL_IN_VAL_NO_SEP);
/*
* Terminate the string value and skip over any additional space
*/
*(pzScan++) = NUL;
pzScan = SPN_WHITESPACE_CHARS(pzScan);
}
}
/*
* parse_mac_args
*
* This routine is called just before the first call to mFunc_Define
* for a particular macro invocation. It scans the text of the invocation
* for name-value assignments that are only to live for the duration
* of the processing of the user defined macro.
*/
LOCAL void
parse_mac_args(templ_t * pT, macro_t * mac)
{
char * pzScan = pT->td_text + mac->md_txt_off;
uint_t ct;
def_list_t * pDL;
def_list_t * pN;
/*
* If there is no argument text, then the arg count is zero.
*/
if (mac->md_txt_off == 0) {
mac->md_res = 0;
return;
}
ct = count_named_values(pT, mac);
/*
* The result is zero if we don't have any
*/
mac->md_sib_idx = (int)ct;
if (ct == 0) {
mac->md_txt_off = 0;
mac->md_res = 0;
return;
}
/*
* Allocate the array of definition descriptors
*/
pzScan = pT->td_text + mac->md_txt_off;
pDL = (def_list_t *)AGALOC(ct * sizeof(def_list_t), "array of def desc");
memset(VOIDP(pDL), 0, ct * sizeof(def_list_t));
mac->md_res = (uintptr_t)pDL;
/*
* Fill in the array of value assignments
*/
fill_in_values(pDL, pzScan, pT, mac);
if (ct > 1) {
/*
* There was more than one value assignment.
* Sort them just so we know the siblings are together.
* Order is preserved by comparing string addresses,
* if the strings compare equal.
*/
pDL = (def_list_t *)mac->md_res;
qsort(VOIDP(pDL), (size_t)ct, sizeof(def_list_t), order_def_list);
/*
* Now, link them all together. Singly linked list.
*/
for (;;) {
if (--ct == 0) {
pDL->de.de_next = NULL;
break;
}
pN = pDL + 1;
/*
* IF the next entry has the same name,
* THEN it is a "twin". Link twins on the twin list.
*/
if (streqvcmp(pDL->de.de_name, pN->de.de_name) == 0) {
pN = link_twins(pDL, pN, (int *)&ct);
if (ct <= 0)
break; /* pN is now invalid */
}
pDL->de.de_next = &(pN->de);
pDL = pN;
}
}
}
/**
* prepare the args for INVOKE macro.
* See if there's any text following the name of the DEFINE macro to invoke.
* If there is, then set up the arguments now so it's easy to deal with
* next time around. The name of the macro to invoke may be dynamic.
* "skip_expr" skips over either a name or a scheme expression that
* is supposed to yield a name.
*
* @param mac the macro structure describing the invocation
*/
static void
prep_invoke_args(macro_t * mac)
{
char * pzText;
templ_t * pT = current_tpl;
if (mac->md_txt_off == 0)
AG_ABEND_IN(pT, mac, PREP_INVOKE_NO_NAME);
mac->md_name_off = mac->md_txt_off;
pzText = pT->td_text + mac->md_txt_off;
pzText = (char *)skip_expr(pzText, strlen(pzText));
/*
* IF there is no more text,
* THEN there are no arguments
*/
if (*pzText == NUL) {
mac->md_txt_off = 0;
mac->md_res = 0;
}
/*
* OTHERWISE, skip to the start of the text and process
* the arguments to the macro
*/
else {
if (! IS_WHITESPACE_CHAR(*pzText))
AG_ABEND_IN(pT, mac, PREP_INVOKE_NO_SEP);
*pzText = NUL;
pzText = SPN_WHITESPACE_CHARS(pzText + 1);
mac->md_txt_off = (uintptr_t)(pzText - pT->td_text);
parse_mac_args(pT, mac);
current_tpl = pT;
}
}
/*=macfunc DEBUG
*
* handler-proc:
* load-proc:
*
* what: Print debug message to trace output
* desc:
*
* If the tracing level is at "debug-message" or above
* (@pxref{autogen trace}), this macro prints a debug message to trace
* output. This message is not evaluated. This macro can also be used to
* set useful debugger breakpoints. By inserting [+DEBUG n+] into your
* template, you can set a debugger breakpoint on the #n case element
* below (in the AutoGen source) and step through the processing of
* interesting parts of your template.
*
* To be useful, you have to have access to the source tree where autogen
* was built and the template being processed. The definitions are also
* helpful, but not crucial. Please contact the author if you think you
* might actually want to use this.
=*/
macro_t *
mFunc_Debug(templ_t * pT, macro_t * mac)
{
static int dummy = 0;
char const * pz = pT->td_text + mac->md_txt_off;
int for_index = (curr_ivk_info->ii_for_depth <= 0)
? -1
: curr_ivk_info->ii_for_data[ curr_ivk_info->ii_for_depth-1].for_index;
fprintf(trace_fp, FN_DEBUG, pz, for_index);
/*
* The case element values were chosen to thwart most
* optimizers that might be too bright for its own good.
* (`dummy' is write-only and could be ignored)
*/
do {
if (IS_DEC_DIGIT_CHAR(*pz)) {
for_index = atoi(pz);
break;
}
} while (*(pz++) != NUL);
if (for_index < 0)
for_index = -1;
switch (for_index) {
case -1: dummy = 'X'; break;
case 0: dummy = 'A'; break;
case 1: dummy = 'u'; break;
case 2: dummy = 't'; break;
case 3: dummy = 'o'; break;
case 4: dummy = 'G'; break;
case 5: dummy = 'e'; break;
case 6: dummy = 'n'; break;
case 7: dummy = 'N'; break;
case 8: dummy = 'U'; break;
case 9: dummy = 'T'; break;
case 10: dummy = '.'; break;
default: dummy++;
}
if (IS_GRAPHIC_CHAR(dummy))
fprintf(trace_fp, FN_DEBUG_GRAPHIC, dummy);
putc(NL, trace_fp);
return mac+1;
}
/**
* Build up a definition context.
* It is created by passed-in macro arguments.
*
* @param def_ct number of definitions
* @param def_list list of definitions
*/
static void
build_defs(int def_ct, def_list_t * def_list)
{
curr_def_ctx.dcx_defent = &(def_list->de);
/*
* FOR each definition, evaluate the associated expression
* and set the text value to it.
*/
do {
if (def_list->pzExpr == NULL)
continue;
retryExpression:
switch (*(def_list->pzExpr)) {
case ';':
{
char * pz = strchr(def_list->pzExpr, NL);
if (pz != NULL) {
pz = SPN_WHITESPACE_CHARS(pz + 1);
def_list->pzExpr = pz;
goto retryExpression;
}
/* FALLTHROUGH */
}
case NUL:
def_list->pzExpr = NULL;
def_list->de.de_val.dvu_text = (char *)zNil;
break;
case '(':
{
SCM res;
/*
* It is a scheme expression. Accept only string
* and number results.
*/
if (OPT_VALUE_TRACE >= TRACE_EXPRESSIONS) {
fprintf(trace_fp, TRACE_BUILD_DEFS,
cur_macro->md_sib_idx - def_ct, def_list->pzExpr);
}
res = ag_eval(def_list->pzExpr);
if (scm_is_string(res)) {
AGDUPSTR(def_list->de.de_val.dvu_text,
ag_scm2zchars(res, "res"), "ev res");
}
else if (scm_is_number(res)) {
def_list->de.de_val.dvu_text = AGALOC(16, "num buf");
snprintf(def_list->de.de_val.dvu_text, (size_t)16,
ULONG_FMT, AG_SCM_TO_ULONG(res));
}
else
AGDUPSTR(def_list->de.de_val.dvu_text, zNil, "nil str");
break;
}
case '`':
if (OPT_VALUE_TRACE >= TRACE_EXPRESSIONS) {
fprintf(trace_fp, TRACE_BUILD_DEFS,
cur_macro->md_sib_idx - def_ct, def_list->pzExpr+1);
}
def_list->de.de_val.dvu_text = shell_cmd(def_list->pzExpr+1);
break;
}
} while (def_list++, --def_ct > 0);
}
/*=macfunc DEFINE
*
* what: Define a user AutoGen macro
* cindex: define macro
* handler_proc:
* load_proc:
* unload-proc:
*
* desc:
*
* This function will define a new macro. You must provide a name for the
* macro. You do not specify any arguments, though the invocation may
* specify a set of name/value pairs that are to be active during the
* processing of the macro.
*
* @example
* [+ define foo +]
* ... macro body with macro functions ...
* [+ enddef +]
* ... [+ foo bar='raw text' baz=<<text expression>> +]
* @end example
*
* Once the macro has been defined, this new macro can be invoked by
* specifying the macro name as the first token after the start macro marker.
* Alternatively, you may make the invocation explicitly invoke a defined
* macro by specifying @code{INVOKE} (@pxref{INVOKE}) in the macro
* invocation. If you do that, the macro name can be computed with an
* expression that gets evaluated every time the INVOKE macro is encountered.
*
* Any remaining text in the macro invocation will be used to create new
* name/value pairs that only persist for the duration of the processing of
* the macro. The expressions are evaluated the same way basic
* expressions are evaluated. @xref{expression syntax}.
*
* The resulting definitions are handled much like regular
* definitions, except:
*
* @enumerate
* @item
* The values may not be compound. That is, they may not contain
* nested name/value pairs.
* @item
* The bindings go away when the macro is complete.
* @item
* The name/value pairs are separated by whitespace instead of
* semi-colons.
* @item
* Sequences of strings are not concatenated.
* @end enumerate
*
* @quotation
* @strong{NB:} The macro is extracted from the template as the template is
* scanned. You cannot conditionally define a macro by enclosing it in an
* @code{IF}/@code{ENDIF} (@pxref{IF}) macro pair. If you need to dynamically
* select the format of a @code{DEFINE}d macro, then put the flavors into
* separate template files that simply define macros. @code{INCLUDE}
* (@pxref{INCLUDE}) the appropriate template when you have computed which
* you need.
* @end quotation
*
* Due to this, it is acceptable and even a good idea to place all the
* @code{DEFINE} macros at the end of the template. That puts the main
* body of the template at the beginning of the file.
=*/
/*=macfunc ENDDEF
*
* what: Ends a macro definition.
* in-context:
*
* desc:
* This macro ends the @code{DEFINE} function template block.
* For a complete description @xref{DEFINE}.
=*/
/**
* This routine runs the invocation of a defined macro.
*
* @param tpl not used
* @param[in] mac the macro that holds the data for the defined macro
*/
macro_t *
mFunc_Define(templ_t * tpl, macro_t * mac)
{
def_list_t * pList = (def_list_t *)mac->md_res;
int defCt = mac->md_sib_idx;
def_ctx_t ctx;
if (OPT_VALUE_TRACE > TRACE_NOTHING) {
tpl = (templ_t *)mac->md_pvt;
fprintf(trace_fp, TPL_INVOKED, tpl->td_name, defCt);
if (OPT_VALUE_TRACE == TRACE_EVERYTHING)
fprintf(trace_fp, TAB_FILE_LINE_FMT,
current_tpl->td_file, mac->md_line);
}
/*
* IF we have no special definitions, then do not nest definitions
*/
if (defCt != 0) {
ctx = curr_def_ctx;
curr_def_ctx.dcx_prev = &ctx;
build_defs(defCt, pList);
}
gen_new_block((templ_t *)mac->md_pvt);
if (defCt != 0)
curr_def_ctx = ctx;
if ((defCt = mac->md_sib_idx) > 0) {
pList = (def_list_t *)mac->md_res;
while (defCt-- > 0) {
if (pList->pzExpr != NULL) {
AGFREE(pList->de.de_val.dvu_text);
pList->de.de_val.dvu_text = NULL;
}
pList++;
}
}
return mac+1;
}
/**
* unload a defined macro
*
* @param[in,out] mac macro containing the data to unload
*/
void
mUnload_Define(macro_t * mac)
{
void * p = VOIDP(mac->md_res);
if (p != NULL)
AGFREE(p);
}
/*=macfunc INVOKE
*
* handler_proc:
* what: Invoke a User Defined Macro
*
* desc:
*
* User defined macros may be invoked explicitly or implicitly.
* If you invoke one implicitly, the macro must begin with the
* name of the defined macro. Consequently, this may @strong{not}
* be a computed value. If you explicitly invoke a user defined macro,
* the macro begins with the macro name @code{INVOKE} followed by
* a @i{basic expression} that must yield a known user defined macro.
* A macro name _must_ be found, or AutoGen will issue a diagnostic
* and exit.
*
* Arguments are passed to the invoked macro by name.
* The text following the macro name must consist of a series of
* names each of which is followed by an equal sign (@code{=}) and
* a @i{basic expression} that yields a string.
*
* The string values may contain template macros that are parsed
* the first time the macro is processed and evaluated again every
* time the macro is evaluated.
=*/
macro_t *
mFunc_Invoke(templ_t * tpl, macro_t * mac)
{
/*
* IF this is the first time through,
* THEN separate the name from the rest of the arguments.
*/
if (mac->md_name_off == 0) {
prep_invoke_args(mac);
/*
* IF the name is constant and not an expression,
* THEN go find the template now and bind the macro call
* to a particular template macro
*/
if (IS_VAR_FIRST_CHAR(tpl->td_text[ mac->md_name_off ])) {
mac->md_code = FTYP_DEFINE;
mac->md_pvt = VOIDP(find_tpl(tpl->td_text + mac->md_name_off));
if (mac->md_pvt == NULL) {
char const * p = tpl->td_text + mac->md_name_off;
AG_ABEND_IN(tpl, mac, aprf(BAD_MAC_NM_FMT, p));
/* NOTREACHED */
}
return mFunc_Define(tpl, mac);
}
}
/*
* Call `eval' to determine the macro name. Every invocation
* may be different!!
*/
{
SCM macName = eval(tpl->td_text + mac->md_name_off);
char * pz = ag_scm2zchars(macName, "mac name");
templ_t * ntpl = find_tpl(pz);
if (ntpl == NULL) {
pz = aprf(BAD_MAC_NM_FMT, pz);
AG_ABEND_IN(tpl, mac, pz);
/* NOTREACHED */
}
mac->md_pvt = VOIDP(ntpl);
}
return mFunc_Define(tpl, mac);
}
/**
* Loads the debug function for load time breakpoints.
* @param pT containing template
* @param pMac the debug macro data
* @param ppzSan pointer to scanning pointer
* @returns the next open macro slot
*/
macro_t *
mLoad_Debug(templ_t * pT, macro_t * pMac, char const ** ppzScan)
{
if (OPT_VALUE_TRACE >= TRACE_DEBUG_MESSAGE)
return mLoad_Unknown(pT, pMac, ppzScan);
return mLoad_Comment(pT, pMac, ppzScan);
}
static templ_t *
new_template(templ_t * base_tpl, macro_t * mac, char const * scan)
{
templ_t * ntpl;
char * copy;
char const * src = (char const *)mac->md_txt_off;
int ct = (int)(base_tpl->td_mac_ct - (mac - base_tpl->td_macros));
size_t aloc_sz = sizeof(*ntpl)
+ ((uint32_t)ct * sizeof(macro_t)) + strlen(scan) + 0x100;
aloc_sz &= (size_t)~0x0F;
/*
* Allocate a new template block that is much larger than needed.
*/
ntpl = (templ_t *)AGALOC(aloc_sz, "new tpl");
memset(VOIDP(ntpl), 0, aloc_sz);
ntpl->td_magic = base_tpl->td_magic;
ntpl->td_size = aloc_sz;
ntpl->td_mac_ct = ct;
ntpl->td_file = strdup(base_tpl->td_file);
copy = ntpl->td_name = VOIDP(ntpl->td_macros + ct);
if (! IS_VAR_FIRST_CHAR(*src))
AG_ABEND_IN(base_tpl, mac, LD_DEF_NEED_NAME);
while (IS_VALUE_NAME_CHAR(*src))
*(copy++) = *(src++);
*(copy++) = NUL;
if (OPT_VALUE_TRACE >= TRACE_BLOCK_MACROS)
fprintf(trace_fp, TRACE_MACRO_DEF, ntpl->td_name, ntpl->td_file);
ntpl->td_text = copy;
ntpl->td_scan = copy+1;
strcpy(ntpl->td_start_mac, base_tpl->td_start_mac);
strcpy(ntpl->td_end_mac, base_tpl->td_end_mac);
current_tpl = ntpl;
return ntpl;
}
static void
load_define_tpl(templ_t * tpl, char const ** ppzScan)
{
macro_t * last_mac = parse_tpl(tpl->td_macros, ppzScan);
int ct;
/*
* Make sure all of the input string was *NOT* scanned.
*/
if (*ppzScan == NULL)
AG_ABEND_IN(tpl, tpl->td_macros, LD_DEF_WOOPS);
ct = (int)(last_mac - tpl->td_macros);
/*
* IF there are empty macro slots,
* THEN pack the text
*/
if (ct < tpl->td_mac_ct) {
int delta = (int)sizeof(macro_t) * (int)(tpl->td_mac_ct - ct);
void * data = (tpl->td_name == NULL) ? tpl->td_text : tpl->td_name;
size_t size = (size_t)(tpl->td_scan - (char *)data);
memmove(VOIDP(last_mac), data, size);
tpl->td_text -= delta;
tpl->td_scan -= delta;
tpl->td_name -= delta;
tpl->td_mac_ct = ct;
}
}
macro_t *
mLoad_Define(templ_t * ori_tpl, macro_t * mac, char const ** p_scan)
{
static load_proc_p_t apDefineLoad[ FUNC_CT ] = { NULL };
templ_t * new_tpl;
/**
* Save the global macro loading mode
*/
load_proc_p_t const * save_load_procs = load_proc_table;
if (mac->md_txt_off == 0)
AG_ABEND_IN(ori_tpl, mac, LD_DEF_NEED_NAME);
/*
* IF this is the first time here, THEN set up the "DEFINE" block
* callout table. It is the standard table, except entries are
* inserted for functions that are enabled only while processing
* a DEFINE block (viz. "ENDDEF" and removing "DEFINE").
*/
if (apDefineLoad[0] == NULL) {
memcpy(VOIDP(apDefineLoad), base_load_table, sizeof(base_load_table));
apDefineLoad[ FTYP_ENDDEF ] = &mLoad_Ending;
apDefineLoad[ FTYP_DEFINE ] = &mLoad_Bogus;
}
load_proc_table = apDefineLoad;
defining_macro = true;
new_tpl = new_template(ori_tpl, mac, *p_scan);
load_define_tpl(new_tpl, p_scan);
defining_macro = false;
/*
* Adjust the sizes. Remove absolute pointers. Reallocate to the correct
* size. Restore the offsets to pointer values.
*/
{
size_t sz = (size_t)(new_tpl->td_scan - (char *)new_tpl);
if (sz < new_tpl->td_size) {
new_tpl->td_size = sz;
new_tpl->td_name -= (long)new_tpl;
new_tpl->td_text -= (long)new_tpl;
new_tpl = AGREALOC(VOIDP(new_tpl), new_tpl->td_size, "resize mac");
new_tpl->td_name += (long)new_tpl;
new_tpl->td_text += (long)new_tpl;
}
}
#if defined(DEBUG_ENABLED)
if (HAVE_OPT(SHOW_DEFS)) {
static char const zSum[] = "loaded %d macros from %s\n"
"\tBinary template size: 0x%X\n\n";
fprintf(trace_fp, zSum, new_tpl->td_mac_ct, new_tpl->td_file,
(unsigned int)new_tpl->td_size);
}
#endif
new_tpl->td_scan = (char *)named_tpls;
named_tpls = new_tpl;
load_proc_table = save_load_procs;
memset(VOIDP(mac), 0, sizeof(*mac));
current_tpl = ori_tpl;
return mac;
}
/**
* @}
*
* Local Variables:
* mode: C
* c-file-style: "stroustrup"
* indent-tabs-mode: nil
* End:
* end of agen5/funcDef.c */