changeset 809:6cf3e1021862

common.subr: Change handling of internal errors. They now - return 64 or 70 - print always an error message to stderr - set the given option variable to the null value - unset OPTARG in *every* case. This is independent whether the short options start with an `:' character or not.
author Franz Glasner <fzglas.hg@dom66.de>
date Tue, 05 Nov 2024 18:42:40 +0100
parents ab21dd56f99e
children a59cc4bea000
files share/local-bsdtools/common.subr tests/common.t
diffstat 2 files changed, 52 insertions(+), 95 deletions(-) [+]
line wrap: on
line diff
--- a/share/local-bsdtools/common.subr	Tue Nov 05 11:57:34 2024 +0100
+++ b/share/local-bsdtools/common.subr	Tue Nov 05 18:42:40 2024 +0100
@@ -251,7 +251,7 @@
 #: Helper for `getopts` to process long options also.
 #:
 #: Invocation:
-#:    postprocess_getopts_for_long shortopts varname longopt-spec*  '' "$@"
+#:    postprocess_getopts_for_long shortopts varname longopt-spec*  '' [ args ... ]
 #:
 #: The `shortopts` *must* contain ``-:`` to allow a "short" option with
 #: name ``-`` and further arguments. This is used by this function to
@@ -266,9 +266,10 @@
 #:   - OPTARG
 #:
 #: Returns:
-#:   int: 1 if an internal processing error occurs or if the long options
-#:        are not terminated by a null string,
-#:        0 otherwise
+#:   int: 0 normally,
+#:        64 on usage errors (illegal chars in long options, missing
+#:        null terminator for options specifications),
+#:        70 otherwise (internal processing errors)
 #:
 #: Heavily inspired by
 #: https://stackoverflow.com/questions/402377/using-getopts-to-process-long-and-short-command-line-options
@@ -280,7 +281,10 @@
 #: as if a required option argument were missing.
 #:
 #: A leading ``:`` in `shortopts` is handled also if an alternate error
-#: handling is to be employed.
+#: handling is to be employed. This is used only if the function's return
+#: value is 0. On internal processing errors an error message is always
+#: printed to stderr and the return value is 64 or 70. Additionally
+#: the option variable is set to the null string and `OPTARG` is unset.
 #:
 #: Arguments for long options *must* use the form ``--long-option=value``.
 #:
@@ -291,8 +295,8 @@
 #: has a trailing ``=`` the long option requires an argument in the same
 #: way as the ``:`` for a short option.
 #:
-#: If a long option is specified more than once in `longopt-spec` the first
-#: one is taken into account.
+#: If a long option is specified more than once in `longopt-spec` only the
+#: first one is taken into account.
 #:
 #: The `shortopts`, the `varname` must be the same as given to `getopts`.
 #: This is also true for the arguments to be analyzed.
@@ -376,15 +380,10 @@
                 ;;
             *=*[!=]|*=*=)
                 # Error: option contains a = character
-                if [ -n "${__ppgofl_caller_reports_error}" ]; then
-                    setvar "${__ppgofl_varname}" '?'  # XXX FIXME this char???
-                    OPTARG="${__ppgofl_longspec}"
-                else
-                    setvar "${__ppgofl_varname}" '?'
-                    unset OPTARG
-                    err "Long option specification contains a forbidden \`=' character: ${__ppgofl_longspec}"
-                fi
-                return 1
+                setvar "${__ppgofl_varname}" ''
+                unset OPTARG
+                err "Long option specification contains a forbidden \`=' character: ${__ppgofl_longspec}"
+                return "${EX_USAGE}"
                 ;;
             *)
                 :
@@ -392,15 +391,10 @@
         esac
     done
     if [ -n "${__ppgofl_longspec}" ]; then
-        if [ -n "${__ppgofl_caller_reports_error}" ]; then
-            setvar "${__ppgofl_varname}" ':'
-            OPTARG=''
-        else
-            setvar "${__ppgofl_varname}" '?'
-            unset OPTARG
-            err "Missing null terminator for long option specifications"
-        fi
-        return 1
+        setvar "${__ppgofl_varname}" ''
+        unset OPTARG
+        err "Missing null terminator for long option specifications"
+        return "${EX_USAGE}"
     fi
 
 #    # Print the "real" arguments that will be analyzed
@@ -467,7 +461,10 @@
         fi
     done
     # Processing error
-    return 1
+    setvar "${__ppgofl_varname}" ''
+    unset OPTARG
+    err "internal processing error: missing null terminator"
+    return "${EX_SOFTWARE}"  # here this is not a usage but an inernal SW error
 }
 
 
--- a/tests/common.t	Tue Nov 05 11:57:34 2024 +0100
+++ b/tests/common.t	Tue Nov 05 18:42:40 2024 +0100
@@ -46,14 +46,14 @@
   $ [ "${opt_b_val}" = "value-of-b" ]
   $ [ -z "${error}" ]
 
-Not null-terminated long options speccifications
+Not null-terminated long options specifications
 
   $ OPTIND=1
   > getopts "ab:-:" opt --long-a --long-b arg
   > postprocess_getopts_for_long "ab:-:" opt "long-a" "long-b"
   /bin/sh: ERROR: Missing null terminator for long option specifications
-  [1]
-  $ [ "${opt}" = '?' ]
+  [64]
+  $ [ -z "${opt}" ]
   $ [ -z "${OPTARG+SET}" ]
 
 Not null-terminated long options specs (alternate error handling)
@@ -61,10 +61,10 @@
   $ OPTIND=1
   > getopts ":ab:-:" opt --long-a --long-b arg
   > postprocess_getopts_for_long ":ab:-:" opt "long-a" "long-b"
-  [1]
-  $ [ "${opt}" = ':' ]
-  $ [ -n "${OPTARG+SET}" ]
-  $ [ -z "${OPTARG}" ]
+  /bin/sh: ERROR: Missing null terminator for long option specifications
+  [64]
+  $ [ -z "${opt}" ]
+  $ [ -z "${OPTARG+SET}" ]
 
 Illegal long option
 
@@ -234,83 +234,43 @@
 Invalid character in long option
 
   $ error=''
-  > opt_a=no
   > OPTIND=1
-  > while getopts "ab:-:" opt --long=a  ; do
-  >   postprocess_getopts_for_long "ab:-:" opt "long=a" "" --long=a arg
-  >    case "$opt" in
-  >      a|long=a) opt_a=yes
-  >                [ -z "${OPTARG+SET}" ] || echo "ERROR: OPTARG"
-  >                ;;
-  >      \?)
-  >                error=foo
-  >                ;;
-  >      *)
-  >                error=bar
-  >                ;;
-  >    esac
-  > done
+  > getopts "ab:-:" opt --long=a
+  > postprocess_getopts_for_long "ab:-:" opt "long=a" "" --long=a arg
   /bin/sh: ERROR: Long option specification contains a forbidden `=' character: long=a
-  $ [ "${error}" = "foo" ]
+  [64]
+  $ [ -z "${opt}" ]
+  $ [ -z "${OPTARG+SET}" ]
 
 Invalid character in long option (alternate error handling)
 
   $ error=''
-  > opt_a=no
   > OPTIND=1
-  > while getopts ":a-:" opt --long=a  ; do
-  >   postprocess_getopts_for_long ":a-:" opt "long=a" "" --long=a arg
-  >    case "$opt" in
-  >      a|long=a) opt_a=yes
-  >                [ -z "${OPTARG+SET}" ] || echo "ERROR: OPTARG"
-  >                ;;
-  >      \?)
-  >                error="${OPTARG}"
-  >                ;;
-  >      *)
-  >                error=bar
-  >                ;;
-  >    esac
-  > done
-  $ [ "${error}" = "long=a" ]
+  > getopts ":a-:" opt --long=a
+  > postprocess_getopts_for_long ":a-:" opt "long=a" "" --long=a arg
+  /bin/sh: ERROR: Long option specification contains a forbidden `=' character: long=a
+  [64]
+  $ [ -z "${opt}" ]
+  $ [ -z "${OPTARG+SET}" ]
 
 Invalid character in long option
 
   $ error=''
-  > opt_b=no
   > OPTIND=1
-  > while getopts "b:-:" opt --long=a  ; do
-  >   postprocess_getopts_for_long "b:-:" opt "long=b=" "" --long=b=value arg
-  >    case "$opt" in
-  >      b|long=b) opt_b=yes
-  >                ;;
-  >      \?)
-  >                error=foo
-  >                ;;
-  >      *)
-  >                error=bar
-  >                ;;
-  >    esac
-  > done
+  > getopts "b:-:" opt --long=a
+  > postprocess_getopts_for_long "b:-:" opt "long=b=" "" --long=b=value arg
   /bin/sh: ERROR: Long option specification contains a forbidden `=' character: long=b=
-  $ [ "${error}" = "foo" ]
+  [64]
+  $ [ -z "${opt}" ]
+  $ [ -z "${OPTARG+SET}" ]
 
 Invalid character in long option (alternate error handling)
 
   $ error=''
-  > opt_b=no
   > OPTIND=1
-  > while getopts ":b:-:" opt --long=a  ; do
-  >   postprocess_getopts_for_long ":b:-:" opt "long=b=" "" --long=b=value arg
-  >    case "$opt" in
-  >      b|long=b) opt_b=yes
-  >                ;;
-  >      \?)
-  >                error="${OPTARG}"
-  >                ;;
-  >      *)
-  >                error=bar
-  >                ;;
-  >    esac
-  > done
-  $ [ "${error}" = "long=b=" ]
+  > getopts ":b:-:" opt --long=a
+  > postprocess_getopts_for_long ":b:-:" opt "long=b=" "" --long=b=value arg
+  /bin/sh: ERROR: Long option specification contains a forbidden `=' character: long=b=
+  [64]
+  $ [ -z "${opt}" ]
+  $ [ -z "${OPTARG+SET}" ]
\ No newline at end of file