uuprog

diff ls.c @ 0:4f628556fa3e

uuprog initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 25 Aug 2011 08:53:01 +0300
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ls.c	Thu Aug 25 08:53:01 2011 +0300
     1.3 @@ -0,0 +1,313 @@
     1.4 +/*! gcc -pedantic -Wall -g -o ls ls.c */
     1.5 +#include <stdio.h>
     1.6 +#include <stdlib.h>
     1.7 +#include <string.h>
     1.8 +#include <errno.h>
     1.9 +#include <time.h>
    1.10 +#include <unistd.h>
    1.11 +#include <fcntl.h>
    1.12 +#include <dirent.h>
    1.13 +#include <pwd.h>
    1.14 +#include <grp.h>
    1.15 +#include <sys/types.h>
    1.16 +#include <sys/stat.h>
    1.17 +
    1.18 +enum {SORT_NONE, SORT_NAME};
    1.19 +
    1.20 +enum {
    1.21 +	OPT_LONG	= 1,
    1.22 +	OPT_ALL		= 2,
    1.23 +	OPT_DIR		= 4,
    1.24 +	OPT_CLASS	= 8,
    1.25 +	OPT_HUMAN	= 16,
    1.26 +	OPT_INODES	= 32
    1.27 +};
    1.28 +
    1.29 +int proc_opt(char opt);
    1.30 +int ls_dir(char *dir);
    1.31 +
    1.32 +unsigned int flags = 0;
    1.33 +int sort_by = SORT_NAME;
    1.34 +int term_col = 80;	/* TODO: detect columns */
    1.35 +
    1.36 +int main(int argc, char **argv)
    1.37 +{
    1.38 +	int i, did_one = 0;
    1.39 +
    1.40 +	for(i=1; i<argc; i++) {
    1.41 +		if(argv[i][0] == '-') {
    1.42 +			char *ptr = argv[i] + 1;
    1.43 +			while(ptr && *ptr) {
    1.44 +				if(proc_opt(*ptr++) == -1) {
    1.45 +					fprintf(stderr, "%s: invalid option -- %c\n", argv[0], *(ptr - 1));
    1.46 +					return 1;
    1.47 +				}
    1.48 +			}
    1.49 +		} else {
    1.50 +			printf("%s:\n", argv[i]);
    1.51 +			if(ls_dir(argv[i]) == -1) {
    1.52 +				fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno));
    1.53 +			}
    1.54 +			did_one = 1;
    1.55 +		}
    1.56 +	}
    1.57 +
    1.58 +	if(!did_one) {
    1.59 +		ls_dir(".");
    1.60 +	}
    1.61 +
    1.62 +	return 0;
    1.63 +}
    1.64 +
    1.65 +int proc_opt(char opt)
    1.66 +{
    1.67 +	switch(opt) {
    1.68 +	case 'a':
    1.69 +		flags |= OPT_ALL;
    1.70 +		break;
    1.71 +
    1.72 +	case 'l':
    1.73 +		flags |= OPT_LONG;
    1.74 +		break;
    1.75 +
    1.76 +	case 'F':
    1.77 +		flags |= OPT_CLASS;
    1.78 +		break;
    1.79 +
    1.80 +	case 'h':
    1.81 +		flags |= OPT_HUMAN;
    1.82 +		break;
    1.83 +
    1.84 +	case 'i':
    1.85 +		flags |= OPT_INODES;
    1.86 +		break;
    1.87 +
    1.88 +	default:
    1.89 +		return -1;
    1.90 +	}
    1.91 +	return 0;
    1.92 +}
    1.93 +
    1.94 +struct entry {
    1.95 +	char *name;
    1.96 +	struct stat st;
    1.97 +	struct entry *next;
    1.98 +};
    1.99 +
   1.100 +int print_entry(struct entry *ent)
   1.101 +{
   1.102 +	int len = strlen(ent->name);
   1.103 +
   1.104 +	if(flags & OPT_LONG) {
   1.105 +		int i;
   1.106 +		struct passwd *pwd;
   1.107 +		struct group *grp;
   1.108 +		char tmbuf[128];
   1.109 +
   1.110 +		switch(ent->st.st_mode & S_IFMT) {
   1.111 +		case S_IFSOCK:
   1.112 +			putchar('s');
   1.113 +			break;
   1.114 +		case S_IFLNK:
   1.115 +			putchar('l');
   1.116 +			break;
   1.117 +		case S_IFBLK:
   1.118 +			putchar('b');
   1.119 +			break;
   1.120 +		case S_IFDIR:
   1.121 +			putchar('d');
   1.122 +			break;
   1.123 +		case S_IFCHR:
   1.124 +			putchar('c');
   1.125 +			break;
   1.126 +		case S_IFIFO:
   1.127 +			putchar('f');
   1.128 +			break;
   1.129 +		default:
   1.130 +			putchar('-');
   1.131 +		}
   1.132 +
   1.133 +		for(i=0; i<3; i++) {
   1.134 +			int s = (2 - i) * 3;
   1.135 +			unsigned int val = (ent->st.st_mode >> s) & 7;
   1.136 +
   1.137 +			putchar(val & 4 ? 'r' : '-');
   1.138 +			putchar(val & 2 ? 'w' : '-');
   1.139 +			putchar(val & 1 ? 'x' : '-');
   1.140 +		}
   1.141 +		printf(" %3d ", (int)ent->st.st_nlink);
   1.142 +
   1.143 +		if(!(pwd = getpwuid(ent->st.st_uid))) {
   1.144 +			printf("%d ", ent->st.st_uid);
   1.145 +		} else {
   1.146 +			printf("%s ", pwd->pw_name);
   1.147 +		}
   1.148 +		if(!(grp = getgrgid(ent->st.st_gid))) {
   1.149 +			printf("%d ", ent->st.st_gid);
   1.150 +		} else {
   1.151 +			printf("%s ", grp->gr_name);
   1.152 +		}
   1.153 +
   1.154 +		sprintf(tmbuf, "%s", ctime(&ent->st.st_mtime));
   1.155 +		tmbuf[strlen(tmbuf) - 1] = 0;
   1.156 +
   1.157 +		printf("%6ld %s ", (long)ent->st.st_size, tmbuf);
   1.158 +	}
   1.159 +
   1.160 +	fputs(ent->name, stdout);
   1.161 +
   1.162 +	if(flags & OPT_CLASS) {
   1.163 +		if(S_ISDIR(ent->st.st_mode)) {
   1.164 +			putchar('/');
   1.165 +			len++;
   1.166 +		} else if(ent->st.st_mode & S_IXUSR) {
   1.167 +			putchar('*');
   1.168 +			len++;
   1.169 +		}
   1.170 +	}
   1.171 +
   1.172 +	return len;
   1.173 +}
   1.174 +
   1.175 +void print_list(struct entry *arr, int count)
   1.176 +{
   1.177 +	int i, j, ncol, longest = 0;
   1.178 +
   1.179 +	for(i=0; i<count; i++) {
   1.180 +		int len = strlen(arr[i].name) + 2;
   1.181 +		if(len > longest) {
   1.182 +			longest = len;
   1.183 +		}
   1.184 +	}
   1.185 +
   1.186 +	if(isatty(1) && !(flags & OPT_LONG)) {
   1.187 +		ncol = term_col / longest;
   1.188 +		if(!ncol) ncol = 1;
   1.189 +	} else {
   1.190 +		ncol = 1;
   1.191 +	}
   1.192 +
   1.193 +	for(i=0; i<count; i++) {
   1.194 +		int len;
   1.195 +
   1.196 +		len = print_entry(&arr[i]);
   1.197 +
   1.198 +		if(i < count - 1 && (i % ncol) == ncol - 1) {
   1.199 +			putchar('\n');
   1.200 +		} else {
   1.201 +			for(j=0; j<longest - len; j++) {
   1.202 +				putchar(' ');
   1.203 +			}
   1.204 +		}
   1.205 +	}
   1.206 +	putchar('\n');
   1.207 +}
   1.208 +
   1.209 +int cmp_func(const void *e1, const void *e2)
   1.210 +{
   1.211 +	const struct entry *ent1, *ent2;
   1.212 +	const char *n1, *n2;
   1.213 +
   1.214 +	ent1 = e1;
   1.215 +	ent2 = e2;
   1.216 +
   1.217 +	switch(sort_by) {
   1.218 +	case SORT_NAME:
   1.219 +	default:
   1.220 +		n1 = ent1->name;
   1.221 +		n2 = ent2->name;
   1.222 +	}
   1.223 +	return strcmp(n1, n2);
   1.224 +}
   1.225 +
   1.226 +int ls_dir(char *dname)
   1.227 +{
   1.228 +	int i, cwd_fd = -1, saved_err, ent_count = 0;
   1.229 +	DIR *dir = 0;
   1.230 +	struct dirent *ent = 0;
   1.231 +	struct entry *earr = 0, *elist = 0, *enode = 0;
   1.232 +
   1.233 +
   1.234 +	if(strcmp(dname, ".") != 0) {
   1.235 +		if((cwd_fd = open(".", O_RDONLY)) == -1) {
   1.236 +			goto err;
   1.237 +		}
   1.238 +		chdir(dname);
   1.239 +	}
   1.240 +
   1.241 +	if(!(dir = opendir("."))) {
   1.242 +		goto err;
   1.243 +	}
   1.244 +
   1.245 +	if(!(elist = malloc(sizeof *elist))) {
   1.246 +		goto err;
   1.247 +	}
   1.248 +	elist->name = 0;
   1.249 +	elist->next = 0;
   1.250 +
   1.251 +	while((ent = readdir(dir))) {
   1.252 +		struct stat st;
   1.253 +
   1.254 +		if(ent->d_name[0] == '.' && !(flags & OPT_ALL)) {
   1.255 +			continue;
   1.256 +		}
   1.257 +
   1.258 +		if(lstat(ent->d_name, &st) == -1) {
   1.259 +			goto err;
   1.260 +		}
   1.261 +
   1.262 +		if(!(enode = malloc(sizeof *enode))) {
   1.263 +			goto err;
   1.264 +		}
   1.265 +		if(!(enode->name = malloc(strlen(ent->d_name) + 1))) {
   1.266 +			goto err;
   1.267 +		}
   1.268 +		strcpy(enode->name, ent->d_name);
   1.269 +		memcpy(&enode->st, &st, sizeof st);
   1.270 +
   1.271 +		enode->next = elist->next;
   1.272 +		elist->next = enode;
   1.273 +		ent_count++;
   1.274 +	}
   1.275 +	closedir(dir);
   1.276 +	dir = 0;
   1.277 +
   1.278 +	/* change the list into an array, don't feel like writing list mergesorts */
   1.279 +	if(!(earr = malloc(ent_count * sizeof *earr))) {
   1.280 +		goto err;
   1.281 +	}
   1.282 +
   1.283 +	i = 0;
   1.284 +	enode = elist->next;
   1.285 +	while(enode) {
   1.286 +		earr[i].name = enode->name;
   1.287 +		earr[i++].st = enode->st;
   1.288 +		enode = enode->next;
   1.289 +	}
   1.290 +	if(sort_by != SORT_NONE) {
   1.291 +		qsort(earr, ent_count, sizeof *earr, cmp_func);
   1.292 +	}
   1.293 +
   1.294 +	print_list(earr, ent_count);
   1.295 +
   1.296 +	if(cwd_fd != -1) {
   1.297 +		fchdir(cwd_fd);
   1.298 +	}
   1.299 +	return 0;
   1.300 +
   1.301 +err:
   1.302 +	saved_err = errno;
   1.303 +	free(earr);
   1.304 +	/*free_entry_list(elist);*/
   1.305 +	free(enode->name);
   1.306 +	free(enode);
   1.307 +	if(dir) {
   1.308 +		closedir(dir);
   1.309 +	}
   1.310 +	if(cwd_fd != -1) {
   1.311 +		fchdir(cwd_fd);
   1.312 +		close(cwd_fd);
   1.313 +	}
   1.314 +	errno = saved_err;
   1.315 +	return -1;
   1.316 +}