TP2 - Correction

ppompeani_grep.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const int MAX_LINE_SIZE = 1024;

// file ne doit pas être NULL
// needle ne doit pas être NULL
void grep(FILE *file, char *needle) {
  char line[1024];
  char *ret = fgets(line, MAX_LINE_SIZE, file);
  while (ret != NULL) {
    // man 3 strstr
    if (strstr(line, needle) != NULL) {
      printf("%s\n", line);
    }
    char *ret = fgets(line, MAX_LINE_SIZE, file);
  }
}

// argv[1] : le texte qu'on cherche
// argv[2] : le fichier à ouvrir
int main(int argc, char **argv) {

  if (argc != 3) {
    printf("Je veux 2 arguments, pas %d arguments.\n", argc - 1);
    return EXIT_FAILURE;
  }

  FILE *file = fopen(argv[2], "r");

  if (file == NULL) {
    printf("Erreur à l'ouverture du fichier\n");
    return EXIT_FAILURE;
  }

  grep(file, argv[1]);

  fclose(file);

  return EXIT_SUCCESS;
}

pompeani_cp.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

const int BUF_SIZE = 1024;

// file et copy ne doivent pas être NULL
int cp(FILE *file, FILE *copy) {
  char buf[BUF_SIZE];
  int bytes_read = BUF_SIZE;
  int bytes_written = BUF_SIZE;

  while (bytes_read == BUF_SIZE && bytes_written == BUF_SIZE) {
    bytes_read = fread(buf, 1, BUF_SIZE, file);
    bytes_written = fwrite(buf, 1, bytes_read, copy);
  }
  if (!feof(file)) {
    printf("Erreur : le fichier d'entrée n'a pas été lu"
           "en entier à cause "
           "d'une erreur\n");
    return EXIT_FAILURE;
  } else if (bytes_written < bytes_read) {
    printf("Erreur : le fichier de sortie n'a pas été"
           "copié en entier à cause "
           "d'une erreur\n");
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}

// argv[1] : le fichier à copier
// argv[2] : le fichier à réer
int main(int argc, char **argv) {

  if (argc != 3) {
    printf("Je veux 2 arguments, pas %d arguments.\n", argc - 1);
    return EXIT_FAILURE;
  }

  if (access(argv[1], R_OK) == -1) {
    printf("Erreur : Je n'ai pas le droit de lire le premier fichier\n");
    return EXIT_FAILURE;
  }

  if (access(argv[2], F_OK) == 0) {
    printf("Erreur : Le second fichier existe déjà\n");
    return EXIT_FAILURE;
  }

  FILE *file1 = fopen(argv[1], "r");

  if (file1 == NULL) {
    printf("Erreur à l'ouverture du premier fichier\n");
    return EXIT_FAILURE;
  }

  FILE *file2 = fopen(argv[2], "w");

  if (file2 == NULL) {
    printf("Erreur à l'ouverture du second fichier\n");
    // Avant de quitter, on ferme le premier fichier
    fclose(file1);

    return EXIT_FAILURE;
  }

  int ret = cp(file1, file2);

  // Peu importe si cp a fini en erreur, on ferme les fichiers
  int close1 = fclose(file1);
  int close2 = fclose(file2);

  if (close1 || close2) {
    printf("Erreur à la fermeture des fichiers\n");
    return EXIT_FAILURE;
  }
  return ret;
}

ppompeani_loremipsum.c

// vim: ts=2 sw=2 et
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

const int BUF_SIZE = 100;

// découpe le fichier en un tableau de mots
// file ne doit pas être NULL
// length ne doit pas être NULL
char **words(FILE *file, int *length) {
  char buf[BUF_SIZE];

  // Petite optimisation :
  // On découple la longueur utilisée du tableau (len)
  // De sa taille réelle en mémoire (size)
  // Ça nous permet de réduire le nombre de realloc sur ce tableau
  int size = 10, len = 0;
  // On initialise le tableau avec une taille réelle de 10
  char **w = (char **)malloc(size * sizeof(char *));

  // On lit la première ligne
  char *ret = fgets(buf, BUF_SIZE, file);

  while (ret != NULL) {
    // Taille de la ligne lue
    int buflen = strlen(buf);
    // Si le tableau finit par retour à la ligne
    if (buf[buflen - 1] == '\n') {
      // Alors on veut se débarrasser de ce retour à la ligne :
      // on le remplace par un \0
      buf[buflen - 1] = '\0';
      // La chaine fait donc un caractère de moins
      buflen--;
    }

    // On alloue une nouvelle chaine de caractère de la bonne taille
    char *new_item = (char *)malloc(buflen * sizeof(char));
    // On lui copie le buffer
    strcpy(new_item, buf);

    // Interlude : on agrandit le _size_ du tableau si nécessaire
    if (len == size) {
      size += 10;
      w = (char **)realloc(w, size * sizeof(char *));
    }

    // On ajoute notre nouvelle chaine de caractères à notre tableau de mots
    w[len] = new_item;
    len++;

    // On lit la ligne suivante
    ret = fgets(buf, BUF_SIZE, file);
  }

  // À la fin,
  // on réduit le _size_ du tableau à sa _len_
  w = (char **)realloc(w, len * sizeof(char *));

  // On met à jour le pointeur passé en paramètre pour
  // instruire la donction appelante de la taille du tableau retourné
  *length = len;
  return w;
}

// X doit être remplacé par un code couleur approprié
// Voir par exemple : 
// https://stackoverflow.com/questions/3219393/stdlib-and-colored-output-in-c#3219471
const char *COLOR = "\x1b[3Xm";
const char *RESET = "\x1b[0m";

int lorem(FILE *file, char **words, int length, int nbwords, char colors) {
  // On donne un nombre aléatoire (le temps en secondes)
  // à srand qui nous servira comme _graine_ pour des nombres
  // pseudo aléatoires
  // Voir par exemple :
  // https://stackoverflow.com/questions/822323/how-to-generate-a-random-int-in-c
  srand((unsigned int)time(NULL));

  // On initialise un chaine qui va nous permettre d'afficher des couleurs
  // On ne peut pas utiliser directement COLOR, qui est une constante
  // On connait sa taille à l'avance, pas besoin de `malloc`
  char color[6];
  // On l'initialise à une chaine vide, dans le cas où l'on ne veut pas
  // afficher de couleurs
  color[0] = '\0';

  for (int i = 0; i < nbwords; i++) {
    // rand() nous retourne un grand nombre
    // modulo le nombre de mots pour en choisir un au hasard
    int random = rand() % length;
    char *word = words[random];

    // Couleurs
    if (colors) {
      random = rand() % 7;
      // Une chance sur 7 d'afficher le mot en blanc
      if (random == 0) {
        strcpy(color, RESET);
      } else {
        // Sinon, on veut afficher
        // \x1b[31m, ou \x1b[32m, ou \x1b[33m, ou \x1b[34m, ou \x1b[35m, ou \x1b[36m
        // On part de COLOR
        strcpy(color, COLOR);
        // Et on remplace le 4e caractère par un nombre de 1 à 6
        color[3] = random + '0';
      }
    }

    int bytes_written;
    // Tous les 10 mots, et à la toute fin, on retourne à la ligne
    if (i % 10 == 9 || i + 1 == nbwords) {
      bytes_written = fprintf(file, "%s%s\n", color, word);
    } else {
      bytes_written = fprintf(file, "%s%s ", color, word);
    }
    if (bytes_written < strlen(word)) {
      return EXIT_FAILURE;
    }
  }
  return EXIT_SUCCESS;
}

void free_tab(char **t, int len) {
  for (int i = 0; i < len; i++) {
    free(t[i]);
  }
  free(t);
}

// argv[1] : un fichier de mots
// argv[2] : le nombre de mots à écrire
// argv[3] : le fichier à ouvrir
int main(int argc, char **argv) {

  if (argc < 3 || argc > 4) {
    printf("Je veux 2 ou 3 arguments, pas %d arguments.\n", argc - 1);
    return EXIT_FAILURE;
  }

  if (access(argv[1], R_OK) == -1) {
    printf("Erreur : je n'ai pas le droit de lire le premier fichier\n");
    return EXIT_FAILURE;
  }

  // On convertit le second argument en int
  int nbwords = atoi(argv[2]);
  if (nbwords <= 0) {
    printf("Erreur : Le second argument doit être un entier supérieur\n");
    return EXIT_FAILURE;
  }

  FILE *words_file = fopen(argv[1], "r");

  if (words_file == NULL) {
    printf("Erreur à l'ouverture du premier fichier\n");
    return EXIT_FAILURE;
  }

  // On lit le premier fichier
  int words_len = 0;
  char **all_words = words(words_file, &words_len);

  if (words_len <= 0) {
    printf("Erreur à la lecture du premier fichier : aucun mot\n");
    return EXIT_FAILURE;
  }

  int close = fclose(words_file);
  if (close) {
    printf("Erreur à la fermeture du premier fichier\n");
    return EXIT_FAILURE;
  }

  FILE *out;
  // On utilise char (un octet) comme type booléen
  char colors;
  // Si on n'a pas donné de 3e argument,
  // On utilise _stdout_, la sortie standard du terminal,
  // comme fichier de sortie
  if (argc == 3) {
    // man 3 fdopen
    out = fdopen(1, "a");
    colors = 1;
  } else {
    // Sinon on ouvre le fichier passé en 3e argument
    if (access(argv[3], F_OK) == 0) {
      printf("Erreur : Le second fichier existe déjà\n");
      return EXIT_FAILURE;
    }

    out = fopen(argv[3], "w");
    colors = 0;
  }

  if (out == NULL) {
    printf("Erreur à l'ouverture du second fichier\n");
    // On libère quand même words et on ferme le premier fichier
    free_tab(all_words, words_len);
    return EXIT_FAILURE;
  }

  int ret = lorem(out, all_words, words_len, nbwords, colors);

  free_tab(all_words, words_len);
  close = fclose(out);

  if (close) {
    printf("Erreur à la fermeture du second fichier\n");
    return EXIT_FAILURE;
  }
  return ret;
}