<?xml version="1.0"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:import href="keyval-common.xsl" />

  <xsl:output method="text" indent="no"/>

  <xsl:preserve-space elements="*"/>

<xsl:template match="keyval">

  <xsl:text>#!/bin/bash

#
# AUTOMATICALLY GENERATED - DO NOT EDIT!
#

#
# Assume command line options are OK
#

OK=true

VARNAME_LIST="</xsl:text>

  <xsl:for-each select="*">
    <xsl:value-of select="(@varname)"/>
    <xsl:text> </xsl:text>
  </xsl:for-each>
  <xsl:text>"

# print_config
#
# Displays current configuration in format suitable for sourcing

print_config() {
    printf "#\n# configuration options for </xsl:text>

  <xsl:value-of select="(@class)"/>

  <xsl:text> script\n#\n\n"
  for e in ${VARNAME_LIST}; do
    if [ "${e}" != "CONFIG_FILE" ]; then
      printf "${e}=%q\n" "${!e}";
    fi
  done
}

# check_config_file CMD
#
# This function checks the CMD value passed. Following rules are
# imposed:
#
#   "" (unset) or "no"
#     Nothing is done
#   "load" 
#     If file $HOME/.</xsl:text>

  <xsl:value-of select="(@namespace)"/>
  <xsl:text>.</xsl:text>
  <xsl:value-of select="(@class)"/>
  <xsl:text>.sh exists it is sourced.
#     If not found error message and exit.
#   "auto" 
#     Similar to "load", but does nothing if default config not found.
#   "save" 
#     Settings are saved to $HOME/.</xsl:text>

  <xsl:value-of select="(@namespace)"/>
  <xsl:text>.</xsl:text>
  <xsl:value-of select="(@class)"/>
  <xsl:text>.sh for future load.
#   "show"
#     Current settings are shown
#   FILE
#     We attempt to load config from FILE specified.

check_config_file() {
  local SCFG="/etc/</xsl:text>

  <xsl:value-of select="(@namespace)"/>
  <xsl:text>.</xsl:text>
  <xsl:value-of select="(@class)"/>
  <xsl:text>.conf"
  local UCFG="${HOME}/.</xsl:text>
  <xsl:value-of select="(@namespace)"/>
  <xsl:text>.</xsl:text>
  <xsl:value-of select="(@class)"/>
  <xsl:text>.conf"
  local CMD="$1"

  if [ "$CMD" = "no" -o "$CMD" = "" ]; then
    return 0;
  elif [ "$CMD" = "show" ]; then
    print_config
    exit 0
  elif [ "${CMD}" = "save" ]; then
    print_config > "${UCFG}"
    echo "Saved configuration as: ${UCFG}";
    echo "Will automatically be loaded at next configure invocation."
    exit
  elif [ "${CMD}" = "auto" ]; then
    for f in "${SCFG}" "${UCFG}"; do
      if [ -f "${f}" ]; then
        . "${f}"
      fi
    done
  elif [ "${CMD}" = "load" ]; then
    if [ -f "${UCFG}" ]; then
      for f in "${SCFG}" "${UCFG}"; do
        if [ -f "${f}" ]; then
          . "${f}"
        fi
      done
    else
      error "unable to read config: ${UCFG}"
      exit 1
    fi
  elif [ -f "${CMD}" ]; then
    for f in "${SCFG}" "${CMD}"; do
      if [ -f "${f}" ]; then
        . "${f}"
      fi
    done
  else
    error "for configuration files, use: --config no|save|load|show|FILE"
    exit 1
  fi
}

# list_options
#
# Displays all options on single line

append_line() {
  LLEN=${#LINE}
  NLEN=$((${LLEN}+${#1}+1))
  if [ "$((${NLEN} > 72))" != "0" ]; then
    printf "${LINE}\n";
    LINE="        ";
  fi
  LINE="${LINE} ${1}"
}

list_options() {
  LINE="  $(basename "$0")";
</xsl:text>

  <xsl:for-each select="*">
    <xsl:text>  append_line "</xsl:text>

    <xsl:if test="not(@default='REQUIRED')">
      <xsl:text>[</xsl:text>
    </xsl:if>

    <xsl:if test="key/@short">
      <xsl:text>-</xsl:text>
      <xsl:value-of select="key/@short"/>
      <xsl:text>|</xsl:text>
    </xsl:if>

    <xsl:text>--</xsl:text>
    <xsl:value-of select="key"/>

    <xsl:if test="(@type)">
      <xsl:text> </xsl:text>
      <xsl:value-of select="(@type)" />
    </xsl:if>

    <xsl:if test="not(@default='REQUIRED')">
      <xsl:text>]</xsl:text>
    </xsl:if>

    <xsl:text>"
</xsl:text>

  </xsl:for-each>

  <xsl:text>
  append_line " [-h|--help]";
  printf "${LINE}\n";
}

# show_usage
#
# Displays help screen

show_usage() {
  printf "\nUsage:\n"
  list_options | fold -s 
  printf "\nWhere:\n"
</xsl:text>

  <xsl:for-each select="*">
    <xsl:text>  printf "  </xsl:text>
    <xsl:if test="key/@short">
      <xsl:text>-</xsl:text>
      <xsl:value-of select="key/@short"/>
      <xsl:text>|</xsl:text>
    </xsl:if>

    <xsl:text>--</xsl:text>
    <xsl:value-of select="key"/>
    <xsl:text>"
  printf " </xsl:text>

    <xsl:value-of select="(@type)"/>
    <xsl:text>  Currently:[$</xsl:text>
    <xsl:value-of select="(@varname)"/>
    <xsl:text>]\n"
  printf "    </xsl:text>

    <xsl:value-of select="summary"/>

    <xsl:text>\n"
</xsl:text>

  </xsl:for-each>

  <xsl:text>  printf "  -h|--help\n    Displays this usage information.\n"
  printf "\n"
}

# error TEXT
#
# Reports error message to screen and sets OK to false - does NOT exit

error() {
  echo "***ERROR*** $1" 1>&amp;2
  OK=false
}

# error_if_switch TEST
#
# makes sure TEST doesn't start with "-"

error_if_switch() {
  local VAL="${1}";
  if [ "${VAL:0:1}" = "-" ]; then
    error "'${VAL}' is not acceptable after ${2:-switch}";
  fi

}

# get_value_for TYPE FROM CNT OPT [MIN] [MAX]
#
# Sets VALUE to the value parsed from FROM. TYPE indicates the type of value
# we are looking for. CNT is 0 if FROM wasn't available (number of
# arguments left on line). OPT is only used for error reporting (the
# command line switch we are looking for). Current rules (based on
# TYPE):
#
# bool
#   If CNT is 0, then echo "true"
#   If FROM starts with '-', then VALUE="$TRUE"
#   Otherwise, accept and set VALUE=FROM if it is "true" OR "false"
#
# int64/double
#   If CNT is 0, then error
#   Otherwise, we accept anything ('-' might be negative)
#
# OTHER
#   If CNT is 0 or FROM starts with '-' then error
#   Otherwise set VALUE=FROM
#
# returns 1 is FROM was used or 0 if not (use via: shift $?)
#
# Non-Error Examples:
#
#   get_value_for "bool" "" "0" "--enable"   # VALUE=true returns 0
#   get_value_for "bool" "--in" "12" "--enable"  # VALUE=true returns 0
#   get_value_for "bool" "false" "12" "--enable" # VALUE=false returns 1
#   get_value_for "file" "file.txt" "1" "--in" # VALUE=file.txt returns 1
#
# Error Examples:
#
#   get_value_for "bool" "no" "1" "--enable" # no not allowed 
#   get_value_for "file" "" "0" "--in" # missing value (0 count)
#   get_value_for "file" "--out" "12" "--in" # omitted value

get_value_for() {
  local TYPE="${1}"; # Type of value (like "int64")
  local VAL="${2}";  # Value to check (like "7")
  local CNT="${3}";  # Maximum number of values (like "1")
  local OPT="${4}";  # Option name (like "--verbosity")

  if [ "${TYPE}" == "bool" ]; then
                           # if true/false omitted, default to true
    if [ "${CNT}" = "0" -o "${VAL:0:1}" = "-" ]; then
      VALUE="true";
      return 0;
    fi

    if [ "${VAL}" != "true" -a "${VAL}" != "false" ]; then
      error "'${VAL}' is unacceptable (it was not true or false)."
      exit 1;
    fi
    VALUE="${VAL}";
    return 1;
  fi
  
  if [ "${CNT}" = "0" ]; then
    error "missing value for ${OPT} switch"
    exit 1;
  fi

  #
  # Allow leading '-' for number types
  #
  if [ "${TYPE}" = "double" -o "${TYPE}" = "int64" ]; then
    local MIN="${5}";
    local MAX="${6}";
    local VALID="true";

    # We can check min/max values for integers
    if [ "${TYPE}" = "int64" ]; then
      TYPE="integer";
      local IVAL="${VAL}"; # Strip leading "+" if present
      if [ "${VAL:0:1}" = "+" ]; then
        IVAL="${VAL:1}";
      fi

      if [ "$((VAL+0))" != "${IVAL}" ]; then
        VALID="false";
      elif [ "${MIN}" != "" -a "$((VAL &lt; MIN))" == "1" ]; then
        VALID="false";
      elif [ "${MAX}" != "" -a "$((VAL &gt; MAX))" == "1" ]; then
        VALID="false";
      fi
    elif [ "${TYPE}" = "double" ]; then
      TYPE="real number";
      # fix signs for dc
      local DVAL="${VAL//-/_}";
      DVAL="${DVAL//+/}";
      local DMIN="${MIN//-/_}";
      DMIN="${DMIN//+/}";
      local DMAX="${MAX//-/_}";
      DMAX="${DMAX//+/}";

      if [ "$(echo "[0p]sa" "${DVAL}" 0.0 + "${DVAL}" "!=a" | dc 2&gt;&amp;1)" = "0" ]; then
        VALID="false";
      elif [ "${MIN}" != "" -a\
             "$(echo "[0p]sa" "${DVAL}" "${DMIN}" "&gt;a" | dc 2&gt;&amp;1)" = "0" ]; then
        VALID="false";
      elif [ "${MAX}" != "" -a\
             "$(echo "[0p]sa" "${DVAL}" "${DMAX}" "&lt;a" | dc 2&gt;&amp;1)" = "0" ]; then
        VALID="false";
      fi
    fi


    if [ "${VALID}" == "true" ]; then
      VALUE="${VAL}";
      return 1;
    fi

    error "${OPT} requires a ${TYPE} in range [${MIN:--INF},${MAX:-INF}] (${VAL} is bad)."
    exit 1;
  fi

  if [ "${VAL:0:1}" = "-" ]; then
    error "'${VAL}' is not acceptable after ${OPT} switch"
    exit 1;
  fi
  VALUE="${VAL}";
  return 1;
}

#
# Set default values
#

</xsl:text>

  <xsl:for-each select="*">

    <xsl:value-of select="(@varname)"/>
    <xsl:text>="</xsl:text>
    <xsl:value-of select="(@default)"/>
    <xsl:text>";
</xsl:text>

  </xsl:for-each>

  <xsl:text>
# process_args CMD ARG0 ARG1 ...
#
#   Process command line arguments passed to CMD

process_args() {

  while test $# -gt 0; do

    OPT="$1";
    shift

    case "$OPT" in

    -h | --help)
      check_config_file "$CONFIG_FILE"
      show_usage;
      exit 1;
      ;;

</xsl:text>

  <xsl:for-each select="*">
    <xsl:text>    </xsl:text>

    <xsl:if test="key/@short">
      <xsl:text>-</xsl:text>
      <xsl:value-of select="key/@short"/>
      <xsl:text> | </xsl:text>
    </xsl:if>

    <xsl:text>--</xsl:text>
    <xsl:value-of select="key"/>
    <xsl:text>)
      get_value_for </xsl:text>

    <xsl:value-of select="(@cctype)"/>
    <xsl:text> "${1}" "$#" "$OPT" "</xsl:text>
    <xsl:value-of select="(@min)"/>
    <xsl:text>" "</xsl:text>
    <xsl:value-of select="(@max)"/>
    <xsl:text>"
      shift $?
      </xsl:text>
    <xsl:value-of select="(@varname)"/>
    <xsl:text>="${VALUE}";
      ;;

</xsl:text>

  </xsl:for-each>

  <xsl:text>
    *)
      error "'$OPT' is not a valid option!"
    esac
  done

}

# check_required_args [EXIT_CODE]
#
#   Checks all arguments which have a default value of "REQUIRED". If
#   these arguments have not been specified by the user, then echos a
#   message (and optionally exits with EXIT_CODE).
#
# EXIT_CODE
#   If this argument is passed, we will exit the script if
#   any required arguments are found to be missing.
#
# RETURNS
#   0 if we were not missing any required arguments, 1 if we were (and
#   we didn't exit).

check_required_args() {
</xsl:text>

  <xsl:for-each select="*">

    <xsl:if test="@default='REQUIRED'">
      <xsl:text>  if [ "${</xsl:text>
      <xsl:value-of select="(@varname)"/>
      <xsl:text>}" = "REQUIRED" ]; then
    show_usage;
    error "missing required option (--</xsl:text>
      <xsl:value-of select="key"/>
      <xsl:text>)";
    exit ${1};
  fi
</xsl:text>

    </xsl:if>

  </xsl:for-each>

  <xsl:text>
  return 0;
}

process_args "$@"

# If configuration files are enabled (CONFIG_FILE set), then check
# user value. Will need to reload command line arguments if "--config
# auto" specified (as it implies different default settings).

if [ "$CONFIG_FILE" != "" ]; then
  check_config_file "$CONFIG_FILE"

  if [ "$CONFIG_FILE" = "auto" ]; then
    process_args "$@"
  fi
fi

#
# If any obvious errors, show the usage and exit now!
#

if [ "$OK" != "true" ]; then
  show_usage 1>&amp;2
  exit 2
fi

#
# END OF SECTION GENERATED BY keyval_to_sh.xsl
#
</xsl:text>

</xsl:template>

</xsl:stylesheet>
