/** * Handle tokeniser emitting a token * * \param token The emitted token * \param pw Pointer to treebuilder instance */ hubbub_error hubbub_treebuilder_token_handler(const hubbub_token *token, void *pw) { hubbub_treebuilder *treebuilder = (hubbub_treebuilder *) pw; hubbub_error err = HUBBUB_REPROCESS; /* Do nothing if we have no document node or there's no tree handler */ if (treebuilder->context.document == NULL || treebuilder->tree_handler == NULL) return HUBBUB_OK; assert((signed) treebuilder->context.current_node >= 0); /* A slightly nasty debugging hook, but very useful */ #ifdef NDEBUG # define mode(x) \ case x: #else # define mode(x) \ case x: \ printf( #x "\n"); #endif while (err == HUBBUB_REPROCESS) { switch (treebuilder->context.mode) { mode(INITIAL) err = handle_initial(treebuilder, token); break; mode(BEFORE_HTML) err = handle_before_html(treebuilder, token); break; mode(BEFORE_HEAD) err = handle_before_head(treebuilder, token); break; mode(IN_HEAD) err = handle_in_head(treebuilder, token); break; mode(IN_HEAD_NOSCRIPT) err = handle_in_head_noscript(treebuilder, token); break; mode(AFTER_HEAD) err = handle_after_head(treebuilder, token); break; mode(IN_BODY) err = handle_in_body(treebuilder, token); break; mode(IN_TABLE) err = handle_in_table(treebuilder, token); break; mode(IN_CAPTION) err = handle_in_caption(treebuilder, token); break; mode(IN_COLUMN_GROUP) err = handle_in_column_group(treebuilder, token); break; mode(IN_TABLE_BODY) err = handle_in_table_body(treebuilder, token); break; mode(IN_ROW) err = handle_in_row(treebuilder, token); break; mode(IN_CELL) err = handle_in_cell(treebuilder, token); break; mode(IN_SELECT) err = handle_in_select(treebuilder, token); break; mode(IN_SELECT_IN_TABLE) err = handle_in_select_in_table(treebuilder, token); break; mode(IN_FOREIGN_CONTENT) err = handle_in_foreign_content(treebuilder, token); break; mode(AFTER_BODY) err = handle_after_body(treebuilder, token); break; mode(IN_FRAMESET) err = handle_in_frameset(treebuilder, token); break; mode(AFTER_FRAMESET) err = handle_after_frameset(treebuilder, token); break; mode(AFTER_AFTER_BODY) err = handle_after_after_body(treebuilder, token); break; mode(AFTER_AFTER_FRAMESET) err = handle_after_after_frameset(treebuilder, token); break; mode(GENERIC_RCDATA) err = handle_generic_rcdata(treebuilder, token); break; } } return err; }
/** * Handle tokens in "in row" insertion mode * * \param treebuilder The treebuilder instance * \param token The token to process * \return True to reprocess the token, false otherwise */ hubbub_error handle_in_row(hubbub_treebuilder *treebuilder, const hubbub_token *token) { hubbub_error err = HUBBUB_OK; switch (token->type) { case HUBBUB_TOKEN_START_TAG: { element_type type = element_type_from_name(treebuilder, &token->data.tag.name); if (type == TH || type == TD) { table_clear_stack(treebuilder); err = insert_element(treebuilder, &token->data.tag, true); if (err != HUBBUB_OK) return err; treebuilder->context.mode = IN_CELL; /* ref node for formatting list */ treebuilder->tree_handler->ref_node( treebuilder->tree_handler->ctx, treebuilder->context.element_stack[ treebuilder->context.current_node].node); err = formatting_list_append(treebuilder, token->data.tag.ns, type, treebuilder->context.element_stack[ treebuilder->context.current_node].node, treebuilder->context.current_node); if (err != HUBBUB_OK) { hubbub_ns ns; element_type type; void *node; /* Revert changes */ remove_node_from_dom(treebuilder, treebuilder->context.element_stack[ treebuilder->context.current_node].node); element_stack_pop(treebuilder, &ns, &type, &node); return err; } } else if (type == CAPTION || type == COL || type == COLGROUP || type == TBODY || type == TFOOT || type == THEAD || type == TR) { err = act_as_if_end_tag_tr(treebuilder); } else { err = handle_in_table(treebuilder, token); } } break; case HUBBUB_TOKEN_END_TAG: { element_type type = element_type_from_name(treebuilder, &token->data.tag.name); if (type == TR) { /* We're done with this token, but act_as_if_end_tag_tr * will return HUBBUB_REPROCESS. Therefore, ignore the * return value. */ (void) act_as_if_end_tag_tr(treebuilder); } else if (type == TABLE) { err = act_as_if_end_tag_tr(treebuilder); } else if (type == BODY || type == CAPTION || type == COL || type == COLGROUP || type == HTML || type == TD || type == TH) { /** \todo parse error */ /* Ignore the token */ } else { err = handle_in_table(treebuilder, token); } } break; case HUBBUB_TOKEN_CHARACTER: case HUBBUB_TOKEN_COMMENT: case HUBBUB_TOKEN_DOCTYPE: case HUBBUB_TOKEN_EOF: err = handle_in_table(treebuilder, token); break; } return err; }