Пример #1
0
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;
}
Пример #2
0
/*
 *  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);
}
Пример #3
0
/**
 *  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;
}
Пример #4
0
/*=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;
}
Пример #5
0
/*=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;
}
Пример #6
0
/*=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;
}
Пример #7
0
/*
 *  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;
}
Пример #8
0
/*
 *  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;
}
Пример #9
0
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;
}