source: mainline/uspace/lib/sif/src/sif.c@ bff8619

Last change on this file since bff8619 was bff8619, checked in by Jiri Svoboda <jiri@…>, 10 months ago

Simplify SIF interface, remove contacts

Remove transactions, move to a load/save model. Remove contacts
application as it was never finished and not useful at all.

  • Property mode set to 100644
File size: 18.0 KB
RevLine 
[b79903b]1/*
[bff8619]2 * Copyright (c) 2024 Jiri Svoboda
[b79903b]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/** @addtogroup libsif
29 * @{
30 */
31/**
32 * @file Structured Information Format
33 *
34 * Structured Information Format (SIF) is an API that allows an application
[bff8619]35 * to maintain data in a persistent repository in a format that is
36 * structured (and hence extensible).
[b79903b]37 *
38 * SIF is meant to be used as the basis for the storage backend used to
39 * maintain application or configuration data. SIF is *not* a (relational)
40 * database (not even close). The structure of a SIF repository is quite
41 * similar to an XML document that contains just tags with attributes
42 * (but no text).
43 */
44
[7b87e1d]45#include <adt/list.h>
46#include <adt/odict.h>
[b79903b]47#include <errno.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <str.h>
51#include "../include/sif.h"
52#include "../private/sif.h"
53
54static errno_t sif_export_node(sif_node_t *, FILE *);
[9c5e3a5]55static errno_t sif_import_node(sif_node_t *, FILE *, sif_node_t **);
[7b87e1d]56static sif_attr_t *sif_node_first_attr(sif_node_t *);
57static sif_attr_t *sif_node_next_attr(sif_attr_t *);
58static void sif_attr_delete(sif_attr_t *);
59static void *sif_attr_getkey(odlink_t *);
60static int sif_attr_cmp(void *, void *);
[b79903b]61
62/** Create new SIF node.
63 *
[7b87e1d]64 * @param parent Parent node
[b79903b]65 * @return Pointer to new node on success or @c NULL if out of memory
66 */
67static sif_node_t *sif_node_new(sif_node_t *parent)
68{
69 sif_node_t *node;
70
71 node = calloc(1, sizeof(sif_node_t));
72 if (node == NULL)
73 return NULL;
74
75 node->parent = parent;
[7b87e1d]76 odict_initialize(&node->attrs, sif_attr_getkey, sif_attr_cmp);
[b79903b]77 list_initialize(&node->children);
78
79 return node;
80}
81
82/** Delete SIF node.
83 *
84 * Delete a SIF node that has been already unlinked from the tree.
[7b87e1d]85 * This will also delete any attributes or child nodes.
[b79903b]86 *
87 * @param node Node
88 */
89static void sif_node_delete(sif_node_t *node)
90{
[7b87e1d]91 sif_attr_t *attr;
92 sif_node_t *child;
93
[b79903b]94 if (node == NULL)
95 return;
96
[7b87e1d]97 assert(!link_used(&node->lparent));
98
[b79903b]99 if (node->ntype != NULL)
100 free(node->ntype);
101
[7b87e1d]102 attr = sif_node_first_attr(node);
103 while (attr != NULL) {
104 odict_remove(&attr->lattrs);
105 sif_attr_delete(attr);
106 attr = sif_node_first_attr(node);
107 }
108
109 child = sif_node_first_child(node);
110 while (child != NULL) {
111 list_remove(&child->lparent);
112 sif_node_delete(child);
113 child = sif_node_first_child(node);
114 }
115
[b79903b]116 free(node);
117}
118
[7b87e1d]119/** Create new SIF attribute.
120 *
121 * @param node Containing node
122 * @return Pointer to new node on success or @c NULL if out of memory
123 */
124static sif_attr_t *sif_attr_new(sif_node_t *node)
125{
126 sif_attr_t *attr;
127
128 attr = calloc(1, sizeof(sif_attr_t));
129 if (attr == NULL)
130 return NULL;
131
132 attr->node = node;
133 return attr;
134}
135
136/** Delete SIF attribute.
137 *
138 * Delete a SIF attribute that has been already unlinked from is node.
139 *
140 * @param attr Attribute
141 */
142static void sif_attr_delete(sif_attr_t *attr)
143{
144 if (attr == NULL)
145 return;
146
147 assert(!odlink_used(&attr->lattrs));
148
149 if (attr->aname != NULL)
150 free(attr->aname);
151 if (attr->avalue != NULL)
152 free(attr->avalue);
153
154 free(attr);
155}
156
[bff8619]157/** Create SIF document.
[b79903b]158 *
[bff8619]159 * @param rdoc Place to store pointer to new document.
[b79903b]160 *
161 * @return EOK on success or error code
162 */
[bff8619]163errno_t sif_new(sif_doc_t **rdoc)
[b79903b]164{
[bff8619]165 sif_doc_t *doc;
[b79903b]166 sif_node_t *root = NULL;
167 errno_t rc;
168
[bff8619]169 doc = calloc(1, sizeof(sif_doc_t));
170 if (doc == NULL)
[b79903b]171 return ENOMEM;
172
173 root = sif_node_new(NULL);
174 if (root == NULL) {
175 rc = ENOMEM;
176 goto error;
177 }
178
179 root->ntype = str_dup("sif");
180 if (root->ntype == NULL) {
181 rc = ENOMEM;
182 goto error;
183 }
184
[bff8619]185 doc->root = root;
[7b87e1d]186
[bff8619]187 *rdoc = doc;
[b79903b]188 return EOK;
189error:
190 sif_node_delete(root);
[bff8619]191 free(doc);
[b79903b]192 return rc;
193}
194
[bff8619]195/** Load SIF document.
[b79903b]196 *
197 * @param fname File name
[bff8619]198 * @param rdoc Place to store pointer to new document.
[b79903b]199 *
200 * @return EOK on success or error code
201 */
[bff8619]202errno_t sif_load(const char *fname, sif_doc_t **rdoc)
[b79903b]203{
[bff8619]204 sif_doc_t *doc;
[b79903b]205 sif_node_t *root = NULL;
206 errno_t rc;
207 FILE *f;
208
[bff8619]209 doc = calloc(1, sizeof(sif_doc_t));
210 if (doc == NULL)
[b79903b]211 return ENOMEM;
212
[bff8619]213 doc->fname = str_dup(fname);
214 if (doc->fname == NULL) {
[1dcba91]215 rc = ENOMEM;
216 goto error;
217 }
218
219 f = fopen(fname, "r");
[9c5e3a5]220 if (f == NULL) {
221 rc = EIO;
[b79903b]222 goto error;
223 }
224
[9c5e3a5]225 rc = sif_import_node(NULL, f, &root);
226 if (rc != EOK)
[b79903b]227 goto error;
228
[9c5e3a5]229 if (str_cmp(root->ntype, "sif") != 0) {
[b79903b]230 rc = EIO;
231 goto error;
232 }
233
[bff8619]234 doc->root = root;
235 *rdoc = doc;
[b79903b]236 return EOK;
237error:
238 sif_node_delete(root);
[bff8619]239 free(doc);
[b79903b]240 return rc;
241}
242
[bff8619]243/** Delete SIF document.
[b79903b]244 *
[bff8619]245 * @param doc SIF document
[b79903b]246 * @return EOK on success or error code
247 */
[bff8619]248void sif_delete(sif_doc_t *doc)
[b79903b]249{
[bff8619]250 sif_node_delete(doc->root);
251 free(doc);
[b79903b]252}
253
254/** Return root node.
255 *
[bff8619]256 * @param doc SIF document
[b79903b]257 */
[bff8619]258sif_node_t *sif_get_root(sif_doc_t *doc)
[b79903b]259{
[bff8619]260 return doc->root;
[b79903b]261}
262
263/** Get first child of a node.
264 *
265 * @param parent Parent node
266 * @return First child node or @c NULL if @a parent has no children
267 */
268sif_node_t *sif_node_first_child(sif_node_t *parent)
269{
270 link_t *link;
271
272 link = list_first(&parent->children);
273 if (link == NULL)
274 return NULL;
275
276 return list_get_instance(link, sif_node_t, lparent);
277}
278
279/** Get next child of a node.
280 *
281 * @param current Current node
282 * @return Next child (i.e. next sibling of @a current)
283 */
284sif_node_t *sif_node_next_child(sif_node_t *current)
285{
286 link_t *link;
287
288 link = list_next(&current->lparent, &current->parent->children);
289 if (link == NULL)
290 return NULL;
291
292 return list_get_instance(link, sif_node_t, lparent);
293}
294
295/** Get node type.
296 *
297 * @param node SIF node
298 * @return Pointer to string, valid until next modification.
299 */
300const char *sif_node_get_type(sif_node_t *node)
301{
302 return node->ntype;
303}
304
305/** Get node attribute.
306 *
307 * @param node SIF node
308 * @param aname Attribute name
309 *
310 * @return Attribute value or @c NULL if attribute is not set
311 */
312const char *sif_node_get_attr(sif_node_t *node, const char *aname)
313{
[7b87e1d]314 odlink_t *link;
315 sif_attr_t *attr;
316
317 link = odict_find_eq(&node->attrs, (void *)aname, NULL);
318 if (link == NULL)
319 return NULL;
320
321 attr = odict_get_instance(link, sif_attr_t, lattrs);
322 return attr->avalue;
[b79903b]323}
324
[bff8619]325/** Save SIF document to file.
326 * *
327 * @param doc SIF document
328 * @param fname File name
[b79903b]329 * @return EOK on success or error code
330 */
[bff8619]331errno_t sif_save(sif_doc_t *doc, const char *fname)
[b79903b]332{
[bff8619]333 FILE *f = NULL;
[b79903b]334 errno_t rc;
335
[bff8619]336 f = fopen(fname, "w");
337 if (f == NULL) {
338 rc = EIO;
339 goto error;
340 }
[b79903b]341
[bff8619]342 rc = sif_export_node(doc->root, f);
[b79903b]343 if (rc != EOK)
[bff8619]344 goto error;
[b79903b]345
[bff8619]346 if (fputc('\n', f) == EOF) {
347 rc = EIO;
348 goto error;
349 }
[1dcba91]350
[bff8619]351 if (fflush(f) == EOF) {
352 rc = EIO;
353 goto error;
354 }
[1dcba91]355
[b79903b]356 return EOK;
[bff8619]357error:
358 if (f != NULL)
359 fclose(f);
360 return rc;
[b79903b]361}
362
363/** Prepend new child.
364 *
365 * Create a new child and prepend it at the beginning of children list of
366 * @a parent.
367 *
368 * @param parent Parent node
369 * @param ctype Child type
370 * @param rchild Place to store pointer to new child
371 *
372 * @return EOK on success or ENOMEM if out of memory
373 */
[bff8619]374errno_t sif_node_prepend_child(sif_node_t *parent, const char *ctype,
375 sif_node_t **rchild)
[b79903b]376{
377 sif_node_t *child;
378
379 child = sif_node_new(parent);
380 if (child == NULL)
381 return ENOMEM;
382
383 child->ntype = str_dup(ctype);
384 if (child->ntype == NULL) {
385 sif_node_delete(child);
386 return ENOMEM;
387 }
388
389 list_prepend(&child->lparent, &parent->children);
390
391 *rchild = child;
392 return EOK;
393}
394
395/** Append new child.
396 *
397 * Create a new child and append it at the end of children list of @a parent.
398 *
399 * @param parent Parent node
400 * @param ctype Child type
401 * @param rchild Place to store pointer to new child
402 *
403 * @return EOK on success or ENOMEM if out of memory
404 */
[bff8619]405errno_t sif_node_append_child(sif_node_t *parent, const char *ctype,
406 sif_node_t **rchild)
[b79903b]407{
408 sif_node_t *child;
409
410 child = sif_node_new(parent);
411 if (child == NULL)
412 return ENOMEM;
413
414 child->ntype = str_dup(ctype);
415 if (child->ntype == NULL) {
416 sif_node_delete(child);
417 return ENOMEM;
418 }
419
420 list_append(&child->lparent, &parent->children);
421
422 *rchild = child;
423 return EOK;
424}
425
426/** Insert new child before existing child.
427 *
428 * Create a new child and insert it before an existing child.
429 *
430 * @param sibling Sibling before which to insert
431 * @param ctype Child type
432 * @param rchild Place to store pointer to new child
433 *
434 * @return EOK on success or ENOMEM if out of memory
435 */
[bff8619]436errno_t sif_node_insert_before(sif_node_t *sibling, const char *ctype,
437 sif_node_t **rchild)
[b79903b]438{
439 sif_node_t *child;
440
441 child = sif_node_new(sibling->parent);
442 if (child == NULL)
443 return ENOMEM;
444
445 child->ntype = str_dup(ctype);
446 if (child->ntype == NULL) {
447 sif_node_delete(child);
448 return ENOMEM;
449 }
450
451 list_insert_before(&child->lparent, &sibling->lparent);
452
453 *rchild = child;
454 return EOK;
455}
456
457/** Insert new child after existing child.
458 *
459 * Create a new child and insert it after an existing child.
460 *
461 * @param sibling Sibling after which to insert
462 * @param ctype Child type
463 * @param rchild Place to store pointer to new child
464 *
465 * @return EOK on success or ENOMEM if out of memory
466 */
[bff8619]467errno_t sif_node_insert_after(sif_node_t *sibling, const char *ctype,
468 sif_node_t **rchild)
[b79903b]469{
470 sif_node_t *child;
471
472 child = sif_node_new(sibling->parent);
473 if (child == NULL)
474 return ENOMEM;
475
476 child->ntype = str_dup(ctype);
477 if (child->ntype == NULL) {
478 sif_node_delete(child);
479 return ENOMEM;
480 }
481
482 list_insert_after(&child->lparent, &sibling->lparent);
483
484 *rchild = child;
485 return EOK;
486}
487
488/** Destroy SIF node.
489 *
490 * @param node Node to destroy
491 */
[bff8619]492void sif_node_destroy(sif_node_t *node)
[b79903b]493{
494 list_remove(&node->lparent);
495 sif_node_delete(node);
496}
497
498/** Set node attribute.
499 *
500 * @param node SIF node
501 * @param aname Attribute name
502 * @param value Attribute value
503 *
504 * @return EOK on success, ENOMEM if out of memory
505 */
[bff8619]506errno_t sif_node_set_attr(sif_node_t *node, const char *aname,
507 const char *avalue)
[b79903b]508{
[7b87e1d]509 odlink_t *link;
510 sif_attr_t *attr;
511 char *cvalue;
512
513 link = odict_find_eq(&node->attrs, (void *)aname, NULL);
514
515 if (link != NULL) {
516 attr = odict_get_instance(link, sif_attr_t, lattrs);
517 cvalue = str_dup(avalue);
518 if (cvalue == NULL)
519 return ENOMEM;
520
521 free(attr->avalue);
522 attr->avalue = cvalue;
523 } else {
524 attr = sif_attr_new(node);
525 if (attr == NULL)
526 return ENOMEM;
527
528 attr->aname = str_dup(aname);
529 if (attr->aname == NULL) {
530 sif_attr_delete(attr);
531 return ENOMEM;
532 }
533
534 attr->avalue = str_dup(avalue);
535 if (attr->avalue == NULL) {
536 sif_attr_delete(attr);
537 return ENOMEM;
538 }
539
540 odict_insert(&attr->lattrs, &node->attrs, NULL);
541 }
542
[b79903b]543 return EOK;
544}
545
546/** Unset node attribute.
547 *
548 * @param node Node
549 * @param aname Attribute name
550 */
[bff8619]551void sif_node_unset_attr(sif_node_t *node, const char *aname)
[b79903b]552{
[7b87e1d]553 odlink_t *link;
554 sif_attr_t *attr;
555
556 link = odict_find_eq(&node->attrs, (void *)aname, NULL);
557 if (link == NULL)
558 return;
559
560 attr = odict_get_instance(link, sif_attr_t, lattrs);
561 odict_remove(link);
562 sif_attr_delete(attr);
[b79903b]563}
564
565/** Export string to file.
566 *
567 * Export string to file (the string is bracketed and escaped).
568 *
569 * @param str String
570 * @param f File
571 * @return EOK on success, EIO on I/O error
572 */
573static errno_t sif_export_string(const char *str, FILE *f)
574{
575 const char *cp;
576
577 if (fputc('[', f) == EOF)
578 return EIO;
579
580 cp = str;
581 while (*cp != '\0') {
582 if (*cp == ']' || *cp == '\\') {
583 if (fputc('\\', f) == EOF)
584 return EIO;
585 }
586 if (fputc(*cp, f) == EOF)
587 return EIO;
588 ++cp;
589 }
590
591 if (fputc(']', f) == EOF)
592 return EIO;
593
594 return EOK;
595}
596
[9c5e3a5]597/** Import string from file.
598 *
599 * Import string from file (the string in the file must be
600 * properly bracketed and escaped).
601 *
602 * @param f File
603 * @param rstr Place to store pointer to newly allocated string
604 * @return EOK on success, EIO on I/O error
605 */
606static errno_t sif_import_string(FILE *f, char **rstr)
607{
608 char *str;
[153dd3b]609 char *nstr;
[9c5e3a5]610 size_t str_size;
611 size_t sidx;
[1c398db2]612 int c;
[9c5e3a5]613 errno_t rc;
614
615 str_size = 1;
616 sidx = 0;
617 str = malloc(str_size + 1);
618 if (str == NULL)
619 return ENOMEM;
620
621 c = fgetc(f);
622 if (c != '[') {
623 rc = EIO;
624 goto error;
625 }
626
627 while (true) {
628 c = fgetc(f);
629 if (c == EOF) {
630 rc = EIO;
631 goto error;
632 }
633
634 if (c == ']')
635 break;
636
637 if (c == '\\') {
638 c = fgetc(f);
639 if (c == EOF) {
640 rc = EIO;
641 goto error;
642 }
643 }
644
645 if (sidx >= str_size) {
646 str_size *= 2;
[153dd3b]647 nstr = realloc(str, str_size + 1);
648 if (nstr == NULL) {
[9c5e3a5]649 rc = ENOMEM;
650 goto error;
651 }
[153dd3b]652
653 str = nstr;
[9c5e3a5]654 }
655
656 str[sidx++] = c;
657 }
658
659 str[sidx] = '\0';
660 *rstr = str;
661 return EOK;
662error:
663 free(str);
664 return rc;
665}
666
[7b87e1d]667/** Import SIF attribute from file.
668 *
669 * @param node Node under which attribute shou
670 * @param f File
671 * @param rattr Place to store pointer to imported SIF attribute
672 * @return EOK on success, EIO on I/O error
673 */
674static errno_t sif_import_attr(sif_node_t *node, FILE *f, sif_attr_t **rattr)
675{
676 errno_t rc;
677 char *aname = NULL;
678 char *avalue = NULL;
679 sif_attr_t *attr;
680 int c;
681
682 rc = sif_import_string(f, &aname);
683 if (rc != EOK)
684 goto error;
685
686 c = fgetc(f);
687 if (c != '=') {
688 rc = EIO;
689 goto error;
690 }
691
692 rc = sif_import_string(f, &avalue);
693 if (rc != EOK)
694 goto error;
695
696 attr = sif_attr_new(node);
697 if (attr == NULL) {
698 rc = ENOMEM;
699 goto error;
700 }
701
702 attr->aname = aname;
703 attr->avalue = avalue;
704
705 *rattr = attr;
706 return EOK;
707error:
708 if (aname != NULL)
709 free(aname);
710 if (avalue != NULL)
711 free(avalue);
712 return rc;
713}
714
715/** Export SIF attribute to file.
716 *
717 * @param attr SIF attribute
718 * @param f File
719 * @return EOK on success, EIO on I/O error
720 */
721static errno_t sif_export_attr(sif_attr_t *attr, FILE *f)
722{
723 errno_t rc;
724
725 rc = sif_export_string(attr->aname, f);
726 if (rc != EOK)
727 return rc;
728
729 if (fputc('=', f) == EOF)
730 return EIO;
731
732 rc = sif_export_string(attr->avalue, f);
733 if (rc != EOK)
734 return rc;
735
736 return EOK;
737}
738
[b79903b]739/** Export SIF node to file.
740 *
741 * @param node SIF node
742 * @param f File
743 * @return EOK on success, EIO on I/O error
744 */
745static errno_t sif_export_node(sif_node_t *node, FILE *f)
746{
747 errno_t rc;
[7b87e1d]748 sif_attr_t *attr;
[b79903b]749 sif_node_t *child;
750
751 rc = sif_export_string(node->ntype, f);
752 if (rc != EOK)
753 return rc;
754
[7b87e1d]755 /* Attributes */
756
757 if (fputc('(', f) == EOF)
758 return EIO;
759
760 attr = sif_node_first_attr(node);
761 while (attr != NULL) {
762 rc = sif_export_attr(attr, f);
763 if (rc != EOK)
764 return rc;
765
766 attr = sif_node_next_attr(attr);
767 }
768
769 if (fputc(')', f) == EOF)
770 return EIO;
771
772 /* Child nodes */
773
[b79903b]774 if (fputc('{', f) == EOF)
775 return EIO;
776
777 child = sif_node_first_child(node);
778 while (child != NULL) {
779 rc = sif_export_node(child, f);
780 if (rc != EOK)
781 return rc;
782
783 child = sif_node_next_child(child);
784 }
785
786 if (fputc('}', f) == EOF)
787 return EIO;
788
789 return EOK;
790}
791
[9c5e3a5]792/** Import SIF node from file.
793 *
794 * @param parent Parent node
795 * @param f File
796 * @param rnode Place to store pointer to imported node
797 * @return EOK on success, EIO on I/O error
798 */
799static errno_t sif_import_node(sif_node_t *parent, FILE *f, sif_node_t **rnode)
800{
801 errno_t rc;
802 sif_node_t *node = NULL;
803 sif_node_t *child;
[ee8d4d6]804 sif_attr_t *attr = NULL;
[9c5e3a5]805 char *ntype;
[1c398db2]806 int c;
[9c5e3a5]807
808 node = sif_node_new(parent);
809 if (node == NULL)
810 return ENOMEM;
811
812 rc = sif_import_string(f, &ntype);
813 if (rc != EOK)
814 goto error;
815
816 node->ntype = ntype;
817
[7b87e1d]818 /* Attributes */
819
820 c = fgetc(f);
821 if (c != '(') {
822 rc = EIO;
823 goto error;
824 }
825
826 c = fgetc(f);
827 if (c == EOF) {
828 rc = EIO;
829 goto error;
830 }
831
832 while (c != ')') {
833 ungetc(c, f);
834
835 rc = sif_import_attr(node, f, &attr);
836 if (rc != EOK)
837 goto error;
838
839 odict_insert(&attr->lattrs, &node->attrs, NULL);
840
841 c = fgetc(f);
842 if (c == EOF) {
843 rc = EIO;
844 goto error;
845 }
846 }
847
848 /* Child nodes */
849
[9c5e3a5]850 c = fgetc(f);
851 if (c != '{') {
852 rc = EIO;
853 goto error;
854 }
855
856 c = fgetc(f);
857 if (c == EOF) {
858 rc = EIO;
859 goto error;
860 }
861
862 while (c != '}') {
863 ungetc(c, f);
864
865 rc = sif_import_node(node, f, &child);
866 if (rc != EOK)
867 goto error;
868
869 list_append(&child->lparent, &node->children);
870
871 c = fgetc(f);
872 if (c == EOF) {
873 rc = EIO;
874 goto error;
875 }
876 }
877
878 *rnode = node;
879 return EOK;
880error:
881 sif_node_delete(node);
882 return rc;
883}
884
[7b87e1d]885/** Get first attribute or a node.
886 *
887 * @param node SIF node
888 * @return First attribute or @c NULL if there is none
889 */
890static sif_attr_t *sif_node_first_attr(sif_node_t *node)
891{
892 odlink_t *link;
893
894 link = odict_first(&node->attrs);
895 if (link == NULL)
896 return NULL;
897
898 return odict_get_instance(link, sif_attr_t, lattrs);
899}
900
901/** Get next attribute or a node.
902 *
903 * @param cur Current attribute
904 * @return Next attribute or @c NULL if there is none
905 */
906static sif_attr_t *sif_node_next_attr(sif_attr_t *cur)
907{
908 odlink_t *link;
909
910 link = odict_next(&cur->lattrs, &cur->node->attrs);
911 if (link == NULL)
912 return NULL;
913
914 return odict_get_instance(link, sif_attr_t, lattrs);
915}
916
917/** Get key callback for ordered dictionary of node attributes.
918 *
919 * @param link Ordered dictionary link of attribute
920 * @return Pointer to attribute name
921 */
922static void *sif_attr_getkey(odlink_t *link)
923{
924 return (void *)odict_get_instance(link, sif_attr_t, lattrs)->aname;
925}
926
927/** Comparison callback for ordered dictionary of node attributes.
928 *
929 * @param a Name of first attribute
930 * @param b Name of second attribute
931 * @return Less than zero, zero or greater than zero, if a < b, a == b, a > b,
932 * respectively.
933 */
934static int sif_attr_cmp(void *a, void *b)
935{
936 char *ca, *cb;
937
938 ca = (char *)a;
939 cb = (char *)b;
940
941 return str_cmp(ca, cb);
942}
943
[b79903b]944/** @}
945 */
Note: See TracBrowser for help on using the repository browser.