a3f6899ef9ae0d8a2d1e0408fbb2957360bf1156
1 /*
2 * Inkscape::Debug::Logger - debug logging facility
3 *
4 * Authors:
5 * MenTaLguY <mental@rydia.net>
6 *
7 * Copyright (C) 2005 MenTaLguY
8 *
9 * Released under GNU GPL, read the file 'COPYING' for more information
10 */
12 #include <fstream>
13 #include <vector>
14 #include <glib/gmessages.h>
15 #include "debug/logger.h"
16 #include "debug/simple-event.h"
17 #include "gc-alloc.h"
19 namespace Inkscape {
21 namespace Debug {
23 bool Logger::_enabled=false;
24 bool Logger::_category_mask[Event::N_CATEGORIES];
26 namespace {
28 static void write_escaped_value(std::ostream &os, Util::ptr_shared<char> value) {
29 for ( char const *current=value ; *current ; ++current ) {
30 switch (*current) {
31 case '&':
32 os << "&";
33 break;
34 case '"':
35 os << """;
36 break;
37 case '\'':
38 os << "'";
39 break;
40 case '<':
41 os << "<";
42 break;
43 case '>':
44 os << ">";
45 break;
46 default:
47 os.put(*current);
48 }
49 }
50 }
52 static void write_indent(std::ostream &os, unsigned depth) {
53 for ( unsigned i = 0 ; i < depth ; i++ ) {
54 os.write(" ", 2);
55 }
56 }
58 static std::ofstream log_stream;
59 static bool empty_tag=false;
60 typedef std::vector<Util::ptr_shared<char>, GC::Alloc<Util::ptr_shared<char>, GC::MANUAL> > TagStack;
61 static TagStack &tag_stack() {
62 static TagStack stack;
63 return stack;
64 }
66 static void do_shutdown() {
67 Debug::Logger::shutdown();
68 }
70 static bool equal_range(char const *c_string,
71 char const *start, char const *end)
72 {
73 return !std::strncmp(start, c_string, end - start) &&
74 !c_string[end - start];
75 }
77 static void set_category_mask(bool * const mask, char const *filter) {
78 if (!filter) {
79 for ( unsigned i = 0 ; i < Event::N_CATEGORIES ; i++ ) {
80 mask[i] = true;
81 }
82 return;
83 } else {
84 for ( unsigned i = 0 ; i < Event::N_CATEGORIES ; i++ ) {
85 mask[i] = false;
86 }
87 mask[Event::CORE] = true;
88 }
90 char const *start;
91 char const *end;
92 start = end = filter;
93 while (*end) {
94 while ( *end && *end != ',' ) { end++; }
95 if ( start != end ) {
96 if (equal_range("CORE", start, end)) {
97 mask[Event::CORE] = true;
98 } else if (equal_range("XML", start, end)) {
99 mask[Event::XML] = true;
100 } else if (equal_range("SPOBJECT", start, end)) {
101 mask[Event::SPOBJECT] = true;
102 } else if (equal_range("DOCUMENT", start, end)) {
103 mask[Event::DOCUMENT] = true;
104 } else if (equal_range("REFCOUNT", start, end)) {
105 mask[Event::REFCOUNT] = true;
106 } else if (equal_range("EXTENSION", start, end)) {
107 mask[Event::EXTENSION] = true;
108 } else {
109 g_warning("Unknown debugging category %*s", end - start, start);
110 }
111 }
112 if (*end) {
113 start = end = end + 1;
114 }
115 }
116 }
118 }
120 void Logger::init() {
121 if (!_enabled) {
122 char const *log_filename=std::getenv("INKSCAPE_DEBUG_LOG");
123 if (log_filename) {
124 log_stream.open(log_filename);
125 if (log_stream.is_open()) {
126 char const *log_filter=std::getenv("INKSCAPE_DEBUG_FILTER");
127 set_category_mask(_category_mask, log_filter);
128 log_stream << "<?xml version=\"1.0\"?>\n";
129 log_stream.flush();
130 _enabled = true;
131 start<SimpleEvent<Event::CORE> >(Util::share_static_string("session"));
132 std::atexit(&do_shutdown);
133 }
134 }
135 }
136 }
138 void Logger::_start(Event const &event) {
139 Util::ptr_shared<char> name=event.name();
141 if (empty_tag) {
142 log_stream << ">\n";
143 }
145 write_indent(log_stream, tag_stack().size());
147 log_stream << "<" << name.pointer();
149 unsigned property_count=event.propertyCount();
150 for ( unsigned i = 0 ; i < property_count ; i++ ) {
151 Event::PropertyPair property=event.property(i);
152 log_stream << " " << property.name.pointer() << "=\"";
153 write_escaped_value(log_stream, property.value);
154 log_stream << "\"";
155 }
157 log_stream.flush();
159 tag_stack().push_back(name);
160 empty_tag = true;
161 }
163 void Logger::_skip() {
164 tag_stack().push_back(Util::ptr_shared<char>());
165 }
167 void Logger::_finish() {
168 if (tag_stack().back()) {
169 if (empty_tag) {
170 log_stream << "/>\n";
171 } else {
172 write_indent(log_stream, tag_stack().size() - 1);
173 log_stream << "</" << tag_stack().back().pointer() << ">\n";
174 }
175 log_stream.flush();
177 empty_tag = false;
178 }
180 tag_stack().pop_back();
181 }
183 void Logger::shutdown() {
184 if (_enabled) {
185 while (!tag_stack().empty()) {
186 finish();
187 }
188 }
189 }
191 }
193 }
195 /*
196 Local Variables:
197 mode:c++
198 c-file-style:"stroustrup"
199 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
200 indent-tabs-mode:nil
201 fill-column:99
202 End:
203 */
204 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :