home *** CD-ROM | disk | FTP | other *** search
- /* Test routines for Eclectus integration utilities.
- Copyright (C) 1992-1996 Eclectus (D. John Anderson, Alan B. Harper).
-
- This file is part of the Eclectus integration utilities.
-
- Eclectus integration utilities are 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.
-
- Eclectus integration utilities 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 the Eclectus integration utilities; see the file COPYING.
- If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge,
- MA 02139, USA. */
-
- #include "diff.h"
- #include <limits.h>
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
-
- #ifdef DF_MACHINE_MACINTOSH
- #include <Types.h>
- #include <CursorCtl.h>
- #endif
-
- /*
- * I put the following array in a struct since I later constuct an array of
- * nameType elements in nameListType. This was done to work around a bug in
- * the MPW compiler which doesn't properly handle taking an address of an
- * array of arrays. I suspect this relates to the fact that the designers
- * of C didn't understand types (i.e. arrays are different from other types
- * like structs).
- */
-
- typedef struct nameType {
- char name [FILENAME_MAX + 1];
- } nameType, *namePType;
-
- /*
- * nameListType is a variable length structure with numberOfItems in the nameData
- * array. Unfortunately ANSI C requires a single element in this array making
- * the syntax of variable length types extremely awkward.
- */
-
- typedef struct nameListType {
- unsigned int numberOfItems;
- nameType nameData[1];
- } nameListType, *nameListPType;
-
- #define ADDED 1
- #define REMOVED 2
-
- static const char *programNamePtr;
- static int showNonCollisions; /* Show all changes, even when they don't collide */
-
- static nameListPType CommandLine (int argc, const char **argv);
- static void CommandLineError (int errorMessage, const char *theString);
- int __cdecl main (int argc, const char **argv);
- static int MergeFiles (struct file_data *fileListPtr,
- FILE *outFilePtr);
- static void MergePaths (nameListPType pathListPtr);
- static void PrependStringToPathName (char *destinationCharPtr, const char *prefixCharPtr);
- static void PrintEndFileName (FILE *outFilePtr);
- static void PrintLines (FILE *outFilePtr,
- struct file_data *filePtr,
- int startLineNumber,
- register int endLineNumber);
- static void PrintStartFileName (FILE *outFilePtr, struct file_data *filePtr);
- static int __cdecl StrPtrCmp (char **string0PtrPtr, char **string1PtrPtr);
-
- nameListPType
- CommandLine (int argc, const char **argv)
- /*
- * Parses the command line. Returns a pointer to a nameListType. Dealing with variable
- * length items is such a pain in the ass in C. The caller is responsible for
- * freeing this storage.
- */
- {
- char commandChar;
- register const char *commandStringPtr;
- const char *lastNamePtr;
- int nameListLength;
- int nameListTotalSpace;
- namePType namePtr;
- nameListPType pathListPtr;
-
- lastNamePtr = NULL;
- /*
- * Set nameListLength to the size of a name list with no elements in it. Since ANSI
- * C requires us to put one item in the array we use offsetof to get the size.
- */
- nameListLength = offsetof (nameListType, nameData);
- nameListTotalSpace = offsetof (nameListType, nameData) + (3 * sizeof (nameType));
- pathListPtr = xmalloc (nameListTotalSpace);
- pathListPtr->numberOfItems = 0;
-
- programNamePtr = *argv++;
- argc--;
-
- /* Parse the commands and make sure they are legal */
-
- while (argc > 0) {
- commandStringPtr = *argv++;
- argc--;
- if (*commandStringPtr != '-') {
- if (nameListLength >= nameListTotalSpace) {
- nameListTotalSpace = nameListLength + (4 * sizeof (nameType));
- pathListPtr = xrealloc (pathListPtr, nameListTotalSpace);
- }
- namePtr = (namePType) (((char *) pathListPtr) + nameListLength);
- memcpy (namePtr->name, commandStringPtr, strlen (commandStringPtr) + 1);
-
- if (lastNamePtr != NULL && FileType (lastNamePtr) == BAD_FILE_TYPE)
- ErrorWithStringArgument (CANT_OPEN_FILE, lastNamePtr);
- lastNamePtr = commandStringPtr;
-
- nameListLength += sizeof (nameType);
- pathListPtr->numberOfItems ++;
- } else {
- if (strlen (commandStringPtr) != 2)
- CommandLineError (UNEXPECTED_OPTION, commandStringPtr);
- commandChar = *(commandStringPtr + 1);
- switch (commandChar) {
- case ('c'):
- showNonCollisions = 1;
- break;
- #ifdef DF_DEBUG
- case ('X'):
- ECCheckFreedBlocks = 1;
- break;
- case ('x'):
- ECHeapCheckOn = 1;
- break;
- #endif
- default:
- CommandLineError (UNEXPECTED_OPTION, commandStringPtr);
- break;
- }
- }
- }
- if (pathListPtr->numberOfItems < 3)
- CommandLineError (THREE_OR_MORE_MERGE_FILES, NULL);
-
- pathListPtr = xrealloc (pathListPtr, nameListLength);
- return (pathListPtr);
- }
-
- void
- CommandLineError (int errorMessage, const char *theString)
- /*
- * Part of CommandLine.
- */
- {
- fprintf (stderr, "# - ");
- if (theString != NULL)
- fprintf (stderr, ECMessagessArray [errorMessage], theString);
- else
- fprintf (stderr, ECMessagessArray [errorMessage], "");
- fprintf (stderr, ".\n\n"
- "### Merge version %s\n"
- "#usage: %s [-c] rootPath modification1Path [modification2Path]"
- " ... destinationPath \n"
- " -c shows all changes even if no collisions occur\n\n",
- VERSION_STRING,
- programNamePtr);
- exit (EXIT_FAILURE);
- }
-
- int
- __cdecl main (int argc, const char **argv)
- {
- #ifdef DF_DEBUG
- ECUns32 allocatedBytes;
- #endif
- nameListPType pathListPtr;
-
- pathListPtr = CommandLine (argc, argv);
- MergePaths (pathListPtr);
- free (pathListPtr);
-
- #ifdef DF_DEBUG
- allocatedBytes = ECDebugPrintMemoryUsage (stderr);
- if (allocatedBytes != 0) {
- fprintf (stderr, "\n\n"
- "MEMORY LEAK! MEMORY LEAK! MEMORY LEAK! MEMORY LEAK!\n"
- "MEMORY LEAK! MEMORY LEAK! MEMORY LEAK! MEMORY LEAK!\n"
- "MEMORY LEAK! MEMORY LEAK! MEMORY LEAK! MEMORY LEAK!\n"
- "MEMORY LEAK! MEMORY LEAK! MEMORY LEAK! MEMORY LEAK!\n"
- "MEMORY LEAK! MEMORY LEAK! MEMORY LEAK! MEMORY LEAK!\n"
- "\n\n");
- }
- #endif
- return (0);
- }
-
- int
- MergeFiles (struct file_data *fileListPtr, FILE *outFilePtr)
- /*
- * Merges a list of files into the first item of the list and writes the result to
- * outFilePtr. Returns 1 if changes overlap (i.e. collide) and must be hand integrated.
- * Returns -1 if there were no differences between any of the files. Returns 0 otherwise.
- */
- {
- int collision;
- struct line_def *firstLinePtr;
- struct change *firstLowLimitPtr;
- register struct file_data *firstMatchFilePtr;
- register struct file_data *filePtr;
- struct file_data *firstScriptFilePtr;
- int highLimit;
- int highLimitInFile;
- struct change *highLimitPtr;
- int lineCount;
- int lineNumber;
- struct line_def *linePtr;
- int lowLimit;
- int lowLimitInFile;
- struct change *lowLimitPtr;
- int nextHighLimit;
- struct change *nextHighLimitPtr;
- int nextLowLimit;
- int overlap;
- int printedOneCopy;
- register struct file_data *rootFilePtr;
- int rootLineNumber;
- int showFileName;
-
- collision = 0;
- rootLineNumber = 0;
- /*
- * Calculate 2 way diffs from all the files and then merge the 2 way diffs.
- */
- rootFilePtr = fileListPtr;
- firstScriptFilePtr = rootFilePtr->nextFilePtr;
- filePtr = firstScriptFilePtr;
- while (filePtr != NULL) {
- diff_2_files (rootFilePtr, filePtr);
- lowLimitPtr = filePtr->scriptPtr;
- filePtr->lowLimitPtr = lowLimitPtr;
- filePtr->highLimitPtr = lowLimitPtr;
- filePtr = filePtr->nextFilePtr;
- }
-
- do {
- /*
- * Find the lowest range of blocks that overlap. This code is tricky. We pass through
- * all the files accumulating a low and high limit of the lowest overlapping changes in
- * the root. It gets tricky because more than one block may be contained in the lowest
- * overlapping range and because as the range expands (as you pass over the files) you
- * may be required to reexamine previous files to pick up previously excluded blocks that
- * are now included in the expanded range.
- */
- lowLimit = INT_MAX;
- highLimit = INT_MAX;
- overlap = FALSE;
-
- SetHighLimitAndReExaminePreviousFiles:
- filePtr = firstScriptFilePtr;
- while (filePtr != NULL) {
- lowLimitPtr = filePtr->lowLimitPtr;
- if (lowLimitPtr != NULL) {
- lowLimitInFile = lowLimitPtr->line0 /* where to begin deleting */;
- highLimitInFile = lowLimitInFile + filePtr->highLimitPtr->deleted /* where to end adding */;
- #if 0 /* comment in when testing */
- printf ("inserted: %d deleted: %d line0: %d line1: %d file: \"%s\" lowLimitInFile: %d highLimitInFile: %d\n",
- lowLimitPtr->inserted, lowLimitPtr->deleted, lowLimitPtr->line0, lowLimitPtr->line1,
- filePtr->namePtr, lowLimitInFile, highLimitInFile);
- #endif
- /*
- * Count non-overlapping empty identical ranges as overlaps
- */
- if (highLimit == lowLimit && highLimit == highLimitInFile && highLimit == lowLimitInFile)
- overlap = TRUE;
- else
- /*
- * Exclude blocks above the range
- */
- if (lowLimitInFile < highLimit) {
- if (highLimitInFile < lowLimit) {
- /*
- * We have a non-overlapping block below all others
- */
- lowLimit = lowLimitInFile;
- highLimit = highLimitInFile;
- } else {
- /*
- * We have a overlapping block, which if it extends the highLimit will open the possibility
- * of overlaps in files that we have already processed. This requires that we reexamine
- * previous files.
- */
- overlap = TRUE;
- if (lowLimitInFile < lowLimit)
- lowLimit = lowLimitInFile;
- if (highLimitInFile > highLimit) {
- highLimit = highLimitInFile;
- #if 0 /* comment in when testing */
- printf ("lowLimit: %d highLimit: %d\n", lowLimit, highLimit);
- #endif
- goto SetHighLimitAndReExaminePreviousFiles;
- } else {
- /*
- * We need to check the possibility of subsequent blocks in this file falling between
- * lowLimit and highLimit.
- */
- nextHighLimitPtr = filePtr->highLimitPtr;
- do {
- nextHighLimitPtr = nextHighLimitPtr->link;
- if (nextHighLimitPtr == NULL /* i.e. no subsequent blocks */)
- break;
- nextLowLimit = nextHighLimitPtr->line0;
- if (nextLowLimit >= highLimit /* i.e. subsequent block doesn't overlap */)
- break;
- /*
- * Subsequent block overlaps. Include it in the list of blocks within the range.
- * Then consider the possibility that the block extended the highLimit and requires
- * that we reexamine previous files.
- */
- filePtr->highLimitPtr = nextHighLimitPtr;
- nextHighLimit = nextLowLimit + nextHighLimitPtr->deleted;
- if (nextHighLimit > highLimit) {
- highLimit = nextHighLimit;
- #if 0 /* comment in when testing */
- printf ("lowLimit: %d highLimit: %d\n", lowLimit, highLimit);
- #endif
- goto SetHighLimitAndReExaminePreviousFiles;
- }
- } while (TRUE);
- }
- }
- }
- }
- #if 0 /* comment in when testing */
- printf ("lowLimit: %d highLimit: %d\n", lowLimit, highLimit);
- #endif
- filePtr = filePtr->nextFilePtr;
- }
- /*
- * We've got the range of changes. If there aren't any more changes then don't write them and
- * exit the loop. Next check for identical changes that overlap.
- */
- if (lowLimit == INT_MAX)
- break;
-
- if (overlap) {
- firstMatchFilePtr = NULL;
- filePtr = firstScriptFilePtr;
- while (filePtr != NULL) {
- lowLimitPtr = filePtr->lowLimitPtr;
- highLimitPtr = filePtr->highLimitPtr;
- if (lowLimitPtr != NULL) {
- highLimitInFile = INT_MAX;
- if (highLimitPtr != NULL)
- highLimitInFile = lowLimitPtr->line0 + highLimitPtr->deleted;
- if (highLimitInFile <= highLimit) {
- if (firstMatchFilePtr == NULL)
- firstMatchFilePtr = filePtr;
- else {
- firstLowLimitPtr = firstMatchFilePtr->lowLimitPtr;
- do {
- if (firstLowLimitPtr == NULL ||
- firstLowLimitPtr->deleted != lowLimitPtr->deleted ||
- firstLowLimitPtr->line0 != lowLimitPtr->line0 ||
- firstLowLimitPtr->inserted != lowLimitPtr->inserted)
- goto ChangesDontMatch;
- lineCount = firstLowLimitPtr->inserted;
- firstLinePtr = &firstMatchFilePtr->linbuf[firstLowLimitPtr->line1];
- linePtr = &filePtr->linbuf[lowLimitPtr->line1];
- while (lineCount > 0) {
- if (firstLinePtr->length != linePtr->length ||
- memcmp (firstLinePtr->text, linePtr->text, linePtr->length) != 0)
- goto ChangesDontMatch;
- firstLinePtr ++;
- linePtr ++;
- lineCount--;
- }
- lowLimitPtr = lowLimitPtr->link;
- firstLowLimitPtr = firstLowLimitPtr->link;
- } while (lowLimitPtr != NULL && highLimit > lowLimitPtr->line0);
- if (firstLowLimitPtr != NULL && highLimit > firstLowLimitPtr->line0)
- goto ChangesDontMatch;
- }
- }
- }
- filePtr = filePtr->nextFilePtr;
- }
- overlap = FALSE;
- }
- ChangesDontMatch:
- /*
- * Write the changes.
- */
- PrintLines (outFilePtr, rootFilePtr, rootLineNumber, lowLimit);
- if (highLimit > lowLimit && showNonCollisions) {
- PrintStartFileName (outFilePtr, rootFilePtr);
- PrintLines (outFilePtr, rootFilePtr, lowLimit, highLimit);
- PrintEndFileName (outFilePtr);
- }
- showFileName = showNonCollisions || overlap;
- filePtr = firstScriptFilePtr;
- printedOneCopy = FALSE;
- while (filePtr != NULL) {
- lowLimitPtr = filePtr->lowLimitPtr;
- highLimitPtr = filePtr->highLimitPtr;
- if (lowLimitPtr != NULL) {
- highLimitInFile = INT_MAX;
- if (highLimitPtr != NULL)
- highLimitInFile = lowLimitPtr->line0 + highLimitPtr->deleted;
- if (highLimitInFile <= highLimit) {
- if (showFileName)
- PrintStartFileName (outFilePtr, filePtr);
- lineNumber = lowLimit;
- do {
- if (showFileName || !printedOneCopy) {
- PrintLines (outFilePtr, rootFilePtr, lineNumber, lowLimitPtr->line0);
- PrintLines (outFilePtr, filePtr, lowLimitPtr->line1, lowLimitPtr->line1 + lowLimitPtr->inserted);
- }
- lineNumber = lowLimitPtr->line0 + lowLimitPtr->deleted;
- if (highLimitPtr == lowLimitPtr)
- highLimitPtr = highLimitPtr->link;
- lowLimitPtr = lowLimitPtr->link;
- } while (lowLimitPtr != NULL && highLimit > lowLimitPtr->line0);
- if (showFileName || !printedOneCopy)
- PrintLines (outFilePtr, rootFilePtr, lineNumber, highLimit);
- if (showFileName)
- PrintEndFileName (outFilePtr);
- filePtr->lowLimitPtr = lowLimitPtr;
- filePtr->highLimitPtr = highLimitPtr;
- printedOneCopy = TRUE;
- }
- }
- if (overlap)
- collision = 1;
- filePtr = filePtr->nextFilePtr;
- }
- rootLineNumber = highLimit;
- } while (TRUE);
- PrintLines (outFilePtr, rootFilePtr, rootLineNumber, INT_MAX);
-
- if (rootLineNumber == 0)
- collision = -1;
- return (collision);
- }
-
- void
- MergePaths (nameListPType pathListPtr)
- {
- char *baseBuffer;
- unsigned int baseBufsize;
- register char *charPtr;
- char **charPtrPtr;
- int collision;
- char *collisionFormatString;
- char collisionName[FILENAME_MAX + 1];
- int count;
- int currentFileType;
- FILE *destinationFileDescriptor;
- fileNameListPType directoryStoragePtr;
- int fileAttributes;
- FILE *fileDescriptor;
- struct file_data *fileListPtr;
- char *fileModeCharPtr;
- register struct file_data *filePtr;
- int filesThatDifferFromBase;
- char *fileTypeString;
- struct file_data *fileWithDataPtr;
- int incompleteMerge;
- char *incompleteMergeString;
- int ioResult;
- int isBinaryFile;
- char *lastFileNamePtr;
- int lastFileType;
- register namePType namePtr;
- int namesArrayLength;
- char **namesArrayPtr;
- int namesArrayTotalSpace;
- int newNamesArrayLength;
- char **nextCharPtrPtr;
- struct file_data *nextFilePtr;
- int sourceFileCount;
- char *suffixCharPtr;
- int version;
- char versionString [12 + LENGTH_OF_COLLISION_PREFIX];
-
- #ifdef DF_MACHINE_MACINTOSH
- SpinCursor (1);
- #endif
-
- destinationFileDescriptor = NULL;
- fileListPtr = NULL;
- collision = FALSE;
- sourceFileCount = pathListPtr->numberOfItems - 1 /* minus destination path */;
-
- count = pathListPtr->numberOfItems - 1 /* minus destination path */;
- namePtr = pathListPtr->nameData /* start with root */;
- lastFileType = BAD_FILE_TYPE;
- lastFileNamePtr = NULL /* initialize for debugging */;
-
- while (count > 0) {
- currentFileType = FileType (namePtr->name);
- if (currentFileType != BAD_FILE_TYPE) {
- if (lastFileType != BAD_FILE_TYPE && lastFileType != currentFileType) {
- fprintf (stderr, "%s\n%s\n", lastFileNamePtr, namePtr->name);
- Error (MIXED_FILE_TYPES_DONT_MERGE);
- }
- lastFileType = currentFileType;
- lastFileNamePtr = namePtr->name;
- }
- count--;
- namePtr ++;
- }
- switch (lastFileType) {
- case (DIRECTORY_TYPE):
- namePtr = pathListPtr->nameData;
- count = sourceFileCount;
-
- namesArrayTotalSpace = (256 * sizeof (char *));
- namesArrayPtr = xmalloc (namesArrayTotalSpace + sizeof (char *) /* for NULL termination */);
- namesArrayLength = 0;
- filePtr = NULL;
-
- do {
- directoryStoragePtr = ReadDirectory (namePtr->name);
- if (directoryStoragePtr != NULL) {
- nextFilePtr = xmalloc (sizeof (struct file_data));
- bzero (nextFilePtr, sizeof (struct file_data));
- nextFilePtr->buffer = (char *) directoryStoragePtr;
- if (fileListPtr == NULL)
- fileListPtr = nextFilePtr;
- else
- filePtr->nextFilePtr = nextFilePtr;
- filePtr = nextFilePtr;
- charPtr = directoryStoragePtr->names;
- newNamesArrayLength = namesArrayLength + (sizeof (char *) * directoryStoragePtr->numberOfItems);
- if (newNamesArrayLength > namesArrayTotalSpace) {
- namesArrayTotalSpace = newNamesArrayLength + (128 * sizeof (char *));
- namesArrayPtr = xrealloc (namesArrayPtr, namesArrayTotalSpace + sizeof (char *)/* for NULL termination */);
- }
- charPtrPtr = (char **) ((char *) namesArrayPtr + namesArrayLength);
- while (*charPtr != '\0') {
- *charPtrPtr++ = charPtr;
- charPtr += strlen (charPtr) + 1;
- }
- namesArrayLength = newNamesArrayLength;
- }
- count --;
- namePtr++;
- } while (count > 0);
- charPtrPtr = (char **) ((char *) namesArrayPtr + namesArrayLength);
- *charPtrPtr = NULL;
-
- ioResult = MakeDirectory (namePtr->name);
- if (ioResult != 0)
- ErrorWithStringArgument (CANT_CREATE_DIRECTORY, namePtr->name);
-
- qsort ((void *) namesArrayPtr,
- namesArrayLength / sizeof (char *),
- sizeof (char *),
- (int(__cdecl *) (const void *, const void *)) StrPtrCmp);
- charPtrPtr = namesArrayPtr;
- while (*charPtrPtr != NULL) {
-
- charPtr = *charPtrPtr;
- if (!IgnoreFile (charPtr)) {
- namePtr = pathListPtr->nameData;
- count = pathListPtr->numberOfItems;
- do {
- suffixCharPtr = strrchr (namePtr->name, DIRECTORY_CHAR);
- if (suffixCharPtr == NULL || *(suffixCharPtr + 1) != '\0')
- AppendCharToPathName (namePtr->name, DIRECTORY_CHAR);
- AppendStringToPathName (namePtr->name, charPtr);
- count --;
- namePtr++;
- } while (count > 0);
-
- MergePaths (pathListPtr);
-
- namePtr = pathListPtr->nameData;
- count = pathListPtr->numberOfItems;
- do {
- RemoveNameSuffix (namePtr->name);
- count --;
- namePtr++;
- } while (count > 0);
- }
-
- nextCharPtrPtr = charPtrPtr + 1;
- while (*nextCharPtrPtr != NULL && strcmp (charPtr, *nextCharPtrPtr) == 0)
- nextCharPtrPtr++;
- charPtrPtr = nextCharPtrPtr;
- }
- free (namesArrayPtr);
- break;
- case (BINARY_TYPE):
- case (TEXT_TYPE):
- isBinaryFile = lastFileType == BINARY_TYPE;
- collision = FALSE;
- incompleteMerge = FALSE;
- /*
- * Allocate the space necessary for all the files.
- */
- fileModeCharPtr = "r";
- if (isBinaryFile)
- fileModeCharPtr = "rb";
- namePtr = pathListPtr->nameData;
- filePtr = xmalloc (sizeof (struct file_data));
- bzero (filePtr, sizeof (struct file_data));
- filePtr->namePtr = namePtr->name;
- filePtr->desc = fopen (namePtr->name, fileModeCharPtr);
- if (filePtr->desc == NULL /* i.e. root doesn't exist*/)
- incompleteMerge = ADDED;
- fileListPtr = filePtr;
- namePtr++; /* Skip over the root file */
- /*
- * Open all the files.
- */
- version = 1;
- do {
- fileDescriptor = fopen (namePtr->name, fileModeCharPtr);
- if (fileDescriptor == NULL) {
- if (!incompleteMerge)
- incompleteMerge = REMOVED;
- } else {
- filePtr->nextFilePtr = xmalloc (sizeof (struct file_data));
- filePtr = filePtr->nextFilePtr;
- bzero (filePtr, sizeof (struct file_data));
- filePtr->namePtr = namePtr->name;
- filePtr->desc = fileDescriptor;
- filePtr->version = version;
- }
- version ++;
- namePtr++;
- } while (version < sourceFileCount);
- /*
- * When we have not removed the file then it needs to be kept in the destination.
- * Note that namePtr points to the destination file,
- */
- if (incompleteMerge != REMOVED) {
- /*
- * If the root exists and the type of files are text we have the
- * typical case of merging one or more files into the root.
- */
- if (fileListPtr->desc != NULL && lastFileType == TEXT_TYPE) {
- destinationFileDescriptor = CreateTypedFile (namePtr->name, isBinaryFile);
- lastFileNamePtr = namePtr->name;
- collision = MergeFiles (fileListPtr, destinationFileDescriptor);
- (void) fclose (destinationFileDescriptor);
- destinationFileDescriptor = NULL;
- fileAttributes = RESOURCE_MASK;
- if (collision == -1) {
- fileAttributes |= DATE_MASK;
- collision = FALSE;
- }
- if (collision) {
- (void) strcpy (collisionName, namePtr->name);
- PrependStringToPathName (collisionName, COLLISION_PREFIX);
- lastFileNamePtr = collisionName;
- /*
- * Remove a file with the collisionName and ignore the result
- * in case the file doesn't exist.
- */
- (void) remove (collisionName);
- ioResult = rename (namePtr->name, collisionName);
- if (ioResult != 0)
- Error (UNEXPECTED_IO_ERROR);
- }
- /*
- * When CopyFileAttributes copies the date it requires that the destination file
- * be closed, otherwise the date is instead set to the time the file is closed.
- */
- CopyFileAttributes (fileListPtr->namePtr, lastFileNamePtr, fileAttributes);
- } else {
- /*
- * Read in all the files
- */
- filePtr = fileListPtr;
- while (filePtr != NULL) {
- if (filePtr->desc != NULL) {
-
- ioResult = fseek (filePtr->desc, 0, SEEK_END);
- if (ioResult != 0)
- ErrorWithStringArgument (UNEXPECTED_IO_ERROR, filePtr->namePtr);
-
- filePtr->bufsize = (unsigned int) ftell (filePtr->desc);
- if (filePtr->bufsize == -1)
- ErrorWithStringArgument (UNEXPECTED_IO_ERROR, filePtr->namePtr);
-
- ioResult = fseek (filePtr->desc, 0, SEEK_SET);
- if (ioResult != 0)
- ErrorWithStringArgument (UNEXPECTED_IO_ERROR, filePtr->namePtr);
-
- filePtr->buffer = (char *) xmalloc (filePtr->bufsize);
- /*
- * We reset bufsize to the actual number of characters in the buffer rather
- * than the size malloced. They may differ when they are text files when,
- * for example, text files store end of lines as more than one character.
- */
- filePtr->buffered_chars = fread (filePtr->buffer, 1, filePtr->bufsize, filePtr->desc);
- if (ferror (filePtr->desc) != 0)
- ErrorWithStringArgument (UNEXPECTED_IO_ERROR, filePtr->namePtr);
- if (filePtr->buffered_chars != filePtr->bufsize) {
- filePtr->bufsize = filePtr->buffered_chars;
- filePtr->buffer = (char *) xrealloc (filePtr->buffer, filePtr->bufsize + 2);
- }
- }
- filePtr = filePtr->nextFilePtr;
- }
- /*
- * If one or fewer files differ from the base then take the modified file or base
- * respectively. This situation occurs only for binary files since text files are
- * merged.
- */
- if (fileListPtr->desc != NULL) {
- filesThatDifferFromBase = 0;
- filePtr = fileListPtr;
- baseBufsize = filePtr->bufsize;
- baseBuffer = filePtr->buffer;
- fileWithDataPtr = filePtr;
- filePtr = filePtr->nextFilePtr;
- while (filePtr != NULL && filesThatDifferFromBase <= 1) {
- if (filePtr->desc != NULL) {
- if ( (baseBufsize != filePtr->bufsize) ||
- memcmp (baseBuffer, filePtr->buffer, filePtr->bufsize) != 0 ) {
- filesThatDifferFromBase += 1;
- fileWithDataPtr = filePtr;
- }
- }
- filePtr = filePtr->nextFilePtr;
- }
- if (filesThatDifferFromBase <= 1)
- goto CopyFileWithData;
- else {
- collision = TRUE;
- goto MotherOfAllCollisions;
- }
- } else {
- /*
- * We don't have a base. If all the copies are equal then keep one
- * of the copies.
- */
- fileWithDataPtr = NULL;
- filePtr = fileListPtr;
- while (filePtr != NULL) {
- if (filePtr->desc != NULL) {
- if (fileWithDataPtr == NULL)
- fileWithDataPtr = filePtr;
- else
- if ( (fileWithDataPtr->bufsize != filePtr->bufsize) ||
- memcmp (fileWithDataPtr->buffer, filePtr->buffer, filePtr->bufsize) != 0 ) {
- collision = TRUE;
- break;
- }
- }
- filePtr = filePtr->nextFilePtr;
- }
-
- if (!collision) {
- /*
- * Copy the file pointed to by fileWithDataPtr to the destination.
- */
- CopyFileWithData:
- destinationFileDescriptor = CreateTypedFile (namePtr->name, isBinaryFile);
- fwrite (fileWithDataPtr->buffer,
- sizeof (char),
- fileWithDataPtr->bufsize,
- destinationFileDescriptor);
- (void) fclose (destinationFileDescriptor);
- destinationFileDescriptor = NULL;
- if (fileListPtr->desc != NULL /*i.e. base exists */)
- CopyFileAttributes (fileListPtr->namePtr, namePtr->name, RESOURCE_MASK | DATE_MASK);
- else
- CopyFileAttributes (fileWithDataPtr->namePtr, namePtr->name, RESOURCE_MASK);
- } else {
- MotherOfAllCollisions:
- /*
- * Copy all the modified files to the destination and indicate a collision.
- */
- filePtr = fileListPtr->nextFilePtr;
- while (filePtr != NULL) {
- strcpy (collisionName, namePtr->name);
- sprintf (versionString, "%s%d", COLLISION_PREFIX, filePtr->version);
- PrependStringToPathName (collisionName, versionString);
- destinationFileDescriptor = CreateTypedFile (collisionName, isBinaryFile);
- fwrite (filePtr->buffer, sizeof (char), filePtr->bufsize, destinationFileDescriptor);
- (void) fclose (destinationFileDescriptor);
- destinationFileDescriptor = NULL;
- CopyFileAttributes (filePtr->namePtr, collisionName, RESOURCE_MASK | DATE_MASK);
- filePtr = filePtr->nextFilePtr;
- }
- }
- }
- }
- }
- fileTypeString = " " ;
- if (lastFileType == BINARY_TYPE)
- fileTypeString = "BINARY FILE";
-
- collisionFormatString = " ";
- if (collision)
- collisionFormatString = "COLLISION";
-
- incompleteMergeString = " ";
- if (incompleteMerge == ADDED)
- incompleteMergeString = "ADDED ";
- else if (incompleteMerge == REMOVED)
- incompleteMergeString = "REMOVED";
-
- printf ("%s %s %s %s\n", collisionFormatString, incompleteMergeString, fileTypeString, namePtr->name);
- break;
- }
-
- filePtr = fileListPtr;
- while (filePtr != NULL) {
- nextFilePtr = filePtr->nextFilePtr;
- freeFile (filePtr);
- free (filePtr);
- filePtr = nextFilePtr;
- }
- }
-
- void
- PrependStringToPathName (char *destinationCharPtr, const char *prefixCharPtr)
- {
- char *fileNamePtr;
- int prefixLength;
-
- fileNamePtr = strrchr (destinationCharPtr, DIRECTORY_CHAR);
- prefixLength = strlen (prefixCharPtr);
- if (strlen (destinationCharPtr) + prefixLength > FILENAME_MAX) {
- if (fileNamePtr == NULL)
- fprintf (stderr, "%s%s\n", prefixCharPtr, destinationCharPtr);
- else {
- *fileNamePtr = '\0';
- fprintf (stderr, "%s%c%s\n", destinationCharPtr, DIRECTORY_CHAR, fileNamePtr + 1);
- *fileNamePtr = DIRECTORY_CHAR;
- }
- Error (PATH_TOO_LONG);
- }
- if (fileNamePtr == NULL)
- fileNamePtr = destinationCharPtr;
- else
- fileNamePtr++;
- (void) memmove (fileNamePtr + prefixLength, fileNamePtr, strlen (fileNamePtr) + 1);
- (void) memcpy (fileNamePtr, prefixCharPtr, prefixLength);
- }
-
-
- void
- PrintEndFileName (FILE *outFilePtr)
- {
- fprintf (outFilePtr, "#####\n");
- }
-
- void
- PrintLines (FILE *outFilePtr, struct file_data *filePtr, int startLineNumber, register int endLineNumber)
- {
- struct line_def *linePtr;
- register int maxLineNumber;
- register int numberOfLines;
-
- linePtr = &filePtr->linbuf[startLineNumber];
- maxLineNumber = filePtr->buffered_lines;
- if (endLineNumber > maxLineNumber)
- endLineNumber = maxLineNumber;
- numberOfLines = endLineNumber - startLineNumber;
- while (numberOfLines > 0) {
- fwrite (linePtr->text, sizeof (char), linePtr->length, outFilePtr);
- linePtr ++;
- numberOfLines --;
- }
- }
-
- void
- PrintStartFileName (FILE *outFilePtr, struct file_data *filePtr)
- {
- fprintf (outFilePtr, "##### File: %s\n", filePtr->namePtr);
- }
-
- int
- __cdecl StrPtrCmp (char **string0PtrPtr, char **string1PtrPtr)
- {
- return (strcmp (*string0PtrPtr, *string1PtrPtr));
- }
-