Ejemplo n.º 1
0
LOCAL void
yyerror(char* s)
{
    static char const yyerr_fmt[] =
        "%s:  in %s on line %d\n"
        "\ttoken in error:  %s\n"
        "\t[[...<error-text>]] %s\n\n"
        "Likely causes:  a mismatched quote, a value that needs "
        "quoting,\n\t\tor a missing semi-colon\n";

    static char const zErrTkn[] = "%s:  ``%s''\n";
    static char const zDf[] = "`%s'\n";

    char* pz;

    if (strlen(pCurCtx->pzScan) > 64 )
        pCurCtx->pzScan[64] = NUL;

    switch (lastToken) {
    case DP_EV_VAR_NAME:
    case DP_EV_OTHER_NAME:
    case DP_EV_STRING:
    case DP_EV_NUMBER:
        if (strlen(pz_token) > 64 )
            pz_token[64] = NUL;

        pz = aprf(zErrTkn, DP_EVT_NAME(lastToken), pz_token);
        break;

    default:
        pz = aprf(zDf, DP_EVT_NAME(lastToken));
    }
    AG_ABEND(aprf(yyerr_fmt, s, pCurCtx->pzCtxFname, pCurCtx->lineNo, pz,
                  pCurCtx->pzScan));
}
Ejemplo n.º 2
0
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *  Support routines for the directives
 *
 *  skipToEndif
 *
 *  Skip through the text to a matching "#endif".  We do this when we
 *  have processed the allowable text (found an "#else" after
 *  accepting the preceeding text) or when encountering a "#if*def"
 *  while skipping a block of text due to a failed test.
 */
static char*
skipToEndif(char* pzStart)
{
    char* pzScan = pzStart;
    char* pzRet;

    for (;;) {
        /*
         *  'pzScan' is pointing to the first character on a line.
         *  Check for a directive on the current line before scanning
         *  later lines.
         */
        if (*pzScan == '#')
            pzScan++;
        else {
            char* pz = strstr(pzScan, zCheckList);
            if (pz == NULL)
                AG_ABEND(aprf(zNoEndif, pCurCtx->pzCtxFname, pCurCtx->lineNo));

            pzScan = pz + STRSIZE(zCheckList);
        }

        while (IS_WHITESPACE_CHAR(*pzScan)) pzScan++;

        switch (findDirective(pzScan)) {
        case DIR_ENDIF:
        {
            /*
             *  We found the endif we are interested in
             */
            char* pz = strchr(pzScan, NL);
            if (pz != NULL)
                pzRet = pz+1;
            else pzRet = pzScan + strlen(pzScan);
            goto leave_func;
        }

        case DIR_IFDEF:
        case DIR_IFNDEF:
            /*
             *  We found a nested ifdef/ifndef
             */
            pzScan = skipToEndif(pzScan);
            break;

        default:
            /*
             *  We do not care what we found
             */
            break; /* ignore it */
        }  /* switch (findDirective(pzScan)) */
    }

leave_func:
    while (pzStart < pzRet) {
        if (*(pzStart++) == NL)
            pCurCtx->lineNo++;
    }
    return pzRet;
}
Ejemplo n.º 3
0
/*=directive error
 *
 *  arg:  [ <descriptive text> ]
 *
 *  text:
 *  This directive will cause AutoGen to stop processing
 *  and exit with a status of EXIT_FAILURE.
=*/
static char*
doDir_error(char* pzArg, char* pzScan)
{
    AG_ABEND(aprf("#error directive -- in %s on line %d\n\t%s\n",
                  pCurCtx->pzCtxFname, pCurCtx->lineNo, pzArg));
    /* NOTREACHED */
    return NULL;
}
Ejemplo n.º 4
0
static void
check_assert_str(char const * pz, char const * arg)
{
    pz = SPN_WHITESPACE_CHARS(pz);

    if (IS_FALSE_TYPE_CHAR(*pz))
        AG_ABEND(aprf(DIRECT_ASSERT_FMT, pz, arg));
}
Ejemplo n.º 5
0
/**
 *  Starting with the current directory, search the directory
 *  list trying to find the base template file name.
 */
LOCAL tTemplate *
loadTemplate(char const * pzFileName, char const * referrer)
{
    static tmap_info_t mapInfo;
    static char        zRealFile[ AG_PATH_MAX ];

    /*
     *  Find the template file somewhere
     */
    {
        static char const * const apzSfx[] = { "tpl", "agl", NULL };
        if (! SUCCESSFUL(findFile(pzFileName, zRealFile, apzSfx, referrer))) {
            errno = ENOENT;
            AG_CANT("map data file", pzFileName);
        }
    }

    /*
     *  Make sure the specified file is a regular file.
     *  Make sure the output time stamp is at least as recent.
     */
    {
        struct stat stbf;
        if (stat(zRealFile, &stbf) != 0)
            AG_CANT("stat file", pzFileName);

        if (! S_ISREG(stbf.st_mode)) {
            errno = EINVAL;
            AG_CANT("not regular file", pzFileName);
        }

        if (outTime <= stbf.st_mtime)
            outTime = stbf.st_mtime + 1;
    }

    text_mmap(zRealFile, PROT_READ|PROT_WRITE, MAP_PRIVATE, &mapInfo);
    if (TEXT_MMAP_FAILED_ADDR(mapInfo.txt_data))
        AG_ABEND(aprf("Could not open template '%s'", zRealFile));

    if (pfDepends != NULL)
        append_source_name(zRealFile);

    /*
     *  Process the leading pseudo-macro.  The template proper
     *  starts immediately after it.
     */
    {
        tMacro    * pSaveMac = pCurMacro;
        tTemplate * pRes;
        pCurMacro = NULL;

        pRes = digest_pseudo_macro(&mapInfo, zRealFile);
        pCurMacro = pSaveMac;
        text_munmap(&mapInfo);

        return pRes;
    }
}
Ejemplo n.º 6
0
/*=gfunc prefix
 *
 * what:  prefix lines with a string
 * general_use:
 *
 * exparg: prefix, string to insert at start of each line
 * exparg: text, multi-line block of text
 *
 * doc:
 *  Prefix every line in the second string with the first string.
 *
 *  For example, if the first string is "# " and the second contains:
 *  @example
 *  two
 *  lines
 *  @end example
 *  @noindent
 *  The result string will contain:
 *  @example
 *  # two
 *  # lines
 *  @end example
=*/
SCM
ag_scm_prefix(SCM prefix, SCM text)
{
    char*    pzPfx;
    char*    pzText;
    char*    pzDta;
    size_t   out_size, rem_size;
    size_t   pfx_size;
    char*    pzRes;

    pzPfx    = ag_scm2zchars(prefix, "prefix");
    pzDta    = \
    pzText   = ag_scm2zchars(text, "text");
    pfx_size = strlen(pzPfx);
    out_size = pfx_size;

    for (;;) {
        switch (*(pzText++)) {
        case NUL:
            goto exit_count;
        case NL:
            out_size += pfx_size;
            /* FALLTHROUGH */
        default:
            out_size++;
        }
    } exit_count:;

    pzText = pzDta;
    pzRes  = pzDta = ag_scribble(rem_size = out_size);
    strcpy(pzDta, pzPfx);
    pzDta    += pfx_size;
    rem_size -= pfx_size;
    pfx_size++;

    for (;;) {
        char ch = *(pzText++);
        switch (ch) {
        case NUL:
            if (rem_size != 0)
                AG_ABEND(PREFIX_FAIL);

            return AG_SCM_STR2SCM(pzRes, out_size);

        case NL:
            *pzDta    = ch;
            strcpy(pzDta+1, pzPfx);
            pzDta    += pfx_size;
            rem_size -= pfx_size;
            break;

        default:
            rem_size--;
            *(pzDta++) = ch;
            break;
        }
    }
}
Ejemplo n.º 7
0
/*=directive elif
 *
 *  text:
 *  This must follow an @code{#if}
 *  otherwise it will generate an error.
 *  It will be ignored.
=*/
static char*
doDir_elif(char* pzArg, char* pzScan)
{
    static char const z[] =
        "`#elif' directive encountered out of context\n\tin %s on line %d\n";

    AG_ABEND(aprf(z, pCurCtx->pzCtxFname, pCurCtx->lineNo));
    /* NOTREACHED */
    return NULL;
}
Ejemplo n.º 8
0
/**
 *  @code{#endshell}, @code{#elif} and @code{#endmac} directives, when found
 *  via a non-nested scan, are always in error.  They should only be found
 *  during the handling of @code{#shell}, @code{#if} and @code{#macdef}
 *  directives.  @code{#else} and @code{#endif} are in error if not matched
 *  with a previous @code{#ifdef} or @code{#ifndef} directive.
 */
static char *
bad_dirv_ctx(directive_enum_t id, char const * arg, char * scan_next)
{
    AG_ABEND(aprf(DIRECT_BAD_CTX_FMT, directive_name(id),
                  cctx->scx_fname, cctx->scx_line));
    (void)arg;
    (void)id;
    /* NOTREACHED */
    return scan_next;
}
Ejemplo n.º 9
0
/**
 *  This directive will cause AutoGen to stop processing
 *  and exit with a status of EXIT_FAILURE.
 */
char *
doDir_error(directive_enum_t id, char const * arg, char * scan_next)
{
    arg = SPN_WHITESPACE_CHARS(arg);
    AG_ABEND(aprf(DIRECT_ERROR_FMT, cctx->scx_fname, cctx->scx_line, arg));
    /* NOTREACHED */
    (void)scan_next;
    (void)id;
    return NULL;
}
Ejemplo n.º 10
0
/*=directive assert
 *
 *  arg:  `shell-script` | (scheme-expr) | <anything else>
 *
 *  text:
 *  If the @code{shell-script} or @code{scheme-expr} do not yield @code{true}
 *  valued results, autogen will be aborted.  If @code{<anything else>} or
 *  nothing at all is provided, then this directive is ignored.
 *
 *  When writing the shell script, remember this is on a preprocessing
 *  line.  Multiple lines must be backslash continued and the result is a
 *  single long line.  Separate multiple commands with semi-colons.
 *
 *  The result is @code{false} (and fails) if the result is empty, the
 *  number zero, or a string that starts with the letters 'n' or 'f' ("no"
 *  or "false").
=*/
static void
check_assert_str(char const* pz, char const* pzArg)
{
    static char const fmt[] = "#assert yielded \"%s\":\n\t`%s`";

    while (IS_WHITESPACE_CHAR(*pz)) pz++;

    if (IS_FALSE_TYPE_CHAR(*pz))
        AG_ABEND(aprf(fmt, pz, pzArg));
}
Ejemplo n.º 11
0
static void
compile_re(regex_t* pRe, char const * pzPat, int flags)
{
    void * const pat = (void *)pzPat;
    int  rerr = regcomp(pRe, pat, flags);
    if (rerr != 0) {
        char zEr[ SCRIBBLE_SIZE ];
        regerror(rerr, pRe, zEr, sizeof(zEr));
        fprintf(stderr, zBadRe, rerr, zEr, pzPat);
        AG_ABEND("Bad regular expression");
    }
}
Ejemplo n.º 12
0
/**
 *  Skip through the text to a matching "#endif".  We do this when we
 *  have processed the allowable text (found an "#else" after
 *  accepting the preceding text) or when encountering a "#if*def"
 *  while skipping a block of text due to a failed test.
 */
static char *
skip_to_endif(char * start)
{
    bool   skipping_if = skip_if_block;
    char * scan = start;
    char * dirv_end;

    for (;;) {
        scan = next_directive(scan);

        switch (find_directive(scan)) {
        case DIR_ENDIF:
        {
            /*
             *  We found the endif we are interested in
             */
            char * pz = strchr(scan, NL);
            if (pz != NULL)
                 dirv_end = pz+1;
            else dirv_end = scan + strlen(scan);
            goto leave_func;
        }

        case DIR_ELIF:
            if (! skip_if_block)
                AG_ABEND(ELIF_CONTEXT_MSG);
            break;

        case DIR_IF:
            skip_if_block = true;
            /* FALLTHROUGH */

        case DIR_IFDEF:
        case DIR_IFNDEF:
            /*
             *  We found a nested conditional, so skip to endif nested, too.
             */
            scan = skip_to_endif(scan);
            skip_if_block = skipping_if;
            break;

        default:
            /*
             *  We do not care what we found
             */
            break; /* ignore it */
        }  /* switch (find_directive(scan)) */
    }

 leave_func:
    cctx->scx_line += count_lines(start, dirv_end);
    return dirv_end;
}
Ejemplo n.º 13
0
/**
 *  Print out an invalid transition message and return EXIT_FAILURE
 */
static int
cgi_invalid_transition( te_cgi_state st, te_cgi_event evt )
{
    /* START == INVALID TRANS MSG == DO NOT CHANGE THIS COMMENT */
    char * pz = aprf( zCgiStrings + CgiFsmErr_off, st, CGI_STATE_NAME( st ),
                     evt, CGI_EVT_NAME( evt ));

    AG_ABEND( aprf(CGI_PARSE_ERR_FMT, pz ));
    /* END   == INVALID TRANS MSG == DO NOT CHANGE THIS COMMENT */

    return EXIT_FAILURE;
}
Ejemplo n.º 14
0
static void
init_scm(void)
{
    last_scm_cmd = SCHEME_INIT_TEXT;

    {
        SCM ini_res = ag_scm_c_eval_string_from_file_line(
            SCHEME_INIT_TEXT, AG_TEXT_STRTABLE_FILE, SCHEME_INIT_TEXT_LINENO);
        AGDUPSTR(libguile_ver, scm2display(ini_res), "ini res");
    }

    {
        unsigned int maj, min, mic;
        switch (sscanf(libguile_ver, "%u.%u.%u", &maj, &min, &mic)) {
        case 2:
        case 3: break;
        default:
            AG_ABEND(aprf(GUILE_VERSION_BAD, libguile_ver));
            /* NOT_REACHED */
        }
        maj = min + (100 * maj);
        if ((GUILE_VERSION / 1000) != maj)
            AG_ABEND(aprf(GUILE_VERSION_WRONG, libguile_ver,
                          MK_STR(GUILE_VERSION)));
    }

    {
#       if GUILE_VERSION >= 200000
#         define SCHEME_INIT_DEBUG SCHEME_INIT_DEBUG_2_0
#       else
#         define SCHEME_INIT_DEBUG SCHEME_INIT_DEBUG_1_6
#       endif
        char * p = aprf(INIT_SCM_ERRS_FMT, SCHEME_INIT_DEBUG);
#       undef  SCHEME_INIT_DEBUG

        last_scm_cmd = p;
        ag_scm_c_eval_string_from_file_line(p, __FILE__, __LINE__);
        AGFREE(p);
    }
}
Ejemplo n.º 15
0
static void
loadScheme(void)
{
    char*    pzText    = pCurCtx->pzScan;
    char*    pzEnd     = (char*)skipScheme(pzText, pzText + strlen(pzText));
    char     endCh     = *pzEnd;
    int      schemeLen = (pzEnd - pzText);
    int      next_ln;
    SCM      res;

    /*
     *  NUL terminate the Scheme expression, run it, then restore
     *  the NUL-ed character.
     */
    if (*pzEnd == NUL)
        AG_ABEND(aprf(zErrMsg, pzProg,
                      "end of Guile/scheme expression not found",
                      pCurCtx->pzCtxFname, pCurCtx->lineNo));

    *pzEnd  = NUL;
    next_ln = pCurCtx->lineNo + count_nl(pzText);

    procState = PROC_STATE_GUILE_PRELOAD;
    res = ag_scm_c_eval_string_from_file_line(
        pzText, pCurCtx->pzCtxFname, pCurCtx->lineNo );
    procState = PROC_STATE_LOAD_DEFS;
    *pzEnd = endCh;

    pCurCtx->pzScan = pzEnd;
    pzEnd = (char*)resolveSCM(res); /* ignore const-ness */
    pCurCtx->lineNo = next_ln;

    if (strlen(pzEnd) >= schemeLen) {
        AGDUPSTR(pzEnd, pzEnd, "SCM Result");

        pz_token = pzEnd;
        manageAllocatedData(pz_token);
    }

    else {
        /*
         *  We know the result is smaller than the source.  Copy in place.
         */
        strcpy(pzText, pzEnd);
        pz_token = pzText;
    }

    lastToken = DP_EV_STRING;
}
Ejemplo n.º 16
0
static char *
next_directive(char * scan)
{
    if (*scan == '#')
        scan++;
    else {
        char * pz = strstr(scan, DIRECT_CK_LIST_MARK);
        if (pz == NULL)
            AG_ABEND(aprf(DIRECT_NOENDIF_FMT, cctx->scx_fname,
                          cctx->scx_line));

        scan = pz + 2;
    }

    return SPN_WHITESPACE_CHARS(scan);
}
Ejemplo n.º 17
0
static char*
skipToEndmac(char* pzStart)
{
    char* pzScan = pzStart;
    char* pzRet;

    for (;;) {
        /*
         *  'pzScan' is pointing to the first character on a line.
         *  Check for a directive on the current line before scanning
         *  later lines.
         */
        if (*pzScan == '#')
            pzScan++;
        else {
            char* pz = strstr(pzScan, zCheckList);
            if (pz == NULL)
                AG_ABEND(aprf(zNoEndif, pCurCtx->pzCtxFname, pCurCtx->lineNo));

            pzScan = pz + STRSIZE(zCheckList);
        }

        while (IS_WHITESPACE_CHAR(*pzScan)) pzScan++;

        if (findDirective(pzScan) == DIR_ENDMAC) {
            /*
             *  We found the endmac we are interested in
             */
            char* pz = strchr(pzScan, NL);
            if (pz != NULL)
                pzRet = pz+1;
            else pzRet = pzScan + strlen(pzScan);
            break;
        }
    }

    while (pzStart < pzRet) {
        if (*(pzStart++) == NL)
            pCurCtx->lineNo++;
    }
    return pzRet;
}
Ejemplo n.º 18
0
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *  A quoted string has been found.
 *  Find the end of it and compress any escape sequences.
 */
static char*
assembleHereString(char* pzScan)
{
    static char const endless[] = "Unterminated HereString";
    ag_bool  trimTabs = AG_FALSE;
    char     zMark[ MAX_HEREMARK_LEN ];
    size_t   markLen = 0;
    char*    pzDest;
    int      here_string_line_no;

    /*
     *  See if we are to strip leading tab chars
     */
    if (*pzScan == '-') {
        trimTabs = AG_TRUE;
        pzScan++;
    }

    /*
     *  Skip white space up to the marker or EOL
     */
    while (IS_WHITESPACE_CHAR(*pzScan)) {
        if (*pzScan++ == NL)
            AG_ABEND(aprf(zErrMsg, pzProg, "HereString missing the mark",
                          pCurCtx->pzCtxFname, pCurCtx->lineNo));
    }

    /*
     *  Copy the marker, noting its length
     */
    {
        char* pz = zMark;
        while (IS_VARIABLE_NAME_CHAR(*pzScan)) {
            if (++markLen >= sizeof(zMark))
                AG_ABEND(aprf(zErrMsg, pzProg, "HereString mark "
                              STR(MAX_HEREMARK_LEN) " or more chars",
                              pCurCtx->pzCtxFname, pCurCtx->lineNo));

            *(pz++) = *(pzScan++);
        }
        if (markLen == 0)
            AG_ABEND(aprf(zErrMsg, pzProg, "HereString missing the mark",
                          pCurCtx->pzCtxFname, pCurCtx->lineNo));
        *pz = NUL;
    }

    pzDest = pzScan;
    pz_token = pzDest;

    /*
     *  Skip forward to the EOL after the marker.
     */
    pzScan = strchr(pzScan, NL);
    if (pzScan == NULL)
        AG_ABEND(aprf(zErrMsg, pzProg, endless, pCurCtx->pzCtxFname,
                      pCurCtx->lineNo));

    /*
     *  And skip the first new line + conditionally skip tabs
     */
    here_string_line_no = pCurCtx->lineNo++;
    pzScan++;

    if (trimTabs)
        while (*pzScan == TAB)  ++pzScan;

    /*
     *  FOR as long as the text does not match the mark
     *       OR it matches but is a substring
     *  DO copy characters
     */
    while (  (strncmp(pzScan, zMark, markLen) != 0)
          || IS_VARIABLE_NAME_CHAR(pzScan[markLen]) )  {

        for (;;) {
            switch (*(pzDest++) = *(pzScan++)) {
            case NL:
                pCurCtx->lineNo++;
                goto lineDone;

            case NUL:
                AG_ABEND(aprf(zErrMsg, pzProg, endless, pCurCtx->pzCtxFname,
                              here_string_line_no));
            }
        } lineDone:;

        if (trimTabs)
            while (*pzScan == TAB)  ++pzScan;
    } /* while strncmp ... */

    /*
     *  pzDest may still equal pz_token, if no data were copied
     */
    if (pzDest > (char*)pz_token)
         pzDest[-1] = NUL;
    else pzDest[0]  = NUL;

    return pzScan + markLen;
}
Ejemplo n.º 19
0
/**
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *  Load the macro array and file name.
 */
static void
load_macs(tTemplate * pT, char const * pzF, char const * pzN,
          char const * pzData)
{
    tMacro* pMac   = pT->aMacros;

    {
        char*   pzText = (char*)(pMac + pT->macroCt);
        size_t  len;

        AGDUPSTR(pT->pzTplFile, pzF, "templ file");

        len = strlen(pzN) + 1;
        memcpy((void*)pzText, (void*)pzN, len);
        pT->pzTplName   = pzText;
        pzText         += len;
        pT->pzTemplText = pzText;
        pT->pNext       = pzText + 1;
    }

    pCurTemplate = pT;

    {
        tMacro* pMacEnd = parseTemplate(pMac, &pzData);
        int     ct;

        /*
         *  Make sure all of the input string was scanned.
         */
        if (pzData != NULL)
            AG_ABEND("Template parse ended unexpectedly");

        ct = pMacEnd - pMac;

        /*
         *  IF there are empty macro slots,
         *  THEN pack the text
         */
        if (ct < pT->macroCt) {
            int     delta = sizeof(tMacro) * (pT->macroCt - ct);
            void*   data  =
                (pT->pzTplName == NULL) ? pT->pzTemplText : pT->pzTplName;
            size_t  size  = pT->pNext - (char*)data;
            memmove((void*)pMacEnd, data, size);

            pT->pzTemplText -= delta;
            pT->pNext       -= delta;
            pT->pzTplName   -= delta;
            pT->macroCt      = ct;
        }
    }

    pT->descSize = pT->pNext - (char*)pT;
    pT->pNext    = NULL;

    /*
     *  We cannot reallocate a smaller array because
     *  the entries are all linked together and
     *  realloc-ing it may cause it to move.
     */
#if defined(DEBUG_ENABLED)
    if (HAVE_OPT(SHOW_DEFS)) {
        static char const zSum[] =
            "loaded %d macros from %s\n"
            "\tBinary template size:  0x%zX\n\n";
        fprintf(pfTrace, zSum, pT->macroCt, pzF, pT->descSize);
    }
#endif
}
Ejemplo n.º 20
0
/**
 *  Invokes @code{$SHELL} or @file{/bin/sh} on a script that should
 *  generate AutoGen definitions.  It does this using the same server
 *  process that handles the back-quoted @code{`} text.
 *  The block of text handed to the shell is terminated with
 *  the #endshell directive.
 *
 *  @strong{CAUTION}@:  let not your @code{$SHELL} be @code{csh}.
 */
char *
doDir_shell(directive_enum_t id, char const * arg, char * scan_next)
{
    static size_t const endshell_len = sizeof("\n#endshell") - 1;

    scan_ctx_t * pCtx;
    char *       pzText = scan_next;

    (void)arg;
    (void)id;

    /*
     *  The output time will always be the current time.
     *  The dynamic content is always current :)
     */
    maxfile_time = outfile_time = time(NULL);

    /*
     *  IF there are no data after the '#shell' directive,
     *  THEN we won't write any data
     *  ELSE we have to find the end of the data.
     */
    if (strncmp(pzText, DIRECT_SHELL_END_SHELL+1, endshell_len-1) == 0)
        return scan_next;

    {
        char * pz = strstr(scan_next, DIRECT_SHELL_END_SHELL);
        if (pz == NULL)
            AG_ABEND(aprf(DIRECT_SHELL_NOEND, cctx->scx_fname,
                          cctx->scx_line));

        while (scan_next < pz) {
            if (*(scan_next++) == NL) cctx->scx_line++;
        }

        *scan_next = NUL;
    }

    /*
     *  Advance the scan pointer to the next line after '#endshell'
     *  IF there is no such line,
     *  THEN the scan will resume on a zero-length string.
     */
    scan_next = strchr(scan_next + endshell_len, NL);
    if (scan_next == NULL)
        scan_next = VOIDP(zNil);

    /*
     *  Save the scan pointer into the current context
     */
    cctx->scx_scan  = scan_next;

    /*
     *  Run the shell command.  The output text becomes the
     *  "file text" that is used for more definitions.
     */
    pzText = shell_cmd(pzText);
    if (pzText == NULL)
        return scan_next;

    if (*pzText == NUL) {
        AGFREE(pzText);
        return scan_next;
    }

    /*
     *  Get the space for the output data and for context overhead.
     *  This is an extra allocation and copy, but easier than rewriting
     *  'loadData()' for this special context.
     */
    pCtx = (scan_ctx_t *)AGALOC(sizeof(scan_ctx_t) + strlen(pzText) + 4,
                             "shell output");

    /*
     *  Link the new scan data into the context stack
     */
    pCtx->scx_next = cctx;
    cctx           = pCtx;

    /*
     *  Set up the rest of the context structure
     */
    AGDUPSTR(pCtx->scx_fname, DIRECT_SHELL_COMP_DEFS, DIRECT_SHELL_COMP_DEFS);
    pCtx->scx_scan  =
    pCtx->scx_data  = (char *)(pCtx + 1);
    pCtx->scx_line  = 0;
    strcpy(pCtx->scx_scan, pzText);
    AGFREE(pzText);

    return pCtx->scx_scan;
}
Ejemplo n.º 21
0
/*
 *  skipToElseEnd
 *
 *  Skip through the text to a matching "#endif" or "#else" or
 *  "#elif*def".  We do this when we are skipping code due to a failed
 *  "#if*def" test.
 */
static char*
skipToElseEnd(char* pzStart)
{
    char* pzScan = pzStart;
    char* pzRet;

    for (;;) {
        /*
         *  'pzScan' is pointing to the first character on a line.
         *  Check for a directive on the current line before scanning
         *  later lines.
         */
        if (*pzScan == '#')
            pzScan++;
        else {
            char* pz = strstr(pzScan, zCheckList);
            if (pz == NULL)
                AG_ABEND(aprf(zNoEndif, pCurCtx->pzCtxFname, pCurCtx->lineNo));

            pzScan = pz + STRSIZE(zCheckList);
        }

        while (IS_WHITESPACE_CHAR(*pzScan)) pzScan++;

        switch (findDirective(pzScan)) {
        case DIR_ELSE:
            /*
             *  We found an "else" directive for an "ifdef"/"ifndef"
             *  that we were skipping over.  Start processing the text.
             */
            ifdefLevel++;
        /* FALLTHROUGH */

        case DIR_ENDIF:
        {
            /*
             *  We reached the end of the "ifdef"/"ifndef" we were
             *  skipping (or we dropped in from above).
             *  Start processing the text.
             */
            char* pz = strchr(pzScan, NL);
            if (pz != NULL)
                pzRet = pz+1;
            else pzRet = pzScan + strlen(pzScan);
            goto leave_func;
        }

        case DIR_IFDEF:
        case DIR_IFNDEF:
            /*
             *  We have found a nested "ifdef"/"ifndef".
             *  Call "skipToEndif()" to find *its* end, then
             *  resume looking for our own "endif" or "else".
             */
            pzScan = skipToEndif(pzScan);
            break;

        default:
            /*
             *  We either don't know what it is or we do not care.
             */
            break;
        }  /* switch (findDirective(pzScan)) */
    }

leave_func:
    while (pzStart < pzRet) {
        if (*(pzStart++) == NL)
            pCurCtx->lineNo++;
    }
    return pzRet;
}
Ejemplo n.º 22
0
/*=directive shell
 *
 *  text:
 *  Invokes @code{$SHELL} or @file{/bin/sh} on a script that should
 *  generate AutoGen definitions.  It does this using the same server
 *  process that handles the back-quoted @code{`} text.
 *  @strong{CAUTION}@:  let not your @code{$SHELL} be @code{csh}.
=*/
static char*
doDir_shell(char* pzArg, char* pzScan)
{
    static char const zShellText[] = "Computed Definitions";
    static char const zEndShell[]  = "\n#endshell";

    tScanCtx*  pCtx;
    char*      pzText = pzScan;

    /*
     *  The output time will always be the current time.
     *  The dynamic content is always current :)
     */
    outTime = time(NULL);

    /*
     *  IF there are no data after the '#shell' directive,
     *  THEN we won't write any data
     *  ELSE we have to find the end of the data.
     */
    if (strncmp(pzText, zEndShell+1, STRSIZE(zEndShell)-1) == 0)
        return pzScan;

    {
        static char const noend[] =
            "Missing #endshell after '#shell' in %s on line %d\n";
        char* pz = strstr(pzScan, zEndShell);
        if (pz == NULL)
            AG_ABEND(aprf(noend, pCurCtx->pzCtxFname, pCurCtx->lineNo));

        while (pzScan < pz) {
            if (*(pzScan++) == NL) pCurCtx->lineNo++;
        }

        *pzScan = NUL;
    }

    /*
     *  Advance the scan pointer to the next line after '#endshell'
     *  IF there is no such line,
     *  THEN the scan will resume on a zero-length string.
     */
    pzScan = strchr(pzScan + STRSIZE(zEndShell), NL);
    if (pzScan == NULL)
        pzScan = (void*)zNil;

    /*
     *  Save the scan pointer into the current context
     */
    pCurCtx->pzScan  = pzScan;

    /*
     *  Run the shell command.  The output text becomes the
     *  "file text" that is used for more definitions.
     */
    pzText = runShell(pzText);
    if (pzText == NULL)
        return pzScan;

    if (*pzText == NUL) {
        AGFREE(pzText);
        return pzScan;
    }

    /*
     *  Get the space for the output data and for context overhead.
     *  This is an extra allocation and copy, but easier than rewriting
     *  'loadData()' for this special context.
     */
    pCtx = (tScanCtx*)AGALOC(sizeof(tScanCtx) + strlen(pzText) + 4,
                             "shell output");

    /*
     *  Link the new scan data into the context stack
     */
    pCtx->pCtx       = pCurCtx;
    pCurCtx          = pCtx;

    /*
     *  Set up the rest of the context structure
     */
    AGDUPSTR(pCtx->pzCtxFname, zShellText, "shell text");
    pCtx->pzScan     =
        pCtx->pzData     = (char*)(pCtx+1);
    pCtx->lineNo     = 0;
    strcpy(pCtx->pzScan, pzText);
    AGFREE(pzText);

    return pCtx->pzScan;
}
Ejemplo n.º 23
0
/**
 *  Suck in the entire definitions file and parse it.
 */
LOCAL void
readDefines(void)
{
    char const *  pzDefFile;
    char *        pzData;
    size_t        dataSize;
    size_t        sizeLeft;
    FILE *        fp;
    def_input_mode_t in_mode = ready_input(&pzDefFile, &dataSize);

    if (in_mode == INPUT_DONE)
        return;

    /*
     *  Allocate the space we need for our definitions.
     */
    sizeLeft = dataSize+4+sizeof(*pBaseCtx);
    pBaseCtx = (tScanCtx*)AGALOC(sizeLeft, "file buffer");
    memset((void*)pBaseCtx, 0, sizeLeft);
    pBaseCtx->lineNo = 1;
    sizeLeft = dataSize;

    /*
     *  Our base context will have its currency pointer set to this
     *  input.  It is also a scanning pointer, but since this buffer
     *  is never deallocated, we do not have to remember the initial
     *  value.  (It may get reallocated here in this routine, tho...)
     */
    pzData =
        pBaseCtx->pzScan =
            pBaseCtx->pzData = (char*)(pBaseCtx+1);
    pBaseCtx->pCtx = NULL;

    /*
     *  Set the input file pointer, as needed
     */
    if (in_mode == INPUT_STDIN)
        fp = stdin;

    else {
        fp = fopen(pzDefFile, "r" FOPEN_TEXT_FLAG);
        if (fp == NULL)
            AG_CANT("open", pzDefFile);

        if (pfDepends != NULL)
            append_source_name(pzDefFile);
    }

    /*
     *  Read until done...
     */
    for (;;) {
        size_t rdct = fread((void*)pzData, (size_t)1, sizeLeft, fp);

        /*
         *  IF we are done,
         */
        if (rdct == 0) {
            /*
             *  IF it is because we are at EOF, then break out
             *  ELSE abend.
             */
            if (feof(fp) || (in_mode == INPUT_STDIN))
                break;

            AG_CANT("read", pzDefFile);
        }

        /*
         *  Advance input pointer, decrease remaining count
         */
        pzData   += rdct;
        sizeLeft -= rdct;

        /*
         *  See if there is any space left
         */
        if (sizeLeft == 0) {
            tScanCtx* p;
            off_t dataOff;

            /*
             *  IF it is a regular file, then we are done
             */
            if (in_mode != INPUT_STDIN)
                break;

            /*
             *  We have more data and we are out of space.
             *  Try to reallocate our input buffer.
             */
            dataSize += (sizeLeft = 0x1000);
            dataOff = pzData - pBaseCtx->pzData;
            p = AGREALOC((void*)pBaseCtx, dataSize+4+sizeof(*pBaseCtx),
                         "expanded file buffer");

            /*
             *  The buffer may have moved.  Set the data pointer at an
             *  offset within the new buffer and make sure our base pointer
             *  has been corrected as well.
             */
            if (p != pBaseCtx) {
                p->pzScan = \
                            p->pzData = (char*)(p+1);
                pzData = p->pzData + dataOff;
                pBaseCtx = p;
            }
        }
    }

    if (pzData == pBaseCtx->pzData)
        AG_ABEND("No definition data were read");

    *pzData = NUL;
    AGDUPSTR(pBaseCtx->pzCtxFname, pzDefFile, "def file name");
    manageAllocatedData(pBaseCtx);
    manageAllocatedData((void*)pBaseCtx->pzCtxFname);

    /*
     *  Close the input file, parse the data
     *  and alphabetically sort the definition tree contents.
     */
    if (in_mode != INPUT_STDIN)
        fclose(fp);

    pCurCtx = pBaseCtx;
    dp_run_fsm();
}
Ejemplo n.º 24
0
/**
 *  Load a file into memory.  Keep it in memory and try to reuse it
 *  if we get called again.  Likely, there will be several extractions
 *  from a single file.
 */
static char const*
load_extract_file(char const* pzNewFile)
{
    static char const * pzFile = NULL;
    static char const * pzText = NULL;
    struct stat  sbuf;
    char* pzIn;

    /*
     *  Make sure that we:
     *
     *  o got the file name from the SCM value
     *  o return the old text if we are searching the same file
     *  o have a regular file with some data
     *  o can allocate the space we need...
     *
     *  If we don't know about the current file, we leave the data
     *  from any previous file we may have loaded.
     *
     *  DO *NOT* include this file in dependency output.  The output may vary
     *  based on its contents, but since it is always optional input, it cannot
     *  be made to be required by make.
     */
    if (pzNewFile == NULL)
        return NULL;

    if (  (pzFile != NULL)
       && (strcmp(pzFile, pzNewFile) == 0))
        return pzText;

    if (  (stat(pzNewFile, &sbuf) != 0)
       || (! S_ISREG(sbuf.st_mode))
       || (sbuf.st_size < 10) )
        return NULL;

    if (pzFile != NULL) {
        AGFREE((void*)pzFile);
        AGFREE((void*)pzText);
        pzFile = pzText = NULL;
    }

    AGDUPSTR(pzFile, pzNewFile, "extract file");
    pzIn = (char*)AGALOC(sbuf.st_size + 1, "Extract Text");

    if (! HAVE_OPT(WRITABLE))
        SET_OPT_WRITABLE;

    pzText = (char const*)pzIn;

    /*
     *  Suck up the file.  We must read it all.
     */
    {
        struct stat stbf;
        FILE* fp = fopen(pzNewFile, "r");
        if (fp == NULL)
            goto bad_return;

        if (fstat(fileno(fp), &stbf) != 0) {
            fclose(fp);
            goto bad_return;
        }

        if (outTime <= stbf.st_mtime)
            outTime = stbf.st_mtime + 1;

        do  {
            size_t sz = fread(pzIn, (size_t)1, (size_t)sbuf.st_size, fp);
            if (sz == 0) {
                fprintf(stderr, LD_EXTRACT_BAD_READ, errno, strerror(errno),
                        (int)sbuf.st_size, pzFile);
                AG_ABEND(LD_EXTRACT_READ_FAIL);
            }

            pzIn += sz;
            sbuf.st_size -= sz;
        } while (sbuf.st_size > 0);

        *pzIn = NUL;
        fclose(fp);

        if (pfDepends != NULL)
            add_source_file(pzNewFile);
    }

    return pzText;

 bad_return:

    AGFREE((void*)pzFile);
    pzFile = NULL;
    AGFREE((void*)pzText);
    pzText = NULL;

    return pzText;
}
Ejemplo n.º 25
0
static ssize_t
safePrintf(char** ppzBuf, char const * pzFmt, void** argV)
{
#if ! defined(DEBUG_ENABLED)
    /*
     *  In normal operation (or during AutoGen testing), seg faults during the
     *  printf operation are caused by bad input data.  During AutoGen
     *  development, we do not supply bad printf arguments, so we want to
     *  capture any segfaults when they happen with the correct stack trace.
     *  Therefore, during AutoGen development, we do not protect against seg
     *  faults.
     */
    struct sigaction  saSave1;
    struct sigaction  saSave2;

    {
        struct sigaction  sa;
        sa.sa_handler = printFault;
        sa.sa_flags   = 0;
        sigemptyset(&sa.sa_mask);

        sigaction(SIGBUS,  &sa, &saSave1);
        sigaction(SIGSEGV, &sa, &saSave2);
    }

    {
        static char const zBadArgs[] = "Bad args to sprintf";
        static char const zBadFmt[]  =
            "%s ERROR:  %s processing printf format:\n\t%s\n";

        /*
         *  IF the sprintfv call below is going to address fault,
         *  THEN ...
         */
        if (sigsetjmp(printJumpEnv, 0) != 0) {
#ifndef HAVE_STRSIGNAL
            extern char* strsignal(int signo);
#endif
            /*
             *  IF the fprintf command in the then clause has not failed yet,
             *  THEN perform that fprintf
             */
            if (sigsetjmp(printJumpEnv, 0) == 0)
                fprintf(pfTrace, zBadFmt, pzProg,
                        strsignal(printJumpSignal), pzFmt);

            /*
             *  The "sprintfv" command below faulted, so we exit
             */
            AG_ABEND(zBadArgs);
        }
    }
#endif /* ! defined(DEBUG_ENABLED) */

    {
        int printSize = asprintfv(ppzBuf, pzFmt, (snv_constpointer*)argV);
        if ((printSize & ~0xFFFFFU) != 0) /* 1MB max */
            AG_ABEND(aprf("asprintfv returned 0x%08X\n", printSize));

#if ! defined(DEBUG_ENABLED)
        sigaction(SIGBUS,  &saSave1, NULL);
        sigaction(SIGSEGV, &saSave2, NULL);
#endif
        return printSize;
    }
}
Ejemplo n.º 26
0
/**
 *  Figure out what to use as the base name of the output file.
 *  If an argument is not provided, we use the base name of
 *  the definitions file.
 */
static void
open_output(tOutSpec * spec)
{
    static char const write_mode[] = "w" FOPEN_BINARY_FLAG "+";

    char const * out_file = NULL;

    if (strcmp(spec->zSuffix, OPEN_OUTPUT_NULL) == 0) {
        static int const flags = FPF_NOUNLINK | FPF_NOCHMOD | FPF_TEMPFILE;
    null_open:
        open_output_file(DEV_NULL, DEV_NULL_LEN, write_mode, flags);
        return;
    }

    /*
     *  IF we are to skip the current suffix,
     *  we will redirect the output to /dev/null and
     *  perform all the work.  There may be side effects.
     */
    if (HAVE_OPT(SKIP_SUFFIX)) {
        int     ct  = STACKCT_OPT(SKIP_SUFFIX);
        const char ** ppz = STACKLST_OPT(SKIP_SUFFIX);

        while (--ct >= 0) {
            if (strcmp(spec->zSuffix, *ppz++) == 0)
                goto null_open;
        }
    }

    /*
     *  Remove any suffixes in the last file name
     */
    {
        char const * def_file = OPT_ARG(BASE_NAME);
        char   z[AG_PATH_MAX];
        const char * pst = strrchr(def_file, '/');
        char * end;

        pst = (pst == NULL) ? def_file : (pst + 1);

        /*
         *  We allow users to specify a suffix with '-' and '_', but when
         *  stripping a suffix from the "base name", we do not recognize 'em.
         */
        end = strchr(pst, '.');
        if (end != NULL) {
            size_t len = (unsigned)(end - pst);
            if (len >= sizeof(z))
                AG_ABEND("--base-name name is too long");

            memcpy(z, pst, len);
            z[ end - pst ] = NUL;
            pst = z;
        }

        /*
         *  Now formulate the output file name in the buffer
         *  provided as the input argument.
         */
        out_file = aprf(spec->pzFileFmt, pst, spec->zSuffix);
        if (out_file == NULL)
            AG_ABEND(aprf(OPEN_OUTPUT_BAD_FMT, spec->pzFileFmt, pst,
                          spec->zSuffix));
    }

    open_output_file(out_file, strlen(out_file), write_mode, 0);
    free((void *)out_file);
}
Ejemplo n.º 27
0
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *   LEXICAL SCANNER
 */
LOCAL te_dp_event
yylex(void)
{
    lastToken = DP_EV_INVALID;

scanAgain:
    /*
     *  Start the process of locating a token.
     *  We branch here after skipping over a comment
     *  or processing a directive (which may change our context).
     */
    if (IS_WHITESPACE_CHAR(*pCurCtx->pzScan))
        trim_whitespace();

    switch (*pCurCtx->pzScan) {
    case NUL:
        /*
         *  IF we are not inside an include context,
         *  THEN go finish.
         */
        if (pCurCtx->pCtx == NULL)
            goto lex_done;

        pop_context();
        goto scanAgain;

    case '#':
    {
        extern char * processDirective(char*);
        char * pz = processDirective(pCurCtx->pzScan+1);
        /*
         *  Ensure that the compiler doesn't try to save a copy of
         *  "pCurCtx" in a register.  It must be reloaded from memory.
         */
        pCurCtx->pzScan = pz;
        goto scanAgain;
    }

    case '{': SET_LIT_TKN(O_BRACE);   break;
    case '=': SET_LIT_TKN(EQ);        break;
    case '}': SET_LIT_TKN(C_BRACE);   break;
    case '[': SET_LIT_TKN(OPEN_BKT);  break;
    case ']': SET_LIT_TKN(CLOSE_BKT); break;
    case ';': SET_LIT_TKN(SEMI);      break;
    case ',': SET_LIT_TKN(COMMA);     break;

    case '\'':
    case '"':
    {
        char* pz = ao_string_cook(pCurCtx->pzScan, &(pCurCtx->lineNo));
        if (pz == NULL)
            goto NUL_error;

        pz_token = pCurCtx->pzScan;

        lastToken = DP_EV_STRING;
        pCurCtx->pzScan = pz;
        break;
    }

    case '<':
        switch (lex_here_string()) {
        case SUCCESS: break;
        case FAILURE: goto BrokenToken;
        case PROBLEM: return DP_EV_INVALID;
        }
        break;

    case '(':
        loadScheme();
        break;

    case '\\':
        if (strncmp(pCurCtx->pzScan+1, "'(", (size_t)2) == 0) {
            alist_to_autogen_def();
            goto scanAgain;
        }
        lex_escaped_char();
        break;

    case '`':
        switch (lex_backquote()) {
        case FAILURE: goto NUL_error;
        case PROBLEM: goto scanAgain;
        case SUCCESS: break;
        }
        break;

    case '/':
        switch (lex_comment()) {
        case SUCCESS: goto scanAgain;
        default: break;
        }
        /* FALLTHROUGH */ /* to Invalid input char */

    default:
    BrokenToken:
        pCurCtx->pzScan = assembleName(pCurCtx->pzScan, &lastToken);
        break;
    }   /* switch (*pCurCtx->pzScan) */

    return lastToken;

NUL_error:

    AG_ABEND(aprf(zErrMsg, pzProg, "unterminated quote in definition",
                  pCurCtx->pzCtxFname, pCurCtx->lineNo));
    return DP_EV_INVALID;

lex_done:
    /*
     *  First time through, return the DP_EV_END token.
     *  Second time through, we really finish.
     */
    if (pCurCtx->pzScan == zNil) {
        pCurCtx->pCtx = pDoneCtx;
        pDoneCtx      = pCurCtx;

        return DP_EV_INVALID;
    }

    pCurCtx->pzScan = (char*)zNil;
    return DP_EV_END;
}
Ejemplo n.º 28
0
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *  It may be a number, a name, a keyword or garbage.
 *  Figure out which.
 */
static char*
assembleName(char * pzScan, te_dp_event * pRetVal)
{
    /*
     *  Check for a number.
     *  Scan it in and advance "pzScan".
     */
    if (  IS_DEC_DIGIT_CHAR(*pzScan)
       || (  (*pzScan == '-')
          && IS_DEC_DIGIT_CHAR(pzScan[1])
       )  )  {
        pz_token = pzScan;
        (void)strtol(pzScan, &pzScan, 0);
        *pRetVal = DP_EV_NUMBER;
        return pzScan;
    }

    if (! IS_UNQUOTABLE_CHAR(*pzScan))
        AG_ABEND(aprf("%s Error: Invalid input char '%c' in %s on line %d\n",
                      pzProg, *pzScan, pCurCtx->pzCtxFname, pCurCtx->lineNo));

    {
        unsigned char* pz = (unsigned char*)pzScan;

        while (IS_VALUE_NAME_CHAR(*pz))          pz++;

        if (IS_UNQUOTABLE_CHAR(*pz)) {
            *pRetVal = DP_EV_OTHER_NAME;
            while (IS_UNQUOTABLE_CHAR(*++pz))    ;
        } else
            *pRetVal = DP_EV_VAR_NAME;

        /*
         *  Return a NAME token, maybe.
         *  If the name is actually a keyword,
         *  we will return that token code instead.
         */
        pz_token = pzScan;
        pzScan   = (char*)pz;
    }

    /*
     *  Now scan the keyword table.
     */
    if (*pRetVal == DP_EV_VAR_NAME) {
        char sv_ch = *pzScan;  /* preserve the following character */
        int  kw_ix = 0;
        *pzScan = NUL;         /* NUL terminate the name           */

        do  {
            if (streqvcmp(apzKeywords[ kw_ix ], (char*)pz_token) == 0) {
                /*
                 *  Return the keyword token code instead of DP_EV_NAME
                 */
                *pRetVal = aKeywordTkn[ kw_ix ];
                break;
            }
        } while (++kw_ix < KEYWORD_CT);

        *pzScan = sv_ch;         /* restore the following character  */
    }

    return pzScan;
}
Ejemplo n.º 29
0
/*
 *  process a single scheme expression, yielding text that gets processed
 *  into AutoGen definitions.
 */
static void
alist_to_autogen_def(void)
{
    static char const zSchemeText[] = "Scheme Computed Definitions";
    static char const zWrap[] = "(alist->autogen-def %s)";

    char*  pzText  = ++(pCurCtx->pzScan);
    char*  pzEnd   = (char*)skipScheme(pzText, pzText + strlen(pzText));

    SCM    res;
    size_t res_len;
    tScanCtx*  pCtx;

    /*
     *  Wrap the scheme expression with the `alist->autogen-def' function
     */
    {
        char endCh = *pzEnd;
        *pzEnd = NUL;
        pzText = aprf(zWrap, pzText);
        *pzEnd = endCh;
    }

    /*
     *  Run the scheme expression.  The result is autogen definition text.
     */
    procState = PROC_STATE_GUILE_PRELOAD;
    res = ag_scm_c_eval_string_from_file_line(
        pzText, pCurCtx->pzCtxFname, pCurCtx->lineNo );

    /*
     *  The result *must* be a string, or we choke.
     */
    if (! AG_SCM_STRING_P(res)) {
        static char const zEr[] =
            "Scheme definition expression does not yield string:\n";
        AG_ABEND(zEr);
    }

    res_len   = AG_SCM_STRLEN(res);
    procState = PROC_STATE_LOAD_DEFS;
    pCurCtx->pzScan = pzEnd;
    AGFREE(pzText);

    /*
     *  Now, push the resulting string onto the input stack
     *  and link the new scan data into the context stack
     */
    pCtx = (tScanCtx*)AGALOC(sizeof(tScanCtx) + 4 + res_len, "lex scan ctx");
    pCtx->pCtx  = pCurCtx;
    pCurCtx     = pCtx;

    /*
     *  Set up the rest of the context structure
     */
    AGDUPSTR(pCtx->pzCtxFname, zSchemeText, "scheme text");
    pCtx->pzScan = \
    pCtx->pzData = (char*)(pCtx+1);
    pCtx->lineNo = 0;
    memcpy((void*)(pCtx->pzScan), (void*)AG_SCM_CHARS(res), res_len);
    pCtx->pzScan[ res_len ] = NUL;

    /*
     *  At this point, the next token will be obtained
     *  from the newly allocated context structure.
     *  When empty, input will resume from the '}' that we
     *  left as the next input token in the old context.
     */
}