Ejemplo n.º 1
0
/*=gfunc extract
 *
 * what:   extract text from another file
 * general_use:
 * exparg: file-name,  name of file with text
 * exparg: marker-fmt, format for marker text
 * exparg: caveat,     warn about changing marker, opt
 * exparg: default,    default initial text,       opt
 *
 * doc:
 *
 * This function is used to help construct output files that may contain
 * text that is carried from one version of the output to the next.
 *
 * The first two arguments are required, the second are optional:
 *
 * @itemize @bullet
 * @item
 *      The @code{file-name} argument is used to name the file that
 *      contains the demarcated text.
 * @item
 *      The @code{marker-fmt} is a formatting string that is used to construct
 *      the starting and ending demarcation strings.  The sprintf function is
 *      given the @code{marker-fmt} with two arguments.  The first is either
 *      "START" or "END".  The second is either "DO NOT CHANGE THIS COMMENT"
 *      or the optional @code{caveat} argument.
 * @item
 *      @code{caveat} is presumed to be absent if it is the empty string
 *      (@code{""}).  If absent, ``DO NOT CHANGE THIS COMMENT'' is used
 *      as the second string argument to the @code{marker-fmt}.
 * @item
 *      When a @code{default} argument is supplied and no pre-existing text
 *      is found, then this text will be inserted between the START and END
 *      markers.
 * @end itemize
 *
 * @noindent
 * The resulting strings are presumed to be unique within
 * the subject file.  As a simplified example:
 *
 * @example
 * [+ (extract "fname" "// %s - SOMETHING - %s" ""
 *             "example default") +]
 * @end example
 * @noindent
 * will result in the following text being inserted into the output:
 *
 * @example
 * // START - SOMETHING - DO NOT CHANGE THIS COMMENT
 * example default
 * // END   - SOMETHING - DO NOT CHANGE THIS COMMENT
 * @end example
 *
 * @noindent
 * The ``@code{example default}'' string can then be carried forward to
 * the next generation of the output, @strong{@i{provided}} the output
 * is not named "@code{fname}" @i{and} the old output is renamed to
 * "@code{fname}" before AutoGen-eration begins.
 *
 * @table @strong
 * @item NB:
 * You can set aside previously generated source files inside the pseudo
 * macro with a Guile/scheme function, extract the text you want to keep
 * with this extract function.  Just remember you should delete it at the
 * end, too.  Here is an example from my Finite State Machine generator:
 *
 * @example
 * [+ AutoGen5 Template  -*- Mode: text -*-
 * h=%s-fsm.h   c=%s-fsm.c
 * (shellf
 * "test -f %1$s-fsm.h && mv -f %1$s-fsm.h .fsm.head
 *  test -f %1$s-fsm.c && mv -f %1$s-fsm.c .fsm.code" (base-name))
 * +]
 * @end example
 *
 * This code will move the two previously produced output files to files
 * named ".fsm.head" and ".fsm.code".  At the end of the 'c' output
 * processing, I delete them.
 *
 * @item also NB:
 * This function presumes that the output file ought to be editable so
 * that the code between the @code{START} and @code{END} marks can be edited
 * by the template user.  Consequently, when the @code{(extract ...)} function
 * is invoked, if the @code{writable} option has not been specified, then
 * it will be set at that point.  If this is not the desired behavior, the
 * @code{--not-writable} command line option will override this.
 * Also, you may use the guile function @code{(chmod "file" mode-value)}
 * to override whatever AutoGen is using for the result mode.
 * @end table
=*/
SCM
ag_scm_extract(SCM file, SCM marker, SCM caveat, SCM def)
{
    char const * pzStart;
    char const * pzEnd;
    char const * pzText;

    if (! AG_SCM_STRING_P(file) || ! AG_SCM_STRING_P(marker))
        return SCM_UNDEFINED;

    pzText = load_extract_file(ag_scm2zchars(file, "extr file"));

    {
        char const * pzMarker = ag_scm2zchars(marker, "marker");
        char const * pzCaveat = EXTRACT_CAVEAT;

        if (AG_SCM_STRING_P(caveat) && (AG_SCM_STRLEN(caveat) > 0))
            pzCaveat = ag_scm2zchars(caveat, "caveat");

        pzStart = aprf(pzMarker, EXTRACT_START, pzCaveat);
        pzEnd   = aprf(pzMarker, EXTRACT_END,   pzCaveat);
    }

    {
        SCM res;

        if (pzText == NULL)
             res = mk_empty_text(pzStart, pzEnd, def);
        else res = get_text(pzText, pzStart, pzEnd, def);

        AGFREE((void*)pzStart);
        AGFREE((void*)pzEnd);
        return res;
    }
}
Ejemplo n.º 2
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.º 3
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.º 4
0
/**
 * Add a system name to the environment.  The input name is up-cased and
 * made to conform to environment variable names.  If not already in the
 * environment, it is added with the string value "1".
 *
 * @param env_name in/out: system name to export
 */
static void
add_sys_env(char * env_name)
{
    int i = 2;

    for (;;) {
        if (IS_UPPER_CASE_CHAR(env_name[i]))
            env_name[i] = (char)tolower(env_name[i]);
        else if (! IS_ALPHANUMERIC_CHAR(env_name[i]))
            env_name[i] = '_';

        if (env_name[ ++i ] == NUL)
            break;
    }

    /*
     *  If the user already has something in the environment, do not
     *  override it.
     */
    if (getenv(env_name) == NULL) {
        char * pz;

        if (OPT_VALUE_TRACE > TRACE_DEBUG_MESSAGE)
            fprintf(trace_fp, TRACE_ADD_TO_ENV_FMT, env_name);

        pz = aprf(ADD_SYS_ENV_VAL_FMT, env_name);
        putenv(pz);
    }
}
Ejemplo n.º 5
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.º 6
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;
}
Ejemplo n.º 7
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.º 8
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.º 9
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.º 10
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.º 11
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.º 12
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.º 13
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.º 14
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;
}
Ejemplo n.º 15
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.º 16
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.º 17
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.º 18
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.º 19
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.º 20
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.º 21
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.º 22
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.º 23
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.º 24
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.º 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
/*
 *  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.
     */
}
Ejemplo n.º 27
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;
}