new constraints generation method

diff --git a/libasn1compiler/Makefile.am b/libasn1compiler/Makefile.am
index bcfaf93..55c5298 100644
--- a/libasn1compiler/Makefile.am
+++ b/libasn1compiler/Makefile.am
@@ -1,7 +1,7 @@
 
 AM_CPPFLAGS =	\
-	-I${top_srcdir}/libasn1parser	\
-	-I${top_srcdir}/libasn1fix
+	-I$(top_srcdir)/libasn1parser	\
+	-I$(top_srcdir)/libasn1fix
 
 noinst_LTLIBRARIES = libasn1compiler.la
 
@@ -17,11 +17,3 @@
 	asn1c_compat.c asn1c_compat.h		\
 	asn1c_fdeps.c asn1c_fdeps.h		\
 	asn1c_internal.h
-
-TESTS = $(check_PROGRAMS)
-
-check_PROGRAMS = check_compiler
-
-check_compiler_LDADD = $(noinst_LTLIBRARIES)		\
-	$(top_builddir)/libasn1parser/libasn1parser.la	\
-	$(top_builddir)/libasn1fix/libasn1fix.la
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index ac13873..f54d2d5 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -5,6 +5,8 @@
 #include "asn1c_internal.h"
 #include "asn1c_C.h"
 #include "asn1c_constraint.h"
+#include "asn1c_out.h"
+#include "asn1c_misc.h"
 #include <asn1fix_export.h>	/* Stuff exported by libasn1fix */
 
 typedef struct tag2el_s {
@@ -17,6 +19,8 @@
 
 static int _fill_tag2el_map(arg_t *arg, tag2el_t **tag2el, int *count, int el_no);
 static int _add_tag2el_member(arg_t *arg, tag2el_t **tag2el, int *count, int el_no);
+static int _expr_elements_count(arg_t *arg, asn1p_expr_t *expr);
+static int _emit_member_table(arg_t *arg, asn1p_expr_t *expr);
 
 static int asn1c_lang_C_type_SEQUENCE_def(arg_t *arg);
 static int asn1c_lang_C_type_SET_def(arg_t *arg);
@@ -27,7 +31,7 @@
 static int emit_tags_vector(arg_t *arg, asn1p_expr_t *expr, int *tags_impl_skip, int choice_mode);
 static int emit_tag2member_map(arg_t *arg, tag2el_t *tag2el, int tag2el_count);
 
-#define	C99_MODE	(arg->flags & A1C_NO_C99)
+#define	C99_MODE	(!(arg->flags & A1C_NO_C99))
 #define	UNNAMED_UNIONS	(arg->flags & A1C_UNNAMED_UNIONS)
 
 #define	PCTX_DEF INDENTED(		\
@@ -176,7 +180,7 @@
 	 * Print out the table according to which the parsing is performed.
 	 */
 	p = MKID(expr->Identifier);
-	OUT("static asn1_SEQUENCE_element_t asn1_DEF_%s_elements[] = {\n", p);
+	OUT("static asn1_TYPE_member_t asn1_MBR_%s[] = {\n", p);
 
 	elements = 0;
 	INDENTED(TQ_FOR(v, &(expr->members), next) {
@@ -187,43 +191,8 @@
 				ext_stop = elements - 1;
 			continue;
 		}
-	OUT("{ ");
 		elements++;
-		OUT("offsetof(struct %s, ", MKID(expr->Identifier));
-		OUT("%s), ", MKID(v->Identifier));
-		if(v->marker) {
-			asn1p_expr_t *tv;
-			int opts = 0;
-			for(tv = v; tv && tv->marker;
-				tv = TQ_NEXT(tv, next), opts++) {
-				if(tv->expr_type == A1TC_EXTENSIBLE)
-					opts--;
-			}
-			OUT("%d,", opts);
-		} else {
-			OUT("0,");
-		}
-		OUT("\n");
-		INDENT(+1);
-		if(C99_MODE) OUT(".tag = ");
-		_print_tag(arg, v, NULL);
-		OUT(",\n");
-		if(C99_MODE) OUT(".tag_mode = ");
-		if(v->tag.tag_class) {
-			if(v->tag.tag_mode == TM_IMPLICIT)
-			OUT("-1,\t/* IMPLICIT tag at current level */\n");
-			else
-			OUT("+1,\t/* EXPLICIT tag at current level */\n");
-		} else {
-			OUT("0,\n");
-		}
-		if(C99_MODE) OUT(".type = ");
-		OUT("(void *)&asn1_DEF_%s,\n",
-			asn1c_type_name(arg, v, TNF_SAFE));
-		if(C99_MODE) OUT(".name = ");
-		OUT("\"%s\"\n", v->Identifier);
-		OUT("},\n");
-		INDENT(-1);
+		_emit_member_table(arg, v);
 	});
 	OUT("};\n");
 
@@ -242,8 +211,6 @@
 	INDENTED(
 		OUT("sizeof(struct %s),\n", p);
 		OUT("offsetof(struct %s, _ber_dec_ctx),\n", p);
-		OUT("asn1_DEF_%s_elements,\n", p);
-		OUT("%d,\t/* Elements count */\n", elements);
 		OUT("asn1_DEF_%s_tag2el,\n", p);
 		OUT("%d,\t/* Count of tags in the map */\n", tag2el_count);
 		OUT("%d,\t/* Start extensions */\n",
@@ -272,6 +239,8 @@
 		}
 		OUT("%d,\t/* Tags to skip */\n", tags_impl_skip);
 		OUT("%d,\t/* Whether CONSTRUCTED */\n", 1);
+		OUT("asn1_MBR_%s,\n", p);
+		OUT("%d,\t/* Elements count */\n", elements);
 		OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p);
 	);
 	OUT("};\n");
@@ -405,48 +374,19 @@
 	 * Print out the table according to which the parsing is performed.
 	 */
 	p = MKID(expr->Identifier);
-	OUT("static asn1_SET_element_t asn1_DEF_%s_elements[] = {\n", p);
+	OUT("static asn1_TYPE_member_t asn1_MBR_%s[] = {\n", p);
 
 	elements = 0;
 	INDENTED(TQ_FOR(v, &(expr->members), next) {
 		if(v->expr_type != A1TC_EXTENSIBLE) {
 			if(comp_mode == 1)
 				v->marker = EM_OPTIONAL;
-			elements++;
 		} else {
 			if(comp_mode < 3) comp_mode++;
 			continue;
 		}
-	OUT("{ ");
-		p = MKID(expr->Identifier);
-		OUT("offsetof(struct %s, ", p);
-		p = MKID(v->Identifier);
-		OUT("%s), ", p);
-		if(v->marker) {
-			OUT("1, /* Optional element */\n");
-		} else {
-			OUT("0,\n");
-		}
-		INDENT(+1);
-		if(C99_MODE) OUT(".tag = ");
-		_print_tag(arg, v, NULL);
-		OUT(",\n");
-		if(C99_MODE) OUT(".tag_mode = ");
-		if(v->tag.tag_class) {
-			if(v->tag.tag_mode == TM_IMPLICIT)
-			OUT("-1,\t/* IMPLICIT tag at current level */\n");
-			else
-			OUT("+1,\t/* EXPLICIT tag at current level */\n");
-		} else {
-			OUT("0,\n");
-		}
-		if(C99_MODE) OUT(".type = ");
-		OUT("(void *)&asn1_DEF_%s,\n",
-			asn1c_type_name(arg, v, TNF_SAFE));
-		if(C99_MODE) OUT(".name = ");
-		OUT("\"%s\"\n", v->Identifier);
-		OUT("},\n");
-		INDENT(-1);
+		elements++;
+		_emit_member_table(arg, v);
 	});
 	OUT("};\n");
 
@@ -496,8 +436,6 @@
 		OUT("sizeof(struct %s),\n", p);
 		OUT("offsetof(struct %s, _ber_dec_ctx),\n", p);
 		OUT("offsetof(struct %s, _presence_map),\n", p);
-		OUT("asn1_DEF_%s_elements,\n", p);
-		OUT("%d,\t/* Elements count */\n", elements);
 		OUT("asn1_DEF_%s_tag2el,\n", p);
 		OUT("%d,\t/* Count of tags in the map */\n", tag2el_count);
 		OUT("%d,\t/* Whether extensible */\n",
@@ -525,6 +463,8 @@
 		}
 		OUT("%d,\t/* Tags to skip */\n", tags_impl_skip);
 		OUT("%d,\t/* Whether CONSTRUCTED */\n", 1);
+		OUT("asn1_MBR_%s,\n", p);
+		OUT("%d,\t/* Elements count */\n", elements);
 		OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p);
 	);
 	OUT("};\n");
@@ -589,20 +529,11 @@
 	 * Print out the table according to which the parsing is performed.
 	 */
 	p = MKID(expr->Identifier);
-	OUT("static asn1_SET_OF_element_t asn1_DEF_%s_elements[] = {\n", p);
+	OUT("static asn1_TYPE_member_t asn1_MBR_%s[] = {\n", p);
 
-	INDENTED(OUT("{ ");
+	INDENTED(
 		v = TQ_FIRST(&(expr->members));
-		INDENT(+1);
-		if(C99_MODE) OUT(".tag = ");
-		_print_tag(arg, v, NULL);
-		OUT(",\n");
-		if(C99_MODE) OUT(".type = ");
-		OUT("(void *)&asn1_DEF_%s",
-			asn1c_type_name(arg, v, TNF_SAFE));
-		OUT(" ");
-		OUT("},\n");
-		INDENT(-1);
+		_emit_member_table(arg, v);
 	);
 	OUT("};\n");
 
@@ -616,7 +547,6 @@
 	INDENTED(
 		OUT("sizeof(struct %s),\n", p);
 		OUT("offsetof(struct %s, _ber_dec_ctx),\n", p);
-		OUT("asn1_DEF_%s_elements\n", p);
 	);
 	OUT("};\n");
 	OUT("asn1_TYPE_descriptor_t asn1_DEF_%s = {\n", p);
@@ -647,6 +577,8 @@
 		}
 		OUT("%d,\t/* Tags to skip */\n", tags_impl_skip);
 		OUT("%d,\t/* Whether CONSTRUCTED */\n", 1);
+		OUT("asn1_MBR_%s,\n", p);
+		OUT("1,\t/* Single element */\n");
 		OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p);
 	);
 	OUT("};\n");
@@ -742,49 +674,19 @@
 	 * Print out the table according to which the parsing is performed.
 	 */
 	p = MKID(expr->Identifier);
-	OUT("static asn1_CHOICE_element_t asn1_DEF_%s_elements[] = {\n", p);
+	OUT("static asn1_TYPE_member_t asn1_MBR_%s[] = {\n", p);
 
 	elements = 0;
 	INDENTED(TQ_FOR(v, &(expr->members), next) {
 		if(v->expr_type != A1TC_EXTENSIBLE) {
 			if(comp_mode == 1)
 				v->marker = EM_OPTIONAL;
-			elements++;
 		} else {
 			if(comp_mode < 3) comp_mode++;
 			continue;
 		}
-	OUT("{ ");
-		p = MKID(expr->Identifier);
-		OUT("offsetof(struct %s, ", p);
-		p = MKID(v->Identifier);
-		if(!UNNAMED_UNIONS) OUT("choice.");
-		OUT("%s), ", p);
-		if(v->marker) {
-			OUT("1, /* Optional element */\n");
-		} else {
-			OUT("0,\n");
-		}
-		INDENT(+1);
-		if(C99_MODE) OUT(".tag = ");
-		_print_tag(arg, v, NULL);
-		OUT(",\n");
-		if(C99_MODE) OUT(".tag_mode = ");
-		if(v->tag.tag_class) {
-			if(v->tag.tag_mode == TM_IMPLICIT)
-			OUT("-1,\t/* IMPLICIT tag at current level */\n");
-			else
-			OUT("+1,\t/* EXPLICIT tag at current level */\n");
-		} else {
-			OUT("0,\n");
-		}
-		if(C99_MODE) OUT(".type = ");
-		OUT("(void *)&asn1_DEF_%s,\n",
-			asn1c_type_name(arg, v, TNF_SAFE));
-		if(C99_MODE) OUT(".name = ");
-		OUT("\"%s\"\n", v->Identifier);
-		OUT("},\n");
-		INDENT(-1);
+		elements++;
+		_emit_member_table(arg, v);
 	});
 	OUT("};\n");
 
@@ -810,8 +712,6 @@
 		OUT("offsetof(struct %s, _ber_dec_ctx),\n", p);
 		OUT("offsetof(struct %s, present),\n", p);
 		OUT("sizeof(((struct %s *)0)->present),\n", p);
-		OUT("asn1_DEF_%s_elements,\n", p);
-		OUT("%d,\t/* Elements count */\n", elements);
 		OUT("asn1_DEF_%s_tag2el,\n", p);
 		OUT("%d,\t/* Count of tags in the map */\n", tag2el_count);
 		OUT("%d\t/* Whether extensible */\n",
@@ -838,6 +738,8 @@
 		}
 		OUT("%d,\t/* Tags to skip */\n", tags_impl_skip);
 		OUT("%d,\t/* Whether CONSTRUCTED */\n", 1);
+		OUT("asn1_MBR_%s,\n", p);
+		OUT("%d,\t/* Elements count */\n", elements);
 		OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p);
 	);
 	OUT("};\n");
@@ -910,6 +812,8 @@
 		if(expr->marker) OUT("\t/* %s */",
 			(expr->marker==EM_OPTIONAL)?"OPTIONAL":"DEFAULT");
 		OUT("\n");
+
+		REDIR(OT_TYPE_DECLS);
 		return 0;
 	}
 
@@ -951,17 +855,20 @@
 		}
 		OUT("%d,\t/* Tags to skip */\n", tags_impl_skip);
 		OUT("-0,\t/* Unknown yet */\n");
+		if(_expr_elements_count(arg, expr))
+			OUT("0, 0,\t/* Defined elsewhere */\n");
+		else
+			OUT("0, 0,\t/* No members */\n");
 		OUT("0\t/* No specifics */\n");
 	);
 	OUT("};\n");
 	OUT("\n");
 
+	REDIR(OT_CODE);
+
 	/*
 	 * Constraint checking.
 	 */
-	/* Emit FROM() tables and others */
-	asn1c_emit_constraint_tables(arg, 0);
-
 	p = MKID(expr->Identifier);
 	OUT("int\n");
 	OUT("%s_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,\n", p);
@@ -990,37 +897,41 @@
 	 * Emit suicidal functions.
 	 */
 
-	{
 	/*
 	 * This function replaces certain fields from the definition
 	 * of a type with the corresponding fields from the basic type
 	 * (from which the current type is inherited).
 	 */
-	char *type_name = asn1c_type_name(arg, expr, TNF_SAFE);
 	OUT("/*\n");
-	OUT(" * This type is implemented using %s,\n", type_name);
+	OUT(" * This type is implemented using %s,\n",
+		asn1c_type_name(arg, expr, TNF_SAFE));
 	OUT(" * so adjust the DEF appropriately.\n");
 	OUT(" */\n");
 	OUT("static void\n");
-	OUT("inherit_TYPE_descriptor(asn1_TYPE_descriptor_t *td) {\n");
+	p = MKID(expr->Identifier);
+	OUT("%s_inherit_TYPE_descriptor(asn1_TYPE_descriptor_t *td) {\n", p);
 	INDENT(+1);
-	OUT("td->ber_decoder = asn1_DEF_%s.ber_decoder;\n", type_name);
-	OUT("td->der_encoder = asn1_DEF_%s.der_encoder;\n", type_name);
-	OUT("td->free_struct = asn1_DEF_%s.free_struct;\n", type_name);
-	OUT("td->print_struct = asn1_DEF_%s.print_struct;\n", type_name);
-	OUT("td->last_tag_form = asn1_DEF_%s.last_tag_form;\n", type_name);
-	OUT("td->specifics = asn1_DEF_%s.specifics;\n", type_name);
+	{
+	char *type_name = asn1c_type_name(arg, expr, TNF_SAFE);
+	OUT("td->ber_decoder    = asn1_DEF_%s.ber_decoder;\n",    type_name);
+	OUT("td->der_encoder    = asn1_DEF_%s.der_encoder;\n",    type_name);
+	OUT("td->free_struct    = asn1_DEF_%s.free_struct;\n",    type_name);
+	OUT("td->print_struct   = asn1_DEF_%s.print_struct;\n",   type_name);
+	OUT("td->last_tag_form  = asn1_DEF_%s.last_tag_form;\n",  type_name);
+	OUT("td->elements       = asn1_DEF_%s.elements;\n",       type_name);
+	OUT("td->elements_count = asn1_DEF_%s.elements_count;\n", type_name);
+	OUT("td->specifics      = asn1_DEF_%s.specifics;\n",      type_name);
+	}
 	INDENT(-1);
 	OUT("}\n");
 	OUT("\n");
-	}
 
 	p = MKID(expr->Identifier);
 	OUT("ber_dec_rval_t\n");
 	OUT("%s_decode_ber(asn1_TYPE_descriptor_t *td,\n", p);
 	INDENTED(
 	OUT("\tvoid **structure, void *bufptr, size_t size, int tag_mode) {\n");
-	OUT("inherit_TYPE_descriptor(td);\n");
+	OUT("%s_inherit_TYPE_descriptor(td);\n", p);
 	OUT("return td->ber_decoder(td, structure,\n");
 	OUT("\tbufptr, size, tag_mode);\n");
 	);
@@ -1033,7 +944,7 @@
 	INDENTED(
 	OUT("\tvoid *structure, int tag_mode, ber_tlv_tag_t tag,\n");
 	OUT("\tasn_app_consume_bytes_f *cb, void *app_key) {\n");
-	OUT("inherit_TYPE_descriptor(td);\n");
+	OUT("%s_inherit_TYPE_descriptor(td);\n", p);
 	OUT("return td->der_encoder(td, structure, tag_mode, tag, cb, app_key);\n");
 	);
 	OUT("}\n");
@@ -1044,7 +955,7 @@
 	OUT("%s_print(asn1_TYPE_descriptor_t *td, const void *struct_ptr,\n", p);
 	INDENTED(
 	OUT("\tint ilevel, asn_app_consume_bytes_f *cb, void *app_key) {\n");
-	OUT("inherit_TYPE_descriptor(td);\n");
+	OUT("%s_inherit_TYPE_descriptor(td);\n", p);
 	OUT("return td->print_struct(td, struct_ptr, ilevel, cb, app_key);\n");
 	);
 	OUT("}\n");
@@ -1055,7 +966,7 @@
 	OUT("%s_free(asn1_TYPE_descriptor_t *td,\n", p);
 	INDENTED(
 	OUT("\tvoid *struct_ptr, int contents_only) {\n");
-	OUT("inherit_TYPE_descriptor(td);\n");
+	OUT("%s_inherit_TYPE_descriptor(td);\n", p);
 	OUT("td->free_struct(td, struct_ptr, contents_only);\n");
 	);
 	OUT("}\n");
@@ -1355,3 +1266,112 @@
 
 	return tags_count;
 }
+
+static int
+_expr_elements_count(arg_t *arg, asn1p_expr_t *expr) {
+	asn1p_expr_t *topmost_parent;
+	asn1p_expr_t *v;
+	int elements = 0;
+
+	topmost_parent = asn1f_find_terminal_type_ex(arg->asn,
+				arg->mod, expr, 0);
+	if(!topmost_parent) return 0;
+
+	if(!(topmost_parent->expr_type & ASN_CONSTR_MASK))
+		return 0;
+
+	TQ_FOR(v, &(topmost_parent->members), next) {
+		if(v->expr_type != A1TC_EXTENSIBLE)
+			elements++;
+	}
+
+	return elements;
+}
+
+static int
+_emit_member_table(arg_t *arg, asn1p_expr_t *expr) {
+	int save_target;
+	arg_t tmp_arg;
+	char *p;
+
+	OUT("{ ");
+	if(expr->marker) {
+		asn1p_expr_t *tv;
+		int opts = 0;
+		for(tv = expr; tv && tv->marker;
+			tv = TQ_NEXT(tv, next), opts++) {
+			if(tv->expr_type == A1TC_EXTENSIBLE)
+				opts--;
+		}
+		OUT("%d, ", opts);
+	} else {
+		OUT("0, ");
+	}
+	if(expr->Identifier) {
+		OUT("offsetof(struct %s, ", MKID(arg->expr->Identifier));
+		if(arg->expr->expr_type == ASN_CONSTR_CHOICE
+			&& (!UNNAMED_UNIONS)) OUT("choice.");
+		OUT("%s),\n", MKID(expr->Identifier));
+	} else {
+		assert(arg->expr->expr_type == ASN_CONSTR_SET_OF
+			|| arg->expr->expr_type == ASN_CONSTR_SEQUENCE_OF);
+		OUT("0,\n");
+	}
+	INDENT(+1);
+	if(C99_MODE) OUT(".tag = ");
+	_print_tag(arg, expr , NULL);
+	OUT(",\n");
+	if(C99_MODE) OUT(".tag_mode = ");
+	if(expr->tag.tag_class) {
+		if(expr->tag.tag_mode == TM_IMPLICIT)
+		OUT("-1,\t/* IMPLICIT tag at current level */\n");
+		else
+		OUT("+1,\t/* EXPLICIT tag at current level */\n");
+	} else {
+		OUT("0,\n");
+	}
+	if(C99_MODE) OUT(".type = ");
+	OUT("(void *)&asn1_DEF_%s,\n",
+		asn1c_type_name(arg, expr, TNF_SAFE));
+	if(C99_MODE) OUT(".memb_constraints = ");
+	if(expr->constraints) {
+		p = MKID(expr->Identifier);
+		if(!expr->Identifier)
+			p = asn1c_type_name(arg, expr, TNF_SAFE);
+		OUT("memb_%s_constraint,\n", p);
+	} else {
+		OUT("0,\t/* Defer to actual type */\n");
+	}
+	if(C99_MODE) OUT(".name = ");
+	OUT("\"%s\"\n", expr->Identifier ? expr->Identifier : "");
+	OUT("},\n");
+	INDENT(-1);
+
+	if(!expr->constraints)
+		return 0;
+
+	save_target = arg->target->target;
+	REDIR(OT_CODE);
+
+	if(expr->Identifier)
+		p = MKID(expr->Identifier);
+	else
+		p = asn1c_type_name(arg, expr, TNF_SAFE);
+	OUT("static int\n");
+	OUT("memb_%s_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,\n", p);
+	INDENT(+1);
+	OUT("\t\tasn_app_consume_bytes_f *app_errlog, void *app_key) {\n");
+	tmp_arg = *arg;
+	tmp_arg.expr = expr;
+	if(asn1c_emit_constraint_checking_code(&tmp_arg) == 1) {
+		OUT("return td->check_constraints\n");
+		OUT("\t(td, sptr, app_errlog, app_key);\n");
+	}
+	INDENT(-1);
+	OUT("}\n");
+	OUT("\n");
+
+	REDIR(save_target);
+
+	return 0;
+}
diff --git a/libasn1compiler/asn1c_constraint.c b/libasn1compiler/asn1c_constraint.c
index dd54224..cf5416b 100644
--- a/libasn1compiler/asn1c_constraint.c
+++ b/libasn1compiler/asn1c_constraint.c
@@ -1,9 +1,12 @@
 #include "asn1c_internal.h"
 #include "asn1c_constraint.h"
+#include "asn1c_misc.h"
+#include "asn1c_out.h"
 
 #include <asn1fix_crange.h>	/* constraint groker from libasn1fix */
 #include <asn1fix_export.h>	/* other exportable stuff from libasn1fix */
 
+static int asn1c_emit_constraint_tables(arg_t *arg, int got_size);
 static int emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range);
 static int emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype);
 static int emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype);
@@ -22,6 +25,7 @@
 	asn1p_expr_type_e etype;
 	asn1p_constraint_t *ct;
 	int got_something = 0;
+	int produce_st = 0;
 
 	ct = expr->combined_constraints;
 	if(ct == NULL)
@@ -57,6 +61,24 @@
 		}
 	}
 
+	/*
+	 * Do we really need an "*st = sptr" pointer?
+	 */
+	switch(etype) {
+	case ASN_BASIC_INTEGER:
+	case ASN_BASIC_ENUMERATED:
+		if(!(arg->flags & A1C_USE_NATIVE_INTEGERS))
+			produce_st = 1;
+		break;
+	case ASN_BASIC_OCTET_STRING:
+		produce_st = 1;
+			break;
+	default:
+		if(etype & ASN_STRING_MASK)
+			produce_st = 1;
+		break;
+	}
+	if(produce_st)
 	OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier));
 
 	if(r_size || r_value) {
@@ -96,6 +118,13 @@
 	if(r_size)
 		emit_size_determination_code(arg, etype);
 
+	INDENT(-1);
+	REDIR(OT_CTABLES);
+	/* Emit FROM() tables */
+	asn1c_emit_constraint_tables(arg, r_size?1:0);
+	REDIR(OT_CODE);
+	INDENT(+1);
+
 	/*
 	 * Here is an if() {} else {} constaint checking code.
 	 */
@@ -126,6 +155,12 @@
 		}
 		if(!got_something) {
 			OUT("1 /* No applicable constraints whatsoever */");
+			OUT(") {\n");
+			INDENT(-1);
+			INDENTED(OUT("/* Nothing is here. See below */\n"));
+			OUT("}\n");
+			OUT("\n");
+			return 1;
 		}
 	INDENT(-1);
 	OUT(") {\n");
@@ -144,16 +179,19 @@
 	return 0;
 }
 
-int
-asn1c_emit_constraint_tables(arg_t *arg, asn1p_constraint_t *ct) {
+static int
+asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
 	asn1_integer_t range_start;
 	asn1_integer_t range_stop;
 	asn1p_expr_type_e etype;
 	asn1cnst_range_t *range;
+	asn1p_constraint_t *ct;
+	int utf8_full_alphabet_check = 0;
+	int max_table_size = 256;
 	int table[256];
 	int use_table;
 
-	if(!ct) ct = arg->expr->combined_constraints;
+	ct = arg->expr->combined_constraints;
 	if(!ct) return 0;
 
 	etype = _find_terminal_type(arg);
@@ -180,10 +218,21 @@
 	 * Check if we need a test table to check the alphabet.
 	 */
 	use_table = 1;
+	if(range->el_count == 0) {
+		/*
+		 * It's better to have a short if() check
+		 * than waste 4k of table space
+		 */
+		use_table = 0;
+	}
 	if((range_stop - range_start) > 255)
 		use_table = 0;
-	if(range->el_count == 0)
-		use_table = 0;
+	if(etype == ASN_STRING_UTF8String) {
+		if(range_stop >= 0x80)
+			use_table = 0;
+		else
+			max_table_size = 128;
+	}
 
 	if(!ct->_compile_mark)
 		ct->_compile_mark = ++global_compile_mark;
@@ -203,15 +252,15 @@
 			}
 			for(v = r->left.value; v <= r->right.value; v++) {
 				assert((v - range_start) >= 0);
-				assert((v - range_start) < 256);
+				assert((v - range_start) < max_table_size);
 				table[v - range_start] = ++n;
 			}
 		}
 
-		OUT("static int permitted_alphabet_table_%d[256] = {\n",
-			ct->_compile_mark);
 		untl = (range_stop - range_start) + 1;
 		untl += (untl % 16)?16 - (untl % 16):0;
+		OUT("static int permitted_alphabet_table_%d[%d] = {\n",
+			ct->_compile_mark, max_table_size);
 		for(n = 0; n < untl; n++) {
 			OUT("%d,", table[n]?1:0);
 			if(!((n+1) % 16)) {
@@ -238,11 +287,42 @@
 		}
 		OUT("};\n");
 		OUT("\n");
+	} else if(etype == ASN_STRING_UTF8String) {
+		/*
+		 * UTF8String type is a special case in many respects.
+		 */
+		assert(range_stop > 255);	/* This one's unobvious */
+		if(got_size) {
+			/*
+			 * Size has been already determined.
+			 * The UTF8String length checker also checks
+			 * for the syntax validity, so we don't have
+			 * to repeat this process twice.
+			 */
+			ct->_compile_mark = 0;	/* Don't generate code */
+			asn1constraint_range_free(range);
+			return 0;
+		} else {
+			utf8_full_alphabet_check = 1;
+		}
+	} else {
+		/*
+		 * This permitted alphabet check will be
+		 * expressed using conditional statements
+		 * instead of table lookups. Table would be
+		 * to large or otherwise inappropriate (too sparse?).
+		 */
 	}
 
 	OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
 			ct->_compile_mark);
-		INDENT(+1);
+	INDENT(+1);
+	if(utf8_full_alphabet_check) {
+		OUT("if(UTF8String_length((UTF8String_t *)sptr, td->name, \n");
+		OUT("\tapp_errlog, app_key) == -1)\n");
+		OUT("\t\treturn 0; /* Alphabet (sic!) test failed. */\n");
+		OUT("\n");
+	} else {
 		if(use_table) {
 			OUT("int *table = permitted_alphabet_table_%d;\n",
 				ct->_compile_mark);
@@ -250,8 +330,9 @@
 		} else {
 			emit_alphabet_check_loop(arg, range);
 		}
-		OUT("return 1;\n");
-		INDENT(-1);
+	}
+	OUT("return 1;\n");
+	INDENT(-1);
 	OUT("}\n");
 	OUT("\n");
 
@@ -338,6 +419,7 @@
 emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1_integer_t natural_start, asn1_integer_t natural_stop) {
 	int ignore_left;
 	int ignore_right;
+	int generated_something = 0;
 	int i;
 
 	for(i = -1; i < range->el_count; i++) {
@@ -381,9 +463,10 @@
 				(long long)r->right.value);
 		}
 		if(r != range) OUT(")");
+		generated_something = 1;
 	}
 
-	return 0;
+	return generated_something;
 }
 
 static int
@@ -412,16 +495,18 @@
 	case ASN_CONSTR_SEQUENCE_OF:
 		OUT("{ /* Determine the number of elements */\n");
 			INDENT(+1);
-			OUT("A_%s_OF(void) *list;\n",
+			OUT("const A_%s_OF(void) *list;\n",
 				etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
-			OUT("(void *)list = st;\n");
+			OUT("(const void *)list = sptr;\n");
 			OUT("size = list->count;\n");
 			INDENT(-1);
 		OUT("}\n");
 		break;
+	case ASN_BASIC_OCTET_STRING:
+		OUT("size = st->size;\n");
+		break;
 	default:
-		if((etype & ASN_STRING_MASK)
-		|| etype == ASN_BASIC_OCTET_STRING) {
+		if(etype & ASN_STRING_MASK) {
 			OUT("size = st->size;\n");
 			break;
 		} else {
@@ -446,7 +531,7 @@
 	case ASN_BASIC_INTEGER:
 	case ASN_BASIC_ENUMERATED:
 		if(arg->flags & A1C_USE_NATIVE_INTEGERS) {
-			OUT("value = *(int *)st;\n");
+			OUT("value = *(int *)sptr;\n");
 		} else {
 			OUT("if(asn1_INTEGER2long(st, &value)) {\n");
 				INDENT(+1);
@@ -458,7 +543,7 @@
 		}
 		break;
 	case ASN_BASIC_BOOLEAN:
-		OUT("value = (*(int *)st) ? 1 : 0;\n");
+		OUT("value = (*(int *)sptr) ? 1 : 0;\n");
 		break;
 	default:
 		WARNING("Value cannot be determined "
diff --git a/libasn1compiler/asn1c_constraint.h b/libasn1compiler/asn1c_constraint.h
index 481c0b3..7c2ffa8 100644
--- a/libasn1compiler/asn1c_constraint.h
+++ b/libasn1compiler/asn1c_constraint.h
@@ -1,7 +1,6 @@
 #ifndef	_ASN1C_CONSTRAINT_H_
 #define	_ASN1C_CONSTRAINT_H_
 
-int asn1c_emit_constraint_tables(arg_t *arg, asn1p_constraint_t *ct);
 int asn1c_emit_constraint_checking_code(arg_t *arg);
 
 #endif	/* _ASN1C_CONSTRAINT_H_ */
diff --git a/libasn1compiler/asn1c_internal.h b/libasn1compiler/asn1c_internal.h
index 061b936..e6b1852 100644
--- a/libasn1compiler/asn1c_internal.h
+++ b/libasn1compiler/asn1c_internal.h
@@ -33,16 +33,9 @@
 	asn1p_module_t	*mod;
 	asn1p_expr_t	*expr;
 
-	int indent_level;
-	int indented;
 	int embed;
 } arg_t;
 
-#include "asn1c_lang.h"		/* Target language initialization */
-#include "asn1c_misc.h"		/* Miscellaneous functions */
-#include "asn1c_out.h"		/* Handle output during compilation */
-#include "asn1c_save.h"		/* Save compiled output */
-
 /*
  * Logging.
  */
diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c
index ee43696..c30174b 100644
--- a/libasn1compiler/asn1c_misc.c
+++ b/libasn1compiler/asn1c_misc.c
@@ -1,4 +1,6 @@
 #include "asn1c_internal.h"
+#include "asn1c_misc.h"
+
 #include <asn1fix_export.h>
 
 /*
diff --git a/libasn1compiler/asn1c_out.c b/libasn1compiler/asn1c_out.c
index 3954916..fb41871 100644
--- a/libasn1compiler/asn1c_out.c
+++ b/libasn1compiler/asn1c_out.c
@@ -1,4 +1,5 @@
 #include "asn1c_internal.h"
+#include "asn1c_out.h"
 
 /*
  * Add an elementary chunk of target language text
@@ -6,6 +7,7 @@
  */
 int
 asn1c_compiled_output(arg_t *arg, const char *fmt, ...) {
+	struct compiler_stream_destination_s *dst;
 	const char *p;
 	int lf_found;
 	va_list ap;
@@ -20,6 +22,7 @@
 		assert(arg->target->target != OT_ASSERT);
 		return -1;
 	default:
+		dst = &arg->target->destination[arg->target->target];
 		break;
 	}
 
@@ -37,16 +40,16 @@
 	/*
 	 * Print out the indentation.
 	 */
-	if(arg->indented == 0) {
-		int i = arg->indent_level;
-		arg->indented = 1;
+	if(dst->indented == 0) {
+		int i = dst->indent_level;
+		dst->indented = 1;
 		while(i--) {
 			ret = asn1c_compiled_output(arg, "\t");
 			if(ret == -1) return -1;
 		}
 	}
 	if(lf_found)
-		arg->indented = 0;
+		dst->indented = 0;
 
 	/*
 	 * Estimate necessary size.
@@ -80,7 +83,7 @@
 
 	if(arg->target->target == OT_INCLUDES) {
 		out_chunk_t *v;
-		TQ_FOR(v, &(arg->target->targets[OT_INCLUDES]), next) {
+		TQ_FOR(v, &dst->chunks, next) {
 			if(m->len == v->len
 			&& !memcmp(m->buf, v->buf, m->len))
 				break;
@@ -93,7 +96,7 @@
 		}
 	}
 
-	TQ_ADD(&(arg->target->targets[arg->target->target]), m, next);
+	TQ_ADD(&dst->chunks, m, next);
 
 	return 0;
 }
diff --git a/libasn1compiler/asn1c_out.h b/libasn1compiler/asn1c_out.h
index 51582d4..f604687 100644
--- a/libasn1compiler/asn1c_out.h
+++ b/libasn1compiler/asn1c_out.h
@@ -19,15 +19,21 @@
 		OT_DEPS,	/* Dependencies (other than #includes) */
 		OT_TYPE_DECLS,	/* Type declarations */
 		OT_FUNC_DECLS,	/* Function declarations */
-		OT_STAT_DEFS,	/* Static definitions */
+		OT_CTABLES,	/* Constraint tables */
 		OT_CODE,	/* Some code */
+		OT_STAT_DEFS,	/* Static definitions */
 		OT_MAX
 	} target;
-	TQ_HEAD(out_chunk_t) targets[OT_MAX];
+
+	struct compiler_stream_destination_s {
+		TQ_HEAD(out_chunk_t) chunks;
+		int indent_level;
+		int indented;
+	} destination[OT_MAX];
 } compiler_streams_t;
 
 static char *_compiler_stream2str[] __attribute__ ((unused))
-    = { "ASSERT", "INCLUDES", "DEPS", "TYPE-DECLS", "FUNC-DECLS", "STAT-DEFS", "CODE" };
+    = { "ASSERT", "INCLUDES", "DEPS", "TYPE-DECLS", "FUNC-DECLS", "CTABLES", "CODE", "STAT-DEFS" };
 
 int asn1c_compiled_output(arg_t *arg, const char *fmt, ...);
 
@@ -38,19 +44,20 @@
 
 /* Redirect output to a different stream. */
 #define	REDIR(foo)	do { arg->target->target = foo; } while(0)
-
-#define	INDENT(val)		arg->indent_level += (val)
-#define	INDENTED(code)	do {			\
-		INDENT(+1);			\
-		do { code; } while(0);		\
-		INDENT(-1);			\
+#define INDENT_LEVEL	\
+		arg->target->destination[arg->target->target].indent_level
+#define	INDENT(val)	INDENT_LEVEL += (val)
+#define	INDENTED(code)	do {					\
+		INDENT(+1);					\
+		do { code; } while(0);				\
+		INDENT(-1);					\
 	} while(0)
 
-#define	FLAT(code)	do {			\
-		int _il = arg->indent_level;	\
-		arg->indent_level = 0;		\
-		do { code; } while(0);		\
-		arg->indent_level = _il;	\
+#define	FLAT(code)	do {					\
+		int _il = INDENT_LEVEL;				\
+		INDENT_LEVEL = 0;				\
+		do { code; } while(0);				\
+		INDENT_LEVEL = _il;				\
 	} while(0)
 
 #define	EMBED(ev)	do {					\
@@ -68,11 +75,11 @@
 
 /* Output a piece of text into a default stream */
 #define	OUT(fmt, args...)	asn1c_compiled_output(arg, fmt, ##args)
-#define	OUT_NOINDENT(fmt, args...)	do {	\
-	int _saved_indent = arg->indent_level;	\
-	arg->indent_level = 0;			\
-	OUT(fmt, ##args);			\
-	arg->indent_level = _saved_indent;	\
+#define	OUT_NOINDENT(fmt, args...)	do {			\
+	int _saved_indent = INDENT_LEVEL;			\
+	INDENT_LEVEL = 0;					\
+	OUT(fmt, ##args);					\
+	INDENT_LEVEL = _saved_indent;				\
 } while(0)
 
 /* Generate #include line */
diff --git a/libasn1compiler/asn1c_save.c b/libasn1compiler/asn1c_save.c
index 3c63053..add70e1 100644
--- a/libasn1compiler/asn1c_save.c
+++ b/libasn1compiler/asn1c_save.c
@@ -1,6 +1,10 @@
 #include "asn1c_internal.h"
 #include "asn1c_compat.h"
 #include "asn1c_fdeps.h"
+#include "asn1c_lang.h"
+#include "asn1c_misc.h"
+#include "asn1c_save.h"
+#include "asn1c_out.h"
 
 static int asn1c_dump_streams(arg_t *arg, asn1c_fdeps_t *);
 static int asn1c_print_streams(arg_t *arg);
@@ -114,14 +118,14 @@
 
 	for(i = 1; i < OT_MAX; i++) {
 		out_chunk_t *ot;
-		if(TQ_FIRST(&cs->targets[i]) == NULL)
+		if(TQ_FIRST(&cs->destination[i].chunks) == NULL)
 			continue;
 
 		printf("\n/*** <<< %s [%s] >>> ***/\n\n",
 			_compiler_stream2str[i],
 			expr->Identifier);
 
-		TQ_FOR(ot, &(cs->targets[i]), next) {
+		TQ_FOR(ot, &(cs->destination[i].chunks), next) {
 			fwrite(ot->buf, ot->len, 1, stdout);
 		}
 	}
@@ -178,18 +182,18 @@
 
 	fprintf(fp_h, "#include <constr_TYPE.h>\n\n");
 
-	TQ_FOR(ot, &(cs->targets[OT_INCLUDES]), next) {
+	TQ_FOR(ot, &(cs->destination[OT_INCLUDES].chunks), next) {
 		asn1c_activate_dependency(deps, 0, ot->buf);
 		fwrite(ot->buf, ot->len, 1, fp_h);
 	}
 	fprintf(fp_h, "\n");
-	TQ_FOR(ot, &(cs->targets[OT_DEPS]), next)
+	TQ_FOR(ot, &(cs->destination[OT_DEPS].chunks), next)
 		fwrite(ot->buf, ot->len, 1, fp_h);
 	fprintf(fp_h, "\n");
-	TQ_FOR(ot, &(cs->targets[OT_TYPE_DECLS]), next)
+	TQ_FOR(ot, &(cs->destination[OT_TYPE_DECLS].chunks), next)
 		fwrite(ot->buf, ot->len, 1, fp_h);
 	fprintf(fp_h, "\n");
-	TQ_FOR(ot, &(cs->targets[OT_FUNC_DECLS]), next)
+	TQ_FOR(ot, &(cs->destination[OT_FUNC_DECLS].chunks), next)
 		fwrite(ot->buf, ot->len, 1, fp_h);
 
 	fprintf(fp_h, "\n#ifdef __cplusplus\n}\n#endif\n\n"
@@ -197,12 +201,14 @@
 		header_id);
 
 	fprintf(fp_c, "#include <%s.h>\n\n", expr->Identifier);	/* Myself */
-	TQ_FOR(ot, &(cs->targets[OT_STAT_DEFS]), next)
+	TQ_FOR(ot, &(cs->destination[OT_CTABLES].chunks), next)
 		fwrite(ot->buf, ot->len, 1, fp_c);
-	TQ_FOR(ot, &(cs->targets[OT_CODE]), next)
+	TQ_FOR(ot, &(cs->destination[OT_CODE].chunks), next)
+		fwrite(ot->buf, ot->len, 1, fp_c);
+	TQ_FOR(ot, &(cs->destination[OT_STAT_DEFS].chunks), next)
 		fwrite(ot->buf, ot->len, 1, fp_c);
 
-	assert(OT_MAX == 7);
+	assert(OT_MAX == 8);
 
 	fclose(fp_c);
 	fclose(fp_h);
diff --git a/libasn1compiler/asn1compiler.c b/libasn1compiler/asn1compiler.c
index 24e539a..dd51156 100644
--- a/libasn1compiler/asn1compiler.c
+++ b/libasn1compiler/asn1compiler.c
@@ -1,4 +1,7 @@
 #include "asn1c_internal.h"
+#include "asn1c_lang.h"
+#include "asn1c_out.h"
+#include "asn1c_save.h"
 
 static void default_logger_cb(int, const char *fmt, ...);
 static int asn1c_compile_expr(arg_t *arg);
@@ -73,7 +76,7 @@
 	type_cb = asn1_lang_map[expr->meta_type][expr->expr_type].type_cb;
 	if(type_cb) {
 
-		if(arg->indent_level == 0)
+		if(arg->target->destination[OT_TYPE_DECLS].indent_level == 0)
 			OUT("\n");
 
 		DEBUG("Compiling %s at line %d",
@@ -134,7 +137,7 @@
 
 	cs = expr->data;
 	for(i = 0; i < OT_MAX; i++) {
-		TQ_INIT(&(cs->targets[i]));
+		TQ_INIT(&(cs->destination[i].chunks));
 	}
 
 	return 0;