Esempio n. 1
0
/**
 * AutoGen specific wrapper function for gettext.  It relies on the macro _()
 * to convert from English to the target language, then strdup-duplicates the
 * result string.  It tries the "libopts" domain first, then whatever has been
 * set via the \a textdomain(3) call.
 *
 * @param[in] pz the input text used as a lookup key.
 * @returns the translated text (if there is one),
 *   or the original text (if not).
 */
static char *
AO_gettext(char const * pz)
{
    char * res;
    if (pz == NULL)
        return NULL;
#ifdef HAVE_DCGETTEXT
    /*
     * While processing the option_xlateable_txt data, try to use the
     * "libopts" domain.  Once we switch to the option descriptor data,
     * do *not* use that domain.
     */
    if (option_xlateable_txt.field_ct != 0) {
        res = dgettext("libopts", pz);
        if (res == pz)
            res = (char *)VOIDP(_(pz));
    } else
        res = (char *)VOIDP(_(pz));
#else
    res = (char *)VOIDP(_(pz));
#endif
    if (res == pz)
        return res;
    res = strdup(res);
    if (res == NULL) {
        fputs(_("No memory for duping translated strings\n"), stderr);
        exit(NTPQ_EXIT_FAILURE);
    }
    return res;
}
Esempio n. 2
0
/**
 *  This is a _stable_ sort.  The entries are sorted alphabetically,
 *  but within entries of the same name the ordering is unchanged.
 *  Typically, we also hope the input is sorted.
 */
static void
sort_list(tArgList * arg_list)
{
    int ix;
    int lm = arg_list->useCt;

    /*
     *  This loop iterates "useCt" - 1 times.
     */
    for (ix = 0; ++ix < lm;) {
        int iy = ix-1;
        tOptionValue * new_v = C(tOptionValue *, arg_list->apzArgs[ix]);
        tOptionValue * old_v = C(tOptionValue *, arg_list->apzArgs[iy]);

        /*
         *  For as long as the new entry precedes the "old" entry,
         *  move the old pointer.  Stop before trying to extract the
         *  "-1" entry.
         */
        while (strcmp(old_v->pzName, new_v->pzName) > 0) {
            arg_list->apzArgs[iy+1] = VOIDP(old_v);
            old_v = (tOptionValue *)VOIDP(arg_list->apzArgs[--iy]);
            if (iy < 0)
                break;
        }

        /*
         *  Always store the pointer.  Sometimes it is redundant,
         *  but the redundancy is cheaper than a test and branch sequence.
         */
        arg_list->apzArgs[iy+1] = VOIDP(new_v);
    }
}
Esempio n. 3
0
/*=export_func  optionNestedVal
 * private:
 *
 * what:  parse a hierarchical option argument
 * arg:   + tOptions * + opts + program options descriptor +
 * arg:   + tOptDesc * + od   + the descriptor for this arg +
 *
 * doc:
 *  Nested value was found on the command line
=*/
void
optionNestedVal(tOptions * opts, tOptDesc * od)
{
    if (opts < OPTPROC_EMIT_LIMIT)
        return;

    if (od->fOptState & OPTST_RESET) {
        tArgList *    arg_list = od->optCookie;
        int           ct;
        char const ** av;

        if (arg_list == NULL)
            return;
        ct = arg_list->useCt;
        av = arg_list->apzArgs;

        while (--ct >= 0) {
            void * p = VOIDP(*(av++));
            optionUnloadNested((tOptionValue const *)p);
        }

        AGFREE(od->optCookie);

    } else {
        tOptionValue * opt_val = optionLoadNested(
            od->optArg.argString, od->pz_Name, strlen(od->pz_Name));

        if (opt_val != NULL)
            addArgListEntry(&(od->optCookie), VOIDP(opt_val));
    }
}
Esempio n. 4
0
/*=export_func  optionNextValue
 *
 * what:  get the next value from a hierarchical list
 * arg:   + const tOptionValue * + pOptValue + a hierarchcal list value +
 * arg:   + const tOptionValue * + pOldValue + a value from this list   +
 *
 * ret_type:  const tOptionValue *
 * ret_desc:  a compound value structure
 *
 * doc:
 *  This routine will return the next entry after the entry passed in.  At the
 *  end of the list, NULL will be returned.  If the entry is not found on the
 *  list, NULL will be returned and "@var{errno}" will be set to EINVAL.
 *  The "@var{pOldValue}" must have been gotten from a prior call to this
 *  routine or to "@code{opitonGetValue()}".
 *
 * err:
 *  The returned result is NULL and errno is set:
 *  @itemize @bullet
 *  @item
 *  @code{EINVAL} - the @code{pOptValue} does not point to a valid
 *  hierarchical option value or @code{pOldValue} does not point to a
 *  member of that option value.
 *  @item
 *  @code{ENOENT} - the supplied @code{pOldValue} pointed to the last entry.
 *  @end itemize
=*/
tOptionValue const *
optionNextValue(tOptionValue const * ov_list,tOptionValue const * oov )
{
    tArgList *           arg_list;
    const tOptionValue * res = NULL;
    int                  err = EINVAL;

    if ((ov_list == NULL) || (ov_list->valType != OPARG_TYPE_HIERARCHY)) {
        errno = EINVAL;
        return NULL;
    }
    arg_list = ov_list->v.nestVal;
    {
        int           ct     = arg_list->useCt;
        const void ** o_list = VOIDP(arg_list->apzArgs);

        while (ct-- > 0) {
            const tOptionValue * nov = *(o_list++);
            if (nov == oov) {
                if (ct == 0) {
                    err = ENOENT;

                } else {
                    err = 0;
                    res = (const tOptionValue *)*o_list;
                }
                break;
            }
        }
    }
    if (err != 0)
        errno = err;
    return res;
}
Esempio n. 5
0
/*=export_func  optionGetValue
 *
 * what:  get a specific value from a hierarcical list
 * arg:   + const tOptionValue * + pOptValue + a hierarchcal value +
 * arg:   + char const *         + valueName + name of value to get +
 *
 * ret_type:  const tOptionValue *
 * ret_desc:  a compound value structure
 *
 * doc:
 *  This routine will find an entry in a nested value option or configurable.
 *  If "valueName" is NULL, then the first entry is returned.  Otherwise,
 *  the first entry with a name that exactly matches the argument will be
 *  returned.  If there is no matching value, NULL is returned and errno is
 *  set to ENOENT. If the provided option value is not a hierarchical value,
 *  NULL is also returned and errno is set to EINVAL.
 *
 * err:
 *  The returned result is NULL and errno is set:
 *  @itemize @bullet
 *  @item
 *  @code{EINVAL} - the @code{pOptValue} does not point to a valid
 *  hierarchical option value.
 *  @item
 *  @code{ENOENT} - no entry matched the given name.
 *  @end itemize
=*/
tOptionValue const *
optionGetValue(tOptionValue const * oov, char const * vname)
{
    tArgList *           arg_list;
    const tOptionValue * res = NULL;

    if ((oov == NULL) || (oov->valType != OPARG_TYPE_HIERARCHY)) {
        errno = EINVAL;
        return res;
    }
    arg_list = oov->v.nestVal;

    if (arg_list->useCt > 0) {
        int           ct     = arg_list->useCt;
        const void ** ovlist = VOIDP(arg_list->apzArgs);

        if (vname == NULL) {
            res = (const tOptionValue *)*ovlist;

        } else do {
            const tOptionValue * opt_val = *(ovlist++);
            if (strcmp(opt_val->pzName, vname) == 0) {
                res = opt_val;
                break;
            }
        } while (--ct > 0);
    }
    if (res == NULL)
        errno = ENOENT;
    return res;
}
Esempio n. 6
0
static void
print_membership(tOptions * pOpts, tOptDesc * pOD)
{
    char const * svstr = pOD->optArg.argString;
    char const * pz;
    uintptr_t val = 1;
    printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
           (int)(uintptr_t)(pOD->optCookie));
    pOD->optCookie = VOIDP(~0UL);
    (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, pOD);

    pz = pOD->optArg.argString;
    while (*pz != NUL) {
        printf("readonly %s_", pOD->pz_NAME);
        pz = SPN_PLUS_N_SPACE_CHARS(pz);

        for (;;) {
            int ch = *(pz++);
            if (IS_LOWER_CASE_CHAR(ch))   fputc(toupper(ch), stdout);
            else if (IS_UPPER_CASE_CHAR(ch))   fputc(ch, stdout);
            else if (IS_PLUS_N_SPACE_CHAR(ch)) goto name_done;
            else if (ch == NUL)        { pz--; goto name_done; }
            else fputc('_', stdout);
        } name_done:;
        printf(SHOW_VAL_FMT, (unsigned long)val);
        val <<= 1;
    }

    AGFREE(pOD->optArg.argString);
    pOD->optArg.argString = svstr;
}
Esempio n. 7
0
/**
 * Convert a name or number into a binary number.
 * "~0" and "-1" will be converted to the largest value in the enumeration.
 *
 * @param name       the keyword name (number) to convert
 * @param pOpts      the program's option descriptor
 * @param pOD        the option descriptor for this option
 * @param paz_names  the list of keywords for this option
 * @param name_ct    the count of keywords
 */
static uintptr_t
find_name(char const * name, tOptions * pOpts, tOptDesc * pOD,
          char const * const *  paz_names, unsigned int name_ct)
{
    /*
     *  Return the matching index as a pointer sized integer.
     *  The result gets stashed in a char * pointer.
     */
    uintptr_t   res = name_ct;
    size_t      len = strlen((char *)name);
    uintptr_t   idx;

    if (IS_DEC_DIGIT_CHAR(*name)) {
        char * pz = VOIDP(name);
        unsigned long val = strtoul(pz, &pz, 0);
        if ((*pz == NUL) && (val < name_ct))
            return (uintptr_t)val;
        pz_enum_err_fmt = znum_too_large;
        option_usage_fp = stderr;
        enum_err(pOpts, pOD, paz_names, (int)name_ct);
        return name_ct;
    }

    if (IS_INVERSION_CHAR(*name) && (name[2] == NUL)) {
        if (  ((name[0] == '~') && (name[1] == '0'))
           || ((name[0] == '-') && (name[1] == '1')))
        return (uintptr_t)(name_ct - 1);
        goto oops;
    }

    /*
     *  Look for an exact match, but remember any partial matches.
     *  Multiple partial matches means we have an ambiguous match.
     */
    for (idx = 0; idx < name_ct; idx++) {
        if (strncmp((char *)paz_names[idx], (char *)name, len) == 0) {
            if (paz_names[idx][len] == NUL)
                return idx;  /* full match */

            if (res == name_ct)
                res = idx; /* save partial match */
            else
                res = (uintptr_t)~0;  /* may yet find full match */
        }
    }

    if (res < name_ct)
        return res; /* partial match */

 oops:

    pz_enum_err_fmt = (res == name_ct) ? zNoKey : zambiguous_key;
    option_usage_fp = stderr;
    enum_err(pOpts, pOD, paz_names, (int)name_ct);
    return name_ct;
}
Esempio n. 8
0
/*=export_func  optionMemberList
 * what:  Get the list of members of a bit mask set
 *
 * arg:   tOptDesc *,  od,   the set membership option description
 *
 * ret_type: char *
 * ret_desc: the names of the set bits
 *
 * doc:   This converts the OPT_VALUE_name mask value to a allocated string.
 *        It is the caller's responsibility to free the string.
=*/
char *
optionMemberList(tOptDesc * od)
{
    uintptr_t    sv = od->optArg.argIntptr;
    char * res;
    (*(od->pOptProc))(OPTPROC_RETURN_VALNAME, od);
    res = VOIDP(od->optArg.argString);
    od->optArg.argIntptr = sv;
    return res;
}
Esempio n. 9
0
/**
 *  Deallocate a list of option arguments.  This must have been gotten from
 *  a hierarchical option argument, not a stacked list of strings.  It is
 *  an internal call, so it is not validated.  The caller is responsible for
 *  knowing what they are doing.
 */
LOCAL void
unload_arg_list(tArgList * arg_list)
{
    int ct = arg_list->useCt;
    char const ** pnew_val = arg_list->apzArgs;

    while (ct-- > 0) {
        tOptionValue * new_val = (tOptionValue *)VOIDP(*(pnew_val++));
        if (new_val->valType == OPARG_TYPE_HIERARCHY)
            unload_arg_list(new_val->v.nestVal);
        AGFREE(new_val);
    }

    AGFREE(arg_list);
}
Esempio n. 10
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 = VOIDP(pOD->optArg.argString);
    else
        AGDUPSTR(pOD->optCookie, pOD->optArg.argString, "file name");

    pOD->optArg.argFd = fd;
    pOD->fOptState &= ~OPTST_ALLOC_ARG;
}
Esempio n. 11
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 = VOIDP(pOD->optArg.argString);
    else
        AGDUPSTR(pOD->optCookie, pOD->optArg.argString, "file name");

    pOD->optArg.argFp = fp;
    pOD->fOptState &= ~OPTST_ALLOC_ARG;
}
Esempio n. 12
0
/*=export_func  optionFindValue
 *
 * what:  find a hierarcicaly valued option instance
 * arg:   + const tOptDesc * + odesc + an option with a nested arg type +
 * arg:   + char const *     + name  + name of value to find +
 * arg:   + char const *     + val   + the matching value    +
 *
 * ret_type:  const tOptionValue *
 * ret_desc:  a compound value structure
 *
 * doc:
 *  This routine will find an entry in a nested value option or configurable.
 *  It will search through the list and return a matching entry.
 *
 * err:
 *  The returned result is NULL and errno is set:
 *  @itemize @bullet
 *  @item
 *  @code{EINVAL} - the @code{pOptValue} does not point to a valid
 *  hierarchical option value.
 *  @item
 *  @code{ENOENT} - no entry matched the given name.
 *  @end itemize
=*/
const tOptionValue *
optionFindValue(const tOptDesc * odesc, char const * name, char const * val)
{
    const tOptionValue * res = NULL;

    if (  (odesc == NULL)
       || (OPTST_GET_ARGTYPE(odesc->fOptState) != OPARG_TYPE_HIERARCHY))  {
        errno = EINVAL;
    }

    else if (odesc->optCookie == NULL) {
        errno = ENOENT;
    }

    else do {
        tArgList *    argl  = odesc->optCookie;
        int           argct = argl->useCt;
        const void ** poptv = VOIDP(argl->apzArgs);

        if (argct == 0) {
            errno = ENOENT;
            break;
        }

        if (name == NULL) {
            res = (const tOptionValue *)*poptv;
            break;
        }

        while (--argct >= 0) {
            const tOptionValue * ov = *(poptv++);
            const tOptionValue * rv = optionGetValue(ov, name);

            if (rv == NULL)
                continue;

            if (val == NULL) {
                res = ov;
                break;
            }
        }
        if (res == NULL)
            errno = ENOENT;
    } while (false);

    return res;
}
Esempio n. 13
0
/**
 * Load the previous shell script output file.  We need to preserve any
 * hand-edited additions outside of the START_MARK and END_MARKs.
 *
 * @param[in] fname  the output file name
 */
static char *
load_old_output(char const * fname, char const * pname)
{
    /*
     *  IF we cannot stat the file,
     *  THEN assume we are creating a new file.
     *       Skip the loading of the old data.
     */
    FILE * fp = fopen(fname, "r" FOPEN_BINARY_FLAG);
    struct stat stbf;
    char * text;
    char * scan;

    if (fp == NULL)
        return NULL;

    /*
     * If we opened it, we should be able to stat it and it needs
     * to be a regular file
     */
    if ((fstat(fileno(fp), &stbf) != 0) || (! S_ISREG(stbf.st_mode)))
        fserr_exit(pname, "fstat", fname);

    scan = text = AGALOC(stbf.st_size + 1, "f data");

    /*
     *  Read in all the data as fast as our OS will let us.
     */
    for (;;) {
        size_t inct = fread(VOIDP(scan), 1, (size_t)stbf.st_size, fp);
        if (inct == 0)
            break;

        stbf.st_size -= (ssize_t)inct;

        if (stbf.st_size == 0)
            break;

        scan += inct;
    }

    *scan = NUL;
    fclose(fp);

    return text;
}
Esempio n. 14
0
/*=export_func optionFileLoad
 *
 * what: Load the locatable config files, in order
 *
 * arg:  + tOptions *   + opts + program options descriptor +
 * arg:  + char const * + prog + program name +
 *
 * ret_type:  int
 * ret_desc:  0 -> SUCCESS, -1 -> FAILURE
 *
 * doc:
 *
 * This function looks in all the specified directories for a configuration
 * file ("rc" file or "ini" file) and processes any found twice.  The first
 * time through, they are processed in reverse order (last file first).  At
 * that time, only "immediate action" configurables are processed.  For
 * example, if the last named file specifies not processing any more
 * configuration files, then no more configuration files will be processed.
 * Such an option in the @strong{first} named directory will have no effect.
 *
 * Once the immediate action configurables have been handled, then the
 * directories are handled in normal, forward order.  In that way, later
 * config files can override the settings of earlier config files.
 *
 * See the AutoOpts documentation for a thorough discussion of the
 * config file format.
 *
 * Configuration files not found or not decipherable are simply ignored.
 *
 * err:  Returns the value, "-1" if the program options descriptor
 *       is out of date or indecipherable.  Otherwise, the value "0" will
 *       always be returned.
=*/
int
optionFileLoad(tOptions * opts, char const * prog)
{
    if (! SUCCESSFUL(validate_struct(opts, prog)))
        return -1;

    /*
     * The pointer to the program name is "const".  However, the
     * structure is in writable memory, so we coerce the address
     * of this pointer to point to writable memory.
     */
    {
        char const ** pp = VOIDP(&(opts->pzProgName));
        *pp = prog;
    }

    intern_file_load(opts);
    return 0;
}
Esempio n. 15
0
/**
 * Translate all the translatable strings in the ntpqOptions
 * structure defined above.  This is done only once.
 */
static void
translate_option_strings(void)
{
    tOptions * const opts = &ntpqOptions;

    /*
     *  Guard against re-translation.  It won't work.  The strings will have
     *  been changed by the first pass through this code.  One shot only.
     */
    if (option_xlateable_txt.field_ct != 0) {
        /*
         *  Do the translations.  The first pointer follows the field count
         *  field.  The field count field is the size of a pointer.
         */
        char ** ppz = (char**)VOIDP(&(option_xlateable_txt));
        int     ix  = option_xlateable_txt.field_ct;

        do {
            ppz++; /* skip over field_ct */
            *ppz = AO_gettext(*ppz);
        } while (--ix > 0);
        /* prevent re-translation and disable "libopts" domain lookup */
        option_xlateable_txt.field_ct = 0;

        coerce_it(VOIDP(&(opts->pzCopyright)));
        coerce_it(VOIDP(&(opts->pzCopyNotice)));
        coerce_it(VOIDP(&(opts->pzFullVersion)));
        coerce_it(VOIDP(&(opts->pzUsageTitle)));
        coerce_it(VOIDP(&(opts->pzExplain)));
        coerce_it(VOIDP(&(opts->pzDetail)));
        {
            tOptDesc * od = opts->pOptDesc;
            for (ix = opts->optCt; ix > 0; ix--, od++)
                coerce_it(VOIDP(&(od->pzText)));
        }
    }
}
Esempio n. 16
0
/*=export_func  optionFindNextValue
 *
 * FIXME: the handling of 'pzName' and 'pzVal' is just wrong.
 *
 * what:  find a hierarcicaly valued option instance
 * arg:   + const tOptDesc * + odesc + an option with a nested arg type +
 * arg:   + const tOptionValue * + pPrevVal + the last entry +
 * arg:   + char const *     + name     + name of value to find +
 * arg:   + char const *     + value    + the matching value    +
 *
 * ret_type:  const tOptionValue *
 * ret_desc:  a compound value structure
 *
 * doc:
 *  This routine will find the next entry in a nested value option or
 *  configurable.  It will search through the list and return the next entry
 *  that matches the criteria.
 *
 * err:
 *  The returned result is NULL and errno is set:
 *  @itemize @bullet
 *  @item
 *  @code{EINVAL} - the @code{pOptValue} does not point to a valid
 *  hierarchical option value.
 *  @item
 *  @code{ENOENT} - no entry matched the given name.
 *  @end itemize
=*/
tOptionValue const *
optionFindNextValue(const tOptDesc * odesc, const tOptionValue * pPrevVal,
                    char const * pzName, char const * pzVal)
{
    bool old_found = false;
    const tOptionValue * res = NULL;

    (void)pzName;
    (void)pzVal;

    if (  (odesc == NULL)
       || (OPTST_GET_ARGTYPE(odesc->fOptState) != OPARG_TYPE_HIERARCHY))  {
        errno = EINVAL;
    }

    else if (odesc->optCookie == NULL) {
        errno = ENOENT;
    }

    else do {
        tArgList *    argl  = odesc->optCookie;
        int           ct    = argl->useCt;
        const void ** poptv = VOIDP(argl->apzArgs);

        while (--ct >= 0) {
            const tOptionValue * pOV = *(poptv++);
            if (old_found) {
                res = pOV;
                break;
            }
            if (pOV == pPrevVal)
                old_found = true;
        }
        if (res == NULL)
            errno = ENOENT;
    } while (false);

    return res;
}
Esempio n. 17
0
/*
 *  doPrognameEnv - check for preset values from the ${PROGNAME}
 *  environment variable.  This is accomplished by parsing the text into
 *  tokens, temporarily replacing the arg vector and calling
 *  immediate_opts and/or regular_opts.
 */
LOCAL void
doPrognameEnv(tOptions * pOpts, teEnvPresetType type)
{
    char const *        env_opts = getenv(pOpts->pzPROGNAME);
    token_list_t *      pTL;
    int                 sv_argc;
    proc_state_mask_t   sv_flag;
    char **             sv_argv;

    /*
     *  No such beast?  Then bail now.
     */
    if (env_opts == NULL)
        return;

    /*
     *  Tokenize the string.  If there's nothing of interest, we'll bail
     *  here immediately.
     */
    pTL = ao_string_tokenize(env_opts);
    if (pTL == NULL)
        return;

    /*
     *  Substitute our $PROGNAME argument list for the real one
     */
    sv_argc = (int)pOpts->origArgCt;
    sv_argv = pOpts->origArgVect;
    sv_flag = pOpts->fOptSet;

    /*
     *  We add a bogus pointer to the start of the list.  The program name
     *  has already been pulled from "argv", so it won't get dereferenced.
     *  The option scanning code will skip the "program name" at the start
     *  of this list of tokens, so we accommodate this way ....
     */
    {
        uintptr_t v = (uintptr_t)(pTL->tkn_list);
        pOpts->origArgVect = VOIDP(v - sizeof(char *));
    }
    pOpts->origArgCt   = (unsigned int)pTL->tkn_ct   + 1;
    pOpts->fOptSet    &= ~OPTPROC_ERRSTOP;

    pOpts->curOptIdx   = 1;
    pOpts->pzCurOpt    = NULL;

    switch (type) {
    case ENV_IMM:
        (void)immediate_opts(pOpts);
        break;

    case ENV_ALL:
        (void)immediate_opts(pOpts);
        pOpts->curOptIdx = 1;
        pOpts->pzCurOpt  = NULL;
        /* FALLTHROUGH */

    case ENV_NON_IMM:
        (void)regular_opts(pOpts);
    }

    /*
     *  Free up the temporary arg vector and restore the original program args.
     */
    free(pTL);
    pOpts->origArgVect = sv_argv;
    pOpts->origArgCt   = (unsigned int)sv_argc;
    pOpts->fOptSet     = sv_flag;
}
Esempio n. 18
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;
}
Esempio n. 19
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;
}
Esempio n. 20
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
}
Esempio n. 21
0
/**
 * capture usage text in shell variables.
 * 
 */
static void
emit_usage(tOptions * opts)
{
    char tm_nm_buf[AO_NAME_SIZE];

    /*
     *  First, switch stdout to the output file name.
     *  Then, change the program name to the one defined
     *  by the definitions (rather than the current
     *  executable name).  Down case the upper cased name.
     */
    if (script_leader != NULL)
        fputs(script_leader, stdout);

    {
        char const * out_nm;

        {
            time_t    c_tim = time(NULL);
            struct tm * ptm = localtime(&c_tim);
            strftime(tm_nm_buf, AO_NAME_SIZE, TIME_FMT, ptm );
        }

        if (HAVE_GENSHELL_OPT(SCRIPT))
             out_nm = GENSHELL_OPT_ARG(SCRIPT);
        else out_nm = STDOUT;

        if ((script_leader == NULL) && (shell_prog != NULL))
            printf(SHELL_MAGIC, shell_prog);

        printf(PREAMBLE_FMT, START_MARK, out_nm, tm_nm_buf);
    }

    printf(END_PRE_FMT, opts->pzPROGNAME);

    /*
     *  Get a copy of the original program name in lower case and
     *  fill in an approximation of the program name from it.
     */
    {
        char *       pzPN = tm_nm_buf;
        char const * pz   = opts->pzPROGNAME;
        char **      pp;

        /* Copy the program name into the time/name buffer */
        for (;;) {
            if ((*pzPN++ = (char)tolower((unsigned char)*pz++)) == NUL)
                break;
        }

        pp  = VOIDP(&(opts->pzProgPath));
        *pp = tm_nm_buf;
        pp  = VOIDP(&(opts->pzProgName));
        *pp = tm_nm_buf;
    }

    text_to_var(opts, TT_LONGUSAGE, NULL);
    text_to_var(opts, TT_USAGE,     NULL);

    {
        tOptDesc * pOptDesc = opts->pOptDesc;
        int        optionCt = opts->optCt;

        for (;;) {
            if (pOptDesc->pOptProc == optionPrintVersion) {
                text_to_var(opts, TT_VERSION, pOptDesc);
                break;
            }

            if (--optionCt <= 0)
                break;
            pOptDesc++;
        }
    }
}
Esempio n. 22
0
/*=export_func  optionSetMembers
 * what:  Convert between bit flag values and strings
 * private:
 *
 * arg:   tOptions *,     opts,     the program options descriptor
 * arg:   tOptDesc *,     od,       the set membership option description
 * arg:   char const * const *,
 *                       nm_list,  list of enumeration names
 * arg:   unsigned int,  nm_ct,    number of names in list
 *
 * doc:   This converts the optArg.argString string from the option description
 *        into the index corresponding to an entry in the name list.
 *        This will match the generated enumeration value.
 *        Full matches are always accepted.  Partial matches are accepted
 *        if there is only one partial match.
=*/
void
optionSetMembers(tOptions * opts, tOptDesc * od,
                 char const * const * nm_list, unsigned int nm_ct)
{
    /*
     *  IF the program option descriptor pointer is invalid,
     *  then it is some sort of special request.
     */
    switch ((uintptr_t)opts) {
    case (uintptr_t)OPTPROC_EMIT_USAGE:
        enum_err(OPTPROC_EMIT_USAGE, od, nm_list, nm_ct);
        return;

    case (uintptr_t)OPTPROC_EMIT_SHELL:
        set_memb_shell(opts, od, nm_list, nm_ct);
        return;

    case (uintptr_t)OPTPROC_RETURN_VALNAME:
        set_memb_names(opts, od, nm_list, nm_ct);
        return;

    default:
        break;
    }

    if ((od->fOptState & OPTST_RESET) != 0)
        return;

    {
        char const * arg;
        bool         invert;
        uintptr_t    res = check_membership_start(od, &arg, &invert);
        if (arg == NULL)
            goto fail_return;

        while (*arg != NUL) {
            bool inv_val = false;
            int  len;

            switch (*arg) {
            case ',':
                arg = SPN_WHITESPACE_CHARS(arg+1);
                if ((*arg == ',') || (*arg == '|'))
                    goto fail_return;
                continue;

            case '-':
            case '!':
                inv_val = true;
                /* FALLTHROUGH */

            case '+':
            case '|':
                arg = SPN_WHITESPACE_CHARS(arg+1);
            }

            len = (int)(BRK_SET_SEPARATOR_CHARS(arg) - arg);
            if (len == 0)
                break;

            if ((len == 3) && (strncmp(arg, zAll, 3) == 0)) {
                if (inv_val)
                     res = 0;
                else res = ~0UL;
            }
            else if ((len == 4) && (strncmp(arg, zNone, 4) == 0)) {
                if (! inv_val)
                    res = 0;
            }
            else do {
                char *    pz;
                uintptr_t bit = strtoul(arg, &pz, 0);

                if (pz != arg + len) {
                    bit = find_member_bit(opts, od, pz, len, nm_list, nm_ct);
                    if (bit == 0UL)
                        goto fail_return;
                }
                if (inv_val)
                     res &= ~bit;
                else res |= bit;
            } while (false);

            arg = SPN_WHITESPACE_CHARS(arg + len);
        }

        if (invert)
            res ^= ~0UL;

        if (nm_ct < (8 * sizeof(uintptr_t)))
            res &= (1UL << nm_ct) - 1UL;

        od->optCookie = VOIDP(res);
    }
    return;

fail_return:
    od->optCookie = VOIDP(0);
}
Esempio n. 23
0
/**
 *  "txt" points to a '<' character, followed by an alpha.
 *  The end of the entry is either the "/>" following the name, or else a
 *  "</name>" string.
 */
static char *
handle_struct(tOptions * opts, tOptState * ost, char * txt, int dir)
{
    tOptionLoadMode mode = option_load_mode;
    tOptionValue    valu;

    char * pzName = ++txt;
    char * pzData;
    char * pcNulPoint;

    txt = SPN_VALUE_NAME_CHARS(txt);
    pcNulPoint = txt;
    valu.valType = OPARG_TYPE_STRING;

    switch (*txt) {
    case ' ':
    case '\t':
        txt = VOIDP(parse_attrs(
            opts, SPN_WHITESPACE_CHARS(txt), &mode, &valu));
        if (txt == NULL)
            return txt;
        if (*txt == '>')
            break;
        if (*txt != '/')
            return NULL;
        /* FALLTHROUGH */

    case '/':
        if (txt[1] != '>')
            return NULL;
        *txt = NUL;
        txt += 2;
        load_opt_line(opts, ost, pzName, dir, mode);
        return txt;

    case '>':
        break;

    default:
        txt = strchr(txt, '>');
        if (txt != NULL)
            txt++;
        return txt;
    }

    /*
     *  If we are here, we have a value.  "txt" points to a closing angle
     *  bracket.  Separate the name from the value for a moment.
     */
    *pcNulPoint = NUL;
    pzData = ++txt;
    txt = trim_xml_text(txt, pzName, mode);
    if (txt == NULL)
        return txt;

    /*
     *  Rejoin the name and value for parsing by "load_opt_line()".
     *  Erase any attributes parsed by "parse_attrs()".
     */
    memset(pcNulPoint, ' ', (size_t)(pzData - pcNulPoint));

    /*
     *  If we are getting a "string" value that is to be cooked,
     *  then process the XML-ish &xx; XML-ish and %XX hex characters.
     */
    if (  (valu.valType == OPARG_TYPE_STRING)
       && (mode == OPTION_LOAD_COOKED))
        cook_xml_text(pzData);

    /*
     *  "pzName" points to what looks like text for one option/configurable.
     *  It is NUL terminated.  Process it.
     */
    load_opt_line(opts, ost, pzName, dir, mode);

    return txt;
}
Esempio n. 24
0
/*=gfunc join
 *
 * what:   join string list with separator
 * general_use:
 * exparg: separator, string to insert between entries
 * exparg: list, list of strings to join,, list
 *
 * doc:  With the first argument as the separator string,
 *       joins together an a-list of strings into one long string.
 *       The list may contain nested lists, partly because you
 *       cannot always control that.
=*/
SCM
ag_scm_join(SCM sep, SCM list)
{
    int      l_len, sv_l_len;
    SCM      car;
    SCM      alist = list;
    size_t   sep_len;
    size_t   str_len;
    char *   pzRes;
    char const * pzSep;
    char *   pzScan;

    if (! AG_SCM_STRING_P(sep))
        return SCM_UNDEFINED;

    sv_l_len = l_len = (int)scm_ilength(list);
    if (l_len == 0)
        return AG_SCM_STR02SCM(zNil);

    pzSep   = scm_i_string_chars(sep);
    sep_len = AG_SCM_STRLEN(sep);
    str_len = 0;

    /*
     *  Count up the lengths of all the strings to be joined.
     */
    for (;;) {
        car  = SCM_CAR(list);
        list = SCM_CDR(list);

        /*
         *  This routine is listed as getting a list as the second
         *  argument.  That means that if someone builds a list and
         *  hands it to us, it magically becomes a nested list.
         *  This unravels that.
         */
        if (! AG_SCM_STRING_P(car)) {
            if (car != SCM_UNDEFINED)
                car = ag_scm_join(sep, car);
            if (! AG_SCM_STRING_P(car))
                return SCM_UNDEFINED;
        }

        str_len += AG_SCM_STRLEN(car);

        if (--l_len <= 0)
            break;

        str_len += sep_len;
    }

    l_len = sv_l_len;
    pzRes = pzScan = scribble_get((ssize_t)str_len);

    /*
     *  Now, copy each one into the output
     */
    for (;;) {
        size_t cpy_len;

        car   = SCM_CAR(alist);
        alist = SCM_CDR(alist);

        /*
         *  This unravels nested lists.
         */
        if (! AG_SCM_STRING_P(car))
            car = ag_scm_join(sep, car);

        cpy_len = AG_SCM_STRLEN(car);
        memcpy(VOIDP(pzScan), scm_i_string_chars(car), cpy_len);
        pzScan += cpy_len;

        /*
         *  IF we reach zero, then do not insert a separation and bail out
         */
        if (--l_len <= 0)
            break;
        memcpy(VOIDP(pzScan), VOIDP(pzSep), sep_len);
        pzScan += sep_len;
    }

    return AG_SCM_STR2SCM(pzRes, str_len);
}