uuprog

view 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 source
1 /*! gcc -pedantic -Wall -g -o ls ls.c */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <time.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <dirent.h>
10 #include <pwd.h>
11 #include <grp.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
15 enum {SORT_NONE, SORT_NAME};
17 enum {
18 OPT_LONG = 1,
19 OPT_ALL = 2,
20 OPT_DIR = 4,
21 OPT_CLASS = 8,
22 OPT_HUMAN = 16,
23 OPT_INODES = 32
24 };
26 int proc_opt(char opt);
27 int ls_dir(char *dir);
29 unsigned int flags = 0;
30 int sort_by = SORT_NAME;
31 int term_col = 80; /* TODO: detect columns */
33 int main(int argc, char **argv)
34 {
35 int i, did_one = 0;
37 for(i=1; i<argc; i++) {
38 if(argv[i][0] == '-') {
39 char *ptr = argv[i] + 1;
40 while(ptr && *ptr) {
41 if(proc_opt(*ptr++) == -1) {
42 fprintf(stderr, "%s: invalid option -- %c\n", argv[0], *(ptr - 1));
43 return 1;
44 }
45 }
46 } else {
47 printf("%s:\n", argv[i]);
48 if(ls_dir(argv[i]) == -1) {
49 fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno));
50 }
51 did_one = 1;
52 }
53 }
55 if(!did_one) {
56 ls_dir(".");
57 }
59 return 0;
60 }
62 int proc_opt(char opt)
63 {
64 switch(opt) {
65 case 'a':
66 flags |= OPT_ALL;
67 break;
69 case 'l':
70 flags |= OPT_LONG;
71 break;
73 case 'F':
74 flags |= OPT_CLASS;
75 break;
77 case 'h':
78 flags |= OPT_HUMAN;
79 break;
81 case 'i':
82 flags |= OPT_INODES;
83 break;
85 default:
86 return -1;
87 }
88 return 0;
89 }
91 struct entry {
92 char *name;
93 struct stat st;
94 struct entry *next;
95 };
97 int print_entry(struct entry *ent)
98 {
99 int len = strlen(ent->name);
101 if(flags & OPT_LONG) {
102 int i;
103 struct passwd *pwd;
104 struct group *grp;
105 char tmbuf[128];
107 switch(ent->st.st_mode & S_IFMT) {
108 case S_IFSOCK:
109 putchar('s');
110 break;
111 case S_IFLNK:
112 putchar('l');
113 break;
114 case S_IFBLK:
115 putchar('b');
116 break;
117 case S_IFDIR:
118 putchar('d');
119 break;
120 case S_IFCHR:
121 putchar('c');
122 break;
123 case S_IFIFO:
124 putchar('f');
125 break;
126 default:
127 putchar('-');
128 }
130 for(i=0; i<3; i++) {
131 int s = (2 - i) * 3;
132 unsigned int val = (ent->st.st_mode >> s) & 7;
134 putchar(val & 4 ? 'r' : '-');
135 putchar(val & 2 ? 'w' : '-');
136 putchar(val & 1 ? 'x' : '-');
137 }
138 printf(" %3d ", (int)ent->st.st_nlink);
140 if(!(pwd = getpwuid(ent->st.st_uid))) {
141 printf("%d ", ent->st.st_uid);
142 } else {
143 printf("%s ", pwd->pw_name);
144 }
145 if(!(grp = getgrgid(ent->st.st_gid))) {
146 printf("%d ", ent->st.st_gid);
147 } else {
148 printf("%s ", grp->gr_name);
149 }
151 sprintf(tmbuf, "%s", ctime(&ent->st.st_mtime));
152 tmbuf[strlen(tmbuf) - 1] = 0;
154 printf("%6ld %s ", (long)ent->st.st_size, tmbuf);
155 }
157 fputs(ent->name, stdout);
159 if(flags & OPT_CLASS) {
160 if(S_ISDIR(ent->st.st_mode)) {
161 putchar('/');
162 len++;
163 } else if(ent->st.st_mode & S_IXUSR) {
164 putchar('*');
165 len++;
166 }
167 }
169 return len;
170 }
172 void print_list(struct entry *arr, int count)
173 {
174 int i, j, ncol, longest = 0;
176 for(i=0; i<count; i++) {
177 int len = strlen(arr[i].name) + 2;
178 if(len > longest) {
179 longest = len;
180 }
181 }
183 if(isatty(1) && !(flags & OPT_LONG)) {
184 ncol = term_col / longest;
185 if(!ncol) ncol = 1;
186 } else {
187 ncol = 1;
188 }
190 for(i=0; i<count; i++) {
191 int len;
193 len = print_entry(&arr[i]);
195 if(i < count - 1 && (i % ncol) == ncol - 1) {
196 putchar('\n');
197 } else {
198 for(j=0; j<longest - len; j++) {
199 putchar(' ');
200 }
201 }
202 }
203 putchar('\n');
204 }
206 int cmp_func(const void *e1, const void *e2)
207 {
208 const struct entry *ent1, *ent2;
209 const char *n1, *n2;
211 ent1 = e1;
212 ent2 = e2;
214 switch(sort_by) {
215 case SORT_NAME:
216 default:
217 n1 = ent1->name;
218 n2 = ent2->name;
219 }
220 return strcmp(n1, n2);
221 }
223 int ls_dir(char *dname)
224 {
225 int i, cwd_fd = -1, saved_err, ent_count = 0;
226 DIR *dir = 0;
227 struct dirent *ent = 0;
228 struct entry *earr = 0, *elist = 0, *enode = 0;
231 if(strcmp(dname, ".") != 0) {
232 if((cwd_fd = open(".", O_RDONLY)) == -1) {
233 goto err;
234 }
235 chdir(dname);
236 }
238 if(!(dir = opendir("."))) {
239 goto err;
240 }
242 if(!(elist = malloc(sizeof *elist))) {
243 goto err;
244 }
245 elist->name = 0;
246 elist->next = 0;
248 while((ent = readdir(dir))) {
249 struct stat st;
251 if(ent->d_name[0] == '.' && !(flags & OPT_ALL)) {
252 continue;
253 }
255 if(lstat(ent->d_name, &st) == -1) {
256 goto err;
257 }
259 if(!(enode = malloc(sizeof *enode))) {
260 goto err;
261 }
262 if(!(enode->name = malloc(strlen(ent->d_name) + 1))) {
263 goto err;
264 }
265 strcpy(enode->name, ent->d_name);
266 memcpy(&enode->st, &st, sizeof st);
268 enode->next = elist->next;
269 elist->next = enode;
270 ent_count++;
271 }
272 closedir(dir);
273 dir = 0;
275 /* change the list into an array, don't feel like writing list mergesorts */
276 if(!(earr = malloc(ent_count * sizeof *earr))) {
277 goto err;
278 }
280 i = 0;
281 enode = elist->next;
282 while(enode) {
283 earr[i].name = enode->name;
284 earr[i++].st = enode->st;
285 enode = enode->next;
286 }
287 if(sort_by != SORT_NONE) {
288 qsort(earr, ent_count, sizeof *earr, cmp_func);
289 }
291 print_list(earr, ent_count);
293 if(cwd_fd != -1) {
294 fchdir(cwd_fd);
295 }
296 return 0;
298 err:
299 saved_err = errno;
300 free(earr);
301 /*free_entry_list(elist);*/
302 free(enode->name);
303 free(enode);
304 if(dir) {
305 closedir(dir);
306 }
307 if(cwd_fd != -1) {
308 fchdir(cwd_fd);
309 close(cwd_fd);
310 }
311 errno = saved_err;
312 return -1;
313 }