1616set -e
1717
1818clean_up () {
19- rm -f $TMP_FILE
20- rm -f $MERGE_FILE
19+ rm -f " $TMP_FILE "
20+ rm -f " $TMP_FILE .new "
2121}
2222
2323usage () {
@@ -43,6 +43,10 @@ STRICT=false
4343CONFIG_PREFIX=${CONFIG_-CONFIG_}
4444WARNOVERRIDE=echo
4545
46+ if [ -z " $AWK " ]; then
47+ AWK=awk
48+ fi
49+
4650while true ; do
4751 case $1 in
4852 " -n" )
@@ -117,11 +121,8 @@ if [ ! -r "$INITFILE" ]; then
117121fi
118122
119123MERGE_LIST=$*
120- SED_CONFIG_EXP1=" s/^\(${CONFIG_PREFIX} [a-zA-Z0-9_]*\)=.*/\1/p"
121- SED_CONFIG_EXP2=" s/^# \(${CONFIG_PREFIX} [a-zA-Z0-9_]*\) is not set$/\1/p"
122124
123125TMP_FILE=$( mktemp ./.tmp.config.XXXXXXXXXX)
124- MERGE_FILE=$( mktemp ./.merge_tmp.config.XXXXXXXXXX)
125126
126127echo " Using $INITFILE as base"
127128
@@ -136,42 +137,129 @@ for ORIG_MERGE_FILE in $MERGE_LIST ; do
136137 echo " The merge file '$ORIG_MERGE_FILE ' does not exist. Exit." >&2
137138 exit 1
138139 fi
139- cat $ORIG_MERGE_FILE > $MERGE_FILE
140- CFG_LIST=$( sed -n -e " $SED_CONFIG_EXP1 " -e " $SED_CONFIG_EXP2 " $MERGE_FILE )
141-
142- for CFG in $CFG_LIST ; do
143- grep -q -w $CFG $TMP_FILE || continue
144- PREV_VAL=$( grep -w $CFG $TMP_FILE )
145- NEW_VAL=$( grep -w $CFG $MERGE_FILE )
146- BUILTIN_FLAG=false
147- if [ " $BUILTIN " = " true" ] && [ " ${NEW_VAL# CONFIG_* =} " = " m" ] && [ " ${PREV_VAL# CONFIG_* =} " = " y" ]; then
148- ${WARNOVERRIDE} Previous value: $PREV_VAL
149- ${WARNOVERRIDE} New value: $NEW_VAL
150- ${WARNOVERRIDE} -y passed, will not demote y to m
151- ${WARNOVERRIDE}
152- BUILTIN_FLAG=true
153- elif [ " x$PREV_VAL " != " x$NEW_VAL " ] ; then
154- ${WARNOVERRIDE} Value of $CFG is redefined by fragment $ORIG_MERGE_FILE :
155- ${WARNOVERRIDE} Previous value: $PREV_VAL
156- ${WARNOVERRIDE} New value: $NEW_VAL
157- ${WARNOVERRIDE}
158- if [ " $STRICT " = " true" ]; then
159- STRICT_MODE_VIOLATED=true
160- fi
161- elif [ " $WARNREDUN " = " true" ]; then
162- ${WARNOVERRIDE} Value of $CFG is redundant by fragment $ORIG_MERGE_FILE :
163- fi
164- if [ " $BUILTIN_FLAG " = " false" ]; then
165- sed -i " /$CFG [ =]/d" $TMP_FILE
166- else
167- sed -i " /$CFG [ =]/d" $MERGE_FILE
168- fi
169- done
170- # In case the previous file lacks a new line at the end
171- echo >> $TMP_FILE
172- cat $MERGE_FILE >> $TMP_FILE
173- done
140+ # Use awk for single-pass processing instead of per-symbol grep/sed
141+ if ! " $AWK " -v prefix=" $CONFIG_PREFIX " \
142+ -v warnoverride=" $WARNOVERRIDE " \
143+ -v strict=" $STRICT " \
144+ -v builtin=" $BUILTIN " \
145+ -v warnredun=" $WARNREDUN " '
146+ BEGIN {
147+ strict_violated = 0
148+ cfg_regex = "^" prefix "[a-zA-Z0-9_]+"
149+ notset_regex = "^# " prefix "[a-zA-Z0-9_]+ is not set$"
150+ }
151+
152+ # Extract config name from a line, returns "" if not a config line
153+ function get_cfg(line) {
154+ if (match(line, cfg_regex)) {
155+ return substr(line, RSTART, RLENGTH)
156+ } else if (match(line, notset_regex)) {
157+ # Extract CONFIG_FOO from "# CONFIG_FOO is not set"
158+ sub(/^# /, "", line)
159+ sub(/ is not set$/, "", line)
160+ return line
161+ }
162+ return ""
163+ }
164+
165+ function warn_builtin(cfg, prev, new) {
166+ if (warnoverride == "true") return
167+ print cfg ": -y passed, will not demote y to m"
168+ print "Previous value: " prev
169+ print "New value: " new
170+ print ""
171+ }
172+
173+ function warn_redefined(cfg, prev, new) {
174+ if (warnoverride == "true") return
175+ print "Value of " cfg " is redefined by fragment " mergefile ":"
176+ print "Previous value: " prev
177+ print "New value: " new
178+ print ""
179+ }
180+
181+ function warn_redundant(cfg) {
182+ if (warnredun != "true" || warnoverride == "true") return
183+ print "Value of " cfg " is redundant by fragment " mergefile ":"
184+ }
185+
186+ # First pass: read merge file, store all lines and index
187+ FILENAME == ARGV[1] {
188+ mergefile = FILENAME
189+ merge_lines[FNR] = $0
190+ merge_total = FNR
191+ cfg = get_cfg($0)
192+ if (cfg != "") {
193+ merge_cfg[cfg] = $0
194+ merge_cfg_line[cfg] = FNR
195+ }
196+ next
197+ }
174198
199+ # Second pass: process base file (TMP_FILE)
200+ FILENAME == ARGV[2] {
201+ cfg = get_cfg($0)
202+
203+ # Not a config or not in merge file - keep it
204+ if (cfg == "" || !(cfg in merge_cfg)) {
205+ print $0 >> ARGV[3]
206+ next
207+ }
208+
209+ prev_val = $0
210+ new_val = merge_cfg[cfg]
211+
212+ # BUILTIN: do not demote y to m
213+ if (builtin == "true" && new_val ~ /=m$/ && prev_val ~ /=y$/) {
214+ warn_builtin(cfg, prev_val, new_val)
215+ print $0 >> ARGV[3]
216+ skip_merge[merge_cfg_line[cfg]] = 1
217+ next
218+ }
219+
220+ # Values equal - redundant
221+ if (prev_val == new_val) {
222+ warn_redundant(cfg)
223+ next
224+ }
225+
226+ # "=n" is the same as "is not set"
227+ if (prev_val ~ /=n$/ && new_val ~ / is not set$/) {
228+ print $0 >> ARGV[3]
229+ next
230+ }
231+
232+ # Values differ - redefined
233+ warn_redefined(cfg, prev_val, new_val)
234+ if (strict == "true") {
235+ strict_violated = 1
236+ }
237+ }
238+
239+ # output file, skip all lines
240+ FILENAME == ARGV[3] {
241+ nextfile
242+ }
243+
244+ END {
245+ # Newline in case base file lacks trailing newline
246+ print "" >> ARGV[3]
247+ # Append merge file, skipping lines marked for builtin preservation
248+ for (i = 1; i <= merge_total; i++) {
249+ if (!(i in skip_merge)) {
250+ print merge_lines[i] >> ARGV[3]
251+ }
252+ }
253+ if (strict_violated) {
254+ exit 1
255+ }
256+ }' \
257+ " $ORIG_MERGE_FILE " " $TMP_FILE " " $TMP_FILE .new" ; then
258+ # awk exited non-zero, strict mode was violated
259+ STRICT_MODE_VIOLATED=true
260+ fi
261+ mv " $TMP_FILE .new" " $TMP_FILE "
262+ done
175263if [ " $STRICT_MODE_VIOLATED " = " true" ]; then
176264 echo " The fragment redefined a value and strict mode had been passed."
177265 exit 1
0 commit comments