2 * Copyright (C) ARM Limited 2013-2015. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
11 #include "CapturedXML.h"
13 #include "OlyUtility.h"
14 #include "SessionData.h"
18 XMLList(XMLList *const prev, mxml_node_t *const node) : mPrev(prev), mNode(node) {}
20 XMLList *getPrev() { return mPrev; }
21 mxml_node_t *getNode() const { return mNode; }
22 void setNode(mxml_node_t *const node) { mNode = node; }
24 static void free(XMLList *list) {
25 while (list != NULL) {
26 XMLList *prev = list->getPrev();
36 // Intentionally unimplemented
37 XMLList(const XMLList &);
38 XMLList &operator=(const XMLList &);
41 mxml_node_t *EventsXML::getTree() {
42 #include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len
44 mxml_node_t *xml = NULL;
47 // Avoid unused variable warning
50 // Load the provided or default events xml
51 if (gSessionData->mEventsXMLPath) {
52 strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
53 fl = fopen(path, "r");
55 xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
60 logg->logMessage("Unable to locate events.xml, using default");
61 xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK);
64 // Append additional events XML
65 if (gSessionData->mEventsXMLAppend) {
66 fl = fopen(gSessionData->mEventsXMLAppend, "r");
68 logg->logError("Unable to open additional events XML %s", gSessionData->mEventsXMLAppend);
71 mxml_node_t *append = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
74 mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
76 logg->logError("Unable to find <events> node in the events.xml, please ensure the first two lines of events XML starts with:\n"
77 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
82 XMLList *categoryList = NULL;
83 XMLList *eventList = NULL;
85 // Make list of all categories in xml
86 mxml_node_t *node = xml;
88 node = mxmlFindElement(node, xml, "category", NULL, NULL, MXML_DESCEND);
92 categoryList = new XMLList(categoryList, node);
95 // Make list of all events in xml
98 node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
102 eventList = new XMLList(eventList, node);
107 for (mxml_node_t *node = mxmlFindElement(append, append, "event", NULL, NULL, MXML_DESCEND),
108 *next = mxmlFindElement(node, append, "event", NULL, NULL, MXML_DESCEND);
110 node = next, next = mxmlFindElement(node, append, "event", NULL, NULL, MXML_DESCEND)) {
111 const char *const category = mxmlElementGetAttr(mxmlGetParent(node), "name");
112 const char *const title = mxmlElementGetAttr(node, "title");
113 const char *const name = mxmlElementGetAttr(node, "name");
114 if (category == NULL || title == NULL || name == NULL) {
115 logg->logError("Not all event XML nodes have the required title and name and parent name attributes");
119 // Replace any duplicate events
120 for (XMLList *event = eventList; event != NULL; event = event->getPrev()) {
121 const char *const category2 = mxmlElementGetAttr(mxmlGetParent(event->getNode()), "name");
122 const char *const title2 = mxmlElementGetAttr(event->getNode(), "title");
123 const char *const name2 = mxmlElementGetAttr(event->getNode(), "name");
124 if (category2 == NULL || title2 == NULL || name2 == NULL) {
125 logg->logError("Not all event XML nodes have the required title and name and parent name attributes");
129 if (strcmp(category, category2) == 0 && strcmp(title, title2) == 0 && strcmp(name, name2) == 0) {
130 logg->logMessage("Replacing counter %s %s: %s", category, title, name);
131 mxml_node_t *parent = mxmlGetParent(event->getNode());
132 mxmlDelete(event->getNode());
133 mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
134 event->setNode(node);
141 for (mxml_node_t *node = strcmp(mxmlGetElement(append), "category") == 0 ? append : mxmlFindElement(append, append, "category", NULL, NULL, MXML_DESCEND),
142 *next = mxmlFindElement(node, append, "category", NULL, NULL, MXML_DESCEND);
144 node = next, next = mxmlFindElement(node, append, "category", NULL, NULL, MXML_DESCEND)) {
145 // After replacing duplicate events, a category may be empty
146 if (mxmlGetFirstChild(node) == NULL) {
150 const char *const name = mxmlElementGetAttr(node, "name");
152 logg->logError("Not all event XML categories have the required name attribute");
156 // Merge identically named categories
158 for (XMLList *category = categoryList; category != NULL; category = category->getPrev()) {
159 const char *const name2 = mxmlElementGetAttr(category->getNode(), "name");
161 logg->logError("Not all event XML categories have the required name attribute");
165 if (strcmp(name, name2) == 0) {
166 logg->logMessage("Merging category %s", name);
168 mxml_node_t *child = mxmlGetFirstChild(node);
172 mxmlAdd(category->getNode(), MXML_ADD_AFTER, mxmlGetLastChild(category->getNode()), child);
183 // Add new categories
184 logg->logMessage("Appending category %s", name);
185 mxmlAdd(events, MXML_ADD_AFTER, mxmlGetLastChild(events), node);
188 XMLList::free(eventList);
189 XMLList::free(categoryList);
197 char *EventsXML::getXML() {
198 mxml_node_t *xml = getTree();
200 // Add dynamic events from the drivers
201 mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
203 logg->logError("Unable to find <events> node in the events.xml, please ensure the first two lines of events XML are:\n"
204 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
208 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
209 driver->writeEvents(events);
212 char *string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
218 void EventsXML::write(const char *path) {
222 snprintf(file, PATH_MAX, "%s/events.xml", path);
224 char *buf = getXML();
225 if (util->writeToDisk(file, buf) < 0) {
226 logg->logError("Error writing %s\nPlease verify the path.", file);