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;
}