source: mainline/uspace/app/bithenge/sequence.c@ 0ce0103

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0ce0103 was c3437d9, checked in by Sean Bartell <wingedtachikoma@…>, 13 years ago

Bithenge: add do{}while() transforms

  • Property mode set to 100644
File size: 28.5 KB
Line 
1/*
2 * Copyright (c) 2012 Sean Bartell
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup bithenge
30 * @{
31 */
32/**
33 * @file
34 * Sequence transforms.
35 */
36
37#include <stdlib.h>
38#include "blob.h"
39#include "expression.h"
40#include "os.h"
41#include "sequence.h"
42#include "tree.h"
43
44
45
46/***************** seq_node *****************/
47
48typedef struct {
49 bithenge_node_t base;
50 const struct seq_node_ops *ops;
51 bithenge_blob_t *blob;
52 bithenge_scope_t scope;
53 aoff64_t *ends;
54 size_t num_ends;
55 bool end_on_empty;
56 bithenge_int_t num_xforms;
57} seq_node_t;
58
59typedef struct seq_node_ops {
60 int (*get_transform)(seq_node_t *self, bithenge_transform_t **out,
61 bithenge_int_t index);
62} seq_node_ops_t;
63
64static bithenge_node_t *seq_as_node(seq_node_t *node)
65{
66 return &node->base;
67}
68
69static seq_node_t *node_as_seq(bithenge_node_t *node)
70{
71 return (seq_node_t *)node;
72}
73
74static int seq_node_field_offset(seq_node_t *self, aoff64_t *out, size_t index)
75{
76 if (index == 0) {
77 *out = 0;
78 return EOK;
79 }
80 index--;
81 aoff64_t prev_offset =
82 self->num_ends ? self->ends[self->num_ends - 1] : 0;
83 for (; self->num_ends <= index; self->num_ends++) {
84 bithenge_transform_t *subxform;
85 int rc = self->ops->get_transform(self, &subxform,
86 self->num_ends);
87 if (rc != EOK)
88 return rc;
89
90 bithenge_node_t *subblob_node;
91 bithenge_blob_inc_ref(self->blob);
92 rc = bithenge_new_offset_blob(&subblob_node, self->blob,
93 prev_offset);
94 if (rc != EOK) {
95 bithenge_transform_dec_ref(subxform);
96 return rc;
97 }
98
99 if (self->end_on_empty) {
100 bool empty;
101 rc = bithenge_blob_empty(
102 bithenge_node_as_blob(subblob_node), &empty);
103 if (rc == EOK && empty) {
104 self->num_xforms = self->num_ends;
105 rc = ENOENT;
106 }
107 if (rc != EOK) {
108 bithenge_transform_dec_ref(subxform);
109 bithenge_node_dec_ref(subblob_node);
110 return rc;
111 }
112 }
113
114 bithenge_blob_t *subblob = bithenge_node_as_blob(subblob_node);
115 aoff64_t field_size;
116 rc = bithenge_transform_prefix_length(subxform, &self->scope,
117 subblob, &field_size);
118 bithenge_node_dec_ref(subblob_node);
119 bithenge_transform_dec_ref(subxform);
120 if (rc != EOK)
121 return rc;
122
123 if (self->num_xforms == -1) {
124 aoff64_t *new_ends = realloc(self->ends,
125 (self->num_ends + 1)*sizeof(*new_ends));
126 if (!new_ends)
127 return ENOMEM;
128 self->ends = new_ends;
129 }
130
131 prev_offset = self->ends[self->num_ends] =
132 prev_offset + field_size;
133 }
134 *out = self->ends[index];
135 return EOK;
136}
137
138static int seq_node_subtransform(seq_node_t *self, bithenge_node_t **out,
139 size_t index)
140{
141 aoff64_t start_pos;
142 int rc = seq_node_field_offset(self, &start_pos, index);
143 if (rc != EOK)
144 return rc;
145
146 bithenge_transform_t *subxform;
147 rc = self->ops->get_transform(self, &subxform, index);
148 if (rc != EOK)
149 return rc;
150
151 if (index == self->num_ends) {
152 /* We can apply the subtransform and cache its prefix length at
153 * the same time. */
154 bithenge_node_t *blob_node;
155 bithenge_blob_inc_ref(self->blob);
156 rc = bithenge_new_offset_blob(&blob_node, self->blob,
157 start_pos);
158 if (rc != EOK) {
159 bithenge_transform_dec_ref(subxform);
160 return rc;
161 }
162
163 if (self->end_on_empty) {
164 bool empty;
165 rc = bithenge_blob_empty(
166 bithenge_node_as_blob(blob_node), &empty);
167 if (rc == EOK && empty) {
168 self->num_xforms = self->num_ends;
169 rc = ENOENT;
170 }
171 if (rc != EOK) {
172 bithenge_transform_dec_ref(subxform);
173 bithenge_node_dec_ref(blob_node);
174 return rc;
175 }
176 }
177
178 aoff64_t size;
179 rc = bithenge_transform_prefix_apply(subxform, &self->scope,
180 bithenge_node_as_blob(blob_node), out, &size);
181 bithenge_node_dec_ref(blob_node);
182 bithenge_transform_dec_ref(subxform);
183 if (rc != EOK)
184 return rc;
185
186 if (self->num_xforms == -1) {
187 aoff64_t *new_ends = realloc(self->ends,
188 (self->num_ends + 1)*sizeof(*new_ends));
189 if (!new_ends)
190 return ENOMEM;
191 self->ends = new_ends;
192 }
193 self->ends[self->num_ends++] = start_pos + size;
194 } else {
195 aoff64_t end_pos;
196 int rc = seq_node_field_offset(self, &end_pos, index + 1);
197 if (rc != EOK) {
198 bithenge_transform_dec_ref(subxform);
199 return rc;
200 }
201
202 bithenge_node_t *blob_node;
203 bithenge_blob_inc_ref(self->blob);
204 rc = bithenge_new_subblob(&blob_node, self->blob, start_pos,
205 end_pos - start_pos);
206 if (rc != EOK) {
207 bithenge_transform_dec_ref(subxform);
208 return rc;
209 }
210
211 rc = bithenge_transform_apply(subxform, &self->scope,
212 blob_node, out);
213 bithenge_node_dec_ref(blob_node);
214 bithenge_transform_dec_ref(subxform);
215 if (rc != EOK)
216 return rc;
217 }
218
219 return EOK;
220}
221
222static int seq_node_complete(seq_node_t *self, bool *out)
223{
224 aoff64_t blob_size, end_pos;
225 int rc = bithenge_blob_size(self->blob, &blob_size);
226 if (rc != EOK)
227 return rc;
228 rc = seq_node_field_offset(self, &end_pos, self->num_xforms);
229 if (rc != EOK)
230 return rc;
231 *out = blob_size == end_pos;
232 return EOK;
233}
234
235static void seq_node_destroy(seq_node_t *self)
236{
237 bithenge_scope_destroy(&self->scope);
238 bithenge_blob_dec_ref(self->blob);
239 free(self->ends);
240}
241
242static void seq_node_set_num_xforms(seq_node_t *self,
243 bithenge_int_t num_xforms)
244{
245 self->num_xforms = num_xforms;
246}
247
248static bithenge_scope_t *seq_node_scope(seq_node_t *self)
249{
250 return &self->scope;
251}
252
253static int seq_node_init(seq_node_t *self, const seq_node_ops_t *ops,
254 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_int_t num_xforms,
255 bool end_on_empty)
256{
257 self->ops = ops;
258 if (num_xforms != -1) {
259 self->ends = malloc(sizeof(*self->ends) * num_xforms);
260 if (!self->ends)
261 return ENOMEM;
262 } else
263 self->ends = NULL;
264 bithenge_blob_inc_ref(blob);
265 self->blob = blob;
266 self->num_xforms = num_xforms;
267 self->num_ends = 0;
268 self->end_on_empty = end_on_empty;
269 bithenge_scope_init(&self->scope);
270 int rc = bithenge_scope_copy(&self->scope, scope);
271 if (rc != EOK) {
272 bithenge_scope_destroy(&self->scope);
273 return rc;
274 }
275 return EOK;
276}
277
278
279
280/***************** bithenge_new_struct *****************/
281
282typedef struct {
283 bithenge_transform_t base;
284 bithenge_named_transform_t *subtransforms;
285 size_t num_subtransforms;
286} struct_transform_t;
287
288static bithenge_transform_t *struct_as_transform(struct_transform_t *xform)
289{
290 return &xform->base;
291}
292
293static struct_transform_t *transform_as_struct(bithenge_transform_t *xform)
294{
295 return (struct_transform_t *)xform;
296}
297
298typedef struct {
299 seq_node_t base;
300 struct_transform_t *transform;
301 bool prefix;
302} struct_node_t;
303
304static seq_node_t *struct_as_seq(struct_node_t *node)
305{
306 return &node->base;
307}
308
309static struct_node_t *seq_as_struct(seq_node_t *base)
310{
311 return (struct_node_t *)base;
312}
313
314static bithenge_node_t *struct_as_node(struct_node_t *node)
315{
316 return seq_as_node(struct_as_seq(node));
317}
318
319static struct_node_t *node_as_struct(bithenge_node_t *node)
320{
321 return seq_as_struct(node_as_seq(node));
322}
323
324static int struct_node_for_each(bithenge_node_t *base,
325 bithenge_for_each_func_t func, void *data)
326{
327 int rc = EOK;
328 struct_node_t *self = node_as_struct(base);
329 bithenge_named_transform_t *subxforms =
330 self->transform->subtransforms;
331
332 for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
333 bithenge_node_t *subxform_result;
334 rc = seq_node_subtransform(struct_as_seq(self),
335 &subxform_result, i);
336 if (rc != EOK)
337 return rc;
338
339 if (subxforms[i].name) {
340 bithenge_node_t *name_node;
341 rc = bithenge_new_string_node(&name_node,
342 subxforms[i].name, false);
343 if (rc == EOK) {
344 rc = func(name_node, subxform_result, data);
345 subxform_result = NULL;
346 }
347 } else {
348 if (bithenge_node_type(subxform_result) !=
349 BITHENGE_NODE_INTERNAL) {
350 rc = EINVAL;
351 } else {
352 rc = bithenge_node_for_each(subxform_result,
353 func, data);
354 }
355 }
356 bithenge_node_dec_ref(subxform_result);
357 if (rc != EOK)
358 return rc;
359 }
360
361 if (!self->prefix) {
362 bool complete;
363 rc = seq_node_complete(struct_as_seq(self), &complete);
364 if (rc != EOK)
365 return rc;
366 if (!complete)
367 return EINVAL;
368 }
369
370 return rc;
371}
372
373static int struct_node_get(bithenge_node_t *base, bithenge_node_t *key,
374 bithenge_node_t **out)
375{
376 struct_node_t *self = node_as_struct(base);
377
378 int rc = ENOENT;
379 if (bithenge_node_type(key) != BITHENGE_NODE_STRING)
380 goto end;
381 const char *name = bithenge_string_node_value(key);
382
383 const bithenge_named_transform_t *subxforms =
384 self->transform->subtransforms;
385 for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
386 if (subxforms[i].name && !str_cmp(name, subxforms[i].name)) {
387 rc = seq_node_subtransform(struct_as_seq(self), out, i);
388 goto end;
389 }
390 }
391
392 for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
393 if (subxforms[i].name)
394 continue;
395 bithenge_node_t *subxform_result;
396 rc = seq_node_subtransform(struct_as_seq(self),
397 &subxform_result, i);
398 if (rc != EOK)
399 goto end;
400 if (bithenge_node_type(subxform_result) !=
401 BITHENGE_NODE_INTERNAL) {
402 bithenge_node_dec_ref(subxform_result);
403 rc = EINVAL;
404 goto end;
405 }
406 bithenge_node_inc_ref(key);
407 rc = bithenge_node_get(subxform_result, key, out);
408 bithenge_node_dec_ref(subxform_result);
409 if (rc != ENOENT)
410 goto end;
411 }
412
413 rc = ENOENT;
414end:
415 bithenge_node_dec_ref(key);
416 return rc;
417}
418
419static void struct_node_destroy(bithenge_node_t *base)
420{
421 struct_node_t *node = node_as_struct(base);
422
423 /* We didn't inc_ref for the scope in struct_transform_make_node, so
424 * make sure it doesn't try to dec_ref. */
425 seq_node_scope(struct_as_seq(node))->current_node = NULL;
426 seq_node_destroy(struct_as_seq(node));
427
428 bithenge_transform_dec_ref(struct_as_transform(node->transform));
429 free(node);
430}
431
432static const bithenge_internal_node_ops_t struct_node_ops = {
433 .for_each = struct_node_for_each,
434 .get = struct_node_get,
435 .destroy = struct_node_destroy,
436};
437
438static int struct_node_get_transform(seq_node_t *base,
439 bithenge_transform_t **out, bithenge_int_t index)
440{
441 struct_node_t *self = seq_as_struct(base);
442 *out = self->transform->subtransforms[index].transform;
443 bithenge_transform_inc_ref(*out);
444 return EOK;
445}
446
447static const seq_node_ops_t struct_node_seq_ops = {
448 .get_transform = struct_node_get_transform,
449};
450
451static int struct_transform_make_node(struct_transform_t *self,
452 bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
453 bool prefix)
454{
455 struct_node_t *node = malloc(sizeof(*node));
456 if (!node)
457 return ENOMEM;
458
459 int rc = bithenge_init_internal_node(struct_as_node(node),
460 &struct_node_ops);
461 if (rc != EOK) {
462 free(node);
463 return rc;
464 }
465
466 rc = seq_node_init(struct_as_seq(node), &struct_node_seq_ops, scope,
467 blob, self->num_subtransforms, false);
468 if (rc != EOK) {
469 free(node);
470 return rc;
471 }
472
473 bithenge_transform_inc_ref(struct_as_transform(self));
474 node->transform = self;
475 node->prefix = prefix;
476 *out = struct_as_node(node);
477
478 /* We should inc_ref(*out) here, but that would make a cycle. Instead,
479 * we leave it 1 too low, so that when the only remaining use of *out
480 * is the scope, *out will be destroyed. Also see the comment in
481 * struct_node_destroy. */
482 bithenge_scope_set_current_node(seq_node_scope(struct_as_seq(node)),
483 *out);
484
485 return EOK;
486}
487
488static int struct_transform_apply(bithenge_transform_t *base,
489 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
490{
491 struct_transform_t *self = transform_as_struct(base);
492 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
493 return EINVAL;
494 return struct_transform_make_node(self, out, scope,
495 bithenge_node_as_blob(in), false);
496}
497
498static int struct_transform_prefix_length(bithenge_transform_t *base,
499 bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
500{
501 struct_transform_t *self = transform_as_struct(base);
502 bithenge_node_t *struct_node;
503 int rc = struct_transform_make_node(self, &struct_node, scope, blob,
504 true);
505 if (rc != EOK)
506 return rc;
507
508 rc = seq_node_field_offset(node_as_seq(struct_node), out,
509 self->num_subtransforms);
510 bithenge_node_dec_ref(struct_node);
511 return rc;
512}
513
514static int struct_transform_prefix_apply(bithenge_transform_t *base,
515 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
516 aoff64_t *out_size)
517{
518 struct_transform_t *self = transform_as_struct(base);
519 int rc = struct_transform_make_node(self, out_node, scope, blob,
520 true);
521 if (rc != EOK)
522 return rc;
523
524 rc = seq_node_field_offset(node_as_seq(*out_node), out_size,
525 self->num_subtransforms);
526 if (rc != EOK) {
527 bithenge_node_dec_ref(*out_node);
528 return rc;
529 }
530
531 return EOK;
532}
533
534static void free_subtransforms(bithenge_named_transform_t *subtransforms)
535{
536 for (size_t i = 0; subtransforms[i].transform; i++) {
537 free((void *)subtransforms[i].name);
538 bithenge_transform_dec_ref(subtransforms[i].transform);
539 }
540 free(subtransforms);
541}
542
543static void struct_transform_destroy(bithenge_transform_t *base)
544{
545 struct_transform_t *self = transform_as_struct(base);
546 free_subtransforms(self->subtransforms);
547 free(self);
548}
549
550static bithenge_transform_ops_t struct_transform_ops = {
551 .apply = struct_transform_apply,
552 .prefix_length = struct_transform_prefix_length,
553 .prefix_apply = struct_transform_prefix_apply,
554 .destroy = struct_transform_destroy,
555};
556
557/** Create a struct transform. The transform will apply its subtransforms
558 * sequentially to a blob to create an internal node. Each result is either
559 * given a key from @a subtransforms or, if the name is NULL, the result's keys
560 * and values are merged into the struct transform's result. This function
561 * takes ownership of @a subtransforms and the names and references therein.
562 * @param[out] out Stores the created transform.
563 * @param subtransforms The subtransforms and field names.
564 * @return EOK on success or an error code from errno.h. */
565int bithenge_new_struct(bithenge_transform_t **out,
566 bithenge_named_transform_t *subtransforms)
567{
568 int rc;
569 struct_transform_t *self = malloc(sizeof(*self));
570 if (!self) {
571 rc = ENOMEM;
572 goto error;
573 }
574 rc = bithenge_init_transform(struct_as_transform(self),
575 &struct_transform_ops, 0);
576 if (rc != EOK)
577 goto error;
578 self->subtransforms = subtransforms;
579 self->num_subtransforms = 0;
580 for (self->num_subtransforms = 0;
581 subtransforms[self->num_subtransforms].transform;
582 self->num_subtransforms++);
583 *out = struct_as_transform(self);
584 return EOK;
585error:
586 free_subtransforms(subtransforms);
587 free(self);
588 return rc;
589}
590
591
592
593/***************** bithenge_repeat_transform *****************/
594
595typedef struct {
596 bithenge_transform_t base;
597 bithenge_expression_t *expr;
598 bithenge_transform_t *xform;
599} repeat_transform_t;
600
601static inline bithenge_transform_t *repeat_as_transform(
602 repeat_transform_t *self)
603{
604 return &self->base;
605}
606
607static inline repeat_transform_t *transform_as_repeat(
608 bithenge_transform_t *base)
609{
610 return (repeat_transform_t *)base;
611}
612
613typedef struct {
614 seq_node_t base;
615 bool prefix;
616 bithenge_int_t count;
617 bithenge_transform_t *xform;
618} repeat_node_t;
619
620static seq_node_t *repeat_as_seq(repeat_node_t *self)
621{
622 return &self->base;
623}
624
625static repeat_node_t *seq_as_repeat(seq_node_t *base)
626{
627 return (repeat_node_t *)base;
628}
629
630static bithenge_node_t *repeat_as_node(repeat_node_t *self)
631{
632 return seq_as_node(repeat_as_seq(self));
633}
634
635static repeat_node_t *node_as_repeat(bithenge_node_t *base)
636{
637 return seq_as_repeat(node_as_seq(base));
638}
639
640static int repeat_node_for_each(bithenge_node_t *base,
641 bithenge_for_each_func_t func, void *data)
642{
643 int rc = EOK;
644 repeat_node_t *self = node_as_repeat(base);
645
646 for (bithenge_int_t i = 0; self->count == -1 || i < self->count; i++) {
647 bithenge_node_t *subxform_result;
648 rc = seq_node_subtransform(repeat_as_seq(self),
649 &subxform_result, i);
650 if ((rc == EINVAL || rc == ENOENT) && self->count == -1) {
651 self->count = i;
652 seq_node_set_num_xforms(repeat_as_seq(self),
653 self->count);
654 rc = EOK;
655 break;
656 }
657 if (rc != EOK)
658 return rc;
659
660 bithenge_node_t *key_node;
661 rc = bithenge_new_integer_node(&key_node, i);
662 if (rc != EOK) {
663 bithenge_node_dec_ref(subxform_result);
664 return rc;
665 }
666 rc = func(key_node, subxform_result, data);
667 if (rc != EOK)
668 return rc;
669 }
670
671 if (!self->prefix) {
672 bool complete;
673 rc = seq_node_complete(repeat_as_seq(self), &complete);
674 if (rc != EOK)
675 return rc;
676 if (!complete)
677 return EINVAL;
678 }
679
680 return rc;
681}
682
683static int repeat_node_get(bithenge_node_t *base, bithenge_node_t *key,
684 bithenge_node_t **out)
685{
686 repeat_node_t *self = node_as_repeat(base);
687
688 if (bithenge_node_type(key) != BITHENGE_NODE_INTEGER) {
689 bithenge_node_dec_ref(key);
690 return ENOENT;
691 }
692
693 bithenge_int_t index = bithenge_integer_node_value(key);
694 bithenge_node_dec_ref(key);
695 if (index < 0 || (self->count != -1 && index >= self->count))
696 return ENOENT;
697 return seq_node_subtransform(repeat_as_seq(self), out, index);
698}
699
700static void repeat_node_destroy(bithenge_node_t *base)
701{
702 repeat_node_t *self = node_as_repeat(base);
703 seq_node_destroy(repeat_as_seq(self));
704 bithenge_transform_dec_ref(self->xform);
705 free(self);
706}
707
708static const bithenge_internal_node_ops_t repeat_node_ops = {
709 .for_each = repeat_node_for_each,
710 .get = repeat_node_get,
711 .destroy = repeat_node_destroy,
712};
713
714static int repeat_node_get_transform(seq_node_t *base,
715 bithenge_transform_t **out, bithenge_int_t index)
716{
717 repeat_node_t *self = seq_as_repeat(base);
718 *out = self->xform;
719 bithenge_transform_inc_ref(*out);
720 return EOK;
721}
722
723static const seq_node_ops_t repeat_node_seq_ops = {
724 .get_transform = repeat_node_get_transform,
725};
726
727static int repeat_transform_make_node(repeat_transform_t *self,
728 bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
729 bool prefix)
730{
731 bithenge_int_t count = -1;
732 if (self->expr != NULL) {
733 bithenge_node_t *count_node;
734 int rc = bithenge_expression_evaluate(self->expr, scope,
735 &count_node);
736 if (rc != EOK)
737 return rc;
738 if (bithenge_node_type(count_node) != BITHENGE_NODE_INTEGER) {
739 bithenge_node_dec_ref(count_node);
740 return EINVAL;
741 }
742 count = bithenge_integer_node_value(count_node);
743 bithenge_node_dec_ref(count_node);
744 if (count < 0)
745 return EINVAL;
746 }
747
748 repeat_node_t *node = malloc(sizeof(*node));
749 if (!node)
750 return ENOMEM;
751
752 int rc = bithenge_init_internal_node(repeat_as_node(node),
753 &repeat_node_ops);
754 if (rc != EOK) {
755 free(node);
756 return rc;
757 }
758
759 rc = seq_node_init(repeat_as_seq(node), &repeat_node_seq_ops, scope,
760 blob, count, count == -1);
761 if (rc != EOK) {
762 free(node);
763 return rc;
764 }
765
766 bithenge_transform_inc_ref(self->xform);
767 node->xform = self->xform;
768 node->count = count;
769 node->prefix = prefix;
770 *out = repeat_as_node(node);
771 return EOK;
772}
773
774static int repeat_transform_apply(bithenge_transform_t *base,
775 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
776{
777 repeat_transform_t *self = transform_as_repeat(base);
778 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
779 return EINVAL;
780 return repeat_transform_make_node(self, out, scope,
781 bithenge_node_as_blob(in), false);
782}
783
784static int repeat_transform_prefix_apply(bithenge_transform_t *base,
785 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
786 aoff64_t *out_size)
787{
788 repeat_transform_t *self = transform_as_repeat(base);
789 int rc = repeat_transform_make_node(self, out_node, scope, blob, true);
790 if (rc != EOK)
791 return rc;
792
793 bithenge_int_t count = node_as_repeat(*out_node)->count;
794 if (count != -1) {
795 rc = seq_node_field_offset(node_as_seq(*out_node), out_size, count);
796 if (rc != EOK) {
797 bithenge_node_dec_ref(*out_node);
798 return rc;
799 }
800 } else {
801 *out_size = 0;
802 for (count = 1; ; count++) {
803 aoff64_t size;
804 rc = seq_node_field_offset(node_as_seq(*out_node),
805 &size, count);
806 if (rc != EOK)
807 break;
808 *out_size = size;
809 }
810 }
811 return EOK;
812}
813
814static void repeat_transform_destroy(bithenge_transform_t *base)
815{
816 repeat_transform_t *self = transform_as_repeat(base);
817 bithenge_transform_dec_ref(self->xform);
818 bithenge_expression_dec_ref(self->expr);
819 free(self);
820}
821
822static const bithenge_transform_ops_t repeat_transform_ops = {
823 .apply = repeat_transform_apply,
824 .prefix_apply = repeat_transform_prefix_apply,
825 .destroy = repeat_transform_destroy,
826};
827
828/** Create a transform that applies its subtransform repeatedly. Takes a
829 * reference to @a xform and @a expr.
830 * @param[out] out Holds the new transform.
831 * @param xform The subtransform to apply repeatedly.
832 * @param expr Used to calculate the number of times @a xform will be applied.
833 * May be NULL, in which case @a xform will be applied indefinitely.
834 * @return EOK on success or an error code from errno.h. */
835int bithenge_repeat_transform(bithenge_transform_t **out,
836 bithenge_transform_t *xform, bithenge_expression_t *expr)
837{
838 int rc;
839 repeat_transform_t *self = malloc(sizeof(*self));
840 if (!self) {
841 rc = ENOMEM;
842 goto error;
843 }
844
845 rc = bithenge_init_transform(repeat_as_transform(self),
846 &repeat_transform_ops, 0);
847 if (rc != EOK)
848 goto error;
849
850 self->expr = expr;
851 self->xform = xform;
852 *out = repeat_as_transform(self);
853 return EOK;
854
855error:
856 free(self);
857 bithenge_expression_dec_ref(expr);
858 bithenge_transform_dec_ref(xform);
859 return rc;
860}
861
862
863
864/***************** bithenge_do_while_transform *****************/
865
866typedef struct {
867 bithenge_transform_t base;
868 bithenge_expression_t *expr;
869 bithenge_transform_t *xform;
870} do_while_transform_t;
871
872static inline bithenge_transform_t *do_while_as_transform(
873 do_while_transform_t *self)
874{
875 return &self->base;
876}
877
878static inline do_while_transform_t *transform_as_do_while(
879 bithenge_transform_t *base)
880{
881 return (do_while_transform_t *)base;
882}
883
884typedef struct {
885 seq_node_t base;
886 bool prefix;
887 bithenge_expression_t *expr;
888 bithenge_transform_t *xform;
889 bithenge_int_t count;
890} do_while_node_t;
891
892static seq_node_t *do_while_as_seq(do_while_node_t *self)
893{
894 return &self->base;
895}
896
897static do_while_node_t *seq_as_do_while(seq_node_t *base)
898{
899 return (do_while_node_t *)base;
900}
901
902static bithenge_node_t *do_while_as_node(do_while_node_t *self)
903{
904 return seq_as_node(do_while_as_seq(self));
905}
906
907static do_while_node_t *node_as_do_while(bithenge_node_t *base)
908{
909 return seq_as_do_while(node_as_seq(base));
910}
911
912static int do_while_node_for_each(bithenge_node_t *base,
913 bithenge_for_each_func_t func, void *data)
914{
915 int rc = EOK;
916 do_while_node_t *self = node_as_do_while(base);
917
918 for (bithenge_int_t i = 0; ; i++) {
919 bithenge_node_t *subxform_result;
920 rc = seq_node_subtransform(do_while_as_seq(self),
921 &subxform_result, i);
922 if (rc != EOK)
923 return rc;
924
925 bithenge_node_t *key_node;
926 rc = bithenge_new_integer_node(&key_node, i);
927 if (rc != EOK) {
928 bithenge_node_dec_ref(subxform_result);
929 return rc;
930 }
931 bithenge_node_inc_ref(subxform_result);
932 rc = func(key_node, subxform_result, data);
933 if (rc != EOK) {
934 bithenge_node_dec_ref(subxform_result);
935 return rc;
936 }
937
938 bithenge_scope_t scope;
939 bithenge_scope_init(&scope);
940 rc = bithenge_scope_copy(&scope,
941 seq_node_scope(do_while_as_seq(self)));
942 bithenge_scope_set_current_node(&scope, subxform_result);
943 if (rc != EOK) {
944 bithenge_scope_destroy(&scope);
945 return rc;
946 }
947 bithenge_node_t *expr_result;
948 rc = bithenge_expression_evaluate(self->expr, &scope,
949 &expr_result);
950 bithenge_scope_destroy(&scope);
951 if (rc != EOK)
952 return rc;
953 if (bithenge_node_type(expr_result) != BITHENGE_NODE_BOOLEAN) {
954 bithenge_node_dec_ref(expr_result);
955 return EINVAL;
956 }
957 bool cond = bithenge_boolean_node_value(expr_result);
958 bithenge_node_dec_ref(expr_result);
959 if (!cond) {
960 self->count = i + 1;
961 seq_node_set_num_xforms(do_while_as_seq(self),
962 self->count);
963 break;
964 }
965 }
966
967 if (!self->prefix) {
968 bool complete;
969 rc = seq_node_complete(do_while_as_seq(self), &complete);
970 if (rc != EOK)
971 return rc;
972 if (!complete)
973 return EINVAL;
974 }
975
976 return rc;
977}
978
979static void do_while_node_destroy(bithenge_node_t *base)
980{
981 do_while_node_t *self = node_as_do_while(base);
982 seq_node_destroy(do_while_as_seq(self));
983 bithenge_expression_dec_ref(self->expr);
984 bithenge_transform_dec_ref(self->xform);
985 free(self);
986}
987
988static const bithenge_internal_node_ops_t do_while_node_ops = {
989 .for_each = do_while_node_for_each,
990 .destroy = do_while_node_destroy,
991};
992
993static int do_while_node_get_transform(seq_node_t *base,
994 bithenge_transform_t **out, bithenge_int_t index)
995{
996 do_while_node_t *self = seq_as_do_while(base);
997 *out = self->xform;
998 bithenge_transform_inc_ref(*out);
999 return EOK;
1000}
1001
1002static const seq_node_ops_t do_while_node_seq_ops = {
1003 .get_transform = do_while_node_get_transform,
1004};
1005
1006static int do_while_transform_make_node(do_while_transform_t *self,
1007 bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
1008 bool prefix)
1009{
1010 do_while_node_t *node = malloc(sizeof(*node));
1011 if (!node)
1012 return ENOMEM;
1013
1014 int rc = bithenge_init_internal_node(do_while_as_node(node),
1015 &do_while_node_ops);
1016 if (rc != EOK) {
1017 free(node);
1018 return rc;
1019 }
1020
1021 rc = seq_node_init(do_while_as_seq(node), &do_while_node_seq_ops,
1022 scope, blob, -1, false);
1023 if (rc != EOK) {
1024 free(node);
1025 return rc;
1026 }
1027
1028 bithenge_transform_inc_ref(self->xform);
1029 node->xform = self->xform;
1030 bithenge_expression_inc_ref(self->expr);
1031 node->expr = self->expr;
1032 node->prefix = prefix;
1033 node->count = -1;
1034 *out = do_while_as_node(node);
1035 return EOK;
1036}
1037
1038static int do_while_transform_apply(bithenge_transform_t *base,
1039 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
1040{
1041 do_while_transform_t *self = transform_as_do_while(base);
1042 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
1043 return EINVAL;
1044 return do_while_transform_make_node(self, out, scope,
1045 bithenge_node_as_blob(in), false);
1046}
1047
1048static int for_each_noop(bithenge_node_t *key, bithenge_node_t *value,
1049 void *data)
1050{
1051 bithenge_node_dec_ref(key);
1052 bithenge_node_dec_ref(value);
1053 return EOK;
1054}
1055
1056static int do_while_transform_prefix_apply(bithenge_transform_t *base,
1057 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
1058 aoff64_t *out_size)
1059{
1060 do_while_transform_t *self = transform_as_do_while(base);
1061 int rc = do_while_transform_make_node(self, out_node, scope, blob,
1062 true);
1063 if (rc != EOK)
1064 return rc;
1065
1066 rc = bithenge_node_for_each(*out_node, for_each_noop, NULL);
1067 if (rc != EOK) {
1068 bithenge_node_dec_ref(*out_node);
1069 return rc;
1070 }
1071
1072 rc = seq_node_field_offset(node_as_seq(*out_node), out_size,
1073 node_as_do_while(*out_node)->count);
1074 if (rc != EOK) {
1075 bithenge_node_dec_ref(*out_node);
1076 return rc;
1077 }
1078
1079 return EOK;
1080}
1081
1082static void do_while_transform_destroy(bithenge_transform_t *base)
1083{
1084 do_while_transform_t *self = transform_as_do_while(base);
1085 bithenge_transform_dec_ref(self->xform);
1086 bithenge_expression_dec_ref(self->expr);
1087 free(self);
1088}
1089
1090static const bithenge_transform_ops_t do_while_transform_ops = {
1091 .apply = do_while_transform_apply,
1092 .prefix_apply = do_while_transform_prefix_apply,
1093 .destroy = do_while_transform_destroy,
1094};
1095
1096/** Create a transform that applies its subtransform while an expression on the
1097 * result returns true. Takes a reference to @a xform and @a expr.
1098 * @param[out] out Holds the new transform.
1099 * @param xform The subtransform to apply repeatedly.
1100 * @param expr Applied in the result of each application of @a xform to
1101 * determine whether there will be more.
1102 * @return EOK on success or an error code from errno.h. */
1103int bithenge_do_while_transform(bithenge_transform_t **out,
1104 bithenge_transform_t *xform, bithenge_expression_t *expr)
1105{
1106 int rc;
1107 do_while_transform_t *self = malloc(sizeof(*self));
1108 if (!self) {
1109 rc = ENOMEM;
1110 goto error;
1111 }
1112
1113 rc = bithenge_init_transform(do_while_as_transform(self),
1114 &do_while_transform_ops, 0);
1115 if (rc != EOK)
1116 goto error;
1117
1118 self->expr = expr;
1119 self->xform = xform;
1120 *out = do_while_as_transform(self);
1121 return EOK;
1122
1123error:
1124 free(self);
1125 bithenge_expression_dec_ref(expr);
1126 bithenge_transform_dec_ref(xform);
1127 return rc;
1128}
1129
1130/** @}
1131 */
Note: See TracBrowser for help on using the repository browser.