1ea906c41SOllivier Robert 22b15cb3dSCy Schubert /** 32b15cb3dSCy Schubert * \file makeshell.c 4ea906c41SOllivier Robert * 5ea906c41SOllivier Robert * This module will interpret the options set in the tOptions 6ea906c41SOllivier Robert * structure and create a Bourne shell script capable of parsing them. 72b15cb3dSCy Schubert * 82b15cb3dSCy Schubert * @addtogroup autoopts 92b15cb3dSCy Schubert * @{ 10ea906c41SOllivier Robert */ 11ea906c41SOllivier Robert /* 122b15cb3dSCy Schubert * This file is part of AutoOpts, a companion to AutoGen. 132b15cb3dSCy Schubert * AutoOpts is free software. 14*276da39aSCy Schubert * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 15ea906c41SOllivier Robert * 162b15cb3dSCy Schubert * AutoOpts is available under any one of two licenses. The license 172b15cb3dSCy Schubert * in use must be one of these two and the choice is under the control 182b15cb3dSCy Schubert * of the user of the license. 19ea906c41SOllivier Robert * 202b15cb3dSCy Schubert * The GNU Lesser General Public License, version 3 or later 212b15cb3dSCy Schubert * See the files "COPYING.lgplv3" and "COPYING.gplv3" 22ea906c41SOllivier Robert * 232b15cb3dSCy Schubert * The Modified Berkeley Software Distribution License 242b15cb3dSCy Schubert * See the file "COPYING.mbsd" 25ea906c41SOllivier Robert * 262b15cb3dSCy Schubert * These files have the following sha256 sums: 27ea906c41SOllivier Robert * 282b15cb3dSCy Schubert * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 292b15cb3dSCy Schubert * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 302b15cb3dSCy Schubert * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 31ea906c41SOllivier Robert */ 32ea906c41SOllivier Robert 33*276da39aSCy Schubert static inline unsigned char to_uchar (char ch) { return ch; } 34*276da39aSCy Schubert 35*276da39aSCy Schubert #define UPPER(_c) (toupper(to_uchar(_c))) 36*276da39aSCy Schubert #define LOWER(_c) (tolower(to_uchar(_c))) 37*276da39aSCy Schubert 38ea906c41SOllivier Robert /* = = = START-STATIC-FORWARD = = = */ 39ea906c41SOllivier Robert static void 402b15cb3dSCy Schubert emit_var_text(char const * prog, char const * var, int fdin); 41ea906c41SOllivier Robert 42ea906c41SOllivier Robert static void 432b15cb3dSCy Schubert text_to_var(tOptions * opts, teTextTo which, tOptDesc * od); 44ea906c41SOllivier Robert 45ea906c41SOllivier Robert static void 462b15cb3dSCy Schubert emit_usage(tOptions * opts); 47ea906c41SOllivier Robert 48ea906c41SOllivier Robert static void 492b15cb3dSCy Schubert emit_wrapup(tOptions * opts); 50ea906c41SOllivier Robert 51ea906c41SOllivier Robert static void 522b15cb3dSCy Schubert emit_setup(tOptions * opts); 53ea906c41SOllivier Robert 54ea906c41SOllivier Robert static void 552b15cb3dSCy Schubert emit_action(tOptions * opts, tOptDesc * od); 56ea906c41SOllivier Robert 57ea906c41SOllivier Robert static void 582b15cb3dSCy Schubert emit_inaction(tOptions * opts, tOptDesc * od); 59ea906c41SOllivier Robert 60ea906c41SOllivier Robert static void 612b15cb3dSCy Schubert emit_flag(tOptions * opts); 62ea906c41SOllivier Robert 63ea906c41SOllivier Robert static void 642b15cb3dSCy Schubert emit_match_expr(char const * name, tOptDesc * cod, tOptions * opts); 652b15cb3dSCy Schubert 662b15cb3dSCy Schubert static void 672b15cb3dSCy Schubert emit_long(tOptions * opts); 682b15cb3dSCy Schubert 692b15cb3dSCy Schubert static char * 702b15cb3dSCy Schubert load_old_output(char const * fname, char const * pname); 712b15cb3dSCy Schubert 722b15cb3dSCy Schubert static void 732b15cb3dSCy Schubert open_out(char const * fname, char const * pname); 74ea906c41SOllivier Robert /* = = = END-STATIC-FORWARD = = = */ 75ea906c41SOllivier Robert 762b15cb3dSCy Schubert LOCAL noreturn void 772b15cb3dSCy Schubert option_exits(int exit_code) 782b15cb3dSCy Schubert { 792b15cb3dSCy Schubert if (print_exit) 802b15cb3dSCy Schubert printf("\nexit %d\n", exit_code); 812b15cb3dSCy Schubert exit(exit_code); 822b15cb3dSCy Schubert } 832b15cb3dSCy Schubert 842b15cb3dSCy Schubert LOCAL noreturn void 852b15cb3dSCy Schubert ao_bug(char const * msg) 862b15cb3dSCy Schubert { 872b15cb3dSCy Schubert fprintf(stderr, zao_bug_msg, msg); 882b15cb3dSCy Schubert option_exits(EX_SOFTWARE); 892b15cb3dSCy Schubert } 902b15cb3dSCy Schubert 912b15cb3dSCy Schubert LOCAL void 922b15cb3dSCy Schubert fserr_warn(char const * prog, char const * op, char const * fname) 932b15cb3dSCy Schubert { 942b15cb3dSCy Schubert fprintf(stderr, zfserr_fmt, prog, errno, strerror(errno), 952b15cb3dSCy Schubert op, fname); 962b15cb3dSCy Schubert } 972b15cb3dSCy Schubert 982b15cb3dSCy Schubert LOCAL noreturn void 992b15cb3dSCy Schubert fserr_exit(char const * prog, char const * op, char const * fname) 1002b15cb3dSCy Schubert { 1012b15cb3dSCy Schubert fserr_warn(prog, op, fname); 1022b15cb3dSCy Schubert option_exits(EXIT_FAILURE); 1032b15cb3dSCy Schubert } 1042b15cb3dSCy Schubert 105ea906c41SOllivier Robert /*=export_func optionParseShell 106ea906c41SOllivier Robert * private: 107ea906c41SOllivier Robert * 108ea906c41SOllivier Robert * what: Decipher a boolean value 109ea906c41SOllivier Robert * arg: + tOptions * + pOpts + program options descriptor + 110ea906c41SOllivier Robert * 111ea906c41SOllivier Robert * doc: 112ea906c41SOllivier Robert * Emit a shell script that will parse the command line options. 113ea906c41SOllivier Robert =*/ 114ea906c41SOllivier Robert void 1152b15cb3dSCy Schubert optionParseShell(tOptions * opts) 116ea906c41SOllivier Robert { 117ea906c41SOllivier Robert /* 118ea906c41SOllivier Robert * Check for our SHELL option now. 119ea906c41SOllivier Robert * IF the output file contains the "#!" magic marker, 120ea906c41SOllivier Robert * it will override anything we do here. 121ea906c41SOllivier Robert */ 1222b15cb3dSCy Schubert if (HAVE_GENSHELL_OPT(SHELL)) 1232b15cb3dSCy Schubert shell_prog = GENSHELL_OPT_ARG(SHELL); 124ea906c41SOllivier Robert 1252b15cb3dSCy Schubert else if (! ENABLED_GENSHELL_OPT(SHELL)) 1262b15cb3dSCy Schubert shell_prog = NULL; 127ea906c41SOllivier Robert 1282b15cb3dSCy Schubert else if ((shell_prog = getenv("SHELL")), 1292b15cb3dSCy Schubert shell_prog == NULL) 130ea906c41SOllivier Robert 1312b15cb3dSCy Schubert shell_prog = POSIX_SHELL; 132ea906c41SOllivier Robert 133ea906c41SOllivier Robert /* 134ea906c41SOllivier Robert * Check for a specified output file 135ea906c41SOllivier Robert */ 1362b15cb3dSCy Schubert if (HAVE_GENSHELL_OPT(SCRIPT)) 1372b15cb3dSCy Schubert open_out(GENSHELL_OPT_ARG(SCRIPT), opts->pzProgName); 138ea906c41SOllivier Robert 1392b15cb3dSCy Schubert emit_usage(opts); 1402b15cb3dSCy Schubert emit_setup(opts); 141ea906c41SOllivier Robert 142ea906c41SOllivier Robert /* 143ea906c41SOllivier Robert * There are four modes of option processing. 144ea906c41SOllivier Robert */ 1452b15cb3dSCy Schubert switch (opts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) { 146ea906c41SOllivier Robert case OPTPROC_LONGOPT: 1472b15cb3dSCy Schubert fputs(LOOP_STR, stdout); 148ea906c41SOllivier Robert 1492b15cb3dSCy Schubert fputs(LONG_OPT_MARK, stdout); 1502b15cb3dSCy Schubert fputs(INIT_LOPT_STR, stdout); 1512b15cb3dSCy Schubert emit_long(opts); 1522b15cb3dSCy Schubert printf(LOPT_ARG_FMT, opts->pzPROGNAME); 1532b15cb3dSCy Schubert fputs(END_OPT_SEL_STR, stdout); 154ea906c41SOllivier Robert 1552b15cb3dSCy Schubert fputs(NOT_FOUND_STR, stdout); 156ea906c41SOllivier Robert break; 157ea906c41SOllivier Robert 158ea906c41SOllivier Robert case 0: 1592b15cb3dSCy Schubert fputs(ONLY_OPTS_LOOP, stdout); 1602b15cb3dSCy Schubert fputs(INIT_LOPT_STR, stdout); 1612b15cb3dSCy Schubert emit_long(opts); 1622b15cb3dSCy Schubert printf(LOPT_ARG_FMT, opts->pzPROGNAME); 163ea906c41SOllivier Robert break; 164ea906c41SOllivier Robert 165ea906c41SOllivier Robert case OPTPROC_SHORTOPT: 1662b15cb3dSCy Schubert fputs(LOOP_STR, stdout); 167ea906c41SOllivier Robert 1682b15cb3dSCy Schubert fputs(FLAG_OPT_MARK, stdout); 1692b15cb3dSCy Schubert fputs(INIT_OPT_STR, stdout); 1702b15cb3dSCy Schubert emit_flag(opts); 1712b15cb3dSCy Schubert printf(OPT_ARG_FMT, opts->pzPROGNAME); 1722b15cb3dSCy Schubert fputs(END_OPT_SEL_STR, stdout); 173ea906c41SOllivier Robert 1742b15cb3dSCy Schubert fputs(NOT_FOUND_STR, stdout); 175ea906c41SOllivier Robert break; 176ea906c41SOllivier Robert 177ea906c41SOllivier Robert case OPTPROC_LONGOPT|OPTPROC_SHORTOPT: 1782b15cb3dSCy Schubert fputs(LOOP_STR, stdout); 179ea906c41SOllivier Robert 1802b15cb3dSCy Schubert fputs(LONG_OPT_MARK, stdout); 1812b15cb3dSCy Schubert fputs(INIT_LOPT_STR, stdout); 1822b15cb3dSCy Schubert emit_long(opts); 1832b15cb3dSCy Schubert printf(LOPT_ARG_FMT, opts->pzPROGNAME); 1842b15cb3dSCy Schubert fputs(END_OPT_SEL_STR, stdout); 185ea906c41SOllivier Robert 1862b15cb3dSCy Schubert fputs(FLAG_OPT_MARK, stdout); 1872b15cb3dSCy Schubert fputs(INIT_OPT_STR, stdout); 1882b15cb3dSCy Schubert emit_flag(opts); 1892b15cb3dSCy Schubert printf(OPT_ARG_FMT, opts->pzPROGNAME); 1902b15cb3dSCy Schubert fputs(END_OPT_SEL_STR, stdout); 191ea906c41SOllivier Robert 1922b15cb3dSCy Schubert fputs(NOT_FOUND_STR, stdout); 193ea906c41SOllivier Robert break; 194ea906c41SOllivier Robert } 195ea906c41SOllivier Robert 1962b15cb3dSCy Schubert emit_wrapup(opts); 1972b15cb3dSCy Schubert if ((script_trailer != NULL) && (*script_trailer != NUL)) 1982b15cb3dSCy Schubert fputs(script_trailer, stdout); 1992b15cb3dSCy Schubert else if (ENABLED_GENSHELL_OPT(SHELL)) 2002b15cb3dSCy Schubert printf(SHOW_PROG_ENV, opts->pzPROGNAME); 201ea906c41SOllivier Robert 2022b15cb3dSCy Schubert #ifdef HAVE_FCHMOD 203ea906c41SOllivier Robert fchmod(STDOUT_FILENO, 0755); 2042b15cb3dSCy Schubert #endif 205ea906c41SOllivier Robert fclose(stdout); 2062b15cb3dSCy Schubert 2072b15cb3dSCy Schubert if (ferror(stdout)) 2082b15cb3dSCy Schubert fserr_exit(opts->pzProgName, zwriting, zstdout_name); 2092b15cb3dSCy Schubert 2102b15cb3dSCy Schubert AGFREE(script_text); 2112b15cb3dSCy Schubert script_leader = NULL; 2122b15cb3dSCy Schubert script_trailer = NULL; 2132b15cb3dSCy Schubert script_text = NULL; 214ea906c41SOllivier Robert } 215ea906c41SOllivier Robert 2162b15cb3dSCy Schubert #ifdef HAVE_WORKING_FORK 2172b15cb3dSCy Schubert /** 2182b15cb3dSCy Schubert * Print the value of "var" to a file descriptor. 2192b15cb3dSCy Schubert * The "fdin" is the read end of a pipe to a forked process that 2202b15cb3dSCy Schubert * is writing usage text to it. We read that text in and re-emit 2212b15cb3dSCy Schubert * to standard out, formatting it so that it is assigned to a 2222b15cb3dSCy Schubert * shell variable. 2232b15cb3dSCy Schubert * 2242b15cb3dSCy Schubert * @param[in] prog The capitalized, c-variable-formatted program name 2252b15cb3dSCy Schubert * @param[in] var a similarly formatted type name 2262b15cb3dSCy Schubert * (LONGUSAGE, USAGE or VERSION) 2272b15cb3dSCy Schubert * @param[in] fdin the input end of a pipe 2282b15cb3dSCy Schubert */ 229ea906c41SOllivier Robert static void 2302b15cb3dSCy Schubert emit_var_text(char const * prog, char const * var, int fdin) 231ea906c41SOllivier Robert { 2322b15cb3dSCy Schubert FILE * fp = fdopen(fdin, "r" FOPEN_BINARY_FLAG); 2332b15cb3dSCy Schubert int nlct = 0; /* defer newlines and skip trailing ones */ 234ea906c41SOllivier Robert 2352b15cb3dSCy Schubert printf(SET_TEXT_FMT, prog, var); 2362b15cb3dSCy Schubert if (fp == NULL) 2372b15cb3dSCy Schubert goto skip_text; 238ea906c41SOllivier Robert 239ea906c41SOllivier Robert for (;;) { 240ea906c41SOllivier Robert int ch = fgetc(fp); 241ea906c41SOllivier Robert switch (ch) { 242ea906c41SOllivier Robert 2432b15cb3dSCy Schubert case NL: 2442b15cb3dSCy Schubert nlct++; 245ea906c41SOllivier Robert break; 246ea906c41SOllivier Robert 247ea906c41SOllivier Robert case '\'': 2482b15cb3dSCy Schubert while (nlct > 0) { 2492b15cb3dSCy Schubert fputc(NL, stdout); 2502b15cb3dSCy Schubert nlct--; 251ea906c41SOllivier Robert } 2522b15cb3dSCy Schubert fputs(apostrophe, stdout); 253ea906c41SOllivier Robert break; 254ea906c41SOllivier Robert 255ea906c41SOllivier Robert case EOF: 2562b15cb3dSCy Schubert goto done; 257ea906c41SOllivier Robert 258ea906c41SOllivier Robert default: 2592b15cb3dSCy Schubert while (nlct > 0) { 2602b15cb3dSCy Schubert fputc(NL, stdout); 2612b15cb3dSCy Schubert nlct--; 262ea906c41SOllivier Robert } 263ea906c41SOllivier Robert fputc(ch, stdout); 264ea906c41SOllivier Robert break; 265ea906c41SOllivier Robert } 2662b15cb3dSCy Schubert } done:; 267ea906c41SOllivier Robert 2682b15cb3dSCy Schubert fclose(fp); 2692b15cb3dSCy Schubert 2702b15cb3dSCy Schubert skip_text: 2712b15cb3dSCy Schubert 2722b15cb3dSCy Schubert fputs(END_SET_TEXT, stdout); 2732b15cb3dSCy Schubert } 2742b15cb3dSCy Schubert #endif 2752b15cb3dSCy Schubert 2762b15cb3dSCy Schubert /** 2772b15cb3dSCy Schubert * The purpose of this function is to assign "long usage", short usage 2782b15cb3dSCy Schubert * and version information to a shell variable. Rather than wind our 2792b15cb3dSCy Schubert * way through all the logic necessary to emit the text directly, we 2802b15cb3dSCy Schubert * fork(), have our child process emit the text the normal way and 2812b15cb3dSCy Schubert * capture the output in the parent process. 2822b15cb3dSCy Schubert * 2832b15cb3dSCy Schubert * @param[in] opts the program options 2842b15cb3dSCy Schubert * @param[in] which what to print: long usage, usage or version 2852b15cb3dSCy Schubert * @param[in] od for TT_VERSION, it is the version option 2862b15cb3dSCy Schubert */ 2872b15cb3dSCy Schubert static void 2882b15cb3dSCy Schubert text_to_var(tOptions * opts, teTextTo which, tOptDesc * od) 2892b15cb3dSCy Schubert { 2902b15cb3dSCy Schubert # define _TT_(n) static char const z ## n [] = #n; 2912b15cb3dSCy Schubert TEXTTO_TABLE 2922b15cb3dSCy Schubert # undef _TT_ 2932b15cb3dSCy Schubert # define _TT_(n) z ## n , 2942b15cb3dSCy Schubert static char const * ttnames[] = { TEXTTO_TABLE }; 2952b15cb3dSCy Schubert # undef _TT_ 2962b15cb3dSCy Schubert 2972b15cb3dSCy Schubert #if ! defined(HAVE_WORKING_FORK) 2982b15cb3dSCy Schubert printf(SET_NO_TEXT_FMT, opts->pzPROGNAME, ttnames[which]); 2992b15cb3dSCy Schubert #else 3002b15cb3dSCy Schubert int fdpair[2]; 3012b15cb3dSCy Schubert 3022b15cb3dSCy Schubert fflush(stdout); 3032b15cb3dSCy Schubert fflush(stderr); 3042b15cb3dSCy Schubert 3052b15cb3dSCy Schubert if (pipe(fdpair) != 0) 3062b15cb3dSCy Schubert fserr_exit(opts->pzProgName, "pipe", zinter_proc_pipe); 3072b15cb3dSCy Schubert 3082b15cb3dSCy Schubert switch (fork()) { 3092b15cb3dSCy Schubert case -1: 3102b15cb3dSCy Schubert fserr_exit(opts->pzProgName, "fork", opts->pzProgName); 3112b15cb3dSCy Schubert /* NOTREACHED */ 3122b15cb3dSCy Schubert 3132b15cb3dSCy Schubert case 0: 3142b15cb3dSCy Schubert /* 3152b15cb3dSCy Schubert * Send both stderr and stdout to the pipe. No matter which 3162b15cb3dSCy Schubert * descriptor is used, we capture the output on the read end. 3172b15cb3dSCy Schubert */ 3182b15cb3dSCy Schubert dup2(fdpair[1], STDERR_FILENO); 3192b15cb3dSCy Schubert dup2(fdpair[1], STDOUT_FILENO); 3202b15cb3dSCy Schubert close(fdpair[0]); 3212b15cb3dSCy Schubert 3222b15cb3dSCy Schubert switch (which) { 3232b15cb3dSCy Schubert case TT_LONGUSAGE: 3242b15cb3dSCy Schubert (*(opts->pUsageProc))(opts, EXIT_SUCCESS); 3252b15cb3dSCy Schubert /* NOTREACHED */ 3262b15cb3dSCy Schubert 3272b15cb3dSCy Schubert case TT_USAGE: 3282b15cb3dSCy Schubert (*(opts->pUsageProc))(opts, EXIT_FAILURE); 3292b15cb3dSCy Schubert /* NOTREACHED */ 3302b15cb3dSCy Schubert 3312b15cb3dSCy Schubert case TT_VERSION: 3322b15cb3dSCy Schubert if (od->fOptState & OPTST_ALLOC_ARG) { 3332b15cb3dSCy Schubert AGFREE(od->optArg.argString); 3342b15cb3dSCy Schubert od->fOptState &= ~OPTST_ALLOC_ARG; 3352b15cb3dSCy Schubert } 3362b15cb3dSCy Schubert od->optArg.argString = "c"; 3372b15cb3dSCy Schubert optionPrintVersion(opts, od); 3382b15cb3dSCy Schubert /* NOTREACHED */ 3392b15cb3dSCy Schubert 3402b15cb3dSCy Schubert default: 3412b15cb3dSCy Schubert option_exits(EXIT_FAILURE); 3422b15cb3dSCy Schubert /* NOTREACHED */ 3432b15cb3dSCy Schubert } 3442b15cb3dSCy Schubert /* NOTREACHED */ 3452b15cb3dSCy Schubert 3462b15cb3dSCy Schubert default: 3472b15cb3dSCy Schubert close(fdpair[1]); 3482b15cb3dSCy Schubert } 3492b15cb3dSCy Schubert 3502b15cb3dSCy Schubert emit_var_text(opts->pzPROGNAME, ttnames[which], fdpair[0]); 351ea906c41SOllivier Robert #endif 352ea906c41SOllivier Robert } 353ea906c41SOllivier Robert 3542b15cb3dSCy Schubert /** 3552b15cb3dSCy Schubert * capture usage text in shell variables. 3562b15cb3dSCy Schubert * 3572b15cb3dSCy Schubert */ 358ea906c41SOllivier Robert static void 3592b15cb3dSCy Schubert emit_usage(tOptions * opts) 360ea906c41SOllivier Robert { 3612b15cb3dSCy Schubert char tm_nm_buf[AO_NAME_SIZE]; 362ea906c41SOllivier Robert 363ea906c41SOllivier Robert /* 364ea906c41SOllivier Robert * First, switch stdout to the output file name. 365ea906c41SOllivier Robert * Then, change the program name to the one defined 366ea906c41SOllivier Robert * by the definitions (rather than the current 367ea906c41SOllivier Robert * executable name). Down case the upper cased name. 368ea906c41SOllivier Robert */ 3692b15cb3dSCy Schubert if (script_leader != NULL) 3702b15cb3dSCy Schubert fputs(script_leader, stdout); 371ea906c41SOllivier Robert 372ea906c41SOllivier Robert { 3732b15cb3dSCy Schubert char const * out_nm; 374ea906c41SOllivier Robert 375ea906c41SOllivier Robert { 3762b15cb3dSCy Schubert time_t c_tim = time(NULL); 3772b15cb3dSCy Schubert struct tm * ptm = localtime(&c_tim); 3782b15cb3dSCy Schubert strftime(tm_nm_buf, AO_NAME_SIZE, TIME_FMT, ptm ); 379ea906c41SOllivier Robert } 380ea906c41SOllivier Robert 3812b15cb3dSCy Schubert if (HAVE_GENSHELL_OPT(SCRIPT)) 3822b15cb3dSCy Schubert out_nm = GENSHELL_OPT_ARG(SCRIPT); 3832b15cb3dSCy Schubert else out_nm = STDOUT; 384ea906c41SOllivier Robert 3852b15cb3dSCy Schubert if ((script_leader == NULL) && (shell_prog != NULL)) 3862b15cb3dSCy Schubert printf(SHELL_MAGIC, shell_prog); 387ea906c41SOllivier Robert 3882b15cb3dSCy Schubert printf(PREAMBLE_FMT, START_MARK, out_nm, tm_nm_buf); 389ea906c41SOllivier Robert } 390ea906c41SOllivier Robert 3912b15cb3dSCy Schubert printf(END_PRE_FMT, opts->pzPROGNAME); 3922b15cb3dSCy Schubert 393ea906c41SOllivier Robert /* 3942b15cb3dSCy Schubert * Get a copy of the original program name in lower case and 3952b15cb3dSCy Schubert * fill in an approximation of the program name from it. 396ea906c41SOllivier Robert */ 397ea906c41SOllivier Robert { 3982b15cb3dSCy Schubert char * pzPN = tm_nm_buf; 3992b15cb3dSCy Schubert char const * pz = opts->pzPROGNAME; 4002b15cb3dSCy Schubert char ** pp; 4012b15cb3dSCy Schubert 4022b15cb3dSCy Schubert /* Copy the program name into the time/name buffer */ 403ea906c41SOllivier Robert for (;;) { 404*276da39aSCy Schubert if ((*pzPN++ = (char)tolower(*pz++)) == NUL) 405ea906c41SOllivier Robert break; 406ea906c41SOllivier Robert } 4072b15cb3dSCy Schubert 408*276da39aSCy Schubert pp = VOIDP(&(opts->pzProgPath)); 4092b15cb3dSCy Schubert *pp = tm_nm_buf; 410*276da39aSCy Schubert pp = VOIDP(&(opts->pzProgName)); 4112b15cb3dSCy Schubert *pp = tm_nm_buf; 412ea906c41SOllivier Robert } 413ea906c41SOllivier Robert 4142b15cb3dSCy Schubert text_to_var(opts, TT_LONGUSAGE, NULL); 4152b15cb3dSCy Schubert text_to_var(opts, TT_USAGE, NULL); 416ea906c41SOllivier Robert 417ea906c41SOllivier Robert { 4182b15cb3dSCy Schubert tOptDesc * pOptDesc = opts->pOptDesc; 4192b15cb3dSCy Schubert int optionCt = opts->optCt; 420ea906c41SOllivier Robert 421ea906c41SOllivier Robert for (;;) { 422ea906c41SOllivier Robert if (pOptDesc->pOptProc == optionPrintVersion) { 4232b15cb3dSCy Schubert text_to_var(opts, TT_VERSION, pOptDesc); 424ea906c41SOllivier Robert break; 425ea906c41SOllivier Robert } 426ea906c41SOllivier Robert 427ea906c41SOllivier Robert if (--optionCt <= 0) 428ea906c41SOllivier Robert break; 429ea906c41SOllivier Robert pOptDesc++; 430ea906c41SOllivier Robert } 431ea906c41SOllivier Robert } 432ea906c41SOllivier Robert } 433ea906c41SOllivier Robert 4342b15cb3dSCy Schubert static void 4352b15cb3dSCy Schubert emit_wrapup(tOptions * opts) 4362b15cb3dSCy Schubert { 4372b15cb3dSCy Schubert tOptDesc * od = opts->pOptDesc; 4382b15cb3dSCy Schubert int opt_ct = opts->presetOptCt; 4392b15cb3dSCy Schubert char const * fmt; 4402b15cb3dSCy Schubert 4412b15cb3dSCy Schubert printf(FINISH_LOOP, opts->pzPROGNAME); 4422b15cb3dSCy Schubert for (;opt_ct > 0; od++, --opt_ct) { 4432b15cb3dSCy Schubert /* 4442b15cb3dSCy Schubert * Options that are either usage documentation or are compiled out 4452b15cb3dSCy Schubert * are not to be processed. 4462b15cb3dSCy Schubert */ 4472b15cb3dSCy Schubert if (SKIP_OPT(od) || (od->pz_NAME == NULL)) 4482b15cb3dSCy Schubert continue; 4492b15cb3dSCy Schubert 4502b15cb3dSCy Schubert /* 4512b15cb3dSCy Schubert * do not presence check if there is no minimum/must-set 4522b15cb3dSCy Schubert */ 4532b15cb3dSCy Schubert if ((od->optMinCt == 0) && ((od->fOptState & OPTST_MUST_SET) == 0)) 4542b15cb3dSCy Schubert continue; 4552b15cb3dSCy Schubert 4562b15cb3dSCy Schubert if (od->optMaxCt > 1) 4572b15cb3dSCy Schubert fmt = CHK_MIN_COUNT; 4582b15cb3dSCy Schubert else fmt = CHK_ONE_REQUIRED; 4592b15cb3dSCy Schubert 4602b15cb3dSCy Schubert { 4612b15cb3dSCy Schubert int min = (od->optMinCt == 0) ? 1 : od->optMinCt; 4622b15cb3dSCy Schubert printf(fmt, opts->pzPROGNAME, od->pz_NAME, min); 4632b15cb3dSCy Schubert } 4642b15cb3dSCy Schubert } 4652b15cb3dSCy Schubert fputs(END_MARK, stdout); 4662b15cb3dSCy Schubert } 467ea906c41SOllivier Robert 468ea906c41SOllivier Robert static void 4692b15cb3dSCy Schubert emit_setup(tOptions * opts) 470ea906c41SOllivier Robert { 4712b15cb3dSCy Schubert tOptDesc * od = opts->pOptDesc; 4722b15cb3dSCy Schubert int opt_ct = opts->presetOptCt; 4732b15cb3dSCy Schubert char const * fmt; 4742b15cb3dSCy Schubert char const * def_val; 475ea906c41SOllivier Robert 4762b15cb3dSCy Schubert for (;opt_ct > 0; od++, --opt_ct) { 4772b15cb3dSCy Schubert char int_val_buf[32]; 478ea906c41SOllivier Robert 479ea906c41SOllivier Robert /* 480ea906c41SOllivier Robert * Options that are either usage documentation or are compiled out 481ea906c41SOllivier Robert * are not to be processed. 482ea906c41SOllivier Robert */ 4832b15cb3dSCy Schubert if (SKIP_OPT(od) || (od->pz_NAME == NULL)) 484ea906c41SOllivier Robert continue; 485ea906c41SOllivier Robert 4862b15cb3dSCy Schubert if (od->optMaxCt > 1) 4872b15cb3dSCy Schubert fmt = MULTI_DEF_FMT; 4882b15cb3dSCy Schubert else fmt = SGL_DEF_FMT; 489ea906c41SOllivier Robert 490ea906c41SOllivier Robert /* 491ea906c41SOllivier Robert * IF this is an enumeration/bitmask option, then convert the value 492ea906c41SOllivier Robert * to a string before printing the default value. 493ea906c41SOllivier Robert */ 4942b15cb3dSCy Schubert switch (OPTST_GET_ARGTYPE(od->fOptState)) { 495ea906c41SOllivier Robert case OPARG_TYPE_ENUMERATION: 4962b15cb3dSCy Schubert (*(od->pOptProc))(OPTPROC_EMIT_SHELL, od ); 4972b15cb3dSCy Schubert def_val = od->optArg.argString; 498ea906c41SOllivier Robert break; 499ea906c41SOllivier Robert 500ea906c41SOllivier Robert /* 501ea906c41SOllivier Robert * Numeric and membership bit options are just printed as a number. 502ea906c41SOllivier Robert */ 503ea906c41SOllivier Robert case OPARG_TYPE_NUMERIC: 5042b15cb3dSCy Schubert snprintf(int_val_buf, sizeof(int_val_buf), "%d", 5052b15cb3dSCy Schubert (int)od->optArg.argInt); 5062b15cb3dSCy Schubert def_val = int_val_buf; 507ea906c41SOllivier Robert break; 508ea906c41SOllivier Robert 509ea906c41SOllivier Robert case OPARG_TYPE_MEMBERSHIP: 5102b15cb3dSCy Schubert snprintf(int_val_buf, sizeof(int_val_buf), "%lu", 5112b15cb3dSCy Schubert (unsigned long)od->optArg.argIntptr); 5122b15cb3dSCy Schubert def_val = int_val_buf; 513ea906c41SOllivier Robert break; 514ea906c41SOllivier Robert 515ea906c41SOllivier Robert case OPARG_TYPE_BOOLEAN: 5162b15cb3dSCy Schubert def_val = (od->optArg.argBool) ? TRUE_STR : FALSE_STR; 517ea906c41SOllivier Robert break; 518ea906c41SOllivier Robert 519ea906c41SOllivier Robert default: 5202b15cb3dSCy Schubert if (od->optArg.argString == NULL) { 5212b15cb3dSCy Schubert if (fmt == SGL_DEF_FMT) 5222b15cb3dSCy Schubert fmt = SGL_NO_DEF_FMT; 5232b15cb3dSCy Schubert def_val = NULL; 524ea906c41SOllivier Robert } 525ea906c41SOllivier Robert else 5262b15cb3dSCy Schubert def_val = od->optArg.argString; 527ea906c41SOllivier Robert } 528ea906c41SOllivier Robert 5292b15cb3dSCy Schubert printf(fmt, opts->pzPROGNAME, od->pz_NAME, def_val); 530ea906c41SOllivier Robert } 531ea906c41SOllivier Robert } 532ea906c41SOllivier Robert 533ea906c41SOllivier Robert static void 5342b15cb3dSCy Schubert emit_action(tOptions * opts, tOptDesc * od) 535ea906c41SOllivier Robert { 5362b15cb3dSCy Schubert if (od->pOptProc == optionPrintVersion) 5372b15cb3dSCy Schubert printf(ECHO_N_EXIT, opts->pzPROGNAME, VER_STR); 538ea906c41SOllivier Robert 5392b15cb3dSCy Schubert else if (od->pOptProc == optionPagedUsage) 5402b15cb3dSCy Schubert printf(PAGE_USAGE_TEXT, opts->pzPROGNAME); 541ea906c41SOllivier Robert 5422b15cb3dSCy Schubert else if (od->pOptProc == optionLoadOpt) { 5432b15cb3dSCy Schubert printf(LVL3_CMD, NO_LOAD_WARN); 5442b15cb3dSCy Schubert printf(LVL3_CMD, YES_NEED_OPT_ARG); 545ea906c41SOllivier Robert 5462b15cb3dSCy Schubert } else if (od->pz_NAME == NULL) { 547ea906c41SOllivier Robert 5482b15cb3dSCy Schubert if (od->pOptProc == NULL) { 5492b15cb3dSCy Schubert printf(LVL3_CMD, NO_SAVE_OPTS); 5502b15cb3dSCy Schubert printf(LVL3_CMD, OK_NEED_OPT_ARG); 551ea906c41SOllivier Robert } else 5522b15cb3dSCy Schubert printf(ECHO_N_EXIT, opts->pzPROGNAME, LONG_USE_STR); 553ea906c41SOllivier Robert 554ea906c41SOllivier Robert } else { 5552b15cb3dSCy Schubert if (od->optMaxCt == 1) 5562b15cb3dSCy Schubert printf(SGL_ARG_FMT, opts->pzPROGNAME, od->pz_NAME); 557ea906c41SOllivier Robert else { 5582b15cb3dSCy Schubert if ((unsigned)od->optMaxCt < NOLIMIT) 5592b15cb3dSCy Schubert printf(CHK_MAX_COUNT, opts->pzPROGNAME, 5602b15cb3dSCy Schubert od->pz_NAME, od->optMaxCt); 561ea906c41SOllivier Robert 5622b15cb3dSCy Schubert printf(MULTI_ARG_FMT, opts->pzPROGNAME, od->pz_NAME); 563ea906c41SOllivier Robert } 564ea906c41SOllivier Robert 565ea906c41SOllivier Robert /* 566ea906c41SOllivier Robert * Fix up the args. 567ea906c41SOllivier Robert */ 5682b15cb3dSCy Schubert if (OPTST_GET_ARGTYPE(od->fOptState) == OPARG_TYPE_NONE) { 5692b15cb3dSCy Schubert printf(SET_MULTI_ARG, opts->pzPROGNAME, od->pz_NAME); 5702b15cb3dSCy Schubert printf(LVL3_CMD, NO_ARG_NEEDED); 571ea906c41SOllivier Robert 5722b15cb3dSCy Schubert } else if (od->fOptState & OPTST_ARG_OPTIONAL) { 5732b15cb3dSCy Schubert printf(SET_MULTI_ARG, opts->pzPROGNAME, od->pz_NAME); 5742b15cb3dSCy Schubert printf(LVL3_CMD, OK_NEED_OPT_ARG); 575ea906c41SOllivier Robert 576ea906c41SOllivier Robert } else { 5772b15cb3dSCy Schubert printf(LVL3_CMD, YES_NEED_OPT_ARG); 578ea906c41SOllivier Robert } 579ea906c41SOllivier Robert } 580ea906c41SOllivier Robert fputs(zOptionEndSelect, stdout); 581ea906c41SOllivier Robert } 582ea906c41SOllivier Robert 583ea906c41SOllivier Robert static void 5842b15cb3dSCy Schubert emit_inaction(tOptions * opts, tOptDesc * od) 585ea906c41SOllivier Robert { 5862b15cb3dSCy Schubert if (od->pOptProc == optionLoadOpt) { 5872b15cb3dSCy Schubert printf(LVL3_CMD, NO_SUPPRESS_LOAD); 588ea906c41SOllivier Robert 5892b15cb3dSCy Schubert } else if (od->optMaxCt == 1) 5902b15cb3dSCy Schubert printf(NO_SGL_ARG_FMT, opts->pzPROGNAME, 5912b15cb3dSCy Schubert od->pz_NAME, od->pz_DisablePfx); 592ea906c41SOllivier Robert else 5932b15cb3dSCy Schubert printf(NO_MULTI_ARG_FMT, opts->pzPROGNAME, 5942b15cb3dSCy Schubert od->pz_NAME, od->pz_DisablePfx); 595ea906c41SOllivier Robert 5962b15cb3dSCy Schubert printf(LVL3_CMD, NO_ARG_NEEDED); 597ea906c41SOllivier Robert fputs(zOptionEndSelect, stdout); 598ea906c41SOllivier Robert } 599ea906c41SOllivier Robert 6002b15cb3dSCy Schubert /** 6012b15cb3dSCy Schubert * recognize flag options. These go at the end. 6022b15cb3dSCy Schubert * At the end, emit code to handle options we don't recognize. 6032b15cb3dSCy Schubert * 6042b15cb3dSCy Schubert * @param[in] opts the program options 6052b15cb3dSCy Schubert */ 606ea906c41SOllivier Robert static void 6072b15cb3dSCy Schubert emit_flag(tOptions * opts) 608ea906c41SOllivier Robert { 6092b15cb3dSCy Schubert tOptDesc * od = opts->pOptDesc; 6102b15cb3dSCy Schubert int opt_ct = opts->optCt; 611ea906c41SOllivier Robert 612ea906c41SOllivier Robert fputs(zOptionCase, stdout); 613ea906c41SOllivier Robert 6142b15cb3dSCy Schubert for (;opt_ct > 0; od++, --opt_ct) { 615ea906c41SOllivier Robert 6162b15cb3dSCy Schubert if (SKIP_OPT(od) || ! IS_GRAPHIC_CHAR(od->optValue)) 617ea906c41SOllivier Robert continue; 618ea906c41SOllivier Robert 6192b15cb3dSCy Schubert printf(zOptionFlag, od->optValue); 6202b15cb3dSCy Schubert emit_action(opts, od); 621ea906c41SOllivier Robert } 6222b15cb3dSCy Schubert printf(UNK_OPT_FMT, FLAG_STR, opts->pzPROGNAME); 623ea906c41SOllivier Robert } 624ea906c41SOllivier Robert 6252b15cb3dSCy Schubert /** 6262b15cb3dSCy Schubert * Emit the match text for a long option. The passed in \a name may be 6272b15cb3dSCy Schubert * either the enablement name or the disablement name. 6282b15cb3dSCy Schubert * 6292b15cb3dSCy Schubert * @param[in] name The current name to check. 6302b15cb3dSCy Schubert * @param[in] cod current option descriptor 6312b15cb3dSCy Schubert * @param[in] opts the program options 632ea906c41SOllivier Robert */ 633ea906c41SOllivier Robert static void 6342b15cb3dSCy Schubert emit_match_expr(char const * name, tOptDesc * cod, tOptions * opts) 635ea906c41SOllivier Robert { 6362b15cb3dSCy Schubert char name_bf[32]; 6372b15cb3dSCy Schubert unsigned int min_match_ct = 2; 6382b15cb3dSCy Schubert unsigned int max_match_ct = strlen(name) - 1; 639ea906c41SOllivier Robert 6402b15cb3dSCy Schubert if (max_match_ct >= sizeof(name_bf) - 1) 6412b15cb3dSCy Schubert goto leave; 6422b15cb3dSCy Schubert 6432b15cb3dSCy Schubert { 6442b15cb3dSCy Schubert tOptDesc * od = opts->pOptDesc; 6452b15cb3dSCy Schubert int ct = opts->optCt; 6462b15cb3dSCy Schubert 6472b15cb3dSCy Schubert for (; ct-- > 0; od++) { 6482b15cb3dSCy Schubert unsigned int match_ct = 0; 649ea906c41SOllivier Robert 650ea906c41SOllivier Robert /* 6512b15cb3dSCy Schubert * Omit the current option, Doc opts and compiled out opts. 652ea906c41SOllivier Robert */ 6532b15cb3dSCy Schubert if ((od == cod) || SKIP_OPT(od)) 654ea906c41SOllivier Robert continue; 655ea906c41SOllivier Robert 656ea906c41SOllivier Robert /* 657ea906c41SOllivier Robert * Check each character of the name case insensitively. 658ea906c41SOllivier Robert * They must not be the same. They cannot be, because it would 659ea906c41SOllivier Robert * not compile correctly if they were. 660ea906c41SOllivier Robert */ 661*276da39aSCy Schubert while (UPPER(od->pz_Name[match_ct]) == UPPER(name[match_ct])) 6622b15cb3dSCy Schubert match_ct++; 663ea906c41SOllivier Robert 6642b15cb3dSCy Schubert if (match_ct > min_match_ct) 6652b15cb3dSCy Schubert min_match_ct = match_ct; 666ea906c41SOllivier Robert 667ea906c41SOllivier Robert /* 668ea906c41SOllivier Robert * Check the disablement name, too. 669ea906c41SOllivier Robert */ 6702b15cb3dSCy Schubert if (od->pz_DisableName == NULL) 6712b15cb3dSCy Schubert continue; 6722b15cb3dSCy Schubert 6732b15cb3dSCy Schubert match_ct = 0; 674*276da39aSCy Schubert while ( toupper(od->pz_DisableName[match_ct]) 675*276da39aSCy Schubert == toupper(name[match_ct])) 6762b15cb3dSCy Schubert match_ct++; 6772b15cb3dSCy Schubert if (match_ct > min_match_ct) 6782b15cb3dSCy Schubert min_match_ct = match_ct; 679ea906c41SOllivier Robert } 680ea906c41SOllivier Robert } 681ea906c41SOllivier Robert 682ea906c41SOllivier Robert /* 6832b15cb3dSCy Schubert * Don't bother emitting partial matches if there is only one possible 6842b15cb3dSCy Schubert * partial match. 685ea906c41SOllivier Robert */ 6862b15cb3dSCy Schubert if (min_match_ct < max_match_ct) { 6872b15cb3dSCy Schubert char * pz = name_bf + min_match_ct; 6882b15cb3dSCy Schubert int nm_ix = min_match_ct; 689ea906c41SOllivier Robert 6902b15cb3dSCy Schubert memcpy(name_bf, name, min_match_ct); 691ea906c41SOllivier Robert 692ea906c41SOllivier Robert for (;;) { 693ea906c41SOllivier Robert *pz = NUL; 6942b15cb3dSCy Schubert printf(zOptionPartName, name_bf); 6952b15cb3dSCy Schubert *pz++ = name[nm_ix++]; 6962b15cb3dSCy Schubert if (name[nm_ix] == NUL) { 697ea906c41SOllivier Robert *pz = NUL; 698ea906c41SOllivier Robert break; 699ea906c41SOllivier Robert } 700ea906c41SOllivier Robert } 701ea906c41SOllivier Robert } 7022b15cb3dSCy Schubert 7032b15cb3dSCy Schubert leave: 7042b15cb3dSCy Schubert printf(zOptionFullName, name); 705ea906c41SOllivier Robert } 706ea906c41SOllivier Robert 7072b15cb3dSCy Schubert /** 7082b15cb3dSCy Schubert * Emit GNU-standard long option handling code. 7092b15cb3dSCy Schubert * 7102b15cb3dSCy Schubert * @param[in] opts the program options 711ea906c41SOllivier Robert */ 712ea906c41SOllivier Robert static void 7132b15cb3dSCy Schubert emit_long(tOptions * opts) 714ea906c41SOllivier Robert { 7152b15cb3dSCy Schubert tOptDesc * od = opts->pOptDesc; 7162b15cb3dSCy Schubert int ct = opts->optCt; 717ea906c41SOllivier Robert 718ea906c41SOllivier Robert fputs(zOptionCase, stdout); 719ea906c41SOllivier Robert 720ea906c41SOllivier Robert /* 721ea906c41SOllivier Robert * do each option, ... 722ea906c41SOllivier Robert */ 723ea906c41SOllivier Robert do { 724ea906c41SOllivier Robert /* 725ea906c41SOllivier Robert * Documentation & compiled-out options 726ea906c41SOllivier Robert */ 7272b15cb3dSCy Schubert if (SKIP_OPT(od)) 728ea906c41SOllivier Robert continue; 729ea906c41SOllivier Robert 7302b15cb3dSCy Schubert emit_match_expr(od->pz_Name, od, opts); 7312b15cb3dSCy Schubert emit_action(opts, od); 732ea906c41SOllivier Robert 733ea906c41SOllivier Robert /* 734ea906c41SOllivier Robert * Now, do the same thing for the disablement version of the option. 735ea906c41SOllivier Robert */ 7362b15cb3dSCy Schubert if (od->pz_DisableName != NULL) { 7372b15cb3dSCy Schubert emit_match_expr(od->pz_DisableName, od, opts); 7382b15cb3dSCy Schubert emit_inaction(opts, od); 739ea906c41SOllivier Robert } 7402b15cb3dSCy Schubert } while (od++, --ct > 0); 741ea906c41SOllivier Robert 7422b15cb3dSCy Schubert printf(UNK_OPT_FMT, OPTION_STR, opts->pzPROGNAME); 743ea906c41SOllivier Robert } 744ea906c41SOllivier Robert 7452b15cb3dSCy Schubert /** 7462b15cb3dSCy Schubert * Load the previous shell script output file. We need to preserve any 7472b15cb3dSCy Schubert * hand-edited additions outside of the START_MARK and END_MARKs. 7482b15cb3dSCy Schubert * 7492b15cb3dSCy Schubert * @param[in] fname the output file name 7502b15cb3dSCy Schubert */ 7512b15cb3dSCy Schubert static char * 7522b15cb3dSCy Schubert load_old_output(char const * fname, char const * pname) 753ea906c41SOllivier Robert { 754ea906c41SOllivier Robert /* 755ea906c41SOllivier Robert * IF we cannot stat the file, 756ea906c41SOllivier Robert * THEN assume we are creating a new file. 757ea906c41SOllivier Robert * Skip the loading of the old data. 758ea906c41SOllivier Robert */ 7592b15cb3dSCy Schubert FILE * fp = fopen(fname, "r" FOPEN_BINARY_FLAG); 7602b15cb3dSCy Schubert struct stat stbf; 7612b15cb3dSCy Schubert char * text; 7622b15cb3dSCy Schubert char * scan; 7632b15cb3dSCy Schubert 7642b15cb3dSCy Schubert if (fp == NULL) 7652b15cb3dSCy Schubert return NULL; 766ea906c41SOllivier Robert 767ea906c41SOllivier Robert /* 7682b15cb3dSCy Schubert * If we opened it, we should be able to stat it and it needs 7692b15cb3dSCy Schubert * to be a regular file 770ea906c41SOllivier Robert */ 7712b15cb3dSCy Schubert if ((fstat(fileno(fp), &stbf) != 0) || (! S_ISREG(stbf.st_mode))) 7722b15cb3dSCy Schubert fserr_exit(pname, "fstat", fname); 773ea906c41SOllivier Robert 7742b15cb3dSCy Schubert scan = text = AGALOC(stbf.st_size + 1, "f data"); 775ea906c41SOllivier Robert 776ea906c41SOllivier Robert /* 777ea906c41SOllivier Robert * Read in all the data as fast as our OS will let us. 778ea906c41SOllivier Robert */ 779ea906c41SOllivier Robert for (;;) { 780*276da39aSCy Schubert size_t inct = fread(VOIDP(scan), 1, (size_t)stbf.st_size, fp); 781ea906c41SOllivier Robert if (inct == 0) 782ea906c41SOllivier Robert break; 783ea906c41SOllivier Robert 7842b15cb3dSCy Schubert stbf.st_size -= (ssize_t)inct; 785ea906c41SOllivier Robert 7862b15cb3dSCy Schubert if (stbf.st_size == 0) 787ea906c41SOllivier Robert break; 7882b15cb3dSCy Schubert 7892b15cb3dSCy Schubert scan += inct; 790ea906c41SOllivier Robert } 791ea906c41SOllivier Robert 7922b15cb3dSCy Schubert *scan = NUL; 793ea906c41SOllivier Robert fclose(fp); 7942b15cb3dSCy Schubert 7952b15cb3dSCy Schubert return text; 7962b15cb3dSCy Schubert } 7972b15cb3dSCy Schubert 7982b15cb3dSCy Schubert /** 7992b15cb3dSCy Schubert * Open the specified output file. If it already exists, load its 8002b15cb3dSCy Schubert * contents and save the non-generated (hand edited) portions. 8012b15cb3dSCy Schubert * If a "start mark" is found, everything before it is preserved leader. 8022b15cb3dSCy Schubert * If not, the entire thing is a trailer. Assuming the start is found, 8032b15cb3dSCy Schubert * then everything after the end marker is the trailer. If the end 8042b15cb3dSCy Schubert * mark is not found, the file is actually corrupt, but we take the 8052b15cb3dSCy Schubert * remainder to be the trailer. 8062b15cb3dSCy Schubert * 8072b15cb3dSCy Schubert * @param[in] fname the output file name 8082b15cb3dSCy Schubert */ 8092b15cb3dSCy Schubert static void 8102b15cb3dSCy Schubert open_out(char const * fname, char const * pname) 8112b15cb3dSCy Schubert { 8122b15cb3dSCy Schubert 8132b15cb3dSCy Schubert do { 8142b15cb3dSCy Schubert char * txt = script_text = load_old_output(fname, pname); 8152b15cb3dSCy Schubert char * scn; 8162b15cb3dSCy Schubert 8172b15cb3dSCy Schubert if (txt == NULL) 8182b15cb3dSCy Schubert break; 8192b15cb3dSCy Schubert 8202b15cb3dSCy Schubert scn = strstr(txt, START_MARK); 8212b15cb3dSCy Schubert if (scn == NULL) { 8222b15cb3dSCy Schubert script_trailer = txt; 823ea906c41SOllivier Robert break; 824ea906c41SOllivier Robert } 825ea906c41SOllivier Robert 8262b15cb3dSCy Schubert *(scn++) = NUL; 8272b15cb3dSCy Schubert scn = strstr(scn, END_MARK); 8282b15cb3dSCy Schubert if (scn == NULL) { 8292b15cb3dSCy Schubert /* 8302b15cb3dSCy Schubert * The file is corrupt. Set the trailer to be everything 8312b15cb3dSCy Schubert * after the start mark. The user will need to fix it up. 8322b15cb3dSCy Schubert */ 8332b15cb3dSCy Schubert script_trailer = txt + strlen(txt) + START_MARK_LEN + 1; 834ea906c41SOllivier Robert break; 835ea906c41SOllivier Robert } 836ea906c41SOllivier Robert 837ea906c41SOllivier Robert /* 8382b15cb3dSCy Schubert * Check to see if the data contains our marker. 8392b15cb3dSCy Schubert * If it does, then we will skip over it 840ea906c41SOllivier Robert */ 8412b15cb3dSCy Schubert script_trailer = scn + END_MARK_LEN; 8422b15cb3dSCy Schubert script_leader = txt; 8432b15cb3dSCy Schubert } while (false); 844ea906c41SOllivier Robert 8452b15cb3dSCy Schubert if (freopen(fname, "w" FOPEN_BINARY_FLAG, stdout) != stdout) 8462b15cb3dSCy Schubert fserr_exit(pname, "freopen", fname); 847ea906c41SOllivier Robert } 848ea906c41SOllivier Robert 849ea906c41SOllivier Robert /*=export_func genshelloptUsage 850ea906c41SOllivier Robert * private: 851ea906c41SOllivier Robert * what: The usage function for the genshellopt generated program 852ea906c41SOllivier Robert * 8532b15cb3dSCy Schubert * arg: + tOptions * + opts + program options descriptor + 8542b15cb3dSCy Schubert * arg: + int + exit_cd + usage text type to produce + 855ea906c41SOllivier Robert * 856ea906c41SOllivier Robert * doc: 857ea906c41SOllivier Robert * This function is used to create the usage strings for the option 858ea906c41SOllivier Robert * processing shell script code. Two child processes are spawned 859ea906c41SOllivier Robert * each emitting the usage text in either the short (error exit) 860ea906c41SOllivier Robert * style or the long style. The generated program will capture this 861ea906c41SOllivier Robert * and create shell script variables containing the two types of text. 862ea906c41SOllivier Robert =*/ 863ea906c41SOllivier Robert void 8642b15cb3dSCy Schubert genshelloptUsage(tOptions * opts, int exit_cd) 865ea906c41SOllivier Robert { 8662b15cb3dSCy Schubert #if ! defined(HAVE_WORKING_FORK) 8672b15cb3dSCy Schubert optionUsage(opts, exit_cd); 868ea906c41SOllivier Robert #else 869ea906c41SOllivier Robert /* 870ea906c41SOllivier Robert * IF not EXIT_SUCCESS, 871ea906c41SOllivier Robert * THEN emit the short form of usage. 872ea906c41SOllivier Robert */ 8732b15cb3dSCy Schubert if (exit_cd != EXIT_SUCCESS) 8742b15cb3dSCy Schubert optionUsage(opts, exit_cd); 875ea906c41SOllivier Robert fflush(stderr); 876ea906c41SOllivier Robert fflush(stdout); 8772b15cb3dSCy Schubert if (ferror(stdout) || ferror(stderr)) 8782b15cb3dSCy Schubert option_exits(EXIT_FAILURE); 879ea906c41SOllivier Robert 880ea906c41SOllivier Robert option_usage_fp = stdout; 881ea906c41SOllivier Robert 882ea906c41SOllivier Robert /* 883ea906c41SOllivier Robert * First, print our usage 884ea906c41SOllivier Robert */ 885ea906c41SOllivier Robert switch (fork()) { 886ea906c41SOllivier Robert case -1: 8872b15cb3dSCy Schubert optionUsage(opts, EXIT_FAILURE); 888ea906c41SOllivier Robert /* NOTREACHED */ 889ea906c41SOllivier Robert 890ea906c41SOllivier Robert case 0: 891ea906c41SOllivier Robert pagerState = PAGER_STATE_CHILD; 8922b15cb3dSCy Schubert optionUsage(opts, EXIT_SUCCESS); 893ea906c41SOllivier Robert /* NOTREACHED */ 894ea906c41SOllivier Robert _exit(EXIT_FAILURE); 895ea906c41SOllivier Robert 896ea906c41SOllivier Robert default: 897ea906c41SOllivier Robert { 898ea906c41SOllivier Robert int sts; 899ea906c41SOllivier Robert wait(&sts); 900ea906c41SOllivier Robert } 901ea906c41SOllivier Robert } 902ea906c41SOllivier Robert 903ea906c41SOllivier Robert /* 904ea906c41SOllivier Robert * Generate the pzProgName, since optionProcess() normally 905ea906c41SOllivier Robert * gets it from the command line 906ea906c41SOllivier Robert */ 907ea906c41SOllivier Robert { 908ea906c41SOllivier Robert char * pz; 909*276da39aSCy Schubert char ** pp = VOIDP(&(optionParseShellOptions->pzProgName)); 9102b15cb3dSCy Schubert AGDUPSTR(pz, optionParseShellOptions->pzPROGNAME, "prog name"); 9112b15cb3dSCy Schubert *pp = pz; 912ea906c41SOllivier Robert while (*pz != NUL) { 913*276da39aSCy Schubert *pz = (char)LOWER(*pz); 914ea906c41SOllivier Robert pz++; 915ea906c41SOllivier Robert } 916ea906c41SOllivier Robert } 917ea906c41SOllivier Robert 918ea906c41SOllivier Robert /* 919ea906c41SOllivier Robert * Separate the makeshell usage from the client usage 920ea906c41SOllivier Robert */ 9212b15cb3dSCy Schubert fprintf(option_usage_fp, zGenshell, optionParseShellOptions->pzProgName); 922ea906c41SOllivier Robert fflush(option_usage_fp); 923ea906c41SOllivier Robert 924ea906c41SOllivier Robert /* 925ea906c41SOllivier Robert * Now, print the client usage. 926ea906c41SOllivier Robert */ 927ea906c41SOllivier Robert switch (fork()) { 928ea906c41SOllivier Robert case 0: 929ea906c41SOllivier Robert pagerState = PAGER_STATE_CHILD; 930ea906c41SOllivier Robert /*FALLTHROUGH*/ 931ea906c41SOllivier Robert case -1: 9322b15cb3dSCy Schubert optionUsage(optionParseShellOptions, EXIT_FAILURE); 933ea906c41SOllivier Robert 934ea906c41SOllivier Robert default: 935ea906c41SOllivier Robert { 936ea906c41SOllivier Robert int sts; 937ea906c41SOllivier Robert wait(&sts); 938ea906c41SOllivier Robert } 939ea906c41SOllivier Robert } 940ea906c41SOllivier Robert 9412b15cb3dSCy Schubert fflush(stdout); 9422b15cb3dSCy Schubert if (ferror(stdout)) 9432b15cb3dSCy Schubert fserr_exit(opts->pzProgName, zwriting, zstdout_name); 9442b15cb3dSCy Schubert 9452b15cb3dSCy Schubert option_exits(EXIT_SUCCESS); 946ea906c41SOllivier Robert #endif 947ea906c41SOllivier Robert } 948ea906c41SOllivier Robert 9492b15cb3dSCy Schubert /** @} 9502b15cb3dSCy Schubert * 951ea906c41SOllivier Robert * Local Variables: 952ea906c41SOllivier Robert * mode: C 953ea906c41SOllivier Robert * c-file-style: "stroustrup" 954ea906c41SOllivier Robert * indent-tabs-mode: nil 955ea906c41SOllivier Robert * End: 956ea906c41SOllivier Robert * end of autoopts/makeshell.c */ 957