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