1
0
Files
irix-657m-src/eoe/cmd/xdiff/xdDiff.c
2022-09-29 17:59:04 +03:00

636 lines
19 KiB
C

/****************************************************************************/
/* xdDiff.c */
/****************************************************************************/
/*
* Functionality to process the output of diff and produce a list
* containing the two files with flags to indicate what the
* differences were.
*/
/*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 1994 Rudy Wortel. All rights reserved.
*/
/*
* $Source: /proj/irix6.5.7m/isms/eoe/cmd/xdiff/RCS/xdDiff.c,v $
* $Revision: 1.2 $
* $Author: blean $
* $Date: 1995/02/27 22:42:22 $
*/
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <xdDiff.h>
/****************************************************************************/
XDdiff *xdFindDiff (
/*
* Return a pointer to the difference whose index is equal to the
* given index.
*/
XDlist *diffs, /*< Look in this list. */
int index /*< Find the entry for this index. */
)
{ /**************************************************************************/
XDdiff *diff;
diff = diffs->first;
while( diff != NULL && diff->index < index ){
diff = diff->next;
}
return diff;
}
/****************************************************************************/
XDdiff *xdAnyUnselected (
/*
* Checks to see if there are any differences that remain unselected.
*/
XDlist *diffs /*< Look in this list. */
)
{ /**************************************************************************/
XDdiff *diff;
diff = diffs->first;
while( diff != NULL ){
if( diff->type != XD_COMMON && diff->selection == XD_SELECTNONE ){
break;
}
diff = diff->next;
}
return diff;
}
/****************************************************************************/
int xdAllocDiff (
/*
* Create a new difference entry. Return 0 when read error occurs.
*/
XDlist *diffs, /*| Difference list being built. */
int index, /*< Overall line index. */
int type, /*< Flag the entry with this type. */
FILE *left, /*< File pointer to the left file. */
int lnuml, /*< Left line number. */
FILE *right, /*< File pointer to the right file. */
int lnumr /*< Right line number. */
)
{ /**************************************************************************/
char text[ 10000 ];
XDdiff *diff;
char *p;
diff = malloc( sizeof (XDdiff) );
if( diff == NULL ){
fprintf( stderr, "%s\n", "Out of memory... Bye!" );
exit( 1 );
}
diff->index = index;
diff->type = type;
diff->lnuml = lnuml;
diff->lnumr = lnumr;
diff->prev = NULL;
diff->next = NULL;
diff->selection = XD_SELECTNONE;
diff->flags = 0;
diff->right = NULL;
if( right != NULL && fgets( text, (sizeof text) - 1, right ) != NULL ){
p = text;
while( *p && *p != '\n' ){
++p;
}
*p = '\0';
diff->right = strdup( text );
}
diff->left = NULL;
if( left != NULL && fgets( text, (sizeof text) - 1, left ) != NULL ){
p = text;
while( *p && *p != '\n' ){
++p;
}
*p = '\0';
diff->left = strdup( text );
}
if( diff->left == NULL && diff->right == NULL ){
free( diff );
diff = NULL;
}else{
/* put it into the list */
if( diffs->first == NULL ){
diffs->first = diff;
diffs->last = diff;
diffs->current = diff;
}else{
diffs->last->next = diff;
diff->prev = diffs->last;
diffs->last = diff;
}
++diffs->lines;
}
return (diff == NULL) ? 0 : 1;
}
/****************************************************************************/
int xdDiffFiles (
/*
* Reads the output of the diff pipe and flags the lines read in
* from the two files. When lines are missing from a file this
* also adds null lines to take their place.
*/
XDlist *diffs, /*| Difference structure being built. */
FILE *left, /*< File pointer to the left file. */
FILE *right, /*< File pointer to the right file. */
FILE *fpd /*< File pointer for reading diff output. */
)
{ /**************************************************************************/
char diff[ 1000 ]; /* Buffer a line of output of diff. */
int difference; /* What kind of difference. */
int leftStart, leftEnd; /* Left line ranges from the diff output. */
int rightStart, rightEnd; /* Right line ranges from the diff output. */
char *type; /* Pointer to the difference chaaracter. */
int leftLine, rightLine; /* Current line number for the two files. */
int differences; /* How many differences were found. */
int index; /* Overall line index. */
leftLine = 0;
rightLine = 0;
differences = 0;
index = 1;
while( fgets( diff, (sizeof diff) - 1, fpd ) ){
/*
* We only need to look at the lines that look like
* <leftRange> [dac] <rightRange>
*/
if( isdigit( diff[ 0 ] ) && (type = strpbrk( diff, "dac" )) != NULL ){
++differences;
/* Get the left range. */
if( sscanf( diff, "%d,%d", &leftStart, &leftEnd ) == 1 ){
leftEnd = leftStart;
}
/* What kind of difference. */
difference = *type++;
/* Get the right range. */
if( sscanf( type, "%d,%d", &rightStart, &rightEnd ) == 1 ){
rightEnd = rightStart;
}
switch( difference ){
case 'd':
/* read the common part */
while( rightLine < rightStart ){
xdAllocDiff( diffs, index++, XD_COMMONTEXT,
left, ++leftLine, right, ++rightLine );
}
/* Flag lines leftStart to leftEnd as left file only. */
while( leftLine < leftEnd ){
xdAllocDiff( diffs, index++, XD_LEFTTEXT,
left, ++leftLine, NULL, rightLine );
}
break;
case 'a':
/* read the common part */
while( leftLine < leftStart ){
xdAllocDiff( diffs, index++, XD_COMMONTEXT,
left, ++leftLine, right, ++rightLine );
}
/* flag lines rightStart to rightEnd as right file only */
while( rightLine < rightEnd ){
xdAllocDiff( diffs, index++, XD_RIGHTTEXT,
NULL, leftLine, right, ++rightLine );
}
break;
case 'c':
/* read the common part */
while( (leftLine + 1) < leftStart ){
xdAllocDiff( diffs, index++, XD_COMMONTEXT,
left, ++leftLine, right, ++rightLine );
}
/*
* flag lines leftStart to leftEnd and rightStart to
* rightEnd as changed.
*/
while( (leftLine < leftEnd) || (rightLine < rightEnd) ){
if( (leftLine < leftEnd) && (rightLine < rightEnd) ){
/* read from both files */
xdAllocDiff( diffs, index++, XD_CHANGEDTEXT,
left, ++leftLine, right, ++rightLine );
}else if( leftLine < leftEnd ){
/* read only from the left */
xdAllocDiff( diffs, index++, XD_CHANGEDTEXT,
left, ++leftLine, NULL, rightLine );
}else if( rightLine < rightEnd ){
/* read only from the right */
xdAllocDiff( diffs, index++, XD_CHANGEDTEXT,
NULL, leftLine, right, ++rightLine );
}
}
break;
}
}
}
/* Read the rest of the two files. */
while( xdAllocDiff( diffs, index, XD_COMMONTEXT,
left, ++leftLine, right, ++rightLine ) ){
++index;
}
diffs->llines = leftLine - 1;
diffs->rlines = rightLine - 1;
sprintf( diff, "%d", diffs->lines );
diffs->digits = strlen( diff );
return differences;
}
/****************************************************************************/
char *xdMakeTemporaryFile (
/*
* Copy the data from the input file pointer and save it in a
* temporary file. Return the name of this file. Returns a pointer
* to a filename which is stored in a static area that will be over
* written on subsequent calls.
*/
FILE *ifp /*< Input file pointer. */
)
{ /**************************************************************************/
static char tempFile[ 1000 ];
char *tmpDir;
FILE *ofp;
int nread;
char iobuf[ BUFSIZ ];
if( (tmpDir = getenv( "TMPDIR" )) == NULL ){
tmpDir = "/usr/tmp";
}
sprintf( tempFile, "%s/xdiffXXXXXX", tmpDir );
(void) mktemp( tempFile );
if( ifp != NULL && (ofp = fopen( tempFile, "w" )) != NULL ){
while( (nread = fread( iobuf, sizeof (char), BUFSIZ, ifp )) > 0 ){
if( fwrite( iobuf, sizeof (char), nread, ofp ) != nread ){
fclose( ofp );
unlink( tempFile );
return NULL;
}
}
fclose( ofp );
}else{
return NULL;
}
return tempFile;
}
/****************************************************************************/
int xdBuildDiffs (
/*
* Take the two file names in the XDlist structure and opens them and
* invokes diff with these as arguments. Calls the function above to read
* the files and build the lists. A file name of NULL means stdin.
*/
XDlist *diffs /*| Difference structure being built. */
)
{ /**************************************************************************/
char str[ 1000 ];
char *copy;
char *leftFile, *rightFile;
FILE *diffFp;
FILE *fp1;
FILE *fp2;
int differences;
int status;
#ifdef __RedoDiff__
XDdiff *diff; /* TO index through the diffs list */
#endif /* __RedoDiff__ */
fp1 = NULL;
fp2 = NULL;
copy = NULL;
status = 0;
#ifdef __RedoDiff__
/* If not the first time, free the memory allocted the previous time */
if ( diffs->first ) {
/* Free allocated memory */
for (diff = diffs->first; diff != NULL; diff = diff->next) free(diff);
for (diff = diffs->last; diff != NULL; diff = diff->next) free(diff);
/* Cancel pointers to items we just freed */
diffs->first = diffs->last = diffs->current = NULL;
/* Flag no lines exist. */
diffs->lines = diffs->rlines = diffs->llines = 0;
}
#endif /* __RedoDiff__ */
/* check the path names for directories */
if( diffs->lfile == NULL ){
if( (copy = xdMakeTemporaryFile( stdin )) != NULL ){
fp1 = fopen( copy, "r" );
}
leftFile = copy;
}else{
fp1 = fopen( diffs->lfile, "r" );
leftFile = diffs->lfile;
}
if( diffs->rfile == NULL ){
if( (copy = xdMakeTemporaryFile( stdin )) != NULL ){
fp2 = fopen( copy, "r" );
}
rightFile = copy;
}else{
fp2 = fopen( diffs->rfile, "r" );
rightFile = diffs->rfile;
}
if( fp1 != NULL && fp2 != NULL ){
sprintf( str, "diff %s%s%s %.400s %.400s",
(diffs->flags & XD_IGN_TRAILING) ? "-w " : "",
(diffs->flags & XD_IGN_WHITESPACE) ? "-b " : "",
(diffs->flags & XD_IGN_CASE) ? "-i " : "",
leftFile, rightFile );
if( (diffFp = popen( str, "r" )) != NULL ){
differences = xdDiffFiles( diffs, fp1, fp2, diffFp );
status = pclose( diffFp );
}
}
if( fp1 != NULL ){
fclose( fp1 );
}else{
fprintf( stderr, "xdiff: Couldn't open '%s'\n", leftFile );
status = -1;
}
if( fp2 != NULL ){
fclose( fp2 );
}else{
fprintf( stderr, "xdiff: Couldn't open '%s'\n", rightFile );
status = -1;
}
if( copy != NULL ){
unlink( copy );
}
if( status == -1 ){
return status;
}else{
return differences;
}
}
/****************************************************************************/
int xdWriteFile (
/*
* Write the selected differences to the given file name. If the file
* name is NULL then write to stdout.
*/
char *fileName, /*< Write to this file. */
XDlist *diffs, /*< List of differences. */
int side /*< Which side to take for common text. */
)
{ /**************************************************************************/
FILE *ofp;
XDdiff *diff;
int status;
status = 0;
if( fileName == NULL ){
ofp = stdout;
}else{
ofp = fopen( fileName, "w" );
}
if( ofp != NULL ){
for( diff = diffs->first; diff != NULL; diff = diff->next ){
if( diff->type == XD_COMMON ){
if( side == XD_LEFTTEXT ){
status = fprintf( ofp, "%s\n", diff->left );
}else{
status = fprintf( ofp, "%s\n", diff->right );
}
}else if( diff->selection == XD_SELECTLEFT ){
if( diff->left != NULL ){
status = fprintf( ofp, "%s\n", diff->left );
}
}else if( diff->selection == XD_SELECTRIGHT ){
if( diff->right != NULL ){
status = fprintf( ofp, "%s\n", diff->right );
}
}else if( diff->selection == XD_SELECTNONE ){
if( diff->left != NULL ){
status = fprintf( ofp, "<:%s\n", diff->left );
}
if( diff->right != NULL ){
status = fprintf( ofp, ">:%s\n", diff->right );
}
}
if( status == EOF ){
break;
}
}
}else{
status = EOF;
}
if( fileName != NULL ){
fclose( ofp );
}
return status;
}
/****************************************************************************/
void xdSplitDifferences (
/*
* If a range of differences is of type XD_CHANGEDTEXT then this will split
* it into two ranges where one is XD_LEFTTEXT and the other is
* XD_RIGHTTEXT. The side argument chooses which side is listed first. The
* selection is retained after the split.
*/
XDlist *diffs, /*< List of differences. */
int side /*< Which side is listed first. */
)
{ /**************************************************************************/
XDdiff *leftDiff;
XDdiff *rightDiff;
XDdiff *firstDiff;
XDdiff *topDiff;
XDdiff *bottomDiff;
XDdiff *prevDiff;
XDdiff *newDiff;
int lline;
int rline;
int added;
int index;
topDiff = diffs->current;
bottomDiff = topDiff;
if( topDiff->type != XD_CHANGEDTEXT ){
return;
}
/* go to the top of the region */
while( topDiff->prev != NULL && topDiff->prev->type == XD_CHANGEDTEXT ){
topDiff = topDiff->prev;
}
/* find the bottom of the region */
while( bottomDiff->next != NULL &&
bottomDiff->next->type == XD_CHANGEDTEXT ){
bottomDiff = bottomDiff->next;
}
rightDiff = topDiff;
prevDiff = NULL;
added = 0;
if( side == XD_LEFTTEXT ){
lline = bottomDiff->lnuml;
rline = topDiff->lnumr - 1;
}else{
lline = topDiff->lnuml - 1;
rline = bottomDiff->lnumr;
}
/* For each line in the region make a new entry for the left side */
while( rightDiff != NULL && rightDiff->type == XD_CHANGEDTEXT ){
leftDiff = malloc( sizeof (XDdiff) );
if( leftDiff == NULL ){
fprintf( stderr, "%s\n", "Out of memory... Bye!" );
exit( 1 );
}
/* Split the information between the two differences */
leftDiff->lnuml = rightDiff->lnuml;
leftDiff->lnumr = rline;
rightDiff->lnuml = lline;
leftDiff->left = rightDiff->left;
leftDiff->right = NULL;
rightDiff->left = NULL;
leftDiff->type = XD_LEFTTEXT;
rightDiff->type = XD_RIGHTTEXT;
leftDiff->flags = rightDiff->flags & ~XD_MATCHED_RIGHT;
rightDiff->flags &= ~XD_MATCHED_LEFT;
leftDiff->selection = rightDiff->selection;
leftDiff->index = rightDiff->index;
/* link up the new differences */
if( prevDiff == NULL ){
firstDiff = leftDiff;
}else{
prevDiff->next = leftDiff;
}
leftDiff->prev = prevDiff;
leftDiff->next = NULL;
prevDiff = leftDiff;
rightDiff = rightDiff->next;
++added;
}
/* new range is bounded by firstDiff and leftDiff */
/* old range is bounded by topDiff and bottomDiff */
if( side == XD_LEFTTEXT ){
/* insert the new differences before topDiff */
if( topDiff->prev == NULL ){
diffs->first = firstDiff;
}else{
topDiff->prev->next = firstDiff;
}
leftDiff->next = topDiff;
firstDiff->prev = topDiff->prev;
topDiff->prev = leftDiff;
}else{
/* insert the new differences after bottomDiff */
if( bottomDiff->next == NULL ){
diffs->last = leftDiff;
}else{
bottomDiff->next->prev = leftDiff;
}
leftDiff->next = bottomDiff->next;
firstDiff->prev = bottomDiff;
bottomDiff->next = firstDiff;
}
/* adjust the index values to compensate for the new entries */
index = topDiff->index;
topDiff = diffs->first;
index = 1;
while( topDiff != NULL ){
topDiff->index = index;
++index;
topDiff = topDiff->next;
}
diffs->lines += added;
}