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

Last change on this file was 17229, checked in by tbretz, 7 years ago
Use Queue from externals instead of src.
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
139bool WindowLog::WriteFile(const string &sout)
140{
141    fMuxFile.lock();
142    fLogFile << sout;
143    fLogFile.flush();
144    fMuxFile.unlock();
145
146    return true;
147}
148
149// --------------------------------------------------------------------------
150//
151//! This is the function which writes the stream physically to a device.
152//! If you want to add a new device this must be done here.
153//!
154//! If the backlog is enabled, the contents are put into the backlog.
155//! if fWindow is NULL the contents are flushed to cout, otherwise
156//! to the window defined by fWindow.
157//!
158//! In addition the contents are flushed to the log-file if open.
159//! If fIsNull is true any output on the screen (cout or fWindow) is
160//! suppressed.
161//!
162//! @todo
163//!    Truncate the backlog
164//
165void WindowLog::WriteBuffer()
166{
167    // Store the number of characters in the buffer which should be flushed
168    const int len = fPPtr - fBase;
169
170    // restart writing to the buffer at its first char
171    fPPtr = fBase;
172
173    // If the is nothing to output, we are done
174    if (len<=0)
175        return;
176
177    // FIXME: Truncate backlog!
178
179    // If fWindow is set, output everything to the window, otherwise
180    // to cout
181    if (!fIsNull)
182    {
183        if (fWindow)
184        {
185            fMuxWindow.lock();
186            if (!fIsNull)
187            {
188                const string sout = string(fBase, len);
189                wprintw(fWindow, "%s", sout.c_str());
190            }
191            // If the stream got flushed due to a line break
192            // reset all attributes
193            if (fBase[len-1]=='\n')
194                wattrset(fWindow, 0);
195            fMuxWindow.unlock();
196        }
197        else
198        {
199            fMuxCout.lock();
200            cout.write(fBase, len);// << sout;
201            // If the stream got flushed due to a line break
202            // reset all attributes
203            if (fBase[len-1]=='\n')
204                cout << "\033[0m";
205            cout.flush();
206            fMuxCout.unlock();
207        }
208    }
209
210    // Add the buffer to the backlog
211    if (fEnableBacklog)
212    {
213        fMuxBacklog.lock();
214        fBacklog.insert(fBacklog.end(), fBase, fBase+len);
215
216        // If the stream got flushed due to a line break
217        // add the reset of all attributes to the backlog
218        if (fBase[len-1]=='\n')
219        {
220            if (!fWindow)
221            {
222                const char *reset = "\033[0m";
223                fBacklog.insert(fBacklog.end(), reset, reset+4);
224
225            }
226            else
227                fAttributes[fBacklog.size()] = -1;
228        }
229        fMuxBacklog.unlock();
230    }
231
232    fQueueFile.emplace(fBase, len);
233    /*
234    // Output everything also to the log-file
235    fMuxFile.lock();
236    fLogFile << sout;
237    //fLogFile.flush();
238    fMuxFile.unlock();
239    */
240    // If we are flushing because of an EOL, we reset also all attributes
241}
242
243// --------------------------------------------------------------------------
244//
245//! This is called to flush the buffer of the streaming devices
246//
247int WindowLog::sync()
248{
249    WriteBuffer();
250    return 0;
251}
252
253// --------------------------------------------------------------------------
254//
255//! This function comes from streambuf and should output the buffer to
256//! the device (flush, endl) or handle a buffer overflow (too many chars)
257//! If a real overflow happens i contains the next chars which doesn't
258//! fit into the buffer anymore.If the buffer is not really filled,
259//! i is EOF(-1).
260//
261int WindowLog::overflow(int i) // i=EOF means not a real overflow
262{
263    *fPPtr++ = (char)i;
264
265    if (fPPtr == fEPtr)
266        WriteBuffer();
267
268    return 0;
269}
270
271// --------------------------------------------------------------------------
272//
273//! Returns the size of the backlog buffer as string.
274//!
275//! @returns
276//!     Size of the backlog as a string, e.g. "1k"
277//
278string WindowLog::GetSizeStr() const
279{
280    int s = GetSizeBacklog()/1000;
281    if (s==0)
282        return "0";
283
284    char u = 'k';
285    if (s>999)
286    {
287        s/=1000;
288        u = 'M';
289    }
290
291    ostringstream str;
292    str << s << u;
293    return str.str();
294}
295
296// --------------------------------------------------------------------------
297//
298//! @returns
299//!     the ANSI code corresponding to the attributes
300//
301string WindowLog::GetAnsiAttr(int m)
302{
303    if (m==kReset || m==kDefault)
304        return "\033[0m";
305
306    string rc;
307
308    if ((m&COLOR_PAIR(kRed)    )==COLOR_PAIR(kRed)    )  rc += "\033[31m";
309    if ((m&COLOR_PAIR(kGreen)  )==COLOR_PAIR(kGreen)  )  rc += "\033[32m";
310    if ((m&COLOR_PAIR(kYellow) )==COLOR_PAIR(kYellow) )  rc += "\033[33m";
311    if ((m&COLOR_PAIR(kBlue)   )==COLOR_PAIR(kBlue)   )  rc += "\033[34m";
312    if ((m&COLOR_PAIR(kMagenta))==COLOR_PAIR(kMagenta))  rc += "\033[35m";
313    if ((m&COLOR_PAIR(kCyan)   )==COLOR_PAIR(kCyan)   )  rc += "\033[36m";
314    if ((m&COLOR_PAIR(kWhite)  )==COLOR_PAIR(kWhite)  )  rc += "\033[0m\033[1m";
315
316    if ((m&kBold     )==kBold     )  rc += "\033[1m";
317    if ((m&kDim      )==kDim      )  rc += "\033[2m";
318    if ((m&kUnderline)==kUnderline)  rc += "\033[4m";
319    if ((m&kBlink    )==kBlink    )  rc += "\033[5m";
320
321    return rc;
322}
323
324// --------------------------------------------------------------------------
325//
326//! Add color to the stream according to the attribute. If fWindow is not
327//! set this is an ANSI color code, otherwise the window's output
328//! attributes are set.
329//! It is also added to the backlog. Access to the backlog is encapsulated
330//! into its mutex.
331//
332void WindowLog::AddColor(int m)
333{
334    const int col = COLOR_PAIR(m);
335
336    if (!fWindow)
337        // We don't have to flush here, because the attributes are simply
338        // part of the stream
339        *this << GetAnsiAttr(col);
340    else
341    {
342        // Before we change the attributes we have to flush the screen
343        // otherwise we would have to buffer them until we flush the
344        // contents
345        flush();
346        wattron(fWindow, col);
347    }
348
349    fMuxBacklog.lock();
350    fAttributes[fBacklog.size()] |= col;
351    fMuxBacklog.unlock();
352}
353
354// --------------------------------------------------------------------------
355//
356//! Add attributes to the stream according to the attribute. If fWindow is
357//! not set this is an ANSI code, otherwise the window's output
358//! attributes are set.
359//! It is also added to the backlog. Access to the backlog is encapsulated
360//! into its mutex.
361//
362void WindowLog::AddAttr(int m)
363{
364    if (!fWindow)
365        // We don't have to flush here, because the attributes are simply
366        // part of the stream
367        *this << GetAnsiAttr(m);
368    else
369    {
370        // Before we change the attributes we have to flush the screen
371        // otherwise we would have to buffer them until we flush the
372        // contents
373        flush();
374        m==kReset ? wattrset(fWindow, 0) : wattron(fWindow, m);
375    }
376
377    fMuxBacklog.lock();
378    m==kReset ?
379        fAttributes[fBacklog.size()] = -1 :
380        fAttributes[fBacklog.size()] |= m;
381    fMuxBacklog.unlock();
382}
383
384// --------------------------------------------------------------------------
385//
386//!
387//
388std::ostream &operator<<(std::ostream &lout, WindowLogColor m)
389{
390    WindowLog *log=dynamic_cast<WindowLog*>(lout.rdbuf());
391    if (log)
392        log->AddColor(m);
393    return lout;
394}
395
396// --------------------------------------------------------------------------
397//
398//!
399//
400std::ostream &operator<<(std::ostream &lout, WindowLogAttrs m)
401{
402    WindowLog *log=dynamic_cast<WindowLog*>(lout.rdbuf());
403    if (log)
404        log->AddAttr(m);
405    return lout;
406}
Note: See TracBrowser for help on using the repository browser.