From 1fccb5a900832e5a3cb6f30bc25ea4b225fd75db Mon Sep 17 00:00:00 2001 From: Jephte CLAIN Date: Sun, 12 Oct 2014 22:54:49 +0400 Subject: [PATCH] fnconv accepte une liste de commandes --- fnconv | 313 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 225 insertions(+), 88 deletions(-) diff --git a/fnconv b/fnconv index da6f157..2dd940d 100755 --- a/fnconv +++ b/fnconv @@ -1,100 +1,237 @@ #!/bin/bash # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 - -function display_help() { - uecho "$scriptname: renommer des fichiers en changeant leur encoding - -USAGE - $scriptname [-f src_enc] [ -t dest_enc] [/path/to/file] - -OPTIONS - -f from - Encoding source. Si n'est pas spécifié ou vaut 'detect', l'encoding est - autodétecté. - -t to - Encoding destination. Doit être spécifié. - -N Ne pas optimiser le calcul de l'encoding. Cette option n'est valide que - si -f n'est pas spécifié. On assume que tous les noms de fichiers n'ont - pas le même encoding. L'encoding from est donc recalculé à chaque fois. - -r inverser from et to, qui doivent être tous les deux spécifiés." -} - -if [ "$#" -eq 1 -a "$1" == --nutools-makelinks ]; then - # créer les liens - scriptname="$(basename "$0")" - for destenc in latin1 utf8; do - ln -s "$scriptname" "${scriptname}2$destenc" - done - exit 0 -fi - source "$(dirname "$0")/lib/ulib/ulib" || exit 1 urequire DEFAULTS -from=detect -case "${scriptname#fnconv2}" in -utf8) to=utf-8;; -latin1) to=iso-8859-1;; -*) to=;; -esac -optimize=1 -parse_opts "${PRETTYOPTS[@]}" \ - --help '$exit_with display_help' \ - -f: from= \ - -t: to= \ - -N optimize= \ - -r reverse \ - @ args -- "$@" && set -- "${args[@]}" || die "$args" +function display_help() { + uecho "$scriptname: renommer un fichier ou les fichiers d'un répertoire -function fnconv() { - # $1 = fichier à renommer - local lfrom="$from" lto="$to" - local srcdir="$(dirname "$1")" - local srcname="$(basename "$1")" - if [ "$lfrom" == "detect" ]; then - lfrom="$("$scriptdir/lib/pywrapper" uencdetect.py "$srcname")" - if [ "$lfrom" == "Unknown" ]; then - eerror "$srcname: Impossible de déterminer l'encoding" - return 1 - fi - if [ -n "$optimize" ]; then - from="$(__norm_encoding "$lfrom")" - [ "$from" != "$to" ] && enote "Conversion $from --> $to" - fi - fi - if [ -n "$optimize" -a "$from" == "$to" ]; then - die "Une conversion de $from à $to n'a pas de sens. -Veuillez re-essayer avec -N si nécessaire." - fi +USAGE + $scriptname [options] [cmds...] - if [ -n "$reverse" ]; then - tmp="$lto" - lto="$lfrom" - lfrom="$tmp" - fi +Une ou plusieurs commandes peuvent être spécifiées, séparées // +La commande par défaut est 'fixcase' - local src="$(abspath "$srcdir/$srcname")" - local dest - dest="$srcdir/$(iconv -f "$lfrom" -t "$lto" <<<"$srcname")" || return 1 - dest="$(abspath "$dest")" - if [ "$src" != "$dest" ]; then - ebegin "$(ppath "$src") --> $(basename "$dest")" \ - mv "$src" "$dest" - fi - src="$dest" - if [ -d "$src" ]; then - etitle -s "$(ppath "$src")" - local subsrcs subsrc - array_lsall subsrcs "$src" - for subsrc in "${subsrcs[@]}"; do - fnconv "$subsrc" - done - eend +OPTIONS + -N, --detect-always + Pour la commande conv, ne pas optimiser le calcul de l'encoding. Cette + option n'est valide que si src_enc n'est pas spécifié. On assume que + tous les fichiers n'ont pas le même encoding: l'encoding src_enc est + donc recalculé à chaque fois. + -r, --reverse + Pour la commande conv, inverser src_enc et dest_enc, qui doivent être + tous les deux spécifiés. + +COMMANDES + conv dest_enc [src_enc] + Convertir le nom du fichier dans un autre encoding. + dest_enc est l'encoding destination. Il doit être spécifié. + src_enc est l'encoding source. S'il n'est pas spécifié ou vaut 'detect', + il est autodétecté. + utf8 [src_enc] + Equivalent à conv utf8 src_enc + latin1 [src_enc] + Equivalent à conv latin1 src_enc + noaccents + Transformer les caractères accentués en caractères non accentués + lowercase + Transfomer le nom en minuscule + uppercase + Transformer le nom en majuscule + fixcase + Transformer le nom en minuscule s'il est entièrement en majuscule" +} + +function _lowercase() { + evalx cat // strlower +} +function _uppercase() { + evalx cat // strupper +} +function _fixcase() { + local actual upper + setx actual=cat + setx upper=strupper "$actual" + if [ "$actual" == "$upper" ]; then + strlower "$actual" + else + echo "$actual" fi } -[ -n "$to" ] || die "Il faut spécifier l'encoding de destination" -to="$(__norm_encoding "$to")" -for src in "$@"; do - fnconv "$src" +function detect_enc() { + local filename enc + if [ -f "$1" ]; then + setx filename=basename -- "$1" + elif [ -d "$1" ]; then + local -a files + setx -a files=evalp find "$1" // head -n1 + if [ ${#files[*]} -gt 0 ]; then + setx filename=basename -- "${files[0]}" + fi + fi + setx enc="$scriptdir/lib/pywrapper" uencdetect.py "$filename" + echo "$enc" + [ "$enc" != Unknown ] +} + +function before_parse_cmd() { + case "$1" in + conv) + if [ -n "$OPTIMIZE_CONV" ]; then + local to="$2" + [ -n "$to" ] && setx CONV_TO=__norm_encoding "$to" + + local from="${3:-detect}" + if [ "$from" == "detect" ]; then + setx from=detect_enc "$FILE" + if [ "$from" == "Unknown" ]; then + echo "$FILE: Impossible de détecter l'encoding" + return 1 + fi + fi + [ -n "$from" ] && setx CONV_FROM=__norm_encoding "$from" + OPTIMIZE_CONV= + fi + ;; + esac +} + +function iconv_detect() { + local to="$1"; shift + local from + if setx from=detect_enc "$FILE"; then + if [ -n "$REVERSE_CONV" ]; then + local tmp="$to" + to="$from" + from="$tmp" + fi + iconv -f "$from" -t "$to" "$@" + return 0 + else + cat + return 1 + fi +} + +function parse_cmd() { + local cmd="$1"; shift + local -a args + case "$cmd" in + utf8) parse_cmd conv utf8 "$@";; + latin1) parse_cmd conv latin1 "$@";; + conv) + local to="$CONV_TO" from="$CONV_FROM" + [ -n "$to" ] || to="$1"; shift + [ -f "$from" ] || from="${1:-detect}"; shift + + if [ -z "$to" ]; then + echo "conv: vous devez spécifier l'encoding destination" + return 1 + fi + setx to=__norm_encoding "$to" + if [ "$from" == "detect" ]; then + qvals iconv_detect "$to" "$@" + else + setx from=__norm_encoding "$from" + if [ "$from" == "$to" ]; then + echo "Une conversion de $from à $to n'a pas de sens. Veuillez re-essayer avec -N si nécessaire." + return 1 + fi + if [ -n "$REVERSE_CONV" ]; then + local tmp="$to" + to="$from" + from="$tmp" + fi + qvals iconv -f "$from" -t "$to" "$@" + fi + ;; + noaccents|noa|fixchars) echo _noaccents;; + lowercase|lower|l) echo _lowercase;; + uppercase|upper|U) echo _uppercase;; + fixcase|fix|c) echo _fixcase;; + *) + echo "$cmd: commande invalide" + return 1 + ;; + esac + return 0 +} + +function fnconv() { + local dir oldname newname + setx dir=dirname -- "$FILE" + setx oldname=basename -- "$FILE" + setx newname=eval "$CMD" <<<"$oldname" + + if [ -d "$FILE" ]; then + if [ "$newname" != "$oldname" ]; then + etitle "$(ppath "$FILE") --> $newname" + mv "$FILE" "$dir/$newname" || die + FILE="$dir/$newname" + else + etitle "$(ppath "$FILE")" + fi + local -a sfiles + array_lsall sfiles "$FILE" + for FILE in "${sfiles[@]}"; do + fnconv + done + eend + else + if [ "$newname" != "$oldname" ]; then + estep "$oldname --> $newname" + mv "$FILE" "$dir/$newname" || die + FILE="$dir/$newname" + fi + fi +} + +OPTIMIZE_CONV=1 +REVERSE_CONV= +CONV_FROM= +CONV_TO= +parse_opts "${PRETTYOPTS[@]}" \ + --help '$exit_with display_help' \ + -N,--detect-always OPTIMIZE_CONV= \ + -r,--reverse REVERSE_CONV=1 \ + @ args -- "$@" && set -- "${args[@]}" || die "$args" + +FILE="$1"; shift +[ "$FILE" == - ] && FILE=/dev/stdin +if [ "$FILE" != /dev/stdin ]; then + [ -e "$FILE" ] || die "$FILE: fichier introuvable" +fi + +[ $# -gt 0 ] || set -- fixcase # commande par défaut + +CMD= # la commande finale à lancer pour convertir le flux +while [ $# -gt 0 ]; do + args=() + while [ $# -gt 0 ]; do + arg="$1"; shift + if [ "$arg" == // ]; then + break + elif [ "${arg%//}" != "$arg" ]; then + local tmp="${arg%//}" + if [ -z "${tmp//\\/}" ]; then + arg="${arg#\\}" + fi + fi + args=("${args[@]}" "$arg") + done + + if [ ${#args[*]} -gt 0 ]; then + before_parse_cmd "${args[@]}" + setx cmd=parse_cmd "${args[@]}" || die "$cmd" + CMD="${CMD:+$CMD | }$cmd" + fi done + +if [ "$FILE" == /dev/stdin ]; then + eval "$CMD" +elif [ -f "$FILE" -o -d "$FILE" ]; then + fnconv +else + die "$FILE: fichier invalide" +fi