Code

Belarusian translation for 0.47, by Hleb Valoshka
[inkscape.git] / src / debug / logger.cpp
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 "inkscape-version.h"
16 #include "debug/logger.h"
17 #include "debug/simple-event.h"
18 #include "gc-alloc.h"
20 namespace Inkscape {
22 namespace Debug {
24 bool Logger::_enabled=false;
25 bool Logger::_category_mask[Event::N_CATEGORIES];
27 namespace {
29 static void write_escaped_value(std::ostream &os, Util::ptr_shared<char> value) {
30     for ( char const *current=value ; *current ; ++current ) {
31         switch (*current) {
32         case '&':
33             os << "&amp;";
34             break;
35         case '"':
36             os << "&quot;";
37             break;
38         case '\'':
39             os << "&apos;";
40             break;
41         case '<':
42             os << "&lt;";
43             break;
44         case '>':
45             os << "&gt;";
46             break;
47         default:
48             os.put(*current);
49         }
50     }
51 }
53 static void write_indent(std::ostream &os, unsigned depth) {
54     for ( unsigned i = 0 ; i < depth ; i++ ) {
55         os.write("  ", 2);
56     }
57 }
59 static std::ofstream log_stream;
60 static bool empty_tag=false;
61 typedef std::vector<Util::ptr_shared<char>, GC::Alloc<Util::ptr_shared<char>, GC::MANUAL> > TagStack;
62 static TagStack &tag_stack() {
63     static TagStack stack;
64     return stack;
65 }
67 static void do_shutdown() {
68     Debug::Logger::shutdown();
69 }
71 static bool equal_range(char const *c_string,
72                         char const *start, char const *end)
73 {
74     return !std::strncmp(start, c_string, end - start) &&
75            !c_string[end - start];
76 }
78 static void set_category_mask(bool * const mask, char const *filter) {
79     if (!filter) {
80         for ( unsigned i = 0 ; i < Event::N_CATEGORIES ; i++ ) {
81             mask[i] = true;
82         }
83         return;
84     } else {
85         for ( unsigned i = 0 ; i < Event::N_CATEGORIES ; i++ ) {
86             mask[i] = false;
87         }
88         mask[Event::CORE] = true;
89     }
91     char const *start;
92     char const *end;
93     start = end = filter;
94     while (*end) {
95         while ( *end && *end != ',' ) { end++; }
96         if ( start != end ) {
97             struct CategoryName {
98                 char const *name;
99                 Event::Category category;
100             };
101             static const CategoryName category_names[] = {
102                 { "CORE", Event::CORE },
103                 { "XML", Event::XML },
104                 { "SPOBJECT", Event::SPOBJECT },
105                 { "DOCUMENT", Event::DOCUMENT },
106                 { "REFCOUNT", Event::REFCOUNT },
107                 { "EXTENSION", Event::EXTENSION },
108                 { "FINALIZERS", Event::FINALIZERS },
109                 { "INTERACTION", Event::INTERACTION },
110                 { "CONFIGURATION", Event::CONFIGURATION },
111                 { "OTHER", Event::OTHER },
112                 { NULL, Event::OTHER }
113             };
114             CategoryName const *iter;
115             for ( iter = category_names ; iter->name ; iter++ ) {
116                 if (equal_range(iter->name, start, end)) {
117                     mask[iter->category] = true;
118                     break;
119                 }
120             }
121             if (!iter->name) {
122                 g_warning("Unknown debugging category %*s", (int)(end - start), start);
123             }
124         }
125         if (*end) {
126             start = end = end + 1;
127         }
128     }
131 typedef SimpleEvent<Event::CORE> CoreEvent;
133 class SessionEvent : public CoreEvent {
134 public:
135     SessionEvent() : CoreEvent(Util::share_static_string("session")) {
136         _addProperty("inkscape-version", Inkscape::version_string);
137     }
138 };
142 void Logger::init() {
143     if (!_enabled) {
144         char const *log_filename=std::getenv("INKSCAPE_DEBUG_LOG");
145         if (log_filename) {
146             log_stream.open(log_filename);
147             if (log_stream.is_open()) {
148                 char const *log_filter=std::getenv("INKSCAPE_DEBUG_FILTER");
149                 set_category_mask(_category_mask, log_filter);
150                 log_stream << "<?xml version=\"1.0\"?>\n";
151                 log_stream.flush();
152                 _enabled = true;
153                 start<SessionEvent>();
154                 std::atexit(&do_shutdown);
155             }
156         }
157     }
160 void Logger::_start(Event const &event) {
161     Util::ptr_shared<char> name=event.name();
163     if (empty_tag) {
164         log_stream << ">\n";
165     }
167     write_indent(log_stream, tag_stack().size());
169     log_stream << "<" << name.pointer();
171     unsigned property_count=event.propertyCount();
172     for ( unsigned i = 0 ; i < property_count ; i++ ) {
173         Event::PropertyPair property=event.property(i);
174         log_stream << " " << property.name.pointer() << "=\"";
175         write_escaped_value(log_stream, property.value);
176         log_stream << "\"";
177     }
179     log_stream.flush();
181     tag_stack().push_back(name);
182     empty_tag = true;
184     event.generateChildEvents();
187 void Logger::_skip() {
188     tag_stack().push_back(Util::ptr_shared<char>());
191 void Logger::_finish() {
192     if (tag_stack().back()) {
193         if (empty_tag) {
194             log_stream << "/>\n";
195         } else {
196             write_indent(log_stream, tag_stack().size() - 1);
197             log_stream << "</" << tag_stack().back().pointer() << ">\n";
198         }
199         log_stream.flush();
201         empty_tag = false;
202     }
204     tag_stack().pop_back();
207 void Logger::shutdown() {
208     if (_enabled) {
209         while (!tag_stack().empty()) {
210             finish();
211         }
212     }
219 /*
220   Local Variables:
221   mode:c++
222   c-file-style:"stroustrup"
223   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
224   indent-tabs-mode:nil
225   fill-column:99
226   End:
227 */
228 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :