/* Name: list.c Author: guozan _SCS_BUPT Mail: guozan523@foxmail.com Date: 2010/4/6 实验目的:练习vi,使用UNIX的系统调用和库函数,体会UNIX文件通配符的处理方式以及命令对选项的处理方式。 编程实现程序list.c,列表普通磁盘文件(不考虑目录和设备文件等),列出文件名和文件大小。 与ls命令类似,命令行参数可以有0到多个 0个参数:列出当前目录下所有文件 参数为普通文件:列出文件 参数为目录:列出目录下所有文件 实现自定义选项r,a,l,h,m以及-- r 递归方式列出子目录 a 列出文件名第一个字符为圆点的普通文件(默认情况下不列出文件名首字符为圆点的文件) l 后跟一整数,限定文件大小的最小值(字节) h 后跟一整数,限定文件大小的最大值(字节) m 后跟一整数n,限定文件的最近修改时间必须在n天内 -- 显式地终止命令选项分析 */ #include <sys/stat.h> #include <sys/types.h> #include <dirent.h> #include <unistd.h> #include <stdio.h> #include <string.h> /* slective options about ls rflag is about recursive aflag is about ones with . infront lflag is about the minimum size hflag is about the maximum size mflag is about the modified time */ int rflag, aflag, lflag, hflag, mflag; long modified_time; //the last time file be modified, days ago off_t lower_size; //file's minimum size off_t upper_size; //file's maximum size /* set the flags, thus the ls option */ void getoptions(int argc, char *argv[]) { char ch; //clear, all unseted rflag = 0; aflag = 0; lflag = 0; hflag = 0; mflag = 0; //use getopt to get the options, want to know more, call man //the last one or after -- was set in argv[optind] while ((ch = getopt(argc, argv, "ral:h:m:")) != -1) { switch (ch) { case 'r': rflag = 1; break; case 'a': aflag = 1; break; case 'l': lflag = 1; lower_size = atol(optarg); break; case 'h': hflag = 1; upper_size = atol(optarg); break; case 'm': mflag = 1; modified_time = atol(optarg); break; //get days case '?': printf("Unknown option: %c/n", (char)optopt); break; default : printf("Step into default/n"); break; } } } /* the function to list things in path */ int ls(char *path) { struct stat st; //for check this is a directory or file char temp[100]; //if path is null, it is used to get current directory // get the path if (path == NULL || path[0] == '-') { path = temp; getcwd(path, 100); } /* open the inode of file */ if (lstat(path, &st)) { fprintf(stderr, "Error: %s not exist./n", path); return (-1); } /* judge whether the file is a file or a directory */ if (S_ISDIR(st.st_mode)) { ls_dir(path); } else if (S_ISREG(st.st_mode)) { print(path); } else { printf("Not ordinary file, wouldn't be listed./n"); } return 0; } /* list dirs, may recursively or not, depending on rflag one thing is sure that it will list directories and files first, then consider the things in the directories */ int ls_dir(char *path) { DIR *dp = NULL; struct dirent *dirp = NULL; if (path[0] != '.' || (path[0] == '.' && aflag == 1)) { printf("/n%s:/n****************************************/n", path); /* open the directory */ if ((dp = opendir(path)) == NULL) { fprintf(stderr, "Error: can't open directory %s!/n", path); return (-1); } chdir(path); /* list all the things in directory */ while ((dirp = readdir(dp)) != NULL) { print(dirp->d_name); } /* recursively ls dirs, after ls things together, it's time to list things in children directory */ if (rflag == 1) { rewinddir(dp); //reset dp while ((dirp = readdir(dp)) != NULL) { if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0) { //no current and parent directory continue; } ls_dir_r(dirp->d_name); //only list directories, judged inside the function } } /* close the directory */ if (closedir(dp)) { fprintf(stderr, "Error: can't close the directory %s!/n", path); return -1; } chdir(".."); } return 0; } /* list directories recursively, only directories, nomatter what path you put in */ int ls_dir_r(char *path) { struct stat st; /* open the inode of file */ if (lstat(path, &st)) { fprintf(stderr, "Error: %s not exist./n", path); return (-1); } /* only ls directories */ if (S_ISDIR(st.st_mode)) { ls_dir(path); } } /* print the filetype/size/name on the screen */ int print(char *path) { struct stat st; time_t tp; char *filename = NULL; //get current time time(&tp); if (lstat(path, &st)) { fprintf(stderr, "Error: %s can't be opened./n", path); return (-1); } /* get file name */ if ((filename = strrchr(path, '/')) != NULL) { filename++; } else { filename = path; } /* judge whether to list the file */ if ((S_ISDIR(st.st_mode)|| S_ISREG(st.st_mode)) //only directories and normal files && (lflag == 0 || (lflag == 1 && (st.st_size >= lower_size))) //the min size && (hflag == 0 || (hflag == 1 && (st.st_size <= upper_size))) //the max size && (mflag == 0 || (mflag == 1 && ((tp - st.st_mtime) <= modified_time * 24 * 60 * 60))) //modified time && (aflag == 1 || (aflag == 0 && filename[0] != '.')) //file with a '.' infront ) { printf("%s/t%10ld/t%s/n", (S_ISDIR(st.st_mode) ? "DIR": "FILE"), st.st_size, filename); } return 0; } /* The main function */ int main(int argc, char *argv[]) { getoptions(argc, argv); ls(argv[optind]); return 0; }