Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Tree construction tester.
  3.  */
  4.  
  5. #define _GNU_SOURCE
  6.  
  7. #include <inttypes.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. #include <hubbub/hubbub.h>
  13. #include <hubbub/parser.h>
  14. #include <hubbub/tree.h>
  15.  
  16. #include "utils/utils.h"
  17.  
  18. #include "testutils.h"
  19.  
  20. typedef struct attr_t attr_t;
  21. typedef struct node_t node_t;
  22. typedef struct buf_t buf_t;
  23.  
  24. struct attr_t {
  25.         hubbub_ns ns;
  26.         char *name;
  27.         char *value;
  28. };
  29.  
  30. struct node_t {
  31.         enum { DOCTYPE, COMMENT, ELEMENT, CHARACTER } type;
  32.  
  33.         union {
  34.                 struct {
  35.                         char *name;
  36.                         char *public_id;
  37.                         char *system_id;
  38.                 } doctype;
  39.  
  40.                 struct {
  41.                         hubbub_ns ns;
  42.                         char *name;
  43.                         attr_t *attrs;
  44.                         size_t n_attrs;
  45.                 } element;
  46.  
  47.                 char *content;          /**< For comments, characters **/
  48.         } data;
  49.  
  50.         node_t *next;
  51.         node_t *prev;
  52.  
  53.         node_t *child;
  54.         node_t *parent;
  55.  
  56.         uint32_t refcnt;
  57. };
  58.  
  59. struct buf_t {
  60.         char *buf;
  61.         size_t len;
  62.         size_t pos;
  63. };
  64.  
  65.  
  66. #define NUM_NAMESPACES 7
  67. const char * const ns_names[NUM_NAMESPACES] =
  68.                 { NULL, NULL /*html*/, "math", "svg", "xlink", "xml", "xmlns" };
  69.  
  70.  
  71. node_t *Document;
  72.  
  73.  
  74.  
  75. static void node_print(buf_t *buf, node_t *node, unsigned depth);
  76.  
  77. static hubbub_error create_comment(void *ctx, const hubbub_string *data, void **result);
  78. static hubbub_error create_doctype(void *ctx, const hubbub_doctype *doctype,
  79.                 void **result);
  80. static hubbub_error create_element(void *ctx, const hubbub_tag *tag, void **result);
  81. static hubbub_error create_text(void *ctx, const hubbub_string *data, void **result);
  82. static hubbub_error ref_node(void *ctx, void *node);
  83. static hubbub_error unref_node(void *ctx, void *node);
  84. static hubbub_error append_child(void *ctx, void *parent, void *child, void **result);
  85. static hubbub_error insert_before(void *ctx, void *parent, void *child, void *ref_child,
  86.                 void **result);
  87. static hubbub_error remove_child(void *ctx, void *parent, void *child, void **result);
  88. static hubbub_error clone_node(void *ctx, void *node, bool deep, void **result);
  89. static hubbub_error reparent_children(void *ctx, void *node, void *new_parent);
  90. static hubbub_error get_parent(void *ctx, void *node, bool element_only, void **result);
  91. static hubbub_error has_children(void *ctx, void *node, bool *result);
  92. static hubbub_error form_associate(void *ctx, void *form, void *node);
  93. static hubbub_error add_attributes(void *ctx, void *node,
  94.                 const hubbub_attribute *attributes, uint32_t n_attributes);
  95. static hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode);
  96. static hubbub_error complete_script(void *ctx, void *script);
  97.  
  98. static void delete_node(node_t *node);
  99. static void delete_attr(attr_t *attr);
  100.  
  101. static hubbub_tree_handler tree_handler = {
  102.         create_comment,
  103.         create_doctype,
  104.         create_element,
  105.         create_text,
  106.         ref_node,
  107.         unref_node,
  108.         append_child,
  109.         insert_before,
  110.         remove_child,
  111.         clone_node,
  112.         reparent_children,
  113.         get_parent,
  114.         has_children,
  115.         form_associate,
  116.         add_attributes,
  117.         set_quirks_mode,
  118.         NULL,
  119.         complete_script,
  120.         NULL
  121. };
  122.  
  123. static void *myrealloc(void *ptr, size_t len, void *pw)
  124. {
  125.         void *ret;
  126.  
  127.         UNUSED(pw);
  128.  
  129.         /* A half-arsed attempt at filling freshly allocated space with junk. */
  130.         if (ptr == NULL) {
  131.                 ret = malloc(len);
  132.                 if (ret != NULL)
  133.                         memset(ret, 0xdf, len);
  134.         } else {
  135.                 ret = realloc(ptr, len);
  136.         }
  137.  
  138.         return ret;
  139. }
  140.  
  141.  
  142. /*
  143.  * Create, initialise, and return, a parser instance.
  144.  */
  145. static hubbub_parser *setup_parser(void)
  146. {
  147.         hubbub_parser *parser;
  148.         hubbub_parser_optparams params;
  149.  
  150.         assert(hubbub_parser_create("UTF-8", false, myrealloc, NULL, &parser) ==
  151.                         HUBBUB_OK);
  152.  
  153.         params.tree_handler = &tree_handler;
  154.         assert(hubbub_parser_setopt(parser, HUBBUB_PARSER_TREE_HANDLER,
  155.                         &params) == HUBBUB_OK);
  156.  
  157.         params.document_node = (void *)1;
  158.         assert(hubbub_parser_setopt(parser, HUBBUB_PARSER_DOCUMENT_NODE,
  159.                         &params) == HUBBUB_OK);
  160.  
  161. /* Don't enable scripting -- we want the same behaviour as NetSurf.
  162.         params.enable_scripting = true;
  163.         assert(hubbub_parser_setopt(parser, HUBBUB_PARSER_ENABLE_SCRIPTING,
  164.                         &params) == HUBBUB_OK);
  165. */
  166.  
  167.         return parser;
  168. }
  169.  
  170.  
  171.  
  172. /*** Buffer handling bits ***/
  173. static void buf_add(buf_t *buf, const char *str)
  174. {
  175.         size_t len = strlen(str) + 1;
  176.  
  177.         if (!buf) {
  178.                 printf("%s", str);
  179.                 return;
  180.         }
  181.  
  182.         if (buf->buf == NULL) {
  183.                 buf->len = ((len + 1024) / 1024) * 1024;
  184.                 buf->buf = calloc(1, buf->len);
  185.         }
  186.  
  187.         while (buf->pos + len > buf->len) {
  188.                 buf->len *= 2;
  189.                 buf->buf = realloc(buf->buf, buf->len);
  190.         }
  191.  
  192.         strcat(buf->buf, str);
  193.         buf->pos += len;
  194. }
  195.  
  196.  
  197. int main(int argc, char **argv)
  198. {
  199.         FILE *fp;
  200.         char buf[4096];
  201.         size_t *chunks;
  202.         size_t n_chunks;
  203.         hubbub_parser *parser;
  204.         uint32_t i;
  205.  
  206.         buf_t got = { NULL, 0, 0 };
  207.  
  208.         if (argc != 2) {
  209.                 printf("Usage: %s <filename>\n", argv[0]);
  210.                 return 1;
  211.         }
  212.  
  213.         fp = fopen(argv[1], "rb");
  214.         if (fp == NULL) {
  215.                 printf("Failed opening %s\n", argv[1]);
  216.                 return 1;
  217.         }
  218.  
  219.         /* Format:
  220.          * #chunks <n>
  221.          * <n> lines
  222.          * #data
  223.          * <data>
  224.          */
  225.  
  226.         assert(fgets(buf, sizeof(buf), fp) != NULL);
  227.         assert(strncmp(buf, "#chunks ", sizeof("#chunks ") - 1) == 0);
  228.         n_chunks = atoi(buf + sizeof("#chunks ") - 1);
  229.  
  230.         chunks = malloc(n_chunks * sizeof(size_t));
  231.         assert(chunks != NULL);
  232.  
  233.         for (i = 0; i < n_chunks; i++) {
  234.                 assert(fgets(buf, sizeof(buf), fp) != NULL);
  235.                 chunks[i] = atoi(buf);
  236.         }
  237.  
  238.         assert(fgets(buf, sizeof(buf), fp) != NULL);
  239.         assert(strcmp(buf, "#data\n") == 0);
  240.  
  241.         parser = setup_parser();
  242.  
  243.         for (i = 0; i < n_chunks; i++) {
  244.                 ssize_t bytes_read;
  245.                 assert(chunks[i] <= sizeof(buf));
  246.  
  247.                 bytes_read = fread(buf, 1, chunks[i], fp);
  248.                 assert((size_t)(bytes_read) == chunks[i]);
  249.  
  250.                 assert(hubbub_parser_parse_chunk(parser, (uint8_t *) buf,
  251.                                 chunks[i]) == HUBBUB_OK);
  252.         }
  253.  
  254.         assert(hubbub_parser_completed(parser) == HUBBUB_OK);
  255.  
  256.         node_print(&got, Document, 0);
  257.         printf("%s", got.buf);
  258.  
  259.         hubbub_parser_destroy(parser);
  260.         while (Document) {
  261.                 node_t *victim = Document;
  262.                 Document = victim->next;
  263.                 delete_node(victim);
  264.         }
  265.         Document = NULL;
  266.  
  267.         printf("PASS\n");
  268.  
  269.         fclose(fp);
  270.  
  271.         free(got.buf);
  272.  
  273.         return 0;
  274. }
  275.  
  276.  
  277. /*** Tree construction functions ***/
  278.  
  279. hubbub_error create_comment(void *ctx, const hubbub_string *data, void **result)
  280. {
  281.         node_t *node = calloc(1, sizeof *node);
  282.  
  283.         UNUSED(ctx);
  284.  
  285.         node->type = COMMENT;
  286.         node->data.content = strndup((const char *) data->ptr, data->len);
  287.         node->refcnt = 1;
  288.         node->refcnt = 1;
  289.  
  290.         *result = node;
  291.  
  292.         return HUBBUB_OK;
  293. }
  294.  
  295. hubbub_error create_doctype(void *ctx, const hubbub_doctype *doctype,
  296.                 void **result)
  297. {
  298.         node_t *node = calloc(1, sizeof *node);
  299.  
  300.         UNUSED(ctx);
  301.  
  302.         node->type = DOCTYPE;
  303.         node->data.doctype.name = strndup(
  304.                         (const char *) doctype->name.ptr,
  305.                         doctype->name.len);
  306.  
  307.         if (!doctype->public_missing) {
  308.                 node->data.doctype.public_id = strndup(
  309.                                 (const char *) doctype->public_id.ptr,
  310.                                 doctype->public_id.len);
  311.         }
  312.  
  313.         if (!doctype->system_missing) {
  314.                 node->data.doctype.system_id = strndup(
  315.                                 (const char *) doctype->system_id.ptr,
  316.                                 doctype->system_id.len);
  317.         }
  318.         node->refcnt = 1;
  319.  
  320.         *result = node;
  321.  
  322.         return HUBBUB_OK;
  323. }
  324.  
  325. hubbub_error create_element(void *ctx, const hubbub_tag *tag, void **result)
  326. {
  327.         node_t *node = calloc(1, sizeof *node);
  328.         size_t i;
  329.  
  330.         UNUSED(ctx);
  331.  
  332.         assert(tag->ns < NUM_NAMESPACES);
  333.  
  334.         node->type = ELEMENT;
  335.         node->data.element.ns = tag->ns;
  336.         node->data.element.name = strndup(
  337.                         (const char *) tag->name.ptr,
  338.                         tag->name.len);
  339.         node->data.element.n_attrs = tag->n_attributes;
  340.  
  341.         node->data.element.attrs = calloc(node->data.element.n_attrs,
  342.                         sizeof *node->data.element.attrs);
  343.  
  344.         for (i = 0; i < tag->n_attributes; i++) {
  345.                 attr_t *attr = &node->data.element.attrs[i];
  346.  
  347.                 assert(tag->attributes[i].ns < NUM_NAMESPACES);
  348.  
  349.                 attr->ns = tag->attributes[i].ns;
  350.  
  351.                 attr->name = strndup(
  352.                                 (const char *) tag->attributes[i].name.ptr,
  353.                                 tag->attributes[i].name.len);
  354.  
  355.                 attr->value = strndup(
  356.                                 (const char *) tag->attributes[i].value.ptr,
  357.                                 tag->attributes[i].value.len);
  358.         }
  359.         node->refcnt = 1;
  360.  
  361.         *result = node;
  362.  
  363.         return HUBBUB_OK;
  364. }
  365.  
  366. hubbub_error create_text(void *ctx, const hubbub_string *data, void **result)
  367. {
  368.         node_t *node = calloc(1, sizeof *node);
  369.  
  370.         UNUSED(ctx);
  371.  
  372.         node->type = CHARACTER;
  373.         node->data.content = strndup((const char *) data->ptr, data->len);
  374.         node->refcnt = 1;
  375.         node->refcnt = 1;
  376.  
  377.         *result = node;
  378.  
  379.         return HUBBUB_OK;
  380. }
  381.  
  382. hubbub_error ref_node(void *ctx, void *node)
  383. {
  384.         node_t *n = node;
  385.  
  386.         UNUSED(ctx);
  387.  
  388.         if (node != (void *) 1)
  389.                 n->refcnt++;
  390.  
  391.         return HUBBUB_OK;
  392. }
  393.  
  394. hubbub_error unref_node(void *ctx, void *node)
  395. {
  396.         node_t *n = node;
  397.  
  398.         UNUSED(ctx);
  399.  
  400.         if (n != (void *) 1) {
  401.                 assert(n->refcnt > 0);
  402.  
  403.                 n->refcnt--;
  404.  
  405.                 printf("Unreferencing node %p (%d)\n", node, n->refcnt);
  406.  
  407.                 if (n->refcnt == 0 && n->parent == NULL) {
  408.                         delete_node(n);
  409.                 }
  410.         }
  411.  
  412.         return HUBBUB_OK;
  413. }
  414.  
  415. hubbub_error append_child(void *ctx, void *parent, void *child, void **result)
  416. {
  417.         node_t *tparent = parent;
  418.         node_t *tchild = child;
  419.  
  420.         node_t *insert = NULL;
  421.  
  422.         tchild->next = tchild->prev = NULL;
  423.  
  424. #ifndef NDEBUG
  425.         printf("appending (%p):\n", (void *) tchild);
  426.         node_print(NULL, tchild, 0);
  427.         printf("to:\n");
  428.         if (parent != (void *)1)
  429.                 node_print(NULL, tparent, 0);
  430. #endif
  431.  
  432.         *result = child;
  433.  
  434.         if (parent == (void *)1) {
  435.                 if (Document) {
  436.                         insert = Document;
  437.                 } else {
  438.                         Document = tchild;
  439.                 }
  440.         } else {
  441.                 if (tparent->child == NULL) {
  442.                         tparent->child = tchild;
  443.                 } else {
  444.                         insert = tparent->child;
  445.                 }
  446.         }
  447.  
  448.         if (insert) {
  449.                 while (insert->next != NULL) {
  450.                         insert = insert->next;
  451.                 }
  452.  
  453.                 if (tchild->type == CHARACTER && insert->type == CHARACTER) {
  454.                         insert->data.content = realloc(insert->data.content,
  455.                                         strlen(insert->data.content) +
  456.                                         strlen(tchild->data.content) + 1);
  457.                         strcat(insert->data.content, tchild->data.content);
  458.                         *result = insert;
  459.                 } else {
  460.                         insert->next = tchild;
  461.                         tchild->prev = insert;
  462.                 }
  463.         }
  464.  
  465.         if (*result == child)
  466.                 tchild->parent = tparent;
  467.  
  468.         ref_node(ctx, *result);
  469.  
  470.         return HUBBUB_OK;
  471. }
  472.  
  473. /* insert 'child' before 'ref_child', under 'parent' */
  474. hubbub_error insert_before(void *ctx, void *parent, void *child,
  475.                 void *ref_child, void **result)
  476. {
  477.         node_t *tparent = parent;
  478.         node_t *tchild = child;
  479.         node_t *tref = ref_child;
  480.  
  481. #ifndef NDEBUG
  482.         printf("inserting (%p):\n", (void *) tchild);
  483.         node_print(NULL, tchild, 0);
  484.         printf("before:\n");
  485.         node_print(NULL, tref, 0);
  486.         printf("under:\n");
  487.         if (parent != (void *)1)
  488.                 node_print(NULL, tparent, 0);
  489. #endif
  490.  
  491.         if (tchild->type == CHARACTER && tref->prev &&
  492.                         tref->prev->type == CHARACTER) {
  493.                 node_t *insert = tref->prev;
  494.  
  495.                 insert->data.content = realloc(insert->data.content,
  496.                                 strlen(insert->data.content) +
  497.                                 strlen(tchild->data.content) + 1);
  498.                 strcat(insert->data.content, tchild->data.content);
  499.  
  500.                 *result = insert;
  501.         } else {
  502.                 tchild->parent = parent;
  503.  
  504.                 tchild->prev = tref->prev;
  505.                 tchild->next = tref;
  506.                 tref->prev = tchild;
  507.  
  508.                 if (tchild->prev)
  509.                         tchild->prev->next = tchild;
  510.                 else
  511.                         tparent->child = tchild;
  512.  
  513.                 *result = child;
  514.         }
  515.  
  516.         ref_node(ctx, *result);
  517.  
  518.         return HUBBUB_OK;
  519. }
  520.  
  521. hubbub_error remove_child(void *ctx, void *parent, void *child, void **result)
  522. {
  523.         node_t *tparent = parent;
  524.         node_t *tchild = child;
  525.  
  526.         assert(tparent->child);
  527.         assert(tchild->parent == tparent);
  528.  
  529.         printf("Removing child %p\n", child);
  530.  
  531.         if (tchild->parent->child == tchild) {
  532.                 tchild->parent->child = tchild->next;
  533.         }
  534.  
  535.         if (tchild->prev)
  536.                 tchild->prev->next = tchild->next;
  537.  
  538.         if (tchild->next)
  539.                 tchild->next->prev = tchild->prev;
  540.  
  541.         /* now reset all the child's pointers */
  542.         tchild->next = tchild->prev = tchild->parent = NULL;
  543.  
  544.         *result = child;
  545.  
  546.         ref_node(ctx, *result);
  547.  
  548.         return HUBBUB_OK;
  549. }
  550.  
  551. hubbub_error clone_node(void *ctx, void *node, bool deep, void **result)
  552. {
  553.         node_t *old_node = node;
  554.         node_t *new_node = calloc(1, sizeof *new_node);
  555.         node_t *last;
  556.         node_t *child;
  557.         size_t i;
  558.  
  559.         new_node->type = old_node->type;
  560.  
  561.         switch (old_node->type) {
  562.         case DOCTYPE:
  563.                 new_node->data.doctype.name =
  564.                                 strdup(old_node->data.doctype.name);
  565.                 if (old_node->data.doctype.public_id)
  566.                         new_node->data.doctype.public_id =
  567.                                 strdup(old_node->data.doctype.public_id);
  568.                 if (old_node->data.doctype.system_id)
  569.                         new_node->data.doctype.system_id =
  570.                                 strdup(old_node->data.doctype.system_id);
  571.                 break;
  572.         case COMMENT:
  573.         case CHARACTER:
  574.                 new_node->data.content = strdup(old_node->data.content);
  575.                 break;
  576.         case ELEMENT:
  577.                 new_node->data.element.ns = old_node->data.element.ns;
  578.                 new_node->data.element.name =
  579.                                 strdup(old_node->data.element.name);
  580.                 new_node->data.element.attrs =
  581.                                 calloc(old_node->data.element.n_attrs,
  582.                                         sizeof *new_node->data.element.attrs);
  583.                 for (i = 0; i < old_node->data.element.n_attrs; i++) {
  584.                         attr_t *attr = &new_node->data.element.attrs[i];
  585.  
  586.                         attr->ns = old_node->data.element.attrs[i].ns;
  587.                         attr->name =
  588.                                 strdup(old_node->data.element.attrs[i].name);
  589.                         attr->value =
  590.                                 strdup(old_node->data.element.attrs[i].value);
  591.                 }
  592.                 new_node->data.element.n_attrs = old_node->data.element.n_attrs;
  593.                 break;
  594.         }
  595.  
  596.         *result = new_node;
  597.  
  598.         new_node->child = new_node->parent =
  599.                         new_node->next = new_node->prev =
  600.                         NULL;
  601.  
  602.         new_node->refcnt = 1;
  603.  
  604.         if (deep == false)
  605.                 return 0;
  606.  
  607.         last = NULL;
  608.  
  609.         for (child = old_node->child; child != NULL;
  610.                         child = child->next) {
  611.                 node_t *n;
  612.  
  613.                 clone_node(ctx, child, true, (void **) (void *) &n);
  614.  
  615.                 n->refcnt = 0;
  616.  
  617.                 if (last == NULL) {
  618.                         new_node->child = n;
  619.                 } else {
  620.                         last->next = n;
  621.                         n->prev = last;
  622.                 }
  623.  
  624.                 n->parent = new_node;
  625.                 last = n;
  626.         }
  627.  
  628.         return HUBBUB_OK;
  629. }
  630.  
  631. /* Take all of the child nodes of "node" and append them to "new_parent" */
  632. hubbub_error reparent_children(void *ctx, void *node, void *new_parent)
  633. {
  634.         node_t *parent = new_parent;
  635.         node_t *old_parent = node;
  636.  
  637.         node_t *insert;
  638.         node_t *kids;
  639.  
  640.         UNUSED(ctx);
  641.  
  642.         kids = old_parent->child;
  643.         if (!kids) return 0;
  644.  
  645.         old_parent->child = NULL;
  646.  
  647.         insert = parent->child;
  648.         if (!insert) {
  649.                 parent->child = kids;
  650.         } else {
  651.                 while (insert->next != NULL) {
  652.                         insert = insert->next;
  653.                 }
  654.  
  655.                 insert->next = kids;
  656.                 kids->prev = insert;
  657.         }
  658.  
  659.         while (kids) {
  660.                 kids->parent = parent;
  661.                 kids = kids->next;
  662.         }
  663.  
  664.         return HUBBUB_OK;
  665. }
  666.  
  667. hubbub_error get_parent(void *ctx, void *node, bool element_only, void **result)
  668. {
  669.         UNUSED(element_only);
  670.  
  671.         *result = ((node_t *)node)->parent;
  672.  
  673.         if (*result != NULL)
  674.                 ref_node(ctx, *result);
  675.  
  676.         return HUBBUB_OK;
  677. }
  678.  
  679. hubbub_error has_children(void *ctx, void *node, bool *result)
  680. {
  681.         UNUSED(ctx);
  682.  
  683.         *result = ((node_t *)node)->child ? true : false;
  684.  
  685.         return HUBBUB_OK;
  686. }
  687.  
  688. hubbub_error form_associate(void *ctx, void *form, void *node)
  689. {
  690.         UNUSED(ctx);
  691.         UNUSED(form);
  692.         UNUSED(node);
  693.  
  694.         return HUBBUB_OK;
  695. }
  696.  
  697. hubbub_error add_attributes(void *ctx, void *vnode,
  698.                 const hubbub_attribute *attributes, uint32_t n_attributes)
  699. {
  700.         node_t *node = vnode;
  701.         size_t old_elems = node->data.element.n_attrs;
  702.         size_t i;
  703.  
  704.         UNUSED(ctx);
  705.  
  706.         node->data.element.n_attrs += n_attributes;
  707.  
  708.         node->data.element.attrs = realloc(node->data.element.attrs,
  709.                         node->data.element.n_attrs *
  710.                                 sizeof *node->data.element.attrs);
  711.  
  712.         for (i = 0; i < n_attributes; i++) {
  713.                 attr_t *attr = &node->data.element.attrs[old_elems + i];
  714.  
  715.                 assert(attributes[i].ns < NUM_NAMESPACES);
  716.  
  717.                 attr->ns = attributes[i].ns;
  718.  
  719.                 attr->name = strndup(
  720.                                 (const char *) attributes[i].name.ptr,
  721.                                 attributes[i].name.len);
  722.  
  723.                 attr->value = strndup(
  724.                                 (const char *) attributes[i].value.ptr,
  725.                                 attributes[i].value.len);
  726.         }
  727.  
  728.  
  729.         return HUBBUB_OK;
  730. }
  731.  
  732. hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode)
  733. {
  734.         UNUSED(ctx);
  735.         UNUSED(mode);
  736.  
  737.         return HUBBUB_OK;
  738. }
  739.  
  740. hubbub_error complete_script(void *ctx, void *script)
  741. {
  742.         UNUSED(ctx);
  743.         UNUSED(script);
  744.  
  745.         return HUBBUB_OK;
  746. }
  747.  
  748.  
  749. /*** Serialising bits ***/
  750.  
  751. static int compare_attrs(const void *a, const void *b) {
  752.         const attr_t *first = a;
  753.         const attr_t *second = b;
  754.  
  755.         return strcmp(first->name, second->name);
  756. }
  757.  
  758.  
  759.  
  760.  
  761. static void indent(buf_t *buf, unsigned depth)
  762. {
  763.         unsigned int i;
  764.  
  765.         buf_add(buf, "| ");
  766.  
  767.         for (i = 0; i < depth; i++) {
  768.                 buf_add(buf, "  ");
  769.         }
  770. }
  771.  
  772. static void print_ns(buf_t *buf, hubbub_ns ns)
  773. {
  774.         if (ns_names[ns] != NULL) {
  775.                 buf_add(buf, ns_names[ns]);
  776.                 buf_add(buf, " ");
  777.         }
  778. }
  779.  
  780. static void node_print(buf_t *buf, node_t *node, unsigned depth)
  781. {
  782.         size_t i;
  783.  
  784.         if (!node) return;
  785.  
  786.         indent(buf, depth);
  787.  
  788.         switch (node->type)
  789.         {
  790.         case DOCTYPE:
  791.                 buf_add(buf, "<!DOCTYPE ");
  792.                 buf_add(buf, node->data.doctype.name);
  793.  
  794.                 if (node->data.doctype.public_id ||
  795.                                 node->data.doctype.system_id) {
  796.                         if (node->data.doctype.public_id) {
  797.                                 buf_add(buf, " \"");
  798.                                 buf_add(buf, node->data.doctype.public_id);
  799.                                 buf_add(buf, "\" ");
  800.                         } else {
  801.                                 buf_add(buf, "\"\" ");
  802.                         }
  803.                        
  804.                         if (node->data.doctype.system_id) {
  805.                                 buf_add(buf, " \"");
  806.                                 buf_add(buf, node->data.doctype.system_id);
  807.                                 buf_add(buf, "\"");
  808.                         } else {
  809.                                 buf_add(buf, "\"\"");
  810.                         }
  811.                 }
  812.  
  813.                 buf_add(buf, ">\n");
  814.                 break;
  815.         case ELEMENT:
  816.                 buf_add(buf, "<");
  817.                 print_ns(buf, node->data.element.ns);
  818.                 buf_add(buf, node->data.element.name);
  819.                 buf_add(buf, ">\n");
  820.  
  821.                 qsort(node->data.element.attrs, node->data.element.n_attrs,
  822.                                 sizeof *node->data.element.attrs,
  823.                                 compare_attrs);
  824.  
  825.                 for (i = 0; i < node->data.element.n_attrs; i++) {
  826.                         indent(buf, depth + 1);
  827.                         print_ns(buf, node->data.element.attrs[i].ns);
  828.                         buf_add(buf, node->data.element.attrs[i].name);
  829.                         buf_add(buf, "=");
  830.                         buf_add(buf, "\"");
  831.                         buf_add(buf, node->data.element.attrs[i].value);
  832.                         buf_add(buf, "\"\n");
  833.                 }
  834.  
  835.                 break;
  836.         case CHARACTER:
  837.                 buf_add(buf, "\"");
  838.                 buf_add(buf, node->data.content);
  839.                 buf_add(buf, "\"\n");
  840.                 break;
  841.         case COMMENT:
  842.                 buf_add(buf, "<!-- ");
  843.                 buf_add(buf, node->data.content);
  844.                 buf_add(buf, " -->\n");
  845.                 break;
  846.         default:
  847.                 printf("Unexpected node type %d\n", node->type);
  848.                 assert(0);
  849.         }
  850.  
  851.         if (node->child) {
  852.                 node_print(buf, node->child, depth + 1);
  853.         }
  854.  
  855.         if (node->next) {
  856.                 node_print(buf, node->next, depth);
  857.         }
  858. }
  859.  
  860. static void delete_node(node_t *node)
  861. {
  862.         size_t i;
  863.         node_t *c, *d;
  864.  
  865.         if (node == NULL)
  866.                 return;
  867.  
  868.         if (node->refcnt != 0) {
  869.                 printf("Node %p has non-zero refcount %d\n",
  870.                                 (void *) node, node->refcnt);
  871.                 assert(0);
  872.         }
  873.  
  874.         switch (node->type) {
  875.         case DOCTYPE:
  876.                 free(node->data.doctype.name);
  877.                 free(node->data.doctype.public_id);
  878.                 free(node->data.doctype.system_id);
  879.                 break;
  880.         case COMMENT:
  881.         case CHARACTER:
  882.                 free(node->data.content);
  883.                 break;
  884.         case ELEMENT:
  885.                 free(node->data.element.name);
  886.                 for (i = 0; i < node->data.element.n_attrs; i++)
  887.                         delete_attr(&node->data.element.attrs[i]);
  888.                 free(node->data.element.attrs);
  889.                 break;
  890.         }
  891.  
  892.         for (c = node->child; c != NULL; c = d) {
  893.                 d = c->next;
  894.  
  895.                 delete_node(c);
  896.         }
  897.  
  898.         memset(node, 0xdf, sizeof(node_t));
  899.  
  900.         free(node);
  901. }
  902.  
  903. static void delete_attr(attr_t *attr)
  904. {
  905.         if (attr == NULL)
  906.                 return;
  907.  
  908.         free(attr->name);
  909.         free(attr->value);
  910.  
  911.         memset(attr, 0xdf, sizeof(attr_t));
  912. }
  913.  
  914.