/* * File: rcomp.c * Contents: anycmp, equiv, lexcmp, numcmp */ #include "..\h\config.h" #include "..\h\rt.h" #include "rproto.h" /* * anycmp - compare any two objects. */ int anycmp(dp1,dp2) dptr dp1, dp2; { register int o1, o2; register long lresult; double rres1, rres2, rresult; /* * Get a collating number for dp1 and dp2. */ o1 = order(dp1); o2 = order(dp2); /* * If dp1 and dp2 aren't of the same type, compare their collating numbers. */ if (o1 != o2) return (o1 > o2 ? Greater : Less); if (o1 == 3) /* * dp1 and dp2 are strings, use lexcmp to compare them. */ return lexcmp(dp1,dp2); switch (Type(*dp1)) { case T_Integer: lresult = IntVal(*dp1) - IntVal(*dp2); if (lresult == 0) return Equal; return ((lresult > 0) ? Greater : Less); #ifdef LargeInts case T_Bignum: lresult = bigcmp(dp1, dp2); if (lresult == 0) return Equal; return ((lresult > 0) ? Greater : Less); #endif /* LargeInts */ case T_Real: GetReal(dp1,rres1); GetReal(dp2,rres2); rresult = rres1 - rres2; if (rresult == 0.0) return Equal; return ((rresult > 0.0) ? Greater : Less); case T_Null: return Equal; case T_Cset: return csetcmp((unsigned int *)((struct b_cset *)BlkLoc(*dp1))->bits, (unsigned int *)((struct b_cset *)BlkLoc(*dp2))->bits); case T_File: case T_Proc: case T_List: case T_Table: case T_Set: case T_Record: case T_Coexpr: case T_External: /* * Collate these values according to the relative positions of * their blocks in the heap. */ lresult = ((long)BlkLoc(*dp1) - (long)BlkLoc(*dp2)); if (lresult == 0) return Equal; return ((lresult > 0) ? Greater : Less); default: syserr("anycmp: unknown datatype."); } } /* * order(x) - return collating number for object x. */ int order(dp) dptr dp; { if (Qual(*dp)) return 3; /* string */ switch (Type(*dp)) { case T_Null: return 0; case T_Integer: return 1; #ifdef LargeInts case T_Bignum: return 1; #endif /* LargeInts */ case T_Real: return 2; case T_Cset: return 4; case T_Coexpr: return 5; case T_File: return 6; case T_Proc: return 7; case T_List: return 8; case T_Table: return 9; case T_Set: return 10; case T_Record: return 11; case T_External: return 12; default: syserr("order: unknown datatype."); } } /* * equiv - test equivalence of two objects. */ int equiv(dp1, dp2) dptr dp1, dp2; { register int result; register word i; register char *s1, *s2; double rres1, rres2; result = 0; /* * If the descriptors are identical, the objects are equivalent. */ if (EqlDesc(*dp1,*dp2)) result = 1; else if (Qual(*dp1) && Qual(*dp2)) { /* * If both are strings of equal length, compare their characters. */ if ((i = StrLen(*dp1)) == StrLen(*dp2)) { s1 = StrLoc(*dp1); s2 = StrLoc(*dp2); result = 1; while (i--) if (*s1++ != *s2++) { result = 0; break; } } } else if (dp1->dword == dp2->dword) switch (Type(*dp1)) { /* * For integers and reals, just compare the values. */ case T_Integer: result = (IntVal(*dp1) == IntVal(*dp2)); break; #ifdef LargeInts case T_Bignum: result = (bigcmp(dp1, dp2) == 0); break; #endif /* LargeInts */ case T_Real: GetReal(dp1, rres1); GetReal(dp2, rres2); result = (rres1 == rres2); break; case T_Cset: /* * Compare the bit arrays of the csets. */ result = 1; for (i = 0; i < CsetSize; i++) if (BlkLoc(*dp1)->cset.bits[i] != BlkLoc(*dp2)->cset.bits[i]) { result = 0; break; } } else /* * dp1 and dp2 are of different types, so they can't be * equivalent. */ result = 0; return result; } /* * lexcmp - lexically compare two strings. */ int lexcmp(dp1, dp2) dptr dp1, dp2; { register char *s1, *s2; register word minlen; word l1, l2; /* * Get length and starting address of both strings. */ l1 = StrLen(*dp1); s1 = StrLoc(*dp1); l2 = StrLen(*dp2); s2 = StrLoc(*dp2); /* * Set minlen to length of the shorter string. */ minlen = Min(l1, l2); /* * Compare as many bytes as are in the smaller string. If an * inequality is found, compare the differing bytes. */ while (minlen--) if (*s1++ != *s2++) return (ToAscii(*--s1 & 0377) > ToAscii(*--s2 & 0377) ? Greater : Less); /* * The strings compared equal for the length of the shorter. */ if (l1 == l2) return Equal; else if (l1 > l2) return Greater; else return Less; } /* * numcmp - compare two numbers. Returns -1, 0, 1 for dp1 <, =, > dp2. * dp3 is made into a descriptor for the return value. */ int numcmp(dp1, dp2, dp3) dptr dp1, dp2, dp3; { int t1, t2; double r1, r2; /* * Be sure that both dp1 and dp2 are numeric. */ if ((t1 = cvnum(dp1)) == CvtFail) RetError(102, *dp1); if ((t2 = cvnum(dp2)) == CvtFail) RetError(102, *dp2); if (t1 == T_Integer && t2 == T_Integer) { /* * dp1 and dp2 are both integers, compare them and * create an integer descriptor in dp3 */ *dp3 = *dp2; if (IntVal(*dp1) == IntVal(*dp2)) return Equal; return ((IntVal(*dp1) > IntVal(*dp2)) ? Greater : Less); } else if (t1 == T_Real || t2 == T_Real) { /* * Either dp1 or dp2 is real. Convert the other to a real, * compare them and create a real descriptor in dp3. */ if (t1 != T_Real) { #ifdef LargeInts if (t1 == T_Bignum) r1 = bigtoreal(dp1); else #endif /* LargeInts */ r1 = IntVal(*dp1); } else r1 = BlkLoc(*dp1)->realblk.realval; if (t2 != T_Real) { #ifdef LargeInts if (t2 == T_Bignum) r2 = bigtoreal(dp2); else #endif /* LargeInts */ r2 = IntVal(*dp2); } else r2 = BlkLoc(*dp2)->realblk.realval; if (makereal(r2, dp3) == Error) return Error; if (r1 == r2) return Equal; return ((r1 > r2) ? Greater : Less); } #ifdef LargeInts else { int result; *dp3 = *dp2; result = bigcmp(dp1, dp2); if (result == 0) return Equal; return ((result > 0) ? Greater : Less); } #endif /* LargeInts */ } /* * csetcmp - compare two cset bit arrays. * The order defined by this function is identical to the lexical order of * the two strings that the csets would be converted into. */ int csetcmp(cs1, cs2) unsigned int *cs1, *cs2; { unsigned int nbit, mask, *cs_end; if (cs1 == cs2) return Equal; /* * The longest common prefix of the two bit arrays converts to some * common prefix string. The first bit on which the csets disagree is * the first character of the conversion strings that disagree, and so this * is the character on which the order is determined. The cset that has * this first non-common bit = one, has in that position the lowest * character, so this cset is lexically least iff the other cset has some * following bit set. If the other cset has no bits set after the first * point of disagreement, then it is a prefix of the other, and is therefor * lexically less. * * Find the first word where cs1 and cs2 are different. */ for (cs_end = cs1 + CsetSize; cs1 < cs_end; cs1++, cs2++) if (*cs1 != *cs2) { /* * Let n be the position at which the bits first differ within * the word. Set nbit to some integer for which the nth bit * is the first bit in the word that is one. Note here and in the * following, that bits go from right to left within a word, so * the _first_ bit is the _rightmost_ bit. */ nbit = *cs1 ^ *cs2; /* Set mask to an integer that has all zeros in bit positions * upto and including position n, and all ones in bit positions * _after_ bit position n. */ for (mask = (unsigned)MaxLong << 1; !(~mask & nbit); mask <<= 1); /* * nbit & ~mask contains zeros everywhere except position n, which * is a one, so *cs2 & (nbit & ~mask) is non-zero iff the nth bit * of *cs2 is one. */ if (*cs2 & (nbit & ~mask)) { /* * If there are bits set in cs1 after bit position n in the * current word, then cs1 is lexically greater than cs2. */ if (*cs1 & mask) return Greater; while (++cs1 < cs_end) if (*cs1) return Greater; /* * Otherwise cs1 is a proper prefix of cs2 and is therefore * lexically less. */ return Less; } /* * If the nth bit of *cs2 isn't one, then the nth bit of cs1 * must be one. Just reverse the logic for the previous * case. */ if (*cs2 & mask) return Less; cs_end = cs2 + (cs_end - cs1); while (++cs2 < cs_end) if (*cs2) return Less; return Greater; } return Equal; }