comparison toys/ls.c @ 571:1a06fcaa1775

Make -d work in ls.
author Rob Landley <rob@landley.net>
date Tue, 24 Apr 2012 20:44:09 -0500
parents 83702597fd31
children c42ed3601b35
comparison
equal deleted inserted replaced
570:83702597fd31 571:1a06fcaa1775
134 134
135 static int filter(struct dirtree *new) 135 static int filter(struct dirtree *new)
136 { 136 {
137 int flags = toys.optflags; 137 int flags = toys.optflags;
138 138
139 // TODO should -1f print here to handle enormous dirs without runing 139 // TODO should -1f print here to handle enormous dirs without runing
140 // out of mem? 140 // out of mem?
141 141
142 if (flags & FLAG_a) return DIRTREE_NORECURSE; 142 if (flags & FLAG_a) return DIRTREE_NORECURSE;
143 if (!(flags & FLAG_A) && new->name[0]=='.') 143 if (!(flags & FLAG_A) && new->name[0]=='.')
144 return DIRTREE_NOSAVE|DIRTREE_NORECURSE; 144 return DIRTREE_NOSAVE|DIRTREE_NORECURSE;
145 145
152 static void listfiles(struct dirtree *indir) 152 static void listfiles(struct dirtree *indir)
153 { 153 {
154 struct dirtree *dt, **sort = 0; 154 struct dirtree *dt, **sort = 0;
155 unsigned long dtlen = 0, ul = 0; 155 unsigned long dtlen = 0, ul = 0;
156 unsigned width, flags = toys.optflags, totals[6], len[6]; 156 unsigned width, flags = toys.optflags, totals[6], len[6];
157 int showdirs = 1; 157
158 158 // There are two "top of tree" variants:
159 // Figure out if we should show directories and current directory name 159 // ls arg1 arg2 arg3
160 if (indir == TT.files) 160 // detect: !indir->parent
161 showdirs = (flags & (FLAG_d|FLAG_R)) || indir->parent; 161 // behavior: don't display dirs, never show dirname/total, option -H
162 if (indir != TT.files || (indir->parent && (flags & FLAG_R))) { 162 // ls onedir (or just "ls" which implies "." as first arg).
163 // detect: indir == TT.files
164 // behavior: only show dirname/total with -R
165
166 // Show current directory name if showing one directory with -d or
167 // not top of tree and -R
168 if (!(indir == TT.files || (flags & FLAG_d))
169 || (indir->parent && (flags & FLAG_R)))
170 {
163 char *path = dirtree_path(indir, 0); 171 char *path = dirtree_path(indir, 0);
164 172
165 if (TT.again++) xputc('\n'); 173 if (TT.again++) xputc('\n');
166 xprintf("%s:\n", path); 174 xprintf("%s:\n", path);
167 free(path); 175 free(path);
179 sort = xmalloc(dtlen * sizeof(void *)); 187 sort = xmalloc(dtlen * sizeof(void *));
180 dtlen = 0; 188 dtlen = 0;
181 continue; 189 continue;
182 } 190 }
183 191
192 if (!(flags & FLAG_f)) qsort(sort, dtlen, sizeof(void *), (void *)compare);
193
194 // Find largest entry in each field
195
196 memset(totals, 0, 6*sizeof(unsigned));
197 for (ul = 0; ul<dtlen; ul++) {
198 entrylen(sort[ul], len);
199 if (flags & FLAG_l) {
200 for (width=0; width<6; width++)
201 if (len[width] > totals[width]) totals[width] = len[width];
202 //TODO } else if (flags & FLAG_C) {
203 } else if (*len > *totals) *totals = *len;
204 }
205
184 // This is wrong, should be blocks used not file count. 206 // This is wrong, should be blocks used not file count.
185 if (indir->parent && (flags & FLAG_l)) xprintf("total %lu\n", dtlen); 207 if (indir->parent && (flags & FLAG_l)) xprintf("total %lu\n", dtlen);
186
187 if (!(flags & FLAG_f)) qsort(sort, dtlen, sizeof(void *), (void *)compare);
188
189 // Find largest entry in each field for everything but -1
190
191 memset(totals, 0, 6*sizeof(unsigned));
192 if ((flags & (FLAG_1|FLAG_l)) != FLAG_1) {
193 for (ul = 0; ul<dtlen; ul++) {
194 entrylen(sort[ul], len);
195 if (flags & FLAG_l) {
196 for (width=0; width<6; width++)
197 if (len[width] > totals[width]) totals[width] = len[width];
198 //TODO } else if (flags & FLAG_C) {
199 } else if (*len > *totals) *totals = *len;
200 }
201 }
202 208
203 // Loop through again to produce output. 209 // Loop through again to produce output.
204 width = 0; 210 width = 0;
205 memset(toybuf, ' ', 256); 211 memset(toybuf, ' ', 256);
206 for (ul = 0; ul<dtlen; ul++) { 212 for (ul = 0; ul<dtlen; ul++) {
207 struct stat *st = &(sort[ul]->st); 213 struct stat *st = &(sort[ul]->st);
208 mode_t mode = st->st_mode; 214 mode_t mode = st->st_mode;
209 char et = endtype(st); 215 char et = endtype(st);
210 216
211 if (S_ISDIR(mode) && !showdirs) continue; 217 // Skip directories at the top of the tree when -d isn't set
218 if (S_ISDIR(mode) && !indir->parent && !(flags & FLAG_d)) continue;
219
220 // Do we need to wrap at right edge of screen?
212 entrylen(sort[ul], len); 221 entrylen(sort[ul], len);
213
214 if (ul) { 222 if (ul) {
215 if (toys.optflags & FLAG_m) xputc(','); 223 if (toys.optflags & FLAG_m) xputc(',');
216 if ((flags & FLAG_1) || width+1+*len > TT.width) { 224 if ((flags & FLAG_1) || width+1+*len > TT.width) {
217 xputc('\n'); 225 xputc('\n');
218 width = 0; 226 width = 0;
267 if (et) xputc(et); 275 if (et) xputc(et);
268 } 276 }
269 277
270 if (width) xputc('\n'); 278 if (width) xputc('\n');
271 279
280 // Free directory entries, recursing first if necessary.
281
272 for (ul = 0; ul<dtlen; free(sort[ul++])) { 282 for (ul = 0; ul<dtlen; free(sort[ul++])) {
273 // TODO follow symlinks when? 283 // TODO follow symlinks when?
274 if (!S_ISDIR(sort[ul]->st.st_mode) || dirtree_isdotdot(sort[ul])) 284 if ((flags & FLAG_d) || !S_ISDIR(sort[ul]->st.st_mode)
275 continue; 285 || dirtree_isdotdot(sort[ul])) continue;
286
287 // Recurse into dirs if at top of the tree or given -R
276 if (!indir->parent || (flags & FLAG_R)) { 288 if (!indir->parent || (flags & FLAG_R)) {
277 int fd = openat(indir->data, sort[ul]->name, 0); 289 int fd = openat(indir->data, sort[ul]->name, 0);
278 290
279 sort[ul]->data = dup(fd); 291 sort[ul]->data = dup(fd);
280 dirtree_recurse(sort[ul], filter); 292 dirtree_recurse(sort[ul], filter);
295 if (!isatty(1) || (toys.optflags&FLAG_l)) toys.optflags |= FLAG_1; 307 if (!isatty(1) || (toys.optflags&FLAG_l)) toys.optflags |= FLAG_1;
296 else { 308 else {
297 TT.width = 80; 309 TT.width = 80;
298 terminal_size(&TT.width, NULL); 310 terminal_size(&TT.width, NULL);
299 } 311 }
312 // The optflags parsing infrastructure should really do this for us,
313 // but currently it has "switch off when this is set", so "-dR" and "-Rd"
314 // behave differently
315 if (toys.optflags & FLAG_d) toys.optflags &= ~FLAG_R;
300 316
301 // Iterate through command line arguments, collecting directories and files. 317 // Iterate through command line arguments, collecting directories and files.
302 // Non-absolute paths are relative to current directory. 318 // Non-absolute paths are relative to current directory.
303 TT.files = dirtree_add_node(0, 0); 319 TT.files = dirtree_add_node(0, 0);
304 for (s = *toys.optargs ? toys.optargs : noargs; *s; s++) { 320 for (s = *toys.optargs ? toys.optargs : noargs; *s; s++) {