home *** CD-ROM | disk | FTP | other *** search
- /*
- **************************** NOTICE! **************************
- * Contrary to the current trend in MS-DOS software this *
- * program, for whatever it is worth, is NOT copyrighted *
- * (with the exception of the runtime library from Borland *
- * International's Turbo C)! The program, in whole or in *
- * part, may be used freely in any fashion or environment *
- * desired. If you find this program to be useful to you, *
- * do NOT send any contribution to the author; in the words *
- * of Rick Conn, 'Enjoy!' However, if you make any *
- * improvements, I would enjoy receiving a copy of the *
- * modified source. I can be reached, usually within 24 *
- * hours, by messages on any of the Phoenix systems, *
- * particularly: *
- * *
- * Bob's Answering Machine [OPUS] *
- * (602) 242-3158 1200/2400 bps *
- * Radioactive West [PCBOARD] *
- * (602) 873-0810 1200/2400 bps *
- * The Tool Shop BBS [PCBOARD] *
- * (602) 279-2673 1200/2400/9600 bps *
- * (Good luck trying! VERY BUSY!) *
- * Technoids Anonymous [PCBOARD] *
- * (602) 899-4876 300/1200/2400 bps *
- * *
- * All can be reached through PC Pursuit. *
- * *
- * or: *
- * on GEnie, mail address: DON-WILL *
- * on CompuServ: 75410,543 *
- * *
- * Every effort has been made to avoid error and moderately *
- * extensive testing has been performed on this program, *
- * however, the author does not warrant it to be fit for any *
- * purpose or to be free from error and disclaims any *
- * liability for actual or any other damage arising from the *
- * use of this program. *
- *****************************************************************
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dos.h>
- #include <ctype.h>
- #include <dir.h>
- #include <mem.h>
- #include <alloc.h>
-
- #include "dosstruc.h"
-
- /*--- Function Prototypes ---*/
-
- void Usage (void);
- void GetDPB (int Disk, struct DpbStruct * Dpb);
- unsigned GetDosVersion (void);
- char *strrspn (char *s1, char *s2);
- int AbortProgram (void);
-
- void SortDir (void);
-
- /*--- End of Prototypes ---*/
-
- #define MAX12BIT 0x0FF6
- #define MAX16BIT 0xFFF6
-
- #if defined(__TINY__)
- #define MODEL "Tiny"
- #elif defined(__SMALL__)
- #define MODEL "Small"
- #elif defined(__COMPACT__)
- #define MODEL "Compact"
- #elif defined(__MEDIUM__)
- #define MODEL "Medium"
- #elif defined(__LARGE__)
- #define MODEL "Large"
- #elif defined(__HUGE__)
- #define MODEL "Huge"
- #endif
-
- 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 Line[80]; /* Working storage for strings */
- char Order = 'N'; /* Sort key indicator (Default=Name/Ext) */
- char Inverse = 0; /* Ascend/Descend indic. (Default=Ascend) */
- char Level = 0; /* Recursive sort indic. (default=Recursive) */
- 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) */
- char TruncateSwt = 0;/* Truncate directories (Default=off) */
- unsigned char *Fat; /* Pointer to FAT buffer (dynamic) */
- char FatDirty = 0; /* FAT needs to be rewritten */
- int Is12Bit; /* 12 / 16 bit cluster indicator */
- int *CluArray; /* Cluster Array ptr, dynamically allocated */
- int Lim, i, j, k, l;
- int OutSectors, OutClusters, BytesPerCluster, ECount;
- unsigned LastCluster; /* Value for end of cluster chain */
- unsigned Cluster, Sector, NumSec;
- unsigned FatSize;
- unsigned Version;
- long MinMem; /* Minimum available memory */
- unsigned Freed = 0; /* Freed clusster count */
- unsigned Version;
- unsigned FatSize;
- unsigned DirStart;
-
- 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 */
- struct ExtendedEntry Dir;
- struct ClusterEntry *p, *t;
- struct ExtFcb Fcb;
-
-
- void
- main (int argc, char *argv[]) {
- char *strrspn();
- void SortDir(), Usage();
-
- char *p, *p1, t1;
- int i, j;
-
- bdos(0x0D, 0, 0); /* Reset Disk Subsystem - Flush all buffers */
- fputs("C-Sort And Pack [CSAP]: Version 3.0.2: Date: June 20, 1990", 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 'T': /* Truncate directories */
- TruncateSwt = 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] != '\\') && (p[0] != '/')) {
- Line[0] = '\\';
- getcurdir(Disk - '@', &Line[1]);
- p1 = &p[strcspn(p, "\\/")];
- t1 = *p1;
- *p1 = '\0';
- if (!strcmp(p, ".")) {
- p = p1;
- *p1 = t1;
- }
- else if (!strcmp(p, "..")) {
- while (!strcmp(p, "..")) {
- p = strrspn(Line, "\\/");
- if ((p - Line) == 0) ++p;
- *p = '\0';
- if (t1 != '\0') p = ++p1;
- else p = p1;
- p1 = &p[strcspn(p, "\\/")];
- t1 = *p1;
- *p1 = '\0';
- }
- *p1 = t1;
- }
- else *p1 = t1;
- if (*p != '\0') 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);
- Version = GetDosVersion() & 0xFF;
- switch (Version) {
- case 2:
- FatSize = Dpb.V.V2.FatSize;
- DirStart = Dpb.V.V2.DirStart;
- break;
- case 3:
- FatSize = Dpb.V.V3.FatSize;
- DirStart = Dpb.V.V3.DirStart;
- break;
- case 4:
- FatSize = Dpb.V.V4.FatSize;
- DirStart = Dpb.V.V4.DirStart;
- break;
- default:
- fprintf(stderr, "Invalid DOS version: %d\n", Version);
- exit(1);
- }
-
- /* Establish whether disk has 16-bit or 12-bit clusters */
-
- if (Dpb.LastCluster > MAX16BIT) {
- fprintf(stderr, "Sorry, CSAP does not yet support FAT entries > 16 bits.\n");
- exit(1);
- }
- 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(FatSize * Dpb.SectorSize)) == NULL) {
- fprintf(stderr, "Insufficient memory for FAT.\n");
- exit(1);
- }
- if (absread(Disk - 'A', 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] = '\0';
- if ((Line[0] != '\\') && (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, (int) (p - Path));
- Parent[(int) (p - Path)] = '\0';
-
- 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= %ld\n", MinMem);
-
- bdos(0x0D, 0, 0); /* Reset disk subsystem - flush all buffers */
- if (FatDirty) {
- if (abswrite(Disk - 'A', FatSize, Dpb.FatStart, Fat) != 0) {
- fprintf(stderr, "Error writing FAT.\n");
- exit(1);
- }
- if (Dpb.FatCopies == 2) {
- if (abswrite(Disk - 'A', FatSize, Dpb.FatStart, Fat) != 0) {
- fprintf(stderr, "Error writing 2nd copy of Fat.\n");
- exit(1);
- }
- }
- printf("There were %d clusters freed\n", Freed);
- }
- bdos(0x0D, 0, 0); /* Reset disk subsystem - flush all buffers */
- bdosptr(0x3B, 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. For some reason, none of the C
- * compilers that I use provide this although they all provide STRSPN
- */
-
- char *
- strrspn (char *s1, char *s2) {
- char *p1;
-
- p1 = s1 + strlen(s1) - 1;
- while (p1 >= s1) {
- if (strchr(s2, *p1) != NULL) return (p1);
- --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.
- */
-
- int
- SearchFirst (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].
- */
-
- long
- Alu2Sec (struct DpbStruct * Dpb, unsigned Alu) {
-
- return ((long) (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 (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 */
- }
-
-
- void
- FreeCluster (int Is12Bit, unsigned Val, unsigned Cluster, unsigned char Fat[]) {
- extern char FatDirty;
- extern unsigned Freed;
- unsigned ClWord, ClOffset;
-
- if (Is12Bit) { /* 12 bit FAT lookup */
- ClOffset = 3 * Cluster / 2;
- ClWord = Fat[ClOffset] + (Fat[ClOffset + 1] << 8);
- if (Cluster & 1) ClWord = (ClWord & 0xF) | (Val & 0xFFF0); /* odd */
- else ClWord = (ClWord & 0xF000) | (Val & 0x0FFF);
- Fat[ClOffset + 1] = ClWord >> 8;
- Fat[ClOffset] = ClWord & 0xFF;
- }
- else ((unsigned int *) Fat)[Cluster] = Val; /* 16 bit FAT lookup */
- ++Freed;
- }
-
-
- /*
- * PutQueue -- Builds a simple FIFO linked list using dynamically acquired
- * memory.
- */
-
- void
- PutQueue (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 (void) {
-
- bdos(0x0D, 0, 0); /* Reset disk subsystem - flush all buffers */
- bdosptr(0x3B, CurDir, 0); /* Reset input Current Directory */
- exit(1);
- return (0);
- }
-
-
- /*
- * strincmp -- The comparsion routine for the qsort algorithm.
- */
-
- int
- strincmp (struct DirEntry * a, struct DirEntry * b) {
- 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 than 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 (a->ModifyDate < b->ModifyDate) t = -1;
- else if (a->ModifyDate > b->ModifyDate) t = 1;
- else {
- if (a->ModifyTime < b->ModifyTime) t = -1;
- else if (a->ModifyTime > b->ModifyTime) t = 1;
- else t = 0;
- }
- break;
- case 'N': /* Sort key is Name/Ext (default) */
- t = strncmp((char *) a->Name, (char *) b->Name, 11);
- break;
- case 'E': /* Sort key is Ext/Name */
- if ((t = strncmp(a->Ext, b->Ext, 3)) == 0) {
- t = strncmp((char *) a->Name, (char *) b->Name, 8);
- }
- break;
- case 'S': /* Sort key is File Size */
- t = a->FileSize - b->FileSize;
- break;
- default:
- t = strncmp((char *) a->Name, (char *) b->Name, 11);
- break;
- }
- if (Inverse) t = -t; /* Sort order is inverse */
- return ((t < 0) ? -1 : ((t > 0) ? 1 : 0));
- }
-
- unsigned
- GetDosVersion (void) {
- union REGS Regs;
-
- Regs.h.ah = 0x30;
- intdos(&Regs, &Regs);
- return (Regs.x.ax);
- }
-
-
- void
- Usage (void) {
-
- 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(" -T Truncate directories.\n");
- printf(" -H This message.\n");
- exit(0);
- }