1/* linbox/util/commentator.C
2 * Copyright (C) 1999 B. David Saunders,
3 *                    Jean-Guillaume Dumas
4 * Copyright (C) 2002 Bradford Hovinen
5 *
6 * Written by B. David Saunders <saunders@cis.udel.edu>,
7 *            Jean-Guillaume Dumas <Jean-Guillaume.Dumas@imag.fr>,
8 *            Bradford Hovinen <hovinen@cis.udel.edu>
9 *
10 * ========LICENCE========
11 * This file is part of the library LinBox.
12 *
13 * LinBox is free software: you can redistribute it and/or modify
14 * it under the terms of the  GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
26 * ========LICENCE========
27 *
28 * This file implements the ++C interface to commentators (for
29 * providing runtime commentary to the user)
30 */
31
32/*! @internal
33 * @file util/commentator.C
34 * @brief implementation of LinBox::Commentator.
35 */
36
37#include "linbox/linbox-config.h"
38
39#include <string>
40#include <sstream>
41#include <cmath>
42#include <cstring>
43#include <cstdlib>
44#include <cstdio>
45
46#include "linbox/util/commentator.h"
47#include "linbox/util/debug.h"
48
49#include "givaro/givpower.h"
50
51namespace LinBox
52{
53    // -----------------------------------------------------
54    // Mathematical routines
55    // -----------------------------------------------------
56    double nroot (double a, long r, double precision)
57    {
58        const long rm = r - 1 ;
59        const double c1 = double (rm) / double (r), c2 = a / double (r);
60        double g = 1, pgr = 1, err = a - 1;
61
62        while (err > precision) {
63            g = g * c1 + c2 / pgr;
64            pgr = pow (g, (double) rm);
65            err = a - pgr * g; if (err < 0) err = -err;
66        }
67
68        return g;
69    }
70
71    long isnpower (long& l, long a)
72    {
73        long r = 2;
74        double g;
75
76        while ((g = nroot ((double)a, r, 0.1)) >= 2) {
77            l = (long) floor (g);
78            if (g-double (l) > 0.1)
79                ++l;
80            if (Givaro::power (l, r) == a)
81                return r;
82            ++r;
83        }
84
85        return 0;
86    }
87
88    Commentator::Commentator () :
89        cnull ("/dev/null")
90        , _estimationMethod (BEST_ESTIMATE), _format (OUTPUT_CONSOLE),
91        _show_timing (true), _show_progress (true), _show_est_time (true)
92        ,_last_line_len(0)
93    {
94        //registerMessageClass (BRIEF_REPORT,         std::clog, 1, LEVEL_IMPORTANT);
95        registerMessageClass (BRIEF_REPORT,         _report, 1, LEVEL_IMPORTANT);
96        registerMessageClass (PROGRESS_REPORT,      _report);
97        registerMessageClass (TIMING_MEASURE,       _report);
98        registerMessageClass (TIMING_ESTIMATE,      _report);
99        registerMessageClass (PARTIAL_RESULT,       _report);
100        registerMessageClass (INTERNAL_WARNING,     _report, 10, LEVEL_NORMAL);
101        registerMessageClass (INTERNAL_ERROR,       _report, 10, LEVEL_NORMAL);
102        registerMessageClass (INTERNAL_DESCRIPTION, _report);
103    }
104    Commentator::Commentator (std::ostream& out) :
105        cnull ("/dev/null")
106        , _estimationMethod (BEST_ESTIMATE), _format (OUTPUT_CONSOLE),
107        _show_timing (true), _show_progress (true), _show_est_time (true)
108        ,_last_line_len(0)
109    {
110        //registerMessageClass (BRIEF_REPORT,         out, 1, LEVEL_IMPORTANT);
111        registerMessageClass (BRIEF_REPORT,         out, 1, LEVEL_IMPORTANT);
112        registerMessageClass (PROGRESS_REPORT,      out);
113        registerMessageClass (TIMING_MEASURE,       out);
114        registerMessageClass (TIMING_ESTIMATE,      out);
115        registerMessageClass (PARTIAL_RESULT,       out);
116        registerMessageClass (INTERNAL_WARNING,     out, 10, LEVEL_NORMAL);
117        registerMessageClass (INTERNAL_ERROR,       out, 10, LEVEL_NORMAL);
118        registerMessageClass (INTERNAL_DESCRIPTION, out);
119    }
120
121    Commentator::~Commentator()
122    {
123        _report << "That's all, Folks!" << std::endl;
124        std::map <const char *, MessageClass *, C_str_Less >::iterator i;
125        for (i = _messageClasses.begin (); i != _messageClasses.end (); ++i)
126            delete i->second;
127        while (!_activities.empty()){
128            delete _activities.top();
129            _activities.pop();
130        }
131    }
132
133    void Commentator::start (const char *description, const char *fn, unsigned long len)
134    {
135        if (fn == (const char *) 0 && _activities.size () > 0)
136            fn = _activities.top ()->_fn;
137
138        if (isPrinted (_activities.size () + 1, LEVEL_IMPORTANT, INTERNAL_DESCRIPTION, fn))
139            report (LEVEL_IMPORTANT, INTERNAL_DESCRIPTION) //<< "Starting activity: "
140            << description << std::endl;
141
142        Activity *new_act = new Activity (description, fn, len);
143
144        if (isPrinted (_activities.size (), LEVEL_IMPORTANT, BRIEF_REPORT, fn))
145            printActivityReport (*new_act);
146
147        _activities.push (new_act);
148
149        new_act->_timer.start ();
150    }
151
152    void Commentator::start (std::string description, const char *fn, unsigned long len)
153    {
154        start(description.c_str(),fn,len);
155    }
156
157    void Commentator::startIteration (unsigned int iter, unsigned long len)
158    {
159        std::ostringstream str;
160
161        str << "Iteration " << iter << std::ends;
162
163        _iteration_str = str.str ();
164        start (_iteration_str.c_str (), (const char *) 0, len);
165    }
166
167    void Commentator::stop (const char *msg, const char *long_msg, const char *fn)
168    {
169        double realtime; //, usertime, systime;
170        Activity *top_act;
171
172        linbox_check (_activities.top () != (Activity *) 0);
173        linbox_check (msg != (const char *) 0);
174
175        if (long_msg == (const char *) 0)
176            long_msg = msg;
177
178        top_act = _activities.top ();
179
180        top_act->_timer.stop ();
181
182        realtime = top_act->_timer.time ();
183        //usertime = top_act->_timer.usertime ();
184        //systime  = top_act->_timer.systime ();
185
186        if (realtime < 0) realtime = 0;
187        //if (usertime < 0) usertime = 0;
188        //if (systime < 0) systime = 0;
189
190        if (fn != (const char *) 0 &&
191            _activities.size () > 0 &&
192            top_act->_fn != (const char *) 0 &&
193            strcmp (fn, top_act->_fn) != 0)
194        {
195            report (LEVEL_IMPORTANT, INTERNAL_WARNING)
196            << "Activity report mismatch. Check that start () and stop () calls are paired correctly." << std::endl;
197        }
198
199        fn = top_act->_fn;
200
201        _activities.pop ();
202
203        if (isPrinted (_activities.size (), LEVEL_IMPORTANT, BRIEF_REPORT, fn))
204        {
205            finishActivityReport (*top_act, msg);
206        }
207
208        if (isPrinted (_activities.size () + 1, LEVEL_IMPORTANT, INTERNAL_DESCRIPTION, fn)) {
209            std::ostream &output = report (LEVEL_IMPORTANT, INTERNAL_DESCRIPTION);
210            output.precision (4);
211            output << "Finished activity (rea: " << realtime << "s, cpu: ";
212            //output.precision (4);
213            //output << usertime << "s, sys: ";
214            //output.precision (4);
215            //output << systime << "s): " << long_msg << std::endl;
216        }
217        else if (isPrinted (_activities.size (), LEVEL_IMPORTANT, INTERNAL_DESCRIPTION, fn)) {
218            std::ostream &output = report (LEVEL_IMPORTANT, INTERNAL_DESCRIPTION);
219            output.precision (4);
220            output << "Completed activity: " << top_act->_desc << " (r: " << realtime << "s, u: ";
221            //output.precision (4);
222            //output << usertime << "s, s: ";
223            //output.precision (4);
224            //output << systime << "s) " << long_msg << std::endl;
225        }
226
227        delete top_act;
228    }
229
230    void Commentator::progress (long k, long len)
231    {
232        linbox_check (_activities.top () != (Activity *) 0);
233
234        Activity *act = _activities.top ();
235        Givaro::RealTimer tmp = act->_timer;
236        act->_timer.stop ();
237
238        if (k == -1)
239            ++(act->_progress);
240        else
241            act->_progress = (unsigned long)k;
242
243        if (len != -1)
244            act->_len = (unsigned long) len;
245
246        if (act->_progress > act->_len)
247            act->_len = act->_progress;
248
249        std::ostream &rep = report (LEVEL_IMPORTANT, PROGRESS_REPORT);
250        rep.precision (3);
251        rep.setf (std::ios::fixed);
252        rep << "Progress: " << act->_progress << " out of " << act->_len
253        << " (" << act->_timer.time () << "s elapsed)" << std::endl;
254
255        if (_show_progress && isPrinted (_activities.size () - 1, LEVEL_IMPORTANT, BRIEF_REPORT, act->_fn))
256            updateActivityReport (*act);
257        act->_timer = tmp;
258    }
259
260    std::ostream &Commentator::report (long level, const char *msg_class)
261    {
262        linbox_check (msg_class != (const char *) 0);
263
264        _report << "$$(" << _activities.size () << ", " << level << ", " << msg_class << ")";
265#if 0
266        if (!isPrinted (_activities.size (), level, msg_class,
267                        (_activities.size () > 0) ? _activities.top ()->_fn : (const char *) 0))
268            return cnull;
269
270        MessageClass &messageClass = getMessageClass (msg_class);
271
272        return messageClass._stream;
273#endif
274        return _report;
275    }
276
277    void Commentator::indent (std::ostream &stream) const
278    {
279        unsigned int i;
280
281        for (i = 0; i < _activities.size (); ++i)
282            stream << "  ";
283    }
284
285    void Commentator::restoreActivityState (ActivityState state)
286    {
287        std::stack<Activity *> backup;
288
289        while (!_activities.empty () && _activities.top () != state._act) {
290            backup.push (_activities.top ());
291            _activities.pop ();
292        }
293
294        if (_activities.empty ()) {
295            // Uh oh -- the state didn't give a valid activity
296
297            while (!backup.empty ()) {
298                _activities.push (backup.top ());
299                backup.pop ();
300            }
301        }
302    }
303
304    void Commentator::setMaxDepth (long depth)
305    {
306        MessageClass &briefReportClass = getMessageClass (BRIEF_REPORT);
307        std::map <const char *, MessageClass *, C_str_Less>::iterator i;
308
309        for (i = _messageClasses.begin (); i != _messageClasses.end (); ++i)
310            if (i->second != &briefReportClass)
311                i->second->setMaxDepth (depth);
312    }
313
314    void Commentator::setMaxDetailLevel (long level)
315    {
316        MessageClass &briefReportClass = getMessageClass (BRIEF_REPORT);
317        std::map <const char *, MessageClass *, C_str_Less>::iterator i;
318
319        for (i = _messageClasses.begin (); i != _messageClasses.end (); ++i)
320            if (i->second != &briefReportClass)
321                i->second->setMaxDetailLevel (level);
322    }
323
324    MessageClass &Commentator::registerMessageClass (const char *msg_class, std::ostream &stream, unsigned long max_depth, unsigned long max_level)
325    {
326        linbox_check (msg_class != (const char *) 0);
327
328        MessageClass *new_obj = new MessageClass (*this, msg_class, stream, max_depth, max_level);
329        _messageClasses[msg_class] = new_obj;
330        return *new_obj;
331    }
332
333    MessageClass &Commentator::cloneMessageClass (const char *new_msg_class, const char *msg_class)
334    {
335        linbox_check (new_msg_class != (const char *) 0);
336        linbox_check (msg_class != (const char *) 0);
337
338        MessageClass *new_obj = new MessageClass (getMessageClass (msg_class));
339        new_obj->_msg_class = new_msg_class;
340        _messageClasses[new_msg_class] = new_obj;
341        return *new_obj;
342    }
343
344    MessageClass &Commentator::cloneMessageClass (const char *new_msg_class, const char *msg_class, std::ostream &stream)
345    {
346        linbox_check (new_msg_class != (const char *) 0);
347        linbox_check (msg_class != (const char *) 0);
348
349        MessageClass &old_obj = getMessageClass (msg_class);
350        MessageClass *new_obj = new MessageClass (*this, new_msg_class, stream, old_obj._configuration);
351        _messageClasses[new_msg_class] = new_obj;
352        return *new_obj;
353    }
354
355    MessageClass &Commentator::getMessageClass (const char *msg_class)
356    { return *_messageClasses[msg_class]; }
357
358    void Commentator::setPrintParameters (unsigned long depth, unsigned long level, const char *fn)
359    {
360        MessageClass &briefReportClass = getMessageClass (BRIEF_REPORT);
361        std::map <const char *, MessageClass *, C_str_Less>::iterator i;
362
363        for (i = _messageClasses.begin (); i != _messageClasses.end (); ++i)
364            if (i->second != &briefReportClass)
365                i->second->setPrintParameters (depth, level, fn);
366    }
367
368    void Commentator::setBriefReportParameters (OutputFormat format, bool show_timing, bool show_progress, bool show_est_time)
369    {
370        _format        = format;
371        _show_timing   = show_timing;
372        _show_progress = show_progress;
373        _show_est_time = show_est_time;
374    }
375
376    bool Commentator::isPrinted (unsigned long depth, unsigned long level, const char *msg_class, const char *fn)
377    {
378        if (_messageClasses.find (msg_class) == _messageClasses.end ())
379            return false;
380
381        MessageClass &messageClass = getMessageClass (msg_class);
382
383        return messageClass.isPrinted (depth, level, fn);
384    }
385
386    void Commentator::setBriefReportStream (std::ostream &stream)
387    { setMessageClassStream (BRIEF_REPORT, stream); }
388
389    void Commentator::setReportStream (std::ostream &stream)
390    {
391        setMessageClassStream (BRIEF_REPORT,      stream);
392        setMessageClassStream (PROGRESS_REPORT,      stream);
393        setMessageClassStream (TIMING_MEASURE,       stream);
394        setMessageClassStream (TIMING_ESTIMATE,      stream);
395        setMessageClassStream (PARTIAL_RESULT,       stream);
396        setMessageClassStream (INTERNAL_ERROR,       stream);
397        setMessageClassStream (INTERNAL_WARNING,     stream);
398        setMessageClassStream (INTERNAL_DESCRIPTION, stream);
399
400        if (&stream == &(getMessageClass (BRIEF_REPORT)._stream))
401            getMessageClass (BRIEF_REPORT).setMaxDepth (0);
402    }
403
404    void Commentator::setMessageClassStream (const char *msg_class, std::ostream &stream)
405    {
406        //temporarily fixed the bug in test-commentator, left memory leaking.
407        MessageClass *old_msg_class = _messageClasses[msg_class];
408        cloneMessageClass (msg_class, msg_class, stream);
409        delete old_msg_class;
410
411    }
412
413    void Commentator::setDefaultReportFile (const char *filename)
414    {
415        _report.open (filename);
416    }
417
418    void Commentator::printActivityReport (Activity &activity)
419    {
420        MessageClass &messageClass = getMessageClass (BRIEF_REPORT);
421
422        if (_format == OUTPUT_CONSOLE) {
423            messageClass._stream << activity._desc << "...";
424
425            if (messageClass.isPrinted (_activities.size () + 1, LEVEL_IMPORTANT, activity._fn))
426                messageClass._stream << std::endl;
427            else if (_show_progress && activity._len > 0) {
428                messageClass._stream << "  0%";
429                _last_line_len = (int)strlen ("  0%");
430            }
431            else
432                _last_line_len = 0;
433
434            messageClass._smart_streambuf.stream ().flush ();
435        }
436        else if (_format == OUTPUT_PIPE &&
437                 (((_show_progress || _show_est_time) && activity._len > 0) ||
438                  messageClass.isPrinted (_activities.size () + 1, LEVEL_IMPORTANT, activity._fn)))
439        {
440            messageClass._stream << activity._desc << "...";
441
442            if (_show_progress)
443                messageClass._stream << std::endl;
444        }
445    }
446
447    void Commentator::updateActivityReport (Activity &activity)
448    {
449        MessageClass &messageClass = getMessageClass (BRIEF_REPORT);
450        std::ostringstream str;
451        double percent = (double) activity._progress / (double) activity._len * 100.0;
452
453        if (_format == OUTPUT_CONSOLE) {
454            if (!messageClass.isPrinted (_activities.size (), LEVEL_IMPORTANT, activity._fn)) {
455                if (_show_progress) {
456                    unsigned int i,  old_len;
457                    for (i = 0; i < _last_line_len; ++i)
458                        messageClass._stream << '\b';
459                    str.width (3);
460                    str << floor (percent + 0.5) << "%" << std::ends;
461                    old_len = _last_line_len;
462                    _last_line_len = (unsigned int)strlen (str.str ().c_str ());
463                    messageClass._stream << str.str ();
464                    for (int ii = 0; ii < (int) (old_len - _last_line_len); ++ii)
465                        messageClass._stream << ' ';
466                }
467            }
468            else if (messageClass.isPrinted (_activities.size () - 1, LEVEL_UNIMPORTANT, activity._fn)) {
469#if 0
470                if (_show_est_time)
471                    messageClass._stream << activity._estimate.front ()._time
472                    << " remaining" << std::endl;
473#endif
474            }
475
476            messageClass._smart_streambuf.stream ().flush ();
477        }
478        else if (_format == OUTPUT_PIPE) {
479            if (_show_progress) {
480                messageClass._stream << floor (percent + 0.5) << "% done";
481#if 0
482                if (_show_est_time)
483                    messageClass._stream << " (" << activity._estimate.front ()._time
484                    << " remaining)";
485#endif
486                messageClass._stream << std::endl;
487            }
488#if 0
489            else if (_show_est_time)
490                messageClass._stream << activity._estimate.front ()._time
491                << " remaining" << std::endl;
492#endif
493        }
494    }
495
496    void Commentator::finishActivityReport (Activity &activity, const char *msg)
497    {
498        MessageClass &messageClass = getMessageClass (BRIEF_REPORT);
499        unsigned int i;
500
501        if (_format == OUTPUT_CONSOLE) {
502            if (!messageClass.isPrinted (_activities.size () + 1, LEVEL_UNIMPORTANT, activity._fn)) {
503                if (_show_progress)
504                    for (i = 0; i < _last_line_len; ++i)
505                        messageClass._stream << '\b';
506
507                messageClass._stream << msg;
508
509                if (_show_timing)
510                    messageClass._stream << " (" << activity._timer.time () << " s)" << std::endl;
511                else
512                    messageClass._stream << std::endl;
513            }
514            else if (messageClass.isPrinted (_activities.size (), LEVEL_UNIMPORTANT, activity._fn)) {
515                for (i = 0; i < _activities.size (); ++i)
516                    messageClass._stream << "  ";
517
518                messageClass._stream << msg;
519                //messageClass._stream << "Done: " << msg;
520
521                if (_show_timing)
522                    messageClass._stream << " (" << activity._timer.time () << " s)" << std::endl;
523                else
524                    messageClass._stream << std::endl;
525            }
526
527            messageClass._smart_streambuf.stream ().flush ();
528        }
529        else if (_format == OUTPUT_PIPE) {
530            for (i = 0; i < _activities.size (); ++i)
531                messageClass._stream << "  ";
532
533            if (((_show_progress || _show_est_time) && activity._len > 0) ||
534                messageClass.isPrinted (_activities.size () + 1, LEVEL_IMPORTANT, activity._fn))
535                messageClass._stream << "Done: " << msg << std::endl;
536            else
537                messageClass._stream << activity._desc << ": " << msg << std::endl;
538        }
539    }
540
541    MessageClass::MessageClass (const Commentator &comm,
542                                const char *msg_class,
543                                std::ostream &stream,
544                                unsigned long max_depth,
545                                unsigned long max_level) :
546        _msg_class (msg_class),
547        _smart_streambuf (comm, stream),
548        _stream (&_smart_streambuf),
549        _max_level (max_level),
550        _max_depth (max_depth)
551    {
552        fixDefaultConfig ();
553    }
554
555    void MessageClass::setMaxDepth (long depth)
556    {
557        _max_depth = (unsigned long) depth;
558        fixDefaultConfig ();
559    }
560
561    void MessageClass::setMaxDetailLevel (long level)
562    {
563        _max_level = (unsigned long) level;
564        fixDefaultConfig ();
565    }
566
567    void MessageClass::setPrintParameters (unsigned long depth, unsigned long level, const char *fn)
568    {
569        if (fn == (const char *) 0)
570            fn = "";
571
572        std::list <std::pair <unsigned long, unsigned long> > &config = _configuration[fn];
573        std::list <std::pair <unsigned long, unsigned long> >::iterator i, j;
574
575        i = config.begin ();
576
577        // Iterate through preceeding elements in the std::list and remove
578        // any that specify a lower level than we are using
579        while (i != config.end () && i->first <= depth) {
580            if (i->second <= level) {
581                j = i++;
582                config.erase (j);
583            }
584            else {
585                ++i;
586            }
587        }
588
589        // Insert our new directive into the std::list
590        if (i == config.end () || i->second != level)
591            config.insert (i, std::pair <unsigned long, unsigned long> (depth, level));
592
593        // Iterate through following elements in the std::list and remove any
594        // that specify a higher level than we are using
595        while (i != config.end ()) {
596            if (i->second > level) {
597                j = i++;
598                config.erase (j);
599            }
600            else {
601                ++i;
602            }
603        }
604
605        // End result: The std::list should be monotonically increasing in
606        // the first parameter and decreasing in the second
607    }
608
609    bool MessageClass::isPrinted (unsigned long depth, unsigned long level, const char *fn)
610    {
611        return
612        checkConfig (_configuration[""], depth, level)
613        ||
614        (	fn != (const char *) 0
615            &&
616            checkConfig (_configuration[fn], depth, level)
617        );
618#if 0
619
620        if (checkConfig (_configuration[""], depth, level))
621            return true;
622        else if (fn != (const char *) 0)
623            //return checkConfig (_configuration[fn], depth, level);
624        { bool ans = checkConfig (_configuration[fn], depth, level);
625            if (ans)
626            {	//std::cerr << " fn=" << fn << ", d " << depth << ", l " << level << " true" << std::endl;
627                return true;
628            }
629            else
630            {	//std::cerr << " fn=" << fn << ", d " << depth << ", l " << level << " false" << std::endl;
631                return false;
632            }
633        }
634
635        else
636        {	//std::cerr << " fn=0, d " << depth << ", l " << level << " false" << std::endl;
637            return false;
638        }
639
640#endif
641    }
642
643    MessageClass::MessageClass (const Commentator &comm,
644                                const char *msg_class,
645                                std::ostream &stream,
646                                Configuration configuration) :
647        _msg_class (msg_class),
648        _smart_streambuf (comm, stream),
649        _stream (&_smart_streambuf),
650        _configuration (configuration)
651    {}
652
653    void MessageClass::fixDefaultConfig ()
654    {
655        std::list <std::pair <unsigned long, unsigned long> > &config = _configuration[""];
656
657        config.clear ();
658        config.push_back (std::pair <unsigned long, unsigned long> (_max_depth, _max_level));
659        config.push_back (std::pair <unsigned long, unsigned long> ((unsigned long) -1, Commentator::LEVEL_ALWAYS));
660    }
661
662    bool MessageClass::checkConfig (std::list <std::pair <unsigned long, unsigned long> > &config,
663                                    unsigned long depth,
664                                    unsigned long ) //lvl
665    {
666        std::list <std::pair <unsigned long, unsigned long> >::iterator i;
667
668        for ( i = config.begin (); i != config.end (); ++i) {
669            if (depth < i->first) {
670#if 0
671                // uninitialized value error goes away if we ignore level.
672                if (level <= i->second)
673                    return true;
674                else
675                    return false;
676#endif
677                return true;
678            }
679        }
680
681        return false;
682    }
683
684    void MessageClass::dumpConfig () const
685    {
686        Configuration::const_iterator i;
687        std::list <std::pair <unsigned long, unsigned long> >::const_iterator j;
688
689        for (i = _configuration.begin (); i != _configuration.end (); ++i) {
690            std::cerr << "Configuration (" << (*i).first << "):" << std::endl;
691
692            for (j = (*i).second.begin (); j != (*i).second.end (); ++j)
693                std::cerr << "  Depth: " << (*j).first << ", Level: " << (*j).second << std::endl;
694
695            std::cerr << std::endl;
696        }
697    }
698
699    int MessageClass::smartStreambuf::sync ()
700    {
701        std::streamsize n = pptr () - pbase ();
702        return (n && writeData (pbase (), n) != n) ? EOF : 0;
703    }
704
705    int MessageClass::smartStreambuf::overflow (int ch)
706    {
707        std::streamsize n = pptr () - pbase ();
708
709        if (n && sync ())
710            return EOF;
711
712        if (ch != EOF) {
713            char cbuf[1];
714            cbuf[0] = (char)ch;
715            if (writeData (cbuf, 1) != 1)
716                return EOF;
717        }
718
719        pbump((int)-n);
720        return 0;
721    }
722
723    std::streamsize MessageClass::smartStreambuf::xsputn (const char *text, std::streamsize n)
724    {
725        return (sync () == EOF) ? 0 : writeData (text, n);
726    }
727
728    int MessageClass::smartStreambuf::writeData (const char *text, std::streamsize n)
729    {
730        std::streamsize idx;
731        std::streamsize m = n;
732
733        if (_indent_next) {
734            _comm.indent (_stream);
735            _indent_next = false;
736        }
737
738        for (idx = 0; (idx < m) &&(text[idx] != '\n') ; ++idx) ;
739
740        while (idx < m) {
741            _stream.write (text, idx + 1);
742            m -= idx + 1;
743
744            if (m > 0)
745                _comm.indent (_stream);
746            else
747                _indent_next = true;
748
749            text += idx + 1;
750            for (idx = 0; idx != '\n' && idx < m; ++idx) ;
751        }
752
753        _stream.write (text, m);
754
755        _stream.flush ();
756
757        return int(n);
758    }
759
760    // 	// Default global commentator
761    // 	Commentator commentator ;
762}
763
764// Local Variables:
765// mode: C++
766// tab-width: 4
767// indent-tabs-mode: nil
768// c-basic-offset: 4
769// End:
770// vim:sts=4:sw=4:ts=4:et:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
771