#!/bin/sh -efu

. shell-error
. shell-quote

# Outputs the value of specified Makefile variable.
# Args:
#
# $1 -- path to the Makefile;
# $2 -- variable name.
get_make_var() {
    [ $# -eq 2 ] || \
	fatal "Usage: get_make_var makefile var_name"

    local makefile="$1"
    local var="$2"

    quote_sed_regexp_variable var "$var"

    sed -n -e "
s/^[[:space:]]*$var[[:space:]]*+\\?=[[:space:]]*\\([^#]*[^\\]\\)\$/\\1/p
/^[[:space:]]*$var[[:space:]]*+\\?=[[:space:]]*[^#]*\\\\\$/,/[^\\\\]\$/ {
    s/^[[:space:]]*$var[[:space:]]*+\\?=[[:space:]]*//
    s/\\\\\$//
    /^[[:space:]]*\$/ d
    p
}
" "$makefile" | \
    tr ' ' '\n' | sort -u | tr '\n' ' ' | \
        sed -e 's/[[:space:]]\+/ /g' \
            -e 's/^[[:space:]]\+//' \
            -e 's/[[:space:]]\+$//' \
            -e '$ s/^.*$/&\n/'
}

# Deletes the given value from the given Makefile variable.
# If the value is not specified, all variable values, defined
# in the Makefile, are deleted. Args:
#
# $1 -- path to the Makefile;
# $2 -- variable name;
# $3 -- variable value (optional, one of).
del_make_value() {
    [ $# -eq 2 -o $# -eq 3 ] || \
	fatal "Usage: del_make_value makefile var_name [var_value]"

    local makefile="$1"
    local var="$2"
    local val="${3:-}"

    quote_sed_regexp_variable var "$var"

    if [ -n "$val" ]; then
	quote_sed_regexp_variable val "$val"
    else
	val='[^[:space:]]\+'
    fi

    sed -i -e "
/^[[:space:]]*$var[[:space:]]*+\\?=[[:space:]]*[^#]*[^\\]\$/ {
    h; x; s/=.*\$/=/; x
    s/^[[:space:]]*$var[[:space:]]*+\\?=[[:space:]]*//
    s/\\(^\\|[[:space:]]\\)$val\\([[:space:]]\\|\$\\)/\\1\\2/g
    H; g; s/=\n[[:space:]]*/= /
    s/\\([^[:space:]]\\)[[:space:]]\\+\\([^[:space:]]\\)/\\1 \\2/g
}
/^[[:space:]]*$var[[:space:]]*+=[[:space:]]*\$/ d
/^[[:space:]]*$var[[:space:]]*+\\?=[[:space:]]*[^#]*\\\\\$/,/[^\\\\]\$/ {
    /^[[:space:]]*$var[[:space:]]*+\\?=/ {
        h; x; s/=.*\$/=/; x
        s/^[[:space:]]*$var[[:space:]]*+\\?=[[:space:]]*//
	s/\\(^\\|[[:space:]]\\)$val\\([[:space:]]\\|\\\\\\?\$\\)/\\1\\2/g
        H; g; s/=\n[[:space:]]*/= /
    }
    /^[[:space:]]*$var[[:space:]]*+\\?=/! {
        s/\\(^\\|[[:space:]]\\)$val\\([[:space:]]\\|\\\\\\?\$\\)/\\1\\2/g
    }
    s/\\([^[:space:]]\\)[[:space:]]\\+\\([^[:space:]]\\)/\\1 \\2/g
    /^[[:space:]]*$var[[:space:]]*+=[[:space:]]*\$/ d
    /^[[:space:]]*\\\\\$/ d
}
" "$makefile"
}


# Adds the given values to the given Makefile variable.
# Args:
#
# $1 -- path to the Makefile;
# $2 -- varibale name;
# $3.. -- list of values to add.
add_make_value() {
    [ $# -ge 2 ] || \
	fatal "Usage: add_make_value makefile var_name [values...]"

    (
        values="$(mktemp --tmpdir add_make_value.XXXX)"
        trap 'rm -rf "$values"' EXIT

	makefile="$1"; shift
	var="$1"; shift

        get_make_var "$makefile" "$var" | tr ' ' '\n' >"$values"

        if [ -s "$values" ]; then
            new_values="$(echo "$@" | tr ' ' '\n' | sort -u | comm -13 "$values" - | tr '\n' ' ')"
            [ -z "$new_values" ] || \
                echo "$var += $new_values" >>"$makefile"
        else
            echo "$var = $*" >>"$makefile"
        fi
    )
}

# Sets the given Makefile variable to the given value (overwriting
# existing values). Args:
#
# $1 -- path to the Makefile;
# $2 -- varibale name;
# $3.. -- value or a list of values to set.
set_make_value() {
    [ $# -ge 2 ] || \
	fatal "Usage: set_make_value makefile var_name [values...]"

    (
        tmp="$(mktemp --tmpdir set_make_value.XXXX)"
        trap 'rm -rf "$tmp"' EXIT

	makefile="$1"; shift
	var="$1"; shift

	cat "$makefile" >"$tmp"
	del_make_value "$tmp" "$var"

	if [ -n "$*" ]; then
	    quote_sed_regexp_variable var "$var"
	    sed -i -e "
/^[[:space:]]*$var[[:space:]]+\\?=[[:space:]]*\$/ d
" "$tmp"
	    add_make_value "$tmp" "$var" "$@"
	fi

	cat "$tmp" >"$makefile"
    )
}

# Deletes the given values from the given Makefile variable.
# If the values are not specified, all variable values, defined
# in the Makefile, are deleted. Args:
#
# $1 -- path to the Makefile;
# $2 -- variable name;
# $3.. -- variable values.
del_make_values() {
    [ $# -ge 2 ] || \
	fatal "Usage: del_make_values makefile var_name [values...]"

    (
        tmp="$(mktemp --tmpdir set_make_value.XXXX)"
        trap 'rm -rf "$tmp"' EXIT

	makefile="$1"; shift
	var="$1"; shift

	cat "$makefile" >"$tmp"

	for val in "$@"; do
	    del_make_value "$tmp" "$var" "$val"
	done

	cat "$tmp" >"$makefile"
    )
}
