diff options
Diffstat (limited to 'autoopts/tpl/optmain.tlib')
-rw-r--r-- | autoopts/tpl/optmain.tlib | 1255 |
1 files changed, 1255 insertions, 0 deletions
diff --git a/autoopts/tpl/optmain.tlib b/autoopts/tpl/optmain.tlib new file mode 100644 index 0000000..13b01de --- /dev/null +++ b/autoopts/tpl/optmain.tlib @@ -0,0 +1,1255 @@ +[= AutoGen5 Template -*- Mode: text -*- + +# Time-stamp: "2012-08-11 08:13:56 bkorb" + +## This file is part of AutoOpts, a companion to AutoGen. +## AutoOpts is free software. +## AutoOpts is Copyright (c) 1992-2012 by Bruce Korb - all rights reserved +## +## AutoOpts is available under any one of two licenses. The license +## in use must be one of these two and the choice is under the control +## of the user of the license. +## +## The GNU Lesser General Public License, version 3 or later +## See the files "COPYING.lgplv3" and "COPYING.gplv3" +## +## The Modified Berkeley Software Distribution License +## See the file "COPYING.mbsd" +## +## These files have the following md5sums: +## +## 43b91e8ca915626ed3818ffb1b71248b COPYING.gplv3 +## 06a1a2e4760c90ea5e1dad8dfaac4d39 COPYING.lgplv3 +## 66a5cedaf62c4b2637025f049f9b826f COPYING.mbsd + +=][= + +(out-push-new) =] +ck_flag_code() { + addon_txt='' + txt1=`[=(. grep-prog)=] -w pOptDesc ${tmp_dir}/flag-code` + test -z "$txt1" && addon_txt=' (void)pOptDesc;\n' + txt2=`[=(. grep-prog)=] -w pOptions ${tmp_dir}/flag-code` + test -z "$txt2" && addon_txt=${addon_txt}' (void)pOptions;\n' + cat ${tmp_dir}/flag-code + test -z "$addon_txt" || printf "\n$addon_txt" + rm -f ${tmp_dir}/flag-code +}[= +(shell (out-pop #t)) =][= + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + + BUILD TEST MAIN + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE build-test-main + +=][= (tpl-file-line extract-fmt) \=] + +#if defined([=(. main-guard)=]) /* TEST MAIN PROCEDURE: */[= + + IF (= (get "test-main") "optionParseShell") + +=] + +extern tOptions genshelloptOptions; +extern void optionParseShell(tOptions*); +extern tOptions* optionParseShellOptions;[= + + ELIF (not (exist? "main-text")) =][= + + (define option-emitter-proc (get "test-main")) + (if (<= (string-length option-emitter-proc) 3) + (set! option-emitter-proc "optionPutShell")) +=] + +extern void [= (. option-emitter-proc) =](tOptions*);[= + + ENDIF + +=] + +/** + * Generated main procedure. This will emit text that a Bourne shell can + * process to handle its command line arguments. + * + * @param argc argument count + * @param argv argument vector + * @returns program exit code + */ +int +main(int argc, char ** argv) +{ + int res = [=(. succ-exit-code)=];[= + + IF (= (get "test-main") "optionParseShell") =] + /* + * Stash a pointer to the options we are generating. + * `genshellUsage()' will use it. + */ + optionParseShellOptions = &[=(. pname)=]Options; + (void)optionProcess(&genshelloptOptions, argc, argv); + optionParseShell(&[=(. pname)=]Options);[= + + ELIF (exist? "main-text") =][= + IF (not (exist? "option-code")) =] + { + int ct = optionProcess(&[=(. pname)=]Options, argc, argv); + argc -= ct; + argv += ct; + }[= + ELSE =][= + (def-file-line "option-code" extract-fmt) =][= + option-code =][= + ENDIF =][= + + (def-file-line "main-text" extract-fmt) =][= + main-text =][= + + ELSE test-main is not optionParseShell and main-text not exist + +=] + (void)optionProcess(&[=(. pname)=]Options, argc, argv); + [= (. option-emitter-proc) =](&[=(. pname)=]Options); + res = ferror(stdout); + if (res != 0) + fputs("output error writing to stdout\n", stderr);[= + ENDIF=] + return res; +} +#endif /* defined [= (. main-guard) =] */[= + +ENDDEF build-test-main + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + + BUILD FOR-EACH MAIN + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE for-each-main =][= + + (if (not (==* (get "argument") "[" )) + (error "command line arguments must be optional for a 'for-each' main")) + + (if (not (exist? "handler-proc")) + (error "'for-each' mains require a handler proc") ) + + (define handler-arg-type "") + (tpl-file-line extract-fmt) + +=] +/** + * strip (destructively) the leading and trailing white space. + * Trailing white space is trimmed with a NUL byte. + * The returned address is that of the first character after the + * leading white space. Characters are not moved. + * + * @param pz_s source text pointer + * @returns pointer to the same text buffer, but after finding the + * first non-white space character. + */ +static char * +trim_input_line(char * pz_s) +{ + char* pz_e = pz_s + strlen(pz_s); + while ((pz_e > pz_s) && isspace((unsigned int)pz_e[-1])) pz_e--; + *pz_e = '\0'; + while ((unsigned int)isspace(*pz_s)) pz_s++; + + switch (*pz_s) { + case '\0': + case '[= ?% comment-char "%s" "#" =]': + return NULL; + default: + return pz_s; + } +}[= + +CASE handler-type =][= +=* name =][= (set! handler-arg-type "char const* pz_fname") + (define handler-proc "validate_fname") =][= +=* file =][= + (set! handler-arg-type "char const* pz_fname, FILE* entry_fp") + (define handler-proc "validate_fname") =][= +*=* text =][= + (set! handler-arg-type + "char const* pz_fname, char* pz_file_text, size_t text_size") + (define handler-proc "validate_fname") =][= +!E =][= (set! handler-arg-type "char const* pz_entry") + (define handler-proc (get "handler-proc")) =][= +* =][= (error) =][= +ESAC =][= + +IF (set! tmp-text (string-append (get "handler-proc") "-code")) + (exist? tmp-text) =] + +static int +[= handler-proc =]([=(. handler-arg-type)=]) +{ + int res = 0;[= + (string-append + (def-file-line tmp-text extract-fmt) + (get tmp-text) ) =] + return res; +}[= + +ELSE + +=] + +extern int [= handler-proc =]([=(. handler-arg-type)=]);[= + +ENDIF + +=][= (tpl-file-line extract-fmt) =][= + +IF (exist? "handler-type") =] +/** + * validate file name and dispach callout procedure. + * This procedure is generated by AutoOpts. + * It will make sure that the input file name refers to a file[= + + CASE handler-type =][= +=* name =] + * that exists.[= +=* file =] + * that exists and has been opened for [= + CASE + (define open-mode (shellf "echo '%s' | sed 's/.*-//'" + (get "handler-type"))) + open-mode =][= + *~~* '[rwa]\+' =]reading and writing[= + *~~* [wa] =]writing[= + *~~* r =]reading[= + ESAC =].[= + +*=* text =] + * that has been read into memory as text.[= + ESAC =] + * + * @param pz_fname the name of the file to process + * @returns program exit code flag + */ +static [= + +(define emit-failing-printf (not (= (get "file-fail-code") "success"))) + + pname-down =]_exit_code_t +validate_fname(char const* pz_fname) +{ + static char const * pz_fs_err = NULL;[= + + IF (*=* (get "handler-type") "text") =] + char* file_text; + size_t text_size; + int res;[= + ENDIF =] + + if (pz_fs_err == NULL) + pz_fs_err = _("fs error %d (%s) %s-ing %s\n"); + + { + struct stat sb; + if (stat(pz_fname, &sb) < 0) {[= + IF (. emit-failing-printf) =] + fprintf(stderr, pz_fs_err, errno, strerror(errno), "stat", + pz_fname);[= + ENDIF =] + return [= (. file-fail-exit-code) =]; + }[= + + IF (*=* (get "handler-type") "text") =] + + if (! S_ISREG(sb.st_mode)) {[= + IF (. emit-failing-printf) =] + fprintf(stderr, pz_fs_err, EINVAL, strerror(EINVAL), + "not regular file:", pz_fname);[= + ENDIF =] + return [= (. file-fail-exit-code) =]; + }[= + + IF (=* (get "handler-type") "some-text") =] + + if (sb.st_size == 0) {[= + IF (. emit-failing-printf) =] + fprintf(stderr, pz_fs_err, EINVAL, strerror(EINVAL), + "empty file:", pz_fname);[= + ENDIF =] + return [= (. file-fail-exit-code) =]; + }[= + + ENDIF =] + + text_size = sb.st_size;[= + + ENDIF =] + }[= + +CASE handler-type =][= +=* name =][= (tpl-file-line extract-fmt) =] + + return [= handler-proc =](pz_fname);[= + +=* file =][= (tpl-file-line extract-fmt) =] + { + int res; + FILE* fp = fopen(pz_fname, "[= + (shellf "echo '%s' | sed 's/.*-//'" + (get "handler-type")) =]"); + if (fp == NULL) { + fprintf(stderr, pz_fs_err, errno, strerror(errno), "fopen", + pz_fname); + return [= (. file-fail-exit-code) =]; + } + res = [= handler-proc =](pz_fname, fp); + fclose(fp); + return res; + }[= + +*=* text =][= (tpl-file-line extract-fmt) =] + file_text = malloc(text_size + 1); + if (file_text == NULL) { + fprintf(stderr, _("cannot allocate %u bytes for %s file text\n"), + (unsigned int)text_size+1, pz_fname); + exit([=(. nomem-exit-code)=]); + } + + { + char* pz = file_text; + size_t sz = text_size; + int fd = open(pz_fname, O_RDONLY); + int try_ct = 0; + + if (fd < 0) { + fprintf(stderr, pz_fs_err, errno, strerror(errno), "open", + pz_fname); + free(file_text); + return [= (. file-fail-exit-code) =]; + } + + while (sz > 0) { + ssize_t rd_ct = read(fd, pz, sz); + /* + * a read count of zero is theoretically okay, but we've already + * checked the file size, so we shoud be reading more. + * For us, a count of zero is an error. + */ + if (rd_ct <= 0) { + /* + * Try retriable errors up to 10 times. Then bomb out. + */ + if ( ((errno == EAGAIN) || (errno == EINTR)) + && (++try_ct < 10) ) + continue; + + fprintf(stderr, pz_fs_err, errno, strerror(errno), "read", + pz_fname); + exit([=(. file-fail-exit-code)=]); + } + pz += rd_ct; + sz -= rd_ct; + } + close(fd); + } + + /* + * Just in case it is a text file, we have an extra byte to NUL + * terminate the thing. + */ + file_text[ text_size ] = '\0'; + res = [= handler-proc =](pz_fname, file_text, text_size); + free(file_text); + return res;[= +ESAC =] +}[= + +ENDIF handler-type exists =][= + +(tpl-file-line extract-fmt) + +=] +/** + * Generated main procedure. This will call the [= (. handler-proc) =] procedure + * for every operand on the command line. If there are no operands, then stdin + * is read for a list of file names to process. stdin must not be a terminal. + * It must be a pipe or a file. + * + * @param argc argument count + * @param argv argument vector + * @returns program exit code + */ +int +main(int argc, char** argv) +{ + int res = 0; + { + int ct = optionProcess(&[=(. pname)=]Options, argc, argv); + argc -= ct; + argv += ct; + }[= + (if (exist? "main-init") (string-append + "\n " (def-file-line "main-init" extract-fmt) "\n" (get "main-init"))) + + =][= (tpl-file-line extract-fmt) =] + /* + * Input list from command line + */ + if (argc > 0) { + do { + res |= [= (. handler-proc) =](*(argv++)); + } while (--argc > 0); + } + + /* + * Input list from tty input + */ + else if (isatty(STDIN_FILENO)) { + fputs(_("[=(. prog-name)=] ERROR: input list is a tty\n"), stderr); + [= (. UP-prefix) =]USAGE([=(. file-fail-exit-code)=]); + /* NOTREACHED */ + } + + /* + * Input list from a pipe or file or some such + */ + else { + int in_ct = 0; + size_t pg_size = getpagesize(); + char* buf = malloc(pg_size); + if (buf == NULL) { + fputs(_("[=(. prog-name) + =] ERROR: no memory for input list\n"), stderr); + return [=(. nomem-exit-code)=]; + } + + for (;;) { + char* pz = fgets(buf, (ssize_t)pg_size, stdin); + if (pz == NULL) + break; + + pz = trim_input_line(pz); + if (pz != NULL) { + res |= [= (. handler-proc) =](pz); + in_ct++; + } + } + + if (in_ct == 0) + fputs(_("[=(. prog-name) + =] Warning: no input lines were read\n"), stderr); + free(buf); + }[= + (if (exist? "main-fini") (string-append + "\n " (def-file-line "main-fini" extract-fmt) "\n" (get "main-fini"))) + \=] + + return res; +}[= + +ENDDEF for-each-main + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + + BUILD MAIN + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE build-main =][= FOR main[] =][= + + CASE main-type =][= + == shell-process =][= + INVOKE build-test-main test-main = "optionPutShell" =][= + + == shell-parser =][= + INVOKE build-test-main test-main = "optionParseShell" =][= + + == main =][= + INVOKE build-test-main =][= + + == include =] +[= INCLUDE tpl =][= + + == invoke =][= + INVOKE (get "func") =][= + + == for-each =][= + INVOKE for-each-main =][= + + * =][= + (error (sprintf "unknown/invalid main-type: '%s'" (get "main-type"))) =][= + + ESAC =][= ENDFOR first-main =][= + +ENDDEF build-main + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + + DECLARE OPTION CALLBACK PROCEDURES + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE decl-callbacks + + This is the test for whether or not to emit callback handling code: + +=] +/* + * Declare option callback procedures + */[= + (define undef-proc-names "") + (define decl-type "") + (define extern-proc-list (string-append + (if (exist? "version-proc") + (get "version-proc") + "optionPrintVersion") "\n" + "optionBooleanVal\n" + "optionNestedVal\n" + "optionNumericVal\n" + "optionResetOpt\n" + "optionStackArg\n" + "optionTimeDate\n" + "optionTimeVal\n" + "optionUnstackArg\n" + "optionVendorOption\n" + + ) ) + + (define extern-test-list "") + + (define emit-decl-list (lambda(txt-var is-extern) + (if (> (string-length txt-var) 1) (begin + + (emit (if is-extern "\nextern tOptProc\n" "\nstatic tOptProc\n")) + (set! txt-var (shellf " + (%s -v '^%s$' | sed '/^$/d' | sort -u | \ + sed 's@$@,@;$s@,$@;@' ) <<_EOProcs_\n%s_EOProcs_" + egrep-prog + (if is-extern "NULL" "(NULL|optionStackArg|optionUnstackArg)") + txt-var )) + + (emit (shellf (if (< (string-length txt-var) 72) + "f='%s' ; echo \" \" $f" + "${CLexe} --spread=1 -I4 <<_EOProcs_\n%s\n_EOProcs_" ) + txt-var )) + )) + )) + + (define static-proc-list "doUsageOpt\n") + (define static-test-list static-proc-list) + (define ifdef-fmt (string-append + "\n#if%1$sdef %2$s" + "\n %3$s tOptProc %4$s;" + "\n#else /* not %2$s */" + "\n# define %4$s NULL" + "\n#endif /* def/not %2$s */")) + + (define make-proc-decl #t) + + (define set-ifdef (lambda(n-or-def ifdef-cb ifdef-name) (begin + (set! decl-type (if (hash-ref is-ext-cb-proc flg-name) "extern" "static")) + (set! make-proc-decl #f) + (ag-fprintf 0 ifdef-fmt n-or-def ifdef-name decl-type ifdef-cb ) + ))) + + (define set-cb-decl (lambda() (begin + + (set! make-proc-decl #t) + (set! tmp-val (hash-ref cb-proc-name flg-name)) + + (if (exist? "ifdef") + (set-ifdef "" tmp-val (get "ifdef")) + + (if (exist? "ifndef") + (set-ifdef "n" tmp-val (get "ifndef")) + + (if (hash-ref is-ext-cb-proc flg-name) + (set! extern-proc-list (string-append + extern-proc-list tmp-val "\n" )) + + (set! static-proc-list (string-append + static-proc-list tmp-val "\n" )) + ) ) ) + + (if make-test-main (begin + (set! tmp-val (hash-ref test-proc-name flg-name)) + (if (hash-ref is-ext-cb-proc flg-name) + (set! extern-test-list (string-append extern-test-list + tmp-val "\n" )) + + (if make-proc-decl + (set! static-test-list + (string-append static-test-list tmp-val "\n") ) ) ) + ) ) + + ))) + =][= + + FOR flag =][= + + ;; Fill in four strings with names of callout procedures: + ;; extern-test-list - external callouts done IFF test main is built + ;; static-test-list - static callouts done IFF test main is built + ;; extern-proc-list - external callouts for normal compilation + ;; static-proc-list - static callouts for normal compilation + ;; + ;; Anything under the control of "if[n]def" has the declaration or + ;; #define to NULL emitted immediately. + ;; + (set! flg-name (get "name")) + + (if (and (hash-ref have-cb-procs flg-name) + (not (hash-ref is-lib-cb-proc flg-name)) ) + (set-cb-decl) + ) =][= + + ENDFOR flag =][= + + IF (. make-test-main) =][= + (set! extern-proc-list (string-append extern-proc-list + "optionVersionStderr\n")) =][= + INVOKE emit-testing-defines =][= + ENDIF make-test-main =][= + + (if (not (exist? "no-libopts")) + (set! extern-proc-list (string-append extern-proc-list + "optionPagedUsage\n")) ) + + (emit-decl-list extern-proc-list #t) + (emit-decl-list static-proc-list #f) + (set! static-proc-list "") =][= + + FOR flag =][= + + (set! flg-name (get "name")) + (if (not (= (hash-ref cb-proc-name flg-name) + (hash-ref test-proc-name flg-name))) + (set! static-proc-list (string-append static-proc-list + "#define " (get-up-name "name") "_OPT_PROC " + (hash-ref cb-proc-name flg-name) "\n")) ) + =][= + ENDFOR flag =][= + + IF (> (string-length static-proc-list) 0) =] + +/* + * #define map the "normal" callout procs + */ +[= (. static-proc-list) =][= + + ENDIF have some #define mappings + +=][= + + (if make-test-main + (ag-fprintf 0 "\n#endif /* defined(%s) */" main-guard) ) + + undef-proc-names =][= + +ENDDEF decl-callbacks =][= + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE emit-testing-defines + +=] +#if defined([=(tpl-file-line extract-fmt) main-guard =]) +/* + * Under test, omit argument processing, or call optionStackArg, + * if multiple copies are allowed. + */[= + + (emit-decl-list extern-test-list #t) + (emit-decl-list static-test-list #f) + (set! static-test-list "") =][= + + FOR flag =][= + + (set! flg-name (get "name")) + (if (not (= (hash-ref cb-proc-name flg-name) + (hash-ref test-proc-name flg-name))) + (set! static-test-list (string-append static-test-list + "#define " (get-up-name "name") "_OPT_PROC " + (hash-ref test-proc-name flg-name) "\n")) ) + =][= + ENDFOR flag =][= + + IF (> (string-length static-test-list) 0) =] + +/* + * #define map the "normal" callout procs to the test ones... + */ +[= (. static-test-list) =][= + + ENDIF have some #define mappings + +=] + +#else /* NOT defined [=(. main-guard)=] */ +/* + * When not under test, there are different procs to use + */[= + +ENDDEF emit-testing-defines + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + + DEFINE OPTION CALLBACKS + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE callback-proc-header =] + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/** + * Code to handle the [=name=] option[= + + IF (exist? "ifdef") + +=], when [= ifdef =] is #define-d[= + (define ifdef-text (string-append "\n#ifdef " (get "ifdef"))) + (set! endif-test-main (string-append + (sprintf "\n#endif /* defined %s */" (get "ifdef")) + endif-test-main + )) =][= + + ELIF (exist? "ifndef") + +=], when [= ifndef =] is *not* #define-d[= + (define ifdef-text (string-append "\n#ifndef " (get "ifndef"))) + (set! endif-test-main (string-append + (sprintf "\n#endif /* ! defined %s */" (get "ifndef")) + endif-test-main + )) =][= + + ELSE unconditional code: + +=][= (define ifdef-text "") =][= + + ENDIF ifdef / ifndef + +=]. + * + * @param pOptions the [=(. prog-name)=] options data structure + * @param pOptDesc the option descriptor for this option. + */[= (. ifdef-text) =] +static void +doOpt[= (set! endif-test-main (string-append "\n}" endif-test-main)) + cap-name =](tOptions* pOptions, tOptDesc* pOptDesc) +{ +[= + +ENDDEF callback-proc-header + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE reset-clause =][= + + (if (exist? "flag-code[0]") + (emit (string-append "\n" (get "flag-code[0]")))) + + (if (exist? "resettable") (emit (string-append + "\n if ((pOptDesc->fOptState & OPTST_RESET) != 0)" + "\n return;" )) ) + + =][= + +ENDDEF reset-clause + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE range-option-code + +=][= + +(define option-arg-type (get "arg-type")) +(define range-count (count "arg-range")) + +\=] + static struct {long rmin, rmax;} const rng[[= + (. range-count) =]] = { +[=(out-push-new) =][= + FOR arg-range ",\n" =]{ [= + + CASE arg-range =][= + *== "->" =][= + (string-substitute (get "arg-range") "->" "") =], LONG_MAX[= + + ==* "->" =]LONG_MIN, [= + (string-substitute (get "arg-range") "->" "") =][= + + *==* "->" =][= + (string-substitute (get "arg-range") "->" ", ") =][= + + ~~ -{0,1}[0-9]+ =][=arg-range=], LONG_MIN[= + + * =][= (error (string-append "Invalid range spec: ``" + (get "arg-range") "''" )) =][= + + ESAC arg-range =] }[= + ENDFOR =][= + + (shellf "${CLexe} -I8 --spread=2 <<_EOF_\n%s\n_EOF_" + (out-pop #t)) =] }; + int ix; + + if (pOptions <= OPTPROC_EMIT_LIMIT) + goto emit_ranges;[= + + INVOKE reset-clause =][= + + CASE (define leave-ok-code "") (define ok-return-code "") + (if (exist? "flag-code[1]") + (begin + (set! leave-ok-code "goto return_okay") + (set! ok-return-code (string-append + "\n return;\n\nreturn_okay:\n" + (get "flag-code[1]") )) + ) + (begin + (set! leave-ok-code "return") + (set! ok-return-code "") + ) ) + + option-arg-type =][= + + =* num =] + optionNumericVal(pOptions, pOptDesc);[= + + = time-date =][= + (error (string-append "time/date option " low-name + " may not be range limited.")) ) + =][= + + =* time =] + optionTimeVal(pOptions, pOptDesc); + if (pOptDesc->optArg.argInt == (long)BAD_TIME) + return;[= + + * =][= + (error (string-append option-arg-type " option " low-name + " may not be range limited.")) ) + =][= + + ESAC =] + + for (ix = 0; ix < [=(. range-count)=]; ix++) { + if (pOptDesc->optArg.argInt < rng[ix].rmin) + continue; /* ranges need not be ordered. */ + if (pOptDesc->optArg.argInt == rng[ix].rmin) + [= (. leave-ok-code) =]; + if (rng[ix].rmax == LONG_MIN) + continue; + if (pOptDesc->optArg.argInt <= rng[ix].rmax) + [= (. leave-ok-code) =]; + } + + option_usage_fp = stderr; + +emit_ranges: + optionShowRange(pOptions, pOptDesc, (void *)rng, [= (. range-count) =]);[= + +(. ok-return-code) =][= + +ENDDEF range-option-code + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE alias-option-code \=] + int res = optionAlias(pOptions, pOptDesc, [= + (string-append INDEX-pfx (get-up-name "aliases")) =]); + if ((res != 0) && ((pOptions->fOptSet & OPTPROC_ERRSTOP) != 0)) + [= (. UP-prefix) =]USAGE([=(. fail-exit-code)=]); +[= + +ENDDEF alias-option-code + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE keyword-code =][= + (emit (tpl-file-line extract-fmt)) + + (set! tmp-ct (count "keyword")) + (if (not (exist? "arg-default")) + (begin + (set! tmp-ct (+ 1 tmp-ct)) + (emit " static char const zDef[2] = { 0x7F, 0 };\n") + ) ) \=] + static char const * const azNames[[= (. tmp-ct) =]] = {[= + (emit (if (not (exist? "arg-default")) " zDef,\n" "\n")) + (out-push-new) =][= + FOR keyword =][= + (string-table-add-ref opt-strs (get "keyword")) =] +[= ENDFOR =][= + (shell (string-append + "${CLexe} -S, -I8 --spread=1 <<-\\_EOF_\n" (out-pop #t) "_EOF_\nset +x" )) +=] }; + + if (pOptions <= OPTPROC_EMIT_LIMIT) { + (void) optionEnumerationVal(pOptions, pOptDesc, azNames, [= + (. tmp-ct)=]); + return; /* protect AutoOpts client code from internal callbacks */ + }[= + + INVOKE reset-clause =][= + + IF (exist? "arg-optional") + +=] + + if (pOptDesc->optArg.argString == NULL) + pOptDesc->optArg.argEnum = [= + (string-append UP-name "_" (if (> (len "arg-optional") 0) + (get-up-name "arg-optional") (if (exist? "arg-default") + (get-up-name "arg-default") + "UNDEFINED" ))) =]; + else + pOptDesc->optArg.argEnum = + optionEnumerationVal(pOptions, pOptDesc, azNames, [=(. tmp-ct)=]);[= + + ELSE + +=] + + pOptDesc->optArg.argEnum = + optionEnumerationVal(pOptions, pOptDesc, azNames, [=(. tmp-ct)=]);[= + + ENDIF =][= + + (if (exist? "flag-code[1]") + (emit (string-append "\n" (get "flag-code[1]")))) + + =][= + +ENDDEF keyword-code + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE set-membership-code + +=][= + +(if (not (exist? "keyword")) + (error "set membership requires keywords")) +(set! tmp-ct (count "keyword")) +(emit (tpl-file-line extract-fmt)) +(ag-fprintf 0 " static char const * const azNames[%d] = {\n" tmp-ct) + +(shell (string-append + + "${CLexe} -I8 --spread=2 --sep=',' -f'\"%s\"' <<_EOF_\n" + (join "\n" (stack "keyword")) + "\n_EOF_\n" )) =] + };[= + + INVOKE reset-clause =] + /* + * This function handles special invalid values for "pOptions" + */ + optionSetMembers(pOptions, pOptDesc, azNames, [= (. tmp-ct) =]);[= + + (if (exist? "flag-code[1]") + (emit (string-append "\n" (get "flag-code[1]")))) + + =][= + +ENDDEF set-membership-code + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE file-name-code + +\=] + static teOptFileType const type = + [= (set! tmp-val (get "open-file")) =][= + CASE file-exists =][= + == "" =]FTYPE_MODE_MAY_EXIST[= + =* "no" =]FTYPE_MODE_MUST_NOT_EXIST[= + * =]FTYPE_MODE_MUST_EXIST[= + ESAC =] + [= CASE open-file =][= + + == "" =]FTYPE_MODE_NO_OPEN[= + =* "desc" =]FTYPE_MODE_OPEN_FD[= + * =]FTYPE_MODE_FOPEN_FP[= + + ESAC =]; + static tuFileMode mode; +[= IF (or (=* tmp-val "desc") (== tmp-val "")) \=] +[= IF (not (exist? "file-mode")) \=] +#ifndef O_CLOEXEC +# define O_CLOEXEC 0 +#endif +[= (define file-mode "O_CLOEXEC") =][= + ELSE =][= + (define file-mode (get "file-mode")) \=] +[= ENDIF \=] + mode.file_flags = [= (. file-mode) =]; +[= ELSE \=] +#ifndef FOPEN_BINARY_FLAG +# define FOPEN_BINARY_FLAG +#endif + mode.file_mode = [= (c-string (get "file-mode")) =] FOPEN_BINARY_FLAG; +[= ENDIF =][= + + INVOKE reset-clause =] + /* + * This function handles special invalid values for "pOptions" + */ + optionFileCheck(pOptions, pOptDesc, type, mode);[= + + (if (exist? "flag-code[1]") + (emit (string-append "\n" (get "flag-code[1]")))) + + =][= + +ENDDEF file-name-code + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE requested-code =][= + +IF (not (or (exist? "extract-code") (exist? "flag-code"))) + =][= RETURN =][= +ENDIF =][= + +(if make-test-main + (begin + (set! endif-test-main + (sprintf "\n#endif /* defined(%s) */" main-guard)) + (sprintf "\n\n#if ! defined(%s)" main-guard) +) ) =][= + +INVOKE callback-proc-header =][= + +IF (out-push-new (string-append tmp-dir "/flag-code")) + (exist? "flag-code") =][= + (def-file-line "flag-code" " /* extracted from %s, line %d */\n") + =][= + (join "\n" (stack "flag-code")) =][= + +ELSE =][= + + (extract (string-append (base-name) ".c.save") (string-append + "/* %s =-= " cap-name " Opt Code =-= %s */")) + =][= +ENDIF =][= +(out-pop) +(shell "ck_flag_code") =][= + +ENDDEF requested-code + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE define-option-callbacks =][= + + FOR flag =][= + (define flag-index (for-index)) + (set-flag-names) + (define endif-test-main "") =][= + +# # # # # # # # # # # # # # # # # # =][= + + IF (exist? "arg-range") =][= + + INVOKE callback-proc-header =][= + INVOKE range-option-code =][= + +# # # # # # # # # # # # # # # # # # =][= + + ELIF (exist? "aliases") =][= + + INVOKE callback-proc-header =][= + INVOKE alias-option-code =][= + +# # # # # # # # # # # # # # # # # # =][= + + ELSE =][= CASE arg-type =][= + + =* key =][= + INVOKE callback-proc-header =][= + INVOKE keyword-code =][= + +# # # # # # # # # # # # # # # # # # =][= + + =* set =][= + + INVOKE callback-proc-header =][= + INVOKE set-membership-code =][= + +# # # # # # # # # # # # # # # # # # =][= + + =* fil =][= + INVOKE callback-proc-header =][= + INVOKE file-name-code =][= + +# # # # # # # # # # # # # # # # # # =][= + + * =][= + INVOKE requested-code =][= + + ESAC =][= + ENDIF =][= + + (. endif-test-main) =][= + + ENDFOR flag =][= + +ENDDEF define-option-callbacks + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][= + +DEFINE emit-option-callbacks =] +/* + * Create the static procedure(s) declared above. + */ +/** + * The callout function that invokes the [= (. usage-proc) + =] function. + * + * @param pOptions the AutoOpts option description structure + * @param pOptDesc the descriptor for the "help" (usage) option. + * @noreturn + */ +static void +doUsageOpt(tOptions * pOptions, tOptDesc * pOptDesc) +{[= + IF (exist? "resettable") =] + if ((pOptDesc->fOptState & OPTST_RESET) != 0) + return; +[=ENDIF=][= + IF (exist? "usage-opt") =] + int ex_code = (pOptDesc->optIndex == [= (. INDEX-pfx) =]HELP) + ? [=(. succ-exit-code)=] : AO_EXIT_REQ_USAGE; + [= (string-append usage-proc "(&" pname "Options, ex_code);") =] + /* NOTREACHED */[= + + ELSE =] + [= (string-append usage-proc "(&" pname "Options, " succ-exit-code ");") =] + /* NOTREACHED */ + (void)pOptDesc;[= + ENDIF =] + (void)pOptions; +}[= + +INVOKE define-option-callbacks =][= + +IF (exist? "main") =][= + INVOKE build-main =][= + +ELIF (. make-test-main) =][= + INVOKE build-test-main =][= + +ENDIF + +=][= +(tpl-file-line extract-fmt) +=][= + +IF (exist? "usage-message") =] +/** + * Print a usage message with a format and va_list argument. + * The [= (. usage-proc) =] function is then invoked to print + * the error usage text (somewhat abbreviated) and then exit. + * + * @param[in] fmt the message format string + * @param[in] ap the var-arg list. + * @noreturn + */ +void +[=(. lc-prefix)=]vusage_message(char const * fmt, va_list ap) +{ + char const * er_leader = _("[= prog-name =] usage error:\n"); + fputs(er_leader, stderr); + vfprintf(stderr, fmt, ap); + [= (string-append usage-proc "(&" pname "Options, " fail-exit-code ");") =] + /* NOTREACHED */ +} + +/** + * Print a usage message with a format and a variable argument list. + * [=(. lc-prefix)=]vusage_message() is called to do the work. + * + * @param[in] fmt the message format string + * @param[in] ... the argument list for the message + * @noreturn + */ +void +[=(. lc-prefix)=]usage_message(char const * fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + [=(. lc-prefix)=]vusage_message(fmt, ap); + /* NOTREACHED */ + va_end(ap); +} +[= + +ENDIF have usage-message =][= + +IF (exist? "die-code") + +=] +/** + * Print a fatal error message and die + * + * @param[in] exit_code the value to call exit(3) with + * @param[in] fmt the death rattle message + * @param[in] ap the argument list for the message + * @noreturn + */ +void +[=(. lc-prefix)=]vdie(int exit_code, char const * fmt, va_list ap) +{ + char const * die_leader = _("[= prog-name =] fatal error:\n");[= + (set! tmp-text (get "die-code")) + (if (> (string-length tmp-text) 1) + (string-append "\n\n" tmp-text "\n")) + =] + fputs(die_leader, stderr); + vfprintf(stderr, fmt, ap); + fflush(stderr); + exit(exit_code); + /* NOTREACHED */ +} + +/** + * Print a fatal error message and die + * + * @param[in] exit_code the value to call exit(3) with + * @param[in] fmt the death rattle message + * @param[in] ... the list of arguments for the message + * @noreturn + */ +void +[=(. lc-prefix)=]die(int exit_code, char const * fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vdie(exit_code, fmt, ap); + /* NOTREACHED */ + va_end(ap); +} + +/** + * Print a file system error fatal error message and die + * + * @param[in] exit_code the value to call exit(3) with. + * @param[in] op the operation that failed. + * @param[in] fname the file name the operation was on. + * @noreturn + */ +void +[=(. lc-prefix)=]fserr(int exit_code, char const * op, char const * fname) +{ + char const * fserr_fmt = _("fserr %d (%s) performing '%s' on %s\n"); + die(exit_code, fserr_fmt, errno, strerror(errno), op, fname); + /* NOTREACHED */ +} +[= + +ENDIF die-code =][= + +ENDDEF emit-option-callbacks + +=] |