home *** CD-ROM | disk | FTP | other *** search
- /* Read, sort and compare two directories. Used for GNU DIFF.
- Copyright (C) 1988, 1989 Free Software Foundation, Inc.
-
- This file is part of GNU DIFF.
-
- GNU DIFF is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- GNU DIFF is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU DIFF; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
- This port is also distributed under the terms of the GNU General
- Public License as published by the Free Software Foundation.
-
- Please note that this file is not identical to the original GNU release,
- you should have received this code as patch to the official release.
-
- $Header: e:/gnu/diff/RCS/dir.c 1.15.0.2 91/03/12 17:06:27 tho Exp $ */
-
- #include "diff.h"
-
- #ifndef __STDC__
- static int compare_names ();
- #endif /* !__STDC__ */
-
- /* Read the directory named DIRNAME and return a sorted vector
- of filenames for its contents. NONEX nonzero means this directory is
- known to be nonexistent, so return zero files. */
-
- struct dirdata
- {
- int length; /* # elements in `files' */
- char **files; /* Sorted names of files in the dir */
- };
-
- #ifdef __STDC__
- static struct dirdata dir_sort(char *, int);
- static int compare_names(char * *, char * *);
- #endif /* __STDC__ */
-
- static struct dirdata
- dir_sort (dirname, nonex)
- char *dirname;
- int nonex;
- {
- register DIR *reading;
- register struct direct *next;
- struct dirdata dirdata;
-
- /* Address of block containing the files that are described. */
- char **files;
-
- /* Length of block that `files' points to, measured in files. */
- int nfiles;
-
- /* Index of first unused in `files'. */
- int files_index;
-
- if (nonex)
- {
- dirdata.length = 0;
- dirdata.files = 0;
- return dirdata;
- }
-
- /* Open the directory and check for errors. */
- reading = opendir (dirname);
- if (!reading)
- {
- perror_with_name (dirname);
- dirdata.length = -1;
- return dirdata;
- }
-
- /* Initialize the table of filenames. */
-
- nfiles = 100;
- files = (char **) xmalloc (nfiles * sizeof (char *));
- files_index = 0;
-
- /* Read the directory entries, and insert the subfiles
- into the `files' table. */
-
- while (next = readdir (reading))
- {
- /* Ignore the files `.' and `..' */
- if (next->d_name[0] == '.'
- && (next->d_name[1] == 0
- || (next->d_name[1] == '.'
- && next->d_name[2] == 0)))
- continue;
-
- if (files_index == nfiles)
- {
- nfiles *= 2;
- files
- = (char **) xrealloc (files, sizeof (char *) * nfiles);
- }
- files[files_index++] = concat (next->d_name, "", "");
- }
-
- closedir (reading);
-
- /* Sort the table. */
- qsort (files, files_index, sizeof (char *), compare_names);
-
- /* Return a description of location and length of the table. */
- dirdata.files = files;
- dirdata.length = files_index;
-
- return dirdata;
- }
-
- /* Sort the files now in the table. */
-
- static int
- compare_names (file1, file2)
- char **file1, **file2;
- {
- return strcmp (*file1, *file2);
- }
-
- /* Compare the contents of two directories named NAME1 and NAME2.
- This is a top-level routine; it does everything necessary for diff
- on two directories.
-
- NONEX1 nonzero says directory NAME1 doesn't exist, but pretend it is
- empty. Likewise NONEX2.
-
- HANDLE_FILE is a caller-provided subroutine called to handle each file.
- It gets five operands: dir and name (rel to original working dir) of file
- in dir 1, dir and name pathname of file in dir 2, and the recursion depth.
-
- For a file that appears in only one of the dirs, one of the name-args
- to HANDLE_FILE is zero.
-
- DEPTH is the current depth in recursion.
-
- Returns the maximum of all the values returned by HANDLE_FILE,
- or 2 if trouble is encountered in opening files. */
-
- #ifdef MSDOS
- int
- diff_dirs (name1, name2, handle_file, depth, nonex1, nonex2)
- char *name1, *name2;
- int (*handle_file) (char *, char *, char *, char *, int);
- int depth, nonex1, nonex2;
- #else
- int
- diff_dirs (name1, name2, handle_file, depth, nonex1, nonex2)
- char *name1, *name2;
- int (*handle_file) ();
- int nonex1, nonex2;
- #endif
- {
- struct dirdata data1, data2;
- register int i1, i2;
- int val = 0;
- int v1;
-
- /* Get sorted contents of both dirs. */
- data1 = dir_sort (name1, nonex1);
- data2 = dir_sort (name2, nonex2);
- if (data1.length == -1 || data2.length == -1)
- {
- if (data1.length >= 0)
- free (data1.files);
- if (data2.length >= 0)
- free (data2.files);
- return 2;
- }
-
- i1 = 0;
- i2 = 0;
-
- /* If -Sname was specified, and this is the topmost level of comparison,
- ignore all file names less than the specified starting name. */
-
- if (dir_start_file && depth == 0)
- {
- while (i1 < data1.length && strcmp (data1.files[i1], dir_start_file) < 0)
- i1++;
- while (i2 < data2.length && strcmp (data2.files[i2], dir_start_file) < 0)
- i2++;
- }
-
- /* Loop while files remain in one or both dirs. */
- while (i1 < data1.length || i2 < data2.length)
- {
- int nameorder;
-
- /* Compare next name in dir 1 with next name in dir 2.
- At the end of a dir,
- pretend the "next name" in that dir is very large. */
-
- if (i1 == data1.length)
- nameorder = 1;
- else if (i2 == data2.length)
- nameorder = -1;
- else
- nameorder = strcmp (data1.files[i1], data2.files[i2]);
-
- if (nameorder == 0)
- {
- /* We have found a file (or subdir) in common between both dirs.
- Compare the two files. */
- v1 = (*handle_file) (name1, data1.files[i1], name2, data2.files[i2],
- depth + 1);
- i1++, i2++;
- }
- if (nameorder < 0)
- {
- /* Next filename in dir 1 is less; that is a file in dir 1 only. */
- v1 = (*handle_file) (name1, data1.files[i1], name2, 0, depth + 1);
- i1++;
- }
- if (nameorder > 0)
- {
- /* Next filename in dir 2 is less; that is a file in dir 2 only. */
- v1 = (*handle_file) (name1, 0, name2, data2.files[i2], depth + 1);
- i2++;
- }
- if (v1 > val)
- val = v1;
- }
- if (data1.files)
- free (data1.files);
- if (data2.files)
- free (data2.files);
-
- return val;
- }
-