Beispiel #1
0
/**
 * Configure a dependency option.
 * Handles any of these letters:  MFQTPGD as the first part of the option
 * argument.
 *
 * @param opts the autogen options data structure
 * @param pOptDesc the option descriptor for this option.
 */
LOCAL void
config_dep(tOptions * opts, tOptDesc * od)
{
    char const * opt_arg = od->optArg.argString;
    (void)opts;

    /*
     *  The option argument is optional.  Make sure we have one.
     */
    if (opt_arg == NULL)
        return;

    while (*opt_arg == 'M')  opt_arg++;
    opt_arg = SPN_WHITESPACE_CHARS(opt_arg);

    switch (*opt_arg) {
    case 'F':
        if (dep_file != NULL)
            dep_usage(CFGDEP_DUP_TARGET_MSG);

        opt_arg = SPN_WHITESPACE_CHARS(opt_arg + 1);
        AGDUPSTR(dep_file, opt_arg, "f name");
        break;

    case 'Q':
    case 'T':
    {
        bool quote_it = (*opt_arg == 'Q');

        if (dep_target != NULL)
            dep_usage(CFGDEP_DUP_TARGET_MSG);

        opt_arg = SPN_WHITESPACE_CHARS(opt_arg + 1);
        if (quote_it)
            dep_target = make_quote_str(opt_arg);
        else
            AGDUPSTR(dep_target, opt_arg, "t name");
        break;
    }

    case 'P':
        dep_phonies = true;
        break;

    case 'D':
    case 'G':
    case NUL:
        /*
         *  'D' and 'G' make sense to GCC, not us.  Ignore 'em.  If we
         *  found a NUL byte, then act like we found -MM on the command line.
         */
        break;

    default:
        dep_usage(CFGDEP_UNKNOWN_DEP_FMT, opt_arg);
    }
}
Beispiel #2
0
/*=export_func  optionStackArg
 * private:
 *
 * what:  put option args on a stack
 * arg:   + tOptions* + opts + program options descriptor +
 * arg:   + tOptDesc* + od   + the descriptor for this arg +
 *
 * doc:
 *  Keep an entry-ordered list of option arguments.
=*/
void
optionStackArg(tOptions * opts, tOptDesc * od)
{
    char * pz;

    if (INQUERY_CALL(opts, od))
        return;

    if ((od->fOptState & OPTST_RESET) != 0) {
        tArgList * arg_list = (void*)od->optCookie;
        int ix;
        if (arg_list == NULL)
            return;

        ix = arg_list->useCt;
        while (--ix >= 0)
            AGFREE(arg_list->apzArgs[ix]);
        AGFREE(arg_list);

    } else {
        if (od->optArg.argString == NULL)
            return;

        AGDUPSTR(pz, od->optArg.argString, "stack arg");
        addArgListEntry(&(od->optCookie), (void*)pz);
    }
}
Beispiel #3
0
/*
 *  optionFixupSavedOpts  Really, it just wipes out option state for
 *  options that are troublesome to copy.  viz., stacked strings and
 *  hierarcicaly valued option args.  We do duplicate string args that
 *  have been marked as allocated though.
 */
static void
fixupSavedOptionArgs(tOptions* pOpts)
{
    tOptions* p   = pOpts->pSavedState;
    tOptDesc* pOD = pOpts->pOptDesc;
    int       ct  = pOpts->optCt;

    /*
     *  Make sure that allocated stuff is only referenced in the
     *  archived copy of the data.
     */
    for (; ct-- > 0; pOD++)  {
        switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
        case OPARG_TYPE_STRING:
            if (pOD->fOptState & OPTST_STACKED) {
                tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc);
                q->optCookie = NULL;
            }
            if (pOD->fOptState & OPTST_ALLOC_ARG) {
                tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc);
                AGDUPSTR(q->optArg.argString, pOD->optArg.argString, "arg");
            }
            break;

        case OPARG_TYPE_HIERARCHY:
        {
            tOptDesc* q = p->pOptDesc + (pOD - pOpts->pOptDesc);
            q->optCookie = NULL;
        }
        }
    }
}
Beispiel #4
0
/*=export_func  optionStackArg
 * private:
 *
 * what:  put option args on a stack
 * arg:   + tOptions* + pOpts    + program options descriptor +
 * arg:   + tOptDesc* + pOptDesc + the descriptor for this arg +
 *
 * doc:
 *  Keep an entry-ordered list of option arguments.
=*/
void
optionStackArg(
    tOptions*  pOpts,
    tOptDesc*  pOD )
{
    char * pz;

    if ((pOD->fOptState & OPTST_RESET) != 0) {
        tArgList* pAL = (void*)pOD->optCookie;
        int ix;
        if (pAL == NULL)
            return;

        ix = pAL->useCt;
        while (--ix >= 0)
            AGFREE(pAL->apzArgs[ix]);
        AGFREE(pAL);

    } else {
        if (pOD->optArg.argString == NULL)
            return;

        AGDUPSTR(pz, pOD->optArg.argString, "stack arg");
        addArgListEntry( &(pOD->optCookie), (void*)pz );
    }
}
Beispiel #5
0
/**
 *  Alters the current line number and/or file name.  You may wish to
 *  use this directive if you extract definition source from other files.
 *  @command{getdefs} uses this mechanism so AutoGen will report the correct
 *  file and approximate line number of any errors found in extracted
 *  definitions.
 */
char *
doDir_line(directive_enum_t id, char const * dir, char * scan_next)
{
    (void)id;
    /*
     *  The sequence must be:  #line <number> "file-name-string"
     *
     *  Start by scanning up to and extracting the line number.
     */
    dir = SPN_WHITESPACE_CHARS(dir);
    if (! IS_DEC_DIGIT_CHAR(*dir))
        return scan_next;

    cctx->scx_line = (int)strtol(dir, (char **)&dir, 0);

    /*
     *  Now extract the quoted file name string.
     *  We dup the string so it won't disappear on us.
     */
    dir = SPN_WHITESPACE_CHARS(dir);
    if (*(dir++) != '"')
        return scan_next;
    {
        char * pz = strchr(dir, '"');
        if (pz == NULL)
            return scan_next;
        *pz = NUL;
    }

    AGDUPSTR(cctx->scx_fname, dir, "#line");

    return scan_next;
}
Beispiel #6
0
/*=directive line
 *
 *  text:
 *
 *  Alters the current line number and/or file name.  You may wish to
 *  use this directive if you extract definition source from other files.
 *  @command{getdefs} uses this mechanism so AutoGen will report the correct
 *  file and approximate line number of any errors found in extracted
 *  definitions.
=*/
static char*
doDir_line(char* pzArg, char* pzScan)
{
    /*
     *  The sequence must be:  #line <number> "file-name-string"
     *
     *  Start by scanning up to and extracting the line number.
     */
    while (IS_WHITESPACE_CHAR(*pzArg)) pzArg++;
    if (! IS_DEC_DIGIT_CHAR(*pzArg))
        return pzScan;

    pCurCtx->lineNo = strtol(pzArg, &pzArg, 0);

    /*
     *  Now extract the quoted file name string.
     *  We dup the string so it won't disappear on us.
     */
    while (IS_WHITESPACE_CHAR(*pzArg)) pzArg++;
    if (*(pzArg++) != '"')
        return pzScan;
    {
        char* pz = strchr(pzArg, '"');
        if (pz == NULL)
            return pzScan;
        *pz = NUL;
    }

    AGDUPSTR(pCurCtx->pzCtxFname, pzArg, "#line file name");

    return pzScan;
}
Beispiel #7
0
static inline char *
ao_xstrdup(char const * pz)
{
    char * str;
    AGDUPSTR(str, pz, "time val str");
    return str;
}
Beispiel #8
0
/*=export_func  optionLoadLine
 *
 * what:  process a string for an option name and value
 *
 * arg:   tOptions*,   pOpts,  program options descriptor
 * arg:   char const*, pzLine, NUL-terminated text
 *
 * doc:
 *
 *  This is a client program callable routine for setting options from, for
 *  example, the contents of a file that they read in.  Only one option may
 *  appear in the text.  It will be treated as a normal (non-preset) option.
 *
 *  When passed a pointer to the option struct and a string, it will find
 *  the option named by the first token on the string and set the option
 *  argument to the remainder of the string.  The caller must NUL terminate
 *  the string.  Any embedded new lines will be included in the option
 *  argument.  If the input looks like one or more quoted strings, then the
 *  input will be "cooked".  The "cooking" is identical to the string
 *  formation used in AutoGen definition files (@pxref{basic expression}),
 *  except that you may not use backquotes.
 *
 * err:   Invalid options are silently ignored.  Invalid option arguments
 *        will cause a warning to print, but the function should return.
=*/
void
optionLoadLine(tOptions * pOpts, char const * pzLine)
{
    tOptState st = OPTSTATE_INITIALIZER(SET);
    char* pz;
    AGDUPSTR(pz, pzLine, "user option line");
    loadOptionLine(pOpts, &st, pz, DIRECTION_PROCESS, OPTION_LOAD_COOKED);
    AGFREE(pz);
}
Beispiel #9
0
/**
 *  Finish off the dependency file
 */
static void
wrap_up_depends(void)
{
    static mode_t const fil_mode =
        S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;

    static char const fmt[] =
        "\n\n%1$s_SList =%2$s\n"
        "\n%3$s : $(%1$s_SList)\n"
        "\n$(%1$s_TList) : %3$s\n"
        "\t@:\n";

    fprintf(pfDepends, fmt, pz_targ_base, pzSourceList, pzDepTarget);
    fclose(pfDepends);
    pfDepends = NULL;

    /*
     * "startTime" is engineered to be 1 second earlier than the mod time
     * of any of the output files.
     */
    {
        struct utimbuf tbuf = {
            .actime  = time(NULL),
            .modtime = startTime
        };

        utime(pzDepFile, &tbuf);

        /*
         * If the target is not the dependency file, then ensure that the
         * file exists and set its time to the same time.  Ignore all errors.
         */
        if (strcmp(pzDepFile, pzDepTarget) != 0) {
            if (access(pzDepTarget, R_OK) != 0)
                close( open(pzDepTarget, O_CREAT, fil_mode));

            utime(pzDepTarget, &tbuf);
        }
    }

    chmod(pzDepFile, fil_mode);

    /*
     * Trim off the temporary suffix and rename the dependency file into
     * place.  We used a mkstemp name in case autogen failed.
     */
    {
        char * pze = strrchr(pzDepFile, '-');
        char * pzn;

        *pze = NUL;
        AGDUPSTR(pzn, pzDepFile, "dep file");
        *pze = '-';
        rename(pzDepFile, pzn);
        AGFREE(pzn);
    }
}
Beispiel #10
0
/*=export_func  optionLoadLine
 *
 * what:  process a string for an option name and value
 *
 * arg:   tOptions *,   opts,  program options descriptor
 * arg:   char const *, line,  NUL-terminated text
 *
 * doc:
 *
 *  This is a client program callable routine for setting options from, for
 *  example, the contents of a file that they read in.  Only one option may
 *  appear in the text.  It will be treated as a normal (non-preset) option.
 *
 *  When passed a pointer to the option struct and a string, it will find
 *  the option named by the first token on the string and set the option
 *  argument to the remainder of the string.  The caller must NUL terminate
 *  the string.  The caller need not skip over any introductory hyphens.
 *  Any embedded new lines will be included in the option
 *  argument.  If the input looks like one or more quoted strings, then the
 *  input will be "cooked".  The "cooking" is identical to the string
 *  formation used in AutoGen definition files (@pxref{basic expression}),
 *  except that you may not use backquotes.
 *
 * err:   Invalid options are silently ignored.  Invalid option arguments
 *        will cause a warning to print, but the function should return.
=*/
void
optionLoadLine(tOptions * opts, char const * line)
{
    tOptState st = OPTSTATE_INITIALIZER(SET);
    char *    pz;
    proc_state_mask_t sv_flags = opts->fOptSet;
    opts->fOptSet &= ~OPTPROC_ERRSTOP;
    AGDUPSTR(pz, line, "opt line");
    load_opt_line(opts, &st, pz, DIRECTION_CALLED, OPTION_LOAD_COOKED);
    AGFREE(pz);
    opts->fOptSet = sv_flags;
}
Beispiel #11
0
/*=gfunc string_contains_eqv_p
 *
 * what:   caseless substring
 * general_use:
 *
 * exparg: text, text to test for pattern
 * exparg: match, pattern/substring to search for
 *
 * string: "*=*"
 *
 * doc:  Test to see if a string contains an equivalent string.
 *       `equivalent' means the strings match, but without regard
 *       to character case and certain characters are considered `equivalent'.
 *       Viz., '-', '_' and '^' are equivalent.
=*/
static tSuccess
Select_Equivalent(char const * sample, char const * pattern)
{
    char*    pz;
    tSuccess res = SUCCESS;
    AGDUPSTR(pz, sample, "equiv chars");
    upString(pz);
    if (strstr(pz, pattern) == NULL)
        res = FAILURE;
    AGFREE((void*)pz);

    return res;
}
Beispiel #12
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;
}
Beispiel #13
0
/**
 *  Open the specified file with open(2) and save the FD.
 *
 * @param pOpts program option descriptor
 * @param pOD   the option descriptor
 * @param mode  the open mode (uses int flags value)
 */
static void
open_file_fd(tOptions * pOpts, tOptDesc * pOD, tuFileMode mode)
{
    int fd = open(pOD->optArg.argString, mode.file_flags);
    if (fd < 0)
        fserr_exit(pOpts->pzProgName, "open", pOD->optArg.argString);
        /* NOTREACHED */

    if ((pOD->fOptState & OPTST_ALLOC_ARG) != 0)
        pOD->optCookie = (void *)(intptr_t)pOD->optArg.argString;
    else
        AGDUPSTR(pOD->optCookie, pOD->optArg.argString, "file name");

    pOD->optArg.argFd = fd;
    pOD->fOptState &= ~OPTST_ALLOC_ARG;
}
Beispiel #14
0
/**
 *  Open the specified file with open(2) and save the FD.
 *
 * @param pOpts program option descriptor
 * @param pOD   the option descriptor
 * @param mode  the open mode (uses "char *" mode value)
 */
static void
fopen_file_fp(tOptions * pOpts, tOptDesc * pOD, tuFileMode mode)
{
    FILE * fp = fopen(pOD->optArg.argString, mode.file_mode);
    if (fp == NULL)
        fserr_exit(pOpts->pzProgName, "fopen", pOD->optArg.argString);
        /* NOTREACHED */

    if ((pOD->fOptState & OPTST_ALLOC_ARG) != 0)
        pOD->optCookie = (void *)(intptr_t)pOD->optArg.argString;
    else
        AGDUPSTR(pOD->optCookie, pOD->optArg.argString, "file name");

    pOD->optArg.argFp = fp;
    pOD->fOptState &= ~OPTST_ALLOC_ARG;
}
Beispiel #15
0
SCM
ag_scm_string_contains_eqv_p(SCM text, SCM substr)
{
    static char const zSrch[] = "search string";
    char* pzSubstr;
    SCM   res;

    AGDUPSTR(pzSubstr, ag_scm2zchars( substr, zSrch ), "substring");

    upString(pzSubstr);
    if (SUCCESSFUL(Select_Equivalent(ag_scm2zchars(text, "sample text"),
                                     pzSubstr)))
         res = SCM_BOOL_T;
    else res = SCM_BOOL_F;
    AGFREE((void*)pzSubstr);
    return res;
}
Beispiel #16
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);
    }
}
Beispiel #17
0
/*=export_func  optionPrintParagraphs
 * private:
 *
 * what:  Print a paragraph of usage text
 * arg:   + char const * + text  + a block of text that has bee i18n-ed +
 * arg:   + bool         + plain + false -> wrap text in fputs()        +
 * arg:   + FILE *       + fp    + the stream file pointer for output   +
 *
 * doc:
 *  This procedure is called in two contexts: when a full or short usage text
 *  has been provided for display, and when autogen is assembling a list of
 *  translatable texts in the optmain.tlib template.  In the former case, \a
 *  plain is set to \a true, otherwise \a false.
 *
 *  Anything less than 256 characters in size is printed as a single unit.
 *  Otherwise, paragraphs are detected.  A paragraph break is defined as just
 *  before a non-empty line preceded by two newlines or a line that starts
 *  with at least one space character but fewer than 8 space characters.
 *  Lines indented with tabs or more than 7 spaces are considered continuation
 *  lines.
 *
 *  If 'plain' is true, we are emitting text for a user to see.  So, if it is
 *  true and NLS is not enabled, then just write the whole thing at once.
=*/
void
optionPrintParagraphs(char const * text, bool plain, FILE * fp)
{
    size_t len = strlen(text);
    char * buf;
#ifndef ENABLE_NLS
    if (plain || (len < 256))
#else
    if (len < 256)
#endif
    {
        print_one_paragraph(text, plain, fp);
        return;
    }

    AGDUPSTR(buf, text, "ppara");
    text = buf;

    for (;;) {
        char * scan;

        if (len < 256) {
        done:
            print_one_paragraph(buf, plain, fp);
            break;
        }
        scan = buf;

    try_longer:
        scan = strchr(scan, NL);
        if (scan == NULL)
            goto done;

        if ((scan - buf) < 8) {
            scan++;
            goto try_longer;
        }

        scan++;
        if ((! isspace((int)*scan)) || (*scan == HT))
            /*
             * line starts with tab or non-whitespace --> continuation
             */
            goto try_longer;

        if (*scan == NL) {
            /*
             * Double newline -> paragraph break
             * Include all newlines in current paragraph.
             */
            while (*++scan == NL)  /*continue*/;

        } else {
            char * p = scan;
            int   sp_ct = 0;

            while (*p == ' ') {
                if (++sp_ct >= 8) {
                    /*
                     * Too many spaces --> continuation line
                     */
                    scan = p;
                    goto try_longer;
                }
                p++;
            }
        }

        /*
         * "scan" points to the first character of a paragraph or the
         * terminating NUL byte.
         */
        {
            char svch = *scan;
            *scan = NUL;
            print_one_paragraph(buf, plain, fp);
            len -= scan - buf;
            if (len <= 0)
                break;
            *scan = svch;
            buf = scan;
        }
    }
    AGFREE((void *)text);
}
Beispiel #18
0
/**
 *  Starting with the current directory, search the directory
 *  list trying to find the base template file name.
 */
LOCAL tSuccess
findFile(char const * pzFName,
         char * pzFullName,
         char const * const * papSuffixList,
         char const * pzReferrer)
{
    char * pzRoot;
    char * pzSfx;
    void * deallocAddr = NULL;

    tSuccess res = SUCCESS;

    /*
     *  Expand leading environment variables.
     *  We will not mess with embedded ones.
     */
    if (*pzFName == '$') {
        if (! optionMakePath(pzFullName, (int)AG_PATH_MAX, pzFName,
                             autogenOptions.pzProgPath))
            return FAILURE;

        AGDUPSTR(pzFName, pzFullName, "find file name");
        deallocAddr = (void*)pzFName;

        /*
         *  pzFName now points to the name the file system can use.
         *  It must _not_ point to pzFullName because we will likely
         *  rewrite that value using this pointer!
         */
    }

    /*
     *  Not a complete file name.  If there is not already
     *  a suffix for the file name, then append ".tpl".
     *  Check for immediate access once again.
     */
    pzRoot = strrchr(pzFName, '/');
    pzSfx  = (pzRoot != NULL)
             ? strchr(++pzRoot, '.')
             : strchr(pzFName,  '.');

    /*
     *  The referrer is useful only if it includes a directory name.
     */
    if (pzReferrer != NULL) {
        char * pz = strrchr(pzReferrer, '/');
        if (pz == NULL)
            pzReferrer = NULL;
        else {
            AGDUPSTR(pzReferrer, pzReferrer, "pzReferrer");
            pz = strrchr(pzReferrer, '/');
            *pz = NUL;
        }
    }

    /*
     *  IF the file name does not contain a directory separator,
     *  then we will use the TEMPL_DIR search list to keep hunting.
     */
    {
        static char const curdir[]  = ".";
        static char const zDirFmt[] = "%s/%s";

        /*
         *  Search each directory in our directory search list
         *  for the file.  We always force one copy of this option.
         */
        int  ct = STACKCT_OPT(TEMPL_DIRS);
        char const ** ppzDir = STACKLST_OPT(TEMPL_DIRS) + ct - 1;
        char const *  pzDir  = curdir;

        if (*pzFName == '/')
            ct = 0;

        do  {
            char * pzEnd;
            void * coerce;

            /*
             *  IF one of our template paths starts with '$', then expand it.
             */
            if (*pzDir == '$') {
                if (! optionMakePath(pzFullName, (int)AG_PATH_MAX, pzDir,
                                     autogenOptions.pzProgPath)) {
                    coerce = (void *)pzDir;
                    strcpy(coerce, curdir);

                } else {
                    AGDUPSTR(pzDir, pzFullName, "find directory name");
                    coerce = (void *)ppzDir[1];
                    free(coerce);
                    ppzDir[1] = pzDir; /* save the computed name for later */
                }
            }

            if ((*pzFName == '/') || (pzDir == curdir)) {
                size_t nln = strlen(pzFName);
                if (nln >= AG_PATH_MAX - MAX_SUFFIX_LEN)
                    break;

                memcpy(pzFullName, pzFName, nln);
                pzEnd  = pzFullName + nln;
                *pzEnd = NUL;
            }
            else {
                pzEnd = pzFullName
                    + snprintf(pzFullName, AG_PATH_MAX - MAX_SUFFIX_LEN,
                               zDirFmt, pzDir, pzFName);
            }

            if (read_okay(pzFullName))
                goto findFileReturn;

            /*
             *  IF the file does not already have a suffix,
             *  THEN try the ones that are okay for this file.
             */
            if ((pzSfx == NULL) && (papSuffixList != NULL)) {
                char const * const * papSL = papSuffixList;
                *(pzEnd++) = '.';

                do  {
                    strcpy(pzEnd, *(papSL++)); /* must fit */
                    if (read_okay(pzFullName))
                        goto findFileReturn;

                } while (*papSL != NULL);
            }

            if (*pzFName == '/')
                break;

            /*
             *  IF there is a referrer, use it before the rest of the
             *  TEMPL_DIRS We detect first time through by *both* pzDir value
             *  and ct value.  "ct" will have this same value next time
             *  through and occasionally "pzDir" will be set to "curdir", but
             *  never again when ct is STACKCT_OPT(TEMPL_DIRS)
             */
            if (  (pzReferrer != NULL)
               && (pzDir == curdir)
               && (ct == STACKCT_OPT(TEMPL_DIRS))) {

                pzDir = pzReferrer;
                ct++;

            } else {
                pzDir = *(ppzDir--);
            }
        } while (--ct >= 0);
    }

    res = FAILURE;

 findFileReturn:
    AGFREE(deallocAddr);
    AGFREE(pzReferrer);
    return res;
}
Beispiel #19
0
/**
 *  Load an option from a block of text.  The text must start with the
 *  configurable/option name and be followed by its associated value.
 *  That value may be processed in any of several ways.  See "tOptionLoadMode"
 *  in autoopts.h.
 *
 * @param[in,out] opts       program options descriptor
 * @param[in,out] opt_state  option processing state
 * @param[in,out] line       source line with long option name in it
 * @param[in]     direction  current processing direction (preset or not)
 * @param[in]     load_mode  option loading mode (OPTION_LOAD_*)
 */
LOCAL void
loadOptionLine(
    tOptions *  opts,
    tOptState * opt_state,
    char *      line,
    tDirection  direction,
    tOptionLoadMode   load_mode )
{
    line = SPN_LOAD_LINE_SKIP_CHARS(line);

    {
        char * arg = assemble_arg_val(line, load_mode);

        if (! SUCCESSFUL(opt_find_long(opts, line, opt_state)))
            return;

        if (opt_state->flags & OPTST_NO_INIT)
            return;

        opt_state->pzOptArg = arg;
    }

    switch (opt_state->flags & (OPTST_IMM|OPTST_DISABLE_IMM)) {
    case 0:
        /*
         *  The selected option has no immediate action.
         *  THEREFORE, if the direction is PRESETTING
         *  THEN we skip this option.
         */
        if (PRESETTING(direction))
            return;
        break;

    case OPTST_IMM:
        if (PRESETTING(direction)) {
            /*
             *  We are in the presetting direction with an option we handle
             *  immediately for enablement, but normally for disablement.
             *  Therefore, skip if disabled.
             */
            if ((opt_state->flags & OPTST_DISABLED) == 0)
                return;
        } else {
            /*
             *  We are in the processing direction with an option we handle
             *  immediately for enablement, but normally for disablement.
             *  Therefore, skip if NOT disabled.
             */
            if ((opt_state->flags & OPTST_DISABLED) != 0)
                return;
        }
        break;

    case OPTST_DISABLE_IMM:
        if (PRESETTING(direction)) {
            /*
             *  We are in the presetting direction with an option we handle
             *  immediately for disablement, but normally for disablement.
             *  Therefore, skip if NOT disabled.
             */
            if ((opt_state->flags & OPTST_DISABLED) != 0)
                return;
        } else {
            /*
             *  We are in the processing direction with an option we handle
             *  immediately for disablement, but normally for disablement.
             *  Therefore, skip if disabled.
             */
            if ((opt_state->flags & OPTST_DISABLED) == 0)
                return;
        }
        break;

    case OPTST_IMM|OPTST_DISABLE_IMM:
        /*
         *  The selected option is always for immediate action.
         *  THEREFORE, if the direction is PROCESSING
         *  THEN we skip this option.
         */
        if (PROCESSING(direction))
            return;
        break;
    }

    /*
     *  Fix up the args.
     */
    if (OPTST_GET_ARGTYPE(opt_state->pOD->fOptState) == OPARG_TYPE_NONE) {
        if (*opt_state->pzOptArg != NUL)
            return;
        opt_state->pzOptArg = NULL;

    } else if (opt_state->pOD->fOptState & OPTST_ARG_OPTIONAL) {
        if (*opt_state->pzOptArg == NUL)
             opt_state->pzOptArg = NULL;
        else {
            AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg");
            opt_state->flags |= OPTST_ALLOC_ARG;
        }

    } else {
        if (*opt_state->pzOptArg == NUL)
             opt_state->pzOptArg = zNil;
        else {
            AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg");
            opt_state->flags |= OPTST_ALLOC_ARG;
        }
    }

    {
        tOptionLoadMode sv = option_load_mode;
        option_load_mode = load_mode;
        handle_opt(opts, opt_state);
        option_load_mode = sv;
    }
}
Beispiel #20
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
}
Beispiel #21
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;
}
Beispiel #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;
}
Beispiel #23
0
/**
 *  This directive will insert definitions from another file into
 *  the current collection.  If the file name is adorned with
 *  double quotes or angle brackets (as in a C program), then the
 *  include is ignored.
 */
char *
doDir_include(directive_enum_t id, char const * dir, char * scan_next)
{
    static char const * const apzSfx[] = { DIRECT_INC_DEF_SFX, NULL };
    scan_ctx_t * new_ctx;
    size_t     inc_sz;
    char       full_name[ AG_PATH_MAX + 1 ];
    (void)id;

    dir = SPN_WHITESPACE_CHARS(dir);
    /*
     *  Ignore C-style includes.  This allows "C" files to be processed
     *  for their "#define"s.
     */
    if ((*dir == '"') || (*dir == '<'))
        return scan_next;

    if (! SUCCESSFUL(
            find_file(dir, full_name, apzSfx, cctx->scx_fname))) {
        errno = ENOENT;
        fswarn("search for", cctx->scx_fname);
        return scan_next;
    }

    /*
     *  Make sure the specified file is a regular file and we can get
     *  the correct size for it.
     */
    inc_sz = file_size(full_name);
    if (inc_sz == 0)
        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.
     */
    {
        size_t sz = sizeof(scan_ctx_t) + 4 + inc_sz;
        new_ctx = (scan_ctx_t *)AGALOC(sz, "inc def head");

        memset(VOIDP(new_ctx), 0, sz);
        new_ctx->scx_line = 1;
    }

    /*
     *  Link it into the context stack
     */
    cctx->scx_scan     = scan_next;
    new_ctx->scx_next  = cctx;
    cctx               = new_ctx;
    AGDUPSTR(new_ctx->scx_fname, full_name, "def file");

    new_ctx->scx_scan  =
    new_ctx->scx_data  =
    scan_next          = (char *)(new_ctx + 1);

    /*
     *  Read all the data.  Usually in a single read, but loop
     *  in case multiple passes are required.
     */
    {
        FILE * fp = fopen(full_name, "r" FOPEN_TEXT_FLAG);
        char * pz = scan_next;

        if (fp == NULL)
            AG_CANT(DIRECT_INC_CANNOT_OPEN, full_name);

        if (dep_fp != NULL)
            add_source_file(full_name);

        do  {
            size_t rdct = fread(VOIDP(pz), (size_t)1, inc_sz, fp);

            if (rdct == 0)
                AG_CANT(DIRECT_INC_CANNOT_READ, full_name);

            pz += rdct;
            inc_sz -= rdct;
        } while (inc_sz > 0);

        fclose(fp);
        *pz = NUL;
    }

    return scan_next;
}
Beispiel #24
0
/*
 *  Load an option from a block of text.  The text must start with the
 *  configurable/option name and be followed by its associated value.
 *  That value may be processed in any of several ways.  See "tOptionLoadMode"
 *  in autoopts.h.
 */
LOCAL void
loadOptionLine(
    tOptions*   pOpts,
    tOptState*  pOS,
    char*       pzLine,
    tDirection  direction,
    tOptionLoadMode   load_mode )
{
    while (isspace( (int)*pzLine ))  pzLine++;

    {
        char* pzArg = assembleArgValue( pzLine, load_mode );

        if (! SUCCESSFUL( longOptionFind( pOpts, pzLine, pOS )))
            return;
        if (pOS->flags & OPTST_NO_INIT)
            return;
        pOS->pzOptArg = pzArg;
    }

    switch (pOS->flags & (OPTST_IMM|OPTST_DISABLE_IMM)) {
    case 0:
        /*
         *  The selected option has no immediate action.
         *  THEREFORE, if the direction is PRESETTING
         *  THEN we skip this option.
         */
        if (PRESETTING(direction))
            return;
        break;

    case OPTST_IMM:
        if (PRESETTING(direction)) {
            /*
             *  We are in the presetting direction with an option we handle
             *  immediately for enablement, but normally for disablement.
             *  Therefore, skip if disabled.
             */
            if ((pOS->flags & OPTST_DISABLED) == 0)
                return;
        } else {
            /*
             *  We are in the processing direction with an option we handle
             *  immediately for enablement, but normally for disablement.
             *  Therefore, skip if NOT disabled.
             */
            if ((pOS->flags & OPTST_DISABLED) != 0)
                return;
        }
        break;

    case OPTST_DISABLE_IMM:
        if (PRESETTING(direction)) {
            /*
             *  We are in the presetting direction with an option we handle
             *  immediately for disablement, but normally for disablement.
             *  Therefore, skip if NOT disabled.
             */
            if ((pOS->flags & OPTST_DISABLED) != 0)
                return;
        } else {
            /*
             *  We are in the processing direction with an option we handle
             *  immediately for disablement, but normally for disablement.
             *  Therefore, skip if disabled.
             */
            if ((pOS->flags & OPTST_DISABLED) == 0)
                return;
        }
        break;

    case OPTST_IMM|OPTST_DISABLE_IMM:
        /*
         *  The selected option is always for immediate action.
         *  THEREFORE, if the direction is PROCESSING
         *  THEN we skip this option.
         */
        if (PROCESSING(direction))
            return;
        break;
    }

    /*
     *  Fix up the args.
     */
    if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) {
        if (*pOS->pzOptArg != NUL)
            return;
        pOS->pzOptArg = NULL;

    } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) {
        if (*pOS->pzOptArg == NUL)
             pOS->pzOptArg = NULL;
        else {
            AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" );
            pOS->flags |= OPTST_ALLOC_ARG;
        }

    } else {
        if (*pOS->pzOptArg == NUL)
             pOS->pzOptArg = zNil;
        else {
            AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" );
            pOS->flags |= OPTST_ALLOC_ARG;
        }
    }

    {
        tOptionLoadMode sv = option_load_mode;
        option_load_mode = load_mode;
        handleOption( pOpts, pOS );
        option_load_mode = sv;
    }
}
Beispiel #25
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;
}
Beispiel #26
0
/*=export_func genshelloptUsage
 * private:
 * what: The usage function for the genshellopt generated program
 *
 * arg:  + tOptions* + pOpts    + program options descriptor +
 * arg:  + int       + exitCode + usage text type to produce +
 *
 * doc:
 *  This function is used to create the usage strings for the option
 *  processing shell script code.  Two child processes are spawned
 *  each emitting the usage text in either the short (error exit)
 *  style or the long style.  The generated program will capture this
 *  and create shell script variables containing the two types of text.
=*/
void
genshelloptUsage( tOptions*  pOpts, int exitCode )
{
#if ! defined(HAVE_WORKING_FORK)
    optionUsage( pOpts, exitCode );
#else
    /*
     *  IF not EXIT_SUCCESS,
     *  THEN emit the short form of usage.
     */
    if (exitCode != EXIT_SUCCESS)
        optionUsage( pOpts, exitCode );
    fflush( stderr );
    fflush( stdout );

    option_usage_fp = stdout;

    /*
     *  First, print our usage
     */
    switch (fork()) {
    case -1:
        optionUsage( pOpts, EXIT_FAILURE );
        /* NOTREACHED */
        _exit( EXIT_FAILURE );

    case 0:
        pagerState = PAGER_STATE_CHILD;
        optionUsage( pOpts, EXIT_SUCCESS );
        /* NOTREACHED */
        _exit( EXIT_FAILURE );

    default:
    {
        int  sts;
        wait( &sts );
    }
    }

    /*
     *  Generate the pzProgName, since optionProcess() normally
     *  gets it from the command line
     */
    {
        char* pz;
        AGDUPSTR( pz, pShellParseOptions->pzPROGNAME, "program name" );
        pShellParseOptions->pzProgName = pz;
        while (*pz != NUL) {
            *pz = tolower( *pz );
            pz++;
        }
    }

    /*
     *  Separate the makeshell usage from the client usage
     */
    fprintf( option_usage_fp, zGenshell, pShellParseOptions->pzProgName );
    fflush( option_usage_fp );

    /*
     *  Now, print the client usage.
     */
    switch (fork()) {
    case 0:
        pagerState = PAGER_STATE_CHILD;
        /*FALLTHROUGH*/
    case -1:
        optionUsage( pShellParseOptions, EXIT_FAILURE );

    default:
    {
        int  sts;
        wait( &sts );
    }
    }

    exit( EXIT_SUCCESS );
#endif
}
Beispiel #27
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.
     */
}
Beispiel #28
0
/*=export_func genshelloptUsage
 * private:
 * what: The usage function for the genshellopt generated program
 *
 * arg:  + tOptions * + opts    + program options descriptor +
 * arg:  + int        + exit_cd + usage text type to produce +
 *
 * doc:
 *  This function is used to create the usage strings for the option
 *  processing shell script code.  Two child processes are spawned
 *  each emitting the usage text in either the short (error exit)
 *  style or the long style.  The generated program will capture this
 *  and create shell script variables containing the two types of text.
=*/
void
genshelloptUsage(tOptions * opts, int exit_cd)
{
#if ! defined(HAVE_WORKING_FORK)
    optionUsage(opts, exit_cd);
#else
    /*
     *  IF not EXIT_SUCCESS,
     *  THEN emit the short form of usage.
     */
    if (exit_cd != EXIT_SUCCESS)
        optionUsage(opts, exit_cd);
    fflush(stderr);
    fflush(stdout);
    if (ferror(stdout) || ferror(stderr))
        option_exits(EXIT_FAILURE);

    option_usage_fp = stdout;

    /*
     *  First, print our usage
     */
    switch (fork()) {
    case -1:
        optionUsage(opts, EXIT_FAILURE);
        /* NOTREACHED */

    case 0:
        pagerState = PAGER_STATE_CHILD;
        optionUsage(opts, EXIT_SUCCESS);
        /* NOTREACHED */
        _exit(EXIT_FAILURE);

    default:
    {
        int  sts;
        wait(&sts);
    }
    }

    /*
     *  Generate the pzProgName, since optionProcess() normally
     *  gets it from the command line
     */
    {
        char *  pz;
        char ** pp = VOIDP(&(optionParseShellOptions->pzProgName));
        AGDUPSTR(pz, optionParseShellOptions->pzPROGNAME, "prog name");
        *pp = pz;
        while (*pz != NUL) {
            *pz = (char)LOWER(*pz);
            pz++;
        }
    }

    /*
     *  Separate the makeshell usage from the client usage
     */
    fprintf(option_usage_fp, zGenshell, optionParseShellOptions->pzProgName);
    fflush(option_usage_fp);

    /*
     *  Now, print the client usage.
     */
    switch (fork()) {
    case 0:
        pagerState = PAGER_STATE_CHILD;
        /*FALLTHROUGH*/
    case -1:
        optionUsage(optionParseShellOptions, EXIT_FAILURE);

    default:
    {
        int  sts;
        wait(&sts);
    }
    }

    fflush(stdout);
    if (ferror(stdout))
        fserr_exit(opts->pzProgName, zwriting, zstdout_name);

    option_exits(EXIT_SUCCESS);
#endif
}
Beispiel #29
0
static void
do_env_opt(tOptState * os, char * env_name,
            tOptions * pOpts, teEnvPresetType type)
{
    os->pzOptArg = getenv(env_name);
    if (os->pzOptArg == NULL)
        return;

    os->flags   = OPTST_PRESET | OPTST_ALLOC_ARG | os->pOD->fOptState;
    os->optType = TOPT_UNDEFINED;

    if (  (os->pOD->pz_DisablePfx != NULL)
       && (streqvcmp(os->pzOptArg, os->pOD->pz_DisablePfx) == 0)) {
        os->flags |= OPTST_DISABLED;
        os->pzOptArg = NULL;
    }

    switch (type) {
    case ENV_IMM:
        /*
         *  Process only immediate actions
         */
        if (DO_IMMEDIATELY(os->flags))
            break;
        return;

    case ENV_NON_IMM:
        /*
         *  Process only NON immediate actions
         */
        if (DO_NORMALLY(os->flags) || DO_SECOND_TIME(os->flags))
            break;
        return;

    default: /* process everything */
        break;
    }

    /*
     *  Make sure the option value string is persistent and consistent.
     *
     *  The interpretation of the option value depends
     *  on the type of value argument the option takes
     */
    if (OPTST_GET_ARGTYPE(os->pOD->fOptState) == OPARG_TYPE_NONE) {
        /*
         *  Ignore any value.
         */
        os->pzOptArg = NULL;

    } else if (os->pzOptArg[0] == NUL) {
        /*
         * If the argument is the empty string and the argument is
         * optional, then treat it as if the option was not specified.
         */
        if ((os->pOD->fOptState & OPTST_ARG_OPTIONAL) == 0)
            return;
        os->pzOptArg = NULL;

    } else {
        AGDUPSTR(os->pzOptArg, os->pzOptArg, "option argument");
        os->flags |= OPTST_ALLOC_ARG;
    }

    handle_opt(pOpts, os);
}
Beispiel #30
0
/*=directive include
 *
 *  arg:  unadorned-file-name
 *
 *  text:
 *  This directive will insert definitions from another file into
 *  the current collection.  If the file name is adorned with
 *  double quotes or angle brackets (as in a C program), then the
 *  include is ignored.
=*/
static char*
doDir_include(char* pzArg, char* pzScan)
{
    static char const * apzSfx[] = { "def", NULL };
    tScanCtx*  pCtx;
    size_t     inclSize;
    char       zFullName[ AG_PATH_MAX + 1 ];

    /*
     *  Ignore C-style includes.  This allows "C" files to be processed
     *  for their "#define"s.
     */
    if ((*pzArg == '"') || (*pzArg == '<'))
        return pzScan;
    pCurCtx->pzScan  = pzScan;

    if (! SUCCESSFUL(
                findFile(pzArg, zFullName, apzSfx, pCurCtx->pzCtxFname))) {
        fprintf(pfTrace, "WARNING:  cannot find `%s' definitions file\n",
                pzArg);
        return pzScan;
    }

    /*
     *  Make sure the specified file is a regular file and we can get
     *  the correct size for it.
     */
    {
        struct stat stbf;
        if (stat(zFullName, &stbf) != 0) {
            fprintf(pfTrace, "WARNING %d (%s):  cannot stat `%s' "
                    "for include\n", errno, strerror(errno), zFullName);
            return pzScan;
        }
        if (! S_ISREG(stbf.st_mode)) {
            fprintf(pfTrace, "WARNING:  `%s' must be regular file to "
                    "include\n", zFullName);
            return pzScan;
        }
        inclSize = stbf.st_size;
        if (outTime <= stbf.st_mtime)
            outTime = stbf.st_mtime + 1;
    }

    if (inclSize == 0)
        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.
     */
    {
        size_t sz = sizeof(tScanCtx) + 4 + inclSize;
        pCtx = (tScanCtx*)AGALOC(sz, "include def header");

        memset((void*)pCtx, 0, sz);
        pCtx->lineNo = 1;
    }

    /*
     *  Link it into the context stack
     */
    pCtx->pCtx       = pCurCtx;
    pCurCtx          = pCtx;
    AGDUPSTR(pCtx->pzCtxFname, zFullName, "def file name");

    pCtx->pzScan     =
        pCtx->pzData     =
            pzScan           = (char*)(pCtx + 1);

    /*
     *  Read all the data.  Usually in a single read, but loop
     *  in case multiple passes are required.
     */
    {
        FILE*  fp = fopen(zFullName, "r" FOPEN_TEXT_FLAG);
        char*  pz = pzScan;

        if (fp == NULL)
            AG_CANT("open file", zFullName);

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

        do  {
            size_t rdct = fread((void*)pz, (size_t)1, inclSize, fp);

            if (rdct == 0)
                AG_CANT("read file", zFullName);

            pz += rdct;
            inclSize -= rdct;
        } while (inclSize > 0);

        fclose(fp);
        *pz = NUL;
    }

    return pzScan;
}