在本文上部分中,主要陈述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);