archie/prospero/user/menu/comp.c
2024-05-27 16:13:40 +02:00

232 lines
6.1 KiB
C

/*
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-copyr.h>.
*
* The menu API and client were written by Kwynn Buess (buess@isi.edu)
*/
#include <usc-copyr.h>
#include <pfs.h>
int compare_collation_ord(VLINK v1,VLINK v2) {
struct pattrib *get_high_coll_ord(PATTRIB);
PATTRIB coll1 = get_high_coll_ord(v1->lattrib);
PATTRIB coll2 = get_high_coll_ord(v2->lattrib);
int temp;
int compare_name(VLINK,VLINK);
struct token *seq_1;
struct token *seq_2;
/* Excluding ASCII and "LAST" (not implemented yet), there are three
possible states for each link -- NO-COLL-ATTRIB, LAST, or what I'll
call "first" (i.e. not LAST). There are three states for each of the
two links, so there are six possible combinations. Here is a table of
them. I have represented NO-COLLATION-ATTRIBUTE with "___",
LAST with 'L', and "first" with 'F'.
Possible combinations of COLLATION-ATTRIBUTES for two links
1: ___ ___
2: L ___
3: F ___
4: L F
5: L L
6: F F
*/
if ((coll1 == NULL) && (coll2 == NULL)) return compare_name(v1,v2);
/* there goes case #1 */
if (coll1 == NULL) return
(!strcmp(coll2->value.sequence->token,"LAST")) ? 1 : -1;
if (coll2 == NULL) return
(!strcmp(coll1->value.sequence->token,"LAST")) ? -1 : 1;
/* there go #2 and #3 */
/* Now we no that neither of the collation pointers are NULL. */
seq_1 = coll1->value.sequence;
seq_2 = coll2->value.sequence;
/* Now there's the degenerate case of a non-NULL COLL-ATTRIB with a
NULL value.sequence. The spec says that this should be treated just
like a NULL COLL-ATTRIB.
Now we repeat the above performance, replacing "coll"'s with "seq"'s
*/
if ((seq_1 == NULL) && (seq_2 == NULL)) return compare_name(v1,v2);
if (seq_1 == NULL) return
(!strcmp(seq_2->token,"LAST")) ? 1 : -1;
if (seq_2 == NULL) return
(!strcmp(seq_1->token,"LAST")) ? -1 : 1;
/* This code determines if EITHER the COLL-ATTRIBS are BOTH "FIRST"
or both "LAST". If not, then one of them is last (case #4), and
we return that as lower. Note that those are the only three
cases left.
*/
if (
(temp = (!(strcmp(seq_1->token,"LAST"))))
!= (!(strcmp(seq_2->token,"LAST")))
) return temp ? -1 : 1;
/* Now we're down to BOTH LAST's and both FIRST's. The process for
comparing these is the same. However, with LAST we must move
beyond the word "LAST" to get to "NUMERIC" or "ASCII".
So we advance the pointer.
*/
if (!strcmp(seq_1->token,"LAST")) {
seq_1 = seq_1 -> next;
seq_2 = seq_2 -> next;
/* This is the case of LAST with no arguments. If both are of type "LAST",
then they remain in the former order (1 comes before 2).
*/
if (seq_1 == NULL && seq_2 == NULL) return 1;
/* If one is "LAST" and the other is "LAST ASCII" or "LAST NUMERIC", then
the one that is "LAST" goes last;
*/
if ((temp = (seq_1 == NULL)) || (seq_2 == NULL))
temp ? -1 : 1;
}
/* Now we are down to NUMERIC or ASCII */
/* If one's ASCII and one's NUMERIC, the NUMERIC comes first */
if ((temp = (!strcmp(seq_1->token,"NUMERIC")))
!= (!strcmp(seq_1->token,"NUMERIC"))
) return temp ? 1 : -1;
/* After that we know that we have both NUMERIC or both ASCII */
/* We know that they're both NUMERIC or BOTH ASCII. Whether they're LAST
NUMERIC or LAST ASCII or "FIRST" NUMERIC and "FIRST" ASCII makes no
difference.
*/
if (!strcmp(seq_1->token,"ASCII")) {
/* Move past the word ASCII */
seq_1 = seq_1 -> next;
seq_2 = seq_2 -> next;
while((seq_1 != NULL) && (seq_2 != NULL)) {
if (temp = strcmp(seq_1->token,seq_2->token)) break;
seq_1 = seq_1 -> next;
seq_2 = seq_2 -> next;
}
if ((seq_1 == NULL) && (seq_2 == NULL))
return compare_name(v1,v2);
/* If one was NULL, the one that ends first is first */
if ((seq_1 == NULL) || (seq_2 == NULL))
return (seq_1 == NULL) ? 1: -1;
/* seq_1 and seq_2 were both non-NULL and non-equal. Determine
the inequality and return. */
return ((temp < 0) ? 1:-1);
}
/* We now assume that only NUMERIC is left. If this isn't the case,
something's very wrong. Perhaps the attribute is malformed */
/* Move past the word NUMERIC */
seq_1 = seq_1 -> next;
seq_2 = seq_2 -> next;
/* Compare numbers until there are no more or they are unequal */
while ((seq_1 != NULL) && (seq_2 != NULL)) {
if (!((atoi(seq_1->token) == atoi(seq_2->token)))) break;
seq_1 = seq_1 -> next;
seq_2 = seq_2 -> next;
}
if ((seq_1 == NULL) && (seq_2 == NULL))
return compare_name(v1,v2);
/* If one was NULL, the one that ends first is first */
if ((seq_1 == NULL) || (seq_2 == NULL))
return (seq_1 == NULL) ? 1: -1;
/* If the loop above ended due to an inequality, determine it. */
return (atoi(seq_1->token) > atoi(seq_2->token)) ? -1: 1;
}
PATTRIB get_high_coll_ord(PATTRIB head) {
int compare_precedence(char,char);
PATTRIB temp = head;
PATTRIB highest = NULL;
while (temp != NULL) {
if (!strcmp(temp->aname,"COLLATION-ORDER")) {
if (highest == NULL) highest = temp;
else if
(compare_precedence(highest->precedence,temp->precedence) == -1)
highest = temp;
}
temp = temp->next;
}
return highest;
}
int compare_name(VLINK a,VLINK b) {
int cnt;
for (cnt=0;
((a->name[cnt]) == (b->name[cnt]))
&& (a->name[cnt] != '\0') && (b->name[cnt] != '\0');
cnt++) /* NULL loop body */
;
return (b->name[cnt] < a->name[cnt]) ? -1:1;
}
int compare_precedence(char p1,char p2) {
if (p1 == ATR_PREC_LINK ) return 1;
if (p2 == ATR_PREC_LINK ) return -1;
if (p1 == ATR_PREC_REPLACE) return 1;
if (p2 == ATR_PREC_REPLACE) return -1;
if (p1 == ATR_PREC_OBJECT ) return 1;
if (p2 == ATR_PREC_OBJECT ) return -1;
if (p1 == ATR_PREC_CACHED ) return 1;
if (p2 == ATR_PREC_CACHED ) return -1;
if (p1 == ATR_PREC_ADD ) return 1;
if (p2 == ATR_PREC_ADD ) return -1;
return 1;
}