Ls command implementation, ls command implementation
In linux, the most commonly used command should be ls. Have you ever wondered how to implement this command? In fact, it is not difficult to understand the interfaces related to the UNIX environment ~
Objectives:
You can use ls to list the brief information of a directory, and ls-l to list the detailed information of a directory. By default, information under the current working directory is listed. You can specify a directory through parameters to list information of multiple directories at the same time.
Implementation:
There are many implementation methods, as long as they can be made in a good style, I will briefly talk about my own ideas.
1. Use the is_detail variable to record whether to list the file details. initpath indicates the directory path to be read.
2. If you do not specify a directory, set the path to the current working directory, obtain all files in the directory, sort the files, and then output the files in brief or in detail. End the program.
3. When the user provides directory parameters, determine whether detailed output is required and set the is_detail variable.
4. For each DIRECTORY parameter specified by each user, the system cyclically obtains all file names in the directory, sorts them, and prints Information Based on is_detail.
The idea is so simple that you only need to process the details of each module.
The main auxiliary functions are:
GetWidth gets the terminal width, which is used to determine the number of columns that can be put down in a simple output file name.
Get_dir_detail: Get all file names in the specified directory.
GetPermission obtains the object permission information based on the object permission bit st_mode, which is represented by a string.
Print_file_info outputs the file information based on the file pointer.
Search_file_info traverses all files in the processing Directory.
Init processes files and directories separately.
Print_simple only outputs the file name, that is, simple display
Code:
# Include <stdio. h> # include <dirent. h> # include <stdlib. h> # include <libgen. h> # include <sys/stat. h> # include <string. h> # include <time. h> # include <pwd. h> # include <grp. h> # include <sys/ioctl. h> # include <unistd. h> # define MAX_FILE 1000/* save the file name and directory */typedef struct item {char d_name [256]; char dir_name [256];} file_item; file_item files [MAX_FILE];/* save file information */typedef struct item_info {unsigned int I _node; char pe Rmission [16]; short owner; short group; off_t size; time_t mod_time; nlink_t link_num; char name [256];} info; int is_detail; int size_of_path; int terminalWidth; /* Get the username */const char * uid_to_name (short uid) {structpasswd * pw_ptr; if (pw_ptr = getpwuid (uid) = NULL) return "Unknown "; elsereturn pw_ptr-> pw_name;}/* obtain the group name */const char * gid_to_name (short gid) {struct group * grp_ptr; if (grp_ptr = Getgrgid (gid) = NULL) return "Unknown"; elsereturn grp_ptr-> gr_name;}/* comparison function */int cmp (const void *, const void * B) {return strcasecmp (* (file_item *) ). d_name, (* (file_item *) B ). d_name);}/* Get terminal width */void getWidth () {struct winsize wbuf; terminalWidth = 80; if (isatty (STDOUT_FILENO) {if (ioctl (STDOUT_FILENO, TIOCGWINSZ, & wbuf) =-1 | wbuf. ws_col = 0) {char * tp; if (tp = getenv ("COLUMNS ")) TerminalWidth = atoi (tp);} else terminalWidth = wbuf. ws_col;} return;}/* Get all file names */void get_dir_detail (const char * dirname) {DIR * dir; struct dirent * drt; int cur = 0; /* Open the directory */dir = opendir (dirname); if (dir = NULL) {perror ("Read directroy Error. "); return;}/* traverse directory */while (drt = readdir (dir ))! = NULL) {file_item * cur_node = files + cur;/* ignore. and .. directory */if (strcmp (drt-> d_name ,". ") = 0) | (strcmp (drt-> d_name ,".. ") = 0) continue; if (drt-> d_name [0] = '. ') continue; size_of_path ++; cur ++; if (cur> = MAX_FILE) {printf ("Too program files! \ N "); exit (-1);}/* file name */strcpy (cur_node-> d_name, drt-> d_name ); /* directory name */strcpy (cur_node-> dir_name, dirname); strcat (cur_node-> dir_name, drt-> d_name);} closedir (dir );} /* Get file permissions */void getPermission (mode_t st_mode, char * permission) {/* initialize 111000000 */unsigned int mask = 0700; static const char * perm [] = {"---", "-- x", "-w-", "-wx", "r --", "r-x ", "rw-", "rwx"}; char type; if (S_ISREG (st_mode) type = '-'; else If (S_ISDIR (st_mode) type = 'D'; else if (S_ISCHR (st_mode) type = 'C'; else if (S_ISLNK (st_mode )) type = 'l'; else type = '? '; Permission [0] = type;/* computing permission */int I = 3; char * ptr = permission + 1; while (I> 0) {* ptr ++ = perm [(st_mode & mask)> (I-1) * 3] [0]; * ptr ++ = perm [(st_mode & mask)> (I-1) * 3] [1]; * ptr ++ = perm [(st_mode & mask)> (I-1) * 3] [2]; I --; mask >>=3 ;}/ * output file information */void print_file_info (info * file_info) {/* format conversion */unsigned fsize = file_info-> size; char ftime [64]; strcpy (ftime, ctime (& file_info-> mod_time); ftime [strle N (ftime)-1] = '\ 0'; int I = 8; printf ("% 10 s", file_info-> permission); printf ("% 3i ", file_info-> link_num); printf ("% 14 s", uid_to_name (file_info-> owner); printf ("% 14 s", gid_to_name (file_info-> group )); printf ("% 8u", fsize); printf ("% 26 s", ftime); printf ("% s \ n", file_info-> name );} /* traverse and process all files */void search_file_info () {struct stat file_stat; int cur = 0; info file_info;/* traverse the file */while (cur <size_of_pat H) {file_item * cur_node = files + cur; memset (file_info.permission, '\ 0', sizeof (file_info.permission); if (stat (cur_node-> dir_name, & file_stat) =-1) {perror ("Can't get the information of the file. \ n "); continue;}/* Get the File Permission */getPermission (file_stat.st_mode, file_info.permission);/* User ID and group ID */file_info.owner = file_stat.st_uid; file_info.group = metadata; /* modification time */file_info.mod_time = Bytes;/* file size */file_info.size = file_stat.st_size;/* I-node number */file_info. I _node = file_stat.st_ino;/* Number of links */file_info.link_num = file_stat.st_nlink; /* copy the file name */strcpy (file_info.name, cur_node-> d_name);/* print the file information */print_file_info (& file_info); cur ++ ;}} /* processing based on whether the initial path is a file or a directory */void init (char * pathname) {size_of_path = 0; struct stat file_stat; if (stat (pathname, & file_stat) =-1) {perror ("Can't get the information of the given path. \ n "); return;}/* Common File */if (S_ISREG (file_stat.st_mode) {size_of_path = 1; char * base_name = basename (pathname ); strcpy (files [0]. d_name, base_name); strcpy (files [0]. dir_name, pathname); return;}/* directory file */if (S_ISDIR (file_stat.st_mode) {/* unified directory format */if (pathname [strlen (pathname) -1]! = '/') {Char * ptr = pathname + strlen (pathname); * ptr ++ = '/'; * ptr = 0;} get_dir_detail (pathname ); return ;}} void print_simple () {int max_len = 0; int num_in_row = 0; int num_in_col = 0; getWidth (); /* obtain the maximum file name length */int I = 1; max_len = strlen (files [0]. d_name); while (I <size_of_path) {int cur_len = strlen (files [I]. d_name); max_len = max_len> cur_len? Max_len: cur_len; I ++;} max_len + = 2;/* calculate the number of rows and the number of each column */num_in_row = terminalWidth/max_len; if (size_of_path % num_in_row = 0) num_in_col = values/num_in_row; else num_in_col = size_of_path/num_in_row + 1; I = 0; while (I <num_in_col) {int j; for (j = 0; j <num_in_row; ++ j) {file_item * cur = files + I + j * num_in_col; printf ("%-* s", max_len, cur-> d_name );} printf ("\ n"); I ++ ;}} int main (int ar Gc, char * argv []) {is_detail = 0;/* set the initial path */char initpath [256]; if (argc = 1 | (argc = 2 & strcmp (argv [1], "-l") = 0) {strcpy (initpath ,". /");/* Get all files in the directory */init (initpath); qsort (files, size_of_path, sizeof (files [0]), cmp ); /* print the information of each file */if (argc = 1) print_simple (); else search_file_info (); exit (0);} int I = 1; if (argc> 2 & strcmp (argv [1], "-l") = 0) {I ++; is_detail = 1 ;}int flag = 1; while (I <argc) {if (! Flag) printf ("\ n"); flag = 0; strcpy (initpath, argv [I]);/* Get all files in the directory */init (initpath ); if (size_of_path = 0) {perror ("usage error \ n"); exit (-1);} qsort (files, size_of_path, sizeof (files [0]), cmp); if (is_detail) {/* print the information of each file */search_file_info ();} else {/* print the brief information */print_simple ();} I ++ ;} return 0 ;}
Paste one: