HelenOS sources
This source file includes following definitions.
- sif_node_new
- sif_node_delete
- sif_attr_new
- sif_attr_delete
- sif_create
- sif_open
- sif_close
- sif_get_root
- sif_node_first_child
- sif_node_next_child
- sif_node_get_type
- sif_node_get_attr
- sif_trans_begin
- sif_trans_end
- sif_trans_abort
- sif_node_prepend_child
- sif_node_append_child
- sif_node_insert_before
- sif_node_insert_after
- sif_node_destroy
- sif_node_set_attr
- sif_node_unset_attr
- sif_export_string
- sif_import_string
- sif_import_attr
- sif_export_attr
- sif_export_node
- sif_import_node
- sif_node_first_attr
- sif_node_next_attr
- sif_attr_getkey
- sif_attr_cmp
#include <adt/list.h>
#include <adt/odict.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <str.h>
#include "../include/sif.h"
#include "../private/sif.h"
static errno_t sif_export_node(sif_node_t *, FILE *);
static errno_t sif_import_node(sif_node_t *, FILE *, sif_node_t **);
static sif_attr_t *sif_node_first_attr(sif_node_t *);
static sif_attr_t *sif_node_next_attr(sif_attr_t *);
static void sif_attr_delete(sif_attr_t *);
static void *sif_attr_getkey(odlink_t *);
static int sif_attr_cmp(void *, void *);
static sif_node_t *sif_node_new(sif_node_t *parent)
{
sif_node_t *node;
node = calloc(1, sizeof(sif_node_t));
if (node == NULL)
return NULL;
node->parent = parent;
odict_initialize(&node->attrs, sif_attr_getkey, sif_attr_cmp);
list_initialize(&node->children);
return node;
}
static void sif_node_delete(sif_node_t *node)
{
sif_attr_t *attr;
sif_node_t *child;
if (node == NULL)
return;
assert(!link_used(&node->lparent));
if (node->ntype != NULL)
free(node->ntype);
attr = sif_node_first_attr(node);
while (attr != NULL) {
odict_remove(&attr->lattrs);
sif_attr_delete(attr);
attr = sif_node_first_attr(node);
}
child = sif_node_first_child(node);
while (child != NULL) {
list_remove(&child->lparent);
sif_node_delete(child);
child = sif_node_first_child(node);
}
free(node);
}
static sif_attr_t *sif_attr_new(sif_node_t *node)
{
sif_attr_t *attr;
attr = calloc(1, sizeof(sif_attr_t));
if (attr == NULL)
return NULL;
attr->node = node;
return attr;
}
static void sif_attr_delete(sif_attr_t *attr)
{
if (attr == NULL)
return;
assert(!odlink_used(&attr->lattrs));
if (attr->aname != NULL)
free(attr->aname);
if (attr->avalue != NULL)
free(attr->avalue);
free(attr);
}
errno_t sif_create(const char *fname, sif_sess_t **rsess)
{
sif_sess_t *sess;
sif_node_t *root = NULL;
sif_trans_t *trans = NULL;
errno_t rc;
FILE *f;
sess = calloc(1, sizeof(sif_sess_t));
if (sess == NULL)
return ENOMEM;
sess->fname = str_dup(fname);
if (sess->fname == NULL) {
rc = ENOMEM;
goto error;
}
root = sif_node_new(NULL);
if (root == NULL) {
rc = ENOMEM;
goto error;
}
root->ntype = str_dup("sif");
if (root->ntype == NULL) {
rc = ENOMEM;
goto error;
}
f = fopen(fname, "wx");
if (f == NULL) {
rc = EIO;
goto error;
}
sess->f = f;
sess->root = root;
rc = sif_trans_begin(sess, &trans);
if (rc != EOK)
goto error;
rc = sif_trans_end(trans);
if (rc != EOK)
goto error;
*rsess = sess;
return EOK;
error:
if (trans != NULL)
sif_trans_abort(trans);
sif_node_delete(root);
if (sess->fname != NULL)
free(sess->fname);
free(sess);
return rc;
}
errno_t sif_open(const char *fname, sif_sess_t **rsess)
{
sif_sess_t *sess;
sif_node_t *root = NULL;
errno_t rc;
FILE *f;
sess = calloc(1, sizeof(sif_sess_t));
if (sess == NULL)
return ENOMEM;
sess->fname = str_dup(fname);
if (sess->fname == NULL) {
rc = ENOMEM;
goto error;
}
f = fopen(fname, "r");
if (f == NULL) {
rc = EIO;
goto error;
}
rc = sif_import_node(NULL, f, &root);
if (rc != EOK)
goto error;
if (str_cmp(root->ntype, "sif") != 0) {
rc = EIO;
goto error;
}
sess->root = root;
sess->f = f;
sess->root = root;
*rsess = sess;
return EOK;
error:
sif_node_delete(root);
if (sess->fname != NULL)
free(sess->fname);
free(sess);
return rc;
}
errno_t sif_close(sif_sess_t *sess)
{
sif_node_delete(sess->root);
if (fclose(sess->f) < 0) {
free(sess);
return EIO;
}
if (sess->fname != NULL)
free(sess->fname);
free(sess);
return EOK;
}
sif_node_t *sif_get_root(sif_sess_t *sess)
{
return sess->root;
}
sif_node_t *sif_node_first_child(sif_node_t *parent)
{
link_t *link;
link = list_first(&parent->children);
if (link == NULL)
return NULL;
return list_get_instance(link, sif_node_t, lparent);
}
sif_node_t *sif_node_next_child(sif_node_t *current)
{
link_t *link;
link = list_next(¤t->lparent, ¤t->parent->children);
if (link == NULL)
return NULL;
return list_get_instance(link, sif_node_t, lparent);
}
const char *sif_node_get_type(sif_node_t *node)
{
return node->ntype;
}
const char *sif_node_get_attr(sif_node_t *node, const char *aname)
{
odlink_t *link;
sif_attr_t *attr;
link = odict_find_eq(&node->attrs, (void *)aname, NULL);
if (link == NULL)
return NULL;
attr = odict_get_instance(link, sif_attr_t, lattrs);
return attr->avalue;
}
errno_t sif_trans_begin(sif_sess_t *sess, sif_trans_t **rtrans)
{
sif_trans_t *trans;
trans = calloc(1, sizeof(sif_trans_t));
if (trans == NULL)
return ENOMEM;
trans->sess = sess;
*rtrans = trans;
return EOK;
}
errno_t sif_trans_end(sif_trans_t *trans)
{
errno_t rc;
(void) fclose(trans->sess->f);
trans->sess->f = fopen(trans->sess->fname, "w");
if (trans->sess->f == NULL)
return EIO;
rc = sif_export_node(trans->sess->root, trans->sess->f);
if (rc != EOK)
return rc;
if (fputc('\n', trans->sess->f) == EOF)
return EIO;
if (fflush(trans->sess->f) == EOF)
return EIO;
free(trans);
return EOK;
}
void sif_trans_abort(sif_trans_t *trans)
{
free(trans);
}
errno_t sif_node_prepend_child(sif_trans_t *trans, sif_node_t *parent,
const char *ctype, sif_node_t **rchild)
{
sif_node_t *child;
child = sif_node_new(parent);
if (child == NULL)
return ENOMEM;
child->ntype = str_dup(ctype);
if (child->ntype == NULL) {
sif_node_delete(child);
return ENOMEM;
}
list_prepend(&child->lparent, &parent->children);
*rchild = child;
return EOK;
}
errno_t sif_node_append_child(sif_trans_t *trans, sif_node_t *parent,
const char *ctype, sif_node_t **rchild)
{
sif_node_t *child;
child = sif_node_new(parent);
if (child == NULL)
return ENOMEM;
child->ntype = str_dup(ctype);
if (child->ntype == NULL) {
sif_node_delete(child);
return ENOMEM;
}
list_append(&child->lparent, &parent->children);
*rchild = child;
return EOK;
}
errno_t sif_node_insert_before(sif_trans_t *trans, sif_node_t *sibling,
const char *ctype, sif_node_t **rchild)
{
sif_node_t *child;
child = sif_node_new(sibling->parent);
if (child == NULL)
return ENOMEM;
child->ntype = str_dup(ctype);
if (child->ntype == NULL) {
sif_node_delete(child);
return ENOMEM;
}
list_insert_before(&child->lparent, &sibling->lparent);
*rchild = child;
return EOK;
}
errno_t sif_node_insert_after(sif_trans_t *trans, sif_node_t *sibling,
const char *ctype, sif_node_t **rchild)
{
sif_node_t *child;
child = sif_node_new(sibling->parent);
if (child == NULL)
return ENOMEM;
child->ntype = str_dup(ctype);
if (child->ntype == NULL) {
sif_node_delete(child);
return ENOMEM;
}
list_insert_after(&child->lparent, &sibling->lparent);
*rchild = child;
return EOK;
}
void sif_node_destroy(sif_trans_t *trans, sif_node_t *node)
{
list_remove(&node->lparent);
sif_node_delete(node);
}
errno_t sif_node_set_attr(sif_trans_t *trans, sif_node_t *node,
const char *aname, const char *avalue)
{
odlink_t *link;
sif_attr_t *attr;
char *cvalue;
link = odict_find_eq(&node->attrs, (void *)aname, NULL);
if (link != NULL) {
attr = odict_get_instance(link, sif_attr_t, lattrs);
cvalue = str_dup(avalue);
if (cvalue == NULL)
return ENOMEM;
free(attr->avalue);
attr->avalue = cvalue;
} else {
attr = sif_attr_new(node);
if (attr == NULL)
return ENOMEM;
attr->aname = str_dup(aname);
if (attr->aname == NULL) {
sif_attr_delete(attr);
return ENOMEM;
}
attr->avalue = str_dup(avalue);
if (attr->avalue == NULL) {
sif_attr_delete(attr);
return ENOMEM;
}
odict_insert(&attr->lattrs, &node->attrs, NULL);
}
return EOK;
}
void sif_node_unset_attr(sif_trans_t *trans, sif_node_t *node,
const char *aname)
{
odlink_t *link;
sif_attr_t *attr;
link = odict_find_eq(&node->attrs, (void *)aname, NULL);
if (link == NULL)
return;
attr = odict_get_instance(link, sif_attr_t, lattrs);
odict_remove(link);
sif_attr_delete(attr);
}
static errno_t sif_export_string(const char *str, FILE *f)
{
const char *cp;
if (fputc('[', f) == EOF)
return EIO;
cp = str;
while (*cp != '\0') {
if (*cp == ']' || *cp == '\\') {
if (fputc('\\', f) == EOF)
return EIO;
}
if (fputc(*cp, f) == EOF)
return EIO;
++cp;
}
if (fputc(']', f) == EOF)
return EIO;
return EOK;
}
static errno_t sif_import_string(FILE *f, char **rstr)
{
char *str;
char *nstr;
size_t str_size;
size_t sidx;
int c;
errno_t rc;
str_size = 1;
sidx = 0;
str = malloc(str_size + 1);
if (str == NULL)
return ENOMEM;
c = fgetc(f);
if (c != '[') {
rc = EIO;
goto error;
}
while (true) {
c = fgetc(f);
if (c == EOF) {
rc = EIO;
goto error;
}
if (c == ']')
break;
if (c == '\\') {
c = fgetc(f);
if (c == EOF) {
rc = EIO;
goto error;
}
}
if (sidx >= str_size) {
str_size *= 2;
nstr = realloc(str, str_size + 1);
if (nstr == NULL) {
rc = ENOMEM;
goto error;
}
str = nstr;
}
str[sidx++] = c;
}
str[sidx] = '\0';
*rstr = str;
return EOK;
error:
free(str);
return rc;
}
static errno_t sif_import_attr(sif_node_t *node, FILE *f, sif_attr_t **rattr)
{
errno_t rc;
char *aname = NULL;
char *avalue = NULL;
sif_attr_t *attr;
int c;
rc = sif_import_string(f, &aname);
if (rc != EOK)
goto error;
c = fgetc(f);
if (c != '=') {
rc = EIO;
goto error;
}
rc = sif_import_string(f, &avalue);
if (rc != EOK)
goto error;
attr = sif_attr_new(node);
if (attr == NULL) {
rc = ENOMEM;
goto error;
}
attr->aname = aname;
attr->avalue = avalue;
*rattr = attr;
return EOK;
error:
if (aname != NULL)
free(aname);
if (avalue != NULL)
free(avalue);
return rc;
}
static errno_t sif_export_attr(sif_attr_t *attr, FILE *f)
{
errno_t rc;
rc = sif_export_string(attr->aname, f);
if (rc != EOK)
return rc;
if (fputc('=', f) == EOF)
return EIO;
rc = sif_export_string(attr->avalue, f);
if (rc != EOK)
return rc;
return EOK;
}
static errno_t sif_export_node(sif_node_t *node, FILE *f)
{
errno_t rc;
sif_attr_t *attr;
sif_node_t *child;
rc = sif_export_string(node->ntype, f);
if (rc != EOK)
return rc;
if (fputc('(', f) == EOF)
return EIO;
attr = sif_node_first_attr(node);
while (attr != NULL) {
rc = sif_export_attr(attr, f);
if (rc != EOK)
return rc;
attr = sif_node_next_attr(attr);
}
if (fputc(')', f) == EOF)
return EIO;
if (fputc('{', f) == EOF)
return EIO;
child = sif_node_first_child(node);
while (child != NULL) {
rc = sif_export_node(child, f);
if (rc != EOK)
return rc;
child = sif_node_next_child(child);
}
if (fputc('}', f) == EOF)
return EIO;
return EOK;
}
static errno_t sif_import_node(sif_node_t *parent, FILE *f, sif_node_t **rnode)
{
errno_t rc;
sif_node_t *node = NULL;
sif_node_t *child;
sif_attr_t *attr = NULL;
char *ntype;
int c;
node = sif_node_new(parent);
if (node == NULL)
return ENOMEM;
rc = sif_import_string(f, &ntype);
if (rc != EOK)
goto error;
node->ntype = ntype;
c = fgetc(f);
if (c != '(') {
rc = EIO;
goto error;
}
c = fgetc(f);
if (c == EOF) {
rc = EIO;
goto error;
}
while (c != ')') {
ungetc(c, f);
rc = sif_import_attr(node, f, &attr);
if (rc != EOK)
goto error;
odict_insert(&attr->lattrs, &node->attrs, NULL);
c = fgetc(f);
if (c == EOF) {
rc = EIO;
goto error;
}
}
c = fgetc(f);
if (c != '{') {
rc = EIO;
goto error;
}
c = fgetc(f);
if (c == EOF) {
rc = EIO;
goto error;
}
while (c != '}') {
ungetc(c, f);
rc = sif_import_node(node, f, &child);
if (rc != EOK)
goto error;
list_append(&child->lparent, &node->children);
c = fgetc(f);
if (c == EOF) {
rc = EIO;
goto error;
}
}
*rnode = node;
return EOK;
error:
sif_node_delete(node);
return rc;
}
static sif_attr_t *sif_node_first_attr(sif_node_t *node)
{
odlink_t *link;
link = odict_first(&node->attrs);
if (link == NULL)
return NULL;
return odict_get_instance(link, sif_attr_t, lattrs);
}
static sif_attr_t *sif_node_next_attr(sif_attr_t *cur)
{
odlink_t *link;
link = odict_next(&cur->lattrs, &cur->node->attrs);
if (link == NULL)
return NULL;
return odict_get_instance(link, sif_attr_t, lattrs);
}
static void *sif_attr_getkey(odlink_t *link)
{
return (void *)odict_get_instance(link, sif_attr_t, lattrs)->aname;
}
static int sif_attr_cmp(void *a, void *b)
{
char *ca, *cb;
ca = (char *)a;
cb = (char *)b;
return str_cmp(ca, cb);
}
HelenOS homepage, sources at GitHub