Nous venons d'étudier les fonctions qui permettent de lire les informations contenues dans une base de données, mais pour agir sur l'apparence du terminal nous nous doutons bien qu'il ne suffit pas de recevoir des données mais aussi d'en transmettre.En effet, s'il s'agit d'une action simple que doit réaliser le terminal, nous pouvons penser qu'il suffit de lui transmettre un code qui déclenche l'action, si l'action est plus complexe il faudra certainement que nous puissions transmettre, en plus des paramètres.
Nous allons étudier les deux cas à travers l'examen détaillé de deux nouvelles
capacités, clear
qui efface l'écran et replace le curseur en haut et à
gauche de l'écran, cup
qui place le curseur à un emplacement déterminé
de l'écran. Enregistrons tout d'abord les chaînes de caractères associées à ces
deux capacités.
clear
et cup
L'utilisation de la fonction tigetstr
avec la capacité clear
donne les messages suivants :
[pierre@localhost terminfo]$ ./testcapc xterm clear
Traitement correct
La capacité clear est supportée par le terminal xterm
Valeur de clear : \E[H\E[2J
[pierre@localhost terminfo]$ ./testcapc linux clear
Traitement correct
La capacité clear est supportée par le terminal linux
Valeur de clear : \E[H\E[J
clear
Un petit commentaire s'impose sur la signification de cette chaîne de
caractères. J'ai opté pour un affichage semblable à celui que l'on trouve dans
les fichiers sources de terminfo
et dans l'affichage produit par
l'utilitaire infocmp
.
Le groupe de caractères \E
correspond effectivement au démarrage
d'une séquence d'échappement.Si vous faites afficher le code ASCII, vous
obtiendrez la valeur 27, c'est à dire ESCAPE.
Le second caractère '['
a pour code ASCII 91. Ce caractère indique
l'attente de codes de commandes de contrôle du terminal (CSI).
Le caractère 'H' qui suit est le code de la commande qui déplace le curseur à
une position déterminée. Par défaut, c'est à dire en l'absence de paramètres
définissant la position en Ligne,Colonne, le curseur est placé dans le coin
supérieur gauche de l'écran du terminal (position 0,0).Vous pouvez aisément
tester cela en utilisant la fonction printf comme le conseille
Cédric dans sa documentation sur ce sujet.
Nous comprenons dès lors que la deuxième chaîne \E[
ouvre une seconde
séquence et cette fois le code 'J'
est le code qui efface l'écran.
Vous noterez que le terminal linux
et xterm
n'ont pas le même
attribut : le terminal linux
est sans attribut, xterm
utilise
la paramètre 2. Rien d'étonnant puisque cela revient au même ! En effet selon
la norme ECMA-48/ISO dont le gestionnaire de terminaux Linux, implémente un
sous-ensemble important, par défaut cette séquence de codes efface tout
l'écran, lorsque l'on place 1 comme attribut l'écran est effacé de son
origine jusqu'à la position du curseur, lorqu'il vaut 2, tout l'écran est
effacé.
Ainsi, la capacité clear
de la base de données terminfo
se
présente comme une composition de séquence de codes d'échappement : une
première qui envoie une commande de positionnement du curseur, \E[H
; une
seconde qui efface l'écran, \EJ
ou \E2J
.
Vous pouvez vérifier cela en envoyant séparément chacune des commandes au Terminal à l'aide de la fonction printf, de cette manière :
printf("\033[H");
car=getchar();
printf("\033[J");
cup
La lecture de la valeur associée à la capacité cup
dans la base de
données terminfo
des terminaux linux
et xterm
, nous
donne ce résultat :
[pierre@localhost terminfo]$ ./testcapc linux cup
Traitement correct
La capacité cup est supportée par le terminal linux
Valeur de cup : \E[%i%p1%d;%p2%dH
[pierre@localhost terminfo]$ ./testcapc xterm cup
Traitement correct
La capacité cup est supportée par le terminal xterm
Valeur de cup : \E[%i%p1%d;%p2%dH
Cette fois, les bases de données des deux terminaux contiennent la même chaîne
de caractères.Si nous isolons le début et la fin de la chaîne de caractères,
nous retrouvons bien la séquence \E[...H
que nous avions analysé dans
le paragraphe précédent et qui correspond à une commande de positionnement du
curseur.Entre les deux nous trouvons une succession de caractères séparés par
un point-virgule (;), ce point virgule sépare les deux attributs attendus par
le terminal, la position dans la ligne, la position en colonne.
Voici donc la signification de chacun de ces signes :
%i indique que les arguments transmis doivent être incrémentés de 1. Cette
incrémentation est rendue nécessaire parce que l'origine de l'écran est 0,0.
Mais cerains terminaux ont une origine 1,1. Donc pour les terminaux à
origine 0,0, on incrémente de 1 et on applique la même procédure.
%p1 et %p2 placent respectivement le premier argument et les second argument
sur la pile.
%d Affiche le sommet de la pile sous forme décimal.
Nous constatons donc que cette chaîne de caractères ne correspond pas à la chaîne de caractères à envoyer au terminal. Puisqu'elle décrit un processus à mettre en oeuvre. Comment allons-nous créer cette chaîne de caractères correspondant à la séquence d'échappement à envoyer au terminal ?
cup
Deux arguments sont attendus pour cette capacité :
tparm
Le prototype de cette fonction est le suivant :
char * tparm(const char * str,...);Cette fonction reçoit comme premier paramètre une chaîne de caractères qui est le résultat de la fonction de lecture d'une capacité
tigetstr
, les
arguments suivants sont de type numérique et doivent être au nombre et dans
l'ordre des arguments attendus par la capacité utilisée.
tparm
avec la capacité cup
Une fois de plus, je me permets de reproduire un programme bien trivial.
#include <stdio.h>
#include <term.h>
#include <ncurses.h>
void affiche(char * m)
{
int i;
for(i=0; i<strlen(m);i++)
if (m[i]==27)
printf("\\E");
else
printf("%c",m[i]);
}
int main(int argc, char * argv[])
{
int r,rb;
char * resu;
char * esc_seq;
int erreur;
char capa[]="cup";
if (argc<2){
printf("Entrez le nom d'un terminal\n");
exit(1);
}
else
r=setupterm(argv[1], fileno(stdout),&erreur);//Terminal de la ligne de commande
if (r==OK){
printf("Traitement correct\n");
resu=tigetstr(capa);
rb=(int)resu;
switch(rb){
case -1 :
printf("%s n'est pas une capacité de type chaîne\n",capa);
break;
case 0 :
printf("La capacité %s n'est pas supportée par le terminal %s\n",capa,argv[1]);
break;
/*Si tout s'est bien passé on applique le traitement par défaut suivant.
La chaîne resu contient alors la valeur dans terminfo de la capacité
cup pour le terminal transmis par la ligne de commande.
On fait afficher cette chaîne et on construit à l'aide de la fonction
tparm la séquence d'échappement à envoyer au terminal enregistrée dans
esc_seq*/
default :
printf("Valeur de la capacité cup lue par tigetstr : ");
affiche(resu);
printf("\n");
esc_seq=tparm(resu,15,30);
printf("Chaîne à envoyer : ");
affiche(esc_seq);
printf(" au terminal %s\n",argv[1]);
break;
}
}
else
switch(erreur){
case 0 :
printf("Le terminal %s est inconnu.\n",argv[1]);
break;
case -1 :
printf("Aucune base de données pour le terminal %s.\n",argv[1]);
break;
}
return 0;
}
Voici le résultat affiché par ce programme :
[pierre@localhost terminfo]$ ./testcha linux Traitement correct Valeur de la capacité cup lue par tigetstr : \E[%i%p1%d;%p2%dH Chaîne à envoyer : \E[16;31H au terminal linuxTrois constatations s'imposent à la lecture de cet affichage :
tigetstr
a bien ramené la chaîne de caractères
contenue dans la base de données terminfo
pour le terminal
linux
: \E[%i%p1%d;%p2%dHtparm
a bien construit une séquence de codes
d'échappement : \E[16;31Htparm
est un interpréteur des capacités définies
dansterminfo
. On remarque en particulier que la fonction tparm
a été invoquée avec comme arguments 15,30. Comme prévu par la valeur %i
de la capacité cup
ces deux nombres ont bien été incrémentés de 1.printf
ou putp
?
Une fois obtenue la séquence de codes d'échappement à l'aide de la fonction
tparm
, reste à expédier le tout au terminal. Vous pouvez bien entendu
envoyer la séquence de codes à l'aide de la fonction printf
.
Nous pouvons cependant préférer l'utilisation de la fonction putp
qui
appartient à la bibliothèque que nous avons utilisée. Le prototype de cette
fonction est le suivant :
int putp(const char * str);De sorte que dans l'exemple précédent nous aurions pu invoquer directement la fonction
putp
ainsi :
putp(tparm(resu,15,30));pour obtenir le déplacement du curseur en ligne 15, colonne 30.