new constraints generation method

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 "