#!/bin/bash

### Transcripteur en Art Ascii - transcii
#
#  À FAIRE :
#     - Alphabet :  (en cours)
#        - profile < 0  ==> profile=0, à voir.
#        - Affiner les csv de l'alphabet (en cours…)
#
### by Tawal®©

version="2023-06-23"

### Variables personnalisables
# Priorité aux variables d'environnement respectives.

    # Fichier de dessins Ascii par défaut (modifiable via l'option '-d').
    # Si non renseigné et sans l'option '-d', utiliser le fichier embarqué.
[ "$Draws" ] || \
Draws=""

    # Par défaut nombre d'espaces pour un espace dans le texte à convertir.
    # Valeur modifiable via l'option '-s'.
[ "$Spaces" ] || \
Spaces=5



### Variables ne pouvant pas provenir de l'environnement (ou Init global ^^) :
Name="${0##*/}"
texte=""
opt_c=""; opt_f=""; opt_i=""; opt_o=""; opt_q=""; opt_s=""; opt_v=""
opt_o_arg=""
arg_abs=""

### Fonctions
_usage_quit ()
{     # Notice d'utilisation
   local surb="\e[1m" ital="\e[3m" rst="\e[m"
   local n l="${#Name}"
   echo -e "Transcripteur en Art Ascii - $Name

${surb}Usage :${rst}

   $Name [-c[-i]] [-d ${surb}FILE${rst}] [-o ${surb}FILE_OUT${rst}] [-s ${surb}N${rst}] [-v…] ${surb}TEXTE…${rst}
   $Name [-c[-i]] [-d ${surb}FILE${rst}] [-o ${surb}FILE_OUT${rst}] [-s ${surb}N${rst}] [-v…] < ${surb}TEXTFILE${rst}
   ${surb}COMMAND${rst} | $Name [-c[-i] [-d ${surb}FILE${rst}] [-o ${surb}FILE_OUT${rst}] [-s ${surb}N${rst}] [-v…]
   $Name --quit [-d ${surb}FILE${rst}] [-v…]
   $Name --help


${surb}Description :${rst}

   Convertir un texte ${surb}TEXTE${rst} ou un fichier ${surb}TEXTFILE${rst} ou un retour de ${surb}COMMAND${rst} en un
   texte d'Art Ascii et afficher le résultat.
   Un fichier de dessins d'Art Ascii est embarqué.
   Par défaut, ce fichier est utilisé à moins que l'option '${surb}--draws${rst}' ne soit
   donnée, ou que la variable d'environnement ${surb}Draws${rst} ne soit renseignée ou écrite
   en dur dans ce script.
   Dans cette notice, le terme ${surb}Ascii${rst} désigne un dessin d'Art Ascii.
   ${surb}Attention :${rst} Désactiver les retours à ligne automatiques pour afficher
   correctement le dessin d'Art Ascii d'une longue ligne convertie.


${surb}Options :${rst}

   Les arguments obligatoires aux options longues le sont aussi aux courtes.
   Les options inutiles dans la ligne de commande sont signalées.

   -c,--check        Vérifier le fichier de dessins Ascii.
                     (Voir ${surb}Format${rst} et ${surb}Vérification${rst} plus bas)
                     Quitter après la vérification totale si une erreur ou plus
                     est rencontrée sauf si l'option '${ital}--ignore${rst}' est renseignée.
                     Afficher si le fichier est conforme ou non.
                     Lister les erreurs rencontrées au niveau de verbosité 1.

   -d,--draws ${surb}FILE${rst}   Indiquer le fichier de dessins Ascii.
                     ${surb}FILE${rst} doit être lisible par l'utilisateur.
                     Prévaut sur la variable d'environnement ${surb}Draws${rst} et sur
                     l'affectation en dur dans ce script de cette variable.

   -f,--force-out    Seulement avec l'option '${ital}--out${rst}'.
                     Forcer l'écrasement du fichier ${surb}FILE_OUT${rst} s'il existe déjà.

   -h,--help         Afficher cette aide et quitter.

   -i,--ignore       Seulement avec l'option '${ital}--check${rst}'.
                     Ignorer les erreurs lors de la vérification du fichier de
                     dessins Ascii. Si des erreurs sont rencontrées, tenter tout
                     de même de convertir.

   -o,--out ${surb}FILE_OUT${rst} Indiquer le fichier de sortie ${surb}FILE_OUT${rst}.
                     Le fichier ${surb}FILE_OUT${rst} ne contient que le résultat final et
                     doit avoir les droits en écriture et ne doit pas exister
                     sinon sortie du programme avec erreur.
                     Les retours '${ital}terminal${rst}' restent actifs.

   -q,--quit         Implique silencieusement l'option '${ital}--check${rst}'.
                     Quitter après la vérification du fichier de dessins Ascii
                     sans convertir.
                     L'option '${ital}--check${rst}' est inutile et non signalée.
                     Les entrées ${surb}TEXTE…${rst} etc sont silencieusement ignorées.

   -s,--spaces ${surb}N${rst}     ${surb}N${rst} espaces insérés dans le dessin final pour un espace dans
                     le texte à convertir.
                     ${surb}N${rst} doit être un entier positif.
                     Par défaut, 5 espaces insérés.
                     Prévaut sur la variable d'environnement ${surb}Spaces${rst} et sur
                     l'affectation en dur dans ce script de cette variable.

   -v,--verbose      Rendre le programme plus parlant.
                     Option répétable 3 fois.
                     Niveaux de verbosité (${ital}-v${rst}, ${ital}-vv${rst}, ${ital}-vvv${rst}) :
                        -v   : + Affichage du texte à convertir.
                               + Affichage des stastitiques du fichier de
                                 dessins Ascii :
                                   - Hauteur totale (nb de lignes par dessin).
                                   - N° de ligne de référence.
                                   - Nombre de dessins Ascii trouvés au total.
                                   - Nombre de dessins Ascci accessibles.
                                   - Liste des caractères dessinables.
                                   - Affichage des caractères ayant plusieurs
                                     définitions + celui retenu.
                               + Affichage des erreurs dans le fichier de
                                 dessins Ascii si vérification de ce dernier.
                               + Indication de la non vérification du fichier de
                                 dessins Ascii.
                               + Affichage des caractères non trouvés dans le
                                 fichier de dessins Ascii.
                               + Affichage des collisions entre dessins dûes aux
                                 données CSV.

                        -vv  : + Même affichage que le niveau 1.
                               + Affichage de la construction du dessin Ascii.

                        -vvv : + Même affichage que le niveau 2.
                               + Affichage de tous les dessins Ascii trouvés et
                                 accessibles dans le fichier de dessins Ascii et
                                 de leurs données CSV.
                               + Affichage du dessin Ascci à ajouter et de
                                 données de débogage.
                               + Affichage plus détaillé de la construction du
                                 texte Ascii.

   -V,--version      Afficher la version et quitter.


${surb}Fichier embarqué de dessins Ascii :${rst}

   Le fichier embarqué ${ital}/tmp/$Name.ascii${rst} est créé en cas d'utilisation.
   Il n'est pas supprimé à la sortie du programme. Il reste disponible et n'est
   pas recréé s'il existe déjà.
   Il respecte le format décrit ci-dessous.
   Particularité :
   Il possède 2 dessins ayant la même clé '${surb}car=ß${rst}' dans leur ligne CSV.
   C'est pour illustrer la différence de comportement avec ou sans vérification.
   Le caractère doublement défini est le 'ß' (non pas '${ital}beta${rst}' mais '${ital}eszett${rst}').
   Cet «effet» permet d'avoir 2 jeux de caractères de dessins Ascii dans le même
   fichier de dessins. Utilisation de l'un ou l'autre mais pas les 2 mélangés.
   Essayez :
       ${ital}$ $Name -v ß${rst}
     et
       ${ital}$ $Name -cv ß${rst}


Les parties ${surb}Format${rst} et ${surb}Vérification${rst} sont là pour ceux qui veulent comprendre
et/ou créer leur propre fichier de dessins d'Art Ascii.

${surb}Format du fichier de dessins Ascii :${rst}

   - Commentaires en entête seulement et précédés du caractère '#' en début de
     ligne. Des lignes vides peuvent séparer des blocs de commentaires et finir
     le dernier bloc de commentaires.

   - Pas de 'blancs' en fin de ligne, dessin Ascii compris.

   - Toute ligne vide en dehors de l'entête du fichier sera comprise dans le
     dessin Ascii décrit par la ligne CSV (voir ${surb}Ligne CSV${rst} plus bas).

   - Dessin Ascii - composé de :
      * Une ligne de données CSV.
        CSV = Comma Separated Values : Valeurs Séparées par des Virgules.
        Ici, les Valeurs sont du format : ${surb}Clé=Valeur[ Valeur2]…${rst}
        appelées '${surb}clé${rst}' désignant aussi bien la ${surb}Clé${rst} que l'ensemble ${surb}Clé=Valeurs…${rst}

      * Les lignes suivantes composant le dessin Ascii jusqu'à la prochaine
        ligne CSV rencontrée ou la fin de fichier.


   - Ligne CSV - composée de :
      * La clé '${surb}car=1-seul-caractère${rst}' en début de ligne CSV (obligatoire).

      * La clé '${surb}zero=entier-relatif${rst}' (présence obligatoire dans la ligne CSV).

      * Les autres clés sont facultatives.

      * Noms et Formats des clés reconnues :
         + ${surb}car${rst}   - Format : ${surb}car=1-Seul-Caractère${rst}

              Exemple : ${ital}car=A${rst}

           Correspond au caractère à dessiner.
           Une clé '${surb}car=1-même-caractère${rst}' peut apparaître plusieurs fois dans le
           fichier de dessins Ascii, définissant ainsi plusieurs dessins pour le
           même caractère.
           Dans ce cas là, sans vérification, le 1er dessin défini est gardé ;
           avec vérification (option '-c'), le dernier dessin défini est gardé ;
           tous les autres doublons sont inacessibles.
           Tous les caractères 1 seule fois définis sont accessibles.

         + ${surb}zero${rst}  - Format : ${surb}zero=entier-relatif${rst}

              Exemple : ${ital}zero=+2${rst}

           Indique le nombre de lignes (en partant du haut) du dessin Ascii
           à dessiner au dessus de la ligne de référence.
           Positionne en hauteur le dessin Ascii.
           Un nombre négatif descend le dessin.

         + ${surb}after${rst} - Format : ${surb}after=entier-relatif_liste-de-caractères…${rst}

              Exemple : ${ital}after=-3_AbcGX${rst}

           Sépare ou serre les dessins entre eux.
           En l'absence de cette clé, le dessin se colle contre le dessin
           précédent sans entrer dans le rectangle minimal encadrant le dessin
           Ascii précédent.
           Le nombre correspond aux nombres d'espaces entre le dessin Ascii
           précédent et celui décrit par la ligne CSV si le caractère précédent
           est présent dans la liste de caractères.
           Le caractère '${surb}_${rst}' est obligatoire et sépare le nombre de la liste.
           Il est possible de mettre un nombre négatif, dans ce cas, cela serre
           les dessins Ascii entre eux d'autant d'espace.
           (Attention aux collisions entre dessins Ascii, signalées à partir du
            niveau de verbosité 1).
           Il est possible de mettre plusieurs '${surb}nombre_liste${rst}'.
           Il suffit de les séparer par un espace :

              Exemple : ${ital}after=-2_TFPVW 1_ABCD 2_XYZ${rst}

           Toutefois, il faut faire attention à ce qu'un même caractère
           n'apparaisse pas dans plusieurs listes.

         + ${surb}profile${rst} - Format : ${surb}profile=nombre_listecaractères ...${rst}

              Exemple : ${ital}profile=1_VW 2_Y${rst}

           Même format que pour la clé ${surb}after${rst}.
           Le dessin Ascii épouse la forme du dessin Ascii précédent
           si présent dans la liste en étant séparé du nombre d'espace indiqué
           par le nombre attenant à la liste.
           Les nombres négatifs ne sont pas admis, le 0 est admis.

         + Un caractère de liste ne peut apparaître qu'une seule fois dans les
           clés '${surb}after${rst}' et '${surb}profile${rst}' réunies.

      * Typiquement un dessin Ascii est décrit ainsi :
         ${surb}car=caractère,zero=[+|-]n[,after=[+|-n]_listcar[ [+|-]n_listcar]…][,profile=[+]n_listcar[ [+]n_listcar]…]
         ligne Ascii
         ligne Ascii
         …${rst}

         Exemple :
            car=a,zero=2,after=-2_FT 1_ABCDEGHIJKLMNOPQRSUWXYZchi-,profile=1_V
            /¯¯|
            |__|_
         Clé '${surb}car${rst}' :
           Le caractère 'a' dans le texte à convertir correspond à ce dessin.
         Clé '${surb}zero${rst}' :
           La 2ième ligne du dessin est placée sur la ligne de référence.
           Réglant ainsi la position en hauteur du dessin.
         Clé '${surb}after${rst}' :
           Le dessin 'a' se serre de 2 espaces vers la gauche s'il vient après
           un 'F' ou un 'T'.
           Le dessin 'a' se sépare d'un espace vers la droite après un caractère
           de la liste :
             ABCDEGHIJKLMNOPQRSUWXYZchi-
         Clé '${surb}profile${rst}' :
           Le dessin 'a' épouse la forme d'un 'V' précédent en étant distant
           d'un epsace (moche, mais pour illustration).

      * Cas particulier du caractère 'virgule' :
         + Il peut se décrire de 2 façons indifférenciées :
            ${surb}car=,,zero=…${rst}  ou  ${surb}car=,zero=…${rst}
           Ces 2 écritures sont équivalentes.

         + Si le caractère '${surb},${rst}' doit être dans une liste d'une des clés '${surb}after${rst}'
           ou '${surb}profile${rst}' alors la virgule doit être la dernière de la liste et
           cette liste doit être la dernière de la clé CSV et la clé CSV doit
           être la dernière de la ligne CSV.
              Exemple : ${ital}car=A,zero=6,profile=0_VY,after=-4_W 1_ABCD,${rst}
              Dans ce cas, la dernière virgule sera considérée comme un
              caractère de la liste : 'ABCD,'
              Et le 'A' se séparera d'un espace après une virgule.


${surb}Vérification du fichier de dessins Ascii :${rst}

   La vérification porte sur la validité de la ligne CSV décrivant le dessin :

      - La clé '${surb}car${rst}' doit n'avoir qu'un seul caractère comme valeur.
        Sinon le dessin Ascii n'est pas accessible.

      - Un caractère Ascii décrit ne peut apparaître qu'une seule fois dans le
        fichier de dessins Ascii (valeur de la clé '${surb}car${rst}).
        Sinon, sans vérification, le 1er dessin est gardé; avec vérification,
        le dernier est gardé.
        Signalement au niveau de verbosité 1.
        Erreur ne provoquant pas la sortie du script.

      - La clé '${surb}zero${rst}' doit être présente et sa valeur doit être un entier
        relatif.

      - Le format des valeurs des clés '${surb}after${rst}' et '${surb}profile${rst}' doit être du type :
           ${ital}[+|-][0-9]+_[[:print:]]+[ [+|-][0-9]+_[[:print:]]+]*${rst}
         ou plus simplement :
           ${ital}nb_listcaractères …${rst}
        Et ${ital}nb${rst} ne doit pas être négatif dans la clé '${surb}profile${rst}'.

      - Pas de répétition de caractères dans les listes de caractères des clés
        '${surb}after${rst}' et '${surb}profile${rst}' réunies.

      - Les lignes du fichier de dessins Ascii ne doivent pas se terminer par
        un ou plusieurs blancs.
        Ces blancs sont supprimés (avec avertissement au niveau de verbosité 1),
        le fichier de dessins Ascii reste intact.
        Erreur ne provoquant pas la sortie du script.


${surb}Variables d'environnement :${rst}

   ${ital}$Name${rst} accepte 2 variables d'environnement :
      ${surb}Draws${rst}  : Fichier des dessins Ascii
      ${surb}Spaces${rst} : Nombre d'espaces finaux pour un espace dans le texte à convertir.

   Elles prévalent sur l'affectation en dur dans ce script.
   Les options '${ital}--draws${rst}' et '${ital}--spaces${rst}' prévalent sur les variables
   d'environnement respectives.


${surb}Notes :${rst}

   Une ligne de dessin par ligne de texte à convertir.

   Une ligne vide est insérée en dessous de chaque ligne de texte convertie.

   Tous les retours 'terminal' sont dirigés vers ${ital}stderr${rst} sauf le résultat final
   qui est dirigé vers la sortie standard.


${surb}Exemples d'utilisation avec le fichier de dessins embarqué :${rst}

   ${ital}$ $Name 'Hello world'${rst}"
cat <<- EOF

   |¯¯|  |¯¯|
   |  |__|  |     |\ |\                      |\    |
   |        |     | )| )                     | )   |
   |   __   |     | )| )                     | )   |
   |  |  |  | /¯¯)|/ |/ /¯¯\   \    //¯¯\|/¯¯|/ /¯¯|
   |__|  |__| |___/\ /\ \__/    \/\/ \__/|   /\ |__|





EOF
   printf "%10s" "2023-06-23"
   n=$(( (79+l)/2 ))
   printf "%${n}s" "$(echo -e "${ital}$Name${rst}")"
   n=$(( 79-n ))
   printf "%${n}s\n" "Tawal®©"
   exit
}

_version_quit()
{
   echo "$Name : $version"
   exit
}
_err_opt_inutile ()
{    # Option inutile.
   echo "$Name : Option$1 inutile$2 l'option $3."
} >&2

_err_opt_v_over ()
{     # Trop de niveaux verbosité demandés (avertissement => verbosisté max = 3).
   echo "$Name : $1 fois l'option '-v' , le maximum est de 3."
} >&2

_err_quit ()
{     # Erreurs avec sortie avant même de commencer.
   local m
   case $1 in
      d)    m="Le fichier de dessins Ascii '$2' est inacessible ou inexistant." ;;
      oe)   m="Le fichier '$2' existe déjà." ;;
      ow)   m="Vous n'avez pas les droits d'écriture pour le fichier '$2'." ;;
      s)    m="L'option '$2' doit avoir un entier en argument." ;;
      opt)  m="L'option '$2' n'est pas reconnue." ;;
      gawk) m="Nécessite 'gawk' : apt install gawk" ;;
      arg_abs) m="L'option '$2' nécessite un paramètre." ;;
      *) exit 127 ;;
   esac
   echo "$Name : $m"
   echo "$Name : Sortie."
   exit 1
} >&2

_test_opt ()
{    # Test de la validité des arguments/valeurs des otpions.
   case $1 in
      v)  (($2<=3))                 || return 1 ;;
      d)  [ -r "$2" ]               || return 1 ;;
      oe) [ ! -e "$2" ]             || return 1 ;;
      ow) touch -c "$2" 2>/dev/null || return 1 ;;
      s)  [[ $2 =~ ^\+?[0-9]+$ ]]   || return 1 ;;
   esac
}

### Gestion des options et arguments.
while getopts :cd:fhio:qs:vV-: option
do
   case $option in
      c) opt_c="-$option"
         ;;
      d) _test_opt d "$OPTARG" || _err_quit d "$OPTARG"
         Draws="$OPTARG"
         ;;
      f) opt_f="-$option"
         ;;
      h) _usage_quit
         ;;
      i) opt_i="-$option"
         ;;
      o) opt_o="-$option"
         opt_o_arg="$OPTARG"
         ;;
      q) opt_q="-$option"
         opt_c="forced"
         ;;
      s) _test_opt s "$OPTARG" || _err_quit s -"$option"
         opt_s="-$option"
         Spaces="$OPTARG"
         ;;
      v) ((opt_v++))
         ;;
      V) _version_quit
         ;;
      :) arg_abs="-$OPTARG"
         ;;
      -) case $OPTARG in
            check)
               opt_c="--$OPTARG"
               ;;
            draws)
               [ ${!OPTIND} ] || { arg_abs="--$OPTARG"; break; }
               _test_opt d ${!OPTIND} || _err_quit d ${!OPTIND}
               Draws=${!OPTIND}
               OPTIND=$((OPTIND+1))
               ;;
            force-out)
               opt_f="--$OPTARG"
               ;;
            help)
               _usage_quit
               ;;
            ignore)
               opt_i="--$OPTARG"
               ;;
            out)
               [ ${!OPTIND} ] || { arg_abs="--$OPTARG"; break; }
               opt_o="--$OPTARG"
               opt_o_arg=${!OPTIND}
               OPTIND=$((OPTIND+1))
               ;;
            quit)
               opt_q="--$OPTARG"
               opt_c="forced"
               ;;
            spaces)
               [ ${!OPTIND} ] || { arg_abs="--$OPTARG"; break; }
               _test_opt s ${!OPTIND} || _err_quit s --"${OPTARG}"
               opt_s="--$OPTARG"
               Spaces=${!OPTIND}
               OPTIND=$((OPTIND+1))
               ;;
            verbose)
               ((opt_v++))
               ;;
            version)
               _version_quit
               ;;
            *)
               _err_quit opt --"$OPTARG"
               ;;
         esac
         ;;
      *) _err_quit opt -"$OPTARG"
         ;;
   esac
done
shift $((OPTIND-1))

# Vérification de la présence de 'gawk'.
hash gawk &>/dev/null || _err_quit gawk

### Option --draws, --out ou --spaces sans argument.
if [ "$arg_abs" ] && [ ! "$opt_q" ]
then
   _err_quit arg_abs "$arg_abs"
elif [[ "$arg_abs" =~ "^-(d|-draws)$" ]] && [ "$opt_q" ]
then
   _err_quit "$arg_abs"
elif [ "$arg_abs" ]
then
   _err_opt_inutile " '$arg_abs' (et sans argument !)" " avec" "'$opt_q'"
fi

### Gestion des confilts entre options.
if [ "$opt_q" ]
then
   [ "$opt_s" ] && _err_opt_inutile " '$opt_s'" " avec" "'$opt_q'"
   [ "$opt_i" ] && _err_opt_inutile " '$opt_i'" " avec" "'$opt_q'"
   if [ "$opt_o" ] && [ "$opt_f" ]
   then
      _err_opt_inutile "s '$opt_o' et '$opt_f'"  "s avec" "'$opt_q'"
   else
      [ "$opt_o" ] && _err_opt_inutile " '$opt_o'" " avec" "'$opt_q'"
      [ "$opt_f" ] && _err_opt_inutile " '$opt_f'" " sans" "'$opt_q'"
   fi
else
   if [ "$opt_o" ]
   then
      if [ "$opt_f" ]
      then
         _test_opt ow "$opt_o_arg" || _err_quit ow "$opt_o_arg"
         _test_opt oe "$opt_o_arg" || echo "Écrasement du fichier '$opt_o_arg' existant." >&2
      else
         _test_opt oe "$opt_o_arg" || _err_quit oe "$opt_o_arg"
         _test_opt ow "$opt_o_arg" || _err_quit ow "$opt_o_arg"
      fi
   elif [ "$opt_f" ]
   then
      _err_opt_inutile " '$opt_f'" " sans" "'$opt_o'"
   fi
   [ "$opt_i" ] && [ ! "$opt_c" ] && _err_opt_inutile " '$opt_i'" " sans" "'$opt_c'"
fi
((opt_v)) && { _test_opt v "$opt_v" || _err_opt_v_over "$opt_v"; }

### Fichier embarqué de dessins Ascii si pas d'autre choix.
if [ ! "$Draws" ]
then
   if [ ! -e "/tmp/transcii.ascii" ]
   then
      cat <<- "EOF"> /tmp/transcii.ascii
################################################################################
##                                                                            ##
##                       -  Dessin Ascii - Transcii  -                        ##
##                                                                            ##
################################################################################


######    Les commentaires ne peuvent apparaître qu'entête du fichier.    ######
######    Ils doivent avoir le caractère '#' en début de ligne.           ######
######    Il est possible de faire plusieurs blocs de commentaires.       ######


############  - Format du fichier Caractères Ascii pour Transcii  -  ###########
#
#   - Commentaires en entête seulement et précédés du caractère '#' en début de
#     ligne. Des lignes vides peuvent séparer des blocs de commentaires et finir
#     le dernier bloc de commentaires.
#
#   - Pas de 'blancs' en fin de ligne, dessin Ascii compris.
#
#   - Toute ligne vide en dehors de l'entête du fichier sera comprise dans le
#     dessin Ascii décrit par la ligne CSV (voir Ligne CSV plus bas).
#
#   - Dessin Ascii - composé de :
#      * Une ligne de données CSV.
#        CSV = Comma Separated Values : Valeurs Séparées par des Virgules.
#        Ici, les Valeurs sont du format : Clé=Valeur[ Valeur2]…
#        appelées 'clé' désignant aussi bien la Clé que l'ensemble Clé=Valeurs…
#
#      * Les lignes suivantes composant le dessin Ascii jusqu'à la prochaine
#        ligne CSV rencontrée ou la fin de fichier.
#
#
#   - Ligne CSV - composée de :
#      * La clé 'car=1-seul-caractère' en début de ligne CSV (obligatoire).
#
#      * La clé 'zero=entier-relatif' (présence obligatoire dans la ligne CSV).
#
#      * Les autres clés sont facultatives.
#
#      * Noms et Formats des clés reconnues :
#         + car   - Format : car=1-Seul-Caractère
#           Correspond au caractère à dessiner.
#           Une clé 'car=1-même-caractère' peut apparaître plusieurs fois dans le
#           fichier de dessins Ascii, définissant ainsi plusieurs dessins pour le
#           même caractère.
#           Dans ce cas là, sans vérification, le 1er dessin défini est gardé ;
#           avec vérification (option '-c'), le dernier dessin défini est gardé ;
#           tous les autres doublons sont inacessibles.
#           Tous les caractères 1 seule fois définis sont accessibles.
#
#              Exemple : car=A
#
#         + zero  - Format : zero=entier-relatif
#           Indique le nombre de lignes (en partant du haut) du dessin Ascii
#           à dessiner au dessus de la ligne de référence.
#           Positionne en hauteur le dessin Ascii.
#           Un nombre négatif descend le dessin.
#
#              Exemple : zero=+2
#
#         + after - Format : after=entier-relatif_liste-de-caractères…
#           Sépare ou serre les dessins entre eux.
#
#              Exemple : after=-3_AbcGX
#
#           En l'absence de cette clé, le dessin se colle contre le dessin
#           précédent sans entrer dans le rectangle minimal encadrant le dessin
#           Ascii précédent.
#           Le nombre correspond aux nombres d'espaces entre le dessin Ascii
#           précédent et celui décrit par la ligne CSV si le caractère précédent
#           est présent dans la liste de caractères.
#           Le caractère '_' est obligatoire et sépare le nombre de la liste.
#           Il est possible de mettre un nombre négatif, dans ce cas, cela serre
#           les dessins Ascii entre eux d'autant d'espace.
#           (Attention aux collisions entre dessins Ascii, signalées à partir du
#            niveau de verbosité 1).
#           Il est possible de mettre plusieurs 'nombre_liste'.
#           Il suffit de les séparer par un espace :
#
#              Exemple : after=-2_TFPVW 1_ABCD 2_XYZ
#
#           Toutefois, il faut faire attention à ce qu'un même caractère
#           n'apparaisse pas dans plusieurs listes.
#
#         + profile - Format : profile=nombre_listecaractères ...
#           Même format que pour la clé after.
#           Le dessin Ascii épouse la forme du dessin Ascii précédent
#           si présent dans la liste en étant séparé du nombre d'espace indiqué
#           par le nombre attenant à la liste.
#           Les nombres négatifs ne sont pas admis, le 0 est admis.
#
#              Exemple : profile=1_VW 2_Y
#
#         + Un caractère de liste ne peut apparaître qu'une seule fois dans les
#           clés 'after' et 'profile' réunies.
#
#      * Typiquement un dessin Ascii est décrit ainsi :
#         car=caractère,zero=[+|-]n[,after=[+|-n]_listcar[ [+|-]n_listcar]…][,profile=[+]n_listcar[ [+]n_listcar]…]
#         ligne Ascii
#         ligne Ascii
#         …
#
#         Exemple :
#            car=a,zero=2,after=-2_FT 1_ABCDEGHIJKLMNOPQRSUWXYZchi-,profile=1_V
#            /¯¯|
#            |__|_
#         Clé 'car' :
#           Le caractère 'a' dans le texte à convertir correspond à ce dessin.
#         Clé 'zero' :
#           La 2ième ligne du dessin est placée sur la ligne de référence.
#           Réglant ainsi la position en hauteur du dessin.
#         Clé 'after' :
#           Le dessin 'a' se serre de 2 espaces vers la gauche s'il vient après
#           un 'F' ou un 'T'.
#           Le dessin 'a' se sépare d'un espace vers la droite après un caractère
#           de la liste :
#             ABCDEGHIJKLMNOPQRSUWXYZchi-
#         Clé 'profile' :
#           Le dessin 'a' épouse la forme d'un 'V' précédent en étant distant
#           d'un epsace (moche, mais pour illustration).
#
#      * Cas particulier du caractère 'virgule' :
#         + Il peut se décrire de 2 façons indifférenciées :
#            car=,,zero=…  ou  car=,zero=…
#           Ces 2 écritures sont équivalentes.
#
#         + Si le caractère ',' doit être dans une liste d'une des clés 'after'
#           ou 'profile' alors la virgule doit être la dernière de la liste et
#           cette liste doit être la dernière de la clé CSV et la clé CSV doit
#           être la dernière de la ligne CSV.
#              Exemple : car=A,zero=6,profile=0_VY,after=-4_W 1_ABCD,
#              Dans ce cas, la dernière virgule sera considérée comme un
#              caractère de la liste : 'ABCD,'
#              Et le 'A' se séparera d'un espace après une virgule.
#
################################################################################

car=A,zero=6,profile=1_VWY,after=-3_T 1_ABCDEFGHIJKLMNOPQRSUXZiî-0123456789.;!?,
     /\
    /  \
   / /\ \
  /  ¯¯  \
 /  /¯¯\  \
/__/    \__\
car=Æ,zero=6,profile=1_VWY,after=-3_T 1_ABCDEFGHIJKLMNOPQRSUXZiî-0123456789.;!?,
     /|¯¯¯¯¯|
    / | |¯¯¯
   / /|  ¯|
  /  ¯| |¯
 /  /¯|  ¯¯¯|
/__/  |_____|
car=Â,zero=7,profile=1_VWY,after=-3_T 1_ABCDEFGHIJKLMNOPQRSUXZiî-0123456789.;!?,
     /\
     /\
    /  \
   / /\ \
  /  ¯¯  \
 /  /¯¯\  \
/__/    \__\
car=Ä,zero=7,profile=1_VWY,after=-3_T 1_ABCDEFGHIJKLMNOPQRSUXZiî-0123456789.;!?,
     ••
     /\
    /  \
   / /\ \
  /  ¯¯  \
 /  /¯¯\  \
/__/    \__\
car=À,zero=7,profile=1_VWY,after=-3_T 1_ABCDEFGHIJKLMNOPQRSUXZiî-0123456789.;!?,
     \
     /\
    /  \
   / /\ \
  /  ¯¯  \
 /  /¯¯\  \
/__/    \__\
car=B,zero=6,after=+1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯¯¯¯\
| |¯¯) )
|  ¯¯  |_
| |¯¯¯)  )
|  ¯¯¯   |
|________|
car=C,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
/¯¯¯¯¯¯¯¯\
|        |
|  |¯¯¯¯¯
|  |
|   ¯¯¯¯¯|
\________/
car=Ç,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
/¯¯¯¯¯¯¯¯\
|        |
|  |¯¯¯¯¯
|  |
|   ¯¯¯¯¯|
\________/
    )_)
car=D,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯¯¯¯¯¯\
|        \
|  |¯¯¯\  \
|  |   )  )
|   ¯¯¯  /
|_______/
car=E,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯¯¯¯¯¯¯|
|  |¯¯¯¯¯
|   ¯¯|
|  |¯¯
|   ¯¯¯¯¯|
|________|
car=É,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
     /
|¯¯¯¯¯¯¯¯|
|  |¯¯¯¯¯
|   ¯¯|
|  |¯¯
|   ¯¯¯¯¯|
|________|
car=È,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
    \
|¯¯¯¯¯¯¯¯|
|  |¯¯¯¯¯
|   ¯¯|
|  |¯¯
|   ¯¯¯¯¯|
|________|
car=Ë,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
    ••
|¯¯¯¯¯¯¯¯|
|  |¯¯¯¯¯
|   ¯¯|
|  |¯¯
|   ¯¯¯¯¯|
|________|
car=Ê,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
    /\
|¯¯¯¯¯¯¯¯|
|  |¯¯¯¯¯
|   ¯¯|
|  |¯¯
|   ¯¯¯¯¯|
|________|
car=F,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯¯¯¯¯¯¯|
|        |
|  |¯¯¯¯¯
|   ¯¯|
|  |¯¯
|__|
car=G,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
/¯¯¯¯¯¯¯¯|
|   _____|
|  (    _
|  |   | |
|  ¯¯¯¯¯ |
\________/
car=H,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯|  |¯¯|
|  |__|  |
|        |
|   __   |
|  |  |  |
|__|  |__|
car=I,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯¯¯|
 |  |
 |  |
 |  |
 |  |
|____|
car=Î,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
  /\
|¯¯¯¯|
 |  |
 |  |
 |  |
 |  |
|____|
car=Ï,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
  ••
|¯¯¯¯|
 |  |
 |  |
 |  |
 |  |
|____|
car=J,zero=6,after=1_BCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
      |¯¯|
      |  |
      |  |
\¯¯\  |  |
 \  \_/  /
  \_____/
car=K,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯| /¯¯/
|  |/  /
|     /
|     \
|  |\  \
|__| \__\
car=L,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯|
|  |
|  |
|  |
|  ¯¯¯¯¯¯|
|________|
car=M,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯\  /¯¯|
|   \/   |
|        |
|  |\/|  |
|  |  |  |
|__|  |__|
car=N,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯\  |¯¯|
|   \ |  |
|    \|  |
|  |\    |
|  | \   |
|__|  \__|
car=O,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
 /¯¯¯¯¯¯\
/        \
|  |¯¯|  |
|  |__|  |
\        /
 \______/
car=Ô,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
    /\
 /¯¯¯¯¯¯\
/        \
|  |¯¯|  |
|  |__|  |
\        /
 \______/
car=Ö,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
    ••
 /¯¯¯¯¯¯\
/        \
|  |¯¯|  |
|  |__|  |
\        /
 \______/
car=Ó,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
     /
 /¯¯¯¯¯¯\
/        \
|  |¯¯|  |
|  |__|  |
\        /
 \______/
car=Ò,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
    \
 /¯¯¯¯¯¯\
/        \
|  |¯¯|  |
|  |__|  |
\        /
 \______/
car=Œ,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
 /¯¯¯\|¯¯¯¯|
/     | |¯¯
| |¯| |  ¯|
| |_| | |¯
\     |  ¯¯|
 \___/|____|
car=P,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯¯¯¯¯¯\
|  |¯¯\  )
|  |__|  )
|       /
|  |¯¯¯¯
|__|
car=Q,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
 /¯¯¯¯¯¯\
(        )
|  |¯¯|  |
|  |__|  |
(      \¯\
 \______\_\
car=R,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯¯¯¯¯¯\
|  |¯¯\  \
|  |___) )
|       \
|  |¯¯\  \
|__|   \__\
car=S,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
/¯¯¯¯¯¯¯¯)
\  \¯¯¯¯¯
 \  ¯¯¯¯\
  ¯¯¯¯\  \
 _____/  /
(_______/
car=T,zero=6,after=-3_au -2_eo -3_A 1_BCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789.;!?,
|¯¯¯¯¯¯¯¯¯¯|
|____  ____|
    |  |
    |  |
    |  |
    |__|
car=U,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯|   |¯¯|
|  |   |  |
|  |   |  |
|  |   |  |
|   ¯¯¯   |
\_________/
car=Û,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
    /\
|¯¯|   |¯¯|
|  |   |  |
|  |   |  |
|  |   |  |
|   ¯¯¯   |
\_________/
car=Ü,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
    ••
|¯¯|   |¯¯|
|  |   |  |
|  |   |  |
|  |   |  |
|   ¯¯¯   |
\_________/
car=Ù,zero=7,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
     \
|¯¯|   |¯¯|
|  |   |  |
|  |   |  |
|  |   |  |
|   ¯¯¯   |
\_________/
car=V,zero=6,profile=1_A,after=-3_a -2_bo -1_cegijmnpqrsuvwxyz 1_CDEFGHIJKLMNOPQRSTUVWXYZ-0123456789.;!?,
\¯¯\    /¯¯/
 \  \  /  /
  \  \/  /
   \    /
    \  /
     \/
car=W,zero=6,profile=1_A,after=2_a -1_cgjmnopqrsuvwxyz -1_be 1_CDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
\¯¯\        /¯¯/
 \  \  /\  /  /
  \  \/  \/  /
   \        /
    \  /\  /
     \/  \/
car=X,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
\¯¯\   /¯¯/
 \  \ /  /
  \  ¯  /
  /  _  \
 /  / \  \
/__/   \__\
car=Y,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXZiî-0123456789.;!?,
\¯¯\  /¯¯/
 \  \/  /
  \_   /
   /  /
  /  /
 /__/
car=Z,zero=6,after=1_ABCDEFGHIJKLMNOPQRSTUVWXYZiî-0123456789.;!?,
|¯¯¯¯¯¯¯¯|
 ¯¯¯¯/ /¯
    / /
   / /
|¯¯  ¯¯¯¯|
|________|
car=a,zero=2,after=-3_F -2_TVWY -1_PD 1_ABCEGHIJKLMNOQRSUXZchiî-0123456789.;!?,
/¯¯|
|__|_
car=æ,zero=2,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZchiî-0123456789.;!?,
/¯|¯)
|_|__
car=à,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZchiî-0123456789.;!?,
 \
/¯¯|
|__|_
car=â,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZchiî-0123456789.;!?,
  ^
/¯¯|
|__|_
car=ä,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZchiî-0123456789.;!?,
 ⋅⋅
/¯¯|
|__|_
car=b,zero=5,after=1_ABCDEFGHIJKLMNOPQRSTUXYZiî-0123456789.;!?,
|\
| )
|/
|¯¯\
|__|
car=c,zero=2,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZeiî-0123456789.;!?,
/¯¯¯
|___
car=ç,zero=2,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZeiî-0123456789.;!?,
/¯¯¯
|___
  )
car=d,zero=5,after=-2_FPTVWY 1_ABCDEGHIJKLMNOQRSUXZiî-0123456789.;!?,
   |
   |
   |
/¯¯|
|__|
car=e,zero=2,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZchiî-0123456789.;!?,
/¯¯)
|___
car=é,zero=3,after=-2_FTPVWY -1_D 1_ABCEGHIJKLMNOQRSUXZchiî-0123456789.;!?,
  /
/¯¯)
|___
car=è,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZchiî-0123456789.;!?,
 \
/¯¯)
|___
car=ê,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZchiî-0123456789.;!?,
  ^
/¯¯)
|___
car=ë,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZciî-0123456789.;!?,
 ⋅⋅
/¯¯)
|___
car=f,zero=5,after=-1_TVWY 1_ABCDEFGHIJKLMNOPQRSUXZchiî-0123456789.;!?,
 |\
 | )
 | )
 |/
_/_
 |\
 | )
 | )
 |/
car=g,zero=2,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZiî-0123456789.;!?,
/¯¯|
|__|/
  /|
 ( |
 ( |
  \|
car=h,zero=5,after=1_ABCDEFGHIJKLMNOPQRSUXYZkciî-0123456789.;!?,
|\
| )
|/
|¯\
| |
car=i,zero=3,after=-2_FPTVWY -1_atu 0_ABCDEGHIJKLMNOQRSUXZ-0123456789.;!?,
 ⋅
 |
 |
car=ï,zero=3,after=-2_FPTVWY -1_atu 1_ABCDEGHIJKLMNOQRSUXZ-0123456789.;!?,
 ⠒
 |
 |
car=î,zero=3,after=-2_FPTVWY -1_atu 1_ABCDEGHIJKLMNOQRSUXZ-0123456789.;!?,
 ^
 |
 |
car=j,zero=3,after=-2_FPTVWY -1_atu 1_ABCDEGHIJKLMNOQRSUXZ-0123456789.;!?,
  ⋅
 /|
  |/
 /|
( |
( |
 \|
car=k,zero=5,after=1_ABCDEFGHIJKLMNOPQRSUXYZiî-0123456789.;!?,
|\
| )
|/
|\¯
| \
car=l,zero=5,after=1_ABCDEFGHIJKLMNOPQRSUXYZiy-0123456789.;!?,
|\
| )
| )
|/
/\
car=m,zero=2,after=1_ABCDEGHIJKLMNOQRSUXYZiî-0123456789.;!?,
|¯|¯|
| | |
car=n,zero=2,after=1_ABCDEFGHIJKLMNOPQRSTUXYZiî-0123456789.;!?,
|¯¯|
|  |
car=o,zero=2,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZciî-0123456789.;!?,
/¯¯\
\__/
car=œ,zero=2,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZciî-0123456789.;!?,
/¯|¯)
\_|__
car=ö,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZciî-0123456789.;!?,
 ⋅⋅
/¯¯\
\__/
car=ô,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNQRSUXZciî-0123456789.;!?,
  ^
/¯¯\
\__/
car=ó,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZciî-0123456789.;!?,
  /
/¯¯\
\__/
car=p,zero=2,after=1_ABCDEFGHIJKLMNOPQRSTUXYZiî-0123456789.;!?,
|¯¯\
|___)
|
|
|
|
car=q,zero=2,after=1_ABCDEFGHIJKLMNOPQRSTUXYZciî-0123456789.;!?,
|¯¯|
\__|
   |
   |
   |
   |
car=r,zero=2,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZceiîï-0123456789.;!?,
|/¯¯
|
car=s,zero=2,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZiî-0123456789.;!?,
 /¯¯\
/  _/
car=t,zero=5,after=1_ABCDEFGHIJKLMNOPQRSTUXYZceiîorsx-0123456789.;!?,
|
|––
|
|
|_
car=u,zero=2,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZciîqo-0123456789.;!?,
|  |
\__|_
car=û,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZciî-0123456789.;!?,
  ^
|  |
\__|_
car=ü,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZciî-0123456789.;!?,
 ⋅⋅
|  |
\__|_
car=ù,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZciî-0123456789.;!?,
 \
|  |
\__|_
car=ú,zero=3,after=-2_FPTVWY -1_D 1_ABCEGHIJKLMNOQRSUXZciî-0123456789.;!?,
  /
|  |
\__|_
car=v,zero=2,after=-2_FPTVWY 1_ABCDEGHIJKLMNOQRSUXZiî-0123456789.;!?,
\  /¯
 \/
car=w,zero=2,after=-2_FPTVWY 1_ABCDEGHIJKLMNOQRSUXZiî-0123456789.;!?,
\    /
 \/\/
car=x,zero=2,after=-2_FTVWY 1_ABCDEGHIJKLMNOPQRSUXZiî-0123456789.;!?,
\/
/\
car=y,zero=2,after=-2_FPTVWY -1_t 1_ABCDEGHIJKLMNOQRSUXZiî-0123456789.;!?,
\  /
 \/
 /|
( |
( |
 \|
car=z,zero=2,after=-2_FPTVWY 1_ABCDEGHIJKLMNOQRSUXZiî-0123456789.;!?,
|¯|
 _|/
 /|
( |
( |
 \|
car=1,zero=3,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
/|
 |
_|_
car=2,zero=3,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
(¯)
 /
/__
car=3,zero=3,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
¯¯|
 –|
__|
car=4,zero=3,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
|
|_|_
  |
car=5,zero=3,after=1_123567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
|¯¯¯
 ¯¯\
(__|
car=6,zero=3,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
/¯¯
|__
(__)
car=7,zero=3,after=1_2357890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
|¯¯|
  –|
   |
car=8,zero=3,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
(¯¯)
(––)
(__)
car=9,zero=3,after=1_2357890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
(¯¯)
 ¯¯|
 __|
car=0,zero=3,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
|¯¯|
|  |
|__|
car=-,zero=2,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
___
car=+,zero=2,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
  |
¯¯|¯¯
car=×,zero=2,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
\/
/\
car=÷,zero=3
 •
–––
 •
car==,zero=2,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUXYZabcdefghijklmnopqrstuvwxyz.;!?,
––––
––––
car=?,zero=6,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.;!?,
 /¯\
(   )
   /
  |

  •
car=!,zero=6,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.;!?,
|
|
|
|

•
car=.,zero=1,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.;!?,
•
car=,,zero=0,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.;!?,
 )
/
car=;,zero=1,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.;!?,
 ⋅
 )
/
car=%,zero=4,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.;!?,
 _
(_) /
   / _
  / (_)
car=#,zero=5,after=1_1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.;!?,
     //  //
 ===========
   //  //
===========
 //  //
car=\,zero=6,after=1_/\
\\
 \\
  \\
   \\
    \\
     \\
car=/,zero=6,after=-3_/ 1_!-\
     //
    //
   //
  //
 //
//
car=$,zero=5,after=1_*\/!?#<>"'^;-$,
 __||___
//¯||¯¯¯
\\_||__
 ¯¯||¯\\
___||_//
¯¯¯||¯¯
car=*,zero=5
\\ || //
 \\||//
========
 //||\\
// || \\
car=>,zero=4
\\
 \\
 //
//
car=<,zero=4
 //
//
\\
 \\
car=",zero=5
//
car=',zero=5
/
car=^,zero=5,after=1_(
 /\
car={,zero=6,after=1_&~"#'{([-|\@)]=+}$^*%!/;.?<>°,
 ((¯
 ((
//
\\
 ((
 ((_
car=},zero=6,after=1_&~"#'{([-|\@)]=+}$^*%!/;.?<>°,
¯))
 ))
  \\
  //
 ))
_))
car=«,zero=2
//
\\
car=»,zero=2
\\
//
car=~,zero=3
 ___   _
//¯\\_//
¯   ¯¯¯
car=[,zero=6
||¯¯
||
||
||
||
||__
car=],zero=6
¯¯||
  ||
  ||
  ||
  ||
__||
car=(,zero=6
  ((
 ((
((
((
 ((
  ((
car=),zero=6
))
 ))
  ))
  ))
 ))
))
car=°,zero=6
 _
(_)
car=&,zero=3
 _
(_)
(_X_
car=ß,zero=+6
\¯¯\    /¯¯/
 \  \  /  /


 /  /  \  \
/__/    \__\
car=ß,zero=+6
\\       //
 \\     //


 //     \\
//       \\
EOF
   fi
   Draws="/tmp/transcii.ascii"
else
   _test_opt d "$Draws" || _err_quit d "$Draws"
fi

### Gestion de l'entrée.
if [ ! "$opt_q" ]
then
   if (($#))
   then
      texte="$(printf "%s\n" "$@")"
   elif [[ $(realpath /dev/fd/0) =~ ^"/dev/pts/" ]]
   then
      echo -n "Entrez votre texte : " >&2
      read -r texte
   else
      texte=$(</dev/fd/0)
   fi
   ((opt_v)) && echo "Texte à convertir : \"$texte\"" >&2
fi

### Programme principal.
gawk -vdraws="$Draws" -vos="$Spaces" \
     -voc="$opt_c" -voi="$opt_i" -voo="$opt_o_arg" -voq="$opt_q" -vov="$opt_v" '
   BEGIN {
   # Traitement du fichier de dessins Ascii.
      FS=""

      # Regex pour les formats des clés ´car´ et ´profile´.
      rgx="^(|+|-)[[:digit:]]?*_[^ ]?*($|( (|+|-)[[:digit:]]?*_[^ ]?*)*$)"

      # Nombre d´espaces.
      for (i=1;i<=os;i++) { space=space" " }

      # Verbosité.
      if (ov && oc) { printf("Vérification du fichier de dessins Ascii : %s\n", draws) > "/dev/stderr" }

      # Lecture du fichier de dessins ascii (1 seule fois).
      while ((getline line < draws)>0) {
         # NR du fichier draws
         ++nr

         # Suppression des espaces en fin de ligne + signalement (affiché plus tard).
         err_trail=0
         if (line ~ /\s+$/  && oc) {
            sub(/\s+$/, "", line)
            err_trail=1
         }

         # Passage des lignes vides et de commentaires en début de fichier.
         if (nr==1 && line ~ /^#|^$/) { comm=1 }
         if (comm && line ~ /^#|^$/) {
            continue
         }else{
            comm=0
         }

         # Récupération des donnés CSV + vérification (selon option -c).
         if (line ~ /^car=/) {
            csv=line

            # Nombres de lignes inférieures (minimum des zéros - hauteur dessin Ascii).
            ((h_neg=h_neg>haut-zero?h_neg:haut-zero))

            # Init global
            get_csv=0
            car=""
            haut=0
            err_val_car=0; err_key_zero=0; err_val_zero=0; err_nb_profile=0
            err_format=0; err_val_repeat=0; err_key_not_recon=0
            con_test=""
            delete Dessin_param

            # Tableau Csv des clés de la ligne CSV, n_f = nombre d´éléments.
            n_f=split(csv, Csv, ",")

            # Vérification de la validité de la clé ´car´.
            if (Csv[1] !~ /^car=.$/ && Csv[1] !~ /^car=$/ && oc) {
               err_csv=1
               err_val_car=Csv[1]
               if (!oi) { get_csv=0 }
            }else{

            # Traitement de la clé ´car´.
               car=substr(Csv[1], index(Csv[1], "=")+1)

               # Gestion du caractère virgule (cas où ´car´ est vide).
               if (car=="") { car="," }

               # Gestion de la répétition de définition de dessin ascii.
               if (car in Ascii) {

                  # De base: accès au premier jeu de dessins.
                  if (!oc) {
                     err_car_repeat[car]++
                     get_csv=0
                  }else{

                  # Avec option ´-c´ : accès au 2ième jeu de dessins.
                     delete Ascii[car]
                     delete Zero[car]
                     delete After[car]
                     delete Profile[car]
                     delete l_Dessin[car]
                     err_car_repeat[car]++
                     L_car_ret[car]=nr
                     get_csv=1
                  }
               }else{

                  # Caractère ajouté à la liste + autorisation de récupérer le dessin ascii.
                  list_car=list_car car
                  n_car_ok++
                  First_car_finded[car]=nr
                  L_car_ret[car]=nr
                  get_csv=1
               }
               n_car++
            }

            # Ajout de la virgule dans la dernière liste de caractère (si présente).
            if (Csv[n_f]=="") {
               Csv[(n_f-1)]=Csv[(n_f-1)]","
               delete Csv[n_f]
            }

            # Gestion des autres clés CSV.
            for (i in Csv) {

               # Clé et paramètre de la clé.
               key=substr(Csv[i], 1, index(Csv[i], "=")-1)
               Dessin_param[key]=substr(Csv[i], index(Csv[i], "=")+1)

               # Clé non reconue.
               if (key !~ /^car$|^zero$|^after$|^profile$/) { err_key_not_recon=key }

               # Traitement de la clé ´zero´.
               if (key=="zero") {
                  zero=Dessin_param[key]

                  # Nombre de ligne supérieures (maximum des zeros).
                  ((h_pos=h_pos>zero?h_pos:zero))

                  # Test de la validité de la valeur de la clé "zero".
                  if (zero !~ /^(|+|-)[[:digit:]]?*$/ && oc) {
                     err_csv=1
                     err_val_zero=1
                     if (!oi) { get_csv=0 }
                  }else{
                     Zero[car]=zero
                  }
               }

               # Test de la validité des valeurs des clés ´after´ et ´profile´.
               dat=Dessin_param[key]
               if ((key=="after" || key=="profile") && (!dat || dat !~ rgx) && oc) {
                  err_csv=1
                  if (ov>=1) {
                     printf("Ligne %-4s car=%s : Mauvais format de la clé \"%s\"\n", nr, car, key) > "/dev/stderr"
                  }
                  if (!oi) { get_csv=0 }
               }

               # Traitement de la clé ´after´.
               if (key=="after") {
                  After[car][1]=""
                  split(Dessin_param[key], After[car], " ")

                  # Concaténation des listes des caractères pour vérification de non-répétition.
                  if (oc) {
                     for (idx in After[car]) {
                        con_test=con_test substr(After[car][idx], (index(After[car][idx], "_")+1))
                     }
                  }
               }

               # Traitement de la clé ´profile´.
               if (key=="profile") {
                  Profile[car][1]=""
                  split(Dessin_param[key], Profile[car], " ")

                  # Concaténation des listes des caractères pour vérification de non-répétition.
                  if (oc) {
                     for (idx in Profile[car]) {
                        con_test=con_test substr(Profile[car][idx], (index(Profile[car][idx], "_")+1))

                  # Test si le nombre est négatif (interdit).
                        n_p=substr(Profile[car][idx], 1, index(Profile[car][idx], "_")+1)
                        if (n_p<0) {
                           err_nb_profile=1
                           err_csv=1
                        }
                     }
                  }
               }
            }

            # Test de la présence de la clé ´zero´.
            if (!("zero" in Dessin_param) && oc) {
               err_key_zero=1
               err_csv=1
               if (!oi) { get_csv=0 }
            }

            # Test de la non-répétition de caractère dans les listes de caractères csv.
            if (con_test && oc) {
               for (c=1;c<=length(con_test);c++) {
                  _test=substr(con_test,c,1)
                  _test=car_spec(_test)
                  _test=_test".*"_test
                  if (con_test ~ _test ) {
                     err_val_repeat=1
                     err_csv=1
                     if (!oi) { get_csv=0 }
                     break
                  }
               }
            }

            # Affichage des erreurs dans le fichier de dessins Ascii (niveau 1 de verbose).
            if (ov>=1 && oc) {
               if (err_val_car) {
                  printf("Ligne %-4s %s : Mauvaise valeur de la clé \"car\", dessin Ascii non accessible.\n", nr, err_val_car) > "/dev/stderr"
               }
               if (err_key_zero) {
                  printf("Ligne %-4s car=%s : La ligne CSV ne contient pas la clé \"zero\", dessin Ascii non accessible.\n", nr, car) > "/dev/stderr"
               }
               if (car in err_car_repeat) {
                  printf("Ligne %-4s car=%s : Ce caractère a déjà été décrit à la ligne %s.\n", nr, car, First_car_finded[car]) > "/dev/stderr"
               }
               if (err_val_zero) {
                  printf("Ligne %-4s car=%s : Mauvaise valeur de la clé \"zero\".\n", nr, car) > "/dev/stderr"
               }
               if (err_nb_profile) {
                  printf("Ligne %-4s car=%s : Nombre négatif dans la clé \"profile\".\n", nr, car) > "/dev/stderr"
               }
               if (err_val_repeat) {
                  printf("Ligne %-4s car=%s : Un même caractère apparaît dans plusieurs clés et/ou valeurs.\n", nr, car) > "/dev/stderr"
               }
               if (err_key_not_recon) {
                  printf("Ligne %-4s car=%s : La ligne CSV contient une clé non reconnue : %s\n", nr, car, err_key_not_recon) > "/dev/stderr"
               }
               if (err_trail) {
                  printf("Ligne %-4s car=%s : Ligne avec au moins un blanc à la fin.\n", nr, car) > "/dev/stderr"
               }
            }

         # Récupération du dessin ascii.
         }else if (get_csv) {
            haut++
            Ascii[car][haut]=line

            # Largeur du dessin ascii (maximum des longueurs des lignes du dessin).
            long=length(line)
            ((l_Dessin[car]=l_Dessin[car]>long?l_Dessin[car]:long))
         }
      }

      # Câlage en hauteur des dessins ascii + mise au carré.
      ((h_neg=h_neg>haut-zero?h_neg:haut-zero))
      h_tot=h_pos+h_neg
      for (car in Ascii) {
         h_seek[car]=h_pos-Zero[car]
         for (i=1;i<=h_tot;i++){
            if (i in Ascii[car]) {
               Dessin[car][i+h_seek[car]]=Ascii[car][i]
               diff=l_Dessin[car]-length(Dessin[car][i+h_seek[car]])
               if (diff>0)  {
                  for (j=1;j<=diff;j++) {
                     Dessin[car][i+h_seek[car]]=Dessin[car][i+h_seek[car]]" "
                  }
               }
            }
            if (!(i in Dessin[car])) {
               for (j=1;j<=l_Dessin[car];j++) {
                  Dessin[car][i]=Dessin[car][i]" "
               }
            }
         }
      }

      # Affichage des statistiques du fichier de dessins.
      if (ov>=1) {
         printf("Statistiques du fichier de dessins :\n") > "/dev/stderr"
         printf("   Hauteur totale d\x27un dessin : %d lignes.\n", h_tot) > "/dev/stderr"
         printf("   Ligne de référence (ligne 0) : %dième (%d supérieures, %d inférieures).\n", h_pos, h_pos, h_neg) > "/dev/stderr"
         printf("   %d dessins trouvés au total.\n", n_car) > "/dev/stderr"
         printf("   %d dessins accessibles.\n", n_car_ok) > "/dev/stderr"
         printf("   Liste des caractères dessinables trouvés dans le fichier de dessins :\n") > "/dev/stderr"
         while (list_car) {tmp=substr(list_car,1,74); list_car=substr(list_car,74) ; print "      "tmp > "/dev/stderr"}
         if (isarray(err_car_repeat)) {
            print "   Répétions de définitions de dessins Ascii :"
            for (i in err_car_repeat) {
               xfois=err_car_repeat[i]+1
               printf("      Le caractère \x27%s\x27 est défini %d fois. Le dessin décrit à la ligne %d est retenu.\n", i, xfois, L_car_ret[i]) > "/dev/stderr"
            }
         }
      }

      # Affichage de l´état du fichier (conforme, non conforme ou non vérifié).
      if (err_csv && oc) {
         printf("Fichier de dessins non conforme.\n") > "/dev/stderr"
      }else{
         if (ov && !oc) {
            printf("Fichier de dessins non vérifié.\n") > "/dev/stderr"
         }else if (oc) {
            printf("Fichier de dessins conforme.\n") > "/dev/stderr"
         }
      }

      # Affichage des dessins ascii et de leurs données csv (niveau 3 de verbosité).
      if (ov>2) {
         printf("\n\nDessins Ascii trouvés et recalés en hauteur + valeurs CSV relevées :\n") > "/dev/stderr"
         for (i in Dessin){
            printf("\ncar=%s\nzero=%d\n", i, Zero[i]) > "/dev/stderr"
            if (i in After){
               for (j in After[i]){ printf("After[%s][%s]=%s\n", i, j, After[i][j]) > "/dev/stderr" }
            }
            if (i in Profile){
               for (j in Profile[i]) { printf("Profile[%s][%s]=%s\n", i, j, Profile[i][j]) > "/dev/stderr" }
            }
            for (j in Dessin[i]){ printf("%-14s%s\n", "Dessin["i"]["j"]=", Dessin[i][j]) > "/dev/stderr" }
         }
         printf("\n") > "/dev/stderr"
      }

      # Gestion de la sortie après lecture du fichier de dessin (selon options).
      if (oc && err_csv && !oi || oq) {
         if (!conf) { m="erreur dans le fichier de dessins" }
         if (oq) { m="option \x27"oq"\x27" }
         printf("Sortie par %s.\n", m) > "/dev/stderr"
         exit err_csv
      }else if (oi && oc && err_csv) {
         print "Ignorer les erreurs et continuer ..." > "/dev/stderr"
      }

      # Premier affichage du traitement du texte à convertir (fin du BEGIN).
      if (ov>1) {printf("\n%s\n", "Construction du texte Ascii Art :") > "/dev/stderr" }

   }

   {
   # Construction du texte en dessin Ascii.

      # Srcutation des caractères du texte à convertir.
      for (i=1;i<=NF;i++) {
         if ($i in Dessin || $i==" ") {

            # Traitement des données Csv.
            if (i>1) {
               $(i-1)=car_spec($(i-1))

               # Récupération des données csv utiles au dessin Ascii à poser.
               if ($i in Profile) {
                  for (j in Profile[$i]) {
                     to_match=substr(Profile[$i][j], index(Profile[$i][j], "_")+1)
                     to_match=gensub(/\$/, "\\$", "g", to_match)
                     if (to_match ~ $(i-1)) {
                        n_after=substr(Profile[$i][j], 1, index(Profile[$i][j], "_")-1)
                        sub(/^+/, "" , n_after)
                        type="Profile"
                        matches=$(i-1)
                        break
                     }else{
                        to_match=""
                     }
                  }
               }
               if ($i in After && !n_after) {
                  for (j in After[$i]) {
                     to_match=substr(After[$i][j], index(After[$i][j], "_")+1)
                     to_match=gensub(/\$/, "\\$", "g", to_match)
                     if (to_match ~ $(i-1)) {
                        n_after=substr(After[$i][j], 1, index(After[$i][j], "_")-1)
                        sub(/^+/, "" , n_after)
                        type="After"
                        matches=$(i-1)
                        break
                     }else{
                        to_match=""
                     }
                  }
               }
            }

            # Construction du dessin Ascii ligne par ligne.
            for (j=1;j<=h_tot;j++) {

               # Gestion des espaces dans le texte à convertir.
               if ($i==" ") {
                  Resultat[NR][j]=Resultat[NR][j] space
               }else{
                  Ascii_tmp=Dessin[$i][j]

                  # Mise en profil du dessin Ascii et du texte déjà converti.
                  if (type=="Profile") {
                     x=0
                     while (sub(/ $/, "", Resultat[NR][j])) {
                        x++
                        if (x>l_Dessin[$(i-1)]) { break }
                     }
                     sub(/^ +/, "", Ascii_tmp)
                     for (k=1;k<=n_after;k++) { Resultat[NR][j]=Resultat[NR][j]" " }
                  }else{

                  # Arrangement du texte déjà converti et du dessin Ascii à poser.

                     # Ajout d´espaces séparateurs.
                     if (n_after>0) {
                        trail=""
                        for (k=1;k<=n_after;k++) { trail=trail" " }
                        Resultat[NR][j]=Resultat[NR][j] trail
                     }else{

                     # Rapprochement par enlèvement d´espaces + gestion des collisions.
                        for (k=-n_after;k>0;k--) {
                           if (!sub(/ $/, "",Resultat[NR][j])) {
                              if (!sub(/^ /, "", Ascii_tmp)) {
                                 # Collision trouvée avec le dessin Ascii précédent.
                                 err_collision=1
                              }
                           }
                        }
                     }
                  }

                  # Pré-enregistrement de la verbosité (pas d´affichage ici).
                  if (ov>1) {
                     if (!sep) { verbose=verbose sprintf("\n") }
                     verbose=verbose sprintf("X%sX--\n",Resultat[NR][j])
                     sep=1
                  }

                  # Ajout du dessin ascii (ligne par ligne).
                  Resultat[NR][j]=Resultat[NR][j]Ascii_tmp
                  lgg=length(Resultat[NR][j])
                  ((lg_mot_max=lg_mot_max>lgg?lg_mot_max:lgg))
               }
            }

            # Ré-alignement vertical au plus près du dessin Ascii posé.
            for (j in Resultat[NR]) {
               lg_mot=length(Resultat[NR][j])
               for (k=1;k<=lg_mot_max-lg_mot;k++) {
                  Resultat[NR][j]=Resultat[NR][j]" "
               }
            }

            # Affichage de la verbosité (selon niveau).
            if (ov>1) {
               if (old_NR<NR) { printf("\n\nLigne %d du texte à convertir :\n", NR) > "/dev/stderr" }
               printf("\nDessin Ascii à poser = \"%s\"\n", $i) > "/dev/stderr"
            }
            if (ov>=1 && err_collision) { printf("Collision entre le dessin \"%s\" et \"%s\".\n", $(i-1), $i) > "/dev/stderr" }
            if (ov>2) {
               if (i>1) {prec=$(i-1)}
               printf("   préc=%-5s n_after=%-5s to_match=%-5s matches=%-5s",prec , n_after ,to_match, matches) > "/dev/stderr"
               if (type=="Profile") { print "(profile=ON)" }else{ printf("\n") > "/dev/stderr" }
               if ($i in Dessin){ for (k=1;k<=h_tot;k++){ print Dessin[$i][k] > "/dev/stderr" } }
               if (verbose) { print verbose > "/dev/stderr" }
            }
            if (ov>1) { for (k=1;k<=h_tot;k++) { print "X"Resultat[NR][k]"X" > "/dev/stderr" } }

         }else{

            # Caractère non défini dans le fichier de dessins Ascii (verbosité).
            if (ov>=1) {
               if (!not_found) { printf("\n") > "/dev/stderr" }
               car_nf=car_spec($i)
               if (list_not_found !~ car_nf || ov>=2) {
                  if (ov>=2) { printf("\n") }
                  printf("Caractère \"%s\" non trouvé dans le fichier de dessins Ascii.\n", $i) > "/dev/stderr"
                  list_not_found=list_not_found car_nf
               }
               not_found=1
            }
         }

         # Init pour le prochain caractère à traiter.
         old_NR=NR
         n_after=0; lg_mot_max=0;
         err_collision=0; sep=0
         type=""; to_match=""; matches=""; verbose=""
      }
   }
   END {

      # Sortie si option ´-c´ sans ´-i´ et erreur dans le fichier de dessins Ascii, ou si option ´-q´.
      if (oc && err_csv && !oi || oq) {
         exit err_csv
      }else{

      # Affichage du résultat (+ fichier de sortie).
         if (ov>=1) { printf("\nRésultat :\n") > "/dev/stderr" }
         for (i=1;i<=NR;i++) {
            for (j=1;j<=h_tot;j++) {
               print Resultat[i][j]
               if (oo) { print Resultat[i][j] > oo }
            }
            printf("\n")
            if (oo) { printf("\n") > oo }
         }
      }
   }

   function car_spec(car) {
      # Ajustement des caractères spéciaux.
      if (car=="\\") { return "\\\\\\\\" }
      if (car=="[") { return "\\[" }
      if (car=="]") { return "\\]" }
      if (car=="(") { return "\\(" }
      if (car==")") { return "\\)" }
      if (car=="^") { return "\\^" }
      if (car=="$") { return "\\$" }
      if (car==".") { return "\\." }
      if (car=="?") { return "\\?" }
      if (car=="*") { return "\\*" }
      if (car=="|") { return "\\|" }
      if (car=="+") { return "\\+" }
      return car
   }
' <<< "$texte"

exit $?
