modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2023-10-17 23:40:19 +04:00
parent f9f16ee0f1
commit 4b15b8f600
11 changed files with 1276 additions and 1772 deletions

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.args "Fonctions de base: analyse d'arguments"
require: base.arr
function: local_args "Afficher des commandes pour rendre locales des variables utilisées par parse_args()
@ -9,6 +8,8 @@ Cela permet d'utiliser parse_args() à l'intérieur d'une fonction."
function local_args() {
echo "local args"
echo "local NUCORE_ARGS_ONERROR_RETURN=1"
echo "local NUCORE_VERBOSITY=\"\$NUCORE_VERBOSITY\""
echo "local NUCORE_INTERACTION=\"\$NUCORE_INTERACTION\""
}
function: parse_args "Analyser les arguments de la ligne de commande à partir des définitions du tableau args

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.arr "Fonctions de base: gestion des variables tableaux"
require: base.core base.str
module: base.array "Fonctions de base: gestion des variables tableaux"
function: array_count "retourner le nombre d'éléments du tableau \$1"
function array_count() {
@ -269,7 +268,7 @@ function array_splitc() {
function: array_xsplitl "créer le tableau \$1 avec chaque ligne de \$2"
function array_xsplitl() {
eval "$1=($(recho_ "$2" | strnl2lf | lawk '
eval "$1=($(recho_ "$2" | nl2lf | lawk '
{
gsub(/'\''/, "'\'\\\\\'\''")
print "'\''" $0 "'\''"
@ -280,7 +279,7 @@ function: array_splitl "créer le tableau \$1 avec chaque ligne de \$2
Les lignes vides sont ignorés."
function array_splitl() {
eval "$1=($(recho_ "$2" | strnl2lf | lawk '
eval "$1=($(recho_ "$2" | nl2lf | lawk '
/^$/ { next }
{
gsub(/'\''/, "'\'\\\\\'\''")

View File

@ -1,468 +0,0 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.eval "Fonctions de base: évaluation d'expressions"
require: base.str base.arr
################################################################################
# Chaines
function: evals "Appliquer à une chaine de caractères une suite de traitements, e.g:
~~~
evals var deref +suffix
~~~
est équivalent à
~~~
echo \"\${var}suffix\"
~~~
En commençant avec la valeur initiale \$1, les arguments \$2..* sont des
opérations à appliquer dans l'ordre.
Les opérations suivantes considèrent que la valeur courante est un nom de
variable:
~~~
:- := :? :+ deref dcount
~~~
Toutes les autres opérations travaillent directement avec la valeur
courante. Les opérations suivantes appliquent une transformation:
~~~
# % / : ^ , +# -# +% -% + - mid repl
~~~
IMPORTANT: aucune de ces fonctions ne met en échappement les valeur des
patterns. Ainsi, si un pattern contient des caractères interdits comme \\ ou \$,
il faut d'abord le traiter avec _qval()
Les opérations suivantes font un test sur la valeur et retournent immédiatement:
~~~
= == != < > -eq -ne -lt -le -gt -ge -n -z
~~~
La syntaxe des opérateurs standards de bash est reprise autant que possible, i.e
si on a l'habitude d'écrire ${varOP} en bash, alors la syntaxe à utiliser à
priori est 'evals var OP' ou 'evals var deref OP' suivant les
opérateurs.
Autres opérateurs:
~~~
deref indirection
dcount nombre d'éléments du tableau
+#STR ajouter un préfixe
-#STR supprimer un préfixe
+%STR ou +STR ajouter un suffixe
-%STR ou -STR supprimer un suffixe
mid RANGE traiter la chaine avec strmid()
repl FROM TO traiter la chaine avec strrepl()
~~~
Tout autre opérateur est traité comme un appel à une fonction qui prend un seul
argument, la valeur courante, et qui affiche le résultat."
function evals() {
local -a es__tmp
local es__value="$1"; shift
while [ $# -gt 0 ]; do
case "$1" in
# l'argument est le nom de la variable
:-*|:=*|:\?*|:+*) eval 'es__value="${'"${es__value}$1"'}"';;
d|deref) es__value="${!es__value}";;
dc|dcount|ds|dsize)
es__value="${es__value}[@]"
es__tmp=("${!es__value}")
es__value="${#es__tmp[@]}"
;;
# l'argument est la valeur de la variable
\#*|%*|/*|:*|^*|,*) eval 'es__value="${es__value'"$1"'}"';;
l|length) es__value="${#es__value}";;
=|==|!=|\<|\>|-eq|-ne|-lt|-le|-gt|-ge)
es__tmp=(\[ "$es__value" "$@" ]); "${es__tmp[@]}"; return $?;;
-n|-z) es__tmp=(\[ "$1" "$es__value" ]); "${es__tmp[@]}"; return $?;;
+#*) eval 'es__value="'"${1#+#}"'$es__value"';;
-#*) eval 'es__value="${es__value'"${1#-}"'}"';;
+%*) eval 'es__value="$es__value"'"${1#+%}";;
+*) eval 'es__value="$es__value"'"${1#+}";;
-%*) eval 'es__value="${es__value'"${1#-}"'}"';;
-*) eval 'es__value="${es__value%'"${1#-}"'}"';;
mid|strmid) eval 'es__value="$(strmid "$2" "$es__value")"'; shift;;
repl|strrepl) eval 'es__value="$(strrepl "$2" "$3" "$es__value")"'; shift; shift;;
*) es__value="$("$1" "$es__value")";;
esac
shift
done
echo "$es__value"
}
function: setxs "équivalent à setx \$1 evals \$2..@"
function setxs() {
local -a ss__args
if [ "$1" == -a ]; then ss__args=(-a); shift; fi
local ss__var="$1"; shift
if [[ "$ss__var" == *=* ]]; then
set -- "${ss__var#*=}" "$@"
ss__var="${ss__var%%=*}"
fi
ss__args=("${ss__args[@]}" "$ss__var")
setx "${ss__args[@]}" evals "$@"
}
function: cmds "lancer une commande avec comme argument le résultat de evals
Par exemple, les deux commandes suivantes sont équivalentes:
~~~
cmds CMD ARGS... // EVALARGS
CMD ARGS... \"\$(evals EVALARGS)\"
~~~"
function cmds() {
local cs__arg
local -a cs__cmd
while [ $# -gt 0 ]; do
cs__arg="$1"; shift
[ "$cs__arg" == // ] && break
cs__cmd=("${cs__cmd[@]}" "$cs__arg")
done
"${cs__cmd[@]}" "$(evals "$@")"
}
function: evalm "construire une chaine en mixant chaines statiques et évaluations de commandes
Par exemple, les deux commandes suivantes sont équivalentes:
~~~
evalm //\"string\" cmd args // cmd args //\"string\"
echo \"string\$(cmd args)\$(cmd args)string\"
~~~"
function evalm() {
local em__val em__arg
local -a em__cmd
while [ $# -gt 0 ]; do
em__arg="$1"
if [ "${em__arg#//}" != "$em__arg" ]; then
em__val="$em__val${em__arg#//}"
shift
continue
fi
em__cmd=()
while [ $# -gt 0 ]; do
em__arg="$1"
[ "${em__arg#//}" != "$em__arg" ] && break
shift
if [ "${em__arg%//}" != "$em__arg" ]; then
local em__tmp="${em__arg%//}"
if [ -z "${em__tmp//\\/}" ]; then
em__arg="${em__arg#\\}"
em__cmd=("${em__cmd[@]}" "$em__arg")
continue
fi
fi
em__cmd=("${em__cmd[@]}" "$em__arg")
done
[ ${#em__cmd[*]} -gt 0 ] && em__val="$em__val$("${em__cmd[@]}")"
done
echo "$em__val"
}
function: setxm "équivalent à setx \$1 evalm \$2..@"
function setxm() {
local -a sm__args
if [ "$1" == -a ]; then sm__args=(-a); shift; fi
local sm__var="$1"; shift
if [[ "$sm__var" == *=* ]]; then
set -- "${sm__var#*=}" "$@"
sm__var="${sm__var%%=*}"
fi
sm__args=("${sm__args[@]}" "$sm__var")
setx "${sm__args[@]}" evalm "$@"
}
function: cmdm "lancer une commande avec comme argument le résultat de evalm
Par exemple, les deux commandes suivantes sont équivalentes:
~~~
cmdm CMD ARGS... // EVALARGS
CMD ARGS... \"\$(evalm EVALARGS)\"
~~~"
function cmdm() {
local cm__arg
local -a cm__cmd
while [ $# -gt 0 ]; do
cm__arg="$1"; shift
[ "$cm__arg" == // ] && break
cm__cmd=("${cm__cmd[@]}" "$cm__arg")
done
"${cm__cmd[@]}" "$(evalm "$@")"
}
################################################################################
# Nombres
function: evali "Evaluer une expression numérique"
function evali() {
echo "$(($*))"
}
################################################################################
# Tableaux
################################################################################
# Composition
function: evalc "Implémenter une syntaxe lisible et naturelle permettant d'enchainer des traitements sur une valeur.
Par exemple, la commande
~~~
evalc cmd1... // cmd2... // cmd3...
~~~
est équivalente à la commande
~~~
cmd3... \"\$(cmd2... \"\$(cmd1...)\")\"
~~~"
function evalc() {
local ec__arg ec__cmd ec__finalcmd
while [ $# -gt 0 ]; do
ec__arg="$1"; shift
if [ "$ec__arg" == // ]; then
if [ ${#ec__cmd} -gt 0 ]; then
if [ ${#ec__finalcmd} -eq 0 ]; then ec__finalcmd="$ec__cmd"
else ec__finalcmd="$ec__cmd \$($ec__finalcmd)"
fi
fi
ec__cmd=
continue
elif [ "${ec__arg%//}" != "$ec__arg" ]; then
local tmp="${ec__arg%//}"
[ -z "${tmp//\\/}" ] && ec__arg="${ec__arg#\\}"
fi
ec__cmd="$ec__cmd \"$(_qval "$ec__arg")\""
done
if [ ${#ec__cmd} -gt 0 ]; then
if [ ${#ec__finalcmd} -eq 0 ]; then ec__finalcmd="$ec__cmd"
else ec__finalcmd="$ec__cmd \$($ec__finalcmd)"
fi
fi
eval "$ec__finalcmd"
}
function: setxc "équivalent à setx \$1 evalc \$2..@"
function setxc() {
local -a sx__args
if [ "$1" == -a ]; then sx__args=(-a); shift; fi
local sx__var="$1"; shift
if [[ "$sx__var" == *=* ]]; then
set -- "${sx__var#*=}" "$@"
sx__var="${sx__var%%=*}"
fi
sx__args=("${sx__args[@]}" "$sx__var")
setx "${sx__args[@]}" evalc "$@"
}
################################################################################
# Chainage
function: evalp "Implémenter une syntaxe alternative permettant d'enchainer des traitements sur un flux de données.
Par exemple, la commande
~~~
evalp cmd1... // cmd2... // cmd3...
~~~
affiche le résultat de la commande
~~~
cmd1... | cmd2... | cmd3...
~~~
Typiquement, cette fonction permet de faciliter la *construction* d'un
enchainement de commandes par programme, ou de faciliter l'utilisation de la
fonction setx() pour récupérer le résultat d'un enchainement. Dans les autres
cas, il est plus simple et naturel d'écrire les enchainements avec la syntaxe de
bash."
function evalp() {
local ep__arg ep__cmd
while [ $# -gt 0 ]; do
ep__arg="$1"; shift
if [ "$ep__arg" == // ]; then
ep__cmd="$ep__cmd |"
continue
elif [ "${ep__arg%//}" != "$ep__arg" ]; then
local ep__tmp="${ep__arg%//}"
if [ -z "${ep__tmp//\\/}" ]; then
ep__arg="${ep__arg#\\}"
fi
fi
ep__cmd="${ep__cmd:+$ep__cmd }\"$(_qval "$ep__arg")\""
done
eval "$ep__cmd"
}
function: setxp "équivalent à setx \$1 evalp \$2..@"
function setxp() {
local -a sp__args
if [ "$1" == -a ]; then sp__args=(-a); shift; fi
local sp__var="$1"; shift
if [[ "$sp__var" == *=* ]]; then
set -- "${sp__var#*=}" "$@"
sp__var="${sp__var%%=*}"
fi
sp__args=("${sp__args[@]}" "$sp__var")
setx "${sp__args[@]}" evalp "$@"
}
function: cmdp "lancer une commande avec comme argument le résultat de evalp
Par exemple, les deux commandes suivantes sont équivalentes:
~~~
cmdp CMD ARGS... // EVALARGS
CMD ARGS... \"\$(evalp EVALARGS)\"
~~~"
function cmdp() {
local cp__arg
local -a cp__cmd
while [ $# -gt 0 ]; do
cp__arg="$1"; shift
[ "$cp__arg" == // ] && break
cp__cmd=("${cp__cmd[@]}" "$cp__arg")
done
"${cp__cmd[@]}" "$(evalp "$@")"
}
################################################################################
# Générique
function: evalx ""
function evalx() {
:
}
function: setxx "équivalent à setx \$1 evalx \$2..@"
function setxx() {
local -a sx__args
if [ "$1" == -a ]; then sx__args=(-a); shift; fi
local sx__var="$1"; shift
if [[ "$sx__var" == *=* ]]; then
set -- "${sx__var#*=}" "$@"
sx__var="${sx__var%%=*}"
fi
sx__args=("${sx__args[@]}" "$sx__var")
setx "${sx__args[@]}" evalx "$@"
}
function: cmdx "lancer une commande avec comme argument le résultat de evalx
Par exemple, les deux commandes suivantes sont équivalentes:
~~~
cmdx CMD ARGS... // EVALARGS
CMD ARGS... \"\$(evalx EVALARGS)\"
~~~"
function cmdx() {
local cx__arg
local -a cx__cmd
while [ $# -gt 0 ]; do
cx__arg="$1"; shift
[ "$cx__arg" == // ] && break
cx__cmd=("${cx__cmd[@]}" "$cx__arg")
done
"${cx__cmd[@]}" "$(evalx "$@")"
}
function: cmdsplitf "\
Cette fonction doit être appelée avec N arguments (avec N>1). Elle analyse et
découpe l'argument \$N comme avec une ligne de commande du shell. Ensuite, elle
appelle la fonction \$1 avec les arguments de \$2 à \${N-1}, suivi des arguments
obtenus lors de l'analyse de l'argument \$N. Par exemple, la commande suivante:
~~~
strsplitf cmd arg1 \"long arg2\" \"arg3 'long arg4'\"
~~~
est équivalente à:
~~~
cmd arg1 \"long arg2\" arg3 \"long arg4\"
~~~
Retourner le code 127 si la fonction à appeler n'est pas spécifiée. Retourner le
code 126 si une erreur s'est produite lors de l'analyse de l'argument \$N"
function cmdsplitf() {
[ $# -gt 0 ] || return 127
local func count
func="$1"; shift
count=$#
if [ $count -gt 0 ]; then
eval 'set -- "${@:1:$(($count-1))}" '"${!count}" || return 126
fi
"$func" "$@"
}
################################################################################
# Tests
function: testx "Faire un test unaire avec la commande [ sur une valeur calculée avec evalx.
Utiliser la syntaxe 'testx op cmds...' e.g.
~~~
testx -z cmd1 // cmd2
~~~"
function testx() {
local t__op="$1"; shift
local t__val="$(evalx "$@")"
[ $t__op "$t__val" ]
}
function: test2x "Faire une test binaire avec la commande [ entre une valeur spécifiée et une valeur calculée avec evalx.
Utiliser la syntaxe 'test2x value op cmds...' e.g.
~~~
test2x value == cmd1 // cmd2
~~~"
function test2x() {
local t__val1="$1"; shift
local t__op="$1"; shift
local t__val2="$(evalx "$@")"
[ "$t__val1" $t__op "$t__val2" ]
}
function: testrx "Faire une test binaire avec la commande [[ entre une valeur spécifiée et une valeur calculée avec evalx.
Utiliser la syntaxe 'testrx value op cmds...' e.g.
~~~
testrx value == cmd1 // cmd2
~~~"
function testrx() {
local t__val1="$1"; shift
local t__op="$1"; shift
local t__val2="$(evalx "$@")"
eval '[[ "$t__val1" '"$t__op"' "$t__val2" ]]'
}
function: testp "Faire un test unaire avec la commande [ sur une valeur calculée avec evalp.
Utiliser la syntaxe 'testp op cmds...' e.g.
~~~
testp -z cmd1 // cmd2
~~~"
function testp() {
local t__op="$1"; shift
local t__val="$(evalp "$@")"
[ $t__op "$t__val" ]
}
function: test2p "Faire une test binaire avec la commande [ entre une valeur spécifiée et une valeur calculée avec evalp.
Utiliser la syntaxe 'test2p value op cmds...' e.g.
~~~
test2p value == cmd1 // cmd2
~~~"
function test2p() {
local t__val1="$1"; shift
local t__op="$1"; shift
local t__val2="$(evalp "$@")"
[ "$t__val1" $t__op "$t__val2" ]
}
function: testrp "Faire une test binaire avec la commande [[ entre une valeur spécifiée et une valeur calculée avec evalp.
Utiliser la syntaxe 'testrp value op cmds...' e.g.
~~~
testrp value == cmd1 // cmd2
~~~"
function testrp() {
local t__val1="$1"; shift
local t__op="$1"; shift
local t__val2="$(evalp "$@")"
eval '[[ "$t__val1" '"$t__op"' "$t__val2" ]]'
}

586
bash/src/base.input.sh Normal file
View File

@ -0,0 +1,586 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.input "Fonctions de base: saisie"
function toienc() {
# $1 étant une variable contenant une chaine encodée dans l'encoding d'entrée $2
# (qui vaut par défaut $NUCORE_INPUT_ENCODING), transformer cette chaine en
# utf-8
local __var="$1" __from="${2:-$NUCORE_INPUT_ENCODING}"
if [ "$__from" != "NUCORE__UTF8" ]; then
_setv "$__var" "$(iconv -f "$__from" -t utf-8 <<<"${!__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 $NUCORE_INPUT_ENCODING
[ $# -gt 0 ] || set -- REPLY
local __var
read "$@"
for __var in "$@"; do
[ -z "$__var" -o "${__var:0:1}" == "-" ] && continue # ignorer les options
toienc "$__var"
done
}
function is_interaction() {
return 1
}
function check_interaction() {
return 0
}
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
__eecho_ "Voulez-vous continuer?" 1>&2
fi
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; local __rv_readline=1 __rv_showdef=1 __rv_nl=
__rv_opts=()
[ -n "$NUCORE_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
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
__eecho_ "Entrez la valeur" 1>&2
fi
if [ -n "$__rv_readline" ]; then
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
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
eerror "Le tableau $__sm_options_var doit être non vide"
return 1
fi
[ -z "$__sm_default" ] && __sm_default="${!__sm_option_var}"
eflush
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
__eecho_ "Entrez le numéro de l'option choisie" 1>&2
fi
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
eerror "Numéro d'option incorrect"
fi
else
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
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"
array_copy __am_action_descs "${3:-actions}"
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
array_copy action_descs __am_action_descs
array_copy options __am_options
array_copy void_actions __am_void_actions
# Calculer la liste des actions valides
local no_options
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")"
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
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}"
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 ! array_contains void_actions "$action"; then
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
array_contains actions "$default_action" || default_action=
fi
if [ -n "$quit_action" ]; then
# si action quitter invalide, alors pas d'action quitter
array_contains actions "$quit_action" || quit_action=
fi
# Type de menu
if [ -n "$no_options" ]; then
if 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 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 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 array_contains actions "$action"; then
# on commence par un code d'action valide. cool :-)
if 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 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"
}

File diff suppressed because it is too large Load Diff

646
bash/src/base.output.sh Normal file
View File

@ -0,0 +1,646 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.output "Fonctions de base: affichage"
NUCORE__TAB=$'\t'
NUCORE__LATIN1=iso-8859-1
NUCORE__LATIN9=iso-8859-15
NUCORE__UTF8=utf-8
if [ ! -x "$(which iconv 2>/dev/null)" ]; then
function iconv() { cat; }
fi
function nucore__lang_encoding() {
case "${LANG,,}" in
*@euro) echo "iso-8859-15";;
*.utf-8|*.utf8) echo "utf-8";;
*) echo "iso-8859-1";;
esac
}
function nucore__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 nucore__init_encoding() {
local default_encoding="$(nucore__lang_encoding)"
[ -n "$default_encoding" ] || default_encoding=utf-8
[ -n "$NUCORE_OUTPUT_ENCODING" ] || NUCORE_OUTPUT_ENCODING="$default_encoding"
NUCORE_OUTPUT_ENCODING="$(nucore__norm_encoding "$NUCORE_OUTPUT_ENCODING")"
[ -n "$NUCORE_INPUT_ENCODING" ] || NUCORE_INPUT_ENCODING="$NUCORE_OUTPUT_ENCODING"
NUCORE_INPUT_ENCODING="$(nucore__norm_encoding "$NUCORE_INPUT_ENCODING")"
}
[ -n "$NUCORE_LANG" -a -z "$LANG" ] && export NUCORE_LANG LANG="$NUCORE_LANG"
nucore__init_encoding
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 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
}
################################################################################
function tooenc() {
# $1 étant une chaine encodée en utf-8, l'afficher dans l'encoding de sortie $2
# qui vaut par défaut $NUCORE_OUTPUT_ENCODING
local value="$1" to="${2:-$NUCORE_OUTPUT_ENCODING}"
if [ "$to" == "$NUCORE__UTF8" ]; then
recho "$value"
else
iconv -f -utf-8 -t "$to" <<<"$value"
fi
}
function uecho() { tooenc "$*"; }
function tooenc_() {
# $1 étant une chaine encodée en utf-8, l'afficher sans passer à la ligne dans
# l'encoding de sortie $2 qui vaut par défaut $NUCORE_OUTPUT_ENCODING
local value="$1" to="${2:-$NUCORE_OUTPUT_ENCODING}"
if [ "$to" == "$NUCORE__UTF8" ]; then
recho_ "$value"
else
recho_ "$value" | iconv -f utf-8 -t "$to"
fi
}
function uecho_() { tooenc_ "$*"; }
# faut-il dater les messages de etitle, estep, ebegin?
# Faire NUCORE_EDATE=1 en début de script pour activer cette fonctionnalité
export NUCORE_EDATE
function __edate() { [ -n "$NUCORE_EDATE" ] && date +"[%d/%m/%Y-%H:%M:%S] "; }
export NUCORE_ELOG_OVERWRITE
function __set_no_colors() { :; }
function elogto() {
# Activer NUCORE_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 NUCORE_ELOG_OVERWRITE=1, alors le fichier en sortie est écrasé. Sinon, les
# lignes en sortie lui sont ajoutées
NUCORE_EDATE=1
if [ -n "$1" -a -n "$2" ]; then
LANG=fr_FR.UTF8
NUCORE_OUTPUT_ENCODING="$NUCORE__UTF8"
__set_no_colors 1
if [ -n "$NUCORE_ELOG_OVERWRITE" ]; then
exec >"$1" 2>"$2"
else
exec >>"$1" 2>>"$2"
fi
elif [ -n "$1" ]; then
LANG=fr_FR.UTF8
NUCORE_OUTPUT_ENCODING="$NUCORE__UTF8"
__set_no_colors 1
if [ -n "$NUCORE_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
# NUCORE__ESTACK est la liste des invocations de 'ebegin' et 'etitle' en cours
# NUCORE__TLEVEL est l'indentation à appliquer avant d'afficher le message
export NUCORE__ESTACK NUCORE__TLEVEL
function __indent() {
# indenter les lignes de $1, sauf la première
if [ "${1/
/}" != "$1" ]; then
sed "2,\$s/^/${NUCORE__TLEVEL}/g" <<<"$1"
else
recho "$1"
fi
}
# fonctions à surcharger pour modifier la façon dont les messages sont affichés
function __eerror() { tooenc "$(__edate)${NUCORE__TLEVEL}ERROR $(__indent "$1")"; }
function __ewarn() { tooenc "$(__edate)${NUCORE__TLEVEL}WARNING $(__indent "$1")"; }
function __enote() { tooenc "$(__edate)${NUCORE__TLEVEL}NOTE $(__indent "$1")"; }
function __ebanner() {
local maxi="${COLUMNS:-80}"
local -a lines
local psfix line
psfix="$(__edate)${NUCORE__TLEVEL}"
while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done
tooenc "$psfix"
maxi=$(($maxi - 1))
array_xsplitl lines "$1"
for line in "" "${lines[@]}" ""; do
line="$(__edate)${NUCORE__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)${NUCORE__TLEVEL}IMPORTANT $(__indent "$1")"; }
function __eattention() { tooenc "$(__edate)${NUCORE__TLEVEL}ATTENTION $(__indent "$1")"; }
function __einfo() { tooenc "$(__edate)${NUCORE__TLEVEL}INFO $(__indent "$1")"; }
function __eecho() { tooenc "$(__edate)${NUCORE__TLEVEL}$(__indent "$1")"; }
function __eecho_() { tooenc_ "$(__edate)${NUCORE__TLEVEL}$(__indent "$1")"; }
function __edebug() { tooenc "$(__edate)${NUCORE__TLEVEL}DEBUG $(__indent "$1")"; }
function __estep() { tooenc "$(__edate)${NUCORE__TLEVEL}. $(__indent "$1")"; }
function __estepe() { tooenc "$(__edate)${NUCORE__TLEVEL}.E $(__indent "$1")"; }
function __estepw() { tooenc "$(__edate)${NUCORE__TLEVEL}.W $(__indent "$1")"; }
function __estepn() { tooenc "$(__edate)${NUCORE__TLEVEL}.N $(__indent "$1")"; }
function __estepi() { tooenc "$(__edate)${NUCORE__TLEVEL}.I $(__indent "$1")"; }
function __estep_() { tooenc_ "$(__edate)${NUCORE__TLEVEL}. $(__indent "$1")"; }
function __estepe_() { tooenc_ "$(__edate)${NUCORE__TLEVEL}.E $(__indent "$1")"; }
function __estepw_() { tooenc_ "$(__edate)${NUCORE__TLEVEL}.W $(__indent "$1")"; }
function __estepn_() { tooenc_ "$(__edate)${NUCORE__TLEVEL}.N $(__indent "$1")"; }
function __estepi_() { tooenc_ "$(__edate)${NUCORE__TLEVEL}.I $(__indent "$1")"; }
function __etitle() { tooenc "$(__edate)${NUCORE__TLEVEL}=== $(__indent "$1")"; }
function __ebegin() { tooenc_ "$(__edate)${NUCORE__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() { :;}
# note: toutes les fonctions d'affichage e* écrivent sur stderr
NUCORE__EPENDING=
function eflush() {
# Afficher les messages en attente
if [ -n "$NUCORE__EPENDING" ]; then recho "$NUCORE__EPENDING" 1>&2; NUCORE__EPENDING=; fi
}
function eclearp() {
# Supprimer les message en attente
NUCORE__EPENDING=
}
function eerror() {
# Afficher un message d'erreur
show_error || return; eflush; __eerror "$*" 1>&2
}
function die() {
[ $# -gt 0 ] && eerror "$@"
exit 1
}
function exit_with {
if [ $# -gt 0 ]; then "$@"; fi
exit $?
}
function die_with {
[ $# -gt 0 ] && 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" ] && _eerror "$du__msg"
exit 1
elif "$@"; then
:
else
du__r=$?
[ -n "$du__msg" ] && _eerror "$du__msg"
exit $du__r
fi
return 0
}
function eerror_unless() {
# Afficher $1 avec 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" ] && _eerror "$eu__msg"
return 1
elif "$@"; then
:
else
eu__r=$?
[ -n "$eu__msg" ] && _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" ] && _eerror "$di__msg"
exit 0
else
di__r=$?
fi
return $di__r
}
function eerror_if() {
# Afficher $1 avec 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" ] && _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 "$NUCORE__ESTACK" ] && NUCORE__TLEVEL="${NUCORE__TLEVEL} "
NUCORE__ESTACK="$NUCORE__ESTACK:t"
if show_info; then
if [ -n "$__t_deferred" ]; then
NUCORE__EPENDING="${NUCORE__EPENDING:+$NUCORE__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
NUCORE__ESTACK="$NUCORE__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
NUCORE__ESTACK=
NUCORE__TLEVEL=
elif [ "${NUCORE__ESTACK%:b}" != "$NUCORE__ESTACK" ]; then
# terminer ebegin
NUCORE__ESTACK="${NUCORE__ESTACK%:b}"
show_info || return
eflush
[ -n "$1" ] && s="$1"
if [ "$s" == "0" ]; then
__eendo 1>&2
else
__eendx 1>&2
fi
elif [ "${NUCORE__ESTACK%:t}" != "$NUCORE__ESTACK" ]; then
# terminer etitle -s
NUCORE__ESTACK="${NUCORE__ESTACK%:t}"
NUCORE__TLEVEL="${NUCORE__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
}

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.path "Fonctions de base: gestion des chemins et des fichiers"
require: base.core
function: in_path "tester l'existence d'un programme dans le PATH"
function in_path() {

View File

@ -8,12 +8,12 @@ if [ -z "$NUCOREDIR" -o "$NUCOREDIR" != "$NUCOREINIT" ]; then
fi
##@include base.init.sh
##@include base.core.sh
##@include base.str.sh
##@include base.arr.sh
##@include base.io.sh
##@include base.eval.sh
##@include base.string.sh
##@include base.array.sh
##@include base.output.sh
##@include base.input.sh
##@include base.split.sh
##@include base.path.sh
##@include base.args.sh
module: base "Chargement de tous les modules base.*"
require: base.init base.core base.str base.arr base.io base.eval base.split base.path base.args
require: base.init base.core base.string base.array base.output base.input base.split base.path base.args

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.split "Fonctions de base: analyse et découpage de valeurs"
require: base.arr
function: splitfsep "\
Découper \$1 de la forme first[SEPsecond] entre first, qui est placé dans la

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.str "Fonctions de base: gestion des valeurs chaines"
module: base.string "Fonctions de base: gestion des valeurs chaines"
function: strmid "Afficher la plage \$1 de la valeur \$2..*

33
bash/tests/test-output.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$(dirname -- "$0")/../src/nucore.sh" || exit 1
#NUCORE_NO_DISABLE_SET_X=1
eerror "erreur"
ewarn "warning"
enote "note"
ebanner "banner"
eimportant "important"
eattention "attention"
einfo "info"
eecho "vanilla"
edebug "debug"
etitle "section"
estep "step"
estepe "stepe"
estepw "stepw"
estepn "stepn"
estepi "stepi"
ebegin "begin"
edot
edotw
eend
echo "\
line1
line2
line3" | elinedots "lines"
eend