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