parent
b79ceb313b
commit
c0d66c7722
|
@ -12,6 +12,5 @@ USAGE
|
|||
OPTIONS"
|
||||
}
|
||||
|
||||
parse_opts "${PRETTYOPTS[@]}" \
|
||||
--help '$exit_with display_help' \
|
||||
@ args -- "$@" && set -- "${args[@]}" || die "$args"
|
||||
args=(--help '$exit_with display_help')
|
||||
parse_args "$@"; set -- "${args[@]}"
|
||||
|
|
|
@ -16,7 +16,7 @@ OPTIONS
|
|||
Pour un script exécutable, indiquer le type de script à générer:
|
||||
system-or-local, sl -- utilise ulib/auto et genparse()
|
||||
default, d -- utilise /etc/ulibauto et genparse()
|
||||
manual, m -- utilise /etc/ulib et parse_opts()
|
||||
manual, m -- utilise /etc/ulib et parse_args()
|
||||
vanilla, v -- script simple
|
||||
auto -- choisir system-or-local, default ou manual en fonction de
|
||||
la présence de [lib/]ulib et/ou de /etc/ulibauto
|
||||
|
@ -92,6 +92,7 @@ function __fixtypes() {
|
|||
esac
|
||||
case "$stype" in
|
||||
manual|m) stype=manual;;
|
||||
legacy|l) stype=legacy;;
|
||||
""|auto|a) stype=auto;;
|
||||
*)
|
||||
ewarn "$stype: sous-type non reconnu. sélection de la valeur 'auto'"
|
||||
|
@ -150,7 +151,7 @@ Voulez-vous générer un script avec cette configuration?" X &&
|
|||
par défaut sont utilisés: urequire DEFAULTS et genparse() pour l'analyse des
|
||||
arguments.
|
||||
- Avec le type 'manual', le fichier /etc/ulib est chargé. Les paramètres par
|
||||
défaut sont utilisés manuellement: urequire DEFAULTS et parse_opts() pour
|
||||
défaut sont utilisés manuellement: urequire DEFAULTS et parse_args() pour
|
||||
l'analyse des arguments.
|
||||
- Avec le type 'vanilla', un script simple est généré."
|
||||
local -a types
|
||||
|
@ -216,6 +217,21 @@ USAGE
|
|||
OPTIONS"
|
||||
}
|
||||
|
||||
args=(--help '\''$exit_with display_help'\'')
|
||||
parse_args "$@"; set -- "${args[@]}"
|
||||
'
|
||||
;;
|
||||
legacy)
|
||||
echo >>"$file" '
|
||||
function display_help() {
|
||||
uecho "$scriptname:
|
||||
|
||||
USAGE
|
||||
$scriptname [options]
|
||||
|
||||
OPTIONS"
|
||||
}
|
||||
|
||||
parse_opts "${PRETTYOPTS[@]}" \
|
||||
--help '\''$exit_with display_help'\'' \
|
||||
@ args -- "$@" && set -- "${args[@]}" || die "$args"
|
||||
|
|
|
@ -1 +1 @@
|
|||
007000000
|
||||
007001000
|
||||
|
|
423
lib/ulib/base
423
lib/ulib/base
|
@ -37,9 +37,10 @@ fi
|
|||
##@include base.array
|
||||
##@include base.quote
|
||||
##@include base.split
|
||||
##@include base.args
|
||||
##@include base.compat
|
||||
uprovide base
|
||||
urequire base.init base.core base.string base.num base.bool base.array base.quote base.split base.compat
|
||||
urequire base.init base.core base.string base.num base.bool base.array base.quote base.split base.args base.compat
|
||||
|
||||
## Informations sur l'hôte sur lequel tourne ce script
|
||||
# Type de système
|
||||
|
@ -2305,426 +2306,6 @@ function lawkrun() {
|
|||
}
|
||||
function cawkrun() { LANG=C lawkrun "$@"; }
|
||||
function awkrun() { LANG=C lawkrun "$@"; }
|
||||
function parse_opts() {
|
||||
# Analyser des arguments. Cette fonction doit être appelée avec une description
|
||||
# des options à analyser, suivie des arguments proprement dits. En fonction des
|
||||
# options rencontrées, certaines variables sont mises à jour.
|
||||
# Les arguments de cette fonction sont donc de la forme 'optdescs -- args'
|
||||
|
||||
# optdescs est une suite d'arguments d'une des formes suivantes: 'opt,opt... var',
|
||||
# 'opt,opt... $cmd', '@ var', '+', '-', '%'
|
||||
# - Dans la forme 'opt var[=value]', opt est une description d'option, var un
|
||||
# nom de variable à mettre à jour, et value une valeur éventuelle pour les
|
||||
# options sans argument. Si plusieurs options sont mentionnées, séparées par des
|
||||
# virgules, alors tous les options partagent les mêmes paramètres.
|
||||
# opt peut être de la forme '-o' ou '--longopt' pour des options sans
|
||||
# arguments. Dans ce cas, var obtient le nombre de fois que l'option est
|
||||
# mentionnée ('' pour aucune mention, '1' pour une seule mention, etc.), sauf si
|
||||
# on utilise la forme var=value, auquel cas la variable obtient la valeur value,
|
||||
# et le nombre d'occurences de l'option n'est pas compté.
|
||||
# Pour faciliter la lecture:
|
||||
# '--opt .' est équivalent à '--opt opt'
|
||||
# '--opt: .' est équivalent à '--opt: opt='
|
||||
# Avec la forme '-o:' ou '--longopt:', l'option prend un argument obligatoire.
|
||||
# Avec la forme '-o::' ou '--longopt::', l'option prend un argument facultatif
|
||||
# (dans ce cas, la valeur de l'option sur la ligne de commande doit
|
||||
# obligatoirement être collée à l'option.)
|
||||
# Si ces options sont mentionnées plusieurs fois sur la ligne de commande, alors
|
||||
# la variable de destination est un tableau qui contient toutes les valeurs.
|
||||
# Le traitement de la valeur d'une variable dépend de la forme utilisée.
|
||||
# - Avec une option sans argument, le comportement est celui décrit ci-dessus.
|
||||
# - Avec une option qui prend des arguments, la forme '-o: var' considère que
|
||||
# var est un tableau qui contiendra toutes les valeurs mentionnées dans les
|
||||
# options. Avec la forme '-o: var=', la variable n'est pas un tableau et
|
||||
# contient toujours la dernière valeur spécifiée.
|
||||
# - Dans la forme 'opt $cmd', la commande cmd est executée avec eval *dès* que
|
||||
# l'option est rencontrée. La variable option_ contient l'option, e.g. '-o' ou
|
||||
# '--longopt'. Le cas échéant, la variable value_ contient la valeur de
|
||||
# l'option. La fonction 'set@ NAME' met à jour la variable NAME, soit en lui
|
||||
# donnant la valeur $value_, soit en l'incrémentant, suivant le type d'option.
|
||||
# La fonction 'inc@ NAME' incrémente la variable NAME, 'res@ NAME [VALUE]'
|
||||
# initialise la variable à la valeur VALUE, 'add@ NAME [VALUE]' met à jour le
|
||||
# tableau NAME, en lui ajoutant la valeur VALUE. Par défaut, VALUE vaut $value_
|
||||
# - Dans la forme '@ var', var est un nom de tableau qui est initialisé avec le
|
||||
# reste des arguments.
|
||||
# - Avec les caractères '-' ou '+', l'on influe sur la méthode d'analyse. Par
|
||||
# défaut, les options sont valides n'importe ou sur la ligne de commande. Avec
|
||||
# '+', l'analyse s'arrête au premier argument qui n'est pas une option. Avec
|
||||
# '-', les options sont valides n'importe ou sur la ligne de commande, mais les
|
||||
# arguments ne sont pas réordonnés, et apparaissent dans l'ordre de leur
|
||||
# mention.
|
||||
# - Toutes les variables mentionnées après le caractère '%' sont
|
||||
# initialisées. Elle sont garanties d'être vides
|
||||
# Si opt est définie plusieurs fois, la dernière définition est celle qui est
|
||||
# retenue, e.g. dans l'exemple suivant, l'option -o prend une valeur et met à
|
||||
# jour la variable second:
|
||||
# parse_opts -o,--longo first=1 -o: second= ....
|
||||
|
||||
# Si une erreur se produit pendant l'analyse, retourner 1. Si '@ var' est
|
||||
# spécifié, insérer le texte de l'erreur comme unique élément du tableau var.
|
||||
# Une suggestion d'utilisation est donc celle-ci:
|
||||
# parse_opts ... @ args -- "$@" && set -- "${args[@]}" || die "$args"
|
||||
|
||||
# D'abord, parser et normaliser les options
|
||||
# options_ contient la liste des options (-o --longo...)
|
||||
# names_ contient la liste des variables qu'il faut mettre à jour (name name...)
|
||||
# flags_ contient la liste des flags pour les options: '' pour une option
|
||||
# simple, ':' pour option avec argument obligatoire, '::' pour option avec
|
||||
# argument facultatif
|
||||
local -a options_ names_ flags_ destargs_
|
||||
local opts_ longopts_
|
||||
__po_parse_optdescs "$@" || shift $?
|
||||
local args_
|
||||
if args_="$(__po_check_options "$@")"; then
|
||||
eval "set -- $args_"
|
||||
__po_process_options "$@"
|
||||
else
|
||||
[ -n "$destargs_" ] && set_var "$destargs_" "$args_"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
function __po_parse_optdescs() {
|
||||
# Parser et normaliser la description des options valides. A l'issue de
|
||||
# l'appel de cette méthode, 3 tableaux sont initialisés, dont chaque
|
||||
# position correspond à une option:
|
||||
# - options_ contient la liste des options valides e.g. (-o --longo...)
|
||||
# - names_ contient la liste des variables qu'il faut mettre à jour pour ces
|
||||
# options e.g. (name name...)
|
||||
# - flags_ contient la liste des flags pour les options: '' pour une option
|
||||
# simple, ':' pour option avec argument obligatoire, '::' pour option avec
|
||||
# argument facultatif, '$' pour une commande à lancer au lieu d'une variable
|
||||
# à mettre à jour.
|
||||
# De plus, les variables suivantes sont initialisées:
|
||||
# - destargs_ obtient la variable qui doit être initialisée avec le reste
|
||||
# des arguments.
|
||||
# - opts_ et longopts_ sont les arguments à utiliser pour la commande getopt
|
||||
# du package util-linux
|
||||
# Retourner le nombre d'arguments à shifter
|
||||
local -a optdescs_
|
||||
local optdesc_ option_ name_ flag_ value_
|
||||
local reset_
|
||||
local shift_
|
||||
local i_ count_
|
||||
|
||||
let shift_=0
|
||||
while [ -n "$1" ]; do
|
||||
if [ "$1" == -- ]; then
|
||||
shift
|
||||
let shift_=$shift_+1
|
||||
break
|
||||
elif [ "$1" == "%" ]; then
|
||||
reset_=1
|
||||
shift
|
||||
let shift_=$shift_+1
|
||||
elif [ "$1" == "-" -o "$1" == "+" ]; then
|
||||
# annuler les précédentes options + ou -
|
||||
if [ "${opts_#+}" != "$opts_" ]; then
|
||||
opts_="${opts_#+}"
|
||||
elif [ "${opts_#-}" != "$opts_" ]; then
|
||||
opts_="${opts_#-}"
|
||||
fi
|
||||
# puis rajouter l'option
|
||||
opts_="$1$opts_"
|
||||
shift
|
||||
let shift_=$shift_+1
|
||||
elif [ "$1" == "@" ]; then
|
||||
destargs_="$2"
|
||||
shift; shift
|
||||
let shift_=$shift_+2
|
||||
elif [[ "$1" == --* ]] || [[ "$1" == -* ]]; then
|
||||
array_split optdescs_ "$1" ","
|
||||
if [ "$2" == . ]; then
|
||||
local autoname_
|
||||
for optdesc_ in "${optdescs_[@]}"; do
|
||||
if [ ${#optdesc_} -gt ${#autoname_} ]; then
|
||||
autoname_="$optdesc_"
|
||||
fi
|
||||
done
|
||||
while [ -n "$autoname_" -a "${autoname_#-}" != "$autoname_" ]; do autoname_="${autoname_#-}"; done
|
||||
while [ -n "$autoname_" -a "${autoname_%:}" != "$autoname_" ]; do autoname_="${autoname_%:}"; done
|
||||
autoname_="${autoname_//-/_}"
|
||||
shift; shift
|
||||
set -- dummy "$autoname_" "$@"
|
||||
fi
|
||||
for optdesc_ in "${optdescs_[@]}"; do
|
||||
if [[ "$2" == \$* ]]; then
|
||||
name_="$2"
|
||||
if [[ "$optdesc_" == *:: ]]; then
|
||||
option_="${optdesc_%::}"
|
||||
flag_='::$'
|
||||
elif [[ "$optdesc_" == *: ]]; then
|
||||
option_="${optdesc_%:}"
|
||||
flag_=':$'
|
||||
else
|
||||
option_="$optdesc_"
|
||||
flag_='$'
|
||||
fi
|
||||
elif [[ "$optdesc_" == *:: ]]; then
|
||||
option_="${optdesc_%::}"
|
||||
if [[ "$2" == *=* ]]; then
|
||||
# la valeur mentionnée est toujours ignorée
|
||||
name_="${2%%=*}="
|
||||
[ -n "$reset_" ] && eval "$name_="
|
||||
else
|
||||
name_="$2"
|
||||
[ -n "$reset_" ] && array_new "$name_"
|
||||
fi
|
||||
flag_=::
|
||||
elif [[ "$optdesc_" == *: ]]; then
|
||||
option_="${optdesc_%:}"
|
||||
if [[ "$2" == *=* ]]; then
|
||||
# la valeur mentionnée est toujours ignorée
|
||||
name_="${2%%=*}="
|
||||
[ -n "$reset_" ] && eval "$name_="
|
||||
else
|
||||
name_="$2"
|
||||
[ -n "$reset_" ] && array_new "$name_"
|
||||
fi
|
||||
flag_=:
|
||||
else
|
||||
option_="$optdesc_"
|
||||
name_="$2"
|
||||
[ -n "$reset_" ] && eval "$name_="
|
||||
flag_=
|
||||
fi
|
||||
|
||||
if i_="$(array_find options_ "$option_")"; then
|
||||
# supprimer l'ancienne occurence
|
||||
options_=("${options_[@]:0:$i_}" "${options_[@]:$(($i_ + 1))}")
|
||||
names_=("${names_[@]:0:$i_}" "${names_[@]:$(($i_ + 1))}")
|
||||
flags_=("${flags_[@]:0:$i_}" "${flags_[@]:$(($i_ + 1))}")
|
||||
fi
|
||||
options_=("${options_[@]}" "$option_")
|
||||
names_=("${names_[@]}" "$name_")
|
||||
flags_=("${flags_[@]}" "$flag_")
|
||||
done
|
||||
shift; shift
|
||||
let shift_=$shift_+2
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
i_=0
|
||||
count_=${#options_[*]}
|
||||
while [ $i_ -lt $count_ ]; do
|
||||
option_="${options_[$i_]}"
|
||||
flag_="${flags_[$i_]}"
|
||||
i_=$(($i_ + 1))
|
||||
|
||||
# pour construire longopts_ et opts_, enlever $ de flag
|
||||
flag_="${flag_%$}"
|
||||
if [[ "$option_" == --* ]]; then
|
||||
longopts_="${longopts_:+$longopts_,}${option_#--}$flag_"
|
||||
elif [[ "$option_" == -* ]]; then
|
||||
opts_="$opts_${option_#-}$flag_"
|
||||
fi
|
||||
done
|
||||
|
||||
return $shift_
|
||||
}
|
||||
function __po_check_options() {
|
||||
# vérifier la validité des options mentionnées dans les arguments
|
||||
# Si les options sont valides, retourner 0 et afficher la chaine des
|
||||
# arguments traitées.
|
||||
# Sinon, retourner 1 et initialiaser la variable $destargs_ avec le message
|
||||
# d'erreur.
|
||||
local -a getopt_args_
|
||||
getopt_args_=(-o "$opts_" ${longopts_:+-l "$longopts_"} -- "$@")
|
||||
local args_
|
||||
if args_="$(getopt -q "${getopt_args_[@]}")"; then
|
||||
rawecho "$args_"
|
||||
return 0
|
||||
else
|
||||
# relancer la commande pour avoir le message d'erreur
|
||||
LANG=C getopt "${getopt_args_[@]}" 2>&1 1>/dev/null
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
function __po_process_options() {
|
||||
# Traiter les options
|
||||
while [ -n "$1" ]; do
|
||||
if [ "$1" == -- ]; then
|
||||
shift
|
||||
break
|
||||
elif [[ "$1" == -* ]]; then
|
||||
local i_
|
||||
let i_=0
|
||||
for option_ in "${options_[@]}"; do
|
||||
[ "$1" == "${options_[$i_]}" ] && break
|
||||
let i_=$i_+1
|
||||
done
|
||||
name_="names_[$i_]"; name_="${!name_}"
|
||||
flag_="flags_[$i_]"; flag_="${!flag_}"
|
||||
function inc@ { eval "let $1=\$$1+1"; }
|
||||
function res@ { set_var "$1" "${value_:-$2}"; }
|
||||
function add@ { array_add "$1" "${value_:-$2}"; }
|
||||
if [ -z "$name_" ]; then
|
||||
# option non reconnue. ce cas aurait dû être traité par
|
||||
# __po_check_options.
|
||||
ewarn "$1: option non reconnue, elle sera ignorée"
|
||||
elif [[ "$flag_" == *\$ ]]; then
|
||||
if [[ "$flag_" == :* ]]; then
|
||||
value_="$2"; shift
|
||||
function set@ { res@ "$@"; }
|
||||
else
|
||||
value_=
|
||||
function set@ { inc@ "$@"; }
|
||||
fi
|
||||
eval "${name_#\$}"
|
||||
elif [ "$flag_" == "" ]; then
|
||||
if [[ "$name_" == *=* ]]; then
|
||||
set_var "${name_%%=*}" "${name_#*=}"
|
||||
else
|
||||
inc@ "$name_"
|
||||
fi
|
||||
elif [ "$flag_" == ":" -o "$flag_" == "::" ]; then
|
||||
value_="$2"; shift
|
||||
if [ "${name_%=}" != "$name_" ]; then
|
||||
set_var "${name_%=}" "$value_"
|
||||
elif [[ "$name_" == *=* ]]; then
|
||||
set_var "${name_%%=*}" "${name_#*=}"
|
||||
else
|
||||
array_add "$name_" "$value_"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
break
|
||||
fi
|
||||
shift
|
||||
done
|
||||
unset -f inc@ res@ add@ set@
|
||||
[ -n "$destargs_" ] &&
|
||||
set_array "$destargs_" @ "$@"
|
||||
return 0
|
||||
}
|
||||
function __genparse_shortopt() {
|
||||
local LC_COLLATE=C
|
||||
local shortopt="${1//[^A-Z]}"
|
||||
shortopt="$(strlower "${shortopt:0:1}")"
|
||||
[ -n "$shortopt" ] && echo "$shortopt"
|
||||
}
|
||||
HELP_DESC=
|
||||
HELP_USAGE=
|
||||
HELP_OPTIONS=
|
||||
function genparse() {
|
||||
# Afficher une ligne de commande à évaluer pour simplifier l'utilisation de
|
||||
# parse_opts(). Une fonction display_help() par défaut est définie et les
|
||||
# options appropriées de parse_opts sont utilisées pour reconnaître les options
|
||||
# spécifiées par les arguments.
|
||||
# Cette fonction peut être utilisée de cette manière:
|
||||
# HELP_DESC=...
|
||||
# HELP_ARG_DESC=... # pour chaque arg
|
||||
# eval "$(genparse [args...])"
|
||||
# D'autres variables peuvent être définies: HELP_USAGE, HELP_OPTIONS,
|
||||
# HELP_ARG_OPTION. Consulter le source pour connaitre leur utilisation
|
||||
# Les arguments de cette fonction sont de la forme 'sansarg' pour une option
|
||||
# simple qui ne prend pas d'argument ou 'avecarg=[default-value]' pour une
|
||||
# option qui prend un argument. Les options générées sont des options
|
||||
# longues. En l'occurence, les options générées sont respectivement '--sansarg'
|
||||
# et '--avecarg:'
|
||||
# Les variables et les options sont toujours en minuscule. Pour les variables,
|
||||
# le caractère '-' est remplacé par '_'. Si une option contient une lettre en
|
||||
# majuscule, l'option courte correspondante à cette lettre sera aussi reconnue.
|
||||
# Par exemple, la commande suivante:
|
||||
# genparse Force enCoding=utf-8 input= long-Option=
|
||||
# affichera ceci:
|
||||
# function display_help() {
|
||||
# [ -n "$HELP_USAGE" ] || HELP_USAGE="USAGE
|
||||
# $scriptname [options]"
|
||||
# [ -n "$HELP_OPTIONS" ] || HELP_OPTIONS="OPTIONS
|
||||
# ${HELP_FORCE_OPTION:- -f, --force${HELP_FORCE_DESC:+
|
||||
# $HELP_FORCE_DESC}}
|
||||
# ${HELP_ENCODING_OPTION:- -c, --encoding VALUE${HELP_ENCODING_DESC:+
|
||||
# ${HELP_ENCODING_DESC}}}
|
||||
# ${HELP_INPUT_OPTION:- --input VALUE${HELP_INPUT_DESC:+
|
||||
# ${HELP_INPUT_DESC}}}
|
||||
# ${HELP_LONG_OPTION_OPTION:- -o, --long-option VALUE${HELP_LONG_OPTION_DESC:+
|
||||
# ${HELP_LONG_OPTION_DESC}}}"
|
||||
# uecho "${HELP_DESC:+$HELP_DESC
|
||||
#
|
||||
# }$HELP_USAGE${HELP_OPTIONS:+
|
||||
#
|
||||
# $HELP_OPTIONS}"
|
||||
# }
|
||||
#
|
||||
# force=
|
||||
# encoding=utf-8
|
||||
# input=""
|
||||
# long_option=""
|
||||
# parse_opts "${PRETTYOPTS[@]}" \
|
||||
# --help '$exit_with display_help' \
|
||||
# -f,--force force=1 \
|
||||
# -c:,--encoding: encoding= \
|
||||
# --input: input= \
|
||||
# -o:,--long-option: long_option= \
|
||||
# @ args -- "$@" && set -- "${args[@]}" || die "$args"
|
||||
|
||||
local -a names descs vars options
|
||||
local i desc var option name uname value shortopt
|
||||
|
||||
# analyser les arguments
|
||||
for var in "$@"; do
|
||||
if [[ "$var" == *=* ]]; then
|
||||
splitvar "$var" name value
|
||||
shortopt="$(__genparse_shortopt "$name")"
|
||||
option="$(strlower "$name")"
|
||||
name="${option//-/_}"
|
||||
array_add names "$name"
|
||||
array_add descs "${shortopt:+-$shortopt, }--$option VALUE"
|
||||
array_add vars "$(set_var_cmd "$name" "$value")"
|
||||
array_add options "${shortopt:+-$shortopt:,}--$option: $name="
|
||||
else
|
||||
name="$var"
|
||||
shortopt="$(__genparse_shortopt "$name")"
|
||||
option="$(strlower "$name")"
|
||||
name="${option//-/_}"
|
||||
array_add names "$name"
|
||||
array_add descs "${shortopt:+-$shortopt, }--$option"
|
||||
array_add vars "$name="
|
||||
array_add options "${shortopt:+-$shortopt,}--$option $name=1"
|
||||
fi
|
||||
done
|
||||
|
||||
# afficher la commande parse_opts
|
||||
echo -n 'function display_help() {
|
||||
[ -n "$HELP_USAGE" ] || HELP_USAGE="USAGE
|
||||
$scriptname'
|
||||
[ -n "$descs" ] && echo -n ' [options]'
|
||||
echo '"'
|
||||
if [ -n "$descs" ]; then
|
||||
echo -n ' [ -n "$HELP_OPTIONS" ] || HELP_OPTIONS="OPTIONS'
|
||||
i=0
|
||||
while [ $i -lt ${#descs[*]} ]; do
|
||||
name="${names[$i]}"
|
||||
uname="$(strupper "$name")"
|
||||
desc="${descs[$i]}"
|
||||
echo -n "
|
||||
\${HELP_${uname}_OPTION:- $desc\${HELP_${uname}_DESC:+
|
||||
\${HELP_${uname}_DESC//
|
||||
/
|
||||
}}}"
|
||||
i=$(($i + 1))
|
||||
done
|
||||
echo '"'
|
||||
fi
|
||||
echo ' uecho "${HELP_DESC:+$HELP_DESC
|
||||
|
||||
}$HELP_USAGE${HELP_OPTIONS:+
|
||||
|
||||
$HELP_OPTIONS}"
|
||||
}
|
||||
'
|
||||
for var in "${vars[@]}"; do
|
||||
echo "$var"
|
||||
done
|
||||
echo 'parse_opts "${PRETTYOPTS[@]}" \'
|
||||
echo ' --help '\''$exit_with display_help'\'' \'
|
||||
for option in "${options[@]}"; do
|
||||
echo " $option \\"
|
||||
done
|
||||
echo ' @ args -- "$@" && set -- "${args[@]}" || die "$args"'
|
||||
}
|
||||
|
||||
function __lf_get_age() {
|
||||
local y=$(date "+%Y")
|
||||
|
|
|
@ -0,0 +1,449 @@
|
|||
##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
## Analyse des arguments de la ligne de commande
|
||||
##@cooked nocomments
|
||||
##@include base.core
|
||||
##@include base.string
|
||||
##@include base.array
|
||||
uprovide base.args
|
||||
urequire base.core base.string base.array #XXX maj de cette liste
|
||||
|
||||
function __po_parse_optdescs() {
|
||||
# Parser et normaliser la description des options valides. A l'issue de
|
||||
# l'appel de cette méthode, 3 tableaux sont initialisés, dont chaque
|
||||
# position correspond à une option:
|
||||
# - options_ contient la liste des options valides e.g. (-o --longo...)
|
||||
# - names_ contient la liste des variables qu'il faut mettre à jour pour ces
|
||||
# options e.g. (name name...)
|
||||
# - flags_ contient la liste des flags pour les options: '' pour une option
|
||||
# simple, ':' pour option avec argument obligatoire, '::' pour option avec
|
||||
# argument facultatif, '$' pour une commande à lancer au lieu d'une variable
|
||||
# à mettre à jour.
|
||||
# De plus, les variables suivantes sont initialisées:
|
||||
# - destargs_ obtient la variable qui doit être initialisée avec le reste
|
||||
# des arguments.
|
||||
# - opts_ et longopts_ sont les arguments à utiliser pour la commande getopt
|
||||
# du package util-linux
|
||||
# Retourner le nombre d'arguments à shifter
|
||||
local -a optdescs_
|
||||
local optdesc_ option_ name_ flag_ value_
|
||||
local reset_
|
||||
local shift_
|
||||
local i_ count_
|
||||
|
||||
let shift_=0
|
||||
while [ -n "$1" ]; do
|
||||
if [ "$1" == -- ]; then
|
||||
shift
|
||||
let shift_=$shift_+1
|
||||
break
|
||||
elif [ "$1" == "%" ]; then
|
||||
reset_=1
|
||||
shift
|
||||
let shift_=$shift_+1
|
||||
elif [ "$1" == "-" -o "$1" == "+" ]; then
|
||||
# annuler les précédentes options + ou -
|
||||
if [ "${opts_#+}" != "$opts_" ]; then
|
||||
opts_="${opts_#+}"
|
||||
elif [ "${opts_#-}" != "$opts_" ]; then
|
||||
opts_="${opts_#-}"
|
||||
fi
|
||||
# puis rajouter l'option
|
||||
opts_="$1$opts_"
|
||||
shift
|
||||
let shift_=$shift_+1
|
||||
elif [ "$1" == "@" ]; then
|
||||
destargs_="$2"
|
||||
shift; shift
|
||||
let shift_=$shift_+2
|
||||
elif [[ "$1" == --* ]] || [[ "$1" == -* ]]; then
|
||||
array_split optdescs_ "$1" ","
|
||||
if [ "$2" == . ]; then
|
||||
local autoname_=
|
||||
for optdesc_ in "${optdescs_[@]}"; do
|
||||
if [ ${#optdesc_} -gt ${#autoname_} ]; then
|
||||
autoname_="$optdesc_"
|
||||
fi
|
||||
done
|
||||
while [ -n "$autoname_" -a "${autoname_#-}" != "$autoname_" ]; do autoname_="${autoname_#-}"; done
|
||||
while [ -n "$autoname_" -a "${autoname_%:}" != "$autoname_" ]; do autoname_="${autoname_%:}"; done
|
||||
autoname_="${autoname_//-/_}"
|
||||
shift; shift
|
||||
set -- dummy "$autoname_" "$@"
|
||||
fi
|
||||
for optdesc_ in "${optdescs_[@]}"; do
|
||||
if [[ "$2" == \$* ]]; then
|
||||
name_="$2"
|
||||
if [[ "$optdesc_" == *:: ]]; then
|
||||
option_="${optdesc_%::}"
|
||||
flag_='::$'
|
||||
elif [[ "$optdesc_" == *: ]]; then
|
||||
option_="${optdesc_%:}"
|
||||
flag_=':$'
|
||||
else
|
||||
option_="$optdesc_"
|
||||
flag_='$'
|
||||
fi
|
||||
elif [[ "$optdesc_" == *:: ]]; then
|
||||
option_="${optdesc_%::}"
|
||||
if [[ "$2" == *=* ]]; then
|
||||
# la valeur mentionnée est toujours ignorée
|
||||
name_="${2%%=*}="
|
||||
[ -n "$reset_" ] && eval "$name_="
|
||||
else
|
||||
name_="$2"
|
||||
[ -n "$reset_" ] && eval "$name_=()"
|
||||
fi
|
||||
flag_=::
|
||||
elif [[ "$optdesc_" == *: ]]; then
|
||||
option_="${optdesc_%:}"
|
||||
if [[ "$2" == *=* ]]; then
|
||||
# la valeur mentionnée est toujours ignorée
|
||||
name_="${2%%=*}="
|
||||
[ -n "$reset_" ] && eval "$name_="
|
||||
else
|
||||
name_="$2"
|
||||
[ -n "$reset_" ] && eval "$name_=()"
|
||||
fi
|
||||
flag_=:
|
||||
else
|
||||
option_="$optdesc_"
|
||||
name_="$2"
|
||||
[ -n "$reset_" ] && eval "$name_="
|
||||
flag_=
|
||||
fi
|
||||
|
||||
if i_="$(array_find options_ "$option_")"; then
|
||||
# supprimer l'ancienne occurence
|
||||
options_=("${options_[@]:0:$i_}" "${options_[@]:$(($i_ + 1))}")
|
||||
names_=("${names_[@]:0:$i_}" "${names_[@]:$(($i_ + 1))}")
|
||||
flags_=("${flags_[@]:0:$i_}" "${flags_[@]:$(($i_ + 1))}")
|
||||
fi
|
||||
options_=("${options_[@]}" "$option_")
|
||||
names_=("${names_[@]}" "$name_")
|
||||
flags_=("${flags_[@]}" "$flag_")
|
||||
done
|
||||
shift; shift
|
||||
let shift_=$shift_+2
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
i_=0
|
||||
count_=${#options_[*]}
|
||||
while [ $i_ -lt $count_ ]; do
|
||||
option_="${options_[$i_]}"
|
||||
flag_="${flags_[$i_]}"
|
||||
i_=$(($i_ + 1))
|
||||
|
||||
# pour construire longopts_ et opts_, enlever $ de flag
|
||||
flag_="${flag_%$}"
|
||||
if [[ "$option_" == --* ]]; then
|
||||
longopts_="${longopts_:+$longopts_,}${option_#--}$flag_"
|
||||
elif [[ "$option_" == -* ]]; then
|
||||
opts_="$opts_${option_#-}$flag_"
|
||||
fi
|
||||
done
|
||||
|
||||
return $shift_
|
||||
}
|
||||
function __po_check_options() {
|
||||
# vérifier la validité des options mentionnées dans les arguments
|
||||
# Si les options sont valides, retourner 0 et afficher la chaine des
|
||||
# arguments traitées.
|
||||
# Sinon, retourner 1 et initialiaser la variable $destargs_ avec le message
|
||||
# d'erreur.
|
||||
local -a getopt_args_
|
||||
getopt_args_=(-o "$opts_" ${longopts_:+-l "$longopts_"} -- "$@")
|
||||
local args_
|
||||
if args_="$(getopt -q "${getopt_args_[@]}")"; then
|
||||
recho "$args_"
|
||||
return 0
|
||||
else
|
||||
# relancer la commande pour avoir le message d'erreur
|
||||
LANG=C getopt "${getopt_args_[@]}" 2>&1 1>/dev/null
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
function __po_process_options() {
|
||||
# Traiter les options
|
||||
while [ -n "$1" ]; do
|
||||
if [ "$1" == -- ]; then
|
||||
shift
|
||||
break
|
||||
elif [[ "$1" == -* ]]; then
|
||||
local i_
|
||||
let i_=0
|
||||
for option_ in "${options_[@]}"; do
|
||||
[ "$1" == "${options_[$i_]}" ] && break
|
||||
let i_=$i_+1
|
||||
done
|
||||
name_="names_[$i_]"; name_="${!name_}"
|
||||
flag_="flags_[$i_]"; flag_="${!flag_}"
|
||||
function inc@ { eval "let $1=\$$1+1"; }
|
||||
function res@ { set_var "$1" "${value_:-$2}"; }
|
||||
function add@ { array_add "$1" "${value_:-$2}"; }
|
||||
if [ -z "$name_" ]; then
|
||||
# option non reconnue. ce cas aurait dû être traité par
|
||||
# __po_check_options.
|
||||
ewarn "$1: option non reconnue, elle sera ignorée"
|
||||
elif [[ "$flag_" == *\$ ]]; then
|
||||
if [[ "$flag_" == :* ]]; then
|
||||
value_="$2"; shift
|
||||
function set@ { res@ "$@"; }
|
||||
else
|
||||
value_=
|
||||
function set@ { inc@ "$@"; }
|
||||
fi
|
||||
eval "${name_#\$}"
|
||||
elif [ "$flag_" == "" ]; then
|
||||
if [[ "$name_" == *=* ]]; then
|
||||
set_var "${name_%%=*}" "${name_#*=}"
|
||||
else
|
||||
inc@ "$name_"
|
||||
fi
|
||||
elif [ "$flag_" == ":" -o "$flag_" == "::" ]; then
|
||||
value_="$2"; shift
|
||||
if [ "${name_%=}" != "$name_" ]; then
|
||||
set_var "${name_%=}" "$value_"
|
||||
elif [[ "$name_" == *=* ]]; then
|
||||
set_var "${name_%%=*}" "${name_#*=}"
|
||||
else
|
||||
array_add "$name_" "$value_"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
break
|
||||
fi
|
||||
shift
|
||||
done
|
||||
unset -f inc@ res@ add@ set@
|
||||
[ -n "$destargs_" ] &&
|
||||
set_array "$destargs_" @ "$@"
|
||||
return 0
|
||||
}
|
||||
function parse_opts() {
|
||||
# Analyser des arguments. Cette fonction doit être appelée avec une description
|
||||
# des options à analyser, suivie des arguments proprement dits. En fonction des
|
||||
# options rencontrées, certaines variables sont mises à jour.
|
||||
# Les arguments de cette fonction sont donc de la forme 'optdescs -- args'
|
||||
|
||||
# optdescs est une suite d'arguments d'une des formes suivantes: 'opt,opt... var',
|
||||
# 'opt,opt... $cmd', '@ var', '+', '-', '%'
|
||||
# - Dans la forme 'opt var[=value]', opt est une description d'option, var un
|
||||
# nom de variable à mettre à jour, et value une valeur éventuelle pour les
|
||||
# options sans argument. Si plusieurs options sont mentionnées, séparées par des
|
||||
# virgules, alors tous les options partagent les mêmes paramètres.
|
||||
# opt peut être de la forme '-o' ou '--longopt' pour des options sans
|
||||
# arguments. Dans ce cas, var obtient le nombre de fois que l'option est
|
||||
# mentionnée ('' pour aucune mention, '1' pour une seule mention, etc.), sauf si
|
||||
# on utilise la forme var=value, auquel cas la variable obtient la valeur value,
|
||||
# et le nombre d'occurences de l'option n'est pas compté.
|
||||
# Pour faciliter la lecture:
|
||||
# '--opt .' est équivalent à '--opt opt'
|
||||
# '--opt: .' est équivalent à '--opt: opt='
|
||||
# Avec la forme '-o:' ou '--longopt:', l'option prend un argument obligatoire.
|
||||
# Avec la forme '-o::' ou '--longopt::', l'option prend un argument facultatif
|
||||
# (dans ce cas, la valeur de l'option sur la ligne de commande doit
|
||||
# obligatoirement être collée à l'option.)
|
||||
# Si ces options sont mentionnées plusieurs fois sur la ligne de commande, alors
|
||||
# la variable de destination est un tableau qui contient toutes les valeurs.
|
||||
# Le traitement de la valeur d'une variable dépend de la forme utilisée.
|
||||
# - Avec une option sans argument, le comportement est celui décrit ci-dessus.
|
||||
# - Avec une option qui prend des arguments, la forme '-o: var' considère que
|
||||
# var est un tableau qui contiendra toutes les valeurs mentionnées dans les
|
||||
# options. Avec la forme '-o: var=', la variable n'est pas un tableau et
|
||||
# contient toujours la dernière valeur spécifiée.
|
||||
# - Dans la forme 'opt $cmd', la commande cmd est executée avec eval *dès* que
|
||||
# l'option est rencontrée. La variable option_ contient l'option, e.g. '-o' ou
|
||||
# '--longopt'. Le cas échéant, la variable value_ contient la valeur de
|
||||
# l'option. La fonction 'set@ NAME' met à jour la variable NAME, soit en lui
|
||||
# donnant la valeur $value_, soit en l'incrémentant, suivant le type d'option.
|
||||
# La fonction 'inc@ NAME' incrémente la variable NAME, 'res@ NAME [VALUE]'
|
||||
# initialise la variable à la valeur VALUE, 'add@ NAME [VALUE]' met à jour le
|
||||
# tableau NAME, en lui ajoutant la valeur VALUE. Par défaut, VALUE vaut $value_
|
||||
# - Dans la forme '@ var', var est un nom de tableau qui est initialisé avec le
|
||||
# reste des arguments.
|
||||
# - Avec les caractères '-' ou '+', l'on influe sur la méthode d'analyse. Par
|
||||
# défaut, les options sont valides n'importe ou sur la ligne de commande. Avec
|
||||
# '+', l'analyse s'arrête au premier argument qui n'est pas une option. Avec
|
||||
# '-', les options sont valides n'importe ou sur la ligne de commande, mais les
|
||||
# arguments ne sont pas réordonnés, et apparaissent dans l'ordre de leur
|
||||
# mention.
|
||||
# - Toutes les variables mentionnées après le caractère '%' sont
|
||||
# initialisées. Elle sont garanties d'être vides
|
||||
# Si opt est définie plusieurs fois, la dernière définition est celle qui est
|
||||
# retenue, e.g. dans l'exemple suivant, l'option -o prend une valeur et met à
|
||||
# jour la variable second:
|
||||
# parse_opts -o,--longo first=1 -o: second= ....
|
||||
|
||||
# Si une erreur se produit pendant l'analyse, retourner 1. Si '@ var' est
|
||||
# spécifié, insérer le texte de l'erreur comme unique élément du tableau var.
|
||||
# Une suggestion d'utilisation est donc celle-ci:
|
||||
# parse_opts ... @ args -- "$@" && set -- "${args[@]}" || die "$args"
|
||||
|
||||
# D'abord, parser et normaliser les options
|
||||
# options_ contient la liste des options (-o --longo...)
|
||||
# names_ contient la liste des variables qu'il faut mettre à jour (name name...)
|
||||
# flags_ contient la liste des flags pour les options: '' pour une option
|
||||
# simple, ':' pour option avec argument obligatoire, '::' pour option avec
|
||||
# argument facultatif
|
||||
local -a options_ names_ flags_ destargs_
|
||||
local opts_ longopts_
|
||||
__po_parse_optdescs "$@" || shift $?
|
||||
local args_
|
||||
if args_="$(__po_check_options "$@")"; then
|
||||
eval "set -- $args_"
|
||||
__po_process_options "$@"
|
||||
else
|
||||
[ -n "$destargs_" ] && set_var "$destargs_" "$args_"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function parse_args_check() {
|
||||
# Simplifier l'utilisation de parse_opts(). En entrée, le tableau args doit être
|
||||
# initialisé avec la liste des options. En sortie, ce tableau contient la liste
|
||||
# des arguments restant sur la ligne de commande. En cas d'erreur, retourner 1.
|
||||
# Exemple d'utilisation:
|
||||
# args=(-c:,--config: .)
|
||||
# parse_args_check "$@" || return
|
||||
parse_opts "${PRETTYOPTS[@]}" "${args[@]}" @ args -- "$@" && return 0
|
||||
eerror "$args"
|
||||
return 1
|
||||
}
|
||||
function parse_args() {
|
||||
# Simplifier l'utilisation de parse_opts(). En entrée, le tableau args doit être
|
||||
# initialisé avec la liste des options. En sortie, ce tableau contient la liste
|
||||
# des arguments restant sur la ligne de commande. En cas d'erreur, quitter le
|
||||
# script avec die()
|
||||
parse_opts "${PRETTYOPTS[@]}" "${args[@]}" @ args -- "$@" || die "$args"
|
||||
}
|
||||
|
||||
HELP_DESC=
|
||||
HELP_USAGE=
|
||||
HELP_OPTIONS=
|
||||
function __genparse_shortopt() {
|
||||
local LC_COLLATE=C
|
||||
local shortopt="${1//[^A-Z]}"
|
||||
shortopt="$(strlower "${shortopt:0:1}")"
|
||||
[ -n "$shortopt" ] && echo "$shortopt"
|
||||
}
|
||||
function genparse() {
|
||||
# Afficher une ligne de commande à évaluer pour simplifier l'utilisation de
|
||||
# parse_opts(). Une fonction display_help() par défaut est définie et les
|
||||
# options appropriées de parse_opts sont utilisées pour reconnaître les options
|
||||
# spécifiées par les arguments.
|
||||
# Cette fonction peut être utilisée de cette manière:
|
||||
# HELP_DESC=...
|
||||
# HELP_ARG_DESC=... # pour chaque arg
|
||||
# eval "$(genparse [args...])"
|
||||
# D'autres variables peuvent être définies: HELP_USAGE, HELP_OPTIONS,
|
||||
# HELP_ARG_OPTION. Consulter le source pour connaitre leur utilisation
|
||||
# Les arguments de cette fonction sont de la forme 'sansarg' pour une option
|
||||
# simple qui ne prend pas d'argument ou 'avecarg=[default-value]' pour une
|
||||
# option qui prend un argument. Les options générées sont des options
|
||||
# longues. En l'occurence, les options générées sont respectivement '--sansarg'
|
||||
# et '--avecarg:'
|
||||
# Les variables et les options sont toujours en minuscule. Pour les variables,
|
||||
# le caractère '-' est remplacé par '_'. Si une option contient une lettre en
|
||||
# majuscule, l'option courte correspondante à cette lettre sera aussi reconnue.
|
||||
# Par exemple, la commande suivante:
|
||||
# genparse Force enCoding=utf-8 input= long-Option=
|
||||
# affichera ceci:
|
||||
# function display_help() {
|
||||
# [ -n "$HELP_USAGE" ] || HELP_USAGE="USAGE
|
||||
# $scriptname [options]"
|
||||
# [ -n "$HELP_OPTIONS" ] || HELP_OPTIONS="OPTIONS
|
||||
# ${HELP_FORCE_OPTION:- -f, --force${HELP_FORCE_DESC:+
|
||||
# $HELP_FORCE_DESC}}
|
||||
# ${HELP_ENCODING_OPTION:- -c, --encoding VALUE${HELP_ENCODING_DESC:+
|
||||
# ${HELP_ENCODING_DESC}}}
|
||||
# ${HELP_INPUT_OPTION:- --input VALUE${HELP_INPUT_DESC:+
|
||||
# ${HELP_INPUT_DESC}}}
|
||||
# ${HELP_LONG_OPTION_OPTION:- -o, --long-option VALUE${HELP_LONG_OPTION_DESC:+
|
||||
# ${HELP_LONG_OPTION_DESC}}}"
|
||||
# uecho "${HELP_DESC:+$HELP_DESC
|
||||
#
|
||||
# }$HELP_USAGE${HELP_OPTIONS:+
|
||||
#
|
||||
# $HELP_OPTIONS}"
|
||||
# }
|
||||
#
|
||||
# force=
|
||||
# encoding=utf-8
|
||||
# input=""
|
||||
# long_option=""
|
||||
# parse_opts "${PRETTYOPTS[@]}" \
|
||||
# --help '$exit_with display_help' \
|
||||
# -f,--force force=1 \
|
||||
# -c:,--encoding: encoding= \
|
||||
# --input: input= \
|
||||
# -o:,--long-option: long_option= \
|
||||
# @ args -- "$@" && set -- "${args[@]}" || die "$args"
|
||||
|
||||
local -a names descs vars options
|
||||
local i desc var option name uname value shortopt
|
||||
|
||||
# analyser les arguments
|
||||
for var in "$@"; do
|
||||
if [[ "$var" == *=* ]]; then
|
||||
splitvar "$var" name value
|
||||
shortopt="$(__genparse_shortopt "$name")"
|
||||
option="$(strlower "$name")"
|
||||
name="${option//-/_}"
|
||||
array_add names "$name"
|
||||
array_add descs "${shortopt:+-$shortopt, }--$option VALUE"
|
||||
array_add vars "$(set_var_cmd "$name" "$value")"
|
||||
array_add options "${shortopt:+-$shortopt:,}--$option: $name="
|
||||
else
|
||||
name="$var"
|
||||
shortopt="$(__genparse_shortopt "$name")"
|
||||
option="$(strlower "$name")"
|
||||
name="${option//-/_}"
|
||||
array_add names "$name"
|
||||
array_add descs "${shortopt:+-$shortopt, }--$option"
|
||||
array_add vars "$name="
|
||||
array_add options "${shortopt:+-$shortopt,}--$option $name=1"
|
||||
fi
|
||||
done
|
||||
|
||||
# afficher la commande parse_opts
|
||||
echo -n 'function display_help() {
|
||||
[ -n "$HELP_USAGE" ] || HELP_USAGE="USAGE
|
||||
$scriptname'
|
||||
[ -n "$descs" ] && echo -n ' [options]'
|
||||
echo '"'
|
||||
if [ -n "$descs" ]; then
|
||||
echo -n ' [ -n "$HELP_OPTIONS" ] || HELP_OPTIONS="OPTIONS'
|
||||
i=0
|
||||
while [ $i -lt ${#descs[*]} ]; do
|
||||
name="${names[$i]}"
|
||||
uname="$(strupper "$name")"
|
||||
desc="${descs[$i]}"
|
||||
echo -n "
|
||||
\${HELP_${uname}_OPTION:- $desc\${HELP_${uname}_DESC:+
|
||||
\${HELP_${uname}_DESC//
|
||||
/
|
||||
}}}"
|
||||
i=$(($i + 1))
|
||||
done
|
||||
echo '"'
|
||||
fi
|
||||
echo ' uecho "${HELP_DESC:+$HELP_DESC
|
||||
|
||||
}$HELP_USAGE${HELP_OPTIONS:+
|
||||
|
||||
$HELP_OPTIONS}"
|
||||
}
|
||||
'
|
||||
for var in "${vars[@]}"; do
|
||||
echo "$var"
|
||||
done
|
||||
echo 'parse_opts "${PRETTYOPTS[@]}" \'
|
||||
echo ' --help '\''$exit_with display_help'\'' \'
|
||||
for option in "${options[@]}"; do
|
||||
echo " $option \\"
|
||||
done
|
||||
echo ' @ args -- "$@" && set -- "${args[@]}" || die "$args"'
|
||||
}
|
Loading…
Reference in New Issue