diff --git a/doc/glmark2.1.in b/doc/glmark2.1.in index cd8399e0..9dcfb8a6 100644 --- a/doc/glmark2.1.in +++ b/doc/glmark2.1.in @@ -55,7 +55,7 @@ Run in fullscreen mode (equivalent to --size -1x-1) The types of results to report for each benchmark, as a ':' separated list [fps,cpu,shader] .TP \fB\-\-results-file\fR RESULTS-FILE -The file to save the results to, in the format determined by the file extension [csv] +The file to save the results to, in the format determined by the file extension [csv,xml] .TP \fB\-\-winsys-options\fR OPTS A list of 'opt=value' pairs for window system specific options, separated by ':' diff --git a/src/options.cpp b/src/options.cpp index f01aa708..8d1ec16e 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -223,7 +223,7 @@ Options::print_help() " --results RESULTS The types of results to report for each benchmark,\n" " as a ':' separated list [fps,cpu,shader]\n" " --results-file F The file to save the results to, in the format determined\n" - " by the file extension [csv]\n" + " by the file extension [csv,xml]\n" " --winsys-options O A list of 'opt=value' pairs for window system specific\n" " options, separated by ':'\n" " -l, --list-scenes Display information about the available scenes\n" diff --git a/src/results-file.cpp b/src/results-file.cpp index f0777619..5762ab72 100644 --- a/src/results-file.cpp +++ b/src/results-file.cpp @@ -104,6 +104,72 @@ class CSVResultsFile : public ResultsFile bool first_field = true; }; +std::string xml_text_escape(const std::string &str) +{ + std::stringstream ss; + + for (auto c : str) + { + switch (c) + { + case '<': ss << "<"; break; + case '>': ss << ">"; break; + case '&': ss << "&"; break; + default: ss << c; break; + } + } + + return ss.str(); +} + +class XMLResultsFile : public ResultsFile +{ +public: + XMLResultsFile(std::ofstream &&fs) : fs{std::move(fs)} {} + + std::string type() override { return "XML"; } + + void begin() override + { + fs << "" << std::endl; + fs << "" << std::endl; + } + + void end() override + { + fs << "" << std::endl; + } + + void begin_info() override + { + fs << " " << std::endl; + } + + void end_info() override + { + fs << " " << std::endl; + } + + void begin_benchmark() override + { + fs << " " << std::endl; + } + + void end_benchmark() override + { + fs << " " << std::endl; + } + + void add_field(const std::string &name, const std::string &value) override + { + std::string escaped = xml_text_escape(value); + fs << " <" << name << ">" << escaped << "" << std::endl; + } + +private: + std::ofstream fs; +}; + std::string get_file_extension(const std::string &str) { auto i = str.rfind('.'); @@ -144,6 +210,10 @@ bool ResultsFile::init(const std::string &file) { ResultsFile::singleton = std::make_unique(std::move(fs)); } + else if (ext == ".xml") + { + ResultsFile::singleton = std::make_unique(std::move(fs)); + } else { Log::error("Results file type %s is not supported\n", file.c_str());