# -*- 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 "------") | while read line_; do if [ "$line_" == "------" ]; 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:: # propvalue # 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_//\"/\\\"}"'" '"$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 = "" 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 }