#!/bin/bash
# This command imports the native HAL video quirks into the pm-utils native
# format. It knows just enough about the video quirk .fdi files to translate
# them into a format that bash can more easily parse.

# While we are at it, replace the .fdi ad-hoc pattern matching language with
# extended regular expressions where we can.

# If anyone wants fo rewrite this in a language that actually understands 
# XML, feel free.

# If run with no arguments, it will translate the already installed .fdi
# quirks into the native ones at their default location.

# If run with one argument, it will translate the .fdi quirks located at 
# $1 into the native ones at their default location.

# if run with two arguments, it will translate the .fdi quirks located at $1
# into the native ones at $2.

. "/usr/local/lib/pm-utils/pm-functions"
shopt -s extglob

begin_match='<match key *= *"([a-z._]+)" ([a-z_]+) *= *"([^"]+)">'
end_match='</match>'
merge='<merge key *= *"([^"]+)" type *= *"bool">true</merge>'
remove='<remove key *= *"([^"]+)"></remove>'
begin_comment='<!--'
end_comment='-->'
in_comment=0
in_match=0

# test to see if the parameter passed is a decimal or hexidecimal number
# Note the complete lack of floating point support.
isnum() {
    [[ $1 =~ ^[0-9]+\$  || $1 =~ ^0[xX][0-9a-fA-F]+\$ ]]
}

space_echo() {
    for ((i=$1; i>0; i--)); do
	printf ' '
	done
    shift
    echo "$1"
}

# Helper function for when translating from .fdi to native format, 
# we need to massage things a little.
escape_match() {
    local fun lit
    fun="regex"
    # first, escape special ere characters
    lit="$2"
    lit="${lit//\\/\\\\}"
    lit="${lit//./\\.}"
    lit="${lit//^/\\^}"
    lit="${lit//[/\\[}"
    lit="${lit//]/\\]}"
    lit="${lit//\(/\\(}"
    lit="${lit//)/\\)}"
    lit="${lit//\*/\\\*}"
    lit="${lit//\+/\\\+}"
    lit="${lit//\?/\\\?}"
    lit="${lit//\{/\\\{}"
    lit="${lit//\}/\\\}}"
    lit="${lit//\|/\\\|}"
    lit="${lit//\$/\\\$}"
    # second, handle the various comparison cases, munging them into
    # extended regular expressions that bash understands.
    case $1 in
	string) lit="^${lit}\$" ;;
	int|uint64) fun=numeric_compare_eq ;;
	string_outof) lit="${lit%;}"; lit="^(${lit//;/|})\$" ;;
	int_outof) fun=numeric_compare_eq_list ;;
	contains) ;;
	contains_outof) lit="${lit%;}"; lit="${lit//;/|}" ;;
	prefix) lit="^${lit}" ;;
	prefix_outof) lit="${lit%;}"; lit="^(${lit//;/|})" ;;
	suffix) lit="${lit}\$" ;;
	contains_ncase) fun=regex_ncase ;;
	contains_not) fun=regex_inverse ;;
	prefix_ncase) fun=regex_ncase;  lit="^${lit}" ;;
	suffix_ncase) fun=regex_ncase; lit="${lit}\$" ;;
	compare_lt|compare_le|compare_gt|compare_ge|compare_ne)
	    # I know, this may not always be the right thing to do.
	    # It is the right thing most of the time, though.
	    if isnum "$lit"; then
		fun="numeric_$1"
	    else
		fun="$1" 
	    fi
	    ;;
	*) echo "$1 not implemented." >&2 ; exit 1 ;;
    esac
    echo "$fun $lit"
}

# This is so not the right way to parse XML, but it happens to work with
# the current hal-info video quirk .fdi files. Maybe someday I will rewrite
# this in a language that actually understands XML, even though XML is the devil. 
translate_xml() {
    local line key val matcher in_comment in_matcher
    while read line; do
	[[ "$line" ]] || continue
	if [[ $line =~ $begin_comment && $line =~ $end_comment ]]; then
	    space_echo $in_match "# $line"
	elif [[ $line =~ $begin_comment ]]; then
	    space_echo $in_match "# $line"
	    ((in_comment++))
	elif [[ $line =~ $end_comment ]]; then
	    space_echo $in_match "# $line"
	    ((in_comment--))
	elif ((in_comment > 0)); then
	    space_echo $in_match "# $line"
	elif [[ $line =~ $begin_match ]]; then
	    ((in_match++))
	    key="${BASH_REMATCH[1]}"
	    matcher="${BASH_REMATCH[2]}"
	    val="${BASH_REMATCH[3]}"
	    space_echo $in_match "match $key $(escape_match "$matcher" "$val")"
	elif [[ $line =~ $end_match ]]; then
	    space_echo $in_match "endmatch"
	    ((in_match--))
	elif [[ $line =~ $merge ]]; then
	    key="${BASH_REMATCH[1]##*.}"
	    space_echo $((in_match + 1)) "addquirk --quirk-${key//_/-}"
	elif [[ $line =~ $remove ]]; then
	    key="${BASH_REMATCH[1]##*.}"
	    space_echo $((in_match + 1)) "delquirk --quirk-${key//_/-}"
	fi
    done

}

loc="/usr/share/hal/fdi/information/10freedesktop/20-video-quirk*.fdi"
[[ $1 && -d $1 ]] && loc="$1/20-video-quirk*.fdi"
[[ $2 ]] && PM_QUIRKDB="$2"


mkdir -p "$PM_QUIRKDB"
for f in $loc;
do
    lf="$PM_QUIRKDB/${f##*/}"
    lf="${lf%.*}.quirkdb"
    [[ -f $f ]] || continue
    [[ $f -nt $lf ]] || continue 
    translate_xml < "$f" > "$lf"
    rm "$PM_LKW_QUIRKS" >/dev/null 2>&1
done

