ac543f203228ebd78e5fa0a9b8f6fe0ab1028cfc
[com/asn1c.git] / libasn1fix / asn1fix_enum.c
1 #include "asn1fix_internal.h"
2
3 /*
4  * Check the validity of an enumeration.
5  */
6 int
7 asn1f_fix_enum(arg_t *arg) {
8         asn1p_expr_t *expr = arg->expr;
9         asn1p_expr_t *ev;
10         asn1c_integer_t max_value = -1;
11         asn1c_integer_t max_value_ext = -1;
12         int rvalue = 0;
13         asn1p_expr_t *ext_marker = NULL;        /* "..." position */
14         int ret;
15
16         /* Keep track of value collisions */
17         asn1c_integer_t *used_vals;
18         int used_vals_sz = 50;
19         int used_vals_next = 0;
20
21         if(expr->expr_type != ASN_BASIC_ENUMERATED)
22                 return 0;       /* Just ignore it */
23
24         DEBUG("(%s)", expr->Identifier);
25
26         used_vals = (asn1c_integer_t *) malloc(sizeof(asn1c_integer_t) * used_vals_sz);
27         if (!used_vals) {
28                 FATAL("Out of memory");
29                 return -1;
30         }
31
32         /*
33          * 1. Scan the enumeration values in search for inconsistencies.
34          */
35         TQ_FOR(ev, &(expr->members), next) {
36                 asn1c_integer_t eval;
37
38                 if(ev->value)
39                         DEBUG("\tItem %s(%s)", ev->Identifier,
40                                 asn1f_printable_value(ev->value));
41                 else
42                         DEBUG("\tItem %s", ev->Identifier);
43
44                 /*
45                  * 1.1 Found an extension mark "...", check correctness.
46                  */
47                 if(ev->expr_type == A1TC_EXTENSIBLE) {
48                         if(ext_marker) {
49                                 FATAL("Enumeration %s at line %d: "
50                                 "Second extension marker is not allowed",
51                                 expr->Identifier,
52                                 ev->_lineno);
53                                 rvalue = -1;
54                         } else {
55                                 /*
56                                  * Remember the marker's position.
57                                  */
58                                 ext_marker = ev;
59                         }
60                         continue;
61                 } else if(ev->Identifier == NULL
62                         || ev->expr_type != A1TC_UNIVERVAL) {
63                         FATAL(
64                                 "Enumeration %s at line %d: "
65                                 "Unsupported enumeration element %s",
66                                 expr->Identifier,
67                                 ev->_lineno,
68                                 ev->Identifier?ev->Identifier:"<anonymous>");
69                         rvalue = -1;
70                         continue;
71                 }
72
73                 /*
74                  * 1.2 Compute the value of the enumeration element.
75                  */
76                 if(ev->value) {
77                         switch(ev->value->type) {
78                         case ATV_INTEGER:
79                                 eval = ev->value->value.v_integer;
80                                 break;
81                         case ATV_REFERENCED:
82                                 FATAL("HERE HERE HERE", 1);
83                                 rvalue = -1;
84                                 continue;
85                                 break;
86                         default:
87                                 FATAL("ENUMERATED type %s at line %d "
88                                         "contain element %s(%s) at line %d",
89                                         expr->Identifier, expr->_lineno,
90                                         ev->Identifier,
91                                         asn1f_printable_value(ev->value),
92                                         ev->_lineno);
93                                 rvalue = -1;
94                                 continue;
95                         }
96                 } else {
97                         eval = max_value + 1;
98                         ev->value = asn1p_value_fromint(eval);
99                         if(ev->value == NULL) {
100                                 rvalue = -1;
101                                 continue;
102                         }
103                 }
104
105                 /*
106                  * 1.3 Check the applicability of this value.
107                  */
108
109                 /*
110                  * Enumeration is allowed to be unordered
111                  * before the first marker, but after the marker
112                  * the values must be ordered.
113                  */
114                 if (ext_marker) {
115                         if (eval > max_value_ext) {
116                                 max_value_ext = eval;
117                         } else {
118                 char max_value_buf[128];
119                 asn1p_itoa_s(max_value_buf, sizeof(max_value_buf),
120                              max_value_ext);
121                 FATAL(
122                                         "Enumeration %s at line %d: "
123                                         "Explicit value \"%s(%s)\" "
124                                         "is not greater "
125                                         "than previous values (max %s)",
126                                         expr->Identifier,
127                                         ev->_lineno,
128                                         ev->Identifier,
129                                         asn1p_itoa(eval),
130                                         max_value_buf);
131                                 rvalue = -1;
132                         }
133                 }
134
135                 if (eval > max_value) {
136                         max_value = eval;
137                 }
138
139
140                 /*
141                  * 1.4 Check that all identifiers are unique
142                  */
143                 int unique = 1;
144                 int uv_idx;
145                 for (uv_idx = 0; uv_idx < used_vals_next; uv_idx++) {
146                         if (used_vals[uv_idx] == eval) {
147                                 FATAL(
148                                         "Enumeration %s at line %d: "
149                                         "Explicit value \"%s(%s)\" "
150                                         "collides with previous values",
151                                         expr->Identifier,
152                                         ev->_lineno,
153                                         ev->Identifier,
154                                         asn1p_itoa(eval));
155                                 rvalue = -1;
156                                 unique = 0;
157                         }
158                 }
159
160                 if (unique) {
161                         /* Grow the array if needed */
162                         if (used_vals_next >= used_vals_sz) {
163                                 asn1c_integer_t *temp;
164                                 int new_sz = used_vals_sz + 50;
165                                 temp = (asn1c_integer_t *) realloc(used_vals,
166                                                         sizeof(asn1c_integer_t) * new_sz);
167                                 if (!temp) return -1;
168                                 used_vals = temp;
169                                 used_vals_sz = new_sz;
170                         }
171                         used_vals[used_vals_next++] = eval;
172                 }
173
174                 /*
175                  * 1.5 Check that all identifiers before the current one
176                  * differs from it.
177                  */
178                 ret = asn1f_check_unique_expr_child(arg, ev, 0, "identifier");
179                 RET2RVAL(ret, rvalue);
180         }
181
182         free(used_vals);
183
184         /*
185          * 2. Reorder the first half (before optional "...") of the
186          * identifiers alphabetically.
187          */
188         // TODO
189
190         return rvalue;
191 }
192