upgrade: PER related changes

diff --git a/libasn1fix/asn1fix_constr.c b/libasn1fix/asn1fix_constr.c
index 7adbcac..ea2fcf1 100644
--- a/libasn1fix/asn1fix_constr.c
+++ b/libasn1fix/asn1fix_constr.c
@@ -1,7 +1,5 @@
 #include "asn1fix_internal.h"
 
-#define	AFT_MAGIC_ANY	1	/* _fetch_tag() flag */
-
 static int _asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v);
 static int _asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b);
 static int _asn1f_fix_type_tag(arg_t *arg, asn1p_expr_t *expr);
@@ -337,6 +335,7 @@
 	case ASN_CONSTR_SEQUENCE:
 	case ASN_CONSTR_SET:
 	case ASN_CONSTR_CHOICE:
+		DEBUG("Checking tags of members of constructed types");
 		break;
 	default:
 		return 0;
@@ -353,6 +352,8 @@
 		if(expr->expr_type != ASN_CONSTR_SEQUENCE || v->marker.flags) {
 			asn1p_expr_t *nv;
 			for(nv = v; (nv = TQ_NEXT(nv, next));) {
+				DEBUG("S/C comparing tags %s s. %s",
+					v->Identifier, nv->Identifier);
 				if(_asn1f_compare_tags(arg, v, nv))
 					r_value = -1;
 				if(expr->expr_type == ASN_CONSTR_SEQUENCE
@@ -404,12 +405,15 @@
 	int ra, rb;
 	int ret;
 
-	ra = asn1f_fetch_outmost_tag(arg->asn, arg->mod, a, &ta, AFT_MAGIC_ANY);
-	rb = asn1f_fetch_outmost_tag(arg->asn, arg->mod, b, &tb, AFT_MAGIC_ANY);
+	ra = asn1f_fetch_outmost_tag(arg->asn, arg->mod, a,
+			&ta, AFT_IMAGINARY_ANY);
+	rb = asn1f_fetch_outmost_tag(arg->asn, arg->mod, b,
+			&tb, AFT_IMAGINARY_ANY);
 
 	/*
 	 * If both tags are explicitly or implicitly given, use them.
 	 */
+	DEBUG("Fetching outmost tags: %d, %d", ra, rb);
 	if(ra == 0 && rb == 0) {
 		/*
 		 * Simple case: fetched both tags.
diff --git a/libasn1fix/asn1fix_retrieve.c b/libasn1fix/asn1fix_retrieve.c
index 730c861..4236858 100644
--- a/libasn1fix/asn1fix_retrieve.c
+++ b/libasn1fix/asn1fix_retrieve.c
@@ -370,6 +370,7 @@
 		return NULL;
 	}
 
+	tc->_type_referenced = 1;
 	tc->_mark |= TM_RECURSION;
 	WITH_MODULE(tc->module,
 		expr = asn1f_find_terminal_thing(arg, tc, what));
diff --git a/libasn1fix/asn1fix_tags.c b/libasn1fix/asn1fix_tags.c
index ff662cc..dfda441 100644
--- a/libasn1fix/asn1fix_tags.c
+++ b/libasn1fix/asn1fix_tags.c
@@ -18,6 +18,9 @@
 	if((flags & AFT_FETCH_OUTMOST)) return count;			\
 } while(0)
 
+/* X.691, #22.2 */
+static int asn1f_fetch_minimal_choice_root_tag(arg_t *arg, struct asn1p_type_tag_s *tag, enum asn1f_aft_flags_e flags);
+
 static int
 asn1f_fetch_tags_impl(arg_t *arg, struct asn1p_type_tag_s **tags, int count, int skip, enum asn1f_aft_flags_e flags) {
 	asn1p_expr_t *expr = arg->expr;
@@ -44,9 +47,13 @@
 			if(expr->expr_type == ASN_TYPE_ANY
 				&& (flags & AFT_IMAGINARY_ANY))
 				tt.tag_value = -1;
-			else if(expr->expr_type == ASN_CONSTR_CHOICE)
-				return count ? count : -1;
-			else
+			else if(expr->expr_type != ASN_CONSTR_CHOICE)
+				return -1;
+			else if(count) return count;
+			else if((flags & AFT_CANON_CHOICE) == 0)
+				return -1;
+			else if(asn1f_fetch_minimal_choice_root_tag(arg,
+					&tt, flags))
 				return -1;
 		}
 		ADD_TAG(skip, tt);
@@ -55,6 +62,7 @@
 
 	if(expr->meta_type == AMT_TYPEREF) {
 		asn1p_expr_t *nexpr;
+		DEBUG("Following the reference %s", expr->Identifier);
 		nexpr = asn1f_lookup_symbol(arg, expr->module, expr->reference);
 		if(nexpr == NULL) {
 			if(errno != EEXIST)	/* -fknown-extern-type */
@@ -87,18 +95,52 @@
 		return count;
 	}
 
+	DEBUG("No tags discovered for type %d", expr->expr_type);
+
 	return -1;
 }
 
+static int
+asn1f_fetch_minimal_choice_root_tag(arg_t *arg, struct asn1p_type_tag_s *tag, enum asn1f_aft_flags_e flags) {
+	struct asn1p_type_tag_s min_tag;
+	asn1p_expr_t *v;
+
+	memset(&min_tag, 0, sizeof(min_tag));
+	min_tag.tag_class = TC_PRIVATE + 1;
+
+	TQ_FOR(v, &(arg->expr->members), next) {
+		arg_t tmparg = *arg;
+		struct asn1p_type_tag_s *tags = 0;
+		int count;
+
+		if(v->expr_type == A1TC_EXTENSIBLE)
+			break;	/* Search only within extension root */
+
+		tmparg.expr = v;
+		count  = asn1f_fetch_tags_impl(&tmparg, &tags, 0, 0, flags);
+		if(count <= 0) continue;
+
+		if(tags[0].tag_class < min_tag.tag_class)
+			min_tag = tags[0];
+		else if(tags[0].tag_class == min_tag.tag_class
+			&& tags[0].tag_value < min_tag.tag_value)
+				min_tag = tags[0];
+		free(tags);
+	}
+
+	if(min_tag.tag_class == TC_PRIVATE + 1)
+		return -1;
+	else
+		*tag = min_tag;
+	return 0;
+}
 
 int
-asn1f_fetch_outmost_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag, int _aft_imaginary_any) {
+asn1f_fetch_outmost_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag, enum asn1f_aft_flags_e flags) {
 	struct asn1p_type_tag_s *tags;
-	enum asn1f_aft_flags_e flags;
 	int count;
 
-	flags = AFT_FETCH_OUTMOST;
-	flags |= AFT_IMAGINARY_ANY * _aft_imaginary_any;
+	flags |= AFT_FETCH_OUTMOST;
 
 	count = asn1f_fetch_tags(asn, mod, expr, &tags, flags);
 	if(count <= 0) return count;
diff --git a/libasn1fix/asn1fix_tags.h b/libasn1fix/asn1fix_tags.h
index a4c31ad..0fbbefe 100644
--- a/libasn1fix/asn1fix_tags.h
+++ b/libasn1fix/asn1fix_tags.h
@@ -5,6 +5,7 @@
 	AFT_IMAGINARY_ANY	= 0x01,	/* Treat ANY tag as [IMAGINARY ANY] */
 	AFT_FETCH_OUTMOST	= 0x02,	/* Fetch only outmost tag */
 	AFT_FULL_COLLECT	= 0x04,	/* Collect all tags */
+	AFT_CANON_CHOICE	= 0x08,	/* Fetch the minimal CHOICE root tag */
 };
 
 /*
@@ -24,6 +25,6 @@
  * Type3 ::= SEQUENCE { ... }
  * Will yield [2] for Type1.
  */
-int asn1f_fetch_outmost_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag, int _aft_imaginary_any);
+int asn1f_fetch_outmost_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag, enum asn1f_aft_flags_e);
 
 #endif	/* _ASN1FIX_TAGS_H_ */