/* * Copyright (C) 2015 William Yu * * This library is free software; you can redistribute it and/or modify * it under the terms of either: * * The LGPL as published by the Free Software Foundation, version * 2.1, available at: https://www.gnu.org/licenses/lgpl-2.1.html * * Or: * * The Mozilla Public License Version 2.0. You may obtain a copy of * the License at https://www.mozilla.org/MPL/ */ #include "xml-parser.h" Structure *structure_new() { Structure *structure; structure = g_new0(Structure, 1); structure->nameSpace = NULL; structure->name = NULL; structure->native = NULL; structure->includes = NULL; structure->methods = NULL; structure->isBare = FALSE; structure->isPossibleGlobal = FALSE; structure->new_full_extraCode = NULL; structure->enumerations = NULL; structure->destroyFunc = NULL; structure->cloneFunc = NULL; structure->defaultNative = NULL; structure->dependencies = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); structure->declarations = NULL; return structure; } void structure_free(Structure * structure) { GList *list; Enumeration *enumeration; if (structure == NULL) return; for (list = g_list_first(structure->methods); list != NULL; list = list->next) { method_free((Method *) list->data); } for (list = g_list_first(structure->includes); list != NULL; list = list->next) { g_free(list->data); } for (list = g_list_first(structure->enumerations); list != NULL; list = g_list_next(list)) { enumeration = (Enumeration *) list->data; enumeration_free(enumeration); enumeration = NULL; } for (list = g_list_first(structure->declarations); list != NULL; list = g_list_next(list)) { declaration_free((Declaration *) list->data); } g_list_free(structure->methods); g_list_free(structure->includes); g_list_free(structure->enumerations); g_list_free(structure->declarations); g_free(structure->nameSpace); g_free(structure->name); g_free(structure->native); g_free(structure->destroyFunc); g_free(structure->cloneFunc); g_free(structure->defaultNative); g_free(structure->new_full_extraCode); g_hash_table_destroy(structure->dependencies); g_free(structure); } Declaration *declaration_new() { Declaration *declaration = g_new0(Declaration, 1); declaration->position = NULL; declaration->content = NULL; return declaration; } void declaration_free(Declaration * declaration) { if (declaration == NULL) return; if (declaration->position != NULL) g_free(declaration->position); if (declaration->content != NULL) g_free(declaration->content); g_free(declaration); } Method *method_new() { Method *method; method = g_new0(Method, 1); method->name = NULL; method->corresponds = NULL; method->kind = NULL; method->since = NULL; method->parameters = NULL; method->ret = NULL; method->comment = NULL; method->custom = NULL; method->annotations = NULL; return method; } void method_free(Method * method) { GList *list; if (method == NULL) return; for (list = method->parameters; list != NULL; list = list->next) { parameter_free((Parameter *) list->data); } for (list = method->annotations; list != NULL; list = list->next) { g_free(list->data); } g_list_free(method->parameters); g_list_free(method->annotations); g_free(method->name); g_free(method->corresponds); g_free(method->kind); g_free(method->since); g_free(method->comment); g_free(method->custom); ret_free(method->ret); g_free(method); } Parameter *parameter_new() { Parameter *parameter; parameter = g_new0(Parameter, 1); parameter->comment = NULL; parameter->name = NULL; parameter->type = NULL; parameter->annotations = NULL; parameter->autofill = NULL; parameter->translator = NULL; parameter->translatorArgus = NULL; parameter->native_op = NULL; parameter->owner_op = NULL; return parameter; } void parameter_free(Parameter * para) { GList *list; if (para == NULL) return; for (list = para->annotations; list != NULL; list = list->next) { g_free(list->data); } for (list = g_list_first(para->translatorArgus); list != NULL; list = g_list_next(list)) { g_free(list->data); } g_list_free(para->annotations); g_list_free(para->translatorArgus); g_free(para->type); g_free(para->comment); g_free(para->name); g_free(para->autofill); g_free(para->translator); g_free(para->native_op); g_free(para->owner_op); g_free(para); } Ret *ret_new() { Ret *ret; ret = g_new0(Ret, 1); ret->comment = NULL; ret->type = NULL; ret->annotations = NULL; ret->translator = NULL; ret->translatorArgus = NULL; ret->errorReturnValue = NULL; return ret; } void ret_free(Ret * ret) { GList *list; if (ret == NULL) return; for (list = g_list_first(ret->annotations); list != NULL; list = g_list_next(list)) { g_free(list->data); } for (list = g_list_first(ret->translatorArgus); list != NULL; list = g_list_next(list)) { g_free(list->data); } g_list_free(ret->annotations); g_list_free(ret->translatorArgus); g_free(ret->type); g_free(ret->comment); g_free(ret->translator); g_free(ret->errorReturnValue); g_free(ret); } Enumeration *enumeration_new() { Enumeration *enumeration = g_new0(Enumeration, 1); enumeration->elements = NULL; enumeration->name = NULL; enumeration->nativeName = NULL; enumeration->defaultNative = NULL; enumeration->comment = NULL; return enumeration; } void enumeration_free(Enumeration * enumeration) { GList *iter; if (enumeration == NULL) return; for (iter = g_list_first(enumeration->elements); iter != NULL; iter = g_list_next(iter)) { g_free(iter->data); } g_list_free(enumeration->elements); g_free(enumeration->name); g_free(enumeration->nativeName); g_free(enumeration->defaultNative); g_free(enumeration->comment); g_free(enumeration); } static gchar *dup_attribute_value(xmlDocPtr doc, const xmlNode * list, int inLine) { xmlChar *xml_value; gchar *glib_value; xml_value = xmlNodeListGetString(doc, list, inLine); if (!xml_value) return NULL; glib_value = g_strdup((const gchar *) xml_value); xmlFree(xml_value); return glib_value; } static gchar *dup_node_content(xmlNodePtr node) { xmlChar *xml_value; gchar *glib_value; xml_value = xmlNodeGetContent(node); if (!xml_value) return NULL; glib_value = g_strdup((const gchar *) xml_value); xmlFree(xml_value); return glib_value; } GList *get_list_from_string(const gchar * str) { gchar **ret; guint iter; guint len; GList *list = NULL; ret = g_strsplit(str, ",", 0); len = g_strv_length(ret); for (iter = 0; iter < len; iter++) { (void)g_strstrip(ret[iter]); list = g_list_append(list, ret[iter]); } g_free(ret); return list; } gboolean parse_parameters(xmlNode * node, Method * method) { xmlAttr *attr; Parameter *para; if (xmlStrcmp(node->name, (xmlChar *) "parameter") != 0) return FALSE; for (; xmlStrcmp(node->name, (xmlChar *) "parameter") == 0; node = node->next) { para = parameter_new(); for (attr = node->properties; attr != NULL; attr = attr->next) { if (xmlStrcmp(attr->name, (xmlChar *) "type") == 0) { para->type = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "name") == 0) { para->name = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "comment") == 0) { para->comment = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "annotation") == 0) { xmlChar *anno; anno = xmlNodeListGetString(attr->doc, attr->children, 1); para->annotations = get_list_from_string((const gchar *) anno); xmlFree(anno); } else if (xmlStrcmp(attr->name, (xmlChar *) "translator_argus") == 0) { xmlChar *argus; argus = xmlNodeListGetString(attr->doc, attr->children, 1); para->translatorArgus = get_list_from_string((const gchar *) argus); xmlFree(argus); } else if (xmlStrcmp(attr->name, (xmlChar *) "translator") == 0) { para->translator = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "autofill") == 0) { para->autofill = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "native_op") == 0) { para->native_op = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "owner_op") == 0) { para->owner_op = dup_attribute_value(attr->doc, attr->children, 1); } else { fprintf(stderr, "The tag name of %s in parameter cannot be finished\n", (char *)attr->name); } } method->parameters = g_list_append(method->parameters, para); } return TRUE; } gboolean parse_return(xmlNode * node, Method * method) { xmlAttr *attr; if (xmlStrcmp(node->name, (xmlChar *) "returns") != 0) { return FALSE; } method->ret = ret_new(); for (attr = node->properties; attr != NULL; attr = attr->next) { if (xmlStrcmp(attr->name, (xmlChar *) "type") == 0) { method->ret->type = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "comment") == 0) { method->ret->comment = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "annotation") == 0) { xmlChar *anno; anno = xmlNodeListGetString(attr->doc, attr->children, 1); method->ret->annotations = get_list_from_string((const gchar *) anno); xmlFree(anno); } else if (xmlStrcmp(attr->name, (xmlChar *) "translator") == 0) { method->ret->translator = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "translator_argus") == 0) { xmlChar *argus; argus = xmlNodeListGetString(attr->doc, attr->children, 1); method->ret->translatorArgus = get_list_from_string((const gchar *) argus); xmlFree(argus); } else if (xmlStrcmp(attr->name, (xmlChar *) "error_return_value") == 0) { method->ret->errorReturnValue = dup_attribute_value(attr->doc, attr->children, 1); } else { fprintf(stderr, "The tag name of '%s' in 'returns' cannot be finished\n", (char *)attr->name); } } return TRUE; } gboolean parse_comment(xmlNode * node, Method * method) { if (xmlStrcmp(node->name, (xmlChar *) "comment") != 0) { return FALSE; } g_free(method->comment); method->comment = dup_node_content(node); return TRUE; } gboolean parse_custom(xmlNode * node, Method * method) { if (xmlStrcmp(node->name, (xmlChar *) "custom") != 0) { return FALSE; } g_free(method->custom); method->custom = dup_node_content (node); return TRUE; } gboolean parse_method(xmlNode * node, Method * method) { xmlNode *child; xmlAttr *attr; if (xmlStrcmp(node->name, (xmlChar *) "method") != 0) { return FALSE; } for (attr = node->properties; attr != NULL; attr = attr->next) { if (xmlStrcmp(attr->name, (xmlChar *) "name") == 0) { method->name = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "corresponds") == 0) { method->corresponds = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "kind") == 0) { method->kind = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "since") == 0) { method->since = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "annotation") == 0) { xmlChar *anno; anno = xmlNodeListGetString(attr->doc, attr->children, 1); method->annotations = get_list_from_string((const gchar *) anno); xmlFree(anno); } else { fprintf(stderr, "The attribute '%s' in method '%s' cannot be parsed", (char *)attr->name, method->name); return TRUE; } } for (child = xmlFirstElementChild(node); child != NULL; child = xmlNextElementSibling(child)) { if (parse_parameters(child, method) != TRUE && parse_return(child, method) != TRUE && parse_comment(child, method) != TRUE && parse_custom(child, method) != TRUE) { fprintf(stderr, "The node named '%s' in method '%s' cannot be parsed\n", (char *)child->name, method->name); return FALSE; } } return TRUE; } gboolean parse_declaration(xmlNode * node, Declaration * declaration) { xmlAttr *attr; g_return_val_if_fail(node != NULL && declaration != NULL, FALSE); if (xmlStrcmp(node->name, (xmlChar *) "declaration") != 0) { return FALSE; } for (attr = node->properties; attr != NULL; attr = attr->next) { if (xmlStrcmp(attr->name, (xmlChar *) "position") == 0) { declaration->position = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "content") == 0) { declaration->content = dup_attribute_value(attr->doc, attr->children, 1); } else { fprintf(stderr, "The node named '%s' in declaration cannot be parsed\n", (char *)attr->name); } } if (!declaration->content) { declaration->content = dup_node_content(node); } return TRUE; } gboolean parse_enumeration(xmlNode * node, Enumeration * enumeration) { xmlAttr *attr; xmlNode *child; gchar *elementName; g_return_val_if_fail(node != NULL && enumeration != NULL, FALSE); if (xmlStrcmp(node->name, (xmlChar *) "enum") != 0) { return FALSE; } for (attr = node->properties; attr != NULL; attr = attr->next) { if (xmlStrcmp(attr->name, (xmlChar *) "name") == 0) { enumeration->name = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "native_name") == 0) { enumeration->nativeName = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "default_native") == 0) { enumeration->defaultNative = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "comment") == 0) { enumeration->comment = dup_attribute_value(attr->doc, attr->children, 1); } else { fprintf(stderr, "The node named '%s' in enum '%s' cannot be parsed\n", (char *)attr->name, enumeration->name); } } for (child = xmlFirstElementChild(node); child != NULL; child = xmlNextElementSibling(child)) { if (xmlStrcmp(child->name, (xmlChar *) "element") != 0) { fprintf(stderr, "The child node named '%s' is not an element in enumeration '%s'\n", (char *)child->name, enumeration->name); continue; } elementName = dup_attribute_value(child->properties->doc, child->properties->children, 1); enumeration->elements = g_list_append(enumeration->elements, elementName); elementName = NULL; } return TRUE; } gboolean parse_structure(xmlNode * node, Structure * structure) { xmlAttr *attr; xmlNode *child; Method *method; Enumeration *enumeration; Declaration *declaration; if (xmlStrcmp(node->name, (xmlChar *) "structure") != 0) { return FALSE; } for (attr = node->properties; attr != NULL; attr = attr->next) { if (xmlStrcmp(attr->name, (xmlChar *) "namespace") == 0) { structure->nameSpace = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "name") == 0) { structure->name = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "native") == 0) { structure->native = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "includes") == 0) { xmlChar *includes; includes = xmlNodeListGetString(attr->doc, attr->children, 1); structure->includes = get_list_from_string((const gchar *) includes); xmlFree(includes); } else if (xmlStrcmp(attr->name, (xmlChar *) "is_possible_global") == 0) { xmlChar *strIsPossibleGlobal; strIsPossibleGlobal = xmlNodeListGetString(attr->doc, attr->children, 1); if (g_strcmp0((const gchar *) strIsPossibleGlobal, "true") == 0) { structure->isPossibleGlobal = TRUE; } xmlFree(strIsPossibleGlobal); } else if (xmlStrcmp(attr->name, (xmlChar *) "destroy_func") == 0) { structure->destroyFunc = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "clone_func") == 0) { structure->cloneFunc = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "new_full_extra_code") == 0) { structure->new_full_extraCode = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "default_native") == 0) { structure->defaultNative = dup_attribute_value(attr->doc, attr->children, 1); } else if (xmlStrcmp(attr->name, (xmlChar *) "is_bare") == 0) { xmlChar *strIsBare; strIsBare = xmlNodeListGetString(attr->doc, attr->children, 1); if (g_strcmp0((const gchar *) strIsBare, "true") == 0) { structure->isBare = TRUE; } xmlFree(strIsBare); } else { fprintf(stderr, "The attribute of %s in structure '%s' cannot be parsed\n", (char *)attr->name, structure->name); } } for (child = xmlFirstElementChild(node); child != NULL; child = xmlNextElementSibling(child)) { if (g_strcmp0((gchar *) child->name, "method") == 0) { method = method_new(); if (!parse_method(child, method)) { method_free(method); } else { structure->methods = g_list_append(structure->methods, method); } method = NULL; } if (g_strcmp0((gchar *) child->name, "declaration") == 0) { declaration = declaration_new(); if (!parse_declaration(child, declaration)) { declaration_free(declaration); } else { structure->declarations = g_list_append(structure->declarations, declaration); } declaration = NULL; } else if (g_strcmp0((gchar *) child->name, "enum") == 0) { enumeration = enumeration_new(); if (!parse_enumeration(child, enumeration)) { enumeration_free(enumeration); } else { structure->enumerations = g_list_append(structure->enumerations, enumeration); } enumeration = NULL; } } populate_dependencies(structure); return TRUE; } void populate_dependencies(Structure * structure) { GList *iter_method; GList *iter_para; Method *method; Parameter *para; gchar *trueType; iter_method = NULL; iter_para = NULL; method = NULL; para = NULL; trueType = NULL; for (iter_method = g_list_first(structure->methods); iter_method != NULL; iter_method = g_list_next(iter_method)) { method = (Method *) iter_method->data; /*Process the parameters */ for (iter_para = g_list_first(method->parameters); iter_para != NULL; iter_para = g_list_next(iter_para)) { para = (Parameter *) iter_para->data; trueType = get_true_type(para->type); (void)g_hash_table_insert(structure->dependencies, trueType, NULL); trueType = NULL; } if (method->ret != NULL) { trueType = get_true_type(method->ret->type); (void)g_hash_table_insert(structure->dependencies, trueType, NULL); trueType = NULL; } } }