source: vendor/synergy/current/lib/base/CLog.cpp

Last change on this file was 2749, checked in by bird, 19 years ago

synergy v1.3.1 sources (zip).

File size: 6.6 KB
Line 
1/*
2 * synergy -- mouse and keyboard sharing utility
3 * Copyright (C) 2002 Chris Schoeneman
4 *
5 * This package is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * found in the file COPYING that should have accompanied this file.
8 *
9 * This package is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include "CLog.h"
16#include "CString.h"
17#include "CStringUtil.h"
18#include "LogOutputters.h"
19#include "CArch.h"
20#include "Version.h"
21#include <cstdio>
22#include <cstring>
23
24// names of priorities
25static const char* g_priority[] = {
26 "FATAL",
27 "ERROR",
28 "WARNING",
29 "NOTE",
30 "INFO",
31 "DEBUG",
32 "DEBUG1",
33 "DEBUG2"
34 };
35
36// number of priorities
37static const int g_numPriority = (int)(sizeof(g_priority) /
38 sizeof(g_priority[0]));
39
40// the default priority
41#if defined(NDEBUG)
42static const int g_defaultMaxPriority = 4;
43#else
44static const int g_defaultMaxPriority = 5;
45#endif
46
47// length of longest string in g_priority
48static const int g_maxPriorityLength = 7;
49
50// length of suffix string (": ")
51static const int g_prioritySuffixLength = 2;
52
53// amount of padded required to fill in the priority prefix
54static const int g_priorityPad = g_maxPriorityLength +
55 g_prioritySuffixLength;
56
57
58//
59// CLog
60//
61
62CLog* CLog::s_log = NULL;
63
64CLog::CLog()
65{
66 assert(s_log == NULL);
67
68 // create mutex for multithread safe operation
69 m_mutex = ARCH->newMutex();
70
71 // other initalization
72 m_maxPriority = g_defaultMaxPriority;
73 m_maxNewlineLength = 0;
74 insert(new CConsoleLogOutputter);
75}
76
77CLog::~CLog()
78{
79 // clean up
80 for (COutputterList::iterator index = m_outputters.begin();
81 index != m_outputters.end(); ++index) {
82 delete *index;
83 }
84 for (COutputterList::iterator index = m_alwaysOutputters.begin();
85 index != m_alwaysOutputters.end(); ++index) {
86 delete *index;
87 }
88 ARCH->closeMutex(m_mutex);
89 s_log = NULL;
90}
91
92CLog*
93CLog::getInstance()
94{
95 // note -- not thread safe; client must initialize log safely
96 if (s_log == NULL) {
97 s_log = new CLog;
98 }
99 return s_log;
100}
101
102void
103CLog::print(const char* file, int line, const char* fmt, ...) const
104{
105 // check if fmt begins with a priority argument
106 int priority = 4;
107 if (fmt[0] == '%' && fmt[1] == 'z') {
108 priority = fmt[2] - '\060';
109 fmt += 3;
110 }
111
112 // done if below priority threshold
113 if (priority > getFilter()) {
114 return;
115 }
116
117 // compute prefix padding length
118 char stack[1024];
119 int pPad = g_priorityPad;
120 if (file != NULL) {
121 sprintf(stack, "%d", line);
122 pPad += strlen(file) + 1 /* comma */ +
123 strlen(stack) + 1 /* colon */ + 1 /* space */;
124 }
125
126 // compute suffix padding length
127 int sPad = m_maxNewlineLength;
128
129 // print to buffer, leaving space for a newline at the end and prefix
130 // at the beginning.
131 char* buffer = stack;
132 int len = (int)(sizeof(stack) / sizeof(stack[0]));
133 while (true) {
134 // try printing into the buffer
135 va_list args;
136 va_start(args, fmt);
137 int n = ARCH->vsnprintf(buffer + pPad, len - pPad - sPad, fmt, args);
138 va_end(args);
139
140 // if the buffer wasn't big enough then make it bigger and try again
141 if (n < 0 || n > (int)len) {
142 if (buffer != stack) {
143 delete[] buffer;
144 }
145 len *= 2;
146 buffer = new char[len];
147 }
148
149 // if the buffer was big enough then continue
150 else {
151 break;
152 }
153 }
154
155 // print the prefix to the buffer. leave space for priority label.
156 char* message = buffer;
157 if (file != NULL) {
158 sprintf(buffer + g_priorityPad, "%s,%d:", file, line);
159 buffer[pPad - 1] = ' ';
160
161 // discard file and line if priority < 0
162 if (priority < 0) {
163 message += pPad - g_priorityPad;
164 }
165 }
166
167 // output buffer
168 output(priority, message);
169
170 // clean up
171 if (buffer != stack) {
172 delete[] buffer;
173 }
174}
175
176void
177CLog::insert(ILogOutputter* outputter, bool alwaysAtHead)
178{
179 assert(outputter != NULL);
180 assert(outputter->getNewline() != NULL);
181
182 CArchMutexLock lock(m_mutex);
183 if (alwaysAtHead) {
184 m_alwaysOutputters.push_front(outputter);
185 }
186 else {
187 m_outputters.push_front(outputter);
188 }
189 int newlineLength = strlen(outputter->getNewline());
190 if (newlineLength > m_maxNewlineLength) {
191 m_maxNewlineLength = newlineLength;
192 }
193 outputter->open(kAppVersion);
194 outputter->show(false);
195}
196
197void
198CLog::remove(ILogOutputter* outputter)
199{
200 CArchMutexLock lock(m_mutex);
201 m_outputters.remove(outputter);
202 m_alwaysOutputters.remove(outputter);
203}
204
205void
206CLog::pop_front(bool alwaysAtHead)
207{
208 CArchMutexLock lock(m_mutex);
209 COutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters;
210 if (!list->empty()) {
211 delete list->front();
212 list->pop_front();
213 }
214}
215
216bool
217CLog::setFilter(const char* maxPriority)
218{
219 if (maxPriority != NULL) {
220 for (int i = 0; i < g_numPriority; ++i) {
221 if (strcmp(maxPriority, g_priority[i]) == 0) {
222 setFilter(i);
223 return true;
224 }
225 }
226 return false;
227 }
228 return true;
229}
230
231void
232CLog::setFilter(int maxPriority)
233{
234 CArchMutexLock lock(m_mutex);
235 m_maxPriority = maxPriority;
236}
237
238int
239CLog::getFilter() const
240{
241 CArchMutexLock lock(m_mutex);
242 return m_maxPriority;
243}
244
245void
246CLog::output(int priority, char* msg) const
247{
248 assert(priority >= -1 && priority < g_numPriority);
249 assert(msg != NULL);
250
251 // insert priority label
252 int n = -g_prioritySuffixLength;
253 if (priority >= 0) {
254 n = strlen(g_priority[priority]);
255 strcpy(msg + g_maxPriorityLength - n, g_priority[priority]);
256 msg[g_maxPriorityLength + 0] = ':';
257 msg[g_maxPriorityLength + 1] = ' ';
258 msg[g_maxPriorityLength + 1] = ' ';
259 }
260
261 // find end of message
262 char* end = msg + g_priorityPad + strlen(msg + g_priorityPad);
263
264 // write to each outputter
265 CArchMutexLock lock(m_mutex);
266 for (COutputterList::const_iterator index = m_alwaysOutputters.begin();
267 index != m_alwaysOutputters.end();
268 ++index) {
269 // get outputter
270 ILogOutputter* outputter = *index;
271
272 // put an appropriate newline at the end
273 strcpy(end, outputter->getNewline());
274
275 // write message
276 outputter->write(static_cast<ILogOutputter::ELevel>(priority),
277 msg + g_maxPriorityLength - n);
278 }
279 for (COutputterList::const_iterator index = m_outputters.begin();
280 index != m_outputters.end(); ++index) {
281 // get outputter
282 ILogOutputter* outputter = *index;
283
284 // put an appropriate newline at the end
285 strcpy(end, outputter->getNewline());
286
287 // write message and break out of loop if it returns false
288 if (!outputter->write(static_cast<ILogOutputter::ELevel>(priority),
289 msg + g_maxPriorityLength - n)) {
290 break;
291 }
292 }
293}
Note: See TracBrowser for help on using the repository browser.