summaryrefslogtreecommitdiff
path: root/agen5/funcDef.c
diff options
context:
space:
mode:
Diffstat (limited to 'agen5/funcDef.c')
-rw-r--r--agen5/funcDef.c899
1 files changed, 899 insertions, 0 deletions
diff --git a/agen5/funcDef.c b/agen5/funcDef.c
new file mode 100644
index 0000000..80906bd
--- /dev/null
+++ b/agen5/funcDef.c
@@ -0,0 +1,899 @@
+
+/**
+ * @file funcDef.c
+ *
+ * This module implements the DEFINE text function.
+ *
+ * Time-stamp: "2012-04-07 09:47:37 bkorb"
+ *
+ * This file is part of AutoGen.
+ * AutoGen Copyright (c) 1992-2012 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((void*)pz);
+ break;
+ }
+ case '"':
+ case '\'':
+ /*
+ * Process the quoted strings now
+ */
+ if ((pzScan - pDL->pzExpr) < 24) {
+ char* pz = (char*)AGALOC(24, "quoted string");
+ memcpy((void*)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 = 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((void*)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((void*)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 = 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 (AG_SCM_STRING_P(res)) {
+ AGDUPSTR(def_list->de.de_val.dvu_text,
+ ag_scm2zchars(res, "res"), "ev res");
+ }
+ else if (AG_SCM_NUM_P(res)) {
+ def_list->de.de_val.dvu_text = AGALOC(16, "num buf");
+ snprintf(def_list->de.de_val.dvu_text, (size_t)16,
+ BUILD_DEFS_LONG_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((void*)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 = (void*)(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 = (void*)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 = (void*)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 = base_tpl->td_mac_ct - (mac - base_tpl->td_macros);
+ size_t aloc_sz =
+ sizeof(*ntpl) + (ct * sizeof(macro_t)) + strlen(scan) + 0x100;
+ aloc_sz &= ~0x0F;
+
+ /*
+ * Allocate a new template block that is much larger than needed.
+ */
+ ntpl = (templ_t*)AGALOC(aloc_sz, "new tpl");
+ memset((void*)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 = (void*)(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 = last_mac - tpl->td_macros;
+
+ /*
+ * IF there are empty macro slots,
+ * THEN pack the text
+ */
+ if (ct < tpl->td_mac_ct) {
+ int delta = sizeof(macro_t) * (tpl->td_mac_ct - ct);
+ void * data = (tpl->td_name == NULL) ? tpl->td_text : tpl->td_name;
+ size_t size = tpl->td_scan - (char*)data;
+ memmove((void*)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((void*)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 = 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((void*)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((void*)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 */