#!/bin/sh -eu

PROG="${0##*/}"
CONFIG_HEADER="${CONFIG_HEADER:-# Generated by $PROG}"
DELETE=
XORG_CONFIG=
SECTION=
SUBSECTION=
ENTRY=
VALUE=

usage()
{
	local rc="${1:-0}"
	[ "$rc" = 0 ] || exec >&2
    cat <<EOF
Write options for Xorg server to a config file.
Usage: $PROG -s <section> [ -S <subsection> ] -e <entry> [ -v <value> ] [ -d ] <config_file>
Valid options are:
    -s, --section <section name>       - section name (Screen, Device, etc)
	-S, --subsection <subsection name> - subsection name (if needed)
    -e, --entry <entry name>           - section's or subsection's entry name
    -v, --value <entry value>          - entry's value. If no value is given current value
	                                     from config file will be printed
    -d, --delete                       - remove whole section or subsection
    -h, --help                         - show this text and exit
EOF
	exit "$rc"
}

#### functions for configs in xorg.conf.d
init_xorgconf_section()
{
    local section="$1"; shift

	egrep -qs "^[[:blank:]]*Section[[:blank:]]+\"${section}\"" "$XORG_CONFIG" && return

	[ -s "$XORG_CONFIG" ] || echo "$CONFIG_HEADER" >"$XORG_CONFIG"

	cat >>"$XORG_CONFIG" <<EOF

Section "$section"
EndSection
EOF
}

init_xorgconf_subsection()
{
    local section="$1"; shift
    local subsection="$1"; shift

	init_xorgconf_section "$section"

	if sed -rn "/^[[:blank:]]*Section[[:blank:]]+\"${section}\"/,/^[[:blank:]]*EndSection/p" \
			"$XORG_CONFIG" | egrep -qs "^[[:blank:]]*SubSection[[:blank:]]+\"${subsection}\""; then
		return
	else
	    sed -ri "/^[[:blank:]]*Section[[:blank:]]+\"${section}\"/,/^[[:blank:]]*EndSection/\
	        {/^[[:blank:]]*EndSection/{i \    SubSection \"${subsection}\"
			i \    EndSubSection
		}}" "$XORG_CONFIG"
	fi
}

read_xorgconf_sec_entry()
{
    local section="$1"; shift
    local section_entry="$1"; shift

    sed -rn "/^[[:blank:]]*Section[[:blank:]]+\"${section}\"/,/^[[:blank:]]*EndSection/ \
        s/^[[:blank:]]*${section_entry}[[:blank:]]*\"?([[:alnum:][:blank:]]+)\"?.*$/\1/p" \
        "$XORG_CONFIG" 2>/dev/null | head -1
}

write_xorgconf_sec_entry()
{
    local section="$1"; shift
    local section_entry="$1"; shift
    local value="$1"; shift

	init_xorgconf_section "$section"
	if sed -rn "/^[[:blank:]]*Section[[:blank:]]+\"${section}\"/,/^[[:blank:]]*EndSection/p" \
			"$XORG_CONFIG" | grep -qs "^[[:blank:]]*$section_entry"; then
		sed -ri "/^[[:blank:]]*Section[[:blank:]]+\"${section}\"/,/^[[:blank:]]*EndSection/ \
			s;^([[:blank:]]*${section_entry}[[:blank:]]+).+;\1${value};" "$XORG_CONFIG"
	else
		sed -ri "/^[[:blank:]]*Section[[:blank:]]+\"${section}\"/,/^[[:blank:]]*SubSection|EndSection/{/^[[:blank:]]*SubSection|EndSection/i \    ${section_entry} $value
		}" "$XORG_CONFIG"
	fi
}

read_xorgconf_subsec_entry()
{
    local section="$1"; shift
    local subsection="$1"; shift
    local subsection_entry="$1"; shift

    sed -rn "/^[[:blank:]]*Section[[:blank:]]+\"${section}\"/,/^[[:blank:]]*EndSection/p" "$XORG_CONFIG" 2>/dev/null |
    sed -rn "/^[[:blank:]]*SubSection[[:blank:]]+\"${subsection}\"/,/^[[:blank:]]*EndSubSection/ \
        s/^[[:blank:]]*${subsection_entry}[[:blank:]]*\"?([[:alnum:][:blank:]]+)\"?.*$/\1/p" | head -1
}

write_xorgconf_subsec_entry()
{
    local section="$1"; shift
    local subsection="$1"; shift
    local subsection_entry="$1"; shift
    local value="$1"; shift

	init_xorgconf_subsection "$section" "$subsection"
	if sed -rn "/^[[:blank:]]*Section[[:blank:]]+\"${section}\"/,/^[[:blank:]]*EndSection/p" "$XORG_CONFIG" |
			sed -rn "/^[[:blank:]]*SubSection[[:blank:]]+\"${subsection}\"/,/^[[:blank:]]*EndSubSection/p" |
			grep -qs "^[[:blank:]]*$subsection_entry"; then
		sed -ri "/^[[:blank:]]*Section[[:blank:]]+\"${section}\"/,/^[[:blank:]]*EndSection/ \
			{/^[[:blank:]]*SubSection[[:blank:]]+\"${subsection}\"/,/^[[:blank:]]*EndSubSection/ \
				s;^([[:blank:]]*${subsection_entry}[[:blank:]]+).+;\1${value};}" "$XORG_CONFIG"
	else
	    sed -ri "/^[[:blank:]]*Section[[:blank:]]+\"${section}\"/,/^[[:blank:]]*EndSection/\
			{/^[[:blank:]]*SubSection[[:blank:]]+\"${subsection}\"/,/^[[:blank:]]*EndSubSection/{/^[[:blank:]]*EndSubSection/i \        ${subsection_entry} $value
	    }}" "$XORG_CONFIG"
	fi
}

TEMP="$(getopt -n "$PROG" -o ds:S:e:v:h -l delete,section:,subsection:,entry:,value:,help -- "$@")" || usage 1
eval set -- "$TEMP"

while :; do
	case "${1-}" in
		-d|--delete) shift; DELETE=1
			;;
		-s|--section) shift; SECTION="$1"; shift
			;;
		-S|--subsection) shift; SUBSECTION="$1"; shift
			;;
		-e|--entry) shift; ENTRY="$1"; shift
			;;
		-v|--value) shift; VALUE="$1"; shift
			;;
		-h|--help) usage 0
			;;
		--) shift; XORG_CONFIG="${1-}"; shift || usage 1; break
			;;
		*) echo "$PROG: unrecognized option: $1" >&2; exit 1
			;;
	esac
done

[ -n "$XORG_CONFIG" -a -z "$*" ] || usage 1

if [ -n "$DELETE" ]; then
	[ -s "$XORG_CONFIG" ] || exit 0
	[ -n "$SECTION" -o -n "$SUBSECTION" -o -n "$ENTRY" -o -n "$VALUE" ] || usage 1
	del_sec=
	del_subsec=
	del_entry=
	com='d'
	[ -n "$SECTION" ] && del_sec="/^[[:blank:]]*Section[[:blank:]]+\"${SECTION}\"/,/^[[:blank:]]*EndSection/"
	if [ -n "$SUBSECTION" ]; then
		del_subsec="/^[[:blank:]]*SubSection[[:blank:]]+\"${SUBSECTION}\"/,/^[[:blank:]]*EndSubSection/"
		if [ -n "$del_sec" ]; then
			del_subsec="{$del_subsec"
			com="$com}"
		fi
	fi
	if [ -n "$ENTRY" -o -n "$VALUE" ]; then
		del_entry="/^[[:blank:]]*${ENTRY}[[:blank:]]*${VALUE}/"
		if [ -n "$del_sec" -o -n "$del_subsec" ]; then
			del_entry="{$del_entry"
			com="$com}"
		fi
	fi
	sed -ri "${del_sec}${del_subsec}${del_entry}${com}" "$XORG_CONFIG"

	grep -qs '^[[:blank:]]*[^#]\+$' "$XORG_CONFIG" || rm "$XORG_CONFIG"
	exit 0
fi

if [ -z "$SECTION" ]; then
	echo "Section not specified" >&2
	exit 1
fi

if [ -n "$VALUE" ]; then
	if [ -n "$SUBSECTION" ]; then
		write_xorgconf_subsec_entry "$SECTION" "$SUBSECTION" "$ENTRY" "$VALUE"
	else
		write_xorgconf_sec_entry "$SECTION" "$ENTRY" "$VALUE"
	fi
else
	if [ -n "$SUBSECTION" ]; then
		read_xorgconf_subsec_entry "$SECTION" "$SUBSECTION" "$ENTRY"
	else
		read_xorgconf_sec_entry "$SECTION" "$ENTRY"
	fi
fi
