KatanaParserString* katana_build_relation_selector_string(KatanaParser* parser, const char* relation, KatanaParserString* string, KatanaParserString* next, KatanaSelector* tagHistory) { if ( NULL != relation ) { katana_string_prepend_characters(parser, relation, string); } if ( NULL != next ) { katana_string_append_string(parser, next, string); } KatanaParserString * result = katana_selector_to_string(parser, tagHistory, (KatanaParserString*)string); katana_parser_deallocate(parser, (void*) string->data); katana_parser_deallocate(parser, (void*) string); return result; }
void katana_string_prepend_characters(struct KatanaInternalParser* parser, const char* str, KatanaParserString* output) { size_t len = strlen(str); size_t new_length = output->length + len; char* new_data = katana_parser_allocate(parser, new_length); memcpy(new_data, str, len); memcpy(new_data+len, output->data, output->length); katana_parser_deallocate(parser, output->data); output->data = new_data; output->length = new_length; output->capacity = new_length; }
static void maybe_resize_string(struct KatanaInternalParser* parser, size_t additional_chars, KatanaParserString* str) { size_t new_length = str->length + additional_chars; size_t new_capacity = str->capacity; while (new_capacity < new_length) { new_capacity *= 2; } if (new_capacity != str->capacity) { char* new_data = katana_parser_allocate(parser, new_capacity); memset(new_data, 0, str->length); memcpy(new_data, str->data, str->length); katana_parser_deallocate(parser, str->data); str->data = new_data; str->capacity = new_capacity; } }
static void enlarge_array_if_full(struct KatanaInternalParser* parser, KatanaArray* array) { if (array->length >= array->capacity) { if (array->capacity) { size_t old_num_bytes = sizeof(void*) * array->capacity; array->capacity *= 2; size_t num_bytes = sizeof(void*) * array->capacity; void** temp = katana_parser_allocate(parser, num_bytes); memcpy(temp, array->data, old_num_bytes); katana_parser_deallocate(parser, array->data); array->data = temp; } else { // 0-capacity array; no previous array to deallocate. array->capacity = 2; array->data = katana_parser_allocate(parser, sizeof(void*) * array->capacity); } } }
KatanaParserString* katana_selector_to_string(KatanaParser* parser, KatanaSelector* selector, KatanaParserString* next) { KatanaParserString* string = katana_parser_allocate(parser, sizeof(KatanaParserString)); katana_string_init(parser, string); bool tag_is_implicit = true; if (selector->match == KatanaSelectorMatchTag && tag_is_implicit) { if ( NULL == selector->tag->prefix ) katana_string_append_characters(parser, selector->tag->local, string); else { katana_string_append_characters(parser, selector->tag->prefix, string); katana_string_append_characters(parser, "|", string); katana_string_append_characters(parser, selector->tag->local, string); } } const KatanaSelector* cs = selector; while (true) { if (cs->match == KatanaSelectorMatchId) { katana_string_append_characters(parser, "#", string); katana_string_append_characters(parser, cs->data->value, string); } else if (cs->match == KatanaSelectorMatchClass) { katana_string_append_characters(parser, ".", string); katana_string_append_characters(parser, cs->data->value, string); } else if (cs->match == KatanaSelectorMatchPseudoClass || cs->match == KatanaSelectorMatchPagePseudoClass) { katana_string_append_characters(parser, ":", string); katana_string_append_characters(parser, cs->data->value, string); switch (cs->pseudo) { case KatanaPseudoAny: case KatanaPseudoNot: case KatanaPseudoHost: case KatanaPseudoHostContext: { if ( cs->data->selectors ) { KatanaArray* sels = cs->data->selectors; for (size_t i=0; i<sels->length; i++) { KatanaParserString* str = katana_selector_to_string(parser, sels->data[i], NULL); katana_string_append_string(parser, str, string); katana_parser_deallocate(parser, (void*) str->data); katana_parser_deallocate(parser, (void*) str); if ( i != sels->length -1 ) { katana_string_append_characters(parser, ", ", string); } } katana_string_append_characters(parser, ")", string); } } break; case KatanaPseudoLang: case KatanaPseudoNthChild: case KatanaPseudoNthLastChild: case KatanaPseudoNthOfType: case KatanaPseudoNthLastOfType: { katana_string_append_characters(parser, cs->data->argument, string); katana_string_append_characters(parser, ")", string); } break; default: break; } } else if (cs->match == KatanaSelectorMatchPseudoElement) { katana_string_append_characters(parser, "::", string); katana_string_append_characters(parser, cs->data->value, string); } else if (katana_selector_is_attribute(cs)) { katana_string_append_characters(parser, "[", string); if (NULL != cs->data->attribute->prefix) { katana_string_append_characters(parser, cs->data->attribute->prefix, string); katana_string_append_characters(parser, "|", string); } katana_string_append_characters(parser, cs->data->attribute->local, string); switch (cs->match) { case KatanaSelectorMatchAttributeExact: katana_string_append_characters(parser, "=", string); break; case KatanaSelectorMatchAttributeSet: katana_string_append_characters(parser, "]", string); break; case KatanaSelectorMatchAttributeList: katana_string_append_characters(parser, "~=", string); break; case KatanaSelectorMatchAttributeHyphen: katana_string_append_characters(parser, "|=", string); break; case KatanaSelectorMatchAttributeBegin: katana_string_append_characters(parser, "^=", string); break; case KatanaSelectorMatchAttributeEnd: katana_string_append_characters(parser, "$=", string); break; case KatanaSelectorMatchAttributeContain: katana_string_append_characters(parser, "*=", string); break; default: break; } if (cs->match != KatanaSelectorMatchAttributeSet) { katana_string_append_characters(parser, "\"", string); katana_string_append_characters(parser, cs->data->value, string); katana_string_append_characters(parser, "\"", string); if (cs->data->bits.attributeMatchType == KatanaAttributeMatchTypeCaseInsensitive) katana_string_append_characters(parser, " i", string); katana_string_append_characters(parser, "]", string); } } if (cs->relation != KatanaSelectorRelationSubSelector || !cs->tagHistory) break; cs = cs->tagHistory; } KatanaSelector* tagHistory = cs->tagHistory; if ( NULL != tagHistory ) { switch (cs->relation) { case KatanaSelectorRelationDescendant: { return katana_build_relation_selector_string(parser, " ", string, next, tagHistory); } case KatanaSelectorRelationChild: { return katana_build_relation_selector_string(parser, " > ", string, next, tagHistory); } case KatanaSelectorRelationShadowDeep: { return katana_build_relation_selector_string(parser, " /deep/ ", string, next, tagHistory); } case KatanaSelectorRelationDirectAdjacent: { return katana_build_relation_selector_string(parser, " + ", string, next, tagHistory); } case KatanaSelectorRelationIndirectAdjacent: { return katana_build_relation_selector_string(parser, " ~ ", string, next, tagHistory); } case KatanaSelectorRelationSubSelector: { return NULL; } case KatanaSelectorRelationShadowPseudo: { return katana_build_relation_selector_string(parser, NULL, string, next, tagHistory); } } } if ( NULL != next ) { katana_string_append_string(parser, (KatanaParserString*)next, string); } return (KatanaParserString*)string; }
void katana_array_destroy(struct KatanaInternalParser* parser, KatanaArray* array) { if (array->capacity > 0) { katana_parser_deallocate(parser, array->data); } }