* it more portable.
*
* KNOWN BUGS:
- * 1. messy output if you mix files and directories on the command line
- * 2. ls -l of a directory doesn't give "total <blocks>" header
- * 3. ls of a symlink to a directory doesn't list directory contents
- * 4. hidden files can make column width too large
+ * 1. ls -l of a directory doesn't give "total <blocks>" header
+ * 2. ls of a symlink to a directory doesn't list directory contents
+ * 3. hidden files can make column width too large
+ *
* NON-OPTIMAL BEHAVIOUR:
* 1. autowidth reads directories twice
* 2. if you do a short directory listing without filetype characters
/************************************************************************/
#include "internal.h"
-#if !defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
-# include <linux/types.h>
-#else
# include <sys/types.h>
-#endif
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
#endif
-#ifndef MAJOR
-#define MAJOR(dev) (((dev)>>8)&0xff)
-#define MINOR(dev) ((dev)&0xff)
-#endif
-
#define FMT_AUTO 0
#define FMT_LONG 1 /* one record per line, extended info */
#define FMT_SINGLE 2 /* one record per line */
#define DISP_DOT 8 /* show . and .. */
#define DISP_NUMERIC 16 /* numeric uid and gid */
#define DISP_FULLTIME 32 /* show extended time display */
-#define DIR_NOLIST 64 /* show directory as itself, not contents */
+#define DIR_NOLIST 64 /* show directory as itself, not contents */
#define DISP_DIRNAME 128 /* show directory name (for internal use) */
-#define DIR_RECURSE 256 /* -R (not yet implemented) */
+#define DISP_RECURSIVE 256 /* Do a recursive listing */
+
+#ifndef MAJOR
+#define MAJOR(dev) (((dev)>>8)&0xff)
+#define MINOR(dev) ((dev)&0xff)
+#endif
static unsigned char display_fmt = FMT_AUTO;
static unsigned short opts = 0;
static unsigned short column = 0;
#ifdef BB_FEATURE_AUTOWIDTH
-static unsigned short terminal_width = 0, column_width = 0;
+static unsigned short terminal_width = 0;
+static unsigned short column_width = 0;
+static unsigned short toplevel_column_width = 0;
#else
#define terminal_width TERMINAL_WIDTH
#define column_width COLUMN_WIDTH
static void list_single(const char *name, struct stat *info,
const char *fullname)
{
- char scratch[PATH_MAX + 1];
+ char scratch[BUFSIZ + 1];
short len = strlen(name);
#ifdef BB_FEATURE_LS_FILETYPES
struct stat info;
DIR *dir;
struct dirent *entry;
- char fullname[MAXNAMLEN + 1], *fnend;
+ char fullname[BUFSIZ + 1], *fnend;
if (lstat(name, &info))
goto listerr;
if (!S_ISDIR(info.st_mode) || (opts & DIR_NOLIST)) {
+#ifdef BB_FEATURE_AUTOWIDTH
+ column_width = toplevel_column_width;
+#endif
list_single(name, &info, name);
return 0;
}
list_single(entry->d_name, &info, fullname);
}
closedir(dir);
+
+ if (opts & DISP_DIRNAME) { /* separate the directory */
+ if (column) {
+ wr("\n", 1);
+ }
+ wr("\n", 1);
+ column = 0;
+ }
+
return 0;
direrr:
#ifdef BB_FEATURE_LS_FILETYPES
"F"
#endif
-#ifdef FEATURE_RECURSIVE
+#ifdef BB_FEATURE_LS_RECURSIVE
"R"
#endif
- "] [filenames...]\n";
+ "] [filenames...]\n"
+#ifndef BB_FEATURE_TRIVIAL_HELP
+ "\nList directory contents\n\n"
+ "Options:\n"
+ "\t-a\tdo not hide entries starting with .\n"
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+ "\t-c\twith -l: show ctime (the time of last\n"
+ "\t\tmodification of file status information)\n"
+#endif
+ "\t-d\tlist directory entries instead of contents\n"
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+ "\t-e\tlist both full date and full time\n"
+#endif
+ "\t-l\tuse a long listing format\n"
+ "\t-n\tlist numeric UIDs and GIDs instead of names\n"
+#ifdef BB_FEATURE_LS_FILETYPES
+ "\t-p\tappend indicator (one of /=@|) to entries\n"
+#endif
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+ "\t-u\twith -l: show access time (the time of last\n"
+ "\t\taccess of the file)\n"
+#endif
+ "\t-x\tlist entries by lines instead of by columns\n"
+ "\t-A\tdo not list implied . and ..\n"
+ "\t-C\tlist entries by columns\n"
+#ifdef BB_FEATURE_LS_FILETYPES
+ "\t-F\tappend indicator (one of */=@|) to entries\n"
+#endif
+#ifdef BB_FEATURE_LS_RECURSIVE
+ "\t-R\tlist subdirectories recursively\n"
+#endif
+#endif
+ ;
+
+
+#ifdef BB_FEATURE_LS_RECURSIVE
+static int dirAction(const char *fileName, struct stat *statbuf, void* junk)
+{
+ int i;
+ fprintf(stdout, "\n%s:\n", fileName);
+ i = list_item(fileName);
+ newline();
+ return (i);
+}
+#endif
extern int ls_main(int argc, char **argv)
{
case 'd':
opts |= DIR_NOLIST;
break;
-#ifdef FEATURE_RECURSIVE
- case 'R':
- opts |= DIR_RECURSE;
- break;
-#endif
#ifdef BB_FEATURE_LS_TIMESTAMPS
case 'u':
time_fmt = TIME_ACCESS;
opts |= DISP_FULLTIME;
break;
#endif
+#ifdef BB_FEATURE_LS_RECURSIVE
+ case 'R':
+ opts |= DISP_RECURSIVE;
+ break;
+#endif
+ case 'g': /* ignore -- for ftp servers */
+ break;
default:
goto print_usage_message;
}
for (i = argi; i < argc; i++) {
int len = strlen(argv[i]);
- if (column_width < len)
- column_width = len;
+ if (toplevel_column_width < len)
+ toplevel_column_width = len;
}
#endif
/* process files specified, or current directory if none */
- i = 0;
- if (argi == argc)
- i = list_item(".");
- while (argi < argc)
- i |= list_item(argv[argi++]);
- newline();
+#ifdef BB_FEATURE_LS_RECURSIVE
+ if (opts & DISP_RECURSIVE) {
+ i = 0;
+ if (argi == argc) {
+ i = recursiveAction(".", TRUE, FALSE, FALSE, NULL, dirAction, NULL);
+ }
+ while (argi < argc) {
+ i |= recursiveAction(argv[argi++], TRUE, FALSE, FALSE, NULL, dirAction, NULL);
+ }
+ } else
+#endif
+ {
+ i = 0;
+ if (argi == argc)
+ i = list_item(".");
+ while (argi < argc)
+ i |= list_item(argv[argi++]);
+ newline();
+ }
exit(i);
print_usage_message: