aboutsummaryrefslogtreecommitdiff
path: root/coreutils/ls.c
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils/ls.c')
-rw-r--r--coreutils/ls.c557
1 files changed, 268 insertions, 289 deletions
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 64ec0fee6..4a4956611 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -73,58 +73,76 @@ enum {
73#endif 73#endif
74 74
75/* what is the overall style of the listing */ 75/* what is the overall style of the listing */
76enum { 76#define STYLE_AUTO (0)
77 STYLE_AUTO = 0, 77#define STYLE_COLUMNS (1U<<21) /* fill columns */
78 STYLE_LONG = 1, /* one record per line, extended info */ 78#define STYLE_LONG (2U<<21) /* one record per line, extended info */
79 STYLE_SINGLE = 2, /* one record per line */ 79#define STYLE_SINGLE (3U<<21) /* one record per line */
80 STYLE_COLUMNS = 3 /* fill columns */ 80
81}; 81#define STYLE_MASK STYLE_SINGLE
82#define STYLE_ONE_RECORD_FLAG STYLE_LONG
82 83
83/* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */ 84/* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */
84/* what file information will be listed */ 85/* what file information will be listed */
85#define LIST_INO (1<<0) 86#define LIST_INO (1U<<0)
86#define LIST_BLOCKS (1<<1) 87#define LIST_BLOCKS (1U<<1)
87#define LIST_MODEBITS (1<<2) 88#define LIST_MODEBITS (1U<<2)
88#define LIST_NLINKS (1<<3) 89#define LIST_NLINKS (1U<<3)
89#define LIST_ID_NAME (1<<4) 90#define LIST_ID_NAME (1U<<4)
90#define LIST_ID_NUMERIC (1<<5) 91#define LIST_ID_NUMERIC (1U<<5)
91#define LIST_SIZE (1<<6) 92#define LIST_SIZE (1U<<6)
92#define LIST_DEV (1<<7) 93#define LIST_DEV (1U<<7)
93#define LIST_DATE_TIME (1<<8) 94#define LIST_DATE_TIME (1U<<8)
94#define LIST_FULLTIME (1<<9) 95#define LIST_FULLTIME (1U<<9)
95#define LIST_FILENAME (1<<10) 96#define LIST_FILENAME (1U<<10)
96#define LIST_SYMLINK (1<<11) 97#define LIST_SYMLINK (1U<<11)
97#define LIST_FILETYPE (1<<12) 98#define LIST_FILETYPE (1U<<12)
98#define LIST_EXEC (1<<13) 99#define LIST_EXEC (1U<<13)
100
101#define LIST_MASK ((LIST_EXEC << 1) - 1)
99 102
100/* what files will be displayed */ 103/* what files will be displayed */
101#define DISP_NORMAL (0) /* show normal filenames */ 104/* TODO -- We may be able to make DISP_NORMAL 0 to save a bit slot. */
102#define DISP_DIRNAME (1<<0) /* 2 or more items? label directories */ 105#define DISP_NORMAL (1U<<14) /* show normal filenames */
103#define DISP_HIDDEN (1<<1) /* show filenames starting with . */ 106#define DISP_DIRNAME (1U<<15) /* 2 or more items? label directories */
104#define DISP_DOT (1<<2) /* show . and .. */ 107#define DISP_HIDDEN (1U<<16) /* show filenames starting with . */
105#define DISP_NOLIST (1<<3) /* show directory as itself, not contents */ 108#define DISP_DOT (1U<<17) /* show . and .. */
106#define DISP_RECURSIVE (1<<4) /* show directory and everything below it */ 109#define DISP_NOLIST (1U<<18) /* show directory as itself, not contents */
107#define DISP_ROWS (1<<5) /* print across rows */ 110#define DISP_RECURSIVE (1U<<19) /* show directory and everything below it */
111#define DISP_ROWS (1U<<20) /* print across rows */
112
113#define DISP_MASK (((DISP_ROWS << 1) - 1) & ~(DISP_NORMAL - 1))
108 114
109#ifdef CONFIG_FEATURE_LS_SORTFILES 115#ifdef CONFIG_FEATURE_LS_SORTFILES
110/* how will the files be sorted */ 116/* how will the files be sorted */
111static const int SORT_FORWARD = 0; /* sort in reverse order */ 117#define SORT_ORDER_FORWARD 0 /* sort in reverse order */
112static const int SORT_REVERSE = 1; /* sort in reverse order */ 118#define SORT_ORDER_REVERSE (1U<<27) /* sort in reverse order */
113static const int SORT_NAME = 2; /* sort by file name */ 119
114static const int SORT_SIZE = 3; /* sort by file size */ 120#define SORT_NAME 0 /* sort by file name */
115static const int SORT_ATIME = 4; /* sort by last access time */ 121#define SORT_SIZE (1U<<28) /* sort by file size */
116static const int SORT_CTIME = 5; /* sort by last change time */ 122#define SORT_ATIME (2U<<28) /* sort by last access time */
117static const int SORT_MTIME = 6; /* sort by last modification time */ 123#define SORT_CTIME (3U<<28) /* sort by last change time */
118static const int SORT_VERSION = 7; /* sort by version */ 124#define SORT_MTIME (4U<<28) /* sort by last modification time */
119static const int SORT_EXT = 8; /* sort by file name extension */ 125#define SORT_VERSION (5U<<28) /* sort by version */
120static const int SORT_DIR = 9; /* sort by file or directory */ 126#define SORT_EXT (6U<<28) /* sort by file name extension */
127#define SORT_DIR (7U<<28) /* sort by file or directory */
128
129#define SORT_MASK (7U<<28)
121#endif 130#endif
122 131
123#ifdef CONFIG_FEATURE_LS_TIMESTAMPS 132#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
124/* which of the three times will be used */ 133/* which of the three times will be used */
125static const int TIME_MOD = 0; 134#define TIME_MOD 0
126static const int TIME_CHANGE = 1; 135#define TIME_CHANGE (1U<<23)
127static const int TIME_ACCESS = 2; 136#define TIME_ACCESS (1U<<24)
137
138#define TIME_MASK (3U<<23)
139#endif
140
141#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
142#define FOLLOW_LINKS (1U<<25)
143#endif
144#ifdef CONFIG_FEATURE_HUMAN_READABLE
145#define LS_DISP_HR (1U<<26)
128#endif 146#endif
129 147
130#define LIST_SHORT (LIST_FILENAME) 148#define LIST_SHORT (LIST_FILENAME)
@@ -133,9 +151,9 @@ static const int TIME_ACCESS = 2;
133 LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK) 151 LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK)
134#define LIST_ILONG (LIST_INO | LIST_LONG) 152#define LIST_ILONG (LIST_INO | LIST_LONG)
135 153
136static const int SPLIT_DIR = 0; 154#define SPLIT_DIR 1
137static const int SPLIT_FILE = 1; 155#define SPLIT_FILE 0
138static const int SPLIT_SUBDIR = 2; 156#define SPLIT_SUBDIR 2
139 157
140#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) 158#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
141#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) 159#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
@@ -169,20 +187,7 @@ static struct dnode **list_dir(const char *);
169static struct dnode **dnalloc(int); 187static struct dnode **dnalloc(int);
170static int list_single(struct dnode *); 188static int list_single(struct dnode *);
171 189
172static unsigned int disp_opts; 190static unsigned int all_fmt;
173static unsigned int style_fmt;
174static unsigned int list_fmt;
175
176#ifdef CONFIG_FEATURE_LS_SORTFILES
177static unsigned int sort_opts;
178static unsigned int sort_order;
179#endif
180#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
181static unsigned int time_fmt;
182#endif
183#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
184static unsigned int follow_links = FALSE;
185#endif
186 191
187#ifdef CONFIG_FEATURE_AUTOWIDTH 192#ifdef CONFIG_FEATURE_AUTOWIDTH
188static unsigned short terminal_width = TERMINAL_WIDTH; 193static unsigned short terminal_width = TERMINAL_WIDTH;
@@ -194,26 +199,22 @@ static unsigned short tabstops = COLUMN_GAP;
194 199
195static int status = EXIT_SUCCESS; 200static int status = EXIT_SUCCESS;
196 201
197#ifdef CONFIG_FEATURE_HUMAN_READABLE
198static unsigned long ls_disp_hr = 0;
199#endif
200
201static struct dnode *my_stat(char *fullname, char *name) 202static struct dnode *my_stat(char *fullname, char *name)
202{ 203{
203 struct stat dstat; 204 struct stat dstat;
204 struct dnode *cur; 205 struct dnode *cur;
205 206
206#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS 207#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
207 if (follow_links) { 208 if (all_fmt & FOLLOW_LINKS) {
208 if (stat(fullname, &dstat)) { 209 if (stat(fullname, &dstat)) {
209 perror_msg("%s", fullname); 210 bb_perror_msg("%s", fullname);
210 status = EXIT_FAILURE; 211 status = EXIT_FAILURE;
211 return 0; 212 return 0;
212 } 213 }
213 } else 214 } else
214#endif 215#endif
215 if (lstat(fullname, &dstat)) { 216 if (lstat(fullname, &dstat)) {
216 perror_msg("%s", fullname); 217 bb_perror_msg("%s", fullname);
217 status = EXIT_FAILURE; 218 status = EXIT_FAILURE;
218 return 0; 219 return 0;
219 } 220 }
@@ -253,9 +254,9 @@ static char bgcolor(mode_t mode)
253#if defined(CONFIG_FEATURE_LS_FILETYPES) || defined(CONFIG_FEATURE_LS_COLOR) 254#if defined(CONFIG_FEATURE_LS_FILETYPES) || defined(CONFIG_FEATURE_LS_COLOR)
254static char append_char(mode_t mode) 255static char append_char(mode_t mode)
255{ 256{
256 if (!(list_fmt & LIST_FILETYPE)) 257 if (!(all_fmt & LIST_FILETYPE))
257 return '\0'; 258 return '\0';
258 if ((list_fmt & LIST_EXEC) && S_ISREG(mode) 259 if ((all_fmt & LIST_EXEC) && S_ISREG(mode)
259 && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) 260 && (mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
260 return '*'; 261 return '*';
261 return APPCHAR(mode); 262 return APPCHAR(mode);
@@ -263,13 +264,11 @@ static char append_char(mode_t mode)
263#endif 264#endif
264 265
265/*----------------------------------------------------------------------*/ 266/*----------------------------------------------------------------------*/
266static int is_subdir(struct dnode *dn)
267{
268 return (S_ISDIR(dn->dstat.st_mode) && strcmp(dn->name, ".") != 0 &&
269 strcmp(dn->name, "..") != 0);
270}
271 267
272static int countdirs(struct dnode **dn, int nfiles) 268#define countdirs(A,B) count_dirs((A), (B), 1)
269#define countsubdirs(A,B) count_dirs((A), (B), 0)
270
271static int count_dirs(struct dnode **dn, int nfiles, int notsubdirs)
273{ 272{
274 int i, dirs; 273 int i, dirs;
275 274
@@ -277,25 +276,17 @@ static int countdirs(struct dnode **dn, int nfiles)
277 return (0); 276 return (0);
278 dirs = 0; 277 dirs = 0;
279 for (i = 0; i < nfiles; i++) { 278 for (i = 0; i < nfiles; i++) {
280 if (S_ISDIR(dn[i]->dstat.st_mode)) 279 if (S_ISDIR(dn[i]->dstat.st_mode)
280 && (notsubdirs
281 || ((dn[i]->name[0] != '.')
282 || (dn[i]->name[1]
283 && ((dn[i]->name[1] != '.')
284 || dn[i]->name[2])))))
281 dirs++; 285 dirs++;
282 } 286 }
283 return (dirs); 287 return (dirs);
284} 288}
285 289
286static int countsubdirs(struct dnode **dn, int nfiles)
287{
288 int i, subdirs;
289
290 if (dn == NULL || nfiles < 1)
291 return 0;
292 subdirs = 0;
293 for (i = 0; i < nfiles; i++)
294 if (is_subdir(dn[i]))
295 subdirs++;
296 return subdirs;
297}
298
299static int countfiles(struct dnode **dnp) 290static int countfiles(struct dnode **dnp)
300{ 291{
301 int nfiles; 292 int nfiles;
@@ -364,18 +355,18 @@ static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
364 355
365 /* copy the entrys into the file or dir array */ 356 /* copy the entrys into the file or dir array */
366 for (d = i = 0; i < nfiles; i++) { 357 for (d = i = 0; i < nfiles; i++) {
367 if (which == SPLIT_DIR) { 358 if (S_ISDIR(dn[i]->dstat.st_mode)) {
368 if (S_ISDIR(dn[i]->dstat.st_mode)) { 359 if (which & (SPLIT_DIR|SPLIT_SUBDIR)) {
369 dnp[d++] = dn[i]; 360 if ((which & SPLIT_DIR)
370 } /* else skip the file */ 361 || ((dn[i]->name[0] != '.')
371 } else if (which == SPLIT_SUBDIR) { 362 || (dn[i]->name[1]
372 if (is_subdir(dn[i])) { 363 && ((dn[i]->name[1] != '.')
373 dnp[d++] = dn[i]; 364 || dn[i]->name[2])))) {
374 } /* else skip the file or dir */ 365 dnp[d++] = dn[i];
375 } else { 366 }
376 if (!(S_ISDIR(dn[i]->dstat.st_mode))) { 367 }
377 dnp[d++] = dn[i]; 368 } else if (!(which & (SPLIT_DIR|SPLIT_SUBDIR))) {
378 } /* else skip the dir */ 369 dnp[d++] = dn[i];
379 } 370 }
380 } 371 }
381 return (dnp); 372 return (dnp);
@@ -385,29 +376,24 @@ static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
385#ifdef CONFIG_FEATURE_LS_SORTFILES 376#ifdef CONFIG_FEATURE_LS_SORTFILES
386static int sortcmp(struct dnode *d1, struct dnode *d2) 377static int sortcmp(struct dnode *d1, struct dnode *d2)
387{ 378{
388 int cmp, dif; 379 unsigned int sort_opts = all_fmt & SORT_MASK;
380 int dif;
389 381
390 cmp = 0; 382 dif = 0; /* assume SORT_NAME */
391 if (sort_opts == SORT_SIZE) { 383 if (sort_opts == SORT_SIZE) {
392 dif = (int) (d1->dstat.st_size - d2->dstat.st_size); 384 dif = (int) (d2->dstat.st_size - d1->dstat.st_size);
393 } else if (sort_opts == SORT_ATIME) { 385 } else if (sort_opts == SORT_ATIME) {
394 dif = (int) (d1->dstat.st_atime - d2->dstat.st_atime); 386 dif = (int) (d2->dstat.st_atime - d1->dstat.st_atime);
395 } else if (sort_opts == SORT_CTIME) { 387 } else if (sort_opts == SORT_CTIME) {
396 dif = (int) (d1->dstat.st_ctime - d2->dstat.st_ctime); 388 dif = (int) (d2->dstat.st_ctime - d1->dstat.st_ctime);
397 } else if (sort_opts == SORT_MTIME) { 389 } else if (sort_opts == SORT_MTIME) {
398 dif = (int) (d1->dstat.st_mtime - d2->dstat.st_mtime); 390 dif = (int) (d2->dstat.st_mtime - d1->dstat.st_mtime);
399 } else if (sort_opts == SORT_DIR) { 391 } else if (sort_opts == SORT_DIR) {
400 dif = S_ISDIR(d1->dstat.st_mode) - S_ISDIR(d2->dstat.st_mode); 392 dif = S_ISDIR(d2->dstat.st_mode) - S_ISDIR(d1->dstat.st_mode);
401 /* } else if (sort_opts == SORT_VERSION) { */ 393 /* } else if (sort_opts == SORT_VERSION) { */
402 /* } else if (sort_opts == SORT_EXT) { */ 394 /* } else if (sort_opts == SORT_EXT) { */
403 } else { /* assume SORT_NAME */
404 dif = 0;
405 } 395 }
406 396
407 if (dif > 0)
408 cmp = -1;
409 if (dif < 0)
410 cmp = 1;
411 if (dif == 0) { 397 if (dif == 0) {
412 /* sort by name- may be a tie_breaker for time or size cmp */ 398 /* sort by name- may be a tie_breaker for time or size cmp */
413#ifdef CONFIG_LOCALE_SUPPORT 399#ifdef CONFIG_LOCALE_SUPPORT
@@ -415,16 +401,12 @@ static int sortcmp(struct dnode *d1, struct dnode *d2)
415#else 401#else
416 dif = strcmp(d1->name, d2->name); 402 dif = strcmp(d1->name, d2->name);
417#endif 403#endif
418 if (dif > 0)
419 cmp = 1;
420 if (dif < 0)
421 cmp = -1;
422 } 404 }
423 405
424 if (sort_order == SORT_REVERSE) { 406 if (all_fmt & SORT_ORDER_REVERSE) {
425 cmp = -1 * cmp; 407 dif = -dif;
426 } 408 }
427 return (cmp); 409 return (dif);
428} 410}
429 411
430/*----------------------------------------------------------------------*/ 412/*----------------------------------------------------------------------*/
@@ -463,20 +445,17 @@ static void showfiles(struct dnode **dn, int nfiles)
463 if (dn == NULL || nfiles < 1) 445 if (dn == NULL || nfiles < 1)
464 return; 446 return;
465 447
466 switch (style_fmt) { 448 if (all_fmt & STYLE_ONE_RECORD_FLAG) {
467 case STYLE_LONG: /* one record per line, extended info */
468 case STYLE_SINGLE: /* one record per line */
469 ncols = 1; 449 ncols = 1;
470 break; 450 } else {
471 default: 451 /* find the longest file name- use that as the column width */
472 /* find the longest file name- use that as the column width */ 452 for (i = 0; i < nfiles; i++) {
473 for (i = 0; i < nfiles; i++) {
474 int len = strlen(dn[i]->name) + 453 int len = strlen(dn[i]->name) +
475 ((list_fmt & LIST_INO) ? 8 : 0) + 454 ((all_fmt & LIST_INO) ? 8 : 0) +
476 ((list_fmt & LIST_BLOCKS) ? 5 : 0); 455 ((all_fmt & LIST_BLOCKS) ? 5 : 0);
477 if (column_width < len) 456 if (column_width < len)
478 column_width = len; 457 column_width = len;
479 } 458 }
480 column_width += tabstops; 459 column_width += tabstops;
481 ncols = (int) (terminal_width / column_width); 460 ncols = (int) (terminal_width / column_width);
482 } 461 }
@@ -494,7 +473,7 @@ static void showfiles(struct dnode **dn, int nfiles)
494 for (nc = 0; nc < ncols; nc++) { 473 for (nc = 0; nc < ncols; nc++) {
495 /* reach into the array based on the column and row */ 474 /* reach into the array based on the column and row */
496 i = (nc * nrows) + row; /* assume display by column */ 475 i = (nc * nrows) + row; /* assume display by column */
497 if (disp_opts & DISP_ROWS) 476 if (all_fmt & DISP_ROWS)
498 i = (row * ncols) + nc; /* display across row */ 477 i = (row * ncols) + nc; /* display across row */
499 if (i < nfiles) { 478 if (i < nfiles) {
500 if (column > 0) { 479 if (column > 0) {
@@ -528,7 +507,7 @@ static void showdirs(struct dnode **dn, int ndirs)
528 return; 507 return;
529 508
530 for (i = 0; i < ndirs; i++) { 509 for (i = 0; i < ndirs; i++) {
531 if (disp_opts & (DISP_DIRNAME | DISP_RECURSIVE)) { 510 if (all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) {
532 printf("\n%s:\n", dn[i]->fullname); 511 printf("\n%s:\n", dn[i]->fullname);
533 } 512 }
534 subdnp = list_dir(dn[i]->fullname); 513 subdnp = list_dir(dn[i]->fullname);
@@ -540,7 +519,7 @@ static void showdirs(struct dnode **dn, int ndirs)
540#endif 519#endif
541 showfiles(subdnp, nfiles); 520 showfiles(subdnp, nfiles);
542#ifdef CONFIG_FEATURE_LS_RECURSIVE 521#ifdef CONFIG_FEATURE_LS_RECURSIVE
543 if (disp_opts & DISP_RECURSIVE) { 522 if (all_fmt & DISP_RECURSIVE) {
544 /* recursive- list the sub-dirs */ 523 /* recursive- list the sub-dirs */
545 dnd = splitdnarray(subdnp, nfiles, SPLIT_SUBDIR); 524 dnd = splitdnarray(subdnp, nfiles, SPLIT_SUBDIR);
546 dndirs = countsubdirs(subdnp, nfiles); 525 dndirs = countsubdirs(subdnp, nfiles);
@@ -573,7 +552,7 @@ static struct dnode **list_dir(const char *path)
573 nfiles = 0; 552 nfiles = 0;
574 dir = opendir(path); 553 dir = opendir(path);
575 if (dir == NULL) { 554 if (dir == NULL) {
576 perror_msg("%s", path); 555 bb_perror_msg("%s", path);
577 status = EXIT_FAILURE; 556 status = EXIT_FAILURE;
578 return (NULL); /* could not open the dir */ 557 return (NULL); /* could not open the dir */
579 } 558 }
@@ -585,9 +564,9 @@ static struct dnode **list_dir(const char *path)
585 if ((entry->d_name[1] == 0 || ( 564 if ((entry->d_name[1] == 0 || (
586 entry->d_name[1] == '.' 565 entry->d_name[1] == '.'
587 && entry->d_name[2] == 0)) 566 && entry->d_name[2] == 0))
588 && !(disp_opts & DISP_DOT)) 567 && !(all_fmt & DISP_DOT))
589 continue; 568 continue;
590 if (!(disp_opts & DISP_HIDDEN)) 569 if (!(all_fmt & DISP_HIDDEN))
591 continue; 570 continue;
592 } 571 }
593 fullname = concat_path_file(path, entry->d_name); 572 fullname = concat_path_file(path, entry->d_name);
@@ -636,9 +615,9 @@ static int list_single(struct dnode *dn)
636 615
637#ifdef CONFIG_FEATURE_LS_TIMESTAMPS 616#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
638 ttime = dn->dstat.st_mtime; /* the default time */ 617 ttime = dn->dstat.st_mtime; /* the default time */
639 if (time_fmt & TIME_ACCESS) 618 if (all_fmt & TIME_ACCESS)
640 ttime = dn->dstat.st_atime; 619 ttime = dn->dstat.st_atime;
641 if (time_fmt & TIME_CHANGE) 620 if (all_fmt & TIME_CHANGE)
642 ttime = dn->dstat.st_ctime; 621 ttime = dn->dstat.st_ctime;
643 filetime = ctime(&ttime); 622 filetime = ctime(&ttime);
644#endif 623#endif
@@ -647,7 +626,7 @@ static int list_single(struct dnode *dn)
647#endif 626#endif
648 627
649 for (i = 0; i <= 31; i++) { 628 for (i = 0; i <= 31; i++) {
650 switch (list_fmt & (1 << i)) { 629 switch (all_fmt & (1 << i)) {
651 case LIST_INO: 630 case LIST_INO:
652 column += printf("%7ld ", (long int) dn->dstat.st_ino); 631 column += printf("%7ld ", (long int) dn->dstat.st_ino);
653 break; 632 break;
@@ -659,7 +638,7 @@ static int list_single(struct dnode *dn)
659#endif 638#endif
660 break; 639 break;
661 case LIST_MODEBITS: 640 case LIST_MODEBITS:
662 column += printf("%-10s ", (char *) mode_string(dn->dstat.st_mode)); 641 column += printf("%-10s ", (char *) bb_mode_string(dn->dstat.st_mode));
663 break; 642 break;
664 case LIST_NLINKS: 643 case LIST_NLINKS:
665 column += printf("%4ld ", (long) dn->dstat.st_nlink); 644 column += printf("%4ld ", (long) dn->dstat.st_nlink);
@@ -683,7 +662,7 @@ static int list_single(struct dnode *dn)
683 (int) MINOR(dn->dstat.st_rdev)); 662 (int) MINOR(dn->dstat.st_rdev));
684 } else { 663 } else {
685#ifdef CONFIG_FEATURE_HUMAN_READABLE 664#ifdef CONFIG_FEATURE_HUMAN_READABLE
686 if (ls_disp_hr == TRUE) { 665 if (all_fmt & LS_DISP_HR) {
687 column += printf("%9s ", 666 column += printf("%9s ",
688 make_human_readable_str(dn->dstat.st_size, 1, 0)); 667 make_human_readable_str(dn->dstat.st_size, 1, 0));
689 } else 668 } else
@@ -700,7 +679,7 @@ static int list_single(struct dnode *dn)
700#ifdef CONFIG_FEATURE_LS_TIMESTAMPS 679#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
701 case LIST_FULLTIME: 680 case LIST_FULLTIME:
702 case LIST_DATE_TIME: 681 case LIST_DATE_TIME:
703 if (list_fmt & LIST_FULLTIME) { 682 if (all_fmt & LIST_FULLTIME) {
704 printf("%24.24s ", filetime); 683 printf("%24.24s ", filetime);
705 column += 25; 684 column += 25;
706 break; 685 break;
@@ -774,47 +753,8 @@ static int list_single(struct dnode *dn)
774} 753}
775 754
776/*----------------------------------------------------------------------*/ 755/*----------------------------------------------------------------------*/
777extern int ls_main(int argc, char **argv)
778{
779 struct dnode **dnf, **dnd;
780 int dnfiles, dndirs;
781 struct dnode *dn, *cur, **dnp;
782 int i, nfiles;
783 int opt;
784 int oi, ac;
785 char **av;
786
787#ifdef CONFIG_FEATURE_AUTOWIDTH
788 struct winsize win = { 0, 0, 0, 0 };
789#endif
790
791 disp_opts = DISP_NORMAL;
792 style_fmt = STYLE_AUTO;
793 list_fmt = LIST_SHORT;
794#ifdef CONFIG_FEATURE_LS_SORTFILES
795 sort_opts = SORT_NAME;
796 sort_order = SORT_FORWARD;
797#endif
798#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
799 time_fmt = TIME_MOD;
800#endif
801#ifdef CONFIG_FEATURE_AUTOWIDTH
802 ioctl(fileno(stdout), TIOCGWINSZ, &win);
803 if (win.ws_col > 0)
804 terminal_width = win.ws_col - 1;
805#endif
806 nfiles = 0;
807 756
808#ifdef CONFIG_FEATURE_LS_COLOR 757static const char ls_opts[] = "1AaCdgilnsx"
809 if (isatty(fileno(stdout)))
810 show_color = 1;
811#endif
812
813 /* process options */
814 while ((opt = getopt(argc, argv, "1AaCdgilnsx"
815#ifdef CONFIG_FEATURE_AUTOWIDTH
816 "T:w:"
817#endif
818#ifdef CONFIG_FEATURE_LS_FILETYPES 758#ifdef CONFIG_FEATURE_LS_FILETYPES
819 "Fp" 759 "Fp"
820#endif 760#endif
@@ -825,7 +765,7 @@ extern int ls_main(int argc, char **argv)
825 "rSvX" 765 "rSvX"
826#endif 766#endif
827#ifdef CONFIG_FEATURE_LS_TIMESTAMPS 767#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
828 "cetu" 768 "ecut"
829#endif 769#endif
830#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS 770#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
831 "L" 771 "L"
@@ -833,141 +773,180 @@ extern int ls_main(int argc, char **argv)
833#ifdef CONFIG_FEATURE_HUMAN_READABLE 773#ifdef CONFIG_FEATURE_HUMAN_READABLE
834 "h" 774 "h"
835#endif 775#endif
836 "k")) > 0) { 776 "k"
837 switch (opt) { 777#ifdef CONFIG_FEATURE_AUTOWIDTH
838 case '1': 778 "T:w:"
839 style_fmt = STYLE_SINGLE;
840 list_fmt = LIST_SHORT;
841 break;
842 case 'A':
843 disp_opts |= DISP_HIDDEN;
844 break;
845 case 'a':
846 disp_opts |= DISP_HIDDEN | DISP_DOT;
847 break;
848 case 'C':
849 style_fmt = STYLE_COLUMNS;
850 list_fmt = LIST_SHORT;
851 break;
852 case 'd':
853 disp_opts |= DISP_NOLIST;
854 break;
855 case 'g': /* ignore -- for ftp servers */
856 break;
857 case 'i':
858 list_fmt |= LIST_INO;
859 break;
860 case 'l':
861 style_fmt = STYLE_LONG;
862 list_fmt |= LIST_LONG;
863#ifdef CONFIG_FEATURE_HUMAN_READABLE
864 ls_disp_hr = FALSE;
865#endif 779#endif
866 break; 780 ;
867 case 'n': 781
868 list_fmt |= LIST_ID_NUMERIC; 782#define LIST_MASK_TRIGGER LIST_SHORT
869 break; 783#define STYLE_MASK_TRIGGER STYLE_MASK
870 case 's': 784#define SORT_MASK_TRIGGER SORT_MASK
871 list_fmt |= LIST_BLOCKS; 785#define DISP_MASK_TRIGGER DISP_ROWS
872 break; 786#define TIME_MASK_TRIGGER TIME_MASK
873 case 'x': 787
874 disp_opts = DISP_ROWS; 788static const unsigned opt_flags[] = {
875 break; 789 LIST_SHORT | STYLE_SINGLE, /* 1 */
790 DISP_HIDDEN, /* A */
791 DISP_HIDDEN | DISP_DOT, /* a */
792 LIST_SHORT | STYLE_COLUMNS, /* C */
793 DISP_NOLIST, /* d */
794 0, /* g - ingored */
795 LIST_INO, /* i */
796 LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */
797 LIST_ID_NUMERIC, /* n */
798 LIST_BLOCKS, /* s */
799 DISP_ROWS, /* x */
876#ifdef CONFIG_FEATURE_LS_FILETYPES 800#ifdef CONFIG_FEATURE_LS_FILETYPES
877 case 'F': 801 LIST_FILETYPE | LIST_EXEC, /* F */
878 list_fmt |= LIST_FILETYPE | LIST_EXEC; 802 LIST_FILETYPE, /* p */
879 break;
880 case 'p':
881 list_fmt |= LIST_FILETYPE;
882 break;
883#endif 803#endif
884#ifdef CONFIG_FEATURE_LS_RECURSIVE 804#ifdef CONFIG_FEATURE_LS_RECURSIVE
885 case 'R': 805 DISP_RECURSIVE, /* R */
886 disp_opts |= DISP_RECURSIVE;
887 break;
888#endif 806#endif
889#ifdef CONFIG_FEATURE_LS_SORTFILES 807#ifdef CONFIG_FEATURE_LS_SORTFILES
890 case 'r': 808 SORT_ORDER_REVERSE, /* r */
891 sort_order |= SORT_REVERSE; 809 SORT_SIZE, /* S */
892 break; 810 SORT_VERSION, /* v */
893 case 'S': 811 SORT_EXT, /* v */
894 sort_opts = SORT_SIZE;
895 break;
896 case 'v':
897 sort_opts = SORT_VERSION;
898 break;
899 case 'X':
900 sort_opts = SORT_EXT;
901 break;
902#endif 812#endif
903#ifdef CONFIG_FEATURE_LS_TIMESTAMPS 813#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
904 case 'e': 814 LIST_FULLTIME, /* e */
905 list_fmt |= LIST_FULLTIME;
906 break;
907 case 'c':
908 time_fmt = TIME_CHANGE;
909#ifdef CONFIG_FEATURE_LS_SORTFILES 815#ifdef CONFIG_FEATURE_LS_SORTFILES
910 sort_opts = SORT_CTIME; 816 TIME_CHANGE | SORT_CTIME, /* c */
817#else
818 TIME_CHANGE, /* c */
911#endif 819#endif
912 break;
913 case 'u':
914 time_fmt = TIME_ACCESS;
915#ifdef CONFIG_FEATURE_LS_SORTFILES 820#ifdef CONFIG_FEATURE_LS_SORTFILES
916 sort_opts = SORT_ATIME; 821 TIME_ACCESS | SORT_ATIME, /* u */
822#else
823 TIME_ACCESS, /* u */
917#endif 824#endif
918 break;
919 case 't':
920#ifdef CONFIG_FEATURE_LS_SORTFILES 825#ifdef CONFIG_FEATURE_LS_SORTFILES
921 sort_opts = SORT_MTIME; 826 SORT_MTIME, /* t */
827#else
828 0, /* t - ignored -- is this correct? */
922#endif 829#endif
923 break;
924#endif 830#endif
925#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS 831#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
926 case 'L': 832 FOLLOW_LINKS, /* L */
927 follow_links = TRUE; 833#endif
928 break; 834#ifdef CONFIG_FEATURE_HUMAN_READABLE
835LS_DISP_HR, /* h */
836#endif
837 0, /* k - ingored */
838};
839
840
841/*----------------------------------------------------------------------*/
842
843extern int ls_main(int argc, char **argv)
844{
845 struct dnode **dnf, **dnd;
846 int dnfiles, dndirs;
847 struct dnode *dn, *cur, **dnp;
848 int i, nfiles;
849 int opt;
850 int oi, ac;
851 char **av;
852
853#ifdef CONFIG_FEATURE_AUTOWIDTH
854 struct winsize win = { 0, 0, 0, 0 };
855#endif
856
857 all_fmt = LIST_SHORT | DISP_NORMAL | STYLE_AUTO
858#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
859 | TIME_MOD
860#endif
861#ifdef CONFIG_FEATURE_LS_SORTFILES
862 | SORT_NAME | SORT_ORDER_FORWARD
863#endif
864 ;
865#ifdef CONFIG_FEATURE_AUTOWIDTH
866 ioctl(fileno(stdout), TIOCGWINSZ, &win);
867 if (win.ws_col > 0)
868 terminal_width = win.ws_col - 1;
869#endif
870 nfiles = 0;
871
872#ifdef CONFIG_FEATURE_LS_COLOR
873 if (isatty(fileno(stdout)))
874 show_color = 1;
929#endif 875#endif
876
877 /* process options */
878 while ((opt = getopt(argc, argv, ls_opts)) > 0) {
930#ifdef CONFIG_FEATURE_AUTOWIDTH 879#ifdef CONFIG_FEATURE_AUTOWIDTH
931 case 'T': 880 if (opt == 'T') {
932 tabstops = atoi(optarg); 881 tabstops = atoi(optarg);
933 break; 882 continue;
934 case 'w': 883 }
884 if (opt == 'w') {
935 terminal_width = atoi(optarg); 885 terminal_width = atoi(optarg);
936 break; 886 continue;
887 }
888 if (opt == ':') {
889 goto print_usage_message;
890 }
937#endif 891#endif
892 {
893 unsigned int flags;
894 const char *p = strchr(ls_opts, opt);
895 if (!p) { /* shouldn't be necessary */
896 goto print_usage_message;
897 }
898 flags = opt_flags[(int)(p - ls_opts)];
899 if (flags & LIST_MASK_TRIGGER) {
900 all_fmt &= ~LIST_MASK;
901 }
902 if (flags & STYLE_MASK_TRIGGER) {
903 all_fmt &= ~STYLE_MASK;
904 }
905 if (flags & SORT_MASK_TRIGGER) {
906 all_fmt &= ~SORT_MASK;
907 }
908 if (flags & DISP_MASK_TRIGGER) {
909 all_fmt &= ~DISP_MASK;
910 }
911 if (flags & TIME_MASK_TRIGGER) {
912 all_fmt &= ~TIME_MASK;
913 }
938#ifdef CONFIG_FEATURE_HUMAN_READABLE 914#ifdef CONFIG_FEATURE_HUMAN_READABLE
939 case 'h': 915 if (opt == 'l') {
940 ls_disp_hr = TRUE; 916 all_fmt &= ~LS_DISP_HR;
941 break; 917 }
942#endif 918#endif
943 case 'k': 919 all_fmt |= flags;
944 break;
945 default:
946 goto print_usage_message;
947 } 920 }
948 } 921 }
949 922
923
950 /* sort out which command line options take precedence */ 924 /* sort out which command line options take precedence */
951#ifdef CONFIG_FEATURE_LS_RECURSIVE 925#ifdef CONFIG_FEATURE_LS_RECURSIVE
952 if (disp_opts & DISP_NOLIST) 926 if (all_fmt & DISP_NOLIST)
953 disp_opts &= ~DISP_RECURSIVE; /* no recurse if listing only dir */ 927 all_fmt &= ~DISP_RECURSIVE; /* no recurse if listing only dir */
954#endif 928#endif
955#if defined (CONFIG_FEATURE_LS_TIMESTAMPS) && defined (CONFIG_FEATURE_LS_SORTFILES) 929#if defined (CONFIG_FEATURE_LS_TIMESTAMPS) && defined (CONFIG_FEATURE_LS_SORTFILES)
956 if (time_fmt & TIME_CHANGE) 930 if (all_fmt & TIME_CHANGE)
957 sort_opts = SORT_CTIME; 931 all_fmt = (all_fmt & ~SORT_MASK) | SORT_CTIME;
958 if (time_fmt & TIME_ACCESS) 932 if (all_fmt & TIME_ACCESS)
959 sort_opts = SORT_ATIME; 933 all_fmt = (all_fmt & ~SORT_MASK) | SORT_ATIME;
960#endif 934#endif
961 if (style_fmt != STYLE_LONG) /* only for long list */ 935 if ((all_fmt & STYLE_MASK) != STYLE_LONG) /* only for long list */
962 list_fmt &= ~(LIST_ID_NUMERIC|LIST_FULLTIME|LIST_ID_NAME|LIST_ID_NUMERIC); 936 all_fmt &= ~(LIST_ID_NUMERIC|LIST_FULLTIME|LIST_ID_NAME|LIST_ID_NUMERIC);
963#ifdef CONFIG_FEATURE_LS_USERNAME 937#ifdef CONFIG_FEATURE_LS_USERNAME
964 if (style_fmt == STYLE_LONG && (list_fmt & LIST_ID_NUMERIC)) 938 if ((all_fmt & STYLE_MASK) == STYLE_LONG && (all_fmt & LIST_ID_NUMERIC))
965 list_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */ 939 all_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */
966#endif 940#endif
967 941
968 /* choose a display format */ 942 /* choose a display format */
969 if (style_fmt == STYLE_AUTO) 943 if ((all_fmt & STYLE_MASK) == STYLE_AUTO)
970 style_fmt = isatty(fileno(stdout)) ? STYLE_COLUMNS : STYLE_SINGLE; 944#if STYLE_AUTO != 0
945 all_fmt = (all_fmt & ~STYLE_MASK)
946 | (isatty(fileno(stdout)) ? STYLE_COLUMNS : STYLE_SINGLE);
947#else
948 all_fmt |= (isatty(fileno(stdout)) ? STYLE_COLUMNS : STYLE_SINGLE);
949#endif
971 950
972 /* 951 /*
973 * when there are no cmd line args we have to supply a default "." arg. 952 * when there are no cmd line args we have to supply a default "." arg.
@@ -979,7 +958,7 @@ extern int ls_main(int argc, char **argv)
979 ac = argc - optind; /* how many cmd line args are left */ 958 ac = argc - optind; /* how many cmd line args are left */
980 if (ac < 1) { 959 if (ac < 1) {
981 av = (char **) xcalloc((size_t) 1, (size_t) (sizeof(char *))); 960 av = (char **) xcalloc((size_t) 1, (size_t) (sizeof(char *)));
982 av[0] = xstrdup("."); 961 av[0] = bb_xstrdup(".");
983 ac = 1; 962 ac = 1;
984 } else { 963 } else {
985 av = (char **) xcalloc((size_t) ac, (size_t) (sizeof(char *))); 964 av = (char **) xcalloc((size_t) ac, (size_t) (sizeof(char *)));
@@ -990,12 +969,12 @@ extern int ls_main(int argc, char **argv)
990 969
991 /* now, everything is in the av array */ 970 /* now, everything is in the av array */
992 if (ac > 1) 971 if (ac > 1)
993 disp_opts |= DISP_DIRNAME; /* 2 or more items? label directories */ 972 all_fmt |= DISP_DIRNAME; /* 2 or more items? label directories */
994 973
995 /* stuff the command line file names into an dnode array */ 974 /* stuff the command line file names into an dnode array */
996 dn = NULL; 975 dn = NULL;
997 for (oi = 0; oi < ac; oi++) { 976 for (oi = 0; oi < ac; oi++) {
998 char *fullname = xstrdup(av[oi]); 977 char *fullname = bb_xstrdup(av[oi]);
999 978
1000 cur = my_stat(fullname, fullname); 979 cur = my_stat(fullname, fullname);
1001 if (!cur) 980 if (!cur)
@@ -1015,7 +994,7 @@ extern int ls_main(int argc, char **argv)
1015 } 994 }
1016 995
1017 996
1018 if (disp_opts & DISP_NOLIST) { 997 if (all_fmt & DISP_NOLIST) {
1019#ifdef CONFIG_FEATURE_LS_SORTFILES 998#ifdef CONFIG_FEATURE_LS_SORTFILES
1020 shellsort(dnp, nfiles); 999 shellsort(dnp, nfiles);
1021#endif 1000#endif
@@ -1042,5 +1021,5 @@ extern int ls_main(int argc, char **argv)
1042 return (status); 1021 return (status);
1043 1022
1044 print_usage_message: 1023 print_usage_message:
1045 show_usage(); 1024 bb_show_usage();
1046} 1025}