Blame agen5/agUtils.c

Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * @file agUtils.c
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * Various utilities for AutoGen.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * @addtogroup autogen
Packit Service 96b5d3
 * @{
Packit Service 96b5d3
 */
Packit Service 96b5d3
/*
Packit Service 96b5d3
 *  This file is part of AutoGen.
Packit Service 96b5d3
 *  Copyright (C) 1992-2016 Bruce Korb - all rights reserved
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * AutoGen is free software: you can redistribute it and/or modify it
Packit Service 96b5d3
 * under the terms of the GNU General Public License as published by the
Packit Service 96b5d3
 * Free Software Foundation, either version 3 of the License, or
Packit Service 96b5d3
 * (at your option) any later version.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * AutoGen is distributed in the hope that it will be useful, but
Packit Service 96b5d3
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 96b5d3
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Packit Service 96b5d3
 * See the GNU General Public License for more details.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * You should have received a copy of the GNU General Public License along
Packit Service 96b5d3
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service 96b5d3
 */
Packit Service 96b5d3
Packit Service 96b5d3
/* = = = START-STATIC-FORWARD = = = */
Packit Service 96b5d3
static void
Packit Service 96b5d3
define_base_name(void);
Packit Service 96b5d3
Packit Service 96b5d3
static void
Packit Service 96b5d3
put_defines_into_env(void);
Packit Service 96b5d3
Packit Service 96b5d3
static void
Packit Service 96b5d3
open_trace_file(char ** av, tOptDesc * odsc);
Packit Service 96b5d3
Packit Service 96b5d3
static void
Packit Service 96b5d3
check_make_dep_env(void);
Packit Service 96b5d3
Packit Service 96b5d3
static char const *
Packit Service 96b5d3
skip_quote(char const * qstr);
Packit Service 96b5d3
/* = = = END-STATIC-FORWARD = = = */
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * Print a file system error fatal error message and die.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * @param[in] op         the operation that failed.
Packit Service 96b5d3
 * @param[in] fname      the file name the operation was on.
Packit Service 96b5d3
 * @noreturn
Packit Service 96b5d3
 */
Packit Service 96b5d3
LOCAL void
Packit Service 96b5d3
fswarn(char const * op, char const * fname)
Packit Service 96b5d3
{
Packit Service 96b5d3
    fprintf(stderr, FS_ERR_WARNING, errno, strerror(errno), op, fname);
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * Allocating printf function.  It either works or kills the program.
Packit Service 96b5d3
 * @param[in] pzFmt the input format
Packit Service 96b5d3
 * @returns the allocated, formatted result string.
Packit Service 96b5d3
 */
Packit Service 96b5d3
LOCAL char *
Packit Service 96b5d3
aprf(char const * pzFmt, ...)
Packit Service 96b5d3
{
Packit Service 96b5d3
    char * pz;
Packit Service 96b5d3
    va_list ap;
Packit Service 96b5d3
    va_start(ap, pzFmt);
Packit Service 96b5d3
    (void)vasprintf(&pz, pzFmt, ap);
Packit Service 96b5d3
    va_end(ap);
Packit Service 96b5d3
Packit Service 96b5d3
    if (pz == NULL) {
Packit Service 96b5d3
        char z[ 2 * SCRIBBLE_SIZE ];
Packit Service 96b5d3
        snprintf(z, sizeof(z), APRF_ALLOCATE_FAIL, pzFmt);
Packit Service 96b5d3
        AG_ABEND(z);
Packit Service 96b5d3
    }
Packit Service 96b5d3
    return pz;
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * Figure out what base name to use.  --base-name was not specified.
Packit Service 96b5d3
 * Base it on the definitions file, if available.
Packit Service 96b5d3
 */
Packit Service 96b5d3
static void
Packit Service 96b5d3
define_base_name(void)
Packit Service 96b5d3
{
Packit Service 96b5d3
    char const *  pz;
Packit Service 96b5d3
    char * pzD;
Packit Service 96b5d3
Packit Service 96b5d3
    if (! ENABLED_OPT(DEFINITIONS)) {
Packit Service 96b5d3
        OPT_ARG(BASE_NAME) = DFT_BASE_NAME;
Packit Service 96b5d3
        return;
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    pz = strrchr(OPT_ARG(DEFINITIONS), '/');
Packit Service 96b5d3
    /*
Packit Service 96b5d3
     *  Point to the character after the last '/', or to the full
Packit Service 96b5d3
     *  definition file name, if there is no '/'.
Packit Service 96b5d3
     */
Packit Service 96b5d3
    pz = (pz == NULL) ? OPT_ARG(DEFINITIONS) : (pz + 1);
Packit Service 96b5d3
Packit Service 96b5d3
    /*
Packit Service 96b5d3
     *  IF input is from stdin, then use "stdin"
Packit Service 96b5d3
     */
Packit Service 96b5d3
    if ((pz[0] == '-') && (pz[1] == NUL)) {
Packit Service 96b5d3
        OPT_ARG(BASE_NAME) = STDIN_FILE_NAME;
Packit Service 96b5d3
        return;
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    /*
Packit Service 96b5d3
     *  Otherwise, use the basename of the definitions file
Packit Service 96b5d3
     */
Packit Service 96b5d3
    OPT_ARG(BASE_NAME) = \
Packit Service 96b5d3
        pzD = AGALOC(strlen(pz)+1, "derived base");
Packit Service 96b5d3
Packit Service 96b5d3
    while ((*pz != NUL) && (*pz != '.'))  *(pzD++) = *(pz++);
Packit Service 96b5d3
    *pzD = NUL;
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * Put the -D option arguments into the environment.
Packit Service 96b5d3
 * This makes them accessible to Guile/Scheme code, too.
Packit Service 96b5d3
 */
Packit Service 96b5d3
static void
Packit Service 96b5d3
put_defines_into_env(void)
Packit Service 96b5d3
{
Packit Service 96b5d3
    int     ct  = STACKCT_OPT(DEFINE);
Packit Service 96b5d3
    char const **   ppz = STACKLST_OPT(DEFINE);
Packit Service 96b5d3
Packit Service 96b5d3
    do  {
Packit Service 96b5d3
        char const * pz = *(ppz++);
Packit Service 96b5d3
        /*
Packit Service 96b5d3
         *  IF there is no associated value,  THEN set it to '1'.
Packit Service 96b5d3
         *  There are weird problems with empty defines.
Packit Service 96b5d3
         *  FIXME:  we loose track of this memory.  Don't know what to do,
Packit Service 96b5d3
         *  really, there is no good recovery mechanism for environment
Packit Service 96b5d3
         *  data.
Packit Service 96b5d3
         */
Packit Service 96b5d3
        if (strchr(pz, '=') == NULL) {
Packit Service 96b5d3
            size_t siz = strlen(pz)+3;
Packit Service 96b5d3
            char * p   = AGALOC(siz, "env define");
Packit Service 96b5d3
Packit Service 96b5d3
            strcpy(p, pz);
Packit Service 96b5d3
            strcpy(p+siz-3, DFT_ENV_VAL);
Packit Service 96b5d3
            pz = p;
Packit Service 96b5d3
        }
Packit Service 96b5d3
Packit Service 96b5d3
        /*
Packit Service 96b5d3
         *  Now put it in the environment
Packit Service 96b5d3
         */
Packit Service 96b5d3
        putenv((char *)pz);
Packit Service 96b5d3
    } while (--ct > 0);
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 *  Open trace output file.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  If the name starts with a pipe character (vertical bar), then
Packit Service 96b5d3
 *  use popen on the command.  If it starts with ">>", then append
Packit Service 96b5d3
 *  to the file name that  follows that.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  The trace output starts with the command and arguments used to
Packit Service 96b5d3
 *  start autogen.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * @param[in] av    autogen's argument vector
Packit Service 96b5d3
 * @param[in] odsc  option descriptor with file name string argument
Packit Service 96b5d3
 */
Packit Service 96b5d3
static void
Packit Service 96b5d3
open_trace_file(char ** av, tOptDesc * odsc)
Packit Service 96b5d3
{
Packit Service 96b5d3
    char const * fname = odsc->optArg.argString;
Packit Service 96b5d3
Packit Service 96b5d3
    trace_is_to_pipe = (*fname == '|');
Packit Service 96b5d3
    if (trace_is_to_pipe)
Packit Service 96b5d3
        trace_fp = popen(++fname, "w");
Packit Service 96b5d3
Packit Service 96b5d3
    else if ((fname[0] == '>') && (fname[1] == '>')) {
Packit Service 96b5d3
        fname = SPN_WHITESPACE_CHARS(fname + 2);
Packit Service 96b5d3
        trace_fp = fopen(fname, "a");
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    else
Packit Service 96b5d3
        trace_fp = fopen(fname, "w");
Packit Service 96b5d3
Packit Service 96b5d3
    if (trace_fp == NULL)
Packit Service 96b5d3
        fserr(AUTOGEN_EXIT_FS_ERROR, "fopen", fname);
Packit Service 96b5d3
Packit Service 96b5d3
#ifdef _IONBF
Packit Service 96b5d3
    setvbuf(trace_fp, NULL, _IONBF, 0);
Packit Service 96b5d3
#endif
Packit Service 96b5d3
Packit Service 96b5d3
    fprintf(trace_fp, TRACE_START_FMT, (unsigned int)getpid(), *av);
Packit Service 96b5d3
    while (*(++av) != NULL)
Packit Service 96b5d3
        fprintf(trace_fp, TRACE_AG_ARG_FMT, *av);
Packit Service 96b5d3
    fprintf(trace_fp, TRACE_START_GUILE, libguile_ver);
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * Check the environment for make dependency info.  We look for
Packit Service 96b5d3
 * AUTOGEN_MAKE_DEP, but if that is not found, we also look for
Packit Service 96b5d3
 * DEPENDENCIES_OUTPUT.  To do dependency tracking at all, we
Packit Service 96b5d3
 * must find one of these environment variables and it must
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * * be non-empty
Packit Service 96b5d3
 * * not contain a variation on "no"
Packit Service 96b5d3
 * * not contain a variation on "false"
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * Furthermore, to specify a file name, the contents must not contain
Packit Service 96b5d3
 * some variation on "yes" or "true".
Packit Service 96b5d3
 */
Packit Service 96b5d3
static void
Packit Service 96b5d3
check_make_dep_env(void)
Packit Service 96b5d3
{
Packit Service 96b5d3
    bool have_opt_string = false;
Packit Service 96b5d3
    bool set_opt         = false;
Packit Service 96b5d3
Packit Service 96b5d3
    char const * mdep = getenv(AG_MAKE_DEP_NAME);
Packit Service 96b5d3
    if (mdep == NULL) {
Packit Service 96b5d3
        mdep = getenv(DEP_OUT_NAME);
Packit Service 96b5d3
        if (mdep == NULL)
Packit Service 96b5d3
            return;
Packit Service 96b5d3
    }
Packit Service 96b5d3
    switch (*mdep) {
Packit Service 96b5d3
    case NUL: break;
Packit Service 96b5d3
    case '1':
Packit Service 96b5d3
        set_opt = (mdep[0] == '1');
Packit Service 96b5d3
        /* FALLTHROUGH */
Packit Service 96b5d3
Packit Service 96b5d3
    case '0':
Packit Service 96b5d3
        if (mdep[1] != NUL)
Packit Service 96b5d3
            have_opt_string = true;
Packit Service 96b5d3
        break;
Packit Service 96b5d3
Packit Service 96b5d3
    case 'y':
Packit Service 96b5d3
    case 'Y':
Packit Service 96b5d3
        set_opt = true;
Packit Service 96b5d3
        have_opt_string = (streqvcmp(mdep + 1, YES_NAME_STR+1) != 0);
Packit Service 96b5d3
        break;
Packit Service 96b5d3
Packit Service 96b5d3
    case 'n':
Packit Service 96b5d3
    case 'N':
Packit Service 96b5d3
        set_opt = \
Packit Service 96b5d3
            have_opt_string = (streqvcmp(mdep + 1, NO_NAME_STR+1) != 0);
Packit Service 96b5d3
        break;
Packit Service 96b5d3
Packit Service 96b5d3
    case 't':
Packit Service 96b5d3
    case 'T':
Packit Service 96b5d3
        set_opt = true;
Packit Service 96b5d3
        have_opt_string = (streqvcmp(mdep + 1, TRUE_NAME_STR+1) != 0);
Packit Service 96b5d3
        break;
Packit Service 96b5d3
Packit Service 96b5d3
    case 'f':
Packit Service 96b5d3
    case 'F':
Packit Service 96b5d3
        set_opt = \
Packit Service 96b5d3
            have_opt_string = (streqvcmp(mdep + 1, FALSE_NAME_STR+1) != 0);
Packit Service 96b5d3
        break;
Packit Service 96b5d3
Packit Service 96b5d3
    default:
Packit Service 96b5d3
        have_opt_string = \
Packit Service 96b5d3
            set_opt = true;
Packit Service 96b5d3
    }
Packit Service 96b5d3
    if (! set_opt) return;
Packit Service 96b5d3
    if (! have_opt_string) {
Packit Service 96b5d3
        SET_OPT_MAKE_DEP("");
Packit Service 96b5d3
        return;
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    {
Packit Service 96b5d3
        char * pz = AGALOC(strlen(mdep) + 5, "mdep");
Packit Service 96b5d3
        char * fp = pz;
Packit Service 96b5d3
Packit Service 96b5d3
        *(pz++) = 'F';
Packit Service 96b5d3
        for (;;) {
Packit Service 96b5d3
            int ch = *(unsigned char *)(mdep++);
Packit Service 96b5d3
            if (IS_END_TOKEN_CHAR(ch))
Packit Service 96b5d3
                break;
Packit Service 96b5d3
Packit Service 96b5d3
            *(pz++) = (char)ch;
Packit Service 96b5d3
        }
Packit Service 96b5d3
        *pz = NUL;
Packit Service 96b5d3
Packit Service 96b5d3
        SET_OPT_SAVE_OPTS(fp);
Packit Service 96b5d3
        mdep = SPN_WHITESPACE_CHARS(mdep);
Packit Service 96b5d3
        if (*mdep == NUL)
Packit Service 96b5d3
            return;
Packit Service 96b5d3
Packit Service 96b5d3
        pz = fp;
Packit Service 96b5d3
        *(pz++) = 'T';
Packit Service 96b5d3
        for (;;) {
Packit Service 96b5d3
            int ch = *(unsigned char *)(mdep++);
Packit Service 96b5d3
            if (IS_END_TOKEN_CHAR(ch))
Packit Service 96b5d3
                break;
Packit Service 96b5d3
Packit Service 96b5d3
            *(pz++) = (char)ch;
Packit Service 96b5d3
        }
Packit Service 96b5d3
        *pz = NUL;
Packit Service 96b5d3
        SET_OPT_SAVE_OPTS(fp);
Packit Service 96b5d3
        AGFREE(fp);
Packit Service 96b5d3
    }
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
LOCAL void
Packit Service 96b5d3
process_ag_opts(int arg_ct, char ** arg_vec)
Packit Service 96b5d3
{
Packit Service 96b5d3
    /*
Packit Service 96b5d3
     *  Advance the argument counters and pointers past any
Packit Service 96b5d3
     *  command line options
Packit Service 96b5d3
     */
Packit Service 96b5d3
    {
Packit Service 96b5d3
        int  optCt = optionProcess(&autogenOptions, arg_ct, arg_vec);
Packit Service 96b5d3
Packit Service 96b5d3
        /*
Packit Service 96b5d3
         *  Make sure we have a source file, even if it is "-" (stdin)
Packit Service 96b5d3
         */
Packit Service 96b5d3
        switch (arg_ct - optCt) {
Packit Service 96b5d3
        case 1:
Packit Service 96b5d3
            if (! HAVE_OPT(DEFINITIONS)) {
Packit Service 96b5d3
                OPT_ARG(DEFINITIONS) = *(arg_vec + optCt);
Packit Service 96b5d3
                break;
Packit Service 96b5d3
            }
Packit Service 96b5d3
            /* FALLTHROUGH */
Packit Service 96b5d3
Packit Service 96b5d3
        default:
Packit Service 96b5d3
            usage_message(DOOPT_TOO_MANY_DEFS, ag_pname);
Packit Service 96b5d3
            /* NOTREACHED */
Packit Service 96b5d3
Packit Service 96b5d3
        case 0:
Packit Service 96b5d3
            if (! HAVE_OPT(DEFINITIONS))
Packit Service 96b5d3
                OPT_ARG(DEFINITIONS) = DFT_DEF_INPUT_STR;
Packit Service 96b5d3
            break;
Packit Service 96b5d3
        }
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    if ((OPT_VALUE_TRACE > TRACE_NOTHING) && HAVE_OPT(TRACE_OUT))
Packit Service 96b5d3
        open_trace_file(arg_vec, &DESC(TRACE_OUT));
Packit Service 96b5d3
Packit Service 96b5d3
    start_time = time(NULL) - 1;
Packit Service 96b5d3
Packit Service 96b5d3
    if (! HAVE_OPT(TIMEOUT))
Packit Service 96b5d3
        OPT_ARG(TIMEOUT) = (char const *)AG_DEFAULT_TIMEOUT;
Packit Service 96b5d3
Packit Service 96b5d3
    /*
Packit Service 96b5d3
     *  IF the definitions file has been disabled,
Packit Service 96b5d3
     *  THEN a template *must* have been specified.
Packit Service 96b5d3
     */
Packit Service 96b5d3
    if (  (! ENABLED_OPT(DEFINITIONS))
Packit Service 96b5d3
       && (! HAVE_OPT(OVERRIDE_TPL)) )
Packit Service 96b5d3
        AG_ABEND(NO_TEMPLATE_ERR_MSG);
Packit Service 96b5d3
Packit Service 96b5d3
    /*
Packit Service 96b5d3
     *  IF we do not have a base-name option, then we compute some value
Packit Service 96b5d3
     */
Packit Service 96b5d3
    if (! HAVE_OPT(BASE_NAME))
Packit Service 96b5d3
        define_base_name();
Packit Service 96b5d3
Packit Service 96b5d3
    check_make_dep_env();
Packit Service 96b5d3
Packit Service 96b5d3
    if (HAVE_OPT(MAKE_DEP))
Packit Service 96b5d3
        start_dep_file();
Packit Service 96b5d3
Packit Service 96b5d3
    strequate(OPT_ARG(EQUATE));
Packit Service 96b5d3
Packit Service 96b5d3
    /*
Packit Service 96b5d3
     *  IF we have some defines to put in our environment, ...
Packit Service 96b5d3
     */
Packit Service 96b5d3
    if (HAVE_OPT(DEFINE))
Packit Service 96b5d3
        put_defines_into_env();
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 *  look for a define string.  It may be in our DEFINE option list
Packit Service 96b5d3
 *  (preferred result) or in the environment.  Look up both.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  @param[in] de_name   name to look for
Packit Service 96b5d3
 *  @param[in] check_env whether or not to look in environment
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  @returns a pointer to the string, if found, or NULL.
Packit Service 96b5d3
 */
Packit Service 96b5d3
LOCAL char const *
Packit Service 96b5d3
get_define_str(char const * de_name, bool check_env)
Packit Service 96b5d3
{
Packit Service 96b5d3
    char const **   ppz;
Packit Service 96b5d3
    int     ct;
Packit Service 96b5d3
    if (HAVE_OPT(DEFINE)) {
Packit Service 96b5d3
        ct  = STACKCT_OPT( DEFINE);
Packit Service 96b5d3
        ppz = STACKLST_OPT(DEFINE);
Packit Service 96b5d3
Packit Service 96b5d3
        while (ct-- > 0) {
Packit Service 96b5d3
            char const * pz   = *(ppz++);
Packit Service 96b5d3
            char * pzEq = strchr(pz, '=');
Packit Service 96b5d3
            int    res;
Packit Service 96b5d3
Packit Service 96b5d3
            if (pzEq != NULL)
Packit Service 96b5d3
                *pzEq = NUL;
Packit Service 96b5d3
Packit Service 96b5d3
            res = strcmp(de_name, pz);
Packit Service 96b5d3
            if (pzEq != NULL)
Packit Service 96b5d3
                *pzEq = '=';
Packit Service 96b5d3
Packit Service 96b5d3
            if (res == 0)
Packit Service 96b5d3
                return (pzEq != NULL) ? pzEq+1 : zNil;
Packit Service 96b5d3
        }
Packit Service 96b5d3
    }
Packit Service 96b5d3
    return check_env ? getenv(de_name) : NULL;
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 *  The following routine scans over quoted text, shifting it in the process
Packit Service 96b5d3
 *  and eliminating the starting quote, ending quote and any embedded
Packit Service 96b5d3
 *  backslashes.  They may be used to embed the quote character in the quoted
Packit Service 96b5d3
 *  text.  The quote character is whatever character the argument is pointing
Packit Service 96b5d3
 *  at when this procedure is called.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  @param[in,out] in_q   input quoted string/output unquoted
Packit Service 96b5d3
 *  @returns the address of the byte after the original closing quote.
Packit Service 96b5d3
 */
Packit Service 96b5d3
LOCAL char *
Packit Service 96b5d3
span_quote(char * in_q)
Packit Service 96b5d3
{
Packit Service 96b5d3
    char   qc = *in_q;          /*  Save the quote character type */
Packit Service 96b5d3
    char * dp = in_q++;         /*  Destination pointer           */
Packit Service 96b5d3
Packit Service 96b5d3
    while (*in_q != qc) {
Packit Service 96b5d3
        switch (*dp++ = *in_q++) {
Packit Service 96b5d3
        case NUL:
Packit Service 96b5d3
            return in_q-1;      /* Return address of terminating NUL */
Packit Service 96b5d3
Packit Service 96b5d3
        case '\\':
Packit Service 96b5d3
            if (qc != '\'') {
Packit Service 96b5d3
                int ct = (int)ao_string_cook_escape_char(in_q, dp-1, 0x7F);
Packit Service 96b5d3
                if (dp[-1] == 0x7F)  dp--;
Packit Service 96b5d3
                in_q += ct;
Packit Service 96b5d3
Packit Service 96b5d3
            } else
Packit Service 96b5d3
                switch (*in_q) {
Packit Service 96b5d3
                case '\\':
Packit Service 96b5d3
                case '\'':
Packit Service 96b5d3
                case '#':
Packit Service 96b5d3
                    dp[-1] = *in_q++;
Packit Service 96b5d3
                }
Packit Service 96b5d3
            break;
Packit Service 96b5d3
Packit Service 96b5d3
        default:
Packit Service 96b5d3
            ;
Packit Service 96b5d3
        }
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    *dp = NUL;
Packit Service 96b5d3
    return in_q+1; /* Return addr of char after the terminating quote */
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 *  The following routine skips over quoted text.  The quote character is
Packit Service 96b5d3
 *  whatever character the argument is pointing at when this procedure is
Packit Service 96b5d3
 *  called.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 *  @param[in] qstr   input quoted string/output unquoted
Packit Service 96b5d3
 *  @returns the address of the byte after the original closing quote.
Packit Service 96b5d3
 */
Packit Service 96b5d3
static char const *
Packit Service 96b5d3
skip_quote(char const * qstr)
Packit Service 96b5d3
{
Packit Service 96b5d3
    char qc = *qstr++;        /*  Save the quote character type */
Packit Service 96b5d3
Packit Service 96b5d3
    while (*qstr != qc) {
Packit Service 96b5d3
        switch (*qstr++) {
Packit Service 96b5d3
        case NUL:
Packit Service 96b5d3
            return qstr-1;      /* Return address of terminating NUL */
Packit Service 96b5d3
Packit Service 96b5d3
        case '\\':
Packit Service 96b5d3
            if (qc == '\'') {
Packit Service 96b5d3
                /*
Packit Service 96b5d3
                 *  Single quoted strings process the backquote specially
Packit Service 96b5d3
                 *  only in front of these three characters:
Packit Service 96b5d3
                 */
Packit Service 96b5d3
                switch (*qstr) {
Packit Service 96b5d3
                case '\\':
Packit Service 96b5d3
                case '\'':
Packit Service 96b5d3
                case '#':
Packit Service 96b5d3
                    qstr++;
Packit Service 96b5d3
                }
Packit Service 96b5d3
Packit Service 96b5d3
            } else {
Packit Service 96b5d3
                char p[10];  /* provide a scratch pad for escape processing */
Packit Service 96b5d3
                qstr += ao_string_cook_escape_char(qstr, p, 0x7F);
Packit Service 96b5d3
            } /* if (q == '\'')      */
Packit Service 96b5d3
        }     /* switch (*qstr++)   */
Packit Service 96b5d3
    }         /* while (*qstr != q) */
Packit Service 96b5d3
Packit Service 96b5d3
    return qstr+1; /* Return addr of char after the terminating quote */
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * Skip over scheme expression.  We need to find what follows it.
Packit Service 96b5d3
 * Guile will carefully parse it later.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * @param[in]  scan  where to start search
Packit Service 96b5d3
 * @param[in]  end   point beyond which not to go
Packit Service 96b5d3
 * @returns    character after closing parenthesis or "end",
Packit Service 96b5d3
 * which ever comes first.
Packit Service 96b5d3
 */
Packit Service 96b5d3
LOCAL char const *
Packit Service 96b5d3
skip_scheme(char const * scan,  char const * end)
Packit Service 96b5d3
{
Packit Service 96b5d3
    int  level = 0;
Packit Service 96b5d3
Packit Service 96b5d3
    for (;;) {
Packit Service 96b5d3
        scan = BRK_SCHEME_NOTE_CHARS(scan);
Packit Service 96b5d3
        if (scan >= end)
Packit Service 96b5d3
            return end;
Packit Service 96b5d3
Packit Service 96b5d3
        switch (*(scan++)) {
Packit Service 96b5d3
        case '(':
Packit Service 96b5d3
            level++;
Packit Service 96b5d3
            break;
Packit Service 96b5d3
Packit Service 96b5d3
        case ')':
Packit Service 96b5d3
            if (--level == 0)
Packit Service 96b5d3
                return scan;
Packit Service 96b5d3
            break;
Packit Service 96b5d3
Packit Service 96b5d3
        case '"':
Packit Service 96b5d3
            scan = skip_quote(scan-1);
Packit Service 96b5d3
        }
Packit Service 96b5d3
    }
Packit Service 96b5d3
}
Packit Service 96b5d3
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * scan past an expression.  An expression is either a Scheme
Packit Service 96b5d3
 * expression starting and ending with balanced parentheses,
Packit Service 96b5d3
 * or a quoted string or a sequence of non-whitespace characters.
Packit Service 96b5d3
 * semicolons denote a comment that extends to the next newline.
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * @param [in]  src  input text
Packit Service 96b5d3
 * @param [in]  len  the maximum length to scan over
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * @returns a pointer to the character next after the expression end.
Packit Service 96b5d3
 */
Packit Service 96b5d3
LOCAL char const *
Packit Service 96b5d3
skip_expr(char const * src, size_t len)
Packit Service 96b5d3
{
Packit Service 96b5d3
    char const * end = src + len;
Packit Service 96b5d3
Packit Service 96b5d3
 guess_again:
Packit Service 96b5d3
Packit Service 96b5d3
    src = SPN_WHITESPACE_CHARS(src);
Packit Service 96b5d3
    if (src >= end)
Packit Service 96b5d3
        return end;
Packit Service 96b5d3
    switch (*src) {
Packit Service 96b5d3
    case ';':
Packit Service 96b5d3
        src = strchr(src, NL);
Packit Service 96b5d3
        if (src == NULL)
Packit Service 96b5d3
            return end;
Packit Service 96b5d3
        goto guess_again;
Packit Service 96b5d3
Packit Service 96b5d3
    case '(':
Packit Service 96b5d3
        return skip_scheme(src, end);
Packit Service 96b5d3
Packit Service 96b5d3
    case '"':
Packit Service 96b5d3
    case '\'':
Packit Service 96b5d3
    case '`':
Packit Service 96b5d3
        src = skip_quote(src);
Packit Service 96b5d3
        return (src > end) ? end : src;
Packit Service 96b5d3
Packit Service 96b5d3
    default:
Packit Service 96b5d3
        break;
Packit Service 96b5d3
    }
Packit Service 96b5d3
Packit Service 96b5d3
    src = BRK_WHITESPACE_CHARS(src);
Packit Service 96b5d3
    return (src > end) ? end : src;
Packit Service 96b5d3
}
Packit Service 96b5d3
/**
Packit Service 96b5d3
 * @}
Packit Service 96b5d3
 *
Packit Service 96b5d3
 * Local Variables:
Packit Service 96b5d3
 * mode: C
Packit Service 96b5d3
 * c-file-style: "stroustrup"
Packit Service 96b5d3
 * indent-tabs-mode: nil
Packit Service 96b5d3
 * End:
Packit Service 96b5d3
 * end of agen5/agUtils.c */