Linux下C++语言实现ls命令

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shanghairuoxiao/article/details/78510198

实现ls命令,支持-l,-a,-r,-q等选项。

//ls命令

#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <string>
#include <algorithm>
#include <assert.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <fcntl.h>

using namespace std;

//options
enum OPTION {OPT_l, OPT_A, OPT_r, OPT_q, OPT_i, OPT_R, OPT_NUM};

//gobal variable
int g_option[OPT_NUM];
vector<string> g_dirPath;
int dirFd;  //the file descriptor  associated with the directory

void get_option(const char* strOption);
void get_path(const char* strPath);
void do_ls(const char* path);
void do_stat(const string& filename, struct stat* p);
void show_info(const struct stat& filestat, const string& name);
void mode_to_letter(mode_t mode, char* str);
char* uid_to_name(uid_t uid);
char* gid_to_name(gid_t gid);

int main(int argc, char** argv)
{
    memset(g_option, 0, sizeof(int) * OPT_NUM);
    //process option
    while(--argc != 0)
    {
        if('-' == argv[argc][0])
        {
            get_option(argv[argc]); 
        }
        else
        {
            get_path(argv[argc]);
        }
    }

    if(g_dirPath.empty())
    {
        do_ls(".");
    }
    else
    {
        for(auto it = g_dirPath.begin(); it != g_dirPath.end();)
        {
            printf("%s:\n", it->c_str());
            do_ls(it->c_str());
            if(++it != g_dirPath.end())
            {
                printf("\n");
            }
        }
    }
    return 0;
}

void get_option(const char* strOption)
{
    assert(strOption);
    while(*(++strOption) != '\0')
    {
        if(*strOption == 'a') g_option[OPT_A] = 1;
        else if(*strOption == 'A') g_option[OPT_A] = 1;
        else if(*strOption == 'l') g_option[OPT_l] = 1;
        else if(*strOption == 'i') g_option[OPT_i] = 1;
        else if(*strOption == 'r') g_option[OPT_r] = 1;
        else if(*strOption == 'q') g_option[OPT_q] = 1;
        else if(*strOption == 'R') g_option[OPT_R] = 1;
        else fprintf(stderr, "option error\n");
    }
}

void get_path(const char* strPath)
{
    assert(strPath);
    g_dirPath.push_back(strPath);
}

void do_ls(const char* path)
{
    assert(path);
    DIR* p_dir;
    struct dirent* p_next;
    vector<string> list;

    if((p_dir = opendir(path)) == NULL)
    {
        perror("opendir error");
        exit(1);
    }

    if((dirFd = dirfd(p_dir)) == -1)
    {
        perror("dirfd error");
        exit(0);
    }

    while((p_next = readdir(p_dir)) != NULL)
    {
        //process option -a
        if(strcmp(p_next->d_name, ".") == 0 || strcmp(p_next->d_name, "..") || (p_next->d_name[0] == '.') == 0)
        {
            if(g_option[OPT_A] == 0)
                continue;
        }

        list.push_back(p_next->d_name);
    }

    if(g_option[OPT_r])
    {
        sort(list.rbegin(), list.rend());
    }
    else if(g_option[OPT_q] == 0)
    {
        sort(list.begin(), list.end());
    }

    for(auto w : list)
    {
        struct stat fsTemp;
        do_stat(w, &fsTemp);
        show_info(fsTemp, w);
    }

    if(closedir(p_dir) != 0)
    {
        perror("closedir error");
        exit(1);
    }
}

void do_stat(const string& filename, struct stat* p)
{
    assert(p);
    if(fstatat(dirFd, filename.c_str(), p, AT_SYMLINK_NOFOLLOW) == -1)
    {
        perror("fstatat error");
        exit(0);
    }
}

void show_info(const struct stat& filestat, const string& name)
{
    if(g_option[OPT_I])
    {
        printf("%ld ", filestat.st_ino);
    }

    if(g_option[OPT_L])
    {
        char buf[11];
        mode_to_letter(filestat.st_mode, buf);
        printf("%s ", buf);
        printf("%4ld ", filestat.st_nlink);
        printf("%-8s ", uid_to_name(filestat.st_uid));
        printf("%-8s ", gid_to_name(filestat.st_gid));
        printf("%8ld ", filestat.st_size);
        printf("%.12s ", 4 + ctime(&filestat.st_mtime)); //只打印前12个字符
        printf("%s\n", name.c_str());
    }
    else
    {
        printf("%s\t", name.c_str());
    }
}

void mode_to_letter(mode_t mode, char* str)
{
    assert(str);
    strcpy(str, "----------");
    if(S_ISDIR(mode)) str[0] = 'd';
    if(S_ISCHR(mode)) str[0] = 'c';
    if(S_ISBLK(mode)) str[0] = 'b';
    if(S_ISFIFO(mode)) str[0] = 'p';
    if(S_ISLNK(mode)) str[0] = 'l';
    if(S_ISSOCK(mode)) str[0] = 's';

    if(S_IRUSR & mode) str[1] = 'r';
    if(S_IWUSR & mode) str[2] = 'w';
    if(S_IXUSR & mode) str[3] = 'x';

    if(S_IRGRP & mode) str[4] = 'r';
    if(S_IWGRP & mode) str[5] = 'w';
    if(S_IXGRP & mode) str[6] = 'x';

    if(S_IROTH & mode) str[7] = 'r';
    if(S_IWOTH & mode) str[8] = 'w';
    if(S_IXOTH & mode) str[9] = 'x';
}

char* uid_to_name(uid_t uid)
{
    struct passwd * pw_ptr;
    static char numstr[10];

    if((pw_ptr = getpwuid(uid)) == NULL)
    {
        sprintf(numstr, "%d", uid);
        return numstr;
    }
    else
    {
        return pw_ptr->pw_name;
    }
}

char* gid_to_name(gid_t gid)
{
    struct group* grp_ptr;
    static char numstr[10];

    if((grp_ptr = getgrgid(gid)) == NULL)
    {
        sprintf(numstr, "%d", gid);
        return numstr;
    }
    else
    {
        return grp_ptr->gr_name;
    }
}

猜你喜欢

转载自blog.csdn.net/shanghairuoxiao/article/details/78510198