uuprog

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