/*
 * Recréation de la commande LS
 * TP/TP de Système
 *  alex, DUT Année Spéciale, IUT NANCY Charlemagne (2006)
 */

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

#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <time.h>
#include <grp.h>

int main ( int argc , char ** argv )
{
    //  Déclarations
    DIR * rep_courant ;
    struct dirent * entree ;
    char * nom ;
    char modeFichier = '-' ;
    char modeFinFichier = ' ' ;
    char chemin [ 256 ] ;
    char esc = 27 ;
    char couleur [ 7 ] ;
    char rst [ ] = "[0m" ;
    struct stat statinfo ;
    int sommeBlocs ;
    int tailleBloc ;
    char * droits [ ] = { "---" , "--x" , "-w-" , "-wx" , "r--" , "r-x" , "rw-" , "rwx" } ;
    int b ;

    // Lecture des paramètres passés sur la ligne de commande 

    if ( argc < 2 )
        strcpy ( chemin , "." ) ;
    else
        strcpy ( chemin , argv [ 1 ] ) ;


    // Ouvre le répertoire courant 
    if ( ( rep_courant = opendir ( chemin ) ) == NULL )
    {
            // Si il n'a pas été possible de l'ouvrir, on sort sur une erreur 
            printf ( "Impossible d'ouvrir le répertoire %s\n" , argv [ 1 ] ) ;
            exit ( 2 ) ;
    }


    sommeBlocs = 0 ;
    tailleBloc = 0 ;

    // Parcoure la liste des entrées figurant dans ce répertoire 
    while ( entree = readdir ( rep_courant ) )
    {
        //Récupère le nom du fichier
        nom = entree -> d_name ;

        //S'il ne commence pas par un point (fichiers cachés sous unix)
        if ( nom [ 0 ] != '.' )
        {
            //Regarde les informations sur le fichier
            b = lstat ( nom , & statinfo ) ;

            //Détermine le mode du fichier

            //un fichier ordinaire ?
            if ( S_ISREG ( statinfo . st_mode ) )
            {
                modeFichier = '-' ;

                //Fichier exécutable ?
                if (
                        ( statinfo . st_mode & S_IXUSR )
                     || ( statinfo . st_mode & S_IXGRP )
                     || ( statinfo . st_mode & S_IXOTH )
                   )
                {
                    modeFinFichier = '*' ;
                    strcpy ( couleur , "[1;32m" ) ;
                }
                else
                {
                    modeFinFichier = ' ' ;
                    strcpy ( couleur , "[0m" ) ;

                }

            }

            //un répertoire ?
            if ( S_ISDIR ( statinfo . st_mode ) )
            {
                modeFichier = 'd' ;
                modeFinFichier = '/' ;
                strcpy ( couleur , "[1;34m" ) ;
            }

            //un périphérique en mode caractère ?
            if ( S_ISCHR ( statinfo . st_mode ) )
            {
                modeFichier = 'c' ;
                modeFinFichier = '/' ;
                strcpy ( couleur , "[33m" ) ;
            }

            //un périphérique en mode bloc ?
            if ( S_ISBLK ( statinfo . st_mode ) )
            {
                modeFichier = 'b' ;
                modeFinFichier = ' ' ;
                strcpy ( couleur , "[33m" ) ;
            }

            //FIFO (tube nommé) ?
            if ( S_ISFIFO ( statinfo . st_mode ) )
            {
                modeFichier = 'p' ;
                modeFinFichier = '|' ;
                strcpy ( couleur , "[1;35m" ) ;
            }

            //un lien symbolique ?
            if ( S_ISLNK ( statinfo . st_mode ) )
            {
                modeFichier = 'l' ;
                modeFinFichier = '@' ;
                strcpy ( couleur , "[1;36m" ) ;
            }

            //une socket ?
            if ( S_ISSOCK ( statinfo . st_mode ) )
            {
                modeFichier = 's' ;
                modeFinFichier = '=' ;
                strcpy ( couleur , "[1;35m" ) ;
            }


            sommeBlocs += statinfo . st_blocks ;

            if ( tailleBloc == 0 )
                tailleBloc = statinfo . st_blksize ;


            //Affiche les infos sur le fichier (format long de la commande ls)

            printf ( "%c%s%s%s %d %s %s %-4d\t%d-%02d-%02d %02d:%02d %c%s%s%c%s%c\n" ,

                    modeFichier ,                                   //Mode de fichier (répertoire, lien, régulier, ...)
                    droits [ ( statinfo . st_mode ) >> 6 & 7 ] ,    //Droits de l'utilisateur
                    droits [ ( statinfo . st_mode ) >> 3 & 7 ] ,    //Droits du groupe
                    droits [ ( statinfo . st_mode ) >> 0 & 7 ] ,    //Droits du reste du monde

                    statinfo . st_nlink ,                           //Nombre de liens matériels

                    ( getpwuid ( statinfo . st_uid ) ) -> pw_name , //Nom (en clair) de l'utilisateur
                    ( getgrgid ( statinfo . st_gid ) ) -> gr_name , //Nom (en clair) du groupe

                    statinfo . st_size  ,                           //Taille du fichier

                    1900 + ( localtime ( & ( statinfo . st_mtime ) ) ) -> tm_year , //Année de dernière modification
                       1 + ( localtime ( & ( statinfo . st_mtime ) ) ) -> tm_mon  , //Mois de dernière modification
                           ( localtime ( & ( statinfo . st_mtime ) ) ) -> tm_mday , //Jour de dernière modification
                           ( localtime ( & ( statinfo . st_mtime ) ) ) -> tm_hour , //Heure de dernière modification
                           ( localtime ( & ( statinfo . st_mtime ) ) ) -> tm_min  , //Minutes de dernière modification
                    esc, couleur,                                   //La séquence d'échappement suivi de la couleur pour le fichier
                    nom ,                                           //Nom du fichier
                    esc, rst ,                                      //La séquence d'échappement de réinitialisation des couleurs
                    modeFinFichier                                  //Le caractère ajouté à la fin du fichier

                   ) ;

        } //Fin if

    } //Fin while

    closedir ( rep_courant ) ; //Ferme le répertoire
    
    printf ( "Total : %d\ntaille bloc : %d\n" , sommeBlocs , tailleBloc ) ;

    return 0 ;
}