版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}
}