<commit_before>/** \file    add_author_synonyms.cc
 *  \brief   Adds author synonyms to each record.
 *  \author  Oliver Obenland
 */

/*
    Copyright (C) 2016-2018, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "MARC.h"
#include "StringUtil.h"
#include "util.h"

static unsigned modified_count(0);
static unsigned record_count(0);

namespace {

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " master_marc_input norm_data_marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

void RemoveCommasDuplicatesAndEmptyEntries(std::vector<std::string> * const vector) {
    std::vector<std::string> cleaned_up_vector;
    std::set<std::string> unique_entries;

    for (auto &entry : *vector) {
        StringUtil::RemoveChars(",", &entry);

        if (entry.empty())
            continue;

        const bool is_new_entry(unique_entries.emplace(entry).second);
        if (is_new_entry)
            cleaned_up_vector.emplace_back(std::move(entry));
    }
    vector->swap(cleaned_up_vector);
}

std::string ExtractNameFromSubfields(const MARC::Record::Field &field, const std::string &subfield_codes) {
    auto subfield_values(field.getSubfields().extractSubfields(subfield_codes));

    if (subfield_values.empty())
        return "";

    std::sort(subfield_values.begin(), subfield_values.end());
    return StringUtil::Join(subfield_values, ' ');
}

void ExtractSynonyms(MARC::Reader * const marc_reader, std::map<std::string, std::string> &author_to_synonyms_map,
                     const std::string &field_list)
{
    std::set<std::string> synonyms;
    std::vector<std::string> tags_and_subfield_codes;
    if (unlikely(StringUtil::Split(field_list, ':', &tags_and_subfield_codes) < 2))
        LOG_ERROR("in ExtractSynonymsAndWriteSynonymMap: need at least two fields!");
    unsigned count(0);
    while (const MARC::Record record = marc_reader->read()) {
        ++count;

        const auto primary_name_field(record.findTag(tags_and_subfield_codes[0].substr(0, 3)));
        if (primary_name_field != record.end())
            continue;

        const std::string primary_name(ExtractNameFromSubfields(*primary_name_field,
                                                                tags_and_subfield_codes[0].substr(3)));
        if (unlikely(primary_name.empty()))
            continue;

        std::vector<std::string> alternatives;
        alternatives.emplace_back(primary_name);
        if (author_to_synonyms_map.find(primary_name) != author_to_synonyms_map.end())
            continue;

        for (unsigned i(1); i < tags_and_subfield_codes.size(); ++i) {
            const std::string tag(tags_and_subfield_codes[i].substr(0, 3));
            const std::string secondary_field_subfield_codes(tags_and_subfield_codes[i].substr(3));
            for (auto secondary_name_field(record.findTag(tag));
                secondary_name_field != record.end();
                ++secondary_name_field)
            {
                const std::string secondary_name(ExtractNameFromSubfields(*secondary_name_field,
                                                                          secondary_field_subfield_codes));
                if (not secondary_name.empty())
                    alternatives.emplace_back(secondary_name);
            }
        }
        RemoveCommasDuplicatesAndEmptyEntries(&alternatives);
        if (alternatives.size() <= 1)
            continue;

        alternatives.erase(alternatives.begin());
        author_to_synonyms_map.emplace(primary_name, StringUtil::Join(alternatives, ','));
    }

    std::cout << "Found synonyms for " << author_to_synonyms_map.size() << " authors while processing " << count
              << " norm data records.\n";
}

const std::string SYNOMYM_FIELD("109"); // This must be an o/w unused field!

void ProcessRecord(MARC::Record * const record, const std::map<std::string, std::string> &author_to_synonyms_map,
                   const std::string &primary_author_field)
{
    if (unlikely(record->findTag(SYNOMYM_FIELD) != record->end()))
        LOG_ERROR("field " + SYNOMYM_FIELD + " is apparently already in use in at least some title records!");

    const auto primary_name_field(record->findTag(primary_author_field.substr(0, 3)));
    if (primary_name_field == record->end())
        return;

    const std::string primary_name(ExtractNameFromSubfields(*primary_name_field,
                                                            primary_author_field.substr(3)));
    if (unlikely(primary_name.empty()))
        return;

    const auto synonyms_iterator = author_to_synonyms_map.find(primary_name);
    if (synonyms_iterator == author_to_synonyms_map.end())
        return;

    const std::string synonyms = synonyms_iterator->second;
    MARC::Subfields subfields;
    subfields.addSubfield('a', synonyms);

    if (not record->insertField(SYNOMYM_FIELD, subfields)) {
        LOG_WARNING("Not enough room to add a " + SYNOMYM_FIELD + " field! (Control number: "
                    + record->getControlNumber() + ")");
        return;
    }
    ++modified_count;
}

void AddAuthorSynonyms(MARC::Reader * const marc_reader, MARC::Writer * marc_writer,
                       const std::map<std::string, std::string> &author_to_synonyms_map,
                       const std::string &primary_author_field)
{
    while (MARC::Record record = marc_reader->read()) {
        ProcessRecord(&record, author_to_synonyms_map, primary_author_field);
        marc_writer->write(record);
        ++record_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

} // unnamed namespace

int Main(int argc, char **argv) {
    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    const std::string authority_data_marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);

    if (unlikely(marc_input_filename == marc_output_filename))
        LOG_ERROR("Title input file name equals title output file name!");
    if (unlikely(authority_data_marc_input_filename == marc_output_filename))
        LOG_ERROR("Authority data input file name equals MARC output file name!");

    auto marc_reader(MARC::Reader::Factory(marc_input_filename));
    auto authority_reader(MARC::Reader::Factory(authority_data_marc_input_filename));
    auto marc_writer(MARC::Writer::Factory(marc_output_filename));

    try {
        std::map<std::string, std::string> author_to_synonyms_map;
        ExtractSynonyms(authority_reader.get(), author_to_synonyms_map, "100abcd:400abcd");
        AddAuthorSynonyms(marc_reader.get(), marc_writer.get(), author_to_synonyms_map, "100abcd");
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }

    return EXIT_SUCCESS;
}
<commit_msg>Fixed a trivial bug.<commit_after>/** \file    add_author_synonyms.cc
 *  \brief   Adds author synonyms to each record.
 *  \author  Oliver Obenland
 */

/*
    Copyright (C) 2016-2018, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "MARC.h"
#include "StringUtil.h"
#include "util.h"

static unsigned modified_count(0);
static unsigned record_count(0);

namespace {

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " master_marc_input norm_data_marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

void RemoveCommasDuplicatesAndEmptyEntries(std::vector<std::string> * const vector) {
    std::vector<std::string> cleaned_up_vector;
    std::set<std::string> unique_entries;

    for (auto &entry : *vector) {
        StringUtil::RemoveChars(",", &entry);

        if (entry.empty())
            continue;

        const bool is_new_entry(unique_entries.emplace(entry).second);
        if (is_new_entry)
            cleaned_up_vector.emplace_back(std::move(entry));
    }
    vector->swap(cleaned_up_vector);
}

std::string ExtractNameFromSubfields(const MARC::Record::Field &field, const std::string &subfield_codes) {
    auto subfield_values(field.getSubfields().extractSubfields(subfield_codes));

    if (subfield_values.empty())
        return "";

    std::sort(subfield_values.begin(), subfield_values.end());
    return StringUtil::Join(subfield_values, ' ');
}

void ExtractSynonyms(MARC::Reader * const marc_reader, std::map<std::string, std::string> &author_to_synonyms_map,
                     const std::string &field_list)
{
    std::set<std::string> synonyms;
    std::vector<std::string> tags_and_subfield_codes;
    if (unlikely(StringUtil::Split(field_list, ':', &tags_and_subfield_codes) < 2))
        LOG_ERROR("need at least two fields!");
    unsigned count(0);
    while (const MARC::Record record = marc_reader->read()) {
        ++count;

        const auto primary_name_field(record.findTag(tags_and_subfield_codes[0].substr(0, MARC::Record::TAG_LENGTH)));
        if (primary_name_field == record.end())
            continue;

        const std::string primary_name(ExtractNameFromSubfields(*primary_name_field,
                                                                tags_and_subfield_codes[0].substr(3)));
        if (unlikely(primary_name.empty()))
            continue;

        std::vector<std::string> alternatives;
        alternatives.emplace_back(primary_name);
        if (author_to_synonyms_map.find(primary_name) != author_to_synonyms_map.end())
            continue;

        for (unsigned i(1); i < tags_and_subfield_codes.size(); ++i) {
            const std::string tag(tags_and_subfield_codes[i].substr(0, 3));
            const std::string secondary_field_subfield_codes(tags_and_subfield_codes[i].substr(3));
            for (auto secondary_name_field(record.findTag(tag));
                secondary_name_field != record.end();
                ++secondary_name_field)
            {
                const std::string secondary_name(ExtractNameFromSubfields(*secondary_name_field,
                                                                          secondary_field_subfield_codes));
                if (not secondary_name.empty())
                    alternatives.emplace_back(secondary_name);
            }
        }
        RemoveCommasDuplicatesAndEmptyEntries(&alternatives);
        if (alternatives.size() <= 1)
            continue;

        alternatives.erase(alternatives.begin());
        author_to_synonyms_map.emplace(primary_name, StringUtil::Join(alternatives, ','));
    }

    std::cout << "Found synonyms for " << author_to_synonyms_map.size() << " authors while processing " << count
              << " norm data records.\n";
}

const std::string SYNOMYM_FIELD("109"); // This must be an o/w unused field!

void ProcessRecord(MARC::Record * const record, const std::map<std::string, std::string> &author_to_synonyms_map,
                   const std::string &primary_author_field)
{
    if (unlikely(record->findTag(SYNOMYM_FIELD) != record->end()))
        LOG_ERROR("field " + SYNOMYM_FIELD + " is apparently already in use in at least some title records!");

    const auto primary_name_field(record->findTag(primary_author_field.substr(0, 3)));
    if (primary_name_field == record->end())
        return;

    const std::string primary_name(ExtractNameFromSubfields(*primary_name_field,
                                                            primary_author_field.substr(3)));
    if (unlikely(primary_name.empty()))
        return;

    const auto synonyms_iterator = author_to_synonyms_map.find(primary_name);
    if (synonyms_iterator == author_to_synonyms_map.end())
        return;

    const std::string synonyms = synonyms_iterator->second;
    MARC::Subfields subfields;
    subfields.addSubfield('a', synonyms);

    if (not record->insertField(SYNOMYM_FIELD, subfields)) {
        LOG_WARNING("Not enough room to add a " + SYNOMYM_FIELD + " field! (Control number: "
                    + record->getControlNumber() + ")");
        return;
    }
    ++modified_count;
}

void AddAuthorSynonyms(MARC::Reader * const marc_reader, MARC::Writer * marc_writer,
                       const std::map<std::string, std::string> &author_to_synonyms_map,
                       const std::string &primary_author_field)
{
    while (MARC::Record record = marc_reader->read()) {
        ProcessRecord(&record, author_to_synonyms_map, primary_author_field);
        marc_writer->write(record);
        ++record_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

} // unnamed namespace

int Main(int argc, char **argv) {
    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    const std::string authority_data_marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);

    if (unlikely(marc_input_filename == marc_output_filename))
        LOG_ERROR("Title input file name equals title output file name!");
    if (unlikely(authority_data_marc_input_filename == marc_output_filename))
        LOG_ERROR("Authority data input file name equals MARC output file name!");

    auto marc_reader(MARC::Reader::Factory(marc_input_filename));
    auto authority_reader(MARC::Reader::Factory(authority_data_marc_input_filename));
    auto marc_writer(MARC::Writer::Factory(marc_output_filename));

    try {
        std::map<std::string, std::string> author_to_synonyms_map;
        ExtractSynonyms(authority_reader.get(), author_to_synonyms_map, "100abcd:400abcd");
        AddAuthorSynonyms(marc_reader.get(), marc_writer.get(), author_to_synonyms_map, "100abcd");
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>
#include "lcio.h"

#include "IO/LCWriter.h"
#include "EVENT/LCIO.h"
#include "DATA/LCFloatVec.h"
#include "DATA/LCIntVec.h"

#include "IMPL/LCEventImpl.h"
#include "IMPL/LCRunHeaderImpl.h"
#include "IMPL/LCCollectionVec.h"
#include "IMPL/SimCalorimeterHitImpl.h"
#include "IMPL/SimTrackerHitImpl.h"
#include "IMPL/MCParticleImpl.h"
#include "IMPL/LCFlagImpl.h"
#include "IMPL/LCTOOLS.h"
#include "IMPL/TPCHitImpl.h"
#include "UTIL/LCRelationNavigator.h"

#include <cstdlib>
#include <iostream>
#include <sstream>

using namespace std ;
using namespace lcio ;

static const int NRUN = 10 ;
static const int NEVENT = 10 ; // events
static const int NMCPART = 10 ;  // mc particles per event
static const int NHITS = 50 ;  // calorimeter hits per event

static string FILEN = "simjob.slcio" ;

/** Simple test program to demonstrate writing of data with lcio.
 */

int main(int argc, char** argv ){

  try{

    // loop over runs
    for(int rn=0;rn<NRUN;rn++){

      // create sio writer
      LCWriter* lcWrt = LCFactory::getInstance()->createLCWriter() ;

      if( argc > 1 ) { FILEN = argv[1] ; }

      if( rn==0 )
	lcWrt->open( FILEN , LCIO::WRITE_NEW )  ;
      else
	lcWrt->open( FILEN , LCIO::WRITE_APPEND )  ;

      // NB: in order to test writing multiple files we create a new LCWriter
      // for every run even though we are in fact writing to one file only;
      // so for a simple job writing one file the
      // 'createLCWriter/open' and 'close/delete' will be outside the run loop...

      LCRunHeaderImpl* runHdr = new LCRunHeaderImpl ;
      runHdr->setRunNumber( rn ) ;

      string detName("D09TileHcal")  ;
      runHdr->setDetectorName( detName ) ;

      stringstream description ;
      description << " run: " << rn <<" just for testing lcio  - no physics !" ;
      runHdr->setDescription( description.str()  ) ;

      string ecalName("ECAL007") ;
      runHdr->addActiveSubdetector( ecalName ) ;

      string tpcName("TPC4711") ;
      runHdr->addActiveSubdetector( tpcName ) ;

      // add some parameters to the run header
//       StringVec sv1 ;
//       sv1.push_back("simjob.cc") ;
//       runHdr->parameters().setValues( "SimulationProgram" , sv1 ) ;
      runHdr->parameters().setValue( "SimulationProgram" , "simjob.cc" ) ;
      IntVec iv(3) ;
      iv[0] = 1 ;
      iv[1] = 2 ;
      iv[2] = 3 ;
      runHdr->parameters().setValues( "SomeIndices" , iv ) ;

      lcWrt->writeRunHeader( runHdr ) ;

      // EventLoop - create some events and write them to the file
      for(int i=0;i<NEVENT;i++){

	// we need to use the implementation classes here
	LCEventImpl*  evt = new LCEventImpl() ;

	evt->setRunNumber(  rn   ) ;
	evt->setEventNumber( i ) ;
	evt->setTimeStamp( 9223372036854775807LL ) ;
	evt->setDetectorName( detName ) ;

	// create and add some mc particles
	LCCollectionVec* mcVec = new LCCollectionVec( LCIO::MCPARTICLE )  ;

	// debug only - don't write MCParticles to output file:
	// mcVec->setTransient() ;

	// debug only - add the same particle to more than one collection
	//LCCollectionVec* mcVec2 = new LCCollectionVec( LCIO::MCPARTICLE )  ;

	MCParticleImpl* mom = new MCParticleImpl ;
	mom->setPDG( 1  ) ;
	float p0[3] = { 0. , 0. , 1000. } ;
	mom->setMomentum( p0 ) ;
	mom->setMass( 3.01 ) ;

	for(int j=0;j<NMCPART;j++){

	  MCParticleImpl* mcp = new MCParticleImpl ;

	  mcp->setPDG( 1000 * (j+1)  ) ;
	  float p[3] = { j*1. , 4./1024. , 8./1024. } ;
	  mcp->setMomentum( p ) ;
	  mcp->setMass( .135 ) ;

	  // create and add some daughters
	  for(int k=0;k<3;k++){
	    MCParticleImpl* d1 = new MCParticleImpl ;

	    d1->setPDG( 1000 * (j+1) + 100 * (k+1)  ) ;
	    float pd1[3] = { k*1. , 4.1 , 8.1 } ;
	    d1->setMomentum( pd1 ) ;
	    d1->setMass( .135 ) ;

	    for(int l=0;l<2;l++){
	      MCParticleImpl* d2 = new MCParticleImpl ;

	      d2->setPDG( 1000 * (j+1) + 100 * (k+1) + 10 *  (l+1)  ) ;
	      float pd2[3] = { l*1. , 0.41 , 4.1 } ;
	      d2->setMomentum( pd2 ) ;
	      d2->setMass( .135 ) ;

	      double ep[3] = { 1.111111 , 2.2222222, 3.3333333 } ;
	      d2->setEndpoint( ep ) ;
	      //	      d2->setSimulatorStatus( 1234 ) ;
	      d2->setCreatedInSimulation(true) ;
	      d2->setBackscatter(true)         ;
	      d2->setDecayedInTracker(true)    ;
	      d2->setDecayedInCalorimeter(false);
	      d2->setHasLeftDetector(false)     ;
	      d2->setStopped(true)             ;

	      d2->addParent( d1 );
	      mcVec->push_back( d2 ) ;

	      // debug only - add the same particle to more than one collection
	      //mcVec2->push_back( d2 ) ;
	    }
	    d1->addParent( mcp );
	    mcVec->push_back( d1 ) ;
	  }

	  mcp->addParent( mom );
	  mcVec->push_back( mcp ) ;
	}
	mcVec->push_back( mom ) ;

	// now add some calorimeter hits
	LCCollectionVec* calVec = new LCCollectionVec( LCIO::SIMCALORIMETERHIT )  ;

	// set flag for long format (including position )
	// and PDG and cellid1
	LCFlagImpl chFlag(0) ;
	chFlag.setBit( LCIO::CHBIT_LONG ) ;
	chFlag.setBit( LCIO::CHBIT_PDG ) ;
	chFlag.setBit( LCIO::CHBIT_ID1 ) ;
	calVec->setFlag( chFlag.getFlag()  ) ;

	for(int j=0;j<NHITS;j++){

	  SimCalorimeterHitImpl* hit = new SimCalorimeterHitImpl ;

	  hit->setEnergy( 3.1415 * rand()/RAND_MAX   )  ;

	  float pos[3] = { 1.1* rand()/RAND_MAX , 2.2* rand()/RAND_MAX , 3.3* rand()/RAND_MAX } ;

	  hit->setCellID0( j+65335 ) ;
	  hit->setCellID1( 65535 ) ;

	  hit->setPosition( pos ) ;

	  calVec->push_back( hit ) ;

	  // assign the hits randomly to MC particles
	  float rn =  .99999*rand()/RAND_MAX ;
	  int mcIndx = static_cast<int>( NMCPART * rn ) ;

	  // in order to access a MCParticle,  we need a dynamic cast as the
	  // LCCollection returns an LCIOObject - this is like vectors in Java
	  hit->addMCParticleContribution(  dynamic_cast<MCParticle*>(mcVec->getElementAt( mcIndx )) ,
					   0.314159, 0.1155 ) ; // no pdg

	}

	// -------- data can be modified as long as is not not made persistent --------

	for(int j=0;j<NHITS;j++){
	  SimCalorimeterHitImpl* existingHit
	    = dynamic_cast<SimCalorimeterHitImpl*>( calVec->getElementAt(j) ) ; // << Ok now

 	  //	    = dynamic_cast<SimCalorimeterHitImpl*>( (*calVec)[j] ) ;  // << not needed

	  existingHit->addMCParticleContribution( dynamic_cast<MCParticle*>
						  (mcVec->getElementAt(0)),
						  0.1, 0. ) ;
	}

	// and finally some tracker hits
	// with some user extensions (4 floats and 2 ints) per track:
	// we just need to create parallel collections of float and int vectors
	LCCollectionVec* trkVec = new LCCollectionVec( LCIO::SIMTRACKERHIT )  ;
	LCCollectionVec* extFVec = new LCCollectionVec( LCIO::LCFLOATVEC )  ;
	LCCollectionVec* extIVec = new LCCollectionVec( LCIO::LCINTVEC )  ;

	for(int j=0;j<NHITS;j++){

	  SimTrackerHitImpl* hit = new SimTrackerHitImpl ;
	  LCFloatVec* extF = new LCFloatVec ;
	  LCIntVec*   extI = new LCIntVec ;

	  hit->setdEdx( 30e-9 ) ;

	  double pos[3] = { 1.1* rand()/RAND_MAX , 2.2* rand()/RAND_MAX , 3.3* rand()/RAND_MAX } ;

	  hit->setPosition( pos ) ;

	  // assign the hits randomly to MC particles
	  float rn =  .99999*rand()/RAND_MAX ;
	  int mcIndx = static_cast<int>( NMCPART * rn ) ;

	  hit->setMCParticle( dynamic_cast<MCParticle*>(mcVec->getElementAt( mcIndx ) ) ) ;

	  // fill the extension vectors (4 floats, 2 ints)
	  extF->push_back( 3.14159 ) ;
	  for(int k=0;k<3;k++) extF->push_back(  pos[k] * 0.1  ) ;

	  extI->push_back( 123456789 ) ;
	  extI->push_back( mcIndx ) ;

	  // add the hit and the extensions to their corresponding collections
	  trkVec->push_back( hit ) ;
	  extFVec->push_back( extF ) ;
	  extIVec->push_back( extI ) ;
	}

	// add all collections to the event
	evt->addCollection( mcVec , "MCParticle" ) ;

	//deubg only
	//evt->addCollection( mcVec2, "MCParticle2" ) ;

	evt->addCollection( calVec , ecalName ) ;
	evt->addCollection( trkVec , tpcName ) ;
	evt->addCollection( extFVec , tpcName+"UserFloatExtension" ) ;
	evt->addCollection( extIVec , tpcName+"UserIntExtension" ) ;

	// test: add a collection for one event only:
// 	if( rn == NRUN-1 && i == 0 ) { // first event o last run
	if( rn == 1 && i == 0 ) { // first event o last run
	  LCCollectionVec* addExtVec = new LCCollectionVec( LCIO::LCFLOATVEC )  ;
	  LCFloatVec* addExt = new LCFloatVec ;
	  addExt->push_back( 1. );
	  addExt->push_back( 2. );
	  addExt->push_back( 3. );
	  addExt->push_back( 4. );
	  addExtVec->push_back( addExt ) ;
	  evt->addCollection( addExtVec , "AdditionalExtension" ) ;
	}

	// even though this is a simjob we can store 'real data' objects :)
	// --- for example we can store TPC hits ------------

	LCCollectionVec* TPCVec = new LCCollectionVec( LCIO::TPCHIT )  ;

	//---- test new relation navigator object
// 	LCRelationNavigator* relNav =
// 	  new LCRelationNavigator( LCIO::TPCHIT, LCIO::SIMTRACKERHIT ) ;

	LCRelationNavigator relNav( LCIO::TPCHIT, LCIO::SIMTRACKERHIT ) ;

	bool storeRawData = true ;

	LCFlagImpl tpcFlag(0) ;
	if(  storeRawData )  // if we want to store the raw data we need to set the flag
	  tpcFlag.setBit( LCIO::TPCBIT_RAW ) ;
	TPCVec->setFlag( tpcFlag.getFlag()  ) ;

	for(int j=0;j<NHITS;j++){

	  TPCHitImpl* tpcHit = new TPCHitImpl ;

	  //---- test new relation navigator object
	  relNav.addRelation( tpcHit , trkVec->getElementAt(j) , 0.95  ) ;

	  tpcHit->setCellID( j ) ;
	  tpcHit->setTime( 0.1234567 ) ;
	  tpcHit->setCharge( 3.14159 ) ;
	  tpcHit->setQuality(  0xbad ) ;

	  if(  storeRawData ) {
	    int rawData[10] ;
	    // fill some random numbers
	    int size =   int( (double(rand()) / RAND_MAX ) * 10 )  ;
	    for(int k=0;k<size;k++){
	      rawData[k] = int( (double(rand()) / RAND_MAX ) * INT_MAX ) ;
	    }

	    tpcHit->setRawData( rawData , size ) ;
	  }

	  TPCVec->push_back( tpcHit ) ;
	}
	evt->addCollection( TPCVec , "TPCRawFADC" ) ;
	evt->addCollection( relNav.createLCCollection() , "TPCRawFADCMCTruth" ) ;

// 	delete relNav ;
	//--------------  all for TPC --------------------

	// write the event to the file
	lcWrt->writeEvent( evt ) ;

	// dump the event to the screen
	LCTOOLS::dumpEvent( evt ) ;

	// ------------ IMPORTANT ------------- !
	// we created the event so we need to delete it ...
	delete evt ;
	// -------------------------------------

	//  dont use this (compatibility with Fortran simjob.F)
	//  if( ! (i%100) ) cout << ". " << flush  ;

      } // evt loop

      delete runHdr ;

      lcWrt->close() ;
      delete lcWrt ;

    } // run loop

    cout << endl
	 << " created  " << NRUN << " runs with  " << NRUN*NEVENT << " events"
	 << endl << endl ;

  } catch( Exception& ex){

    cout << " an excpetion occured: " << endl ;
    cout << "  " << ex.what() << endl ;
    return 1 ;
  }

  return 0 ;
}

<commit_msg>use current time stamp and not infinity<commit_after>
#include "lcio.h"

#include "IO/LCWriter.h"
#include "EVENT/LCIO.h"
#include "DATA/LCFloatVec.h"
#include "DATA/LCIntVec.h"

#include "IMPL/LCEventImpl.h"
#include "IMPL/LCRunHeaderImpl.h"
#include "IMPL/LCCollectionVec.h"
#include "IMPL/SimCalorimeterHitImpl.h"
#include "IMPL/SimTrackerHitImpl.h"
#include "IMPL/MCParticleImpl.h"
#include "IMPL/LCFlagImpl.h"
#include "IMPL/LCTOOLS.h"
#include "IMPL/TPCHitImpl.h"
#include "UTIL/LCRelationNavigator.h"
#include "UTIL/LCTime.h"

#include <cstdlib>
#include <iostream>
#include <sstream>

using namespace std ;
using namespace lcio ;

static const int NRUN = 10 ;
static const int NEVENT = 10 ; // events
static const int NMCPART = 10 ;  // mc particles per event
static const int NHITS = 50 ;  // calorimeter hits per event

static string FILEN = "simjob.slcio" ;

/** Simple test program to demonstrate writing of data with lcio.
 */

int main(int argc, char** argv ){

  try{

    // loop over runs
    for(int rn=0;rn<NRUN;rn++){

      // create sio writer
      LCWriter* lcWrt = LCFactory::getInstance()->createLCWriter() ;

      if( argc > 1 ) { FILEN = argv[1] ; }

      if( rn==0 )
	lcWrt->open( FILEN , LCIO::WRITE_NEW )  ;
      else
	lcWrt->open( FILEN , LCIO::WRITE_APPEND )  ;

      // NB: in order to test writing multiple files we create a new LCWriter
      // for every run even though we are in fact writing to one file only;
      // so for a simple job writing one file the
      // 'createLCWriter/open' and 'close/delete' will be outside the run loop...

      LCRunHeaderImpl* runHdr = new LCRunHeaderImpl ;
      runHdr->setRunNumber( rn ) ;

      string detName("D09TileHcal")  ;
      runHdr->setDetectorName( detName ) ;

      stringstream description ;
      description << " run: " << rn <<" just for testing lcio  - no physics !" ;
      runHdr->setDescription( description.str()  ) ;

      string ecalName("ECAL007") ;
      runHdr->addActiveSubdetector( ecalName ) ;

      string tpcName("TPC4711") ;
      runHdr->addActiveSubdetector( tpcName ) ;

      // add some parameters to the run header
//       StringVec sv1 ;
//       sv1.push_back("simjob.cc") ;
//       runHdr->parameters().setValues( "SimulationProgram" , sv1 ) ;
      runHdr->parameters().setValue( "SimulationProgram" , "simjob.cc" ) ;
      IntVec iv(3) ;
      iv[0] = 1 ;
      iv[1] = 2 ;
      iv[2] = 3 ;
      runHdr->parameters().setValues( "SomeIndices" , iv ) ;

      lcWrt->writeRunHeader( runHdr ) ;

      // EventLoop - create some events and write them to the file
      for(int i=0;i<NEVENT;i++){

	// we need to use the implementation classes here
	LCEventImpl*  evt = new LCEventImpl() ;

	evt->setRunNumber(  rn   ) ;
	evt->setEventNumber( i ) ;
	LCTime now ;
	evt->setTimeStamp( now.timeStamp()  ) ;
	evt->setDetectorName( detName ) ;

	// create and add some mc particles
	LCCollectionVec* mcVec = new LCCollectionVec( LCIO::MCPARTICLE )  ;

	// debug only - don't write MCParticles to output file:
	// mcVec->setTransient() ;

	// debug only - add the same particle to more than one collection
	//LCCollectionVec* mcVec2 = new LCCollectionVec( LCIO::MCPARTICLE )  ;

	MCParticleImpl* mom = new MCParticleImpl ;
	mom->setPDG( 1  ) ;
	float p0[3] = { 0. , 0. , 1000. } ;
	mom->setMomentum( p0 ) ;
	mom->setMass( 3.01 ) ;

	for(int j=0;j<NMCPART;j++){

	  MCParticleImpl* mcp = new MCParticleImpl ;

	  mcp->setPDG( 1000 * (j+1)  ) ;
	  float p[3] = { j*1. , 4./1024. , 8./1024. } ;
	  mcp->setMomentum( p ) ;
	  mcp->setMass( .135 ) ;

	  // create and add some daughters
	  for(int k=0;k<3;k++){
	    MCParticleImpl* d1 = new MCParticleImpl ;

	    d1->setPDG( 1000 * (j+1) + 100 * (k+1)  ) ;
	    float pd1[3] = { k*1. , 4.1 , 8.1 } ;
	    d1->setMomentum( pd1 ) ;
	    d1->setMass( .135 ) ;

	    for(int l=0;l<2;l++){
	      MCParticleImpl* d2 = new MCParticleImpl ;

	      d2->setPDG( 1000 * (j+1) + 100 * (k+1) + 10 *  (l+1)  ) ;
	      float pd2[3] = { l*1. , 0.41 , 4.1 } ;
	      d2->setMomentum( pd2 ) ;
	      d2->setMass( .135 ) ;

	      double ep[3] = { 1.111111 , 2.2222222, 3.3333333 } ;
	      d2->setEndpoint( ep ) ;
	      //	      d2->setSimulatorStatus( 1234 ) ;
	      d2->setCreatedInSimulation(true) ;
	      d2->setBackscatter(true)         ;
	      d2->setDecayedInTracker(true)    ;
	      d2->setDecayedInCalorimeter(false);
	      d2->setHasLeftDetector(false)     ;
	      d2->setStopped(true)             ;

	      d2->addParent( d1 );
	      mcVec->push_back( d2 ) ;

	      // debug only - add the same particle to more than one collection
	      //mcVec2->push_back( d2 ) ;
	    }
	    d1->addParent( mcp );
	    mcVec->push_back( d1 ) ;
	  }

	  mcp->addParent( mom );
	  mcVec->push_back( mcp ) ;
	}
	mcVec->push_back( mom ) ;

	// now add some calorimeter hits
	LCCollectionVec* calVec = new LCCollectionVec( LCIO::SIMCALORIMETERHIT )  ;

	// set flag for long format (including position )
	// and PDG and cellid1
	LCFlagImpl chFlag(0) ;
	chFlag.setBit( LCIO::CHBIT_LONG ) ;
	chFlag.setBit( LCIO::CHBIT_PDG ) ;
	chFlag.setBit( LCIO::CHBIT_ID1 ) ;
	calVec->setFlag( chFlag.getFlag()  ) ;

	for(int j=0;j<NHITS;j++){

	  SimCalorimeterHitImpl* hit = new SimCalorimeterHitImpl ;

	  hit->setEnergy( 3.1415 * rand()/RAND_MAX   )  ;

	  float pos[3] = { 1.1* rand()/RAND_MAX , 2.2* rand()/RAND_MAX , 3.3* rand()/RAND_MAX } ;

	  hit->setCellID0( j+65335 ) ;
	  hit->setCellID1( 65535 ) ;

	  hit->setPosition( pos ) ;

	  calVec->push_back( hit ) ;

	  // assign the hits randomly to MC particles
	  float rn =  .99999*rand()/RAND_MAX ;
	  int mcIndx = static_cast<int>( NMCPART * rn ) ;

	  // in order to access a MCParticle,  we need a dynamic cast as the
	  // LCCollection returns an LCIOObject - this is like vectors in Java
	  hit->addMCParticleContribution(  dynamic_cast<MCParticle*>(mcVec->getElementAt( mcIndx )) ,
					   0.314159, 0.1155 ) ; // no pdg

	}

	// -------- data can be modified as long as is not not made persistent --------

	for(int j=0;j<NHITS;j++){
	  SimCalorimeterHitImpl* existingHit
	    = dynamic_cast<SimCalorimeterHitImpl*>( calVec->getElementAt(j) ) ; // << Ok now

 	  //	    = dynamic_cast<SimCalorimeterHitImpl*>( (*calVec)[j] ) ;  // << not needed

	  existingHit->addMCParticleContribution( dynamic_cast<MCParticle*>
						  (mcVec->getElementAt(0)),
						  0.1, 0. ) ;
	}

	// and finally some tracker hits
	// with some user extensions (4 floats and 2 ints) per track:
	// we just need to create parallel collections of float and int vectors
	LCCollectionVec* trkVec = new LCCollectionVec( LCIO::SIMTRACKERHIT )  ;
	LCCollectionVec* extFVec = new LCCollectionVec( LCIO::LCFLOATVEC )  ;
	LCCollectionVec* extIVec = new LCCollectionVec( LCIO::LCINTVEC )  ;

	for(int j=0;j<NHITS;j++){

	  SimTrackerHitImpl* hit = new SimTrackerHitImpl ;
	  LCFloatVec* extF = new LCFloatVec ;
	  LCIntVec*   extI = new LCIntVec ;

	  hit->setdEdx( 30e-9 ) ;

	  double pos[3] = { 1.1* rand()/RAND_MAX , 2.2* rand()/RAND_MAX , 3.3* rand()/RAND_MAX } ;

	  hit->setPosition( pos ) ;

	  // assign the hits randomly to MC particles
	  float rn =  .99999*rand()/RAND_MAX ;
	  int mcIndx = static_cast<int>( NMCPART * rn ) ;

	  hit->setMCParticle( dynamic_cast<MCParticle*>(mcVec->getElementAt( mcIndx ) ) ) ;

	  // fill the extension vectors (4 floats, 2 ints)
	  extF->push_back( 3.14159 ) ;
	  for(int k=0;k<3;k++) extF->push_back(  pos[k] * 0.1  ) ;

	  extI->push_back( 123456789 ) ;
	  extI->push_back( mcIndx ) ;

	  // add the hit and the extensions to their corresponding collections
	  trkVec->push_back( hit ) ;
	  extFVec->push_back( extF ) ;
	  extIVec->push_back( extI ) ;
	}

	// add all collections to the event
	evt->addCollection( mcVec , "MCParticle" ) ;

	//deubg only
	//evt->addCollection( mcVec2, "MCParticle2" ) ;

	evt->addCollection( calVec , ecalName ) ;
	evt->addCollection( trkVec , tpcName ) ;
	evt->addCollection( extFVec , tpcName+"UserFloatExtension" ) ;
	evt->addCollection( extIVec , tpcName+"UserIntExtension" ) ;

	// test: add a collection for one event only:
// 	if( rn == NRUN-1 && i == 0 ) { // first event o last run
	if( rn == 1 && i == 0 ) { // first event o last run
	  LCCollectionVec* addExtVec = new LCCollectionVec( LCIO::LCFLOATVEC )  ;
	  LCFloatVec* addExt = new LCFloatVec ;
	  addExt->push_back( 1. );
	  addExt->push_back( 2. );
	  addExt->push_back( 3. );
	  addExt->push_back( 4. );
	  addExtVec->push_back( addExt ) ;
	  evt->addCollection( addExtVec , "AdditionalExtension" ) ;
	}

	// even though this is a simjob we can store 'real data' objects :)
	// --- for example we can store TPC hits ------------

	LCCollectionVec* TPCVec = new LCCollectionVec( LCIO::TPCHIT )  ;

	//---- test new relation navigator object
// 	LCRelationNavigator* relNav =
// 	  new LCRelationNavigator( LCIO::TPCHIT, LCIO::SIMTRACKERHIT ) ;

	LCRelationNavigator relNav( LCIO::TPCHIT, LCIO::SIMTRACKERHIT ) ;

	bool storeRawData = true ;

	LCFlagImpl tpcFlag(0) ;
	if(  storeRawData )  // if we want to store the raw data we need to set the flag
	  tpcFlag.setBit( LCIO::TPCBIT_RAW ) ;
	TPCVec->setFlag( tpcFlag.getFlag()  ) ;

	for(int j=0;j<NHITS;j++){

	  TPCHitImpl* tpcHit = new TPCHitImpl ;

	  //---- test new relation navigator object
	  relNav.addRelation( tpcHit , trkVec->getElementAt(j) , 0.95  ) ;

	  tpcHit->setCellID( j ) ;
	  tpcHit->setTime( 0.1234567 ) ;
	  tpcHit->setCharge( 3.14159 ) ;
	  tpcHit->setQuality(  0xbad ) ;

	  if(  storeRawData ) {
	    int rawData[10] ;
	    // fill some random numbers
	    int size =   int( (double(rand()) / RAND_MAX ) * 10 )  ;
	    for(int k=0;k<size;k++){
	      rawData[k] = int( (double(rand()) / RAND_MAX ) * INT_MAX ) ;
	    }

	    tpcHit->setRawData( rawData , size ) ;
	  }

	  TPCVec->push_back( tpcHit ) ;
	}
	evt->addCollection( TPCVec , "TPCRawFADC" ) ;
	evt->addCollection( relNav.createLCCollection() , "TPCRawFADCMCTruth" ) ;

// 	delete relNav ;
	//--------------  all for TPC --------------------

	// write the event to the file
	lcWrt->writeEvent( evt ) ;

	// dump the event to the screen
	LCTOOLS::dumpEvent( evt ) ;

	// ------------ IMPORTANT ------------- !
	// we created the event so we need to delete it ...
	delete evt ;
	// -------------------------------------

	//  dont use this (compatibility with Fortran simjob.F)
	//  if( ! (i%100) ) cout << ". " << flush  ;

      } // evt loop

      delete runHdr ;

      lcWrt->close() ;
      delete lcWrt ;

    } // run loop

    cout << endl
	 << " created  " << NRUN << " runs with  " << NRUN*NEVENT << " events"
	 << endl << endl ;

  } catch( Exception& ex){

    cout << " an excpetion occured: " << endl ;
    cout << "  " << ex.what() << endl ;
    return 1 ;
  }

  return 0 ;
}

<|endoftext|>


<commit_before>/*******************************************************************************
* ALMA - Atacama Large Millimiter Array
* (c) National Research Council of Canada, 2006
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* "@(#) $Id: acsstartupIrFeed.cpp,v 1.1 2006/03/24 23:24:53 dfugate Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* dfugate  2006-03-24  created
*/

/************************************************************************
*   NAME
*
*
*   SYNOPSIS
*
*
*   DESCRIPTION
*
*   FILES
*
*   ENVIRONMENT
*
*   COMMANDS
*
*   RETURN VALUES
*
*   CAUTIONS
*
*   EXAMPLES
*
*   SEE ALSO
*
*   BUGS
*
*------------------------------------------------------------------------
*/

// Uncomment this if you are using the VLT environment
// #include "vltPort.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static char *rcsId="@(#) $Id: acsstartupIrFeed.cpp,v 1.1 2006/03/24 23:24:53 dfugate Exp $";
static void *use_rcsId = ((void)&use_rcsId,(void *) &rcsId);

#include <iostream>
#include <list>
#include <acsutilPorts.h>
#include <dirent.h>
#include <fstream>

using std::string;
using std::list;
using std::cout;

/**
 * Helper function adds all IDL files found within dirName
 * to files list.
 */
void addIdlFiles(std::string dirName,
		 list<string> & files)
{
    //open the directory
    DIR* dir = opendir(dirName.c_str());

    //sanity check
    if (dir==0)
	{
	return;
	}

    //traverse the directory looking for files that end in ".idl"
    struct dirent * file = readdir(dir);
    while(file!=0)
	{
	string t_file = file->d_name;

	//good, found a match
	if(t_file.rfind(".idl") != string::npos)
	    {
	    files.push_back(t_file);
	    }

	file = readdir(dir);
	}

    closedir(dir);
}

int main(int argc, char *argv[])
{
    list<string> idlFiles;

    std::string managerHost = ACSPorts::getIP();
    std::string ifrPort     = ACSPorts::getIRPort();
    std::string ifrCorbaloc = "corbaloc::" + managerHost + ":" + ifrPort + "/DefaultRepository";
    std::string aceRoot     = getenv("ACE_ROOT");
    std::string idlPath     = getenv("IDL_PATH");
    std::string outFile     = argv[1];
    std::string processId   = argv[2];

    std::ofstream file(outFile.c_str());

    ///Split idlPath after the first $ACE_ROOT

    //find first reference to ACE_ROOT
    std::string::size_type aceRootIndex = idlPath.find(aceRoot);

    //chop off everything after and including ACE_ROOT
    idlPath = idlPath.substr(0, aceRootIndex);

    //get rid of all the nasty "-I"s
    while(true)
	{
	std::string::size_type includeIndex = idlPath.find("-I");
	//sanity check
	if (includeIndex == string::npos)
	    {
	    break;
	    }

	idlPath.erase(includeIndex, 2);
	}

    //cycle through each area of IDL path
    while(idlPath.length()!=0)
	{
	//find the next whitespace to...
	std::string::size_type wsIndex = idlPath.find(" ");
	//sanity check
	if (wsIndex == string::npos)
	    {
	    break;
	    }

	//...get the next IDL directory
	string idlDir = idlPath.substr(0, wsIndex);

	//examine the IDL directory adding all IDLs found
	addIdlFiles(idlDir, idlFiles);

	//shrink the idlPath
	idlPath.erase(0, wsIndex + 1);
	}

    //remove duplicates
    idlFiles.unique();

    file << "#ifndef acsIrfeedDyn_" << processId <<"_idl" << std::endl;
    file << "#define acsIrfeedDyn_" << processId <<"_idl" << std::endl;
    file << "/*******************************************************************************" << std::endl;
    file << "* ALMA Project" << std::endl;
    file << "*" << std::endl;
    file << "* This file is dynamically created by acsIrfeed to load" << std::endl;
    file << "* in the Orbacus Interface Repository" << std::endl;
    file << "* the complete set of IDL interfaces" << std::endl;
    file << "*" << std::endl;
    file << "*/" << std::endl;
    file << "" << std::endl;
    file << "#define local" << std::endl;
    file << "#include <CosPropertyService.idl>" << std::endl;
    file << "#undef local" << std::endl;
    file << "" << std::endl;
    file << "#include <acserr.idl>" << std::endl;
    file << "" << std::endl;

    while (idlFiles.empty() == false)
	{
	file << "#include <" << idlFiles.front() << ">" << std::endl;
	idlFiles.pop_front();
	}

    file << "#endif" << std::endl;

    return 0;

}

<commit_msg>Refactored a tiny bit.<commit_after>/*******************************************************************************
* ALMA - Atacama Large Millimiter Array
* (c) National Research Council of Canada, 2006
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* "@(#) $Id: acsstartupIrFeed.cpp,v 1.2 2006/05/05 21:04:50 dfugate Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* dfugate  2006-03-24  created
*/

/************************************************************************
*   NAME
*
*
*   SYNOPSIS
*
*
*   DESCRIPTION
*
*   FILES
*
*   ENVIRONMENT
*
*   COMMANDS
*
*   RETURN VALUES
*
*   CAUTIONS
*
*   EXAMPLES
*
*   SEE ALSO
*
*   BUGS
*
*------------------------------------------------------------------------
*/

// Uncomment this if you are using the VLT environment
// #include "vltPort.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static char *rcsId="@(#) $Id: acsstartupIrFeed.cpp,v 1.2 2006/05/05 21:04:50 dfugate Exp $";
static void *use_rcsId = ((void)&use_rcsId,(void *) &rcsId);

#include <iostream>
#include <list>
#include <acsutilPorts.h>
#include <dirent.h>
#include <fstream>

using std::string;
using std::list;
using std::cout;

/**
 * Helper function adds all IDL files found within dirName
 * to files list.
 */
void addIdlFiles(std::string dirName,
		 list<string> & files)
{
    //open the directory
    DIR* dir = opendir(dirName.c_str());

    //sanity check
    if (dir==0)
	{
	return;
	}

    //traverse the directory looking for files that end in ".idl"
    struct dirent * file = readdir(dir);
    while(file!=0)
	{
	string t_file = file->d_name;

	//good, found a match
	if(t_file.rfind(".idl") != string::npos)
	    {
	    files.push_back(t_file);
	    }

	file = readdir(dir);
	}

    closedir(dir);
}

int main(int argc, char *argv[])
{
    list<string> idlFiles;

    std::string aceRoot     = getenv("ACE_ROOT");
    std::string idlPath     = getenv("IDL_PATH");
    std::string outFile     = argv[1];
    std::string processId   = argv[2];

    std::ofstream file(outFile.c_str());

    ///Split idlPath after the first $ACE_ROOT

    //find first reference to ACE_ROOT
    std::string::size_type aceRootIndex = idlPath.find(aceRoot);

    //chop off everything after and including ACE_ROOT
    idlPath = idlPath.substr(0, aceRootIndex);

    //get rid of all the nasty "-I"s
    while(true)
	{
	std::string::size_type includeIndex = idlPath.find("-I");
	//sanity check
	if (includeIndex == string::npos)
	    {
	    break;
	    }

	idlPath.erase(includeIndex, 2);
	}

    //cycle through each area of IDL path
    while(idlPath.length()!=0)
	{
	//find the next whitespace to...
	std::string::size_type wsIndex = idlPath.find(" ");
	//sanity check
	if (wsIndex == string::npos)
	    {
	    break;
	    }

	//...get the next IDL directory
	string idlDir = idlPath.substr(0, wsIndex);

	//examine the IDL directory adding all IDLs found
	addIdlFiles(idlDir, idlFiles);

	//shrink the idlPath
	idlPath.erase(0, wsIndex + 1);
	}

    //remove duplicates
    idlFiles.unique();

    file << "#ifndef acsIrfeedDyn_" << processId <<"_idl" << std::endl;
    file << "#define acsIrfeedDyn_" << processId <<"_idl" << std::endl;
    file << "/*******************************************************************************" << std::endl;
    file << "* ALMA Project" << std::endl;
    file << "*" << std::endl;
    file << "* This file is dynamically created by acsIrfeed to load" << std::endl;
    file << "* in the Orbacus Interface Repository" << std::endl;
    file << "* the complete set of IDL interfaces" << std::endl;
    file << "*" << std::endl;
    file << "*/" << std::endl;
    file << "" << std::endl;
    file << "#define local" << std::endl;
    file << "#include <CosPropertyService.idl>" << std::endl;
    file << "#undef local" << std::endl;
    file << "" << std::endl;
    file << "#include <acserr.idl>" << std::endl;
    file << "" << std::endl;

    while (idlFiles.empty() == false)
	{
	file << "#include <" << idlFiles.front() << ">" << std::endl;
	idlFiles.pop_front();
	}

    file << "#endif" << std::endl;

    return 0;

}

<|endoftext|>


<commit_before>/*
 * Copyright 2008-2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "esnpapi.h"
#include "proxyImpl.h"

#include <org/w3c/dom.h>

using namespace org::w3c::dom;

void initializeHtmlMetaDataO_U()
{
    ProxyControl::registerMetaData(html::HTMLObjectElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLObjectElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLOListElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLOListElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLOptGroupElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLOptGroupElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLOptionElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLOptionElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLOptionsCollection::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLOptionsCollection_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLOutputElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLOutputElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLParagraphElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLParagraphElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLParamElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLParamElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLPreElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLPreElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLProgressElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLProgressElement_Bridge<Any, invoke> >::createInstance);
    // TODO: HTMLPropertiesCollection overrides HTMLCollection in a way the current Bridge classes can not handle.
    ProxyControl::registerMetaData(html::HTMLPropertiesCollection::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLPropertiesCollection_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLQuoteElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLQuoteElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLScriptElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLScriptElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLSelectElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLSelectElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLSourceElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLSourceElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLSpanElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLSpanElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLStyleElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLStyleElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableCaptionElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableCaptionElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableCellElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableCellElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableColElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableColElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableDataCellElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableDataCellElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableHeaderCellElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableHeaderCellElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableRowElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableRowElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableSectionElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableSectionElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTextAreaElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTextAreaElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTimeElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTimeElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTitleElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTitleElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLUListElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLUListElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLUnknownElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLUnknownElement_Bridge<Any, invoke> >::createInstance);
}
<commit_msg>(initializeHtmlMetaDataO_U) : Clean up.<commit_after>/*
 * Copyright 2008-2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "esnpapi.h"
#include "proxyImpl.h"

#include <org/w3c/dom.h>

using namespace org::w3c::dom;

void initializeHtmlMetaDataO_U()
{
    ProxyControl::registerMetaData(html::HTMLObjectElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLObjectElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLOListElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLOListElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLOptGroupElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLOptGroupElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLOptionElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLOptionElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLOptionsCollection::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLOptionsCollection_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLOutputElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLOutputElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLParagraphElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLParagraphElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLParamElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLParamElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLPreElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLPreElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLProgressElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLProgressElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLPropertiesCollection::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLPropertiesCollection_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLQuoteElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLQuoteElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLScriptElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLScriptElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLSelectElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLSelectElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLSourceElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLSourceElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLSpanElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLSpanElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLStyleElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLStyleElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableCaptionElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableCaptionElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableCellElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableCellElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableColElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableColElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableDataCellElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableDataCellElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableHeaderCellElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableHeaderCellElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableRowElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableRowElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTableSectionElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTableSectionElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTextAreaElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTextAreaElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTimeElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTimeElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLTitleElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLTitleElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLUListElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLUListElement_Bridge<Any, invoke> >::createInstance);
    ProxyControl::registerMetaData(html::HTMLUnknownElement::getMetaData(), Proxy_Impl<ProxyObject, html::HTMLUnknownElement_Bridge<Any, invoke> >::createInstance);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014–2016 The SmartSqlite contributors (see NOTICE.txt)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <cstdio>
#include <memory>
#include <string>

#include <gmock/gmock.h>

#include "smartsqlite/connection.h"
#include "smartsqlite/exceptions.h"

using namespace testing;

namespace {

// 96B = 768b
std::string SOME_KEY =
        "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0"
        "NTY3ODkwMTIxMjM0NTY3ODkwMTIzNDU2"
        "Nzg5MDEyMzQ1Njc4OTAxMjEyMzQ1Njc4"
        "OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEy";
std::string ANOTHER_KEY =
        "MDk4NzY1NDMyMTA5ODc2NTQzMjEwOTg3"
        "NjU0MzIxMDkwOTg3NjU0MzIxMDk4NzY1"
        "NDMyMTA5ODc2NTQzMjEwOTA5ODc2NTQz"
        "MjEwOTg3NjU0MzIxMDk4NzY1NDMyMTA5";

}

class BotanSqlite3: public Test
{
protected:
    BotanSqlite3()
        : dbFilename_(tempDbName())
        , attachedFilename_(tempDbName())
    {
    }

    std::string tempDbName()
    {
        return std::string(std::tmpnam(nullptr)) + ".db";
    }

    void connect(std::string filename = "")
    {
        if (filename.empty()) filename = dbFilename_;
        connection_ = std::unique_ptr<SmartSqlite::Connection>(
                    new SmartSqlite::Connection(filename));
    }

    void disconnect()
    {
        ASSERT_THAT(connection_, Not(IsNull()));
        connection_.reset();
    }

    void deleteDb(const std::string &path)
    {
        ASSERT_THAT(path, Not(IsEmpty()));
        std::remove(path.c_str());
    }

    void setKey(const std::string &key)
    {
        connection_->setKey(key);
    }

    void rekey(const std::string &key)
    {
        connection_->changeKey(key);
    }

    void createTable(const std::string db = "main")
    {
        connection_->exec(std::string("CREATE TABLE ") + db + ".tbl (foo INT, bar TEXT)");
        connection_->exec(std::string("INSERT INTO ") + db + ".tbl VALUES (21, 'half the truth')");
        connection_->exec(std::string("INSERT INTO ") + db + ".tbl VALUES (42, 'the truth')");
    }

    void attach()
    {
        connection_->exec(
                    std::string("ATTACH DATABASE '") + attachedFilename_ + "' "
                    + "AS att");
    }

    void attachWithKey(const std::string &key)
    {
        connection_->exec(
                    std::string("ATTACH DATABASE '") + attachedFilename_ + "' "
                    + "AS att KEY '" + key + "'");
    }

    void checkForTestData()
    {
        auto stmt = connection_->prepare("SELECT * FROM tbl");

        auto rowIter = stmt.begin();
        ASSERT_THAT(rowIter, Not(Eq(stmt.end())));

        EXPECT_THAT(rowIter->get<int>(0), Eq(21));
        EXPECT_THAT(rowIter->get<std::string>(1), Eq("half the truth"));

        ++rowIter;
        ASSERT_THAT(rowIter, Not(Eq(stmt.end())));

        EXPECT_THAT(rowIter->get<int>(0), Eq(42));
        EXPECT_THAT(rowIter->get<std::string>(1), Eq("the truth"));

        ++rowIter;
        ASSERT_THAT(rowIter, Eq(stmt.end()));
    }

    std::string dbFilename_;
    std::string attachedFilename_;
    std::unique_ptr<SmartSqlite::Connection> connection_;
};

TEST_F(BotanSqlite3, canAccessEncryptedDatabase)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    setKey(SOME_KEY);
    checkForTestData();
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, preventsAccessWithoutKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    EXPECT_THROW(checkForTestData(), SmartSqlite::SqliteException);
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, preventsAccessWithWrongKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    setKey(ANOTHER_KEY);
    EXPECT_THROW(checkForTestData(), SmartSqlite::SqliteException);
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, preventsShortKey)
{
    auto shortKey = SOME_KEY;
    shortKey.pop_back();

    connect();
    EXPECT_THROW(setKey(shortKey), SmartSqlite::SqliteException);
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, preventsLongKey)
{
    auto longKey = SOME_KEY;
    longKey.push_back('0');

    connect();
    EXPECT_THROW(setKey(longKey), SmartSqlite::SqliteException);
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, preventsInvalidBase64Key)
{
    auto invalidKey = SOME_KEY;
    invalidKey.back() = 'x';

    connect();
    EXPECT_THROW(setKey(invalidKey), SmartSqlite::SqliteException);
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, encryptDatabase)
{
    connect();
    createTable();
    disconnect();

    connect();
    rekey(SOME_KEY);
    checkForTestData();
    disconnect();

    connect();
    setKey(SOME_KEY);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, changeKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    setKey(SOME_KEY);
    rekey(ANOTHER_KEY);
    checkForTestData();
    disconnect();

    connect();
    setKey(ANOTHER_KEY);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, decryptDatabase)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    setKey(SOME_KEY);
    rekey("");
    checkForTestData();
    disconnect();

    connect();
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, vacuumWorks)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    setKey(SOME_KEY);
    connection_->exec("VACUUM");
    disconnect();

    connect();
    setKey(SOME_KEY);
    checkForTestData();
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, attachWithSameKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();

    attach();
    createTable("att");
    disconnect();

    connect(attachedFilename_);
    setKey(SOME_KEY);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
    deleteDb(attachedFilename_);
}

TEST_F(BotanSqlite3, attachWithoutKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();

    attachWithKey("");
    createTable("att");
    disconnect();

    connect(attachedFilename_);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
    deleteDb(attachedFilename_);
}

TEST_F(BotanSqlite3, attachWithDifferentKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();

    attachWithKey(ANOTHER_KEY);
    createTable("att");
    disconnect();

    connect(attachedFilename_);
    setKey(ANOTHER_KEY);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
    deleteDb(attachedFilename_);
}

TEST_F(BotanSqlite3, attachWhenMainIsUnencrypted)
{
    connect();
    createTable();

    attachWithKey(SOME_KEY);
    createTable("att");
    disconnect();

    connect(attachedFilename_);
    setKey(SOME_KEY);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
    deleteDb(attachedFilename_);
}
<commit_msg>botansqlite3: Fix key validation tests<commit_after>/*
 * Copyright 2014–2016 The SmartSqlite contributors (see NOTICE.txt)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <cstdio>
#include <memory>
#include <string>

#include <gmock/gmock.h>

#include "smartsqlite/connection.h"
#include "smartsqlite/exceptions.h"

using namespace testing;

namespace {

// 96B = 768b
std::string SOME_KEY =
        "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0"
        "NTY3ODkwMTIxMjM0NTY3ODkwMTIzNDU2"
        "Nzg5MDEyMzQ1Njc4OTAxMjEyMzQ1Njc4"
        "OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEy";
std::string ANOTHER_KEY =
        "MDk4NzY1NDMyMTA5ODc2NTQzMjEwOTg3"
        "NjU0MzIxMDkwOTg3NjU0MzIxMDk4NzY1"
        "NDMyMTA5ODc2NTQzMjEwOTA5ODc2NTQz"
        "MjEwOTg3NjU0MzIxMDk4NzY1NDMyMTA5";

}

class BotanSqlite3: public Test
{
protected:
    BotanSqlite3()
        : dbFilename_(tempDbName())
        , attachedFilename_(tempDbName())
    {
    }

    std::string tempDbName()
    {
        return std::string(std::tmpnam(nullptr)) + ".db";
    }

    void connect(std::string filename = "")
    {
        if (filename.empty()) filename = dbFilename_;
        connection_ = std::unique_ptr<SmartSqlite::Connection>(
                    new SmartSqlite::Connection(filename));
    }

    void disconnect()
    {
        ASSERT_THAT(connection_, Not(IsNull()));
        connection_.reset();
    }

    void deleteDb(const std::string &path)
    {
        ASSERT_THAT(path, Not(IsEmpty()));
        std::remove(path.c_str());
    }

    void setKey(const std::string &key)
    {
        connection_->setKey(key);
    }

    void rekey(const std::string &key)
    {
        connection_->changeKey(key);
    }

    void createTable(const std::string db = "main")
    {
        connection_->exec(std::string("CREATE TABLE ") + db + ".tbl (foo INT, bar TEXT)");
        connection_->exec(std::string("INSERT INTO ") + db + ".tbl VALUES (21, 'half the truth')");
        connection_->exec(std::string("INSERT INTO ") + db + ".tbl VALUES (42, 'the truth')");
    }

    void attach()
    {
        connection_->exec(
                    std::string("ATTACH DATABASE '") + attachedFilename_ + "' "
                    + "AS att");
    }

    void attachWithKey(const std::string &key)
    {
        connection_->exec(
                    std::string("ATTACH DATABASE '") + attachedFilename_ + "' "
                    + "AS att KEY '" + key + "'");
    }

    void checkForTestData()
    {
        auto stmt = connection_->prepare("SELECT * FROM tbl");

        auto rowIter = stmt.begin();
        ASSERT_THAT(rowIter, Not(Eq(stmt.end())));

        EXPECT_THAT(rowIter->get<int>(0), Eq(21));
        EXPECT_THAT(rowIter->get<std::string>(1), Eq("half the truth"));

        ++rowIter;
        ASSERT_THAT(rowIter, Not(Eq(stmt.end())));

        EXPECT_THAT(rowIter->get<int>(0), Eq(42));
        EXPECT_THAT(rowIter->get<std::string>(1), Eq("the truth"));

        ++rowIter;
        ASSERT_THAT(rowIter, Eq(stmt.end()));
    }

    std::string dbFilename_;
    std::string attachedFilename_;
    std::unique_ptr<SmartSqlite::Connection> connection_;
};

TEST_F(BotanSqlite3, canAccessEncryptedDatabase)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    setKey(SOME_KEY);
    checkForTestData();
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, preventsAccessWithoutKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    EXPECT_THROW(checkForTestData(), SmartSqlite::SqliteException);
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, preventsAccessWithWrongKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    setKey(ANOTHER_KEY);
    EXPECT_THROW(checkForTestData(), SmartSqlite::SqliteException);
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, preventsShortKey)
{
    auto shortKey = SOME_KEY;
    shortKey.back() = '='; // remove last char

    connect();
    EXPECT_THROW(setKey(shortKey), SmartSqlite::SqliteException);
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, preventsLongKey)
{
    auto longKey = SOME_KEY;
    longKey.append("Mw=="); // "3" + padding

    connect();
    EXPECT_THROW(setKey(longKey), SmartSqlite::SqliteException);
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, preventsInvalidBase64Key)
{
    auto invalidKey = SOME_KEY;
    invalidKey.back() = '%';

    connect();
    EXPECT_THROW(setKey(invalidKey), SmartSqlite::SqliteException);
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, encryptDatabase)
{
    connect();
    createTable();
    disconnect();

    connect();
    rekey(SOME_KEY);
    checkForTestData();
    disconnect();

    connect();
    setKey(SOME_KEY);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, changeKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    setKey(SOME_KEY);
    rekey(ANOTHER_KEY);
    checkForTestData();
    disconnect();

    connect();
    setKey(ANOTHER_KEY);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, decryptDatabase)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    setKey(SOME_KEY);
    rekey("");
    checkForTestData();
    disconnect();

    connect();
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, vacuumWorks)
{
    connect();
    setKey(SOME_KEY);
    createTable();
    disconnect();

    connect();
    setKey(SOME_KEY);
    connection_->exec("VACUUM");
    disconnect();

    connect();
    setKey(SOME_KEY);
    checkForTestData();
    disconnect();
    deleteDb(dbFilename_);
}

TEST_F(BotanSqlite3, attachWithSameKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();

    attach();
    createTable("att");
    disconnect();

    connect(attachedFilename_);
    setKey(SOME_KEY);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
    deleteDb(attachedFilename_);
}

TEST_F(BotanSqlite3, attachWithoutKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();

    attachWithKey("");
    createTable("att");
    disconnect();

    connect(attachedFilename_);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
    deleteDb(attachedFilename_);
}

TEST_F(BotanSqlite3, attachWithDifferentKey)
{
    connect();
    setKey(SOME_KEY);
    createTable();

    attachWithKey(ANOTHER_KEY);
    createTable("att");
    disconnect();

    connect(attachedFilename_);
    setKey(ANOTHER_KEY);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
    deleteDb(attachedFilename_);
}

TEST_F(BotanSqlite3, attachWhenMainIsUnencrypted)
{
    connect();
    createTable();

    attachWithKey(SOME_KEY);
    createTable("att");
    disconnect();

    connect(attachedFilename_);
    setKey(SOME_KEY);
    checkForTestData();
    disconnect();

    deleteDb(dbFilename_);
    deleteDb(attachedFilename_);
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <sstream>
#include <numeric>
#include <boost/utility/value_init.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/limits.hpp>
#include <boost/foreach.hpp>
#include "misc_language.h"
#include "include_base_utils.h"
#include "cryptonote_basic_impl.h"
#include "cryptonote_format_utils.h"
#include "file_io_utils.h"
#include "common/command_line.h"
#include "string_coding.h"
#include "storages/portable_storage_template_helper.h"

using namespace epee;

#include "miner.h"

namespace cryptonote
{

  namespace
  {
    const command_line::arg_descriptor<std::string> arg_extra_messages =  {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true};
    const command_line::arg_descriptor<std::string> arg_start_mining =    {"start-mining", "Specify wallet address to mining for", "", true};
    const command_line::arg_descriptor<uint32_t>      arg_mining_threads =  {"mining-threads", "Specify mining threads count", 0, true};
  }

  miner::miner(i_miner_handler* phandler):m_stop(1),
    m_template(boost::value_initialized<block>()),
    m_template_no(0),
    m_diffic(0),
    m_thread_index(0),
    m_phandler(phandler),
    m_height(0),
    m_pausers_count(0),
    m_threads_total(0),
    m_starter_nonce(0),
    m_last_hr_merge_time(0),
    m_hashes(0),
    m_do_print_hashrate(false),
    m_do_mining(false),
    m_current_hash_rate(0)
  {

  }
  //-----------------------------------------------------------------------------------------------------
  miner::~miner()
  {
    stop();
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::set_block_template(const block& bl, const difficulty_type& di, uint64_t height)
  {
    CRITICAL_REGION_LOCAL(m_template_lock);
    m_template = bl;
    m_diffic = di;
    m_height = height;
    ++m_template_no;
    m_starter_nonce = crypto::rand<uint32_t>();
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::on_block_chain_update()
  {
    if(!is_mining())
      return true;

    return request_block_template();
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::request_block_template()
  {
    block bl = AUTO_VAL_INIT(bl);
    difficulty_type di = AUTO_VAL_INIT(di);
    uint64_t height = AUTO_VAL_INIT(height);
    cryptonote::blobdata extra_nonce;
    if(m_extra_messages.size() && m_config.current_extra_message_index < m_extra_messages.size())
    {
      extra_nonce = m_extra_messages[m_config.current_extra_message_index];
    }

    if(!m_phandler->get_block_template(bl, m_mine_address, di, height, extra_nonce))
    {
      LOG_ERROR("Failed to get_block_template(), stopping mining");
      return false;
    }
    set_block_template(bl, di, height);
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::on_idle()
  {
    m_update_block_template_interval.do_call([&](){
      if(is_mining())request_block_template();
      return true;
    });

    m_update_merge_hr_interval.do_call([&](){
      merge_hr();
      return true;
    });

    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::do_print_hashrate(bool do_hr)
  {
    m_do_print_hashrate = do_hr;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::merge_hr()
  {
    if(m_last_hr_merge_time && is_mining())
    {
      m_current_hash_rate = m_hashes * 1000 / ((misc_utils::get_tick_count() - m_last_hr_merge_time + 1));
      CRITICAL_REGION_LOCAL(m_last_hash_rates_lock);
      m_last_hash_rates.push_back(m_current_hash_rate);
      if(m_last_hash_rates.size() > 19)
        m_last_hash_rates.pop_front();
      if(m_do_print_hashrate)
      {
        uint64_t total_hr = std::accumulate(m_last_hash_rates.begin(), m_last_hash_rates.end(), 0);
        float hr = static_cast<float>(total_hr)/static_cast<float>(m_last_hash_rates.size());
        std::cout << "hashrate: " << std::setprecision(4) << std::fixed << hr << ENDL;
      }
    }
    m_last_hr_merge_time = misc_utils::get_tick_count();
    m_hashes = 0;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::init_options(boost::program_options::options_description& desc)
  {
    command_line::add_arg(desc, arg_extra_messages);
    command_line::add_arg(desc, arg_start_mining);
    command_line::add_arg(desc, arg_mining_threads);
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::init(const boost::program_options::variables_map& vm)
  {
    if(command_line::has_arg(vm, arg_extra_messages))
    {
      std::string buff;
      bool r = file_io_utils::load_file_to_string(command_line::get_arg(vm, arg_extra_messages), buff);
      CHECK_AND_ASSERT_MES(r, false, "Failed to load file with extra messages: " << command_line::get_arg(vm, arg_extra_messages));
      std::vector<std::string> extra_vec;
      boost::split(extra_vec, buff, boost::is_any_of("\n"), boost::token_compress_on );
      m_extra_messages.resize(extra_vec.size());
      for(size_t i = 0; i != extra_vec.size(); i++)
      {
        string_tools::trim(extra_vec[i]);
        if(!extra_vec[i].size())
          continue;
        std::string buff = string_encoding::base64_decode(extra_vec[i]);
        if(buff != "0")
          m_extra_messages[i] = buff;
      }
      m_config_folder_path = boost::filesystem::path(command_line::get_arg(vm, arg_extra_messages)).parent_path().string();
      m_config = AUTO_VAL_INIT(m_config);
      epee::serialization::load_t_from_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
      LOG_PRINT_L0("Loaded " << m_extra_messages.size() << " extra messages, current index " << m_config.current_extra_message_index);
    }

    if(command_line::has_arg(vm, arg_start_mining))
    {
      if(!cryptonote::get_account_address_from_str(m_mine_address, command_line::get_arg(vm, arg_start_mining)))
      {
        LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled");
        return false;
      }
      m_threads_total = 1;
      m_do_mining = true;
      if(command_line::has_arg(vm, arg_mining_threads))
      {
        m_threads_total = command_line::get_arg(vm, arg_mining_threads);
      }
    }

    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::is_mining() const
  {
    return !m_stop;
  }
  //-----------------------------------------------------------------------------------------------------
  const account_public_address& miner::get_mining_address() const
  {
    return m_mine_address;
  }
  //-----------------------------------------------------------------------------------------------------
  uint32_t miner::get_threads_count() const {
    return m_threads_total;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs)
  {
    m_mine_address = adr;
    m_threads_total = static_cast<uint32_t>(threads_count);
    m_starter_nonce = crypto::rand<uint32_t>();
    CRITICAL_REGION_LOCAL(m_threads_lock);
    if(is_mining())
    {
      LOG_ERROR("Starting miner but it's already started");
      return false;
    }

    if(!m_threads.empty())
    {
      LOG_ERROR("Unable to start miner because there are active mining threads");
      return false;
    }

    if(!m_template_no)
      request_block_template();//lets update block template

    boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0);
    boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0);

    for(size_t i = 0; i != threads_count; i++)
    {
      m_threads.push_back(boost::thread(attrs, boost::bind(&miner::worker_thread, this)));
    }

    LOG_PRINT_L0("Mining has started with " << threads_count << " threads, good luck!" )
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  uint64_t miner::get_speed() const
  {
    if(is_mining()) {
      return m_current_hash_rate;
    }
    else {
      return 0;
    }
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::send_stop_signal()
  {
    boost::interprocess::ipcdetail::atomic_write32(&m_stop, 1);
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::stop()
  {
    send_stop_signal();
    CRITICAL_REGION_LOCAL(m_threads_lock);

    BOOST_FOREACH(boost::thread& th, m_threads)
      th.join();

    m_threads.clear();
    LOG_PRINT_L0("Mining has been stopped, " << m_threads.size() << " finished" );
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height)
  {
    for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++)
    {
      crypto::hash h;
      get_block_longhash(bl, h, height);

      if(check_hash(h, diffic))
      {
        return true;
      }
    }
    return false;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::on_synchronized()
  {
    if(m_do_mining)
    {
      boost::thread::attributes attrs;
      attrs.set_stack_size(THREAD_STACK_SIZE);

      start(m_mine_address, m_threads_total, attrs);
    }
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::pause()
  {
    CRITICAL_REGION_LOCAL(m_miners_count_lock);
    ++m_pausers_count;
    if(m_pausers_count == 1 && is_mining())
      LOG_PRINT_L2("MINING PAUSED");
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::resume()
  {
    CRITICAL_REGION_LOCAL(m_miners_count_lock);
    --m_pausers_count;
    if(m_pausers_count < 0)
    {
      m_pausers_count = 0;
      LOG_PRINT_RED_L0("Unexpected miner::resume() called");
    }
    if(!m_pausers_count && is_mining())
      LOG_PRINT_L2("MINING RESUMED");
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::worker_thread()
  {
    uint32_t th_local_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index);
    LOG_PRINT_L0("Miner thread was started ["<< th_local_index << "]");
    log_space::log_singletone::set_thread_log_prefix(std::string("[miner ") + std::to_string(th_local_index) + "]");
    uint32_t nonce = m_starter_nonce + th_local_index;
    uint64_t height = 0;
    difficulty_type local_diff = 0;
    uint32_t local_template_ver = 0;
    block b;
    while(!m_stop)
    {
      if(m_pausers_count)//anti split workaround
      {
        misc_utils::sleep_no_w(100);
        continue;
      }

      if(local_template_ver != m_template_no)
      {

        CRITICAL_REGION_BEGIN(m_template_lock);
        b = m_template;
        local_diff = m_diffic;
        height = m_height;
        CRITICAL_REGION_END();
        local_template_ver = m_template_no;
        nonce = m_starter_nonce + th_local_index;
      }

      if(!local_template_ver)//no any set_block_template call
      {
        LOG_PRINT_L2("Block template not set yet");
        epee::misc_utils::sleep_no_w(1000);
        continue;
      }

      b.nonce = nonce;
      crypto::hash h;
      get_block_longhash(b, h, height);

      if(check_hash(h, local_diff))
      {
        //we lucky!
        ++m_config.current_extra_message_index;
        LOG_PRINT_GREEN("Found block for difficulty: " << local_diff, LOG_LEVEL_0);
        if(!m_phandler->handle_block_found(b))
        {
          --m_config.current_extra_message_index;
        }else
        {
          //success update, lets update config
          epee::serialization::store_t_to_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
        }
      }
      nonce+=m_threads_total;
      ++m_hashes;
    }
    LOG_PRINT_L0("Miner thread stopped ["<< th_local_index << "]");
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
}

<commit_msg>Update miner.cpp<commit_after>// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <sstream>
#include <numeric>
#include <boost/utility/value_init.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/limits.hpp>
#include <boost/foreach.hpp>
#include "misc_language.h"
#include "include_base_utils.h"
#include "cryptonote_basic_impl.h"
#include "cryptonote_format_utils.h"
#include "file_io_utils.h"
#include "common/command_line.h"
#include "string_coding.h"
#include "storages/portable_storage_template_helper.h"

using namespace epee;

#include "miner.h"

extern "C" void slow_hash_allocate_state();
extern "C" void slow_hash_free_state();
namespace cryptonote
{

  namespace
  {
    const command_line::arg_descriptor<std::string> arg_extra_messages =  {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true};
    const command_line::arg_descriptor<std::string> arg_start_mining =    {"start-mining", "Specify wallet address to mining for", "", true};
    const command_line::arg_descriptor<uint32_t>      arg_mining_threads =  {"mining-threads", "Specify mining threads count", 0, true};
  }

  miner::miner(i_miner_handler* phandler):m_stop(1),
    m_template(boost::value_initialized<block>()),
    m_template_no(0),
    m_diffic(0),
    m_thread_index(0),
    m_phandler(phandler),
    m_height(0),
    m_pausers_count(0),
    m_threads_total(0),
    m_starter_nonce(0),
    m_last_hr_merge_time(0),
    m_hashes(0),
    m_do_print_hashrate(false),
    m_do_mining(false),
    m_current_hash_rate(0)
  {

  }
  //-----------------------------------------------------------------------------------------------------
  miner::~miner()
  {
    stop();
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::set_block_template(const block& bl, const difficulty_type& di, uint64_t height)
  {
    CRITICAL_REGION_LOCAL(m_template_lock);
    m_template = bl;
    m_diffic = di;
    m_height = height;
    ++m_template_no;
    m_starter_nonce = crypto::rand<uint32_t>();
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::on_block_chain_update()
  {
    if(!is_mining())
      return true;

    return request_block_template();
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::request_block_template()
  {
    block bl = AUTO_VAL_INIT(bl);
    difficulty_type di = AUTO_VAL_INIT(di);
    uint64_t height = AUTO_VAL_INIT(height);
    cryptonote::blobdata extra_nonce;
    if(m_extra_messages.size() && m_config.current_extra_message_index < m_extra_messages.size())
    {
      extra_nonce = m_extra_messages[m_config.current_extra_message_index];
    }

    if(!m_phandler->get_block_template(bl, m_mine_address, di, height, extra_nonce))
    {
      LOG_ERROR("Failed to get_block_template(), stopping mining");
      return false;
    }
    set_block_template(bl, di, height);
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::on_idle()
  {
    m_update_block_template_interval.do_call([&](){
      if(is_mining())request_block_template();
      return true;
    });

    m_update_merge_hr_interval.do_call([&](){
      merge_hr();
      return true;
    });

    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::do_print_hashrate(bool do_hr)
  {
    m_do_print_hashrate = do_hr;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::merge_hr()
  {
    if(m_last_hr_merge_time && is_mining())
    {
      m_current_hash_rate = m_hashes * 1000 / ((misc_utils::get_tick_count() - m_last_hr_merge_time + 1));
      CRITICAL_REGION_LOCAL(m_last_hash_rates_lock);
      m_last_hash_rates.push_back(m_current_hash_rate);
      if(m_last_hash_rates.size() > 19)
        m_last_hash_rates.pop_front();
      if(m_do_print_hashrate)
      {
        uint64_t total_hr = std::accumulate(m_last_hash_rates.begin(), m_last_hash_rates.end(), 0);
        float hr = static_cast<float>(total_hr)/static_cast<float>(m_last_hash_rates.size());
        std::cout << "hashrate: " << std::setprecision(4) << std::fixed << hr << ENDL;
      }
    }
    m_last_hr_merge_time = misc_utils::get_tick_count();
    m_hashes = 0;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::init_options(boost::program_options::options_description& desc)
  {
    command_line::add_arg(desc, arg_extra_messages);
    command_line::add_arg(desc, arg_start_mining);
    command_line::add_arg(desc, arg_mining_threads);
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::init(const boost::program_options::variables_map& vm)
  {
    if(command_line::has_arg(vm, arg_extra_messages))
    {
      std::string buff;
      bool r = file_io_utils::load_file_to_string(command_line::get_arg(vm, arg_extra_messages), buff);
      CHECK_AND_ASSERT_MES(r, false, "Failed to load file with extra messages: " << command_line::get_arg(vm, arg_extra_messages));
      std::vector<std::string> extra_vec;
      boost::split(extra_vec, buff, boost::is_any_of("\n"), boost::token_compress_on );
      m_extra_messages.resize(extra_vec.size());
      for(size_t i = 0; i != extra_vec.size(); i++)
      {
        string_tools::trim(extra_vec[i]);
        if(!extra_vec[i].size())
          continue;
        std::string buff = string_encoding::base64_decode(extra_vec[i]);
        if(buff != "0")
          m_extra_messages[i] = buff;
      }
      m_config_folder_path = boost::filesystem::path(command_line::get_arg(vm, arg_extra_messages)).parent_path().string();
      m_config = AUTO_VAL_INIT(m_config);
      epee::serialization::load_t_from_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
      LOG_PRINT_L0("Loaded " << m_extra_messages.size() << " extra messages, current index " << m_config.current_extra_message_index);
    }

    if(command_line::has_arg(vm, arg_start_mining))
    {
      if(!cryptonote::get_account_address_from_str(m_mine_address, command_line::get_arg(vm, arg_start_mining)))
      {
        LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled");
        return false;
      }
      m_threads_total = 1;
      m_do_mining = true;
      if(command_line::has_arg(vm, arg_mining_threads))
      {
        m_threads_total = command_line::get_arg(vm, arg_mining_threads);
      }
    }

    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::is_mining() const
  {
    return !m_stop;
  }
  //-----------------------------------------------------------------------------------------------------
  const account_public_address& miner::get_mining_address() const
  {
    return m_mine_address;
  }
  //-----------------------------------------------------------------------------------------------------
  uint32_t miner::get_threads_count() const {
    return m_threads_total;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs)
  {
    m_mine_address = adr;
    m_threads_total = static_cast<uint32_t>(threads_count);
    m_starter_nonce = crypto::rand<uint32_t>();
    CRITICAL_REGION_LOCAL(m_threads_lock);
    if(is_mining())
    {
      LOG_ERROR("Starting miner but it's already started");
      return false;
    }

    if(!m_threads.empty())
    {
      LOG_ERROR("Unable to start miner because there are active mining threads");
      return false;
    }

    if(!m_template_no)
      request_block_template();//lets update block template

    boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0);
    boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0);

    for(size_t i = 0; i != threads_count; i++)
    {
      m_threads.push_back(boost::thread(attrs, boost::bind(&miner::worker_thread, this)));
    }

    LOG_PRINT_L0("Mining has started with " << threads_count << " threads, good luck!" )
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  uint64_t miner::get_speed() const
  {
    if(is_mining()) {
      return m_current_hash_rate;
    }
    else {
      return 0;
    }
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::send_stop_signal()
  {
    boost::interprocess::ipcdetail::atomic_write32(&m_stop, 1);
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::stop()
  {
    send_stop_signal();
    CRITICAL_REGION_LOCAL(m_threads_lock);

    BOOST_FOREACH(boost::thread& th, m_threads)
      th.join();

    m_threads.clear();
    LOG_PRINT_L0("Mining has been stopped, " << m_threads.size() << " finished" );
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height)
  {
    for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++)
    {
      crypto::hash h;
      get_block_longhash(bl, h, height);

      if(check_hash(h, diffic))
      {
        return true;
      }
    }
    return false;
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::on_synchronized()
  {
    if(m_do_mining)
    {
      boost::thread::attributes attrs;
      attrs.set_stack_size(THREAD_STACK_SIZE);

      start(m_mine_address, m_threads_total, attrs);
    }
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::pause()
  {
    CRITICAL_REGION_LOCAL(m_miners_count_lock);
    ++m_pausers_count;
    if(m_pausers_count == 1 && is_mining())
      LOG_PRINT_L2("MINING PAUSED");
  }
  //-----------------------------------------------------------------------------------------------------
  void miner::resume()
  {
    CRITICAL_REGION_LOCAL(m_miners_count_lock);
    --m_pausers_count;
    if(m_pausers_count < 0)
    {
      m_pausers_count = 0;
      LOG_PRINT_RED_L0("Unexpected miner::resume() called");
    }
    if(!m_pausers_count && is_mining())
      LOG_PRINT_L2("MINING RESUMED");
  }
  //-----------------------------------------------------------------------------------------------------
  bool miner::worker_thread()
  {
    uint32_t th_local_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index);
    LOG_PRINT_L0("Miner thread was started ["<< th_local_index << "]");
    log_space::log_singletone::set_thread_log_prefix(std::string("[miner ") + std::to_string(th_local_index) + "]");
    uint32_t nonce = m_starter_nonce + th_local_index;
    uint64_t height = 0;
    difficulty_type local_diff = 0;
    uint32_t local_template_ver = 0;
    block b;
	  slow_hash_allocate_state();
    while(!m_stop)
    {
      if(m_pausers_count)//anti split workaround
      {
        misc_utils::sleep_no_w(100);
        continue;
      }

      if(local_template_ver != m_template_no)
      {

        CRITICAL_REGION_BEGIN(m_template_lock);
        b = m_template;
        local_diff = m_diffic;
        height = m_height;
        CRITICAL_REGION_END();
        local_template_ver = m_template_no;
        nonce = m_starter_nonce + th_local_index;
      }

      if(!local_template_ver)//no any set_block_template call
      {
        LOG_PRINT_L2("Block template not set yet");
        epee::misc_utils::sleep_no_w(1000);
        continue;
      }

      b.nonce = nonce;
      crypto::hash h;
      get_block_longhash(b, h, height);

      if(check_hash(h, local_diff))
      {
        //we lucky!
        ++m_config.current_extra_message_index;
        LOG_PRINT_GREEN("Found block for difficulty: " << local_diff, LOG_LEVEL_0);
        if(!m_phandler->handle_block_found(b))
        {
          --m_config.current_extra_message_index;
        }else
        {
          //success update, lets update config
          epee::serialization::store_t_to_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
        }
      }
      nonce+=m_threads_total;
      ++m_hashes;
    }
	  slow_hash_free_state();
    LOG_PRINT_L0("Miner thread stopped ["<< th_local_index << "]");
    return true;
  }
  //-----------------------------------------------------------------------------------------------------
}

<|endoftext|>