LCOV - code coverage report
Current view: top level - libMagAOX/logger - logMeta.cpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 0.0 % 243 0
Test Date: 2026-01-03 21:03:39 Functions: 0.0 % 9 0

            Line data    Source code
       1              : /** \file logMeta.cpp
       2              :   * \brief Declares and defines the logMeta class and related classes.
       3              :   * \author Jared R. Males (jaredmales@gmail.com)
       4              :   *
       5              :   * \ingroup logger_files
       6              :   *
       7              :   */
       8              : 
       9              : 
      10              : #include "logMeta.hpp"
      11              : 
      12              : //#include "generated/logTypes.hpp"
      13              : 
      14              : #include "generated/logMemberAccessor.hpp"
      15              : 
      16              : 
      17              : namespace MagAOX
      18              : {
      19              : namespace logger
      20              : {
      21              : 
      22              : /*
      23              : logMetaDetail logMemberAccessor( flatlogs::eventCodeT ec,
      24              :                           const std::string & memberName
      25              :                         )
      26              : {
      27              :    switch(ec)
      28              :    {
      29              :       case telem_stdcam::eventCode:
      30              :          return telem_stdcam::getAccessor(memberName);
      31              :       case telem_telcat::eventCode:
      32              :          return telem_telcat::getAccessor(memberName);
      33              :       case telem_teldata::eventCode:
      34              :          return telem_teldata::getAccessor(memberName);
      35              :       case telem_telpos::eventCode:
      36              :          return telem_telpos::getAccessor(memberName);
      37              :       case telem_stage::eventCode:
      38              :          return telem_stage::getAccessor(memberName);
      39              :       case telem_zaber::eventCode:
      40              :          return telem_zaber::getAccessor(memberName);
      41              :       case telem_dmspeck::eventCode:
      42              :          return telem_dmspeck::getAccessor(memberName);
      43              :       case telem_observer::eventCode:
      44              :          return telem_observer::getAccessor(memberName);
      45              :       case telem_fxngen::eventCode:
      46              :          return telem_fxngen::getAccessor(memberName);
      47              :       case telem_loopgain::eventCode:
      48              :          return telem_loopgain::getAccessor(memberName);
      49              :       default:
      50              :          std::cerr << "Missing logMemberAccessor case entry for " << ec << ": " << memberName << "\n";
      51              :          return logMetaDetail();
      52              :    }
      53              : }*/
      54              : 
      55              : 
      56            0 : logMeta::logMeta( const logMetaSpec & lms )
      57              : {
      58            0 :    setLog(lms);
      59            0 : }
      60              : 
      61            0 : const std::string & logMeta::device()
      62              : {
      63            0 :    return m_spec.device;
      64              : }
      65              : 
      66            0 : const std::string & logMeta::keyword()
      67              : {
      68            0 :    return m_spec.keyword;
      69              : }
      70              : 
      71            0 : const std::string & logMeta::comment()
      72              : {
      73            0 :    return m_spec.comment;
      74              : }
      75              : 
      76            0 : int logMeta::setLog( const logMetaSpec & lms )
      77              : {
      78            0 :    m_spec = lms;
      79            0 :    m_detail = logMemberAccessor(m_spec.eventCode, m_spec.member);
      80              : 
      81            0 :    if(m_spec.keyword == "") m_spec.keyword = m_detail.keyword;
      82            0 :    if(m_spec.format == "") m_spec.format = m_detail.format;
      83            0 :    if(m_spec.format == "")
      84              :    {
      85            0 :       switch(m_detail.valType)
      86              :       {
      87            0 :          case valTypes::String:
      88            0 :             m_spec.format = "%s";
      89            0 :             break;
      90            0 :          case valTypes::Bool:
      91            0 :             m_spec.format = "%d";
      92            0 :             break;
      93            0 :          case valTypes::Char:
      94            0 :             m_spec.format = "%d";
      95            0 :             break;
      96            0 :          case valTypes::UChar:
      97            0 :             m_spec.format = "%u";
      98            0 :             break;
      99            0 :          case valTypes::Short:
     100            0 :             m_spec.format = "%d";
     101            0 :             break;
     102            0 :          case valTypes::UShort:
     103            0 :             m_spec.format = "%u";
     104            0 :             break;
     105            0 :          case valTypes::Int:
     106            0 :             m_spec.format = "%d";
     107            0 :             break;
     108            0 :          case valTypes::UInt:
     109            0 :             m_spec.format = "%u";
     110            0 :             break;
     111            0 :          case valTypes::Long:
     112            0 :             m_spec.format = "%ld";
     113            0 :             break;
     114            0 :          case valTypes::ULong:
     115            0 :             m_spec.format = "%lu";
     116            0 :             break;
     117            0 :          case valTypes::Float:
     118            0 :             m_spec.format = "%G";
     119            0 :             break;
     120            0 :          case valTypes::Double:
     121            0 :             m_spec.format = "%G";
     122            0 :             break;
     123            0 :          case valTypes::Vector_Bool:
     124            0 :             m_spec.format = "%d";
     125            0 :             break;
     126            0 :          case valTypes::Vector_Float:
     127            0 :             m_spec.format = "%G";
     128            0 :             break;
     129            0 :          default:
     130            0 :             std::cerr << "Unrecognised value type for " + m_spec.device + " " + m_spec.keyword + ".  Using format %d/\n";
     131            0 :             m_spec.format = "%d";
     132              : 
     133              :       }
     134              : 
     135              :    }
     136              : 
     137              : 
     138            0 :    if(m_spec.comment == "") m_spec.comment = m_detail.comment;
     139              : 
     140            0 :    return 0;
     141              : }
     142              : 
     143              : 
     144            0 : std::string logMeta::value( logMap<verboseT> & lm,
     145              :                             const flatlogs::timespecX & stime,
     146              :                             const flatlogs::timespecX & atime
     147              :                           )
     148              : {
     149            0 :    if(m_detail.accessor == nullptr) return "";
     150              : 
     151            0 :    if(m_detail.valType == valTypes::String)
     152              :    {
     153            0 :       std::string vs = valueString( lm, stime, atime);
     154            0 :       if(vs == m_invalidValue)
     155              :       {
     156            0 :          std::cerr << __FILE__ << " " << __LINE__ << " valueString returned invalid value\n";
     157              :       }
     158            0 :       return vs;
     159            0 :    }
     160              :    else
     161              :    {
     162            0 :       std::string vn = valueNumber( lm, stime, atime);
     163            0 :       if(vn == m_invalidValue)
     164              :       {
     165            0 :          std::cerr << __FILE__ << " " << __LINE__ << " valueNumber returned invalid value\n";
     166              :       }
     167            0 :       return vn;
     168            0 :    }
     169              : }
     170              : 
     171            0 : std::string logMeta::valueNumber( logMap<verboseT> & lm,
     172              :                                   const flatlogs::timespecX & stime,
     173              :                                   const flatlogs::timespecX & atime
     174              :                                 )
     175              : {
     176              :    char str[64];
     177              : 
     178            0 :    if(m_detail.metaType == metaTypes::State)
     179              :    {
     180            0 :       switch(m_detail.valType)
     181              :       {
     182            0 :          case valTypes::Bool:
     183              :          {
     184              :             bool val;
     185            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<bool(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     186            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     187            0 :             return std::string(str);
     188              :          }
     189            0 :          case valTypes::Char:
     190              :          {
     191              :             char val;
     192            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<char(*)(void*)>(m_detail.accessor), &m_hint) != 0)
     193              :             {
     194            0 :                std::cerr << "getLogStateVal returned error: " << __FILE__ << " " << __LINE__ << "\n";
     195            0 :                return m_invalidValue;
     196              :             }
     197            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     198            0 :             return std::string(str);
     199              :          }
     200            0 :          case valTypes::UChar:
     201              :          {
     202              :             unsigned char val;
     203            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<unsigned char(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     204            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     205            0 :             return std::string(str);
     206              :          }
     207            0 :          case valTypes::Short:
     208              :          {
     209              :             short val;
     210            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<short(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     211            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     212            0 :             return std::string(str);
     213              :          }
     214            0 :          case valTypes::UShort:
     215              :          {
     216              :             unsigned short val;
     217            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<unsigned short(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     218            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     219            0 :             return std::string(str);
     220              :          }
     221            0 :          case valTypes::Int:
     222              :          {
     223              :             int val;
     224            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<int(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     225            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     226            0 :             return std::string(str);
     227              :          }
     228            0 :          case valTypes::UInt:
     229              :          {
     230              :             unsigned int val;
     231            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<unsigned int(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     232            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     233            0 :             return std::string(str);
     234              :          }
     235            0 :          case valTypes::Long:
     236              :          {
     237              :             long val;
     238            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<long(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     239            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     240            0 :             return std::string(str);
     241              :          }
     242            0 :          case valTypes::ULong:
     243              :          {
     244              :             unsigned long val;
     245            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<unsigned long(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     246            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     247            0 :             return std::string(str);
     248              :          }
     249            0 :          case valTypes::LongLong:
     250              :          {
     251              :             long long val;
     252            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<long long(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     253            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     254            0 :             return std::string(str);
     255              :          }
     256            0 :          case valTypes::ULongLong:
     257              :          {
     258              :             unsigned long long val;
     259            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<unsigned long long(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     260            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     261            0 :             return std::string(str);
     262              :          }
     263            0 :          case valTypes::Float:
     264              :          {
     265              :             float val;
     266            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<float(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     267            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     268            0 :             return std::string(str);
     269              :          }
     270            0 :          case valTypes::Double:
     271              :          {
     272              :             double val;
     273            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<double(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     274            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     275            0 :             return std::string(str);
     276              :          }
     277            0 :          case valTypes::Vector_Bool:
     278              :          {
     279            0 :             std::vector<bool> val;
     280            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<std::vector<bool>(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     281              : 
     282            0 :             if(val.size() == 0) return "";
     283              : 
     284            0 :             std::string res;
     285              : 
     286            0 :             for(size_t n = 0; n < val.size()-1; ++n)
     287              :             {
     288            0 :                snprintf(str, sizeof(str), m_spec.format.c_str(), (int) val[n]);
     289            0 :                res += str;
     290            0 :                res += ',';
     291              :             }
     292              : 
     293            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), (int) val.back());
     294            0 :             res += str;
     295              : 
     296            0 :             return res;
     297            0 :          }
     298            0 :          case valTypes::Vector_Float:
     299              :          {
     300            0 :             std::vector<float> val;
     301            0 :             if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<std::vector<float>(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     302              : 
     303            0 :             if(val.size() == 0) return "";
     304              : 
     305            0 :             std::string res;
     306              : 
     307            0 :             for(size_t n = 0; n < val.size()-1; ++n)
     308              :             {
     309            0 :                snprintf(str, sizeof(str), m_spec.format.c_str(), val[n]);
     310            0 :                res += str;
     311            0 :                res += ',';
     312              :             }
     313              : 
     314            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val.back());
     315            0 :             res += str;
     316              : 
     317            0 :             std::cerr << "State Vector_Float " << res << '\n';
     318            0 :             return res;
     319            0 :          }
     320            0 :          default:
     321            0 :             return m_invalidValue;
     322              :       }
     323              :    }
     324            0 :    else if(m_detail.metaType == metaTypes::Continuous)
     325              :    {
     326            0 :       switch(m_detail.valType)
     327              :       {
     328            0 :          case valTypes::Bool:
     329              :          {
     330              :             bool val;
     331            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<bool(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     332            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     333            0 :             return std::string(str);
     334              :          }
     335            0 :          case valTypes::Char:
     336              :          {
     337              :             char val;
     338            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<char(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     339            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     340            0 :             return std::string(str);
     341              :          }
     342            0 :          case valTypes::UChar:
     343              :          {
     344              :             unsigned char val;
     345            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<unsigned char(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     346            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     347            0 :             return std::string(str);
     348              :          }
     349            0 :          case valTypes::Short:
     350              :          {
     351              :             short val;
     352            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<short(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     353            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     354            0 :             return std::string(str);
     355              :          }
     356            0 :          case valTypes::UShort:
     357              :          {
     358              :             unsigned short val;
     359            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<unsigned short(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     360            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     361            0 :             return std::string(str);
     362              :          }
     363            0 :          case valTypes::Int:
     364              :          {
     365              :             int val;
     366            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<int(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     367            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     368            0 :             return std::string(str);
     369              :          }
     370            0 :          case valTypes::UInt:
     371              :          {
     372              :             unsigned int val;
     373            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<unsigned int(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     374            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     375            0 :             return std::string(str);
     376              :          }
     377            0 :          case valTypes::Long:
     378              :          {
     379              :             long val;
     380            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<long(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     381            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     382            0 :             return std::string(str);
     383              :          }
     384            0 :          case valTypes::ULong:
     385              :          {
     386              :             unsigned long val;
     387            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<unsigned long(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     388            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     389            0 :             return std::string(str);
     390              :          }
     391            0 :          case valTypes::LongLong:
     392              :          {
     393              :             long long val;
     394            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<long long(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     395            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     396            0 :             return std::string(str);
     397              :          }
     398            0 :          case valTypes::ULongLong:
     399              :          {
     400              :             unsigned long long val;
     401            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<unsigned long long(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     402            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     403            0 :             return std::string(str);
     404              :          }
     405            0 :          case valTypes::Float:
     406              :          {
     407              :             float val;
     408            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<float(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     409            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     410            0 :             return std::string(str);
     411              :          }
     412            0 :          case valTypes::Double:
     413              :          {
     414              :             double val;
     415            0 :             if( getLogContVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<double(*)(void*)>(m_detail.accessor), &m_hint) != 0) return m_invalidValue;
     416            0 :             snprintf(str, sizeof(str), m_spec.format.c_str(), val);
     417            0 :             return std::string(str);
     418              :          }
     419            0 :          default:
     420            0 :             return m_invalidValue;
     421              :       }
     422              :    }
     423              : 
     424            0 :    return m_invalidValue;
     425              : 
     426              : }
     427              : 
     428            0 : std::string logMeta::valueString( logMap<verboseT> & lm,
     429              :                                   const flatlogs::timespecX & stime,
     430              :                                   const flatlogs::timespecX & atime
     431              :                                 )
     432              : {
     433            0 :    std::string val;
     434            0 :    if(m_detail.metaType == metaTypes::State)
     435              :    {
     436            0 :       if( getLogStateVal(val,lm, m_spec.device,m_spec.eventCode,stime,atime,reinterpret_cast<std::string(*)(void*)>(m_detail.accessor), &m_hint) != 0)
     437              :       {
     438            0 :          std::cerr << "getLogStateVal returned error " << __FILE__ << " " << __LINE__ << "\n";
     439              : 
     440              :          #ifdef HARD_EXIT
     441              :          std::cerr << __FILE__ << " " << __LINE__ << "\n";
     442              : 
     443              :          exit(-1);
     444              :          #endif
     445            0 :          val = m_invalidValue;
     446              :       }
     447              :    }
     448              :    else
     449              :    {
     450            0 :       std::cerr << "String type specified as something other than state\n";
     451              :    }
     452            0 :    return val;
     453            0 : }
     454              : 
     455            0 : mx::fits::fitsHeaderCard<logMeta::verboseT> logMeta::card( logMap<verboseT> &lm,
     456              :                                           const flatlogs::timespecX & stime,
     457              :                                           const flatlogs::timespecX & atime
     458              :                                         )
     459              : {
     460              :    #ifdef DEBUG
     461              :    std::cerr << __FILE__ << " " << __LINE__ << "\n";
     462              :    #endif
     463              : 
     464            0 :    std::string vstr = value(lm, stime, atime);
     465              : 
     466              :    #ifdef DEBUG
     467              :    std::cerr << __FILE__ << " " << __LINE__ << "\n";
     468              :    #endif
     469              : 
     470            0 :    std::string keyw;
     471            0 :    if(m_detail.hierarch)
     472              :    {
     473              :       //Add spaces to make sure hierarch is invoked
     474            0 :       keyw = m_spec.device + " " + m_spec.keyword;
     475            0 :       if(keyw.size() < 9)
     476              :       {
     477            0 :          keyw += std::string(9-keyw.size(), ' ');
     478              :       }
     479              :    }
     480              :    else
     481              :    {
     482            0 :       keyw = m_spec.keyword;
     483              :    }
     484              : 
     485            0 :    if(vstr == m_invalidValue)
     486              :    {
     487            0 :       std::cerr << "got invalid value: " << __FILE__ << " " << __LINE__ << "\n";
     488              :       // always a string sentinel value, so return here to skip the valType conditional
     489            0 :       return mx::fits::fitsHeaderCard<verboseT>(keyw, vstr, m_spec.comment);
     490              :    }
     491              : 
     492            0 :    if(m_detail.valType == valTypes::String || m_detail.valType == valTypes::Vector_Bool || m_detail.valType == valTypes::Vector_Float)
     493              :    {
     494            0 :       return mx::fits::fitsHeaderCard<verboseT>(keyw, vstr, m_spec.comment);
     495              :    }
     496              :    else
     497              :    {
     498            0 :       return mx::fits::fitsHeaderCard<verboseT>(keyw, vstr.c_str(), m_detail.valType, m_spec.comment);
     499              :    }
     500            0 : }
     501              : 
     502              : } // logger
     503              : } // MagAOX
     504              : 
     505              : 
     506              : 
        

Generated by: LCOV version 2.0-1