diff --git a/src/model.c b/src/model.c index 0070ade..fb2ddae 100644 --- a/src/model.c +++ b/src/model.c @@ -25,4 +25,449 @@ #include "../include/arrows.h" #include "../include/scheduler.h" +#define READ_SITE 1 << 0 +#define READ_WEIGHT 1 << 1 +#define READ_X 1 << 2 +#define READ_Y 1 << 3 +#define READ_Z 1 << 4 +#define SUCCESSFUL_READ_ARROW_X (READ_SITE | READ_WEIGHT | READ_X) +#define SUCCESSFUL_READ_ARROW_XY (READ_SITE | READ_WEIGHT | READ_X | READ_Y) +#define SUCCESSFUL_READ_ARROW_XYZ (READ_SITE | READ_WEIGHT | READ_X | READ_Y | READ_Z) +static xmlDocPtr model; +static xmlHashTablePtr model_hashtable; + +bool model_init(const char *content, size_t length, const char *basename) +{ + xmlNode *node; + + /* + * this initialize the library and check potential ABI mismatches + * between the version it was compiled for and the actual shared + * library used. + */ + LIBXML_TEST_VERSION + + model = xmlReadMemory(content, length, basename, NULL, 0); + + if (model == NULL ) { + return false; + } + + node = xmlDocGetRootElement(model); + + if (node == NULL) { + g_printerr("Empty XML model !\n"); + xmlFreeDoc(model); + return false; + } + + if (xmlStrcmp(node->name, (xmlChar *) "gem-graph-model")) { + g_printerr("document of the wrong type, root node != gem-graph-model\n"); + xmlFreeDoc(model); + return false; + } + + model_hashtable = xmlHashCreate(0); + + if (model_hashtable == NULL) { + g_printerr("Can't create model hash table !\n"); + xmlFreeDoc(model); + return false; + } + + return true; +} + +bool model_shutdown(void) +{ + xmlFreeDoc(model); + xmlHashFree(model_hashtable, NULL); + + // Cleanup function for the XML library + xmlCleanupParser(); + + // This is to debug memory for regression tests + xmlMemoryDump(); + + return true; +} + +/******************************************************************************/ + +static inline xmlNodePtr getNextChild(xmlNodePtr node, xmlChar *last) +{ + while (node != NULL && xmlStrcmp(node->name, last)) { + // //printf(" <>--- line n°%lu <%s>\n", xmlGetLineNo(node), node->name); + node = node->next; + } + return node; +} + +static inline xmlChar* splitStrAtSlash(xmlChar *toSplit) +{ + toSplit = (xmlChar *)xmlStrchr(toSplit, '/'); + toSplit = xmlStrsub (toSplit, 1, xmlStrlen(toSplit)); + return toSplit; +} + +static inline xmlChar* getFirstTag(xmlChar *path) +{ + xmlChar *preop = path; + path = (xmlChar *)xmlStrchr(path, '/'); + path = xmlStrsub (path, 1, xmlStrlen(path)); + + //printf("%s = %s + / + %s\n", preop,\ + xmlStrsub (preop, 0, xmlStrlen(preop) - xmlStrlen(path) - 1), path); + + return xmlStrsub (preop, 0, xmlStrlen(preop) - xmlStrlen(path) - 1); +} + +static inline xmlChar* getLastTag(xmlChar *path) +{ + while ((ulong)xmlStrchr (path, '/')) + path = splitStrAtSlash((xmlChar *)path); + + // //printf("last tag in the path = <%s>\n", path); + return path; // which is no more the given path but only its last tag ! +} + +/******************************************************************************/ + +static xmlNodePtr model_get_node(xmlChar *path) +{ + xmlNodePtr node; + xmlChar *extrait; + xmlChar *reste, *last, *affich; + + // Lookup for node from path in hash table + node = xmlHashLookup(model_hashtable, path); + + // Found a node in hash table + if (node) { + return node; + + // no node found in hash table + } else { + reste = path; + affich = reste; + last = getLastTag(reste); + node = xmlDocGetRootElement(model); + + while (xmlStrchr (reste, '/')) { + extrait = getFirstTag(reste); + reste = splitStrAtSlash((xmlChar *)reste); + node = node->xmlChildrenNode; + node = getNextChild(node, extrait); + } + + if(node && xmlStrcmp(node->name, last)) { + node = node->xmlChildrenNode; + + while (node && xmlStrcmp(node->name, last)) { + node = node->next; + } + xmlHashAddEntry (model_hashtable, path, node); + } + + return node; + + } + + return NULL; +} + +/******************************************************************************/ + +static inline long model_get_node_long_attrib(xmlNodePtr node, char *id) +{ + xmlAttr *attribute; + xmlChar* value; + long ret_value; + + if (node && node->properties) { + attribute = node->properties; + while(attribute && attribute->name && attribute->children) { + if (!xmlStrcmp(attribute->name, (const xmlChar *)id)) { + value = xmlNodeListGetString(node->doc, attribute->children, 1); + ret_value = strtol((char *)value, NULL, 0); + xmlFree(value); + return ret_value; + } + attribute = attribute->next; + } + } + return 0; +} + +static inline bool model_get_node_str_attrib(xmlNodePtr node, + char *id, + char *dest) +{ + xmlAttr *attribute; + xmlChar* value; + + if (node && node->properties) { + attribute = node->properties; + while(attribute && attribute->name && attribute->children) { + if (!xmlStrcmp(attribute->name, (const xmlChar *)id)) { + value = xmlNodeListGetString(node->doc, attribute->children, 1); + strcpy(dest, value); + xmlFree(value); + return true; + } + attribute = attribute->next; + } + } + return false; +} + +/******************************************************************************/ + +char model_get_dim(void) +{ + xmlAttr *attribute; + xmlChar* value; + xmlNodePtr node = model_get_node( + (xmlChar *)"parameters/space-param/dimension"); + + if (xmlHasProp (node, (xmlChar *) "z")) return 3; + if (xmlHasProp (node, (xmlChar *) "y")) return 2; + if (xmlHasProp (node, (xmlChar *) "x")) return 1; + return 0; +} + +long model_get_dim_value(const char *axis) +{ + xmlAttr *attribute; + xmlChar *value; + long ret_value; + xmlNodePtr node = model_get_node( + (xmlChar *)"parameters/space-param/dimension"); + + return model_get_node_long_attrib(node, axis); +} + +char model_get_multiplicity(void) +{ + xmlAttr *attribute; + xmlChar* value; + xmlNodePtr node = model_get_node( + (xmlChar *)"parameters/space-param/site_multiplicity"); + + if (node->children) + if (node->children->content) + return (char)strtol((char *)node->children->content, NULL, 0); + + return 0; +} + +bool model_get_next_state(char *new_state_id) +{ + static xmlNodePtr cur_node = NULL; + xmlAttr *attribute; + xmlChar *value; + + if (cur_node == NULL) { + // Get first state + cur_node = model_get_node((xmlChar *)"savedstates/state"); + + } else { + // Get next state + if (cur_node->next) + cur_node = cur_node->next; + else + return false; + } + + // Lookup in properties + if (model_get_node_str_attrib(cur_node, "id", new_state_id)) + return true; + + cur_node = NULL; + return false; +} + +long model_get_state_arrows_count(const char *state_id) +{ + xmlNodePtr cur_node = NULL; + xmlAttr *attribute; + long value = 0; + bool found = false; + char temp_char[25]; + uint check = 0; // bit field checker + + //printf("NEW CALL : cur_node = %p\n", cur_node); + + assert(state_id); + + // Get first state node + cur_node = model_get_node((xmlChar *)"savedstates/state"); + + // Lookup in properties + while (cur_node && cur_node->properties) { + attribute = cur_node->properties; + + // Look for the id attribute + if (model_get_node_str_attrib(cur_node, "id", &temp_char)) { + if (!xmlStrcmp(temp_char, (const xmlChar *)state_id)) { + found = true; + break; + } + } + cur_node = cur_node->next; + } + + // Check if the state has been found + if (!found) { + cur_node = NULL; + return -1; + } + + + // Count arrows + if (cur_node->children) { + cur_node = cur_node->children; + while (cur_node) { + if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) + value++; + cur_node = cur_node->next; + } + } else { + return -1; + } + return value; +} + +bool model_get_next_arrow(struct arrow_t *new_arrow, + const char *state_id, + char dimension) +{ + static xmlNodePtr cur_node = NULL; + xmlAttr *attribute; + xmlChar *value; + bool found = false; + char temp_char[25]; + uint check = 0; // bit field checker + + //printf("NEW CALL : cur_node = %p\n", cur_node); + + assert(new_arrow); + assert(state_id); + + if (cur_node == NULL) { + // Get first state node + cur_node = model_get_node((xmlChar *)"savedstates/state"); + + // Lookup in properties + while (cur_node && cur_node->properties) { + attribute = cur_node->properties; + + // Look for the id attribute + if (model_get_node_str_attrib(cur_node, "id", &temp_char)) { + if (!xmlStrcmp(temp_char, (const xmlChar *)state_id)) { + found = true; + break; + } + } + cur_node = cur_node->next; + } + + // Check if the state has been found + if (!found) { + cur_node = NULL; + return false; + } + + // Get first arrow + if (cur_node->children) { + cur_node = cur_node->children; + + found = false; + while (cur_node && cur_node->name) { + if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) { + found = true; + break; + } + cur_node = cur_node->next; + } + } + + // Check if the state has been found + if (!found) { + cur_node = NULL; + return false; + } + + } else { + // Get next arrow + found = false; + while (cur_node->next) { + cur_node = cur_node->next; + if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) { + found = true; + break; + } + } + + // Check if the state has been found + if (!found) { + cur_node = NULL; + return false; + } + } + + //printf("DURING CALL : cur_node = %p\n", cur_node); + //printf("DURING CALL : cur_node->name = %s\n", cur_node->name); + + // Lookup in properties + if (cur_node && cur_node->properties) { + attribute = cur_node->properties; + + while(attribute && attribute->name && attribute->children) { + //printf("attr name : %s\n", attribute->name); + if (!xmlStrcmp(attribute->name, (const xmlChar *)"site")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_arrow->site = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_SITE; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"weight")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_arrow->load = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_WEIGHT; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"x")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_arrow->x = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_X; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"y")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_arrow->y = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_Y; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"z")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_arrow->z = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_Z; + } + attribute = attribute->next; + } + + switch(dimension) { + case 3: + return (bool)(check & SUCCESSFUL_READ_ARROW_XYZ); + case 2: + return (bool)(check & SUCCESSFUL_READ_ARROW_XY); + case 1: + return (bool)(check & SUCCESSFUL_READ_ARROW_X); + } + } + cur_node = NULL; + return false; +} diff --git a/src/parsing.c b/src/parsing.c deleted file mode 100644 index ec88c89..0000000 --- a/src/parsing.c +++ /dev/null @@ -1,27 +0,0 @@ -//=-------------------------------------------------------------------------=// -// XML parsing module // -// // -// Copyright © 2021 Libre en Communs (contact@a-lec.org) // -// Copyright © 2021 Adrien Bourmault (neox@a-lec.org) // -// // -// This file is part of gem-graph. // -// // -// This program is free software: you can redistribute it and/or modify // -// it under the terms of the GNU Affero General Public License as // -// published by the Free Software Foundation, either version 3 of the // -// License, or (at your option) any later version. // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU Affero General Public License for more details. // -// // -// You should have received a copy of the GNU Affero General Public License // -// along with this program. If not, see . // -//=-------------------------------------------------------------------------=// - -#include "../include/parsing.h" -#include "../include/arrows.h" -#include "../include/model.h" - -