CompareRopesAsMobs:
PROC[rope1,rope2:
ROPE, stats: Stats] =
TRUSTED {
MobBuf1: Buffer = NEW[BufferRep[SIZE[Mob]]];
Mob1: MobPtr = LOOPHOLE[@MobBuf1[0]];
MobBuf2: Buffer = NEW[BufferRep[SIZE[Mob]]];
Mob2: MobPtr = LOOPHOLE[@MobBuf2[0]];
len: INT = MIN[rope1.Length[], rope2.Length[]];
GetWords[rope1, 0, SIZE[Mob], MobBuf1];
GetWords[rope2, 0, SIZE[Mob], MobBuf2];
stats.base1 ¬ Mob1;
stats.base2 ¬ Mob2;
(stats.out).PutRope[stats.name1];
(stats.out).PutRope["\n version: "];
VersionOut[Mob1.version, stats, TRUE];
(stats.out).PutF1[", bytes: %g\n source: ", [integer[rope1.Length[]]]];
NameOut[rope1, Mob1.ssOffset.units, Mob1.source, stats];
(stats.out).PutRope["\n sourceVersion: "];
VersionOut[Mob1.sourceVersion, stats];
(stats.out).PutRope["\n"];
(stats.out).PutRope[stats.name2];
(stats.out).PutRope["\n version: "];
VersionOut[Mob2.version, stats, TRUE];
(stats.out).PutF1[", bytes: %g\n source: ", [integer[rope2.Length[]]]];
NameOut[rope2, Mob2.ssOffset.units, Mob2.source, stats];
(stats.out).PutRope["\n sourceVersion: "];
VersionOut[Mob2.sourceVersion, stats];
(stats.out).PutRope["\n"];
IF rope1.Length[] # rope2.Length[]
THEN {
(stats.out).PutRope["Warning, files have different lengths.\n"];
stats.errors ¬ stats.errors +1};
CompareInts[
"In versionIdent\n", Mob1.versionIdent, Mob2.versionIdent, stats];
CompareVersionStamps[
"In version\n", Mob1.version, Mob2.version, stats];
CompareVersionStamps[
"In creator\n", Mob1.creator, Mob2.creator, stats];
CompareVersionStamps[
"In sourceVersion\n", Mob1.sourceVersion, Mob2.sourceVersion, stats];
CompareInts[
"In source\n", Mob1.source, Mob2.source, stats];
CompareInts[
"In nBytes\n", Mob1.nBytes, Mob2.nBytes, stats];
CompareCard16s[
"In nConfigs\n", Mob1.nConfigs, Mob2.nConfigs, stats];
CompareCard16s[
"In nModules\n", Mob1.nModules, Mob2.nModules, stats];
CompareCard16s[
"In nImports\n", Mob1.nImports, Mob2.nImports, stats];
CompareBools[
"In definitions\n", Mob1.definitions, Mob2.definitions, stats];
CompareBools[
"In repackaged\n", Mob1.repackaged, Mob2.repackaged, stats];
CompareBools[
"In typeExported\n", Mob1.typeExported, Mob2.typeExported, stats];
CompareBools[
"In inlineFloat\n", Mob1.inlineFloat, Mob2.inlineFloat, stats];
CompareBools[
"In mappingStarted\n", Mob1.mappingStarted, Mob2.mappingStarted, stats];
CompareBools[
"In mappingFinished\n", Mob1.mappingFinished, Mob2.mappingFinished, stats];
CompareBools[
"In versions\n", Mob1.versions, Mob2.versions, stats];
CompareBools[
"In extended\n", Mob1.extended, Mob2.extended, stats];
CompareCard16s[
"In nDummies\n", Mob1.nDummies, Mob2.nDummies, stats];
IF stats.debug THEN (stats.out).PutRope["** Tables\n"];
CompareTables[
"string table", @Mob1.ssOffset, @Mob2.ssOffset, stats];
CompareTables[
"config table", @Mob1.ctOffset, @Mob2.ctOffset, stats];
CompareTables[
"module table", @Mob1.mtOffset, @Mob2.mtOffset, stats];
CompareTables[
"import table", @Mob1.impOffset, @Mob2.impOffset, stats];
CompareTables[
"export table", @Mob1.expOffset, @Mob2.expOffset, stats];
CompareTables[
"external variable table", @Mob1.evOffset, @Mob2.evOffset, stats];
CompareTables[
"segment table", @Mob1.sgOffset, @Mob2.sgOffset, stats];
CompareTables[
"file table", @Mob1.ftOffset, @Mob2.ftOffset, stats];
CompareTables[
"space table", @Mob1.spOffset, @Mob2.spOffset, stats];
CompareTables[
"name table", @Mob1.ntOffset, @Mob2.ntOffset, stats];
CompareTables[
"type table", @Mob1.typOffset, @Mob2.typOffset, stats];
CompareTables[
"type map table", @Mob1.tmOffset, @Mob2.tmOffset, stats];
CompareTables[
"frame pack table", @Mob1.fpOffset, @Mob2.fpOffset, stats];
IF Mob1.extended
AND Mob2.extended
THEN {
CompareTables[
"link fragment table", @Mob1.lfOffset, @Mob2.lfOffset, stats, TRUE];
CompareTables[
"ref literal fragment table", @Mob1.rfOffset, @Mob2.rfOffset, stats, TRUE];
CompareTables[
"type fragment table", @Mob1.tfOffset, @Mob2.tfOffset, stats, TRUE];
CompareInts[
"In rtPages\n", Mob1.rtOffset.units, Mob2.rtOffset.units, stats]};
IF stats.debug
THEN {
(stats.out).PutRope["** Segments for file 1\n"];
SegmentsOut[rope1, Mob1, stats];
(stats.out).PutRope["** Segments for file 2\n"];
SegmentsOut[rope2, Mob2, stats]};
IF stats.debug
THEN {
(stats.out).PutRope["** Files for file 1\n"];
FilesOut[rope1, Mob1, stats];
(stats.out).PutRope["** Files for file 2\n"];
FilesOut[rope2, Mob2, stats]};
{
-- compare the code in the various modules
mti1: CARD ¬ LOOPHOLE[FIRST[MobDefs.MTIndex], CARD]+Mob1.mtOffset.units;
mti2: CARD ¬ LOOPHOLE[FIRST[MobDefs.MTIndex], CARD]+Mob2.mtOffset.units;
FOR i:
NAT
IN [0..
MIN[Mob1.nModules,Mob2.nModules])
DO
mtr1: MobDefs.MTRecord;
mtr2: MobDefs.MTRecord;
sgr1: MobDefs.SGRecord;
sgr2: MobDefs.SGRecord;
nw1, nw2, sgi1, sgi2: CARD;
byteOff1,byteOff2: INT;
sb1,sb2: INT;
GetWordsToPtr[rope1, mti1, SIZE[MobDefs.MTRecord], @mtr1];
GetWordsToPtr[rope2, mti2, SIZE[MobDefs.MTRecord], @mtr2];
nw1 ¬ SIZE[MobDefs.MTRecord];
nw2 ¬ SIZE[MobDefs.MTRecord];
IF stats.doCode
OR stats.doAll
THEN {
Compare the code portions of this module.
First, get the proper SGRecords for the code
sgi1 ¬ Mob1.sgOffset.units + LOOPHOLE[mtr1.code.sgi, CARD];
sgi2 ¬ Mob2.sgOffset.units + LOOPHOLE[mtr2.code.sgi, CARD];
GetWordsToPtr[rope1, sgi1, SIZE[MobDefs.SGRecord], @sgr1];
GetWordsToPtr[rope2, sgi2, SIZE[MobDefs.SGRecord], @sgr2];
sb1 ¬ sgr1.base.units;
sb2 ¬ sgr2.base.units;
byteOff1 ¬ (mtr1.code.offset+sb1)*bytesPerUnit;
byteOff2 ¬ (mtr2.code.offset+sb2)*bytesPerUnit;
SELECT
TRUE
FROM
mtr1.code.length = 0
AND mtr2.code.length = 0 =>
(stats.out).PutRope["No code.\n"];
mtr1.code.length = 0 =>
(stats.out).PutF1[
"No code for file 1, %g bytes for file 2.\n",
[integer[mtr2.code.length]]];
mtr1.code.length = 0 =>
(stats.out).PutF1[
"No code for file 2, %g bytes for file 1.\n",
[integer[mtr1.code.length]]];
ENDCASE =>
Finally, compare the code
CompareBytes[
IO.PutFR[
"In code for %g (module %g)\n",
[rope[GetName[rope1, Mob1.ssOffset.units, mtr1.name]]],
[integer[i]]],
byteOff1, byteOff2, MIN[mtr1.code.length, mtr2.code.length], stats];
};
IF stats.doSymbols
OR stats.doAll
THEN {
Compare the symbol portions of this module.
First, get the proper SGRecords for the symbols
sgi1 ¬ Mob1.sgOffset.units + LOOPHOLE[mtr1.sseg, CARD];
sgi2 ¬ Mob2.sgOffset.units + LOOPHOLE[mtr2.sseg, CARD];
GetWordsToPtr[rope1, sgi1, SIZE[MobDefs.SGRecord], @sgr1];
GetWordsToPtr[rope2, sgi2, SIZE[MobDefs.SGRecord], @sgr2];
sb1 ¬ sgr1.base.units;
sb2 ¬ sgr2.base.units;
Set the symbol offset in stats for use by Diagnose
stats.symOff1 ¬ sb1;
stats.symOff2 ¬ sb2;
Compare the basic symbols
CompareWords[
IO.PutFR[
"In basic symbols for %g (module %g)\n",
[rope[GetName[rope1, Mob1.ssOffset.units, mtr1.name]]], [integer[i]]],
sb1, sb2, MIN[sgr1.units.units, sgr2.units.units], stats];
Compare the extended symbols
stats.symOff1 ¬ stats.symOff2 ¬ 0; -- inhibit Diagnose
CompareWords[
IO.PutFR[
"In extended symbols for %g (module %g)\n",
[rope[GetName[rope1, Mob1.ssOffset.units, mtr1.name]]],
[integer[i]]],
sb1+sgr1.units.units,
sb2+sgr2.units.units,
MIN[sgr1.extraUnits.units, sgr2.extraUnits.units],
stats
];
};
mti1 ¬ mti1 + nw1;
mti2 ¬ mti2 + nw2;
ENDLOOP;
};
IF stats.debug
THEN {
stats.maxTabLim1 ¬ stats.maxTabLim2 ¬ SIZE[Mob];
CompareWords[
"In whole file\n",
stats.maxTabLim1, stats.maxTabLim2,
MIN[len/bytesPerUnit-stats.maxTabLim1, len/bytesPerUnit-stats.maxTabLim2],
stats];
};
SELECT stats.errors
FROM
0 => {};
1 => ERROR GiveUp["Too bad, only one little difference."];
ENDCASE =>
ERROR GiveUp[
IO.PutFR1["%g differences encountered.", [integer[stats.errors]]]];
};
CompareWords:
PROC
[name: ROPE, offset1,offset2: INT, nWords: INT, stats: Stats] = TRUSTED {
r1: ROPE = (stats.rope1).Substr[0, (offset1+nWords)*bytesPerUnit];
lim1: INT = r1.Length[];
r2: ROPE = (stats.rope2).Substr[0, (offset2+nWords)*bytesPerUnit];
lim2: INT = r2.Length[];
sth1,sth2: SymbolTableHeader ¬ NIL;
off1: INT ¬ offset1*bytesPerUnit;
off2: INT ¬ offset2*bytesPerUnit;
IF stats.debug
THEN
(stats.out).PutFL[
"** %g CompareWords[offset1: %g, offset2: %g, nWords: %g]\n",
LIST[[rope[name]], [integer[offset1]], [integer[offset2]], [integer[nWords]]]];
WHILE off1 < lim1
AND off2 < lim2
DO
nc: INT = r1.Run[off1, r2, off2];
nOff1: INT ¬ off1+nc;
nOff2: INT ¬ off2+nc;
nwOff1,nwOff2: INT;
w1,w2: WORD;
f1,f2: ROPE;
which1,which2: ROPE ¬ NIL;
IF nOff1 >= lim1 OR nOff2 >= lim2 THEN EXIT;
IF name # NIL THEN {(stats.out).PutRope[name]; name ¬ NIL};
nwOff1 ¬ nOff1/bytesPerUnit;
nwOff2 ¬ nOff2/bytesPerUnit;
f1 ¬ r1.Flatten[nOff1 ¬ nwOff1*bytesPerUnit, bytesPerUnit];
w1 ¬ (LOOPHOLE[f1, WordPtr]+SIZE[TEXT]);
f2 ¬ r2.Flatten[nOff2 ¬ nwOff2*bytesPerUnit, bytesPerUnit];
w2 ¬ (LOOPHOLE[f2, WordPtr]+SIZE[TEXT]);
IF nOff1 = nOff2 THEN (stats.out).PutF1[" at word offset %g", [integer[nwOff1]]]
ELSE (stats.out).PutF[
" at word offsets (%g, %g)", [integer[nwOff1]], [integer[nwOff2]]];
(stats.out).PutFL[
", %b # %b (\"%q\" # \"%q\")\n",
LIST[[cardinal[w1]], [cardinal[w2]], [rope[f1]], [rope[f2]]]];
IF stats.symOff1 > 0
THEN {
IF sth1 =
NIL
THEN {
sth1 ¬ NEW[SymbolSegment.STHeader];
GetWordsToPtr[
stats.rope1, stats.symOff1, SIZE[SymbolSegment.STHeader], LOOPHOLE[sth1]]
};
Try to determine which block it is in
which1 ¬ Diagnose[stats.rope1, sth1, offset1, nwOff1];
(stats.out).PutRope[which1];
(stats.out).PutRope["\n"]};
IF stats.symOff2 > 0
THEN {
IF sth2 =
NIL
THEN {
sth2 ¬ NEW[SymbolSegment.STHeader];
GetWordsToPtr[
stats.rope2, stats.symOff2, SIZE[SymbolSegment.STHeader], LOOPHOLE[sth2]];
};
Try to determine which block it is in
which2 ¬ Diagnose[stats.rope2, sth2, offset2, nwOff2];
IF
NOT which1.Equal[which2]
THEN {
Different diagnoses for the two files!
(stats.out).PutRope[" (Mob1)\n"];
(stats.out).PutRope[which2];
(stats.out).PutRope[" (Mob2)\n"]};
};
IF (stats.errors ¬ stats.errors + 1) > stats.maxErrors
THEN {
ERROR GiveUp["Too many differences encountered."]};
off1 ¬ nOff1 + bytesPerUnit;
off2 ¬ nOff2 + bytesPerUnit;
ENDLOOP;
};
CompareTables:
PROC
[name: ROPE, ptr1, ptr2: LONG POINTER, stats: Stats, rt: BOOL ¬ FALSE] = TRUSTED {
src1: WordPtr ¬ LOOPHOLE[ptr1, WordPtr];
targetBitsPerUnit: CARD ¬ LOOPHOLE[ptr1, MobPtr].format.bitsPerUnit[0];
targetBytesPerUnit: CARD ¬ targetBitsPerUnit/BITS[BYTE];
offset1: CARD ¬ (LOOPHOLE[src1, WordPtr] * targetBytesPerUnit)/BYTES[UNIT];
len1: CARD = (src1+SIZE[MobDefs.MobOffset]);
lim1: CARD = len1+offset1;
src2: WordPtr ¬ LOOPHOLE[ptr2, WordPtr];
offset2: CARD ¬ src2;
len2: CARD = (src2+SIZE[MobDefs.MobOffset]);
lim2: CARD = len2+offset2;
nWords: CARD = MIN[lim1, lim2];
oldErrors: CARDINAL;
rtOff1,rtOff2: INT ¬ 0;
IF stats.debug
THEN {
(stats.out).PutFL[
" %g, range1 = [%g, %g), range2 = [%g, %g).\n",
LIST[[rope[name]], [integer[offset1]], [integer[lim1]], [integer[offset2]], [integer[lim2]]]];
};
stats.maxTabLim1 ¬ MAX[stats.maxTabLim1, lim1];
stats.maxTabLim2 ¬ MAX[stats.maxTabLim2, lim2];
IF offset1 # offset2
THEN {
(stats.out).PutF[
"Offsets for %g not equal, %g # %g\n",
[rope[name]], [cardinal[offset1]], [cardinal[offset2]]];
IF (stats.errors ¬ stats.errors + 1) > stats.maxErrors
THEN {
ERROR GiveUp["Too many differences encountered."]};
};
IF len1 # len2
THEN {
(stats.out).PutF[
"Lengths for %g not equal, %g # %g\n",
[rope[name]], [cardinal[len1]], [cardinal[len2]]];
IF (stats.errors ¬ stats.errors + 1) > stats.maxErrors
THEN {
ERROR GiveUp["Too many differences encountered."]};
};
oldErrors ¬ stats.errors;
IF rt
THEN {
This table should be interpreted relative to the RTMob extension
rtOff1 ¬ LOOPHOLE[stats.base1, MobPtr].rtOffset.units;
rtOff2 ¬ LOOPHOLE[stats.base2, MobPtr].rtOffset.units};
Now compare the words within the table.
CompareWords[
Rope.Cat["In ", name, "\n"],
rtOff1+offset1, rtOff2+offset2, MIN[len1, len2], stats
! GiveUp => {
stats.errors ¬ oldErrors+1;
(stats.out).PutRope["... too many differences for this table.\n"];
CONTINUE}];
};