From 2dcb773997d69a87ec0073cd590a3eb1837020cd Mon Sep 17 00:00:00 2001 From: Alexey Fedoseev Date: Sun, 31 Mar 2024 17:50:49 +0300 Subject: [PATCH] add Cyberiada Document structure to allow multi-sm files --- cyberiadaml.c | 294 +++++++++++++++++++++++++++++++------------------- cyberiadaml.h | 125 +++++++++++---------- test.c | 10 +- 3 files changed, 258 insertions(+), 171 deletions(-) diff --git a/cyberiadaml.c b/cyberiadaml.c index 55cf1bc..d881481 100644 --- a/cyberiadaml.c +++ b/cyberiadaml.c @@ -243,7 +243,7 @@ static CyberiadaNode* cyberiada_new_node(const char* id) new_node->type = cybNodeSimpleState; new_node->title = NULL; new_node->title_len = 0; - new_node->action = NULL; + new_node->actions = NULL; new_node->next = NULL; new_node->parent = NULL; new_node->children = NULL; @@ -277,7 +277,7 @@ static int cyberiada_destroy_node(CyberiadaNode* node) if(node->children) { cyberiada_destroy_all_nodes(node->children); } - if(node->action) cyberiada_destroy_action(node->action); + if(node->actions) cyberiada_destroy_action(node->actions); if(node->geometry_rect) free(node->geometry_rect); free(node); } @@ -554,7 +554,7 @@ static int cyberiada_decode_state_block_action(const char* text, CyberiadaAction return CYBERIADA_NO_ERROR; } -static int cyberiada_decode_state_action(const char* text, CyberiadaAction** action) +static int cyberiada_decode_state_actions(const char* text, CyberiadaAction** action) { int res; size_t buffer_len; @@ -769,19 +769,23 @@ static int cyberiada_destroy_edge(CyberiadaEdge* e) return CYBERIADA_NO_ERROR; } -static int cyberiada_graph_reconstruct_edges(CyberiadaSM* sm) +static int cyberiada_graphs_reconstruct_edges(CyberiadaDocument* doc) { - CyberiadaEdge* edge = sm->edges; - while (edge) { - CyberiadaNode* source = cyberiada_graph_find_node_by_id(sm->nodes, edge->source_id); - CyberiadaNode* target = cyberiada_graph_find_node_by_id(sm->nodes, edge->target_id); - if (!source || !target) { - ERROR("cannot find source/target node for edge %s %s\n", edge->source_id, edge->target_id); - return CYBERIADA_FORMAT_ERROR; + CyberiadaEdge* edge; + CyberiadaSM* sm; + for (sm = doc->state_machines; sm; sm = sm->next) { + edge = sm->edges; + while (edge) { + CyberiadaNode* source = cyberiada_graph_find_node_by_id(sm->nodes, edge->source_id); + CyberiadaNode* target = cyberiada_graph_find_node_by_id(sm->nodes, edge->target_id); + if (!source || !target) { + ERROR("cannot find source/target node for edge %s %s\n", edge->source_id, edge->target_id); + return CYBERIADA_FORMAT_ERROR; + } + edge->source = source; + edge->target = target; + edge = edge->next; } - edge->source = source; - edge->target = target; - edge = edge->next; } return CYBERIADA_NO_ERROR; } @@ -876,11 +880,11 @@ static MetainfoDeclaration cyberiada_metadata[] = { } }; -static int cyberiada_add_default_meta(CyberiadaSM* sm, const char* sm_name) +static int cyberiada_add_default_meta(CyberiadaDocument* doc, const char* sm_name) { CyberiadaMetainformation* meta; - if (sm->meta_info) { + if (doc->meta_info) { return CYBERIADA_BAD_PARAMETER; } @@ -897,7 +901,7 @@ static int cyberiada_add_default_meta(CyberiadaSM* sm, const char* sm_name) meta->actions_order_flag = 1; meta->event_propagation_flag = 1; - sm->meta_info = meta; + doc->meta_info = meta; return CYBERIADA_NO_ERROR; } @@ -1008,34 +1012,44 @@ static int cyberiada_add_default_meta(CyberiadaSM* sm, const char* sm_name) * The Cyberiada GraphML library fucntions declarations * ----------------------------------------------------------------------------- */ -CyberiadaSM* cyberiada_create_sm(void) +static int cyberiada_init_sm(CyberiadaSM* sm) +{ + if (sm) { + sm->nodes = NULL; + sm->edges = NULL; + sm->next = NULL; + } + return CYBERIADA_NO_ERROR; +} + +static CyberiadaSM* cyberiada_create_sm(void) { CyberiadaSM* sm = (CyberiadaSM*)malloc(sizeof(CyberiadaSM)); cyberiada_init_sm(sm); return sm; } -int cyberiada_init_sm(CyberiadaSM* sm) +CyberiadaDocument* cyberiada_create_sm_document(void) { - if (sm) { - sm->format = NULL; - sm->meta_info = NULL; - sm->nodes = NULL; - sm->edges = NULL; + CyberiadaDocument* doc = (CyberiadaDocument*)malloc(sizeof(CyberiadaDocument)); + cyberiada_init_sm_document(doc); + return doc; +} + +int cyberiada_init_sm_document(CyberiadaDocument* doc) +{ + if (doc) { + doc->format = NULL; + doc->meta_info = NULL; + doc->state_machines = NULL; } return CYBERIADA_NO_ERROR; } -int cyberiada_cleanup_sm(CyberiadaSM* sm) +static int cyberiada_destroy_sm(CyberiadaSM* sm) { CyberiadaEdge *edge, *e; if (sm) { - if (sm->format) { - free(sm->format); - } - if (sm->meta_info) { - cyberiada_destroy_meta(sm->meta_info); - } if (sm->nodes) { cyberiada_destroy_all_nodes(sm->nodes); } @@ -1047,18 +1061,41 @@ int cyberiada_cleanup_sm(CyberiadaSM* sm) cyberiada_destroy_edge(e); } while (edge); } - cyberiada_init_sm(sm); + free(sm); } return CYBERIADA_NO_ERROR; } -int cyberiada_destroy_sm(CyberiadaSM* sm) +int cyberiada_cleanup_sm_document(CyberiadaDocument* doc) { - int res = cyberiada_cleanup_sm(sm); + CyberiadaSM *sm, *sm2; + if (doc) { + if (doc->format) { + free(doc->format); + } + if (doc->meta_info) { + cyberiada_destroy_meta(doc->meta_info); + } + if (doc->state_machines) { + sm = doc->state_machines; + do { + sm2 = sm; + sm = sm->next; + cyberiada_destroy_sm(sm2); + } while (sm); + } + cyberiada_init_sm_document(doc); + } + return CYBERIADA_NO_ERROR; +} + +int cyberiada_destroy_sm_document(CyberiadaDocument* doc) +{ + int res = cyberiada_cleanup_sm_document(doc); if (res != CYBERIADA_NO_ERROR) { return res; } - free(sm); + free(doc); return CYBERIADA_NO_ERROR; } @@ -1206,11 +1243,12 @@ static int cyberiada_get_element_text(char* buffer, size_t buffer_len, } static GraphProcessorState handle_new_graph(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; size_t buffer_len = sizeof(buffer) - 1; + CyberiadaSM* sm = doc->state_machines; /* process the top graph element only */ if(cyberiada_get_attr_value(buffer, buffer_len, xml_node, @@ -1218,6 +1256,7 @@ static GraphProcessorState handle_new_graph(xmlNode* xml_node, return gpsInvalid; } /* DEBUG("found graph %s \n", buffer); */ + while (sm->next) sm = sm->next; if (sm->nodes == NULL) { sm->nodes = cyberiada_new_node(CYBERIADA_ROOT_NODE); sm->nodes->type = cybNodeSM; @@ -1227,7 +1266,7 @@ static GraphProcessorState handle_new_graph(xmlNode* xml_node, } static GraphProcessorState handle_new_node(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { CyberiadaNode* node; @@ -1254,7 +1293,7 @@ static GraphProcessorState handle_new_node(xmlNode* xml_node, cyberiada_graph_add_sibling_node(parent->children, node); } - if (*(node->id) != 0 || sm->format) { + if (*(node->id) != 0 || doc->format) { return gpsNode; } else { return gpsFakeNode; @@ -1262,7 +1301,7 @@ static GraphProcessorState handle_new_node(xmlNode* xml_node, } static GraphProcessorState handle_group_node(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { CyberiadaNode* current = node_stack_current_node(stack); @@ -1275,7 +1314,7 @@ static GraphProcessorState handle_group_node(xmlNode* xml_node, } static GraphProcessorState handle_comment_node(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { CyberiadaNode* current = node_stack_current_node(stack); @@ -1290,7 +1329,7 @@ static GraphProcessorState handle_comment_node(xmlNode* xml_node, } static GraphProcessorState handle_generic_node(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; @@ -1379,7 +1418,7 @@ static int cyberiada_xml_read_rect(xmlNode* xml_node, } static GraphProcessorState handle_node_geometry(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { CyberiadaNodeType type; @@ -1407,7 +1446,7 @@ static GraphProcessorState handle_node_geometry(xmlNode* xml_node, } static GraphProcessorState handle_property(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; @@ -1424,7 +1463,7 @@ static GraphProcessorState handle_property(xmlNode* xml_node, } static GraphProcessorState handle_node_title(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; @@ -1445,7 +1484,7 @@ static GraphProcessorState handle_node_title(xmlNode* xml_node, } static GraphProcessorState handle_node_action(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; @@ -1460,12 +1499,12 @@ static GraphProcessorState handle_node_action(xmlNode* xml_node, /* DEBUG("Set node %s comment text %s\n", current->id, buffer); */ cyberiada_copy_string(&(current->title), &(current->title_len), buffer); } else { - if (current->action != NULL) { - ERROR("Trying to set node %s action twice\n", current->id); + if (current->actions != NULL) { + ERROR("Trying to set node %s actions twice\n", current->id); return gpsInvalid; } /* DEBUG("Set node %s action %s\n", current->id, buffer); */ - if (cyberiada_decode_state_action(buffer, &(current->action)) != CYBERIADA_NO_ERROR) { + if (cyberiada_decode_state_actions(buffer, &(current->actions)) != CYBERIADA_NO_ERROR) { ERROR("cannot decode node action\n"); return gpsInvalid; } @@ -1474,7 +1513,7 @@ static GraphProcessorState handle_node_action(xmlNode* xml_node, } static GraphProcessorState handle_new_edge(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; @@ -1483,6 +1522,8 @@ static GraphProcessorState handle_new_edge(xmlNode* xml_node, size_t source_buffer_len = sizeof(source_buffer) - 1; char target_buffer[MAX_STR_LEN]; size_t target_buffer_len = sizeof(target_buffer) - 1; + CyberiadaSM* sm = doc->state_machines; + while (sm->next) sm = sm->next; if(cyberiada_get_attr_value(buffer, buffer_len, xml_node, GRAPHML_ID_ATTRIBUTE) != CYBERIADA_NO_ERROR) { @@ -1505,10 +1546,13 @@ static GraphProcessorState handle_new_edge(xmlNode* xml_node, } static GraphProcessorState handle_edge_geometry(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { - CyberiadaEdge *current = cyberiada_graph_find_last_edge(sm); + CyberiadaEdge *current; + CyberiadaSM* sm = doc->state_machines; + while (sm->next) sm = sm->next; + current = cyberiada_graph_find_last_edge(sm); if (current == NULL) { ERROR("no current edge\n"); return gpsInvalid; @@ -1533,12 +1577,15 @@ static GraphProcessorState handle_edge_geometry(xmlNode* xml_node, } static GraphProcessorState handle_edge_point(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { - CyberiadaEdge *current = cyberiada_graph_find_last_edge(sm); + CyberiadaEdge *current; CyberiadaPoint* p; CyberiadaPolyline *pl, *last_pl; + CyberiadaSM* sm = doc->state_machines; + while (sm->next) sm = sm->next; + current = cyberiada_graph_find_last_edge(sm); if (current == NULL) { ERROR("no current edge\n"); return gpsInvalid; @@ -1562,12 +1609,14 @@ static GraphProcessorState handle_edge_point(xmlNode* xml_node, } static GraphProcessorState handle_edge_label(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; size_t buffer_len = sizeof(buffer) - 1; CyberiadaEdge *current; + CyberiadaSM* sm = doc->state_machines; + while (sm->next) sm = sm->next; current = cyberiada_graph_find_last_edge(sm); if (current == NULL) { ERROR("no current edge\n"); @@ -1589,7 +1638,7 @@ static GraphProcessorState handle_edge_label(xmlNode* xml_node, } static GraphProcessorState handle_new_init_data(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; @@ -1601,9 +1650,9 @@ static GraphProcessorState handle_new_init_data(xmlNode* xml_node, cyberiada_get_element_text(buffer, buffer_len, xml_node); if (strcmp(buffer, CYBERIADA_FORMAT_CYBERIADAML) == 0) { - cyberiada_copy_string(&(sm->format), &(sm->format_len), + cyberiada_copy_string(&(doc->format), &(doc->format_len), CYBERIADA_FORMAT_CYBERIADAML); - /* DEBUG("sm format %s\n", sm->format); */ + /* DEBUG("doc format %s\n", doc->format); */ return gpsInit; } else { ERROR("Bad Cyberida-GraphML format: %s\n", buffer); @@ -1615,7 +1664,7 @@ static GraphProcessorState handle_new_init_data(xmlNode* xml_node, } static GraphProcessorState handle_new_init_key(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; @@ -1678,7 +1727,7 @@ static GraphProcessorState handle_new_init_key(xmlNode* xml_node, } static GraphProcessorState handle_node_data(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; @@ -1707,12 +1756,12 @@ static GraphProcessorState handle_node_data(xmlNode* xml_node, /* DEBUG("Set node %s title %s\n", current->id, buffer); */ cyberiada_copy_string(&(current->title), &(current->title_len), buffer); } else { - if (current->action != NULL) { + if (current->actions != NULL) { ERROR("Trying to set node %s action twice\n", current->id); return gpsInvalid; } /* DEBUG("Set node %s action %s\n", current->id, buffer); */ - if (cyberiada_decode_state_action(buffer, &(current->action)) != CYBERIADA_NO_ERROR) { + if (cyberiada_decode_state_actions(buffer, &(current->actions)) != CYBERIADA_NO_ERROR) { ERROR("cannot decode node action\n"); return gpsInvalid; } @@ -1732,7 +1781,7 @@ static GraphProcessorState handle_node_data(xmlNode* xml_node, } static GraphProcessorState handle_fake_node_data(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; @@ -1769,12 +1818,14 @@ static GraphProcessorState handle_fake_node_data(xmlNode* xml_node, } static GraphProcessorState handle_edge_data(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack) { char buffer[MAX_STR_LEN]; size_t buffer_len = sizeof(buffer) - 1; CyberiadaEdge *current; + CyberiadaSM* sm = doc->state_machines; + while (sm->next) sm = sm->next; current = cyberiada_graph_find_last_edge(sm); if (current == NULL) { ERROR("no current edge\n"); @@ -1808,7 +1859,7 @@ static GraphProcessorState handle_edge_data(xmlNode* xml_node, } typedef GraphProcessorState (*Handler)(xmlNode* xml_root, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack); typedef struct { @@ -1856,7 +1907,7 @@ static ProcessorTransition cyb_processor_state_table[] = { const size_t cyb_processor_state_table_size = sizeof(cyb_processor_state_table) / sizeof(ProcessorTransition); static int dispatch_processor(xmlNode* xml_node, - CyberiadaSM* sm, + CyberiadaDocument* doc, NodeStack** stack, GraphProcessorState* gps, ProcessorTransition* processor_state_table, @@ -1869,7 +1920,7 @@ static int dispatch_processor(xmlNode* xml_node, for (i = 0; i < processor_state_table_size; i++) { if (processor_state_table[i].state == *gps && strcmp(xml_element_name, processor_state_table[i].symbol) == 0) { - *gps = (*(processor_state_table[i].handler))(xml_node, sm, stack); + *gps = (*(processor_state_table[i].handler))(xml_node, doc, stack); return CYBERIADA_NO_ERROR; } } @@ -1877,12 +1928,12 @@ static int dispatch_processor(xmlNode* xml_node, return CYBERIADA_NOT_FOUND; } -static int cyberiada_build_graph(xmlNode* xml_root, - CyberiadaSM* sm, - NodeStack** stack, - GraphProcessorState* gps, - ProcessorTransition* processor_state_table, - size_t processor_state_table_size) +static int cyberiada_build_graphs(xmlNode* xml_root, + CyberiadaDocument* doc, + NodeStack** stack, + GraphProcessorState* gps, + ProcessorTransition* processor_state_table, + size_t processor_state_table_size) { xmlNode *cur_xml_node = NULL; /* NodeStack* s = *stack; */ @@ -1900,14 +1951,14 @@ static int cyberiada_build_graph(xmlNode* xml_root, sm->nodes ? sm->nodes->id : "none", debug_state_names[*gps]); */ node_stack_push(stack); - dispatch_processor(cur_xml_node, sm, stack, gps, + dispatch_processor(cur_xml_node, doc, stack, gps, processor_state_table, processor_state_table_size); if (*gps == gpsInvalid) { return CYBERIADA_FORMAT_ERROR; } if (cur_xml_node->children) { - int res = cyberiada_build_graph(cur_xml_node->children, sm, stack, gps, - processor_state_table, processor_state_table_size); + int res = cyberiada_build_graphs(cur_xml_node->children, doc, stack, gps, + processor_state_table, processor_state_table_size); if (res != CYBERIADA_NO_ERROR) { return res; } @@ -1917,7 +1968,7 @@ static int cyberiada_build_graph(xmlNode* xml_root, return CYBERIADA_NO_ERROR; } -static int cyberiada_decode_yed_xml(xmlNode* root, CyberiadaSM* sm) +static int cyberiada_decode_yed_xml(xmlNode* root, CyberiadaDocument* doc) { char buffer[MAX_STR_LEN]; size_t buffer_len = sizeof(buffer) - 1; @@ -1926,21 +1977,21 @@ static int cyberiada_decode_yed_xml(xmlNode* root, CyberiadaSM* sm) NodeStack* stack = NULL; char berloga_format = 0; int res; - + if (cyberiada_get_attr_value(buffer, buffer_len, root, GRAPHML_BERLOGA_SCHEMENAME_ATTR) == CYBERIADA_NO_ERROR) { - cyberiada_copy_string(&(sm->format), &(sm->format_len), CYBERIADA_FORMAT_BERLOGA); + cyberiada_copy_string(&(doc->format), &(doc->format_len), CYBERIADA_FORMAT_BERLOGA); berloga_format = 1; } else { - cyberiada_copy_string(&(sm->format), &(sm->format_len), CYBERIADA_FORMAT_OSTRANNA); + cyberiada_copy_string(&(doc->format), &(doc->format_len), CYBERIADA_FORMAT_OSTRANNA); berloga_format = 0; } - /* DEBUG("sm format %s\n", sm->format); */ + /* DEBUG("doc format %s\n", doc->format); */ - if ((res = cyberiada_build_graph(root, sm, &stack, &gps, - yed_processor_state_table, - yed_processor_state_table_size)) != CYBERIADA_NO_ERROR) { + if ((res = cyberiada_build_graphs(root, doc, &stack, &gps, + yed_processor_state_table, + yed_processor_state_table_size)) != CYBERIADA_NO_ERROR) { return res; } @@ -1950,30 +2001,30 @@ static int cyberiada_decode_yed_xml(xmlNode* root, CyberiadaSM* sm) } if (berloga_format) { - cyberiada_add_default_meta(sm, buffer); + cyberiada_add_default_meta(doc, buffer); } else { - if (sm->nodes) { - node = cyberiada_graph_find_node_by_type(sm->nodes, cybNodeCompositeState); + if (doc->state_machines->nodes) { + node = cyberiada_graph_find_node_by_type(doc->state_machines->nodes, cybNodeCompositeState); } if (node) { - cyberiada_add_default_meta(sm, node->title); + cyberiada_add_default_meta(doc, node->title); } else { - cyberiada_add_default_meta(sm, EMPTY_TITLE); + cyberiada_add_default_meta(doc, EMPTY_TITLE); } } return CYBERIADA_NO_ERROR; } -static int cyberiada_decode_cyberiada_xml(xmlNode* root, CyberiadaSM* sm) +static int cyberiada_decode_cyberiada_xml(xmlNode* root, CyberiadaDocument* doc) { GraphProcessorState gps = gpsInit; NodeStack* stack = NULL; int res; /* CyberiadaNode *meta_node, *ext_node; CyberiadaEdge *edge, *prev_edge;*/ - - if ((res = cyberiada_build_graph(root, sm, &stack, &gps, + + if ((res = cyberiada_build_graphs(root, doc, &stack, &gps, cyb_processor_state_table, cyb_processor_state_table_size)) != CYBERIADA_NO_ERROR) { return res; @@ -2060,13 +2111,13 @@ static int cyberiada_check_graphml_ns(xmlNode* root, CyberiadaXMLFormat* format) return CYBERIADA_NO_ERROR; } -int cyberiada_read_sm(CyberiadaSM* sm, const char* filename, CyberiadaXMLFormat format) +int cyberiada_read_sm_document(CyberiadaDocument* cyb_doc, const char* filename, CyberiadaXMLFormat format) { int res; xmlDoc* doc = NULL; xmlNode* root = NULL; - cyberiada_init_sm(sm); + cyberiada_init_sm_document(cyb_doc); /* parse the file and get the DOM */ if ((doc = xmlReadFile(filename, NULL, 0)) == NULL) { @@ -2093,11 +2144,13 @@ int cyberiada_read_sm(CyberiadaSM* sm, const char* filename, CyberiadaXMLFormat break; } + cyb_doc->state_machines = cyberiada_create_sm(); + /* DEBUG("reading format %d\n", format); */ if (format == cybxmlYED) { - res = cyberiada_decode_yed_xml(root, sm); + res = cyberiada_decode_yed_xml(root, cyb_doc); } else if (format == cybxmlCyberiada) { - res = cyberiada_decode_cyberiada_xml(root, sm); + res = cyberiada_decode_cyberiada_xml(root, cyb_doc); } else { ERROR("error: unsupported GraphML format of file %s\n", filename); @@ -2109,7 +2162,7 @@ int cyberiada_read_sm(CyberiadaSM* sm, const char* filename, CyberiadaXMLFormat break; } - if ((res = cyberiada_graph_reconstruct_edges(sm)) != CYBERIADA_NO_ERROR) { + if ((res = cyberiada_graphs_reconstruct_edges(cyb_doc)) != CYBERIADA_NO_ERROR) { ERROR("error: cannot reconstruct graph edges from file %s\n", filename); break; @@ -2199,7 +2252,7 @@ static int cyberiada_print_node(CyberiadaNode* node, int level) node->geometry_rect->height); } - cyberiada_print_action(node->action, level + 1); + cyberiada_print_action(node->actions, level + 1); printf("%sChildren:\n", levelspace); for (cur_node = node->children; cur_node; cur_node = cur_node->next) { @@ -2262,14 +2315,13 @@ static int cyberiada_print_edge(CyberiadaEdge* edge) return CYBERIADA_NO_ERROR; }*/ -int cyberiada_print_sm(CyberiadaSM* sm) +static int cyberiada_print_sm(CyberiadaSM* sm) { CyberiadaNode* cur_node; CyberiadaEdge* cur_edge; /*CyberiadaExtension* cur_ext;*/ - printf("\nState Machine [%s]\n", sm->format); - cyberiada_print_meta(sm->meta_info); + printf("State Machine\n"); printf("Nodes:\n"); for (cur_node = sm->nodes; cur_node; cur_node = cur_node->next) { @@ -2294,6 +2346,20 @@ int cyberiada_print_sm(CyberiadaSM* sm) return CYBERIADA_NO_ERROR; } +int cyberiada_print_sm_document(CyberiadaDocument* doc) +{ + CyberiadaSM* sm; + + printf("\nDocument:\n"); + cyberiada_print_meta(doc->meta_info); + + for (sm = doc->state_machines; sm; sm = sm->next) { + cyberiada_print_sm(sm); + } + + return CYBERIADA_NO_ERROR; +} + #define INDENT_STR " " #define XML_WRITE_OPEN_E(w, e) if ((res = xmlTextWriterStartElement(w, (const xmlChar *)e)) < 0) { \ fprintf(stderr, "xml open element error %d at %s:%d", res, __FILE__, __LINE__); \ @@ -2349,7 +2415,7 @@ typedef struct { const char* attr_yfiles; } GraphMLKey; -static int cyberiada_write_sm_cyberiada(CyberiadaSM* sm, xmlTextWriterPtr writer) +static int cyberiada_write_sm_document_cyberiada(CyberiadaDocument* doc, xmlTextWriterPtr writer) { return CYBERIADA_NO_ERROR; } @@ -2647,7 +2713,7 @@ static int cyberiada_write_node_yed(xmlTextWriterPtr writer, CyberiadaNode* node return CYBERIADA_XML_ERROR; } - if (cyberiada_write_node_action_yed(writer, node->action, indent + 3) != CYBERIADA_NO_ERROR) { + if (cyberiada_write_node_action_yed(writer, node->actions, indent + 3) != CYBERIADA_NO_ERROR) { ERROR("error while writing simple node action\n"); return CYBERIADA_XML_ERROR; } @@ -2688,7 +2754,7 @@ static int cyberiada_write_node_yed(xmlTextWriterPtr writer, CyberiadaNode* node return CYBERIADA_XML_ERROR; } - if (cyberiada_write_node_action_yed(writer, node->action, indent + 5) != CYBERIADA_NO_ERROR) { + if (cyberiada_write_node_action_yed(writer, node->actions, indent + 5) != CYBERIADA_NO_ERROR) { ERROR("error while writing composite node action\n"); return CYBERIADA_XML_ERROR; } @@ -2796,13 +2862,14 @@ static GraphMLKey yed_graphml_keys[] = { }; const size_t yed_graphml_keys_count = sizeof(yed_graphml_keys) / sizeof(GraphMLKey); -static int cyberiada_write_sm_yed(CyberiadaSM* sm, xmlTextWriterPtr writer) +static int cyberiada_write_sm_document_yed(CyberiadaDocument* doc, xmlTextWriterPtr writer) { size_t i; int res; GraphMLKey* key; CyberiadaNode* cur_node; CyberiadaEdge* cur_edge; + CyberiadaSM* sm = doc->state_machines; XML_WRITE_OPEN_E(writer, GRAPHML_GRAPHML_ELEMENT); @@ -2811,8 +2878,8 @@ static int cyberiada_write_sm_yed(CyberiadaSM* sm, xmlTextWriterPtr writer) XML_WRITE_ATTR(writer, yed_graphml_attributes[i], yed_graphml_attributes[i + 1]); } /* add scheme name if it is available */ - if (sm->meta_info && sm->meta_info->name && *sm->meta_info->name) { - XML_WRITE_ATTR(writer, GRAPHML_BERLOGA_SCHEMENAME_ATTR, sm->meta_info->name); + if (doc->meta_info && doc->meta_info->name && *doc->meta_info->name) { + XML_WRITE_ATTR(writer, GRAPHML_BERLOGA_SCHEMENAME_ATTR, doc->meta_info->name); } /* write graphml keys */ @@ -2865,7 +2932,7 @@ static int cyberiada_write_sm_yed(CyberiadaSM* sm, xmlTextWriterPtr writer) return CYBERIADA_NO_ERROR; } -int cyberiada_write_sm(CyberiadaSM* sm, const char* filename, CyberiadaXMLFormat format) +int cyberiada_write_sm_document(CyberiadaDocument* doc, const char* filename, CyberiadaXMLFormat format) { xmlTextWriterPtr writer; int res; @@ -2875,8 +2942,8 @@ int cyberiada_write_sm(CyberiadaSM* sm, const char* filename, CyberiadaXMLFormat return CYBERIADA_BAD_PARAMETER; } - if (!sm) { - ERROR("empty SM to write\n"); + if (!doc) { + ERROR("empty SM document to write\n"); return CYBERIADA_BAD_PARAMETER; } @@ -2894,9 +2961,14 @@ int cyberiada_write_sm(CyberiadaSM* sm, const char* filename, CyberiadaXMLFormat } if (format == cybxmlYED) { - res = cyberiada_write_sm_yed(sm, writer); + if (!doc->state_machines || doc->state_machines->next) { + ERROR("YED format supports only single SM documents\n"); + xmlFreeTextWriter(writer); + return CYBERIADA_BAD_PARAMETER; + } + res = cyberiada_write_sm_document_yed(doc, writer); } else if (format == cybxmlCyberiada) { - res = cyberiada_write_sm_cyberiada(sm, writer); + res = cyberiada_write_sm_document_cyberiada(doc, writer); } if (res != CYBERIADA_NO_ERROR) { ERROR("error writing xml %d\n", res); diff --git a/cyberiadaml.h b/cyberiadaml.h index f3b65a4..6895715 100644 --- a/cyberiadaml.h +++ b/cyberiadaml.h @@ -38,14 +38,10 @@ typedef enum { cybNodeCompositeState = 2, /* composite state */ cybNodeSubmachineState = 4, /* submachine state */ cybNodeComment = 8, /* comment node */ - cybNodeMachineComment = 16, /* machine-readable comment node */ + cybNodeMachineComment = 16, /* machine-readable comment node */ cybNodeInitial = 32, /* initial pseudostate */ - cybNodeFinal = 64, /* final pseudostate */ - cybNodeChoice = 128, /* final pseudostate */ - cybNodeEntry = 256, /* entry pseudostate */ - cybNodeExit = 512, /* exit pseudostate */ - cybNodeShallowHistory = 1024, /* shallow history pseudostate */ - cybNodeTerminate = 2048, /* terminate pseudostate */ + cybNodeFinal = 64, /* final state */ + cybNodeChoice = 128, /* choice pseudostate */ } CyberiadaNodeType; typedef unsigned int CyberiadaNodeTypeMask; @@ -53,7 +49,7 @@ typedef unsigned int CyberiadaNodeTypeMask; /* SM node types: */ typedef enum { cybEdgeTransition = 0, - cybEdgeComment = 1, + cybEdgeComment = 1, } CyberiadaEdgeType; /* SM action types: */ @@ -88,7 +84,7 @@ typedef struct _CyberiadaAction { size_t guard_len; char* behavior; size_t behavior_len; - struct _CyberiadaAction* next; + struct _CyberiadaAction* next; } CyberiadaAction; /* SM node (state) */ @@ -98,7 +94,7 @@ typedef struct _CyberiadaNode { size_t id_len; char* title; size_t title_len; - CyberiadaAction* action; + CyberiadaAction* actions; CyberiadaRect* geometry_rect; struct _CyberiadaNode* next; struct _CyberiadaNode* parent; @@ -126,48 +122,67 @@ typedef struct _CyberiadaEdge { struct _CyberiadaEdge* next; } CyberiadaEdge; -/* SM metainformation */ -typedef struct { - char* standard_version; /* HSM standard version (required parameter) */ - size_t standard_version_len; - char* platform_name; /* target platform name */ - size_t platform_name_len; - char* platform_version; /* target platform version */ - size_t platform_version_len; - char* platform_language; /* target platform language */ - size_t platform_language_len; - char* target_system; /* target system controlled by the SM */ - size_t target_system_len; - char* name; /* document name */ - size_t name_len; - char* author; /* document author */ - size_t author_len; - char* contact; /* document author's contact */ - size_t contact_len; - char* description; /* document description */ - size_t description_len; - char* version; /* document version */ - size_t version_len; - char* date; /* document date */ - size_t date_len; - char actions_order_flag; /* actions order flag (0 = not set, 1 = transition first, 2 = exit first) */ - char event_propagation_flag; /* event propagation flag (0 = not set, 1 = block events, 2 = propagate events) */ -} CyberiadaMetainformation; - /* SM graph (state machine) */ -typedef struct { - char* format; /* SM graph format string */ - size_t format_len; /* SM graph format string length */ - CyberiadaMetainformation* meta_info; +typedef struct _CyberiadaSM { CyberiadaNode* nodes; CyberiadaEdge* edges; + struct _CyberiadaSM* next; } CyberiadaSM; +/* SM metainformation */ +typedef struct { + /* HSM standard version (required parameter) */ + char* standard_version; + size_t standard_version_len; + /* target platform name */ + char* platform_name; + size_t platform_name_len; + /* target platform version */ + char* platform_version; + size_t platform_version_len; + /* target platform language */ + char* platform_language; + size_t platform_language_len; + /* target system controlled by the SM */ + char* target_system; + size_t target_system_len; + /* document name */ + char* name; + size_t name_len; + /* document author */ + char* author; + size_t author_len; + /* document author's contact */ + char* contact; + size_t contact_len; + /* document description */ + char* description; + size_t description_len; + /* document version */ + char* version; + size_t version_len; + /* document date */ + char* date; + size_t date_len; + /* actions order flag (0 = not set, 1 = transition first, 2 = exit first) */ + char actions_order_flag; + /* event propagation flag (0 = not set, 1 = block events, 2 = propagate events) */ + char event_propagation_flag; +} CyberiadaMetainformation; + +/* SM document */ +typedef struct { + char* format; /* SM document format string */ + size_t format_len; /* SM document format string length */ + CyberiadaMetainformation* meta_info; /* SM document metainformation */ + CyberiadaSM* state_machines; /* State machines */ +} CyberiadaDocument; + /* SM GraphML supported formats */ typedef enum { - cybxmlCyberiada = 0, - cybxmlYED, - cybxmlUnknown + cybxmlCyberiada = 0, + cybxmlYED = 1, + cybxmlUnknown = 2 } CyberiadaXMLFormat; /* ----------------------------------------------------------------------------- @@ -188,28 +203,28 @@ typedef enum { * ----------------------------------------------------------------------------- */ /* Allocate the SM structure in memory (for heap usage) */ - CyberiadaSM* cyberiada_create_sm(void); + CyberiadaDocument* cyberiada_create_sm_document(void); /* Initialize the SM structure */ /* Do not use the structure before the initialization! */ - int cyberiada_init_sm(CyberiadaSM* sm); + int cyberiada_init_sm_document(CyberiadaDocument* doc); /* Cleanup the content of the SM structure */ /* Free the allocated memory of the structure content but not the structure itself */ - int cyberiada_cleanup_sm(CyberiadaSM* sm); - + int cyberiada_cleanup_sm_document(CyberiadaDocument* doc); + /* Free the allocated SM structure with the content (for heap usage) */ - int cyberiada_destroy_sm(CyberiadaSM* sm); + int cyberiada_destroy_sm_document(CyberiadaDocument* doc); /* Read an XML file and decode the SM structure */ - /* Allocate the SM structure first */ - int cyberiada_read_sm(CyberiadaSM* sm, const char* filename, CyberiadaXMLFormat format); + /* Allocate the SM document structure first */ + int cyberiada_read_sm_document(CyberiadaDocument* doc, const char* filename, CyberiadaXMLFormat format); - /* Encode the SM structure and write the data to an XML file */ - int cyberiada_write_sm(CyberiadaSM* sm, const char* filename, CyberiadaXMLFormat format); + /* Encode the SM document structure and write the data to an XML file */ + int cyberiada_write_sm_document(CyberiadaDocument* doc, const char* filename, CyberiadaXMLFormat format); /* Print the SM structure to stdout */ - int cyberiada_print_sm(CyberiadaSM* sm); + int cyberiada_print_sm_document(CyberiadaDocument* doc); #ifdef __cplusplus } diff --git a/test.c b/test.c index 5bec0bb..130d1f5 100644 --- a/test.c +++ b/test.c @@ -71,7 +71,7 @@ int main(int argc, char** argv) CyberiadaXMLFormat source_format = cybxmlUnknown, dest_format = cybxmlUnknown; unsigned int i; int res; - CyberiadaSM sm; + CyberiadaDocument doc; char print = 0; if (argc < 3) { @@ -172,23 +172,23 @@ int main(int argc, char** argv) } } - if ((res = cyberiada_read_sm(&sm, source_filename, source_format)) != CYBERIADA_NO_ERROR) { + if ((res = cyberiada_read_sm_document(&doc, source_filename, source_format)) != CYBERIADA_NO_ERROR) { fprintf(stderr, "error while reading %s file: %d\n", source_filename, res); return 2; } if (print) { - cyberiada_print_sm(&sm); + cyberiada_print_sm_document(&doc); } else { - if ((res = cyberiada_write_sm(&sm, dest_filename, dest_format)) != CYBERIADA_NO_ERROR) { + if ((res = cyberiada_write_sm_document(&doc, dest_filename, dest_format)) != CYBERIADA_NO_ERROR) { fprintf(stderr, "error while writing %s file: %d\n", dest_filename, res); return 3; } } - cyberiada_cleanup_sm(&sm); + cyberiada_cleanup_sm_document(&doc); return 0; }