在本文上部分中,主要陈述my_ls.c的大致结构,本文主要来分析my_ls中主函数是如何实现的。
(1)进入main函数。首先对命令行参数进行解析,即提取命令行参数中‘-’后的选项。用户的输入有多样性,如ls -l -a;ls -la。我们用两层循环类来解析参数,外层循环对argv[]数组中的元素依次进行内层循环的解析,二层循环对以‘-’为首的字符串进行选项提取,并把每个选项存于param[]数组当中,用num来记下‘-’的数目,以备后用。而命令行参数中的总选项数目则用j计数。实现代码如下:
j=0;
num=0;
for(i=1;i<\argc;i++)
{
if(argv[i][0]=='-')
{
for(k=1;k<\strlen(argv[i]);k++)
{
param[j++]=argv[i][k];
}
num++;//count the number of '-'
}
}
接下来,我们来检查刚刚提取的选项是否合法。本程序我们只支持选项-l和-a,因此如果我们增添其他选项,只要适当添加代码即可。并且我们用或运算记录参数,以备后用。最后为选项数组的末尾元素赋‘\0’。
//check the argument because of only supporting -a and -l
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("error:my_ls invalid option -%c\n",param[i]);
exit(1);
}
}
param[j]='\0';
由上面我们所知num记录的是参数中‘-’的数量,因此如果num+1==argc,那说明用户所输入的命令行参数不包含目录或文件名。只是显示当前目录下的文件。因为这是我们必须自动将path赋值为当前目录。为了使其称为一个字符串,必须在末尾加‘\0’。然后进入display_dir函数。实现代码如下:
//print the information of current directory if the command without the name of target file and current directory
if((num+1)==argc)
{
strcpy(path,"./");
path[2]='\0';
display_dir(flag_param,path);
return 0;
}
如果命令行参数包含目录或者文件名,那么我们要检查其合法性(参数中的目录或者文件是否存在)。这里我们利用stat族函数来获取文件的属性,实现上述功能。stat族函数通常有两个参数:文件路径/文件描述符,struct stat *buf类型的结构体。如果操作成功,那么buf将保存文件的属性。若合法,利用宏S_ISDIR(buf.st_mode);判断此文件是否为目录文件。若为目录文件则进入display_dir函数,否则进入display函数。通常情况,display_dir函数是获取path目录下所有文件的完整路径名,在使每个文件执行dsiplay函数。因此如果参数中是指定的文件名,则可绕过display_dir函数,直接进入display函数。
i=1;
do
{
//the current argument doesn't comprise the target file name and dirctory name
if(argv[i][0]=='-')
{
i++;
continue;
}
else
{
strcpy(path,argv[i]);
//detect if the "path" exsit
if(stat(path,&buf)==-1)
{
my_err("stat",errno,__LINE__);
}
//detect the "path" is a file or a directory
if(S_ISDIR(buf.st_mode))
{
//directory
//detect if the last character of the "path" is '/'
if(path[strlen(path)-1]=='/')
{
path[strlen(path)]=='\0';
}
else
{
path[strlen(path)]='/';
path[strlen(path)]='\0';
}
display_dir(flag_param,path);
i++;
}
else
{
//file
display(flag_param,path);
i++;
}
}
}while(i<\argc);