home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programming
/
powerprogramming1994.iso
/
progtool
/
dirutl
/
tk_ls.arc
/
LS.C
next >
Wrap
Text File
|
1989-01-14
|
17KB
|
687 lines
static char title[] = "Ls.com, file list/find program, version 1.00, (14 January 1988)";
static char copyright[] = "Copyright 1989 Timothy L. Kay -- non-commercial use permitted";
static char permission[] = "Permission is hereby granted to distribute freely for non-commercial use only.";
static char me[] = "Timothy L. Kay\nCaltech, 256-80\nPasadena, CA 91125\ntim@csvax.caltech.edu";
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <alloc.h>
#include <string.h>
#include <dir.h>
#include <dos.h>
#include <ctype.h>
#define STDERR fprintf(stderr,
int multi;
int flag_1 = 0;
int flag_F = 0;
int flag_R = 0;
int flag_a = 0;
int flag_d = 0;
int flag_f = 0;
int flag_l = 0;
int flag_t = 0;
int flag_v = 0;
int value_b = -1;
int value_f = 0;
#define vf_archive 0x01
#define vf_ascii 0x02
#define vf_size 0x04
#define vf_bak 0x08
long param_size;
#define PARAM_SIZE_DEFAULT 10000L
long param_percent;
#define PARAM_PERCENT_DEFAULT 90
typedef struct {
char ff_reserved[21];
char ff_attrib;
struct { unsigned x:5; unsigned m:6; unsigned h:5; } ff_ftime;
struct { unsigned d:5; unsigned m:4; unsigned y:7; } ff_fdate;
long ff_fsize;
char ff_name[13];
} FF;
#define SFF sizeof(FF)
int ffirst(char *p, FF *f, int m) {
return findfirst(p, (struct ffblk *)f, m);
}
int fnext(FF *f) {
return findnext((struct ffblk *)f);
}
void help() {
printf("Usage: ls [-c] [?] [--] [-?] [-1FRabltv] [-f[abis[#]]] [file ...]\n");
printf(" where\n");
printf(" -,? print this message c print copyright message\n");
printf(" 1 print files in single column with path prepended\n");
printf(" F enable inverse video for directories (or SET TERM=ansi)\n");
printf(" R recursively list contents of subdirectories\n");
printf(" a list all (including hidden and system) files\n");
printf(" b# print files in single column preceded with %%i, i=1..#\n");
printf(" f find files that match particular criteria\n");
printf(" a# find files that contain > #%% ASCII text (default %d%%)\n", PARAM_PERCENT_DEFAULT);
printf(" b find files with extension .bak\n");
printf(" i find files with archive bit on\n");
printf(" s# find files smaller than # bytes (default %ld bytes)\n", PARAM_SIZE_DEFAULT);
printf(" l long format includes file date, time, size, attributes\n");
printf(" t list files in time order rather than alphabetic\n");
printf(" v verbose details of find decisions\n");
printf("\n");
printf(" examples\n");
printf(" ls list files in current directory\n");
printf(" ls -Rfas1000 / lists all ASCII files smaller than 1000 bytes\n");
printf(" ls -vRfas1000 / same but explains why some files do not qualify\n");
printf(" ls -Rfas / | zoo aI /backup backs up all ASCII files of reasonable size\n");
printf(" ls -b2 *.c > temp.bat ; temp cc -DMSDOS compile all .c files\n");
exit(0);
}
void copyr()
{
printf("%s\n", title);
printf("%s\n", copyright);
printf("%s\n", permission);
printf("\n");
printf("%s\n", me);
exit(0);
}
/*
* int cmp(char *s, char *t)
*
* Compares strings s and t, and returns an int whose value is
*
* < 0 if s < t,
* 0 s == t, or
* > 0 s > t.
*
* The comparison is more complex than the one performed by strcmp().
* Any sequences of digits are treated as separate fields. For
* example, the string "a100-x" is treated as three fields: the
* string "a", the number 100, and the string "-x". This way, the
* string "a30" is considered less than the string "a100".
*/
int cmp(char *s, char *t) {
char *s1, *t1;
int s0, t0;
for (s1 = s, t1 = t; *s1 || *t1; s = s1, t = t1) {
while (*s1 && 0 == isdigit(*s1)) {
++s1;
}
while (*t1 && 0 == isdigit(*t1)) {
++t1;
}
s0 = s1 - s;
t0 = t1 - t;
if (s0 < t0) {
int d = strncmp(s, t, s0);
if (d) {
return d;
}
return -1;
} else if (s0 > t0) {
int d = strncmp(s, t, t0);
if (d) {
return d;
}
return 1;
} else {
int d = strncmp(s, t, s0);
if (d) {
return d;
}
}
while (*s1 && isdigit(*s1)) {
++s1;
}
while (*t1 && isdigit(*t1)) {
++t1;
}
s0 = s1 - s;
t0 = t1 - t;
if (s0 != t0) {
return s0 - t0;
} else {
int d = strncmp(s, t, s0);
if (d) {
return d;
}
}
}
return 0;
}
int ncmp(FF *a, FF *b) {
return strcmp(a->ff_name, b->ff_name);
}
int tcmp(FF *a, FF *b) {
if (a->ff_fdate.y != b->ff_fdate.y) {
return b->ff_fdate.y - a->ff_fdate.y;
}
if (a->ff_fdate.m != b->ff_fdate.m) {
return b->ff_fdate.m - a->ff_fdate.m;
}
if (a->ff_fdate.d != b->ff_fdate.d) {
return b->ff_fdate.d - a->ff_fdate.d;
}
if (a->ff_ftime.h != b->ff_ftime.h) {
return b->ff_ftime.h - a->ff_ftime.h;
}
if (a->ff_ftime.m != b->ff_ftime.m) {
return b->ff_ftime.m - a->ff_ftime.m;
}
if (a->ff_ftime.x != b->ff_ftime.x) {
return b->ff_ftime.x - a->ff_ftime.x;
}
return 0;
}
/*
* FF *dir(char *s, int m)
*
* Returns a pointer to an array of FF structures consisting of the
* filenames which match pattern s along with their attributes. The
* mask m determines what types of files (directories, system, hidden,
* etc.) are eligible to be matched. The last entry of the array has
* an empty file name. If an error occurs, 0 is returned.
*/
FF *dir(char *s, int m) {
int i, n;
FF *x, *xp;
FF f;
/* make a first pass to count files */
i = ffirst(s, &f, m);
while (0 == i && 0 == flag_a && '.' == *f.ff_name) {
i = fnext(&f);
}
if (i != 0) {
return 0;
}
for (n = 0; i == 0; ++n) {
do {
i = fnext(&f);
} while (0 == i && 0 == flag_a && '.' == *f.ff_name);
}
/* allocate array */
xp = x = malloc(SFF * (n + 1));
if (x == 0) {
return 0;
}
/* collect data */
ffirst(s, &f, m);
while (0 == flag_a && '.' == *f.ff_name) {
fnext(&f);
}
for (i = 0; i < n; ++i) {
*xp = f;
strlwr(xp->ff_name);
++xp;
do {
fnext(&f);
} while (0 == flag_a && '.' == *f.ff_name);
}
*xp->ff_name = 0;
/* sort data */
if (flag_t) {
qsort(x, n, SFF, tcmp);
} else {
qsort(x, n, SFF, ncmp);
}
return x;
}
void flags(char *s) {
for (; *s; ++s) {
switch (*s) {
case '-':
case '?': help();
case '1': flag_1 = 1; flag_l = 0; break;
case 'C': flag_1 = 0; flag_l = 0; break;
case 'F': flag_F = 1; break;
case 'R': flag_R = 1; break;
case 'a': flag_a = 1; break;
case 'b':
flag_1 = 1;
flag_l = 0;
if (s[1] && isdigit(s[1])) {
value_b = s[1] - '0';
++s;
} else {
value_b = 1;
}
break;
case 'c': copyr();
case 'd': flag_d = 1; break;
case 'f':
flag_f = 1;
if (0 == flag_1 && 0 == flag_l) {
flag_1 = 1;
}
for (++s; *s; ++s) {
switch (*s) {
case 'a':
value_f |= vf_ascii;
param_percent = 0;
while (isdigit(s[1])) {
param_size = 10 * param_percent + *++s - '0';
}
if (0 == param_percent) {
param_percent = PARAM_PERCENT_DEFAULT;
}
break;
case 'b': value_f |= vf_bak; break;
case 'i': value_f |= vf_archive; break;
case 's':
value_f |= vf_size;
param_size = 0;
while (isdigit(s[1])) {
param_size = 10 * param_size + *++s - '0';
}
if (0 == param_size) {
param_size = PARAM_SIZE_DEFAULT;
}
break;
default:
STDERR "Unknown switch -f%c\n", *s);
exit(1);
}
}
--s;
break;
case 'l': flag_1 = 0; flag_l = 1; break;
case 't': flag_t = 1; break;
case 'v': flag_v = 1; break;
default:
STDERR "Unknown switch -%c\n", *s);
exit(1);
}
}
}
void massage(char *s) {
if (0 == *s) {
return;
}
for (; *s; ++s) {
if ('\\' == *s) {
*s = '/';
} else if (isupper(*s)) {
*s = tolower(*s);
}
}
if (*--s == '/') {
*s = 0;
}
}
void path(char *p, char *s) {
char *pp;
strcpy(p, s);
pp = strrchr(p, '/');
if (0 == pp) {
*p = 0;
} else {
pp[1] = 0;
}
}
char month[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
void outputLong_1(FF *f) {
if (f->ff_attrib & (FA_DIREC | FA_LABEL)) {
printf("%c%c%c%c%c%c%c%c %d %.3s %2d %2d:%02d %s\n",
(f->ff_attrib & 0x80) ? '8' : ' ',
(f->ff_attrib & 0x40) ? '4' : ' ',
(f->ff_attrib & FA_ARCH) ? 'a' : '-',
(f->ff_attrib & FA_DIREC) ? 'd' : '-',
(f->ff_attrib & FA_LABEL) ? 'v' : '-',
(f->ff_attrib & FA_SYSTEM) ? 's' : '-',
(f->ff_attrib & FA_HIDDEN) ? 'h' : '-',
(f->ff_attrib & FA_RDONLY) ? 'r' : '-',
f->ff_fdate.y + 1980, month + 3 * (f->ff_fdate.m - 1), f->ff_fdate.d,
f->ff_ftime.h, f->ff_ftime.m,
f->ff_name);
} else {
printf("%c%c%c%c%c%c%c%c %d %.3s %2d %2d:%02d %6ld %s\n",
(f->ff_attrib & 0x80) ? '8' : ' ',
(f->ff_attrib & 0x40) ? '4' : ' ',
(f->ff_attrib & FA_ARCH) ? 'a' : '-',
(f->ff_attrib & FA_DIREC) ? 'd' : '-',
(f->ff_attrib & FA_LABEL) ? 'v' : '-',
(f->ff_attrib & FA_SYSTEM) ? 's' : '-',
(f->ff_attrib & FA_HIDDEN) ? 'h' : '-',
(f->ff_attrib & FA_RDONLY) ? 'r' : '-',
f->ff_fdate.y + 1980, month + 3 * (f->ff_fdate.m - 1), f->ff_fdate.d,
f->ff_ftime.h, f->ff_ftime.m,
f->ff_fsize, f->ff_name);
}
}
void reverse(char *q, char *p) {
while (*p) {
if ('/' == *p) {
*q++ = '\\';
} else {
*q++ = *p;
}
++p;
}
*q = 0;
}
int qualifies(char *p, FF *f) {
char fn[MAXPATH];
sprintf(fn, "%s%s", p, f->ff_name);
if (0 == (value_f & vf_bak)
&& 0 == strcmp(".bak", f->ff_name + strlen(f->ff_name) - 4)) {
if (flag_v) {
STDERR "%s -- skipped (.bak)\n", fn);
}
return 0;
}
if (f->ff_attrib & FA_DIREC) {
return 0;
}
if ((value_f & vf_archive) && 0 == (f->ff_attrib & FA_ARCH)) {
if (flag_v) {
STDERR "%s -- skipped (archive bit off)\n", fn);
}
return 0;
}
if ((value_f & vf_size) && (param_size < f->ff_fsize)) {
if (flag_v) {
STDERR "%s -- skipped (%ld bytes)\n", fn, f->ff_fsize);
}
return 0;
}
if ((value_f & vf_ascii)) {
int fd, i, j, c;
char buf[512];
fd = open(fn, O_RDONLY | O_BINARY);
if (fd < 0) {
perror(fn);
return 0;
}
i = read(fd, buf, sizeof buf);
if (i < 512 && i < f->ff_fsize) {
STDERR "1 Cannot read %s\n", fn);
close(fd);
return 0;
}
for (c = 0, j = 0; j < i; ++j) {
c += isprint(buf[j]) || isspace(buf[j]);
}
if (100L * c < param_percent * i) {
if (flag_v) {
STDERR "%s -- skipped (%d%% printable)\n", fn, 100L * c / i);
}
close(fd);
return 0;
}
if (512 < f->ff_fsize) {
lseek(fd, -512L, 2);
i = read(fd, buf, sizeof buf);
if (i < 512 && i < f->ff_fsize) {
STDERR "2 Cannot read %s\n", fn);
close(fd);
return 0;
}
for (c = 0, j = 0; j < i; ++j) {
c += isprint(buf[j]) || isspace(buf[j]);
}
if (100L * c < param_percent * i) {
if (flag_v) {
STDERR "%s -- skipped (%d%% printable)\n", fn, 100L * c / i);
}
close(fd);
return 0;
}
}
if (3 * 512 < f->ff_fsize) {
lseek(fd, f->ff_fsize / 2L - 256L, 0);
i = read(fd, buf, sizeof buf);
if (i < 512 && i < f->ff_fsize) {
STDERR "3 Cannot read %s\n", fn);
close(fd);
return 0;
}
for (c = 0, j = 0; j < i; ++j) {
c += isprint(buf[j]) || isspace(buf[j]);
}
if (100L * c < param_percent * i) {
if (flag_v) {
STDERR "%s -- skipped (%d%% printable)\n", fn, 100L * c / i);
}
close(fd);
return 0;
}
}
close(fd);
}
return 1;
}
void outputLong(char *p, FF *f) {
char q[MAXPATH];
reverse(q, p);
for (; *f->ff_name; ++f) {
if (0 == flag_f || qualifies(p, f)) {
outputLong_1(f);
}
}
}
void outputOne(char *p, FF *f) {
char q[MAXPATH];
reverse(q, p);
for (; *f->ff_name; ++f) {
if (0 == flag_f || qualifies(p, f)) {
if (0 <= value_b) {
int i, k;
for (i = 1; i <= value_b; ++i) {
printf("%%%d ", i);
}
k = 45 - strlen(q);
if (k < 0) {
k = 0;
}
printf("%s%-*s", q, k, f->ff_name);
for (; i <= 9; ++i) {
printf(" %%%d", i);
}
printf("\n");
} else {
printf("%s%s\n", p, f->ff_name);
}
}
}
}
#define SCREENWIDTH 80
void outputColumn(FF *f) {
FF *fp;
int i, j, n, on_a_line, number_of_lines;
for (n = 0, fp = f; *fp->ff_name; ++n, ++fp)
;
on_a_line = SCREENWIDTH / 13;
number_of_lines = (n + on_a_line - 1) / on_a_line;
for (i = 0; i < number_of_lines; ++i) {
for (j = 0; j < on_a_line; ++j) {
int k = j * number_of_lines + i;
if (k < n) {
if (flag_F && (f[k].ff_attrib & FA_DIREC) && isatty(1)) {
printf(" \033[7m%s\033[0m%s", f[k].ff_name,
" " + strlen(f[k].ff_name));
} else {
printf(" %-12.12s", f[k].ff_name);
}
}
}
printf("\n");
}
}
/* -d causes the arguments themselves to be output. This
* mode isn't very useful unless some globbing code is
* added to c0?.c
*/
void list_d(char *s) {
if (flag_1) {
printf("%s\n", s);
} else if (flag_l) {
/*
outputLong_1(s);
*/
} else {
printf("%s\n", s);
}
}
/* -R lists the entire directory tree. */
void list_R(char *s) {
FF *f, *fp;
char p[MAXPATH];
path(p, s);
f = dir(s, flag_a ? 0xef : 0x00);
if (0 == flag_1) {
printf("%s:\n", p);
}
if (f) {
if (flag_1) {
outputOne(p, f);
} else if (flag_l) {
outputLong(p, f);
} else {
outputColumn(f);
}
}
free(f);
f = dir(s, flag_a ? 0xff : FA_DIREC);
if (0 == f) {
return;
}
for (fp = f; *fp->ff_name; ++fp) {
char r[MAXPATH];
if ((fp->ff_attrib & FA_DIREC) && '.' != *fp->ff_name) {
sprintf(r, "%s%s/*.*", p, fp->ff_name);
list_R(r);
}
}
free(f);
}
/* Without -d and -R, files are listed, and directory contents
are listed.
*/
void list(char *s) {
FF *f;
char p[MAXPATH];
f = dir(s, flag_a ? 0xff : FA_DIREC);
if (0 == f) {
return;
}
path(p, s);
if (flag_1) {
outputOne(p, f);
} else if (flag_l) {
outputLong(p, f);
} else {
outputColumn(f);
}
free(f);
}
/* The dir function is called twice. The first time, we add
* "/*.*" to the end of the pattern. If this fails, we try
* without. We can't just stat it to see if it is a directory
* because it may have wildcards, and we'd get its expansion.
* We can't compare the names because a directory could
* contain a file of the same name.
*/
void select(char *s) {
char fn[MAXPATH];
FF f;
massage(s);
sprintf(fn, "%s/*.*", s);
if (ffirst(fn, &f, 0xff)) {
strcpy(fn, s);
if (ffirst(fn, &f, 0xff)) {
return;
}
} else if (multi && 0 == flag_R) {
printf("%s:\n", s);
}
if (flag_d) {
list_d(fn);
} else if (flag_R) {
list_R(fn);
} else {
list(fn);
}
}
void set_flag_F()
{
char *ep = getenv("TERM");
if (ep) {
flag_F = !strcmp(ep, "ansi") || !strcmp(ep, "vt100");
}
}
void main(int argc, char *argv[]) {
int i, j, named = 0;
if (argc == 2 && !strcmp(argv[1], "?")) {
help();
}
set_flag_F();
for (j = 0, i = 1; i < argc; ++i) {
if (argv[i][0] != '-') {
++j;
}
}
if (j < 2) {
multi = 0;
} else {
multi = 1;
}
for (i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
flags(argv[i] + 1);
} else {
named = 1;
select(argv[i]);
}
}
if (0 == named) {
select("*.*");
}
}