1: 2# NAME: 3# setopts.sh - set opt_* for shell scripts 4# 5# SYNOPSIS: 6# opt_str=s:a.b^cl,z= 7# opt_a=default 8# 9# . setopts.sh 10# 11# DESCRIPTION: 12# This module sets shell variables for each option specified in 13# "opt_str". 14# 15# If the option is followed by a ':' it requires an argument. 16# It defaults to an empty string and specifying that option on 17# the command line overrides the current value. 18# 19# If the option "o" is followed by a '.' then it is treated as for 20# ':' except that any argument provided on the command line is 21# appended to the current value using the value of "opt_dot_$o" 22# if set, or "opt_dot" as separator (default is a space). 23# 24# If the option is followed by a ',' then it is treated as for 25# a '.' except that the separator is "opt_comma" (default ','). 26# 27# If the option is followed by ``='' it requires an argument 28# of the form "var=val" which will be evaluated. 29# 30# If the option is followed by a ``^'' then it is treated as a 31# boolean and defaults to 0. 32# 33# Options that have no qualifier are set to the flag if present 34# otherwise they are unset. That is if '-c' is given then 35# "opt_c" will be set to '-c'. 36# 37# If "opt_assign_eval" is set (and to something other than 38# 'no'), args of the form "var=val" will be evaluated. 39# 40# NOTES: 41# The implementation uses the getopts builtin if available. 42# 43# Also it does not work when loaded via a function call as "$@" 44# will be the args to that function. In such cases set 45# _SETOPTS_DELAY and call 'setopts "$@"; shift $__shift' 46# afterwards. 47# 48# AUTHOR: 49# Simon J. Gerraty <sjg@crufty.net> 50# 51 52# RCSid: 53# $Id: setopts.sh,v 1.16 2025/08/07 21:59:54 sjg Exp $ 54# 55# @(#) Copyright (c) 1995-2025 Simon J. Gerraty 56# 57# SPDX-License-Identifier: BSD-2-Clause 58# 59# Please send copies of changes and bug-fixes to: 60# sjg@crufty.net 61# 62 63# the case checks just skip the sed(1) commands unless needed 64case "$opt_str" in 65*\^*) # the only ones we need to set are the booleans x, 66 eval `echo $opt_str | sed -e 's/[^^]*$//' -e 's/[^^]*\([^^]^\)/\1/g' -e 's/\(.\)^/opt_\1=${opt_\1-0}; /g'` 67 ;; 68esac 69case "$opt_str" in 70*[=,.\^]*) 71 _opt_str=`echo $opt_str | sed -e 's/[=,.]/:/g' -e 's/\^//g'`;; 72*) _opt_str=$opt_str;; 73esac 74 75opt_append=${opt_append:-" "} 76opt_dot=${opt_dot:-$opt_append} 77opt_comma=${opt_comma:-,} 78 79set1opt() { 80 o=$1 81 a="$2" 82 83 case "$opt_str" in 84 *${o}:*) eval "opt_$o=\"$a\"";; 85 *${o}.*) eval "opt_$o=\"\${opt_$o}\${opt_$o:+\${opt_dot_$o:-$opt_dot}}$a\"";; 86 *${o},*) eval "opt_$o=\"\${opt_$o}\${opt_$o:+$opt_comma}$a\"";; 87 *${o}=*) 88 case "$a" in 89 *=*) eval "$a";; 90 *) Myname=${Myname:-`basename $0 .sh`} 91 echo "$Myname: -$o requires argument of form var=val" >&2 92 exit 1 93 ;; 94 esac 95 ;; 96 *${o}\^*) eval opt_$o=1;; 97 *) eval opt_$o=-$o;; 98 esac 99} 100 101setopts() { 102 __shift=$# 103 # use getopts builtin if we can 104 case `type getopts 2>&1` in 105 *builtin*) 106 : OPTIND=$OPTIND @="$@" 107 while getopts $_opt_str o 108 do 109 case "$o" in 110 \?) exit 1;; 111 esac 112 set1opt $o "$OPTARG" 113 done 114 shift $(($OPTIND - 1)) 115 while : 116 do 117 case "$1" in 118 *=*) 119 case "$opt_assign_eval" in 120 ""|no) break;; 121 *) eval "$1"; shift;; 122 esac 123 ;; 124 *) break;; 125 esac 126 done 127 ;; 128 *) # likely not a POSIX shell either 129 # getopt(1) isn't as good 130 set -- `getopt $_opt_str "$@" 2>&1` 131 case "$1" in 132 getopt:) 133 Myname=${Myname:-`basename $0 .sh`} 134 echo "$*" | tr ':' '\012' | sed -e '/^getopt/d' -e 's/ getopt$//' -e "s/^/$Myname:/" -e 's/ --/:/' -e 's/-.*//' 2>&2 135 exit 1 136 ;; 137 esac 138 139 while : 140 do 141 : 1="$1" 142 case "$1" in 143 --) shift; break;; 144 -*) 145 # Most shells give you ' ' in IFS whether you 146 # want it or not, but at least one, doesn't. 147 # So the following gives us consistency. 148 o=`IFS=" -"; set -- $1; echo $*` # lose the '-' 149 set1opt $o "$2" 150 case "$_opt_str" in 151 *${o}:*) shift;; 152 esac 153 ;; 154 *=*) case "$opt_assign_eval" in 155 ""|no) break;; 156 *) eval "$1";; 157 esac 158 ;; 159 *) break;; 160 esac 161 shift 162 done 163 ;; 164 esac 165 # let caller know how many args we consumed 166 __shift=`expr $__shift - $#` 167} 168 169${_SETOPTS_DELAY:+:} setopts "$@" 170${_SETOPTS_DELAY:+:} shift $__shift 171