Initial revision


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@2 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/libasn1fix/asn1fix_compat.c b/libasn1fix/asn1fix_compat.c
new file mode 100644
index 0000000..aef26c0
--- /dev/null
+++ b/libasn1fix/asn1fix_compat.c
@@ -0,0 +1,132 @@
+#include "asn1fix_internal.h"
+
+static int asn1f_check_same_children(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b);
+
+/*
+ * Check that the expressions given are compatible in their type.
+ * ORDER DOES MATTER! (See .h).
+ */
+int
+asn1f_check_type_compatibility(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
+	asn1p_expr_type_e atype, btype;
+
+	atype = a->expr_type;
+	btype = b->expr_type;
+
+	DEBUG("%s(%s:%x@%d, %s:%x@%d)", __func__,
+		a->Identifier, atype, a->_lineno,
+		b->Identifier, btype, b->_lineno);
+
+	/*
+	 * Expected terminal type!
+	 */
+	assert(atype != A1TC_REFERENCE);
+	assert(btype != A1TC_REFERENCE);
+
+	if(atype != btype) {
+		/*
+		 * Limited compatibility.
+		 */
+		if((atype == A1TC_UNIVERVAL && btype == ASN_BASIC_INTEGER)
+		|| (atype == A1TC_UNIVERVAL && btype == ASN_BASIC_ENUMERATED)
+		)
+			return 0;
+		DEBUG("\t%s and %s are not compatible",
+			a->Identifier, b->Identifier);
+		return -1;	/* Fairly obviously */
+	}
+
+	if(a == b)
+		return 0;	/* Fairly obviously */
+
+	switch(atype) {
+	case ASN_BASIC_INTEGER:
+		/* All integers are compatible */
+		return 0;
+	case ASN_BASIC_ENUMERATED:
+		/*
+		 * Enumerations are not compatible
+		 * unless their definitions are the same.
+		 */
+		if(asn1f_check_same_children(arg, a, b)) {
+			DEBUG("\tEnumerations are different %s and %s",
+				a->Identifier, b->Identifier);
+			return -1;
+		}
+		return 0;
+	default:
+		/* Compatibility is not defined yet */
+		DEBUG("\tCompatibility rule is not defined for %s and %s",
+			a->Identifier, b->Identifier);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Check that the children are exactly same.
+ */
+static int
+asn1f_check_same_children(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
+	asn1p_expr_t *achild;
+	asn1p_expr_t *bchild;
+
+	achild = TQ_FIRST(&(a->members));
+	bchild = TQ_FIRST(&(b->members));
+
+	while(1) {
+		if(achild->expr_type != bchild->expr_type)
+			return -1;
+
+		if(achild->Identifier && bchild->Identifier) {
+			if(strcmp(achild->Identifier, bchild->Identifier))
+				return -1;
+		} else if(!(!achild->Identifier && !bchild->Identifier)) {
+			return -1;
+		}
+
+		if(achild->value && bchild->value) {
+			if(achild->value->type != bchild->value->type)
+				return -1;
+			switch(achild->value->type) {
+			case ATV_INTEGER:
+				if(achild->value->value.v_integer
+				!= bchild->value->value.v_integer)
+					return -1;
+				break;
+			case ATV_REFERENCED:
+			default:
+				DEBUG("Value %s at lines %d and "
+					"%d cannot be used in "
+					"semantical equality check",
+					asn1f_printable_value(achild->value),
+					achild->value->value.reference->_lineno,
+					bchild->value->value.reference->_lineno
+				);
+				return -1;
+			}
+		} else if(!(!achild->value && !bchild->value)) {
+			/* One of values is defined, and another is not */
+			return -1;
+		}
+
+		achild = TQ_NEXT(achild, next);
+		bchild = TQ_NEXT(bchild, next);
+
+		if(achild && bchild)
+			continue;
+		else if(!achild && !bchild)
+			break;
+		else
+			return -1;
+	}
+
+	DEBUG("\t%s:%x@%d and %s:%x@%d are semantically equivalent",
+		a->Identifier, a->expr_type, a->_lineno,
+		b->Identifier, b->expr_type, b->_lineno);
+
+	return 0;
+}
+
+