home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / rcs567s.zip / diff16 / dir.c < prev    next >
C/C++ Source or Header  |  1994-06-25  |  10KB  |  391 lines

  1. /* Read, sort and compare two directories.  Used for GNU DIFF.
  2.    Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  3.    Modified for DOS and OS/2 on 1991/09/14 by Kai Uwe Rommel
  4.     <rommel@ars.muc.de>.
  5.  
  6. This file is part of GNU DIFF.
  7.  
  8. GNU DIFF is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 1, or (at your option)
  11. any later version.
  12.  
  13. GNU DIFF is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. GNU General Public License for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with GNU DIFF; see the file COPYING.  If not, write to
  20. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  21.  
  22. #include "diff.h"
  23.  
  24. static int compare_names ();
  25.  
  26. /* Read the directory named DIRNAME and return a sorted vector
  27.    of filenames for its contents.  NONEX nonzero means this directory is
  28.    known to be nonexistent, so return zero files.  */
  29.  
  30. struct dirdata
  31. {
  32.   int length;            /* # elements in `files' */
  33.   char **files;            /* Sorted names of files in the dir */
  34. };
  35.  
  36. #if defined(MSDOS)
  37. /*
  38. ** due to difference of opinion btw gnu and microsoft about what
  39. ** const means, const is defined away in diff.h, which causes warnings
  40. ** when compiling the headers.  This ugliness is avoided here.
  41. */
  42. #ifdef const
  43. #undef const
  44. #endif
  45. #include <string.h>
  46. #include <ctype.h>
  47. #ifdef OS2
  48. #define strcmp stricmp
  49.   /* stricmp() this is important for the HPFS because it is
  50.   /* case-preserving but NOT case-sensitive */
  51. #include <stdlib.h>
  52. #define INCL_NOPM
  53. #include <os2.h>
  54. #define _A_NORMAL        0x00
  55. #define _A_SUBDIR        0x10
  56. #define _MAX_NAME        256
  57. #else
  58. #ifdef __TURBOC__
  59. #include <dir.h>
  60. #define _A_NORMAL        0x00
  61. #define _A_SUBDIR        0x10
  62. #endif
  63. #include <dos.h>
  64. #define _MAX_NAME        13
  65. #endif
  66.  
  67. struct direct {
  68.     char d_name[_MAX_NAME];
  69. };
  70.  
  71. typedef struct _dir {
  72.         int first;
  73. #ifdef OS2
  74.         FILEFINDBUF find;
  75. #else
  76. #ifdef __TURBOC__
  77.         struct ffblk dta;
  78. #else
  79.         struct find_t dta;
  80. #endif
  81. #endif
  82.     struct direct current;
  83. } DIR;
  84.  
  85. #ifdef OS2
  86. static HDIR hdir;
  87. static USHORT count;
  88. static BOOL lower;
  89. #endif
  90.  
  91. #ifdef OS2
  92. int IsFileSystemFAT(char *dir)
  93. {
  94.   USHORT nDrive;
  95.   ULONG lMap;
  96.   BYTE bData[64], bName[3];
  97.   USHORT cbData;
  98.  
  99.   if ( _osmode == DOS_MODE )
  100.     return TRUE;
  101.   else
  102.   {
  103.     /* We separate FAT and HPFS file systems here.
  104.      * Filenames read from a FAT system are converted to lower case
  105.      * while the case of filenames read from a HPFS (and other future
  106.      * file systems, like Unix-compatibles) is preserved.
  107.      */
  108.  
  109.     if ( isalpha(dir[0]) && (dir[1] == ':') )
  110.       nDrive = toupper(dir[0]) - '@';
  111.     else
  112.       DosQCurDisk(&nDrive, &lMap);
  113.  
  114.     bName[0] = (char) (nDrive + '@');
  115.     bName[1] = ':';
  116.     bName[2] = 0;
  117.  
  118.     cbData = sizeof(bData);
  119.  
  120.     if ( !DosQFSAttach(bName, 0U, 1U, bData, &cbData, 0L) )
  121.       return !strcmp(bData + (*(USHORT *) (bData + 2) + 7), "FAT");
  122.     else
  123.       return FALSE;
  124.  
  125.     /* End of this ugly code */
  126.   }
  127. }
  128. #endif
  129.  
  130. DIR *
  131. opendir(char *name) {
  132.     char localname[_MAX_NAME];
  133.     DIR *rval = malloc(sizeof(DIR));
  134.     strcpy(localname,name);
  135.         strcat(localname,"/*.*");
  136. #ifdef OS2
  137.         lower = IsFileSystemFAT(name);
  138.         hdir = count = 1;
  139. #endif
  140.     if(rval == NULL ||
  141. #ifdef OS2
  142.            DosFindFirst(localname, &hdir, _A_NORMAL|_A_SUBDIR, &rval->find,
  143.                         sizeof(FILEFINDBUF), &count, 0L) != 0)
  144. #else
  145. #ifdef __TURBOC__
  146.           findfirst(localname,&rval->dta,_A_NORMAL|_A_SUBDIR) != 0)
  147. #else
  148.           _dos_findfirst(localname,_A_NORMAL|_A_SUBDIR,&rval->dta) != 0)
  149. #endif
  150. #endif
  151.                 return NULL;
  152.     rval->first = 1;
  153.     return rval;
  154. }
  155.  
  156. void
  157. closedir(DIR *x) {
  158.     free(x);
  159. }
  160.  
  161. struct direct *
  162. readdir(DIR *thisdir) {
  163.     /*
  164.     ** first time through, we don't need to look for a file
  165.     */
  166.         if(!thisdir->first) {
  167. #ifdef OS2
  168.                 if(DosFindNext(hdir, &thisdir->find, sizeof(FILEFINDBUF),
  169.                                &count) != 0)
  170. #else
  171. #ifdef __TURBOC__
  172.                 if(findnext(&thisdir->dta) != 0)
  173. #else
  174.                 if(_dos_findnext(&thisdir->dta) != 0)
  175. #endif
  176. #endif
  177.             return NULL;
  178.     } else
  179.                 thisdir->first = 0;
  180. #ifdef OS2
  181.         strcpy(thisdir->current.d_name,thisdir->find.achName);
  182. #else
  183. #ifdef __BORLANDC__
  184.         strcpy(thisdir->current.d_name,thisdir->dta.ff_name);
  185. #else
  186.         strcpy(thisdir->current.d_name,thisdir->dta.name);
  187. #endif
  188. #endif
  189.     /* thisdir->current.d_name[13] = '\0'; */
  190. #ifdef OS2
  191.         if ( lower )
  192. #endif
  193.       strlwr(thisdir->current.d_name);
  194.     return &thisdir->current;
  195. }
  196.  
  197. #endif /* MSDOS */
  198.  
  199. static struct dirdata
  200. dir_sort (dirname, nonex)
  201.      char *dirname;
  202.      int nonex;
  203. {
  204.   register DIR *reading;
  205.   register struct direct *next;
  206.   struct dirdata dirdata;
  207.  
  208.   /* Address of block containing the files that are described.  */
  209.   char **files;
  210.  
  211.   /* Length of block that `files' points to, measured in files.  */
  212.   int nfiles;
  213.  
  214.   /* Index of first unused in `files'.  */
  215.   int files_index;
  216.  
  217.   if (nonex)
  218.     {
  219.       dirdata.length = 0;
  220.       dirdata.files = 0;
  221.       return dirdata;
  222.     }
  223.  
  224.   /* Open the directory and check for errors.  */
  225.   reading = opendir (dirname);
  226.   if (!reading)
  227.     {
  228.       perror_with_name (dirname);
  229.       dirdata.length = -1;
  230.       return dirdata;
  231.     }
  232.  
  233.   /* Initialize the table of filenames.  */
  234.  
  235.   nfiles = 100;
  236.   files = (char **) xmalloc (nfiles * sizeof (char *));
  237.   files_index = 0;
  238.  
  239.   /* Read the directory entries, and insert the subfiles
  240.      into the `files' table.  */
  241.  
  242.   while (next = readdir (reading))
  243.     {
  244.       /* Ignore the files `.' and `..' */
  245.       if (next->d_name[0] == '.'
  246.       && (next->d_name[1] == 0
  247.           || (next->d_name[1] == '.'
  248.           && next->d_name[2] == 0)))
  249.     continue;
  250.  
  251.       if (files_index == nfiles)
  252.     {
  253.       nfiles *= 2;
  254.       files
  255.         = (char **) xrealloc (files, sizeof (char *) * nfiles);
  256.     }
  257.       files[files_index++] = concat (next->d_name, "", "");
  258.     }
  259.  
  260.   closedir (reading);
  261.  
  262.   /* Sort the table.  */
  263.   qsort (files, files_index, sizeof (char *), compare_names);
  264.  
  265.   /* Return a description of location and length of the table.  */
  266.   dirdata.files = files;
  267.   dirdata.length = files_index;
  268.  
  269.   return dirdata;
  270. }
  271.  
  272. /* Sort the files now in the table.  */
  273.  
  274. static int
  275. compare_names (file1, file2)
  276.      char **file1, **file2;
  277. {
  278.   return strcmp (*file1, *file2);
  279. }
  280.  
  281. /* Compare the contents of two directories named NAME1 and NAME2.
  282.    This is a top-level routine; it does everything necessary for diff
  283.    on two directories.
  284.  
  285.    NONEX1 nonzero says directory NAME1 doesn't exist, but pretend it is
  286.    empty.  Likewise NONEX2.
  287.  
  288.    HANDLE_FILE is a caller-provided subroutine called to handle each file.
  289.    It gets five operands: dir and name (rel to original working dir) of file
  290.    in dir 1, dir and name pathname of file in dir 2, and the recursion depth.
  291.  
  292.    For a file that appears in only one of the dirs, one of the name-args
  293.    to HANDLE_FILE is zero.
  294.  
  295.    DEPTH is the current depth in recursion.
  296.  
  297.    Returns the maximum of all the values returned by HANDLE_FILE,
  298.    or 2 if trouble is encountered in opening files.  */
  299.  
  300. int
  301. diff_dirs (name1, name2, handle_file, depth, nonex1, nonex2)
  302.      char *name1, *name2;
  303. #if !defined(MSDOS)
  304.      int (*handle_file) ();
  305. #else
  306.       /* sorry, rms, I can't live with the assumption that
  307.       ** sizeof(char *) == sizeof(int)
  308.       */
  309.       int (*handle_file)(char *,char *,
  310.              char *,char *,int);
  311. #endif
  312.      int depth, nonex1, nonex2;
  313. {
  314.   struct dirdata data1, data2;
  315.   register int i1, i2;
  316.   int val = 0;
  317.   int v1;
  318.  
  319.   /* Get sorted contents of both dirs.  */
  320.   data1 = dir_sort (name1, nonex1);
  321.   data2 = dir_sort (name2, nonex2);
  322.   if (data1.length == -1 || data2.length == -1)
  323.     {
  324.       if (data1.length >= 0)
  325.     free (data1.files);
  326.       if (data2.length >= 0)
  327.     free (data2.files);
  328.       return 2;
  329.     }
  330.  
  331.   i1 = 0;
  332.   i2 = 0;
  333.  
  334.   /* If -Sname was specified, and this is the topmost level of comparison,
  335.      ignore all file names less than the specified starting name.  */
  336.  
  337.   if (dir_start_file && depth == 0)
  338.     {
  339.       while (i1 < data1.length && strcmp (data1.files[i1], dir_start_file) < 0)
  340.     i1++;
  341.       while (i2 < data2.length && strcmp (data2.files[i2], dir_start_file) < 0)
  342.     i2++;
  343.     }
  344.  
  345.   /* Loop while files remain in one or both dirs.  */
  346.   while (i1 < data1.length || i2 < data2.length)
  347.     {
  348.       int nameorder;
  349.  
  350.       /* Compare next name in dir 1 with next name in dir 2.
  351.      At the end of a dir,
  352.      pretend the "next name" in that dir is very large.  */
  353.  
  354.       if (i1 == data1.length)
  355.     nameorder = 1;
  356.       else if (i2 == data2.length)
  357.     nameorder = -1;
  358.       else
  359.     nameorder = strcmp (data1.files[i1], data2.files[i2]);
  360.  
  361.       if (nameorder == 0)
  362.     {
  363.       /* We have found a file (or subdir) in common between both dirs.
  364.          Compare the two files.  */
  365.       v1 = (*handle_file) (name1, data1.files[i1], name2, data2.files[i2],
  366.                    depth + 1);
  367.       i1++, i2++;
  368.     }
  369.       if (nameorder < 0)
  370.     {
  371.       /* Next filename in dir 1 is less; that is a file in dir 1 only.  */
  372.       v1 = (*handle_file) (name1, data1.files[i1], name2, 0, depth + 1);
  373.       i1++;
  374.     }
  375.       if (nameorder > 0)
  376.     {
  377.       /* Next filename in dir 2 is less; that is a file in dir 2 only.  */
  378.       v1 = (*handle_file) (name1, 0, name2, data2.files[i2], depth + 1);
  379.       i2++;
  380.     }
  381.       if (v1 > val)
  382.     val = v1;
  383.     }
  384.   if (data1.files)
  385.     free (data1.files);
  386.   if (data2.files)
  387.     free (data2.files);
  388.  
  389.   return val;
  390. }
  391.