blob: 8e70c90146d67712a38e4c9df00a8eb22f20a0df [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include "asn1fix_internal.h"
Lev Walkin97bdee22004-06-28 21:21:24 +00002#include "asn1fix.h"
Lev Walkinf15320b2004-06-03 03:38:44 +00003
4char const *
5asn1f_printable_reference(asn1p_ref_t *ref) {
6 if(ref) {
7 asn1p_value_t v;
8
9 v.type = ATV_REFERENCED;
10 v.value.reference = ref;
11
12 return asn1f_printable_value(&v);
13 } else {
14 return "<no ref>";
15 }
16}
17
18char const *
19asn1f_printable_value(asn1p_value_t *v) {
20 static char buf[128];
21 static char *managedptr;
22 static int managedptr_len;
23 int ret;
24
25#define ENSURE(len) do { \
26 if(len >= managedptr_len) { \
27 if(managedptr) \
28 free(managedptr); \
29 managedptr = malloc(len + 1); \
30 if(managedptr) { \
31 managedptr_len = len; \
32 } else { \
33 managedptr_len = 0; \
34 return "<memory allocation error>"; \
35 } \
36 } \
37 } while(0)
38
39 if(v == NULL)
40 return "<no value>";
41
42 switch(v->type) {
43 case ATV_NOVALUE:
44 return "<NO VALUE>";
45 case ATV_REFERENCED:
46 {
47 asn1p_ref_t *ref;
48 char reflen;
49 char *ptr;
50 int i;
51
52 assert(v->value.reference);
53 ref = v->value.reference;
54 reflen = ref->comp_count; /* Number of dots */
55 for(i = 0; i < ref->comp_count; i++)
56 reflen += strlen(ref->components[i].name);
57 /*
58 * Make sure we have a buffer of this size.
59 */
60 ENSURE(reflen);
61
62 /*
63 * Fill-up the buffer.
64 */
65 ptr = managedptr;
66 for(i = 0; i < ref->comp_count; i++) {
67 char *nc;
68 if(i) *ptr++ = '.';
69 for(nc = ref->components[i].name; *nc; nc++)
70 *ptr++ = *nc;
71 }
72 *ptr++ = '\0';
73 assert(reflen == (ptr - managedptr));
74 return managedptr;
75 }
76 case ATV_REAL:
77 ret = snprintf(buf, sizeof(buf), "%f", v->value.v_double);
Lev Walkind9bd7752004-06-05 08:17:50 +000078 if(ret >= (ssize_t)sizeof(buf))
Lev Walkinf15320b2004-06-03 03:38:44 +000079 memcpy(buf + sizeof(buf) - 4, "...", 4);
80 return buf;
81 case ATV_INTEGER:
82 ret = snprintf(buf, sizeof(buf), "%lld",
83 (long long)v->value.v_integer);
Lev Walkind9bd7752004-06-05 08:17:50 +000084 if(ret >= (ssize_t)sizeof(buf))
Lev Walkinf15320b2004-06-03 03:38:44 +000085 memcpy(buf + sizeof(buf) - 4, "...", 4);
86 return buf;
87 case ATV_MIN: return "MIN";
88 case ATV_MAX: return "MAX";
89 case ATV_FALSE: return "FALSE";
90 case ATV_TRUE: return "TRUE";
91 case ATV_STRING:
92 case ATV_UNPARSED:
93 /* Buffer is guaranteed to be null-terminated */
94 assert(v->value.string.buf[v->value.string.size] == '\0');
95 return v->value.string.buf;
96 case ATV_BITVECTOR:
97 {
98 uint8_t *bitvector;
99 char *ptr;
100 int len;
101 int i;
102 /*
103 * Compute number of bytes necessary
104 * to represend the binary value.
105 */
106 int bits = v->value.binary_vector.size_in_bits;
107 len = ((bits%8)?bits:(bits >> 2)) + sizeof("''H");
108 /*
109 * Reallocate managed buffer
110 */
111 ENSURE(len);
112
113 /*
114 * Fill the buffer.
115 */
116 ptr = managedptr;
117 bitvector = v->value.binary_vector.bits;
118 *ptr++ = '\'';
119 if(bits%8) {
120 /*
121 * Dump bit by bit.
122 */
123 for(i = 0; i < bits; i++) {
124 uint8_t uc;
125 uc = bitvector[i>>3];
126 *ptr++ = ((uc >> (7-(i%8)))&1)?'1':'0';
127 }
128 } else {
Lev Walkind9bd7752004-06-05 08:17:50 +0000129 static const char *hextable="0123456789ABCDEF";
Lev Walkinf15320b2004-06-03 03:38:44 +0000130 /*
131 * Dump byte by byte.
132 */
133 for(i = 0; i < (bits >> 3); i++) {
134 *ptr++ = hextable[bitvector[i] >> 4];
135 *ptr++ = hextable[bitvector[i] & 0x0f];
136 }
137 }
138 *ptr++ = '\'';
139 *ptr++ = (bits%8)?'B':'H';
140 *ptr++ = 'H';
141 assert((ptr - managedptr) == len);
142 return managedptr;
143 }
144 }
145
146 return "<some complex value>";
147}
148
149
150/*
151 * Recursively invoke a given function over the given expr and all its
152 * children.
153 */
154int
155asn1f_recurse_expr(arg_t *arg, int (*callback)(arg_t *arg)) {
156 asn1p_expr_t *expr = arg->expr;
157 int rvalue = 0;
158 int ret;
159
160 assert(expr);
161
162 /*
163 * Invoke the callback at this very level.
164 */
165 ret = callback(arg);
166 RET2RVAL(ret, rvalue);
167
168 /*
169 * Recursively invoke myself
170 * to iterate over each element in the tree.
171 */
172 TQ_FOR(arg->expr, &(expr->members), next) {
173 assert(arg->expr->expr_type != A1TC_INVALID);
Lev Walkin1004aa92004-09-08 00:28:11 +0000174 assert(arg->expr->parent_expr == expr);
Lev Walkinf15320b2004-06-03 03:38:44 +0000175 ret = asn1f_recurse_expr(arg, callback);
176 RET2RVAL(ret, rvalue);
177 }
178
179 arg->expr = expr; /* Restore original position */
180
181 return rvalue;
182}
183
184
185/*
186 * Check that every child of a given expr has unique name or does not have any.
187 */
188int
189asn1f_check_unique_expr(arg_t *arg,
190 int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b)) {
191 asn1p_expr_t *expr;
192 int rvalue = 0;
193
194 TQ_FOR(expr, &(arg->expr->members), next) {
195 if(expr->Identifier) {
196 int ret = asn1f_check_unique_expr_child(arg, expr,
197 opt_compare);
198 if(ret) rvalue = -1;
199 } else {
200 /*
201 * No point of comparing this child with any other:
202 * this one does not have a name.
203 */
204 }
205 }
206
207 return rvalue;
208}
209
210/*
211 * Check that every preceeding child of the given expr is not
212 * having the name of the given one.
213 */
214int
215asn1f_check_unique_expr_child(arg_t *arg, asn1p_expr_t *child,
216 int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b)) {
217 asn1p_expr_t *expr;
218 int rvalue = 0;
219
220 assert(child);
221 assert(opt_compare || child->Identifier);
222
223 TQ_FOR(expr, &(arg->expr->members), next) {
224 int ret;
225
226 if(expr == child)
227 break;
228
229 /*
230 * Compare according to the custom rule or default
231 * names comparisons.
232 */
233 if(opt_compare) {
234 ret = opt_compare(expr, child);
235 } else {
236 if(expr->Identifier == NULL
237 || expr->expr_type == A1TC_EXTENSIBLE)
238 continue;
239 ret = strcasecmp(expr->Identifier, child->Identifier);
240 }
241
242 if(ret == 0) {
243 char *msg;
244 msg = opt_compare
245 ?"Expressions clash"
246 :"Identifiers name clash";
247 arg->eh(1,
248 "%s: "
249 "\"%s\" at line %d has similar %s with "
250 "\"%s\" at line %d",
251 msg,
252 expr->Identifier,
253 expr->_lineno,
254 opt_compare?"property":"name",
255 child->Identifier,
256 child->_lineno
257 );
258
259 rvalue = -1;
260 }
261 }
262
263 return rvalue;
264}
265
266int
267asn1f_count_children(asn1p_expr_t *expr) {
268 asn1p_expr_t *child;
269 int count = 0;
270
271 TQ_FOR(child, &(expr->members), next) {
272 count++;
273 }
274
275 return count;
276}
277
Lev Walkin97bdee22004-06-28 21:21:24 +0000278
279static char **known_types;
280static int known_types_count;
281static int known_types_size;
282
283static int _known_types_cmp(const void *ap, const void *bp) {
284 const char *a = *(const char * const *)ap;
285 const char *b = *(const char * const *)bp;
286 return strcmp(a, b);
287}
288
289int
290asn1f_make_known_external_type(const char *type_name) {
291 char *tname;
292
293 /* Check for duplicates */
294 if(asn1f_check_known_external_type(type_name) == 0) {
295 errno = EEXIST;
296 return -1;
297 }
298
299 /* Ensure enough space */
300 if(known_types_count <= known_types_size) {
301 int n = known_types_size ? known_types_size << 1 : 4;
302 void *p;
303 p = realloc(known_types, n * sizeof(known_types[0]));
304 if(!p) return -1;
305 known_types = p;
306 known_types_size = n;
307 }
308
309 tname = strdup(type_name);
310 if(!tname) return -1;
311
312 known_types[known_types_count++] = tname;
313
314#ifdef HAVE_MERGESORT
315 mergesort
316#else
317 qsort
318#endif
319 (known_types, known_types_count, sizeof(known_types[0]),
320 _known_types_cmp);
321
322 return 0;
323}
324
325int
326asn1f_check_known_external_type(const char *type_name) {
327 void *p = bsearch(&type_name, known_types, known_types_count,
328 sizeof(known_types[0]), _known_types_cmp);
329 if(p) return 0;
330 errno = ESRCH;
331 return -1;
332}
333