home *** CD-ROM | disk | FTP | other *** search
/ Hall of Fame / HallofFameCDROM.cdr / dos / csap208b.lzh / CSAP.C next >
Text File  |  1987-07-30  |  12KB  |  383 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <dos.h>
  4. #include <ctype.h>
  5. #include <dir.h>
  6. #include <mem.h>
  7.  
  8. #include "dosstruc.h"
  9.  
  10. #define MAX12BIT 0x0FF6
  11. #if defined(__TINY__)
  12. #define MODEL "Tiny"
  13. #endif
  14. #if defined(__SMALL__)
  15. #define MODEL "Small"
  16. #endif
  17. #if defined(__MEDIUM__)
  18. #define MODEL "Medium"
  19. #endif
  20. #if defined(__COMPACT__)
  21. #define    MODEL "Compact"
  22. #endif
  23. #if defined(__LARGE__)
  24. #define MODEL "Large"
  25. #endif
  26. #if defined(__HUGE__)
  27. #define MODEL "Huge"
  28. #endif
  29.  
  30. struct    DpbStruct Dpb;        /* Disk Parameter Blcok (see dosstruc.h)    */
  31. struct    ClusterQueue CluQ;    /* Queue of cluster for directory            */
  32. struct    DirEntry *DirBuff;    /* Buffer for directory to be sorted        */
  33. unsigned  LastCluster;            /* Value for end of cluster chain            */
  34. int       Is12Bit;                /* 12 / 16 bit cluster indicator            */
  35. int          *CluArray;            /* Cluster Array ptr, dynamically allocated    */
  36. char      Disk;                    /* Alpha working disk ('A', 'B', .... )        */
  37. char      CurDir[67];            /* Storage for Current Directory of disk    */
  38. char      Path[67];                /* Storage for Path to sort                    */
  39. char      Parent[67];            /* Storage for Parent part of Path            */
  40. char      Element[13];            /* Storage for Child part of Path            */
  41. char      *Fat;                    /* Pointer to FAT buffer (dynamic)            */
  42. char      Line[80];                /* Working storage for strings                */
  43. unsigned  Cluster, Sector, NumSec;
  44. unsigned  MinMem;                /* Minimum available memory                    */
  45. struct    ExtendedEntry Dir;
  46. int       Lim, i, j, k, l;
  47. struct    ClusterEntry *p, *t;
  48. int       OutSectors, OutClusters, BytesPerCluster, ECount;
  49. struct    ExtFcb Fcb;
  50. char      Order = 'N';            /* Sort key indicator (Default=Name/Ext)    */
  51. char      Inverse = 0;            /* Ascend/Descend indic. (Default=Ascend)    */
  52. char      Level = 0;            /* Recursive sort indic. (default=Recursic)    */
  53. char      RSwt = 0;                /* Report switch (Default=No Report)        */
  54. char      VerSwt = 0;            /* Pause for operator verify (Default=off)    */
  55. char      Packed = 1;            /* Elim. "erased" entries (Default=on)        */
  56.  
  57.  
  58. main (argc, argv)
  59. int argc;
  60. char **argv;
  61. {
  62.     char   *strrspn();
  63.     void   SortDir(), ShowRoot(), Usage();
  64.  
  65.     char      *p;
  66.     union REGS      Reg;
  67.     unsigned  Cluster, Sector;
  68.     int       i, j, AbortProgram();
  69.  
  70.     fputs("C-Sort And Pack [CSAP]: Version 2.08b: Date: 07-30-1987", stderr);
  71.     fputs(" [", stderr);
  72.     fputs(MODEL, stderr);
  73.     fputs(" Model]\n", stderr);
  74.  
  75.     fputs("    use \"CSAP -H\" or \"CSAP ?\" for help.\n\n", stderr);
  76.     Disk = getdisk() + 'A';
  77.     Line[0] = '\\'; getcurdir(Disk - '@', &Line[1]);
  78.  
  79.     ctrlbrk(AbortProgram);        /* Install "wrap-up" in Control Break vec.    */
  80.  
  81. /* Interpret command line arguments, if any      */
  82.  
  83.     for (i=1; i<argc; ++i) {
  84.         if (argv[i][0] == '-') {
  85.             for (j=1; j<strlen(argv[i]); ++j) {
  86.                 switch (toupper(argv[i][j])) {
  87.                     case 'N':            /* Sort Key = Name/Ext (default)    */
  88.                         Order = 'N';
  89.                         break;
  90.                     case 'D':            /* Sort Key = Date/Time               */
  91.                         Order = 'D';
  92.                         break;
  93.                     case 'E':            /* Sort Key = Ext/Name                */
  94.                         Order = 'E';
  95.                         break;
  96.                     case 'S':            /* Sort Key = File Size                */
  97.                         Order = 'S';
  98.                         break;
  99.                     case 'R':            /* Report Dir loc. & "erased"        */
  100.                         RSwt = 1;
  101.                         break;
  102.                     case 'I':            /* Sort order inverse                */
  103.                         Inverse = 1;
  104.                         break;
  105.                     case 'P':            /* Do NOT remove "erased" entries    */
  106.                         Packed = 0;
  107.                         break;
  108.                     case 'L':            /* Limit sort to one level            */
  109.                         Level = 1;
  110.                         break;
  111.                     case 'V':            /* Request approval before sort        */
  112.                         VerSwt = 1;
  113.                         break;
  114.                     case 'H':
  115.                         Usage();
  116.                     default:            /* Illegal option                    */
  117.                         fprintf(stderr, "Invalid option %s.\n", argv[i]);
  118.                         Usage();
  119.                         break;
  120.                     }
  121.                 }
  122.             }
  123.         else {        /* Not switch, assume directory name or '?'        */
  124.             if (argv[i][0] == '?') Usage();
  125.             if (argv[i][1] == ':') {    /* Check for disk specified    */
  126.                   Disk = toupper(argv[i][0]); p = &argv[i][2];
  127.                 }
  128.             else p = &argv[i][0];
  129.             if (p[0] != '\\') {
  130.                 Line[0] = '\\'; getcurdir(Disk - '@', &Line[1]);
  131.                 strcat(Line, "\\"); strcat(Line, p);
  132.                 }
  133.             else strcpy(Line,p);
  134.             }
  135.         }
  136.  
  137. /*
  138.     Get disk information - uses un-documented DOS call, Int 21H, Func. 32H
  139.         This function has been verified to work correctly in PC/MS-DOS
  140.         versions 2.0 through 3.3.  It is heavily used by DOS programs such
  141.         as CHKDSK.
  142. */
  143.  
  144.     GetDPB(Disk, &Dpb);
  145.  
  146. /* Establish whether disk has 16-bit or 12-bit clusters  */
  147.  
  148.     Is12Bit = (Dpb.LastCluster > MAX12BIT) ? 0 : 1;
  149.     LastCluster = (Is12Bit) ? 0x0FF8 : 0xFFF8;
  150.  
  151. /*
  152.     Get & save current directory of working disk.  We have to change to sort
  153.     and must restore on termination
  154. */
  155.     CurDir[0] = Disk; CurDir[1] = ':'; CurDir[2] = '\\';
  156.     getcurdir(Disk - '@', (char *) &CurDir[3]);
  157.  
  158. /* Allocate space to hold entire FAT in memory and read it in  */
  159.  
  160.     if ((Fat = malloc(Dpb.FatSize * Dpb.SectorSize)) == NULL) {
  161.         fprintf(stderr, "Insufficient memory for FAT.\n");
  162.         exit(1);
  163.         }
  164.     if (absread(Disk-'A', Dpb.FatSize, Dpb.FatStart, Fat) != 0) {
  165.         fprintf(stderr, "Error reading FAT.\n");
  166.         exit(1);
  167.         }
  168.  
  169. /*
  170.     Develop full path name for directory to be sorted and separate into
  171.         Parent and Child portions
  172. */
  173.  
  174.     Path[0] = Parent[0] = Element[0] = '\0';
  175.     Path[0] = Disk; Path[1] = ':';
  176.     Path[2] = 0x00;
  177.     if (Line[0] != '\\') {
  178.         strcat(Path, "\\"); strcpy(&Path[3], &CurDir[3]);
  179.         if ((Path[strlen(Path)-1] != '\\') && (Path[strlen(Path)-1] != '/'))
  180.             strcat(Path, "\\");
  181.         }
  182.     strcat(Path, Line);
  183.     p = strrspn(Path, "\\/");
  184.     strcpy(Element, &p[1]);
  185.     if (p[-1] ==  ':') p++;
  186.     strncpy(Parent, Path, p - Path); Parent[p - Path] = 0x00;
  187.  
  188.     MinMem = coreleft();        /* Initialize minimum available memory        */
  189.  
  190. /*
  191.     Perform sort.  SortDir is recursive and, if Level is not on, will sort
  192.     sort all levels of the hierarchy from the starting level down
  193. */
  194.  
  195.     SortDir();
  196.  
  197.     printf("Minimum memory= %u\n", MinMem);
  198.  
  199.     bdos(0x3B, (int) CurDir, 0);    /* Restore input "current" directory    */
  200.     }  /* end Main */
  201.  
  202.  
  203. /*
  204.     STRRSPN is simply a reverse version of STRSPN.  It finds the LAST
  205.     occurance in S1 of any member of S2.  Fo some reason, none of the C
  206.     compilers that I use provide this although they all provide STRSPN
  207. */
  208.  
  209. char *strrspn (s1, s2)
  210. char *s1, *s2;
  211. {
  212.     char *p2start = s2;
  213.     char *p1;
  214.  
  215.     p1 = s1 + strlen(s1) - 1;
  216.     while (p1 >= s1) {
  217.         while (*s2) {
  218.             if (*p1 == *s2) return(p1);
  219.             s2++;
  220.             }
  221.         s2 = p2start;
  222.         p1--;
  223.         }
  224.     return( (char *) NULL);
  225.     }
  226.  
  227.  
  228. /*  SearchFirst --  Search for First Directory Entry.
  229.  *                  On entry fcb contains an extended File Control Block
  230.  *                  with file name and attribute bits set.  On exit, fcb
  231.  *                  contains matched entry unless return code is 255, in
  232.  *                  which case no match was found.  This routine is used
  233.  *                    instead of the ones provided by the caller so that the
  234.  *                    cluster information for the directory can be obtained.
  235.  */
  236. SearchFirst(Fcb)
  237. struct ExtFcb *Fcb;
  238. {
  239.     union REGS regs;
  240.  
  241.     regs.x.ax = 0x1100;
  242.     regs.x.dx = (unsigned) Fcb;
  243.     intdos(®s, ®s);
  244.     return((int) (regs.x.ax & 0xFF));
  245.     }
  246.  
  247. /*  Alu2Sec -- Converts an input cluster number [ALU] into the disk-relative
  248.  *             sector for use with DOS Absolute Disk Read [interrupt 25H] or
  249.  *             Absolute Disk Write [interrupt 26H].  Requires access to the
  250.  *             undocumented DOS Disk Parameter Block [use funtion GetDPB].
  251.  */
  252. unsigned int Alu2Sec (Dpb, Alu)
  253. struct DpbStruct *Dpb;
  254. unsigned Alu;
  255. {
  256.     return( (Alu - 2) * (Dpb->ClusterSize + 1) + Dpb->DataStart);
  257.     }
  258.  
  259. /*  NextCl -- This function calculates the logical "chaining" of cluster
  260.  *            numbers in a File Allocation Table [FAT].  Given an entry
  261.  *            cluster number it calculates the next cluster using the
  262.  *            array Fat[].
  263.  *
  264.  *            If Is12Bit is TRUE then Fat[] is assumed to contain 12 bit
  265.  *            entries, otherwise Fat[] is assumed to contain 16 bit entries.
  266.  */
  267. unsigned NextCl(Is12Bit, Cluster, Fat)
  268. int Is12Bit;
  269. unsigned Cluster;
  270. unsigned char Fat[];
  271. {
  272.     unsigned ClWord, ClOffset;
  273.  
  274.     if (Is12Bit) {                                    /* 12 bit FAT lookup */
  275.         ClOffset = 3 * Cluster / 2;
  276.         ClWord = Fat[ClOffset] + (Fat[ClOffset + 1] << 8);
  277.         if (Cluster & 1) return (ClWord >> 4);        /* odd cluster  */
  278.         else return (ClWord & 0x0FFF);                /* even cluster */
  279.         }
  280.     else return (((unsigned int *) Fat)[Cluster]);   /* 16 bit FAT lookup */
  281.     }
  282.  
  283.  
  284. /* PutQueue -- Builds a simple FIFO linked list using dynamically acquired
  285.  *             memory.
  286.  */
  287. void PutQueue (Q, Cluster)
  288. struct ClusterQueue *Q;
  289. unsigned Cluster;
  290. {
  291.     struct ClusterEntry *p;
  292.  
  293.     if ((p = malloc(sizeof(struct ClusterEntry))) == NULL) {
  294.         fprintf(stderr, "Insufficient memory(1).\n");
  295.         AbortProgram();
  296.         }
  297.     p->Next = NULL; p->Cluster = Cluster;
  298.     if (Q->Head == NULL) Q->Head = p;
  299.     else Q->Current->Next = p;
  300.     Q->Current = p; Q->Count++;
  301.     }
  302.  
  303. /* AbortProgram -- Aborts the program, resetting the current directory,
  304.  *                 with an error code of 1.
  305.  */
  306. int AbortProgram () {
  307.  
  308.     bdos(0x3B, (int) CurDir, 0);       /* Reset input Current Directory */
  309.     exit(1);
  310.     }
  311.  
  312.  
  313.  
  314. /* strincmp -- The comparsion routine for the qsort algorithm.
  315.  */
  316. int strincmp (a, b)
  317. struct DirEntry *a, *b;
  318. {
  319.     int  i;
  320.     long t;
  321.  
  322. /* Ensure that "erased" entries sort high no matter what the sort key is.    */
  323.  
  324.     if ((a->Name[0] == 0xE5)  && (b->Name[0] != 0xE5)) return(1);
  325.     if (b->Name[0] == 0xE5) return(-1);
  326.  
  327. /* Ensure that directories sort lower that files no matter what sort key    */
  328.  
  329.     if ((a->Name[0] != 0xE5) && (b->Name[0] != 0xE5)) {
  330.         if ((a->Attribute & 0x10) ^ (b->Attribute & 0x10)) {
  331.             if (a->Attribute & 0x10) return(-1);
  332.             else return(1);
  333.             }
  334.         }
  335.  
  336. /* Actual sort key compare routines  */
  337.  
  338.     switch (Order) {
  339.         case 'D':            /* Sort key is Date/Time            */
  340.             if ((t = a->ModifyDate - b->ModifyDate) == 0) {
  341.                 t = a->ModifyTime - b->ModifyTime;
  342.                 }
  343.             break;
  344.         case 'N':            /* Sort key is Name/Ext (default)    */
  345.             t = strncmp(a->Name, b->Name, 11);
  346.             break;
  347.         case 'E':            /* Sort key is Ext/Name                */
  348.             if ((t = strncmp(a->Ext, b->Ext, 3)) == 0) {
  349.                 t = strncmp(a->Name, b->Name, 8);
  350.                 }
  351.             break;
  352.         case 'S':            /* Sort key is File Size            */
  353.             t = a->FileSize - b->FileSize;
  354.             break;
  355.         default:
  356.             t = strncmp(a->Name, b->Name, 11);
  357.             break;
  358.         }
  359.     if (Inverse) t = -t;    /* Sort order is inverse    */
  360.     return((t < 0) ? -1 : ((t > 0) ? 1 : 0));
  361.     }
  362.  
  363. void Usage () {
  364.  
  365.     printf("USAGE:    CSAP [options] [[d:]directory_name]\n");
  366.     printf("                        or\n");
  367.     printf("          CSAP [[d:]directory_name] [options]\n");
  368.     printf("\n");
  369.     printf("Options:\n");
  370.     printf("    -N    Sort on Name/Ext (default).\n");
  371.     printf("    -D    Sort on Date/Time.\n");
  372.     printf("    -E    Sort on Ext/Name.\n");
  373.     printf("    -S    Sort on File Size.\n");
  374.     printf("\n");
  375.     printf("    -R    Report number of \"erased\" entries and directory location.\n");
  376.     printf("    -I    Inverse sort order, i.e. descending.\n");
  377.     printf("    -P    Do NOT remove \"erased\" entries.\n");
  378.     printf("    -L    Limit sort to a single level.\n");
  379.     printf("    -V    Request confirmation before sorting.\n");
  380.     printf("    -H    This message.\n");
  381.     exit(0);
  382.     }
  383.