home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / dirutl / di11.arc / DIPRINT.C < prev    next >
Text File  |  1987-11-29  |  21KB  |  516 lines

  1. #include <stdio.h>
  2. #include <dir.h>
  3. #include <dos.h>
  4. #include <ctype.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <io.h>
  8. #include "di.h"
  9. long FreeSpace(int Drive);
  10. long SpaceUsed(Entry *Entries,int Num,int Drive);
  11. char *Label(int Drive);
  12. char *AddCommasL(long N);
  13. char *FileDate(int PDate);
  14. char *FileTime(int PTime);
  15. void PrintFull(Entry *Entries,int Num,char *Dir);
  16. void PrintLong(Entry *Entries,int Num);
  17. void PrintShort(Entry *Entries,int Num,int LineEnts);
  18. void FiltAttribs(int *OldAtts,int *NewAtts,int Att);
  19. AUSize(int Drive);
  20. MatchingAtts(int Attribs[],char Attrib);
  21.  
  22. void PrintHeader(NameNode *Files,int PrintFree)
  23. /* Prints the volume label and, if PrintFree is true, the free space for all
  24.    drives specified in the filespecs in Files, including the default drive if
  25.    indicated by any filespec. */
  26. {
  27. int Drives[26],    /* One entry for each drive, indicating whether it should be
  28.            printed */
  29. Drive,    /* Specific or default drive specified in current filespec */
  30. CurDrive,    /* Default drive */
  31. I;    
  32. char *Volume;    /* Volume label of a drive */
  33.  
  34.    CurDrive = getdisk();    /* Get default drive in case it is specified */
  35.    for (I = 0; I <= 25; I++)    /* Initialize array to no drives speced */
  36.       Drives[I] = FALSE;
  37.    while (Files != NULL) {    /* For each filespec */
  38.       if (strchr(Files -> Name,':') == NULL)    /* If no drive speced, use
  39.                                  default drive */
  40.          Drives[CurDrive] = TRUE;
  41.       else {
  42.          Drive = Files -> Name[0] - 'A';    /* Get drive number */
  43.          if (0 <= Drive && Drive <= 25)    /* Make sure it is a letter */
  44.             Drives[Drive] = TRUE;
  45.       }
  46.       Files = Files -> Next;
  47.    }
  48.    putchar('\n');    /* Put a blank line between program invokation and
  49.                   first line of listing */
  50.    for (I = 0; I <= 25; I++)    /* For each possible drive */
  51.       if (Drives[I]) {    /* If drive was specified in any filespec */
  52.          Volume = Label(I);    /* Get volume label */
  53.          if (Volume == NULL)    
  54.             printf("Volume in drive %c has no label",I + 'A');
  55.          else
  56.             printf("Volume in drive %c is %s",I + 'A',Volume);
  57.          if (PrintFree)    /* If PrintFree is true, print free space */
  58.             printf("  : %s bytes free",AddCommasL(FreeSpace(I)));
  59.          puts(".");
  60.          More(1);    
  61.       }
  62. }
  63.  
  64. int AUSize(int Drive)
  65. /* Returns the size of the allocation units on drive Drive, in bytes. */
  66. {
  67.    struct fatinfo FatInfo;    /* Struct used by getfat() */
  68.    getfat(Drive + 1,&FatInfo);
  69.    /* Size of allocation units = # of sectors per cluster * bytes per sector */
  70.    return(FatInfo.fi_sclus * FatInfo.fi_bysec);
  71. }
  72.  
  73. long SpaceUsed(Entry *Entries,int Num,int Drive)
  74. /* Returns the actual amount of space used by all of the files in Entries,
  75.    assuming that they are on drive Drive */
  76. {
  77.    int AU;    /* Size of allocation units on drive Drive */
  78.    int I;
  79.    long TotalSpace = 0L;    /* Total space used by the files */
  80.  
  81.    AU = AUSize(Drive);    /* Find size of alloc units */
  82.    for (I = 0; I < Num; I++)    /* For each file, add the space it uses */
  83.       TotalSpace += (Entries[I] -> ff_fsize + AU - 1) / AU * AU;
  84.    return(TotalSpace);
  85. }
  86.  
  87. char *AddCommasL(long N)
  88. /* Converts long integer N to a string, stores it in a static buffer,
  89.    inserts commas where appropriate, and returns a pointer to the bufffer */
  90. {
  91. static char Buf[15];    /* Buffer */
  92. int Pos,    /* Current position that comma is being inserted at */
  93. Num,        /* Number of commas to insert */
  94. I;
  95.  
  96.    Pos = sprintf(Buf,"%ld",N);    /* Convert N to a string and put the length of
  97.                       the string in Pos */
  98.    Num = ((Buf[0] == '-' ? Pos - 1 : Pos) - 1) / 3;    /* Find num of commas
  99.                                   to insert */
  100.    for (I = 0; I < Num; I++) {
  101.       Pos -= 3;        /* Find next location at which to insert comma */
  102.       Insert(Buf,",",Pos);
  103.    }
  104.    return(Buf);
  105. }
  106.  
  107. long FreeSpace(int Drive)
  108. /* Returns the free space on drive Drive */
  109. {
  110. struct dfree DFree;    /* Structure used by getdfree */
  111.  
  112.    getdfree(Drive + 1,&DFree);    /* Get available clusters, sectors/cluster,
  113.                       and bytes/sector */
  114.    ExTest(DFree.df_sclus == -1,"Disk error.");    /* Exit if error */
  115.    return((long) DFree.df_avail * DFree.df_bsec * (long) DFree.df_sclus);
  116. }
  117.  
  118. char *Label(int Drive)
  119. /* if drive Drive (0 = A, 1 = B, etc) has a label, it is put in a static
  120.    buffer and a pointer to the buffer is returned. Otherwise a null
  121.    pointer is returned */
  122. {
  123. static char *FileSpec = " :\\*.*",    /* Filespec that will by used to
  124.                 find label, with room for drive letter */
  125. Volume[13];    /* Buffer */
  126. struct ffblk FFBlk;    /* Structure used by findfirst() */
  127. char *Dot;    /* Start of file ext in volume label */
  128.  
  129.    FileSpec[0] = Drive + 'A';    /* Add drive letter to filespec */
  130.    if (findfirst(FileSpec,&FFBlk,FA_LABEL))    /* Get label */
  131.       return(NULL);    /* if no label, return null */
  132.    else {
  133.       strcpy(Volume,FFBlk.ff_name);    /* Copy label to volume */
  134.       Dot = strchr(Volume,'.');    
  135.       if (Dot != NULL)    /* If volume had a dot in it, remove it */
  136.          strcpy(Dot,Dot - Volume + FFBlk.ff_name + 1);
  137.       return(Volume);
  138.    }
  139. }
  140.  
  141. void GetEntries(EntryListType *EntryList,int Attribs[],char Name[],int PrintCP)
  142. /* calloc() is used to make an array of pointers to the structure returned by
  143.    findfirst/next.  The array is expanded with realloc() as neccessary.
  144.    Elements of the array are made to point to matching directory entries.
  145.    A dir entry will match if its name matches Name and its attribs match at
  146.    least one of the attrib and-terms in Attribs.  "." and ".." dir entries will
  147.    match only attrib specs that specifically include dirs, and only if PrintCP
  148.    is true.  The entry list and number of matching entries found are returned
  149.    in EntryList. */
  150. {
  151. int Done,    /* Whether all matching files have been found */
  152. NumEnts,    /* Number of matching entries found */
  153. DirAttribs[MAX_ATTS];    /* Attribute list containing those attrib terms in
  154.                Attribs that specifically include directories */
  155. unsigned Length;    /* Current length that the entry array has been
  156.                c/realloc()ed to */
  157. Entry *Entries;        /* Entry array */
  158.  
  159.    if (PrintCP)
  160.       FiltAttribs(Attribs,DirAttribs,FA_DIREC);    /* Copy all entries in Attribs
  161.                that specifically include dirs into DirAttribs */
  162.    else
  163.       *DirAttribs = NO_AT;
  164.    Length = ENTRY_INC;    /* Do initial allocation for Entries */
  165.    Entries = (Entry *) CallocT(Length,sizeof(Entry));
  166.    NumEnts = 0;        /* No entries found yet */
  167.    Entries[0] = (Entry) MallocT(sizeof(struct ffblk));    /* Start with one
  168.                                empty entry */
  169.    Done = findfirst(Name,Entries[0],0x3f);
  170.    while (!Done) {  /* For each entry in specified dir that matches Name */
  171.      if (MatchingAtts(CPDir(Entries[NumEnts] -> ff_name) ?
  172.       DirAttribs : Attribs,Entries[NumEnts] -> ff_attrib)) { /* Check whether
  173.        the attribs of the found entry match any of those in Attribs if the
  174.        found entry is not the current or parent dir ("." or ".."), or in
  175.        DirAttribs if it is one of them.  The current or parent dir will
  176.        therefore only be printed if directories have specifically been
  177.        requested */
  178.         if (NumEnts == Length - 1) {  /* Reallocate Entries with more space */
  179.            Length += ENTRY_INC;
  180.            Entries = (Entry *) ReallocT(Entries,Length * sizeof(Entry));
  181.         }
  182.         Entries[++NumEnts] = (Entry) MallocT(sizeof(struct ffblk));  /* Add
  183.                             new empty node */
  184.         *(Entries[NumEnts]) = *(Entries[NumEnts - 1]); /* copy last matching
  185.                 entry to new node for next call to findnext() */
  186.       }
  187.       Done = findnext(Entries[NumEnts]);     /* Get next matching entry */
  188.    }
  189.    free(Entries[NumEnts]);    /* Get rid of last node added, since it is the
  190.                       one that findnext() failed on */
  191.    EntryList -> NumEnts = NumEnts;    /* Copy array & num of entries to
  192.                           EntryList */
  193.    EntryList -> Entries = Entries;
  194. }
  195.  
  196. void FiltAttribs(int OldAtts[],int NewAtts[],int Att)
  197. /* Copies all attributes in OldAtts that have at least one of the attribs
  198.    indicated in Att, or that have no attribs (= 0) to NewAtts */
  199. {
  200. int I,
  201. NumAtts;    /* Number of matching attrib terms found */
  202.  
  203.    NumAtts = I = 0;
  204.    while (OldAtts[I] != NO_AT) {
  205.       if (OldAtts[I] & Att || OldAtts[I] == 0)
  206.          NewAtts[NumAtts++] = OldAtts[I];
  207.       I++;
  208.    }
  209.    NewAtts[NumAtts] = NO_AT;    /* Mark end of array */
  210. }
  211.  
  212. void PrintList(EntryListType *EntryList, /* Entry list and length of list */
  213.  ListType *ListSpec, /* Specifies what type of listing to do */
  214.  char *Dir /* Name of path that list was produced from */)
  215. /* Print list of dir entries according to ListSpec */
  216. {
  217. int J,
  218. NumEnts;    /* Number of entries in list */
  219. Entry *Entries;    /* Entry list */
  220.  
  221.    Entries = EntryList -> Entries;
  222.    NumEnts = EntryList -> NumEnts;
  223.    if (ListSpec -> ListType != 'F' && ListSpec -> PrintHeaders) {
  224.       /* If list type is not "full path" and headers are to be printed...*/
  225.       printf("Directory of %s  : %d matching file(s)",Dir,NumEnts);
  226.       if (ListSpec -> PrintFree)    /* Print total space used by files */
  227.          printf(" using %ldk",
  228.           (SpaceUsed(Entries,NumEnts,(int) *Dir - 'A') + 1023) >> 10);
  229.       puts(".\n");
  230.       More(2);
  231.    }
  232.    if (NumEnts) {    /* If at least one matching entry for dir */
  233.       switch (ListSpec -> ListType) {
  234.          case 'W' : PrintShort(Entries,NumEnts,ListSpec -> LineEnts);
  235.                     break;
  236.          case 'L' : PrintLong(Entries,NumEnts);
  237.                     break;
  238.          case 'F' : PrintFull(Entries,NumEnts,Dir);
  239.       }
  240.       for (J = 0; J < NumEnts; J++) /* Free entry nodes pointed to by array */
  241.          free(Entries[J]);
  242.    }
  243.    free(Entries);    /* Free array */
  244. }
  245.  
  246. MatchingAtts(int Attribs[],char Attrib)
  247. /* Returns true if Attrib matches any of the attrib and-terms in Attribs;
  248.    otherwise returns false.  Attrib will match a term if it has all of the
  249.    attributes specified in the low byte of the term and none of the attribs
  250.    specified in the high byte of the term */
  251. {
  252. int I,
  253. FullAtt;    /* Full attribute */
  254.  
  255.    FullAtt = Attrib | (~((int) Attrib) << 8);    /* Produce full attrib by
  256.     copying Attrib in true form into the low byte and complemented form
  257.     into the high byte. */
  258.    I = 0;
  259.    while (Attribs[I] != NO_AT && (Attribs[I] & FullAtt) != Attribs[I])
  260.     /* Check whether Attrib matches any of the attribute terms given in
  261.        Attribs. To check for match, FullAtt is first ANDed with an attrib
  262.        term.  Since Attrib is true in the low byte of FullAtt, all attrib
  263.        bits that Attrib has and are specified in lo byte of the term (attribs
  264.        that Attrib must have to match) will be on in the low byte of the
  265.        result.  Since Attrib is complemented in the high
  266.        byte of FullAtt, all attrib bits that Attrib does not have and are
  267.        specified in the high byte of the term (attribs that Attrib cannot
  268.        have if it is to match) will be on in the high byte of the result.
  269.        In order to match, the result must therefor be equal to the term. */
  270.       I++;
  271.    return(Attribs[I] != NO_AT);
  272. }
  273.  
  274. void PrintShort(Entry *Entries,int Num,int LineEnts)
  275. /* Prints a 'short' listing of the entries in Entries.  Prints the file names
  276.    only, with LineEnts names on each line.  A backslash is appended to
  277.    directory entries. Num is the number of entries in Entries */
  278. {
  279. int I,
  280. Width,        /* Width to print each name with (padding with blanks) */
  281. NotEven;    /* Whether the entries will exactly fit on a line */
  282. char *Name,    /* Points to the name being printed (either the original
  283.             list entry or a copy of it with a backslash appended) */
  284. Dir[14];    /* Copy of the file name, with a backslash appended to
  285.            indicate that it is a directory */
  286.  
  287.    Width = 80 / LineEnts;    /* Find width to print each name with */
  288.    NotEven = 80 % LineEnts;    /* Determine whether LineEnts names will
  289.                    exactly fit on a line */
  290.    for (I = 0; I < Num; I++) {    /* For each entry */
  291.       if (Entries[I] -> ff_attrib & FA_DIREC) {    /* If the entry is a dir, make
  292.        a copy of it, append a backslash to it, & make Name point to the copy */
  293.          strcpy(Dir,Entries[I] -> ff_name);
  294.          strcat(Dir,"\\");
  295.          Name = Dir;
  296.       }
  297.       else    /* Otherwise make Name point to the original name */
  298.          Name = Entries[I] -> ff_name;
  299.       printf("%-*s",Width,Name);    /* Print the name */
  300.       if ((I + 1) % LineEnts == 0) {    /* If it was the last name on a line */
  301.          if (NotEven)    /* If LineEnts entries do not exactly fit on a line,
  302.           the cursor will not have automatically wrapped around to the next
  303.           line; print a newline */
  304.             putchar('\n');
  305.          More(1);
  306.       }
  307.    }
  308.    if (I % LineEnts) {    /* If the last name printed was not the last one on
  309.                a line and therefore did not cause a CR, print one */
  310.       putchar('\n');
  311.       More(1);
  312.    }
  313. }
  314.  
  315. void PrintLong(Entry *Entries,int Num)
  316. /* Print a 'long' dir listing. Prints each file's name, ext, size, time, date,
  317.    and attributes.  Dirs and the volume label report a size of 0, so they are
  318.    printed with a special label in the size column.  The list is modified. */
  319. {
  320. int I;
  321. Entry File;    /* Entry being printed */
  322. char Size[12],    /* File size converted to a string, or a special label for
  323.            dirs and the volume label */
  324. *Ext;        /* Start of the extension of the file name */
  325.  
  326.    for (I = 0; I < Num; I++) {
  327.       File = Entries[I];
  328.       if (File -> ff_attrib & FA_DIREC)    /* If entry is a dir or the vol label,
  329.                         give it a label instead of a file size */
  330.          strcpy(Size,"<DIR>  ");
  331.       else if (File -> ff_attrib & FA_LABEL)
  332.          strcpy(Size,"<LAB>  ");
  333.       else
  334.          sprintf(Size,"%ld",File -> ff_fsize);
  335.       Ext = strchr(File -> ff_name,'.');    /* Find the start of the ext
  336.                                  of the file name */
  337.       if (Ext == NULL || CPDir(File -> ff_name))    /* If there is no ext,
  338.        or the first dot in the entry for the current or parent dir was found,
  339.        make Ext point to a null string */
  340.          Ext = "";
  341.       else {
  342.          *Ext = '\0';    /* Otherwise make Ext point to the start of the file
  343.           ext and replace the dot with a null char so that when the file name
  344.           is printed it will not include the file ext */
  345.          Ext++;
  346.       }
  347.       printf("%-9s%-3s%9s%10s%8s   %-6s\n",File -> ff_name,Ext,Size,
  348.        FileDate(File -> ff_fdate),FileTime(File -> ff_ftime),
  349.        AttribWtoS(File -> ff_attrib));
  350.       More(1);
  351.    }
  352. }
  353.  
  354. char *FileDate(int PDate)
  355. /* Converts the file date word PDate into a string of the form mm-dd-yy,
  356.    puts it in a static buffer and returns a pointer to the buffer */
  357. {
  358. static char Date[9];
  359.  
  360.    sprintf(Date,"%2u-%02u-%02u",(PDate >> 5) & 0xf,PDate & 0x1f,
  361.     ((PDate >> 9) & 0x7f) + 80);
  362.    return(Date);
  363. }
  364.  
  365. char *FileTime(int PTime)
  366. /* Converts the file time word PTime to a string of the form HH:MMm, where m
  367.    is 'a' for AM and 'p' for PM, puts it in a static buffer, and returns a
  368.    pointer to the buffer */
  369. {
  370. static char Time[7];
  371. int NHour;    /* File hour in 12-hour format */
  372.  
  373.    NHour = ((PTime >> 11) & 0x1f) % 12;
  374.    if (NHour == 0)
  375.       NHour = 12;
  376.    sprintf(Time,"%2u:%02u%c",NHour,(PTime >> 5) & 0x3f,
  377.     ((PTime >> 11) & 0x1f) > 11 ? 'p' : 'a');
  378.    return(Time);
  379. }
  380.  
  381. void PrintFull(Entry *Entries,int Num,char *Dir)
  382. /* Print 'Full Path' listing of the file names in Entries.  The entries in
  383.    Entries are assumed to have been produced from the path given in Dir.
  384.    Dir is copied, and the filename is removed from it.  For each file name in
  385.    Entries, prints the file's size, time, date, and attributes; then Dir is
  386.    printed followed by the filename.  If the entry is a dir, a backslash is
  387.    printed at the end.
  388.    Dirs and the volume label report a size of 0, so they are printed with a
  389.    special label in the size column.
  390.    The list is modified. Num is the # of entries in Entries. */
  391. {
  392. char Name[MAXPATH];    /* Full path name of the file name */
  393. int I;
  394. Entry File;    /* Entry being printed */
  395. char Size[12];    /* File size converted to a string, or a special label for
  396.            dirs and the volume label */
  397.  
  398.    strcpy(Name,Dir);
  399.    *(strrchr(Name,'\\') + 1) = '\0';    /* Remove the file name from Dir */
  400.    for (I = 0; I < Num; I++) {
  401.       File = Entries[I];
  402.       if (File -> ff_attrib & FA_DIREC)    /* If entry is a dir or the vol label,
  403.                         give it a label instead of a file size */
  404.          strcpy(Size,"<DIR>  ");
  405.       else if (File -> ff_attrib & FA_LABEL)
  406.          strcpy(Size,"<LAB>  ");
  407.       else
  408.          sprintf(Size,"%ld",File -> ff_fsize);
  409.       /* If the entry is a directory, follow it with a backslash */
  410.       printf("%9s%10s%8s  %-6s%s%s%s\n",Size,FileDate(File -> ff_fdate),
  411.        FileTime(File -> ff_ftime),AttribWtoS(File -> ff_attrib),Name,
  412.        File -> ff_name,File -> ff_attrib & FA_DIREC ? "\\" : "");
  413.       More(1);
  414.    }
  415. }
  416.  
  417. void SortList(EntryListType *EntryList,char Sort)
  418. /* Sorts EntryList according the sort specification Sort.  Any groups of
  419.    entries that are not differentiated by the first sort are then sorted
  420.    by name. The sort specs are:
  421.      X = alpha by file eXtension; T = by Time & date, oldest to newest;
  422.      Z = by file siZe, smallest to largest; I = by directory attribute,
  423.      dirs first, then other files; N = sort by Name only;   */
  424. {
  425. int Num,    /* Number of entries */
  426. Start,        /* Start of a group of undifferentiated entries */
  427. I;
  428. Entry *List;    /* List to sort */
  429. int (*CompFunc)(Entry *E1,Entry *E2), /* Comparison func to be used in sort */
  430.  ExtComp(Entry *E1,Entry *E2),TDComp(Entry *E1,Entry *E2),
  431.  SizeComp(Entry *E1,Entry *E2),DAComp(Entry *E1,Entry *E2),
  432.  NameComp(Entry *E1,Entry *E2);  /* Comparison functions */
  433.  
  434.    Num = EntryList -> NumEnts;
  435.    List = EntryList -> Entries;
  436.    if (Sort != 'N') {    /* Do a first sort */
  437.       switch (Sort) {    /* Select sort function */
  438.          case 'X' :    CompFunc = ExtComp;
  439.                   break;
  440.          case 'T' :    CompFunc = TDComp;
  441.                   break;
  442.          case 'Z' :    CompFunc = SizeComp;
  443.                   break;
  444.          case 'I' :    CompFunc = DAComp;
  445.       }
  446.       qsort(List,Num,sizeof(Entry),CompFunc);    /* Do first sort */
  447.    }
  448.    Start = 0;    /* Intialize undiffentiated entries start to 0 */
  449.    for (I = 1; I < Num; I++)
  450.       if ((*CompFunc)(&List[I - 1],&List[I])) {    /* If comp func differentiates
  451.                         current entry from the previous one */
  452.          if (I - Start > 1) /* If more than one entry was passed before
  453.           differentiation was found, sort undifferentiated entries by name */
  454.             qsort(List + Start,I - Start,sizeof(Entry),NameComp);
  455.          Start = I;    /* Make start of undiff ents be current ent */
  456.       }
  457.    if (I - Start > 1)    /* If the last entry was the last of a group of
  458.                 undiffed entries, sort them */
  459.       qsort(List + Start,I - Start,sizeof(Entry),NameComp);
  460. }
  461.  
  462. DAComp(Entry *E1,Entry *E2)
  463. /* Compares file dir attribs.  Returns a negative int if E1 is a dir and
  464.    E2 is not; 0 if they both are or are not, and a positive int if E2 is
  465.    and E1 is not */
  466. {
  467.    return(((*E2) -> ff_attrib & FA_DIREC) - ((*E1) -> ff_attrib & FA_DIREC));
  468. }
  469.  
  470. NameComp(Entry *E1,Entry *E2)
  471. /* Compares the names of E1 and E2.  Returns a neg int, zero, or a pos int if
  472.    the name of E1 is lexicographically less than, equal to, or greater than
  473.    the name of E2.  Since strings are terminated with a null (lex value 0),
  474.    a file name will be less than the same initial name with extra characters,
  475.    including an ext. Because '.' has a value less than any letter, a file name
  476.    with an extension will be less than a file name with the same initial name
  477.    but other extra chars instead of an ext. */
  478. {
  479.    return(strcmp((*E1) -> ff_name,(*E2) -> ff_name));
  480. }
  481.  
  482. ExtComp(Entry *E1,Entry *E2)
  483. /* Compares file names by their extension.  Returns a neg int, zero, or a
  484.    pos int if the ext of E1 is lexicographically less than, equal to, or
  485.    greater than the ext of E2.  A file name without an ext will be less than
  486.    a file name with one. */
  487. {
  488. char *Ext1,*Ext2;    /* Exts of the files, or null strings if they did
  489.                not have exts */
  490.  
  491.    Ext1 = strchr((*E1) -> ff_name,'.');
  492.    if (Ext1 == NULL)
  493.       Ext1 = "";
  494.    Ext2 = strchr((*E2) -> ff_name,'.');
  495.    if (Ext2 == NULL)
  496.       Ext2 = "";
  497.    return(strcmp(Ext1,Ext2));
  498. }
  499.  
  500. TDComp(Entry *E1,Entry *E2)
  501. /* Compares the time and date of E1 and E2.  Returns -1, 0, or +1 if the
  502.    file date if E1 is earlier than, the same as, or later than the file
  503.    date of E2 */
  504. {
  505.    return(Sign((((long) ((*E1) -> ff_fdate) << 16) + (*E1) -> ff_ftime) -
  506.           (((long) ((*E2) -> ff_fdate) << 16) + (*E2) -> ff_ftime)));
  507. }
  508.  
  509. SizeComp(Entry *E1,Entry *E2)
  510. /* Compares the size fo E1 and E2.  Returns -1, 0, or +1 if E1 is smaller
  511.    than, the same size as, or larger than E2 */
  512. {
  513.    return(Sign((*E1) -> ff_fsize - (*E2) -> ff_fsize));
  514. }
  515.  
  516.