Category : C Source Code
Archive   : UNIXTOOL.ZIP
Filename : LS.C
Output of file : LS.C contained in archive : UNIXTOOL.ZIP
* Attribute bits:
* d - directory
* r - read only file
* h - hidden file
* s - system file
* a - archive bit
*
* Files within each directory are sorted alphabetically.
* Directories are listed separate from other files.
*/
#include
#include
#include
#include
#include
#define SIZE(x) (sizeof(x)/sizeof(x[0]))
#define A_RONLY 0x01 /* Read only file */
#define A_HIDDEN 0x02 /* Hidden file */
#define A_SYSTEM 0x04 /* System file */
#define A_DIRECTORY 0x10 /* Directory file */
#define A_ARCHIVE 0x20 /* Archive bit */
#define FNLEN 80 /* Maximum filename length */
#define MAXFILES 512 /* Max number of files/directory */
static char ID[]="## ls.c 2.0 K.van Houten 230987 ##";
struct date {
unsigned d_sec: 5; /* Time, 2 second intervals */
unsigned d_min: 6; /* Time, minutes */
unsigned d_hour: 5; /* Time, hours */
unsigned d_day: 5; /* Date, day of month */
unsigned d_month: 4; /* Date, month of year */
unsigned d_year: 7; /* Date, year since 1980 */
};
struct find {
char fnd_dosinfo[21]; /* Reserved for dos */
char fnd_attr; /* File attribute */
struct date fnd_date; /* Date structure */
long fnd_size; /* File size */
char fnd_name[13]; /* File name less path */
};
char *nameptr ();
char *date ();
char *malloc ();
char *strrchr ();
int qscmp ();
extern int clsize(); /* get cluster size */
long clust();
short tmp;
struct find f; /* Used to return data from msdos */
union REGS r, o; /* Contains register values for intcall() */
int count; /* Number of files/directory */
char *p; /* Pointer to filename */
int i;
int j;
int lflg = 0; /* long */
int tflg = 0; /* time sort */
int sflg = 0; /* size in bloks */
int rflg = 0; /* reverse sort */
int fflg = 0; /* identify executables and subdirs */
long dirlen; /* Total length of one dir */
char line[FNLEN]; /* Filename buffer */
char dirs[20][50]; /* Subdir buffer */
int dirc; /* Subdir count */
int drive; /* drive nr */
char *file; /* Command line argument */
struct find *fnd[MAXFILES]; /* Pointers to file structures */
int bsize; /* size of clusters */
int spc; /* number of K's per cluster */
static struct atr { /* Attribute structure */
int a_mask;
int a_name;
} atr[] = {
A_DIRECTORY, 'd',
A_RONLY, 'r',
A_HIDDEN, 'h',
A_SYSTEM, 's',
A_ARCHIVE, 'a'
};
main (argc, argv)
int argc; /* Number of command line arguments */
char *argv[]; /* Array of pointers to arguments */
{
char buf[70];
drive = defdrv();
bsize=clsize(drive);
spc=bsize/1024;
for (argc--,argv++; argc>0; argc--,argv++) {
if (**argv == '-') {
while (*++(*argv)) {
switch (**argv) {
case 'l':
lflg++;
break;
case 't':
tflg++;
break;
case 's':
sflg++;
break;
case 'r':
rflg++;
break;
case 'F':
fflg++;
break;
default:
printf("Usage: ls [-Flrst] [file [file ...]]\n");
exit(1);
}
}
}
else
break;
}
r.h.ah = 0x1a; /* SET DISK TRANSFER ADDRESS FUNCTION */
r.x.dx = (int) & f;
tmp = intdos (&r, &o);
/* Produces error 0 ???
if (o.x.cflag) {
perror ("SETTING DTA ");
exit (1);
}
*/
dirc = 0;
count = 0;
if (argc == 0) {
strcpy(dirs[dirc++],".");
}
else {
while (file = *argv++, argc--) {
/* handle relative directorys */
if (strcmp(file,"..") == 0) {
strcpy(dirs[dirc++],"..\\.");
continue;
}
if (file[strlen(file)-1] == '.') {
strcpy(dirs[dirc++],file);
continue;
}
/* handle drive letters */
if (strlen(file) == 2 && file[1] == ':') {
strcpy(dirs[dirc],file);
strcat(dirs[dirc++],".");
continue;
}
/* handle abs. dirs */
if (file[strlen(file)-1] == '\\') {
strcpy(dirs[dirc], file);
strcat(dirs[dirc++],".");
continue;
}
findf ();
if (o.x.cflag) {
continue;
}
for (;;) {
if (o.x.cflag) {
break;
}
if (f.fnd_attr & A_DIRECTORY) {
if (f.fnd_name[0] == '.')
goto next;
*dirs[dirc]='\0';
if (strrchr(file,'\\')!=NULL) {
strncpy(dirs[dirc],file,((strrchr(file,'\\')-file)+1));
}
strcat (dirs[dirc++], f.fnd_name);/* save subdir name */
}
else {
if ((fnd[count] =
(struct find *)malloc(sizeof(struct find))) == NULL)
fatal ("out of memory");
*fnd[count] = f;
/* Increment total size */
dirlen += clust(fnd[count]->fnd_size);
count++;
}
next: findn ();
}
}
if (count == 0 && dirc == 0) {
printf("File not found\n");
exit(1);
}
}
/* All arguments done, now print simple files */
qsort (fnd, count, sizeof (struct find *), qscmp);
for (i = 0; i < count; i++) {
printentry(i);
if ((lflg==0) && (((i+1) % (sflg?4:5)) == 0) && (i > 1))
printf("\n");
}
for (i = 0; i < dirc; i++)
printdir(i);
return (1);
}
/*
* Print one entry, format depends on options selected.
*/
printentry(x)
int x;
{
long sz;
char pbuf[50]; /* print buffer */
sz = fnd[x] -> fnd_size;
/* block size */
if (sflg)
{
if ((fnd[x] -> fnd_attr & A_DIRECTORY) == 0)
{
printf("%3d ",clust(sz));
}
else
printf(" 0 ");
}
if (lflg) {
/* mode bits */
for (j = 0; j < SIZE (atr); j++)
if (atr[j].a_mask & fnd[x] -> fnd_attr)
putchar (atr[j].a_name);
else
putchar ('-');
/* file size */
printf (" %10ld ", sz);
/* file date */
printf ("%s ", date (&fnd[x] -> fnd_date));
}
/* file name */
if (fflg == 0)
printf ("%-12s " , strlwr (fnd[x] -> fnd_name));
/* executable / subdir info */
if (fflg)
{
if (fnd[x] -> fnd_attr & A_DIRECTORY)
sprintf (pbuf,"%s/" , strlwr (fnd[x] -> fnd_name));
else
{
if (isexe(fnd[x]->fnd_name))
sprintf (pbuf,"%s*" , strlwr (fnd[x] -> fnd_name));
else
sprintf (pbuf,"%s " , strlwr (fnd[x] -> fnd_name));
}
printf ("%-12s " , pbuf);
}
if (lflg)
printf("\n");
free (fnd[x]); /* Free find structure */
}
printdir (x)
int x;
{
int i;
char fbuf[80]; /* to assemble filename */
/* Complex, but needed for DOS 2.11 compatibility */
if (dirs[x][strlen(dirs[x])-1] == '.') {
dirs[x][strlen(dirs[x])-1] = '\0';
strcpy(fbuf,dirs[x]);
strcat(fbuf,"*.*");
}
else {
strcpy(fbuf,dirs[x]);
strcat(fbuf,"\\*.*");
}
if (dirs[x][1] == ':') { /* other drive */
drive=tolower(*dirs[x])-'a';
}
else {
drive=defdrv();
}
bsize=clsize(drive);
spc=bsize/1024;
file = fbuf;
p = nameptr (file);
count = p - file;
if (count + sizeof (f.fnd_name) > FNLEN)
fatal ("filename too long: %s", file);
strncpy (line, file, count);
p = line + count;
count = 0; /* Init file count */
dirlen = 0;
findf ();
for (;;) {
if (o.x.cflag)
break;
if (count >= MAXFILES)
fatal ("Too many files in one directory");
if ((fnd[count] =
(struct find *) malloc (sizeof (struct find))) == NULL)
fatal ("out of memory");
if (!((f.fnd_attr & A_DIRECTORY) &&
((strcmp (f.fnd_name, ".") == 0) ||
(strcmp (f.fnd_name, "..") == 0)))) {
memcpy (fnd[count], &f, sizeof f);
/* Increment total size */
dirlen += clust(fnd[count] -> fnd_size);
count++;
}
findn ();
}
if (count)
qsort (fnd, count, sizeof (struct find *), qscmp);
if (*dirs[x] != '\0')
printf("\n%s:\n", strlwr(dirs[x]));
if (lflg) {
printf ("Total %d\n",dirlen);
}
for (i = 0; i < count; i++) {
printentry(i);
if ((lflg==0) && (((i+1) % (sflg?4:5)) == 0) && (i > 1))
printf("\n");
}
}
/*
* Find first entry, return info in find structure.
*/
findf ()
{
r.h.ah = 0x4e; /* FINDFIRST function */
r.x.cx = A_HIDDEN | A_SYSTEM | A_DIRECTORY |
A_RONLY | A_ARCHIVE;
r.x.dx = (int) file;
tmp = intdos (&r, &o); /* Find first */
}
/*
* Find next entry
*/
findn ()
{
r.h.ah = 0x4f; /* Now use FINDNEXT function */
tmp = intdos (&r, &o); /* Find next */
}
/*
* Return a pointer to an ascii date, given a pointer
* to a date structure
*/
char ad[40];
char *
date (dp)
register struct date *dp;
{
static char *month[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
};
sprintf (ad, "%2d %s %4d %02d:%02d:%02d",
dp -> d_day,
month[dp -> d_month - 1],
dp -> d_year + 1980,
dp -> d_hour,
dp -> d_min,
dp -> d_sec * 2);
return (ad);
}
/*
* Qsort compare routine
* Directories first, other files second, sort alphabetically.
* This routine is called by qsort and passed two pointers to
* find structure pointers.
*/
qscmp (p1, p2)
struct find **p1;
struct find **p2;
{
register struct find *f1 = *p1;
register struct find *f2 = *p2;
register int cmp;
int inv = 1;
if (rflg)
inv=-1;
/*
if (cmp = (f2 -> fnd_attr & A_DIRECTORY) - (f1 -> fnd_attr & A_DIRECTORY))
return (cmp);
*/
if (tflg) {
if (cmp = (f2->fnd_date.d_year - f1->fnd_date.d_year))
return(inv * cmp);
if (cmp = (f2->fnd_date.d_month - f1->fnd_date.d_month))
return(inv * cmp);
if (cmp = (f2->fnd_date.d_day - f1->fnd_date.d_day))
return(inv * cmp);
if (cmp = (f2->fnd_date.d_hour - f1->fnd_date.d_hour))
return(inv * cmp);
if (cmp = (f2->fnd_date.d_min - f1->fnd_date.d_min))
return(inv * cmp);
if (cmp = (f2->fnd_date.d_sec - f1->fnd_date.d_sec))
return(inv * cmp);
}
return (inv * strcmp (f1 -> fnd_name, f2 -> fnd_name));
}
/*
* Return a pointer to the beginning of the filename (past pathname if any)
*/
char *
nameptr (name)
char *name;
{
register char *p1;
if ((p1 = strrchr (name, '\\')) != NULL)
return (++p1);
else
if ((p1 = strrchr (name, ':')) != NULL)
return (++p1);
return (name);
}
/*
* Fatal error
* The %r (recursive) printf format specifier is non-portable.
*/
fatal (p)
char *p;
{
printf ("ls fatal error\n");
exit (0);
}
long
clust(sz)
long sz;
{
return(spc*((sz % bsize) ? (sz / bsize + 1) : (sz / bsize)));
}
int
defdrv()
{
int tmp;
union REGS r;
r.h.ah = 0x19; /* get default drive */
tmp = intdos(&r,&r);
if (r.x.cflag != 0) {
printf("Error reading def. drive: %d\n",tmp);
exit(1);
}
return(r.h.al);
}
int
isexe(n)
char *n;
{
char *p,*t;
if ((p=strchr(n,'.')) == NULL)
return(0);
p++;
if (strncmp(p,"EXE",3) == 0)
return(1);
if (strncmp(p,"COM",3) == 0)
return(1);
if (strncmp(p,"BAT",3) == 0)
return(1);
return(0);
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/