Index: uspace/lib/sif/src/sif.c
===================================================================
--- uspace/lib/sif/src/sif.c	(revision bff8619cdacb5b15f795cd78a330c58648be779b)
+++ uspace/lib/sif/src/sif.c	(revision 7268bf1477ab3540e4dcf359102dcb4b92317d13)
@@ -45,5 +45,7 @@
 #include <adt/list.h>
 #include <adt/odict.h>
+#include <ctype.h>
 #include <errno.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -53,5 +55,5 @@
 
 static errno_t sif_export_node(sif_node_t *, FILE *);
-static errno_t sif_import_node(sif_node_t *, FILE *, sif_node_t **);
+static errno_t sif_import_node(sif_node_t *, FILE *, sif_node_t **, bool *);
 static sif_attr_t *sif_node_first_attr(sif_node_t *);
 static sif_attr_t *sif_node_next_attr(sif_attr_t *);
@@ -60,4 +62,24 @@
 static int sif_attr_cmp(void *, void *);
 
+/** Determine if character can start a name.
+ *
+ * @param c Character
+ * @return @c true iff the character can start a name
+ */
+static bool sif_is_name_start_char(char c)
+{
+	return isalpha(c) || c == '_';
+}
+
+/** Determine if character can continue a name.
+ *
+ * @param c Character
+ * @return @c true iff the character can continue a name
+ */
+static bool sif_is_name_char(char c)
+{
+	return isalnum(c) || c == '-' || c == '.';
+}
+
 /** Create new SIF node.
  *
@@ -205,4 +227,5 @@
 	sif_node_t *root = NULL;
 	errno_t rc;
+	bool endtag;
 	FILE *f;
 
@@ -223,6 +246,6 @@
 	}
 
-	rc = sif_import_node(NULL, f, &root);
-	if (rc != EOK)
+	rc = sif_import_node(NULL, f, &root, &endtag);
+	if (rc != EOK || endtag == true)
 		goto error;
 
@@ -343,9 +366,4 @@
 	if (rc != EOK)
 		goto error;
-
-	if (fputc('\n', f) == EOF) {
-		rc = EIO;
-		goto error;
-	}
 
 	if (fflush(f) == EOF) {
@@ -563,7 +581,7 @@
 }
 
-/** Export string to file.
- *
- * Export string to file (the string is bracketed and escaped).
+/** Export node name to file.
+ *
+ * Export node name to file.
  *
  * @param str String
@@ -571,38 +589,79 @@
  * @return EOK on success, EIO on I/O error
  */
+static errno_t sif_export_name(const char *str, FILE *f)
+{
+	if (fputs(str, f) == EOF)
+		return EIO;
+
+	return EOK;
+}
+
+/** Export string to file.
+ *
+ * Export string to file (the string is double-quoted and escaped).
+ *
+ * @param str String
+ * @param f File
+ * @return EOK on success, EIO on I/O error
+ */
 static errno_t sif_export_string(const char *str, FILE *f)
 {
 	const char *cp;
 
-	if (fputc('[', f) == EOF)
+	if (fputc('"', f) == EOF)
 		return EIO;
 
 	cp = str;
 	while (*cp != '\0') {
-		if (*cp == ']' || *cp == '\\') {
-			if (fputc('\\', f) == EOF)
+		if (*cp == '<') {
+			if (fputs("&lt;", f) == EOF)
+				return EIO;
+		} else if (*cp == '"') {
+			if (fputs("&quot;", f) == EOF)
+				return EIO;
+		} else {
+			if (fputc(*cp, f) == EOF)
 				return EIO;
 		}
-		if (fputc(*cp, f) == EOF)
+
+		++cp;
+	}
+
+	if (fputc('"', f) == EOF)
+		return EIO;
+
+	return EOK;
+}
+
+/** Read characters from file, make sure they match the specified sequence.
+ *
+ * @param f File
+ * @param chars Expected sequence of characters to be read
+ *
+ * @return EOK on success, EIO on I/O error or mismatch
+ */
+static errno_t sif_get_verify_chars(FILE *f, const char *chars)
+{
+	const char *cp;
+	char c;
+
+	cp = chars;
+	while (*cp != '\0') {
+		c = fgetc(f);
+		if (c != *cp)
 			return EIO;
 		++cp;
 	}
 
-	if (fputc(']', f) == EOF)
-		return EIO;
-
-	return EOK;
-}
-
-/** Import string from file.
- *
- * Import string from file (the string in the file must be
- * properly bracketed and escaped).
- *
+	return EOK;
+}
+
+/** Import name from file.
+ * *
  * @param f File
  * @param rstr Place to store pointer to newly allocated string
  * @return EOK on success, EIO on I/O error
  */
-static errno_t sif_import_string(FILE *f, char **rstr)
+static errno_t sif_import_name(FILE *f, char **rstr)
 {
 	char *str;
@@ -620,5 +679,5 @@
 
 	c = fgetc(f);
-	if (c != '[') {
+	if (!sif_is_name_start_char(c)) {
 		rc = EIO;
 		goto error;
@@ -626,21 +685,4 @@
 
 	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;
@@ -655,4 +697,93 @@
 
 		str[sidx++] = c;
+
+		c = fgetc(f);
+		if (!sif_is_name_char(c))
+			break;
+	}
+
+	ungetc(c, f);
+
+	str[sidx] = '\0';
+	*rstr = str;
+	return EOK;
+error:
+	free(str);
+	return rc;
+}
+
+/** Import string from file.
+ *
+ * Import string from file (the string in the file must be
+ * properly quoted and escaped).
+ *
+ * @param f File
+ * @param rstr Place to store pointer to newly allocated string
+ * @return EOK on success, EIO on I/O error
+ */
+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 (c == 'q') {
+				rc = sif_get_verify_chars(f, "uot;");
+				if (rc != EOK)
+					goto error;
+			} else if (c == 'l') {
+				rc = sif_get_verify_chars(f, "t;");
+				if (rc != EOK)
+					goto error;
+			} else {
+				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;
 	}
 
@@ -680,5 +811,5 @@
 	int c;
 
-	rc = sif_import_string(f, &aname);
+	rc = sif_import_name(f, &aname);
 	if (rc != EOK)
 		goto error;
@@ -723,5 +854,5 @@
 	errno_t rc;
 
-	rc = sif_export_string(attr->aname, f);
+	rc = sif_export_name(attr->aname, f);
 	if (rc != EOK)
 		return rc;
@@ -749,5 +880,8 @@
 	sif_node_t *child;
 
-	rc = sif_export_string(node->ntype, f);
+	if (fputc('<', f) == EOF)
+		return EIO;
+
+	rc = sif_export_name(node->ntype, f);
 	if (rc != EOK)
 		return rc;
@@ -755,9 +889,9 @@
 	/* Attributes */
 
-	if (fputc('(', f) == EOF)
-		return EIO;
-
 	attr = sif_node_first_attr(node);
 	while (attr != NULL) {
+		if (fputc(' ', f) == EOF)
+			return EIO;
+
 		rc = sif_export_attr(attr, f);
 		if (rc != EOK)
@@ -767,11 +901,8 @@
 	}
 
-	if (fputc(')', f) == EOF)
+	if (fputs(">\n", f) == EOF)
 		return EIO;
 
 	/* Child nodes */
-
-	if (fputc('{', f) == EOF)
-		return EIO;
 
 	child = sif_node_first_child(node);
@@ -784,5 +915,12 @@
 	}
 
-	if (fputc('}', f) == EOF)
+	if (fputs("</", f) == EOF)
+		return EIO;
+
+	rc = sif_export_name(node->ntype, f);
+	if (rc != EOK)
+		return rc;
+
+	if (fputs(">\n", f) == EOF)
 		return EIO;
 
@@ -795,7 +933,9 @@
  * @param f File
  * @param rnode Place to store pointer to imported node
+ * @param rendtag Place to store @c true iff end tag is encountered
  * @return EOK on success, EIO on I/O error
  */
-static errno_t sif_import_node(sif_node_t *parent, FILE *f, sif_node_t **rnode)
+static errno_t sif_import_node(sif_node_t *parent, FILE *f, sif_node_t **rnode,
+    bool *rendtag)
 {
 	errno_t rc;
@@ -803,4 +943,6 @@
 	sif_node_t *child;
 	sif_attr_t *attr = NULL;
+	bool endtag;
+	bool cendtag;
 	char *ntype;
 	int c;
@@ -810,5 +952,22 @@
 		return ENOMEM;
 
-	rc = sif_import_string(f, &ntype);
+	c = fgetc(f);
+	while (isspace(c))
+		c = fgetc(f);
+
+	if (c != '<') {
+		rc = EIO;
+		goto error;
+	}
+
+	c = fgetc(f);
+	if (c == '/') {
+		endtag = true;
+	} else {
+		endtag = false;
+		ungetc(c, f);
+	}
+
+	rc = sif_import_name(f, &ntype);
 	if (rc != EOK)
 		goto error;
@@ -817,10 +976,4 @@
 
 	/* Attributes */
-
-	c = fgetc(f);
-	if (c != '(') {
-		rc = EIO;
-		goto error;
-	}
 
 	c = fgetc(f);
@@ -830,5 +983,13 @@
 	}
 
-	while (c != ')') {
+	while (c != '>') {
+		/* End tags cannot have attributes */
+		if (endtag) {
+			rc = EIO;
+			goto error;
+		}
+
+		while (isspace(c))
+			c = fgetc(f);
 		ungetc(c, f);
 
@@ -848,33 +1009,21 @@
 	/* Child nodes */
 
-	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;
+	if (!endtag) {
+		while (true) {
+			rc = sif_import_node(node, f, &child, &cendtag);
+			if (rc != EOK)
+				goto error;
+
+			if (cendtag) {
+				sif_node_delete(child);
+				break;
+			}
+
+			list_append(&child->lparent, &node->children);
 		}
 	}
 
 	*rnode = node;
+	*rendtag = endtag;
 	return EOK;
 error:
