1181834Sroberto 2290001Sglebius/** 3290001Sglebius * \file pgusage.c 4181834Sroberto * 5181834Sroberto * Automated Options Paged Usage module. 6181834Sroberto * 7290001Sglebius * @addtogroup autoopts 8290001Sglebius * @{ 9290001Sglebius */ 10290001Sglebius/* 11181834Sroberto * This routine will run run-on options through a pager so the 12181834Sroberto * user may examine, print or edit them at their leisure. 13181834Sroberto * 14290001Sglebius * This file is part of AutoOpts, a companion to AutoGen. 15290001Sglebius * AutoOpts is free software. 16290001Sglebius * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 17181834Sroberto * 18290001Sglebius * AutoOpts is available under any one of two licenses. The license 19290001Sglebius * in use must be one of these two and the choice is under the control 20290001Sglebius * of the user of the license. 21181834Sroberto * 22290001Sglebius * The GNU Lesser General Public License, version 3 or later 23290001Sglebius * See the files "COPYING.lgplv3" and "COPYING.gplv3" 24181834Sroberto * 25290001Sglebius * The Modified Berkeley Software Distribution License 26290001Sglebius * See the file "COPYING.mbsd" 27181834Sroberto * 28290001Sglebius * These files have the following sha256 sums: 29181834Sroberto * 30290001Sglebius * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 31290001Sglebius * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 32290001Sglebius * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 33181834Sroberto */ 34181834Sroberto 35290001Sglebius#if defined(HAVE_WORKING_FORK) 36290001Sglebiusstatic inline FILE * 37290001Sglebiusopen_tmp_usage(char ** buf) 38290001Sglebius{ 39290001Sglebius char * bf; 40290001Sglebius size_t bfsz; 41181834Sroberto 42290001Sglebius { 43290001Sglebius unsigned int my_pid = (unsigned int)getpid(); 44290001Sglebius char const * tmpdir = getenv(TMPDIR); 45290001Sglebius if (tmpdir == NULL) 46290001Sglebius tmpdir = tmp_dir; 47290001Sglebius bfsz = TMP_FILE_FMT_LEN + strlen(tmpdir) + 10; 48290001Sglebius bf = AGALOC(bfsz, "tmp fil"); 49290001Sglebius snprintf(bf, bfsz, TMP_FILE_FMT, tmpdir, my_pid); 50290001Sglebius } 51290001Sglebius 52290001Sglebius { 53290001Sglebius static mode_t const cmask = S_IRWXO | S_IRWXG; 54290001Sglebius mode_t svmsk = umask(cmask); 55290001Sglebius int fd = mkstemp(bf); 56290001Sglebius (void)umask(svmsk); 57290001Sglebius 58290001Sglebius if (fd < 0) { 59290001Sglebius AGFREE(bf); 60290001Sglebius return NULL; 61290001Sglebius } 62290001Sglebius *buf = bf; 63290001Sglebius return fdopen(fd, "w"); 64290001Sglebius } 65290001Sglebius} 66290001Sglebius 67290001Sglebiusstatic inline char * 68290001Sglebiusmk_pager_cmd(char const * fname) 69290001Sglebius{ 70290001Sglebius /* 71290001Sglebius * Page the file and remove it when done. For shell script processing, 72290001Sglebius * we must redirect the output to the current stderr, otherwise stdout. 73290001Sglebius */ 74290001Sglebius fclose(option_usage_fp); 75290001Sglebius option_usage_fp = NULL; 76290001Sglebius 77290001Sglebius { 78290001Sglebius char const * pager = (char const *)getenv(PAGER_NAME); 79290001Sglebius size_t bfsz; 80290001Sglebius char * res; 81290001Sglebius 82290001Sglebius /* 83290001Sglebius * Use the "more(1)" program if "PAGER" has not been defined 84290001Sglebius */ 85290001Sglebius if (pager == NULL) 86290001Sglebius pager = MORE_STR; 87290001Sglebius 88290001Sglebius bfsz = 2 * strlen(fname) + strlen(pager) + PAGE_USAGE_FMT_LEN; 89290001Sglebius res = AGALOC(bfsz, "more cmd"); 90290001Sglebius snprintf(res, bfsz, PAGE_USAGE_FMT, pager, fname); 91290001Sglebius AGFREE(fname); 92290001Sglebius return res; 93290001Sglebius } 94290001Sglebius} 95290001Sglebius#endif 96290001Sglebius 97181834Sroberto/*=export_func optionPagedUsage 98181834Sroberto * private: 99181834Sroberto * 100290001Sglebius * what: emit help text and pass through a pager program. 101290001Sglebius * arg: + tOptions * + opts + program options descriptor + 102290001Sglebius * arg: + tOptDesc * + od + the descriptor for this arg + 103181834Sroberto * 104181834Sroberto * doc: 105181834Sroberto * Run the usage output through a pager. 106181834Sroberto * This is very handy if it is very long. 107290001Sglebius * This is disabled on platforms without a working fork() function. 108181834Sroberto=*/ 109181834Srobertovoid 110290001SglebiusoptionPagedUsage(tOptions * opts, tOptDesc * od) 111181834Sroberto{ 112290001Sglebius#if ! defined(HAVE_WORKING_FORK) 113290001Sglebius if ((od->fOptState & OPTST_RESET) != 0) 114290001Sglebius return; 115290001Sglebius 116290001Sglebius (*opts->pUsageProc)(opts, EXIT_SUCCESS); 117181834Sroberto#else 118290001Sglebius static bool sv_print_exit = false; 119290001Sglebius static char * fil_name = NULL; 120181834Sroberto 121181834Sroberto /* 122181834Sroberto * IF we are being called after the usage proc is done 123181834Sroberto * (and thus has called "exit(2)") 124181834Sroberto * THEN invoke the pager to page through the usage file we created. 125181834Sroberto */ 126181834Sroberto switch (pagerState) { 127181834Sroberto case PAGER_STATE_INITIAL: 128181834Sroberto { 129290001Sglebius if ((od->fOptState & OPTST_RESET) != 0) 130290001Sglebius return; 131290001Sglebius option_usage_fp = open_tmp_usage(&fil_name); 132181834Sroberto if (option_usage_fp == NULL) 133290001Sglebius (*opts->pUsageProc)(opts, EXIT_SUCCESS); 134181834Sroberto 135290001Sglebius pagerState = PAGER_STATE_READY; 136290001Sglebius sv_print_exit = print_exit; 137181834Sroberto 138181834Sroberto /* 139181834Sroberto * Set up so this routine gets called during the exit logic 140181834Sroberto */ 141290001Sglebius atexit((void(*)(void))optionPagedUsage); 142181834Sroberto 143181834Sroberto /* 144181834Sroberto * The usage procedure will now put the usage information into 145290001Sglebius * the temporary file we created above. Keep any shell commands 146290001Sglebius * out of the result. 147181834Sroberto */ 148290001Sglebius print_exit = false; 149290001Sglebius (*opts->pUsageProc)(opts, EXIT_SUCCESS); 150181834Sroberto 151290001Sglebius /* NOTREACHED */ 152290001Sglebius _exit(EXIT_FAILURE); 153181834Sroberto } 154181834Sroberto 155181834Sroberto case PAGER_STATE_READY: 156290001Sglebius fil_name = mk_pager_cmd(fil_name); 157181834Sroberto 158290001Sglebius if (sv_print_exit) { 159290001Sglebius fputs("\nexit 0\n", stdout); 160290001Sglebius fclose(stdout); 161290001Sglebius dup2(STDERR_FILENO, STDOUT_FILENO); 162181834Sroberto 163290001Sglebius } else { 164290001Sglebius fclose(stderr); 165290001Sglebius dup2(STDOUT_FILENO, STDERR_FILENO); 166290001Sglebius } 167181834Sroberto 168290001Sglebius ignore_val( system( fil_name)); 169290001Sglebius AGFREE(fil_name); 170181834Sroberto 171181834Sroberto case PAGER_STATE_CHILD: 172181834Sroberto /* 173181834Sroberto * This is a child process used in creating shell script usage. 174181834Sroberto */ 175181834Sroberto break; 176181834Sroberto } 177181834Sroberto#endif 178181834Sroberto} 179181834Sroberto 180290001Sglebius/** @} 181290001Sglebius * 182181834Sroberto * Local Variables: 183181834Sroberto * mode: C 184181834Sroberto * c-file-style: "stroustrup" 185181834Sroberto * indent-tabs-mode: nil 186181834Sroberto * End: 187181834Sroberto * end of autoopts/pgusage.c */ 188