DebStream.cc 21.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// (C) Copyright 2014 by Autodesk, Inc.
//
// The information contained herein is confidential, proprietary
// to Autodesk,  Inc.,  and considered a trade secret as defined
// in section 499C of the penal code of the State of California.
// Use of  this information  by  anyone  other  than  authorized
// employees of Autodesk, Inc.  is granted  only under a written
// non-disclosure agreement,  expressly  prescribing  the  scope
// and manner of such use.

#include "DebOut.hh"
#include <string>
#include <fstream>
#include <time.h>
#include <vector>
#include <iostream>
17
#include <map>
18

19
#ifdef DEB_ON
20 21 22

#define LOCAL_PROC static

23
LOCAL_PROC bool is_html_filename(const char* const str)
24
{
25
  const char* dot = strchr(str, '.');
26 27
  if (dot == nullptr) return false;
  ++dot;
28
  return (!strncmp(dot, "htm", 3)) || (!strncmp(dot, "HTM", 3)) ;
29 30
}

31 32 33
namespace ReForm {

class FunctionCallSequence
34
{
35 36 37 38 39 40
  std::string func_name_;
  std::vector<DebEnter*> debs_;  // These may not have sequential counts when multithreaded.

public:
  FunctionCallSequence(const char* _func_name, DebEnter* _deb)
    : func_name_(_func_name)
41
  {
42 43 44
    debs_.push_back(_deb);
  }
  ~FunctionCallSequence() {}
45

46 47 48
  bool add(const char* _func_name, DebEnter* _deb)
  {
    if (func_name_ == _func_name)
49
    {
50
      debs_.push_back(_deb);
51
      return true;
52
    }
53 54
    return false;
  }
55

56 57 58
  bool pop()
  {
    if (debs_.size() > 1)
59
    {
60 61
      debs_.pop_back();
      return true;
62
    }
63 64 65
    debs_.clear();
    return false;
  }
66

67 68 69 70 71
  int number_calls() const
  {
    if (!this) return 0;
    return (int)debs_.size();
  }
72

73 74 75 76 77 78
  int count(int i = 0) const
  {
    int num = number_calls();
    if (i < num) return debs_[num - 1 - i]->count_;
    return -1;
  }
79

80 81 82 83
  const char* name() const
  {
    return func_name_.c_str();
  }
84

85 86 87 88 89 90
  // Replace interior of < > in function name with . for brevity
  void compact_name(std::string& str) const
  {
    int cnt = 0;
    const char* ptr = func_name_.c_str();
    while (ptr && (*ptr != '\0'))
91
    {
92 93 94 95
      char c = *ptr;
      if (c == '>') --cnt;
      if (cnt == 0) str.append(1, c);
      if (c == '<')
96
      {
97 98
        if (cnt == 0) str.append(".");
        ++cnt;
99
      }
100
      ++ptr;
101
    }
102
  }
103

104 105 106 107 108 109 110
  // Get single call stack element string
  void get(std::string& _str, const bool _strip_angled, bool _with_counts) const
  {
    if (_strip_angled) compact_name(_str);
    else _str.append(name());
    _str.append("[");
    if (_with_counts)
111 112
    {

113 114 115 116 117 118 119
      int num = number_calls();
      int prev = -2;
      int seq_cnt = 0;
      for (int i = 0; i < num; ++i)
      {
        int cnt = debs_[i]->count_;
        if (cnt != prev + 1)
120
        {
121
          char buffer[64];
122

123 124 125 126
          if (seq_cnt > 0)
          {
            _str.append("-");
            sprintf_s(buffer, sizeof(buffer), "%i", prev);
127
            _str.append(buffer);
128
          }
129 130 131 132 133 134 135 136 137 138 139 140 141 142
          if (i > 0) _str.append(",");
          sprintf_s(buffer, sizeof(buffer), "%i", cnt);
          _str.append(buffer);
          seq_cnt = 0;
        }
        else
          ++seq_cnt;
        prev = cnt;
      } // endfor i
    } // endif _with_counts
    else
      _str.append("*");
    _str.append("]");
  } // endfunc get
143

144
  void indent(std::string& _str, DebFile* _dfile, bool _is_html);
145

146
}; // endclass FunctionCallSequence
147 148


149 150 151 152 153 154 155
class CallStack
{
  std::vector<FunctionCallSequence> calls_;
  int depth_;
public:
  CallStack() : depth_(0) {}
  ~CallStack() {}
156

157 158 159 160 161 162
  void add(const char* _func_name, DebEnter* _deb)
  {
    if (calls_.empty() || !calls_.back().add(_func_name, _deb))
      calls_.push_back(FunctionCallSequence(_func_name, _deb));
    ++depth_;
  }
163

164 165 166 167 168 169
  void pop()
  {
    if (!calls_.back().pop())
      calls_.pop_back();
    --depth_;
  }
170

171 172 173 174 175 176
  const FunctionCallSequence* call(int _up = 0)
  {
    int num = (int)calls_.size();
    if (_up < num) return &calls_[num - 1 - _up];
    return nullptr;
  }
177

178 179 180 181 182
  // Read a particular call stack element
  bool read(int _up, const char*& _funcname, int& _count)
  {
    const FunctionCallSequence* fcs = call(_up);
    if (fcs != nullptr)
183
    {
184 185 186
      _funcname = fcs->name();
      _count = fcs->count(0); // Return most recent deb_enter_count
      return true;
187
    }
188 189
    return false;
  }
190

191 192 193 194 195 196
  // Get a full call stack sting.
  // returns number of call stack function elements
  int get(std::string& _str, bool _with_counts = true) const
  {
    int num = (int)calls_.size();
    for (int i = 0; i < num; ++i)
197
    {
198 199
      if (i > 0) _str.append("->");
      calls_[i].get(_str, true, _with_counts);
200
    }
201 202
    return num;
  }
203

204 205 206 207
  int depth() const
  {
    return depth_;
  }
208

209
  bool indent(std::string& _str, DebFile* _dfile, const bool is_html);
210
}; // endclass CallStack
211

212 213


214
class DebFile
215 216
{
private:
217 218 219 220 221
  class module_stats
  {
  public:
    int lev_; // Level set for this module
    int col_; // Colour (24 bit RGB, MSB=Red) for this module's DEB_out
222
    module_stats(int _lev = 0) : lev_(_lev), col_(0x808080) {}
223 224 225 226 227 228
    ~module_stats() {}
  };

  std::map<std::string, module_stats> module_map_;
  typedef std::map<std::string, module_stats>::iterator module_map_itr;
  typedef std::map<std::string, module_stats>::const_iterator const_module_map_itr;
229

230
  DebStream::StreamType type_;
231 232
  int lev_;
  int num_flush_;
233
  int priority_; // Last permission granted
234
  int indent_size_;
235

236 237
  bool at_line_start_;

238 239 240 241
  std::string current_;
  std::string output_;
  std::string file_name_;
  std::fstream file_stream_;
242
  //std::string indent_string_;
243
  DebStream* deb_stream_;
244 245 246 247
  CallStack call_stack_;

public:

248 249 250 251
  CallStack& call_stack()
  {
    return call_stack_;
  }
252

253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
  bool is_kept_open() const
  {
    return 0 != (type_ & DebStream::StreamType::keep_open);
  }
  bool is_html() const
  {
    return 0 != (type_ & DebStream::StreamType::html);
  }
  bool is_retained() const
  {
    return 0 != (type_ & DebStream::StreamType::retain);
  }
  bool is_appended() const
  {
    return 0 != (type_ & DebStream::StreamType::append);
  }
269
  // Only applies to HTML DEB_out
270 271 272 273 274 275 276 277
  bool is_white_on_black() const
  {
    return true;
  }
  int indent_size()
  {
    return indent_size_;
  }
278

279 280 281 282 283 284 285 286
  bool file_is_open() const
  {
    return file_stream_.is_open();
  }
  int priority() const
  {
    return priority_;
  }
287

288 289 290 291 292 293 294 295
  bool fork_to_cout()
  {
    return false;
  }
  bool fork_to_cerr()
  {
    return true;
  }
296 297


298
  const char* file_name() const
299
  {
300
    if (this && (!file_name_.empty())) return file_name_.c_str();
301 302
    return nullptr;
  }
303

304 305 306 307 308 309
  void clear()
  {
    current_.clear();
    output_.clear();
    file_name_.clear();
  }
310

311 312 313 314 315 316 317
  char prev_char() const
  {
    if (!current_.empty()) return current_.back();
    if (!output_.empty()) return output_.back();
    return '\0';
  }

318

319
  void indent(bool _full_text)
320
  {
321
    std::string str;
322
    if (call_stack().indent(str, this,  _full_text && is_html()))
323
      current_.append(str);
324 325
  }

326

327
  void line_break(bool _with_indent = false)
328
  {
329
    if (is_html()) current_.append("<br>");   // Don't bother with matching </br>
330 331
    current_.append("\n", 1);

332 333
    if (_with_indent) indent(false);
    else at_line_start_ = true;
334

335 336
  }

337 338 339 340 341 342
  void set_level(int _lev)
  {
    lev_ = _lev;
  }

  void print_direct(const std::string& _s)
343 344 345 346 347
  {
    current_.append(_s);
  }


348 349
  void print(const char _c)
  {
350
    if (_c == '\n')
351 352 353 354 355
    {
      line_break();
      return;
    }

356 357
    if (at_line_start_)
    {
358
      indent(true);
359 360 361 362
      at_line_start_ = false;
    }


363 364 365
    if (is_html())
    {
      // translate the esoteric characters used in IGM DEB_out
366 367


368
      if (_c == '')  // -62
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
        return;

      if (_c == '') // 167 = -89
      {
        current_.append("&sect;");
        return;
      }

      if (_c == '') // -80
      {
        current_.append("&deg;");
        return;
      }
    }
    current_.append(&_c, 1);
384 385
  }

386
  void print(const char* const _s, bool _fork = true)
387 388 389
  {
    if (_s != nullptr)
    {
390
      for (int i = 0; ; ++i)
391 392
      {
        const char c = _s[i];
393
        if (c == '\0') break;
394 395 396 397
        print(c);
      }
      if (_fork)
      {
398 399 400 401
        if (fork_to_cout())
          std::cout << _s;
        if (fork_to_cerr())
          std::cerr << _s;
402
      }
403
    }
404 405 406 407 408 409 410 411
  }

  void print(int _i)
  {
    char buffer[64];
    sprintf_s(buffer, sizeof(buffer), "%i", _i);
    print(buffer);
  }
412

413 414 415 416 417 418 419
  void print(double _d)
  {
    char buffer[64];
    sprintf_s(buffer, sizeof(buffer), "%.17g", _d);
    print(buffer);
  }

420 421
  void print(const DebCommand& _co)
  {
422 423 424
    switch (_co.com())
    {
    case DebCommand::end :
425
      if (is_html()) print_direct("</FONT>");
426 427
      break;
    case DebCommand::end_lf :
428
      if (is_html()) print_direct("</FONT>");
429 430 431 432 433
      line_break();
      break;
    }
  }

434 435 436 437
  DebStream& stream()
  {
    return *deb_stream_;
  }
438

439 440
  // Append current asctime to given string
  bool add_time(std::string& str)
441 442
  {
    time_t rawtime;
443
    time(&rawtime);
444
    struct tm timeinfo;
445
    errno_t err = localtime_s(&timeinfo, &rawtime);
446 447 448 449 450 451
    if (err == 0)
    {
      char buffer[256];
      err = asctime_s(buffer, sizeof(buffer), &timeinfo);
      if (err == 0)
      {
452
        str.append(buffer);
453 454 455 456 457 458
        return true;
      }
    }
    return false;
  }

459

460
#if 1
461
  bool hover(std::string& _str, const std::string& _hover, const bool _open)
462 463 464 465
  {
    if (is_html())
    {
      char buffer[1024];
466 467
      if (_open)  sprintf_s(buffer, sizeof(buffer),
                              "<span title=\"%s\">", _hover.c_str());
468 469 470 471 472 473 474 475
      else sprintf_s(buffer, sizeof(buffer), "</span>");
      _str.append(buffer);
      return true;
    }
    return false;
  }
#endif

476
  bool anchor(std::string& _str, const int _id, const char* _tag, const bool _open)
477 478 479 480 481 482 483 484 485 486 487 488
  {
    if (is_html())
    {
      char buffer[1024];
      if (_open)  sprintf_s(buffer, sizeof(buffer), "<A name=\"%08X_%s\">", _id, _tag);
      else sprintf_s(buffer, sizeof(buffer), "</A>");
      _str.append(buffer);
      return true;
    }
    return false;
  }

489
  bool link_to(std::string& _str, const int _id, const char* _tag, const std::string& _hover, const bool _open)
490 491 492 493 494 495 496 497 498 499
  {
    if (is_html())
    {
      char buffer[2048];
      if (_open)
      {
        // HTML title hover text is cropped to 64 char in Firefox but displays
        // OK in Chrome. We could use javascript to avoid this limit but HTML
        // is simpler.
        if (_hover.empty()) sprintf_s(buffer, sizeof(buffer),
500 501 502
                                        "<A href=\"#%08X_%s\">", _id, _tag);
        else sprintf_s(buffer, sizeof(buffer),
                         "<A href=\"#%08X_%s\" title=\"%s\">", _id, _tag, _hover.c_str());
503 504 505 506 507 508 509 510 511
      }
      else sprintf_s(buffer, sizeof(buffer), "</A>");
      _str.append(buffer);
      return true;
    }
    return false;
  }


512 513 514
  void header(std::string& str)
  {
    if (is_html())
515 516 517 518 519 520 521 522 523
    {
      str.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\">");
      str.append("\n<HTML><HEAD>");
      str.append("\n<TITLE>ReForm DEB_out");
      str.append("</TITLE>");
      // javascript lib loads go here
      // stylesheet loads go here
      // within HEAD javascript goes here
      str.append("\n</HEAD>");
524
      if (is_white_on_black())
525
      {
526
        str.append("\n<BODY BGCOLOR=\"#000000\" TEXT=\"#FFFFFF\" LINK=\"#%00FFFF\" VLINK=\"#FFFF00\" >");
527
        //str.append( "\n<BODY BGCOLOR=\"#000000\" TEXT=\"#FFFFFF\"  >");
528 529 530 531
      }
      else
      {
        str.append("\n<BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#%FF0000\" VLINK=\"#0000FF\" >");
532
        //str.append( "\n<BODY BGCOLOR=\"#000000\" TEXT=\"#FFFFFF\" >");
533 534 535 536 537 538
      }
      str.append("\n");
    } // endif is_html
    bool date_header = true;
    if (date_header)
    {
539
      if (!file_name_.empty())
540 541 542 543
      {
        str.append(file_name_);
        str.append(" opened ");
      }
544
      add_time(str);
545
      str.append("[ Build: " __TIME__  " " __DATE__  "] ");
546 547
      if (is_html()) str.append("<BR>");
      str.append("\n");
548 549 550 551 552 553 554 555
    }
  }

  void footer()
  {
    bool date_footer = true;
    if (date_footer)
    {
556
      std::string str("\n");
557
      if (!file_name_.empty()) str.append(file_name_);
558
      str.append(" Closed: ");
559 560
      add_time(str);
      stream() << str << "\n";
561 562 563
    }

    if (is_html())
564
      stream().print("\n</BODY></HTML>", false);
565
  }
566

567 568 569 570
  bool is_first_flush()
  {
    return num_flush_ == 0 ;
  }
571

572 573 574
  int flush()
  {
    int res = 0;
575
    if (!current_.empty())
576
    {
577 578
      const char* fname = file_name();
      if ((fname != nullptr) || file_is_open())
579
      {
580
        if (!file_is_open())
581
        {
582 583 584
          file_stream_.open(fname,
                            std::fstream::out | ((is_appended() && !is_first_flush()) ?
                                                 std::fstream::app  :  std::fstream::trunc));
585 586 587 588 589
        }

        if (file_stream_.is_open())
        {
          std::string hdr;
590 591 592
          if (!is_appended())
          {
            // Reoutput entire file
593 594 595 596 597 598
            header(hdr);
            output_.append(hdr);
            file_stream_ << output_;
          }
          else
          {
599
            if (is_first_flush())
600 601
            {
              header(hdr);
602 603
              if (is_retained())
                output_.append(hdr);
604 605 606 607 608 609
              file_stream_ << hdr;
            }
            ++num_flush_;
          }
          file_stream_ << current_;

610
          if (is_retained())
611 612
            output_.append(current_);

613 614
          current_.clear();
          if (!is_kept_open())
615 616 617 618 619 620
            file_stream_.close();
        } // endif fs.is_open
        else
          res = -1;
      }
    } // endif current empty
621
    return res;
622 623 624 625 626 627 628 629 630
  }  // endfunc flush

  void close()
  {
    footer();
    flush();
  }


631
  void set_file_name(const char* _name)
632 633
  {
    file_name_ = _name;
634
    if (is_html_filename(_name))
635
      type_ = (DebStream::StreamType)(type_ | DebStream::StreamType::html);
636
  }
637 638

  void set_module_level(const char* const _module, const int _lev)
639 640
  {
    std::pair<module_map_itr, bool> ins =  module_map_.insert(
641
        std::pair<std::string, module_stats>(_module, module_stats(_lev)));
642 643 644
    if (!ins.second) ins.first->second.lev_ = _lev;
  }

645
  int get_module_level(const char* const _module) const
646 647 648 649 650 651
  {
    const_module_map_itr it = module_map_.find(std::string(_module));
    if (it == module_map_.end()) return lev_;
    return it->second.lev_;
  }

652
  void set_module_color(const char* const _module, const int _col)
653 654
  {
    std::pair<module_map_itr, bool> ins =  module_map_.insert(
655
        std::pair<std::string, module_stats>(_module, module_stats(lev_)));
656 657 658
    ins.first->second.col_ = _col;
  }

659
  int get_module_color(const char* const _module) const
660 661
  {
    const_module_map_itr it = module_map_.find(std::string(_module));
662 663 664 665 666
    if (it == module_map_.end())
    {
      if (is_white_on_black()) return 0xFFFFFF;
      else return 0x000000;
    }
667 668
    return it->second.col_;
  }
669 670

  int permission(const int _lev, const int _warn, const char* const _module)
671 672 673 674
  {
    _warn;
    int lev = get_module_level(_module);
    lev -= _lev;
675
    if (lev < 0) lev = 0;
676 677 678
    if (lev > 0) priority_ = lev;
    return lev;
  }
679 680

  bool is_at_line_start()
681
  {
682
    return at_line_start_;
683 684 685 686 687
  }


  DebFile(
    DebStream* _deb_stream,
688 689 690
    DebStream::StreamType _type = (DebStream::StreamType)(DebStream::append | DebStream::retain),
    const char* _file_name = nullptr) :
    type_(_type), lev_(5), deb_stream_(_deb_stream), num_flush_(0)
691 692
  {
    set_file_name(_file_name);
693
    indent_size_ = 3;
694
    at_line_start_ = false; // Don't want to indent header
695 696
    //    indent_string_ = ".";
    set_module_color("PARA", 0xFF8000);
697 698
    set_module_color("SOLV", 0x00FF00);
    set_module_color("NSLV", 0xFFFF00);
699
    set_module_color("FELD", 0x0080FF);
700
    set_module_color("CURV", 0x00FFFF);
701 702
    set_module_color("QMGN", 0xFF00FF);
    // Don't set a TEST module colour here because Test is not part of Reform
703 704 705 706
  }

  ~DebFile() {}

707

708
}; // endclass DebFile
709 710 711 712 713

// =====================================
//      DebEnter member funcs
// =====================================

714
DebEnter::DebEnter(const char* const _funcname, const int _count, const char* const _module)
715
{
716
  // TODO: this might have to be atomic
717
  static int id_cnt = 0;
718
  module_ = _module;
719
  deb_outs_ = 0;
720
  deb_lines_ = 0;
721
  id_ = ++id_cnt;
722 723
  count_ = _count;
  stream(0, false).dfile()->call_stack().add(_funcname, this);
724 725
}

726
DebEnter::~DebEnter()
727
{
728
  DebFile* impl = stream(0, false).dfile();
729
  impl->call_stack().pop();
730

731
  std::string str;
732
  if (((deb_outs_ > 0) || (deb_lines_ > 0)) && impl->anchor(str, id_, "exit", true))
733
  {
734
    impl->anchor(str, id_, "exit", false);
735 736
    impl->print_direct(str);
  }
737 738
}

739
DebStream& DebEnter::stream(const int _warn, const bool _print)
740
{
741 742
  DebStream& ds = ReForm::DebStream::get_global(_warn);
  DebFile* impl = ds.dfile();
743

744
  if (_print)
745
  {
746 747 748 749
    if (impl->is_html())
    {
      int col = impl->get_module_color(module_);
      char buffer[256];
750 751
      sprintf_s(buffer, sizeof(buffer), "<FONT COLOR=\"#%06X\" SIZE=%i>",
                col, impl->priority() + 1);
752
      impl->print_direct(buffer);
753 754
    }

755
    if (deb_outs_ < 1)
756 757
    {
      // First DEB_out in this function so output callstack, and flush.
758
      impl->indent(true);
759 760 761 762
      std::string str;
      bool is_html = impl->is_html();
      if (is_html)
      {
763
        str.append("<FONT SIZE=2><u>");
764
        impl->anchor(str, id_, "enter", true);
765
      }
766
      else
767 768
      {
        // .txt call stack lead in
769 770 771
        str.append("****>");
      }

772
      impl->call_stack().get(str);
773
      if (is_html) str.append("</u></FONT>");
774 775
      impl->print_direct(str.c_str()); // Don't fork callstack to cerr etc.
      impl->line_break();
776
      ds.dfile()->flush();
777 778 779 780 781 782 783
    }
    ++deb_outs_;
  }

  return ds;
}

784
int DebEnter::permission(const int _lev, const int _warn)
785
{
786 787
  int res = ReForm::DebStream::get_global().dfile()->permission(_lev, _warn, module_);
  return res;
788 789
}

790

791
void FunctionCallSequence::indent(std::string& _str, DebFile* _dfile, bool _is_html)
792 793
{
  int num = number_calls();
794 795 796
  for (int i = 0; i < num; ++i)
  {
    DebEnter* deb = debs_[i];
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
    if (_is_html)
    {
      /* HTML indent element is <L> with span title the name and count
      of the function and with < linking to the entry anchor (if present) and
      > linking to the exit anchor (will be present).
      L is the first letter of the module name */
      char hovert[1024];
      sprintf_s(hovert, sizeof(hovert), "%s[%i]", func_name_.c_str(), deb->count_);
      int col = _dfile->get_module_color(deb->module_);
      char buffer[1024];
      sprintf_s(buffer, sizeof(buffer), "<FONT COLOR=\"#%06X\">.", col);

      _dfile->hover(_str, std::string(hovert), true);

      _str.append(buffer);
      std::string cstk;
      //impl->call_stack().get(cstk);
814
      if ((deb->deb_outs_ > 0) && _dfile->link_to(_str, deb->id_, "enter", cstk, true))
815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
      {
        _str.append("&lt;");
        _dfile->link_to(_str, deb->id_, "enter", cstk,  false);
      }
      else _str.append("&lt;");

      _str.append(deb->module_, 1);

      if (_dfile->link_to(_str, deb->id_, "exit", cstk, true))
      {
        _str.append("&gt;");
        _dfile->link_to(_str, deb->id_, "exit", cstk,  false);
        ++deb->deb_lines_;
      }

      _dfile->hover(_str, std::string(hovert), false);

      _str.append("</FONT>");
    } // endif html
    else _str.append("  ");
  }
}

838
bool CallStack::indent(std::string& _str, DebFile* _dfile, const bool is_html)
839 840 841 842 843 844 845 846 847 848
{

  if (_dfile->indent_size() == 0) return false;
  if (is_html)
  {
    char buffer[64];
    sprintf_s(buffer, sizeof(buffer), "<FONT SIZE=%i>", _dfile->indent_size());
    _str.append(buffer);
  }
  int num = (int)calls_.size();
849 850
  int i0 = 0;
  if (!is_html) ++i0; // Don't waste whitespace on first level indent if .txt
851
  for (int i = i0; i < num; ++i)
852 853 854 855 856 857
    calls_[i].indent(_str, _dfile,  is_html);
  if (is_html) _str.append(":&nbsp;</FONT>\n");
  return true;
}


858 859 860 861 862
// =====================================
//        DebStream member funcs
// =====================================


863
DebStream::DebStream(const char* _file_name, StreamType _type)
864 865
{
  // NB. disable DEB_out over this new if new contains DEB_out
866
  dfile_ = new DebFile(this, _type, _file_name);
867 868 869 870
}

DebStream::~DebStream()
{
871
  if (dfile_ != nullptr)
872
  {
873 874
    dfile()->close();
    dfile()->clear();
875
    // NB. disable DEB_out over this delete if delete contains DEB_out
876 877
    delete dfile_;
    dfile_ = nullptr;
878 879 880 881 882
  }
}

DebStream& DebStream::print(const int _i)
{
883
  dfile_->print(_i);
884 885 886 887 888
  return *this;
};

DebStream& DebStream::print(const double _d)
{
889
  dfile_->print(_d);
890 891 892
  return *this;
};

893
DebStream& DebStream::print(const char* _s, bool _fork)
894
{
895
  dfile_->print(_s, _fork);
896 897 898 899 900
  return *this;
};

DebStream& DebStream::print(const char _c)
{
901 902 903 904
  dfile_->print(_c);
  return *this;
};

905
DebStream& DebStream::print(const DebCommand& _co)
906 907
{
  dfile_->print(_co);
908 909 910
  return *this;
};

911
DebStream& DebStream::get_global(int _warn)
912
{
913
  _warn;
914 915
  // TODO: Replace with a Singleton?? ThreadArray??
  static DebStream g_ds__("reform_deb_out.txt");
916
  //static DebStream g_ds__("reform_deb_out.htm");
917 918 919
  return g_ds__;
}

920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
DebStream& operator<<(DebStream& ds, const int i)
{
  return ds.print(i);
}
DebStream& operator<<(DebStream& ds, const double d)
{
  return ds.print(d);
}
DebStream& operator<<(DebStream& ds, const char* const s)
{
  return ds.print(s);
}
DebStream& operator<<(DebStream& ds, const char c)
{
  return ds.print(c);
}
936

937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
DebStream& operator<<(DebStream& ds, const size_t i)
{
  return ds.print((int)i);
}
DebStream& operator<<(DebStream& ds, const unsigned int i)
{
  return ds.print((int)i);
}
DebStream& operator<<(DebStream& ds, const float f)
{
  return ds.print((double)f);
}
DebStream& operator<<(DebStream& ds, const std::string& s)
{
  return ds.print(s.c_str());
}
953

954 955 956 957
DebStream& operator<<(DebStream& ds, const DebCommand& co)
{
  return ds.print(co);
}
958 959


960 961 962
}//namespace


963
#endif // DEB_ON