Blame src/libopts/pgusage.c

Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * \file pgusage.c
Packit 549fdc
 *
Packit 549fdc
 *   Automated Options Paged Usage module.
Packit 549fdc
 *
Packit 549fdc
 * @addtogroup autoopts
Packit 549fdc
 * @{
Packit 549fdc
 */
Packit 549fdc
/*
Packit 549fdc
 *  This routine will run run-on options through a pager so the
Packit 549fdc
 *  user may examine, print or edit them at their leisure.
Packit 549fdc
 *
Packit 549fdc
 *  This file is part of AutoOpts, a companion to AutoGen.
Packit 549fdc
 *  AutoOpts is free software.
Packit 549fdc
 *  AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved
Packit 549fdc
 *
Packit 549fdc
 *  AutoOpts is available under any one of two licenses.  The license
Packit 549fdc
 *  in use must be one of these two and the choice is under the control
Packit 549fdc
 *  of the user of the license.
Packit 549fdc
 *
Packit 549fdc
 *   The GNU Lesser General Public License, version 3 or later
Packit 549fdc
 *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
Packit 549fdc
 *
Packit 549fdc
 *   The Modified Berkeley Software Distribution License
Packit 549fdc
 *      See the file "COPYING.mbsd"
Packit 549fdc
 *
Packit 549fdc
 *  These files have the following sha256 sums:
Packit 549fdc
 *
Packit 549fdc
 *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
Packit 549fdc
 *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
Packit 549fdc
 *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
Packit 549fdc
 */
Packit 549fdc
Packit 549fdc
#if defined(HAVE_WORKING_FORK)
Packit 549fdc
static inline FILE *
Packit 549fdc
open_tmp_usage(char ** buf)
Packit 549fdc
{
Packit 549fdc
    char * bf;
Packit 549fdc
    size_t bfsz;
Packit 549fdc
Packit 549fdc
    {
Packit 549fdc
        unsigned int my_pid = (unsigned int)getpid();
Packit 549fdc
        char const * tmpdir = getenv(TMPDIR);
Packit 549fdc
        if (tmpdir == NULL)
Packit 549fdc
            tmpdir = tmp_dir;
Packit 549fdc
        bfsz = TMP_FILE_FMT_LEN + strlen(tmpdir) + 10;
Packit 549fdc
        bf   = AGALOC(bfsz, "tmp fil");
Packit 549fdc
        snprintf(bf, bfsz, TMP_FILE_FMT, tmpdir, my_pid);
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
    {
Packit 549fdc
        static mode_t const cmask = S_IRWXO | S_IRWXG;
Packit 549fdc
        mode_t svmsk = umask(cmask);
Packit 549fdc
        int fd = mkstemp(bf);
Packit 549fdc
        (void)umask(svmsk);
Packit 549fdc
Packit 549fdc
        if (fd < 0) {
Packit 549fdc
            AGFREE(bf);
Packit 549fdc
            return NULL;
Packit 549fdc
        }
Packit 549fdc
        *buf = bf;
Packit 549fdc
        return fdopen(fd, "w");
Packit 549fdc
    }
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static inline char *
Packit 549fdc
mk_pager_cmd(char const * fname)
Packit 549fdc
{
Packit 549fdc
    /*
Packit 549fdc
     * Page the file and remove it when done.  For shell script processing,
Packit 549fdc
     * we must redirect the output to the current stderr, otherwise stdout.
Packit 549fdc
     */
Packit 549fdc
    fclose(option_usage_fp);
Packit 549fdc
    option_usage_fp = NULL;
Packit 549fdc
Packit 549fdc
    {
Packit 549fdc
        char const * pager  = (char const *)getenv(PAGER_NAME);
Packit 549fdc
        size_t bfsz;
Packit 549fdc
        char * res;
Packit 549fdc
Packit 549fdc
        /*
Packit 549fdc
         *  Use the "more(1)" program if "PAGER" has not been defined
Packit 549fdc
         */
Packit 549fdc
        if (pager == NULL)
Packit 549fdc
            pager = MORE_STR;
Packit 549fdc
Packit 549fdc
        bfsz = 2 * strlen(fname) + strlen(pager) + PAGE_USAGE_FMT_LEN;
Packit 549fdc
        res  = AGALOC(bfsz, "more cmd");
Packit 549fdc
        snprintf(res, bfsz, PAGE_USAGE_FMT, pager, fname);
Packit 549fdc
        AGFREE(fname);
Packit 549fdc
        return res;
Packit 549fdc
    }
Packit 549fdc
}
Packit 549fdc
#endif
Packit 549fdc
Packit 549fdc
/*=export_func  optionPagedUsage
Packit 549fdc
 * private:
Packit 549fdc
 *
Packit 549fdc
 * what:  emit help text and pass through a pager program.
Packit 549fdc
 * arg:   + tOptions * + opts + program options descriptor +
Packit 549fdc
 * arg:   + tOptDesc * + od   + the descriptor for this arg +
Packit 549fdc
 *
Packit 549fdc
 * doc:
Packit 549fdc
 *  Run the usage output through a pager.
Packit 549fdc
 *  This is very handy if it is very long.
Packit 549fdc
 *  This is disabled on platforms without a working fork() function.
Packit 549fdc
=*/
Packit 549fdc
void
Packit 549fdc
optionPagedUsage(tOptions * opts, tOptDesc * od)
Packit 549fdc
{
Packit 549fdc
#if ! defined(HAVE_WORKING_FORK)
Packit 549fdc
    if ((od->fOptState & OPTST_RESET) != 0)
Packit 549fdc
        return;
Packit 549fdc
Packit 549fdc
    (*opts->pUsageProc)(opts, EXIT_SUCCESS);
Packit 549fdc
#else
Packit 549fdc
    static bool sv_print_exit = false;
Packit 549fdc
    static char * fil_name = NULL;
Packit 549fdc
Packit 549fdc
    /*
Packit 549fdc
     *  IF we are being called after the usage proc is done
Packit 549fdc
     *     (and thus has called "exit(2)")
Packit 549fdc
     *  THEN invoke the pager to page through the usage file we created.
Packit 549fdc
     */
Packit 549fdc
    switch (pagerState) {
Packit 549fdc
    case PAGER_STATE_INITIAL:
Packit 549fdc
    {
Packit 549fdc
        if ((od->fOptState & OPTST_RESET) != 0)
Packit 549fdc
            return;
Packit 549fdc
        option_usage_fp = open_tmp_usage(&fil_name);
Packit 549fdc
        if (option_usage_fp == NULL)
Packit 549fdc
            (*opts->pUsageProc)(opts, EXIT_SUCCESS);
Packit 549fdc
Packit 549fdc
        pagerState    = PAGER_STATE_READY;
Packit 549fdc
        sv_print_exit = print_exit;
Packit 549fdc
Packit 549fdc
        /*
Packit 549fdc
         *  Set up so this routine gets called during the exit logic
Packit 549fdc
         */
Packit 549fdc
        atexit((void(*)(void))optionPagedUsage);
Packit 549fdc
Packit 549fdc
        /*
Packit 549fdc
         *  The usage procedure will now put the usage information into
Packit 549fdc
         *  the temporary file we created above.  Keep any shell commands
Packit 549fdc
         *  out of the result.
Packit 549fdc
         */
Packit 549fdc
        print_exit = false;
Packit 549fdc
        (*opts->pUsageProc)(opts, EXIT_SUCCESS);
Packit 549fdc
Packit 549fdc
        /* NOTREACHED */
Packit 549fdc
        _exit(EXIT_FAILURE);
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
    case PAGER_STATE_READY:
Packit 549fdc
        fil_name = mk_pager_cmd(fil_name);
Packit 549fdc
Packit 549fdc
        if (sv_print_exit) {
Packit 549fdc
            fputs("\nexit 0\n", stdout);
Packit 549fdc
            fclose(stdout);
Packit 549fdc
            dup2(STDERR_FILENO, STDOUT_FILENO);
Packit 549fdc
Packit 549fdc
        } else {
Packit 549fdc
            fclose(stderr);
Packit 549fdc
            dup2(STDOUT_FILENO, STDERR_FILENO);
Packit 549fdc
        }
Packit 549fdc
Packit 549fdc
        ignore_val( system( fil_name));
Packit 549fdc
        AGFREE(fil_name);
Packit 549fdc
Packit 549fdc
    case PAGER_STATE_CHILD:
Packit 549fdc
        /*
Packit 549fdc
         *  This is a child process used in creating shell script usage.
Packit 549fdc
         */
Packit 549fdc
        break;
Packit 549fdc
    }
Packit 549fdc
#endif
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/** @}
Packit 549fdc
 *
Packit 549fdc
 * Local Variables:
Packit 549fdc
 * mode: C
Packit 549fdc
 * c-file-style: "stroustrup"
Packit 549fdc
 * indent-tabs-mode: nil
Packit 549fdc
 * End:
Packit 549fdc
 * end of autoopts/pgusage.c */