Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1143 lines
28 KiB

/* This program merges the given source files */
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdlib.h>
#include <signal.h>
#include <malloc.h>
#include <string.h>
#include <stdarg.h>
#include <process.h>
#include "version.h"
#include "unicode.h"
#define szROBin "rb"
#define szWOBin "wb"
#define fTrue 1
#define fFalse 0
#define lnMax 0x7ffffffe
#define lnNil 0x7fffffff /* MUST be greater than lnMax */
#define cbszMin 200
#define cbszInc 100
#ifdef BIT16
#define cbszMax (0xfff0 - cbszInc)
#else
#define cbszMax (0x7ffffff0 - cbszInc)
#endif
#define cchFileNameMax _MAX_PATH
int fDebug = fFalse;
int fHalfAss = fFalse;
int fIgnBlanks = fFalse;
int fIgnLeadSp = fFalse;
int fOldSlmParams = fFalse;
int fSlmParams = fFalse;
long posOrg;
long lnSave;
typedef struct
{
char *szMi; /* name given */
char *szDiff; /* temp name of the form /usr/tmp/M$$.imi */
FILE *pfDiff;
long lnStart; /* set to lnNil when done */
long clnOrg;
char chOp; /* a, c, or d */
long clnNew;
int fTemp; /* fFalse if diff file was on command line */
BOOL bUnicode;
} MI;
#define imiMax (_NFILE - 5) /* 5 for stdin, stdout, stderr, org and new */
MI rgmi[imiMax];
MI *pmiMac = rgmi;
int pid;
int fConflict; /* set if any conflict */
char szUsage1[] = "\nMERGE %u.%u.%02ua Beta\n";
char szUsage2[] = "(This utility is for SLM use only. DO NOT REMOVE!)\n";
/* original file */
char *szOrg;
long lnOrg;
FILE *pfOrg;
BOOL Org_bUnicode;
/* filename only, no path. Only used if -s */
char *szName;
/* new file */
char *szNew;
FILE *pfNew;
/* for -s when we have to construct the names for the two files */
char szOrgT[cchFileNameMax], szMi0[cchFileNameMax], szMi1[cchFileNameMax];
void main(int, char **);
char * SzDiffFlag(void);
char * MergeSzDup(char *);
void RemoveEquMi(void);
int FCmprMiPair(register MI *, register MI *);
int SubtractMi(MI *, MI *, long );
void FindNextEffect(MI **, int *);
void CopyOrg(long);
void SkipOrg(long);
int FMiInRange(MI *, long, long);
void DumpConflict(register MI *);
void DoMerge(register MI *, long);
char * SzMkTemp(int , int );
void InitMi(char *);
void RemoveTemp(void);
int FAnyMi(void);
void AdvanceMi(register MI *);
int FGetLine(FILE *, WCHAR **, BOOL);
int FGetMiLine(MI *, WCHAR **);
int FGetOrgLine(WCHAR **);
void PutLine(char *, ...);
void SaveOrgPos(void);
void SetOrgPos(void);
void OpenOrgNew(char *, char *);
void CloseOrgNew(void);
int MergeRunDiff(char *, char *, char *);
void CopyDiff(register MI *);
void MergeFatalError(int, char *, ... );
void Assert(int);
void Debug(char *, ...);
void __cdecl
main(
int iszMac,
char **rgsz)
{
register char *sz;
int isz, fHard;
MI *pmi;
/* Optionally read args from response file. */
if (iszMac == 2 && rgsz[1][0] == '@') {
FILE *pfArgs;
char *szFile = rgsz[1] + 1;
char *sz0 = rgsz[0];
WCHAR szBuf[BUFSIZ];
char *MergeSzDup();
BOOL bUnicode;
bUnicode = IsFileUnicode (szFile);
/* Open the file, read each line from the file and add it
* to rgsz, incrementing iszMac as we go.
*/
if ((pfArgs = fopen(szFile, "r")) == 0)
MergeFatalError( 2, "cannot open response file %s\n", szFile );
if ((rgsz = (char **)malloc(sizeof(char *))) == 0)
MergeFatalError( 2, "out of memory allocating arguments\n" );
iszMac = 1;
rgsz[0] = MergeSzDup(sz0);
while (fgetsW(szBuf, BUFSIZ, pfArgs, bUnicode) != NULL) {
/* Removing trailing '\n'. */
WCHAR *pchNl;
BYTE chBuf[BUFSIZ * 2];
if ((pchNl = wcschr(szBuf, L'\n')) != 0)
*pchNl = (WCHAR) 0;
++iszMac;
if ((rgsz = (char **)realloc((char *)rgsz, iszMac * sizeof(char *))) == NULL)
MergeFatalError( 2, "out of memory allocating arguments\n" );
memset (chBuf, 0, sizeof(chBuf));
#ifdef _WIN32
WideCharToMultiByte (CP_ACP, 0, szBuf, -1, chBuf, sizeof(chBuf), NULL, NULL);
#else
wcstombs (chBuf, szBuf, sizeof(chBuf));
#endif
rgsz[iszMac - 1] = MergeSzDup(chBuf);
}
fclose(pfArgs);
}
if (getenv("MERGE_DEBUG") != NULL)
fDebug = fTrue;
if (iszMac > 1 && *(sz = rgsz[1]) == '-') {
while (*sz != '\0') {
switch(*sz++) {
case 'd':
fDebug = fTrue;
break;
case 'h':
fHalfAss = fTrue;
break;
case 'b':
fIgnBlanks = fTrue;
break;
case 'l':
fIgnLeadSp = fTrue;
break;
case 's':
fOldSlmParams = fTrue;
break;
case 'z':
fSlmParams = fTrue;
break;
}
}
/* shift remaining args over */
iszMac--;
rgsz[1] = rgsz[0];
rgsz++;
}
if (fOldSlmParams) {
if (iszMac != 7)
MergeFatalError( 2, "usage: merge -s[bhld] <master pattern> <base> <file> <diffBaseSrc> <diffBaseCur> <result>\n" );
}
else if (fSlmParams) {
if (iszMac != 6)
MergeFatalError( 2, "usage: merge -z[bhld] <base> <file> <diffBaseSrc> <diffBaseCur> <result>\n" );
}
else {
if (iszMac < 4)
MergeFatalError( 2, "usage: merge [-bhld] <original> <new files> <result>\n" );
}
pid = _getpid();
Debug("pid = %d\n", pid);
if (fOldSlmParams) {
/* original - /S/base/P/C/<base>
result = <result>
*/
sprintf(szOrgT, rgsz[1], "base", rgsz[2]);
OpenOrgNew(szOrgT, rgsz[6]);
/* initialize global var for use in messages */
szName = rgsz[3];
/* diffBaseSrc = +/S/diff/P/C/<diffBaseSrc> */
*szMi0 = '+';
sprintf(szMi0+1, rgsz[1], "diff", rgsz[4]);
InitMi(szMi0);
/* diff = +/S/diff/P/C/<diff> */
*szMi1 = '+';
sprintf(szMi1+1, rgsz[1], "diff", rgsz[5]);
InitMi(szMi1);
}
else if (fSlmParams) {
OpenOrgNew(rgsz[1], rgsz[5]);
/* initialize global var for use in messages */
szName = rgsz[2];
/* diffBaseSrc */
*szMi0 = '+';
strcpy(szMi0 + 1, rgsz[3]);
InitMi(szMi0);
/* diffBaseCur */
*szMi1 = '+';
strcat(szMi1 + 1, rgsz[4]);
InitMi(szMi1);
}
else {
/* open file */
OpenOrgNew(rgsz[1], rgsz[iszMac-1]);
for (isz = 2; isz < iszMac - 1; isz++)
InitMi(rgsz[isz]);
}
while (FAnyMi()) {
Debug("At line %d in original\n", lnOrg);
RemoveEquMi();
FindNextEffect(&pmi, &fHard); /* find next record */
CopyOrg(pmi->lnStart); /* copy to but not including */
if (fHard)
DumpConflict(pmi); /* dump conflict at line ln */
else
DoMerge(pmi, pmi->clnOrg);
}
CopyOrg(lnMax);
CloseOrgNew();
RemoveTemp();
if (fConflict)
MergeFatalError(1, "%s: one or more files conflicted.\n", (fOldSlmParams||fSlmParams) ? szName : szOrg );
exit(0);
}
/* construct flag for diff assuming that it can accept "-" to mean no options */
char *
SzDiffFlag(
void)
{
static char szFlag[5];
register char *sz = szFlag;
*sz++ = '-';
*sz++ = 's'; // SLMDIFF gots to have this...
if (fHalfAss)
*sz++ = 'h';
if (fIgnBlanks)
*sz++ = 'b';
if (fIgnLeadSp)
*sz++ = 'l';
*sz = '\0';
return szFlag;
}
char *
MergeSzDup(
char *sz)
{
char *szNew;
if ((szNew = malloc(strlen(sz)+1)) == NULL)
MergeFatalError(2, "out of memory\n");
strcpy(szNew, sz);
return szNew;
}
/* Removes (or incrments pointers over) equal Mi's to avoid Conflicts */
void
RemoveEquMi(
void)
{
register MI *pmi1, *pmi2;
int fEqual;
Debug("Begin RemoveEqual------------->\n");
do {
fEqual = fFalse;
/* Select a unique pair of MI's */
for(pmi1 = rgmi; pmi1 < pmiMac; pmi1++) {
for(pmi2 = pmi1 + 1; pmi2 < pmiMac; pmi2++) {
Debug("%s & %s:\t\t", pmi1->szMi, pmi2->szMi);
if (pmi1->lnStart != pmi2->lnStart) {
Debug("Start lines not equal\n");
continue;
}
if (pmi1->chOp != pmi2->chOp) {
Debug("Operations not equal\n");
continue;
}
if (pmi1->lnStart == lnNil || pmi2->lnStart == lnNil) {
Debug("No conflict: one file at EOF\n");
continue;
}
if (FCmprMiPair(pmi1, pmi2))
fEqual = fTrue;
}
}
} while(fEqual);
Debug("<------------End of RemoveEqual\n");
}
/* Compares two Mi's for equality */
/* Check for operation equality, startline equality, not EOF */
/* before calling this routine. */
int
FCmprMiPair(
register MI *pmi1,
register MI *pmi2)
{
WCHAR *sz1;
WCHAR *sz2;
long cln, clnLim;
long pos1, pos2;
int fEquil = fFalse;
if (NULL == (sz1 = malloc(cbszMin)))
MergeFatalError(2, "out of memory\n");
if (NULL == (sz2 = malloc(cbszMin)))
MergeFatalError(2, "out of memory\n");
Debug("<%c> conflict detected\n", pmi1->chOp);
switch(pmi1->chOp) {
case L'a':
case L'c':
/* Store File position */
pos1 = ftell(pmi1->pfDiff); /* Top of diff section */
pos2 = ftell(pmi2->pfDiff);
cln = 0, clnLim = min(pmi1->clnNew, pmi2->clnNew);
/* if there are not anymore equal lines, return fFalse */
if (clnLim == 0)
goto CmprMiPairExit;
while(cln < clnLim) {
/* Read strings to compare */
if (!FGetMiLine(pmi1, &sz1))
MergeFatalError( 2, "error reading %s\n", pmi1->szMi );
if (!FGetMiLine(pmi2, &sz2))
MergeFatalError( 2, "error reading %s\n", pmi2->szMi );
/* Quit comparing if not equal */
Debug("Compare\n%s%s\n", sz1, sz2);
if (wcscmp(sz1, sz2) != 0) {
/* reset both mi */
fseek(pmi2->pfDiff, pos2, 0);
fseek(pmi1->pfDiff, pos1, 0);
goto CmprMiPairExit;
}
cln++;
}
Debug("Number of equal lines: %ld\n", cln);
if (pmi1->clnNew == cln) {
SubtractMi(pmi1, pmi2, pos1);
fEquil = fTrue;
goto CmprMiPairExit;
}
Assert(pmi2->clnNew == cln);
SubtractMi(pmi2, pmi1, pos2);
fEquil = fTrue;
goto CmprMiPairExit;
case L'd':
pmi2->clnOrg -= min(pmi1->clnOrg, pmi2->clnOrg);
pmi2->lnStart += min(pmi1->clnOrg, pmi2->clnOrg);
if (pmi2->clnOrg == 0)
AdvanceMi(pmi2);
fEquil = fTrue;
goto CmprMiPairExit;
}
CmprMiPairExit:
free(sz1);
free(sz2);
return (fEquil);
}
/*
* Adjust *pmiAdjust to not reflect those portions of the change which
* are covered by *pmiKeep. This allows us to not conflict when changes
* match.
*/
int
SubtractMi(
MI *pmiKeep,
MI *pmiAdjust,
long posKeep)
{
/* rewind pmiKeep to start of mi so it gets used */
fseek(pmiKeep->pfDiff, posKeep, 0);
/* remove the identical lines from *pmiAdjust */
pmiAdjust->clnNew -= pmiKeep->clnNew;
pmiAdjust->lnStart += pmiKeep->clnOrg;
/* FIX BUG where lnStart (ie. lnMin) was equal to lnStart+clnOrg,
* (lnLim) which of course is because clnOrg = 0 for append. This
* having lnMac=lnLim was causing FindNextEffect to think there is a
* conflict (ie. acted the same as if you added the line differently
* rather than the same) when there really isn't! By incrementing
* *pmiAdjust to go to the next line, this moves over the matching
* part, and will not cause FMiInRange() to return true.
*/
if (pmiAdjust->chOp == L'a')
pmiAdjust->lnStart++;
if (pmiAdjust->clnOrg > pmiKeep->clnOrg) {
/* remove the portion of the source
* covered by *pmiKeep from the record for
* pmiAdjust.
*/
pmiAdjust->clnOrg -= pmiKeep->clnOrg;
}
else {
/* change pmiAdjust to an append */
pmiAdjust->chOp = L'a';
pmiAdjust->clnOrg = 0;
}
/* advance to next entry in diff file if we ended up clearing this one */
if ((0L == pmiAdjust->clnOrg) && (0L == pmiAdjust->clnNew))
AdvanceMi(pmiAdjust);
return fTrue;
}
/* finds next MI which will effect the source file */
void
FindNextEffect(
MI **ppmi,
int *pfHard)
{
int cmi;
long lnMin, lnLim;
register MI *pmi, *pmiFirst;
pmiFirst = 0; /* will be first and largest */
for (pmi = rgmi; pmi < pmiMac; pmi++) {
if (pmiFirst == 0 || pmi->lnStart < pmiFirst->lnStart)
pmiFirst = pmi;
if (pmi->lnStart == pmiFirst->lnStart &&
pmi->clnOrg > pmiFirst->clnOrg)
pmiFirst = pmi;
}
/* find number of changes in range from lnMin to lnLim; will have >= 1*/
cmi = 0;
lnMin = pmiFirst->lnStart;
lnLim = lnMin + pmiFirst->clnOrg;
for (pmi = rgmi; pmi < pmiMac; pmi++) {
if (FMiInRange(pmi, lnMin, lnLim))
cmi++;
}
Debug("Next change: cmi = %d, lnStart = %ld, lnLim = %ld\n", cmi, lnMin, lnLim);
*pfHard = cmi != 1;
*ppmi = pmiFirst;
}
/* copy orginal file up to but not including ln */
void
CopyOrg(
long ln)
{
WCHAR *sz;
if (NULL == (sz = malloc(cbszMin)))
MergeFatalError(2, "out of memory\n");
Debug("Copy from line %ld to %ld in original\n", lnOrg, ln);
if (ln < lnOrg)
MergeFatalError(2, "%s: backwards copy\n", szOrg);
while(!feof(pfOrg) && lnOrg < ln) {
if (FGetOrgLine(&sz)) {
Debug("\t%ws", sz);
PutLine("%ws", sz);
}
lnOrg++;
}
lnOrg = ln; /* in case of premature eof */
free(sz);
}
/* skips cln lines in original module */
void
SkipOrg(
long cln)
{
WCHAR *sz;
if (NULL == (sz = malloc(cbszMin)))
MergeFatalError(2, "out of memory\n");
Debug("Skip %ld line(s) in original starting at %ld\n", cln, lnOrg);
while(cln-- > 0) {
FGetOrgLine(&sz);
Debug("\t%ws", sz);
lnOrg++;
}
free(sz);
}
/* return fTrue if pmi starts at or after lnMin but before lnLim */
int
FMiInRange(
MI *pmi,
long lnMin,
long lnLim)
{
if (pmi->lnStart < lnMin)
MergeFatalError( 2, "%s: merge processed out of order\n", (fSlmParams||fOldSlmParams) ? szName: szOrg );
return (lnMin == lnLim && pmi->lnStart == lnMin ||
lnMin != lnLim && pmi->lnStart < lnLim);
}
/* dump conflicting modules starting at line pmi->lnStart */
void
DumpConflict(
register MI *pmi)
{
long lnMin = pmi->lnStart;
long lnLim;
Debug("DumpConflict starting at line %ld\n", lnMin);
if (lnMin != lnOrg)
MergeFatalError( 2, "%s: original out of synch\n", (fSlmParams || fOldSlmParams) ? szName : szOrg );
/* minimum range of effect */
lnLim = lnMin + pmi->clnOrg;
/* find maximum range of effect */
for (pmi = rgmi; pmi < pmiMac; pmi++) {
/* if this pmi starts within range lnMin, lnLim and
the extent of the change is greater than thought before.
*/
if (FMiInRange(pmi, lnMin, lnLim) &&
pmi->lnStart + pmi->clnOrg > lnLim)
lnLim = pmi->lnStart + pmi->clnOrg;
}
Debug("\tConflict effects %ld line(s)\n", lnLim - lnMin);
SaveOrgPos();
PutLine("/------------------Merge Conflict------------------\\\r\n");
if (lnMin != lnLim) {
PutLine("+++++++++++++: %s\r\n", (fSlmParams || fOldSlmParams) ? "Original source": szOrg);
CopyOrg(lnLim);
}
/* for each conflicting mi */
for (pmi = rgmi; pmi < pmiMac; pmi++) {
if (FMiInRange(pmi, lnMin, lnLim)) {
SetOrgPos(); /* reposition for merge */
Debug("\tConflict in file %s: lnStart = %ld, clnOrg = %ld, clnNew = %d\n",
pmi->szMi, pmi->lnStart, pmi->clnOrg, pmi->clnNew);
if (fSlmParams || fOldSlmParams) {
if (pmi == rgmi)
PutLine("+++++++++++++: Current source\r\n");
else
PutLine("+++++++++++++: User's version\r\n");
}
else
PutLine("+++++++++++++: %s\r\n", pmi->szMi);
do {
CopyOrg(pmi->lnStart); /* lines before change*/
/* only merge those lines which fall before
lnLim. DoMerge may advance to next change.
*/
DoMerge(pmi, pmi->lnStart + pmi->clnOrg > lnLim
? lnLim - pmi->lnStart
: pmi->clnOrg);
}
while(FMiInRange(pmi, lnMin, lnLim));
/* copy lines after change */
CopyOrg(lnLim);
}
}
if (lnLim != lnOrg)
MergeFatalError( 2, "%s: original out of synch\n", (fSlmParams || fOldSlmParams) ? szName : szOrg );
PutLine("\\-------------------End Conflict-------------------/\r\n");
fConflict = fTrue;
Debug("End conflict\n");
}
/* merge module which begins at line ln; only effect cln lines of the original*/
void
DoMerge(
register MI *pmi,
long cln)
{
Debug("Merge from %s: lnStart = %ld, cln = %ld/%ld, op = %c\n",
pmi->szMi, pmi->lnStart, cln, pmi->clnOrg, pmi->chOp);
if (cln < 0 || cln > pmi->clnOrg)
MergeFatalError( 2, "%s: merging more than original effect\n", (fSlmParams || fOldSlmParams) ? szName : szOrg );
if (pmi->chOp == L'd' || pmi->chOp == L'c')
SkipOrg(cln);
if (pmi->chOp == L'a' || pmi->chOp == L'c')
CopyDiff(pmi);
pmi->lnStart += cln;
pmi->clnOrg -= cln;
pmi->chOp = L'd'; /* if any left, we will just delete it */
if (pmi->clnOrg == 0)
/* all done with this MI; move to next. AdvanceMi also skips
source lines effected and seperator if needed.
*/
AdvanceMi(pmi);
}
/* return a pointer to a temporary filename */
char *
SzMkTemp(
int pid,
int imi)
{
char *szTemp;
register char *sz;
char *getenv();
szTemp = malloc(100);
*szTemp = '\0';
if ((sz = getenv("TMP")) != NULL || (sz = getenv("TEMP")) != NULL) {
strcpy(szTemp, sz);
sz = strchr(szTemp, '\0');
/* add trailing \ if no trailing \ or / yet. */
if (*(sz-1) != '\\' && *(sz-1) != '/')
*sz++ = '\\', *sz = '\0';
}
/* print name on end of szTemp */
sprintf(strchr(szTemp, '\0'), "M%d.%d", pid, imi);
return szTemp;
}
void
InitMi(
char *szNew)
{
int w;
register MI *pmi;
char *szCmd;
Debug("Initialization for %s\n", szNew);
if (NULL == (szCmd = malloc((cchFileNameMax * 3) + 40)))
MergeFatalError(2, "out of memory\n");
if (pmiMac - rgmi >= imiMax)
MergeFatalError( 2, "too many files to merge (%d max)\n", imiMax );
pmi = pmiMac;
pmi->szMi = szNew;
pmi->szDiff = SzMkTemp(pid, pmiMac - rgmi);
pmiMac++;
if (*szNew != '+') /* If not a diff file */ {
char *SzDiffFlag();
sprintf(szCmd, "diff %s %s %s > %s", SzDiffFlag(), szOrg, szNew, pmi->szDiff);
Debug("\tExecute: %s\n", szCmd);
if ((w = MergeRunDiff(szOrg, szNew, pmi->szDiff)) != 0 && w != 0x100 && w != 0xa00 && w != 0xb00)
MergeFatalError( 2, "diff status: %d\n", w );
Debug("\tdiff result: %d\n", w != 0);
pmi->fTemp = fTrue;
}
else {
strcpy(pmi->szDiff, szNew+1);
pmi->fTemp = fFalse;
}
pmi->bUnicode = IsFileUnicode (pmi->szDiff);
if ((pmi->pfDiff = fopen(pmi->szDiff, szROBin)) == NULL)
MergeFatalError( 2, "cannot open temp file for %s\n", pmi->szMi );
Debug("\tTemp file: %s\n", pmi->szDiff);
AdvanceMi(pmi); /* skip to first record */
free(szCmd);
}
void
RemoveTemp(
void)
{
register MI *pmi;
for (pmi = rgmi; pmi < pmiMac; pmi++)
{
if (pmi->pfDiff)
fclose(pmi->pfDiff);
if (pmi->fTemp)
_unlink(pmi->szDiff);
pmi->pfDiff = 0;
}
}
/* return fTrue if any MI do not have lnStart == lnNil */
int
FAnyMi(
void)
{
register MI *pmi;
for (pmi = rgmi; pmi < pmiMac; pmi++)
if (pmi->lnStart != lnNil)
return fTrue;
return fFalse;
}
/* copy the new lines from the diff file to the new file */
void
CopyDiff(
register MI *pmi)
{
WCHAR *sz;
if (NULL == (sz = malloc(cbszMin)))
MergeFatalError(2, "out of memory\n");
Debug("Copy %ld line(s) from %s\n", pmi->clnNew, pmi->szMi);
while(!feof(pmi->pfDiff) && pmi->clnNew-- > 0) {
if (FGetMiLine(pmi, &sz)) { /* read a line from diff */
Debug("\t%ws", sz);
PutLine("%ws", sz + 2); /* remove two characters and write to new file */
}
}
pmi->clnNew = 0;
free(sz);
}
/* read next effect-record, skipping source lines, and seperator if any */
void
AdvanceMi(
register MI *pmi)
{
long ln1, ln2, ln3, ln4, cln;
WCHAR ch;
WCHAR *pchOp, *pchC1, *pchC2;
WCHAR *sz;
if (NULL == (sz = malloc(cbszMin)))
MergeFatalError(2, "out of memory\n");
Debug("Advance to next change for %s\n", pmi->szMi);
if (!FGetMiLine(pmi, &sz)) {
pmi->lnStart = lnNil; /* tested in FAnyMi() */
pmi->clnOrg = 0;
pmi->clnNew = 0;
pmi->chOp = 0;
free(sz);
return;
}
Debug("\tActual line: %ws", sz);
/* FORM: #[,#]a/c/d#[,#] */
if (((pchOp = wcsrchr(sz, L'a')) == 0) &&
((pchOp = wcsrchr(sz, L'c')) == 0) &&
((pchOp = wcsrchr(sz, L'd')) == 0))
MergeFatalError( 2, "%s: no operator character\n", pmi->szMi );
ch = *pchOp;
ln1 = ln2 = ln3 = ln4 = lnMax; /* in case a sscanf fails */
if ((pchC2 = wcsrchr(sz, L',')) != 0) {
*pchC2 = L'\0';
swscanf(pchC2+1, L"%ld", &ln4);
}
if ((pchC1 = wcsrchr(sz, L',')) != 0) {
*pchC1 = L'\0';
swscanf(pchC1+1, L"%ld", &ln2);
}
swscanf(sz, L"%ld", &ln1); /* starting number */
swscanf(pchOp+1, L"%ld", &ln3); /* number after operator */
if (pchC1 == 0 && pchC2 == 0)
/* no commas */
ln4 = ln3, ln2 = ln1;
else if (pchC1 == 0) {
/* pchC2 != 0 */
if (pchC2 < pchOp)
/* only comma before operator */
ln2 = ln4, ln4 = ln3;
else
/* only comma after operator */
ln2 = ln1;
}
/* else pchC1 != 0 and pchC2 != 0; both commas */
if (ln1 == lnMax || ln3 == lnMax)
MergeFatalError( 2, "%s: invalid change record\n", pmi->szMi );
pmi->lnStart = ln1 + (ch == L'a'); /* + 1 if 'a' */
pmi->clnOrg = ch == L'a' ? 0L : ln2 - ln1 + 1;
pmi->clnNew = ch == L'd' ? 0L : ln4 - ln3 + 1;
pmi->chOp = (char) ch; // ch is always 'a', 'c', or 'd'
Debug("\tCalculated line: %ld,%ld%c%ld,%ld\n", ln1, ln2, ch, ln3, ln4);
if (ln2 == lnMax) {
/* line was #,$c/d... ; have to count number of lines to change/delete */
cln = 0;
switch(ch) {
case L'c':
/* count lines up to one which starts with - */
while(FGetMiLine(pmi, &sz) && (*sz != '-'))
cln++;
break;
case L'd':
/* count rest of lines */
while(FGetMiLine(pmi, &sz))
cln++;
break;
}
if (cln == 0)
/* 'a' or other error */
MergeFatalError( 2, "%s: invalid change record\n", pmi->szMi );
ln2 = ln1 + cln - 1;
pmi->clnOrg = cln;
Debug("\tCounted line: %ld,%ld%c%ld,%ld\n", ln1, ln2, ch, ln3, ln4);
}
else {
/* have proper count of lines */
cln = pmi->clnOrg;
if (ch == L'c')
/* for separator line */
cln++;
while(cln-- > 0 && FGetMiLine(pmi, &sz))
;
}
Debug("End Advance\n");
free(sz);
}
int
FGetLine(
FILE *pf,
WCHAR **psz,
BOOL bUnicode)
{
unsigned cbsz = 0;
unsigned cbszMac = _msize(*psz) / sizeof (WCHAR);
**psz = L'\0';
while (fTrue) {
if (NULL == fgetsW(*psz + cbsz, cbszMac - cbsz - 1, pf, bUnicode))
return(**psz != L'\0');
cbsz = wcslen(*psz);
if ((cbsz < (cbszMac - 2)) || (L'\n' == *(*psz + cbsz - 1)))
return(fTrue);
if (cbszMac >= cbszMax / sizeof (WCHAR))
MergeFatalError(2, "out of memory\n");
if (NULL == (*psz = realloc(*psz, _msize(*psz) + cbszInc)))
MergeFatalError(2, "out of memory\n");
cbszMac += cbszInc / sizeof(WCHAR);
}
}
int
FGetMiLine(
MI *pmi,
WCHAR **psz)
{
return (FGetLine(pmi->pfDiff, psz, pmi->bUnicode));
}
int
FGetOrgLine(
WCHAR **psz)
{
return (FGetLine(pfOrg, psz, Org_bUnicode));
}
void
PutLine(
char *szformat, ...)
{
va_list marker;
va_start(marker, szformat);
vfprintf(pfNew, szformat, marker );
va_end(marker);
if (ferror(pfNew) != 0)
MergeFatalError( 2, "write error\n" );
}
void
SaveOrgPos(
void)
{
long ftell();
posOrg = ftell(pfOrg);
lnSave = lnOrg;
}
void
SetOrgPos(
void)
{
fseek(pfOrg, posOrg, 0);
lnOrg = lnSave;
}
void
OpenOrgNew(
char *sz1,
char *sz2)
{
Org_bUnicode = IsFileUnicode (sz1);
/* open original */
szOrg = sz1;
pfOrg = fopen(szOrg, szROBin);
if (pfOrg == 0) {
perror("merge1:");
MergeFatalError( 2, "cannot open %s\n", szOrg );
}
lnOrg = 1; /* current line; 1 based */
Debug("szOrg = %s\n", szOrg);
/* open new */
szNew = sz2;
if (strcmp(szNew, szOrg) == 0)
MergeFatalError( 2, "%s: original and result are the same file\n", (fSlmParams || fOldSlmParams) ? szName : szOrg );
pfNew = strcmp(szNew, "-") == 0 ? _fdopen(1, szWOBin) : fopen(szNew, szWOBin);
if (pfNew == 0) {
perror("merge2:");
MergeFatalError( 2, "cannot open %s\n", szNew );
}
Debug("szNew = %s\n", szNew);
}
void
CloseOrgNew(
void)
{
if (pfOrg) {
fclose(pfOrg);
pfOrg = 0;
}
if (pfNew) {
if (ferror(pfNew) != 0 || fclose(pfNew) != 0) {
/* Prevent CloseOrgNew/FatalError mutual recursion */
pfNew = 0;
MergeFatalError( 2, "write error\n" );
}
pfNew = 0;
}
}
/*VARARGS3*/
/* run diff with args as passed; returns status of diff. */
int
MergeRunDiff(
char *szFile1,
char *szFile2,
char *szStdOut)
{
int fdNew; /* temp fd for new stdout */
int fdOld; /* dup of old stdout while diff runs */
int status;
/* set standard output to file passed */
fdOld = _dup(1);
_close(1); /* next create will use fd == 1! */
fdNew = _creat(szStdOut, 0660);
/* REVIEW - this if statement was commented out in the old NT version */
if (fdNew != 1)
MergeFatalError( 2, "handle for stdout is not 1?\n" );
/* << 8 to make the return value look like one from Xenix */
status = _spawnlp(P_WAIT, "slmdiff.exe", "slmdiff", SzDiffFlag(), szFile1, szFile2, (char *)NULL) << 8;
/* restore stdout */
_dup2(fdOld, 1);
_close(fdOld);
return status;
}
void
MergeFatalError(
int w,
char *fmt, ... )
{
va_list marker;
va_start(marker, fmt );
fprintf(stderr, "\n");
if (strncmp(fmt, "usage: ", 7) != 0)
fprintf(stderr, "merge: ");
vfprintf(stderr, fmt, marker);
va_end(marker);
if (2 == w) {
fprintf(stderr, szUsage1, rmj, rmm, rup);
fprintf(stderr, szUsage2);
}
CloseOrgNew();
RemoveTemp();
exit(w);
}
void
Assert(
int fIsTrue)
{
if (!fIsTrue)
MergeFatalError( 2, "Assertion failure\n" );
}
/*VARARGS1*/
void
Debug(
char *szformat, ...)
{
if (fDebug) {
va_list marker;
va_start(marker, szformat);
vprintf(szformat, marker );
va_end(marker);
}
}