implement -R
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@10561 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
		| @@ -1,5 +1,5 @@ | |||||||
| /* | /* | ||||||
|  * Copyright (c) 1999 - 2000 Kungliga Tekniska H<>gskolan |  * Copyright (c) 1999 - 2001 Kungliga Tekniska H<>gskolan | ||||||
|  * (Royal Institute of Technology, Stockholm, Sweden).  |  * (Royal Institute of Technology, Stockholm, Sweden).  | ||||||
|  * All rights reserved.  |  * All rights reserved.  | ||||||
|  * |  * | ||||||
| @@ -49,14 +49,21 @@ RCSID("$Id$"); | |||||||
|  |  | ||||||
| #define sec_fprintf2 fprintf | #define sec_fprintf2 fprintf | ||||||
| #define sec_fflush fflush | #define sec_fflush fflush | ||||||
| void | static void list_files(FILE *out, const char **files, int n_files, int flags); | ||||||
| builtin_ls(FILE *out, const char *file); | static int parse_flags(const char *options); | ||||||
|  |  | ||||||
| int | int | ||||||
| main(int argc, char **argv) | main(int argc, char **argv) | ||||||
| { | { | ||||||
|     int i; |     int i = 1; | ||||||
|     for(i = 1; i < argc; i++) |     int flags; | ||||||
| 	builtin_ls(stdout, argv[i]); |     if(argc > 1 && argv[1][0] == '-') { | ||||||
|  | 	flags = parse_flags(argv[1]); | ||||||
|  | 	i = 2; | ||||||
|  |     } else | ||||||
|  | 	flags = parse_flags(NULL); | ||||||
|  |  | ||||||
|  |     list_files(stdout, (const char **)argv + i, argc - i, flags); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| @@ -107,7 +114,10 @@ free_fileinfo(struct fileinfo *f) | |||||||
| #define LS_DISP_LONG	(1 << 8) | #define LS_DISP_LONG	(1 << 8) | ||||||
| #define LS_DISP_COLUMN	(2 << 8) | #define LS_DISP_COLUMN	(2 << 8) | ||||||
| #define LS_DISP_CROSS	(3 << 8) | #define LS_DISP_CROSS	(3 << 8) | ||||||
| #define LS_IGNORE_DOTDIR (1 << 10) | #define LS_SHOW_ALL	(1 << 10) | ||||||
|  | #define LS_RECURSIVE	(1 << 11) | ||||||
|  | #define LS_EXTRA_BLANK	(1 << 12) | ||||||
|  | #define LS_SHOW_DIRNAME	(1 << 13) | ||||||
|  |  | ||||||
| #ifndef S_ISTXT | #ifndef S_ISTXT | ||||||
| #define S_ISTXT S_ISVTX | #define S_ISTXT S_ISVTX | ||||||
| @@ -121,19 +131,25 @@ free_fileinfo(struct fileinfo *f) | |||||||
| #define S_ISLNK(mode)   (((mode) & _S_IFMT) == S_IFLNK) | #define S_ISLNK(mode)   (((mode) & _S_IFMT) == S_IFLNK) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | static size_t | ||||||
|  | block_convert(size_t blocks) | ||||||
|  | { | ||||||
|  | #ifdef S_BLKSIZE | ||||||
|  |     return blocks * S_BLKSIZE / 1024; | ||||||
|  | #else | ||||||
|  |     return blocks * 512 / 1024; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| make_fileinfo(const char *filename, struct fileinfo *file, int flags) | make_fileinfo(FILE *out, const char *filename, struct fileinfo *file, int flags) | ||||||
| { | { | ||||||
|     char buf[128]; |     char buf[128]; | ||||||
|     int file_type = 0; |     int file_type = 0; | ||||||
|     struct stat *st = &file->st; |     struct stat *st = &file->st; | ||||||
|  |  | ||||||
|     file->inode = st->st_ino; |     file->inode = st->st_ino; | ||||||
| #ifdef S_BLKSIZE |     file->bsize = block_convert(st->st_blocks); | ||||||
|     file->bsize = st->st_blocks * S_BLKSIZE / 1024; |  | ||||||
| #else |  | ||||||
|     file->bsize = st->st_blocks * 512 / 1024; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     if(S_ISDIR(st->st_mode)) { |     if(S_ISDIR(st->st_mode)) { | ||||||
| 	file->mode[0] = 'd'; | 	file->mode[0] = 'd'; | ||||||
| @@ -252,7 +268,7 @@ make_fileinfo(const char *filename, struct fileinfo *file, int flags) | |||||||
| 	    buf[n] = '\0'; | 	    buf[n] = '\0'; | ||||||
| 	    file->link = strdup(buf); | 	    file->link = strdup(buf); | ||||||
| 	} else | 	} else | ||||||
| 	    warn("%s: readlink", filename); | 	    sec_fprintf2(out, "readlink(%s): %s", filename, strerror(errno)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -449,6 +465,12 @@ list_files(FILE *out, const char **files, int n_files, int flags) | |||||||
| { | { | ||||||
|     struct fileinfo *fi; |     struct fileinfo *fi; | ||||||
|     int i; |     int i; | ||||||
|  |     int *dirs = NULL; | ||||||
|  |     size_t total_blocks = 0; | ||||||
|  |     int n_print = 0; | ||||||
|  |  | ||||||
|  |     if(n_files > 1) | ||||||
|  | 	flags |= LS_SHOW_DIRNAME; | ||||||
|  |  | ||||||
|     fi = calloc(n_files, sizeof(*fi)); |     fi = calloc(n_files, sizeof(*fi)); | ||||||
|     if (fi == NULL) { |     if (fi == NULL) { | ||||||
| @@ -460,12 +482,23 @@ list_files(FILE *out, const char **files, int n_files, int flags) | |||||||
| 	    sec_fprintf2(out, "%s: %s\r\n", files[i], strerror(errno)); | 	    sec_fprintf2(out, "%s: %s\r\n", files[i], strerror(errno)); | ||||||
| 	    fi[i].filename = NULL; | 	    fi[i].filename = NULL; | ||||||
| 	} else { | 	} else { | ||||||
| 	    if((flags & LS_DIRS) == 0 && S_ISDIR(fi[i].st.st_mode)) { | 	    int include_in_list = 1; | ||||||
| 		if(n_files > 1) | 	    total_blocks += block_convert(fi[i].st.st_blocks); | ||||||
| 		    sec_fprintf2(out, "%s:\r\n", files[i]); | 	    if(S_ISDIR(fi[i].st.st_mode)) { | ||||||
| 		list_dir(out, files[i], flags); | 		if(dirs == NULL) | ||||||
| 	    } else { | 		    dirs = calloc(n_files, sizeof(*dirs)); | ||||||
| 		make_fileinfo(files[i], &fi[i], flags); | 		if(dirs == NULL) { | ||||||
|  | 		    sec_fprintf2(out, "%s: %s\r\n",  | ||||||
|  | 				 files[i], strerror(errno)); | ||||||
|  | 		    goto out; | ||||||
|  | 		} | ||||||
|  | 		dirs[i] = 1; | ||||||
|  | 		if((flags & LS_DIRS) == 0) | ||||||
|  | 		    include_in_list = 0; | ||||||
|  | 	    } | ||||||
|  | 	    if(include_in_list) { | ||||||
|  | 		make_fileinfo(out, files[i], &fi[i], flags); | ||||||
|  | 		n_print++; | ||||||
| 	    } | 	    } | ||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
| @@ -523,6 +556,8 @@ list_files(FILE *out, const char **files, int n_files, int flags) | |||||||
| 	max_bsize = log10(max_bsize); | 	max_bsize = log10(max_bsize); | ||||||
| 	max_n_link = log10(max_n_link); | 	max_n_link = log10(max_n_link); | ||||||
| 	 | 	 | ||||||
|  | 	if(n_print > 0) | ||||||
|  | 	    sec_fprintf2(out, "total %lu\r\n", (unsigned long)total_blocks); | ||||||
| 	if(flags & LS_SORT_REVERSE) | 	if(flags & LS_SORT_REVERSE) | ||||||
| 	    for(i = n_files - 1; i >= 0; i--) | 	    for(i = n_files - 1; i >= 0; i--) | ||||||
| 		print_file(out, | 		print_file(out, | ||||||
| @@ -554,6 +589,7 @@ list_files(FILE *out, const char **files, int n_files, int flags) | |||||||
|     } else if(DISP_MODE(flags) == LS_DISP_COLUMN ||  |     } else if(DISP_MODE(flags) == LS_DISP_COLUMN ||  | ||||||
| 	      DISP_MODE(flags) == LS_DISP_CROSS) { | 	      DISP_MODE(flags) == LS_DISP_CROSS) { | ||||||
| 	int max_len = 0; | 	int max_len = 0; | ||||||
|  | 	int size_len = 0; | ||||||
| 	int num_files = n_files; | 	int num_files = n_files; | ||||||
| 	int columns; | 	int columns; | ||||||
| 	int j; | 	int j; | ||||||
| @@ -564,14 +600,30 @@ list_files(FILE *out, const char **files, int n_files, int flags) | |||||||
| 	    } | 	    } | ||||||
| 	    if(strlen(fi[i].filename) > max_len) | 	    if(strlen(fi[i].filename) > max_len) | ||||||
| 		max_len = strlen(fi[i].filename); | 		max_len = strlen(fi[i].filename); | ||||||
|  | 	    if(log10(fi[i].bsize) > size_len) | ||||||
|  | 		size_len = log10(fi[i].bsize); | ||||||
| 	} | 	} | ||||||
| 	columns = 80 / (max_len + 1); /* get space between columns */ | 	if(num_files == 0) | ||||||
| 	max_len = 80 / columns; | 	    goto next; | ||||||
|  | 	if(flags & LS_SIZE) { | ||||||
|  | 	    columns = 80 / (size_len + 1 + max_len + 1); | ||||||
|  | 	    max_len = 80 / columns - size_len - 1; | ||||||
|  | 	} else { | ||||||
|  | 	    columns = 80 / (max_len + 1); /* get space between columns */ | ||||||
|  | 	    max_len = 80 / columns; | ||||||
|  | 	} | ||||||
|  | 	if(flags & LS_SIZE) | ||||||
|  | 	    sec_fprintf2(out, "total %lu\r\n",  | ||||||
|  | 			 (unsigned long)total_blocks); | ||||||
| 	if(DISP_MODE(flags) == LS_DISP_CROSS) { | 	if(DISP_MODE(flags) == LS_DISP_CROSS) { | ||||||
| 	    for(i = 0, j = 0; i < n_files; i++) { | 	    for(i = 0, j = 0; i < n_files; i++) { | ||||||
| 		if(fi[i].filename == NULL) | 		if(fi[i].filename == NULL) | ||||||
| 		    continue; | 		    continue; | ||||||
| 		sec_fprintf2(out, "%-*s", max_len, fi[i].filename); | 		if(flags & LS_SIZE) | ||||||
|  | 		    sec_fprintf2(out, "%*u %-*s", size_len, fi[i].bsize,  | ||||||
|  | 				 max_len, fi[i].filename); | ||||||
|  | 		else | ||||||
|  | 		    sec_fprintf2(out, "%-*s", max_len, fi[i].filename); | ||||||
| 		j++; | 		j++; | ||||||
| 		if(j == columns) { | 		if(j == columns) { | ||||||
| 		    sec_fprintf2(out, "\r\n"); | 		    sec_fprintf2(out, "\r\n"); | ||||||
| @@ -579,7 +631,7 @@ list_files(FILE *out, const char **files, int n_files, int flags) | |||||||
| 		} | 		} | ||||||
| 	    } | 	    } | ||||||
| 	    if(j > 0) | 	    if(j > 0) | ||||||
| 		    sec_fprintf2(out, "\r\n"); | 		sec_fprintf2(out, "\r\n"); | ||||||
| 	} else { | 	} else { | ||||||
| 	    int skip = (num_files + columns - 1) / columns; | 	    int skip = (num_files + columns - 1) / columns; | ||||||
| 	    j = 0; | 	    j = 0; | ||||||
| @@ -587,7 +639,11 @@ list_files(FILE *out, const char **files, int n_files, int flags) | |||||||
| 		for(j = i; j < n_files;) { | 		for(j = i; j < n_files;) { | ||||||
| 		    while(j < n_files && fi[j].filename == NULL) | 		    while(j < n_files && fi[j].filename == NULL) | ||||||
| 			j++; | 			j++; | ||||||
| 		    sec_fprintf2(out, "%-*s", max_len, fi[j].filename); | 		    if(flags & LS_SIZE) | ||||||
|  | 			sec_fprintf2(out, "%*u %-*s", size_len, fi[j].bsize,  | ||||||
|  | 				     max_len, fi[j].filename); | ||||||
|  | 		    else | ||||||
|  | 			sec_fprintf2(out, "%-*s", max_len, fi[j].filename); | ||||||
| 		    j += skip; | 		    j += skip; | ||||||
| 		} | 		} | ||||||
| 		sec_fprintf2(out, "\r\n"); | 		sec_fprintf2(out, "\r\n"); | ||||||
| @@ -600,9 +656,24 @@ list_files(FILE *out, const char **files, int n_files, int flags) | |||||||
| 	    sec_fprintf2(out, "%s\r\n", fi[i].filename); | 	    sec_fprintf2(out, "%s\r\n", fi[i].filename); | ||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
|  |   next: | ||||||
|  |     if(((flags & LS_DIRS) == 0 || (flags & LS_RECURSIVE)) && dirs != NULL) { | ||||||
|  | 	for(i = 0; i < n_files; i++) | ||||||
|  | 	    if(dirs[i]) { | ||||||
|  | 		if((flags & LS_SHOW_DIRNAME)) { | ||||||
|  | 		    if ((flags & LS_EXTRA_BLANK)) | ||||||
|  | 			sec_fprintf2(out, "\r\n"); | ||||||
|  | 		    sec_fprintf2(out, "%s:\r\n", files[i]); | ||||||
|  | 		} | ||||||
|  | 		list_dir(out, files[i], flags | LS_DIRS | LS_EXTRA_BLANK); | ||||||
|  | 	    } | ||||||
|  |     } | ||||||
|  |   out: | ||||||
|     for(i = 0; i < n_files; i++) |     for(i = 0; i < n_files; i++) | ||||||
| 	free_fileinfo(&fi[i]); | 	free_fileinfo(&fi[i]); | ||||||
|     free(fi); |     free(fi); | ||||||
|  |     if(dirs != NULL) | ||||||
|  | 	free(dirs); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| @@ -615,6 +686,22 @@ free_files (char **files, int n) | |||||||
|     free (files); |     free (files); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int | ||||||
|  | hide_file(const char *filename, int flags) | ||||||
|  | { | ||||||
|  |     if(filename[0] != '.') | ||||||
|  | 	return 0; | ||||||
|  |     if((flags & LS_IGNORE_DOT)) | ||||||
|  | 	return 1; | ||||||
|  |     if(filename[1] == '\0' || (filename[1] == '.' && filename[2] == '\0')) { | ||||||
|  | 	if((flags & LS_SHOW_ALL)) | ||||||
|  | 	    return 0; | ||||||
|  | 	else | ||||||
|  | 	    return 1; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| list_dir(FILE *out, const char *directory, int flags) | list_dir(FILE *out, const char *directory, int flags) | ||||||
| { | { | ||||||
| @@ -630,15 +717,8 @@ list_dir(FILE *out, const char *directory, int flags) | |||||||
|     while((ent = readdir(d)) != NULL) { |     while((ent = readdir(d)) != NULL) { | ||||||
| 	void *tmp; | 	void *tmp; | ||||||
|  |  | ||||||
| 	if(ent->d_name[0] == '.') { | 	if(hide_file(ent->d_name, flags)) | ||||||
| 	    if (ent->d_name[1] == 0 && flags & LS_IGNORE_DOTDIR) /* Ignore . */ | 	    continue; | ||||||
| 	        continue; |  | ||||||
| 	    if (ent->d_name[1] == '.' && ent->d_name[2] == 0 |  | ||||||
| 		&& flags & LS_IGNORE_DOTDIR) /* Ignore .. */ |  | ||||||
| 	        continue; |  | ||||||
| 	    if (flags & LS_IGNORE_DOT) |  | ||||||
| 	        continue; |  | ||||||
| 	} |  | ||||||
| 	tmp = realloc(files, (n_files + 1) * sizeof(*files)); | 	tmp = realloc(files, (n_files + 1) * sizeof(*files)); | ||||||
| 	if (tmp == NULL) { | 	if (tmp == NULL) { | ||||||
| 	    sec_fprintf2(out, "%s: out of memory\r\n", directory); | 	    sec_fprintf2(out, "%s: out of memory\r\n", directory); | ||||||
| @@ -657,64 +737,84 @@ list_dir(FILE *out, const char *directory, int flags) | |||||||
| 	++n_files; | 	++n_files; | ||||||
|     } |     } | ||||||
|     closedir(d); |     closedir(d); | ||||||
|     list_files(out, (const char**)files, n_files, flags | LS_DIRS); |     list_files(out, (const char**)files, n_files, flags); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int | ||||||
|  | parse_flags(const char *options) | ||||||
|  | { | ||||||
|  | #ifdef TEST | ||||||
|  |     int flags = LS_SORT_NAME | LS_IGNORE_DOT | LS_DISP_COLUMN; | ||||||
|  | #else | ||||||
|  |     int flags = LS_SORT_NAME | LS_IGNORE_DOT | LS_DISP_LONG; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     const char *p; | ||||||
|  |     if(options == NULL || *options != '-') | ||||||
|  | 	return flags; | ||||||
|  |     for(p = options + 1; *p; p++) { | ||||||
|  | 	switch(*p) { | ||||||
|  | 	case '1': | ||||||
|  | 	    flags = (flags & ~LS_DISP_MODE); | ||||||
|  | 	    break; | ||||||
|  | 	case 'a': | ||||||
|  | 	    flags |= LS_SHOW_ALL; | ||||||
|  | 	    /*FALLTHROUGH*/ | ||||||
|  | 	case 'A': | ||||||
|  | 	    flags &= ~LS_IGNORE_DOT; | ||||||
|  | 	    break; | ||||||
|  | 	case 'C': | ||||||
|  | 	    flags = (flags & ~LS_DISP_MODE) | LS_DISP_COLUMN; | ||||||
|  | 	    break; | ||||||
|  | 	case 'd': | ||||||
|  | 	    flags |= LS_DIRS; | ||||||
|  | 	    break; | ||||||
|  | 	case 'f': | ||||||
|  | 	    flags = (flags & ~LS_SORT_MODE); | ||||||
|  | 	    break; | ||||||
|  | 	case 'F': | ||||||
|  | 	    flags |= LS_TYPE; | ||||||
|  | 	    break; | ||||||
|  | 	case 'i': | ||||||
|  | 	    flags |= LS_INODE; | ||||||
|  | 	    break; | ||||||
|  | 	case 'l': | ||||||
|  | 	    flags = (flags & ~LS_DISP_MODE) | LS_DISP_LONG; | ||||||
|  | 	    break; | ||||||
|  | 	case 't': | ||||||
|  | 	    flags = (flags & ~LS_SORT_MODE) | LS_SORT_MTIME; | ||||||
|  | 	    break; | ||||||
|  | 	case 's': | ||||||
|  | 	    flags |= LS_SIZE; | ||||||
|  | 	    break; | ||||||
|  | 	case 'S': | ||||||
|  | 	    flags = (flags & ~LS_SORT_MODE) | LS_SORT_SIZE; | ||||||
|  | 	    break; | ||||||
|  | 	case 'r': | ||||||
|  | 	    flags |= LS_SORT_REVERSE; | ||||||
|  | 	    break; | ||||||
|  | 	case 'R': | ||||||
|  | 	    flags |= LS_RECURSIVE; | ||||||
|  | 	    break; | ||||||
|  | 	case 'x': | ||||||
|  | 	    flags = (flags & ~LS_DISP_MODE) | LS_DISP_CROSS; | ||||||
|  | 	    break; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |     return flags; | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| builtin_ls(FILE *out, const char *file) | builtin_ls(FILE *out, const char *file) | ||||||
| { | { | ||||||
|     int flags = LS_SORT_NAME | LS_IGNORE_DOT | LS_IGNORE_DOTDIR | LS_DISP_LONG; |     int flags; | ||||||
|  |  | ||||||
|     if(*file == '-') { |     if(*file == '-') { | ||||||
| 	const char *p; | 	flags = parse_flags(file); | ||||||
| 	for(p = file + 1; *p; p++) { |  | ||||||
| 	    switch(*p) { |  | ||||||
| 	    case '1': |  | ||||||
| 		flags = (flags & ~LS_DISP_MODE); |  | ||||||
| 		break; |  | ||||||
| 	    case 'a': |  | ||||||
| 		flags &= ~(LS_IGNORE_DOT | LS_IGNORE_DOTDIR); |  | ||||||
| 		break; |  | ||||||
| 	    case 'A': |  | ||||||
| 		flags &= ~LS_IGNORE_DOT; |  | ||||||
| 		break; |  | ||||||
| 	    case 'C': |  | ||||||
| 		flags = (flags & ~LS_DISP_MODE) | LS_DISP_COLUMN; |  | ||||||
| 		break; |  | ||||||
| 	    case 'd': |  | ||||||
| 		flags |= LS_DIRS; |  | ||||||
| 		break; |  | ||||||
| 	    case 'f': |  | ||||||
| 		flags = (flags & ~LS_SORT_MODE); |  | ||||||
| 		break; |  | ||||||
| 	    case 'F': |  | ||||||
| 		flags |= LS_TYPE; |  | ||||||
| 		break; |  | ||||||
| 	    case 'i': |  | ||||||
| 		flags |= LS_INODE; |  | ||||||
| 		break; |  | ||||||
| 	    case 'l': |  | ||||||
| 		flags = (flags & ~LS_DISP_MODE) | LS_DISP_LONG; |  | ||||||
| 		break; |  | ||||||
| 	    case 't': |  | ||||||
| 		flags = (flags & ~LS_SORT_MODE) | LS_SORT_MTIME; |  | ||||||
| 		break; |  | ||||||
| 	    case 's': |  | ||||||
| 		flags |= LS_SIZE; |  | ||||||
| 		break; |  | ||||||
| 	    case 'S': |  | ||||||
| 		flags = (flags & ~LS_SORT_MODE) | LS_SORT_SIZE; |  | ||||||
| 		break; |  | ||||||
| 	    case 'r': |  | ||||||
| 		flags |= LS_SORT_REVERSE; |  | ||||||
| 		break; |  | ||||||
| 	    case 'x': |  | ||||||
| 		flags = (flags & ~LS_DISP_MODE) | LS_DISP_CROSS; |  | ||||||
| 		break; |  | ||||||
| 	    } |  | ||||||
| 	} |  | ||||||
| 	file = "."; | 	file = "."; | ||||||
|     } |     } else | ||||||
|  | 	flags = parse_flags(""); | ||||||
|  |  | ||||||
|     list_files(out, &file, 1, flags); |     list_files(out, &file, 1, flags); | ||||||
|     sec_fflush(out); |     sec_fflush(out); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Johan Danielsson
					Johan Danielsson