Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 03/03/2010, à 01:01

arnaud_d

scanf, std::cin et sécurité

Bonsoir,

J'ai appris le C et le C++ au cours de mes études d'ingé et je souhaiterais m'y remettre.
En lisant mes deux sites préférés en la matière, à savoir developpez.com et cplusplus.com je me rends compte que j'ai appris à programmer comme un cochon.

Il y a quelques mois on m'expliquait plein de choses interessantes à propos d'espace de nommage sur le forum (non on ne met pas using namespace std à chaque début de programme), ce soir je viens pour une autre question à propos de scanf et de la sécurité.

Voilà, je viens de lire l'article scanf de developpez.com qui m'a vraiment impressioné. J'avais jamais appris à vérifier le nombre de champs analysés par scanf, c'est à dire l'entier que renvoie cette fonction, et encore moi de vider le buffer.

Me voilà maintenant prêt à appliquer ces conseils. Je me suis fait une fiche avec plusieurs colonnes, une pour chaque langage que je connais (bash, C, C++ et Python) et à chaque fois je met côte à côte le code correpondant à une même tache.

Sauf que voilà, comment prend-on toutes ces précautions sous C++ ? Ce que je veux dire c'est que si j'ai bien compris, scanf c'est du C et std::cin c'est du C++, pas question d'utiliser scanf dans un programme en C++.

Mais alors, quelqu'un pourrait-il me dire ce que deviendrait le programme suivant en C++ ?

#include <stdio.h>

int main(void){

  int nombre = 0;
  int ok = 0;
  int retour;

  printf("saisissez un nombre :\n");
  while (!ok){

    retour = scanf("%d%*[^\n]", &nombre);
    printf("retour : %d\n", retour);
    if ( !retour ){
      /* erreur de saisie, on vide le flux */
      int c;
      while ( ((c = getchar()) != '\n') && c != EOF);

      printf("on vous a demande de saisir un nombre\n");
      printf("veuillez recommencer :\n");
    }
    else {
      /* reussite de la saisie */
      getchar(); /* on enleve le '\n' restant */

      printf("saisie acceptee\n");
      ok = 1;  /* sort de la boucle */
    }

  }

  return 0;
}

Les deux lignes les plus importantes sont bien sûr :

retour = scanf("%d%*[^\n]", &nombre);

pour ne valider que l'entier si l'utilisateur s'amuse à entrer par exemple "43lokfds" et

while ( ((c = getchar()) != '\n') && c != EOF);

pour vider le flux.

Merci pour votre aide !

Hors ligne

#2 Le 03/03/2010, à 01:30

Le Farfadet Spatial

Re : scanf, std::cin et sécurité

Salut à tous !

arnaud_d a écrit :

non on ne met pas using namespace std à chaque début de programme

Tiens, cela pourrait bien être moi qui ait dit ça. En tout cas, c'est tout à fait vrai.

   Concernant le sujet qui t'amène, globalement, tu n'as pas besoin de te soucier de cela avec la bibliothèque standard C++. Un exemple vite-fait-mal-fait :

#include <iostream>

int main (void) {
  int nombre;
  std::cin >> nombre;
  std::cout << nombre << '\n';
  return 0;
}

Une trace d'exécution :

$ ./test 
43lokfds
43

On voit bien que seul les nombres ont été pris en compte.

   La bibliothèque standard s'occupe de vider le flux, toutefois tu peux gérer cela de manière fine, cf. le Stroustrup, que je ne doute pas que tu t'es procuré !

   À bientôt.

                                                                                                                                 Le Farfadet Spatial

Hors ligne

#3 Le 03/03/2010, à 14:33

arnaud_d

Re : scanf, std::cin et sécurité

Salut,

Oui oui, je confirme c'était toi smile ici

Ok donc tout ça est assuré par std::cin.

Je te remercie pour toutes tes explications parce que les bases du C++ ne sont vraiment pas claires. Quand on m'a appris le C++, on m'a présenté ça comme une amélioration du C permettant de disposer des classes et de faire de jolies GUI sous Visual C++. Donc du coup pour moi il y avait un monde C = console = scanf et un monde C++ = GUI = champs de saisie. Voila pourquoi je comprend rien au std::cin etc...

Cependant j'ai une autre question : qu'est-ce qui remplace le fscanf en C++, je veux dire, comment fait-on pour extraire des données dans un fichier ?

Mon but là c'est d'arriver à faire un programme en C++ qui extrait des données dans un fichier texte et les traite genre

data.txt

Le Farfadet 1940
arnaud_d 1984
$ ./prog
Le Farfadet est le plus vieux car il a 70 ans

Est-ce que je suis obligé de passer par du Regex auquel je ne comprend toujours rien malgré plusieurs mois d'efforts ou est-ce qu'il existe un système comme le masque du scanf ? Parce qu'en plus je veux pas qu'ils s'arrête après le "Le" de "Le Farfadet".

Merci pour ton aide

Arnaud

Hors ligne

#4 Le 03/03/2010, à 15:16

Le Farfadet Spatial

Re : scanf, std::cin et sécurité

Salut à tous !

arnaud_d a écrit :

Je te remercie pour toutes tes explications parce que les bases du C++ ne sont vraiment pas claires. Quand on m'a appris le C++, on m'a présenté ça comme une amélioration du C permettant de disposer des classes et de faire de jolies GUI sous Visual C++. Donc du coup pour moi il y avait un monde C = console = scanf et un monde C++ = GUI = champs de saisie. Voila pourquoi je comprend rien au std::cin etc...

Lorsque Bjarne STROUSTRUP a lancé son projet C with classes, au tout début des années quatre-vingt, il s'agissait bien d'ajouter la possibilité de créer des classes dans C. Cependant, C++ s'est peu-à-peu détaché de C, pour devenir un langage différent. La bibliothèque standard C++, notamment, a bénéficié du recul obtenu avec la pratique de la bibliothèque standard C et des spécificités de C++.

   Le problème, c'est que, encore maintenant, C++ est enseigné comme une sur-couche de C, ce qui est une erreur et entraîne les confusions auxquelles tu te heurtes. En plus, trop souvent également, l'enseignement de C++ se résume à l'enseignement de Visual C++, qui ne respecte pas toujours la norme.

Cependant j'ai une autre question : qu'est-ce qui remplace le fscanf en C++, je veux dire, comment fait-on pour extraire des données dans un fichier ?

Mon but là c'est d'arriver à faire un programme en C++ qui extrait des données dans un fichier texte et les traite genre

data.txt

Le Farfadet 1940
arnaud_d 1984
$ ./prog
Le Farfadet est le plus vieux car il a 70 ans

Est-ce que je suis obligé de passer par du Regex auquel je ne comprend toujours rien malgré plusieurs mois d'efforts ou est-ce qu'il existe un système comme le masque du scanf ? Parce qu'en plus je veux pas qu'ils s'arrête après le "Le" de "Le Farfadet".

Le Farfadet Spatial existe depuis bien plus de 70 ans, il observe votre planète depuis des éons -- et il n'a pas de problème d'égo, raison pour laquelle il parle de lui à la troisième personne !

   Plus sérieusement, il y a plusieurs solutions à ton problème.

   Tout d'abord, getline (std::cout.getline(chaine)) permet de récupérer les valeurs du fichier lignes par lignes et les streamstrings -- std::stringstream, std::istringstream et std::ostringstream -- permettent d'effectuer des manipulations de type flux sur des chaînes de caractères, deux éléments qui peuvent t'aider.

   Ensuite, tu peux faire attention à ton formatage, par exemple en décidant que le nom et la date de naissance doivent être séparés par une tabulation, ce qui permet de savoir si on a affaire à un nom composé.

   Tu peux aussi utiliser les expressions régulières, donc. Visiblement, tu n'accroches pas. C'est dommage, parce que c'est souvent très utile.

   Enfin, tu peux formater tes données en XML et utiliser Libxml++, très bien faite.

   Laquelle de ces solutions de convient le mieux ?

   En attendant, je te rappelle les références de l'évangile selon saint STROUSTRUP :

      Le Langage C++
      Bjarne STROUSTRUP
      Pearson Education

   À bientôt.

                                                                                                                                             Le Farfadet Spatial

Hors ligne

#5 Le 03/03/2010, à 16:23

arnaud_d

Re : scanf, std::cin et sécurité

Merci pour ta réponse.

Je suis content de savoir que tu as plus de 70 ans car la sagesse de tes propos est à la mesure de ton age.

Merci de m'avoir précisé de quel ouvrage de Stroustrup tu faisais référence et non, je ne l'ai pas. Je vais voir si je peux me l'acheter.

Merci pour les pistes que tu m'as données, j'espère revenir un de ces jours avec une solution (ce que je n'ai jamais fait lors de notre dernière conversation ^^).

Je ne suis pas définitivement fâché avec les RE, c'est juste un problème de capacité neuronique inssufisante pour aborder ce machin. Je vais persister...

A bientôt.

PS : je préfère ta première solution...

Hors ligne

#6 Le 03/03/2010, à 16:49

Le Farfadet Spatial

Re : scanf, std::cin et sécurité

Salut à tous !

arnaud_d a écrit :

Je suis content de savoir que tu as plus de 70 ans car la sagesse de tes propos est à la mesure de ton age.

Il vous en prie !

Merci de m'avoir précisé de quel ouvrage de Stroustrup tu faisais référence et non, je ne l'ai pas. Je vais voir si je peux me l'acheter.

Lorsque l'on commence à vraiment vouloir maitriser C++, il est en effet indispensable. En général, on peut facilement l'emprunter en bibliothèque ou l'acheter en librairie.

Je ne suis pas définitivement fâché avec les RE, c'est juste un problème de capacité neuronique inssufisante pour aborder ce machin. Je vais persister...

Le livre suivant peut t'aider :

      Maîtrise des expressions régulières
      Jeffrey E. F. FRIEDL
      O'Reilly

PS : je préfère ta première solution...

Dans ce cas, tu trouveras toutes les références sur les flux, les chaînes de caractères et ce qui s'ensuit dans le STROUSTRUP. Ce sera plus complet que ce que je pourrais te dire sur ce forum. Cela dit, n'hésite pas à revenir si tu as des questions.

   À mon avis, c'est tout de même bien de réfléchir un peu au format sous lequel tu vas enregistrer des données, ça t'aidera beaucoup.

   À bientôt.

                                                                                                                                             Le Farfadet Spatial

Hors ligne

#7 Le 04/03/2010, à 14:37

arnaud_d

Re : scanf, std::cin et sécurité

Tiens en attendant, je peux te poser une autre question?

Comme je te disais je fais un tableau d'équivalence entre langages et voici la section "Binary file : reading one byte at a given position and print its hex representation"

En python :

# -*- coding:Utf-8 -*-
#!/usr/bin/python

f = open('file.bin','rb') 
f.seek(0x0BD2) 
byte = f.read(1) 
print byte.encode("hex") 
f.close()

et en C++ je n'y arrive pas, il ne veux pas m'afficher le code hexa du char lu :

#include <iostream> 
#include <fstream> 

int main(int argc, char* argv[]) 
{ 
  int length(1); 
  char* memblock; 
  std::ifstream f("file.bin", std::ios::in|std::ios::binary); 
  if (f.is_open()) 
  { 
    memblock = new char[length]; 
    f.seekg(0x0BD2, std::ios::beg); 
    f.read(memblock, length); 
    f.close();
    std::cout << std::hex << memblock << std::endl;
	delete[] memblock;
  } 
  else std::cout << "Unable to open file"; 
  return 0; 
}

A ton avis pourquoi ?

Hors ligne

#8 Le 04/03/2010, à 17:05

Link31

Re : scanf, std::cin et sécurité

std::cout << "0x" << std::hex << static_cast<int>(*memblock) << std::endl;

Hors ligne

#9 Le 04/03/2010, à 17:41

arnaud_d

Re : scanf, std::cin et sécurité

Bonjour Link31,

Décidément quand j'ai un problème en C++ toi et Le Farfadet n'êtes jamais bien loin smile

Je me disais bien qu'il y avait un problème de cast mais je savais pas comment faire.

Par contre il y a un problème de signe si je puis dire : si par exemple je cherche à lire un byte 0x92 dans mon fichier alors en intégrant ta ligne j'obtiens

0xffffff92

qui correspond à l'entier signé -110 (si j'enlève la conversion en hexa).

Comment obtenir simplement 0x92 (si possible sans ajouter un signe moins ce qui est la première solution à laquelle j'ai pensé mais qui me semble sale et qui risque surtout de marcher pour cet exemple mais poser problème pour un autre byte).

Merci de ton aide.

Hors ligne

#10 Le 04/03/2010, à 21:59

Le Farfadet Spatial

Re : scanf, std::cin et sécurité

Salut à tous !

   Arnau_d, « length » devrait être un constante, ce serait beaucoup plus propre. Je te propose de réécrire ton code ainsi :

#include <iostream> 
#include <fstream> 

int main(int argc, char* argv[]) {
  if (argc != 2) {
    std::cerr << "Usage: hexa file_name.\n";
    return -1;
  }

  std::ifstream f(argv[1], std::ios::in|std::ios::binary);
  if (!f.is_open()) {
    std::cerr << "Unable to open file named \"" << argv[1] << "\".\n";
    return -2;
  }

  const int length = 1;
  char memblock [1];
  f.seekg(0x0BD2, std::ios::beg);
  f.read(memblock, length);
  f.close();
  std::cout << "0x" << std::hex << static_cast<int>(*memblock) << '\n';

  return 0;
}

J'ai également privilégié diriger les messages d'erreurs vers la sortie d'erreurs standard.

   Cela dit, peux-tu envoyer une copie du fichier « file.bin », parce que je ne vois pas où est le problème.

   À bientôt.

                                                                                                                                 Le Farfadet Spatial

Dernière modification par Le Farfadet Spatial (Le 04/03/2010, à 22:02)

Hors ligne

#11 Le 04/03/2010, à 22:18

arnaud_d

Re : scanf, std::cin et sécurité

Ok merci, je vois maintenant parfaitement à quoi doit ressembler un joli code.

Mon fichier file.bin est le premier fichier qui me passait sous la main que j'ai renomé (en plus l'adresse 0x0BD2 est pas très éloignée donc un petit fichier convient).

Il se trouve qu'en ouvrant ce fichier avec ghex2 et en me positionnant à l'adresse 0xBD2 le byte est 0x92.

Ainsi je voudrais que mon programme C++ me retourne 0x92 et non 0xffffff92.

Ce qui me tracasse c'est que mon programme python le fait très bien, je devrais bien arriver à faire la même chose en C++ hmm

Je confirme : ce programme n'a aucun interet à part extraire la valeur hexa d'un byte à un endroit aléatoire du fichier.

Merci pour ton aide en tous cas smile

Hors ligne

#12 Le 04/03/2010, à 22:35

Le Farfadet Spatial

Re : scanf, std::cin et sécurité

Salut à tous !

arnaud_d a écrit :

Ce qui me tracasse c'est que mon programme python le fait très bien, je devrais bien arriver à faire la même chose en C++ hmm

J'ai testé le code que j'ai posté et il n'y a pas de problème : j'ai la même valeur avec ce petit code et avec Ghex. Chez moi ça marche. Du coup, j'aurais voulu tester avec ton fichier.

   À bientôt.

                                                                                                                                     Le Farfadet Spatial

Hors ligne

#13 Le 04/03/2010, à 22:57

Link31

Re : scanf, std::cin et sécurité

Tu dois utiliser un tableau d'unsigned char. Le seul souci, c'est que la STL ne définit pas std::ifstream::read() pour le type unsigned char, donc on passe par un cast supplémentaire.

Tu remarqueras au passage l'utilisation de std::vector<>, qui permet entre autres de stocker la longueur du tableau dans le tableau lui-même. Il est tout à fait possible d'utiliser un tableau de type C à la place.

#include <iostream>
#include <fstream>
#include <vector>

int main(int argc, char* argv[]) {
	if (argc != 2) {
		std::cerr << "Usage: hexa file_name.\n";
		return -1;
	}

	std::ifstream f(argv[1], std::ios::in|std::ios::binary);
	if (!f.is_open()) {
		std::cerr << "Unable to open file named \"" << argv[1] << "\".\n";
		return -2;
	}

	const int length = 1;
	std::vector<unsigned char> buf(length);
	f.seekg(0, std::ios::beg);
	f.read(reinterpret_cast<char*>(&buf[0]), buf.size());
	f.close();
	std::cout << "0x" << std::hex << static_cast<int>(buf[0]) << '\n';

	return 0;
}

Hors ligne

#14 Le 05/03/2010, à 00:23

arnaud_d

Re : scanf, std::cin et sécurité

Mouais je comprend pas tout...

J'ai essayé avec un autre fichier (j'appelerais le premier fichier file1.bin (~1 Mo) et le deuxième file2.bin (~14 ko)).

Avec l'éditeur hexa je lis les bytes de chaque fichier à l'adresse 0x0BD2 :

file1.bin : 0x92
file2.bin : 0x68

Alors que le programme de Farfadet donne respectivement 0xffffff92 et 0x68, le programme de Link31 donne dans les deux cas la bonne réponse...

Pourquoi le prog de Farfadet marche-t-il avec un fichier et pas l'autre ?

Vous trouverez une archive zip avec les deux fichiers .bin ici

Je pars me documenter un peu sur le reinterpret_cast<char*>...

Hors ligne

#15 Le 05/03/2010, à 01:20

Le Farfadet Spatial

Re : scanf, std::cin et sécurité

Salut à tous !

arnaud_d a écrit :

Je pars me documenter un peu sur le reinterpret_cast<char*>...

Tu trouveras dans le STROUSTRUP une longue discussion sur les différents types de conversion en C++.

   Ôtez-moi d'un doute : ai-je déjà indiqué que le STROUSTRUP est incontournable ?

   À bientôt.

                                                                                                                                     Le Farfadet Spatial

Hors ligne

#16 Le 05/03/2010, à 01:39

arnaud_d

Re : scanf, std::cin et sécurité

Je me demande si c'est bien normal de le trouver en téléchargement PDF sur internet en s'aidant simplement de google...

Hors ligne

#17 Le 05/03/2010, à 01:52

Le Farfadet Spatial

Re : scanf, std::cin et sécurité

Salut à tous !

arnaud_d a écrit :

Je me demande si c'est bien normal de le trouver en téléchargement

Ça a une bonne tête de violation de la propriété intellectuelle.

   À bientôt.

                                                                                         Le Farfadet Spatial

Hors ligne

#18 Le 07/03/2010, à 16:19

arnaud_d

Re : scanf, std::cin et sécurité

Bonjour,

Je voudrais vous poser une autre question à propos des headers. Je ne me souviens plus comment proceder et j'ai l'impression d'après ce que j'ai lu qu'il y a plusieurs façons de faire.

Je suis en train de m'entrainer à créer un programme axé sur les classes, le meilleur exemple je trouve est celui des figures géométriques.

J'ai donc créé

- une classe Point (deux entiers pour définir les coordonnées du point)
- une classe Shape qui dérive de Point et qui possède en plus un angle, une fonction de translation et une fonction de rotation (virtuelle)
- une classe Square qui dérive de Shape, avec un constructeur et la définition de la fonction rotation
- une classe Circle qui dérive également de Shape, avec un constructeur et une définition de la fonction rotate qui est une fonction vide.

Voici mes headers pour vous donner une idée, surtout ne vous attardez pas sur les erreurs, j'ai pas fini.

#Point.h

class Point{
  int x;
  int y;

  public :

  void tanslate(int , int );  
  Point(int , int );
}
# Shape.h

class Shape {  
  Point centre;
  int angle;

  public:

  Shape(int,int,int);  
  void translate (int, int);  
  virtual void rotate (int) = 0;
};
#Circle.h

class Circle : Public Shape {
  public :
  Circle (int, int);
};
class Square : Public Shape {
  public :
  Square (int ,int ,int );
  rotate (int);
};

Question n°1
Dois-je créer autant de headers que de source file que de classes définies ?
C'est à dire Point.h, Point.cpp, Shape.h, Shape.cpp, Circle.h, Circle.cpp ....
+ un fichier genre main.cpp (sans main.h) ?


Question(s) n°2
Dois-je mettre un #include "Point.h" dans Shape.h, dans Shape.cpp ?
Dois-je mettre un #include "Shape.h" dans Circle.h, Circle.cpp ?

Et que déclarer dans mon main.cpp ?
Et comment empêcher que des classes soient définies deux fois ? Comment utiliser #ifndef et où ?

Je viens de voir que translate était définie pour Shape ce qui est une erreur...

Merci pour vos réponses

Dernière modification par arnaud_d (Le 07/03/2010, à 16:20)

Hors ligne

#19 Le 07/03/2010, à 16:43

Le Farfadet Spatial

Re : scanf, std::cin et sécurité

Salut à tous !

   D'une manière générale, pour créer tes en-têtes et les fichiers liés -- pour l'instant, je ne me suis pas penché sur tes classes particulières.

   Tout d'abord, la norme n'impose pas grand-chose, pour ne pas dire rien. Cependant, l'expérience a permis de définir des pratiques qui fonctionnent bien.

   Tout d'abord, je te déconseille de faire un fichier d'en-tête et un fichier source pour chaque classe : bien vite, la navigation devient difficile. Au contraire, je te conseille, autant que possible, de faire en sorte que la hiérarchie de tes fichiers traduise la logique interne de ton code. Cela signifie notamment de regrouper les classes qui sont liées les unes aux autres.

   Ensuite, il est courant de décomposer d'un côté un fichier d'en-tête avec les prototypes des fonctions, de l'autre un fichier d'implémentation contenant le code effectif des fonctions. Techniquement, le fichier d'en-tête est là pour les autres parties du code utilisant les fonctions, pas pour le fichier d'implémentation. Cependant, il est très fortement recommandé d'inclure le fichier d'en-tête dans le fichier d'implémentation, car cela permet de s'assurer que prototypes et implémentations sont cohérents entre eux. Mon avis est qu'il faut toujours faire ainsi.

   Il est important de protéger les en-têtes afin d'éviter les définitions multiples. Cela se fait selon ce modèle :

#ifndef NOM_FICHIER_HPP
#define NOM_FICHIER_HPP

// Ici, le code.

#endif  // #ifndef NOM_FICHIER_HPP

En procédant ainsi, tu peux inclure le fichier dans n'importe quelle partie du code en évitant les problèmes. Si tu as recours à des modèles (« template »), alors il peut encore y avoir quelques problèmes de définitions multiples, qui se règlent alors à l'aide de « static », mais on a le temps d'y revenir.

   Dans le fichier principal du programme et d'une manière générale dans tout ton code, astreint toi à inclure tous les en-têtes auxquels le code fait directement appel, afin que tu puisses aisément isoler un fichier du reste du code. Les en-têtes utilisés de manière indirecte sont inclus par les en-têtes utilisé directement, ne cherche pas à les ajouter.

   À bientôt.

                                                                                                                                 Le Farfadet Spatial

Hors ligne

#20 Le 07/03/2010, à 17:15

arnaud_d

Re : scanf, std::cin et sécurité

Bonjour,

Merci pour ta réponse si rapide et comme d'habitude si complète.

Si je t'ai bien compris je dois faire comme suit :

// graphic.h

#ifndef _GRAPHIC_H_
#define _GRAPHIC_H_

class Point{
  int x;
  int y;

  public :

  void tanslate (int , int );  
  Point (int , int );
}

class Shape : public Point {  
  Point centre;
  int angle;

  public:

  Shape(int,int,int);  
  virtual void rotate (int) = 0;
};

class Circle : public Shape {
  public :
  Circle (int, int);
  void rotate (int);
};

class Square : public Shape {
  public :
  Square (int ,int ,int );
  void rotate (int);
};

#endif  // #ifndef _GRAPHIC_H_
// graphic.cpp

#include "graphic.h"

Point :: Point (int a, int b){
  x = a;
  y = b;
}

void Point :: translate (int a, int b){
  x += a;
  y += b;
}

void Shape :: Shape (int x, int y, int a) : Point (x,y) {
  angle = a;
}

Circle :: Circle (int x, int y) : Shape (x,y,0) {};

void Circle :: rotate (int a) {}; // Void function

Square :: Square (int a, int b, int c) : Shape (a, b, c) {};

void Square :: rotate (int rot_a){
  a += rot_a;
}
// main.cpp

#include <iostream>
#include "graphic.h"

int main(int argc, char* argv[]) 
{ 
  
  return 0; 
}

Hors ligne

#21 Le 07/03/2010, à 17:53

Le Farfadet Spatial

Re : scanf, std::cin et sécurité

Salut à tous !

arnaud_d a écrit :

Si je t'ai bien compris je dois faire comme suit :

À première vue, ça ne m'a pas l'air mal.

   À bientôt.

                                                                                                                                     Le Farfadet Spatial

Hors ligne