home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hall of Fame
/
HallofFameCDROM.cdr
/
dos
/
csap208b.lzh
/
CSAP.C
next >
Wrap
Text File
|
1987-07-30
|
12KB
|
383 lines
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <ctype.h>
#include <dir.h>
#include <mem.h>
#include "dosstruc.h"
#define MAX12BIT 0x0FF6
#if defined(__TINY__)
#define MODEL "Tiny"
#endif
#if defined(__SMALL__)
#define MODEL "Small"
#endif
#if defined(__MEDIUM__)
#define MODEL "Medium"
#endif
#if defined(__COMPACT__)
#define MODEL "Compact"
#endif
#if defined(__LARGE__)
#define MODEL "Large"
#endif
#if defined(__HUGE__)
#define MODEL "Huge"
#endif
struct DpbStruct Dpb; /* Disk Parameter Blcok (see dosstruc.h) */
struct ClusterQueue CluQ; /* Queue of cluster for directory */
struct DirEntry *DirBuff; /* Buffer for directory to be sorted */
unsigned LastCluster; /* Value for end of cluster chain */
int Is12Bit; /* 12 / 16 bit cluster indicator */
int *CluArray; /* Cluster Array ptr, dynamically allocated */
char Disk; /* Alpha working disk ('A', 'B', .... ) */
char CurDir[67]; /* Storage for Current Directory of disk */
char Path[67]; /* Storage for Path to sort */
char Parent[67]; /* Storage for Parent part of Path */
char Element[13]; /* Storage for Child part of Path */
char *Fat; /* Pointer to FAT buffer (dynamic) */
char Line[80]; /* Working storage for strings */
unsigned Cluster, Sector, NumSec;
unsigned MinMem; /* Minimum available memory */
struct ExtendedEntry Dir;
int Lim, i, j, k, l;
struct ClusterEntry *p, *t;
int OutSectors, OutClusters, BytesPerCluster, ECount;
struct ExtFcb Fcb;
char Order = 'N'; /* Sort key indicator (Default=Name/Ext) */
char Inverse = 0; /* Ascend/Descend indic. (Default=Ascend) */
char Level = 0; /* Recursive sort indic. (default=Recursic) */
char RSwt = 0; /* Report switch (Default=No Report) */
char VerSwt = 0; /* Pause for operator verify (Default=off) */
char Packed = 1; /* Elim. "erased" entries (Default=on) */
main (argc, argv)
int argc;
char **argv;
{
char *strrspn();
void SortDir(), ShowRoot(), Usage();
char *p;
union REGS Reg;
unsigned Cluster, Sector;
int i, j, AbortProgram();
fputs("C-Sort And Pack [CSAP]: Version 2.08b: Date: 07-30-1987", stderr);
fputs(" [", stderr);
fputs(MODEL, stderr);
fputs(" Model]\n", stderr);
fputs(" use \"CSAP -H\" or \"CSAP ?\" for help.\n\n", stderr);
Disk = getdisk() + 'A';
Line[0] = '\\'; getcurdir(Disk - '@', &Line[1]);
ctrlbrk(AbortProgram); /* Install "wrap-up" in Control Break vec. */
/* Interpret command line arguments, if any */
for (i=1; i<argc; ++i) {
if (argv[i][0] == '-') {
for (j=1; j<strlen(argv[i]); ++j) {
switch (toupper(argv[i][j])) {
case 'N': /* Sort Key = Name/Ext (default) */
Order = 'N';
break;
case 'D': /* Sort Key = Date/Time */
Order = 'D';
break;
case 'E': /* Sort Key = Ext/Name */
Order = 'E';
break;
case 'S': /* Sort Key = File Size */
Order = 'S';
break;
case 'R': /* Report Dir loc. & "erased" */
RSwt = 1;
break;
case 'I': /* Sort order inverse */
Inverse = 1;
break;
case 'P': /* Do NOT remove "erased" entries */
Packed = 0;
break;
case 'L': /* Limit sort to one level */
Level = 1;
break;
case 'V': /* Request approval before sort */
VerSwt = 1;
break;
case 'H':
Usage();
default: /* Illegal option */
fprintf(stderr, "Invalid option %s.\n", argv[i]);
Usage();
break;
}
}
}
else { /* Not switch, assume directory name or '?' */
if (argv[i][0] == '?') Usage();
if (argv[i][1] == ':') { /* Check for disk specified */
Disk = toupper(argv[i][0]); p = &argv[i][2];
}
else p = &argv[i][0];
if (p[0] != '\\') {
Line[0] = '\\'; getcurdir(Disk - '@', &Line[1]);
strcat(Line, "\\"); strcat(Line, p);
}
else strcpy(Line,p);
}
}
/*
Get disk information - uses un-documented DOS call, Int 21H, Func. 32H
This function has been verified to work correctly in PC/MS-DOS
versions 2.0 through 3.3. It is heavily used by DOS programs such
as CHKDSK.
*/
GetDPB(Disk, &Dpb);
/* Establish whether disk has 16-bit or 12-bit clusters */
Is12Bit = (Dpb.LastCluster > MAX12BIT) ? 0 : 1;
LastCluster = (Is12Bit) ? 0x0FF8 : 0xFFF8;
/*
Get & save current directory of working disk. We have to change to sort
and must restore on termination
*/
CurDir[0] = Disk; CurDir[1] = ':'; CurDir[2] = '\\';
getcurdir(Disk - '@', (char *) &CurDir[3]);
/* Allocate space to hold entire FAT in memory and read it in */
if ((Fat = malloc(Dpb.FatSize * Dpb.SectorSize)) == NULL) {
fprintf(stderr, "Insufficient memory for FAT.\n");
exit(1);
}
if (absread(Disk-'A', Dpb.FatSize, Dpb.FatStart, Fat) != 0) {
fprintf(stderr, "Error reading FAT.\n");
exit(1);
}
/*
Develop full path name for directory to be sorted and separate into
Parent and Child portions
*/
Path[0] = Parent[0] = Element[0] = '\0';
Path[0] = Disk; Path[1] = ':';
Path[2] = 0x00;
if (Line[0] != '\\') {
strcat(Path, "\\"); strcpy(&Path[3], &CurDir[3]);
if ((Path[strlen(Path)-1] != '\\') && (Path[strlen(Path)-1] != '/'))
strcat(Path, "\\");
}
strcat(Path, Line);
p = strrspn(Path, "\\/");
strcpy(Element, &p[1]);
if (p[-1] == ':') p++;
strncpy(Parent, Path, p - Path); Parent[p - Path] = 0x00;
MinMem = coreleft(); /* Initialize minimum available memory */
/*
Perform sort. SortDir is recursive and, if Level is not on, will sort
sort all levels of the hierarchy from the starting level down
*/
SortDir();
printf("Minimum memory= %u\n", MinMem);
bdos(0x3B, (int) CurDir, 0); /* Restore input "current" directory */
} /* end Main */
/*
STRRSPN is simply a reverse version of STRSPN. It finds the LAST
occurance in S1 of any member of S2. Fo some reason, none of the C
compilers that I use provide this although they all provide STRSPN
*/
char *strrspn (s1, s2)
char *s1, *s2;
{
char *p2start = s2;
char *p1;
p1 = s1 + strlen(s1) - 1;
while (p1 >= s1) {
while (*s2) {
if (*p1 == *s2) return(p1);
s2++;
}
s2 = p2start;
p1--;
}
return( (char *) NULL);
}
/* SearchFirst -- Search for First Directory Entry.
* On entry fcb contains an extended File Control Block
* with file name and attribute bits set. On exit, fcb
* contains matched entry unless return code is 255, in
* which case no match was found. This routine is used
* instead of the ones provided by the caller so that the
* cluster information for the directory can be obtained.
*/
SearchFirst(Fcb)
struct ExtFcb *Fcb;
{
union REGS regs;
regs.x.ax = 0x1100;
regs.x.dx = (unsigned) Fcb;
intdos(®s, ®s);
return((int) (regs.x.ax & 0xFF));
}
/* Alu2Sec -- Converts an input cluster number [ALU] into the disk-relative
* sector for use with DOS Absolute Disk Read [interrupt 25H] or
* Absolute Disk Write [interrupt 26H]. Requires access to the
* undocumented DOS Disk Parameter Block [use funtion GetDPB].
*/
unsigned int Alu2Sec (Dpb, Alu)
struct DpbStruct *Dpb;
unsigned Alu;
{
return( (Alu - 2) * (Dpb->ClusterSize + 1) + Dpb->DataStart);
}
/* NextCl -- This function calculates the logical "chaining" of cluster
* numbers in a File Allocation Table [FAT]. Given an entry
* cluster number it calculates the next cluster using the
* array Fat[].
*
* If Is12Bit is TRUE then Fat[] is assumed to contain 12 bit
* entries, otherwise Fat[] is assumed to contain 16 bit entries.
*/
unsigned NextCl(Is12Bit, Cluster, Fat)
int Is12Bit;
unsigned Cluster;
unsigned char Fat[];
{
unsigned ClWord, ClOffset;
if (Is12Bit) { /* 12 bit FAT lookup */
ClOffset = 3 * Cluster / 2;
ClWord = Fat[ClOffset] + (Fat[ClOffset + 1] << 8);
if (Cluster & 1) return (ClWord >> 4); /* odd cluster */
else return (ClWord & 0x0FFF); /* even cluster */
}
else return (((unsigned int *) Fat)[Cluster]); /* 16 bit FAT lookup */
}
/* PutQueue -- Builds a simple FIFO linked list using dynamically acquired
* memory.
*/
void PutQueue (Q, Cluster)
struct ClusterQueue *Q;
unsigned Cluster;
{
struct ClusterEntry *p;
if ((p = malloc(sizeof(struct ClusterEntry))) == NULL) {
fprintf(stderr, "Insufficient memory(1).\n");
AbortProgram();
}
p->Next = NULL; p->Cluster = Cluster;
if (Q->Head == NULL) Q->Head = p;
else Q->Current->Next = p;
Q->Current = p; Q->Count++;
}
/* AbortProgram -- Aborts the program, resetting the current directory,
* with an error code of 1.
*/
int AbortProgram () {
bdos(0x3B, (int) CurDir, 0); /* Reset input Current Directory */
exit(1);
}
/* strincmp -- The comparsion routine for the qsort algorithm.
*/
int strincmp (a, b)
struct DirEntry *a, *b;
{
int i;
long t;
/* Ensure that "erased" entries sort high no matter what the sort key is. */
if ((a->Name[0] == 0xE5) && (b->Name[0] != 0xE5)) return(1);
if (b->Name[0] == 0xE5) return(-1);
/* Ensure that directories sort lower that files no matter what sort key */
if ((a->Name[0] != 0xE5) && (b->Name[0] != 0xE5)) {
if ((a->Attribute & 0x10) ^ (b->Attribute & 0x10)) {
if (a->Attribute & 0x10) return(-1);
else return(1);
}
}
/* Actual sort key compare routines */
switch (Order) {
case 'D': /* Sort key is Date/Time */
if ((t = a->ModifyDate - b->ModifyDate) == 0) {
t = a->ModifyTime - b->ModifyTime;
}
break;
case 'N': /* Sort key is Name/Ext (default) */
t = strncmp(a->Name, b->Name, 11);
break;
case 'E': /* Sort key is Ext/Name */
if ((t = strncmp(a->Ext, b->Ext, 3)) == 0) {
t = strncmp(a->Name, b->Name, 8);
}
break;
case 'S': /* Sort key is File Size */
t = a->FileSize - b->FileSize;
break;
default:
t = strncmp(a->Name, b->Name, 11);
break;
}
if (Inverse) t = -t; /* Sort order is inverse */
return((t < 0) ? -1 : ((t > 0) ? 1 : 0));
}
void Usage () {
printf("USAGE: CSAP [options] [[d:]directory_name]\n");
printf(" or\n");
printf(" CSAP [[d:]directory_name] [options]\n");
printf("\n");
printf("Options:\n");
printf(" -N Sort on Name/Ext (default).\n");
printf(" -D Sort on Date/Time.\n");
printf(" -E Sort on Ext/Name.\n");
printf(" -S Sort on File Size.\n");
printf("\n");
printf(" -R Report number of \"erased\" entries and directory location.\n");
printf(" -I Inverse sort order, i.e. descending.\n");
printf(" -P Do NOT remove \"erased\" entries.\n");
printf(" -L Limit sort to a single level.\n");
printf(" -V Request confirmation before sorting.\n");
printf(" -H This message.\n");
exit(0);
}