xref: /freebsd/contrib/bmake/mk/setopts.sh (revision 6a7405f5a6b639682cacf01e35d561411ff556aa)
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 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" as
22#	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.13 2023/02/20 19:30:06 sjg Exp $
54#
55#	@(#) Copyright (c) 1995-2023 Simon J. Gerraty
56#
57#	This file is provided in the hope that it will
58#	be of use.  There is absolutely NO WARRANTY.
59#	Permission to copy, redistribute or otherwise
60#	use this file is hereby granted provided that
61#	the above copyright notice and this notice are
62#	left intact.
63#
64#	Please send copies of changes and bug-fixes to:
65#	sjg@crufty.net
66#
67
68# the case checks just skip the sed(1) commands unless needed
69case "$opt_str" in
70*\^*)	# the only ones we need to set are the booleans x,
71	eval `echo $opt_str | sed -e 's/[^^]*$//' -e 's/[^^]*\([^^]^\)/\1/g' -e 's/\(.\)^/opt_\1=${opt_\1-0}; /g'`
72	;;
73esac
74case "$opt_str" in
75*[=,.\^]*)
76	_opt_str=`echo $opt_str | sed -e 's/[=,.]/:/g' -e 's/\^//g'`;;
77*)	_opt_str=$opt_str;;
78esac
79
80opt_append=${opt_append:-" "}
81opt_dot=${opt_dot:-$opt_append}
82opt_comma=${opt_comma:-,}
83
84set1opt() {
85	o=$1
86	a="$2"
87
88	case "$opt_str" in
89	*${o}:*) eval "opt_$o=\"$a\"";;
90	*${o}.*) eval "opt_$o=\"\${opt_$o}\${opt_$o:+$opt_dot}$a\"";;
91	*${o},*) eval "opt_$o=\"\${opt_$o}\${opt_$o:+$opt_comma}$a\"";;
92	*${o}=*)
93		case "$a" in
94		*=*) eval "$a";;
95		*) Myname=${Myname:-`basename $0 .sh`}
96			echo "$Myname: -$o requires argument of form var=val" >&2
97			exit 1
98			;;
99		esac
100		;;
101	*${o}\^*) eval opt_$o=1;;
102	*) eval opt_$o=-$o;;
103	esac
104}
105
106setopts() {
107	__shift=$#
108	# use getopts builtin if we can
109	case `type getopts 2>&1` in
110	*builtin*)
111		: OPTIND=$OPTIND @="$@"
112		while getopts $_opt_str o
113		do
114			case "$o" in
115			\?) exit 1;;
116			esac
117			set1opt $o "$OPTARG"
118		done
119		shift $(($OPTIND - 1))
120		while :
121		do
122			case "$1" in
123			*=*)
124				case "$opt_assign_eval" in
125				""|no) break;;
126				*) eval "$1"; shift;;
127				esac
128				;;
129			*)	break;;
130			esac
131		done
132		;;
133	*)	# likely not a POSIX shell either
134		# getopt(1) isn't as good
135		set -- `getopt $_opt_str "$@" 2>&1`
136		case "$1" in
137		getopt:)
138			Myname=${Myname:-`basename $0 .sh`}
139			echo "$*" | tr ':' '\012' | sed -e '/^getopt/d' -e 's/ getopt$//' -e "s/^/$Myname:/" -e 's/ --/:/' -e 's/-.*//' 2>&2
140			exit 1
141			;;
142		esac
143
144		while :
145		do
146			: 1="$1"
147			case "$1" in
148			--)	shift; break;;
149			-*)
150				# Most shells give you ' ' in IFS whether you
151				# want it or not, but at least one, doesn't.
152				# So the following gives us consistency.
153				o=`IFS=" -"; set -- $1; echo $*` # lose the '-'
154				set1opt $o "$2"
155				case "$_opt_str" in
156				*${o}:*) shift;;
157				esac
158				;;
159			*=*)	case "$opt_assign_eval" in
160				""|no) break;;
161				*) eval "$1";;
162				esac
163				;;
164			*)	break;;
165			esac
166			shift
167		done
168		;;
169	esac
170	# let caller know how many args we consumed
171	__shift=`expr $__shift - $#`
172}
173
174${_SETOPTS_DELAY:+:} setopts "$@"
175${_SETOPTS_DELAY:+:} shift $__shift
176