xref: /linux/scripts/config (revision 3abe3d0223dd1ceb3af6543b71db3856762603a8)
1#!/usr/bin/env bash
2# SPDX-License-Identifier: GPL-2.0
3# Manipulate options in a .config file from the command line
4
5myname=${0##*/}
6
7# If no prefix forced, use the default CONFIG_
8CONFIG_="${CONFIG_-CONFIG_}"
9
10# We use an uncommon delimiter for sed substitutions
11SED_DELIM=$(echo -en "\001")
12
13usage() {
14	cat >&2 <<EOL
15Manipulate options in a .config file from the command line.
16Usage:
17$myname options command ...
18commands:
19	--enable|-e option   Enable option
20	--disable|-d option  Disable option
21	--module|-m option   Turn option into a module
22	--set-str option string
23	                     Set option to "string"
24	--set-val option value
25	                     Set option to value
26	--undefine|-u option Undefine option
27	--state|-s option    Print state of option (n,y,m,undef)
28
29	--enable-after|-E beforeopt option
30                             Enable option directly after other option
31	--disable-after|-D beforeopt option
32                             Disable option directly after other option
33	--module-after|-M beforeopt option
34                             Turn option into module directly after other option
35	--refresh            Refresh the config using old settings
36
37	commands can be repeated multiple times
38
39options:
40	--file config-file   .config file to change (default .config)
41	--keep-case|-k       Keep next symbols' case (don't upper-case it)
42
43$myname doesn't check the validity of the .config file. This is done at next
44make time.
45
46By default, $myname will upper-case the given symbol. Use --keep-case to keep
47the case of all following symbols unchanged.
48
49$myname uses 'CONFIG_' as the default symbol prefix. Set the environment
50variable CONFIG_ to the prefix to use. Eg.: CONFIG_="FOO_" $myname ...
51EOL
52	exit 1
53}
54
55checkarg() {
56	ARG="$1"
57	if [ "$ARG" = "" ] ; then
58		usage
59	fi
60	case "$ARG" in
61	${CONFIG_}*)
62		ARG="${ARG/${CONFIG_}/}"
63		;;
64	esac
65	if [ "$MUNGE_CASE" = "yes" ] ; then
66		ARG="`echo $ARG | tr a-z A-Z`"
67	fi
68}
69
70txt_append() {
71	local anchor="$1"
72	local insert="$2"
73	local infile="$3"
74
75	# sed append cmd: 'a\' + newline + text + newline
76	cmd="$(printf "a\\%b$insert" "\n")"
77
78	# We don't really need a backup file, but in-place editing with backup
79	# skipped is not portable due to different implementations parsing
80	# arguments in incompatible manners.
81	# Create a backup file anyway to ensure portability. The file will be
82	# deleted on exit.
83	sed -E -i.swp -e "/$anchor/$cmd" "$infile"
84	SED_EDITED=1
85}
86
87txt_subst() {
88	local before="$1"
89	local after="$2"
90	local infile="$3"
91
92	sed -E -i.swp -e "s$SED_DELIM$before$SED_DELIM$after$SED_DELIM" "$infile"
93	SED_EDITED=1
94}
95
96txt_delete() {
97	local text="$1"
98	local infile="$2"
99
100	sed -E -i.swp -e "/$text/d" "$infile"
101	SED_EDITED=1
102}
103
104set_var() {
105	local name=$1 new=$2 before=$3
106
107	name_re="^($name=.*|# $name is not set)"
108	before_re="^($before=|# $before is not set)"
109	if test -n "$before" && grep -Eq "$before_re" "$FN"; then
110		txt_append "$before_re" "$new" "$FN"
111	elif grep -Eq "$name_re" "$FN"; then
112		txt_subst "$name_re" "$new" "$FN"
113	else
114		echo "$new" >>"$FN"
115	fi
116}
117
118undef_var() {
119	local name=$1
120
121	txt_delete "^($name=|# $name is not set)" "$FN"
122}
123
124SED_EDITED=0
125on_exit() {
126	if [ "$SED_EDITED" -ge 1 ]; then
127		rm -f "$FN.swp"
128	fi
129}
130trap on_exit EXIT
131
132FN=.config
133CMDS=()
134while [[ $# -gt 0 ]]; do
135	if [ "$1" = "--file" ]; then
136		if [ "$2" = "" ]; then
137			usage
138		fi
139		FN="$2"
140		shift 2
141	else
142		CMDS+=("$1")
143		shift
144	fi
145done
146
147set -- "${CMDS[@]}"
148if [ "$1" = "" ] ; then
149	usage
150fi
151
152MUNGE_CASE=yes
153while [ "$1" != "" ] ; do
154	CMD="$1"
155	shift
156	case "$CMD" in
157	--keep-case|-k)
158		MUNGE_CASE=no
159		continue
160		;;
161	--refresh)
162		;;
163	--*-after|-E|-D|-M)
164		checkarg "$1"
165		A=$ARG
166		checkarg "$2"
167		B=$ARG
168		shift 2
169		;;
170	-*)
171		checkarg "$1"
172		shift
173		;;
174	esac
175	case "$CMD" in
176	--enable|-e)
177		set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=y"
178		;;
179
180	--disable|-d)
181		set_var "${CONFIG_}$ARG" "# ${CONFIG_}$ARG is not set"
182		;;
183
184	--module|-m)
185		set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=m"
186		;;
187
188	--set-str)
189		# sed swallows one level of escaping, so we need double-escaping
190		set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=\"${1//\"/\\\\\"}\""
191		shift
192		;;
193
194	--set-val)
195		set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=$1"
196		shift
197		;;
198	--undefine|-u)
199		undef_var "${CONFIG_}$ARG"
200		;;
201
202	--state|-s)
203		if grep -q "# ${CONFIG_}$ARG is not set" $FN ; then
204			echo n
205		else
206			V="$(grep "^${CONFIG_}$ARG=" $FN)"
207			if [ $? != 0 ] ; then
208				echo undef
209			else
210				V="${V/#${CONFIG_}$ARG=/}"
211				V="${V/#\"/}"
212				V="${V/%\"/}"
213				V="${V//\\\"/\"}"
214				echo "${V}"
215			fi
216		fi
217		;;
218
219	--enable-after|-E)
220		set_var "${CONFIG_}$B" "${CONFIG_}$B=y" "${CONFIG_}$A"
221		;;
222
223	--disable-after|-D)
224		set_var "${CONFIG_}$B" "# ${CONFIG_}$B is not set" "${CONFIG_}$A"
225		;;
226
227	--module-after|-M)
228		set_var "${CONFIG_}$B" "${CONFIG_}$B=m" "${CONFIG_}$A"
229		;;
230
231	--refresh)
232		yes "" | make oldconfig KCONFIG_CONFIG=$FN
233		;;
234
235	*)
236		echo "bad command: $CMD" >&2
237		usage
238		;;
239	esac
240done
241