windows-nt/Source/XPSP1/NT/sdktools/diff/diff.c
2020-09-26 16:20:57 +08:00

1275 lines
30 KiB
C

/* SORT
* %Z% %M% %I% %D% %Q%
*
* Copyright (C) Microsoft Corporation, 1983
*
* This Module contains Proprietary Information of Microsoft
* Corporation and AT&T, and should be treated as Confidential.
*/
/*** diff - differential file comparison
*
* MODIFICATION HISTORY
* M000 18 Apr 83 andyp
* - 3.0 upgrade. No changes.
* M001 22 Mar 84 vich
* - Don't try to unlink NULL. Trying to do so doesn't break anything,
* but it makes kernel debugging a pain due to faults in user mode.
* M002 ??
* - added the MSDOS flag.
* M006 31 Mar 86 craigwi
* - for the MSDOS version, fixed -b feature so that it ignores all \r
* M010 15 Dec 86 craigwi
* - after printing the result, diff aborts with status = 2 if any error
* occurred on stdout.
* M013 21 Mar 88 jangr
* - added -s flag to return SLM specific error statuses:
* 10 files identical
* 11 files different
* 12 other errors
* 13 write error
* M017 27 Oct 88 alanba
* - changed messages to not specify using the -h option and giving
* a clear error message if being executed from within SLM.
*/
/*
* Uses an algorithm due to Harold Stone, which finds
* a pair of longest identical subsequences in the two
* files.
*
* The major goal is to generate the match vector J.
* J[i] is the index of the line in file1 corresponding
* to line i file0. J[i] = 0 if there is no
* such line in file1.
*
* Lines are hashed so as to work in core. All potential
* matches are located by sorting the lines of each file
* on the hash (called value). In particular, this
* collects the equivalence classes in file1 together.
* Subroutine equiv replaces the value of each line in
* file0 by the index of the first element of its
* matching equivalence in (the reordered) file1.
* To save space equiv squeezes file1 into a single
* array member in which the equivalence classes
* are simply concatenated, except that their first
* members are flagged by changing sign.
*
* Next the indices that point into member are unsorted into
* array class according to the original order of file0.
*
* The cleverness lies in routine stone. This marches
* through the lines of file0, developing a vector klist
* of "k-candidates". At step i a k-candidate is a matched
* pair of lines x,y (x in file0 y in file1) such that
* there is a common subsequence of lenght k
* between the first i lines of file0 and the first y
* lines of file1, but there is no such subsequence for
* any smaller y. x is the earliest possible mate to y
* that occurs in such a subsequence.
*
* Whenever any of the members of the equivalence class of
* lines in file1 matable to a line in file0 has serial number
* less than the y of some k-candidate, that k-candidate
* with the smallest such y is replaced. The new
* k-candidate is chained (via pred) to the current
* k-1 candidate so that the actual subsequence can
* be recovered. When a member has serial number greater
* that the y of all k-candidates, the klist is extended.
* At the end, the longest subsequence is pulled out
* and placed in the array J by unravel.
*
* With J in hand, the matches there recorded are
* checked against reality to assure that no spurious
* matches have crept in due to hashing. If they have,
* they are broken, and "jackpot " is recorded--a harmless
* matter except that a true match for a spuriously
* mated line may now be unnecessarily reported as a change.
*
* Much of the complexity of the program comes simply
* from trying to minimize core utilization and
* maximize the range of doable problems by dynamically
* allocating what is needed and reusing what is not.
* The core requirements for problems larger than somewhat
* are (in words) 2*length(file0) + length(file1) +
* 3*(number of k-candidates installed), typically about
* 6n words for files of length n.
*/
#include <stdio.h>
#include <io.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <excpt.h>
#include <process.h>
#include <fcntl.h>
#ifdef _OS2_SUBSYS_
#define INCL_DOSSIGNALS
#include <os2.h>
#else
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
/*
* Signal subtypes for XCPT_SIGNAL
*/
#define XCPT_SIGNAL 0xC0010003
#define XCPT_SIGNAL_INTR 1
#define XCPT_SIGNAL_KILLPROC 3
#define XCPT_SIGNAL_BREAK 4
#endif
#define isslash(c) (c=='/'||c=='\\')
#define DIFFH "diffh.exe"
#ifndef _MAX_PATH
#if defined(LFNMAX) && defined(LPNMAX)
#define _MAX_PATH (LFNMAX + LPNMAX + 1)
#else
#define _MAX_PATH (80)
#endif
#endif
#ifndef _HEAP_MAXREQ
#define _HEAP_MAXREQ ((~(unsigned int) 0) - (unsigned) 32)
#endif
#define HALFLONG 16
#define low(x) (x&((1L<<HALFLONG)-1))
#define high(x) (x>>HALFLONG)
struct cand **clist; /* merely a free storage pot for candidates */
int clistcnt = 0; /* number of arrays of struct cand in clist */
unsigned clen = 0; /* total number of struct cand in all clist arrays */
/*
Number of struct cand in one clist array
(the largest power of 2 smaller than (64k / sizeof(struct cand))
is 2^13. Thus, these gross hacks to make the array references
more efficient, and still permit huge files.
*/
#define CLISTSEG (0x2000)
#define CLISTDIV(x) ((x) >> 13)
#define CLISTMOD(x) ((x) & (CLISTSEG - 1))
#define CLIST(x) (clist[CLISTDIV(x)][CLISTMOD(x)])
PVOID input[2];
char *inputfile[2];
int inputfilesize[2];
char *inputfilep[2];
int inputfileleft[2];
#define EndOfFile(x) (inputfileleft[x] <= 0)
#define GetChar(x) ((char)((inputfileleft[x]--) ? \
(*(inputfilep[x])++) : \
EOF))
#define SEARCH(c1,k1,y1) (CLIST(c1[k1]).y < y1) ? (k1+1) : search(c1,k1,y1)
#if 0
char
GetChar( int x );
char
GetChar( int x ) {
if ( inputfileleft[x]-- ) {
return *(inputfilep[x])++;
} else {
return EOF;
}
}
#endif
struct cand {
int x;
int y;
unsigned pred;
} cand;
struct line {
int serial;
int value;
} *file[2], line;
typedef struct _FILEMAP *PFILEMAP;
typedef struct _FILEMAP {
HANDLE FileHandle;
HANDLE MapHandle;
DWORD Access;
DWORD Create;
DWORD Share;
PVOID Base;
DWORD Offset;
DWORD Size;
DWORD Allocated;
} FILEMAP;
PVOID
Open(
const char *FileName,
const char *Mode,
DWORD Size
);
int
Close (
PVOID Map
);
/* fn prototypes gen'd from cl -Zg */
void done(void);
char *talloc(unsigned n);
char *ralloc(char *p,unsigned n);
void myfree( char *p );
void noroom(void);
int __cdecl sortcmp(void const *first, void const *second);
void unsort(struct line *f,unsigned l,int *b);
void filename(char * *pa1,char * *pa2);
void prepare(int i,char *arg);
void prune(void);
void equiv(struct line *a,int n,struct line *b,int m,int *c);
int stone(int *a,unsigned n,int *b,unsigned *c);
unsigned newcand(int x,int y,unsigned pred);
int search(unsigned *c,int k,int y);
void unravel(unsigned p);
void check(char * *argv);
char * skipline(int f);
void output(char * *argv);
void change(int a,int b,int c,int d);
void range(int a,int b,char *separator);
void fetch(char * *f,int a,int b, int lb,char *s);
int readhash( int f);
void mesg(char *s,char *t);
void SetOutputFile (char *FileName);
unsigned len[2];
struct line *sfile[2]; /*shortened by pruning common prefix and suffix*/
unsigned slen[2];
unsigned int pref, suff; /*length of prefix and suffix*/
int *class; /*will be overlaid on file[0]*/
int *member; /*will be overlaid on file[1]*/
unsigned *klist; /*will be overlaid on file[0] after class*/
int *J; /*will be overlaid on class*/
char * *ixold; /*will be overlaid on klist*/
char * *ixnew; /*will be overlaid on file[1]*/
int opt; /* -1,0,1 = -e,normal,-f */
int status = 2; /*abnormal status; set to 0/1 just before successful exit */
int anychange = 0;
char *empty = "";
int bflag;
int slmFlag;
FILE* OutputFile;
char *tempfile; /*used when comparing against std input*/
#ifndef MSDOS
char *dummy; /*used in resetting storage search ptr*/
#endif
void
done()
{
if (tempfile != NULL)
_unlink(tempfile);
if (OutputFile && OutputFile != stdout) {
fclose(OutputFile);
}
exit(10*slmFlag + status);
}
#define MALLOC(n) talloc(n)
#define REALLOC(p,n) ralloc(p,n)
#define FREE(p) myfree(p)
// #define DEBUG_MALLOC
#ifdef DEBUG_MALLOC
#define MALLOC_SIG 0xABCDEF00
#define FREE_SIG 0x00FEDCBA
typedef struct _MEMBLOCK {
DWORD Sig;
} MEMBLOCK, *PMEMBLOCK;
#endif
char *
talloc(
unsigned n
)
{
#ifdef DEBUG_MALLOC
PMEMBLOCK mem;
char DbgB[128];
//sprintf(DbgB, "MALLOC size %d -> ", n );
//OutputDebugString( DbgB );
mem = malloc( n + sizeof(MEMBLOCK)+1 );
if ( !mem ) {
noroom();
}
mem->Sig = MALLOC_SIG;
//sprintf(DbgB, "%lX\n", mem );
//OutputDebugString( DbgB );
return (char *)((PBYTE)mem + sizeof(MEMBLOCK));
#else
register char *p;
p = malloc(++n);
if (p == NULL) {
noroom();
}
return p;
#endif
}
char *
ralloc(
char *p,
unsigned n
)
{
#ifdef DEBUG_MALLOC
PMEMBLOCK mem;
char DbgB[128];
mem = (PMEMBLOCK)((PBYTE)p - sizeof(MEMBLOCK));
//sprintf(DbgB, "REALLOC: %lX, %d -> ", mem, n );
//OutputDebugString( DbgB );
if ( mem->Sig != MALLOC_SIG ) {
sprintf(DbgB, "REALLOC ERROR: Reallocating %lX\n", mem );
OutputDebugString( DbgB );
}
mem->Sig = FREE_SIG;
mem = (PMEMBLOCK)realloc(mem, n + sizeof(MEMBLOCK)+1);
if (!mem) {
noroom();
}
mem->Sig = MALLOC_SIG;
//sprintf(DbgB, "%lX\n", mem );
//OutputDebugString( DbgB );
return (char *)((PBYTE)mem + sizeof(MEMBLOCK));
#else
p = realloc(p, ++n);
if (p==NULL) {
noroom();
}
return(p);
#endif
}
void
myfree(
char *p
)
{
#ifdef DEBUG_MALLOC
PMEMBLOCK mem;
char DbgB[128];
mem = (PMEMBLOCK)((PBYTE)p - sizeof(MEMBLOCK));
//sprintf(DbgB, "FREE: %lX -> ", mem );
//OutputDebugString( DbgB);
if ( mem->Sig != MALLOC_SIG ) {
sprintf(DbgB, "\n\tFREE ERROR: FREEING %lX\n", mem );
OutputDebugString( DbgB );
}
mem->Sig = FREE_SIG;
free(mem);
//sprintf(DbgB, "Ok\n", mem );
//OutputDebugString( DbgB);
#else
if (p) {
free(p);
}
#endif
}
void
noroom()
{
if (slmFlag == 1) {
mesg("file too big; do delfile filename/addfile filename, or",empty);
mesg("reduce the size of the file.",empty);
done();
}
mesg("files too big",empty); /* end M017 */
done();
}
int
__cdecl
sortcmp(
const void *first,
const void *second
)
{
struct line *one = (struct line *)first;
struct line *two = (struct line *)second;
if (one->value < two->value)
return -1;
else if (one->value > two->value)
return 1;
else if (one->serial < two->serial)
return -1;
else if (one->serial > two->serial)
return 1;
else
return 0;
}
void
unsort(
struct line *f,
unsigned l,
int *b
)
{
register int *a;
register unsigned int i;
a = (int *)MALLOC((l+1)*sizeof(int));
if (a) {
memset(a, 0, (l+1)*sizeof(int));
for (i=1;i<=l;i++)
a[f[i].serial] = f[i].value;
for (i=1;i<=l;i++)
b[i] = a[i];
FREE((char *)a);
}
}
void
filename(
char **pa1,
char **pa2
)
{
register char *a1, *b1, *a2;
char buf[BUFSIZ];
struct _stat stbuf;
int i, f;
a1 = *pa1;
a2 = *pa2;
if (_stat(a1,&stbuf)!=-1 && ((stbuf.st_mode&S_IFMT)==S_IFDIR)) {
b1 = *pa1 = MALLOC((unsigned) _MAX_PATH);
while (*b1++ = *a1++) ;
if (isslash(b1[-2]))
b1--;
else
b1[-1] = '/';
a1 = b1;
if ( a2[1] == ':' ) {
a2 += 2;
}
while (*a1++ = *a2++)
if (*a2 && !isslash(*a2) && isslash(a2[-1])) /*M002*/
a1 = b1;
} else if (a1[0]=='-'&&a1[1]==0&&tempfile==NULL) {
/* the signal handling in original source
**
** signal(SIGINT,done);
** #ifndef MSDOS
** signal(SIGHUP,done);
** signal(SIGPIPE,done);
** signal(SIGTERM,done);
** #endif
*/
if ((*pa1 = tempfile = _tempnam(getenv("TEMP"), "d")) == NULL) {
mesg("cannot create temporary file", "");
done();
}
if ((f = _open(tempfile,O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
mesg("cannot create ",tempfile);
done();
}
while ((i=_read(0,buf,BUFSIZ))>0)
_write(f,buf,i);
_close(f);
}
}
void
prepare(
int i,
char *arg
)
{
#define CHUNKSIZE 100
register struct line *p;
register unsigned j;
register int h;
char *c;
PVOID f;
unsigned int MaxSize;
if ((f = input[i] = Open(arg,"r", 0)) == NULL) {
mesg("cannot open ", arg);
done();
}
inputfile[i] = ((PFILEMAP)f)->Base;
inputfilesize[i] = ((PFILEMAP)f)->Size;
inputfilep[i] = inputfile[i];
inputfileleft[i] = inputfilesize[i];
//
// Lets assume that lines are 30 characters on average
//
MaxSize = inputfilesize[i] / 30;
p = (struct line *)MALLOC((3+MaxSize)*sizeof(line));
for (j=0; h=readhash(i);) {
j++;
if ( j >= MaxSize ) {
MaxSize += CHUNKSIZE;
p = (struct line *)REALLOC((char *)p,(MaxSize+3)*sizeof(line));
}
p[j].value = h;
}
p = (struct line *)REALLOC((char *)p,(j+3+1)*sizeof(line));
len[i] = j;
file[i] = p;
//Close(input[i]);
}
void
prune()
{
register unsigned int i,j;
for (pref=0;pref<len[0]&&pref<len[1]&&
file[0][pref+1].value==file[1][pref+1].value;
pref++ ) ;
for (suff=0;suff<len[0]-pref&&suff<len[1]-pref&&
file[0][len[0]-suff].value==file[1][len[1]-suff].value;
suff++) ;
for (j=0;j<2;j++) {
sfile[j] = file[j]+pref;
slen[j] = len[j]-pref-suff;
for (i=0;i<=slen[j];i++)
sfile[j][i].serial = i;
}
}
void
equiv(
struct line *a,
int n,
struct line *b,
int m,
int *c
)
{
register int i, j;
i = j = 1;
while (i<=n && j<=m) {
if (a[i].value <b[j].value)
a[i++].value = 0;
else if (a[i].value == b[j].value)
a[i++].value = j;
else
j++;
}
while (i <= n)
a[i++].value = 0;
b[m+1].value = 0;
j = 0;
while (++j <= m) {
c[j] = -b[j].serial;
while (b[j+1].value == b[j].value) {
j++;
c[j] = b[j].serial;
}
}
c[j] = -1;
}
char **args;
void
__cdecl
main(
int argc,
char **argv
)
{
register int k;
args = argv;
OutputFile = stdout; // Init to default
argc--;
argv++;
while (argc > 0 && argv[0][0]=='-') {
BOOL Skip = FALSE;
for (k=1; (!Skip) && argv[0][k]; k++) {
switch (argv[0][k]) {
case 'e':
opt = -1;
break;
case 'f':
opt = 1;
break;
case 'b':
bflag = 1;
break;
case 'h':
_execvp(DIFFH, args);
mesg("cannot run diffh",empty);
done();
case 's':
slmFlag = 1;
break;
case 'o':
//
// Dirty hack: Redirection is not working, so if
// this flag is present, output goes to
// file.
//
argc--;
argv++;
if (argc < 3) {
mesg("arg count",empty);
done();
}
SetOutputFile(argv[0]);
Skip = TRUE;
break;
}
}
argc--;
argv++;
}
if (argc!=2) {
mesg("arg count",empty);
done();
}
#ifndef MSDOS
dummy = malloc(1);
#endif
_setmode(_fileno(OutputFile), O_BINARY);
_setmode(_fileno(stdin),O_TEXT);
filename(&argv[0], &argv[1]);
filename(&argv[1], &argv[0]);
prepare(0, argv[0]);
prepare(1, argv[1]);
prune();
qsort((char *) (sfile[0] + 1), slen[0], sizeof(struct line), sortcmp);
qsort((char *) (sfile[1] + 1), slen[1], sizeof(struct line), sortcmp);
member = (int *)file[1];
equiv(sfile[0], slen[0], sfile[1], slen[1], member);
member = (int *)REALLOC((char *)member,(slen[1]+2)*sizeof(int));
class = (int *)file[0];
unsort(sfile[0], slen[0], class);
class = (int *)REALLOC((char *)class,(slen[0]+2)*sizeof(int));
klist = (unsigned *)MALLOC((slen[0]+2)*sizeof(int));
clist = (struct cand **)MALLOC(sizeof(struct cand *));
clist[0] = (struct cand *) MALLOC(sizeof(struct cand));
clistcnt = 1;
k = stone(class, slen[0], member, klist);
FREE((char *)member);
FREE((char *)class);
J = (int *)MALLOC((len[0]+2)*sizeof(int));
unravel(klist[k]);
for (k = 0; k < clistcnt; ++k)
FREE((char *)(clist[k]));
FREE((char *)clist);
FREE((char *)klist);
ixold = (char **)MALLOC((len[0]+2)*sizeof(char *));
ixnew = (char **)MALLOC((len[1]+2)*sizeof(char *));
check(argv);
output(argv);
status = anychange;
Close(input[0]);
Close(input[1]);
done();
}
stone(
int *a,
unsigned n,
int *b,
unsigned *c
)
{
register int i, k,y;
int j, l;
unsigned oldc, tc;
int oldl;
k = 0;
c[0] = newcand(0,0,0);
for (i=1; i<=(int)n; i++) {
j = a[i];
if (j==0)
continue;
y = -b[j];
oldl = 0;
oldc = c[0];
do {
if (y <= CLIST(oldc).y)
continue;
l = SEARCH(c, k, y);
if (l!=oldl+1)
oldc = c[l-1];
if (l<=k) {
if (CLIST(c[l]).y <= y)
continue;
tc = c[l];
c[l] = newcand(i,y,oldc);
oldc = tc;
oldl = l;
} else {
c[l] = newcand(i,y,oldc);
k++;
break;
}
} while ((y=b[++j]) > 0);
}
return(k);
}
unsigned
newcand(
int x,
int y,
unsigned pred
)
{
register struct cand *q;
++clen;
if ((int)CLISTDIV(clen) > (clistcnt - 1)) {
// printf("diff: surpassing segment boundry..\n");
clist = (struct cand **) REALLOC((char *) clist,
++clistcnt * sizeof(struct cand *));
clist[clistcnt-1] = (struct cand *) MALLOC(sizeof(struct cand));
}
clist[clistcnt-1] = (struct cand *)
REALLOC((char *)(clist[clistcnt-1]),
(1 + CLISTMOD(clen)) * sizeof(struct cand));
q = &CLIST(clen - 1);
q->x = x;
q->y = y;
q->pred = pred;
return(clen-1);
}
search(
unsigned *c,
int k,
int y
)
{
register int i, j;
int l;
int t;
//if(CLIST(c[k]).y<y) /*quick look for typical case*/
// return(k+1);
i = 0;
j = k+1;
while ((l=(i+j)/2) > i) {
t = CLIST(c[l]).y;
if (t > y)
j = l;
else if (t < y)
i = l;
else
return(l);
}
return(l+1);
}
void
unravel(
unsigned p
)
{
register unsigned int i;
register struct cand *q;
for (i=0; i<=len[0]; i++)
J[i] = i<=pref ? i:
i>len[0]-suff ? i+len[1]-len[0]:
0;
for (q=&CLIST(p);q->y!=0;q=&CLIST(q->pred)) {
J[q->x+pref] = q->y+pref;
}
}
/* check does double duty:
1. ferret out any fortuitous correspondences due
to confounding by hashing (which result in "jackpot")
2. collect random access indexes to the two files */
void
check(
char **argv
)
{
register unsigned int i, j;
int jackpot;
char c,d;
//input[0] = fopen(argv[0],"r");
//input[1] = fopen(argv[1],"r");
inputfilep[0] = inputfile[0];
inputfilep[1] = inputfile[1];
inputfileleft[0] = inputfilesize[0];
inputfileleft[1] = inputfilesize[1];
j = 1;
ixold[0] = ixnew[0] = 0L;
ixold[0] = inputfilep[0];
ixnew[0] = inputfilep[1];
//ixold[1] = inputfilep[0];
//ixnew[1] = inputfilep[1];
jackpot = 0;
for (i=1;i<=len[0];i++) {
if (J[i]==0) {
ixold[i] = skipline(0);
continue;
}
while (j<(unsigned)J[i]) {
ixnew[j] = skipline(1);
j++;
}
for (;;) {
c = GetChar(0);
d = GetChar(1);
if (bflag && isspace(c) && isspace(d)) {
do {
if (c=='\n') break;
} while (isspace(c=GetChar(0)));
do {
if (d=='\n') break;
} while (isspace(d=GetChar(1)));
}
if (c!=d) {
jackpot++;
J[i] = 0;
if (c!='\n')
skipline(0);
if (d!='\n')
skipline(1);
break;
}
if (c=='\n')
break;
}
ixold[i] = inputfilep[0];
ixnew[j] = inputfilep[1];
j++;
}
for (;j<=len[1];j++) {
ixnew[j] = skipline(1);
}
//fclose(input[0]);
//fclose(input[1]);
/*
if(jackpot)
mesg("jackpot",empty);
*/
}
char *
skipline(
int f
)
{
while (GetChar(f) != '\n' )
;
return inputfilep[f];
}
void
output(
char **argv
)
{
int m;
register int i0, i1, j1;
int j0;
input[0] = Open(argv[0],"r", 0);
input[1] = Open(argv[1],"r", 0);
m = len[0];
J[0] = 0;
J[m+1] = len[1]+1;
if (opt!=-1) for (i0=1;i0<=m;i0=i1+1) {
while (i0<=m&&J[i0]==J[i0-1]+1) i0++;
j0 = J[i0-1]+1;
i1 = i0-1;
while (i1<m&&J[i1+1]==0) i1++;
j1 = J[i1+1]-1;
J[i1] = j1;
change(i0,i1,j0,j1);
} else for (i0=m;i0>=1;i0=i1-1) {
while (i0>=1&&J[i0]==J[i0+1]-1&&J[i0]!=0) i0--;
j0 = J[i0+1]-1;
i1 = i0+1;
while (i1>1&&J[i1-1]==0) i1--;
j1 = J[i1-1]+1;
J[i1] = j1;
change(i1,i0,j1,j0);
}
if (m==0)
change(1,0,1,len[1]);
}
void
change(
int a,
int b,
int c,
int d
)
{
if (a>b&&c>d)
return;
anychange = 1;
if (opt!=1) {
range(a,b,",");
putc(a>b?'a':c>d?'d':'c', OutputFile);
if (opt!=-1)
range(c,d,",");
} else {
putc(a>b?'a':c>d?'d':'c', OutputFile);
range(a,b," ");
}
putc('\r',OutputFile);
putc('\n',OutputFile);
if (opt==0) {
fetch(ixold,a,b,0,"< ");
if (a<=b&&c<=d)
fputs("---\r\n", OutputFile);
}
fetch(ixnew,c,d,1,opt==0?"> ":empty);
if (opt!=0&&c<=d)
fputs(".",OutputFile);
}
void
range(
int a,
int b,
char *separator
)
{
fprintf(OutputFile,"%d", a>b?b:a);
if (a<b)
fprintf(OutputFile,"%s%d", separator, b);
}
void
fetch(
char **f,
int a,
int b,
int lb,
char *s
)
{
register int i, j;
register int nc;
register char c;
char *p;
UNREFERENCED_PARAMETER( lb );
for (i=a;i<=b;i++) {
p = f[i-1];
nc = (int)(f[i]-f[i-1]);
fputs(s, OutputFile);
for (j=0;j<nc;j++) {
c = *p++;
if (c == '\n' ) {
//putc( '\r', OutputFile );
putc( '\n', OutputFile );
if ( p >= f[i] ) break;
} else {
putc(c, OutputFile);
}
}
}
}
/* hashing has the effect of
* arranging line in 7-bit bytes and then
* summing 1-s complement in 16-bit hunks
*/
readhash(
int f
)
{
register unsigned shift;
register char t;
register int space;
long sum = 1L;
space = 0;
if (!bflag) for (shift=0;(t=GetChar(f))!='\n';shift+=7) {
if (t==(char)EOF && EndOfFile(f) )
return(0);
sum += (long)t << (shift%=HALFLONG);
} else for (shift=0;;) {
switch (t=GetChar(f)) {
case '\t':
case ' ':
case '\r':
space++;
continue;
default:
if ( t==(char)EOF && EndOfFile(f) ) {
return(0);
}
if (space) {
shift += 7;
space = 0;
}
sum += (long)t << (shift%=HALFLONG);
shift += 7;
continue;
case '\n':
break;
}
break;
}
sum = low(sum) + high(sum);
return((short)low(sum) + (short)high(sum));
}
void
mesg(
char *s,
char *t
)
{
fprintf(stderr,"diff: %s%s\n",s,t);
}
void
SetOutputFile (
char *FileName
)
{
OutputFile = fopen(FileName, "ab");
if (!OutputFile) {
mesg("Unable to open: ", FileName);
done();
}
}
PVOID
Open(
const char *FileName,
const char *Mode,
DWORD Size
)
{
PFILEMAP FileMap = NULL;
FileMap = (PFILEMAP)malloc(sizeof(FILEMAP));
if ( FileMap ) {
FileMap->Access = 0;
FileMap->Share = FILE_SHARE_READ | FILE_SHARE_WRITE;
while ( *Mode ) {
switch ( *Mode ) {
case 'r':
FileMap->Access |= GENERIC_READ;
FileMap->Create = OPEN_EXISTING;
break;
case 'w':
FileMap->Access |= GENERIC_WRITE;
FileMap->Create = CREATE_ALWAYS;
break;
case 'a':
FileMap->Access += GENERIC_WRITE;
FileMap->Create = OPEN_ALWAYS;
break;
case '+':
FileMap->Access |= (GENERIC_READ | GENERIC_WRITE);
break;
default:
break;
}
Mode++;
}
FileMap->FileHandle = CreateFile(
FileName,
FileMap->Access,
FileMap->Share,
NULL,
FileMap->Create,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if ( FileMap->FileHandle != INVALID_HANDLE_VALUE ) {
FileMap->Size = GetFileSize( FileMap->FileHandle, NULL );
FileMap->Allocated = (FileMap->Access == GENERIC_READ) ? FileMap->Size : Size;
FileMap->MapHandle = CreateFileMapping(
FileMap->FileHandle,
NULL,
(FileMap->Access & GENERIC_WRITE) ? PAGE_READWRITE : PAGE_READONLY,
0,
(FileMap->Access == GENERIC_READ) ? 0 : (DWORD)Size,
NULL
);
if ( FileMap->MapHandle ) {
FileMap->Base = MapViewOfFile(
FileMap->MapHandle,
(FileMap->Access & GENERIC_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ,
0,
0,
(FileMap->Access == GENERIC_READ) ? 0 : Size
);
if ( FileMap->Base ) {
if ( FileMap->Create == OPEN_ALWAYS ) {
FileMap->Offset = FileMap->Size;
}
goto Done;
}
CloseHandle( FileMap->MapHandle );
}
CloseHandle( FileMap->FileHandle );
}
free( FileMap );
FileMap = NULL;
}
Done:
return (PVOID)FileMap;
}
int
Close (
PVOID Map
)
{
PFILEMAP FileMap = (PFILEMAP)Map;
UnmapViewOfFile( FileMap->Base );
CloseHandle( FileMap->MapHandle );
if ( FileMap->Access & GENERIC_WRITE ) {
SetFilePointer( FileMap->FileHandle,
FileMap->Size,
0,
FILE_BEGIN );
SetEndOfFile( FileMap->FileHandle );
}
CloseHandle( FileMap->FileHandle );
free( FileMap );
return 0;
}