Skip to content
Snippets Groups Projects
Printout.cpp 13.67 KiB
//==========================================================================
//  AIDA Detector description implementation for LCD
//--------------------------------------------------------------------------
// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
// All rights reserved.
//
// For the licensing terms see $DD4hepINSTALL/LICENSE.
// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
//
// Author     : M.Frank
//
//==========================================================================

// Framework include files
#include "DD4hep/Printout.h"

// C/C++ include files
#include <cstring>
#include <cstdarg>
#include <sstream>
#include <stdexcept>
// Disable some diagnostics for ROOT dictionaries
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wvarargs"
#endif

using namespace std;

namespace {
  size_t _the_printer_1(void*, DD4hep::PrintLevel lvl, const char* src, const char* text);
  size_t _the_printer_2(void* par, DD4hep::PrintLevel lvl, const char* src, const char* fmt, va_list& args);

  std::string print_fmt = "%-16s %5s %s";
  DD4hep::PrintLevel print_lvl = DD4hep::INFO;
  void* print_arg = 0;
  DD4hep::output_function1_t print_func_1 = 0;
  DD4hep::output_function2_t print_func_2 = _the_printer_2;

  const char* print_level(DD4hep::PrintLevel lvl)   {
    switch(lvl)   {
    case DD4hep::NOLOG:     return "NOLOG";
    case DD4hep::VERBOSE:   return "VERB ";
    case DD4hep::DEBUG:     return "DEBUG";
    case DD4hep::INFO:      return "INFO ";
    case DD4hep::WARNING:   return "WARN ";
    case DD4hep::ERROR:     return "ERROR";
    case DD4hep::FATAL:     return "FATAL";
    case DD4hep::ALWAYS:    return "     ";
    default:
      if ( lvl> DD4hep::ALWAYS )
        return print_level(DD4hep::ALWAYS);
      return print_level(DD4hep::NOLOG);
    }
  }

  size_t _the_printer_1(void*, DD4hep::PrintLevel lvl, const char* src, const char* text) {
    ::fflush(stdout);
    ::fflush(stderr);
    cout << flush;
    cerr << flush;
    size_t len = ::fprintf(stdout, print_fmt.c_str(), src, print_level(lvl), text);
    ::fputc('\n',stdout);
    return len;
  }

  size_t _the_printer_2(void* par, DD4hep::PrintLevel lvl, const char* src, const char* fmt, va_list& args) {
    if ( !print_func_1 )  {
      char text[4096];
      ::fflush(stdout);
      ::fflush(stderr);
      cout << flush;
      cerr << flush;
      ::snprintf(text,sizeof(text),print_fmt.c_str(),src,print_level(lvl),fmt);
      size_t len = ::vfprintf(stdout, text, args);
      ::fputc('\n',stdout);
      return len;
    }
    char str[4096];
    ::vsnprintf(str, sizeof(str), fmt, args);
    return print_func_1(par, lvl, src, str);
  }

  string __format(const char* fmt, va_list& args) {
    char str[4096];
    ::vsnprintf(str, sizeof(str), fmt, args);
    return string(str);
  }
}

/// Helper function to serialize argument list to a single string
/**
 *  \arg argc       [int,read-only]      Number of arguments.
 *  \arg argv       [char**,read-only]   Argument strings
 *  \return String containing the concatenated arguments
 */
string DD4hep::arguments(int argc, char** argv)   {
  stringstream str;
  for(int i=0; i<argc;)  {
    str << argv[i];
    if ( ++i < argc ) str << " ";
  }
  return str.str();
}  

/** Calls the display action
 *  \arg severity   [int,read-only]      Display severity flag
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
int DD4hep::printout(PrintLevel severity, const char* src, const char* fmt, ...) {
  if (severity >= print_lvl) {
    va_list args;
    va_start(args, fmt);
    printout(severity, src, fmt, args);
    va_end(args);
  }
  return 1;
}

/** Calls the display action
 *  \arg severity   [int,read-only]      Display severity flag
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
int DD4hep::printout(PrintLevel severity, const string& src, const char* fmt, ...) {
  if (severity >= print_lvl) {
    va_list args;
    va_start(args, fmt);
    printout(severity, src.c_str(), fmt, args);
    va_end(args);
  }
  return 1;
}

/** Calls the display action
 *  \arg severity   [int,read-only]      Display severity flag
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
int DD4hep::printout(PrintLevel severity, const char* src, const string& fmt, ...) {
  if (severity >= print_lvl) {
    va_list args;
    va_start(args, &fmt);
    printout(severity, src, fmt.c_str(), args);
    va_end(args);
  }
  return 1;
}

/** Calls the display action
 *  \arg severity   [int,read-only]      Display severity flag
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
int DD4hep::printout(PrintLevel severity, const string& src, const string& fmt, ...) {
  if (severity >= print_lvl) {
    va_list args;
    va_start(args, &fmt);
    printout(severity, src.c_str(), fmt.c_str(), args);
    va_end(args);
  }
  return 1;
}

/** Calls the display action
 *  \arg severity   [int,read-only]      Display severity flag
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
int DD4hep::printout(PrintLevel severity, const char* src, const char* fmt, va_list& args) {
  if (severity >= print_lvl) {
    print_func_2(print_arg, severity,src,fmt,args);
  }
  return 1;
}

/** Calls the display action
 *  \arg severity   [int,read-only]      Display severity flag
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
int DD4hep::printout(PrintLevel severity, const string& src, const char* fmt, va_list& args) {
  return printout(severity, src.c_str(), fmt, args);
}

/** Calls the display action
 *  \arg severity   [int,read-only]      Display severity flag
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
int DD4hep::printout(PrintLevel severity, const char* src, const string& fmt, va_list& args) {
  return printout(severity, src, fmt.c_str(), args);
}

/** Calls the display action
 *  \arg severity   [int,read-only]      Display severity flag
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
int DD4hep::printout(PrintLevel severity, const string& src, const string& fmt, va_list& args) {
  return printout(severity, src.c_str(), fmt.c_str(), args);
}

/** Calls the display action with ERROR and throws an std::runtime_error exception
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
int DD4hep::except(const string& src, const string& fmt, ...) {
  va_list args;
  va_start(args, &fmt);
  return except(src.c_str(),fmt.c_str(), args);
}

/** Calls the display action with ERROR and throws an std::runtime_error exception
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
int DD4hep::except(const char* src, const char* fmt, ...) {
  va_list args;
  va_start(args, fmt);
  return except(src, fmt, args);
}

/** Calls the display action with ERROR and throws an std::runtime_error exception
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \arg args       [ap_list,read-only]  List with variable number of arguments to fill format string.
 *  \return Status code indicating success or failure
 */
int DD4hep::except(const string& src, const string& fmt, va_list& args) {
  string msg = __format(fmt.c_str(), args);
  va_end(args);
  printout(ERROR, src.c_str(), "%s", msg.c_str());
  // No return. Must call va_end here!
  throw runtime_error((src+": "+msg).c_str());
}

/** Calls the display action with ERROR and throws an std::runtime_error exception
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \arg args       [ap_list,read-only]  List with variable number of arguments to fill format string.
 *  \return Status code indicating success or failure
 */
int DD4hep::except(const char* src, const char* fmt, va_list& args) {
  string msg = __format(fmt, args);
  va_end(args);
  printout(ERROR, src, "%s", msg.c_str());
  // No return. Must call va_end here!
  throw runtime_error((string(src)+": "+msg).c_str());
}

/** Build exception string
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
string DD4hep::format(const string& src, const string& fmt, ...) {
  va_list args;
  va_start(args, &fmt);
  string str = format(src, fmt, args);
  va_end(args);
  return str;
}

/** Build exception string
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \return Status code indicating success or failure
 */
string DD4hep::format(const char* src, const char* fmt, ...) {
  va_list args;
  va_start(args, fmt);
  string str = format(src, fmt, args);
  va_end(args);
  return str;
}

/** Build exception string and throw std::runtime_error
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \arg args       [ap_list,read-only]  List with variable number of arguments to fill format string.
 *  \return Status code indicating success or failure
 */
string DD4hep::format(const string& src, const string& fmt, va_list& args) {
  return format(src.c_str(), fmt.c_str(), args);
}

/** Build exception string and throw std::runtime_error
 *  \arg src        [string,read-only]   Information source (component, etc.)
 *  \arg fmt        [string,read-only]   Format string for ellipsis args
 *  \arg args       [ap_list,read-only]  List with variable number of arguments to fill format string.
 *  \return Status code indicating success or failure
 */
string DD4hep::format(const char* src, const char* fmt, va_list& args) {
  char str[4096];
  size_t len1 = ::snprintf(str, sizeof(str), "%s: ", src);
  size_t len2 = ::vsnprintf(str + len1, sizeof(str) - len1, fmt, args);
  if ( len2 > sizeof(str) - len1 )  {
    len2 = sizeof(str) - len1 - 1;
    str[sizeof(str)-1] = 0;
  }
  return string(str);
}

/// Set new print level. Returns the old print level
DD4hep::PrintLevel DD4hep::setPrintLevel(PrintLevel new_level) {
  PrintLevel old = print_lvl;
  print_lvl = new_level;
  return old;
}

/// Access the current printer level
DD4hep::PrintLevel DD4hep::printLevel()  {
  return print_lvl;
}

/// Translate the printer level from string to value
DD4hep::PrintLevel DD4hep::printLevel(const char* value)  {
  if ( !value ) except("Printout","Invalid printlevel requested [EINVAL: Null-pointer argument]");
  // Explicit values
  if ( strcmp(value,"NOLOG")   == 0 ) return DD4hep::NOLOG;
  if ( strcmp(value,"VERBOSE") == 0 ) return DD4hep::VERBOSE;
  if ( strcmp(value,"DEBUG")   == 0 ) return DD4hep::DEBUG;
  if ( strcmp(value,"INFO")    == 0 ) return DD4hep::INFO;
  if ( strcmp(value,"WARNING") == 0 ) return DD4hep::WARNING;
  if ( strcmp(value,"ERROR")   == 0 ) return DD4hep::ERROR;
  if ( strcmp(value,"FATAL")   == 0 ) return DD4hep::FATAL;
  if ( strcmp(value,"ALWAYS")  == 0 ) return DD4hep::ALWAYS;
  // Numeric values
  if ( strcmp(value,"0")       == 0 ) return DD4hep::NOLOG;
  if ( strcmp(value,"1")       == 0 ) return DD4hep::VERBOSE;
  if ( strcmp(value,"2")       == 0 ) return DD4hep::DEBUG;
  if ( strcmp(value,"3")       == 0 ) return DD4hep::INFO;
  if ( strcmp(value,"4")       == 0 ) return DD4hep::WARNING;
  if ( strcmp(value,"5")       == 0 ) return DD4hep::ERROR;
  if ( strcmp(value,"6")       == 0 ) return DD4hep::FATAL;
  if ( strcmp(value,"7")       == 0 ) return DD4hep::ALWAYS;
  except("Printout","Unknown printlevel requested:%s",value);
  return DD4hep::ALWAYS;
}

/// Translate the printer level from string to value
DD4hep::PrintLevel DD4hep::printLevel(const std::string& value)  {
  return printLevel(value.c_str());
}

/// Check if this print level would result in some output
bool DD4hep::isActivePrintLevel(int severity)   {
  return severity >= print_lvl;
}

/// Set new printout format for the 3 fields: source-level-message. All 3 are strings
string DD4hep::setPrintFormat(const string& new_format) {
  string old = print_fmt;
  print_fmt  = new_format;
  return old;
}

/// Customize printer function
void DD4hep::setPrinter(void* arg, output_function1_t fcn) {
  print_arg  = arg;
  print_func_1 = fcn ? fcn : _the_printer_1;
}

/// Customize printer function
void DD4hep::setPrinter2(void* arg, output_function2_t fcn) {
  print_arg = arg;
  print_func_2 = fcn ? fcn : _the_printer_2;
}