source: mainline/uspace/app/bithenge/sequence.c@ 6be4142

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

Bithenge: print transform errors; fixes and fat.bh improvements

  • Property mode set to 100644
File size: 29.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, blob_node,
212 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_dec_ref(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 self->scope = scope;
270 if (self->scope)
271 bithenge_scope_inc_ref(self->scope);
272 return EOK;
273}
274
275
276
277/***************** bithenge_new_struct *****************/
278
279typedef struct {
280 bithenge_transform_t base;
281 bithenge_named_transform_t *subtransforms;
282 size_t num_subtransforms;
283} struct_transform_t;
284
285static bithenge_transform_t *struct_as_transform(struct_transform_t *xform)
286{
287 return &xform->base;
288}
289
290static struct_transform_t *transform_as_struct(bithenge_transform_t *xform)
291{
292 return (struct_transform_t *)xform;
293}
294
295typedef struct {
296 seq_node_t base;
297 struct_transform_t *transform;
298 bool prefix;
299} struct_node_t;
300
301static seq_node_t *struct_as_seq(struct_node_t *node)
302{
303 return &node->base;
304}
305
306static struct_node_t *seq_as_struct(seq_node_t *base)
307{
308 return (struct_node_t *)base;
309}
310
311static bithenge_node_t *struct_as_node(struct_node_t *node)
312{
313 return seq_as_node(struct_as_seq(node));
314}
315
316static struct_node_t *node_as_struct(bithenge_node_t *node)
317{
318 return seq_as_struct(node_as_seq(node));
319}
320
321static int struct_node_for_each(bithenge_node_t *base,
322 bithenge_for_each_func_t func, void *data)
323{
324 int rc = EOK;
325 struct_node_t *self = node_as_struct(base);
326 bithenge_named_transform_t *subxforms =
327 self->transform->subtransforms;
328
329 for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
330 bithenge_node_t *subxform_result;
331 rc = seq_node_subtransform(struct_as_seq(self),
332 &subxform_result, i);
333 if (rc != EOK)
334 return rc;
335
336 if (subxforms[i].name) {
337 bithenge_node_t *name_node;
338 rc = bithenge_new_string_node(&name_node,
339 subxforms[i].name, false);
340 if (rc == EOK) {
341 rc = func(name_node, subxform_result, data);
342 subxform_result = NULL;
343 }
344 } else {
345 if (bithenge_node_type(subxform_result) !=
346 BITHENGE_NODE_INTERNAL) {
347 rc = EINVAL;
348 } else {
349 rc = bithenge_node_for_each(subxform_result,
350 func, data);
351 }
352 }
353 bithenge_node_dec_ref(subxform_result);
354 if (rc != EOK)
355 return rc;
356 }
357
358 if (!self->prefix) {
359 bool complete;
360 rc = seq_node_complete(struct_as_seq(self), &complete);
361 if (rc != EOK)
362 return rc;
363 if (!complete)
364 return EINVAL;
365 }
366
367 return rc;
368}
369
370static int struct_node_get(bithenge_node_t *base, bithenge_node_t *key,
371 bithenge_node_t **out)
372{
373 struct_node_t *self = node_as_struct(base);
374
375 int rc = ENOENT;
376 if (bithenge_node_type(key) != BITHENGE_NODE_STRING)
377 goto end;
378 const char *name = bithenge_string_node_value(key);
379
380 const bithenge_named_transform_t *subxforms =
381 self->transform->subtransforms;
382 for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
383 if (subxforms[i].name && !str_cmp(name, subxforms[i].name)) {
384 rc = seq_node_subtransform(struct_as_seq(self), out, i);
385 goto end;
386 }
387 }
388
389 for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
390 if (subxforms[i].name)
391 continue;
392 bithenge_node_t *subxform_result;
393 rc = seq_node_subtransform(struct_as_seq(self),
394 &subxform_result, i);
395 if (rc != EOK)
396 goto end;
397 if (bithenge_node_type(subxform_result) !=
398 BITHENGE_NODE_INTERNAL) {
399 bithenge_node_dec_ref(subxform_result);
400 rc = EINVAL;
401 goto end;
402 }
403 bithenge_node_inc_ref(key);
404 rc = bithenge_node_get(subxform_result, key, out);
405 bithenge_node_dec_ref(subxform_result);
406 if (rc != ENOENT)
407 goto end;
408 }
409
410 rc = ENOENT;
411end:
412 bithenge_node_dec_ref(key);
413 return rc;
414}
415
416static void struct_node_destroy(bithenge_node_t *base)
417{
418 struct_node_t *node = node_as_struct(base);
419
420 /* Treat the scope carefully because of the circular reference. In
421 * struct_transform_make_node, things are set up so node owns a
422 * reference to the scope, but scope doesn't own a reference to node,
423 * so node's reference count is too low. */
424 bithenge_scope_t *scope = seq_node_scope(struct_as_seq(node));
425 if (scope->refs == 1) {
426 /* Mostly normal destroy, but we didn't inc_ref(node) for the
427 * scope in struct_transform_make_node, so make sure it doesn't
428 * try to dec_ref. */
429 scope->current_node = NULL;
430 seq_node_destroy(struct_as_seq(node));
431 } else if (scope->refs > 1) {
432 /* The scope is still needed, but node isn't otherwise needed.
433 * Switch things around so scope owns a reference to node, but
434 * not vice versa, and scope's reference count is too low. */
435 bithenge_node_inc_ref(base);
436 bithenge_scope_dec_ref(scope);
437 return;
438 } else {
439 /* This happens after the previous case, when scope is no
440 * longer used and is being destroyed. Since scope is already
441 * being destroyed, set it to NULL here so we don't try to
442 * destroy it twice. */
443 struct_as_seq(node)->scope = NULL;
444 seq_node_destroy(struct_as_seq(node));
445 }
446
447 bithenge_transform_dec_ref(struct_as_transform(node->transform));
448 free(node);
449}
450
451static const bithenge_internal_node_ops_t struct_node_ops = {
452 .for_each = struct_node_for_each,
453 .get = struct_node_get,
454 .destroy = struct_node_destroy,
455};
456
457static int struct_node_get_transform(seq_node_t *base,
458 bithenge_transform_t **out, bithenge_int_t index)
459{
460 struct_node_t *self = seq_as_struct(base);
461 *out = self->transform->subtransforms[index].transform;
462 bithenge_transform_inc_ref(*out);
463 return EOK;
464}
465
466static const seq_node_ops_t struct_node_seq_ops = {
467 .get_transform = struct_node_get_transform,
468};
469
470static int struct_transform_make_node(struct_transform_t *self,
471 bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
472 bool prefix)
473{
474 struct_node_t *node = malloc(sizeof(*node));
475 if (!node)
476 return ENOMEM;
477
478 int rc = bithenge_init_internal_node(struct_as_node(node),
479 &struct_node_ops);
480 if (rc != EOK) {
481 free(node);
482 return rc;
483 }
484 bithenge_scope_t *inner;
485 rc = bithenge_scope_new(&inner, scope);
486 if (rc != EOK) {
487 free(node);
488 return rc;
489 }
490 /* We should inc_ref(node) here, but that would make a cycle. Instead,
491 * we leave it 1 too low, so that when the only remaining use of node
492 * is the scope, node will be destroyed. Also see the comment in
493 * struct_node_destroy. */
494 bithenge_scope_set_current_node(inner, struct_as_node(node));
495
496 rc = seq_node_init(struct_as_seq(node), &struct_node_seq_ops, inner,
497 blob, self->num_subtransforms, false);
498 bithenge_scope_dec_ref(inner);
499 if (rc != EOK) {
500 free(node);
501 return rc;
502 }
503
504 bithenge_transform_inc_ref(struct_as_transform(self));
505 node->transform = self;
506 node->prefix = prefix;
507 *out = struct_as_node(node);
508
509 return EOK;
510}
511
512static int struct_transform_apply(bithenge_transform_t *base,
513 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
514{
515 struct_transform_t *self = transform_as_struct(base);
516 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
517 return EINVAL;
518 return struct_transform_make_node(self, out, scope,
519 bithenge_node_as_blob(in), false);
520}
521
522static int struct_transform_prefix_length(bithenge_transform_t *base,
523 bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
524{
525 struct_transform_t *self = transform_as_struct(base);
526 bithenge_node_t *struct_node;
527 int rc = struct_transform_make_node(self, &struct_node, scope, blob,
528 true);
529 if (rc != EOK)
530 return rc;
531
532 rc = seq_node_field_offset(node_as_seq(struct_node), out,
533 self->num_subtransforms);
534 bithenge_node_dec_ref(struct_node);
535 return rc;
536}
537
538static int struct_transform_prefix_apply(bithenge_transform_t *base,
539 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
540 aoff64_t *out_size)
541{
542 struct_transform_t *self = transform_as_struct(base);
543 int rc = struct_transform_make_node(self, out_node, scope, blob,
544 true);
545 if (rc != EOK)
546 return rc;
547
548 rc = seq_node_field_offset(node_as_seq(*out_node), out_size,
549 self->num_subtransforms);
550 if (rc != EOK) {
551 bithenge_node_dec_ref(*out_node);
552 return rc;
553 }
554
555 return EOK;
556}
557
558static void free_subtransforms(bithenge_named_transform_t *subtransforms)
559{
560 for (size_t i = 0; subtransforms[i].transform; i++) {
561 free((void *)subtransforms[i].name);
562 bithenge_transform_dec_ref(subtransforms[i].transform);
563 }
564 free(subtransforms);
565}
566
567static void struct_transform_destroy(bithenge_transform_t *base)
568{
569 struct_transform_t *self = transform_as_struct(base);
570 free_subtransforms(self->subtransforms);
571 free(self);
572}
573
574static bithenge_transform_ops_t struct_transform_ops = {
575 .apply = struct_transform_apply,
576 .prefix_length = struct_transform_prefix_length,
577 .prefix_apply = struct_transform_prefix_apply,
578 .destroy = struct_transform_destroy,
579};
580
581/** Create a struct transform. The transform will apply its subtransforms
582 * sequentially to a blob to create an internal node. Each result is either
583 * given a key from @a subtransforms or, if the name is NULL, the result's keys
584 * and values are merged into the struct transform's result. This function
585 * takes ownership of @a subtransforms and the names and references therein.
586 * @param[out] out Stores the created transform.
587 * @param subtransforms The subtransforms and field names.
588 * @return EOK on success or an error code from errno.h. */
589int bithenge_new_struct(bithenge_transform_t **out,
590 bithenge_named_transform_t *subtransforms)
591{
592 int rc;
593 struct_transform_t *self = malloc(sizeof(*self));
594 if (!self) {
595 rc = ENOMEM;
596 goto error;
597 }
598 rc = bithenge_init_transform(struct_as_transform(self),
599 &struct_transform_ops, 0);
600 if (rc != EOK)
601 goto error;
602 self->subtransforms = subtransforms;
603 self->num_subtransforms = 0;
604 for (self->num_subtransforms = 0;
605 subtransforms[self->num_subtransforms].transform;
606 self->num_subtransforms++);
607 *out = struct_as_transform(self);
608 return EOK;
609error:
610 free_subtransforms(subtransforms);
611 free(self);
612 return rc;
613}
614
615
616
617/***************** bithenge_repeat_transform *****************/
618
619typedef struct {
620 bithenge_transform_t base;
621 bithenge_expression_t *expr;
622 bithenge_transform_t *xform;
623} repeat_transform_t;
624
625static inline bithenge_transform_t *repeat_as_transform(
626 repeat_transform_t *self)
627{
628 return &self->base;
629}
630
631static inline repeat_transform_t *transform_as_repeat(
632 bithenge_transform_t *base)
633{
634 return (repeat_transform_t *)base;
635}
636
637typedef struct {
638 seq_node_t base;
639 bool prefix;
640 bithenge_int_t count;
641 bithenge_transform_t *xform;
642} repeat_node_t;
643
644static seq_node_t *repeat_as_seq(repeat_node_t *self)
645{
646 return &self->base;
647}
648
649static repeat_node_t *seq_as_repeat(seq_node_t *base)
650{
651 return (repeat_node_t *)base;
652}
653
654static bithenge_node_t *repeat_as_node(repeat_node_t *self)
655{
656 return seq_as_node(repeat_as_seq(self));
657}
658
659static repeat_node_t *node_as_repeat(bithenge_node_t *base)
660{
661 return seq_as_repeat(node_as_seq(base));
662}
663
664static int repeat_node_for_each(bithenge_node_t *base,
665 bithenge_for_each_func_t func, void *data)
666{
667 int rc = EOK;
668 repeat_node_t *self = node_as_repeat(base);
669
670 for (bithenge_int_t i = 0; self->count == -1 || i < self->count; i++) {
671 bithenge_node_t *subxform_result;
672 rc = seq_node_subtransform(repeat_as_seq(self),
673 &subxform_result, i);
674 if ((rc == EINVAL || rc == ENOENT) && self->count == -1) {
675 self->count = i;
676 seq_node_set_num_xforms(repeat_as_seq(self),
677 self->count);
678 rc = EOK;
679 break;
680 }
681 if (rc != EOK)
682 return rc;
683
684 bithenge_node_t *key_node;
685 rc = bithenge_new_integer_node(&key_node, i);
686 if (rc != EOK) {
687 bithenge_node_dec_ref(subxform_result);
688 return rc;
689 }
690 rc = func(key_node, subxform_result, data);
691 if (rc != EOK)
692 return rc;
693 }
694
695 if (!self->prefix) {
696 bool complete;
697 rc = seq_node_complete(repeat_as_seq(self), &complete);
698 if (rc != EOK)
699 return rc;
700 if (!complete)
701 return EINVAL;
702 }
703
704 return rc;
705}
706
707static int repeat_node_get(bithenge_node_t *base, bithenge_node_t *key,
708 bithenge_node_t **out)
709{
710 repeat_node_t *self = node_as_repeat(base);
711
712 if (bithenge_node_type(key) != BITHENGE_NODE_INTEGER) {
713 bithenge_node_dec_ref(key);
714 return ENOENT;
715 }
716
717 bithenge_int_t index = bithenge_integer_node_value(key);
718 bithenge_node_dec_ref(key);
719 if (index < 0 || (self->count != -1 && index >= self->count))
720 return ENOENT;
721 return seq_node_subtransform(repeat_as_seq(self), out, index);
722}
723
724static void repeat_node_destroy(bithenge_node_t *base)
725{
726 repeat_node_t *self = node_as_repeat(base);
727 seq_node_destroy(repeat_as_seq(self));
728 bithenge_transform_dec_ref(self->xform);
729 free(self);
730}
731
732static const bithenge_internal_node_ops_t repeat_node_ops = {
733 .for_each = repeat_node_for_each,
734 .get = repeat_node_get,
735 .destroy = repeat_node_destroy,
736};
737
738static int repeat_node_get_transform(seq_node_t *base,
739 bithenge_transform_t **out, bithenge_int_t index)
740{
741 repeat_node_t *self = seq_as_repeat(base);
742 *out = self->xform;
743 bithenge_transform_inc_ref(*out);
744 return EOK;
745}
746
747static const seq_node_ops_t repeat_node_seq_ops = {
748 .get_transform = repeat_node_get_transform,
749};
750
751static int repeat_transform_make_node(repeat_transform_t *self,
752 bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
753 bool prefix)
754{
755 bithenge_int_t count = -1;
756 if (self->expr != NULL) {
757 bithenge_node_t *count_node;
758 int rc = bithenge_expression_evaluate(self->expr, scope,
759 &count_node);
760 if (rc != EOK)
761 return rc;
762 if (bithenge_node_type(count_node) != BITHENGE_NODE_INTEGER) {
763 bithenge_node_dec_ref(count_node);
764 return EINVAL;
765 }
766 count = bithenge_integer_node_value(count_node);
767 bithenge_node_dec_ref(count_node);
768 if (count < 0)
769 return EINVAL;
770 }
771
772 repeat_node_t *node = malloc(sizeof(*node));
773 if (!node)
774 return ENOMEM;
775
776 int rc = bithenge_init_internal_node(repeat_as_node(node),
777 &repeat_node_ops);
778 if (rc != EOK) {
779 free(node);
780 return rc;
781 }
782
783 rc = seq_node_init(repeat_as_seq(node), &repeat_node_seq_ops, scope,
784 blob, count, count == -1);
785 if (rc != EOK) {
786 free(node);
787 return rc;
788 }
789
790 bithenge_transform_inc_ref(self->xform);
791 node->xform = self->xform;
792 node->count = count;
793 node->prefix = prefix;
794 *out = repeat_as_node(node);
795 return EOK;
796}
797
798static int repeat_transform_apply(bithenge_transform_t *base,
799 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
800{
801 repeat_transform_t *self = transform_as_repeat(base);
802 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
803 return EINVAL;
804 return repeat_transform_make_node(self, out, scope,
805 bithenge_node_as_blob(in), false);
806}
807
808static int repeat_transform_prefix_apply(bithenge_transform_t *base,
809 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
810 aoff64_t *out_size)
811{
812 repeat_transform_t *self = transform_as_repeat(base);
813 int rc = repeat_transform_make_node(self, out_node, scope, blob, true);
814 if (rc != EOK)
815 return rc;
816
817 bithenge_int_t count = node_as_repeat(*out_node)->count;
818 if (count != -1) {
819 rc = seq_node_field_offset(node_as_seq(*out_node), out_size, count);
820 if (rc != EOK) {
821 bithenge_node_dec_ref(*out_node);
822 return rc;
823 }
824 } else {
825 *out_size = 0;
826 for (count = 1; ; count++) {
827 aoff64_t size;
828 rc = seq_node_field_offset(node_as_seq(*out_node),
829 &size, count);
830 if (rc != EOK)
831 break;
832 *out_size = size;
833 }
834 }
835 return EOK;
836}
837
838static void repeat_transform_destroy(bithenge_transform_t *base)
839{
840 repeat_transform_t *self = transform_as_repeat(base);
841 bithenge_transform_dec_ref(self->xform);
842 bithenge_expression_dec_ref(self->expr);
843 free(self);
844}
845
846static const bithenge_transform_ops_t repeat_transform_ops = {
847 .apply = repeat_transform_apply,
848 .prefix_apply = repeat_transform_prefix_apply,
849 .destroy = repeat_transform_destroy,
850};
851
852/** Create a transform that applies its subtransform repeatedly. Takes a
853 * reference to @a xform and @a expr.
854 * @param[out] out Holds the new transform.
855 * @param xform The subtransform to apply repeatedly.
856 * @param expr Used to calculate the number of times @a xform will be applied.
857 * May be NULL, in which case @a xform will be applied indefinitely.
858 * @return EOK on success or an error code from errno.h. */
859int bithenge_repeat_transform(bithenge_transform_t **out,
860 bithenge_transform_t *xform, bithenge_expression_t *expr)
861{
862 int rc;
863 repeat_transform_t *self = malloc(sizeof(*self));
864 if (!self) {
865 rc = ENOMEM;
866 goto error;
867 }
868
869 rc = bithenge_init_transform(repeat_as_transform(self),
870 &repeat_transform_ops, 0);
871 if (rc != EOK)
872 goto error;
873
874 self->expr = expr;
875 self->xform = xform;
876 *out = repeat_as_transform(self);
877 return EOK;
878
879error:
880 free(self);
881 bithenge_expression_dec_ref(expr);
882 bithenge_transform_dec_ref(xform);
883 return rc;
884}
885
886
887
888/***************** bithenge_do_while_transform *****************/
889
890typedef struct {
891 bithenge_transform_t base;
892 bithenge_expression_t *expr;
893 bithenge_transform_t *xform;
894} do_while_transform_t;
895
896static inline bithenge_transform_t *do_while_as_transform(
897 do_while_transform_t *self)
898{
899 return &self->base;
900}
901
902static inline do_while_transform_t *transform_as_do_while(
903 bithenge_transform_t *base)
904{
905 return (do_while_transform_t *)base;
906}
907
908typedef struct {
909 seq_node_t base;
910 bool prefix;
911 bithenge_expression_t *expr;
912 bithenge_transform_t *xform;
913 bithenge_int_t count;
914} do_while_node_t;
915
916static seq_node_t *do_while_as_seq(do_while_node_t *self)
917{
918 return &self->base;
919}
920
921static do_while_node_t *seq_as_do_while(seq_node_t *base)
922{
923 return (do_while_node_t *)base;
924}
925
926static bithenge_node_t *do_while_as_node(do_while_node_t *self)
927{
928 return seq_as_node(do_while_as_seq(self));
929}
930
931static do_while_node_t *node_as_do_while(bithenge_node_t *base)
932{
933 return seq_as_do_while(node_as_seq(base));
934}
935
936static int do_while_node_for_each(bithenge_node_t *base,
937 bithenge_for_each_func_t func, void *data)
938{
939 int rc = EOK;
940 do_while_node_t *self = node_as_do_while(base);
941
942 for (bithenge_int_t i = 0; ; i++) {
943 bithenge_node_t *subxform_result;
944 rc = seq_node_subtransform(do_while_as_seq(self),
945 &subxform_result, i);
946 if (rc != EOK)
947 return rc;
948
949 bithenge_node_t *key_node;
950 rc = bithenge_new_integer_node(&key_node, i);
951 if (rc != EOK) {
952 bithenge_node_dec_ref(subxform_result);
953 return rc;
954 }
955 bithenge_node_inc_ref(subxform_result);
956 rc = func(key_node, subxform_result, data);
957 if (rc != EOK) {
958 bithenge_node_dec_ref(subxform_result);
959 return rc;
960 }
961
962 bithenge_scope_t *scope;
963 rc = bithenge_scope_new(&scope,
964 seq_node_scope(do_while_as_seq(self)));
965 if (rc != EOK) {
966 bithenge_node_dec_ref(subxform_result);
967 return rc;
968 }
969 bithenge_scope_set_current_node(scope, subxform_result);
970 bithenge_node_t *expr_result;
971 rc = bithenge_expression_evaluate(self->expr, scope,
972 &expr_result);
973 bithenge_scope_dec_ref(scope);
974 if (rc != EOK)
975 return rc;
976 if (bithenge_node_type(expr_result) != BITHENGE_NODE_BOOLEAN) {
977 bithenge_node_dec_ref(expr_result);
978 return EINVAL;
979 }
980 bool cond = bithenge_boolean_node_value(expr_result);
981 bithenge_node_dec_ref(expr_result);
982 if (!cond) {
983 self->count = i + 1;
984 seq_node_set_num_xforms(do_while_as_seq(self),
985 self->count);
986 break;
987 }
988 }
989
990 if (!self->prefix) {
991 bool complete;
992 rc = seq_node_complete(do_while_as_seq(self), &complete);
993 if (rc != EOK)
994 return rc;
995 if (!complete)
996 return EINVAL;
997 }
998
999 return rc;
1000}
1001
1002static void do_while_node_destroy(bithenge_node_t *base)
1003{
1004 do_while_node_t *self = node_as_do_while(base);
1005 seq_node_destroy(do_while_as_seq(self));
1006 bithenge_expression_dec_ref(self->expr);
1007 bithenge_transform_dec_ref(self->xform);
1008 free(self);
1009}
1010
1011static const bithenge_internal_node_ops_t do_while_node_ops = {
1012 .for_each = do_while_node_for_each,
1013 .destroy = do_while_node_destroy,
1014};
1015
1016static int do_while_node_get_transform(seq_node_t *base,
1017 bithenge_transform_t **out, bithenge_int_t index)
1018{
1019 do_while_node_t *self = seq_as_do_while(base);
1020 *out = self->xform;
1021 bithenge_transform_inc_ref(*out);
1022 return EOK;
1023}
1024
1025static const seq_node_ops_t do_while_node_seq_ops = {
1026 .get_transform = do_while_node_get_transform,
1027};
1028
1029static int do_while_transform_make_node(do_while_transform_t *self,
1030 bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
1031 bool prefix)
1032{
1033 do_while_node_t *node = malloc(sizeof(*node));
1034 if (!node)
1035 return ENOMEM;
1036
1037 int rc = bithenge_init_internal_node(do_while_as_node(node),
1038 &do_while_node_ops);
1039 if (rc != EOK) {
1040 free(node);
1041 return rc;
1042 }
1043
1044 rc = seq_node_init(do_while_as_seq(node), &do_while_node_seq_ops,
1045 scope, blob, -1, false);
1046 if (rc != EOK) {
1047 free(node);
1048 return rc;
1049 }
1050
1051 bithenge_transform_inc_ref(self->xform);
1052 node->xform = self->xform;
1053 bithenge_expression_inc_ref(self->expr);
1054 node->expr = self->expr;
1055 node->prefix = prefix;
1056 node->count = -1;
1057 *out = do_while_as_node(node);
1058 return EOK;
1059}
1060
1061static int do_while_transform_apply(bithenge_transform_t *base,
1062 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
1063{
1064 do_while_transform_t *self = transform_as_do_while(base);
1065 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
1066 return EINVAL;
1067 return do_while_transform_make_node(self, out, scope,
1068 bithenge_node_as_blob(in), false);
1069}
1070
1071static int for_each_noop(bithenge_node_t *key, bithenge_node_t *value,
1072 void *data)
1073{
1074 bithenge_node_dec_ref(key);
1075 bithenge_node_dec_ref(value);
1076 return EOK;
1077}
1078
1079static int do_while_transform_prefix_apply(bithenge_transform_t *base,
1080 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
1081 aoff64_t *out_size)
1082{
1083 do_while_transform_t *self = transform_as_do_while(base);
1084 int rc = do_while_transform_make_node(self, out_node, scope, blob,
1085 true);
1086 if (rc != EOK)
1087 return rc;
1088
1089 rc = bithenge_node_for_each(*out_node, for_each_noop, NULL);
1090 if (rc != EOK) {
1091 bithenge_node_dec_ref(*out_node);
1092 return rc;
1093 }
1094
1095 rc = seq_node_field_offset(node_as_seq(*out_node), out_size,
1096 node_as_do_while(*out_node)->count);
1097 if (rc != EOK) {
1098 bithenge_node_dec_ref(*out_node);
1099 return rc;
1100 }
1101
1102 return EOK;
1103}
1104
1105static void do_while_transform_destroy(bithenge_transform_t *base)
1106{
1107 do_while_transform_t *self = transform_as_do_while(base);
1108 bithenge_transform_dec_ref(self->xform);
1109 bithenge_expression_dec_ref(self->expr);
1110 free(self);
1111}
1112
1113static const bithenge_transform_ops_t do_while_transform_ops = {
1114 .apply = do_while_transform_apply,
1115 .prefix_apply = do_while_transform_prefix_apply,
1116 .destroy = do_while_transform_destroy,
1117};
1118
1119/** Create a transform that applies its subtransform while an expression on the
1120 * result returns true. Takes a reference to @a xform and @a expr.
1121 * @param[out] out Holds the new transform.
1122 * @param xform The subtransform to apply repeatedly.
1123 * @param expr Applied in the result of each application of @a xform to
1124 * determine whether there will be more.
1125 * @return EOK on success or an error code from errno.h. */
1126int bithenge_do_while_transform(bithenge_transform_t **out,
1127 bithenge_transform_t *xform, bithenge_expression_t *expr)
1128{
1129 int rc;
1130 do_while_transform_t *self = malloc(sizeof(*self));
1131 if (!self) {
1132 rc = ENOMEM;
1133 goto error;
1134 }
1135
1136 rc = bithenge_init_transform(do_while_as_transform(self),
1137 &do_while_transform_ops, 0);
1138 if (rc != EOK)
1139 goto error;
1140
1141 self->expr = expr;
1142 self->xform = xform;
1143 *out = do_while_as_transform(self);
1144 return EOK;
1145
1146error:
1147 free(self);
1148 bithenge_expression_dec_ref(expr);
1149 bithenge_transform_dec_ref(xform);
1150 return rc;
1151}
1152
1153/** @}
1154 */
Note: See TracBrowser for help on using the repository browser.