1ea906c41SOllivier Robert
22b15cb3dSCy Schubert /**
32b15cb3dSCy Schubert * \file pgusage.c
4ea906c41SOllivier Robert *
5ea906c41SOllivier Robert * Automated Options Paged Usage module.
6ea906c41SOllivier Robert *
72b15cb3dSCy Schubert * @addtogroup autoopts
82b15cb3dSCy Schubert * @{
92b15cb3dSCy Schubert */
102b15cb3dSCy Schubert /*
11ea906c41SOllivier Robert * This routine will run run-on options through a pager so the
12ea906c41SOllivier Robert * user may examine, print or edit them at their leisure.
132b15cb3dSCy Schubert *
142b15cb3dSCy Schubert * This file is part of AutoOpts, a companion to AutoGen.
152b15cb3dSCy Schubert * AutoOpts is free software.
16*a466cc55SCy Schubert * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
172b15cb3dSCy Schubert *
182b15cb3dSCy Schubert * AutoOpts is available under any one of two licenses. The license
192b15cb3dSCy Schubert * in use must be one of these two and the choice is under the control
202b15cb3dSCy Schubert * of the user of the license.
212b15cb3dSCy Schubert *
222b15cb3dSCy Schubert * The GNU Lesser General Public License, version 3 or later
232b15cb3dSCy Schubert * See the files "COPYING.lgplv3" and "COPYING.gplv3"
242b15cb3dSCy Schubert *
252b15cb3dSCy Schubert * The Modified Berkeley Software Distribution License
262b15cb3dSCy Schubert * See the file "COPYING.mbsd"
272b15cb3dSCy Schubert *
282b15cb3dSCy Schubert * These files have the following sha256 sums:
292b15cb3dSCy Schubert *
302b15cb3dSCy Schubert * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3
312b15cb3dSCy Schubert * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3
322b15cb3dSCy Schubert * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd
33ea906c41SOllivier Robert */
34ea906c41SOllivier Robert
352b15cb3dSCy Schubert #if defined(HAVE_WORKING_FORK)
36276da39aSCy Schubert static inline FILE *
open_tmp_usage(char ** buf)372b15cb3dSCy Schubert open_tmp_usage(char ** buf)
382b15cb3dSCy Schubert {
392b15cb3dSCy Schubert char * bf;
402b15cb3dSCy Schubert size_t bfsz;
412b15cb3dSCy Schubert
422b15cb3dSCy Schubert {
432b15cb3dSCy Schubert unsigned int my_pid = (unsigned int)getpid();
442b15cb3dSCy Schubert char const * tmpdir = getenv(TMPDIR);
452b15cb3dSCy Schubert if (tmpdir == NULL)
462b15cb3dSCy Schubert tmpdir = tmp_dir;
472b15cb3dSCy Schubert bfsz = TMP_FILE_FMT_LEN + strlen(tmpdir) + 10;
482b15cb3dSCy Schubert bf = AGALOC(bfsz, "tmp fil");
492b15cb3dSCy Schubert snprintf(bf, bfsz, TMP_FILE_FMT, tmpdir, my_pid);
502b15cb3dSCy Schubert }
512b15cb3dSCy Schubert
522b15cb3dSCy Schubert {
532b15cb3dSCy Schubert static mode_t const cmask = S_IRWXO | S_IRWXG;
542b15cb3dSCy Schubert mode_t svmsk = umask(cmask);
552b15cb3dSCy Schubert int fd = mkstemp(bf);
562b15cb3dSCy Schubert (void)umask(svmsk);
572b15cb3dSCy Schubert
582b15cb3dSCy Schubert if (fd < 0) {
592b15cb3dSCy Schubert AGFREE(bf);
602b15cb3dSCy Schubert return NULL;
612b15cb3dSCy Schubert }
622b15cb3dSCy Schubert *buf = bf;
632b15cb3dSCy Schubert return fdopen(fd, "w");
642b15cb3dSCy Schubert }
652b15cb3dSCy Schubert }
662b15cb3dSCy Schubert
67276da39aSCy Schubert static inline char *
mk_pager_cmd(char const * fname)682b15cb3dSCy Schubert mk_pager_cmd(char const * fname)
692b15cb3dSCy Schubert {
702b15cb3dSCy Schubert /*
712b15cb3dSCy Schubert * Page the file and remove it when done. For shell script processing,
722b15cb3dSCy Schubert * we must redirect the output to the current stderr, otherwise stdout.
732b15cb3dSCy Schubert */
742b15cb3dSCy Schubert fclose(option_usage_fp);
752b15cb3dSCy Schubert option_usage_fp = NULL;
762b15cb3dSCy Schubert
772b15cb3dSCy Schubert {
782b15cb3dSCy Schubert char const * pager = (char const *)getenv(PAGER_NAME);
792b15cb3dSCy Schubert size_t bfsz;
802b15cb3dSCy Schubert char * res;
812b15cb3dSCy Schubert
82ea906c41SOllivier Robert /*
832b15cb3dSCy Schubert * Use the "more(1)" program if "PAGER" has not been defined
84ea906c41SOllivier Robert */
852b15cb3dSCy Schubert if (pager == NULL)
862b15cb3dSCy Schubert pager = MORE_STR;
87ea906c41SOllivier Robert
88276da39aSCy Schubert bfsz = 2 * strlen(fname) + strlen(pager) + PAGE_USAGE_FMT_LEN;
892b15cb3dSCy Schubert res = AGALOC(bfsz, "more cmd");
902b15cb3dSCy Schubert snprintf(res, bfsz, PAGE_USAGE_FMT, pager, fname);
91276da39aSCy Schubert AGFREE(fname);
922b15cb3dSCy Schubert return res;
932b15cb3dSCy Schubert }
942b15cb3dSCy Schubert }
952b15cb3dSCy Schubert #endif
96ea906c41SOllivier Robert
97ea906c41SOllivier Robert /*=export_func optionPagedUsage
98ea906c41SOllivier Robert * private:
99ea906c41SOllivier Robert *
1002b15cb3dSCy Schubert * what: emit help text and pass through a pager program.
1012b15cb3dSCy Schubert * arg: + tOptions * + opts + program options descriptor +
1022b15cb3dSCy Schubert * arg: + tOptDesc * + od + the descriptor for this arg +
103ea906c41SOllivier Robert *
104ea906c41SOllivier Robert * doc:
105ea906c41SOllivier Robert * Run the usage output through a pager.
106ea906c41SOllivier Robert * This is very handy if it is very long.
1072b15cb3dSCy Schubert * This is disabled on platforms without a working fork() function.
108ea906c41SOllivier Robert =*/
109ea906c41SOllivier Robert void
optionPagedUsage(tOptions * opts,tOptDesc * od)1102b15cb3dSCy Schubert optionPagedUsage(tOptions * opts, tOptDesc * od)
111ea906c41SOllivier Robert {
1122b15cb3dSCy Schubert #if ! defined(HAVE_WORKING_FORK)
1132b15cb3dSCy Schubert if ((od->fOptState & OPTST_RESET) != 0)
1142b15cb3dSCy Schubert return;
1152b15cb3dSCy Schubert
1162b15cb3dSCy Schubert (*opts->pUsageProc)(opts, EXIT_SUCCESS);
117ea906c41SOllivier Robert #else
1182b15cb3dSCy Schubert static bool sv_print_exit = false;
1192b15cb3dSCy Schubert static char * fil_name = NULL;
120ea906c41SOllivier Robert
121ea906c41SOllivier Robert /*
122ea906c41SOllivier Robert * IF we are being called after the usage proc is done
123ea906c41SOllivier Robert * (and thus has called "exit(2)")
124ea906c41SOllivier Robert * THEN invoke the pager to page through the usage file we created.
125ea906c41SOllivier Robert */
126ea906c41SOllivier Robert switch (pagerState) {
127ea906c41SOllivier Robert case PAGER_STATE_INITIAL:
128ea906c41SOllivier Robert {
1292b15cb3dSCy Schubert if ((od->fOptState & OPTST_RESET) != 0)
1302b15cb3dSCy Schubert return;
1312b15cb3dSCy Schubert option_usage_fp = open_tmp_usage(&fil_name);
132ea906c41SOllivier Robert if (option_usage_fp == NULL)
1332b15cb3dSCy Schubert (*opts->pUsageProc)(opts, EXIT_SUCCESS);
134ea906c41SOllivier Robert
135ea906c41SOllivier Robert pagerState = PAGER_STATE_READY;
1362b15cb3dSCy Schubert sv_print_exit = print_exit;
137ea906c41SOllivier Robert
138ea906c41SOllivier Robert /*
139ea906c41SOllivier Robert * Set up so this routine gets called during the exit logic
140ea906c41SOllivier Robert */
141ea906c41SOllivier Robert atexit((void(*)(void))optionPagedUsage);
142ea906c41SOllivier Robert
143ea906c41SOllivier Robert /*
144ea906c41SOllivier Robert * The usage procedure will now put the usage information into
1452b15cb3dSCy Schubert * the temporary file we created above. Keep any shell commands
1462b15cb3dSCy Schubert * out of the result.
147ea906c41SOllivier Robert */
1482b15cb3dSCy Schubert print_exit = false;
1492b15cb3dSCy Schubert (*opts->pUsageProc)(opts, EXIT_SUCCESS);
150ea906c41SOllivier Robert
151ea906c41SOllivier Robert /* NOTREACHED */
152ea906c41SOllivier Robert _exit(EXIT_FAILURE);
153ea906c41SOllivier Robert }
154ea906c41SOllivier Robert
155ea906c41SOllivier Robert case PAGER_STATE_READY:
1562b15cb3dSCy Schubert fil_name = mk_pager_cmd(fil_name);
157ea906c41SOllivier Robert
1582b15cb3dSCy Schubert if (sv_print_exit) {
1592b15cb3dSCy Schubert fputs("\nexit 0\n", stdout);
1602b15cb3dSCy Schubert fclose(stdout);
1612b15cb3dSCy Schubert dup2(STDERR_FILENO, STDOUT_FILENO);
162ea906c41SOllivier Robert
1632b15cb3dSCy Schubert } else {
164ea906c41SOllivier Robert fclose(stderr);
165ea906c41SOllivier Robert dup2(STDOUT_FILENO, STDERR_FILENO);
166ea906c41SOllivier Robert }
167ea906c41SOllivier Robert
1682b15cb3dSCy Schubert ignore_val( system( fil_name));
1692b15cb3dSCy Schubert AGFREE(fil_name);
1702b15cb3dSCy Schubert
171ea906c41SOllivier Robert case PAGER_STATE_CHILD:
172ea906c41SOllivier Robert /*
173ea906c41SOllivier Robert * This is a child process used in creating shell script usage.
174ea906c41SOllivier Robert */
175ea906c41SOllivier Robert break;
176ea906c41SOllivier Robert }
177ea906c41SOllivier Robert #endif
178ea906c41SOllivier Robert }
179ea906c41SOllivier Robert
1802b15cb3dSCy Schubert /** @}
1812b15cb3dSCy Schubert *
182ea906c41SOllivier Robert * Local Variables:
183ea906c41SOllivier Robert * mode: C
184ea906c41SOllivier Robert * c-file-style: "stroustrup"
185ea906c41SOllivier Robert * indent-tabs-mode: nil
186ea906c41SOllivier Robert * End:
187ea906c41SOllivier Robert * end of autoopts/pgusage.c */
188