; IfsDirCompareRecords.asm ; Copyright Xerox Corporation 1981 ; Last modified May 3, 1981 1:07 PM by Taft .ent CompareRecords .bext IFSError ; The following must agree with the DR structure in IfsDirs.decl. DR.header = 0. DR.pathName = 6. drHeaderMask = 171600 .dmr GetNextChar = 66400 .srel CompareRecords: .CompareRecords .nrel ; CompareRecords(r1, r2) ; Compares two B-Tree records in the same manner as DirCompareKey. ; This differs from DirCompareKey in that it compares two records ; rather than a key and a record. ; Note: this procedure is not reentrant. .CompareRecords: sta 3 1 2 sta 0 2 2 ; r1 sta 1 3 2 ; r2 ; Find position of last "!" in r1. mov 0 3 ; r1 lda 0 DR.header 3 ; minimal check that this is really a DR lda 1 cdrHeaderMask and# 0 1 szr jmp BadDR lda 0 DR.pathName 3 ; extract string length lda 1 c177400 ands 1 0 sta 0 lenVerString ; save temporarily lda 1 cDR.pathName add 3 1 ; address of string in record lda 3 csdR1 snz 3 3 ; CSD pointers already set up? jsr SetupCSDs ; no, do so first sta 1 1 3 ; save string address FindLastExcl: jsr @363 ; load ac0'th byte from array pointed to ; by ac1, and return byte in ac1. ; does not clobber ac0! lda 3 cExcl sne 1 3 jmp FoundExcl neg 0 0 ; decrement string index com 0 0 lda 3 csdR1 lda 1 1 3 jmp FindLastExcl ; CompareRecords (cont'd) ; Set up CSD for r1 FoundExcl: lda 1 lenVerString ; compute length of version string sub 0 1 ; = entire string length - position of "!" sta 1 lenVerString subzr 1 1 ; 100000B add 1 0 ; begin at right-hand byte sta 0 @csdR1 ; Set up CSD for r2 lda 3 3 2 ; r2 lda 0 DR.header 3 ; minimal check that this is really a DR lda 1 cdrHeaderMask and# 0 1 szr jmp BadDR lda 0 DR.pathName 3 ; extract string length lda 1 c177400 ands 1 0 subzr 1 1 ; 100000B add 1 0 ; begin at right-hand byte lda 1 cDR.pathName add 3 1 ; address of string in record lda 3 csdR2 sta 0 0 3 sta 1 1 3 ; Compare characters in the "<dir>name!" portion CompareBodyLoop: lda 0 csdR1 GetNextChar 140 ; get char from r1, convert to upper case jmp R1Exhausted mov 1 3 lda 0 csdR2 GetNextChar 140 ; get char from r2, convert to upper case jmp RetGr ; exhausted: r1 is greater than r2 sne 1 3 jmp CompareBodyLoop ; equal, continue comparing ; First mismatch. If all remaining characters of r2 are digits ; then r2's body is an initial substring of r1 and we declare ; r1 to be greater. Otherwise we return the result of comparing ; the mismatching character codes. Note that the only possible effect ; of looking at the rest of r2 is to return "greater" where we ; otherwise would return "less". But if r1's char > r2's char anyway, then ; just say so now without bothering to check. slt 3 1 jmp RetGr CheckDigitsLoop: lda 0 cDigit0 ; r2 char a digit? sub 0 1 lda 0 d10 sltu 1 0 jmp RetLs ; no, r1 is less than r2 lda 0 csdR2 GetNextChar 0 ; get next char from r2 jmp RetGr ; exhausted: r1 is greater than r2 jmp CheckDigitsLoop ; Still inside CompareRecords; this stuff is here for addressing reasons. ; Internal procedure to set up csdR1 and csdR2. ; Returns with AC3 = csdR1. ; Does not disturb other ACs. SetupCSDs: sta 3 csdBlk jsr AfterCSDs csdBlk: .blk 5 AfterCSDs: skeven 3 3 ; force CSDs to be even inc 3 3 sta 3 csdR2 inc 3 3 inc 3 3 sta 3 csdR1 jmp @csdBlk csdR1: .blk 1 csdR2: .blk 1 lenVerString: .blk 1 c177400: 177400 cDigit0: 60 d10: 10. cDR.pathName: DR.pathName cExcl: 41 ; "!" BadDR1: lda 3 2 2 BadDR: sta 3 lenVerString lda 0 2 2 lda 1 3 2 jsr @370 6 77400 lda 0 .ecMalformedDR lda 1 lenVerString jsrii lvIFSError ; IFSError(ecMalformedDR, record) 2 cdrHeaderMask: drHeaderMask .ecMalformedDR: 36. lvIFSError: IFSError ; CompareRecords (cont'd) ; r1 is exhausted before r2: bodies seem to match. ; Now parse the version strings and compare them numerically. ; It must be possible to parse r1's version; if not, the record is malformed. ; If a non-digit is encountered in r2 then r1's body is an initial substring ; of r2 and is therefore "less". R1Exhausted: lda 0 @csdR1 ; get r1 byte flag (count is zero) lda 1 lenVerString ; merge with length of version string add 1 0 sta 0 @csdR1 mkzero 3 3 ; init parsed version ParseV1Loop: lda 0 csdR1 GetNextChar 0 ; get next char from r1 jmp V1Exhausted ; exhausted: go begin work on v2 lda 0 cDigit0 ; char a digit? sub 0 1 lda 0 d10 sltu 1 0 jmp BadDR1 ; no, r1 is malformed mov 3 0 ; yes, multiply parsed version by 10 addzl 3 3 addzl 0 3 add 1 3 ; add in new digit jmp ParseV1Loop V1Exhausted: sta 3 lenVerString ; store r1's version here temporarily mkzero 3 3 ; init parsed version ParseV2Loop: lda 0 csdR2 GetNextChar 0 ; get next char from r2 jmp V2Exhausted ; exhausted: go compare version numbers lda 0 cDigit0 ; char a digit? sub 0 1 lda 0 d10 sltu 1 0 jmp RetLs ; no, r1 is less than r2 mov 3 0 ; yes, multiply parsed version by 10 addzl 3 3 addzl 0 3 add 1 3 ; add in new digit jmp ParseV2Loop ; Reached end of version number. Compare versions. V2Exhausted: lda 0 lenVerString ; r1's version sne 0 3 jmp RetEq sltu 0 3 RetGr: mkone 0 0 skp ; r1 > r2, return 1 RetLs: mkminusone 0 0 ; r1 < r2, return -1 lda 3 1 2 jmp 1 3 RetEq: mkzero 0 0 ; r1 = r2, return 0 lda 3 1 2 jmp 1 3 .end // The following procedure is equivalent to the one in this module: //--------------------------------------------------------------------------- let CompareRecords(r1, r2) = valof //--------------------------------------------------------------------------- // Compares two B-Tree records in the same manner as DirCompareKey. // This differs from DirCompareKey in that it compares two records // rather than a key and a record. [ if (r1>>DR.header & drHeaderMask) ne 0 then IFSError(ecMalformedDR, r1) if (r2>>DR.header & drHeaderMask) ne 0 then IFSError(ecMalformedDR, r2) // Find position of last "!" in first record let lenBodyString = nil for i = r1>>DR.pathName.length to 1 by -1 do if r1>>DR.pathName.char↑i eq $! then [ lenBodyString = i; break ] // Compare chars in the "<dir>name!" (string) portion let lenR2 = r2>>DR.pathName.length for i = 1 to lenBodyString do [ // If we run off the end of r2 then r1 is greater. if i gr lenR2 resultis 1 let c1 = r1>>DR.pathName.char↑i let c2 = r2>>DR.pathName.char↑i if c1 ne c2 then [ // Lower-case alphabetics collate with upper-case if c1 ge $a & c1 le $z then c1 = c1-($a-$A) if c2 ge $a & c2 le $z then c2 = c2-($a-$A) if c1 ne c2 then [ // Definitely a mismatch. If all remaining characters of r2 // are digits then r2's body is an initial substring // of r1 and we declare r1 to be greater. Otherwise we // return the result of comparing the mismatching character codes. // Note that the only possible effect of looking at the rest of r2 // is to return "greater" where we otherwise would return // "less". But if r1's char > r2's char anyway, then just say so now // without bothering to check. if c1 ls c2 then for j = i to lenR2 do [ let digit = r2>>DR.pathName.char↑j - $0 if digit ls 0 % digit gr 9 resultis -1 ] resultis 1 ] ] ] // Bodies equal, now parse the version strings and compare them numerically. // It must be possible to parse r1's version; if not, the record is malformed. // If a non-digit is encountered in r2 then r1's body is an initial substring // of r2 and we return "less than" let v1 = 0 for i = lenBodyString+1 to r1>>DR.pathName.length do [ let digit = r1>>DR.pathName.char↑i - $0 if digit ls 0 % digit gr 9 then IFSError(ecMalformedDR, r1) v1 = 10*v1+digit ] let v2 = 0 for i = lenBodyString+1 to lenR2 do [ let digit = r2>>DR.pathName.char↑i - $0 if digit ls 0 % digit gr 9 resultis -1 //non-digit encountered v2 = 10*v2+digit ] resultis Usc(v1, v2) ]