[Améliorations] Programme de manipulation de fichiers

Programme de manipulation de fichiers [Améliorations] - C - Programmation

Marsh Posté le 24-10-2011 à 17:26:54    

Edit : désolé pour l'indentation bizarre, il y a eu un problème lors du c/c... :S

 

Bonjour,

 

Je vous présente un petit programme de manipulation de fichiers. Je suis à la recherche de remarques, critiques, etc, vu que je ne programme que depuis un an.

 

Voici le code :

 
Code :
  1. /**
  2. * \file main.c
  3. * \brief gere les arguments du main()
  4. * \author lucas-84
  5. * \version 0.1
  6. * \date 24/10/2011
  7. *
  8. * Gere les arguments du main() d'un programme de manipulation de fichiers.
  9. *
  10. */
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include "error.h"
  15. #include "file.h"
  16. /**
  17. * \fn int main (void)
  18. * \brief Entrée du programme.
  19. *
  20. * \return EXIT_FAILURE en cas d'erreur, EXIT_SUCCESS sinon.
  21. */
  22. int main (int argc, char *argv[])
  23. {
  24.     const char *args[] = {"-c", "-r", "-w"};
  25.     ret_e (*handle_file) (const char *);
  26.     if (argc <= 1) {
  27. PRINT_ERROR_ARG_MAIN ();
  28. return EXIT_FAILURE;
  29.     }
  30.     if (strcmp (argv[1], args[0]) == 0) {
  31. handle_file = create_file;
  32.     } else if (strcmp (argv[1], args[1]) == 0) {
  33. handle_file = read_file;
  34.     } else if (strcmp (argv[1], args[2]) == 0) {
  35. handle_file = write_file;
  36.     } else {
  37. PRINT_ERROR_ARG_MAIN ();
  38. return EXIT_FAILURE;
  39.     }
  40.     if (handle_file (argv[2]) == RET_ERROR) {
  41. return EXIT_FAILURE;
  42.     }
  43.     return EXIT_SUCCESS;
  44. }
 
Code :
  1. /****************************************************************************
  2.   Name ........ : file.c
  3.   Role ........ : handles files
  4.   Author  ..... : lucas-84
  5.   Version ..... : V0.1 on 24/10/2011
  6.   Compilation :
  7.    gcc -Wall -pedantic -std=c99 -o zReader main.c file.c error.c
  8.   Execution :
  9.    ./zReader [OPTIONS] [FILE]
  10. ****************************************************************************/
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include "error.h"
  15. #include "file.h"
  16. /**
  17. * \fn static ret_e open_file (const char *path, const char *mode)
  18. * \brief Ouvre un fichier
  19. *
  20. * \param path pointeur vers une chaine de caractere indiquant le chemin du
  21. * fichier a creer.
  22. * \param mode pointeur vers une chaine de caractere indiquant le mode
  23. * d'ouverture du fichier a creer.
  24. * \return NULL en cas d'erreur, le fichier ouvert sinon.
  25. */
  26. /*@null@*/ static FILE *open_file (const char *path, const char *mode)
  27. {
  28.     FILE *f = NULL;
  29.     if ((f = fopen (path, mode)) == NULL) {
  30. PRINT_ERROR ("fopen" );
  31. return NULL;
  32.     }
  33.     return f;
  34. }
  35. /**
  36. * \fn static ret_e close_file (FILE *f)
  37. * \brief Ferme un fichier
  38. *
  39. * \param f fichier a fermer.
  40. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon.
  41. */
  42. static ret_e close_file (FILE *f)
  43. {
  44.     if (fclose (f) == EOF) {
  45. PRINT_ERROR ("fclose" );
  46. return RET_ERROR;
  47.     }
  48.     return RET_SUCCESS;
  49. }
  50. /**
  51. * \fn ret_e create_file (const char *path)
  52. * \brief Cree un fichier
  53. *
  54. * \param path pointeur vers une chaine de caractere indiquant le chemin du
  55. * fichier a creer.
  56. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon.
  57. */
  58. ret_e create_file (const char *path)
  59. {
  60.     FILE *f = NULL;
  61.     if ((f = open_file (path, "w" )) == NULL) {
  62. return RET_ERROR;
  63.     }
  64.     if (close_file (f) == RET_ERROR) {
  65. return RET_ERROR;
  66.     }
  67.     return RET_SUCCESS;
  68. }
  69. /**
  70. * \fn ret_e read_file (const char *path)
  71. * \brief Lit un fichier
  72. *
  73. * \param path pointeur vers une chaine de caractere indiquant le chemin du
  74. * fichier a creer.
  75. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon.
  76. */
  77. ret_e read_file (const char *path)
  78. {
  79.     FILE *f = NULL;
  80.     int c;
  81.     if ((f = open_file (path, "r" )) == NULL) {
  82. return RET_ERROR;
  83.     }
  84.     while ((c = fgetc (stdin)) != EOF) {
  85. (void) fprintf (stdout, "%c", c);
  86.     }
  87.     if (close_file (f) == RET_ERROR) {
  88. return RET_ERROR;
  89.     }
  90.     return RET_SUCCESS;
  91. }
  92. /**
  93. * \fn ret_e write_file (const char *path)
  94. * \brief Ecrit un fichier
  95. *
  96. * \param path pointeur vers une chaine de caractere indiquant le chemin du
  97. * fichier a creer.
  98. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon.
  99. */
  100. ret_e write_file (const char *path)
  101. {
  102.     FILE *f = NULL;
  103.     char s[LINE_MAX] = "";
  104.     if ((f = open_file (path, "a+" )) == NULL) {
  105. return RET_ERROR;
  106.     }
  107.     (void) fprintf (stdout, "\"/quit\" to stop\n" );
  108.     while (fgets (s, (int) sizeof (s), stdin) != NULL &&
  109.    strstr (s, "/quit" ) == 0)  {
  110. (void) fputs (s, f);
  111.     }
  112.     if (close_file (f) == RET_ERROR) {
  113. return RET_ERROR;
  114.     }
  115.     return RET_SUCCESS;
  116. }
 
Code :
  1. /****************************************************************************
  2.   Name ........ : file.h
  3.   Role ........ : declares file.c functions
  4.   Author  ..... : lucas-84
  5.   Version ..... : V0.1 on 24/10/2011
  6.   Compilation :
  7.    gcc -Wall -pedantic -std=c99 -o zReader main.c file.c error.c
  8.   Execution :
  9.    ./zReader [OPTIONS] [FILE]
  10. ****************************************************************************/
  11. #ifndef FILE_H
  12. #define FILE_H
  13. #include "error.h"
  14. #define LINE_MAX  512
  15. ret_e create_file (const char *);
  16. ret_e read_file (const char *);
  17. ret_e write_file (const char *);
  18. #endif
 
Code :
  1. /****************************************************************************
  2.   Name ........ : error.h
  3.   Role ........ : declares error.c functions
  4.   Author  ..... : lucas-84
  5.   Version ..... : V0.1 on 24/10/2011
  6.   Compilation :
  7.    gcc -Wall -pedantic -std=c99 -o zReader main.c file.c error.c
  8.   Execution :
  9.    ./zReader [OPTIONS] [FILE]
  10. ****************************************************************************/
  11. #ifndef ERROR_H
  12. #define ERROR_H
  13. #include <errno.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #define PRINT_ERROR(s)                                                       \
  17.     do {                                                                     \
  18.         (void) fprintf(stderr, "----------------------------------------"    \
  19.                                "----------------------------------------\n"  \
  20.                                "\t\t\t\t\tERROR\n\n"                         \
  21.                                "Fonction    : %s\n"                          \
  22.                                "File        : %s\n"                          \
  23.                                "Line        : %d\n"                          \
  24.                                "Description : %s\n"                          \
  25.                                "----------------------------------------"    \
  26.                                "----------------------------------------\n", \
  27.                                s, __FILE__, __LINE__, strerror(errno));      \
  28.     } while (0)
  29. #define PRINT_ERROR_ARG_MAIN()                                               \
  30.     do {                                                                     \
  31.         (void) fputs ("----------------------------------------"      \
  32.                       "----------------------------------------\n"      \
  33.                       "\t\t\t\t\tERROR\n\n"         \
  34.                       "Invalid argument.\n"         \
  35.                       "Synopsis : ./zReader [OPTIONS] [FILE]\n"       \
  36.                       "Options :\n"                 \
  37.                       "  -c : create file\n"         \
  38.                       "  -r : read file\n"         \
  39.                       "  -w : write file\n"         \
  40.                       "----------------------------------------"      \
  41.                       "----------------------------------------\n", stdout); \
  42.     } while (0)      
  43. #define PRINT_ERROR_ARG_FUNCTION(s)                                          \
  44.     do {                                                                     \
  45.         (void) fprintf(stderr, "----------------------------------------"    \
  46.                                "----------------------------------------\n"  \
  47.                                "\t\t\t\t\tERROR\n\n"                         \
  48.                                "Fonction    : %s\n"                          \
  49.                                "File        : %s\n"                          \
  50.                                "Line        : %d\n"                          \
  51.                                "Description : bad argument\n"                \
  52.                                "----------------------------------------"    \
  53.                                "----------------------------------------\n", \
  54.                                s, __FILE__, __LINE__);                       \
  55.     } while (0)
  56. /**
  57. * \enum ret_e
  58. * \brief Constantes d'erreurs.
  59. *
  60. * Str_err_e est un type de retour des fonctions de file.c indiquant si une
  61. * erreur s'est produite ou pas.
  62. */
  63. typedef enum {
  64.     RET_ERROR = -1,
  65.     RET_SUCCESS = 1
  66. } ret_e;
  67. #endif
 

Merci d'avance et bonne journée à vous tous,
lucas-84

 


Message édité par lucas-84 le 24-10-2011 à 17:30:18
Reply

Marsh Posté le 24-10-2011 à 17:26:54   

Reply

Marsh Posté le 24-10-2011 à 19:22:04    

Bon, j'ai pris une fonction au hasard.
C'est une question de style, mais plutôt que ceci:

Code :
  1. ret_e read_file (const char *path)
  2. {
  3.     FILE *f = NULL;
  4.     int c;
  5.     if ((f = open_file (path, "r" )) == NULL) {
  6.         return RET_ERROR;
  7.     }
  8.     while ((c = fgetc (stdin)) != EOF) {
  9.         (void) fprintf (stdout, "%c", c);
  10.     }
  11.     if (close_file (f) == RET_ERROR) {
  12.         return RET_ERROR;
  13.     }
  14.     return RET_SUCCESS;
  15. }


J'aurais écrit ceci:

Code :
  1. ret_e read_file(const char *path)
  2. {
  3.     FILE *f;
  4.     if (f = open_file(path, "r" )) {
  5.         int c = fgetc(stdin);
  6.         while (c != EOF) {
  7.             fprintf(stdout, "%c", c);
  8.             c = fgetc(stdin);
  9.         }
  10.         if (close_file(f)) {
  11.             return RET_SUCCESS;
  12.         }
  13.     }
  14.     return RET_ERROR;
  15. }


Ou j'ai un seul chemin amenant au succès, et un retour en erreur par défaut.
En plus, ça permet d'avoir des lignes de sens plus clair à la lecture:
if (f = open_file(path, "r" )) { --> Si on a ouvert le fichier ...
La manière dont tu as écrit ton code n'est utile que si tu fais des différentiations sur les types d'erreur rencontrées, et ce n'est manifestement pas le cas de ton code.
 
Le cast par (void) de le ligne (void) fprintf (stdout, "%c", c); est totalement inutile et à éviter AMHA.
A+,


Message édité par gilou le 24-10-2011 à 19:37:19

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 24-10-2011 à 19:34:55    

Salut,
 
Tout d'abord, merci à toi d'avoir répondu.
 
Je prend note pour le changement que tu proposes, par contre :
 

Code :
  1. # int c = fgetc(stdin);
  2. #         while (c != EOF) {
  3. #             fprintf(stdout, "%c", c);
  4. #             c = fgetc(stdin);
  5. #         }


 
 
Ce n'est pas un peu répétitif ?
 
Pour le cast, j'avais lu ça dans des conseils de codage de wikisource, cela permettait de bien tester les retours de fonction. Et puis, splint râle quand je ne caste pas, alors...


Message édité par lucas-84 le 24-10-2011 à 19:35:43
Reply

Marsh Posté le 24-10-2011 à 19:50:41    

Euh, vu que tu ne fais qu’appeler la fonction, sans utiliser la valeur de retour de celle ci, il n'y a aucune raison valable pour qu'un outil râle dans ce cas précis.
Un outil peut râler en cas d'affectation mais ici il n'y en a pas.
 
Quand à être répétitif, c'est exactement la même chose que dans ton code, mais je préfère un test de boucle simple sans appel de fonction dedans si on peut l'éviter.
Il faudrait profiler pour voir si le code généré est plus efficace, mais ici, c'est plus une question de goût, de préoccupation de lisibilité et de maintenance.  
Ce que tu as écrit ici n'a rien de problématique, parce qu'on a des procédure de base bien connues comme fgetc et qu'on sait ce qu'elle fait.  
Par contre ce style peut être un peu moins compréhensible avec des procédures maisons dont on n'a pas toujours en tête ce qu'elles renvoient en cas d'échec (en particulier s'il y a plusieurs codes d'échec).
 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 25-10-2011 à 09:47:39    

Citation :

Euh, vu que tu ne fais qu’appeler la fonction, sans utiliser la valeur de retour de celle ci, il n'y a aucune raison valable pour qu'un outil râle dans ce cas précis.
Un outil peut râler en cas d'affectation mais ici il n'y en a pas.

 
Citation :

Une bonne habitude consiste à caster en void tous les appels à des fonctions dont on souhaite ignorer les codes retour. Cette pratique facilite les contrôle avec les outils qualité.

 

[...]

 

Les outils de contrôle statiques comme splint émettent un warning lorsqu'un codes retour de fonction n'est pas testé ou explicitement ignoré.


http://fr.wikibooks.org/wiki/Conse [...] fication_3

 
Citation :

Quand à être répétitif, c'est exactement la même chose que dans ton code, mais je préfère un test de boucle simple sans appel de fonction dedans si on peut l'éviter.

 

En fait, c'est juste que j'ai vu deux fois « fgetc (stdin) » et ça m'a un peu surpris. Pas moyen de faire ça avec un do while ?

 
Citation :

Il faudrait profiler pour voir si le code généré est plus efficace, mais ici, c'est plus une question de goût, de préoccupation de lisibilité et de maintenance.  
Ce que tu as écrit ici n'a rien de problématique, parce qu'on a des procédure de base bien connues comme fgetc et qu'on sait ce qu'elle fait.  
Par contre ce style peut être un peu moins compréhensible avec des procédures maisons dont on n'a pas toujours en tête ce qu'elles renvoient en cas d'échec (en particulier s'il y a plusieurs codes d'échec).

 

Dans ce cas-là, est-il préférable de faire de même avec les conditions ? Aucun appel de fonction dedans ?

 


Message édité par lucas-84 le 25-10-2011 à 09:48:01
Reply

Marsh Posté le 25-10-2011 à 11:22:29    

Citation :

Une bonne habitude consiste à caster en void tous les appels à des fonctions dont on souhaite ignorer les codes retour. Cette pratique facilite les contrôle avec les outils qualité.


Ça n'a pas grand intérêt sauf éventuellement, à indiquer explicitement à un outil, qui devrait être paramétrable afin de ne pas se préoccuper de ce genre de chose, qu'on ne se préoccupe pas de la valeur de retour. Bref, ça me semble plus être la règle posée pour faire plaisir à un outil et son concepteur qu'autre chose.
Dans la pratique, on ne rencontre pas ce style de cast dans du code C habituellement. Elle est pas complètement idiote donc cette règle, mais comme elle ne fait pas partie des usages, elle risque plus de déconcerter quelqu'un qui relira le code qu'autre chose.
 

Citation :

En fait, c'est juste que j'ai vu deux fois « fgetc (stdin) » et ça m'a un peu surpris. Pas moyen de faire ça avec un do while ?


A partir du moment ou on exécute le même nombre de fois fgetc (stdin), il vaut mieux avoir un code plus simple et lisible AMHA, en particulier, vis à vis de ce que l'on teste dans sa boucle.
 

Citation :

Dans ce cas-là, est-il préférable de faire de même avec les conditions ? Aucun appel de fonction dedans ?


On n’exécute la condition qu'une fois, alors c'est moins important, mais ça peut être préférable.
 
Mais en fait, l'intérêt de ce style, c'est le suivant:
Quand on a:
int (ou char) machin = f(blabla);
if (test sur machin) { bloc (ou on n'utilise pas machin) }
On peut le remplacer par
if (f(blabla)) { bloc }
parce que ça évite une variable inutile.
 
Idem quand on a:
int (ou char) machin = f(blabla);
while (test sur machin) { bloc (ou on n'utilise pas machin, sauf une fois, pour avoir une nouvelle valeur de test, en faisant machin = f(blabla)) }
On peut le remplacer par
ça se remplace par
while (f(blabla)) { bloc }
 
Par contre, a partir du moment ou on utilise la valeur testée dans le bloc, on ne gagne rien a utiliser ce style de codage (peut être quelques octets dans l'exécutable généré), et on rend la lecture moins claire.
 
Pour reprendre ta page exemple,

Citation :

while ((optc = getopt_long (argc, argv, "htvm", longopts, (int *) 0)) != EOF)


Un (bon) programmeur sait à quoi correspond getopt_long, donc il comprends le sens de ce code.
Mais dès que cela devient trop complexe à lire sans perdre le fil du code courant, il vaut mieux éviter, car c'est mauvais pour la maintenance du code.
 
Un autre point:
FILE *f = NULL;
Il vaut mieux éviter d'affecter a NULL un pointeur déclaré, car alors, le compilateur n'émettra plus les warnings qu'il émet quand un pointeur est utilisé avant d'avoir été affecté, puisque maintenant pour lui, le pointeur a été affecté avant première utilisation, et ça, c'est le genre de warning très utile.
(l'inconvénient c'est que si dans une fonction, on renvoie un pointeur sans l'avoir affecté, la fonction appelante ne peut pas vérifier qu'il n'y a pas eu affectation, mais dans la pratique je préfère ce cas de figure, car quand je récupère un pointeur d'une fonction appellée, je vais relire son code pour vérifier qu'il y a bien eu affectation avant retour de la fonction).
 
A+,


Message édité par gilou le 25-10-2011 à 11:35:22

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 25-10-2011 à 13:51:27    

Merci encore une fois pour ta réponse.

 
Citation :

Ça n'a pas grand intérêt sauf éventuellement, à indiquer explicitement à un outil, qui devrait être paramétrable afin de ne pas se préoccuper de ce genre de chose, qu'on ne se préoccupe pas de la valeur de retour. Bref, ça me semble plus être la règle posée pour faire plaisir à un outil et son concepteur qu'autre chose.
Dans la pratique, on ne rencontre pas ce style de cast dans du code C habituellement. Elle est pas complètement idiote donc cette règle, mais comme elle ne fait pas partie des usages, elle risque plus de déconcerter quelqu'un qui relira le code qu'autre chose.

 

Si on gagne en lisibilité, je m'avoue vaincu. Mais bon, avec splint :

 
Citation :

file.c:149:3: Return value (type int) ignored: fputs(s, f)
  Result returned by function call is not used. If this is intended, can cast
  result to (void) to eliminate message. (Use -retvalint to inhibit warning)

 
Citation :

On n’exécute la condition qu'une fois, alors c'est moins important, mais ça peut être préférable.
 
Mais en fait, l'intérêt de ce style, c'est le suivant:
Quand on a:
int (ou char) machin = f(blabla);
if (test sur machin) { bloc (ou on n'utilise pas machin) }
On peut le remplacer par
if (f(blabla)) { bloc }
parce que ça évite une variable inutile.
 
Idem quand on a:
int (ou char) machin = f(blabla);
while (test sur machin) { bloc (ou on n'utilise pas machin, sauf une fois, pour avoir une nouvelle valeur de test, en faisant machin = f(blabla)) }
On peut le remplacer par
ça se remplace par
while (f(blabla)) { bloc }
 
Par contre, a partir du moment ou on utilise la valeur testée dans le bloc, on ne gagne rien a utiliser ce style de codage (peut être quelques octets dans l'exécutable généré), et on rend la lecture moins claire.

 

Après réflexion, je suis tout à fait d'accord.

 
Citation :

Un (bon) programmeur sait à quoi correspond getopt_long, donc il comprends le sens de ce code.
Mais dès que cela devient trop complexe à lire sans perdre le fil du code courant, il vaut mieux éviter, car c'est mauvais pour la maintenance du code.
 
Un autre point:
FILE *f = NULL;
Il vaut mieux éviter d'affecter a NULL un pointeur déclaré, car alors, le compilateur n'émettra plus les warnings qu'il émet quand un pointeur est utilisé avant d'avoir été affecté, puisque maintenant pour lui, le pointeur a été affecté avant première utilisation, et ça, c'est le genre de warning très utile.
(l'inconvénient c'est que si dans une fonction, on renvoie un pointeur sans l'avoir affecté, la fonction appelante ne peut pas vérifier qu'il n'y a pas eu affectation, mais dans la pratique je préfère ce cas de figure, car quand je récupère un pointeur d'une fonction appellée, je vais relire son code pour vérifier qu'il y a bien eu affectation avant retour de la fonction).

 

Je prends note, c'est très intéressant. :)

 

Sinon, j'essaie en ce moment de décortiquer une suite de messages de splint :

 
Spoiler :

splint file.c
Splint 3.1.2 --- 03 May 2009

 

file.c: (in function open_file)
file.c:35:12: Dependent storage f returned as implicitly only: f
  Dependent storage is transferred to a non-dependent reference. (Use
  -dependenttrans to inhibit warning)
   file.c:30:34: Storage f becomes dependent
file.c: (in function create_file)
file.c:67:24: Fresh storage f not released before return
  A memory leak has been detected. Storage allocated locally is not released
  before the last reference to it is lost. (Use -mustfreefresh to inhibit
  warning)
   file.c:64:37: Fresh storage f created
file.c: (in function read_file)
file.c:91:24: Fresh storage f not released before return
   file.c:82:37: Fresh storage f created
file.c: (in function write_file)
file.c:114:6: Return value (type int) ignored: fputs(s, f)
  Result returned by function call is not used. If this is intended, can cast
  result to (void) to eliminate message. (Use -retvalint to inhibit warning)
file.c:116:24: Fresh storage f not released before return
   file.c:106:37: Fresh storage f created

 
 

D'après ce que j'ai déchiffré rapidement, on dirait qu'il ne détecte pas le fclose et donc la libération de la mémoire. Il me parle de memory leak, mais après avoir passé un coup de valgrind, je n'en vois aucune.
Mon file.c :

 
Code :
  1. /**
  2. * \file file.c
  3. * \brief manipule les fichiers
  4. * \author lucas-84
  5. * \version V0.2 on 25/10/2011
  6. * \date 24/10/2011
  7. *
  8. * Manipule les fichiers directement
  9. *
  10. */
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include "error.h"
  15. #include "file.h"
  16. /**
  17. * \fn static ret_e open_file (const char *path, const char *mode)
  18. * \brief Ouvre un fichier
  19. *
  20. * \param path pointeur vers une chaine de caractere indiquant le chemin du
  21. * fichier a creer.
  22. * \param mode pointeur vers une chaine de caractere indiquant le mode
  23. * d'ouverture du fichier a creer.
  24. * \return NULL en cas d'erreur, le fichier ouvert sinon.
  25. */
  26. /*@null@*/ static FILE *open_file (const char *path, const char *mode)
  27. {
  28.     FILE *f = fopen (path, mode);
  29.     if (f == NULL) {
  30. PRINT_ERROR ("fopen" );
  31.     }
  32.     return f;
  33. }
  34. /**
  35. * \fn static ret_e close_file (FILE *f)
  36. * \brief Ferme un fichier
  37. *
  38. * \param f fichier a fermer.
  39. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon.
  40. */
  41. static ret_e close_file (FILE *f)
  42. {
  43.     if (fclose (f) == EOF) {
  44.         PRINT_ERROR ("fclose" );
  45. return RET_ERROR;
  46.     }
  47.     return RET_SUCCESS;
  48. }
  49. /**
  50. * \fn ret_e create_file (const char *path)
  51. * \brief Cree un fichier
  52. *
  53. * \param path pointeur vers une chaine de caractere indiquant le chemin du
  54. * fichier a creer.
  55. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon.
  56. */
  57. ret_e create_file (const char *path)
  58. {
  59.     FILE *f = open_file (path, "w" );
  60.     if (f != NULL) {
  61. return close_file (f);
  62.     }
  63.     return RET_ERROR;
  64. }
  65. /**
  66. * \fn ret_e read_file (const char *path)
  67. * \brief Lit un fichier
  68. *
  69. * \param path pointeur vers une chaine de caractere indiquant le chemin du
  70. * fichier a creer.
  71. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon.
  72. */
  73. ret_e read_file (const char *path)
  74. {
  75.     FILE *f = open_file (path, "r" );
  76.     if (f != NULL) {
  77. int c = fgetc (stdin);
  78. while (c != EOF) {
  79.     fprintf (stdout, "%c", c);
  80.     c = fgetc (stdin);
  81. }
  82. return close_file (f);
  83.     }
  84.     return RET_ERROR;
  85. }
  86. /**
  87. * \fn ret_e write_file (const char *path)
  88. * \brief Ecrit un fichier
  89. *
  90. * \param path pointeur vers une chaine de caractere indiquant le chemin du
  91. * fichier a creer.
  92. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon.
  93. */
  94. ret_e write_file (const char *path)
  95. {
  96.     FILE *f = open_file (path, "a" );
  97.     if (f != NULL) {
  98. char s[LINE_MAX] = "";
  99. fprintf (stdout, "\"/quit\" to stop\n" );
  100. while (fgets (s, (int) sizeof (s), stdin) != NULL &&
  101.        strstr (s, "/quit" ) == 0)  {
  102.     fputs (s, f);
  103. }
  104. return close_file (f);
  105.     }
  106.     return RET_ERROR;
  107. }
 

Merci à tous  !  :jap:
Bonne journée,
lucas-84


Message édité par lucas-84 le 25-10-2011 à 14:17:17
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed