xref: /freebsd/contrib/bmake/mk/setopts.sh (revision c60f6422ffae3ea85e7b10bad950ad27c463af18)
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