blob: b4685ff78861ad6811745c1f0759f38a0f9b0691 [file] [log] [blame]
Lev Walkin4efbfb72005-02-25 14:20:30 +00001#include "asn1fix_internal.h"
2#include "asn1fix_constraint.h"
3#include "asn1fix_crange.h"
Lev Walkinb45e0672004-08-18 05:42:05 +00004
5#undef FATAL
6#define FATAL(fmt, args...) do { \
7 fprintf(stderr, "FATAL: "); \
8 fprintf(stderr, fmt, ##args); \
9 fprintf(stderr, "\n"); \
10 } while(0)
11
12void
13asn1constraint_range_free(asn1cnst_range_t *cr) {
14 if(cr) {
15 int i;
16 if(cr->elements) {
17 for(i = 0; i < cr->el_count; i++)
18 asn1constraint_range_free(cr->elements[i]);
19 free(cr->elements);
20 }
21 free(cr);
22 }
23}
24#define _range_free(foo) asn1constraint_range_free(foo)
25
26static asn1cnst_range_t *_range_new() {
27 asn1cnst_range_t *r;
28 r = calloc(1, sizeof(*r));
29 if(r) {
30 r->left.type = ARE_MIN;
31 r->right.type = ARE_MAX;
32 }
33 return r;
34}
35
36static void _range_remove_element(asn1cnst_range_t *range, int idx) {
37 assert(idx >= 0 && idx < range->el_count);
38
39 assert(!range->elements[idx]->elements);
40
41 _range_free(range->elements[idx]);
42
43 memmove(&range->elements[idx],
44 &range->elements[idx + 1],
45 (range->el_count - idx - 1)
46 * sizeof(range->elements[0])
47 );
48 range->el_count--;
49 range->elements[range->el_count] = 0; /* JIC */
50
51 if(range->el_count == 0) {
52 range->el_size = 0;
53 free(range->elements);
54 range->elements = 0;
55 }
56}
57
58static int _range_insert(asn1cnst_range_t *into, asn1cnst_range_t *cr) {
59
60 assert(!cr->elements);
61
62 if(into->el_count == into->el_size) {
63 void *p;
64 int n = into->el_size?(into->el_size << 1):4;
65 p = realloc(into->elements, n * sizeof(into->elements[0]));
66 if(p) {
67 into->el_size = n;
68 into->elements = p;
69 } else {
70 assert(p);
71 return -1;
72 }
73 }
74
75 into->elements[into->el_count++] = cr;
76 return 0;
77}
78
79static asn1cnst_range_t *_range_clone(const asn1cnst_range_t *range) {
80 asn1cnst_range_t *clone;
81 int i;
82
83 clone = _range_new();
84 if(!clone) return NULL;
85
86 *clone = *range;
87 clone->elements = 0;
88 clone->el_count = 0;
89 clone->el_size = 0;
90
91 for(i = 0; i < range->el_count; i++) {
92 asn1cnst_range_t *r = _range_clone(range->elements[i]);
93 if(!r || _range_insert(clone, r)) {
94 _range_free(clone);
95 _range_free(r);
96 return NULL;
97 }
98 }
99
100 return clone;
101}
102
103static int
104_edge_compare(const asn1cnst_edge_t *el, const asn1cnst_edge_t *er) {
105
106 switch(el->type) {
107 case ARE_MIN:
108 switch(er->type) {
109 case ARE_MIN: return 0;
110 case ARE_MAX: return -1;
111 case ARE_VALUE: return -1;
112 }
113 break;
114 case ARE_MAX:
115 switch(er->type) {
116 case ARE_MIN: return 1;
117 case ARE_MAX: return 0;
118 case ARE_VALUE: return 1;
119 }
120 break;
121 case ARE_VALUE:
122 switch(er->type) {
123 case ARE_MIN: return 1;
124 case ARE_MAX: return -1;
125 case ARE_VALUE:
126 if(el->value < er->value)
127 return -1;
128 if(el->value > er->value)
129 return 1;
130 return 0;
131 }
132 break;
133 }
134
135 return 0;
136}
137
138static int
139_range_compare(const void *a, const void *b) {
140 const asn1cnst_range_t *ra = *(const asn1cnst_range_t * const *)a;
141 const asn1cnst_range_t *rb = *(const asn1cnst_range_t * const *)b;
142 int ret;
143
144 ret = _edge_compare(&ra->left, &rb->left);
145 if(!ret) {
146 ret = _edge_compare(&ra->right, &rb->right);
147 }
148
149 return ret;
150}
151
152static char *
153_edge_value(const asn1cnst_edge_t *edge) {
154 static char buf[128];
155 *buf = '\0';
156 switch(edge->type) {
157 case ARE_MIN: strcpy(buf, "MIN"); break;
158 case ARE_MAX: strcpy(buf, "MAX"); break;
159 case ARE_VALUE:
Lev Walkinda997b12017-08-04 01:38:41 -0700160 snprintf(buf, sizeof(buf), "%s", asn1p_itoa(edge->value));
Lev Walkin3b2278a2016-01-24 16:43:50 -0800161 break;
162 default:
163 assert(!"edge->type");
Lev Walkinb45e0672004-08-18 05:42:05 +0000164 }
165 return buf;
166}
167
Lev Walkinb45e0672004-08-18 05:42:05 +0000168static int
169_edge_is_within(const asn1cnst_range_t *range, const asn1cnst_edge_t *edge) {
170 int i;
171
172 for(i = -1; i < range->el_count; i++) {
173 const asn1cnst_range_t *r;
174 if(i == -1) {
175 if(range->el_count) continue;
176 r = range;
177 } else {
178 r = range->elements[i];
179 }
180 if(_edge_compare(&r->left, edge) <= 0
181 && _edge_compare(&r->right, edge) >= 0)
182 return 1;
183 }
184
185 return 0;
186}
187
188static int
189_check_edges_within(const asn1cnst_range_t *range, const asn1cnst_range_t *r) {
190
191 if(!_edge_is_within(range, &r->left)) {
192 FATAL("Constraint value %s at line %d "
193 "is not within "
194 "a parent constraint range",
195 _edge_value(&r->left),
196 r->left.lineno
197 );
198 return -1;
199 }
200
201 if(!_edge_is_within(range, &r->right)) {
202 FATAL("Constraint value %s at line %d "
203 "is not within "
204 "a parent constraint range",
205 _edge_value(&r->right),
206 r->right.lineno
207 );
208 return -1;
209 }
210
211 return 0;
212}
213
214static int _range_merge_in(asn1cnst_range_t *into, asn1cnst_range_t *cr) {
215 asn1cnst_range_t *r;
216 int prev_count = into->el_count;
217 int i;
218
Lev Walkined1ce782017-07-31 20:21:47 -0700219 into->not_OER_visible |= cr->not_OER_visible;
Lev Walkinb74ac572004-08-25 02:05:28 +0000220 into->not_PER_visible |= cr->not_PER_visible;
221 into->extensible |= cr->extensible;
Lev Walkined1ce782017-07-31 20:21:47 -0700222 if(into->extensible)
223 into->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +0000224
Lev Walkinb45e0672004-08-18 05:42:05 +0000225 /*
226 * Add the element OR all its children "into".
227 */
228 for(i = -1; i < cr->el_count; i++) {
229
230 if(i == -1) {
231 if(cr->el_count) continue;
232 r = cr;
233 } else {
234 r = cr->elements[i];
235 }
236
237 if(_range_insert(into, r)) {
238 into->el_count = prev_count; /* Undo */
239 return -1;
240 }
241 }
242
243 if(cr->el_count) {
244 cr->el_count = 0;
245 _range_free(cr);
246 } else {
247 /* This range is linked into "into". */
248 }
249
250 return 0;
251}
252
Lev Walkinf6e04b52017-09-11 06:51:21 -0700253enum range_fill_result {
254 RFR_OK,
255 RFR_FAIL,
256 RFR_INCOMPATIBLE
257};
258static enum range_fill_result _range_fill(asn1p_value_t *val, const asn1cnst_range_t *minmax, asn1cnst_edge_t *edge, asn1cnst_range_t *range, enum asn1p_constraint_type_e type, int lineno) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000259 unsigned char *p, *pend;
260
261 edge->lineno = lineno;
262
263 switch(val->type) {
264 case ATV_INTEGER:
265 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
Lev Walkinda997b12017-08-04 01:38:41 -0700266 FATAL("Integer %s value invalid "
Lev Walkinb45e0672004-08-18 05:42:05 +0000267 "for %s constraint at line %d",
Lev Walkinda997b12017-08-04 01:38:41 -0700268 asn1p_itoa(val->value.v_integer),
Lev Walkinb45e0672004-08-18 05:42:05 +0000269 asn1p_constraint_type2str(type), lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700270 return RFR_FAIL;
Lev Walkinb45e0672004-08-18 05:42:05 +0000271 }
272 edge->type = ARE_VALUE;
273 edge->value = val->value.v_integer;
Lev Walkinf6e04b52017-09-11 06:51:21 -0700274 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000275 case ATV_MIN:
276 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
277 FATAL("MIN invalid for %s constraint at line %d",
278 asn1p_constraint_type2str(type), lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700279 return RFR_FAIL;
Lev Walkinb45e0672004-08-18 05:42:05 +0000280 }
281 edge->type = ARE_MIN;
282 if(minmax) *edge = minmax->left;
283 edge->lineno = lineno; /* Restore lineno */
Lev Walkinf6e04b52017-09-11 06:51:21 -0700284 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000285 case ATV_MAX:
286 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
287 FATAL("MAX invalid for %s constraint at line %d",
288 asn1p_constraint_type2str(type), lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700289 return RFR_FAIL;
Lev Walkinb45e0672004-08-18 05:42:05 +0000290 }
291 edge->type = ARE_MAX;
292 if(minmax) *edge = minmax->right;
293 edge->lineno = lineno; /* Restore lineno */
Lev Walkinf6e04b52017-09-11 06:51:21 -0700294 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000295 case ATV_FALSE:
296 case ATV_TRUE:
297 if(type != ACT_EL_RANGE) {
298 FATAL("%s is invalid for %s constraint at line %d",
299 val->type==ATV_TRUE?"TRUE":"FALSE",
300 asn1p_constraint_type2str(type),
301 lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700302 return RFR_FAIL;
Lev Walkinb45e0672004-08-18 05:42:05 +0000303 }
304 edge->type = ARE_VALUE;
305 edge->value = (val->type==ATV_TRUE);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700306 return RFR_OK;
Lev Walkin1e448d32005-03-24 14:26:38 +0000307 case ATV_TUPLE:
308 case ATV_QUADRUPLE:
309 edge->type = ARE_VALUE;
310 edge->value = val->value.v_integer;
Lev Walkinf6e04b52017-09-11 06:51:21 -0700311 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000312 case ATV_STRING:
313 if(type != ACT_CT_FROM)
Lev Walkinf6e04b52017-09-11 06:51:21 -0700314 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000315 break;
Lev Walkin1ef05162004-08-25 00:42:25 +0000316 case ATV_REFERENCED:
Lev Walkinfd97d5e2004-09-15 11:45:44 +0000317 FATAL("Unresolved constraint element \"%s\" at line %d",
Lev Walkin1ef05162004-08-25 00:42:25 +0000318 asn1f_printable_reference(val->value.reference),
319 lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700320 return RFR_FAIL;
321 case ATV_BITVECTOR:
322 /* Value constraint... not supported yet. */
323 /* OER: X.696 (08/2015) #8.2.2i */
324 return RFR_INCOMPATIBLE;
Lev Walkinb45e0672004-08-18 05:42:05 +0000325 default:
Lev Walkinf6e04b52017-09-11 06:51:21 -0700326 FATAL("Unrecognized constraint range element type %d at line %d",
327 val->type, lineno);
328 return RFR_FAIL;
Lev Walkinb45e0672004-08-18 05:42:05 +0000329 }
330
331 assert(val->type == ATV_STRING);
332
333 p = val->value.string.buf;
334 pend = p + val->value.string.size;
Lev Walkinf6e04b52017-09-11 06:51:21 -0700335 if(p == pend) return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000336
337 edge->type = ARE_VALUE;
338 if(val->value.string.size == 1) {
339 edge->value = *p;
340 } else {
341 /*
342 * Else this is a set:
343 * (FROM("abcdef"))
344 * However, (FROM("abc".."def")) is forbidden.
345 * See also 47.4.4.
346 */
Lev Walkinb8108ec2004-09-29 13:17:17 +0000347 asn1c_integer_t vmin, vmax;
Lev Walkinb45e0672004-08-18 05:42:05 +0000348 vmin = vmax = *p;
349 for(; p < pend; p++) {
350 asn1cnst_range_t *nr = _range_new();
351 int ret;
352 assert(nr);
353
354 if(*p < vmin) vmin = *p;
355 if(*p > vmax) vmax = *p;
356
357 ret = _range_insert(range, nr);
358 assert(ret == 0);
359
360 nr->left.type = ARE_VALUE;
361 nr->left.value = *p;
362 nr->left.lineno = lineno;
363 nr->right = nr->left;
364 }
365 edge->value = (edge == &range->right) ? vmin : vmax;
366 }
367
Lev Walkinf6e04b52017-09-11 06:51:21 -0700368 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000369}
370
371/*
372 * Check if ranges contain common elements.
373 */
374static int
375_range_overlap(const asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
376 int lr, rl;
377 const asn1cnst_edge_t *ra_l = &ra->left;
378 const asn1cnst_edge_t *ra_r = &ra->right;
379 const asn1cnst_edge_t *rb_l = &rb->left;
380 const asn1cnst_edge_t *rb_r = &rb->right;
381
382 assert(_edge_compare(ra_l, ra_r) <= 0);
383 assert(_edge_compare(rb_l, rb_r) <= 0);
384
385 lr = _edge_compare(ra_l, rb_r);
386 rl = _edge_compare(ra_r, rb_l);
387
388 /*
389 * L: |---|
390 * R: |---|
391 */
392 if(lr > 0) return 0;
393
394 /*
395 * L: |---|
396 * R: |---|
397 */
398 if(rl < 0) return 0;
399
400 return 1;
401}
402
Lev Walkin3b2278a2016-01-24 16:43:50 -0800403
404static int _range_partial_compare(const void *pa, const void *pb) {
405 const asn1cnst_range_t *ra = *(const void * const *)pa;
406 const asn1cnst_range_t *rb = *(const void * const *)pb;
407
408 return _edge_compare(&ra->left, &rb->left);
409}
410
411static void _range_partial_sort_elements(asn1cnst_range_t *r) {
412 qsort(r->elements, r->el_count, sizeof(r->elements[0]),
413 _range_partial_compare);
414}
415
Lev Walkinb45e0672004-08-18 05:42:05 +0000416/*
417 * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
418 */
419static asn1cnst_range_t *
420_range_split(asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
421 asn1cnst_range_t *range, *nr;
422 int ll, rr;
423
424 assert(ra);
425 assert(rb);
426 assert(!ra->el_count);
427 assert(!rb->el_count);
428
429 if(!_range_overlap(ra, rb)) {
430 errno = 0;
431 return 0;
432 }
433
434 ll = _edge_compare(&ra->left, &rb->left);
435 rr = _edge_compare(&ra->right, &rb->right);
436
437 /*
438 * L: |---|
439 * R: |-------|
440 */
441 if(ll >= 0 && rr <= 0) {
442 errno = 0;
443 return 0;
444 }
445
446 range = _range_new();
447 assert(range);
448
449 nr = _range_new();
450 assert(nr);
451
452 /*
453 * L: |---...
454 * R: |--..
455 */
Lev Walkin88693e82005-05-17 21:46:18 +0000456 while(ll < 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000457 nr->left = ra->left;
458 nr->right = rb->left;
Lev Walkin88693e82005-05-17 21:46:18 +0000459 if(nr->right.type == ARE_VALUE) {
Lev Walkin3b2278a2016-01-24 16:43:50 -0800460 if(nr->right.value == INTMAX_MIN) {
Lev Walkin88693e82005-05-17 21:46:18 +0000461 /* We've hit the limit here. */
462 break;
463 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000464 nr->right.value--;
Lev Walkin88693e82005-05-17 21:46:18 +0000465 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000466 _range_insert(range, nr);
467 nr = _range_new();
468 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000469 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000470 }
471
472 /*
473 * L: ...---|
474 * R: ..--|
475 */
Lev Walkin88693e82005-05-17 21:46:18 +0000476 while(rr > 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000477 nr->left = rb->right;
478 nr->right = ra->right;
Lev Walkin88693e82005-05-17 21:46:18 +0000479 if(nr->left.type == ARE_VALUE) {
Lev Walkin3b2278a2016-01-24 16:43:50 -0800480 if(nr->left.value == INTMAX_MAX) {
Lev Walkin88693e82005-05-17 21:46:18 +0000481 /* We've hit the limit here. */
482 break;
483 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000484 nr->left.value++;
Lev Walkin88693e82005-05-17 21:46:18 +0000485 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000486 _range_insert(range, nr);
487 nr = _range_new();
488 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000489 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000490 }
491
492 /*
493 * L: |---|
494 * R: |-----|
495 */
496 nr->left = ra->left;
497 nr->right = ra->right;
498 if(_edge_compare(&ra->left, &rb->left) < 0)
499 nr->left = rb->left;
500 if(_edge_compare(&ra->right, &rb->right) > 0)
501 nr->right = rb->right;
502
503 _range_insert(range, nr);
504
Lev Walkin3b2278a2016-01-24 16:43:50 -0800505 _range_partial_sort_elements(range);
506
Lev Walkinb45e0672004-08-18 05:42:05 +0000507 return range;
508}
509
510static int
Lev Walkined1ce782017-07-31 20:21:47 -0700511_range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int strict_edge_check, int is_oer) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000512 int ret;
513 int i, j;
514
Lev Walkinb74ac572004-08-25 02:05:28 +0000515 assert(!range->incompatible);
516
Lev Walkined1ce782017-07-31 20:21:47 -0700517 if(is_oer) {
518 assert(range->extensible == 0);
519 assert(range->not_OER_visible == 0);
520 assert(with->extensible == 0);
521 assert(with->not_OER_visible == 0);
522 if(range->extensible) {
523 assert(range->not_OER_visible);
524 }
525 if(range->extensible || range->not_OER_visible) {
526 /* X.696 #8.2.4 Completely ignore the extensible constraints */
527 /* (XXX)(YYY,...) Retain the first one (XXX). */
528 asn1cnst_range_t *tmp = _range_new();
529 *tmp = *range;
530 *range = *with;
531 _range_free(tmp);
532 return 0;
533 }
534
535 if(with->extensible) {
536 assert(with->not_OER_visible);
537 }
538 if(with->extensible || with->not_OER_visible) {
539 /* X.696 #8.2.4 Completely ignore the extensible constraints */
540 return 0;
541 }
542 } else {
543 /* Propagate errors */
544 range->extensible |= with->extensible;
545 if(with->extensible)
546 range->not_OER_visible = 1;
547 range->not_PER_visible |= with->not_PER_visible;
548 }
Lev Walkinb74ac572004-08-25 02:05:28 +0000549 range->empty_constraint |= with->empty_constraint;
550
551 if(range->empty_constraint) {
552 /* No use in intersecting empty constraints */
Lev Walkinb45e0672004-08-18 05:42:05 +0000553 return 0;
554 }
555
556 /*
557 * This is an AND operation.
558 */
559
560 /* If this is the only element, insert it into itself as a child */
561 if(range->el_count == 0) {
562 asn1cnst_range_t *r = _range_new();
563 r->left = range->left;
564 r->right = range->right;
565 _range_insert(range, r);
566 assert(range->el_count == 1);
567 }
568
569 /*
570 * Make sure we're dealing with sane data.
571 * G.4.2.3
572 */
573 if(strict_edge_check) {
574 for(j = -1; j < with->el_count; j++) {
575
576 if(j == -1) {
577 if(with->el_count) continue;
578 if(_check_edges_within(range, with))
579 return -1;
580 } else {
581 if(_check_edges_within(range,
582 with->elements[j]))
583 return -1;
584 }
585 }
586 }
587
588 /*
589 * Split range in pieces.
590 */
591
592 for(i = 0; i < range->el_count; i++) {
593 for(j = -1; j < with->el_count; j++) {
594 const asn1cnst_range_t *wel;
595 asn1cnst_range_t *r;
596
597 if(j == -1) {
598 if(with->el_count) continue;
599 wel = with;
600 } else {
601 wel = with->elements[j];
Lev Walkin88693e82005-05-17 21:46:18 +0000602 assert(!wel->el_count); /* non-compound item! */
Lev Walkinb45e0672004-08-18 05:42:05 +0000603 }
604
605 r = _range_split(range->elements[i], wel);
606 if(r) {
607 int ec;
608 /* Substitute the current element with a split */
609 _range_remove_element(range, i);
610 assert(r->el_count);
611 for(ec = 0; ec < r->el_count; ec++) {
612 ret = _range_insert(range, r->elements[ec]);
613 assert(ret == 0);
614 }
615 r->el_count = 0;
616 _range_free(r);
617 i--;
618 break; /* Try again from this point */
619 }
620 }
621 }
622
623 assert(range->el_count);
624
625 /*
626 * Remove pieces which aren't AND-compatible "with" range.
627 */
628
629 for(i = 0; i < range->el_count; i++) {
630 for(j = -1; j < with->el_count; j++) {
631 const asn1cnst_range_t *wel;
632
633 if(j == -1) {
634 if(with->el_count) continue;
635 wel = with;
636 } else {
637 wel = with->elements[j];
638 }
639
640 if(_range_overlap(range->elements[i], wel))
641 break;
642 }
643 if(j == with->el_count) {
644 _range_remove_element(range, i);
645 i--;
646 }
647 }
648
649 if(range->el_count == 0)
650 range->empty_constraint = 1;
651
652 return 0;
653}
654
655static int
656_range_union(asn1cnst_range_t *range) {
657 int i;
658
659 qsort(range->elements, range->el_count, sizeof(range->elements[0]),
660 _range_compare);
661
662 /*
663 * The range is sorted by the start values.
664 */
665 for(i = 1; i < range->el_count; i++) {
666 asn1cnst_range_t *ra = range->elements[i - 1];
667 asn1cnst_range_t *rb = range->elements[i];
668
669 if(_range_overlap(ra, rb)) {
670 if(_edge_compare(&ra->left, &rb->left) < 0)
671 rb->left = ra->left;
672
673 if(_edge_compare(&ra->right, &rb->right) > 0)
674 rb->right = ra->right;
675 } else {
676 /*
677 * Still, range may be joined: (1..4)(5..10).
678 * This logic is valid only for whole numbers
679 * (i.e., not REAL type, but REAL constraints
Lev Walkinb74ac572004-08-25 02:05:28 +0000680 * are not PER-visible (X.691, #9.3.12).
Lev Walkinb45e0672004-08-18 05:42:05 +0000681 */
682 if(ra->right.type == ARE_VALUE
683 && rb->left.type == ARE_VALUE
684 && (rb->left.value - ra->right.value) == 1) {
685 /* (1..10) */
686 rb->left = ra->left;
687 } else {
688 continue;
689 }
690 }
691
692 /*
693 * Squeeze the array by removing the ra.
694 */
695 _range_remove_element(range, i - 1);
696
697 i--; /* Retry from the current point */
698 }
699
700 return 0;
701}
702
703static int
704_range_canonicalize(asn1cnst_range_t *range) {
705
706 if(range->el_count == 0) {
707 /*
708 * Switch left and right edges, make them sorted.
709 * It might be a mild warning though.
710 */
711 if(_edge_compare(&range->left, &range->right) > 0) {
712 asn1cnst_edge_t tmp = range->left;
713 range->left = range->right;
714 range->right = tmp;
715 }
716
Markus Elfringf3d18612016-03-15 08:35:24 +0100717 free(range->elements);
718 range->elements = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000719 range->el_size = 0;
720 return 0;
721 }
722
723 /*
724 * Remove duplicates and overlaps by merging them in.
725 */
726 _range_union(range);
727
728 /* Refine the left edge of a parent */
729 range->left = range->elements[0]->left;
730
731 /* Refine the right edge of a parent */
732 range->right = range->elements[range->el_count - 1]->right;
733
734 /* Remove the child, if it's a single one */
735 if(range->el_count == 1) {
736 _range_remove_element(range, 0);
737 }
738
739 return 0;
740}
741
742asn1cnst_range_t *
Lev Walkined1ce782017-07-31 20:21:47 -0700743asn1constraint_compute_OER_range(const char *dbg_name, asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e requested_ct_type, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
Lev Walkina28cbb92017-07-31 20:20:17 -0700744 return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags | CPR_strict_OER_visibility);
Lev Walkin98eabc12017-07-19 08:51:11 +0400745}
746
747asn1cnst_range_t *
Lev Walkined1ce782017-07-31 20:21:47 -0700748asn1constraint_compute_PER_range(const char *dbg_name, asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e requested_ct_type, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
Lev Walkina28cbb92017-07-31 20:20:17 -0700749 if(0) return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags | CPR_strict_PER_visibility);
750 /* Due to pecularities of PER constraint handling, we don't enable strict PER visibility upfront here. */
751 return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags);
Lev Walkin98eabc12017-07-19 08:51:11 +0400752}
753
754asn1cnst_range_t *
Lev Walkined1ce782017-07-31 20:21:47 -0700755asn1constraint_compute_constraint_range(
756 const char *dbg_name, asn1p_expr_type_e expr_type,
757 const asn1p_constraint_t *ct,
758 enum asn1p_constraint_type_e requested_ct_type,
759 const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
760 asn1cnst_range_t *range;
Lev Walkinb45e0672004-08-18 05:42:05 +0000761 asn1cnst_range_t *tmp;
762 asn1p_value_t *vmin;
763 asn1p_value_t *vmax;
764 int expectation_met;
Lev Walkind541c252004-09-05 10:36:22 +0000765 unsigned int i;
Lev Walkinb45e0672004-08-18 05:42:05 +0000766 int ret;
Lev Walkinb45e0672004-08-18 05:42:05 +0000767
768 if(!exmet) {
769 exmet = &expectation_met;
770 *exmet = 0;
771 }
772
773 /*
Lev Walkinb74ac572004-08-25 02:05:28 +0000774 * Check if the requested constraint is theoretically compatible
775 * with the given expression type.
Lev Walkinb45e0672004-08-18 05:42:05 +0000776 */
Lev Walkined1ce782017-07-31 20:21:47 -0700777 if(asn1constraint_compatible(expr_type, requested_ct_type,
Lev Walkin4b553412005-08-14 14:45:44 +0000778 cpr_flags & CPR_simulate_fbless_SIZE) != 1) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000779 errno = EINVAL;
780 return 0;
781 }
782
Lev Walkined1ce782017-07-31 20:21:47 -0700783 /*
784 * Check arguments' validity.
785 */
786 switch(requested_ct_type) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000787 case ACT_EL_RANGE:
788 if(exmet == &expectation_met)
789 *exmet = 1;
790 break;
791 case ACT_CT_FROM:
Lev Walkin98eabc12017-07-19 08:51:11 +0400792 if(cpr_flags & CPR_strict_OER_visibility) {
793 errno = EINVAL;
794 return 0;
795 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000796 if(!minmax) {
797 minmax = asn1constraint_default_alphabet(expr_type);
798 if(minmax) {
799 break;
800 }
801 }
802 /* Fall through */
803 case ACT_CT_SIZE:
804 if(!minmax) {
805 static asn1cnst_range_t mm;
806 mm.left.type = ARE_VALUE;
807 mm.left.value = 0;
808 mm.right.type = ARE_MAX;
809 minmax = &mm;
810 }
811 break;
812 default:
813 errno = EINVAL;
814 return 0;
815 }
816
817 if(minmax) {
818 range = _range_clone(minmax);
819 } else {
820 range = _range_new();
821 }
822
Lev Walkinb74ac572004-08-25 02:05:28 +0000823 /*
824 * X.691, #9.3.6
Lev Walkin98eabc12017-07-19 08:51:11 +0400825 * Constraints on restricted character string types
Lev Walkinb74ac572004-08-25 02:05:28 +0000826 * which are not known-multiplier are not PER-visible.
827 */
828 if((expr_type & ASN_STRING_NKM_MASK))
829 range->not_PER_visible = 1;
830
Lev Walkin98eabc12017-07-19 08:51:11 +0400831 if(!ct
832 || (range->not_PER_visible && (cpr_flags & CPR_strict_PER_visibility)))
833 return range;
834
835 /*
836 * X.696 (08/2015), #8.2.2
837 * SIZE constraints on restricted character string types
838 * which are not known-multiplier are not OER-visible.
839 */
Lev Walkined1ce782017-07-31 20:21:47 -0700840 if(requested_ct_type == ACT_CT_SIZE && (expr_type & ASN_STRING_NKM_MASK))
Lev Walkin98eabc12017-07-19 08:51:11 +0400841 range->not_OER_visible = 1;
842
843 if(!ct
844 || (range->not_OER_visible && (cpr_flags & CPR_strict_OER_visibility)))
845 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +0000846
847 switch(ct->type) {
848 case ACT_EL_VALUE:
849 vmin = vmax = ct->value;
850 break;
851 case ACT_EL_RANGE:
852 case ACT_EL_LLRANGE:
853 case ACT_EL_RLRANGE:
854 case ACT_EL_ULRANGE:
855 vmin = ct->range_start;
856 vmax = ct->range_stop;
857 break;
858 case ACT_EL_EXT:
859 if(!*exmet) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000860 range->incompatible = 1;
Lev Walkined1ce782017-07-31 20:21:47 -0700861 range->extensible = 1;
862 range->not_OER_visible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000863 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000864 _range_free(range);
865 errno = ERANGE;
866 range = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000867 }
868 return range;
869 case ACT_CT_SIZE:
870 case ACT_CT_FROM:
Lev Walkined1ce782017-07-31 20:21:47 -0700871 if(requested_ct_type == ct->type) {
872 /*
873 * Specifically requested to process SIZE() or FROM() constraint.
874 */
Lev Walkinb45e0672004-08-18 05:42:05 +0000875 *exmet = 1;
876 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000877 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000878 return range;
879 }
880 assert(ct->el_count == 1);
Lev Walkined1ce782017-07-31 20:21:47 -0700881 tmp = asn1constraint_compute_constraint_range(
882 dbg_name, expr_type, ct->elements[0], requested_ct_type, minmax,
883 exmet, cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +0000884 if(tmp) {
885 _range_free(range);
886 } else {
887 if(errno == ERANGE) {
888 range->empty_constraint = 1;
889 range->extensible = 1;
Lev Walkined1ce782017-07-31 20:21:47 -0700890 if(range->extensible)
891 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +0000892 tmp = range;
893 } else {
894 _range_free(range);
895 }
896 }
897 return tmp;
Lev Walkinb45e0672004-08-18 05:42:05 +0000898 case ACT_CA_SET: /* (10..20)(15..17) */
899 case ACT_CA_INT: /* SIZE(1..2) ^ FROM("ABCD") */
900
901 /* AND constraints, one after another. */
902 for(i = 0; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -0700903 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -0700904 ct->elements[i], requested_ct_type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000905 ct->type==ACT_CA_SET?range:minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000906 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000907 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000908 if(errno == ERANGE) {
Lev Walkined1ce782017-07-31 20:21:47 -0700909 range->extensible = 1;
910 if(range->extensible)
911 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +0000912 continue;
913 } else {
914 _range_free(range);
915 return NULL;
916 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000917 }
918
Lev Walkinb74ac572004-08-25 02:05:28 +0000919 if(tmp->incompatible) {
920 /*
921 * Ignore constraints
922 * incompatible with arguments:
923 * SIZE(1..2) ^ FROM("ABCD")
924 * either SIZE or FROM will be ignored.
925 */
926 _range_free(tmp);
927 continue;
928 }
929
Lev Walkin98eabc12017-07-19 08:51:11 +0400930 if(tmp->not_OER_visible
931 && (cpr_flags & CPR_strict_OER_visibility)) {
932 /*
933 * Ignore not OER-visible
934 */
935 _range_free(tmp);
936 continue;
937 }
938
Lev Walkin4b553412005-08-14 14:45:44 +0000939 if(tmp->not_PER_visible
940 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000941 if(ct->type == ACT_CA_SET) {
942 /*
943 * X.691, #9.3.18:
944 * Ignore this separate component.
945 */
946 } else {
947 /*
948 * X.691, #9.3.19:
949 * Ignore not PER-visible INTERSECTION
950 */
951 }
952 _range_free(tmp);
953 continue;
954 }
955
Lev Walkinb45e0672004-08-18 05:42:05 +0000956 ret = _range_intersection(range, tmp,
Lev Walkined1ce782017-07-31 20:21:47 -0700957 ct->type == ACT_CA_SET, cpr_flags & CPR_strict_OER_visibility);
Lev Walkinb45e0672004-08-18 05:42:05 +0000958 _range_free(tmp);
959 if(ret) {
960 _range_free(range);
961 errno = EPERM;
962 return NULL;
963 }
Lev Walkined1ce782017-07-31 20:21:47 -0700964
Lev Walkinb45e0672004-08-18 05:42:05 +0000965 _range_canonicalize(range);
966 }
967
968 return range;
969 case ACT_CA_CSV: /* SIZE(1..2, 3..4) */
970 case ACT_CA_UNI: /* SIZE(1..2) | FROM("ABCD") */
971
Lev Walkinb74ac572004-08-25 02:05:28 +0000972 /*
973 * Grab the first valid constraint.
974 */
975 tmp = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000976 for(i = 0; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -0700977 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -0700978 ct->elements[i], requested_ct_type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000979 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000980 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000981 if(errno == ERANGE) {
982 range->extensible = 1;
Lev Walkined1ce782017-07-31 20:21:47 -0700983 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +0000984 continue;
985 } else {
986 _range_free(range);
987 return NULL;
988 }
989 }
990 if(tmp->incompatible) {
991 _range_free(tmp);
992 tmp = 0;
993 }
994 break;
995 }
996 if(tmp) {
997 tmp->extensible |= range->extensible;
Lev Walkined1ce782017-07-31 20:21:47 -0700998 tmp->not_OER_visible |= range->not_OER_visible;
Lev Walkinb74ac572004-08-25 02:05:28 +0000999 tmp->empty_constraint |= range->empty_constraint;
1000 _range_free(range);
1001 range = tmp;
1002 } else {
1003 range->incompatible = 1;
1004 return range;
1005 }
1006
1007 /*
1008 * Merge with the rest of them.
1009 * Canonicalizator will do the union magic.
1010 */
1011 for(; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -07001012 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -07001013 ct->elements[i], requested_ct_type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +00001014 cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +00001015 if(!tmp) {
1016 if(errno == ERANGE) {
1017 range->extensible = 1;
Lev Walkined1ce782017-07-31 20:21:47 -07001018 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +00001019 continue;
1020 } else {
1021 _range_free(range);
1022 return NULL;
1023 }
1024 }
1025
1026 if(tmp->incompatible) {
1027 _range_free(tmp);
1028 _range_canonicalize(range);
1029 range->incompatible = 1;
1030 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +00001031 }
1032
1033 if(tmp->empty_constraint) {
Lev Walkinb74ac572004-08-25 02:05:28 +00001034 /*
1035 * Ignore empty constraints in OR logic.
1036 */
1037 range->extensible |= tmp->extensible;
Lev Walkined1ce782017-07-31 20:21:47 -07001038 range->not_OER_visible |= tmp->not_OER_visible;
Lev Walkinb45e0672004-08-18 05:42:05 +00001039 _range_free(tmp);
1040 continue;
1041 }
1042
Lev Walkinb45e0672004-08-18 05:42:05 +00001043 _range_merge_in(range, tmp);
1044 }
1045
1046 _range_canonicalize(range);
1047
Lev Walkined1ce782017-07-31 20:21:47 -07001048 if(requested_ct_type == ACT_CT_FROM) {
Lev Walkin98eabc12017-07-19 08:51:11 +04001049 /*
1050 * X.696 permitted alphabet constraints are not OER-visible.
1051 */
1052 range->not_OER_visible = 1;
1053 if(range->extensible) {
1054 /*
1055 * X.691, #9.3.10:
1056 * Extensible permitted alphabet constraints
1057 * are not PER-visible.
1058 */
1059 range->not_PER_visible = 1;
1060 }
1061 }
Lev Walkinb74ac572004-08-25 02:05:28 +00001062
Lev Walkin4b553412005-08-14 14:45:44 +00001063 if(range->not_PER_visible
1064 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +00001065 /*
1066 * X.691, #9.3.19:
1067 * If not PER-visible constraint is part of UNION,
Lev Walkinb74ac572004-08-25 02:05:28 +00001068 * the whole resulting constraint is not PER-visible.
Lev Walkinb45e0672004-08-18 05:42:05 +00001069 */
1070 _range_free(range);
1071 if(minmax)
1072 range = _range_clone(minmax);
1073 else
1074 range = _range_new();
Lev Walkinb74ac572004-08-25 02:05:28 +00001075 range->not_PER_visible = 1;
1076 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001077 }
1078
1079 return range;
1080 case ACT_CA_EXC: /* FROM("ABCD") EXCEPT FROM("AB") */
1081 /*
Lev Walkindbdc0672017-07-26 18:55:30 -07001082 * X.691 (PER), #9.3.19:
Lev Walkinb45e0672004-08-18 05:42:05 +00001083 * EXCEPT and the following value set is completely ignored.
Lev Walkindbdc0672017-07-26 18:55:30 -07001084 * X.696 (OER), #8.2.6:
1085 * EXCEPT keyword and the following value set is completely ignored.
Lev Walkinb45e0672004-08-18 05:42:05 +00001086 */
1087 assert(ct->el_count >= 1);
1088 _range_free(range);
Lev Walkina28cbb92017-07-31 20:20:17 -07001089 range = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -07001090 ct->elements[0], requested_ct_type, minmax, exmet, cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +00001091 return range;
1092 default:
Lev Walkinb74ac572004-08-25 02:05:28 +00001093 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001094 return range;
1095 }
1096
Lev Walkinb45e0672004-08-18 05:42:05 +00001097 if(!*exmet) {
1098 /*
1099 * Expectation is not met. Return the default range.
1100 */
Lev Walkinb74ac572004-08-25 02:05:28 +00001101 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001102 return range;
1103 }
1104
1105 _range_free(range);
1106 range = _range_new();
1107
Lev Walkinf6e04b52017-09-11 06:51:21 -07001108 enum range_fill_result rfr;
1109 rfr = _range_fill(vmin, minmax, &range->left,
Lev Walkined1ce782017-07-31 20:21:47 -07001110 range, requested_ct_type, ct->_lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -07001111 if(rfr == RFR_OK) {
1112 rfr = _range_fill(vmax, minmax, &range->right,
1113 range, requested_ct_type, ct->_lineno);
1114 }
1115 switch(rfr) {
1116 case RFR_OK:
1117 break;
1118 case RFR_FAIL:
1119 _range_free(range);
1120 errno = EPERM;
1121 return NULL;
1122 case RFR_INCOMPATIBLE:
1123 range->incompatible = 1;
1124 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +00001125 }
1126
1127 if(minmax) {
1128 asn1cnst_range_t *clone;
1129
1130 clone = _range_clone(minmax);
1131
1132 /* Constrain parent type with given data. */
Lev Walkined1ce782017-07-31 20:21:47 -07001133 ret = _range_intersection(clone, range, 1,
1134 cpr_flags & CPR_strict_OER_visibility);
Lev Walkinb45e0672004-08-18 05:42:05 +00001135 _range_free(range);
1136 if(ret) {
1137 _range_free(clone);
1138 errno = EPERM;
1139 return NULL;
1140 }
1141 range = clone;
1142 }
1143
1144 /*
1145 * Recompute elements's min/max, remove duplicates, etc.
1146 */
1147 _range_canonicalize(range);
1148
1149 return range;
1150}
1151
Lev Walkin3b2278a2016-01-24 16:43:50 -08001152#ifdef UNIT_TEST
1153int main() {
1154 asn1cnst_range_t *ra = _range_new();
1155 asn1cnst_range_t *rb = _range_new();
1156
1157 fprintf(stderr, "Testing (MIN..20) x (10..15) => (MIN..9,10..15,16..20)\n");
1158
1159 /* (MIN..20) */
1160 ra->left.type = ARE_MIN;
1161 ra->right.type = ARE_VALUE; ra->right.value = 20;
1162
1163 /* (10..15) */
1164 rb->left.type = ARE_VALUE; rb->left.value = 10;
1165 rb->right.type = ARE_VALUE; rb->right.value = 15;
1166
1167 /*
1168 * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
1169 */
1170 asn1cnst_range_t *r = _range_split(ra, rb);
1171 assert(r);
1172 assert(r->left.type == ARE_MIN);
1173 assert(r->right.type == ARE_MAX);
1174
1175 assert(r->el_count == 3);
1176 assert(r->elements[0]->elements == NULL);
1177 assert(r->elements[1]->elements == NULL);
1178 assert(r->elements[2]->elements == NULL);
1179
1180 /* (MIN..9) */
1181 fprintf(stderr, "[0].left = %s\n", _edge_value(&r->elements[0]->left));
1182 fprintf(stderr, "[0].right = %s\n", _edge_value(&r->elements[0]->right));
1183 assert(r->elements[0]->left.type == ARE_MIN);
1184 assert(r->elements[0]->right.type == ARE_VALUE);
1185 assert(r->elements[0]->right.value == 9);
1186
1187 /* (10..15) */
1188 fprintf(stderr, "[1].left = %s\n", _edge_value(&r->elements[1]->left));
1189 fprintf(stderr, "[1].right = %s\n", _edge_value(&r->elements[1]->right));
1190 assert(r->elements[1]->left.type == ARE_VALUE);
1191 assert(r->elements[1]->left.value == 10);
1192 assert(r->elements[1]->right.type == ARE_VALUE);
1193 assert(r->elements[1]->right.value == 15);
1194
1195 /* (16..20) */
1196 fprintf(stderr, "[2].left = %s\n", _edge_value(&r->elements[2]->left));
1197 fprintf(stderr, "[2].right = %s\n", _edge_value(&r->elements[2]->right));
1198 assert(r->elements[2]->left.type == ARE_VALUE);
1199 assert(r->elements[2]->left.value == 16);
1200 assert(r->elements[2]->right.type == ARE_VALUE);
1201 assert(r->elements[2]->right.value == 20);
1202
1203 _range_free(r);
1204
1205
1206
1207 fprintf(stderr, "Testing (MIN..20) x (<min>..15) => (<min>..15,16..20)\n");
1208
1209 /* (MIN..20) */
1210 ra->left.type = ARE_MIN;
1211 ra->right.type = ARE_VALUE; ra->right.value = 20;
1212
1213 /* (<INTMAX_MIN>..15) */
1214 rb->left.type = ARE_VALUE; rb->left.value = INTMAX_MIN;
1215 rb->right.type = ARE_VALUE; rb->right.value = 15;
1216
1217 r = _range_split(ra, rb);
1218 assert(r);
1219 assert(r->left.type == ARE_MIN);
1220 assert(r->right.type == ARE_MAX);
1221
1222 assert(r->el_count == 2);
1223 assert(r->elements[0]->elements == NULL);
1224 assert(r->elements[1]->elements == NULL);
1225
1226 /* (<min>..16) */
1227 fprintf(stderr, "[0].left = %s\n", _edge_value(&r->elements[0]->left));
1228 fprintf(stderr, "[0].right = %s\n", _edge_value(&r->elements[0]->right));
1229 assert(r->elements[0]->left.type == ARE_VALUE);
1230 assert(r->elements[0]->left.value == INTMAX_MIN);
1231 assert(r->elements[0]->right.type == ARE_VALUE);
1232 assert(r->elements[0]->right.value == 15);
1233
1234 /* (16..20) */
1235 fprintf(stderr, "[1].left = %s\n", _edge_value(&r->elements[1]->left));
1236 fprintf(stderr, "[1].right = %s\n", _edge_value(&r->elements[1]->right));
1237 assert(r->elements[1]->left.type == ARE_VALUE);
1238 assert(r->elements[1]->left.value == 16);
1239 assert(r->elements[1]->right.type == ARE_VALUE);
1240 assert(r->elements[1]->right.value == 20);
1241
1242 _range_free(r);
1243
1244 return 0;
1245}
1246#endif