source: trunk/FACT++/src/WindowLog.cc@ 17050

Last change on this file since 17050 was 16881, checked in by tbretz, 11 years ago
Replaced some loops with cout.write for better performance
File size: 10.3 KB
Line 
1// **************************************************************************
2/** @class WindowLog
3
4@brief A C++ ostream to an ncurses window supporting attributes and colors
5
6@section References
7
8 - <A HREF="http://www.gnu.org/software/ncurses">GNU Ncurses</A>
9
10@todo
11 improve docu
12
13
14**/
15// **************************************************************************
16#include "WindowLog.h"
17
18#include <sstream>
19#include <iostream>
20#include <algorithm>
21
22#include <curses.h>
23
24#include "tools.h"
25
26using namespace std;
27
28// --------------------------------------------------------------------------
29//
30//! Delete the contents of the backlog
31//
32void WindowLog::EmptyBacklog()
33{
34 fMuxBacklog.lock();
35 fBacklog.clear();
36 fMuxBacklog.unlock();
37}
38
39// --------------------------------------------------------------------------
40//
41//! Display the backlog. If fWindow is NULL then it is flushed to cout
42//! otherwise to the window (including the colors and attributes)
43//!
44//! Access to cout, the backlog and the window is encapsulated in mutices.
45//
46void WindowLog::Display(bool empty)
47{
48 if (!fWindow)
49 {
50 fMuxBacklog.lock();
51 fMuxCout.lock();
52
53 cout.write(fBacklog.data(), fBacklog.size());
54 cout.flush();
55
56 if (empty)
57 fBacklog.clear();
58
59 fMuxCout.unlock();
60 fMuxBacklog.unlock();
61 return;
62 }
63
64 const int w = getmaxx(fWindow);
65
66 fMuxBacklog.lock();
67 fMuxWindow.lock();
68 //vector<char>::iterator p0 = fBacklog.begin();
69
70 int lines = 0;
71 int x = 0;
72
73 for (unsigned int i=0; i<fBacklog.size(); i++)
74 {
75 if (fAttributes.find(i)!=fAttributes.end())
76 fAttributes[i]==-1 ? wattrset(fWindow, 0) : wattron(fWindow, fAttributes[i]);
77
78 if (fBacklog[i]=='\n')
79 {
80 // The attribute is added to the backlog in WriteBuffer
81 //wattrset(fWindow, 0);
82 lines += x/w + 1;
83 x=0;
84 }
85 wprintw(fWindow, "%c", fBacklog[i]);
86 x++;
87 }
88
89 if (empty)
90 fBacklog.clear();
91
92 fMuxWindow.unlock();
93 fMuxBacklog.unlock();
94
95 lines += x/w;
96}
97
98// --------------------------------------------------------------------------
99//
100//! Open a log-file into which any of the following output is written. If a
101//! log-file is alraedy open it is closed.
102//! before the new file is opened or an old one closed the current buffer
103//! is flushed.
104//!
105//! @param filename
106//! The filename of the file to open
107//!
108//! @returns
109//! Whether the log-file stream is open or not
110//
111bool WindowLog::OpenLogFile(const string &filename, bool append)
112{
113 fMuxFile.lock();
114 flush();
115
116 if (fLogFile.is_open())
117 fLogFile.close();
118
119 fLogFile.open(filename, append ? ios::app|ios::out : ios::out);
120 if (append)
121 fLogFile << '\n';
122
123 fMuxFile.unlock();
124
125 return fLogFile.is_open();
126}
127
128// --------------------------------------------------------------------------
129//
130//! Close an open log-file
131//
132void WindowLog::CloseLogFile()
133{
134 fMuxFile.lock();
135 fLogFile.close();
136 fMuxFile.unlock();
137}
138
139void WindowLog::WriteFile(const string &sout)
140{
141 fMuxFile.lock();
142 fLogFile << sout;
143 fLogFile.flush();
144 fMuxFile.unlock();
145}
146
147// --------------------------------------------------------------------------
148//
149//! This is the function which writes the stream physically to a device.
150//! If you want to add a new device this must be done here.
151//!
152//! If the backlog is enabled, the contents are put into the backlog.
153//! if fWindow is NULL the contents are flushed to cout, otherwise
154//! to the window defined by fWindow.
155//!
156//! In addition the contents are flushed to the log-file if open.
157//! If fIsNull is true any output on the screen (cout or fWindow) is
158//! suppressed.
159//!
160//! @todo
161//! Truncate the backlog
162//
163void WindowLog::WriteBuffer()
164{
165 // Store the number of characters in the buffer which should be flushed
166 const int len = fPPtr - fBase;
167
168 // restart writing to the buffer at its first char
169 fPPtr = fBase;
170
171 // If the is nothing to output, we are done
172 if (len<=0)
173 return;
174
175 // FIXME: Truncate backlog!
176
177 // If fWindow is set, output everything to the window, otherwise
178 // to cout
179 if (!fIsNull)
180 {
181 if (fWindow)
182 {
183 fMuxWindow.lock();
184 if (!fIsNull)
185 {
186 const string sout = string(fBase, len);
187 wprintw(fWindow, "%s", sout.c_str());
188 }
189 // If the stream got flushed due to a line break
190 // reset all attributes
191 if (fBase[len-1]=='\n')
192 wattrset(fWindow, 0);
193 fMuxWindow.unlock();
194 }
195 else
196 {
197 fMuxCout.lock();
198 cout.write(fBase, len);// << sout;
199 // If the stream got flushed due to a line break
200 // reset all attributes
201 if (fBase[len-1]=='\n')
202 cout << "\033[0m";
203 cout.flush();
204 fMuxCout.unlock();
205 }
206 }
207
208 // Add the buffer to the backlog
209 if (fEnableBacklog)
210 {
211 fMuxBacklog.lock();
212 fBacklog.insert(fBacklog.end(), fBase, fBase+len);
213
214 // If the stream got flushed due to a line break
215 // add the reset of all attributes to the backlog
216 if (fBase[len-1]=='\n')
217 {
218 if (!fWindow)
219 {
220 const char *reset = "\033[0m";
221 fBacklog.insert(fBacklog.end(), reset, reset+4);
222
223 }
224 else
225 fAttributes[fBacklog.size()] = -1;
226 }
227 fMuxBacklog.unlock();
228 }
229
230 fQueueFile.emplace(fBase, len);
231 /*
232 // Output everything also to the log-file
233 fMuxFile.lock();
234 fLogFile << sout;
235 //fLogFile.flush();
236 fMuxFile.unlock();
237 */
238 // If we are flushing because of an EOL, we reset also all attributes
239}
240
241// --------------------------------------------------------------------------
242//
243//! This is called to flush the buffer of the streaming devices
244//
245int WindowLog::sync()
246{
247 WriteBuffer();
248 return 0;
249}
250
251// --------------------------------------------------------------------------
252//
253//! This function comes from streambuf and should output the buffer to
254//! the device (flush, endl) or handle a buffer overflow (too many chars)
255//! If a real overflow happens i contains the next chars which doesn't
256//! fit into the buffer anymore.If the buffer is not really filled,
257//! i is EOF(-1).
258//
259int WindowLog::overflow(int i) // i=EOF means not a real overflow
260{
261 *fPPtr++ = (char)i;
262
263 if (fPPtr == fEPtr)
264 WriteBuffer();
265
266 return 0;
267}
268
269// --------------------------------------------------------------------------
270//
271//! Returns the size of the backlog buffer as string.
272//!
273//! @returns
274//! Size of the backlog as a string, e.g. "1k"
275//
276string WindowLog::GetSizeStr() const
277{
278 int s = GetSizeBacklog()/1000;
279 if (s==0)
280 return "0";
281
282 char u = 'k';
283 if (s>999)
284 {
285 s/=1000;
286 u = 'M';
287 }
288
289 ostringstream str;
290 str << s << u;
291 return str.str();
292}
293
294// --------------------------------------------------------------------------
295//
296//! @returns
297//! the ANSI code corresponding to the attributes
298//
299string WindowLog::GetAnsiAttr(int m)
300{
301 if (m==kReset || m==kDefault)
302 return "\033[0m";
303
304 string rc;
305
306 if ((m&COLOR_PAIR(kRed) )==COLOR_PAIR(kRed) ) rc += "\033[31m";
307 if ((m&COLOR_PAIR(kGreen) )==COLOR_PAIR(kGreen) ) rc += "\033[32m";
308 if ((m&COLOR_PAIR(kYellow) )==COLOR_PAIR(kYellow) ) rc += "\033[33m";
309 if ((m&COLOR_PAIR(kBlue) )==COLOR_PAIR(kBlue) ) rc += "\033[34m";
310 if ((m&COLOR_PAIR(kMagenta))==COLOR_PAIR(kMagenta)) rc += "\033[35m";
311 if ((m&COLOR_PAIR(kCyan) )==COLOR_PAIR(kCyan) ) rc += "\033[36m";
312 if ((m&COLOR_PAIR(kWhite) )==COLOR_PAIR(kWhite) ) rc += "\033[0m\033[1m";
313
314 if ((m&kBold )==kBold ) rc += "\033[1m";
315 if ((m&kDim )==kDim ) rc += "\033[2m";
316 if ((m&kUnderline)==kUnderline) rc += "\033[4m";
317 if ((m&kBlink )==kBlink ) rc += "\033[5m";
318
319 return rc;
320}
321
322// --------------------------------------------------------------------------
323//
324//! Add color to the stream according to the attribute. If fWindow is not
325//! set this is an ANSI color code, otherwise the window's output
326//! attributes are set.
327//! It is also added to the backlog. Access to the backlog is encapsulated
328//! into its mutex.
329//
330void WindowLog::AddColor(int m)
331{
332 const int col = COLOR_PAIR(m);
333
334 if (!fWindow)
335 // We don't have to flush here, because the attributes are simply
336 // part of the stream
337 *this << GetAnsiAttr(col);
338 else
339 {
340 // Before we change the attributes we have to flush the screen
341 // otherwise we would have to buffer them until we flush the
342 // contents
343 flush();
344 wattron(fWindow, col);
345 }
346
347 fMuxBacklog.lock();
348 fAttributes[fBacklog.size()] |= col;
349 fMuxBacklog.unlock();
350}
351
352// --------------------------------------------------------------------------
353//
354//! Add attributes to the stream according to the attribute. If fWindow is
355//! not set this is an ANSI code, otherwise the window's output
356//! attributes are set.
357//! It is also added to the backlog. Access to the backlog is encapsulated
358//! into its mutex.
359//
360void WindowLog::AddAttr(int m)
361{
362 if (!fWindow)
363 // We don't have to flush here, because the attributes are simply
364 // part of the stream
365 *this << GetAnsiAttr(m);
366 else
367 {
368 // Before we change the attributes we have to flush the screen
369 // otherwise we would have to buffer them until we flush the
370 // contents
371 flush();
372 m==kReset ? wattrset(fWindow, 0) : wattron(fWindow, m);
373 }
374
375 fMuxBacklog.lock();
376 m==kReset ?
377 fAttributes[fBacklog.size()] = -1 :
378 fAttributes[fBacklog.size()] |= m;
379 fMuxBacklog.unlock();
380}
381
382// --------------------------------------------------------------------------
383//
384//!
385//
386std::ostream &operator<<(std::ostream &lout, WindowLogColor m)
387{
388 WindowLog *log=dynamic_cast<WindowLog*>(lout.rdbuf());
389 if (log)
390 log->AddColor(m);
391 return lout;
392}
393
394// --------------------------------------------------------------------------
395//
396//!
397//
398std::ostream &operator<<(std::ostream &lout, WindowLogAttrs m)
399{
400 WindowLog *log=dynamic_cast<WindowLog*>(lout.rdbuf());
401 if (log)
402 log->AddAttr(m);
403 return lout;
404}
Note: See TracBrowser for help on using the repository browser.