more support for parametrized type; additional ANY support

diff --git a/libasn1fix/asn1fix.c b/libasn1fix/asn1fix.c
index 46a3272..4a27932 100644
--- a/libasn1fix/asn1fix.c
+++ b/libasn1fix/asn1fix.c
@@ -159,18 +159,24 @@
 		RET2RVAL(ret, rvalue);
 
 		/*
-		 * 2.[234] Process SEQUENCE/SET/CHOICE types.
-		 */
-		ret = asn1f_recurse_expr(arg, asn1f_fix_constructed);
-		RET2RVAL(ret, rvalue);
-
-		/*
 		 * 2.5.4
 		 */
 		ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_types);
 		RET2RVAL(ret, rvalue);
 
 		/*
+		 * Fix tagging of top-level types.
+		 */
+		ret = asn1f_fix_constr_tag(arg, 1);
+		RET2RVAL(ret, rvalue);
+
+		/*
+		 * 2.[234] Process SEQUENCE/SET/CHOICE types.
+		 */
+		ret = asn1f_recurse_expr(arg, asn1f_fix_constructed);
+		RET2RVAL(ret, rvalue);
+
+		/*
 		 * 2.5.5
 		 */
 		ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_values);
@@ -239,6 +245,10 @@
 	TQ_FOR(expr, &(arg->mod->members), next) {
 		arg->expr = expr;
 
+		if(arg->expr->meta_type == AMT_PARAMTYPE)
+			/* Do not process the parametrized types here */
+			continue;
+
 		ret = asn1f_recurse_expr(arg, asn1f_check_constraints);
 		RET2RVAL(ret, rvalue);
 
@@ -286,7 +296,7 @@
 	RET2RVAL(ret, rvalue);
 
 	/* Fix tagging */
-	ret = asn1f_fix_constr_tag(arg);
+	ret = asn1f_fix_constr_tag(arg, 0);
 	RET2RVAL(ret, rvalue);
 
 	/* Import COMPONENTS OF stuff */
@@ -308,6 +318,8 @@
 		etype = top_parent->expr_type;
 	else	etype = A1TC_INVALID;
 
+	DEBUG("asn1f_resolve_constraints(%s)", arg->expr->Identifier);
+
 	ret = asn1constraint_resolve(arg, arg->expr->module,
 		arg->expr->constraints, etype, 0);
 	RET2RVAL(ret, rvalue);
@@ -326,6 +338,10 @@
 	int rvalue = 0;
 	int ret;
 
+	DEBUG("asn1f_check_constraints(%s{%d/%d})",
+		arg->expr->Identifier,
+		arg->expr->meta_type, arg->expr->expr_type);
+
 	top_parent = asn1f_find_terminal_type(arg, arg->expr);
 	if(!top_parent)
 		return 0;
@@ -339,8 +355,13 @@
 				etype,
 				arg->expr->combined_constraints,
 				test_types[i], 0, 0, 0);
-		if(!range && errno == EPERM)
+		if(!range && errno == EPERM) {
+			FATAL("This error happened for %s (%d) at line %d",
+				arg->expr->Identifier,
+				arg->expr->meta_type,
+				arg->expr->_lineno);
 			return -1;
+		}
 		asn1constraint_range_free(range);
 	}
 
diff --git a/libasn1fix/asn1fix_constr.c b/libasn1fix/asn1fix_constr.c
index fab78d3..8c9dd38 100644
--- a/libasn1fix/asn1fix_constr.c
+++ b/libasn1fix/asn1fix_constr.c
@@ -1,7 +1,10 @@
 #include "asn1fix_internal.h"
 
+#define	AFT_IMAGINARY_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);
 
 int
 asn1f_pull_components_of(arg_t *arg) {
@@ -77,6 +80,9 @@
 	return r_value;
 }
 
+/*
+ * Fix extensibility parts inside constructed types (SEQUENCE, SET, CHOICE).
+ */
 int
 asn1f_fix_constr_ext(arg_t *arg) {
 	asn1p_expr_t *expr = arg->expr;
@@ -103,6 +109,10 @@
 	TQ_INIT(&ext_list);
 	cur_list = (void *)&root_list;
 
+	/*
+	 * Split the set of fields into two lists, the root list
+	 * and the extensions list.
+	 */
 	while((v = TQ_REMOVE(&(expr->members), next))) {
 		if(v->expr_type == A1TC_EXTENSIBLE) {
 			ext_count++;
@@ -161,16 +171,30 @@
 
 
 int
-asn1f_fix_constr_tag(arg_t *arg) {
+asn1f_fix_constr_tag(arg_t *arg, int fix_top_level) {
 	asn1p_expr_t *expr = arg->expr;
 	asn1p_expr_t *v;
-	int fl_impl_tags = 0;
-	int fl_auto_tags = 0;
 	int root_tagged = 0;	/* The root component is manually tagged */
 	int ext_tagged = 0;	/* The extensions are manually tagged */
 	int component_number = 0;
 	int r_value = 0;
 
+	DEBUG("%s(%s) for line %d", __func__,
+		expr->Identifier, expr->_lineno);
+
+	/*
+	 * Fix the top-level type itself first.
+	 */
+	if(fix_top_level) {
+		if(expr->tag.tag_class == TC_NOCLASS)
+			return r_value;
+
+		if(_asn1f_fix_type_tag(arg, expr))
+			r_value = -1;
+
+		return r_value;
+	}
+
 	switch(expr->expr_type) {
 	case ASN_CONSTR_SEQUENCE:
 	case ASN_CONSTR_SET:
@@ -180,14 +204,7 @@
 		return 0;
 	}
 
-	fl_impl_tags = (arg->mod->module_flags & MSF_IMPLICIT_TAGS);
-	fl_auto_tags = (arg->mod->module_flags & MSF_AUTOMATIC_TAGS);
-
-	DEBUG("%s(%s) {%d, %d} for line %d", __func__,
-		expr->Identifier, fl_impl_tags, fl_auto_tags, expr->_lineno);
-
 	TQ_FOR(v, &(expr->members), next) {
-		int must_explicit = 0;
 
 		if(v->expr_type == A1TC_EXTENSIBLE) {
 			component_number++;
@@ -196,43 +213,18 @@
 
 		if(v->tag.tag_class == TC_NOCLASS) {
 			continue;
-		} else {
-			switch(component_number) {
-			case 0: case 2:
-				root_tagged = 1; break;
-			default:
-				ext_tagged = 1; break;
-			}
 		}
 
-		must_explicit = _asn1f_check_if_tag_must_be_explicit(arg, v);
-
-		if(fl_impl_tags) {
-			if(v->tag.tag_mode != TM_EXPLICIT) {
-				if(must_explicit)
-					v->tag.tag_mode = TM_EXPLICIT;
-				else
-					v->tag.tag_mode = TM_IMPLICIT;
-			}
-		} else {
-			if(v->tag.tag_mode == TM_DEFAULT) {
-				v->tag.tag_mode = TM_EXPLICIT;
-			}
+		switch(component_number) {
+		case 0: case 2:
+			root_tagged = 1; break;
+		default:
+			ext_tagged = 1; break;
 		}
 
-		/*
-		 * Perform a final sanity check.
-		 */
-		if(must_explicit) {
-			if(v->tag.tag_mode == TM_IMPLICIT) {
-				FATAL("%s tagged in IMPLICIT mode "
-					"but must be EXPLICIT at line %d",
-					v->Identifier, v->_lineno);
-				r_value = -1;
-			} else {
-				v->tag.tag_mode = TM_EXPLICIT;
-			}
-		}
+		if(_asn1f_fix_type_tag(arg, v))
+			r_value = -1;
+
 	}
 
 	if(ext_tagged && !root_tagged) {
@@ -241,13 +233,51 @@
 			"but root components are not",
 			expr->Identifier, expr->_lineno);
 		r_value = -1;
-	} else if(!root_tagged && !ext_tagged && fl_auto_tags) {
+	} else if(!root_tagged && !ext_tagged
+			&& (arg->mod->module_flags & MSF_AUTOMATIC_TAGS)) {
+		/* Make a decision on automatic tagging */
 		expr->auto_tags_OK = 1;
 	}
 
 	return r_value;
 }
 
+static int
+_asn1f_fix_type_tag(arg_t *arg, asn1p_expr_t *expr) {
+	int must_explicit = _asn1f_check_if_tag_must_be_explicit(arg, expr);
+	int fl_impl_tags = (arg->mod->module_flags & MSF_IMPLICIT_TAGS);
+	int r_value = 0;
+
+	if(fl_impl_tags) {
+		if(expr->tag.tag_mode != TM_EXPLICIT) {
+			if(must_explicit)
+				expr->tag.tag_mode = TM_EXPLICIT;
+			else
+				expr->tag.tag_mode = TM_IMPLICIT;
+		}
+	} else {
+		if(expr->tag.tag_mode == TM_DEFAULT) {
+			expr->tag.tag_mode = TM_EXPLICIT;
+		}
+	}
+
+	/*
+	 * Perform a final sanity check.
+	 */
+	if(must_explicit) {
+		if(expr->tag.tag_mode == TM_IMPLICIT) {
+			FATAL("%s tagged in IMPLICIT mode "
+				"but must be EXPLICIT at line %d",
+				expr->Identifier, expr->_lineno);
+			r_value = -1;
+		} else {
+			expr->tag.tag_mode = TM_EXPLICIT;
+		}
+	}
+
+	return r_value;
+}
+
 int
 asn1f_fix_constr_autotag(arg_t *arg) {
 	asn1p_expr_t *expr = arg->expr;
@@ -333,11 +363,25 @@
 
 static int
 _asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v) {
+	struct asn1p_type_tag_s tag;
+	struct asn1p_type_tag_s save_tag;
 	asn1p_expr_t *reft;
+	int ret;
+
+	/*
+	 * Fetch the _next_ tag for this type.
+	 */
+	save_tag = v->tag;			/* Save existing tag */
+	memset(&v->tag, 0, sizeof(v->tag));	/* Remove it temporarily */
+	ret = asn1f_fetch_tag(arg->asn, arg->mod, v, &tag, 0);
+	v->tag = save_tag;			/* Restore the tag back */
+
+	if(ret == 0) return 0;	/* If found tag, it's okay */
 
 	reft = asn1f_find_terminal_type(arg, v);
 	if(reft) {
 		switch(reft->expr_type) {
+		case ASN_TYPE_ANY:
 		case ASN_CONSTR_CHOICE:
 			return 1;
 		default:
@@ -357,8 +401,8 @@
 	int ra, rb;
 	int ret;
 
-	ra = asn1f_fetch_tag(arg->asn, arg->mod, a, &ta);
-	rb = asn1f_fetch_tag(arg->asn, arg->mod, b, &tb);
+	ra = asn1f_fetch_tag(arg->asn, arg->mod, a, &ta, AFT_IMAGINARY_ANY);
+	rb = asn1f_fetch_tag(arg->asn, arg->mod, b, &tb, AFT_IMAGINARY_ANY);
 
 	/*
 	 * If both tags are explicitly or implicitly given, use them.
@@ -367,8 +411,12 @@
 		/*
 		 * Simple case: fetched both tags.
 		 */
-		if(ta.tag_value == tb.tag_value
-		&& ta.tag_class == tb.tag_class) {
+
+		if((ta.tag_value == tb.tag_value
+			&& ta.tag_class == tb.tag_class)
+		|| ta.tag_value == -1	/* Spread IMAGINARY ANY tag... */
+		|| tb.tag_value == -1	/* ...it is an evil virus, fear it! */
+		) {
 			char *p = (a->expr_type == A1TC_EXTENSIBLE)
 				?"potentially ":"";
 			FATAL("Component \"%s\" at line %d %shas the same tag "
diff --git a/libasn1fix/asn1fix_constr.h b/libasn1fix/asn1fix_constr.h
index 59970ad..ffed143 100644
--- a/libasn1fix/asn1fix_constr.h
+++ b/libasn1fix/asn1fix_constr.h
@@ -14,7 +14,7 @@
 /*
  * Fix tagging in constructed types.
  */
-int asn1f_fix_constr_tag(arg_t *);
+int asn1f_fix_constr_tag(arg_t *, int fix_top_level);
 
 /*
  * Check distinctive tagging in constructed types.
diff --git a/libasn1fix/asn1fix_constraint.c b/libasn1fix/asn1fix_constraint.c
index 4a25fae..3f30009 100644
--- a/libasn1fix/asn1fix_constraint.c
+++ b/libasn1fix/asn1fix_constraint.c
@@ -93,7 +93,7 @@
 
 		expr->combined_constraints = ct_parent;
 		if(ct_expr->type == ACT_CA_SET) {
-			int i;
+			unsigned int i;
 			for(i = 0; i < ct_expr->el_count; i++) {
 				if(asn1p_constraint_insert(
 					expr->combined_constraints,
@@ -120,9 +120,9 @@
 
 int
 asn1constraint_resolve(arg_t *arg, asn1p_module_t *mod, asn1p_constraint_t *ct, asn1p_expr_type_e etype, enum asn1p_constraint_type_e effective_type) {
+	unsigned int el;
 	int rvalue = 0;
 	int ret;
-	int el;
 
 	if(!ct) return 0;
 
@@ -208,7 +208,7 @@
 
 static void
 _remove_exceptions(arg_t *arg, asn1p_constraint_t *ct) {
-	int i;
+	unsigned int i;
 
 	for(i = 0; i < ct->el_count; i++) {
 		if(ct->elements[i]->type == ACT_EL_EXT)
diff --git a/libasn1fix/asn1fix_crange.c b/libasn1fix/asn1fix_crange.c
index 6ef8c8a..53d4640 100644
--- a/libasn1fix/asn1fix_crange.c
+++ b/libasn1fix/asn1fix_crange.c
@@ -699,8 +699,8 @@
 	asn1p_value_t *vmin;
 	asn1p_value_t *vmax;
 	int expectation_met;
+	unsigned int i;
 	int ret;
-	int i;
 
 	if(!exmet) {
 		exmet = &expectation_met;
diff --git a/libasn1fix/asn1fix_param.c b/libasn1fix/asn1fix_param.c
index c399ae4..5ce6b93 100644
--- a/libasn1fix/asn1fix_param.c
+++ b/libasn1fix/asn1fix_param.c
@@ -2,7 +2,10 @@
 
 static int asn1f_parametrize(arg_t *arg, asn1p_expr_t *ex, asn1p_expr_t *ptype);
 static int asn1f_param_process_recursive(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
+static int asn1f_param_process_constraints(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
+
 static asn1p_expr_t *_referenced_argument(asn1p_ref_t *ref, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
+static int _process_constraints(arg_t *arg, asn1p_constraint_t *ct, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
 
 int
 asn1f_fix_parametrized_assignment(arg_t *arg) {
@@ -79,6 +82,7 @@
 	 * as a child of the expression, replacing all occurences of
 	 * symbols which are defined as parametrized type arguments
 	 * with the actual values.
+	 * 3. Don't forget to parametrize the subtype constraints.
 	 */
 
 	nex = asn1p_expr_clone(ptype, 0);
@@ -117,34 +121,40 @@
 
 	TQ_FOR(child, &(expr->members), next) {
 		asn1p_expr_t *ra;
-		asn1p_expr_t *ne;
+		asn1p_expr_t *ne;	/* new expression (clone) */
+
+		if(asn1f_param_process_constraints(arg, child, ptype, actargs))
+			return -1;
 
 		ra = _referenced_argument(child->reference, ptype, actargs);
-		if(ra == NULL) continue;
-
-		DEBUG("Substituting parameter for %s %s at line %d",
-			child->Identifier,
-			asn1f_printable_reference(child->reference),
-			child->_lineno
-		);
-
-		assert(child->meta_type == AMT_TYPEREF);
-		assert(child->expr_type == A1TC_REFERENCE);
-
-		ne = asn1p_expr_clone(ra, 0);
-		if(ne == NULL) return -1;
-		assert(ne->Identifier == 0);
-		ne->Identifier = strdup(child->Identifier);
-		if(ne->Identifier == 0) {
-			asn1p_expr_free(ne);
-			return -1;
+		if(ra) {
+			DEBUG("Substituting parameter for %s %s at line %d",
+				child->Identifier,
+				asn1f_printable_reference(child->reference),
+				child->_lineno
+			);
+	
+			assert(child->meta_type == AMT_TYPEREF);
+			assert(child->expr_type == A1TC_REFERENCE);
+	
+			ne = asn1p_expr_clone(ra, 0);
+			if(ne == NULL) return -1;
+			assert(ne->Identifier == 0);
+			ne->Identifier = strdup(child->Identifier);
+			if(ne->Identifier == 0) {
+				asn1p_expr_free(ne);
+				return -1;
+			}
+			SUBSTITUTE(child, ne);
 		}
-		SUBSTITUTE(child, ne);
 	}
 
 	return 0;
 }
 
+/*
+ * Check that the given ref looks like an argument of a parametrized type.
+ */
 static asn1p_expr_t *
 _referenced_argument(asn1p_ref_t *ref, asn1p_expr_t *ptype, asn1p_expr_t *actargs) {
 	asn1p_expr_t *aa;
@@ -163,3 +173,84 @@
 
 	return NULL;
 }
+
+/*
+ * Search for parameters inside constraints.
+ */
+static int
+asn1f_param_process_constraints(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs) {
+	asn1p_constraint_t *cts;
+	int ret;
+
+	if(!expr->constraints) return 0;
+
+	cts = asn1p_constraint_clone(expr->constraints);
+	assert(cts);
+
+	ret = _process_constraints(arg, cts, ptype, actargs);
+	if(ret == 1) {
+		asn1p_constraint_free(expr->constraints);
+		expr->constraints = cts;
+		ret = 0;
+	} else {
+		asn1p_constraint_free(cts);
+	}
+
+	return ret;
+}
+
+static int
+_process_constraints(arg_t *arg, asn1p_constraint_t *ct, asn1p_expr_t *ptype, asn1p_expr_t *actargs) {
+	asn1p_value_t *values[3];
+	int rvalue = 0;
+	size_t i;
+
+	values[0] = ct->value;
+	values[1] = ct->range_start;
+	values[2] = ct->range_stop;
+
+	for(i = 0; i < sizeof(values)/sizeof(values[0]); i++) {
+		asn1p_value_t *v = values[i];
+		asn1p_expr_t *ra;
+		asn1p_ref_t *ref;
+		char *str;
+
+		if(!v || v->type != ATV_REFERENCED) continue;
+
+		ref = v->value.reference;
+		ra = _referenced_argument(ref, ptype, actargs);
+		if(!ra) continue;
+
+		DEBUG("_process_constraints(%s), ra=%s",
+			asn1f_printable_reference(ref), ra->Identifier);
+
+		str = strdup(ra->Identifier);
+		if(!str) return -1;
+
+		assert(ref->comp_count == 1);
+		ref = asn1p_ref_new(ref->_lineno);
+		if(!ref) { free(str); return -1; }
+
+		if(asn1p_ref_add_component(ref, str, 0)) {
+			free(str);
+			return -1;
+		}
+
+		asn1p_ref_free(v->value.reference);
+		v->value.reference = ref;
+		rvalue = 1;
+	}
+
+	/* Process the rest of constraints recursively */
+	for(i = 0; i < ct->el_count; i++) {
+		int ret = _process_constraints(arg, ct->elements[i],
+			ptype, actargs);
+		if(ret == -1)
+			rvalue = -1;
+		else if(ret == 1 && rvalue != -1)
+			rvalue = 1;
+	}
+
+	return rvalue;
+}
+
diff --git a/libasn1fix/asn1fix_tags.c b/libasn1fix/asn1fix_tags.c
index de80fad..22ba422 100644
--- a/libasn1fix/asn1fix_tags.c
+++ b/libasn1fix/asn1fix_tags.c
@@ -1,7 +1,7 @@
 #include "asn1fix_internal.h"
 
 int
-asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag) {
+asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag, int flags) {
 	int ret;
 
 	if(expr->tag.tag_class != TC_NOCLASS) {
@@ -19,6 +19,11 @@
 		memset(tag, 0, sizeof(*tag));
 		tag->tag_class = TC_UNIVERSAL;
 		tag->tag_value = expr_type2uclass_value[expr->expr_type];
+		if(flags && expr->expr_type == ASN_TYPE_ANY) {
+			assert(tag->tag_value == 0);
+			tag->tag_value = -1;
+			return 0;
+		}
 		return (tag->tag_value == 0) ? -1 : 0;
 	}
 
@@ -37,7 +42,8 @@
 			return -1;
 
 		expr->_mark |= TM_RECURSION;
-		ret = asn1f_fetch_tag(asn, expr->module, expr, tag);
+		ret = asn1f_fetch_tag(asn, expr->module, expr, tag,
+			flags);
 		expr->_mark &= ~TM_RECURSION;
 		return ret;
 	}
diff --git a/libasn1fix/asn1fix_tags.h b/libasn1fix/asn1fix_tags.h
index 9d3595b..429e56d 100644
--- a/libasn1fix/asn1fix_tags.h
+++ b/libasn1fix/asn1fix_tags.h
@@ -1,6 +1,6 @@
 #ifndef	_ASN1FIX_TAGS_H_
 #define	_ASN1FIX_TAGS_H_
 
-int asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag);
+int asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag, int special_ANY_handling);
 
 #endif	/* _ASN1FIX_TAGS_H_ */