diff --git a/data/dimers random walk.xml b/data/dimers random walk.xml index 12ae465..39ecfd7 100644 --- a/data/dimers random walk.xml +++ b/data/dimers random walk.xml @@ -1,21 +1,17 @@ - - Modèle de test - - Léontine Patinette - - 2 - - 1630000000 - + + model name + owner + owner_id + 2021 1.0 + Ref - Ref - + 0 9 @@ -30,7 +26,7 @@ - + @@ -42,8 +38,8 @@ - - + + @@ -53,8 +49,8 @@ - - + + @@ -73,7 +69,7 @@ - + @@ -93,7 +89,7 @@ - @@ -103,7 +99,7 @@ - diff --git a/include/base.h b/include/base.h index 365d60f..d91466d 100644 --- a/include/base.h +++ b/include/base.h @@ -1,25 +1,32 @@ /* - * Gem-graph OpenGL experiments + * @file * - * Desc: Base header + * Gem-graph main file * - * Copyright (C) 2023 Arthur Menges - * Copyright (C) 2023 Adrien Bourmault + * Gem-graph OpenGL experiments * - * This file is part of Gem-graph. + * Desc: Base header * - * 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 file is part of Gem-graph. * - * 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. + * @cond LICENSE + * Copyright © 2021 Libre en Communs + * Copyright © 2021-2024 Adrien Bourmault + * Copyright © 2021-2024 Jean Sirmai * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * 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 . + * @endcond */ #pragma once @@ -58,10 +65,9 @@ static inline char *read_file(char *filename); // < used by : init.c /* * char *read_file(char *filename) reads a file from filename into a provided buffer * - * @param filename, file name - * contents, target ptr + * @param filename * - * @return void + * @return contents */ static inline char *read_file(char *filename) { diff --git a/include/parsing.h b/include/parse.h similarity index 69% rename from include/parsing.h rename to include/parse.h index 1cf7ff8..a1de310 100644 --- a/include/parsing.h +++ b/include/parse.h @@ -26,18 +26,19 @@ #include #include "base.h" -bool model_init(const char *content, size_t length, const char *basename); -bool model_shutdown(void); +bool parse_model_init(const char *content, size_t length, const char *basename); +bool parse_model_shutdown(void); -char model_get_dim(void); -long model_get_dim_value(const char *axis); -char model_get_multiplicity(void); -bool model_get_next_state(char *new_state_id); -bool model_get_next_arrow(struct arrow_t *new_arrow, +char parse_model_get_dim(void); +long parse_model_get_dim_value(const char *axis); +char parse_model_get_multiplicity(void); +bool parse_model_get_next_space_state(char *new_state_id); +bool parse_model_get_next_arrow(struct arrow_t *new_arrow, const char *state_id, char dimension); -long model_get_state_arrows_count(const char *state_id); -bool model_get_next_arrow(struct arrow_t *new_arrow, +long parse_model_get_state_arrows_count(const char *state_id); +bool parse_model_get_next_arrow(struct arrow_t *new_arrow, const char *state_id, char dimension); +void parse_model_test(); diff --git a/src/parsing.c b/src/parse.c similarity index 56% rename from src/parsing.c rename to src/parse.c index 99fc764..2da5802 100644 --- a/src/parsing.c +++ b/src/parse.c @@ -1,6 +1,53 @@ /** * @file - * Phantom docs (TODO) + * + * XML Gem-graph model parsing functions + * + * ----------------------------------------------------------------------------- + * + * @warning about the word '*node*' + * + * A possible confusion between the xml tree '*nodes*' used in the model xml file + * and the gem-graph '*nodes*' that are local space units used in the geometric + * space representation could make this code difficult to understand; + * + * The local name 'node' used alone should be avoided. + * + * In this version, this ambiguity is resolved by using the name "cur_node" + * (current node) for the the xml 'nodes' processed by the parser. + * + * ----------------------------------------------------------------------------- + * + * unstable documentation: TODO + * - a link towards reference text describing how gem-graph operates and why + * all the parsed items (compulsory or optional) are useful is missing. + * - a link towards the description of the gem-graph model structure (and its XML + * implementation) is missing. + * + * List of the gem-graph concepts and names (version="0.2.1") parsed here: + * - identity, + * - parameters + * - objects + * - global space (as opposed to local space or working area) + * - dimension (of the space), size + * - topology and limits (of the space): torus, limited area,... + * - (state of the global space) + * - conditions + * - transitions + * - arrow + * - arrow address (site, weight, x, y, z) + * - site + * - node (local space units of the geometric graph) + * - multiplicity (number of sites in each state unit ('cell') + * . + * + * @see space doc (including arrow doc) (TODO) + * + * ----------------------------------------------------------------------------- + * + * This file is inherited from a previous development of the Gem-graph server + * then client, in the devel branch commit + * 79cae535258d557e29592a45fbdf426149505738 * * This file is part of Gem-graph. * @@ -24,36 +71,59 @@ * @endcond */ -#include -#include -#include -#include -#include -#include -#include -#include -#include // http://xmlsoft.org/examples/#parse1.c - // https://gnome.pages.gitlab.gnome.org/libxml2/devhelp/general.html +#include // http://xmlsoft.org/examples/#parse1.c + // https://gnome.pages.gitlab.gnome.org/libxml2/devhelp/general.html #include "../include/base.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) +#define READ_SITE 1 << 0 /**< arrow address = (site, weight, x, y, z) @see arrow doc */ +#define READ_WEIGHT 1 << 1 /**< arrow address = (site, weight, x, y, z) @see arrow doc */ +#define READ_X 1 << 2 /**< arrow address = (site, weight, x, y, z) @see arrow doc */ +#define READ_Y 1 << 3 /**< arrow address = (site, weight, x, y, z) @see arrow doc */ +#define READ_Z 1 << 4 /**< arrow address = (site, weight, x, y, z) @see arrow doc */ +/** unstable doc */ +#define SUCCESSFUL_READ_ARROW_X (READ_SITE | READ_WEIGHT | READ_X) /**< flag 1D */ +/** unstable doc */ +#define SUCCESSFUL_READ_ARROW_XY (READ_SITE | READ_WEIGHT | READ_X | READ_Y) /**< flag 2D */ +/** unstable doc */ +#define SUCCESSFUL_READ_ARROW_XYZ (READ_SITE | READ_WEIGHT | READ_X | READ_Y | READ_Z) /**< flag 3D */ static xmlDocPtr model; -static xmlHashTablePtr model_hashtable; +static xmlHashTablePtr parse_model_hashtable; -bool model_init(const char *content, size_t length, const char *basename) +/** + * unstable doc + * + * a debug function + * + * @callgraph parse_model_init() + * @callgraph lseek() + */ +void parse_model_test() { - xmlNode *node; - /* + char *content; + char *basename = "data/dimers random walk.xml"; + size_t length = lseek(*basename, length, *xxx); + parse_model_init (content, length, "/truc/fichier.xml"); + */ +} + + +/** + * unstable doc + * + * @param *content + * @param length + * @param *basename + * + * @returns bool + */ +bool parse_model_init(const char *content, size_t length, const char *basename) +{ + xmlNode *cur_node; + + /** * this initialize the library and check potential ABI mismatches * between the version it was compiled for and the actual shared * library used. @@ -66,23 +136,23 @@ bool model_init(const char *content, size_t length, const char *basename) return false; } - node = xmlDocGetRootElement(model); + cur_node = xmlDocGetRootElement(model); - if (node == NULL) { + if (cur_node == NULL) { g_printerr("Empty XML model !\n"); xmlFreeDoc(model); return false; } - if (xmlStrcmp(node->name, (xmlChar *) "gem-graph-model")) { + if (xmlStrcmp(cur_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); + parse_model_hashtable = xmlHashCreate(0); - if (model_hashtable == NULL) { + if (parse_model_hashtable == NULL) { g_printerr("Can't create model hash table !\n"); xmlFreeDoc(model); return false; @@ -91,10 +161,15 @@ bool model_init(const char *content, size_t length, const char *basename) return true; } -bool model_shutdown(void) +/** + * unstable doc + * + * @returns bool + */ +bool parse_model_shutdown(void) { xmlFreeDoc(model); - xmlHashFree(model_hashtable, NULL); + xmlHashFree(parse_model_hashtable, NULL); // Cleanup function for the XML library xmlCleanupParser(); @@ -107,15 +182,22 @@ bool model_shutdown(void) /******************************************************************************/ -static inline xmlNodePtr getNextChild(xmlNodePtr node, xmlChar *last) +/** + * static doc is ignored by doxygen / consider local helpfulness + */ +static inline xmlNodePtr getNextChild(xmlNodePtr cur_node, xmlChar *last) { - while (node != NULL && xmlStrcmp(node->name, last)) { - // //printf(" <>--- line n°%lu <%s>\n", xmlGetLineNo(node), node->name); - node = node->next; + while (cur_node != NULL && xmlStrcmp(cur_node->name, last)) { + // printf(" <>--- line n°%lu <%s>\n", xmlGetLineNo(cur_node), + // cur_node->name); + cur_node = cur_node->next; } - return node; + return cur_node; } +/** + * static doc is ignored by doxygen / consider local helpfulness + */ static inline xmlChar* splitStrAtSlash(xmlChar *toSplit) { toSplit = (xmlChar *)xmlStrchr(toSplit, '/'); @@ -123,17 +205,24 @@ static inline xmlChar* splitStrAtSlash(xmlChar *toSplit) return toSplit; } +/** + * static doc is ignored by doxygen / consider local helpfulness + */ 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); + // 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 doc is ignored by doxygen / consider local helpfulness + */ static inline xmlChar* getLastTag(xmlChar *path) { while ((ulong)xmlStrchr (path, '/')) @@ -145,42 +234,45 @@ static inline xmlChar* getLastTag(xmlChar *path) /******************************************************************************/ -static xmlNodePtr model_get_node(xmlChar *path) +/** + * static doc is ignored by doxygen / consider local helpfulness + */ +static xmlNodePtr parse_model_get_node(xmlChar *path) { - xmlNodePtr node; + xmlNodePtr cur_node; xmlChar *extrait; xmlChar *reste, *last; - // Lookup for node from path in hash table - node = xmlHashLookup(model_hashtable, path); + // Lookup for cur_node from path in hash table + cur_node = xmlHashLookup(parse_model_hashtable, path); - // Found a node in hash table - if (node) { - return node; + // Found a cur_node in hash table + if (cur_node) { + return cur_node; - // no node found in hash table + // no cur_node found in hash table } else { reste = path; last = getLastTag(reste); - node = xmlDocGetRootElement(model); + cur_node = xmlDocGetRootElement(model); while (xmlStrchr (reste, '/')) { extrait = getFirstTag(reste); reste = splitStrAtSlash((xmlChar *)reste); - node = node->xmlChildrenNode; - node = getNextChild(node, extrait); + cur_node = cur_node->xmlChildrenNode; + cur_node = getNextChild(cur_node, extrait); } - if(node && xmlStrcmp(node->name, last)) { - node = node->xmlChildrenNode; + if(cur_node && xmlStrcmp(cur_node->name, last)) { + cur_node = cur_node->xmlChildrenNode; - while (node && xmlStrcmp(node->name, last)) { - node = node->next; + while (cur_node && xmlStrcmp(cur_node->name, last)) { + cur_node = cur_node->next; } - xmlHashAddEntry (model_hashtable, path, node); + xmlHashAddEntry (parse_model_hashtable, path, cur_node); } - return node; + return cur_node; } @@ -189,17 +281,20 @@ static xmlNodePtr model_get_node(xmlChar *path) /******************************************************************************/ -static inline long model_get_node_long_attrib(xmlNodePtr node, char *id) +/** + * static doc is ignored by doxygen / consider local helpfulness + */ +static inline long parse_model_get_node_long_attrib(xmlNodePtr cur_node, char *id) { xmlAttr *attribute; xmlChar* value; long ret_value; - if (node && node->properties) { - attribute = node->properties; + if (cur_node && cur_node->properties) { + attribute = cur_node->properties; while(attribute && attribute->name && attribute->children) { if (!xmlStrcmp(attribute->name, (const xmlChar *)id)) { - value = xmlNodeListGetString(node->doc, attribute->children, 1); + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); ret_value = strtol((char *)value, NULL, 0); xmlFree(value); return ret_value; @@ -210,18 +305,21 @@ static inline long model_get_node_long_attrib(xmlNodePtr node, char *id) return 0; } -static inline bool model_get_node_str_attrib(xmlNodePtr node, +/** + * static doc is ignored by doxygen / consider local helpfulness + */ +static inline bool parse_model_get_node_str_attrib(xmlNodePtr cur_node, char *id, char *dest) { xmlAttr *attribute; xmlChar* value; - if (node && node->properties) { - attribute = node->properties; + if (cur_node && cur_node->properties) { + attribute = cur_node->properties; while(attribute && attribute->name && attribute->children) { if (!xmlStrcmp(attribute->name, (const xmlChar *)id)) { - value = xmlNodeListGetString(node->doc, attribute->children, 1); + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); strcpy(dest, (char *)value); xmlFree(value); return true; @@ -234,45 +332,81 @@ static inline bool model_get_node_str_attrib(xmlNodePtr node, /******************************************************************************/ -char model_get_dim(void) +/** + * unstable doc + * + * 'dim' means here the number of dimensions (x,y,z) of this model space + * @see a reference text explaining that models of any dimension (> 0) can be + * used by gem-graph + * + * @returns 0, 1, 2, or 3 + */ +char parse_model_get_dim(void) { - // xmlAttr *attribute; - // xmlChar* value; - xmlNodePtr node = model_get_node( + xmlNodePtr cur_node = parse_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; + if (xmlHasProp (cur_node, (xmlChar *) "z")) return 3; + if (xmlHasProp (cur_node, (xmlChar *) "y")) return 2; + if (xmlHasProp (cur_node, (xmlChar *) "x")) return 1; return 0; } -long model_get_dim_value(const char *axis) +/** + * unstable doc + * + * 'dim' means here the number of dimensions (x,y,z) of this model space + * @see a reference text explaining that models of any dimension (> 0) can be + * used by gem-graph + * + * @param *axis + * + * @returns long + */ +long parse_model_get_dim_value(const char *axis) { // xmlAttr *attribute; // xmlChar *value; // long ret_value; - xmlNodePtr node = model_get_node( + xmlNodePtr cur_node = parse_model_get_node( (xmlChar *)"parameters/space-param/dimension"); - return model_get_node_long_attrib(node, (char *)axis); + return parse_model_get_node_long_attrib(cur_node, (char *)axis); } -char model_get_multiplicity(void) +/** + * unstable doc + * + * 'multiplicity' + * @see arrow doc + */ +char parse_model_get_multiplicity(void) { // xmlAttr *attribute; // xmlChar* value; - xmlNodePtr node = model_get_node( + xmlNodePtr cur_node = parse_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); + if (cur_node->children) + if (cur_node->children->content) + return (char)strtol((char *)cur_node->children->content, NULL, 0); return 0; } -bool model_get_next_state(char *new_state_id) +/** + * unstable doc + * + * next *state* is one of the possible states of the global space. + * + * @see a reference text explaining that the gem-graph server calculates successive + * states of a Markov chain from the initial state; + * + * @param *new_state_id + * + * @returns boolean + */ +bool parse_model_get_next_space_state(char *new_state_id) { static xmlNodePtr cur_node = NULL; // xmlAttr *attribute; @@ -280,7 +414,7 @@ bool model_get_next_state(char *new_state_id) if (cur_node == NULL) { // Get first state - cur_node = model_get_node((xmlChar *)"savedstates/state"); + cur_node = parse_model_get_node((xmlChar *)"savedstates/state"); } else { // Get next state @@ -291,14 +425,21 @@ bool model_get_next_state(char *new_state_id) } // Lookup in properties - if (model_get_node_str_attrib(cur_node, "id", new_state_id)) + if (parse_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) +/** + * unstable doc + * + * @param *state_id + * + * @returns long + */ +long parse_model_get_state_arrows_count(const char *state_id) { xmlNodePtr cur_node = NULL; // xmlAttr *attribute; @@ -312,14 +453,14 @@ long model_get_state_arrows_count(const char *state_id) assert(state_id); // Get first state node - cur_node = model_get_node((xmlChar *)"savedstates/state"); + cur_node = parse_model_get_node((xmlChar *)"savedstates/state"); // Lookup in properties while (cur_node && cur_node->properties) { // attribute = cur_node->properties; < usage ? // Look for the id attribute - if (model_get_node_str_attrib(cur_node, "id", (char *)&temp_char)) { + if (parse_model_get_node_str_attrib(cur_node, "id", (char *)&temp_char)) { if (!xmlStrcmp((const xmlChar *)temp_char, (const xmlChar *)state_id)) { found = true; break; @@ -349,7 +490,19 @@ long model_get_state_arrows_count(const char *state_id) return value; } -bool model_get_next_arrow(struct arrow_t *new_arrow, +/** + * unstable doc + * + * @see A reference text explaining that the list parsed here describes the + * arrows repartition in the initial state of the space. + * + * @param *new_arrow + * @param *state_id + * @param *dimension + * + * @returns bool + */ +bool parse_model_get_next_arrow(struct arrow_t *new_arrow, const char *state_id, char dimension) { @@ -367,14 +520,14 @@ bool model_get_next_arrow(struct arrow_t *new_arrow, if (cur_node == NULL) { // Get first state node - cur_node = model_get_node((xmlChar *)"savedstates/state"); + cur_node = parse_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", (char *)&temp_char)) { + if (parse_model_get_node_str_attrib(cur_node, "id", (char *)&temp_char)) { if (!xmlStrcmp((xmlChar *)temp_char, (const xmlChar *)state_id)) { found = true; break;