#include #include #include #include #include #include #include #include #include #include #include // Codes couleurs ANSI #define COLOR_RESET "\033[0m" #define COLOR_BLUE "\033[1;34m" #define COLOR_GREEN "\033[1;32m" #define COLOR_CYAN "\033[1;36m" #define COLOR_YELLOW "\033[1;33m" #define COLOR_RED "\033[1;31m" // Structure pour stocker les informations d'un fichier typedef struct { char name[256]; struct stat stat_info; char type; // 'd' = directory, 'f' = file, 'l' = link } FileInfo; // Options de ligne de commande typedef struct { int show_all; // -a : afficher fichiers cachés int long_format; // -l : format détaillé int sort_by_size; // --size : trier par taille int sort_by_time; // --time : trier par date int human_readable; // -h : tailles lisibles (KB, MB) } Options; // Convertir les permissions en format rwxrwxrwx void format_permissions(mode_t mode, char *str) { str[0] = (S_ISDIR(mode)) ? 'd' : '-'; str[1] = (mode & S_IRUSR) ? 'r' : '-'; str[2] = (mode & S_IWUSR) ? 'w' : '-'; str[3] = (mode & S_IXUSR) ? 'x' : '-'; str[4] = (mode & S_IRGRP) ? 'r' : '-'; str[5] = (mode & S_IWGRP) ? 'w' : '-'; str[6] = (mode & S_IXGRP) ? 'x' : '-'; str[7] = (mode & S_IROTH) ? 'r' : '-'; str[8] = (mode & S_IWOTH) ? 'w' : '-'; str[9] = (mode & S_IXOTH) ? 'x' : '-'; str[10] = '\0'; } // Formater la taille en format lisible (KB, MB, GB) void format_size(off_t size, char *str, int human_readable) { if (!human_readable) { sprintf(str, "%ld", (long)size); return; } if (size < 1024) { sprintf(str, "%ld B", (long)size); } else if (size < 1024 * 1024) { sprintf(str, "%.1f KB", size / 1024.0); } else if (size < 1024 * 1024 * 1024) { sprintf(str, "%.1f MB", size / (1024.0 * 1024.0)); } else { sprintf(str, "%.1f GB", size / (1024.0 * 1024.0 * 1024.0)); } } // Formater la date void format_time(time_t time, char *str) { struct tm *tm_info = localtime(&time); strftime(str, 64, "%b %d %H:%M", tm_info); } // Obtenir la couleur selon le type de fichier const char* get_color(char type, mode_t mode) { if (type == 'd') return COLOR_BLUE; if (type == 'l') return COLOR_CYAN; if (mode & S_IXUSR) return COLOR_GREEN; // Exécutable return COLOR_RESET; } // Fonction de comparaison pour le tri par nom int compare_by_name(const void *a, const void *b) { FileInfo *fa = (FileInfo *)a; FileInfo *fb = (FileInfo *)b; return strcmp(fa->name, fb->name); } // Fonction de comparaison pour le tri par taille int compare_by_size(const void *a, const void *b) { FileInfo *fa = (FileInfo *)a; FileInfo *fb = (FileInfo *)b; return (fb->stat_info.st_size - fa->stat_info.st_size); } // Fonction de comparaison pour le tri par date int compare_by_time(const void *a, const void *b) { FileInfo *fa = (FileInfo *)a; FileInfo *fb = (FileInfo *)b; return (fb->stat_info.st_mtime - fa->stat_info.st_mtime); } // Afficher en format court (par défaut) void display_short(FileInfo *files, int count, Options *opts) { for (int i = 0; i < count; i++) { const char *color = get_color(files[i].type, files[i].stat_info.st_mode); if (files[i].type == 'd') { printf("%s[DIR] %s/%s\n", color, files[i].name, COLOR_RESET); } else { char size_str[32]; format_size(files[i].stat_info.st_size, size_str, opts->human_readable); printf("%s[FILE] %s%s (%s)\n", color, files[i].name, COLOR_RESET, size_str); } } } // Afficher en format long (-l) void display_long(FileInfo *files, int count, Options *opts) { for (int i = 0; i < count; i++) { char perms[12]; char size_str[32]; char time_str[64]; format_permissions(files[i].stat_info.st_mode, perms); format_size(files[i].stat_info.st_size, size_str, opts->human_readable); format_time(files[i].stat_info.st_mtime, time_str); // Obtenir nom d'utilisateur et groupe struct passwd *pw = getpwuid(files[i].stat_info.st_uid); struct group *gr = getgrgid(files[i].stat_info.st_gid); const char *color = get_color(files[i].type, files[i].stat_info.st_mode); printf("%s %3ld %-8s %-8s %8s %s %s%s%s\n", perms, (long)files[i].stat_info.st_nlink, pw ? pw->pw_name : "?", gr ? gr->gr_name : "?", size_str, time_str, color, files[i].name, COLOR_RESET); } } // Lister le contenu d'un répertoire int list_directory(const char *path, Options *opts) { DIR *dir = opendir(path); if (dir == NULL) { fprintf(stderr, "%sErreur: Impossible d'ouvrir '%s': %s%s\n", COLOR_RED, path, strerror(errno), COLOR_RESET); return 1; } // Allouer de la mémoire pour stocker les fichiers FileInfo *files = malloc(sizeof(FileInfo) * 1000); if (files == NULL) { fprintf(stderr, "Erreur allocation mémoire\n"); closedir(dir); return 1; } int count = 0; struct dirent *entry; // Lire tous les fichiers while ((entry = readdir(dir)) != NULL) { // Ignorer . et .. sauf si -a est activé if (!opts->show_all) { if (entry->d_name[0] == '.') continue; } // Construire le chemin complet char full_path[1024]; snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name); // Obtenir les informations avec stat() if (stat(full_path, &files[count].stat_info) == -1) { continue; // Ignorer si stat échoue } // Copier le nom et déterminer le type strncpy(files[count].name, entry->d_name, sizeof(files[count].name) - 1); if (S_ISDIR(files[count].stat_info.st_mode)) { files[count].type = 'd'; } else if (S_ISLNK(files[count].stat_info.st_mode)) { files[count].type = 'l'; } else { files[count].type = 'f'; } count++; if (count >= 1000) break; // Limite de sécurité } closedir(dir); // Trier selon l'option if (opts->sort_by_size) { qsort(files, count, sizeof(FileInfo), compare_by_size); } else if (opts->sort_by_time) { qsort(files, count, sizeof(FileInfo), compare_by_time); } else { qsort(files, count, sizeof(FileInfo), compare_by_name); } // Afficher l'en-tête printf("\n%sContenu du répertoire: %s%s\n", COLOR_CYAN, path, COLOR_RESET); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); // Afficher les fichiers if (opts->long_format) { display_long(files, count, opts); } else { display_short(files, count, opts); } // Compter les dossiers et fichiers int dir_count = 0, file_count = 0; for (int i = 0; i < count; i++) { if (files[i].type == 'd') dir_count++; else file_count++; } printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("%s%d dossier(s), %d fichier(s)%s\n\n", COLOR_YELLOW, dir_count, file_count, COLOR_RESET); free(files); return 0; } // Afficher l'aide void show_help() { printf("\n%smyls - Liste de fichiers colorée%s\n\n", COLOR_CYAN, COLOR_RESET); printf("Usage: myls [OPTIONS] [RÉPERTOIRE]\n\n"); printf("Options:\n"); printf(" -a Afficher tous les fichiers (y compris cachés)\n"); printf(" -l Format long avec détails\n"); printf(" -h Tailles lisibles (KB, MB, GB)\n"); printf(" --size Trier par taille (décroissant)\n"); printf(" --time Trier par date de modification\n"); printf(" --help Afficher cette aide\n\n"); printf("Exemples:\n"); printf(" myls\n"); printf(" myls -l\n"); printf(" myls -lh ~/Documents\n"); printf(" myls --size\n"); printf(" myls -a --time\n\n"); } int main(int argc, char *argv[]) { Options opts = {0, 0, 0, 0, 0}; const char *path = "."; // Parser les arguments for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-a") == 0) { opts.show_all = 1; } else if (strcmp(argv[i], "-l") == 0) { opts.long_format = 1; } else if (strcmp(argv[i], "-h") == 0) { opts.human_readable = 1; } else if (strcmp(argv[i], "-lh") == 0 || strcmp(argv[i], "-hl") == 0) { opts.long_format = 1; opts.human_readable = 1; } else if (strcmp(argv[i], "-al") == 0 || strcmp(argv[i], "-la") == 0) { opts.show_all = 1; opts.long_format = 1; } else if (strcmp(argv[i], "--size") == 0) { opts.sort_by_size = 1; } else if (strcmp(argv[i], "--time") == 0) { opts.sort_by_time = 1; } else if (strcmp(argv[i], "--help") == 0) { show_help(); return 0; } else if (argv[i][0] != '-') { path = argv[i]; } else { fprintf(stderr, "%sOption inconnue: %s%s\n", COLOR_RED, argv[i], COLOR_RESET); show_help(); return 1; } } return list_directory(path, &opts); }