tMacro * mLoad_While(tTemplate* pT, tMacro* pMac, char const ** ppzScan) { size_t srcLen = (size_t)pMac->res; /* macro len */ tpLoadProc const * papLP = papLoadProc; tMacro * pEndMac; /* * While processing an "IF" macro, * we have handler functions for 'ELIF', 'ELSE' and 'ENDIF' * Otherwise, we do not. Switch the callout function table. */ static tpLoadProc apWhileLoad[ FUNC_CT ] = { NULL }; /* * IF there is no associated text expression * THEN woops! what are we to case on? */ if (srcLen == 0) AG_ABEND_IN(pT, pMac, LD_WHILE_NO_EXPR); if (apWhileLoad[0] == NULL) { memcpy((void*)apWhileLoad, apLoadProc, sizeof(apLoadProc)); apWhileLoad[ FTYP_ENDWHILE ] = &mLoad_Ending; } papLoadProc = apWhileLoad; /* * Load the expression */ (void)mLoad_Expr(pT, pMac, ppzScan); /* * Now, do a nested parse of the template. When the matching 'ENDWHILE' * macro is encountered, the handler routine will cause 'parseTemplate()' * to return with the text scanning pointer pointing to the remaining * text. */ pEndMac = parseTemplate(pMac+1, ppzScan); if (*ppzScan == NULL) AG_ABEND_IN(pT, pMac, LD_WHILE_NO_ENDWHILE); pMac->sibIndex = pMac->endIndex = pEndMac - pT->aMacros; /* * Restore the context of any encompassing block macros */ papLoadProc = papLP; return pEndMac; }
/* * mLoad_Include -- digest an INCLUDE macro * * Simply verify that there is some argument to this macro. * Regular "expr" macros are their own argument, so there is always one. */ tMacro* mLoad_Include(tTemplate* pT, tMacro* pMac, char const ** ppzScan) { if ((int)pMac->res == 0) AG_ABEND_IN(pT, pMac, LD_INC_NO_FNAME); return mLoad_Expr(pT, pMac, ppzScan); }
/** * Some functions are known to AutoGen, but invalid out of context. * For example, ELIF, ELSE and ENDIF are all known to AutoGen. * However, the load function pointer for those functions points * here, until an "IF" function is encountered. */ tMacro* mLoad_Bogus(tTemplate* pT, tMacro* pMac, char const ** ppzScan) { char const * pzSrc = (char const*)pMac->ozText; /* macro text */ char const * pzMac; char z[ 64 ]; if (pzSrc != NULL) { z[0] = ':'; z[1] = z[2] = ' '; strncpy(z+3, pzSrc, (size_t)60); z[63] = NUL; pzSrc = z; } else pzSrc = zNil; { int ix = pMac->funcCode; if ((unsigned)ix >= FUNC_CT) ix = 0; pzMac = apzFuncNames[ ix ]; } pzSrc = aprf(LD_BOGUS_UNKNOWN, pT->pzTplFile, pMac->lineNo, pzMac, pzSrc); AG_ABEND_IN(pT, pMac, pzSrc); /* NOTREACHED */ return NULL; }
/*=macfunc BOGUS * * what: Out-of-context or unknown functions are bogus. * handler_proc: * load_proc: * unnamed: =*/ tMacro* mFunc_Bogus(tTemplate* pT, tMacro* pMac) { char * pz = aprf(FN_BOGUS_FMT, pMac->funcCode, (pMac->funcCode < FUNC_CT) ? apzFuncNames[ pMac->funcCode ] : FN_BOGUS_HUH); AG_ABEND_IN(pT, pMac, pz); /* NOTREACHED */ return pMac; }
/*=macfunc ELIF * * what: Alternate Conditional Template Block * in-context: * * desc: * This macro must only appear after an @code{IF} function, and * before any associated @code{ELSE} or @code{ENDIF} functions. * It denotes the start of an alternate template block for the * @code{IF} function. Its expression argument is evaluated as are * the arguments to @code{IF}. For a complete description @xref{IF}. =*/ static tMacro* mLoad_Elif(tTemplate* pT, tMacro* pMac, char const ** ppzScan) { if ((int)pMac->res == 0) AG_ABEND_IN(pT, pMac, NO_IF_EXPR); /* * Load the expression */ (void)mLoad_Expr(pT, pMac, ppzScan); current_if.pElse->sibIndex = pMac - pT->aMacros; current_if.pElse = pMac; return pMac + 1; }
/*=macfunc SELECT * * what: Selection block for CASE function * in-context: * alias: | ~ | = | * | ! | + | * unload-proc: * * desc: * This macro selects a block of text by matching an expression * against the sample text expression evaluated in the @code{CASE} * macro. @xref{CASE}. * * You do not specify a @code{SELECT} macro with the word ``select''. * Instead, you must use one of the 19 match operators described in * the @code{CASE} macro description. =*/ static tMacro* mLoad_Select(tTemplate * pT, tMacro* pMac, char const ** ppzScan) { char const * pzScan = *ppzScan; /* text after macro */ char* pzCopy = pT->pNext; /* next text dest */ char const * pzSrc = (char*)pMac->ozText; /* macro text */ long srcLen = pMac->res; /* macro len */ static char const zInvSel[] = "Invalid selection clause"; int typ = (int)FTYP_SELECT_COMPARE_FULL; /* * Set the global macro loading mode */ papLoadProc = apCaseLoad; pMac->res = 0; if (srcLen == 0) AG_ABEND_IN(pT, pMac, "Empty macro text"); /* * IF the first character is an asterisk, * THEN the match can start anywhere in the string */ if (*pzSrc == '*') { pzSrc++; if (IS_WHITESPACE_CHAR(*pzSrc) || (*pzSrc == NUL)) { typ = (int)FTYP_SELECT_MATCH_ANYTHING; srcLen = 0; pMac->ozText = 0; goto selection_done; } typ |= (int)FTYP_SELECT_COMPARE_SKP_START; } /* * The next character must indicate whether we are * pattern matching ('~') or doing string compares ('=') */ switch (*pzSrc++) { case '~': /* * Or in the pattern matching bit */ typ |= (int)FTYP_SELECT_MATCH_FULL; pMac->res = REG_EXTENDED; /* FALLTHROUGH */ case '=': /* * IF the '~' or '=' is doubled, * THEN it is a case sensitive match. Skip over the char. * ELSE or in the case insensitive bit */ if (pzSrc[0] == pzSrc[-1]) { pzSrc++; } else { typ |= (int)FTYP_SELECT_EQUIVALENT_FULL; } break; case '!': case '+': switch (*pzSrc) { case 'e': case 'E': break; default: goto bad_sel; } if ((pzSrc[1] != NUL) && (! IS_WHITESPACE_CHAR(pzSrc[1]))) goto bad_sel; typ = (int)((pzSrc[-1] == '!') ? FTYP_SELECT_MATCH_NONEXISTENCE : FTYP_SELECT_MATCH_EXISTENCE); srcLen = 0; pMac->ozText = 0; goto selection_done; default: bad_sel: AG_ABEND_IN(pT, pMac, zInvSel); } /* * IF the last character is an asterisk, * THEN the match may end before the test string ends. * OR in the "may end early" bit. */ if (*pzSrc == '*') { pzSrc++; typ |= (int)FTYP_SELECT_COMPARE_SKP_END; } if (! IS_WHITESPACE_CHAR(*pzSrc)) AG_ABEND_IN(pT, pMac, zInvSel); while (IS_WHITESPACE_CHAR(*pzSrc)) pzSrc++; srcLen -= pzSrc - (char const *)pMac->ozText; if (srcLen <= 0) AG_ABEND_IN(pT, pMac, zInvSel); /* * See if we are doing case insensitive regular expressions */ if ( (typ & (int)FTYP_SELECT_EQV_MATCH_FULL) == (int)FTYP_SELECT_EQV_MATCH_FULL) { int bitSet; pMac->res = REG_EXTENDED | REG_ICASE; /* * Turn off the case comparison mode for regular expressions. * We don't have to worry about it. It is done for us. */ bitSet = ~(int)FTYP_SELECT_EQUIVALENT_FULL; bitSet |= (int)FTYP_SELECT_COMPARE_FULL; /* dont turn this bit off! */ typ &= bitSet; } /* * Copy the expression */ pzScan = pzCopy; pMac->ozText = (pzCopy - pT->pzTemplText); if (typ == (int)FTYP_SELECT_EQUIVALENT) { do { *(pzCopy++) = toupper(*(pzSrc++)); } while (--srcLen > 0); } else { do { *(pzCopy++) = *(pzSrc++); } while (--srcLen > 0); } *(pzCopy++) = NUL; *(pzCopy++) = NUL; pT->pNext = pzCopy; if ((*pzScan == '"') || (*pzScan == '\'')) { void * ptr = (void *)pzScan; spanQuote(ptr); } selection_done: pMac->funcCode = (teFuncType)typ; current_case.pSelect->sibIndex = (pMac - pT->aMacros); current_case.pSelect = (tMacro*)pMac; return pMac + 1; }
/* * mLoad_CASE * * This function is called to set up (load) the macro * when the template is first read in (before processing). */ tMacro* mLoad_Case(tTemplate* pT, tMacro* pMac, char const ** ppzScan) { size_t srcLen = (size_t)pMac->res; /* macro len */ tCaseStack save_stack = current_case; tMacro* pEsacMac; /* * Save the global macro loading mode */ tpLoadProc const * papLP = papLoadProc; /* * IF there is no associated text expression * THEN woops! what are we to case on? */ if (srcLen == 0) AG_ABEND_IN(pT, pMac, "expressionless CASE"); /* * Load the expression */ (void)mLoad_Expr(pT, pMac, ppzScan); /* * IF this is the first time here, * THEN set up the "CASE" mode callout tables. * It is the standard table, except entries are inserted * for SELECT and ESAC. */ if (apCaseLoad[0] == NULL) { int i; /* * Until there is a selection clause, only comment and select * macros are allowed. */ for (i=0; i < FUNC_CT; i++) apSelectOnly[i] = mLoad_Bogus; memcpy((void*)apCaseLoad, apLoadProc, sizeof( apLoadProc )); apSelectOnly[ FTYP_COMMENT] = mLoad_Comment; apSelectOnly[ FTYP_SELECT ] = \ apCaseLoad[ FTYP_SELECT ] = mLoad_Select; apCaseLoad[ FTYP_ESAC ] = mLoad_Ending; } /* * Set the "select macro only" loading mode */ papLoadProc = apSelectOnly; /* * Save global pointers to the current macro entry. * We will need this to link the CASE, SELECT and ESAC * functions together. */ current_case.pCase = current_case.pSelect = pMac; /* * Continue parsing the template from this nested level */ pEsacMac = parseTemplate(pMac+1, ppzScan); if (*ppzScan == NULL) AG_ABEND_IN(pT, pMac, "ESAC not found"); /* * Tell the last select macro where its end is. * (It ends with the "next" sibling. Since there * is no "next" at the end, it is a tiny lie.) * * Also, make sure the CASE macro knows where the end is. */ pMac->endIndex = \ current_case.pSelect->sibIndex = (pEsacMac - pT->aMacros); /* * Restore any enclosing CASE function's context. */ current_case = save_stack; /* * Restore the global macro loading mode */ papLoadProc = papLP; /* * Return the next available macro descriptor */ return pEsacMac; }
/* * mLoad_Unknown -- the default (unknown) load function * * Move any text into the text offset field. * This is used as the default load mechanism. */ tMacro * mLoad_Unknown(tTemplate * pT, tMacro * pMac, char const ** ppzScan) { char * pzCopy = pT->pNext; char const * pzSrc; size_t srcLen = (size_t)pMac->res; /* macro len */ if (srcLen <= 0) goto return_emtpy_expression; pzSrc = (char const*)pMac->ozText; /* macro text */ switch (*pzSrc) { case ';': /* * Strip off scheme comments */ do { while (--srcLen, (*++pzSrc != NL)) { if (srcLen <= 0) goto return_emtpy_expression; } while (--srcLen, IS_WHITESPACE_CHAR(*++pzSrc)) { if (srcLen <= 0) goto return_emtpy_expression; } } while (*pzSrc == ';'); break; case '[': case '.': { size_t remLen; /* * We are going to recopy the definition name, * this time as a canonical name (i.e. with '[', ']' and '.' * characters and all blanks squeezed out) */ pzCopy = pT->pzTemplText + pMac->ozName; /* * Move back the source pointer. We may have skipped blanks, * so skip over however many first, then back up over the name. */ while (IS_WHITESPACE_CHAR(pzSrc[-1])) pzSrc--, srcLen++; remLen = strlen(pzCopy); pzSrc -= remLen; srcLen += remLen; /* * Now copy over the full canonical name. Check for errors. */ remLen = canonicalizeName(pzCopy, pzSrc, (int)srcLen); if (remLen > srcLen) AG_ABEND_IN(pT, pMac, LD_UNKNOWN_INVAL_DEF); pzSrc += srcLen - remLen; srcLen = remLen; pT->pNext = pzCopy + strlen(pzCopy) + 1; if (srcLen <= 0) goto return_emtpy_expression; break; } } /* * Copy the expression */ pzCopy = pT->pNext; /* next text dest */ pMac->ozText = (pzCopy - pT->pzTemplText); pMac->res = 0; memcpy(pzCopy, pzSrc, srcLen); pzCopy += srcLen; *(pzCopy++) = NUL; *pzCopy = NUL; /* double terminate */ pT->pNext = pzCopy; return pMac + 1; return_emtpy_expression: pMac->ozText = 0; pMac->res = 0; return pMac + 1; }
tMacro* mLoad_If(tTemplate* pT, tMacro* pMac, char const ** ppzScan) { size_t srcLen = (size_t)pMac->res; /* macro len */ tIfStack save_stack = current_if; tpLoadProc const * papLP = papLoadProc; tMacro * pEndifMac; /* * While processing an "IF" macro, * we have handler functions for 'ELIF', 'ELSE' and 'ENDIF' * Otherwise, we do not. Switch the callout function table. */ static tpLoadProc apIfLoad[ FUNC_CT ] = { NULL }; /* * IF there is no associated text expression * THEN woops! what are we to case on? */ if (srcLen == 0) AG_ABEND_IN(pT, pMac, NO_IF_EXPR); if (apIfLoad[0] == NULL) { memcpy((void*)apIfLoad, apLoadProc, sizeof(apLoadProc)); apIfLoad[ FTYP_ELIF ] = &mLoad_Elif; apIfLoad[ FTYP_ELSE ] = &mLoad_Else; apIfLoad[ FTYP_ENDIF ] = &mLoad_Ending; } papLoadProc = apIfLoad; /* * We will need to chain together the 'IF', 'ELIF', and 'ELSE' * macros. The 'ENDIF' gets absorbed. */ current_if.pIf = current_if.pElse = pMac; /* * Load the expression */ (void)mLoad_Expr(pT, pMac, ppzScan); /* * Now, do a nested parse of the template. * When the matching 'ENDIF' macro is encountered, * the handler routine will cause 'parseTemplate()' * to return with the text scanning pointer pointing * to the remaining text. */ pEndifMac = parseTemplate(pMac+1, ppzScan); if (*ppzScan == NULL) AG_ABEND_IN(pT, pMac, LD_IF_NO_ENDIF); current_if.pIf->endIndex = \ current_if.pElse->sibIndex = pEndifMac - pT->aMacros; /* * Restore the context of any encompassing block macros */ current_if = save_stack; papLoadProc = papLP; return pEndifMac; }