diff options
author | David Sommerseth <davids@redhat.com> | 2009-08-11 11:34:21 +0200 |
---|---|---|
committer | David Sommerseth <davids@redhat.com> | 2009-08-11 11:34:21 +0200 |
commit | eb08fd406370a81172d7fdd0663233a5f140b784 (patch) | |
tree | c50e19f2b873441672b20a7e339c176d9a4a7cbf /src/dmixml.c | |
parent | 39cbdfb56e80cabbd67754d8d77f781e14eaa3da (diff) | |
parent | 3165a97a06f891622b913714bc4f8ca54565f9cc (diff) | |
download | python-dmidecode-eb08fd406370a81172d7fdd0663233a5f140b784.tar.gz python-dmidecode-eb08fd406370a81172d7fdd0663233a5f140b784.tar.xz python-dmidecode-eb08fd406370a81172d7fdd0663233a5f140b784.zip |
Merge commit 'nima/xml'
Conflicts:
debian/changelog
Had the same changelog entry in both xml and master
branch, with a minor wording difference. Removed the
duplicate and merged in the changelog entries from the
XML branch
src/dmidecode.c
Merge process got confused by some functions which was not
changed. Removed the code coming from the master branch and
let the XML be the base.
src/setup-dbg.py
src/setup.py
In the XML branch, the version of the python-dmidecode is
now a function which retrieves the version number from
src/version.h. Merged in this feature to master as well.
Diffstat (limited to 'src/dmixml.c')
-rw-r--r-- | src/dmixml.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/src/dmixml.c b/src/dmixml.c new file mode 100644 index 0000000..5d9f1a1 --- /dev/null +++ b/src/dmixml.c @@ -0,0 +1,360 @@ +/* Simplified XML API for dmidecode + * + * Copyright 2009 David Sommerseth <davids@redhat.com> + * Copyright 2009 Nima Talebi <nima@autonomy.net.au> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open unpatent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + */ + +/** + * @file dmixml.c + * @brief Helper functions for XML nodes and documents. + * @author David Sommerseth <davids@redhat.com> + * @author Nima Talebi <nima@autonomy.net.au> + */ + + + +#include <string.h> +#include <stdarg.h> +#include <assert.h> + +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/xmlstring.h> + +#include "dmixml.h" + +/** + * Internal function for dmixml_* functions. The function will allocate a buffer and populate it + * according to the format string + * @author David Sommerseth <davids@redhat.com> + * @param size_t The requested size for the new buffer + * @param const char* The format of the string being built (uses vsnprintf()) + * @param ... The needed variables to build up the string + * @return xmlChar* Pointer to the buffer of the string + */ +xmlChar *dmixml_buildstr(size_t len, const char *fmt, va_list ap) { + xmlChar *ret = NULL, *xmlfmt = NULL; + xmlChar *ptr = NULL; + + ret = (xmlChar *) malloc(len+2); + assert( ret != NULL ); + memset(ret, 0, len+2); + + xmlfmt = xmlCharStrdup(fmt); + assert( xmlfmt != NULL ); + + xmlStrVPrintf(ret, len, xmlfmt, ap); + free(xmlfmt); + + // Right trim the string + ptr = ret + xmlStrlen(ret)-1; + while( (ptr >= ret) && (*ptr == ' ') ) { + *ptr = 0; + ptr--; + } + return ret; +} + + +/** + * Add an XML property/attribute to the given XML node + * @author David Sommerseth <davids@redhat.com> + * @param xmlNode* A pointer to the xmlNode being updated + * @param const char* The name of the attribute + * @param const char* Value of the string (can make use of string formating options) + * @return xmlAttr* Pointer to the new attribute node. On errors an assert is + * triggered and return value should be NULL. + */ +xmlAttr *dmixml_AddAttribute(xmlNode *node, const char *atrname, const char *fmt, ...) +{ + xmlChar *val_s = NULL, *atrname_s = NULL; + xmlAttr *res = NULL; + va_list ap; + + if( (node == NULL) || (atrname == NULL) || (fmt == NULL) ) { + return NULL; + } + + atrname_s = xmlCharStrdup(atrname); + assert( atrname_s != NULL ); + + va_start(ap, fmt); + val_s = dmixml_buildstr(2048, fmt, ap); + va_end(ap); + + res = xmlNewProp(node, atrname_s, + (xmlStrcmp(val_s, (xmlChar *) "(null)") == 0 ? NULL : val_s)); + + free(atrname_s); + free(val_s); + + assert( res != NULL ); + return res; +} + + +/** + * Adds a new XML tag to the given node with the given tag name and value. + * @author David Sommerseth <davids@redhat.com> + * @param xmlNode* Pointer to the parent node for this new node + * @param const char* Name of the new tag + * @param const char* Contents of the new tag (can make use of string formating options) + * @return xmlNode* Pointer to the new tag. On errors an assert is triggered and return + * value should be NULL. + */ +xmlNode *dmixml_AddTextChild(xmlNode *node, const char *tagname, const char *fmt, ...) +{ + xmlChar *val_s = NULL, *tagname_s = NULL; + xmlNode *res = NULL; + va_list ap; + + if( (node == NULL) || (tagname == NULL) || (fmt == NULL) ) { + return NULL; + } + + tagname_s = xmlCharStrdup(tagname); + assert( tagname_s != NULL ); + + va_start(ap, fmt); + val_s = dmixml_buildstr(2048, fmt, ap); + va_end(ap); + + // Do not add any contents if the string contents is "(null)" + res = xmlNewTextChild(node, NULL, tagname_s, + (xmlStrcmp(val_s, (xmlChar *) "(null)") == 0 ? NULL : val_s)); + + free(tagname_s); + free(val_s); + + assert( res != NULL ); + return res; +} + +/** + * Adds a text node child to the given XML node. If input is NULL, the tag contents will be empty. + * @author David Sommerseth <davids@redhat.com> + * @param xmlNode* Pointer to the current node which will get the text child + * @param const char* Contents of the tag (can make use of string formating options) + * @return xmlNode* Pointer to the tags content node + */ +xmlNode *dmixml_AddTextContent(xmlNode *node, const char *fmt, ...) +{ + xmlChar *val_s = NULL; + xmlNode *res = NULL; + va_list ap; + + if( (node == NULL) || (fmt == NULL) ) { + return NULL; + } + + va_start(ap, fmt); + val_s = dmixml_buildstr(2048, fmt, ap); + va_end(ap); + + if( xmlStrcmp(val_s, (xmlChar *) "(null)") != 0 ) { + res = xmlAddChild(node, xmlNewText(val_s)); + } else { + res = node; + } + free(val_s); + + assert( res != NULL ); + return res; +} + +/** + * Retrieve the contents of a named attribute in a given XML node + * @author David Sommerseth <davids@redhat.com> + * @param xmlNode* Pointer to the XML node of which we want to extract the attribute value + * @param const char* The name of the attribute to be extracted + * @return char* Pointer to the attribute contents if found, otherwise NULL. This value + * must NOT be freed, as it points directly into the value in the XML document. + */ +char *dmixml_GetAttrValue(xmlNode *node, const char *key) { + xmlAttr *aptr = NULL; + xmlChar *key_s = NULL; + + if( node == NULL ) { + return NULL; + } + + key_s = xmlCharStrdup(key); + assert( key_s != NULL ); + + for( aptr = node->properties; aptr != NULL; aptr = aptr->next ) { + if( xmlStrcmp(aptr->name, key_s) == 0 ) { + free(key_s); key_s = NULL; + // FIXME: Should find better way how to return UTF-8 data + return (char *)(aptr->children != NULL ? aptr->children->content : NULL); + } + } + free(key_s); key_s = NULL; + return NULL; +} + +/** + * Internal function - Retrieve a pointer to an XML node based on tag name and a specified attribute + * value. To get a hit, tag name and the attribute must be found and the value of the attribute must + * match as well. The function will traverse all children nodes of the given input node, but it will + * not go deeper. + * @author David Sommerseth <davids@redhat.com> + * @author Nima Talebi <nima@autonomy.net.au> + * @param xmlNode* Pointer to the XML node of where to start searching + * @param const char* Tag name the function will search for + * @param const char* Attribute to check for in the tag + * @param const char* Value of the attribute which must match to have a hit + * @param int Be case sensitive or not. 1 == case sensitive, 0 == case insensitive + * @return xmlNode* Pointer to the found XML node, NULL if no tag was found. + */ +xmlNode *__dmixml_FindNodeByAttr(xmlNode *node, const char *tagkey, const char *attrkey, + const char *val, int casesens) { + xmlNode *ptr_n = NULL; + xmlChar *tag_s = NULL; + int (*compare_func) (const char *, const char *); + + assert( node != NULL ); + if( node->children == NULL ) { + return NULL; + } + + tag_s = xmlCharStrdup(tagkey); + assert( tag_s != NULL ); + + compare_func = (casesens == 1 ? strcmp : strcasecmp); + + foreach_xmlnode(node->children, ptr_n) { + // To return the correct node, we need to check node type, + // tag name and the attribute value of the given attribute. + if( (ptr_n->type == XML_ELEMENT_NODE) + && (xmlStrcmp(ptr_n->name, tag_s) == 0) + && (compare_func(dmixml_GetAttrValue(ptr_n, attrkey), val) == 0 ) ) { + goto exit; + } + } + exit: + free(tag_s); tag_s = NULL; + return ptr_n; +} + +/** + * Retrieve a poitner to an XML node with the given name. The function will traverse + * all children nodes of the given input node, but it will not go deeper. The function + * will only return the first hit. + * @author David Sommerseth <davids@redhat.com> + * @param xmlNode* Pointer to the XML node of where to start searching + * @param const char* Name of the tag name the function will look for. + * @return xmlNode* Pointer to the found XML node, NULL if no tag was found. + */ +xmlNode *dmixml_FindNode(xmlNode *node, const char *key) { + xmlNode *ptr_n = NULL; + xmlChar *key_s = NULL; + + if( node->children == NULL ) { + return NULL; + } + + key_s = xmlCharStrdup(key); + assert( key_s != NULL ); + + for( ptr_n = node->children; ptr_n != NULL; ptr_n = ptr_n->next ) { + if( (ptr_n->type == XML_ELEMENT_NODE) + && (xmlStrcmp(ptr_n->name, key_s) == 0) ) { + free(key_s); key_s = NULL; + return ptr_n; + } + } + free(key_s); key_s = NULL; + return NULL; +} + +/** + * Retrieve the text contents of the given XML node + * @author David Sommerseth <davids@redhat.com> + * @param xmlNode* Pointer to the XML node of which we want to extract the contents + * @return char* Pointer to the tag contents if found, otherwise NULL. This value + * must NOT be freed, as it points directly into the value in the XML document. + */ +inline char *dmixml_GetContent(xmlNode *node) { + // FIXME: Should find better way how to return UTF-8 data + return (((node != NULL) && (node->children != NULL)) ? (char *) node->children->content : NULL); +} + +/** + * Retrieve the text content of a given tag. The function will traverse + * all children nodes of the given input node, but it will not go deeper. + * The function will only return the first hit. + * @author David Sommerseth <davids@redhat.com> + * @param xmlNode* Pointer to the XML node of where to start searching + * @param const char* Name of the tag the function will look for + * @return char* Pointer to the tag contents if found, otherwise NULL. This value + * must NOT be freed, as it points directly into the value in the XML document. + */ +inline char *dmixml_GetNodeContent(xmlNode *node, const char *key) { + return dmixml_GetContent(dmixml_FindNode(node, key)); +} + +/** + * Retrieve the contents from an XPath object. + * @author David Sommerseth <davids@redhat.com> + * @param char* Pointer to a buffer where to return the value + * @param size_t Size of the return buffer + * @param xmlXPathObject* Pointer to the XPath object containing the data + * @param int If the XPath object contains a node set, this defines + * which of the elements to be extracted. + * @return char* Points at the return buffer if a value is found, otherwise NULL is returned. + */ +char *dmixml_GetXPathContent(char *buf, size_t buflen, xmlXPathObject *xpo, int idx) { + memset(buf, 0, buflen); + + if( xpo == NULL ) { + return NULL; + } + + switch( xpo->type ) { + case XPATH_STRING: + strncpy(buf, (char *)xpo->stringval, buflen-1); + break; + + case XPATH_NUMBER: + snprintf(buf, buflen-1, "%f", xpo->floatval); + break; + + case XPATH_NODESET: + if( (xpo->nodesetval != NULL) && (xpo->nodesetval->nodeNr >= (idx+1)) ) { + char *str = dmixml_GetContent(xpo->nodesetval->nodeTab[idx]); + if( str != NULL ) { + strncpy(buf, str, buflen-1); + } else { + memset(buf, 0, buflen); + } + } + break; + + default: + fprintf(stderr, "dmixml_GetXPathContent(...):: " + "Do not know how to handle XPath type %i\n", + xpo->type); + return NULL; + } + return buf; +} |