1181834Sroberto 2285612Sdelphij/** 3285612Sdelphij * \file pgusage.c 4181834Sroberto * 5181834Sroberto * Automated Options Paged Usage module. 6181834Sroberto * 7285612Sdelphij * @addtogroup autoopts 8285612Sdelphij * @{ 9285612Sdelphij */ 10285612Sdelphij/* 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 * 14285612Sdelphij * This file is part of AutoOpts, a companion to AutoGen. 15285612Sdelphij * AutoOpts is free software. 16285612Sdelphij * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 17181834Sroberto * 18285612Sdelphij * AutoOpts is available under any one of two licenses. The license 19285612Sdelphij * in use must be one of these two and the choice is under the control 20285612Sdelphij * of the user of the license. 21181834Sroberto * 22285612Sdelphij * The GNU Lesser General Public License, version 3 or later 23285612Sdelphij * See the files "COPYING.lgplv3" and "COPYING.gplv3" 24181834Sroberto * 25285612Sdelphij * The Modified Berkeley Software Distribution License 26285612Sdelphij * See the file "COPYING.mbsd" 27181834Sroberto * 28285612Sdelphij * These files have the following sha256 sums: 29181834Sroberto * 30285612Sdelphij * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 31285612Sdelphij * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 32285612Sdelphij * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 33181834Sroberto */ 34181834Sroberto 35285612Sdelphij#if defined(HAVE_WORKING_FORK) 36285612Sdelphijstatic inline FILE * 37285612Sdelphijopen_tmp_usage(char ** buf) 38285612Sdelphij{ 39285612Sdelphij char * bf; 40285612Sdelphij size_t bfsz; 41181834Sroberto 42285612Sdelphij { 43285612Sdelphij unsigned int my_pid = (unsigned int)getpid(); 44285612Sdelphij char const * tmpdir = getenv(TMPDIR); 45285612Sdelphij if (tmpdir == NULL) 46285612Sdelphij tmpdir = tmp_dir; 47285612Sdelphij bfsz = TMP_FILE_FMT_LEN + strlen(tmpdir) + 10; 48285612Sdelphij bf = AGALOC(bfsz, "tmp fil"); 49285612Sdelphij snprintf(bf, bfsz, TMP_FILE_FMT, tmpdir, my_pid); 50285612Sdelphij } 51285612Sdelphij 52285612Sdelphij { 53285612Sdelphij static mode_t const cmask = S_IRWXO | S_IRWXG; 54285612Sdelphij mode_t svmsk = umask(cmask); 55285612Sdelphij int fd = mkstemp(bf); 56285612Sdelphij (void)umask(svmsk); 57285612Sdelphij 58285612Sdelphij if (fd < 0) { 59285612Sdelphij AGFREE(bf); 60285612Sdelphij return NULL; 61285612Sdelphij } 62285612Sdelphij *buf = bf; 63285612Sdelphij return fdopen(fd, "w"); 64285612Sdelphij } 65285612Sdelphij} 66285612Sdelphij 67285612Sdelphijstatic inline char * 68285612Sdelphijmk_pager_cmd(char const * fname) 69285612Sdelphij{ 70285612Sdelphij /* 71285612Sdelphij * Page the file and remove it when done. For shell script processing, 72285612Sdelphij * we must redirect the output to the current stderr, otherwise stdout. 73285612Sdelphij */ 74285612Sdelphij fclose(option_usage_fp); 75285612Sdelphij option_usage_fp = NULL; 76285612Sdelphij 77285612Sdelphij { 78285612Sdelphij char const * pager = (char const *)getenv(PAGER_NAME); 79285612Sdelphij size_t bfsz; 80285612Sdelphij char * res; 81285612Sdelphij 82285612Sdelphij /* 83285612Sdelphij * Use the "more(1)" program if "PAGER" has not been defined 84285612Sdelphij */ 85285612Sdelphij if (pager == NULL) 86285612Sdelphij pager = MORE_STR; 87285612Sdelphij 88285612Sdelphij bfsz = 2 * strlen(fname) + strlen(pager) + PAGE_USAGE_FMT_LEN; 89285612Sdelphij res = AGALOC(bfsz, "more cmd"); 90285612Sdelphij snprintf(res, bfsz, PAGE_USAGE_FMT, pager, fname); 91285612Sdelphij AGFREE(fname); 92285612Sdelphij return res; 93285612Sdelphij } 94285612Sdelphij} 95285612Sdelphij#endif 96285612Sdelphij 97181834Sroberto/*=export_func optionPagedUsage 98181834Sroberto * private: 99181834Sroberto * 100285612Sdelphij * what: emit help text and pass through a pager program. 101285612Sdelphij * arg: + tOptions * + opts + program options descriptor + 102285612Sdelphij * 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. 107285612Sdelphij * This is disabled on platforms without a working fork() function. 108181834Sroberto=*/ 109181834Srobertovoid 110285612SdelphijoptionPagedUsage(tOptions * opts, tOptDesc * od) 111181834Sroberto{ 112285612Sdelphij#if ! defined(HAVE_WORKING_FORK) 113285612Sdelphij if ((od->fOptState & OPTST_RESET) != 0) 114285612Sdelphij return; 115285612Sdelphij 116285612Sdelphij (*opts->pUsageProc)(opts, EXIT_SUCCESS); 117181834Sroberto#else 118285612Sdelphij static bool sv_print_exit = false; 119285612Sdelphij 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 { 129285612Sdelphij if ((od->fOptState & OPTST_RESET) != 0) 130285612Sdelphij return; 131285612Sdelphij option_usage_fp = open_tmp_usage(&fil_name); 132181834Sroberto if (option_usage_fp == NULL) 133285612Sdelphij (*opts->pUsageProc)(opts, EXIT_SUCCESS); 134181834Sroberto 135285612Sdelphij pagerState = PAGER_STATE_READY; 136285612Sdelphij sv_print_exit = print_exit; 137181834Sroberto 138181834Sroberto /* 139181834Sroberto * Set up so this routine gets called during the exit logic 140181834Sroberto */ 141285612Sdelphij atexit((void(*)(void))optionPagedUsage); 142181834Sroberto 143181834Sroberto /* 144181834Sroberto * The usage procedure will now put the usage information into 145285612Sdelphij * the temporary file we created above. Keep any shell commands 146285612Sdelphij * out of the result. 147181834Sroberto */ 148285612Sdelphij print_exit = false; 149285612Sdelphij (*opts->pUsageProc)(opts, EXIT_SUCCESS); 150181834Sroberto 151285612Sdelphij /* NOTREACHED */ 152285612Sdelphij _exit(EXIT_FAILURE); 153181834Sroberto } 154181834Sroberto 155181834Sroberto case PAGER_STATE_READY: 156285612Sdelphij fil_name = mk_pager_cmd(fil_name); 157181834Sroberto 158285612Sdelphij if (sv_print_exit) { 159285612Sdelphij fputs("\nexit 0\n", stdout); 160285612Sdelphij fclose(stdout); 161285612Sdelphij dup2(STDERR_FILENO, STDOUT_FILENO); 162181834Sroberto 163285612Sdelphij } else { 164285612Sdelphij fclose(stderr); 165285612Sdelphij dup2(STDOUT_FILENO, STDERR_FILENO); 166285612Sdelphij } 167181834Sroberto 168285612Sdelphij ignore_val( system( fil_name)); 169285612Sdelphij 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 180285612Sdelphij/** @} 181285612Sdelphij * 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