6 typedef struct NDir NDir;
31 int compar(NDir*, NDir*);
32 char* asciitime(long);
34 void rwx(long, char*);
37 void format(Dir*, char*);
39 char* xcleanname(char*);
41 int swidth; /* max width of -s size */
42 int qwidth; /* max width of -q version */
43 int vwidth; /* max width of dev */
44 int uwidth; /* max width of userid */
45 int mwidth; /* max width of muid */
46 int lwidth; /* max width of length */
47 int gwidth; /* max width of groupid */
51 main(int argc, char *argv[])
55 Binit(&bin, 1, OWRITE);
57 case 'F': Fflag++; break;
58 case 'd': dflag++; break;
59 case 'l': lflag++; break;
60 case 'm': mflag++; break;
61 case 'n': nflag++; break;
62 case 'p': pflag++; break;
63 case 'q': qflag++; break;
64 case 'Q': Qflag++; break;
65 case 'r': rflag++; break;
66 case 's': sflag++; break;
67 case 't': tflag++; break;
68 case 'T': Tflag++; break;
69 case 'u': uflag++; break;
70 default: fprint(2, "usage: ls [-dlmnpqrstuFQT] [file ...]\n");
74 doquote = needsrcquote;
76 fmtinstall('M', dirmodefmt);
82 else for(i=0; i<argc; i++)
83 errs |= ls(argv[i], 1);
85 exits(errs? "errors" : 0);
89 ls(char *s, int multi)
99 fprint(2, "ls: %s: %r\n", s);
102 if((db->qid.type&QTDIR) && dflag==0){
108 n = dirreadall(fd, &db);
114 dirbuf[ndir+i].d = db+i;
115 dirbuf[ndir+i].prefix = multi? s : 0;
123 dirbuf[ndir].prefix = 0;
125 p = utfrrune(s, '/');
127 dirbuf[ndir].prefix = s;
143 qsort(dirbuf, ndir, sizeof dirbuf[0], (int (*)(void*, void*))compar);
144 for(i=0; i<ndir; i++)
145 dowidths(dirbuf[i].d);
146 for(i=0; i<ndir; i++) {
147 if(!pflag && (s = dirbuf[i].prefix)) {
148 if(strcmp(s, "/") ==0) /* / is a special case */
150 sprint(buf, "%s/%s", s, dirbuf[i].d->name);
151 format(dirbuf[i].d, buf);
153 format(dirbuf[i].d, dirbuf[i].d->name);
166 n = sprint(buf, "%llud", (db->length+1023)/1024);
171 n = sprint(buf, "%lud", db->qid.vers);
176 n = snprint(buf, sizeof buf, "[%q]", db->muid);
181 n = sprint(buf, "%ud", db->dev);
184 n = sprint(buf, "%q", db->uid);
187 n = sprint(buf, "%q", db->gid);
190 n = sprint(buf, "%llud", db->length);
201 if(QTDIR & db->qid.type)
209 format(Dir *db, char *name)
214 Bprint(&bin, "%*llud ",
215 swidth, (db->length+1023)/1024);
217 Bprint(&bin, "[%q] ", db->muid);
218 for(i=2+strlen(db->muid); i<mwidth; i++)
222 Bprint(&bin, "(%.16llux %*lud %.2ux) ",
224 qwidth, db->qid.vers,
227 Bprint(&bin, "%c ", (db->mode&DMTMP)? 't': '-');
230 Bprint(&bin, "%M %C %*ud %*q %*q %*llud %s ",
236 asciitime(uflag? db->atime: db->mtime));
237 Bprint(&bin, Qflag? "%s%s\n": "%q%s\n", name, fileflag(db));
246 dirbuf=(NDir *)realloc(dirbuf, ndirbuf*sizeof(NDir));
248 fprint(2, "ls: malloc fail\n");
249 exits("malloc fail");
254 compar(NDir *a, NDir *b)
264 i = bd->atime-ad->atime;
266 i = bd->mtime-ad->mtime;
268 if(a->prefix && b->prefix){
269 i = strcmp(a->prefix, b->prefix);
271 i = strcmp(ad->name, bd->name);
273 i = strcmp(a->prefix, bd->name);
275 i = 1; /* a is longer than b */
277 i = strcmp(ad->name, b->prefix);
279 i = -1; /* b is longer than a */
281 i = strcmp(ad->name, bd->name);
297 /* 6 months in the past or a day in the future */
298 if(l<clk-180L*24*60*60 || clk+24L*60*60<l){
299 memmove(buf, t+4, 7); /* month and day */
300 memmove(buf+7, t+23, 5); /* year */
302 memmove(buf, t+4, 12); /* skip day of week */
308 * Compress slashes, remove trailing slash. Don't worry about . and ..
311 xcleanname(char *name)
315 for(r=w=name; *r; r++){
316 if(*r=='/' && r>name && *(r-1)=='/')
323 while(w-1>name && *(w-1)=='/')