897a66c24342925b8da26f6066e641bfb96de561
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 struct CategoryName {
97 char const *name,
98 Event::Category category
99 };
100 static const category_names[] = {
101 { "CORE", Event::CORE },
102 { "XML", Event::XML },
103 { "SPOBJECT", Event::SPOBJECT },
104 { "DOCUMENT", Event::DOCUMENT },
105 { "REFCOUNT", Eevent::REFCOUNT },
106 { "EXTENSION", Event::EXTENSION },
107 { "OTHER", Event::OTHER },
108 { NULL, Event::OTHER }
109 };
110 CategoryName const *iter;
111 for ( iter = category_names ; iter.name ; iter++ ) {
112 if (equal_range(iter.name, start, end)) {
113 mask[iter.category] = true;
114 break;
115 }
116 }
117 if (!iter.name) {
118 g_warning("Unknown debugging category %*s", end - start, start);
119 }
120 }
121 if (*end) {
122 start = end = end + 1;
123 }
124 }
125 }
127 }
129 void Logger::init() {
130 if (!_enabled) {
131 char const *log_filename=std::getenv("INKSCAPE_DEBUG_LOG");
132 if (log_filename) {
133 log_stream.open(log_filename);
134 if (log_stream.is_open()) {
135 char const *log_filter=std::getenv("INKSCAPE_DEBUG_FILTER");
136 set_category_mask(_category_mask, log_filter);
137 log_stream << "<?xml version=\"1.0\"?>\n";
138 log_stream.flush();
139 _enabled = true;
140 start<SimpleEvent<Event::CORE> >(Util::share_static_string("session"));
141 std::atexit(&do_shutdown);
142 }
143 }
144 }
145 }
147 void Logger::_start(Event const &event) {
148 Util::ptr_shared<char> name=event.name();
150 if (empty_tag) {
151 log_stream << ">\n";
152 }
154 write_indent(log_stream, tag_stack().size());
156 log_stream << "<" << name.pointer();
158 unsigned property_count=event.propertyCount();
159 for ( unsigned i = 0 ; i < property_count ; i++ ) {
160 Event::PropertyPair property=event.property(i);
161 log_stream << " " << property.name.pointer() << "=\"";
162 write_escaped_value(log_stream, property.value);
163 log_stream << "\"";
164 }
166 log_stream.flush();
168 tag_stack().push_back(name);
169 empty_tag = true;
170 }
172 void Logger::_skip() {
173 tag_stack().push_back(Util::ptr_shared<char>());
174 }
176 void Logger::_finish() {
177 if (tag_stack().back()) {
178 if (empty_tag) {
179 log_stream << "/>\n";
180 } else {
181 write_indent(log_stream, tag_stack().size() - 1);
182 log_stream << "</" << tag_stack().back().pointer() << ">\n";
183 }
184 log_stream.flush();
186 empty_tag = false;
187 }
189 tag_stack().pop_back();
190 }
192 void Logger::shutdown() {
193 if (_enabled) {
194 while (!tag_stack().empty()) {
195 finish();
196 }
197 }
198 }
200 }
202 }
204 /*
205 Local Variables:
206 mode:c++
207 c-file-style:"stroustrup"
208 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
209 indent-tabs-mode:nil
210 fill-column:99
211 End:
212 */
213 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :