#!/bin/bash
#
# Usage <path-to-script> .config [<dir>]
#
# E.g.
#
# $ ./split-linux-config.sh config_x86_64 /tmp/config_x86_64
#
# output directory /tmp/config_x86_64 ...
# 24
# General setup 24 -- 59
# IRQ subsystem 59 -- 77
# General setup 77 -- 91
# Timers subsystem 91 -- 101
# ...
# ...
# Kernel Testing and Coverage 6626 -- 6681
# Kernel hacking 6681 -- 6682
# Root Menu 6682 --
#
# $ tree /tmp/config_x86_64
# /tmp/config_x86_64
# ├── cfg
# └── Root Menu
# ├── Binary Emulations
# │  └── cfg
# ├── Bluetooth device drivers
# │  └── cfg
# ├── Bus options (PCI etc.)
# │  └── cfg
# ├── Certificates for signature checking
# │  └── cfg
#
# ......
set -eu
TITLES=( "Root Menu" )
LINENOS=( 1 )
printm() {
SPACES="$1"
while [ $SPACES -gt 1 ]; do
(( SPACES-- ))
echo -n " "
done
echo -n "$2"
}
mkdirp() {
if [ $# -eq 0 ]; then
return
fi
local DIR="$1"
local -a EXISTING
shift
if ! [ -d "$DIR" ]; then
shopt -s nullglob
EXISTING=( * )
shopt -u nullglob
mkdir "$DIR"
#ln -s "$DIR" ".sub.${#EXISTING[@]}"
fi
cd "$DIR"
mkdirp "$@"
cd ..
}
emit() {
local START="$1"
shift
local END="$1"
shift
if [[ "$END" -eq "$START" ]]; then
return
fi
[[ "$END" -gt "$START" ]]
local CDIR
printf -v CDIR "%s/" "$@"
mkdirp "$@"
local FNAME=".cfg.$(printf "%010d" $START)"
tail "-n+$START" < "$CFG" | head "-n$(( END - START))" > "$CDIR/$FNAME"
ln "$CDIR/$FNAME" "$FNAME"
}
process() {
local LINE="$1"
local TEXT="${LINE#*":# "}"
local LINENO="${LINE:0:$(( ${#LINE} - ${#TEXT} - 3 ))}"
TEXT="${TEXT//\//-}"
if [[ "$TEXT" == "end of ${TITLES[-1]}" ]]; then
local NEXT="$(( LINENO + 1))"
echo "$NEXT"
emit "${LINENOS[-1]}" "$NEXT" "${TITLES[@]}"
unset TITLES[-1]
unset LINENOS[-1]
LINENOS[-1]="$NEXT"
printm ${#TITLES[@]} "${TITLES[-1]} ${LINENOS[-1]} -- "
else
echo "$LINENO"
emit "${LINENOS[-1]}" "$LINENO" "${TITLES[@]}"
TITLES+=( "$TEXT" )
LINENOS+=( "$LINENO" )
printm ${#TITLES[@]} "${TITLES[-1]} ${LINENOS[-1]} -- "
fi
}
finalize() {
local -a DIRS
local -a CFGS
shopt -s nullglob
DIRS=( * )
CFGS=( .cfg.* )
shopt -u nullglob
if [ "${#DIRS[@]}" -gt 0 ]; then
for d in "${DIRS[@]}"; do
cd "$d"
finalize
cd ..
done
fi
if [ "${#CFGS[@]}" -gt 0 ]; then
for c in "${CFGS[@]}"; do
cat "${CFGS[@]}" > cfg
done
rm "${CFGS[@]}"
fi
}
if [ $# -gt 1 ]; then
TDIR="$2"
else
TDIR="$(mktemp -d /tmp/config-XXXXXX)"
fi
echo "output directory $TDIR ..." >&2
CFG="$(readlink -f "$1")"
pushd "$TDIR"
while read -r ; do
process "$REPLY"
done < <(grep -En '^# ' < "$CFG" | grep -Fv '# CONFIG_')
finalize
diff -u "$CFG" cfg
popd