/* 類比ls命令,實現參數-tariRl.有些代碼重複出現,可改進 可以在該程式的基礎上增加參數,該程式思路清晰,容易擴充 */#include<stdio.h>#include<string.h>#include<stdlib.h>#include<sys/types.h>#include<unistd.h>#include<sys/stat.h>#include<dirent.h>#include<sys/ioctl.h>#include<pwd.h>#include<grp.h>#define LL (1<<0) /*帶l參數標誌*/#define IL (1<<1) /*帶i參數標誌*/#define RU (1<<2) /*帶R參數標誌*/#define TL (1<<16) /*帶t參數標誌*/#define AL (1<<17) /*帶a參數標誌*/#define RL (1<<18) /*帶r參數標誌*/#define LENGTH 500 /*字串最大長度*/#define MAX_FILE_COUNT 500/*檔案清單最大長度*//*函式宣告*/void error(char* error_message,int line);void display(struct stat* stalist,char (*namelist)[LENGTH],int n,int mode);int file_list(char* path,struct stat* stalist,char (*namelist)[LENGTH],int mode);void display_simply(char (*namelist)[LENGTH],int n);void display_LL(struct stat * stalist,char (*namelist)[LENGTH],int n);void display_IL(struct stat * stalist,char (*namelist)[LENGTH],int n);void display_LL_IL(struct stat * stalist,char (*namelist)[LENGTH],int n);void display_RU(struct stat* stalist,char (*namelist)[LENGTH],int n,int mode);void display_RU_LL(struct stat * stalist,char (*namelist)[LENGTH],int n,int mode);void display_RU_IL(struct stat* stalist,char (*namelist)[LENGTH],int n,int mode);void display_RU_IL_LL(struct stat * stalist,char (*namelist)[LENGTH],int n,int mode);/*主函數*/int main(int argc,char **argv){ int i,j; /*mode的前16個位用來標誌那些能影響顯示的參數,16位之後的位用來標誌不影響輸出格式的參數。這個程式只用到了0-3位,16-18位,如果要在該程式的基礎上增加參數,可以用其他沒有使用的位。 mode的第0位為1表示帶l參數,mode的第1位為1表示帶i參數,mode的第2位為1表示帶R參數,mode的第16位為1表示帶t參數,mode的第17位為1表示帶a參數,mode的第18位為1表示帶r參數*/ int mode=0; char error_message[LENGTH]={0};/*錯誤資訊*/ char path[LENGTH]={0};/*路徑*/ struct stat stalist[MAX_FILE_COUNT];/*檔案詳細資料數組*/ char namelist[MAX_FILE_COUNT][LENGTH];/*檔案名稱數組*/ int flag=0;/*判斷是否指定了目錄*/ int count;/*檔案個數*/ /*解析參數*/ for(i=1;i<argc;i++){ if(argv[i][0]=='-'){/*如果是選項參數*/ for(j=1;j<strlen(argv[i]);j++){if(argv[i][j]=='l') mode=mode|LL;else if(argv[i][j]=='i') mode=mode|IL;else if(argv[i][j]=='R') mode=mode|RU;else if(argv[i][j]=='r') mode=mode|RL;else if(argv[i][j]=='a') mode=mode|AL;else if(argv[i][j]=='t') mode=mode|TL;else{ snprintf(error_message,LENGTH,"no option of %c",argv[i][j]); error(error_message,__LINE__);} }}else{/*參數為目錄或檔案*/ if(flag==1)error("can not specify more then two dir or file",__LINE__); elseflag=1; if(argv[i][0]!='/'){/*相對路徑*/strcat(path,get_current_dir_name());strcat(path,"/");strncat(path,argv[i],strlen(argv[i])); }else/*絕對路徑*/strcpy(path,argv[i]);} } if(flag==0)/*未指定任何目錄或檔案,則使用預設目前的目錄*/strcat(path,get_current_dir_name()); /*根據mode擷取指定目錄下的檔案*/ count=file_list(path,stalist,namelist,mode); /*根據mode顯示檔案*/ display(stalist,namelist,count,mode); return 0;}/*擷取檔案清單*/int file_list(char* path,struct stat* stalist,char (*namelist)[LENGTH],int mode){ int i=0,index,j,k; DIR *dir; struct dirent *ptr; char str[LENGTH]; char nametemp[LENGTH]; struct stat statemp; if(stat(path,&stalist[0])<0){//puts(path);error("the specify file is not exist",__LINE__); } if(S_ISDIR(stalist[0].st_mode)){/*如果該路徑指向的是一個目錄*/ if((dir=opendir(path))==NULL){/*開啟目錄*/ sprintf(str,"can not open %s",path); error(str,__LINE__);} chdir(path);/*改變當前工作目錄到path*/ i=0;while((ptr=readdir(dir))!=NULL){/*依次讀取目錄下的所有檔案*/ if(ptr->d_name[0]=='.' && !(mode & AL))/*忽略隱藏檔案*/continue; /*按字母順序插入到stalist數組及namelist數組*/ for(j=i;j>0;j--){if(strcmp(ptr->d_name,namelist[j-1])>0) break; } for(k=i;k>j;k--){strcpy(namelist[k],namelist[k-1]);stalist[k]=stalist[k-1]; } strcpy(namelist[j],ptr->d_name); stat(ptr->d_name,&stalist[j]); i++; if(i==MAX_FILE_COUNT)error("file count beyond MAX_FILE_COUNT",__LINE__);}closedir(dir); }else{j=strlen(path)-1;while(j>=0 && path[j]!='/'){ j--;}if(j<0) error("path error",__LINE__);j++;k=0; while(path[j]){ namelist[0][k]=path[j]; j++; k++;} namelist[0][k]=0; return 1; } if(mode & TL){/*按檔案修改時間排序*/for(j=0;j<i;j++){ index=j; for(k=j+1;k<i;k++)if(stalist[index].st_mtime<stalist[k].st_mtime){ index=k;} statemp=stalist[j]; stalist[j]=stalist[index]; stalist[index]=statemp; strcpy(nametemp,namelist[j]); strcpy(namelist[j],namelist[index]); strcpy(namelist[index],nametemp);} } if(mode & RL){/*反序排列*/for(j=0;j<i/2;j++){ strcpy(nametemp,namelist[j]); strcpy(namelist[j],namelist[i-j-1]); strcpy(namelist[i-j-1],nametemp); statemp=stalist[j]; stalist[j]=stalist[i-j-1]; stalist[i-j-1]=statemp;} } return i;}/*根據mode選擇不同的函數進行顯示*/void display(struct stat* stalist,char (*namelist)[LENGTH],int n,int mode){ /*使mode的高16位為0*/ int m = mode & ((1<<16)-1); switch(m){case 0: display_simply(namelist,n); break;case 1: display_LL(stalist,namelist,n); break;case 2: display_IL(stalist,namelist,n); break;case 3: display_LL_IL(stalist,namelist,n); break;case 4: display_RU(stalist,namelist,n,mode); break;case 5: display_RU_LL(stalist,namelist,n,mode); break; case 6: display_RU_IL(stalist,namelist,n,mode); break;case 7: display_RU_IL_LL(stalist,namelist,n,mode); break; }}/*不帶顯示選項,簡單顯示檔案名稱*/void display_simply(char (*namelist)[LENGTH],int n){ int i,maxlength=0,cols; struct winsize ts; for(i=0;i<n;i++)if(strlen(namelist[i])>maxlength) maxlength=strlen(namelist[i]); /*擷取終端的大小*/ ioctl(STDIN_FILENO,TIOCGWINSZ,&ts); cols=ts.ws_col; cols/=(maxlength+1); //lines=ts.ws_row; for(i=0;i<n;i++){ if(i!=0 && i%cols==0) puts(""); printf("%*s",-(maxlength+1),namelist[i]); } putchar('\n');}/*-l 參數,顯示詳細檔案資訊*/void display_LL(struct stat * stalist,char (*namelist)[LENGTH],int n){ int i,mode; char* str; for(i=0;i<n;i++){ mode=stalist[i].st_mode; if(S_ISDIR(mode)) printf("d");else printf("-");if(mode & (1<<8)) printf("r");else printf("-"); if(mode & (1<<7)) printf("w");else printf("-"); if(mode & (1<<6)) printf("x");else printf("-"); if(mode & (1<<5)) printf("r");else printf("-"); if(mode & (1<<4)) printf("w");else printf("-"); if(mode & (1<<3)) printf("x");else printf("-"); if(mode & (1<<2)) printf("r");else printf("-"); if(mode & (1<<1)) printf("w");else printf("-"); if(mode & (1<<0)) printf("x");else printf("-");printf(" %-3d",stalist[i].st_nlink);printf(" %-6s",getpwuid(stalist[i].st_uid)->pw_name);printf(" %-6s",getgrgid(stalist[i].st_gid)->gr_name);printf(" %-10d",stalist[i].st_size);str=ctime(&stalist[i].st_mtime);str[strlen(str)-2]=0;printf(" %s",str);printf(" %s\n",namelist[i]); }}/*-i 參數,顯示檔案名稱及節點號*/void display_IL(struct stat* stalist,char (*namelist)[LENGTH],int n){ int i,maxlength=0,cols; struct winsize ts; for(i=0;i<n;i++)if(strlen(namelist[i])>maxlength) maxlength=strlen(namelist[i]); /*擷取終端的大小*/ ioctl(STDIN_FILENO,TIOCGWINSZ,&ts); cols=ts.ws_col; cols/=(maxlength+9); //lines=ts.ws_row; for(i=0;i<n;i++){ if(i!=0 && i%cols==0) puts(""); printf("%-8d ",stalist[i].st_ino); printf("%*s",-(maxlength+1),namelist[i]); } putchar('\n'); }/*-li 參數,顯示詳細檔案資訊和節點號*/void display_LL_IL(struct stat * stalist,char (*namelist)[LENGTH],int n){ int i,mode; char* str; for(i=0;i<n;i++){ printf("%-8d ",stalist[i].st_ino); mode=stalist[i].st_mode; if(S_ISDIR(mode)) printf("d");else printf("-");if(mode & (1<<8)) printf("r");else printf("-"); if(mode & (1<<7)) printf("w");else printf("-"); if(mode & (1<<6)) printf("x");else printf("-"); if(mode & (1<<5)) printf("r");else printf("-"); if(mode & (1<<4)) printf("w");else printf("-"); if(mode & (1<<3)) printf("x");else printf("-"); if(mode & (1<<2)) printf("r");else printf("-"); if(mode & (1<<1)) printf("w");else printf("-"); if(mode & (1<<0)) printf("x");else printf("-");printf(" %-3d",stalist[i].st_nlink);printf(" %-6s",getpwuid(stalist[i].st_uid)->pw_name);printf(" %-6s",getgrgid(stalist[i].st_gid)->gr_name);printf(" %-10d",stalist[i].st_size);str=ctime(&stalist[i].st_mtime);str[strlen(str)-2]=0;printf(" %s",str);printf(" %s\n",namelist[i]); }}/*-R 參數,簡單顯示所有檔案,包括目錄下面的子目錄*/void display_RU(struct stat* stalist,char (*namelist)[LENGTH],int n,int mode){ int i,count; char path[LENGTH]={0},temp[LENGTH]={0}; struct stat sta[MAX_FILE_COUNT]; char name[MAX_FILE_COUNT][LENGTH]; puts(get_current_dir_name()); display_simply(namelist,n); putchar('\n'); strcpy(path,get_current_dir_name()); for(i=0;i<n;i++){ if(strcmp(namelist[i],".")==0 || strcmp(namelist[i],"..")==0) continue;if(S_ISDIR(stalist[i].st_mode)){ strcpy(temp,path); strcat(path,"/"); strcat(path,namelist[i]); count=file_list(path,sta,name,mode); display_RU(sta,name,count,mode); strcpy(path,temp);} }}/*-Rl 參數,顯示所有檔案,包括目錄下面的子目錄的詳細資料*/void display_RU_LL(struct stat * stalist,char (*namelist)[LENGTH],int n,int mode){ int i,count; char path[LENGTH]={0},temp[LENGTH]={0}; struct stat sta[MAX_FILE_COUNT]; char name[MAX_FILE_COUNT][LENGTH]; puts(get_current_dir_name()); display_LL(stalist,namelist,n); putchar('\n'); strcpy(path,get_current_dir_name()); for(i=0;i<n;i++){if(strcmp(namelist[i],".")==0 || strcmp(namelist[i],"..")==0) continue;if(S_ISDIR(stalist[i].st_mode)){ strcpy(temp,path); strcat(path,"/"); strcat(path,namelist[i]); count=file_list(path,sta,name,mode); display_RU_LL(sta,name,count,mode); strcpy(path,temp);} }}/*-Ri 參數,簡單顯示所有檔案,包括目錄下的子目錄,及節點號*/void display_RU_IL(struct stat* stalist,char (*namelist)[LENGTH],int n,int mode){ int i,count; char path[LENGTH]={0},temp[LENGTH]={0}; struct stat sta[MAX_FILE_COUNT]; char name[MAX_FILE_COUNT][LENGTH]; puts(get_current_dir_name()); display_IL(stalist,namelist,n); putchar('\n'); strcpy(path,get_current_dir_name()); for(i=0;i<n;i++){if(strcmp(namelist[i],".")==0 || strcmp(namelist[i],"..")==0) continue;if(S_ISDIR(stalist[i].st_mode)){ strcpy(temp,path); strcat(path,"/"); strcat(path,namelist[i]); count=file_list(path,sta,name,mode); display_RU_IL(sta,name,count,mode); strcpy(path,temp);} }}/*-Ril 參數,顯示所有檔案,包括目錄下面的子目錄的詳細資料,及節點號*/void display_RU_IL_LL(struct stat * stalist,char (*namelist)[LENGTH],int n,int mode){ int i,count; char path[LENGTH]={0},temp[LENGTH]={0}; struct stat sta[MAX_FILE_COUNT]; char name[MAX_FILE_COUNT][LENGTH]; puts(get_current_dir_name()); display_LL_IL(stalist,namelist,n); putchar('\n'); strcpy(path,get_current_dir_name()); for(i=0;i<n;i++){if(strcmp(namelist[i],".")==0 || strcmp(namelist[i],"..")==0) continue;if(S_ISDIR(stalist[i].st_mode)){ strcpy(temp,path); strcat(path,"/"); strcat(path,namelist[i]); count=file_list(path,sta,name,mode); display_RU_IL_LL(sta,name,count,mode); strcpy(path,temp);} }}//錯誤處理函數void error(char* error_message,int line){ char str[5]; sprintf(str,"%d:",line); strcat(str,error_message); perror(str); exit(EXIT_FAILURE);}