1339 lines
43 KiB
Io
1339 lines
43 KiB
Io
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
##@cooked nocomments
|
|
module: base.io base_ "Fonctions de base: affichage et saisie"
|
|
require: base.arr
|
|
|
|
NULIB__TAB=$'\t'
|
|
NULIB__LATIN1=iso-8859-1
|
|
NULIB__LATIN9=iso-8859-15
|
|
NULIB__UTF8=utf-8
|
|
NULIB_IENC="$NULIB__UTF8"
|
|
NULIB_OENC="$NULIB__UTF8"
|
|
|
|
if [ ! -x "$(which iconv 2>/dev/null)" ]; then
|
|
function iconv() { cat; }
|
|
fi
|
|
|
|
function nulib__lang_encoding() {
|
|
case "${LANG,,}" in
|
|
*@euro) echo "iso-8859-15";;
|
|
*.utf-8|*.utf8) echo "utf-8";;
|
|
*) echo "iso-8859-1";;
|
|
esac
|
|
}
|
|
|
|
function nulib__norm_encoding() {
|
|
local enc="${1,,}"
|
|
enc="${enc//[-_]/}"
|
|
case "$enc" in
|
|
latin|latin1|iso8859|iso88591|8859|88591) echo "iso-8859-1";;
|
|
latin9|iso885915|885915) echo "iso-8859-15";;
|
|
utf|utf8) echo "utf-8";;
|
|
*) echo "$1";;
|
|
esac
|
|
}
|
|
|
|
function nulib__init_encoding() {
|
|
local DEFAULT_ENCODING="$(nulib__lang_encoding)"
|
|
[ -n "$DEFAULT_ENCODING" ] || DEFAULT_ENCODING=utf-8
|
|
[ -n "$NULIB_OUTPUT_ENCODING" ] || NULIB_OUTPUT_ENCODING="$DEFAULT_ENCODING"
|
|
NULIB_OUTPUT_ENCODING="$(nulib__norm_encoding "$NULIB_OUTPUT_ENCODING")"
|
|
[ -n "$NULIB_INPUT_ENCODING" ] || NULIB_INPUT_ENCODING="$NULIB_OUTPUT_ENCODING"
|
|
NULIB_INPUT_ENCODING="$(nulib__norm_encoding "$NULIB_INPUT_ENCODING")"
|
|
[ -n "$NULIB_EDITOR_ENCODING" ] || NULIB_EDITOR_ENCODING="$NULIB_INPUT_ENCODING"
|
|
NULIB_EDITOR_ENCODING="$(nulib__norm_encoding "$NULIB_EDITOR_ENCODING")"
|
|
|
|
NULIB_IENC="$NULIB_INPUT_ENCODING"
|
|
NULIB_OENC="$NULIB_OUTPUT_ENCODING"
|
|
}
|
|
[ -n "$NULIB_LANG" -a -z "$LANG" ] && export NULIB_LANG LANG="$NULIB_LANG"
|
|
nulib__init_encoding
|
|
|
|
function nulib_local() {
|
|
# Afficher les commandes pour rendre locales certaines variables en fonction des
|
|
# arguments:
|
|
# - opts rend locale args, pour utiliser parse_opts() à l'intérieur d'une
|
|
# fonction.
|
|
# - verbosity et interaction rendent respectivement locales NULIB_VERBOSITY et
|
|
# NULIB_INTERACTION. Ceci est utile pour pouvoir appeler sans risque de
|
|
# pollution de l'environnement une fonction qui utilise parse_opts() avec les
|
|
# définitions de PRETTYOPTS.
|
|
# Si aucun arguments n'est fourni, toutes les définitions sont affichées.
|
|
local arg
|
|
[ $# -gt 0 ] || set -- opts verbosity interaction
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
parse_opts|opts|o|args) echo "local -a args";;
|
|
verbosity|v) echo "local NULIB_VERBOSITY='$NULIB_VERBOSITY'";;
|
|
interaction|i) echo "local NULIB_INTERACTION='$NULIB_INTERACTION'";;
|
|
esac
|
|
done
|
|
}
|
|
|
|
function noerror() {
|
|
# lancer la commande "$@" et masquer son code de retour
|
|
[ $# -gt 0 ] || set :
|
|
"$@" || return 0
|
|
}
|
|
|
|
function noout() {
|
|
# lancer la commande "$@" en supprimant sa sortie standard
|
|
[ $# -gt 0 ] || return 0
|
|
"$@" >/dev/null
|
|
}
|
|
|
|
function noerr() {
|
|
# lancer la commande "$@" en supprimant sa sortie d'erreur
|
|
[ $# -gt 0 ] || return 0
|
|
"$@" 2>/dev/null
|
|
}
|
|
|
|
function stdredir() {
|
|
# Lancer la commande $4..@ en redirigeant stdin depuis $1, stdout vers $2,
|
|
# stderr vers $3. Si $1 est vide ou vaut /dev/stdin, la redirection n'est
|
|
# pas faite. Si $2 est vide ou vaut /dev/stdout, la redirection n'est pas
|
|
# faite. Si $3 est vide ou vaut /dev/stderr, la redirection n'est pas faite.
|
|
# Cette fonction existe parce que sur certaines versions de bash, il semble
|
|
# que les redirections /dev/std* ne sont pas traitées de façon particulière.
|
|
# De plus, sur des technologies telles que OpenVZ, les chemins /dev/std* ne
|
|
# sont pas créés (parce que /proc/self/fd/* n'est pas accessible). Donc,
|
|
# dans de rares cas où le script tourne sur OpenVZ avec une version de bash
|
|
# qui est buggée, la redirection n'est pas faite correctement.
|
|
local __redirs __in __out __err
|
|
if [ -n "$1" -o "$1" == /dev/stdin ]; then
|
|
if [ "${1#<}" != "$1" ]; then
|
|
__in="${1#<}"
|
|
else
|
|
__in="$1"
|
|
fi
|
|
__redirs="$__redirs"' <"$__in"'
|
|
fi; shift
|
|
if [ -n "$1" -o "$1" == /dev/stdout ]; then
|
|
if [ "${1#>>}" != "$1" ]; then
|
|
__out="${1#>>}"
|
|
__redirs="$__redirs"' >>"$__out"'
|
|
elif [ "${1#>}" != "$1" ]; then
|
|
__out="${1#>}"
|
|
__redirs="$__redirs"' >"$__out"'
|
|
else
|
|
__out="$1"
|
|
__redirs="$__redirs"' >"$__out"'
|
|
fi
|
|
fi; shift
|
|
if [ -n "$1" -o "$1" == /dev/stderr ]; then
|
|
if [ "${1#>>}" != "$1" ]; then
|
|
__err="${1#>>}"
|
|
__redirs="$__redirs"' 2>>"$__err"'
|
|
elif [ "${1#>}" != "$1" ]; then
|
|
__err="${1#>}"
|
|
__redirs="$__redirs"' 2>"$__err"'
|
|
else
|
|
__err="$1"
|
|
__redirs="$__redirs"' 2>"$__err"'
|
|
fi
|
|
fi; shift
|
|
eval '"$@"'"$__redirs"
|
|
}
|
|
|
|
function isatty() {
|
|
# tester si STDOUT n'est pas une redirection
|
|
tty -s <&1
|
|
}
|
|
|
|
function in_isatty() {
|
|
# tester si STDIN n'est pas une redirection
|
|
tty -s
|
|
}
|
|
|
|
function out_isatty() {
|
|
# tester si STDOUT n'est pas une redirection. identique à isatty()
|
|
tty -s <&1
|
|
}
|
|
|
|
function err_isatty() {
|
|
# tester si STDERR n'est pas une redirection
|
|
tty -s <&2
|
|
}
|
|
|
|
################################################################################
|
|
# affichage
|
|
|
|
function tooenc() {
|
|
# Transformer la valeur $1 de l'encoding $2(=$NULIB_OENC) vers l'encoding de sortie
|
|
# $3=($NULIB_OUTPUT_ENCODING)
|
|
local src="$1" from="${2:-$NULIB_OENC}" to="${3:-$NULIB_OUTPUT_ENCODING}"
|
|
if [ "$from" == "$to" ]; then
|
|
recho "$src"
|
|
else
|
|
iconv -f "$from" -t "$to" <<<"$src"
|
|
fi
|
|
}
|
|
|
|
function uecho() {
|
|
tooenc "$*"
|
|
}
|
|
|
|
function tooenc_() {
|
|
# Transformer la valeur $1 de l'encoding $2(=$NULIB_OENC) vers l'encoding de sortie
|
|
# $3=($NULIB_OUTPUT_ENCODING)
|
|
local src="$1" from="${2:-$NULIB_OENC}" to="${3:-$NULIB_OUTPUT_ENCODING}"
|
|
if [ "$from" == "$to" ]; then
|
|
recho_ "$src"
|
|
else
|
|
recho_ "$src" | iconv -f "$from" -t "$to"
|
|
fi
|
|
}
|
|
|
|
function uecho_() {
|
|
tooenc_ "$*"
|
|
}
|
|
|
|
function stooenc() { ### XXX
|
|
# Transformer la valeur lue sur stdin de $NULIB_OENC vers l'encoding de sortie par
|
|
# défaut ($NULIB_OUTPUT_ENCODING)
|
|
local from="${1:-$NULIB_OENC}" to="${2:-$NULIB_OUTPUT_ENCODING}"
|
|
if [ "$from" == "$to" ]; then
|
|
cat
|
|
else
|
|
iconv -f "$from" -t "$to"
|
|
fi
|
|
}
|
|
|
|
# faut-il dater les messages de etitle, estep, ebegin?
|
|
# Faire NULIB_EDATE=1 en début de script pour activer cette fonctionnalité
|
|
export NULIB_EDATE
|
|
function __edate() { [ -n "$NULIB_EDATE" ] && date +"[%d/%m/%Y-%H:%M:%S] "; }
|
|
|
|
export NULIB_ELOG_OVERWRITE
|
|
function __set_no_colors() { :; }
|
|
function elogto() {
|
|
# Activer NULIB_EDATE et rediriger STDOUT et STDERR vers le fichier $1
|
|
# Si deux fichiers sont spécifiés, rediriger STDOUT vers $1 et STDERR vers $2
|
|
# Si aucun fichier n'est spécifié, ne pas faire de redirection
|
|
# Si la redirection est activée, forcer l'utilisation de l'encoding UTF8
|
|
# Si NULIB_ELOG_OVERWRITE=1, alors le fichier en sortie est écrasé. Sinon, les
|
|
# lignes en sortie lui sont ajoutées
|
|
NULIB_EDATE=1
|
|
if [ -n "$1" -a -n "$2" ]; then
|
|
LANG=fr_FR.UTF8
|
|
NULIB_OUTPUT_ENCODING="$NULIB__UTF8"
|
|
__set_no_colors 1
|
|
if [ -n "$NULIB_ELOG_OVERWRITE" ]; then
|
|
exec >"$1" 2>"$2"
|
|
else
|
|
exec >>"$1" 2>>"$2"
|
|
fi
|
|
elif [ -n "$1" ]; then
|
|
LANG=fr_FR.UTF8
|
|
NULIB_OUTPUT_ENCODING="$NULIB__UTF8"
|
|
__set_no_colors 1
|
|
if [ -n "$NULIB_ELOG_OVERWRITE" ]; then
|
|
exec >"$1" 2>&1
|
|
else
|
|
exec >>"$1" 2>&1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# variables utilisées pour l'affichage indenté des messages et des titres
|
|
# __estack est la liste des invocations de 'ebegin' et 'etitle' en cours
|
|
# __tlevel est l'indentation à appliquer avant d'afficher le message
|
|
export __estack __tlevel
|
|
function __indent() {
|
|
# indenter les lignes de $1, sauf la première
|
|
if [ "${1/
|
|
/}" != "$1" ]; then
|
|
sed "2,\$s/^/${__tlevel}/g" <<<"$1"
|
|
else
|
|
recho "$1"
|
|
fi
|
|
}
|
|
# fonctions à surcharger pour modifier la façon dont les messages sont affichés
|
|
function __eerror() { tooenc "$(__edate)${__tlevel}ERROR $(__indent "$1")"; }
|
|
function __ewarn() { tooenc "$(__edate)${__tlevel}WARNING $(__indent "$1")"; }
|
|
function __enote() { tooenc "$(__edate)${__tlevel}NOTE $(__indent "$1")"; }
|
|
function __ebanner() {
|
|
local maxi="${COLUMNS:-80}"
|
|
local -a lines
|
|
local psfix line
|
|
|
|
psfix="$(__edate)${__tlevel}"
|
|
while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done
|
|
|
|
tooenc "$psfix"
|
|
maxi=$(($maxi - 1))
|
|
base_array_xsplitl lines "$1"
|
|
for line in "" "${lines[@]}" ""; do
|
|
line="$(__edate)${__tlevel}= $line"
|
|
if [ ${#line} -le $maxi ]; then
|
|
while [ ${#line} -lt $maxi ]; do line="$line "; done
|
|
line="$line="
|
|
fi
|
|
tooenc "$line"
|
|
done
|
|
tooenc "$psfix"
|
|
}
|
|
function __eimportant() { tooenc "$(__edate)${__tlevel}IMPORTANT $(__indent "$1")"; }
|
|
function __eattention() { tooenc "$(__edate)${__tlevel}ATTENTION $(__indent "$1")"; }
|
|
function __einfo() { tooenc "$(__edate)${__tlevel}INFO $(__indent "$1")"; }
|
|
function __eecho() { tooenc "$(__edate)${__tlevel}$(__indent "$1")"; }
|
|
function __eecho_() { tooenc_ "$(__edate)${__tlevel}$(__indent "$1")"; }
|
|
function __edebug() { tooenc "$(__edate)${__tlevel}DEBUG $(__indent "$1")"; }
|
|
function __estep() { tooenc "$(__edate)${__tlevel}. $(__indent "$1")"; }
|
|
function __estepe() { tooenc "$(__edate)${__tlevel}.E $(__indent "$1")"; }
|
|
function __estepw() { tooenc "$(__edate)${__tlevel}.W $(__indent "$1")"; }
|
|
function __estepn() { tooenc "$(__edate)${__tlevel}.N $(__indent "$1")"; }
|
|
function __estepi() { tooenc "$(__edate)${__tlevel}.I $(__indent "$1")"; }
|
|
function __estep_() { tooenc_ "$(__edate)${__tlevel}. $(__indent "$1")"; }
|
|
function __estepe_() { tooenc_ "$(__edate)${__tlevel}.E $(__indent "$1")"; }
|
|
function __estepw_() { tooenc_ "$(__edate)${__tlevel}.W $(__indent "$1")"; }
|
|
function __estepn_() { tooenc_ "$(__edate)${__tlevel}.N $(__indent "$1")"; }
|
|
function __estepi_() { tooenc_ "$(__edate)${__tlevel}.I $(__indent "$1")"; }
|
|
function __etitle() { tooenc "$(__edate)${__tlevel}=== $(__indent "$1")"; }
|
|
function __ebegin() { tooenc_ "$(__edate)${__tlevel}. $(__indent "$1"): "; }
|
|
function __edoto() { echo_ "."; }
|
|
function __edotw() { echo_ "w"; }
|
|
function __edotx() { echo_ "x"; }
|
|
function __edotp() { echo_ "+"; }
|
|
function __edotd() { tooenc "($1)"; }
|
|
function __eendo() { echo "[ok]"; }
|
|
function __eendx() { echo "[error]"; }
|
|
PRETTYOPTS=()
|
|
function set_verbosity() { :;}
|
|
function set_interaction() { :;}
|
|
function show_error() {
|
|
# tester respectivement si on doit afficher les messages d'erreur,
|
|
# d'avertissement, d'information, de debug
|
|
return 0
|
|
}
|
|
function show_warn() {
|
|
return 0
|
|
}
|
|
function show_info() {
|
|
return 0
|
|
}
|
|
function show_verbose() {
|
|
return 0
|
|
}
|
|
function show_debug() {
|
|
[ -n "$DEBUG" ]
|
|
}
|
|
function check_verbosity() {
|
|
return 0
|
|
}
|
|
function get_verbosity_option() { :;}
|
|
function check_interaction() {
|
|
return 0
|
|
}
|
|
|
|
# note: toutes les fonctions d'affichage e* écrivent sur stderr
|
|
__epending=
|
|
function eflush() {
|
|
# Afficher les messages en attente
|
|
if [ -n "$__epending" ]; then recho "$__epending" 1>&2; __epending=; fi
|
|
}
|
|
function eclearp() {
|
|
# Supprimer les message en attente
|
|
__epending=
|
|
}
|
|
function eerror() {
|
|
# Afficher un message d'erreur
|
|
show_error || return; eflush; __eerror "$*" 1>&2
|
|
}
|
|
|
|
function die() {
|
|
[ $# -gt 0 ] && base_eerror "$@"
|
|
exit 1
|
|
}
|
|
|
|
function exit_with {
|
|
if [ $# -gt 0 ]; then "$@"; fi
|
|
exit $?
|
|
}
|
|
|
|
function die_with {
|
|
[ $# -gt 0 ] && base_eerror "$1"
|
|
shift
|
|
[ $# -gt 0 ] && "$@"
|
|
exit 1
|
|
}
|
|
|
|
function die_unless() {
|
|
# Afficher $1 et quitter le script avec die() si la commande $2..@ retourne FAUX
|
|
local du__r
|
|
local du__msg="$1"; shift
|
|
if [ $# -eq 0 ]; then
|
|
[ -n "$du__msg" ] && base__eerror "$du__msg"
|
|
exit 1
|
|
elif "$@"; then
|
|
:
|
|
else
|
|
du__r=$?
|
|
[ -n "$du__msg" ] && base__eerror "$du__msg"
|
|
exit $du__r
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
function eerror_unless() {
|
|
# Afficher $1 avec base_eerror() si la commande $2..@ retourne FAUX. dans tous les cas, retourner le code de retour de la commande.
|
|
local eu__r
|
|
local eu__msg="$1"; shift
|
|
if [ $# -eq 0 ]; then
|
|
[ -n "$eu__msg" ] && base__eerror "$eu__msg"
|
|
return 1
|
|
elif "$@"; then
|
|
:
|
|
else
|
|
eu__r=$?
|
|
[ -n "$eu__msg" ] && base__eerror "$eu__msg"
|
|
return $eu__r
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
function die_if() {
|
|
# Afficher $1 et quitter le script avec die() si la commande $2..@ retourne VRAI. sinon, retourner le code de retour de la commande
|
|
local di__r=0
|
|
local di__msg="$1"; shift
|
|
[ $# -eq 0 ] && return 0
|
|
if "$@"; then
|
|
[ -n "$di__msg" ] && base__eerror "$di__msg"
|
|
exit 0
|
|
else
|
|
di__r=$?
|
|
fi
|
|
return $di__r
|
|
}
|
|
|
|
function eerror_if() {
|
|
# Afficher $1 avec base_eerror() si la commande $2..@ retourne VRAI. dans tous les cas, retourner le code de retour de la commande.
|
|
local ei__r=0
|
|
local ei__msg="$1"; shift
|
|
[ $# -eq 0 ] && return 0
|
|
if "$@"; then
|
|
[ -n "$ei__msg" ] && base__eerror "$ei__msg"
|
|
else
|
|
ei__r=$?
|
|
fi
|
|
return $ei__r
|
|
}
|
|
|
|
function ewarn() {
|
|
# Afficher un message d'avertissement
|
|
show_warn || return; eflush; __ewarn "$*" 1>&2
|
|
}
|
|
function enote() {
|
|
# Afficher un message d'information de même niveau qu'un avertissement
|
|
show_info || return; eflush; __enote "$*" 1>&2
|
|
}
|
|
function ebanner() {
|
|
# Afficher un message très important encadré, puis attendre 5 secondes
|
|
show_error || return; eflush; __ebanner "$*" 1>&2; sleep 5
|
|
}
|
|
function eimportant() {
|
|
# Afficher un message très important
|
|
show_error || return; eflush; __eimportant "$*" 1>&2
|
|
}
|
|
function eattention() {
|
|
# Afficher un message important
|
|
show_warn || return; eflush; __eattention "$*" 1>&2
|
|
}
|
|
function einfo() {
|
|
# Afficher un message d'information
|
|
show_info || return; eflush; __einfo "$*" 1>&2
|
|
}
|
|
function eecho() {
|
|
# Afficher un message d'information sans préfixe
|
|
show_info || return; eflush; __eecho "$*" 1>&2
|
|
}
|
|
function eecho_() {
|
|
show_info || return; eflush; __eecho_ "$*" 1>&2
|
|
}
|
|
function edebug() {
|
|
# Afficher un message de debug
|
|
show_debug || return; eflush; __edebug "$*" 1>&2
|
|
}
|
|
function trace() {
|
|
# Afficher la commande $1..@, la lancer, puis afficher son code d'erreur si une
|
|
# erreur se produit
|
|
local r cmd="$(qvals "$@")"
|
|
show_info && { eflush; __eecho "\$ $cmd" 1>&2; }
|
|
"$@"; r=$?
|
|
if [ $r -ne 0 ]; then
|
|
if show_info; then
|
|
eflush; __eecho "^ [EC #$r]" 1>&2
|
|
elif show_error; then
|
|
eflush; __eecho "^ $cmd [EC #$r]" 1>&2;
|
|
fi
|
|
fi
|
|
return $r
|
|
}
|
|
function trace_error() {
|
|
# Lancer la commande $1..@, puis afficher son code d'erreur si une erreur se
|
|
# produit. La différence avec trace() est que la commande n'est affichée que si
|
|
# une erreur se produit.
|
|
local r
|
|
"$@"; r=$?
|
|
if [ $r -ne 0 ]; then
|
|
local cmd="$(qvals "$@")"
|
|
show_error && { eflush; __eecho "^ $cmd [EC #$r]" 1>&2; }
|
|
fi
|
|
return $r
|
|
}
|
|
|
|
function etitle() {
|
|
# Afficher le titre $1, qui est le début éventuel d'une section. Les section
|
|
# imbriquées sont affichées indentées. La section n'est pas terminée, et il faut
|
|
# la terminer explicitement avec eend, sauf dans certains cas précis:
|
|
# - Si $2..$* est spécifié, c'est une commande. Lancer la commande dans le
|
|
# contexte de la section. Puis, la section est automatiquement terminée sauf si
|
|
# l'option -s est spécifiée, auquel cas la section reste ouverte. Si l'option -p
|
|
# est spécifiée, eclearp() est appelé pour purger les messages en attente
|
|
# - Dans le cas contraire, l'option -s est ignorée: la section doit toujours
|
|
# être terminée explicitement.
|
|
# La fonction etitled() est comme etitle(), mais le titre n'est pas affiché
|
|
# immédiatement. L'affichage effectif est effectué dès qu'une fonction e* est
|
|
# utilisée. Ceci permet, avec la fonction eclearp(), de ne pas afficher de titre
|
|
# pour une section vide.
|
|
local __t_deferred=
|
|
__t_etitle "$@"
|
|
}
|
|
function etitled() {
|
|
local __t_deferred=1
|
|
__t_etitle "$@"
|
|
}
|
|
function __t_etitle() {
|
|
local __t_eend=default
|
|
local __t_clearp=
|
|
while [ -n "$1" ]; do
|
|
if [ "$1" == "--" ]; then
|
|
shift
|
|
break
|
|
elif [ "$1" == "-s" ]; then
|
|
__t_eend=
|
|
shift
|
|
elif [ "$1" == "--eend" ]; then
|
|
__t_eend=1
|
|
shift
|
|
elif [ "$1" == "-p" ]; then
|
|
__t_clearp=1
|
|
shift
|
|
else
|
|
break
|
|
fi
|
|
done
|
|
local __t_title="$1"; shift
|
|
local __t_s=0
|
|
# etitle
|
|
[ -n "$__estack" ] && __tlevel="${__tlevel} "
|
|
__estack="$__estack:t"
|
|
if show_info; then
|
|
if [ -n "$__t_deferred" ]; then
|
|
__epending="${__epending:+$__epending
|
|
}$(__etitle "$__t_title")"
|
|
else
|
|
eflush
|
|
__etitle "$__t_title" 1>&2
|
|
fi
|
|
fi
|
|
# commande
|
|
if [ $# -gt 0 ]; then
|
|
"$@"
|
|
__t_s=$?
|
|
[ "$__t_eend" == "default" ] && __t_eend=1
|
|
fi
|
|
# eend
|
|
[ "$__t_eend" == "default" ] && __t_eend=
|
|
if [ -n "$__t_eend" ]; then
|
|
eend $__t_s
|
|
[ -n "$__t_clearp" ] && eclearp
|
|
fi
|
|
return $__t_s
|
|
}
|
|
function estep() {
|
|
# Afficher la description d'une opération. Cette fonction est particulièrement
|
|
# appropriée dans le contexte d'un etitle.
|
|
# Les variantes e (error), w (warning), n (note), i (info) permettent d'afficher
|
|
# des couleurs différentes, mais toutes sont du niveau info.
|
|
show_info || return; eflush; __estep "$*" 1>&2
|
|
}
|
|
function estepe() {
|
|
show_info || return; eflush; __estepe "$*" 1>&2
|
|
}
|
|
function estepw() {
|
|
show_info || return; eflush; __estepw "$*" 1>&2
|
|
}
|
|
function estepn() {
|
|
show_info || return; eflush; __estepn "$*" 1>&2
|
|
}
|
|
function estepi() {
|
|
show_info || return; eflush; __estepi "$*" 1>&2
|
|
}
|
|
function estep_() {
|
|
show_info || return; eflush; __estep_ "$*" 1>&2
|
|
}
|
|
function estepe_() {
|
|
show_info || return; eflush; __estepe_ "$*" 1>&2
|
|
}
|
|
function estepw_() {
|
|
show_info || return; eflush; __estepw_ "$*" 1>&2
|
|
}
|
|
function estepn_() {
|
|
show_info || return; eflush; __estepn_ "$*" 1>&2
|
|
}
|
|
function estepi_() {
|
|
show_info || return; eflush; __estepi_ "$*" 1>&2
|
|
}
|
|
function ebegin() {
|
|
# Afficher le message $1, qui décrit le début d'une opération. Cette fonction
|
|
# débute une section, qu'il faut terminer avec eend.
|
|
# Si $2..$* est spécifié, c'est une commande. Lancer la commande dans le
|
|
# contexte de la section. Puis, la section est terminée automatiquement, sauf si
|
|
# l'option -s est spécifiée, auquel cas la section reste ouverte.
|
|
local __b_eend=default
|
|
while [ -n "$1" ]; do
|
|
if [ "$1" == "--" ]; then
|
|
shift
|
|
break
|
|
elif [ "$1" == "-s" ]; then
|
|
__b_eend=
|
|
shift
|
|
elif [ "$1" == "--eend" ]; then
|
|
__b_eend=1
|
|
shift
|
|
else
|
|
break
|
|
fi
|
|
done
|
|
local __b_msg="$1"; shift
|
|
local __b_s=0
|
|
# ebegin
|
|
__estack="$__estack:b"
|
|
if show_info; then
|
|
eflush
|
|
__ebegin "$__b_msg" 1>&2
|
|
fi
|
|
# commande
|
|
if [ $# -gt 0 ]; then
|
|
"$@"
|
|
__b_s=$?
|
|
[ "$__b_eend" == "default" ] && __b_eend=1
|
|
fi
|
|
# eend
|
|
[ "$__b_eend" == "default" ] && __b_eend=
|
|
[ -n "$__b_eend" ] && eend $__b_s
|
|
return $__b_s
|
|
}
|
|
function edot() {
|
|
# Afficher une étape d'une opération, matérialisée par un point '.' ou une
|
|
# croix 'x' en cas de succès ou d'erreur. Cette fonction est particulièrement
|
|
# appropriée dans le contexte d'un ebegin.
|
|
local s=$?
|
|
show_info || return
|
|
eflush
|
|
[ -n "$1" ] && s="$1"
|
|
shift
|
|
if [ "$s" == "0" ]; then
|
|
__edoto 1>&2
|
|
else
|
|
__edotx 1>&2
|
|
fi
|
|
show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
|
|
return $s
|
|
}
|
|
function edotw() {
|
|
# Afficher un avertissement comme étape d'une opération, matérialisée par une
|
|
# lettre 'w' (typiquement de couleur jaune). Cette fonction est particulièrement
|
|
# appropriée dans le contexte d'un ebegin.
|
|
local s=$?
|
|
show_info || return
|
|
eflush
|
|
[ -n "$1" ] && s="$1"
|
|
shift
|
|
__edotw 1>&2
|
|
show_verbose && [ $# -gt 0 ] && __edotd "$*" 1>&2
|
|
return $s
|
|
}
|
|
function ewait() {
|
|
# Afficher les étapes d'une opération qui dure, matérialisées par des '+' toutes
|
|
# les secondes tant que le processus $1 tourne.
|
|
# A utiliser de cette manière:
|
|
# ebegin "msg"
|
|
# cmd &
|
|
# ewait $!
|
|
# eend
|
|
[ -n "$1" ] || return 1
|
|
if show_info; then
|
|
local count=2
|
|
eflush
|
|
little_sleep # certains processus retournent tout de suite
|
|
while is_running "$1"; do
|
|
sleep 1
|
|
if [ $count -gt 0 ]; then
|
|
# attendre 2 secondes avant de commencer à afficher des '+'
|
|
count=$(($count - 1))
|
|
else
|
|
__edotp 1>&2
|
|
fi
|
|
done
|
|
# terminer par un '.'
|
|
__edoto 1>&2
|
|
else
|
|
# ne rien afficher, mais attendre quand même la fin de l'opération
|
|
wait "$1"
|
|
fi
|
|
}
|
|
function eend() {
|
|
# Terminer une section.
|
|
# Avec l'option -c, remettre à zéro toutes les informations de section
|
|
# Si la section en cours est un ebegin, afficher la fin de l'opération: [ok] ou
|
|
# [error] en fonction du code de retour de la dernière commande (ou de $1 si
|
|
# cette valeur est donnée)
|
|
# Si la section en cours est un etitle, marquer la fin de la section concernée
|
|
# par le titre.
|
|
local s=$?
|
|
if [ "$1" == "-c" ]; then
|
|
__estack=
|
|
__tlevel=
|
|
elif [ "${__estack%:b}" != "$__estack" ]; then
|
|
# terminer ebegin
|
|
__estack="${__estack%:b}"
|
|
show_info || return
|
|
eflush
|
|
[ -n "$1" ] && s="$1"
|
|
if [ "$s" == "0" ]; then
|
|
__eendo 1>&2
|
|
else
|
|
__eendx 1>&2
|
|
fi
|
|
elif [ "${__estack%:t}" != "$__estack" ]; then
|
|
# terminer etitle -s
|
|
__estack="${__estack%:t}"
|
|
__tlevel="${__tlevel% }"
|
|
fi
|
|
}
|
|
function __elinedots() {
|
|
ebegin "$1"
|
|
local line
|
|
if show_debug; then
|
|
while read line; do
|
|
__edoto 1>&2
|
|
__edotd "$line" 1>&2
|
|
done
|
|
else
|
|
while read line; do
|
|
__edoto 1>&2
|
|
done
|
|
fi
|
|
eend
|
|
}
|
|
function elinedots() {
|
|
# Afficher un message comme avec ebegin "$1", puis afficher un point '.' pour
|
|
# chaque ligne lue sur stdin. Cela permet de suivre une opération. En mode
|
|
# DEBUG, afficher la ligne affichée plutôt qu'un point.
|
|
# Si $2..$* sont spécifiés, lancer la commande et suivre sa sortie. Ainsi,
|
|
# 'elinedots msg cmd args' est un raccourci pour 'cmd args | elinedots msg'
|
|
local msg="$1"; shift
|
|
if [ $# -gt 0 ]; then
|
|
"$@" | __elinedots "$msg"
|
|
else
|
|
__elinedots "$msg"
|
|
fi
|
|
}
|
|
|
|
################################################################################
|
|
# saisie
|
|
|
|
function toienc() {
|
|
# Transformer la valeur de la variable $1 de l'encoding d'entrée
|
|
# $3(=$NULIB_INPUT_ENCODING) vers l'encoding $2(=$NULIB_IENC)
|
|
local __tie_var="$1" __tie_to="${2:-$NULIB_IENC}" __tie_from="${3:-$NULIB_INPUT_ENCODING}"
|
|
if [ "$__tie_from" != "$__tie_to" ]; then
|
|
_setv "$__tie_var" "$(iconv -f "$__tie_from" -t "$__tie_to" <<<"${!__tie_var}")"
|
|
fi
|
|
}
|
|
|
|
function uread() {
|
|
# Lire une valeur sur stdin et la placer dans la variable $1. On assume que la
|
|
# valeur en entrée est encodée dans l'encoding d'entrée par défaut
|
|
[ $# -gt 0 ] || set -- REPLY
|
|
local __r_var
|
|
read "$@"
|
|
for __r_var in "$@"; do
|
|
[ -z "$__r_var" -o "${__r_var:0:1}" == "-" ] && continue # ignorer les options
|
|
toienc "$__r_var"
|
|
done
|
|
}
|
|
|
|
function stoienc() { ### XXX
|
|
# Transformer la valeur lue sur stdin de $NULIB_IENC vers l'encoding d'entrée par
|
|
# défaut ($NULIB_INPUT_ENCODING)
|
|
local to="${1:-$NULIB_IENC}" from="${2:-$NULIB_INPUT_ENCODING}"
|
|
if [ "$from" == "$to" ]; then
|
|
cat
|
|
else
|
|
iconv -f "$from" -t "$to"
|
|
fi
|
|
}
|
|
|
|
|
|
|
|
function is_interaction() {
|
|
return 1
|
|
}
|
|
|
|
function get_interaction_option() { :;}
|
|
|
|
function ask_yesno() {
|
|
# Afficher le message $1 suivi de [oN] ou [On] suivant que $2 vaut O ou N, puis
|
|
# lire la réponse. Retourner 0 si la réponse est vrai, 1 sinon.
|
|
# Si $1 est une option, elle est utilisée avec check_interaction pour savoir si
|
|
# on est en mode interactif ou non. A ce moment-là, les valeurs sont décalées
|
|
# ($2=message, $3=default)
|
|
# Si $2 vaut C, la valeur par défaut est N si on est interactif, O sinon
|
|
# Si $2 vaut X, la valeur par défaut est O si on est interactif, N sinon
|
|
local interactive=1
|
|
if [[ "$1" == -* ]]; then
|
|
if [ "$1" != -- ]; then
|
|
check_interaction "$1" || interactive=
|
|
fi
|
|
shift
|
|
else
|
|
check_interaction -c || interactive=
|
|
fi
|
|
local default="${2:-N}"
|
|
if [ "$default" == "C" ]; then
|
|
[ -n "$interactive" ] && default=N || default=O
|
|
elif [ "$default" == "X" ]; then
|
|
[ -n "$interactive" ] && default=O || default=N
|
|
fi
|
|
if [ -n "$interactive" ]; then
|
|
eflush
|
|
local message="$1"
|
|
local prompt="[oN]"
|
|
local r
|
|
is_yes "$default" && prompt="[On]"
|
|
if [ -n "$message" ]; then
|
|
__eecho_ "$message" 1>&2
|
|
else
|
|
NULIB_OENC="$NULIB__UTF8" __eecho_ "Voulez-vous continuer?" 1>&2
|
|
fi
|
|
NULIB_OENC="$NULIB__UTF8" tooenc_ " $prompt " 1>&2
|
|
uread r
|
|
is_yes "${r:-$default}"
|
|
else
|
|
is_yes "$default"
|
|
fi
|
|
}
|
|
|
|
function ask_any() {
|
|
# Afficher le message $1 suivi du texte "[$2]" (qui vaut par défaut +Oq), puis
|
|
# lire la réponse. Les lettres de la chaine de format $2 sont numérotées de 0 à
|
|
# $((${#2} - 1)). Le code de retour est le numéro de la lettre qui a été
|
|
# sélectionnée. Cette fonction est une généralisation de ask_yesno() pour
|
|
# n'importe quel ensemble de lettres.
|
|
# La première lettre en majuscule est la lettre sélectionnée par défaut.
|
|
# La lettre O matche toutes les lettres qui signifient oui: o, y, 1, v, t
|
|
# La lettre N matche toutes les lettres qui signifient non: n, f, 0
|
|
# Il y a des raccourcis:
|
|
# +O --> On
|
|
# +N --> oN
|
|
# +C --> oN si on est en mode interactif, On sinon
|
|
# +X --> On si on est en mode interactifn oN sinon
|
|
# Si $1 est une option, elle est utilisée avec check_interaction pour savoir si
|
|
# on est en mode interactif ou non. A ce moment-là, les valeurs sont décalées
|
|
# ($2=message, $3=format)
|
|
local interactive=1
|
|
if [[ "$1" == -* ]]; then
|
|
if [ "$1" != -- ]; then
|
|
check_interaction "$1" || interactive=
|
|
fi
|
|
shift
|
|
else
|
|
check_interaction -c || interactive=
|
|
fi
|
|
local format="${2:-+Oq}"
|
|
format="${format/+O/On}"
|
|
format="${format/+N/oN}"
|
|
if [ -n "$interactive" ]; then
|
|
format="${format/+C/oN}"
|
|
format="${format/+X/On}"
|
|
else
|
|
format="${format/+C/On}"
|
|
format="${format/+X/oN}"
|
|
fi
|
|
local i count="${#format}"
|
|
|
|
if [ -n "$interactive" ]; then
|
|
eflush
|
|
local message="${1:-Voulez-vous continuer?}"
|
|
local prompt="[$format]"
|
|
local r f lf defi
|
|
while true; do
|
|
__eecho_ "$message $prompt " 1>&2
|
|
uread r
|
|
r="$(strlower "${r:0:1}")"
|
|
i=0; defi=
|
|
while [ $i -lt $count ]; do
|
|
f="${format:$i:1}"
|
|
lf="$(strlower "$f")"
|
|
[ "$r" == "$lf" ] && return $i
|
|
if [ -z "$defi" ]; then
|
|
[ -z "${f/[A-Z]/}" ] && defi="$i"
|
|
fi
|
|
if [ "$lf" == o ]; then
|
|
case "$r" in o|y|1|v|t) return $i;; esac
|
|
elif [ "$lf" == n ]; then
|
|
case "$r" in n|f|0) return $i;; esac
|
|
fi
|
|
i=$(($i + 1))
|
|
done
|
|
[ -z "$r" ] && return ${defi:-0}
|
|
done
|
|
else
|
|
i=0
|
|
while [ $i -lt $count ]; do
|
|
f="${format:$i:1}"
|
|
[ -z "${f/[A-Z]/}" ] && return $i
|
|
i=$(($i + 1))
|
|
done
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
function read_value() {
|
|
# Afficher le message $1 suivi de la valeur par défaut [$3] si elle est non
|
|
# vide, puis lire la valeur donnée par l'utilisateur. Cette valeur doit être non
|
|
# vide si $4(=O) est vrai. La valeur saisie est placée dans la variable
|
|
# $2(=value)
|
|
# Si $1 est une option, elle est utilisée avec check_interaction pour savoir si
|
|
# on est en mode interactif ou non. A ce moment-là, les valeurs sont décalées
|
|
# ($2=message, $3=variable, $4=default, $5=required)
|
|
# En mode non interactif, c'est la valeur par défaut qui est sélectionnée. Si
|
|
# l'utilisateur requière que la valeur soit non vide et que la valeur par défaut
|
|
# est vide, afficher un message d'erreur et retourner faux
|
|
# read_password() est comme read_value(), mais la valeur saisie n'est pas
|
|
# affichée, ce qui la rend appropriée pour la lecture d'un mot de passe.
|
|
local -a __rv_opts __rv_readline=1 __rv_showdef=1 __rv_nl=
|
|
__rv_opts=()
|
|
[ -n "$NULIB_NO_READLINE" ] && __rv_readline=
|
|
__rv_read "$@"
|
|
}
|
|
|
|
function read_password() {
|
|
local -a __rv_opts __rv_readline= __rv_showdef= __rv_nl=1
|
|
__rv_opts=(-s)
|
|
__rv_read "$@"
|
|
}
|
|
|
|
function __rv_read() {
|
|
local __rv_int=1
|
|
if [[ "$1" == -* ]]; then
|
|
if [ "$1" != -- ]; then
|
|
check_interaction "$1" || __rv_int=
|
|
fi
|
|
shift
|
|
else
|
|
check_interaction -c || __rv_int=
|
|
fi
|
|
local __rv_msg="$1" __rv_v="${2:-value}" __rv_d="$3" __rv_re="${4:-O}"
|
|
if [ -z "$__rv_int" ]; then
|
|
# En mode non interactif, retourner la valeur par défaut
|
|
if is_yes "$__rv_re" && [ -z "$__rv_d" ]; then
|
|
NULIB_OENC="$NULIB__UTF8" eerror "La valeur par défaut de $__rv_v doit être non vide"
|
|
return 1
|
|
fi
|
|
_setv "$__rv_v" "$__rv_d"
|
|
return 0
|
|
fi
|
|
|
|
eflush
|
|
local __rv_r
|
|
while true; do
|
|
if [ -n "$__rv_msg" ]; then
|
|
__eecho_ "$__rv_msg" 1>&2
|
|
else
|
|
NULIB_OENC="$NULIB__UTF8" __eecho_ "Entrez la valeur" 1>&2
|
|
fi
|
|
if [ -n "$__rv_readline" ]; then
|
|
NULIB_OENC="$NULIB__UTF8" tooenc_ ": " 1>&2
|
|
uread -e ${__rv_d:+-i"$__rv_d"} "${__rv_opts[@]}" __rv_r
|
|
else
|
|
if [ -n "$__rv_d" ]; then
|
|
if [ -n "$__rv_showdef" ]; then
|
|
tooenc_ " [$__rv_d]" 1>&2
|
|
else
|
|
tooenc_ " [****]" 1>&2
|
|
fi
|
|
fi
|
|
NULIB_OENC="$NULIB__UTF8" tooenc_ ": " 1>&2
|
|
uread "${__rv_opts[@]}" __rv_r
|
|
[ -n "$__rv_nl" ] && echo
|
|
fi
|
|
__rv_r="${__rv_r:-$__rv_d}"
|
|
if [ -n "$__rv_r" ] || ! is_yes "$__rv_re"; then
|
|
_setv "$__rv_v" "$__rv_r"
|
|
return 0
|
|
fi
|
|
done
|
|
}
|
|
|
|
function simple_menu() {
|
|
# Afficher un menu simple dont les éléments sont les valeurs du tableau
|
|
# $2(=options). L'option choisie est placée dans la variable $1(=option)
|
|
# -t TITLE: spécifier le titre du menu
|
|
# -m YOUR_CHOICE: spécifier le message d'invite pour la sélection de l'option
|
|
# -d DEFAULT: spécifier l'option par défaut. Par défaut, prendre la valeur
|
|
# actuelle de la variable $1(=option)
|
|
local __sm_title= __sm_yourchoice= __sm_default=
|
|
local -a __sm_args
|
|
parse_opts -t: __sm_title= -m: __sm_yourchoice= -d: __sm_default= @ __sm_args -- "$@" &&
|
|
set -- "${__sm_args[@]}" || ewarn "$__sm_args"
|
|
|
|
local __sm_option_var="${1:-option}" __sm_options_var="${2:-options}"
|
|
local __sm_option __sm_options
|
|
__sm_options="$__sm_options_var[*]"
|
|
if [ -z "${!__sm_options}" ]; then
|
|
NULIB_OENC="$NULIB__UTF8" eerror "Le tableau $__sm_options_var doit être non vide"
|
|
return 1
|
|
fi
|
|
[ -z "$__sm_default" ] && __sm_default="${!__sm_option_var}"
|
|
|
|
eflush
|
|
base_array_copy __sm_options "$__sm_options_var"
|
|
local __sm_c=0 __sm_i __sm_choice
|
|
while true; do
|
|
if [ "$__sm_c" == "0" ]; then
|
|
# Afficher le menu
|
|
[ -n "$__sm_title" ] && __eecho "=== $__sm_title ===" 1>&2
|
|
__sm_i=1
|
|
for __sm_option in "${__sm_options[@]}"; do
|
|
if [ "$__sm_option" == "$__sm_default" ]; then
|
|
__eecho "$__sm_i*- $__sm_option" 1>&2
|
|
else
|
|
__eecho "$__sm_i - $__sm_option" 1>&2
|
|
fi
|
|
let __sm_i=$__sm_i+1
|
|
done
|
|
fi
|
|
|
|
# Afficher les choix
|
|
if [ -n "$__sm_yourchoice" ]; then
|
|
__eecho_ "$__sm_yourchoice" 1>&2
|
|
else
|
|
NULIB_OENC="$NULIB__UTF8" __eecho_ "Entrez le numéro de l'option choisie" 1>&2
|
|
fi
|
|
NULIB_OENC="$NULIB__UTF8" tooenc_ ": " 1>&2
|
|
uread __sm_choice
|
|
|
|
# Valeur par défaut
|
|
if [ -z "$__sm_choice" -a -n "$__sm_default" ]; then
|
|
__sm_option="$__sm_default"
|
|
break
|
|
fi
|
|
# Vérifier la saisie
|
|
if [ -n "$__sm_choice" -a -z "${__sm_choice//[0-9]/}" ]; then
|
|
if [ "$__sm_choice" -gt 0 -a "$__sm_choice" -le "${#__sm_options[*]}" ]; then
|
|
__sm_option="${__sm_options[$(($__sm_choice - 1))]}"
|
|
break
|
|
else
|
|
NULIB_OENC="$NULIB__UTF8" eerror "Numéro d'option incorrect"
|
|
fi
|
|
else
|
|
NULIB_OENC="$NULIB__UTF8" eerror "Vous devez saisir le numéro de l'option choisie"
|
|
fi
|
|
|
|
let __sm_c=$__sm_c+1
|
|
if [ "$__sm_c" -eq 5 ]; then
|
|
# sauter une ligne toutes les 4 tentatives
|
|
NULIB_OENC="$NULIB__UTF8" tooenc "" 1>&2
|
|
__sm_c=0
|
|
fi
|
|
done
|
|
_setv "$__sm_option_var" "$__sm_option"
|
|
}
|
|
|
|
function actions_menu() {
|
|
# Afficher un menu dont les éléments sont les valeurs du tableau $4(=options),
|
|
# et une liste d'actions tirées du tableau $3(=actions). L'option choisie est
|
|
# placée dans la variable $2(=option). L'action choisie est placée dans la
|
|
# variable $1(=action)
|
|
# Un choix est saisi sous la forme [action]num_option
|
|
# -t TITLE: spécifier le titre du menu
|
|
# -m OPT_YOUR_CHOICE: spécifier le message d'invite pour la sélection de
|
|
# l'action et de l'option
|
|
# -M ACT_YOUR_CHOICE: spécifier le message d'invite dans le cas où aucune option
|
|
# n'est disponible. Dans ce cas, seules les actions vides sont possibles.
|
|
# -e VOID_ACTION: spécifier qu'une action est vide, c'est à dire qu'elle ne
|
|
# requière pas d'être associée à une option. Par défaut, la dernière action
|
|
# est classée dans cette catégorie puisque c'est l'action "quitter"
|
|
# -d DEFAULT_ACTION: choisir l'action par défaut. par défaut, c'est la première
|
|
# action.
|
|
# -q QUIT_ACTION: choisir l'option "quitter" qui provoque la sortie du menu sans
|
|
# choix. par défaut, c'est la dernière action.
|
|
# -o DEFAULT_OPTION: choisir l'option par défaut. par défaut, prendre la valeur
|
|
# actuelle de la variable $2(=option)
|
|
local -a __am_action_descs __am_options __am_void_actions
|
|
local __am_tmp __am_select_action __am_select_option __am_title __am_optyc __am_actyc
|
|
local __am_default_action=auto __am_quit_action=auto
|
|
local __am_default_option=
|
|
local -a __am_args
|
|
parse_opts \
|
|
-t: __am_title= \
|
|
-m: __am_optyc= \
|
|
-M: __am_actyc= \
|
|
-e: __am_void_actions \
|
|
-d: __am_default_action= \
|
|
-q: __am_quit_action= \
|
|
-o: __am_default_option= \
|
|
@ __am_args -- "$@" && set -- "${__am_args[@]}" || { eerror "$__am_args"; return 1; }
|
|
|
|
__am_tmp="${1:-action}"; __am_select_action="${!__am_tmp}"
|
|
__am_tmp="${2:-option}"; __am_select_option="${!__am_tmp}"
|
|
[ -n "$__am_default_option" ] && __am_select_option="$__am_default_option"
|
|
base_array_copy __am_action_descs "${3:-actions}"
|
|
base_array_copy __am_options "${4:-options}"
|
|
|
|
eerror_unless [ ${#__am_action_descs[*]} -gt 0 ] "Vous devez spécifier le tableau des actions" || return
|
|
__actions_menu || return 1
|
|
_setv "${1:-action}" "$__am_select_action"
|
|
_setv "${2:-option}" "$__am_select_option"
|
|
}
|
|
|
|
function __actions_menu() {
|
|
local title="$__am_title"
|
|
local optyc="$__am_optyc" actyc="$__am_actyc"
|
|
local default_action="$__am_default_action"
|
|
local quit_action="$__am_quit_action"
|
|
local select_action="$__am_select_action"
|
|
local select_option="$__am_select_option"
|
|
local -a action_descs options void_actions
|
|
base_array_copy action_descs __am_action_descs
|
|
base_array_copy options __am_options
|
|
base_array_copy void_actions __am_void_actions
|
|
|
|
# Calculer la liste des actions valides
|
|
local no_options
|
|
base_array_isempty options && no_options=1
|
|
|
|
local -a actions
|
|
local tmp action name
|
|
for tmp in "${action_descs[@]}"; do
|
|
splitfsep2 "$tmp" : action name
|
|
[ -n "$action" ] || action="${name:0:1}"
|
|
action="$(strlower "$action")"
|
|
base_array_addu actions "$action"
|
|
done
|
|
|
|
# Calculer l'action par défaut
|
|
if [ "$default_action" == auto ]; then
|
|
# si action par défaut non spécifiée, alors prendre la première action
|
|
default_action="$select_action"
|
|
if [ -n "$default_action" ]; then
|
|
base_array_contains actions "$default_action" || default_action=
|
|
fi
|
|
[ -n "$default_action" ] || default_action="${actions[0]}"
|
|
fi
|
|
default_action="${default_action:0:1}"
|
|
default_action="$(strlower "$default_action")"
|
|
|
|
# Calculer l'action quitter par défaut
|
|
if [ "$quit_action" == auto ]; then
|
|
# si action par défaut non spécifiée, alors prendre la dernière action,
|
|
# s'il y a au moins 2 actions
|
|
if [ ${#actions[*]} -gt 1 ]; then
|
|
quit_action="${actions[@]:$((-1)):1}"
|
|
base_array_addu void_actions "$quit_action"
|
|
fi
|
|
fi
|
|
quit_action="${quit_action:0:1}"
|
|
quit_action="$(strlower "$quit_action")"
|
|
|
|
# Calculer la ligne des actions à afficher
|
|
local action_title
|
|
for tmp in "${action_descs[@]}"; do
|
|
splitfsep2 "$tmp" : action name
|
|
[ -n "$action" ] || action="${name:0:1}"
|
|
[ -n "$name" ] || name="$action"
|
|
action="$(strlower "$action")"
|
|
if [ -n "$no_options" ]; then
|
|
if ! base_array_contains void_actions "$action"; then
|
|
base_array_del actions "$action"
|
|
continue
|
|
fi
|
|
fi
|
|
[ "$action" == "$default_action" ] && name="$name*"
|
|
action_title="${action_title:+$action_title/}$name"
|
|
done
|
|
if [ -n "$default_action" ]; then
|
|
# si action par défaut invalide, alors pas d'action par défaut
|
|
base_array_contains actions "$default_action" || default_action=
|
|
fi
|
|
if [ -n "$quit_action" ]; then
|
|
# si action quitter invalide, alors pas d'action quitter
|
|
base_array_contains actions "$quit_action" || quit_action=
|
|
fi
|
|
|
|
# Type de menu
|
|
if [ -n "$no_options" ]; then
|
|
if base_array_isempty void_actions; then
|
|
eerror "Aucune option n'est définie. Il faut définir le tableau des actions vides"
|
|
return 1
|
|
fi
|
|
__void_actions_menu
|
|
else
|
|
__options_actions_menu
|
|
fi
|
|
}
|
|
|
|
function __void_actions_menu() {
|
|
eflush
|
|
local c=0 choice
|
|
while true; do
|
|
if [ $c -eq 0 ]; then
|
|
[ -n "$title" ] && __etitle "$title" 1>&2
|
|
__eecho_ "=== Actions disponibles: " 1>&2
|
|
tooenc "$action_title" 1>&2
|
|
fi
|
|
if [ -n "$actyc" ]; then
|
|
__eecho_ "$actyc" 1>&2
|
|
elif [ -n "$optyc" ]; then
|
|
__eecho_ "$optyc" 1>&2
|
|
else
|
|
__eecho_ "Entrez l'action à effectuer" 1>&2
|
|
fi
|
|
tooenc_ ": " 1>&2
|
|
uread choice
|
|
if [ -z "$choice" -a -n "$default_action" ]; then
|
|
select_action="$default_action"
|
|
break
|
|
fi
|
|
|
|
# vérifier la saisie
|
|
choice="${choice:0:1}"
|
|
choice="$(strlower "$choice")"
|
|
if base_array_contains actions "$choice"; then
|
|
select_action="$choice"
|
|
break
|
|
elif [ -n "$choice" ]; then
|
|
eerror "$choice: action incorrecte"
|
|
else
|
|
eerror "vous devez saisir l'action à effectuer"
|
|
fi
|
|
let c=$c+1
|
|
if [ $c -eq 5 ]; then
|
|
# sauter une ligne toutes les 4 tentatives
|
|
tooenc "" 1>&2
|
|
c=0
|
|
fi
|
|
done
|
|
__am_select_action="$select_action"
|
|
__am_select_option=
|
|
}
|
|
|
|
function __options_actions_menu() {
|
|
eflush
|
|
local c=0 option choice action option
|
|
while true; do
|
|
if [ $c -eq 0 ]; then
|
|
[ -n "$title" ] && __etitle "$title" 1>&2
|
|
i=1
|
|
for option in "${options[@]}"; do
|
|
if [ "$option" == "$select_option" ]; then
|
|
tooenc "$i*- $option" 1>&2
|
|
else
|
|
tooenc "$i - $option" 1>&2
|
|
fi
|
|
let i=$i+1
|
|
done
|
|
__estepn_ "Actions disponibles: " 1>&2
|
|
tooenc "$action_title" 1>&2
|
|
fi
|
|
if [ -n "$optyc" ]; then
|
|
__eecho_ "$optyc" 1>&2
|
|
else
|
|
__eecho_ "Entrez l'action et le numéro de l'option choisie" 1>&2
|
|
fi
|
|
tooenc_ ": " 1>&2
|
|
uread choice
|
|
|
|
# vérifier la saisie
|
|
if [ -z "$choice" -a -n "$default_action" ]; then
|
|
action="$default_action"
|
|
if base_array_contains void_actions "$action"; then
|
|
select_action="$action"
|
|
select_option=
|
|
break
|
|
elif [ -n "$select_option" ]; then
|
|
select_action="$action"
|
|
break
|
|
fi
|
|
fi
|
|
action="${choice:0:1}"
|
|
action="$(strlower "$action")"
|
|
if base_array_contains actions "$action"; then
|
|
# on commence par un code d'action valide. cool :-)
|
|
if base_array_contains void_actions "$action"; then
|
|
select_action="$action"
|
|
select_option=
|
|
break
|
|
else
|
|
option="${choice:1}"
|
|
option="${option// /}"
|
|
if [ -z "$option" -a -n "$select_option" ]; then
|
|
select_action="$action"
|
|
break
|
|
elif [ -z "$option" ]; then
|
|
eerror "vous devez saisir le numéro de l'option"
|
|
elif isnum "$option"; then
|
|
if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
|
|
select_action="$action"
|
|
select_option="${options[$(($option - 1))]}"
|
|
break
|
|
fi
|
|
else
|
|
eerror "$option: numéro d'option incorrecte"
|
|
fi
|
|
fi
|
|
elif isnum "$choice"; then
|
|
# on a simplement donné un numéro d'option
|
|
action="$default_action"
|
|
if [ -n "$action" ]; then
|
|
if base_array_contains void_actions "$action"; then
|
|
select_action="$action"
|
|
select_option=
|
|
break
|
|
else
|
|
option="${choice// /}"
|
|
if [ -z "$option" ]; then
|
|
eerror "vous devez saisir le numéro de l'option"
|
|
elif isnum "$option"; then
|
|
if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
|
|
select_action="$action"
|
|
select_option="${options[$(($option - 1))]}"
|
|
break
|
|
fi
|
|
else
|
|
eerror "$option: numéro d'option incorrecte"
|
|
fi
|
|
fi
|
|
else
|
|
eerror "Vous devez spécifier l'action à effectuer"
|
|
fi
|
|
elif [ -n "$choice" ]; then
|
|
eerror "$choice: action et/ou option incorrecte"
|
|
else
|
|
eerror "vous devez saisir l'action à effectuer"
|
|
fi
|
|
let c=$c+1
|
|
if [ $c -eq 5 ]; then
|
|
# sauter une ligne toutes les 4 tentatives
|
|
tooenc "" 1>&2
|
|
c=0
|
|
fi
|
|
done
|
|
__am_select_action="$select_action"
|
|
__am_select_option="$select_option"
|
|
}
|