nutools/legacy/sysinc/functions

1827 lines
55 KiB
Bash

# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##################################################
# Gestion des fichiers
function filter_conf() {
# filtrer un fichier de configuration en enlevant les commentaires et les lignes vides
# $1==-m fusionner les lignes qui se terminent par \
local merge=cat
if [ "$1" == -m ]; then
merge='awk '\''substr($0, length($0)) == "\\" { while (substr($0, length($0)) == "\\") { getline nextline; $0 = substr($0, 1, length($0) - 1) nextline }; print; next } {print}'\'
fi
grep -v '^#' | grep -v '^$' | eval "$merge"
}
##################################################
# Gestion des fichiers et répertoires temporaires
function make_tempfile() {
# $1=template du fichier à créer
local mktmpdir=
if [ "$1" == "-d" ]; then
shift
mktmpdir=1
fi
local template="${1:-$TMPDIR/tmp.XXXXXX}"
local base="${template%%X*}"
local XXXs="${template#$base}"
[ -z "$XXXs" ] && XXXs="XXXXXX"
local nbX="${#XXXs}"
local n="$$0" suff
while true; do
suff="$n"
while [ ${#suff} -lt $nbX ]; do suff="0$suff"; done
tempfile="$base$suff"
if [ -n "$mktmpdir" ]; then
# répertoire temporaire
if [ ! -d "$tempfile" ]; then
mkdir "$tempfile"
break
fi
else
# fichier temporaire
if [ ! -f "$tempfile" ]; then
touch "$tempfile"
break
fi
fi
n=$(($n + 1))
done
echo "$tempfile"
}
# autoclean: gérer une liste de fichiers temporaires à supprimer en fin de programme
__ac_files=()
function __ac_trap() {
local file_
for file_ in "${__ac_files[@]}"; do
[ -e "$file_" ] && rm -rf "$file_"
done
}
trap __ac_trap 1 3 15 EXIT
function autoclean() {
# Ajouter $1..$n à la liste des fichiers à supprimer à la fin du programme
local file_
for file_ in "$@"; do
[ -n "$file_" ] && array_add __ac_files "$file_"
done
}
function ac_set_tmpfile() {
# Créer un fichier temporaire avec le motif $2, l'ajouter à la liste des
# fichiers à supprimer en fin de programme, et mettre sa valeur dans la
# variable $1
local tmpfile_="$(mktempf "$2")"
autoclean "$tmpfile_"
set_var "$1" "$tmpfile_"
}
function ac_set_tmpdir() {
# Créer un répertoire temporaire avec le motif $2, l'ajouter à la liste des
# fichiers à supprimer en fin de programme, et mettre sa valeur dans la
# variable $1
local tmpdir_="$(mktempd "$2")"
autoclean "$tmpdir_"
set_var "$1" "$tmpdir_"
}
##################################################
# args: gestion d'un ensemble d'arguments
function read_args() {
# Lire les arguments et les mettre sur plusieurs lignes dans la variable
# dont le nom est donné dans $1. Ceci permet de façon fiable de traiter des
# arguments avec des espaces dedans.
# note: cela suppose bien sûr que les arguments ne contiennent pas de retour
# à la ligne!!!
if [ -z "$1" ]; then return 1; fi
local varname_="$1"; shift
local args_ arg_
for arg_ in "$@"; do
args_="${args_:+$args_
}$arg_"
done
set_var "$varname_" "$args_"
}
function next_arg() {
# Soit la variable args dont le nom est donné dans $1, et la variable next
# dont le nom est donné dans $2. Mettre à jour next avec la première ligne
# de la variable args. Mettre à jour args avec le reste des lignes.
if [ -z "$1" -o -z "$2" ]; then return 1; fi
local args_="$1"
local arg_="$2"
local line_ first_=1 first_line_ last_lines_
eval "$((echo "${!args_}"; echo "---<eof>---") | while read line_; do
if [ "$line_" == "---<eof>---" ]; then
echo "first_line_=\"$(quote_arg "$first_line_")\"
last_lines_=\"$(echo "$last_lines_" | awk '/.+/ { print; next }' | quote_string)\""
elif [ -n "$first_" ]; then
first_=
first_line_="$line_"
else
last_lines_="$last_lines_
$line_"
fi
done)"
set_var "$args_" "$last_lines_"
set_var "$arg_" "$first_line_"
if [ -z "$first_line_" ]; then return 1; fi
}
function get_option() {
# $1 est un argument de la forme "option:value"
# $2 est une liste d'options valides, séparées par des espaces
# $3 est un suffixe à rajouter au nom de variable
# Si $1 est une option valide (de la forme 'option:value' avec option
# faisant partie de la liste (optionnelle) des options valides) alors mettre
# à jour la variable $option avec la valeur value. sinon, retourner un code
# d'erreur
local arg_="$1"
local valid_options_="$2" valid_option_ is_valid_ option_ value_
local suffix_="$3"
option_="$(expr "$arg_" : "\(..*\):")"
[ -z "$option_" ] && return 1
if [ -n "$2" ]; then
# vérifier que $option est valide
is_valid_=
for valid_option_ in $valid_options_; do
if [ "$option_" == "$valid_option_" ]; then
is_valid_=1
break
fi
done
[ -z "$is_valid_" ] && return 1
fi
value_="${1##$option_:}"
set_var "$option_$suffix_" "$value_"
}
##################################################
# input: fonctions pour poser des question et saisir des valeurs
function ask_yesno() {
# $1=message, $2=default (N par défaut)
# Afficher le message $message suivi de [oN] ou [On] suivant que $default
# vaut O ou N. Retourner 0 si la réponse est oui, 1 sinon
# Si default vaut C, alors la valeur par défaut dépend du niveau
# d'interactivité: N si on est interactif et O si on est pas interactif
# Support de l'affichage de la question suivant le niveau d'interaction
# et/ou de verbosité Le message ne sera affiché que si le niveau
# d'interaction (ou de verbosité) courant est supérieur ou égal à celui qui
# est spécifié en argument. Sinon, la valeur par défaut est retournée
local r
check_verbosity "$1"; r=$?; [ $r -le 1 ] && shift
local message="$1"
local prompt="[oN]"
local default="${2:-N}"
if [ "$default" == "C" ]; then
if [ $r -ne 1 ]; then
default=N
else
default=O
fi
fi
is_yes "$default" && prompt="[On]"
if [ $r -ne 1 ]; then
if [ -n "$message" ]; then
tooenc_ "$message"
else
tooenc_ "Voulez-vous continuer?" "$UTF8"
fi
echo_ " $prompt "
uread r
else
r=
fi
is_yes "${r:-$default}"
}
function read_value() {
# $1=message, $2=varname, $3=default, $4=refuse_empty
# Afficher le message $message suivi la valeur par défaut [$default] si elle
# est non vide, puis lire la valeur donnée par l'utilisateur. Cette valeur
# doit être non vide si $refuse_empty est vrai (ce qui est le cas par
# défaut)
# La valeur saisie est placée dans la variable $varname (par défaut value)
# note: les variables locales sont suffixées de _ pour éviter que $varname
# soit égal à une des variables locales.
# Support l'affichage de la question suivant le niveau de "verbosité"
# Le message ne sera affiché que si le niveau de verbosité courant est
# supérieur ou égal à celui qui est spécifié en argument. Sinon, la valeur
# par défaut est retournée. (note: si l'utilisateur requière que la valeur
# soit non vide et que la valeur par défaut est vide, le script s'arrête
# avec une erreur)
local r_
check_verbosity "$1"; r_=$?; [ $r_ -le 1 ] && shift
local message_="$1"
local varname_="${2:-value}"
local default_="$3"
local refuse_empty_="${4:-O}"
local read_value_=
if [ $r_ -ne 1 ]; then
read_value_=1
elif [ -z "$default_" ] && is_yes "$refuse_empty_"; then
read_value_=1
fi
if [ -n "$read_value_" ]; then
while true; do
if [ -n "$message_" ]; then
tooenc_ "$message_"
else
tooenc_ "Entrez la valeur" "$UTF8"
fi
[ -n "$default_" ] && tooenc_ " [$default_]"
echo_ ": "
uread r_; r_="${r_:-$default_}"
if [ -n "$r_" ] || ! is_yes "$refuse_empty_"; then
set_var "$varname_" "$r_"
return 0
fi
done
else
if [ -z "$default_" ] && is_yes "$refuse_empty_"; then
OENC="$UTF8" die "La valeur par défaut de $varname_ doit être non vide"
else
set_var "$varname_" "$default_"
fi
fi
}
##################################################
# menu: fonctions afficher un menu
function simple_menu() {
# $1=option_varname
# $2=options (une par ligne)
# $3..*=votre_choix:, titre_du_menu:, choix_par_defaut:
# Afficher un menu dont les membres sont les lignes de $options. Un choix
# doit être saisi sous la forme num_option. L'option choisie est placée dans
# la variable $option_varname
# note: les variables locales sont suffixées de _ pour éviter que
# $option_varname soit égal à une des variables locales.
local tab_=" " # contient une tabulation
local i_ c_
local options_one_by_line_ options_ option_
local choice_ choice_option_
local option_varname_
local votre_choix_ titre_du_menu_ choix_par_defaut_
# nom de la variable destination
option_varname_="$1"; shift
if [ -z "$option_varname_" ]; then
OENC="$UTF8" eerror "option_varname doit être spécifié"
return 1
fi
choix_par_defaut_="${!option_varname_}"
# Construire le tableau des options
options_one_by_line_="$1"; shift
if [ -z "$options_one_by_line_" ]; then
OENC="$UTF8" eerror "options doit être non vide"
return 1
fi
i_=0
while next_arg options_one_by_line_ option_; do
options_[$i_]="$option_"
i_=$(($i_ + 1))
done
# autres paramètres
while [ -n "$1" ]; do
! get_option "$1" "votre_choix titre_du_menu choix_par_defaut" _ && break
shift
done
c_=0
while true; do
if [ "$c_" == "0" ]; then
# Afficher le menu
[ -n "$titre_du_menu_" ] && tooenc "=== $titre_du_menu_ ==="
i_=1
for option_ in "${options_[@]}"; do
if [ "$option_" == "$choix_par_defaut_" ]; then
echo "$i_*- $option_"
else
echo "$i_ - $option_"
fi
i_=$(($i_ + 1))
done
fi
# Afficher les choix
if [ -n "$votre_choix_" ]; then
tooenc_ "$votre_choix_"
else
tooenc_ "Entrez le numéro de l'option choisie" "$UTF8"
fi
echo_ ": "
uread choice_
# valeur par défaut
if [ -z "$choice_" -a -n "$choix_par_defaut_" ]; then
choice_option_="$choix_par_defaut_"
break
fi
# vérifier la saisie
choice_option_="$(expr "$choice_" : "[ $tab_]*\([0-9]*\)")"
if [ -n "$choice_option_" ] && [ "$choice_option_" -gt "0" -a "$choice_option_" -le "${#options_[*]}" ]; then
# numéro d'option correct
choice_option_="${options_[$(($choice_option_ - 1))]}"
break
else
OENC="$UTF8" eerror "Numéro d'option incorrect"
fi
c_=$(($c_ + 1))
if [ "$c_" == "5" ]; then
echo "" # sauter une ligne toutes les 4 tentatives
c_=0
fi
done
set_var "$option_varname_" "$choice_option_"
}
function actions_menu() {
# $1=action_varname, $2=option_varname
# $3=actions (séparées par des espaces), $4=options (une par ligne)
# $5..*=action_quitter:, action_par_defaut:, actions_vides:, votre_choix:,
# titre_du_menu:, message_sans_options:
# Afficher un menu dont les membres sont les lignes de $options. Sur
# chacunes de ces entrées de menu, les actions de $actions peuvent être
# appliquées. Un choix doit être saisi sous la forme [action]num_option. Si
# action n'est pas précisé, il s'agit de l'action par défaut qui est
# sélectionnée. Par défaut, action_par_defaut est la première action, et
# action_quitter (qui provoque la sortie du menu sans choix) est la dernière
# action
# actions est une chaine d'éléments de la forme "k:Description" séparés par
# des espaces, où k est un lettre, et Description une description de
# l'action. Dans la chaine Description, les caractères '_' sont remplacés
# par des espaces pour l'affichage
# l'action choisie est placée dans la variable $action_varname. l'option
# choisie est placée dans la variable $option_varname
# note: les variables locales sont suffixées de _ pour éviter que
# $action_varname ou $option_varname soient égals à une des variables
# locales.
local tab_=" " # contient une tabulation
local i_ c_ error_displayed_
local options_one_by_line_ options_ option_
local actions_sep_by_space_ actions_ action_ action_key_ action_name_ action_names_
local actions_vides_ action_vide_
local action_quitter_
local action_par_defaut_
local choice_ choice_ok_ choice_action_ choice_option_
local action_varname_ option_varname_
local sans_options_ message_sans_options_
action_varname_="$1"; shift
option_varname_="$1"; shift
if [ -z "$action_varname_" -o -z "$option_varname_" ]; then
OENC="$UTF8" eerror "action_varname et option_varname doivent être spécifiés"
return 1
fi
# actions possibles
actions_sep_by_space_="$1"; shift
if [ -z "$actions_sep_by_space_" ]; then
OENC="$UTF8" eerror "actions doit être non vide"
return 1
fi
# Construire le tableau des options
options_one_by_line_="$1"; shift
if [ -n "$options_one_by_line_" ]; then
i_=0
while next_arg options_one_by_line_ option_; do
options_[$i_]="$option_"
i_=$(($i_ + 1))
done
else
sans_options_=1
fi
# autres paramètres
while [ -n "$1" ]; do
! get_option "$1" "actions_vides action_quitter action_par_defaut votre_choix titre_du_menu message_sans_options" _ && break
shift
done
if [ -n "$sans_options_" -a -z "$actions_vides_" ]; then
OENC="$UTF8" eerror "options doit être non vide"
return 1
fi
# Construire le tableau des actions
i_=0
for action_ in $actions_sep_by_space_; do
action_key_="$(first_char "$action_")"
action_="$(last_chars "$action_")"
if [ "$(first_char "$action_")" == ":" ]; then
action_name_="$(last_chars "$action_")"
action_name_="${action_name_//_/ }"
else
action_name_="$action_key_"
fi
[ -z "$action_par_defaut_" ] && action_par_defaut_="$action_key_"
[ "$action_key_" == "$action_par_defaut_" ] && action_name_="$action_name_*"
action_names_="${action_names_:+$action_names_/}$action_name_"
actions_[$i_]="$(echo $action_key_ | awk '{print tolower($0)}')"
i_=$(($i_ + 1))
done
[ -z "$action_quitter_" ] && action_quitter_="$action_key_"
if [ "$action_par_defaut_" == "$action_quitter_" ]; then
OENC="$UTF8" eerror "action_par_defaut et action_quitter doivent être différents"
return 1
fi
actions_vides_="$actions_vides_ $action_quitter_"
# Lecture des choix de l'utilisateur
c_=0
while true; do
if [ "$c_" == "0" ]; then
# Afficher le menu
[ -n "$titre_du_menu_" ] && tooenc "=== $titre_du_menu_ ==="
if [ -z "$sans_options_" ]; then
i_=1
for option_ in "${options_[@]}"; do
tooenc "$i_ - $option_"
i_=$(($i_ + 1))
done
else
if [ -n "$message_sans_options_" ]; then
tooenc "$message_sans_options_"
else
tooenc "Pas d'options disponibles" "$UTF8"
fi
fi
fi
# Afficher les choix
tooenc_ "
Actions disponibles: " "$UTF8"
tooenc "$action_names_"
if [ -n "$votre_choix_" ]; then
tooenc_ "$votre_choix_"
else
tooenc_ "Entrez le numéro de l'option choisie" "$UTF8"
fi
echo_ ": "
read choice_
# vérifier la saisie
choice_option_="$(expr "$choice_" : "\([0-9]*\)")"
if [ -n "$choice_option_" ]; then
# on a donné le numéro de l'option sans l'action. retourner l'action par défaut
if [ -z "$sans_options_" -a "$choice_option_" -gt "0" -a "$choice_option_" -le "${#options_[*]}" ]; then
# numéro d'option correct
choice_option_="${options_[$(($choice_option_ - 1))]}"
choice_action_="$action_par_defaut_"
break
else
OENC="$UTF8" eerror "Numéro d'option incorrect"
fi
else
choice_action_="$(expr "$choice_" : "\([^ $tab_]\)")"
choice_ok_=
error_displayed_=
for action_ in "${actions_[@]}"; do
if [ "$choice_action_" == "$action_" ]; then
# action correcte
# est-ce une action vide (une action qui ne requière pas de numéro d'option)
for action_vide_ in $actions_vides_; do
if [ "$choice_action_" == "$action_vide_" ]; then
# retourner comme option tous les arguments de
# l'action vide, en trimant les espaces de début
choice_option_="$(expr "$choice_" : "[^ $tab_][ $tab_]*\(.*\)")"
choice_ok_=1
break
fi
done
[ -n "$choice_ok_" ] && break
# lire le numéro d'option associé à l'action
choice_option_="$(expr "$choice_" : "[^ $tab_][ $tab_]*\([0-9]*\)")"
if [ -n "$choice_option_" ] && [ "$choice_option_" -gt "0" -a "$choice_option_" -le "${#options_[*]}" ]; then
# numéro d'option correct
choice_option_="${options_[$(($choice_option_ - 1))]}"
choice_ok_=1
else
OENC="$UTF8" eerror "Il faut spécifier un numéro d'option correct avec l'action"
error_displayed_=1
fi
[ -n "$choice_ok_" ] && break
fi
done
[ -n "$choice_ok_" ] && break
[ -z "$error_displayed_" ] && OENC="$UTF8" eerror "Action incorrecte"
fi
c_=$(($c_ + 1))
if [ "$c_" == "5" ]; then
echo "" # sauter une ligne toutes les 4 tentatives
c_=0
fi
done
set_var "$action_varname_" "$choice_action_"
set_var "$option_varname_" "$choice_option_"
}
##################################################
# fileopts: opérations sur les fichiers
function file_get_vars() {
# lire les variables dans un fichier
local OENC="$UTF8"
local done_ prefix_ whole_file_ file_ vars_ var_ script_
# traiter les arguments
done_=
while [ -z "$done_" ]; do
case "$1" in
--prefix|-p)
# prefixe pour la variable
prefix_="$2"
shift; shift
;;
--whole-file|-w)
# lire les variables dans le fichier en entier, et pas seulement
# dans l'en-tête.
whole_file_=1
shift
;;
*)
done_=1
;;
esac
done
# obtenir le nom du fichier
file_="$1"; shift
if [ ! -f "$file_" ]; then
# fichier inexistant
ewarn "Fichier inexistant: $file_"
return 1
fi
# initialiser les valeurs par défaut
vars_=
while [ -n "$1" ]; do
var_="$1"; shift
vars_="${vars_:+$vars_ }$var_"
set_var "$var_" "$1"; shift
done
# puis parcourir le fichier pour initialiser la valeur définitive des
# variables
if [ -z "$whole_file_" ]; then
script_="/^ *$/ { exit }
"
fi
for var_ in $vars_; do
script_="$script_
"'$0 ~ "^ *#* *" prefix "'"$var_"'=" {
# enlever les caractères inutiles
sub(" *#* *" prefix "'"$var_"'=", "")
# enlever éventuellement les quotes autour de la valeur
if ($0 ~ /^".*" *$/) {
$0 = substr($0, 2) # premier quote
match($0, /" *$/)
$0 = substr($0, 1, RSTART - 1) # dernier quote
}
# remplacer dans les valeurs les occurences de quotes
gsub("\"", "\\\"")
# afficher la ligne à évaluer
print "'"$var_"'=\"" $0 "\""
}
'
done
eval "$(uawk -v prefix="$prefix_" "$script_" <"$file_")"
}
function file_set_vars() {
# écrire les variables dans un fichier. Le fichier *doit exister*
local OENC="$UTF8"
local done_ quote_ comment_ prefix_ whole_file_ file_ var_ script_
# traiter les arguments
done_=
while [ -z "$done_" ]; do
case "$1" in
--quote-always|-q)
# toujours mettre les valeurs entre quotes
quote_=1
shift
;;
--comment-prefix|-c)
# commentaire à préfixer
comment_="$2"
shift; shift
;;
--prefix|-p)
# prefixe pour la variable
prefix_="$2"
shift; shift
;;
--whole-file|-w)
# écrire les variables dans le fichier en entier, et pas seulement
# dans l'en-tête.
whole_file_=1
shift
;;
*)
done_=1
;;
esac
done
# obtenir le nom du fichier
file_="$1"; shift
if [ ! -f "$file_" ]; then
# fichier inexistant
ewarn "Fichier inexistant: $file_"
return 1
fi
# puis parcourir le fichier pour mettre à jour les valeurs
script_='BEGIN {
# faut-il mettre à jour les variables?
update_vars = 1'
for var_ in "$@"; do
script_="$script_
${var_}_done = 0"
done
script_="$script_
}"
script_="$script_"'
function quote_value_maybe(value) {
if (quote_always || index(value, " ") != 0) {
return "\"" value "\""
} else {
return value
}
}
function write_all_remaining_vars() {'
for var_ in "$@"; do
value="${!var_}"
script_="$script_"'
if (! '"$var_"'_done) {
print comment prefix "'"$var_"'=" quote_value_maybe("'"${value//\"/\\\"}"'")
'"$var_"'_done = 1
}'
done
script_="$script_
}"
if [ -z "$whole_file_" ]; then
script_="$script_"'
/^[ \t]*$/ {
write_all_remaining_vars()
update_vars = 0
}'
fi
script_="$script_"'
update_vars && comment == "" && $0 ~ "^ *#* *.*=.*$" {
#comment = gensub("^( *#* *).*=.*$", "\\1", 1)
comment = ""
if (match($0, /^ *#* */) != 0) {
comment = substr($0, RSTART, RLENGTH)
}
}'
for var_ in "$@"; do
value="${!var_}"
script_="$script_"'
update_vars && ! '"$var_"'_done && $0 ~ "^ *#* *" prefix "'"$var_"'=" {
#$0 = gensub("^( *#* *" prefix "'"$var_"'=).*$", "\\1", 1)
match($0, "^ *#* *" prefix "'"$var_"'=")
$0 = substr($0, RSTART, RLENGTH)
$0 = $0 quote_value_maybe("'"${value//\"/\\\"}"'")
print
'"$var_"'_done = 1
next
}'
done
script_="$script_"'
{
print
}
END {
if (update_vars) {
write_all_remaining_vars()
}
}'
uawk -v quote_always="$quote_" -v comment="$comment_" -v prefix="$prefix_" "$script_" <"$file_" >"$file_.$$" &&
/bin/mv "$file_.$$" "$file_"
}
function file_get_properties() {
# lire les propriétés d'un fichier de propriété java ou xml
if endswith "$1" .xml; then
file_get_xml_properties "$@"
else
file_get_java_properties "$@"
fi
}
function file_set_properties() {
# écrire les propriétés d'un fichier de propriété java ou xml
local done_ create_
while [ -z "$done_" ]; do
case "$1" in
--create|-c)
create_=1
shift
;;
*)
done_=1
;;
esac
done
if endswith "$1" .xml; then
file_set_xml_properties ${create_:+-c} "$@"
else
file_set_java_properties ${create_:+-c} "$@"
fi
}
function file_get_java_properties() {
# lire les propriétés d'un fichier de propriétés java. note: les noms de
# propriété java peuvent contenir le caractère "." mais pas les noms de
# variable bash. La conversion est faite automatiquement. Par exemple::
# file_get_properties build.properties path.to.package "default value"
# charge la valeur de la propriété dans la variable path_to_package
# $1=nom du fichier de propriété
# $2..n=propriétés qu'il faut lire et valeurs par défaut de ces propriétés
# $__2*i __=nom de la propriété
# $__2*i+1__=valeur par défaut de la propriété si la valeur n'existe pas
# dans le fichier
local OENC="$UTF8"
local file_="$1"; shift
if [ ! -f "$file_" ]; then
# fichier inexistant
ewarn "Fichier de propriété inexistant: $file_"
return 1
fi
local var_ sh_var_ awk_var_
local script
while [ -n "$1" ]; do
# pour chacune des variables...
var_="$1"; shift
sh_var_="${var_//./_}" # nom de la variable shell traduite ("." --> "_")
sh_var_="${sh_var_//-/_}" # ("-" --> "_")
awkre_var_="${var_//./\\\\.}" # nom de la variable pour une expression régulière awk
# initialiser la valeur par défaut
set_var "$sh_var_" "$1"; shift
# et créer le script qui affichera sa valeur
script="$script"'
$0 ~ "^[ \t]*'"$(quote_awk "$awkre_var_")"'=" {
# enlever les caractères de début
sub("^[ \t]*'"$(quote_awk "$awkre_var_")"'=", "")
value = $0
# éventuellement ajouter les lignes de continuation
while (substr(value, length(value), 1) == "\\") {
getline
sub("^[ \t]*", "")
value = substr(value, 1, length(value) - 1) $0
}
gsub("\"", "\\\"", value)
print "'"$sh_var_"'=\"" value "\""
}
'
done
eval "$(awk "$script" <"$file_")"
}
function file_set_java_properties() {
# écrire des propriétés dans un fichier de propriétés java.
# $1=nom du fichier de propriété
# $2..n=propriétés qu'il faut écrire et valeurs de ces propriétés
# $__2*i __=nom de la propriété
# $__2*i+1__=valeur de la propriété
# traiter les arguments
local OENC="$UTF8"
local done_ create_
while [ -z "$done_" ]; do
case "$1" in
--create|-c)
# créer le fichier s'il n'existe pas
create_=1
shift
;;
*)
done_=1
;;
esac
done
local file_="$1"; shift
if [ ! -f "$file_" ]; then
if [ -n "$create_" ]; then
touch "$file_"
else
# fichier inexistant
ewarn "Fichier de propriété inexistant: $file_"
return 1
fi
fi
# récupérer les noms des propriétés et leur valeur
local var_ arg_ sh_var_ awkre_var_ value_
local -a vars_ values_
value_=vars_
for arg_ in "$@"; do
array_add "$value_" "$arg_"
if [ "$value_" == "vars_" ]; then
value_=values_
else
value_=vars_
fi
done
# créer le script qui va parcourir le fichier pour mettre à jour les valeurs
script_="BEGIN {"
for var_ in "${vars_[@]}"; do
sh_var_="${var_//./_}" # nom de la variable shell traduite ("." --> "_")
sh_var_="${sh_var_//-/_}" # ("-" --> "_")
script_="$script_
${sh_var_}_done = 0"
done
script_="$script_"'
}
function write_all_remaining_vars() {'
local i=0
while [ $i -lt ${#vars_[*]} ]; do
var_="${vars_[$i]}"
sh_var_="${var_//./_}" # nom de la variable shell traduite ("." --> "_")
sh_var_="${sh_var_//-/_}" # ("-" --> "_")
awkre_var_="${var_//./\\\\.}" # nom de la variable pour une expression régulière awk
value_="${values_[$i]}"
script_="$script_"'
if (! '"$sh_var_"'_done) {
print "'"$var_"'=" "'"${value_//\"/\\\"}"'"
'"$sh_var_"'_done = 1
}'
i=$((i + 1))
done
script_="$script_
}"
local i=0
while [ $i -lt ${#vars_[*]} ]; do
var_="${vars_[$i]}"
sh_var_="${var_//./_}" # nom de la variable shell traduite ("." --> "_")
sh_var_="${sh_var_//-/_}" # ("-" --> "_")
awkre_var_="${var_//./\\\\.}" # nom de la variable pour une expression régulière awk
value_="${values_[$i]}"
script_="$script_"'
! '"$sh_var_"'_done && $0 ~ "^[ \t]*'"$awkre_var_"'=" {
#name = gensub("^([ \t]*'"$awkre_var_"'=).*$", "\\1", 1)
match($0, "^[ \t]*'"$awkre_var_"'=")
name = substr($0, RSTART, RLENGTH)
value = substr($0, length(name) + 1)
while (substr(value, length(value), 1) == "\\") {
getline
value = value $0
}
line = name "'"${value_//\"/\\\"}"'"
prefix = ""
max_len = 75
if (length(line) > max_len) {
do {
print prefix substr(line, 1, max_len) "\\"
line = substr(line, max_len + 1)
prefix = " "
max_len = 71
} while (length(line) > max_len)
}
print prefix line
'"$sh_var_"'_done = 1
next
}'
i=$((i + 1))
done
script_="$script_
{
print
}
END {
write_all_remaining_vars()
}"
awk "$script_" <"$file_" >"$file_.$$" &&
/bin/mv "$file_.$$" "$file_"
}
function file_get_xml_properties() {
# lire les propriétés d'un fichier de propriétés xml. Limitation: les
# propriétés ne doivent pas être continuées sur plusieurs lignes. Les
# propriétés doivent être écrites sous la forme::
# <propname>propvalue</propname>
# note: les noms de propriété java peuvent contenir le caractère "." mais
# pas les noms de variable bash. La conversion est faite
# automatiquement. Par exemple::
# file_get_properties build.properties path.to.package "default value"
# charge la valeur de la propriété dans la variable path_to_package
# $1=nom du fichier de propriété
# $2..n=propriétés qu'il faut lire et valeurs par défaut de ces propriétés
# $__2*i __=nom de la propriété
# $__2*i+1__=valeur par défaut de la propriété si la valeur n'existe pas
# dans le fichier
local OENC="$UTF8"
local file_="$1"; shift
if [ ! -f "$file_" ]; then
# fichier inexistant
ewarn "Fichier de propriété inexistant: $file_"
return 1
fi
local var_ sh_var_ awk_var_
local script
while [ -n "$1" ]; do
# pour chacune des variables...
var_="$1"; shift
sh_var_="${var_//./_}" # nom de la variable shell traduite ("." --> "_")
sh_var_="${sh_var_//-/_}" # ("-" --> "_")
awkre_var_="${var_//./\\\\.}" # nom de la variable pour une expression régulière awk
# initialiser la valeur par défaut
set_var "$sh_var_" "$1"; shift
# et créer le script qui affichera sa valeur
script="$script"'
$0 ~ /^[ \t]*<'"$awkre_var_"'>.*<\/'"$awkre_var_"'>/ {
sub(/^[ \t]*<'"$awkre_var_"'>/, "")
sub(/<\/'"$awkre_var_"'>.*$/, "")
gsub("\"", "\\\"", $0)
print "'"$sh_var_"'=\"" $0 "\""
}
'
done
eval "$(awk "$script" <"$file_")"
}
function file_set_xml_properties() {
# écrire des propriétés dans un fichier de propriétés java.
# $1=nom du fichier de propriété
# $2..n=propriétés qu'il faut écrire et valeurs de ces propriétés
# $__2*i __=nom de la propriété
# $__2*i+1__=valeur de la propriété
# traiter les arguments
local OENC="$UTF8"
local done_ create_
while [ -z "$done_" ]; do
case "$1" in
--create|-c)
# créer le fichier s'il n'existe pas
create_=1
shift
;;
*)
done_=1
;;
esac
done
local file_="$1"; shift
if [ ! -f "$file_" ]; then
if [ -n "$create_" ]; then
touch "$file_"
else
# fichier inexistant
ewarn "Fichier de propriété inexistant: $file_"
return 1
fi
fi
# récupérer les noms des propriétés et leur valeur
local var_ arg_ sh_var_ awkre_var_ value_
local -a vars_ values_
value_=vars_
for arg_ in "$@"; do
array_add "$value_" "$arg_"
if [ "$value_" == "vars_" ]; then
value_=values_
else
value_=vars_
fi
done
# créer le script qui va parcourir le fichier pour mettre à jour les valeurs
script_='BEGIN {
rootElement = ""'
for var_ in "${vars_[@]}"; do
sh_var_="${var_//./_}" # nom de la variable shell traduite ("." --> "_")
sh_var_="${sh_var_//-/_}" # ("-" --> "_")
script_="$script_
${sh_var_}_done = 0"
done
script_="$script_"'
}
function write_all_remaining_vars() {'
local i=0
while [ $i -lt ${#vars_[*]} ]; do
var_="${vars_[$i]}"
sh_var_="${var_//./_}" # nom de la variable shell traduite ("." --> "_")
sh_var_="${sh_var_//-/_}" # ("-" --> "_")
awkre_var_="${var_//./\\\\.}" # nom de la variable pour une expression régulière awk
value_="${values_[$i]}"
script_="$script_"'
if (! '"$sh_var_"'_done) {
print "<'"$var_"'>'"${value_//\"/\\\"}"'</'"$var_"'>"
'"$sh_var_"'_done = 1
}'
i=$((i + 1))
done
script_="$script_
}"'
rootElement == "" {
match($0, /<.*>/)
element = substr($0, RSTART + 1, RLENGTH - 2)
firstChar = substr(element, 1, 1)
if (firstChar != "?" && firstChar != "!") {
rootElement = element
}
}'
local i=0
while [ $i -lt ${#vars_[*]} ]; do
var_="${vars_[$i]}"
sh_var_="${var_//./_}" # nom de la variable shell traduite ("." --> "_")
sh_var_="${sh_var_//-/_}" # ("-" --> "_")
awkre_var_="${var_//./\\\\.}" # nom de la variable pour une expression régulière awk
value_="${values_[$i]}"
script_="$script_"'
rootElement != "" && ! '"$sh_var_"'_done && $0 ~ /^[ \t]*<'"$awkre_var_"'>.*<\/'"$awkre_var_"'>/ {
match($0, /^[ \t]*<'"$awkre_var_"'>/)
first = substr($0, RSTART, RLENGTH)
value = substr($0, length(first) + 1)
match(value, /<\/'"$awkre_var_"'>.*$/)
last = substr(value, RSTART, RLENGTH)
value = substr(value, 1, RSTART)
print first "'"${value_//\"/\\\"}"'" last
'"$sh_var_"'_done = 1
next
}'
i=$((i + 1))
done
script_="$script_"'
rootElement != "" && $0 ~ "</" rootElement ">" {
rootElement = ""
write_all_remaining_vars()
}
{
print
}
END {
write_all_remaining_vars()
}'
awk "$script_" <"$file_" >"$file_.$$" &&
/bin/mv "$file_.$$" "$file_"
}
##################################################
# date: fonction pour afficher la date en français et au format RFC-822
function get_date_rfc822() {
if [ -n "$__legacy_date__" ]; then
LC_TIME=C date +"%a, %d %b %Y %H:%M:%S %Z"
else
date -R
fi
}
function get_date_fr() {
date +"%d/%m/%Y"
}
function get_time_fr() {
date +"%Hh%M"
}
function parse_date() {
local value="$1" type="${2:-date}"
local now="$(awk 'BEGIN { print mktime(strftime("%Y %m %d 00 00 00 +0400")) }')"
case "$value" in
+*)
value="$(($now + ${value#+} * 86400))"
;;
*)
value="$(<<<"$value" awk -F/ '{
nd = strftime("%d"); nm = strftime("%m"); ny = strftime("%Y")
d = $1 + 0; if (d < 1 || d > 31) d = nd;
if ($2 == "") m = nm;
else { m = $2 + 0; if (m < 1 || m > 12) m = nm; }
if ($3 == "") y = ny;
else { y = $3 + 0; if (y < 100) y = y + 2000; }
print mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d));
}')"
esac
case "$type" in
d|date)
awk '{ print strftime("%d/%m/%Y", $0 + 0) }' <<<"$value"
;;
l|ldap)
awk '{ print strftime("%Y%m%d%H%M%S+0400", $0 + 0) }' <<<"$value"
;;
*)
echo "$value"
;;
esac
}
##################################################
# path: fonctions pour gérer les chemins
function abspath() {
# Retourner un chemin absolu vers $1. Si $2 est non nul et si $1 est un
# chemin relatif, alors $1 est exprimé par rapport à $2, sinon il est
# exprimé par rapport au répertoire courant.
local pwd="$(pwd)"
if [ -n "$2" ]; then
# tout d'abord, calculer le répertoire à partir duquel on exprime les
# chemin relatifs
if [ -d "$2" ]; then
pwd="$(cd "$2"; pwd)"
else
pwd="$(abspath "$2")"
fi
fi
if [ -e "$1" ]; then
local dn="$(dirname "$1")" bn="$(basename "$1")"
if [ "$bn" == "." ]; then
echo "$(cd "$pwd"; cd "$dn"; pwd)"
elif [ "$bn" == ".." ]; then
echo "$(cd "$pwd"; cd "$dn/.."; pwd)"
elif [ "$dn" == "/" ]; then
echo "/$bn"
else
echo "$(cd "$pwd"; cd "$dn"; pwd)/$bn"
fi
else
if first_char_is "$1" "/"; then
echo "$1"
else
echo "$pwd/$1"
fi
fi
}
function relpath() {
# Retourner le chemin relatif de $1 par rapport à $2. Si $2 n'est pas
# spécifié, on prend le répertoire courant. Si $1 ou $2 ne sont pas des
# répertoires absolus, il sont transformés en chemins absolus par rapport à
# $3.
# Si $1==$2, retourner une chaine vide
local p="$(abspath "$1" "$3")" cwd="$2"
if [ -z "$cwd" ]; then
cwd="$(pwd)"
else
cwd="$(abspath "$cwd" "$3")"
fi
if [ "$p" == "$cwd" ]; then
echo ""
elif [ "${p#$cwd/}" != "$p" ]; then
echo "${p#$cwd/}"
else
local rp
while [ -n "$cwd" -a "${p#$cwd/}" == "$p" ]; do
rp="${rp:+$rp/}.."
cwd="${cwd%/*}"
done
rp="$rp/${p#$cwd/}"
# ${rp%//} traite le cas $1==/
echo "${rp%//}"
fi
}
function deref() {
# Retourner un chemin absolu vers le fichier $1, dans lequel
# toutes les composantes "lien symbolique" ont été supprimées.
local OENC="$UTF8"
local max_deref=50
local file="$1"
while [ -L "$file" ]; do
basedir="$(dirname "$file")"
link="$(readlink "$file")"
if first_char_is "$link" "/"; then
# lien absolu
file="$link"
else
# lien relatif
file="$basedir/$link"
fi
max_deref=$(($max_deref - 1))
[ $max_deref -eq 0 ] && die "Plus de 50 indirection. Le lien $file est-il récursif?"
done
abspath "$file"
}
function path_if_test() {
# afficher un chemin si le fichier $2 existe (en utilisant l'opérateur $1)
# dans l'un des chemins absolus $4..n. si $3==relative, afficher le chemin
# relatif, sinon le chemin absolu. note: $3 peut être de la forme
# relative:path, auquel cas le chemin affiché est exprimé relativement à
# path
local op_="$1"; shift
local file_="$1"; shift
local rel_="$1" reldir_=; shift
if beginswith "$rel_" relative; then
reldir_="${rel_#relative}"
if beginswith "$reldir_" :; then
# on a un argument de la forme relative:path
reldir_="${reldir_#:}"
if [ -n "$reldir_" ]; then
reldir_="${reldir_}/"
fi
else
# argument vide ou format non valide
reldir_=
fi
else
rel_=
fi
while [ -n "$1" ]; do
local basedir_="$1"
if [ $op_ "$basedir_/$file_" ]; then
if [ -n "$rel_" ]; then
echo "$reldir_$file_"
else
echo "$basedir_/$file_"
fi
break
fi
shift
done
}
function is_archive() {
# tester si l'extension d'un fichier indique que c'est une archive
local name="${1%.zip}"
name="${name%.tgz}"
name="${name%.tar.gz}"
name="${name%.tar}"
name="${name%.tar.bz2}"
name="${name%.jar}"
name="${name%.war}"
name="${name%.ear}"
[ "$name" != "$1" ]
}
function extract_archive() {
# Extraire le contenu de l'archive $1 dans le répertoire ${2:-.}
# Les autres arguments indiquent les fichiers à extraire
local arch="$1" destdir="${2:-.}"
shift; shift
if endswith "$arch" .zip; then
unzip -d "$destdir" "$arch" "$@" || return
elif endswith "$arch" .tgz || endswith "$arch" .tar.gz; then
tar xzf "$arch" -C "$destdir" "$@" || return
elif endswith "$arch" .tbz2 || endswith "$arch" .tar.bz2; then
tar xjf "$arch" -C "$destdir" "$@" || return
elif endswith "$arch" .tar; then
tar xf "$arch" -C "$destdir" "$@" || return
elif endswith "$arch" .jar || endswith "$arch" .war || endswith "$arch" .ear; then
jar xf "$arch" -C "$destdir" "$@" || return
else
return 1
fi
}
##################################################
# array: fonctions pour gérer des tableaux
# Afficher la commande permettant d'initialiser le tableau $1 avec les valeurs:
# soit du tableau $2, soit de $3..$n si $2=="@"
# S'il n'y a que l'argument $1, alors afficher la commande permettant de
# recréer le tableau $1
function set_array_cmd() {
[ $# -eq 1 ] && set -- "$1" "$1"
local s_ v_ f_
s_="$1=("; shift
if [ "$1" == "@" ]; then
shift
else
eval "set -- \"\${$1[@]}\""
fi
f_=1
for v_ in "$@"; do
[ -n "$f_" ] && f_= || s_="$s_ "
s_="$s_\"$(quote_arg "$v_")\""
done
s_="$s_)"
echo "$s_"
}
# Soit $1 un tableau à créer. Si $2=="@", créer le tableau $1 avec les valeurs
# $3..$n. Sinon, créer le tableau $1 avec les valeurs du tableau $2.
# Cette fonction n'existe que comme un pendant de set_var(), mais le véritable
# intérêt est la fonction set_array_cmd(). cf array_copy() pour une version plus
# efficace de la copie de tableaux
function set_array() {
eval "$(set_array_cmd "$@")"
}
function array_count() {
# retourner le nombre d'éléments du tableau $1
eval "echo \${#$1[*]}"
}
function array_isempty() {
# tester si un tableau est vide
test $(array_count "$1") -eq 0
}
function array_new() {
# créer un tableau vide dont le nom est $1
eval "$1=()"
}
function array_add() {
# ajouter la valeur $2 au tableau dont le nom est $1
eval "$1=(\"\${$1[@]}\" \"$(quote_arg "$2")\")"
}
# insérer la valeur $2 au début du tableau dont le nom est $1
function array_ins() { eval "$1=(\"$(quote_arg "$2")\" \"\${$1[@]}\")"; }
function array_add_values() {
# Ajouter les valeurs $2 au tableau dont le nom est $1
# $2 est une liste de valeurs séparées par des espaces ou le caractère ':'
local array_="$1" value_
if [[ "$2" == *:* ]]; then
local IFS=:
set -- $2
unset IFS
else
set -- $2
fi
for value_ in "$@"; do
array_add "$array_" "$value_"
done
}
function array_del() {
# supprimer les valeurs $2 du tableau dont le nom est $1
local arg_="$(quote_arg "$2")" value_
local -a array_
eval 'for value_ in "${'"$1"'[@]}"; do if [ "$value_" != "'"$arg_"'" ]; then array_add array_ "$value_"; fi; done'
array_copy "$1" array_
}
function array_set() {
# ajouter la valeur $2 au tableau dont le nom est $1, si la valeur n'y est
# pas déjà. Retourner vrai si la valeur a été ajoutée
local value_="$(quote_arg "$2")" i_
eval "for i_ in \"\${$1[@]}\"; do if [ \"\$i_\" == \"$value_\" ]; then return 1; fi; done"
array_add "$1" "$2"
return 0
}
function array_contains() {
# tester si le tableau dont le nom est $1 contient la valeur $2
local value_="$(quote_arg "$2")" i_
eval "for i_ in \"\${$1[@]}\"; do if [ \"\$i_\" == \"$value_\" ]; then return; fi; done"
return 1
}
function array_copy() {
# copier le contenu du tableau $2 dans le tableau $1
eval "$1=(\"\${$2[@]}\")"
}
function array_extend() {
# Ajouter le contenu du tableau $2 au tableau $1
eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"
}
# dans le tableau $1, remplacer toutes les occurences de $2 par $3..*
function array_replace() {
local srcname_="$1"; shift
local from_="$1"; shift
local -a dest_
local src_ v_
src_="$srcname_[@]"
for value_ in "${!src_}"; do
if [ "$value_" == "$from_" ]; then
dest_=("${dest_[@]}" "$@")
else
dest_=("${dest_[@]}" "$value_")
fi
done
array_copy "$srcname_" dest_
}
# Pour chacune des valeurs 'v' du tableau $1, appeler la fonction $2 avec les
# arguments '$v $3..$n'
function array_each() {
local an_="$1"; shift
local f_="$1"; shift
local a_="$an_[@]" v
for v_ in "${!a_}"; do
"$f_" "$v_" "$@"
done
}
# retourner la première valeur du tableau $1
function first_value() { eval "echo \"\${$1[@]:0:1}\""; }
# retourner la dernière valeur du tableau $1
function last_value() { eval "echo \"\${$1[@]:\$((-1)):1}\""; }
# copier le contenu du tableau $2 dans le tableau $1
function array_copy() { eval "$1=(\"\${$2[@]}\")"; }
# copier tous les valeurs du tableau $2(=$1) dans le tableau $1, excepté la dernière
function array_copy_firsts() { eval "$1=(\"\${${2:-$1}[@]:0:\$((\${#${2:-$1}[@]}-1))}\")"; }
function array_del_last() { array_copy_firsts "$1"; }
# copier tous les valeurs du tableau $2(=$1) dans le tableau $1, excepté la première
function array_copy_lasts() { eval "$1=(\"\${${2:-$1}[@]:1}\")"; }
function array_del_first() { array_copy_lasts "$1"; }
# ajouter le contenu du tableau $2 au tableau $1
function array_extend() { eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"; }
# ajouter toutes les valeurs du tableau $2 dans le tableau $1, excepté la dernière
function array_extend_firsts() { eval "$1=(\"\${$1[@]}\" \"\${$2[@]:0:\$((\${#$2[@]}-1))}\")"; }
# ajouter toutes les valeurs du tableau $2 dans le tableau $1, excepté la première
function array_extend_lasts() { eval "$1=(\"\${$1[@]}\" \"\${$2[@]:1}\")"; }
# Pour chacune des valeurs 'v' du tableau $1, appeler la fonction $2 avec les
# arguments '$v $3..$n', et remplacer la valeur par le résultat de la fonction
function array_map() {
local an_="$1"; shift
local f_="$1"; shift
local a_="$an_[@]" v
local -a vs_
for v_ in "${!a_}"; do
vs_=("${vs_[@]}" "$("$f_" "$v_" "$@")")
done
array_copy "$an_" vs_
}
function array_from_args() {
# créer le tableau dont le nom est $1 avec les arguments à partir de $2
local array_="$1"; shift
eval "$array_"'=("$@")'
}
function array_from_file() {
# créer le tableau dont le nom est $1 avec les lignes du fichier $2
# si $3=all, ne pas supprimer les lignes vide ou de commentaire
eval "$(<"$2" uawk -v name="$1" -v all="$3" '
BEGIN {
print name "=("
}
all != "all" && $0 ~ /^$/ { next }
all != "all" && $0 ~ /^#/ { next }
{
gsub(/'\''/, "'\'\\\\\'\''")
print "'\''" $0 "'\''"
}
END {
print ")"
}')" #"
}
function array_from_lines() {
# créer le tableau $1 avec chaque ligne de $2. Les lignes vides sont
# ignorés.
eval "$(<<<"$2" uawk -v name="$1" '
BEGIN {
print name "=("
}
/^$/ { next }
{
gsub(/'\''/, "'\'\\\\\'\''")
print "'\''" $0 "'\''"
}
END {
print ")"
}')" #"
}
function array_split() {
# créer le tableau $1 avec chaque élément de $2 (un ensemble d'éléments
# séparés par $3, qui vaut ':' par défaut). Les éléments vides sont
# ignorés. par exemple "a::b" est équivalent à "a:b"
eval "$(<<<"$2" uawk -v RS="" -v ORS="" '{ gsub("\r*\n$", ""); print }' |
uawk -v name="$1" -v RS="${3:-:}" '
BEGIN {
print name "=("
}
/^$/ { next }
{
gsub(/'\''/, "'\'\\\\\'\''")
print "'\''" $0 "'\''"
}
END {
print ")"
}')" #"
}
function array_from_path() {
array_split "$1" "$2" ":"
}
function array_join() {
# afficher le contenu du tableau dont le nom est $1 sous forme d'une liste
# de chemins séparés par $2
# Si $1=="@", alors les éléments du tableaux sont les arguments de la
# fonction à partir de $3
# Si $1!="@" et que le tableau est vide, afficher $3
# Si $1!="@", $4 et $5 sont des préfixes et suffixes à rajouter à chaque élément
local array_ line_ joined_ sep_="${2:-,}" pfix_ sfix_
if [ "$1" == "@" ]; then
array_="\$@"
shift; shift
else
array_="\${$1[@]}"
pfix_="$4"
sfix_="$5"
fi
eval 'for line_ in "'"$array_"'"; do joined_="${joined_:+$joined_'"$sep_"'}$pfix_$line_$sfix_"; done'
if [ -n "$joined_" ]; then
echo "$joined_"
elif [ "$array_" != "\$@" -a -n "$3" ]; then
echo "$3"
fi
}
function array_to_lines() {
# afficher le tableau dont le nom est $1 sous forme de lignes
array_join "$1" "
" "$2" "$3" "$4"
}
function array_to_path() {
# afficher le tableau dont le nom est $1 sous forme d'une liste de chemins
# séparés par ':')
array_join "$1" ":" "$2" "$3" "$4"
}
function array_enum_start() {
# Commencer l'énumération du tableau $1
[ -z "$1" ] && return 1
set_var_literal "${1}_enum_index" 0
}
function array_enum_next() {
# Soit la variable array dont le nom est donné dans $1, et la variable next
# dont le nom est donné dans $2. Mettre à jour next avec l'élément
# $1_enum_index du tableau array, supprimer cet élément, et incrémenter
# $1_enum_index. Retourner faux s'il n'y a plus d'éléments dans le tableau
local arrayname_="$1" varname_="$2"
[ -z "$arrayname_" -o -z "$varname_" ] && return 1
eval "local count_=\${#$arrayname_[*]}"
[ $count_ -eq 0 ] && return 1
# calculer l'index de départ
local index_="${arrayname_}_enum_index"
[ -z "${!index_}" ] && set_var_literal "$index_" 0
# lire la valeur
local item_="$arrayname_[${!index_}]"
set_var "$varname_" "${!item_}"
# la supprimer du tableau
unset "$item_"
# incrémenter le compteur
set_var_literal "$index_" $((${!index_} + 1))
}
function __array_ls() {
# Lister les fichiers avec `list_$1 $3 $4...`, et les mettre dans le tableau $2
# Le tableau contient les chemins complets, par seulement les noms comme avec list_$1
local list_="list_${1:-all}"; shift
local arrayname_="$1"; shift
local basedir_="${1:-.}"; shift
local -a files_
array_from_lines files_ "$("$list_" "$basedir_" "$@")"
local file_
array_new "$arrayname_"
for file_ in "${files_[@]}"; do
array_add "$arrayname_" "$basedir_/$file_"
done
}
function array_lsall() {
# Lister les fichiers avec `list_all $2 $3...`, et les mettre dans le tableau $1
# Le tableau contient les chemins complets, par seulement les noms comme avec list_all
__array_ls all "$@"
}
function array_lsdirs() {
# Lister les fichiers avec `list_dirs $2 $3...`, et les mettre dans le tableau $1
# Le tableau contient les chemins complets, par seulement les noms comme avec list_dirs
__array_ls dirs "$@"
}
function array_lsfiles() {
# Lister les fichiers avec `list_files $2 $3...`, et les mettre dans le tableau $1
# Le tableau contient les chemins complets, par seulement les noms comme avec list_files
__array_ls files "$@"
}
##################################################
# Accès à une resource web
function _dumpurl_method_available() {
# $1=dumpurl_method
local m="$1"
if [ "$m" == "curl" ]; then
progexists curl || [ -n "$__curl_EXISTS__" ]
elif [ "$m" == "wget" ]; then
if progexists wget || [ -n "$__wget_EXISTS__" ]; then
# vérifier la version ce doit être >= 1.9
wget --version | grep "^GNU Wget" | awk '{
v = $0
major = 0
minor = 0
if (match(v, /[0-9][0-9]*/) != 0) {
major = substr(v, RSTART, RLENGTH) + 0
v = substr(v, RSTART + RLENGTH + 1)
}
if (match(v, /[0-9][0-9]*/) != 0) {
minor = substr(v, RSTART, RLENGTH) + 0
v = substr(v, RSTART + RLENGTH + 1)
}
if (major >= 1 && minor >= 9) {
exit 0
} else {
exit 1
}
}'
fi
else
return 1
fi
}
function dumpurl_method() {
if [ -z "$DUMPURL_METHOD" ]; then
local DUMPURL_METHOD
if _dumpurl_method_available curl; then
DUMPURL_METHOD=curl
elif _dumpurl_method_available wget; then
DUMPURL_METHOD=wget
## XXX telnet non supporté pour le moment
#elif progexists telnet; then
# DUMPURL_METHOD=telnet
fi
fi
echo "$DUMPURL_METHOD"
}
function dumpurl_available() {
# retourner vrai si dumpurl est disponible (si wget ou curl sont trouvés)
_dumpurl_method_available "$(dumpurl_method)"
}
function dumpurl() {
# afficher le résultat du téléchargement de l'url $1, ou une chaine vide si
# une erreur s'est produite.
# l'option -m choisit la méthode: GET ou POST (suivi de la chaine à envoyer)
# l'option -H permet d'ajouter des en-têtes
local done= http_method=GET postdata headers header url no_proxy
local -a headers
while [ -n "$1" ]; do
case "$1" in
--)
shift
done=1
;;
-m)
shift
http_method="$1"
if [ "$http_method" == "POST" ]; then
postdata="$2"
shift
fi
;;
-H)
shift
array_add headers "$1: $2"
shift
;;
-X)
no_proxy=1
;;
-*)
#ewarn "option non reconnue: $1"
;;
*)
done=1
;;
esac
[ -n "$done" ] && break
shift
done
url="$1"
dumpurl_available || return 1
local dumpurl_method="$(dumpurl_method)"
if [ "$dumpurl_method" == "curl" ]; then
curl="curl${no_proxy:+ -x ''}"
for header in "${headers[@]}"; do
curl="$curl --header \"$(quote_arg "$header")\""
done
if [ "$http_method" == "GET" ]; then
:
elif [ "$http_method" == "POST" ]; then
curl="$curl --data-binary \"$(quote_arg "$postdata")\""
else
# méthode inconnue
return 1
fi
curl="$curl -f -s \"$(quote_arg "$url")\""
eval "$curl"
elif [ "$dumpurl_method" == "wget" ]; then
wget="wget${no_proxy:+ --no-proxy}"
for header in "${headers[@]}"; do
wget="$wget --header=\"$(quote_arg "$header")\""
done
if [ "$http_method" == "GET" ]; then
:
elif [ "$http_method" == "POST" ]; then
wget="$wget --post-data=\"$(quote_arg "$postdata")\""
else
# méthode inconnue
return 1
fi
wget="$wget -q -O - \"$(quote_arg "$url")\""
eval "$wget"
# XXX pas encore implémenté
#elif [ "$dumpurl_method" == "telnet" ]; then
# return 1
else
return 1
fi
}