ls.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
ls.c (5449B) | |
--- | |
1 #include <u.h> | |
2 #include <libc.h> | |
3 #include <bio.h> | |
4 | |
5 #define dirbuf p9dirbuf /* avoid conflict on sun */ | |
6 | |
7 typedef struct NDir NDir; | |
8 struct NDir | |
9 { | |
10 Dir *d; | |
11 char *prefix; | |
12 }; | |
13 | |
14 int errs = 0; | |
15 int dflag; | |
16 int lflag; | |
17 int mflag; | |
18 int nflag; | |
19 int pflag; | |
20 int qflag; | |
21 int Qflag; | |
22 int rflag; | |
23 int sflag; | |
24 int tflag; | |
25 int uflag; | |
26 int Fflag; | |
27 int ndirbuf; | |
28 int ndir; | |
29 NDir* dirbuf; | |
30 int ls(char*, int); | |
31 int compar(NDir*, NDir*); | |
32 char* asciitime(long); | |
33 char* darwx(long); | |
34 void rwx(long, char*); | |
35 void growto(long); | |
36 void dowidths(Dir*); | |
37 void format(Dir*, char*); | |
38 void output(void); | |
39 ulong clk; | |
40 int swidth; /* max width of -s size */ | |
41 int qwidth; /* max width of -q version */ | |
42 int vwidth; /* max width of dev */ | |
43 int uwidth; /* max width of userid */ | |
44 int mwidth; /* max width of muid */ | |
45 int glwidth; /* max width of groupid and length */ | |
46 Biobuf bin; | |
47 | |
48 void | |
49 main(int argc, char *argv[]) | |
50 { | |
51 int i; | |
52 | |
53 Binit(&bin, 1, OWRITE); | |
54 ARGBEGIN{ | |
55 case 'F': Fflag++; break; | |
56 case 'd': dflag++; break; | |
57 case 'l': lflag++; break; | |
58 case 'm': mflag++; break; | |
59 case 'n': nflag++; break; | |
60 case 'p': pflag++; break; | |
61 case 'q': qflag++; break; | |
62 case 'Q': Qflag++; break; | |
63 case 'r': rflag++; break; | |
64 case 's': sflag++; break; | |
65 case 't': tflag++; break; | |
66 case 'u': uflag++; break; | |
67 default: fprint(2, "usage: ls [-dlmnpqrstuFQ] [file ...]\… | |
68 exits("usage"); | |
69 }ARGEND | |
70 | |
71 doquote = needsrcquote; | |
72 quotefmtinstall(); | |
73 fmtinstall('M', dirmodefmt); | |
74 | |
75 if(lflag) | |
76 clk = time(0); | |
77 if(argc == 0) | |
78 errs = ls(".", 0); | |
79 else for(i=0; i<argc; i++) | |
80 errs |= ls(argv[i], 1); | |
81 output(); | |
82 exits(errs? "errors" : 0); | |
83 } | |
84 | |
85 int | |
86 ls(char *s, int multi) | |
87 { | |
88 int fd; | |
89 long i, n; | |
90 char *p; | |
91 Dir *db; | |
92 | |
93 for(;;) { | |
94 p = utfrrune(s, '/'); | |
95 if(p == 0 || p[1] != 0 || p == s) | |
96 break; | |
97 *p = 0; | |
98 } | |
99 db = dirstat(s); | |
100 if(db == nil){ | |
101 error: | |
102 fprint(2, "ls: %s: %r\n", s); | |
103 return 1; | |
104 } | |
105 if(db->qid.type&QTDIR && dflag==0){ | |
106 free(db); | |
107 db = nil; | |
108 output(); | |
109 fd = open(s, OREAD); | |
110 if(fd == -1) | |
111 goto error; | |
112 n = dirreadall(fd, &db); | |
113 if(n < 0) | |
114 goto error; | |
115 growto(ndir+n); | |
116 for(i=0; i<n; i++){ | |
117 dirbuf[ndir+i].d = db+i; | |
118 dirbuf[ndir+i].prefix = multi? s : 0; | |
119 } | |
120 ndir += n; | |
121 close(fd); | |
122 output(); | |
123 }else{ | |
124 growto(ndir+1); | |
125 dirbuf[ndir].d = db; | |
126 dirbuf[ndir].prefix = 0; | |
127 p = utfrrune(s, '/'); | |
128 if(p){ | |
129 dirbuf[ndir].prefix = s; | |
130 *p = 0; | |
131 /* restore original name; don't use result of st… | |
132 dirbuf[ndir].d->name = strdup(p+1); | |
133 } | |
134 ndir++; | |
135 } | |
136 return 0; | |
137 } | |
138 | |
139 void | |
140 output(void) | |
141 { | |
142 int i; | |
143 char buf[4096]; | |
144 char *s; | |
145 | |
146 if(!nflag) | |
147 qsort(dirbuf, ndir, sizeof dirbuf[0], (int (*)(const voi… | |
148 for(i=0; i<ndir; i++) | |
149 dowidths(dirbuf[i].d); | |
150 for(i=0; i<ndir; i++) { | |
151 if(!pflag && (s = dirbuf[i].prefix)) { | |
152 if(strcmp(s, "/") ==0) /* / is a special … | |
153 s = ""; | |
154 sprint(buf, "%s/%s", s, dirbuf[i].d->name); | |
155 format(dirbuf[i].d, buf); | |
156 } else | |
157 format(dirbuf[i].d, dirbuf[i].d->name); | |
158 } | |
159 ndir = 0; | |
160 Bflush(&bin); | |
161 } | |
162 | |
163 void | |
164 dowidths(Dir *db) | |
165 { | |
166 char buf[256]; | |
167 int n; | |
168 | |
169 if(sflag) { | |
170 n = sprint(buf, "%llud", (db->length+1023)/1024); | |
171 if(n > swidth) | |
172 swidth = n; | |
173 } | |
174 if(qflag) { | |
175 n = sprint(buf, "%lud", db->qid.vers); | |
176 if(n > qwidth) | |
177 qwidth = n; | |
178 } | |
179 if(mflag) { | |
180 n = snprint(buf, sizeof buf, "[%s]", db->muid); | |
181 if(n > mwidth) | |
182 mwidth = n; | |
183 } | |
184 if(lflag) { | |
185 n = sprint(buf, "%ud", db->dev); | |
186 if(n > vwidth) | |
187 vwidth = n; | |
188 n = strlen(db->uid); | |
189 if(n > uwidth) | |
190 uwidth = n; | |
191 n = sprint(buf, "%llud", db->length); | |
192 n += strlen(db->gid); | |
193 if(n > glwidth) | |
194 glwidth = n; | |
195 } | |
196 } | |
197 | |
198 char* | |
199 fileflag(Dir *db) | |
200 { | |
201 if(Fflag == 0) | |
202 return ""; | |
203 if(QTDIR & db->qid.type) | |
204 return "/"; | |
205 if(0111 & db->mode) | |
206 return "*"; | |
207 return ""; | |
208 } | |
209 | |
210 void | |
211 format(Dir *db, char *name) | |
212 { | |
213 int i; | |
214 | |
215 if(sflag) | |
216 Bprint(&bin, "%*llud ", | |
217 swidth, (db->length+1023)/1024); | |
218 if(mflag){ | |
219 Bprint(&bin, "[%s] ", db->muid); | |
220 for(i=2+strlen(db->muid); i<mwidth; i++) | |
221 Bprint(&bin, " "); | |
222 } | |
223 if(qflag) | |
224 Bprint(&bin, "(%.16llux %*lud %.2ux) ", | |
225 db->qid.path, | |
226 qwidth, db->qid.vers, | |
227 db->qid.type); | |
228 if(lflag) | |
229 Bprint(&bin, | |
230 "%M %C %*ud %*s %s %*llud %s ", | |
231 db->mode, db->type, | |
232 vwidth, db->dev, | |
233 -uwidth, db->uid, | |
234 db->gid, | |
235 (int)(glwidth-strlen(db->gid)), db->length, | |
236 asciitime(uflag? db->atime : db->mtime)); | |
237 Bprint(&bin, | |
238 Qflag? "%s%s\n" : "%q%s\n", | |
239 name, fileflag(db)); | |
240 } | |
241 | |
242 void | |
243 growto(long n) | |
244 { | |
245 if(n <= ndirbuf) | |
246 return; | |
247 ndirbuf = n; | |
248 dirbuf=(NDir *)realloc(dirbuf, ndirbuf*sizeof(NDir)); | |
249 if(dirbuf == 0){ | |
250 fprint(2, "ls: malloc fail\n"); | |
251 exits("malloc fail"); | |
252 } | |
253 } | |
254 | |
255 int | |
256 compar(NDir *a, NDir *b) | |
257 { | |
258 long i; | |
259 Dir *ad, *bd; | |
260 | |
261 ad = a->d; | |
262 bd = b->d; | |
263 | |
264 if(tflag){ | |
265 if(uflag) | |
266 i = bd->atime-ad->atime; | |
267 else | |
268 i = bd->mtime-ad->mtime; | |
269 }else{ | |
270 if(a->prefix && b->prefix){ | |
271 i = strcmp(a->prefix, b->prefix); | |
272 if(i == 0) | |
273 i = strcmp(ad->name, bd->name); | |
274 }else if(a->prefix){ | |
275 i = strcmp(a->prefix, bd->name); | |
276 if(i == 0) | |
277 i = 1; /* a is longer than b */ | |
278 }else if(b->prefix){ | |
279 i = strcmp(ad->name, b->prefix); | |
280 if(i == 0) | |
281 i = -1; /* b is longer than a */ | |
282 }else | |
283 i = strcmp(ad->name, bd->name); | |
284 } | |
285 if(i == 0) | |
286 i = (ad<bd? -1 : 1); | |
287 if(rflag) | |
288 i = -i; | |
289 return i; | |
290 } | |
291 | |
292 char* | |
293 asciitime(long l) | |
294 { | |
295 static char buf[32]; | |
296 char *t; | |
297 | |
298 t = ctime(l); | |
299 /* 6 months in the past or a day in the future */ | |
300 if(l<clk-180L*24*60*60 || clk+24L*60*60<l){ | |
301 memmove(buf, t+4, 7); /* month and day */ | |
302 memmove(buf+7, t+23, 5); /* year */ | |
303 }else | |
304 memmove(buf, t+4, 12); /* skip day of wee… | |
305 buf[12] = 0; | |
306 return buf; | |
307 } | |
308 |