Signed-off-by: Xu Wang <gesaint(a)linux.vnet.ibm.com>
---
libxkutil/device_parsing.c | 297 ++++++++++++++++++++++++++++++++++++++++++++
libxkutil/device_parsing.h | 25 ++++-
2 files changed, 320 insertions(+), 2 deletions(-)
diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c
index f1da880..e95b0a9 100644
--- a/libxkutil/device_parsing.c
+++ b/libxkutil/device_parsing.c
@@ -404,6 +404,303 @@ char *get_node_content(xmlNode *node)
return buf;
}
+/*
+ * This function is just used for debugging. If you found something wrong
+ * please call this function and check the result of output in the logs.
+ */
+void print_others(struct others *head)
+{
+ CU_DEBUG("**************************************************");
+ while (head) {
+ CU_DEBUG("---------------------------");
+ CU_DEBUG("- others id: %d", head->id);
+ CU_DEBUG("- others name: %s", head->name);
+ CU_DEBUG("- others value: %s", head->value);
+ CU_DEBUG("- others type: %d", head->type);
+ CU_DEBUG("- others parent_id: %d", head->parent_id);
+ CU_DEBUG("- others parent_name: %s", head->parent_name);
+ if (head->status == ACTIVE) {
+ CU_DEBUG("- others status: ACTIVE");
+ } else {
+ CU_DEBUG("- others status: INACTIVE");
+ }
+ CU_DEBUG("---------------------------");
+ head = head->next;
+ }
+ CU_DEBUG("**************************************************");
+}
+
+/*
+ * Add one node into head link list. All items are set as parameters.
+ *
+ * @head: The link list head pointer to be added.
+ * @node: Where the value of node come from.
+ * @name: Name of this link list node (maybe a node or an attribute in xml).
+ * @type: TYPE_NODE: Stands for the value from a xml node.
+ * TYPE_PROP: Means that this value is an attribute of a node.
+ * @parent_id: The id of parent node.
+ * @parent_name: Name of parent node.
+ */
+static struct others *add_others(struct others *head,
+ xmlNode *node,
+ const xmlChar *name,
+ enum others_type type,
+ int parent_id,
+ const xmlChar *parent_name)
+{
+ struct others *new = NULL;
+ struct others *end = head;
+
+ new = calloc(1, sizeof(*new));
+ if (new == NULL) {
+ CU_DEBUG("calloc space failed.");
+ return NULL;
+ }
+
+ new->id = 0;
+ new->name = strdup((char *)name);
+ new->parent_id = parent_id;
+ if (parent_name) {
+ new->parent_name = strdup((char *)parent_name);
+ }
+ new->type = type;
+ if (type == TYPE_PROP) {
+ new->value = get_attr_value(node, (char *)name);
+ } else if (type == TYPE_NODE) {
+ new->value = get_node_content(node);
+ }
+ new->next = NULL;
+
+ if (head == NULL) {
+ head = new;
+ } else {
+ /* Seek to the end of link list and calculate conflicts */
+ while (end) {
+ if (STREQ(end->name, (char *)name) &&
+ end->type == type) {
+ /* id conflict, +1 */
+ new->id++;
+ }
+ if (end->next) {
+ end = end->next;
+ } else {
+ break;
+ }
+ }
+ end->next = new;
+ }
+ new->status = ACTIVE;
+
+ return head;
+}
+
+bool compare_param_int(int a, int b)
+{
+ if (a == -1 || b == -1) {
+ return true;
+ } else if (a == b) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool compare_param_str(const char *a, const char *b)
+{
+ if (a == NULL || b == NULL) {
+ return true;
+ } else if (STREQ(a, b)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*
+ * This function is the main operation for members of virtual device structure.
+ * The whole data of xml is saved in the others link list. By calling this
+ * function each variable of virtual device could get the value it wanted.
+ * After value was fetched, the node in the others link list to be INACTIVE
+ * status.
+ *
+ * @head: The link list saved all data needed.
+ * @id: Id of name, to identify different nodes but with same name.
+ * @name: Name of node the caller want to get value.
+ * @type: TYPE_NODE: Caller want to get a value of node.
+ * TYPE_PROP: Caller want to get a value of attribute.
+ * @parent_id: The id of parent node caller want.
+ * @parent_name: The name of parent node caller want.
+ *
+ * If caller doesn't want to point @id, @parent_id or @parent_name,
+ * @id could be set as -1, @parent_id and @parent_name should be
+ * set as NULL.
+ */
+char *fetch_from_others(struct others **head,
+ int id,
+ char *name,
+ enum others_type type,
+ int parent_id,
+ char *parent_name)
+{
+ struct others *tmp = *head;
+ char *value = NULL;
+
+ while (tmp) {
+ if (compare_param_int(tmp->id, id) &&
+ STREQ(tmp->name, name) &&
+ compare_param_int(tmp->parent_id, parent_id) &&
+ compare_param_str(tmp->parent_name, parent_name) &&
+ tmp->type == type &&
+ tmp->status == ACTIVE) {
+ value = strdup(tmp->value);
+ tmp->status = INACTIVE;
+ return value;
+ }
+ tmp = tmp->next;
+ }
+
+ return NULL;
+}
+
+/*
+ * This function seeks in the others link list and return the result of
+ * seeking. If success the node seeked will to be INACTIVE status.
+ *
+ * @head: The link list head pointer to be seeked.
+ * @id: Id of node to be seeked.
+ * @name: Name of node to be seeked.
+ * @type: TYPE_NODE: The node to be seeked is a node of xml.
+ * TYPE_PROP: The node to be seeked is a attribute of a node.
+ * @parent_id: Id of parent node which to be seeked.
+ * @parent_name: Name of parent node which to be seeked.
+ *
+ * If the caller doesn't point @id, @parent_id or @parent_name, they should
+ * be set as -1, -1 or NULL. Other parameters is mandantory.
+ */
+static bool seek_in_others(struct others **head,
+ int id,
+ char *name,
+ enum others_type type,
+ int parent_id,
+ char *parent_name)
+{
+ struct others *tmp = *head;
+
+ while (tmp) {
+ if (compare_param_int(tmp->id, id) &&
+ STREQ(tmp->name, name) &&
+ compare_param_int(tmp->parent_id, parent_id) &&
+ compare_param_str(tmp->parent_name, parent_name) &&
+ tmp->type == type &&
+ tmp->status == ACTIVE) {
+ tmp->status = INACTIVE;
+ return true;
+ }
+ tmp = tmp->next;
+ }
+
+ return false;
+}
+
+struct others *combine_others(struct others *head1,
+ struct others *head2)
+{
+ struct others *tail1 = head1;
+
+ if (tail1 == NULL) {
+ return head2;
+ }
+
+ while (tail1->next) {
+ tail1 = tail1->next;
+ }
+
+ tail1->next = head2;
+ return head1;
+}
+
+static struct others *seek_to_tail(struct others *others)
+{
+ if (others == NULL) {
+ return NULL;
+ }
+
+ while (others->next) {
+ others = others->next;
+ }
+
+ return others;
+}
+
+/*
+ * Parse all data from xml and build a link list to save it.
+ *
+ * @head: Where data from xml to save.
+ * @node: The root node of xml to be parsed.
+ * @parent_id: Parent node id of root node, usually zero.
+ * @parent_name: Parent node name of root node.
+ */
+static struct others *parse_data_to_others(struct others *head,
+ xmlNode *node,
+ int parent_id,
+ const xmlChar *parent_name)
+{
+ xmlNode *child = NULL;
+ xmlAttrPtr attrPtr = NULL;
+ struct others *tail = NULL;
+ int tail_id = 0;
+
+ /* If name of node is "text", all operations will skip */
+ if (XSTREQ(node->name, "text")) {
+ return head;
+ }
+
+ head = add_others(head,
+ node,
+ node->name,
+ TYPE_NODE,
+ parent_id,
+ parent_name);
+
+ if (head == NULL) {
+ goto err;
+ }
+
+ /* tail is the node we added above */
+ tail = seek_to_tail(head);
+ if (tail == NULL) {
+ tail_id = 0;
+ } else {
+ tail_id = tail->id;
+ }
+
+ /* Get properties of node */
+ attrPtr = node->properties;
+ while (attrPtr) {
+ head = add_others(head,
+ node,
+ attrPtr->name,
+ TYPE_PROP,
+ tail_id,
+ node->name);
+ if (head == NULL) {
+ goto err;
+ }
+
+ attrPtr = attrPtr->next;
+ }
+
+ for (child = node->children; child != NULL; child = child->next) {
+ /* Recursion to restore child's properties or child if have */
+ head = parse_data_to_others(head, child, tail_id, node->name);
+ }
+
+ return head;
+err:
+ CU_DEBUG("add_others failed.");
+ return NULL;
+}
+
static int parse_fs_device(xmlNode *dnode, struct virt_device **vdevs)
{
struct virt_device *vdev = NULL;
diff --git a/libxkutil/device_parsing.h b/libxkutil/device_parsing.h
index 147551a..ee9b515 100644
--- a/libxkutil/device_parsing.h
+++ b/libxkutil/device_parsing.h
@@ -48,10 +48,10 @@ struct others {
enum others_type type;
char *value;
struct others *next;
- enum status {
+ enum {
ACTIVE,
INACTIVE
- };
+ } status;
};
/* The structure for saving unknown device */
@@ -310,6 +310,27 @@ int attach_device(virDomainPtr dom, struct virt_device *dev);
int detach_device(virDomainPtr dom, struct virt_device *dev);
int change_device(virDomainPtr dom, struct virt_device *dev);
+char *fetch_from_others(struct others **head,
+ int id,
+ char *name,
+ enum others_type type,
+ int parent_id,
+ char *parent_name);
+
+void cleanup_node_of_others(struct others *others);
+
+bool compare_parent(const char *a, const char *b);
+
+void print_others(struct others *head);
+
+void cleanup_others(struct others *others);
+
+struct others *combine_others(struct others *head1, struct others *head2);
+
+bool compare_param_int(int a, int b);
+
+bool compare_param_str(const char *a, const char *b);
+
#define XSTREQ(x, y) (STREQ((char *)x, y))
#define STRPROP(d, p, n) (d->p = get_node_content(n))
--
1.7.1