home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / rcs57pc3.zip / diff16 / dir.c < prev    next >
C/C++ Source or Header  |  1996-03-20  |  10KB  |  393 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. #ifndef _MAX_NAME
  57. #define _MAX_NAME        256
  58. #endif
  59. #else
  60. #ifdef __TURBOC__
  61. #include <dir.h>
  62. #define _A_NORMAL        0x00
  63. #define _A_SUBDIR        0x10
  64. #endif
  65. #include <dos.h>
  66. #define _MAX_NAME        13
  67. #endif
  68.  
  69. struct direct {
  70.     char d_name[_MAX_NAME];
  71. };
  72.  
  73. typedef struct _dir {
  74.         int first;
  75. #ifdef OS2
  76.         FILEFINDBUF find;
  77. #else
  78. #ifdef __TURBOC__
  79.         struct ffblk dta;
  80. #else
  81.         struct find_t dta;
  82. #endif
  83. #endif
  84.     struct direct current;
  85. } DIR;
  86.  
  87. #ifdef OS2
  88. static HDIR hdir;
  89. static USHORT count;
  90. static BOOL lower;
  91. #endif
  92.  
  93. #ifdef OS2
  94. int IsFileSystemFAT(char *dir)
  95. {
  96.   USHORT nDrive;
  97.   ULONG lMap;
  98.   BYTE bData[64], bName[3];
  99.   USHORT cbData;
  100.  
  101.   if ( _osmode == DOS_MODE )
  102.     return TRUE;
  103.   else
  104.   {
  105.     /* We separate FAT and HPFS file systems here.
  106.      * Filenames read from a FAT system are converted to lower case
  107.      * while the case of filenames read from a HPFS (and other future
  108.      * file systems, like Unix-compatibles) is preserved.
  109.      */
  110.  
  111.     if ( isalpha(dir[0]) && (dir[1] == ':') )
  112.       nDrive = toupper(dir[0]) - '@';
  113.     else
  114.       DosQCurDisk(&nDrive, &lMap);
  115.  
  116.     bName[0] = (char) (nDrive + '@');
  117.     bName[1] = ':';
  118.     bName[2] = 0;
  119.  
  120.     cbData = sizeof(bData);
  121.  
  122.     if ( !DosQFSAttach(bName, 0U, 1U, bData, &cbData, 0L) )
  123.       return !strcmp(bData + (*(USHORT *) (bData + 2) + 7), "FAT");
  124.     else
  125.       return FALSE;
  126.  
  127.     /* End of this ugly code */
  128.   }
  129. }
  130. #endif
  131.  
  132. DIR *
  133. opendir(char *name) {
  134.     char localname[_MAX_NAME];
  135.     DIR *rval = malloc(sizeof(DIR));
  136.     strcpy(localname,name);
  137.         strcat(localname,"/*.*");
  138. #ifdef OS2
  139.         lower = IsFileSystemFAT(name);
  140.         hdir = count = 1;
  141. #endif
  142.     if(rval == NULL ||
  143. #ifdef OS2
  144.            DosFindFirst(localname, &hdir, _A_NORMAL|_A_SUBDIR, &rval->find,
  145.                         sizeof(FILEFINDBUF), &count, 0L) != 0)
  146. #else
  147. #ifdef __TURBOC__
  148.           findfirst(localname,&rval->dta,_A_NORMAL|_A_SUBDIR) != 0)
  149. #else
  150.           _dos_findfirst(localname,_A_NORMAL|_A_SUBDIR,&rval->dta) != 0)
  151. #endif
  152. #endif
  153.                 return NULL;
  154.     rval->first = 1;
  155.     return rval;
  156. }
  157.  
  158. void
  159. closedir(DIR *x) {
  160.     free(x);
  161. }
  162.  
  163. struct direct *
  164. readdir(DIR *thisdir) {
  165.     /*
  166.     ** first time through, we don't need to look for a file
  167.     */
  168.         if(!thisdir->first) {
  169. #ifdef OS2
  170.                 if(DosFindNext(hdir, &thisdir->find, sizeof(FILEFINDBUF),
  171.                                &count) != 0)
  172. #else
  173. #ifdef __TURBOC__
  174.                 if(findnext(&thisdir->dta) != 0)
  175. #else
  176.                 if(_dos_findnext(&thisdir->dta) != 0)
  177. #endif
  178. #endif
  179.             return NULL;
  180.     } else
  181.                 thisdir->first = 0;
  182. #ifdef OS2
  183.         strcpy(thisdir->current.d_name,thisdir->find.achName);
  184. #else
  185. #ifdef __BORLANDC__
  186.         strcpy(thisdir->current.d_name,thisdir->dta.ff_name);
  187. #else
  188.         strcpy(thisdir->current.d_name,thisdir->dta.name);
  189. #endif
  190. #endif
  191.     /* thisdir->current.d_name[13] = '\0'; */
  192. #ifdef OS2
  193.         if ( lower )
  194. #endif
  195.       strlwr(thisdir->current.d_name);
  196.     return &thisdir->current;
  197. }
  198.  
  199. #endif /* MSDOS */
  200.  
  201. static struct dirdata
  202. dir_sort (dirname, nonex)
  203.      char *dirname;
  204.      int nonex;
  205. {
  206.   register DIR *reading;
  207.   register struct direct *next;
  208.   struct dirdata dirdata;
  209.  
  210.   /* Address of block containing the files that are described.  */
  211.   char **files;
  212.  
  213.   /* Length of block that `files' points to, measured in files.  */
  214.   int nfiles;
  215.  
  216.   /* Index of first unused in `files'.  */
  217.   int files_index;
  218.  
  219.   if (nonex)
  220.     {
  221.       dirdata.length = 0;
  222.       dirdata.files = 0;
  223.       return dirdata;
  224.     }
  225.  
  226.   /* Open the directory and check for errors.  */
  227.   reading = opendir (dirname);
  228.   if (!reading)
  229.     {
  230.       perror_with_name (dirname);
  231.       dirdata.length = -1;
  232.       return dirdata;
  233.     }
  234.  
  235.   /* Initialize the table of filenames.  */
  236.  
  237.   nfiles = 100;
  238.   files = (char **) xmalloc (nfiles * sizeof (char *));
  239.   files_index = 0;
  240.  
  241.   /* Read the directory entries, and insert the subfiles
  242.      into the `files' table.  */
  243.  
  244.   while (next = readdir (reading))
  245.     {
  246.       /* Ignore the files `.' and `..' */
  247.       if (next->d_name[0] == '.'
  248.       && (next->d_name[1] == 0
  249.           || (next->d_name[1] == '.'
  250.           && next->d_name[2] == 0)))
  251.     continue;
  252.  
  253.       if (files_index == nfiles)
  254.     {
  255.       nfiles *= 2;
  256.       files
  257.         = (char **) xrealloc (files, sizeof (char *) * nfiles);
  258.     }
  259.       files[files_index++] = concat (next->d_name, "", "");
  260.     }
  261.  
  262.   closedir (reading);
  263.  
  264.   /* Sort the table.  */
  265.   qsort (files, files_index, sizeof (char *), compare_names);
  266.  
  267.   /* Return a description of location and length of the table.  */
  268.   dirdata.files = files;
  269.   dirdata.length = files_index;
  270.  
  271.   return dirdata;
  272. }
  273.  
  274. /* Sort the files now in the table.  */
  275.  
  276. static int
  277. compare_names (file1, file2)
  278.      char **file1, **file2;
  279. {
  280.   return strcmp (*file1, *file2);
  281. }
  282.  
  283. /* Compare the contents of two directories named NAME1 and NAME2.
  284.    This is a top-level routine; it does everything necessary for diff
  285.    on two directories.
  286.  
  287.    NONEX1 nonzero says directory NAME1 doesn't exist, but pretend it is
  288.    empty.  Likewise NONEX2.
  289.  
  290.    HANDLE_FILE is a caller-provided subroutine called to handle each file.
  291.    It gets five operands: dir and name (rel to original working dir) of file
  292.    in dir 1, dir and name pathname of file in dir 2, and the recursion depth.
  293.  
  294.    For a file that appears in only one of the dirs, one of the name-args
  295.    to HANDLE_FILE is zero.
  296.  
  297.    DEPTH is the current depth in recursion.
  298.  
  299.    Returns the maximum of all the values returned by HANDLE_FILE,
  300.    or 2 if trouble is encountered in opening files.  */
  301.  
  302. int
  303. diff_dirs (name1, name2, handle_file, depth, nonex1, nonex2)
  304.      char *name1, *name2;
  305. #if !defined(MSDOS)
  306.      int (*handle_file) ();
  307. #else
  308.       /* sorry, rms, I can't live with the assumption that
  309.       ** sizeof(char *) == sizeof(int)
  310.       */
  311.       int (*handle_file)(char *,char *,
  312.              char *,char *,int);
  313. #endif
  314.      int depth, nonex1, nonex2;
  315. {
  316.   struct dirdata data1, data2;
  317.   register int i1, i2;
  318.   int val = 0;
  319.   int v1;
  320.  
  321.   /* Get sorted contents of both dirs.  */
  322.   data1 = dir_sort (name1, nonex1);
  323.   data2 = dir_sort (name2, nonex2);
  324.   if (data1.length == -1 || data2.length == -1)
  325.     {
  326.       if (data1.length >= 0)
  327.     free (data1.files);
  328.       if (data2.length >= 0)
  329.     free (data2.files);
  330.       return 2;
  331.     }
  332.  
  333.   i1 = 0;
  334.   i2 = 0;
  335.  
  336.   /* If -Sname was specified, and this is the topmost level of comparison,
  337.      ignore all file names less than the specified starting name.  */
  338.  
  339.   if (dir_start_file && depth == 0)
  340.     {
  341.       while (i1 < data1.length && strcmp (data1.files[i1], dir_start_file) < 0)
  342.     i1++;
  343.       while (i2 < data2.length && strcmp (data2.files[i2], dir_start_file) < 0)
  344.     i2++;
  345.     }
  346.  
  347.   /* Loop while files remain in one or both dirs.  */
  348.   while (i1 < data1.length || i2 < data2.length)
  349.     {
  350.       int nameorder;
  351.  
  352.       /* Compare next name in dir 1 with next name in dir 2.
  353.      At the end of a dir,
  354.      pretend the "next name" in that dir is very large.  */
  355.  
  356.       if (i1 == data1.length)
  357.     nameorder = 1;
  358.       else if (i2 == data2.length)
  359.     nameorder = -1;
  360.       else
  361.     nameorder = strcmp (data1.files[i1], data2.files[i2]);
  362.  
  363.       if (nameorder == 0)
  364.     {
  365.       /* We have found a file (or subdir) in common between both dirs.
  366.          Compare the two files.  */
  367.       v1 = (*handle_file) (name1, data1.files[i1], name2, data2.files[i2],
  368.                    depth + 1);
  369.       i1++, i2++;
  370.     }
  371.       if (nameorder < 0)
  372.     {
  373.       /* Next filename in dir 1 is less; that is a file in dir 1 only.  */
  374.       v1 = (*handle_file) (name1, data1.files[i1], name2, 0, depth + 1);
  375.       i1++;
  376.     }
  377.       if (nameorder > 0)
  378.     {
  379.       /* Next filename in dir 2 is less; that is a file in dir 2 only.  */
  380.       v1 = (*handle_file) (name1, 0, name2, data2.files[i2], depth + 1);
  381.       i2++;
  382.     }
  383.       if (v1 > val)
  384.     val = v1;
  385.     }
  386.   if (data1.files)
  387.     free (data1.files);
  388.   if (data2.files)
  389.     free (data2.files);
  390.  
  391.   return val;
  392. }
  393.