132785Speter/* Read, sort and compare two directories. Used for GNU DIFF. 232785Speter Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. 332785Speter 432785SpeterThis file is part of GNU DIFF. 532785Speter 632785SpeterGNU DIFF is free software; you can redistribute it and/or modify 732785Speterit under the terms of the GNU General Public License as published by 832785Speterthe Free Software Foundation; either version 2, or (at your option) 932785Speterany later version. 1032785Speter 1132785SpeterGNU DIFF is distributed in the hope that it will be useful, 1232785Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of 1332785SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1432785SpeterGNU General Public License for more details. 1532785Speter 1654427Speter*/ 1732785Speter 1832785Speter#include "diff.h" 1932785Speter 2032785Speter/* Read the directory named by DIR and store into DIRDATA a sorted vector 2132785Speter of filenames for its contents. DIR->desc == -1 means this directory is 2232785Speter known to be nonexistent, so set DIRDATA to an empty vector. 2332785Speter Return -1 (setting errno) if error, 0 otherwise. */ 2432785Speter 2532785Speterstruct dirdata 2632785Speter{ 2732785Speter char const **names; /* Sorted names of files in dir, 0-terminated. */ 2832785Speter char *data; /* Allocated storage for file names. */ 2932785Speter}; 3032785Speter 3132785Speterstatic int compare_names PARAMS((void const *, void const *)); 3232785Speterstatic int dir_sort PARAMS((struct file_data const *, struct dirdata *)); 3332785Speter 3432785Speter#ifdef _WIN32 3532785Speter#define CLOSEDIR_VOID 1 3632785Speter#endif 3732785Speter 3832785Speterstatic int 3932785Speterdir_sort (dir, dirdata) 4032785Speter struct file_data const *dir; 4132785Speter struct dirdata *dirdata; 4232785Speter{ 4332785Speter register struct dirent *next; 4432785Speter register int i; 4532785Speter 4632785Speter /* Address of block containing the files that are described. */ 4732785Speter char const **names; 4832785Speter 4932785Speter /* Number of files in directory. */ 5032785Speter size_t nnames; 5132785Speter 5232785Speter /* Allocated and used storage for file name data. */ 5332785Speter char *data; 5432785Speter size_t data_alloc, data_used; 5532785Speter 5632785Speter dirdata->names = 0; 5732785Speter dirdata->data = 0; 5832785Speter nnames = 0; 5932785Speter data = 0; 6032785Speter 6132785Speter if (dir->desc != -1) 6232785Speter { 6332785Speter /* Open the directory and check for errors. */ 6481404Speter register DIR *reading = CVS_OPENDIR (dir->name); 6532785Speter if (!reading) 6632785Speter return -1; 6732785Speter 6832785Speter /* Initialize the table of filenames. */ 6932785Speter 7032785Speter data_alloc = max (1, (size_t) dir->stat.st_size); 7132785Speter data_used = 0; 7232785Speter dirdata->data = data = xmalloc (data_alloc); 7332785Speter 7432785Speter /* Read the directory entries, and insert the subfiles 7532785Speter into the `data' table. */ 7632785Speter 7781404Speter while ((errno = 0, (next = CVS_READDIR (reading)) != 0)) 7832785Speter { 7932785Speter char *d_name = next->d_name; 8032785Speter size_t d_size = NAMLEN (next) + 1; 8132785Speter 8232785Speter /* Ignore the files `.' and `..' */ 8332785Speter if (d_name[0] == '.' 8432785Speter && (d_name[1] == 0 || (d_name[1] == '.' && d_name[2] == 0))) 8532785Speter continue; 8632785Speter 8732785Speter if (excluded_filename (d_name)) 8832785Speter continue; 8932785Speter 9032785Speter while (data_alloc < data_used + d_size) 9132785Speter dirdata->data = data = xrealloc (data, data_alloc *= 2); 9232785Speter memcpy (data + data_used, d_name, d_size); 9332785Speter data_used += d_size; 9432785Speter nnames++; 9532785Speter } 9632785Speter if (errno) 9732785Speter { 9832785Speter int e = errno; 9981404Speter CVS_CLOSEDIR (reading); 10032785Speter errno = e; 10132785Speter return -1; 10232785Speter } 10332785Speter#if CLOSEDIR_VOID 10481404Speter CVS_CLOSEDIR (reading); 10532785Speter#else 10681404Speter if (CVS_CLOSEDIR (reading) != 0) 10732785Speter return -1; 10832785Speter#endif 10932785Speter } 11032785Speter 11132785Speter /* Create the `names' table from the `data' table. */ 11232785Speter dirdata->names = names = (char const **) xmalloc (sizeof (char *) 11332785Speter * (nnames + 1)); 11432785Speter for (i = 0; i < nnames; i++) 11532785Speter { 11632785Speter names[i] = data; 11732785Speter data += strlen (data) + 1; 11832785Speter } 11932785Speter names[nnames] = 0; 12032785Speter 12132785Speter /* Sort the table. */ 12232785Speter qsort (names, nnames, sizeof (char *), compare_names); 12332785Speter 12432785Speter return 0; 12532785Speter} 12632785Speter 12732785Speter/* Sort the files now in the table. */ 12832785Speter 12932785Speterstatic int 13032785Spetercompare_names (file1, file2) 13132785Speter void const *file1, *file2; 13232785Speter{ 13332785Speter return filename_cmp (* (char const *const *) file1, 13432785Speter * (char const *const *) file2); 13532785Speter} 13632785Speter 13732785Speter/* Compare the contents of two directories named in FILEVEC[0] and FILEVEC[1]. 13832785Speter This is a top-level routine; it does everything necessary for diff 13932785Speter on two directories. 14032785Speter 14132785Speter FILEVEC[0].desc == -1 says directory FILEVEC[0] doesn't exist, 14232785Speter but pretend it is empty. Likewise for FILEVEC[1]. 14332785Speter 14432785Speter HANDLE_FILE is a caller-provided subroutine called to handle each file. 14532785Speter It gets five operands: dir and name (rel to original working dir) of file 14632785Speter in dir 0, dir and name pathname of file in dir 1, and the recursion depth. 14732785Speter 14832785Speter For a file that appears in only one of the dirs, one of the name-args 14932785Speter to HANDLE_FILE is zero. 15032785Speter 15132785Speter DEPTH is the current depth in recursion, used for skipping top-level 15232785Speter files by the -S option. 15332785Speter 15432785Speter Returns the maximum of all the values returned by HANDLE_FILE, 15532785Speter or 2 if trouble is encountered in opening files. */ 15632785Speter 15732785Speterint 15832785Speterdiff_dirs (filevec, handle_file, depth) 15932785Speter struct file_data const filevec[]; 16032785Speter int (*handle_file) PARAMS((char const *, char const *, char const *, char const *, int)); 16132785Speter int depth; 16232785Speter{ 16332785Speter struct dirdata dirdata[2]; 16432785Speter int val = 0; /* Return value. */ 16532785Speter int i; 16632785Speter 16732785Speter /* Get sorted contents of both dirs. */ 16832785Speter for (i = 0; i < 2; i++) 16932785Speter if (dir_sort (&filevec[i], &dirdata[i]) != 0) 17032785Speter { 17132785Speter perror_with_name (filevec[i].name); 17232785Speter val = 2; 17332785Speter } 17432785Speter 17532785Speter if (val == 0) 17632785Speter { 17732785Speter register char const * const *names0 = dirdata[0].names; 17832785Speter register char const * const *names1 = dirdata[1].names; 17932785Speter char const *name0 = filevec[0].name; 18032785Speter char const *name1 = filevec[1].name; 18132785Speter 18232785Speter /* If `-S name' was given, and this is the topmost level of comparison, 18332785Speter ignore all file names less than the specified starting name. */ 18432785Speter 18532785Speter if (dir_start_file && depth == 0) 18632785Speter { 18732785Speter while (*names0 && filename_cmp (*names0, dir_start_file) < 0) 18832785Speter names0++; 18932785Speter while (*names1 && filename_cmp (*names1, dir_start_file) < 0) 19032785Speter names1++; 19132785Speter } 19232785Speter 19332785Speter /* Loop while files remain in one or both dirs. */ 19432785Speter while (*names0 || *names1) 19532785Speter { 19632785Speter /* Compare next name in dir 0 with next name in dir 1. 19732785Speter At the end of a dir, 19832785Speter pretend the "next name" in that dir is very large. */ 19932785Speter int nameorder = (!*names0 ? 1 : !*names1 ? -1 20032785Speter : filename_cmp (*names0, *names1)); 20132785Speter int v1 = (*handle_file) (name0, 0 < nameorder ? 0 : *names0++, 20232785Speter name1, nameorder < 0 ? 0 : *names1++, 20332785Speter depth + 1); 20432785Speter if (v1 > val) 20532785Speter val = v1; 20632785Speter } 20732785Speter } 20832785Speter 20932785Speter for (i = 0; i < 2; i++) 21032785Speter { 21132785Speter if (dirdata[i].names) 21232785Speter free (dirdata[i].names); 21332785Speter if (dirdata[i].data) 21432785Speter free (dirdata[i].data); 21532785Speter } 21632785Speter 21732785Speter return val; 21832785Speter} 219