#!/bin/bash

# Create a minimal xorg.conf that sets the resolution and/or the video driver.
#
# If our name is "buildxconfig" then we mimic the behavior of the older version.
# Otherwise we behave better and take all of our input via the command line.
#
# If boot parameter "xorgconf" is given or an "xres=xxx" is given then we set
# the resolution.
#
# If an "xdrvr=xxx" is given then we set the video driver.
#
# If both conditions are met then we set both
#
# Whenever we set the resolution then we also add other modes as fallbacks.


ME=${0##*/}
case $ME in
    buildxconfig) LEGACY_MODE=true;;
esac

XORG_CONF=./xorg.conf
DO_XORG=

VBOX_OPTS="HORIZ=28-70  DRIVER=vesa RESOLUTION=1280x1024"
DRIVER_DIR=/usr/lib/xorg/modules/drivers
DRIVER_EXT=_drv.so

VALID_DRIVERS=$(ls $DRIVER_DIR | sed -n "s/$DRIVER_EXT//p")

 WHITE=$(printf "\e[1;37m")
   RED=$(printf "\e[0;31m")
YELLOW=$(printf "\e[1;33m")
    NC=$(printf "\e[0m")


usage() {
    local ret=${1:-0}
    cat <<Usage
Usage: $ME [options] [<driver>,<resolution>,auto,safe,vbox]

Create an xorg.conf file based on the arguments given on the command line.

Options:
    -f --force          Force creation even if driver specfied is not found
    -h --help           Show this usage
    -o --output=<file>  Write output to <file> instead of stdout
    --                  Optional delimiter to indicate the end of options

Xorg Arguments:
A comma delimited list of options.

    safe              Set driver to "vesa" and set default resolutions
    auto              Set default resolutions
    HHHHxWWWW         Set the resolution
    h=xxxx            Set horizontal sync frequency range
    v=yyyy            Set vertical refresh frequency range
    vbox              Set the driver and horizontal frequency:
                        $VBOX_OPTS

Any other argument is considered to be the name of a graphics driver.
Use --force to create an xorg.conf that specifies a driver that is not
on the host system.

Available drivers:
$(echo "$VALID_DRIVERS" | column -x -c 70)

Usage
    exit $ret
}

main() {

    # Read command line params that start with "-" and remove them from "$@"
    local param
    while [ $# -gt 0 -a -n "$1" -a -z "${1##-*}" ]; do
        param=${1#-}
        shift
        case $param in
               -force|f) FORCE=true        ;;
                -help|h) usage             ;;
              -output|o) [ $# -gt 0 ] || error "Expected a filename after -$param"
                         FILE=$1; shift    ;;
          -output=*|o=*) FILE=${param#*=}  ;;
                      -) break             ;;
                      *) error "Unknown command line argument -$param"
        esac
    done

    if [ "$LEGACY_MODE" ]; then
        [ $# -gt 0 ] && FILE=$1
        : ${CMDLINE:=$(cat /proc/cmdline)}
        read_cmdline $CMDLINE
        [ -n "$DO_XORG" ] || exit
    else
        read_args $1
    fi

    if [ "$FILE" ]; then
        mkdir -p $(dirname "$FILE")
        [ -e "$FILE" -a ! -e "$FILE.bak" ] && mv $FILE $FILE.bak
        write_xorg_conf "$RESOLUTION" "$DRIVER" > $FILE
    else
        write_xorg_conf "$RESOLUTION" "$DRIVER"
    fi
}

read_args() {
    local param value
    for param in ${1//,/ };  do
        value=${param#*=}

        case $param in
            vbox)   eval "$VBOX_OPTS"                 ;;
             h=*)   HORIZ=$value                      ;;
             v=*)    VERT=$value                      ;;
            safe)   RESOLUTION=auto     ; DRIVER=vesa ;;
            auto)   RESOLUTION=auto                   ;;

               *)   if echo $param | grep -q "^[0-9]\+x[0-9]\+$"; then
                        RESOLUTION=$param
                        continue
                    fi
                    if [ "$FORCE" -o -e $DRIVER_DIR/$param$DRIVER_EXT ]; then
                        DRIVER=$param
                        continue
                    fi
                    driver_error $param
                    ;;
        esac
    done
}

read_cmdline() {
    local param value
    for param ; do
        value=${param#*=}
        case $param in
                 xres=safe)  DRIVER=vesa       ;  RESOLUTION=auto ;;
            xdrvr=*|drvr=*)  DRIVER=$value     ;  DO_XORG=true    ;;
              xres=*|res=*)  RESOLUTION=$value ;  DO_XORG=true    ;;
                  xorgconf)  DO_XORG=true                         ;;
                    noxorg)  exit 0                               ;;
          esac
    done
}

modes_section() {
    local res_param=$1
    [ "$res_param" ] || return
    local res_regex="[0-9]\+x[0-9]\+"
    local resolution=$(echo "$res_param" | grep -o "$res_regex")

    local modes add_modes

    case $resolution in
         1024x768) add_modes=' "800x600"'                                                           ;;
        1280x1024) add_modes=' "1024x768"  "800x600"'                                               ;;
         1280x800) add_modes=' "1280x768"  "1024x768"  "800x600"'                                   ;;
        1920x1200) add_modes=' "1680x1050" "1440x900"  "1280x1024" "1280x800" "1024x768" "800x600"' ;;
        1680x1050) add_modes=' "1440x900"  "1280x1024" "1280x800"  "1024x768" "800x600"'            ;;
        1600x1200) add_modes=' "1450x1050" "1280x1024" "1024x768"  "800x600"'                       ;;
        1450x1050) add_modes=' "1280x1024" "1024x768"  "800x600"'                                   ;;
         1440x900) add_modes=' "1280x1024" "1280x800"  "1024x768"  "800x600"'                       ;;
         1280x768) add_modes=' "1280x800"  "1333x768" "1024x768"  "800x600"'                        ;;
                *) add_modes=' "1280x1024" "1333x768" "1024x768"  "800x600"'                        ;;
    esac

    add_modes=$(echo "$add_modes" | sed -r -e "s/ \"$resolution\"//" -e "s/\s+/ /g")

    [ -n "$resolution" ] && modes="\"$resolution\""
    [ -n "$add_modes"  ] && modes="$modes$add_modes"

    cat<<Modes_Section
    SubSection "Display"
        Modes $modes
    EndSubSection
Modes_Section
}

driver_entry() {
    local driver=$1
    [ "$driver" ] || return
    printf "\n    Driver     \"$driver\""
}

horizontal_entry() {
    local range=$1
    [ "$range" ] || return
    printf "\n    HorizSync    $range"
}

vertical_entry() {
    local range=$1
    [ "$range" ] || return
    printf "\n    VertRefresh  $range"
}

write_xorg_conf() {
    local mode=$1  driver=$2

    cat <<Xorg_Conf
#----------------------------------------------------------------------
# xorg.conf file
#
# Generated by $ME sometime around $(date)
#
# If you want to save customizations, delete the line above or this
# file will get automatically deleted on the next live boot.
#----------------------------------------------------------------------

Section "Monitor"
    Identifier "Monitor0"
    Option "DPMS" "true"$(horizontal_entry $HORIZ)$(vertical_entry $VERT)
EndSection

Section "Device"
    Identifier "Device0"$(driver_entry $driver)
EndSection

Section "Screen"
    Identifier "Screen0"
    Monitor "Monitor0"
    Device  "Device0"
$(modes_section $mode)
EndSection
Xorg_Conf
}

driver_error() {
    local driver=$1
    cat <<Driver_Error >&2
$WHITE$ME$YELLOW Error:$RED Unrecognized (uninstalled?) video driver:$WHITE $driver
$RED
Available drivers:
$(echo "$VALID_DRIVERS" | column -x -c 70)

Use --force to force use of an unrecognized driver$NC
Driver_Error

    exit 3
}

error() {
    echo "$WHITE$ME$YELLOW Error:$RED $*$NC" >&2
    exit 7
}

warn() {
    echo "$ME$YELLOW Warning: $*$NC" >&2
}

main "$@"
