Commit 049144d0 authored by Dom Sekotill's avatar Dom Sekotill
Browse files

Moved argument parsing functions to their own file

parent e529f388
Loading
Loading
Loading
Loading

arg_parse_functions

0 → 100644
+225 −0
Original line number Diff line number Diff line
#! /bin/bash
#
#  This file contains functions for parsing command line arguments.
#
#  Copyright (C) 2013  Dom Sekotill
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
#


##
# add_arg()
# Add an argument to parse out of the command line.
#
# Usage:
# add_arg {FLAG|VALUE} <argument> [<destination variable> [<default value>
#         [<metaname>]]]
#
# Parameters:
# $1
#   One of FLAG or VALUE
#     FLAG:
#       Argument is not followed on the command line by a value, it is always 
#       false by default and true if given on the command line.
#     VALUE:
#       Argument is expected to be followed by a value.
# $2
#   Argument name; the argument as it will be given on the command line.  
#   Typically either in short or long forms. Short forms are a single hyphen 
#   followed by a single letter or number, long forms are two hyphens followed 
#   by several letters, numbers, hyphens & underscores. Short forms can be 
#   combined as a single hyphen followed by the letters or characters of 
#   several arguments. This combined form may only have at most one VALUE 
#   argument (on the end) as it needs to be followed by its value.
# $3
#   The variable to write the value into. Leading hyphens are removed and other 
#   hyphens converted to underscores. If not given or a null string it defaults 
#   to $2
# $4
#   The default value if the argument does not apear on the command line (only 
#   for VALUE types)
# $5
#   The name to use as a placeholder for values in help messages. It defaults 
#   to $3 converted to uppercase.
##
add_arg ()
{
	local argtype=$1 argname=$2 dest=$3 default=$4 metavar=$5
	if [ "$argtype" = FLAG ]; then
		default=no
	elif [ "$argtype" = VALUE ]; then
		echo -n
	else
		die "'argtype' must be one of 'FLAG' or 'VALUE'"
	fi
	dest=${dest:-$argname}
	dest=${dest##-}
	dest=${dest##-}
	dest=${dest//-/_}
	metavar=${metavar:-`echo $dest | tr [a-z] [A-Z]`}
	eval _ARGS_${argtype}_${dest}=\"$dest,$metavar,$argtype,$default$'\n'$argname\"
}


##
# add_arg_alias()
# Add an alias to a previously defined argument.
#
# This is typically used to define both long and short versions of an argument, 
# or to define a depricated argument name.
#
# Usage:
# add_arg_alias <argument> <alias>
##
add_arg_alias ()
{
	local dest=$1 alias=$2 var flag_var value_var
	dest=${dest##-}
	dest=${dest##-}
	dest=${dest//-/_}
	flag_var=_ARGS_FLAG_$dest
	value_var=_ARGS_VALUE_$dest
	if [ "${!flag_var}" ]; then
		var="$flag_var"
	elif [ "${!value_var}" ]; then
		var="$value_var"
	else
		die "$dest is not a valid argument or destination"
	fi
	eval "$var=\"\$$var,$alias\""
}


##
# add_option()
# Add an option (positional argument) for the parser to look for.
#
# Positional arguments are values without an argument name. Their relative 
# position to each other is important (unlike named arguments which can be 
# given in any order).
#
# Usage:
# add_option <destination variable> [{yes|no} [<default value [<metaname>]]]
#
# Parameters:
# $1
#   The valiable to store the value in.
# $2
#   Whether the argument is required. Either "yes" or "no"
# $3
#   The default value.
# $4
#   The name to use as a placeholder for values in help messages. It defaults 
#   to $1 if not given or a null string.
##
add_option ()
{
	local dest=$1 default=$2 required=$3 metavar=$4
	required=${required:-yes}
	[ "$required" = yes ] || [ "$required" = no ] || \
		die "'required' must be one of 'yes' or 'no'"
	metavar=${metavar:-$dest}
	eval _OPTS_$dest=$dest,$metavar,$required,\"$default\"
}


##
# sumarise_args()
# Print a single summary line of the arguments defined.
#
# Usage:
# sumarise_args
##
sumarise_args ()
{
	local ignore_long_flag short_flags long_flags values
	local arg dest metavar argtype default names required
	local yes=" <%s>" no=" [<%s>]"
	local IFS
	for arg in ${!_ARGS_*}; do
		{
			IFS=,
			read dest metavar argtype default
			read -a names
		} <<< "${!arg}"
		if [ "$argtype" = FLAG ]; then
			ignore_long_flag=no
			for name in ${names[@]}; do
				case $name in
					-?)
						short_flags="${short_flags:--}${name#-}"
						ignore_long_flag=yes
						break ;;
				esac
			done
			if [ "$ignore_long_flag" = no ]; then
				long_flags="$long_flags [${names[0]}]"
			fi
		else
			values="$values [${names[0]} <$metavar>]"
		fi
	done
	printf -- "${short_flags:+ [$short_flags]}$long_flags$values"
	for arg in ${!_OPTS_*}; do
		IFS=, read dest metavar required default <<< "${!arg}"
		printf "${!required}" $metavar
	done
	echo
}


##
# parse_args()
# Parse all defined arguments.
#
# Usage:
# parse_args "$@"
##
parse_args ()
{
	local command=$1
	shift
	while [ "$1" ]; do
		case "$1" in
			--help|-h)
				printf "$BIN $command"
				sumarise_args | wrap "    "
				return 1
				;;
			--summary)
				echo "$summary"
				return 1
				;;
		esac
		shift
	done
}


##
# free_args()
# Free all defined arguments so that the don't intefer with future argument 
# definintions (for instance if multiple subcommands are parsing their 
# arguments).
#
# Usage:
# free_args
##
free_args ()
{
	for arg in ${!_ARGS_*} ${!_OPTS_*}; do
		eval unset $arg
	done
}
+1 −110
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ set -e
# LIBDIR is populated by the install script
LIBDIR=`dirname $0`
source $LIBDIR/string_functions
source $LIBDIR/arg_parse_functions

BIN=`basename "$0"`
GIT="git ${GIT_DIR+--git-dir "${GIT_DIR}"}"
@@ -51,116 +52,6 @@ full_usage ()
	done
}

add_arg ()
{
	local argtype=$1 argname=$2 dest=$3 default=$4 metavar=$5
	if [ "$argtype" = FLAG ]; then
		default=no
	elif [ "$argtype" = VALUE ]; then
		echo -n
	else
		die "'argtype' must be one of 'FLAG' or 'VALUE'"
	fi
	dest=${dest:-$argname}
	dest=${dest##-}
	dest=${dest##-}
	dest=${dest//-/_}
	metavar=${metavar:-`echo $dest | tr [a-z] [A-Z]`}
	eval _ARGS_${argtype}_${dest}=\"$dest,$metavar,$argtype,$default$'\n'$argname\"
}

add_arg_alias ()
{
	local dest=$1 alias=$2 var flag_var value_var
	dest=${dest##-}
	dest=${dest##-}
	dest=${dest//-/_}
	flag_var=_ARGS_FLAG_$dest
	value_var=_ARGS_VALUE_$dest
	if [ "${!flag_var}" ]; then
		var="$flag_var"
	elif [ "${!value_var}" ]; then
		var="$value_var"
	else
		die "$dest is not a valid argument or destination"
	fi
	eval "$var=\"\$$var,$alias\""
}

add_option ()
{
	local dest=$1 default=$2 required=$3 metavar=$4
	required=${required:-yes}
	[ "$required" = yes ] || [ "$required" = no ] || \
		die "'required' must be one of 'yes' or 'no'"
	metavar=${metavar:-$dest}
	eval _OPTS_$dest=$dest,$metavar,$required,\"$default\"
}

sumarise_args ()
{
	local ignore_long_flag short_flags long_flags values
	local arg dest metavar argtype default names required
	local yes=" <%s>" no=" [<%s>]"
	local IFS
	for arg in ${!_ARGS_*}; do
		{
			IFS=,
			read dest metavar argtype default
			read -a names
		} <<< "${!arg}"
		if [ "$argtype" = FLAG ]; then
			ignore_long_flag=no
			for name in ${names[@]}; do
				case $name in
					-?)
						short_flags="${short_flags:--}${name#-}"
						ignore_long_flag=yes
						break ;;
				esac
			done
			if [ "$ignore_long_flag" = no ]; then
				long_flags="$long_flags [${names[0]}]"
			fi
		else
			values="$values [${names[0]} <$metavar>]"
		fi
	done
	printf -- "${short_flags:+ [$short_flags]}$long_flags$values"
	for arg in ${!_OPTS_*}; do
		IFS=, read dest metavar required default <<< "${!arg}"
		printf "${!required}" $metavar
	done
	echo
}

parse_args ()
{
	local command=$1
	shift
	while [ "$1" ]; do
		case "$1" in
			--help|-h)
				printf "$BIN $command"
				sumarise_args | wrap "    "
				return 1
				;;
			--summary)
				echo "$summary"
				return 1
				;;
		esac
		shift
	done
}

free_args ()
{
	for arg in ${!_ARGS_*} ${!_OPTS_*}; do
		eval unset $arg
	done
}

cmd_init ()
{
	summary="set up git-hook directories in a repository"