自己实现 ls命令

实现代码如下(只支持-a 与-l 选项):

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

#define PARAM_NONE 0
#define PARAM_A    1
#define PARAM_L    2
#define MAXROWLEN    80

void my_err(const char *err_string ,int line )
{
    fprintf(stderr,"line:%d " ,line) ; 
    perror(err_string) ; 
    exit(1) ;
}

void display_attribute(struct stat buf,char *name)
{
    char buf_time[32];
    struct passwd *psd;
    struct group *grp;

    if(S_ISREG(buf.st_mode))
        printf("-");
    else if(S_ISDIR(buf.st_mode))
        printf("d");

    if(buf.st_mode & S_IRUSR)  //与对应的权限取与运算即可
        printf("r");
    else printf("-");
    if (buf.st_mode & S_IWUSR)
        printf("w");
    else printf("-");
    if(buf.st_mode & S_IXUSR )
        printf("x");
    else printf("-");

    if(buf.st_mode & S_IRGRP)
        printf("r");
    else printf("-");
    if (buf.st_mode & S_IWGRP)
        printf("w");
    else printf("-");
    if(buf.st_mode & S_IXGRP )
        printf("x");
    else printf("-");

    if(buf.st_mode & S_IROTH)
        printf("r");
    else printf("-");
    if (buf.st_mode & S_IWOTH)
        printf("w");
    else printf("-");
    if(buf.st_mode & S_IXOTH)
        printf("x");
    else printf("-");
    printf(".   ");
    printf("%4d",buf.st_nlink);
    psd=getpwuid(buf.st_uid);
    grp=getgrgid(buf.st_gid);
    printf("%-8s",psd->pw_name);
    printf("%-8s",grp->gr_name);
    printf("%6d",buf.st_size);
    strcpy(buf_time,ctime(&buf.st_mtime));
    buf_time[strlen(buf_time)- 1]='\0';
    printf(" %s",buf_time);
}

void display(int flag_param,char *pathname)///home/liushengxi/test.c   /home/liushengxi/.vimrc
{
    int i,j;
    struct stat buf;
    char name[NAME_MAX + 1];//最长文件名 name 
    for(i= 0,j= 0;i<strlen(pathname);i++)
    {
        if(pathname[i]=='/')
        {
            j= 0;
            continue;
        }
        name[j++]=pathname[i];
    }
    name[j]='\0';
    if(lstat(pathname,&buf) < 0)  //buf 存储文件
        my_err("lstat",__LINE__);
    switch(flag_param)
    {
        case PARAM_NONE:
            if(name[0] != '.')
                printf("%s\n",name);//打印单个文件
            break;
        case PARAM_A:printf("%s\n",name);
                     break;
        case PARAM_L:
                     if(name[0] != '.')
                     {
                         display_attribute(buf,name); //另一个函数
                         printf("%-8s\n",name);
                     }
                     break;
        case PARAM_A+PARAM_L:
                     display_attribute(buf,name);
                     printf("%-8s\n",name);
                     break;
        default:break;
    }
}

void display_dir(int  flag_param,char *path) //path 目录名
{
    DIR *dir;
    struct  dirent  *ptr;
    int count= 0;
    char filename[256][PATH_MAX+ 1],temp[PATH_MAX + 1];
    dir=opendir(path);
    if(dir == NULL)
        my_err("opendir",__LINE__);

    while((ptr=readdir(dir)) != NULL)//目录下的文件名ptr->d_name 
        count++;
    closedir(dir);
    if(count > 256)
        my_err("too many files in the dir ",__LINE__);
    int i,j,len=strlen(path); //路径
    dir=opendir(path);
    for(i= 0;i<count;i++) //一个文件一个文件的打开
    {
        ptr=readdir(dir);
        if(ptr == NULL )
        {
            my_err("readdir",__LINE__);
        }
        strncpy(filename[i],path,len);//把目录名考到filename中
        filename[i][len]='\0';
        strcat(filename[i],ptr->d_name);//把文件名考到filename中
        filename[i][len+strlen(ptr->d_name)]='\0';
    }
    for(i= 0;i< count- 1;i++)
    {
        for(j= 0;j< count -1 -i ;j++)
        {
            if(strcmp(filename[j],filename[j + 1]) > 0 )//
            {
                strcpy(temp,filename[j+ 1]);
                strcpy(filename[j + 1],filename[j]);
                strcpy(filename[j],temp);
            }
        }
    }
    for(i= 0;i< count; i++)
        display(flag_param,filename[i]);
    closedir(dir);
}
int main(int argc,char **argv)  
{
    int i,j,k,num;
    char path[PATH_MAX+ 1]; //路径
    int param[32]; //保存命令行参数
    struct stat buf; //文件信息 
    int flag_param=PARAM_NONE;//参数种类
    j= 0;
    num = 0;
    for(i= 1;i<argc;i++) //ls -a -l rgbobn      argc==4;num == 3
    {
        if(argv[i][0] == '-')
        {
            for(k= 1;k <strlen(argv[i]);k++,j++)
                param[j]=argv[i][k];
        }
        num++;
    }
    for(i=  0;i< j;i++)
    {
        if(param[i] == 'a')
        {
            flag_param |= PARAM_A;
            continue;
        }
        else if(param[i]== 'l')
        {
            flag_param |= PARAM_L;
            continue;
        }
        else 
        {
            printf("sorry !! now we agree -al\n");
            exit(1);
        }
    }
    param[j]='\0';
    if((num + 1) != argc) //只输入a.out ,即 ls  
    {
        strcpy(path,"./");
        path[2]='\0';
        display_dir(flag_param,path);//parh== './' 
        return 0;
    }
    i= 1;
    do
    {
    if(argv[i][0] == '-')
        {
            i++;
            continue;
        }
        else 
        {
            strcpy(path,argv[i]);
            if(stat(path,&buf)< 0)
                my_err("stat",__LINE__);
            if(S_ISDIR(buf.st_mode))// argv[i] 是一个目录
            {
                printf("ISDIR\n");
                if(path[strlen(argv[i])- 1] != '/')
                {
                    path[strlen(argv[i])] ='/';
                    path[strlen(argv[i]+ 1)] ='\0';
                }
                else  path[strlen(argv[i])] ='\0';

                display_dir(flag_param,path);//flag_param ==  0
                i++ ;
            }
            else //arhv[i]是一个文件
            {
                display(flag_param,path);
                i++ ;
            }
        }
    }while(i< argc);
    return 0;
}

输入命令时的几种可能情况:

    -     ls 
    -     ls  -a 
	-     ls  -l
	-     ls   -al 
	-     ls   -l    /home
	-     ls   -a   -l   /home/
	-     ls    文件
	-     ls  -l    文件名
	-     ls    -a  -l  文件名

设计思路:

只有两种情况:

1. 查看文件

2. 查看目录

获取文件属性的三个函数:

   #include <sys/types.h>
   #include <sys/stat.h>
   #include <unistd.h>

   int stat(const char *path, struct stat *buf);
   int fstat(int fd, struct stat *buf);
   int lstat(const char *path, struct stat *buf);

##struct stat *buf 保存文件状态信息的结构体

struct stat
{

dev_t       st_dev;     /* ID of device containing file -文件所在设备的ID*/  

ino_t       st_ino;     /* inode number -inode节点号*/  

mode_t      st_mode;    /* protection -保护模式?*/  

nlink_t     st_nlink;   /* number of hard links -链向此文件的连接数(硬连接)*/  

uid_t       st_uid;     /* user ID of owner -user id*/  

gid_t       st_gid;     /* group ID of owner - group id*/  

dev_t       st_rdev;    /* device ID (if special file) -设备号,针对设备文件*/  

off_t       st_size;    /* total size, in bytes -文件大小,字节为单位*/  

blksize_t   st_blksize; /* blocksize for filesystem I/O -系统块的大小*/  

blkcnt_t    st_blocks;  /* number of blocks allocated -文件所占块数*/  

time_t      st_atime;   /* time of last access -最近存取时间*/  

time_t      st_mtime;   /* time of last modification -最近修改时间*/  

time_t      st_ctime;   /* time of last status change - */  

};

struct passwd //保存文件所有者的信息
{
char * pw_name; /* Username, POSIX.1 /
char * pw_passwd; /
Password /
__uid_t pw_uid; /
User ID, POSIX.1 /
__gid_t pw_gid; /
Group ID, POSIX.1 /
char * pw_gecos; /
Real Name or Comment field /
char * pw_dir; /
Home directory, POSIX.1 /
char * pw_shell; /
Shell Program, POSIX.1 */
};

struct group { //保存文件所有者所属组的信息
char gr_name; / group name */
char gr_passwd; / group password /
gid_t gr_gid; /
group ID */
char *gr_mem; / NULL-terminated array of pointers
to names of group members */
};
getpwuid函数是通过用户的uid查找用户的passwd数据
getgrgid()用来依参数gid指定的组识别码逐一搜索组文件,找到时便将该组的数据以group结构返回

The group structure is defined in\<grp.h> as follows:
struct group
{
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* group members */
};

系统标准配置变量包含由一个特殊系统标准所要求的最小值。POSIX、POSIX2_ 和 XOPEN 前缀显示变量包含分别由 POSIX 1003.1、POSIX 1003.2 和 X/Open 系统标准要求的系统特性最小值。系统标准是系统满足的用来支持特定系统标准的全系统最小值。实际配置值可能超出这些标准。用于 getconf 命令的这些系统标准配置变量的定义如下:
NAME_MAX

文件名中的最大字节数(不包含终止空字符)。如果 PathName 参数引用目录,返回值应用于目录内的文件名。

PATH_MAX

路径名中的最大字节数,包含终止空字符。如果 PathName 参数引用目录,返回值为当指定目录是工作目录时的相对路径名的最大长度。

struct dirent
{
  long d_ino; /* inode number 索引节点号 /
  
off_t d_off; /
offset to this dirent 在目录文件中的偏移 /
  
unsigned short d_reclen; /
length of this d_name 文件名长 /
  
unsigned char d_type; /
the type of d_name 文件类型 /
  
char d_name [NAME_MAX+1]; /
file name (null-terminated) 文件名,最长255字符 */
}

从上述定义也能够看出来,dirent结构体存储的关于文件的信息很少,所以dirent同样也是起着一个索引的作用,如果想获得类似ls -l那种效果的文件信息,必须要靠stat函数了。

 转义序列以控制字符'ESC'开头。该字符的ASCII码十进制表示为27,十六进制表示为0x1B,八进制表示为033。多数转义序列超过两个字符,故通常以'ESC'和左括号'['开头。该起始序列称为控制序列引导符(CSI,Control Sequence Intro),通常由'\033['或'\e['代替。

 通过转义序列设置终端显示属性时,可采用以下格式:

\033[ Param {;Param;…}m

\e[ Param {;Param;…}m

 其中,'\033['或'\e['引导转义序列,'m'表示设置属性并结束转义序列。Param为属性值,{...}表示可选(多个参数之间用分号隔开,与顺序无关)。例如,在Linux Shell中执行下述命令:



 即设置输出为红色字体(31),白色背景(47)。选项'-e'为echo命令激活特殊字符的解析器。

 注意,转义序列可被控制字符'CAN'(Cancel )和'SUB'(Substitute)中断。

 转义序列相关的常用参数如下(通过man console_codes命令可查看更多的参数描述):

显示:0(默认)、1(粗体/高亮)、22(非粗体)、4(单条下划线)、24(无下划线)、5(闪烁)、25(无闪烁)、7(反显、翻转前景色和背景色)、27(无反显)
颜色:0(黑)、1(红)、2(绿)、 3(黄)、4(蓝)、5(洋红)、6(青)、7(白)
前景色为30+颜色值,如31表示前景色为红色;背景色为40+颜色值,如41表示背景色为红色。

调色效果如下图所示:



 因此,通过转义序列设置终端显示属性时,常见格式为:

\033[显示方式;前景色;背景色m输出字符串\033[0m

\e[显示方式;前景色;背景色m输出字符串\033[0m

 其中 ,'\033[0m'用于恢复默认的终端输出属性,否则会影响后续的输出。

 此外,还有一些ANSI控制码,如:nA (光标上移n行 )、nB(光标下移n行 )、nC(光标右移n行 )、nD (光标左移n行 )、2J(清屏)、K(清除从光标到行尾的内容)、s(保存光标位置)、u(恢复光标位置)、?25l(隐藏光标)、?25l(显示光标)。

 基于常用参数,可定义如下单一控制宏,用于printf系列语句:

复制代码
1 #define NONE “\e[0m”
2 #define BLACK “\e[0;30m”
3 #define L_BLACK “\e[1;30m”
4 #define RED “\e[0;31m”
5 #define L_RED “\e[1;31m”
6 #define GREEN “\e[0;32m”
7 #define L_GREEN “\e[1;32m”
8 #define BROWN “\e[0;33m”
9 #define YELLOW “\e[1;33m”
10 #define BLUE “\e[0;34m”
11 #define L_BLUE “\e[1;34m”
12 #define PURPLE “\e[0;35m”
13 #define L_PURPLE “\e[1;35m”
14 #define CYAN “\e[0;36m”
15 #define L_CYAN “\e[1;36m”
16 #define GRAY “\e[0;37m”
17 #define WHITE “\e[1;37m”
18
19 #define BOLD “\e[1m”
20 #define UNDERLINE “\e[4m”
21 #define BLINK “\e[5m”
22 #define REVERSE “\e[7m”
23 #define HIDE “\e[8m”
24 #define CLEAR “\e[2J”
25 #define CLRLINE “\r\e[K” //or “\e[1K\r”

求10(1010)的第三位数
int a=10;
int b=a;
b=b>>(3-1)&1;
得到的b就是10的第三位

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值