UML 2.0 / CyberiadaML standatd compliance
This commit is contained in:
2
Makefile
2
Makefile
@@ -8,7 +8,7 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
TEST_TARGET := cyberiada_test
|
TEST_TARGET := cyberiada_test
|
||||||
LIB_SOURCES := cyberiadaml.c
|
LIB_SOURCES := cyberiadaml.c utf8enc.c
|
||||||
TEST_SOURCES := test.c
|
TEST_SOURCES := test.c
|
||||||
LIB_OBJECTS := $(patsubst %.c, %.o, $(LIB_SOURCES))
|
LIB_OBJECTS := $(patsubst %.c, %.o, $(LIB_SOURCES))
|
||||||
TEST_OBJECTS := $(patsubst %.c, %.o, $(TEST_SOURCES))
|
TEST_OBJECTS := $(patsubst %.c, %.o, $(TEST_SOURCES))
|
||||||
|
|||||||
801
cyberiadaml.c
801
cyberiadaml.c
@@ -22,10 +22,13 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
#include "cyberiadaml.h"
|
#include "cyberiadaml.h"
|
||||||
|
#include "utf8enc.h"
|
||||||
|
|
||||||
#define GRAPHML_NAMESPACE_URI "http://graphml.graphdrawing.org/xmlns"
|
#define GRAPHML_NAMESPACE_URI "http://graphml.graphdrawing.org/xmlns"
|
||||||
#define GRAPHML_NAMESPACE_URI_YED "http://www.yworks.com/xml/graphml"
|
#define GRAPHML_NAMESPACE_URI_YED "http://www.yworks.com/xml/graphml"
|
||||||
@@ -99,8 +102,11 @@ static int cyberiada_copy_string(char** target, size_t* size, const char* source
|
|||||||
{
|
{
|
||||||
char* target_str;
|
char* target_str;
|
||||||
size_t strsize;
|
size_t strsize;
|
||||||
if (!source)
|
if (!source) {
|
||||||
return CYBERIADA_BAD_PARAMETER;
|
*target = NULL;
|
||||||
|
*size = 0;
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
strsize = strlen(source);
|
strsize = strlen(source);
|
||||||
if (strsize > MAX_STR_LEN - 1) {
|
if (strsize > MAX_STR_LEN - 1) {
|
||||||
strsize = MAX_STR_LEN - 1;
|
strsize = MAX_STR_LEN - 1;
|
||||||
@@ -139,18 +145,63 @@ static CyberiadaNode* cyberiada_new_node(const char* id)
|
|||||||
{
|
{
|
||||||
CyberiadaNode* new_node = (CyberiadaNode*)malloc(sizeof(CyberiadaNode));
|
CyberiadaNode* new_node = (CyberiadaNode*)malloc(sizeof(CyberiadaNode));
|
||||||
cyberiada_copy_string(&(new_node->id), &(new_node->id_len), id);
|
cyberiada_copy_string(&(new_node->id), &(new_node->id_len), id);
|
||||||
|
new_node->type = cybNodeSimpleState;
|
||||||
new_node->title = NULL;
|
new_node->title = NULL;
|
||||||
new_node->title_len = 0;
|
new_node->title_len = 0;
|
||||||
new_node->type = cybNodeSimple;
|
new_node->behavior = NULL;
|
||||||
new_node->next = NULL;
|
new_node->next = NULL;
|
||||||
new_node->parent = NULL;
|
new_node->parent = NULL;
|
||||||
new_node->children = NULL;
|
new_node->children = NULL;
|
||||||
new_node->action = NULL;
|
|
||||||
new_node->action_len = 0;
|
|
||||||
new_node->geometry_rect = NULL;
|
new_node->geometry_rect = NULL;
|
||||||
return new_node;
|
return new_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cyberiada_destroy_behavior(CyberiadaBehavior* behavior)
|
||||||
|
{
|
||||||
|
CyberiadaBehavior* b;
|
||||||
|
if (behavior != NULL) {
|
||||||
|
do {
|
||||||
|
b = behavior;
|
||||||
|
if (b->trigger) free(b->trigger);
|
||||||
|
if (b->guard) free(b->guard);
|
||||||
|
if (b->action) free(b->action);
|
||||||
|
behavior = b->next;
|
||||||
|
free(b);
|
||||||
|
} while (behavior);
|
||||||
|
}
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cyberiada_destroy_all_nodes(CyberiadaNode* node);
|
||||||
|
|
||||||
|
static int cyberiada_destroy_node(CyberiadaNode* node)
|
||||||
|
{
|
||||||
|
if(node != NULL) {
|
||||||
|
if(node->id) free(node->id);
|
||||||
|
if(node->title) free(node->title);
|
||||||
|
if(node->children) {
|
||||||
|
cyberiada_destroy_all_nodes(node->children);
|
||||||
|
}
|
||||||
|
if(node->behavior) cyberiada_destroy_behavior(node->behavior);
|
||||||
|
if(node->geometry_rect) free(node->geometry_rect);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cyberiada_destroy_all_nodes(CyberiadaNode* node)
|
||||||
|
{
|
||||||
|
CyberiadaNode* n;
|
||||||
|
if(node != NULL) {
|
||||||
|
do {
|
||||||
|
n = node;
|
||||||
|
node = node->next;
|
||||||
|
cyberiada_destroy_node(n);
|
||||||
|
} while (node);
|
||||||
|
}
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
static CyberiadaEdge* cyberiada_new_edge(const char* id, const char* source, const char* target)
|
static CyberiadaEdge* cyberiada_new_edge(const char* id, const char* source, const char* target)
|
||||||
{
|
{
|
||||||
CyberiadaEdge* new_edge = (CyberiadaEdge*)malloc(sizeof(CyberiadaEdge));
|
CyberiadaEdge* new_edge = (CyberiadaEdge*)malloc(sizeof(CyberiadaEdge));
|
||||||
@@ -160,7 +211,7 @@ static CyberiadaEdge* cyberiada_new_edge(const char* id, const char* source, con
|
|||||||
cyberiada_copy_string(&(new_edge->target_id), &(new_edge->target_id_len), target);
|
cyberiada_copy_string(&(new_edge->target_id), &(new_edge->target_id_len), target);
|
||||||
new_edge->source = NULL;
|
new_edge->source = NULL;
|
||||||
new_edge->target = NULL;
|
new_edge->target = NULL;
|
||||||
new_edge->action = NULL;
|
new_edge->behavior = NULL;
|
||||||
new_edge->next = NULL;
|
new_edge->next = NULL;
|
||||||
new_edge->geometry_source_point = NULL;
|
new_edge->geometry_source_point = NULL;
|
||||||
new_edge->geometry_target_point = NULL;
|
new_edge->geometry_target_point = NULL;
|
||||||
@@ -170,6 +221,323 @@ static CyberiadaEdge* cyberiada_new_edge(const char* id, const char* source, con
|
|||||||
return new_edge;
|
return new_edge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CyberiadaBehavior* cyberiada_new_behavior(CyberiadaBehaviorType type,
|
||||||
|
const char* trigger,
|
||||||
|
const char* guard,
|
||||||
|
const char* action)
|
||||||
|
{
|
||||||
|
CyberiadaBehavior* behavior = (CyberiadaBehavior*)malloc(sizeof(CyberiadaBehavior));
|
||||||
|
behavior->type = type;
|
||||||
|
cyberiada_copy_string(&(behavior->trigger), &(behavior->trigger_len), trigger);
|
||||||
|
cyberiada_copy_string(&(behavior->guard), &(behavior->guard_len), guard);
|
||||||
|
cyberiada_copy_string(&(behavior->action), &(behavior->action_len), action);
|
||||||
|
behavior->next = NULL;
|
||||||
|
return behavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BEHAVIOR_NEWLINE "\n\n"
|
||||||
|
#define BEHAVIOR_NEWLINE2 "\r\n\r\n"
|
||||||
|
#define BEHAVIOR_TRIGGER_ENTRY "entry"
|
||||||
|
#define BEHAVIOR_TRIGGER_EXIT "exit"
|
||||||
|
#define BEHAVIOR_TRIGGER_DO "do"
|
||||||
|
#define BEHAVIOR_EDGE_REGEXP "^\\s*(\\w((\\w| |\\.)*\\w)?(\\(\\w+\\))?)?\\s*(\\[([^]]+)\\])?\\s*(/\\s*(.*))?\\s*$"
|
||||||
|
#define BEHAVIOR_NODE_REGEXP "^\\s*(\\w((\\w| |\\.)*\\w)?(\\(\\w+\\))?)\\s*(\\[([^]]+)\\])?\\s*(/\\s*(.*)?)\\s*$"
|
||||||
|
#define BEHAVIOR_REGEXP_MATCHES 9
|
||||||
|
#define BEHAVIOR_REGEXP_MATCH_TRIGGER 1
|
||||||
|
#define BEHAVIOR_REGEXP_MATCH_GUARD 6
|
||||||
|
#define BEHAVIOR_REGEXP_MATCH_ACTION 8
|
||||||
|
#define BEHAVIOR_SPACES_REGEXP "^\\s*$"
|
||||||
|
/*#define BEHAVIOR_NEWLINE_REGEXP "^([^\n]*(\n[ \t\r]*[^\\s])?)*\n\\s*\n(.*)?$"
|
||||||
|
#define BEHAVIOR_NL_REGEXP_MATCHES 4*/
|
||||||
|
|
||||||
|
static regex_t cyberiada_edge_behavior_regexp;
|
||||||
|
static regex_t cyberiada_node_behavior_regexp;
|
||||||
|
/*static regex_t cyberiada_newline_regexp;*/
|
||||||
|
static regex_t cyberiada_spaces_regexp;
|
||||||
|
|
||||||
|
static int cyberiada_init_behavior_regexps(void)
|
||||||
|
{
|
||||||
|
if (regcomp(&cyberiada_edge_behavior_regexp, BEHAVIOR_EDGE_REGEXP, REG_EXTENDED)) {
|
||||||
|
ERROR("cannot compile edge behavior regexp\n");
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}
|
||||||
|
if (regcomp(&cyberiada_node_behavior_regexp, BEHAVIOR_NODE_REGEXP, REG_EXTENDED)) {
|
||||||
|
ERROR("cannot compile edge behavior regexp\n");
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}
|
||||||
|
/* if (regcomp(&cyberiada_newline_regexp, BEHAVIOR_NEWLINE_REGEXP, REG_EXTENDED)) {
|
||||||
|
ERROR("cannot compile new line regexp\n");
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}*/
|
||||||
|
if (regcomp(&cyberiada_spaces_regexp, BEHAVIOR_SPACES_REGEXP, REG_EXTENDED)) {
|
||||||
|
ERROR("cannot compile new line regexp\n");
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cyberiada_free_behavior_regexps(void)
|
||||||
|
{
|
||||||
|
regfree(&cyberiada_edge_behavior_regexp);
|
||||||
|
regfree(&cyberiada_node_behavior_regexp);
|
||||||
|
/* regfree(&cyberiada_newline_regexp);*/
|
||||||
|
regfree(&cyberiada_spaces_regexp);
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int cyberiaga_matchres_behavior_regexps(const char* text,
|
||||||
|
const regmatch_t* pmatch, size_t pmatch_size,
|
||||||
|
char** trigger, char** guard, char** action)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
char* part;
|
||||||
|
int start, end;
|
||||||
|
|
||||||
|
if (pmatch_size != BEHAVIOR_REGEXP_MATCHES) {
|
||||||
|
ERROR("bad behavior regexp match array size\n");
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < pmatch_size; i++) {
|
||||||
|
if (i != BEHAVIOR_REGEXP_MATCH_TRIGGER &&
|
||||||
|
i != BEHAVIOR_REGEXP_MATCH_GUARD &&
|
||||||
|
i != BEHAVIOR_REGEXP_MATCH_ACTION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
start = pmatch[i].rm_so;
|
||||||
|
end = pmatch[i].rm_eo;
|
||||||
|
if (end > start && text[start] != 0) {
|
||||||
|
part = (char*)malloc((size_t)(end - start + 1));
|
||||||
|
strncpy(part, &text[start], (size_t)(end - start));
|
||||||
|
part[(size_t)(end - start)] = 0;
|
||||||
|
} else {
|
||||||
|
part = "";
|
||||||
|
}
|
||||||
|
if (i == BEHAVIOR_REGEXP_MATCH_TRIGGER) {
|
||||||
|
*trigger = part;
|
||||||
|
} else if (i == BEHAVIOR_REGEXP_MATCH_GUARD) {
|
||||||
|
*guard = part;
|
||||||
|
} else {
|
||||||
|
/* i == BEHAVIOR_REGEXP_MATCH_ACTION */
|
||||||
|
*action = part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static int cyberiaga_matchres_newline(const regmatch_t* pmatch, size_t pmatch_size,
|
||||||
|
size_t* next_block)
|
||||||
|
{
|
||||||
|
if (pmatch_size != BEHAVIOR_NL_REGEXP_MATCHES) {
|
||||||
|
ERROR("bad new line regexp match array size\n");
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}
|
||||||
|
if (next_block) {
|
||||||
|
*next_block = (size_t)pmatch[pmatch_size - 1].rm_so;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
static int decode_utf8_strings(char** trigger, char** guard, char** action)
|
||||||
|
{
|
||||||
|
char* oldptr;
|
||||||
|
size_t len;
|
||||||
|
if (*trigger && **trigger) {
|
||||||
|
oldptr = *trigger;
|
||||||
|
*trigger = utf8_decode(*trigger, strlen(*trigger), &len);
|
||||||
|
free(oldptr);
|
||||||
|
}
|
||||||
|
if (*guard && **guard) {
|
||||||
|
oldptr = *guard;
|
||||||
|
*guard = utf8_decode(*guard, strlen(*guard), &len);
|
||||||
|
free(oldptr);
|
||||||
|
}
|
||||||
|
if (*action && **action) {
|
||||||
|
oldptr = *action;
|
||||||
|
*action = utf8_decode(*action, strlen(*action), &len);
|
||||||
|
free(oldptr);
|
||||||
|
}
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cyberiada_decode_edge_behavior(const char* text, CyberiadaBehavior** behavior)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
size_t buffer_len;
|
||||||
|
char *trigger = "", *guard = "", *action = "";
|
||||||
|
char *buffer;
|
||||||
|
regmatch_t pmatch[BEHAVIOR_REGEXP_MATCHES];
|
||||||
|
|
||||||
|
buffer = utf8_encode(text, strlen(text), &buffer_len);
|
||||||
|
|
||||||
|
if ((res = regexec(&cyberiada_edge_behavior_regexp, buffer,
|
||||||
|
BEHAVIOR_REGEXP_MATCHES, pmatch, 0)) != 0) {
|
||||||
|
if (res == REG_NOMATCH) {
|
||||||
|
ERROR("edge behavior text didn't match the regexp\n");
|
||||||
|
return CYBERIADA_BEHAVIOR_FORMAT_ERROR;
|
||||||
|
} else {
|
||||||
|
ERROR("edge behavior regexp error %d\n", res);
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cyberiaga_matchres_behavior_regexps(text,
|
||||||
|
pmatch, BEHAVIOR_REGEXP_MATCHES,
|
||||||
|
&trigger, &guard, &action) != CYBERIADA_NO_ERROR) {
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}
|
||||||
|
|
||||||
|
decode_utf8_strings(&trigger, &guard, &action);
|
||||||
|
|
||||||
|
/*DEBUG("\n");
|
||||||
|
DEBUG("edge behavior:\n");
|
||||||
|
DEBUG("trigger: %s\n", trigger);
|
||||||
|
DEBUG("guard: %s\n", guard);
|
||||||
|
DEBUG("action: %s\n", action);*/
|
||||||
|
|
||||||
|
*behavior = cyberiada_new_behavior(cybBehaviorTransition, trigger, guard, action);
|
||||||
|
|
||||||
|
if (*trigger) free(trigger);
|
||||||
|
if (*guard) free(guard);
|
||||||
|
if (*action) free(action);
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cyberiada_add_behavior(const char* trigger, const char* guard, const char* action,
|
||||||
|
CyberiadaBehavior** behavior)
|
||||||
|
{
|
||||||
|
CyberiadaBehavior* new_behavior;
|
||||||
|
CyberiadaBehaviorType type;
|
||||||
|
|
||||||
|
if (trigger) {
|
||||||
|
if (strcmp(trigger, BEHAVIOR_TRIGGER_ENTRY) == 0) {
|
||||||
|
type = cybBehaviorEntry;
|
||||||
|
} else if (strcmp(trigger, BEHAVIOR_TRIGGER_EXIT) == 0) {
|
||||||
|
type = cybBehaviorExit;
|
||||||
|
} else if (strcmp(trigger, BEHAVIOR_TRIGGER_DO) == 0) {
|
||||||
|
type = cybBehaviorDo;
|
||||||
|
} else {
|
||||||
|
type = cybBehaviorTransition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*DEBUG("\n");
|
||||||
|
DEBUG("node behavior:\n");
|
||||||
|
DEBUG("trigger: %s\n", trigger);
|
||||||
|
DEBUG("guard: %s\n", guard);
|
||||||
|
DEBUG("action: %s\n", action);
|
||||||
|
DEBUG("type: %d\n", type);*/
|
||||||
|
|
||||||
|
new_behavior = cyberiada_new_behavior(type, trigger, guard, action);
|
||||||
|
if (*behavior) {
|
||||||
|
CyberiadaBehavior* b = *behavior;
|
||||||
|
while (b->next) b = b->next;
|
||||||
|
b->next = new_behavior;
|
||||||
|
} else {
|
||||||
|
*behavior = new_behavior;
|
||||||
|
}
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cyberiada_decode_state_block_behavior(const char* text, CyberiadaBehavior** behavior)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
char *trigger = "", *guard = "", *action = "";
|
||||||
|
regmatch_t pmatch[BEHAVIOR_REGEXP_MATCHES];
|
||||||
|
if ((res = regexec(&cyberiada_node_behavior_regexp, text,
|
||||||
|
BEHAVIOR_REGEXP_MATCHES, pmatch, 0)) != 0) {
|
||||||
|
if (res == REG_NOMATCH) {
|
||||||
|
ERROR("node block behavior text didn't match the regexp\n");
|
||||||
|
return CYBERIADA_BEHAVIOR_FORMAT_ERROR;
|
||||||
|
} else {
|
||||||
|
ERROR("node block behavior regexp error %d\n", res);
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cyberiaga_matchres_behavior_regexps(text,
|
||||||
|
pmatch, BEHAVIOR_REGEXP_MATCHES,
|
||||||
|
&trigger, &guard, &action) != CYBERIADA_NO_ERROR) {
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}
|
||||||
|
|
||||||
|
decode_utf8_strings(&trigger, &guard, &action);
|
||||||
|
cyberiada_add_behavior(trigger, guard, action, behavior);
|
||||||
|
|
||||||
|
if (*trigger) free(trigger);
|
||||||
|
if (*guard) free(guard);
|
||||||
|
if (*action) free(action);
|
||||||
|
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cyberiada_decode_state_behavior(const char* text, CyberiadaBehavior** behavior)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
size_t buffer_len;
|
||||||
|
char *buffer, *start, *block, *block2, *next;
|
||||||
|
/* regmatch_t pmatch[BEHAVIOR_NL_REGEXP_MATCHES];*/
|
||||||
|
|
||||||
|
buffer = utf8_encode(text, strlen(text), &buffer_len);
|
||||||
|
next = buffer;
|
||||||
|
|
||||||
|
*behavior = NULL;
|
||||||
|
|
||||||
|
while (*next) {
|
||||||
|
start = next;
|
||||||
|
block = strstr(start, BEHAVIOR_NEWLINE);
|
||||||
|
block2 = strstr(start, BEHAVIOR_NEWLINE2);
|
||||||
|
if (block2 && ((block && (block > block2)) || !block)) {
|
||||||
|
block = block2;
|
||||||
|
*block2 = 0;
|
||||||
|
next = block2 + 4;
|
||||||
|
} else if (block) {
|
||||||
|
*block = 0;
|
||||||
|
next = block + 2;
|
||||||
|
} else {
|
||||||
|
block = start;
|
||||||
|
next = start + strlen(block);
|
||||||
|
}
|
||||||
|
/* if ((res = regexec(&cyberiada_newline_regexp, start,
|
||||||
|
BEHAVIOR_NL_REGEXP_MATCHES, pmatch, 0)) != 0) {
|
||||||
|
if (res != REG_NOMATCH) {
|
||||||
|
ERROR("newline regexp error %d\n", res);
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res == REG_NOMATCH) {
|
||||||
|
block = start;
|
||||||
|
start = start + strlen(block);
|
||||||
|
} else {
|
||||||
|
if (cyberiaga_matchres_newline(pmatch, BEHAVIOR_NL_REGEXP_MATCHES,
|
||||||
|
&next_block) != CYBERIADA_NO_ERROR) {
|
||||||
|
return CYBERIADA_ASSERT;
|
||||||
|
}
|
||||||
|
block = start;
|
||||||
|
start[next_block - 1] = 0;
|
||||||
|
start = start + next_block;
|
||||||
|
DEBUG("first part: '%s'\n", block);
|
||||||
|
DEBUG("second part: '%s'\n", start);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (regexec(&cyberiada_spaces_regexp, start, 0, NULL, 0) == 0) {
|
||||||
|
continue ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = cyberiada_decode_state_block_behavior(start, behavior)) != CYBERIADA_NO_ERROR) {
|
||||||
|
ERROR("error while decoding state block %s: %d\n", start, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/*static CyberiadaExtension* cyberiada_new_extension(const char* id, const char* title, const char* data)
|
/*static CyberiadaExtension* cyberiada_new_extension(const char* id, const char* title, const char* data)
|
||||||
{
|
{
|
||||||
CyberiadaExtension* new_ext = (CyberiadaExtension*)malloc(sizeof(CyberiadaExtension));
|
CyberiadaExtension* new_ext = (CyberiadaExtension*)malloc(sizeof(CyberiadaExtension));
|
||||||
@@ -210,131 +578,26 @@ static int cyberiada_graph_add_sibling_node(CyberiadaNode* sibling, CyberiadaNod
|
|||||||
return CYBERIADA_NO_ERROR;
|
return CYBERIADA_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cyberiada_graph_add_edge(CyberiadaSM* sm, const char* id, const char* source, const char* target)
|
/*static int cyberiada_graph_add_node_behavior(CyberiadaNode* node,
|
||||||
|
CyberiadaBehaviorType type,
|
||||||
|
const char* trigger,
|
||||||
|
const char* guard,
|
||||||
|
const char* action)
|
||||||
{
|
{
|
||||||
CyberiadaEdge* last_edge;
|
CyberiadaBehavior *behavior, *new_behavior;
|
||||||
CyberiadaEdge* new_edge;
|
if (!node) {
|
||||||
if (!sm) {
|
|
||||||
return CYBERIADA_BAD_PARAMETER;
|
return CYBERIADA_BAD_PARAMETER;
|
||||||
}
|
}
|
||||||
new_edge = cyberiada_new_edge(id, source, target);
|
new_behavior = cyberiada_new_behavior(type, trigger, guard, action);
|
||||||
last_edge = sm->edges;
|
if (node->behavior) {
|
||||||
if (last_edge == NULL) {
|
node->behavior = new_behavior;
|
||||||
sm->edges = new_edge;
|
|
||||||
} else {
|
} else {
|
||||||
while (last_edge->next) last_edge = last_edge->next;
|
behavior = node->behavior;
|
||||||
last_edge->next = new_edge;
|
while (behavior->next) behavior = behavior->next;
|
||||||
|
behavior->next = new_behavior;
|
||||||
}
|
}
|
||||||
return CYBERIADA_NO_ERROR;
|
return CYBERIADA_NO_ERROR;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
static CyberiadaEdge* cyberiada_graph_find_last_edge(CyberiadaSM* sm)
|
|
||||||
{
|
|
||||||
CyberiadaEdge* edge;
|
|
||||||
if (!sm) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
edge = sm->edges;
|
|
||||||
while (edge && edge->next) edge = edge->next;
|
|
||||||
return edge;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cyberiada_graph_reconstruct_edges(CyberiadaSM* sm)
|
|
||||||
{
|
|
||||||
CyberiadaEdge* edge = sm->edges;
|
|
||||||
while (edge) {
|
|
||||||
CyberiadaNode* source = cyberiada_graph_find_node(sm->nodes, edge->source_id);
|
|
||||||
CyberiadaNode* target = cyberiada_graph_find_node(sm->nodes, edge->target_id);
|
|
||||||
if (!source || !target) {
|
|
||||||
fprintf(stderr, "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;
|
|
||||||
}
|
|
||||||
return CYBERIADA_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
|
||||||
* The Cyberiada GraphML library fucntions declarations
|
|
||||||
* ----------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
CyberiadaSM* cyberiada_create_sm(void)
|
|
||||||
{
|
|
||||||
CyberiadaSM* sm = (CyberiadaSM*)malloc(sizeof(CyberiadaSM));
|
|
||||||
cyberiada_init_sm(sm);
|
|
||||||
return sm;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cyberiada_init_sm(CyberiadaSM* sm)
|
|
||||||
{
|
|
||||||
if (sm) {
|
|
||||||
sm->name = NULL;
|
|
||||||
sm->name = 0;
|
|
||||||
sm->version = NULL;
|
|
||||||
sm->version_len = 0;
|
|
||||||
sm->info = NULL;
|
|
||||||
sm->info_len = 0;
|
|
||||||
sm->nodes = NULL;
|
|
||||||
sm->edges = NULL;
|
|
||||||
/*sm->extensions = NULL;*/
|
|
||||||
}
|
|
||||||
return CYBERIADA_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cyberiada_destroy_all_nodes(CyberiadaNode* node);
|
|
||||||
|
|
||||||
static int cyberiada_destroy_node(CyberiadaNode* node)
|
|
||||||
{
|
|
||||||
if(node != NULL) {
|
|
||||||
if(node->id) free(node->id);
|
|
||||||
if(node->title) free(node->title);
|
|
||||||
if(node->children) {
|
|
||||||
cyberiada_destroy_all_nodes(node->children);
|
|
||||||
}
|
|
||||||
if(node->action) free(node->action);
|
|
||||||
if(node->geometry_rect) free(node->geometry_rect);
|
|
||||||
free(node);
|
|
||||||
}
|
|
||||||
return CYBERIADA_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cyberiada_destroy_all_nodes(CyberiadaNode* node)
|
|
||||||
{
|
|
||||||
CyberiadaNode* n;
|
|
||||||
if(node != NULL) {
|
|
||||||
do {
|
|
||||||
n = node;
|
|
||||||
node = node->next;
|
|
||||||
cyberiada_destroy_node(n);
|
|
||||||
} while (node);
|
|
||||||
}
|
|
||||||
return CYBERIADA_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cyberiada_destroy_edge(CyberiadaEdge* e)
|
|
||||||
{
|
|
||||||
CyberiadaPolyline *polyline, *pl;
|
|
||||||
if (e->id) free(e->id);
|
|
||||||
if (e->source_id) free(e->source_id);
|
|
||||||
if (e->target_id) free(e->target_id);
|
|
||||||
if (e->action) free(e->action);
|
|
||||||
if (e->geometry_source_point) free(e->geometry_source_point);
|
|
||||||
if (e->geometry_target_point) free(e->geometry_target_point);
|
|
||||||
if (e->geometry_polyline) {
|
|
||||||
polyline = e->geometry_polyline;
|
|
||||||
do {
|
|
||||||
pl = polyline;
|
|
||||||
polyline = polyline->next;
|
|
||||||
free(pl);
|
|
||||||
} while (polyline);
|
|
||||||
}
|
|
||||||
if (e->geometry_label) free(e->geometry_label);
|
|
||||||
if (e->color) free(e->color);
|
|
||||||
free(e);
|
|
||||||
return CYBERIADA_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*static int cyberiada_find_and_remove_node(CyberiadaNode* current, CyberiadaNode* target)
|
/*static int cyberiada_find_and_remove_node(CyberiadaNode* current, CyberiadaNode* target)
|
||||||
{
|
{
|
||||||
@@ -381,6 +644,125 @@ static int cyberiada_remove_node(CyberiadaSM* sm, CyberiadaNode* node)
|
|||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
static int cyberiada_graph_add_edge(CyberiadaSM* sm, const char* id, const char* source, const char* target)
|
||||||
|
{
|
||||||
|
CyberiadaEdge* last_edge;
|
||||||
|
CyberiadaEdge* new_edge;
|
||||||
|
if (!sm) {
|
||||||
|
return CYBERIADA_BAD_PARAMETER;
|
||||||
|
}
|
||||||
|
new_edge = cyberiada_new_edge(id, source, target);
|
||||||
|
last_edge = sm->edges;
|
||||||
|
if (last_edge == NULL) {
|
||||||
|
sm->edges = new_edge;
|
||||||
|
} else {
|
||||||
|
while (last_edge->next) last_edge = last_edge->next;
|
||||||
|
last_edge->next = new_edge;
|
||||||
|
}
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CyberiadaEdge* cyberiada_graph_find_last_edge(CyberiadaSM* sm)
|
||||||
|
{
|
||||||
|
CyberiadaEdge* edge;
|
||||||
|
if (!sm) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
edge = sm->edges;
|
||||||
|
while (edge && edge->next) edge = edge->next;
|
||||||
|
return edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static int cyberiada_graph_add_edge_behavior(CyberiadaEdge* edge,
|
||||||
|
CyberiadaBehaviorType type,
|
||||||
|
const char* trigger,
|
||||||
|
const char* guard,
|
||||||
|
const char* action)
|
||||||
|
{
|
||||||
|
CyberiadaBehavior *behavior, *new_behavior;
|
||||||
|
if (!edge) {
|
||||||
|
return CYBERIADA_BAD_PARAMETER;
|
||||||
|
}
|
||||||
|
new_behavior = cyberiada_new_behavior(type, trigger, guard, action);
|
||||||
|
if (edge->behavior) {
|
||||||
|
edge->behavior = new_behavior;
|
||||||
|
} else {
|
||||||
|
behavior = edge->behavior;
|
||||||
|
while (behavior->next) behavior = behavior->next;
|
||||||
|
behavior->next = new_behavior;
|
||||||
|
}
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
static int cyberiada_destroy_edge(CyberiadaEdge* e)
|
||||||
|
{
|
||||||
|
CyberiadaPolyline *polyline, *pl;
|
||||||
|
if (e->id) free(e->id);
|
||||||
|
if (e->source_id) free(e->source_id);
|
||||||
|
if (e->target_id) free(e->target_id);
|
||||||
|
if (e->behavior) cyberiada_destroy_behavior(e->behavior);
|
||||||
|
if (e->geometry_source_point) free(e->geometry_source_point);
|
||||||
|
if (e->geometry_target_point) free(e->geometry_target_point);
|
||||||
|
if (e->geometry_polyline) {
|
||||||
|
polyline = e->geometry_polyline;
|
||||||
|
do {
|
||||||
|
pl = polyline;
|
||||||
|
polyline = polyline->next;
|
||||||
|
free(pl);
|
||||||
|
} while (polyline);
|
||||||
|
}
|
||||||
|
if (e->geometry_label) free(e->geometry_label);
|
||||||
|
if (e->color) free(e->color);
|
||||||
|
free(e);
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int cyberiada_graph_reconstruct_edges(CyberiadaSM* sm)
|
||||||
|
{
|
||||||
|
CyberiadaEdge* edge = sm->edges;
|
||||||
|
while (edge) {
|
||||||
|
CyberiadaNode* source = cyberiada_graph_find_node(sm->nodes, edge->source_id);
|
||||||
|
CyberiadaNode* target = cyberiada_graph_find_node(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;
|
||||||
|
}
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* The Cyberiada GraphML library fucntions declarations
|
||||||
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
CyberiadaSM* cyberiada_create_sm(void)
|
||||||
|
{
|
||||||
|
CyberiadaSM* sm = (CyberiadaSM*)malloc(sizeof(CyberiadaSM));
|
||||||
|
cyberiada_init_sm(sm);
|
||||||
|
return sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cyberiada_init_sm(CyberiadaSM* sm)
|
||||||
|
{
|
||||||
|
if (sm) {
|
||||||
|
sm->name = NULL;
|
||||||
|
sm->name = 0;
|
||||||
|
sm->version = NULL;
|
||||||
|
sm->version_len = 0;
|
||||||
|
sm->info = NULL;
|
||||||
|
sm->info_len = 0;
|
||||||
|
sm->nodes = NULL;
|
||||||
|
sm->edges = NULL;
|
||||||
|
/*sm->extensions = NULL;*/
|
||||||
|
}
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
int cyberiada_cleanup_sm(CyberiadaSM* sm)
|
int cyberiada_cleanup_sm(CyberiadaSM* sm)
|
||||||
{
|
{
|
||||||
CyberiadaEdge *edge, *e;
|
CyberiadaEdge *edge, *e;
|
||||||
@@ -431,33 +813,6 @@ int cyberiada_destroy_sm(CyberiadaSM* sm)
|
|||||||
return CYBERIADA_NO_ERROR;
|
return CYBERIADA_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cyberiada_get_attr_value(char* buffer, size_t buffer_len,
|
|
||||||
xmlNode* node, const char* attrname)
|
|
||||||
{
|
|
||||||
xmlAttr* attribute = node->properties;
|
|
||||||
while(attribute) {
|
|
||||||
if (strcmp((const char*)attribute->name, attrname) == 0) {
|
|
||||||
xmlChar* value = xmlNodeListGetString(node->doc, attribute->children, 1);
|
|
||||||
strncpy(buffer, (char*)value, buffer_len);
|
|
||||||
xmlFree(value);
|
|
||||||
return CYBERIADA_NO_ERROR;
|
|
||||||
}
|
|
||||||
attribute = attribute->next;
|
|
||||||
}
|
|
||||||
return CYBERIADA_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cyberiada_get_element_text(char* buffer, size_t buffer_len,
|
|
||||||
xmlNode* node)
|
|
||||||
{
|
|
||||||
xmlChar* value = xmlNodeListGetString(node->doc,
|
|
||||||
node->xmlChildrenNode,
|
|
||||||
1);
|
|
||||||
strncpy(buffer, (char*)value, buffer_len);
|
|
||||||
xmlFree(value);
|
|
||||||
return CYBERIADA_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
* The Cyberiada GraphML XML processor state machine
|
* The Cyberiada GraphML XML processor state machine
|
||||||
* ----------------------------------------------------------------------------- */
|
* ----------------------------------------------------------------------------- */
|
||||||
@@ -569,10 +924,37 @@ static int node_stack_pop(NodeStack** stack, CyberiadaNode** node, const char**
|
|||||||
return CYBERIADA_NO_ERROR;
|
return CYBERIADA_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static int node_stack_empty(NodeStack** stack) */
|
static int node_stack_empty(NodeStack* stack)
|
||||||
/* { */
|
{
|
||||||
/* return *stack == NULL; */
|
return stack == NULL;
|
||||||
/* } */
|
}
|
||||||
|
|
||||||
|
static int cyberiada_get_attr_value(char* buffer, size_t buffer_len,
|
||||||
|
xmlNode* node, const char* attrname)
|
||||||
|
{
|
||||||
|
xmlAttr* attribute = node->properties;
|
||||||
|
while(attribute) {
|
||||||
|
if (strcmp((const char*)attribute->name, attrname) == 0) {
|
||||||
|
xmlChar* value = xmlNodeListGetString(node->doc, attribute->children, 1);
|
||||||
|
strncpy(buffer, (char*)value, buffer_len);
|
||||||
|
xmlFree(value);
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
attribute = attribute->next;
|
||||||
|
}
|
||||||
|
return CYBERIADA_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cyberiada_get_element_text(char* buffer, size_t buffer_len,
|
||||||
|
xmlNode* node)
|
||||||
|
{
|
||||||
|
xmlChar* value = xmlNodeListGetString(node->doc,
|
||||||
|
node->xmlChildrenNode,
|
||||||
|
1);
|
||||||
|
strncpy(buffer, (char*)value, buffer_len);
|
||||||
|
xmlFree(value);
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
static GraphProcessorState handle_new_graph(xmlNode* xml_node,
|
static GraphProcessorState handle_new_graph(xmlNode* xml_node,
|
||||||
CyberiadaSM* sm,
|
CyberiadaSM* sm,
|
||||||
@@ -621,7 +1003,6 @@ static GraphProcessorState handle_new_node(xmlNode* xml_node,
|
|||||||
} else {
|
} else {
|
||||||
cyberiada_graph_add_sibling_node(parent->children, node);
|
cyberiada_graph_add_sibling_node(parent->children, node);
|
||||||
}
|
}
|
||||||
DEBUG("sm version %s\n", sm->version);
|
|
||||||
|
|
||||||
if (*(node->id) != 0 || sm->version) {
|
if (*(node->id) != 0 || sm->version) {
|
||||||
return gpsNode;
|
return gpsNode;
|
||||||
@@ -639,7 +1020,7 @@ static GraphProcessorState handle_group_node(xmlNode* xml_node,
|
|||||||
ERROR("current node invalid\n");
|
ERROR("current node invalid\n");
|
||||||
return gpsInvalid;
|
return gpsInvalid;
|
||||||
}
|
}
|
||||||
current->type = cybNodeComposite;
|
current->type = cybNodeCompositeState;
|
||||||
return gpsNodeGeometry;
|
return gpsNodeGeometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -653,7 +1034,8 @@ static GraphProcessorState handle_comment_node(xmlNode* xml_node,
|
|||||||
return gpsInvalid;
|
return gpsInvalid;
|
||||||
}
|
}
|
||||||
current->type = cybNodeComment;
|
current->type = cybNodeComment;
|
||||||
cyberiada_copy_string(&(current->title), &(current->title_len), COMMENT_TITLE);
|
DEBUG("Set node type comment\n");
|
||||||
|
/*cyberiada_copy_string(&(current->title), &(current->title_len), COMMENT_TITLE);*/
|
||||||
return gpsNodeGeometry;
|
return gpsNodeGeometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,7 +1062,7 @@ static GraphProcessorState handle_generic_node(xmlNode* xml_node,
|
|||||||
}
|
}
|
||||||
cyberiada_copy_string(&(current->title), &(current->title_len), "");
|
cyberiada_copy_string(&(current->title), &(current->title_len), "");
|
||||||
} else {
|
} else {
|
||||||
current->type = cybNodeSimple;
|
current->type = cybNodeSimpleState;
|
||||||
}
|
}
|
||||||
return gpsNodeGeometry;
|
return gpsNodeGeometry;
|
||||||
}
|
}
|
||||||
@@ -812,7 +1194,7 @@ static GraphProcessorState handle_node_title(xmlNode* xml_node,
|
|||||||
return gpsNodeAction;
|
return gpsNodeAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GraphProcessorState handle_node_action(xmlNode* xml_node,
|
static GraphProcessorState handle_node_behavior(xmlNode* xml_node,
|
||||||
CyberiadaSM* sm,
|
CyberiadaSM* sm,
|
||||||
NodeStack** stack)
|
NodeStack** stack)
|
||||||
{
|
{
|
||||||
@@ -823,13 +1205,21 @@ static GraphProcessorState handle_node_action(xmlNode* xml_node,
|
|||||||
ERROR("current node invalid\n");
|
ERROR("current node invalid\n");
|
||||||
return gpsInvalid;
|
return gpsInvalid;
|
||||||
}
|
}
|
||||||
if (current->action != NULL) {
|
cyberiada_get_element_text(buffer, buffer_len, xml_node);
|
||||||
ERROR("Trying to set node %s action twice\n", current->id);
|
if (current->type == cybNodeComment) {
|
||||||
|
DEBUG("Set node %s comment text %s\n", current->id, buffer);
|
||||||
|
cyberiada_copy_string(&(current->title), &(current->title_len), buffer);
|
||||||
|
} else {
|
||||||
|
if (current->behavior != NULL) {
|
||||||
|
ERROR("Trying to set node %s behavior twice\n", current->id);
|
||||||
return gpsInvalid;
|
return gpsInvalid;
|
||||||
}
|
}
|
||||||
cyberiada_get_element_text(buffer, buffer_len, xml_node);
|
DEBUG("Set node %s behavior %s\n", current->id, buffer);
|
||||||
DEBUG("Set node %s action %s\n", current->id, buffer);
|
if (cyberiada_decode_state_behavior(buffer, &(current->behavior)) != CYBERIADA_NO_ERROR) {
|
||||||
cyberiada_copy_string(&(current->action), &(current->action_len), buffer);
|
ERROR("cannot decode node behavior\n");
|
||||||
|
return gpsInvalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
return gpsGraph;
|
return gpsGraph;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -933,15 +1323,18 @@ static GraphProcessorState handle_edge_label(xmlNode* xml_node,
|
|||||||
ERROR("no current edge\n");
|
ERROR("no current edge\n");
|
||||||
return gpsInvalid;
|
return gpsInvalid;
|
||||||
}
|
}
|
||||||
if (current->action != NULL) {
|
if (current->behavior != NULL) {
|
||||||
ERROR("Trying to set edge %s:%s label twice\n",
|
ERROR("Trying to set edge %s:%s label twice\n",
|
||||||
current->source_id, current->target_id);
|
current->source_id, current->target_id);
|
||||||
return gpsInvalid;
|
return gpsInvalid;
|
||||||
}
|
}
|
||||||
cyberiada_get_element_text(buffer, buffer_len, xml_node);
|
cyberiada_get_element_text(buffer, buffer_len, xml_node);
|
||||||
DEBUG("add edge %s:%s action %s\n",
|
DEBUG("add edge %s:%s behavior %s\n",
|
||||||
current->source_id, current->target_id, buffer);
|
current->source_id, current->target_id, buffer);
|
||||||
cyberiada_copy_string(&(current->action), &(current->action_len), buffer);
|
if (cyberiada_decode_edge_behavior(buffer, &(current->behavior)) != CYBERIADA_NO_ERROR) {
|
||||||
|
ERROR("cannot decode edge behavior\n");
|
||||||
|
return gpsInvalid;
|
||||||
|
}
|
||||||
return gpsGraph;
|
return gpsGraph;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -960,6 +1353,7 @@ static GraphProcessorState handle_new_init_data(xmlNode* xml_node,
|
|||||||
if (strcmp(buffer, CYBERIADA_VERSION_CYBERIADAML) == 0) {
|
if (strcmp(buffer, CYBERIADA_VERSION_CYBERIADAML) == 0) {
|
||||||
cyberiada_copy_string(&(sm->version), &(sm->version_len),
|
cyberiada_copy_string(&(sm->version), &(sm->version_len),
|
||||||
CYBERIADA_VERSION_CYBERIADAML);
|
CYBERIADA_VERSION_CYBERIADAML);
|
||||||
|
DEBUG("sm version %s\n", sm->version);
|
||||||
return gpsInit;
|
return gpsInit;
|
||||||
} else {
|
} else {
|
||||||
ERROR("Bad Cyberida-GraphML version: %s\n", buffer);
|
ERROR("Bad Cyberida-GraphML version: %s\n", buffer);
|
||||||
@@ -1063,12 +1457,15 @@ static GraphProcessorState handle_node_data(xmlNode* xml_node,
|
|||||||
DEBUG("Set node %s title %s\n", current->id, buffer);
|
DEBUG("Set node %s title %s\n", current->id, buffer);
|
||||||
cyberiada_copy_string(&(current->title), &(current->title_len), buffer);
|
cyberiada_copy_string(&(current->title), &(current->title_len), buffer);
|
||||||
} else {
|
} else {
|
||||||
if (current->action != NULL) {
|
if (current->behavior != NULL) {
|
||||||
ERROR("Trying to set node %s action twice\n", current->id);
|
ERROR("Trying to set node %s behavior twice\n", current->id);
|
||||||
|
return gpsInvalid;
|
||||||
|
}
|
||||||
|
DEBUG("Set node %s behavior %s\n", current->id, buffer);
|
||||||
|
if (cyberiada_decode_state_behavior(buffer, &(current->behavior)) != CYBERIADA_NO_ERROR) {
|
||||||
|
ERROR("cannot decode node behavior\n");
|
||||||
return gpsInvalid;
|
return gpsInvalid;
|
||||||
}
|
}
|
||||||
DEBUG("Set node %s action %s\n", current->id, buffer);
|
|
||||||
cyberiada_copy_string(&(current->action), &(current->action_len), buffer);
|
|
||||||
}
|
}
|
||||||
} else if (strcmp(buffer, GRAPHML_CYB_DATA_INITIAL) == 0) {
|
} else if (strcmp(buffer, GRAPHML_CYB_DATA_INITIAL) == 0) {
|
||||||
current->type = cybNodeInitial;
|
current->type = cybNodeInitial;
|
||||||
@@ -1140,8 +1537,11 @@ static GraphProcessorState handle_edge_data(xmlNode* xml_node,
|
|||||||
}
|
}
|
||||||
if (strcmp(buffer, GRAPHML_CYB_DATA_DATA) == 0) {
|
if (strcmp(buffer, GRAPHML_CYB_DATA_DATA) == 0) {
|
||||||
cyberiada_get_element_text(buffer, buffer_len, xml_node);
|
cyberiada_get_element_text(buffer, buffer_len, xml_node);
|
||||||
DEBUG("Set edge %s action %s\n", current->id, buffer);
|
DEBUG("Set edge %s behavior %s\n", current->id, buffer);
|
||||||
cyberiada_copy_string(&(current->action), &(current->action_len), buffer);
|
if (cyberiada_decode_edge_behavior(buffer, &(current->behavior)) != CYBERIADA_NO_ERROR) {
|
||||||
|
ERROR("cannot decode edge behavior\n");
|
||||||
|
return gpsInvalid;
|
||||||
|
}
|
||||||
} else if (strcmp(buffer, GRAPHML_CYB_DATA_GEOMETRY) == 0) {
|
} else if (strcmp(buffer, GRAPHML_CYB_DATA_GEOMETRY) == 0) {
|
||||||
if (cyberiada_xml_read_point(xml_node,
|
if (cyberiada_xml_read_point(xml_node,
|
||||||
&(current->geometry_label)) != CYBERIADA_NO_ERROR) {
|
&(current->geometry_label)) != CYBERIADA_NO_ERROR) {
|
||||||
@@ -1179,7 +1579,8 @@ static ProcessorTransition yed_processor_state_table[] = {
|
|||||||
{gpsNodeStart, GRAPHML_YED_PROPNODE, &handle_property},
|
{gpsNodeStart, GRAPHML_YED_PROPNODE, &handle_property},
|
||||||
{gpsNodeStart, GRAPHML_NODE_ELEMENT, &handle_new_node},
|
{gpsNodeStart, GRAPHML_NODE_ELEMENT, &handle_new_node},
|
||||||
{gpsNodeTitle, GRAPHML_YED_LABELNODE, &handle_node_title},
|
{gpsNodeTitle, GRAPHML_YED_LABELNODE, &handle_node_title},
|
||||||
{gpsNodeAction, GRAPHML_YED_LABELNODE, &handle_node_action},
|
{gpsNodeAction, GRAPHML_YED_LABELNODE, &handle_node_behavior},
|
||||||
|
{gpsNodeAction, GRAPHML_NODE_ELEMENT, &handle_new_node},
|
||||||
{gpsEdge, GRAPHML_EDGE_ELEMENT, &handle_new_edge},
|
{gpsEdge, GRAPHML_EDGE_ELEMENT, &handle_new_edge},
|
||||||
{gpsEdge, GRAPHML_YED_PATHNODE, &handle_edge_geometry},
|
{gpsEdge, GRAPHML_YED_PATHNODE, &handle_edge_geometry},
|
||||||
{gpsEdgePath, GRAPHML_YED_POINTNODE, &handle_edge_point},
|
{gpsEdgePath, GRAPHML_YED_POINTNODE, &handle_edge_point},
|
||||||
@@ -1280,6 +1681,7 @@ static int cyberiada_decode_yed_xml(xmlNode* root, CyberiadaSM* sm)
|
|||||||
cyberiada_copy_string(&(sm->name), &(sm->name_len), buffer);
|
cyberiada_copy_string(&(sm->name), &(sm->name_len), buffer);
|
||||||
}
|
}
|
||||||
cyberiada_copy_string(&(sm->version), &(sm->version_len), CYBERIADA_VERSION_BERLOGA);
|
cyberiada_copy_string(&(sm->version), &(sm->version_len), CYBERIADA_VERSION_BERLOGA);
|
||||||
|
DEBUG("sm version %s\n", sm->version);
|
||||||
|
|
||||||
if ((res = cyberiada_build_graph(root, sm, &stack, &gps,
|
if ((res = cyberiada_build_graph(root, sm, &stack, &gps,
|
||||||
yed_processor_state_table,
|
yed_processor_state_table,
|
||||||
@@ -1287,8 +1689,8 @@ static int cyberiada_decode_yed_xml(xmlNode* root, CyberiadaSM* sm)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack != NULL) {
|
if (!node_stack_empty(stack)) {
|
||||||
fprintf(stderr, "error with node stack\n");
|
ERROR("error with node stack\n");
|
||||||
return CYBERIADA_FORMAT_ERROR;
|
return CYBERIADA_FORMAT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1319,7 +1721,7 @@ static int cyberiada_decode_cyberiada_xml(xmlNode* root, CyberiadaSM* sm)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack != NULL) {
|
if (!node_stack_empty(stack)) {
|
||||||
ERROR("error with node stack\n");
|
ERROR("error with node stack\n");
|
||||||
return CYBERIADA_FORMAT_ERROR;
|
return CYBERIADA_FORMAT_ERROR;
|
||||||
}
|
}
|
||||||
@@ -1414,6 +1816,8 @@ int cyberiada_read_sm(CyberiadaSM* sm, const char* filename, CyberiadaXMLFormat
|
|||||||
return CYBERIADA_XML_ERROR;
|
return CYBERIADA_XML_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cyberiada_init_behavior_regexps();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* get the root element node */
|
/* get the root element node */
|
||||||
root = xmlDocGetRootElement(doc);
|
root = xmlDocGetRootElement(doc);
|
||||||
@@ -1454,12 +1858,41 @@ int cyberiada_read_sm(CyberiadaSM* sm, const char* filename, CyberiadaXMLFormat
|
|||||||
}
|
}
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
|
cyberiada_free_behavior_regexps();
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
xmlCleanupParser();
|
xmlCleanupParser();
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cyberiada_print_behavior(CyberiadaBehavior* behavior, int level)
|
||||||
|
{
|
||||||
|
char levelspace[16];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(levelspace, 0, sizeof(levelspace));
|
||||||
|
for(i = 0; i < level; i++) {
|
||||||
|
if (i == 14) break;
|
||||||
|
levelspace[i] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%sBehaviors:\n", levelspace);
|
||||||
|
while (behavior) {
|
||||||
|
printf("%s Behavior (type %d):\n", levelspace, behavior->type);
|
||||||
|
if(behavior->trigger) {
|
||||||
|
printf("%s Trigger: \"%s\"\n", levelspace, behavior->trigger);
|
||||||
|
}
|
||||||
|
if(behavior->guard) {
|
||||||
|
printf("%s Guard: \"%s\"\n", levelspace, behavior->guard);
|
||||||
|
}
|
||||||
|
if(behavior->action) {
|
||||||
|
printf("%s Action: \"%s\"\n", levelspace, behavior->action);
|
||||||
|
}
|
||||||
|
behavior = behavior->next;
|
||||||
|
}
|
||||||
|
return CYBERIADA_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
static int cyberiada_print_node(CyberiadaNode* node, int level)
|
static int cyberiada_print_node(CyberiadaNode* node, int level)
|
||||||
{
|
{
|
||||||
CyberiadaNode* cur_node;
|
CyberiadaNode* cur_node;
|
||||||
@@ -1484,10 +1917,7 @@ static int cyberiada_print_node(CyberiadaNode* node, int level)
|
|||||||
node->geometry_rect->height);
|
node->geometry_rect->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%sActions:\n", levelspace);
|
cyberiada_print_behavior(node->behavior, level + 1);
|
||||||
if(node->action) {
|
|
||||||
printf("%s\"%s\"\n", levelspace, node->action);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%sChildren:\n", levelspace);
|
printf("%sChildren:\n", levelspace);
|
||||||
for (cur_node = node->children; cur_node; cur_node = cur_node->next) {
|
for (cur_node = node->children; cur_node; cur_node = cur_node->next) {
|
||||||
@@ -1539,9 +1969,8 @@ static int cyberiada_print_edge(CyberiadaEdge* edge)
|
|||||||
edge->geometry_label->x,
|
edge->geometry_label->x,
|
||||||
edge->geometry_label->y);
|
edge->geometry_label->y);
|
||||||
}
|
}
|
||||||
if (edge->action) {
|
|
||||||
printf(" Action:\n %s\n", edge->action);
|
cyberiada_print_behavior(edge->behavior, 2);
|
||||||
}
|
|
||||||
return CYBERIADA_NO_ERROR;
|
return CYBERIADA_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,6 @@
|
|||||||
#ifndef __CYBERIADA_ML_H
|
#ifndef __CYBERIADA_ML_H
|
||||||
#define __CYBERIADA_ML_H
|
#define __CYBERIADA_ML_H
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -36,8 +34,9 @@ extern "C" {
|
|||||||
/* SM node types: */
|
/* SM node types: */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
cybNodeSM = 0, /* state machine */
|
cybNodeSM = 0, /* state machine */
|
||||||
cybNodeSimple, /* simple state */
|
cybNodeSimpleState, /* simple state */
|
||||||
cybNodeComposite, /* composite state */
|
cybNodeCompositeState, /* composite state */
|
||||||
|
cybNodeSubmachineState, /* submachine state */
|
||||||
cybNodeComment, /* comment node */
|
cybNodeComment, /* comment node */
|
||||||
cybNodeInitial, /* initial pseudostate */
|
cybNodeInitial, /* initial pseudostate */
|
||||||
cybNodeFinal, /* final pseudostate */
|
cybNodeFinal, /* final pseudostate */
|
||||||
@@ -45,15 +44,27 @@ typedef enum {
|
|||||||
cybNodeJunction, /* junction pseudostate */
|
cybNodeJunction, /* junction pseudostate */
|
||||||
cybNodeEntry, /* entry pseudostate */
|
cybNodeEntry, /* entry pseudostate */
|
||||||
cybNodeExit, /* exit pseudostate */
|
cybNodeExit, /* exit pseudostate */
|
||||||
|
cybNodeHistory, /* shallow history pseudostate */
|
||||||
|
cybNodeDeepHistory, /* deep history pseudostate */
|
||||||
|
cybNodeFork, /* fork pseudostate */
|
||||||
|
cybNodeJoin, /* join pseudostate */
|
||||||
|
cybNodeTerminate, /* terminate pseudostate */
|
||||||
} CyberiadaNodeType;
|
} CyberiadaNodeType;
|
||||||
|
|
||||||
/* SM node types: */
|
/* SM node types: */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
cybEdgeTransition = 0,
|
cybEdgeTransition = 0,
|
||||||
cybEdgeComment
|
|
||||||
} CyberiadaEdgeType;
|
} CyberiadaEdgeType;
|
||||||
|
|
||||||
/* SM node geometry */
|
/* SM behavior types: */
|
||||||
|
typedef enum {
|
||||||
|
cybBehaviorTransition = 0,
|
||||||
|
cybBehaviorEntry = 1,
|
||||||
|
cybBehaviorExit = 2,
|
||||||
|
cybBehaviorDo = 3,
|
||||||
|
} CyberiadaBehaviorType;
|
||||||
|
|
||||||
|
/* SM node & transitions geometry */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
double x, y;
|
double x, y;
|
||||||
@@ -68,6 +79,18 @@ typedef struct _CyberiadaPolyline {
|
|||||||
struct _CyberiadaPolyline* next;
|
struct _CyberiadaPolyline* next;
|
||||||
} CyberiadaPolyline;
|
} CyberiadaPolyline;
|
||||||
|
|
||||||
|
/* SM behavior */
|
||||||
|
typedef struct _CyberiadaBehavior {
|
||||||
|
CyberiadaBehaviorType type;
|
||||||
|
char* trigger;
|
||||||
|
size_t trigger_len;
|
||||||
|
char* guard;
|
||||||
|
size_t guard_len;
|
||||||
|
char* action;
|
||||||
|
size_t action_len;
|
||||||
|
struct _CyberiadaBehavior* next;
|
||||||
|
} CyberiadaBehavior;
|
||||||
|
|
||||||
/* SM node (state) */
|
/* SM node (state) */
|
||||||
typedef struct _CyberiadaNode {
|
typedef struct _CyberiadaNode {
|
||||||
CyberiadaNodeType type;
|
CyberiadaNodeType type;
|
||||||
@@ -75,8 +98,7 @@ typedef struct _CyberiadaNode {
|
|||||||
size_t id_len;
|
size_t id_len;
|
||||||
char* title;
|
char* title;
|
||||||
size_t title_len;
|
size_t title_len;
|
||||||
char* action;
|
CyberiadaBehavior* behavior;
|
||||||
size_t action_len;
|
|
||||||
CyberiadaRect* geometry_rect;
|
CyberiadaRect* geometry_rect;
|
||||||
struct _CyberiadaNode* next;
|
struct _CyberiadaNode* next;
|
||||||
struct _CyberiadaNode* parent;
|
struct _CyberiadaNode* parent;
|
||||||
@@ -94,8 +116,7 @@ typedef struct _CyberiadaEdge {
|
|||||||
size_t target_id_len;
|
size_t target_id_len;
|
||||||
CyberiadaNode* source;
|
CyberiadaNode* source;
|
||||||
CyberiadaNode* target;
|
CyberiadaNode* target;
|
||||||
char* action;
|
CyberiadaBehavior* behavior;
|
||||||
size_t action_len;
|
|
||||||
CyberiadaPoint* geometry_source_point;
|
CyberiadaPoint* geometry_source_point;
|
||||||
CyberiadaPoint* geometry_target_point;
|
CyberiadaPoint* geometry_target_point;
|
||||||
CyberiadaPolyline* geometry_polyline;
|
CyberiadaPolyline* geometry_polyline;
|
||||||
@@ -143,9 +164,10 @@ typedef enum {
|
|||||||
#define CYBERIADA_NO_ERROR 0
|
#define CYBERIADA_NO_ERROR 0
|
||||||
#define CYBERIADA_XML_ERROR 1
|
#define CYBERIADA_XML_ERROR 1
|
||||||
#define CYBERIADA_FORMAT_ERROR 2
|
#define CYBERIADA_FORMAT_ERROR 2
|
||||||
#define CYBERIADA_NOT_FOUND 3
|
#define CYBERIADA_BEHAVIOR_FORMAT_ERROR 3
|
||||||
#define CYBERIADA_BAD_PARAMETER 4
|
#define CYBERIADA_NOT_FOUND 4
|
||||||
#define CYBERIADA_ASSERT 5
|
#define CYBERIADA_BAD_PARAMETER 5
|
||||||
|
#define CYBERIADA_ASSERT 6
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
* The Cyberiada GraphML library functions
|
* The Cyberiada GraphML library functions
|
||||||
@@ -166,6 +188,9 @@ typedef enum {
|
|||||||
/* Read an XML file and decode the SM structure */
|
/* Read an XML file and decode the SM structure */
|
||||||
int cyberiada_read_sm(CyberiadaSM* sm, const char* filename, CyberiadaXMLFormat format);
|
int cyberiada_read_sm(CyberiadaSM* sm, 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);
|
||||||
|
|
||||||
/* Print the SM structure to stdout */
|
/* Print the SM structure to stdout */
|
||||||
int cyberiada_print_sm(CyberiadaSM* sm);
|
int cyberiada_print_sm(CyberiadaSM* sm);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user