home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR2 / CSAP400.ZIP / CSAP.C next >
C/C++ Source or Header  |  1993-09-09  |  18KB  |  578 lines

  1. /*
  2.    ****************************  NOTICE!  **************************
  3.    *   Contrary to the current trend  in  MS-DOS  software  this   *
  4.    *   program,  for  whatever  it is worth,  is NOT copyrighted   *
  5.    *   (with the exception of the runtime library  from  Borland   *
  6.    *   International's  Turbo  C)!  The program,  in whole or in   *
  7.    *   part,  may be used freely in any fashion  or  environment   *
  8.    *   desired.  If  you  find this program to be useful to you,   *
  9.    *   do NOT send any contribution to the author;  in the words   *
  10.    *   of  Rick  Conn,   'Enjoy!'  However,   if  you  make  any   *
  11.    *   improvements,  I would enjoy  receiving  a  copy  of  the   *
  12.    *   modified  source.  I can be reached at the following:       *
  13.    *                                                               *
  14.    *                on CompuServ:           70410,1004             *
  15.    *                on Channel 1 BBS        (xxx) xxx-xxx          *
  16.    *   or by mail or phone:                                        *
  17.    *                                                               *
  18.    *                Don A. Williams                                *
  19.    *                3913 W. Solano Dr. N.                          *
  20.    *                Phoenix, AZ  85019                             *
  21.    *                (602) 841-5333                                 *
  22.    *                                                               *
  23.    *   Every  effort has been made to avoid error and moderately   *
  24.    *   extensive testing has been  performed  on  this  program,   *
  25.    *   however, the author does not warrant it to be fit for any   *
  26.    *   purpose  or  to  be  free  from  error  and disclaims any   *
  27.    *   liability for actual or any other damage arising from the   *
  28.    *   use of this program.                                        *
  29.    *****************************************************************
  30. */
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <dos.h>
  36. #include <ctype.h>
  37. #include <dir.h>
  38. #include <mem.h>
  39. #include <alloc.h>
  40.  
  41. #define MAIN
  42.  
  43. #include "dosstruc.h"
  44.  
  45. /*---   Function Prototypes  ---*/
  46.  
  47. void            Usage(void);
  48. void            GetDPB(int Disk, struct DpbStruct * Dpb);
  49. unsigned        GetDosVersion(void);
  50. char           *strrspn(char *s1, char *s2);
  51. int             AbortProgram(void);
  52. void            SortDir(void);
  53.  
  54. /*---   End of Prototypes  ---*/
  55.  
  56. #define MAX12BIT 0x0FF6
  57. #define MAX16BIT 0xFFF6
  58.  
  59. #if defined(__TINY__)
  60.     #define MODEL "Tiny"
  61. #elif defined(__SMALL__)
  62.     #define MODEL "Small"
  63. #elif defined(__COMPACT__)
  64.     #define MODEL "Compact"
  65. #elif defined(__MEDIUM__)
  66.     #define MODEL "Medium"
  67. #elif defined(__LARGE__)
  68.     #define MODEL "Large"
  69. #elif defined(__HUGE__)
  70.     #define MODEL "Huge"
  71. #endif
  72.  
  73. char            Disk;            /* Alpha working disk ('A', 'B', .... )         */
  74. char            CurDir[67];        /* Storage for Current Directory of disk     */
  75. char            Path[67];        /* Storage for Path to sort                     */
  76. char            Parent[67];        /* Storage for Parent part of Path             */
  77. char            Element[13];    /* Storage for Child part of Path             */
  78. char            Line[80];        /* Working storage for strings                 */
  79. char            Order = 'N';    /* Sort key indicator (Default=Name/Ext)     */
  80. char            Inverse = 0;    /* Ascend/Descend indic. (Default=Ascend)     */
  81. char            Level = 0;        /* Recursive sort indic. (default=Recursive) */
  82. char            RSwt = 0;        /* Report switch (Default=No Report)         */
  83. char            VerSwt = 0;        /* Pause for operator verify (Default=off)     */
  84. char            Packed = 1;        /* Elim. "erased" entries (Default=on)         */
  85. char            TruncateSwt = 0;/* Truncate directories (Default=off)     */
  86. char            FatDirty = 0;    /* FAT needs to be rewritten                 */
  87. int             Is12Bit;        /* 12 / 16 bit cluster indicator             */
  88. int            *CluArray;        /* Cluster Array ptr, dynamically allocated     */
  89. int             Lim, i, j, k, l;
  90. long            m;
  91. int             OutSectors, OutClusters, BytesPerCluster, ECount;
  92. unsigned        LastCluster;    /* Value for end of cluster chain             */
  93. unsigned        Cluster, Sector, NumSec;
  94. unsigned        FatSize;
  95. long            FatRecSize;
  96. short           FatRecCount;
  97.  
  98. struct FatStruct {
  99.     unsigned char  *Ptr;
  100.     unsigned        Size;
  101.     }              *FatArray;
  102.  
  103. unsigned        Version;
  104. long            MinMem;            /* Minimum available memory                     */
  105. unsigned        Freed = 0;        /* Freed cluster count                         */
  106. unsigned        Version;
  107. unsigned        DirStart;
  108.  
  109. struct DpbStruct Dpb;            /* Disk Parameter Block (see dosstruc.h)     */
  110. struct ClusterQueue CluQ;        /* Queue of cluster for directory             */
  111. struct DirEntry *DirBuff;        /* Buffer for directory to be sorted         */
  112. struct ExtendedEntry Dir;
  113. struct ClusterEntry *p, *t;
  114. struct ExtFcb   Fcb;
  115.  
  116.  void
  117. main (int argc, char *argv[]) {
  118.     char           *strrspn();
  119.     void            SortDir(), Usage();
  120.     char           *p, *p1, t1;
  121.     int             i, j;
  122.  
  123.     bdos(0x0D, 0, 0);            /* Reset Disk Subsystem - Flush all buffers */
  124.     fputs("C-Sort And Pack [CSAP]: Version 4.0.0: Date: September 12, 1993", stderr);
  125.     fputs(" [", stderr);
  126.     fputs(MODEL, stderr);
  127.     fputs(" Model]\n", stderr);
  128.     fputs("    use \"CSAP -H\" or \"CSAP ?\" for help.\n\n", stderr);
  129.  
  130.     Disk = getdisk() + 'A';
  131.     Line[0] = '\\';
  132.     getcurdir(Disk - '@', &Line[1]);
  133.  
  134.     ctrlbrk(AbortProgram);        /* Install "wrap-up" in Control Break vec. */
  135.  
  136.     /* Interpret command line arguments, if any      */
  137.  
  138.     for (i = 1; i < argc; ++i) {
  139.         if (argv[i][0] == '-') {
  140.             for (j = 1; j < strlen(argv[i]); ++j) {
  141.                 switch (toupper(argv[i][j])) {
  142.                     case 'N':    /* Sort Key = Name/Ext (default)     */
  143.                         Order = 'N';
  144.                         break;
  145.                     case 'D':    /* Sort Key = Date/Time                */
  146.                         Order = 'D';
  147.                         break;
  148.                     case 'E':    /* Sort Key = Ext/Name                 */
  149.                         Order = 'E';
  150.                         break;
  151.                     case 'S':    /* Sort Key = File Size                 */
  152.                         Order = 'S';
  153.                         break;
  154.                     case 'R':    /* Report Dir loc. & "erased"         */
  155.                         RSwt = 1;
  156.                         break;
  157.                     case 'I':    /* Sort order inverse                 */
  158.                         Inverse = 1;
  159.                         break;
  160.                     case 'P':    /* Do NOT remove "erased" entries     */
  161.                         Packed = 0;
  162.                         break;
  163.                     case 'L':    /* Limit sort to one level             */
  164.                         Level = 1;
  165.                         break;
  166.                     case 'V':    /* Request approval before sort         */
  167.                         VerSwt = 1;
  168.                         break;
  169.                     case 'T':    /* Truncate directories                 */
  170.                         TruncateSwt = 1;
  171.                         break;
  172.                     case 'H':
  173.                         Usage();
  174.                     default:    /* Illegal option                     */
  175.                         fprintf(stderr, "Invalid option %s.\n", argv[i]);
  176.                         Usage();
  177.                         break;
  178.                 }
  179.             }
  180.         }
  181.         else {                    /* Not switch, assume directory name or '?'         */
  182.             if (argv[i][0] == '?') Usage();
  183.             if (argv[i][1] == ':') {    /* Check for disk specified     */
  184.                 Disk = toupper(argv[i][0]);
  185.                 p = &argv[i][2];
  186.             }
  187.             else p = &argv[i][0];
  188.             if ((p[0] != '\\') && (p[0] != '/')) {
  189.                 Line[0] = '\\';
  190.                 getcurdir(Disk - '@', &Line[1]);
  191.                 p1 = &p[strcspn(p, "\\/")];
  192.                 t1 = *p1;
  193.                 *p1 = '\0';
  194.                 if (!strcmp(p, ".")) {
  195.                     p = p1;
  196.                     *p1 = t1;
  197.                 }
  198.                 else if (!strcmp(p, "..")) {
  199.                     while (!strcmp(p, "..")) {
  200.                         p = strrspn(Line, "\\/");
  201.                         if ((p - Line) == 0) ++p;
  202.                         *p = '\0';
  203.                         if (t1 != '\0') p = ++p1;
  204.                         else p = p1;
  205.                         p1 = &p[strcspn(p, "\\/")];
  206.                         t1 = *p1;
  207.                         *p1 = '\0';
  208.                     }
  209.                     *p1 = t1;
  210.                 }
  211.                 else *p1 = t1;
  212.                 if (*p != '\0') strcat(Line, "\\");
  213.                 strcat(Line, p);
  214.             }
  215.             else strcpy(Line, p);
  216.         }
  217.     }
  218.  
  219.     /*
  220.      * Get disk information - uses un-documented DOS call, Int 21H, Func. 32H
  221.      * This function has been verified to work correctly in PC/MS-DOS
  222.      * versions 2.0 through 3.3.  It is heavily used by DOS programs such as
  223.      * CHKDSK.
  224.      */
  225.  
  226.     GetDPB(Disk, &Dpb);
  227.     Version = GetDosVersion() & 0xFF;
  228.     switch (Version) {
  229.         case 2:
  230.             FatSize = Dpb.V.V2.FatSize;
  231.             DirStart = Dpb.V.V2.DirStart;
  232.             break;
  233.         case 3:
  234.             FatSize = Dpb.V.V3.FatSize;
  235.             DirStart = Dpb.V.V3.DirStart;
  236.             break;
  237.         case 4:
  238.         case 5:
  239.         case 6:
  240.             FatSize = Dpb.V.V4.FatSize;
  241.             DirStart = Dpb.V.V4.DirStart;
  242.             break;
  243.         default:
  244.             fprintf(stderr, "Invalid DOS version: %d\n", Version);
  245.             exit(1);
  246.     }
  247.     FatRecSize = FatSize * Dpb.SectorSize;
  248.  
  249.     /* Establish whether disk has 16-bit or 12-bit clusters  */
  250.  
  251.     if (Dpb.LastCluster > MAX16BIT) {
  252.         fprintf(stderr, "Sorry, CSAP does not yet support FAT entries > 16 bits.\n");
  253.         exit(1);
  254.     }
  255.     Is12Bit = (Dpb.LastCluster > MAX12BIT) ? 0 : 1;
  256.     LastCluster = (Is12Bit) ? 0x0FF8 : 0xFFF8;
  257.  
  258.     /*
  259.      * Get & save current directory of working disk.  We have to change to
  260.      * sort and must restore on termination
  261.      */
  262.  
  263.     CurDir[0] = Disk;
  264.     CurDir[1] = ':';
  265.     CurDir[2] = '\\';
  266.     getcurdir(Disk - '@', (char *) &CurDir[3]);
  267.  
  268.     /* Allocate space to hold entire FAT in memory and read it in  */
  269.  
  270.     FatRecCount = (FatRecSize / FAT_BLK) + 1;
  271.     if ((FatArray = malloc(FatRecCount * sizeof(struct FatStruct))) == NULL) {
  272.         fprintf(stderr, "Insufficient memory for FAT array.\n");
  273.         exit(1);
  274.     }
  275.     for (m = FatRecSize, i = 0; i < FatRecCount; i++, m -= (m > FAT_BLK) ? FAT_BLK : m) {
  276.         if ((FatArray[i].Ptr = malloc((m > FAT_BLK) ? FAT_BLK : (unsigned) m)) == NULL) {
  277.             fprintf(stderr, "Insufficient memory for FAT Array entry.\n");
  278.             exit(1);
  279.         }
  280.         FatArray[i].Size = (m > FAT_BLK) ? FAT_BLK : (unsigned) m;
  281.     }
  282.  
  283.     for (i = 0, m = Dpb.FatStart; i < FatRecCount; m += FatArray[i].Size / Dpb.SectorSize, i++) {
  284.         if (absread(Disk - 'A', FatArray[i].Size / Dpb.SectorSize, m, FatArray[i].Ptr) != 0) {
  285.             fprintf(stderr, "Error reading FAT.\n");
  286.             perror("");
  287.             exit(1);
  288.         }
  289.     }
  290.  
  291.     /*
  292.      * Develop full path name for directory to be sorted and separate into
  293.      * Parent and Child portions
  294.      */
  295.  
  296.     Path[0] = Parent[0] = Element[0] = '\0';
  297.     Path[0] = Disk;
  298.     Path[1] = ':';
  299.     Path[2] = '\0';
  300.     if ((Line[0] != '\\') && (Line[0] != '/')) {
  301.         strcat(Path, "\\");
  302.         strcpy(&Path[3], &CurDir[3]);
  303.         if ((Path[strlen(Path) - 1] != '\\') && (Path[strlen(Path) - 1] != '/'))
  304.             strcat(Path, "\\");
  305.     }
  306.     strcat(Path, Line);
  307.     p = strrspn(Path, "\\/");
  308.     strcpy(Element, &p[1]);
  309.     if (p[-1] == ':') p++;
  310.     strncpy(Parent, Path, (int) (p - Path));
  311.     Parent[(int) (p - Path)] = '\0';
  312.  
  313.     MinMem = coreleft();        /* Initialize minimum available memory         */
  314.  
  315.     /*
  316.      * Perform sort.  SortDir is recursive and, if Level is not on, will sort
  317.      * sort all levels of the hierarchy from the starting level down
  318.      */
  319.  
  320.     SortDir();
  321.  
  322.     printf("Minimum memory= %ld\n", MinMem);
  323.  
  324.     bdos(0x0D, 0, 0);            /* Reset disk subsystem - flush all buffers */
  325.     if (FatDirty) {
  326.         for (i = 0, m = Dpb.FatStart; i < FatRecCount; m += FatArray[i].Size / Dpb.SectorSize, i++) {
  327.             if (abswrite(Disk - 'A', FatArray[i].Size / Dpb.SectorSize, m, FatArray[i].Ptr) != 0) {
  328.                 fprintf(stderr, "Error writing FAT.\n");
  329.                 perror("");
  330.                 exit(1);
  331.             }
  332.         }
  333.         if (Dpb.FatCopies == 2) {
  334.             for (i = 0, m = Dpb.FatStart + FatSize; i < FatRecCount; m += FatArray[i].Size / Dpb.SectorSize, i++) {
  335.                 if (abswrite(Disk - 'A', FatArray[i].Size / Dpb.SectorSize, m, FatArray[i].Ptr) != 0) {
  336.                     fprintf(stderr, "Error writing 2nd copy of FAT.\n");
  337.                     perror("");
  338.                     exit(1);
  339.                 }
  340.             }
  341.         }
  342.         printf("There %s %d cluster%s (%d bytes) freed\n",
  343.                (Freed == 1) ? "was" : "were",
  344.                Freed,
  345.                (Freed == 1) ? "" : "s",
  346.                Freed * Dpb.SectorSize * (Dpb.ClusterSize + 1));
  347.     }
  348.     bdos(0x0D, 0, 0);            /* Reset disk subsystem - flush all buffers */
  349.     bdosptr(0x3B, CurDir, 0);    /* Restore input "current" directory     */
  350. }                                /* end Main */
  351.  
  352.  
  353. /*
  354.  * STRRSPN is simply a reverse version of STRSPN.  It finds the LAST
  355.  * occurance in S1 of any member of S2.  For some reason, none of the C
  356.  * compilers that I use provide this although they all provide STRSPN
  357.  */
  358.  
  359.  char           *
  360. strrspn (char *s1, char *s2) {
  361.     char           *p1;
  362.  
  363.     p1 = s1 + strlen(s1) - 1;
  364.     while (p1 >= s1) {
  365.         if (strchr(s2, *p1) != NULL) return (p1);
  366.         --p1;
  367.     }
  368.     return ((char *) NULL);
  369. }
  370.  
  371.  
  372. /*
  373.  * SearchFirst --  Search for First Directory Entry. On entry fcb contains an
  374.  * extended File Control Block with file name and attribute bits set.  On
  375.  * exit, fcb contains matched entry unless return code is 255, in which case
  376.  * no match was found.  This routine is used instead of the ones provided by
  377.  * the compiler so that the cluster information for the directory can be
  378.  * obtained.
  379.  */
  380.  
  381.  int
  382. SearchFirst (struct ExtFcb * Fcb) {
  383.     union REGS      regs;
  384.  
  385.     regs.x.ax = 0x1100;
  386.     regs.x.dx = (unsigned) Fcb;
  387.     intdos(®s, ®s);
  388.     return ((int) (regs.x.ax & 0xFF));
  389. }
  390.  
  391.  
  392.  
  393. /*
  394.  * Alu2Sec -- Converts an input cluster number [ALU] into the disk-relative
  395.  * sector for use with DOS Absolute Disk Read [interrupt 25H] or Absolute
  396.  * Disk Write [interrupt 26H].  Requires access to the undocumented DOS Disk
  397.  * Parameter Block [use funtion GetDPB].
  398.  */
  399.  
  400.  long
  401. Alu2Sec (struct DpbStruct * Dpb, unsigned Alu) {
  402.  
  403.     return ((long) (Alu - 2) * (Dpb->ClusterSize + 1) + Dpb->DataStart);
  404. }
  405.  
  406. /*
  407.  * NextCl -- This function calculates the logical "chaining" of cluster
  408.  * numbers in a File Allocation Table [FAT].  Given an entry cluster number
  409.  * it calculates the next cluster using the array Fat[].
  410.  *
  411.  * If Is12Bit is TRUE then Fat[] is assumed to contain 12 bit entries, otherwise
  412.  * Fat[] is assumed to contain 16 bit entries.
  413.  */
  414.  
  415.  unsigned
  416. NextCl (int Is12Bit, unsigned Cluster) {
  417.     unsigned        ClWord, ClOffset;
  418.  
  419.     if (Is12Bit) {                /* 12 bit FAT lookup */
  420.         ClOffset = 3 * Cluster / 2;
  421.         ClWord = (FatArray[ClOffset/FAT_BLK].Ptr[ClOffset%FAT_BLK] & 0xFF)
  422.             + (FatArray[(ClOffset+1)/FAT_BLK].Ptr[(ClOffset+1)%FAT_BLK] << 8);
  423.         if (Cluster & 1) return (ClWord >> 4);    /* odd cluster  */
  424.         else return (ClWord & 0x0FFF);    /* even cluster */
  425.     }
  426.     else
  427.         return (((unsigned int *) FatArray[Cluster / INT_FAT_BLK].Ptr)[Cluster % INT_FAT_BLK]);    /* 16 bit FAT lookup */
  428. }
  429.  
  430.  
  431.  void
  432. FreeCluster (int Is12Bit, unsigned Val, unsigned Cluster) {
  433.     extern char     FatDirty;
  434.     extern unsigned Freed;
  435.     unsigned        ClWord, ClOffset;
  436.  
  437.     if (Is12Bit) {                /* 12 bit FAT lookup */
  438.         ClOffset = 3 * Cluster / 2;
  439.         ClWord = FatArray[ClOffset/FAT_BLK].Ptr[ClOffset%FAT_BLK]
  440.             + (FatArray[(ClOffset+1)/FAT_BLK].Ptr[(ClOffset+1)%FAT_BLK] << 8);
  441.         if (Cluster & 1) ClWord = (ClWord & 0xF) | (Val & 0xFFF0);    /* odd     */
  442.         else ClWord = (ClWord & 0xF000) | (Val & 0x0FFF);
  443.         FatArray[(ClOffset+1)/FAT_BLK].Ptr[(ClOffset+1)%FAT_BLK] = ClWord >> 8;
  444.         FatArray[ClOffset/FAT_BLK].Ptr[ClOffset%FAT_BLK] = ClWord & 0xFF;
  445.     }
  446.     else
  447.         ((unsigned int *) FatArray[Cluster/INT_FAT_BLK].Ptr)[Cluster%INT_FAT_BLK] = Val;    /* 16 bit FAT lookup */
  448.     if (!Val) ++Freed;
  449. }
  450.  
  451.  
  452. /*
  453.  * PutQueue -- Builds a simple FIFO linked list using dynamically acquired
  454.  * memory.
  455.  */
  456.  
  457.  void
  458. PutQueue (struct ClusterQueue * Q, unsigned Cluster) {
  459.     struct ClusterEntry *p;
  460.  
  461.     if ((p = malloc(sizeof(struct ClusterEntry))) == NULL) {
  462.         fprintf(stderr, "Insufficient memory(1).\n");
  463.         AbortProgram();
  464.     }
  465.     p->Next = NULL;
  466.     p->Cluster = Cluster;
  467.     if (Q->Head == NULL) Q->Head = p;
  468.     else Q->Current->Next = p;
  469.     Q->Current = p;
  470.     Q->Count++;
  471. }
  472.  
  473.  
  474. /*
  475.  * AbortProgram -- Aborts the program, resetting the current directory, with
  476.  * an error code of 1.
  477.  */
  478.  
  479.  int
  480. AbortProgram (void) {
  481.  
  482.     bdos(0x0D, 0, 0);            /* Reset disk subsystem - flush all buffers */
  483.     bdosptr(0x3B, CurDir, 0);    /* Reset input Current Directory */
  484.     exit(1);
  485.     return (0);
  486. }
  487.  
  488.  
  489. /*
  490.  * strincmp -- The comparsion routine for the qsort algorithm.
  491.  */
  492.  
  493.  int
  494. strincmp (struct DirEntry * a, struct DirEntry * b) {
  495.     long            t;
  496.  
  497.     /*
  498.      * Ensure that "erased" entries sort high no matter what the sort key is.
  499.      */
  500.  
  501.     if ((a->Name[0] == 0xE5) && (b->Name[0] != 0xE5)) return (1);
  502.     if (b->Name[0] == 0xE5) return (-1);
  503.  
  504.     /*
  505.      * Ensure that directories sort lower than files no matter what sort key
  506.      */
  507.  
  508.     if ((a->Name[0] != 0xE5) && (b->Name[0] != 0xE5)) {
  509.         if ((a->Attribute & 0x10) ^ (b->Attribute & 0x10)) {
  510.             if (a->Attribute & 0x10) return (-1);
  511.             else return (1);
  512.         }
  513.     }
  514.  
  515.     /* Actual sort key compare routines  */
  516.  
  517.     switch (Order) {
  518.         case 'D':                /* Sort key is Date/Time             */
  519.             if (a->ModifyDate < b->ModifyDate) t = -1;
  520.             else if (a->ModifyDate > b->ModifyDate) t = 1;
  521.             else {
  522.                 if (a->ModifyTime < b->ModifyTime) t = -1;
  523.                 else if (a->ModifyTime > b->ModifyTime) t = 1;
  524.                 else t = 0;
  525.             }
  526.             break;
  527.         case 'N':                /* Sort key is Name/Ext (default)     */
  528.             t = strncmp((char *) a->Name, (char *) b->Name, 11);
  529.             break;
  530.         case 'E':                /* Sort key is Ext/Name                 */
  531.             if ((t = strncmp(a->Ext, b->Ext, 3)) == 0) {
  532.                 t = strncmp((char *) a->Name, (char *) b->Name, 8);
  533.             }
  534.             break;
  535.         case 'S':                /* Sort key is File Size             */
  536.             t = a->FileSize - b->FileSize;
  537.             break;
  538.         default:
  539.             t = strncmp((char *) a->Name, (char *) b->Name, 11);
  540.             break;
  541.     }
  542.     if (Inverse) t = -t;                    /* Sort order is inverse     */
  543.     return ((t < 0) ? -1 : ((t > 0) ? 1 : 0));
  544. }
  545.  
  546.  unsigned
  547. GetDosVersion (void) {
  548.     union REGS      Regs;
  549.  
  550.     Regs.h.ah = 0x30;
  551.     intdos(&Regs, &Regs);
  552.     return (Regs.x.ax);
  553. }
  554.  
  555.  
  556.  void
  557. Usage (void) {
  558.  
  559.     printf("USAGE:    CSAP [options] [[d:]directory_name]\n");
  560.     printf("                        or\n");
  561.     printf("          CSAP [[d:]directory_name] [options]\n");
  562.     printf("\n");
  563.     printf("Options:\n");
  564.     printf("    -N    Sort on Name/Ext (default).\n");
  565.     printf("    -D    Sort on Date/Time.\n");
  566.     printf("    -E    Sort on Ext/Name.\n");
  567.     printf("    -S    Sort on File Size.\n");
  568.     printf("\n");
  569.     printf("    -R    Report number of \"erased\" entries and directory location.\n");
  570.     printf("    -I    Inverse sort order, i.e. descending.\n");
  571.     printf("    -P    Do NOT remove \"erased\" entries.\n");
  572.     printf("    -L    Limit sort to a single level.\n");
  573.     printf("    -V    Request confirmation before sorting.\n");
  574.     printf("    -T    Truncate directories.\n");
  575.     printf("    -H    This message.\n");
  576.     exit(0);
  577. }
  578.