aboutsummaryrefslogtreecommitdiffstats
path: root/libasn1compiler/asn1c_misc.c
diff options
context:
space:
mode:
authorLev Walkin <vlm@lionet.info>2005-08-14 02:18:27 +0000
committerLev Walkin <vlm@lionet.info>2005-08-14 02:18:27 +0000
commit082cadcaaa610df424a1327656abb3055c9f6873 (patch)
tree7a875ab66bf5a6ceb92831e06fccd81abe3b656f /libasn1compiler/asn1c_misc.c
parentb02a8835951516edda86f73b1bcffc4904e0f639 (diff)
PER visible constraints are used to select the native representation for INTEGER types
Diffstat (limited to 'libasn1compiler/asn1c_misc.c')
-rw-r--r--libasn1compiler/asn1c_misc.c88
1 files changed, 86 insertions, 2 deletions
diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c
index 8c5bb628..bcf062f3 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 @@ asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
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 @@ asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
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;
+}
+