#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)ls.c 5.17 (Berkeley) %G%";
+static char sccsid[] = "@(#)ls.c 5.25 (Berkeley) %G%";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
+#include <sys/ioctl.h>
#include <dirent.h>
#include <strings.h>
#include <errno.h>
#include <stdio.h>
#include "ls.h"
-int lstat(), strlen(), prablelen();
+int lstat(), strlen();
char *emalloc();
int qflg, Aflg, Cflg, Fflg, Lflg, Rflg, Sflg;
+int termwidth = 80; /* default terminal width */
+
/* flags */
int f_accesstime; /* use time of last access */
-int f_firsttime = 1; /* to control recursion */
int f_group; /* show group ownership of a file */
int f_ignorelink; /* indirect through symbolic link operands */
int f_inode; /* print inode */
char **argv;
{
extern int optind, stat();
+ struct winsize win;
int ch;
+ char *p, *getenv();
int namecmp(), revnamecmp(), acccmp(), revacccmp();
int modcmp(), revmodcmp(), statcmp(), revstatcmp();
+ int printcol(), printlong(), printscol();
/*
* terminal defaults to -C -q
*/
if (isatty(1)) {
f_nonprint = 1;
- lengthfcn = prablelen;
+ if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) {
+ if (p = getenv("COLUMNS"))
+ termwidth = atoi(p);
+ }
+ else
+ termwidth = win.ws_col;
} else
f_singlecol = 1;
break;
case 'q':
f_nonprint = 1;
- lengthfcn = prablelen;
break;
case 'r':
f_reversesort = 1;
f_recursive = 0;
/* if need to stat files */
- needstat = f_longform || f_recursive || f_timesort || f_size ||
- f_inode || f_type;
+ needstat = f_longform || f_recursive || f_timesort || f_size || f_type;
/* select a sort function */
if (f_reversesort) {
sortfcn = modcmp;
}
+ /* select a print function */
+ if (f_singlecol)
+ printfcn = printscol;
+ else if (f_longform)
+ printfcn = printlong;
+ else
+ printfcn = printcol;
+
if (argc)
- args(argc, argv);
+ doargs(argc, argv);
else
- curdir();
+ dodot();
exit(0);
}
-curdir()
+dodot()
{
LS local, *stats;
int num;
(void)fprintf(stderr, "ls: .: %s\n", strerror(errno));
exit(1);
}
- if (num = buildstats(&local, &stats, &names))
- ls(stats, num);
+ if (num = tabdir(&local, &stats, &names))
+ displaydir(stats, num);
}
static char path[MAXPATHLEN + 1];
static char *endofpath = path;
-args(argc, argv)
+doargs(argc, argv)
int argc;
char **argv;
{
- register LS *dstats, *rstats;
+ register LS *dstatp, *rstatp;
+ LS *dstats, *rstats;
register int cnt, dircnt, regcnt;
struct stat sb;
LS *stats;
int num, (*statfcn)(), stat(), lstat();
char *names, top[MAXPATHLEN + 1];
+ /*
+ * walk through the operands, building separate arrays of LS
+ * structures for directory and non-directory files.
+ */
dstats = rstats = NULL;
statfcn = f_ignorelink ? stat : lstat;
for (dircnt = regcnt = 0; *argv; ++argv) {
}
if (!f_specialdir && !f_listdir && S_ISDIR(sb.st_mode)) {
if (!dstats)
- dstats = (LS *)emalloc((u_int)argc *
+ dstatp = dstats = (LS *)emalloc((u_int)argc *
(sizeof(LS)));
- dstats[dircnt].name = *argv;
- dstats[dircnt].lstat = sb;
+ dstatp->name = *argv;
+ dstatp->lstat = sb;
+ ++dstatp;
++dircnt;
}
else {
if (!rstats)
- rstats = (LS *)emalloc((u_int)argc *
+ rstatp = rstats = (LS *)emalloc((u_int)argc *
(sizeof(LS)));
- rstats[regcnt].name = *argv;
- rstats[regcnt].lstat = sb;
+ rstatp->name = *argv;
+ rstatp->lstat = sb;
+ ++rstatp;
++regcnt;
}
}
+ /* display regular files */
if (regcnt) {
+ /*
+ * for -f flag -- switch above treats all -f operands as
+ * regular files; this code uses tabdir() to read
+ * them as directories.
+ */
if (f_specialdir) {
- for (cnt = 0; cnt < regcnt; ++cnt) {
- if (num = buildstats(rstats++, &stats, &names))
- ls(stats, num);
+ for (cnt = regcnt; cnt--;) {
+ if (num = tabdir(rstats++, &stats, &names))
+ displaydir(stats, num);
(void)free((char *)stats);
(void)free((char *)names);
}
} else
- ls(rstats, regcnt);
- if (dircnt)
- (void)putchar('\n');
+ displaydir(rstats, regcnt);
}
+ /* display directories */
if (dircnt) {
register char *p;
for (cnt = 0; cnt < dircnt; ++dstats) {
for (endofpath = path, p = dstats->name;
*endofpath = *p++; ++endofpath);
- ls_dir(dstats, cnt, regcnt || dircnt > 1);
+ subdir(dstats, regcnt, regcnt || dircnt > 1);
if (++cnt < dircnt && chdir(top)) {
(void)fprintf(stderr, "ls: %s: %s\n",
top, strerror(errno));
}
}
}
-#ifdef whybother
- (void)free((char *)rstats);
- (void)free((char *)dstats);
-#endif
}
-ls(stats, num)
+displaydir(stats, num)
LS *stats;
register int num;
{
register char *p, *savedpath;
LS *lp;
- if (num > 1 && !f_specialdir)
+ if (num > 1 && !f_specialdir) {
+ u_long save1, save2;
+
+ save1 = stats[0].lstat.st_btotal;
+ save2 = stats[0].lstat.st_maxlen;
qsort((char *)stats, num, sizeof(LS), sortfcn);
+ stats[0].lstat.st_btotal = save1;
+ stats[0].lstat.st_maxlen = save2;
+ }
- printdir(stats, num);
+ printfcn(stats, num);
if (f_recursive) {
savedpath = endofpath;
if (endofpath != path && endofpath[-1] != '/')
*endofpath++ = '/';
for (; *endofpath = *p++; ++endofpath);
- ls_dir(lp, 1, 1);
+ subdir(lp, 1, 1);
*(endofpath = savedpath) = '\0';
}
}
}
-ls_dir(lp, newline, tag)
+subdir(lp, newline, tag)
LS *lp;
int newline, tag;
{
int num;
char *names;
+ /*
+ * this doesn't really belong here, but it's the only place that
+ * everybody goes through; the `tag' variable is so that we don't
+ * print the header for directories unless we're going to display
+ * more directories, or we've already displayed files or directories.
+ * The `newline' variable keeps us from inserting a newline before
+ * we've displayed anything at all.
+ */
if (newline)
(void)putchar('\n');
if (tag)
lp->name, strerror(errno));
return;
}
- if (num = buildstats(lp, &stats, &names))
- ls(stats, num);
+ if (num = tabdir(lp, &stats, &names))
+ displaydir(stats, num);
(void)free((char *)stats);
(void)free((char *)names);
if (chdir("..")) {
}
}
-static
-buildstats(lp, s_stats, s_names)
+tabdir(lp, s_stats, s_names)
LS *lp, **s_stats;
char **s_names;
{
- register int cnt, maxentry;
+ register DIR *dirp;
+ register int cnt, maxentry, maxlen;
register char *p, *names;
- struct dirent *entry;
+ struct dirent *dp;
+ u_long blocks;
LS *stats;
- DIR *dirp;
- /* make this big so we don't realloc often */
+ /*
+ * allocate space for array of LS structures and the file names
+ * the name field will point to. Make it big so we don't have
+ * to realloc often.
+ */
#define DEFNUM 256
maxentry = DEFNUM;
*s_stats = stats = (LS *)emalloc((u_int)DEFNUM * sizeof(LS));
*s_names = names = emalloc((u_int)lp->lstat.st_size);
if (!(dirp = opendir(f_specialdir ? lp->name : "."))) {
- (void)fprintf(stderr, "ls: %s: %s\n",
- lp->name, strerror(errno));
+ (void)fprintf(stderr, "ls: %s: %s\n", lp->name,
+ strerror(errno));
return(0);
}
- for (cnt = 0; entry = readdir(dirp);) {
- p = entry->d_name;
+ blocks = 0;
+ maxlen = -1;
+ for (cnt = 0; dp = readdir(dirp);) {
+ /* this does -A and -a */
+ p = dp->d_name;
if (p[0] == '.') {
if (!f_listdot)
continue;
(u_int)maxentry * sizeof(LS))))
nomem();
}
- if (needstat && lstat(entry->d_name, &stats[cnt].lstat)) {
+ if (needstat && lstat(dp->d_name, &stats[cnt].lstat)) {
(void)fprintf(stderr, "ls: %s: %s\n",
- entry->d_name, strerror(errno));
+ dp->d_name, strerror(errno));
if (errno == ENOENT)
continue;
exit(1);
}
stats[cnt].name = names;
- bcopy(entry->d_name, names, (int)entry->d_namlen);
- names += entry->d_namlen;
+
+ /* strip out unprintables */
+ if (f_nonprint)
+ prcopy(dp->d_name, names, (int)dp->d_namlen);
+ else
+ bcopy(dp->d_name, names, (int)dp->d_namlen);
+ names += dp->d_namlen;
*names++ = '\0';
+
+ /*
+ * get the inode from the directory, so the -f flag
+ * works right.
+ */
+ stats[cnt].lstat.st_ino = dp->d_ino;
+
+ /* save name length for -C format */
+ stats[cnt].len = dp->d_namlen;
+ /* calculate number of blocks if -l format */
+ if (f_longform || f_size)
+ blocks += stats[cnt].lstat.st_blocks;
+ /* save max length if -C format */
+ if (!f_longform && !f_singlecol && maxlen < (int)dp->d_namlen)
+ maxlen = dp->d_namlen;
++cnt;
}
+ stats[0].lstat.st_btotal = blocks;
+ stats[0].lstat.st_maxlen = maxlen;
closedir(dirp);
return(cnt);
}