michael@0: /* GRAPHITE2 LICENSING michael@0: michael@0: Copyright 2010, SIL International michael@0: All rights reserved. michael@0: michael@0: This library is free software; you can redistribute it and/or modify michael@0: it under the terms of the GNU Lesser General Public License as published michael@0: by the Free Software Foundation; either version 2.1 of License, or michael@0: (at your option) any later version. michael@0: michael@0: This program is distributed in the hope that it will be useful, michael@0: but WITHOUT ANY WARRANTY; without even the implied warranty of michael@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU michael@0: Lesser General Public License for more details. michael@0: michael@0: You should also have received a copy of the GNU Lesser General Public michael@0: License along with this library in the file named "LICENSE". michael@0: If not, write to the Free Software Foundation, 51 Franklin Street, michael@0: Suite 500, Boston, MA 02110-1335, USA or visit their web page on the michael@0: internet at http://www.fsf.org/licenses/lgpl.html. michael@0: michael@0: Alternatively, the contents of this file may be used under the terms of the michael@0: Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public michael@0: License, as published by the Free Software Foundation, either version 2 michael@0: of the License or (at your option) any later version. michael@0: */ michael@0: michael@0: #include michael@0: #include michael@0: #include "Main.h" michael@0: #include "XmlTraceLog.h" michael@0: michael@0: michael@0: using namespace graphite2; michael@0: michael@0: #ifndef DISABLE_TRACING michael@0: michael@0: /*static*/ XmlTraceLog XmlTraceLog::sm_NullLog(NULL, NULL, GRLOG_NONE); michael@0: XmlTraceLog * XmlTraceLog::sLog = &sm_NullLog; michael@0: michael@0: XmlTraceLog::XmlTraceLog(FILE * file, const char * ns, GrLogMask logMask) michael@0: : m_file(file), m_depth(0), m_mask(logMask) michael@0: { michael@0: if (!m_file) return; michael@0: int deep = 0; michael@0: #ifdef ENABLE_DEEP_TRACING michael@0: deep = 1; michael@0: #endif michael@0: fprintf(m_file, "\n<%s xmlns=\"%s\" mask=\"%x\" deep=\"%d\">", michael@0: xmlTraceLogElements[ElementTopLevel].mName, ns, logMask, deep); michael@0: m_elementStack[m_depth++] = ElementTopLevel; michael@0: m_elementEmpty = true; michael@0: m_inElement = false; michael@0: m_lastNodeText = false; michael@0: } michael@0: michael@0: XmlTraceLog::~XmlTraceLog() michael@0: { michael@0: if (m_file && m_file != stdout && m_file != stderr) michael@0: { michael@0: assert(m_depth == 1); michael@0: while (m_depth > 0) michael@0: { michael@0: closeElement(m_elementStack[m_depth-1]); michael@0: } michael@0: fclose(m_file); michael@0: m_file = NULL; michael@0: } michael@0: } michael@0: michael@0: void XmlTraceLog::addSingleElement(XmlTraceLogElement eId, const int value) michael@0: { michael@0: if (!m_file) return; michael@0: if (m_inElement) michael@0: { michael@0: if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask) michael@0: fprintf(m_file, ">"); michael@0: } michael@0: if (xmlTraceLogElements[eId].mFlags & m_mask) michael@0: { michael@0: if (!m_lastNodeText) michael@0: { michael@0: fprintf(m_file, "\n"); michael@0: for (size_t i = 0; i < m_depth; i++) michael@0: { michael@0: fprintf(m_file, " "); michael@0: } michael@0: } michael@0: fprintf(m_file, "<%s val=\"%d\"/>", xmlTraceLogElements[eId].mName, value); michael@0: } michael@0: m_inElement = false; michael@0: m_lastNodeText = false; michael@0: } michael@0: michael@0: void XmlTraceLog::writeElementArray(XmlTraceLogElement eId, XmlTraceLogAttribute aId, int16 values [], size_t length) michael@0: { michael@0: if (!m_file) return; michael@0: if (xmlTraceLogElements[eId].mFlags & m_mask) michael@0: { michael@0: if(m_inElement && xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask) michael@0: { michael@0: fprintf(m_file, ">"); michael@0: m_inElement = false; michael@0: } michael@0: // line break after 5 columns michael@0: for (size_t i = 0; i < length; i++) michael@0: { michael@0: if (i % 5 == 0) michael@0: { michael@0: fprintf(m_file, "\n"); michael@0: for (size_t j = 0; j < m_depth; j++) michael@0: { michael@0: fprintf(m_file, " "); michael@0: } michael@0: } michael@0: fprintf(m_file, "<%s index=\"%d\" %s=\"%d\"/>", xmlTraceLogElements[eId].mName, int(i), michael@0: xmlTraceLogAttributes[aId], (int)values[i]); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void XmlTraceLog::writeText(const char * utf8) michael@0: { michael@0: if (!m_file) return; michael@0: if (m_inElement) michael@0: { michael@0: if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask) michael@0: { michael@0: fprintf(m_file, ">"); michael@0: } michael@0: m_inElement = false; michael@0: } michael@0: if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask) michael@0: { michael@0: escapeIfNeeded(utf8); michael@0: } michael@0: m_lastNodeText = true; michael@0: } michael@0: michael@0: void XmlTraceLog::writeUnicode(const uint32 code) michael@0: { michael@0: if (!m_file) return; michael@0: if (m_inElement) michael@0: { michael@0: if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask) michael@0: { michael@0: fprintf(m_file, ">"); michael@0: } michael@0: m_inElement = false; michael@0: } michael@0: if (xmlTraceLogElements[m_elementStack[m_depth-1]].mFlags & m_mask) michael@0: { michael@0: fprintf(m_file, "&#x%02x;", code); michael@0: } michael@0: m_lastNodeText = true; michael@0: } michael@0: michael@0: void XmlTraceLog::escapeIfNeeded(const char * data) michael@0: { michael@0: size_t length = strlen(data); michael@0: for (size_t i = 0; i < length; i++) michael@0: { michael@0: switch (data[i]) michael@0: { michael@0: case '<': michael@0: fprintf(m_file, "<"); michael@0: break; michael@0: case '>': michael@0: fprintf(m_file, ">"); michael@0: break; michael@0: case '&': michael@0: fprintf(m_file, "&"); michael@0: break; michael@0: case '"': michael@0: fprintf(m_file, """); michael@0: break; michael@0: default: michael@0: fprintf(m_file, "%c", data[i]); michael@0: } michael@0: } michael@0: } michael@0: michael@0: static const int MAX_MSG_LEN = 1024; michael@0: michael@0: void XmlTraceLog::error(const char * msg, ...) michael@0: { michael@0: if (!m_file) return; michael@0: openElement(ElementError); michael@0: va_list args; michael@0: va_start(args, msg); michael@0: char buffer[MAX_MSG_LEN]; michael@0: #ifndef NDEBUG michael@0: int len = michael@0: #endif michael@0: vsnprintf(buffer, MAX_MSG_LEN, msg, args); michael@0: assert(len + 1 < MAX_MSG_LEN); michael@0: writeText(buffer); michael@0: va_end(args); michael@0: closeElement(ElementError); michael@0: } michael@0: michael@0: void XmlTraceLog::warning(const char * msg, ...) michael@0: { michael@0: if (!m_file) return; michael@0: openElement(ElementWarning); michael@0: va_list args; michael@0: va_start(args, msg); michael@0: char buffer[MAX_MSG_LEN]; michael@0: #ifndef NDEBUG michael@0: int len = michael@0: #endif michael@0: vsnprintf(buffer, MAX_MSG_LEN, msg, args); michael@0: assert(len + 1 < MAX_MSG_LEN); michael@0: writeText(buffer); michael@0: va_end(args); michael@0: closeElement(ElementWarning); michael@0: } michael@0: michael@0: #endif //!DISABLE_TRACING