0
点赞
收藏
分享

微信扫一扫

Linux命令ls的自我实现

婉殇成长笔记 2022-03-22 阅读 41

文章目录

知识要点

1.Linux系统编程 目录和文件部分

2.C语言编程能力

任务说明

验收要求

  • 实现 ls 的 -a、-l、-R、-t、-r、-i、-s 参数,并允许这些参数任意组合.
  • -R 需要通对 / 的遍历测试
  • 界面美观(输出对齐、与颜色显示等)
  • 无资源与内存泄露

参考资料

  • man 手册.
  • MichaelKerrisk.Linux/UNIX系统编程手册[M].北京:人民邮电出版社.
  • W.RichardStevens.Stephen.UNIX环境高级编程[M].第3版.戚正伟,译.北京:人民邮电出版社.
  • Unix/Linux编程实践教程

所要用到的函数

在这里插入图片描述

ls初步简单实现(较为简单直接上代码)

   #include<stdio.h>                                                                                                                                                                        
   #include<sys/types.h>
   #include<dirent.h>
   #include<string.h> 
   #define MAX_LEN 150      
     int g_leavelen = MAX_LEN;
     int g_maxlen;       
     void do_ls(char []);             
     int  main(int argc,char  *argv[])
    {            
      if(argc==1)
      {                               
        do_ls(".");  // .代表当前目录 
      }   
      else
      {
        while(--argc)
        {
          printf("%s:\n",*++argv);
          do_ls(*argv);
        }
      }
      return 0;
    }
    void do_ls(char dirname[])
    {
      DIR*dir_ptr;
      struct dirent*direntp;
      if((dir_ptr=opendir(dirname))==NULL)     //打开失败
      {
        fprintf(stderr,"lsl:cannot open %s\n",dirname);
      }
      else                                   //打开成功
      {
         while((direntp=readdir(dir_ptr))!=NULL)  //依次读取目录,找到最大长度
          {
             if(direntp->d_name[0]!='.')
             {
               printf("%s  ",direntp->d_name);
             }
      }
        closedir(dir_ptr);
      }

ls -l的初步实现

所要的效果

在这里插入图片描述

分析以及所需要解决的问题

需要显示文件类型和许可权限,文件链接数,用户ID,所属组ID,所占空间大小,文件修改时间,文件名称。
我们要获取这些信息就需要,stat的联机帮助和/usr/include/sys/stat.h。
他们描述了struct stat 的成员变量
在这里插入图片描述
先简单使用一下,代码如下:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
void show_stat_info(char*fname,struct stat*buf);
int main(int argc,char*argv[])
{
  struct stat info;
  if(argc>1)
    if(stat(argv[1],&info)!=-1)
    {
      show_stat_info(argv[1],&info);
      return 0;
    }
  else 
    perror(argv[1]);
  return 1;
}
void show_stat_info(char*fname,struct stat*buf)
{
  printf("    mode : %o\n",buf->st_mode);
  printf("    links: %d\n",buf->st_nlink);
  printf("    user : %d\n",buf->st_uid);
  printf("    group: %d\n",buf->st_gid);
  printf("    size : %d\n",buf->st_size);
  printf("    modtime : %d\n",buf->st_mtim);
  printf("    name: %s\n",fname);
}

在终端执行如下:
在这里插入图片描述
系统ls -l my_ls2.c 的结果如下:
在这里插入图片描述
我们用stat调出来的

  • 文件类型和许可权限是一串八进制代码
  • 用户ID和所属组ID都是一串数字
  • 显示的时间是时间戳

以上就是我们要实现 ls -l所需要解决的问题

将模式字段转换成字符

s_mode中的这串模式字段是一串八进制数字
把它传化为一个16位的二进制数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过掩码把其他无关部分置为0,再与表示目录的代码比较,从而判断这是否是一个目录

更简单的方法就是用<sys/stat.h>中的宏来代替上述代码:
在这里插入图片描述
在这里插入图片描述
根据上述,我们已经可以解码获得许可权限,代码如下:

void mode_to_letters(int mode,char 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(mode&S_IRUSR)str[1]='r';
      if(mode&S_IWUSR)str[2]='w';
      if(mode&S_IXUSR)str[3]='x'; 
      if(mode&S_IRGRP)str[4]='r';
      if(mode&S_IWGRP)str[5]='w';
      if(mode&S_IXGRP)str[6]='x';
      if(mode&S_IROTH)str[7]='r';
      if(mode&S_IWOTH)str[8]='w';
      if(mode&S_IXOTH)str[9]='x';
    }

将用户,所属组ID转化为字符串

所属组也有一个对应得结构体group和passwd类似
现在就可以实现将用户,所属组ID转化为字符串了
代码如下:

109   char*uid_to_name(gid_t uid)
  110 {
W>111   struct passwd*getpwuid();
  112   struct passwd*pw_ptr;
  113   static char numstr[10];                                                                                                             
E>114   if((pw_ptr=getpwuid(uid))==NULL)
  115   {
  116     sprintf(numstr,"%d",uid);
  117     return numstr;
  118   }
  119   else 
  120   {
  121     return pw_ptr->pw_name;
  122   }
  123 }
  124 char*gid_to_name(gid_t gid)
  125 {
W>126   struct group*getgrgid(),*grp_ptr;
  127   static char numstr[10];
E>128   if((grp_ptr=getgrgid(gid))==NULL)
  129   {
  130     sprintf(numstr,"%d",gid);
  131     return numstr;
  132   }
  133   else 
  134   {
  135     return grp_ptr->gr_name;
  136   }

最终ls -l代码实现以及效果

#include<string.h>                                                                                                                    
     #include<stdio.h>
     #include<sys/types.h>
     #include<dirent.h>
     #include<sys/stat.h>
     #include<grp.h>
     #include<pwd.h>
     void do_ls(char[]);       //依次提取文件
     void dostat(char*);     
     void show_file_info(char*,struct stat*);  //打印文件信息
     void mode_to_letters(int ,char[]);
     char*uid_to_name(uid_t);    //将用户ID转化为字符串
     char*gid_to_name(gid_t);    //将所属组ID转化为字符串
     int main(int argc,char* argv[])
     {
      if(argc==1)
       do_ls(".");                   //进入当前目录
      else                            //若有参数,进入指定目录
      {
        while(--argc)
        {
          printf("%s:\n",*++argv);
          do_ls(*argv);
        }
      }
      return 0;
    }
    void do_ls(char dirname[])
    {
      DIR*dir_ptr;
      struct dirent*direntp;
      if((dir_ptr=opendir(dirname))==NULL)
        fprintf(stderr,"lsl:cannot open %s\n",dirname);
      else 
      { 
	         while((direntp=readdir(dir_ptr))!=NULL)
	         {
		           if(direntp->d_name[0]!='.')         //判断是否是隐藏文件,若不是执行下一步
		           dostat(direntp->d_name);                                                                           
	         }
        }
        closedir(dir_ptr);
      }
    }
    void dostat(char*filename)
    {
    struct stat info;
      if(stat(filename,&info)==-1)
        perror(filename);
      else 
        show_file_info(filename,&info);
    }
    void show_file_info(char*filename,struct stat*info_p)
    {
      char*uid_to_name(),*ctime(),*git_to_name(),*filemode();
      void mode_to_letters();
      char modestr[11];
      mode_to_letters(info_p->st_mode,modestr);
      printf("%s ",modestr);
      printf("%4d ",(int)info_p->st_nlink);
      printf("%-8s ",uid_to_name(info_p->st_uid));                                                                                        
      printf("%-8s ",gid_to_name(info_p->st_gid));
      printf("%8ld ",(long)info_p->st_size);
      printf("%.12s ",4+ctime(&info_p->st_size));
      printf("%s\n",filename);
    }
    void mode_to_letters(int mode,char 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(mode&S_IRUSR)str[1]='r';
      if(mode&S_IWUSR)str[2]='w';
      if(mode&S_IXUSR)str[3]='x'; 
      if(mode&S_IRGRP)str[4]='r';
      if(mode&S_IWGRP)str[5]='w';
      if(mode&S_IXGRP)str[6]='x';
      if(mode&S_IROTH)str[7]='r';
      if(mode&S_IWOTH)str[8]='w';
      if(mode&S_IXOTH)str[9]='x';
     }
      char*uid_to_name(gid_t uid)
      {
        struct passwd*getpwuid();
        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*getgrgid(),*grp_ptr;
          static char numstr[10];
       if((grp_ptr=getgrgid(gid))==NULL)
        {
          sprintf(numstr,"%d",gid);
          return numstr;
        }
       else 
       {
           return grp_ptr->gr_name;
       }
    }                          

效果展示:
在这里插入图片描述

ls -a(显示隐藏文件)

这一步骤实现起来很简单,隐藏文件就是文件名第一个字符是 . 的文件 比如 .git
我们在普通的ls 显示时都会有

 if(direntp->d_name[0]=='.')
        continue;

此步骤就是为了不显示隐藏文件
我们可以在执行到这一步时,对参数进行判断,查看是否有参数 -a 若有该参数跳过该步骤即可

ls -s(在文件左侧显示文件大小,以1024字节为块单位)

此步骤也极为简单,在结构体stat中存有该文件的所占字节的大小,st_size
我们只需要对该文件字节大小除以1024就可以得到所需显示的文件大小
但需要注意的是,当除以1024后得到的大小小于等于4且不等于0时,也需要显示4
实现起来也很简单,当检测到 -s 参数时执行下面代码即可:

  struct stat info;
           if(stat(filename,&info)==-1)
             perror(filename);
             long long size=info.st_size/1024;                              
               if(size<=4)           
                  printf("4   ");                
               else         
                  printf("%-4lld",size);                                                                                                                                                    

ls -i(输出文件的 i 节点的索引信息)

文件的索引信息也是保存在结构体stat中的st_ino中的,当检测到参数 -i 执行下面即可

    struct stat info;
    if(stat(filenames[j],&info)==-1)
       perror(filenames[j]);
     printf("%d  ",info.st_ino); 

ls -R(递归遍历目录)

思路讲解
我们可以先将该目录下的所有文件依次遍历打印出来,当打印完后,再次对该文件进行依次遍历,在此次遍历的过程中要对其文件的类型进行判断,若判断此文件为目录文件时,需要将此目录文件再次传入该函数,进行递归。
注意事项,当判断该文件为目录文件时,若要想在递归进入的函数中访问到该目录下的文件信息,我们应当传入该目录文件的路径,而不是目录名,此时我们就可以用到函数
sprintf

#include<stdio.h>
#include<sys/types.h>
#include<dirent.h>
#include<sys/stat.h>
#include<string.h>
void ls_R(char path[]);
int main()
{
  ls_R("/");
  return 0;
}
void ls_R(char path[])
{
  printf("%s:\n",path);
  DIR*dir_ptr;
  struct dirent*direntp;
  if((dir_ptr=opendir(path))==NULL)//打开目录
    fprintf(stderr,"lsl:cannot open %s\n",path);
  else 
  {
  if(direntp->d_name[0]=='.')
        continue;
    while((direntp=readdir(dir_ptr))!=NULL)//读取当前目录文件
    {
      printf("%s  ",direntp->d_name);
    }
  }
  printf("\n");
  closedir(dir_ptr);
  if((dir_ptr=opendir(path))==NULL)//打开目录
    fprintf(stderr,"lsl:cannot open %s\n",path);
  else 
  {
    while((direntp=readdir(dir_ptr))!=NULL)
    {
      if(direntp->d_name[0]=='.')
        continue;
      struct stat info;
      char temp[PATH_MAX];
      sprintf(temp,"%s/%s",path,direntp->d_name);
      if(stat(temp,&info)==-1)
        perror(temp);
      if(S_ISDIR(info.st_mode))//判断是否为目录,如果是目录就进入递归
      {
        ls_R(temp);
      }
      
    }
  }
}

文件的颜色显示

不同文件显示出来对应的颜色也是不一样的
例如: 目录文件是蓝色
可执行文件绿色
普通文件白色
文件类型的获取在ls -l部分已经讲过

//文件名字颜色
int get_color(struct stat buf);
void printf_name(char *name,int color);
void printf_name1(char *name,int color);
//颜色参数
#define WHITE 0
#define BLUE  1
#define GREEN 2
#define RED   3
#define LBLUE 4
#define YELLOW 5
//对不同的文件类型给不同的颜色
int get_color(struct stat buf)
{
 int color = 0;
 if(S_ISLNK(buf.st_mode))
 {
     color = LBLUE;
 }
 else if(S_ISDIR(buf.st_mode))
 {
     color = BLUE;
 }
 else if(S_ISCHR(buf.st_mode) ||S_ISBLK(buf.st_mode) )
 {
     color = YELLOW;
 }
 else if(buf.st_mode & S_IXUSR)
 {
     color = GREEN;
 }
 return color;
}
打印有颜色的文件名
void printf_name(char *name,int color)
{
 if(color == GREEN)
 {
     printf("\033[1m\033[32m%-22s\033[0m",name);
 }
 else if(color == BLUE)
 {
     printf("\033[1m\033[34m%-22s\033[0m",name);
 }
 else if(color == WHITE)
 {
     printf("%-22s",name);
 }
 else if(color == LBLUE)
 {
     printf("\033[1m\033[36m%-22s\033[0m",name);
 }
 else if(color == YELLOW)
 {
     printf("\033[1m\033[33m%-22s\033[0m",name);
 }
}

文件的字典序

在Linux中ls命令显示出来的文件顺序是以文件名以字典序排出来的,所以我们在自己实现myls时也需要考虑到字典序问题,我使用的方法是快排(其他排序方法也是可以的)
我们可以创建一个全局变量的数组,和全局的计数变量

//存放数组名的数组
char *filenames[4096];
//目录中文件个数	
int file_cnt = 0;		

我们可以先将目录中的文件名存入数组中,然后进行排序,排完序后再从数组中输出文件名即可
代码如下:

//比较两字符串的字典序
//s1靠前,返回负数,s1靠后,返回正数
//s1和s2完全一样,返回0
int compare(char* s1,char* s2)
{
  if(*s1=='.')
    s1++;
  if(*s2=='.')
    s2++;
	while(*s1 && *s2 && *s1 == *s2)
  {
		++s1;
		++s2;
    if(*s1=='.')
      s1++;
    if(*s2=='.')
      s2++;
	}
	return *s1 - *s2;
}

int partition(char** filenames,int start,int end)
{
	if(!filenames)	return -1;
	char* privot = filenames[start];
	while(start < end){
		while(start < end && compare(privot,filenames[end]) < 0)
			--end;
		swap(&filenames[start],&filenames[end]);
		while(start < end && compare(privot,filenames[start]) >= 0)
			++start;
		swap(&filenames[start],&filenames[end]);
	}
	return start;
}

void sort(char** filenames,int start,int end)
{
	if(start < end)
	{
		int position = partition(filenames,start,end);
		sort(filenames,start,position - 1);
		sort(filenames,position + 1,end);
	}
}
//将目录中的文件依次存入数组中
void restored_ls(struct dirent* cur_item)
{
	filenames[file_cnt++] = cur_item->d_name;
}

void error_handle(const char* dir_name)
{
	perror(dir_name);
	exit(1);
}

注意事项:隐藏文件开头的那个 . 和文件后缀的.都不参与排序,直接跳过即可
使用时:

  //将文件名存入数组
       while((direntp = readdir(dir_ptr)))
       {
         restored_ls(direntp);
       }
       sort(filenames,0,file_cnt-1);
       int i=0;
       for(i=0;i<cur_item;i++)
       {
         //对排好序的文件名进行排序
	   }

ls -r(以逆序显示文件)

在上面我们实现了文件的字典序,-r就是将其逆序即可
这个实现起来就更简单了。在上一步我们已经实现将排好序的文件名存到数组当中了,我们想实现文件逆序显示只需要将数组中的文件名倒着输出就可以了

   for(i=cir_item-1;i>=0;i--)
     {
       //对排好序的文件名进行排序
     }

实现各种参数组合(最终代码)

#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<dirent.h>
#include<sys/stat.h>
#include<grp.h>
#include<pwd.h>
void do_ls(char[]);// -al
void do_ls1(char[]);// -l
void do_ls2(char[]);// -a
void do_ls3(char[]);// ls
void do_ls4(char[]);// ls
void do_ls5(char[]);// ls -i
void do_ls6(char[]);// ls -ial
void ls_R(char path[]);//ls -R
//void dostat(char*);
//void show_file_info(char*,struct stat*);
void mode_to_letters(int ,char[]);
//用来适配ls -R
void dostat(char*,char*);
void show_file_info(char*,char*,struct stat*);
char*uid_to_name(uid_t);
char*gid_to_name(gid_t);
void match(int argc,char*argv[]);
void restored_ls(struct dirent*);
void error_handle(const char*);
//字典序
void swap(char** s1,char** s2);
int compare(char* s1,char* s2);
int partition(char** filenames,int start,int end);
void sort(char** filenames,int start,int end);
//文件名字颜色
int get_color(struct stat buf);
void printf_name(char *name,int color);
void printf_name1(char *name,int color);
//颜色参数
#define WHITE 0
#define BLUE  1
#define GREEN 2
#define RED   3
#define LBLUE 4
#define YELLOW 5
int has_a=0;
int has_l=0;
int has_al=0;
int has_i=0;
int has_ial=0;
int has_il=0;
int has_ai=0;
int has_R=0;
int has_aR=0;
int has_Rl=0;
int has_iR=0;
int has_aRl=0;
int has_r=0;
int has_ar=0;
int has_s=0;
//存放数组名的数组
char *filenames[4096];		
int file_cnt = 0;			//目录中文件个数
int main(int argc,char* argv[])
{
  int*app=(int*)malloc(sizeof(int)*10);
   match(argc,argv);
  if(argc==1)
  {
    do_ls2(".");
  }
  else 
  {
    char* name=".";
     int i=0;
     for(i=1;i<argc;i++)
     {
       if(argv[i][0]!='-')
       {
         name=argv[i];
         break;
       }
     }
   // while(--argc)
   // {
      if(has_a==1&&has_l!=1||has_ar==1)
      {
        do_ls3(name);
      }
      else if(has_r==1)
      {
        do_ls2(name);
      }
      else if(has_a!=1&&has_l==1)
      {
        do_ls(name);
      }
      else if(has_al==1)
      {
        do_ls4(name);
      }
      else if(has_i==1&&has_a!=1&&has_l!=1&&has_al!=1)
      {
        do_ls5(name);
      }
      else if(has_ial==1)
      {
        do_ls4(name);
      }
      else if(has_il==1)
      {
        do_ls4(name);
      }
      else if(has_ai==1)
      {
        do_ls5(name);
      }
      else if(has_aR==1)
      {
        ls_R(name);
      }
      else if(has_R==1)
      {
        ls_R(name);
      }
      else if(has_aRl==1||has_Rl==1)
      {
        ls_R(name);
      }
      else if(has_s==1)
      {
        do_ls2(name);
      }
      else 
      {
         printf("%s:\n",*++argv);
         do_ls(*argv);
      }
 //  }
  }
  return 0;
  
}
void do_ls(char dirname[])
{
  DIR*dir_ptr;
  struct dirent*direntp;
  if((dir_ptr=opendir(dirname))==NULL)
    fprintf(stderr,"lsl:cannot open %s\n",dirname);
  else 
  {   
    //读取目录并显示信息
          //将文件名存入数组
          while((direntp = readdir(dir_ptr)))
          {
            restored_ls(direntp);
          }
          sort(filenames,0,file_cnt-1);
          int j = 0;
          for(j = 0;j < file_cnt;++j)
          {
               if(filenames[j][0]=='.')
                 continue;
                   char temp1[PATH_MAX];
            sprintf(temp1,"%s/%s" ,dirname,filenames[j]);
            dostat(temp1,filenames[j]);

          }

    closedir(dir_ptr);
  }
}
 void do_ls4(char dirname[])
    {
      DIR*dir_ptr;
      struct dirent*direntp;
      if((dir_ptr=opendir(dirname))==NULL)
        fprintf(stderr,"lsl:cannot open %s\n",dirname);
      else 
      { 
         
                  //读取目录并显示信息
          //将文件名存入数组
          while((direntp = readdir(dir_ptr)))
          {
            restored_ls(direntp);
          }
          sort(filenames,0,file_cnt-1);
          int j = 0;
          for(j = 0;j < file_cnt;++j)
          {
            if(has_il==1)
            {
              if(filenames[j][0]=='.')
                continue;
            }
              char temp1[PATH_MAX];
            sprintf(temp1,"%s/%s",dirname,filenames[j]);
            dostat(temp1,filenames[j]);

         }

        closedir(dir_ptr);
      }
    }

void do_ls1(char dirname[])
    {                                                                                                                                                                                        
      DIR*dir_ptr;
      struct dirent*direntp;
      if((dir_ptr=opendir(dirname))==NULL)
        fprintf(stderr,"lsl:cannot open %s\n",dirname);
      else 
      { 
               //读取目录并显示信息
       //将文件名存入数组
       while((direntp = readdir(dir_ptr)))
       {
         restored_ls(direntp);
       }
       sort(filenames,0,file_cnt-1);
       int j = 0;
       for(j = 0;j < file_cnt;++j)
       {
                char temp1[PATH_MAX];
            sprintf(temp1,"%s/%s",dirname,filenames[j]);
            dostat(temp1,filenames[j]);
       }
        closedir(dir_ptr);
      }
    }
void do_ls2(char dirname[])
{
  int i=0;
  DIR*dir_ptr;
  struct dirent*direntp;
  if((dir_ptr=opendir(dirname))==NULL)     //打开失败
  {
    fprintf(stderr,"lsl:cannot open %s\n",dirname);
  }
  else                                   //打开成功
  {
      
           //读取目录并显示信息
		//将文件名存入数组
		while((direntp = readdir(dir_ptr)))
    {
			restored_ls(direntp);
    }
    sort(filenames,0,file_cnt-1);
    int j = 0;
    if(has_r==1)
    {
      for(j=file_cnt-1;j>=0;--j)
      {
          if(filenames[j][0]=='.')
          continue;
        struct stat info;
        if(stat(filenames[j],&info)==-1)
          perror(filenames[j]);
        int color=get_color(info);
        if(has_s==1)
        {
          long long size=info.st_size/1024;                              
            if(size<=4)                                                    
               printf("4   ");                                                
            else                                                           
               printf("%-4lld",size);   
        }
            printf_name(filenames[j],color);
            i++;
            if(i==4)
            {
              printf("\n");
              i=0;
            }
      }
      printf("\n");
      return;
    }
		for(j = 0;j < file_cnt;++j)
    {
        if(filenames[j][0]=='.')
          continue;
        struct stat info;
        if(stat(filenames[j],&info)==-1)
          perror(filenames[j]);
        int color=get_color(info);
        if(has_s==1)
          {                       
             long long size=info.st_size/1024;                              
               if(size<=4)           
                  printf("4   ");                
               else         
                  printf("%-4lld",size);                                                                                                                                                    
           }                     
            printf_name(filenames[j],color);
            i++;
            if(i==4)
            {
              printf("\n");
              i=0;
            }
     }
      }
     printf("\n");
    closedir(dir_ptr);
    
}
void do_ls3(char dirname[])
{
  int i=0;
  int len=0;
  DIR*dir_ptr;
  struct dirent*direntp;
  if((dir_ptr=opendir(dirname))==NULL)     //打开失败
  {
    fprintf(stderr,"lsl:cannot open %s\n",dirname);
  }
  else                                   //打开成功
  {
     while((direntp = readdir(dir_ptr)))
       {
         restored_ls(direntp);
       }
       sort(filenames,0,file_cnt-1);
       int j = 0;
       if(has_ar==1)
       {
          for(j = file_cnt-1;j >=0;--j)
       {
            struct stat info;
           if(stat(filenames[j],&info)==-1)
             perror(filenames[j]);
           int color=get_color(info);
           if(has_s==1)
          {                       
             long long size=info.st_size/1024;                              
               if(size<=4)           
                  printf("4   ");                
               else         
                  printf("%-4lld",size);                                                                                                                                                    
           }                     
           printf_name(filenames[j],color);
    
               i++;
               if(i==4)
               {
                 printf("\n");
                 i=0;
               }
        }
				  printf("\n");
				return;
       }
       for(j = 0;j < file_cnt;++j)
       {
            struct stat info;
           if(stat(filenames[j],&info)==-1)
             perror(filenames[j]);
           int color=get_color(info);
            if(has_s==1)
          {                       
             long long size=info.st_size/1024;                              
               if(size<=4)           
                  printf("4   ");                
               else         
                  printf("%-4lld",size);                                                                                                                                                    
           }                        
           printf_name(filenames[j],color);
    
               i++;
               if(i==4)
               {
                 printf("\n");
                 i=0;
               }
        }

     
  printf("\n");
    closedir(dir_ptr);
  
  }
}

void do_ls5(char dirname[])
{
  int i=0;
  DIR*dir_ptr;
  struct dirent*direntp;
  if((dir_ptr=opendir(dirname))==NULL)
    fprintf(stderr,"ls1:cannot open %s\n",dirname);
  else 
  {
     while((direntp = readdir(dir_ptr)))
          {
            restored_ls(direntp);
          }
          sort(filenames,0,file_cnt-1);                                                                                                                              
          int j = 0;
          for(j = 0;j < file_cnt;++j)
          {
            if(has_ai!=1)
            {
                if(filenames[j][0]=='.')
                  continue;
            }
                struct stat info;
                if(stat(filenames[j],&info)==-1)
                  perror(filenames[j]);
                  printf("%d  ",info.st_ino); 
                 int color=get_color(info);
                 if(has_s==1)
          {                       
             long long size=info.st_size/1024;                              
               if(size<=4)           
                  printf("4   ");                
               else         
                  printf("%-4lld",size);                                                                                                                                                    
           }                     
                  printf_name(filenames[j],color);
                  i++;
                  if(i==4)
                  {
                    printf("\n");
                    i=0;
                  }
           }

  closedir(dir_ptr);
  printf("\n");

  }
}

void mode_to_letters(int mode,char 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(mode&S_IRUSR)str[1]='r';
  if(mode&S_IWUSR)str[2]='w';
  if(mode&S_IXUSR)str[3]='x';

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

  if(mode&S_IROTH)str[7]='r';
  if(mode&S_IWOTH)str[8]='w';
  if(mode&S_IXOTH)str[9]='x';
}
//用来适配-R
void dostat(char*path,char*filename)
{
  struct stat info;
  if(stat(path,&info)==-1)
    perror(path);
  else 
    show_file_info(path,filename,&info);
}
void show_file_info(char*path,char*filename,struct stat*info_p)
{
  char*uid_to_name(),*ctime(),*git_to_name(),*filemode();
  void mode_to_letters();
  char modestr[11];
      struct stat info;
       if(stat(path,&info)==-1)
       perror(path);
       int color=get_color(info);
  mode_to_letters(info_p->st_mode,modestr);
  if(has_ial==1||has_il==1)
  printf("%ul ",info_p->st_ino);
  if(has_s==1)
          {                       
             long long size=info.st_size/1024;                              
               if(size<=4)           
                  printf("4 ");                
               else         
                  printf("%-lld ",size);                                                                                                                                                    
           }                     
  printf("%s ",modestr);
  printf("%4d ",(int)info_p->st_nlink);
  printf("%-8s ",uid_to_name(info_p->st_uid));
  printf("%-8s ",gid_to_name(info_p->st_gid));
  printf("%8ld ",(long)info_p->st_size);
  printf("%.12s ",4+ctime(&info_p->st_ctim));
  printf_name1(filename,color);
  printf("\n");
}
char*uid_to_name(gid_t uid)
{
  struct passwd*getpwuid();
  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*getgrgid(),*grp_ptr;
  static char numstr[10];
  if((grp_ptr=getgrgid(gid))==NULL)
  {
    sprintf(numstr,"%d",gid);
    return numstr;
  }
  else 
  {
    return grp_ptr->gr_name;
  }
}
void match(int argc,char*argv[])
{
  int i=1;
  for(i=1;i<argc;i++)
  {
    if(strcmp(argv[i],"-a")==0)
      has_a=1;
    if(strcmp(argv[i],"-l")==0)
      has_l=1;
    if(strcmp(argv[i],"-R")==0)
      has_R=1;
    if(strcmp(argv[i],"-al")==0||strcmp(argv[i],"-la")==0||(has_a==1&&has_l==1))
    {
     has_al=1;
     has_a=0;
     has_l=0;
    }
    if(strcmp(argv[i],"-r")==0)
      has_r=1;
		if(strcmp(argv[i],"-ra")==0||strcmp(argv[i],"-ar")==0||(has_a==1&&has_r==1))
    {
      has_ar=1;
      has_a=0;
      has_r=0;
    }
    if(strcmp(argv[i],"-i")==0)
      has_i=1;
    if(strcmp(argv[i],"-ail")==0||strcmp(argv[i],"-ial")==0||strcmp(argv[i],"-lia")==0||strcmp(argv[i],"-ali")==0||strcmp(argv[i],"ila")==0||strcmp(argv[i],"lai")==0||(has_a==1&&has_l==1&&has_i==1)||(has_il==1&&has_a==1)||(has_ai==1&&has_l==1))
    {
      has_ial=1;
      has_i=0;
      has_a=0;
      has_l=0;
      has_il=0;
      has_al=0;
    }
    if(strcmp(argv[i],"-il")==0||strcmp(argv[i],"-li")==0||(has_i==1&&has_l==1))
    {
      has_il=1;
      has_i=0;
      has_l=0;
    }
     if(strcmp(argv[i],"-Rl")==0||strcmp(argv[i],"-lR")==0||(has_l==1&&has_R==1))
    {
      has_Rl=1;
      has_R=0;
      has_l=0;
    }
     if(strcmp(argv[i],"-aR")==0||strcmp(argv[i],"-Ra")==0||(has_a==1&&has_l==1))
    {
      has_aR=1;
      has_R=0;
      has_a=0;
    }
    if(strcmp(argv[i],"-aRl")==0||strcmp(argv[i],"-alR")==0||strcmp(argv[i],"-laR")==0||strcmp(argv[i],"-lRa")==0||strcmp(argv[i],"-Ral")==0||strcmp(argv[i],"-Rla")==0||(has_a==1&&has_l==1&&has_R==1)||(has_aR==1&&has_l==1)||(has_Rl==1&&has_a==1)||(has_al==1&&has_R==1))
    {
      has_aRl=1;
      has_a=0;
      has_R=0;
      has_l=0;
      has_aR=0;
      has_Rl=0;
      has_al=0;
    }
     if(strcmp(argv[i],"-s")==0)
     {
       has_s=1;
     }
     if(strcmp(argv[i],"-as")==0||strcmp(argv[i],"-sa"))
     {
       has_s=1;
       has_a=1;
     }

  }
}
//交换两字符串
void swap(char** s1,char** s2)
{
	char* tmp = *s1;
	*s1 = *s2;
	*s2 = tmp;
}

//比较两字符串的字典序
//s1靠前,返回负数,s1靠后,返回正数
//s1和s2完全一样,返回0
int compare(char* s1,char* s2)
{
  if(*s1=='.')
    s1++;
  if(*s2=='.')
    s2++;
	while(*s1 && *s2 && *s1 == *s2)
  {
		++s1;
		++s2;
    if(*s1=='.')
      s1++;
    if(*s2=='.')
      s2++;
	}
	return *s1 - *s2;
}

int partition(char** filenames,int start,int end){
	if(!filenames)	return -1;
	char* privot = filenames[start];
	while(start < end){
		while(start < end && compare(privot,filenames[end]) < 0)
			--end;
		swap(&filenames[start],&filenames[end]);
		while(start < end && compare(privot,filenames[start]) >= 0)
			++start;
		swap(&filenames[start],&filenames[end]);
	}
	return start;
}

void sort(char** filenames,int start,int end){
	if(start < end){
		int position = partition(filenames,start,end);
		sort(filenames,start,position - 1);
		sort(filenames,position + 1,end);
	}
}
void restored_ls(struct dirent* cur_item){
	char* result = cur_item->d_name;
	filenames[file_cnt++] = cur_item->d_name;
}

void error_handle(const char* dir_name){
	perror(dir_name);
	exit(1);
}
//对不同的文件类型给不同的颜色
int get_color(struct stat buf)
{
    int color = 0;
    if(S_ISLNK(buf.st_mode))
    {
        color = LBLUE;
    }
    else if(S_ISDIR(buf.st_mode))
    {
        color = BLUE;
    }
    else if(S_ISCHR(buf.st_mode) ||S_ISBLK(buf.st_mode) )
    {
        color = YELLOW;
    }
    else if(buf.st_mode & S_IXUSR)
    {
        color = GREEN;
    }
    return color;
}

void printf_name(char *name,int color)
{
    if(color == GREEN)
    {
        printf("\033[1m\033[32m%-22s\033[0m",name);
    }
    else if(color == BLUE)
    {
        printf("\033[1m\033[34m%-22s\033[0m",name);
    }
    else if(color == WHITE)
    {
        printf("%-22s",name);
    }
    else if(color == LBLUE)
    {
        printf("\033[1m\033[36m%-22s\033[0m",name);
    }
    else if(color == YELLOW)
    {
        printf("\033[1m\033[33m%-22s\033[0m",name);
    }
}
void printf_name1(char *name,int color)
{
    if(color == GREEN)
    {
        printf("\033[1m\033[32m%s\033[0m",name);
    }
    else if(color == BLUE)
    {
        printf("\033[1m\033[34m%s\033[0m",name);
    }
    else if(color == WHITE)
    {
        printf("%s",name);
    }
    else if(color == LBLUE)
    {
        printf("\033[1m\033[36m%s\033[0m",name);
    }
    else if(color == YELLOW)
    {
        printf("\033[1m\033[33m%s\033[0m",name);
    }
}
void printf_name2(char *name,int color)
{
    if(color == GREEN)
    {
        printf("\033[1m\033[32m%s\033[0m  ",name);
    }
    else if(color == BLUE)
    {
        printf("\033[1m\033[34m%s\033[0m  ",name);
    }
    else if(color == WHITE)
    {
        printf("%s  ",name);
    }
    else if(color == LBLUE)
    {
        printf("\033[1m\033[36m%s\033[0m  ",name);
    }
    else if(color == YELLOW)
    {
        printf("\033[1m\033[33m%s\033[0m  ",name);
    }
}
void ls_R(char path[])
{
  printf("%s:\n",path);
  DIR*dir_ptr;
  struct dirent*direntp;
  if((dir_ptr=opendir(path))==NULL)//打开目录
    fprintf(stderr,"lsl:cannot open %s\n",path);
  else 
  {
    while((direntp=readdir(dir_ptr))!=NULL)//读取当前目录文件
    {
      restored_ls(direntp);
    }
       sort(filenames,0,file_cnt-1);                          
    int j=0;
    int i=0;
    for(j=0;j<file_cnt;++j)
    {
      if(has_aRl==1||has_Rl==1)
      {
          char temp1[PATH_MAX];
         sprintf(temp1,"%s/%s",path,filenames[j]);
         dostat(temp1,filenames[j]);
         continue;
      }
      if(filenames[j][0]=='.'&&(has_aR!=1||has_aRl!=1))
        continue;
      struct stat info;
      char temp1[PATH_MAX];
      sprintf(temp1,"%s/%s",path,filenames[j]);
      if(stat(temp1,&info)==-1)
        perror(temp1);
      int color=get_color(info);
      if(has_s==1)
          {                       
             long long size=info.st_size/1024;                              
               if(size<=4)           
                  printf("4   ");                
               else         
                  printf("%-4lld",size);                                                                                                                                                    
           }                     
      printf_name2(filenames[j],color);
    }
  }
  printf("\n");
  printf("\n");
  file_cnt=0;
  closedir(dir_ptr);
  if((dir_ptr=opendir(path))==NULL)//打开目录
    fprintf(stderr,"lsl:cannot open %s\n",path);
  else 
  {
    while((direntp=readdir(dir_ptr))!=NULL)
    {
      if(strcmp(direntp->d_name,".")==0||strcmp(direntp->d_name,"..")==0)             
        continue;
      if(has_R==1)
      {
        if(direntp->d_name[0]=='.')
          continue;
      }
      struct stat info;
      char temp[PATH_MAX];
      sprintf(temp,"%s/%s",path,direntp->d_name);
      if(stat(temp,&info)==-1)
        perror(temp);
      if(S_ISDIR(info.st_mode))//判断是否为目录,如果是目录就进入递归
      {
        ls_R(temp);
      }
      
    }
  }
}

总结与感想

在最开始看到这个任务时,无从下手,然后通过查阅各种资料书籍以及其他学长的代码
才开始有了自己的思路,然后开始一点点的完成。通过这个任务还是学到了很多东西的,了解了文件信息的存储,学会使用了很多文件函数比如:opendir(),readdir(),close()等,了解了文件的权限,索引等信息。了解了结构体stat。提高了c语言编程能力以及gdb的使用
不足:参数处理方面太菜,使用最无脑的字符串匹配
代码啰嗦,代码风格不是特别好。

举报

相关推荐

0 条评论