/** * Print information about each option. * * @param[in] opts the program options * @param[in] exit_code whether or not there was a usage error reported. * used to select full usage versus abbreviated. */ static void print_usage_details(tOptions * opts, int exit_code) { { char const * pOptTitle = NULL; int flen; /* * Determine which header and which option formatting strings to use */ if (do_gnu_usage(opts)) { flen = setGnuOptFmts(opts, &pOptTitle); sprintf(line_fmt_buf, zFmtFmt, flen); fputc(NL, option_usage_fp); } else { flen = setStdOptFmts(opts, &pOptTitle); sprintf(line_fmt_buf, zFmtFmt, flen); /* * When we exit with EXIT_SUCCESS and the first option is a doc * option, we do *NOT* want to emit the column headers. * Otherwise, we do. */ if ( (exit_code != EXIT_SUCCESS) || ((opts->pOptDesc->fOptState & OPTST_DOCUMENT) == 0) ) fputs(pOptTitle, option_usage_fp); } flen = 4 - ((flen + 15) / 8); if (flen > 0) tab_skip_ct = flen; prt_opt_usage(opts, exit_code, pOptTitle); } /* * Describe the mechanics of denoting the options */ switch (opts->fOptSet & OPTPROC_L_N_S) { case OPTPROC_L_N_S: fputs(zFlagOkay, option_usage_fp); break; case OPTPROC_SHORTOPT: break; case OPTPROC_LONGOPT: fputs(zNoFlags, option_usage_fp); break; case 0: fputs(zOptsOnly, option_usage_fp); break; } if ((opts->fOptSet & OPTPROC_NUM_OPT) != 0) fputs(zNumberOpt, option_usage_fp); if ((opts->fOptSet & OPTPROC_REORDER) != 0) fputs(zReorder, option_usage_fp); if (opts->pzExplain != NULL) fputs(opts->pzExplain, option_usage_fp); /* * IF the user is asking for help (thus exiting with SUCCESS), * THEN see what additional information we can provide. */ if (exit_code == EXIT_SUCCESS) prt_prog_detail(opts); /* * Give bug notification preference to the packager information */ if (HAS_pzPkgDataDir(opts) && (opts->pzPackager != NULL)) fputs(opts->pzPackager, option_usage_fp); else if (opts->pzBugAddr != NULL) fprintf(option_usage_fp, zPlsSendBugs, opts->pzBugAddr); fflush(option_usage_fp); if (ferror(option_usage_fp) != 0) fserr_exit(opts->pzProgName, zwriting, (option_usage_fp == stderr) ? zstderr_name : zstdout_name); }
/*=export_func genshelloptUsage * private: * what: The usage function for the genshellopt generated program * * arg: + tOptions * + opts + program options descriptor + * arg: + int + exit_cd + usage text type to produce + * * doc: * This function is used to create the usage strings for the option * processing shell script code. Two child processes are spawned * each emitting the usage text in either the short (error exit) * style or the long style. The generated program will capture this * and create shell script variables containing the two types of text. =*/ void genshelloptUsage(tOptions * opts, int exit_cd) { #if ! defined(HAVE_WORKING_FORK) optionUsage(opts, exit_cd); #else /* * IF not EXIT_SUCCESS, * THEN emit the short form of usage. */ if (exit_cd != EXIT_SUCCESS) optionUsage(opts, exit_cd); fflush(stderr); fflush(stdout); if (ferror(stdout) || ferror(stderr)) option_exits(EXIT_FAILURE); option_usage_fp = stdout; /* * First, print our usage */ switch (fork()) { case -1: optionUsage(opts, EXIT_FAILURE); /* NOTREACHED */ case 0: pagerState = PAGER_STATE_CHILD; optionUsage(opts, EXIT_SUCCESS); /* NOTREACHED */ _exit(EXIT_FAILURE); default: { int sts; wait(&sts); } } /* * Generate the pzProgName, since optionProcess() normally * gets it from the command line */ { char * pz; char ** pp = VOIDP(&(optionParseShellOptions->pzProgName)); AGDUPSTR(pz, optionParseShellOptions->pzPROGNAME, "prog name"); *pp = pz; while (*pz != NUL) { *pz = (char)LOWER(*pz); pz++; } } /* * Separate the makeshell usage from the client usage */ fprintf(option_usage_fp, zGenshell, optionParseShellOptions->pzProgName); fflush(option_usage_fp); /* * Now, print the client usage. */ switch (fork()) { case 0: pagerState = PAGER_STATE_CHILD; /*FALLTHROUGH*/ case -1: optionUsage(optionParseShellOptions, EXIT_FAILURE); default: { int sts; wait(&sts); } } fflush(stdout); if (ferror(stdout)) fserr_exit(opts->pzProgName, zwriting, zstdout_name); option_exits(EXIT_SUCCESS); #endif }
/*=export_func optionParseShell * private: * * what: Decipher a boolean value * arg: + tOptions * + pOpts + program options descriptor + * * doc: * Emit a shell script that will parse the command line options. =*/ void optionParseShell(tOptions * opts) { /* * Check for our SHELL option now. * IF the output file contains the "#!" magic marker, * it will override anything we do here. */ if (HAVE_GENSHELL_OPT(SHELL)) shell_prog = GENSHELL_OPT_ARG(SHELL); else if (! ENABLED_GENSHELL_OPT(SHELL)) shell_prog = NULL; else if ((shell_prog = getenv("SHELL")), shell_prog == NULL) shell_prog = POSIX_SHELL; /* * Check for a specified output file */ if (HAVE_GENSHELL_OPT(SCRIPT)) open_out(GENSHELL_OPT_ARG(SCRIPT), opts->pzProgName); emit_usage(opts); emit_setup(opts); /* * There are four modes of option processing. */ switch (opts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) { case OPTPROC_LONGOPT: fputs(LOOP_STR, stdout); fputs(LONG_OPT_MARK, stdout); fputs(INIT_LOPT_STR, stdout); emit_long(opts); printf(LOPT_ARG_FMT, opts->pzPROGNAME); fputs(END_OPT_SEL_STR, stdout); fputs(NOT_FOUND_STR, stdout); break; case 0: fputs(ONLY_OPTS_LOOP, stdout); fputs(INIT_LOPT_STR, stdout); emit_long(opts); printf(LOPT_ARG_FMT, opts->pzPROGNAME); break; case OPTPROC_SHORTOPT: fputs(LOOP_STR, stdout); fputs(FLAG_OPT_MARK, stdout); fputs(INIT_OPT_STR, stdout); emit_flag(opts); printf(OPT_ARG_FMT, opts->pzPROGNAME); fputs(END_OPT_SEL_STR, stdout); fputs(NOT_FOUND_STR, stdout); break; case OPTPROC_LONGOPT|OPTPROC_SHORTOPT: fputs(LOOP_STR, stdout); fputs(LONG_OPT_MARK, stdout); fputs(INIT_LOPT_STR, stdout); emit_long(opts); printf(LOPT_ARG_FMT, opts->pzPROGNAME); fputs(END_OPT_SEL_STR, stdout); fputs(FLAG_OPT_MARK, stdout); fputs(INIT_OPT_STR, stdout); emit_flag(opts); printf(OPT_ARG_FMT, opts->pzPROGNAME); fputs(END_OPT_SEL_STR, stdout); fputs(NOT_FOUND_STR, stdout); break; } emit_wrapup(opts); if ((script_trailer != NULL) && (*script_trailer != NUL)) fputs(script_trailer, stdout); else if (ENABLED_GENSHELL_OPT(SHELL)) printf(SHOW_PROG_ENV, opts->pzPROGNAME); #ifdef HAVE_FCHMOD fchmod(STDOUT_FILENO, 0755); #endif fclose(stdout); if (ferror(stdout)) fserr_exit(opts->pzProgName, zwriting, zstdout_name); AGFREE(script_text); script_leader = NULL; script_trailer = NULL; script_text = NULL; }
/** * The purpose of this function is to assign "long usage", short usage * and version information to a shell variable. Rather than wind our * way through all the logic necessary to emit the text directly, we * fork(), have our child process emit the text the normal way and * capture the output in the parent process. * * @param[in] opts the program options * @param[in] which what to print: long usage, usage or version * @param[in] od for TT_VERSION, it is the version option */ static void text_to_var(tOptions * opts, teTextTo which, tOptDesc * od) { # define _TT_(n) static char const z ## n [] = #n; TEXTTO_TABLE # undef _TT_ # define _TT_(n) z ## n , static char const * ttnames[] = { TEXTTO_TABLE }; # undef _TT_ #if ! defined(HAVE_WORKING_FORK) printf(SET_NO_TEXT_FMT, opts->pzPROGNAME, ttnames[which]); #else int fdpair[2]; fflush(stdout); fflush(stderr); if (pipe(fdpair) != 0) fserr_exit(opts->pzProgName, "pipe", zinter_proc_pipe); switch (fork()) { case -1: fserr_exit(opts->pzProgName, "fork", opts->pzProgName); /* NOTREACHED */ case 0: /* * Send both stderr and stdout to the pipe. No matter which * descriptor is used, we capture the output on the read end. */ dup2(fdpair[1], STDERR_FILENO); dup2(fdpair[1], STDOUT_FILENO); close(fdpair[0]); switch (which) { case TT_LONGUSAGE: (*(opts->pUsageProc))(opts, EXIT_SUCCESS); /* NOTREACHED */ case TT_USAGE: (*(opts->pUsageProc))(opts, EXIT_FAILURE); /* NOTREACHED */ case TT_VERSION: if (od->fOptState & OPTST_ALLOC_ARG) { AGFREE(od->optArg.argString); od->fOptState &= ~OPTST_ALLOC_ARG; } od->optArg.argString = "c"; optionPrintVersion(opts, od); /* NOTREACHED */ default: option_exits(EXIT_FAILURE); /* NOTREACHED */ } /* NOTREACHED */ default: close(fdpair[1]); } emit_var_text(opts->pzPROGNAME, ttnames[which], fdpair[0]); #endif }
/*=export_func optionUsage * private: * * what: Print usage text * arg: + tOptions* + opts + program options descriptor + * arg: + int + exitCode + exit code for calling exit(3) + * * doc: * This routine will print usage in both GNU-standard and AutoOpts-expanded * formats. The descriptor specifies the default, but AUTOOPTS_USAGE will * over-ride this, providing the value of it is set to either "gnu" or * "autoopts". This routine will @strong{not} return. * * If "exitCode" is "AO_EXIT_REQ_USAGE" (normally 64), then output will to * to stdout and the actual exit code will be "EXIT_SUCCESS". =*/ void optionUsage(tOptions * opts, int usage_exit_code) { int exit_code = (usage_exit_code == AO_EXIT_REQ_USAGE) ? EXIT_SUCCESS : usage_exit_code; displayEnum = false; set_usage_flags(opts, NULL); /* * Paged usage will preset option_usage_fp to an output file. * If it hasn't already been set, then set it to standard output * on successful exit (help was requested), otherwise error out. * * Test the version before obtaining pzFullUsage or pzShortUsage. * These fields do not exist before revision 30. */ { char const * pz; if (exit_code == EXIT_SUCCESS) { pz = (opts->structVersion >= 30 * 4096) ? opts->pzFullUsage : NULL; if (option_usage_fp == NULL) option_usage_fp = print_exit ? stderr : stdout; } else { pz = (opts->structVersion >= 30 * 4096) ? opts->pzShortUsage : NULL; if (option_usage_fp == NULL) option_usage_fp = stderr; } if (((opts->fOptSet & OPTPROC_COMPUTE) == 0) && (pz != NULL)) { if ((opts->fOptSet & OPTPROC_TRANSLATE) != 0) optionPrintParagraphs(pz, true, option_usage_fp); else fputs(pz, option_usage_fp); goto flush_and_exit; } } fprintf(option_usage_fp, opts->pzUsageTitle, opts->pzProgName); if ((exit_code == EXIT_SUCCESS) || (! skip_misuse_usage(opts))) print_usage_details(opts, usage_exit_code); else print_offer_usage(opts); flush_and_exit: fflush(option_usage_fp); if (ferror(option_usage_fp) != 0) fserr_exit(opts->pzProgName, zwriting, (option_usage_fp == stdout) ? zstdout_name : zstderr_name); option_exits(exit_code); }