PER visible constraints are used to select the native representation for INTEGER types


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@957 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index f91da76..d39018e 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -218,29 +218,26 @@
 	asn1p_expr_t *expr = arg->expr;
 	asn1p_expr_t *v;
 	int el_count = expr_elements_count(arg, expr);
-	int eidx = 0;
 
 	if(el_count) {
+		int eidx = 0;
 		REDIR(OT_DEPS);
 		OUT("typedef enum ");
 			out_name_chain(arg, 1);
 		OUT(" {\n");
 		TQ_FOR(v, &(expr->members), next) {
-			switch(v->expr_type) {
-			case A1TC_UNIVERVAL:
-				OUT("\t");
-				out_name_chain(arg, 0);
-				OUT("_%s", MKID(v->Identifier));
-				OUT("\t= %" PRIdASN "%s\n",
-					v->value->value.v_integer,
-					(eidx+1 < el_count) ? "," : "");
-				eidx++;
-				break;
-			default:
+			eidx++;
+			if(v->expr_type != A1TC_UNIVERVAL) {
 				OUT("/* Unexpected BIT STRING element: %s */\n",
 				v->Identifier);
-				break;
+				continue;
 			}
+			OUT("\t");
+			out_name_chain(arg, 0);
+			OUT("_%s", MKID(v->Identifier));
+			OUT("\t= %" PRIdASN "%s\n",
+				v->value->value.v_integer,
+				(eidx < el_count) ? "," : "");
 		}
 		OUT("} ");
 			out_name_chain(arg, 0);
diff --git a/libasn1compiler/asn1c_constraint.c b/libasn1compiler/asn1c_constraint.c
index d75313d..372730f 100644
--- a/libasn1compiler/asn1c_constraint.c
+++ b/libasn1compiler/asn1c_constraint.c
@@ -62,6 +62,9 @@
 	switch(etype) {
 	case ASN_BASIC_INTEGER:
 	case ASN_BASIC_ENUMERATED:
+		if(asn1c_type_fits_long(arg, arg->expr) == FL_NOTFIT)
+			produce_st = 1;
+		break;
 	case ASN_BASIC_REAL:
 		if(!(arg->flags & A1C_USE_NATIVE_TYPES))
 			produce_st = 1;
@@ -556,7 +559,7 @@
 	switch(etype) {
 	case ASN_BASIC_INTEGER:
 	case ASN_BASIC_ENUMERATED:
-		if(arg->flags & A1C_USE_NATIVE_TYPES) {
+		if(asn1c_type_fits_long(arg, arg->expr) != FL_NOTFIT) {
 			OUT("value = *(const long *)sptr;\n");
 		} else {
 			if(r_value->el_count == 0
diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c
index 8c5bb62..bcf062f 100644
--- a/libasn1compiler/asn1c_misc.c
+++ b/libasn1compiler/asn1c_misc.c
@@ -1,7 +1,8 @@
 #include "asn1c_internal.h"
 #include "asn1c_misc.h"
 
-#include <asn1fix_export.h>
+#include <asn1fix_crange.h>	/* constraint groker from libasn1fix */
+#include <asn1fix_export.h>	/* other exportable stuff from libasn1fix */
 
 /*
  * Checks that the given string is not a reserved C/C++ keyword.
@@ -189,7 +190,9 @@
 	case ASN_BASIC_INTEGER:
 	case ASN_BASIC_ENUMERATED:
 	case ASN_BASIC_REAL:
-		if((arg->flags & A1C_USE_NATIVE_TYPES)) {
+		if((expr->expr_type == ASN_BASIC_REAL
+			&& (arg->flags & A1C_USE_NATIVE_TYPES))
+		|| asn1c_type_fits_long(arg, expr)) {
 			switch(_format) {
 			case TNF_CTYPE:
 			case TNF_RSAFE:
@@ -239,3 +242,84 @@
 	return typename;
 }
 
+/*
+ * Check whether the specified INTEGER or ENUMERATED type can be represented
+ * using the generic 'long' type.
+ */
+enum asn1c_fitslong_e
+asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
+	asn1cnst_range_t *range = 0;
+	asn1cnst_edge_t left;
+	asn1cnst_edge_t right;
+	asn1p_expr_t *v;
+
+/*
+ * Since we don't know the sizeof(long) on the possible target platform
+ * which will be compiling the code generated by asn1c, let's play it
+ * simple: long's range is equal to or greater than int32_t.
+ */
+#define	LEFTMIN		INT32_MIN
+#define	RIGHTMAX	INT32_MAX
+
+	/* Descend to the terminal type */
+	expr = asn1f_find_terminal_type_ex(arg->asn, expr);
+	if(expr == 0) return FL_NOTFIT;
+
+	/* The "fits into long" operation is relevant only for integer types */
+	switch(expr->expr_type) {
+	case ASN_BASIC_INTEGER:
+	case ASN_BASIC_ENUMERATED:
+		break;
+	default:
+		return FL_NOTFIT;
+	}
+
+	/*
+	 * First, evaluate the range of explicitly given identifiers.
+	 */
+	TQ_FOR(v, &(expr->members), next) {
+		if(v->expr_type != A1TC_UNIVERVAL)
+			continue;
+		if(v->value->value.v_integer < LEFTMIN
+		|| v->value->value.v_integer > RIGHTMAX)
+			return FL_NOTFIT;
+	}
+
+	/*
+	 * Second, pull up the PER visible range of the INTEGER.
+	 */
+	if(expr->combined_constraints)
+		range = asn1constraint_compute_PER_range(expr->expr_type,
+			expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
+	if(!range
+	|| range->empty_constraint
+	|| range->extensible
+	|| range->incompatible
+	|| range->not_PER_visible
+	) {
+		asn1constraint_range_free(range);
+		return (arg->flags & A1C_USE_NATIVE_TYPES)
+			? FL_FORCED : FL_NOTFIT;
+	}
+
+	left = range->left;
+	right = range->right;
+	asn1constraint_range_free(range);
+
+	/* If some fixed value is outside of target range, not fit */
+	if(left.type == ARE_VALUE
+			&& (left.value < LEFTMIN || left.value > RIGHTMAX))
+		return FL_NOTFIT;
+	if(right.type == ARE_VALUE
+			&& (right.value > RIGHTMAX || right.value < LEFTMIN))
+		return FL_NOTFIT;
+
+	/* If the range is open, fits only if -fnative-types is given */
+	if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
+		return (arg->flags & A1C_USE_NATIVE_TYPES)
+			? FL_FORCED : FL_NOTFIT;
+	}
+
+	return FL_FITSOK;
+}
+
diff --git a/libasn1compiler/asn1c_misc.h b/libasn1compiler/asn1c_misc.h
index eab7567..8da261d 100644
--- a/libasn1compiler/asn1c_misc.h
+++ b/libasn1compiler/asn1c_misc.h
@@ -24,4 +24,19 @@
 };
 char *asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format);
 
+/*
+ * Check whether the specified INTEGER or ENUMERATED type can be represented
+ * using the generic 'long' type.
+ * Return values:
+ * 	FL_NOTFIT:	No, it cannot be represented using long.
+ * 	FL_FITSOK:	It can be represented using long.
+ * 	FL_FORCED:	Probably can't, but -fnative-types is in force.
+ */
+enum asn1c_fitslong_e {
+	FL_NOTFIT,
+	FL_FITSOK,
+	FL_FORCED,
+};
+enum asn1c_fitslong_e asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr);
+
 #endif	/* _ASN1_COMPILER_MISC_H_ */