diff options
Diffstat (limited to 'pcilib/xml.c')
-rw-r--r-- | pcilib/xml.c | 885 |
1 files changed, 637 insertions, 248 deletions
diff --git a/pcilib/xml.c b/pcilib/xml.c index 73a3deb..c431b73 100644 --- a/pcilib/xml.c +++ b/pcilib/xml.c @@ -39,14 +39,25 @@ #include "register.h" #include "xml.h" #include "error.h" +#include "view.h" +#include "views/enum.h" +#include "views/transform.h" -#define BANKS_PATH ((xmlChar*)"/model/banks/bank/bank_description") /**< path to complete nodes of banks.*/ -//#define REGISTERS_PATH ((xmlChar*)"/model/banks/bank/registers/register") /**< all standard registers nodes.*/ -//#define BIT_REGISTERS_PATH ((xmlChar*)"/model/banks/bank/registers/register/registers_bits/register_bits") /**< all bits registers nodes.*/ -#define REGISTERS_PATH ((xmlChar*)"../registers/register") /**< all standard registers nodes.*/ -#define BIT_REGISTERS_PATH ((xmlChar*)"./registers_bits/register_bits") /**< all bits registers nodes.*/ -static char *pcilib_xml_bank_default_format = "0x%lx"; +#define BANKS_PATH ((xmlChar*)"/model/bank") /**< path to complete nodes of banks */ +#define REGISTERS_PATH ((xmlChar*)"./register") /**< all standard registers nodes */ +#define BIT_REGISTERS_PATH ((xmlChar*)"./field") /**< all bits registers nodes */ +#define REGISTER_VIEWS_PATH ((xmlChar*)"./view") /**< supported register & field views */ +#define TRANSFORM_VIEWS_PATH ((xmlChar*)"/model/transform") /**< path to complete nodes of views */ +#define ENUM_VIEWS_PATH ((xmlChar*)"/model/enum") /**< path to complete nodes of views */ +#define ENUM_ELEMENTS_PATH ((xmlChar*)"./name") /**< all elements in the enum */ +#define UNITS_PATH ((xmlChar*)"/model/unit") /**< path to complete nodes of units */ +#define UNIT_TRANSFORMS_PATH ((xmlChar*)"./transform") /**< all transforms of the unit */ + + + +static const char *pcilib_xml_bank_default_format = "0x%lx"; +static const char *pcilib_xml_enum_view_unit = "name"; typedef struct { pcilib_register_description_t base; @@ -59,7 +70,7 @@ static xmlNodePtr pcilib_xml_get_parent_bank_node(xmlDocPtr doc, xmlNodePtr node bank_node = node->parent->parent; // bank_description is always a first node according to the XSD schema return xmlFirstElementChild(bank_node); - + } static xmlNodePtr pcilib_xml_get_parent_register_node(xmlDocPtr doc, xmlNodePtr node) { @@ -67,76 +78,105 @@ static xmlNodePtr pcilib_xml_get_parent_register_node(xmlDocPtr doc, xmlNodePtr } */ -static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_description_t *xml_desc, xmlDocPtr doc, xmlNodePtr node, pcilib_register_bank_description_t *bdesc) { +static int pcilib_xml_parse_view_reference(pcilib_t *ctx, xmlDocPtr doc, xmlNodePtr node, pcilib_view_reference_t *desc) { + xmlAttr *cur; + char *value, *name; + + for (cur = node->properties; cur != NULL; cur = cur->next) { + if(!cur->children) continue; + if(!xmlNodeIsText(cur->children)) continue; + + name = (char*)cur->name; + value = (char*)cur->children->content; + + if (!strcasecmp(name, "name")) { + desc->name = value; + } else if (!strcasecmp(name, "view")) { + desc->view = value; + } + } + + if (!desc->name) + desc->name = desc->view; + + return 0; +} + +static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_description_t *xml_desc, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_register_bank_description_t *bdesc) { + int err; pcilib_register_description_t *desc = (pcilib_register_description_t*)xml_desc; - xmlNodePtr cur; + xmlXPathObjectPtr nodes; + xmlNodeSetPtr nodeset; + + xmlAttrPtr cur; char *value, *name; char *endptr; - for (cur = node->children; cur != NULL; cur = cur->next) { - if (!cur->children) continue; - if (!xmlNodeIsText(cur->children)) continue; - - name = (char*)cur->name; + + for (cur = node->properties; cur != NULL; cur = cur->next) { + if (!cur->children) continue; + if (!xmlNodeIsText(cur->children)) continue; + + name = (char*)cur->name; value = (char*)cur->children->content; if (!value) continue; - + if (!strcasecmp((char*)name, "address")) { - uintptr_t addr = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)) { - pcilib_error("Invalid address (%s) is specified in the XML register description", value); - return PCILIB_ERROR_INVALID_DATA; - } + uintptr_t addr = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)) { + pcilib_error("Invalid address (%s) is specified in the XML register description", value); + return PCILIB_ERROR_INVALID_DATA; + } desc->addr = addr; } else if(!strcasecmp(name, "offset")) { - int offset = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)||(offset < 0)||(offset > (8 * sizeof(pcilib_register_value_t)))) { - pcilib_error("Invalid offset (%s) is specified in the XML register description", value); - return PCILIB_ERROR_INVALID_DATA; - } + int offset = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)||(offset < 0)||(offset > (8 * sizeof(pcilib_register_value_t)))) { + pcilib_error("Invalid offset (%s) is specified in the XML register description", value); + return PCILIB_ERROR_INVALID_DATA; + } desc->offset = (pcilib_register_size_t)offset; } else if (!strcasecmp(name,"size")) { - int size = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)||(size <= 0)||(size > (8 * sizeof(pcilib_register_value_t)))) { - pcilib_error("Invalid size (%s) is specified in the XML register description", value); - return PCILIB_ERROR_INVALID_DATA; - } + int size = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)||(size <= 0)||(size > (8 * sizeof(pcilib_register_value_t)))) { + pcilib_error("Invalid size (%s) is specified in the XML register description", value); + return PCILIB_ERROR_INVALID_DATA; + } desc->bits = (pcilib_register_size_t)size; } else if (!strcasecmp(name, "default")) { - pcilib_register_value_t val = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)) { - pcilib_error("Invalid default value (%s) is specified in the XML register description", value); - return PCILIB_ERROR_INVALID_DATA; - } + pcilib_register_value_t val = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)) { + pcilib_error("Invalid default value (%s) is specified in the XML register description", value); + return PCILIB_ERROR_INVALID_DATA; + } desc->defvalue = val; } else if (!strcasecmp(name,"min")) { - pcilib_register_value_t min = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)) { - pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value); - return PCILIB_ERROR_INVALID_DATA; - } - xml_desc->min = min; + pcilib_register_value_t min = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)) { + pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value); + return PCILIB_ERROR_INVALID_DATA; + } + xml_desc->min = min; } else if (!strcasecmp(name, "max")) { - pcilib_register_value_t max = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)) { - pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value); - return PCILIB_ERROR_INVALID_DATA; - } - xml_desc->max = max; + pcilib_register_value_t max = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)) { + pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value); + return PCILIB_ERROR_INVALID_DATA; + } + xml_desc->max = max; } else if (!strcasecmp((char*)name,"rwmask")) { if (!strcasecmp(value, "all")) { desc->rwmask = PCILIB_REGISTER_ALL_BITS; } else if (!strcasecmp(value, "none")) { desc->rwmask = 0; } else { - uintptr_t mask = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)) { - pcilib_error("Invalid mask (%s) is specified in the XML register description", value); - return PCILIB_ERROR_INVALID_DATA; - } - desc->rwmask = mask; - } + uintptr_t mask = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)) { + pcilib_error("Invalid mask (%s) is specified in the XML register description", value); + return PCILIB_ERROR_INVALID_DATA; + } + desc->rwmask = mask; + } } else if (!strcasecmp(name, "mode")) { if (!strcasecmp(value, "R")) { desc->mode = PCILIB_REGISTER_R; @@ -151,15 +191,15 @@ static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_descript } else if (!strcasecmp(value, "W1C")) { desc->mode = PCILIB_REGISTER_W1C; } else { - pcilib_error("Invalid access mode (%s) is specified in the XML register description", value); - return PCILIB_ERROR_INVALID_DATA; + pcilib_error("Invalid access mode (%s) is specified in the XML register description", value); + return PCILIB_ERROR_INVALID_DATA; } } else if (!strcasecmp(name, "type")) { if (!strcasecmp(value, "fifo")) { desc->type = PCILIB_REGISTER_FIFO; } else { - pcilib_error("Invalid register type (%s) is specified in the XML register description", value); - return PCILIB_ERROR_INVALID_DATA; + pcilib_error("Invalid register type (%s) is specified in the XML register description", value); + return PCILIB_ERROR_INVALID_DATA; } } else if (!strcasecmp(name,"name")) { desc->name = value; @@ -168,82 +208,121 @@ static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_descript } } + xpath->node = node; + nodes = xmlXPathEvalExpression(REGISTER_VIEWS_PATH, xpath); + xpath->node = NULL; + + if (!nodes) { + xmlErrorPtr xmlerr = xmlGetLastError(); + + if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", REGISTER_VIEWS_PATH, xmlerr->code, xmlerr->message); + else pcilib_error("Failed to parse XPath expression %s", REGISTER_VIEWS_PATH); + return PCILIB_ERROR_FAILED; + } + + + nodeset = nodes->nodesetval; + if (!xmlXPathNodeSetIsEmpty(nodeset)) { + int i; + + desc->views = (pcilib_view_reference_t*)malloc((nodeset->nodeNr + 1) * sizeof(pcilib_view_reference_t)); + if (!desc->views) { + xmlXPathFreeObject(nodes); + pcilib_error("Failed to allocate %zu bytes of memory to store supported register views", (nodeset->nodeNr + 1) * sizeof(char*)); + return PCILIB_ERROR_MEMORY; + } + + memset(desc->views, 0, (nodeset->nodeNr + 1) * sizeof(pcilib_view_reference_t)); + for (i = 0; i < nodeset->nodeNr; i++) { + err = pcilib_xml_parse_view_reference(ctx, doc, nodeset->nodeTab[i], &desc->views[i]); + if (err) { + xmlXPathFreeObject(nodes); + return err; + } + } + } + xmlXPathFreeObject(nodes); + return 0; } static int pcilib_xml_create_register(pcilib_t *ctx, pcilib_register_bank_t bank, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) { int err; - xmlXPathObjectPtr nodes; xmlNodeSetPtr nodeset; pcilib_xml_register_description_t desc = {{0}}; pcilib_xml_register_description_t fdesc; - + pcilib_register_t reg; - + desc.base.bank = ctx->banks[bank].addr; desc.base.rwmask = PCILIB_REGISTER_ALL_BITS; desc.base.mode = PCILIB_REGISTER_R; desc.base.type = PCILIB_REGISTER_STANDARD; - - err = pcilib_xml_parse_register(ctx, &desc, doc, node, &ctx->banks[bank]); + + err = pcilib_xml_parse_register(ctx, &desc, xpath, doc, node, &ctx->banks[bank]); if (err) { - pcilib_error("Error (%i) parsing an XML register", err); - return err; + pcilib_error("Error (%i) parsing an XML register", err); + return err; } - + err = pcilib_add_registers(ctx, PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE, 1, &desc.base, ®); if (err) { - pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, desc.base.name); - return err; + if (desc.base.views) free(desc.base.views); + pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, desc.base.name); + return err; } - ctx->register_ctx[reg].xml = node; + ctx->register_ctx[reg].xml = node; ctx->register_ctx[reg].min = desc.min; ctx->register_ctx[reg].max = desc.max; + ctx->register_ctx[reg].views = desc.base.views; + xpath->node = node; nodes = xmlXPathEvalExpression(BIT_REGISTERS_PATH, xpath); xpath->node = NULL; - + if (!nodes) { - xmlErrorPtr xmlerr = xmlGetLastError(); + xmlErrorPtr xmlerr = xmlGetLastError(); - if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", BIT_REGISTERS_PATH, xmlerr->code, xmlerr->message); - else pcilib_error("Failed to parse XPath expression %s", BIT_REGISTERS_PATH); - return PCILIB_ERROR_FAILED; + if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", BIT_REGISTERS_PATH, xmlerr->code, xmlerr->message); + else pcilib_error("Failed to parse XPath expression %s", BIT_REGISTERS_PATH); + return PCILIB_ERROR_FAILED; } nodeset = nodes->nodesetval; if (!xmlXPathNodeSetIsEmpty(nodeset)) { - int i; - - for (i = 0; i < nodeset->nodeNr; i++) { - memset(&fdesc, 0, sizeof(pcilib_xml_register_description_t)); - - fdesc.base.bank = desc.base.bank; - fdesc.base.addr = desc.base.addr; - fdesc.base.mode = desc.base.mode; - fdesc.base.rwmask = desc.base.rwmask; - fdesc.base.type = PCILIB_REGISTER_BITS; - - err = pcilib_xml_parse_register(ctx, &fdesc, doc, nodeset->nodeTab[i], &ctx->banks[bank]); - if (err) { - pcilib_error("Error parsing field in the XML register %s", desc.base.name); - continue; - } - - err = pcilib_add_registers(ctx, PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE, 1, &fdesc.base, ®); - if (err) { - pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, fdesc.base.name); - continue; - } - - ctx->register_ctx[reg].xml = nodeset->nodeTab[i]; - ctx->register_ctx[reg].min = fdesc.min; - ctx->register_ctx[reg].max = fdesc.max; - } + int i; + + for (i = 0; i < nodeset->nodeNr; i++) { + memset(&fdesc, 0, sizeof(pcilib_xml_register_description_t)); + + fdesc.base.bank = desc.base.bank; + fdesc.base.addr = desc.base.addr; + fdesc.base.mode = desc.base.mode; + fdesc.base.rwmask = desc.base.rwmask; + fdesc.base.type = PCILIB_REGISTER_BITS; + + err = pcilib_xml_parse_register(ctx, &fdesc, xpath, doc, nodeset->nodeTab[i], &ctx->banks[bank]); + if (err) { + pcilib_error("Error parsing field in the XML register %s", desc.base.name); + continue; + } + + err = pcilib_add_registers(ctx, PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE, 1, &fdesc.base, ®); + if (err) { + if (fdesc.base.views) free(fdesc.base.views); + pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, fdesc.base.name); + continue; + } + + ctx->register_ctx[reg].xml = nodeset->nodeTab[i]; + ctx->register_ctx[reg].min = fdesc.min; + ctx->register_ctx[reg].max = fdesc.max; + ctx->register_ctx[reg].views = fdesc.base.views; + } } xmlXPathFreeObject(nodes); @@ -252,11 +331,11 @@ static int pcilib_xml_create_register(pcilib_t *ctx, pcilib_register_bank_t bank static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) { int err; - + int override = 0; pcilib_register_bank_description_t desc = {0}; pcilib_register_bank_t bank; - xmlNodePtr cur; + xmlAttrPtr cur; char *value, *name; char *endptr; @@ -273,70 +352,70 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo desc.endianess = PCILIB_HOST_ENDIAN; desc.raw_endianess = PCILIB_HOST_ENDIAN; - // iterate through all children, representing bank properties, to fill the structure - for (cur = node->children; cur != NULL; cur = cur->next) { - if (!cur->children) continue; - if (!xmlNodeIsText(cur->children)) continue; - - name = (char*)cur->name; + // iterate through all children, representing bank properties, to fill the structure + for (cur = node->properties; cur != NULL; cur = cur->next) { + if (!cur->children) continue; + if (!xmlNodeIsText(cur->children)) continue; + + name = (char*)cur->name; value = (char*)cur->children->content; if (!value) continue; - + if (!strcasecmp(name, "bar")) { - char bar = value[0]-'0'; - if ((strlen(value) != 1)||(bar < 0)||(bar > 5)) { - pcilib_error("Invalid BAR (%s) is specified in the XML bank description", value); - return PCILIB_ERROR_INVALID_DATA; - } + char bar = value[0]-'0'; + if ((strlen(value) != 1)||(bar < 0)||(bar > 5)) { + pcilib_error("Invalid BAR (%s) is specified in the XML bank description", value); + return PCILIB_ERROR_INVALID_DATA; + } desc.bar = (pcilib_bar_t)bar; override = 1; } else if (!strcasecmp(name,"size")) { - long size = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)||(size<=0)) { - pcilib_error("Invalid bank size (%s) is specified in the XML bank description", value); - return PCILIB_ERROR_INVALID_DATA; - } + long size = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)||(size<=0)) { + pcilib_error("Invalid bank size (%s) is specified in the XML bank description", value); + return PCILIB_ERROR_INVALID_DATA; + } desc.size = (size_t)size; override = 1; } else if (!strcasecmp(name,"protocol")) { - pcilib_register_protocol_t protocol = pcilib_find_register_protocol_by_name(ctx, value); - if (protocol == PCILIB_REGISTER_PROTOCOL_INVALID) { - pcilib_error("Unsupported protocol (%s) is specified in the XML bank description", value); - return PCILIB_ERROR_NOTSUPPORTED; - } - desc.protocol = ctx->protocols[protocol].addr; + pcilib_register_protocol_t protocol = pcilib_find_register_protocol_by_name(ctx, value); + if (protocol == PCILIB_REGISTER_PROTOCOL_INVALID) { + pcilib_error("Unsupported protocol (%s) is specified in the XML bank description", value); + return PCILIB_ERROR_NOTSUPPORTED; + } + desc.protocol = ctx->protocols[protocol].addr; override = 1; } else if (!strcasecmp(name,"address")) { - uintptr_t addr = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)) { - pcilib_error("Invalid address (%s) is specified in the XML bank description", value); - return PCILIB_ERROR_INVALID_DATA; - } + uintptr_t addr = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)) { + pcilib_error("Invalid address (%s) is specified in the XML bank description", value); + return PCILIB_ERROR_INVALID_DATA; + } desc.read_addr = addr; desc.write_addr = addr; override = 1; } else if (!strcasecmp(name,"read_address")) { - uintptr_t addr = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)) { - pcilib_error("Invalid address (%s) is specified in the XML bank description", value); - return PCILIB_ERROR_INVALID_DATA; - } + uintptr_t addr = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)) { + pcilib_error("Invalid address (%s) is specified in the XML bank description", value); + return PCILIB_ERROR_INVALID_DATA; + } desc.read_addr = addr; override = 1; } else if (!strcasecmp(name,"write_address")) { - uintptr_t addr = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)) { - pcilib_error("Invalid address (%s) is specified in the XML bank description", value); - return PCILIB_ERROR_INVALID_DATA; - } + uintptr_t addr = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)) { + pcilib_error("Invalid address (%s) is specified in the XML bank description", value); + return PCILIB_ERROR_INVALID_DATA; + } desc.write_addr = addr; override = 1; } else if(strcasecmp((char*)name,"word_size")==0) { - int access = strtol(value, &endptr, 0); - if ((strlen(endptr) > 0)||(access%8)||(access<=0)||(access>(8 * sizeof(pcilib_register_value_t)))) { - pcilib_error("Invalid word size (%s) is specified in the XML bank description", value); - return PCILIB_ERROR_INVALID_DATA; - } + int access = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)||(access%8)||(access<=0)||(access>(8 * sizeof(pcilib_register_value_t)))) { + pcilib_error("Invalid word size (%s) is specified in the XML bank description", value); + return PCILIB_ERROR_INVALID_DATA; + } desc.access = access; override = 1; } else if (!strcasecmp(name,"endianess")) { @@ -344,8 +423,8 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo else if (!strcasecmp(value,"big")) desc.endianess = PCILIB_BIG_ENDIAN; else if (!strcasecmp(value,"host")) desc.endianess = PCILIB_HOST_ENDIAN; else { - pcilib_error("Invalid endianess (%s) is specified in the XML bank description", value); - return PCILIB_ERROR_INVALID_DATA; + pcilib_error("Invalid endianess (%s) is specified in the XML bank description", value); + return PCILIB_ERROR_INVALID_DATA; } override = 1; } else if (!strcasecmp(name,"format")) { @@ -357,7 +436,7 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo desc.description = value; override = 1; } else if (!strcasecmp((char*)name,"override")) { - override = 1; + override = 1; } } @@ -369,31 +448,302 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo ctx->xml.bank_nodes[bank] = node; if (ctx->bank_ctx[bank]) { - ctx->bank_ctx[bank]->xml = node; + ctx->bank_ctx[bank]->xml = node; } xpath->node = node; nodes = xmlXPathEvalExpression(REGISTERS_PATH, xpath); xpath->node = NULL; + + if (!nodes) { + xmlErrorPtr xmlerr = xmlGetLastError(); + if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", REGISTERS_PATH, xmlerr->code, xmlerr->message); + else pcilib_error("Failed to parse XPath expression %s", REGISTERS_PATH); + return PCILIB_ERROR_FAILED; + } + + nodeset = nodes->nodesetval; + if (!xmlXPathNodeSetIsEmpty(nodeset)) { + int i; + for (i = 0; i < nodeset->nodeNr; i++) { + err = pcilib_xml_create_register(ctx, bank, xpath, doc, nodeset->nodeTab[i]); + if (err) pcilib_error("Error creating XML registers for bank %s", desc.name); + } + } + xmlXPathFreeObject(nodes); + + return 0; +} + +static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_view_description_t *desc) { + xmlAttrPtr cur; + const char *value, *name; + + desc->type = PCILIB_TYPE_STRING; + + for (cur = node->properties; cur != NULL; cur = cur->next) { + if (!cur->children) continue; + if (!xmlNodeIsText(cur->children)) continue; + + name = (char*)cur->name; + value = (char*)cur->children->content; + if (!value) continue; + + if (!strcasecmp(name, "name")) { + desc->name = value; + } else if (!strcasecmp((char*)name, "description")) { + desc->description = value; + } else if (!strcasecmp((char*)name, "unit")) { + desc->unit = value; + } else if (!strcasecmp((char*)name, "type")) { + if (!strcasecmp(value, "string")) desc->type = PCILIB_TYPE_STRING; + else if (!strcasecmp(value, "float")) desc->type = PCILIB_TYPE_DOUBLE; + else if (!strcasecmp(value, "int")) desc->type = PCILIB_TYPE_LONG; + else { + pcilib_error("Invalid type (%s) of register view is specified in the XML bank description", value); + return PCILIB_ERROR_INVALID_DATA; + } + } + } + + return 0; +} + +static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) { + int err; + xmlAttrPtr cur; + const char *value, *name; + + pcilib_transform_view_description_t desc = {0}; + + desc.base.api = &pcilib_enum_view_xml_api; + + err = pcilib_xml_parse_view(ctx, xpath, doc, node, (pcilib_view_description_t*)&desc); + if (err) return err; + + for (cur = node->properties; cur != NULL; cur = cur->next) { + if (!cur->children) continue; + if (!xmlNodeIsText(cur->children)) continue; + + name = (char*)cur->name; + value = (char*)cur->children->content; + if (!value) continue; + + if (!strcasecmp(name, "read_from_register")) { + desc.read_from_reg = value; + } else if (!strcasecmp(name, "write_to_register")) { + desc.write_to_reg = value; + } + } + + + return pcilib_add_views(ctx, 1, (pcilib_view_description_t*)&desc); +} + + +static int pcilib_xml_parse_value_name(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_value_name_t *desc) { + xmlAttr *cur; + char *value, *name; + char *endptr; + + int min_set = 0, max_set = 0; + pcilib_register_value_t val; + for (cur = node->properties; cur != NULL; cur = cur->next) { + if(!cur->children) continue; + if(!xmlNodeIsText(cur->children)) continue; + + name = (char*)cur->name; + value = (char*)cur->children->content; + + if (!strcasecmp(name, "name")) { + desc->name = value; + } else if (!strcasecmp(name, "value")) { + val = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)) { + pcilib_error("Invalid enum value (%s) is specified in the XML enum node", value); + return PCILIB_ERROR_INVALID_DATA; + } + desc->value = val; + } else if (!strcasecmp(name, "min")) { + val = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)) { + pcilib_error("Invalid enum min-value (%s) is specified in the XML enum node", value); + return PCILIB_ERROR_INVALID_DATA; + } + desc->min = val; + min_set = 1; + } else if (!strcasecmp(name, "max")) { + val = strtol(value, &endptr, 0); + if ((strlen(endptr) > 0)) { + pcilib_error("Invalid enum max-value (%s) is specified in the XML enum node", value); + return PCILIB_ERROR_INVALID_DATA; + } + desc->max = val; + max_set = 1; + } + } + + if ((!min_set)&&(!max_set)) { + desc->min = desc->value; + desc->max = desc->value; + } else if (max_set) { + desc->min = 0; + } else if (min_set) { + desc->max = (pcilib_register_value_t)-1; + } + + if ((desc->min > desc->max)||(desc->value < desc->min)||(desc->value > desc->max)) { + pcilib_error("Invalid enum configuration (min: %lu, max: %lu, value: %lu)", desc->min, desc->max, desc->value); + return PCILIB_ERROR_INVALID_DATA; + } + + return 0; +} + +static int pcilib_xml_create_enum_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) { + int i; + int err; + + xmlXPathObjectPtr nodes; + xmlNodeSetPtr nodeset; + + pcilib_enum_view_description_t desc = {0}; + + desc.base.unit = pcilib_xml_enum_view_unit; + desc.base.api = &pcilib_enum_view_xml_api; + + err = pcilib_xml_parse_view(ctx, xpath, doc, node, (pcilib_view_description_t*)&desc); + if (err) return err; + + + xpath->node = node; + nodes = xmlXPathEvalExpression(ENUM_ELEMENTS_PATH, xpath); + xpath->node = NULL; + + if (!nodes) { + xmlErrorPtr xmlerr = xmlGetLastError(); + if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", ENUM_ELEMENTS_PATH, xmlerr->code, xmlerr->message); + else pcilib_error("Failed to parse XPath expression %s", ENUM_ELEMENTS_PATH); + return PCILIB_ERROR_FAILED; + } + + nodeset = nodes->nodesetval; + if (xmlXPathNodeSetIsEmpty(nodeset)) { + xmlXPathFreeObject(nodes); + pcilib_error("No names is defined for enum view (%s)", desc.base.name); + return PCILIB_ERROR_INVALID_DATA; + } + + desc.names = (pcilib_value_name_t*)malloc((nodeset->nodeNr + 1) * sizeof(pcilib_value_name_t)); + if (!desc.names) { + xmlXPathFreeObject(nodes); + pcilib_error("No names is defined for enum view (%s)", desc.base.name); + return PCILIB_ERROR_INVALID_DATA; + } + + + for (i = 0; i < nodeset->nodeNr; i++) { + err = pcilib_xml_parse_value_name(ctx, xpath, doc, nodeset->nodeTab[i], &desc.names[i]); + if (err) { + xmlXPathFreeObject(nodes); + free(desc.names); + return err; + } + } + memset(&desc.names[nodeset->nodeNr], 0, sizeof(pcilib_value_name_t)); + + xmlXPathFreeObject(nodes); + + + err = pcilib_add_views(ctx, 1, (pcilib_view_description_t*)&desc); + if (err) free(desc.names); + return err; +} + +static int pcilib_xml_parse_unit_transform(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_unit_transform_t *desc) { + xmlAttrPtr cur; + char *value, *name; + + for (cur = node->properties; cur != NULL; cur = cur->next) { + if (!cur->children) continue; + if (!xmlNodeIsText(cur->children)) continue; + + name = (char*)cur->name; + value = (char*)cur->children->content; + + if (!strcasecmp(name, "unit")) { + desc->unit = value; + } else if (!strcasecmp(name, "transform")) { + desc->transform = value; + } + } + + return 0; +} + +/** + * function to create a unit from a unit xml node, then populating ctx with it + *@param[in,out] ctx - the pcilib_t running + *@param[in] xpath - the xpath context of the unis xml file + *@param[in] doc - the AST of the unit xml file + *@param[in] node - the node representing the unit + *@return an error code: 0 if evrythinh is ok + */ +static int pcilib_xml_create_unit(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) { + int err; + + pcilib_unit_description_t desc = {0}; + + xmlXPathObjectPtr nodes; + xmlNodeSetPtr nodeset; + + xmlAttrPtr cur; + char *value, *name; + + for (cur = node->properties; cur != NULL; cur = cur->next) { + if (!cur->children) continue; + if (!xmlNodeIsText(cur->children)) continue; + + name = (char*)cur->name; + value = (char*)cur->children->content; + if (!strcasecmp(name, "name")) { + desc.name = value; + } + } + + xpath->node = node; + nodes = xmlXPathEvalExpression(UNIT_TRANSFORMS_PATH, xpath); + xpath->node = NULL; + if (!nodes) { - xmlErrorPtr xmlerr = xmlGetLastError(); - if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", REGISTERS_PATH, xmlerr->code, xmlerr->message); - else pcilib_error("Failed to parse XPath expression %s", REGISTERS_PATH); - return PCILIB_ERROR_FAILED; + xmlErrorPtr xmlerr = xmlGetLastError(); + if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", UNIT_TRANSFORMS_PATH, xmlerr->code, xmlerr->message); + else pcilib_error("Failed to parse XPath expression %s", UNIT_TRANSFORMS_PATH); + return PCILIB_ERROR_FAILED; } nodeset = nodes->nodesetval; if (!xmlXPathNodeSetIsEmpty(nodeset)) { int i; + + if (nodeset->nodeNr > PCILIB_MAX_TRANSFORMS_PER_UNIT) { + xmlXPathFreeObject(nodes); + pcilib_error("Too many transforms for unit %s are defined, only %lu are supported", desc.name, PCILIB_MAX_TRANSFORMS_PER_UNIT); + return PCILIB_ERROR_INVALID_DATA; + } + for (i = 0; i < nodeset->nodeNr; i++) { - err = pcilib_xml_create_register(ctx, bank, xpath, doc, nodeset->nodeTab[i]); - if (err) pcilib_error("Error creating XML registers for bank %s", desc.name); + err = pcilib_xml_parse_unit_transform(ctx, xpath, doc, nodeset->nodeTab[i], &desc.transforms[i]); + if (err) { + xmlXPathFreeObject(nodes); + return err; + } } } xmlXPathFreeObject(nodes); - return 0; + return pcilib_add_units(ctx, 1, &desc); } @@ -405,69 +755,108 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo * @param[in] pci the pcilib_t running, which will be filled */ static int pcilib_xml_process_document(pcilib_t *ctx, xmlDocPtr doc, xmlXPathContextPtr xpath) { - xmlXPathObjectPtr bank_nodes; + int err; + xmlXPathObjectPtr bank_nodes = NULL, transform_nodes = NULL, enum_nodes = NULL, unit_nodes = NULL; xmlNodeSetPtr nodeset; + int i; - bank_nodes = xmlXPathEvalExpression(BANKS_PATH, xpath); - if (!bank_nodes) { - xmlErrorPtr xmlerr = xmlGetLastError(); - if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", BANKS_PATH, xmlerr->code, xmlerr->message); - else pcilib_error("Failed to parse XPath expression %s", BANKS_PATH); - return PCILIB_ERROR_FAILED; + bank_nodes = xmlXPathEvalExpression(BANKS_PATH, xpath); + if (bank_nodes) transform_nodes = xmlXPathEvalExpression(TRANSFORM_VIEWS_PATH, xpath); + if (transform_nodes) enum_nodes = xmlXPathEvalExpression(ENUM_VIEWS_PATH, xpath); + if (enum_nodes) unit_nodes = xmlXPathEvalExpression(UNITS_PATH, xpath); + + if (!unit_nodes) { + const unsigned char *expr = (enum_nodes?UNITS_PATH:(transform_nodes?ENUM_VIEWS_PATH:(bank_nodes?TRANSFORM_VIEWS_PATH:BANKS_PATH))); + + if (enum_nodes) xmlXPathFreeObject(enum_nodes); + if (transform_nodes) xmlXPathFreeObject(transform_nodes); + if (bank_nodes) xmlXPathFreeObject(bank_nodes); + xmlErrorPtr xmlerr = xmlGetLastError(); + if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", expr, xmlerr->code, xmlerr->message); + else pcilib_error("Failed to parse XPath expression %s", expr); + return PCILIB_ERROR_FAILED; } + nodeset = unit_nodes->nodesetval; + if(!xmlXPathNodeSetIsEmpty(nodeset)) { + for(i=0; i < nodeset->nodeNr; i++) { + err = pcilib_xml_create_unit(ctx, xpath, doc, nodeset->nodeTab[i]); + if (err) pcilib_error("Error (%i) creating unit", err); + } + } + + nodeset = transform_nodes->nodesetval; + if (!xmlXPathNodeSetIsEmpty(nodeset)) { + for(i=0; i < nodeset->nodeNr; i++) { + err = pcilib_xml_create_transform_view(ctx, xpath, doc, nodeset->nodeTab[i]); + if (err) pcilib_error("Error (%i) creating register transform", err); + } + } + + nodeset = enum_nodes->nodesetval; + if (!xmlXPathNodeSetIsEmpty(nodeset)) { + for(i=0; i < nodeset->nodeNr; i++) { + err = pcilib_xml_create_enum_view(ctx, xpath, doc, nodeset->nodeTab[i]); + if (err) pcilib_error("Error (%i) creating register enum", err); + } + } nodeset = bank_nodes->nodesetval; if (!xmlXPathNodeSetIsEmpty(nodeset)) { - int i; - for (i = 0; i < nodeset->nodeNr; i++) { - pcilib_xml_create_bank(ctx, xpath, doc, nodeset->nodeTab[i]); - } + for (i = 0; i < nodeset->nodeNr; i++) { + err = pcilib_xml_create_bank(ctx, xpath, doc, nodeset->nodeTab[i]); + if (err) pcilib_error("Error (%i) creating bank", err); + } } + + + xmlXPathFreeObject(unit_nodes); + xmlXPathFreeObject(enum_nodes); + xmlXPathFreeObject(transform_nodes); xmlXPathFreeObject(bank_nodes); - + return 0; } static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) { int err; - + xmlSchemaParserCtxtPtr ctxt; /** we first parse the xsd file for AST with validation*/ ctxt = xmlSchemaNewParserCtxt(xsd_filename); if (!ctxt) { - xmlErrorPtr xmlerr = xmlGetLastError(); - if (xmlerr) pcilib_error("xmlSchemaNewParserCtxt reported error %d - %s", xmlerr->code, xmlerr->message); - else pcilib_error("Failed to create a parser for XML schemas"); - return PCILIB_ERROR_FAILED; + xmlErrorPtr xmlerr = xmlGetLastError(); + if (xmlerr) pcilib_error("xmlSchemaNewParserCtxt reported error %d - %s", xmlerr->code, xmlerr->message); + else pcilib_error("Failed to create a parser for XML schemas"); + return PCILIB_ERROR_FAILED; } - + ctx->xml.schema = xmlSchemaParse(ctxt); if (!ctx->xml.schema) { - xmlErrorPtr xmlerr = xmlGetLastError(); - xmlSchemaFreeParserCtxt(ctxt); - if (xmlerr) pcilib_error("Failed to parse XML schema, xmlSchemaParse reported error %d - %s", xmlerr->code, xmlerr->message); - else pcilib_error("Failed to parse XML schema"); - return PCILIB_ERROR_INVALID_DATA; + xmlErrorPtr xmlerr = xmlGetLastError(); + xmlSchemaFreeParserCtxt(ctxt); + if (xmlerr) pcilib_error("Failed to parse XML schema, xmlSchemaParse reported error %d - %s", xmlerr->code, xmlerr->message); + else pcilib_error("Failed to parse XML schema"); + return PCILIB_ERROR_INVALID_DATA; } - + xmlSchemaFreeParserCtxt(ctxt); ctx->xml.validator = xmlSchemaNewValidCtxt(ctx->xml.schema); if (!ctx->xml.validator) { - xmlErrorPtr xmlerr = xmlGetLastError(); - if (xmlerr) pcilib_error("xmlSchemaNewValidCtxt reported error %d - %s", xmlerr->code, xmlerr->message); - else pcilib_error("Failed to create a validation context"); - return PCILIB_ERROR_FAILED; + xmlErrorPtr xmlerr = xmlGetLastError(); + if (xmlerr) pcilib_error("xmlSchemaNewValidCtxt reported error %d - %s", xmlerr->code, xmlerr->message); + else pcilib_error("Failed to create a validation context"); + return PCILIB_ERROR_FAILED; } - + err = xmlSchemaSetValidOptions(ctx->xml.validator, XML_SCHEMA_VAL_VC_I_CREATE); if (err) { - xmlErrorPtr xmlerr = xmlGetLastError(); - if (xmlerr) pcilib_error("xmlSchemaSetValidOptions reported error %d - %s", xmlerr->code, xmlerr->message); - else pcilib_error("Failed to configure the validation context to populate default attributes"); - return PCILIB_ERROR_FAILED; + xmlErrorPtr xmlerr = xmlGetLastError(); + if (xmlerr) pcilib_error("xmlSchemaSetValidOptions reported error %d - %s", xmlerr->code, xmlerr->message); + else pcilib_error("Failed to configure the validation context to populate default attributes"); + return PCILIB_ERROR_FAILED; } return 0; @@ -481,46 +870,46 @@ static int pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *nam full_name = (char*)alloca(strlen(path) + strlen(name) + 2); if (!name) { - pcilib_error("Error allocating %zu bytes of memory in stack to create a file name", strlen(path) + strlen(name) + 2); - return PCILIB_ERROR_MEMORY; + pcilib_error("Error allocating %zu bytes of memory in stack to create a file name", strlen(path) + strlen(name) + 2); + return PCILIB_ERROR_MEMORY; } sprintf(full_name, "%s/%s", path, name); doc = xmlCtxtReadFile(ctx->xml.parser, full_name, NULL, 0); if (!doc) { - xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser); - if (xmlerr) pcilib_error("Error parsing %s, xmlCtxtReadFile reported error %d - %s", full_name, xmlerr->code, xmlerr->message); - else pcilib_error("Error parsing %s", full_name); - return PCILIB_ERROR_INVALID_DATA; + xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser); + if (xmlerr) pcilib_error("Error parsing %s, xmlCtxtReadFile reported error %d - %s", full_name, xmlerr->code, xmlerr->message); + else pcilib_error("Error parsing %s", full_name); + return PCILIB_ERROR_INVALID_DATA; } err = xmlSchemaValidateDoc(ctx->xml.validator, doc); if (err) { - xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser); - xmlFreeDoc(doc); - if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", full_name, xmlerr->code, xmlerr->message); - else pcilib_error("Error validating %s", full_name); - return PCILIB_ERROR_VERIFY; + xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser); + xmlFreeDoc(doc); + if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", full_name, xmlerr->code, xmlerr->message); + else pcilib_error("Error validating %s", full_name); + return PCILIB_ERROR_VERIFY; } xpath = xmlXPathNewContext(doc); if (!xpath) { - xmlErrorPtr xmlerr = xmlGetLastError(); - xmlFreeDoc(doc); - if (xmlerr) pcilib_error("Document %s: xmlXpathNewContext reported error %d - %s for document %s", full_name, xmlerr->code, xmlerr->message); - else pcilib_error("Error creating XPath context for %s", full_name); - return PCILIB_ERROR_FAILED; + xmlErrorPtr xmlerr = xmlGetLastError(); + xmlFreeDoc(doc); + if (xmlerr) pcilib_error("Document %s: xmlXpathNewContext reported error %d - %s for document %s", full_name, xmlerr->code, xmlerr->message); + else pcilib_error("Error creating XPath context for %s", full_name); + return PCILIB_ERROR_FAILED; } - // This can only partially fail... Therefore we need to keep XML and just return the error... + // This can only partially fail... Therefore we need to keep XML and just return the error... err = pcilib_xml_process_document(ctx, doc, xpath); if (ctx->xml.num_files == PCILIB_MAX_MODEL_FILES) { - xmlFreeDoc(doc); + xmlFreeDoc(doc); xmlXPathFreeContext(xpath); - pcilib_error("Too many XML files for a model, only up to %zu are supported", PCILIB_MAX_MODEL_FILES); - return PCILIB_ERROR_TOOBIG; + pcilib_error("Too many XML files for a model, only up to %zu are supported", PCILIB_MAX_MODEL_FILES); + return PCILIB_ERROR_TOOBIG; } ctx->xml.docs[ctx->xml.num_files] = doc; @@ -550,12 +939,12 @@ int pcilib_process_xml(pcilib_t *ctx, const char *location) { if (!rep) return PCILIB_ERROR_NOTFOUND; while ((file = readdir(rep)) != NULL) { - size_t len = strlen(file->d_name); - if ((len < 4)||(strcasecmp(file->d_name + len - 4, ".xml"))) continue; - if (file->d_type != DT_REG) continue; - - err = pcilib_xml_load_file(ctx, model_path, file->d_name); - if (err) pcilib_error("Error processing XML file %s", file->d_name); + size_t len = strlen(file->d_name); + if ((len < 4)||(strcasecmp(file->d_name + len - 4, ".xml"))) continue; + if (file->d_type != DT_REG) continue; + + err = pcilib_xml_load_file(ctx, model_path, file->d_name); + if (err) pcilib_error("Error processing XML file %s", file->d_name); } closedir(rep); @@ -586,16 +975,16 @@ int pcilib_init_xml(pcilib_t *ctx, const char *model) { sprintf(xsd_path, "%s/model.xsd", model_dir); if (stat(xsd_path, &st)) { - pcilib_info("XML models are not present"); - return PCILIB_ERROR_NOTFOUND; + pcilib_info("XML models are not present"); + return PCILIB_ERROR_NOTFOUND; } ctx->xml.parser = xmlNewParserCtxt(); if (!ctx->xml.parser) { - xmlErrorPtr xmlerr = xmlGetLastError(); - if (xmlerr) pcilib_error("xmlNewParserCtxt reported error %d (%s)", xmlerr->code, xmlerr->message); - else pcilib_error("Failed to create an XML parser context"); - return PCILIB_ERROR_FAILED; + xmlErrorPtr xmlerr = xmlGetLastError(); + if (xmlerr) pcilib_error("xmlNewParserCtxt reported error %d (%s)", xmlerr->code, xmlerr->message); + else pcilib_error("Failed to create an XML parser context"); + return PCILIB_ERROR_FAILED; } err = pcilib_xml_load_xsd(ctx, xsd_path); @@ -613,44 +1002,44 @@ void pcilib_free_xml(pcilib_t *ctx) { memset(ctx->xml.bank_nodes, 0, sizeof(ctx->xml.bank_nodes)); for (i = 0; i < ctx->num_banks; i++) { - if (ctx->bank_ctx[i]) - ctx->bank_ctx[i]->xml = NULL; + if (ctx->bank_ctx[i]) + ctx->bank_ctx[i]->xml = NULL; } - + for (i = 0; i < ctx->num_reg; i++) { - ctx->register_ctx[i].xml = NULL; + ctx->register_ctx[i].xml = NULL; } - + for (i = 0; i < ctx->xml.num_files; i++) { - if (ctx->xml.docs[i]) { - xmlFreeDoc(ctx->xml.docs[i]); - ctx->xml.docs[i] = NULL; - } - if (ctx->xml.xpath[i]) { - xmlXPathFreeContext(ctx->xml.xpath[i]); - ctx->xml.xpath[i] = NULL; - } + if (ctx->xml.docs[i]) { + xmlFreeDoc(ctx->xml.docs[i]); + ctx->xml.docs[i] = NULL; + } + if (ctx->xml.xpath[i]) { + xmlXPathFreeContext(ctx->xml.xpath[i]); + ctx->xml.xpath[i] = NULL; + } } ctx->xml.num_files = 0; if (ctx->xml.validator) { - xmlSchemaFreeValidCtxt(ctx->xml.validator); - ctx->xml.validator = NULL; + xmlSchemaFreeValidCtxt(ctx->xml.validator); + ctx->xml.validator = NULL; } - + if (ctx->xml.schema) { - xmlSchemaFree(ctx->xml.schema); - ctx->xml.schema = NULL; - + xmlSchemaFree(ctx->xml.schema); + ctx->xml.schema = NULL; + } if (ctx->xml.parser) { - xmlFreeParserCtxt(ctx->xml.parser); - ctx->xml.parser = NULL; + xmlFreeParserCtxt(ctx->xml.parser); + ctx->xml.parser = NULL; } -/* - xmlSchemaCleanupTypes(); - xmlCleanupParser(); - xmlMemoryDump(); -*/ + /* + xmlSchemaCleanupTypes(); + xmlCleanupParser(); + xmlMemoryDump(); + */ } |